}
}
-static void
-dp_netdev_pop_vlan(struct ofpbuf *packet)
-{
- struct vlan_eth_header *veh = packet->l2;
- if (packet->size >= sizeof *veh
- && veh->veth_type == htons(ETH_TYPE_VLAN)) {
- struct eth_header tmp;
-
- memcpy(tmp.eth_dst, veh->veth_dst, ETH_ADDR_LEN);
- memcpy(tmp.eth_src, veh->veth_src, ETH_ADDR_LEN);
- tmp.eth_type = veh->veth_next_type;
-
- ofpbuf_pull(packet, VLAN_HEADER_LEN);
- packet->l2 = (char*)packet->l2 + VLAN_HEADER_LEN;
- memcpy(packet->data, &tmp, sizeof tmp);
- }
-}
-
static void
dp_netdev_set_dl(struct ofpbuf *packet, const struct ovs_key_ethernet *eth_key)
{
break;
case OVS_ACTION_ATTR_POP_VLAN:
- dp_netdev_pop_vlan(packet);
+ eth_pop_vlan(packet);
break;
case OVS_ACTION_ATTR_SET:
packet->l2 = packet->data;
}
+/* Removes outermost VLAN header (if any is present) from 'packet'.
+ *
+ * 'packet->l2' must initially point to 'packet''s Ethernet header. */
+void
+eth_pop_vlan(struct ofpbuf *packet)
+{
+ struct vlan_eth_header *veh = packet->l2;
+ if (packet->size >= sizeof *veh
+ && veh->veth_type == htons(ETH_TYPE_VLAN)) {
+ struct eth_header tmp;
+
+ memcpy(tmp.eth_dst, veh->veth_dst, ETH_ADDR_LEN);
+ memcpy(tmp.eth_src, veh->veth_src, ETH_ADDR_LEN);
+ tmp.eth_type = veh->veth_next_type;
+
+ ofpbuf_pull(packet, VLAN_HEADER_LEN);
+ packet->l2 = (char*)packet->l2 + VLAN_HEADER_LEN;
+ memcpy(packet->data, &tmp, sizeof tmp);
+ }
+}
+
/* Given the IP netmask 'netmask', returns the number of bits of the IP address
* that it specifies, that is, the number of 1-bits in 'netmask'. 'netmask'
* must be a CIDR netmask (see ip_is_cidr()). */
const uint8_t eth_src[ETH_ADDR_LEN]);
void eth_push_vlan(struct ofpbuf *, ovs_be16 tci);
+void eth_pop_vlan(struct ofpbuf *);
/* Example:
*