diff options
Diffstat (limited to 'vnet')
-rw-r--r-- | vnet/vnet/buffer.h | 13 | ||||
-rw-r--r-- | vnet/vnet/classify/ip_classify.c | 9 | ||||
-rw-r--r-- | vnet/vnet/dhcpv6/proxy_node.c | 6 | ||||
-rw-r--r-- | vnet/vnet/ethernet/ethernet.h | 44 | ||||
-rw-r--r-- | vnet/vnet/ethernet/node.c | 8 | ||||
-rw-r--r-- | vnet/vnet/ip/ip6_neighbor.c | 2 | ||||
-rw-r--r-- | vnet/vnet/l2/l2_input.h | 4 | ||||
-rw-r--r-- | vnet/vnet/l2/l2_vtr.h | 4 |
8 files changed, 83 insertions, 7 deletions
diff --git a/vnet/vnet/buffer.h b/vnet/vnet/buffer.h index f7fd8e8f872..7153f3541b1 100644 --- a/vnet/vnet/buffer.h +++ b/vnet/vnet/buffer.h @@ -49,6 +49,19 @@ #define IP_BUFFER_L4_CHECKSUM_COMPUTED (1 << LOG2_IP_BUFFER_L4_CHECKSUM_COMPUTED) #define IP_BUFFER_L4_CHECKSUM_CORRECT (1 << LOG2_IP_BUFFER_L4_CHECKSUM_CORRECT) +/* VLAN header flags. + * These bits are zeroed in vlib_buffer_init_for_free_list() + * meaning wherever the buffer comes from they have a reasonable + * value (eg, if ip4/ip6 generates the packet.) + */ +#define LOG2_ETH_BUFFER_VLAN_2_DEEP LOG2_VLIB_BUFFER_FLAG_USER(3) +#define LOG2_ETH_BUFFER_VLAN_1_DEEP LOG2_VLIB_BUFFER_FLAG_USER(4) +#define ETH_BUFFER_VLAN_2_DEEP (1 << LOG2_ETH_BUFFER_VLAN_2_DEEP) +#define ETH_BUFFER_VLAN_1_DEEP (1 << LOG2_ETH_BUFFER_VLAN_1_DEEP) +#define ETH_BUFFER_VLAN_BITS (ETH_BUFFER_VLAN_1_DEEP | \ + ETH_BUFFER_VLAN_2_DEEP) + + #define foreach_buffer_opaque_union_subtype \ _(ethernet) \ _(ip) \ diff --git a/vnet/vnet/classify/ip_classify.c b/vnet/vnet/classify/ip_classify.c index 55c08e0ceeb..8152f6ce353 100644 --- a/vnet/vnet/classify/ip_classify.c +++ b/vnet/vnet/classify/ip_classify.c @@ -104,11 +104,13 @@ ip_classify_inline (vlib_main_t * vm, bi0 = from[0]; b0 = vlib_get_buffer (vm, bi0); - h0 = b0->data; + h0 = (void *)vlib_buffer_get_current(b0) - + ethernet_buffer_header_size(b0); bi1 = from[1]; b1 = vlib_get_buffer (vm, bi1); - h1 = b1->data; + h1 = (void *)vlib_buffer_get_current(b1) - + ethernet_buffer_header_size(b1); adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX]; adj0 = ip_get_adjacency (lm, adj_index0); @@ -152,7 +154,8 @@ ip_classify_inline (vlib_main_t * vm, bi0 = from[0]; b0 = vlib_get_buffer (vm, bi0); - h0 = b0->data; + h0 = (void *)vlib_buffer_get_current(b0) - + ethernet_buffer_header_size(b0); adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX]; adj0 = ip_get_adjacency (lm, adj_index0); diff --git a/vnet/vnet/dhcpv6/proxy_node.c b/vnet/vnet/dhcpv6/proxy_node.c index 01f5965c1b4..4dc746f6936 100644 --- a/vnet/vnet/dhcpv6/proxy_node.c +++ b/vnet/vnet/dhcpv6/proxy_node.c @@ -201,8 +201,7 @@ dhcpv6_proxy_to_server_input (vlib_main_t * vm, b0 = vlib_get_buffer (vm, bi0); h0 = vlib_buffer_get_current (b0); - e_h0 = (ethernet_header_t *)b0->data; - clib_memcpy(client_src_mac, e_h0->src_address, 6); + /* Send to DHCPV6 server via the configured FIB */ vnet_buffer(b0)->sw_if_index[VLIB_TX] = dpm->server_fib_index; @@ -212,6 +211,9 @@ dhcpv6_proxy_to_server_input (vlib_main_t * vm, */ u0 = (void *)h0 -(sizeof(*u0)); ip0 = (void *)u0 -(sizeof(*ip0)); + e_h0 = (void *)ip0 - ethernet_buffer_header_size(b0); + + clib_memcpy(client_src_mac, e_h0->src_address, 6); switch (h0->u.msg_type) { case DHCPV6_MSG_SOLICIT: diff --git a/vnet/vnet/ethernet/ethernet.h b/vnet/vnet/ethernet/ethernet.h index 492aa759d00..6f16527c0e3 100644 --- a/vnet/vnet/ethernet/ethernet.h +++ b/vnet/vnet/ethernet/ethernet.h @@ -308,6 +308,50 @@ ethernet_buffer_get_header (vlib_buffer_t * b) + vnet_buffer (b)->ethernet.start_of_ethernet_header); } +/** Returns the number of VLAN headers in the current Ethernet frame in the + * buffer. Returns 0, 1, 2 for the known header count. The value 3 indicates + * the number of headers is not known. + */ +#define ethernet_buffer_get_vlan_count(b) ( \ + ((b)->flags & ETH_BUFFER_VLAN_BITS) >> LOG2_ETH_BUFFER_VLAN_1_DEEP \ +) + +/** Sets the number of VLAN headers in the current Ethernet frame in the + * buffer. Values 0, 1, 2 indicate the header count. The value 3 indicates + * the number of headers is not known. + */ +#define ethernet_buffer_set_vlan_count(b, v) ( \ + (b)->flags = ((b)->flags & ~ETH_BUFFER_VLAN_BITS) | \ + (((v) << LOG2_ETH_BUFFER_VLAN_1_DEEP) & ETH_BUFFER_VLAN_BITS) \ +) + +/** Adjusts the vlan count by the delta in 'v' */ +#define ethernet_buffer_adjust_vlan_count(b, v) ( \ + ethernet_buffer_set_vlan_count(b, \ + (word)ethernet_buffer_get_vlan_count(b) + (word)(v)) \ +) + +/** Adjusts the vlan count by the header size byte delta in 'v' */ +#define ethernet_buffer_adjust_vlan_count_by_bytes(b, v) ( \ + (b)->flags = ((b)->flags & ~ETH_BUFFER_VLAN_BITS) | (( \ + ((b)->flags & ETH_BUFFER_VLAN_BITS) + \ + ((v) << (LOG2_ETH_BUFFER_VLAN_1_DEEP - 2)) \ + ) & ETH_BUFFER_VLAN_BITS) \ +) + +/** + * Determine the size of the Ethernet headers of the current frame in + * the buffer. This uses the VLAN depth flags that are set by + * ethernet-input. Because these flags are stored in the vlib_buffer_t + * "flags" field this count is valid regardless of the node so long as it's + * checked downstream of ethernet-input; That is, the value is not stored in + * the opaque space. + */ +#define ethernet_buffer_header_size(b) ( \ + ethernet_buffer_get_vlan_count((b)) * sizeof(ethernet_vlan_header_t) + \ + sizeof(ethernet_header_t) \ +) + ethernet_main_t * ethernet_get_main (vlib_main_t * vm); u32 ethernet_set_flags (vnet_main_t * vnm, u32 hw_if_index, u32 flags); void ethernet_sw_interface_set_l2_mode (vnet_main_t * vnm, u32 sw_if_index, u32 l2); diff --git a/vnet/vnet/ethernet/node.c b/vnet/vnet/ethernet/node.c index 1ec49c4b805..7b9924f5cde 100644 --- a/vnet/vnet/ethernet/node.c +++ b/vnet/vnet/ethernet/node.c @@ -98,6 +98,7 @@ parse_header (ethernet_input_variant_t variant, u16 * outer_id, u16 * inner_id, u32 * match_flags) { + u8 vlan_count; if (variant == ETHERNET_INPUT_VARIANT_ETHERNET || variant == ETHERNET_INPUT_VARIANT_NOT_L2) { @@ -129,6 +130,7 @@ parse_header (ethernet_input_variant_t variant, *inner_id = 0; *match_flags = SUBINT_CONFIG_VALID | SUBINT_CONFIG_MATCH_0_TAG; + vlan_count = 0; // check for vlan encaps if ((*type == ETHERNET_TYPE_VLAN) || @@ -150,6 +152,7 @@ parse_header (ethernet_input_variant_t variant, *type = clib_net_to_host_u16(h0->type); vlib_buffer_advance (b0, sizeof (h0[0])); + vlan_count = 1; if (*type == ETHERNET_TYPE_VLAN) { // Double tagged packet @@ -164,13 +167,16 @@ parse_header (ethernet_input_variant_t variant, *type = clib_net_to_host_u16(h0->type); vlib_buffer_advance (b0, sizeof (h0[0])); + vlan_count = 2; if (*type == ETHERNET_TYPE_VLAN) { // More than double tagged packet *match_flags = SUBINT_CONFIG_VALID | SUBINT_CONFIG_MATCH_3_TAG; + vlan_count = 3; // "unknown" number, aka, 3-or-more } } } + ethernet_buffer_set_vlan_count(b0, vlan_count); } // Determine the subinterface for this packet, given the result of the @@ -230,7 +236,7 @@ determine_next_node (ethernet_main_t * em, *next0 = em->l2_next; // record the L2 len and reset the buffer so the L2 header is preserved vnet_buffer(b0)->l2.l2_len = b0->current_data; - vlib_buffer_advance (b0, -(b0->current_data)); + vlib_buffer_advance(b0, - ethernet_buffer_header_size(b0)); // check for common IP/MPLS ethertypes } else if (type0 == ETHERNET_TYPE_IP4) { diff --git a/vnet/vnet/ip/ip6_neighbor.c b/vnet/vnet/ip/ip6_neighbor.c index 329cc6d7d67..19eb5a8d54d 100644 --- a/vnet/vnet/ip/ip6_neighbor.c +++ b/vnet/vnet/ip/ip6_neighbor.c @@ -847,7 +847,7 @@ icmp6_neighbor_solicitation_or_advertisement (vlib_main_t * vm, /* Reuse current MAC header, copy SMAC to DMAC and * interface MAC to SMAC */ - vlib_buffer_reset (p0); + vlib_buffer_advance(p0, - ethernet_buffer_header_size(p0)); eth0 = vlib_buffer_get_current(p0); clib_memcpy(eth0->dst_address, eth0->src_address, 6); clib_memcpy(eth0->src_address, eth_if0->address, 6); diff --git a/vnet/vnet/l2/l2_input.h b/vnet/vnet/l2/l2_input.h index 1e5c1f0abc8..50649e79061 100644 --- a/vnet/vnet/l2/l2_input.h +++ b/vnet/vnet/l2/l2_input.h @@ -227,6 +227,7 @@ vnet_update_l2_len (vlib_buffer_t * b) { ethernet_header_t * eth; u16 ethertype; + u8 vlan_count = 0; /* point at currrent l2 hdr */ eth = vlib_buffer_get_current (b); @@ -245,12 +246,15 @@ vnet_update_l2_len (vlib_buffer_t * b) (ethertype == ETHERNET_TYPE_VLAN_9200)) { ethernet_vlan_header_t * vlan; vnet_buffer(b)->l2.l2_len += sizeof (*vlan); + vlan_count = 1; vlan = (void *) (eth+1); ethertype = clib_net_to_host_u16 (vlan->type); if (ethertype == ETHERNET_TYPE_VLAN) { vnet_buffer(b)->l2.l2_len += sizeof (*vlan); + vlan_count = 2; } } + ethernet_buffer_set_vlan_count(b, vlan_count); } /* diff --git a/vnet/vnet/l2/l2_vtr.h b/vnet/vnet/l2/l2_vtr.h index aef6c6d255e..ccd0920db52 100644 --- a/vnet/vnet/l2/l2_vtr.h +++ b/vnet/vnet/l2/l2_vtr.h @@ -96,6 +96,10 @@ l2_vtr_process (vlib_buffer_t * b0, // Update l2_len vnet_buffer(b0)->l2.l2_len += (word)config->push_bytes - (word)config->pop_bytes; + // Update vlan tag count + ethernet_buffer_adjust_vlan_count_by_bytes(b0, + (word)config->push_bytes - (word)config->pop_bytes); + // Update packet len vlib_buffer_advance(b0, (word)config->pop_bytes - (word)config->push_bytes); |