aboutsummaryrefslogtreecommitdiffstats
path: root/net/openvswitch/actions.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/openvswitch/actions.c')
-rw-r--r--net/openvswitch/actions.c86
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. */
210static 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
238static int pop_vlan(struct sk_buff *skb, struct sw_flow_key *key) 209static 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
270static int push_vlan(struct sk_buff *skb, struct sw_flow_key *key, 221static 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
298static int set_eth_addr(struct sk_buff *skb, struct sw_flow_key *key, 232static 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: