+#define ip6_frag_hdr_offset(hdr) \
+ (clib_net_to_host_u16 ((hdr)->fragment_offset_and_more) >> 3)
+
+#define ip6_frag_hdr_offset_bytes(hdr) (8 * ip6_frag_hdr_offset (hdr))
+
+#define ip6_frag_hdr_more(hdr) \
+ (clib_net_to_host_u16 ((hdr)->fragment_offset_and_more) & 0x1)
+
+#define ip6_frag_hdr_offset_and_more(offset, more) \
+ clib_host_to_net_u16 (((offset) << 3) + !!(more))
+
+#define ip6_ext_header_len(p) ((((ip6_ext_header_t *)(p))->n_data_u64s+1) << 3)
+#define ip6_ext_authhdr_len(p) ((((ip6_ext_header_t *)(p))->n_data_u64s+2) << 2)
+
+static inline int
+ip6_ext_header_len_s (ip_protocol_t nh, void *p)
+{
+ if (ip6_ext_hdr (nh))
+ return ip6_ext_header_len (p);
+ switch (nh)
+ {
+ case IP_PROTOCOL_IPSEC_AH:
+ return ip6_ext_authhdr_len (p);
+ case IP_PROTOCOL_IPV6_FRAGMENTATION:
+ return sizeof (ip6_frag_hdr_t);
+ case IP_PROTOCOL_ICMP6:
+ return 4;
+ case IP_PROTOCOL_UDP:
+ return 8;
+ case IP_PROTOCOL_TCP:
+ return 20;
+ default: /* Caller is responsible for validating the length of terminating
+ protocols */
+ ;
+ }
+ return 0;
+}
+
+always_inline void *
+ip6_ext_next_header (ip6_ext_header_t * ext_hdr)
+{
+ return (void *) ((u8 *) ext_hdr + ip6_ext_header_len (ext_hdr));
+}
+
+always_inline void *
+ip6_ext_next_header_offset (void *hdr, u16 offset)
+{
+ return (hdr + offset);
+}
+
+always_inline int
+vlib_object_within_buffer_data (vlib_main_t * vm, vlib_buffer_t * b,
+ void *obj, size_t len)
+{
+ u8 *o = obj;
+ if (o < b->data ||
+ o + len > b->data + vlib_buffer_get_default_data_size (vm))
+ return 0;
+ return 1;
+}
+
+/* Returns the number of bytes left in buffer from p. */
+static inline u32
+vlib_bytes_left_in_buffer (vlib_buffer_t *b, void *obj)
+{
+ return b->current_length - (((u8 *) obj - b->data) - b->current_data);
+}
+
+always_inline void *
+ip6_ext_next_header_s (ip_protocol_t cur_nh, void *hdr, u32 max_offset,
+ u32 *offset, int *res_nh, bool *last)
+{
+ u16 hdrlen = 0;
+ int new_nh = -1;
+ void *res = 0;
+ if (ip6_ext_hdr (cur_nh))
+ {
+ hdrlen = ip6_ext_header_len (hdr);
+ new_nh = ((ip6_ext_header_t *) hdr)->next_hdr;
+ res = hdr + hdrlen;
+ }
+ else if (cur_nh == IP_PROTOCOL_IPV6_FRAGMENTATION)
+ {
+ ip6_frag_hdr_t *frag_hdr = (ip6_frag_hdr_t *) hdr;
+ if (ip6_frag_hdr_offset (frag_hdr) > 0)
+ *last = true;
+ new_nh = frag_hdr->next_hdr;
+ hdrlen = sizeof (ip6_frag_hdr_t);
+ res = hdr + hdrlen;
+ }
+ else if (cur_nh == IP_PROTOCOL_IPSEC_AH)
+ {
+ new_nh = ((ip6_ext_header_t *) hdr)->next_hdr;
+ hdrlen = ip6_ext_authhdr_len (hdr);
+ res = hdr + hdrlen;
+ }
+ else
+ {
+ ;
+ }
+
+ if (res && (*offset + hdrlen) >= max_offset)
+ {
+ return 0;
+ }
+ *res_nh = new_nh;
+ *offset += hdrlen;
+ return res;
+}
+
+#define IP6_EXT_HDR_MAX (4) /* Maximum number of headers */
+#define IP6_EXT_HDR_MAX_DEPTH (256) /* Maximum header depth */
+typedef struct
+{
+ int length;
+ struct
+ {
+ u16 protocol;
+ u16 offset;
+ } eh[IP6_EXT_HDR_MAX];
+} ip6_ext_hdr_chain_t;