+/* Like struct in6_addr, but whereas that struct requires 32-bit alignment on
+ * most implementations, this one only requires 16-bit alignment. */
+union ovs_16aligned_in6_addr {
+ ovs_be16 be16[8];
+ ovs_16aligned_be32 be32[4];
+};
+
+/* Like struct in6_hdr, but whereas that struct requires 32-bit alignment, this
+ * one only requires 16-bit alignment. */
+struct ovs_16aligned_ip6_hdr {
+ union {
+ struct ovs_16aligned_ip6_hdrctl {
+ ovs_16aligned_be32 ip6_un1_flow;
+ ovs_be16 ip6_un1_plen;
+ uint8_t ip6_un1_nxt;
+ uint8_t ip6_un1_hlim;
+ } ip6_un1;
+ uint8_t ip6_un2_vfc;
+ } ip6_ctlun;
+ union ovs_16aligned_in6_addr ip6_src;
+ union ovs_16aligned_in6_addr ip6_dst;
+};
+
+/* Like struct in6_frag, but whereas that struct requires 32-bit alignment,
+ * this one only requires 16-bit alignment. */
+struct ovs_16aligned_ip6_frag {
+ uint8_t ip6f_nxt;
+ uint8_t ip6f_reserved;
+ ovs_be16 ip6f_offlg;
+ ovs_16aligned_be32 ip6f_ident;
+};
+
+#define ICMP6_HEADER_LEN 4
+struct icmp6_header {
+ uint8_t icmp6_type;
+ uint8_t icmp6_code;
+ ovs_be16 icmp6_cksum;
+};
+BUILD_ASSERT_DECL(ICMP6_HEADER_LEN == sizeof(struct icmp6_header));
+
+/* Neighbor Discovery option field.
+ * ND options are always a multiple of 8 bytes in size. */
+#define ND_OPT_LEN 8
+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 */
+};
+BUILD_ASSERT_DECL(ND_OPT_LEN == sizeof(struct ovs_nd_opt));
+
+/* Like struct nd_msg (from ndisc.h), but whereas that struct requires 32-bit
+ * alignment, this one only requires 16-bit alignment. */
+#define ND_MSG_LEN 24
+struct ovs_nd_msg {
+ struct icmp6_header icmph;
+ ovs_16aligned_be32 rco_flags;
+ union ovs_16aligned_in6_addr target;
+ struct ovs_nd_opt options[0];
+};
+BUILD_ASSERT_DECL(ND_MSG_LEN == sizeof(struct ovs_nd_msg));
+
+/*
+ * Use the same struct for MLD and MLD2, naming members as the defined fields in
+ * in the corresponding version of the protocol, though they are reserved in the
+ * other one.
+ */
+#define MLD_HEADER_LEN 8
+struct mld_header {
+ uint8_t type;
+ uint8_t code;
+ ovs_be16 csum;
+ ovs_be16 mrd;
+ ovs_be16 ngrp;
+};
+BUILD_ASSERT_DECL(MLD_HEADER_LEN == sizeof(struct mld_header));
+
+#define MLD2_RECORD_LEN 20
+struct mld2_record {
+ uint8_t type;
+ uint8_t aux_len;
+ ovs_be16 nsrcs;
+ union ovs_16aligned_in6_addr maddr;
+};
+BUILD_ASSERT_DECL(MLD2_RECORD_LEN == sizeof(struct mld2_record));
+
+#define MLD_QUERY 130
+#define MLD_REPORT 131
+#define MLD_DONE 132
+#define MLD2_REPORT 143
+
+/* The IPv6 flow label is in the lower 20 bits of the first 32-bit word. */
+#define IPV6_LABEL_MASK 0x000fffff
+