mirror of
https://github.com/torvalds/linux.git
synced 2026-11-06 21:58:01 +01:00
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.ccd37ab22a7("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.c8830e65ed4("net: use assign_bit() where applicable")07bd391eb9("octeontx2-af: Fix CQ enable state tracking after AQ writes") net/core/sock.c31c5ea8a32("ipv6: Remove IPV6_ADDRFORM.")31b564f70d("net: use the full socket in sk_mc_loop()") net/mptcp/protocol.h0cb6910130("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:
commit
207dd12bc1
1
.mailmap
1
.mailmap
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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"),
|
||||
},
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 "
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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) { }
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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) ? :
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -232,6 +232,7 @@ static int ip6_frag_queue(struct net *net,
|
|||
}
|
||||
|
||||
skb_dst_drop(skb);
|
||||
skb_orphan(skb);
|
||||
return -EINPROGRESS;
|
||||
|
||||
insert_error:
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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)) ||
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) >
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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) >
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Reference in New Issue
Block a user