[ovs-dev] [RFC PATCH] userspace: Define and use struct eth_addr.

Jarno Rajahalme jrajahalme at nicira.com
Fri Aug 28 01:29:16 UTC 2015


Define struct eth_addr and use it instead of a uint8_t array for all
ethernet addresses in OVS userspace.  The struct is always the right
size, and it can be assigned without an explicit memcpy, which makes
code more readable.

"struct eth_addr" is a good type name for this as many utility
functions are already named accordingly.

struct eth_addr can be accessed as bytes as well as ovs_be16's, which
makes the struct 16-bit aligned.  All use seems to be 16-bit aligned,
so some algorithms on the ethernet addresses can be made a bit more
efficient making use of this fact.

As the struct fits into a register (in 64-bit systems) we pass it by
value when possible.

This patch also changes the few uses of Linux specific ETH_ALEN to
OVS's own ETH_ADDR_LEN, and removes the OFP_ETH_ALEN, as it is no
longer needed.

This work stemmed from a desire to make all struct flow members
assignable for unrelated exploration purposes.  However, I think this
might be a nice code readability improvement by itself.

Signed-off-by: Jarno Rajahalme <jrajahalme at nicira.com>
---
 build-aux/check-structs            |   1 +
 build-aux/extract-odp-netlink-h    |   9 +-
 include/openflow/openflow-1.0.h    |  15 ++-
 include/openflow/openflow-1.1.h    |  19 ++--
 include/openflow/openflow-1.4.h    |   4 +-
 include/openflow/openflow-common.h |   2 -
 include/openvswitch/types.h        |  10 ++
 lib/bfd.c                          |  42 ++++----
 lib/bfd.h                          |   2 +-
 lib/cfm.c                          |  13 ++-
 lib/cfm.h                          |   2 +-
 lib/csum.c                         |  14 +--
 lib/csum.h                         |   4 +-
 lib/flow.c                         |  54 +++++------
 lib/flow.h                         |   8 +-
 lib/lacp.c                         |  16 ++-
 lib/lacp.h                         |   6 +-
 lib/lldp/aa-structs.h              |   2 +-
 lib/lldp/lldp-tlv.h                |   4 +-
 lib/lldp/lldp.c                    |   4 +-
 lib/lldp/lldpd-structs.h           |   2 +-
 lib/lldp/lldpd.c                   |   4 +-
 lib/lldp/lldpd.h                   |   4 +-
 lib/mac-learning.c                 |  12 +--
 lib/mac-learning.h                 |   8 +-
 lib/match.c                        |  72 +++++++-------
 lib/match.h                        |  24 ++---
 lib/meta-flow.c                    |  45 +++++----
 lib/meta-flow.h                    |   4 +-
 lib/netdev-bsd.c                   |  25 +++--
 lib/netdev-dpdk.c                  |  12 +--
 lib/netdev-dummy.c                 |  24 +++--
 lib/netdev-linux.c                 |  31 +++---
 lib/netdev-provider.h              |   8 +-
 lib/netdev-vport.c                 |  14 ++-
 lib/netdev-windows.c               |  15 ++-
 lib/netdev.c                       |   8 +-
 lib/netdev.h                       |   6 +-
 lib/nx-match.c                     |   5 +-
 lib/odp-execute.c                  |  40 ++++----
 lib/odp-util.c                     |  44 ++++-----
 lib/ofp-actions.c                  |  22 ++---
 lib/ofp-actions.h                  |   2 +-
 lib/ofp-parse.c                    |   4 +-
 lib/ofp-parse.h                    |   2 +-
 lib/ofp-util.c                     |  70 ++++++-------
 lib/ofp-util.h                     |   4 +-
 lib/ovs-lldp.c                     |  12 ++-
 lib/ovs-lldp.h                     |   2 +-
 lib/packets.c                      |  75 ++++++--------
 lib/packets.h                      | 194 ++++++++++++++++++++-----------------
 lib/rstp-state-machines.c          |   2 +-
 lib/rtnetlink.c                    |   8 +-
 lib/rtnetlink.h                    |   4 +-
 lib/sflow.h                        |  14 ++-
 lib/sflow_receiver.c               |   5 +-
 lib/stp.c                          |   2 +-
 lib/tnl-arp-cache.c                |  10 +-
 lib/tnl-arp-cache.h                |   2 +-
 ofproto/bond.c                     |  38 ++++----
 ofproto/bond.h                     |  10 +-
 ofproto/fail-open.c                |   4 +-
 ofproto/in-band.c                  |  34 +++----
 ofproto/ofproto-dpif-ipfix.c       |  10 +-
 ofproto/ofproto-dpif-monitor.c     |  18 ++--
 ofproto/ofproto-dpif-monitor.h     |   2 +-
 ofproto/ofproto-dpif-sflow.c       |  10 +-
 ofproto/ofproto-dpif-xlate.c       |  24 ++---
 ofproto/ofproto-dpif.c             |  16 +--
 ofproto/ofproto.c                  |  12 +--
 ofproto/tunnel.c                   |   8 +-
 ofproto/tunnel.h                   |   4 +-
 ovn/lib/lex.c                      |   4 +-
 ovn/northd/ovn-northd.c            |   8 +-
 tests/test-aa.c                    |  44 ++-------
 tests/test-classifier.c            |  36 +++----
 tests/test-sflow.c                 |  10 +-
 utilities/ovs-ofctl.c              |   2 +-
 vswitchd/bridge.c                  |  96 +++++++++---------
 79 files changed, 697 insertions(+), 765 deletions(-)

diff --git a/build-aux/check-structs b/build-aux/check-structs
index 44ffaa7..f79f235 100755
--- a/build-aux/check-structs
+++ b/build-aux/check-structs
@@ -15,6 +15,7 @@ types['ovs_be16'] = {"size": 2, "alignment": 2}
 types['ovs_be32'] = {"size": 4, "alignment": 4}
 types['ovs_be64'] = {"size": 8, "alignment": 8}
 types['ovs_32aligned_be64'] = {"size": 8, "alignment": 4}
+types['struct eth_addr'] = {"size": 6, "alignment": 1}
 
 token = None
 line = ""
diff --git a/build-aux/extract-odp-netlink-h b/build-aux/extract-odp-netlink-h
index 9a9d1d5..b414330 100755
--- a/build-aux/extract-odp-netlink-h
+++ b/build-aux/extract-odp-netlink-h
@@ -20,11 +20,14 @@ $i\
 #include "OvsDpInterfaceExt.h"\
 #endif\
 
+# Use OVS's own struct eth_addr instead of a 6-byte char array.
+s,<linux/types\.h>,"openvswitch/types.h",
+s,#.*<linux/if_ether\.h>,,
+s/__u8[ \t]*\([a-zA-Z0-9_]*\)[ \t]*\[[ \t]*ETH_ALEN[ \t]*\]/struct eth_addr \1/
 
 # Transform most Linux-specific __u<N> types into C99 uint<N>_t types,
 # and most Linux-specific __be<N> into Open vSwitch ovs_be<N>,
 # and use the appropriate userspace header.
-s,<linux/types\.h>,"openvswitch/types.h",
 s/__u32/uint32_t/g
 s/__u16/uint16_t/g
 s/__u8/uint8_t/g
@@ -36,7 +39,3 @@ s/__be16/ovs_be16/g
 # boundary.
 s/__u64/ovs_32aligned_u64/g
 s/__be64/ovs_32aligned_be64/g
-
-# Use OVS's own ETH_ADDR_LEN instead of Linux-specific ETH_ALEN.
-s,<linux/if_ether\.h>,"packets.h",
-s/ETH_ALEN/ETH_ADDR_LEN/
diff --git a/include/openflow/openflow-1.0.h b/include/openflow/openflow-1.0.h
index 856634a..54b15f2 100644
--- a/include/openflow/openflow-1.0.h
+++ b/include/openflow/openflow-1.0.h
@@ -96,7 +96,7 @@ enum ofp10_port_features {
 /* Description of a physical port */
 struct ofp10_phy_port {
     ovs_be16 port_no;
-    uint8_t hw_addr[OFP_ETH_ALEN];
+    struct eth_addr hw_addr;
     char name[OFP_MAX_PORT_NAME_LEN]; /* Null-terminated */
 
     ovs_be32 config;        /* Bitmap of OFPPC_* and OFPPC10_* flags. */
@@ -114,11 +114,10 @@ OFP_ASSERT(sizeof(struct ofp10_phy_port) == 48);
 /* Modify behavior of the physical port */
 struct ofp10_port_mod {
     ovs_be16 port_no;
-    uint8_t hw_addr[OFP_ETH_ALEN]; /* The hardware address is not
-                                      configurable.  This is used to
-                                      sanity-check the request, so it must
-                                      be the same as returned in an
-                                      ofp10_phy_port struct. */
+    struct eth_addr hw_addr; /* The hardware address is not configurable.  This
+                                is used to sanity-check the request, so it must
+                                be the same as returned in an ofp10_phy_port
+                                struct. */
 
     ovs_be32 config;        /* Bitmap of OFPPC_* flags. */
     ovs_be32 mask;          /* Bitmap of OFPPC_* flags to be changed. */
@@ -234,8 +233,8 @@ enum ofp10_flow_wildcards {
 struct ofp10_match {
     ovs_be32 wildcards;        /* Wildcard fields. */
     ovs_be16 in_port;          /* Input switch port. */
-    uint8_t dl_src[OFP_ETH_ALEN]; /* Ethernet source address. */
-    uint8_t dl_dst[OFP_ETH_ALEN]; /* Ethernet destination address. */
+    struct eth_addr dl_src;    /* Ethernet source address. */
+    struct eth_addr dl_dst;    /* Ethernet destination address. */
     ovs_be16 dl_vlan;          /* Input VLAN. */
     uint8_t dl_vlan_pcp;       /* Input VLAN priority. */
     uint8_t pad1[1];           /* Align to 64-bits. */
diff --git a/include/openflow/openflow-1.1.h b/include/openflow/openflow-1.1.h
index b5a7310..5b4ba2b 100644
--- a/include/openflow/openflow-1.1.h
+++ b/include/openflow/openflow-1.1.h
@@ -110,7 +110,7 @@ enum ofp11_port_features {
 struct ofp11_port {
     ovs_be32 port_no;
     uint8_t pad[4];
-    uint8_t hw_addr[OFP_ETH_ALEN];
+    struct eth_addr hw_addr;
     uint8_t pad2[2];                  /* Align to 64 bits. */
     char name[OFP_MAX_PORT_NAME_LEN]; /* Null-terminated */
 
@@ -133,11 +133,10 @@ OFP_ASSERT(sizeof(struct ofp11_port) == 64);
 struct ofp11_port_mod {
     ovs_be32 port_no;
     uint8_t pad[4];
-    uint8_t hw_addr[OFP_ETH_ALEN]; /* The hardware address is not
-                                      configurable.  This is used to
-                                      sanity-check the request, so it must
-                                      be the same as returned in an
-                                      ofp11_port struct. */
+    struct eth_addr hw_addr; /* The hardware address is not configurable.  This
+                                is used to sanity-check the request, so it must
+                                be the same as returned in an ofp11_port
+                                struct. */
     uint8_t pad2[2];        /* Pad to 64 bits. */
     ovs_be32 config;        /* Bitmap of OFPPC_* flags. */
     ovs_be32 mask;          /* Bitmap of OFPPC_* flags to be changed. */
@@ -194,10 +193,10 @@ struct ofp11_match {
     struct ofp11_match_header omh;
     ovs_be32 in_port;          /* Input switch port. */
     ovs_be32 wildcards;        /* Wildcard fields. */
-    uint8_t dl_src[OFP_ETH_ALEN]; /* Ethernet source address. */
-    uint8_t dl_src_mask[OFP_ETH_ALEN]; /* Ethernet source address mask.  */
-    uint8_t dl_dst[OFP_ETH_ALEN]; /* Ethernet destination address. */
-    uint8_t dl_dst_mask[OFP_ETH_ALEN]; /* Ethernet destination address mask. */
+    struct eth_addr dl_src;    /* Ethernet source address. */
+    struct eth_addr dl_src_mask; /* Ethernet source address mask.  */
+    struct eth_addr dl_dst;    /* Ethernet destination address. */
+    struct eth_addr dl_dst_mask; /* Ethernet destination address mask. */
     ovs_be16 dl_vlan;          /* Input VLAN id. */
     uint8_t dl_vlan_pcp;       /* Input VLAN priority. */
     uint8_t pad1[1];           /* Align to 32-bits */
diff --git a/include/openflow/openflow-1.4.h b/include/openflow/openflow-1.4.h
index 37eef4a..1ed4e39 100644
--- a/include/openflow/openflow-1.4.h
+++ b/include/openflow/openflow-1.4.h
@@ -72,7 +72,7 @@ struct ofp14_port {
     ovs_be32 port_no;
     ovs_be16 length;
     uint8_t pad[2];
-    uint8_t hw_addr[OFP_ETH_ALEN];
+    struct eth_addr hw_addr;
     uint8_t pad2[2];                  /* Align to 64 bits. */
     char name[OFP_MAX_PORT_NAME_LEN]; /* Null-terminated */
 
@@ -106,7 +106,7 @@ OFP_ASSERT(sizeof(struct ofp14_port_mod_prop_ethernet) == 8);
 struct ofp14_port_mod {
     ovs_be32 port_no;
     uint8_t pad[4];
-    uint8_t hw_addr[OFP_ETH_ALEN];
+    struct eth_addr hw_addr;
     uint8_t pad2[2];
     ovs_be32 config;        /* Bitmap of OFPPC_* flags. */
     ovs_be32 mask;          /* Bitmap of OFPPC_* flags to be changed. */
diff --git a/include/openflow/openflow-common.h b/include/openflow/openflow-common.h
index d32213f..c0d2282 100644
--- a/include/openflow/openflow-common.h
+++ b/include/openflow/openflow-common.h
@@ -113,8 +113,6 @@ enum ofp_version {
 #define OFP_OLD_PORT  6633
 #define OFP_PORT  6653
 
-#define OFP_ETH_ALEN 6          /* Bytes in an Ethernet address. */
-
 #define OFP_DEFAULT_MISS_SEND_LEN   128
 
 /* Values below this cutoff are 802.3 packets and the two bytes
diff --git a/include/openvswitch/types.h b/include/openvswitch/types.h
index 629a3e5..c138b9c 100644
--- a/include/openvswitch/types.h
+++ b/include/openvswitch/types.h
@@ -106,4 +106,14 @@ typedef uint32_t OVS_BITWISE ofp11_port_t;
 #define ODP_PORT_C(X) ((OVS_FORCE odp_port_t) (X))
 #define OFP11_PORT_C(X) ((OVS_FORCE ofp11_port_t) (X))
 
+/* Using this stuct instead of a bare array makes an ethernet address field
+ * assignable.  The size of the array is also part of the type, so it is easier
+ * to deal with. */
+struct eth_addr {
+    union {
+        uint8_t ea[6];
+        ovs_be16 be16[3];
+    };
+};
+
 #endif /* openvswitch/types.h */
diff --git a/lib/bfd.c b/lib/bfd.c
index 889c76e..dae682f 100644
--- a/lib/bfd.c
+++ b/lib/bfd.c
@@ -170,10 +170,10 @@ struct bfd {
 
     uint32_t rmt_disc;            /* bfd.RemoteDiscr. */
 
-    uint8_t local_eth_src[ETH_ADDR_LEN]; /* Local eth src address. */
-    uint8_t local_eth_dst[ETH_ADDR_LEN]; /* Local eth dst address. */
+    struct eth_addr local_eth_src; /* Local eth src address. */
+    struct eth_addr local_eth_dst; /* Local eth dst address. */
 
-    uint8_t rmt_eth_dst[ETH_ADDR_LEN];   /* Remote eth dst address. */
+    struct eth_addr rmt_eth_dst;   /* Remote eth dst address. */
 
     ovs_be32 ip_src;              /* IPv4 source address. */
     ovs_be32 ip_dst;              /* IPv4 destination address. */
@@ -357,7 +357,7 @@ bfd_configure(struct bfd *bfd, const char *name, const struct smap *cfg,
     bool cpath_down, forwarding_if_rx;
     const char *hwaddr, *ip_src, *ip_dst;
     struct in_addr in_addr;
-    uint8_t ea[ETH_ADDR_LEN];
+    struct eth_addr ea;
 
     if (!cfg || !smap_get_bool(cfg, "enable", false)) {
         bfd_unref(bfd);
@@ -441,24 +441,24 @@ bfd_configure(struct bfd *bfd, const char *name, const struct smap *cfg,
     }
 
     hwaddr = smap_get(cfg, "bfd_local_src_mac");
-    if (hwaddr && eth_addr_from_string(hwaddr, ea)) {
-        memcpy(bfd->local_eth_src, ea, ETH_ADDR_LEN);
+    if (hwaddr && eth_addr_from_string(hwaddr, &ea)) {
+        bfd->local_eth_src = ea;
     } else {
-        memset(bfd->local_eth_src, 0, ETH_ADDR_LEN);
+        bfd->local_eth_src = eth_addr_zero;
     }
 
     hwaddr = smap_get(cfg, "bfd_local_dst_mac");
-    if (hwaddr && eth_addr_from_string(hwaddr, ea)) {
-        memcpy(bfd->local_eth_dst, ea, ETH_ADDR_LEN);
+    if (hwaddr && eth_addr_from_string(hwaddr, &ea)) {
+        bfd->local_eth_dst = ea;
     } else {
-        memset(bfd->local_eth_dst, 0, ETH_ADDR_LEN);
+        bfd->local_eth_dst = eth_addr_zero;
     }
 
     hwaddr = smap_get(cfg, "bfd_remote_dst_mac");
-    if (hwaddr && eth_addr_from_string(hwaddr, ea)) {
-        memcpy(bfd->rmt_eth_dst, ea, ETH_ADDR_LEN);
+    if (hwaddr && eth_addr_from_string(hwaddr, &ea)) {
+        bfd->rmt_eth_dst = ea;
     } else {
-        memset(bfd->rmt_eth_dst, 0, ETH_ADDR_LEN);
+        bfd->rmt_eth_dst = eth_addr_zero;
     }
 
     ip_src = smap_get(cfg, "bfd_src_ip");
@@ -589,7 +589,7 @@ bfd_should_send_packet(const struct bfd *bfd) OVS_EXCLUDED(mutex)
 
 void
 bfd_put_packet(struct bfd *bfd, struct dp_packet *p,
-               uint8_t eth_src[ETH_ADDR_LEN]) OVS_EXCLUDED(mutex)
+               const struct eth_addr eth_src) OVS_EXCLUDED(mutex)
 {
     long long int min_tx, min_rx;
     struct udp_header *udp;
@@ -614,14 +614,10 @@ bfd_put_packet(struct bfd *bfd, struct dp_packet *p,
 
     dp_packet_reserve(p, 2); /* Properly align after the ethernet header. */
     eth = dp_packet_put_uninit(p, sizeof *eth);
-    memcpy(eth->eth_src,
-           eth_addr_is_zero(bfd->local_eth_src) ? eth_src
-                                                : bfd->local_eth_src,
-           ETH_ADDR_LEN);
-    memcpy(eth->eth_dst,
-           eth_addr_is_zero(bfd->local_eth_dst) ? eth_addr_bfd
-                                                : bfd->local_eth_dst,
-           ETH_ADDR_LEN);
+    eth->eth_src = eth_addr_is_zero(bfd->local_eth_src)
+        ? eth_src : bfd->local_eth_src;
+    eth->eth_dst = eth_addr_is_zero(bfd->local_eth_dst)
+        ? eth_addr_bfd : bfd->local_eth_dst;
     eth->eth_type = htons(ETH_TYPE_IP);
 
     ip = dp_packet_put_zeros(p, sizeof *ip);
@@ -678,7 +674,7 @@ bfd_should_process_flow(const struct bfd *bfd_, const struct flow *flow,
     if (!eth_addr_is_zero(bfd->rmt_eth_dst)) {
         memset(&wc->masks.dl_dst, 0xff, sizeof wc->masks.dl_dst);
 
-        if (memcmp(bfd->rmt_eth_dst, flow->dl_dst, ETH_ADDR_LEN)) {
+        if (!eth_addr_equals(bfd->rmt_eth_dst, flow->dl_dst)) {
             return false;
         }
     }
diff --git a/lib/bfd.h b/lib/bfd.h
index 19da3a3..6a1d547 100644
--- a/lib/bfd.h
+++ b/lib/bfd.h
@@ -36,7 +36,7 @@ void bfd_run(struct bfd *);
 
 bool bfd_should_send_packet(const struct bfd *);
 void bfd_put_packet(struct bfd *bfd, struct dp_packet *packet,
-                    uint8_t eth_src[ETH_ADDR_LEN]);
+                    const struct eth_addr eth_src);
 
 bool bfd_should_process_flow(const struct bfd *, const struct flow *,
                              struct flow_wildcards *);
diff --git a/lib/cfm.c b/lib/cfm.c
index 6a507a1..587454a 100644
--- a/lib/cfm.c
+++ b/lib/cfm.c
@@ -44,11 +44,10 @@ VLOG_DEFINE_THIS_MODULE(cfm);
 #define CFM_MAX_RMPS 256
 
 /* Ethernet destination address of CCM packets. */
-static const uint8_t eth_addr_ccm[ETH_ADDR_LEN] = {
-    0x01, 0x80, 0xC2, 0x00, 0x00, 0x30 };
-static const uint8_t eth_addr_ccm_x[ETH_ADDR_LEN] = {
-    0x01, 0x23, 0x20, 0x00, 0x00, 0x30
-};
+static const struct eth_addr eth_addr_ccm = {
+    { { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x30 } } };
+static const struct eth_addr eth_addr_ccm_x = {
+    { { 0x01, 0x23, 0x20, 0x00, 0x00, 0x30 } } };
 
 #define ETH_TYPE_CFM 0x8902
 
@@ -185,7 +184,7 @@ cfm_rx_packets(const struct cfm *cfm) OVS_REQUIRES(mutex)
     }
 }
 
-static const uint8_t *
+static struct eth_addr
 cfm_ccm_addr(struct cfm *cfm)
 {
     bool extended;
@@ -565,7 +564,7 @@ cfm_should_send_ccm(struct cfm *cfm) OVS_EXCLUDED(mutex)
  * should be sent whenever cfm_should_send_ccm() indicates. */
 void
 cfm_compose_ccm(struct cfm *cfm, struct dp_packet *packet,
-                const uint8_t eth_src[ETH_ADDR_LEN]) OVS_EXCLUDED(mutex)
+                const struct eth_addr eth_src) OVS_EXCLUDED(mutex)
 {
     uint16_t ccm_vlan;
     struct ccm *ccm;
diff --git a/lib/cfm.h b/lib/cfm.h
index 5ef8639..98d48b3 100644
--- a/lib/cfm.h
+++ b/lib/cfm.h
@@ -94,7 +94,7 @@ void cfm_unref(struct cfm *);
 void cfm_run(struct cfm *);
 bool cfm_should_send_ccm(struct cfm *);
 void cfm_compose_ccm(struct cfm *, struct dp_packet *,
-                     const uint8_t eth_src[ETH_ADDR_LEN]);
+                     const struct eth_addr eth_src);
 long long int cfm_wait(struct cfm *);
 bool cfm_configure(struct cfm *, const struct cfm_settings *);
 void cfm_set_netdev(struct cfm *, const struct netdev *);
diff --git a/lib/csum.c b/lib/csum.c
index 155ae85..c87c8dd 100644
--- a/lib/csum.c
+++ b/lib/csum.c
@@ -114,19 +114,15 @@ recalc_csum32(ovs_be16 old_csum, ovs_be32 old_u32, ovs_be32 new_u32)
 
 /* Returns the new checksum for a packet in which the checksum field previously
  * contained 'old_csum' and in which a field that contained the 6 bytes at
- * 'old_bytes' was changed to contain the 6 bytes at 'new_bytes'. */
+ * 'old_mac' was changed to contain the 6 bytes at 'new_mac'. */
 ovs_be16
-recalc_csum48(ovs_be16 old_csum, const void *old_bytes,
-              const void *new_bytes)
+recalc_csum48(ovs_be16 old_csum, const struct eth_addr old_mac,
+              const struct eth_addr new_mac)
 {
     ovs_be16 new_csum = old_csum;
-    const uint16_t *p16_old = old_bytes,
-                   *p16_new = new_bytes;
-    int i;
 
-    for (i = 0; i < 3; ++i) {
-        new_csum = recalc_csum16(new_csum, get_unaligned_be16(&p16_old[i]),
-                                 get_unaligned_be16(&p16_new[i]));
+    for (int i = 0; i < 3; ++i) {
+        new_csum = recalc_csum16(new_csum, old_mac.be16[i], new_mac.be16[i]);
     }
 
     return new_csum;
diff --git a/lib/csum.h b/lib/csum.h
index ceff001..293339d 100644
--- a/lib/csum.h
+++ b/lib/csum.h
@@ -28,8 +28,8 @@ uint32_t csum_continue(uint32_t partial, const void *, size_t);
 ovs_be16 csum_finish(uint32_t partial);
 ovs_be16 recalc_csum16(ovs_be16 old_csum, ovs_be16 old_u16, ovs_be16 new_u16);
 ovs_be16 recalc_csum32(ovs_be16 old_csum, ovs_be32 old_u32, ovs_be32 new_u32);
-ovs_be16 recalc_csum48(ovs_be16 old_csum, const void *old_bytes,
-                       const void *new_bytes);
+ovs_be16 recalc_csum48(ovs_be16 old_csum, const struct eth_addr old_mac,
+                       const struct eth_addr new_mac);
 ovs_be16 recalc_csum128(ovs_be16 old_csum, ovs_16aligned_be32 old_u32[4],
                         const ovs_be32 new_u32[4]);
 
diff --git a/lib/flow.c b/lib/flow.c
index 1dbf82f..4236e87 100644
--- a/lib/flow.c
+++ b/lib/flow.c
@@ -348,7 +348,7 @@ parse_ethertype(const void **datap, size_t *sizep)
 static inline void
 parse_icmpv6(const void **datap, size_t *sizep, const struct icmp6_hdr *icmp,
              const struct in6_addr **nd_target,
-             uint8_t arp_buf[2][ETH_ADDR_LEN])
+             struct eth_addr arp_buf[2])
 {
     if (icmp->icmp6_code == 0 &&
         (icmp->icmp6_type == ND_NEIGHBOR_SOLICIT ||
@@ -362,8 +362,8 @@ parse_icmpv6(const void **datap, size_t *sizep, const struct icmp6_hdr *icmp,
         while (*sizep >= 8) {
             /* The minimum size of an option is 8 bytes, which also is
              * the size of Ethernet link-layer options. */
-            const struct nd_opt_hdr *nd_opt = *datap;
-            int opt_len = nd_opt->nd_opt_len * 8;
+            const struct ovs_nd_opt *nd_opt = *datap;
+            int opt_len = nd_opt->nd_opt_len * ND_OPT_LEN;
 
             if (!opt_len || opt_len > *sizep) {
                 return;
@@ -373,16 +373,16 @@ parse_icmpv6(const void **datap, size_t *sizep, const struct icmp6_hdr *icmp,
              * provided.  It is considered an error if the same link
              * layer option is specified twice. */
             if (nd_opt->nd_opt_type == ND_OPT_SOURCE_LINKADDR
-                    && opt_len == 8) {
+                && opt_len == 8) {
                 if (OVS_LIKELY(eth_addr_is_zero(arp_buf[0]))) {
-                    memcpy(arp_buf[0], nd_opt + 1, ETH_ADDR_LEN);
+                    arp_buf[0] = nd_opt->nd_opt_mac;
                 } else {
                     goto invalid;
                 }
             } else if (nd_opt->nd_opt_type == ND_OPT_TARGET_LINKADDR
-                    && opt_len == 8) {
+                       && opt_len == 8) {
                 if (OVS_LIKELY(eth_addr_is_zero(arp_buf[1]))) {
-                    memcpy(arp_buf[1], nd_opt + 1, ETH_ADDR_LEN);
+                    arp_buf[1] = nd_opt->nd_opt_mac;
                 } else {
                     goto invalid;
                 }
@@ -398,9 +398,8 @@ parse_icmpv6(const void **datap, size_t *sizep, const struct icmp6_hdr *icmp,
 
 invalid:
     *nd_target = NULL;
-    memset(arp_buf[0], 0, ETH_ADDR_LEN);
-    memset(arp_buf[1], 0, ETH_ADDR_LEN);
-    return;
+    arp_buf[0] = eth_addr_zero;
+    arp_buf[1] = eth_addr_zero;
 }
 
 /* Initializes 'flow' members from 'packet' and 'md'
@@ -660,7 +659,7 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst)
     } else {
         if (dl_type == htons(ETH_TYPE_ARP) ||
             dl_type == htons(ETH_TYPE_RARP)) {
-            uint8_t arp_buf[2][ETH_ADDR_LEN];
+            struct eth_addr arp_buf[2];
             const struct arp_eth_header *arp = (const struct arp_eth_header *)
                 data_try_pull(&data, &size, ARP_ETH_HEADER_LEN);
 
@@ -682,8 +681,8 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst)
                 /* Must be adjacent. */
                 ASSERT_SEQUENTIAL(arp_sha, arp_tha);
 
-                memcpy(arp_buf[0], arp->ar_sha, ETH_ADDR_LEN);
-                memcpy(arp_buf[1], arp->ar_tha, ETH_ADDR_LEN);
+                arp_buf[0] = arp->ar_sha;
+                arp_buf[1] = arp->ar_tha;
                 miniflow_push_macs(mf, arp_sha, arp_buf);
                 miniflow_pad_to_64(mf, tcp_flags);
             }
@@ -700,7 +699,7 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst)
             if (OVS_LIKELY(size >= TCP_HEADER_LEN)) {
                 const struct tcp_header *tcp = data;
 
-                miniflow_push_be32(mf, arp_tha[2], 0);
+                miniflow_push_be32(mf, arp_tha.ea[2], 0);
                 miniflow_push_be32(mf, tcp_flags,
                                    TCP_FLAGS_BE32(tcp->tcp_ctl));
                 miniflow_push_be16(mf, tp_src, tcp->tcp_src);
@@ -743,14 +742,13 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst)
         } else if (OVS_LIKELY(nw_proto == IPPROTO_ICMPV6)) {
             if (OVS_LIKELY(size >= sizeof(struct icmp6_hdr))) {
                 const struct in6_addr *nd_target = NULL;
-                uint8_t arp_buf[2][ETH_ADDR_LEN];
+                struct eth_addr arp_buf[2] = { };
                 const struct icmp6_hdr *icmp = data_pull(&data, &size,
                                                          sizeof *icmp);
-                memset(arp_buf, 0, sizeof arp_buf);
                 parse_icmpv6(&data, &size, icmp, &nd_target, arp_buf);
                 if (nd_target) {
                     miniflow_push_words(mf, nd_target, nd_target,
-                                        sizeof *nd_target / 8);
+                                        sizeof *nd_target / sizeof(uint64_t));
                 }
                 miniflow_push_macs(mf, arp_sha, arp_buf);
                 miniflow_pad_to_64(mf, tcp_flags);
@@ -1548,15 +1546,15 @@ flow_hash_symmetric_l4(const struct flow *flow, uint32_t basis)
         ovs_be16 eth_type;
         ovs_be16 vlan_tci;
         ovs_be16 tp_port;
-        uint8_t eth_addr[ETH_ADDR_LEN];
+        struct eth_addr eth_addr;
         uint8_t ip_proto;
     } fields;
 
     int i;
 
     memset(&fields, 0, sizeof fields);
-    for (i = 0; i < ETH_ADDR_LEN; i++) {
-        fields.eth_addr[i] = flow->dl_src[i] ^ flow->dl_dst[i];
+    for (i = 0; i < ARRAY_SIZE(fields.eth_addr.be16); i++) {
+        fields.eth_addr.be16[i] = flow->dl_src.be16[i] ^ flow->dl_dst.be16[i];
     }
     fields.vlan_tci = flow->vlan_tci & htons(VLAN_VID_MASK);
     fields.eth_type = flow->dl_type;
@@ -1628,8 +1626,8 @@ flow_random_hash_fields(struct flow *flow)
     /* Initialize to all zeros. */
     memset(flow, 0, sizeof *flow);
 
-    eth_addr_random(flow->dl_src);
-    eth_addr_random(flow->dl_dst);
+    eth_addr_random(&flow->dl_src);
+    eth_addr_random(&flow->dl_dst);
 
     flow->vlan_tci = (OVS_FORCE ovs_be16) (random_uint16() & VLAN_VID_MASK);
 
@@ -1723,7 +1721,7 @@ flow_hash_fields(const struct flow *flow, enum nx_hash_fields fields,
     switch (fields) {
 
     case NX_HASH_FIELDS_ETH_SRC:
-        return jhash_bytes(flow->dl_src, sizeof flow->dl_src, basis);
+        return jhash_bytes(&flow->dl_src, sizeof flow->dl_src, basis);
 
     case NX_HASH_FIELDS_SYMMETRIC_L4:
         return flow_hash_symmetric_l4(flow, basis);
@@ -2106,7 +2104,7 @@ flow_compose_l4(struct dp_packet *p, const struct flow *flow)
                 (icmp->icmp6_type == ND_NEIGHBOR_SOLICIT ||
                  icmp->icmp6_type == ND_NEIGHBOR_ADVERT)) {
                 struct in6_addr *nd_target;
-                struct nd_opt_hdr *nd_opt;
+                struct ovs_nd_opt *nd_opt;
 
                 l4_len += sizeof *nd_target;
                 nd_target = dp_packet_put_zeros(p, sizeof *nd_target);
@@ -2117,14 +2115,14 @@ flow_compose_l4(struct dp_packet *p, const struct flow *flow)
                     nd_opt = dp_packet_put_zeros(p, 8);
                     nd_opt->nd_opt_len = 1;
                     nd_opt->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
-                    memcpy(nd_opt + 1, flow->arp_sha, ETH_ADDR_LEN);
+                    nd_opt->nd_opt_mac = flow->arp_sha;
                 }
                 if (!eth_addr_is_zero(flow->arp_tha)) {
                     l4_len += 8;
                     nd_opt = dp_packet_put_zeros(p, 8);
                     nd_opt->nd_opt_len = 1;
                     nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
-                    memcpy(nd_opt + 1, flow->arp_tha, ETH_ADDR_LEN);
+                    nd_opt->nd_opt_mac = flow->arp_tha;
                 }
             }
             icmp->icmp6_cksum = (OVS_FORCE uint16_t)
@@ -2216,8 +2214,8 @@ flow_compose(struct dp_packet *p, const struct flow *flow)
             flow->nw_proto == ARP_OP_REPLY) {
             put_16aligned_be32(&arp->ar_spa, flow->nw_src);
             put_16aligned_be32(&arp->ar_tpa, flow->nw_dst);
-            memcpy(arp->ar_sha, flow->arp_sha, ETH_ADDR_LEN);
-            memcpy(arp->ar_tha, flow->arp_tha, ETH_ADDR_LEN);
+            arp->ar_sha = flow->arp_sha;
+            arp->ar_tha = flow->arp_tha;
         }
     }
 
diff --git a/lib/flow.h b/lib/flow.h
index 25172e0..6ed7de3 100644
--- a/lib/flow.h
+++ b/lib/flow.h
@@ -107,8 +107,8 @@ struct flow {
     uint8_t pad1[6];            /* Pad to 64 bits. */
 
     /* L2, Order the same as in the Ethernet header! (64-bit aligned) */
-    uint8_t dl_dst[ETH_ADDR_LEN]; /* Ethernet destination address. */
-    uint8_t dl_src[ETH_ADDR_LEN]; /* Ethernet source address. */
+    struct eth_addr dl_dst;     /* Ethernet destination address. */
+    struct eth_addr dl_src;     /* Ethernet source address. */
     ovs_be16 dl_type;           /* Ethernet frame type. */
     ovs_be16 vlan_tci;          /* If 802.1Q, TCI | VLAN_CFI; otherwise 0. */
     ovs_be32 mpls_lse[ROUND_UP(FLOW_MAX_MPLS_LABELS, 2)]; /* MPLS label stack
@@ -124,8 +124,8 @@ struct flow {
     uint8_t nw_ttl;             /* IP TTL/Hop Limit. */
     uint8_t nw_proto;           /* IP protocol or low 8 bits of ARP opcode. */
     struct in6_addr nd_target;  /* IPv6 neighbor discovery (ND) target. */
-    uint8_t arp_sha[ETH_ADDR_LEN]; /* ARP/ND source hardware address. */
-    uint8_t arp_tha[ETH_ADDR_LEN]; /* ARP/ND target hardware address. */
+    struct eth_addr arp_sha;    /* ARP/ND source hardware address. */
+    struct eth_addr arp_tha;    /* ARP/ND target hardware address. */
     ovs_be16 tcp_flags;         /* TCP flags. With L3 to avoid matching L4. */
     ovs_be16 pad2;              /* Pad to 64 bits. */
 
diff --git a/lib/lacp.c b/lib/lacp.c
index 29b8b43..c5d0fb1 100644
--- a/lib/lacp.c
+++ b/lib/lacp.c
@@ -53,7 +53,7 @@ VLOG_DEFINE_THIS_MODULE(lacp);
 OVS_PACKED(
 struct lacp_info {
     ovs_be16 sys_priority;            /* System priority. */
-    uint8_t sys_id[ETH_ADDR_LEN];     /* System ID. */
+    struct eth_addr sys_id;           /* System ID. */
     ovs_be16 key;                     /* Operational key. */
     ovs_be16 port_priority;           /* Port priority. */
     ovs_be16 port_id;                 /* Port ID. */
@@ -94,7 +94,7 @@ enum slave_status {
 struct lacp {
     struct ovs_list node;         /* Node in all_lacps list. */
     char *name;                   /* Name of this lacp object. */
-    uint8_t sys_id[ETH_ADDR_LEN]; /* System ID. */
+    struct eth_addr sys_id;       /* System ID. */
     uint16_t sys_priority;        /* System Priority. */
     bool active;                  /* Active or Passive. */
 
@@ -286,7 +286,7 @@ lacp_configure(struct lacp *lacp, const struct lacp_settings *s)
 
     if (!eth_addr_equals(lacp->sys_id, s->id)
         || lacp->sys_priority != s->priority) {
-        memcpy(lacp->sys_id, s->id, ETH_ADDR_LEN);
+        lacp->sys_id = s->id;
         lacp->sys_priority = s->priority;
         lacp->update = true;
     }
@@ -732,7 +732,7 @@ slave_get_actor(struct slave *slave, struct lacp_info *actor)
     actor->port_priority = htons(slave->port_priority);
     actor->port_id = htons(slave->port_id);
     actor->sys_priority = htons(lacp->sys_priority);
-    memcpy(&actor->sys_id, lacp->sys_id, ETH_ADDR_LEN);
+    actor->sys_id = lacp->sys_id;
 }
 
 /* Given 'slave', populates 'priority' with data representing its LACP link
@@ -1002,12 +1002,8 @@ lacp_get_slave_stats(const struct lacp *lacp, const void *slave_, struct lacp_sl
     if (slave) {
 	ret = true;
 	slave_get_actor(slave, &actor);
-	memcpy(&stats->dot3adAggPortActorSystemID,
-	       actor.sys_id,
-	       ETH_ADDR_LEN);
-	memcpy(&stats->dot3adAggPortPartnerOperSystemID,
-	       slave->partner.sys_id,
-	       ETH_ADDR_LEN);
+	stats->dot3adAggPortActorSystemID = actor.sys_id;
+	stats->dot3adAggPortPartnerOperSystemID = slave->partner.sys_id;
 	stats->dot3adAggPortAttachedAggID = (lacp->key_slave->key ?
 					     lacp->key_slave->key :
 					     lacp->key_slave->port_id);
diff --git a/lib/lacp.h b/lib/lacp.h
index f56001b..f35cff5 100644
--- a/lib/lacp.h
+++ b/lib/lacp.h
@@ -31,7 +31,7 @@ enum lacp_status {
 
 struct lacp_settings {
     char *name;                       /* Name (for debugging). */
-    uint8_t id[ETH_ADDR_LEN];         /* System ID. Must be nonzero. */
+    struct eth_addr id;               /* System ID. Must be nonzero. */
     uint16_t priority;                /* System priority. */
     bool active;                      /* Active or passive mode? */
     bool fast;                        /* Fast or slow probe interval. */
@@ -72,8 +72,8 @@ void lacp_wait(struct lacp *);
 
 struct lacp_slave_stats {
     /* id */
-    uint8_t dot3adAggPortActorSystemID[ETH_ADDR_LEN];
-    uint8_t dot3adAggPortPartnerOperSystemID[ETH_ADDR_LEN];
+    struct eth_addr dot3adAggPortActorSystemID;
+    struct eth_addr dot3adAggPortPartnerOperSystemID;
     uint32_t dot3adAggPortAttachedAggID;
     /* state */
     uint8_t dot3adAggPortActorAdminState;
diff --git a/lib/lldp/aa-structs.h b/lib/lldp/aa-structs.h
index 983c74c..473031e 100644
--- a/lib/lldp/aa-structs.h
+++ b/lib/lldp/aa-structs.h
@@ -24,7 +24,7 @@
 #include "list.h"
 
 struct lldp_aa_element_system_id {
-    uint8_t  system_mac[6];
+    struct eth_addr system_mac;
     uint16_t conn_type;
     uint16_t rsvd;
     uint8_t  rsvd2[2];
diff --git a/lib/lldp/lldp-tlv.h b/lib/lldp/lldp-tlv.h
index 2b94828..f54493d 100644
--- a/lib/lldp/lldp-tlv.h
+++ b/lib/lldp/lldp-tlv.h
@@ -18,8 +18,8 @@
 #ifndef _LLDP_TLV_H
 #define _LLDP_TLV_H
 
-#define LLDP_MULTICAST_ADDR    {        \
-    0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e  \
+#define LLDP_MULTICAST_ADDR    {                \
+    { { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e } }  \
 }
 
 #define LLDP_TLV_END            0
diff --git a/lib/lldp/lldp.c b/lib/lldp/lldp.c
index 493c2ff..0340f67 100644
--- a/lib/lldp/lldp.c
+++ b/lib/lldp/lldp.c
@@ -349,7 +349,7 @@ lldp_decode(struct lldpd *cfg OVS_UNUSED, char *frame, int s,
 {
     struct lldpd_chassis *chassis;
     struct lldpd_port *port;
-    const char lldpaddr[] = LLDP_MULTICAST_ADDR;
+    const struct eth_addr lldpaddr = LLDP_MULTICAST_ADDR;
     const char dot1[] = LLDP_TLV_ORG_DOT1;
     const char dot3[] = LLDP_TLV_ORG_DOT3;
     const char med[] = LLDP_TLV_ORG_MED;
@@ -384,7 +384,7 @@ lldp_decode(struct lldpd *cfg OVS_UNUSED, char *frame, int s,
         VLOG_WARN("too short frame received on %s", hardware->h_ifname);
         goto malformed;
     }
-    if (PEEK_CMP(lldpaddr, ETH_ADDR_LEN) != 0) {
+    if (PEEK_CMP(&lldpaddr, ETH_ADDR_LEN) != 0) {
         VLOG_INFO("frame not targeted at LLDP multicast address "
                   "received on %s", hardware->h_ifname);
         goto malformed;
diff --git a/lib/lldp/lldpd-structs.h b/lib/lldp/lldpd-structs.h
index 59d239c..15e5ce8 100644
--- a/lib/lldp/lldpd-structs.h
+++ b/lib/lldp/lldpd-structs.h
@@ -182,7 +182,7 @@ struct lldpd_hardware {
                                    * to 0. */
     int               h_ifindex;  /* Interface index, used by SNMP */
     char              h_ifname[IFNAMSIZ]; /* Should be unique */
-    u_int8_t          h_lladdr[ETH_ADDR_LEN];
+    struct eth_addr   h_lladdr;
 
     u_int64_t         h_tx_cnt;
     u_int64_t         h_rx_cnt;
diff --git a/lib/lldp/lldpd.c b/lib/lldp/lldpd.c
index 71d3938..71f7e44 100644
--- a/lib/lldp/lldpd.c
+++ b/lib/lldp/lldpd.c
@@ -50,7 +50,7 @@ static struct protocol protos[] =
     { LLDPD_MODE_LLDP, 1, "LLDP", 'l', lldp_send, lldp_decode, NULL,
       LLDP_MULTICAST_ADDR },
     { 0, 0, "any", ' ', NULL, NULL, NULL,
-    { 0,0,0,0,0,0 } }
+      { { { 0,0,0,0,0,0 } } } }
 };
 
 void lldpd_assign_cfg_to_protocols(struct lldpd *cfg)
@@ -209,7 +209,7 @@ lldpd_guess_type(struct lldpd *cfg, char *frame, int s)
             continue;
         }
         if (cfg->g_protocols[i].guess == NULL) {
-            if (memcmp(frame, cfg->g_protocols[i].mac, ETH_ADDR_LEN) == 0) {
+            if (memcmp(frame, &cfg->g_protocols[i].mac, ETH_ADDR_LEN) == 0) {
                 VLOG_DBG("guessed protocol is %s (from MAC address)",
                     cfg->g_protocols[i].name);
                 return cfg->g_protocols[i].mode;
diff --git a/lib/lldp/lldpd.h b/lib/lldp/lldpd.h
index 6bd4b05..c295ab4 100644
--- a/lib/lldp/lldpd.h
+++ b/lib/lldp/lldpd.h
@@ -54,9 +54,7 @@ struct protocol {
     int(*guess)(PROTO_GUESS_SIG);   /* Can be NULL, use MAC address in this
                                      * case
                                      */
-    u_int8_t mac[ETH_ADDR_LEN];  /* Destination MAC address used by this
-                                  * protocol
-                                  */
+    struct eth_addr mac;  /* Destination MAC address used by this protocol */
 };
 
 #define SMART_HIDDEN(port) (port->p_hidden_in)
diff --git a/lib/mac-learning.c b/lib/mac-learning.c
index 190920b..f7c2781 100644
--- a/lib/mac-learning.c
+++ b/lib/mac-learning.c
@@ -42,7 +42,7 @@ mac_entry_age(const struct mac_learning *ml, const struct mac_entry *e)
 }
 
 static uint32_t
-mac_table_hash(const struct mac_learning *ml, const uint8_t mac[ETH_ADDR_LEN],
+mac_table_hash(const struct mac_learning *ml, const struct eth_addr mac,
                uint16_t vlan)
 {
     return hash_mac(mac, vlan, ml->secret);
@@ -56,7 +56,7 @@ mac_entry_from_lru_node(struct ovs_list *list)
 
 static struct mac_entry *
 mac_entry_lookup(const struct mac_learning *ml,
-                 const uint8_t mac[ETH_ADDR_LEN], uint16_t vlan)
+                 const struct eth_addr mac, uint16_t vlan)
 {
     struct mac_entry *e;
 
@@ -286,7 +286,7 @@ is_learning_vlan(const struct mac_learning *ml, uint16_t vlan)
  * 'vlan' is configured on 'ml' to flood all packets. */
 bool
 mac_learning_may_learn(const struct mac_learning *ml,
-                       const uint8_t src_mac[ETH_ADDR_LEN], uint16_t vlan)
+                       const struct eth_addr src_mac, uint16_t vlan)
 {
     return ml && is_learning_vlan(ml, vlan) && !eth_addr_is_multicast(src_mac);
 }
@@ -301,7 +301,7 @@ mac_learning_may_learn(const struct mac_learning *ml,
  * the new entry's port to a nonnull value with mac_entry_set_port(). */
 struct mac_entry *
 mac_learning_insert(struct mac_learning *ml,
-                    const uint8_t src_mac[ETH_ADDR_LEN], uint16_t vlan)
+                    const struct eth_addr src_mac, uint16_t vlan)
 {
     struct mac_entry *e;
 
@@ -315,7 +315,7 @@ mac_learning_insert(struct mac_learning *ml,
 
         e = xmalloc(sizeof *e);
         hmap_insert(&ml->table, &e->hmap_node, hash);
-        memcpy(e->mac, src_mac, ETH_ADDR_LEN);
+        e->mac = src_mac;
         e->vlan = vlan;
         e->grat_arp_lock = TIME_MIN;
         e->mlport = NULL;
@@ -339,7 +339,7 @@ mac_learning_insert(struct mac_learning *ml,
  * learning entry, if any. */
 struct mac_entry *
 mac_learning_lookup(const struct mac_learning *ml,
-                    const uint8_t dst[ETH_ADDR_LEN], uint16_t vlan)
+                    const struct eth_addr dst, uint16_t vlan)
 {
     if (eth_addr_is_multicast(dst)) {
         /* No tag because the treatment of multicast destinations never
diff --git a/lib/mac-learning.h b/lib/mac-learning.h
index 079b043..1f41706 100644
--- a/lib/mac-learning.h
+++ b/lib/mac-learning.h
@@ -104,7 +104,7 @@ struct mac_entry {
     struct hmap_node hmap_node; /* Node in a mac_learning hmap. */
     time_t expires;             /* Expiration time. */
     time_t grat_arp_lock;       /* Gratuitous ARP lock expiration time. */
-    uint8_t mac[ETH_ADDR_LEN];  /* Known MAC address. */
+    struct eth_addr mac;        /* Known MAC address. */
     uint16_t vlan;              /* VLAN tag. */
 
     /* The following are marked guarded to prevent users from iterating over or
@@ -200,17 +200,17 @@ void mac_learning_set_max_entries(struct mac_learning *ml, size_t max_entries)
 
 /* Learning. */
 bool mac_learning_may_learn(const struct mac_learning *ml,
-                            const uint8_t src_mac[ETH_ADDR_LEN],
+                            const struct eth_addr src_mac,
                             uint16_t vlan)
     OVS_REQ_RDLOCK(ml->rwlock);
 struct mac_entry *mac_learning_insert(struct mac_learning *ml,
-                                      const uint8_t src[ETH_ADDR_LEN],
+                                      const struct eth_addr src,
                                       uint16_t vlan)
     OVS_REQ_WRLOCK(ml->rwlock);
 
 /* Lookup. */
 struct mac_entry *mac_learning_lookup(const struct mac_learning *ml,
-                                      const uint8_t dst[ETH_ADDR_LEN],
+                                      const struct eth_addr dst,
                                       uint16_t vlan)
     OVS_REQ_RDLOCK(ml->rwlock);
 
diff --git a/lib/match.c b/lib/match.c
index 0177f82..9e465d8 100644
--- a/lib/match.c
+++ b/lib/match.c
@@ -294,55 +294,54 @@ match_set_dl_type(struct match *match, ovs_be16 dl_type)
 /* Modifies 'value_src' so that the Ethernet address must match 'value_dst'
  * exactly.  'mask_dst' is set to all 1s. */
 static void
-set_eth(const uint8_t value_src[ETH_ADDR_LEN],
-        uint8_t value_dst[ETH_ADDR_LEN],
-        uint8_t mask_dst[ETH_ADDR_LEN])
+set_eth(const struct eth_addr value_src,
+        struct eth_addr *value_dst,
+        struct eth_addr *mask_dst)
 {
-    memcpy(value_dst, value_src, ETH_ADDR_LEN);
-    memset(mask_dst, 0xff, ETH_ADDR_LEN);
+    *value_dst = value_src;
+    *mask_dst = eth_addr_exact;
 }
 
 /* Modifies 'value_src' so that the Ethernet address must match 'value_src'
  * after each byte is ANDed with the appropriate byte in 'mask_src'.
  * 'mask_dst' is set to 'mask_src' */
 static void
-set_eth_masked(const uint8_t value_src[ETH_ADDR_LEN],
-               const uint8_t mask_src[ETH_ADDR_LEN],
-               uint8_t value_dst[ETH_ADDR_LEN],
-               uint8_t mask_dst[ETH_ADDR_LEN])
+set_eth_masked(const struct eth_addr value_src,
+               const struct eth_addr mask_src,
+               struct eth_addr *value_dst, struct eth_addr *mask_dst)
 {
     size_t i;
 
-    for (i = 0; i < ETH_ADDR_LEN; i++) {
-        value_dst[i] = value_src[i] & mask_src[i];
-        mask_dst[i] = mask_src[i];
+    for (i = 0; i < ARRAY_SIZE(value_dst->be16); i++) {
+        value_dst->be16[i] = value_src.be16[i] & mask_src.be16[i];
     }
+    *mask_dst = mask_src;
 }
 
 /* Modifies 'rule' so that the source Ethernet address must match 'dl_src'
  * exactly. */
 void
-match_set_dl_src(struct match *match, const uint8_t dl_src[ETH_ADDR_LEN])
+match_set_dl_src(struct match *match, const struct eth_addr dl_src)
 {
-    set_eth(dl_src, match->flow.dl_src, match->wc.masks.dl_src);
+    set_eth(dl_src, &match->flow.dl_src, &match->wc.masks.dl_src);
 }
 
 /* Modifies 'rule' so that the source Ethernet address must match 'dl_src'
  * after each byte is ANDed with the appropriate byte in 'mask'. */
 void
 match_set_dl_src_masked(struct match *match,
-                        const uint8_t dl_src[ETH_ADDR_LEN],
-                        const uint8_t mask[ETH_ADDR_LEN])
+                        const struct eth_addr dl_src,
+                        const struct eth_addr mask)
 {
-    set_eth_masked(dl_src, mask, match->flow.dl_src, match->wc.masks.dl_src);
+    set_eth_masked(dl_src, mask, &match->flow.dl_src, &match->wc.masks.dl_src);
 }
 
 /* Modifies 'match' so that the Ethernet address must match 'dl_dst'
  * exactly. */
 void
-match_set_dl_dst(struct match *match, const uint8_t dl_dst[ETH_ADDR_LEN])
+match_set_dl_dst(struct match *match, const struct eth_addr dl_dst)
 {
-    set_eth(dl_dst, match->flow.dl_dst, match->wc.masks.dl_dst);
+    set_eth(dl_dst, &match->flow.dl_dst, &match->wc.masks.dl_dst);
 }
 
 /* Modifies 'match' so that the Ethernet address must match 'dl_dst' after each
@@ -352,10 +351,10 @@ match_set_dl_dst(struct match *match, const uint8_t dl_dst[ETH_ADDR_LEN])
  * accepted by flow_wildcards_is_dl_dst_mask_valid() are allowed. */
 void
 match_set_dl_dst_masked(struct match *match,
-                        const uint8_t dl_dst[ETH_ADDR_LEN],
-                        const uint8_t mask[ETH_ADDR_LEN])
+                        const struct eth_addr dl_dst,
+                        const struct eth_addr mask)
 {
-    set_eth_masked(dl_dst, mask, match->flow.dl_dst, match->wc.masks.dl_dst);
+    set_eth_masked(dl_dst, mask, &match->flow.dl_dst, &match->wc.masks.dl_dst);
 }
 
 void
@@ -644,35 +643,35 @@ match_set_icmp_code(struct match *match, uint8_t icmp_code)
 }
 
 void
-match_set_arp_sha(struct match *match, const uint8_t sha[ETH_ADDR_LEN])
+match_set_arp_sha(struct match *match, const struct eth_addr sha)
 {
-    memcpy(match->flow.arp_sha, sha, ETH_ADDR_LEN);
-    memset(match->wc.masks.arp_sha, UINT8_MAX, ETH_ADDR_LEN);
+    match->flow.arp_sha = sha;
+    match->wc.masks.arp_sha = eth_addr_exact;
 }
 
 void
 match_set_arp_sha_masked(struct match *match,
-                         const uint8_t arp_sha[ETH_ADDR_LEN],
-                         const uint8_t mask[ETH_ADDR_LEN])
+                         const struct eth_addr arp_sha,
+                         const struct eth_addr mask)
 {
     set_eth_masked(arp_sha, mask,
-                   match->flow.arp_sha, match->wc.masks.arp_sha);
+                   &match->flow.arp_sha, &match->wc.masks.arp_sha);
 }
 
 void
-match_set_arp_tha(struct match *match, const uint8_t tha[ETH_ADDR_LEN])
+match_set_arp_tha(struct match *match, const struct eth_addr tha)
 {
-    memcpy(match->flow.arp_tha, tha, ETH_ADDR_LEN);
-    memset(match->wc.masks.arp_tha, UINT8_MAX, ETH_ADDR_LEN);
+    match->flow.arp_tha = tha;
+    match->wc.masks.arp_tha = eth_addr_exact;
 }
 
 void
 match_set_arp_tha_masked(struct match *match,
-                         const uint8_t arp_tha[ETH_ADDR_LEN],
-                         const uint8_t mask[ETH_ADDR_LEN])
+                         const struct eth_addr arp_tha,
+                         const struct eth_addr mask)
 {
     set_eth_masked(arp_tha, mask,
-                   match->flow.arp_tha, match->wc.masks.arp_tha);
+                   &match->flow.arp_tha, &match->wc.masks.arp_tha);
 }
 
 void
@@ -784,12 +783,11 @@ match_init_hidden_fields(struct match *m)
 
 static void
 format_eth_masked(struct ds *s, const char *name,
-                  const uint8_t eth[ETH_ADDR_LEN],
-                  const uint8_t mask[ETH_ADDR_LEN])
+                  const struct eth_addr eth, const struct eth_addr mask)
 {
     if (!eth_addr_is_zero(mask)) {
         ds_put_format(s, "%s=", name);
-        eth_format_masked(eth, mask, s);
+        eth_format_masked(eth, &mask, s);
         ds_put_char(s, ',');
     }
 }
diff --git a/lib/match.h b/lib/match.h
index 6356a55..3e133e5 100644
--- a/lib/match.h
+++ b/lib/match.h
@@ -85,12 +85,12 @@ void match_set_pkt_mark(struct match *, uint32_t pkt_mark);
 void match_set_pkt_mark_masked(struct match *, uint32_t pkt_mark, uint32_t mask);
 void match_set_skb_priority(struct match *, uint32_t skb_priority);
 void match_set_dl_type(struct match *, ovs_be16);
-void match_set_dl_src(struct match *, const uint8_t[ETH_ADDR_LEN]);
-void match_set_dl_src_masked(struct match *, const uint8_t dl_src[ETH_ADDR_LEN],
-                             const uint8_t mask[ETH_ADDR_LEN]);
-void match_set_dl_dst(struct match *, const uint8_t[ETH_ADDR_LEN]);
-void match_set_dl_dst_masked(struct match *, const uint8_t dl_dst[ETH_ADDR_LEN],
-                             const uint8_t mask[ETH_ADDR_LEN]);
+void match_set_dl_src(struct match *, const struct eth_addr );
+void match_set_dl_src_masked(struct match *, const struct eth_addr dl_src,
+                             const struct eth_addr mask);
+void match_set_dl_dst(struct match *, const struct eth_addr);
+void match_set_dl_dst_masked(struct match *, const struct eth_addr dl_dst,
+                             const struct eth_addr mask);
 void match_set_dl_tci(struct match *, ovs_be16 tci);
 void match_set_dl_tci_masked(struct match *, ovs_be16 tci, ovs_be16 mask);
 void match_set_any_vid(struct match *);
@@ -126,14 +126,14 @@ void match_set_nw_frag(struct match *, uint8_t nw_frag);
 void match_set_nw_frag_masked(struct match *, uint8_t nw_frag, uint8_t mask);
 void match_set_icmp_type(struct match *, uint8_t);
 void match_set_icmp_code(struct match *, uint8_t);
-void match_set_arp_sha(struct match *, const uint8_t[ETH_ADDR_LEN]);
+void match_set_arp_sha(struct match *, const struct eth_addr);
 void match_set_arp_sha_masked(struct match *,
-                              const uint8_t arp_sha[ETH_ADDR_LEN],
-                              const uint8_t mask[ETH_ADDR_LEN]);
-void match_set_arp_tha(struct match *, const uint8_t[ETH_ADDR_LEN]);
+                              const struct eth_addr arp_sha,
+                              const struct eth_addr mask);
+void match_set_arp_tha(struct match *, const struct eth_addr);
 void match_set_arp_tha_masked(struct match *,
-                              const uint8_t arp_tha[ETH_ADDR_LEN],
-                              const uint8_t mask[ETH_ADDR_LEN]);
+                              const struct eth_addr arp_tha,
+                              const struct eth_addr mask);
 void match_set_ipv6_src(struct match *, const struct in6_addr *);
 void match_set_ipv6_src_masked(struct match *, const struct in6_addr *,
                                const struct in6_addr *);
diff --git a/lib/meta-flow.c b/lib/meta-flow.c
index 5a46ce4..ed0041f 100644
--- a/lib/meta-flow.c
+++ b/lib/meta-flow.c
@@ -656,11 +656,11 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow,
         break;
 
     case MFF_ETH_SRC:
-        memcpy(value->mac, flow->dl_src, ETH_ADDR_LEN);
+        value->mac = flow->dl_src;
         break;
 
     case MFF_ETH_DST:
-        memcpy(value->mac, flow->dl_dst, ETH_ADDR_LEN);
+        value->mac = flow->dl_dst;
         break;
 
     case MFF_ETH_TYPE:
@@ -753,12 +753,12 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow,
 
     case MFF_ARP_SHA:
     case MFF_ND_SLL:
-        memcpy(value->mac, flow->arp_sha, ETH_ADDR_LEN);
+        value->mac = flow->arp_sha;
         break;
 
     case MFF_ARP_THA:
     case MFF_ND_TLL:
-        memcpy(value->mac, flow->arp_tha, ETH_ADDR_LEN);
+        value->mac = flow->arp_tha;
         break;
 
     case MFF_TCP_SRC:
@@ -1155,11 +1155,11 @@ mf_set_flow_value(const struct mf_field *mf,
         break;
 
     case MFF_ETH_SRC:
-        memcpy(flow->dl_src, value->mac, ETH_ADDR_LEN);
+        flow->dl_src = value->mac;
         break;
 
     case MFF_ETH_DST:
-        memcpy(flow->dl_dst, value->mac, ETH_ADDR_LEN);
+        flow->dl_dst = value->mac;
         break;
 
     case MFF_ETH_TYPE:
@@ -1255,12 +1255,12 @@ mf_set_flow_value(const struct mf_field *mf,
 
     case MFF_ARP_SHA:
     case MFF_ND_SLL:
-        memcpy(flow->arp_sha, value->mac, ETH_ADDR_LEN);
+        flow->arp_sha = value->mac;
         break;
 
     case MFF_ARP_THA:
     case MFF_ND_TLL:
-        memcpy(flow->arp_tha, value->mac, ETH_ADDR_LEN);
+        flow->arp_tha = value->mac;
         break;
 
     case MFF_TCP_SRC:
@@ -1423,13 +1423,13 @@ mf_set_wild(const struct mf_field *mf, struct match *match)
         break;
 
     case MFF_ETH_SRC:
-        memset(match->flow.dl_src, 0, ETH_ADDR_LEN);
-        memset(match->wc.masks.dl_src, 0, ETH_ADDR_LEN);
+        match->flow.dl_src = eth_addr_zero;
+        match->wc.masks.dl_src = eth_addr_zero;
         break;
 
     case MFF_ETH_DST:
-        memset(match->flow.dl_dst, 0, ETH_ADDR_LEN);
-        memset(match->wc.masks.dl_dst, 0, ETH_ADDR_LEN);
+        match->flow.dl_dst = eth_addr_zero;
+        match->wc.masks.dl_dst = eth_addr_zero;
         break;
 
     case MFF_ETH_TYPE:
@@ -1521,14 +1521,14 @@ mf_set_wild(const struct mf_field *mf, struct match *match)
 
     case MFF_ARP_SHA:
     case MFF_ND_SLL:
-        memset(match->flow.arp_sha, 0, ETH_ADDR_LEN);
-        memset(match->wc.masks.arp_sha, 0, ETH_ADDR_LEN);
+        match->flow.arp_sha = eth_addr_zero;
+        match->wc.masks.arp_sha = eth_addr_zero;
         break;
 
     case MFF_ARP_THA:
     case MFF_ND_TLL:
-        memset(match->flow.arp_tha, 0, ETH_ADDR_LEN);
-        memset(match->wc.masks.arp_tha, 0, ETH_ADDR_LEN);
+        match->flow.arp_tha = eth_addr_zero;
+        match->wc.masks.arp_tha = eth_addr_zero;
         break;
 
     case MFF_TCP_SRC:
@@ -1858,23 +1858,22 @@ syntax_error:
 
 static char *
 mf_from_ethernet_string(const struct mf_field *mf, const char *s,
-                        uint8_t mac[ETH_ADDR_LEN],
-                        uint8_t mask[ETH_ADDR_LEN])
+                        struct eth_addr *mac, struct eth_addr *mask)
 {
     int n;
 
     ovs_assert(mf->n_bytes == ETH_ADDR_LEN);
 
     n = -1;
-    if (ovs_scan(s, ETH_ADDR_SCAN_FMT"%n", ETH_ADDR_SCAN_ARGS(mac), &n)
+    if (ovs_scan(s, ETH_ADDR_SCAN_FMT"%n", ETH_ADDR_SCAN_ARGS(*mac), &n)
         && n == strlen(s)) {
-        memset(mask, 0xff, ETH_ADDR_LEN);
+        *mask = eth_addr_exact;
         return NULL;
     }
 
     n = -1;
     if (ovs_scan(s, ETH_ADDR_SCAN_FMT"/"ETH_ADDR_SCAN_FMT"%n",
-                 ETH_ADDR_SCAN_ARGS(mac), ETH_ADDR_SCAN_ARGS(mask), &n)
+                 ETH_ADDR_SCAN_ARGS(*mac), ETH_ADDR_SCAN_ARGS(*mask), &n)
         && n == strlen(s)) {
         return NULL;
     }
@@ -2081,7 +2080,7 @@ mf_parse(const struct mf_field *mf, const char *s,
         break;
 
     case MFS_ETHERNET:
-        error = mf_from_ethernet_string(mf, s, value->mac, mask->mac);
+        error = mf_from_ethernet_string(mf, s, &value->mac, &mask->mac);
         break;
 
     case MFS_IPV4:
@@ -2237,7 +2236,7 @@ mf_format(const struct mf_field *mf,
         break;
 
     case MFS_ETHERNET:
-        eth_format_masked(value->mac, mask->mac, s);
+        eth_format_masked(value->mac, mask ? &mask->mac : NULL, s);
         break;
 
     case MFS_IPV4:
diff --git a/lib/meta-flow.h b/lib/meta-flow.h
index 323da02..0966f10 100644
--- a/lib/meta-flow.h
+++ b/lib/meta-flow.h
@@ -1741,7 +1741,7 @@ struct mf_field {
 union mf_value {
     uint8_t tun_metadata[128];
     struct in6_addr ipv6;
-    uint8_t mac[ETH_ADDR_LEN];
+    struct eth_addr mac;
     ovs_be64 be64;
     ovs_be32 be32;
     ovs_be16 be16;
@@ -1779,7 +1779,7 @@ union mf_subvalue {
     };
     struct {
         uint8_t dummy_mac[122];
-        uint8_t mac[6];
+        struct eth_addr mac;
     };
     struct {
         ovs_be32 dummy_ipv4[31];
diff --git a/lib/netdev-bsd.c b/lib/netdev-bsd.c
index 03101a8..f755475 100644
--- a/lib/netdev-bsd.c
+++ b/lib/netdev-bsd.c
@@ -89,7 +89,7 @@ struct netdev_bsd {
     unsigned int cache_valid;
 
     int ifindex;
-    uint8_t etheraddr[ETH_ADDR_LEN];
+    struct eth_addr etheraddr;
     struct in_addr in4;
     struct in_addr netmask;
     struct in6_addr in6;
@@ -137,9 +137,9 @@ static int set_flags(const char *, int flags);
 static int do_set_addr(struct netdev *netdev,
                        unsigned long ioctl_nr, const char *ioctl_name,
                        struct in_addr addr);
-static int get_etheraddr(const char *netdev_name, uint8_t ea[ETH_ADDR_LEN]);
+static int get_etheraddr(const char *netdev_name, struct eth_addr *ea);
 static int set_etheraddr(const char *netdev_name, int hwaddr_family,
-                         int hwaddr_len, const uint8_t[ETH_ADDR_LEN]);
+                         int hwaddr_len, const struct eth_addr);
 static int get_ifindex(const struct netdev *, int *ifindexp);
 
 static int ifr_get_flags(const struct ifreq *);
@@ -769,7 +769,7 @@ netdev_bsd_send_wait(struct netdev *netdev_, int qid OVS_UNUSED)
  */
 static int
 netdev_bsd_set_etheraddr(struct netdev *netdev_,
-                         const uint8_t mac[ETH_ADDR_LEN])
+                         const struct eth_addr mac)
 {
     struct netdev_bsd *netdev = netdev_bsd_cast(netdev_);
     int error = 0;
@@ -781,7 +781,7 @@ netdev_bsd_set_etheraddr(struct netdev *netdev_,
                               ETH_ADDR_LEN, mac);
         if (!error) {
             netdev->cache_valid |= VALID_ETHERADDR;
-            memcpy(netdev->etheraddr, mac, ETH_ADDR_LEN);
+            netdev->etheraddr = mac;
             netdev_change_seq_changed(netdev_);
         }
     }
@@ -795,8 +795,7 @@ netdev_bsd_set_etheraddr(struct netdev *netdev_,
  * free the returned buffer.
  */
 static int
-netdev_bsd_get_etheraddr(const struct netdev *netdev_,
-                         uint8_t mac[ETH_ADDR_LEN])
+netdev_bsd_get_etheraddr(const struct netdev *netdev_, struct eth_addr *mac)
 {
     struct netdev_bsd *netdev = netdev_bsd_cast(netdev_);
     int error = 0;
@@ -804,13 +803,13 @@ netdev_bsd_get_etheraddr(const struct netdev *netdev_,
     ovs_mutex_lock(&netdev->mutex);
     if (!(netdev->cache_valid & VALID_ETHERADDR)) {
         error = get_etheraddr(netdev_get_kernel_name(netdev_),
-                              netdev->etheraddr);
+                              &netdev->etheraddr);
         if (!error) {
             netdev->cache_valid |= VALID_ETHERADDR;
         }
     }
     if (!error) {
-        memcpy(mac, netdev->etheraddr, ETH_ADDR_LEN);
+        *mac = netdev->etheraddr;
     }
     ovs_mutex_unlock(&netdev->mutex);
 
@@ -1408,7 +1407,7 @@ netdev_bsd_get_next_hop(const struct in_addr *host OVS_UNUSED,
 static int
 netdev_bsd_arp_lookup(const struct netdev *netdev OVS_UNUSED,
                       ovs_be32 ip OVS_UNUSED,
-		      uint8_t mac[ETH_ADDR_LEN] OVS_UNUSED)
+                      struct eth_addr *mac OVS_UNUSED)
 {
 #if defined(__NetBSD__)
     const struct rt_msghdr *rtm;
@@ -1678,7 +1677,7 @@ get_ifindex(const struct netdev *netdev_, int *ifindexp)
 }
 
 static int
-get_etheraddr(const char *netdev_name, uint8_t ea[ETH_ADDR_LEN])
+get_etheraddr(const char *netdev_name, struct eth_addr *ea)
 {
     struct ifaddrs *head;
     struct ifaddrs *ifa;
@@ -1711,7 +1710,7 @@ get_etheraddr(const char *netdev_name, uint8_t ea[ETH_ADDR_LEN])
 static int
 set_etheraddr(const char *netdev_name OVS_UNUSED, int hwaddr_family OVS_UNUSED,
               int hwaddr_len OVS_UNUSED,
-              const uint8_t mac[ETH_ADDR_LEN] OVS_UNUSED)
+              const struct eth_addr mac OVS_UNUSED)
 {
 #if defined(__FreeBSD__)
     struct ifreq ifr;
@@ -1721,7 +1720,7 @@ set_etheraddr(const char *netdev_name OVS_UNUSED, int hwaddr_family OVS_UNUSED,
     ovs_strlcpy(ifr.ifr_name, netdev_name, sizeof ifr.ifr_name);
     ifr.ifr_addr.sa_family = hwaddr_family;
     ifr.ifr_addr.sa_len = hwaddr_len;
-    memcpy(ifr.ifr_addr.sa_data, mac, hwaddr_len);
+    memcpy(ifr.ifr_addr.sa_data, &mac, hwaddr_len);
     error = af_inet_ioctl(SIOCSIFLLADDR, &ifr);
     if (error) {
         VLOG_ERR("ioctl(SIOCSIFLLADDR) on %s device failed: %s",
diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c
index 3444bb1..4ce0a1e 100644
--- a/lib/netdev-dpdk.c
+++ b/lib/netdev-dpdk.c
@@ -204,7 +204,7 @@ struct netdev_dpdk {
     /* Protects stats */
     rte_spinlock_t stats_lock;
 
-    uint8_t hwaddr[ETH_ADDR_LEN];
+    struct eth_addr hwaddr;
     enum netdev_flags flags;
 
     struct rte_eth_link link;
@@ -1265,14 +1265,13 @@ netdev_dpdk_eth_send(struct netdev *netdev, int qid,
 }
 
 static int
-netdev_dpdk_set_etheraddr(struct netdev *netdev,
-                          const uint8_t mac[ETH_ADDR_LEN])
+netdev_dpdk_set_etheraddr(struct netdev *netdev, const struct eth_addr mac)
 {
     struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
 
     ovs_mutex_lock(&dev->mutex);
     if (!eth_addr_equals(dev->hwaddr, mac)) {
-        memcpy(dev->hwaddr, mac, ETH_ADDR_LEN);
+        dev->hwaddr = mac;
         netdev_change_seq_changed(netdev);
     }
     ovs_mutex_unlock(&dev->mutex);
@@ -1281,13 +1280,12 @@ netdev_dpdk_set_etheraddr(struct netdev *netdev,
 }
 
 static int
-netdev_dpdk_get_etheraddr(const struct netdev *netdev,
-                          uint8_t mac[ETH_ADDR_LEN])
+netdev_dpdk_get_etheraddr(const struct netdev *netdev, struct eth_addr *mac)
 {
     struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
 
     ovs_mutex_lock(&dev->mutex);
-    memcpy(mac, dev->hwaddr, ETH_ADDR_LEN);
+    *mac = dev->hwaddr;
     ovs_mutex_unlock(&dev->mutex);
 
     return 0;
diff --git a/lib/netdev-dummy.c b/lib/netdev-dummy.c
index 285f544..9946d5a 100644
--- a/lib/netdev-dummy.c
+++ b/lib/netdev-dummy.c
@@ -105,7 +105,7 @@ struct netdev_dummy {
     /* Protects all members below. */
     struct ovs_mutex mutex OVS_ACQ_AFTER(dummy_list_mutex);
 
-    uint8_t hwaddr[ETH_ADDR_LEN] OVS_GUARDED;
+    struct eth_addr hwaddr OVS_GUARDED;
     int mtu OVS_GUARDED;
     struct netdev_stats stats OVS_GUARDED;
     enum netdev_flags flags OVS_GUARDED;
@@ -651,12 +651,12 @@ netdev_dummy_construct(struct netdev *netdev_)
 
     ovs_mutex_init(&netdev->mutex);
     ovs_mutex_lock(&netdev->mutex);
-    netdev->hwaddr[0] = 0xaa;
-    netdev->hwaddr[1] = 0x55;
-    netdev->hwaddr[2] = n >> 24;
-    netdev->hwaddr[3] = n >> 16;
-    netdev->hwaddr[4] = n >> 8;
-    netdev->hwaddr[5] = n;
+    netdev->hwaddr.ea[0] = 0xaa;
+    netdev->hwaddr.ea[1] = 0x55;
+    netdev->hwaddr.ea[2] = n >> 24;
+    netdev->hwaddr.ea[3] = n >> 16;
+    netdev->hwaddr.ea[4] = n >> 8;
+    netdev->hwaddr.ea[5] = n;
     netdev->mtu = 1500;
     netdev->flags = 0;
     netdev->ifindex = -EOPNOTSUPP;
@@ -970,14 +970,13 @@ netdev_dummy_send(struct netdev *netdev, int qid OVS_UNUSED,
 }
 
 static int
-netdev_dummy_set_etheraddr(struct netdev *netdev,
-                           const uint8_t mac[ETH_ADDR_LEN])
+netdev_dummy_set_etheraddr(struct netdev *netdev, const struct eth_addr mac)
 {
     struct netdev_dummy *dev = netdev_dummy_cast(netdev);
 
     ovs_mutex_lock(&dev->mutex);
     if (!eth_addr_equals(dev->hwaddr, mac)) {
-        memcpy(dev->hwaddr, mac, ETH_ADDR_LEN);
+        dev->hwaddr = mac;
         netdev_change_seq_changed(netdev);
     }
     ovs_mutex_unlock(&dev->mutex);
@@ -986,13 +985,12 @@ netdev_dummy_set_etheraddr(struct netdev *netdev,
 }
 
 static int
-netdev_dummy_get_etheraddr(const struct netdev *netdev,
-                           uint8_t mac[ETH_ADDR_LEN])
+netdev_dummy_get_etheraddr(const struct netdev *netdev, struct eth_addr *mac)
 {
     struct netdev_dummy *dev = netdev_dummy_cast(netdev);
 
     ovs_mutex_lock(&dev->mutex);
-    memcpy(mac, dev->hwaddr, ETH_ADDR_LEN);
+    *mac = dev->hwaddr;
     ovs_mutex_unlock(&dev->mutex);
 
     return 0;
diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c
index 712cb5a..56eed04 100644
--- a/lib/netdev-linux.c
+++ b/lib/netdev-linux.c
@@ -443,7 +443,7 @@ struct netdev_linux {
     /* The following are figured out "on demand" only.  They are only valid
      * when the corresponding VALID_* bit in 'cache_valid' is set. */
     int ifindex;
-    uint8_t etheraddr[ETH_ADDR_LEN];
+    struct eth_addr etheraddr;
     struct in_addr address, netmask;
     struct in6_addr in6;
     int mtu;
@@ -506,8 +506,8 @@ static int get_ifindex(const struct netdev *, int *ifindexp);
 static int do_set_addr(struct netdev *netdev,
                        int ioctl_nr, const char *ioctl_name,
                        struct in_addr addr);
-static int get_etheraddr(const char *netdev_name, uint8_t ea[ETH_ADDR_LEN]);
-static int set_etheraddr(const char *netdev_name, const uint8_t[ETH_ADDR_LEN]);
+static int get_etheraddr(const char *netdev_name, struct eth_addr *ea);
+static int set_etheraddr(const char *netdev_name, const struct eth_addr);
 static int get_stats_via_netlink(const struct netdev *, struct netdev_stats *);
 static int af_packet_sock(void);
 static bool netdev_linux_miimon_enabled(void);
@@ -700,8 +700,8 @@ netdev_linux_update(struct netdev_linux *dev,
                 dev->netdev_mtu_error = 0;
             }
 
-            if (!eth_addr_is_zero(change->addr)) {
-                memcpy(dev->etheraddr, change->addr, ETH_ADDR_LEN);
+            if (!eth_addr_is_zero(change->mac)) {
+                dev->etheraddr = change->mac;
                 dev->cache_valid |= VALID_ETHERADDR;
                 dev->ether_addr_error = 0;
             }
@@ -1234,8 +1234,7 @@ netdev_linux_send_wait(struct netdev *netdev, int qid OVS_UNUSED)
 /* Attempts to set 'netdev''s MAC address to 'mac'.  Returns 0 if successful,
  * otherwise a positive errno value. */
 static int
-netdev_linux_set_etheraddr(struct netdev *netdev_,
-                           const uint8_t mac[ETH_ADDR_LEN])
+netdev_linux_set_etheraddr(struct netdev *netdev_, const struct eth_addr mac)
 {
     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
     enum netdev_flags old_flags = 0;
@@ -1260,7 +1259,7 @@ netdev_linux_set_etheraddr(struct netdev *netdev_,
         netdev->ether_addr_error = error;
         netdev->cache_valid |= VALID_ETHERADDR;
         if (!error) {
-            memcpy(netdev->etheraddr, mac, ETH_ADDR_LEN);
+            netdev->etheraddr = mac;
         }
     }
 
@@ -1275,8 +1274,7 @@ exit:
 
 /* Copies 'netdev''s MAC address to 'mac' which is passed as param. */
 static int
-netdev_linux_get_etheraddr(const struct netdev *netdev_,
-                           uint8_t mac[ETH_ADDR_LEN])
+netdev_linux_get_etheraddr(const struct netdev *netdev_, struct eth_addr *mac)
 {
     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
     int error;
@@ -1284,13 +1282,13 @@ netdev_linux_get_etheraddr(const struct netdev *netdev_,
     ovs_mutex_lock(&netdev->mutex);
     if (!(netdev->cache_valid & VALID_ETHERADDR)) {
         netdev->ether_addr_error = get_etheraddr(netdev_get_name(netdev_),
-                                                 netdev->etheraddr);
+                                                 &netdev->etheraddr);
         netdev->cache_valid |= VALID_ETHERADDR;
     }
 
     error = netdev->ether_addr_error;
     if (!error) {
-        memcpy(mac, netdev->etheraddr, ETH_ADDR_LEN);
+        *mac = netdev->etheraddr;
     }
     ovs_mutex_unlock(&netdev->mutex);
 
@@ -2681,7 +2679,7 @@ netdev_internal_get_status(const struct netdev *netdev OVS_UNUSED,
  * ENXIO indicates that there is not ARP table entry for 'ip' on 'netdev'. */
 static int
 netdev_linux_arp_lookup(const struct netdev *netdev,
-                        ovs_be32 ip, uint8_t mac[ETH_ADDR_LEN])
+                        ovs_be32 ip, struct eth_addr *mac)
 {
     struct arpreq r;
     struct sockaddr_in sin;
@@ -5493,7 +5491,7 @@ get_ifindex(const struct netdev *netdev_, int *ifindexp)
 }
 
 static int
-get_etheraddr(const char *netdev_name, uint8_t ea[ETH_ADDR_LEN])
+get_etheraddr(const char *netdev_name, struct eth_addr *ea)
 {
     struct ifreq ifr;
     int hwaddr_family;
@@ -5522,8 +5520,7 @@ get_etheraddr(const char *netdev_name, uint8_t ea[ETH_ADDR_LEN])
 }
 
 static int
-set_etheraddr(const char *netdev_name,
-              const uint8_t mac[ETH_ADDR_LEN])
+set_etheraddr(const char *netdev_name, const struct eth_addr mac)
 {
     struct ifreq ifr;
     int error;
@@ -5531,7 +5528,7 @@ set_etheraddr(const char *netdev_name,
     memset(&ifr, 0, sizeof ifr);
     ovs_strzcpy(ifr.ifr_name, netdev_name, sizeof ifr.ifr_name);
     ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
-    memcpy(ifr.ifr_hwaddr.sa_data, mac, ETH_ADDR_LEN);
+    memcpy(ifr.ifr_hwaddr.sa_data, &mac, ETH_ADDR_LEN);
     COVERAGE_INC(netdev_set_hwaddr);
     error = af_inet_ioctl(SIOCSIFHWADDR, &ifr);
     if (error) {
diff --git a/lib/netdev-provider.h b/lib/netdev-provider.h
index aab63b7..a33bb3b 100644
--- a/lib/netdev-provider.h
+++ b/lib/netdev-provider.h
@@ -337,15 +337,13 @@ struct netdev_class {
     void (*send_wait)(struct netdev *netdev, int qid);
 
     /* Sets 'netdev''s Ethernet address to 'mac' */
-    int (*set_etheraddr)(struct netdev *netdev,
-                         const uint8_t mac[ETH_ADDR_LEN]);
+    int (*set_etheraddr)(struct netdev *netdev, const struct eth_addr mac);
 
     /* Retrieves 'netdev''s Ethernet address into 'mac'.
      *
      * This address will be advertised as 'netdev''s MAC address through the
      * OpenFlow protocol, among other uses. */
-    int (*get_etheraddr)(const struct netdev *netdev,
-                         uint8_t mac[ETH_ADDR_LEN]);
+    int (*get_etheraddr)(const struct netdev *netdev, struct eth_addr *mac);
 
     /* Retrieves 'netdev''s MTU into '*mtup'.
      *
@@ -683,7 +681,7 @@ struct netdev_class {
      * This function may be set to null if it would always return EOPNOTSUPP
      * anyhow. */
     int (*arp_lookup)(const struct netdev *netdev, ovs_be32 ip,
-                      uint8_t mac[ETH_ADDR_LEN]);
+                      struct eth_addr *mac);
 
     /* Retrieves the current set of flags on 'netdev' into '*old_flags'.  Then,
      * turns off the flags that are set to 1 in 'off' and turns on the flags
diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
index 63aaaaa..eceaa81 100644
--- a/lib/netdev-vport.c
+++ b/lib/netdev-vport.c
@@ -75,7 +75,7 @@ struct netdev_vport {
     /* Protects all members below. */
     struct ovs_mutex mutex;
 
-    uint8_t etheraddr[ETH_ADDR_LEN];
+    struct eth_addr etheraddr;
     struct netdev_stats stats;
 
     /* Tunnels. */
@@ -249,7 +249,7 @@ netdev_vport_construct(struct netdev *netdev_)
     const char *type = netdev_get_type(netdev_);
 
     ovs_mutex_init(&dev->mutex);
-    eth_addr_random(dev->etheraddr);
+    eth_addr_random(&dev->etheraddr);
 
     /* Add a default destination port for tunnel ports if none specified. */
     if (!strcmp(type, "geneve")) {
@@ -284,13 +284,12 @@ netdev_vport_dealloc(struct netdev *netdev_)
 }
 
 static int
-netdev_vport_set_etheraddr(struct netdev *netdev_,
-                           const uint8_t mac[ETH_ADDR_LEN])
+netdev_vport_set_etheraddr(struct netdev *netdev_, const struct eth_addr mac)
 {
     struct netdev_vport *netdev = netdev_vport_cast(netdev_);
 
     ovs_mutex_lock(&netdev->mutex);
-    memcpy(netdev->etheraddr, mac, ETH_ADDR_LEN);
+    netdev->etheraddr = mac;
     ovs_mutex_unlock(&netdev->mutex);
     netdev_change_seq_changed(netdev_);
 
@@ -298,13 +297,12 @@ netdev_vport_set_etheraddr(struct netdev *netdev_,
 }
 
 static int
-netdev_vport_get_etheraddr(const struct netdev *netdev_,
-                           uint8_t mac[ETH_ADDR_LEN])
+netdev_vport_get_etheraddr(const struct netdev *netdev_, struct eth_addr *mac)
 {
     struct netdev_vport *netdev = netdev_vport_cast(netdev_);
 
     ovs_mutex_lock(&netdev->mutex);
-    memcpy(mac, netdev->etheraddr, ETH_ADDR_LEN);
+    *mac = netdev->etheraddr;
     ovs_mutex_unlock(&netdev->mutex);
 
     return 0;
diff --git a/lib/netdev-windows.c b/lib/netdev-windows.c
index 1eb8727..51d088a 100644
--- a/lib/netdev-windows.c
+++ b/lib/netdev-windows.c
@@ -53,7 +53,7 @@ struct netdev_windows {
 
     unsigned int cache_valid;
     int ifindex;
-    uint8_t mac[ETH_ADDR_LEN];
+    struct eth_addr mac;
     uint32_t mtu;
     unsigned int ifi_flags;
 };
@@ -70,7 +70,7 @@ struct netdev_windows_netdev_info {
 
     /* General information of a network device. */
     const char *name;
-    uint8_t mac_address[ETH_ADDR_LEN];
+    struct eth_addr mac_address;
     uint32_t mtu;
     uint32_t ifi_flags;
 };
@@ -153,7 +153,6 @@ static int
 netdev_windows_system_construct(struct netdev *netdev_)
 {
     struct netdev_windows *netdev = netdev_windows_cast(netdev_);
-    uint8_t mac[ETH_ADDR_LEN];
     struct netdev_windows_netdev_info info;
     struct ofpbuf *buf;
     int ret;
@@ -169,7 +168,7 @@ netdev_windows_system_construct(struct netdev *netdev_)
     netdev->dev_type = info.ovs_type;
     netdev->port_no = info.port_no;
 
-    memcpy(netdev->mac, info.mac_address, ETH_ADDR_LEN);
+    netdev->mac = info.mac_address;
     netdev->cache_valid = VALID_ETHERADDR;
     netdev->ifindex = -EOPNOTSUPP;
 
@@ -318,13 +317,13 @@ netdev_windows_dealloc(struct netdev *netdev_)
 
 static int
 netdev_windows_get_etheraddr(const struct netdev *netdev_,
-                             uint8_t mac[ETH_ADDR_LEN])
+                             struct eth_addr *mac)
 {
     struct netdev_windows *netdev = netdev_windows_cast(netdev_);
 
     ovs_assert((netdev->cache_valid & VALID_ETHERADDR) != 0);
     if (netdev->cache_valid & VALID_ETHERADDR) {
-        memcpy(mac, netdev->mac, ETH_ADDR_LEN);
+        *mac = netdev->mac;
     } else {
         return EINVAL;
     }
@@ -349,7 +348,7 @@ netdev_windows_get_mtu(const struct netdev *netdev_, int *mtup)
  * But vswitchd bringup expects this to be implemented. */
 static int
 netdev_windows_set_etheraddr(const struct netdev *netdev_,
-                             uint8_t mac[ETH_ADDR_LEN])
+                             const struct eth_addr mac)
 {
     return 0;
 }
@@ -380,7 +379,7 @@ netdev_windows_update_flags(struct netdev *netdev_,
  */
 static int
 netdev_windows_arp_lookup(const struct netdev *netdev,
-                          ovs_be32 ip, uint8_t mac[ETH_ADDR_LEN])
+                          ovs_be32 ip, struct eth_addr *mac)
 {
     PMIB_IPNETTABLE arp_table = NULL;
     /* The buffer length of all ARP entries */
diff --git a/lib/netdev.c b/lib/netdev.c
index 4819ae9..e3b70b1 100644
--- a/lib/netdev.c
+++ b/lib/netdev.c
@@ -816,7 +816,7 @@ netdev_send_wait(struct netdev *netdev, int qid)
 /* Attempts to set 'netdev''s MAC address to 'mac'.  Returns 0 if successful,
  * otherwise a positive errno value. */
 int
-netdev_set_etheraddr(struct netdev *netdev, const uint8_t mac[ETH_ADDR_LEN])
+netdev_set_etheraddr(struct netdev *netdev, const struct eth_addr mac)
 {
     return netdev->netdev_class->set_etheraddr(netdev, mac);
 }
@@ -825,7 +825,7 @@ netdev_set_etheraddr(struct netdev *netdev, const uint8_t mac[ETH_ADDR_LEN])
  * the MAC address into 'mac'.  On failure, returns a positive errno value and
  * clears 'mac' to all-zeros. */
 int
-netdev_get_etheraddr(const struct netdev *netdev, uint8_t mac[ETH_ADDR_LEN])
+netdev_get_etheraddr(const struct netdev *netdev, struct eth_addr *mac)
 {
     return netdev->netdev_class->get_etheraddr(netdev, mac);
 }
@@ -1259,13 +1259,13 @@ netdev_restore_flags(struct netdev_saved_flags *sf)
  * ENXIO indicates that there is no ARP table entry for 'ip' on 'netdev'. */
 int
 netdev_arp_lookup(const struct netdev *netdev,
-                  ovs_be32 ip, uint8_t mac[ETH_ADDR_LEN])
+                  ovs_be32 ip, struct eth_addr *mac)
 {
     int error = (netdev->netdev_class->arp_lookup
                  ? netdev->netdev_class->arp_lookup(netdev, ip, mac)
                  : EOPNOTSUPP);
     if (error) {
-        memset(mac, 0, ETH_ADDR_LEN);
+        *mac = eth_addr_zero;
     }
     return error;
 }
diff --git a/lib/netdev.h b/lib/netdev.h
index 9d412ee..0fbcb65 100644
--- a/lib/netdev.h
+++ b/lib/netdev.h
@@ -194,8 +194,8 @@ int netdev_pop_header(struct netdev *netdev, struct dp_packet **buffers,
                       int cnt);
 
 /* Hardware address. */
-int netdev_set_etheraddr(struct netdev *, const uint8_t mac[ETH_ADDR_LEN]);
-int netdev_get_etheraddr(const struct netdev *, uint8_t mac[ETH_ADDR_LEN]);
+int netdev_set_etheraddr(struct netdev *, const struct eth_addr mac);
+int netdev_get_etheraddr(const struct netdev *, struct eth_addr *mac);
 
 /* PHY interface. */
 bool netdev_get_carrier(const struct netdev *);
@@ -260,7 +260,7 @@ int netdev_get_next_hop(const struct netdev *, const struct in_addr *host,
                         struct in_addr *next_hop, char **);
 int netdev_get_status(const struct netdev *, struct smap *);
 int netdev_arp_lookup(const struct netdev *, ovs_be32 ip,
-                      uint8_t mac[ETH_ADDR_LEN]);
+                      struct eth_addr *mac);
 
 struct netdev *netdev_find_dev_by_in4(const struct in_addr *);
 
diff --git a/lib/nx-match.c b/lib/nx-match.c
index 54645df..bb70f0a 100644
--- a/lib/nx-match.c
+++ b/lib/nx-match.c
@@ -749,10 +749,9 @@ nxm_put_64m(struct ofpbuf *b, enum mf_field_id field, enum ofp_version version,
 static void
 nxm_put_eth_masked(struct ofpbuf *b,
                    enum mf_field_id field, enum ofp_version version,
-                   const uint8_t value[ETH_ADDR_LEN],
-                   const uint8_t mask[ETH_ADDR_LEN])
+                   const struct eth_addr value, const struct eth_addr mask)
 {
-    nxm_put(b, field, version, value, mask, ETH_ADDR_LEN);
+    nxm_put(b, field, version, value.ea, mask.ea, ETH_ADDR_LEN);
 }
 
 static void
diff --git a/lib/odp-execute.c b/lib/odp-execute.c
index c4806e1..54a43cd 100644
--- a/lib/odp-execute.c
+++ b/lib/odp-execute.c
@@ -36,13 +36,13 @@
 
 /* Masked copy of an ethernet address. 'src' is already properly masked. */
 static void
-ether_addr_copy_masked(uint8_t *dst, const uint8_t *src,
-                       const uint8_t *mask)
+ether_addr_copy_masked(struct eth_addr *dst, const struct eth_addr src,
+                       const struct eth_addr mask)
 {
     int i;
 
-    for (i = 0; i < ETH_ADDR_LEN; i++) {
-        dst[i] = src[i] | (dst[i] & ~mask[i]);
+    for (i = 0; i < ARRAY_SIZE(dst->be16); i++) {
+        dst->be16[i] = src.be16[i] | (dst->be16[i] & ~mask.be16[i]);
     }
 }
 
@@ -54,11 +54,11 @@ odp_eth_set_addrs(struct dp_packet *packet, const struct ovs_key_ethernet *key,
 
     if (eh) {
         if (!mask) {
-            memcpy(eh->eth_src, key->eth_src, sizeof eh->eth_src);
-            memcpy(eh->eth_dst, key->eth_dst, sizeof eh->eth_dst);
+            eh->eth_src = key->eth_src;
+            eh->eth_dst = key->eth_dst;
         } else {
-            ether_addr_copy_masked(eh->eth_src, key->eth_src, mask->eth_src);
-            ether_addr_copy_masked(eh->eth_dst, key->eth_dst, mask->eth_dst);
+            ether_addr_copy_masked(&eh->eth_src, key->eth_src, mask->eth_src);
+            ether_addr_copy_masked(&eh->eth_dst, key->eth_dst, mask->eth_dst);
         }
     }
 }
@@ -163,19 +163,19 @@ set_arp(struct dp_packet *packet, const struct ovs_key_arp *key,
 
     if (!mask) {
         arp->ar_op = key->arp_op;
-        memcpy(arp->ar_sha, key->arp_sha, ETH_ADDR_LEN);
+        arp->ar_sha = key->arp_sha;
         put_16aligned_be32(&arp->ar_spa, key->arp_sip);
-        memcpy(arp->ar_tha, key->arp_tha, ETH_ADDR_LEN);
+        arp->ar_tha = key->arp_tha;
         put_16aligned_be32(&arp->ar_tpa, key->arp_tip);
     } else {
         ovs_be32 ar_spa = get_16aligned_be32(&arp->ar_spa);
         ovs_be32 ar_tpa = get_16aligned_be32(&arp->ar_tpa);
 
         arp->ar_op = key->arp_op | (arp->ar_op & ~mask->arp_op);
-        ether_addr_copy_masked(arp->ar_sha, key->arp_sha, mask->arp_sha);
+        ether_addr_copy_masked(&arp->ar_sha, key->arp_sha, mask->arp_sha);
         put_16aligned_be32(&arp->ar_spa,
                            key->arp_sip | (ar_spa & ~mask->arp_sip));
-        ether_addr_copy_masked(arp->ar_tha, key->arp_tha, mask->arp_tha);
+        ether_addr_copy_masked(&arp->ar_tha, key->arp_tha, mask->arp_tha);
         put_16aligned_be32(&arp->ar_tpa,
                            key->arp_tip | (ar_tpa & ~mask->arp_tip));
     }
@@ -191,21 +191,21 @@ odp_set_nd(struct dp_packet *packet, const struct ovs_key_nd *key,
     if (OVS_LIKELY(ns && nd_opt)) {
         int bytes_remain = dp_packet_l4_size(packet) - sizeof(*ns);
         ovs_be32 tgt_buf[4];
-        uint8_t sll_buf[ETH_ADDR_LEN] = {0};
-        uint8_t tll_buf[ETH_ADDR_LEN] = {0};
+        struct eth_addr sll_buf = eth_addr_zero;
+        struct eth_addr tll_buf = eth_addr_zero;
 
         while (bytes_remain >= ND_OPT_LEN && nd_opt->nd_opt_len != 0) {
             if (nd_opt->nd_opt_type == ND_OPT_SOURCE_LINKADDR
                 && nd_opt->nd_opt_len == 1) {
-                memcpy(sll_buf, nd_opt->nd_opt_data, ETH_ADDR_LEN);
-                ether_addr_copy_masked(sll_buf, key->nd_sll, mask->nd_sll);
+                sll_buf = nd_opt->nd_opt_mac;
+                ether_addr_copy_masked(&sll_buf, key->nd_sll, mask->nd_sll);
 
                 /* A packet can only contain one SLL or TLL option */
                 break;
             } else if (nd_opt->nd_opt_type == ND_OPT_TARGET_LINKADDR
                        && nd_opt->nd_opt_len == 1) {
-                memcpy(tll_buf, nd_opt->nd_opt_data, ETH_ADDR_LEN);
-                ether_addr_copy_masked(tll_buf, key->nd_tll, mask->nd_tll);
+                tll_buf = nd_opt->nd_opt_mac;
+                ether_addr_copy_masked(&tll_buf, key->nd_tll, mask->nd_tll);
 
                 /* A packet can only contain one SLL or TLL option */
                 break;
@@ -305,8 +305,8 @@ odp_execute_set_action(struct dp_packet *packet, const struct nlattr *a)
         if (OVS_LIKELY(dp_packet_get_nd_payload(packet))) {
             const struct ovs_key_nd *nd_key
                    = nl_attr_get_unspec(a, sizeof(struct ovs_key_nd));
-            packet_set_nd(packet, nd_key->nd_target,
-                          nd_key->nd_sll, nd_key->nd_tll);
+            packet_set_nd(packet, nd_key->nd_target, nd_key->nd_sll,
+                          nd_key->nd_tll);
         }
         break;
 
diff --git a/lib/odp-util.c b/lib/odp-util.c
index b50d87b..049d618 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -1516,8 +1516,8 @@ odp_portno_names_destroy(struct hmap *portno_names)
 /* Format helpers. */
 
 static void
-format_eth(struct ds *ds, const char *name, const uint8_t key[ETH_ADDR_LEN],
-           const uint8_t (*mask)[ETH_ADDR_LEN], bool verbose)
+format_eth(struct ds *ds, const char *name, const struct eth_addr key,
+           const struct eth_addr *mask, bool verbose)
 {
     bool mask_empty = mask && eth_addr_is_zero(*mask);
 
@@ -1528,7 +1528,7 @@ format_eth(struct ds *ds, const char *name, const uint8_t key[ETH_ADDR_LEN],
             ds_put_format(ds, "%s="ETH_ADDR_FMT",", name, ETH_ADDR_ARGS(key));
         } else {
             ds_put_format(ds, "%s=", name);
-            eth_format_masked(key, *mask, ds);
+            eth_format_masked(key, mask, ds);
             ds_put_char(ds, ',');
         }
     }
@@ -2391,12 +2391,12 @@ ovs_frag_type_from_string(const char *s, enum ovs_frag_type *type)
 /* Parsing. */
 
 static int
-scan_eth(const char *s, uint8_t (*key)[ETH_ADDR_LEN],
-         uint8_t (*mask)[ETH_ADDR_LEN])
+scan_eth(const char *s, struct eth_addr *key, struct eth_addr *mask)
 {
     int n;
 
-    if (ovs_scan(s, ETH_ADDR_SCAN_FMT"%n", ETH_ADDR_SCAN_ARGS(*key), &n)) {
+    if (ovs_scan(s, ETH_ADDR_SCAN_FMT"%n",
+                 ETH_ADDR_SCAN_ARGS(*key), &n)) {
         int len = n;
 
         if (mask) {
@@ -3495,8 +3495,8 @@ odp_flow_key_from_flow__(const struct odp_flow_key_parms *parms,
                                                     sizeof *nd_key);
                 memcpy(nd_key->nd_target, &data->nd_target,
                         sizeof nd_key->nd_target);
-                memcpy(nd_key->nd_sll, data->arp_sha, ETH_ADDR_LEN);
-                memcpy(nd_key->nd_tll, data->arp_tha, ETH_ADDR_LEN);
+                nd_key->nd_sll = data->arp_sha;
+                nd_key->nd_tll = data->arp_tha;
             }
         }
     }
@@ -3995,8 +3995,8 @@ parse_l2_5_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1],
                     nd_key = nl_attr_get(attrs[OVS_KEY_ATTR_ND]);
                     memcpy(&flow->nd_target, nd_key->nd_target,
                            sizeof flow->nd_target);
-                    memcpy(flow->arp_sha, nd_key->nd_sll, ETH_ADDR_LEN);
-                    memcpy(flow->arp_tha, nd_key->nd_tll, ETH_ADDR_LEN);
+                    flow->arp_sha = nd_key->nd_sll;
+                    flow->arp_tha = nd_key->nd_tll;
                     if (is_mask) {
                         if (!is_all_zeros(nd_key, sizeof *nd_key) &&
                             (flow->tp_src != htons(0xffff) ||
@@ -4430,15 +4430,15 @@ commit(enum ovs_key_attr attr, bool use_masked_set,
 static void
 get_ethernet_key(const struct flow *flow, struct ovs_key_ethernet *eth)
 {
-    memcpy(eth->eth_src, flow->dl_src, ETH_ADDR_LEN);
-    memcpy(eth->eth_dst, flow->dl_dst, ETH_ADDR_LEN);
+    eth->eth_src = flow->dl_src;
+    eth->eth_dst = flow->dl_dst;
 }
 
 static void
 put_ethernet_key(const struct ovs_key_ethernet *eth, struct flow *flow)
 {
-    memcpy(flow->dl_src, eth->eth_src, ETH_ADDR_LEN);
-    memcpy(flow->dl_dst, eth->eth_dst, ETH_ADDR_LEN);
+    flow->dl_src = eth->eth_src;
+    flow->dl_dst = eth->eth_dst;
 }
 
 static void
@@ -4666,8 +4666,8 @@ get_arp_key(const struct flow *flow, struct ovs_key_arp *arp)
     arp->arp_sip = flow->nw_src;
     arp->arp_tip = flow->nw_dst;
     arp->arp_op = htons(flow->nw_proto);
-    memcpy(arp->arp_sha, flow->arp_sha, ETH_ADDR_LEN);
-    memcpy(arp->arp_tha, flow->arp_tha, ETH_ADDR_LEN);
+    arp->arp_sha = flow->arp_sha;
+    arp->arp_tha = flow->arp_tha;
 }
 
 static void
@@ -4676,8 +4676,8 @@ put_arp_key(const struct ovs_key_arp *arp, struct flow *flow)
     flow->nw_src = arp->arp_sip;
     flow->nw_dst = arp->arp_tip;
     flow->nw_proto = ntohs(arp->arp_op);
-    memcpy(flow->arp_sha, arp->arp_sha, ETH_ADDR_LEN);
-    memcpy(flow->arp_tha, arp->arp_tha, ETH_ADDR_LEN);
+    flow->arp_sha = arp->arp_sha;
+    flow->arp_tha = arp->arp_tha;
 }
 
 static enum slow_path_reason
@@ -4704,8 +4704,8 @@ get_nd_key(const struct flow *flow, struct ovs_key_nd *nd)
 {
     memcpy(nd->nd_target, &flow->nd_target, sizeof flow->nd_target);
     /* nd_sll and nd_tll are stored in arp_sha and arp_tha, respectively */
-    memcpy(nd->nd_sll, flow->arp_sha, ETH_ADDR_LEN);
-    memcpy(nd->nd_tll, flow->arp_tha, ETH_ADDR_LEN);
+    nd->nd_sll = flow->arp_sha;
+    nd->nd_tll = flow->arp_tha;
 }
 
 static void
@@ -4713,8 +4713,8 @@ put_nd_key(const struct ovs_key_nd *nd, struct flow *flow)
 {
     memcpy(&flow->nd_target, nd->nd_target, sizeof flow->nd_target);
     /* nd_sll and nd_tll are stored in arp_sha and arp_tha, respectively */
-    memcpy(flow->arp_sha, nd->nd_sll, ETH_ADDR_LEN);
-    memcpy(flow->arp_tha, nd->nd_tll, ETH_ADDR_LEN);
+    flow->arp_sha = nd->nd_sll;
+    flow->arp_tha = nd->nd_tll;
 }
 
 static enum slow_path_reason
diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c
index ad88c6e..3cc0fad 100644
--- a/lib/ofp-actions.c
+++ b/lib/ofp-actions.c
@@ -1334,7 +1334,7 @@ format_PUSH_VLAN(const struct ofpact_null *a OVS_UNUSED, struct ds *s)
 struct ofp_action_dl_addr {
     ovs_be16 type;                  /* Type. */
     ovs_be16 len;                   /* Length is 16. */
-    uint8_t dl_addr[OFP_ETH_ALEN];  /* Ethernet address. */
+    struct eth_addr dl_addr;        /* Ethernet address. */
     uint8_t pad[6];
 };
 OFP_ASSERT(sizeof(struct ofp_action_dl_addr) == 16);
@@ -1343,7 +1343,7 @@ static enum ofperr
 decode_OFPAT_RAW_SET_DL_SRC(const struct ofp_action_dl_addr *a,
                             struct ofpbuf *out)
 {
-    memcpy(ofpact_put_SET_ETH_SRC(out)->mac, a->dl_addr, ETH_ADDR_LEN);
+    ofpact_put_SET_ETH_SRC(out)->mac = a->dl_addr;
     return 0;
 }
 
@@ -1351,7 +1351,7 @@ static enum ofperr
 decode_OFPAT_RAW_SET_DL_DST(const struct ofp_action_dl_addr *a,
                             struct ofpbuf *out)
 {
-    memcpy(ofpact_put_SET_ETH_DST(out)->mac, a->dl_addr, ETH_ADDR_LEN);
+    ofpact_put_SET_ETH_DST(out)->mac = a->dl_addr;
     return 0;
 }
 
@@ -1360,16 +1360,14 @@ encode_SET_ETH_addr(const struct ofpact_mac *mac, enum ofp_version ofp_version,
                     enum ofp_raw_action_type raw, enum mf_field_id field,
                     struct ofpbuf *out)
 {
-    const uint8_t *addr = mac->mac;
-
     if (ofp_version < OFP12_VERSION) {
         struct ofp_action_dl_addr *oada;
 
         oada = ofpact_put_raw(out, ofp_version, raw, 0);
-        memcpy(oada->dl_addr, addr, ETH_ADDR_LEN);
+        oada->dl_addr = mac->mac;
     } else {
         ofpact_put_set_field(out, ofp_version, field,
-                             eth_addr_to_uint64(addr));
+                             eth_addr_to_uint64(mac->mac));
     }
 }
 
@@ -1396,14 +1394,14 @@ static char * OVS_WARN_UNUSED_RESULT
 parse_SET_ETH_SRC(char *arg, struct ofpbuf *ofpacts,
                  enum ofputil_protocol *usable_protocols OVS_UNUSED)
 {
-    return str_to_mac(arg, ofpact_put_SET_ETH_SRC(ofpacts)->mac);
+    return str_to_mac(arg, &ofpact_put_SET_ETH_SRC(ofpacts)->mac);
 }
 
 static char * OVS_WARN_UNUSED_RESULT
 parse_SET_ETH_DST(char *arg, struct ofpbuf *ofpacts,
                  enum ofputil_protocol *usable_protocols OVS_UNUSED)
 {
-    return str_to_mac(arg, ofpact_put_SET_ETH_DST(ofpacts)->mac);
+    return str_to_mac(arg, &ofpact_put_SET_ETH_DST(ofpacts)->mac);
 }
 
 static void
@@ -2377,13 +2375,11 @@ set_field_to_legacy_openflow(const struct ofpact_set_field *sf,
         break;
 
     case MFF_ETH_SRC:
-        memcpy(put_OFPAT_SET_DL_SRC(out, ofp_version)->dl_addr,
-               sf->value.mac, ETH_ADDR_LEN);
+        put_OFPAT_SET_DL_SRC(out, ofp_version)->dl_addr = sf->value.mac;
         break;
 
     case MFF_ETH_DST:
-        memcpy(put_OFPAT_SET_DL_DST(out, ofp_version)->dl_addr,
-               sf->value.mac, ETH_ADDR_LEN);
+        put_OFPAT_SET_DL_DST(out, ofp_version)->dl_addr = sf->value.mac;
         break;
 
     case MFF_IPV4_SRC:
diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h
index b26845d..51b2963 100644
--- a/lib/ofp-actions.h
+++ b/lib/ofp-actions.h
@@ -329,7 +329,7 @@ struct ofpact_vlan_pcp {
  * Used for OFPAT10_SET_DL_SRC, OFPAT10_SET_DL_DST. */
 struct ofpact_mac {
     struct ofpact ofpact;
-    uint8_t mac[ETH_ADDR_LEN];
+    struct eth_addr mac;
 };
 
 /* OFPACT_SET_IPV4_SRC, OFPACT_SET_IPV4_DST.
diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c
index 372d72f..80011a5 100644
--- a/lib/ofp-parse.c
+++ b/lib/ofp-parse.c
@@ -144,9 +144,9 @@ str_to_be64(const char *str, ovs_be64 *valuep)
  * Returns NULL if successful, otherwise a malloc()'d string describing the
  * error.  The caller is responsible for freeing the returned string. */
 char * OVS_WARN_UNUSED_RESULT
-str_to_mac(const char *str, uint8_t mac[ETH_ADDR_LEN])
+str_to_mac(const char *str, struct eth_addr *mac)
 {
-    if (!ovs_scan(str, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(mac))) {
+    if (!ovs_scan(str, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(*mac))) {
         return xasprintf("invalid mac address %s", str);
     }
     return NULL;
diff --git a/lib/ofp-parse.h b/lib/ofp-parse.h
index 930e3d9..b64a32e 100644
--- a/lib/ofp-parse.h
+++ b/lib/ofp-parse.h
@@ -97,7 +97,7 @@ char *str_to_u16(const char *str, const char *name, uint16_t *valuep)
 char *str_to_u32(const char *str, uint32_t *valuep) OVS_WARN_UNUSED_RESULT;
 char *str_to_u64(const char *str, uint64_t *valuep) OVS_WARN_UNUSED_RESULT;
 char *str_to_be64(const char *str, ovs_be64 *valuep) OVS_WARN_UNUSED_RESULT;
-char *str_to_mac(const char *str, uint8_t mac[ETH_ADDR_LEN]) OVS_WARN_UNUSED_RESULT;
+char *str_to_mac(const char *str, struct eth_addr *mac) OVS_WARN_UNUSED_RESULT;
 char *str_to_ip(const char *str, ovs_be32 *ip) OVS_WARN_UNUSED_RESULT;
 
 #endif /* ofp-parse.h */
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index 0a5232d..f8fbcef 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -228,10 +228,10 @@ ofputil_wildcard_from_ofpfw10(uint32_t ofpfw, struct flow_wildcards *wc)
     }
 
     if (!(ofpfw & OFPFW10_DL_SRC)) {
-        memset(wc->masks.dl_src, 0xff, ETH_ADDR_LEN);
+        WC_MASK_FIELD(wc, dl_src);
     }
     if (!(ofpfw & OFPFW10_DL_DST)) {
-        memset(wc->masks.dl_dst, 0xff, ETH_ADDR_LEN);
+        WC_MASK_FIELD(wc, dl_dst);
     }
     if (!(ofpfw & OFPFW10_DL_TYPE)) {
         wc->masks.dl_type = OVS_BE16_MAX;
@@ -264,8 +264,8 @@ ofputil_match_from_ofp10_match(const struct ofp10_match *ofmatch,
     match->flow.dl_type = ofputil_dl_type_from_openflow(ofmatch->dl_type);
     match->flow.tp_src = ofmatch->tp_src;
     match->flow.tp_dst = ofmatch->tp_dst;
-    memcpy(match->flow.dl_src, ofmatch->dl_src, ETH_ADDR_LEN);
-    memcpy(match->flow.dl_dst, ofmatch->dl_dst, ETH_ADDR_LEN);
+    match->flow.dl_src = ofmatch->dl_src;
+    match->flow.dl_dst = ofmatch->dl_dst;
     match->flow.nw_tos = ofmatch->nw_tos & IP_DSCP_MASK;
     match->flow.nw_proto = ofmatch->nw_proto;
 
@@ -361,8 +361,8 @@ ofputil_match_to_ofp10_match(const struct match *match,
     /* Compose most of the match structure. */
     ofmatch->wildcards = htonl(ofpfw);
     ofmatch->in_port = htons(ofp_to_u16(match->flow.in_port.ofp_port));
-    memcpy(ofmatch->dl_src, match->flow.dl_src, ETH_ADDR_LEN);
-    memcpy(ofmatch->dl_dst, match->flow.dl_dst, ETH_ADDR_LEN);
+    ofmatch->dl_src = match->flow.dl_src;
+    ofmatch->dl_dst = match->flow.dl_dst;
     ofmatch->dl_type = ofputil_dl_type_to_openflow(match->flow.dl_type);
     ofmatch->nw_src = match->flow.nw_src;
     ofmatch->nw_dst = match->flow.nw_dst;
@@ -419,10 +419,7 @@ ofputil_match_from_ofp11_match(const struct ofp11_match *ofmatch,
                                struct match *match)
 {
     uint16_t wc = ntohl(ofmatch->wildcards);
-    uint8_t dl_src_mask[ETH_ADDR_LEN];
-    uint8_t dl_dst_mask[ETH_ADDR_LEN];
     bool ipv4, arp, rarp;
-    int i;
 
     match_init_catchall(match);
 
@@ -437,15 +434,10 @@ ofputil_match_from_ofp11_match(const struct ofp11_match *ofmatch,
         match_set_in_port(match, ofp_port);
     }
 
-    for (i = 0; i < ETH_ADDR_LEN; i++) {
-        dl_src_mask[i] = ~ofmatch->dl_src_mask[i];
-    }
-    match_set_dl_src_masked(match, ofmatch->dl_src, dl_src_mask);
-
-    for (i = 0; i < ETH_ADDR_LEN; i++) {
-        dl_dst_mask[i] = ~ofmatch->dl_dst_mask[i];
-    }
-    match_set_dl_dst_masked(match, ofmatch->dl_dst, dl_dst_mask);
+    match_set_dl_src_masked(match, ofmatch->dl_src,
+                            eth_addr_invert(ofmatch->dl_src_mask));
+    match_set_dl_dst_masked(match, ofmatch->dl_dst,
+                            eth_addr_invert(ofmatch->dl_dst_mask));
 
     if (!(wc & OFPFW11_DL_VLAN)) {
         if (ofmatch->dl_vlan == htons(OFPVID11_NONE)) {
@@ -572,7 +564,6 @@ ofputil_match_to_ofp11_match(const struct match *match,
                              struct ofp11_match *ofmatch)
 {
     uint32_t wc = 0;
-    int i;
 
     memset(ofmatch, 0, sizeof *ofmatch);
     ofmatch->omh.type = htons(OFPMT_STANDARD);
@@ -584,15 +575,10 @@ ofputil_match_to_ofp11_match(const struct match *match,
         ofmatch->in_port = ofputil_port_to_ofp11(match->flow.in_port.ofp_port);
     }
 
-    memcpy(ofmatch->dl_src, match->flow.dl_src, ETH_ADDR_LEN);
-    for (i = 0; i < ETH_ADDR_LEN; i++) {
-        ofmatch->dl_src_mask[i] = ~match->wc.masks.dl_src[i];
-    }
-
-    memcpy(ofmatch->dl_dst, match->flow.dl_dst, ETH_ADDR_LEN);
-    for (i = 0; i < ETH_ADDR_LEN; i++) {
-        ofmatch->dl_dst_mask[i] = ~match->wc.masks.dl_dst[i];
-    }
+    ofmatch->dl_src = match->flow.dl_src;
+    ofmatch->dl_src_mask = eth_addr_invert(match->wc.masks.dl_src);
+    ofmatch->dl_dst = match->flow.dl_dst;
+    ofmatch->dl_dst_mask = eth_addr_invert(match->wc.masks.dl_dst);
 
     if (match->wc.masks.vlan_tci == htons(0)) {
         wc |= OFPFW11_DL_VLAN | OFPFW11_DL_VLAN_PCP;
@@ -3744,7 +3730,7 @@ ofputil_decode_ofp10_phy_port(struct ofputil_phy_port *pp,
                               const struct ofp10_phy_port *opp)
 {
     pp->port_no = u16_to_ofp(ntohs(opp->port_no));
-    memcpy(pp->hw_addr, opp->hw_addr, OFP_ETH_ALEN);
+    pp->hw_addr = opp->hw_addr;
     ovs_strlcpy(pp->name, opp->name, OFP_MAX_PORT_NAME_LEN);
 
     pp->config = ntohl(opp->config) & OFPPC10_ALL;
@@ -3771,7 +3757,7 @@ ofputil_decode_ofp11_port(struct ofputil_phy_port *pp,
     if (error) {
         return error;
     }
-    memcpy(pp->hw_addr, op->hw_addr, OFP_ETH_ALEN);
+    pp->hw_addr = op->hw_addr;
     ovs_strlcpy(pp->name, op->name, OFP_MAX_PORT_NAME_LEN);
 
     pp->config = ntohl(op->config) & OFPPC11_ALL;
@@ -3833,7 +3819,7 @@ ofputil_pull_ofp14_port(struct ofputil_phy_port *pp, struct ofpbuf *msg)
     if (error) {
         return error;
     }
-    memcpy(pp->hw_addr, op->hw_addr, OFP_ETH_ALEN);
+    pp->hw_addr = op->hw_addr;
     ovs_strlcpy(pp->name, op->name, OFP_MAX_PORT_NAME_LEN);
 
     pp->config = ntohl(op->config) & OFPPC11_ALL;
@@ -3875,7 +3861,7 @@ ofputil_encode_ofp10_phy_port(const struct ofputil_phy_port *pp,
     memset(opp, 0, sizeof *opp);
 
     opp->port_no = htons(ofp_to_u16(pp->port_no));
-    memcpy(opp->hw_addr, pp->hw_addr, ETH_ADDR_LEN);
+    opp->hw_addr = pp->hw_addr;
     ovs_strlcpy(opp->name, pp->name, OFP_MAX_PORT_NAME_LEN);
 
     opp->config = htonl(pp->config & OFPPC10_ALL);
@@ -3894,7 +3880,7 @@ ofputil_encode_ofp11_port(const struct ofputil_phy_port *pp,
     memset(op, 0, sizeof *op);
 
     op->port_no = ofputil_port_to_ofp11(pp->port_no);
-    memcpy(op->hw_addr, pp->hw_addr, ETH_ADDR_LEN);
+    op->hw_addr = pp->hw_addr;
     ovs_strlcpy(op->name, pp->name, OFP_MAX_PORT_NAME_LEN);
 
     op->config = htonl(pp->config & OFPPC11_ALL);
@@ -3921,7 +3907,7 @@ ofputil_put_ofp14_port(const struct ofputil_phy_port *pp,
     op = ofpbuf_put_zeros(b, sizeof *op);
     op->port_no = ofputil_port_to_ofp11(pp->port_no);
     op->length = htons(sizeof *op + sizeof *eth);
-    memcpy(op->hw_addr, pp->hw_addr, ETH_ADDR_LEN);
+    op->hw_addr = pp->hw_addr;
     ovs_strlcpy(op->name, pp->name, sizeof op->name);
     op->config = htonl(pp->config & OFPPC11_ALL);
     op->state = htonl(pp->state & OFPPS11_ALL);
@@ -4333,7 +4319,7 @@ ofputil_decode_port_mod(const struct ofp_header *oh,
         const struct ofp10_port_mod *opm = b.data;
 
         pm->port_no = u16_to_ofp(ntohs(opm->port_no));
-        memcpy(pm->hw_addr, opm->hw_addr, ETH_ADDR_LEN);
+        pm->hw_addr = opm->hw_addr;
         pm->config = ntohl(opm->config) & OFPPC10_ALL;
         pm->mask = ntohl(opm->mask) & OFPPC10_ALL;
         pm->advertise = netdev_port_features_from_ofp10(opm->advertise);
@@ -4346,7 +4332,7 @@ ofputil_decode_port_mod(const struct ofp_header *oh,
             return error;
         }
 
-        memcpy(pm->hw_addr, opm->hw_addr, ETH_ADDR_LEN);
+        pm->hw_addr = opm->hw_addr;
         pm->config = ntohl(opm->config) & OFPPC11_ALL;
         pm->mask = ntohl(opm->mask) & OFPPC11_ALL;
         pm->advertise = netdev_port_features_from_ofp11(opm->advertise);
@@ -4361,7 +4347,7 @@ ofputil_decode_port_mod(const struct ofp_header *oh,
             return error;
         }
 
-        memcpy(pm->hw_addr, opm->hw_addr, ETH_ADDR_LEN);
+        pm->hw_addr = opm->hw_addr;
         pm->config = ntohl(opm->config) & OFPPC11_ALL;
         pm->mask = ntohl(opm->mask) & OFPPC11_ALL;
 
@@ -4421,7 +4407,7 @@ ofputil_encode_port_mod(const struct ofputil_port_mod *pm,
         b = ofpraw_alloc(OFPRAW_OFPT10_PORT_MOD, ofp_version, 0);
         opm = ofpbuf_put_zeros(b, sizeof *opm);
         opm->port_no = htons(ofp_to_u16(pm->port_no));
-        memcpy(opm->hw_addr, pm->hw_addr, ETH_ADDR_LEN);
+        opm->hw_addr = pm->hw_addr;
         opm->config = htonl(pm->config & OFPPC10_ALL);
         opm->mask = htonl(pm->mask & OFPPC10_ALL);
         opm->advertise = netdev_port_features_to_ofp10(pm->advertise);
@@ -4436,7 +4422,7 @@ ofputil_encode_port_mod(const struct ofputil_port_mod *pm,
         b = ofpraw_alloc(OFPRAW_OFPT11_PORT_MOD, ofp_version, 0);
         opm = ofpbuf_put_zeros(b, sizeof *opm);
         opm->port_no = ofputil_port_to_ofp11(pm->port_no);
-        memcpy(opm->hw_addr, pm->hw_addr, ETH_ADDR_LEN);
+        opm->hw_addr = pm->hw_addr;
         opm->config = htonl(pm->config & OFPPC11_ALL);
         opm->mask = htonl(pm->mask & OFPPC11_ALL);
         opm->advertise = netdev_port_features_to_ofp11(pm->advertise);
@@ -4450,7 +4436,7 @@ ofputil_encode_port_mod(const struct ofputil_port_mod *pm,
         b = ofpraw_alloc(OFPRAW_OFPT14_PORT_MOD, ofp_version, sizeof *eth);
         opm = ofpbuf_put_zeros(b, sizeof *opm);
         opm->port_no = ofputil_port_to_ofp11(pm->port_no);
-        memcpy(opm->hw_addr, pm->hw_addr, ETH_ADDR_LEN);
+        opm->hw_addr = pm->hw_addr;
         opm->config = htonl(pm->config & OFPPC11_ALL);
         opm->mask = htonl(pm->mask & OFPPC11_ALL);
 
@@ -6521,10 +6507,10 @@ ofputil_normalize_match__(struct match *match, bool may_log)
         wc.masks.nw_ttl = 0;
     }
     if (!(may_match & MAY_ARP_SHA)) {
-        memset(wc.masks.arp_sha, 0, ETH_ADDR_LEN);
+        WC_UNMASK_FIELD(&wc, arp_sha);
     }
     if (!(may_match & MAY_ARP_THA)) {
-        memset(wc.masks.arp_tha, 0, ETH_ADDR_LEN);
+        WC_UNMASK_FIELD(&wc, arp_tha);
     }
     if (!(may_match & MAY_IPV6)) {
         wc.masks.ipv6_src = wc.masks.ipv6_dst = in6addr_any;
diff --git a/lib/ofp-util.h b/lib/ofp-util.h
index 2668e75..527a5ab 100644
--- a/lib/ofp-util.h
+++ b/lib/ofp-util.h
@@ -496,7 +496,7 @@ enum ofputil_port_state {
 /* Abstract ofp10_phy_port or ofp11_port. */
 struct ofputil_phy_port {
     ofp_port_t port_no;
-    uint8_t hw_addr[OFP_ETH_ALEN];
+    struct eth_addr hw_addr;
     char name[OFP_MAX_PORT_NAME_LEN];
     enum ofputil_port_config config;
     enum ofputil_port_state state;
@@ -572,7 +572,7 @@ struct ofpbuf *ofputil_encode_port_status(const struct ofputil_port_status *,
 /* Abstract ofp_port_mod. */
 struct ofputil_port_mod {
     ofp_port_t port_no;
-    uint8_t hw_addr[OFP_ETH_ALEN];
+    struct eth_addr hw_addr;
     enum ofputil_port_config config;
     enum ofputil_port_config mask;
     enum netdev_features advertise;
diff --git a/lib/ovs-lldp.c b/lib/ovs-lldp.c
index 54c70c5..bd1729c 100644
--- a/lib/ovs-lldp.c
+++ b/lib/ovs-lldp.c
@@ -722,12 +722,12 @@ lldp_wait(struct lldp *lldp) OVS_EXCLUDED(mutex)
  */
 void
 lldp_put_packet(struct lldp *lldp, struct dp_packet *packet,
-                uint8_t eth_src[ETH_ADDR_LEN]) OVS_EXCLUDED(mutex)
+                const struct eth_addr eth_src) OVS_EXCLUDED(mutex)
 {
     struct lldpd *mylldpd = lldp->lldpd;
     struct lldpd_hardware *hw = lldpd_first_hardware(mylldpd);
-    static const uint8_t eth_addr_lldp[6] =
-        {0x01, 0x80, 0xC2, 0x00, 0x00, 0x0e};
+    static const struct eth_addr eth_addr_lldp =
+        { { { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x0e } } };
 
     ovs_mutex_lock(&mutex);
 
@@ -791,8 +791,10 @@ lldp_create(const struct netdev *netdev,
     lchassis->c_cap_enabled = LLDP_CAP_BRIDGE;
     lchassis->c_id_subtype = LLDP_CHASSISID_SUBTYPE_LLADDR;
     lchassis->c_id_len = ETH_ADDR_LEN;
-    lchassis->c_id = xmalloc(ETH_ADDR_LEN);
-    netdev_get_etheraddr(netdev, lchassis->c_id);
+
+    struct eth_addr *mac = xmalloc(ETH_ADDR_LEN);
+    netdev_get_etheraddr(netdev, mac);
+    lchassis->c_id = &mac->ea[0];
 
     list_init(&lchassis->c_mgmt);
     lchassis->c_ttl = lldp->lldpd->g_config.c_tx_interval *
diff --git a/lib/ovs-lldp.h b/lib/ovs-lldp.h
index 807590a..e780e5b 100644
--- a/lib/ovs-lldp.h
+++ b/lib/ovs-lldp.h
@@ -88,7 +88,7 @@ bool lldp_should_process_flow(struct lldp *lldp, const struct flow *flow);
 bool lldp_configure(struct lldp *lldp, const struct smap *cfg);
 void lldp_process_packet(struct lldp *cfg, const struct dp_packet *);
 void lldp_put_packet(struct lldp *lldp, struct dp_packet *packet,
-                     uint8_t eth_src[ETH_ADDR_LEN]);
+                     const struct eth_addr eth_src);
 void lldpd_assign_cfg_to_protocols(struct lldpd *cfg);
 struct lldp * lldp_create(const struct netdev *netdev, const uint32_t mtu,
                           const struct smap *cfg);
diff --git a/lib/packets.c b/lib/packets.c
index ca8d87c..a4d7854 100644
--- a/lib/packets.c
+++ b/lib/packets.c
@@ -56,7 +56,7 @@ dpid_from_string(const char *s, uint64_t *dpidp)
  * If you change this function's behavior, please update corresponding
  * documentation in vswitch.xml at the same time. */
 bool
-eth_addr_is_reserved(const uint8_t ea[ETH_ADDR_LEN])
+eth_addr_is_reserved(const struct eth_addr ea)
 {
     struct eth_addr_node {
         struct hmap_node hmap_node;
@@ -129,12 +129,12 @@ eth_addr_is_reserved(const uint8_t ea[ETH_ADDR_LEN])
 }
 
 bool
-eth_addr_from_string(const char *s, uint8_t ea[ETH_ADDR_LEN])
+eth_addr_from_string(const char *s, struct eth_addr *ea)
 {
-    if (ovs_scan(s, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(ea))) {
+    if (ovs_scan(s, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(*ea))) {
         return true;
     } else {
-        memset(ea, 0, ETH_ADDR_LEN);
+        *ea = eth_addr_zero;
         return false;
     }
 }
@@ -146,7 +146,7 @@ eth_addr_from_string(const char *s, uint8_t ea[ETH_ADDR_LEN])
  * The returned packet has enough headroom to insert an 802.1Q VLAN header if
  * desired. */
 void
-compose_rarp(struct dp_packet *b, const uint8_t eth_src[ETH_ADDR_LEN])
+compose_rarp(struct dp_packet *b, const struct eth_addr eth_src)
 {
     struct eth_header *eth;
     struct arp_eth_header *arp;
@@ -156,8 +156,8 @@ compose_rarp(struct dp_packet *b, const uint8_t eth_src[ETH_ADDR_LEN])
                              + ARP_ETH_HEADER_LEN);
     dp_packet_reserve(b, 2 + VLAN_HEADER_LEN);
     eth = dp_packet_put_uninit(b, sizeof *eth);
-    memcpy(eth->eth_dst, eth_addr_broadcast, ETH_ADDR_LEN);
-    memcpy(eth->eth_src, eth_src, ETH_ADDR_LEN);
+    eth->eth_dst = eth_addr_broadcast;
+    eth->eth_src = eth_src;
     eth->eth_type = htons(ETH_TYPE_RARP);
 
     arp = dp_packet_put_uninit(b, sizeof *arp);
@@ -166,9 +166,9 @@ compose_rarp(struct dp_packet *b, const uint8_t eth_src[ETH_ADDR_LEN])
     arp->ar_hln = sizeof arp->ar_sha;
     arp->ar_pln = sizeof arp->ar_spa;
     arp->ar_op = htons(ARP_OP_RARP);
-    memcpy(arp->ar_sha, eth_src, ETH_ADDR_LEN);
+    arp->ar_sha = eth_src;
     put_16aligned_be32(&arp->ar_spa, htonl(0));
-    memcpy(arp->ar_tha, eth_src, ETH_ADDR_LEN);
+    arp->ar_tha = eth_src;
     put_16aligned_be32(&arp->ar_tpa, htonl(0));
 
     dp_packet_reset_offsets(b);
@@ -371,24 +371,12 @@ eth_from_hex(const char *hex, struct dp_packet **packetp)
 }
 
 void
-eth_format_masked(const uint8_t eth[ETH_ADDR_LEN],
-                  const uint8_t mask[ETH_ADDR_LEN], struct ds *s)
+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
-eth_addr_bitand(const uint8_t src[ETH_ADDR_LEN],
-                const uint8_t mask[ETH_ADDR_LEN],
-                uint8_t dst[ETH_ADDR_LEN])
-{
-    int i;
-
-    for (i = 0; i < ETH_ADDR_LEN; i++) {
-        dst[i] = src[i] & mask[i];
+    if (mask && !eth_mask_is_exact(*mask)) {
+        ds_put_format(s, "/"ETH_ADDR_FMT, ETH_ADDR_ARGS(*mask));
     }
 }
 
@@ -571,8 +559,8 @@ ipv6_is_cidr(const struct in6_addr *netmask)
  * The returned packet has enough headroom to insert an 802.1Q VLAN header if
  * desired. */
 void *
-eth_compose(struct dp_packet *b, const uint8_t eth_dst[ETH_ADDR_LEN],
-            const uint8_t eth_src[ETH_ADDR_LEN], uint16_t eth_type,
+eth_compose(struct dp_packet *b, const struct eth_addr eth_dst,
+            const struct eth_addr eth_src, uint16_t eth_type,
             size_t size)
 {
     void *data;
@@ -587,8 +575,8 @@ eth_compose(struct dp_packet *b, const uint8_t eth_dst[ETH_ADDR_LEN],
     eth = dp_packet_put_uninit(b, ETH_HEADER_LEN);
     data = dp_packet_put_uninit(b, size);
 
-    memcpy(eth->eth_dst, eth_dst, ETH_ADDR_LEN);
-    memcpy(eth->eth_src, eth_src, ETH_ADDR_LEN);
+    eth->eth_dst = eth_dst;
+    eth->eth_src = eth_src;
     eth->eth_type = htons(eth_type);
 
     dp_packet_reset_offsets(b);
@@ -889,8 +877,7 @@ packet_set_sctp_port(struct dp_packet *packet, ovs_be16 src, ovs_be16 dst)
 
 void
 packet_set_nd(struct dp_packet *packet, const ovs_be32 target[4],
-              const uint8_t sll[ETH_ADDR_LEN],
-              const uint8_t tll[ETH_ADDR_LEN]) {
+              const struct eth_addr sll, const struct eth_addr tll) {
     struct ovs_nd_msg *ns;
     struct ovs_nd_opt *nd_opt;
     int bytes_remain = dp_packet_l4_size(packet);
@@ -912,22 +899,22 @@ packet_set_nd(struct dp_packet *packet, const ovs_be32 target[4],
     while (bytes_remain >= ND_OPT_LEN && nd_opt->nd_opt_len != 0) {
         if (nd_opt->nd_opt_type == ND_OPT_SOURCE_LINKADDR
             && nd_opt->nd_opt_len == 1) {
-            if (memcmp(nd_opt->nd_opt_data, sll, ETH_ADDR_LEN)) {
+            if (!eth_addr_equals(nd_opt->nd_opt_mac, sll)) {
                 ovs_be16 *csum = &(ns->icmph.icmp6_cksum);
 
-                *csum = recalc_csum48(*csum, nd_opt->nd_opt_data, sll);
-                memcpy(nd_opt->nd_opt_data, sll, ETH_ADDR_LEN);
+                *csum = recalc_csum48(*csum, nd_opt->nd_opt_mac, sll);
+                nd_opt->nd_opt_mac = sll;
             }
 
             /* A packet can only contain one SLL or TLL option */
             break;
         } else if (nd_opt->nd_opt_type == ND_OPT_TARGET_LINKADDR
                    && nd_opt->nd_opt_len == 1) {
-            if (memcmp(nd_opt->nd_opt_data, tll, ETH_ADDR_LEN)) {
+            if (!eth_addr_equals(nd_opt->nd_opt_mac, tll)) {
                 ovs_be16 *csum = &(ns->icmph.icmp6_cksum);
 
-                *csum = recalc_csum48(*csum, nd_opt->nd_opt_data, tll);
-                memcpy(nd_opt->nd_opt_data, tll, ETH_ADDR_LEN);
+                *csum = recalc_csum48(*csum, nd_opt->nd_opt_mac, tll);
+                nd_opt->nd_opt_mac = tll;
             }
 
             /* A packet can only contain one SLL or TLL option */
@@ -1031,9 +1018,8 @@ packet_format_tcp_flags(struct ds *s, uint16_t tcp_flags)
  * 'broadcast' is true. */
 void
 compose_arp(struct dp_packet *b, uint16_t arp_op,
-            const uint8_t arp_sha[ETH_ADDR_LEN],
-            const uint8_t arp_tha[ETH_ADDR_LEN], bool broadcast,
-            ovs_be32 arp_spa, ovs_be32 arp_tpa)
+            const struct eth_addr arp_sha, const struct eth_addr arp_tha,
+            bool broadcast, ovs_be32 arp_spa, ovs_be32 arp_tpa)
 {
     struct eth_header *eth;
     struct arp_eth_header *arp;
@@ -1043,9 +1029,8 @@ compose_arp(struct dp_packet *b, uint16_t arp_op,
     dp_packet_reserve(b, 2 + VLAN_HEADER_LEN);
 
     eth = dp_packet_put_uninit(b, sizeof *eth);
-    memcpy(eth->eth_dst, broadcast ? eth_addr_broadcast : arp_tha,
-           ETH_ADDR_LEN);
-    memcpy(eth->eth_src, arp_sha, ETH_ADDR_LEN);
+    eth->eth_dst = broadcast ? eth_addr_broadcast : arp_tha;
+    eth->eth_src = arp_sha;
     eth->eth_type = htons(ETH_TYPE_ARP);
 
     arp = dp_packet_put_uninit(b, sizeof *arp);
@@ -1054,8 +1039,8 @@ compose_arp(struct dp_packet *b, uint16_t arp_op,
     arp->ar_hln = sizeof arp->ar_sha;
     arp->ar_pln = sizeof arp->ar_spa;
     arp->ar_op = htons(arp_op);
-    memcpy(arp->ar_sha, arp_sha, ETH_ADDR_LEN);
-    memcpy(arp->ar_tha, arp_tha, ETH_ADDR_LEN);
+    arp->ar_sha = arp_sha;
+    arp->ar_tha = arp_tha;
 
     put_16aligned_be32(&arp->ar_spa, arp_spa);
     put_16aligned_be32(&arp->ar_tpa, arp_tpa);
diff --git a/lib/packets.h b/lib/packets.h
index 7140c83..fd235dc 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -147,133 +147,145 @@ bool dpid_from_string(const char *s, uint64_t *dpidp);
 
 #define ETH_ADDR_LEN           6
 
-static const uint8_t eth_addr_broadcast[ETH_ADDR_LEN] OVS_UNUSED
-    = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+static const struct eth_addr eth_addr_broadcast OVS_UNUSED
+    = { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } } };
 
-static const uint8_t eth_addr_zero[ETH_ADDR_LEN] OVS_UNUSED
-    = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static const struct eth_addr eth_addr_exact OVS_UNUSED
+    = { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } } };
 
-static const uint8_t eth_addr_stp[ETH_ADDR_LEN] OVS_UNUSED
-    = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x00 };
+static const struct eth_addr eth_addr_zero OVS_UNUSED
+    = { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } };
 
-static const uint8_t eth_addr_lacp[ETH_ADDR_LEN] OVS_UNUSED
-    = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x02 };
+static const struct eth_addr eth_addr_stp OVS_UNUSED
+    = { { { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x00 } } };
 
-static const uint8_t eth_addr_bfd[ETH_ADDR_LEN] OVS_UNUSED
-    = { 0x00, 0x23, 0x20, 0x00, 0x00, 0x01 };
+static const struct eth_addr eth_addr_lacp OVS_UNUSED
+    = { { { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x02 } } };
 
-static inline bool eth_addr_is_broadcast(const uint8_t ea[ETH_ADDR_LEN])
+static const struct eth_addr eth_addr_bfd OVS_UNUSED
+    = { { { 0x00, 0x23, 0x20, 0x00, 0x00, 0x01 } } };
+
+static inline bool eth_addr_is_broadcast(const struct eth_addr a)
 {
-    return (ea[0] & ea[1] & ea[2] & ea[3] & ea[4] & ea[5]) == 0xff;
+    return (a.be16[0] & a.be16[1] & a.be16[2]) == htons(0xffff);
 }
 
-static inline bool eth_addr_is_multicast(const uint8_t ea[ETH_ADDR_LEN])
+static inline bool eth_addr_is_multicast(const struct eth_addr a)
 {
-    return ea[0] & 1;
+    return a.ea[0] & 1;
 }
-static inline bool eth_addr_is_local(const uint8_t ea[ETH_ADDR_LEN])
+
+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 ea[0] & 2
-       || (ea[0] == 0x00 && ea[1] == 0x23 && ea[2] == 0x20 && ea[3] & 0x80);
+    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 uint8_t ea[ETH_ADDR_LEN])
+static inline bool eth_addr_is_zero(const struct eth_addr a)
 {
-    return !(ea[0] | ea[1] | ea[2] | ea[3] | ea[4] | ea[5]);
+    return !(a.be16[0] | a.be16[1] | a.be16[2]);
 }
 
-static inline int eth_mask_is_exact(const uint8_t ea[ETH_ADDR_LEN])
+static inline int eth_mask_is_exact(const struct eth_addr a)
 {
-    return (ea[0] & ea[1] & ea[2] & ea[3] & ea[4] & ea[5]) == 0xff;
+    return (a.be16[0] & a.be16[1] & a.be16[2]) == htons(0xffff);
 }
 
-static inline int eth_addr_compare_3way(const uint8_t a[ETH_ADDR_LEN],
-                                        const uint8_t b[ETH_ADDR_LEN])
+static inline int eth_addr_compare_3way(const struct eth_addr a,
+                                        const struct eth_addr b)
 {
-    return memcmp(a, b, ETH_ADDR_LEN);
+    return memcmp(&a, &b, sizeof a);
 }
-static inline bool eth_addr_equals(const uint8_t a[ETH_ADDR_LEN],
-                                   const uint8_t b[ETH_ADDR_LEN])
+
+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_addr_equal_except(const uint8_t a[ETH_ADDR_LEN],
-                                    const uint8_t b[ETH_ADDR_LEN],
-                                    const uint8_t mask[ETH_ADDR_LEN])
+
+static inline bool eth_addr_equal_except(const struct eth_addr a,
+                                         const struct eth_addr b,
+                                         const struct eth_addr mask)
 {
-    return !(((a[0] ^ b[0]) & mask[0])
-             || ((a[1] ^ b[1]) & mask[1])
-             || ((a[2] ^ b[2]) & mask[2])
-             || ((a[3] ^ b[3]) & mask[3])
-             || ((a[4] ^ b[4]) & mask[4])
-             || ((a[5] ^ b[5]) & mask[5]));
+    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]));
 }
-static inline uint64_t eth_addr_to_uint64(const uint8_t ea[ETH_ADDR_LEN])
+
+static inline uint64_t eth_addr_to_uint64(const struct eth_addr ea)
 {
-    return (((uint64_t) ea[0] << 40)
-            | ((uint64_t) ea[1] << 32)
-            | ((uint64_t) ea[2] << 24)
-            | ((uint64_t) ea[3] << 16)
-            | ((uint64_t) ea[4] << 8)
-            | ea[5]);
+    return (((uint64_t) ntohs(ea.be16[0]) << 32)
+            | ((uint64_t) ntohs(ea.be16[1]) << 16)
+            | ntohs(ea.be16[2]));
 }
-static inline uint64_t eth_addr_vlan_to_uint64(const uint8_t ea[ETH_ADDR_LEN],
+
+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));
 }
-static inline void eth_addr_from_uint64(uint64_t x, uint8_t ea[ETH_ADDR_LEN])
+
+static inline void eth_addr_from_uint64(uint64_t x, struct eth_addr *ea)
+{
+    ea->be16[0] = htons(x >> 32);
+    ea->be16[1] = htons(x >> 16);
+    ea->be16[2] = htons(x);
+}
+
+static inline struct eth_addr eth_addr_invert(const struct eth_addr src)
 {
-    ea[0] = x >> 40;
-    ea[1] = x >> 32;
-    ea[2] = x >> 24;
-    ea[3] = x >> 16;
-    ea[4] = x >> 8;
-    ea[5] = x;
+    struct eth_addr dst;
+
+    for (int i = 0; i < ARRAY_SIZE(src.be16); i++) {
+        dst.be16[i] = ~src.be16[i];
+    }
+
+    return dst;
 }
-static inline void eth_addr_mark_random(uint8_t ea[ETH_ADDR_LEN])
+
+static inline void eth_addr_mark_random(struct eth_addr *ea)
 {
-    ea[0] &= ~1;                /* Unicast. */
-    ea[0] |= 2;                 /* Private. */
+    ea->ea[0] &= ~1;                /* Unicast. */
+    ea->ea[0] |= 2;                 /* Private. */
 }
-static inline void eth_addr_random(uint8_t ea[ETH_ADDR_LEN])
+
+static inline void eth_addr_random(struct eth_addr *ea)
 {
-    random_bytes(ea, ETH_ADDR_LEN);
+    random_bytes((uint8_t *)ea, sizeof *ea);
     eth_addr_mark_random(ea);
 }
-static inline void eth_addr_nicira_random(uint8_t ea[ETH_ADDR_LEN])
+
+static inline void eth_addr_nicira_random(struct eth_addr *ea)
 {
     eth_addr_random(ea);
 
     /* Set the OUI to the Nicira one. */
-    ea[0] = 0x00;
-    ea[1] = 0x23;
-    ea[2] = 0x20;
+    ea->ea[0] = 0x00;
+    ea->ea[1] = 0x23;
+    ea->ea[2] = 0x20;
 
     /* Set the top bit to indicate random Nicira address. */
-    ea[3] |= 0x80;
+    ea->ea[3] |= 0x80;
 }
-static inline uint32_t hash_mac(const uint8_t ea[ETH_ADDR_LEN],
+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 uint8_t ea[ETH_ADDR_LEN]);
-bool eth_addr_from_string(const char *, uint8_t ea[ETH_ADDR_LEN]);
+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 uint8_t eth_src[ETH_ADDR_LEN]);
+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 uint8_t eth[ETH_ADDR_LEN],
-                       const uint8_t mask[ETH_ADDR_LEN], struct ds *s);
-void eth_addr_bitand(const uint8_t src[ETH_ADDR_LEN],
-                     const uint8_t mask[ETH_ADDR_LEN],
-                     uint8_t dst[ETH_ADDR_LEN]);
+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);
@@ -288,20 +300,20 @@ ovs_be32 set_mpls_lse_values(uint8_t ttl, uint8_t tc, uint8_t bos,
 
 /* Example:
  *
- * uint8_t mac[ETH_ADDR_LEN];
+ * 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)                                   \
-    (ea)[0], (ea)[1], (ea)[2], (ea)[3], (ea)[4], (ea)[5]
+#define ETH_ADDR_ARGS(EA)                                               \
+    (EA).ea[0], (EA).ea[1], (EA).ea[2], (EA).ea[3], (EA).ea[4], (EA).ea[5]
 
 /* Example:
  *
  * char *string = "1 00:11:22:33:44:55 2";
- * uint8_t mac[ETH_ADDR_LEN];
+ * struct eth_addr mac;
  * int a, b;
  *
  * if (ovs_scan(string, "%d"ETH_ADDR_SCAN_FMT"%d",
@@ -310,8 +322,8 @@ ovs_be32 set_mpls_lse_values(uint8_t ttl, uint8_t tc, uint8_t bos,
  * }
  */
 #define ETH_ADDR_SCAN_FMT "%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8
-#define ETH_ADDR_SCAN_ARGS(ea) \
-        &(ea)[0], &(ea)[1], &(ea)[2], &(ea)[3], &(ea)[4], &(ea)[5]
+#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
@@ -350,8 +362,8 @@ static inline bool eth_type_vlan(ovs_be16 eth_type)
 #define ETH_VLAN_TOTAL_MAX (ETH_HEADER_LEN + VLAN_HEADER_LEN + ETH_PAYLOAD_MAX)
 OVS_PACKED(
 struct eth_header {
-    uint8_t eth_dst[ETH_ADDR_LEN];
-    uint8_t eth_src[ETH_ADDR_LEN];
+    struct eth_addr eth_dst;
+    struct eth_addr eth_src;
     ovs_be16 eth_type;
 });
 BUILD_ASSERT_DECL(ETH_HEADER_LEN == sizeof(struct eth_header));
@@ -435,8 +447,8 @@ BUILD_ASSERT_DECL(VLAN_HEADER_LEN == sizeof(struct vlan_header));
 #define VLAN_ETH_HEADER_LEN (ETH_HEADER_LEN + VLAN_HEADER_LEN)
 OVS_PACKED(
 struct vlan_eth_header {
-    uint8_t veth_dst[ETH_ADDR_LEN];
-    uint8_t veth_src[ETH_ADDR_LEN];
+    struct eth_addr veth_dst;
+    struct eth_addr veth_src;
     ovs_be16 veth_type;         /* Always htons(ETH_TYPE_VLAN). */
     ovs_be16 veth_tci;          /* Lowest 12 bits are VLAN ID. */
     ovs_be16 veth_next_type;
@@ -713,10 +725,10 @@ struct arp_eth_header {
     ovs_be16 ar_op;            /* Opcode. */
 
     /* Ethernet+IPv4 specific members. */
-    uint8_t ar_sha[ETH_ADDR_LEN]; /* Sender hardware address. */
-    ovs_16aligned_be32 ar_spa;           /* Sender protocol address. */
-    uint8_t ar_tha[ETH_ADDR_LEN]; /* Target hardware address. */
-    ovs_16aligned_be32 ar_tpa;           /* Target protocol address. */
+    struct eth_addr ar_sha;     /* Sender hardware address. */
+    ovs_16aligned_be32 ar_spa;  /* Sender protocol address. */
+    struct eth_addr ar_tha;     /* Target hardware address. */
+    ovs_16aligned_be32 ar_tpa;  /* Target protocol address. */
 };
 BUILD_ASSERT_DECL(ARP_ETH_HEADER_LEN == sizeof(struct arp_eth_header));
 
@@ -766,7 +778,7 @@ BUILD_ASSERT_DECL(ICMP6_HEADER_LEN == sizeof(struct icmp6_header));
 struct ovs_nd_opt {
     uint8_t  nd_opt_type;      /* Values defined in icmp6.h */
     uint8_t  nd_opt_len;       /* in units of 8 octets (the size of this struct) */
-    uint8_t  nd_opt_data[6];   /* Ethernet address in the case of SLL or TLL options */
+    struct eth_addr nd_opt_mac;   /* Ethernet address in the case of SLL or TLL options */
 };
 BUILD_ASSERT_DECL(ND_OPT_LEN == sizeof(struct ovs_nd_opt));
 
@@ -899,11 +911,11 @@ 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);
 
-void *eth_compose(struct dp_packet *, const uint8_t eth_dst[ETH_ADDR_LEN],
-                  const uint8_t eth_src[ETH_ADDR_LEN], uint16_t eth_type,
+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);
-void *snap_compose(struct dp_packet *, const uint8_t eth_dst[ETH_ADDR_LEN],
-                   const uint8_t eth_src[ETH_ADDR_LEN],
+void *snap_compose(struct dp_packet *, const struct eth_addr eth_dst,
+                   const struct eth_addr eth_src,
                    unsigned int oui, uint16_t snap_type, size_t size);
 void packet_set_ipv4(struct dp_packet *, ovs_be32 src, ovs_be32 dst, uint8_t tos,
                      uint8_t ttl);
@@ -914,13 +926,13 @@ void packet_set_tcp_port(struct dp_packet *, ovs_be16 src, ovs_be16 dst);
 void packet_set_udp_port(struct dp_packet *, ovs_be16 src, ovs_be16 dst);
 void packet_set_sctp_port(struct dp_packet *, ovs_be16 src, ovs_be16 dst);
 void packet_set_nd(struct dp_packet *, const ovs_be32 target[4],
-                   const uint8_t sll[6], const uint8_t tll[6]);
+                   const struct eth_addr sll, const struct eth_addr tll);
 
 void packet_format_tcp_flags(struct ds *, uint16_t);
 const char *packet_tcp_flag_to_string(uint32_t flag);
 void compose_arp(struct dp_packet *, uint16_t arp_op,
-                 const uint8_t arp_sha[ETH_ADDR_LEN],
-                 const uint8_t arp_tha[ETH_ADDR_LEN], bool broadcast,
+                 const struct eth_addr arp_sha,
+                 const struct eth_addr arp_tha, bool broadcast,
                  ovs_be32 arp_spa, ovs_be32 arp_tpa);
 uint32_t packet_csum_pseudoheader(const struct ip_header *);
 
diff --git a/lib/rstp-state-machines.c b/lib/rstp-state-machines.c
index f55221f..a5e1869 100644
--- a/lib/rstp-state-machines.c
+++ b/lib/rstp-state-machines.c
@@ -700,7 +700,7 @@ rstp_send_bpdu(struct rstp_port *p, const void *bpdu, size_t bpdu_size)
     dp_packet_set_l3(pkt, dp_packet_put(pkt, bpdu, bpdu_size));
 
     /* 802.2 header. */
-    memcpy(eth->eth_dst, eth_addr_stp, ETH_ADDR_LEN);
+    eth->eth_dst = eth_addr_stp;
     /* p->rstp->send_bpdu() must fill in source address. */
     eth->eth_type = htons(dp_packet_size(pkt) - ETH_HEADER_LEN);
 
diff --git a/lib/rtnetlink.c b/lib/rtnetlink.c
index 1ecd23b..d0c1ee7 100644
--- a/lib/rtnetlink.c
+++ b/lib/rtnetlink.c
@@ -87,11 +87,11 @@ rtnetlink_parse(struct ofpbuf *buf, struct rtnetlink_change *change)
                                       : 0);
 
             if (attrs[IFLA_ADDRESS] &&
-                nl_attr_get_size(attrs[IFLA_ADDRESS]) == ETH_ALEN) {
-                memcpy(change->addr, nl_attr_get(attrs[IFLA_ADDRESS]),
-                       ETH_ALEN);
+                nl_attr_get_size(attrs[IFLA_ADDRESS]) == ETH_ADDR_LEN) {
+                memcpy(&change->mac, nl_attr_get(attrs[IFLA_ADDRESS]),
+                       ETH_ADDR_LEN);
             } else {
-                memset(change->addr, 0, ETH_ALEN);
+                memset(&change->mac, 0, ETH_ADDR_LEN);
             }
         }
     } else if (rtnetlink_type_is_rtnlgrp_addr(nlmsg->nlmsg_type)) {
diff --git a/lib/rtnetlink.h b/lib/rtnetlink.h
index f2da394..91ed486 100644
--- a/lib/rtnetlink.h
+++ b/lib/rtnetlink.h
@@ -21,6 +21,8 @@
 #include <stdint.h>
 #include <linux/if_ether.h>
 
+#include "openvswitch/types.h"
+
 struct ofpbuf;
 struct nln_notifier;
 
@@ -41,7 +43,7 @@ struct rtnetlink_change {
     /* Network device link status. */
     int master_ifindex;         /* Ifindex of datapath master (0 if none). */
     int mtu;                    /* Current MTU. */
-    uint8_t addr[ETH_ALEN];
+    struct eth_addr mac;
     unsigned int ifi_flags;     /* Flags of network device. */
 
     /* Network device address status. */
diff --git a/lib/sflow.h b/lib/sflow.h
index 475ccaf..95bedd9 100644
--- a/lib/sflow.h
+++ b/lib/sflow.h
@@ -12,6 +12,8 @@
 #include "windefs.h"
 #endif
 
+#include "openvswitch/types.h"
+
 typedef enum {
     SFL_DSCLASS_IFINDEX = 0,
     SFL_DSCLASS_VLAN = 1,
@@ -81,8 +83,10 @@ typedef struct _SFLSampled_header {
 typedef struct _SFLSampled_ethernet {
     u_int32_t eth_len;       /* The length of the MAC packet excluding
 				lower layer encapsulations */
-    u_int8_t src_mac[8];    /* 6 bytes + 2 pad */
-    u_int8_t dst_mac[8];
+    struct eth_addr src_mac;    /* 6 bytes */
+    u_int8_t pad1[2];           /* 2 pad */
+    struct eth_addr dst_mac;
+    u_int8_t pad2[2];
     u_int32_t eth_type;
 } SFLSampled_ethernet;
 
@@ -527,8 +531,10 @@ typedef  union _SFLLACP_portState {
 } SFLLACP_portState;
 
 typedef struct _SFLLACP_counters {
-    uint8_t actorSystemID[8];   /* 6 bytes + 2 pad */
-    uint8_t partnerSystemID[8]; /* 6 bytes + 2 pad */
+    struct eth_addr actorSystemID;   /* 6 bytes */
+    uint8_t pad1[2];
+    struct eth_addr partnerSystemID; /* 6 bytes */
+    uint8_t pad2[2];
     uint32_t attachedAggID;
     SFLLACP_portState portState;
     uint32_t LACPDUsRx;
diff --git a/lib/sflow_receiver.c b/lib/sflow_receiver.c
index dd515eb..cde1359 100644
--- a/lib/sflow_receiver.c
+++ b/lib/sflow_receiver.c
@@ -227,9 +227,10 @@ inline static u_int32_t addressEncodingLength(SFLAddress *addr) {
     return (addr->type == SFLADDRESSTYPE_IP_V6) ? 20 : 8;  // type + address (unspecified == IPV4)
 }
 
-inline static void putMACAddress(SFLReceiver *receiver, u_int8_t *mac)
+inline static void putMACAddress(SFLReceiver *receiver,
+                                 const struct eth_addr mac)
 {
-    memcpy(receiver->sampleCollector.datap, mac, 6);
+    memcpy(receiver->sampleCollector.datap, &mac, 6);
     receiver->sampleCollector.datap += 2;
 }
 
diff --git a/lib/stp.c b/lib/stp.c
index 22bd93a..467b0ba 100644
--- a/lib/stp.c
+++ b/lib/stp.c
@@ -1580,7 +1580,7 @@ stp_send_bpdu(struct stp_port *p, const void *bpdu, size_t bpdu_size)
     dp_packet_set_l3(pkt, dp_packet_put(pkt, bpdu, bpdu_size));
 
     /* 802.2 header. */
-    memcpy(eth->eth_dst, eth_addr_stp, ETH_ADDR_LEN);
+    eth->eth_dst = eth_addr_stp;
     /* p->stp->send_bpdu() must fill in source address. */
     eth->eth_type = htons(dp_packet_size(pkt) - ETH_HEADER_LEN);
 
diff --git a/lib/tnl-arp-cache.c b/lib/tnl-arp-cache.c
index 16a805e..3107631 100644
--- a/lib/tnl-arp-cache.c
+++ b/lib/tnl-arp-cache.c
@@ -44,7 +44,7 @@
 struct tnl_arp_entry {
     struct cmap_node cmap_node;
     ovs_be32 ip;
-    uint8_t mac[ETH_ADDR_LEN];
+    struct eth_addr mac;
     time_t expires;             /* Expiration time. */
     char br_name[IFNAMSIZ];
 };
@@ -68,14 +68,14 @@ tnl_arp_lookup__(const char br_name[IFNAMSIZ], ovs_be32 dst)
 
 int
 tnl_arp_lookup(const char br_name[IFNAMSIZ], ovs_be32 dst,
-               uint8_t mac[ETH_ADDR_LEN])
+               struct eth_addr *mac)
 {
     struct tnl_arp_entry *arp;
     int res = ENOENT;
 
     arp = tnl_arp_lookup__(br_name, dst);
     if (arp) {
-        memcpy(mac, arp->mac, ETH_ADDR_LEN);
+        *mac = arp->mac;
         res = 0;
     }
 
@@ -113,7 +113,7 @@ tnl_arp_snoop(const struct flow *flow, struct flow_wildcards *wc,
     ovs_mutex_lock(&mutex);
     arp = tnl_arp_lookup__(name, flow->nw_src);
     if (arp) {
-        if (!memcmp(arp->mac, flow->arp_sha, ETH_ADDR_LEN)) {
+        if (eth_addr_equals(arp->mac, flow->arp_sha)) {
             arp->expires = time_now() + ARP_ENTRY_DEFAULT_IDLE_TIME;
             ovs_mutex_unlock(&mutex);
             return 0;
@@ -125,7 +125,7 @@ tnl_arp_snoop(const struct flow *flow, struct flow_wildcards *wc,
     arp = xmalloc(sizeof *arp);
 
     arp->ip = flow->nw_src;
-    memcpy(arp->mac, flow->arp_sha, ETH_ADDR_LEN);
+    arp->mac = flow->arp_sha;
     arp->expires = time_now() + ARP_ENTRY_DEFAULT_IDLE_TIME;
     ovs_strlcpy(arp->br_name, name, sizeof arp->br_name);
     cmap_insert(&table, &arp->cmap_node, (OVS_FORCE uint32_t) arp->ip);
diff --git a/lib/tnl-arp-cache.h b/lib/tnl-arp-cache.h
index 8b8dc0a..acc4ff7 100644
--- a/lib/tnl-arp-cache.h
+++ b/lib/tnl-arp-cache.h
@@ -33,7 +33,7 @@
 
 int tnl_arp_snoop(const struct flow *flow, struct flow_wildcards *wc,
                   const char dev_name[]);
-int tnl_arp_lookup(const char dev_name[], ovs_be32 dst, uint8_t mac[ETH_ADDR_LEN]);
+int tnl_arp_lookup(const char dev_name[], ovs_be32 dst, struct eth_addr *mac);
 void tnl_arp_cache_init(void);
 void tnl_arp_cache_run(void);
 
diff --git a/ofproto/bond.c b/ofproto/bond.c
index 64ea82a..d7a7d30 100644
--- a/ofproto/bond.c
+++ b/ofproto/bond.c
@@ -140,7 +140,7 @@ struct bond {
 
     /* Interface name may not be persistent across an OS reboot, use
      * MAC address for identifing the active slave */
-    uint8_t active_slave_mac[ETH_ADDR_LEN];
+    struct eth_addr active_slave_mac;
                                /* The MAC address of the active interface. */
     /* Legacy compatibility. */
     bool lacp_fallback_ab; /* Fallback to active-backup on LACP failure. */
@@ -172,7 +172,7 @@ static void bond_link_status_update(struct bond_slave *)
     OVS_REQ_WRLOCK(rwlock);
 static void bond_choose_active_slave(struct bond *)
     OVS_REQ_WRLOCK(rwlock);
-static unsigned int bond_hash_src(const uint8_t mac[ETH_ADDR_LEN],
+static unsigned int bond_hash_src(const struct eth_addr mac,
                                   uint16_t vlan, uint32_t basis);
 static unsigned int bond_hash_tcp(const struct flow *, uint16_t vlan,
                                   uint32_t basis);
@@ -458,9 +458,7 @@ bond_reconfigure(struct bond *bond, const struct bond_settings *s)
         bond_entry_reset(bond);
     }
 
-    memcpy(bond->active_slave_mac, s->active_slave_mac,
-           sizeof s->active_slave_mac);
-
+    bond->active_slave_mac = s->active_slave_mac;
     bond->active_slave_changed = false;
 
     ovs_rwlock_unlock(&rwlock);
@@ -468,19 +466,19 @@ bond_reconfigure(struct bond *bond, const struct bond_settings *s)
 }
 
 static struct bond_slave *
-bond_find_slave_by_mac(const struct bond *bond, const uint8_t mac[ETH_ADDR_LEN])
+bond_find_slave_by_mac(const struct bond *bond, const struct eth_addr mac)
 {
     struct bond_slave *slave;
 
     /* Find the last active slave */
     HMAP_FOR_EACH(slave, hmap_node, &bond->slaves) {
-        uint8_t slave_mac[ETH_ADDR_LEN];
+        struct eth_addr slave_mac;
 
-        if (netdev_get_etheraddr(slave->netdev, slave_mac)) {
+        if (netdev_get_etheraddr(slave->netdev, &slave_mac)) {
             continue;
         }
 
-        if (!memcmp(slave_mac, mac, sizeof(slave_mac))) {
+        if (eth_addr_equals(slave_mac, mac)) {
             return slave;
         }
     }
@@ -491,10 +489,10 @@ bond_find_slave_by_mac(const struct bond *bond, const uint8_t mac[ETH_ADDR_LEN])
 static void
 bond_active_slave_changed(struct bond *bond)
 {
-    uint8_t mac[ETH_ADDR_LEN];
+    struct eth_addr mac;
 
-    netdev_get_etheraddr(bond->active_slave->netdev, mac);
-    memcpy(bond->active_slave_mac, mac, sizeof bond->active_slave_mac);
+    netdev_get_etheraddr(bond->active_slave->netdev, &mac);
+    bond->active_slave_mac = mac;
     bond->active_slave_changed = true;
     seq_change(connectivity_seq_get());
 }
@@ -721,8 +719,7 @@ bond_should_send_learning_packets(struct bond *bond)
  * caller should send the composed packet on the port associated with
  * port_aux and takes ownership of the returned ofpbuf. */
 struct dp_packet *
-bond_compose_learning_packet(struct bond *bond,
-                             const uint8_t eth_src[ETH_ADDR_LEN],
+bond_compose_learning_packet(struct bond *bond, const struct eth_addr eth_src,
                              uint16_t vlan, void **port_aux)
 {
     struct bond_slave *slave;
@@ -732,7 +729,7 @@ bond_compose_learning_packet(struct bond *bond,
     ovs_rwlock_rdlock(&rwlock);
     ovs_assert(may_send_learning_packets(bond));
     memset(&flow, 0, sizeof flow);
-    memcpy(flow.dl_src, eth_src, ETH_ADDR_LEN);
+    flow.dl_src = eth_src;
     slave = choose_output_slave(bond, &flow, NULL, vlan);
 
     packet = dp_packet_new(0);
@@ -763,7 +760,7 @@ bond_compose_learning_packet(struct bond *bond,
  */
 enum bond_verdict
 bond_check_admissibility(struct bond *bond, const void *slave_,
-                         const uint8_t eth_dst[ETH_ADDR_LEN])
+                         const struct eth_addr eth_dst)
 {
     enum bond_verdict verdict = BV_DROP;
     struct bond_slave *slave;
@@ -1562,7 +1559,7 @@ bond_unixctl_hash(struct unixctl_conn *conn, int argc, const char *argv[],
     const char *mac_s = argv[1];
     const char *vlan_s = argc > 2 ? argv[2] : NULL;
     const char *basis_s = argc > 3 ? argv[3] : NULL;
-    uint8_t mac[ETH_ADDR_LEN];
+    struct eth_addr mac;
     uint8_t hash;
     char *hash_cstr;
     unsigned int vlan;
@@ -1705,7 +1702,7 @@ bond_link_status_update(struct bond_slave *slave)
 }
 
 static unsigned int
-bond_hash_src(const uint8_t mac[ETH_ADDR_LEN], uint16_t vlan, uint32_t basis)
+bond_hash_src(const struct eth_addr mac, uint16_t vlan, uint32_t basis)
 {
     return hash_mac(mac, vlan, basis);
 }
@@ -1871,7 +1868,8 @@ bond_choose_active_slave(struct bond *bond)
  * If return true, 'mac' will store the bond's current active slave's
  * MAC address.  */
 bool
-bond_get_changed_active_slave(const char *name, uint8_t* mac, bool force)
+bond_get_changed_active_slave(const char *name, struct eth_addr *mac,
+                              bool force)
 {
     struct bond *bond;
 
@@ -1879,7 +1877,7 @@ bond_get_changed_active_slave(const char *name, uint8_t* mac, bool force)
     bond = bond_find(name);
     if (bond) {
         if (bond->active_slave_changed || force) {
-            memcpy(mac, bond->active_slave_mac, ETH_ADDR_LEN);
+            *mac = bond->active_slave_mac;
             bond->active_slave_changed = false;
             ovs_rwlock_unlock(&rwlock);
             return true;
diff --git a/ofproto/bond.h b/ofproto/bond.h
index 9082354..9a5ea9e 100644
--- a/ofproto/bond.h
+++ b/ofproto/bond.h
@@ -54,7 +54,7 @@ struct bond_settings {
 
     bool lacp_fallback_ab_cfg;  /* Fallback to active-backup on LACP failure. */
 
-    uint8_t active_slave_mac[ETH_ADDR_LEN];
+    struct eth_addr active_slave_mac;
                                 /* The MAC address of the interface
                                    that was active during the last
                                    ovs run. */
@@ -82,9 +82,9 @@ void bond_slave_set_may_enable(struct bond *, void *slave_, bool may_enable);
 /* Special MAC learning support for SLB bonding. */
 bool bond_should_send_learning_packets(struct bond *);
 struct dp_packet *bond_compose_learning_packet(struct bond *,
-                                            const uint8_t eth_src[ETH_ADDR_LEN],
-                                            uint16_t vlan, void **port_aux);
-bool bond_get_changed_active_slave(const char *name, uint8_t mac[ETH_ADDR_LEN],
+                                               const struct eth_addr eth_src,
+                                               uint16_t vlan, void **port_aux);
+bool bond_get_changed_active_slave(const char *name, struct eth_addr *mac,
                                    bool force);
 
 /* Packet processing. */
@@ -94,7 +94,7 @@ enum bond_verdict {
     BV_DROP_IF_MOVED            /* Drop if we've learned a different port. */
 };
 enum bond_verdict bond_check_admissibility(struct bond *, const void *slave_,
-                                           const uint8_t dst[ETH_ADDR_LEN]);
+                                           const struct eth_addr dst);
 void *bond_choose_output_slave(struct bond *, const struct flow *,
                                struct flow_wildcards *, uint16_t vlan);
 
diff --git a/ofproto/fail-open.c b/ofproto/fail-open.c
index 4abc66e..38e775a 100644
--- a/ofproto/fail-open.c
+++ b/ofproto/fail-open.c
@@ -119,11 +119,11 @@ static void
 send_bogus_packet_ins(struct fail_open *fo)
 {
     struct ofproto_packet_in pin;
-    uint8_t mac[ETH_ADDR_LEN];
+    struct eth_addr mac;
     struct dp_packet b;
 
     dp_packet_init(&b, 128);
-    eth_addr_nicira_random(mac);
+    eth_addr_nicira_random(&mac);
     compose_rarp(&b, mac);
 
     memset(&pin, 0, sizeof pin);
diff --git a/ofproto/in-band.c b/ofproto/in-band.c
index 3608c13..ea7e315 100644
--- a/ofproto/in-band.c
+++ b/ofproto/in-band.c
@@ -67,10 +67,10 @@ enum {
 
 /* Track one remote IP and next hop information. */
 struct in_band_remote {
-    struct sockaddr_in remote_addr; /* IP address, in network byte order. */
-    uint8_t remote_mac[ETH_ADDR_LEN]; /* Next-hop MAC, all-zeros if unknown. */
-    uint8_t last_remote_mac[ETH_ADDR_LEN]; /* Previous nonzero next-hop MAC. */
-    struct netdev *remote_netdev; /* Device to send to next-hop MAC. */
+    struct sockaddr_in remote_addr;  /* IP address, in network byte order. */
+    struct eth_addr remote_mac;      /* Next-hop MAC, all-zeros if unknown. */
+    struct eth_addr last_remote_mac; /* Previous nonzero next-hop MAC. */
+    struct netdev *remote_netdev;    /* Device to send to next-hop MAC. */
 };
 
 /* What to do to an in_band_rule. */
@@ -98,7 +98,7 @@ struct in_band {
 
     /* Local information. */
     time_t next_local_refresh;       /* Refresh timer. */
-    uint8_t local_mac[ETH_ADDR_LEN]; /* Current MAC. */
+    struct eth_addr local_mac;       /* Current MAC. */
     struct netdev *local_netdev;     /* Local port's network device. */
 
     /* Flow tracking. */
@@ -115,7 +115,7 @@ refresh_remote(struct in_band *ib, struct in_band_remote *r)
     int retval;
 
     /* Find the next-hop IP address. */
-    memset(r->remote_mac, 0, sizeof r->remote_mac);
+    r->remote_mac = eth_addr_zero;
     retval = netdev_get_next_hop(ib->local_netdev, &r->remote_addr.sin_addr,
                                  &next_hop_inaddr, &next_hop_dev);
     if (retval) {
@@ -149,7 +149,7 @@ refresh_remote(struct in_band *ib, struct in_band_remote *r)
 
     /* Look up the MAC address of the next-hop IP address. */
     retval = netdev_arp_lookup(r->remote_netdev, next_hop_inaddr.s_addr,
-                               r->remote_mac);
+                               &r->remote_mac);
     if (retval) {
         VLOG_DBG_RL(&rl, "%s: cannot look up remote MAC address ("IP_FMT"): %s",
                     ib->ofproto->name, IP_ARGS(next_hop_inaddr.s_addr),
@@ -175,11 +175,11 @@ refresh_remotes(struct in_band *ib)
     any_changes = false;
     ib->next_remote_refresh = TIME_MAX;
     for (r = ib->remotes; r < &ib->remotes[ib->n_remotes]; r++) {
-        uint8_t old_remote_mac[ETH_ADDR_LEN];
+        struct eth_addr old_remote_mac;
         time_t next_refresh;
 
         /* Save old MAC. */
-        memcpy(old_remote_mac, r->remote_mac, ETH_ADDR_LEN);
+        old_remote_mac = r->remote_mac;
 
         /* Refresh remote information. */
         next_refresh = refresh_remote(ib, r) + time_now();
@@ -195,7 +195,7 @@ refresh_remotes(struct in_band *ib)
                          ib->ofproto->name,
                          ETH_ADDR_ARGS(r->last_remote_mac),
                          ETH_ADDR_ARGS(r->remote_mac));
-                memcpy(r->last_remote_mac, r->remote_mac, ETH_ADDR_LEN);
+                r->last_remote_mac = r->remote_mac;
             }
         }
     }
@@ -208,7 +208,7 @@ refresh_remotes(struct in_band *ib)
 static bool
 refresh_local(struct in_band *ib)
 {
-    uint8_t ea[ETH_ADDR_LEN];
+    struct eth_addr ea;
     time_t now;
 
     now = time_now();
@@ -217,12 +217,12 @@ refresh_local(struct in_band *ib)
     }
     ib->next_local_refresh = now + 1;
 
-    if (netdev_get_etheraddr(ib->local_netdev, ea)
+    if (netdev_get_etheraddr(ib->local_netdev, &ea)
         || eth_addr_equals(ea, ib->local_mac)) {
         return false;
     }
 
-    memcpy(ib->local_mac, ea, ETH_ADDR_LEN);
+    ib->local_mac = ea;
     return true;
 }
 
@@ -306,23 +306,21 @@ update_rules(struct in_band *ib)
     }
 
     for (r = ib->remotes; r < &ib->remotes[ib->n_remotes]; r++) {
-        const uint8_t *remote_mac = r->remote_mac;
-
-        if (eth_addr_is_zero(remote_mac)) {
+        if (eth_addr_is_zero(r->remote_mac)) {
             continue;
         }
 
         /* (d) Allow ARP replies to the next hop's MAC address. */
         match_init_catchall(&match);
         match_set_dl_type(&match, htons(ETH_TYPE_ARP));
-        match_set_dl_dst(&match, remote_mac);
+        match_set_dl_dst(&match, r->remote_mac);
         match_set_nw_proto(&match, ARP_OP_REPLY);
         add_rule(ib, &match, IBR_TO_NEXT_HOP_ARP);
 
         /* (e) Allow ARP requests from the next hop's MAC address. */
         match_init_catchall(&match);
         match_set_dl_type(&match, htons(ETH_TYPE_ARP));
-        match_set_dl_src(&match, remote_mac);
+        match_set_dl_src(&match, r->remote_mac);
         match_set_nw_proto(&match, ARP_OP_REQUEST);
         add_rule(ib, &match, IBR_FROM_NEXT_HOP_ARP);
     }
diff --git a/ofproto/ofproto-dpif-ipfix.c b/ofproto/ofproto-dpif-ipfix.c
index 0adf393..b4d3ea0 100644
--- a/ofproto/ofproto-dpif-ipfix.c
+++ b/ofproto/ofproto-dpif-ipfix.c
@@ -230,8 +230,8 @@ OVS_PACKED(
 struct ipfix_data_record_flow_key_common {
     ovs_be32 observation_point_id;  /* OBSERVATION_POINT_ID */
     uint8_t flow_direction;  /* FLOW_DIRECTION */
-    uint8_t source_mac_address[ETH_ADDR_LEN]; /* SOURCE_MAC_ADDRESS */
-    uint8_t destination_mac_address[ETH_ADDR_LEN]; /* DESTINATION_MAC_ADDRESS */
+    struct eth_addr source_mac_address; /* SOURCE_MAC_ADDRESS */
+    struct eth_addr destination_mac_address; /* DESTINATION_MAC_ADDRESS */
     ovs_be16 ethernet_type;  /* ETHERNET_TYPE */
     uint8_t ethernet_header_length;  /* ETHERNET_HEADER_LENGTH */
 });
@@ -1438,10 +1438,8 @@ ipfix_cache_entry_init(struct ipfix_flow_cache_entry *entry,
         data_common->observation_point_id = htonl(obs_point_id);
         data_common->flow_direction =
             (output_odp_port == ODPP_NONE) ? INGRESS_FLOW : EGRESS_FLOW;
-        memcpy(data_common->source_mac_address, flow->dl_src,
-               sizeof flow->dl_src);
-        memcpy(data_common->destination_mac_address, flow->dl_dst,
-               sizeof flow->dl_dst);
+        data_common->source_mac_address = flow->dl_src;
+        data_common->destination_mac_address = flow->dl_dst;
         data_common->ethernet_type = flow->dl_type;
         data_common->ethernet_header_length = ethernet_header_length;
     }
diff --git a/ofproto/ofproto-dpif-monitor.c b/ofproto/ofproto-dpif-monitor.c
index 252a5d8..0548400 100644
--- a/ofproto/ofproto-dpif-monitor.c
+++ b/ofproto/ofproto-dpif-monitor.c
@@ -53,7 +53,7 @@ struct mport {
     struct cfm *cfm;                  /* Reference to cfm. */
     struct bfd *bfd;                  /* Reference to bfd. */
     struct lldp *lldp;                /* Reference to lldp. */
-    uint8_t hw_addr[OFP_ETH_ALEN];    /* Hardware address. */
+    struct eth_addr hw_addr;          /* Hardware address. */
 };
 
 /* Entry of the 'send_soon' list.  Contains the pointer to the
@@ -88,12 +88,13 @@ static void monitor_run(void);
 static void monitor_mport_run(struct mport *, struct dp_packet *);
 
 static void mport_register(const struct ofport_dpif *, struct bfd *,
-                           struct cfm *, struct lldp *, uint8_t[ETH_ADDR_LEN])
+                           struct cfm *, struct lldp *,
+                           const struct eth_addr *)
     OVS_REQUIRES(monitor_mutex);
 static void mport_unregister(const struct ofport_dpif *)
     OVS_REQUIRES(monitor_mutex);
 static void mport_update(struct mport *, struct bfd *, struct cfm *,
-                         struct lldp *, uint8_t[ETH_ADDR_LEN])
+                         struct lldp *, const struct eth_addr *)
     OVS_REQUIRES(monitor_mutex);
 static struct mport *mport_find(const struct ofport_dpif *)
     OVS_REQUIRES(monitor_mutex);
@@ -118,7 +119,8 @@ mport_find(const struct ofport_dpif *ofport) OVS_REQUIRES(monitor_mutex)
  * if it doesn't exist.  Otherwise, just updates its fields. */
 static void
 mport_register(const struct ofport_dpif *ofport, struct bfd *bfd,
-               struct cfm *cfm, struct lldp *lldp, uint8_t *hw_addr)
+               struct cfm *cfm, struct lldp *lldp,
+               const struct eth_addr *hw_addr)
     OVS_REQUIRES(monitor_mutex)
 {
     struct mport *mport = mport_find(ofport);
@@ -150,7 +152,7 @@ mport_unregister(const struct ofport_dpif *ofport)
 /* Updates the fields of an existing mport struct. */
 static void
 mport_update(struct mport *mport, struct bfd *bfd, struct cfm *cfm,
-             struct lldp *lldp, uint8_t hw_addr[ETH_ADDR_LEN])
+             struct lldp *lldp, const struct eth_addr *hw_addr)
     OVS_REQUIRES(monitor_mutex)
 {
     ovs_assert(mport);
@@ -167,8 +169,8 @@ mport_update(struct mport *mport, struct bfd *bfd, struct cfm *cfm,
         lldp_unref(mport->lldp);
         mport->lldp = lldp_ref(lldp);
     }
-    if (hw_addr && memcmp(mport->hw_addr, hw_addr, ETH_ADDR_LEN)) {
-        memcpy(mport->hw_addr, hw_addr, ETH_ADDR_LEN);
+    if (hw_addr && !eth_addr_equals(mport->hw_addr, *hw_addr)) {
+        mport->hw_addr = *hw_addr;
     }
     /* If bfd/cfm/lldp is added or reconfigured, move the mport on top of the heap
      * so that the monitor thread can run the mport next time it wakes up. */
@@ -316,7 +318,7 @@ void
 ofproto_dpif_monitor_port_update(const struct ofport_dpif *ofport,
                                  struct bfd *bfd, struct cfm *cfm,
                                  struct lldp *lldp,
-                                 uint8_t hw_addr[ETH_ADDR_LEN])
+                                 const struct eth_addr *hw_addr)
 {
     ovs_mutex_lock(&monitor_mutex);
     if (!cfm && !bfd && !lldp) {
diff --git a/ofproto/ofproto-dpif-monitor.h b/ofproto/ofproto-dpif-monitor.h
index b65d70b..7d6d0da 100644
--- a/ofproto/ofproto-dpif-monitor.h
+++ b/ofproto/ofproto-dpif-monitor.h
@@ -29,6 +29,6 @@ void ofproto_dpif_monitor_port_send_soon(const struct ofport_dpif *);
 
 void ofproto_dpif_monitor_port_update(const struct ofport_dpif *,
                                       struct bfd *, struct cfm *,
-                                      struct lldp *, uint8_t[OFP_ETH_ALEN]);
+                                      struct lldp *, const struct eth_addr *);
 
 #endif /* ofproto-dpif-monitor.h */
diff --git a/ofproto/ofproto-dpif-sflow.c b/ofproto/ofproto-dpif-sflow.c
index 264f2db..260c01b 100644
--- a/ofproto/ofproto-dpif-sflow.c
+++ b/ofproto/ofproto-dpif-sflow.c
@@ -368,12 +368,10 @@ sflow_agent_get_counters(void *ds_, SFLPoller *poller,
     if (ofproto_port_get_lacp_stats(dsp->ofport, &lacp_stats) == 0) {
 	memset(&lacp_elem, 0, sizeof lacp_elem);
 	lacp_elem.tag = SFLCOUNTERS_LACP;
-	memcpy(&lacp_elem.counterBlock.lacp.actorSystemID,
-	       lacp_stats.dot3adAggPortActorSystemID,
-	       ETH_ADDR_LEN);
-	memcpy(&lacp_elem.counterBlock.lacp.partnerSystemID,
-	       lacp_stats.dot3adAggPortPartnerOperSystemID,
-	       ETH_ADDR_LEN);
+	lacp_elem.counterBlock.lacp.actorSystemID =
+        lacp_stats.dot3adAggPortActorSystemID;
+	lacp_elem.counterBlock.lacp.partnerSystemID =
+        lacp_stats.dot3adAggPortPartnerOperSystemID;
 	lacp_elem.counterBlock.lacp.attachedAggID =
 	    lacp_stats.dot3adAggPortAttachedAggID;
 	lacp_elem.counterBlock.lacp.portState.v.actorAdmin =
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index 6b9713f..205798a 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -2707,7 +2707,8 @@ xlate_flood_packet(struct xbridge *xbridge, struct dp_packet *packet)
 }
 
 static void
-tnl_send_arp_request(const struct xport *out_dev, const uint8_t eth_src[ETH_ADDR_LEN],
+tnl_send_arp_request(const struct xport *out_dev,
+                     const struct eth_addr eth_src,
                      ovs_be32 ip_src, ovs_be32 ip_dst)
 {
     struct xbridge *xbridge = out_dev->xbridge;
@@ -2728,8 +2729,8 @@ build_tunnel_send(struct xlate_ctx *ctx, const struct xport *xport,
     struct ovs_action_push_tnl tnl_push_data;
     struct xport *out_dev = NULL;
     ovs_be32 s_ip, d_ip = 0;
-    uint8_t smac[ETH_ADDR_LEN];
-    uint8_t dmac[ETH_ADDR_LEN];
+    struct eth_addr smac;
+    struct eth_addr dmac;
     int err;
 
     err = tnl_route_lookup_flow(flow, &d_ip, &out_dev);
@@ -2741,7 +2742,7 @@ build_tunnel_send(struct xlate_ctx *ctx, const struct xport *xport,
                  IP_ARGS(d_ip), netdev_get_name(out_dev->netdev));
 
     /* Use mac addr of bridge port of the peer. */
-    err = netdev_get_etheraddr(out_dev->netdev, smac);
+    err = netdev_get_etheraddr(out_dev->netdev, &smac);
     if (err) {
         xlate_report(ctx, "tunnel output device lacks Ethernet address");
         return err;
@@ -2753,7 +2754,7 @@ build_tunnel_send(struct xlate_ctx *ctx, const struct xport *xport,
         return err;
     }
 
-    err = tnl_arp_lookup(out_dev->xbridge->name, d_ip, dmac);
+    err = tnl_arp_lookup(out_dev->xbridge->name, d_ip, &dmac);
     if (err) {
         xlate_report(ctx, "ARP cache miss for "IP_FMT" on bridge %s, "
                      "sending ARP request",
@@ -4211,13 +4212,13 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
             break;
 
         case OFPACT_SET_ETH_SRC:
-            memset(&wc->masks.dl_src, 0xff, sizeof wc->masks.dl_src);
-            memcpy(flow->dl_src, ofpact_get_SET_ETH_SRC(a)->mac, ETH_ADDR_LEN);
+            WC_MASK_FIELD(wc, dl_src);
+            flow->dl_src = ofpact_get_SET_ETH_SRC(a)->mac;
             break;
 
         case OFPACT_SET_ETH_DST:
-            memset(&wc->masks.dl_dst, 0xff, sizeof wc->masks.dl_dst);
-            memcpy(flow->dl_dst, ofpact_get_SET_ETH_DST(a)->mac, ETH_ADDR_LEN);
+            WC_MASK_FIELD(wc, dl_dst);
+            flow->dl_dst = ofpact_get_SET_ETH_DST(a)->mac;
             break;
 
         case OFPACT_SET_IPV4_SRC:
@@ -5167,7 +5168,7 @@ xlate_push_stats(struct xlate_cache *xcache,
 {
     struct xc_entry *entry;
     struct ofpbuf entries = xcache->entries;
-    uint8_t dmac[ETH_ADDR_LEN];
+    struct eth_addr dmac;
 
     if (!stats->n_packets) {
         return;
@@ -5211,7 +5212,8 @@ xlate_push_stats(struct xlate_cache *xcache,
             break;
         case XC_TNL_ARP:
             /* Lookup arp to avoid arp timeout. */
-            tnl_arp_lookup(entry->u.tnl_arp_cache.br_name, entry->u.tnl_arp_cache.d_ip, dmac);
+            tnl_arp_lookup(entry->u.tnl_arp_cache.br_name,
+                           entry->u.tnl_arp_cache.d_ip, &dmac);
             break;
         default:
             OVS_NOT_REACHED();
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 30db4fe..1279907 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -1829,7 +1829,7 @@ port_modified(struct ofport *port_)
     }
 
     ofproto_dpif_monitor_port_update(port, port->bfd, port->cfm,
-                                     port->lldp, port->up.pp.hw_addr);
+                                     port->lldp, &port->up.pp.hw_addr);
 
     dp_port_name = netdev_vport_get_dpif_port(netdev, namebuf, sizeof namebuf);
 
@@ -1965,7 +1965,7 @@ out:
         ofproto->backer->need_revalidate = REV_RECONFIGURE;
     }
     ofproto_dpif_monitor_port_update(ofport, ofport->bfd, ofport->cfm,
-                                     ofport->lldp, ofport->up.pp.hw_addr);
+                                     ofport->lldp, &ofport->up.pp.hw_addr);
     return error;
 }
 
@@ -2007,7 +2007,7 @@ set_bfd(struct ofport *ofport_, const struct smap *cfg)
         ofproto->backer->need_revalidate = REV_RECONFIGURE;
     }
     ofproto_dpif_monitor_port_update(ofport, ofport->bfd, ofport->cfm,
-                                     ofport->lldp, ofport->up.pp.hw_addr);
+                                     ofport->lldp, &ofport->up.pp.hw_addr);
     return 0;
 }
 
@@ -2063,7 +2063,7 @@ set_lldp(struct ofport *ofport_,
                                      ofport->bfd,
                                      ofport->cfm,
                                      ofport->lldp,
-                                     ofport->up.pp.hw_addr);
+                                     &ofport->up.pp.hw_addr);
     return error;
 }
 
@@ -2119,7 +2119,7 @@ rstp_send_bpdu_cb(struct dp_packet *pkt, void *ofport_, void *ofproto_)
     struct ofport_dpif *ofport = ofport_;
     struct eth_header *eth = dp_packet_l2(pkt);
 
-    netdev_get_etheraddr(ofport->up.netdev, eth->eth_src);
+    netdev_get_etheraddr(ofport->up.netdev, &eth->eth_src);
     if (eth_addr_is_zero(eth->eth_src)) {
         VLOG_WARN_RL(&rl, "%s port %d: cannot send RSTP BPDU on a port which "
                      "does not have a configured source MAC address.",
@@ -2144,7 +2144,7 @@ send_bpdu_cb(struct dp_packet *pkt, int port_num, void *ofproto_)
     } else {
         struct eth_header *eth = dp_packet_l2(pkt);
 
-        netdev_get_etheraddr(ofport->up.netdev, eth->eth_src);
+        netdev_get_etheraddr(ofport->up.netdev, &eth->eth_src);
         if (eth_addr_is_zero(eth->eth_src)) {
             VLOG_WARN_RL(&rl, "%s: cannot send BPDU on port %d "
                          "with unknown MAC", ofproto->up.name, port_num);
@@ -2978,10 +2978,10 @@ send_pdu_cb(void *port_, const void *pdu, size_t pdu_size)
 {
     static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 10);
     struct ofport_dpif *port = port_;
-    uint8_t ea[ETH_ADDR_LEN];
+    struct eth_addr ea;
     int error;
 
-    error = netdev_get_etheraddr(port->up.netdev, ea);
+    error = netdev_get_etheraddr(port->up.netdev, &ea);
     if (!error) {
         struct dp_packet packet;
         void *packet_pdu;
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index e9b1472..e6c0351 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -2317,7 +2317,7 @@ ofport_open(struct ofproto *ofproto,
         }
     }
     pp->port_no = ofproto_port->ofp_port;
-    netdev_get_etheraddr(netdev, pp->hw_addr);
+    netdev_get_etheraddr(netdev, &pp->hw_addr);
     ovs_strlcpy(pp->name, ofproto_port->name, sizeof pp->name);
     netdev_get_flags(netdev, &flags);
     pp->config = flags & NETDEV_UP ? 0 : OFPUTIL_PC_PORT_DOWN;
@@ -2424,7 +2424,7 @@ ofport_remove_with_name(struct ofproto *ofproto, const char *name)
 static void
 ofport_modified(struct ofport *port, struct ofputil_phy_port *pp)
 {
-    memcpy(port->pp.hw_addr, pp->hw_addr, ETH_ADDR_LEN);
+    port->pp.hw_addr = pp->hw_addr;
     port->pp.config = ((port->pp.config & ~OFPUTIL_PC_PORT_DOWN)
                         | (pp->config & OFPUTIL_PC_PORT_DOWN));
     port->pp.state = ((port->pp.state & ~OFPUTIL_PS_LINK_DOWN)
@@ -7277,10 +7277,10 @@ pick_datapath_id(const struct ofproto *ofproto)
 
     port = ofproto_get_port(ofproto, OFPP_LOCAL);
     if (port) {
-        uint8_t ea[ETH_ADDR_LEN];
+        struct eth_addr ea;
         int error;
 
-        error = netdev_get_etheraddr(port->netdev, ea);
+        error = netdev_get_etheraddr(port->netdev, &ea);
         if (!error) {
             return eth_addr_to_uint64(ea);
         }
@@ -7294,8 +7294,8 @@ pick_datapath_id(const struct ofproto *ofproto)
 static uint64_t
 pick_fallback_dpid(void)
 {
-    uint8_t ea[ETH_ADDR_LEN];
-    eth_addr_nicira_random(ea);
+    struct eth_addr ea;
+    eth_addr_nicira_random(&ea);
     return eth_addr_to_uint64(ea);
 }
 
diff --git a/ofproto/tunnel.c b/ofproto/tunnel.c
index a7df772..b85c2b5 100644
--- a/ofproto/tunnel.c
+++ b/ofproto/tunnel.c
@@ -669,8 +669,8 @@ tnl_port_get_name(const struct tnl_port *tnl_port) OVS_REQ_RDLOCK(rwlock)
 int
 tnl_port_build_header(const struct ofport_dpif *ofport,
                       const struct flow *tnl_flow,
-                      uint8_t dmac[ETH_ADDR_LEN],
-                      uint8_t smac[ETH_ADDR_LEN],
+                      const struct eth_addr dmac,
+                      const struct eth_addr smac,
                       ovs_be32 ip_src, struct ovs_action_push_tnl *data)
 {
     struct tnl_port *tnl_port;
@@ -687,8 +687,8 @@ tnl_port_build_header(const struct ofport_dpif *ofport,
     memset(data->header, 0, sizeof data->header);
 
     eth = (struct eth_header *)data->header;
-    memcpy(eth->eth_dst, dmac, ETH_ADDR_LEN);
-    memcpy(eth->eth_src, smac, ETH_ADDR_LEN);
+    eth->eth_dst = dmac;
+    eth->eth_src = smac;
     eth->eth_type = htons(ETH_TYPE_IP);
 
     l3 = (eth + 1);
diff --git a/ofproto/tunnel.h b/ofproto/tunnel.h
index 4a28df9..3bb76c5 100644
--- a/ofproto/tunnel.h
+++ b/ofproto/tunnel.h
@@ -52,8 +52,8 @@ tnl_port_should_receive(const struct flow *flow)
 
 int tnl_port_build_header(const struct ofport_dpif *ofport,
                           const struct flow *tnl_flow,
-                          uint8_t dmac[ETH_ADDR_LEN],
-                          uint8_t smac[ETH_ADDR_LEN],
+                          const struct eth_addr dmac,
+                          const struct eth_addr smac,
                           ovs_be32 ip_src, struct ovs_action_push_tnl *data);
 
 #endif /* tunnel.h */
diff --git a/ovn/lib/lex.c b/ovn/lib/lex.c
index fe11b72..46e86c2 100644
--- a/ovn/lib/lex.c
+++ b/ovn/lib/lex.c
@@ -295,7 +295,7 @@ lex_parse_integer__(const char *p, struct lex_token *token)
     size_t len = end - start;
 
     int n;
-    uint8_t mac[ETH_ADDR_LEN];
+    struct eth_addr mac;
 
     if (!len) {
         lex_error(token, "Integer constant expected.");
@@ -303,7 +303,7 @@ lex_parse_integer__(const char *p, struct lex_token *token)
                && ovs_scan(start, ETH_ADDR_SCAN_FMT"%n",
                            ETH_ADDR_SCAN_ARGS(mac), &n)
                && n == len) {
-        memcpy(token->value.mac, mac, sizeof token->value.mac);
+        token->value.mac = mac;
         token->format = LEX_F_ETHERNET;
     } else if (start + strspn(start, "0123456789") == end) {
         if (p[0] == '0' && len > 1) {
diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c
index 9d3d658..befe122 100644
--- a/ovn/northd/ovn-northd.c
+++ b/ovn/northd/ovn-northd.c
@@ -701,9 +701,9 @@ build_port_security(const char *eth_addr_field,
 
     size_t n = 0;
     for (size_t i = 0; i < n_port_security; i++) {
-        uint8_t ea[ETH_ADDR_LEN];
+        struct eth_addr ea;
 
-        if (eth_addr_from_string(port_security[i], ea)) {
+        if (eth_addr_from_string(port_security[i], &ea)) {
             ds_put_format(match, ETH_ADDR_FMT, ETH_ADDR_ARGS(ea));
             ds_put_char(match, ' ');
             n++;
@@ -779,9 +779,9 @@ build_lflows(struct northd_context *ctx, struct hmap *datapaths,
     /* Ingress table 1: Destination lookup, unicast handling (priority 50), */
     HMAP_FOR_EACH (op, key_node, ports) {
         for (size_t i = 0; i < op->nb->n_macs; i++) {
-            uint8_t mac[ETH_ADDR_LEN];
+            struct eth_addr mac;
 
-            if (eth_addr_from_string(op->nb->macs[i], mac)) {
+            if (eth_addr_from_string(op->nb->macs[i], &mac)) {
                 struct ds match, actions;
 
                 ds_init(&match);
diff --git a/tests/test-aa.c b/tests/test-aa.c
index 9dabce1..0b0e256 100644
--- a/tests/test-aa.c
+++ b/tests/test-aa.c
@@ -26,11 +26,11 @@
 #define ETH_TYPE_LLDP   0x88cc
 
 /* Dummy MAC addresses */
-static uint8_t chassis_mac[ETH_ADDR_LEN] = { 0x5e, 0x10, 0x8e, 0xe7, 0x84, 0xad };
-static uint8_t eth_src[ETH_ADDR_LEN] = { 0x5e, 0x10, 0x8e, 0xe7, 0x84, 0xad };
+static const struct eth_addr chassis_mac = { { { 0x5e, 0x10, 0x8e, 0xe7, 0x84, 0xad } } };
+static const struct eth_addr eth_src = { { { 0x5e, 0x10, 0x8e, 0xe7, 0x84, 0xad } } };
 
 /* LLDP multicast address */
-static const uint8_t eth_addr_lldp[6] = {0x01, 0x80, 0xC2, 0x00, 0x00, 0x0e};
+static const struct eth_addr eth_addr_lldp = { { { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x0e } } };
 
 /* Count of tests run */
 static int num_tests = 0;
@@ -84,18 +84,8 @@ check_received_aa(struct lldpd_port *sport,
 
     assert(rport->p_element.type == sport->p_element.type);
     assert(rport->p_element.mgmt_vlan == sport->p_element.mgmt_vlan);
-    assert(rport->p_element.system_id.system_mac[0] ==
-           sport->p_element.system_id.system_mac[0]);
-    assert(rport->p_element.system_id.system_mac[1] ==
-           sport->p_element.system_id.system_mac[1]);
-    assert(rport->p_element.system_id.system_mac[2] ==
-           sport->p_element.system_id.system_mac[2]);
-    assert(rport->p_element.system_id.system_mac[3] ==
-           sport->p_element.system_id.system_mac[3]);
-    assert(rport->p_element.system_id.system_mac[4] ==
-           sport->p_element.system_id.system_mac[4]);
-    assert(rport->p_element.system_id.system_mac[5] ==
-           sport->p_element.system_id.system_mac[5]);
+    assert(eth_addr_equals(rport->p_element.system_id.system_mac,
+                           sport->p_element.system_id.system_mac));
     assert(rport->p_element.system_id.conn_type ==
            sport->p_element.system_id.conn_type);
     assert(rport->p_element.system_id.rsvd ==
@@ -163,12 +153,8 @@ test_aa_send(void)
     hardware.h_lport.p_element.type =
         LLDP_TLV_AA_ELEM_TYPE_CLIENT_VIRTUAL_SWITCH;
     hardware.h_lport.p_element.mgmt_vlan = 0xCDC;
-    hardware.h_lport.p_element.system_id.system_mac[0] = 0x1;
-    hardware.h_lport.p_element.system_id.system_mac[1] = 0x2;
-    hardware.h_lport.p_element.system_id.system_mac[2] = 0x3;
-    hardware.h_lport.p_element.system_id.system_mac[3] = 0x4;
-    hardware.h_lport.p_element.system_id.system_mac[4] = 0x5;
-    hardware.h_lport.p_element.system_id.system_mac[5] = 0x6;
+    eth_addr_from_uint64(0x010203040506,
+                         &hardware.h_lport.p_element.system_id.system_mac);
 
     hardware.h_lport.p_element.system_id.conn_type = 0x5;
     hardware.h_lport.p_element.system_id.rsvd = 0x3CC;
@@ -177,7 +163,7 @@ test_aa_send(void)
 
     /* Local chassis info */
     chassis.c_id_subtype = LLDP_CHASSISID_SUBTYPE_LLADDR;
-    chassis.c_id = chassis_mac;
+    chassis.c_id = CONST_CAST(uint8_t *, chassis_mac.ea);
     chassis.c_id_len = ETH_ADDR_LEN;
     chassis.c_name = "Dummy chassis";
     chassis.c_descr = "Long dummy chassis description";
@@ -228,18 +214,8 @@ test_aa_send(void)
 
     hw->h_lport.p_element.type = hardware.h_lport.p_element.type;
     hw->h_lport.p_element.mgmt_vlan = hardware.h_lport.p_element.mgmt_vlan;
-    hw->h_lport.p_element.system_id.system_mac[0] =
-        hardware.h_lport.p_element.system_id.system_mac[0];
-    hw->h_lport.p_element.system_id.system_mac[1] =
-        hardware.h_lport.p_element.system_id.system_mac[1];
-    hw->h_lport.p_element.system_id.system_mac[2] =
-        hardware.h_lport.p_element.system_id.system_mac[2];
-    hw->h_lport.p_element.system_id.system_mac[3] =
-        hardware.h_lport.p_element.system_id.system_mac[3];
-    hw->h_lport.p_element.system_id.system_mac[4] =
-        hardware.h_lport.p_element.system_id.system_mac[4];
-    hw->h_lport.p_element.system_id.system_mac[5] =
-        hardware.h_lport.p_element.system_id.system_mac[5];
+    hw->h_lport.p_element.system_id.system_mac =
+        hardware.h_lport.p_element.system_id.system_mac;
 
     hw->h_lport.p_element.system_id.conn_type =
         hardware.h_lport.p_element.system_id.conn_type;
diff --git a/tests/test-classifier.c b/tests/test-classifier.c
index 6a59df5..bd5a267 100644
--- a/tests/test-classifier.c
+++ b/tests/test-classifier.c
@@ -315,12 +315,12 @@ static ovs_be16 dl_type_values[]
 static ovs_be16 tp_src_values[] = { CONSTANT_HTONS(49362),
                                     CONSTANT_HTONS(80) };
 static ovs_be16 tp_dst_values[] = { CONSTANT_HTONS(6667), CONSTANT_HTONS(22) };
-static uint8_t dl_src_values[][ETH_ADDR_LEN] = {
-                                      { 0x00, 0x02, 0xe3, 0x0f, 0x80, 0xa4 },
-                                      { 0x5e, 0x33, 0x7f, 0x5f, 0x1e, 0x99 } };
-static uint8_t dl_dst_values[][ETH_ADDR_LEN] = {
-                                      { 0x4a, 0x27, 0x71, 0xae, 0x64, 0xc1 },
-                                      { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };
+static struct eth_addr dl_src_values[] = {
+    { { { 0x00, 0x02, 0xe3, 0x0f, 0x80, 0xa4 } } },
+    { { { 0x5e, 0x33, 0x7f, 0x5f, 0x1e, 0x99 } } } };
+static struct eth_addr dl_dst_values[] = {
+    { { { 0x4a, 0x27, 0x71, 0xae, 0x64, 0xc1 } } },
+    { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } } } };
 static uint8_t nw_proto_values[] = { IPPROTO_TCP, IPPROTO_ICMP };
 static uint8_t nw_dscp_values[] = { 48, 0 };
 
@@ -341,11 +341,11 @@ init_values(void)
     values[CLS_F_IDX_VLAN_TCI][0] = &vlan_tci_values[0];
     values[CLS_F_IDX_VLAN_TCI][1] = &vlan_tci_values[1];
 
-    values[CLS_F_IDX_DL_SRC][0] = dl_src_values[0];
-    values[CLS_F_IDX_DL_SRC][1] = dl_src_values[1];
+    values[CLS_F_IDX_DL_SRC][0] = &dl_src_values[0];
+    values[CLS_F_IDX_DL_SRC][1] = &dl_src_values[1];
 
-    values[CLS_F_IDX_DL_DST][0] = dl_dst_values[0];
-    values[CLS_F_IDX_DL_DST][1] = dl_dst_values[1];
+    values[CLS_F_IDX_DL_DST][0] = &dl_dst_values[0];
+    values[CLS_F_IDX_DL_DST][1] = &dl_dst_values[1];
 
     values[CLS_F_IDX_DL_TYPE][0] = &dl_type_values[0];
     values[CLS_F_IDX_DL_TYPE][1] = &dl_type_values[1];
@@ -431,10 +431,8 @@ compare_classifiers(struct classifier *cls, size_t n_invisible_rules,
         flow.dl_type = dl_type_values[get_value(&x, N_DL_TYPE_VALUES)];
         flow.tp_src = tp_src_values[get_value(&x, N_TP_SRC_VALUES)];
         flow.tp_dst = tp_dst_values[get_value(&x, N_TP_DST_VALUES)];
-        memcpy(flow.dl_src, dl_src_values[get_value(&x, N_DL_SRC_VALUES)],
-               ETH_ADDR_LEN);
-        memcpy(flow.dl_dst, dl_dst_values[get_value(&x, N_DL_DST_VALUES)],
-               ETH_ADDR_LEN);
+        flow.dl_src = dl_src_values[get_value(&x, N_DL_SRC_VALUES)];
+        flow.dl_dst = dl_dst_values[get_value(&x, N_DL_DST_VALUES)];
         flow.nw_proto = nw_proto_values[get_value(&x, N_NW_PROTO_VALUES)];
         flow.nw_tos = nw_dscp_values[get_value(&x, N_NW_DSCP_VALUES)];
 
@@ -685,9 +683,9 @@ make_rule(int wc_fields, int priority, int value_pat)
         } else if (f_idx == CLS_F_IDX_TP_DST) {
             match.wc.masks.tp_dst = OVS_BE16_MAX;
         } else if (f_idx == CLS_F_IDX_DL_SRC) {
-            memset(match.wc.masks.dl_src, 0xff, ETH_ADDR_LEN);
+            WC_MASK_FIELD(&match.wc, dl_src);
         } else if (f_idx == CLS_F_IDX_DL_DST) {
-            memset(match.wc.masks.dl_dst, 0xff, ETH_ADDR_LEN);
+            WC_MASK_FIELD(&match.wc, dl_dst);
         } else if (f_idx == CLS_F_IDX_VLAN_TCI) {
             match.wc.masks.vlan_tci = OVS_BE16_MAX;
         } else if (f_idx == CLS_F_IDX_TUN_ID) {
@@ -1434,10 +1432,8 @@ benchmark(bool use_wc)
         flow->dl_type = dl_type_values[get_value(&x, N_DL_TYPE_VALUES)];
         flow->tp_src = tp_src_values[get_value(&x, N_TP_SRC_VALUES)];
         flow->tp_dst = tp_dst_values[get_value(&x, N_TP_DST_VALUES)];
-        memcpy(flow->dl_src, dl_src_values[get_value(&x, N_DL_SRC_VALUES)],
-               ETH_ADDR_LEN);
-        memcpy(flow->dl_dst, dl_dst_values[get_value(&x, N_DL_DST_VALUES)],
-               ETH_ADDR_LEN);
+        flow->dl_src = dl_src_values[get_value(&x, N_DL_SRC_VALUES)];
+        flow->dl_dst = dl_dst_values[get_value(&x, N_DL_DST_VALUES)];
         flow->nw_proto = nw_proto_values[get_value(&x, N_NW_PROTO_VALUES)];
         flow->nw_tos = nw_dscp_values[get_value(&x, N_NW_DSCP_VALUES)];
     }
diff --git a/tests/test-sflow.c b/tests/test-sflow.c
index 3f6ffb2..6f90ebf 100644
--- a/tests/test-sflow.c
+++ b/tests/test-sflow.c
@@ -241,7 +241,7 @@ process_counter_sample(struct sflow_xdr *x)
         printf("\n");
     }
     if (x->offset.LACPCOUNTERS) {
-	uint8_t *mac;
+	struct eth_addr *mac;
 	union {
 	    ovs_be32 all;
 	    struct {
@@ -254,11 +254,11 @@ process_counter_sample(struct sflow_xdr *x)
 
         sflowxdr_setc(x, x->offset.LACPCOUNTERS);
         printf("LACPCOUNTERS");
-	mac = (uint8_t *)sflowxdr_str(x);
-	printf(" sysID="ETH_ADDR_FMT, ETH_ADDR_ARGS(mac));
+	mac = (void *)sflowxdr_str(x);
+	printf(" sysID="ETH_ADDR_FMT, ETH_ADDR_ARGS(*mac));
 	sflowxdr_skip(x, 2);
-	mac = (uint8_t *)sflowxdr_str(x);
-	printf(" partnerID="ETH_ADDR_FMT, ETH_ADDR_ARGS(mac));
+	mac = (void *)sflowxdr_str(x);
+	printf(" partnerID="ETH_ADDR_FMT, ETH_ADDR_ARGS(*mac));
 	sflowxdr_skip(x, 2);
 	printf(" aggID=%"PRIu32, sflowxdr_next(x));
 	state.all = sflowxdr_next_n(x);
diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
index 6ec7151..75e84e2 100644
--- a/utilities/ovs-ofctl.c
+++ b/utilities/ovs-ofctl.c
@@ -1899,7 +1899,7 @@ ofctl_mod_port(struct ovs_cmdl_context *ctx)
     fetch_ofputil_phy_port(ctx->argv[1], ctx->argv[2], &pp);
 
     pm.port_no = pp.port_no;
-    memcpy(pm.hw_addr, pp.hw_addr, ETH_ADDR_LEN);
+    pm.hw_addr = pp.hw_addr;
     pm.config = 0;
     pm.mask = 0;
     pm.advertise = 0;
diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
index f021360..19ec857 100644
--- a/vswitchd/bridge.c
+++ b/vswitchd/bridge.c
@@ -116,8 +116,8 @@ struct bridge {
     struct hmap_node node;      /* In 'all_bridges'. */
     char *name;                 /* User-specified arbitrary name. */
     char *type;                 /* Datapath type. */
-    uint8_t ea[ETH_ADDR_LEN];   /* Bridge Ethernet Address. */
-    uint8_t default_ea[ETH_ADDR_LEN]; /* Default MAC. */
+    struct eth_addr ea;         /* Bridge Ethernet Address. */
+    struct eth_addr default_ea; /* Default MAC. */
     const struct ovsrec_bridge *cfg;
 
     /* OpenFlow switch processing. */
@@ -259,11 +259,10 @@ static bool bridge_aa_need_refresh(struct bridge *);
 static void bridge_configure_remotes(struct bridge *,
                                      const struct sockaddr_in *managers,
                                      size_t n_managers);
-static void bridge_pick_local_hw_addr(struct bridge *,
-                                      uint8_t ea[ETH_ADDR_LEN],
+static void bridge_pick_local_hw_addr(struct bridge *, struct eth_addr *ea,
                                       struct iface **hw_addr_iface);
 static uint64_t bridge_pick_datapath_id(struct bridge *,
-                                        const uint8_t bridge_ea[ETH_ADDR_LEN],
+                                        const struct eth_addr bridge_ea,
                                         struct iface *hw_addr_iface);
 static uint64_t dpid_from_hash(const void *, size_t nbytes);
 static bool bridge_has_bond_fake_iface(const struct bridge *,
@@ -1012,13 +1011,13 @@ port_configure(struct port *port)
 static void
 bridge_configure_datapath_id(struct bridge *br)
 {
-    uint8_t ea[ETH_ADDR_LEN];
+    struct eth_addr ea;
     uint64_t dpid;
     struct iface *local_iface;
     struct iface *hw_addr_iface;
     char *dpid_string;
 
-    bridge_pick_local_hw_addr(br, ea, &hw_addr_iface);
+    bridge_pick_local_hw_addr(br, &ea, &hw_addr_iface);
     local_iface = iface_from_ofp_port(br, OFPP_LOCAL);
     if (local_iface) {
         int error = netdev_set_etheraddr(local_iface->netdev, ea);
@@ -1029,7 +1028,7 @@ bridge_configure_datapath_id(struct bridge *br)
                         br->name, ovs_strerror(error));
         }
     }
-    memcpy(br->ea, ea, ETH_ADDR_LEN);
+    br->ea = ea;
 
     dpid = bridge_pick_datapath_id(br, ea, hw_addr_iface);
     if (dpid != ofproto_get_datapath_id(br->ofproto)) {
@@ -1474,9 +1473,9 @@ bridge_configure_stp(struct bridge *br, bool enable_stp)
 
         config_str = smap_get(&br->cfg->other_config, "stp-system-id");
         if (config_str) {
-            uint8_t ea[ETH_ADDR_LEN];
+            struct eth_addr ea;
 
-            if (eth_addr_from_string(config_str, ea)) {
+            if (eth_addr_from_string(config_str, &ea)) {
                 br_s.system_id = eth_addr_to_uint64(ea);
             } else {
                 br_s.system_id = eth_addr_to_uint64(br->ea);
@@ -1567,9 +1566,9 @@ bridge_configure_rstp(struct bridge *br, bool enable_rstp)
 
         config_str = smap_get(&br->cfg->other_config, "rstp-address");
         if (config_str) {
-            uint8_t ea[ETH_ADDR_LEN];
+            struct eth_addr ea;
 
-            if (eth_addr_from_string(config_str, ea)) {
+            if (eth_addr_from_string(config_str, &ea)) {
                 br_s.address = eth_addr_to_uint64(ea);
             }
             else {
@@ -1953,7 +1952,7 @@ bridge_configure_mcast_snooping(struct bridge *br)
 }
 
 static void
-find_local_hw_addr(const struct bridge *br, uint8_t ea[ETH_ADDR_LEN],
+find_local_hw_addr(const struct bridge *br, struct eth_addr *ea,
                    const struct port *fake_br, struct iface **hw_addr_iface)
 {
     struct hmapx mirror_output_ports;
@@ -1977,7 +1976,7 @@ find_local_hw_addr(const struct bridge *br, uint8_t ea[ETH_ADDR_LEN],
     /* Otherwise choose the minimum non-local MAC address among all of the
      * interfaces. */
     HMAP_FOR_EACH (port, hmap_node, &br->ports) {
-        uint8_t iface_ea[ETH_ADDR_LEN];
+        struct eth_addr iface_ea;
         struct iface *candidate;
         struct iface *iface;
 
@@ -1988,12 +1987,13 @@ find_local_hw_addr(const struct bridge *br, uint8_t ea[ETH_ADDR_LEN],
 
         /* Choose the MAC address to represent the port. */
         iface = NULL;
-        if (port->cfg->mac && eth_addr_from_string(port->cfg->mac, iface_ea)) {
+        if (port->cfg->mac && eth_addr_from_string(port->cfg->mac,
+                                                   &iface_ea)) {
             /* Find the interface with this Ethernet address (if any) so that
              * we can provide the correct devname to the caller. */
             LIST_FOR_EACH (candidate, port_elem, &port->ifaces) {
-                uint8_t candidate_ea[ETH_ADDR_LEN];
-                if (!netdev_get_etheraddr(candidate->netdev, candidate_ea)
+                struct eth_addr candidate_ea;
+                if (!netdev_get_etheraddr(candidate->netdev, &candidate_ea)
                     && eth_addr_equals(iface_ea, candidate_ea)) {
                     iface = candidate;
                 }
@@ -2028,7 +2028,7 @@ find_local_hw_addr(const struct bridge *br, uint8_t ea[ETH_ADDR_LEN],
             }
 
             /* Grab MAC. */
-            error = netdev_get_etheraddr(iface->netdev, iface_ea);
+            error = netdev_get_etheraddr(iface->netdev, &iface_ea);
             if (error) {
                 continue;
             }
@@ -2039,16 +2039,16 @@ find_local_hw_addr(const struct bridge *br, uint8_t ea[ETH_ADDR_LEN],
             !eth_addr_is_local(iface_ea) &&
             !eth_addr_is_reserved(iface_ea) &&
             !eth_addr_is_zero(iface_ea) &&
-            (!found_addr || eth_addr_compare_3way(iface_ea, ea) < 0))
+            (!found_addr || eth_addr_compare_3way(iface_ea, *ea) < 0))
         {
-            memcpy(ea, iface_ea, ETH_ADDR_LEN);
+            *ea = iface_ea;
             *hw_addr_iface = iface;
             found_addr = true;
         }
     }
 
     if (!found_addr) {
-        memcpy(ea, br->default_ea, ETH_ADDR_LEN);
+        *ea = br->default_ea;
         *hw_addr_iface = NULL;
     }
 
@@ -2056,7 +2056,7 @@ find_local_hw_addr(const struct bridge *br, uint8_t ea[ETH_ADDR_LEN],
 }
 
 static void
-bridge_pick_local_hw_addr(struct bridge *br, uint8_t ea[ETH_ADDR_LEN],
+bridge_pick_local_hw_addr(struct bridge *br, struct eth_addr *ea,
                           struct iface **hw_addr_iface)
 {
     const char *hwaddr;
@@ -2065,10 +2065,10 @@ bridge_pick_local_hw_addr(struct bridge *br, uint8_t ea[ETH_ADDR_LEN],
     /* Did the user request a particular MAC? */
     hwaddr = smap_get(&br->cfg->other_config, "hwaddr");
     if (hwaddr && eth_addr_from_string(hwaddr, ea)) {
-        if (eth_addr_is_multicast(ea)) {
+        if (eth_addr_is_multicast(*ea)) {
             VLOG_ERR("bridge %s: cannot set MAC address to multicast "
-                     "address "ETH_ADDR_FMT, br->name, ETH_ADDR_ARGS(ea));
-        } else if (eth_addr_is_zero(ea)) {
+                     "address "ETH_ADDR_FMT, br->name, ETH_ADDR_ARGS(*ea));
+        } else if (eth_addr_is_zero(*ea)) {
             VLOG_ERR("bridge %s: cannot set MAC address to zero", br->name);
         } else {
             return;
@@ -2086,7 +2086,7 @@ bridge_pick_local_hw_addr(struct bridge *br, uint8_t ea[ETH_ADDR_LEN],
  * 'hw_addr_iface' must be passed in as a null pointer. */
 static uint64_t
 bridge_pick_datapath_id(struct bridge *br,
-                        const uint8_t bridge_ea[ETH_ADDR_LEN],
+                        const struct eth_addr bridge_ea,
                         struct iface *hw_addr_iface)
 {
     /*
@@ -2139,12 +2139,14 @@ bridge_pick_datapath_id(struct bridge *br,
 static uint64_t
 dpid_from_hash(const void *data, size_t n)
 {
-    uint8_t hash[SHA1_DIGEST_SIZE];
-
-    BUILD_ASSERT_DECL(sizeof hash >= ETH_ADDR_LEN);
-    sha1_bytes(data, n, hash);
-    eth_addr_mark_random(hash);
-    return eth_addr_to_uint64(hash);
+    union {
+        uint8_t bytes[SHA1_DIGEST_SIZE];
+        struct eth_addr ea;
+    } hash;
+
+    sha1_bytes(data, n, hash.bytes);
+    eth_addr_mark_random(&hash.ea);
+    return eth_addr_to_uint64(hash.ea);
 }
 
 static void
@@ -2155,7 +2157,7 @@ iface_refresh_netdev_status(struct iface *iface)
     enum netdev_features current;
     enum netdev_flags flags;
     const char *link_state;
-    uint8_t mac[ETH_ADDR_LEN];
+    struct eth_addr mac;
     int64_t bps, mtu_64, ifindex64, link_resets;
     int mtu, error;
 
@@ -2215,7 +2217,7 @@ iface_refresh_netdev_status(struct iface *iface)
         ovsrec_interface_set_mtu(iface->cfg, NULL, 0);
     }
 
-    error = netdev_get_etheraddr(iface->netdev, mac);
+    error = netdev_get_etheraddr(iface->netdev, &mac);
     if (!error) {
         char mac_string[32];
 
@@ -2591,14 +2593,14 @@ port_refresh_rstp_status(struct port *port)
 static void
 port_refresh_bond_status(struct port *port, bool force_update)
 {
-    uint8_t mac[ETH_ADDR_LEN];
+    struct eth_addr mac;
 
     /* Return if port is not a bond */
     if (list_is_singleton(&port->ifaces)) {
         return;
     }
 
-    if (bond_get_changed_active_slave(port->name, mac, force_update)) {
+    if (bond_get_changed_active_slave(port->name, &mac, force_update)) {
         struct ds mac_s;
 
         ds_init(&mac_s);
@@ -3175,8 +3177,8 @@ bridge_create(const struct ovsrec_bridge *br_cfg)
 
     /* Derive the default Ethernet address from the bridge's UUID.  This should
      * be unique and it will be stable between ovs-vswitchd runs.  */
-    memcpy(br->default_ea, &br_cfg->header_.uuid, ETH_ADDR_LEN);
-    eth_addr_mark_random(br->default_ea);
+    memcpy(&br->default_ea, &br_cfg->header_.uuid, ETH_ADDR_LEN);
+    eth_addr_mark_random(&br->default_ea);
 
     hmap_init(&br->ports);
     hmap_init(&br->ifaces);
@@ -4086,7 +4088,7 @@ port_configure_lacp(struct port *port, struct lacp_settings *s)
             return NULL;
         }
     } else {
-        memcpy(s->id, port->bridge->ea, ETH_ADDR_LEN);
+        s->id = port->bridge->ea;
     }
 
     if (eth_addr_is_zero(s->id)) {
@@ -4205,7 +4207,7 @@ port_configure_bond(struct port *port, struct bond_settings *s)
     if (!mac_s || !ovs_scan(mac_s, ETH_ADDR_SCAN_FMT,
                             ETH_ADDR_SCAN_ARGS(s->active_slave_mac))) {
         /* OVSDB did not store the last active interface */
-        memset(s->active_slave_mac, 0, sizeof(s->active_slave_mac));
+        s->active_slave_mac = eth_addr_zero;
     }
 }
 
@@ -4336,19 +4338,19 @@ iface_from_ofp_port(const struct bridge *br, ofp_port_t ofp_port)
 static void
 iface_set_mac(const struct bridge *br, const struct port *port, struct iface *iface)
 {
-    uint8_t ea[ETH_ADDR_LEN], *mac = NULL;
+    struct eth_addr ea, *mac = NULL;
     struct iface *hw_addr_iface;
 
     if (strcmp(iface->type, "internal")) {
         return;
     }
 
-    if (iface->cfg->mac && eth_addr_from_string(iface->cfg->mac, ea)) {
-        mac = ea;
+    if (iface->cfg->mac && eth_addr_from_string(iface->cfg->mac, &ea)) {
+        mac = &ea;
     } else if (port->cfg->fake_bridge) {
         /* Fake bridge and no MAC set in the configuration. Pick a local one. */
-        find_local_hw_addr(br, ea, port, &hw_addr_iface);
-        mac = ea;
+        find_local_hw_addr(br, &ea, port, &hw_addr_iface);
+        mac = &ea;
     }
 
     if (mac) {
@@ -4356,11 +4358,11 @@ iface_set_mac(const struct bridge *br, const struct port *port, struct iface *if
             VLOG_ERR("interface %s: ignoring mac in Interface record "
                      "(use Bridge record to set local port's mac)",
                      iface->name);
-        } else if (eth_addr_is_multicast(mac)) {
+        } else if (eth_addr_is_multicast(*mac)) {
             VLOG_ERR("interface %s: cannot set MAC to multicast address",
                      iface->name);
         } else {
-            int error = netdev_set_etheraddr(iface->netdev, mac);
+            int error = netdev_set_etheraddr(iface->netdev, *mac);
             if (error) {
                 VLOG_ERR("interface %s: setting MAC failed (%s)",
                          iface->name, ovs_strerror(error));
-- 
2.1.4




More information about the dev mailing list