aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiri Pirko <jiri@resnulli.us>2014-11-19 08:05:02 -0500
committerDavid S. Miller <davem@davemloft.net>2014-11-21 14:20:18 -0500
commit93515d53b133d66f01aec7b231fa3e40e3d2fd9a (patch)
tree6b3bc7c1e38c90eeacdbfb4ddce02d208ae66d63
parente21951212f03b8d805795d8f71206853b2ab344d (diff)
net: move vlan pop/push functions into common code
So it can be used from out of openvswitch code. Did couple of cosmetic changes on the way, namely variable naming and adding support for 8021AD proto. Signed-off-by: Jiri Pirko <jiri@resnulli.us> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/skbuff.h2
-rw-r--r--net/core/skbuff.c95
-rw-r--r--net/openvswitch/actions.c86
3 files changed, 106 insertions, 77 deletions
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index e045516891a9..78c299f40bac 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -2679,6 +2679,8 @@ unsigned int skb_gso_transport_seglen(const struct sk_buff *skb);
2679struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features); 2679struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features);
2680struct sk_buff *skb_vlan_untag(struct sk_buff *skb); 2680struct sk_buff *skb_vlan_untag(struct sk_buff *skb);
2681int skb_ensure_writable(struct sk_buff *skb, int write_len); 2681int skb_ensure_writable(struct sk_buff *skb, int write_len);
2682int skb_vlan_pop(struct sk_buff *skb);
2683int skb_vlan_push(struct sk_buff *skb, __be16 vlan_proto, u16 vlan_tci);
2682 2684
2683struct skb_checksum_ops { 2685struct skb_checksum_ops {
2684 __wsum (*update)(const void *mem, int len, __wsum wsum); 2686 __wsum (*update)(const void *mem, int len, __wsum wsum);
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index d11bbe0da355..c906c5f4bf69 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -4163,6 +4163,101 @@ int skb_ensure_writable(struct sk_buff *skb, int write_len)
4163} 4163}
4164EXPORT_SYMBOL(skb_ensure_writable); 4164EXPORT_SYMBOL(skb_ensure_writable);
4165 4165
4166/* remove VLAN header from packet and update csum accordingly. */
4167static int __skb_vlan_pop(struct sk_buff *skb, u16 *vlan_tci)
4168{
4169 struct vlan_hdr *vhdr;
4170 unsigned int offset = skb->data - skb_mac_header(skb);
4171 int err;
4172
4173 __skb_push(skb, offset);
4174 err = skb_ensure_writable(skb, VLAN_ETH_HLEN);
4175 if (unlikely(err))
4176 goto pull;
4177
4178 skb_postpull_rcsum(skb, skb->data + (2 * ETH_ALEN), VLAN_HLEN);
4179
4180 vhdr = (struct vlan_hdr *)(skb->data + ETH_HLEN);
4181 *vlan_tci = ntohs(vhdr->h_vlan_TCI);
4182
4183 memmove(skb->data + VLAN_HLEN, skb->data, 2 * ETH_ALEN);
4184 __skb_pull(skb, VLAN_HLEN);
4185
4186 vlan_set_encap_proto(skb, vhdr);
4187 skb->mac_header += VLAN_HLEN;
4188
4189 if (skb_network_offset(skb) < ETH_HLEN)
4190 skb_set_network_header(skb, ETH_HLEN);
4191
4192 skb_reset_mac_len(skb);
4193pull:
4194 __skb_pull(skb, offset);
4195
4196 return err;
4197}
4198
4199int skb_vlan_pop(struct sk_buff *skb)
4200{
4201 u16 vlan_tci;
4202 __be16 vlan_proto;
4203 int err;
4204
4205 if (likely(vlan_tx_tag_present(skb))) {
4206 skb->vlan_tci = 0;
4207 } else {
4208 if (unlikely((skb->protocol != htons(ETH_P_8021Q) &&
4209 skb->protocol != htons(ETH_P_8021AD)) ||
4210 skb->len < VLAN_ETH_HLEN))
4211 return 0;
4212
4213 err = __skb_vlan_pop(skb, &vlan_tci);
4214 if (err)
4215 return err;
4216 }
4217 /* move next vlan tag to hw accel tag */
4218 if (likely((skb->protocol != htons(ETH_P_8021Q) &&
4219 skb->protocol != htons(ETH_P_8021AD)) ||
4220 skb->len < VLAN_ETH_HLEN))
4221 return 0;
4222
4223 vlan_proto = skb->protocol;
4224 err = __skb_vlan_pop(skb, &vlan_tci);
4225 if (unlikely(err))
4226 return err;
4227
4228 __vlan_hwaccel_put_tag(skb, vlan_proto, vlan_tci);
4229 return 0;
4230}
4231EXPORT_SYMBOL(skb_vlan_pop);
4232
4233int skb_vlan_push(struct sk_buff *skb, __be16 vlan_proto, u16 vlan_tci)
4234{
4235 if (vlan_tx_tag_present(skb)) {
4236 unsigned int offset = skb->data - skb_mac_header(skb);
4237 int err;
4238
4239 /* __vlan_insert_tag expect skb->data pointing to mac header.
4240 * So change skb->data before calling it and change back to
4241 * original position later
4242 */
4243 __skb_push(skb, offset);
4244 err = __vlan_insert_tag(skb, skb->vlan_proto,
4245 vlan_tx_tag_get(skb));
4246 if (err)
4247 return err;
4248 skb->protocol = skb->vlan_proto;
4249 skb->mac_len += VLAN_HLEN;
4250 __skb_pull(skb, offset);
4251
4252 if (skb->ip_summed == CHECKSUM_COMPLETE)
4253 skb->csum = csum_add(skb->csum, csum_partial(skb->data
4254 + (2 * ETH_ALEN), VLAN_HLEN, 0));
4255 }
4256 __vlan_hwaccel_put_tag(skb, vlan_proto, vlan_tci);
4257 return 0;
4258}
4259EXPORT_SYMBOL(skb_vlan_push);
4260
4166/** 4261/**
4167 * alloc_skb_with_frags - allocate skb with page frags 4262 * alloc_skb_with_frags - allocate skb with page frags
4168 * 4263 *
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: