Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 13a8e0c8 authored by Jiri Bohac's avatar Jiri Bohac Committed by David S. Miller
Browse files

bonding: don't increase rx_dropped after processing LACPDUs



Since commit 3aba891d, bonding processes LACP frames (802.3ad
mode) with bond_handle_frame(). Currently a copy of the skb is
made and the original is left to be processed by other
rx_handlers and the rest of the network stack by returning
RX_HANDLER_ANOTHER.  As there is no protocol handler for
PKT_TYPE_LACPDU, the frame is dropped and dev->rx_dropped
increased.

Fix this by making bond_handle_frame() return RX_HANDLER_CONSUMED
if bonding has processed the LACP frame.

Signed-off-by: default avatarJiri Bohac <jbohac@suse.cz>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 38bf1953
Loading
Loading
Loading
Loading
+12 −6
Original line number Original line Diff line number Diff line
@@ -2173,9 +2173,10 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
 * received frames (loopback). Since only the payload is given to this
 * received frames (loopback). Since only the payload is given to this
 * function, it check for loopback.
 * function, it check for loopback.
 */
 */
static void bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, u16 length)
static int bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, u16 length)
{
{
	struct port *port;
	struct port *port;
	int ret = RX_HANDLER_ANOTHER;


	if (length >= sizeof(struct lacpdu)) {
	if (length >= sizeof(struct lacpdu)) {


@@ -2184,11 +2185,12 @@ static void bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, u
		if (!port->slave) {
		if (!port->slave) {
			pr_warning("%s: Warning: port of slave %s is uninitialized\n",
			pr_warning("%s: Warning: port of slave %s is uninitialized\n",
				   slave->dev->name, slave->dev->master->name);
				   slave->dev->name, slave->dev->master->name);
			return;
			return ret;
		}
		}


		switch (lacpdu->subtype) {
		switch (lacpdu->subtype) {
		case AD_TYPE_LACPDU:
		case AD_TYPE_LACPDU:
			ret = RX_HANDLER_CONSUMED;
			pr_debug("Received LACPDU on port %d\n",
			pr_debug("Received LACPDU on port %d\n",
				 port->actor_port_number);
				 port->actor_port_number);
			/* Protect against concurrent state machines */
			/* Protect against concurrent state machines */
@@ -2198,6 +2200,7 @@ static void bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, u
			break;
			break;


		case AD_TYPE_MARKER:
		case AD_TYPE_MARKER:
			ret = RX_HANDLER_CONSUMED;
			// No need to convert fields to Little Endian since we don't use the marker's fields.
			// No need to convert fields to Little Endian since we don't use the marker's fields.


			switch (((struct bond_marker *)lacpdu)->tlv_type) {
			switch (((struct bond_marker *)lacpdu)->tlv_type) {
@@ -2219,6 +2222,7 @@ static void bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, u
			}
			}
		}
		}
	}
	}
	return ret;
}
}


/**
/**
@@ -2456,18 +2460,20 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
	return NETDEV_TX_OK;
	return NETDEV_TX_OK;
}
}


void bond_3ad_lacpdu_recv(struct sk_buff *skb, struct bonding *bond,
int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct bonding *bond,
			  struct slave *slave)
			  struct slave *slave)
{
{
	int ret = RX_HANDLER_ANOTHER;
	if (skb->protocol != PKT_TYPE_LACPDU)
	if (skb->protocol != PKT_TYPE_LACPDU)
		return;
		return ret;


	if (!pskb_may_pull(skb, sizeof(struct lacpdu)))
	if (!pskb_may_pull(skb, sizeof(struct lacpdu)))
		return;
		return ret;


	read_lock(&bond->lock);
	read_lock(&bond->lock);
	bond_3ad_rx_indication((struct lacpdu *) skb->data, slave, skb->len);
	ret = bond_3ad_rx_indication((struct lacpdu *) skb->data, slave, skb->len);
	read_unlock(&bond->lock);
	read_unlock(&bond->lock);
	return ret;
}
}


/*
/*
+1 −1
Original line number Original line Diff line number Diff line
@@ -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);
void bond_3ad_lacpdu_recv(struct sk_buff *skb, struct bonding *bond,
int bond_3ad_lacpdu_recv(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);
+11 −5
Original line number Original line Diff line number Diff line
@@ -1444,8 +1444,9 @@ 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;
	void (*recv_probe)(struct sk_buff *, struct bonding *,
	int (*recv_probe)(struct sk_buff *, struct bonding *,
				struct slave *);
				struct slave *);
	int ret = RX_HANDLER_ANOTHER;


	skb = skb_share_check(skb, GFP_ATOMIC);
	skb = skb_share_check(skb, GFP_ATOMIC);
	if (unlikely(!skb))
	if (unlikely(!skb))
@@ -1464,8 +1465,12 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb)
		struct sk_buff *nskb = skb_clone(skb, GFP_ATOMIC);
		struct sk_buff *nskb = skb_clone(skb, GFP_ATOMIC);


		if (likely(nskb)) {
		if (likely(nskb)) {
			recv_probe(nskb, bond, slave);
			ret = recv_probe(nskb, bond, slave);
			dev_kfree_skb(nskb);
			dev_kfree_skb(nskb);
			if (ret == RX_HANDLER_CONSUMED) {
				consume_skb(skb);
				return ret;
			}
		}
		}
	}
	}


@@ -1487,7 +1492,7 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb)
		memcpy(eth_hdr(skb)->h_dest, bond->dev->dev_addr, ETH_ALEN);
		memcpy(eth_hdr(skb)->h_dest, bond->dev->dev_addr, ETH_ALEN);
	}
	}


	return RX_HANDLER_ANOTHER;
	return ret;
}
}


/* enslave device <slave> to bond device <master> */
/* enslave device <slave> to bond device <master> */
@@ -2723,7 +2728,7 @@ static void bond_validate_arp(struct bonding *bond, struct slave *slave, __be32
	}
	}
}
}


static void bond_arp_rcv(struct sk_buff *skb, struct bonding *bond,
static int bond_arp_rcv(struct sk_buff *skb, struct bonding *bond,
			 struct slave *slave)
			 struct slave *slave)
{
{
	struct arphdr *arp;
	struct arphdr *arp;
@@ -2731,7 +2736,7 @@ static void bond_arp_rcv(struct sk_buff *skb, struct bonding *bond,
	__be32 sip, tip;
	__be32 sip, tip;


	if (skb->protocol != __cpu_to_be16(ETH_P_ARP))
	if (skb->protocol != __cpu_to_be16(ETH_P_ARP))
		return;
		return RX_HANDLER_ANOTHER;


	read_lock(&bond->lock);
	read_lock(&bond->lock);


@@ -2776,6 +2781,7 @@ static void bond_arp_rcv(struct sk_buff *skb, struct bonding *bond,


out_unlock:
out_unlock:
	read_unlock(&bond->lock);
	read_unlock(&bond->lock);
	return RX_HANDLER_ANOTHER;
}
}


/*
/*