Skip to content

Commit 93515d5

Browse files
jpirkodavem330
authored andcommitted
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>
1 parent e219512 commit 93515d5

File tree

3 files changed

+106
-77
lines changed

3 files changed

+106
-77
lines changed

include/linux/skbuff.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2679,6 +2679,8 @@ unsigned int skb_gso_transport_seglen(const struct sk_buff *skb);
26792679
struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features);
26802680
struct sk_buff *skb_vlan_untag(struct sk_buff *skb);
26812681
int skb_ensure_writable(struct sk_buff *skb, int write_len);
2682+
int skb_vlan_pop(struct sk_buff *skb);
2683+
int skb_vlan_push(struct sk_buff *skb, __be16 vlan_proto, u16 vlan_tci);
26822684

26832685
struct skb_checksum_ops {
26842686
__wsum (*update)(const void *mem, int len, __wsum wsum);

net/core/skbuff.c

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4163,6 +4163,101 @@ int skb_ensure_writable(struct sk_buff *skb, int write_len)
41634163
}
41644164
EXPORT_SYMBOL(skb_ensure_writable);
41654165

4166+
/* remove VLAN header from packet and update csum accordingly. */
4167+
static 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);
4193+
pull:
4194+
__skb_pull(skb, offset);
4195+
4196+
return err;
4197+
}
4198+
4199+
int 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+
}
4231+
EXPORT_SYMBOL(skb_vlan_pop);
4232+
4233+
int 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+
}
4259+
EXPORT_SYMBOL(skb_vlan_push);
4260+
41664261
/**
41674262
* alloc_skb_with_frags - allocate skb with page frags
41684263
*

net/openvswitch/actions.c

Lines changed: 9 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -206,93 +206,27 @@ static int set_mpls(struct sk_buff *skb, struct sw_flow_key *key,
206206
return 0;
207207
}
208208

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-
238209
static int pop_vlan(struct sk_buff *skb, struct sw_flow_key *key)
239210
{
240-
__be16 tci;
241211
int err;
242212

243-
if (likely(vlan_tx_tag_present(skb))) {
244-
skb->vlan_tci = 0;
245-
} else {
246-
if (unlikely(skb->protocol != htons(ETH_P_8021Q) ||
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)) {
213+
err = skb_vlan_pop(skb);
214+
if (vlan_tx_tag_present(skb))
215+
invalidate_flow_key(key);
216+
else
257217
key->eth.tci = 0;
258-
return 0;
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;
218+
return err;
268219
}
269220

270221
static int push_vlan(struct sk_buff *skb, struct sw_flow_key *key,
271222
const struct ovs_action_push_vlan *vlan)
272223
{
273-
if (unlikely(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-
224+
if (vlan_tx_tag_present(skb))
290225
invalidate_flow_key(key);
291-
} else {
226+
else
292227
key->eth.tci = vlan->vlan_tci;
293-
}
294-
__vlan_hwaccel_put_tag(skb, vlan->vlan_tpid, ntohs(vlan->vlan_tci) & ~VLAN_TAG_PRESENT);
295-
return 0;
228+
return skb_vlan_push(skb, vlan->vlan_tpid,
229+
ntohs(vlan->vlan_tci) & ~VLAN_TAG_PRESENT);
296230
}
297231

298232
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,
858792

859793
case OVS_ACTION_ATTR_PUSH_VLAN:
860794
err = push_vlan(skb, key, nla_data(a));
861-
if (unlikely(err)) /* skb already freed. */
862-
return err;
863795
break;
864796

865797
case OVS_ACTION_ATTR_POP_VLAN:

0 commit comments

Comments
 (0)