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

Pull networking fixes from Paolo Abeni:
 "Including fixes from Bluetooth and Wireless. No known outstanding
  regressions.

  Current release - regressions:

   - eth:
      - bonding: fix mii_status when slave is down
      - mlx5e: fix missing error assignment in mlx5e_xfrm_add_state()

  Previous releases - regressions:

   - sched: limit try_bulk_dequeue_skb() batches

   - ipv4: route: prevent rt_bind_exception() from rebinding stale fnhe

   - af_unix: initialise scc_index in unix_add_edge()

   - netpoll: fix incorrect refcount handling causing incorrect cleanup

   - bluetooth: don't hold spin lock over sleeping functions

   - hsr: Fix supervision frame sending on HSRv0

   - sctp: prevent possible shift out-of-bounds

   - tipc: fix use-after-free in tipc_mon_reinit_self().

   - dsa: tag_brcm: do not mark link local traffic as offloaded

   - eth: virtio-net: fix incorrect flags recording in big mode

  Previous releases - always broken:

   - sched: initialize struct tc_ife to fix kernel-infoleak

   - wifi:
      - mac80211: reject address change while connecting
      - iwlwifi: avoid toggling links due to wrong element use

   - bluetooth: cancel mesh send timer when hdev removed

   - strparser: fix signed/unsigned mismatch bug

   - handshake: fix memory leak in tls_handshake_accept()

  Misc:

   - selftests: mptcp: fix some flaky tests"

* tag 'net-6.18-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net: (60 commits)
  hsr: Follow standard for HSRv0 supervision frames
  hsr: Fix supervision frame sending on HSRv0
  virtio-net: fix incorrect flags recording in big mode
  ipv4: route: Prevent rt_bind_exception() from rebinding stale fnhe
  wifi: iwlwifi: mld: always take beacon ies in link grading
  wifi: iwlwifi: mvm: fix beacon template/fixed rate
  wifi: iwlwifi: fix aux ROC time event iterator usage
  net_sched: limit try_bulk_dequeue_skb() batches
  selftests: mptcp: join: properly kill background tasks
  selftests: mptcp: connect: trunc: read all recv data
  selftests: mptcp: join: userspace: longer transfer
  selftests: mptcp: join: endpoints: longer transfer
  selftests: mptcp: join: rm: set backup flag
  selftests: mptcp: connect: fix fallback note due to OoO
  ethtool: fix incorrect kernel-doc style comment in ethtool.h
  mlx5: Fix default values in create CQ
  Bluetooth: btrtl: Avoid loading the config file on security chips
  net/mlx5e: Fix potentially misleading debug message
  net/mlx5e: Fix wraparound in rate limiting for values above 255 Gbps
  net/mlx5e: Fix maxrate wraparound in threshold between units
  ...
This commit is contained in:
Linus Torvalds
2025-11-13 11:20:25 -08:00
65 changed files with 1206 additions and 316 deletions

View File

@@ -13,10 +13,10 @@ Simple CLI
Kernel comes with a simple CLI tool which should be useful when Kernel comes with a simple CLI tool which should be useful when
developing Netlink related code. The tool is implemented in Python developing Netlink related code. The tool is implemented in Python
and can use a YAML specification to issue Netlink requests and can use a YAML specification to issue Netlink requests
to the kernel. Only Generic Netlink is supported. to the kernel.
The tool is located at ``tools/net/ynl/pyynl/cli.py``. It accepts The tool is located at ``tools/net/ynl/pyynl/cli.py``. It accepts
a handul of arguments, the most important ones are: a handful of arguments, the most important ones are:
- ``--spec`` - point to the spec file - ``--spec`` - point to the spec file
- ``--do $name`` / ``--dump $name`` - issue request ``$name`` - ``--do $name`` / ``--dump $name`` - issue request ``$name``

View File

@@ -50,7 +50,7 @@
#define RTL_CHIP_SUBVER (&(struct rtl_vendor_cmd) {{0x10, 0x38, 0x04, 0x28, 0x80}}) #define RTL_CHIP_SUBVER (&(struct rtl_vendor_cmd) {{0x10, 0x38, 0x04, 0x28, 0x80}})
#define RTL_CHIP_REV (&(struct rtl_vendor_cmd) {{0x10, 0x3A, 0x04, 0x28, 0x80}}) #define RTL_CHIP_REV (&(struct rtl_vendor_cmd) {{0x10, 0x3A, 0x04, 0x28, 0x80}})
#define RTL_SEC_PROJ (&(struct rtl_vendor_cmd) {{0x10, 0xA4, 0x0D, 0x00, 0xb0}}) #define RTL_SEC_PROJ (&(struct rtl_vendor_cmd) {{0x10, 0xA4, 0xAD, 0x00, 0xb0}})
#define RTL_PATCH_SNIPPETS 0x01 #define RTL_PATCH_SNIPPETS 0x01
#define RTL_PATCH_DUMMY_HEADER 0x02 #define RTL_PATCH_DUMMY_HEADER 0x02
@@ -534,7 +534,6 @@ static int rtlbt_parse_firmware_v2(struct hci_dev *hdev,
{ {
struct rtl_epatch_header_v2 *hdr; struct rtl_epatch_header_v2 *hdr;
int rc; int rc;
u8 reg_val[2];
u8 key_id; u8 key_id;
u32 num_sections; u32 num_sections;
struct rtl_section *section; struct rtl_section *section;
@@ -549,14 +548,7 @@ static int rtlbt_parse_firmware_v2(struct hci_dev *hdev,
.len = btrtl_dev->fw_len - 7, /* Cut the tail */ .len = btrtl_dev->fw_len - 7, /* Cut the tail */
}; };
rc = btrtl_vendor_read_reg16(hdev, RTL_SEC_PROJ, reg_val); key_id = btrtl_dev->key_id;
if (rc < 0)
return -EIO;
key_id = reg_val[0];
rtl_dev_dbg(hdev, "%s: key id %u", __func__, key_id);
btrtl_dev->key_id = key_id;
hdr = rtl_iov_pull_data(&iov, sizeof(*hdr)); hdr = rtl_iov_pull_data(&iov, sizeof(*hdr));
if (!hdr) if (!hdr)
@@ -1070,6 +1062,8 @@ struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev,
u16 hci_rev, lmp_subver; u16 hci_rev, lmp_subver;
u8 hci_ver, lmp_ver, chip_type = 0; u8 hci_ver, lmp_ver, chip_type = 0;
int ret; int ret;
int rc;
u8 key_id;
u8 reg_val[2]; u8 reg_val[2];
btrtl_dev = kzalloc(sizeof(*btrtl_dev), GFP_KERNEL); btrtl_dev = kzalloc(sizeof(*btrtl_dev), GFP_KERNEL);
@@ -1180,6 +1174,14 @@ next:
goto err_free; goto err_free;
} }
rc = btrtl_vendor_read_reg16(hdev, RTL_SEC_PROJ, reg_val);
if (rc < 0)
goto err_free;
key_id = reg_val[0];
btrtl_dev->key_id = key_id;
rtl_dev_info(hdev, "%s: key id %u", __func__, key_id);
btrtl_dev->fw_len = -EIO; btrtl_dev->fw_len = -EIO;
if (lmp_subver == RTL_ROM_LMP_8852A && hci_rev == 0x000c) { if (lmp_subver == RTL_ROM_LMP_8852A && hci_rev == 0x000c) {
snprintf(fw_name, sizeof(fw_name), "%s_v2.bin", snprintf(fw_name, sizeof(fw_name), "%s_v2.bin",
@@ -1202,7 +1204,7 @@ next:
goto err_free; goto err_free;
} }
if (btrtl_dev->ic_info->cfg_name) { if (btrtl_dev->ic_info->cfg_name && !btrtl_dev->key_id) {
if (postfix) { if (postfix) {
snprintf(cfg_name, sizeof(cfg_name), "%s-%s.bin", snprintf(cfg_name, sizeof(cfg_name), "%s-%s.bin",
btrtl_dev->ic_info->cfg_name, postfix); btrtl_dev->ic_info->cfg_name, postfix);

View File

@@ -4361,6 +4361,11 @@ static void btusb_disconnect(struct usb_interface *intf)
hci_unregister_dev(hdev); hci_unregister_dev(hdev);
if (data->oob_wake_irq)
device_init_wakeup(&data->udev->dev, false);
if (data->reset_gpio)
gpiod_put(data->reset_gpio);
if (intf == data->intf) { if (intf == data->intf) {
if (data->isoc) if (data->isoc)
usb_driver_release_interface(&btusb_driver, data->isoc); usb_driver_release_interface(&btusb_driver, data->isoc);
@@ -4371,17 +4376,11 @@ static void btusb_disconnect(struct usb_interface *intf)
usb_driver_release_interface(&btusb_driver, data->diag); usb_driver_release_interface(&btusb_driver, data->diag);
usb_driver_release_interface(&btusb_driver, data->intf); usb_driver_release_interface(&btusb_driver, data->intf);
} else if (intf == data->diag) { } else if (intf == data->diag) {
usb_driver_release_interface(&btusb_driver, data->intf);
if (data->isoc) if (data->isoc)
usb_driver_release_interface(&btusb_driver, data->isoc); usb_driver_release_interface(&btusb_driver, data->isoc);
usb_driver_release_interface(&btusb_driver, data->intf);
} }
if (data->oob_wake_irq)
device_init_wakeup(&data->udev->dev, false);
if (data->reset_gpio)
gpiod_put(data->reset_gpio);
hci_free_dev(hdev); hci_free_dev(hdev);
} }

View File

@@ -1020,15 +1020,18 @@ int mlx5_ib_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
if (cq->create_flags & IB_UVERBS_CQ_FLAGS_IGNORE_OVERRUN) if (cq->create_flags & IB_UVERBS_CQ_FLAGS_IGNORE_OVERRUN)
MLX5_SET(cqc, cqc, oi, 1); MLX5_SET(cqc, cqc, oi, 1);
if (udata) {
cq->mcq.comp = mlx5_add_cq_to_tasklet;
cq->mcq.tasklet_ctx.comp = mlx5_ib_cq_comp;
} else {
cq->mcq.comp = mlx5_ib_cq_comp;
}
err = mlx5_core_create_cq(dev->mdev, &cq->mcq, cqb, inlen, out, sizeof(out)); err = mlx5_core_create_cq(dev->mdev, &cq->mcq, cqb, inlen, out, sizeof(out));
if (err) if (err)
goto err_cqb; goto err_cqb;
mlx5_ib_dbg(dev, "cqn 0x%x\n", cq->mcq.cqn); mlx5_ib_dbg(dev, "cqn 0x%x\n", cq->mcq.cqn);
if (udata)
cq->mcq.tasklet_ctx.comp = mlx5_ib_cq_comp;
else
cq->mcq.comp = mlx5_ib_cq_comp;
cq->mcq.event = mlx5_ib_cq_event; cq->mcq.event = mlx5_ib_cq_event;
INIT_LIST_HEAD(&cq->wc_list); INIT_LIST_HEAD(&cq->wc_list);

View File

@@ -2120,7 +2120,7 @@ skip_mac_set:
/* check for initial state */ /* check for initial state */
new_slave->link = BOND_LINK_NOCHANGE; new_slave->link = BOND_LINK_NOCHANGE;
if (bond->params.miimon) { if (bond->params.miimon) {
if (netif_carrier_ok(slave_dev)) { if (netif_running(slave_dev) && netif_carrier_ok(slave_dev)) {
if (bond->params.updelay) { if (bond->params.updelay) {
bond_set_slave_link_state(new_slave, bond_set_slave_link_state(new_slave,
BOND_LINK_BACK, BOND_LINK_BACK,
@@ -2665,7 +2665,8 @@ static int bond_miimon_inspect(struct bonding *bond)
bond_for_each_slave_rcu(bond, slave, iter) { bond_for_each_slave_rcu(bond, slave, iter) {
bond_propose_link_state(slave, BOND_LINK_NOCHANGE); bond_propose_link_state(slave, BOND_LINK_NOCHANGE);
link_state = netif_carrier_ok(slave->dev); link_state = netif_running(slave->dev) &&
netif_carrier_ok(slave->dev);
switch (slave->link) { switch (slave->link) {
case BOND_LINK_UP: case BOND_LINK_UP:

View File

@@ -1835,6 +1835,8 @@ fec_enet_rx_queue(struct net_device *ndev, u16 queue_id, int budget)
ndev->stats.rx_packets++; ndev->stats.rx_packets++;
pkt_len = fec16_to_cpu(bdp->cbd_datlen); pkt_len = fec16_to_cpu(bdp->cbd_datlen);
ndev->stats.rx_bytes += pkt_len; ndev->stats.rx_bytes += pkt_len;
if (fep->quirks & FEC_QUIRK_HAS_RACC)
ndev->stats.rx_bytes -= 2;
index = fec_enet_get_bd_index(bdp, &rxq->bd); index = fec_enet_get_bd_index(bdp, &rxq->bd);
page = rxq->rx_skb_info[index].page; page = rxq->rx_skb_info[index].page;

View File

@@ -66,8 +66,8 @@ void mlx5_cq_tasklet_cb(struct tasklet_struct *t)
tasklet_schedule(&ctx->task); tasklet_schedule(&ctx->task);
} }
static void mlx5_add_cq_to_tasklet(struct mlx5_core_cq *cq, void mlx5_add_cq_to_tasklet(struct mlx5_core_cq *cq,
struct mlx5_eqe *eqe) struct mlx5_eqe *eqe)
{ {
unsigned long flags; unsigned long flags;
struct mlx5_eq_tasklet *tasklet_ctx = cq->tasklet_ctx.priv; struct mlx5_eq_tasklet *tasklet_ctx = cq->tasklet_ctx.priv;
@@ -95,7 +95,15 @@ static void mlx5_add_cq_to_tasklet(struct mlx5_core_cq *cq,
if (schedule_tasklet) if (schedule_tasklet)
tasklet_schedule(&tasklet_ctx->task); tasklet_schedule(&tasklet_ctx->task);
} }
EXPORT_SYMBOL(mlx5_add_cq_to_tasklet);
static void mlx5_core_cq_dummy_cb(struct mlx5_core_cq *cq, struct mlx5_eqe *eqe)
{
mlx5_core_err(cq->eq->core.dev,
"CQ default completion callback, CQ #%u\n", cq->cqn);
}
#define MLX5_CQ_INIT_CMD_SN cpu_to_be32(2 << 28)
/* Callers must verify outbox status in case of err */ /* Callers must verify outbox status in case of err */
int mlx5_create_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq, int mlx5_create_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
u32 *in, int inlen, u32 *out, int outlen) u32 *in, int inlen, u32 *out, int outlen)
@@ -121,10 +129,19 @@ int mlx5_create_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
cq->arm_sn = 0; cq->arm_sn = 0;
cq->eq = eq; cq->eq = eq;
cq->uid = MLX5_GET(create_cq_in, in, uid); cq->uid = MLX5_GET(create_cq_in, in, uid);
/* Kernel CQs must set the arm_db address prior to calling
* this function, allowing for the proper value to be
* initialized. User CQs are responsible for their own
* initialization since they do not use the arm_db field.
*/
if (cq->arm_db)
*cq->arm_db = MLX5_CQ_INIT_CMD_SN;
refcount_set(&cq->refcount, 1); refcount_set(&cq->refcount, 1);
init_completion(&cq->free); init_completion(&cq->free);
if (!cq->comp) if (!cq->comp)
cq->comp = mlx5_add_cq_to_tasklet; cq->comp = mlx5_core_cq_dummy_cb;
/* assuming CQ will be deleted before the EQ */ /* assuming CQ will be deleted before the EQ */
cq->tasklet_ctx.priv = &eq->tasklet_ctx; cq->tasklet_ctx.priv = &eq->tasklet_ctx;
INIT_LIST_HEAD(&cq->tasklet_ctx.list); INIT_LIST_HEAD(&cq->tasklet_ctx.list);

View File

@@ -541,7 +541,7 @@ static int mlx5_devlink_num_doorbells_validate(struct devlink *devlink, u32 id,
max_num_channels = mlx5e_get_max_num_channels(mdev); max_num_channels = mlx5e_get_max_num_channels(mdev);
if (val32 > max_num_channels) { if (val32 > max_num_channels) {
NL_SET_ERR_MSG_FMT_MOD(extack, NL_SET_ERR_MSG_FMT_MOD(extack,
"Requested num_doorbells (%u) exceeds maximum number of channels (%u)", "Requested num_doorbells (%u) exceeds max number of channels (%u)",
val32, max_num_channels); val32, max_num_channels);
return -EINVAL; return -EINVAL;
} }

View File

@@ -804,7 +804,8 @@ static int mlx5e_xfrm_add_state(struct net_device *dev,
goto err_xfrm; goto err_xfrm;
} }
if (mlx5_eswitch_block_mode(priv->mdev)) err = mlx5_eswitch_block_mode(priv->mdev);
if (err)
goto unblock_ipsec; goto unblock_ipsec;
if (x->props.mode == XFRM_MODE_TUNNEL && if (x->props.mode == XFRM_MODE_TUNNEL &&

View File

@@ -595,32 +595,55 @@ static int mlx5e_dcbnl_ieee_setmaxrate(struct net_device *netdev,
struct mlx5_core_dev *mdev = priv->mdev; struct mlx5_core_dev *mdev = priv->mdev;
u8 max_bw_value[IEEE_8021QAZ_MAX_TCS]; u8 max_bw_value[IEEE_8021QAZ_MAX_TCS];
u8 max_bw_unit[IEEE_8021QAZ_MAX_TCS]; u8 max_bw_unit[IEEE_8021QAZ_MAX_TCS];
__u64 upper_limit_mbps = roundup(255 * MLX5E_100MB, MLX5E_1GB); __u64 upper_limit_mbps;
__u64 upper_limit_gbps;
int i; int i;
struct {
int scale;
const char *units_str;
} units[] = {
[MLX5_100_MBPS_UNIT] = {
.scale = 100,
.units_str = "Mbps",
},
[MLX5_GBPS_UNIT] = {
.scale = 1,
.units_str = "Gbps",
},
};
memset(max_bw_value, 0, sizeof(max_bw_value)); memset(max_bw_value, 0, sizeof(max_bw_value));
memset(max_bw_unit, 0, sizeof(max_bw_unit)); memset(max_bw_unit, 0, sizeof(max_bw_unit));
upper_limit_mbps = 255 * MLX5E_100MB;
upper_limit_gbps = 255 * MLX5E_1GB;
for (i = 0; i <= mlx5_max_tc(mdev); i++) { for (i = 0; i <= mlx5_max_tc(mdev); i++) {
if (!maxrate->tc_maxrate[i]) { if (!maxrate->tc_maxrate[i]) {
max_bw_unit[i] = MLX5_BW_NO_LIMIT; max_bw_unit[i] = MLX5_BW_NO_LIMIT;
continue; continue;
} }
if (maxrate->tc_maxrate[i] < upper_limit_mbps) { if (maxrate->tc_maxrate[i] <= upper_limit_mbps) {
max_bw_value[i] = div_u64(maxrate->tc_maxrate[i], max_bw_value[i] = div_u64(maxrate->tc_maxrate[i],
MLX5E_100MB); MLX5E_100MB);
max_bw_value[i] = max_bw_value[i] ? max_bw_value[i] : 1; max_bw_value[i] = max_bw_value[i] ? max_bw_value[i] : 1;
max_bw_unit[i] = MLX5_100_MBPS_UNIT; max_bw_unit[i] = MLX5_100_MBPS_UNIT;
} else { } else if (max_bw_value[i] <= upper_limit_gbps) {
max_bw_value[i] = div_u64(maxrate->tc_maxrate[i], max_bw_value[i] = div_u64(maxrate->tc_maxrate[i],
MLX5E_1GB); MLX5E_1GB);
max_bw_unit[i] = MLX5_GBPS_UNIT; max_bw_unit[i] = MLX5_GBPS_UNIT;
} else {
netdev_err(netdev,
"tc_%d maxrate %llu Kbps exceeds limit %llu\n",
i, maxrate->tc_maxrate[i],
upper_limit_gbps);
return -EINVAL;
} }
} }
for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
netdev_dbg(netdev, "%s: tc_%d <=> max_bw %d Gbps\n", netdev_dbg(netdev, "%s: tc_%d <=> max_bw %u %s\n", __func__, i,
__func__, i, max_bw_value[i]); max_bw_value[i] * units[max_bw_unit[i]].scale,
units[max_bw_unit[i]].units_str);
} }
return mlx5_modify_port_ets_rate_limit(mdev, max_bw_value, max_bw_unit); return mlx5_modify_port_ets_rate_limit(mdev, max_bw_value, max_bw_unit);

View File

@@ -2219,7 +2219,6 @@ static int mlx5e_alloc_cq_common(struct mlx5_core_dev *mdev,
mcq->set_ci_db = cq->wq_ctrl.db.db; mcq->set_ci_db = cq->wq_ctrl.db.db;
mcq->arm_db = cq->wq_ctrl.db.db + 1; mcq->arm_db = cq->wq_ctrl.db.db + 1;
*mcq->set_ci_db = 0; *mcq->set_ci_db = 0;
*mcq->arm_db = 0;
mcq->vector = param->eq_ix; mcq->vector = param->eq_ix;
mcq->comp = mlx5e_completion_event; mcq->comp = mlx5e_completion_event;
mcq->event = mlx5e_cq_error_event; mcq->event = mlx5e_cq_error_event;

View File

@@ -421,6 +421,13 @@ static int mlx5_fpga_conn_create_cq(struct mlx5_fpga_conn *conn, int cq_size)
__be64 *pas; __be64 *pas;
u32 i; u32 i;
conn->cq.mcq.cqe_sz = 64;
conn->cq.mcq.set_ci_db = conn->cq.wq_ctrl.db.db;
conn->cq.mcq.arm_db = conn->cq.wq_ctrl.db.db + 1;
*conn->cq.mcq.set_ci_db = 0;
conn->cq.mcq.vector = 0;
conn->cq.mcq.comp = mlx5_fpga_conn_cq_complete;
cq_size = roundup_pow_of_two(cq_size); cq_size = roundup_pow_of_two(cq_size);
MLX5_SET(cqc, temp_cqc, log_cq_size, ilog2(cq_size)); MLX5_SET(cqc, temp_cqc, log_cq_size, ilog2(cq_size));
@@ -468,15 +475,7 @@ static int mlx5_fpga_conn_create_cq(struct mlx5_fpga_conn *conn, int cq_size)
if (err) if (err)
goto err_cqwq; goto err_cqwq;
conn->cq.mcq.cqe_sz = 64;
conn->cq.mcq.set_ci_db = conn->cq.wq_ctrl.db.db;
conn->cq.mcq.arm_db = conn->cq.wq_ctrl.db.db + 1;
*conn->cq.mcq.set_ci_db = 0;
*conn->cq.mcq.arm_db = 0;
conn->cq.mcq.vector = 0;
conn->cq.mcq.comp = mlx5_fpga_conn_cq_complete;
tasklet_setup(&conn->cq.tasklet, mlx5_fpga_conn_cq_tasklet); tasklet_setup(&conn->cq.tasklet, mlx5_fpga_conn_cq_tasklet);
mlx5_fpga_dbg(fdev, "Created CQ #0x%x\n", conn->cq.mcq.cqn); mlx5_fpga_dbg(fdev, "Created CQ #0x%x\n", conn->cq.mcq.cqn);
goto out; goto out;

View File

@@ -873,12 +873,6 @@ err_free_sqc:
return err; return err;
} }
static void hws_cq_complete(struct mlx5_core_cq *mcq,
struct mlx5_eqe *eqe)
{
pr_err("CQ completion CQ: #%u\n", mcq->cqn);
}
static int hws_send_ring_alloc_cq(struct mlx5_core_dev *mdev, static int hws_send_ring_alloc_cq(struct mlx5_core_dev *mdev,
int numa_node, int numa_node,
struct mlx5hws_send_engine *queue, struct mlx5hws_send_engine *queue,
@@ -901,7 +895,6 @@ static int hws_send_ring_alloc_cq(struct mlx5_core_dev *mdev,
mcq->cqe_sz = 64; mcq->cqe_sz = 64;
mcq->set_ci_db = cq->wq_ctrl.db.db; mcq->set_ci_db = cq->wq_ctrl.db.db;
mcq->arm_db = cq->wq_ctrl.db.db + 1; mcq->arm_db = cq->wq_ctrl.db.db + 1;
mcq->comp = hws_cq_complete;
for (i = 0; i < mlx5_cqwq_get_size(&cq->wq); i++) { for (i = 0; i < mlx5_cqwq_get_size(&cq->wq); i++) {
cqe = mlx5_cqwq_get_wqe(&cq->wq, i); cqe = mlx5_cqwq_get_wqe(&cq->wq, i);

View File

@@ -1049,12 +1049,6 @@ static int dr_prepare_qp_to_rts(struct mlx5dr_domain *dmn)
return 0; return 0;
} }
static void dr_cq_complete(struct mlx5_core_cq *mcq,
struct mlx5_eqe *eqe)
{
pr_err("CQ completion CQ: #%u\n", mcq->cqn);
}
static struct mlx5dr_cq *dr_create_cq(struct mlx5_core_dev *mdev, static struct mlx5dr_cq *dr_create_cq(struct mlx5_core_dev *mdev,
struct mlx5_uars_page *uar, struct mlx5_uars_page *uar,
size_t ncqe) size_t ncqe)
@@ -1089,6 +1083,13 @@ static struct mlx5dr_cq *dr_create_cq(struct mlx5_core_dev *mdev,
cqe->op_own = MLX5_CQE_INVALID << 4 | MLX5_CQE_OWNER_MASK; cqe->op_own = MLX5_CQE_INVALID << 4 | MLX5_CQE_OWNER_MASK;
} }
cq->mcq.cqe_sz = 64;
cq->mcq.set_ci_db = cq->wq_ctrl.db.db;
cq->mcq.arm_db = cq->wq_ctrl.db.db + 1;
*cq->mcq.set_ci_db = 0;
cq->mcq.vector = 0;
cq->mdev = mdev;
inlen = MLX5_ST_SZ_BYTES(create_cq_in) + inlen = MLX5_ST_SZ_BYTES(create_cq_in) +
sizeof(u64) * cq->wq_ctrl.buf.npages; sizeof(u64) * cq->wq_ctrl.buf.npages;
in = kvzalloc(inlen, GFP_KERNEL); in = kvzalloc(inlen, GFP_KERNEL);
@@ -1112,27 +1113,12 @@ static struct mlx5dr_cq *dr_create_cq(struct mlx5_core_dev *mdev,
pas = (__be64 *)MLX5_ADDR_OF(create_cq_in, in, pas); pas = (__be64 *)MLX5_ADDR_OF(create_cq_in, in, pas);
mlx5_fill_page_frag_array(&cq->wq_ctrl.buf, pas); mlx5_fill_page_frag_array(&cq->wq_ctrl.buf, pas);
cq->mcq.comp = dr_cq_complete;
err = mlx5_core_create_cq(mdev, &cq->mcq, in, inlen, out, sizeof(out)); err = mlx5_core_create_cq(mdev, &cq->mcq, in, inlen, out, sizeof(out));
kvfree(in); kvfree(in);
if (err) if (err)
goto err_cqwq; goto err_cqwq;
cq->mcq.cqe_sz = 64;
cq->mcq.set_ci_db = cq->wq_ctrl.db.db;
cq->mcq.arm_db = cq->wq_ctrl.db.db + 1;
*cq->mcq.set_ci_db = 0;
/* set no-zero value, in order to avoid the HW to run db-recovery on
* CQ that used in polling mode.
*/
*cq->mcq.arm_db = cpu_to_be32(2 << 28);
cq->mcq.vector = 0;
cq->mdev = mdev;
return cq; return cq;
err_cqwq: err_cqwq:

View File

@@ -276,9 +276,31 @@ static int am65_cpsw_iet_set_verify_timeout_count(struct am65_cpsw_port *port)
/* The number of wireside clocks contained in the verify /* The number of wireside clocks contained in the verify
* timeout counter. The default is 0x1312d0 * timeout counter. The default is 0x1312d0
* (10ms at 125Mhz in 1G mode). * (10ms at 125Mhz in 1G mode).
* The frequency of the clock depends on the link speed
* and the PHY interface.
*/ */
val = 125 * HZ_PER_MHZ; /* assuming 125MHz wireside clock */ switch (port->slave.phy_if) {
case PHY_INTERFACE_MODE_RGMII:
case PHY_INTERFACE_MODE_RGMII_ID:
case PHY_INTERFACE_MODE_RGMII_RXID:
case PHY_INTERFACE_MODE_RGMII_TXID:
if (port->qos.link_speed == SPEED_1000)
val = 125 * HZ_PER_MHZ; /* 125 MHz at 1000Mbps*/
else if (port->qos.link_speed == SPEED_100)
val = 25 * HZ_PER_MHZ; /* 25 MHz at 100Mbps*/
else
val = (25 * HZ_PER_MHZ) / 10; /* 2.5 MHz at 10Mbps*/
break;
case PHY_INTERFACE_MODE_QSGMII:
case PHY_INTERFACE_MODE_SGMII:
val = 125 * HZ_PER_MHZ; /* 125 MHz */
break;
default:
netdev_err(port->ndev, "selected mode does not supported IET\n");
return -EOPNOTSUPP;
}
val /= MILLIHZ_PER_HZ; /* count per ms timeout */ val /= MILLIHZ_PER_HZ; /* count per ms timeout */
val *= verify_time_ms; /* count for timeout ms */ val *= verify_time_ms; /* count for timeout ms */
@@ -295,20 +317,21 @@ static int am65_cpsw_iet_verify_wait(struct am65_cpsw_port *port)
u32 ctrl, status; u32 ctrl, status;
int try; int try;
try = 20; try = 3;
/* Reset the verify state machine by writing 1
* to LINKFAIL
*/
ctrl = readl(port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
ctrl |= AM65_CPSW_PN_IET_MAC_LINKFAIL;
writel(ctrl, port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
/* Clear MAC_LINKFAIL bit to start Verify. */
ctrl = readl(port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
ctrl &= ~AM65_CPSW_PN_IET_MAC_LINKFAIL;
writel(ctrl, port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
do { do {
/* Reset the verify state machine by writing 1
* to LINKFAIL
*/
ctrl = readl(port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
ctrl |= AM65_CPSW_PN_IET_MAC_LINKFAIL;
writel(ctrl, port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
/* Clear MAC_LINKFAIL bit to start Verify. */
ctrl = readl(port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
ctrl &= ~AM65_CPSW_PN_IET_MAC_LINKFAIL;
writel(ctrl, port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
msleep(port->qos.iet.verify_time_ms); msleep(port->qos.iet.verify_time_ms);
status = readl(port->port_base + AM65_CPSW_PN_REG_IET_STATUS); status = readl(port->port_base + AM65_CPSW_PN_REG_IET_STATUS);
@@ -330,7 +353,7 @@ static int am65_cpsw_iet_verify_wait(struct am65_cpsw_port *port)
netdev_dbg(port->ndev, "MAC Merge verify error\n"); netdev_dbg(port->ndev, "MAC Merge verify error\n");
return -ENODEV; return -ENODEV;
} }
} while (try-- > 0); } while (--try > 0);
netdev_dbg(port->ndev, "MAC Merge verify timeout\n"); netdev_dbg(port->ndev, "MAC Merge verify timeout\n");
return -ETIMEDOUT; return -ETIMEDOUT;

View File

@@ -73,8 +73,11 @@ int mdiobus_register_device(struct mdio_device *mdiodev)
return err; return err;
err = mdiobus_register_reset(mdiodev); err = mdiobus_register_reset(mdiodev);
if (err) if (err) {
gpiod_put(mdiodev->reset_gpio);
mdiodev->reset_gpio = NULL;
return err; return err;
}
/* Assert the reset signal */ /* Assert the reset signal */
mdio_device_reset(mdiodev, 1); mdio_device_reset(mdiodev, 1);

View File

@@ -4380,12 +4380,6 @@ static int lan8814_config_init(struct phy_device *phydev)
{ {
struct kszphy_priv *lan8814 = phydev->priv; struct kszphy_priv *lan8814 = phydev->priv;
/* Reset the PHY */
lanphy_modify_page_reg(phydev, LAN8814_PAGE_COMMON_REGS,
LAN8814_QSGMII_SOFT_RESET,
LAN8814_QSGMII_SOFT_RESET_BIT,
LAN8814_QSGMII_SOFT_RESET_BIT);
/* Disable ANEG with QSGMII PCS Host side */ /* Disable ANEG with QSGMII PCS Host side */
lanphy_modify_page_reg(phydev, LAN8814_PAGE_PORT_REGS, lanphy_modify_page_reg(phydev, LAN8814_PAGE_PORT_REGS,
LAN8814_QSGMII_PCS1G_ANEG_CONFIG, LAN8814_QSGMII_PCS1G_ANEG_CONFIG,
@@ -4471,6 +4465,12 @@ static int lan8814_probe(struct phy_device *phydev)
addr, sizeof(struct lan8814_shared_priv)); addr, sizeof(struct lan8814_shared_priv));
if (phy_package_init_once(phydev)) { if (phy_package_init_once(phydev)) {
/* Reset the PHY */
lanphy_modify_page_reg(phydev, LAN8814_PAGE_COMMON_REGS,
LAN8814_QSGMII_SOFT_RESET,
LAN8814_QSGMII_SOFT_RESET_BIT,
LAN8814_QSGMII_SOFT_RESET_BIT);
err = lan8814_release_coma_mode(phydev); err = lan8814_release_coma_mode(phydev);
if (err) if (err)
return err; return err;

View File

@@ -2631,22 +2631,28 @@ static void receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
return; return;
} }
/* 1. Save the flags early, as the XDP program might overwrite them. /* About the flags below:
* 1. Save the flags early, as the XDP program might overwrite them.
* These flags ensure packets marked as VIRTIO_NET_HDR_F_DATA_VALID * These flags ensure packets marked as VIRTIO_NET_HDR_F_DATA_VALID
* stay valid after XDP processing. * stay valid after XDP processing.
* 2. XDP doesn't work with partially checksummed packets (refer to * 2. XDP doesn't work with partially checksummed packets (refer to
* virtnet_xdp_set()), so packets marked as * virtnet_xdp_set()), so packets marked as
* VIRTIO_NET_HDR_F_NEEDS_CSUM get dropped during XDP processing. * VIRTIO_NET_HDR_F_NEEDS_CSUM get dropped during XDP processing.
*/ */
flags = ((struct virtio_net_common_hdr *)buf)->hdr.flags;
if (vi->mergeable_rx_bufs) if (vi->mergeable_rx_bufs) {
flags = ((struct virtio_net_common_hdr *)buf)->hdr.flags;
skb = receive_mergeable(dev, vi, rq, buf, ctx, len, xdp_xmit, skb = receive_mergeable(dev, vi, rq, buf, ctx, len, xdp_xmit,
stats); stats);
else if (vi->big_packets) } else if (vi->big_packets) {
void *p = page_address((struct page *)buf);
flags = ((struct virtio_net_common_hdr *)p)->hdr.flags;
skb = receive_big(dev, vi, rq, buf, len, stats); skb = receive_big(dev, vi, rq, buf, len, stats);
else } else {
flags = ((struct virtio_net_common_hdr *)buf)->hdr.flags;
skb = receive_small(dev, vi, rq, buf, ctx, len, xdp_xmit, stats); skb = receive_small(dev, vi, rq, buf, ctx, len, xdp_xmit, stats);
}
if (unlikely(!skb)) if (unlikely(!skb))
return; return;

View File

@@ -5961,6 +5961,9 @@ static int wmi_process_mgmt_tx_comp(struct ath11k *ar,
dma_unmap_single(ar->ab->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); dma_unmap_single(ar->ab->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
info = IEEE80211_SKB_CB(msdu); info = IEEE80211_SKB_CB(msdu);
memset(&info->status, 0, sizeof(info->status));
info->status.rates[0].idx = -1;
if ((!(info->flags & IEEE80211_TX_CTL_NO_ACK)) && if ((!(info->flags & IEEE80211_TX_CTL_NO_ACK)) &&
!tx_compl_param->status) { !tx_compl_param->status) {
info->flags |= IEEE80211_TX_STAT_ACK; info->flags |= IEEE80211_TX_STAT_ACK;

View File

@@ -708,18 +708,13 @@ static int
iwl_mld_get_chan_load_from_element(struct iwl_mld *mld, iwl_mld_get_chan_load_from_element(struct iwl_mld *mld,
struct ieee80211_bss_conf *link_conf) struct ieee80211_bss_conf *link_conf)
{ {
struct ieee80211_vif *vif = link_conf->vif;
const struct cfg80211_bss_ies *ies; const struct cfg80211_bss_ies *ies;
const struct element *bss_load_elem = NULL; const struct element *bss_load_elem = NULL;
const struct ieee80211_bss_load_elem *bss_load; const struct ieee80211_bss_load_elem *bss_load;
guard(rcu)(); guard(rcu)();
if (ieee80211_vif_link_active(vif, link_conf->link_id)) ies = rcu_dereference(link_conf->bss->beacon_ies);
ies = rcu_dereference(link_conf->bss->beacon_ies);
else
ies = rcu_dereference(link_conf->bss->ies);
if (ies) if (ies)
bss_load_elem = cfg80211_find_elem(WLAN_EID_QBSS_LOAD, bss_load_elem = cfg80211_find_elem(WLAN_EID_QBSS_LOAD,
ies->data, ies->len); ies->data, ies->len);

View File

@@ -938,19 +938,12 @@ u8 iwl_mvm_mac_ctxt_get_lowest_rate(struct iwl_mvm *mvm,
u16 iwl_mvm_mac_ctxt_get_beacon_flags(const struct iwl_fw *fw, u8 rate_idx) u16 iwl_mvm_mac_ctxt_get_beacon_flags(const struct iwl_fw *fw, u8 rate_idx)
{ {
u16 flags = iwl_mvm_mac80211_idx_to_hwrate(fw, rate_idx);
bool is_new_rate = iwl_fw_lookup_cmd_ver(fw, BEACON_TEMPLATE_CMD, 0) > 10; bool is_new_rate = iwl_fw_lookup_cmd_ver(fw, BEACON_TEMPLATE_CMD, 0) > 10;
u16 flags, cck_flag;
if (is_new_rate) {
flags = iwl_mvm_mac80211_idx_to_hwrate(fw, rate_idx);
cck_flag = IWL_MAC_BEACON_CCK;
} else {
cck_flag = IWL_MAC_BEACON_CCK_V1;
flags = iwl_fw_rate_idx_to_plcp(rate_idx);
}
if (rate_idx <= IWL_LAST_CCK_RATE) if (rate_idx <= IWL_LAST_CCK_RATE)
flags |= cck_flag; flags |= is_new_rate ? IWL_MAC_BEACON_CCK
: IWL_MAC_BEACON_CCK_V1;
return flags; return flags;
} }

View File

@@ -463,7 +463,7 @@ static int iwl_mvm_aux_roc_te_handle_notif(struct iwl_mvm *mvm,
if (!aux_roc_te) /* Not a Aux ROC time event */ if (!aux_roc_te) /* Not a Aux ROC time event */
return -EINVAL; return -EINVAL;
iwl_mvm_te_check_trigger(mvm, notif, te_data); iwl_mvm_te_check_trigger(mvm, notif, aux_roc_te);
IWL_DEBUG_TE(mvm, IWL_DEBUG_TE(mvm,
"Aux ROC time event notification - UID = 0x%x action %d (error = %d)\n", "Aux ROC time event notification - UID = 0x%x action %d (error = %d)\n",
@@ -475,14 +475,14 @@ static int iwl_mvm_aux_roc_te_handle_notif(struct iwl_mvm *mvm,
/* End TE, notify mac80211 */ /* End TE, notify mac80211 */
ieee80211_remain_on_channel_expired(mvm->hw); ieee80211_remain_on_channel_expired(mvm->hw);
iwl_mvm_roc_finished(mvm); /* flush aux queue */ iwl_mvm_roc_finished(mvm); /* flush aux queue */
list_del(&te_data->list); /* remove from list */ list_del(&aux_roc_te->list); /* remove from list */
te_data->running = false; aux_roc_te->running = false;
te_data->vif = NULL; aux_roc_te->vif = NULL;
te_data->uid = 0; aux_roc_te->uid = 0;
te_data->id = TE_MAX; aux_roc_te->id = TE_MAX;
} else if (le32_to_cpu(notif->action) == TE_V2_NOTIF_HOST_EVENT_START) { } else if (le32_to_cpu(notif->action) == TE_V2_NOTIF_HOST_EVENT_START) {
set_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status); set_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status);
te_data->running = true; aux_roc_te->running = true;
ieee80211_ready_on_channel(mvm->hw); /* Start TE */ ieee80211_ready_on_channel(mvm->hw); /* Start TE */
} else { } else {
IWL_DEBUG_TE(mvm, IWL_DEBUG_TE(mvm,

View File

@@ -159,9 +159,15 @@ int iwl_mvm_legacy_rate_to_mac80211_idx(u32 rate_n_flags,
u8 iwl_mvm_mac80211_idx_to_hwrate(const struct iwl_fw *fw, int rate_idx) u8 iwl_mvm_mac80211_idx_to_hwrate(const struct iwl_fw *fw, int rate_idx)
{ {
return (rate_idx >= IWL_FIRST_OFDM_RATE ? if (iwl_fw_lookup_cmd_ver(fw, TX_CMD, 0) > 8)
rate_idx - IWL_FIRST_OFDM_RATE : /* In the new rate legacy rates are indexed:
rate_idx); * 0 - 3 for CCK and 0 - 7 for OFDM.
*/
return (rate_idx >= IWL_FIRST_OFDM_RATE ?
rate_idx - IWL_FIRST_OFDM_RATE :
rate_idx);
return iwl_fw_rate_idx_to_plcp(rate_idx);
} }
u8 iwl_mvm_mac80211_ac_to_ucode_ac(enum ieee80211_ac_numbers ac) u8 iwl_mvm_mac80211_ac_to_ucode_ac(enum ieee80211_ac_numbers ac)

View File

@@ -2966,6 +2966,51 @@ mwl8k_cmd_rf_antenna(struct ieee80211_hw *hw, int antenna, int mask)
/* /*
* CMD_SET_BEACON. * CMD_SET_BEACON.
*/ */
static bool mwl8k_beacon_has_ds_params(const u8 *buf, int len)
{
const struct ieee80211_mgmt *mgmt = (const void *)buf;
int ies_len;
if (len <= offsetof(struct ieee80211_mgmt, u.beacon.variable))
return false;
ies_len = len - offsetof(struct ieee80211_mgmt, u.beacon.variable);
return cfg80211_find_ie(WLAN_EID_DS_PARAMS, mgmt->u.beacon.variable,
ies_len) != NULL;
}
static void mwl8k_beacon_copy_inject_ds_params(struct ieee80211_hw *hw,
u8 *buf_dst, const u8 *buf_src,
int src_len)
{
const struct ieee80211_mgmt *mgmt = (const void *)buf_src;
static const u8 before_ds_params[] = {
WLAN_EID_SSID,
WLAN_EID_SUPP_RATES,
};
const u8 *ies;
int hdr_len, left, offs, pos;
ies = mgmt->u.beacon.variable;
hdr_len = offsetof(struct ieee80211_mgmt, u.beacon.variable);
offs = ieee80211_ie_split(ies, src_len - hdr_len, before_ds_params,
ARRAY_SIZE(before_ds_params), 0);
pos = hdr_len + offs;
left = src_len - pos;
memcpy(buf_dst, buf_src, pos);
/* Inject a DSSS Parameter Set after SSID + Supp Rates */
buf_dst[pos + 0] = WLAN_EID_DS_PARAMS;
buf_dst[pos + 1] = 1;
buf_dst[pos + 2] = hw->conf.chandef.chan->hw_value;
memcpy(buf_dst + pos + 3, buf_src + pos, left);
}
struct mwl8k_cmd_set_beacon { struct mwl8k_cmd_set_beacon {
struct mwl8k_cmd_pkt_hdr header; struct mwl8k_cmd_pkt_hdr header;
__le16 beacon_len; __le16 beacon_len;
@@ -2975,17 +3020,33 @@ struct mwl8k_cmd_set_beacon {
static int mwl8k_cmd_set_beacon(struct ieee80211_hw *hw, static int mwl8k_cmd_set_beacon(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u8 *beacon, int len) struct ieee80211_vif *vif, u8 *beacon, int len)
{ {
bool ds_params_present = mwl8k_beacon_has_ds_params(beacon, len);
struct mwl8k_cmd_set_beacon *cmd; struct mwl8k_cmd_set_beacon *cmd;
int rc; int rc, final_len = len;
cmd = kzalloc(sizeof(*cmd) + len, GFP_KERNEL); if (!ds_params_present) {
/*
* mwl8k firmware requires a DS Params IE with the current
* channel in AP beacons. If mac80211/hostapd does not
* include it, inject one here. IE ID + length + channel
* number = 3 bytes.
*/
final_len += 3;
}
cmd = kzalloc(sizeof(*cmd) + final_len, GFP_KERNEL);
if (cmd == NULL) if (cmd == NULL)
return -ENOMEM; return -ENOMEM;
cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_BEACON); cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_BEACON);
cmd->header.length = cpu_to_le16(sizeof(*cmd) + len); cmd->header.length = cpu_to_le16(sizeof(*cmd) + final_len);
cmd->beacon_len = cpu_to_le16(len); cmd->beacon_len = cpu_to_le16(final_len);
memcpy(cmd->beacon, beacon, len);
if (ds_params_present)
memcpy(cmd->beacon, beacon, len);
else
mwl8k_beacon_copy_inject_ds_params(hw, cmd->beacon, beacon,
len);
rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header);
kfree(cmd); kfree(cmd);

View File

@@ -2003,8 +2003,14 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
struct ieee80211_sta *sta = control->sta; struct ieee80211_sta *sta = control->sta;
struct ieee80211_bss_conf *bss_conf; struct ieee80211_bss_conf *bss_conf;
/* This can happen in case of monitor injection */
if (!vif) {
ieee80211_free_txskb(hw, skb);
return;
}
if (link != IEEE80211_LINK_UNSPECIFIED) { if (link != IEEE80211_LINK_UNSPECIFIED) {
bss_conf = rcu_dereference(txi->control.vif->link_conf[link]); bss_conf = rcu_dereference(vif->link_conf[link]);
if (sta) if (sta)
link_sta = rcu_dereference(sta->link[link]); link_sta = rcu_dereference(sta->link[link]);
} else { } else {
@@ -2065,13 +2071,13 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
return; return;
} }
if (txi->control.vif) if (vif)
hwsim_check_magic(txi->control.vif); hwsim_check_magic(vif);
if (control->sta) if (control->sta)
hwsim_check_sta_magic(control->sta); hwsim_check_sta_magic(control->sta);
if (ieee80211_hw_check(hw, SUPPORTS_RC_TABLE)) if (ieee80211_hw_check(hw, SUPPORTS_RC_TABLE))
ieee80211_get_tx_rates(txi->control.vif, control->sta, skb, ieee80211_get_tx_rates(vif, control->sta, skb,
txi->control.rates, txi->control.rates,
ARRAY_SIZE(txi->control.rates)); ARRAY_SIZE(txi->control.rates));

View File

@@ -573,6 +573,8 @@ static int cq_create(struct mlx5_vdpa_net *ndev, u16 idx, u32 num_ent)
vcq->mcq.set_ci_db = vcq->db.db; vcq->mcq.set_ci_db = vcq->db.db;
vcq->mcq.arm_db = vcq->db.db + 1; vcq->mcq.arm_db = vcq->db.db + 1;
vcq->mcq.cqe_sz = 64; vcq->mcq.cqe_sz = 64;
vcq->mcq.comp = mlx5_vdpa_cq_comp;
vcq->cqe = num_ent;
err = cq_frag_buf_alloc(ndev, &vcq->buf, num_ent); err = cq_frag_buf_alloc(ndev, &vcq->buf, num_ent);
if (err) if (err)
@@ -612,10 +614,6 @@ static int cq_create(struct mlx5_vdpa_net *ndev, u16 idx, u32 num_ent)
if (err) if (err)
goto err_vec; goto err_vec;
vcq->mcq.comp = mlx5_vdpa_cq_comp;
vcq->cqe = num_ent;
vcq->mcq.set_ci_db = vcq->db.db;
vcq->mcq.arm_db = vcq->db.db + 1;
mlx5_cq_arm(&mvq->cq.mcq, MLX5_CQ_DB_REQ_NOT, uar_page, mvq->cq.mcq.cons_index); mlx5_cq_arm(&mvq->cq.mcq, MLX5_CQ_DB_REQ_NOT, uar_page, mvq->cq.mcq.cons_index);
kfree(in); kfree(in);
return 0; return 0;

View File

@@ -492,7 +492,7 @@ struct ethtool_pause_stats {
}; };
#define ETHTOOL_MAX_LANES 8 #define ETHTOOL_MAX_LANES 8
/** /*
* IEEE 802.3ck/df defines 16 bins for FEC histogram plus one more for * IEEE 802.3ck/df defines 16 bins for FEC histogram plus one more for
* the end-of-list marker, total 17 items * the end-of-list marker, total 17 items
*/ */

View File

@@ -183,6 +183,7 @@ static inline void mlx5_cq_put(struct mlx5_core_cq *cq)
complete(&cq->free); complete(&cq->free);
} }
void mlx5_add_cq_to_tasklet(struct mlx5_core_cq *cq, struct mlx5_eqe *eqe);
int mlx5_create_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq, int mlx5_create_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
u32 *in, int inlen, u32 *out, int outlen); u32 *in, int inlen, u32 *out, int outlen);
int mlx5_core_create_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq, int mlx5_core_create_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,

View File

@@ -2783,6 +2783,11 @@ struct hci_ev_le_per_adv_report {
__u8 data[]; __u8 data[];
} __packed; } __packed;
#define HCI_EV_LE_PA_SYNC_LOST 0x10
struct hci_ev_le_pa_sync_lost {
__le16 handle;
} __packed;
#define LE_PA_DATA_COMPLETE 0x00 #define LE_PA_DATA_COMPLETE 0x00
#define LE_PA_DATA_MORE_TO_COME 0x01 #define LE_PA_DATA_MORE_TO_COME 0x01
#define LE_PA_DATA_TRUNCATED 0x02 #define LE_PA_DATA_TRUNCATED 0x02

View File

@@ -53,6 +53,11 @@ static bool enable_6lowpan;
static struct l2cap_chan *listen_chan; static struct l2cap_chan *listen_chan;
static DEFINE_MUTEX(set_lock); static DEFINE_MUTEX(set_lock);
enum {
LOWPAN_PEER_CLOSING,
LOWPAN_PEER_MAXBITS
};
struct lowpan_peer { struct lowpan_peer {
struct list_head list; struct list_head list;
struct rcu_head rcu; struct rcu_head rcu;
@@ -61,6 +66,8 @@ struct lowpan_peer {
/* peer addresses in various formats */ /* peer addresses in various formats */
unsigned char lladdr[ETH_ALEN]; unsigned char lladdr[ETH_ALEN];
struct in6_addr peer_addr; struct in6_addr peer_addr;
DECLARE_BITMAP(flags, LOWPAN_PEER_MAXBITS);
}; };
struct lowpan_btle_dev { struct lowpan_btle_dev {
@@ -289,6 +296,7 @@ static int recv_pkt(struct sk_buff *skb, struct net_device *dev,
local_skb->pkt_type = PACKET_HOST; local_skb->pkt_type = PACKET_HOST;
local_skb->dev = dev; local_skb->dev = dev;
skb_reset_mac_header(local_skb);
skb_set_transport_header(local_skb, sizeof(struct ipv6hdr)); skb_set_transport_header(local_skb, sizeof(struct ipv6hdr));
if (give_skb_to_upper(local_skb, dev) != NET_RX_SUCCESS) { if (give_skb_to_upper(local_skb, dev) != NET_RX_SUCCESS) {
@@ -919,7 +927,9 @@ static int bt_6lowpan_disconnect(struct l2cap_conn *conn, u8 dst_type)
BT_DBG("peer %p chan %p", peer, peer->chan); BT_DBG("peer %p chan %p", peer, peer->chan);
l2cap_chan_lock(peer->chan);
l2cap_chan_close(peer->chan, ENOENT); l2cap_chan_close(peer->chan, ENOENT);
l2cap_chan_unlock(peer->chan);
return 0; return 0;
} }
@@ -956,10 +966,11 @@ static struct l2cap_chan *bt_6lowpan_listen(void)
} }
static int get_l2cap_conn(char *buf, bdaddr_t *addr, u8 *addr_type, static int get_l2cap_conn(char *buf, bdaddr_t *addr, u8 *addr_type,
struct l2cap_conn **conn) struct l2cap_conn **conn, bool disconnect)
{ {
struct hci_conn *hcon; struct hci_conn *hcon;
struct hci_dev *hdev; struct hci_dev *hdev;
int le_addr_type;
int n; int n;
n = sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx %hhu", n = sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx %hhu",
@@ -970,13 +981,32 @@ static int get_l2cap_conn(char *buf, bdaddr_t *addr, u8 *addr_type,
if (n < 7) if (n < 7)
return -EINVAL; return -EINVAL;
if (disconnect) {
/* The "disconnect" debugfs command has used different address
* type constants than "connect" since 2015. Let's retain that
* for now even though it's obviously buggy...
*/
*addr_type += 1;
}
switch (*addr_type) {
case BDADDR_LE_PUBLIC:
le_addr_type = ADDR_LE_DEV_PUBLIC;
break;
case BDADDR_LE_RANDOM:
le_addr_type = ADDR_LE_DEV_RANDOM;
break;
default:
return -EINVAL;
}
/* The LE_PUBLIC address type is ignored because of BDADDR_ANY */ /* The LE_PUBLIC address type is ignored because of BDADDR_ANY */
hdev = hci_get_route(addr, BDADDR_ANY, BDADDR_LE_PUBLIC); hdev = hci_get_route(addr, BDADDR_ANY, BDADDR_LE_PUBLIC);
if (!hdev) if (!hdev)
return -ENOENT; return -ENOENT;
hci_dev_lock(hdev); hci_dev_lock(hdev);
hcon = hci_conn_hash_lookup_le(hdev, addr, *addr_type); hcon = hci_conn_hash_lookup_le(hdev, addr, le_addr_type);
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
hci_dev_put(hdev); hci_dev_put(hdev);
@@ -993,41 +1023,52 @@ static int get_l2cap_conn(char *buf, bdaddr_t *addr, u8 *addr_type,
static void disconnect_all_peers(void) static void disconnect_all_peers(void)
{ {
struct lowpan_btle_dev *entry; struct lowpan_btle_dev *entry;
struct lowpan_peer *peer, *tmp_peer, *new_peer; struct lowpan_peer *peer;
struct list_head peers; int nchans;
INIT_LIST_HEAD(&peers); /* l2cap_chan_close() cannot be called from RCU, and lock ordering
* chan->lock > devices_lock prevents taking write side lock, so copy
/* We make a separate list of peers as the close_cb() will * then close.
* modify the device peers list so it is better not to mess
* with the same list at the same time.
*/ */
rcu_read_lock(); rcu_read_lock();
list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list)
list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) { list_for_each_entry_rcu(peer, &entry->peers, list)
list_for_each_entry_rcu(peer, &entry->peers, list) { clear_bit(LOWPAN_PEER_CLOSING, peer->flags);
new_peer = kmalloc(sizeof(*new_peer), GFP_ATOMIC);
if (!new_peer)
break;
new_peer->chan = peer->chan;
INIT_LIST_HEAD(&new_peer->list);
list_add(&new_peer->list, &peers);
}
}
rcu_read_unlock(); rcu_read_unlock();
spin_lock(&devices_lock); do {
list_for_each_entry_safe(peer, tmp_peer, &peers, list) { struct l2cap_chan *chans[32];
l2cap_chan_close(peer->chan, ENOENT); int i;
list_del_rcu(&peer->list); nchans = 0;
kfree_rcu(peer, rcu);
} spin_lock(&devices_lock);
spin_unlock(&devices_lock);
list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) {
list_for_each_entry_rcu(peer, &entry->peers, list) {
if (test_and_set_bit(LOWPAN_PEER_CLOSING,
peer->flags))
continue;
l2cap_chan_hold(peer->chan);
chans[nchans++] = peer->chan;
if (nchans >= ARRAY_SIZE(chans))
goto done;
}
}
done:
spin_unlock(&devices_lock);
for (i = 0; i < nchans; ++i) {
l2cap_chan_lock(chans[i]);
l2cap_chan_close(chans[i], ENOENT);
l2cap_chan_unlock(chans[i]);
l2cap_chan_put(chans[i]);
}
} while (nchans);
} }
struct set_enable { struct set_enable {
@@ -1050,7 +1091,9 @@ static void do_enable_set(struct work_struct *work)
mutex_lock(&set_lock); mutex_lock(&set_lock);
if (listen_chan) { if (listen_chan) {
l2cap_chan_lock(listen_chan);
l2cap_chan_close(listen_chan, 0); l2cap_chan_close(listen_chan, 0);
l2cap_chan_unlock(listen_chan);
l2cap_chan_put(listen_chan); l2cap_chan_put(listen_chan);
} }
@@ -1103,13 +1146,15 @@ static ssize_t lowpan_control_write(struct file *fp,
buf[buf_size] = '\0'; buf[buf_size] = '\0';
if (memcmp(buf, "connect ", 8) == 0) { if (memcmp(buf, "connect ", 8) == 0) {
ret = get_l2cap_conn(&buf[8], &addr, &addr_type, &conn); ret = get_l2cap_conn(&buf[8], &addr, &addr_type, &conn, false);
if (ret == -EINVAL) if (ret == -EINVAL)
return ret; return ret;
mutex_lock(&set_lock); mutex_lock(&set_lock);
if (listen_chan) { if (listen_chan) {
l2cap_chan_lock(listen_chan);
l2cap_chan_close(listen_chan, 0); l2cap_chan_close(listen_chan, 0);
l2cap_chan_unlock(listen_chan);
l2cap_chan_put(listen_chan); l2cap_chan_put(listen_chan);
listen_chan = NULL; listen_chan = NULL;
} }
@@ -1140,7 +1185,7 @@ static ssize_t lowpan_control_write(struct file *fp,
} }
if (memcmp(buf, "disconnect ", 11) == 0) { if (memcmp(buf, "disconnect ", 11) == 0) {
ret = get_l2cap_conn(&buf[11], &addr, &addr_type, &conn); ret = get_l2cap_conn(&buf[11], &addr, &addr_type, &conn, true);
if (ret < 0) if (ret < 0)
return ret; return ret;
@@ -1271,7 +1316,9 @@ static void __exit bt_6lowpan_exit(void)
debugfs_remove(lowpan_control_debugfs); debugfs_remove(lowpan_control_debugfs);
if (listen_chan) { if (listen_chan) {
l2cap_chan_lock(listen_chan);
l2cap_chan_close(listen_chan, 0); l2cap_chan_close(listen_chan, 0);
l2cap_chan_unlock(listen_chan);
l2cap_chan_put(listen_chan); l2cap_chan_put(listen_chan);
} }

View File

@@ -769,21 +769,23 @@ static void find_bis(struct hci_conn *conn, void *data)
d->count++; d->count++;
} }
static int hci_le_big_terminate(struct hci_dev *hdev, u8 big, struct hci_conn *conn) static int hci_le_big_terminate(struct hci_dev *hdev, struct hci_conn *conn)
{ {
struct iso_list_data *d; struct iso_list_data *d;
int ret; int ret;
bt_dev_dbg(hdev, "big 0x%2.2x sync_handle 0x%4.4x", big, conn->sync_handle); bt_dev_dbg(hdev, "hcon %p big 0x%2.2x sync_handle 0x%4.4x", conn,
conn->iso_qos.bcast.big, conn->sync_handle);
d = kzalloc(sizeof(*d), GFP_KERNEL); d = kzalloc(sizeof(*d), GFP_KERNEL);
if (!d) if (!d)
return -ENOMEM; return -ENOMEM;
d->big = big; d->big = conn->iso_qos.bcast.big;
d->sync_handle = conn->sync_handle; d->sync_handle = conn->sync_handle;
if (test_and_clear_bit(HCI_CONN_PA_SYNC, &conn->flags)) { if (conn->type == PA_LINK &&
test_and_clear_bit(HCI_CONN_PA_SYNC, &conn->flags)) {
hci_conn_hash_list_flag(hdev, find_bis, PA_LINK, hci_conn_hash_list_flag(hdev, find_bis, PA_LINK,
HCI_CONN_PA_SYNC, d); HCI_CONN_PA_SYNC, d);
@@ -801,6 +803,9 @@ static int hci_le_big_terminate(struct hci_dev *hdev, u8 big, struct hci_conn *c
d->big_sync_term = true; d->big_sync_term = true;
} }
if (!d->pa_sync_term && !d->big_sync_term)
return 0;
ret = hci_cmd_sync_queue(hdev, big_terminate_sync, d, ret = hci_cmd_sync_queue(hdev, big_terminate_sync, d,
terminate_big_destroy); terminate_big_destroy);
if (ret) if (ret)
@@ -852,8 +857,7 @@ static void bis_cleanup(struct hci_conn *conn)
hci_le_terminate_big(hdev, conn); hci_le_terminate_big(hdev, conn);
} else { } else {
hci_le_big_terminate(hdev, conn->iso_qos.bcast.big, hci_le_big_terminate(hdev, conn);
conn);
} }
} }
@@ -994,19 +998,20 @@ static struct hci_conn *__hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t
conn->mtu = hdev->le_mtu ? hdev->le_mtu : hdev->acl_mtu; conn->mtu = hdev->le_mtu ? hdev->le_mtu : hdev->acl_mtu;
break; break;
case CIS_LINK: case CIS_LINK:
case BIS_LINK:
case PA_LINK:
/* conn->src should reflect the local identity address */ /* conn->src should reflect the local identity address */
hci_copy_identity_address(hdev, &conn->src, &conn->src_type); hci_copy_identity_address(hdev, &conn->src, &conn->src_type);
/* set proper cleanup function */ if (conn->role == HCI_ROLE_MASTER)
if (!bacmp(dst, BDADDR_ANY))
conn->cleanup = bis_cleanup;
else if (conn->role == HCI_ROLE_MASTER)
conn->cleanup = cis_cleanup; conn->cleanup = cis_cleanup;
conn->mtu = hdev->iso_mtu ? hdev->iso_mtu : conn->mtu = hdev->iso_mtu;
hdev->le_mtu ? hdev->le_mtu : hdev->acl_mtu; break;
case PA_LINK:
case BIS_LINK:
/* conn->src should reflect the local identity address */
hci_copy_identity_address(hdev, &conn->src, &conn->src_type);
conn->cleanup = bis_cleanup;
conn->mtu = hdev->iso_mtu;
break; break;
case SCO_LINK: case SCO_LINK:
if (lmp_esco_capable(hdev)) if (lmp_esco_capable(hdev))

View File

@@ -5843,6 +5843,29 @@ static void hci_le_enh_conn_complete_evt(struct hci_dev *hdev, void *data,
le16_to_cpu(ev->supervision_timeout)); le16_to_cpu(ev->supervision_timeout));
} }
static void hci_le_pa_sync_lost_evt(struct hci_dev *hdev, void *data,
struct sk_buff *skb)
{
struct hci_ev_le_pa_sync_lost *ev = data;
u16 handle = le16_to_cpu(ev->handle);
struct hci_conn *conn;
bt_dev_dbg(hdev, "sync handle 0x%4.4x", handle);
hci_dev_lock(hdev);
/* Delete the pa sync connection */
conn = hci_conn_hash_lookup_pa_sync_handle(hdev, handle);
if (conn) {
clear_bit(HCI_CONN_BIG_SYNC, &conn->flags);
clear_bit(HCI_CONN_PA_SYNC, &conn->flags);
hci_disconn_cfm(conn, HCI_ERROR_REMOTE_USER_TERM);
hci_conn_del(conn);
}
hci_dev_unlock(hdev);
}
static void hci_le_ext_adv_term_evt(struct hci_dev *hdev, void *data, static void hci_le_ext_adv_term_evt(struct hci_dev *hdev, void *data,
struct sk_buff *skb) struct sk_buff *skb)
{ {
@@ -7001,14 +7024,9 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data,
continue; continue;
} }
if (ev->status != 0x42) { if (ev->status != 0x42)
/* Mark PA sync as established */ /* Mark PA sync as established */
set_bit(HCI_CONN_PA_SYNC, &bis->flags); set_bit(HCI_CONN_PA_SYNC, &bis->flags);
/* Reset cleanup callback of PA Sync so it doesn't
* terminate the sync when deleting the connection.
*/
conn->cleanup = NULL;
}
bis->sync_handle = conn->sync_handle; bis->sync_handle = conn->sync_handle;
bis->iso_qos.bcast.big = ev->handle; bis->iso_qos.bcast.big = ev->handle;
@@ -7051,29 +7069,24 @@ static void hci_le_big_sync_lost_evt(struct hci_dev *hdev, void *data,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct hci_evt_le_big_sync_lost *ev = data; struct hci_evt_le_big_sync_lost *ev = data;
struct hci_conn *bis, *conn; struct hci_conn *bis;
bool mgmt_conn; bool mgmt_conn = false;
bt_dev_dbg(hdev, "big handle 0x%2.2x", ev->handle); bt_dev_dbg(hdev, "big handle 0x%2.2x", ev->handle);
hci_dev_lock(hdev); hci_dev_lock(hdev);
/* Delete the pa sync connection */
bis = hci_conn_hash_lookup_pa_sync_big_handle(hdev, ev->handle);
if (bis) {
conn = hci_conn_hash_lookup_pa_sync_handle(hdev,
bis->sync_handle);
if (conn)
hci_conn_del(conn);
}
/* Delete each bis connection */ /* Delete each bis connection */
while ((bis = hci_conn_hash_lookup_big_state(hdev, ev->handle, while ((bis = hci_conn_hash_lookup_big_state(hdev, ev->handle,
BT_CONNECTED, BT_CONNECTED,
HCI_ROLE_SLAVE))) { HCI_ROLE_SLAVE))) {
mgmt_conn = test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &bis->flags); if (!mgmt_conn) {
mgmt_device_disconnected(hdev, &bis->dst, bis->type, bis->dst_type, mgmt_conn = test_and_clear_bit(HCI_CONN_MGMT_CONNECTED,
ev->reason, mgmt_conn); &bis->flags);
mgmt_device_disconnected(hdev, &bis->dst, bis->type,
bis->dst_type, ev->reason,
mgmt_conn);
}
clear_bit(HCI_CONN_BIG_SYNC, &bis->flags); clear_bit(HCI_CONN_BIG_SYNC, &bis->flags);
hci_disconn_cfm(bis, ev->reason); hci_disconn_cfm(bis, ev->reason);
@@ -7187,6 +7200,9 @@ static const struct hci_le_ev {
hci_le_per_adv_report_evt, hci_le_per_adv_report_evt,
sizeof(struct hci_ev_le_per_adv_report), sizeof(struct hci_ev_le_per_adv_report),
HCI_MAX_EVENT_SIZE), HCI_MAX_EVENT_SIZE),
/* [0x10 = HCI_EV_LE_PA_SYNC_LOST] */
HCI_LE_EV(HCI_EV_LE_PA_SYNC_LOST, hci_le_pa_sync_lost_evt,
sizeof(struct hci_ev_le_pa_sync_lost)),
/* [0x12 = HCI_EV_LE_EXT_ADV_SET_TERM] */ /* [0x12 = HCI_EV_LE_EXT_ADV_SET_TERM] */
HCI_LE_EV(HCI_EV_LE_EXT_ADV_SET_TERM, hci_le_ext_adv_term_evt, HCI_LE_EV(HCI_EV_LE_EXT_ADV_SET_TERM, hci_le_ext_adv_term_evt,
sizeof(struct hci_evt_le_ext_adv_set_term)), sizeof(struct hci_evt_le_ext_adv_set_term)),

View File

@@ -6999,7 +6999,7 @@ static void create_pa_complete(struct hci_dev *hdev, void *data, int err)
hci_dev_lock(hdev); hci_dev_lock(hdev);
if (!hci_conn_valid(hdev, conn)) if (hci_conn_valid(hdev, conn))
clear_bit(HCI_CONN_CREATE_PA_SYNC, &conn->flags); clear_bit(HCI_CONN_CREATE_PA_SYNC, &conn->flags);
if (!err) if (!err)

View File

@@ -497,6 +497,7 @@ void l2cap_chan_hold(struct l2cap_chan *c)
kref_get(&c->kref); kref_get(&c->kref);
} }
EXPORT_SYMBOL_GPL(l2cap_chan_hold);
struct l2cap_chan *l2cap_chan_hold_unless_zero(struct l2cap_chan *c) struct l2cap_chan *l2cap_chan_hold_unless_zero(struct l2cap_chan *c)
{ {

View File

@@ -9497,6 +9497,7 @@ void mgmt_index_removed(struct hci_dev *hdev)
cancel_delayed_work_sync(&hdev->discov_off); cancel_delayed_work_sync(&hdev->discov_off);
cancel_delayed_work_sync(&hdev->service_cache); cancel_delayed_work_sync(&hdev->service_cache);
cancel_delayed_work_sync(&hdev->rpa_expired); cancel_delayed_work_sync(&hdev->rpa_expired);
cancel_delayed_work_sync(&hdev->mesh_send_done);
} }
void mgmt_power_on(struct hci_dev *hdev, int err) void mgmt_power_on(struct hci_dev *hdev, int err)

View File

@@ -811,6 +811,10 @@ static void __netpoll_cleanup(struct netpoll *np)
if (!npinfo) if (!npinfo)
return; return;
/* At this point, there is a single npinfo instance per netdevice, and
* its refcnt tracks how many netpoll structures are linked to it. We
* only perform npinfo cleanup when the refcnt decrements to zero.
*/
if (refcount_dec_and_test(&npinfo->refcnt)) { if (refcount_dec_and_test(&npinfo->refcnt)) {
const struct net_device_ops *ops; const struct net_device_ops *ops;
@@ -820,8 +824,7 @@ static void __netpoll_cleanup(struct netpoll *np)
RCU_INIT_POINTER(np->dev->npinfo, NULL); RCU_INIT_POINTER(np->dev->npinfo, NULL);
call_rcu(&npinfo->rcu, rcu_cleanup_netpoll_info); call_rcu(&npinfo->rcu, rcu_cleanup_netpoll_info);
} else }
RCU_INIT_POINTER(np->dev->npinfo, NULL);
skb_pool_flush(np); skb_pool_flush(np);
} }

View File

@@ -176,7 +176,8 @@ static struct sk_buff *brcm_tag_rcv_ll(struct sk_buff *skb,
/* Remove Broadcom tag and update checksum */ /* Remove Broadcom tag and update checksum */
skb_pull_rcsum(skb, BRCM_TAG_LEN); skb_pull_rcsum(skb, BRCM_TAG_LEN);
dsa_default_offload_fwd_mark(skb); if (likely(!is_link_local_ether_addr(eth_hdr(skb)->h_dest)))
dsa_default_offload_fwd_mark(skb);
return skb; return skb;
} }
@@ -250,7 +251,8 @@ static struct sk_buff *brcm_leg_tag_rcv(struct sk_buff *skb,
/* Remove Broadcom tag and update checksum */ /* Remove Broadcom tag and update checksum */
skb_pull_rcsum(skb, len); skb_pull_rcsum(skb, len);
dsa_default_offload_fwd_mark(skb); if (likely(!is_link_local_ether_addr(eth_hdr(skb)->h_dest)))
dsa_default_offload_fwd_mark(skb);
dsa_strip_etype_header(skb, len); dsa_strip_etype_header(skb, len);

View File

@@ -259,6 +259,7 @@ static int tls_handshake_accept(struct handshake_req *req,
out_cancel: out_cancel:
genlmsg_cancel(msg, hdr); genlmsg_cancel(msg, hdr);
nlmsg_free(msg);
out: out:
return ret; return ret;
} }

View File

@@ -320,6 +320,9 @@ static void send_hsr_supervision_frame(struct hsr_port *port,
} }
hsr_stag = skb_put(skb, sizeof(struct hsr_sup_tag)); hsr_stag = skb_put(skb, sizeof(struct hsr_sup_tag));
skb_set_network_header(skb, ETH_HLEN + HSR_HLEN);
skb_reset_mac_len(skb);
set_hsr_stag_path(hsr_stag, (hsr->prot_version ? 0x0 : 0xf)); set_hsr_stag_path(hsr_stag, (hsr->prot_version ? 0x0 : 0xf));
set_hsr_stag_HSR_ver(hsr_stag, hsr->prot_version); set_hsr_stag_HSR_ver(hsr_stag, hsr->prot_version);
@@ -334,7 +337,7 @@ static void send_hsr_supervision_frame(struct hsr_port *port,
} }
hsr_stag->tlv.HSR_TLV_type = type; hsr_stag->tlv.HSR_TLV_type = type;
/* TODO: Why 12 in HSRv0? */ /* HSRv0 has 6 unused bytes after the MAC */
hsr_stag->tlv.HSR_TLV_length = hsr->prot_version ? hsr_stag->tlv.HSR_TLV_length = hsr->prot_version ?
sizeof(struct hsr_sup_payload) : 12; sizeof(struct hsr_sup_payload) : 12;

View File

@@ -262,15 +262,23 @@ static struct sk_buff *prp_fill_rct(struct sk_buff *skb,
return skb; return skb;
} }
static void hsr_set_path_id(struct hsr_ethhdr *hsr_ethhdr, static void hsr_set_path_id(struct hsr_frame_info *frame,
struct hsr_ethhdr *hsr_ethhdr,
struct hsr_port *port) struct hsr_port *port)
{ {
int path_id; int path_id;
if (port->type == HSR_PT_SLAVE_A) if (port->hsr->prot_version) {
path_id = 0; if (port->type == HSR_PT_SLAVE_A)
else path_id = 0;
path_id = 1; else
path_id = 1;
} else {
if (frame->is_supervision)
path_id = 0xf;
else
path_id = 1;
}
set_hsr_tag_path(&hsr_ethhdr->hsr_tag, path_id); set_hsr_tag_path(&hsr_ethhdr->hsr_tag, path_id);
} }
@@ -304,7 +312,7 @@ static struct sk_buff *hsr_fill_tag(struct sk_buff *skb,
else else
hsr_ethhdr = (struct hsr_ethhdr *)pc; hsr_ethhdr = (struct hsr_ethhdr *)pc;
hsr_set_path_id(hsr_ethhdr, port); hsr_set_path_id(frame, hsr_ethhdr, port);
set_hsr_tag_LSDU_size(&hsr_ethhdr->hsr_tag, lsdu_size); set_hsr_tag_LSDU_size(&hsr_ethhdr->hsr_tag, lsdu_size);
hsr_ethhdr->hsr_tag.sequence_nr = htons(frame->sequence_nr); hsr_ethhdr->hsr_tag.sequence_nr = htons(frame->sequence_nr);
hsr_ethhdr->hsr_tag.encap_proto = hsr_ethhdr->ethhdr.h_proto; hsr_ethhdr->hsr_tag.encap_proto = hsr_ethhdr->ethhdr.h_proto;
@@ -330,7 +338,7 @@ struct sk_buff *hsr_create_tagged_frame(struct hsr_frame_info *frame,
(struct hsr_ethhdr *)skb_mac_header(frame->skb_hsr); (struct hsr_ethhdr *)skb_mac_header(frame->skb_hsr);
/* set the lane id properly */ /* set the lane id properly */
hsr_set_path_id(hsr_ethhdr, port); hsr_set_path_id(frame, hsr_ethhdr, port);
return skb_clone(frame->skb_hsr, GFP_ATOMIC); return skb_clone(frame->skb_hsr, GFP_ATOMIC);
} else if (port->dev->features & NETIF_F_HW_HSR_TAG_INS) { } else if (port->dev->features & NETIF_F_HW_HSR_TAG_INS) {
return skb_clone(frame->skb_std, GFP_ATOMIC); return skb_clone(frame->skb_std, GFP_ATOMIC);

View File

@@ -607,6 +607,11 @@ static void fnhe_remove_oldest(struct fnhe_hash_bucket *hash)
oldest_p = fnhe_p; oldest_p = fnhe_p;
} }
} }
/* Clear oldest->fnhe_daddr to prevent this fnhe from being
* rebound with new dsts in rt_bind_exception().
*/
oldest->fnhe_daddr = 0;
fnhe_flush_routes(oldest); fnhe_flush_routes(oldest);
*oldest_p = oldest->fnhe_next; *oldest_p = oldest->fnhe_next;
kfree_rcu(oldest, rcu); kfree_rcu(oldest, rcu);

View File

@@ -223,6 +223,10 @@ static int ieee80211_can_powered_addr_change(struct ieee80211_sub_if_data *sdata
if (netif_carrier_ok(sdata->dev)) if (netif_carrier_ok(sdata->dev))
return -EBUSY; return -EBUSY;
/* if any stations are set known (so they know this vif too), reject */
if (sta_info_get_by_idx(sdata, 0))
return -EBUSY;
/* First check no ROC work is happening on this iface */ /* First check no ROC work is happening on this iface */
list_for_each_entry(roc, &local->roc_list, list) { list_for_each_entry(roc, &local->roc_list, list) {
if (roc->sdata != sdata) if (roc->sdata != sdata)
@@ -242,12 +246,16 @@ static int ieee80211_can_powered_addr_change(struct ieee80211_sub_if_data *sdata
ret = -EBUSY; ret = -EBUSY;
} }
/*
* More interface types could be added here but changing the
* address while powered makes the most sense in client modes.
*/
switch (sdata->vif.type) { switch (sdata->vif.type) {
case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_P2P_CLIENT:
/* More interface types could be added here but changing the /* refuse while connecting */
* address while powered makes the most sense in client modes. if (sdata->u.mgd.auth_data || sdata->u.mgd.assoc_data)
*/ return -EBUSY;
break; break;
default: default:
ret = -EOPNOTSUPP; ret = -EOPNOTSUPP;

View File

@@ -5360,10 +5360,14 @@ void ieee80211_rx_list(struct ieee80211_hw *hw, struct ieee80211_sta *pubsta,
if (WARN_ON(!local->started)) if (WARN_ON(!local->started))
goto drop; goto drop;
if (likely(!(status->flag & RX_FLAG_FAILED_PLCP_CRC))) { if (likely(!(status->flag & RX_FLAG_FAILED_PLCP_CRC) &&
!(status->flag & RX_FLAG_NO_PSDU &&
status->zero_length_psdu_type ==
IEEE80211_RADIOTAP_ZERO_LEN_PSDU_NOT_CAPTURED))) {
/* /*
* Validate the rate, unless a PLCP error means that * Validate the rate, unless there was a PLCP error which may
* we probably can't have a valid rate here anyway. * have an invalid rate or the PSDU was not capture and may be
* missing rate information.
*/ */
switch (status->encoding) { switch (status->encoding) {

View File

@@ -195,13 +195,15 @@ static inline int tcf_connmark_dump(struct sk_buff *skb, struct tc_action *a,
const struct tcf_connmark_info *ci = to_connmark(a); const struct tcf_connmark_info *ci = to_connmark(a);
unsigned char *b = skb_tail_pointer(skb); unsigned char *b = skb_tail_pointer(skb);
const struct tcf_connmark_parms *parms; const struct tcf_connmark_parms *parms;
struct tc_connmark opt = { struct tc_connmark opt;
.index = ci->tcf_index,
.refcnt = refcount_read(&ci->tcf_refcnt) - ref,
.bindcnt = atomic_read(&ci->tcf_bindcnt) - bind,
};
struct tcf_t t; struct tcf_t t;
memset(&opt, 0, sizeof(opt));
opt.index = ci->tcf_index;
opt.refcnt = refcount_read(&ci->tcf_refcnt) - ref;
opt.bindcnt = atomic_read(&ci->tcf_bindcnt) - bind;
rcu_read_lock(); rcu_read_lock();
parms = rcu_dereference(ci->parms); parms = rcu_dereference(ci->parms);

View File

@@ -644,13 +644,15 @@ static int tcf_ife_dump(struct sk_buff *skb, struct tc_action *a, int bind,
unsigned char *b = skb_tail_pointer(skb); unsigned char *b = skb_tail_pointer(skb);
struct tcf_ife_info *ife = to_ife(a); struct tcf_ife_info *ife = to_ife(a);
struct tcf_ife_params *p; struct tcf_ife_params *p;
struct tc_ife opt = { struct tc_ife opt;
.index = ife->tcf_index,
.refcnt = refcount_read(&ife->tcf_refcnt) - ref,
.bindcnt = atomic_read(&ife->tcf_bindcnt) - bind,
};
struct tcf_t t; struct tcf_t t;
memset(&opt, 0, sizeof(opt));
opt.index = ife->tcf_index,
opt.refcnt = refcount_read(&ife->tcf_refcnt) - ref,
opt.bindcnt = atomic_read(&ife->tcf_bindcnt) - bind,
spin_lock_bh(&ife->tcf_lock); spin_lock_bh(&ife->tcf_lock);
opt.action = ife->tcf_action; opt.action = ife->tcf_action;
p = rcu_dereference_protected(ife->params, p = rcu_dereference_protected(ife->params,

View File

@@ -1599,6 +1599,11 @@ static int __tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n,
NL_SET_ERR_MSG(extack, "Failed to find specified qdisc"); NL_SET_ERR_MSG(extack, "Failed to find specified qdisc");
return -ENOENT; return -ENOENT;
} }
if (p->flags & TCQ_F_INGRESS) {
NL_SET_ERR_MSG(extack,
"Cannot add children to ingress/clsact qdisc");
return -EOPNOTSUPP;
}
q = qdisc_leaf(p, clid, extack); q = qdisc_leaf(p, clid, extack);
if (IS_ERR(q)) if (IS_ERR(q))
return PTR_ERR(q); return PTR_ERR(q);

View File

@@ -180,9 +180,10 @@ static inline void dev_requeue_skb(struct sk_buff *skb, struct Qdisc *q)
static void try_bulk_dequeue_skb(struct Qdisc *q, static void try_bulk_dequeue_skb(struct Qdisc *q,
struct sk_buff *skb, struct sk_buff *skb,
const struct netdev_queue *txq, const struct netdev_queue *txq,
int *packets) int *packets, int budget)
{ {
int bytelimit = qdisc_avail_bulklimit(txq) - skb->len; int bytelimit = qdisc_avail_bulklimit(txq) - skb->len;
int cnt = 0;
while (bytelimit > 0) { while (bytelimit > 0) {
struct sk_buff *nskb = q->dequeue(q); struct sk_buff *nskb = q->dequeue(q);
@@ -193,8 +194,10 @@ static void try_bulk_dequeue_skb(struct Qdisc *q,
bytelimit -= nskb->len; /* covers GSO len */ bytelimit -= nskb->len; /* covers GSO len */
skb->next = nskb; skb->next = nskb;
skb = nskb; skb = nskb;
(*packets)++; /* GSO counts as one pkt */ if (++cnt >= budget)
break;
} }
(*packets) += cnt;
skb_mark_not_on_list(skb); skb_mark_not_on_list(skb);
} }
@@ -228,7 +231,7 @@ static void try_bulk_dequeue_skb_slow(struct Qdisc *q,
* A requeued skb (via q->gso_skb) can also be a SKB list. * A requeued skb (via q->gso_skb) can also be a SKB list.
*/ */
static struct sk_buff *dequeue_skb(struct Qdisc *q, bool *validate, static struct sk_buff *dequeue_skb(struct Qdisc *q, bool *validate,
int *packets) int *packets, int budget)
{ {
const struct netdev_queue *txq = q->dev_queue; const struct netdev_queue *txq = q->dev_queue;
struct sk_buff *skb = NULL; struct sk_buff *skb = NULL;
@@ -295,7 +298,7 @@ validate:
if (skb) { if (skb) {
bulk: bulk:
if (qdisc_may_bulk(q)) if (qdisc_may_bulk(q))
try_bulk_dequeue_skb(q, skb, txq, packets); try_bulk_dequeue_skb(q, skb, txq, packets, budget);
else else
try_bulk_dequeue_skb_slow(q, skb, packets); try_bulk_dequeue_skb_slow(q, skb, packets);
} }
@@ -387,7 +390,7 @@ bool sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q,
* >0 - queue is not empty. * >0 - queue is not empty.
* *
*/ */
static inline bool qdisc_restart(struct Qdisc *q, int *packets) static inline bool qdisc_restart(struct Qdisc *q, int *packets, int budget)
{ {
spinlock_t *root_lock = NULL; spinlock_t *root_lock = NULL;
struct netdev_queue *txq; struct netdev_queue *txq;
@@ -396,7 +399,7 @@ static inline bool qdisc_restart(struct Qdisc *q, int *packets)
bool validate; bool validate;
/* Dequeue packet */ /* Dequeue packet */
skb = dequeue_skb(q, &validate, packets); skb = dequeue_skb(q, &validate, packets, budget);
if (unlikely(!skb)) if (unlikely(!skb))
return false; return false;
@@ -414,7 +417,7 @@ void __qdisc_run(struct Qdisc *q)
int quota = READ_ONCE(net_hotdata.dev_tx_weight); int quota = READ_ONCE(net_hotdata.dev_tx_weight);
int packets; int packets;
while (qdisc_restart(q, &packets)) { while (qdisc_restart(q, &packets, quota)) {
quota -= packets; quota -= packets;
if (quota <= 0) { if (quota <= 0) {
if (q->flags & TCQ_F_NOLOCK) if (q->flags & TCQ_F_NOLOCK)

View File

@@ -486,6 +486,7 @@ void sctp_transport_update_rto(struct sctp_transport *tp, __u32 rtt)
if (tp->rttvar || tp->srtt) { if (tp->rttvar || tp->srtt) {
struct net *net = tp->asoc->base.net; struct net *net = tp->asoc->base.net;
unsigned int rto_beta, rto_alpha;
/* 6.3.1 C3) When a new RTT measurement R' is made, set /* 6.3.1 C3) When a new RTT measurement R' is made, set
* RTTVAR <- (1 - RTO.Beta) * RTTVAR + RTO.Beta * |SRTT - R'| * RTTVAR <- (1 - RTO.Beta) * RTTVAR + RTO.Beta * |SRTT - R'|
* SRTT <- (1 - RTO.Alpha) * SRTT + RTO.Alpha * R' * SRTT <- (1 - RTO.Alpha) * SRTT + RTO.Alpha * R'
@@ -497,10 +498,14 @@ void sctp_transport_update_rto(struct sctp_transport *tp, __u32 rtt)
* For example, assuming the default value of RTO.Alpha of * For example, assuming the default value of RTO.Alpha of
* 1/8, rto_alpha would be expressed as 3. * 1/8, rto_alpha would be expressed as 3.
*/ */
tp->rttvar = tp->rttvar - (tp->rttvar >> net->sctp.rto_beta) rto_beta = READ_ONCE(net->sctp.rto_beta);
+ (((__u32)abs((__s64)tp->srtt - (__s64)rtt)) >> net->sctp.rto_beta); if (rto_beta < 32)
tp->srtt = tp->srtt - (tp->srtt >> net->sctp.rto_alpha) tp->rttvar = tp->rttvar - (tp->rttvar >> rto_beta)
+ (rtt >> net->sctp.rto_alpha); + (((__u32)abs((__s64)tp->srtt - (__s64)rtt)) >> rto_beta);
rto_alpha = READ_ONCE(net->sctp.rto_alpha);
if (rto_alpha < 32)
tp->srtt = tp->srtt - (tp->srtt >> rto_alpha)
+ (rtt >> rto_alpha);
} else { } else {
/* 6.3.1 C2) When the first RTT measurement R is made, set /* 6.3.1 C2) When the first RTT measurement R is made, set
* SRTT <- R, RTTVAR <- R/2. * SRTT <- R, RTTVAR <- R/2.

View File

@@ -890,6 +890,7 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini)
return SMC_CLC_DECL_CNFERR; return SMC_CLC_DECL_CNFERR;
} }
pclc_base->hdr.typev1 = SMC_TYPE_N; pclc_base->hdr.typev1 = SMC_TYPE_N;
ini->smc_type_v1 = SMC_TYPE_N;
} else { } else {
pclc_base->iparea_offset = htons(sizeof(*pclc_smcd)); pclc_base->iparea_offset = htons(sizeof(*pclc_smcd));
plen += sizeof(*pclc_prfx) + plen += sizeof(*pclc_prfx) +

View File

@@ -238,7 +238,7 @@ static int __strp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb,
strp_parser_err(strp, -EMSGSIZE, desc); strp_parser_err(strp, -EMSGSIZE, desc);
break; break;
} else if (len <= (ssize_t)head->len - } else if (len <= (ssize_t)head->len -
skb->len - stm->strp.offset) { (ssize_t)skb->len - stm->strp.offset) {
/* Length must be into new skb (and also /* Length must be into new skb (and also
* greater than zero) * greater than zero)
*/ */

View File

@@ -145,7 +145,9 @@ void tipc_net_finalize_work(struct work_struct *work)
{ {
struct tipc_net *tn = container_of(work, struct tipc_net, work); struct tipc_net *tn = container_of(work, struct tipc_net, work);
rtnl_lock();
tipc_net_finalize(tipc_link_net(tn->bcl), tn->trial_addr); tipc_net_finalize(tipc_link_net(tn->bcl), tn->trial_addr);
rtnl_unlock();
} }
void tipc_net_stop(struct net *net) void tipc_net_stop(struct net *net)

View File

@@ -145,6 +145,7 @@ enum unix_vertex_index {
}; };
static unsigned long unix_vertex_unvisited_index = UNIX_VERTEX_INDEX_MARK1; static unsigned long unix_vertex_unvisited_index = UNIX_VERTEX_INDEX_MARK1;
static unsigned long unix_vertex_max_scc_index = UNIX_VERTEX_INDEX_START;
static void unix_add_edge(struct scm_fp_list *fpl, struct unix_edge *edge) static void unix_add_edge(struct scm_fp_list *fpl, struct unix_edge *edge)
{ {
@@ -153,6 +154,7 @@ static void unix_add_edge(struct scm_fp_list *fpl, struct unix_edge *edge)
if (!vertex) { if (!vertex) {
vertex = list_first_entry(&fpl->vertices, typeof(*vertex), entry); vertex = list_first_entry(&fpl->vertices, typeof(*vertex), entry);
vertex->index = unix_vertex_unvisited_index; vertex->index = unix_vertex_unvisited_index;
vertex->scc_index = ++unix_vertex_max_scc_index;
vertex->out_degree = 0; vertex->out_degree = 0;
INIT_LIST_HEAD(&vertex->edges); INIT_LIST_HEAD(&vertex->edges);
INIT_LIST_HEAD(&vertex->scc_entry); INIT_LIST_HEAD(&vertex->scc_entry);
@@ -489,10 +491,15 @@ prev_vertex:
scc_dead = unix_vertex_dead(v); scc_dead = unix_vertex_dead(v);
} }
if (scc_dead) if (scc_dead) {
unix_collect_skb(&scc, hitlist); unix_collect_skb(&scc, hitlist);
else if (!unix_graph_maybe_cyclic) } else {
unix_graph_maybe_cyclic = unix_scc_cyclic(&scc); if (unix_vertex_max_scc_index < vertex->scc_index)
unix_vertex_max_scc_index = vertex->scc_index;
if (!unix_graph_maybe_cyclic)
unix_graph_maybe_cyclic = unix_scc_cyclic(&scc);
}
list_del(&scc); list_del(&scc);
} }
@@ -507,6 +514,7 @@ static void unix_walk_scc(struct sk_buff_head *hitlist)
unsigned long last_index = UNIX_VERTEX_INDEX_START; unsigned long last_index = UNIX_VERTEX_INDEX_START;
unix_graph_maybe_cyclic = false; unix_graph_maybe_cyclic = false;
unix_vertex_max_scc_index = UNIX_VERTEX_INDEX_START;
/* Visit every vertex exactly once. /* Visit every vertex exactly once.
* __unix_walk_scc() moves visited vertices to unix_visited_vertices. * __unix_walk_scc() moves visited vertices to unix_visited_vertices.

View File

@@ -861,6 +861,18 @@ class TypeIndexedArray(Type):
return [f"{member} = {self.c_name};", return [f"{member} = {self.c_name};",
f"{presence} = n_{self.c_name};"] f"{presence} = n_{self.c_name};"]
def free_needs_iter(self):
return self.sub_type == 'nest'
def _free_lines(self, ri, var, ref):
lines = []
if self.sub_type == 'nest':
lines += [
f"for (i = 0; i < {var}->{ref}_count.{self.c_name}; i++)",
f'{self.nested_render_name}_free(&{var}->{ref}{self.c_name}[i]);',
]
lines += f"free({var}->{ref}{self.c_name});",
return lines
class TypeNestTypeValue(Type): class TypeNestTypeValue(Type):
def _complex_member_type(self, ri): def _complex_member_type(self, ri):

View File

@@ -18,6 +18,7 @@ TEST_PROGS := \
netcons_fragmented_msg.sh \ netcons_fragmented_msg.sh \
netcons_overflow.sh \ netcons_overflow.sh \
netcons_sysdata.sh \ netcons_sysdata.sh \
netcons_torture.sh \
netpoll_basic.py \ netpoll_basic.py \
ping.py \ ping.py \
psp.py \ psp.py \

View File

@@ -14,6 +14,7 @@ TEST_PROGS := \
dev_addr_lists.sh \ dev_addr_lists.sh \
mode-1-recovery-updelay.sh \ mode-1-recovery-updelay.sh \
mode-2-recovery-updelay.sh \ mode-2-recovery-updelay.sh \
netcons_over_bonding.sh \
# end of TEST_PROGS # end of TEST_PROGS
TEST_FILES := \ TEST_FILES := \
@@ -24,6 +25,7 @@ TEST_FILES := \
TEST_INCLUDES := \ TEST_INCLUDES := \
../../../net/lib.sh \ ../../../net/lib.sh \
../lib/sh/lib_netcons.sh \
../../../net/forwarding/lib.sh \ ../../../net/forwarding/lib.sh \
# end of TEST_INCLUDES # end of TEST_INCLUDES

View File

@@ -1,5 +1,6 @@
CONFIG_BONDING=y CONFIG_BONDING=y
CONFIG_BRIDGE=y CONFIG_BRIDGE=y
CONFIG_CONFIGFS_FS=y
CONFIG_DUMMY=y CONFIG_DUMMY=y
CONFIG_INET_ESP=y CONFIG_INET_ESP=y
CONFIG_INET_ESP_OFFLOAD=y CONFIG_INET_ESP_OFFLOAD=y
@@ -9,6 +10,9 @@ CONFIG_MACVLAN=y
CONFIG_NET_ACT_GACT=y CONFIG_NET_ACT_GACT=y
CONFIG_NET_CLS_FLOWER=y CONFIG_NET_CLS_FLOWER=y
CONFIG_NET_CLS_MATCHALL=m CONFIG_NET_CLS_MATCHALL=m
CONFIG_NETCONSOLE=m
CONFIG_NETCONSOLE_DYNAMIC=y
CONFIG_NETCONSOLE_EXTENDED_LOG=y
CONFIG_NETDEVSIM=m CONFIG_NETDEVSIM=m
CONFIG_NET_SCH_INGRESS=y CONFIG_NET_SCH_INGRESS=y
CONFIG_NLMON=y CONFIG_NLMON=y

View File

@@ -0,0 +1,361 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: GPL-2.0
#
# This selftest exercises trying to have multiple netpoll users at the same
# time.
#
# This selftest has multiple smalls test inside, and the goal is to
# get interfaces with bonding and netconsole in different orders in order
# to catch any possible issue.
#
# The main test composes of four interfaces being created using netdevsim; two
# of them are bonded to serve as the netconsole's transmit interface. The
# remaining two interfaces are similarly bonded and assigned to a separate
# network namespace, which acts as the receive interface, where socat monitors
# for incoming messages.
#
# A netconsole message is then sent to ensure it is properly received across
# this configuration.
#
# Later, run a few other tests, to make sure that bonding and netconsole
# cannot coexist.
#
# The test's objective is to exercise netpoll usage when managed simultaneously
# by multiple subsystems (netconsole and bonding).
#
# Author: Breno Leitao <leitao@debian.org>
set -euo pipefail
SCRIPTDIR=$(dirname "$(readlink -e "${BASH_SOURCE[0]}")")
source "${SCRIPTDIR}"/../lib/sh/lib_netcons.sh
modprobe netdevsim 2> /dev/null || true
modprobe netconsole 2> /dev/null || true
modprobe bonding 2> /dev/null || true
modprobe veth 2> /dev/null || true
# The content of kmsg will be save to the following file
OUTPUT_FILE="/tmp/${TARGET}"
# Check for basic system dependency and exit if not found
check_for_dependencies
# Set current loglevel to KERN_INFO(6), and default to KERN_NOTICE(5)
echo "6 5" > /proc/sys/kernel/printk
# Remove the namespace, interfaces and netconsole target on exit
trap cleanup_bond EXIT
FORMAT="extended"
IP_VERSION="ipv4"
VETH0="veth"$(( RANDOM % 256))
VETH1="veth"$((256 + RANDOM % 256))
TXNS=""
RXNS=""
# Create "bond_tx_XX" and "bond_rx_XX" interfaces, and set DSTIF and SRCIF with
# the bonding interfaces
function setup_bonding_ifaces() {
local RAND=$(( RANDOM % 100 ))
BOND_TX_MAIN_IF="bond_tx_$RAND"
BOND_RX_MAIN_IF="bond_rx_$RAND"
# Setup TX
if ! ip -n "${TXNS}" link add "${BOND_TX_MAIN_IF}" type bond mode balance-rr
then
echo "Failed to create bond TX interface. Is CONFIG_BONDING set?" >&2
# only clean nsim ifaces and namespace. Nothing else has been
# initialized
cleanup_bond_nsim
trap - EXIT
exit "${ksft_skip}"
fi
# create_netdevsim() got the interface up, but it needs to be down
# before being enslaved.
ip -n "${TXNS}" \
link set "${BOND_TX1_SLAVE_IF}" down
ip -n "${TXNS}" \
link set "${BOND_TX2_SLAVE_IF}" down
ip -n "${TXNS}" \
link set "${BOND_TX1_SLAVE_IF}" master "${BOND_TX_MAIN_IF}"
ip -n "${TXNS}" \
link set "${BOND_TX2_SLAVE_IF}" master "${BOND_TX_MAIN_IF}"
ip -n "${TXNS}" \
link set "${BOND_TX_MAIN_IF}" up
# Setup RX
ip -n "${RXNS}" \
link add "${BOND_RX_MAIN_IF}" type bond mode balance-rr
ip -n "${RXNS}" \
link set "${BOND_RX1_SLAVE_IF}" down
ip -n "${RXNS}" \
link set "${BOND_RX2_SLAVE_IF}" down
ip -n "${RXNS}" \
link set "${BOND_RX1_SLAVE_IF}" master "${BOND_RX_MAIN_IF}"
ip -n "${RXNS}" \
link set "${BOND_RX2_SLAVE_IF}" master "${BOND_RX_MAIN_IF}"
ip -n "${RXNS}" \
link set "${BOND_RX_MAIN_IF}" up
export DSTIF="${BOND_RX_MAIN_IF}"
export SRCIF="${BOND_TX_MAIN_IF}"
}
# Create 4 netdevsim interfaces. Two of them will be bound to TX bonding iface
# and the other two will be bond to the RX interface (on the other namespace)
function create_ifaces_bond() {
BOND_TX1_SLAVE_IF=$(create_netdevsim "${NSIM_BOND_TX_1}" "${TXNS}")
BOND_TX2_SLAVE_IF=$(create_netdevsim "${NSIM_BOND_TX_2}" "${TXNS}")
BOND_RX1_SLAVE_IF=$(create_netdevsim "${NSIM_BOND_RX_1}" "${RXNS}")
BOND_RX2_SLAVE_IF=$(create_netdevsim "${NSIM_BOND_RX_2}" "${RXNS}")
}
# netdevsim link BOND_TX to BOND_RX interfaces
function link_ifaces_bond() {
local BOND_TX1_SLAVE_IFIDX
local BOND_TX2_SLAVE_IFIDX
local BOND_RX1_SLAVE_IFIDX
local BOND_RX2_SLAVE_IFIDX
local TXNS_FD
local RXNS_FD
BOND_TX1_SLAVE_IFIDX=$(ip netns exec "${TXNS}" \
cat /sys/class/net/"$BOND_TX1_SLAVE_IF"/ifindex)
BOND_TX2_SLAVE_IFIDX=$(ip netns exec "${TXNS}" \
cat /sys/class/net/"$BOND_TX2_SLAVE_IF"/ifindex)
BOND_RX1_SLAVE_IFIDX=$(ip netns exec "${RXNS}" \
cat /sys/class/net/"$BOND_RX1_SLAVE_IF"/ifindex)
BOND_RX2_SLAVE_IFIDX=$(ip netns exec "${RXNS}" \
cat /sys/class/net/"$BOND_RX2_SLAVE_IF"/ifindex)
exec {TXNS_FD}</var/run/netns/"${TXNS}"
exec {RXNS_FD}</var/run/netns/"${RXNS}"
# Linking TX ifaces to the RX ones (on the other namespace)
echo "${TXNS_FD}:$BOND_TX1_SLAVE_IFIDX $RXNS_FD:$BOND_RX1_SLAVE_IFIDX" \
> "$NSIM_DEV_SYS_LINK"
echo "${TXNS_FD}:$BOND_TX2_SLAVE_IFIDX $RXNS_FD:$BOND_RX2_SLAVE_IFIDX" \
> "$NSIM_DEV_SYS_LINK"
exec {TXNS_FD}<&-
exec {RXNS_FD}<&-
}
function create_all_ifaces() {
# setup_ns function is coming from lib.sh
setup_ns TXNS RXNS
export NAMESPACE="${RXNS}"
# Create two interfaces for RX and two for TX
create_ifaces_bond
# Link netlink ifaces
link_ifaces_bond
}
# configure DSTIF and SRCIF IPs
function configure_ifaces_ips() {
local IP_VERSION=${1:-"ipv4"}
select_ipv4_or_ipv6 "${IP_VERSION}"
ip -n "${RXNS}" addr add "${DSTIP}"/24 dev "${DSTIF}"
ip -n "${RXNS}" link set "${DSTIF}" up
ip -n "${TXNS}" addr add "${SRCIP}"/24 dev "${SRCIF}"
ip -n "${TXNS}" link set "${SRCIF}" up
}
function test_enable_netpoll_on_enslaved_iface() {
echo 0 > "${NETCONS_PATH}"/enabled
# At this stage, BOND_TX1_SLAVE_IF is enslaved to BOND_TX_MAIN_IF, and
# linked to BOND_RX1_SLAVE_IF inside the namespace.
echo "${BOND_TX1_SLAVE_IF}" > "${NETCONS_PATH}"/dev_name
# This should fail with the following message in dmesg:
# netpoll: netconsole: ethX is a slave device, aborting
set +e
enable_netcons_ns 2> /dev/null
set -e
if [[ $(cat "${NETCONS_PATH}"/enabled) -eq 1 ]]
then
echo "test failed: Bonding and netpoll cannot co-exists." >&2
exit "${ksft_fail}"
fi
}
function test_delete_bond_and_reenable_target() {
ip -n "${TXNS}" \
link delete "${BOND_TX_MAIN_IF}" type bond
# BOND_TX1_SLAVE_IF is not attached to a bond interface anymore
# netpoll can be plugged in there
echo "${BOND_TX1_SLAVE_IF}" > "${NETCONS_PATH}"/dev_name
# this should work, since the interface is not enslaved
enable_netcons_ns
if [[ $(cat "${NETCONS_PATH}"/enabled) -eq 0 ]]
then
echo "test failed: Unable to start netpoll on an unbond iface." >&2
exit "${ksft_fail}"
fi
}
# Send a netconsole message to the netconsole target
function test_send_netcons_msg_through_bond_iface() {
# Listen for netconsole port inside the namespace and
# destination interface
listen_port_and_save_to "${OUTPUT_FILE}" "${IP_VERSION}" &
# Wait for socat to start and listen to the port.
wait_for_port "${RXNS}" "${PORT}" "${IP_VERSION}"
# Send the message
echo "${MSG}: ${TARGET}" > /dev/kmsg
# Wait until socat saves the file to disk
busywait "${BUSYWAIT_TIMEOUT}" test -s "${OUTPUT_FILE}"
# Make sure the message was received in the dst part
# and exit
validate_result "${OUTPUT_FILE}" "${FORMAT}"
# kill socat in case it is still running
pkill_socat
}
# BOND_TX1_SLAVE_IF has netconsole enabled on it, bind it to BOND_TX_MAIN_IF.
# Given BOND_TX_MAIN_IF was deleted, recreate it first
function test_enslave_netcons_enabled_iface {
# netconsole got disabled while the interface was down
if [[ $(cat "${NETCONS_PATH}"/enabled) -eq 0 ]]
then
echo "test failed: netconsole expected to be enabled against BOND_TX1_SLAVE_IF" >&2
exit "${ksft_fail}"
fi
# recreate the bonding iface. it got deleted by previous
# test (test_delete_bond_and_reenable_target)
ip -n "${TXNS}" \
link add "${BOND_TX_MAIN_IF}" type bond mode balance-rr
# sub-interface need to be down before attaching to bonding
# This will also disable netconsole.
ip -n "${TXNS}" \
link set "${BOND_TX1_SLAVE_IF}" down
ip -n "${TXNS}" \
link set "${BOND_TX1_SLAVE_IF}" master "${BOND_TX_MAIN_IF}"
ip -n "${TXNS}" \
link set "${BOND_TX_MAIN_IF}" up
# netconsole got disabled while the interface was down
if [[ $(cat "${NETCONS_PATH}"/enabled) -eq 1 ]]
then
echo "test failed: Device is part of a bond iface, cannot have netcons enabled" >&2
exit "${ksft_fail}"
fi
}
# Get netconsole enabled on a bonding interface and attach a second
# sub-interface.
function test_enslave_iface_to_bond {
# BOND_TX_MAIN_IF has only BOND_TX1_SLAVE_IF right now
echo "${BOND_TX_MAIN_IF}" > "${NETCONS_PATH}"/dev_name
enable_netcons_ns
# netcons is attached to bond0 and BOND_TX1_SLAVE_IF is
# part of BOND_TX_MAIN_IF. Attach BOND_TX2_SLAVE_IF to BOND_TX_MAIN_IF.
ip -n "${TXNS}" \
link set "${BOND_TX2_SLAVE_IF}" master "${BOND_TX_MAIN_IF}"
if [[ $(cat "${NETCONS_PATH}"/enabled) -eq 0 ]]
then
echo "test failed: Netconsole should be enabled on bonding interface. Failed" >&2
exit "${ksft_fail}"
fi
}
function test_enslave_iff_disabled_netpoll_iface {
local ret
# Create two interfaces. veth interfaces it known to have
# IFF_DISABLE_NETPOLL set
if ! ip link add "${VETH0}" type veth peer name "${VETH1}"
then
echo "Failed to create veth TX interface. Is CONFIG_VETH set?" >&2
exit "${ksft_skip}"
fi
set +e
# This will print RTNETLINK answers: Device or resource busy
ip link set "${VETH0}" master "${BOND_TX_MAIN_IF}" 2> /dev/null
ret=$?
set -e
if [[ $ret -eq 0 ]]
then
echo "test failed: veth interface could not be enslaved"
exit "${ksft_fail}"
fi
}
# Given that netconsole picks the current net namespace, we need to enable it
# from inside the TXNS namespace
function enable_netcons_ns() {
ip netns exec "${TXNS}" sh -c \
"mount -t configfs configfs /sys/kernel/config && echo 1 > $NETCONS_PATH/enabled"
}
####################
# Tests start here #
####################
# Create regular interfaces using netdevsim and link them
create_all_ifaces
# Setup the bonding interfaces
# BOND_RX_MAIN_IF has BOND_RX{1,2}_SLAVE_IF
# BOND_TX_MAIN_IF has BOND_TX{1,2}_SLAVE_IF
setup_bonding_ifaces
# Configure the ips as BOND_RX1_SLAVE_IF and BOND_TX1_SLAVE_IF
configure_ifaces_ips "${IP_VERSION}"
_create_dynamic_target "${FORMAT}" "${NETCONS_PATH}"
enable_netcons_ns
set_user_data
# Test #1 : Create an bonding interface and attach netpoll into
# the bonding interface. Netconsole/netpoll should work on
# the bonding interface.
test_send_netcons_msg_through_bond_iface
echo "test #1: netpoll on bonding interface worked. Test passed" >&2
# Test #2: Attach netpoll to an enslaved interface
# Try to attach netpoll to an enslaved sub-interface (while still being part of
# a bonding interface), which shouldn't be allowed
test_enable_netpoll_on_enslaved_iface
echo "test #2: netpoll correctly rejected enslaved interface (expected behavior). Test passed." >&2
# Test #3: Unplug the sub-interface from bond and enable netconsole
# Detach the interface from a bonding interface and attach netpoll again
test_delete_bond_and_reenable_target
echo "test #3: Able to attach to an unbound interface. Test passed." >&2
# Test #4: Enslave a sub-interface that had netconsole enabled
# Try to enslave an interface that has netconsole/netpoll enabled.
# Previous test has netconsole enabled in BOND_TX1_SLAVE_IF, try to enslave it
test_enslave_netcons_enabled_iface
echo "test #4: Enslaving an interface with netpoll attached. Test passed." >&2
# Test #5: Enslave a sub-interface to a bonding interface
# Enslave an interface to a bond interface that has netpoll attached
# At this stage, BOND_TX_MAIN_IF is created and BOND_TX1_SLAVE_IF is part of
# it. Netconsole is currently disabled
test_enslave_iface_to_bond
echo "test #5: Enslaving an interface to bond+netpoll. Test passed." >&2
# Test #6: Enslave a IFF_DISABLE_NETPOLL sub-interface to a bonding interface
# At this stage, BOND_TX_MAIN_IF has both sub interface and netconsole is
# enabled. This test will try to enslave an a veth (IFF_DISABLE_NETPOLL) interface
# and it should fail, with netpoll: veth0 doesn't support polling
test_enslave_iff_disabled_netpoll_iface
echo "test #6: Enslaving IFF_DISABLE_NETPOLL ifaces to bond iface is not supported. Test passed." >&2
cleanup_bond
trap - EXIT
exit "${EXIT_STATUS}"

View File

@@ -11,9 +11,11 @@ set -euo pipefail
LIBDIR=$(dirname "$(readlink -e "${BASH_SOURCE[0]}")") LIBDIR=$(dirname "$(readlink -e "${BASH_SOURCE[0]}")")
SRCIF="" # to be populated later SRCIF="" # to be populated later
SRCIP="" # to be populated later
SRCIP4="192.0.2.1" SRCIP4="192.0.2.1"
SRCIP6="fc00::1" SRCIP6="fc00::1"
DSTIF="" # to be populated later DSTIF="" # to be populated later
DSTIP="" # to be populated later
DSTIP4="192.0.2.2" DSTIP4="192.0.2.2"
DSTIP6="fc00::2" DSTIP6="fc00::2"
@@ -28,17 +30,23 @@ NETCONS_PATH="${NETCONS_CONFIGFS}"/"${TARGET}"
# NAMESPACE will be populated by setup_ns with a random value # NAMESPACE will be populated by setup_ns with a random value
NAMESPACE="" NAMESPACE=""
# IDs for netdevsim # IDs for netdevsim. We either use NSIM_DEV_{1,2}_ID for standard test
# or NSIM_BOND_{T,R}X_{1,2} for the bonding tests. Not both at the
# same time.
NSIM_DEV_1_ID=$((256 + RANDOM % 256)) NSIM_DEV_1_ID=$((256 + RANDOM % 256))
NSIM_DEV_2_ID=$((512 + RANDOM % 256)) NSIM_DEV_2_ID=$((512 + RANDOM % 256))
NSIM_BOND_TX_1=$((768 + RANDOM % 256))
NSIM_BOND_TX_2=$((1024 + RANDOM % 256))
NSIM_BOND_RX_1=$((1280 + RANDOM % 256))
NSIM_BOND_RX_2=$((1536 + RANDOM % 256))
NSIM_DEV_SYS_NEW="/sys/bus/netdevsim/new_device" NSIM_DEV_SYS_NEW="/sys/bus/netdevsim/new_device"
NSIM_DEV_SYS_LINK="/sys/bus/netdevsim/link_device"
# Used to create and delete namespaces # Used to create and delete namespaces
source "${LIBDIR}"/../../../../net/lib.sh source "${LIBDIR}"/../../../../net/lib.sh
# Create netdevsim interfaces # Create netdevsim interfaces
create_ifaces() { create_ifaces() {
echo "$NSIM_DEV_2_ID" > "$NSIM_DEV_SYS_NEW" echo "$NSIM_DEV_2_ID" > "$NSIM_DEV_SYS_NEW"
echo "$NSIM_DEV_1_ID" > "$NSIM_DEV_SYS_NEW" echo "$NSIM_DEV_1_ID" > "$NSIM_DEV_SYS_NEW"
udevadm settle 2> /dev/null || true udevadm settle 2> /dev/null || true
@@ -113,31 +121,38 @@ function set_network() {
configure_ip configure_ip
} }
function create_dynamic_target() { function _create_dynamic_target() {
local FORMAT=${1:-"extended"} local FORMAT="${1:?FORMAT parameter required}"
local NCPATH="${2:?NCPATH parameter required}"
DSTMAC=$(ip netns exec "${NAMESPACE}" \ DSTMAC=$(ip netns exec "${NAMESPACE}" \
ip link show "${DSTIF}" | awk '/ether/ {print $2}') ip link show "${DSTIF}" | awk '/ether/ {print $2}')
# Create a dynamic target # Create a dynamic target
mkdir "${NETCONS_PATH}" mkdir "${NCPATH}"
echo "${DSTIP}" > "${NETCONS_PATH}"/remote_ip echo "${DSTIP}" > "${NCPATH}"/remote_ip
echo "${SRCIP}" > "${NETCONS_PATH}"/local_ip echo "${SRCIP}" > "${NCPATH}"/local_ip
echo "${DSTMAC}" > "${NETCONS_PATH}"/remote_mac echo "${DSTMAC}" > "${NCPATH}"/remote_mac
echo "${SRCIF}" > "${NETCONS_PATH}"/dev_name echo "${SRCIF}" > "${NCPATH}"/dev_name
if [ "${FORMAT}" == "basic" ] if [ "${FORMAT}" == "basic" ]
then then
# Basic target does not support release # Basic target does not support release
echo 0 > "${NETCONS_PATH}"/release echo 0 > "${NCPATH}"/release
echo 0 > "${NETCONS_PATH}"/extended echo 0 > "${NCPATH}"/extended
elif [ "${FORMAT}" == "extended" ] elif [ "${FORMAT}" == "extended" ]
then then
echo 1 > "${NETCONS_PATH}"/extended echo 1 > "${NCPATH}"/extended
fi fi
}
echo 1 > "${NETCONS_PATH}"/enabled function create_dynamic_target() {
local FORMAT=${1:-"extended"}
local NCPATH=${2:-"$NETCONS_PATH"}
_create_dynamic_target "${FORMAT}" "${NCPATH}"
echo 1 > "${NCPATH}"/enabled
# This will make sure that the kernel was able to # This will make sure that the kernel was able to
# load the netconsole driver configuration. The console message # load the netconsole driver configuration. The console message
@@ -185,14 +200,26 @@ function do_cleanup() {
echo "${DEFAULT_PRINTK_VALUES}" > /proc/sys/kernel/printk echo "${DEFAULT_PRINTK_VALUES}" > /proc/sys/kernel/printk
} }
function cleanup() { function cleanup_netcons() {
# delete netconsole dynamic reconfiguration # delete netconsole dynamic reconfiguration
echo 0 > "${NETCONS_PATH}"/enabled # do not fail if the target is already disabled
if [[ ! -d "${NETCONS_PATH}" ]]
then
# in some cases this is called before netcons path is created
return
fi
if [[ $(cat "${NETCONS_PATH}"/enabled) != 0 ]]
then
echo 0 > "${NETCONS_PATH}"/enabled || true
fi
# Remove all the keys that got created during the selftest # Remove all the keys that got created during the selftest
find "${NETCONS_PATH}/userdata/" -mindepth 1 -type d -delete find "${NETCONS_PATH}/userdata/" -mindepth 1 -type d -delete
# Remove the configfs entry # Remove the configfs entry
rmdir "${NETCONS_PATH}" rmdir "${NETCONS_PATH}"
}
function cleanup() {
cleanup_netcons
do_cleanup do_cleanup
} }
@@ -369,3 +396,24 @@ function wait_for_port() {
# more frequently on IPv6 # more frequently on IPv6
sleep 1 sleep 1
} }
# Clean up netdevsim ifaces created for bonding test
function cleanup_bond_nsim() {
ip -n "${TXNS}" \
link delete "${BOND_TX_MAIN_IF}" type bond || true
ip -n "${RXNS}" \
link delete "${BOND_RX_MAIN_IF}" type bond || true
cleanup_netdevsim "$NSIM_BOND_TX_1"
cleanup_netdevsim "$NSIM_BOND_TX_2"
cleanup_netdevsim "$NSIM_BOND_RX_1"
cleanup_netdevsim "$NSIM_BOND_RX_2"
}
# cleanup tests that use bonding interfaces
function cleanup_bond() {
cleanup_netcons
cleanup_bond_nsim
cleanup_all_ns
ip link delete "${VETH0}" || true
}

View File

@@ -0,0 +1,130 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: GPL-2.0
# Repeatedly send kernel messages, toggles netconsole targets on and off,
# creates and deletes targets in parallel, and toggles the source interface to
# simulate stress conditions.
#
# This test aims to verify the robustness of netconsole under dynamic
# configurations and concurrent operations.
#
# The major goal is to run this test with LOCKDEP, Kmemleak and KASAN to make
# sure no issues is reported.
#
# Author: Breno Leitao <leitao@debian.org>
set -euo pipefail
SCRIPTDIR=$(dirname "$(readlink -e "${BASH_SOURCE[0]}")")
source "${SCRIPTDIR}"/lib/sh/lib_netcons.sh
# Number of times the main loop run
ITERATIONS=${1:-150}
# Only test extended format
FORMAT="extended"
# And ipv6 only
IP_VERSION="ipv6"
# Create, enable and delete some targets.
create_and_delete_random_target() {
COUNT=2
RND_PREFIX=$(mktemp -u netcons_rnd_XXXX_)
if [ -d "${NETCONS_CONFIGFS}/${RND_PREFIX}${COUNT}" ] || \
[ -d "${NETCONS_CONFIGFS}/${RND_PREFIX}0" ]; then
echo "Function didn't finish yet, skipping it." >&2
return
fi
# enable COUNT targets
for i in $(seq ${COUNT})
do
RND_TARGET="${RND_PREFIX}"${i}
RND_TARGET_PATH="${NETCONS_CONFIGFS}"/"${RND_TARGET}"
# Basic population so the target can come up
_create_dynamic_target "${FORMAT}" "${RND_TARGET_PATH}"
done
echo "netconsole selftest: ${COUNT} additional targets were created" > /dev/kmsg
# disable them all
for i in $(seq ${COUNT})
do
RND_TARGET="${RND_PREFIX}"${i}
RND_TARGET_PATH="${NETCONS_CONFIGFS}"/"${RND_TARGET}"
if [[ $(cat "${RND_TARGET_PATH}/enabled") -eq 1 ]]
then
echo 0 > "${RND_TARGET_PATH}"/enabled
fi
rmdir "${RND_TARGET_PATH}"
done
}
# Disable and enable the target mid-air, while messages
# are being transmitted.
toggle_netcons_target() {
for i in $(seq 2)
do
if [ ! -d "${NETCONS_PATH}" ]
then
break
fi
echo 0 > "${NETCONS_PATH}"/enabled 2> /dev/null || true
# Try to enable a bit harder, given it might fail to enable
# Write to `enabled` might fail depending on the lock, which is
# highly contentious here
for _ in $(seq 5)
do
echo 1 > "${NETCONS_PATH}"/enabled 2> /dev/null || true
done
done
}
toggle_iface(){
ip link set "${SRCIF}" down
ip link set "${SRCIF}" up
}
# Start here
modprobe netdevsim 2> /dev/null || true
modprobe netconsole 2> /dev/null || true
# Check for basic system dependency and exit if not found
check_for_dependencies
# Set current loglevel to KERN_INFO(6), and default to KERN_NOTICE(5)
echo "6 5" > /proc/sys/kernel/printk
# Remove the namespace, interfaces and netconsole target on exit
trap cleanup EXIT
# Create one namespace and two interfaces
set_network "${IP_VERSION}"
# Create a dynamic target for netconsole
create_dynamic_target "${FORMAT}"
for i in $(seq "$ITERATIONS")
do
for _ in $(seq 10)
do
echo "${MSG}: ${TARGET} ${i}" > /dev/kmsg
done
wait
if (( i % 30 == 0 )); then
toggle_netcons_target &
fi
if (( i % 50 == 0 )); then
# create some targets, enable them, send msg and disable
# all in a parallel thread
create_and_delete_random_target &
fi
if (( i % 70 == 0 )); then
toggle_iface &
fi
done
wait
exit "${EXIT_STATUS}"

View File

@@ -176,6 +176,8 @@ run_test()
local rcv_dmac=$(mac_get $rcv_if_name) local rcv_dmac=$(mac_get $rcv_if_name)
local should_receive local should_receive
setup_wait
tcpdump_start $rcv_if_name tcpdump_start $rcv_if_name
mc_route_prepare $send_if_name mc_route_prepare $send_if_name

View File

@@ -710,8 +710,14 @@ static int copyfd_io_poll(int infd, int peerfd, int outfd,
bw = do_rnd_write(peerfd, winfo->buf + winfo->off, winfo->len); bw = do_rnd_write(peerfd, winfo->buf + winfo->off, winfo->len);
if (bw < 0) { if (bw < 0) {
if (cfg_rcv_trunc) /* expected reset, continue to read */
return 0; if (cfg_rcv_trunc &&
(errno == ECONNRESET ||
errno == EPIPE)) {
fds.events &= ~POLLOUT;
continue;
}
perror("write"); perror("write");
return 111; return 111;
} }
@@ -737,8 +743,10 @@ static int copyfd_io_poll(int infd, int peerfd, int outfd,
} }
if (fds.revents & (POLLERR | POLLNVAL)) { if (fds.revents & (POLLERR | POLLNVAL)) {
if (cfg_rcv_trunc) if (cfg_rcv_trunc) {
return 0; fds.events &= ~(POLLERR | POLLNVAL);
continue;
}
fprintf(stderr, "Unexpected revents: " fprintf(stderr, "Unexpected revents: "
"POLLERR/POLLNVAL(%x)\n", fds.revents); "POLLERR/POLLNVAL(%x)\n", fds.revents);
return 5; return 5;
@@ -1433,7 +1441,7 @@ static void parse_opts(int argc, char **argv)
*/ */
if (cfg_truncate < 0) { if (cfg_truncate < 0) {
cfg_rcv_trunc = true; cfg_rcv_trunc = true;
signal(SIGPIPE, handle_signal); signal(SIGPIPE, SIG_IGN);
} }
break; break;
case 'j': case 'j':

View File

@@ -492,7 +492,7 @@ do_transfer()
"than expected (${expect_synrx})" "than expected (${expect_synrx})"
retc=1 retc=1
fi fi
if [ ${stat_ackrx_now_l} -lt ${expect_ackrx} ] && [ ${stat_ooo_now} -eq 0 ]; then if [ ${stat_ackrx_now_l} -lt ${expect_ackrx} ]; then
if [ ${stat_ooo_now} -eq 0 ]; then if [ ${stat_ooo_now} -eq 0 ]; then
mptcp_lib_pr_fail "lower MPC ACK rx (${stat_ackrx_now_l})" \ mptcp_lib_pr_fail "lower MPC ACK rx (${stat_ackrx_now_l})" \
"than expected (${expect_ackrx})" "than expected (${expect_ackrx})"

View File

@@ -2532,7 +2532,7 @@ remove_tests()
if reset "remove single subflow"; then if reset "remove single subflow"; then
pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns1 0 1
pm_nl_set_limits $ns2 0 1 pm_nl_set_limits $ns2 0 1
pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow,backup
addr_nr_ns2=-1 speed=slow \ addr_nr_ns2=-1 speed=slow \
run_tests $ns1 $ns2 10.0.1.1 run_tests $ns1 $ns2 10.0.1.1
chk_join_nr 1 1 1 chk_join_nr 1 1 1
@@ -2545,8 +2545,8 @@ remove_tests()
if reset "remove multiple subflows"; then if reset "remove multiple subflows"; then
pm_nl_set_limits $ns1 0 2 pm_nl_set_limits $ns1 0 2
pm_nl_set_limits $ns2 0 2 pm_nl_set_limits $ns2 0 2
pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow,backup
pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow,backup
addr_nr_ns2=-2 speed=slow \ addr_nr_ns2=-2 speed=slow \
run_tests $ns1 $ns2 10.0.1.1 run_tests $ns1 $ns2 10.0.1.1
chk_join_nr 2 2 2 chk_join_nr 2 2 2
@@ -2557,7 +2557,7 @@ remove_tests()
# single address, remove # single address, remove
if reset "remove single address"; then if reset "remove single address"; then
pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns1 0 1
pm_nl_add_endpoint $ns1 10.0.2.1 flags signal pm_nl_add_endpoint $ns1 10.0.2.1 flags signal,backup
pm_nl_set_limits $ns2 1 1 pm_nl_set_limits $ns2 1 1
addr_nr_ns1=-1 speed=slow \ addr_nr_ns1=-1 speed=slow \
run_tests $ns1 $ns2 10.0.1.1 run_tests $ns1 $ns2 10.0.1.1
@@ -2570,9 +2570,9 @@ remove_tests()
# subflow and signal, remove # subflow and signal, remove
if reset "remove subflow and signal"; then if reset "remove subflow and signal"; then
pm_nl_set_limits $ns1 0 2 pm_nl_set_limits $ns1 0 2
pm_nl_add_endpoint $ns1 10.0.2.1 flags signal pm_nl_add_endpoint $ns1 10.0.2.1 flags signal,backup
pm_nl_set_limits $ns2 1 2 pm_nl_set_limits $ns2 1 2
pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow,backup
addr_nr_ns1=-1 addr_nr_ns2=-1 speed=slow \ addr_nr_ns1=-1 addr_nr_ns2=-1 speed=slow \
run_tests $ns1 $ns2 10.0.1.1 run_tests $ns1 $ns2 10.0.1.1
chk_join_nr 2 2 2 chk_join_nr 2 2 2
@@ -2584,10 +2584,10 @@ remove_tests()
# subflows and signal, remove # subflows and signal, remove
if reset "remove subflows and signal"; then if reset "remove subflows and signal"; then
pm_nl_set_limits $ns1 0 3 pm_nl_set_limits $ns1 0 3
pm_nl_add_endpoint $ns1 10.0.2.1 flags signal pm_nl_add_endpoint $ns1 10.0.2.1 flags signal,backup
pm_nl_set_limits $ns2 1 3 pm_nl_set_limits $ns2 1 3
pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow,backup
pm_nl_add_endpoint $ns2 10.0.4.2 flags subflow pm_nl_add_endpoint $ns2 10.0.4.2 flags subflow,backup
addr_nr_ns1=-1 addr_nr_ns2=-2 speed=10 \ addr_nr_ns1=-1 addr_nr_ns2=-2 speed=10 \
run_tests $ns1 $ns2 10.0.1.1 run_tests $ns1 $ns2 10.0.1.1
chk_join_nr 3 3 3 chk_join_nr 3 3 3
@@ -2599,9 +2599,9 @@ remove_tests()
# addresses remove # addresses remove
if reset "remove addresses"; then if reset "remove addresses"; then
pm_nl_set_limits $ns1 3 3 pm_nl_set_limits $ns1 3 3
pm_nl_add_endpoint $ns1 10.0.2.1 flags signal id 250 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal,backup id 250
pm_nl_add_endpoint $ns1 10.0.3.1 flags signal pm_nl_add_endpoint $ns1 10.0.3.1 flags signal,backup
pm_nl_add_endpoint $ns1 10.0.4.1 flags signal pm_nl_add_endpoint $ns1 10.0.4.1 flags signal,backup
pm_nl_set_limits $ns2 3 3 pm_nl_set_limits $ns2 3 3
addr_nr_ns1=-3 speed=10 \ addr_nr_ns1=-3 speed=10 \
run_tests $ns1 $ns2 10.0.1.1 run_tests $ns1 $ns2 10.0.1.1
@@ -2614,10 +2614,10 @@ remove_tests()
# invalid addresses remove # invalid addresses remove
if reset "remove invalid addresses"; then if reset "remove invalid addresses"; then
pm_nl_set_limits $ns1 3 3 pm_nl_set_limits $ns1 3 3
pm_nl_add_endpoint $ns1 10.0.12.1 flags signal pm_nl_add_endpoint $ns1 10.0.12.1 flags signal,backup
# broadcast IP: no packet for this address will be received on ns1 # broadcast IP: no packet for this address will be received on ns1
pm_nl_add_endpoint $ns1 224.0.0.1 flags signal pm_nl_add_endpoint $ns1 224.0.0.1 flags signal,backup
pm_nl_add_endpoint $ns1 10.0.3.1 flags signal pm_nl_add_endpoint $ns1 10.0.3.1 flags signal,backup
pm_nl_set_limits $ns2 2 2 pm_nl_set_limits $ns2 2 2
addr_nr_ns1=-3 speed=10 \ addr_nr_ns1=-3 speed=10 \
run_tests $ns1 $ns2 10.0.1.1 run_tests $ns1 $ns2 10.0.1.1
@@ -2631,10 +2631,10 @@ remove_tests()
# subflows and signal, flush # subflows and signal, flush
if reset "flush subflows and signal"; then if reset "flush subflows and signal"; then
pm_nl_set_limits $ns1 0 3 pm_nl_set_limits $ns1 0 3
pm_nl_add_endpoint $ns1 10.0.2.1 flags signal pm_nl_add_endpoint $ns1 10.0.2.1 flags signal,backup
pm_nl_set_limits $ns2 1 3 pm_nl_set_limits $ns2 1 3
pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow,backup
pm_nl_add_endpoint $ns2 10.0.4.2 flags subflow pm_nl_add_endpoint $ns2 10.0.4.2 flags subflow,backup
addr_nr_ns1=-8 addr_nr_ns2=-8 speed=slow \ addr_nr_ns1=-8 addr_nr_ns2=-8 speed=slow \
run_tests $ns1 $ns2 10.0.1.1 run_tests $ns1 $ns2 10.0.1.1
chk_join_nr 3 3 3 chk_join_nr 3 3 3
@@ -2647,9 +2647,9 @@ remove_tests()
if reset "flush subflows"; then if reset "flush subflows"; then
pm_nl_set_limits $ns1 3 3 pm_nl_set_limits $ns1 3 3
pm_nl_set_limits $ns2 3 3 pm_nl_set_limits $ns2 3 3
pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow id 150 pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow,backup id 150
pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow,backup
pm_nl_add_endpoint $ns2 10.0.4.2 flags subflow pm_nl_add_endpoint $ns2 10.0.4.2 flags subflow,backup
addr_nr_ns1=-8 addr_nr_ns2=-8 speed=slow \ addr_nr_ns1=-8 addr_nr_ns2=-8 speed=slow \
run_tests $ns1 $ns2 10.0.1.1 run_tests $ns1 $ns2 10.0.1.1
chk_join_nr 3 3 3 chk_join_nr 3 3 3
@@ -2666,9 +2666,9 @@ remove_tests()
# addresses flush # addresses flush
if reset "flush addresses"; then if reset "flush addresses"; then
pm_nl_set_limits $ns1 3 3 pm_nl_set_limits $ns1 3 3
pm_nl_add_endpoint $ns1 10.0.2.1 flags signal id 250 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal,backup id 250
pm_nl_add_endpoint $ns1 10.0.3.1 flags signal pm_nl_add_endpoint $ns1 10.0.3.1 flags signal,backup
pm_nl_add_endpoint $ns1 10.0.4.1 flags signal pm_nl_add_endpoint $ns1 10.0.4.1 flags signal,backup
pm_nl_set_limits $ns2 3 3 pm_nl_set_limits $ns2 3 3
addr_nr_ns1=-8 addr_nr_ns2=-8 speed=slow \ addr_nr_ns1=-8 addr_nr_ns2=-8 speed=slow \
run_tests $ns1 $ns2 10.0.1.1 run_tests $ns1 $ns2 10.0.1.1
@@ -2681,9 +2681,9 @@ remove_tests()
# invalid addresses flush # invalid addresses flush
if reset "flush invalid addresses"; then if reset "flush invalid addresses"; then
pm_nl_set_limits $ns1 3 3 pm_nl_set_limits $ns1 3 3
pm_nl_add_endpoint $ns1 10.0.12.1 flags signal pm_nl_add_endpoint $ns1 10.0.12.1 flags signal,backup
pm_nl_add_endpoint $ns1 10.0.3.1 flags signal pm_nl_add_endpoint $ns1 10.0.3.1 flags signal,backup
pm_nl_add_endpoint $ns1 10.0.14.1 flags signal pm_nl_add_endpoint $ns1 10.0.14.1 flags signal,backup
pm_nl_set_limits $ns2 3 3 pm_nl_set_limits $ns2 3 3
addr_nr_ns1=-8 speed=slow \ addr_nr_ns1=-8 speed=slow \
run_tests $ns1 $ns2 10.0.1.1 run_tests $ns1 $ns2 10.0.1.1
@@ -3806,7 +3806,7 @@ userspace_tests()
continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then
set_userspace_pm $ns1 set_userspace_pm $ns1
pm_nl_set_limits $ns2 2 2 pm_nl_set_limits $ns2 2 2
{ speed=5 \ { test_linkfail=128 speed=5 \
run_tests $ns1 $ns2 10.0.1.1 & } 2>/dev/null run_tests $ns1 $ns2 10.0.1.1 & } 2>/dev/null
local tests_pid=$! local tests_pid=$!
wait_mpj $ns1 wait_mpj $ns1
@@ -3831,7 +3831,7 @@ userspace_tests()
chk_mptcp_info subflows 0 subflows 0 chk_mptcp_info subflows 0 subflows 0
chk_subflows_total 1 1 chk_subflows_total 1 1
kill_events_pids kill_events_pids
mptcp_lib_kill_wait $tests_pid mptcp_lib_kill_group_wait $tests_pid
fi fi
# userspace pm create destroy subflow # userspace pm create destroy subflow
@@ -3839,7 +3839,7 @@ userspace_tests()
continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then
set_userspace_pm $ns2 set_userspace_pm $ns2
pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns1 0 1
{ speed=5 \ { test_linkfail=128 speed=5 \
run_tests $ns1 $ns2 10.0.1.1 & } 2>/dev/null run_tests $ns1 $ns2 10.0.1.1 & } 2>/dev/null
local tests_pid=$! local tests_pid=$!
wait_mpj $ns2 wait_mpj $ns2
@@ -3859,7 +3859,7 @@ userspace_tests()
chk_mptcp_info subflows 0 subflows 0 chk_mptcp_info subflows 0 subflows 0
chk_subflows_total 1 1 chk_subflows_total 1 1
kill_events_pids kill_events_pids
mptcp_lib_kill_wait $tests_pid mptcp_lib_kill_group_wait $tests_pid
fi fi
# userspace pm create id 0 subflow # userspace pm create id 0 subflow
@@ -3867,7 +3867,7 @@ userspace_tests()
continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then
set_userspace_pm $ns2 set_userspace_pm $ns2
pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns1 0 1
{ speed=5 \ { test_linkfail=128 speed=5 \
run_tests $ns1 $ns2 10.0.1.1 & } 2>/dev/null run_tests $ns1 $ns2 10.0.1.1 & } 2>/dev/null
local tests_pid=$! local tests_pid=$!
wait_mpj $ns2 wait_mpj $ns2
@@ -3880,7 +3880,7 @@ userspace_tests()
chk_mptcp_info subflows 1 subflows 1 chk_mptcp_info subflows 1 subflows 1
chk_subflows_total 2 2 chk_subflows_total 2 2
kill_events_pids kill_events_pids
mptcp_lib_kill_wait $tests_pid mptcp_lib_kill_group_wait $tests_pid
fi fi
# userspace pm remove initial subflow # userspace pm remove initial subflow
@@ -3888,7 +3888,7 @@ userspace_tests()
continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then
set_userspace_pm $ns2 set_userspace_pm $ns2
pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns1 0 1
{ speed=5 \ { test_linkfail=128 speed=5 \
run_tests $ns1 $ns2 10.0.1.1 & } 2>/dev/null run_tests $ns1 $ns2 10.0.1.1 & } 2>/dev/null
local tests_pid=$! local tests_pid=$!
wait_mpj $ns2 wait_mpj $ns2
@@ -3904,7 +3904,7 @@ userspace_tests()
chk_mptcp_info subflows 1 subflows 1 chk_mptcp_info subflows 1 subflows 1
chk_subflows_total 1 1 chk_subflows_total 1 1
kill_events_pids kill_events_pids
mptcp_lib_kill_wait $tests_pid mptcp_lib_kill_group_wait $tests_pid
fi fi
# userspace pm send RM_ADDR for ID 0 # userspace pm send RM_ADDR for ID 0
@@ -3912,7 +3912,7 @@ userspace_tests()
continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then
set_userspace_pm $ns1 set_userspace_pm $ns1
pm_nl_set_limits $ns2 1 1 pm_nl_set_limits $ns2 1 1
{ speed=5 \ { test_linkfail=128 speed=5 \
run_tests $ns1 $ns2 10.0.1.1 & } 2>/dev/null run_tests $ns1 $ns2 10.0.1.1 & } 2>/dev/null
local tests_pid=$! local tests_pid=$!
wait_mpj $ns1 wait_mpj $ns1
@@ -3930,7 +3930,7 @@ userspace_tests()
chk_mptcp_info subflows 1 subflows 1 chk_mptcp_info subflows 1 subflows 1
chk_subflows_total 1 1 chk_subflows_total 1 1
kill_events_pids kill_events_pids
mptcp_lib_kill_wait $tests_pid mptcp_lib_kill_group_wait $tests_pid
fi fi
} }
@@ -3943,7 +3943,7 @@ endpoint_tests()
pm_nl_set_limits $ns1 2 2 pm_nl_set_limits $ns1 2 2
pm_nl_set_limits $ns2 2 2 pm_nl_set_limits $ns2 2 2
pm_nl_add_endpoint $ns1 10.0.2.1 flags signal pm_nl_add_endpoint $ns1 10.0.2.1 flags signal
{ speed=slow \ { test_linkfail=128 speed=slow \
run_tests $ns1 $ns2 10.0.1.1 & } 2>/dev/null run_tests $ns1 $ns2 10.0.1.1 & } 2>/dev/null
local tests_pid=$! local tests_pid=$!
@@ -3960,7 +3960,7 @@ endpoint_tests()
pm_nl_add_endpoint $ns2 10.0.2.2 flags signal pm_nl_add_endpoint $ns2 10.0.2.2 flags signal
pm_nl_check_endpoint "modif is allowed" \ pm_nl_check_endpoint "modif is allowed" \
$ns2 10.0.2.2 id 1 flags signal $ns2 10.0.2.2 id 1 flags signal
mptcp_lib_kill_wait $tests_pid mptcp_lib_kill_group_wait $tests_pid
fi fi
if reset_with_tcp_filter "delete and re-add" ns2 10.0.3.2 REJECT OUTPUT && if reset_with_tcp_filter "delete and re-add" ns2 10.0.3.2 REJECT OUTPUT &&
@@ -3970,7 +3970,7 @@ endpoint_tests()
pm_nl_set_limits $ns2 0 3 pm_nl_set_limits $ns2 0 3
pm_nl_add_endpoint $ns2 10.0.1.2 id 1 dev ns2eth1 flags subflow pm_nl_add_endpoint $ns2 10.0.1.2 id 1 dev ns2eth1 flags subflow
pm_nl_add_endpoint $ns2 10.0.2.2 id 2 dev ns2eth2 flags subflow pm_nl_add_endpoint $ns2 10.0.2.2 id 2 dev ns2eth2 flags subflow
{ test_linkfail=4 speed=5 \ { test_linkfail=128 speed=5 \
run_tests $ns1 $ns2 10.0.1.1 & } 2>/dev/null run_tests $ns1 $ns2 10.0.1.1 & } 2>/dev/null
local tests_pid=$! local tests_pid=$!
@@ -4015,7 +4015,7 @@ endpoint_tests()
chk_mptcp_info subflows 3 subflows 3 chk_mptcp_info subflows 3 subflows 3
done done
mptcp_lib_kill_wait $tests_pid mptcp_lib_kill_group_wait $tests_pid
kill_events_pids kill_events_pids
chk_evt_nr ns1 MPTCP_LIB_EVENT_LISTENER_CREATED 1 chk_evt_nr ns1 MPTCP_LIB_EVENT_LISTENER_CREATED 1
@@ -4048,7 +4048,7 @@ endpoint_tests()
# broadcast IP: no packet for this address will be received on ns1 # broadcast IP: no packet for this address will be received on ns1
pm_nl_add_endpoint $ns1 224.0.0.1 id 2 flags signal pm_nl_add_endpoint $ns1 224.0.0.1 id 2 flags signal
pm_nl_add_endpoint $ns1 10.0.1.1 id 42 flags signal pm_nl_add_endpoint $ns1 10.0.1.1 id 42 flags signal
{ test_linkfail=4 speed=5 \ { test_linkfail=128 speed=5 \
run_tests $ns1 $ns2 10.0.1.1 & } 2>/dev/null run_tests $ns1 $ns2 10.0.1.1 & } 2>/dev/null
local tests_pid=$! local tests_pid=$!
@@ -4089,7 +4089,7 @@ endpoint_tests()
wait_mpj $ns2 wait_mpj $ns2
chk_subflow_nr "after re-re-add ID 0" 3 chk_subflow_nr "after re-re-add ID 0" 3
chk_mptcp_info subflows 3 subflows 3 chk_mptcp_info subflows 3 subflows 3
mptcp_lib_kill_wait $tests_pid mptcp_lib_kill_group_wait $tests_pid
kill_events_pids kill_events_pids
chk_evt_nr ns1 MPTCP_LIB_EVENT_LISTENER_CREATED 1 chk_evt_nr ns1 MPTCP_LIB_EVENT_LISTENER_CREATED 1
@@ -4121,7 +4121,7 @@ endpoint_tests()
# broadcast IP: no packet for this address will be received on ns1 # broadcast IP: no packet for this address will be received on ns1
pm_nl_add_endpoint $ns1 224.0.0.1 id 2 flags signal pm_nl_add_endpoint $ns1 224.0.0.1 id 2 flags signal
pm_nl_add_endpoint $ns2 10.0.3.2 id 3 flags subflow pm_nl_add_endpoint $ns2 10.0.3.2 id 3 flags subflow
{ test_linkfail=4 speed=20 \ { test_linkfail=128 speed=20 \
run_tests $ns1 $ns2 10.0.1.1 & } 2>/dev/null run_tests $ns1 $ns2 10.0.1.1 & } 2>/dev/null
local tests_pid=$! local tests_pid=$!
@@ -4137,7 +4137,7 @@ endpoint_tests()
wait_mpj $ns2 wait_mpj $ns2
pm_nl_add_endpoint $ns1 10.0.3.1 id 2 flags signal pm_nl_add_endpoint $ns1 10.0.3.1 id 2 flags signal
wait_mpj $ns2 wait_mpj $ns2
mptcp_lib_kill_wait $tests_pid mptcp_lib_kill_group_wait $tests_pid
join_syn_tx=3 join_connect_err=1 \ join_syn_tx=3 join_connect_err=1 \
chk_join_nr 2 2 2 chk_join_nr 2 2 2

View File

@@ -350,6 +350,27 @@ mptcp_lib_kill_wait() {
wait "${1}" 2>/dev/null wait "${1}" 2>/dev/null
} }
# $1: PID
mptcp_lib_pid_list_children() {
local curr="${1}"
# evoke 'ps' only once
local pids="${2:-"$(ps o pid,ppid)"}"
echo "${curr}"
local pid
for pid in $(echo "${pids}" | awk "\$2 == ${curr} { print \$1 }"); do
mptcp_lib_pid_list_children "${pid}" "${pids}"
done
}
# $1: PID
mptcp_lib_kill_group_wait() {
# Some users might not have procps-ng: cannot use "kill -- -PID"
mptcp_lib_pid_list_children "${1}" | xargs -r kill &>/dev/null
wait "${1}" 2>/dev/null
}
# $1: IP address # $1: IP address
mptcp_lib_is_v6() { mptcp_lib_is_v6() {
[ -z "${1##*:*}" ] [ -z "${1##*:*}" ]

View File

@@ -961,5 +961,49 @@
"teardown": [ "teardown": [
"$TC qdisc del dev $DUMMY root" "$TC qdisc del dev $DUMMY root"
] ]
},
{
"id": "4989",
"name": "Try to add an fq child to an ingress qdisc",
"category": [
"qdisc",
"ingress"
],
"plugins": {
"requires": "nsPlugin"
},
"setup": [
"$TC qdisc add dev $DUMMY handle ffff:0 ingress"
],
"cmdUnderTest": "$TC qdisc add dev $DUMMY parent ffff:0 handle ffe0:0 fq",
"expExitCode": "2",
"verifyCmd": "$TC -j qdisc ls dev $DUMMY handle ffe0:",
"matchJSON": [],
"matchCount": "1",
"teardown": [
"$TC qdisc del dev $DUMMY ingress"
]
},
{
"id": "c2b0",
"name": "Try to add an fq child to a clsact qdisc",
"category": [
"qdisc",
"ingress"
],
"plugins": {
"requires": "nsPlugin"
},
"setup": [
"$TC qdisc add dev $DUMMY handle ffff:0 clsact"
],
"cmdUnderTest": "$TC qdisc add dev $DUMMY parent ffff:0 handle ffe0:0 fq",
"expExitCode": "2",
"verifyCmd": "$TC -j qdisc ls dev $DUMMY handle ffe0:",
"matchJSON": [],
"matchCount": "1",
"teardown": [
"$TC qdisc del dev $DUMMY clsact"
]
} }
] ]