diff options
Diffstat (limited to 'net/openvswitch/actions.c')
-rw-r--r-- | net/openvswitch/actions.c | 86 |
1 files changed, 9 insertions, 77 deletions
diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index 7ffa37716265..4e05ea1c2d11 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c | |||
@@ -206,93 +206,27 @@ static int set_mpls(struct sk_buff *skb, struct sw_flow_key *key, | |||
206 | return 0; | 206 | return 0; |
207 | } | 207 | } |
208 | 208 | ||
209 | /* remove VLAN header from packet and update csum accordingly. */ | ||
210 | static int __pop_vlan_tci(struct sk_buff *skb, __be16 *current_tci) | ||
211 | { | ||
212 | struct vlan_hdr *vhdr; | ||
213 | int err; | ||
214 | |||
215 | err = skb_ensure_writable(skb, VLAN_ETH_HLEN); | ||
216 | if (unlikely(err)) | ||
217 | return err; | ||
218 | |||
219 | skb_postpull_rcsum(skb, skb->data + (2 * ETH_ALEN), VLAN_HLEN); | ||
220 | |||
221 | vhdr = (struct vlan_hdr *)(skb->data + ETH_HLEN); | ||
222 | *current_tci = vhdr->h_vlan_TCI; | ||
223 | |||
224 | memmove(skb->data + VLAN_HLEN, skb->data, 2 * ETH_ALEN); | ||
225 | __skb_pull(skb, VLAN_HLEN); | ||
226 | |||
227 | vlan_set_encap_proto(skb, vhdr); | ||
228 | skb->mac_header += VLAN_HLEN; | ||
229 | |||
230 | if (skb_network_offset(skb) < ETH_HLEN) | ||
231 | skb_set_network_header(skb, ETH_HLEN); | ||
232 | |||
233 | /* Update mac_len for subsequent MPLS actions */ | ||
234 | skb_reset_mac_len(skb); | ||
235 | return 0; | ||
236 | } | ||
237 | |||
238 | static int pop_vlan(struct sk_buff *skb, struct sw_flow_key *key) | 209 | static int pop_vlan(struct sk_buff *skb, struct sw_flow_key *key) |
239 | { | 210 | { |
240 | __be16 tci; | ||
241 | int err; | 211 | int err; |
242 | 212 | ||
243 | if (likely(vlan_tx_tag_present(skb))) { | 213 | err = skb_vlan_pop(skb); |
244 | skb->vlan_tci = 0; | 214 | if (vlan_tx_tag_present(skb)) |
245 | } else { | 215 | invalidate_flow_key(key); |
246 | if (unlikely(skb->protocol != htons(ETH_P_8021Q) || | 216 | else |
247 | skb->len < VLAN_ETH_HLEN)) | ||
248 | return 0; | ||
249 | |||
250 | err = __pop_vlan_tci(skb, &tci); | ||
251 | if (err) | ||
252 | return err; | ||
253 | } | ||
254 | /* move next vlan tag to hw accel tag */ | ||
255 | if (likely(skb->protocol != htons(ETH_P_8021Q) || | ||
256 | skb->len < VLAN_ETH_HLEN)) { | ||
257 | key->eth.tci = 0; | 217 | key->eth.tci = 0; |
258 | return 0; | 218 | return err; |
259 | } | ||
260 | |||
261 | invalidate_flow_key(key); | ||
262 | err = __pop_vlan_tci(skb, &tci); | ||
263 | if (unlikely(err)) | ||
264 | return err; | ||
265 | |||
266 | __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ntohs(tci)); | ||
267 | return 0; | ||
268 | } | 219 | } |
269 | 220 | ||
270 | static int push_vlan(struct sk_buff *skb, struct sw_flow_key *key, | 221 | static int push_vlan(struct sk_buff *skb, struct sw_flow_key *key, |
271 | const struct ovs_action_push_vlan *vlan) | 222 | const struct ovs_action_push_vlan *vlan) |
272 | { | 223 | { |
273 | if (unlikely(vlan_tx_tag_present(skb))) { | 224 | if (vlan_tx_tag_present(skb)) |
274 | u16 current_tag; | ||
275 | |||
276 | /* push down current VLAN tag */ | ||
277 | current_tag = vlan_tx_tag_get(skb); | ||
278 | |||
279 | skb = vlan_insert_tag_set_proto(skb, skb->vlan_proto, | ||
280 | current_tag); | ||
281 | if (!skb) | ||
282 | return -ENOMEM; | ||
283 | /* Update mac_len for subsequent MPLS actions */ | ||
284 | skb->mac_len += VLAN_HLEN; | ||
285 | |||
286 | if (skb->ip_summed == CHECKSUM_COMPLETE) | ||
287 | skb->csum = csum_add(skb->csum, csum_partial(skb->data | ||
288 | + (2 * ETH_ALEN), VLAN_HLEN, 0)); | ||
289 | |||
290 | invalidate_flow_key(key); | 225 | invalidate_flow_key(key); |
291 | } else { | 226 | else |
292 | key->eth.tci = vlan->vlan_tci; | 227 | key->eth.tci = vlan->vlan_tci; |
293 | } | 228 | return skb_vlan_push(skb, vlan->vlan_tpid, |
294 | __vlan_hwaccel_put_tag(skb, vlan->vlan_tpid, ntohs(vlan->vlan_tci) & ~VLAN_TAG_PRESENT); | 229 | ntohs(vlan->vlan_tci) & ~VLAN_TAG_PRESENT); |
295 | return 0; | ||
296 | } | 230 | } |
297 | 231 | ||
298 | static int set_eth_addr(struct sk_buff *skb, struct sw_flow_key *key, | 232 | static int set_eth_addr(struct sk_buff *skb, struct sw_flow_key *key, |
@@ -858,8 +792,6 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, | |||
858 | 792 | ||
859 | case OVS_ACTION_ATTR_PUSH_VLAN: | 793 | case OVS_ACTION_ATTR_PUSH_VLAN: |
860 | err = push_vlan(skb, key, nla_data(a)); | 794 | err = push_vlan(skb, key, nla_data(a)); |
861 | if (unlikely(err)) /* skb already freed. */ | ||
862 | return err; | ||
863 | break; | 795 | break; |
864 | 796 | ||
865 | case OVS_ACTION_ATTR_POP_VLAN: | 797 | case OVS_ACTION_ATTR_POP_VLAN: |