From 58dc4ead3b2640e155161574e16c2198adb31991 Mon Sep 17 00:00:00 2001 From: Justin Pettit Date: Wed, 25 Jun 2008 23:22:39 -0700 Subject: [PATCH] Fix VLAN modification action in kernel switch. A number of errors were uncovered when we actually tried playing with VLAN tags on real traffic. This fixes endian, sk_buff, and other issues. Unrelated to VLAN tagging, this also protects some printk calls with net_ratelimit. --- datapath/datapath.c | 5 +---- datapath/forward.c | 22 +++++++++++++++++----- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/datapath/datapath.c b/datapath/datapath.c index 00dbac7c..84036448 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -443,10 +443,7 @@ static void do_port_input(struct net_bridge_port *p, struct sk_buff *skb) { /* Push the Ethernet header back on. */ - if (skb->protocol == htons(ETH_P_8021Q)) - skb_push(skb, VLAN_ETH_HLEN); - else - skb_push(skb, ETH_HLEN); + skb_push(skb, ETH_HLEN); fwd_port_input(p->dp->chain, skb, p->port_no); } diff --git a/datapath/forward.c b/datapath/forward.c index 44967203..e0b07011 100644 --- a/datapath/forward.c +++ b/datapath/forward.c @@ -87,10 +87,16 @@ void execute_actions(struct datapath *dp, struct sk_buff *skb, max_len = ntohs(a->arg.output.max_len); } else { if (!make_writable(&skb)) { - printk("make_writable failed\n"); + if (net_ratelimit()) + printk("make_writable failed\n"); break; } skb = execute_setter(skb, eth_proto, key, a); + if (!skb) { + if (net_ratelimit()) + printk("execute_setter lost skb\n"); + return; + } } } if (prev_port != -1) @@ -199,17 +205,23 @@ static struct sk_buff *vlan_pull_tag(struct sk_buff *skb) static struct sk_buff *modify_vlan(struct sk_buff *skb, const struct sw_flow_key *key, const struct ofp_action *a) { - uint16_t new_id = a->arg.vlan_id; + uint16_t new_id = ntohs(a->arg.vlan_id); if (new_id != OFP_VLAN_NONE) { if (key->dl_vlan != htons(OFP_VLAN_NONE)) { /* Modify vlan id, but maintain other TCI values */ struct vlan_ethhdr *vh = vlan_eth_hdr(skb); vh->h_vlan_TCI = (vh->h_vlan_TCI - & ~(htons(VLAN_VID_MASK))) | htons(new_id); + & ~(htons(VLAN_VID_MASK))) | a->arg.vlan_id; } else { /* Add vlan header */ - skb = vlan_put_tag(skb, new_id); + + /* xxx The vlan_put_tag function, doesn't seem to work + * xxx reliably when it attempts to use the hardware-accelerated + * xxx version. We'll directly use the software version + * xxx until the problem can be diagnosed. + */ + skb = __vlan_put_tag(skb, new_id); } } else { /* Remove an existing vlan header if it exists */ @@ -603,7 +615,7 @@ make_writable(struct sk_buff **pskb) if (skb_shared(*pskb) || skb_cloned(*pskb)) goto copy_skb; - return pskb_may_pull(*pskb, 64); /* FIXME? */ + return pskb_may_pull(*pskb, 40); /* FIXME? */ copy_skb: nskb = skb_copy(*pskb, GFP_ATOMIC); -- 2.30.2