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

Commit f663dd9a authored by Jason Wang's avatar Jason Wang Committed by David S. Miller
Browse files

net: core: explicitly select a txq before doing l2 forwarding



Currently, the tx queue were selected implicitly in ndo_dfwd_start_xmit(). The
will cause several issues:

- NETIF_F_LLTX were removed for macvlan, so txq lock were done for macvlan
  instead of lower device which misses the necessary txq synchronization for
  lower device such as txq stopping or frozen required by dev watchdog or
  control path.
- dev_hard_start_xmit() was called with NULL txq which bypasses the net device
  watchdog.
- dev_hard_start_xmit() does not check txq everywhere which will lead a crash
  when tso is disabled for lower device.

Fix this by explicitly introducing a new param for .ndo_select_queue() for just
selecting queues in the case of l2 forwarding offload. netdev_pick_tx() was also
extended to accept this parameter and dev_queue_xmit_accel() was used to do l2
forwarding transmission.

With this fixes, NETIF_F_LLTX could be preserved for macvlan and there's no need
to check txq against NULL in dev_hard_start_xmit(). Also there's no need to keep
a dedicated ndo_dfwd_start_xmit() and we can just reuse the code of
dev_queue_xmit() to do the transmission.

In the future, it was also required for macvtap l2 forwarding support since it
provides a necessary synchronization method.

Cc: John Fastabend <john.r.fastabend@intel.com>
Cc: Neil Horman <nhorman@tuxdriver.com>
Cc: e1000-devel@lists.sourceforge.net
Signed-off-by: default avatarJason Wang <jasowang@redhat.com>
Acked-by: default avatarNeil Horman <nhorman@tuxdriver.com>
Acked-by: default avatarJohn Fastabend <john.r.fastabend@intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b13ba1b8
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -3732,7 +3732,8 @@ static inline int bond_slave_override(struct bonding *bond,
}


static u16 bond_select_queue(struct net_device *dev, struct sk_buff *skb)
static u16 bond_select_queue(struct net_device *dev, struct sk_buff *skb,
			     void *accel_priv)
{
	/*
	 * This helper function exists to help dev_pick_tx get the correct
+2 −1
Original line number Diff line number Diff line
@@ -1833,7 +1833,8 @@ void bnx2x_netif_stop(struct bnx2x *bp, int disable_hw)
		bnx2x_napi_disable_cnic(bp);
}

u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb)
u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb,
		       void *accel_priv)
{
	struct bnx2x *bp = netdev_priv(dev);

+2 −1
Original line number Diff line number Diff line
@@ -524,7 +524,8 @@ int bnx2x_set_vf_mac(struct net_device *dev, int queue, u8 *mac);
int bnx2x_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos);

/* select_queue callback */
u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb);
u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb,
		       void *accel_priv);

static inline void bnx2x_update_rx_prod(struct bnx2x *bp,
					struct bnx2x_fastpath *fp,
+13 −20
Original line number Diff line number Diff line
@@ -6827,12 +6827,20 @@ static inline int ixgbe_maybe_stop_tx(struct ixgbe_ring *tx_ring, u16 size)
	return __ixgbe_maybe_stop_tx(tx_ring, size);
}

#ifdef IXGBE_FCOE
static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb)
static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb,
			      void *accel_priv)
{
	struct ixgbe_fwd_adapter *fwd_adapter = accel_priv;
#ifdef IXGBE_FCOE
	struct ixgbe_adapter *adapter;
	struct ixgbe_ring_feature *f;
	int txq;
#endif

	if (fwd_adapter)
		return skb->queue_mapping + fwd_adapter->tx_base_queue;

#ifdef IXGBE_FCOE

	/*
	 * only execute the code below if protocol is FCoE
@@ -6858,9 +6866,11 @@ static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb)
		txq -= f->indices;

	return txq + f->offset;
#else
	return __netdev_pick_tx(dev, skb);
#endif
}

#endif
netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
			  struct ixgbe_adapter *adapter,
			  struct ixgbe_ring *tx_ring)
@@ -7629,27 +7639,11 @@ static void ixgbe_fwd_del(struct net_device *pdev, void *priv)
	kfree(fwd_adapter);
}

static netdev_tx_t ixgbe_fwd_xmit(struct sk_buff *skb,
				  struct net_device *dev,
				  void *priv)
{
	struct ixgbe_fwd_adapter *fwd_adapter = priv;
	unsigned int queue;
	struct ixgbe_ring *tx_ring;

	queue = skb->queue_mapping + fwd_adapter->tx_base_queue;
	tx_ring = fwd_adapter->real_adapter->tx_ring[queue];

	return __ixgbe_xmit_frame(skb, dev, tx_ring);
}

static const struct net_device_ops ixgbe_netdev_ops = {
	.ndo_open		= ixgbe_open,
	.ndo_stop		= ixgbe_close,
	.ndo_start_xmit		= ixgbe_xmit_frame,
#ifdef IXGBE_FCOE
	.ndo_select_queue	= ixgbe_select_queue,
#endif
	.ndo_set_rx_mode	= ixgbe_set_rx_mode,
	.ndo_validate_addr	= eth_validate_addr,
	.ndo_set_mac_address	= ixgbe_set_mac,
@@ -7689,7 +7683,6 @@ static const struct net_device_ops ixgbe_netdev_ops = {
	.ndo_bridge_getlink	= ixgbe_ndo_bridge_getlink,
	.ndo_dfwd_add_station	= ixgbe_fwd_add,
	.ndo_dfwd_del_station	= ixgbe_fwd_del,
	.ndo_dfwd_start_xmit	= ixgbe_fwd_xmit,
};

/**
+2 −1
Original line number Diff line number Diff line
@@ -619,7 +619,8 @@ ltq_etop_set_multicast_list(struct net_device *dev)
}

static u16
ltq_etop_select_queue(struct net_device *dev, struct sk_buff *skb)
ltq_etop_select_queue(struct net_device *dev, struct sk_buff *skb,
		      void *accel_priv)
{
	/* we are currently only using the first queue */
	return 0;
Loading