Commit de063b70 authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller

bonding: remove packet cloning in recv_probe()

Cloning all packets in input path have a significant cost.

Use skb_header_pointer()/skb_copy_bits() instead of pskb_may_pull() so
that recv_probe handlers (bond_3ad_lacpdu_recv / bond_arp_rcv /
rlb_arp_recv ) dont touch input skb.

bond_handle_frame() can avoid the skb_clone()/dev_kfree_skb()
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Cc: Jay Vosburgh <fubar@us.ibm.com>
Cc: Andy Gospodarek <andy@greyhouse.net>
Cc: Jiri Bohac <jbohac@suse.cz>
Cc: Nicolas de Pesloüan <nicolas.2p.debian@free.fr>
Cc: Maciej Żenczykowski <maze@google.com>
Signed-off-by: default avatarJay Vosburgh <fubar@us.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 072c0559
...@@ -2460,18 +2460,21 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) ...@@ -2460,18 +2460,21 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_OK; return NETDEV_TX_OK;
} }
int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct bonding *bond, int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond,
struct slave *slave) struct slave *slave)
{ {
int ret = RX_HANDLER_ANOTHER; int ret = RX_HANDLER_ANOTHER;
struct lacpdu *lacpdu, _lacpdu;
if (skb->protocol != PKT_TYPE_LACPDU) if (skb->protocol != PKT_TYPE_LACPDU)
return ret; return ret;
if (!pskb_may_pull(skb, sizeof(struct lacpdu))) lacpdu = skb_header_pointer(skb, 0, sizeof(_lacpdu), &_lacpdu);
if (!lacpdu)
return ret; return ret;
read_lock(&bond->lock); read_lock(&bond->lock);
ret = bond_3ad_rx_indication((struct lacpdu *) skb->data, slave, skb->len); ret = bond_3ad_rx_indication(lacpdu, slave, skb->len);
read_unlock(&bond->lock); read_unlock(&bond->lock);
return ret; return ret;
} }
......
...@@ -274,7 +274,7 @@ void bond_3ad_adapter_duplex_changed(struct slave *slave); ...@@ -274,7 +274,7 @@ void bond_3ad_adapter_duplex_changed(struct slave *slave);
void bond_3ad_handle_link_change(struct slave *slave, char link); void bond_3ad_handle_link_change(struct slave *slave, char link);
int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info); int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info);
int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev); int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev);
int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct bonding *bond, int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond,
struct slave *slave); struct slave *slave);
int bond_3ad_set_carrier(struct bonding *bond); int bond_3ad_set_carrier(struct bonding *bond);
void bond_3ad_update_lacp_rate(struct bonding *bond); void bond_3ad_update_lacp_rate(struct bonding *bond);
......
...@@ -342,27 +342,17 @@ static void rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp) ...@@ -342,27 +342,17 @@ static void rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp)
_unlock_rx_hashtbl_bh(bond); _unlock_rx_hashtbl_bh(bond);
} }
static int rlb_arp_recv(struct sk_buff *skb, struct bonding *bond, static int rlb_arp_recv(const struct sk_buff *skb, struct bonding *bond,
struct slave *slave) struct slave *slave)
{ {
struct arp_pkt *arp; struct arp_pkt *arp, _arp;
if (skb->protocol != cpu_to_be16(ETH_P_ARP)) if (skb->protocol != cpu_to_be16(ETH_P_ARP))
goto out; goto out;
arp = (struct arp_pkt *) skb->data; arp = skb_header_pointer(skb, 0, sizeof(_arp), &_arp);
if (!arp) { if (!arp)
pr_debug("Packet has no ARP data\n");
goto out; goto out;
}
if (!pskb_may_pull(skb, arp_hdr_len(bond->dev)))
goto out;
if (skb->len < sizeof(struct arp_pkt)) {
pr_debug("Packet is too small to be an ARP\n");
goto out;
}
if (arp->op_code == htons(ARPOP_REPLY)) { if (arp->op_code == htons(ARPOP_REPLY)) {
/* update rx hash table for this ARP */ /* update rx hash table for this ARP */
......
...@@ -1444,7 +1444,7 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb) ...@@ -1444,7 +1444,7 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb)
struct sk_buff *skb = *pskb; struct sk_buff *skb = *pskb;
struct slave *slave; struct slave *slave;
struct bonding *bond; struct bonding *bond;
int (*recv_probe)(struct sk_buff *, struct bonding *, int (*recv_probe)(const struct sk_buff *, struct bonding *,
struct slave *); struct slave *);
int ret = RX_HANDLER_ANOTHER; int ret = RX_HANDLER_ANOTHER;
...@@ -1462,17 +1462,12 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb) ...@@ -1462,17 +1462,12 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb)
recv_probe = ACCESS_ONCE(bond->recv_probe); recv_probe = ACCESS_ONCE(bond->recv_probe);
if (recv_probe) { if (recv_probe) {
struct sk_buff *nskb = skb_clone(skb, GFP_ATOMIC); ret = recv_probe(skb, bond, slave);
if (likely(nskb)) {
ret = recv_probe(nskb, bond, slave);
dev_kfree_skb(nskb);
if (ret == RX_HANDLER_CONSUMED) { if (ret == RX_HANDLER_CONSUMED) {
consume_skb(skb); consume_skb(skb);
return ret; return ret;
} }
} }
}
if (bond_should_deliver_exact_match(skb, slave, bond)) { if (bond_should_deliver_exact_match(skb, slave, bond)) {
return RX_HANDLER_EXACT; return RX_HANDLER_EXACT;
...@@ -2737,25 +2732,31 @@ static void bond_validate_arp(struct bonding *bond, struct slave *slave, __be32 ...@@ -2737,25 +2732,31 @@ static void bond_validate_arp(struct bonding *bond, struct slave *slave, __be32
} }
} }
static int bond_arp_rcv(struct sk_buff *skb, struct bonding *bond, static int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond,
struct slave *slave) struct slave *slave)
{ {
struct arphdr *arp; struct arphdr *arp = (struct arphdr *)skb->data;
unsigned char *arp_ptr; unsigned char *arp_ptr;
__be32 sip, tip; __be32 sip, tip;
int alen;
if (skb->protocol != __cpu_to_be16(ETH_P_ARP)) if (skb->protocol != __cpu_to_be16(ETH_P_ARP))
return RX_HANDLER_ANOTHER; return RX_HANDLER_ANOTHER;
read_lock(&bond->lock); read_lock(&bond->lock);
alen = arp_hdr_len(bond->dev);
pr_debug("bond_arp_rcv: bond %s skb->dev %s\n", pr_debug("bond_arp_rcv: bond %s skb->dev %s\n",
bond->dev->name, skb->dev->name); bond->dev->name, skb->dev->name);
if (!pskb_may_pull(skb, arp_hdr_len(bond->dev))) if (alen > skb_headlen(skb)) {
arp = kmalloc(alen, GFP_ATOMIC);
if (!arp)
goto out_unlock; goto out_unlock;
if (skb_copy_bits(skb, 0, arp, alen) < 0)
goto out_unlock;
}
arp = arp_hdr(skb);
if (arp->ar_hln != bond->dev->addr_len || if (arp->ar_hln != bond->dev->addr_len ||
skb->pkt_type == PACKET_OTHERHOST || skb->pkt_type == PACKET_OTHERHOST ||
skb->pkt_type == PACKET_LOOPBACK || skb->pkt_type == PACKET_LOOPBACK ||
...@@ -2790,6 +2791,8 @@ static int bond_arp_rcv(struct sk_buff *skb, struct bonding *bond, ...@@ -2790,6 +2791,8 @@ static int bond_arp_rcv(struct sk_buff *skb, struct bonding *bond,
out_unlock: out_unlock:
read_unlock(&bond->lock); read_unlock(&bond->lock);
if (arp != (struct arphdr *)skb->data)
kfree(arp);
return RX_HANDLER_ANOTHER; return RX_HANDLER_ANOTHER;
} }
......
...@@ -218,7 +218,7 @@ struct bonding { ...@@ -218,7 +218,7 @@ struct bonding {
struct slave *primary_slave; struct slave *primary_slave;
bool force_primary; bool force_primary;
s32 slave_cnt; /* never change this value outside the attach/detach wrappers */ s32 slave_cnt; /* never change this value outside the attach/detach wrappers */
int (*recv_probe)(struct sk_buff *, struct bonding *, int (*recv_probe)(const struct sk_buff *, struct bonding *,
struct slave *); struct slave *);
rwlock_t lock; rwlock_t lock;
rwlock_t curr_slave_lock; rwlock_t curr_slave_lock;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment