mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2024-12-29 09:13:38 +00:00
Including fixes from bpf and netfilter.
Previous releases - regressions: - Revert "net: rtnetlink: Enslave device before bringing it up", breaks the case inverse to the one it was trying to fix - net: dsa: fix oob access in DSA's netdevice event handler dereference netdev_priv() before check its a DSA port - sched: track device in tcf_block_get/put_ext() only for clsact binder types - net: tls, fix WARNING in __sk_msg_free when record becomes full during splice and MORE hint set - sfp-bus: fix SFP mode detect from bitrate - drv: stmmac: prevent DSA tags from breaking COE Previous releases - always broken: - bpf: fix no forward progress in in bpf_iter_udp if output buffer is too small - bpf: reject variable offset alu on registers with a type of PTR_TO_FLOW_KEYS to prevent oob access - netfilter: tighten input validation - net: add more sanity check in virtio_net_hdr_to_skb() - rxrpc: fix use of Don't Fragment flag on RESPONSE packets, avoid infinite loop - amt: do not use the portion of skb->cb area which may get clobbered - mptcp: improve validation of the MPTCPOPT_MP_JOIN MCTCP option Misc: - spring cleanup of inactive maintainers Signed-off-by: Jakub Kicinski <kuba@kernel.org> -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEE6jPA+I1ugmIBA4hXMUZtbf5SIrsFAmWpnvoACgkQMUZtbf5S Irvskg/+Or5tETxOmpQXxnj6ECZyrSp0Jcyd7+TIcos/7JfPdn3Kebl004SG4h/s bwKDOIIP1iSjQ+0NFsPjyYIVd6wFuCElSB7npV5uQAT6ptXx7A4Ym68/rVxodI8T 6hiYV/mlPuZF8JjRhtp/VJL8sY1qnG7RIUB4oH3y9HQNfwZX0lIWChuUilHuWfbq zQ2Iu97tMkoIBjXrkIT3Qaj0aFxYbjCOrg9zy+FZ69a7Rmrswr//7amlCH6saNTx Ku7Wl8FXhe7O23OiM6GSl7AechSM1aJ5kOS3orseej0+aSp9eH3ekYGmbsQr6sjz ix/eZ7V7SUkJK3bEH5haeymk4TDV3lHE8SziMbosK4wVbHOyPwEmqCxppADYJLZs WycHZKcTBluFBOxknAofH7m5Hh0ToXkeTfpptSSGtRB4WncAOMsMapr3yS4WXg/q AnOo/tzCBgMrnSJtD/kjqgUiCk8vYoLc8lBR9K74l0zqI1sf13OfuTHvEgqIS6z1 Ir/ewlAV6fCH8gQbyzjKUVlyjZS4+vFv19xg/2GgLf+LdyzcCOxUZkND3/DE6+OA Dgf9gtABYU4hGXMUfTfml3KCBTF65QmY8dIh17zraNylYUHEJ2lI4D+sdiqWUrXb mXPBJh4nOPwIV5t2gT80skNwF3aWPr6l4ieY2codSbP04rO74S8= =YhQQ -----END PGP SIGNATURE----- Merge tag 'net-6.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net Pull networking fixes from Jakub Kicinski: "Including fixes from bpf and netfilter. Previous releases - regressions: - Revert "net: rtnetlink: Enslave device before bringing it up", breaks the case inverse to the one it was trying to fix - net: dsa: fix oob access in DSA's netdevice event handler dereference netdev_priv() before check its a DSA port - sched: track device in tcf_block_get/put_ext() only for clsact binder types - net: tls, fix WARNING in __sk_msg_free when record becomes full during splice and MORE hint set - sfp-bus: fix SFP mode detect from bitrate - drv: stmmac: prevent DSA tags from breaking COE Previous releases - always broken: - bpf: fix no forward progress in in bpf_iter_udp if output buffer is too small - bpf: reject variable offset alu on registers with a type of PTR_TO_FLOW_KEYS to prevent oob access - netfilter: tighten input validation - net: add more sanity check in virtio_net_hdr_to_skb() - rxrpc: fix use of Don't Fragment flag on RESPONSE packets, avoid infinite loop - amt: do not use the portion of skb->cb area which may get clobbered - mptcp: improve validation of the MPTCPOPT_MP_JOIN MCTCP option Misc: - spring cleanup of inactive maintainers" * tag 'net-6.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net: (88 commits) i40e: Include types.h to some headers ipv6: mcast: fix data-race in ipv6_mc_down / mld_ifc_work selftests: mlxsw: qos_pfc: Adjust the test to support 8 lanes selftests: mlxsw: qos_pfc: Remove wrong description mlxsw: spectrum_router: Register netdevice notifier before nexthop mlxsw: spectrum_acl_tcam: Fix stack corruption mlxsw: spectrum_acl_tcam: Fix NULL pointer dereference in error path mlxsw: spectrum_acl_erp: Fix error flow of pool allocation failure ethtool: netlink: Add missing ethnl_ops_begin/complete selftests: bonding: Add more missing config options selftests: netdevsim: add a config file libbpf: warn on unexpected __arg_ctx type when rewriting BTF selftests/bpf: add tests confirming type logic in kernel for __arg_ctx bpf: enforce types for __arg_ctx-tagged arguments in global subprogs bpf: extract bpf_ctx_convert_map logic and make it more reusable libbpf: feature-detect arg:ctx tag support in kernel ipvs: avoid stat macros calls from preemptible context netfilter: nf_tables: reject NFT_SET_CONCAT with not field length description netfilter: nf_tables: skip dead set elements in netlink dump netfilter: nf_tables: do not allow mismatch field size and set key length ...
This commit is contained in:
commit
736b5545d3
17
CREDITS
17
CREDITS
@ -179,6 +179,7 @@ E: ralf@gnu.org
|
||||
P: 1024/AF7B30C1 CF 97 C2 CC 6D AE A7 FE C8 BA 9C FC 88 DE 32 C3
|
||||
D: Linux/MIPS port
|
||||
D: Linux/68k hacker
|
||||
D: AX25 maintainer
|
||||
S: Hauptstrasse 19
|
||||
S: 79837 St. Blasien
|
||||
S: Germany
|
||||
@ -677,6 +678,10 @@ D: Media subsystem (V4L/DVB) drivers and core
|
||||
D: EDAC drivers and EDAC 3.0 core rework
|
||||
S: Brazil
|
||||
|
||||
N: Landen Chao
|
||||
E: Landen.Chao@mediatek.com
|
||||
D: MT7531 Ethernet switch support
|
||||
|
||||
N: Raymond Chen
|
||||
E: raymondc@microsoft.com
|
||||
D: Author of Configure script
|
||||
@ -814,6 +819,10 @@ D: Support for Xircom PGSDB9 (firmware and host driver)
|
||||
S: Bucharest
|
||||
S: Romania
|
||||
|
||||
N: John Crispin
|
||||
E: john@phrozen.org
|
||||
D: MediaTek MT7623 Gigabit ethernet support
|
||||
|
||||
N: Laurence Culhane
|
||||
E: loz@holmes.demon.co.uk
|
||||
D: Wrote the initial alpha SLIP code
|
||||
@ -1538,6 +1547,10 @@ N: Andrew Haylett
|
||||
E: ajh@primag.co.uk
|
||||
D: Selection mechanism
|
||||
|
||||
N: Johan Hedberg
|
||||
E: johan.hedberg@gmail.com
|
||||
D: Bluetooth subsystem maintainer
|
||||
|
||||
N: Andre Hedrick
|
||||
E: andre@linux-ide.org
|
||||
E: andre@linuxdiskcert.org
|
||||
@ -3052,6 +3065,10 @@ S: Demonstratsii 8-382
|
||||
S: Tula 300000
|
||||
S: Russia
|
||||
|
||||
N: Thomas Petazzoni
|
||||
E: thomas.petazzoni@bootlin.com
|
||||
D: Driver for the Marvell Armada 370/XP network unit.
|
||||
|
||||
N: Gordon Peters
|
||||
E: GordPeters@smarttech.com
|
||||
D: Isochronous receive for IEEE 1394 driver (OHCI module).
|
||||
|
16
MAINTAINERS
16
MAINTAINERS
@ -3390,9 +3390,8 @@ F: Documentation/devicetree/bindings/iio/adc/avia-hx711.yaml
|
||||
F: drivers/iio/adc/hx711.c
|
||||
|
||||
AX.25 NETWORK LAYER
|
||||
M: Ralf Baechle <ralf@linux-mips.org>
|
||||
L: linux-hams@vger.kernel.org
|
||||
S: Maintained
|
||||
S: Orphan
|
||||
W: https://linux-ax25.in-berlin.de
|
||||
F: include/net/ax25.h
|
||||
F: include/uapi/linux/ax25.h
|
||||
@ -3631,7 +3630,6 @@ F: drivers/mtd/devices/block2mtd.c
|
||||
|
||||
BLUETOOTH DRIVERS
|
||||
M: Marcel Holtmann <marcel@holtmann.org>
|
||||
M: Johan Hedberg <johan.hedberg@gmail.com>
|
||||
M: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
|
||||
L: linux-bluetooth@vger.kernel.org
|
||||
S: Supported
|
||||
@ -4726,11 +4724,8 @@ F: drivers/i2c/busses/i2c-octeon*
|
||||
F: drivers/i2c/busses/i2c-thunderx*
|
||||
|
||||
CAVIUM LIQUIDIO NETWORK DRIVER
|
||||
M: Derek Chickles <dchickles@marvell.com>
|
||||
M: Satanand Burla <sburla@marvell.com>
|
||||
M: Felix Manlunas <fmanlunas@marvell.com>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Supported
|
||||
S: Orphan
|
||||
W: http://www.marvell.com
|
||||
F: drivers/net/ethernet/cavium/liquidio/
|
||||
|
||||
@ -10239,7 +10234,6 @@ IBM Power SRIOV Virtual NIC Device Driver
|
||||
M: Haren Myneni <haren@linux.ibm.com>
|
||||
M: Rick Lindsley <ricklind@linux.ibm.com>
|
||||
R: Nick Child <nnac123@linux.ibm.com>
|
||||
R: Dany Madden <danymadden@us.ibm.com>
|
||||
R: Thomas Falcon <tlfalcon@linux.ibm.com>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Supported
|
||||
@ -13003,10 +12997,10 @@ S: Maintained
|
||||
F: drivers/thermal/armada_thermal.c
|
||||
|
||||
MARVELL MVNETA ETHERNET DRIVER
|
||||
M: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
|
||||
M: Marcin Wojtas <marcin.s.wojtas@gmail.com>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/net/ethernet/marvell/mvneta.*
|
||||
F: drivers/net/ethernet/marvell/mvneta*
|
||||
|
||||
MARVELL MVPP2 ETHERNET DRIVER
|
||||
M: Marcin Wojtas <marcin.s.wojtas@gmail.com>
|
||||
@ -13656,7 +13650,6 @@ F: drivers/dma/mediatek/
|
||||
|
||||
MEDIATEK ETHERNET DRIVER
|
||||
M: Felix Fietkau <nbd@nbd.name>
|
||||
M: John Crispin <john@phrozen.org>
|
||||
M: Sean Wang <sean.wang@mediatek.com>
|
||||
M: Mark Lee <Mark-MC.Lee@mediatek.com>
|
||||
M: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
@ -13812,7 +13805,6 @@ F: include/soc/mediatek/smi.h
|
||||
MEDIATEK SWITCH DRIVER
|
||||
M: Arınç ÜNAL <arinc.unal@arinc9.com>
|
||||
M: Daniel Golle <daniel@makrotopia.org>
|
||||
M: Landen Chao <Landen.Chao@mediatek.com>
|
||||
M: DENG Qingfang <dqfext@gmail.com>
|
||||
M: Sean Wang <sean.wang@mediatek.com>
|
||||
L: netdev@vger.kernel.org
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include <linux/net.h>
|
||||
#include <linux/igmp.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <net/sch_generic.h>
|
||||
#include <net/pkt_sched.h>
|
||||
#include <net/net_namespace.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/udp.h>
|
||||
@ -80,11 +80,11 @@ static struct mld2_grec mldv2_zero_grec;
|
||||
|
||||
static struct amt_skb_cb *amt_skb_cb(struct sk_buff *skb)
|
||||
{
|
||||
BUILD_BUG_ON(sizeof(struct amt_skb_cb) + sizeof(struct qdisc_skb_cb) >
|
||||
BUILD_BUG_ON(sizeof(struct amt_skb_cb) + sizeof(struct tc_skb_cb) >
|
||||
sizeof_field(struct sk_buff, cb));
|
||||
|
||||
return (struct amt_skb_cb *)((void *)skb->cb +
|
||||
sizeof(struct qdisc_skb_cb));
|
||||
sizeof(struct tc_skb_cb));
|
||||
}
|
||||
|
||||
static void __amt_source_gc_work(void)
|
||||
|
@ -1135,6 +1135,8 @@ static int vsc73xx_gpio_probe(struct vsc73xx *vsc)
|
||||
|
||||
vsc->gc.label = devm_kasprintf(vsc->dev, GFP_KERNEL, "VSC%04x",
|
||||
vsc->chipid);
|
||||
if (!vsc->gc.label)
|
||||
return -ENOMEM;
|
||||
vsc->gc.ngpio = 4;
|
||||
vsc->gc.owner = THIS_MODULE;
|
||||
vsc->gc.parent = vsc->dev;
|
||||
|
@ -1490,7 +1490,7 @@ int cn23xx_get_vf_stats(struct octeon_device *oct, int vfidx,
|
||||
mbox_cmd.q_no = vfidx * oct->sriov_info.rings_per_vf;
|
||||
mbox_cmd.recv_len = 0;
|
||||
mbox_cmd.recv_status = 0;
|
||||
mbox_cmd.fn = (octeon_mbox_callback_t)cn23xx_get_vf_stats_callback;
|
||||
mbox_cmd.fn = cn23xx_get_vf_stats_callback;
|
||||
ctx.stats = stats;
|
||||
atomic_set(&ctx.status, 0);
|
||||
mbox_cmd.fn_arg = (void *)&ctx;
|
||||
|
@ -429,7 +429,7 @@ int cn23xx_octeon_pfvf_handshake(struct octeon_device *oct)
|
||||
mbox_cmd.q_no = 0;
|
||||
mbox_cmd.recv_len = 0;
|
||||
mbox_cmd.recv_status = 0;
|
||||
mbox_cmd.fn = (octeon_mbox_callback_t)octeon_pfvf_hs_callback;
|
||||
mbox_cmd.fn = octeon_pfvf_hs_callback;
|
||||
mbox_cmd.fn_arg = &status;
|
||||
|
||||
octeon_mbox_write(oct, &mbox_cmd);
|
||||
|
@ -57,7 +57,10 @@ union octeon_mbox_message {
|
||||
} s;
|
||||
};
|
||||
|
||||
typedef void (*octeon_mbox_callback_t)(void *, void *, void *);
|
||||
struct octeon_mbox_cmd;
|
||||
|
||||
typedef void (*octeon_mbox_callback_t)(struct octeon_device *,
|
||||
struct octeon_mbox_cmd *, void *);
|
||||
|
||||
struct octeon_mbox_cmd {
|
||||
union octeon_mbox_message msg;
|
||||
|
@ -5,6 +5,7 @@
|
||||
#define _I40E_ADMINQ_CMD_H_
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
/* This header file defines the i40e Admin Queue commands and is shared between
|
||||
* i40e Firmware and Software.
|
||||
|
@ -4,6 +4,7 @@
|
||||
#ifndef _I40E_DIAG_H_
|
||||
#define _I40E_DIAG_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include "i40e_adminq_cmd.h"
|
||||
|
||||
/* forward-declare the HW struct for the compiler */
|
||||
|
@ -506,6 +506,7 @@ u32 rpm2_get_lmac_fifo_len(void *rpmd, int lmac_id)
|
||||
rpm_t *rpm = rpmd;
|
||||
u8 num_lmacs;
|
||||
u32 fifo_len;
|
||||
u16 max_lmac;
|
||||
|
||||
lmac_info = rpm_read(rpm, 0, RPM2_CMRX_RX_LMACS);
|
||||
/* LMACs are divided into two groups and each group
|
||||
@ -513,7 +514,11 @@ u32 rpm2_get_lmac_fifo_len(void *rpmd, int lmac_id)
|
||||
* Group0 lmac_id range {0..3}
|
||||
* Group1 lmac_id range {4..7}
|
||||
*/
|
||||
max_lmac = (rpm_read(rpm, 0, CGX_CONST) >> 24) & 0xFF;
|
||||
if (max_lmac > 4)
|
||||
fifo_len = rpm->mac_ops->fifo_len / 2;
|
||||
else
|
||||
fifo_len = rpm->mac_ops->fifo_len;
|
||||
|
||||
if (lmac_id < 4) {
|
||||
num_lmacs = hweight8(lmac_info & 0xF);
|
||||
|
@ -301,6 +301,7 @@ mlxsw_sp_acl_erp_table_alloc(struct mlxsw_sp_acl_erp_core *erp_core,
|
||||
unsigned long *p_index)
|
||||
{
|
||||
unsigned int num_rows, entry_size;
|
||||
unsigned long index;
|
||||
|
||||
/* We only allow allocations of entire rows */
|
||||
if (num_erps % erp_core->num_erp_banks != 0)
|
||||
@ -309,10 +310,11 @@ mlxsw_sp_acl_erp_table_alloc(struct mlxsw_sp_acl_erp_core *erp_core,
|
||||
entry_size = erp_core->erpt_entries_size[region_type];
|
||||
num_rows = num_erps / erp_core->num_erp_banks;
|
||||
|
||||
*p_index = gen_pool_alloc(erp_core->erp_tables, num_rows * entry_size);
|
||||
if (*p_index == 0)
|
||||
index = gen_pool_alloc(erp_core->erp_tables, num_rows * entry_size);
|
||||
if (!index)
|
||||
return -ENOBUFS;
|
||||
*p_index -= MLXSW_SP_ACL_ERP_GENALLOC_OFFSET;
|
||||
|
||||
*p_index = index - MLXSW_SP_ACL_ERP_GENALLOC_OFFSET;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -681,13 +681,13 @@ static void
|
||||
mlxsw_sp_acl_tcam_region_destroy(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_acl_tcam_region *region)
|
||||
{
|
||||
struct mlxsw_sp_acl_tcam *tcam = mlxsw_sp_acl_to_tcam(mlxsw_sp->acl);
|
||||
const struct mlxsw_sp_acl_tcam_ops *ops = mlxsw_sp->acl_tcam_ops;
|
||||
|
||||
ops->region_fini(mlxsw_sp, region->priv);
|
||||
mlxsw_sp_acl_tcam_region_disable(mlxsw_sp, region);
|
||||
mlxsw_sp_acl_tcam_region_free(mlxsw_sp, region);
|
||||
mlxsw_sp_acl_tcam_region_id_put(region->group->tcam,
|
||||
region->id);
|
||||
mlxsw_sp_acl_tcam_region_id_put(tcam, region->id);
|
||||
kfree(region);
|
||||
}
|
||||
|
||||
@ -1564,6 +1564,8 @@ int mlxsw_sp_acl_tcam_init(struct mlxsw_sp *mlxsw_sp,
|
||||
tcam->max_groups = max_groups;
|
||||
tcam->max_group_size = MLXSW_CORE_RES_GET(mlxsw_sp->core,
|
||||
ACL_MAX_GROUP_SIZE);
|
||||
tcam->max_group_size = min_t(unsigned int, tcam->max_group_size,
|
||||
MLXSW_REG_PAGT_ACL_MAX_NUM);
|
||||
|
||||
err = ops->init(mlxsw_sp, tcam->priv, tcam);
|
||||
if (err)
|
||||
|
@ -11472,6 +11472,13 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp,
|
||||
if (err)
|
||||
goto err_register_netevent_notifier;
|
||||
|
||||
mlxsw_sp->router->netdevice_nb.notifier_call =
|
||||
mlxsw_sp_router_netdevice_event;
|
||||
err = register_netdevice_notifier_net(mlxsw_sp_net(mlxsw_sp),
|
||||
&mlxsw_sp->router->netdevice_nb);
|
||||
if (err)
|
||||
goto err_register_netdev_notifier;
|
||||
|
||||
mlxsw_sp->router->nexthop_nb.notifier_call =
|
||||
mlxsw_sp_nexthop_obj_event;
|
||||
err = register_nexthop_notifier(mlxsw_sp_net(mlxsw_sp),
|
||||
@ -11487,22 +11494,15 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp,
|
||||
if (err)
|
||||
goto err_register_fib_notifier;
|
||||
|
||||
mlxsw_sp->router->netdevice_nb.notifier_call =
|
||||
mlxsw_sp_router_netdevice_event;
|
||||
err = register_netdevice_notifier_net(mlxsw_sp_net(mlxsw_sp),
|
||||
&mlxsw_sp->router->netdevice_nb);
|
||||
if (err)
|
||||
goto err_register_netdev_notifier;
|
||||
|
||||
return 0;
|
||||
|
||||
err_register_netdev_notifier:
|
||||
unregister_fib_notifier(mlxsw_sp_net(mlxsw_sp),
|
||||
&mlxsw_sp->router->fib_nb);
|
||||
err_register_fib_notifier:
|
||||
unregister_nexthop_notifier(mlxsw_sp_net(mlxsw_sp),
|
||||
&mlxsw_sp->router->nexthop_nb);
|
||||
err_register_nexthop_notifier:
|
||||
unregister_netdevice_notifier_net(mlxsw_sp_net(mlxsw_sp),
|
||||
&router->netdevice_nb);
|
||||
err_register_netdev_notifier:
|
||||
unregister_netevent_notifier(&mlxsw_sp->router->netevent_nb);
|
||||
err_register_netevent_notifier:
|
||||
unregister_inet6addr_validator_notifier(&router->inet6addr_valid_nb);
|
||||
@ -11550,11 +11550,11 @@ void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp)
|
||||
{
|
||||
struct mlxsw_sp_router *router = mlxsw_sp->router;
|
||||
|
||||
unregister_netdevice_notifier_net(mlxsw_sp_net(mlxsw_sp),
|
||||
&router->netdevice_nb);
|
||||
unregister_fib_notifier(mlxsw_sp_net(mlxsw_sp), &router->fib_nb);
|
||||
unregister_nexthop_notifier(mlxsw_sp_net(mlxsw_sp),
|
||||
&router->nexthop_nb);
|
||||
unregister_netdevice_notifier_net(mlxsw_sp_net(mlxsw_sp),
|
||||
&router->netdevice_nb);
|
||||
unregister_netevent_notifier(&router->netevent_nb);
|
||||
unregister_inet6addr_validator_notifier(&router->inet6addr_valid_nb);
|
||||
unregister_inetaddr_validator_notifier(&router->inetaddr_valid_nb);
|
||||
|
@ -414,6 +414,7 @@ static const u64 fix_mac[] = {
|
||||
END_SIGN
|
||||
};
|
||||
|
||||
MODULE_DESCRIPTION("Neterion 10GbE driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(DRV_VERSION);
|
||||
|
||||
|
@ -396,7 +396,7 @@ static int rmnet_fill_info(struct sk_buff *skb, const struct net_device *dev)
|
||||
|
||||
struct rtnl_link_ops rmnet_link_ops __read_mostly = {
|
||||
.kind = "rmnet",
|
||||
.maxtype = __IFLA_RMNET_MAX,
|
||||
.maxtype = IFLA_RMNET_MAX,
|
||||
.priv_size = sizeof(struct rmnet_priv),
|
||||
.setup = rmnet_vnd_setup,
|
||||
.validate = rmnet_rtnl_validate,
|
||||
|
@ -1949,7 +1949,7 @@ static netdev_tx_t ravb_start_xmit(struct sk_buff *skb, struct net_device *ndev)
|
||||
struct ravb_tstamp_skb *ts_skb;
|
||||
struct ravb_tx_desc *desc;
|
||||
unsigned long flags;
|
||||
u32 dma_addr;
|
||||
dma_addr_t dma_addr;
|
||||
void *buffer;
|
||||
u32 entry;
|
||||
u32 len;
|
||||
|
@ -267,6 +267,7 @@ struct stmmac_priv {
|
||||
u32 msg_enable;
|
||||
int wolopts;
|
||||
int wol_irq;
|
||||
bool wol_irq_disabled;
|
||||
int clk_csr;
|
||||
struct timer_list eee_ctrl_timer;
|
||||
int lpi_irq;
|
||||
|
@ -321,8 +321,9 @@ static int stmmac_ethtool_get_link_ksettings(struct net_device *dev,
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(dev);
|
||||
|
||||
if (priv->hw->pcs & STMMAC_PCS_RGMII ||
|
||||
priv->hw->pcs & STMMAC_PCS_SGMII) {
|
||||
if (!(priv->plat->flags & STMMAC_FLAG_HAS_INTEGRATED_PCS) &&
|
||||
(priv->hw->pcs & STMMAC_PCS_RGMII ||
|
||||
priv->hw->pcs & STMMAC_PCS_SGMII)) {
|
||||
struct rgmii_adv adv;
|
||||
u32 supported, advertising, lp_advertising;
|
||||
|
||||
@ -407,8 +408,9 @@ stmmac_ethtool_set_link_ksettings(struct net_device *dev,
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(dev);
|
||||
|
||||
if (priv->hw->pcs & STMMAC_PCS_RGMII ||
|
||||
priv->hw->pcs & STMMAC_PCS_SGMII) {
|
||||
if (!(priv->plat->flags & STMMAC_FLAG_HAS_INTEGRATED_PCS) &&
|
||||
(priv->hw->pcs & STMMAC_PCS_RGMII ||
|
||||
priv->hw->pcs & STMMAC_PCS_SGMII)) {
|
||||
/* Only support ANE */
|
||||
if (cmd->base.autoneg != AUTONEG_ENABLE)
|
||||
return -EINVAL;
|
||||
@ -830,10 +832,16 @@ static int stmmac_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
|
||||
if (wol->wolopts) {
|
||||
pr_info("stmmac: wakeup enable\n");
|
||||
device_set_wakeup_enable(priv->device, 1);
|
||||
/* Avoid unbalanced enable_irq_wake calls */
|
||||
if (priv->wol_irq_disabled)
|
||||
enable_irq_wake(priv->wol_irq);
|
||||
priv->wol_irq_disabled = false;
|
||||
} else {
|
||||
device_set_wakeup_enable(priv->device, 0);
|
||||
/* Avoid unbalanced disable_irq_wake calls */
|
||||
if (!priv->wol_irq_disabled)
|
||||
disable_irq_wake(priv->wol_irq);
|
||||
priv->wol_irq_disabled = true;
|
||||
}
|
||||
|
||||
mutex_lock(&priv->lock);
|
||||
|
@ -3628,6 +3628,7 @@ static int stmmac_request_irq_multi_msi(struct net_device *dev)
|
||||
/* Request the Wake IRQ in case of another line
|
||||
* is used for WoL
|
||||
*/
|
||||
priv->wol_irq_disabled = true;
|
||||
if (priv->wol_irq > 0 && priv->wol_irq != dev->irq) {
|
||||
int_name = priv->int_name_wol;
|
||||
sprintf(int_name, "%s:%s", dev->name, "wol");
|
||||
@ -4434,6 +4435,28 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_has_ip_ethertype() - Check if packet has IP ethertype
|
||||
* @skb: socket buffer to check
|
||||
*
|
||||
* Check if a packet has an ethertype that will trigger the IP header checks
|
||||
* and IP/TCP checksum engine of the stmmac core.
|
||||
*
|
||||
* Return: true if the ethertype can trigger the checksum engine, false
|
||||
* otherwise
|
||||
*/
|
||||
static bool stmmac_has_ip_ethertype(struct sk_buff *skb)
|
||||
{
|
||||
int depth = 0;
|
||||
__be16 proto;
|
||||
|
||||
proto = __vlan_get_protocol(skb, eth_header_parse_protocol(skb),
|
||||
&depth);
|
||||
|
||||
return (depth <= ETH_HLEN) &&
|
||||
(proto == htons(ETH_P_IP) || proto == htons(ETH_P_IPV6));
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_xmit - Tx entry point of the driver
|
||||
* @skb : the socket buffer
|
||||
@ -4498,9 +4521,13 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
/* DWMAC IPs can be synthesized to support tx coe only for a few tx
|
||||
* queues. In that case, checksum offloading for those queues that don't
|
||||
* support tx coe needs to fallback to software checksum calculation.
|
||||
*
|
||||
* Packets that won't trigger the COE e.g. most DSA-tagged packets will
|
||||
* also have to be checksummed in software.
|
||||
*/
|
||||
if (csum_insertion &&
|
||||
priv->plat->tx_queues_cfg[queue].coe_unsupported) {
|
||||
(priv->plat->tx_queues_cfg[queue].coe_unsupported ||
|
||||
!stmmac_has_ip_ethertype(skb))) {
|
||||
if (unlikely(skb_checksum_help(skb)))
|
||||
goto dma_map_err;
|
||||
csum_insertion = !csum_insertion;
|
||||
@ -5065,7 +5092,7 @@ static void stmmac_dispatch_skb_zc(struct stmmac_priv *priv, u32 queue,
|
||||
stmmac_rx_vlan(priv->dev, skb);
|
||||
skb->protocol = eth_type_trans(skb, priv->dev);
|
||||
|
||||
if (unlikely(!coe))
|
||||
if (unlikely(!coe) || !stmmac_has_ip_ethertype(skb))
|
||||
skb_checksum_none_assert(skb);
|
||||
else
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
@ -5588,7 +5615,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
|
||||
|
||||
skb->protocol = eth_type_trans(skb, priv->dev);
|
||||
|
||||
if (unlikely(!coe))
|
||||
if (unlikely(!coe) || !stmmac_has_ip_ethertype(skb))
|
||||
skb_checksum_none_assert(skb);
|
||||
else
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
|
@ -56,7 +56,7 @@
|
||||
#define AM65_CPSW_MAX_PORTS 8
|
||||
|
||||
#define AM65_CPSW_MIN_PACKET_SIZE VLAN_ETH_ZLEN
|
||||
#define AM65_CPSW_MAX_PACKET_SIZE (VLAN_ETH_FRAME_LEN + ETH_FCS_LEN)
|
||||
#define AM65_CPSW_MAX_PACKET_SIZE 2024
|
||||
|
||||
#define AM65_CPSW_REG_CTL 0x004
|
||||
#define AM65_CPSW_REG_STAT_PORT_EN 0x014
|
||||
@ -2244,7 +2244,8 @@ am65_cpsw_nuss_init_port_ndev(struct am65_cpsw_common *common, u32 port_idx)
|
||||
eth_hw_addr_set(port->ndev, port->slave.mac_addr);
|
||||
|
||||
port->ndev->min_mtu = AM65_CPSW_MIN_PACKET_SIZE;
|
||||
port->ndev->max_mtu = AM65_CPSW_MAX_PACKET_SIZE;
|
||||
port->ndev->max_mtu = AM65_CPSW_MAX_PACKET_SIZE -
|
||||
(VLAN_ETH_HLEN + ETH_FCS_LEN);
|
||||
port->ndev->hw_features = NETIF_F_SG |
|
||||
NETIF_F_RXCSUM |
|
||||
NETIF_F_HW_CSUM |
|
||||
|
@ -26,7 +26,7 @@ config NGBE
|
||||
tristate "Wangxun(R) GbE PCI Express adapters support"
|
||||
depends on PCI
|
||||
select LIBWX
|
||||
select PHYLIB
|
||||
select PHYLINK
|
||||
help
|
||||
This driver supports Wangxun(R) GbE PCI Express family of
|
||||
adapters.
|
||||
|
@ -2769,4 +2769,5 @@ void wx_set_ring(struct wx *wx, u32 new_tx_count,
|
||||
}
|
||||
EXPORT_SYMBOL(wx_set_ring);
|
||||
|
||||
MODULE_DESCRIPTION("Common library for Wangxun(R) Ethernet drivers.");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -369,6 +369,12 @@ static int nsim_init_netdevsim_vf(struct netdevsim *ns)
|
||||
return err;
|
||||
}
|
||||
|
||||
static void nsim_exit_netdevsim(struct netdevsim *ns)
|
||||
{
|
||||
nsim_udp_tunnels_info_destroy(ns->netdev);
|
||||
mock_phc_destroy(ns->phc);
|
||||
}
|
||||
|
||||
struct netdevsim *
|
||||
nsim_create(struct nsim_dev *nsim_dev, struct nsim_dev_port *nsim_dev_port)
|
||||
{
|
||||
@ -417,8 +423,7 @@ void nsim_destroy(struct netdevsim *ns)
|
||||
}
|
||||
rtnl_unlock();
|
||||
if (nsim_dev_port_is_pf(ns->nsim_dev_port))
|
||||
nsim_udp_tunnels_info_destroy(dev);
|
||||
mock_phc_destroy(ns->phc);
|
||||
nsim_exit_netdevsim(ns);
|
||||
free_netdev(dev);
|
||||
}
|
||||
|
||||
|
@ -3338,8 +3338,10 @@ static int lan8814_probe(struct phy_device *phydev)
|
||||
#define LAN8841_ADC_CHANNEL_MASK 198
|
||||
#define LAN8841_PTP_RX_PARSE_L2_ADDR_EN 370
|
||||
#define LAN8841_PTP_RX_PARSE_IP_ADDR_EN 371
|
||||
#define LAN8841_PTP_RX_VERSION 374
|
||||
#define LAN8841_PTP_TX_PARSE_L2_ADDR_EN 434
|
||||
#define LAN8841_PTP_TX_PARSE_IP_ADDR_EN 435
|
||||
#define LAN8841_PTP_TX_VERSION 438
|
||||
#define LAN8841_PTP_CMD_CTL 256
|
||||
#define LAN8841_PTP_CMD_CTL_PTP_ENABLE BIT(2)
|
||||
#define LAN8841_PTP_CMD_CTL_PTP_DISABLE BIT(1)
|
||||
@ -3383,6 +3385,12 @@ static int lan8841_config_init(struct phy_device *phydev)
|
||||
phy_write_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG,
|
||||
LAN8841_PTP_RX_PARSE_IP_ADDR_EN, 0);
|
||||
|
||||
/* Disable checking for minorVersionPTP field */
|
||||
phy_write_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG,
|
||||
LAN8841_PTP_RX_VERSION, 0xff00);
|
||||
phy_write_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG,
|
||||
LAN8841_PTP_TX_VERSION, 0xff00);
|
||||
|
||||
/* 100BT Clause 40 improvenent errata */
|
||||
phy_write_mmd(phydev, LAN8841_MMD_ANALOG_REG,
|
||||
LAN8841_ANALOG_CONTROL_1,
|
||||
@ -4839,6 +4847,7 @@ static struct phy_driver ksphy_driver[] = {
|
||||
.flags = PHY_POLL_CABLE_TEST,
|
||||
.driver_data = &ksz9131_type,
|
||||
.probe = kszphy_probe,
|
||||
.soft_reset = genphy_soft_reset,
|
||||
.config_init = ksz9131_config_init,
|
||||
.config_intr = kszphy_config_intr,
|
||||
.config_aneg = ksz9131_config_aneg,
|
||||
|
@ -151,10 +151,6 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
|
||||
unsigned int br_min, br_nom, br_max;
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(modes) = { 0, };
|
||||
|
||||
phylink_set(modes, Autoneg);
|
||||
phylink_set(modes, Pause);
|
||||
phylink_set(modes, Asym_Pause);
|
||||
|
||||
/* Decode the bitrate information to MBd */
|
||||
br_min = br_nom = br_max = 0;
|
||||
if (id->base.br_nominal) {
|
||||
@ -339,6 +335,10 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
|
||||
}
|
||||
}
|
||||
|
||||
phylink_set(modes, Autoneg);
|
||||
phylink_set(modes, Pause);
|
||||
phylink_set(modes, Asym_Pause);
|
||||
|
||||
if (bus->sfp_quirk && bus->sfp_quirk->modes)
|
||||
bus->sfp_quirk->modes(id, modes, interfaces);
|
||||
|
||||
|
@ -752,4 +752,5 @@ EXPORT_SYMBOL(slhc_compress);
|
||||
EXPORT_SYMBOL(slhc_uncompress);
|
||||
EXPORT_SYMBOL(slhc_toss);
|
||||
|
||||
MODULE_DESCRIPTION("Compression helpers for SLIP (serial line)");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
|
@ -1437,5 +1437,6 @@ static void sl_keepalive(struct timer_list *t)
|
||||
}
|
||||
|
||||
#endif
|
||||
MODULE_DESCRIPTION("SLIP (serial line) protocol module");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS_LDISC(N_SLIP);
|
||||
|
@ -4295,10 +4295,11 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
|
||||
{
|
||||
vq_callback_t **callbacks;
|
||||
struct virtqueue **vqs;
|
||||
int ret = -ENOMEM;
|
||||
int i, total_vqs;
|
||||
const char **names;
|
||||
int ret = -ENOMEM;
|
||||
int total_vqs;
|
||||
bool *ctx;
|
||||
u16 i;
|
||||
|
||||
/* We expect 1 RX virtqueue followed by 1 TX virtqueue, followed by
|
||||
* possible N-1 RX/TX queue pairs used in multiqueue mode, followed by
|
||||
@ -4335,8 +4336,8 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
|
||||
for (i = 0; i < vi->max_queue_pairs; i++) {
|
||||
callbacks[rxq2vq(i)] = skb_recv_done;
|
||||
callbacks[txq2vq(i)] = skb_xmit_done;
|
||||
sprintf(vi->rq[i].name, "input.%d", i);
|
||||
sprintf(vi->sq[i].name, "output.%d", i);
|
||||
sprintf(vi->rq[i].name, "input.%u", i);
|
||||
sprintf(vi->sq[i].name, "output.%u", i);
|
||||
names[rxq2vq(i)] = vi->rq[i].name;
|
||||
names[txq2vq(i)] = vi->sq[i].name;
|
||||
if (ctx)
|
||||
|
@ -28,6 +28,7 @@
|
||||
|
||||
static struct spi_device *g_spi;
|
||||
|
||||
MODULE_DESCRIPTION("Slic Maxim DS26522 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Zhao Qiang<B45475@freescale.com>");
|
||||
|
||||
|
@ -512,7 +512,7 @@ s32 btf_find_dtor_kfunc(struct btf *btf, u32 btf_id);
|
||||
int register_btf_id_dtor_kfuncs(const struct btf_id_dtor_kfunc *dtors, u32 add_cnt,
|
||||
struct module *owner);
|
||||
struct btf_struct_meta *btf_find_struct_meta(const struct btf *btf, u32 btf_id);
|
||||
const struct btf_member *
|
||||
const struct btf_type *
|
||||
btf_get_prog_ctx_type(struct bpf_verifier_log *log, const struct btf *btf,
|
||||
const struct btf_type *t, enum bpf_prog_type prog_type,
|
||||
int arg);
|
||||
|
@ -42,7 +42,7 @@ static inline int nf_bridge_get_physinif(const struct sk_buff *skb)
|
||||
if (!nf_bridge)
|
||||
return 0;
|
||||
|
||||
return nf_bridge->physindev ? nf_bridge->physindev->ifindex : 0;
|
||||
return nf_bridge->physinif;
|
||||
}
|
||||
|
||||
static inline int nf_bridge_get_physoutif(const struct sk_buff *skb)
|
||||
@ -56,11 +56,11 @@ static inline int nf_bridge_get_physoutif(const struct sk_buff *skb)
|
||||
}
|
||||
|
||||
static inline struct net_device *
|
||||
nf_bridge_get_physindev(const struct sk_buff *skb)
|
||||
nf_bridge_get_physindev(const struct sk_buff *skb, struct net *net)
|
||||
{
|
||||
const struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb);
|
||||
|
||||
return nf_bridge ? nf_bridge->physindev : NULL;
|
||||
return nf_bridge ? dev_get_by_index_rcu(net, nf_bridge->physinif) : NULL;
|
||||
}
|
||||
|
||||
static inline struct net_device *
|
||||
|
@ -295,7 +295,7 @@ struct nf_bridge_info {
|
||||
u8 bridged_dnat:1;
|
||||
u8 sabotage_in_done:1;
|
||||
__u16 frag_max_size;
|
||||
struct net_device *physindev;
|
||||
int physinif;
|
||||
|
||||
/* always valid & non-NULL from FORWARD on, for physdev match */
|
||||
struct net_device *physoutdev;
|
||||
|
@ -3,6 +3,8 @@
|
||||
#define _LINUX_VIRTIO_NET_H
|
||||
|
||||
#include <linux/if_vlan.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <linux/udp.h>
|
||||
#include <uapi/linux/tcp.h>
|
||||
#include <uapi/linux/virtio_net.h>
|
||||
@ -49,6 +51,7 @@ static inline int virtio_net_hdr_to_skb(struct sk_buff *skb,
|
||||
const struct virtio_net_hdr *hdr,
|
||||
bool little_endian)
|
||||
{
|
||||
unsigned int nh_min_len = sizeof(struct iphdr);
|
||||
unsigned int gso_type = 0;
|
||||
unsigned int thlen = 0;
|
||||
unsigned int p_off = 0;
|
||||
@ -65,6 +68,7 @@ static inline int virtio_net_hdr_to_skb(struct sk_buff *skb,
|
||||
gso_type = SKB_GSO_TCPV6;
|
||||
ip_proto = IPPROTO_TCP;
|
||||
thlen = sizeof(struct tcphdr);
|
||||
nh_min_len = sizeof(struct ipv6hdr);
|
||||
break;
|
||||
case VIRTIO_NET_HDR_GSO_UDP:
|
||||
gso_type = SKB_GSO_UDP;
|
||||
@ -100,7 +104,8 @@ static inline int virtio_net_hdr_to_skb(struct sk_buff *skb,
|
||||
if (!skb_partial_csum_set(skb, start, off))
|
||||
return -EINVAL;
|
||||
|
||||
p_off = skb_transport_offset(skb) + thlen;
|
||||
nh_min_len = max_t(u32, nh_min_len, skb_transport_offset(skb));
|
||||
p_off = nh_min_len + thlen;
|
||||
if (!pskb_may_pull(skb, p_off))
|
||||
return -EINVAL;
|
||||
} else {
|
||||
@ -140,7 +145,7 @@ static inline int virtio_net_hdr_to_skb(struct sk_buff *skb,
|
||||
|
||||
skb_set_transport_header(skb, keys.control.thoff);
|
||||
} else if (gso_type) {
|
||||
p_off = thlen;
|
||||
p_off = nh_min_len + thlen;
|
||||
if (!pskb_may_pull(skb, p_off))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -128,7 +128,7 @@ netdev_txq_completed_mb(struct netdev_queue *dev_queue,
|
||||
netdev_txq_completed_mb(txq, pkts, bytes); \
|
||||
\
|
||||
_res = -1; \
|
||||
if (pkts && likely(get_desc > start_thrs)) { \
|
||||
if (pkts && likely(get_desc >= start_thrs)) { \
|
||||
_res = 1; \
|
||||
if (unlikely(netif_tx_queue_stopped(txq)) && \
|
||||
!(down_cond)) { \
|
||||
|
231
kernel/bpf/btf.c
231
kernel/bpf/btf.c
@ -5615,21 +5615,46 @@ static u8 bpf_ctx_convert_map[] = {
|
||||
#undef BPF_MAP_TYPE
|
||||
#undef BPF_LINK_TYPE
|
||||
|
||||
const struct btf_member *
|
||||
static const struct btf_type *find_canonical_prog_ctx_type(enum bpf_prog_type prog_type)
|
||||
{
|
||||
const struct btf_type *conv_struct;
|
||||
const struct btf_member *ctx_type;
|
||||
|
||||
conv_struct = bpf_ctx_convert.t;
|
||||
if (!conv_struct)
|
||||
return NULL;
|
||||
/* prog_type is valid bpf program type. No need for bounds check. */
|
||||
ctx_type = btf_type_member(conv_struct) + bpf_ctx_convert_map[prog_type] * 2;
|
||||
/* ctx_type is a pointer to prog_ctx_type in vmlinux.
|
||||
* Like 'struct __sk_buff'
|
||||
*/
|
||||
return btf_type_by_id(btf_vmlinux, ctx_type->type);
|
||||
}
|
||||
|
||||
static int find_kern_ctx_type_id(enum bpf_prog_type prog_type)
|
||||
{
|
||||
const struct btf_type *conv_struct;
|
||||
const struct btf_member *ctx_type;
|
||||
|
||||
conv_struct = bpf_ctx_convert.t;
|
||||
if (!conv_struct)
|
||||
return -EFAULT;
|
||||
/* prog_type is valid bpf program type. No need for bounds check. */
|
||||
ctx_type = btf_type_member(conv_struct) + bpf_ctx_convert_map[prog_type] * 2 + 1;
|
||||
/* ctx_type is a pointer to prog_ctx_type in vmlinux.
|
||||
* Like 'struct sk_buff'
|
||||
*/
|
||||
return ctx_type->type;
|
||||
}
|
||||
|
||||
const struct btf_type *
|
||||
btf_get_prog_ctx_type(struct bpf_verifier_log *log, const struct btf *btf,
|
||||
const struct btf_type *t, enum bpf_prog_type prog_type,
|
||||
int arg)
|
||||
{
|
||||
const struct btf_type *conv_struct;
|
||||
const struct btf_type *ctx_struct;
|
||||
const struct btf_member *ctx_type;
|
||||
const struct btf_type *ctx_type;
|
||||
const char *tname, *ctx_tname;
|
||||
|
||||
conv_struct = bpf_ctx_convert.t;
|
||||
if (!conv_struct) {
|
||||
bpf_log(log, "btf_vmlinux is malformed\n");
|
||||
return NULL;
|
||||
}
|
||||
t = btf_type_by_id(btf, t->type);
|
||||
while (btf_type_is_modifier(t))
|
||||
t = btf_type_by_id(btf, t->type);
|
||||
@ -5646,17 +5671,15 @@ btf_get_prog_ctx_type(struct bpf_verifier_log *log, const struct btf *btf,
|
||||
bpf_log(log, "arg#%d struct doesn't have a name\n", arg);
|
||||
return NULL;
|
||||
}
|
||||
/* prog_type is valid bpf program type. No need for bounds check. */
|
||||
ctx_type = btf_type_member(conv_struct) + bpf_ctx_convert_map[prog_type] * 2;
|
||||
/* ctx_struct is a pointer to prog_ctx_type in vmlinux.
|
||||
* Like 'struct __sk_buff'
|
||||
*/
|
||||
ctx_struct = btf_type_by_id(btf_vmlinux, ctx_type->type);
|
||||
if (!ctx_struct)
|
||||
|
||||
ctx_type = find_canonical_prog_ctx_type(prog_type);
|
||||
if (!ctx_type) {
|
||||
bpf_log(log, "btf_vmlinux is malformed\n");
|
||||
/* should not happen */
|
||||
return NULL;
|
||||
}
|
||||
again:
|
||||
ctx_tname = btf_name_by_offset(btf_vmlinux, ctx_struct->name_off);
|
||||
ctx_tname = btf_name_by_offset(btf_vmlinux, ctx_type->name_off);
|
||||
if (!ctx_tname) {
|
||||
/* should not happen */
|
||||
bpf_log(log, "Please fix kernel include/linux/bpf_types.h\n");
|
||||
@ -5677,28 +5700,167 @@ btf_get_prog_ctx_type(struct bpf_verifier_log *log, const struct btf *btf,
|
||||
/* bpf_user_pt_regs_t is a typedef, so resolve it to
|
||||
* underlying struct and check name again
|
||||
*/
|
||||
if (!btf_type_is_modifier(ctx_struct))
|
||||
if (!btf_type_is_modifier(ctx_type))
|
||||
return NULL;
|
||||
while (btf_type_is_modifier(ctx_struct))
|
||||
ctx_struct = btf_type_by_id(btf_vmlinux, ctx_struct->type);
|
||||
while (btf_type_is_modifier(ctx_type))
|
||||
ctx_type = btf_type_by_id(btf_vmlinux, ctx_type->type);
|
||||
goto again;
|
||||
}
|
||||
return ctx_type;
|
||||
}
|
||||
|
||||
/* forward declarations for arch-specific underlying types of
|
||||
* bpf_user_pt_regs_t; this avoids the need for arch-specific #ifdef
|
||||
* compilation guards below for BPF_PROG_TYPE_PERF_EVENT checks, but still
|
||||
* works correctly with __builtin_types_compatible_p() on respective
|
||||
* architectures
|
||||
*/
|
||||
struct user_regs_struct;
|
||||
struct user_pt_regs;
|
||||
|
||||
static int btf_validate_prog_ctx_type(struct bpf_verifier_log *log, const struct btf *btf,
|
||||
const struct btf_type *t, int arg,
|
||||
enum bpf_prog_type prog_type,
|
||||
enum bpf_attach_type attach_type)
|
||||
{
|
||||
const struct btf_type *ctx_type;
|
||||
const char *tname, *ctx_tname;
|
||||
|
||||
if (!btf_is_ptr(t)) {
|
||||
bpf_log(log, "arg#%d type isn't a pointer\n", arg);
|
||||
return -EINVAL;
|
||||
}
|
||||
t = btf_type_by_id(btf, t->type);
|
||||
|
||||
/* KPROBE and PERF_EVENT programs allow bpf_user_pt_regs_t typedef */
|
||||
if (prog_type == BPF_PROG_TYPE_KPROBE || prog_type == BPF_PROG_TYPE_PERF_EVENT) {
|
||||
while (btf_type_is_modifier(t) && !btf_type_is_typedef(t))
|
||||
t = btf_type_by_id(btf, t->type);
|
||||
|
||||
if (btf_type_is_typedef(t)) {
|
||||
tname = btf_name_by_offset(btf, t->name_off);
|
||||
if (tname && strcmp(tname, "bpf_user_pt_regs_t") == 0)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* all other program types don't use typedefs for context type */
|
||||
while (btf_type_is_modifier(t))
|
||||
t = btf_type_by_id(btf, t->type);
|
||||
|
||||
/* `void *ctx __arg_ctx` is always valid */
|
||||
if (btf_type_is_void(t))
|
||||
return 0;
|
||||
|
||||
tname = btf_name_by_offset(btf, t->name_off);
|
||||
if (str_is_empty(tname)) {
|
||||
bpf_log(log, "arg#%d type doesn't have a name\n", arg);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* special cases */
|
||||
switch (prog_type) {
|
||||
case BPF_PROG_TYPE_KPROBE:
|
||||
if (__btf_type_is_struct(t) && strcmp(tname, "pt_regs") == 0)
|
||||
return 0;
|
||||
break;
|
||||
case BPF_PROG_TYPE_PERF_EVENT:
|
||||
if (__builtin_types_compatible_p(bpf_user_pt_regs_t, struct pt_regs) &&
|
||||
__btf_type_is_struct(t) && strcmp(tname, "pt_regs") == 0)
|
||||
return 0;
|
||||
if (__builtin_types_compatible_p(bpf_user_pt_regs_t, struct user_pt_regs) &&
|
||||
__btf_type_is_struct(t) && strcmp(tname, "user_pt_regs") == 0)
|
||||
return 0;
|
||||
if (__builtin_types_compatible_p(bpf_user_pt_regs_t, struct user_regs_struct) &&
|
||||
__btf_type_is_struct(t) && strcmp(tname, "user_regs_struct") == 0)
|
||||
return 0;
|
||||
break;
|
||||
case BPF_PROG_TYPE_RAW_TRACEPOINT:
|
||||
case BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE:
|
||||
/* allow u64* as ctx */
|
||||
if (btf_is_int(t) && t->size == 8)
|
||||
return 0;
|
||||
break;
|
||||
case BPF_PROG_TYPE_TRACING:
|
||||
switch (attach_type) {
|
||||
case BPF_TRACE_RAW_TP:
|
||||
/* tp_btf program is TRACING, so need special case here */
|
||||
if (__btf_type_is_struct(t) &&
|
||||
strcmp(tname, "bpf_raw_tracepoint_args") == 0)
|
||||
return 0;
|
||||
/* allow u64* as ctx */
|
||||
if (btf_is_int(t) && t->size == 8)
|
||||
return 0;
|
||||
break;
|
||||
case BPF_TRACE_ITER:
|
||||
/* allow struct bpf_iter__xxx types only */
|
||||
if (__btf_type_is_struct(t) &&
|
||||
strncmp(tname, "bpf_iter__", sizeof("bpf_iter__") - 1) == 0)
|
||||
return 0;
|
||||
break;
|
||||
case BPF_TRACE_FENTRY:
|
||||
case BPF_TRACE_FEXIT:
|
||||
case BPF_MODIFY_RETURN:
|
||||
/* allow u64* as ctx */
|
||||
if (btf_is_int(t) && t->size == 8)
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case BPF_PROG_TYPE_LSM:
|
||||
case BPF_PROG_TYPE_STRUCT_OPS:
|
||||
/* allow u64* as ctx */
|
||||
if (btf_is_int(t) && t->size == 8)
|
||||
return 0;
|
||||
break;
|
||||
case BPF_PROG_TYPE_TRACEPOINT:
|
||||
case BPF_PROG_TYPE_SYSCALL:
|
||||
case BPF_PROG_TYPE_EXT:
|
||||
return 0; /* anything goes */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ctx_type = find_canonical_prog_ctx_type(prog_type);
|
||||
if (!ctx_type) {
|
||||
/* should not happen */
|
||||
bpf_log(log, "btf_vmlinux is malformed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* resolve typedefs and check that underlying structs are matching as well */
|
||||
while (btf_type_is_modifier(ctx_type))
|
||||
ctx_type = btf_type_by_id(btf_vmlinux, ctx_type->type);
|
||||
|
||||
/* if program type doesn't have distinctly named struct type for
|
||||
* context, then __arg_ctx argument can only be `void *`, which we
|
||||
* already checked above
|
||||
*/
|
||||
if (!__btf_type_is_struct(ctx_type)) {
|
||||
bpf_log(log, "arg#%d should be void pointer\n", arg);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ctx_tname = btf_name_by_offset(btf_vmlinux, ctx_type->name_off);
|
||||
if (!__btf_type_is_struct(t) || strcmp(ctx_tname, tname) != 0) {
|
||||
bpf_log(log, "arg#%d should be `struct %s *`\n", arg, ctx_tname);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btf_translate_to_vmlinux(struct bpf_verifier_log *log,
|
||||
struct btf *btf,
|
||||
const struct btf_type *t,
|
||||
enum bpf_prog_type prog_type,
|
||||
int arg)
|
||||
{
|
||||
const struct btf_member *prog_ctx_type, *kern_ctx_type;
|
||||
|
||||
prog_ctx_type = btf_get_prog_ctx_type(log, btf, t, prog_type, arg);
|
||||
if (!prog_ctx_type)
|
||||
if (!btf_get_prog_ctx_type(log, btf, t, prog_type, arg))
|
||||
return -ENOENT;
|
||||
kern_ctx_type = prog_ctx_type + 1;
|
||||
return kern_ctx_type->type;
|
||||
return find_kern_ctx_type_id(prog_type);
|
||||
}
|
||||
|
||||
int get_kern_ctx_btf_id(struct bpf_verifier_log *log, enum bpf_prog_type prog_type)
|
||||
@ -6934,6 +7096,23 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < nargs; i++) {
|
||||
const char *tag;
|
||||
|
||||
if (sub->args[i].arg_type != ARG_PTR_TO_CTX)
|
||||
continue;
|
||||
|
||||
/* check if arg has "arg:ctx" tag */
|
||||
t = btf_type_by_id(btf, args[i].type);
|
||||
tag = btf_find_decl_tag_value(btf, fn_t, i, "arg:");
|
||||
if (IS_ERR_OR_NULL(tag) || strcmp(tag, "ctx") != 0)
|
||||
continue;
|
||||
|
||||
if (btf_validate_prog_ctx_type(log, btf, t, i, prog_type,
|
||||
prog->expected_attach_type))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sub->arg_cnt = nargs;
|
||||
sub->args_cached = true;
|
||||
|
||||
|
@ -12826,6 +12826,10 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
|
||||
}
|
||||
|
||||
switch (base_type(ptr_reg->type)) {
|
||||
case PTR_TO_FLOW_KEYS:
|
||||
if (known)
|
||||
break;
|
||||
fallthrough;
|
||||
case CONST_PTR_TO_MAP:
|
||||
/* smin_val represents the known value */
|
||||
if (known && smin_val == 0 && opcode == BPF_ADD)
|
||||
|
@ -279,8 +279,17 @@ int br_nf_pre_routing_finish_bridge(struct net *net, struct sock *sk, struct sk_
|
||||
|
||||
if ((READ_ONCE(neigh->nud_state) & NUD_CONNECTED) &&
|
||||
READ_ONCE(neigh->hh.hh_len)) {
|
||||
struct net_device *br_indev;
|
||||
|
||||
br_indev = nf_bridge_get_physindev(skb, net);
|
||||
if (!br_indev) {
|
||||
neigh_release(neigh);
|
||||
goto free_skb;
|
||||
}
|
||||
|
||||
neigh_hh_bridge(&neigh->hh, skb);
|
||||
skb->dev = nf_bridge->physindev;
|
||||
skb->dev = br_indev;
|
||||
|
||||
ret = br_handle_frame_finish(net, sk, skb);
|
||||
} else {
|
||||
/* the neighbour function below overwrites the complete
|
||||
@ -352,12 +361,18 @@ br_nf_ipv4_daddr_was_changed(const struct sk_buff *skb,
|
||||
*/
|
||||
static int br_nf_pre_routing_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
struct net_device *dev = skb->dev;
|
||||
struct net_device *dev = skb->dev, *br_indev;
|
||||
struct iphdr *iph = ip_hdr(skb);
|
||||
struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb);
|
||||
struct rtable *rt;
|
||||
int err;
|
||||
|
||||
br_indev = nf_bridge_get_physindev(skb, net);
|
||||
if (!br_indev) {
|
||||
kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
nf_bridge->frag_max_size = IPCB(skb)->frag_max_size;
|
||||
|
||||
if (nf_bridge->pkt_otherhost) {
|
||||
@ -397,7 +412,7 @@ static int br_nf_pre_routing_finish(struct net *net, struct sock *sk, struct sk_
|
||||
} else {
|
||||
if (skb_dst(skb)->dev == dev) {
|
||||
bridged_dnat:
|
||||
skb->dev = nf_bridge->physindev;
|
||||
skb->dev = br_indev;
|
||||
nf_bridge_update_protocol(skb);
|
||||
nf_bridge_push_encap_header(skb);
|
||||
br_nf_hook_thresh(NF_BR_PRE_ROUTING,
|
||||
@ -410,7 +425,7 @@ static int br_nf_pre_routing_finish(struct net *net, struct sock *sk, struct sk_
|
||||
skb->pkt_type = PACKET_HOST;
|
||||
}
|
||||
} else {
|
||||
rt = bridge_parent_rtable(nf_bridge->physindev);
|
||||
rt = bridge_parent_rtable(br_indev);
|
||||
if (!rt) {
|
||||
kfree_skb(skb);
|
||||
return 0;
|
||||
@ -419,7 +434,7 @@ static int br_nf_pre_routing_finish(struct net *net, struct sock *sk, struct sk_
|
||||
skb_dst_set_noref(skb, &rt->dst);
|
||||
}
|
||||
|
||||
skb->dev = nf_bridge->physindev;
|
||||
skb->dev = br_indev;
|
||||
nf_bridge_update_protocol(skb);
|
||||
nf_bridge_push_encap_header(skb);
|
||||
br_nf_hook_thresh(NF_BR_PRE_ROUTING, net, sk, skb, skb->dev, NULL,
|
||||
@ -456,7 +471,7 @@ struct net_device *setup_pre_routing(struct sk_buff *skb, const struct net *net)
|
||||
}
|
||||
|
||||
nf_bridge->in_prerouting = 1;
|
||||
nf_bridge->physindev = skb->dev;
|
||||
nf_bridge->physinif = skb->dev->ifindex;
|
||||
skb->dev = brnf_get_logical_dev(skb, skb->dev, net);
|
||||
|
||||
if (skb->protocol == htons(ETH_P_8021Q))
|
||||
@ -553,7 +568,11 @@ static int br_nf_forward_finish(struct net *net, struct sock *sk, struct sk_buff
|
||||
if (skb->protocol == htons(ETH_P_IPV6))
|
||||
nf_bridge->frag_max_size = IP6CB(skb)->frag_max_size;
|
||||
|
||||
in = nf_bridge->physindev;
|
||||
in = nf_bridge_get_physindev(skb, net);
|
||||
if (!in) {
|
||||
kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
if (nf_bridge->pkt_otherhost) {
|
||||
skb->pkt_type = PACKET_OTHERHOST;
|
||||
nf_bridge->pkt_otherhost = false;
|
||||
@ -899,6 +918,13 @@ static unsigned int ip_sabotage_in(void *priv,
|
||||
static void br_nf_pre_routing_finish_bridge_slow(struct sk_buff *skb)
|
||||
{
|
||||
struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb);
|
||||
struct net_device *br_indev;
|
||||
|
||||
br_indev = nf_bridge_get_physindev(skb, dev_net(skb->dev));
|
||||
if (!br_indev) {
|
||||
kfree_skb(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
skb_pull(skb, ETH_HLEN);
|
||||
nf_bridge->bridged_dnat = 0;
|
||||
@ -908,7 +934,7 @@ static void br_nf_pre_routing_finish_bridge_slow(struct sk_buff *skb)
|
||||
skb_copy_to_linear_data_offset(skb, -(ETH_HLEN - ETH_ALEN),
|
||||
nf_bridge->neigh_header,
|
||||
ETH_HLEN - ETH_ALEN);
|
||||
skb->dev = nf_bridge->physindev;
|
||||
skb->dev = br_indev;
|
||||
|
||||
nf_bridge->physoutdev = NULL;
|
||||
br_handle_frame_finish(dev_net(skb->dev), NULL, skb);
|
||||
|
@ -102,9 +102,15 @@ static int br_nf_pre_routing_finish_ipv6(struct net *net, struct sock *sk, struc
|
||||
{
|
||||
struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb);
|
||||
struct rtable *rt;
|
||||
struct net_device *dev = skb->dev;
|
||||
struct net_device *dev = skb->dev, *br_indev;
|
||||
const struct nf_ipv6_ops *v6ops = nf_get_ipv6_ops();
|
||||
|
||||
br_indev = nf_bridge_get_physindev(skb, net);
|
||||
if (!br_indev) {
|
||||
kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
nf_bridge->frag_max_size = IP6CB(skb)->frag_max_size;
|
||||
|
||||
if (nf_bridge->pkt_otherhost) {
|
||||
@ -122,7 +128,7 @@ static int br_nf_pre_routing_finish_ipv6(struct net *net, struct sock *sk, struc
|
||||
}
|
||||
|
||||
if (skb_dst(skb)->dev == dev) {
|
||||
skb->dev = nf_bridge->physindev;
|
||||
skb->dev = br_indev;
|
||||
nf_bridge_update_protocol(skb);
|
||||
nf_bridge_push_encap_header(skb);
|
||||
br_nf_hook_thresh(NF_BR_PRE_ROUTING,
|
||||
@ -133,7 +139,7 @@ static int br_nf_pre_routing_finish_ipv6(struct net *net, struct sock *sk, struc
|
||||
ether_addr_copy(eth_hdr(skb)->h_dest, dev->dev_addr);
|
||||
skb->pkt_type = PACKET_HOST;
|
||||
} else {
|
||||
rt = bridge_parent_rtable(nf_bridge->physindev);
|
||||
rt = bridge_parent_rtable(br_indev);
|
||||
if (!rt) {
|
||||
kfree_skb(skb);
|
||||
return 0;
|
||||
@ -142,7 +148,7 @@ static int br_nf_pre_routing_finish_ipv6(struct net *net, struct sock *sk, struc
|
||||
skb_dst_set_noref(skb, &rt->dst);
|
||||
}
|
||||
|
||||
skb->dev = nf_bridge->physindev;
|
||||
skb->dev = br_indev;
|
||||
nf_bridge_update_protocol(skb);
|
||||
nf_bridge_push_encap_header(skb);
|
||||
br_nf_hook_thresh(NF_BR_PRE_ROUTING, net, sk, skb,
|
||||
|
@ -2899,13 +2899,6 @@ static int do_setlink(const struct sk_buff *skb,
|
||||
call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
|
||||
}
|
||||
|
||||
if (tb[IFLA_MASTER]) {
|
||||
err = do_set_master(dev, nla_get_u32(tb[IFLA_MASTER]), extack);
|
||||
if (err)
|
||||
goto errout;
|
||||
status |= DO_SETLINK_MODIFIED;
|
||||
}
|
||||
|
||||
if (ifm->ifi_flags || ifm->ifi_change) {
|
||||
err = dev_change_flags(dev, rtnl_dev_combine_flags(dev, ifm),
|
||||
extack);
|
||||
@ -2913,6 +2906,13 @@ static int do_setlink(const struct sk_buff *skb,
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (tb[IFLA_MASTER]) {
|
||||
err = do_set_master(dev, nla_get_u32(tb[IFLA_MASTER]), extack);
|
||||
if (err)
|
||||
goto errout;
|
||||
status |= DO_SETLINK_MODIFIED;
|
||||
}
|
||||
|
||||
if (tb[IFLA_CARRIER]) {
|
||||
err = dev_change_carrier(dev, nla_get_u8(tb[IFLA_CARRIER]));
|
||||
if (err)
|
||||
|
@ -2806,13 +2806,14 @@ EXPORT_SYMBOL_GPL(dsa_user_dev_check);
|
||||
static int dsa_user_changeupper(struct net_device *dev,
|
||||
struct netdev_notifier_changeupper_info *info)
|
||||
{
|
||||
struct dsa_port *dp = dsa_user_to_port(dev);
|
||||
struct netlink_ext_ack *extack;
|
||||
int err = NOTIFY_DONE;
|
||||
struct dsa_port *dp;
|
||||
|
||||
if (!dsa_user_dev_check(dev))
|
||||
return err;
|
||||
|
||||
dp = dsa_user_to_port(dev);
|
||||
extack = netdev_notifier_info_to_extack(&info->info);
|
||||
|
||||
if (netif_is_bridge_master(info->upper_dev)) {
|
||||
@ -2865,11 +2866,13 @@ static int dsa_user_changeupper(struct net_device *dev,
|
||||
static int dsa_user_prechangeupper(struct net_device *dev,
|
||||
struct netdev_notifier_changeupper_info *info)
|
||||
{
|
||||
struct dsa_port *dp = dsa_user_to_port(dev);
|
||||
struct dsa_port *dp;
|
||||
|
||||
if (!dsa_user_dev_check(dev))
|
||||
return NOTIFY_DONE;
|
||||
|
||||
dp = dsa_user_to_port(dev);
|
||||
|
||||
if (netif_is_bridge_master(info->upper_dev) && !info->linking)
|
||||
dsa_port_pre_bridge_leave(dp, info->upper_dev);
|
||||
else if (netif_is_lag_master(info->upper_dev) && !info->linking)
|
||||
|
@ -234,17 +234,20 @@ int ethnl_set_features(struct sk_buff *skb, struct genl_info *info)
|
||||
dev = req_info.dev;
|
||||
|
||||
rtnl_lock();
|
||||
ret = ethnl_ops_begin(dev);
|
||||
if (ret < 0)
|
||||
goto out_rtnl;
|
||||
ethnl_features_to_bitmap(old_active, dev->features);
|
||||
ethnl_features_to_bitmap(old_wanted, dev->wanted_features);
|
||||
ret = ethnl_parse_bitset(req_wanted, req_mask, NETDEV_FEATURE_COUNT,
|
||||
tb[ETHTOOL_A_FEATURES_WANTED],
|
||||
netdev_features_strings, info->extack);
|
||||
if (ret < 0)
|
||||
goto out_rtnl;
|
||||
goto out_ops;
|
||||
if (ethnl_bitmap_to_features(req_mask) & ~NETIF_F_ETHTOOL_BITS) {
|
||||
GENL_SET_ERR_MSG(info, "attempt to change non-ethtool features");
|
||||
ret = -EINVAL;
|
||||
goto out_rtnl;
|
||||
goto out_ops;
|
||||
}
|
||||
|
||||
/* set req_wanted bits not in req_mask from old_wanted */
|
||||
@ -281,6 +284,8 @@ int ethnl_set_features(struct sk_buff *skb, struct genl_info *info)
|
||||
if (mod)
|
||||
netdev_features_change(dev);
|
||||
|
||||
out_ops:
|
||||
ethnl_ops_complete(dev);
|
||||
out_rtnl:
|
||||
rtnl_unlock();
|
||||
ethnl_parse_header_dev_put(&req_info);
|
||||
|
@ -167,4 +167,5 @@ static void __exit hsr_exit(void)
|
||||
|
||||
module_init(hsr_init);
|
||||
module_exit(hsr_exit);
|
||||
MODULE_DESCRIPTION("High-availability Seamless Redundancy (HSR) driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -239,7 +239,6 @@ static int nf_reject_fill_skb_dst(struct sk_buff *skb_in)
|
||||
void nf_send_reset(struct net *net, struct sock *sk, struct sk_buff *oldskb,
|
||||
int hook)
|
||||
{
|
||||
struct net_device *br_indev __maybe_unused;
|
||||
struct sk_buff *nskb;
|
||||
struct iphdr *niph;
|
||||
const struct tcphdr *oth;
|
||||
@ -289,9 +288,13 @@ void nf_send_reset(struct net *net, struct sock *sk, struct sk_buff *oldskb,
|
||||
* build the eth header using the original destination's MAC as the
|
||||
* source, and send the RST packet directly.
|
||||
*/
|
||||
br_indev = nf_bridge_get_physindev(oldskb);
|
||||
if (br_indev) {
|
||||
if (nf_bridge_info_exists(oldskb)) {
|
||||
struct ethhdr *oeth = eth_hdr(oldskb);
|
||||
struct net_device *br_indev;
|
||||
|
||||
br_indev = nf_bridge_get_physindev(oldskb, net);
|
||||
if (!br_indev)
|
||||
goto free_nskb;
|
||||
|
||||
nskb->dev = br_indev;
|
||||
niph->tot_len = htons(nskb->len);
|
||||
|
@ -805,7 +805,7 @@ void udp_flush_pending_frames(struct sock *sk)
|
||||
|
||||
if (up->pending) {
|
||||
up->len = 0;
|
||||
up->pending = 0;
|
||||
WRITE_ONCE(up->pending, 0);
|
||||
ip_flush_pending_frames(sk);
|
||||
}
|
||||
}
|
||||
@ -993,7 +993,7 @@ int udp_push_pending_frames(struct sock *sk)
|
||||
|
||||
out:
|
||||
up->len = 0;
|
||||
up->pending = 0;
|
||||
WRITE_ONCE(up->pending, 0);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(udp_push_pending_frames);
|
||||
@ -1070,7 +1070,7 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
|
||||
getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag;
|
||||
|
||||
fl4 = &inet->cork.fl.u.ip4;
|
||||
if (up->pending) {
|
||||
if (READ_ONCE(up->pending)) {
|
||||
/*
|
||||
* There are pending frames.
|
||||
* The socket lock must be held while it's corked.
|
||||
@ -1269,7 +1269,7 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
|
||||
fl4->saddr = saddr;
|
||||
fl4->fl4_dport = dport;
|
||||
fl4->fl4_sport = inet->inet_sport;
|
||||
up->pending = AF_INET;
|
||||
WRITE_ONCE(up->pending, AF_INET);
|
||||
|
||||
do_append_data:
|
||||
up->len += ulen;
|
||||
@ -1281,7 +1281,7 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
|
||||
else if (!corkreq)
|
||||
err = udp_push_pending_frames(sk);
|
||||
else if (unlikely(skb_queue_empty(&sk->sk_write_queue)))
|
||||
up->pending = 0;
|
||||
WRITE_ONCE(up->pending, 0);
|
||||
release_sock(sk);
|
||||
|
||||
out:
|
||||
@ -1319,7 +1319,7 @@ void udp_splice_eof(struct socket *sock)
|
||||
struct sock *sk = sock->sk;
|
||||
struct udp_sock *up = udp_sk(sk);
|
||||
|
||||
if (!up->pending || udp_test_bit(CORK, sk))
|
||||
if (!READ_ONCE(up->pending) || udp_test_bit(CORK, sk))
|
||||
return;
|
||||
|
||||
lock_sock(sk);
|
||||
@ -3137,16 +3137,18 @@ static struct sock *bpf_iter_udp_batch(struct seq_file *seq)
|
||||
struct bpf_udp_iter_state *iter = seq->private;
|
||||
struct udp_iter_state *state = &iter->state;
|
||||
struct net *net = seq_file_net(seq);
|
||||
int resume_bucket, resume_offset;
|
||||
struct udp_table *udptable;
|
||||
unsigned int batch_sks = 0;
|
||||
bool resized = false;
|
||||
struct sock *sk;
|
||||
|
||||
resume_bucket = state->bucket;
|
||||
resume_offset = iter->offset;
|
||||
|
||||
/* The current batch is done, so advance the bucket. */
|
||||
if (iter->st_bucket_done) {
|
||||
if (iter->st_bucket_done)
|
||||
state->bucket++;
|
||||
iter->offset = 0;
|
||||
}
|
||||
|
||||
udptable = udp_get_table_seq(seq, net);
|
||||
|
||||
@ -3166,19 +3168,19 @@ static struct sock *bpf_iter_udp_batch(struct seq_file *seq)
|
||||
for (; state->bucket <= udptable->mask; state->bucket++) {
|
||||
struct udp_hslot *hslot2 = &udptable->hash2[state->bucket];
|
||||
|
||||
if (hlist_empty(&hslot2->head)) {
|
||||
iter->offset = 0;
|
||||
if (hlist_empty(&hslot2->head))
|
||||
continue;
|
||||
}
|
||||
|
||||
iter->offset = 0;
|
||||
spin_lock_bh(&hslot2->lock);
|
||||
udp_portaddr_for_each_entry(sk, &hslot2->head) {
|
||||
if (seq_sk_match(seq, sk)) {
|
||||
/* Resume from the last iterated socket at the
|
||||
* offset in the bucket before iterator was stopped.
|
||||
*/
|
||||
if (iter->offset) {
|
||||
--iter->offset;
|
||||
if (state->bucket == resume_bucket &&
|
||||
iter->offset < resume_offset) {
|
||||
++iter->offset;
|
||||
continue;
|
||||
}
|
||||
if (iter->end_sk < iter->max_sk) {
|
||||
@ -3192,9 +3194,6 @@ static struct sock *bpf_iter_udp_batch(struct seq_file *seq)
|
||||
|
||||
if (iter->end_sk)
|
||||
break;
|
||||
|
||||
/* Reset the current bucket's offset before moving to the next bucket. */
|
||||
iter->offset = 0;
|
||||
}
|
||||
|
||||
/* All done: no batch made. */
|
||||
@ -3213,7 +3212,6 @@ static struct sock *bpf_iter_udp_batch(struct seq_file *seq)
|
||||
/* After allocating a larger batch, retry one more time to grab
|
||||
* the whole bucket.
|
||||
*/
|
||||
state->bucket--;
|
||||
goto again;
|
||||
}
|
||||
done:
|
||||
|
@ -2722,8 +2722,12 @@ void ipv6_mc_down(struct inet6_dev *idev)
|
||||
synchronize_net();
|
||||
mld_query_stop_work(idev);
|
||||
mld_report_stop_work(idev);
|
||||
|
||||
mutex_lock(&idev->mc_lock);
|
||||
mld_ifc_stop_work(idev);
|
||||
mld_gq_stop_work(idev);
|
||||
mutex_unlock(&idev->mc_lock);
|
||||
|
||||
mld_dad_stop_work(idev);
|
||||
}
|
||||
|
||||
|
@ -278,7 +278,6 @@ static int nf_reject6_fill_skb_dst(struct sk_buff *skb_in)
|
||||
void nf_send_reset6(struct net *net, struct sock *sk, struct sk_buff *oldskb,
|
||||
int hook)
|
||||
{
|
||||
struct net_device *br_indev __maybe_unused;
|
||||
struct sk_buff *nskb;
|
||||
struct tcphdr _otcph;
|
||||
const struct tcphdr *otcph;
|
||||
@ -354,9 +353,15 @@ void nf_send_reset6(struct net *net, struct sock *sk, struct sk_buff *oldskb,
|
||||
* build the eth header using the original destination's MAC as the
|
||||
* source, and send the RST packet directly.
|
||||
*/
|
||||
br_indev = nf_bridge_get_physindev(oldskb);
|
||||
if (br_indev) {
|
||||
if (nf_bridge_info_exists(oldskb)) {
|
||||
struct ethhdr *oeth = eth_hdr(oldskb);
|
||||
struct net_device *br_indev;
|
||||
|
||||
br_indev = nf_bridge_get_physindev(oldskb, net);
|
||||
if (!br_indev) {
|
||||
kfree_skb(nskb);
|
||||
return;
|
||||
}
|
||||
|
||||
nskb->dev = br_indev;
|
||||
nskb->protocol = htons(ETH_P_IPV6);
|
||||
|
@ -1135,7 +1135,7 @@ static void udp_v6_flush_pending_frames(struct sock *sk)
|
||||
udp_flush_pending_frames(sk);
|
||||
else if (up->pending) {
|
||||
up->len = 0;
|
||||
up->pending = 0;
|
||||
WRITE_ONCE(up->pending, 0);
|
||||
ip6_flush_pending_frames(sk);
|
||||
}
|
||||
}
|
||||
@ -1313,7 +1313,7 @@ static int udp_v6_push_pending_frames(struct sock *sk)
|
||||
&inet_sk(sk)->cork.base);
|
||||
out:
|
||||
up->len = 0;
|
||||
up->pending = 0;
|
||||
WRITE_ONCE(up->pending, 0);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -1370,7 +1370,7 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
} else if (!up->pending) {
|
||||
} else if (!READ_ONCE(up->pending)) {
|
||||
if (sk->sk_state != TCP_ESTABLISHED)
|
||||
return -EDESTADDRREQ;
|
||||
daddr = &sk->sk_v6_daddr;
|
||||
@ -1401,8 +1401,8 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
|
||||
return -EMSGSIZE;
|
||||
|
||||
getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag;
|
||||
if (up->pending) {
|
||||
if (up->pending == AF_INET)
|
||||
if (READ_ONCE(up->pending)) {
|
||||
if (READ_ONCE(up->pending) == AF_INET)
|
||||
return udp_sendmsg(sk, msg, len);
|
||||
/*
|
||||
* There are pending frames.
|
||||
@ -1593,7 +1593,7 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
|
||||
goto out;
|
||||
}
|
||||
|
||||
up->pending = AF_INET6;
|
||||
WRITE_ONCE(up->pending, AF_INET6);
|
||||
|
||||
do_append_data:
|
||||
if (ipc6.dontfrag < 0)
|
||||
@ -1607,7 +1607,7 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
|
||||
else if (!corkreq)
|
||||
err = udp_v6_push_pending_frames(sk);
|
||||
else if (unlikely(skb_queue_empty(&sk->sk_write_queue)))
|
||||
up->pending = 0;
|
||||
WRITE_ONCE(up->pending, 0);
|
||||
|
||||
if (err > 0)
|
||||
err = inet6_test_bit(RECVERR6, sk) ? net_xmit_errno(err) : 0;
|
||||
@ -1648,7 +1648,7 @@ static void udpv6_splice_eof(struct socket *sock)
|
||||
struct sock *sk = sock->sk;
|
||||
struct udp_sock *up = udp_sk(sk);
|
||||
|
||||
if (!up->pending || udp_test_bit(CORK, sk))
|
||||
if (!READ_ONCE(up->pending) || udp_test_bit(CORK, sk))
|
||||
return;
|
||||
|
||||
lock_sock(sk);
|
||||
|
@ -123,8 +123,8 @@ static void mptcp_parse_option(const struct sk_buff *skb,
|
||||
break;
|
||||
|
||||
case MPTCPOPT_MP_JOIN:
|
||||
mp_opt->suboptions |= OPTIONS_MPTCP_MPJ;
|
||||
if (opsize == TCPOLEN_MPTCP_MPJ_SYN) {
|
||||
mp_opt->suboptions |= OPTION_MPTCP_MPJ_SYN;
|
||||
mp_opt->backup = *ptr++ & MPTCPOPT_BACKUP;
|
||||
mp_opt->join_id = *ptr++;
|
||||
mp_opt->token = get_unaligned_be32(ptr);
|
||||
@ -135,6 +135,7 @@ static void mptcp_parse_option(const struct sk_buff *skb,
|
||||
mp_opt->backup, mp_opt->join_id,
|
||||
mp_opt->token, mp_opt->nonce);
|
||||
} else if (opsize == TCPOLEN_MPTCP_MPJ_SYNACK) {
|
||||
mp_opt->suboptions |= OPTION_MPTCP_MPJ_SYNACK;
|
||||
mp_opt->backup = *ptr++ & MPTCPOPT_BACKUP;
|
||||
mp_opt->join_id = *ptr++;
|
||||
mp_opt->thmac = get_unaligned_be64(ptr);
|
||||
@ -145,11 +146,10 @@ static void mptcp_parse_option(const struct sk_buff *skb,
|
||||
mp_opt->backup, mp_opt->join_id,
|
||||
mp_opt->thmac, mp_opt->nonce);
|
||||
} else if (opsize == TCPOLEN_MPTCP_MPJ_ACK) {
|
||||
mp_opt->suboptions |= OPTION_MPTCP_MPJ_ACK;
|
||||
ptr += 2;
|
||||
memcpy(mp_opt->hmac, ptr, MPTCPOPT_HMAC_LEN);
|
||||
pr_debug("MP_JOIN hmac");
|
||||
} else {
|
||||
mp_opt->suboptions &= ~OPTIONS_MPTCP_MPJ;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -157,8 +157,8 @@ static int subflow_check_req(struct request_sock *req,
|
||||
|
||||
mptcp_get_options(skb, &mp_opt);
|
||||
|
||||
opt_mp_capable = !!(mp_opt.suboptions & OPTIONS_MPTCP_MPC);
|
||||
opt_mp_join = !!(mp_opt.suboptions & OPTIONS_MPTCP_MPJ);
|
||||
opt_mp_capable = !!(mp_opt.suboptions & OPTION_MPTCP_MPC_SYN);
|
||||
opt_mp_join = !!(mp_opt.suboptions & OPTION_MPTCP_MPJ_SYN);
|
||||
if (opt_mp_capable) {
|
||||
SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_MPCAPABLEPASSIVE);
|
||||
|
||||
@ -254,8 +254,8 @@ int mptcp_subflow_init_cookie_req(struct request_sock *req,
|
||||
subflow_init_req(req, sk_listener);
|
||||
mptcp_get_options(skb, &mp_opt);
|
||||
|
||||
opt_mp_capable = !!(mp_opt.suboptions & OPTIONS_MPTCP_MPC);
|
||||
opt_mp_join = !!(mp_opt.suboptions & OPTIONS_MPTCP_MPJ);
|
||||
opt_mp_capable = !!(mp_opt.suboptions & OPTION_MPTCP_MPC_ACK);
|
||||
opt_mp_join = !!(mp_opt.suboptions & OPTION_MPTCP_MPJ_ACK);
|
||||
if (opt_mp_capable && opt_mp_join)
|
||||
return -EINVAL;
|
||||
|
||||
@ -486,7 +486,7 @@ static void subflow_finish_connect(struct sock *sk, const struct sk_buff *skb)
|
||||
|
||||
mptcp_get_options(skb, &mp_opt);
|
||||
if (subflow->request_mptcp) {
|
||||
if (!(mp_opt.suboptions & OPTIONS_MPTCP_MPC)) {
|
||||
if (!(mp_opt.suboptions & OPTION_MPTCP_MPC_SYNACK)) {
|
||||
MPTCP_INC_STATS(sock_net(sk),
|
||||
MPTCP_MIB_MPCAPABLEACTIVEFALLBACK);
|
||||
mptcp_do_fallback(sk);
|
||||
@ -506,7 +506,7 @@ static void subflow_finish_connect(struct sock *sk, const struct sk_buff *skb)
|
||||
} else if (subflow->request_join) {
|
||||
u8 hmac[SHA256_DIGEST_SIZE];
|
||||
|
||||
if (!(mp_opt.suboptions & OPTIONS_MPTCP_MPJ)) {
|
||||
if (!(mp_opt.suboptions & OPTION_MPTCP_MPJ_SYNACK)) {
|
||||
subflow->reset_reason = MPTCP_RST_EMPTCP;
|
||||
goto do_reset;
|
||||
}
|
||||
@ -783,12 +783,13 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk,
|
||||
* options.
|
||||
*/
|
||||
mptcp_get_options(skb, &mp_opt);
|
||||
if (!(mp_opt.suboptions & OPTIONS_MPTCP_MPC))
|
||||
if (!(mp_opt.suboptions &
|
||||
(OPTION_MPTCP_MPC_SYN | OPTION_MPTCP_MPC_ACK)))
|
||||
fallback = true;
|
||||
|
||||
} else if (subflow_req->mp_join) {
|
||||
mptcp_get_options(skb, &mp_opt);
|
||||
if (!(mp_opt.suboptions & OPTIONS_MPTCP_MPJ) ||
|
||||
if (!(mp_opt.suboptions & OPTION_MPTCP_MPJ_ACK) ||
|
||||
!subflow_hmac_valid(req, &mp_opt) ||
|
||||
!mptcp_can_accept_new_subflow(subflow_req->msk)) {
|
||||
SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_JOINACKMAC);
|
||||
|
@ -138,9 +138,9 @@ hash_netiface4_data_next(struct hash_netiface4_elem *next,
|
||||
#include "ip_set_hash_gen.h"
|
||||
|
||||
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
|
||||
static const char *get_physindev_name(const struct sk_buff *skb)
|
||||
static const char *get_physindev_name(const struct sk_buff *skb, struct net *net)
|
||||
{
|
||||
struct net_device *dev = nf_bridge_get_physindev(skb);
|
||||
struct net_device *dev = nf_bridge_get_physindev(skb, net);
|
||||
|
||||
return dev ? dev->name : NULL;
|
||||
}
|
||||
@ -177,7 +177,7 @@ hash_netiface4_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
|
||||
if (opt->cmdflags & IPSET_FLAG_PHYSDEV) {
|
||||
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
|
||||
const char *eiface = SRCDIR ? get_physindev_name(skb) :
|
||||
const char *eiface = SRCDIR ? get_physindev_name(skb, xt_net(par)) :
|
||||
get_physoutdev_name(skb);
|
||||
|
||||
if (!eiface)
|
||||
@ -395,7 +395,7 @@ hash_netiface6_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
|
||||
if (opt->cmdflags & IPSET_FLAG_PHYSDEV) {
|
||||
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
|
||||
const char *eiface = SRCDIR ? get_physindev_name(skb) :
|
||||
const char *eiface = SRCDIR ? get_physindev_name(skb, xt_net(par)) :
|
||||
get_physoutdev_name(skb);
|
||||
|
||||
if (!eiface)
|
||||
|
@ -271,7 +271,7 @@ static inline bool decrement_ttl(struct netns_ipvs *ipvs,
|
||||
skb->dev = dst->dev;
|
||||
icmpv6_send(skb, ICMPV6_TIME_EXCEED,
|
||||
ICMPV6_EXC_HOPLIMIT, 0);
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
|
||||
IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -286,7 +286,7 @@ static inline bool decrement_ttl(struct netns_ipvs *ipvs,
|
||||
{
|
||||
if (ip_hdr(skb)->ttl <= 1) {
|
||||
/* Tell the sender its packet died... */
|
||||
__IP_INC_STATS(net, IPSTATS_MIB_INHDRERRORS);
|
||||
IP_INC_STATS(net, IPSTATS_MIB_INHDRERRORS);
|
||||
icmp_send(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, 0);
|
||||
return false;
|
||||
}
|
||||
|
@ -111,7 +111,8 @@ nf_log_dump_packet_common(struct nf_log_buf *m, u8 pf,
|
||||
unsigned int hooknum, const struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
const struct nf_loginfo *loginfo, const char *prefix)
|
||||
const struct nf_loginfo *loginfo, const char *prefix,
|
||||
struct net *net)
|
||||
{
|
||||
const struct net_device *physoutdev __maybe_unused;
|
||||
const struct net_device *physindev __maybe_unused;
|
||||
@ -121,7 +122,7 @@ nf_log_dump_packet_common(struct nf_log_buf *m, u8 pf,
|
||||
in ? in->name : "",
|
||||
out ? out->name : "");
|
||||
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
|
||||
physindev = nf_bridge_get_physindev(skb);
|
||||
physindev = nf_bridge_get_physindev(skb, net);
|
||||
if (physindev && in != physindev)
|
||||
nf_log_buf_add(m, "PHYSIN=%s ", physindev->name);
|
||||
physoutdev = nf_bridge_get_physoutdev(skb);
|
||||
@ -148,7 +149,7 @@ static void nf_log_arp_packet(struct net *net, u_int8_t pf,
|
||||
loginfo = &default_loginfo;
|
||||
|
||||
nf_log_dump_packet_common(m, pf, hooknum, skb, in, out, loginfo,
|
||||
prefix);
|
||||
prefix, net);
|
||||
dump_arp_packet(m, loginfo, skb, skb_network_offset(skb));
|
||||
|
||||
nf_log_buf_close(m);
|
||||
@ -845,7 +846,7 @@ static void nf_log_ip_packet(struct net *net, u_int8_t pf,
|
||||
loginfo = &default_loginfo;
|
||||
|
||||
nf_log_dump_packet_common(m, pf, hooknum, skb, in,
|
||||
out, loginfo, prefix);
|
||||
out, loginfo, prefix, net);
|
||||
|
||||
if (in)
|
||||
dump_mac_header(m, loginfo, skb);
|
||||
@ -880,7 +881,7 @@ static void nf_log_ip6_packet(struct net *net, u_int8_t pf,
|
||||
loginfo = &default_loginfo;
|
||||
|
||||
nf_log_dump_packet_common(m, pf, hooknum, skb, in, out,
|
||||
loginfo, prefix);
|
||||
loginfo, prefix, net);
|
||||
|
||||
if (in)
|
||||
dump_mac_header(m, loginfo, skb);
|
||||
@ -916,7 +917,7 @@ static void nf_log_unknown_packet(struct net *net, u_int8_t pf,
|
||||
loginfo = &default_loginfo;
|
||||
|
||||
nf_log_dump_packet_common(m, pf, hooknum, skb, in, out, loginfo,
|
||||
prefix);
|
||||
prefix, net);
|
||||
|
||||
dump_mac_header(m, loginfo, skb);
|
||||
|
||||
|
@ -82,11 +82,9 @@ static void __nf_queue_entry_init_physdevs(struct nf_queue_entry *entry)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
|
||||
const struct sk_buff *skb = entry->skb;
|
||||
struct nf_bridge_info *nf_bridge;
|
||||
|
||||
nf_bridge = nf_bridge_info_get(skb);
|
||||
if (nf_bridge) {
|
||||
entry->physin = nf_bridge_get_physindev(skb);
|
||||
if (nf_bridge_info_exists(skb)) {
|
||||
entry->physin = nf_bridge_get_physindev(skb, entry->state.net);
|
||||
entry->physout = nf_bridge_get_physoutdev(skb);
|
||||
} else {
|
||||
entry->physin = NULL;
|
||||
|
@ -2977,6 +2977,9 @@ static int nf_tables_delchain(struct sk_buff *skb, const struct nfnl_info *info,
|
||||
*/
|
||||
int nft_register_expr(struct nft_expr_type *type)
|
||||
{
|
||||
if (WARN_ON_ONCE(type->maxattr > NFT_EXPR_MAXATTR))
|
||||
return -ENOMEM;
|
||||
|
||||
nfnl_lock(NFNL_SUBSYS_NFTABLES);
|
||||
if (type->family == NFPROTO_UNSPEC)
|
||||
list_add_tail_rcu(&type->list, &nf_tables_expressions);
|
||||
@ -3271,14 +3274,13 @@ int nft_expr_clone(struct nft_expr *dst, struct nft_expr *src)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (src->ops->clone) {
|
||||
if (WARN_ON_ONCE(!src->ops->clone))
|
||||
return -EINVAL;
|
||||
|
||||
dst->ops = src->ops;
|
||||
err = src->ops->clone(dst, src);
|
||||
if (err < 0)
|
||||
return err;
|
||||
} else {
|
||||
memcpy(dst, src, src->ops->size);
|
||||
}
|
||||
|
||||
__module_get(src->ops->type->owner);
|
||||
|
||||
@ -4811,8 +4813,8 @@ static int nft_set_desc_concat_parse(const struct nlattr *attr,
|
||||
static int nft_set_desc_concat(struct nft_set_desc *desc,
|
||||
const struct nlattr *nla)
|
||||
{
|
||||
u32 num_regs = 0, key_num_regs = 0;
|
||||
struct nlattr *attr;
|
||||
u32 num_regs = 0;
|
||||
int rem, err, i;
|
||||
|
||||
nla_for_each_nested(attr, nla, rem) {
|
||||
@ -4827,6 +4829,10 @@ static int nft_set_desc_concat(struct nft_set_desc *desc,
|
||||
for (i = 0; i < desc->field_count; i++)
|
||||
num_regs += DIV_ROUND_UP(desc->field_len[i], sizeof(u32));
|
||||
|
||||
key_num_regs = DIV_ROUND_UP(desc->klen, sizeof(u32));
|
||||
if (key_num_regs != num_regs)
|
||||
return -EINVAL;
|
||||
|
||||
if (num_regs > NFT_REG32_COUNT)
|
||||
return -E2BIG;
|
||||
|
||||
@ -5048,19 +5054,31 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,
|
||||
}
|
||||
|
||||
desc.policy = NFT_SET_POL_PERFORMANCE;
|
||||
if (nla[NFTA_SET_POLICY] != NULL)
|
||||
if (nla[NFTA_SET_POLICY] != NULL) {
|
||||
desc.policy = ntohl(nla_get_be32(nla[NFTA_SET_POLICY]));
|
||||
switch (desc.policy) {
|
||||
case NFT_SET_POL_PERFORMANCE:
|
||||
case NFT_SET_POL_MEMORY:
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
if (nla[NFTA_SET_DESC] != NULL) {
|
||||
err = nf_tables_set_desc_parse(&desc, nla[NFTA_SET_DESC]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (desc.field_count > 1 && !(flags & NFT_SET_CONCAT))
|
||||
if (desc.field_count > 1) {
|
||||
if (!(flags & NFT_SET_CONCAT))
|
||||
return -EINVAL;
|
||||
} else if (flags & NFT_SET_CONCAT) {
|
||||
return -EINVAL;
|
||||
}
|
||||
} else if (flags & NFT_SET_CONCAT) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (nla[NFTA_SET_EXPR] || nla[NFTA_SET_EXPRESSIONS])
|
||||
desc.expr = true;
|
||||
@ -5704,7 +5722,7 @@ static int nf_tables_dump_setelem(const struct nft_ctx *ctx,
|
||||
const struct nft_set_ext *ext = nft_set_elem_ext(set, elem_priv);
|
||||
struct nft_set_dump_args *args;
|
||||
|
||||
if (nft_set_elem_expired(ext))
|
||||
if (nft_set_elem_expired(ext) || nft_set_elem_is_dead(ext))
|
||||
return 0;
|
||||
|
||||
args = container_of(iter, struct nft_set_dump_args, iter);
|
||||
@ -6568,7 +6586,7 @@ static int nft_setelem_catchall_deactivate(const struct net *net,
|
||||
|
||||
list_for_each_entry(catchall, &set->catchall_list, list) {
|
||||
ext = nft_set_elem_ext(set, catchall->elem);
|
||||
if (!nft_is_active(net, ext))
|
||||
if (!nft_is_active_next(net, ext))
|
||||
continue;
|
||||
|
||||
kfree(elem->priv);
|
||||
|
@ -508,7 +508,7 @@ __build_packet_message(struct nfnl_log_net *log,
|
||||
htonl(br_port_get_rcu(indev)->br->dev->ifindex)))
|
||||
goto nla_put_failure;
|
||||
} else {
|
||||
struct net_device *physindev;
|
||||
int physinif;
|
||||
|
||||
/* Case 2: indev is bridge group, we need to look for
|
||||
* physical device (when called from ipv4) */
|
||||
@ -516,10 +516,10 @@ __build_packet_message(struct nfnl_log_net *log,
|
||||
htonl(indev->ifindex)))
|
||||
goto nla_put_failure;
|
||||
|
||||
physindev = nf_bridge_get_physindev(skb);
|
||||
if (physindev &&
|
||||
physinif = nf_bridge_get_physinif(skb);
|
||||
if (physinif &&
|
||||
nla_put_be32(inst->skb, NFULA_IFINDEX_PHYSINDEV,
|
||||
htonl(physindev->ifindex)))
|
||||
htonl(physinif)))
|
||||
goto nla_put_failure;
|
||||
}
|
||||
#endif
|
||||
|
@ -58,6 +58,7 @@ static inline bool nft_limit_eval(struct nft_limit_priv *priv, u64 cost)
|
||||
static int nft_limit_init(struct nft_limit_priv *priv,
|
||||
const struct nlattr * const tb[], bool pkts)
|
||||
{
|
||||
bool invert = false;
|
||||
u64 unit, tokens;
|
||||
|
||||
if (tb[NFTA_LIMIT_RATE] == NULL ||
|
||||
@ -90,19 +91,23 @@ static int nft_limit_init(struct nft_limit_priv *priv,
|
||||
priv->rate);
|
||||
}
|
||||
|
||||
if (tb[NFTA_LIMIT_FLAGS]) {
|
||||
u32 flags = ntohl(nla_get_be32(tb[NFTA_LIMIT_FLAGS]));
|
||||
|
||||
if (flags & ~NFT_LIMIT_F_INV)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (flags & NFT_LIMIT_F_INV)
|
||||
invert = true;
|
||||
}
|
||||
|
||||
priv->limit = kmalloc(sizeof(*priv->limit), GFP_KERNEL_ACCOUNT);
|
||||
if (!priv->limit)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->limit->tokens = tokens;
|
||||
priv->tokens_max = priv->limit->tokens;
|
||||
|
||||
if (tb[NFTA_LIMIT_FLAGS]) {
|
||||
u32 flags = ntohl(nla_get_be32(tb[NFTA_LIMIT_FLAGS]));
|
||||
|
||||
if (flags & NFT_LIMIT_F_INV)
|
||||
priv->invert = true;
|
||||
}
|
||||
priv->invert = invert;
|
||||
priv->limit->last = ktime_get_ns();
|
||||
spin_lock_init(&priv->limit->lock);
|
||||
|
||||
|
@ -59,7 +59,7 @@ physdev_mt(const struct sk_buff *skb, struct xt_action_param *par)
|
||||
(!!outdev ^ !(info->invert & XT_PHYSDEV_OP_BRIDGED)))
|
||||
return false;
|
||||
|
||||
physdev = nf_bridge_get_physindev(skb);
|
||||
physdev = nf_bridge_get_physindev(skb, xt_net(par));
|
||||
indev = physdev ? physdev->name : NULL;
|
||||
|
||||
if ((info->bitmask & XT_PHYSDEV_OP_ISIN &&
|
||||
|
@ -858,4 +858,5 @@ void nfc_digital_unregister_device(struct nfc_digital_dev *ddev)
|
||||
}
|
||||
EXPORT_SYMBOL(nfc_digital_unregister_device);
|
||||
|
||||
MODULE_DESCRIPTION("NFC Digital protocol stack");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -1577,4 +1577,5 @@ static void nci_cmd_work(struct work_struct *work)
|
||||
}
|
||||
}
|
||||
|
||||
MODULE_DESCRIPTION("NFC Controller Interface");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -319,4 +319,5 @@ struct sk_buff *nci_spi_read(struct nci_spi *nspi)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nci_spi_read);
|
||||
|
||||
MODULE_DESCRIPTION("NFC Controller Interface (NCI) SPI link layer");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -1079,6 +1079,7 @@ void rxrpc_send_version_request(struct rxrpc_local *local,
|
||||
/*
|
||||
* local_object.c
|
||||
*/
|
||||
void rxrpc_local_dont_fragment(const struct rxrpc_local *local, bool set);
|
||||
struct rxrpc_local *rxrpc_lookup_local(struct net *, const struct sockaddr_rxrpc *);
|
||||
struct rxrpc_local *rxrpc_get_local(struct rxrpc_local *, enum rxrpc_local_trace);
|
||||
struct rxrpc_local *rxrpc_get_local_maybe(struct rxrpc_local *, enum rxrpc_local_trace);
|
||||
|
@ -36,6 +36,17 @@ static void rxrpc_encap_err_rcv(struct sock *sk, struct sk_buff *skb, int err,
|
||||
return ipv6_icmp_error(sk, skb, err, port, info, payload);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set or clear the Don't Fragment flag on a socket.
|
||||
*/
|
||||
void rxrpc_local_dont_fragment(const struct rxrpc_local *local, bool set)
|
||||
{
|
||||
if (set)
|
||||
ip_sock_set_mtu_discover(local->socket->sk, IP_PMTUDISC_DO);
|
||||
else
|
||||
ip_sock_set_mtu_discover(local->socket->sk, IP_PMTUDISC_DONT);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare a local to an address. Return -ve, 0 or +ve to indicate less than,
|
||||
* same or greater than.
|
||||
@ -203,7 +214,7 @@ static int rxrpc_open_socket(struct rxrpc_local *local, struct net *net)
|
||||
ip_sock_set_recverr(usk);
|
||||
|
||||
/* we want to set the don't fragment bit */
|
||||
ip_sock_set_mtu_discover(usk, IP_PMTUDISC_DO);
|
||||
rxrpc_local_dont_fragment(local, true);
|
||||
|
||||
/* We want receive timestamps. */
|
||||
sock_enable_timestamps(usk);
|
||||
|
@ -494,14 +494,12 @@ int rxrpc_send_data_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb)
|
||||
switch (conn->local->srx.transport.family) {
|
||||
case AF_INET6:
|
||||
case AF_INET:
|
||||
ip_sock_set_mtu_discover(conn->local->socket->sk,
|
||||
IP_PMTUDISC_DONT);
|
||||
rxrpc_local_dont_fragment(conn->local, false);
|
||||
rxrpc_inc_stat(call->rxnet, stat_tx_data_send_frag);
|
||||
ret = do_udp_sendmsg(conn->local->socket, &msg, len);
|
||||
conn->peer->last_tx_at = ktime_get_seconds();
|
||||
|
||||
ip_sock_set_mtu_discover(conn->local->socket->sk,
|
||||
IP_PMTUDISC_DO);
|
||||
rxrpc_local_dont_fragment(conn->local, true);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -724,7 +724,9 @@ static int rxkad_send_response(struct rxrpc_connection *conn,
|
||||
serial = atomic_inc_return(&conn->serial);
|
||||
whdr.serial = htonl(serial);
|
||||
|
||||
rxrpc_local_dont_fragment(conn->local, false);
|
||||
ret = kernel_sendmsg(conn->local->socket, &msg, iov, 3, len);
|
||||
rxrpc_local_dont_fragment(conn->local, true);
|
||||
if (ret < 0) {
|
||||
trace_rxrpc_tx_fail(conn->debug_id, serial, ret,
|
||||
rxrpc_tx_point_rxkad_response);
|
||||
|
@ -1424,6 +1424,14 @@ static void tcf_block_owner_del(struct tcf_block *block,
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
static bool tcf_block_tracks_dev(struct tcf_block *block,
|
||||
struct tcf_block_ext_info *ei)
|
||||
{
|
||||
return tcf_block_shared(block) &&
|
||||
(ei->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS ||
|
||||
ei->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS);
|
||||
}
|
||||
|
||||
int tcf_block_get_ext(struct tcf_block **p_block, struct Qdisc *q,
|
||||
struct tcf_block_ext_info *ei,
|
||||
struct netlink_ext_ack *extack)
|
||||
@ -1462,7 +1470,7 @@ int tcf_block_get_ext(struct tcf_block **p_block, struct Qdisc *q,
|
||||
if (err)
|
||||
goto err_block_offload_bind;
|
||||
|
||||
if (tcf_block_shared(block)) {
|
||||
if (tcf_block_tracks_dev(block, ei)) {
|
||||
err = xa_insert(&block->ports, dev->ifindex, dev, GFP_KERNEL);
|
||||
if (err) {
|
||||
NL_SET_ERR_MSG(extack, "block dev insert failed");
|
||||
@ -1516,7 +1524,7 @@ void tcf_block_put_ext(struct tcf_block *block, struct Qdisc *q,
|
||||
|
||||
if (!block)
|
||||
return;
|
||||
if (tcf_block_shared(block))
|
||||
if (tcf_block_tracks_dev(block, ei))
|
||||
xa_erase(&block->ports, dev->ifindex);
|
||||
tcf_chain0_head_change_cb_del(block, ei);
|
||||
tcf_block_owner_del(block, q, ei->binder_type);
|
||||
|
@ -2280,6 +2280,7 @@ static void __exit exit_rpcsec_gss(void)
|
||||
}
|
||||
|
||||
MODULE_ALIAS("rpc-auth-6");
|
||||
MODULE_DESCRIPTION("Sun RPC Kerberos RPCSEC_GSS client authentication");
|
||||
MODULE_LICENSE("GPL");
|
||||
module_param_named(expired_cred_retry_delay,
|
||||
gss_expired_cred_retry_delay,
|
||||
|
@ -650,6 +650,7 @@ static void __exit cleanup_kerberos_module(void)
|
||||
gss_mech_unregister(&gss_kerberos_mech);
|
||||
}
|
||||
|
||||
MODULE_DESCRIPTION("Sun RPC Kerberos 5 module");
|
||||
MODULE_LICENSE("GPL");
|
||||
module_init(init_kerberos_module);
|
||||
module_exit(cleanup_kerberos_module);
|
||||
|
@ -148,6 +148,7 @@ cleanup_sunrpc(void)
|
||||
#endif
|
||||
rcu_barrier(); /* Wait for completion of call_rcu()'s */
|
||||
}
|
||||
MODULE_DESCRIPTION("Sun RPC core");
|
||||
MODULE_LICENSE("GPL");
|
||||
fs_initcall(init_sunrpc); /* Ensure we're initialised before nfs */
|
||||
module_exit(cleanup_sunrpc);
|
||||
|
@ -1052,7 +1052,11 @@ static int tls_sw_sendmsg_locked(struct sock *sk, struct msghdr *msg,
|
||||
if (ret < 0)
|
||||
goto send_end;
|
||||
tls_ctx->pending_open_record_frags = true;
|
||||
if (full_record || eor || sk_msg_full(msg_pl))
|
||||
|
||||
if (sk_msg_full(msg_pl))
|
||||
full_record = true;
|
||||
|
||||
if (full_record || eor)
|
||||
goto copied;
|
||||
continue;
|
||||
}
|
||||
|
@ -6695,6 +6695,67 @@ static struct {
|
||||
/* all other program types don't have "named" context structs */
|
||||
};
|
||||
|
||||
static bool need_func_arg_type_fixup(const struct btf *btf, const struct bpf_program *prog,
|
||||
const char *subprog_name, int arg_idx,
|
||||
int arg_type_id, const char *ctx_name)
|
||||
{
|
||||
const struct btf_type *t;
|
||||
const char *tname;
|
||||
|
||||
/* check if existing parameter already matches verifier expectations */
|
||||
t = skip_mods_and_typedefs(btf, arg_type_id, NULL);
|
||||
if (!btf_is_ptr(t))
|
||||
goto out_warn;
|
||||
|
||||
/* typedef bpf_user_pt_regs_t is a special PITA case, valid for kprobe
|
||||
* and perf_event programs, so check this case early on and forget
|
||||
* about it for subsequent checks
|
||||
*/
|
||||
while (btf_is_mod(t))
|
||||
t = btf__type_by_id(btf, t->type);
|
||||
if (btf_is_typedef(t) &&
|
||||
(prog->type == BPF_PROG_TYPE_KPROBE || prog->type == BPF_PROG_TYPE_PERF_EVENT)) {
|
||||
tname = btf__str_by_offset(btf, t->name_off) ?: "<anon>";
|
||||
if (strcmp(tname, "bpf_user_pt_regs_t") == 0)
|
||||
return false; /* canonical type for kprobe/perf_event */
|
||||
}
|
||||
|
||||
/* now we can ignore typedefs moving forward */
|
||||
t = skip_mods_and_typedefs(btf, t->type, NULL);
|
||||
|
||||
/* if it's `void *`, definitely fix up BTF info */
|
||||
if (btf_is_void(t))
|
||||
return true;
|
||||
|
||||
/* if it's already proper canonical type, no need to fix up */
|
||||
tname = btf__str_by_offset(btf, t->name_off) ?: "<anon>";
|
||||
if (btf_is_struct(t) && strcmp(tname, ctx_name) == 0)
|
||||
return false;
|
||||
|
||||
/* special cases */
|
||||
switch (prog->type) {
|
||||
case BPF_PROG_TYPE_KPROBE:
|
||||
case BPF_PROG_TYPE_PERF_EVENT:
|
||||
/* `struct pt_regs *` is expected, but we need to fix up */
|
||||
if (btf_is_struct(t) && strcmp(tname, "pt_regs") == 0)
|
||||
return true;
|
||||
break;
|
||||
case BPF_PROG_TYPE_RAW_TRACEPOINT:
|
||||
case BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE:
|
||||
/* allow u64* as ctx */
|
||||
if (btf_is_int(t) && t->size == 8)
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
out_warn:
|
||||
pr_warn("prog '%s': subprog '%s' arg#%d is expected to be of `struct %s *` type\n",
|
||||
prog->name, subprog_name, arg_idx, ctx_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
static int clone_func_btf_info(struct btf *btf, int orig_fn_id, struct bpf_program *prog)
|
||||
{
|
||||
int fn_id, fn_proto_id, ret_type_id, orig_proto_id;
|
||||
@ -6757,6 +6818,69 @@ static int clone_func_btf_info(struct btf *btf, int orig_fn_id, struct bpf_progr
|
||||
return fn_id;
|
||||
}
|
||||
|
||||
static int probe_kern_arg_ctx_tag(void)
|
||||
{
|
||||
/* To minimize merge conflicts with BPF token series that refactors
|
||||
* feature detection code a lot, we don't integrate
|
||||
* probe_kern_arg_ctx_tag() into kernel_supports() feature-detection
|
||||
* framework yet, doing our own caching internally.
|
||||
* This will be cleaned up a bit later when bpf/bpf-next trees settle.
|
||||
*/
|
||||
static int cached_result = -1;
|
||||
static const char strs[] = "\0a\0b\0arg:ctx\0";
|
||||
const __u32 types[] = {
|
||||
/* [1] INT */
|
||||
BTF_TYPE_INT_ENC(1 /* "a" */, BTF_INT_SIGNED, 0, 32, 4),
|
||||
/* [2] PTR -> VOID */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_PTR, 0, 0), 0),
|
||||
/* [3] FUNC_PROTO `int(void *a)` */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_FUNC_PROTO, 0, 1), 1),
|
||||
BTF_PARAM_ENC(1 /* "a" */, 2),
|
||||
/* [4] FUNC 'a' -> FUNC_PROTO (main prog) */
|
||||
BTF_TYPE_ENC(1 /* "a" */, BTF_INFO_ENC(BTF_KIND_FUNC, 0, BTF_FUNC_GLOBAL), 3),
|
||||
/* [5] FUNC_PROTO `int(void *b __arg_ctx)` */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_FUNC_PROTO, 0, 1), 1),
|
||||
BTF_PARAM_ENC(3 /* "b" */, 2),
|
||||
/* [6] FUNC 'b' -> FUNC_PROTO (subprog) */
|
||||
BTF_TYPE_ENC(3 /* "b" */, BTF_INFO_ENC(BTF_KIND_FUNC, 0, BTF_FUNC_GLOBAL), 5),
|
||||
/* [7] DECL_TAG 'arg:ctx' -> func 'b' arg 'b' */
|
||||
BTF_TYPE_DECL_TAG_ENC(5 /* "arg:ctx" */, 6, 0),
|
||||
};
|
||||
const struct bpf_insn insns[] = {
|
||||
/* main prog */
|
||||
BPF_CALL_REL(+1),
|
||||
BPF_EXIT_INSN(),
|
||||
/* global subprog */
|
||||
BPF_EMIT_CALL(BPF_FUNC_get_func_ip), /* needs PTR_TO_CTX */
|
||||
BPF_EXIT_INSN(),
|
||||
};
|
||||
const struct bpf_func_info_min func_infos[] = {
|
||||
{ 0, 4 }, /* main prog -> FUNC 'a' */
|
||||
{ 2, 6 }, /* subprog -> FUNC 'b' */
|
||||
};
|
||||
LIBBPF_OPTS(bpf_prog_load_opts, opts);
|
||||
int prog_fd, btf_fd, insn_cnt = ARRAY_SIZE(insns);
|
||||
|
||||
if (cached_result >= 0)
|
||||
return cached_result;
|
||||
|
||||
btf_fd = libbpf__load_raw_btf((char *)types, sizeof(types), strs, sizeof(strs));
|
||||
if (btf_fd < 0)
|
||||
return 0;
|
||||
|
||||
opts.prog_btf_fd = btf_fd;
|
||||
opts.func_info = &func_infos;
|
||||
opts.func_info_cnt = ARRAY_SIZE(func_infos);
|
||||
opts.func_info_rec_size = sizeof(func_infos[0]);
|
||||
|
||||
prog_fd = bpf_prog_load(BPF_PROG_TYPE_KPROBE, "det_arg_ctx",
|
||||
"GPL", insns, insn_cnt, &opts);
|
||||
close(btf_fd);
|
||||
|
||||
cached_result = probe_fd(prog_fd);
|
||||
return cached_result;
|
||||
}
|
||||
|
||||
/* Check if main program or global subprog's function prototype has `arg:ctx`
|
||||
* argument tags, and, if necessary, substitute correct type to match what BPF
|
||||
* verifier would expect, taking into account specific program type. This
|
||||
@ -6766,7 +6890,7 @@ static int clone_func_btf_info(struct btf *btf, int orig_fn_id, struct bpf_progr
|
||||
*/
|
||||
static int bpf_program_fixup_func_info(struct bpf_object *obj, struct bpf_program *prog)
|
||||
{
|
||||
const char *ctx_name = NULL, *ctx_tag = "arg:ctx";
|
||||
const char *ctx_name = NULL, *ctx_tag = "arg:ctx", *fn_name;
|
||||
struct bpf_func_info_min *func_rec;
|
||||
struct btf_type *fn_t, *fn_proto_t;
|
||||
struct btf *btf = obj->btf;
|
||||
@ -6780,6 +6904,10 @@ static int bpf_program_fixup_func_info(struct bpf_object *obj, struct bpf_progra
|
||||
if (!obj->btf_ext || !prog->func_info)
|
||||
return 0;
|
||||
|
||||
/* don't do any fix ups if kernel natively supports __arg_ctx */
|
||||
if (probe_kern_arg_ctx_tag() > 0)
|
||||
return 0;
|
||||
|
||||
/* some BPF program types just don't have named context structs, so
|
||||
* this fallback mechanism doesn't work for them
|
||||
*/
|
||||
@ -6842,15 +6970,11 @@ static int bpf_program_fixup_func_info(struct bpf_object *obj, struct bpf_progra
|
||||
if (arg_idx < 0 || arg_idx >= arg_cnt)
|
||||
continue;
|
||||
|
||||
/* check if existing parameter already matches verifier expectations */
|
||||
/* check if we should fix up argument type */
|
||||
p = &btf_params(fn_proto_t)[arg_idx];
|
||||
t = skip_mods_and_typedefs(btf, p->type, NULL);
|
||||
if (btf_is_ptr(t) &&
|
||||
(t = skip_mods_and_typedefs(btf, t->type, NULL)) &&
|
||||
btf_is_struct(t) &&
|
||||
strcmp(btf__str_by_offset(btf, t->name_off), ctx_name) == 0) {
|
||||
continue; /* no need for fix up */
|
||||
}
|
||||
fn_name = btf__str_by_offset(btf, fn_t->name_off) ?: "<anon>";
|
||||
if (!need_func_arg_type_fixup(btf, prog, fn_name, arg_idx, p->type, ctx_name))
|
||||
continue;
|
||||
|
||||
/* clone fn/fn_proto, unless we already did it for another arg */
|
||||
if (func_rec->type_id == orig_fn_id) {
|
||||
|
135
tools/testing/selftests/bpf/prog_tests/sock_iter_batch.c
Normal file
135
tools/testing/selftests/bpf/prog_tests/sock_iter_batch.c
Normal file
@ -0,0 +1,135 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2024 Meta
|
||||
|
||||
#include <test_progs.h>
|
||||
#include "network_helpers.h"
|
||||
#include "sock_iter_batch.skel.h"
|
||||
|
||||
#define TEST_NS "sock_iter_batch_netns"
|
||||
|
||||
static const int nr_soreuse = 4;
|
||||
|
||||
static void do_test(int sock_type, bool onebyone)
|
||||
{
|
||||
int err, i, nread, to_read, total_read, iter_fd = -1;
|
||||
int first_idx, second_idx, indices[nr_soreuse];
|
||||
struct bpf_link *link = NULL;
|
||||
struct sock_iter_batch *skel;
|
||||
int *fds[2] = {};
|
||||
|
||||
skel = sock_iter_batch__open();
|
||||
if (!ASSERT_OK_PTR(skel, "sock_iter_batch__open"))
|
||||
return;
|
||||
|
||||
/* Prepare 2 buckets of sockets in the kernel hashtable */
|
||||
for (i = 0; i < ARRAY_SIZE(fds); i++) {
|
||||
int local_port;
|
||||
|
||||
fds[i] = start_reuseport_server(AF_INET6, sock_type, "::1", 0, 0,
|
||||
nr_soreuse);
|
||||
if (!ASSERT_OK_PTR(fds[i], "start_reuseport_server"))
|
||||
goto done;
|
||||
local_port = get_socket_local_port(*fds[i]);
|
||||
if (!ASSERT_GE(local_port, 0, "get_socket_local_port"))
|
||||
goto done;
|
||||
skel->rodata->ports[i] = ntohs(local_port);
|
||||
}
|
||||
|
||||
err = sock_iter_batch__load(skel);
|
||||
if (!ASSERT_OK(err, "sock_iter_batch__load"))
|
||||
goto done;
|
||||
|
||||
link = bpf_program__attach_iter(sock_type == SOCK_STREAM ?
|
||||
skel->progs.iter_tcp_soreuse :
|
||||
skel->progs.iter_udp_soreuse,
|
||||
NULL);
|
||||
if (!ASSERT_OK_PTR(link, "bpf_program__attach_iter"))
|
||||
goto done;
|
||||
|
||||
iter_fd = bpf_iter_create(bpf_link__fd(link));
|
||||
if (!ASSERT_GE(iter_fd, 0, "bpf_iter_create"))
|
||||
goto done;
|
||||
|
||||
/* Test reading a bucket (either from fds[0] or fds[1]).
|
||||
* Only read "nr_soreuse - 1" number of sockets
|
||||
* from a bucket and leave one socket out from
|
||||
* that bucket on purpose.
|
||||
*/
|
||||
to_read = (nr_soreuse - 1) * sizeof(*indices);
|
||||
total_read = 0;
|
||||
first_idx = -1;
|
||||
do {
|
||||
nread = read(iter_fd, indices, onebyone ? sizeof(*indices) : to_read);
|
||||
if (nread <= 0 || nread % sizeof(*indices))
|
||||
break;
|
||||
total_read += nread;
|
||||
|
||||
if (first_idx == -1)
|
||||
first_idx = indices[0];
|
||||
for (i = 0; i < nread / sizeof(*indices); i++)
|
||||
ASSERT_EQ(indices[i], first_idx, "first_idx");
|
||||
} while (total_read < to_read);
|
||||
ASSERT_EQ(nread, onebyone ? sizeof(*indices) : to_read, "nread");
|
||||
ASSERT_EQ(total_read, to_read, "total_read");
|
||||
|
||||
free_fds(fds[first_idx], nr_soreuse);
|
||||
fds[first_idx] = NULL;
|
||||
|
||||
/* Read the "whole" second bucket */
|
||||
to_read = nr_soreuse * sizeof(*indices);
|
||||
total_read = 0;
|
||||
second_idx = !first_idx;
|
||||
do {
|
||||
nread = read(iter_fd, indices, onebyone ? sizeof(*indices) : to_read);
|
||||
if (nread <= 0 || nread % sizeof(*indices))
|
||||
break;
|
||||
total_read += nread;
|
||||
|
||||
for (i = 0; i < nread / sizeof(*indices); i++)
|
||||
ASSERT_EQ(indices[i], second_idx, "second_idx");
|
||||
} while (total_read <= to_read);
|
||||
ASSERT_EQ(nread, 0, "nread");
|
||||
/* Both so_reuseport ports should be in different buckets, so
|
||||
* total_read must equal to the expected to_read.
|
||||
*
|
||||
* For a very unlikely case, both ports collide at the same bucket,
|
||||
* the bucket offset (i.e. 3) will be skipped and it cannot
|
||||
* expect the to_read number of bytes.
|
||||
*/
|
||||
if (skel->bss->bucket[0] != skel->bss->bucket[1])
|
||||
ASSERT_EQ(total_read, to_read, "total_read");
|
||||
|
||||
done:
|
||||
for (i = 0; i < ARRAY_SIZE(fds); i++)
|
||||
free_fds(fds[i], nr_soreuse);
|
||||
if (iter_fd < 0)
|
||||
close(iter_fd);
|
||||
bpf_link__destroy(link);
|
||||
sock_iter_batch__destroy(skel);
|
||||
}
|
||||
|
||||
void test_sock_iter_batch(void)
|
||||
{
|
||||
struct nstoken *nstoken = NULL;
|
||||
|
||||
SYS_NOFAIL("ip netns del " TEST_NS " &> /dev/null");
|
||||
SYS(done, "ip netns add %s", TEST_NS);
|
||||
SYS(done, "ip -net %s link set dev lo up", TEST_NS);
|
||||
|
||||
nstoken = open_netns(TEST_NS);
|
||||
if (!ASSERT_OK_PTR(nstoken, "open_netns"))
|
||||
goto done;
|
||||
|
||||
if (test__start_subtest("tcp")) {
|
||||
do_test(SOCK_STREAM, true);
|
||||
do_test(SOCK_STREAM, false);
|
||||
}
|
||||
if (test__start_subtest("udp")) {
|
||||
do_test(SOCK_DGRAM, true);
|
||||
do_test(SOCK_DGRAM, false);
|
||||
}
|
||||
close_netns(nstoken);
|
||||
|
||||
done:
|
||||
SYS_NOFAIL("ip netns del " TEST_NS " &> /dev/null");
|
||||
}
|
@ -47,6 +47,19 @@ static void subtest_ctx_arg_rewrite(void)
|
||||
struct btf *btf = NULL;
|
||||
__u32 info_len = sizeof(info);
|
||||
int err, fd, i;
|
||||
struct btf *kern_btf = NULL;
|
||||
|
||||
kern_btf = btf__load_vmlinux_btf();
|
||||
if (!ASSERT_OK_PTR(kern_btf, "kern_btf_load"))
|
||||
return;
|
||||
|
||||
/* simple detection of kernel native arg:ctx tag support */
|
||||
if (btf__find_by_name_kind(kern_btf, "bpf_subprog_arg_info", BTF_KIND_STRUCT) > 0) {
|
||||
test__skip();
|
||||
btf__free(kern_btf);
|
||||
return;
|
||||
}
|
||||
btf__free(kern_btf);
|
||||
|
||||
skel = test_global_func_ctx_args__open();
|
||||
if (!ASSERT_OK_PTR(skel, "skel_open"))
|
||||
|
@ -72,6 +72,8 @@
|
||||
#define inet_rcv_saddr sk.__sk_common.skc_rcv_saddr
|
||||
#define inet_dport sk.__sk_common.skc_dport
|
||||
|
||||
#define udp_portaddr_hash inet.sk.__sk_common.skc_u16hashes[1]
|
||||
|
||||
#define ir_loc_addr req.__req_common.skc_rcv_saddr
|
||||
#define ir_num req.__req_common.skc_num
|
||||
#define ir_rmt_addr req.__req_common.skc_daddr
|
||||
@ -85,6 +87,7 @@
|
||||
#define sk_rmem_alloc sk_backlog.rmem_alloc
|
||||
#define sk_refcnt __sk_common.skc_refcnt
|
||||
#define sk_state __sk_common.skc_state
|
||||
#define sk_net __sk_common.skc_net
|
||||
#define sk_v6_daddr __sk_common.skc_v6_daddr
|
||||
#define sk_v6_rcv_saddr __sk_common.skc_v6_rcv_saddr
|
||||
#define sk_flags __sk_common.skc_flags
|
||||
|
91
tools/testing/selftests/bpf/progs/sock_iter_batch.c
Normal file
91
tools/testing/selftests/bpf/progs/sock_iter_batch.c
Normal file
@ -0,0 +1,91 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2024 Meta
|
||||
|
||||
#include "vmlinux.h"
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include <bpf/bpf_core_read.h>
|
||||
#include <bpf/bpf_endian.h>
|
||||
#include "bpf_tracing_net.h"
|
||||
#include "bpf_kfuncs.h"
|
||||
|
||||
#define ATTR __always_inline
|
||||
#include "test_jhash.h"
|
||||
|
||||
static bool ipv6_addr_loopback(const struct in6_addr *a)
|
||||
{
|
||||
return (a->s6_addr32[0] | a->s6_addr32[1] |
|
||||
a->s6_addr32[2] | (a->s6_addr32[3] ^ bpf_htonl(1))) == 0;
|
||||
}
|
||||
|
||||
volatile const __u16 ports[2];
|
||||
unsigned int bucket[2];
|
||||
|
||||
SEC("iter/tcp")
|
||||
int iter_tcp_soreuse(struct bpf_iter__tcp *ctx)
|
||||
{
|
||||
struct sock *sk = (struct sock *)ctx->sk_common;
|
||||
struct inet_hashinfo *hinfo;
|
||||
unsigned int hash;
|
||||
struct net *net;
|
||||
int idx;
|
||||
|
||||
if (!sk)
|
||||
return 0;
|
||||
|
||||
sk = bpf_rdonly_cast(sk, bpf_core_type_id_kernel(struct sock));
|
||||
if (sk->sk_family != AF_INET6 ||
|
||||
sk->sk_state != TCP_LISTEN ||
|
||||
!ipv6_addr_loopback(&sk->sk_v6_rcv_saddr))
|
||||
return 0;
|
||||
|
||||
if (sk->sk_num == ports[0])
|
||||
idx = 0;
|
||||
else if (sk->sk_num == ports[1])
|
||||
idx = 1;
|
||||
else
|
||||
return 0;
|
||||
|
||||
/* bucket selection as in inet_lhash2_bucket_sk() */
|
||||
net = sk->sk_net.net;
|
||||
hash = jhash2(sk->sk_v6_rcv_saddr.s6_addr32, 4, net->hash_mix);
|
||||
hash ^= sk->sk_num;
|
||||
hinfo = net->ipv4.tcp_death_row.hashinfo;
|
||||
bucket[idx] = hash & hinfo->lhash2_mask;
|
||||
bpf_seq_write(ctx->meta->seq, &idx, sizeof(idx));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define udp_sk(ptr) container_of(ptr, struct udp_sock, inet.sk)
|
||||
|
||||
SEC("iter/udp")
|
||||
int iter_udp_soreuse(struct bpf_iter__udp *ctx)
|
||||
{
|
||||
struct sock *sk = (struct sock *)ctx->udp_sk;
|
||||
struct udp_table *udptable;
|
||||
int idx;
|
||||
|
||||
if (!sk)
|
||||
return 0;
|
||||
|
||||
sk = bpf_rdonly_cast(sk, bpf_core_type_id_kernel(struct sock));
|
||||
if (sk->sk_family != AF_INET6 ||
|
||||
!ipv6_addr_loopback(&sk->sk_v6_rcv_saddr))
|
||||
return 0;
|
||||
|
||||
if (sk->sk_num == ports[0])
|
||||
idx = 0;
|
||||
else if (sk->sk_num == ports[1])
|
||||
idx = 1;
|
||||
else
|
||||
return 0;
|
||||
|
||||
/* bucket selection as in udp_hashslot2() */
|
||||
udptable = sk->sk_net.net->ipv4.udp_table;
|
||||
bucket[idx] = udp_sk(sk)->udp_portaddr_hash & udptable->mask;
|
||||
bpf_seq_write(ctx->meta->seq, &idx, sizeof(idx));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
@ -69,3 +69,34 @@ u32 jhash(const void *key, u32 length, u32 initval)
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static __always_inline u32 jhash2(const u32 *k, u32 length, u32 initval)
|
||||
{
|
||||
u32 a, b, c;
|
||||
|
||||
/* Set up the internal state */
|
||||
a = b = c = JHASH_INITVAL + (length<<2) + initval;
|
||||
|
||||
/* Handle most of the key */
|
||||
while (length > 3) {
|
||||
a += k[0];
|
||||
b += k[1];
|
||||
c += k[2];
|
||||
__jhash_mix(a, b, c);
|
||||
length -= 3;
|
||||
k += 3;
|
||||
}
|
||||
|
||||
/* Handle the last 3 u32's */
|
||||
switch (length) {
|
||||
case 3: c += k[2];
|
||||
case 2: b += k[1];
|
||||
case 1: a += k[0];
|
||||
__jhash_final(a, b, c);
|
||||
break;
|
||||
case 0: /* Nothing left to add */
|
||||
break;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include <vmlinux.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include <bpf/bpf_tracing.h>
|
||||
#include "bpf_misc.h"
|
||||
#include "xdp_metadata.h"
|
||||
#include "bpf_kfuncs.h"
|
||||
@ -138,25 +139,182 @@ __weak int subprog_ctx_tag(void *ctx __arg_ctx)
|
||||
return bpf_get_stack(ctx, stack, sizeof(stack), 0);
|
||||
}
|
||||
|
||||
__weak int raw_tp_canonical(struct bpf_raw_tracepoint_args *ctx __arg_ctx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
__weak int raw_tp_u64_array(u64 *ctx __arg_ctx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("?raw_tp")
|
||||
__success __log_level(2)
|
||||
int arg_tag_ctx_raw_tp(void *ctx)
|
||||
{
|
||||
return subprog_ctx_tag(ctx);
|
||||
return subprog_ctx_tag(ctx) + raw_tp_canonical(ctx) + raw_tp_u64_array(ctx);
|
||||
}
|
||||
|
||||
SEC("?raw_tp.w")
|
||||
__success __log_level(2)
|
||||
int arg_tag_ctx_raw_tp_writable(void *ctx)
|
||||
{
|
||||
return subprog_ctx_tag(ctx) + raw_tp_canonical(ctx) + raw_tp_u64_array(ctx);
|
||||
}
|
||||
|
||||
SEC("?tp_btf/sys_enter")
|
||||
__success __log_level(2)
|
||||
int arg_tag_ctx_raw_tp_btf(void *ctx)
|
||||
{
|
||||
return subprog_ctx_tag(ctx) + raw_tp_canonical(ctx) + raw_tp_u64_array(ctx);
|
||||
}
|
||||
|
||||
struct whatever { };
|
||||
|
||||
__weak int tp_whatever(struct whatever *ctx __arg_ctx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("?tp")
|
||||
__success __log_level(2)
|
||||
int arg_tag_ctx_tp(void *ctx)
|
||||
{
|
||||
return subprog_ctx_tag(ctx);
|
||||
return subprog_ctx_tag(ctx) + tp_whatever(ctx);
|
||||
}
|
||||
|
||||
__weak int kprobe_subprog_pt_regs(struct pt_regs *ctx __arg_ctx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
__weak int kprobe_subprog_typedef(bpf_user_pt_regs_t *ctx __arg_ctx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("?kprobe")
|
||||
__success __log_level(2)
|
||||
int arg_tag_ctx_kprobe(void *ctx)
|
||||
{
|
||||
return subprog_ctx_tag(ctx);
|
||||
return subprog_ctx_tag(ctx) +
|
||||
kprobe_subprog_pt_regs(ctx) +
|
||||
kprobe_subprog_typedef(ctx);
|
||||
}
|
||||
|
||||
__weak int perf_subprog_regs(
|
||||
#if defined(bpf_target_riscv)
|
||||
struct user_regs_struct *ctx __arg_ctx
|
||||
#elif defined(bpf_target_s390)
|
||||
/* user_pt_regs typedef is anonymous struct, so only `void *` works */
|
||||
void *ctx __arg_ctx
|
||||
#elif defined(bpf_target_loongarch) || defined(bpf_target_arm64) || defined(bpf_target_powerpc)
|
||||
struct user_pt_regs *ctx __arg_ctx
|
||||
#else
|
||||
struct pt_regs *ctx __arg_ctx
|
||||
#endif
|
||||
)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
__weak int perf_subprog_typedef(bpf_user_pt_regs_t *ctx __arg_ctx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
__weak int perf_subprog_canonical(struct bpf_perf_event_data *ctx __arg_ctx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("?perf_event")
|
||||
__success __log_level(2)
|
||||
int arg_tag_ctx_perf(void *ctx)
|
||||
{
|
||||
return subprog_ctx_tag(ctx) +
|
||||
perf_subprog_regs(ctx) +
|
||||
perf_subprog_typedef(ctx) +
|
||||
perf_subprog_canonical(ctx);
|
||||
}
|
||||
|
||||
__weak int iter_subprog_void(void *ctx __arg_ctx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
__weak int iter_subprog_typed(struct bpf_iter__task *ctx __arg_ctx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("?iter/task")
|
||||
__success __log_level(2)
|
||||
int arg_tag_ctx_iter_task(struct bpf_iter__task *ctx)
|
||||
{
|
||||
return (iter_subprog_void(ctx) + iter_subprog_typed(ctx)) & 1;
|
||||
}
|
||||
|
||||
__weak int tracing_subprog_void(void *ctx __arg_ctx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
__weak int tracing_subprog_u64(u64 *ctx __arg_ctx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int acc;
|
||||
|
||||
SEC("?fentry/" SYS_PREFIX "sys_nanosleep")
|
||||
__success __log_level(2)
|
||||
int BPF_PROG(arg_tag_ctx_fentry)
|
||||
{
|
||||
acc += tracing_subprog_void(ctx) + tracing_subprog_u64(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("?fexit/" SYS_PREFIX "sys_nanosleep")
|
||||
__success __log_level(2)
|
||||
int BPF_PROG(arg_tag_ctx_fexit)
|
||||
{
|
||||
acc += tracing_subprog_void(ctx) + tracing_subprog_u64(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("?fmod_ret/" SYS_PREFIX "sys_nanosleep")
|
||||
__success __log_level(2)
|
||||
int BPF_PROG(arg_tag_ctx_fmod_ret)
|
||||
{
|
||||
return tracing_subprog_void(ctx) + tracing_subprog_u64(ctx);
|
||||
}
|
||||
|
||||
SEC("?lsm/bpf")
|
||||
__success __log_level(2)
|
||||
int BPF_PROG(arg_tag_ctx_lsm)
|
||||
{
|
||||
return tracing_subprog_void(ctx) + tracing_subprog_u64(ctx);
|
||||
}
|
||||
|
||||
SEC("?struct_ops/test_1")
|
||||
__success __log_level(2)
|
||||
int BPF_PROG(arg_tag_ctx_struct_ops)
|
||||
{
|
||||
return tracing_subprog_void(ctx) + tracing_subprog_u64(ctx);
|
||||
}
|
||||
|
||||
SEC(".struct_ops")
|
||||
struct bpf_dummy_ops dummy_1 = {
|
||||
.test_1 = (void *)arg_tag_ctx_struct_ops,
|
||||
};
|
||||
|
||||
SEC("?syscall")
|
||||
__success __log_level(2)
|
||||
int arg_tag_ctx_syscall(void *ctx)
|
||||
{
|
||||
return tracing_subprog_void(ctx) + tracing_subprog_u64(ctx) + tp_whatever(ctx);
|
||||
}
|
||||
|
||||
__weak int subprog_dynptr(struct bpf_dynptr *dptr)
|
||||
|
@ -146,4 +146,23 @@ l0_%=: exit; \
|
||||
: __clobber_all);
|
||||
}
|
||||
|
||||
SEC("flow_dissector")
|
||||
__description("flow_keys illegal alu op with variable offset")
|
||||
__failure __msg("R7 pointer arithmetic on flow_keys prohibited")
|
||||
__naked void flow_keys_illegal_variable_offset_alu(void)
|
||||
{
|
||||
asm volatile(" \
|
||||
r6 = r1; \
|
||||
r7 = *(u64*)(r6 + %[flow_keys_off]); \
|
||||
r8 = 8; \
|
||||
r8 /= 1; \
|
||||
r8 &= 8; \
|
||||
r7 += r8; \
|
||||
r0 = *(u64*)(r7 + 0); \
|
||||
exit; \
|
||||
" :
|
||||
: __imm_const(flow_keys_off, offsetof(struct __sk_buff, flow_keys))
|
||||
: __clobber_all);
|
||||
}
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
@ -1,2 +1,10 @@
|
||||
CONFIG_BONDING=y
|
||||
CONFIG_BRIDGE=y
|
||||
CONFIG_DUMMY=y
|
||||
CONFIG_IPV6=y
|
||||
CONFIG_MACVLAN=y
|
||||
CONFIG_NET_ACT_GACT=y
|
||||
CONFIG_NET_CLS_FLOWER=y
|
||||
CONFIG_NET_SCH_INGRESS=y
|
||||
CONFIG_NLMON=y
|
||||
CONFIG_VETH=y
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
# Regression Test:
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
# Regression Test:
|
||||
|
@ -40,7 +40,6 @@
|
||||
# | + $swp1 $swp3 + + $swp4 |
|
||||
# | | iPOOL1 iPOOL0 | | iPOOL2 |
|
||||
# | | ePOOL4 ePOOL5 | | ePOOL4 |
|
||||
# | | 1Gbps | | 1Gbps |
|
||||
# | | PFC:enabled=1 | | PFC:enabled=1 |
|
||||
# | +-|----------------------|-+ +-|------------------------+ |
|
||||
# | | + $swp1.111 $swp3.111 + | | + $swp4.111 | |
|
||||
@ -120,6 +119,9 @@ h2_destroy()
|
||||
|
||||
switch_create()
|
||||
{
|
||||
local lanes_swp4
|
||||
local pg1_size
|
||||
|
||||
# pools
|
||||
# -----
|
||||
|
||||
@ -229,7 +231,20 @@ switch_create()
|
||||
dcb pfc set dev $swp4 prio-pfc all:off 1:on
|
||||
# PG0 will get autoconfigured to Xoff, give PG1 arbitrarily 100K, which
|
||||
# is (-2*MTU) about 80K of delay provision.
|
||||
dcb buffer set dev $swp4 buffer-size all:0 1:$_100KB
|
||||
pg1_size=$_100KB
|
||||
|
||||
setup_wait_dev_with_timeout $swp4
|
||||
|
||||
lanes_swp4=$(ethtool $swp4 | grep 'Lanes:')
|
||||
lanes_swp4=${lanes_swp4#*"Lanes: "}
|
||||
|
||||
# 8-lane ports use two buffers among which the configured buffer
|
||||
# is split, so double the size to get twice (20K + 80K).
|
||||
if [[ $lanes_swp4 -eq 8 ]]; then
|
||||
pg1_size=$((pg1_size * 2))
|
||||
fi
|
||||
|
||||
dcb buffer set dev $swp4 buffer-size all:0 1:$pg1_size
|
||||
|
||||
# bridges
|
||||
# -------
|
||||
|
@ -10,7 +10,8 @@ lib_dir=$(dirname $0)/../../../../net/forwarding
|
||||
ALL_TESTS="single_mask_test identical_filters_test two_masks_test \
|
||||
multiple_masks_test ctcam_edge_cases_test delta_simple_test \
|
||||
delta_two_masks_one_key_test delta_simple_rehash_test \
|
||||
bloom_simple_test bloom_complex_test bloom_delta_test"
|
||||
bloom_simple_test bloom_complex_test bloom_delta_test \
|
||||
max_erp_entries_test max_group_size_test"
|
||||
NUM_NETIFS=2
|
||||
source $lib_dir/lib.sh
|
||||
source $lib_dir/tc_common.sh
|
||||
@ -983,6 +984,109 @@ bloom_delta_test()
|
||||
log_test "bloom delta test ($tcflags)"
|
||||
}
|
||||
|
||||
max_erp_entries_test()
|
||||
{
|
||||
# The number of eRP entries is limited. Once the maximum number of eRPs
|
||||
# has been reached, filters cannot be added. This test verifies that
|
||||
# when this limit is reached, inserstion fails without crashing.
|
||||
|
||||
RET=0
|
||||
|
||||
local num_masks=32
|
||||
local num_regions=15
|
||||
local chain_failed
|
||||
local mask_failed
|
||||
local ret
|
||||
|
||||
if [[ "$tcflags" != "skip_sw" ]]; then
|
||||
return 0;
|
||||
fi
|
||||
|
||||
for ((i=1; i < $num_regions; i++)); do
|
||||
for ((j=$num_masks; j >= 0; j--)); do
|
||||
tc filter add dev $h2 ingress chain $i protocol ip \
|
||||
pref $i handle $j flower $tcflags \
|
||||
dst_ip 192.1.0.0/$j &> /dev/null
|
||||
ret=$?
|
||||
|
||||
if [ $ret -ne 0 ]; then
|
||||
chain_failed=$i
|
||||
mask_failed=$j
|
||||
break 2
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
# We expect to exceed the maximum number of eRP entries, so that
|
||||
# insertion eventually fails. Otherwise, the test should be adjusted to
|
||||
# add more filters.
|
||||
check_fail $ret "expected to exceed number of eRP entries"
|
||||
|
||||
for ((; i >= 1; i--)); do
|
||||
for ((j=0; j <= $num_masks; j++)); do
|
||||
tc filter del dev $h2 ingress chain $i protocol ip \
|
||||
pref $i handle $j flower &> /dev/null
|
||||
done
|
||||
done
|
||||
|
||||
log_test "max eRP entries test ($tcflags). " \
|
||||
"max chain $chain_failed, mask $mask_failed"
|
||||
}
|
||||
|
||||
max_group_size_test()
|
||||
{
|
||||
# The number of ACLs in an ACL group is limited. Once the maximum
|
||||
# number of ACLs has been reached, filters cannot be added. This test
|
||||
# verifies that when this limit is reached, insertion fails without
|
||||
# crashing.
|
||||
|
||||
RET=0
|
||||
|
||||
local num_acls=32
|
||||
local max_size
|
||||
local ret
|
||||
|
||||
if [[ "$tcflags" != "skip_sw" ]]; then
|
||||
return 0;
|
||||
fi
|
||||
|
||||
for ((i=1; i < $num_acls; i++)); do
|
||||
if [[ $(( i % 2 )) == 1 ]]; then
|
||||
tc filter add dev $h2 ingress pref $i proto ipv4 \
|
||||
flower $tcflags dst_ip 198.51.100.1/32 \
|
||||
ip_proto tcp tcp_flags 0x01/0x01 \
|
||||
action drop &> /dev/null
|
||||
else
|
||||
tc filter add dev $h2 ingress pref $i proto ipv6 \
|
||||
flower $tcflags dst_ip 2001:db8:1::1/128 \
|
||||
action drop &> /dev/null
|
||||
fi
|
||||
|
||||
ret=$?
|
||||
[[ $ret -ne 0 ]] && max_size=$((i - 1)) && break
|
||||
done
|
||||
|
||||
# We expect to exceed the maximum number of ACLs in a group, so that
|
||||
# insertion eventually fails. Otherwise, the test should be adjusted to
|
||||
# add more filters.
|
||||
check_fail $ret "expected to exceed number of ACLs in a group"
|
||||
|
||||
for ((; i >= 1; i--)); do
|
||||
if [[ $(( i % 2 )) == 1 ]]; then
|
||||
tc filter del dev $h2 ingress pref $i proto ipv4 \
|
||||
flower $tcflags dst_ip 198.51.100.1/32 \
|
||||
ip_proto tcp tcp_flags 0x01/0x01 \
|
||||
action drop &> /dev/null
|
||||
else
|
||||
tc filter del dev $h2 ingress pref $i proto ipv6 \
|
||||
flower $tcflags dst_ip 2001:db8:1::1/128 \
|
||||
action drop &> /dev/null
|
||||
fi
|
||||
done
|
||||
|
||||
log_test "max ACL group size test ($tcflags). max size $max_size"
|
||||
}
|
||||
|
||||
setup_prepare()
|
||||
{
|
||||
h1=${NETIFS[p1]}
|
||||
|
10
tools/testing/selftests/drivers/net/netdevsim/config
Normal file
10
tools/testing/selftests/drivers/net/netdevsim/config
Normal file
@ -0,0 +1,10 @@
|
||||
CONFIG_DUMMY=y
|
||||
CONFIG_GENEVE=m
|
||||
CONFIG_IPV6=y
|
||||
CONFIG_NETDEVSIM=m
|
||||
CONFIG_NET_SCH_MQPRIO=y
|
||||
CONFIG_NET_SCH_MULTIQ=y
|
||||
CONFIG_NET_SCH_PRIO=y
|
||||
CONFIG_PSAMPLE=y
|
||||
CONFIG_PTP_1588_CLOCK_MOCK=y
|
||||
CONFIG_VXLAN=m
|
@ -51,6 +51,7 @@ function make_netdev {
|
||||
fi
|
||||
|
||||
echo $NSIM_ID $@ > /sys/bus/netdevsim/new_device
|
||||
udevadm settle
|
||||
# get new device name
|
||||
ls /sys/bus/netdevsim/devices/netdevsim${NSIM_ID}/net/
|
||||
}
|
||||
|
@ -8,16 +8,20 @@ NSIM_NETDEV=$(make_netdev)
|
||||
|
||||
set -o pipefail
|
||||
|
||||
# Since commit 2b3ddcb35357 ("ethtool: fec: Change the prompt ...")
|
||||
# in ethtool CLI the Configured lines start with Supported/Configured.
|
||||
configured=$($ETHTOOL --show-fec $NSIM_NETDEV | tail -2 | head -1 | cut -d' ' -f1)
|
||||
|
||||
# netdevsim starts out with None/None
|
||||
s=$($ETHTOOL --show-fec $NSIM_NETDEV | tail -2)
|
||||
check $? "$s" "Configured FEC encodings: None
|
||||
check $? "$s" "$configured FEC encodings: None
|
||||
Active FEC encoding: None"
|
||||
|
||||
# Test Auto
|
||||
$ETHTOOL --set-fec $NSIM_NETDEV encoding auto
|
||||
check $?
|
||||
s=$($ETHTOOL --show-fec $NSIM_NETDEV | tail -2)
|
||||
check $? "$s" "Configured FEC encodings: Auto
|
||||
check $? "$s" "$configured FEC encodings: Auto
|
||||
Active FEC encoding: Off"
|
||||
|
||||
# Test case in-sensitivity
|
||||
@ -25,7 +29,7 @@ for o in off Off OFF; do
|
||||
$ETHTOOL --set-fec $NSIM_NETDEV encoding $o
|
||||
check $?
|
||||
s=$($ETHTOOL --show-fec $NSIM_NETDEV | tail -2)
|
||||
check $? "$s" "Configured FEC encodings: Off
|
||||
check $? "$s" "$configured FEC encodings: Off
|
||||
Active FEC encoding: Off"
|
||||
done
|
||||
|
||||
@ -33,7 +37,7 @@ for o in BaseR baser BAser; do
|
||||
$ETHTOOL --set-fec $NSIM_NETDEV encoding $o
|
||||
check $?
|
||||
s=$($ETHTOOL --show-fec $NSIM_NETDEV | tail -2)
|
||||
check $? "$s" "Configured FEC encodings: BaseR
|
||||
check $? "$s" "$configured FEC encodings: BaseR
|
||||
Active FEC encoding: BaseR"
|
||||
done
|
||||
|
||||
@ -41,7 +45,7 @@ for o in llrs rs; do
|
||||
$ETHTOOL --set-fec $NSIM_NETDEV encoding $o
|
||||
check $?
|
||||
s=$($ETHTOOL --show-fec $NSIM_NETDEV | tail -2)
|
||||
check $? "$s" "Configured FEC encodings: ${o^^}
|
||||
check $? "$s" "$configured FEC encodings: ${o^^}
|
||||
Active FEC encoding: ${o^^}"
|
||||
done
|
||||
|
||||
@ -49,13 +53,13 @@ done
|
||||
$ETHTOOL --set-fec $NSIM_NETDEV encoding rs llrs
|
||||
check $?
|
||||
s=$($ETHTOOL --show-fec $NSIM_NETDEV | tail -2)
|
||||
check $? "$s" "Configured FEC encodings: RS LLRS
|
||||
check $? "$s" "$configured FEC encodings: RS LLRS
|
||||
Active FEC encoding: LLRS"
|
||||
|
||||
$ETHTOOL --set-fec $NSIM_NETDEV encoding rs off auto
|
||||
check $?
|
||||
s=$($ETHTOOL --show-fec $NSIM_NETDEV | tail -2)
|
||||
check $? "$s" "Configured FEC encodings: Auto Off RS
|
||||
check $? "$s" "$configured FEC encodings: Auto Off RS
|
||||
Active FEC encoding: RS"
|
||||
|
||||
# Make sure other link modes are rejected
|
||||
|
@ -233,6 +233,7 @@ function print_tables {
|
||||
function get_netdev_name {
|
||||
local -n old=$1
|
||||
|
||||
udevadm settle
|
||||
new=$(ls /sys/class/net)
|
||||
|
||||
for netdev in $new; do
|
||||
|
0
tools/testing/selftests/net/forwarding/lib.sh
Executable file → Normal file
0
tools/testing/selftests/net/forwarding/lib.sh
Executable file → Normal file
@ -28,6 +28,7 @@ ALL_TESTS="
|
||||
kci_test_neigh_get
|
||||
kci_test_bridge_parent_id
|
||||
kci_test_address_proto
|
||||
kci_test_enslave_bonding
|
||||
"
|
||||
|
||||
devdummy="test-dummy0"
|
||||
@ -1241,6 +1242,31 @@ kci_test_address_proto()
|
||||
return $ret
|
||||
}
|
||||
|
||||
kci_test_enslave_bonding()
|
||||
{
|
||||
local bond="bond123"
|
||||
local ret=0
|
||||
|
||||
setup_ns testns
|
||||
if [ $? -ne 0 ]; then
|
||||
end_test "SKIP bonding tests: cannot add net namespace $testns"
|
||||
return $ksft_skip
|
||||
fi
|
||||
|
||||
run_cmd ip -netns $testns link add dev $bond type bond mode balance-rr
|
||||
run_cmd ip -netns $testns link add dev $devdummy type dummy
|
||||
run_cmd ip -netns $testns link set dev $devdummy up
|
||||
run_cmd ip -netns $testns link set dev $devdummy master $bond down
|
||||
if [ $ret -ne 0 ]; then
|
||||
end_test "FAIL: initially up interface added to a bond and set down"
|
||||
ip netns del "$testns"
|
||||
return 1
|
||||
fi
|
||||
|
||||
end_test "PASS: enslave interface in a bond"
|
||||
ip netns del "$testns"
|
||||
}
|
||||
|
||||
kci_test_rtnl()
|
||||
{
|
||||
local current_test
|
||||
|
@ -52,5 +52,5 @@ $(OUTPUT)/%_ipv6: %.c
|
||||
|
||||
$(OUTPUT)/icmps-accept_ipv4: CFLAGS+= -DTEST_ICMPS_ACCEPT
|
||||
$(OUTPUT)/icmps-accept_ipv6: CFLAGS+= -DTEST_ICMPS_ACCEPT
|
||||
$(OUTPUT)/bench-lookups_ipv4: LDFLAGS+= -lm
|
||||
$(OUTPUT)/bench-lookups_ipv6: LDFLAGS+= -lm
|
||||
$(OUTPUT)/bench-lookups_ipv4: LDLIBS+= -lm
|
||||
$(OUTPUT)/bench-lookups_ipv6: LDLIBS+= -lm
|
||||
|
@ -707,6 +707,20 @@ TEST_F(tls, splice_from_pipe)
|
||||
EXPECT_EQ(memcmp(mem_send, mem_recv, send_len), 0);
|
||||
}
|
||||
|
||||
TEST_F(tls, splice_more)
|
||||
{
|
||||
unsigned int f = SPLICE_F_NONBLOCK | SPLICE_F_MORE | SPLICE_F_GIFT;
|
||||
int send_len = TLS_PAYLOAD_MAX_LEN;
|
||||
char mem_send[TLS_PAYLOAD_MAX_LEN];
|
||||
int i, send_pipe = 1;
|
||||
int p[2];
|
||||
|
||||
ASSERT_GE(pipe(p), 0);
|
||||
EXPECT_GE(write(p[1], mem_send, send_len), 0);
|
||||
for (i = 0; i < 32; i++)
|
||||
EXPECT_EQ(splice(p[0], NULL, self->fd, NULL, send_pipe, f), 1);
|
||||
}
|
||||
|
||||
TEST_F(tls, splice_from_pipe2)
|
||||
{
|
||||
int send_len = 16000;
|
||||
|
Loading…
Reference in New Issue
Block a user