mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-06 01:49:46 +00:00
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:
@@ -13,10 +13,10 @@ Simple CLI
|
||||
Kernel comes with a simple CLI tool which should be useful when
|
||||
developing Netlink related code. The tool is implemented in Python
|
||||
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
|
||||
a handul of arguments, the most important ones are:
|
||||
a handful of arguments, the most important ones are:
|
||||
|
||||
- ``--spec`` - point to the spec file
|
||||
- ``--do $name`` / ``--dump $name`` - issue request ``$name``
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
|
||||
#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_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_DUMMY_HEADER 0x02
|
||||
@@ -534,7 +534,6 @@ static int rtlbt_parse_firmware_v2(struct hci_dev *hdev,
|
||||
{
|
||||
struct rtl_epatch_header_v2 *hdr;
|
||||
int rc;
|
||||
u8 reg_val[2];
|
||||
u8 key_id;
|
||||
u32 num_sections;
|
||||
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 */
|
||||
};
|
||||
|
||||
rc = btrtl_vendor_read_reg16(hdev, RTL_SEC_PROJ, reg_val);
|
||||
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;
|
||||
key_id = btrtl_dev->key_id;
|
||||
|
||||
hdr = rtl_iov_pull_data(&iov, sizeof(*hdr));
|
||||
if (!hdr)
|
||||
@@ -1070,6 +1062,8 @@ struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev,
|
||||
u16 hci_rev, lmp_subver;
|
||||
u8 hci_ver, lmp_ver, chip_type = 0;
|
||||
int ret;
|
||||
int rc;
|
||||
u8 key_id;
|
||||
u8 reg_val[2];
|
||||
|
||||
btrtl_dev = kzalloc(sizeof(*btrtl_dev), GFP_KERNEL);
|
||||
@@ -1180,6 +1174,14 @@ next:
|
||||
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;
|
||||
if (lmp_subver == RTL_ROM_LMP_8852A && hci_rev == 0x000c) {
|
||||
snprintf(fw_name, sizeof(fw_name), "%s_v2.bin",
|
||||
@@ -1202,7 +1204,7 @@ next:
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
if (btrtl_dev->ic_info->cfg_name) {
|
||||
if (btrtl_dev->ic_info->cfg_name && !btrtl_dev->key_id) {
|
||||
if (postfix) {
|
||||
snprintf(cfg_name, sizeof(cfg_name), "%s-%s.bin",
|
||||
btrtl_dev->ic_info->cfg_name, postfix);
|
||||
|
||||
@@ -4361,6 +4361,11 @@ static void btusb_disconnect(struct usb_interface *intf)
|
||||
|
||||
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 (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->intf);
|
||||
} else if (intf == data->diag) {
|
||||
usb_driver_release_interface(&btusb_driver, data->intf);
|
||||
if (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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
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));
|
||||
if (err)
|
||||
goto err_cqb;
|
||||
|
||||
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;
|
||||
|
||||
INIT_LIST_HEAD(&cq->wc_list);
|
||||
|
||||
@@ -2120,7 +2120,7 @@ skip_mac_set:
|
||||
/* check for initial state */
|
||||
new_slave->link = BOND_LINK_NOCHANGE;
|
||||
if (bond->params.miimon) {
|
||||
if (netif_carrier_ok(slave_dev)) {
|
||||
if (netif_running(slave_dev) && netif_carrier_ok(slave_dev)) {
|
||||
if (bond->params.updelay) {
|
||||
bond_set_slave_link_state(new_slave,
|
||||
BOND_LINK_BACK,
|
||||
@@ -2665,7 +2665,8 @@ static int bond_miimon_inspect(struct bonding *bond)
|
||||
bond_for_each_slave_rcu(bond, slave, iter) {
|
||||
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) {
|
||||
case BOND_LINK_UP:
|
||||
|
||||
@@ -1835,6 +1835,8 @@ fec_enet_rx_queue(struct net_device *ndev, u16 queue_id, int budget)
|
||||
ndev->stats.rx_packets++;
|
||||
pkt_len = fec16_to_cpu(bdp->cbd_datlen);
|
||||
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);
|
||||
page = rxq->rx_skb_info[index].page;
|
||||
|
||||
@@ -66,8 +66,8 @@ void mlx5_cq_tasklet_cb(struct tasklet_struct *t)
|
||||
tasklet_schedule(&ctx->task);
|
||||
}
|
||||
|
||||
static void mlx5_add_cq_to_tasklet(struct mlx5_core_cq *cq,
|
||||
struct mlx5_eqe *eqe)
|
||||
void mlx5_add_cq_to_tasklet(struct mlx5_core_cq *cq,
|
||||
struct mlx5_eqe *eqe)
|
||||
{
|
||||
unsigned long flags;
|
||||
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)
|
||||
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 */
|
||||
int mlx5_create_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
|
||||
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->eq = eq;
|
||||
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);
|
||||
init_completion(&cq->free);
|
||||
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 */
|
||||
cq->tasklet_ctx.priv = &eq->tasklet_ctx;
|
||||
INIT_LIST_HEAD(&cq->tasklet_ctx.list);
|
||||
|
||||
@@ -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);
|
||||
if (val32 > max_num_channels) {
|
||||
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);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -804,7 +804,8 @@ static int mlx5e_xfrm_add_state(struct net_device *dev,
|
||||
goto err_xfrm;
|
||||
}
|
||||
|
||||
if (mlx5_eswitch_block_mode(priv->mdev))
|
||||
err = mlx5_eswitch_block_mode(priv->mdev);
|
||||
if (err)
|
||||
goto unblock_ipsec;
|
||||
|
||||
if (x->props.mode == XFRM_MODE_TUNNEL &&
|
||||
|
||||
@@ -595,32 +595,55 @@ static int mlx5e_dcbnl_ieee_setmaxrate(struct net_device *netdev,
|
||||
struct mlx5_core_dev *mdev = priv->mdev;
|
||||
u8 max_bw_value[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;
|
||||
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_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++) {
|
||||
if (!maxrate->tc_maxrate[i]) {
|
||||
max_bw_unit[i] = MLX5_BW_NO_LIMIT;
|
||||
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],
|
||||
MLX5E_100MB);
|
||||
max_bw_value[i] = max_bw_value[i] ? max_bw_value[i] : 1;
|
||||
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],
|
||||
MLX5E_1GB);
|
||||
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++) {
|
||||
netdev_dbg(netdev, "%s: tc_%d <=> max_bw %d Gbps\n",
|
||||
__func__, i, max_bw_value[i]);
|
||||
netdev_dbg(netdev, "%s: tc_%d <=> max_bw %u %s\n", __func__, 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);
|
||||
|
||||
@@ -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->arm_db = cq->wq_ctrl.db.db + 1;
|
||||
*mcq->set_ci_db = 0;
|
||||
*mcq->arm_db = 0;
|
||||
mcq->vector = param->eq_ix;
|
||||
mcq->comp = mlx5e_completion_event;
|
||||
mcq->event = mlx5e_cq_error_event;
|
||||
|
||||
@@ -421,6 +421,13 @@ static int mlx5_fpga_conn_create_cq(struct mlx5_fpga_conn *conn, int cq_size)
|
||||
__be64 *pas;
|
||||
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);
|
||||
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)
|
||||
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);
|
||||
|
||||
mlx5_fpga_dbg(fdev, "Created CQ #0x%x\n", conn->cq.mcq.cqn);
|
||||
|
||||
goto out;
|
||||
|
||||
@@ -873,12 +873,6 @@ err_free_sqc:
|
||||
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,
|
||||
int numa_node,
|
||||
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->set_ci_db = cq->wq_ctrl.db.db;
|
||||
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++) {
|
||||
cqe = mlx5_cqwq_get_wqe(&cq->wq, i);
|
||||
|
||||
@@ -1049,12 +1049,6 @@ static int dr_prepare_qp_to_rts(struct mlx5dr_domain *dmn)
|
||||
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,
|
||||
struct mlx5_uars_page *uar,
|
||||
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;
|
||||
}
|
||||
|
||||
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) +
|
||||
sizeof(u64) * cq->wq_ctrl.buf.npages;
|
||||
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);
|
||||
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));
|
||||
kvfree(in);
|
||||
|
||||
if (err)
|
||||
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;
|
||||
|
||||
err_cqwq:
|
||||
|
||||
@@ -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
|
||||
* timeout counter. The default is 0x1312d0
|
||||
* (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 *= 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;
|
||||
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 {
|
||||
/* 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);
|
||||
|
||||
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");
|
||||
return -ENODEV;
|
||||
}
|
||||
} while (try-- > 0);
|
||||
} while (--try > 0);
|
||||
|
||||
netdev_dbg(port->ndev, "MAC Merge verify timeout\n");
|
||||
return -ETIMEDOUT;
|
||||
|
||||
@@ -73,8 +73,11 @@ int mdiobus_register_device(struct mdio_device *mdiodev)
|
||||
return err;
|
||||
|
||||
err = mdiobus_register_reset(mdiodev);
|
||||
if (err)
|
||||
if (err) {
|
||||
gpiod_put(mdiodev->reset_gpio);
|
||||
mdiodev->reset_gpio = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Assert the reset signal */
|
||||
mdio_device_reset(mdiodev, 1);
|
||||
|
||||
@@ -4380,12 +4380,6 @@ static int lan8814_config_init(struct phy_device *phydev)
|
||||
{
|
||||
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 */
|
||||
lanphy_modify_page_reg(phydev, LAN8814_PAGE_PORT_REGS,
|
||||
LAN8814_QSGMII_PCS1G_ANEG_CONFIG,
|
||||
@@ -4471,6 +4465,12 @@ static int lan8814_probe(struct phy_device *phydev)
|
||||
addr, sizeof(struct lan8814_shared_priv));
|
||||
|
||||
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);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@@ -2631,22 +2631,28 @@ static void receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
|
||||
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
|
||||
* stay valid after XDP processing.
|
||||
* 2. XDP doesn't work with partially checksummed packets (refer to
|
||||
* virtnet_xdp_set()), so packets marked as
|
||||
* 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,
|
||||
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);
|
||||
else
|
||||
} else {
|
||||
flags = ((struct virtio_net_common_hdr *)buf)->hdr.flags;
|
||||
skb = receive_small(dev, vi, rq, buf, ctx, len, xdp_xmit, stats);
|
||||
}
|
||||
|
||||
if (unlikely(!skb))
|
||||
return;
|
||||
|
||||
@@ -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);
|
||||
|
||||
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)) &&
|
||||
!tx_compl_param->status) {
|
||||
info->flags |= IEEE80211_TX_STAT_ACK;
|
||||
|
||||
@@ -708,18 +708,13 @@ static int
|
||||
iwl_mld_get_chan_load_from_element(struct iwl_mld *mld,
|
||||
struct ieee80211_bss_conf *link_conf)
|
||||
{
|
||||
struct ieee80211_vif *vif = link_conf->vif;
|
||||
const struct cfg80211_bss_ies *ies;
|
||||
const struct element *bss_load_elem = NULL;
|
||||
const struct ieee80211_bss_load_elem *bss_load;
|
||||
|
||||
guard(rcu)();
|
||||
|
||||
if (ieee80211_vif_link_active(vif, link_conf->link_id))
|
||||
ies = rcu_dereference(link_conf->bss->beacon_ies);
|
||||
else
|
||||
ies = rcu_dereference(link_conf->bss->ies);
|
||||
|
||||
ies = rcu_dereference(link_conf->bss->beacon_ies);
|
||||
if (ies)
|
||||
bss_load_elem = cfg80211_find_elem(WLAN_EID_QBSS_LOAD,
|
||||
ies->data, ies->len);
|
||||
|
||||
@@ -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 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;
|
||||
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)
|
||||
flags |= cck_flag;
|
||||
flags |= is_new_rate ? IWL_MAC_BEACON_CCK
|
||||
: IWL_MAC_BEACON_CCK_V1;
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
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,
|
||||
"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 */
|
||||
ieee80211_remain_on_channel_expired(mvm->hw);
|
||||
iwl_mvm_roc_finished(mvm); /* flush aux queue */
|
||||
list_del(&te_data->list); /* remove from list */
|
||||
te_data->running = false;
|
||||
te_data->vif = NULL;
|
||||
te_data->uid = 0;
|
||||
te_data->id = TE_MAX;
|
||||
list_del(&aux_roc_te->list); /* remove from list */
|
||||
aux_roc_te->running = false;
|
||||
aux_roc_te->vif = NULL;
|
||||
aux_roc_te->uid = 0;
|
||||
aux_roc_te->id = TE_MAX;
|
||||
} else if (le32_to_cpu(notif->action) == TE_V2_NOTIF_HOST_EVENT_START) {
|
||||
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 */
|
||||
} else {
|
||||
IWL_DEBUG_TE(mvm,
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
return (rate_idx >= IWL_FIRST_OFDM_RATE ?
|
||||
rate_idx - IWL_FIRST_OFDM_RATE :
|
||||
rate_idx);
|
||||
if (iwl_fw_lookup_cmd_ver(fw, TX_CMD, 0) > 8)
|
||||
/* In the new rate legacy rates are indexed:
|
||||
* 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)
|
||||
|
||||
@@ -2966,6 +2966,51 @@ mwl8k_cmd_rf_antenna(struct ieee80211_hw *hw, int antenna, int mask)
|
||||
/*
|
||||
* 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_pkt_hdr header;
|
||||
__le16 beacon_len;
|
||||
@@ -2975,17 +3020,33 @@ struct mwl8k_cmd_set_beacon {
|
||||
static int mwl8k_cmd_set_beacon(struct ieee80211_hw *hw,
|
||||
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;
|
||||
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)
|
||||
return -ENOMEM;
|
||||
|
||||
cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_BEACON);
|
||||
cmd->header.length = cpu_to_le16(sizeof(*cmd) + len);
|
||||
cmd->beacon_len = cpu_to_le16(len);
|
||||
memcpy(cmd->beacon, beacon, len);
|
||||
cmd->header.length = cpu_to_le16(sizeof(*cmd) + final_len);
|
||||
cmd->beacon_len = cpu_to_le16(final_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);
|
||||
kfree(cmd);
|
||||
|
||||
@@ -2003,8 +2003,14 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
|
||||
struct ieee80211_sta *sta = control->sta;
|
||||
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) {
|
||||
bss_conf = rcu_dereference(txi->control.vif->link_conf[link]);
|
||||
bss_conf = rcu_dereference(vif->link_conf[link]);
|
||||
if (sta)
|
||||
link_sta = rcu_dereference(sta->link[link]);
|
||||
} else {
|
||||
@@ -2065,13 +2071,13 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
|
||||
return;
|
||||
}
|
||||
|
||||
if (txi->control.vif)
|
||||
hwsim_check_magic(txi->control.vif);
|
||||
if (vif)
|
||||
hwsim_check_magic(vif);
|
||||
if (control->sta)
|
||||
hwsim_check_sta_magic(control->sta);
|
||||
|
||||
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,
|
||||
ARRAY_SIZE(txi->control.rates));
|
||||
|
||||
|
||||
@@ -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.arm_db = vcq->db.db + 1;
|
||||
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);
|
||||
if (err)
|
||||
@@ -612,10 +614,6 @@ static int cq_create(struct mlx5_vdpa_net *ndev, u16 idx, u32 num_ent)
|
||||
if (err)
|
||||
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);
|
||||
kfree(in);
|
||||
return 0;
|
||||
|
||||
@@ -492,7 +492,7 @@ struct ethtool_pause_stats {
|
||||
};
|
||||
|
||||
#define ETHTOOL_MAX_LANES 8
|
||||
/**
|
||||
/*
|
||||
* IEEE 802.3ck/df defines 16 bins for FEC histogram plus one more for
|
||||
* the end-of-list marker, total 17 items
|
||||
*/
|
||||
|
||||
@@ -183,6 +183,7 @@ static inline void mlx5_cq_put(struct mlx5_core_cq *cq)
|
||||
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,
|
||||
u32 *in, int inlen, u32 *out, int outlen);
|
||||
int mlx5_core_create_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
|
||||
|
||||
@@ -2783,6 +2783,11 @@ struct hci_ev_le_per_adv_report {
|
||||
__u8 data[];
|
||||
} __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_MORE_TO_COME 0x01
|
||||
#define LE_PA_DATA_TRUNCATED 0x02
|
||||
|
||||
@@ -53,6 +53,11 @@ static bool enable_6lowpan;
|
||||
static struct l2cap_chan *listen_chan;
|
||||
static DEFINE_MUTEX(set_lock);
|
||||
|
||||
enum {
|
||||
LOWPAN_PEER_CLOSING,
|
||||
LOWPAN_PEER_MAXBITS
|
||||
};
|
||||
|
||||
struct lowpan_peer {
|
||||
struct list_head list;
|
||||
struct rcu_head rcu;
|
||||
@@ -61,6 +66,8 @@ struct lowpan_peer {
|
||||
/* peer addresses in various formats */
|
||||
unsigned char lladdr[ETH_ALEN];
|
||||
struct in6_addr peer_addr;
|
||||
|
||||
DECLARE_BITMAP(flags, LOWPAN_PEER_MAXBITS);
|
||||
};
|
||||
|
||||
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->dev = dev;
|
||||
|
||||
skb_reset_mac_header(local_skb);
|
||||
skb_set_transport_header(local_skb, sizeof(struct ipv6hdr));
|
||||
|
||||
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);
|
||||
|
||||
l2cap_chan_lock(peer->chan);
|
||||
l2cap_chan_close(peer->chan, ENOENT);
|
||||
l2cap_chan_unlock(peer->chan);
|
||||
|
||||
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,
|
||||
struct l2cap_conn **conn)
|
||||
struct l2cap_conn **conn, bool disconnect)
|
||||
{
|
||||
struct hci_conn *hcon;
|
||||
struct hci_dev *hdev;
|
||||
int le_addr_type;
|
||||
int n;
|
||||
|
||||
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)
|
||||
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 */
|
||||
hdev = hci_get_route(addr, BDADDR_ANY, BDADDR_LE_PUBLIC);
|
||||
if (!hdev)
|
||||
return -ENOENT;
|
||||
|
||||
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_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)
|
||||
{
|
||||
struct lowpan_btle_dev *entry;
|
||||
struct lowpan_peer *peer, *tmp_peer, *new_peer;
|
||||
struct list_head peers;
|
||||
struct lowpan_peer *peer;
|
||||
int nchans;
|
||||
|
||||
INIT_LIST_HEAD(&peers);
|
||||
|
||||
/* We make a separate list of peers as the close_cb() will
|
||||
* modify the device peers list so it is better not to mess
|
||||
* with the same list at the same time.
|
||||
/* l2cap_chan_close() cannot be called from RCU, and lock ordering
|
||||
* chan->lock > devices_lock prevents taking write side lock, so copy
|
||||
* then close.
|
||||
*/
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) {
|
||||
list_for_each_entry_rcu(peer, &entry->peers, list) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list)
|
||||
list_for_each_entry_rcu(peer, &entry->peers, list)
|
||||
clear_bit(LOWPAN_PEER_CLOSING, peer->flags);
|
||||
rcu_read_unlock();
|
||||
|
||||
spin_lock(&devices_lock);
|
||||
list_for_each_entry_safe(peer, tmp_peer, &peers, list) {
|
||||
l2cap_chan_close(peer->chan, ENOENT);
|
||||
do {
|
||||
struct l2cap_chan *chans[32];
|
||||
int i;
|
||||
|
||||
list_del_rcu(&peer->list);
|
||||
kfree_rcu(peer, rcu);
|
||||
}
|
||||
spin_unlock(&devices_lock);
|
||||
nchans = 0;
|
||||
|
||||
spin_lock(&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 {
|
||||
@@ -1050,7 +1091,9 @@ static void do_enable_set(struct work_struct *work)
|
||||
|
||||
mutex_lock(&set_lock);
|
||||
if (listen_chan) {
|
||||
l2cap_chan_lock(listen_chan);
|
||||
l2cap_chan_close(listen_chan, 0);
|
||||
l2cap_chan_unlock(listen_chan);
|
||||
l2cap_chan_put(listen_chan);
|
||||
}
|
||||
|
||||
@@ -1103,13 +1146,15 @@ static ssize_t lowpan_control_write(struct file *fp,
|
||||
buf[buf_size] = '\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)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&set_lock);
|
||||
if (listen_chan) {
|
||||
l2cap_chan_lock(listen_chan);
|
||||
l2cap_chan_close(listen_chan, 0);
|
||||
l2cap_chan_unlock(listen_chan);
|
||||
l2cap_chan_put(listen_chan);
|
||||
listen_chan = NULL;
|
||||
}
|
||||
@@ -1140,7 +1185,7 @@ static ssize_t lowpan_control_write(struct file *fp,
|
||||
}
|
||||
|
||||
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)
|
||||
return ret;
|
||||
|
||||
@@ -1271,7 +1316,9 @@ static void __exit bt_6lowpan_exit(void)
|
||||
debugfs_remove(lowpan_control_debugfs);
|
||||
|
||||
if (listen_chan) {
|
||||
l2cap_chan_lock(listen_chan);
|
||||
l2cap_chan_close(listen_chan, 0);
|
||||
l2cap_chan_unlock(listen_chan);
|
||||
l2cap_chan_put(listen_chan);
|
||||
}
|
||||
|
||||
|
||||
@@ -769,21 +769,23 @@ static void find_bis(struct hci_conn *conn, void *data)
|
||||
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;
|
||||
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);
|
||||
if (!d)
|
||||
return -ENOMEM;
|
||||
|
||||
d->big = big;
|
||||
d->big = conn->iso_qos.bcast.big;
|
||||
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_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;
|
||||
}
|
||||
|
||||
if (!d->pa_sync_term && !d->big_sync_term)
|
||||
return 0;
|
||||
|
||||
ret = hci_cmd_sync_queue(hdev, big_terminate_sync, d,
|
||||
terminate_big_destroy);
|
||||
if (ret)
|
||||
@@ -852,8 +857,7 @@ static void bis_cleanup(struct hci_conn *conn)
|
||||
|
||||
hci_le_terminate_big(hdev, conn);
|
||||
} else {
|
||||
hci_le_big_terminate(hdev, conn->iso_qos.bcast.big,
|
||||
conn);
|
||||
hci_le_big_terminate(hdev, 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;
|
||||
break;
|
||||
case CIS_LINK:
|
||||
case BIS_LINK:
|
||||
case PA_LINK:
|
||||
/* conn->src should reflect the local identity address */
|
||||
hci_copy_identity_address(hdev, &conn->src, &conn->src_type);
|
||||
|
||||
/* set proper cleanup function */
|
||||
if (!bacmp(dst, BDADDR_ANY))
|
||||
conn->cleanup = bis_cleanup;
|
||||
else if (conn->role == HCI_ROLE_MASTER)
|
||||
if (conn->role == HCI_ROLE_MASTER)
|
||||
conn->cleanup = cis_cleanup;
|
||||
|
||||
conn->mtu = hdev->iso_mtu ? hdev->iso_mtu :
|
||||
hdev->le_mtu ? hdev->le_mtu : hdev->acl_mtu;
|
||||
conn->mtu = hdev->iso_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;
|
||||
case SCO_LINK:
|
||||
if (lmp_esco_capable(hdev))
|
||||
|
||||
@@ -5843,6 +5843,29 @@ static void hci_le_enh_conn_complete_evt(struct hci_dev *hdev, void *data,
|
||||
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,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
@@ -7001,14 +7024,9 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ev->status != 0x42) {
|
||||
if (ev->status != 0x42)
|
||||
/* Mark PA sync as established */
|
||||
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->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 hci_evt_le_big_sync_lost *ev = data;
|
||||
struct hci_conn *bis, *conn;
|
||||
bool mgmt_conn;
|
||||
struct hci_conn *bis;
|
||||
bool mgmt_conn = false;
|
||||
|
||||
bt_dev_dbg(hdev, "big handle 0x%2.2x", ev->handle);
|
||||
|
||||
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 */
|
||||
while ((bis = hci_conn_hash_lookup_big_state(hdev, ev->handle,
|
||||
BT_CONNECTED,
|
||||
HCI_ROLE_SLAVE))) {
|
||||
mgmt_conn = test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &bis->flags);
|
||||
mgmt_device_disconnected(hdev, &bis->dst, bis->type, bis->dst_type,
|
||||
ev->reason, mgmt_conn);
|
||||
if (!mgmt_conn) {
|
||||
mgmt_conn = test_and_clear_bit(HCI_CONN_MGMT_CONNECTED,
|
||||
&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);
|
||||
hci_disconn_cfm(bis, ev->reason);
|
||||
@@ -7187,6 +7200,9 @@ static const struct hci_le_ev {
|
||||
hci_le_per_adv_report_evt,
|
||||
sizeof(struct hci_ev_le_per_adv_report),
|
||||
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] */
|
||||
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)),
|
||||
|
||||
@@ -6999,7 +6999,7 @@ static void create_pa_complete(struct hci_dev *hdev, void *data, int err)
|
||||
|
||||
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);
|
||||
|
||||
if (!err)
|
||||
|
||||
@@ -497,6 +497,7 @@ void l2cap_chan_hold(struct l2cap_chan *c)
|
||||
|
||||
kref_get(&c->kref);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(l2cap_chan_hold);
|
||||
|
||||
struct l2cap_chan *l2cap_chan_hold_unless_zero(struct l2cap_chan *c)
|
||||
{
|
||||
|
||||
@@ -9497,6 +9497,7 @@ void mgmt_index_removed(struct hci_dev *hdev)
|
||||
cancel_delayed_work_sync(&hdev->discov_off);
|
||||
cancel_delayed_work_sync(&hdev->service_cache);
|
||||
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)
|
||||
|
||||
@@ -811,6 +811,10 @@ static void __netpoll_cleanup(struct netpoll *np)
|
||||
if (!npinfo)
|
||||
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)) {
|
||||
const struct net_device_ops *ops;
|
||||
|
||||
@@ -820,8 +824,7 @@ static void __netpoll_cleanup(struct netpoll *np)
|
||||
|
||||
RCU_INIT_POINTER(np->dev->npinfo, NULL);
|
||||
call_rcu(&npinfo->rcu, rcu_cleanup_netpoll_info);
|
||||
} else
|
||||
RCU_INIT_POINTER(np->dev->npinfo, NULL);
|
||||
}
|
||||
|
||||
skb_pool_flush(np);
|
||||
}
|
||||
|
||||
@@ -176,7 +176,8 @@ static struct sk_buff *brcm_tag_rcv_ll(struct sk_buff *skb,
|
||||
/* Remove Broadcom tag and update checksum */
|
||||
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;
|
||||
}
|
||||
@@ -250,7 +251,8 @@ static struct sk_buff *brcm_leg_tag_rcv(struct sk_buff *skb,
|
||||
/* Remove Broadcom tag and update checksum */
|
||||
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);
|
||||
|
||||
|
||||
@@ -259,6 +259,7 @@ static int tls_handshake_accept(struct handshake_req *req,
|
||||
|
||||
out_cancel:
|
||||
genlmsg_cancel(msg, hdr);
|
||||
nlmsg_free(msg);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -320,6 +320,9 @@ static void send_hsr_supervision_frame(struct hsr_port *port,
|
||||
}
|
||||
|
||||
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_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;
|
||||
/* TODO: Why 12 in HSRv0? */
|
||||
/* HSRv0 has 6 unused bytes after the MAC */
|
||||
hsr_stag->tlv.HSR_TLV_length = hsr->prot_version ?
|
||||
sizeof(struct hsr_sup_payload) : 12;
|
||||
|
||||
|
||||
@@ -262,15 +262,23 @@ static struct sk_buff *prp_fill_rct(struct sk_buff *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)
|
||||
{
|
||||
int path_id;
|
||||
|
||||
if (port->type == HSR_PT_SLAVE_A)
|
||||
path_id = 0;
|
||||
else
|
||||
path_id = 1;
|
||||
if (port->hsr->prot_version) {
|
||||
if (port->type == HSR_PT_SLAVE_A)
|
||||
path_id = 0;
|
||||
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);
|
||||
}
|
||||
@@ -304,7 +312,7 @@ static struct sk_buff *hsr_fill_tag(struct sk_buff *skb,
|
||||
else
|
||||
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);
|
||||
hsr_ethhdr->hsr_tag.sequence_nr = htons(frame->sequence_nr);
|
||||
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);
|
||||
|
||||
/* 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);
|
||||
} else if (port->dev->features & NETIF_F_HW_HSR_TAG_INS) {
|
||||
return skb_clone(frame->skb_std, GFP_ATOMIC);
|
||||
|
||||
@@ -607,6 +607,11 @@ static void fnhe_remove_oldest(struct fnhe_hash_bucket *hash)
|
||||
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);
|
||||
*oldest_p = oldest->fnhe_next;
|
||||
kfree_rcu(oldest, rcu);
|
||||
|
||||
@@ -223,6 +223,10 @@ static int ieee80211_can_powered_addr_change(struct ieee80211_sub_if_data *sdata
|
||||
if (netif_carrier_ok(sdata->dev))
|
||||
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 */
|
||||
list_for_each_entry(roc, &local->roc_list, list) {
|
||||
if (roc->sdata != sdata)
|
||||
@@ -242,12 +246,16 @@ static int ieee80211_can_powered_addr_change(struct ieee80211_sub_if_data *sdata
|
||||
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) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
/* More interface types could be added here but changing the
|
||||
* address while powered makes the most sense in client modes.
|
||||
*/
|
||||
/* refuse while connecting */
|
||||
if (sdata->u.mgd.auth_data || sdata->u.mgd.assoc_data)
|
||||
return -EBUSY;
|
||||
break;
|
||||
default:
|
||||
ret = -EOPNOTSUPP;
|
||||
|
||||
@@ -5360,10 +5360,14 @@ void ieee80211_rx_list(struct ieee80211_hw *hw, struct ieee80211_sta *pubsta,
|
||||
if (WARN_ON(!local->started))
|
||||
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
|
||||
* we probably can't have a valid rate here anyway.
|
||||
* Validate the rate, unless there was a PLCP error which may
|
||||
* have an invalid rate or the PSDU was not capture and may be
|
||||
* missing rate information.
|
||||
*/
|
||||
|
||||
switch (status->encoding) {
|
||||
|
||||
@@ -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);
|
||||
unsigned char *b = skb_tail_pointer(skb);
|
||||
const struct tcf_connmark_parms *parms;
|
||||
struct tc_connmark opt = {
|
||||
.index = ci->tcf_index,
|
||||
.refcnt = refcount_read(&ci->tcf_refcnt) - ref,
|
||||
.bindcnt = atomic_read(&ci->tcf_bindcnt) - bind,
|
||||
};
|
||||
struct tc_connmark opt;
|
||||
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();
|
||||
parms = rcu_dereference(ci->parms);
|
||||
|
||||
|
||||
@@ -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);
|
||||
struct tcf_ife_info *ife = to_ife(a);
|
||||
struct tcf_ife_params *p;
|
||||
struct tc_ife opt = {
|
||||
.index = ife->tcf_index,
|
||||
.refcnt = refcount_read(&ife->tcf_refcnt) - ref,
|
||||
.bindcnt = atomic_read(&ife->tcf_bindcnt) - bind,
|
||||
};
|
||||
struct tc_ife opt;
|
||||
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);
|
||||
opt.action = ife->tcf_action;
|
||||
p = rcu_dereference_protected(ife->params,
|
||||
|
||||
@@ -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");
|
||||
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);
|
||||
if (IS_ERR(q))
|
||||
return PTR_ERR(q);
|
||||
|
||||
@@ -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,
|
||||
struct sk_buff *skb,
|
||||
const struct netdev_queue *txq,
|
||||
int *packets)
|
||||
int *packets, int budget)
|
||||
{
|
||||
int bytelimit = qdisc_avail_bulklimit(txq) - skb->len;
|
||||
int cnt = 0;
|
||||
|
||||
while (bytelimit > 0) {
|
||||
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 */
|
||||
skb->next = nskb;
|
||||
skb = nskb;
|
||||
(*packets)++; /* GSO counts as one pkt */
|
||||
if (++cnt >= budget)
|
||||
break;
|
||||
}
|
||||
(*packets) += cnt;
|
||||
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.
|
||||
*/
|
||||
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;
|
||||
struct sk_buff *skb = NULL;
|
||||
@@ -295,7 +298,7 @@ validate:
|
||||
if (skb) {
|
||||
bulk:
|
||||
if (qdisc_may_bulk(q))
|
||||
try_bulk_dequeue_skb(q, skb, txq, packets);
|
||||
try_bulk_dequeue_skb(q, skb, txq, packets, budget);
|
||||
else
|
||||
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.
|
||||
*
|
||||
*/
|
||||
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;
|
||||
struct netdev_queue *txq;
|
||||
@@ -396,7 +399,7 @@ static inline bool qdisc_restart(struct Qdisc *q, int *packets)
|
||||
bool validate;
|
||||
|
||||
/* Dequeue packet */
|
||||
skb = dequeue_skb(q, &validate, packets);
|
||||
skb = dequeue_skb(q, &validate, packets, budget);
|
||||
if (unlikely(!skb))
|
||||
return false;
|
||||
|
||||
@@ -414,7 +417,7 @@ void __qdisc_run(struct Qdisc *q)
|
||||
int quota = READ_ONCE(net_hotdata.dev_tx_weight);
|
||||
int packets;
|
||||
|
||||
while (qdisc_restart(q, &packets)) {
|
||||
while (qdisc_restart(q, &packets, quota)) {
|
||||
quota -= packets;
|
||||
if (quota <= 0) {
|
||||
if (q->flags & TCQ_F_NOLOCK)
|
||||
|
||||
@@ -486,6 +486,7 @@ void sctp_transport_update_rto(struct sctp_transport *tp, __u32 rtt)
|
||||
|
||||
if (tp->rttvar || tp->srtt) {
|
||||
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
|
||||
* RTTVAR <- (1 - RTO.Beta) * RTTVAR + RTO.Beta * |SRTT - 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
|
||||
* 1/8, rto_alpha would be expressed as 3.
|
||||
*/
|
||||
tp->rttvar = tp->rttvar - (tp->rttvar >> net->sctp.rto_beta)
|
||||
+ (((__u32)abs((__s64)tp->srtt - (__s64)rtt)) >> net->sctp.rto_beta);
|
||||
tp->srtt = tp->srtt - (tp->srtt >> net->sctp.rto_alpha)
|
||||
+ (rtt >> net->sctp.rto_alpha);
|
||||
rto_beta = READ_ONCE(net->sctp.rto_beta);
|
||||
if (rto_beta < 32)
|
||||
tp->rttvar = tp->rttvar - (tp->rttvar >> rto_beta)
|
||||
+ (((__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 {
|
||||
/* 6.3.1 C2) When the first RTT measurement R is made, set
|
||||
* SRTT <- R, RTTVAR <- R/2.
|
||||
|
||||
@@ -890,6 +890,7 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini)
|
||||
return SMC_CLC_DECL_CNFERR;
|
||||
}
|
||||
pclc_base->hdr.typev1 = SMC_TYPE_N;
|
||||
ini->smc_type_v1 = SMC_TYPE_N;
|
||||
} else {
|
||||
pclc_base->iparea_offset = htons(sizeof(*pclc_smcd));
|
||||
plen += sizeof(*pclc_prfx) +
|
||||
|
||||
@@ -238,7 +238,7 @@ static int __strp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb,
|
||||
strp_parser_err(strp, -EMSGSIZE, desc);
|
||||
break;
|
||||
} 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
|
||||
* greater than zero)
|
||||
*/
|
||||
|
||||
@@ -145,7 +145,9 @@ void tipc_net_finalize_work(struct work_struct *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);
|
||||
rtnl_unlock();
|
||||
}
|
||||
|
||||
void tipc_net_stop(struct net *net)
|
||||
|
||||
@@ -145,6 +145,7 @@ enum unix_vertex_index {
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -153,6 +154,7 @@ static void unix_add_edge(struct scm_fp_list *fpl, struct unix_edge *edge)
|
||||
if (!vertex) {
|
||||
vertex = list_first_entry(&fpl->vertices, typeof(*vertex), entry);
|
||||
vertex->index = unix_vertex_unvisited_index;
|
||||
vertex->scc_index = ++unix_vertex_max_scc_index;
|
||||
vertex->out_degree = 0;
|
||||
INIT_LIST_HEAD(&vertex->edges);
|
||||
INIT_LIST_HEAD(&vertex->scc_entry);
|
||||
@@ -489,10 +491,15 @@ prev_vertex:
|
||||
scc_dead = unix_vertex_dead(v);
|
||||
}
|
||||
|
||||
if (scc_dead)
|
||||
if (scc_dead) {
|
||||
unix_collect_skb(&scc, hitlist);
|
||||
else if (!unix_graph_maybe_cyclic)
|
||||
unix_graph_maybe_cyclic = unix_scc_cyclic(&scc);
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
@@ -507,6 +514,7 @@ static void unix_walk_scc(struct sk_buff_head *hitlist)
|
||||
unsigned long last_index = UNIX_VERTEX_INDEX_START;
|
||||
|
||||
unix_graph_maybe_cyclic = false;
|
||||
unix_vertex_max_scc_index = UNIX_VERTEX_INDEX_START;
|
||||
|
||||
/* Visit every vertex exactly once.
|
||||
* __unix_walk_scc() moves visited vertices to unix_visited_vertices.
|
||||
|
||||
@@ -861,6 +861,18 @@ class TypeIndexedArray(Type):
|
||||
return [f"{member} = {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):
|
||||
def _complex_member_type(self, ri):
|
||||
|
||||
@@ -18,6 +18,7 @@ TEST_PROGS := \
|
||||
netcons_fragmented_msg.sh \
|
||||
netcons_overflow.sh \
|
||||
netcons_sysdata.sh \
|
||||
netcons_torture.sh \
|
||||
netpoll_basic.py \
|
||||
ping.py \
|
||||
psp.py \
|
||||
|
||||
@@ -14,6 +14,7 @@ TEST_PROGS := \
|
||||
dev_addr_lists.sh \
|
||||
mode-1-recovery-updelay.sh \
|
||||
mode-2-recovery-updelay.sh \
|
||||
netcons_over_bonding.sh \
|
||||
# end of TEST_PROGS
|
||||
|
||||
TEST_FILES := \
|
||||
@@ -24,6 +25,7 @@ TEST_FILES := \
|
||||
|
||||
TEST_INCLUDES := \
|
||||
../../../net/lib.sh \
|
||||
../lib/sh/lib_netcons.sh \
|
||||
../../../net/forwarding/lib.sh \
|
||||
# end of TEST_INCLUDES
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
CONFIG_BONDING=y
|
||||
CONFIG_BRIDGE=y
|
||||
CONFIG_CONFIGFS_FS=y
|
||||
CONFIG_DUMMY=y
|
||||
CONFIG_INET_ESP=y
|
||||
CONFIG_INET_ESP_OFFLOAD=y
|
||||
@@ -9,6 +10,9 @@ CONFIG_MACVLAN=y
|
||||
CONFIG_NET_ACT_GACT=y
|
||||
CONFIG_NET_CLS_FLOWER=y
|
||||
CONFIG_NET_CLS_MATCHALL=m
|
||||
CONFIG_NETCONSOLE=m
|
||||
CONFIG_NETCONSOLE_DYNAMIC=y
|
||||
CONFIG_NETCONSOLE_EXTENDED_LOG=y
|
||||
CONFIG_NETDEVSIM=m
|
||||
CONFIG_NET_SCH_INGRESS=y
|
||||
CONFIG_NLMON=y
|
||||
|
||||
361
tools/testing/selftests/drivers/net/bonding/netcons_over_bonding.sh
Executable file
361
tools/testing/selftests/drivers/net/bonding/netcons_over_bonding.sh
Executable 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}"
|
||||
@@ -11,9 +11,11 @@ set -euo pipefail
|
||||
LIBDIR=$(dirname "$(readlink -e "${BASH_SOURCE[0]}")")
|
||||
|
||||
SRCIF="" # to be populated later
|
||||
SRCIP="" # to be populated later
|
||||
SRCIP4="192.0.2.1"
|
||||
SRCIP6="fc00::1"
|
||||
DSTIF="" # to be populated later
|
||||
DSTIP="" # to be populated later
|
||||
DSTIP4="192.0.2.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=""
|
||||
|
||||
# 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_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_LINK="/sys/bus/netdevsim/link_device"
|
||||
|
||||
# Used to create and delete namespaces
|
||||
source "${LIBDIR}"/../../../../net/lib.sh
|
||||
|
||||
# Create netdevsim interfaces
|
||||
create_ifaces() {
|
||||
|
||||
echo "$NSIM_DEV_2_ID" > "$NSIM_DEV_SYS_NEW"
|
||||
echo "$NSIM_DEV_1_ID" > "$NSIM_DEV_SYS_NEW"
|
||||
udevadm settle 2> /dev/null || true
|
||||
@@ -113,31 +121,38 @@ function set_network() {
|
||||
configure_ip
|
||||
}
|
||||
|
||||
function create_dynamic_target() {
|
||||
local FORMAT=${1:-"extended"}
|
||||
function _create_dynamic_target() {
|
||||
local FORMAT="${1:?FORMAT parameter required}"
|
||||
local NCPATH="${2:?NCPATH parameter required}"
|
||||
|
||||
DSTMAC=$(ip netns exec "${NAMESPACE}" \
|
||||
ip link show "${DSTIF}" | awk '/ether/ {print $2}')
|
||||
|
||||
# Create a dynamic target
|
||||
mkdir "${NETCONS_PATH}"
|
||||
mkdir "${NCPATH}"
|
||||
|
||||
echo "${DSTIP}" > "${NETCONS_PATH}"/remote_ip
|
||||
echo "${SRCIP}" > "${NETCONS_PATH}"/local_ip
|
||||
echo "${DSTMAC}" > "${NETCONS_PATH}"/remote_mac
|
||||
echo "${SRCIF}" > "${NETCONS_PATH}"/dev_name
|
||||
echo "${DSTIP}" > "${NCPATH}"/remote_ip
|
||||
echo "${SRCIP}" > "${NCPATH}"/local_ip
|
||||
echo "${DSTMAC}" > "${NCPATH}"/remote_mac
|
||||
echo "${SRCIF}" > "${NCPATH}"/dev_name
|
||||
|
||||
if [ "${FORMAT}" == "basic" ]
|
||||
then
|
||||
# Basic target does not support release
|
||||
echo 0 > "${NETCONS_PATH}"/release
|
||||
echo 0 > "${NETCONS_PATH}"/extended
|
||||
echo 0 > "${NCPATH}"/release
|
||||
echo 0 > "${NCPATH}"/extended
|
||||
elif [ "${FORMAT}" == "extended" ]
|
||||
then
|
||||
echo 1 > "${NETCONS_PATH}"/extended
|
||||
echo 1 > "${NCPATH}"/extended
|
||||
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
|
||||
# load the netconsole driver configuration. The console message
|
||||
@@ -185,14 +200,26 @@ function do_cleanup() {
|
||||
echo "${DEFAULT_PRINTK_VALUES}" > /proc/sys/kernel/printk
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
function cleanup_netcons() {
|
||||
# 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
|
||||
find "${NETCONS_PATH}/userdata/" -mindepth 1 -type d -delete
|
||||
# Remove the configfs entry
|
||||
rmdir "${NETCONS_PATH}"
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
cleanup_netcons
|
||||
do_cleanup
|
||||
}
|
||||
|
||||
@@ -369,3 +396,24 @@ function wait_for_port() {
|
||||
# more frequently on IPv6
|
||||
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
|
||||
}
|
||||
|
||||
130
tools/testing/selftests/drivers/net/netcons_torture.sh
Executable file
130
tools/testing/selftests/drivers/net/netcons_torture.sh
Executable 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}"
|
||||
@@ -176,6 +176,8 @@ run_test()
|
||||
local rcv_dmac=$(mac_get $rcv_if_name)
|
||||
local should_receive
|
||||
|
||||
setup_wait
|
||||
|
||||
tcpdump_start $rcv_if_name
|
||||
|
||||
mc_route_prepare $send_if_name
|
||||
|
||||
@@ -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);
|
||||
if (bw < 0) {
|
||||
if (cfg_rcv_trunc)
|
||||
return 0;
|
||||
/* expected reset, continue to read */
|
||||
if (cfg_rcv_trunc &&
|
||||
(errno == ECONNRESET ||
|
||||
errno == EPIPE)) {
|
||||
fds.events &= ~POLLOUT;
|
||||
continue;
|
||||
}
|
||||
|
||||
perror("write");
|
||||
return 111;
|
||||
}
|
||||
@@ -737,8 +743,10 @@ static int copyfd_io_poll(int infd, int peerfd, int outfd,
|
||||
}
|
||||
|
||||
if (fds.revents & (POLLERR | POLLNVAL)) {
|
||||
if (cfg_rcv_trunc)
|
||||
return 0;
|
||||
if (cfg_rcv_trunc) {
|
||||
fds.events &= ~(POLLERR | POLLNVAL);
|
||||
continue;
|
||||
}
|
||||
fprintf(stderr, "Unexpected revents: "
|
||||
"POLLERR/POLLNVAL(%x)\n", fds.revents);
|
||||
return 5;
|
||||
@@ -1433,7 +1441,7 @@ static void parse_opts(int argc, char **argv)
|
||||
*/
|
||||
if (cfg_truncate < 0) {
|
||||
cfg_rcv_trunc = true;
|
||||
signal(SIGPIPE, handle_signal);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
}
|
||||
break;
|
||||
case 'j':
|
||||
|
||||
@@ -492,7 +492,7 @@ do_transfer()
|
||||
"than expected (${expect_synrx})"
|
||||
retc=1
|
||||
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
|
||||
mptcp_lib_pr_fail "lower MPC ACK rx (${stat_ackrx_now_l})" \
|
||||
"than expected (${expect_ackrx})"
|
||||
|
||||
@@ -2532,7 +2532,7 @@ remove_tests()
|
||||
if reset "remove single subflow"; then
|
||||
pm_nl_set_limits $ns1 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 \
|
||||
run_tests $ns1 $ns2 10.0.1.1
|
||||
chk_join_nr 1 1 1
|
||||
@@ -2545,8 +2545,8 @@ remove_tests()
|
||||
if reset "remove multiple subflows"; then
|
||||
pm_nl_set_limits $ns1 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.3.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,backup
|
||||
addr_nr_ns2=-2 speed=slow \
|
||||
run_tests $ns1 $ns2 10.0.1.1
|
||||
chk_join_nr 2 2 2
|
||||
@@ -2557,7 +2557,7 @@ remove_tests()
|
||||
# single address, remove
|
||||
if reset "remove single address"; then
|
||||
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
|
||||
addr_nr_ns1=-1 speed=slow \
|
||||
run_tests $ns1 $ns2 10.0.1.1
|
||||
@@ -2570,9 +2570,9 @@ remove_tests()
|
||||
# subflow and signal, remove
|
||||
if reset "remove subflow and signal"; then
|
||||
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_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 \
|
||||
run_tests $ns1 $ns2 10.0.1.1
|
||||
chk_join_nr 2 2 2
|
||||
@@ -2584,10 +2584,10 @@ remove_tests()
|
||||
# subflows and signal, remove
|
||||
if reset "remove subflows and signal"; then
|
||||
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_add_endpoint $ns2 10.0.3.2 flags subflow
|
||||
pm_nl_add_endpoint $ns2 10.0.4.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,backup
|
||||
addr_nr_ns1=-1 addr_nr_ns2=-2 speed=10 \
|
||||
run_tests $ns1 $ns2 10.0.1.1
|
||||
chk_join_nr 3 3 3
|
||||
@@ -2599,9 +2599,9 @@ remove_tests()
|
||||
# addresses remove
|
||||
if reset "remove addresses"; then
|
||||
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.3.1 flags signal
|
||||
pm_nl_add_endpoint $ns1 10.0.4.1 flags signal
|
||||
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,backup
|
||||
pm_nl_add_endpoint $ns1 10.0.4.1 flags signal,backup
|
||||
pm_nl_set_limits $ns2 3 3
|
||||
addr_nr_ns1=-3 speed=10 \
|
||||
run_tests $ns1 $ns2 10.0.1.1
|
||||
@@ -2614,10 +2614,10 @@ remove_tests()
|
||||
# invalid addresses remove
|
||||
if reset "remove invalid addresses"; then
|
||||
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
|
||||
pm_nl_add_endpoint $ns1 224.0.0.1 flags signal
|
||||
pm_nl_add_endpoint $ns1 10.0.3.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,backup
|
||||
pm_nl_set_limits $ns2 2 2
|
||||
addr_nr_ns1=-3 speed=10 \
|
||||
run_tests $ns1 $ns2 10.0.1.1
|
||||
@@ -2631,10 +2631,10 @@ remove_tests()
|
||||
# subflows and signal, flush
|
||||
if reset "flush subflows and signal"; then
|
||||
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_add_endpoint $ns2 10.0.3.2 flags subflow
|
||||
pm_nl_add_endpoint $ns2 10.0.4.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,backup
|
||||
addr_nr_ns1=-8 addr_nr_ns2=-8 speed=slow \
|
||||
run_tests $ns1 $ns2 10.0.1.1
|
||||
chk_join_nr 3 3 3
|
||||
@@ -2647,9 +2647,9 @@ remove_tests()
|
||||
if reset "flush subflows"; then
|
||||
pm_nl_set_limits $ns1 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.3.2 flags subflow
|
||||
pm_nl_add_endpoint $ns2 10.0.4.2 flags subflow
|
||||
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,backup
|
||||
pm_nl_add_endpoint $ns2 10.0.4.2 flags subflow,backup
|
||||
addr_nr_ns1=-8 addr_nr_ns2=-8 speed=slow \
|
||||
run_tests $ns1 $ns2 10.0.1.1
|
||||
chk_join_nr 3 3 3
|
||||
@@ -2666,9 +2666,9 @@ remove_tests()
|
||||
# addresses flush
|
||||
if reset "flush addresses"; then
|
||||
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.3.1 flags signal
|
||||
pm_nl_add_endpoint $ns1 10.0.4.1 flags signal
|
||||
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,backup
|
||||
pm_nl_add_endpoint $ns1 10.0.4.1 flags signal,backup
|
||||
pm_nl_set_limits $ns2 3 3
|
||||
addr_nr_ns1=-8 addr_nr_ns2=-8 speed=slow \
|
||||
run_tests $ns1 $ns2 10.0.1.1
|
||||
@@ -2681,9 +2681,9 @@ remove_tests()
|
||||
# invalid addresses flush
|
||||
if reset "flush invalid addresses"; then
|
||||
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.3.1 flags signal
|
||||
pm_nl_add_endpoint $ns1 10.0.14.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,backup
|
||||
pm_nl_add_endpoint $ns1 10.0.14.1 flags signal,backup
|
||||
pm_nl_set_limits $ns2 3 3
|
||||
addr_nr_ns1=-8 speed=slow \
|
||||
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
|
||||
set_userspace_pm $ns1
|
||||
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
|
||||
local tests_pid=$!
|
||||
wait_mpj $ns1
|
||||
@@ -3831,7 +3831,7 @@ userspace_tests()
|
||||
chk_mptcp_info subflows 0 subflows 0
|
||||
chk_subflows_total 1 1
|
||||
kill_events_pids
|
||||
mptcp_lib_kill_wait $tests_pid
|
||||
mptcp_lib_kill_group_wait $tests_pid
|
||||
fi
|
||||
|
||||
# userspace pm create destroy subflow
|
||||
@@ -3839,7 +3839,7 @@ userspace_tests()
|
||||
continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then
|
||||
set_userspace_pm $ns2
|
||||
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
|
||||
local tests_pid=$!
|
||||
wait_mpj $ns2
|
||||
@@ -3859,7 +3859,7 @@ userspace_tests()
|
||||
chk_mptcp_info subflows 0 subflows 0
|
||||
chk_subflows_total 1 1
|
||||
kill_events_pids
|
||||
mptcp_lib_kill_wait $tests_pid
|
||||
mptcp_lib_kill_group_wait $tests_pid
|
||||
fi
|
||||
|
||||
# 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
|
||||
set_userspace_pm $ns2
|
||||
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
|
||||
local tests_pid=$!
|
||||
wait_mpj $ns2
|
||||
@@ -3880,7 +3880,7 @@ userspace_tests()
|
||||
chk_mptcp_info subflows 1 subflows 1
|
||||
chk_subflows_total 2 2
|
||||
kill_events_pids
|
||||
mptcp_lib_kill_wait $tests_pid
|
||||
mptcp_lib_kill_group_wait $tests_pid
|
||||
fi
|
||||
|
||||
# userspace pm remove initial subflow
|
||||
@@ -3888,7 +3888,7 @@ userspace_tests()
|
||||
continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then
|
||||
set_userspace_pm $ns2
|
||||
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
|
||||
local tests_pid=$!
|
||||
wait_mpj $ns2
|
||||
@@ -3904,7 +3904,7 @@ userspace_tests()
|
||||
chk_mptcp_info subflows 1 subflows 1
|
||||
chk_subflows_total 1 1
|
||||
kill_events_pids
|
||||
mptcp_lib_kill_wait $tests_pid
|
||||
mptcp_lib_kill_group_wait $tests_pid
|
||||
fi
|
||||
|
||||
# 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
|
||||
set_userspace_pm $ns1
|
||||
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
|
||||
local tests_pid=$!
|
||||
wait_mpj $ns1
|
||||
@@ -3930,7 +3930,7 @@ userspace_tests()
|
||||
chk_mptcp_info subflows 1 subflows 1
|
||||
chk_subflows_total 1 1
|
||||
kill_events_pids
|
||||
mptcp_lib_kill_wait $tests_pid
|
||||
mptcp_lib_kill_group_wait $tests_pid
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -3943,7 +3943,7 @@ endpoint_tests()
|
||||
pm_nl_set_limits $ns1 2 2
|
||||
pm_nl_set_limits $ns2 2 2
|
||||
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
|
||||
local tests_pid=$!
|
||||
|
||||
@@ -3960,7 +3960,7 @@ endpoint_tests()
|
||||
pm_nl_add_endpoint $ns2 10.0.2.2 flags signal
|
||||
pm_nl_check_endpoint "modif is allowed" \
|
||||
$ns2 10.0.2.2 id 1 flags signal
|
||||
mptcp_lib_kill_wait $tests_pid
|
||||
mptcp_lib_kill_group_wait $tests_pid
|
||||
fi
|
||||
|
||||
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_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
|
||||
{ test_linkfail=4 speed=5 \
|
||||
{ test_linkfail=128 speed=5 \
|
||||
run_tests $ns1 $ns2 10.0.1.1 & } 2>/dev/null
|
||||
local tests_pid=$!
|
||||
|
||||
@@ -4015,7 +4015,7 @@ endpoint_tests()
|
||||
chk_mptcp_info subflows 3 subflows 3
|
||||
done
|
||||
|
||||
mptcp_lib_kill_wait $tests_pid
|
||||
mptcp_lib_kill_group_wait $tests_pid
|
||||
|
||||
kill_events_pids
|
||||
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
|
||||
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
|
||||
{ test_linkfail=4 speed=5 \
|
||||
{ test_linkfail=128 speed=5 \
|
||||
run_tests $ns1 $ns2 10.0.1.1 & } 2>/dev/null
|
||||
local tests_pid=$!
|
||||
|
||||
@@ -4089,7 +4089,7 @@ endpoint_tests()
|
||||
wait_mpj $ns2
|
||||
chk_subflow_nr "after re-re-add ID 0" 3
|
||||
chk_mptcp_info subflows 3 subflows 3
|
||||
mptcp_lib_kill_wait $tests_pid
|
||||
mptcp_lib_kill_group_wait $tests_pid
|
||||
|
||||
kill_events_pids
|
||||
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
|
||||
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
|
||||
{ test_linkfail=4 speed=20 \
|
||||
{ test_linkfail=128 speed=20 \
|
||||
run_tests $ns1 $ns2 10.0.1.1 & } 2>/dev/null
|
||||
local tests_pid=$!
|
||||
|
||||
@@ -4137,7 +4137,7 @@ endpoint_tests()
|
||||
wait_mpj $ns2
|
||||
pm_nl_add_endpoint $ns1 10.0.3.1 id 2 flags signal
|
||||
wait_mpj $ns2
|
||||
mptcp_lib_kill_wait $tests_pid
|
||||
mptcp_lib_kill_group_wait $tests_pid
|
||||
|
||||
join_syn_tx=3 join_connect_err=1 \
|
||||
chk_join_nr 2 2 2
|
||||
|
||||
@@ -350,6 +350,27 @@ mptcp_lib_kill_wait() {
|
||||
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
|
||||
mptcp_lib_is_v6() {
|
||||
[ -z "${1##*:*}" ]
|
||||
|
||||
@@ -961,5 +961,49 @@
|
||||
"teardown": [
|
||||
"$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"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user