Networking fixes for 6.4-rc8, including fixes from ipsec, bpf,

mptcp and netfilter.
 
 Current release - regressions:
 
   - netfilter: add NFT_TRANS_PREPARE_ERROR to deal with bound set/chain
 
   - eth: mlx5e:
     - fix scheduling of IPsec ASO query while in atomic
     - free IRQ rmap and notifier on kernel shutdown
 
 Current release - new code bugs:
 
   - phy: manual remove LEDs to ensure correct ordering
 
 Previous releases - regressions:
 
   - mptcp: fix possible divide by zero in recvmsg()
 
   - dsa: revert "net: phy: dp83867: perform soft reset and retain established link"
 
 Previous releases - always broken:
 
   - sched: netem: acquire qdisc lock in netem_change()
 
   - bpf:
     - fix verifier id tracking of scalars on spill
     - fix NULL dereference on exceptions
     - accept function names that contain dots
 
   - netfilter: disallow element updates of bound anonymous sets
 
   - mptcp: ensure listener is unhashed before updating the sk status
 
   - xfrm:
     - add missed call to delete offloaded policies
     - fix inbound ipv4/udp/esp packets to UDPv6 dualstack sockets
 
   - selftests: fixes for FIPS mode
 
   - dsa: mt7530: fix multiple CPU ports, BPDU and LLDP handling
 
   - eth: sfc: use budget for TX completions
 
 Misc:
 
   - wifi: iwlwifi: add support for SO-F device with PCI id 0x7AF0
 
 Signed-off-by: Paolo Abeni <pabeni@redhat.com>
 -----BEGIN PGP SIGNATURE-----
 
 iQJGBAABCAAwFiEEg1AjqC77wbdLX2LbKSR5jcyPE6QFAmSUZO0SHHBhYmVuaUBy
 ZWRoYXQuY29tAAoJECkkeY3MjxOkBjAP/RfTUYdlPqz9jSvz0HmQt2Er39HyVb9I
 pzEpJSQGfO+eyIrlxmleu8cAaW5HdvyfMcBgr04uh+Jf06s+VJrD95IO9zDHHKoC
 86itYNKMS3fSt1ivzg49i5uq66MhjtAcfIOB9HMOAQ2Jd+DYlzyWOOHw28ZAxsBZ
 Q6TU97YEMuU4FdLkoKob1aVswC5cPxNx2IH9NagfbtijaYZqeN9ZX9EI5yMUyH8f
 5gboqOhXUQK0MQLM5TFySHeoayyQ+tRBz24nF0/6lWiRr+xzMTEKdkFpRza7Mxzj
 S8NxN3C+zOf96gic6kYOXmM6y0sOlbwC9JoeWTp8Tuh6DEYi6xLC2XkiYJ51idZg
 PElgRpkM1ddqvvFWFgZlNik5z0vbGnJH7pt0VuOSNntxE60cdQwvWEOr09vvPcS5
 0nMVD0uc8pds2h4hit+sdLltcVnOgoNUYr1/sI6oydofa1BrLnhFPF7z/gUs9foD
 NuCchiaBF11yBGKufcNBNEB4w35g3Kcu6TGhHb168OJi+UnSnwlI0Ccw7iO10pkv
 RjefhR60+wZC6+leo57nZeYqaLQJuALY0QYFsyeM+T0MGSYkbH24CmbNdSmO4MRr
 +VX2CwIqeIds4Hx31o0Feu+FaJqXw46/2nrSDxel/hlCJnGSMXZTw+b/4pFEHLP+
 l71ijZpJqV1S
 =GH2b
 -----END PGP SIGNATURE-----

Merge tag 'net-6.4-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net

Pull networking fixes from Paolo Abeni:
 "Including fixes from ipsec, bpf, mptcp and netfilter.

  Current release - regressions:

   - netfilter: add NFT_TRANS_PREPARE_ERROR to deal with bound set/chain

   - eth: mlx5e:
      - fix scheduling of IPsec ASO query while in atomic
      - free IRQ rmap and notifier on kernel shutdown

  Current release - new code bugs:

   - phy: manual remove LEDs to ensure correct ordering

  Previous releases - regressions:

   - mptcp: fix possible divide by zero in recvmsg()

   - dsa: revert "net: phy: dp83867: perform soft reset and retain
     established link"

  Previous releases - always broken:

   - sched: netem: acquire qdisc lock in netem_change()

   - bpf:
      - fix verifier id tracking of scalars on spill
      - fix NULL dereference on exceptions
      - accept function names that contain dots

   - netfilter: disallow element updates of bound anonymous sets

   - mptcp: ensure listener is unhashed before updating the sk status

   - xfrm:
      - add missed call to delete offloaded policies
      - fix inbound ipv4/udp/esp packets to UDPv6 dualstack sockets

   - selftests: fixes for FIPS mode

   - dsa: mt7530: fix multiple CPU ports, BPDU and LLDP handling

   - eth: sfc: use budget for TX completions

  Misc:

   - wifi: iwlwifi: add support for SO-F device with PCI id 0x7AF0"

* tag 'net-6.4-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net: (74 commits)
  revert "net: align SO_RCVMARK required privileges with SO_MARK"
  net: wwan: iosm: Convert single instance struct member to flexible array
  sch_netem: acquire qdisc lock in netem_change()
  selftests: forwarding: Fix race condition in mirror installation
  wifi: mac80211: report all unusable beacon frames
  mptcp: ensure listener is unhashed before updating the sk status
  mptcp: drop legacy code around RX EOF
  mptcp: consolidate fallback and non fallback state machine
  mptcp: fix possible list corruption on passive MPJ
  mptcp: fix possible divide by zero in recvmsg()
  mptcp: handle correctly disconnect() failures
  bpf: Force kprobe multi expected_attach_type for kprobe_multi link
  bpf/btf: Accept function names that contain dots
  Revert "net: phy: dp83867: perform soft reset and retain established link"
  net: mdio: fix the wrong parameters
  netfilter: nf_tables: Fix for deleting base chains with payload
  netfilter: nfnetlink_osf: fix module autoload
  netfilter: nf_tables: drop module reference after updating chain
  netfilter: nf_tables: disallow timeout for anonymous sets
  netfilter: nf_tables: disallow updates of anonymous sets
  ...
This commit is contained in:
Linus Torvalds 2023-06-22 17:59:51 -07:00
commit 8a28a0b6f1
78 changed files with 1178 additions and 351 deletions

View File

@ -9972,8 +9972,9 @@ M: Miquel Raynal <miquel.raynal@bootlin.com>
L: linux-wpan@vger.kernel.org L: linux-wpan@vger.kernel.org
S: Maintained S: Maintained
W: https://linux-wpan.org/ W: https://linux-wpan.org/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/sschmidt/wpan.git Q: https://patchwork.kernel.org/project/linux-wpan/list/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/sschmidt/wpan-next.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/wpan/wpan.git
T: git git://git.kernel.org/pub/scm/linux/kernel/git/wpan/wpan-next.git
F: Documentation/networking/ieee802154.rst F: Documentation/networking/ieee802154.rst
F: drivers/net/ieee802154/ F: drivers/net/ieee802154/
F: include/linux/ieee802154.h F: include/linux/ieee802154.h
@ -13269,10 +13270,11 @@ F: drivers/memory/mtk-smi.c
F: include/soc/mediatek/smi.h F: include/soc/mediatek/smi.h
MEDIATEK SWITCH DRIVER MEDIATEK SWITCH DRIVER
M: Sean Wang <sean.wang@mediatek.com> M: Arınç ÜNAL <arinc.unal@arinc9.com>
M: Daniel Golle <daniel@makrotopia.org>
M: Landen Chao <Landen.Chao@mediatek.com> M: Landen Chao <Landen.Chao@mediatek.com>
M: DENG Qingfang <dqfext@gmail.com> M: DENG Qingfang <dqfext@gmail.com>
M: Daniel Golle <daniel@makrotopia.org> M: Sean Wang <sean.wang@mediatek.com>
L: netdev@vger.kernel.org L: netdev@vger.kernel.org
S: Maintained S: Maintained
F: drivers/net/dsa/mt7530-mdio.c F: drivers/net/dsa/mt7530-mdio.c

View File

@ -2570,7 +2570,7 @@ out_image:
} }
if (bpf_jit_enable > 1) if (bpf_jit_enable > 1)
bpf_jit_dump(prog->len, proglen, pass + 1, image); bpf_jit_dump(prog->len, proglen, pass + 1, rw_image);
if (image) { if (image) {
if (!prog->is_func || extra_pass) { if (!prog->is_func || extra_pass) {

View File

@ -399,6 +399,20 @@ static void mt7530_pll_setup(struct mt7530_priv *priv)
core_set(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN); core_set(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN);
} }
/* If port 6 is available as a CPU port, always prefer that as the default,
* otherwise don't care.
*/
static struct dsa_port *
mt753x_preferred_default_local_cpu_port(struct dsa_switch *ds)
{
struct dsa_port *cpu_dp = dsa_to_port(ds, 6);
if (dsa_port_is_cpu(cpu_dp))
return cpu_dp;
return NULL;
}
/* Setup port 6 interface mode and TRGMII TX circuit */ /* Setup port 6 interface mode and TRGMII TX circuit */
static int static int
mt7530_pad_clk_setup(struct dsa_switch *ds, phy_interface_t interface) mt7530_pad_clk_setup(struct dsa_switch *ds, phy_interface_t interface)
@ -985,6 +999,18 @@ unlock_exit:
mutex_unlock(&priv->reg_mutex); mutex_unlock(&priv->reg_mutex);
} }
static void
mt753x_trap_frames(struct mt7530_priv *priv)
{
/* Trap BPDUs to the CPU port(s) */
mt7530_rmw(priv, MT753X_BPC, MT753X_BPDU_PORT_FW_MASK,
MT753X_BPDU_CPU_ONLY);
/* Trap LLDP frames with :0E MAC DA to the CPU port(s) */
mt7530_rmw(priv, MT753X_RGAC2, MT753X_R0E_PORT_FW_MASK,
MT753X_R0E_PORT_FW(MT753X_BPDU_CPU_ONLY));
}
static int static int
mt753x_cpu_port_enable(struct dsa_switch *ds, int port) mt753x_cpu_port_enable(struct dsa_switch *ds, int port)
{ {
@ -1007,9 +1033,16 @@ mt753x_cpu_port_enable(struct dsa_switch *ds, int port)
UNU_FFP(BIT(port))); UNU_FFP(BIT(port)));
/* Set CPU port number */ /* Set CPU port number */
if (priv->id == ID_MT7621) if (priv->id == ID_MT7530 || priv->id == ID_MT7621)
mt7530_rmw(priv, MT7530_MFC, CPU_MASK, CPU_EN | CPU_PORT(port)); mt7530_rmw(priv, MT7530_MFC, CPU_MASK, CPU_EN | CPU_PORT(port));
/* Add the CPU port to the CPU port bitmap for MT7531 and the switch on
* the MT7988 SoC. Trapped frames will be forwarded to the CPU port that
* is affine to the inbound user port.
*/
if (priv->id == ID_MT7531 || priv->id == ID_MT7988)
mt7530_set(priv, MT7531_CFC, MT7531_CPU_PMAP(BIT(port)));
/* CPU port gets connected to all user ports of /* CPU port gets connected to all user ports of
* the switch. * the switch.
*/ */
@ -2255,6 +2288,8 @@ mt7530_setup(struct dsa_switch *ds)
priv->p6_interface = PHY_INTERFACE_MODE_NA; priv->p6_interface = PHY_INTERFACE_MODE_NA;
mt753x_trap_frames(priv);
/* Enable and reset MIB counters */ /* Enable and reset MIB counters */
mt7530_mib_reset(ds); mt7530_mib_reset(ds);
@ -2352,17 +2387,9 @@ static int
mt7531_setup_common(struct dsa_switch *ds) mt7531_setup_common(struct dsa_switch *ds)
{ {
struct mt7530_priv *priv = ds->priv; struct mt7530_priv *priv = ds->priv;
struct dsa_port *cpu_dp;
int ret, i; int ret, i;
/* BPDU to CPU port */ mt753x_trap_frames(priv);
dsa_switch_for_each_cpu_port(cpu_dp, ds) {
mt7530_rmw(priv, MT7531_CFC, MT7531_CPU_PMAP_MASK,
BIT(cpu_dp->index));
break;
}
mt7530_rmw(priv, MT753X_BPC, MT753X_BPDU_PORT_FW_MASK,
MT753X_BPDU_CPU_ONLY);
/* Enable and reset MIB counters */ /* Enable and reset MIB counters */
mt7530_mib_reset(ds); mt7530_mib_reset(ds);
@ -3085,6 +3112,7 @@ static int mt7988_setup(struct dsa_switch *ds)
const struct dsa_switch_ops mt7530_switch_ops = { const struct dsa_switch_ops mt7530_switch_ops = {
.get_tag_protocol = mtk_get_tag_protocol, .get_tag_protocol = mtk_get_tag_protocol,
.setup = mt753x_setup, .setup = mt753x_setup,
.preferred_default_local_cpu_port = mt753x_preferred_default_local_cpu_port,
.get_strings = mt7530_get_strings, .get_strings = mt7530_get_strings,
.get_ethtool_stats = mt7530_get_ethtool_stats, .get_ethtool_stats = mt7530_get_ethtool_stats,
.get_sset_count = mt7530_get_sset_count, .get_sset_count = mt7530_get_sset_count,

View File

@ -54,6 +54,7 @@ enum mt753x_id {
#define MT7531_MIRROR_PORT_GET(x) (((x) >> 16) & MIRROR_MASK) #define MT7531_MIRROR_PORT_GET(x) (((x) >> 16) & MIRROR_MASK)
#define MT7531_MIRROR_PORT_SET(x) (((x) & MIRROR_MASK) << 16) #define MT7531_MIRROR_PORT_SET(x) (((x) & MIRROR_MASK) << 16)
#define MT7531_CPU_PMAP_MASK GENMASK(7, 0) #define MT7531_CPU_PMAP_MASK GENMASK(7, 0)
#define MT7531_CPU_PMAP(x) FIELD_PREP(MT7531_CPU_PMAP_MASK, x)
#define MT753X_MIRROR_REG(id) ((((id) == ID_MT7531) || ((id) == ID_MT7988)) ? \ #define MT753X_MIRROR_REG(id) ((((id) == ID_MT7531) || ((id) == ID_MT7988)) ? \
MT7531_CFC : MT7530_MFC) MT7531_CFC : MT7530_MFC)
@ -66,6 +67,11 @@ enum mt753x_id {
#define MT753X_BPC 0x24 #define MT753X_BPC 0x24
#define MT753X_BPDU_PORT_FW_MASK GENMASK(2, 0) #define MT753X_BPDU_PORT_FW_MASK GENMASK(2, 0)
/* Register for :03 and :0E MAC DA frame control */
#define MT753X_RGAC2 0x2c
#define MT753X_R0E_PORT_FW_MASK GENMASK(18, 16)
#define MT753X_R0E_PORT_FW(x) FIELD_PREP(MT753X_R0E_PORT_FW_MASK, x)
enum mt753x_bpdu_port_fw { enum mt753x_bpdu_port_fw {
MT753X_BPDU_FOLLOW_MFC, MT753X_BPDU_FOLLOW_MFC,
MT753X_BPDU_CPU_EXCLUDE = 4, MT753X_BPDU_CPU_EXCLUDE = 4,

View File

@ -1135,8 +1135,8 @@ static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter,
eth_hdr_len = ntohs(skb->protocol) == ETH_P_8021Q ? eth_hdr_len = ntohs(skb->protocol) == ETH_P_8021Q ?
VLAN_ETH_HLEN : ETH_HLEN; VLAN_ETH_HLEN : ETH_HLEN;
if (skb->len <= 60 && if (skb->len <= 60 &&
(lancer_chip(adapter) || skb_vlan_tag_present(skb)) && (lancer_chip(adapter) || BE3_chip(adapter) ||
is_ipv4_pkt(skb)) { skb_vlan_tag_present(skb)) && is_ipv4_pkt(skb)) {
ip = (struct iphdr *)ip_hdr(skb); ip = (struct iphdr *)ip_hdr(skb);
pskb_trim(skb, eth_hdr_len + ntohs(ip->tot_len)); pskb_trim(skb, eth_hdr_len + ntohs(ip->tot_len));
} }

View File

@ -54,6 +54,9 @@ static int phy_mode(enum dpmac_eth_if eth_if, phy_interface_t *if_mode)
case DPMAC_ETH_IF_XFI: case DPMAC_ETH_IF_XFI:
*if_mode = PHY_INTERFACE_MODE_10GBASER; *if_mode = PHY_INTERFACE_MODE_10GBASER;
break; break;
case DPMAC_ETH_IF_CAUI:
*if_mode = PHY_INTERFACE_MODE_25GBASER;
break;
default: default:
return -EINVAL; return -EINVAL;
} }
@ -79,6 +82,8 @@ static enum dpmac_eth_if dpmac_eth_if_mode(phy_interface_t if_mode)
return DPMAC_ETH_IF_XFI; return DPMAC_ETH_IF_XFI;
case PHY_INTERFACE_MODE_1000BASEX: case PHY_INTERFACE_MODE_1000BASEX:
return DPMAC_ETH_IF_1000BASEX; return DPMAC_ETH_IF_1000BASEX;
case PHY_INTERFACE_MODE_25GBASER:
return DPMAC_ETH_IF_CAUI;
default: default:
return DPMAC_ETH_IF_MII; return DPMAC_ETH_IF_MII;
} }
@ -418,7 +423,7 @@ int dpaa2_mac_connect(struct dpaa2_mac *mac)
mac->phylink_config.mac_capabilities = MAC_SYM_PAUSE | MAC_ASYM_PAUSE | mac->phylink_config.mac_capabilities = MAC_SYM_PAUSE | MAC_ASYM_PAUSE |
MAC_10FD | MAC_100FD | MAC_1000FD | MAC_2500FD | MAC_5000FD | MAC_10FD | MAC_100FD | MAC_1000FD | MAC_2500FD | MAC_5000FD |
MAC_10000FD; MAC_10000FD | MAC_25000FD;
dpaa2_mac_set_supported_interfaces(mac); dpaa2_mac_set_supported_interfaces(mac);

View File

@ -732,7 +732,8 @@ static void mlx5e_rx_compute_wqe_bulk_params(struct mlx5e_params *params,
static int mlx5e_build_rq_frags_info(struct mlx5_core_dev *mdev, static int mlx5e_build_rq_frags_info(struct mlx5_core_dev *mdev,
struct mlx5e_params *params, struct mlx5e_params *params,
struct mlx5e_xsk_param *xsk, struct mlx5e_xsk_param *xsk,
struct mlx5e_rq_frags_info *info) struct mlx5e_rq_frags_info *info,
u32 *xdp_frag_size)
{ {
u32 byte_count = MLX5E_SW2HW_MTU(params, params->sw_mtu); u32 byte_count = MLX5E_SW2HW_MTU(params, params->sw_mtu);
int frag_size_max = DEFAULT_FRAG_SIZE; int frag_size_max = DEFAULT_FRAG_SIZE;
@ -845,6 +846,8 @@ out:
info->log_num_frags = order_base_2(info->num_frags); info->log_num_frags = order_base_2(info->num_frags);
*xdp_frag_size = info->num_frags > 1 && params->xdp_prog ? PAGE_SIZE : 0;
return 0; return 0;
} }
@ -989,7 +992,8 @@ int mlx5e_build_rq_param(struct mlx5_core_dev *mdev,
} }
default: /* MLX5_WQ_TYPE_CYCLIC */ default: /* MLX5_WQ_TYPE_CYCLIC */
MLX5_SET(wq, wq, log_wq_sz, params->log_rq_mtu_frames); MLX5_SET(wq, wq, log_wq_sz, params->log_rq_mtu_frames);
err = mlx5e_build_rq_frags_info(mdev, params, xsk, &param->frags_info); err = mlx5e_build_rq_frags_info(mdev, params, xsk, &param->frags_info,
&param->xdp_frag_size);
if (err) if (err)
return err; return err;
ndsegs = param->frags_info.num_frags; ndsegs = param->frags_info.num_frags;

View File

@ -24,6 +24,7 @@ struct mlx5e_rq_param {
u32 rqc[MLX5_ST_SZ_DW(rqc)]; u32 rqc[MLX5_ST_SZ_DW(rqc)];
struct mlx5_wq_param wq; struct mlx5_wq_param wq;
struct mlx5e_rq_frags_info frags_info; struct mlx5e_rq_frags_info frags_info;
u32 xdp_frag_size;
}; };
struct mlx5e_sq_param { struct mlx5e_sq_param {

View File

@ -2021,6 +2021,8 @@ void
mlx5_tc_ct_delete_flow(struct mlx5_tc_ct_priv *priv, mlx5_tc_ct_delete_flow(struct mlx5_tc_ct_priv *priv,
struct mlx5_flow_attr *attr) struct mlx5_flow_attr *attr)
{ {
if (!attr->ct_attr.ft) /* no ct action, return */
return;
if (!attr->ct_attr.nf_ft) /* means only ct clear action, and not ct_clear,ct() */ if (!attr->ct_attr.nf_ft) /* means only ct clear action, and not ct_clear,ct() */
return; return;

View File

@ -86,7 +86,7 @@ static int mlx5e_init_xsk_rq(struct mlx5e_channel *c,
if (err) if (err)
return err; return err;
return xdp_rxq_info_reg(&rq->xdp_rxq, rq->netdev, rq_xdp_ix, 0); return xdp_rxq_info_reg(&rq->xdp_rxq, rq->netdev, rq_xdp_ix, c->napi.napi_id);
} }
static int mlx5e_open_xsk_rq(struct mlx5e_channel *c, struct mlx5e_params *params, static int mlx5e_open_xsk_rq(struct mlx5e_channel *c, struct mlx5e_params *params,

View File

@ -61,16 +61,19 @@ static void mlx5e_ipsec_handle_tx_limit(struct work_struct *_work)
struct mlx5e_ipsec_sa_entry *sa_entry = dwork->sa_entry; struct mlx5e_ipsec_sa_entry *sa_entry = dwork->sa_entry;
struct xfrm_state *x = sa_entry->x; struct xfrm_state *x = sa_entry->x;
spin_lock(&x->lock); if (sa_entry->attrs.drop)
return;
spin_lock_bh(&x->lock);
xfrm_state_check_expire(x); xfrm_state_check_expire(x);
if (x->km.state == XFRM_STATE_EXPIRED) { if (x->km.state == XFRM_STATE_EXPIRED) {
sa_entry->attrs.drop = true; sa_entry->attrs.drop = true;
mlx5e_accel_ipsec_fs_modify(sa_entry); spin_unlock_bh(&x->lock);
}
spin_unlock(&x->lock);
if (sa_entry->attrs.drop) mlx5e_accel_ipsec_fs_modify(sa_entry);
return; return;
}
spin_unlock_bh(&x->lock);
queue_delayed_work(sa_entry->ipsec->wq, &dwork->dwork, queue_delayed_work(sa_entry->ipsec->wq, &dwork->dwork,
MLX5_IPSEC_RESCHED); MLX5_IPSEC_RESCHED);
@ -1040,11 +1043,17 @@ err_fs:
return err; return err;
} }
static void mlx5e_xfrm_free_policy(struct xfrm_policy *x) static void mlx5e_xfrm_del_policy(struct xfrm_policy *x)
{ {
struct mlx5e_ipsec_pol_entry *pol_entry = to_ipsec_pol_entry(x); struct mlx5e_ipsec_pol_entry *pol_entry = to_ipsec_pol_entry(x);
mlx5e_accel_ipsec_fs_del_pol(pol_entry); mlx5e_accel_ipsec_fs_del_pol(pol_entry);
}
static void mlx5e_xfrm_free_policy(struct xfrm_policy *x)
{
struct mlx5e_ipsec_pol_entry *pol_entry = to_ipsec_pol_entry(x);
kfree(pol_entry); kfree(pol_entry);
} }
@ -1065,6 +1074,7 @@ static const struct xfrmdev_ops mlx5e_ipsec_packet_xfrmdev_ops = {
.xdo_dev_state_update_curlft = mlx5e_xfrm_update_curlft, .xdo_dev_state_update_curlft = mlx5e_xfrm_update_curlft,
.xdo_dev_policy_add = mlx5e_xfrm_add_policy, .xdo_dev_policy_add = mlx5e_xfrm_add_policy,
.xdo_dev_policy_delete = mlx5e_xfrm_del_policy,
.xdo_dev_policy_free = mlx5e_xfrm_free_policy, .xdo_dev_policy_free = mlx5e_xfrm_free_policy,
}; };

View File

@ -305,7 +305,17 @@ static void mlx5e_ipsec_update_esn_state(struct mlx5e_ipsec_sa_entry *sa_entry,
} }
mlx5e_ipsec_build_accel_xfrm_attrs(sa_entry, &attrs); mlx5e_ipsec_build_accel_xfrm_attrs(sa_entry, &attrs);
/* It is safe to execute the modify below unlocked since the only flows
* that could affect this HW object, are create, destroy and this work.
*
* Creation flow can't co-exist with this modify work, the destruction
* flow would cancel this work, and this work is a single entity that
* can't conflict with it self.
*/
spin_unlock_bh(&sa_entry->x->lock);
mlx5_accel_esp_modify_xfrm(sa_entry, &attrs); mlx5_accel_esp_modify_xfrm(sa_entry, &attrs);
spin_lock_bh(&sa_entry->x->lock);
data.data_offset_condition_operand = data.data_offset_condition_operand =
MLX5_IPSEC_ASO_REMOVE_FLOW_PKT_CNT_OFFSET; MLX5_IPSEC_ASO_REMOVE_FLOW_PKT_CNT_OFFSET;
@ -431,7 +441,7 @@ static void mlx5e_ipsec_handle_event(struct work_struct *_work)
aso = sa_entry->ipsec->aso; aso = sa_entry->ipsec->aso;
attrs = &sa_entry->attrs; attrs = &sa_entry->attrs;
spin_lock(&sa_entry->x->lock); spin_lock_bh(&sa_entry->x->lock);
ret = mlx5e_ipsec_aso_query(sa_entry, NULL); ret = mlx5e_ipsec_aso_query(sa_entry, NULL);
if (ret) if (ret)
goto unlock; goto unlock;
@ -447,7 +457,7 @@ static void mlx5e_ipsec_handle_event(struct work_struct *_work)
mlx5e_ipsec_handle_limits(sa_entry); mlx5e_ipsec_handle_limits(sa_entry);
unlock: unlock:
spin_unlock(&sa_entry->x->lock); spin_unlock_bh(&sa_entry->x->lock);
kfree(work); kfree(work);
} }
@ -596,7 +606,8 @@ int mlx5e_ipsec_aso_query(struct mlx5e_ipsec_sa_entry *sa_entry,
do { do {
ret = mlx5_aso_poll_cq(aso->aso, false); ret = mlx5_aso_poll_cq(aso->aso, false);
if (ret) if (ret)
usleep_range(2, 10); /* We are in atomic context */
udelay(10);
} while (ret && time_is_after_jiffies(expires)); } while (ret && time_is_after_jiffies(expires));
spin_unlock_bh(&aso->lock); spin_unlock_bh(&aso->lock);
return ret; return ret;

View File

@ -641,7 +641,7 @@ static void mlx5e_free_mpwqe_rq_drop_page(struct mlx5e_rq *rq)
} }
static int mlx5e_init_rxq_rq(struct mlx5e_channel *c, struct mlx5e_params *params, static int mlx5e_init_rxq_rq(struct mlx5e_channel *c, struct mlx5e_params *params,
struct mlx5e_rq *rq) u32 xdp_frag_size, struct mlx5e_rq *rq)
{ {
struct mlx5_core_dev *mdev = c->mdev; struct mlx5_core_dev *mdev = c->mdev;
int err; int err;
@ -665,7 +665,8 @@ static int mlx5e_init_rxq_rq(struct mlx5e_channel *c, struct mlx5e_params *param
if (err) if (err)
return err; return err;
return xdp_rxq_info_reg(&rq->xdp_rxq, rq->netdev, rq->ix, c->napi.napi_id); return __xdp_rxq_info_reg(&rq->xdp_rxq, rq->netdev, rq->ix, c->napi.napi_id,
xdp_frag_size);
} }
static int mlx5_rq_shampo_alloc(struct mlx5_core_dev *mdev, static int mlx5_rq_shampo_alloc(struct mlx5_core_dev *mdev,
@ -2240,7 +2241,7 @@ static int mlx5e_open_rxq_rq(struct mlx5e_channel *c, struct mlx5e_params *param
{ {
int err; int err;
err = mlx5e_init_rxq_rq(c, params, &c->rq); err = mlx5e_init_rxq_rq(c, params, rq_params->xdp_frag_size, &c->rq);
if (err) if (err)
return err; return err;

View File

@ -1439,6 +1439,7 @@ static void mlx5e_tc_del_nic_flow(struct mlx5e_priv *priv,
mlx5e_hairpin_flow_del(priv, flow); mlx5e_hairpin_flow_del(priv, flow);
free_flow_post_acts(flow); free_flow_post_acts(flow);
mlx5_tc_ct_delete_flow(get_ct_priv(flow->priv), attr);
kvfree(attr->parse_attr); kvfree(attr->parse_attr);
kfree(flow->attr); kfree(flow->attr);

View File

@ -511,10 +511,11 @@ static int mlx5_cmd_set_fte(struct mlx5_core_dev *dev,
struct mlx5_flow_rule *dst; struct mlx5_flow_rule *dst;
void *in_flow_context, *vlan; void *in_flow_context, *vlan;
void *in_match_value; void *in_match_value;
int reformat_id = 0;
unsigned int inlen; unsigned int inlen;
int dst_cnt_size; int dst_cnt_size;
u32 *in, action;
void *in_dests; void *in_dests;
u32 *in;
int err; int err;
if (mlx5_set_extended_dest(dev, fte, &extended_dest)) if (mlx5_set_extended_dest(dev, fte, &extended_dest))
@ -553,22 +554,42 @@ static int mlx5_cmd_set_fte(struct mlx5_core_dev *dev,
MLX5_SET(flow_context, in_flow_context, extended_destination, MLX5_SET(flow_context, in_flow_context, extended_destination,
extended_dest); extended_dest);
if (extended_dest) {
u32 action;
action = fte->action.action & action = fte->action.action;
~MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT; if (extended_dest)
MLX5_SET(flow_context, in_flow_context, action, action); action &= ~MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT;
} else {
MLX5_SET(flow_context, in_flow_context, action, MLX5_SET(flow_context, in_flow_context, action, action);
fte->action.action);
if (fte->action.pkt_reformat) if (!extended_dest && fte->action.pkt_reformat) {
MLX5_SET(flow_context, in_flow_context, packet_reformat_id, struct mlx5_pkt_reformat *pkt_reformat = fte->action.pkt_reformat;
fte->action.pkt_reformat->id);
if (pkt_reformat->owner == MLX5_FLOW_RESOURCE_OWNER_SW) {
reformat_id = mlx5_fs_dr_action_get_pkt_reformat_id(pkt_reformat);
if (reformat_id < 0) {
mlx5_core_err(dev,
"Unsupported SW-owned pkt_reformat type (%d) in FW-owned table\n",
pkt_reformat->reformat_type);
err = reformat_id;
goto err_out;
}
} else {
reformat_id = fte->action.pkt_reformat->id;
}
} }
if (fte->action.modify_hdr)
MLX5_SET(flow_context, in_flow_context, packet_reformat_id, (u32)reformat_id);
if (fte->action.modify_hdr) {
if (fte->action.modify_hdr->owner == MLX5_FLOW_RESOURCE_OWNER_SW) {
mlx5_core_err(dev, "Can't use SW-owned modify_hdr in FW-owned table\n");
err = -EOPNOTSUPP;
goto err_out;
}
MLX5_SET(flow_context, in_flow_context, modify_header_id, MLX5_SET(flow_context, in_flow_context, modify_header_id,
fte->action.modify_hdr->id); fte->action.modify_hdr->id);
}
MLX5_SET(flow_context, in_flow_context, encrypt_decrypt_type, MLX5_SET(flow_context, in_flow_context, encrypt_decrypt_type,
fte->action.crypto.type); fte->action.crypto.type);
@ -885,6 +906,8 @@ static int mlx5_cmd_packet_reformat_alloc(struct mlx5_flow_root_namespace *ns,
pkt_reformat->id = MLX5_GET(alloc_packet_reformat_context_out, pkt_reformat->id = MLX5_GET(alloc_packet_reformat_context_out,
out, packet_reformat_id); out, packet_reformat_id);
pkt_reformat->owner = MLX5_FLOW_RESOURCE_OWNER_FW;
kfree(in); kfree(in);
return err; return err;
} }
@ -969,6 +992,7 @@ static int mlx5_cmd_modify_header_alloc(struct mlx5_flow_root_namespace *ns,
err = mlx5_cmd_exec(dev, in, inlen, out, sizeof(out)); err = mlx5_cmd_exec(dev, in, inlen, out, sizeof(out));
modify_hdr->id = MLX5_GET(alloc_modify_header_context_out, out, modify_header_id); modify_hdr->id = MLX5_GET(alloc_modify_header_context_out, out, modify_header_id);
modify_hdr->owner = MLX5_FLOW_RESOURCE_OWNER_FW;
kfree(in); kfree(in);
return err; return err;
} }

View File

@ -54,8 +54,14 @@ struct mlx5_flow_definer {
u32 id; u32 id;
}; };
enum mlx5_flow_resource_owner {
MLX5_FLOW_RESOURCE_OWNER_FW,
MLX5_FLOW_RESOURCE_OWNER_SW,
};
struct mlx5_modify_hdr { struct mlx5_modify_hdr {
enum mlx5_flow_namespace_type ns_type; enum mlx5_flow_namespace_type ns_type;
enum mlx5_flow_resource_owner owner;
union { union {
struct mlx5_fs_dr_action action; struct mlx5_fs_dr_action action;
u32 id; u32 id;
@ -65,6 +71,7 @@ struct mlx5_modify_hdr {
struct mlx5_pkt_reformat { struct mlx5_pkt_reformat {
enum mlx5_flow_namespace_type ns_type; enum mlx5_flow_namespace_type ns_type;
int reformat_type; /* from mlx5_ifc */ int reformat_type; /* from mlx5_ifc */
enum mlx5_flow_resource_owner owner;
union { union {
struct mlx5_fs_dr_action action; struct mlx5_fs_dr_action action;
u32 id; u32 id;

View File

@ -126,14 +126,22 @@ out:
return ret; return ret;
} }
static void irq_release(struct mlx5_irq *irq) /* mlx5_system_free_irq - Free an IRQ
* @irq: IRQ to free
*
* Free the IRQ and other resources such as rmap from the system.
* BUT doesn't free or remove reference from mlx5.
* This function is very important for the shutdown flow, where we need to
* cleanup system resoruces but keep mlx5 objects alive,
* see mlx5_irq_table_free_irqs().
*/
static void mlx5_system_free_irq(struct mlx5_irq *irq)
{ {
struct mlx5_irq_pool *pool = irq->pool; struct mlx5_irq_pool *pool = irq->pool;
#ifdef CONFIG_RFS_ACCEL #ifdef CONFIG_RFS_ACCEL
struct cpu_rmap *rmap; struct cpu_rmap *rmap;
#endif #endif
xa_erase(&pool->irqs, irq->pool_index);
/* free_irq requires that affinity_hint and rmap will be cleared before /* free_irq requires that affinity_hint and rmap will be cleared before
* calling it. To satisfy this requirement, we call * calling it. To satisfy this requirement, we call
* irq_cpu_rmap_remove() to remove the notifier * irq_cpu_rmap_remove() to remove the notifier
@ -145,10 +153,18 @@ static void irq_release(struct mlx5_irq *irq)
irq_cpu_rmap_remove(rmap, irq->map.virq); irq_cpu_rmap_remove(rmap, irq->map.virq);
#endif #endif
free_cpumask_var(irq->mask);
free_irq(irq->map.virq, &irq->nh); free_irq(irq->map.virq, &irq->nh);
if (irq->map.index && pci_msix_can_alloc_dyn(pool->dev->pdev)) if (irq->map.index && pci_msix_can_alloc_dyn(pool->dev->pdev))
pci_msix_free_irq(pool->dev->pdev, irq->map); pci_msix_free_irq(pool->dev->pdev, irq->map);
}
static void irq_release(struct mlx5_irq *irq)
{
struct mlx5_irq_pool *pool = irq->pool;
xa_erase(&pool->irqs, irq->pool_index);
mlx5_system_free_irq(irq);
free_cpumask_var(irq->mask);
kfree(irq); kfree(irq);
} }
@ -565,15 +581,21 @@ void mlx5_irqs_release_vectors(struct mlx5_irq **irqs, int nirqs)
int mlx5_irqs_request_vectors(struct mlx5_core_dev *dev, u16 *cpus, int nirqs, int mlx5_irqs_request_vectors(struct mlx5_core_dev *dev, u16 *cpus, int nirqs,
struct mlx5_irq **irqs, struct cpu_rmap **rmap) struct mlx5_irq **irqs, struct cpu_rmap **rmap)
{ {
struct mlx5_irq_table *table = mlx5_irq_table_get(dev);
struct mlx5_irq_pool *pool = table->pcif_pool;
struct irq_affinity_desc af_desc; struct irq_affinity_desc af_desc;
struct mlx5_irq *irq; struct mlx5_irq *irq;
int offset = 1;
int i; int i;
if (!pool->xa_num_irqs.max)
offset = 0;
af_desc.is_managed = false; af_desc.is_managed = false;
for (i = 0; i < nirqs; i++) { for (i = 0; i < nirqs; i++) {
cpumask_clear(&af_desc.mask); cpumask_clear(&af_desc.mask);
cpumask_set_cpu(cpus[i], &af_desc.mask); cpumask_set_cpu(cpus[i], &af_desc.mask);
irq = mlx5_irq_request(dev, i + 1, &af_desc, rmap); irq = mlx5_irq_request(dev, i + offset, &af_desc, rmap);
if (IS_ERR(irq)) if (IS_ERR(irq))
break; break;
irqs[i] = irq; irqs[i] = irq;
@ -699,7 +721,8 @@ static void mlx5_irq_pool_free_irqs(struct mlx5_irq_pool *pool)
unsigned long index; unsigned long index;
xa_for_each(&pool->irqs, index, irq) xa_for_each(&pool->irqs, index, irq)
free_irq(irq->map.virq, &irq->nh); mlx5_system_free_irq(irq);
} }
static void mlx5_irq_pools_free_irqs(struct mlx5_irq_table *table) static void mlx5_irq_pools_free_irqs(struct mlx5_irq_table *table)

View File

@ -1421,9 +1421,13 @@ dr_action_create_reformat_action(struct mlx5dr_domain *dmn,
} }
case DR_ACTION_TYP_TNL_L3_TO_L2: case DR_ACTION_TYP_TNL_L3_TO_L2:
{ {
u8 hw_actions[DR_ACTION_CACHE_LINE_SIZE] = {}; u8 *hw_actions;
int ret; int ret;
hw_actions = kzalloc(DR_ACTION_CACHE_LINE_SIZE, GFP_KERNEL);
if (!hw_actions)
return -ENOMEM;
ret = mlx5dr_ste_set_action_decap_l3_list(dmn->ste_ctx, ret = mlx5dr_ste_set_action_decap_l3_list(dmn->ste_ctx,
data, data_sz, data, data_sz,
hw_actions, hw_actions,
@ -1431,6 +1435,7 @@ dr_action_create_reformat_action(struct mlx5dr_domain *dmn,
&action->rewrite->num_of_actions); &action->rewrite->num_of_actions);
if (ret) { if (ret) {
mlx5dr_dbg(dmn, "Failed creating decap l3 action list\n"); mlx5dr_dbg(dmn, "Failed creating decap l3 action list\n");
kfree(hw_actions);
return ret; return ret;
} }
@ -1440,6 +1445,7 @@ dr_action_create_reformat_action(struct mlx5dr_domain *dmn,
ret = mlx5dr_ste_alloc_modify_hdr(action); ret = mlx5dr_ste_alloc_modify_hdr(action);
if (ret) { if (ret) {
mlx5dr_dbg(dmn, "Failed preparing reformat data\n"); mlx5dr_dbg(dmn, "Failed preparing reformat data\n");
kfree(hw_actions);
return ret; return ret;
} }
return 0; return 0;
@ -2129,6 +2135,11 @@ mlx5dr_action_create_aso(struct mlx5dr_domain *dmn, u32 obj_id,
return action; return action;
} }
u32 mlx5dr_action_get_pkt_reformat_id(struct mlx5dr_action *action)
{
return action->reformat->id;
}
int mlx5dr_action_destroy(struct mlx5dr_action *action) int mlx5dr_action_destroy(struct mlx5dr_action *action)
{ {
if (WARN_ON_ONCE(refcount_read(&action->refcount) > 1)) if (WARN_ON_ONCE(refcount_read(&action->refcount) > 1))

View File

@ -331,8 +331,16 @@ static int mlx5_cmd_dr_create_fte(struct mlx5_flow_root_namespace *ns,
} }
if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT) { if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT) {
bool is_decap = fte->action.pkt_reformat->reformat_type == bool is_decap;
MLX5_REFORMAT_TYPE_L3_TUNNEL_TO_L2;
if (fte->action.pkt_reformat->owner == MLX5_FLOW_RESOURCE_OWNER_FW) {
err = -EINVAL;
mlx5dr_err(domain, "FW-owned reformat can't be used in SW rule\n");
goto free_actions;
}
is_decap = fte->action.pkt_reformat->reformat_type ==
MLX5_REFORMAT_TYPE_L3_TUNNEL_TO_L2;
if (is_decap) if (is_decap)
actions[num_actions++] = actions[num_actions++] =
@ -661,6 +669,7 @@ static int mlx5_cmd_dr_packet_reformat_alloc(struct mlx5_flow_root_namespace *ns
return -EINVAL; return -EINVAL;
} }
pkt_reformat->owner = MLX5_FLOW_RESOURCE_OWNER_SW;
pkt_reformat->action.dr_action = action; pkt_reformat->action.dr_action = action;
return 0; return 0;
@ -691,6 +700,7 @@ static int mlx5_cmd_dr_modify_header_alloc(struct mlx5_flow_root_namespace *ns,
return -EINVAL; return -EINVAL;
} }
modify_hdr->owner = MLX5_FLOW_RESOURCE_OWNER_SW;
modify_hdr->action.dr_action = action; modify_hdr->action.dr_action = action;
return 0; return 0;
@ -816,6 +826,19 @@ static u32 mlx5_cmd_dr_get_capabilities(struct mlx5_flow_root_namespace *ns,
return steering_caps; return steering_caps;
} }
int mlx5_fs_dr_action_get_pkt_reformat_id(struct mlx5_pkt_reformat *pkt_reformat)
{
switch (pkt_reformat->reformat_type) {
case MLX5_REFORMAT_TYPE_L2_TO_VXLAN:
case MLX5_REFORMAT_TYPE_L2_TO_NVGRE:
case MLX5_REFORMAT_TYPE_L2_TO_L2_TUNNEL:
case MLX5_REFORMAT_TYPE_L2_TO_L3_TUNNEL:
case MLX5_REFORMAT_TYPE_INSERT_HDR:
return mlx5dr_action_get_pkt_reformat_id(pkt_reformat->action.dr_action);
}
return -EOPNOTSUPP;
}
bool mlx5_fs_dr_is_supported(struct mlx5_core_dev *dev) bool mlx5_fs_dr_is_supported(struct mlx5_core_dev *dev)
{ {
return mlx5dr_is_supported(dev); return mlx5dr_is_supported(dev);

View File

@ -38,6 +38,8 @@ struct mlx5_fs_dr_table {
bool mlx5_fs_dr_is_supported(struct mlx5_core_dev *dev); bool mlx5_fs_dr_is_supported(struct mlx5_core_dev *dev);
int mlx5_fs_dr_action_get_pkt_reformat_id(struct mlx5_pkt_reformat *pkt_reformat);
const struct mlx5_flow_cmds *mlx5_fs_cmd_get_dr_cmds(void); const struct mlx5_flow_cmds *mlx5_fs_cmd_get_dr_cmds(void);
#else #else
@ -47,6 +49,11 @@ static inline const struct mlx5_flow_cmds *mlx5_fs_cmd_get_dr_cmds(void)
return NULL; return NULL;
} }
static inline u32 mlx5_fs_dr_action_get_pkt_reformat_id(struct mlx5_pkt_reformat *pkt_reformat)
{
return 0;
}
static inline bool mlx5_fs_dr_is_supported(struct mlx5_core_dev *dev) static inline bool mlx5_fs_dr_is_supported(struct mlx5_core_dev *dev)
{ {
return false; return false;

View File

@ -150,6 +150,8 @@ mlx5dr_action_create_dest_match_range(struct mlx5dr_domain *dmn,
int mlx5dr_action_destroy(struct mlx5dr_action *action); int mlx5dr_action_destroy(struct mlx5dr_action *action);
u32 mlx5dr_action_get_pkt_reformat_id(struct mlx5dr_action *action);
int mlx5dr_definer_get(struct mlx5dr_domain *dmn, u16 format_id, int mlx5dr_definer_get(struct mlx5dr_domain *dmn, u16 format_id,
u8 *dw_selectors, u8 *byte_selectors, u8 *dw_selectors, u8 *byte_selectors,
u8 *match_mask, u32 *definer_id); u8 *match_mask, u32 *definer_id);

View File

@ -582,8 +582,7 @@ qcaspi_spi_thread(void *data)
while (!kthread_should_stop()) { while (!kthread_should_stop()) {
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
if ((qca->intr_req == qca->intr_svc) && if ((qca->intr_req == qca->intr_svc) &&
(qca->txr.skb[qca->txr.head] == NULL) && !qca->txr.skb[qca->txr.head])
(qca->sync == QCASPI_SYNC_READY))
schedule(); schedule();
set_current_state(TASK_RUNNING); set_current_state(TASK_RUNNING);

View File

@ -2950,7 +2950,7 @@ static u32 efx_ef10_extract_event_ts(efx_qword_t *event)
return tstamp; return tstamp;
} }
static void static int
efx_ef10_handle_tx_event(struct efx_channel *channel, efx_qword_t *event) efx_ef10_handle_tx_event(struct efx_channel *channel, efx_qword_t *event)
{ {
struct efx_nic *efx = channel->efx; struct efx_nic *efx = channel->efx;
@ -2958,13 +2958,14 @@ efx_ef10_handle_tx_event(struct efx_channel *channel, efx_qword_t *event)
unsigned int tx_ev_desc_ptr; unsigned int tx_ev_desc_ptr;
unsigned int tx_ev_q_label; unsigned int tx_ev_q_label;
unsigned int tx_ev_type; unsigned int tx_ev_type;
int work_done;
u64 ts_part; u64 ts_part;
if (unlikely(READ_ONCE(efx->reset_pending))) if (unlikely(READ_ONCE(efx->reset_pending)))
return; return 0;
if (unlikely(EFX_QWORD_FIELD(*event, ESF_DZ_TX_DROP_EVENT))) if (unlikely(EFX_QWORD_FIELD(*event, ESF_DZ_TX_DROP_EVENT)))
return; return 0;
/* Get the transmit queue */ /* Get the transmit queue */
tx_ev_q_label = EFX_QWORD_FIELD(*event, ESF_DZ_TX_QLABEL); tx_ev_q_label = EFX_QWORD_FIELD(*event, ESF_DZ_TX_QLABEL);
@ -2973,8 +2974,7 @@ efx_ef10_handle_tx_event(struct efx_channel *channel, efx_qword_t *event)
if (!tx_queue->timestamping) { if (!tx_queue->timestamping) {
/* Transmit completion */ /* Transmit completion */
tx_ev_desc_ptr = EFX_QWORD_FIELD(*event, ESF_DZ_TX_DESCR_INDX); tx_ev_desc_ptr = EFX_QWORD_FIELD(*event, ESF_DZ_TX_DESCR_INDX);
efx_xmit_done(tx_queue, tx_ev_desc_ptr & tx_queue->ptr_mask); return efx_xmit_done(tx_queue, tx_ev_desc_ptr & tx_queue->ptr_mask);
return;
} }
/* Transmit timestamps are only available for 8XXX series. They result /* Transmit timestamps are only available for 8XXX series. They result
@ -3000,6 +3000,7 @@ efx_ef10_handle_tx_event(struct efx_channel *channel, efx_qword_t *event)
* fields in the event. * fields in the event.
*/ */
tx_ev_type = EFX_QWORD_FIELD(*event, ESF_EZ_TX_SOFT1); tx_ev_type = EFX_QWORD_FIELD(*event, ESF_EZ_TX_SOFT1);
work_done = 0;
switch (tx_ev_type) { switch (tx_ev_type) {
case TX_TIMESTAMP_EVENT_TX_EV_COMPLETION: case TX_TIMESTAMP_EVENT_TX_EV_COMPLETION:
@ -3016,6 +3017,7 @@ efx_ef10_handle_tx_event(struct efx_channel *channel, efx_qword_t *event)
tx_queue->completed_timestamp_major = ts_part; tx_queue->completed_timestamp_major = ts_part;
efx_xmit_done_single(tx_queue); efx_xmit_done_single(tx_queue);
work_done = 1;
break; break;
default: default:
@ -3026,6 +3028,8 @@ efx_ef10_handle_tx_event(struct efx_channel *channel, efx_qword_t *event)
EFX_QWORD_VAL(*event)); EFX_QWORD_VAL(*event));
break; break;
} }
return work_done;
} }
static void static void
@ -3081,13 +3085,16 @@ static void efx_ef10_handle_driver_generated_event(struct efx_channel *channel,
} }
} }
#define EFX_NAPI_MAX_TX 512
static int efx_ef10_ev_process(struct efx_channel *channel, int quota) static int efx_ef10_ev_process(struct efx_channel *channel, int quota)
{ {
struct efx_nic *efx = channel->efx; struct efx_nic *efx = channel->efx;
efx_qword_t event, *p_event; efx_qword_t event, *p_event;
unsigned int read_ptr; unsigned int read_ptr;
int ev_code; int spent_tx = 0;
int spent = 0; int spent = 0;
int ev_code;
if (quota <= 0) if (quota <= 0)
return spent; return spent;
@ -3126,7 +3133,11 @@ static int efx_ef10_ev_process(struct efx_channel *channel, int quota)
} }
break; break;
case ESE_DZ_EV_CODE_TX_EV: case ESE_DZ_EV_CODE_TX_EV:
efx_ef10_handle_tx_event(channel, &event); spent_tx += efx_ef10_handle_tx_event(channel, &event);
if (spent_tx >= EFX_NAPI_MAX_TX) {
spent = quota;
goto out;
}
break; break;
case ESE_DZ_EV_CODE_DRIVER_EV: case ESE_DZ_EV_CODE_DRIVER_EV:
efx_ef10_handle_driver_event(channel, &event); efx_ef10_handle_driver_event(channel, &event);

View File

@ -253,6 +253,8 @@ static void ef100_ev_read_ack(struct efx_channel *channel)
efx_reg(channel->efx, ER_GZ_EVQ_INT_PRIME)); efx_reg(channel->efx, ER_GZ_EVQ_INT_PRIME));
} }
#define EFX_NAPI_MAX_TX 512
static int ef100_ev_process(struct efx_channel *channel, int quota) static int ef100_ev_process(struct efx_channel *channel, int quota)
{ {
struct efx_nic *efx = channel->efx; struct efx_nic *efx = channel->efx;
@ -260,6 +262,7 @@ static int ef100_ev_process(struct efx_channel *channel, int quota)
bool evq_phase, old_evq_phase; bool evq_phase, old_evq_phase;
unsigned int read_ptr; unsigned int read_ptr;
efx_qword_t *p_event; efx_qword_t *p_event;
int spent_tx = 0;
int spent = 0; int spent = 0;
bool ev_phase; bool ev_phase;
int ev_type; int ev_type;
@ -295,7 +298,9 @@ static int ef100_ev_process(struct efx_channel *channel, int quota)
efx_mcdi_process_event(channel, p_event); efx_mcdi_process_event(channel, p_event);
break; break;
case ESE_GZ_EF100_EV_TX_COMPLETION: case ESE_GZ_EF100_EV_TX_COMPLETION:
ef100_ev_tx(channel, p_event); spent_tx += ef100_ev_tx(channel, p_event);
if (spent_tx >= EFX_NAPI_MAX_TX)
spent = quota;
break; break;
case ESE_GZ_EF100_EV_DRIVER: case ESE_GZ_EF100_EV_DRIVER:
netif_info(efx, drv, efx->net_dev, netif_info(efx, drv, efx->net_dev,

View File

@ -346,7 +346,7 @@ void ef100_tx_write(struct efx_tx_queue *tx_queue)
ef100_tx_push_buffers(tx_queue); ef100_tx_push_buffers(tx_queue);
} }
void ef100_ev_tx(struct efx_channel *channel, const efx_qword_t *p_event) int ef100_ev_tx(struct efx_channel *channel, const efx_qword_t *p_event)
{ {
unsigned int tx_done = unsigned int tx_done =
EFX_QWORD_FIELD(*p_event, ESF_GZ_EV_TXCMPL_NUM_DESC); EFX_QWORD_FIELD(*p_event, ESF_GZ_EV_TXCMPL_NUM_DESC);
@ -357,7 +357,7 @@ void ef100_ev_tx(struct efx_channel *channel, const efx_qword_t *p_event)
unsigned int tx_index = (tx_queue->read_count + tx_done - 1) & unsigned int tx_index = (tx_queue->read_count + tx_done - 1) &
tx_queue->ptr_mask; tx_queue->ptr_mask;
efx_xmit_done(tx_queue, tx_index); return efx_xmit_done(tx_queue, tx_index);
} }
/* Add a socket buffer to a TX queue /* Add a socket buffer to a TX queue

View File

@ -20,7 +20,7 @@ void ef100_tx_init(struct efx_tx_queue *tx_queue);
void ef100_tx_write(struct efx_tx_queue *tx_queue); void ef100_tx_write(struct efx_tx_queue *tx_queue);
unsigned int ef100_tx_max_skb_descs(struct efx_nic *efx); unsigned int ef100_tx_max_skb_descs(struct efx_nic *efx);
void ef100_ev_tx(struct efx_channel *channel, const efx_qword_t *p_event); int ef100_ev_tx(struct efx_channel *channel, const efx_qword_t *p_event);
netdev_tx_t ef100_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb); netdev_tx_t ef100_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb);
int __ef100_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb, int __ef100_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb,

View File

@ -249,7 +249,7 @@ void efx_xmit_done_check_empty(struct efx_tx_queue *tx_queue)
} }
} }
void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index) int efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index)
{ {
unsigned int fill_level, pkts_compl = 0, bytes_compl = 0; unsigned int fill_level, pkts_compl = 0, bytes_compl = 0;
unsigned int efv_pkts_compl = 0; unsigned int efv_pkts_compl = 0;
@ -279,6 +279,8 @@ void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index)
} }
efx_xmit_done_check_empty(tx_queue); efx_xmit_done_check_empty(tx_queue);
return pkts_compl + efv_pkts_compl;
} }
/* Remove buffers put into a tx_queue for the current packet. /* Remove buffers put into a tx_queue for the current packet.

View File

@ -28,7 +28,7 @@ static inline bool efx_tx_buffer_in_use(struct efx_tx_buffer *buffer)
} }
void efx_xmit_done_check_empty(struct efx_tx_queue *tx_queue); void efx_xmit_done_check_empty(struct efx_tx_queue *tx_queue);
void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index); int efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index);
void efx_enqueue_unwind(struct efx_tx_queue *tx_queue, void efx_enqueue_unwind(struct efx_tx_queue *tx_queue,
unsigned int insert_count); unsigned int insert_count);

View File

@ -1348,3 +1348,5 @@ module_spi_driver(adf7242_driver);
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>"); MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("ADF7242 IEEE802.15.4 Transceiver Driver"); MODULE_DESCRIPTION("ADF7242 IEEE802.15.4 Transceiver Driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_FIRMWARE(FIRMWARE);

View File

@ -685,7 +685,7 @@ static int hwsim_del_edge_nl(struct sk_buff *msg, struct genl_info *info)
static int hwsim_set_edge_lqi(struct sk_buff *msg, struct genl_info *info) static int hwsim_set_edge_lqi(struct sk_buff *msg, struct genl_info *info)
{ {
struct nlattr *edge_attrs[MAC802154_HWSIM_EDGE_ATTR_MAX + 1]; struct nlattr *edge_attrs[MAC802154_HWSIM_EDGE_ATTR_MAX + 1];
struct hwsim_edge_info *einfo; struct hwsim_edge_info *einfo, *einfo_old;
struct hwsim_phy *phy_v0; struct hwsim_phy *phy_v0;
struct hwsim_edge *e; struct hwsim_edge *e;
u32 v0, v1; u32 v0, v1;
@ -723,8 +723,10 @@ static int hwsim_set_edge_lqi(struct sk_buff *msg, struct genl_info *info)
list_for_each_entry_rcu(e, &phy_v0->edges, list) { list_for_each_entry_rcu(e, &phy_v0->edges, list) {
if (e->endpoint->idx == v1) { if (e->endpoint->idx == v1) {
einfo->lqi = lqi; einfo->lqi = lqi;
rcu_assign_pointer(e->info, einfo); einfo_old = rcu_replace_pointer(e->info, einfo,
lockdep_is_held(&hwsim_phys_lock));
rcu_read_unlock(); rcu_read_unlock();
kfree_rcu(einfo_old, rcu);
mutex_unlock(&hwsim_phys_lock); mutex_unlock(&hwsim_phys_lock);
return 0; return 0;
} }

View File

@ -936,7 +936,7 @@ static int dp83867_phy_reset(struct phy_device *phydev)
{ {
int err; int err;
err = phy_write(phydev, DP83867_CTRL, DP83867_SW_RESTART); err = phy_write(phydev, DP83867_CTRL, DP83867_SW_RESET);
if (err < 0) if (err < 0)
return err; return err;

View File

@ -1287,7 +1287,7 @@ EXPORT_SYMBOL_GPL(mdiobus_modify_changed);
* @mask: bit mask of bits to clear * @mask: bit mask of bits to clear
* @set: bit mask of bits to set * @set: bit mask of bits to set
*/ */
int mdiobus_c45_modify_changed(struct mii_bus *bus, int devad, int addr, int mdiobus_c45_modify_changed(struct mii_bus *bus, int addr, int devad,
u32 regnum, u16 mask, u16 set) u32 regnum, u16 mask, u16 set)
{ {
int err; int err;

View File

@ -3021,6 +3021,15 @@ static int phy_led_blink_set(struct led_classdev *led_cdev,
return err; return err;
} }
static void phy_leds_unregister(struct phy_device *phydev)
{
struct phy_led *phyled;
list_for_each_entry(phyled, &phydev->leds, list) {
led_classdev_unregister(&phyled->led_cdev);
}
}
static int of_phy_led(struct phy_device *phydev, static int of_phy_led(struct phy_device *phydev,
struct device_node *led) struct device_node *led)
{ {
@ -3054,7 +3063,7 @@ static int of_phy_led(struct phy_device *phydev,
init_data.fwnode = of_fwnode_handle(led); init_data.fwnode = of_fwnode_handle(led);
init_data.devname_mandatory = true; init_data.devname_mandatory = true;
err = devm_led_classdev_register_ext(dev, cdev, &init_data); err = led_classdev_register_ext(dev, cdev, &init_data);
if (err) if (err)
return err; return err;
@ -3083,6 +3092,7 @@ static int of_phy_leds(struct phy_device *phydev)
err = of_phy_led(phydev, led); err = of_phy_led(phydev, led);
if (err) { if (err) {
of_node_put(led); of_node_put(led);
phy_leds_unregister(phydev);
return err; return err;
} }
} }
@ -3305,6 +3315,9 @@ static int phy_remove(struct device *dev)
cancel_delayed_work_sync(&phydev->state_queue); cancel_delayed_work_sync(&phydev->state_queue);
if (IS_ENABLED(CONFIG_PHYLIB_LEDS))
phy_leds_unregister(phydev);
phydev->state = PHY_DOWN; phydev->state = PHY_DOWN;
sfp_bus_del_upstream(phydev->sfp_bus); sfp_bus_del_upstream(phydev->sfp_bus);

View File

@ -548,6 +548,8 @@ static const struct iwl_dev_info iwl_dev_info_table[] = {
IWL_DEV_INFO(0x54F0, 0x1692, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690i_name), IWL_DEV_INFO(0x54F0, 0x1692, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690i_name),
IWL_DEV_INFO(0x7A70, 0x1691, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690s_name), IWL_DEV_INFO(0x7A70, 0x1691, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690s_name),
IWL_DEV_INFO(0x7A70, 0x1692, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690i_name), IWL_DEV_INFO(0x7A70, 0x1692, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690i_name),
IWL_DEV_INFO(0x7AF0, 0x1691, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690s_name),
IWL_DEV_INFO(0x7AF0, 0x1692, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690i_name),
IWL_DEV_INFO(0x271C, 0x0214, iwl9260_2ac_cfg, iwl9260_1_name), IWL_DEV_INFO(0x271C, 0x0214, iwl9260_2ac_cfg, iwl9260_1_name),
IWL_DEV_INFO(0x7E40, 0x1691, iwl_cfg_ma_a0_gf4_a0, iwl_ax411_killer_1690s_name), IWL_DEV_INFO(0x7E40, 0x1691, iwl_cfg_ma_a0_gf4_a0, iwl_ax411_killer_1690s_name),

View File

@ -626,14 +626,12 @@ static void mux_dl_adb_decode(struct iosm_mux *ipc_mux,
if (adth->signature != cpu_to_le32(IOSM_AGGR_MUX_SIG_ADTH)) if (adth->signature != cpu_to_le32(IOSM_AGGR_MUX_SIG_ADTH))
goto adb_decode_err; goto adb_decode_err;
if (le16_to_cpu(adth->table_length) < (sizeof(struct mux_adth) - if (le16_to_cpu(adth->table_length) < sizeof(struct mux_adth))
sizeof(struct mux_adth_dg)))
goto adb_decode_err; goto adb_decode_err;
/* Calculate the number of datagrams. */ /* Calculate the number of datagrams. */
nr_of_dg = (le16_to_cpu(adth->table_length) - nr_of_dg = (le16_to_cpu(adth->table_length) -
sizeof(struct mux_adth) + sizeof(struct mux_adth)) /
sizeof(struct mux_adth_dg)) /
sizeof(struct mux_adth_dg); sizeof(struct mux_adth_dg);
/* Is the datagram table empty ? */ /* Is the datagram table empty ? */
@ -649,7 +647,7 @@ static void mux_dl_adb_decode(struct iosm_mux *ipc_mux,
} }
/* New aggregated datagram table. */ /* New aggregated datagram table. */
dg = &adth->dg; dg = adth->dg;
if (mux_dl_process_dg(ipc_mux, adbh, dg, skb, if_id, if (mux_dl_process_dg(ipc_mux, adbh, dg, skb, if_id,
nr_of_dg) < 0) nr_of_dg) < 0)
goto adb_decode_err; goto adb_decode_err;
@ -849,7 +847,7 @@ static void ipc_mux_ul_encode_adth(struct iosm_mux *ipc_mux,
adth->if_id = i; adth->if_id = i;
adth->table_length = cpu_to_le16(adth_dg_size); adth->table_length = cpu_to_le16(adth_dg_size);
adth_dg_size -= offsetof(struct mux_adth, dg); adth_dg_size -= offsetof(struct mux_adth, dg);
memcpy(&adth->dg, ul_adb->dg[i], adth_dg_size); memcpy(adth->dg, ul_adb->dg[i], adth_dg_size);
ul_adb->if_cnt++; ul_adb->if_cnt++;
} }
@ -1426,14 +1424,13 @@ static int ipc_mux_get_payload_from_adb(struct iosm_mux *ipc_mux,
if (adth->signature == cpu_to_le32(IOSM_AGGR_MUX_SIG_ADTH)) { if (adth->signature == cpu_to_le32(IOSM_AGGR_MUX_SIG_ADTH)) {
nr_of_dg = (le16_to_cpu(adth->table_length) - nr_of_dg = (le16_to_cpu(adth->table_length) -
sizeof(struct mux_adth) + sizeof(struct mux_adth)) /
sizeof(struct mux_adth_dg)) /
sizeof(struct mux_adth_dg); sizeof(struct mux_adth_dg);
if (nr_of_dg <= 0) if (nr_of_dg <= 0)
return payload_size; return payload_size;
dg = &adth->dg; dg = adth->dg;
for (i = 0; i < nr_of_dg; i++, dg++) { for (i = 0; i < nr_of_dg; i++, dg++) {
if (le32_to_cpu(dg->datagram_index) < if (le32_to_cpu(dg->datagram_index) <

View File

@ -161,7 +161,7 @@ struct mux_adth {
u8 opt_ipv4v6; u8 opt_ipv4v6;
__le32 next_table_index; __le32 next_table_index;
__le32 reserved2; __le32 reserved2;
struct mux_adth_dg dg; struct mux_adth_dg dg[];
}; };
/** /**

View File

@ -762,3 +762,6 @@ EXPORT_SYMBOL(fdp_nci_remove);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("NFC NCI driver for Intel Fields Peak NFC controller"); MODULE_DESCRIPTION("NFC NCI driver for Intel Fields Peak NFC controller");
MODULE_AUTHOR("Robert Dolca <robert.dolca@intel.com>"); MODULE_AUTHOR("Robert Dolca <robert.dolca@intel.com>");
MODULE_FIRMWARE(FDP_OTP_PATCH_NAME);
MODULE_FIRMWARE(FDP_RAM_PATCH_NAME);

View File

@ -958,6 +958,14 @@ struct dsa_switch_ops {
struct phy_device *phy); struct phy_device *phy);
void (*port_disable)(struct dsa_switch *ds, int port); void (*port_disable)(struct dsa_switch *ds, int port);
/*
* Compatibility between device trees defining multiple CPU ports and
* drivers which are not OK to use by default the numerically smallest
* CPU port of a switch for its local ports. This can return NULL,
* meaning "don't know/don't care".
*/
struct dsa_port *(*preferred_default_local_cpu_port)(struct dsa_switch *ds);
/* /*
* Port's MAC EEE settings * Port's MAC EEE settings
*/ */

View File

@ -472,7 +472,8 @@ struct nft_set_ops {
int (*init)(const struct nft_set *set, int (*init)(const struct nft_set *set,
const struct nft_set_desc *desc, const struct nft_set_desc *desc,
const struct nlattr * const nla[]); const struct nlattr * const nla[]);
void (*destroy)(const struct nft_set *set); void (*destroy)(const struct nft_ctx *ctx,
const struct nft_set *set);
void (*gc_init)(const struct nft_set *set); void (*gc_init)(const struct nft_set *set);
unsigned int elemsize; unsigned int elemsize;
@ -809,6 +810,8 @@ int nft_set_elem_expr_clone(const struct nft_ctx *ctx, struct nft_set *set,
struct nft_expr *expr_array[]); struct nft_expr *expr_array[]);
void nft_set_elem_destroy(const struct nft_set *set, void *elem, void nft_set_elem_destroy(const struct nft_set *set, void *elem,
bool destroy_expr); bool destroy_expr);
void nf_tables_set_elem_destroy(const struct nft_ctx *ctx,
const struct nft_set *set, void *elem);
/** /**
* struct nft_set_gc_batch_head - nf_tables set garbage collection batch * struct nft_set_gc_batch_head - nf_tables set garbage collection batch
@ -901,6 +904,7 @@ struct nft_expr_type {
enum nft_trans_phase { enum nft_trans_phase {
NFT_TRANS_PREPARE, NFT_TRANS_PREPARE,
NFT_TRANS_PREPARE_ERROR,
NFT_TRANS_ABORT, NFT_TRANS_ABORT,
NFT_TRANS_COMMIT, NFT_TRANS_COMMIT,
NFT_TRANS_RELEASE NFT_TRANS_RELEASE
@ -1009,7 +1013,10 @@ static inline struct nft_userdata *nft_userdata(const struct nft_rule *rule)
return (void *)&rule->data[rule->dlen]; return (void *)&rule->data[rule->dlen];
} }
void nf_tables_rule_release(const struct nft_ctx *ctx, struct nft_rule *rule); void nft_rule_expr_activate(const struct nft_ctx *ctx, struct nft_rule *rule);
void nft_rule_expr_deactivate(const struct nft_ctx *ctx, struct nft_rule *rule,
enum nft_trans_phase phase);
void nf_tables_rule_destroy(const struct nft_ctx *ctx, struct nft_rule *rule);
static inline void nft_set_elem_update_expr(const struct nft_set_ext *ext, static inline void nft_set_elem_update_expr(const struct nft_set_ext *ext,
struct nft_regs *regs, struct nft_regs *regs,
@ -1104,6 +1111,8 @@ int nft_setelem_validate(const struct nft_ctx *ctx, struct nft_set *set,
const struct nft_set_iter *iter, const struct nft_set_iter *iter,
struct nft_set_elem *elem); struct nft_set_elem *elem);
int nft_set_catchall_validate(const struct nft_ctx *ctx, struct nft_set *set); int nft_set_catchall_validate(const struct nft_ctx *ctx, struct nft_set *set);
int nf_tables_bind_chain(const struct nft_ctx *ctx, struct nft_chain *chain);
void nf_tables_unbind_chain(const struct nft_ctx *ctx, struct nft_chain *chain);
enum nft_chain_types { enum nft_chain_types {
NFT_CHAIN_T_DEFAULT = 0, NFT_CHAIN_T_DEFAULT = 0,
@ -1140,11 +1149,17 @@ int nft_chain_validate_dependency(const struct nft_chain *chain,
int nft_chain_validate_hooks(const struct nft_chain *chain, int nft_chain_validate_hooks(const struct nft_chain *chain,
unsigned int hook_flags); unsigned int hook_flags);
static inline bool nft_chain_binding(const struct nft_chain *chain)
{
return chain->flags & NFT_CHAIN_BINDING;
}
static inline bool nft_chain_is_bound(struct nft_chain *chain) static inline bool nft_chain_is_bound(struct nft_chain *chain)
{ {
return (chain->flags & NFT_CHAIN_BINDING) && chain->bound; return (chain->flags & NFT_CHAIN_BINDING) && chain->bound;
} }
int nft_chain_add(struct nft_table *table, struct nft_chain *chain);
void nft_chain_del(struct nft_chain *chain); void nft_chain_del(struct nft_chain *chain);
void nf_tables_chain_destroy(struct nft_ctx *ctx); void nf_tables_chain_destroy(struct nft_ctx *ctx);
@ -1558,6 +1573,7 @@ static inline void nft_set_elem_clear_busy(struct nft_set_ext *ext)
* struct nft_trans - nf_tables object update in transaction * struct nft_trans - nf_tables object update in transaction
* *
* @list: used internally * @list: used internally
* @binding_list: list of objects with possible bindings
* @msg_type: message type * @msg_type: message type
* @put_net: ctx->net needs to be put * @put_net: ctx->net needs to be put
* @ctx: transaction context * @ctx: transaction context
@ -1565,6 +1581,7 @@ static inline void nft_set_elem_clear_busy(struct nft_set_ext *ext)
*/ */
struct nft_trans { struct nft_trans {
struct list_head list; struct list_head list;
struct list_head binding_list;
int msg_type; int msg_type;
bool put_net; bool put_net;
struct nft_ctx ctx; struct nft_ctx ctx;
@ -1575,6 +1592,7 @@ struct nft_trans_rule {
struct nft_rule *rule; struct nft_rule *rule;
struct nft_flow_rule *flow; struct nft_flow_rule *flow;
u32 rule_id; u32 rule_id;
bool bound;
}; };
#define nft_trans_rule(trans) \ #define nft_trans_rule(trans) \
@ -1583,6 +1601,8 @@ struct nft_trans_rule {
(((struct nft_trans_rule *)trans->data)->flow) (((struct nft_trans_rule *)trans->data)->flow)
#define nft_trans_rule_id(trans) \ #define nft_trans_rule_id(trans) \
(((struct nft_trans_rule *)trans->data)->rule_id) (((struct nft_trans_rule *)trans->data)->rule_id)
#define nft_trans_rule_bound(trans) \
(((struct nft_trans_rule *)trans->data)->bound)
struct nft_trans_set { struct nft_trans_set {
struct nft_set *set; struct nft_set *set;
@ -1607,15 +1627,19 @@ struct nft_trans_set {
(((struct nft_trans_set *)trans->data)->gc_int) (((struct nft_trans_set *)trans->data)->gc_int)
struct nft_trans_chain { struct nft_trans_chain {
struct nft_chain *chain;
bool update; bool update;
char *name; char *name;
struct nft_stats __percpu *stats; struct nft_stats __percpu *stats;
u8 policy; u8 policy;
bool bound;
u32 chain_id; u32 chain_id;
struct nft_base_chain *basechain; struct nft_base_chain *basechain;
struct list_head hook_list; struct list_head hook_list;
}; };
#define nft_trans_chain(trans) \
(((struct nft_trans_chain *)trans->data)->chain)
#define nft_trans_chain_update(trans) \ #define nft_trans_chain_update(trans) \
(((struct nft_trans_chain *)trans->data)->update) (((struct nft_trans_chain *)trans->data)->update)
#define nft_trans_chain_name(trans) \ #define nft_trans_chain_name(trans) \
@ -1624,6 +1648,8 @@ struct nft_trans_chain {
(((struct nft_trans_chain *)trans->data)->stats) (((struct nft_trans_chain *)trans->data)->stats)
#define nft_trans_chain_policy(trans) \ #define nft_trans_chain_policy(trans) \
(((struct nft_trans_chain *)trans->data)->policy) (((struct nft_trans_chain *)trans->data)->policy)
#define nft_trans_chain_bound(trans) \
(((struct nft_trans_chain *)trans->data)->bound)
#define nft_trans_chain_id(trans) \ #define nft_trans_chain_id(trans) \
(((struct nft_trans_chain *)trans->data)->chain_id) (((struct nft_trans_chain *)trans->data)->chain_id)
#define nft_trans_basechain(trans) \ #define nft_trans_basechain(trans) \
@ -1700,6 +1726,7 @@ static inline int nft_request_module(struct net *net, const char *fmt, ...) { re
struct nftables_pernet { struct nftables_pernet {
struct list_head tables; struct list_head tables;
struct list_head commit_list; struct list_head commit_list;
struct list_head binding_list;
struct list_head module_list; struct list_head module_list;
struct list_head notify_list; struct list_head notify_list;
struct mutex commit_mutex; struct mutex commit_mutex;

View File

@ -1054,6 +1054,7 @@ struct xfrm_offload {
struct sec_path { struct sec_path {
int len; int len;
int olen; int olen;
int verified_cnt;
struct xfrm_state *xvec[XFRM_MAX_DEPTH]; struct xfrm_state *xvec[XFRM_MAX_DEPTH];
struct xfrm_offload ovec[XFRM_MAX_OFFLOAD_DEPTH]; struct xfrm_offload ovec[XFRM_MAX_OFFLOAD_DEPTH];

View File

@ -744,13 +744,12 @@ static bool btf_name_offset_valid(const struct btf *btf, u32 offset)
return offset < btf->hdr.str_len; return offset < btf->hdr.str_len;
} }
static bool __btf_name_char_ok(char c, bool first, bool dot_ok) static bool __btf_name_char_ok(char c, bool first)
{ {
if ((first ? !isalpha(c) : if ((first ? !isalpha(c) :
!isalnum(c)) && !isalnum(c)) &&
c != '_' && c != '_' &&
((c == '.' && !dot_ok) || c != '.')
c != '.'))
return false; return false;
return true; return true;
} }
@ -767,20 +766,20 @@ static const char *btf_str_by_offset(const struct btf *btf, u32 offset)
return NULL; return NULL;
} }
static bool __btf_name_valid(const struct btf *btf, u32 offset, bool dot_ok) static bool __btf_name_valid(const struct btf *btf, u32 offset)
{ {
/* offset must be valid */ /* offset must be valid */
const char *src = btf_str_by_offset(btf, offset); const char *src = btf_str_by_offset(btf, offset);
const char *src_limit; const char *src_limit;
if (!__btf_name_char_ok(*src, true, dot_ok)) if (!__btf_name_char_ok(*src, true))
return false; return false;
/* set a limit on identifier length */ /* set a limit on identifier length */
src_limit = src + KSYM_NAME_LEN; src_limit = src + KSYM_NAME_LEN;
src++; src++;
while (*src && src < src_limit) { while (*src && src < src_limit) {
if (!__btf_name_char_ok(*src, false, dot_ok)) if (!__btf_name_char_ok(*src, false))
return false; return false;
src++; src++;
} }
@ -788,17 +787,14 @@ static bool __btf_name_valid(const struct btf *btf, u32 offset, bool dot_ok)
return !*src; return !*src;
} }
/* Only C-style identifier is permitted. This can be relaxed if
* necessary.
*/
static bool btf_name_valid_identifier(const struct btf *btf, u32 offset) static bool btf_name_valid_identifier(const struct btf *btf, u32 offset)
{ {
return __btf_name_valid(btf, offset, false); return __btf_name_valid(btf, offset);
} }
static bool btf_name_valid_section(const struct btf *btf, u32 offset) static bool btf_name_valid_section(const struct btf *btf, u32 offset)
{ {
return __btf_name_valid(btf, offset, true); return __btf_name_valid(btf, offset);
} }
static const char *__btf_name_by_offset(const struct btf *btf, u32 offset) static const char *__btf_name_by_offset(const struct btf *btf, u32 offset)
@ -4422,7 +4418,7 @@ static s32 btf_var_check_meta(struct btf_verifier_env *env,
} }
if (!t->name_off || if (!t->name_off ||
!__btf_name_valid(env->btf, t->name_off, true)) { !__btf_name_valid(env->btf, t->name_off)) {
btf_verifier_log_type(env, t, "Invalid name"); btf_verifier_log_type(env, t, "Invalid name");
return -EINVAL; return -EINVAL;
} }

View File

@ -3440,6 +3440,11 @@ static int bpf_prog_attach_check_attach_type(const struct bpf_prog *prog,
return prog->enforce_expected_attach_type && return prog->enforce_expected_attach_type &&
prog->expected_attach_type != attach_type ? prog->expected_attach_type != attach_type ?
-EINVAL : 0; -EINVAL : 0;
case BPF_PROG_TYPE_KPROBE:
if (prog->expected_attach_type == BPF_TRACE_KPROBE_MULTI &&
attach_type != BPF_TRACE_KPROBE_MULTI)
return -EINVAL;
return 0;
default: default:
return 0; return 0;
} }

View File

@ -3868,6 +3868,9 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env,
return err; return err;
} }
save_register_state(state, spi, reg, size); save_register_state(state, spi, reg, size);
/* Break the relation on a narrowing spill. */
if (fls64(reg->umax_value) > BITS_PER_BYTE * size)
state->stack[spi].spilled_ptr.id = 0;
} else if (!reg && !(off % BPF_REG_SIZE) && is_bpf_st_mem(insn) && } else if (!reg && !(off % BPF_REG_SIZE) && is_bpf_st_mem(insn) &&
insn->imm != 0 && env->bpf_capable) { insn->imm != 0 && env->bpf_capable) {
struct bpf_reg_state fake_reg = {}; struct bpf_reg_state fake_reg = {};
@ -17214,9 +17217,10 @@ static int jit_subprogs(struct bpf_verifier_env *env)
} }
/* finally lock prog and jit images for all functions and /* finally lock prog and jit images for all functions and
* populate kallsysm * populate kallsysm. Begin at the first subprogram, since
* bpf_prog_load will add the kallsyms for the main program.
*/ */
for (i = 0; i < env->subprog_cnt; i++) { for (i = 1; i < env->subprog_cnt; i++) {
bpf_prog_lock_ro(func[i]); bpf_prog_lock_ro(func[i]);
bpf_prog_kallsyms_add(func[i]); bpf_prog_kallsyms_add(func[i]);
} }
@ -17242,6 +17246,8 @@ static int jit_subprogs(struct bpf_verifier_env *env)
prog->jited = 1; prog->jited = 1;
prog->bpf_func = func[0]->bpf_func; prog->bpf_func = func[0]->bpf_func;
prog->jited_len = func[0]->jited_len; prog->jited_len = func[0]->jited_len;
prog->aux->extable = func[0]->aux->extable;
prog->aux->num_exentries = func[0]->aux->num_exentries;
prog->aux->func = func; prog->aux->func = func;
prog->aux->func_cnt = env->subprog_cnt; prog->aux->func_cnt = env->subprog_cnt;
bpf_prog_jit_attempt_done(prog); bpf_prog_jit_attempt_done(prog);

View File

@ -1362,12 +1362,6 @@ set_sndbuf:
__sock_set_mark(sk, val); __sock_set_mark(sk, val);
break; break;
case SO_RCVMARK: case SO_RCVMARK:
if (!sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_RAW) &&
!sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) {
ret = -EPERM;
break;
}
sock_valbool_flag(sk, SOCK_RCVMARK, valbool); sock_valbool_flag(sk, SOCK_RCVMARK, valbool);
break; break;

View File

@ -403,6 +403,24 @@ static int dsa_tree_setup_default_cpu(struct dsa_switch_tree *dst)
return 0; return 0;
} }
static struct dsa_port *
dsa_switch_preferred_default_local_cpu_port(struct dsa_switch *ds)
{
struct dsa_port *cpu_dp;
if (!ds->ops->preferred_default_local_cpu_port)
return NULL;
cpu_dp = ds->ops->preferred_default_local_cpu_port(ds);
if (!cpu_dp)
return NULL;
if (WARN_ON(!dsa_port_is_cpu(cpu_dp) || cpu_dp->ds != ds))
return NULL;
return cpu_dp;
}
/* Perform initial assignment of CPU ports to user ports and DSA links in the /* Perform initial assignment of CPU ports to user ports and DSA links in the
* fabric, giving preference to CPU ports local to each switch. Default to * fabric, giving preference to CPU ports local to each switch. Default to
* using the first CPU port in the switch tree if the port does not have a CPU * using the first CPU port in the switch tree if the port does not have a CPU
@ -410,12 +428,16 @@ static int dsa_tree_setup_default_cpu(struct dsa_switch_tree *dst)
*/ */
static int dsa_tree_setup_cpu_ports(struct dsa_switch_tree *dst) static int dsa_tree_setup_cpu_ports(struct dsa_switch_tree *dst)
{ {
struct dsa_port *cpu_dp, *dp; struct dsa_port *preferred_cpu_dp, *cpu_dp, *dp;
list_for_each_entry(cpu_dp, &dst->ports, list) { list_for_each_entry(cpu_dp, &dst->ports, list) {
if (!dsa_port_is_cpu(cpu_dp)) if (!dsa_port_is_cpu(cpu_dp))
continue; continue;
preferred_cpu_dp = dsa_switch_preferred_default_local_cpu_port(cpu_dp->ds);
if (preferred_cpu_dp && preferred_cpu_dp != cpu_dp)
continue;
/* Prefer a local CPU port */ /* Prefer a local CPU port */
dsa_switch_for_each_port(dp, cpu_dp->ds) { dsa_switch_for_each_port(dp, cpu_dp->ds) {
/* Prefer the first local CPU port found */ /* Prefer the first local CPU port found */

View File

@ -13,7 +13,7 @@
#define MAXNAME 32 #define MAXNAME 32
#define WPAN_PHY_ENTRY __array(char, wpan_phy_name, MAXNAME) #define WPAN_PHY_ENTRY __array(char, wpan_phy_name, MAXNAME)
#define WPAN_PHY_ASSIGN strlcpy(__entry->wpan_phy_name, \ #define WPAN_PHY_ASSIGN strscpy(__entry->wpan_phy_name, \
wpan_phy_name(wpan_phy), \ wpan_phy_name(wpan_phy), \
MAXNAME) MAXNAME)
#define WPAN_PHY_PR_FMT "%s" #define WPAN_PHY_PR_FMT "%s"

View File

@ -340,6 +340,9 @@ static int esp_xmit(struct xfrm_state *x, struct sk_buff *skb, netdev_features_
secpath_reset(skb); secpath_reset(skb);
if (skb_needs_linearize(skb, skb->dev->features) &&
__skb_linearize(skb))
return -ENOMEM;
return 0; return 0;
} }

View File

@ -164,6 +164,7 @@ drop:
kfree_skb(skb); kfree_skb(skb);
return 0; return 0;
} }
EXPORT_SYMBOL(xfrm4_udp_encap_rcv);
int xfrm4_rcv(struct sk_buff *skb) int xfrm4_rcv(struct sk_buff *skb)
{ {

View File

@ -374,6 +374,9 @@ static int esp6_xmit(struct xfrm_state *x, struct sk_buff *skb, netdev_features
secpath_reset(skb); secpath_reset(skb);
if (skb_needs_linearize(skb, skb->dev->features) &&
__skb_linearize(skb))
return -ENOMEM;
return 0; return 0;
} }

View File

@ -86,6 +86,9 @@ int xfrm6_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
__be32 *udpdata32; __be32 *udpdata32;
__u16 encap_type = up->encap_type; __u16 encap_type = up->encap_type;
if (skb->protocol == htons(ETH_P_IP))
return xfrm4_udp_encap_rcv(sk, skb);
/* if this is not encapsulated socket, then just return now */ /* if this is not encapsulated socket, then just return now */
if (!encap_type) if (!encap_type)
return 1; return 1;

View File

@ -2110,7 +2110,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
/* either the frame has been decrypted or will be dropped */ /* either the frame has been decrypted or will be dropped */
status->flag |= RX_FLAG_DECRYPTED; status->flag |= RX_FLAG_DECRYPTED;
if (unlikely(ieee80211_is_beacon(fc) && result == RX_DROP_UNUSABLE && if (unlikely(ieee80211_is_beacon(fc) && (result & RX_DROP_UNUSABLE) &&
rx->sdata->dev)) rx->sdata->dev))
cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev, cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
skb->data, skb->len); skb->data, skb->len);

View File

@ -14,7 +14,7 @@
#define MAXNAME 32 #define MAXNAME 32
#define LOCAL_ENTRY __array(char, wpan_phy_name, MAXNAME) #define LOCAL_ENTRY __array(char, wpan_phy_name, MAXNAME)
#define LOCAL_ASSIGN strlcpy(__entry->wpan_phy_name, \ #define LOCAL_ASSIGN strscpy(__entry->wpan_phy_name, \
wpan_phy_name(local->hw.phy), MAXNAME) wpan_phy_name(local->hw.phy), MAXNAME)
#define LOCAL_PR_FMT "%s" #define LOCAL_PR_FMT "%s"
#define LOCAL_PR_ARG __entry->wpan_phy_name #define LOCAL_PR_ARG __entry->wpan_phy_name

View File

@ -1047,6 +1047,7 @@ static int mptcp_pm_nl_create_listen_socket(struct sock *sk,
if (err) if (err)
return err; return err;
inet_sk_state_store(newsk, TCP_LISTEN);
err = kernel_listen(ssock, backlog); err = kernel_listen(ssock, backlog);
if (err) if (err)
return err; return err;

View File

@ -44,7 +44,7 @@ enum {
static struct percpu_counter mptcp_sockets_allocated ____cacheline_aligned_in_smp; static struct percpu_counter mptcp_sockets_allocated ____cacheline_aligned_in_smp;
static void __mptcp_destroy_sock(struct sock *sk); static void __mptcp_destroy_sock(struct sock *sk);
static void __mptcp_check_send_data_fin(struct sock *sk); static void mptcp_check_send_data_fin(struct sock *sk);
DEFINE_PER_CPU(struct mptcp_delegated_action, mptcp_delegated_actions); DEFINE_PER_CPU(struct mptcp_delegated_action, mptcp_delegated_actions);
static struct net_device mptcp_napi_dev; static struct net_device mptcp_napi_dev;
@ -424,8 +424,7 @@ static bool mptcp_pending_data_fin_ack(struct sock *sk)
{ {
struct mptcp_sock *msk = mptcp_sk(sk); struct mptcp_sock *msk = mptcp_sk(sk);
return !__mptcp_check_fallback(msk) && return ((1 << sk->sk_state) &
((1 << sk->sk_state) &
(TCPF_FIN_WAIT1 | TCPF_CLOSING | TCPF_LAST_ACK)) && (TCPF_FIN_WAIT1 | TCPF_CLOSING | TCPF_LAST_ACK)) &&
msk->write_seq == READ_ONCE(msk->snd_una); msk->write_seq == READ_ONCE(msk->snd_una);
} }
@ -583,9 +582,6 @@ static bool mptcp_check_data_fin(struct sock *sk)
u64 rcv_data_fin_seq; u64 rcv_data_fin_seq;
bool ret = false; bool ret = false;
if (__mptcp_check_fallback(msk))
return ret;
/* Need to ack a DATA_FIN received from a peer while this side /* Need to ack a DATA_FIN received from a peer while this side
* of the connection is in ESTABLISHED, FIN_WAIT1, or FIN_WAIT2. * of the connection is in ESTABLISHED, FIN_WAIT1, or FIN_WAIT2.
* msk->rcv_data_fin was set when parsing the incoming options * msk->rcv_data_fin was set when parsing the incoming options
@ -623,7 +619,8 @@ static bool mptcp_check_data_fin(struct sock *sk)
} }
ret = true; ret = true;
mptcp_send_ack(msk); if (!__mptcp_check_fallback(msk))
mptcp_send_ack(msk);
mptcp_close_wake_up(sk); mptcp_close_wake_up(sk);
} }
return ret; return ret;
@ -850,12 +847,12 @@ static bool __mptcp_finish_join(struct mptcp_sock *msk, struct sock *ssk)
return true; return true;
} }
static void __mptcp_flush_join_list(struct sock *sk) static void __mptcp_flush_join_list(struct sock *sk, struct list_head *join_list)
{ {
struct mptcp_subflow_context *tmp, *subflow; struct mptcp_subflow_context *tmp, *subflow;
struct mptcp_sock *msk = mptcp_sk(sk); struct mptcp_sock *msk = mptcp_sk(sk);
list_for_each_entry_safe(subflow, tmp, &msk->join_list, node) { list_for_each_entry_safe(subflow, tmp, join_list, node) {
struct sock *ssk = mptcp_subflow_tcp_sock(subflow); struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
bool slow = lock_sock_fast(ssk); bool slow = lock_sock_fast(ssk);
@ -897,49 +894,6 @@ bool mptcp_schedule_work(struct sock *sk)
return false; return false;
} }
void mptcp_subflow_eof(struct sock *sk)
{
if (!test_and_set_bit(MPTCP_WORK_EOF, &mptcp_sk(sk)->flags))
mptcp_schedule_work(sk);
}
static void mptcp_check_for_eof(struct mptcp_sock *msk)
{
struct mptcp_subflow_context *subflow;
struct sock *sk = (struct sock *)msk;
int receivers = 0;
mptcp_for_each_subflow(msk, subflow)
receivers += !subflow->rx_eof;
if (receivers)
return;
if (!(sk->sk_shutdown & RCV_SHUTDOWN)) {
/* hopefully temporary hack: propagate shutdown status
* to msk, when all subflows agree on it
*/
WRITE_ONCE(sk->sk_shutdown, sk->sk_shutdown | RCV_SHUTDOWN);
smp_mb__before_atomic(); /* SHUTDOWN must be visible first */
sk->sk_data_ready(sk);
}
switch (sk->sk_state) {
case TCP_ESTABLISHED:
inet_sk_state_store(sk, TCP_CLOSE_WAIT);
break;
case TCP_FIN_WAIT1:
inet_sk_state_store(sk, TCP_CLOSING);
break;
case TCP_FIN_WAIT2:
inet_sk_state_store(sk, TCP_CLOSE);
break;
default:
return;
}
mptcp_close_wake_up(sk);
}
static struct sock *mptcp_subflow_recv_lookup(const struct mptcp_sock *msk) static struct sock *mptcp_subflow_recv_lookup(const struct mptcp_sock *msk)
{ {
struct mptcp_subflow_context *subflow; struct mptcp_subflow_context *subflow;
@ -1609,7 +1563,7 @@ out:
if (!mptcp_timer_pending(sk)) if (!mptcp_timer_pending(sk))
mptcp_reset_timer(sk); mptcp_reset_timer(sk);
if (do_check_data_fin) if (do_check_data_fin)
__mptcp_check_send_data_fin(sk); mptcp_check_send_data_fin(sk);
} }
static void __mptcp_subflow_push_pending(struct sock *sk, struct sock *ssk, bool first) static void __mptcp_subflow_push_pending(struct sock *sk, struct sock *ssk, bool first)
@ -1727,7 +1681,13 @@ static int mptcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg,
if (ret && ret != -EINPROGRESS && ret != -ERESTARTSYS && ret != -EINTR) if (ret && ret != -EINPROGRESS && ret != -ERESTARTSYS && ret != -EINTR)
*copied_syn = 0; *copied_syn = 0;
} else if (ret && ret != -EINPROGRESS) { } else if (ret && ret != -EINPROGRESS) {
mptcp_disconnect(sk, 0); /* The disconnect() op called by tcp_sendmsg_fastopen()/
* __inet_stream_connect() can fail, due to looking check,
* see mptcp_disconnect().
* Attempt it again outside the problematic scope.
*/
if (!mptcp_disconnect(sk, 0))
sk->sk_socket->state = SS_UNCONNECTED;
} }
inet_sk(sk)->defer_connect = 0; inet_sk(sk)->defer_connect = 0;
@ -2158,9 +2118,6 @@ static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
break; break;
} }
if (test_and_clear_bit(MPTCP_WORK_EOF, &msk->flags))
mptcp_check_for_eof(msk);
if (sk->sk_shutdown & RCV_SHUTDOWN) { if (sk->sk_shutdown & RCV_SHUTDOWN) {
/* race breaker: the shutdown could be after the /* race breaker: the shutdown could be after the
* previous receive queue check * previous receive queue check
@ -2389,7 +2346,10 @@ static void __mptcp_close_ssk(struct sock *sk, struct sock *ssk,
need_push = (flags & MPTCP_CF_PUSH) && __mptcp_retransmit_pending_data(sk); need_push = (flags & MPTCP_CF_PUSH) && __mptcp_retransmit_pending_data(sk);
if (!dispose_it) { if (!dispose_it) {
tcp_disconnect(ssk, 0); /* The MPTCP code never wait on the subflow sockets, TCP-level
* disconnect should never fail
*/
WARN_ON_ONCE(tcp_disconnect(ssk, 0));
msk->subflow->state = SS_UNCONNECTED; msk->subflow->state = SS_UNCONNECTED;
mptcp_subflow_ctx_reset(subflow); mptcp_subflow_ctx_reset(subflow);
release_sock(ssk); release_sock(ssk);
@ -2408,13 +2368,6 @@ static void __mptcp_close_ssk(struct sock *sk, struct sock *ssk,
kfree_rcu(subflow, rcu); kfree_rcu(subflow, rcu);
} else { } else {
/* otherwise tcp will dispose of the ssk and subflow ctx */ /* otherwise tcp will dispose of the ssk and subflow ctx */
if (ssk->sk_state == TCP_LISTEN) {
tcp_set_state(ssk, TCP_CLOSE);
mptcp_subflow_queue_clean(sk, ssk);
inet_csk_listen_stop(ssk);
mptcp_event_pm_listener(ssk, MPTCP_EVENT_LISTENER_CLOSED);
}
__tcp_close(ssk, 0); __tcp_close(ssk, 0);
/* close acquired an extra ref */ /* close acquired an extra ref */
@ -2671,16 +2624,12 @@ static void mptcp_worker(struct work_struct *work)
if (unlikely((1 << state) & (TCPF_CLOSE | TCPF_LISTEN))) if (unlikely((1 << state) & (TCPF_CLOSE | TCPF_LISTEN)))
goto unlock; goto unlock;
mptcp_check_data_fin_ack(sk);
mptcp_check_fastclose(msk); mptcp_check_fastclose(msk);
mptcp_pm_nl_work(msk); mptcp_pm_nl_work(msk);
if (test_and_clear_bit(MPTCP_WORK_EOF, &msk->flags)) mptcp_check_send_data_fin(sk);
mptcp_check_for_eof(msk); mptcp_check_data_fin_ack(sk);
__mptcp_check_send_data_fin(sk);
mptcp_check_data_fin(sk); mptcp_check_data_fin(sk);
if (test_and_clear_bit(MPTCP_WORK_CLOSE_SUBFLOW, &msk->flags)) if (test_and_clear_bit(MPTCP_WORK_CLOSE_SUBFLOW, &msk->flags))
@ -2812,13 +2761,19 @@ void mptcp_subflow_shutdown(struct sock *sk, struct sock *ssk, int how)
break; break;
fallthrough; fallthrough;
case TCP_SYN_SENT: case TCP_SYN_SENT:
tcp_disconnect(ssk, O_NONBLOCK); WARN_ON_ONCE(tcp_disconnect(ssk, O_NONBLOCK));
break; break;
default: default:
if (__mptcp_check_fallback(mptcp_sk(sk))) { if (__mptcp_check_fallback(mptcp_sk(sk))) {
pr_debug("Fallback"); pr_debug("Fallback");
ssk->sk_shutdown |= how; ssk->sk_shutdown |= how;
tcp_shutdown(ssk, how); tcp_shutdown(ssk, how);
/* simulate the data_fin ack reception to let the state
* machine move forward
*/
WRITE_ONCE(mptcp_sk(sk)->snd_una, mptcp_sk(sk)->snd_nxt);
mptcp_schedule_work(sk);
} else { } else {
pr_debug("Sending DATA_FIN on subflow %p", ssk); pr_debug("Sending DATA_FIN on subflow %p", ssk);
tcp_send_ack(ssk); tcp_send_ack(ssk);
@ -2858,7 +2813,7 @@ static int mptcp_close_state(struct sock *sk)
return next & TCP_ACTION_FIN; return next & TCP_ACTION_FIN;
} }
static void __mptcp_check_send_data_fin(struct sock *sk) static void mptcp_check_send_data_fin(struct sock *sk)
{ {
struct mptcp_subflow_context *subflow; struct mptcp_subflow_context *subflow;
struct mptcp_sock *msk = mptcp_sk(sk); struct mptcp_sock *msk = mptcp_sk(sk);
@ -2876,19 +2831,6 @@ static void __mptcp_check_send_data_fin(struct sock *sk)
WRITE_ONCE(msk->snd_nxt, msk->write_seq); WRITE_ONCE(msk->snd_nxt, msk->write_seq);
/* fallback socket will not get data_fin/ack, can move to the next
* state now
*/
if (__mptcp_check_fallback(msk)) {
WRITE_ONCE(msk->snd_una, msk->write_seq);
if ((1 << sk->sk_state) & (TCPF_CLOSING | TCPF_LAST_ACK)) {
inet_sk_state_store(sk, TCP_CLOSE);
mptcp_close_wake_up(sk);
} else if (sk->sk_state == TCP_FIN_WAIT1) {
inet_sk_state_store(sk, TCP_FIN_WAIT2);
}
}
mptcp_for_each_subflow(msk, subflow) { mptcp_for_each_subflow(msk, subflow) {
struct sock *tcp_sk = mptcp_subflow_tcp_sock(subflow); struct sock *tcp_sk = mptcp_subflow_tcp_sock(subflow);
@ -2908,7 +2850,7 @@ static void __mptcp_wr_shutdown(struct sock *sk)
WRITE_ONCE(msk->write_seq, msk->write_seq + 1); WRITE_ONCE(msk->write_seq, msk->write_seq + 1);
WRITE_ONCE(msk->snd_data_fin_enable, 1); WRITE_ONCE(msk->snd_data_fin_enable, 1);
__mptcp_check_send_data_fin(sk); mptcp_check_send_data_fin(sk);
} }
static void __mptcp_destroy_sock(struct sock *sk) static void __mptcp_destroy_sock(struct sock *sk)
@ -2953,10 +2895,24 @@ static __poll_t mptcp_check_readable(struct mptcp_sock *msk)
return EPOLLIN | EPOLLRDNORM; return EPOLLIN | EPOLLRDNORM;
} }
static void mptcp_listen_inuse_dec(struct sock *sk) static void mptcp_check_listen_stop(struct sock *sk)
{ {
if (inet_sk_state_load(sk) == TCP_LISTEN) struct sock *ssk;
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
if (inet_sk_state_load(sk) != TCP_LISTEN)
return;
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
ssk = mptcp_sk(sk)->first;
if (WARN_ON_ONCE(!ssk || inet_sk_state_load(ssk) != TCP_LISTEN))
return;
lock_sock_nested(ssk, SINGLE_DEPTH_NESTING);
mptcp_subflow_queue_clean(sk, ssk);
inet_csk_listen_stop(ssk);
mptcp_event_pm_listener(ssk, MPTCP_EVENT_LISTENER_CLOSED);
tcp_set_state(ssk, TCP_CLOSE);
release_sock(ssk);
} }
bool __mptcp_close(struct sock *sk, long timeout) bool __mptcp_close(struct sock *sk, long timeout)
@ -2969,7 +2925,7 @@ bool __mptcp_close(struct sock *sk, long timeout)
WRITE_ONCE(sk->sk_shutdown, SHUTDOWN_MASK); WRITE_ONCE(sk->sk_shutdown, SHUTDOWN_MASK);
if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) { if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) {
mptcp_listen_inuse_dec(sk); mptcp_check_listen_stop(sk);
inet_sk_state_store(sk, TCP_CLOSE); inet_sk_state_store(sk, TCP_CLOSE);
goto cleanup; goto cleanup;
} }
@ -3073,15 +3029,20 @@ static int mptcp_disconnect(struct sock *sk, int flags)
{ {
struct mptcp_sock *msk = mptcp_sk(sk); struct mptcp_sock *msk = mptcp_sk(sk);
/* Deny disconnect if other threads are blocked in sk_wait_event()
* or inet_wait_for_connect().
*/
if (sk->sk_wait_pending)
return -EBUSY;
/* We are on the fastopen error path. We can't call straight into the /* We are on the fastopen error path. We can't call straight into the
* subflows cleanup code due to lock nesting (we are already under * subflows cleanup code due to lock nesting (we are already under
* msk->firstsocket lock). Do nothing and leave the cleanup to the * msk->firstsocket lock).
* caller.
*/ */
if (msk->fastopening) if (msk->fastopening)
return 0; return -EBUSY;
mptcp_listen_inuse_dec(sk); mptcp_check_listen_stop(sk);
inet_sk_state_store(sk, TCP_CLOSE); inet_sk_state_store(sk, TCP_CLOSE);
mptcp_stop_timer(sk); mptcp_stop_timer(sk);
@ -3140,6 +3101,7 @@ struct sock *mptcp_sk_clone_init(const struct sock *sk,
inet_sk(nsk)->pinet6 = mptcp_inet6_sk(nsk); inet_sk(nsk)->pinet6 = mptcp_inet6_sk(nsk);
#endif #endif
nsk->sk_wait_pending = 0;
__mptcp_init_sock(nsk); __mptcp_init_sock(nsk);
msk = mptcp_sk(nsk); msk = mptcp_sk(nsk);
@ -3327,9 +3289,14 @@ static void mptcp_release_cb(struct sock *sk)
for (;;) { for (;;) {
unsigned long flags = (msk->cb_flags & MPTCP_FLAGS_PROCESS_CTX_NEED) | unsigned long flags = (msk->cb_flags & MPTCP_FLAGS_PROCESS_CTX_NEED) |
msk->push_pending; msk->push_pending;
struct list_head join_list;
if (!flags) if (!flags)
break; break;
INIT_LIST_HEAD(&join_list);
list_splice_init(&msk->join_list, &join_list);
/* the following actions acquire the subflow socket lock /* the following actions acquire the subflow socket lock
* *
* 1) can't be invoked in atomic scope * 1) can't be invoked in atomic scope
@ -3340,8 +3307,9 @@ static void mptcp_release_cb(struct sock *sk)
msk->push_pending = 0; msk->push_pending = 0;
msk->cb_flags &= ~flags; msk->cb_flags &= ~flags;
spin_unlock_bh(&sk->sk_lock.slock); spin_unlock_bh(&sk->sk_lock.slock);
if (flags & BIT(MPTCP_FLUSH_JOIN_LIST)) if (flags & BIT(MPTCP_FLUSH_JOIN_LIST))
__mptcp_flush_join_list(sk); __mptcp_flush_join_list(sk, &join_list);
if (flags & BIT(MPTCP_PUSH_PENDING)) if (flags & BIT(MPTCP_PUSH_PENDING))
__mptcp_push_pending(sk, 0); __mptcp_push_pending(sk, 0);
if (flags & BIT(MPTCP_RETRANSMIT)) if (flags & BIT(MPTCP_RETRANSMIT))

View File

@ -113,7 +113,6 @@
/* MPTCP socket atomic flags */ /* MPTCP socket atomic flags */
#define MPTCP_NOSPACE 1 #define MPTCP_NOSPACE 1
#define MPTCP_WORK_RTX 2 #define MPTCP_WORK_RTX 2
#define MPTCP_WORK_EOF 3
#define MPTCP_FALLBACK_DONE 4 #define MPTCP_FALLBACK_DONE 4
#define MPTCP_WORK_CLOSE_SUBFLOW 5 #define MPTCP_WORK_CLOSE_SUBFLOW 5
@ -476,14 +475,13 @@ struct mptcp_subflow_context {
send_mp_fail : 1, send_mp_fail : 1,
send_fastclose : 1, send_fastclose : 1,
send_infinite_map : 1, send_infinite_map : 1,
rx_eof : 1,
remote_key_valid : 1, /* received the peer key from */ remote_key_valid : 1, /* received the peer key from */
disposable : 1, /* ctx can be free at ulp release time */ disposable : 1, /* ctx can be free at ulp release time */
stale : 1, /* unable to snd/rcv data, do not use for xmit */ stale : 1, /* unable to snd/rcv data, do not use for xmit */
local_id_valid : 1, /* local_id is correctly initialized */ local_id_valid : 1, /* local_id is correctly initialized */
valid_csum_seen : 1, /* at least one csum validated */ valid_csum_seen : 1, /* at least one csum validated */
is_mptfo : 1, /* subflow is doing TFO */ is_mptfo : 1, /* subflow is doing TFO */
__unused : 8; __unused : 9;
enum mptcp_data_avail data_avail; enum mptcp_data_avail data_avail;
u32 remote_nonce; u32 remote_nonce;
u64 thmac; u64 thmac;
@ -720,7 +718,6 @@ static inline u64 mptcp_expand_seq(u64 old_seq, u64 cur_seq, bool use_64bit)
void __mptcp_check_push(struct sock *sk, struct sock *ssk); void __mptcp_check_push(struct sock *sk, struct sock *ssk);
void __mptcp_data_acked(struct sock *sk); void __mptcp_data_acked(struct sock *sk);
void __mptcp_error_report(struct sock *sk); void __mptcp_error_report(struct sock *sk);
void mptcp_subflow_eof(struct sock *sk);
bool mptcp_update_rcv_data_fin(struct mptcp_sock *msk, u64 data_fin_seq, bool use_64bit); bool mptcp_update_rcv_data_fin(struct mptcp_sock *msk, u64 data_fin_seq, bool use_64bit);
static inline bool mptcp_data_fin_enabled(const struct mptcp_sock *msk) static inline bool mptcp_data_fin_enabled(const struct mptcp_sock *msk)
{ {

View File

@ -1749,14 +1749,16 @@ static void subflow_state_change(struct sock *sk)
{ {
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
struct sock *parent = subflow->conn; struct sock *parent = subflow->conn;
struct mptcp_sock *msk;
__subflow_state_change(sk); __subflow_state_change(sk);
msk = mptcp_sk(parent);
if (subflow_simultaneous_connect(sk)) { if (subflow_simultaneous_connect(sk)) {
mptcp_propagate_sndbuf(parent, sk); mptcp_propagate_sndbuf(parent, sk);
mptcp_do_fallback(sk); mptcp_do_fallback(sk);
mptcp_rcv_space_init(mptcp_sk(parent), sk); mptcp_rcv_space_init(msk, sk);
pr_fallback(mptcp_sk(parent)); pr_fallback(msk);
subflow->conn_finished = 1; subflow->conn_finished = 1;
mptcp_set_connected(parent); mptcp_set_connected(parent);
} }
@ -1772,11 +1774,12 @@ static void subflow_state_change(struct sock *sk)
subflow_sched_work_if_closed(mptcp_sk(parent), sk); subflow_sched_work_if_closed(mptcp_sk(parent), sk);
if (__mptcp_check_fallback(mptcp_sk(parent)) && /* when the fallback subflow closes the rx side, trigger a 'dummy'
!subflow->rx_eof && subflow_is_done(sk)) { * ingress data fin, so that the msk state will follow along
subflow->rx_eof = 1; */
mptcp_subflow_eof(parent); if (__mptcp_check_fallback(msk) && subflow_is_done(sk) && msk->first == sk &&
} mptcp_update_rcv_data_fin(msk, READ_ONCE(msk->ack_seq), true))
mptcp_schedule_work(parent);
} }
void mptcp_subflow_queue_clean(struct sock *listener_sk, struct sock *listener_ssk) void mptcp_subflow_queue_clean(struct sock *listener_sk, struct sock *listener_ssk)

View File

@ -1207,6 +1207,7 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
skb->transport_header = skb->network_header; skb->transport_header = skb->network_header;
skb_set_inner_ipproto(skb, next_protocol); skb_set_inner_ipproto(skb, next_protocol);
skb_set_inner_mac_header(skb, skb_inner_network_offset(skb));
if (tun_type == IP_VS_CONN_F_TUNNEL_TYPE_GUE) { if (tun_type == IP_VS_CONN_F_TUNNEL_TYPE_GUE) {
bool check = false; bool check = false;
@ -1349,6 +1350,7 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
skb->transport_header = skb->network_header; skb->transport_header = skb->network_header;
skb_set_inner_ipproto(skb, next_protocol); skb_set_inner_ipproto(skb, next_protocol);
skb_set_inner_mac_header(skb, skb_inner_network_offset(skb));
if (tun_type == IP_VS_CONN_F_TUNNEL_TYPE_GUE) { if (tun_type == IP_VS_CONN_F_TUNNEL_TYPE_GUE) {
bool check = false; bool check = false;

View File

@ -151,6 +151,7 @@ static struct nft_trans *nft_trans_alloc_gfp(const struct nft_ctx *ctx,
return NULL; return NULL;
INIT_LIST_HEAD(&trans->list); INIT_LIST_HEAD(&trans->list);
INIT_LIST_HEAD(&trans->binding_list);
trans->msg_type = msg_type; trans->msg_type = msg_type;
trans->ctx = *ctx; trans->ctx = *ctx;
@ -163,13 +164,20 @@ static struct nft_trans *nft_trans_alloc(const struct nft_ctx *ctx,
return nft_trans_alloc_gfp(ctx, msg_type, size, GFP_KERNEL); return nft_trans_alloc_gfp(ctx, msg_type, size, GFP_KERNEL);
} }
static void nft_trans_destroy(struct nft_trans *trans) static void nft_trans_list_del(struct nft_trans *trans)
{ {
list_del(&trans->list); list_del(&trans->list);
list_del(&trans->binding_list);
}
static void nft_trans_destroy(struct nft_trans *trans)
{
nft_trans_list_del(trans);
kfree(trans); kfree(trans);
} }
static void nft_set_trans_bind(const struct nft_ctx *ctx, struct nft_set *set) static void __nft_set_trans_bind(const struct nft_ctx *ctx, struct nft_set *set,
bool bind)
{ {
struct nftables_pernet *nft_net; struct nftables_pernet *nft_net;
struct net *net = ctx->net; struct net *net = ctx->net;
@ -183,16 +191,80 @@ static void nft_set_trans_bind(const struct nft_ctx *ctx, struct nft_set *set)
switch (trans->msg_type) { switch (trans->msg_type) {
case NFT_MSG_NEWSET: case NFT_MSG_NEWSET:
if (nft_trans_set(trans) == set) if (nft_trans_set(trans) == set)
nft_trans_set_bound(trans) = true; nft_trans_set_bound(trans) = bind;
break; break;
case NFT_MSG_NEWSETELEM: case NFT_MSG_NEWSETELEM:
if (nft_trans_elem_set(trans) == set) if (nft_trans_elem_set(trans) == set)
nft_trans_elem_set_bound(trans) = true; nft_trans_elem_set_bound(trans) = bind;
break; break;
} }
} }
} }
static void nft_set_trans_bind(const struct nft_ctx *ctx, struct nft_set *set)
{
return __nft_set_trans_bind(ctx, set, true);
}
static void nft_set_trans_unbind(const struct nft_ctx *ctx, struct nft_set *set)
{
return __nft_set_trans_bind(ctx, set, false);
}
static void __nft_chain_trans_bind(const struct nft_ctx *ctx,
struct nft_chain *chain, bool bind)
{
struct nftables_pernet *nft_net;
struct net *net = ctx->net;
struct nft_trans *trans;
if (!nft_chain_binding(chain))
return;
nft_net = nft_pernet(net);
list_for_each_entry_reverse(trans, &nft_net->commit_list, list) {
switch (trans->msg_type) {
case NFT_MSG_NEWCHAIN:
if (nft_trans_chain(trans) == chain)
nft_trans_chain_bound(trans) = bind;
break;
case NFT_MSG_NEWRULE:
if (trans->ctx.chain == chain)
nft_trans_rule_bound(trans) = bind;
break;
}
}
}
static void nft_chain_trans_bind(const struct nft_ctx *ctx,
struct nft_chain *chain)
{
__nft_chain_trans_bind(ctx, chain, true);
}
int nf_tables_bind_chain(const struct nft_ctx *ctx, struct nft_chain *chain)
{
if (!nft_chain_binding(chain))
return 0;
if (nft_chain_binding(ctx->chain))
return -EOPNOTSUPP;
if (chain->bound)
return -EBUSY;
chain->bound = true;
chain->use++;
nft_chain_trans_bind(ctx, chain);
return 0;
}
void nf_tables_unbind_chain(const struct nft_ctx *ctx, struct nft_chain *chain)
{
__nft_chain_trans_bind(ctx, chain, false);
}
static int nft_netdev_register_hooks(struct net *net, static int nft_netdev_register_hooks(struct net *net,
struct list_head *hook_list) struct list_head *hook_list)
{ {
@ -292,6 +364,19 @@ static void nft_trans_commit_list_add_tail(struct net *net, struct nft_trans *tr
{ {
struct nftables_pernet *nft_net = nft_pernet(net); struct nftables_pernet *nft_net = nft_pernet(net);
switch (trans->msg_type) {
case NFT_MSG_NEWSET:
if (!nft_trans_set_update(trans) &&
nft_set_is_anonymous(nft_trans_set(trans)))
list_add_tail(&trans->binding_list, &nft_net->binding_list);
break;
case NFT_MSG_NEWCHAIN:
if (!nft_trans_chain_update(trans) &&
nft_chain_binding(nft_trans_chain(trans)))
list_add_tail(&trans->binding_list, &nft_net->binding_list);
break;
}
list_add_tail(&trans->list, &nft_net->commit_list); list_add_tail(&trans->list, &nft_net->commit_list);
} }
@ -338,8 +423,9 @@ static struct nft_trans *nft_trans_chain_add(struct nft_ctx *ctx, int msg_type)
ntohl(nla_get_be32(ctx->nla[NFTA_CHAIN_ID])); ntohl(nla_get_be32(ctx->nla[NFTA_CHAIN_ID]));
} }
} }
nft_trans_chain(trans) = ctx->chain;
nft_trans_commit_list_add_tail(ctx->net, trans); nft_trans_commit_list_add_tail(ctx->net, trans);
return trans; return trans;
} }
@ -357,8 +443,7 @@ static int nft_delchain(struct nft_ctx *ctx)
return 0; return 0;
} }
static void nft_rule_expr_activate(const struct nft_ctx *ctx, void nft_rule_expr_activate(const struct nft_ctx *ctx, struct nft_rule *rule)
struct nft_rule *rule)
{ {
struct nft_expr *expr; struct nft_expr *expr;
@ -371,9 +456,8 @@ static void nft_rule_expr_activate(const struct nft_ctx *ctx,
} }
} }
static void nft_rule_expr_deactivate(const struct nft_ctx *ctx, void nft_rule_expr_deactivate(const struct nft_ctx *ctx, struct nft_rule *rule,
struct nft_rule *rule, enum nft_trans_phase phase)
enum nft_trans_phase phase)
{ {
struct nft_expr *expr; struct nft_expr *expr;
@ -495,6 +579,58 @@ static int nft_trans_set_add(const struct nft_ctx *ctx, int msg_type,
return __nft_trans_set_add(ctx, msg_type, set, NULL); return __nft_trans_set_add(ctx, msg_type, set, NULL);
} }
static void nft_setelem_data_deactivate(const struct net *net,
const struct nft_set *set,
struct nft_set_elem *elem);
static int nft_mapelem_deactivate(const struct nft_ctx *ctx,
struct nft_set *set,
const struct nft_set_iter *iter,
struct nft_set_elem *elem)
{
nft_setelem_data_deactivate(ctx->net, set, elem);
return 0;
}
struct nft_set_elem_catchall {
struct list_head list;
struct rcu_head rcu;
void *elem;
};
static void nft_map_catchall_deactivate(const struct nft_ctx *ctx,
struct nft_set *set)
{
u8 genmask = nft_genmask_next(ctx->net);
struct nft_set_elem_catchall *catchall;
struct nft_set_elem elem;
struct nft_set_ext *ext;
list_for_each_entry(catchall, &set->catchall_list, list) {
ext = nft_set_elem_ext(set, catchall->elem);
if (!nft_set_elem_active(ext, genmask))
continue;
elem.priv = catchall->elem;
nft_setelem_data_deactivate(ctx->net, set, &elem);
break;
}
}
static void nft_map_deactivate(const struct nft_ctx *ctx, struct nft_set *set)
{
struct nft_set_iter iter = {
.genmask = nft_genmask_next(ctx->net),
.fn = nft_mapelem_deactivate,
};
set->ops->walk(ctx, set, &iter);
WARN_ON_ONCE(iter.err);
nft_map_catchall_deactivate(ctx, set);
}
static int nft_delset(const struct nft_ctx *ctx, struct nft_set *set) static int nft_delset(const struct nft_ctx *ctx, struct nft_set *set)
{ {
int err; int err;
@ -503,6 +639,9 @@ static int nft_delset(const struct nft_ctx *ctx, struct nft_set *set)
if (err < 0) if (err < 0)
return err; return err;
if (set->flags & (NFT_SET_MAP | NFT_SET_OBJECT))
nft_map_deactivate(ctx, set);
nft_deactivate_next(ctx->net, set); nft_deactivate_next(ctx->net, set);
ctx->table->use--; ctx->table->use--;
@ -2226,7 +2365,7 @@ static int nft_basechain_init(struct nft_base_chain *basechain, u8 family,
return 0; return 0;
} }
static int nft_chain_add(struct nft_table *table, struct nft_chain *chain) int nft_chain_add(struct nft_table *table, struct nft_chain *chain)
{ {
int err; int err;
@ -2528,6 +2667,8 @@ static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy,
nft_trans_basechain(trans) = basechain; nft_trans_basechain(trans) = basechain;
INIT_LIST_HEAD(&nft_trans_chain_hooks(trans)); INIT_LIST_HEAD(&nft_trans_chain_hooks(trans));
list_splice(&hook.list, &nft_trans_chain_hooks(trans)); list_splice(&hook.list, &nft_trans_chain_hooks(trans));
if (nla[NFTA_CHAIN_HOOK])
module_put(hook.type->owner);
nft_trans_commit_list_add_tail(ctx->net, trans); nft_trans_commit_list_add_tail(ctx->net, trans);
@ -2670,21 +2811,18 @@ static int nf_tables_newchain(struct sk_buff *skb, const struct nfnl_info *info,
return nf_tables_addchain(&ctx, family, genmask, policy, flags, extack); return nf_tables_addchain(&ctx, family, genmask, policy, flags, extack);
} }
static int nft_delchain_hook(struct nft_ctx *ctx, struct nft_chain *chain, static int nft_delchain_hook(struct nft_ctx *ctx,
struct nft_base_chain *basechain,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
const struct nft_chain *chain = &basechain->chain;
const struct nlattr * const *nla = ctx->nla; const struct nlattr * const *nla = ctx->nla;
struct nft_chain_hook chain_hook = {}; struct nft_chain_hook chain_hook = {};
struct nft_base_chain *basechain;
struct nft_hook *this, *hook; struct nft_hook *this, *hook;
LIST_HEAD(chain_del_list); LIST_HEAD(chain_del_list);
struct nft_trans *trans; struct nft_trans *trans;
int err; int err;
if (!nft_is_base_chain(chain))
return -EOPNOTSUPP;
basechain = nft_base_chain(chain);
err = nft_chain_parse_hook(ctx->net, basechain, nla, &chain_hook, err = nft_chain_parse_hook(ctx->net, basechain, nla, &chain_hook,
ctx->family, chain->flags, extack); ctx->family, chain->flags, extack);
if (err < 0) if (err < 0)
@ -2769,7 +2907,12 @@ static int nf_tables_delchain(struct sk_buff *skb, const struct nfnl_info *info,
if (chain->flags & NFT_CHAIN_HW_OFFLOAD) if (chain->flags & NFT_CHAIN_HW_OFFLOAD)
return -EOPNOTSUPP; return -EOPNOTSUPP;
return nft_delchain_hook(&ctx, chain, extack); if (nft_is_base_chain(chain)) {
struct nft_base_chain *basechain = nft_base_chain(chain);
if (nft_base_chain_netdev(table->family, basechain->ops.hooknum))
return nft_delchain_hook(&ctx, basechain, extack);
}
} }
if (info->nlh->nlmsg_flags & NLM_F_NONREC && if (info->nlh->nlmsg_flags & NLM_F_NONREC &&
@ -3490,8 +3633,7 @@ err_fill_rule_info:
return err; return err;
} }
static void nf_tables_rule_destroy(const struct nft_ctx *ctx, void nf_tables_rule_destroy(const struct nft_ctx *ctx, struct nft_rule *rule)
struct nft_rule *rule)
{ {
struct nft_expr *expr, *next; struct nft_expr *expr, *next;
@ -3508,7 +3650,7 @@ static void nf_tables_rule_destroy(const struct nft_ctx *ctx,
kfree(rule); kfree(rule);
} }
void nf_tables_rule_release(const struct nft_ctx *ctx, struct nft_rule *rule) static void nf_tables_rule_release(const struct nft_ctx *ctx, struct nft_rule *rule)
{ {
nft_rule_expr_deactivate(ctx, rule, NFT_TRANS_RELEASE); nft_rule_expr_deactivate(ctx, rule, NFT_TRANS_RELEASE);
nf_tables_rule_destroy(ctx, rule); nf_tables_rule_destroy(ctx, rule);
@ -3596,12 +3738,6 @@ int nft_setelem_validate(const struct nft_ctx *ctx, struct nft_set *set,
return 0; return 0;
} }
struct nft_set_elem_catchall {
struct list_head list;
struct rcu_head rcu;
void *elem;
};
int nft_set_catchall_validate(const struct nft_ctx *ctx, struct nft_set *set) int nft_set_catchall_validate(const struct nft_ctx *ctx, struct nft_set *set)
{ {
u8 genmask = nft_genmask_next(ctx->net); u8 genmask = nft_genmask_next(ctx->net);
@ -3844,7 +3980,7 @@ err_destroy_flow_rule:
if (flow) if (flow)
nft_flow_rule_destroy(flow); nft_flow_rule_destroy(flow);
err_release_rule: err_release_rule:
nft_rule_expr_deactivate(&ctx, rule, NFT_TRANS_PREPARE); nft_rule_expr_deactivate(&ctx, rule, NFT_TRANS_PREPARE_ERROR);
nf_tables_rule_destroy(&ctx, rule); nf_tables_rule_destroy(&ctx, rule);
err_release_expr: err_release_expr:
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
@ -4777,6 +4913,9 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,
if (!(flags & NFT_SET_TIMEOUT)) if (!(flags & NFT_SET_TIMEOUT))
return -EINVAL; return -EINVAL;
if (flags & NFT_SET_ANONYMOUS)
return -EOPNOTSUPP;
err = nf_msecs_to_jiffies64(nla[NFTA_SET_TIMEOUT], &desc.timeout); err = nf_msecs_to_jiffies64(nla[NFTA_SET_TIMEOUT], &desc.timeout);
if (err) if (err)
return err; return err;
@ -4785,6 +4924,10 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,
if (nla[NFTA_SET_GC_INTERVAL] != NULL) { if (nla[NFTA_SET_GC_INTERVAL] != NULL) {
if (!(flags & NFT_SET_TIMEOUT)) if (!(flags & NFT_SET_TIMEOUT))
return -EINVAL; return -EINVAL;
if (flags & NFT_SET_ANONYMOUS)
return -EOPNOTSUPP;
desc.gc_int = ntohl(nla_get_be32(nla[NFTA_SET_GC_INTERVAL])); desc.gc_int = ntohl(nla_get_be32(nla[NFTA_SET_GC_INTERVAL]));
} }
@ -4831,6 +4974,9 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,
if (info->nlh->nlmsg_flags & NLM_F_REPLACE) if (info->nlh->nlmsg_flags & NLM_F_REPLACE)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (nft_set_is_anonymous(set))
return -EOPNOTSUPP;
err = nft_set_expr_alloc(&ctx, set, nla, exprs, &num_exprs, flags); err = nft_set_expr_alloc(&ctx, set, nla, exprs, &num_exprs, flags);
if (err < 0) if (err < 0)
return err; return err;
@ -4934,7 +5080,7 @@ err_set_expr_alloc:
for (i = 0; i < set->num_exprs; i++) for (i = 0; i < set->num_exprs; i++)
nft_expr_destroy(&ctx, set->exprs[i]); nft_expr_destroy(&ctx, set->exprs[i]);
err_set_destroy: err_set_destroy:
ops->destroy(set); ops->destroy(&ctx, set);
err_set_init: err_set_init:
kfree(set->name); kfree(set->name);
err_set_name: err_set_name:
@ -4949,7 +5095,7 @@ static void nft_set_catchall_destroy(const struct nft_ctx *ctx,
list_for_each_entry_safe(catchall, next, &set->catchall_list, list) { list_for_each_entry_safe(catchall, next, &set->catchall_list, list) {
list_del_rcu(&catchall->list); list_del_rcu(&catchall->list);
nft_set_elem_destroy(set, catchall->elem, true); nf_tables_set_elem_destroy(ctx, set, catchall->elem);
kfree_rcu(catchall, rcu); kfree_rcu(catchall, rcu);
} }
} }
@ -4964,7 +5110,7 @@ static void nft_set_destroy(const struct nft_ctx *ctx, struct nft_set *set)
for (i = 0; i < set->num_exprs; i++) for (i = 0; i < set->num_exprs; i++)
nft_expr_destroy(ctx, set->exprs[i]); nft_expr_destroy(ctx, set->exprs[i]);
set->ops->destroy(set); set->ops->destroy(ctx, set);
nft_set_catchall_destroy(ctx, set); nft_set_catchall_destroy(ctx, set);
kfree(set->name); kfree(set->name);
kvfree(set); kvfree(set);
@ -5129,10 +5275,60 @@ static void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set,
} }
} }
static void nft_setelem_data_activate(const struct net *net,
const struct nft_set *set,
struct nft_set_elem *elem);
static int nft_mapelem_activate(const struct nft_ctx *ctx,
struct nft_set *set,
const struct nft_set_iter *iter,
struct nft_set_elem *elem)
{
nft_setelem_data_activate(ctx->net, set, elem);
return 0;
}
static void nft_map_catchall_activate(const struct nft_ctx *ctx,
struct nft_set *set)
{
u8 genmask = nft_genmask_next(ctx->net);
struct nft_set_elem_catchall *catchall;
struct nft_set_elem elem;
struct nft_set_ext *ext;
list_for_each_entry(catchall, &set->catchall_list, list) {
ext = nft_set_elem_ext(set, catchall->elem);
if (!nft_set_elem_active(ext, genmask))
continue;
elem.priv = catchall->elem;
nft_setelem_data_activate(ctx->net, set, &elem);
break;
}
}
static void nft_map_activate(const struct nft_ctx *ctx, struct nft_set *set)
{
struct nft_set_iter iter = {
.genmask = nft_genmask_next(ctx->net),
.fn = nft_mapelem_activate,
};
set->ops->walk(ctx, set, &iter);
WARN_ON_ONCE(iter.err);
nft_map_catchall_activate(ctx, set);
}
void nf_tables_activate_set(const struct nft_ctx *ctx, struct nft_set *set) void nf_tables_activate_set(const struct nft_ctx *ctx, struct nft_set *set)
{ {
if (nft_set_is_anonymous(set)) if (nft_set_is_anonymous(set)) {
if (set->flags & (NFT_SET_MAP | NFT_SET_OBJECT))
nft_map_activate(ctx, set);
nft_clear(ctx->net, set); nft_clear(ctx->net, set);
}
set->use++; set->use++;
} }
@ -5143,14 +5339,28 @@ void nf_tables_deactivate_set(const struct nft_ctx *ctx, struct nft_set *set,
enum nft_trans_phase phase) enum nft_trans_phase phase)
{ {
switch (phase) { switch (phase) {
case NFT_TRANS_PREPARE: case NFT_TRANS_PREPARE_ERROR:
nft_set_trans_unbind(ctx, set);
if (nft_set_is_anonymous(set)) if (nft_set_is_anonymous(set))
nft_deactivate_next(ctx->net, set); nft_deactivate_next(ctx->net, set);
set->use--;
break;
case NFT_TRANS_PREPARE:
if (nft_set_is_anonymous(set)) {
if (set->flags & (NFT_SET_MAP | NFT_SET_OBJECT))
nft_map_deactivate(ctx, set);
nft_deactivate_next(ctx->net, set);
}
set->use--; set->use--;
return; return;
case NFT_TRANS_ABORT: case NFT_TRANS_ABORT:
case NFT_TRANS_RELEASE: case NFT_TRANS_RELEASE:
if (nft_set_is_anonymous(set) &&
set->flags & (NFT_SET_MAP | NFT_SET_OBJECT))
nft_map_deactivate(ctx, set);
set->use--; set->use--;
fallthrough; fallthrough;
default: default:
@ -5903,6 +6113,7 @@ static void nft_set_elem_expr_destroy(const struct nft_ctx *ctx,
__nft_set_elem_expr_destroy(ctx, expr); __nft_set_elem_expr_destroy(ctx, expr);
} }
/* Drop references and destroy. Called from gc, dynset and abort path. */
void nft_set_elem_destroy(const struct nft_set *set, void *elem, void nft_set_elem_destroy(const struct nft_set *set, void *elem,
bool destroy_expr) bool destroy_expr)
{ {
@ -5924,11 +6135,11 @@ void nft_set_elem_destroy(const struct nft_set *set, void *elem,
} }
EXPORT_SYMBOL_GPL(nft_set_elem_destroy); EXPORT_SYMBOL_GPL(nft_set_elem_destroy);
/* Only called from commit path, nft_setelem_data_deactivate() already deals /* Destroy element. References have been already dropped in the preparation
* with the refcounting from the preparation phase. * path via nft_setelem_data_deactivate().
*/ */
static void nf_tables_set_elem_destroy(const struct nft_ctx *ctx, void nf_tables_set_elem_destroy(const struct nft_ctx *ctx,
const struct nft_set *set, void *elem) const struct nft_set *set, void *elem)
{ {
struct nft_set_ext *ext = nft_set_elem_ext(set, elem); struct nft_set_ext *ext = nft_set_elem_ext(set, elem);
@ -6491,19 +6702,19 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
if (flags) if (flags)
*nft_set_ext_flags(ext) = flags; *nft_set_ext_flags(ext) = flags;
if (obj) {
*nft_set_ext_obj(ext) = obj;
obj->use++;
}
if (ulen > 0) { if (ulen > 0) {
if (nft_set_ext_check(&tmpl, NFT_SET_EXT_USERDATA, ulen) < 0) { if (nft_set_ext_check(&tmpl, NFT_SET_EXT_USERDATA, ulen) < 0) {
err = -EINVAL; err = -EINVAL;
goto err_elem_userdata; goto err_elem_free;
} }
udata = nft_set_ext_userdata(ext); udata = nft_set_ext_userdata(ext);
udata->len = ulen - 1; udata->len = ulen - 1;
nla_memcpy(&udata->data, nla[NFTA_SET_ELEM_USERDATA], ulen); nla_memcpy(&udata->data, nla[NFTA_SET_ELEM_USERDATA], ulen);
} }
if (obj) {
*nft_set_ext_obj(ext) = obj;
obj->use++;
}
err = nft_set_elem_expr_setup(ctx, &tmpl, ext, expr_array, num_exprs); err = nft_set_elem_expr_setup(ctx, &tmpl, ext, expr_array, num_exprs);
if (err < 0) if (err < 0)
goto err_elem_free; goto err_elem_free;
@ -6558,10 +6769,7 @@ err_set_full:
err_element_clash: err_element_clash:
kfree(trans); kfree(trans);
err_elem_free: err_elem_free:
if (obj) nft_set_elem_destroy(set, elem.priv, true);
obj->use--;
err_elem_userdata:
nf_tables_set_elem_destroy(ctx, set, elem.priv);
err_parse_data: err_parse_data:
if (nla[NFTA_SET_ELEM_DATA] != NULL) if (nla[NFTA_SET_ELEM_DATA] != NULL)
nft_data_release(&elem.data.val, desc.type); nft_data_release(&elem.data.val, desc.type);
@ -6605,7 +6813,8 @@ static int nf_tables_newsetelem(struct sk_buff *skb,
if (IS_ERR(set)) if (IS_ERR(set))
return PTR_ERR(set); return PTR_ERR(set);
if (!list_empty(&set->bindings) && set->flags & NFT_SET_CONSTANT) if (!list_empty(&set->bindings) &&
(set->flags & (NFT_SET_CONSTANT | NFT_SET_ANONYMOUS)))
return -EBUSY; return -EBUSY;
nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla); nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla);
@ -6638,7 +6847,6 @@ static int nf_tables_newsetelem(struct sk_buff *skb,
void nft_data_hold(const struct nft_data *data, enum nft_data_types type) void nft_data_hold(const struct nft_data *data, enum nft_data_types type)
{ {
struct nft_chain *chain; struct nft_chain *chain;
struct nft_rule *rule;
if (type == NFT_DATA_VERDICT) { if (type == NFT_DATA_VERDICT) {
switch (data->verdict.code) { switch (data->verdict.code) {
@ -6646,15 +6854,6 @@ void nft_data_hold(const struct nft_data *data, enum nft_data_types type)
case NFT_GOTO: case NFT_GOTO:
chain = data->verdict.chain; chain = data->verdict.chain;
chain->use++; chain->use++;
if (!nft_chain_is_bound(chain))
break;
chain->table->use++;
list_for_each_entry(rule, &chain->rules, list)
chain->use++;
nft_chain_add(chain->table, chain);
break; break;
} }
} }
@ -6889,7 +7088,9 @@ static int nf_tables_delsetelem(struct sk_buff *skb,
set = nft_set_lookup(table, nla[NFTA_SET_ELEM_LIST_SET], genmask); set = nft_set_lookup(table, nla[NFTA_SET_ELEM_LIST_SET], genmask);
if (IS_ERR(set)) if (IS_ERR(set))
return PTR_ERR(set); return PTR_ERR(set);
if (!list_empty(&set->bindings) && set->flags & NFT_SET_CONSTANT)
if (!list_empty(&set->bindings) &&
(set->flags & (NFT_SET_CONSTANT | NFT_SET_ANONYMOUS)))
return -EBUSY; return -EBUSY;
nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla); nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla);
@ -7671,6 +7872,7 @@ void nf_tables_deactivate_flowtable(const struct nft_ctx *ctx,
enum nft_trans_phase phase) enum nft_trans_phase phase)
{ {
switch (phase) { switch (phase) {
case NFT_TRANS_PREPARE_ERROR:
case NFT_TRANS_PREPARE: case NFT_TRANS_PREPARE:
case NFT_TRANS_ABORT: case NFT_TRANS_ABORT:
case NFT_TRANS_RELEASE: case NFT_TRANS_RELEASE:
@ -8943,7 +9145,7 @@ static void nf_tables_trans_destroy_work(struct work_struct *w)
synchronize_rcu(); synchronize_rcu();
list_for_each_entry_safe(trans, next, &head, list) { list_for_each_entry_safe(trans, next, &head, list) {
list_del(&trans->list); nft_trans_list_del(trans);
nft_commit_release(trans); nft_commit_release(trans);
} }
} }
@ -9308,6 +9510,27 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
return 0; return 0;
} }
list_for_each_entry(trans, &nft_net->binding_list, binding_list) {
switch (trans->msg_type) {
case NFT_MSG_NEWSET:
if (!nft_trans_set_update(trans) &&
nft_set_is_anonymous(nft_trans_set(trans)) &&
!nft_trans_set_bound(trans)) {
pr_warn_once("nftables ruleset with unbound set\n");
return -EINVAL;
}
break;
case NFT_MSG_NEWCHAIN:
if (!nft_trans_chain_update(trans) &&
nft_chain_binding(nft_trans_chain(trans)) &&
!nft_trans_chain_bound(trans)) {
pr_warn_once("nftables ruleset with unbound chain\n");
return -EINVAL;
}
break;
}
}
/* 0. Validate ruleset, otherwise roll back for error reporting. */ /* 0. Validate ruleset, otherwise roll back for error reporting. */
if (nf_tables_validate(net) < 0) if (nf_tables_validate(net) < 0)
return -EAGAIN; return -EAGAIN;
@ -9677,7 +9900,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
kfree(nft_trans_chain_name(trans)); kfree(nft_trans_chain_name(trans));
nft_trans_destroy(trans); nft_trans_destroy(trans);
} else { } else {
if (nft_chain_is_bound(trans->ctx.chain)) { if (nft_trans_chain_bound(trans)) {
nft_trans_destroy(trans); nft_trans_destroy(trans);
break; break;
} }
@ -9700,6 +9923,10 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
nft_trans_destroy(trans); nft_trans_destroy(trans);
break; break;
case NFT_MSG_NEWRULE: case NFT_MSG_NEWRULE:
if (nft_trans_rule_bound(trans)) {
nft_trans_destroy(trans);
break;
}
trans->ctx.chain->use--; trans->ctx.chain->use--;
list_del_rcu(&nft_trans_rule(trans)->list); list_del_rcu(&nft_trans_rule(trans)->list);
nft_rule_expr_deactivate(&trans->ctx, nft_rule_expr_deactivate(&trans->ctx,
@ -9734,6 +9961,9 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
case NFT_MSG_DESTROYSET: case NFT_MSG_DESTROYSET:
trans->ctx.table->use++; trans->ctx.table->use++;
nft_clear(trans->ctx.net, nft_trans_set(trans)); nft_clear(trans->ctx.net, nft_trans_set(trans));
if (nft_trans_set(trans)->flags & (NFT_SET_MAP | NFT_SET_OBJECT))
nft_map_activate(&trans->ctx, nft_trans_set(trans));
nft_trans_destroy(trans); nft_trans_destroy(trans);
break; break;
case NFT_MSG_NEWSETELEM: case NFT_MSG_NEWSETELEM:
@ -9814,7 +10044,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
list_for_each_entry_safe_reverse(trans, next, list_for_each_entry_safe_reverse(trans, next,
&nft_net->commit_list, list) { &nft_net->commit_list, list) {
list_del(&trans->list); nft_trans_list_del(trans);
nf_tables_abort_release(trans); nf_tables_abort_release(trans);
} }
@ -10263,22 +10493,12 @@ static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
static void nft_verdict_uninit(const struct nft_data *data) static void nft_verdict_uninit(const struct nft_data *data)
{ {
struct nft_chain *chain; struct nft_chain *chain;
struct nft_rule *rule;
switch (data->verdict.code) { switch (data->verdict.code) {
case NFT_JUMP: case NFT_JUMP:
case NFT_GOTO: case NFT_GOTO:
chain = data->verdict.chain; chain = data->verdict.chain;
chain->use--; chain->use--;
if (!nft_chain_is_bound(chain))
break;
chain->table->use--;
list_for_each_entry(rule, &chain->rules, list)
chain->use--;
nft_chain_del(chain);
break; break;
} }
} }
@ -10513,6 +10733,9 @@ static void __nft_release_table(struct net *net, struct nft_table *table)
list_for_each_entry_safe(set, ns, &table->sets, list) { list_for_each_entry_safe(set, ns, &table->sets, list) {
list_del(&set->list); list_del(&set->list);
table->use--; table->use--;
if (set->flags & (NFT_SET_MAP | NFT_SET_OBJECT))
nft_map_deactivate(&ctx, set);
nft_set_destroy(&ctx, set); nft_set_destroy(&ctx, set);
} }
list_for_each_entry_safe(obj, ne, &table->objects, list) { list_for_each_entry_safe(obj, ne, &table->objects, list) {
@ -10597,6 +10820,7 @@ static int __net_init nf_tables_init_net(struct net *net)
INIT_LIST_HEAD(&nft_net->tables); INIT_LIST_HEAD(&nft_net->tables);
INIT_LIST_HEAD(&nft_net->commit_list); INIT_LIST_HEAD(&nft_net->commit_list);
INIT_LIST_HEAD(&nft_net->binding_list);
INIT_LIST_HEAD(&nft_net->module_list); INIT_LIST_HEAD(&nft_net->module_list);
INIT_LIST_HEAD(&nft_net->notify_list); INIT_LIST_HEAD(&nft_net->notify_list);
mutex_init(&nft_net->commit_mutex); mutex_init(&nft_net->commit_mutex);

View File

@ -439,3 +439,4 @@ module_init(nfnl_osf_init);
module_exit(nfnl_osf_fini); module_exit(nfnl_osf_fini);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_OSF);

View File

@ -76,11 +76,9 @@ static int nft_immediate_init(const struct nft_ctx *ctx,
switch (priv->data.verdict.code) { switch (priv->data.verdict.code) {
case NFT_JUMP: case NFT_JUMP:
case NFT_GOTO: case NFT_GOTO:
if (nft_chain_is_bound(chain)) { err = nf_tables_bind_chain(ctx, chain);
err = -EBUSY; if (err < 0)
goto err1; return err;
}
chain->bound = true;
break; break;
default: default:
break; break;
@ -98,6 +96,31 @@ static void nft_immediate_activate(const struct nft_ctx *ctx,
const struct nft_expr *expr) const struct nft_expr *expr)
{ {
const struct nft_immediate_expr *priv = nft_expr_priv(expr); const struct nft_immediate_expr *priv = nft_expr_priv(expr);
const struct nft_data *data = &priv->data;
struct nft_ctx chain_ctx;
struct nft_chain *chain;
struct nft_rule *rule;
if (priv->dreg == NFT_REG_VERDICT) {
switch (data->verdict.code) {
case NFT_JUMP:
case NFT_GOTO:
chain = data->verdict.chain;
if (!nft_chain_binding(chain))
break;
chain_ctx = *ctx;
chain_ctx.chain = chain;
list_for_each_entry(rule, &chain->rules, list)
nft_rule_expr_activate(&chain_ctx, rule);
nft_clear(ctx->net, chain);
break;
default:
break;
}
}
return nft_data_hold(&priv->data, nft_dreg_to_type(priv->dreg)); return nft_data_hold(&priv->data, nft_dreg_to_type(priv->dreg));
} }
@ -107,6 +130,43 @@ static void nft_immediate_deactivate(const struct nft_ctx *ctx,
enum nft_trans_phase phase) enum nft_trans_phase phase)
{ {
const struct nft_immediate_expr *priv = nft_expr_priv(expr); const struct nft_immediate_expr *priv = nft_expr_priv(expr);
const struct nft_data *data = &priv->data;
struct nft_ctx chain_ctx;
struct nft_chain *chain;
struct nft_rule *rule;
if (priv->dreg == NFT_REG_VERDICT) {
switch (data->verdict.code) {
case NFT_JUMP:
case NFT_GOTO:
chain = data->verdict.chain;
if (!nft_chain_binding(chain))
break;
chain_ctx = *ctx;
chain_ctx.chain = chain;
list_for_each_entry(rule, &chain->rules, list)
nft_rule_expr_deactivate(&chain_ctx, rule, phase);
switch (phase) {
case NFT_TRANS_PREPARE_ERROR:
nf_tables_unbind_chain(ctx, chain);
fallthrough;
case NFT_TRANS_PREPARE:
nft_deactivate_next(ctx->net, chain);
break;
default:
nft_chain_del(chain);
chain->bound = false;
chain->table->use--;
break;
}
break;
default:
break;
}
}
if (phase == NFT_TRANS_COMMIT) if (phase == NFT_TRANS_COMMIT)
return; return;
@ -131,15 +191,27 @@ static void nft_immediate_destroy(const struct nft_ctx *ctx,
case NFT_GOTO: case NFT_GOTO:
chain = data->verdict.chain; chain = data->verdict.chain;
if (!nft_chain_is_bound(chain)) if (!nft_chain_binding(chain))
break; break;
/* Rule construction failed, but chain is already bound:
* let the transaction records release this chain and its rules.
*/
if (chain->bound) {
chain->use--;
break;
}
/* Rule has been deleted, release chain and its rules. */
chain_ctx = *ctx; chain_ctx = *ctx;
chain_ctx.chain = chain; chain_ctx.chain = chain;
list_for_each_entry_safe(rule, n, &chain->rules, list) chain->use--;
nf_tables_rule_release(&chain_ctx, rule); list_for_each_entry_safe(rule, n, &chain->rules, list) {
chain->use--;
list_del(&rule->list);
nf_tables_rule_destroy(&chain_ctx, rule);
}
nf_tables_chain_destroy(&chain_ctx); nf_tables_chain_destroy(&chain_ctx);
break; break;
default: default:

View File

@ -271,13 +271,14 @@ static int nft_bitmap_init(const struct nft_set *set,
return 0; return 0;
} }
static void nft_bitmap_destroy(const struct nft_set *set) static void nft_bitmap_destroy(const struct nft_ctx *ctx,
const struct nft_set *set)
{ {
struct nft_bitmap *priv = nft_set_priv(set); struct nft_bitmap *priv = nft_set_priv(set);
struct nft_bitmap_elem *be, *n; struct nft_bitmap_elem *be, *n;
list_for_each_entry_safe(be, n, &priv->list, head) list_for_each_entry_safe(be, n, &priv->list, head)
nft_set_elem_destroy(set, be, true); nf_tables_set_elem_destroy(ctx, set, be);
} }
static bool nft_bitmap_estimate(const struct nft_set_desc *desc, u32 features, static bool nft_bitmap_estimate(const struct nft_set_desc *desc, u32 features,

View File

@ -400,19 +400,31 @@ static int nft_rhash_init(const struct nft_set *set,
return 0; return 0;
} }
struct nft_rhash_ctx {
const struct nft_ctx ctx;
const struct nft_set *set;
};
static void nft_rhash_elem_destroy(void *ptr, void *arg) static void nft_rhash_elem_destroy(void *ptr, void *arg)
{ {
nft_set_elem_destroy(arg, ptr, true); struct nft_rhash_ctx *rhash_ctx = arg;
nf_tables_set_elem_destroy(&rhash_ctx->ctx, rhash_ctx->set, ptr);
} }
static void nft_rhash_destroy(const struct nft_set *set) static void nft_rhash_destroy(const struct nft_ctx *ctx,
const struct nft_set *set)
{ {
struct nft_rhash *priv = nft_set_priv(set); struct nft_rhash *priv = nft_set_priv(set);
struct nft_rhash_ctx rhash_ctx = {
.ctx = *ctx,
.set = set,
};
cancel_delayed_work_sync(&priv->gc_work); cancel_delayed_work_sync(&priv->gc_work);
rcu_barrier(); rcu_barrier();
rhashtable_free_and_destroy(&priv->ht, nft_rhash_elem_destroy, rhashtable_free_and_destroy(&priv->ht, nft_rhash_elem_destroy,
(void *)set); (void *)&rhash_ctx);
} }
/* Number of buckets is stored in u32, so cap our result to 1U<<31 */ /* Number of buckets is stored in u32, so cap our result to 1U<<31 */
@ -643,7 +655,8 @@ static int nft_hash_init(const struct nft_set *set,
return 0; return 0;
} }
static void nft_hash_destroy(const struct nft_set *set) static void nft_hash_destroy(const struct nft_ctx *ctx,
const struct nft_set *set)
{ {
struct nft_hash *priv = nft_set_priv(set); struct nft_hash *priv = nft_set_priv(set);
struct nft_hash_elem *he; struct nft_hash_elem *he;
@ -653,7 +666,7 @@ static void nft_hash_destroy(const struct nft_set *set)
for (i = 0; i < priv->buckets; i++) { for (i = 0; i < priv->buckets; i++) {
hlist_for_each_entry_safe(he, next, &priv->table[i], node) { hlist_for_each_entry_safe(he, next, &priv->table[i], node) {
hlist_del_rcu(&he->node); hlist_del_rcu(&he->node);
nft_set_elem_destroy(set, he, true); nf_tables_set_elem_destroy(ctx, set, he);
} }
} }
} }

View File

@ -1974,12 +1974,16 @@ static void nft_pipapo_walk(const struct nft_ctx *ctx, struct nft_set *set,
struct nft_set_iter *iter) struct nft_set_iter *iter)
{ {
struct nft_pipapo *priv = nft_set_priv(set); struct nft_pipapo *priv = nft_set_priv(set);
struct net *net = read_pnet(&set->net);
struct nft_pipapo_match *m; struct nft_pipapo_match *m;
struct nft_pipapo_field *f; struct nft_pipapo_field *f;
int i, r; int i, r;
rcu_read_lock(); rcu_read_lock();
m = rcu_dereference(priv->match); if (iter->genmask == nft_genmask_cur(net))
m = rcu_dereference(priv->match);
else
m = priv->clone;
if (unlikely(!m)) if (unlikely(!m))
goto out; goto out;
@ -2148,10 +2152,12 @@ out_scratch:
/** /**
* nft_set_pipapo_match_destroy() - Destroy elements from key mapping array * nft_set_pipapo_match_destroy() - Destroy elements from key mapping array
* @ctx: context
* @set: nftables API set representation * @set: nftables API set representation
* @m: matching data pointing to key mapping array * @m: matching data pointing to key mapping array
*/ */
static void nft_set_pipapo_match_destroy(const struct nft_set *set, static void nft_set_pipapo_match_destroy(const struct nft_ctx *ctx,
const struct nft_set *set,
struct nft_pipapo_match *m) struct nft_pipapo_match *m)
{ {
struct nft_pipapo_field *f; struct nft_pipapo_field *f;
@ -2168,15 +2174,17 @@ static void nft_set_pipapo_match_destroy(const struct nft_set *set,
e = f->mt[r].e; e = f->mt[r].e;
nft_set_elem_destroy(set, e, true); nf_tables_set_elem_destroy(ctx, set, e);
} }
} }
/** /**
* nft_pipapo_destroy() - Free private data for set and all committed elements * nft_pipapo_destroy() - Free private data for set and all committed elements
* @ctx: context
* @set: nftables API set representation * @set: nftables API set representation
*/ */
static void nft_pipapo_destroy(const struct nft_set *set) static void nft_pipapo_destroy(const struct nft_ctx *ctx,
const struct nft_set *set)
{ {
struct nft_pipapo *priv = nft_set_priv(set); struct nft_pipapo *priv = nft_set_priv(set);
struct nft_pipapo_match *m; struct nft_pipapo_match *m;
@ -2186,7 +2194,7 @@ static void nft_pipapo_destroy(const struct nft_set *set)
if (m) { if (m) {
rcu_barrier(); rcu_barrier();
nft_set_pipapo_match_destroy(set, m); nft_set_pipapo_match_destroy(ctx, set, m);
#ifdef NFT_PIPAPO_ALIGN #ifdef NFT_PIPAPO_ALIGN
free_percpu(m->scratch_aligned); free_percpu(m->scratch_aligned);
@ -2203,7 +2211,7 @@ static void nft_pipapo_destroy(const struct nft_set *set)
m = priv->clone; m = priv->clone;
if (priv->dirty) if (priv->dirty)
nft_set_pipapo_match_destroy(set, m); nft_set_pipapo_match_destroy(ctx, set, m);
#ifdef NFT_PIPAPO_ALIGN #ifdef NFT_PIPAPO_ALIGN
free_percpu(priv->clone->scratch_aligned); free_percpu(priv->clone->scratch_aligned);

View File

@ -664,7 +664,8 @@ static int nft_rbtree_init(const struct nft_set *set,
return 0; return 0;
} }
static void nft_rbtree_destroy(const struct nft_set *set) static void nft_rbtree_destroy(const struct nft_ctx *ctx,
const struct nft_set *set)
{ {
struct nft_rbtree *priv = nft_set_priv(set); struct nft_rbtree *priv = nft_set_priv(set);
struct nft_rbtree_elem *rbe; struct nft_rbtree_elem *rbe;
@ -675,7 +676,7 @@ static void nft_rbtree_destroy(const struct nft_set *set)
while ((node = priv->root.rb_node) != NULL) { while ((node = priv->root.rb_node) != NULL) {
rb_erase(node, &priv->root); rb_erase(node, &priv->root);
rbe = rb_entry(node, struct nft_rbtree_elem, node); rbe = rb_entry(node, struct nft_rbtree_elem, node);
nft_set_elem_destroy(set, rbe, true); nf_tables_set_elem_destroy(ctx, set, rbe);
} }
} }

View File

@ -71,4 +71,3 @@ MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
MODULE_DESCRIPTION("Passive OS fingerprint matching."); MODULE_DESCRIPTION("Passive OS fingerprint matching.");
MODULE_ALIAS("ipt_osf"); MODULE_ALIAS("ipt_osf");
MODULE_ALIAS("ip6t_osf"); MODULE_ALIAS("ip6t_osf");
MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_OSF);

View File

@ -966,6 +966,7 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt,
if (ret < 0) if (ret < 0)
return ret; return ret;
sch_tree_lock(sch);
/* backup q->clg and q->loss_model */ /* backup q->clg and q->loss_model */
old_clg = q->clg; old_clg = q->clg;
old_loss_model = q->loss_model; old_loss_model = q->loss_model;
@ -974,7 +975,7 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt,
ret = get_loss_clg(q, tb[TCA_NETEM_LOSS]); ret = get_loss_clg(q, tb[TCA_NETEM_LOSS]);
if (ret) { if (ret) {
q->loss_model = old_loss_model; q->loss_model = old_loss_model;
return ret; goto unlock;
} }
} else { } else {
q->loss_model = CLG_RANDOM; q->loss_model = CLG_RANDOM;
@ -1041,6 +1042,8 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt,
/* capping jitter to the range acceptable by tabledist() */ /* capping jitter to the range acceptable by tabledist() */
q->jitter = min_t(s64, abs(q->jitter), INT_MAX); q->jitter = min_t(s64, abs(q->jitter), INT_MAX);
unlock:
sch_tree_unlock(sch);
return ret; return ret;
get_table_failure: get_table_failure:
@ -1050,7 +1053,8 @@ get_table_failure:
*/ */
q->clg = old_clg; q->clg = old_clg;
q->loss_model = old_loss_model; q->loss_model = old_loss_model;
return ret;
goto unlock;
} }
static int netem_init(struct Qdisc *sch, struct nlattr *opt, static int netem_init(struct Qdisc *sch, struct nlattr *opt,

View File

@ -131,6 +131,7 @@ struct sec_path *secpath_set(struct sk_buff *skb)
memset(sp->ovec, 0, sizeof(sp->ovec)); memset(sp->ovec, 0, sizeof(sp->ovec));
sp->olen = 0; sp->olen = 0;
sp->len = 0; sp->len = 0;
sp->verified_cnt = 0;
return sp; return sp;
} }
@ -330,11 +331,10 @@ xfrm_inner_mode_encap_remove(struct xfrm_state *x,
{ {
switch (x->props.mode) { switch (x->props.mode) {
case XFRM_MODE_BEET: case XFRM_MODE_BEET:
switch (XFRM_MODE_SKB_CB(skb)->protocol) { switch (x->sel.family) {
case IPPROTO_IPIP: case AF_INET:
case IPPROTO_BEETPH:
return xfrm4_remove_beet_encap(x, skb); return xfrm4_remove_beet_encap(x, skb);
case IPPROTO_IPV6: case AF_INET6:
return xfrm6_remove_beet_encap(x, skb); return xfrm6_remove_beet_encap(x, skb);
} }
break; break;

View File

@ -310,6 +310,52 @@ static void xfrmi_scrub_packet(struct sk_buff *skb, bool xnet)
skb->mark = 0; skb->mark = 0;
} }
static int xfrmi_input(struct sk_buff *skb, int nexthdr, __be32 spi,
int encap_type, unsigned short family)
{
struct sec_path *sp;
sp = skb_sec_path(skb);
if (sp && (sp->len || sp->olen) &&
!xfrm_policy_check(NULL, XFRM_POLICY_IN, skb, family))
goto discard;
XFRM_SPI_SKB_CB(skb)->family = family;
if (family == AF_INET) {
XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr);
XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL;
} else {
XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct ipv6hdr, daddr);
XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = NULL;
}
return xfrm_input(skb, nexthdr, spi, encap_type);
discard:
kfree_skb(skb);
return 0;
}
static int xfrmi4_rcv(struct sk_buff *skb)
{
return xfrmi_input(skb, ip_hdr(skb)->protocol, 0, 0, AF_INET);
}
static int xfrmi6_rcv(struct sk_buff *skb)
{
return xfrmi_input(skb, skb_network_header(skb)[IP6CB(skb)->nhoff],
0, 0, AF_INET6);
}
static int xfrmi4_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
{
return xfrmi_input(skb, nexthdr, spi, encap_type, AF_INET);
}
static int xfrmi6_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
{
return xfrmi_input(skb, nexthdr, spi, encap_type, AF_INET6);
}
static int xfrmi_rcv_cb(struct sk_buff *skb, int err) static int xfrmi_rcv_cb(struct sk_buff *skb, int err)
{ {
const struct xfrm_mode *inner_mode; const struct xfrm_mode *inner_mode;
@ -945,8 +991,8 @@ static struct pernet_operations xfrmi_net_ops = {
}; };
static struct xfrm6_protocol xfrmi_esp6_protocol __read_mostly = { static struct xfrm6_protocol xfrmi_esp6_protocol __read_mostly = {
.handler = xfrm6_rcv, .handler = xfrmi6_rcv,
.input_handler = xfrm_input, .input_handler = xfrmi6_input,
.cb_handler = xfrmi_rcv_cb, .cb_handler = xfrmi_rcv_cb,
.err_handler = xfrmi6_err, .err_handler = xfrmi6_err,
.priority = 10, .priority = 10,
@ -996,8 +1042,8 @@ static struct xfrm6_tunnel xfrmi_ip6ip_handler __read_mostly = {
#endif #endif
static struct xfrm4_protocol xfrmi_esp4_protocol __read_mostly = { static struct xfrm4_protocol xfrmi_esp4_protocol __read_mostly = {
.handler = xfrm4_rcv, .handler = xfrmi4_rcv,
.input_handler = xfrm_input, .input_handler = xfrmi4_input,
.cb_handler = xfrmi_rcv_cb, .cb_handler = xfrmi_rcv_cb,
.err_handler = xfrmi4_err, .err_handler = xfrmi4_err,
.priority = 10, .priority = 10,

View File

@ -1831,6 +1831,7 @@ again:
__xfrm_policy_unlink(pol, dir); __xfrm_policy_unlink(pol, dir);
spin_unlock_bh(&net->xfrm.xfrm_policy_lock); spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
xfrm_dev_policy_delete(pol);
cnt++; cnt++;
xfrm_audit_policy_delete(pol, 1, task_valid); xfrm_audit_policy_delete(pol, 1, task_valid);
xfrm_policy_kill(pol); xfrm_policy_kill(pol);
@ -1869,6 +1870,7 @@ again:
__xfrm_policy_unlink(pol, dir); __xfrm_policy_unlink(pol, dir);
spin_unlock_bh(&net->xfrm.xfrm_policy_lock); spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
xfrm_dev_policy_delete(pol);
cnt++; cnt++;
xfrm_audit_policy_delete(pol, 1, task_valid); xfrm_audit_policy_delete(pol, 1, task_valid);
xfrm_policy_kill(pol); xfrm_policy_kill(pol);
@ -3349,6 +3351,13 @@ xfrm_policy_ok(const struct xfrm_tmpl *tmpl, const struct sec_path *sp, int star
if (xfrm_state_ok(tmpl, sp->xvec[idx], family, if_id)) if (xfrm_state_ok(tmpl, sp->xvec[idx], family, if_id))
return ++idx; return ++idx;
if (sp->xvec[idx]->props.mode != XFRM_MODE_TRANSPORT) { if (sp->xvec[idx]->props.mode != XFRM_MODE_TRANSPORT) {
if (idx < sp->verified_cnt) {
/* Secpath entry previously verified, consider optional and
* continue searching
*/
continue;
}
if (start == -1) if (start == -1)
start = -2-idx; start = -2-idx;
break; break;
@ -3723,6 +3732,9 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
* Order is _important_. Later we will implement * Order is _important_. Later we will implement
* some barriers, but at the moment barriers * some barriers, but at the moment barriers
* are implied between each two transformations. * are implied between each two transformations.
* Upon success, marks secpath entries as having been
* verified to allow them to be skipped in future policy
* checks (e.g. nested tunnels).
*/ */
for (i = xfrm_nr-1, k = 0; i >= 0; i--) { for (i = xfrm_nr-1, k = 0; i >= 0; i--) {
k = xfrm_policy_ok(tpp[i], sp, k, family, if_id); k = xfrm_policy_ok(tpp[i], sp, k, family, if_id);
@ -3741,6 +3753,8 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
} }
xfrm_pols_put(pols, npols); xfrm_pols_put(pols, npols);
sp->verified_cnt = k;
return 1; return 1;
} }
XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLBLOCK); XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLBLOCK);

View File

@ -0,0 +1,29 @@
// SPDX-License-Identifier: GPL-2.0
#include <test_progs.h>
#include "test_subprogs_extable.skel.h"
void test_subprogs_extable(void)
{
const int read_sz = 456;
struct test_subprogs_extable *skel;
int err;
skel = test_subprogs_extable__open_and_load();
if (!ASSERT_OK_PTR(skel, "skel_open_and_load"))
return;
err = test_subprogs_extable__attach(skel);
if (!ASSERT_OK(err, "skel_attach"))
goto cleanup;
/* trigger tracepoint */
ASSERT_OK(trigger_module_test_read(read_sz), "trigger_read");
ASSERT_NEQ(skel->bss->triggered, 0, "verify at least one program ran");
test_subprogs_extable__detach(skel);
cleanup:
test_subprogs_extable__destroy(skel);
}

View File

@ -0,0 +1,51 @@
// SPDX-License-Identifier: GPL-2.0
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__uint(max_entries, 8);
__type(key, __u32);
__type(value, __u64);
} test_array SEC(".maps");
unsigned int triggered;
static __u64 test_cb(struct bpf_map *map, __u32 *key, __u64 *val, void *data)
{
return 1;
}
SEC("fexit/bpf_testmod_return_ptr")
int BPF_PROG(handle_fexit_ret_subprogs, int arg, struct file *ret)
{
*(volatile long *)ret;
*(volatile int *)&ret->f_mode;
bpf_for_each_map_elem(&test_array, test_cb, NULL, 0);
triggered++;
return 0;
}
SEC("fexit/bpf_testmod_return_ptr")
int BPF_PROG(handle_fexit_ret_subprogs2, int arg, struct file *ret)
{
*(volatile long *)ret;
*(volatile int *)&ret->f_mode;
bpf_for_each_map_elem(&test_array, test_cb, NULL, 0);
triggered++;
return 0;
}
SEC("fexit/bpf_testmod_return_ptr")
int BPF_PROG(handle_fexit_ret_subprogs3, int arg, struct file *ret)
{
*(volatile long *)ret;
*(volatile int *)&ret->f_mode;
bpf_for_each_map_elem(&test_array, test_cb, NULL, 0);
triggered++;
return 0;
}
char _license[] SEC("license") = "GPL";

View File

@ -371,4 +371,83 @@ __naked void and_then_at_fp_8(void)
" ::: __clobber_all); " ::: __clobber_all);
} }
SEC("xdp")
__description("32-bit spill of 64-bit reg should clear ID")
__failure __msg("math between ctx pointer and 4294967295 is not allowed")
__naked void spill_32bit_of_64bit_fail(void)
{
asm volatile (" \
r6 = r1; \
/* Roll one bit to force the verifier to track both branches. */\
call %[bpf_get_prandom_u32]; \
r0 &= 0x8; \
/* Put a large number into r1. */ \
r1 = 0xffffffff; \
r1 <<= 32; \
r1 += r0; \
/* Assign an ID to r1. */ \
r2 = r1; \
/* 32-bit spill r1 to stack - should clear the ID! */\
*(u32*)(r10 - 8) = r1; \
/* 32-bit fill r2 from stack. */ \
r2 = *(u32*)(r10 - 8); \
/* Compare r2 with another register to trigger find_equal_scalars.\
* Having one random bit is important here, otherwise the verifier cuts\
* the corners. If the ID was mistakenly preserved on spill, this would\
* cause the verifier to think that r1 is also equal to zero in one of\
* the branches, and equal to eight on the other branch.\
*/ \
r3 = 0; \
if r2 != r3 goto l0_%=; \
l0_%=: r1 >>= 32; \
/* At this point, if the verifier thinks that r1 is 0, an out-of-bounds\
* read will happen, because it actually contains 0xffffffff.\
*/ \
r6 += r1; \
r0 = *(u32*)(r6 + 0); \
exit; \
" :
: __imm(bpf_get_prandom_u32)
: __clobber_all);
}
SEC("xdp")
__description("16-bit spill of 32-bit reg should clear ID")
__failure __msg("dereference of modified ctx ptr R6 off=65535 disallowed")
__naked void spill_16bit_of_32bit_fail(void)
{
asm volatile (" \
r6 = r1; \
/* Roll one bit to force the verifier to track both branches. */\
call %[bpf_get_prandom_u32]; \
r0 &= 0x8; \
/* Put a large number into r1. */ \
w1 = 0xffff0000; \
r1 += r0; \
/* Assign an ID to r1. */ \
r2 = r1; \
/* 16-bit spill r1 to stack - should clear the ID! */\
*(u16*)(r10 - 8) = r1; \
/* 16-bit fill r2 from stack. */ \
r2 = *(u16*)(r10 - 8); \
/* Compare r2 with another register to trigger find_equal_scalars.\
* Having one random bit is important here, otherwise the verifier cuts\
* the corners. If the ID was mistakenly preserved on spill, this would\
* cause the verifier to think that r1 is also equal to zero in one of\
* the branches, and equal to eight on the other branch.\
*/ \
r3 = 0; \
if r2 != r3 goto l0_%=; \
l0_%=: r1 >>= 16; \
/* At this point, if the verifier thinks that r1 is 0, an out-of-bounds\
* read will happen, because it actually contains 0xffff.\
*/ \
r6 += r1; \
r0 = *(u32*)(r6 + 0); \
exit; \
" :
: __imm(bpf_get_prandom_u32)
: __clobber_all);
}
char _license[] SEC("license") = "GPL"; char _license[] SEC("license") = "GPL";

View File

@ -249,7 +249,7 @@
/** /**
* FIXTURE_SETUP() - Prepares the setup function for the fixture. * FIXTURE_SETUP() - Prepares the setup function for the fixture.
* *_metadata* is included so that EXPECT_* and ASSERT_* work correctly. * *_metadata* is included so that EXPECT_*, ASSERT_* etc. work correctly.
* *
* @fixture_name: fixture name * @fixture_name: fixture name
* *
@ -275,7 +275,7 @@
/** /**
* FIXTURE_TEARDOWN() * FIXTURE_TEARDOWN()
* *_metadata* is included so that EXPECT_* and ASSERT_* work correctly. * *_metadata* is included so that EXPECT_*, ASSERT_* etc. work correctly.
* *
* @fixture_name: fixture name * @fixture_name: fixture name
* *
@ -388,7 +388,7 @@
if (setjmp(_metadata->env) == 0) { \ if (setjmp(_metadata->env) == 0) { \
fixture_name##_setup(_metadata, &self, variant->data); \ fixture_name##_setup(_metadata, &self, variant->data); \
/* Let setup failure terminate early. */ \ /* Let setup failure terminate early. */ \
if (!_metadata->passed) \ if (!_metadata->passed || _metadata->skip) \
return; \ return; \
_metadata->setup_completed = true; \ _metadata->setup_completed = true; \
fixture_name##_##test_name(_metadata, &self, variant->data); \ fixture_name##_##test_name(_metadata, &self, variant->data); \

View File

@ -92,6 +92,13 @@ NSC_CMD="ip netns exec ${NSC}"
which ping6 > /dev/null 2>&1 && ping6=$(which ping6) || ping6=$(which ping) which ping6 > /dev/null 2>&1 && ping6=$(which ping6) || ping6=$(which ping)
# Check if FIPS mode is enabled
if [ -f /proc/sys/crypto/fips_enabled ]; then
fips_enabled=`cat /proc/sys/crypto/fips_enabled`
else
fips_enabled=0
fi
################################################################################ ################################################################################
# utilities # utilities
@ -1216,7 +1223,7 @@ ipv4_tcp_novrf()
run_cmd nettest -d ${NSA_DEV} -r ${a} run_cmd nettest -d ${NSA_DEV} -r ${a}
log_test_addr ${a} $? 1 "No server, device client, local conn" log_test_addr ${a} $? 1 "No server, device client, local conn"
ipv4_tcp_md5_novrf [ "$fips_enabled" = "1" ] || ipv4_tcp_md5_novrf
} }
ipv4_tcp_vrf() ipv4_tcp_vrf()
@ -1270,9 +1277,11 @@ ipv4_tcp_vrf()
log_test_addr ${a} $? 1 "Global server, local connection" log_test_addr ${a} $? 1 "Global server, local connection"
# run MD5 tests # run MD5 tests
setup_vrf_dup if [ "$fips_enabled" = "0" ]; then
ipv4_tcp_md5 setup_vrf_dup
cleanup_vrf_dup ipv4_tcp_md5
cleanup_vrf_dup
fi
# #
# enable VRF global server # enable VRF global server
@ -2772,7 +2781,7 @@ ipv6_tcp_novrf()
log_test_addr ${a} $? 1 "No server, device client, local conn" log_test_addr ${a} $? 1 "No server, device client, local conn"
done done
ipv6_tcp_md5_novrf [ "$fips_enabled" = "1" ] || ipv6_tcp_md5_novrf
} }
ipv6_tcp_vrf() ipv6_tcp_vrf()
@ -2842,9 +2851,11 @@ ipv6_tcp_vrf()
log_test_addr ${a} $? 1 "Global server, local connection" log_test_addr ${a} $? 1 "Global server, local connection"
# run MD5 tests # run MD5 tests
setup_vrf_dup if [ "$fips_enabled" = "0" ]; then
ipv6_tcp_md5 setup_vrf_dup
cleanup_vrf_dup ipv6_tcp_md5
cleanup_vrf_dup
fi
# #
# enable VRF global server # enable VRF global server

View File

@ -93,12 +93,16 @@ cleanup()
test_gretap() test_gretap()
{ {
ip neigh replace 192.0.2.130 lladdr $(mac_get $h3) \
nud permanent dev br2
full_test_span_gre_dir gt4 ingress 8 0 "mirror to gretap" full_test_span_gre_dir gt4 ingress 8 0 "mirror to gretap"
full_test_span_gre_dir gt4 egress 0 8 "mirror to gretap" full_test_span_gre_dir gt4 egress 0 8 "mirror to gretap"
} }
test_ip6gretap() test_ip6gretap()
{ {
ip neigh replace 2001:db8:2::2 lladdr $(mac_get $h3) \
nud permanent dev br2
full_test_span_gre_dir gt6 ingress 8 0 "mirror to ip6gretap" full_test_span_gre_dir gt6 ingress 8 0 "mirror to ip6gretap"
full_test_span_gre_dir gt6 egress 0 8 "mirror to ip6gretap" full_test_span_gre_dir gt6 egress 0 8 "mirror to ip6gretap"
} }

View File

@ -90,12 +90,16 @@ cleanup()
test_gretap() test_gretap()
{ {
ip neigh replace 192.0.2.130 lladdr $(mac_get $h3) \
nud permanent dev br1
full_test_span_gre_dir gt4 ingress 8 0 "mirror to gretap" full_test_span_gre_dir gt4 ingress 8 0 "mirror to gretap"
full_test_span_gre_dir gt4 egress 0 8 "mirror to gretap" full_test_span_gre_dir gt4 egress 0 8 "mirror to gretap"
} }
test_ip6gretap() test_ip6gretap()
{ {
ip neigh replace 2001:db8:2::2 lladdr $(mac_get $h3) \
nud permanent dev br1
full_test_span_gre_dir gt6 ingress 8 0 "mirror to ip6gretap" full_test_span_gre_dir gt6 ingress 8 0 "mirror to ip6gretap"
full_test_span_gre_dir gt6 egress 0 8 "mirror to ip6gretap" full_test_span_gre_dir gt6 egress 0 8 "mirror to ip6gretap"
} }

View File

@ -25,6 +25,8 @@
#define TLS_PAYLOAD_MAX_LEN 16384 #define TLS_PAYLOAD_MAX_LEN 16384
#define SOL_TLS 282 #define SOL_TLS 282
static int fips_enabled;
struct tls_crypto_info_keys { struct tls_crypto_info_keys {
union { union {
struct tls12_crypto_info_aes_gcm_128 aes128; struct tls12_crypto_info_aes_gcm_128 aes128;
@ -235,7 +237,7 @@ FIXTURE_VARIANT(tls)
{ {
uint16_t tls_version; uint16_t tls_version;
uint16_t cipher_type; uint16_t cipher_type;
bool nopad; bool nopad, fips_non_compliant;
}; };
FIXTURE_VARIANT_ADD(tls, 12_aes_gcm) FIXTURE_VARIANT_ADD(tls, 12_aes_gcm)
@ -254,24 +256,28 @@ FIXTURE_VARIANT_ADD(tls, 12_chacha)
{ {
.tls_version = TLS_1_2_VERSION, .tls_version = TLS_1_2_VERSION,
.cipher_type = TLS_CIPHER_CHACHA20_POLY1305, .cipher_type = TLS_CIPHER_CHACHA20_POLY1305,
.fips_non_compliant = true,
}; };
FIXTURE_VARIANT_ADD(tls, 13_chacha) FIXTURE_VARIANT_ADD(tls, 13_chacha)
{ {
.tls_version = TLS_1_3_VERSION, .tls_version = TLS_1_3_VERSION,
.cipher_type = TLS_CIPHER_CHACHA20_POLY1305, .cipher_type = TLS_CIPHER_CHACHA20_POLY1305,
.fips_non_compliant = true,
}; };
FIXTURE_VARIANT_ADD(tls, 13_sm4_gcm) FIXTURE_VARIANT_ADD(tls, 13_sm4_gcm)
{ {
.tls_version = TLS_1_3_VERSION, .tls_version = TLS_1_3_VERSION,
.cipher_type = TLS_CIPHER_SM4_GCM, .cipher_type = TLS_CIPHER_SM4_GCM,
.fips_non_compliant = true,
}; };
FIXTURE_VARIANT_ADD(tls, 13_sm4_ccm) FIXTURE_VARIANT_ADD(tls, 13_sm4_ccm)
{ {
.tls_version = TLS_1_3_VERSION, .tls_version = TLS_1_3_VERSION,
.cipher_type = TLS_CIPHER_SM4_CCM, .cipher_type = TLS_CIPHER_SM4_CCM,
.fips_non_compliant = true,
}; };
FIXTURE_VARIANT_ADD(tls, 12_aes_ccm) FIXTURE_VARIANT_ADD(tls, 12_aes_ccm)
@ -311,6 +317,9 @@ FIXTURE_SETUP(tls)
int one = 1; int one = 1;
int ret; int ret;
if (fips_enabled && variant->fips_non_compliant)
SKIP(return, "Unsupported cipher in FIPS mode");
tls_crypto_info_init(variant->tls_version, variant->cipher_type, tls_crypto_info_init(variant->tls_version, variant->cipher_type,
&tls12); &tls12);
@ -1865,4 +1874,17 @@ TEST(prequeue) {
close(cfd); close(cfd);
} }
static void __attribute__((constructor)) fips_check(void) {
int res;
FILE *f;
f = fopen("/proc/sys/crypto/fips_enabled", "r");
if (f) {
res = fscanf(f, "%d", &fips_enabled);
if (res != 1)
ksft_print_msg("ERROR: Couldn't read /proc/sys/crypto/fips_enabled\n");
fclose(f);
}
}
TEST_HARNESS_MAIN TEST_HARNESS_MAIN

View File

@ -264,60 +264,60 @@ setup_xfrm()
ip -netns host1 xfrm state add src ${HOST1_4} dst ${HOST2_4} \ ip -netns host1 xfrm state add src ${HOST1_4} dst ${HOST2_4} \
proto esp spi ${SPI_1} reqid 0 mode tunnel \ proto esp spi ${SPI_1} reqid 0 mode tunnel \
replay-window 4 replay-oseq 0x4 \ replay-window 4 replay-oseq 0x4 \
auth-trunc 'hmac(md5)' ${AUTH_1} 96 \ auth-trunc 'hmac(sha1)' ${AUTH_1} 96 \
enc 'cbc(des3_ede)' ${ENC_1} \ enc 'cbc(aes)' ${ENC_1} \
sel src ${h1_4} dst ${h2_4} ${devarg} sel src ${h1_4} dst ${h2_4} ${devarg}
ip -netns host2 xfrm state add src ${HOST1_4} dst ${HOST2_4} \ ip -netns host2 xfrm state add src ${HOST1_4} dst ${HOST2_4} \
proto esp spi ${SPI_1} reqid 0 mode tunnel \ proto esp spi ${SPI_1} reqid 0 mode tunnel \
replay-window 4 replay-oseq 0x4 \ replay-window 4 replay-oseq 0x4 \
auth-trunc 'hmac(md5)' ${AUTH_1} 96 \ auth-trunc 'hmac(sha1)' ${AUTH_1} 96 \
enc 'cbc(des3_ede)' ${ENC_1} \ enc 'cbc(aes)' ${ENC_1} \
sel src ${h1_4} dst ${h2_4} sel src ${h1_4} dst ${h2_4}
ip -netns host1 xfrm state add src ${HOST2_4} dst ${HOST1_4} \ ip -netns host1 xfrm state add src ${HOST2_4} dst ${HOST1_4} \
proto esp spi ${SPI_2} reqid 0 mode tunnel \ proto esp spi ${SPI_2} reqid 0 mode tunnel \
replay-window 4 replay-oseq 0x4 \ replay-window 4 replay-oseq 0x4 \
auth-trunc 'hmac(md5)' ${AUTH_2} 96 \ auth-trunc 'hmac(sha1)' ${AUTH_2} 96 \
enc 'cbc(des3_ede)' ${ENC_2} \ enc 'cbc(aes)' ${ENC_2} \
sel src ${h2_4} dst ${h1_4} ${devarg} sel src ${h2_4} dst ${h1_4} ${devarg}
ip -netns host2 xfrm state add src ${HOST2_4} dst ${HOST1_4} \ ip -netns host2 xfrm state add src ${HOST2_4} dst ${HOST1_4} \
proto esp spi ${SPI_2} reqid 0 mode tunnel \ proto esp spi ${SPI_2} reqid 0 mode tunnel \
replay-window 4 replay-oseq 0x4 \ replay-window 4 replay-oseq 0x4 \
auth-trunc 'hmac(md5)' ${AUTH_2} 96 \ auth-trunc 'hmac(sha1)' ${AUTH_2} 96 \
enc 'cbc(des3_ede)' ${ENC_2} \ enc 'cbc(aes)' ${ENC_2} \
sel src ${h2_4} dst ${h1_4} sel src ${h2_4} dst ${h1_4}
ip -6 -netns host1 xfrm state add src ${HOST1_6} dst ${HOST2_6} \ ip -6 -netns host1 xfrm state add src ${HOST1_6} dst ${HOST2_6} \
proto esp spi ${SPI_1} reqid 0 mode tunnel \ proto esp spi ${SPI_1} reqid 0 mode tunnel \
replay-window 4 replay-oseq 0x4 \ replay-window 4 replay-oseq 0x4 \
auth-trunc 'hmac(md5)' ${AUTH_1} 96 \ auth-trunc 'hmac(sha1)' ${AUTH_1} 96 \
enc 'cbc(des3_ede)' ${ENC_1} \ enc 'cbc(aes)' ${ENC_1} \
sel src ${h1_6} dst ${h2_6} ${devarg} sel src ${h1_6} dst ${h2_6} ${devarg}
ip -6 -netns host2 xfrm state add src ${HOST1_6} dst ${HOST2_6} \ ip -6 -netns host2 xfrm state add src ${HOST1_6} dst ${HOST2_6} \
proto esp spi ${SPI_1} reqid 0 mode tunnel \ proto esp spi ${SPI_1} reqid 0 mode tunnel \
replay-window 4 replay-oseq 0x4 \ replay-window 4 replay-oseq 0x4 \
auth-trunc 'hmac(md5)' ${AUTH_1} 96 \ auth-trunc 'hmac(sha1)' ${AUTH_1} 96 \
enc 'cbc(des3_ede)' ${ENC_1} \ enc 'cbc(aes)' ${ENC_1} \
sel src ${h1_6} dst ${h2_6} sel src ${h1_6} dst ${h2_6}
ip -6 -netns host1 xfrm state add src ${HOST2_6} dst ${HOST1_6} \ ip -6 -netns host1 xfrm state add src ${HOST2_6} dst ${HOST1_6} \
proto esp spi ${SPI_2} reqid 0 mode tunnel \ proto esp spi ${SPI_2} reqid 0 mode tunnel \
replay-window 4 replay-oseq 0x4 \ replay-window 4 replay-oseq 0x4 \
auth-trunc 'hmac(md5)' ${AUTH_2} 96 \ auth-trunc 'hmac(sha1)' ${AUTH_2} 96 \
enc 'cbc(des3_ede)' ${ENC_2} \ enc 'cbc(aes)' ${ENC_2} \
sel src ${h2_6} dst ${h1_6} ${devarg} sel src ${h2_6} dst ${h1_6} ${devarg}
ip -6 -netns host2 xfrm state add src ${HOST2_6} dst ${HOST1_6} \ ip -6 -netns host2 xfrm state add src ${HOST2_6} dst ${HOST1_6} \
proto esp spi ${SPI_2} reqid 0 mode tunnel \ proto esp spi ${SPI_2} reqid 0 mode tunnel \
replay-window 4 replay-oseq 0x4 \ replay-window 4 replay-oseq 0x4 \
auth-trunc 'hmac(md5)' ${AUTH_2} 96 \ auth-trunc 'hmac(sha1)' ${AUTH_2} 96 \
enc 'cbc(des3_ede)' ${ENC_2} \ enc 'cbc(aes)' ${ENC_2} \
sel src ${h2_6} dst ${h1_6} sel src ${h2_6} dst ${h1_6}
} }