+static void
+gre44_fixup (vlib_main_t * vm,
+ const ip_adjacency_t * adj, vlib_buffer_t * b0, const void *data)
+{
+ tunnel_encap_decap_flags_t flags;
+ ip4_and_gre_header_t *ip0;
+
+ ip0 = vlib_buffer_get_current (b0);
+ flags = pointer_to_uword (data);
+
+ /* Fixup the checksum and len fields in the GRE tunnel encap
+ * that was applied at the midchain node */
+ ip0->ip4.length =
+ clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
+ tunnel_encap_fixup_4o4 (flags, (ip4_header_t *) (ip0 + 1), &ip0->ip4);
+ ip0->ip4.checksum = ip4_header_checksum (&ip0->ip4);
+}
+
+static void
+gre64_fixup (vlib_main_t * vm,
+ const ip_adjacency_t * adj, vlib_buffer_t * b0, const void *data)
+{
+ tunnel_encap_decap_flags_t flags;
+ ip4_and_gre_header_t *ip0;
+
+ ip0 = vlib_buffer_get_current (b0);
+ flags = pointer_to_uword (data);
+
+ /* Fixup the checksum and len fields in the GRE tunnel encap
+ * that was applied at the midchain node */
+ ip0->ip4.length =
+ clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
+ tunnel_encap_fixup_6o4 (flags, (ip6_header_t *) (ip0 + 1), &ip0->ip4);
+ ip0->ip4.checksum = ip4_header_checksum (&ip0->ip4);
+}
+
+static void
+grex4_fixup (vlib_main_t * vm,
+ const ip_adjacency_t * adj, vlib_buffer_t * b0, const void *data)
+{
+ ip4_header_t *ip0;
+
+ ip0 = vlib_buffer_get_current (b0);
+
+ /* Fixup the checksum and len fields in the GRE tunnel encap
+ * that was applied at the midchain node */
+ ip0->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
+ ip0->checksum = ip4_header_checksum (ip0);
+}
+
+static void
+gre46_fixup (vlib_main_t * vm,
+ const ip_adjacency_t * adj, vlib_buffer_t * b0, const void *data)
+{
+ tunnel_encap_decap_flags_t flags;
+ ip6_and_gre_header_t *ip0;
+
+ ip0 = vlib_buffer_get_current (b0);
+ flags = pointer_to_uword (data);
+
+ /* Fixup the payload length field in the GRE tunnel encap that was applied
+ * at the midchain node */
+ ip0->ip6.payload_length =
+ clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0) -
+ sizeof (*ip0));
+ tunnel_encap_fixup_4o6 (flags, (ip4_header_t *) (ip0 + 1), &ip0->ip6);
+}
+
+static void
+gre66_fixup (vlib_main_t * vm,
+ const ip_adjacency_t * adj, vlib_buffer_t * b0, const void *data)
+{
+ tunnel_encap_decap_flags_t flags;
+ ip6_and_gre_header_t *ip0;
+
+ ip0 = vlib_buffer_get_current (b0);
+ flags = pointer_to_uword (data);
+
+ /* Fixup the payload length field in the GRE tunnel encap that was applied
+ * at the midchain node */
+ ip0->ip6.payload_length =
+ clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0) -
+ sizeof (*ip0));
+ tunnel_encap_fixup_6o6 (flags, (ip6_header_t *) (ip0 + 1), &ip0->ip6);
+}
+
+static void
+grex6_fixup (vlib_main_t * vm,
+ const ip_adjacency_t * adj, vlib_buffer_t * b0, const void *data)
+{
+ ip6_header_t *ip0;
+
+ ip0 = vlib_buffer_get_current (b0);
+
+ /* Fixup the payload length field in the GRE tunnel encap that was applied
+ * at the midchain node */
+ ip0->payload_length =
+ clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0) -
+ sizeof (*ip0));
+}
+
+/**
+ * return the appropriate fixup function given the overlay (link-type) and
+ * underlay (fproto) combination
+ */
+static adj_midchain_fixup_t
+gre_get_fixup (fib_protocol_t fproto, vnet_link_t lt)
+{
+ if (fproto == FIB_PROTOCOL_IP6 && lt == VNET_LINK_IP6)
+ return (gre66_fixup);
+ if (fproto == FIB_PROTOCOL_IP6 && lt == VNET_LINK_IP4)
+ return (gre46_fixup);
+ if (fproto == FIB_PROTOCOL_IP4 && lt == VNET_LINK_IP6)
+ return (gre64_fixup);
+ if (fproto == FIB_PROTOCOL_IP4 && lt == VNET_LINK_IP4)
+ return (gre44_fixup);
+ if (fproto == FIB_PROTOCOL_IP6 && lt == VNET_LINK_ETHERNET)
+ return (grex6_fixup);
+ if (fproto == FIB_PROTOCOL_IP4 && lt == VNET_LINK_ETHERNET)
+ return (grex4_fixup);
+
+ ASSERT (0);
+ return (gre44_fixup);
+}
+