mirror of https://gitee.com/openkylin/linux.git
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: Eric 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: Jay Vosburgh <fubar@us.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
072c0559e2
commit
de063b7040
|
@ -2460,18 +2460,21 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
|
|||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct bonding *bond,
|
||||
struct slave *slave)
|
||||
int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond,
|
||||
struct slave *slave)
|
||||
{
|
||||
int ret = RX_HANDLER_ANOTHER;
|
||||
struct lacpdu *lacpdu, _lacpdu;
|
||||
|
||||
if (skb->protocol != PKT_TYPE_LACPDU)
|
||||
return ret;
|
||||
|
||||
if (!pskb_may_pull(skb, sizeof(struct lacpdu)))
|
||||
lacpdu = skb_header_pointer(skb, 0, sizeof(_lacpdu), &_lacpdu);
|
||||
if (!lacpdu)
|
||||
return ret;
|
||||
|
||||
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);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -274,8 +274,8 @@ void bond_3ad_adapter_duplex_changed(struct slave *slave);
|
|||
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_xmit_xor(struct sk_buff *skb, struct net_device *dev);
|
||||
int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct bonding *bond,
|
||||
struct slave *slave);
|
||||
int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond,
|
||||
struct slave *slave);
|
||||
int bond_3ad_set_carrier(struct bonding *bond);
|
||||
void bond_3ad_update_lacp_rate(struct bonding *bond);
|
||||
#endif //__BOND_3AD_H__
|
||||
|
|
|
@ -342,27 +342,17 @@ static void rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp)
|
|||
_unlock_rx_hashtbl_bh(bond);
|
||||
}
|
||||
|
||||
static int rlb_arp_recv(struct sk_buff *skb, struct bonding *bond,
|
||||
struct slave *slave)
|
||||
static int rlb_arp_recv(const struct sk_buff *skb, struct bonding *bond,
|
||||
struct slave *slave)
|
||||
{
|
||||
struct arp_pkt *arp;
|
||||
struct arp_pkt *arp, _arp;
|
||||
|
||||
if (skb->protocol != cpu_to_be16(ETH_P_ARP))
|
||||
goto out;
|
||||
|
||||
arp = (struct arp_pkt *) skb->data;
|
||||
if (!arp) {
|
||||
pr_debug("Packet has no ARP data\n");
|
||||
arp = skb_header_pointer(skb, 0, sizeof(_arp), &_arp);
|
||||
if (!arp)
|
||||
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)) {
|
||||
/* update rx hash table for this ARP */
|
||||
|
|
|
@ -1444,8 +1444,8 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb)
|
|||
struct sk_buff *skb = *pskb;
|
||||
struct slave *slave;
|
||||
struct bonding *bond;
|
||||
int (*recv_probe)(struct sk_buff *, struct bonding *,
|
||||
struct slave *);
|
||||
int (*recv_probe)(const struct sk_buff *, struct bonding *,
|
||||
struct slave *);
|
||||
int ret = RX_HANDLER_ANOTHER;
|
||||
|
||||
skb = skb_share_check(skb, GFP_ATOMIC);
|
||||
|
@ -1462,15 +1462,10 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb)
|
|||
|
||||
recv_probe = ACCESS_ONCE(bond->recv_probe);
|
||||
if (recv_probe) {
|
||||
struct sk_buff *nskb = skb_clone(skb, GFP_ATOMIC);
|
||||
|
||||
if (likely(nskb)) {
|
||||
ret = recv_probe(nskb, bond, slave);
|
||||
dev_kfree_skb(nskb);
|
||||
if (ret == RX_HANDLER_CONSUMED) {
|
||||
consume_skb(skb);
|
||||
return ret;
|
||||
}
|
||||
ret = recv_probe(skb, bond, slave);
|
||||
if (ret == RX_HANDLER_CONSUMED) {
|
||||
consume_skb(skb);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
struct slave *slave)
|
||||
static int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond,
|
||||
struct slave *slave)
|
||||
{
|
||||
struct arphdr *arp;
|
||||
struct arphdr *arp = (struct arphdr *)skb->data;
|
||||
unsigned char *arp_ptr;
|
||||
__be32 sip, tip;
|
||||
int alen;
|
||||
|
||||
if (skb->protocol != __cpu_to_be16(ETH_P_ARP))
|
||||
return RX_HANDLER_ANOTHER;
|
||||
|
||||
read_lock(&bond->lock);
|
||||
alen = arp_hdr_len(bond->dev);
|
||||
|
||||
pr_debug("bond_arp_rcv: bond %s skb->dev %s\n",
|
||||
bond->dev->name, skb->dev->name);
|
||||
|
||||
if (!pskb_may_pull(skb, arp_hdr_len(bond->dev)))
|
||||
goto out_unlock;
|
||||
if (alen > skb_headlen(skb)) {
|
||||
arp = kmalloc(alen, GFP_ATOMIC);
|
||||
if (!arp)
|
||||
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 ||
|
||||
skb->pkt_type == PACKET_OTHERHOST ||
|
||||
skb->pkt_type == PACKET_LOOPBACK ||
|
||||
|
@ -2790,6 +2791,8 @@ static int bond_arp_rcv(struct sk_buff *skb, struct bonding *bond,
|
|||
|
||||
out_unlock:
|
||||
read_unlock(&bond->lock);
|
||||
if (arp != (struct arphdr *)skb->data)
|
||||
kfree(arp);
|
||||
return RX_HANDLER_ANOTHER;
|
||||
}
|
||||
|
||||
|
|
|
@ -218,8 +218,8 @@ struct bonding {
|
|||
struct slave *primary_slave;
|
||||
bool force_primary;
|
||||
s32 slave_cnt; /* never change this value outside the attach/detach wrappers */
|
||||
int (*recv_probe)(struct sk_buff *, struct bonding *,
|
||||
struct slave *);
|
||||
int (*recv_probe)(const struct sk_buff *, struct bonding *,
|
||||
struct slave *);
|
||||
rwlock_t lock;
|
||||
rwlock_t curr_slave_lock;
|
||||
u8 send_peer_notif;
|
||||
|
|
Loading…
Reference in New Issue