Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net/sched: act_vlan: Add {POP,PUSH}_ETH actions

Implement TCA_VLAN_ACT_POP_ETH and TCA_VLAN_ACT_PUSH_ETH, to
respectively pop and push a base Ethernet header at the beginning of a
frame.

POP_ETH is just a matter of pulling ETH_HLEN bytes. VLAN tags, if any,
must be stripped before calling POP_ETH.

PUSH_ETH is restricted to skbs with no mac_header, and only the MAC
addresses can be configured. The Ethertype is automatically set from
skb->protocol. These restrictions ensure that all skb's fields remain
consistent, so that this action can't confuse other part of the
networking stack (like GSO).

Since openvswitch already had these actions, consolidate the code in
skbuff.c (like for vlan and mpls push/pop).

Signed-off-by: Guillaume Nault <gnault@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Guillaume Nault and committed by
David S. Miller
19fbcb36 e275d49a

+126 -18
+3
include/linux/skbuff.h
··· 3573 3573 int __skb_vlan_pop(struct sk_buff *skb, u16 *vlan_tci); 3574 3574 int skb_vlan_pop(struct sk_buff *skb); 3575 3575 int skb_vlan_push(struct sk_buff *skb, __be16 vlan_proto, u16 vlan_tci); 3576 + int skb_eth_pop(struct sk_buff *skb); 3577 + int skb_eth_push(struct sk_buff *skb, const unsigned char *dst, 3578 + const unsigned char *src); 3576 3579 int skb_mpls_push(struct sk_buff *skb, __be32 mpls_lse, __be16 mpls_proto, 3577 3580 int mac_len, bool ethernet); 3578 3581 int skb_mpls_pop(struct sk_buff *skb, __be16 next_proto, int mac_len,
+2
include/net/tc_act/tc_vlan.h
··· 11 11 12 12 struct tcf_vlan_params { 13 13 int tcfv_action; 14 + unsigned char tcfv_push_dst[ETH_ALEN]; 15 + unsigned char tcfv_push_src[ETH_ALEN]; 14 16 u16 tcfv_push_vid; 15 17 __be16 tcfv_push_proto; 16 18 u8 tcfv_push_prio;
+4
include/uapi/linux/tc_act/tc_vlan.h
··· 16 16 #define TCA_VLAN_ACT_POP 1 17 17 #define TCA_VLAN_ACT_PUSH 2 18 18 #define TCA_VLAN_ACT_MODIFY 3 19 + #define TCA_VLAN_ACT_POP_ETH 4 20 + #define TCA_VLAN_ACT_PUSH_ETH 5 19 21 20 22 struct tc_vlan { 21 23 tc_gen; ··· 32 30 TCA_VLAN_PUSH_VLAN_PROTOCOL, 33 31 TCA_VLAN_PAD, 34 32 TCA_VLAN_PUSH_VLAN_PRIORITY, 33 + TCA_VLAN_PUSH_ETH_DST, 34 + TCA_VLAN_PUSH_ETH_SRC, 35 35 __TCA_VLAN_MAX, 36 36 }; 37 37 #define TCA_VLAN_MAX (__TCA_VLAN_MAX - 1)
+67
net/core/skbuff.c
··· 5558 5558 } 5559 5559 EXPORT_SYMBOL(skb_vlan_push); 5560 5560 5561 + /** 5562 + * skb_eth_pop() - Drop the Ethernet header at the head of a packet 5563 + * 5564 + * @skb: Socket buffer to modify 5565 + * 5566 + * Drop the Ethernet header of @skb. 5567 + * 5568 + * Expects that skb->data points to the mac header and that no VLAN tags are 5569 + * present. 5570 + * 5571 + * Returns 0 on success, -errno otherwise. 5572 + */ 5573 + int skb_eth_pop(struct sk_buff *skb) 5574 + { 5575 + if (!pskb_may_pull(skb, ETH_HLEN) || skb_vlan_tagged(skb) || 5576 + skb_network_offset(skb) < ETH_HLEN) 5577 + return -EPROTO; 5578 + 5579 + skb_pull_rcsum(skb, ETH_HLEN); 5580 + skb_reset_mac_header(skb); 5581 + skb_reset_mac_len(skb); 5582 + 5583 + return 0; 5584 + } 5585 + EXPORT_SYMBOL(skb_eth_pop); 5586 + 5587 + /** 5588 + * skb_eth_push() - Add a new Ethernet header at the head of a packet 5589 + * 5590 + * @skb: Socket buffer to modify 5591 + * @dst: Destination MAC address of the new header 5592 + * @src: Source MAC address of the new header 5593 + * 5594 + * Prepend @skb with a new Ethernet header. 5595 + * 5596 + * Expects that skb->data points to the mac header, which must be empty. 5597 + * 5598 + * Returns 0 on success, -errno otherwise. 5599 + */ 5600 + int skb_eth_push(struct sk_buff *skb, const unsigned char *dst, 5601 + const unsigned char *src) 5602 + { 5603 + struct ethhdr *eth; 5604 + int err; 5605 + 5606 + if (skb_network_offset(skb) || skb_vlan_tag_present(skb)) 5607 + return -EPROTO; 5608 + 5609 + err = skb_cow_head(skb, sizeof(*eth)); 5610 + if (err < 0) 5611 + return err; 5612 + 5613 + skb_push(skb, sizeof(*eth)); 5614 + skb_reset_mac_header(skb); 5615 + skb_reset_mac_len(skb); 5616 + 5617 + eth = eth_hdr(skb); 5618 + ether_addr_copy(eth->h_dest, dst); 5619 + ether_addr_copy(eth->h_source, src); 5620 + eth->h_proto = skb->protocol; 5621 + 5622 + skb_postpush_rcsum(skb, eth, sizeof(*eth)); 5623 + 5624 + return 0; 5625 + } 5626 + EXPORT_SYMBOL(skb_eth_push); 5627 + 5561 5628 /* Update the ethertype of hdr and the skb csum value if required. */ 5562 5629 static void skb_mod_eth_type(struct sk_buff *skb, struct ethhdr *hdr, 5563 5630 __be16 ethertype)
+10 -18
net/openvswitch/actions.c
··· 277 277 */ 278 278 static int pop_eth(struct sk_buff *skb, struct sw_flow_key *key) 279 279 { 280 - skb_pull_rcsum(skb, ETH_HLEN); 281 - skb_reset_mac_header(skb); 282 - skb_reset_mac_len(skb); 280 + int err; 281 + 282 + err = skb_eth_pop(skb); 283 + if (err) 284 + return err; 283 285 284 286 /* safe right before invalidate_flow_key */ 285 287 key->mac_proto = MAC_PROTO_NONE; ··· 292 290 static int push_eth(struct sk_buff *skb, struct sw_flow_key *key, 293 291 const struct ovs_action_push_eth *ethh) 294 292 { 295 - struct ethhdr *hdr; 293 + int err; 296 294 297 - /* Add the new Ethernet header */ 298 - if (skb_cow_head(skb, ETH_HLEN) < 0) 299 - return -ENOMEM; 300 - 301 - skb_push(skb, ETH_HLEN); 302 - skb_reset_mac_header(skb); 303 - skb_reset_mac_len(skb); 304 - 305 - hdr = eth_hdr(skb); 306 - ether_addr_copy(hdr->h_source, ethh->addresses.eth_src); 307 - ether_addr_copy(hdr->h_dest, ethh->addresses.eth_dst); 308 - hdr->h_proto = skb->protocol; 309 - 310 - skb_postpush_rcsum(skb, hdr, ETH_HLEN); 295 + err = skb_eth_push(skb, ethh->addresses.eth_dst, 296 + ethh->addresses.eth_src); 297 + if (err) 298 + return err; 311 299 312 300 /* safe right before invalidate_flow_key */ 313 301 key->mac_proto = MAC_PROTO_ETHERNET;
+40
net/sched/act_vlan.c
··· 77 77 /* put updated tci as hwaccel tag */ 78 78 __vlan_hwaccel_put_tag(skb, p->tcfv_push_proto, tci); 79 79 break; 80 + case TCA_VLAN_ACT_POP_ETH: 81 + err = skb_eth_pop(skb); 82 + if (err) 83 + goto drop; 84 + break; 85 + case TCA_VLAN_ACT_PUSH_ETH: 86 + err = skb_eth_push(skb, p->tcfv_push_dst, p->tcfv_push_src); 87 + if (err) 88 + goto drop; 89 + break; 80 90 default: 81 91 BUG(); 82 92 } ··· 103 93 } 104 94 105 95 static const struct nla_policy vlan_policy[TCA_VLAN_MAX + 1] = { 96 + [TCA_VLAN_UNSPEC] = { .strict_start_type = TCA_VLAN_PUSH_ETH_DST }, 106 97 [TCA_VLAN_PARMS] = { .len = sizeof(struct tc_vlan) }, 107 98 [TCA_VLAN_PUSH_VLAN_ID] = { .type = NLA_U16 }, 108 99 [TCA_VLAN_PUSH_VLAN_PROTOCOL] = { .type = NLA_U16 }, 109 100 [TCA_VLAN_PUSH_VLAN_PRIORITY] = { .type = NLA_U8 }, 101 + [TCA_VLAN_PUSH_ETH_DST] = NLA_POLICY_ETH_ADDR, 102 + [TCA_VLAN_PUSH_ETH_SRC] = NLA_POLICY_ETH_ADDR, 110 103 }; 111 104 112 105 static int tcf_vlan_init(struct net *net, struct nlattr *nla, ··· 192 179 if (tb[TCA_VLAN_PUSH_VLAN_PRIORITY]) 193 180 push_prio = nla_get_u8(tb[TCA_VLAN_PUSH_VLAN_PRIORITY]); 194 181 break; 182 + case TCA_VLAN_ACT_POP_ETH: 183 + break; 184 + case TCA_VLAN_ACT_PUSH_ETH: 185 + if (!tb[TCA_VLAN_PUSH_ETH_DST] || !tb[TCA_VLAN_PUSH_ETH_SRC]) { 186 + if (exists) 187 + tcf_idr_release(*a, bind); 188 + else 189 + tcf_idr_cleanup(tn, index); 190 + return -EINVAL; 191 + } 192 + break; 195 193 default: 196 194 if (exists) 197 195 tcf_idr_release(*a, bind); ··· 242 218 p->tcfv_push_vid = push_vid; 243 219 p->tcfv_push_prio = push_prio; 244 220 p->tcfv_push_proto = push_proto; 221 + 222 + if (action == TCA_VLAN_ACT_PUSH_ETH) { 223 + nla_memcpy(&p->tcfv_push_dst, tb[TCA_VLAN_PUSH_ETH_DST], 224 + ETH_ALEN); 225 + nla_memcpy(&p->tcfv_push_src, tb[TCA_VLAN_PUSH_ETH_SRC], 226 + ETH_ALEN); 227 + } 245 228 246 229 spin_lock_bh(&v->tcf_lock); 247 230 goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch); ··· 309 278 (nla_put_u8(skb, TCA_VLAN_PUSH_VLAN_PRIORITY, 310 279 p->tcfv_push_prio)))) 311 280 goto nla_put_failure; 281 + 282 + if (p->tcfv_action == TCA_VLAN_ACT_PUSH_ETH) { 283 + if (nla_put(skb, TCA_VLAN_PUSH_ETH_DST, ETH_ALEN, 284 + p->tcfv_push_dst)) 285 + goto nla_put_failure; 286 + if (nla_put(skb, TCA_VLAN_PUSH_ETH_SRC, ETH_ALEN, 287 + p->tcfv_push_src)) 288 + goto nla_put_failure; 289 + } 312 290 313 291 tcf_tm_dump(&t, &v->tcf_tm); 314 292 if (nla_put_64bit(skb, TCA_VLAN_TM, sizeof(t), &t, TCA_VLAN_PAD))