Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net

Merge in late fixes in preparation for the net-next PR.

Conflicts:

net/netfilter/nf_conntrack_netlink.c
  cd37ab22a7 ("netfilter: nf_conntrack_netlink: fix inverted IPv6 tuple filter")
  1ae2d094b0 ("netfilter: ctnetlink: fix inverted IPv6 address match in dump filter")

Adjacent changes:

drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
  8830e65ed4 ("net: use assign_bit() where applicable")
  07bd391eb9 ("octeontx2-af: Fix CQ enable state tracking after AQ writes")

net/core/sock.c
  31c5ea8a32 ("ipv6: Remove IPV6_ADDRFORM.")
  31b564f70d ("net: use the full socket in sk_mc_loop()")

net/mptcp/protocol.h
  0cb6910130 ("mptcp: remove thmac from subflow ctx")
  7538fa33bb ("mptcp: fix subflow bitfield misuse")

Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
Paolo Abeni 2026-10-22 11:41:47 +02:00
commit 207dd12bc1
122 changed files with 1739 additions and 489 deletions

View File

@ -641,6 +641,7 @@ Mayuresh Janorkar <mayur@ti.com>
Md Sadre Alam <quic_mdalam@quicinc.com> <mdalam@codeaurora.org>
Miaoqing Pan <quic_miaoqing@quicinc.com> <miaoqing@codeaurora.org>
Michael Buesch <m@bues.ch>
Michael Chan <michael.chan@broadcom.com> <mchan@broadcom.com>
Michael Grzeschik <mgr@kernel.org> <m.grzeschik@pengutronix.de>
Michael Grzeschik <mgr@kernel.org> <mgr@pengutronix.de>
Michael Riesch <michael.riesch@collabora.com> <michael.riesch@wolfvision.net>

View File

@ -3825,5 +3825,6 @@ l3mdev_accept - BOOLEAN
max_dgram_qlen - INTEGER
The maximum length of dgram socket receive queue
Default: 10
Possible values: 0 - INT_MAX
Default: 10

View File

@ -5624,7 +5624,7 @@ F: drivers/net/ethernet/broadcom/unimac.h
BROADCOM TG3 GIGABIT ETHERNET DRIVER
M: Pavan Chebbi <pavan.chebbi@broadcom.com>
M: Michael Chan <mchan@broadcom.com>
M: Michael Chan <michael.chan@broadcom.com>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/ethernet/broadcom/tg3.*
@ -28875,6 +28875,7 @@ F: virt/lib/
VIRTIO AND VHOST VSOCK DRIVER
M: Stefan Hajnoczi <stefanha@redhat.com>
M: Stefano Garzarella <sgarzare@redhat.com>
R: Bobby Eshleman <bobbyeshleman@meta.com>
L: kvm@vger.kernel.org
L: virtualization@lists.linux.dev
L: netdev@vger.kernel.org
@ -29180,6 +29181,7 @@ F: drivers/media/test-drivers/vivid/*
VM SOCKETS (AF_VSOCK)
M: Stefano Garzarella <sgarzare@redhat.com>
R: Bobby Eshleman <bobbyeshleman@meta.com>
L: virtualization@lists.linux.dev
L: netdev@vger.kernel.org
S: Maintained

View File

@ -511,6 +511,13 @@ static int bcmasp_netfilt_wr_to_hw(struct bcmasp_priv *priv,
return 0;
}
static bool bcmasp_netfilt_is_companion(struct bcmasp_priv *priv, int i)
{
return i > 0 && (i % 2) &&
priv->net_filters[i].wake_filter &&
priv->net_filters[i - 1].wake_filter;
}
void bcmasp_netfilt_suspend(struct bcmasp_intf *intf)
{
struct bcmasp_priv *priv = intf->parent;
@ -524,9 +531,7 @@ void bcmasp_netfilt_suspend(struct bcmasp_intf *intf)
priv->net_filters[i].port != intf->port)
continue;
if (i > 0 && (i % 2) &&
priv->net_filters[i].wake_filter &&
priv->net_filters[i - 1].wake_filter)
if (bcmasp_netfilt_is_companion(priv, i))
continue;
ret = bcmasp_netfilt_wr_to_hw(priv, &priv->net_filters[i]);
@ -556,9 +561,7 @@ int bcmasp_netfilt_get_all_active(struct bcmasp_intf *intf, u32 *rule_locs,
priv->net_filters[i].port != intf->port)
continue;
if (i > 0 && (i % 2) &&
priv->net_filters[i].wake_filter &&
priv->net_filters[i - 1].wake_filter)
if (bcmasp_netfilt_is_companion(priv, i))
continue;
if (j == *rule_cnt)
@ -583,9 +586,7 @@ int bcmasp_netfilt_get_active(struct bcmasp_intf *intf)
continue;
/* Skip over a wake filter pair */
if (i > 0 && (i % 2) &&
priv->net_filters[i].wake_filter &&
priv->net_filters[i - 1].wake_filter)
if (bcmasp_netfilt_is_companion(priv, i))
continue;
cnt++;
@ -607,6 +608,9 @@ bool bcmasp_netfilt_check_dup(struct bcmasp_intf *intf,
priv->net_filters[i].port != intf->port)
continue;
if (bcmasp_netfilt_is_companion(priv, i))
continue;
cur = &priv->net_filters[i].fs;
if (cur->flow_type != fs->flow_type ||
@ -659,7 +663,7 @@ bool bcmasp_netfilt_check_dup(struct bcmasp_intf *intf,
}
/* If no network filter found, return open filter.
* If no more open filters return NULL
* If no more open filters return error.
*/
struct bcmasp_net_filter *bcmasp_netfilt_get_init(struct bcmasp_intf *intf,
u32 loc, bool wake_filter,
@ -669,45 +673,55 @@ struct bcmasp_net_filter *bcmasp_netfilt_get_init(struct bcmasp_intf *intf,
struct bcmasp_priv *priv = intf->parent;
int i, open_index = -1;
/* Check whether we exceed the filter table capacity */
if (!init) {
if (loc == RX_CLS_LOC_ANY || loc >= priv->num_net_filters)
return ERR_PTR(-EINVAL);
if (priv->net_filters[loc].claimed &&
priv->net_filters[loc].port == intf->port &&
!bcmasp_netfilt_is_companion(priv, loc))
return &priv->net_filters[loc];
return ERR_PTR(-ENOENT);
}
if (loc != RX_CLS_LOC_ANY && loc >= priv->num_net_filters)
return ERR_PTR(-EINVAL);
/* If the filter location is busy (already claimed) and we are initializing
* the filter (insertion), return a busy error code.
*/
if (loc != RX_CLS_LOC_ANY && init && priv->net_filters[loc].claimed)
return ERR_PTR(-EBUSY);
if (loc != RX_CLS_LOC_ANY) {
if (priv->net_filters[loc].claimed)
return ERR_PTR(-EBUSY);
/* We need two filters for wake-up, so we cannot use an odd filter */
if (wake_filter && loc != RX_CLS_LOC_ANY && (loc % 2))
return ERR_PTR(-EINVAL);
/* Initialize the loop index based on the desired location or from 0 */
i = loc == RX_CLS_LOC_ANY ? 0 : loc;
for ( ; i < priv->num_net_filters; i++) {
/* Found matching network filter */
if (!init &&
priv->net_filters[i].claimed &&
priv->net_filters[i].hw_index == i &&
priv->net_filters[i].port == intf->port)
return &priv->net_filters[i];
/* If we don't need a new filter or new filter already found */
if (!init || open_index >= 0)
continue;
/* Wake filter conslidates two filters to cover more bytes
* Wake filter is open if...
* 1. It is an even filter
* 2. The current and next filter is not claimed
*/
if (wake_filter && !(i % 2) && !priv->net_filters[i].claimed &&
!priv->net_filters[i + 1].claimed)
open_index = i;
else if (!priv->net_filters[i].claimed)
open_index = i;
/* We need two filters for wake-up, so we cannot use an odd filter */
if (wake_filter) {
if ((loc % 2) || loc + 1 >= priv->num_net_filters)
return ERR_PTR(-EINVAL);
if (priv->net_filters[loc + 1].claimed)
return ERR_PTR(-EBUSY);
}
open_index = loc;
} else {
for (i = 0; i < priv->num_net_filters; i++) {
/* Wake filter consolidates two filters to cover more bytes.
* Wake filter is open if:
* 1. It is an even filter
* 2. The current and next filter is not claimed
*/
if (wake_filter) {
if (!(i % 2) && (i + 1 < priv->num_net_filters) &&
!priv->net_filters[i].claimed &&
!priv->net_filters[i + 1].claimed) {
open_index = i;
break;
}
} else if (!priv->net_filters[i].claimed) {
open_index = i;
break;
}
}
}
if (open_index >= 0) {
@ -716,16 +730,20 @@ struct bcmasp_net_filter *bcmasp_netfilt_get_init(struct bcmasp_intf *intf,
nfilter->port = intf->port;
nfilter->ch = intf->channel + priv->tx_chan_offset;
nfilter->hw_index = open_index;
if (wake_filter) {
/* Claim next filter */
priv->net_filters[open_index + 1].claimed = true;
priv->net_filters[open_index + 1].wake_filter = true;
priv->net_filters[open_index + 1].hw_index = open_index + 1;
priv->net_filters[open_index + 1].port = intf->port;
priv->net_filters[open_index + 1].ch = intf->channel +
priv->tx_chan_offset;
nfilter->wake_filter = true;
}
}
if (wake_filter && open_index >= 0) {
/* Claim next filter */
priv->net_filters[open_index + 1].claimed = true;
priv->net_filters[open_index + 1].wake_filter = true;
nfilter->wake_filter = true;
}
return nfilter ? nfilter : ERR_PTR(-EINVAL);
return nfilter ? nfilter : ERR_PTR(-ENOSPC);
}
void bcmasp_netfilt_release(struct bcmasp_intf *intf,
@ -733,7 +751,8 @@ void bcmasp_netfilt_release(struct bcmasp_intf *intf,
{
struct bcmasp_priv *priv = intf->parent;
if (nfilt->wake_filter) {
if (nfilt->wake_filter && !(nfilt->hw_index % 2) &&
nfilt->hw_index + 1 < priv->num_net_filters) {
memset(&priv->net_filters[nfilt->hw_index + 1], 0,
sizeof(struct bcmasp_net_filter));
}

View File

@ -245,10 +245,6 @@ struct bcmasp_intf_stats64 {
};
struct bcmasp_mib_counters {
u32 edpkt_ts;
u32 edpkt_rx_pkt_cnt;
u32 edpkt_hdr_ext_cnt;
u32 edpkt_hdr_out_cnt;
u32 umac_frm_cnt;
u32 fb_frm_cnt;
u32 fb_rx_fifo_depth;

View File

@ -234,7 +234,7 @@ static struct sk_buff *bcmasp_csum_offload(struct net_device *dev,
static netdev_tx_t bcmasp_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct bcmasp_intf *intf = netdev_priv(dev);
unsigned int total_bytes, size;
unsigned int total_bytes, size, min_size;
int spb_index, nr_frags, i, j;
struct bcmasp_tx_cb *txcb;
dma_addr_t mapping, valid;
@ -263,16 +263,21 @@ static netdev_tx_t bcmasp_xmit(struct sk_buff *skb, struct net_device *dev)
if (!skb)
return NETDEV_TX_OK;
min_size = ETH_ZLEN + ETH_FCS_LEN;
if (csum_hw)
min_size += sizeof(struct bcmasp_pkt_offload);
if (skb->len < min_size) {
if (skb_put_padto(skb, min_size))
return NETDEV_TX_OK;
nr_frags = skb_shinfo(skb)->nr_frags;
}
spb_index = intf->tx_spb_index;
valid = intf->tx_spb_dma_valid;
for (i = 0; i <= nr_frags; i++) {
if (!i) {
size = skb_headlen(skb);
if (!nr_frags && size < (ETH_ZLEN + ETH_FCS_LEN)) {
if (skb_put_padto(skb, ETH_ZLEN + ETH_FCS_LEN))
return NETDEV_TX_OK;
size = skb->len;
}
mapping = dma_map_single(kdev, skb->data, size,
DMA_TO_DEVICE);
} else {
@ -286,6 +291,11 @@ static netdev_tx_t bcmasp_xmit(struct sk_buff *skb, struct net_device *dev)
intf->mib.tx_dma_failed++;
spb_index = intf->tx_spb_index;
for (j = 0; j < i; j++) {
txcb = &intf->tx_cbs[spb_index];
dma_unmap_single(kdev,
dma_unmap_addr(txcb, dma_addr),
dma_unmap_len(txcb, dma_len),
DMA_TO_DEVICE);
bcmasp_clean_txcb(intf, spb_index);
spb_index = incr_ring(spb_index,
DESC_RING_COUNT);
@ -530,6 +540,12 @@ static int bcmasp_rx_poll(struct napi_struct *napi, int budget)
DMA_FROM_DEVICE);
len = desc->size;
if (unlikely(len < 2 + ETH_HLEN + (intf->crc_fwd ? ETH_FCS_LEN : 0))) {
u64_stats_update_begin(&stats->syncp);
u64_stats_inc(&stats->rx_dropped);
u64_stats_update_end(&stats->syncp);
goto next;
}
/* Allocate a page pool page as the SKB data area so the
* kernel can recycle it efficiently after the packet is
@ -1300,7 +1316,7 @@ struct bcmasp_intf *bcmasp_interface_create(struct bcmasp_priv *priv,
ndev_dn->name);
goto err_free_netdev;
}
intf->phy_dn = ndev_dn;
intf->phy_dn = of_node_get(ndev_dn);
}
/* Map resource */
@ -1340,6 +1356,7 @@ struct bcmasp_intf *bcmasp_interface_create(struct bcmasp_priv *priv,
err_deregister_fixed_link:
if (of_phy_is_fixed_link(ndev_dn))
of_phy_deregister_fixed_link(ndev_dn);
of_node_put(intf->phy_dn);
err_free_netdev:
free_netdev(ndev);
err:
@ -1352,6 +1369,7 @@ void bcmasp_interface_destroy(struct bcmasp_intf *intf)
unregister_netdev(intf->ndev);
if (of_phy_is_fixed_link(intf->ndev_dn))
of_phy_deregister_fixed_link(intf->ndev_dn);
of_node_put(intf->phy_dn);
free_netdev(intf->ndev);
}

View File

@ -3666,7 +3666,8 @@ static void bnx2x_update_pbds_gso_enc(struct sk_buff *skb,
u8 outerip_off, outerip_len = 0;
/* from outer IP to transport */
hlen_w = skb_inner_transport_offset(skb) >> 1;
hlen_w = (skb_inner_transport_offset(skb) -
skb_network_offset(skb)) >> 1;
/* transport len */
hlen_w += inner_tcp_hdrlen(skb) >> 1;

View File

@ -381,11 +381,31 @@ int bnxt_xdp_xmit(struct net_device *dev, int num_frames,
return nxmit;
}
static void bnxt_xdp_apply_cfg(struct bnxt *bp, int tx_xdp)
{
struct net_device *dev = bp->dev;
int tc = bp->num_tc ? : 1;
if (bp->xdp_prog) {
bnxt_set_rx_skb_mode(bp, true);
xdp_features_set_redirect_target_locked(dev, true);
} else {
xdp_features_clear_redirect_target_locked(dev);
bnxt_set_rx_skb_mode(bp, false);
}
bp->tx_nr_rings_xdp = tx_xdp;
bp->tx_nr_rings = bp->tx_nr_rings_per_tc * tc + tx_xdp;
bnxt_set_cp_rings(bp, true);
bnxt_set_tpa_flags(bp);
bnxt_set_ring_params(bp);
}
static int bnxt_xdp_set(struct bnxt *bp, struct bpf_prog *prog)
{
struct net_device *dev = bp->dev;
int tx_xdp = 0, rc, tc;
struct bpf_prog *old;
int old_tx_xdp;
netdev_assert_locked(dev);
@ -418,26 +438,23 @@ static int bnxt_xdp_set(struct bnxt *bp, struct bpf_prog *prog)
if (netif_running(dev))
bnxt_close_nic(bp, true, false);
old_tx_xdp = bp->tx_nr_rings_xdp;
old = xchg(&bp->xdp_prog, prog);
bnxt_xdp_apply_cfg(bp, tx_xdp);
if (netif_running(dev)) {
rc = bnxt_open_nic(bp, true, false);
/* a detach cannot be undone, only an attach */
if (rc && prog) {
WRITE_ONCE(bp->xdp_prog, old);
bnxt_xdp_apply_cfg(bp, old_tx_xdp);
return rc;
}
}
if (old)
bpf_prog_put(old);
if (prog) {
bnxt_set_rx_skb_mode(bp, true);
xdp_features_set_redirect_target_locked(dev, true);
} else {
xdp_features_clear_redirect_target_locked(dev);
bnxt_set_rx_skb_mode(bp, false);
}
bp->tx_nr_rings_xdp = tx_xdp;
bp->tx_nr_rings = bp->tx_nr_rings_per_tc * tc + tx_xdp;
bnxt_set_cp_rings(bp, true);
bnxt_set_tpa_flags(bp);
bnxt_set_ring_params(bp);
if (netif_running(dev))
return bnxt_open_nic(bp, true, false);
return 0;
}

View File

@ -18297,6 +18297,12 @@ static const struct dmi_system_id tg3_restart_aer_quirk_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge R750"),
},
},
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "datto"),
DMI_MATCH(DMI_PRODUCT_NAME, "SIRIS 5 1U Server"),
},
},
{}
};

View File

@ -78,6 +78,7 @@ static const struct ptp_clock_info dpaa2_ptp_caps = {
.n_per_out = 3,
.n_pins = 0,
.pps = 1,
.supported_extts_flags = PTP_RISING_EDGE | PTP_STRICT_FLAGS,
.adjfine = ptp_qoriq_adjfine,
.adjtime = ptp_qoriq_adjtime,
.gettime64 = ptp_qoriq_gettime,

View File

@ -16,6 +16,7 @@ static struct ptp_clock_info enetc_ptp_caps = {
.n_per_out = 0,
.n_pins = 0,
.pps = 1,
.supported_extts_flags = PTP_RISING_EDGE | PTP_STRICT_FLAGS,
.adjfine = ptp_qoriq_adjfine,
.adjtime = ptp_qoriq_adjtime,
.gettime64 = ptp_qoriq_gettime,

View File

@ -448,6 +448,7 @@ static int hbg_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (ret)
return ret;
netdev->netdev_ops = &hbg_netdev_ops;
ret = hbg_init(priv);
if (ret)
return ret;
@ -460,7 +461,6 @@ static int hbg_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
netdev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS;
netdev->max_mtu = priv->dev_specs.max_mtu;
netdev->min_mtu = priv->dev_specs.min_mtu;
netdev->netdev_ops = &hbg_netdev_ops;
netdev->watchdog_timeo = 5 * HZ;
hbg_hw_set_mtu(priv, ETH_DATA_LEN);

View File

@ -1244,13 +1244,13 @@ static int rvu_nix_blk_aq_enq_inst(struct rvu *rvu, struct nix_hw *nix_hw,
__assign_bit(req->qidx, pfvf->rq_bmap, ena);
}
if (req->ctype == NIX_AQ_CTYPE_SQ) {
ena = (req->rq.ena & req->sq_mask.ena) |
ena = (req->sq.ena & req->sq_mask.ena) |
(test_bit(req->qidx, pfvf->sq_bmap) &
~req->sq_mask.ena);
__assign_bit(req->qidx, pfvf->sq_bmap, ena);
}
if (req->ctype == NIX_AQ_CTYPE_CQ) {
ena = (req->rq.ena & req->cq_mask.ena) |
ena = (req->cq.ena & req->cq_mask.ena) |
(test_bit(req->qidx, pfvf->cq_bmap) &
~req->cq_mask.ena);
__assign_bit(req->qidx, pfvf->cq_bmap, ena);

View File

@ -138,7 +138,7 @@ mlx5_dpll_pin_ffo_get(struct mlx5_dpll_synce_status *synce_status,
{
if (!synce_status->oper_freq_measure)
return -ENODATA;
*ffo = 1000000LL * synce_status->frequency_diff;
*ffo = synce_status->frequency_diff;
return 0;
}

View File

@ -98,7 +98,7 @@ static void mlx5e_skb_cb_hwtstamp_tx(struct sk_buff *skb,
ptpsq->cq_stats->abort_abs_diff_ns += diff;
if (diff > (NSEC_PER_SEC >> 1) &&
!test_and_set_bit(MLX5E_SQ_STATE_RECOVERING, &sq->state)) {
netdev_warn(sq->channel->netdev,
netdev_warn(sq->netdev,
"PTP TX timestamp difference between CQE and port exceeds threshold: %lld ns, recovering SQ %u\n",
(s64)diff, sq->sqn);
queue_work(sq->priv->wq, &ptpsq->report_unhealthy_work);

View File

@ -403,11 +403,6 @@ static bool mlx5e_ethtool_set_tcp_data_split(struct mlx5e_priv *priv,
return false;
}
/* Might need to disable HW-GRO if it was kept on due to hds. */
if (tcp_data_split == ETHTOOL_TCP_DATA_SPLIT_DISABLED &&
dev->cfg->hds_config == ETHTOOL_TCP_DATA_SPLIT_ENABLED)
netdev_update_features(priv->netdev);
return true;
}
@ -468,13 +463,23 @@ static int mlx5e_set_ringparam(struct net_device *dev,
struct netlink_ext_ack *extack)
{
struct mlx5e_priv *priv = netdev_priv(dev);
int err;
if (!mlx5e_ethtool_set_tcp_data_split(priv,
kernel_param->tcp_data_split,
extack))
return -EINVAL;
return mlx5e_ethtool_set_ringparam(priv, param, extack);
err = mlx5e_ethtool_set_ringparam(priv, param, extack);
if (err)
return err;
/* Might need to disable HW-GRO if it was kept on due to hds. */
if (kernel_param->tcp_data_split == ETHTOOL_TCP_DATA_SPLIT_DISABLED &&
dev->cfg->hds_config == ETHTOOL_TCP_DATA_SPLIT_ENABLED)
netdev_update_features(priv->netdev);
return 0;
}
void mlx5e_ethtool_get_channels(struct mlx5e_priv *priv,

View File

@ -3075,7 +3075,6 @@ void mlx5e_close_channels(struct mlx5e_channels *chs)
{
int i;
ASSERT_RTNL();
if (chs->ptp) {
mlx5e_ptp_close(chs->ptp);
chs->ptp = NULL;

View File

@ -63,6 +63,7 @@ static int mlx5_fs_init_hws_actions_pool(struct mlx5_core_dev *dev,
xa_init(&hws_pool->el2tol3tnl_pools);
xa_init(&hws_pool->el2tol2tnl_pools);
xa_init(&hws_pool->mh_pools);
mutex_init(&hws_pool->mh_pools_lock);
xa_init(&hws_pool->table_dests);
xa_init(&hws_pool->vport_dests);
xa_init(&hws_pool->vport_vhca_dests);
@ -111,6 +112,7 @@ static void mlx5_fs_cleanup_hws_actions_pool(struct mlx5_fs_hws_context *fs_ctx)
xa_for_each(&hws_pool->mh_pools, i, pool)
mlx5_fs_destroy_mh_pool(pool, &hws_pool->mh_pools, i);
xa_destroy(&hws_pool->mh_pools);
mutex_destroy(&hws_pool->mh_pools_lock);
xa_for_each(&hws_pool->el2tol2tnl_pools, i, pool)
mlx5_fs_destroy_pr_pool(pool, &hws_pool->el2tol2tnl_pools, i);
xa_destroy(&hws_pool->el2tol2tnl_pools);
@ -1237,7 +1239,7 @@ static struct mlx5_fs_pool *
mlx5_fs_get_pr_encap_pool(struct mlx5_core_dev *dev, struct xarray *pr_pools,
enum mlx5hws_action_type reformat_type, size_t size)
{
struct mlx5_fs_pool *pr_pool;
struct mlx5_fs_pool *pr_pool, *old;
unsigned long index = size;
int err;
@ -1251,13 +1253,14 @@ mlx5_fs_get_pr_encap_pool(struct mlx5_core_dev *dev, struct xarray *pr_pools,
err = mlx5_fs_hws_pr_pool_init(pr_pool, dev, size, reformat_type);
if (err)
goto free_pr_pool;
err = xa_insert(pr_pools, index, pr_pool, GFP_KERNEL);
if (err)
goto cleanup_pr_pool;
return pr_pool;
old = xa_cmpxchg(pr_pools, index, NULL, pr_pool, GFP_KERNEL);
if (!old)
return pr_pool;
cleanup_pr_pool:
mlx5_fs_hws_pr_pool_cleanup(pr_pool);
kfree(pr_pool);
return xa_is_err(old) ? ERR_PTR(xa_err(old)) : old;
free_pr_pool:
kfree(pr_pool);
return ERR_PTR(err);
@ -1465,6 +1468,23 @@ mlx5_fs_destroy_mh_pool(struct mlx5_fs_pool *pool, struct xarray *mh_pools,
kfree(pool);
}
static struct mlx5_fs_pool *
mlx5_fs_find_mh_pool(struct xarray *mh_pools,
struct mlx5hws_action_mh_pattern *pattern,
unsigned long *cnt)
{
struct mlx5_fs_pool *pool;
unsigned long i;
*cnt = 0;
xa_for_each(mh_pools, i, pool) {
if (mlx5_fs_hws_mh_pool_match(pool, pattern))
return pool;
(*cnt)++;
}
return NULL;
}
static int mlx5_cmd_hws_modify_header_alloc(struct mlx5_flow_root_namespace *ns,
u8 namespace, u8 num_actions,
void *modify_actions,
@ -1475,33 +1495,28 @@ static int mlx5_cmd_hws_modify_header_alloc(struct mlx5_flow_root_namespace *ns,
struct mlx5_fs_hws_mh *mh_data = NULL;
struct mlx5hws_action *hws_action;
struct mlx5_fs_pool *pool;
unsigned long i, cnt = 0;
bool known_pattern;
unsigned long cnt;
int err;
pattern.sz = MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto) * num_actions;
pattern.data = modify_actions;
known_pattern = false;
xa_for_each(&hws_pool->mh_pools, i, pool) {
if (mlx5_fs_hws_mh_pool_match(pool, &pattern)) {
known_pattern = true;
break;
}
cnt++;
}
if (!known_pattern) {
pool = mlx5_fs_create_mh_pool(ns->dev, &pattern,
&hws_pool->mh_pools, cnt);
pool = mlx5_fs_find_mh_pool(&hws_pool->mh_pools, &pattern, &cnt);
if (!pool) {
mutex_lock(&hws_pool->mh_pools_lock);
pool = mlx5_fs_find_mh_pool(&hws_pool->mh_pools, &pattern,
&cnt);
if (!pool)
pool = mlx5_fs_create_mh_pool(ns->dev, &pattern,
&hws_pool->mh_pools, cnt);
mutex_unlock(&hws_pool->mh_pools_lock);
if (IS_ERR(pool))
return PTR_ERR(pool);
}
mh_data = mlx5_fs_hws_mh_pool_acquire_mh(pool);
if (IS_ERR(mh_data)) {
err = PTR_ERR(mh_data);
goto destroy_pool;
}
if (IS_ERR(mh_data))
return PTR_ERR(mh_data);
hws_action = mh_data->bulk->hws_action;
mh_data->data = kmemdup(pattern.data, pattern.sz, GFP_KERNEL);
if (!mh_data->data) {
@ -1517,9 +1532,6 @@ static int mlx5_cmd_hws_modify_header_alloc(struct mlx5_flow_root_namespace *ns,
release_mh:
mlx5_fs_hws_mh_pool_release_mh(pool, mh_data);
destroy_pool:
if (!known_pattern)
mlx5_fs_destroy_mh_pool(pool, &hws_pool->mh_pools, cnt);
return err;
}

View File

@ -19,6 +19,7 @@ struct mlx5_fs_hws_actions_pool {
struct xarray el2tol3tnl_pools;
struct xarray el2tol2tnl_pools;
struct xarray mh_pools;
struct mutex mh_pools_lock; /* serializes pool creation */
struct xarray table_dests;
struct xarray vport_vhca_dests;
struct xarray vport_dests;

View File

@ -3,6 +3,7 @@
#include <mlx5_core.h>
#include "fs_hws_pools.h"
#include "internal.h"
#define MLX5_FS_HWS_DEFAULT_BULK_LEN 65536
#define MLX5_FS_HWS_POOL_MAX_THRESHOLD BIT(18)
@ -389,7 +390,7 @@ bool mlx5_fs_hws_mh_pool_match(struct mlx5_fs_pool *mh_pool,
struct mlx5hws_action_mh_pattern *pattern)
{
struct mlx5hws_action_mh_pattern *pool_pattern;
int num_actions, i;
int num_actions;
pool_pattern = mh_pool->pool_ctx;
if (WARN_ON_ONCE(!pool_pattern))
@ -398,12 +399,8 @@ bool mlx5_fs_hws_mh_pool_match(struct mlx5_fs_pool *mh_pool,
if (pattern->sz != pool_pattern->sz)
return false;
num_actions = pattern->sz / MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto);
for (i = 0; i < num_actions; i++) {
if ((__force __be32)pattern->data[i] !=
(__force __be32)pool_pattern->data[i])
return false;
}
return true;
return mlx5hws_pat_compare_pattern(num_actions, pool_pattern->data,
num_actions, pattern->data);
}
struct mlx5hws_action *mlx5_fc_get_hws_action(struct mlx5hws_context *ctx,

View File

@ -96,10 +96,10 @@ void mlx5hws_pat_uninit_pattern_cache(struct mlx5hws_pattern_cache *cache)
kfree(cache);
}
static bool mlx5hws_pat_compare_pattern(int cur_num_of_actions,
__be64 cur_actions[],
int num_of_actions,
__be64 actions[])
bool mlx5hws_pat_compare_pattern(int cur_num_of_actions,
__be64 cur_actions[],
int num_of_actions,
__be64 actions[])
{
int i;
@ -116,8 +116,8 @@ static bool mlx5hws_pat_compare_pattern(int cur_num_of_actions,
return false;
} else {
/* Compare just the control, not the values */
if ((__force __be32)actions[i] !=
(__force __be32)cur_actions[i])
if (*(__be32 *)&actions[i] !=
*(__be32 *)&cur_actions[i])
return false;
}
}

View File

@ -49,6 +49,11 @@ int mlx5hws_pat_init_pattern_cache(struct mlx5hws_pattern_cache **cache);
void mlx5hws_pat_uninit_pattern_cache(struct mlx5hws_pattern_cache *cache);
bool mlx5hws_pat_compare_pattern(int cur_num_of_actions,
__be64 cur_actions[],
int num_of_actions,
__be64 actions[]);
bool mlx5hws_pat_verify_actions(struct mlx5hws_context *ctx, __be64 pattern[], size_t sz);
int mlx5hws_arg_create(struct mlx5hws_context *ctx,

View File

@ -2001,7 +2001,7 @@ mlxsw_core_health_fw_fatal_test(struct devlink_health_reporter *reporter,
struct netlink_ext_ack *extack)
{
struct mlxsw_core *mlxsw_core = devlink_health_reporter_priv(reporter);
char mfgd_pl[MLXSW_REG_MFGD_LEN];
char mfgd_pl[MLXSW_REG_MFGD_LEN] = {0};
int err;
/* Read the register first to make sure no other bits are changed. */
@ -2022,7 +2022,7 @@ mlxsw_core_health_fw_fatal_ops = {
static int mlxsw_core_health_fw_fatal_config(struct mlxsw_core *mlxsw_core,
bool enable)
{
char mfgd_pl[MLXSW_REG_MFGD_LEN];
char mfgd_pl[MLXSW_REG_MFGD_LEN] = {0};
int err;
/* Read the register first to make sure no other bits are changed. */

View File

@ -120,7 +120,7 @@ static ssize_t mlxsw_hwmon_temp_rst_store(struct device *dev,
container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev;
struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon;
char mtmp_pl[MLXSW_REG_MTMP_LEN];
char mtmp_pl[MLXSW_REG_MTMP_LEN] = {0};
unsigned long val;
int index;
int err;
@ -177,7 +177,7 @@ static ssize_t mlxsw_hwmon_fan_fault_show(struct device *dev,
container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev;
struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon;
char fore_pl[MLXSW_REG_FORE_LEN];
char fore_pl[MLXSW_REG_FORE_LEN] = {0};
bool fault;
int err;

View File

@ -1734,7 +1734,7 @@ static int mlxsw_sp2_span_init(struct mlxsw_sp *mlxsw_sp)
static int mlxsw_sp2_span_policer_id_base_set(struct mlxsw_sp *mlxsw_sp,
u16 policer_id_base)
{
char mogcr_pl[MLXSW_REG_MOGCR_LEN];
char mogcr_pl[MLXSW_REG_MOGCR_LEN] = {0};
int err;
err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(mogcr), mogcr_pl);

View File

@ -82,6 +82,9 @@ int lan969x_dsm_calendar_calc(struct sparx5 *sparx5, u32 taxi,
struct lan969x_dsm_cal_dev_speed *speed;
int err;
for (u32 i = 0; i < SPX5_DSM_CAL_LEN; i++)
data->schedule[i] = SPX5_DSM_CAL_EMPTY;
/* Maximum bandwidth for this taxi */
taxi_bw = (128 * 1000000) / sparx5_clk_period(sparx5->coreclock);
@ -125,7 +128,7 @@ int lan969x_dsm_calendar_calc(struct sparx5 *sparx5, u32 taxi,
}
if (n_devs == 0) {
data->schedule[0] = SPX5_DSM_CAL_EMPTY;
data->schedule[0] = SPX5_DSM_CAL_MAX_DEVS_PER_TAXI;
return 0;
}
@ -167,9 +170,6 @@ int lan969x_dsm_calendar_calc(struct sparx5 *sparx5, u32 taxi,
return -EINVAL;
}
for (u32 i = 0; i < SPX5_DSM_CAL_LEN; i++)
data->schedule[i] = SPX5_DSM_CAL_EMPTY;
/* Place the remaining devices */
for (u32 i = 0; i < DSM_CAL_DEV_MAX; i++) {
speed = &dev_speeds[i];

View File

@ -54,10 +54,9 @@ static void lan969x_fdma_tx_clear_buf(struct sparx5 *sparx5, int weight)
{
struct fdma *fdma = &sparx5->tx.fdma;
struct sparx5_tx_buf *db;
unsigned long flags;
int i;
spin_lock_irqsave(&sparx5->tx_lock, flags);
spin_lock(&sparx5->tx_lock);
for (i = 0; i < fdma->n_dcbs; ++i) {
db = &sparx5->tx.dbs[i];
@ -83,7 +82,7 @@ static void lan969x_fdma_tx_clear_buf(struct sparx5 *sparx5, int weight)
db->used = false;
}
spin_unlock_irqrestore(&sparx5->tx_lock, flags);
spin_unlock(&sparx5->tx_lock);
}
static void lan969x_fdma_free_pages(struct sparx5_rx *rx)

View File

@ -1991,8 +1991,8 @@ static int qede_flow_spec_to_rule(struct qede_dev *edev,
struct ethtool_rx_flow_spec *fs)
{
struct ethtool_rx_flow_spec_input input = {};
struct netlink_ext_ack extack = {};
struct ethtool_rx_flow_rule *flow;
struct netlink_ext_ack extack;
__be16 proto;
int err;

View File

@ -346,7 +346,7 @@ static int dwxgmac2_dma_interrupt(struct stmmac_priv *priv,
u64_stats_update_end(&stats->syncp);
ret |= handle_rx;
}
if (likely(intr_status & (XGMAC_TI | XGMAC_TBU))) {
if (likely(intr_status & XGMAC_TI)) {
u64_stats_update_begin(&stats->syncp);
u64_stats_inc(&stats->tx_normal_irq_n[chan]);
u64_stats_update_end(&stats->syncp);

View File

@ -1773,8 +1773,10 @@ static void stmmac_free_tx_buffer(struct stmmac_priv *priv,
tx_q->xdpf[i] = NULL;
}
if (tx_q->tx_skbuff_dma[i].buf_type == STMMAC_TXBUF_T_XSK_TX)
if (tx_q->tx_skbuff_dma[i].buf_type == STMMAC_TXBUF_T_XSK_TX) {
tx_q->xsk_frames_done++;
tx_q->tx_skbuff_dma[i].buf_type = STMMAC_TXBUF_T_SKB;
}
if (tx_q->tx_skbuff[i] &&
tx_q->tx_skbuff_dma[i].buf_type == STMMAC_TXBUF_T_SKB) {
@ -2956,8 +2958,11 @@ static int stmmac_tx_clean(struct stmmac_priv *priv, int budget, u32 queue,
tx_q->xdpf[entry] = NULL;
}
if (tx_q->tx_skbuff_dma[entry].buf_type == STMMAC_TXBUF_T_XSK_TX)
if (tx_q->tx_skbuff_dma[entry].buf_type == STMMAC_TXBUF_T_XSK_TX) {
tx_q->xsk_frames_done++;
/* Teardown must not count this slot again. */
tx_q->tx_skbuff_dma[entry].buf_type = STMMAC_TXBUF_T_SKB;
}
if (tx_q->tx_skbuff_dma[entry].buf_type == STMMAC_TXBUF_T_SKB) {
if (likely(skb)) {

View File

@ -144,6 +144,17 @@ int nsim_bpf_setup_tc_block_cb(enum tc_setup_type type,
return -EOPNOTSUPP;
}
/* A dev-bound program can be replayed here when a netdev joins
* a shared block, after the core attach-time check has run;
* enforce the device match as nfp does.
*/
if (prog && bpf_prog_is_dev_bound(prog->aux) &&
!bpf_offload_dev_match(prog, ns->netdev)) {
NSIM_EA(cls_bpf->common.extack,
"program bound to a different device");
return -EINVAL;
}
if (cls_bpf->command != TC_CLSBPF_OFFLOAD)
return -EOPNOTSUPP;

View File

@ -55,6 +55,8 @@
#define MII_M1011_IMASK 0x12
#define MII_M1011_IMASK_INIT 0x6400
#define MII_M1011_IMASK_CLEAR 0x0000
/* WOL Event Interrupt Enable, 88E1318S and 88E1510 only */
#define MII_M1011_IMASK_WOL BIT(7)
#define MII_M1011_PHY_SCR 0x10
#define MII_M1011_PHY_SCR_DOWNSHIFT_EN BIT(11)
@ -139,11 +141,6 @@
#define MII_88E1318S_PHY_MSCR1_REG 16
#define MII_88E1318S_PHY_MSCR1_PAD_ODD BIT(6)
/* Copper Specific Interrupt Enable Register */
#define MII_88E1318S_PHY_CSIER 0x12
/* WOL Event Interrupt Enable */
#define MII_88E1318S_PHY_CSIER_WOL_EIE BIT(7)
#define MII_88E1318S_PHY_LED_FUNC 0x10
#define MII_88E1318S_PHY_LED_FUNC_OFF (0x8)
#define MII_88E1318S_PHY_LED_FUNC_ON (0x9)
@ -354,6 +351,7 @@ struct marvell_priv {
u32 step;
s8 pair;
u8 vct_phase;
bool wol_enabled;
};
static int marvell_read_page(struct phy_device *phydev)
@ -407,7 +405,8 @@ static int marvell_config_intr(struct phy_device *phydev)
return err;
}
static irqreturn_t marvell_handle_interrupt(struct phy_device *phydev)
static irqreturn_t __marvell_handle_interrupt(struct phy_device *phydev,
u16 mask)
{
int irq_status;
@ -417,7 +416,7 @@ static irqreturn_t marvell_handle_interrupt(struct phy_device *phydev)
return IRQ_NONE;
}
if (!(irq_status & MII_M1011_IMASK_INIT))
if (!(irq_status & mask))
return IRQ_NONE;
phy_trigger_machine(phydev);
@ -425,6 +424,57 @@ static irqreturn_t marvell_handle_interrupt(struct phy_device *phydev)
return IRQ_HANDLED;
}
static irqreturn_t marvell_handle_interrupt(struct phy_device *phydev)
{
return __marvell_handle_interrupt(phydev, MII_M1011_IMASK_INIT);
}
/* WOL_EIE also routes WoL events to INTn. Keep it set while WoL is enabled,
* unless INTn is the PHY interrupt and that interrupt is being disabled:
* nothing would read IEVENT after free_irq() to release the line.
*/
static u16 m88e1318_wol_imask(struct phy_device *phydev)
{
struct marvell_priv *priv = phydev->priv;
if (priv->wol_enabled &&
(phydev->interrupts == PHY_INTERRUPT_ENABLED ||
!phy_interrupt_is_valid(phydev)))
return MII_M1011_IMASK_WOL;
return 0;
}
static int m88e1318_config_intr(struct phy_device *phydev)
{
bool enable = phydev->interrupts == PHY_INTERRUPT_ENABLED;
u16 imask;
int err;
if (enable) {
err = marvell_ack_interrupt(phydev);
if (err)
return err;
}
/* Serialise against m88e1318_set_wol() updating wol_enabled */
phy_lock_mdio_bus(phydev);
imask = enable ? MII_M1011_IMASK_INIT : MII_M1011_IMASK_CLEAR;
imask |= m88e1318_wol_imask(phydev);
err = __phy_write(phydev, MII_M1011_IMASK, imask);
phy_unlock_mdio_bus(phydev);
if (err || enable)
return err;
return marvell_ack_interrupt(phydev);
}
static irqreturn_t m88e1318_handle_interrupt(struct phy_device *phydev)
{
return __marvell_handle_interrupt(phydev, MII_M1011_IMASK_INIT |
MII_M1011_IMASK_WOL);
}
static int marvell_set_polarity(struct phy_device *phydev, int polarity)
{
u16 val;
@ -1969,18 +2019,27 @@ static void m88e1318_get_wol(struct phy_device *phydev,
static int m88e1318_set_wol(struct phy_device *phydev,
struct ethtool_wolinfo *wol)
{
struct marvell_priv *priv = phydev->priv;
int err = 0, oldpage;
oldpage = phy_save_page(phydev);
if (oldpage < 0)
goto error;
if (wol->wolopts & (WAKE_MAGIC | WAKE_PHY)) {
/* Explicitly switch to page 0x00, just to be sure */
err = marvell_write_page(phydev, MII_MARVELL_COPPER_PAGE);
if (err < 0)
goto error;
priv->wol_enabled = !!(wol->wolopts & (WAKE_MAGIC | WAKE_PHY));
/* Explicitly switch to page 0x00, just to be sure */
err = marvell_write_page(phydev, MII_MARVELL_COPPER_PAGE);
if (err < 0)
goto error;
/* Update the WOL interrupt enable */
err = __phy_modify(phydev, MII_M1011_IMASK, MII_M1011_IMASK_WOL,
m88e1318_wol_imask(phydev));
if (err < 0)
goto error;
if (priv->wol_enabled) {
/* If WOL event happened once, the LED[2] interrupt pin
* will not be cleared unless we reading the interrupt status
* register. If interrupts are in use, the normal interrupt
@ -1990,12 +2049,6 @@ static int m88e1318_set_wol(struct phy_device *phydev,
if (!phy_interrupt_is_valid(phydev))
__phy_read(phydev, MII_M1011_IEVENT);
/* Enable the WOL interrupt */
err = __phy_set_bits(phydev, MII_88E1318S_PHY_CSIER,
MII_88E1318S_PHY_CSIER_WOL_EIE);
if (err < 0)
goto error;
err = marvell_write_page(phydev, MII_MARVELL_LED_PAGE);
if (err < 0)
goto error;
@ -3817,8 +3870,8 @@ static struct phy_driver marvell_drivers[] = {
.config_init = m88e1318_config_init,
.config_aneg = m88e1318_config_aneg,
.read_status = marvell_read_status,
.config_intr = marvell_config_intr,
.handle_interrupt = marvell_handle_interrupt,
.config_intr = m88e1318_config_intr,
.handle_interrupt = m88e1318_handle_interrupt,
.get_wol = m88e1318_get_wol,
.set_wol = m88e1318_set_wol,
.resume = genphy_resume,
@ -3930,8 +3983,8 @@ static struct phy_driver marvell_drivers[] = {
.config_init = m88e1510_config_init,
.config_aneg = m88e1510_config_aneg,
.read_status = marvell_read_status,
.config_intr = marvell_config_intr,
.handle_interrupt = marvell_handle_interrupt,
.config_intr = m88e1318_config_intr,
.handle_interrupt = m88e1318_handle_interrupt,
.get_wol = m88e1318_get_wol,
.set_wol = m88e1318_set_wol,
.resume = m88e1510_resume,

View File

@ -92,6 +92,63 @@ static int qca83xx_probe(struct phy_device *phydev)
return 0;
}
static int qca8337_read_status(struct phy_device *phydev)
{
struct at803x_ss_mask ss_mask = {
.speed_mask = AT803X_SS_SPEED_MASK,
.speed_shift = __bf_shf(AT803X_SS_SPEED_MASK),
};
int ret, old_link = phydev->link;
ret = genphy_read_status(phydev);
if (ret)
return ret;
/* Keep the state resolved at link-up while the link stays up */
if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link)
goto out;
phydev->mdix = ETH_TP_MDI_INVALID;
/* genphy_read_status() derives speed and duplex from the
* advertisements, which is wrong after a SmartSpeed downshift.
* Use what the PHY resolved instead.
*/
if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete &&
phydev->link) {
phydev->speed = SPEED_UNKNOWN;
phydev->duplex = DUPLEX_UNKNOWN;
phydev->pause = false;
phydev->asym_pause = false;
ret = at803x_read_specific_status(phydev, ss_mask);
if (ret)
return ret;
/* Report the link down until speed and duplex are resolved,
* so that the next poll reads them again. Also clear what
* genphy_read_status() read for an up link, as the
* PHY_HALTED path of the state machine does.
*/
if (phydev->speed == SPEED_UNKNOWN ||
phydev->duplex == DUPLEX_UNKNOWN) {
phydev->link = 0;
phydev->duplex = DUPLEX_UNKNOWN;
phydev->mdix = ETH_TP_MDI_INVALID;
phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN;
linkmode_zero(phydev->lp_advertising);
} else {
phy_resolve_aneg_pause(phydev);
}
}
out:
/* MDI-X configuration is not implemented */
phydev->mdix_ctrl = ETH_TP_MDI_INVALID;
return 0;
}
static int qca83xx_config_init(struct phy_device *phydev)
{
u8 switch_revision;
@ -220,6 +277,7 @@ static struct phy_driver qca83xx_driver[] = {
.flags = PHY_IS_INTERNAL,
.config_init = qca83xx_config_init,
.soft_reset = genphy_soft_reset,
.read_status = qca8337_read_status,
.get_sset_count = qca83xx_get_sset_count,
.get_strings = qca83xx_get_strings,
.get_stats = qca83xx_get_stats,

View File

@ -194,18 +194,16 @@ static int __set_item(struct pppoe_net *pn, struct pppox_sock *po)
return 0;
}
static void __delete_item(struct pppoe_net *pn, __be16 sid,
char *addr, int ifindex)
static void __delete_item(struct pppoe_net *pn, const struct pppox_sock *po)
{
int hash = hash_item(sid, addr);
int hash = hash_item(po->pppoe_pa.sid, po->pppoe_pa.remote);
struct pppox_sock *ret, __rcu **src;
ret = rcu_dereference_protected(pn->hash_table[hash], lockdep_is_held(&pn->hash_lock));
src = &pn->hash_table[hash];
while (ret) {
if (cmp_addr(&ret->pppoe_pa, sid, addr) &&
ret->pppoe_ifindex == ifindex) {
if (ret == po) {
struct pppox_sock *next;
next = rcu_dereference_protected(ret->next,
@ -236,11 +234,10 @@ static inline struct pppox_sock *get_item(struct pppoe_net *pn, __be16 sid,
return po;
}
static inline void delete_item(struct pppoe_net *pn, __be16 sid,
char *addr, int ifindex)
static void delete_item(struct pppoe_net *pn, const struct pppox_sock *po)
{
spin_lock(&pn->hash_lock);
__delete_item(pn, sid, addr, ifindex);
__delete_item(pn, po);
spin_unlock(&pn->hash_lock);
}
@ -570,8 +567,7 @@ static int pppoe_release(struct socket *sock)
* protect "po" from concurrent updates
* on pppoe_flush_dev
*/
delete_item(pn, po->pppoe_pa.sid, po->pppoe_pa.remote,
po->pppoe_ifindex);
delete_item(pn, po);
sock_orphan(sk);
sock->sk = NULL;
@ -621,8 +617,7 @@ static int pppoe_connect(struct socket *sock, struct sockaddr_unsized *uservaddr
if (stage_session(po->pppoe_pa.sid)) {
pppox_unbind_sock(sk);
pn = pppoe_pernet(sock_net(sk));
delete_item(pn, po->pppoe_pa.sid,
po->pppoe_pa.remote, po->pppoe_ifindex);
delete_item(pn, po);
if (po->pppoe_dev) {
dev_put(po->pppoe_dev);
po->pppoe_dev = NULL;
@ -672,8 +667,7 @@ static int pppoe_connect(struct socket *sock, struct sockaddr_unsized *uservaddr
error = ppp_register_net_channel(dev_net(dev), &po->chan);
if (error) {
delete_item(pn, po->pppoe_pa.sid,
po->pppoe_pa.remote, po->pppoe_ifindex);
delete_item(pn, po);
goto err_put;
}

View File

@ -1225,6 +1225,17 @@ static int team_port_add(struct team *team, struct net_device *port_dev,
return -EINVAL;
}
if (port_dev->type == ARPHRD_CAN ||
port_dev->type == ARPHRD_IEEE802154 ||
port_dev->type == ARPHRD_IEEE802154_MONITOR ||
port_dev->type == ARPHRD_6LOWPAN) {
NL_SET_ERR_MSG(extack,
"CAN, IEEE 802.15.4 and 6LoWPAN devices can't be added as a team port");
netdev_err(dev, "Device %s is CAN, IEEE 802.15.4 or 6LoWPAN. These device types can't be added as a team port\n",
portname);
return -EINVAL;
}
if (netif_is_team_port(port_dev)) {
NL_SET_ERR_MSG(extack, "Device is already a port of a team device");
netdev_err(dev, "Device %s is already a port "

View File

@ -513,14 +513,18 @@ static u16 tun_select_queue(struct net_device *dev, struct sk_buff *skb,
return ret;
}
static inline bool tun_not_capable(struct tun_struct *tun)
static inline bool tun_permitted(struct tun_struct *tun)
{
const struct cred *cred = current_cred();
struct net *net = dev_net(tun->dev);
return ((uid_valid(tun->owner) && !uid_eq(cred->euid, tun->owner)) ||
(gid_valid(tun->group) && !in_egroup_p(tun->group))) &&
!ns_capable(net->user_ns, CAP_NET_ADMIN);
/* If both uid and gid are set, *both* must match */
if ((uid_valid(tun->owner) || gid_valid(tun->group)) &&
(!uid_valid(tun->owner) || uid_eq(cred->euid, tun->owner)) &&
(!gid_valid(tun->group) || in_egroup_p(tun->group)))
return true;
return ns_capable(net->user_ns, CAP_NET_ADMIN);
}
static void tun_set_real_num_queues(struct tun_struct *tun)
@ -2879,7 +2883,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
!!(tun->flags & IFF_MULTI_QUEUE))
return -EINVAL;
if (tun_not_capable(tun))
if (!tun_permitted(tun))
return -EPERM;
err = security_tun_dev_open(tun->security);
if (err < 0)

View File

@ -617,7 +617,7 @@ static void veth_xdp_flush(struct veth_rq *rq, struct veth_xdp_tx_bq *bq)
rcv_priv = netdev_priv(rcv);
rcv_rq = &rcv_priv->rq[veth_select_rxq(rcv)];
/* xdp_ring is initialized on receive side? */
if (unlikely(!rcu_access_pointer(rcv_rq->xdp_prog)))
if (unlikely(!rcu_access_pointer(rcv_rq->napi)))
goto out;
__veth_xdp_flush(rcv_rq);

View File

@ -443,9 +443,6 @@ struct virtnet_info {
/* Work struct for setting rx mode */
struct work_struct rx_mode_work;
/* OK to queue work setting RX mode? */
bool rx_mode_work_enabled;
/* Does the affinity hint is set for virtqueues? */
bool affinity_hint_set;
@ -712,16 +709,13 @@ static void virtnet_rq_free_buf(struct virtnet_info *vi,
static void enable_rx_mode_work(struct virtnet_info *vi)
{
rtnl_lock();
vi->rx_mode_work_enabled = true;
rtnl_unlock();
if (enable_work(&vi->rx_mode_work) && netif_running(vi->dev))
schedule_work(&vi->rx_mode_work);
}
static void disable_rx_mode_work(struct virtnet_info *vi)
{
rtnl_lock();
vi->rx_mode_work_enabled = false;
rtnl_unlock();
disable_work_sync(&vi->rx_mode_work);
}
static void virtqueue_napi_schedule(struct napi_struct *napi,
@ -908,6 +902,15 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
}
BUG_ON(offset >= PAGE_SIZE);
/* The first frag starts at offset, each next frag is a full page. */
if (unlikely(DIV_ROUND_UP(offset + len, PAGE_SIZE) > MAX_SKB_FRAGS)) {
pr_debug("%s: rx error: len %u needs more than %d frags\n",
vi->dev->name, len, MAX_SKB_FRAGS);
kfree_skb(skb);
return NULL;
}
while (len) {
unsigned int frag_size = min((unsigned)PAGE_SIZE - offset, len);
skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, offset,
@ -3941,8 +3944,7 @@ static void virtnet_set_rx_mode(struct net_device *dev)
{
struct virtnet_info *vi = netdev_priv(dev);
if (vi->rx_mode_work_enabled)
schedule_work(&vi->rx_mode_work);
schedule_work(&vi->rx_mode_work);
}
static int virtnet_vlan_rx_add_vid(struct net_device *dev,
@ -5759,7 +5761,6 @@ static void virtnet_freeze_down(struct virtio_device *vdev)
/* Make sure no work handler is accessing the device */
flush_work(&vi->config_work);
disable_rx_mode_work(vi);
flush_work(&vi->rx_mode_work);
if (netif_running(vi->dev)) {
rtnl_lock();
@ -5789,8 +5790,6 @@ static int virtnet_restore_up(struct virtio_device *vdev)
virtio_device_ready(vdev);
enable_rx_mode_work(vi);
if (netif_running(vi->dev)) {
rtnl_lock();
err = virtnet_open(vi->dev);
@ -5802,6 +5801,8 @@ static int virtnet_restore_up(struct virtio_device *vdev)
netif_tx_lock_bh(vi->dev);
netif_device_attach(vi->dev);
netif_tx_unlock_bh(vi->dev);
enable_rx_mode_work(vi);
return 0;
err_destroy_pools:
@ -6734,7 +6735,8 @@ static void virtnet_set_big_packets(struct virtnet_info *vi, const int mtu)
*/
if (mtu > ETH_DATA_LEN || guest_gso) {
vi->big_packets = true;
vi->big_packets_num_skbfrags = guest_gso ? MAX_SKB_FRAGS : DIV_ROUND_UP(mtu, PAGE_SIZE);
vi->big_packets_num_skbfrags = guest_gso ? MAX_SKB_FRAGS - 1 :
DIV_ROUND_UP(mtu, PAGE_SIZE);
}
}
@ -6897,6 +6899,7 @@ static int virtnet_probe(struct virtio_device *vdev)
INIT_WORK(&vi->config_work, virtnet_config_changed_work);
INIT_WORK(&vi->rx_mode_work, virtnet_rx_mode_work);
disable_work(&vi->rx_mode_work);
if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF)) {
vi->mergeable_rx_bufs = true;
@ -7055,8 +7058,6 @@ static int virtnet_probe(struct virtio_device *vdev)
if (vi->has_rss || vi->has_rss_hash_report)
virtnet_init_default_rss(vi);
enable_rx_mode_work(vi);
for (i = 0; i < ARRAY_SIZE(guest_offloads); i++) {
unsigned int fbit;
@ -7160,6 +7161,8 @@ static int virtnet_probe(struct virtio_device *vdev)
goto free_unregister_netdev;
}
enable_rx_mode_work(vi);
pr_debug("virtnet: registered device %s with %d RX and TX vq's\n",
dev->name, max_queue_pairs);
@ -7212,7 +7215,6 @@ static void virtnet_remove(struct virtio_device *vdev)
/* Make sure no work handler is accessing the device. */
flush_work(&vi->config_work);
disable_rx_mode_work(vi);
flush_work(&vi->rx_mode_work);
virtnet_free_irq_moder(vi);

View File

@ -355,6 +355,7 @@ static const struct ptp_clock_info ptp_qoriq_caps = {
.n_per_out = 0,
.n_pins = 0,
.pps = 1,
.supported_extts_flags = PTP_RISING_EDGE | PTP_STRICT_FLAGS,
.adjfine = ptp_qoriq_adjfine,
.adjtime = ptp_qoriq_adjtime,
.gettime64 = ptp_qoriq_gettime,

View File

@ -2552,6 +2552,11 @@ struct net_device {
/* protected by rtnl_lock */
struct bpf_xdp_entity xdp_state[__MAX_XDP_MODE];
#ifdef CONFIG_XDP_SOCKETS
/** @xsk_pools: assigned AF_XDP pools, ops protected */
struct hlist_head xsk_pools;
#endif
u8 dev_addr_shadow[MAX_ADDR_LEN];
netdevice_tracker linkwatch_dev_tracker;
netdevice_tracker watchdog_dev_tracker;

View File

@ -639,9 +639,9 @@ struct skb_shared_info {
*
* Transport layers send out clones of payload skbs they hold for
* retransmissions. To allow lower layers of the stack to prepend their headers
* we split &skb_shared_info.dataref into two halves.
* The lower 16 bits count the overall number of references.
* The higher 16 bits indicate how many of the references are payload-only.
* we split &skb_shared_info.dataref into two parts.
* The lower 30 bits count the overall number of references.
* Bit 30 indicates whether one of the references is payload-only.
* skb_header_cloned() checks if skb is allowed to add / write the headers.
*
* The creator of the skb (e.g. TCP) marks its skb as &sk_buff.nohdr
@ -661,7 +661,7 @@ struct skb_shared_info {
* Having multiple payload-only skbs with different lengths of hdr_len is not
* possible. The payload-only skbs should never leave their owner.
*/
#define SKB_DATAREF_SHIFT 16
#define SKB_DATAREF_SHIFT 30
#define SKB_DATAREF_MASK ((1 << SKB_DATAREF_SHIFT) - 1)
@ -1042,8 +1042,6 @@ struct sk_buff {
__u16 tc_index; /* traffic control index */
#endif
u16 alloc_cpu;
union {
__wsum csum;
struct {
@ -1094,6 +1092,8 @@ struct sk_buff {
); /* end headers group */
u16 alloc_cpu;
/* These elements must be at the end, see alloc_skb() for details. */
sk_buff_data_t tail;
sk_buff_data_t end;

View File

@ -81,6 +81,9 @@ struct ifa6_config {
u8 ifa_proto;
const struct in6_addr *peer_pfx;
struct inet6_ifaddr *ifpub;
unsigned long cstamp;
unsigned long tstamp;
u32 rt_priority;
u32 ifa_flags;

View File

@ -36,9 +36,6 @@
#define IP_VS_HDR_INVERSE 1
#define IP_VS_HDR_ICMP 2
/* Destination Server Flags */
#define IP_VS_DEST_F_OVERLOAD 0x0002 /* server is overloaded */
/* Destination Server Config Flags */
#define IP_VS_DEST_CF_AVAILABLE 0x0001 /* server is available */
@ -973,33 +970,44 @@ struct ip_vs_dest_dst {
* and so on.
*/
struct ip_vs_dest {
/* Cacheline for hash table nodes - read-mostly */
struct list_head n_list; /* for the dests in the service */
struct hlist_node d_list; /* for table with all the dests */
u16 af; /* address family */
__be16 port; /* port number of the server */
union nf_inet_addr addr; /* IP address of the server */
volatile unsigned int flags; /* dest status flags */
atomic_t conn_flags; /* flags to copy to conn */
atomic_t weight; /* server weight */
unsigned long cflags; /* config flags */
atomic_t last_weight; /* server latest weight */
/* connection thresholds */
u32 l_threshold_val;/* used lower threshold */
u32 u_threshold_val;/* used upper threshold */
/* 32/48 */
u32 l_threshold; /* lower threshold */
u32 u_threshold; /* upper threshold */
unsigned long cflags; /* config flags */
/* 44/64 */
atomic_t conn_flags; /* flags to copy to conn */
__u16 tun_type; /* tunnel type */
__be16 tun_port; /* tunnel port */
__u16 tun_flags; /* tunnel flags */
u16 af; /* address family */
__be16 port; /* port number of the server */
/* 60/80 */
union nf_inet_addr addr; /* IP address of the server */
/* connection counters */
atomic_t totalconns; /* total connections */
atomic_t activeconns; /* active connections */
atomic_t persistconns; /* persistent connections */
refcount_t refcnt; /* reference counter */
struct ip_vs_stats stats; /* statistics */
unsigned long idle_start; /* start time, jiffies */
/* connection counters and thresholds */
atomic_t activeconns; /* active connections */
atomic_t totalconns; /* total connections */
atomic_t persistconns; /* persistent connections */
__u32 u_threshold; /* upper threshold */
__u32 l_threshold; /* lower threshold */
__u32 l_threshold_val;/* used lower threshold */
/* for destination cache */
spinlock_t dst_lock; /* lock of dst_cache */
struct ip_vs_dest_dst __rcu *dest_dst; /* cached dst info */
@ -1915,7 +1923,13 @@ static inline void ip_vs_dest_put_and_free(struct ip_vs_dest *dest)
kfree(dest);
}
void ip_vs_dest_update_overload(struct ip_vs_dest *dest, int mode);
void ip_vs_dest_update_overload(struct ip_vs_dest *dest, bool overload);
/* Check if dest is in overloaded state */
static inline bool ip_vs_dest_is_overloaded(const struct ip_vs_dest *dest)
{
return READ_ONCE(dest->l_threshold_val);
}
/* IPVS sync daemon data and function prototypes
* (from ip_vs_sync.c)

View File

@ -219,6 +219,9 @@ int mptcp_subflow_init_cookie_req(struct request_sock *req,
struct request_sock *mptcp_subflow_reqsk_alloc(const struct request_sock_ops *ops,
struct sock *sk_listener,
bool attach_listener);
/* Caller must hold an RCU read-side lock. */
void mptcp_subflow_reqsk_clone(struct request_sock *req,
struct request_sock *new_req);
__be32 mptcp_get_reset_option(const struct sk_buff *skb);
@ -305,6 +308,12 @@ static inline struct request_sock *mptcp_subflow_reqsk_alloc(const struct reques
return NULL;
}
/* Caller must hold an RCU read-side lock. */
static inline void mptcp_subflow_reqsk_clone(struct request_sock *req,
struct request_sock *new_req)
{
}
static inline __be32 mptcp_reset_option(const struct sk_buff *skb) { return htonl(0u); }
static inline void mptcp_active_detect_blackhole(struct sock *sk, bool expired) { }

View File

@ -252,6 +252,7 @@ struct sctp_chunk *sctp_make_fwdtsn(const struct sctp_association *asoc,
struct sctp_fwdtsn_skip *skiplist);
struct sctp_chunk *sctp_make_auth(const struct sctp_association *asoc,
__u16 key_id);
void sctp_control_set_owner_w(struct sctp_chunk *chunk);
struct sctp_chunk *sctp_make_strreset_req(const struct sctp_association *asoc,
__u16 stream_num, __be16 *stream_list,
bool out, bool in);

View File

@ -48,6 +48,8 @@ struct xsk_buff_pool {
struct device *dev;
struct net_device *netdev;
struct list_head xsk_tx_list;
/* Assigned pools, including deferred releases; ops protected. */
struct hlist_node dev_node;
/* Protects modifications to the xsk_tx_list */
spinlock_t xsk_tx_list_lock;
refcount_t users;
@ -119,6 +121,7 @@ bool xp_put_pool(struct xsk_buff_pool *pool);
void xp_clear_dev(struct xsk_buff_pool *pool);
void xp_add_xsk(struct xsk_buff_pool *pool, struct xdp_sock *xs);
void xp_del_xsk(struct xsk_buff_pool *pool, struct xdp_sock *xs);
void xp_clear_dev_all(struct net_device *dev);
/* AF_XDP, and XDP core. */
void xp_free(struct xdp_buff_xsk *xskb);

View File

@ -110,6 +110,8 @@ static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb,
unsigned int len;
int ret;
len = skb->len;
/* Handle non-VLAN frames if they are sent to us, for example by DHCP.
*
* NOTE: THIS ASSUMES DIX ETHERNET, SPECIFICALLY NOT SUPPORTING
@ -121,10 +123,39 @@ static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb,
vlan_tci = vlan->vlan_id;
vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb->priority);
__vlan_hwaccel_put_tag(skb, vlan->vlan_proto, vlan_tci);
} else if (skb_headlen(skb) >= VLAN_ETH_HLEN + sizeof(__be16) &&
!skb_shared(skb) && !skb_vlan_tag_present(skb) &&
!skb_metadata_len(skb) &&
(skb->ip_summed != CHECKSUM_PARTIAL ||
skb_checksum_start_offset(skb) >= VLAN_ETH_HLEN) &&
vlan_hw_offload_capable(READ_ONCE(vlan->real_dev->features),
vlan->vlan_proto)) {
u16 vlan_tci;
/* The frame carries its outer tag in-band, either inserted
* by vlan_dev_hard_header() or provided by the sender.
* Let the real device insert it: some NICs can not offload
* checksum or TSO for frames carrying an in-band tag.
* Not all ndo_start_xmit() callers set the mac header.
* vlan_set_encap_proto() may read two bytes after the vlan
* header, so frames with a shorter linear part are sent
* unchanged, as are shared skbs (e.g. from pktgen), skbs
* already carrying a hwaccel tag (e.g. from generic XDP
* redirect), skbs carrying XDP metadata, and CHECKSUM_PARTIAL
* skbs whose checksum starts within the header to be popped.
* On allocation failure, drop the frame rather than handing
* it to the real device with an in-band tag.
*/
skb_reset_mac_header(skb);
if (unlikely(__skb_vlan_pop(skb, &vlan_tci))) {
dev_kfree_skb_any(skb);
this_cpu_inc(vlan->vlan_pcpu_stats->tx_dropped);
return NETDEV_TX_OK;
}
__vlan_hwaccel_put_tag(skb, vlan->vlan_proto, vlan_tci);
}
skb->dev = vlan->real_dev;
len = skb->len;
if (unlikely(netpoll_tx_running(dev)))
return vlan_netpoll_send_skb(vlan, skb);

View File

@ -819,6 +819,7 @@ static int br_mdb_add_group_src_fwd(const struct br_mdb_config *cfg,
struct br_mdb_config sg_cfg;
struct br_ip sg_ip;
u8 flags = 0;
int err;
sg_ip = cfg->group;
sg_ip.src = src_ip->src;
@ -842,7 +843,11 @@ static int br_mdb_add_group_src_fwd(const struct br_mdb_config *cfg,
sg_cfg.filter_mode = MCAST_INCLUDE;
sg_cfg.rt_protocol = cfg->rt_protocol;
sg_cfg.nlflags = cfg->nlflags;
return br_mdb_add_group_sg(&sg_cfg, sgmp, brmctx, flags, extack);
err = br_mdb_add_group_sg(&sg_cfg, sgmp, brmctx, flags, extack);
if (err)
br_multicast_del_group(sgmp);
return err;
}
static int br_mdb_add_group_src(const struct br_mdb_config *cfg,
@ -1047,6 +1052,7 @@ static int br_mdb_add_group(const struct br_mdb_config *cfg,
struct net_bridge_mcast *brmctx;
struct br_ip group = cfg->group;
unsigned char flags = 0;
int err;
brmctx = __br_mdb_choose_context(br, entry, extack);
if (!brmctx)
@ -1073,9 +1079,13 @@ static int br_mdb_add_group(const struct br_mdb_config *cfg,
flags |= MDB_PG_FLAGS_PERMANENT;
if (br_multicast_is_star_g(&group))
return br_mdb_add_group_star_g(cfg, mp, brmctx, flags, extack);
err = br_mdb_add_group_star_g(cfg, mp, brmctx, flags, extack);
else
return br_mdb_add_group_sg(cfg, mp, brmctx, flags, extack);
err = br_mdb_add_group_sg(cfg, mp, brmctx, flags, extack);
if (err)
br_multicast_del_group(mp);
return err;
}
static int __br_mdb_add(const struct br_mdb_config *cfg,

View File

@ -647,6 +647,14 @@ static void br_multicast_del_mdb_entry(struct net_bridge_mdb_entry *mp)
queue_work(system_long_wq, &br->mcast_gc_work);
}
void br_multicast_del_group(struct net_bridge_mdb_entry *mp)
{
if (mp->ports || mp->host_joined)
return;
br_multicast_del_mdb_entry(mp);
}
static void br_multicast_group_expired(struct timer_list *t)
{
struct net_bridge_mdb_entry *mp = timer_container_of(mp, t, timer);
@ -1554,6 +1562,7 @@ __br_multicast_add_group(struct net_bridge_mcast *brmctx,
p = br_multicast_new_port_group(pmctx->port, group, *pp, 0, src,
filter_mode, RTPROT_KERNEL, NULL);
if (unlikely(!p)) {
br_multicast_del_group(mp);
p = ERR_PTR(-ENOMEM);
goto out;
}

View File

@ -1143,6 +1143,7 @@ struct net_bridge_mdb_entry *
br_mdb_ip_get(struct net_bridge *br, struct br_ip *dst);
struct net_bridge_mdb_entry *
br_multicast_new_group(struct net_bridge *br, struct br_ip *group);
void br_multicast_del_group(struct net_bridge_mdb_entry *mp);
struct net_bridge_port_group *
br_multicast_new_port_group(struct net_bridge_port *port,
const struct br_ip *group,

View File

@ -187,6 +187,10 @@ int skb_gro_receive(struct sk_buff *p, struct sk_buff *skb)
}
merge:
/* skb_segment() cannot split the linear part of a frag_list member. */
if (unlikely(headlen > offset + skb_shinfo(p)->gso_size))
return -E2BIG;
/* sk ownership - if any - completely transferred to the aggregated packet */
skb->destructor = NULL;
skb->sk = NULL;

View File

@ -1584,7 +1584,6 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
#ifdef CONFIG_NET_RX_BUSY_POLL
CHECK_SKB_FIELD(napi_id);
#endif
CHECK_SKB_FIELD(alloc_cpu);
#ifdef CONFIG_XPS
CHECK_SKB_FIELD(sender_cpu);
#endif
@ -1616,6 +1615,7 @@ static struct sk_buff *__skb_clone(struct sk_buff *n, struct sk_buff *skb)
C(pfmemalloc);
C(pp_recycle);
n->destructor = NULL;
C(alloc_cpu);
C(tail);
C(end);
C(head);

View File

@ -770,6 +770,7 @@ bool sk_mc_loop(const struct sock *sk)
{
if (dev_recursion_level())
return false;
sk = sk_const_to_full_sk(sk);
if (!sk)
return true;

View File

@ -2369,8 +2369,8 @@ static int inet_netconf_get_devconf(struct sk_buff *in_skb,
struct net *net = sock_net(in_skb->sk);
struct nlattr *tb[NETCONFA_MAX + 1];
const struct ipv4_devconf *devconf;
struct in_device *in_dev = NULL;
struct net_device *dev = NULL;
struct in_device *in_dev;
struct net_device *dev;
struct sk_buff *skb;
int ifindex;
int err;
@ -2382,7 +2382,13 @@ static int inet_netconf_get_devconf(struct sk_buff *in_skb,
if (!tb[NETCONFA_IFINDEX])
return -EINVAL;
skb = nlmsg_new(inet_netconf_msgsize_devconf(NETCONFA_ALL), GFP_KERNEL);
if (!skb)
return -ENOBUFS;
ifindex = nla_get_s32(tb[NETCONFA_IFINDEX]);
rcu_read_lock();
switch (ifindex) {
case NETCONFA_IFINDEX_ALL:
devconf = net->ipv4.devconf_all;
@ -2392,36 +2398,29 @@ static int inet_netconf_get_devconf(struct sk_buff *in_skb,
break;
default:
err = -ENODEV;
dev = dev_get_by_index(net, ifindex);
if (dev)
in_dev = in_dev_get(dev);
dev = dev_get_by_index_rcu(net, ifindex);
if (!dev)
goto out_unlock;
in_dev = __in_dev_get_rcu(dev);
if (!in_dev)
goto errout;
goto out_unlock;
devconf = &in_dev->cnf;
break;
}
err = -ENOBUFS;
skb = nlmsg_new(inet_netconf_msgsize_devconf(NETCONFA_ALL), GFP_KERNEL);
if (!skb)
goto errout;
err = inet_netconf_fill_devconf(skb, ifindex, devconf,
NETLINK_CB(in_skb).portid,
nlh->nlmsg_seq, RTM_NEWNETCONF, 0,
NETCONFA_ALL);
out_unlock:
rcu_read_unlock();
if (err < 0) {
/* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
WARN_ON(err == -EMSGSIZE);
kfree_skb(skb);
goto errout;
return err;
}
err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
errout:
if (in_dev)
in_dev_put(in_dev);
dev_put(dev);
return err;
return rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
}
static int inet_netconf_dump_devconf(struct sk_buff *skb,

View File

@ -242,7 +242,7 @@ static int gre_gro_complete(struct sk_buff *skb, int nhoff)
__be16 type;
skb->encapsulation = 1;
skb_shinfo(skb)->gso_type = SKB_GSO_GRE;
skb_shinfo(skb)->gso_type |= SKB_GSO_GRE;
type = greh->protocol;
if (greh->flags & GRE_KEY)

View File

@ -21,6 +21,7 @@
#include <net/xfrm.h>
#include <net/tcp.h>
#include <net/tcp_ecn.h>
#include <net/mptcp.h>
#include <net/sock_reuseport.h>
#include <net/addrconf.h>
@ -961,6 +962,9 @@ static struct request_sock *inet_reqsk_clone(struct request_sock *req,
rcu_assign_pointer(tcp_sk(nreq->sk)->fastopen_rsk, nreq);
}
if (rsk_is_mptcp(req))
mptcp_subflow_reqsk_clone(req, nreq);
return nreq;
}

View File

@ -1367,6 +1367,7 @@ static int erspan_tunnel_init(struct net_device *dev)
dev->features |= GRE_FEATURES;
dev->hw_features |= GRE_FEATURES;
dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
dev->lltx = true;
netif_keep_dst(dev);
return ip_tunnel_init(dev);

View File

@ -357,6 +357,11 @@ void nf_send_unreach(struct sk_buff *skb_in, int code, int hook)
if (!skb_valid_dst(skb_in) && nf_reject_fill_skb_dst(skb_in) < 0)
return;
if (hook == NF_INET_INGRESS) {
memset(IPCB(skb_in), 0, sizeof(*IPCB(skb_in)));
IPCB(skb_in)->iif = skb_in->skb_iif;
}
if (skb_csum_unnecessary(skb_in) ||
!nf_reject_verify_csum(skb_in, dataoff, proto)) {
icmp_send(skb_in, ICMP_DEST_UNREACH, code, 0);

View File

@ -404,12 +404,12 @@ static struct request_sock *cookie_tcp_check(struct net *net, struct sock *sk,
*/
struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb)
{
struct ip_options *opt = &TCP_SKB_CB(skb)->header.h4.opt;
const struct tcphdr *th = tcp_hdr(skb);
struct tcp_sock *tp = tcp_sk(sk);
struct inet_request_sock *ireq;
struct net *net = sock_net(sk);
struct tcp_request_sock *treq;
struct ip_options_rcu *opt;
struct request_sock *req;
struct sock *ret = sk;
struct flowi4 fl4;
@ -449,6 +449,8 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb)
SKB_DR_SET(reason, SECURITY_HOOK);
goto out_free;
}
/* Load ireq->ireq_opt after the LSM hook, which can replace it. */
opt = rcu_dereference_protected(ireq->ireq_opt, true);
tcp_ao_syncookie(sk, skb, req, AF_INET);
@ -461,7 +463,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb)
flowi4_init_output(&fl4, ireq->ir_iif, ireq->ir_mark,
ip_sock_rt_tos(sk), ip_sock_rt_scope(sk),
IPPROTO_TCP, inet_sk_flowi_flags(sk),
opt->srr ? opt->faddr : ireq->ir_rmt_addr,
(opt && opt->opt.srr) ? opt->opt.faddr : ireq->ir_rmt_addr,
ireq->ir_loc_addr, th->source, th->dest,
sk_uid(sk));
security_req_classify_flow(req, flowi4_to_flowi_common(&fl4));
@ -470,6 +472,12 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb)
SKB_DR_SET(reason, IP_OUTNOROUTES);
goto out_free;
}
/* Same check as in inet_csk_route_req(). */
if (opt && opt->opt.is_strictroute && rt->rt_uses_gateway) {
ip_rt_put(rt);
SKB_DR_SET(reason, IP_OUTNOROUTES);
goto out_free;
}
/* Try to redo what tcp_v4_send_synack did. */
req->rsk_window_clamp = READ_ONCE(tp->window_clamp) ? :

View File

@ -579,6 +579,7 @@ static int tcp_bpf_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
copy);
if (ret < 0) {
sk_msg_trim(sk, msg_tx, osize);
err = ret;
goto out_err;
}

View File

@ -161,16 +161,26 @@ static void tcpm_check_stamp(struct tcp_metrics_block *tm,
rcu_dereference_protected(p, lockdep_is_held(&tcp_metrics_lock))
static struct tcp_metrics_block *tcpm_new(struct dst_entry *dst,
struct net *net,
struct inetpeer_addr *saddr,
struct inetpeer_addr *daddr,
unsigned int hash)
{
struct tcp_metrics_block *tm;
bool reclaim = false;
struct net *net;
spin_lock_bh(&tcp_metrics_lock);
net = dst_dev_net_rcu(dst);
/* Do not add entries to a dismantling netns: they would not be
* flushed again. Callers are in an RCU read-side section, and
* cleanup_net() waits for a grace period after the netns refcount
* reached zero and before tcp_metrics_flush_all(NULL) runs, so an
* entry added after a successful check_net() is seen by the flush.
*/
if (unlikely(!check_net(net))) {
tm = NULL;
goto out_unlock;
}
/* While waiting for the spin-lock the cache might have been populated
* with this entry and so we have to check again.
@ -273,7 +283,7 @@ static struct tcp_metrics_block *__tcp_get_metrics_req(struct request_sock *req,
return NULL;
}
net = dst_dev_net_rcu(dst);
net = sock_net(req_to_sk(req));
hash ^= net_hash_mix(net);
hash = hash_32(hash, tcp_metrics_hash_log);
@ -318,7 +328,7 @@ static struct tcp_metrics_block *tcp_get_metrics(struct sock *sk,
else
return NULL;
net = dst_dev_net_rcu(dst);
net = sock_net(sk);
hash ^= net_hash_mix(net);
hash = hash_32(hash, tcp_metrics_hash_log);
@ -326,7 +336,7 @@ static struct tcp_metrics_block *tcp_get_metrics(struct sock *sk,
if (tm == TCP_METRICS_RECLAIM_PTR)
tm = NULL;
if (!tm && create)
tm = tcpm_new(dst, &saddr, &daddr, hash);
tm = tcpm_new(dst, net, &saddr, &daddr, hash);
else
tcpm_check_stamp(tm, dst);

View File

@ -1158,10 +1158,19 @@ ipv6_add_addr(struct inet6_dev *idev, struct ifa6_config *cfg,
ifa->flags |= IFA_F_TENTATIVE;
ifa->valid_lft = cfg->valid_lft;
ifa->prefered_lft = cfg->preferred_lft;
ifa->cstamp = ifa->tstamp = jiffies;
ifa->tokenized = false;
ifa->rt = f6i;
ifa->ifpub = cfg->ifpub;
if (cfg->ifpub) {
ifa->cstamp = cfg->cstamp;
ifa->tstamp = cfg->tstamp;
} else {
unsigned long now = jiffies;
ifa->cstamp = now;
ifa->tstamp = now;
}
ifa->idev = idev;
in6_dev_hold(idev);
@ -1171,14 +1180,18 @@ ipv6_add_addr(struct inet6_dev *idev, struct ifa6_config *cfg,
rcu_read_lock();
err = ipv6_add_addr_hash(idev->dev, ifa);
write_lock_bh(&idev->lock);
if (idev->dead)
err = -ENODEV;
else
err = ipv6_add_addr_hash(idev->dev, ifa);
if (err < 0) {
write_unlock_bh(&idev->lock);
rcu_read_unlock();
goto out;
}
write_lock_bh(&idev->lock);
/* Add to inet6_dev unicast addr list. */
ipv6_link_dev_addr(idev, ifa);
@ -1490,6 +1503,9 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, bool block)
cfg.pfx = &addr;
cfg.scope = ipv6_addr_scope(cfg.pfx);
cfg.ifpub = ifp;
cfg.cstamp = now;
cfg.tstamp = tmp_tstamp;
ift = ipv6_add_addr(idev, &cfg, block, NULL);
if (IS_ERR(ift)) {
@ -1500,12 +1516,6 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, bool block)
goto retry;
}
spin_lock_bh(&ift->lock);
ift->ifpub = ifp;
ift->cstamp = now;
ift->tstamp = tmp_tstamp;
spin_unlock_bh(&ift->lock);
addrconf_dad_start(ift);
in6_ifa_put(ift);
in6_dev_put(idev);
@ -2191,6 +2201,7 @@ void addrconf_dad_failure(struct sk_buff *skb, struct inet6_ifaddr *ifp)
ifp->idev->dev->name, &ifp->addr, eth_hdr(skb)->h_source);
if (ifp->flags & IFA_F_STABLE_PRIVACY) {
bool start_dad = false;
struct in6_addr new_addr;
struct inet6_ifaddr *ifp2;
int retries = ifp->stable_privacy_retry + 1;
@ -2229,11 +2240,14 @@ void addrconf_dad_failure(struct sk_buff *skb, struct inet6_ifaddr *ifp)
goto lock_errdad;
spin_lock_bh(&ifp2->lock);
ifp2->stable_privacy_retry = retries;
ifp2->state = INET6_IFADDR_STATE_PREDAD;
if (ifp2->state != INET6_IFADDR_STATE_DEAD) {
ifp2->stable_privacy_retry = retries;
start_dad = true;
}
spin_unlock_bh(&ifp2->lock);
addrconf_mod_dad_work(ifp2, net->ipv6.sysctl.idgen_delay);
if (start_dad)
addrconf_mod_dad_work(ifp2, net->ipv6.sysctl.idgen_delay);
in6_ifa_put(ifp2);
lock_errdad:
spin_lock_bh(&ifp->lock);
@ -3900,7 +3914,9 @@ static int addrconf_ifdown(struct net_device *dev, bool unregister)
* Do not dev_put!
*/
if (unregister) {
write_lock_bh(&idev->lock);
WRITE_ONCE(idev->dead, 1);
write_unlock_bh(&idev->lock);
/* protected by rtnl_lock */
RCU_INIT_POINTER(dev->ip6_ptr, NULL);
@ -4022,6 +4038,10 @@ static int addrconf_ifdown(struct net_device *dev, bool unregister)
}
if (!keep) {
spin_lock_bh(&net->ipv6.addrconf_hash_lock);
hlist_del_init_rcu(&ifa->addr_lst);
spin_unlock_bh(&net->ipv6.addrconf_hash_lock);
write_lock_bh(&idev->lock);
list_del_rcu(&ifa->if_list);
write_unlock_bh(&idev->lock);

View File

@ -1428,6 +1428,10 @@ static int calipso_skbuff_delattr(struct sk_buff *skb)
skb_pull(skb, delta);
memmove((char *)ip6_hdr + delta, ip6_hdr, size);
skb_reset_network_header(skb);
ip6_hdr = ipv6_hdr(skb);
/* BIG TCP packets have payload_len == 0 */
if (ip6_hdr->payload_len)
be16_add_cpu(&ip6_hdr->payload_len, -delta);
}
return 0;

View File

@ -1889,6 +1889,7 @@ static int ip6erspan_tap_init(struct net_device *dev)
dev->mtu -= 8;
dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
dev->lltx = true;
ip6erspan_tnl_link_config(tunnel, 1);
netdev_hold(dev, &tunnel->dev_tracker, GFP_KERNEL);

View File

@ -398,7 +398,7 @@ find_prev_fhdr(struct sk_buff *skb, u8 *prevhdrp, int *prevhoff, int *fhoff)
{
u8 nexthdr = ipv6_hdr(skb)->nexthdr;
const int netoff = skb_network_offset(skb);
u8 prev_nhoff = netoff + offsetof(struct ipv6hdr, nexthdr);
int prev_nhoff = netoff + offsetof(struct ipv6hdr, nexthdr);
int start = netoff + sizeof(struct ipv6hdr);
int len = skb->len - start;
u8 prevhdr = NEXTHDR_IPV6;

View File

@ -444,6 +444,11 @@ void nf_send_unreach6(struct net *net, struct sk_buff *skb_in,
if (hooknum == NF_INET_LOCAL_OUT && skb_in->dev == NULL)
skb_in->dev = net->loopback_dev;
if (hooknum == NF_INET_INGRESS) {
memset(IP6CB(skb_in), 0, sizeof(*IP6CB(skb_in)));
IP6CB(skb_in)->iif = skb_in->skb_iif;
}
if (!skb_valid_dst(skb_in) && nf_reject6_fill_skb_dst(skb_in) < 0)
return;

View File

@ -232,6 +232,7 @@ static int ip6_frag_queue(struct net *net,
}
skb_dst_drop(skb);
skb_orphan(skb);
return -EINPROGRESS;
insert_error:

View File

@ -1511,6 +1511,15 @@ static struct rt6_info *rt6_make_pcpu_route(struct net *net,
*/
static DEFINE_SPINLOCK(rt6_exception_lock);
/* Exceptions are accounted to the netns their dst was allocated in.
* Unlike dev_net(dst->dev), it does not change when the device moves to
* another netns or when dst_dev_put() points the dst to blackhole_netdev.
*/
static struct net *rt6_exception_net(const struct rt6_info *rt)
{
return container_of(rt->dst.ops, struct net, ipv6.ip6_dst_ops);
}
/* Remove rt6_ex from hash table and free the memory
* Caller must hold rt6_exception_lock
*/
@ -1522,7 +1531,7 @@ static void rt6_remove_exception(struct rt6_exception_bucket *bucket,
if (!bucket || !rt6_ex)
return;
net = dev_net(rt6_ex->rt6i->dst.dev);
net = rt6_exception_net(rt6_ex->rt6i);
net->ipv6.rt6_stats->fib_rt_cache--;
/* purge completely the exception to allow releasing the held resources:
@ -1750,7 +1759,7 @@ static int rt6_insert_exception(struct rt6_info *nrt,
rt6_ex->stamp = jiffies;
hlist_add_head_rcu(&rt6_ex->hlist, &bucket->chain);
bucket->depth++;
net->ipv6.rt6_stats->fib_rt_cache++;
rt6_exception_net(nrt)->ipv6.rt6_stats->fib_rt_cache++;
/* Randomize max depth to avoid some side channels attacks. */
max_depth = FIB6_MAX_DEPTH + get_random_u32_below(FIB6_MAX_DEPTH);
@ -6468,7 +6477,9 @@ void fib6_info_hw_flags_set(struct net *net, struct fib6_info *f6i,
if (!fib_notify_on_flag_change)
return;
skb = nlmsg_new(rt6_nlmsg_size(f6i), GFP_KERNEL);
rcu_read_lock();
skb = nlmsg_new(rt6_nlmsg_size(f6i), GFP_ATOMIC);
if (!skb) {
err = -ENOBUFS;
goto errout;
@ -6481,10 +6492,13 @@ void fib6_info_hw_flags_set(struct net *net, struct fib6_info *f6i,
goto errout;
}
rcu_read_unlock();
rtnl_notify(skb, net, 0, RTNLGRP_IPV6_ROUTE, NULL, GFP_KERNEL);
return;
errout:
rcu_read_unlock();
rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
}
EXPORT_SYMBOL(fib6_info_hw_flags_set);

View File

@ -915,11 +915,9 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb,
* check if we sre sending sequence numbers and if not,
* configure it so.
*/
if (!session->lns_mode && !session->send_seq) {
if (!session->lns_mode && !READ_ONCE(session->send_seq)) {
trace_session_seqnum_lns_enable(session);
session->send_seq = 1;
l2tp_session_set_header_len(session, tunnel->version,
tunnel->encap);
WRITE_ONCE(session->send_seq, true);
}
} else {
/* No sequence numbers.
@ -937,12 +935,10 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb,
* If we're the LNS and we're sending sequence numbers, the
* LAC is broken. Discard the frame.
*/
if (!session->lns_mode && session->send_seq) {
if (!session->lns_mode && READ_ONCE(session->send_seq)) {
trace_session_seqnum_lns_disable(session);
session->send_seq = 0;
l2tp_session_set_header_len(session, tunnel->version,
tunnel->encap);
} else if (session->send_seq) {
WRITE_ONCE(session->send_seq, false);
} else if (READ_ONCE(session->send_seq)) {
pr_debug_ratelimited("%s: recv data has no seq numbers when required. Discarding.\n",
session->name);
atomic_long_inc(&session->stats.rx_seq_discards);
@ -1138,7 +1134,8 @@ static void l2tp_udp_encap_err_recv(struct sock *sk, struct sk_buff *skb, int er
/* Build an L2TP header for the session into the buffer provided.
*/
static int l2tp_build_l2tpv2_header(struct l2tp_session *session, void *buf)
static int l2tp_build_l2tpv2_header(struct l2tp_session *session, void *buf,
bool send_seq)
{
struct l2tp_tunnel *tunnel = session->tunnel;
__be16 *bufp = buf;
@ -1147,14 +1144,14 @@ static int l2tp_build_l2tpv2_header(struct l2tp_session *session, void *buf)
u32 tunnel_id = tunnel->peer_tunnel_id;
u32 session_id = session->peer_session_id;
if (session->send_seq)
if (send_seq)
flags |= L2TP_HDRFLAG_S;
/* Setup L2TP header. */
*bufp++ = htons(flags);
*bufp++ = htons(tunnel_id);
*bufp++ = htons(session_id);
if (session->send_seq) {
if (send_seq) {
*bufp++ = htons(session->ns);
*bufp++ = 0;
session->ns++;
@ -1165,7 +1162,8 @@ static int l2tp_build_l2tpv2_header(struct l2tp_session *session, void *buf)
return bufp - optr;
}
static int l2tp_build_l2tpv3_header(struct l2tp_session *session, void *buf)
static int l2tp_build_l2tpv3_header(struct l2tp_session *session, void *buf,
bool send_seq)
{
struct l2tp_tunnel *tunnel = session->tunnel;
char *bufp = buf;
@ -1191,7 +1189,7 @@ static int l2tp_build_l2tpv3_header(struct l2tp_session *session, void *buf)
if (session->l2specific_type == L2TP_L2SPECTYPE_DEFAULT) {
u32 l2h = 0;
if (session->send_seq) {
if (send_seq) {
l2h = 0x40000000 | session->ns;
session->ns++;
session->ns &= 0xffffff;
@ -1225,19 +1223,24 @@ static int l2tp_xmit_queue(struct l2tp_tunnel *tunnel, struct sk_buff *skb, stru
static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, unsigned int *len)
{
struct l2tp_tunnel *tunnel = session->tunnel;
bool send_seq = READ_ONCE(session->send_seq);
unsigned int data_len = skb->len;
struct sock *sk = tunnel->sock;
u16 hdr_len = session->hdr_len;
int headroom, uhlen, udp_len;
int ret = NET_XMIT_SUCCESS;
struct inet_sock *inet;
struct udphdr *uh;
if (tunnel->version == L2TP_HDR_VER_2 && !send_seq)
hdr_len -= 4;
/* Check that there's enough headroom in the skb to insert IP,
* UDP and L2TP headers. If not enough, expand it to
* make room. Adjust truesize.
*/
uhlen = (tunnel->encap == L2TP_ENCAPTYPE_UDP) ? sizeof(*uh) : 0;
headroom = NET_SKB_PAD + sizeof(struct iphdr) + uhlen + session->hdr_len;
headroom = NET_SKB_PAD + sizeof(struct iphdr) + uhlen + hdr_len;
if (skb_cow_head(skb, headroom)) {
kfree_skb(skb);
return NET_XMIT_DROP;
@ -1245,9 +1248,9 @@ static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, uns
/* Setup L2TP header */
if (tunnel->version == L2TP_HDR_VER_2)
l2tp_build_l2tpv2_header(session, __skb_push(skb, session->hdr_len));
l2tp_build_l2tpv2_header(session, __skb_push(skb, hdr_len), send_seq);
else
l2tp_build_l2tpv3_header(session, __skb_push(skb, session->hdr_len));
l2tp_build_l2tpv3_header(session, __skb_push(skb, hdr_len), send_seq);
/* Reset control buffer */
memset(skb->cb, 0, sizeof(skb->cb));
@ -1290,7 +1293,7 @@ static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, uns
uh = udp_hdr(skb);
uh->source = inet->inet_sport;
uh->dest = inet->inet_dport;
udp_len = uhlen + session->hdr_len + data_len;
udp_len = uhlen + hdr_len + data_len;
if (udp_len > U16_MAX) {
kfree_skb(skb);
ret = NET_XMIT_DROP;
@ -1759,16 +1762,11 @@ static void l2tp_session_del_work(struct work_struct *work)
l2tp_session_put(session);
}
/* We come here whenever a session's send_seq, cookie_len or
* l2specific_type parameters are set.
*/
void l2tp_session_set_header_len(struct l2tp_session *session, int version,
enum l2tp_encap_type encap)
static void l2tp_session_set_header_len(struct l2tp_session *session, int version,
enum l2tp_encap_type encap)
{
if (version == L2TP_HDR_VER_2) {
session->hdr_len = 6;
if (session->send_seq)
session->hdr_len += 4;
session->hdr_len = 10;
} else {
session->hdr_len = 4 + session->cookie_len;
session->hdr_len += l2tp_get_l2specific_len(session);
@ -1776,7 +1774,6 @@ void l2tp_session_set_header_len(struct l2tp_session *session, int version,
session->hdr_len += 4;
}
}
EXPORT_SYMBOL_GPL(l2tp_session_set_header_len);
struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id,
u32 peer_session_id, struct l2tp_session_cfg *cfg)

View File

@ -76,7 +76,7 @@ struct l2tp_session {
u8 peer_cookie[8];
int peer_cookie_len;
u16 l2specific_type;
u16 hdr_len;
u16 hdr_len; /* maximum L2TP header length */
u32 nr; /* session NR state (receive) */
u32 ns; /* session NR state (send) */
struct sk_buff_head reorder_q; /* receive reorder queue */
@ -94,8 +94,8 @@ struct l2tp_session {
char name[L2TP_SESSION_NAME_MAX]; /* for logging */
char ifname[IFNAMSIZ];
bool send_seq; /* send packets with sequence numbers? */
unsigned int recv_seq:1; /* expect receive packets with sequence numbers? */
unsigned int send_seq:1; /* send packets with sequence numbers? */
unsigned int lns_mode:1; /* behave as LNS?
* LAC enables sequence numbers under LNS control.
*/
@ -257,8 +257,6 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb,
int l2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb);
/* Transmit path helpers for sending packets over the tunnel socket. */
void l2tp_session_set_header_len(struct l2tp_session *session, int version,
enum l2tp_encap_type encap);
int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb);
/* Pseudowire management.

View File

@ -182,12 +182,12 @@ static void l2tp_dfs_seq_session_show(struct seq_file *m, void *v)
session->pwtype == L2TP_PWTYPE_ETH ? "ETH" :
session->pwtype == L2TP_PWTYPE_PPP ? "PPP" :
"");
if (session->send_seq || session->recv_seq)
if (READ_ONCE(session->send_seq) || session->recv_seq)
seq_printf(m, " nr %u, ns %u\n", session->nr, session->ns);
seq_printf(m, " refcnt %d\n", refcount_read(&session->ref_count));
seq_printf(m, " config 0/0/%c/%c/-/%s %08x %u\n",
session->recv_seq ? 'R' : '-',
session->send_seq ? 'S' : '-',
READ_ONCE(session->send_seq) ? 'S' : '-',
session->lns_mode ? "LNS" : "LAC",
0,
jiffies_to_msecs(session->reorder_timeout));

View File

@ -700,12 +700,9 @@ static int l2tp_nl_cmd_session_modify(struct sk_buff *skb, struct genl_info *inf
if (info->attrs[L2TP_ATTR_RECV_SEQ])
session->recv_seq = nla_get_u8(info->attrs[L2TP_ATTR_RECV_SEQ]);
if (info->attrs[L2TP_ATTR_SEND_SEQ]) {
struct l2tp_tunnel *tunnel = session->tunnel;
session->send_seq = nla_get_u8(info->attrs[L2TP_ATTR_SEND_SEQ]);
l2tp_session_set_header_len(session, tunnel->version, tunnel->encap);
}
if (info->attrs[L2TP_ATTR_SEND_SEQ])
WRITE_ONCE(session->send_seq,
nla_get_u8(info->attrs[L2TP_ATTR_SEND_SEQ]) & 1);
if (info->attrs[L2TP_ATTR_LNS_MODE])
session->lns_mode = nla_get_u8(info->attrs[L2TP_ATTR_LNS_MODE]);
@ -748,7 +745,7 @@ static int l2tp_nl_session_send(struct sk_buff *skb, u32 portid, u32 seq, int fl
(session->peer_cookie_len &&
nla_put(skb, L2TP_ATTR_PEER_COOKIE, session->peer_cookie_len, session->peer_cookie)) ||
nla_put_u8(skb, L2TP_ATTR_RECV_SEQ, session->recv_seq) ||
nla_put_u8(skb, L2TP_ATTR_SEND_SEQ, session->send_seq) ||
nla_put_u8(skb, L2TP_ATTR_SEND_SEQ, READ_ONCE(session->send_seq)) ||
nla_put_u8(skb, L2TP_ATTR_LNS_MODE, session->lns_mode) ||
(l2tp_tunnel_uses_xfrm(tunnel) &&
nla_put_u8(skb, L2TP_ATTR_USING_IPSEC, 1)) ||

View File

@ -1195,9 +1195,7 @@ static int pppol2tp_session_setsockopt(struct sock *sk,
err = -EINVAL;
break;
}
session->send_seq = !!val;
l2tp_session_set_header_len(session, session->tunnel->version,
session->tunnel->encap);
WRITE_ONCE(session->send_seq, !!val);
break;
case PPPOL2TP_SO_LNSMODE:
@ -1307,7 +1305,7 @@ static int pppol2tp_session_getsockopt(struct sock *sk,
break;
case PPPOL2TP_SO_SENDSEQ:
*val = session->send_seq;
*val = READ_ONCE(session->send_seq);
break;
case PPPOL2TP_SO_LNSMODE:
@ -1546,7 +1544,7 @@ static void pppol2tp_seq_session_show(struct seq_file *m, void *v)
state, user_data_ok);
seq_printf(m, " 0/0/%c/%c/%s %08x %u\n",
session->recv_seq ? 'R' : '-',
session->send_seq ? 'S' : '-',
READ_ONCE(session->send_seq) ? 'S' : '-',
session->lns_mode ? "LNS" : "LAC",
0,
jiffies_to_msecs(session->reorder_timeout));

View File

@ -3705,6 +3705,24 @@ static void mptcp_copy_ip_options(struct sock *newsk, const struct sock *sk)
rcu_read_unlock();
}
static void mptcp_sk_clone_destroy(struct sock *nsk)
{
struct mptcp_sock *msk = mptcp_sk(nsk);
mptcp_release_sched(msk);
mptcp_set_state(nsk, TCP_CLOSE);
/* inet_csk_prepare_forced_close() clears TCP sock_ops state via
* tcp_sk(), but nsk is an MPTCP master socket; keep the inet-level
* destroy preparation here.
*/
bh_unlock_sock(nsk);
sock_put(nsk);
sock_set_flag(nsk, SOCK_DEAD);
tcp_orphan_count_inc();
inet_sk(nsk)->inet_num = 0;
inet_csk_destroy_sock(nsk);
}
struct sock *mptcp_sk_clone_init(const struct sock *sk,
const struct mptcp_options_received *mp_opt,
struct sock *ssk,
@ -3764,11 +3782,6 @@ struct sock *mptcp_sk_clone_init(const struct sock *sk,
list_add(&subflow->node, &msk->conn_list);
sock_hold(ssk);
/* new mpc subflow takes ownership of the newly
* created mptcp socket
*/
mptcp_token_accept(subflow_req, msk);
/* set msk addresses early to ensure mptcp_pm_get_local_id()
* uses the correct data
*/
@ -3777,6 +3790,14 @@ struct sock *mptcp_sk_clone_init(const struct sock *sk,
mptcp_rcv_space_init(msk, ssk);
msk->rcvq_space.time = mptcp_stamp();
if (!mptcp_token_accept(subflow_req, msk)) {
list_del_init(&subflow->node);
WRITE_ONCE(msk->first, NULL);
sock_put(ssk);
mptcp_sk_clone_destroy(nsk);
return NULL;
}
if (mp_opt->suboptions & OPTION_MPTCP_MPC_ACK)
__mptcp_subflow_fully_established(msk, subflow, mp_opt);
bh_unlock_sock(nsk);
@ -4211,9 +4232,16 @@ static int mptcp_connect(struct sock *sk, struct sockaddr_unsized *uaddr,
* subflow_finish_connect()
*/
if (unlikely(err)) {
/* avoid leaving a dangling token in an unconnected socket */
mptcp_token_destroy(msk);
mptcp_set_state(sk, TCP_CLOSE);
spin_lock_bh(&msk->fallback_lock);
msk->allow_subflows = true;
msk->allow_infinite_fallback = true;
clear_bit(MPTCP_FALLBACK_DONE, &msk->flags);
spin_unlock_bh(&msk->fallback_lock);
mptcp_subflow_ctx_reset(mptcp_subflow_ctx(ssk));
return err;
}

View File

@ -597,14 +597,16 @@ struct mptcp_subflow_context {
closing : 1, /* must not pass rx data to msk anymore */
valid_csum_seen : 1, /* at least one csum validated */
is_mptfo : 1, /* subflow is doing TFO */
close_event_done : 1, /* has done the post-closed part */
mpc_drop : 1, /* the MPC option has been dropped in a rtx */
resetting : 1, /* subflow is resetting */
__unused : 8;
__unused : 9;
bool data_avail;
bool scheduled;
bool pm_listener; /* a listener managed by the kernel PM? */
bool fully_established; /* path validated */
bool close_event_done; /* has done the post-closed part,
* protected by msk socket lock
*/
u32 lent_mem_frag;
u32 remote_nonce;
u32 local_nonce;
@ -1094,9 +1096,11 @@ static inline void mptcp_token_init_request(struct request_sock *req)
}
int mptcp_token_new_request(struct request_sock *req);
void mptcp_token_move_request(struct request_sock *req,
struct request_sock *new_req);
void mptcp_token_destroy_request(struct request_sock *req);
int mptcp_token_new_connect(struct sock *ssk);
void mptcp_token_accept(struct mptcp_subflow_request_sock *r,
bool mptcp_token_accept(struct mptcp_subflow_request_sock *r,
struct mptcp_sock *msk);
bool mptcp_token_exists(u32 token);
struct mptcp_sock *mptcp_token_get_sock(struct net *net, u32 token);

View File

@ -47,6 +47,41 @@ static void subflow_req_destructor(struct request_sock *req)
mptcp_token_destroy_request(req);
}
void mptcp_subflow_reqsk_clone(struct request_sock *req,
struct request_sock *new_req)
{
struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
struct mptcp_subflow_request_sock *new_subflow_req;
struct mptcp_sock *msk;
new_subflow_req = mptcp_subflow_rsk(new_req);
RCU_LOCKDEP_WARN(!rcu_read_lock_any_held(),
"MPTCP reqsk clone called without RCU");
/* A non-NULL ->msk means the request owns one reference. The clone
* copied only the pointer, while the original request can concurrently
* transfer its reference to the child. Acquire a reference for the
* clone, then verify that the original request still owns the same msk.
* MPTCP sockets use SLAB_TYPESAFE_BY_RCU and all clone callers run in
* an RCU read-side critical section, keeping the memory stable here.
*/
msk = READ_ONCE(subflow_req->msk);
if (msk) {
struct sock *sk = (struct sock *)msk;
if (!refcount_inc_not_zero_acquire(&sk->sk_refcnt)) {
msk = NULL;
} else if (READ_ONCE(subflow_req->msk) != msk) {
sock_put(sk);
msk = NULL;
}
}
new_subflow_req->msk = msk;
mptcp_token_move_request(req, new_req);
}
static void subflow_generate_hmac(u64 key1, u64 key2, u32 nonce1, u32 nonce2,
void *hmac)
{
@ -889,8 +924,10 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk,
if (ctx->mp_capable) {
ctx->conn = mptcp_sk_clone_init(listener->conn, &mp_opt, child, req);
if (!ctx->conn)
if (!ctx->conn) {
fallback = true;
goto fallback;
}
ctx->subflow_id = 1;
owner = mptcp_sk(ctx->conn);
@ -927,7 +964,7 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk,
}
/* move the msk reference ownership to the subflow */
subflow_req->msk = NULL;
WRITE_ONCE(subflow_req->msk, NULL);
ctx->conn = (struct sock *)owner;
if (subflow_use_different_sport(owner, sk)) {

View File

@ -180,6 +180,43 @@ int mptcp_token_new_connect(struct sock *ssk)
return 0;
}
/**
* mptcp_token_move_request - move request token ownership to a clone
* @req: original request socket
* @new_req: cloned request socket
*
* Move the token hash entry from the original request to its clone.
*/
void mptcp_token_move_request(struct request_sock *req,
struct request_sock *new_req)
{
struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
struct mptcp_subflow_request_sock *new_subflow_req;
struct mptcp_subflow_request_sock *pos;
struct token_bucket *bucket;
new_subflow_req = mptcp_subflow_rsk(new_req);
if (hlist_nulls_unhashed_lockless(&subflow_req->token_node)) {
mptcp_token_init_request(new_req);
return;
}
bucket = token_bucket(subflow_req->token);
spin_lock_bh(&bucket->lock);
if (hlist_nulls_unhashed(&subflow_req->token_node)) {
mptcp_token_init_request(new_req);
} else {
pos = __token_lookup_req(bucket, subflow_req->token);
if (pos == subflow_req)
hlist_nulls_replace_init_rcu(&subflow_req->token_node,
&new_subflow_req->token_node);
else
mptcp_token_init_request(new_req);
}
spin_unlock_bh(&bucket->lock);
}
/**
* mptcp_token_accept - replace a req sk with full sock in token hash
* @req: the request socket to be removed
@ -187,24 +224,36 @@ int mptcp_token_new_connect(struct sock *ssk)
*
* Called when a SYN packet creates a new logical connection, i.e.
* is not a join request.
*
* Return: true on success.
*/
void mptcp_token_accept(struct mptcp_subflow_request_sock *req,
bool mptcp_token_accept(struct mptcp_subflow_request_sock *req,
struct mptcp_sock *msk)
{
struct mptcp_subflow_request_sock *pos;
struct sock *sk = (struct sock *)msk;
struct token_bucket *bucket;
bool ret = false;
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
bucket = token_bucket(req->token);
spin_lock_bh(&bucket->lock);
if (hlist_nulls_unhashed(&req->token_node))
goto unlock;
/* pedantic lookup check for the moved token */
pos = __token_lookup_req(bucket, req->token);
if (!WARN_ON_ONCE(pos != req))
hlist_nulls_del_init_rcu(&req->token_node);
if (pos != req)
goto unlock;
hlist_nulls_del_init_rcu(&req->token_node);
__sk_nulls_add_node_rcu((struct sock *)msk, &bucket->msk_chain);
ret = true;
unlock:
spin_unlock_bh(&bucket->lock);
if (ret)
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
return ret;
}
bool mptcp_token_exists(u32 token)
@ -355,16 +404,21 @@ void mptcp_token_destroy_request(struct request_sock *req)
struct mptcp_subflow_request_sock *pos;
struct token_bucket *bucket;
if (hlist_nulls_unhashed(&subflow_req->token_node))
if (hlist_nulls_unhashed_lockless(&subflow_req->token_node))
return;
bucket = token_bucket(subflow_req->token);
spin_lock_bh(&bucket->lock);
if (hlist_nulls_unhashed(&subflow_req->token_node))
goto unlock;
pos = __token_lookup_req(bucket, subflow_req->token);
if (!WARN_ON_ONCE(pos != subflow_req)) {
if (pos == subflow_req) {
hlist_nulls_del_init_rcu(&pos->token_node);
bucket->chain_len--;
}
unlock:
spin_unlock_bh(&bucket->lock);
}

View File

@ -99,7 +99,7 @@ static void mptcp_token_test_accept(struct kunit *test)
KUNIT_ASSERT_EQ(test, 0,
mptcp_token_new_request((struct request_sock *)req));
msk->token = req->token;
mptcp_token_accept(req, msk);
KUNIT_EXPECT_TRUE(test, mptcp_token_accept(req, msk));
KUNIT_EXPECT_PTR_EQ(test, msk, mptcp_token_get_sock(&init_net, msk->token));
/* this is now a no-op */
@ -122,7 +122,7 @@ static void mptcp_token_test_destroyed(struct kunit *test)
KUNIT_ASSERT_EQ(test, 0,
mptcp_token_new_request((struct request_sock *)req));
msk->token = req->token;
mptcp_token_accept(req, msk);
KUNIT_EXPECT_TRUE(test, mptcp_token_accept(req, msk));
/* simulate race on removal */
refcount_set(&sk->sk_refcnt, 0);

View File

@ -1153,8 +1153,8 @@ ip_vs_bind_dest(struct ip_vs_conn *cp, struct ip_vs_dest *dest)
if (!(flags & IP_VS_CONN_F_INACTIVE))
atomic_inc(&dest->activeconns);
tc = atomic_inc_return(&dest->totalconns);
if (tc == READ_ONCE(dest->u_threshold))
ip_vs_dest_update_overload(dest, 1);
if (tc >= READ_ONCE(dest->u_threshold_val))
ip_vs_dest_update_overload(dest, true);
} else {
/* It is a persistent connection/template, so increase
the persistent connection counter */
@ -1246,8 +1246,8 @@ static inline void ip_vs_unbind_dest(struct ip_vs_conn *cp)
if (!(cp->flags & IP_VS_CONN_F_INACTIVE))
atomic_dec(&dest->activeconns);
tc = atomic_fetch_dec(&dest->totalconns);
if (tc == READ_ONCE(dest->l_threshold_val))
ip_vs_dest_update_overload(dest, -1);
if (tc <= READ_ONCE(dest->l_threshold_val))
ip_vs_dest_update_overload(dest, false);
} else {
/* It is a persistent connection/template, so decrease
the persistent connection counter */

View File

@ -1309,32 +1309,32 @@ void ip_vs_stats_free(struct ip_vs_stats *stats)
* - conns reach u_threshold and exceed it: set the flag
* - conns go below l_threshold (or 75% of u_threshold): clear the flag
*/
static void __ip_vs_dest_update_overload(struct ip_vs_dest *dest, int mode)
static void __ip_vs_dest_update_overload(struct ip_vs_dest *dest, bool overload)
{
int conns;
u32 l, u;
lockdep_assert_held(&dest->dst_lock);
u = READ_ONCE(dest->u_threshold);
if (!u)
goto unset;
l = READ_ONCE(dest->l_threshold_val);
conns = atomic_read(&dest->totalconns);
if (conns >= (mode > 0 ? l : u)) {
dest->flags |= IP_VS_DEST_F_OVERLOAD;
return;
if (u) {
/* Low threshold defaults to 75% of upper threshold */
l = READ_ONCE(dest->l_threshold) ? : (u - (u >> 2));
conns = atomic_read(&dest->totalconns);
if (conns >= (overload ? l : u)) {
WRITE_ONCE(dest->u_threshold_val, INT_MAX);
WRITE_ONCE(dest->l_threshold_val, l);
return;
}
}
if (conns >= (mode < 0 ? u : l))
return;
unset:
dest->flags &= ~IP_VS_DEST_F_OVERLOAD;
WRITE_ONCE(dest->u_threshold_val, u ? : INT_MAX);
WRITE_ONCE(dest->l_threshold_val, 0);
}
void ip_vs_dest_update_overload(struct ip_vs_dest *dest, int mode)
void ip_vs_dest_update_overload(struct ip_vs_dest *dest, bool overload)
{
spin_lock_bh(&dest->dst_lock);
__ip_vs_dest_update_overload(dest, mode);
__ip_vs_dest_update_overload(dest, overload);
spin_unlock_bh(&dest->dst_lock);
}
@ -1406,15 +1406,13 @@ __ip_vs_update_dest(struct ip_vs_service *svc, struct ip_vs_dest *dest,
if (READ_ONCE(dest->u_threshold) != udest->u_threshold ||
READ_ONCE(dest->l_threshold) != udest->l_threshold) {
bool overload;
spin_lock_bh(&dest->dst_lock);
WRITE_ONCE(dest->u_threshold, udest->u_threshold);
WRITE_ONCE(dest->l_threshold, udest->l_threshold);
/* Low threshold defaults to 75% of upper threshold */
WRITE_ONCE(dest->l_threshold_val,
udest->l_threshold ? :
(udest->u_threshold -
(udest->u_threshold >> 2)));
__ip_vs_dest_update_overload(dest, 0);
overload = ip_vs_dest_is_overloaded(dest);
__ip_vs_dest_update_overload(dest, overload);
spin_unlock_bh(&dest->dst_lock);
}
@ -2454,6 +2452,8 @@ proc_do_sync_threshold(const struct ctl_table *table, int write,
mutex_lock(&ipvs->sync_mutex);
memcpy(val, valp, sizeof(val));
rc = proc_dointvec(&tmp, write, buffer, lenp, ppos);
if (rc)
goto out;
if (write) {
if (val[0] < 0 || val[1] < 0 ||
(val[0] >= val[1] && val[1]))
@ -2461,6 +2461,7 @@ proc_do_sync_threshold(const struct ctl_table *table, int write,
else
memcpy(valp, val, sizeof(val));
}
out:
mutex_unlock(&ipvs->sync_mutex);
return rc;
}

View File

@ -195,16 +195,6 @@ static int ip_vs_dh_dest_changed(struct ip_vs_service *svc,
}
/*
* If the dest flags is set with IP_VS_DEST_F_OVERLOAD,
* consider that the server is overloaded here.
*/
static inline int is_overloaded(struct ip_vs_dest *dest)
{
return dest->flags & IP_VS_DEST_F_OVERLOAD;
}
/*
* Destination hashing scheduling
*/
@ -219,10 +209,8 @@ ip_vs_dh_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
s = (struct ip_vs_dh_state *) svc->sched_data;
dest = ip_vs_dh_get(svc->af, s, &iph->daddr);
if (!dest ||
!(dest->cflags & IP_VS_DEST_CF_AVAILABLE)
|| atomic_read(&dest->weight) <= 0
|| is_overloaded(dest)) {
if (!dest || atomic_read(&dest->weight) <= 0 ||
ip_vs_dest_is_overloaded(dest)) {
ip_vs_scheduler_err(svc, "no destination available");
return NULL;
}

View File

@ -29,7 +29,7 @@ ip_vs_fo_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
* Find virtual server with highest weight and send it traffic
*/
list_for_each_entry_rcu(dest, &svc->destinations, n_list) {
if (!(dest->flags & IP_VS_DEST_F_OVERLOAD) &&
if (!ip_vs_dest_is_overloaded(dest) &&
atomic_read(&dest->weight) > hw) {
hweight = dest;
hw = atomic_read(&dest->weight);

View File

@ -418,7 +418,7 @@ __ip_vs_lblc_schedule(struct ip_vs_service *svc)
* new connection.
*/
list_for_each_entry_rcu(dest, &svc->destinations, n_list) {
if (dest->flags & IP_VS_DEST_F_OVERLOAD)
if (ip_vs_dest_is_overloaded(dest))
continue;
if (atomic_read(&dest->weight) > 0) {
least = dest;
@ -433,7 +433,7 @@ __ip_vs_lblc_schedule(struct ip_vs_service *svc)
*/
nextstage:
list_for_each_entry_continue_rcu(dest, &svc->destinations, n_list) {
if (dest->flags & IP_VS_DEST_F_OVERLOAD)
if (ip_vs_dest_is_overloaded(dest))
continue;
doh = ip_vs_dest_conn_overhead(dest);

View File

@ -166,7 +166,7 @@ static inline struct ip_vs_dest *ip_vs_dest_set_min(struct ip_vs_dest_set *set)
/* select the first destination server, whose weight > 0 */
list_for_each_entry_rcu(e, &set->list, list) {
least = e->dest;
if (least->flags & IP_VS_DEST_F_OVERLOAD)
if (ip_vs_dest_is_overloaded(least))
continue;
if ((atomic_read(&least->weight) > 0) &&
@ -181,7 +181,7 @@ static inline struct ip_vs_dest *ip_vs_dest_set_min(struct ip_vs_dest_set *set)
nextstage:
list_for_each_entry_continue_rcu(e, &set->list, list) {
dest = e->dest;
if (dest->flags & IP_VS_DEST_F_OVERLOAD)
if (ip_vs_dest_is_overloaded(dest))
continue;
doh = ip_vs_dest_conn_overhead(dest);
@ -580,7 +580,7 @@ __ip_vs_lblcr_schedule(struct ip_vs_service *svc)
* new connection.
*/
list_for_each_entry_rcu(dest, &svc->destinations, n_list) {
if (dest->flags & IP_VS_DEST_F_OVERLOAD)
if (ip_vs_dest_is_overloaded(dest))
continue;
if (atomic_read(&dest->weight) > 0) {
@ -596,7 +596,7 @@ __ip_vs_lblcr_schedule(struct ip_vs_service *svc)
*/
nextstage:
list_for_each_entry_continue_rcu(dest, &svc->destinations, n_list) {
if (dest->flags & IP_VS_DEST_F_OVERLOAD)
if (ip_vs_dest_is_overloaded(dest))
continue;
doh = ip_vs_dest_conn_overhead(dest);

View File

@ -38,7 +38,7 @@ ip_vs_lc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
*/
list_for_each_entry_rcu(dest, &svc->destinations, n_list) {
if ((dest->flags & IP_VS_DEST_F_OVERLOAD) ||
if (ip_vs_dest_is_overloaded(dest) ||
atomic_read(&dest->weight) == 0)
continue;
doh = ip_vs_dest_conn_overhead(dest);

View File

@ -80,7 +80,7 @@ static inline void generate_hash_secret(hsiphash_key_t *hash1,
static inline bool is_unavailable(struct ip_vs_dest *dest)
{
return atomic_read(&dest->weight) <= 0 ||
dest->flags & IP_VS_DEST_F_OVERLOAD;
ip_vs_dest_is_overloaded(dest);
}
/* Returns hash value for IPVS MH entry */

View File

@ -72,7 +72,7 @@ ip_vs_nq_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
list_for_each_entry_rcu(dest, &svc->destinations, n_list) {
if (dest->flags & IP_VS_DEST_F_OVERLOAD ||
if (ip_vs_dest_is_overloaded(dest) ||
!atomic_read(&dest->weight))
continue;

View File

@ -33,7 +33,7 @@ ip_vs_ovf_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
*/
list_for_each_entry_rcu(dest, &svc->destinations, n_list) {
w = atomic_read(&dest->weight);
if ((dest->flags & IP_VS_DEST_F_OVERLOAD) ||
if (ip_vs_dest_is_overloaded(dest) ||
atomic_read(&dest->activeconns) > w ||
w == 0)
continue;

View File

@ -66,7 +66,7 @@ ip_vs_rr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
list_for_each_entry_continue_rcu(dest,
&svc->destinations,
n_list) {
if (!(dest->flags & IP_VS_DEST_F_OVERLOAD) &&
if (!ip_vs_dest_is_overloaded(dest) &&
atomic_read(&dest->weight) > 0)
/* HIT */
goto out;

View File

@ -75,7 +75,7 @@ ip_vs_sed_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
*/
list_for_each_entry_rcu(dest, &svc->destinations, n_list) {
if (!(dest->flags & IP_VS_DEST_F_OVERLOAD) &&
if (!ip_vs_dest_is_overloaded(dest) &&
atomic_read(&dest->weight) > 0) {
least = dest;
loh = ip_vs_sed_dest_overhead(least);
@ -90,7 +90,7 @@ ip_vs_sed_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
*/
nextstage:
list_for_each_entry_continue_rcu(dest, &svc->destinations, n_list) {
if (dest->flags & IP_VS_DEST_F_OVERLOAD)
if (ip_vs_dest_is_overloaded(dest))
continue;
doh = ip_vs_sed_dest_overhead(dest);
if ((__s64)loh * atomic_read(&dest->weight) >

View File

@ -73,7 +73,7 @@ struct ip_vs_sh_state {
static inline bool is_unavailable(struct ip_vs_dest *dest)
{
return atomic_read(&dest->weight) <= 0 ||
dest->flags & IP_VS_DEST_F_OVERLOAD;
ip_vs_dest_is_overloaded(dest);
}
/*

View File

@ -52,7 +52,7 @@ static struct ip_vs_dest *ip_vs_twos_schedule(struct ip_vs_service *svc,
/* Generate a random weight between [0,sum of all weights) */
list_for_each_entry_rcu(dest, &svc->destinations, n_list) {
if (!(dest->flags & IP_VS_DEST_F_OVERLOAD)) {
if (!ip_vs_dest_is_overloaded(dest)) {
weight = atomic_read(&dest->weight);
if (weight > 0) {
total_weight += weight;
@ -75,7 +75,7 @@ static struct ip_vs_dest *ip_vs_twos_schedule(struct ip_vs_service *svc,
/* Pick two weighted servers */
list_for_each_entry_rcu(dest, &svc->destinations, n_list) {
if (dest->flags & IP_VS_DEST_F_OVERLOAD)
if (ip_vs_dest_is_overloaded(dest))
continue;
weight = atomic_read(&dest->weight);

View File

@ -47,7 +47,7 @@ ip_vs_wlc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
*/
list_for_each_entry_rcu(dest, &svc->destinations, n_list) {
if (!(dest->flags & IP_VS_DEST_F_OVERLOAD) &&
if (!ip_vs_dest_is_overloaded(dest) &&
atomic_read(&dest->weight) > 0) {
least = dest;
loh = ip_vs_dest_conn_overhead(least);
@ -62,7 +62,7 @@ ip_vs_wlc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
*/
nextstage:
list_for_each_entry_continue_rcu(dest, &svc->destinations, n_list) {
if (dest->flags & IP_VS_DEST_F_OVERLOAD)
if (ip_vs_dest_is_overloaded(dest))
continue;
doh = ip_vs_dest_conn_overhead(dest);
if ((__s64)loh * atomic_read(&dest->weight) >

View File

@ -176,7 +176,7 @@ ip_vs_wrr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
list_for_each_entry_continue_rcu(dest,
&svc->destinations,
n_list) {
if (!(dest->flags & IP_VS_DEST_F_OVERLOAD) &&
if (!ip_vs_dest_is_overloaded(dest) &&
atomic_read(&dest->weight) >= mark->cw)
goto found;
if (dest == stop)

View File

@ -1109,13 +1109,13 @@ static int ctnetlink_filter_match_tuple(struct nf_conntrack_tuple *filter_tuple,
break;
case NFPROTO_IPV6:
if ((flags & CTA_FILTER_FLAG(CTA_IP_SRC)) &&
!ipv6_addr_equal(&filter_tuple->src.u3.in6,
&ct_tuple->src.u3.in6))
ipv6_addr_cmp(&filter_tuple->src.u3.in6,
&ct_tuple->src.u3.in6))
return 0;
if ((flags & CTA_FILTER_FLAG(CTA_IP_DST)) &&
!ipv6_addr_equal(&filter_tuple->dst.u3.in6,
&ct_tuple->dst.u3.in6))
ipv6_addr_cmp(&filter_tuple->dst.u3.in6,
&ct_tuple->dst.u3.in6))
return 0;
break;
}

View File

@ -170,14 +170,14 @@ static void nf_flow_tuple_encap(struct nf_flowtable_ctx *ctx,
int i = 0;
if (skb_vlan_tag_present(skb)) {
tuple->encap[i].id = skb_vlan_tag_get(skb);
tuple->encap[i].id = skb_vlan_tag_get_id(skb);
tuple->encap[i].proto = skb->vlan_proto;
i++;
}
switch (skb->protocol) {
case htons(ETH_P_8021Q):
veth = (struct vlan_ethhdr *)skb_mac_header(skb);
tuple->encap[i].id = ntohs(veth->h_vlan_TCI);
tuple->encap[i].id = ntohs(veth->h_vlan_TCI) & VLAN_VID_MASK;
tuple->encap[i].proto = skb->protocol;
offset += VLAN_HLEN;
break;
@ -509,6 +509,7 @@ static int nf_flow_offload_forward(struct nf_flowtable_ctx *ctx,
nf_flow_encap_pop(ctx, skb, tuplehash);
thoff -= ctx->offset;
skb_set_transport_header(skb, thoff);
iph = ip_hdr(skb);
nf_flow_nat_ip(flow, skb, thoff, dir, iph);
@ -1136,6 +1137,7 @@ static int nf_flow_offload_ipv6_forward(struct nf_flowtable_ctx *ctx,
flow_offload_refresh(flow_table, flow, false);
nf_flow_encap_pop(ctx, skb, tuplehash);
skb_set_transport_header(skb, sizeof(*ip6h));
ip6h = ipv6_hdr(skb);
nf_flow_nat_ipv6(flow, skb, dir, ip6h);

View File

@ -20,6 +20,7 @@
#include <linux/tcp.h>
#include <linux/udp.h>
#include <net/gre.h>
#include <linux/icmp.h>
#include <linux/icmpv6.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
@ -1008,11 +1009,14 @@ static bool nft_payload_validate_inet_csum_offset(const struct nft_ctx *ctx,
if (priv->csum_flags) /* makes no sense, asks for "re-update" of L4 checksum */
return false;
/* no further check here; offset can't be negative so bogus
* offsets can corrupt L4 or payload but not l3 headers.
* We already allow arbitrary l4/inner payload writes.
*/
return true;
/* Validate csum_offset is one of the supported transport header checksums */
if (priv->csum_offset == offsetof(struct tcphdr, check) ||
priv->csum_offset == offsetof(struct udphdr, check) ||
priv->csum_offset == offsetof(struct icmphdr, checksum) ||
priv->csum_offset == offsetof(struct icmp6hdr, icmp6_cksum))
return true;
return false;
case NFT_PAYLOAD_INNER_HEADER:
return true;
case NFT_PAYLOAD_TUN_HEADER:
@ -1046,6 +1050,27 @@ static bool nft_payload_csum_nh_write_ok(const struct nft_payload_set *priv,
return false;
}
static bool nft_payload_csum_th_write_ok(const struct nft_payload_set *priv,
const struct nft_pktinfo *pkt)
{
if (!(pkt->flags & NFT_PKTINFO_L4PROTO))
return false;
switch (pkt->tprot) {
case IPPROTO_TCP:
return priv->csum_offset == offsetof(struct tcphdr, check);
case IPPROTO_UDP:
case IPPROTO_UDPLITE:
return priv->csum_offset == offsetof(struct udphdr, check);
case IPPROTO_ICMPV6:
return priv->csum_offset == offsetof(struct icmp6hdr, icmp6_cksum);
case IPPROTO_ICMP:
return priv->csum_offset == offsetof(struct icmphdr, checksum);
}
return false;
}
static bool nft_payload_csum_write_ok(const struct nft_pktinfo *pkt,
const struct nft_payload_set *priv)
{
@ -1055,9 +1080,10 @@ static bool nft_payload_csum_write_ok(const struct nft_pktinfo *pkt,
case NFT_PAYLOAD_NETWORK_HEADER:
return nft_payload_csum_nh_write_ok(priv, pkt);
case NFT_PAYLOAD_TRANSPORT_HEADER:
return nft_payload_csum_th_write_ok(priv, pkt);
case NFT_PAYLOAD_INNER_HEADER:
/* neither offsets are validated, offsets cannot be
* negative so real l3 headers cannot be mangled.
/* offset is not validated, offset cannot be
* negative so real l3/l4 headers cannot be mangled.
*/
return true;
case NFT_PAYLOAD_TUN_HEADER:

View File

@ -1091,7 +1091,8 @@ static void nft_rbtree_commit(struct nft_set *set)
* representation. Use next start element to complete this
* interval.
*/
if (nft_rbtree_interval_start(rbe) &&
if (nft_set_is_anonymous(set) &&
nft_rbtree_interval_start(rbe) &&
nft_rbtree_interval_start(prev_rbe) &&
priv->array_next->intervals[num_intervals].from)
priv->array_next->intervals[num_intervals++].to = &prev_rbe->ext;

View File

@ -62,7 +62,7 @@ dccp_find_option(u_int8_t option,
return true;
}
if (op[i] < 2 || i == optlen - 1)
if (op[i] <= DCCPO_MAX_RESERVED || i == optlen - 1)
i++;
else
i += op[i + 1] ? : 1;

View File

@ -949,6 +949,12 @@ static void rds_ib_process_recv(struct rds_connection *conn,
}
}
if (data_len < min_t(u32, ic->i_recv_data_rem, RDS_FRAG_SIZE)) {
rds_ib_conn_error(conn,
"fragment shorter than header-declared length; forcing reconnect\n");
goto done;
}
list_add_tail(&recv->r_frag->f_item, &ibinc->ii_frags);
recv->r_frag = NULL;
@ -1004,7 +1010,12 @@ void rds_ib_recv_cqe_handler(struct rds_ib_connection *ic,
* event is processed.
*/
if (wc->status == IB_WC_SUCCESS) {
rds_ib_process_recv(conn, recv, wc->byte_len, state);
if (wc->opcode != IB_WC_RECV)
rds_ib_conn_error(conn,
"recv completion had unexpected opcode %u, disconnecting and reconnecting\n",
wc->opcode);
else
rds_ib_process_recv(conn, recv, wc->byte_len, state);
} else {
/* We expect errors as the qp is drained during shutdown */
if (rds_conn_up(conn) || rds_conn_connecting(conn))

Some files were not shown because too many files have changed in this diff Show More