]> git.proxmox.com Git - mirror_ovs.git/blobdiff - lib/packets.h
cirrus: Use FreeBSD 12.2.
[mirror_ovs.git] / lib / packets.h
index f583e0540ca7dc47105c8f61c47b85c32d8967f1..481bc22fa1fe8630bb51a8982fe0827c52f018fd 100644 (file)
 #include "tun-metadata.h"
 #include "unaligned.h"
 #include "util.h"
+#include "timeval.h"
 
 struct dp_packet;
+struct conn;
 struct ds;
 
 /* Purely internal to OVS userspace. These flags should never be exposed to
@@ -50,6 +52,12 @@ flow_tnl_dst_is_set(const struct flow_tnl *tnl)
     return tnl->ip_dst || ipv6_addr_is_set(&tnl->ipv6_dst);
 }
 
+static inline bool
+flow_tnl_src_is_set(const struct flow_tnl *tnl)
+{
+    return tnl->ip_src || ipv6_addr_is_set(&tnl->ipv6_src);
+}
+
 struct in6_addr flow_tnl_dst(const struct flow_tnl *tnl);
 struct in6_addr flow_tnl_src(const struct flow_tnl *tnl);
 
@@ -107,6 +115,9 @@ PADDED_MEMBERS_CACHELINE_MARKER(CACHE_LINE_SIZE, cacheline0,
     uint32_t ct_mark;           /* Connection mark. */
     ovs_u128 ct_label;          /* Connection label. */
     union flow_in_port in_port; /* Input port. */
+    struct conn *conn;          /* Cached conntrack connection. */
+    bool reply;                 /* True if reply direction. */
+    bool icmp_related;          /* True if ICMP related. */
 );
 
 PADDED_MEMBERS_CACHELINE_MARKER(CACHE_LINE_SIZE, cacheline1,
@@ -138,6 +149,12 @@ pkt_metadata_init_tnl(struct pkt_metadata *md)
     memset(md, 0, offsetof(struct pkt_metadata, tunnel.metadata.opts));
 }
 
+static inline void
+pkt_metadata_init_conn(struct pkt_metadata *md)
+{
+    md->conn = NULL;
+}
+
 static inline void
 pkt_metadata_init(struct pkt_metadata *md, odp_port_t port)
 {
@@ -156,10 +173,12 @@ pkt_metadata_init(struct pkt_metadata *md, odp_port_t port)
     md->tunnel.ip_dst = 0;
     md->tunnel.ipv6_dst = in6addr_any;
     md->in_port.odp_port = port;
+    md->conn = NULL;
 }
 
 /* This function prefetches the cachelines touched by pkt_metadata_init()
- * For performance reasons the two functions should be kept in sync. */
+ * and pkt_metadata_init_tnl().  For performance reasons the two functions
+ * should be kept in sync. */
 static inline void
 pkt_metadata_prefetch_init(struct pkt_metadata *md)
 {
@@ -167,6 +186,10 @@ pkt_metadata_prefetch_init(struct pkt_metadata *md)
      * be initialized later in pkt_metadata_init(). */
     OVS_PREFETCH(md->cacheline0);
 
+    /* Prefetch cacheline1 as members of this cacheline will be zeroed out
+     * in pkt_metadata_init_tnl(). */
+    OVS_PREFETCH(md->cacheline1);
+
     /* Prefetch cachline2 as ip_dst & ipv6_dst fields will be initialized. */
     OVS_PREFETCH(md->cacheline2);
 }
@@ -258,12 +281,7 @@ static inline bool eth_addr_equal_except(const struct eth_addr a,
              || ((a.be16[2] ^ b.be16[2]) & mask.be16[2]));
 }
 
-static inline uint64_t eth_addr_to_uint64(const struct eth_addr ea)
-{
-    return (((uint64_t) ntohs(ea.be16[0]) << 32)
-            | ((uint64_t) ntohs(ea.be16[1]) << 16)
-            | ntohs(ea.be16[2]));
-}
+uint64_t eth_addr_to_uint64(const struct eth_addr ea);
 
 static inline uint64_t eth_addr_vlan_to_uint64(const struct eth_addr ea,
                                                uint16_t vlan)
@@ -271,12 +289,7 @@ static inline uint64_t eth_addr_vlan_to_uint64(const struct eth_addr ea,
     return (((uint64_t)vlan << 48) | eth_addr_to_uint64(ea));
 }
 
-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 & 0xFFFF0000) >> 16);
-    ea->be16[2] = htons(x & 0xFFFF);
-}
+void eth_addr_from_uint64(uint64_t x, struct eth_addr *ea);
 
 static inline struct eth_addr eth_addr_invert(const struct eth_addr src)
 {
@@ -289,11 +302,7 @@ static inline struct eth_addr eth_addr_invert(const struct eth_addr src)
     return dst;
 }
 
-static inline void eth_addr_mark_random(struct eth_addr *ea)
-{
-    ea->ea[0] &= ~1;                /* Unicast. */
-    ea->ea[0] |= 2;                 /* Private. */
-}
+void eth_addr_mark_random(struct eth_addr *ea);
 
 static inline void eth_addr_random(struct eth_addr *ea)
 {
@@ -399,6 +408,8 @@ ovs_be32 set_mpls_lse_values(uint8_t ttl, uint8_t tc, uint8_t bos,
 #define ETH_TYPE_MPLS          0x8847
 #define ETH_TYPE_MPLS_MCAST    0x8848
 #define ETH_TYPE_NSH           0x894f
+#define ETH_TYPE_ERSPAN1       0x88be   /* version 1 type II */
+#define ETH_TYPE_ERSPAN2       0x22eb   /* version 2 type III */
 
 static inline bool eth_type_mpls(ovs_be16 eth_type)
 {
@@ -566,6 +577,30 @@ mpls_lse_to_ttl(ovs_be32 mpls_lse)
     return (ntohl(mpls_lse) & MPLS_TTL_MASK) >> MPLS_TTL_SHIFT;
 }
 
+/* Set label in mpls lse. */
+static inline void
+flow_set_mpls_lse_label(ovs_be32 *mpls_lse, uint32_t label)
+{
+    *mpls_lse &= ~htonl(MPLS_LABEL_MASK);
+    *mpls_lse |= htonl(label << MPLS_LABEL_SHIFT);
+}
+
+/* Set TC in mpls lse. */
+static inline void
+flow_set_mpls_lse_tc(ovs_be32 *mpls_lse, uint8_t tc)
+{
+    *mpls_lse &= ~htonl(MPLS_TC_MASK);
+    *mpls_lse |= htonl((tc & 0x7) << MPLS_TC_SHIFT);
+}
+
+/* Set BOS in mpls lse. */
+static inline void
+flow_set_mpls_lse_bos(ovs_be32 *mpls_lse, uint8_t bos)
+{
+    *mpls_lse &= ~htonl(MPLS_BOS_MASK);
+    *mpls_lse |= htonl((bos & 0x1) << MPLS_BOS_SHIFT);
+}
+
 /* Set TTL in mpls lse. */
 static inline void
 flow_set_mpls_lse_ttl(ovs_be32 *mpls_lse, uint8_t ttl)
@@ -673,6 +708,7 @@ char *ip_parse_cidr_len(const char *s, int *n, ovs_be32 *ip,
 #define IP_ECN_ECT_0 0x02
 #define IP_ECN_CE 0x03
 #define IP_ECN_MASK 0x03
+#define IP_DSCP_CS6 0xc0
 #define IP_DSCP_MASK 0xfc
 
 static inline int
@@ -736,6 +772,9 @@ struct icmp_header {
 };
 BUILD_ASSERT_DECL(ICMP_HEADER_LEN == sizeof(struct icmp_header));
 
+/* ICMPV4 */
+#define ICMP_ERROR_DATA_L4_LEN 8
+
 #define IGMP_HEADER_LEN 8
 struct igmp_header {
     uint8_t igmp_type;
@@ -755,6 +794,20 @@ struct igmpv3_header {
 };
 BUILD_ASSERT_DECL(IGMPV3_HEADER_LEN == sizeof(struct igmpv3_header));
 
+#define IGMPV3_QUERY_HEADER_LEN 12
+struct igmpv3_query_header {
+    uint8_t type;
+    uint8_t max_resp;
+    ovs_be16 csum;
+    ovs_16aligned_be32 group;
+    uint8_t srs_qrv;
+    uint8_t qqic;
+    ovs_be16 nsrcs;
+};
+BUILD_ASSERT_DECL(
+    IGMPV3_QUERY_HEADER_LEN == sizeof(struct igmpv3_query_header
+));
+
 #define IGMPV3_RECORD_LEN 8
 struct igmpv3_record {
     uint8_t type;
@@ -902,7 +955,7 @@ union ovs_16aligned_in6_addr {
     ovs_16aligned_be32 be32[4];
 };
 
-/* Like struct in6_hdr, but whereas that struct requires 32-bit alignment, this
+/* Like struct ip6_hdr, but whereas that struct requires 32-bit alignment, this
  * one only requires 16-bit alignment. */
 struct ovs_16aligned_ip6_hdr {
     union {
@@ -935,15 +988,19 @@ struct icmp6_header {
 };
 BUILD_ASSERT_DECL(ICMP6_HEADER_LEN == sizeof(struct icmp6_header));
 
-#define ICMP6_ERROR_HEADER_LEN 8
-struct icmp6_error_header {
+#define ICMP6_DATA_HEADER_LEN 8
+struct icmp6_data_header {
     struct icmp6_header icmp6_base;
-    ovs_be32 icmp6_error_ext;
+    union {
+        ovs_16aligned_be32 be32[1];
+        ovs_be16           be16[2];
+        uint8_t            u8[4];
+    } icmp6_data;
 };
-BUILD_ASSERT_DECL(ICMP6_ERROR_HEADER_LEN == sizeof(struct icmp6_error_header));
+BUILD_ASSERT_DECL(ICMP6_DATA_HEADER_LEN == sizeof(struct icmp6_data_header));
 
 uint32_t packet_csum_pseudoheader6(const struct ovs_16aligned_ip6_hdr *);
-uint16_t packet_csum_upperlayer6(const struct ovs_16aligned_ip6_hdr *,
+ovs_be16 packet_csum_upperlayer6(const struct ovs_16aligned_ip6_hdr *,
                                  const void *, uint8_t, uint16_t);
 
 /* Neighbor Discovery option field.
@@ -970,9 +1027,6 @@ struct ovs_nd_prefix_opt {
 };
 BUILD_ASSERT_DECL(ND_PREFIX_OPT_LEN == sizeof(struct ovs_nd_prefix_opt));
 
-#define ND_PREFIX_ON_LINK            0x80
-#define ND_PREFIX_AUTONOMOUS_ADDRESS 0x40
-
 /* Neighbor Discovery option: MTU. */
 #define ND_MTU_OPT_LEN 8
 #define ND_MTU_DEFAULT 0
@@ -1143,80 +1197,19 @@ in6_addr_get_mapped_ipv4(const struct in6_addr *addr)
     }
 }
 
-static inline void
-in6_addr_solicited_node(struct in6_addr *addr, const struct in6_addr *ip6)
-{
-    union ovs_16aligned_in6_addr *taddr =
-        (union ovs_16aligned_in6_addr *) addr;
-    memset(taddr->be16, 0, sizeof(taddr->be16));
-    taddr->be16[0] = htons(0xff02);
-    taddr->be16[5] = htons(0x1);
-    taddr->be16[6] = htons(0xff00);
-    memcpy(&addr->s6_addr[13], &ip6->s6_addr[13], 3);
-}
+void in6_addr_solicited_node(struct in6_addr *addr,
+                             const struct in6_addr *ip6);
 
-/*
- * Generates ipv6 EUI64 address from the given eth addr
- * and prefix and stores it in 'lla'
- */
-static inline void
-in6_generate_eui64(struct eth_addr ea, struct in6_addr *prefix,
-                   struct in6_addr *lla)
-{
-    union ovs_16aligned_in6_addr *taddr =
-        (union ovs_16aligned_in6_addr *) lla;
-    union ovs_16aligned_in6_addr *prefix_taddr =
-        (union ovs_16aligned_in6_addr *) prefix;
-    taddr->be16[0] = prefix_taddr->be16[0];
-    taddr->be16[1] = prefix_taddr->be16[1];
-    taddr->be16[2] = prefix_taddr->be16[2];
-    taddr->be16[3] = prefix_taddr->be16[3];
-    taddr->be16[4] = htons(((ea.ea[0] ^ 0x02) << 8) | ea.ea[1]);
-    taddr->be16[5] = htons(ea.ea[2] << 8 | 0x00ff);
-    taddr->be16[6] = htons(0xfe << 8 | ea.ea[3]);
-    taddr->be16[7] = ea.be16[2];
-}
+void in6_generate_eui64(struct eth_addr ea, const struct in6_addr *prefix,
+                        struct in6_addr *lla);
 
-/*
- * Generates ipv6 link local address from the given eth addr
- * with prefix 'fe80::/64' and stores it in 'lla'
- */
-static inline void
-in6_generate_lla(struct eth_addr ea, struct in6_addr *lla)
-{
-    union ovs_16aligned_in6_addr *taddr =
-        (union ovs_16aligned_in6_addr *) lla;
-    memset(taddr->be16, 0, sizeof(taddr->be16));
-    taddr->be16[0] = htons(0xfe80);
-    taddr->be16[4] = htons(((ea.ea[0] ^ 0x02) << 8) | ea.ea[1]);
-    taddr->be16[5] = htons(ea.ea[2] << 8 | 0x00ff);
-    taddr->be16[6] = htons(0xfe << 8 | ea.ea[3]);
-    taddr->be16[7] = ea.be16[2];
-}
+void in6_generate_lla(struct eth_addr ea, struct in6_addr *lla);
 
 /* Returns true if 'addr' is a link local address.  Otherwise, false. */
-static inline bool
-in6_is_lla(struct in6_addr *addr)
-{
-#ifdef s6_addr32
-    return addr->s6_addr32[0] == htonl(0xfe800000) && !(addr->s6_addr32[1]);
-#else
-    return addr->s6_addr[0] == 0xfe && addr->s6_addr[1] == 0x80 &&
-         !(addr->s6_addr[2] | addr->s6_addr[3] | addr->s6_addr[4] |
-           addr->s6_addr[5] | addr->s6_addr[6] | addr->s6_addr[7]);
-#endif
-}
+bool in6_is_lla(struct in6_addr *addr);
 
-static inline void
-ipv6_multicast_to_ethernet(struct eth_addr *eth, const struct in6_addr *ip6)
-{
-    eth->ea[0] = 0x33;
-    eth->ea[1] = 0x33;
-    eth->ea[2] = ip6->s6_addr[12];
-    eth->ea[3] = ip6->s6_addr[13];
-    eth->ea[4] = ip6->s6_addr[14];
-    eth->ea[5] = ip6->s6_addr[15];
-}
+void ipv6_multicast_to_ethernet(struct eth_addr *eth,
+                                const struct in6_addr *ip6);
 
 static inline bool dl_type_is_ip_any(ovs_be16 dl_type)
 {
@@ -1241,6 +1234,218 @@ struct gre_base_hdr {
 #define GRE_FLAGS       0x00F8
 #define GRE_VERSION     0x0007
 
+/*
+ * ERSPAN protocol header and metadata
+ *
+ * Version 1 (Type II) header (8 octets [42:49])
+ *  0                   1                   2                   3
+ *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |  Ver  |          VLAN         | COS | En|T|    Session ID     |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |      Reserved         |                  Index                |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ *
+ *  ERSPAN Version 2 (Type III) header (12 octets [42:49])
+ *  0                   1                   2                   3
+ *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |  Ver  |          VLAN         | COS |BSO|T|     Session ID    |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                          Timestamp                            |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |             SGT               |P|    FT   |   Hw ID   |D|Gra|O|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ */
+
+/* ERSPAN has fixed 8-byte GRE header */
+#define ERSPAN_GREHDR_LEN   8
+#define ERSPAN_HDR(gre_base_hdr) \
+    ((struct erspan_base_hdr *)((char *)gre_base_hdr + ERSPAN_GREHDR_LEN))
+
+#define ERSPAN_V1_MDSIZE    4
+#define ERSPAN_V2_MDSIZE    8
+
+#define ERSPAN_SID_MASK     0x03ff  /* 10-bit Session ID. */
+#define ERSPAN_IDX_MASK     0xfffff /* v1 Index */
+#define ERSPAN_HWID_MASK    0x03f0
+#define ERSPAN_DIR_MASK     0x0008
+
+struct erspan_base_hdr {
+#ifdef WORDS_BIGENDIAN
+    uint8_t ver:4,
+            vlan_upper:4;
+    uint8_t vlan:8;
+    uint8_t cos:3,
+            en:2,
+            t:1,
+            session_id_upper:2;
+    uint8_t session_id:8;
+#else
+    uint8_t vlan_upper:4,
+            ver:4;
+    uint8_t vlan:8;
+    uint8_t session_id_upper:2,
+            t:1,
+            en:2,
+            cos:3;
+    uint8_t session_id:8;
+#endif
+};
+
+struct erspan_md2 {
+    ovs_16aligned_be32 timestamp;
+    ovs_be16 sgt;
+#ifdef WORDS_BIGENDIAN
+    uint8_t p:1,
+            ft:5,
+            hwid_upper:2;
+    uint8_t hwid:4,
+            dir:1,
+            gra:2,
+            o:1;
+#else
+    uint8_t hwid_upper:2,
+            ft:5,
+            p:1;
+    uint8_t o:1,
+            gra:2,
+            dir:1,
+            hwid:4;
+#endif
+};
+
+struct erspan_metadata {
+    int version;
+    union {
+        ovs_be32 index;         /* Version 1 (type II)*/
+        struct erspan_md2 md2;  /* Version 2 (type III) */
+    } u;
+};
+
+static inline uint16_t get_sid(const struct erspan_base_hdr *ershdr)
+{
+    return (ershdr->session_id_upper << 8) + ershdr->session_id;
+}
+
+static inline void set_sid(struct erspan_base_hdr *ershdr, uint16_t id)
+{
+    ershdr->session_id = id & 0xff;
+    ershdr->session_id_upper = (id >> 8) &0x3;
+}
+
+static inline uint8_t get_hwid(const struct erspan_md2 *md2)
+{
+    return (md2->hwid_upper << 4) + md2->hwid;
+}
+
+static inline void set_hwid(struct erspan_md2 *md2, uint8_t hwid)
+{
+    md2->hwid = hwid & 0xf;
+    md2->hwid_upper = (hwid >> 4) & 0x3;
+}
+
+/* ERSPAN timestamp granularity
+ *   00b --> granularity = 100 microseconds
+ *   01b --> granularity = 100 nanoseconds
+ *   10b --> granularity = IEEE 1588
+ * Here we only support 100 microseconds.
+ */
+enum erspan_ts_gra {
+    ERSPAN_100US,
+    ERSPAN_100NS,
+    ERSPAN_IEEE1588,
+};
+
+static inline ovs_be32 get_erspan_ts(enum erspan_ts_gra gra)
+{
+    ovs_be32 ts = 0;
+
+    switch (gra) {
+    case ERSPAN_100US:
+        ts = htonl((uint32_t)(time_wall_usec() / 100));
+        break;
+    case ERSPAN_100NS:
+        /* fall back */
+    case ERSPAN_IEEE1588:
+        /* fall back */
+    default:
+        OVS_NOT_REACHED();
+        break;
+    }
+    return ts;
+}
+
+/*
+ * GTP-U protocol header and metadata
+ * See:
+ *   User Plane Protocol and Architectural Analysis on 3GPP 5G System
+ *                 draft-hmm-dmm-5g-uplane-analysis-00
+ *
+ * 0                   1                   2                   3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Ver |P|R|E|S|N| Message Type|             Length              |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                Tunnel Endpoint Identifier                     |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |      Sequence Number        |   N-PDU Number  |  Next-Ext-Hdr |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * GTP-U Flags:
+ *   P: Protocol Type (Set to '1')
+ *   R: Reserved Bit (Set to '0')
+ *   E: Extension Header Flag (Set to '1' if extension header exists)
+ *   S: Sequence Number Flag (Set to '1' if sequence number exists)
+ *   N: N-PDU Number Flag (Set to '1' if N-PDU number exists)
+ *
+ * GTP-U Message Type:
+ *   Indicates the type of GTP-U message.
+ *
+ * GTP-U Length:
+ *   Indicates the length in octets of the payload.
+ *
+ * User payload is transmitted in G-PDU packets.
+ */
+
+#define GTPU_VER_MASK   0xe0
+#define GTPU_P_MASK     0x10
+#define GTPU_E_MASK     0x04
+#define GTPU_S_MASK     0x02
+
+/* GTP-U UDP port. */
+#define GTPU_DST_PORT   2152
+
+/* Default GTP-U flags: Ver = 1 and P = 1. */
+#define GTPU_FLAGS_DEFAULT  0x30
+
+/* GTP-U message type for normal user plane PDU. */
+#define GTPU_MSGTYPE_REQ    1   /* Echo Request. */
+#define GTPU_MSGTYPE_REPL   2   /* Echo Reply. */
+#define GTPU_MSGTYPE_GPDU   255 /* User Payload. */
+
+struct gtpu_metadata {
+    uint8_t flags;
+    uint8_t msgtype;
+};
+BUILD_ASSERT_DECL(sizeof(struct gtpu_metadata) == 2);
+
+struct gtpuhdr {
+    struct gtpu_metadata md;
+    ovs_be16 len;
+    ovs_16aligned_be32 teid;
+};
+BUILD_ASSERT_DECL(sizeof(struct gtpuhdr) == 8);
+
+struct gtpuhdr_opt {
+    ovs_be16 seqno;
+    uint8_t pdu_number;
+    uint8_t next_ext_type;
+};
+BUILD_ASSERT_DECL(sizeof(struct gtpuhdr_opt) == 4);
+
 /* VXLAN protocol header */
 struct vxlanhdr {
     union {
@@ -1357,16 +1562,6 @@ 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);
 
-enum port_flags {
-    PORT_OPTIONAL,
-    PORT_REQUIRED,
-    PORT_FORBIDDEN,
-};
-
-char *ipv46_parse(const char *s, enum port_flags flags,
-                  struct sockaddr_storage *ss)
-    OVS_WARN_UNUSED_RESULT;
-
 bool ipv6_parse(const char *s, struct in6_addr *ip);
 char *ipv6_parse_masked(const char *s, struct in6_addr *ipv6,
                         struct in6_addr *mask);
@@ -1401,9 +1596,17 @@ void packet_set_sctp_port(struct dp_packet *, ovs_be16 src, ovs_be16 dst);
 void packet_set_icmp(struct dp_packet *, uint8_t type, uint8_t code);
 void packet_set_nd(struct dp_packet *, const struct in6_addr *target,
                    const struct eth_addr sll, const struct eth_addr tll);
-
+void packet_set_nd_ext(struct dp_packet *packet,
+                       const ovs_16aligned_be32 rso_flags,
+                       const uint8_t opt_type);
+void packet_set_igmp3_query(struct dp_packet *, uint8_t max_resp,
+                            ovs_be32 group, bool srs, uint8_t qrv,
+                            uint8_t qqic);
 void packet_format_tcp_flags(struct ds *, uint16_t);
 const char *packet_tcp_flag_to_string(uint32_t flag);
+void *compose_ipv6(struct dp_packet *packet, uint8_t proto,
+                   const struct in6_addr *src, const struct in6_addr *dst,
+                   uint8_t key_tc, ovs_be32 key_fl, uint8_t key_hl, int size);
 void compose_arp__(struct dp_packet *);
 void compose_arp(struct dp_packet *, uint16_t arp_op,
                  const struct eth_addr arp_sha,