- while (n_left_from >= 4 && n_left_to_next >= 2)
- {
- vlib_buffer_t * b0, * b1;
- ip4_header_t * ip0, * ip1;
- ip4_and_gre_union_t * h0, * h1;
- u32 bi0, next0, bi1, next1;
- __attribute__((unused)) u8 error0, error1;
- u16 gre_protocol0, gre_protocol1;
-
- /* Prefetch the next iteration */
- {
- vlib_buffer_t * p2, * p3;
-
- p2 = vlib_get_buffer (vm, from[2]);
- p3 = vlib_get_buffer (vm, from[3]);
-
- vlib_prefetch_buffer_header (p2, LOAD);
- vlib_prefetch_buffer_header (p3, LOAD);
-
- /*
- * Prefetch packet data. We expect to overwrite
- * the inbound L2 header with an ip header and a
- * gre header. Might want to prefetch the last line
- * of rewrite space as well; need profile data
- */
- CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
- CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
- }
-
- /* Pick up the next two buffer indices */
- bi0 = from[0];
- bi1 = from[1];
-
- /* Speculatively enqueue them where we sent the last buffer */
- to_next[0] = bi0;
- to_next[1] = bi1;
- from += 2;
- to_next += 2;
- n_left_to_next -= 2;
- n_left_from -= 2;
-
- b0 = vlib_get_buffer (vm, bi0);
- b1 = vlib_get_buffer (vm, bi1);
-
- vnet_buffer (b0)->sw_if_index[VLIB_TX] = t->outer_fib_index;
- vnet_buffer (b1)->sw_if_index[VLIB_TX] = t->outer_fib_index;
-
- if (PREDICT_FALSE(t->teb))
- {
- gre_protocol0 = clib_net_to_host_u16(GRE_PROTOCOL_teb);
- gre_protocol1 = clib_net_to_host_u16(GRE_PROTOCOL_teb);
- }
- else
- {
- ip0 = vlib_buffer_get_current (b0);
- gre_protocol0 = clib_net_to_host_u16 (0x800);
- gre_protocol0 =
- ((ip0->ip_version_and_header_length & 0xF0) == 0x60) ?
- 0x86DD : gre_protocol0;
-
- ip1 = vlib_buffer_get_current (b1);
- gre_protocol1 = clib_net_to_host_u16 (0x800);
- gre_protocol1 =
- ((ip1->ip_version_and_header_length & 0xF0) == 0x60) ?
- 0x86DD : gre_protocol1;
- }
-
- vlib_buffer_advance (b0, -sizeof(*h0));
- vlib_buffer_advance (b1, -sizeof(*h1));
-
- h0 = vlib_buffer_get_current (b0);
- h1 = vlib_buffer_get_current (b1);
- h0->as_u64[0] = 0;
- h0->as_u64[1] = 0;
- h0->as_u64[2] = 0;
-
- h1->as_u64[0] = 0;
- h1->as_u64[1] = 0;
- h1->as_u64[2] = 0;
-
- ip0 = &h0->ip4_and_gre.ip4;
- h0->ip4_and_gre.gre.protocol = gre_protocol0;
- ip0->ip_version_and_header_length = 0x45;
- ip0->ttl = 254;
- ip0->protocol = IP_PROTOCOL_GRE;
-
- ip1 = &h1->ip4_and_gre.ip4;
- h1->ip4_and_gre.gre.protocol = gre_protocol1;
- ip1->ip_version_and_header_length = 0x45;
- ip1->ttl = 254;
- ip1->protocol = IP_PROTOCOL_GRE;
-
- ip0->length =
- clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
- ip1->length =
- clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b1));
- ip0->src_address.as_u32 = t->tunnel_src.as_u32;
- ip1->src_address.as_u32 = t->tunnel_src.as_u32;
- ip0->dst_address.as_u32 = t->tunnel_dst.as_u32;
- ip1->dst_address.as_u32 = t->tunnel_dst.as_u32;
- ip0->checksum = ip4_header_checksum (ip0);
- ip1->checksum = ip4_header_checksum (ip1);
-
- /* ip4_lookup will route to the tunnel partner */
- next0 = GRE_OUTPUT_NEXT_LOOKUP;
- next1 = GRE_OUTPUT_NEXT_LOOKUP;
- error0 = GRE_ERROR_NONE;
- error1 = GRE_ERROR_NONE;
-
- /*
- * Enqueue 2 pkts. This macro deals with next0 != next1,
- * acquiring enqueue rights to the indicated next
- * node input frame, etc.
- */
- vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
- to_next, n_left_to_next,
- bi0, bi1, next0, next1);
- }