dpif-netdev: Properly track whether there is a vlan header.
authorBen Pfaff <blp@nicira.com>
Wed, 28 Jul 2010 00:00:54 +0000 (17:00 -0700)
committerBen Pfaff <blp@nicira.com>
Tue, 10 Aug 2010 18:44:54 +0000 (11:44 -0700)
It looks to me like the current dpif-netdev implementation doesn't handle
the case where a packet comes in without a VLAN and then is subjected to
multiple ODPAT_SET_VLAN_* operations.  dp_netdev_modify_vlan_tci() just
checks the flow key each time to see whether there's a VLAN, but it doesn't
update the flow key to note that there is now a VLAN.

One fix would be to update the flow key, but it's "const" these days.
Instead, add a check for whether the Ethernet type is ETH_TYPE_VLAN,
which should be equivalent.

lib/dpif-netdev.c

index ec971b1..c17b525 100644 (file)
@@ -1090,12 +1090,14 @@ dp_netdev_wait(void)
  * bits outside of 'mask'.
  */
 static void
-dp_netdev_modify_vlan_tci(struct ofpbuf *packet, const flow_t *key,
-                          uint16_t tci, uint16_t mask)
+dp_netdev_modify_vlan_tci(struct ofpbuf *packet, uint16_t tci, uint16_t mask)
 {
     struct vlan_eth_header *veh;
+    struct eth_header *eh;
 
-    if (key->dl_vlan != htons(ODP_VLAN_NONE)) {
+    eh = packet->l2;
+    if (packet->size >= sizeof(struct vlan_eth_header)
+        && eh->eth_type == htons(ETH_TYPE_VLAN)) {
         /* Clear 'mask' bits, but maintain other TCI bits. */
         veh = packet->l2;
         veh->veth_tci &= ~htons(mask);
@@ -1292,14 +1294,14 @@ dp_netdev_execute_actions(struct dp_netdev *dp,
                        break;
 
                case ODPAT_SET_VLAN_VID:
-                       dp_netdev_modify_vlan_tci(packet, key, ntohs(a->vlan_vid.vlan_vid),
+                       dp_netdev_modify_vlan_tci(packet, ntohs(a->vlan_vid.vlan_vid),
                                       VLAN_VID_MASK);
             break;
 
                case ODPAT_SET_VLAN_PCP:
-                       dp_netdev_modify_vlan_tci(
-                packet, key, a->vlan_pcp.vlan_pcp << VLAN_PCP_SHIFT,
-                VLAN_PCP_MASK);
+                       dp_netdev_modify_vlan_tci(packet,
+                                      a->vlan_pcp.vlan_pcp << VLAN_PCP_SHIFT,
+                                      VLAN_PCP_MASK);
             break;
 
                case ODPAT_STRIP_VLAN: