aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--vlib/vlib/buffer.h3
-rw-r--r--vnet/vnet/buffer.h13
-rw-r--r--vnet/vnet/classify/ip_classify.c9
-rw-r--r--vnet/vnet/dhcpv6/proxy_node.c6
-rw-r--r--vnet/vnet/ethernet/ethernet.h44
-rw-r--r--vnet/vnet/ethernet/node.c8
-rw-r--r--vnet/vnet/ip/ip6_neighbor.c2
-rw-r--r--vnet/vnet/l2/l2_input.h4
-rw-r--r--vnet/vnet/l2/l2_vtr.h4
9 files changed, 84 insertions, 9 deletions
diff --git a/vlib/vlib/buffer.h b/vlib/vlib/buffer.h
index 07ed85d8c31..e11085b72a0 100644
--- a/vlib/vlib/buffer.h
+++ b/vlib/vlib/buffer.h
@@ -93,8 +93,7 @@ typedef struct {
#define VLIB_BUFFER_NEXT_PRESENT (1 << VLIB_BUFFER_LOG2_NEXT_PRESENT)
#define VLIB_BUFFER_IS_RECYCLED (1 << 2)
#define VLIB_BUFFER_TOTAL_LENGTH_VALID (1 << 3)
-#define VLIB_BUFFER_HGSHM_USER_INDEX_VALID (1 << 4)
-#define VLIB_BUFFER_REPL_FAIL (1 << 5)
+#define VLIB_BUFFER_REPL_FAIL (1 << 4)
/* User defined buffer flags. */
#define LOG2_VLIB_BUFFER_FLAG_USER(n) (32 - (n))
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);