mirror of https://github.com/torvalds/linux.git
Including fixes from bluetooth.
Quite calm week. No new regression under investigation.
Current release - regressions:
- eth: revert "igb: Disable threaded IRQ for igb_msix_other"
Current release - new code bugs:
- bluetooth: btintel: direct exception event to bluetooth stack
Previous releases - regressions:
- core: fix data-races around sk->sk_forward_alloc
- netlink: terminate outstanding dump on socket close
- mptcp: error out earlier on disconnect
- vsock: fix accept_queue memory leak
- phylink: ensure PHY momentary link-fails are handled
- eth: mlx5:
- fix null-ptr-deref in add rule err flow
- lock FTE when checking if active
- eth: dwmac-mediatek: fix inverted handling of mediatek,mac-wol
Previous releases - always broken:
- sched: fix u32's systematic failure to free IDR entries for hnodes.
- sctp: fix possible UAF in sctp_v6_available()
- eth: bonding: add ns target multicast address to slave device
- eth: mlx5: fix msix vectors to respect platform limit
- eth: icssg-prueth: fix 1 PPS sync
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
-----BEGIN PGP SIGNATURE-----
iQJGBAABCAAwFiEEg1AjqC77wbdLX2LbKSR5jcyPE6QFAmc174YSHHBhYmVuaUBy
ZWRoYXQuY29tAAoJECkkeY3MjxOkgKIP/3Lk1byZ0dKvxsvyBBDeF7yBOsKRsjLt
XfrkcxkS/nloDkh8hM8gLiXjzHuHSo8p7YQ8eaZ215FAozkQbTHnyVUiokDY4vqz
VwCqcHZBTCVZNntOK//lP20wE/FDPrLrRIAflshXHuJv+GBZDKUrjBiyiWhyXltv
slcj7pW9mQyk/AaRW2n3jF985mBxgSXzNI1agDonq/+yP2R35GMO+jIqJHZ9CLH3
GZakZs6ZVWqKbk3/U9qhH9nZsVwBt18eqwkaFYszOc8eMlSp0j9yLmdPfbYcLjbe
tIu/wTF70iHlgw/fbPMWA6dsaf/vN9U96qG3YRH+zwvWUGFYcq/gRSeXceI6/N5u
EAn8Y1IKXiCdCLd1iRyYZqRhHhnpCkbnx9TURdsCclbFW9bf+BU0MjEP3xfq84sD
gbO0RXg4ZS2uUFC4EdNkKIMyqLkMcwQMkioGlUM14oXpU0mQDh3BQrS6yrOvH3d6
YewK7viNYpUlRt54ISTSFSVDff0AAHIWSlNOdH5xLD6YosA+aCJk6icTlmINlx1a
+ccPDY+dH0Dzwx9n0L6hPodVZeax1elnYLlhkgEFgh8v9Tz8TDjCAN2iI/R1A+QJ
r80OZG5qXY89BsCvBXz35svDnFucDkIMupVW88kbfgWeRZrzlFn44CFnLT3n08iT
KMNrKktGlXCg
=2o5W
-----END PGP SIGNATURE-----
Merge tag 'net-6.12-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
Pull networking fixes from Paolo Abeni:
"Including fixes from bluetooth.
Quite calm week. No new regression under investigation.
Current release - regressions:
- eth: revert "igb: Disable threaded IRQ for igb_msix_other"
Current release - new code bugs:
- bluetooth: btintel: direct exception event to bluetooth stack
Previous releases - regressions:
- core: fix data-races around sk->sk_forward_alloc
- netlink: terminate outstanding dump on socket close
- mptcp: error out earlier on disconnect
- vsock: fix accept_queue memory leak
- phylink: ensure PHY momentary link-fails are handled
- eth: mlx5:
- fix null-ptr-deref in add rule err flow
- lock FTE when checking if active
- eth: dwmac-mediatek: fix inverted handling of mediatek,mac-wol
Previous releases - always broken:
- sched: fix u32's systematic failure to free IDR entries for hnodes.
- sctp: fix possible UAF in sctp_v6_available()
- eth: bonding: add ns target multicast address to slave device
- eth: mlx5: fix msix vectors to respect platform limit
- eth: icssg-prueth: fix 1 PPS sync"
* tag 'net-6.12-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net: (38 commits)
net: sched: u32: Add test case for systematic hnode IDR leaks
selftests: bonding: add ns multicast group testing
bonding: add ns target multicast address to slave device
net: ti: icssg-prueth: Fix 1 PPS sync
stmmac: dwmac-intel-plat: fix call balance of tx_clk handling routines
net: Make copy_safe_from_sockptr() match documentation
net: stmmac: dwmac-mediatek: Fix inverted handling of mediatek,mac-wol
ipmr: Fix access to mfc_cache_list without lock held
samples: pktgen: correct dev to DEV
net: phylink: ensure PHY momentary link-fails are handled
mptcp: pm: use _rcu variant under rcu_read_lock
mptcp: hold pm lock when deleting entry
mptcp: update local address flags when setting it
net: sched: cls_u32: Fix u32's systematic failure to free IDR entries for hnodes.
MAINTAINERS: Re-add cancelled Renesas driver sections
Revert "igb: Disable threaded IRQ for igb_msix_other"
Bluetooth: btintel: Direct exception event to bluetooth stack
Bluetooth: hci_core: Fix calling mgmt_device_connected
virtio/vsock: Improve MSG_ZEROCOPY error handling
vsock: Fix sk_error_queue memory leak
...
This commit is contained in:
commit
cfaaa7d010
|
|
@ -225,6 +225,15 @@ The user must ensure the tokens are returned to the kernel in a timely manner.
|
||||||
Failure to do so will exhaust the limited dmabuf that is bound to the RX queue
|
Failure to do so will exhaust the limited dmabuf that is bound to the RX queue
|
||||||
and will lead to packet drops.
|
and will lead to packet drops.
|
||||||
|
|
||||||
|
The user must pass no more than 128 tokens, with no more than 1024 total frags
|
||||||
|
among the token->token_count across all the tokens. If the user provides more
|
||||||
|
than 1024 frags, the kernel will free up to 1024 frags and return early.
|
||||||
|
|
||||||
|
The kernel returns the number of actual frags freed. The number of frags freed
|
||||||
|
can be less than the tokens provided by the user in case of:
|
||||||
|
|
||||||
|
(a) an internal kernel leak bug.
|
||||||
|
(b) the user passed more than 1024 frags.
|
||||||
|
|
||||||
Implementation & Caveats
|
Implementation & Caveats
|
||||||
========================
|
========================
|
||||||
|
|
|
||||||
30
MAINTAINERS
30
MAINTAINERS
|
|
@ -19579,6 +19579,17 @@ S: Supported
|
||||||
F: Documentation/devicetree/bindings/i2c/renesas,iic-emev2.yaml
|
F: Documentation/devicetree/bindings/i2c/renesas,iic-emev2.yaml
|
||||||
F: drivers/i2c/busses/i2c-emev2.c
|
F: drivers/i2c/busses/i2c-emev2.c
|
||||||
|
|
||||||
|
RENESAS ETHERNET AVB DRIVER
|
||||||
|
M: Paul Barker <paul.barker.ct@bp.renesas.com>
|
||||||
|
M: Niklas Söderlund <niklas.soderlund@ragnatech.se>
|
||||||
|
L: netdev@vger.kernel.org
|
||||||
|
L: linux-renesas-soc@vger.kernel.org
|
||||||
|
S: Supported
|
||||||
|
F: Documentation/devicetree/bindings/net/renesas,etheravb.yaml
|
||||||
|
F: drivers/net/ethernet/renesas/Kconfig
|
||||||
|
F: drivers/net/ethernet/renesas/Makefile
|
||||||
|
F: drivers/net/ethernet/renesas/ravb*
|
||||||
|
|
||||||
RENESAS ETHERNET SWITCH DRIVER
|
RENESAS ETHERNET SWITCH DRIVER
|
||||||
R: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
|
R: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
|
||||||
L: netdev@vger.kernel.org
|
L: netdev@vger.kernel.org
|
||||||
|
|
@ -19628,6 +19639,14 @@ F: Documentation/devicetree/bindings/i2c/renesas,rmobile-iic.yaml
|
||||||
F: drivers/i2c/busses/i2c-rcar.c
|
F: drivers/i2c/busses/i2c-rcar.c
|
||||||
F: drivers/i2c/busses/i2c-sh_mobile.c
|
F: drivers/i2c/busses/i2c-sh_mobile.c
|
||||||
|
|
||||||
|
RENESAS R-CAR SATA DRIVER
|
||||||
|
M: Geert Uytterhoeven <geert+renesas@glider.be>
|
||||||
|
L: linux-ide@vger.kernel.org
|
||||||
|
L: linux-renesas-soc@vger.kernel.org
|
||||||
|
S: Supported
|
||||||
|
F: Documentation/devicetree/bindings/ata/renesas,rcar-sata.yaml
|
||||||
|
F: drivers/ata/sata_rcar.c
|
||||||
|
|
||||||
RENESAS R-CAR THERMAL DRIVERS
|
RENESAS R-CAR THERMAL DRIVERS
|
||||||
M: Niklas Söderlund <niklas.soderlund@ragnatech.se>
|
M: Niklas Söderlund <niklas.soderlund@ragnatech.se>
|
||||||
L: linux-renesas-soc@vger.kernel.org
|
L: linux-renesas-soc@vger.kernel.org
|
||||||
|
|
@ -19703,6 +19722,17 @@ S: Supported
|
||||||
F: Documentation/devicetree/bindings/i2c/renesas,rzv2m.yaml
|
F: Documentation/devicetree/bindings/i2c/renesas,rzv2m.yaml
|
||||||
F: drivers/i2c/busses/i2c-rzv2m.c
|
F: drivers/i2c/busses/i2c-rzv2m.c
|
||||||
|
|
||||||
|
RENESAS SUPERH ETHERNET DRIVER
|
||||||
|
M: Niklas Söderlund <niklas.soderlund@ragnatech.se>
|
||||||
|
L: netdev@vger.kernel.org
|
||||||
|
L: linux-renesas-soc@vger.kernel.org
|
||||||
|
S: Supported
|
||||||
|
F: Documentation/devicetree/bindings/net/renesas,ether.yaml
|
||||||
|
F: drivers/net/ethernet/renesas/Kconfig
|
||||||
|
F: drivers/net/ethernet/renesas/Makefile
|
||||||
|
F: drivers/net/ethernet/renesas/sh_eth*
|
||||||
|
F: include/linux/sh_eth.h
|
||||||
|
|
||||||
RENESAS USB PHY DRIVER
|
RENESAS USB PHY DRIVER
|
||||||
M: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
|
M: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
|
||||||
L: linux-renesas-soc@vger.kernel.org
|
L: linux-renesas-soc@vger.kernel.org
|
||||||
|
|
|
||||||
|
|
@ -3288,13 +3288,12 @@ static int btintel_diagnostics(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
case INTEL_TLV_TEST_EXCEPTION:
|
case INTEL_TLV_TEST_EXCEPTION:
|
||||||
/* Generate devcoredump from exception */
|
/* Generate devcoredump from exception */
|
||||||
if (!hci_devcd_init(hdev, skb->len)) {
|
if (!hci_devcd_init(hdev, skb->len)) {
|
||||||
hci_devcd_append(hdev, skb);
|
hci_devcd_append(hdev, skb_clone(skb, GFP_ATOMIC));
|
||||||
hci_devcd_complete(hdev);
|
hci_devcd_complete(hdev);
|
||||||
} else {
|
} else {
|
||||||
bt_dev_err(hdev, "Failed to generate devcoredump");
|
bt_dev_err(hdev, "Failed to generate devcoredump");
|
||||||
kfree_skb(skb);
|
|
||||||
}
|
}
|
||||||
return 0;
|
break;
|
||||||
default:
|
default:
|
||||||
bt_dev_err(hdev, "Invalid exception type %02X", tlv->val[0]);
|
bt_dev_err(hdev, "Invalid exception type %02X", tlv->val[0]);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1008,6 +1008,8 @@ static void bond_hw_addr_swap(struct bonding *bond, struct slave *new_active,
|
||||||
|
|
||||||
if (bond->dev->flags & IFF_UP)
|
if (bond->dev->flags & IFF_UP)
|
||||||
bond_hw_addr_flush(bond->dev, old_active->dev);
|
bond_hw_addr_flush(bond->dev, old_active->dev);
|
||||||
|
|
||||||
|
bond_slave_ns_maddrs_add(bond, old_active);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (new_active) {
|
if (new_active) {
|
||||||
|
|
@ -1024,6 +1026,8 @@ static void bond_hw_addr_swap(struct bonding *bond, struct slave *new_active,
|
||||||
dev_mc_sync(new_active->dev, bond->dev);
|
dev_mc_sync(new_active->dev, bond->dev);
|
||||||
netif_addr_unlock_bh(bond->dev);
|
netif_addr_unlock_bh(bond->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bond_slave_ns_maddrs_del(bond, new_active);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2341,6 +2345,11 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
|
||||||
bond_compute_features(bond);
|
bond_compute_features(bond);
|
||||||
bond_set_carrier(bond);
|
bond_set_carrier(bond);
|
||||||
|
|
||||||
|
/* Needs to be called before bond_select_active_slave(), which will
|
||||||
|
* remove the maddrs if the slave is selected as active slave.
|
||||||
|
*/
|
||||||
|
bond_slave_ns_maddrs_add(bond, new_slave);
|
||||||
|
|
||||||
if (bond_uses_primary(bond)) {
|
if (bond_uses_primary(bond)) {
|
||||||
block_netpoll_tx();
|
block_netpoll_tx();
|
||||||
bond_select_active_slave(bond);
|
bond_select_active_slave(bond);
|
||||||
|
|
@ -2350,7 +2359,6 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
|
||||||
if (bond_mode_can_use_xmit_hash(bond))
|
if (bond_mode_can_use_xmit_hash(bond))
|
||||||
bond_update_slave_arr(bond, NULL);
|
bond_update_slave_arr(bond, NULL);
|
||||||
|
|
||||||
|
|
||||||
if (!slave_dev->netdev_ops->ndo_bpf ||
|
if (!slave_dev->netdev_ops->ndo_bpf ||
|
||||||
!slave_dev->netdev_ops->ndo_xdp_xmit) {
|
!slave_dev->netdev_ops->ndo_xdp_xmit) {
|
||||||
if (bond->xdp_prog) {
|
if (bond->xdp_prog) {
|
||||||
|
|
@ -2548,6 +2556,12 @@ static int __bond_release_one(struct net_device *bond_dev,
|
||||||
if (oldcurrent == slave)
|
if (oldcurrent == slave)
|
||||||
bond_change_active_slave(bond, NULL);
|
bond_change_active_slave(bond, NULL);
|
||||||
|
|
||||||
|
/* Must be called after bond_change_active_slave () as the slave
|
||||||
|
* might change from an active slave to a backup slave. Then it is
|
||||||
|
* necessary to clear the maddrs on the backup slave.
|
||||||
|
*/
|
||||||
|
bond_slave_ns_maddrs_del(bond, slave);
|
||||||
|
|
||||||
if (bond_is_lb(bond)) {
|
if (bond_is_lb(bond)) {
|
||||||
/* Must be called only after the slave has been
|
/* Must be called only after the slave has been
|
||||||
* detached from the list and the curr_active_slave
|
* detached from the list and the curr_active_slave
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
#include <linux/sched/signal.h>
|
#include <linux/sched/signal.h>
|
||||||
|
|
||||||
#include <net/bonding.h>
|
#include <net/bonding.h>
|
||||||
|
#include <net/ndisc.h>
|
||||||
|
|
||||||
static int bond_option_active_slave_set(struct bonding *bond,
|
static int bond_option_active_slave_set(struct bonding *bond,
|
||||||
const struct bond_opt_value *newval);
|
const struct bond_opt_value *newval);
|
||||||
|
|
@ -1234,6 +1235,68 @@ static int bond_option_arp_ip_targets_set(struct bonding *bond,
|
||||||
}
|
}
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_IPV6)
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
|
static bool slave_can_set_ns_maddr(const struct bonding *bond, struct slave *slave)
|
||||||
|
{
|
||||||
|
return BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP &&
|
||||||
|
!bond_is_active_slave(slave) &&
|
||||||
|
slave->dev->flags & IFF_MULTICAST;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void slave_set_ns_maddrs(struct bonding *bond, struct slave *slave, bool add)
|
||||||
|
{
|
||||||
|
struct in6_addr *targets = bond->params.ns_targets;
|
||||||
|
char slot_maddr[MAX_ADDR_LEN];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!slave_can_set_ns_maddr(bond, slave))
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; i < BOND_MAX_NS_TARGETS; i++) {
|
||||||
|
if (ipv6_addr_any(&targets[i]))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!ndisc_mc_map(&targets[i], slot_maddr, slave->dev, 0)) {
|
||||||
|
if (add)
|
||||||
|
dev_mc_add(slave->dev, slot_maddr);
|
||||||
|
else
|
||||||
|
dev_mc_del(slave->dev, slot_maddr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bond_slave_ns_maddrs_add(struct bonding *bond, struct slave *slave)
|
||||||
|
{
|
||||||
|
if (!bond->params.arp_validate)
|
||||||
|
return;
|
||||||
|
slave_set_ns_maddrs(bond, slave, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bond_slave_ns_maddrs_del(struct bonding *bond, struct slave *slave)
|
||||||
|
{
|
||||||
|
if (!bond->params.arp_validate)
|
||||||
|
return;
|
||||||
|
slave_set_ns_maddrs(bond, slave, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void slave_set_ns_maddr(struct bonding *bond, struct slave *slave,
|
||||||
|
struct in6_addr *target, struct in6_addr *slot)
|
||||||
|
{
|
||||||
|
char target_maddr[MAX_ADDR_LEN], slot_maddr[MAX_ADDR_LEN];
|
||||||
|
|
||||||
|
if (!bond->params.arp_validate || !slave_can_set_ns_maddr(bond, slave))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* remove the previous maddr from slave */
|
||||||
|
if (!ipv6_addr_any(slot) &&
|
||||||
|
!ndisc_mc_map(slot, slot_maddr, slave->dev, 0))
|
||||||
|
dev_mc_del(slave->dev, slot_maddr);
|
||||||
|
|
||||||
|
/* add new maddr on slave if target is set */
|
||||||
|
if (!ipv6_addr_any(target) &&
|
||||||
|
!ndisc_mc_map(target, target_maddr, slave->dev, 0))
|
||||||
|
dev_mc_add(slave->dev, target_maddr);
|
||||||
|
}
|
||||||
|
|
||||||
static void _bond_options_ns_ip6_target_set(struct bonding *bond, int slot,
|
static void _bond_options_ns_ip6_target_set(struct bonding *bond, int slot,
|
||||||
struct in6_addr *target,
|
struct in6_addr *target,
|
||||||
unsigned long last_rx)
|
unsigned long last_rx)
|
||||||
|
|
@ -1243,8 +1306,10 @@ static void _bond_options_ns_ip6_target_set(struct bonding *bond, int slot,
|
||||||
struct slave *slave;
|
struct slave *slave;
|
||||||
|
|
||||||
if (slot >= 0 && slot < BOND_MAX_NS_TARGETS) {
|
if (slot >= 0 && slot < BOND_MAX_NS_TARGETS) {
|
||||||
bond_for_each_slave(bond, slave, iter)
|
bond_for_each_slave(bond, slave, iter) {
|
||||||
slave->target_last_arp_rx[slot] = last_rx;
|
slave->target_last_arp_rx[slot] = last_rx;
|
||||||
|
slave_set_ns_maddr(bond, slave, target, &targets[slot]);
|
||||||
|
}
|
||||||
targets[slot] = *target;
|
targets[slot] = *target;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1296,15 +1361,30 @@ static int bond_option_ns_ip6_targets_set(struct bonding *bond,
|
||||||
{
|
{
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void slave_set_ns_maddrs(struct bonding *bond, struct slave *slave, bool add) {}
|
||||||
|
|
||||||
|
void bond_slave_ns_maddrs_add(struct bonding *bond, struct slave *slave) {}
|
||||||
|
|
||||||
|
void bond_slave_ns_maddrs_del(struct bonding *bond, struct slave *slave) {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int bond_option_arp_validate_set(struct bonding *bond,
|
static int bond_option_arp_validate_set(struct bonding *bond,
|
||||||
const struct bond_opt_value *newval)
|
const struct bond_opt_value *newval)
|
||||||
{
|
{
|
||||||
|
bool changed = !!bond->params.arp_validate != !!newval->value;
|
||||||
|
struct list_head *iter;
|
||||||
|
struct slave *slave;
|
||||||
|
|
||||||
netdev_dbg(bond->dev, "Setting arp_validate to %s (%llu)\n",
|
netdev_dbg(bond->dev, "Setting arp_validate to %s (%llu)\n",
|
||||||
newval->string, newval->value);
|
newval->string, newval->value);
|
||||||
bond->params.arp_validate = newval->value;
|
bond->params.arp_validate = newval->value;
|
||||||
|
|
||||||
|
if (changed) {
|
||||||
|
bond_for_each_slave(bond, slave, iter)
|
||||||
|
slave_set_ns_maddrs(bond, slave, !!bond->params.arp_validate);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -907,7 +907,7 @@ static int igb_request_msix(struct igb_adapter *adapter)
|
||||||
int i, err = 0, vector = 0, free_vector = 0;
|
int i, err = 0, vector = 0, free_vector = 0;
|
||||||
|
|
||||||
err = request_irq(adapter->msix_entries[vector].vector,
|
err = request_irq(adapter->msix_entries[vector].vector,
|
||||||
igb_msix_other, IRQF_NO_THREAD, netdev->name, adapter);
|
igb_msix_other, 0, netdev->name, adapter);
|
||||||
if (err)
|
if (err)
|
||||||
goto err_out;
|
goto err_out;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -866,7 +866,7 @@ mlx5_tc_ct_entry_add_rule(struct mlx5_tc_ct_priv *ct_priv,
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_rule:
|
err_rule:
|
||||||
mlx5_tc_ct_entry_destroy_mod_hdr(ct_priv, zone_rule->attr, zone_rule->mh);
|
mlx5_tc_ct_entry_destroy_mod_hdr(ct_priv, attr, zone_rule->mh);
|
||||||
mlx5_put_label_mapping(ct_priv, attr->ct_attr.ct_labels_id);
|
mlx5_put_label_mapping(ct_priv, attr->ct_attr.ct_labels_id);
|
||||||
err_mod_hdr:
|
err_mod_hdr:
|
||||||
kfree(attr);
|
kfree(attr);
|
||||||
|
|
|
||||||
|
|
@ -660,7 +660,7 @@ tx_sync_info_get(struct mlx5e_ktls_offload_context_tx *priv_tx,
|
||||||
while (remaining > 0) {
|
while (remaining > 0) {
|
||||||
skb_frag_t *frag = &record->frags[i];
|
skb_frag_t *frag = &record->frags[i];
|
||||||
|
|
||||||
get_page(skb_frag_page(frag));
|
page_ref_inc(skb_frag_page(frag));
|
||||||
remaining -= skb_frag_size(frag);
|
remaining -= skb_frag_size(frag);
|
||||||
info->frags[i++] = *frag;
|
info->frags[i++] = *frag;
|
||||||
}
|
}
|
||||||
|
|
@ -763,7 +763,7 @@ void mlx5e_ktls_tx_handle_resync_dump_comp(struct mlx5e_txqsq *sq,
|
||||||
stats = sq->stats;
|
stats = sq->stats;
|
||||||
|
|
||||||
mlx5e_tx_dma_unmap(sq->pdev, dma);
|
mlx5e_tx_dma_unmap(sq->pdev, dma);
|
||||||
put_page(wi->resync_dump_frag_page);
|
page_ref_dec(wi->resync_dump_frag_page);
|
||||||
stats->tls_dump_packets++;
|
stats->tls_dump_packets++;
|
||||||
stats->tls_dump_bytes += wi->num_bytes;
|
stats->tls_dump_bytes += wi->num_bytes;
|
||||||
}
|
}
|
||||||
|
|
@ -816,12 +816,12 @@ mlx5e_ktls_tx_handle_ooo(struct mlx5e_ktls_offload_context_tx *priv_tx,
|
||||||
|
|
||||||
err_out:
|
err_out:
|
||||||
for (; i < info.nr_frags; i++)
|
for (; i < info.nr_frags; i++)
|
||||||
/* The put_page() here undoes the page ref obtained in tx_sync_info_get().
|
/* The page_ref_dec() here undoes the page ref obtained in tx_sync_info_get().
|
||||||
* Page refs obtained for the DUMP WQEs above (by page_ref_add) will be
|
* Page refs obtained for the DUMP WQEs above (by page_ref_add) will be
|
||||||
* released only upon their completions (or in mlx5e_free_txqsq_descs,
|
* released only upon their completions (or in mlx5e_free_txqsq_descs,
|
||||||
* if channel closes).
|
* if channel closes).
|
||||||
*/
|
*/
|
||||||
put_page(skb_frag_page(&info.frags[i]));
|
page_ref_dec(skb_frag_page(&info.frags[i]));
|
||||||
|
|
||||||
return MLX5E_KTLS_SYNC_FAIL;
|
return MLX5E_KTLS_SYNC_FAIL;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4267,7 +4267,8 @@ void mlx5e_set_xdp_feature(struct net_device *netdev)
|
||||||
struct mlx5e_params *params = &priv->channels.params;
|
struct mlx5e_params *params = &priv->channels.params;
|
||||||
xdp_features_t val;
|
xdp_features_t val;
|
||||||
|
|
||||||
if (params->packet_merge.type != MLX5E_PACKET_MERGE_NONE) {
|
if (!netdev->netdev_ops->ndo_bpf ||
|
||||||
|
params->packet_merge.type != MLX5E_PACKET_MERGE_NONE) {
|
||||||
xdp_clear_features_flag(netdev);
|
xdp_clear_features_flag(netdev);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@
|
||||||
#include "en.h"
|
#include "en.h"
|
||||||
#include "en/port.h"
|
#include "en/port.h"
|
||||||
#include "eswitch.h"
|
#include "eswitch.h"
|
||||||
|
#include "lib/mlx5.h"
|
||||||
|
|
||||||
static int mlx5e_test_health_info(struct mlx5e_priv *priv)
|
static int mlx5e_test_health_info(struct mlx5e_priv *priv)
|
||||||
{
|
{
|
||||||
|
|
@ -247,6 +248,9 @@ static int mlx5e_cond_loopback(struct mlx5e_priv *priv)
|
||||||
if (is_mdev_switchdev_mode(priv->mdev))
|
if (is_mdev_switchdev_mode(priv->mdev))
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
if (mlx5_get_sd(priv->mdev))
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2527,8 +2527,11 @@ static void __esw_offloads_unload_rep(struct mlx5_eswitch *esw,
|
||||||
struct mlx5_eswitch_rep *rep, u8 rep_type)
|
struct mlx5_eswitch_rep *rep, u8 rep_type)
|
||||||
{
|
{
|
||||||
if (atomic_cmpxchg(&rep->rep_data[rep_type].state,
|
if (atomic_cmpxchg(&rep->rep_data[rep_type].state,
|
||||||
REP_LOADED, REP_REGISTERED) == REP_LOADED)
|
REP_LOADED, REP_REGISTERED) == REP_LOADED) {
|
||||||
|
if (rep_type == REP_ETH)
|
||||||
|
__esw_offloads_unload_rep(esw, rep, REP_IB);
|
||||||
esw->offloads.rep_ops[rep_type]->unload(rep);
|
esw->offloads.rep_ops[rep_type]->unload(rep);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __unload_reps_all_vport(struct mlx5_eswitch *esw, u8 rep_type)
|
static void __unload_reps_all_vport(struct mlx5_eswitch *esw, u8 rep_type)
|
||||||
|
|
|
||||||
|
|
@ -2105,13 +2105,22 @@ lookup_fte_locked(struct mlx5_flow_group *g,
|
||||||
fte_tmp = NULL;
|
fte_tmp = NULL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (!fte_tmp->node.active) {
|
|
||||||
tree_put_node(&fte_tmp->node, false);
|
|
||||||
fte_tmp = NULL;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
nested_down_write_ref_node(&fte_tmp->node, FS_LOCK_CHILD);
|
nested_down_write_ref_node(&fte_tmp->node, FS_LOCK_CHILD);
|
||||||
|
|
||||||
|
if (!fte_tmp->node.active) {
|
||||||
|
up_write_ref_node(&fte_tmp->node, false);
|
||||||
|
|
||||||
|
if (take_write)
|
||||||
|
up_write_ref_node(&g->node, false);
|
||||||
|
else
|
||||||
|
up_read_ref_node(&g->node);
|
||||||
|
|
||||||
|
tree_put_node(&fte_tmp->node, false);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (take_write)
|
if (take_write)
|
||||||
up_write_ref_node(&g->node, false);
|
up_write_ref_node(&g->node, false);
|
||||||
|
|
|
||||||
|
|
@ -593,9 +593,11 @@ static void irq_pool_free(struct mlx5_irq_pool *pool)
|
||||||
kvfree(pool);
|
kvfree(pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int irq_pools_init(struct mlx5_core_dev *dev, int sf_vec, int pcif_vec)
|
static int irq_pools_init(struct mlx5_core_dev *dev, int sf_vec, int pcif_vec,
|
||||||
|
bool dynamic_vec)
|
||||||
{
|
{
|
||||||
struct mlx5_irq_table *table = dev->priv.irq_table;
|
struct mlx5_irq_table *table = dev->priv.irq_table;
|
||||||
|
int sf_vec_available = sf_vec;
|
||||||
int num_sf_ctrl;
|
int num_sf_ctrl;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
|
@ -616,6 +618,13 @@ static int irq_pools_init(struct mlx5_core_dev *dev, int sf_vec, int pcif_vec)
|
||||||
num_sf_ctrl = DIV_ROUND_UP(mlx5_sf_max_functions(dev),
|
num_sf_ctrl = DIV_ROUND_UP(mlx5_sf_max_functions(dev),
|
||||||
MLX5_SFS_PER_CTRL_IRQ);
|
MLX5_SFS_PER_CTRL_IRQ);
|
||||||
num_sf_ctrl = min_t(int, MLX5_IRQ_CTRL_SF_MAX, num_sf_ctrl);
|
num_sf_ctrl = min_t(int, MLX5_IRQ_CTRL_SF_MAX, num_sf_ctrl);
|
||||||
|
if (!dynamic_vec && (num_sf_ctrl + 1) > sf_vec_available) {
|
||||||
|
mlx5_core_dbg(dev,
|
||||||
|
"Not enough IRQs for SFs control and completion pool, required=%d avail=%d\n",
|
||||||
|
num_sf_ctrl + 1, sf_vec_available);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
table->sf_ctrl_pool = irq_pool_alloc(dev, pcif_vec, num_sf_ctrl,
|
table->sf_ctrl_pool = irq_pool_alloc(dev, pcif_vec, num_sf_ctrl,
|
||||||
"mlx5_sf_ctrl",
|
"mlx5_sf_ctrl",
|
||||||
MLX5_EQ_SHARE_IRQ_MIN_CTRL,
|
MLX5_EQ_SHARE_IRQ_MIN_CTRL,
|
||||||
|
|
@ -624,9 +633,11 @@ static int irq_pools_init(struct mlx5_core_dev *dev, int sf_vec, int pcif_vec)
|
||||||
err = PTR_ERR(table->sf_ctrl_pool);
|
err = PTR_ERR(table->sf_ctrl_pool);
|
||||||
goto err_pf;
|
goto err_pf;
|
||||||
}
|
}
|
||||||
/* init sf_comp_pool */
|
sf_vec_available -= num_sf_ctrl;
|
||||||
|
|
||||||
|
/* init sf_comp_pool, remaining vectors are for the SF completions */
|
||||||
table->sf_comp_pool = irq_pool_alloc(dev, pcif_vec + num_sf_ctrl,
|
table->sf_comp_pool = irq_pool_alloc(dev, pcif_vec + num_sf_ctrl,
|
||||||
sf_vec - num_sf_ctrl, "mlx5_sf_comp",
|
sf_vec_available, "mlx5_sf_comp",
|
||||||
MLX5_EQ_SHARE_IRQ_MIN_COMP,
|
MLX5_EQ_SHARE_IRQ_MIN_COMP,
|
||||||
MLX5_EQ_SHARE_IRQ_MAX_COMP);
|
MLX5_EQ_SHARE_IRQ_MAX_COMP);
|
||||||
if (IS_ERR(table->sf_comp_pool)) {
|
if (IS_ERR(table->sf_comp_pool)) {
|
||||||
|
|
@ -715,6 +726,7 @@ int mlx5_irq_table_get_num_comp(struct mlx5_irq_table *table)
|
||||||
int mlx5_irq_table_create(struct mlx5_core_dev *dev)
|
int mlx5_irq_table_create(struct mlx5_core_dev *dev)
|
||||||
{
|
{
|
||||||
int num_eqs = mlx5_max_eq_cap_get(dev);
|
int num_eqs = mlx5_max_eq_cap_get(dev);
|
||||||
|
bool dynamic_vec;
|
||||||
int total_vec;
|
int total_vec;
|
||||||
int pcif_vec;
|
int pcif_vec;
|
||||||
int req_vec;
|
int req_vec;
|
||||||
|
|
@ -724,21 +736,31 @@ int mlx5_irq_table_create(struct mlx5_core_dev *dev)
|
||||||
if (mlx5_core_is_sf(dev))
|
if (mlx5_core_is_sf(dev))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
/* PCI PF vectors usage is limited by online cpus, device EQs and
|
||||||
|
* PCI MSI-X capability.
|
||||||
|
*/
|
||||||
pcif_vec = MLX5_CAP_GEN(dev, num_ports) * num_online_cpus() + 1;
|
pcif_vec = MLX5_CAP_GEN(dev, num_ports) * num_online_cpus() + 1;
|
||||||
pcif_vec = min_t(int, pcif_vec, num_eqs);
|
pcif_vec = min_t(int, pcif_vec, num_eqs);
|
||||||
|
pcif_vec = min_t(int, pcif_vec, pci_msix_vec_count(dev->pdev));
|
||||||
|
|
||||||
total_vec = pcif_vec;
|
total_vec = pcif_vec;
|
||||||
if (mlx5_sf_max_functions(dev))
|
if (mlx5_sf_max_functions(dev))
|
||||||
total_vec += MLX5_MAX_MSIX_PER_SF * mlx5_sf_max_functions(dev);
|
total_vec += MLX5_MAX_MSIX_PER_SF * mlx5_sf_max_functions(dev);
|
||||||
total_vec = min_t(int, total_vec, pci_msix_vec_count(dev->pdev));
|
total_vec = min_t(int, total_vec, pci_msix_vec_count(dev->pdev));
|
||||||
pcif_vec = min_t(int, pcif_vec, pci_msix_vec_count(dev->pdev));
|
|
||||||
|
|
||||||
req_vec = pci_msix_can_alloc_dyn(dev->pdev) ? 1 : total_vec;
|
req_vec = pci_msix_can_alloc_dyn(dev->pdev) ? 1 : total_vec;
|
||||||
n = pci_alloc_irq_vectors(dev->pdev, 1, req_vec, PCI_IRQ_MSIX);
|
n = pci_alloc_irq_vectors(dev->pdev, 1, req_vec, PCI_IRQ_MSIX);
|
||||||
if (n < 0)
|
if (n < 0)
|
||||||
return n;
|
return n;
|
||||||
|
|
||||||
err = irq_pools_init(dev, total_vec - pcif_vec, pcif_vec);
|
/* Further limit vectors of the pools based on platform for non dynamic case */
|
||||||
|
dynamic_vec = pci_msix_can_alloc_dyn(dev->pdev);
|
||||||
|
if (!dynamic_vec) {
|
||||||
|
pcif_vec = min_t(int, n, pcif_vec);
|
||||||
|
total_vec = min_t(int, n, total_vec);
|
||||||
|
}
|
||||||
|
|
||||||
|
err = irq_pools_init(dev, total_vec - pcif_vec, pcif_vec, dynamic_vec);
|
||||||
if (err)
|
if (err)
|
||||||
pci_free_irq_vectors(dev->pdev);
|
pci_free_irq_vectors(dev->pdev);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,12 @@ static int intel_eth_plat_probe(struct platform_device *pdev)
|
||||||
if (IS_ERR(dwmac->tx_clk))
|
if (IS_ERR(dwmac->tx_clk))
|
||||||
return PTR_ERR(dwmac->tx_clk);
|
return PTR_ERR(dwmac->tx_clk);
|
||||||
|
|
||||||
clk_prepare_enable(dwmac->tx_clk);
|
ret = clk_prepare_enable(dwmac->tx_clk);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&pdev->dev,
|
||||||
|
"Failed to enable tx_clk\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check and configure TX clock rate */
|
/* Check and configure TX clock rate */
|
||||||
rate = clk_get_rate(dwmac->tx_clk);
|
rate = clk_get_rate(dwmac->tx_clk);
|
||||||
|
|
@ -119,7 +124,7 @@ static int intel_eth_plat_probe(struct platform_device *pdev)
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&pdev->dev,
|
dev_err(&pdev->dev,
|
||||||
"Failed to set tx_clk\n");
|
"Failed to set tx_clk\n");
|
||||||
return ret;
|
goto err_tx_clk_disable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -133,7 +138,7 @@ static int intel_eth_plat_probe(struct platform_device *pdev)
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&pdev->dev,
|
dev_err(&pdev->dev,
|
||||||
"Failed to set clk_ptp_ref\n");
|
"Failed to set clk_ptp_ref\n");
|
||||||
return ret;
|
goto err_tx_clk_disable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -149,12 +154,15 @@ static int intel_eth_plat_probe(struct platform_device *pdev)
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
|
ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
|
||||||
if (ret) {
|
if (ret)
|
||||||
clk_disable_unprepare(dwmac->tx_clk);
|
goto err_tx_clk_disable;
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
err_tx_clk_disable:
|
||||||
|
if (dwmac->data->tx_clk_en)
|
||||||
|
clk_disable_unprepare(dwmac->tx_clk);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void intel_eth_plat_remove(struct platform_device *pdev)
|
static void intel_eth_plat_remove(struct platform_device *pdev)
|
||||||
|
|
@ -162,7 +170,8 @@ static void intel_eth_plat_remove(struct platform_device *pdev)
|
||||||
struct intel_dwmac *dwmac = get_stmmac_bsp_priv(&pdev->dev);
|
struct intel_dwmac *dwmac = get_stmmac_bsp_priv(&pdev->dev);
|
||||||
|
|
||||||
stmmac_pltfr_remove(pdev);
|
stmmac_pltfr_remove(pdev);
|
||||||
clk_disable_unprepare(dwmac->tx_clk);
|
if (dwmac->data->tx_clk_en)
|
||||||
|
clk_disable_unprepare(dwmac->tx_clk);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct platform_driver intel_eth_plat_driver = {
|
static struct platform_driver intel_eth_plat_driver = {
|
||||||
|
|
|
||||||
|
|
@ -589,9 +589,9 @@ static int mediatek_dwmac_common_data(struct platform_device *pdev,
|
||||||
|
|
||||||
plat->mac_interface = priv_plat->phy_mode;
|
plat->mac_interface = priv_plat->phy_mode;
|
||||||
if (priv_plat->mac_wol)
|
if (priv_plat->mac_wol)
|
||||||
plat->flags |= STMMAC_FLAG_USE_PHY_WOL;
|
|
||||||
else
|
|
||||||
plat->flags &= ~STMMAC_FLAG_USE_PHY_WOL;
|
plat->flags &= ~STMMAC_FLAG_USE_PHY_WOL;
|
||||||
|
else
|
||||||
|
plat->flags |= STMMAC_FLAG_USE_PHY_WOL;
|
||||||
plat->riwt_off = 1;
|
plat->riwt_off = 1;
|
||||||
plat->maxmtu = ETH_DATA_LEN;
|
plat->maxmtu = ETH_DATA_LEN;
|
||||||
plat->host_dma_width = priv_plat->variant->dma_bit_mask;
|
plat->host_dma_width = priv_plat->variant->dma_bit_mask;
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
#include <linux/if_hsr.h>
|
#include <linux/if_hsr.h>
|
||||||
#include <linux/if_vlan.h>
|
#include <linux/if_vlan.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/io-64-nonatomic-hi-lo.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/mfd/syscon.h>
|
#include <linux/mfd/syscon.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
|
@ -411,6 +412,8 @@ static int prueth_perout_enable(void *clockops_data,
|
||||||
struct prueth_emac *emac = clockops_data;
|
struct prueth_emac *emac = clockops_data;
|
||||||
u32 reduction_factor = 0, offset = 0;
|
u32 reduction_factor = 0, offset = 0;
|
||||||
struct timespec64 ts;
|
struct timespec64 ts;
|
||||||
|
u64 current_cycle;
|
||||||
|
u64 start_offset;
|
||||||
u64 ns_period;
|
u64 ns_period;
|
||||||
|
|
||||||
if (!on)
|
if (!on)
|
||||||
|
|
@ -449,8 +452,14 @@ static int prueth_perout_enable(void *clockops_data,
|
||||||
writel(reduction_factor, emac->prueth->shram.va +
|
writel(reduction_factor, emac->prueth->shram.va +
|
||||||
TIMESYNC_FW_WC_SYNCOUT_REDUCTION_FACTOR_OFFSET);
|
TIMESYNC_FW_WC_SYNCOUT_REDUCTION_FACTOR_OFFSET);
|
||||||
|
|
||||||
writel(0, emac->prueth->shram.va +
|
current_cycle = icssg_read_time(emac->prueth->shram.va +
|
||||||
TIMESYNC_FW_WC_SYNCOUT_START_TIME_CYCLECOUNT_OFFSET);
|
TIMESYNC_FW_WC_CYCLECOUNT_OFFSET);
|
||||||
|
|
||||||
|
/* Rounding of current_cycle count to next second */
|
||||||
|
start_offset = roundup(current_cycle, MSEC_PER_SEC);
|
||||||
|
|
||||||
|
hi_lo_writeq(start_offset, emac->prueth->shram.va +
|
||||||
|
TIMESYNC_FW_WC_SYNCOUT_START_TIME_CYCLECOUNT_OFFSET);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -330,6 +330,18 @@ static inline int prueth_emac_slice(struct prueth_emac *emac)
|
||||||
extern const struct ethtool_ops icssg_ethtool_ops;
|
extern const struct ethtool_ops icssg_ethtool_ops;
|
||||||
extern const struct dev_pm_ops prueth_dev_pm_ops;
|
extern const struct dev_pm_ops prueth_dev_pm_ops;
|
||||||
|
|
||||||
|
static inline u64 icssg_read_time(const void __iomem *addr)
|
||||||
|
{
|
||||||
|
u32 low, high;
|
||||||
|
|
||||||
|
do {
|
||||||
|
high = readl(addr + 4);
|
||||||
|
low = readl(addr);
|
||||||
|
} while (high != readl(addr + 4));
|
||||||
|
|
||||||
|
return low + ((u64)high << 32);
|
||||||
|
}
|
||||||
|
|
||||||
/* Classifier helpers */
|
/* Classifier helpers */
|
||||||
void icssg_class_set_mac_addr(struct regmap *miig_rt, int slice, u8 *mac);
|
void icssg_class_set_mac_addr(struct regmap *miig_rt, int slice, u8 *mac);
|
||||||
void icssg_class_set_host_mac_addr(struct regmap *miig_rt, const u8 *mac);
|
void icssg_class_set_host_mac_addr(struct regmap *miig_rt, const u8 *mac);
|
||||||
|
|
|
||||||
|
|
@ -437,13 +437,15 @@ static void mse102x_tx_work(struct work_struct *work)
|
||||||
mse = &mses->mse102x;
|
mse = &mses->mse102x;
|
||||||
|
|
||||||
while ((txb = skb_dequeue(&mse->txq))) {
|
while ((txb = skb_dequeue(&mse->txq))) {
|
||||||
|
unsigned int len = max_t(unsigned int, txb->len, ETH_ZLEN);
|
||||||
|
|
||||||
mutex_lock(&mses->lock);
|
mutex_lock(&mses->lock);
|
||||||
ret = mse102x_tx_pkt_spi(mse, txb, work_timeout);
|
ret = mse102x_tx_pkt_spi(mse, txb, work_timeout);
|
||||||
mutex_unlock(&mses->lock);
|
mutex_unlock(&mses->lock);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
mse->ndev->stats.tx_dropped++;
|
mse->ndev->stats.tx_dropped++;
|
||||||
} else {
|
} else {
|
||||||
mse->ndev->stats.tx_bytes += txb->len;
|
mse->ndev->stats.tx_bytes += len;
|
||||||
mse->ndev->stats.tx_packets++;
|
mse->ndev->stats.tx_packets++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ struct phylink {
|
||||||
unsigned int pcs_neg_mode;
|
unsigned int pcs_neg_mode;
|
||||||
unsigned int pcs_state;
|
unsigned int pcs_state;
|
||||||
|
|
||||||
bool mac_link_dropped;
|
bool link_failed;
|
||||||
bool using_mac_select_pcs;
|
bool using_mac_select_pcs;
|
||||||
|
|
||||||
struct sfp_bus *sfp_bus;
|
struct sfp_bus *sfp_bus;
|
||||||
|
|
@ -1475,9 +1475,9 @@ static void phylink_resolve(struct work_struct *w)
|
||||||
cur_link_state = pl->old_link_state;
|
cur_link_state = pl->old_link_state;
|
||||||
|
|
||||||
if (pl->phylink_disable_state) {
|
if (pl->phylink_disable_state) {
|
||||||
pl->mac_link_dropped = false;
|
pl->link_failed = false;
|
||||||
link_state.link = false;
|
link_state.link = false;
|
||||||
} else if (pl->mac_link_dropped) {
|
} else if (pl->link_failed) {
|
||||||
link_state.link = false;
|
link_state.link = false;
|
||||||
retrigger = true;
|
retrigger = true;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1572,7 +1572,7 @@ static void phylink_resolve(struct work_struct *w)
|
||||||
phylink_link_up(pl, link_state);
|
phylink_link_up(pl, link_state);
|
||||||
}
|
}
|
||||||
if (!link_state.link && retrigger) {
|
if (!link_state.link && retrigger) {
|
||||||
pl->mac_link_dropped = false;
|
pl->link_failed = false;
|
||||||
queue_work(system_power_efficient_wq, &pl->resolve);
|
queue_work(system_power_efficient_wq, &pl->resolve);
|
||||||
}
|
}
|
||||||
mutex_unlock(&pl->state_mutex);
|
mutex_unlock(&pl->state_mutex);
|
||||||
|
|
@ -1835,6 +1835,8 @@ static void phylink_phy_change(struct phy_device *phydev, bool up)
|
||||||
pl->phy_state.pause |= MLO_PAUSE_RX;
|
pl->phy_state.pause |= MLO_PAUSE_RX;
|
||||||
pl->phy_state.interface = phydev->interface;
|
pl->phy_state.interface = phydev->interface;
|
||||||
pl->phy_state.link = up;
|
pl->phy_state.link = up;
|
||||||
|
if (!up)
|
||||||
|
pl->link_failed = true;
|
||||||
mutex_unlock(&pl->state_mutex);
|
mutex_unlock(&pl->state_mutex);
|
||||||
|
|
||||||
phylink_run_resolve(pl);
|
phylink_run_resolve(pl);
|
||||||
|
|
@ -2158,7 +2160,7 @@ EXPORT_SYMBOL_GPL(phylink_disconnect_phy);
|
||||||
static void phylink_link_changed(struct phylink *pl, bool up, const char *what)
|
static void phylink_link_changed(struct phylink *pl, bool up, const char *what)
|
||||||
{
|
{
|
||||||
if (!up)
|
if (!up)
|
||||||
pl->mac_link_dropped = true;
|
pl->link_failed = true;
|
||||||
phylink_run_resolve(pl);
|
phylink_run_resolve(pl);
|
||||||
phylink_dbg(pl, "%s link %s\n", what, up ? "up" : "down");
|
phylink_dbg(pl, "%s link %s\n", what, up ? "up" : "down");
|
||||||
}
|
}
|
||||||
|
|
@ -2792,7 +2794,7 @@ int phylink_ethtool_set_pauseparam(struct phylink *pl,
|
||||||
* link will cycle.
|
* link will cycle.
|
||||||
*/
|
*/
|
||||||
if (manual_changed) {
|
if (manual_changed) {
|
||||||
pl->mac_link_dropped = true;
|
pl->link_failed = true;
|
||||||
phylink_run_resolve(pl);
|
phylink_run_resolve(pl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,9 @@ static inline int copy_safe_from_sockptr(void *dst, size_t ksize,
|
||||||
{
|
{
|
||||||
if (optlen < ksize)
|
if (optlen < ksize)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
return copy_from_sockptr(dst, optval, ksize);
|
if (copy_from_sockptr(dst, optval, ksize))
|
||||||
|
return -EFAULT;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int copy_struct_from_sockptr(void *dst, size_t ksize,
|
static inline int copy_struct_from_sockptr(void *dst, size_t ksize,
|
||||||
|
|
|
||||||
|
|
@ -161,5 +161,7 @@ void bond_option_arp_ip_targets_clear(struct bonding *bond);
|
||||||
#if IS_ENABLED(CONFIG_IPV6)
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
void bond_option_ns_ip6_targets_clear(struct bonding *bond);
|
void bond_option_ns_ip6_targets_clear(struct bonding *bond);
|
||||||
#endif
|
#endif
|
||||||
|
void bond_slave_ns_maddrs_add(struct bonding *bond, struct slave *slave);
|
||||||
|
void bond_slave_ns_maddrs_del(struct bonding *bond, struct slave *slave);
|
||||||
|
|
||||||
#endif /* _NET_BOND_OPTIONS_H */
|
#endif /* _NET_BOND_OPTIONS_H */
|
||||||
|
|
|
||||||
|
|
@ -3788,8 +3788,6 @@ static void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
|
|
||||||
hci_dev_lock(hdev);
|
hci_dev_lock(hdev);
|
||||||
conn = hci_conn_hash_lookup_handle(hdev, handle);
|
conn = hci_conn_hash_lookup_handle(hdev, handle);
|
||||||
if (conn && hci_dev_test_flag(hdev, HCI_MGMT))
|
|
||||||
mgmt_device_connected(hdev, conn, NULL, 0);
|
|
||||||
hci_dev_unlock(hdev);
|
hci_dev_unlock(hdev);
|
||||||
|
|
||||||
if (conn) {
|
if (conn) {
|
||||||
|
|
|
||||||
|
|
@ -1052,32 +1052,34 @@ static int sock_reserve_memory(struct sock *sk, int bytes)
|
||||||
|
|
||||||
#ifdef CONFIG_PAGE_POOL
|
#ifdef CONFIG_PAGE_POOL
|
||||||
|
|
||||||
/* This is the number of tokens that the user can SO_DEVMEM_DONTNEED in
|
/* This is the number of tokens and frags that the user can SO_DEVMEM_DONTNEED
|
||||||
* 1 syscall. The limit exists to limit the amount of memory the kernel
|
* in 1 syscall. The limit exists to limit the amount of memory the kernel
|
||||||
* allocates to copy these tokens.
|
* allocates to copy these tokens, and to prevent looping over the frags for
|
||||||
|
* too long.
|
||||||
*/
|
*/
|
||||||
#define MAX_DONTNEED_TOKENS 128
|
#define MAX_DONTNEED_TOKENS 128
|
||||||
|
#define MAX_DONTNEED_FRAGS 1024
|
||||||
|
|
||||||
static noinline_for_stack int
|
static noinline_for_stack int
|
||||||
sock_devmem_dontneed(struct sock *sk, sockptr_t optval, unsigned int optlen)
|
sock_devmem_dontneed(struct sock *sk, sockptr_t optval, unsigned int optlen)
|
||||||
{
|
{
|
||||||
unsigned int num_tokens, i, j, k, netmem_num = 0;
|
unsigned int num_tokens, i, j, k, netmem_num = 0;
|
||||||
struct dmabuf_token *tokens;
|
struct dmabuf_token *tokens;
|
||||||
|
int ret = 0, num_frags = 0;
|
||||||
netmem_ref netmems[16];
|
netmem_ref netmems[16];
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
if (!sk_is_tcp(sk))
|
if (!sk_is_tcp(sk))
|
||||||
return -EBADF;
|
return -EBADF;
|
||||||
|
|
||||||
if (optlen % sizeof(struct dmabuf_token) ||
|
if (optlen % sizeof(*tokens) ||
|
||||||
optlen > sizeof(*tokens) * MAX_DONTNEED_TOKENS)
|
optlen > sizeof(*tokens) * MAX_DONTNEED_TOKENS)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
tokens = kvmalloc_array(optlen, sizeof(*tokens), GFP_KERNEL);
|
num_tokens = optlen / sizeof(*tokens);
|
||||||
|
tokens = kvmalloc_array(num_tokens, sizeof(*tokens), GFP_KERNEL);
|
||||||
if (!tokens)
|
if (!tokens)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
num_tokens = optlen / sizeof(struct dmabuf_token);
|
|
||||||
if (copy_from_sockptr(tokens, optval, optlen)) {
|
if (copy_from_sockptr(tokens, optval, optlen)) {
|
||||||
kvfree(tokens);
|
kvfree(tokens);
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
@ -1086,24 +1088,28 @@ sock_devmem_dontneed(struct sock *sk, sockptr_t optval, unsigned int optlen)
|
||||||
xa_lock_bh(&sk->sk_user_frags);
|
xa_lock_bh(&sk->sk_user_frags);
|
||||||
for (i = 0; i < num_tokens; i++) {
|
for (i = 0; i < num_tokens; i++) {
|
||||||
for (j = 0; j < tokens[i].token_count; j++) {
|
for (j = 0; j < tokens[i].token_count; j++) {
|
||||||
|
if (++num_frags > MAX_DONTNEED_FRAGS)
|
||||||
|
goto frag_limit_reached;
|
||||||
|
|
||||||
netmem_ref netmem = (__force netmem_ref)__xa_erase(
|
netmem_ref netmem = (__force netmem_ref)__xa_erase(
|
||||||
&sk->sk_user_frags, tokens[i].token_start + j);
|
&sk->sk_user_frags, tokens[i].token_start + j);
|
||||||
|
|
||||||
if (netmem &&
|
if (!netmem || WARN_ON_ONCE(!netmem_is_net_iov(netmem)))
|
||||||
!WARN_ON_ONCE(!netmem_is_net_iov(netmem))) {
|
continue;
|
||||||
netmems[netmem_num++] = netmem;
|
|
||||||
if (netmem_num == ARRAY_SIZE(netmems)) {
|
netmems[netmem_num++] = netmem;
|
||||||
xa_unlock_bh(&sk->sk_user_frags);
|
if (netmem_num == ARRAY_SIZE(netmems)) {
|
||||||
for (k = 0; k < netmem_num; k++)
|
xa_unlock_bh(&sk->sk_user_frags);
|
||||||
WARN_ON_ONCE(!napi_pp_put_page(netmems[k]));
|
for (k = 0; k < netmem_num; k++)
|
||||||
netmem_num = 0;
|
WARN_ON_ONCE(!napi_pp_put_page(netmems[k]));
|
||||||
xa_lock_bh(&sk->sk_user_frags);
|
netmem_num = 0;
|
||||||
}
|
xa_lock_bh(&sk->sk_user_frags);
|
||||||
ret++;
|
|
||||||
}
|
}
|
||||||
|
ret++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
frag_limit_reached:
|
||||||
xa_unlock_bh(&sk->sk_user_frags);
|
xa_unlock_bh(&sk->sk_user_frags);
|
||||||
for (k = 0; k < netmem_num; k++)
|
for (k = 0; k < netmem_num; k++)
|
||||||
WARN_ON_ONCE(!napi_pp_put_page(netmems[k]));
|
WARN_ON_ONCE(!napi_pp_put_page(netmems[k]));
|
||||||
|
|
|
||||||
|
|
@ -618,7 +618,7 @@ static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
|
||||||
by tcp. Feel free to propose better solution.
|
by tcp. Feel free to propose better solution.
|
||||||
--ANK (980728)
|
--ANK (980728)
|
||||||
*/
|
*/
|
||||||
if (np->rxopt.all)
|
if (np->rxopt.all && sk->sk_state != DCCP_LISTEN)
|
||||||
opt_skb = skb_clone_and_charge_r(skb, sk);
|
opt_skb = skb_clone_and_charge_r(skb, sk);
|
||||||
|
|
||||||
if (sk->sk_state == DCCP_OPEN) { /* Fast path */
|
if (sk->sk_state == DCCP_OPEN) { /* Fast path */
|
||||||
|
|
|
||||||
|
|
@ -310,7 +310,8 @@ int mr_table_dump(struct mr_table *mrt, struct sk_buff *skb,
|
||||||
if (filter->filter_set)
|
if (filter->filter_set)
|
||||||
flags |= NLM_F_DUMP_FILTERED;
|
flags |= NLM_F_DUMP_FILTERED;
|
||||||
|
|
||||||
list_for_each_entry_rcu(mfc, &mrt->mfc_cache_list, list) {
|
list_for_each_entry_rcu(mfc, &mrt->mfc_cache_list, list,
|
||||||
|
lockdep_rtnl_is_held()) {
|
||||||
if (e < s_e)
|
if (e < s_e)
|
||||||
goto next_entry;
|
goto next_entry;
|
||||||
if (filter->dev &&
|
if (filter->dev &&
|
||||||
|
|
|
||||||
|
|
@ -1618,7 +1618,7 @@ int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
|
||||||
by tcp. Feel free to propose better solution.
|
by tcp. Feel free to propose better solution.
|
||||||
--ANK (980728)
|
--ANK (980728)
|
||||||
*/
|
*/
|
||||||
if (np->rxopt.all)
|
if (np->rxopt.all && sk->sk_state != TCP_LISTEN)
|
||||||
opt_skb = skb_clone_and_charge_r(skb, sk);
|
opt_skb = skb_clone_and_charge_r(skb, sk);
|
||||||
|
|
||||||
if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */
|
if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */
|
||||||
|
|
@ -1656,8 +1656,6 @@ int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
|
||||||
if (reason)
|
if (reason)
|
||||||
goto reset;
|
goto reset;
|
||||||
}
|
}
|
||||||
if (opt_skb)
|
|
||||||
__kfree_skb(opt_skb);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
|
|
|
||||||
|
|
@ -524,7 +524,8 @@ __lookup_addr(struct pm_nl_pernet *pernet, const struct mptcp_addr_info *info)
|
||||||
{
|
{
|
||||||
struct mptcp_pm_addr_entry *entry;
|
struct mptcp_pm_addr_entry *entry;
|
||||||
|
|
||||||
list_for_each_entry(entry, &pernet->local_addr_list, list) {
|
list_for_each_entry_rcu(entry, &pernet->local_addr_list, list,
|
||||||
|
lockdep_is_held(&pernet->lock)) {
|
||||||
if (mptcp_addresses_equal(&entry->addr, info, entry->addr.port))
|
if (mptcp_addresses_equal(&entry->addr, info, entry->addr.port))
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -308,14 +308,17 @@ int mptcp_pm_nl_remove_doit(struct sk_buff *skb, struct genl_info *info)
|
||||||
|
|
||||||
lock_sock(sk);
|
lock_sock(sk);
|
||||||
|
|
||||||
|
spin_lock_bh(&msk->pm.lock);
|
||||||
match = mptcp_userspace_pm_lookup_addr_by_id(msk, id_val);
|
match = mptcp_userspace_pm_lookup_addr_by_id(msk, id_val);
|
||||||
if (!match) {
|
if (!match) {
|
||||||
GENL_SET_ERR_MSG(info, "address with specified id not found");
|
GENL_SET_ERR_MSG(info, "address with specified id not found");
|
||||||
|
spin_unlock_bh(&msk->pm.lock);
|
||||||
release_sock(sk);
|
release_sock(sk);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
list_move(&match->list, &free_list);
|
list_move(&match->list, &free_list);
|
||||||
|
spin_unlock_bh(&msk->pm.lock);
|
||||||
|
|
||||||
mptcp_pm_remove_addrs(msk, &free_list);
|
mptcp_pm_remove_addrs(msk, &free_list);
|
||||||
|
|
||||||
|
|
@ -560,6 +563,7 @@ int mptcp_userspace_pm_set_flags(struct sk_buff *skb, struct genl_info *info)
|
||||||
struct nlattr *token = info->attrs[MPTCP_PM_ATTR_TOKEN];
|
struct nlattr *token = info->attrs[MPTCP_PM_ATTR_TOKEN];
|
||||||
struct nlattr *attr = info->attrs[MPTCP_PM_ATTR_ADDR];
|
struct nlattr *attr = info->attrs[MPTCP_PM_ATTR_ADDR];
|
||||||
struct net *net = sock_net(skb->sk);
|
struct net *net = sock_net(skb->sk);
|
||||||
|
struct mptcp_pm_addr_entry *entry;
|
||||||
struct mptcp_sock *msk;
|
struct mptcp_sock *msk;
|
||||||
int ret = -EINVAL;
|
int ret = -EINVAL;
|
||||||
struct sock *sk;
|
struct sock *sk;
|
||||||
|
|
@ -601,6 +605,17 @@ int mptcp_userspace_pm_set_flags(struct sk_buff *skb, struct genl_info *info)
|
||||||
if (loc.flags & MPTCP_PM_ADDR_FLAG_BACKUP)
|
if (loc.flags & MPTCP_PM_ADDR_FLAG_BACKUP)
|
||||||
bkup = 1;
|
bkup = 1;
|
||||||
|
|
||||||
|
spin_lock_bh(&msk->pm.lock);
|
||||||
|
list_for_each_entry(entry, &msk->pm.userspace_pm_local_addr_list, list) {
|
||||||
|
if (mptcp_addresses_equal(&entry->addr, &loc.addr, false)) {
|
||||||
|
if (bkup)
|
||||||
|
entry->flags |= MPTCP_PM_ADDR_FLAG_BACKUP;
|
||||||
|
else
|
||||||
|
entry->flags &= ~MPTCP_PM_ADDR_FLAG_BACKUP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spin_unlock_bh(&msk->pm.lock);
|
||||||
|
|
||||||
lock_sock(sk);
|
lock_sock(sk);
|
||||||
ret = mptcp_pm_nl_mp_prio_send_ack(msk, &loc.addr, &rem.addr, bkup);
|
ret = mptcp_pm_nl_mp_prio_send_ack(msk, &loc.addr, &rem.addr, bkup);
|
||||||
release_sock(sk);
|
release_sock(sk);
|
||||||
|
|
|
||||||
|
|
@ -2082,7 +2082,8 @@ static void mptcp_rcv_space_adjust(struct mptcp_sock *msk, int copied)
|
||||||
slow = lock_sock_fast(ssk);
|
slow = lock_sock_fast(ssk);
|
||||||
WRITE_ONCE(ssk->sk_rcvbuf, rcvbuf);
|
WRITE_ONCE(ssk->sk_rcvbuf, rcvbuf);
|
||||||
WRITE_ONCE(tcp_sk(ssk)->window_clamp, window_clamp);
|
WRITE_ONCE(tcp_sk(ssk)->window_clamp, window_clamp);
|
||||||
tcp_cleanup_rbuf(ssk, 1);
|
if (tcp_can_send_ack(ssk))
|
||||||
|
tcp_cleanup_rbuf(ssk, 1);
|
||||||
unlock_sock_fast(ssk, slow);
|
unlock_sock_fast(ssk, slow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2205,7 +2206,7 @@ static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
|
||||||
cmsg_flags = MPTCP_CMSG_INQ;
|
cmsg_flags = MPTCP_CMSG_INQ;
|
||||||
|
|
||||||
while (copied < len) {
|
while (copied < len) {
|
||||||
int bytes_read;
|
int err, bytes_read;
|
||||||
|
|
||||||
bytes_read = __mptcp_recvmsg_mskq(msk, msg, len - copied, flags, &tss, &cmsg_flags);
|
bytes_read = __mptcp_recvmsg_mskq(msk, msg, len - copied, flags, &tss, &cmsg_flags);
|
||||||
if (unlikely(bytes_read < 0)) {
|
if (unlikely(bytes_read < 0)) {
|
||||||
|
|
@ -2267,9 +2268,16 @@ static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
|
||||||
}
|
}
|
||||||
|
|
||||||
pr_debug("block timeout %ld\n", timeo);
|
pr_debug("block timeout %ld\n", timeo);
|
||||||
sk_wait_data(sk, &timeo, NULL);
|
mptcp_rcv_space_adjust(msk, copied);
|
||||||
|
err = sk_wait_data(sk, &timeo, NULL);
|
||||||
|
if (err < 0) {
|
||||||
|
err = copied ? : err;
|
||||||
|
goto out_err;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mptcp_rcv_space_adjust(msk, copied);
|
||||||
|
|
||||||
out_err:
|
out_err:
|
||||||
if (cmsg_flags && copied >= 0) {
|
if (cmsg_flags && copied >= 0) {
|
||||||
if (cmsg_flags & MPTCP_CMSG_TS)
|
if (cmsg_flags & MPTCP_CMSG_TS)
|
||||||
|
|
@ -2285,8 +2293,6 @@ static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
|
||||||
pr_debug("msk=%p rx queue empty=%d:%d copied=%d\n",
|
pr_debug("msk=%p rx queue empty=%d:%d copied=%d\n",
|
||||||
msk, skb_queue_empty_lockless(&sk->sk_receive_queue),
|
msk, skb_queue_empty_lockless(&sk->sk_receive_queue),
|
||||||
skb_queue_empty(&msk->receive_queue), copied);
|
skb_queue_empty(&msk->receive_queue), copied);
|
||||||
if (!(flags & MSG_PEEK))
|
|
||||||
mptcp_rcv_space_adjust(msk, copied);
|
|
||||||
|
|
||||||
release_sock(sk);
|
release_sock(sk);
|
||||||
return copied;
|
return copied;
|
||||||
|
|
|
||||||
|
|
@ -393,15 +393,6 @@ static void netlink_skb_set_owner_r(struct sk_buff *skb, struct sock *sk)
|
||||||
|
|
||||||
static void netlink_sock_destruct(struct sock *sk)
|
static void netlink_sock_destruct(struct sock *sk)
|
||||||
{
|
{
|
||||||
struct netlink_sock *nlk = nlk_sk(sk);
|
|
||||||
|
|
||||||
if (nlk->cb_running) {
|
|
||||||
if (nlk->cb.done)
|
|
||||||
nlk->cb.done(&nlk->cb);
|
|
||||||
module_put(nlk->cb.module);
|
|
||||||
kfree_skb(nlk->cb.skb);
|
|
||||||
}
|
|
||||||
|
|
||||||
skb_queue_purge(&sk->sk_receive_queue);
|
skb_queue_purge(&sk->sk_receive_queue);
|
||||||
|
|
||||||
if (!sock_flag(sk, SOCK_DEAD)) {
|
if (!sock_flag(sk, SOCK_DEAD)) {
|
||||||
|
|
@ -414,14 +405,6 @@ static void netlink_sock_destruct(struct sock *sk)
|
||||||
WARN_ON(nlk_sk(sk)->groups);
|
WARN_ON(nlk_sk(sk)->groups);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void netlink_sock_destruct_work(struct work_struct *work)
|
|
||||||
{
|
|
||||||
struct netlink_sock *nlk = container_of(work, struct netlink_sock,
|
|
||||||
work);
|
|
||||||
|
|
||||||
sk_free(&nlk->sk);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This lock without WQ_FLAG_EXCLUSIVE is good on UP and it is _very_ bad on
|
/* This lock without WQ_FLAG_EXCLUSIVE is good on UP and it is _very_ bad on
|
||||||
* SMP. Look, when several writers sleep and reader wakes them up, all but one
|
* SMP. Look, when several writers sleep and reader wakes them up, all but one
|
||||||
* immediately hit write lock and grab all the cpus. Exclusive sleep solves
|
* immediately hit write lock and grab all the cpus. Exclusive sleep solves
|
||||||
|
|
@ -731,12 +714,6 @@ static void deferred_put_nlk_sk(struct rcu_head *head)
|
||||||
if (!refcount_dec_and_test(&sk->sk_refcnt))
|
if (!refcount_dec_and_test(&sk->sk_refcnt))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (nlk->cb_running && nlk->cb.done) {
|
|
||||||
INIT_WORK(&nlk->work, netlink_sock_destruct_work);
|
|
||||||
schedule_work(&nlk->work);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
sk_free(sk);
|
sk_free(sk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -788,6 +765,14 @@ static int netlink_release(struct socket *sock)
|
||||||
NETLINK_URELEASE, &n);
|
NETLINK_URELEASE, &n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Terminate any outstanding dump */
|
||||||
|
if (nlk->cb_running) {
|
||||||
|
if (nlk->cb.done)
|
||||||
|
nlk->cb.done(&nlk->cb);
|
||||||
|
module_put(nlk->cb.module);
|
||||||
|
kfree_skb(nlk->cb.skb);
|
||||||
|
}
|
||||||
|
|
||||||
module_put(nlk->module);
|
module_put(nlk->module);
|
||||||
|
|
||||||
if (netlink_is_kernel(sk)) {
|
if (netlink_is_kernel(sk)) {
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
#include <linux/rhashtable.h>
|
#include <linux/rhashtable.h>
|
||||||
#include <linux/atomic.h>
|
#include <linux/atomic.h>
|
||||||
#include <linux/workqueue.h>
|
|
||||||
#include <net/sock.h>
|
#include <net/sock.h>
|
||||||
|
|
||||||
/* flags */
|
/* flags */
|
||||||
|
|
@ -50,7 +49,6 @@ struct netlink_sock {
|
||||||
|
|
||||||
struct rhash_head node;
|
struct rhash_head node;
|
||||||
struct rcu_head rcu;
|
struct rcu_head rcu;
|
||||||
struct work_struct work;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline struct netlink_sock *nlk_sk(struct sock *sk)
|
static inline struct netlink_sock *nlk_sk(struct sock *sk)
|
||||||
|
|
|
||||||
|
|
@ -92,6 +92,16 @@ struct tc_u_common {
|
||||||
long knodes;
|
long knodes;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static u32 handle2id(u32 h)
|
||||||
|
{
|
||||||
|
return ((h & 0x80000000) ? ((h >> 20) & 0x7FF) : h);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 id2handle(u32 id)
|
||||||
|
{
|
||||||
|
return (id | 0x800U) << 20;
|
||||||
|
}
|
||||||
|
|
||||||
static inline unsigned int u32_hash_fold(__be32 key,
|
static inline unsigned int u32_hash_fold(__be32 key,
|
||||||
const struct tc_u32_sel *sel,
|
const struct tc_u32_sel *sel,
|
||||||
u8 fshift)
|
u8 fshift)
|
||||||
|
|
@ -310,7 +320,7 @@ static u32 gen_new_htid(struct tc_u_common *tp_c, struct tc_u_hnode *ptr)
|
||||||
int id = idr_alloc_cyclic(&tp_c->handle_idr, ptr, 1, 0x7FF, GFP_KERNEL);
|
int id = idr_alloc_cyclic(&tp_c->handle_idr, ptr, 1, 0x7FF, GFP_KERNEL);
|
||||||
if (id < 0)
|
if (id < 0)
|
||||||
return 0;
|
return 0;
|
||||||
return (id | 0x800U) << 20;
|
return id2handle(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct hlist_head *tc_u_common_hash;
|
static struct hlist_head *tc_u_common_hash;
|
||||||
|
|
@ -360,7 +370,7 @@ static int u32_init(struct tcf_proto *tp)
|
||||||
return -ENOBUFS;
|
return -ENOBUFS;
|
||||||
|
|
||||||
refcount_set(&root_ht->refcnt, 1);
|
refcount_set(&root_ht->refcnt, 1);
|
||||||
root_ht->handle = tp_c ? gen_new_htid(tp_c, root_ht) : 0x80000000;
|
root_ht->handle = tp_c ? gen_new_htid(tp_c, root_ht) : id2handle(0);
|
||||||
root_ht->prio = tp->prio;
|
root_ht->prio = tp->prio;
|
||||||
root_ht->is_root = true;
|
root_ht->is_root = true;
|
||||||
idr_init(&root_ht->handle_idr);
|
idr_init(&root_ht->handle_idr);
|
||||||
|
|
@ -612,7 +622,7 @@ static int u32_destroy_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht,
|
||||||
if (phn == ht) {
|
if (phn == ht) {
|
||||||
u32_clear_hw_hnode(tp, ht, extack);
|
u32_clear_hw_hnode(tp, ht, extack);
|
||||||
idr_destroy(&ht->handle_idr);
|
idr_destroy(&ht->handle_idr);
|
||||||
idr_remove(&tp_c->handle_idr, ht->handle);
|
idr_remove(&tp_c->handle_idr, handle2id(ht->handle));
|
||||||
RCU_INIT_POINTER(*hn, ht->next);
|
RCU_INIT_POINTER(*hn, ht->next);
|
||||||
kfree_rcu(ht, rcu);
|
kfree_rcu(ht, rcu);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -989,7 +999,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
|
||||||
|
|
||||||
err = u32_replace_hw_hnode(tp, ht, userflags, extack);
|
err = u32_replace_hw_hnode(tp, ht, userflags, extack);
|
||||||
if (err) {
|
if (err) {
|
||||||
idr_remove(&tp_c->handle_idr, handle);
|
idr_remove(&tp_c->handle_idr, handle2id(handle));
|
||||||
kfree(ht);
|
kfree(ht);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -683,7 +683,7 @@ static int sctp_v6_available(union sctp_addr *addr, struct sctp_sock *sp)
|
||||||
struct sock *sk = &sp->inet.sk;
|
struct sock *sk = &sp->inet.sk;
|
||||||
struct net *net = sock_net(sk);
|
struct net *net = sock_net(sk);
|
||||||
struct net_device *dev = NULL;
|
struct net_device *dev = NULL;
|
||||||
int type;
|
int type, res, bound_dev_if;
|
||||||
|
|
||||||
type = ipv6_addr_type(in6);
|
type = ipv6_addr_type(in6);
|
||||||
if (IPV6_ADDR_ANY == type)
|
if (IPV6_ADDR_ANY == type)
|
||||||
|
|
@ -697,14 +697,21 @@ static int sctp_v6_available(union sctp_addr *addr, struct sctp_sock *sp)
|
||||||
if (!(type & IPV6_ADDR_UNICAST))
|
if (!(type & IPV6_ADDR_UNICAST))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (sk->sk_bound_dev_if) {
|
rcu_read_lock();
|
||||||
dev = dev_get_by_index_rcu(net, sk->sk_bound_dev_if);
|
bound_dev_if = READ_ONCE(sk->sk_bound_dev_if);
|
||||||
|
if (bound_dev_if) {
|
||||||
|
res = 0;
|
||||||
|
dev = dev_get_by_index_rcu(net, bound_dev_if);
|
||||||
if (!dev)
|
if (!dev)
|
||||||
return 0;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ipv6_can_nonlocal_bind(net, &sp->inet) ||
|
res = ipv6_can_nonlocal_bind(net, &sp->inet) ||
|
||||||
ipv6_chk_addr(net, in6, dev, 0);
|
ipv6_chk_addr(net, in6, dev, 0);
|
||||||
|
|
||||||
|
out:
|
||||||
|
rcu_read_unlock();
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function checks if the address is a valid address to be used for
|
/* This function checks if the address is a valid address to be used for
|
||||||
|
|
|
||||||
|
|
@ -836,6 +836,9 @@ static void vsock_sk_destruct(struct sock *sk)
|
||||||
{
|
{
|
||||||
struct vsock_sock *vsk = vsock_sk(sk);
|
struct vsock_sock *vsk = vsock_sk(sk);
|
||||||
|
|
||||||
|
/* Flush MSG_ZEROCOPY leftovers. */
|
||||||
|
__skb_queue_purge(&sk->sk_error_queue);
|
||||||
|
|
||||||
vsock_deassign_transport(vsk);
|
vsock_deassign_transport(vsk);
|
||||||
|
|
||||||
/* When clearing these addresses, there's no need to set the family and
|
/* When clearing these addresses, there's no need to set the family and
|
||||||
|
|
|
||||||
|
|
@ -400,6 +400,7 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk,
|
||||||
if (virtio_transport_init_zcopy_skb(vsk, skb,
|
if (virtio_transport_init_zcopy_skb(vsk, skb,
|
||||||
info->msg,
|
info->msg,
|
||||||
can_zcopy)) {
|
can_zcopy)) {
|
||||||
|
kfree_skb(skb);
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -1513,6 +1514,14 @@ virtio_transport_recv_listen(struct sock *sk, struct sk_buff *skb,
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* __vsock_release() might have already flushed accept_queue.
|
||||||
|
* Subsequent enqueues would lead to a memory leak.
|
||||||
|
*/
|
||||||
|
if (sk->sk_shutdown == SHUTDOWN_MASK) {
|
||||||
|
virtio_transport_reset_no_sock(t, skb);
|
||||||
|
return -ESHUTDOWN;
|
||||||
|
}
|
||||||
|
|
||||||
child = vsock_create_connected(sk);
|
child = vsock_create_connected(sk);
|
||||||
if (!child) {
|
if (!child) {
|
||||||
virtio_transport_reset_no_sock(t, skb);
|
virtio_transport_reset_no_sock(t, skb);
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ if [ -n "$DST_PORT" ]; then
|
||||||
pg_set $DEV "udp_dst_max $UDP_DST_MAX"
|
pg_set $DEV "udp_dst_max $UDP_DST_MAX"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
[ ! -z "$UDP_CSUM" ] && pg_set $dev "flag UDPCSUM"
|
[ ! -z "$UDP_CSUM" ] && pg_set $DEV "flag UDPCSUM"
|
||||||
|
|
||||||
# Setup random UDP port src range
|
# Setup random UDP port src range
|
||||||
pg_set $DEV "flag UDPSRC_RND"
|
pg_set $DEV "flag UDPSRC_RND"
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@ ALL_TESTS="
|
||||||
|
|
||||||
lib_dir=$(dirname "$0")
|
lib_dir=$(dirname "$0")
|
||||||
source ${lib_dir}/bond_topo_3d1c.sh
|
source ${lib_dir}/bond_topo_3d1c.sh
|
||||||
|
c_maddr="33:33:00:00:00:10"
|
||||||
|
g_maddr="33:33:00:00:02:54"
|
||||||
|
|
||||||
skip_prio()
|
skip_prio()
|
||||||
{
|
{
|
||||||
|
|
@ -240,6 +242,54 @@ arp_validate_test()
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Testing correct multicast groups are added to slaves for ns targets
|
||||||
|
arp_validate_mcast()
|
||||||
|
{
|
||||||
|
RET=0
|
||||||
|
local arp_valid=$(cmd_jq "ip -n ${s_ns} -j -d link show bond0" ".[].linkinfo.info_data.arp_validate")
|
||||||
|
local active_slave=$(cmd_jq "ip -n ${s_ns} -d -j link show bond0" ".[].linkinfo.info_data.active_slave")
|
||||||
|
|
||||||
|
for i in $(seq 0 2); do
|
||||||
|
maddr_list=$(ip -n ${s_ns} maddr show dev eth${i})
|
||||||
|
|
||||||
|
# arp_valid == 0 or active_slave should not join any maddrs
|
||||||
|
if { [ "$arp_valid" == "null" ] || [ "eth${i}" == ${active_slave} ]; } && \
|
||||||
|
echo "$maddr_list" | grep -qE "${c_maddr}|${g_maddr}"; then
|
||||||
|
RET=1
|
||||||
|
check_err 1 "arp_valid $arp_valid active_slave $active_slave, eth$i has mcast group"
|
||||||
|
# arp_valid != 0 and backup_slave should join both maddrs
|
||||||
|
elif [ "$arp_valid" != "null" ] && [ "eth${i}" != ${active_slave} ] && \
|
||||||
|
( ! echo "$maddr_list" | grep -q "${c_maddr}" || \
|
||||||
|
! echo "$maddr_list" | grep -q "${m_maddr}"); then
|
||||||
|
RET=1
|
||||||
|
check_err 1 "arp_valid $arp_valid active_slave $active_slave, eth$i has mcast group"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Do failover
|
||||||
|
ip -n ${s_ns} link set ${active_slave} down
|
||||||
|
# wait for active link change
|
||||||
|
slowwait 2 active_slave_changed $active_slave
|
||||||
|
active_slave=$(cmd_jq "ip -n ${s_ns} -d -j link show bond0" ".[].linkinfo.info_data.active_slave")
|
||||||
|
|
||||||
|
for i in $(seq 0 2); do
|
||||||
|
maddr_list=$(ip -n ${s_ns} maddr show dev eth${i})
|
||||||
|
|
||||||
|
# arp_valid == 0 or active_slave should not join any maddrs
|
||||||
|
if { [ "$arp_valid" == "null" ] || [ "eth${i}" == ${active_slave} ]; } && \
|
||||||
|
echo "$maddr_list" | grep -qE "${c_maddr}|${g_maddr}"; then
|
||||||
|
RET=1
|
||||||
|
check_err 1 "arp_valid $arp_valid active_slave $active_slave, eth$i has mcast group"
|
||||||
|
# arp_valid != 0 and backup_slave should join both maddrs
|
||||||
|
elif [ "$arp_valid" != "null" ] && [ "eth${i}" != ${active_slave} ] && \
|
||||||
|
( ! echo "$maddr_list" | grep -q "${c_maddr}" || \
|
||||||
|
! echo "$maddr_list" | grep -q "${m_maddr}"); then
|
||||||
|
RET=1
|
||||||
|
check_err 1 "arp_valid $arp_valid active_slave $active_slave, eth$i has mcast group"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
arp_validate_arp()
|
arp_validate_arp()
|
||||||
{
|
{
|
||||||
local mode=$1
|
local mode=$1
|
||||||
|
|
@ -261,8 +311,10 @@ arp_validate_ns()
|
||||||
fi
|
fi
|
||||||
|
|
||||||
for val in $(seq 0 6); do
|
for val in $(seq 0 6); do
|
||||||
arp_validate_test "mode $mode arp_interval 100 ns_ip6_target ${g_ip6} arp_validate $val"
|
arp_validate_test "mode $mode arp_interval 100 ns_ip6_target ${g_ip6},${c_ip6} arp_validate $val"
|
||||||
log_test "arp_validate" "$mode ns_ip6_target arp_validate $val"
|
log_test "arp_validate" "$mode ns_ip6_target arp_validate $val"
|
||||||
|
arp_validate_mcast
|
||||||
|
log_test "arp_validate" "join mcast group"
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ log.txt
|
||||||
msg_oob
|
msg_oob
|
||||||
msg_zerocopy
|
msg_zerocopy
|
||||||
ncdevmem
|
ncdevmem
|
||||||
|
netlink-dumps
|
||||||
nettest
|
nettest
|
||||||
psock_fanout
|
psock_fanout
|
||||||
psock_snd
|
psock_snd
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,7 @@ TEST_PROGS += test_vxlan_vnifiltering.sh
|
||||||
TEST_GEN_FILES += io_uring_zerocopy_tx
|
TEST_GEN_FILES += io_uring_zerocopy_tx
|
||||||
TEST_PROGS += io_uring_zerocopy_tx.sh
|
TEST_PROGS += io_uring_zerocopy_tx.sh
|
||||||
TEST_GEN_FILES += bind_bhash
|
TEST_GEN_FILES += bind_bhash
|
||||||
|
TEST_GEN_PROGS += netlink-dumps
|
||||||
TEST_GEN_PROGS += sk_bind_sendto_listen
|
TEST_GEN_PROGS += sk_bind_sendto_listen
|
||||||
TEST_GEN_PROGS += sk_connect_zero_addr
|
TEST_GEN_PROGS += sk_connect_zero_addr
|
||||||
TEST_GEN_PROGS += sk_so_peek_off
|
TEST_GEN_PROGS += sk_so_peek_off
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,110 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/syscall.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <linux/genetlink.h>
|
||||||
|
#include <linux/netlink.h>
|
||||||
|
#include <linux/mqueue.h>
|
||||||
|
|
||||||
|
#include "../kselftest_harness.h"
|
||||||
|
|
||||||
|
static const struct {
|
||||||
|
struct nlmsghdr nlhdr;
|
||||||
|
struct genlmsghdr genlhdr;
|
||||||
|
struct nlattr ahdr;
|
||||||
|
__u16 val;
|
||||||
|
__u16 pad;
|
||||||
|
} dump_policies = {
|
||||||
|
.nlhdr = {
|
||||||
|
.nlmsg_len = sizeof(dump_policies),
|
||||||
|
.nlmsg_type = GENL_ID_CTRL,
|
||||||
|
.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP,
|
||||||
|
.nlmsg_seq = 1,
|
||||||
|
},
|
||||||
|
.genlhdr = {
|
||||||
|
.cmd = CTRL_CMD_GETPOLICY,
|
||||||
|
.version = 2,
|
||||||
|
},
|
||||||
|
.ahdr = {
|
||||||
|
.nla_len = 6,
|
||||||
|
.nla_type = CTRL_ATTR_FAMILY_ID,
|
||||||
|
},
|
||||||
|
.val = GENL_ID_CTRL,
|
||||||
|
.pad = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Sanity check for the test itself, make sure the dump doesn't fit in one msg
|
||||||
|
TEST(test_sanity)
|
||||||
|
{
|
||||||
|
int netlink_sock;
|
||||||
|
char buf[8192];
|
||||||
|
ssize_t n;
|
||||||
|
|
||||||
|
netlink_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
|
||||||
|
ASSERT_GE(netlink_sock, 0);
|
||||||
|
|
||||||
|
n = send(netlink_sock, &dump_policies, sizeof(dump_policies), 0);
|
||||||
|
ASSERT_EQ(n, sizeof(dump_policies));
|
||||||
|
|
||||||
|
n = recv(netlink_sock, buf, sizeof(buf), MSG_DONTWAIT);
|
||||||
|
ASSERT_GE(n, sizeof(struct nlmsghdr));
|
||||||
|
|
||||||
|
n = recv(netlink_sock, buf, sizeof(buf), MSG_DONTWAIT);
|
||||||
|
ASSERT_GE(n, sizeof(struct nlmsghdr));
|
||||||
|
|
||||||
|
close(netlink_sock);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(close_in_progress)
|
||||||
|
{
|
||||||
|
int netlink_sock;
|
||||||
|
ssize_t n;
|
||||||
|
|
||||||
|
netlink_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
|
||||||
|
ASSERT_GE(netlink_sock, 0);
|
||||||
|
|
||||||
|
n = send(netlink_sock, &dump_policies, sizeof(dump_policies), 0);
|
||||||
|
ASSERT_EQ(n, sizeof(dump_policies));
|
||||||
|
|
||||||
|
close(netlink_sock);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(close_with_ref)
|
||||||
|
{
|
||||||
|
char cookie[NOTIFY_COOKIE_LEN] = {};
|
||||||
|
int netlink_sock, mq_fd;
|
||||||
|
struct sigevent sigev;
|
||||||
|
ssize_t n;
|
||||||
|
|
||||||
|
netlink_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
|
||||||
|
ASSERT_GE(netlink_sock, 0);
|
||||||
|
|
||||||
|
n = send(netlink_sock, &dump_policies, sizeof(dump_policies), 0);
|
||||||
|
ASSERT_EQ(n, sizeof(dump_policies));
|
||||||
|
|
||||||
|
mq_fd = syscall(__NR_mq_open, "sed", O_CREAT | O_WRONLY, 0600, 0);
|
||||||
|
ASSERT_GE(mq_fd, 0);
|
||||||
|
|
||||||
|
memset(&sigev, 0, sizeof(sigev));
|
||||||
|
sigev.sigev_notify = SIGEV_THREAD;
|
||||||
|
sigev.sigev_value.sival_ptr = cookie;
|
||||||
|
sigev.sigev_signo = netlink_sock;
|
||||||
|
|
||||||
|
syscall(__NR_mq_notify, mq_fd, &sigev);
|
||||||
|
|
||||||
|
close(netlink_sock);
|
||||||
|
|
||||||
|
// give mqueue time to fire
|
||||||
|
usleep(100 * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_HARNESS_MAIN
|
||||||
|
|
@ -329,5 +329,29 @@
|
||||||
"teardown": [
|
"teardown": [
|
||||||
"$TC qdisc del dev $DEV1 parent root drr"
|
"$TC qdisc del dev $DEV1 parent root drr"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1234",
|
||||||
|
"name": "Exercise IDR leaks by creating/deleting a filter many (2048) times",
|
||||||
|
"category": [
|
||||||
|
"filter",
|
||||||
|
"u32"
|
||||||
|
],
|
||||||
|
"plugins": {
|
||||||
|
"requires": "nsPlugin"
|
||||||
|
},
|
||||||
|
"setup": [
|
||||||
|
"$TC qdisc add dev $DEV1 parent root handle 10: drr",
|
||||||
|
"$TC filter add dev $DEV1 parent 10:0 protocol ip prio 2 u32 match ip src 0.0.0.2/32 action drop",
|
||||||
|
"$TC filter add dev $DEV1 parent 10:0 protocol ip prio 3 u32 match ip src 0.0.0.3/32 action drop"
|
||||||
|
],
|
||||||
|
"cmdUnderTest": "bash -c 'for i in {1..2048} ;do echo filter delete dev $DEV1 pref 3;echo filter add dev $DEV1 parent 10:0 protocol ip prio 3 u32 match ip src 0.0.0.3/32 action drop;done | $TC -b -'",
|
||||||
|
"expExitCode": "0",
|
||||||
|
"verifyCmd": "$TC filter show dev $DEV1",
|
||||||
|
"matchPattern": "protocol ip pref 3 u32",
|
||||||
|
"matchCount": "3",
|
||||||
|
"teardown": [
|
||||||
|
"$TC qdisc del dev $DEV1 parent root drr"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue