Skip to content

Commit a815bde

Browse files
joamakiborkmann
authored andcommitted
net, bonding: Refactor bond_xmit_hash for use with xdp_buff
In preparation for adding XDP support to the bonding driver refactor the packet hashing functions to be able to work with any linear data buffer without an skb. Signed-off-by: Jussi Maki <[email protected]> Signed-off-by: Daniel Borkmann <[email protected]> Cc: Jay Vosburgh <[email protected]> Cc: Veaceslav Falico <[email protected]> Cc: Andy Gospodarek <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent c83ae15 commit a815bde

File tree

1 file changed

+90
-57
lines changed

1 file changed

+90
-57
lines changed

drivers/net/bonding/bond_main.c

Lines changed: 90 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -3614,55 +3614,80 @@ static struct notifier_block bond_netdev_notifier = {
36143614

36153615
/*---------------------------- Hashing Policies -----------------------------*/
36163616

3617+
/* Helper to access data in a packet, with or without a backing skb.
3618+
* If skb is given the data is linearized if necessary via pskb_may_pull.
3619+
*/
3620+
static inline const void *bond_pull_data(struct sk_buff *skb,
3621+
const void *data, int hlen, int n)
3622+
{
3623+
if (likely(n <= hlen))
3624+
return data;
3625+
else if (skb && likely(pskb_may_pull(skb, n)))
3626+
return skb->head;
3627+
3628+
return NULL;
3629+
}
3630+
36173631
/* L2 hash helper */
3618-
static inline u32 bond_eth_hash(struct sk_buff *skb)
3632+
static inline u32 bond_eth_hash(struct sk_buff *skb, const void *data, int mhoff, int hlen)
36193633
{
3620-
struct ethhdr *ep, hdr_tmp;
3634+
struct ethhdr *ep;
36213635

3622-
ep = skb_header_pointer(skb, 0, sizeof(hdr_tmp), &hdr_tmp);
3623-
if (ep)
3624-
return ep->h_dest[5] ^ ep->h_source[5] ^ ep->h_proto;
3625-
return 0;
3636+
data = bond_pull_data(skb, data, hlen, mhoff + sizeof(struct ethhdr));
3637+
if (!data)
3638+
return 0;
3639+
3640+
ep = (struct ethhdr *)(data + mhoff);
3641+
return ep->h_dest[5] ^ ep->h_source[5] ^ ep->h_proto;
36263642
}
36273643

3628-
static bool bond_flow_ip(struct sk_buff *skb, struct flow_keys *fk,
3629-
int *noff, int *proto, bool l34)
3644+
static bool bond_flow_ip(struct sk_buff *skb, struct flow_keys *fk, const void *data,
3645+
int hlen, __be16 l2_proto, int *nhoff, int *ip_proto, bool l34)
36303646
{
36313647
const struct ipv6hdr *iph6;
36323648
const struct iphdr *iph;
36333649

3634-
if (skb->protocol == htons(ETH_P_IP)) {
3635-
if (unlikely(!pskb_may_pull(skb, *noff + sizeof(*iph))))
3650+
if (l2_proto == htons(ETH_P_IP)) {
3651+
data = bond_pull_data(skb, data, hlen, *nhoff + sizeof(*iph));
3652+
if (!data)
36363653
return false;
3637-
iph = (const struct iphdr *)(skb->data + *noff);
3654+
3655+
iph = (const struct iphdr *)(data + *nhoff);
36383656
iph_to_flow_copy_v4addrs(fk, iph);
3639-
*noff += iph->ihl << 2;
3657+
*nhoff += iph->ihl << 2;
36403658
if (!ip_is_fragment(iph))
3641-
*proto = iph->protocol;
3642-
} else if (skb->protocol == htons(ETH_P_IPV6)) {
3643-
if (unlikely(!pskb_may_pull(skb, *noff + sizeof(*iph6))))
3659+
*ip_proto = iph->protocol;
3660+
} else if (l2_proto == htons(ETH_P_IPV6)) {
3661+
data = bond_pull_data(skb, data, hlen, *nhoff + sizeof(*iph6));
3662+
if (!data)
36443663
return false;
3645-
iph6 = (const struct ipv6hdr *)(skb->data + *noff);
3664+
3665+
iph6 = (const struct ipv6hdr *)(data + *nhoff);
36463666
iph_to_flow_copy_v6addrs(fk, iph6);
3647-
*noff += sizeof(*iph6);
3648-
*proto = iph6->nexthdr;
3667+
*nhoff += sizeof(*iph6);
3668+
*ip_proto = iph6->nexthdr;
36493669
} else {
36503670
return false;
36513671
}
36523672

3653-
if (l34 && *proto >= 0)
3654-
fk->ports.ports = skb_flow_get_ports(skb, *noff, *proto);
3673+
if (l34 && *ip_proto >= 0)
3674+
fk->ports.ports = __skb_flow_get_ports(skb, *nhoff, *ip_proto, data, hlen);
36553675

36563676
return true;
36573677
}
36583678

3659-
static u32 bond_vlan_srcmac_hash(struct sk_buff *skb)
3679+
static u32 bond_vlan_srcmac_hash(struct sk_buff *skb, const void *data, int mhoff, int hlen)
36603680
{
3661-
struct ethhdr *mac_hdr = (struct ethhdr *)skb_mac_header(skb);
3681+
struct ethhdr *mac_hdr;
36623682
u32 srcmac_vendor = 0, srcmac_dev = 0;
36633683
u16 vlan;
36643684
int i;
36653685

3686+
data = bond_pull_data(skb, data, hlen, mhoff + sizeof(struct ethhdr));
3687+
if (!data)
3688+
return 0;
3689+
mac_hdr = (struct ethhdr *)(data + mhoff);
3690+
36663691
for (i = 0; i < 3; i++)
36673692
srcmac_vendor = (srcmac_vendor << 8) | mac_hdr->h_source[i];
36683693

@@ -3678,49 +3703,46 @@ static u32 bond_vlan_srcmac_hash(struct sk_buff *skb)
36783703
}
36793704

36803705
/* Extract the appropriate headers based on bond's xmit policy */
3681-
static bool bond_flow_dissect(struct bonding *bond, struct sk_buff *skb,
3682-
struct flow_keys *fk)
3706+
static bool bond_flow_dissect(struct bonding *bond, struct sk_buff *skb, const void *data,
3707+
__be16 l2_proto, int nhoff, int hlen, struct flow_keys *fk)
36833708
{
36843709
bool l34 = bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER34;
3685-
int noff, proto = -1;
3710+
int ip_proto = -1;
36863711

36873712
switch (bond->params.xmit_policy) {
36883713
case BOND_XMIT_POLICY_ENCAP23:
36893714
case BOND_XMIT_POLICY_ENCAP34:
36903715
memset(fk, 0, sizeof(*fk));
36913716
return __skb_flow_dissect(NULL, skb, &flow_keys_bonding,
3692-
fk, NULL, 0, 0, 0, 0);
3717+
fk, data, l2_proto, nhoff, hlen, 0);
36933718
default:
36943719
break;
36953720
}
36963721

36973722
fk->ports.ports = 0;
36983723
memset(&fk->icmp, 0, sizeof(fk->icmp));
3699-
noff = skb_network_offset(skb);
3700-
if (!bond_flow_ip(skb, fk, &noff, &proto, l34))
3724+
if (!bond_flow_ip(skb, fk, data, hlen, l2_proto, &nhoff, &ip_proto, l34))
37013725
return false;
37023726

37033727
/* ICMP error packets contains at least 8 bytes of the header
37043728
* of the packet which generated the error. Use this information
37053729
* to correlate ICMP error packets within the same flow which
37063730
* generated the error.
37073731
*/
3708-
if (proto == IPPROTO_ICMP || proto == IPPROTO_ICMPV6) {
3709-
skb_flow_get_icmp_tci(skb, &fk->icmp, skb->data,
3710-
skb_transport_offset(skb),
3711-
skb_headlen(skb));
3712-
if (proto == IPPROTO_ICMP) {
3732+
if (ip_proto == IPPROTO_ICMP || ip_proto == IPPROTO_ICMPV6) {
3733+
skb_flow_get_icmp_tci(skb, &fk->icmp, data, nhoff, hlen);
3734+
if (ip_proto == IPPROTO_ICMP) {
37133735
if (!icmp_is_err(fk->icmp.type))
37143736
return true;
37153737

3716-
noff += sizeof(struct icmphdr);
3717-
} else if (proto == IPPROTO_ICMPV6) {
3738+
nhoff += sizeof(struct icmphdr);
3739+
} else if (ip_proto == IPPROTO_ICMPV6) {
37183740
if (!icmpv6_is_err(fk->icmp.type))
37193741
return true;
37203742

3721-
noff += sizeof(struct icmp6hdr);
3743+
nhoff += sizeof(struct icmp6hdr);
37223744
}
3723-
return bond_flow_ip(skb, fk, &noff, &proto, l34);
3745+
return bond_flow_ip(skb, fk, data, hlen, l2_proto, &nhoff, &ip_proto, l34);
37243746
}
37253747

37263748
return true;
@@ -3736,33 +3758,26 @@ static u32 bond_ip_hash(u32 hash, struct flow_keys *flow)
37363758
return hash >> 1;
37373759
}
37383760

3739-
/**
3740-
* bond_xmit_hash - generate a hash value based on the xmit policy
3741-
* @bond: bonding device
3742-
* @skb: buffer to use for headers
3743-
*
3744-
* This function will extract the necessary headers from the skb buffer and use
3745-
* them to generate a hash based on the xmit_policy set in the bonding device
3761+
/* Generate hash based on xmit policy. If @skb is given it is used to linearize
3762+
* the data as required, but this function can be used without it if the data is
3763+
* known to be linear (e.g. with xdp_buff).
37463764
*/
3747-
u32 bond_xmit_hash(struct bonding *bond, struct sk_buff *skb)
3765+
static u32 __bond_xmit_hash(struct bonding *bond, struct sk_buff *skb, const void *data,
3766+
__be16 l2_proto, int mhoff, int nhoff, int hlen)
37483767
{
37493768
struct flow_keys flow;
37503769
u32 hash;
37513770

3752-
if (bond->params.xmit_policy == BOND_XMIT_POLICY_ENCAP34 &&
3753-
skb->l4_hash)
3754-
return skb->hash;
3755-
37563771
if (bond->params.xmit_policy == BOND_XMIT_POLICY_VLAN_SRCMAC)
3757-
return bond_vlan_srcmac_hash(skb);
3772+
return bond_vlan_srcmac_hash(skb, data, mhoff, hlen);
37583773

37593774
if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER2 ||
3760-
!bond_flow_dissect(bond, skb, &flow))
3761-
return bond_eth_hash(skb);
3775+
!bond_flow_dissect(bond, skb, data, l2_proto, nhoff, hlen, &flow))
3776+
return bond_eth_hash(skb, data, mhoff, hlen);
37623777

37633778
if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER23 ||
37643779
bond->params.xmit_policy == BOND_XMIT_POLICY_ENCAP23) {
3765-
hash = bond_eth_hash(skb);
3780+
hash = bond_eth_hash(skb, data, mhoff, hlen);
37663781
} else {
37673782
if (flow.icmp.id)
37683783
memcpy(&hash, &flow.icmp, sizeof(hash));
@@ -3773,6 +3788,25 @@ u32 bond_xmit_hash(struct bonding *bond, struct sk_buff *skb)
37733788
return bond_ip_hash(hash, &flow);
37743789
}
37753790

3791+
/**
3792+
* bond_xmit_hash - generate a hash value based on the xmit policy
3793+
* @bond: bonding device
3794+
* @skb: buffer to use for headers
3795+
*
3796+
* This function will extract the necessary headers from the skb buffer and use
3797+
* them to generate a hash based on the xmit_policy set in the bonding device
3798+
*/
3799+
u32 bond_xmit_hash(struct bonding *bond, struct sk_buff *skb)
3800+
{
3801+
if (bond->params.xmit_policy == BOND_XMIT_POLICY_ENCAP34 &&
3802+
skb->l4_hash)
3803+
return skb->hash;
3804+
3805+
return __bond_xmit_hash(bond, skb, skb->head, skb->protocol,
3806+
skb->mac_header, skb->network_header,
3807+
skb_headlen(skb));
3808+
}
3809+
37763810
/*-------------------------- Device entry points ----------------------------*/
37773811

37783812
void bond_work_init_all(struct bonding *bond)
@@ -4434,8 +4468,7 @@ static netdev_tx_t bond_xmit_roundrobin(struct sk_buff *skb,
44344468
return bond_tx_drop(bond_dev, skb);
44354469
}
44364470

4437-
static struct slave *bond_xmit_activebackup_slave_get(struct bonding *bond,
4438-
struct sk_buff *skb)
4471+
static struct slave *bond_xmit_activebackup_slave_get(struct bonding *bond)
44394472
{
44404473
return rcu_dereference(bond->curr_active_slave);
44414474
}
@@ -4449,7 +4482,7 @@ static netdev_tx_t bond_xmit_activebackup(struct sk_buff *skb,
44494482
struct bonding *bond = netdev_priv(bond_dev);
44504483
struct slave *slave;
44514484

4452-
slave = bond_xmit_activebackup_slave_get(bond, skb);
4485+
slave = bond_xmit_activebackup_slave_get(bond);
44534486
if (slave)
44544487
return bond_dev_queue_xmit(bond, skb, slave->dev);
44554488

@@ -4747,7 +4780,7 @@ static struct net_device *bond_xmit_get_slave(struct net_device *master_dev,
47474780
slave = bond_xmit_roundrobin_slave_get(bond, skb);
47484781
break;
47494782
case BOND_MODE_ACTIVEBACKUP:
4750-
slave = bond_xmit_activebackup_slave_get(bond, skb);
4783+
slave = bond_xmit_activebackup_slave_get(bond);
47514784
break;
47524785
case BOND_MODE_8023AD:
47534786
case BOND_MODE_XOR:

0 commit comments

Comments
 (0)