+/** IPv6 fragment extension header. */
+#define RTE_IPV6_EHDR_MF_SHIFT 0
+#define RTE_IPV6_EHDR_MF_MASK 1
+#define RTE_IPV6_EHDR_FO_SHIFT 3
+#define RTE_IPV6_EHDR_FO_MASK (~((1 << RTE_IPV6_EHDR_FO_SHIFT) - 1))
+#define RTE_IPV6_EHDR_FO_ALIGN (1 << RTE_IPV6_EHDR_FO_SHIFT)
+
+#define RTE_IPV6_FRAG_USED_MASK (RTE_IPV6_EHDR_MF_MASK | RTE_IPV6_EHDR_FO_MASK)
+
+#define RTE_IPV6_GET_MF(x) ((x) & RTE_IPV6_EHDR_MF_MASK)
+#define RTE_IPV6_GET_FO(x) ((x) >> RTE_IPV6_EHDR_FO_SHIFT)
+
+#define RTE_IPV6_SET_FRAG_DATA(fo, mf) \
+ (((fo) & RTE_IPV6_EHDR_FO_MASK) | ((mf) & RTE_IPV6_EHDR_MF_MASK))
+
+struct rte_ipv6_fragment_ext {
+ uint8_t next_header; /**< Next header type */
+ uint8_t reserved; /**< Reserved */
+ rte_be16_t frag_data; /**< All fragmentation data */
+ rte_be32_t id; /**< Packet ID */
+} __rte_packed;
+
+/* IPv6 fragment extension header size */
+#define RTE_IPV6_FRAG_HDR_SIZE sizeof(struct rte_ipv6_fragment_ext)
+
+/**
+ * Parse next IPv6 header extension
+ *
+ * This function checks if proto number is an IPv6 extensions and parses its
+ * data if so, providing information on next header and extension length.
+ *
+ * @param p
+ * Pointer to an extension raw data.
+ * @param proto
+ * Protocol number extracted from the "next header" field from
+ * the IPv6 header or the previous extension.
+ * @param ext_len
+ * Extension data length.
+ * @return
+ * next protocol number if proto is an IPv6 extension, -EINVAL otherwise
+ */
+__rte_experimental
+static inline int
+rte_ipv6_get_next_ext(const uint8_t *p, int proto, size_t *ext_len)
+{
+ int next_proto;
+
+ switch (proto) {
+ case IPPROTO_AH:
+ next_proto = *p++;
+ *ext_len = (*p + 2) * sizeof(uint32_t);
+ break;
+
+ case IPPROTO_HOPOPTS:
+ case IPPROTO_ROUTING:
+ case IPPROTO_DSTOPTS:
+ next_proto = *p++;
+ *ext_len = (*p + 1) * sizeof(uint64_t);
+ break;
+
+ case IPPROTO_FRAGMENT:
+ next_proto = *p;
+ *ext_len = RTE_IPV6_FRAG_HDR_SIZE;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return next_proto;
+}
+