Merge tag 'net-6.14-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
Pull networking fixes from Paolo Abeni:
"Including fixes from can, bluetooth and ipsec.
This contains a last minute revert of a recent GRE patch, mostly to
allow me stating there are no known regressions outstanding.
Current release - regressions:
- revert "gre: Fix IPv6 link-local address generation."
- eth: ti: am65-cpsw: fix NAPI registration sequence
Previous releases - regressions:
- ipv6: fix memleak of nhc_pcpu_rth_output in fib_check_nh_v6_gw().
- mptcp: fix data stream corruption in the address announcement
- bluetooth: fix connection regression between LE and non-LE adapters
- can:
- flexcan: only change CAN state when link up in system PM
- ucan: fix out of bound read in strscpy() source
Previous releases - always broken:
- lwtunnel: fix reentry loops
- ipv6: fix TCP GSO segmentation with NAT
- xfrm: force software GSO only in tunnel mode
- eth: ti: icssg-prueth: add lock to stats
Misc:
- add Andrea Mayer as a maintainer of SRv6"
* tag 'net-6.14-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net: (33 commits)
MAINTAINERS: Add Andrea Mayer as a maintainer of SRv6
Revert "gre: Fix IPv6 link-local address generation."
Revert "selftests: Add IPv6 link-local address generation tests for GRE devices."
net/neighbor: add missing policy for NDTPA_QUEUE_LENBYTES
tools headers: Sync uapi/asm-generic/socket.h with the kernel sources
mptcp: Fix data stream corruption in the address announcement
selftests: net: test for lwtunnel dst ref loops
net: ipv6: ioam6: fix lwtunnel_output() loop
net: lwtunnel: fix recursion loops
net: ti: icssg-prueth: Add lock to stats
net: atm: fix use after free in lec_send()
xsk: fix an integer overflow in xp_create_and_assign_umem()
net: stmmac: dwc-qos-eth: use devm_kzalloc() for AXI data
selftests: drv-net: use defer in the ping test
phy: fix xa_alloc_cyclic() error handling
dpll: fix xa_alloc_cyclic() error handling
devlink: fix xa_alloc_cyclic() error handling
ipv6: Set errno after ip_fib_metrics_init() in ip6_route_info_create().
ipv6: Fix memleak of nhc_pcpu_rth_output in fib_check_nh_v6_gw().
net: ipv6: fix TCP GSO segmentation with NAT
...
This commit is contained in:
@@ -170,7 +170,7 @@ allOf:
|
||||
const: renesas,r8a779h0-canfd
|
||||
then:
|
||||
patternProperties:
|
||||
"^channel[5-7]$": false
|
||||
"^channel[4-7]$": false
|
||||
else:
|
||||
if:
|
||||
not:
|
||||
|
||||
11
MAINTAINERS
11
MAINTAINERS
@@ -16660,6 +16660,17 @@ F: net/mptcp/
|
||||
F: tools/testing/selftests/bpf/*/*mptcp*.[ch]
|
||||
F: tools/testing/selftests/net/mptcp/
|
||||
|
||||
NETWORKING [SRv6]
|
||||
M: Andrea Mayer <andrea.mayer@uniroma2.it>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git
|
||||
F: include/linux/seg6*
|
||||
F: include/net/seg6*
|
||||
F: include/uapi/linux/seg6*
|
||||
F: net/ipv6/seg6*
|
||||
F: tools/testing/selftests/net/srv6*
|
||||
|
||||
NETWORKING [TCP]
|
||||
M: Eric Dumazet <edumazet@google.com>
|
||||
M: Neal Cardwell <ncardwell@google.com>
|
||||
|
||||
@@ -505,7 +505,7 @@ dpll_pin_alloc(u64 clock_id, u32 pin_idx, struct module *module,
|
||||
xa_init_flags(&pin->parent_refs, XA_FLAGS_ALLOC);
|
||||
ret = xa_alloc_cyclic(&dpll_pin_xa, &pin->id, pin, xa_limit_32b,
|
||||
&dpll_pin_xa_id, GFP_KERNEL);
|
||||
if (ret)
|
||||
if (ret < 0)
|
||||
goto err_xa_alloc;
|
||||
return pin;
|
||||
err_xa_alloc:
|
||||
|
||||
@@ -2260,14 +2260,19 @@ static int __maybe_unused flexcan_suspend(struct device *device)
|
||||
|
||||
flexcan_chip_interrupts_disable(dev);
|
||||
|
||||
err = flexcan_transceiver_disable(priv);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = pinctrl_pm_select_sleep_state(device);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
netif_stop_queue(dev);
|
||||
netif_device_detach(dev);
|
||||
|
||||
priv->can.state = CAN_STATE_SLEEPING;
|
||||
}
|
||||
priv->can.state = CAN_STATE_SLEEPING;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -2278,7 +2283,6 @@ static int __maybe_unused flexcan_resume(struct device *device)
|
||||
struct flexcan_priv *priv = netdev_priv(dev);
|
||||
int err;
|
||||
|
||||
priv->can.state = CAN_STATE_ERROR_ACTIVE;
|
||||
if (netif_running(dev)) {
|
||||
netif_device_attach(dev);
|
||||
netif_start_queue(dev);
|
||||
@@ -2292,12 +2296,20 @@ static int __maybe_unused flexcan_resume(struct device *device)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = flexcan_chip_start(dev);
|
||||
err = flexcan_transceiver_enable(priv);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = flexcan_chip_start(dev);
|
||||
if (err) {
|
||||
flexcan_transceiver_disable(priv);
|
||||
return err;
|
||||
}
|
||||
|
||||
flexcan_chip_interrupts_enable(dev);
|
||||
}
|
||||
|
||||
priv->can.state = CAN_STATE_ERROR_ACTIVE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -787,22 +787,14 @@ static void rcar_canfd_configure_controller(struct rcar_canfd_global *gpriv)
|
||||
}
|
||||
|
||||
static void rcar_canfd_configure_afl_rules(struct rcar_canfd_global *gpriv,
|
||||
u32 ch)
|
||||
u32 ch, u32 rule_entry)
|
||||
{
|
||||
u32 cfg;
|
||||
int offset, start, page, num_rules = RCANFD_CHANNEL_NUMRULES;
|
||||
int offset, page, num_rules = RCANFD_CHANNEL_NUMRULES;
|
||||
u32 rule_entry_index = rule_entry % 16;
|
||||
u32 ridx = ch + RCANFD_RFFIFO_IDX;
|
||||
|
||||
if (ch == 0) {
|
||||
start = 0; /* Channel 0 always starts from 0th rule */
|
||||
} else {
|
||||
/* Get number of Channel 0 rules and adjust */
|
||||
cfg = rcar_canfd_read(gpriv->base, RCANFD_GAFLCFG(ch));
|
||||
start = RCANFD_GAFLCFG_GETRNC(gpriv, 0, cfg);
|
||||
}
|
||||
|
||||
/* Enable write access to entry */
|
||||
page = RCANFD_GAFL_PAGENUM(start);
|
||||
page = RCANFD_GAFL_PAGENUM(rule_entry);
|
||||
rcar_canfd_set_bit(gpriv->base, RCANFD_GAFLECTR,
|
||||
(RCANFD_GAFLECTR_AFLPN(gpriv, page) |
|
||||
RCANFD_GAFLECTR_AFLDAE));
|
||||
@@ -818,13 +810,13 @@ static void rcar_canfd_configure_afl_rules(struct rcar_canfd_global *gpriv,
|
||||
offset = RCANFD_C_GAFL_OFFSET;
|
||||
|
||||
/* Accept all IDs */
|
||||
rcar_canfd_write(gpriv->base, RCANFD_GAFLID(offset, start), 0);
|
||||
rcar_canfd_write(gpriv->base, RCANFD_GAFLID(offset, rule_entry_index), 0);
|
||||
/* IDE or RTR is not considered for matching */
|
||||
rcar_canfd_write(gpriv->base, RCANFD_GAFLM(offset, start), 0);
|
||||
rcar_canfd_write(gpriv->base, RCANFD_GAFLM(offset, rule_entry_index), 0);
|
||||
/* Any data length accepted */
|
||||
rcar_canfd_write(gpriv->base, RCANFD_GAFLP0(offset, start), 0);
|
||||
rcar_canfd_write(gpriv->base, RCANFD_GAFLP0(offset, rule_entry_index), 0);
|
||||
/* Place the msg in corresponding Rx FIFO entry */
|
||||
rcar_canfd_set_bit(gpriv->base, RCANFD_GAFLP1(offset, start),
|
||||
rcar_canfd_set_bit(gpriv->base, RCANFD_GAFLP1(offset, rule_entry_index),
|
||||
RCANFD_GAFLP1_GAFLFDP(ridx));
|
||||
|
||||
/* Disable write access to page */
|
||||
@@ -1851,6 +1843,7 @@ static int rcar_canfd_probe(struct platform_device *pdev)
|
||||
unsigned long channels_mask = 0;
|
||||
int err, ch_irq, g_irq;
|
||||
int g_err_irq, g_recc_irq;
|
||||
u32 rule_entry = 0;
|
||||
bool fdmode = true; /* CAN FD only mode - default */
|
||||
char name[9] = "channelX";
|
||||
int i;
|
||||
@@ -2023,7 +2016,8 @@ static int rcar_canfd_probe(struct platform_device *pdev)
|
||||
rcar_canfd_configure_tx(gpriv, ch);
|
||||
|
||||
/* Configure receive rules */
|
||||
rcar_canfd_configure_afl_rules(gpriv, ch);
|
||||
rcar_canfd_configure_afl_rules(gpriv, ch, rule_entry);
|
||||
rule_entry += RCANFD_CHANNEL_NUMRULES;
|
||||
}
|
||||
|
||||
/* Configure common interrupts */
|
||||
|
||||
@@ -186,7 +186,7 @@ union ucan_ctl_payload {
|
||||
*/
|
||||
struct ucan_ctl_cmd_get_protocol_version cmd_get_protocol_version;
|
||||
|
||||
u8 raw[128];
|
||||
u8 fw_str[128];
|
||||
} __packed;
|
||||
|
||||
enum {
|
||||
@@ -424,18 +424,20 @@ static int ucan_ctrl_command_out(struct ucan_priv *up,
|
||||
UCAN_USB_CTL_PIPE_TIMEOUT);
|
||||
}
|
||||
|
||||
static int ucan_device_request_in(struct ucan_priv *up,
|
||||
u8 cmd, u16 subcmd, u16 datalen)
|
||||
static void ucan_get_fw_str(struct ucan_priv *up, char *fw_str, size_t size)
|
||||
{
|
||||
return usb_control_msg(up->udev,
|
||||
usb_rcvctrlpipe(up->udev, 0),
|
||||
cmd,
|
||||
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
|
||||
subcmd,
|
||||
0,
|
||||
up->ctl_msg_buffer,
|
||||
datalen,
|
||||
UCAN_USB_CTL_PIPE_TIMEOUT);
|
||||
int ret;
|
||||
|
||||
ret = usb_control_msg(up->udev, usb_rcvctrlpipe(up->udev, 0),
|
||||
UCAN_DEVICE_GET_FW_STRING,
|
||||
USB_DIR_IN | USB_TYPE_VENDOR |
|
||||
USB_RECIP_DEVICE,
|
||||
0, 0, fw_str, size - 1,
|
||||
UCAN_USB_CTL_PIPE_TIMEOUT);
|
||||
if (ret > 0)
|
||||
fw_str[ret] = '\0';
|
||||
else
|
||||
strscpy(fw_str, "unknown", size);
|
||||
}
|
||||
|
||||
/* Parse the device information structure reported by the device and
|
||||
@@ -1314,7 +1316,6 @@ static int ucan_probe(struct usb_interface *intf,
|
||||
u8 in_ep_addr;
|
||||
u8 out_ep_addr;
|
||||
union ucan_ctl_payload *ctl_msg_buffer;
|
||||
char firmware_str[sizeof(union ucan_ctl_payload) + 1];
|
||||
|
||||
udev = interface_to_usbdev(intf);
|
||||
|
||||
@@ -1527,17 +1528,6 @@ static int ucan_probe(struct usb_interface *intf,
|
||||
*/
|
||||
ucan_parse_device_info(up, &ctl_msg_buffer->cmd_get_device_info);
|
||||
|
||||
/* just print some device information - if available */
|
||||
ret = ucan_device_request_in(up, UCAN_DEVICE_GET_FW_STRING, 0,
|
||||
sizeof(union ucan_ctl_payload));
|
||||
if (ret > 0) {
|
||||
/* copy string while ensuring zero termination */
|
||||
strscpy(firmware_str, up->ctl_msg_buffer->raw,
|
||||
sizeof(union ucan_ctl_payload) + 1);
|
||||
} else {
|
||||
strcpy(firmware_str, "unknown");
|
||||
}
|
||||
|
||||
/* device is compatible, reset it */
|
||||
ret = ucan_ctrl_command_out(up, UCAN_COMMAND_RESET, 0, 0);
|
||||
if (ret < 0)
|
||||
@@ -1555,7 +1545,10 @@ static int ucan_probe(struct usb_interface *intf,
|
||||
|
||||
/* initialisation complete, log device info */
|
||||
netdev_info(up->netdev, "registered device\n");
|
||||
netdev_info(up->netdev, "firmware string: %s\n", firmware_str);
|
||||
ucan_get_fw_str(up, up->ctl_msg_buffer->fw_str,
|
||||
sizeof(up->ctl_msg_buffer->fw_str));
|
||||
netdev_info(up->netdev, "firmware string: %s\n",
|
||||
up->ctl_msg_buffer->fw_str);
|
||||
|
||||
/* success */
|
||||
return 0;
|
||||
|
||||
@@ -134,9 +134,10 @@ static int mana_gd_detect_devices(struct pci_dev *pdev)
|
||||
struct gdma_list_devices_resp resp = {};
|
||||
struct gdma_general_req req = {};
|
||||
struct gdma_dev_id dev;
|
||||
u32 i, max_num_devs;
|
||||
int found_dev = 0;
|
||||
u16 dev_type;
|
||||
int err;
|
||||
u32 i;
|
||||
|
||||
mana_gd_init_req_hdr(&req.hdr, GDMA_LIST_DEVICES, sizeof(req),
|
||||
sizeof(resp));
|
||||
@@ -148,12 +149,17 @@ static int mana_gd_detect_devices(struct pci_dev *pdev)
|
||||
return err ? err : -EPROTO;
|
||||
}
|
||||
|
||||
max_num_devs = min_t(u32, MAX_NUM_GDMA_DEVICES, resp.num_of_devs);
|
||||
|
||||
for (i = 0; i < max_num_devs; i++) {
|
||||
for (i = 0; i < GDMA_DEV_LIST_SIZE &&
|
||||
found_dev < resp.num_of_devs; i++) {
|
||||
dev = resp.devs[i];
|
||||
dev_type = dev.type;
|
||||
|
||||
/* Skip empty devices */
|
||||
if (dev.as_uint32 == 0)
|
||||
continue;
|
||||
|
||||
found_dev++;
|
||||
|
||||
/* HWC is already detected in mana_hwc_create_channel(). */
|
||||
if (dev_type == GDMA_DEVICE_HWC)
|
||||
continue;
|
||||
|
||||
@@ -46,7 +46,9 @@ static int dwc_eth_dwmac_config_dt(struct platform_device *pdev,
|
||||
u32 a_index = 0;
|
||||
|
||||
if (!plat_dat->axi) {
|
||||
plat_dat->axi = kzalloc(sizeof(struct stmmac_axi), GFP_KERNEL);
|
||||
plat_dat->axi = devm_kzalloc(&pdev->dev,
|
||||
sizeof(struct stmmac_axi),
|
||||
GFP_KERNEL);
|
||||
|
||||
if (!plat_dat->axi)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -2306,14 +2306,18 @@ static void am65_cpsw_nuss_remove_tx_chns(struct am65_cpsw_common *common)
|
||||
static int am65_cpsw_nuss_ndev_add_tx_napi(struct am65_cpsw_common *common)
|
||||
{
|
||||
struct device *dev = common->dev;
|
||||
struct am65_cpsw_tx_chn *tx_chn;
|
||||
int i, ret = 0;
|
||||
|
||||
for (i = 0; i < common->tx_ch_num; i++) {
|
||||
struct am65_cpsw_tx_chn *tx_chn = &common->tx_chns[i];
|
||||
tx_chn = &common->tx_chns[i];
|
||||
|
||||
hrtimer_init(&tx_chn->tx_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED);
|
||||
tx_chn->tx_hrtimer.function = &am65_cpsw_nuss_tx_timer_callback;
|
||||
|
||||
netif_napi_add_tx(common->dma_ndev, &tx_chn->napi_tx,
|
||||
am65_cpsw_nuss_tx_poll);
|
||||
|
||||
ret = devm_request_irq(dev, tx_chn->irq,
|
||||
am65_cpsw_nuss_tx_irq,
|
||||
IRQF_TRIGGER_HIGH,
|
||||
@@ -2323,19 +2327,16 @@ static int am65_cpsw_nuss_ndev_add_tx_napi(struct am65_cpsw_common *common)
|
||||
tx_chn->id, tx_chn->irq, ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
netif_napi_add_tx(common->dma_ndev, &tx_chn->napi_tx,
|
||||
am65_cpsw_nuss_tx_poll);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
for (--i ; i >= 0 ; i--) {
|
||||
struct am65_cpsw_tx_chn *tx_chn = &common->tx_chns[i];
|
||||
|
||||
netif_napi_del(&tx_chn->napi_tx);
|
||||
netif_napi_del(&tx_chn->napi_tx);
|
||||
for (--i; i >= 0; i--) {
|
||||
tx_chn = &common->tx_chns[i];
|
||||
devm_free_irq(dev, tx_chn->irq, tx_chn);
|
||||
netif_napi_del(&tx_chn->napi_tx);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -2569,6 +2570,9 @@ static int am65_cpsw_nuss_init_rx_chns(struct am65_cpsw_common *common)
|
||||
HRTIMER_MODE_REL_PINNED);
|
||||
flow->rx_hrtimer.function = &am65_cpsw_nuss_rx_timer_callback;
|
||||
|
||||
netif_napi_add(common->dma_ndev, &flow->napi_rx,
|
||||
am65_cpsw_nuss_rx_poll);
|
||||
|
||||
ret = devm_request_irq(dev, flow->irq,
|
||||
am65_cpsw_nuss_rx_irq,
|
||||
IRQF_TRIGGER_HIGH,
|
||||
@@ -2577,11 +2581,8 @@ static int am65_cpsw_nuss_init_rx_chns(struct am65_cpsw_common *common)
|
||||
dev_err(dev, "failure requesting rx %d irq %u, %d\n",
|
||||
i, flow->irq, ret);
|
||||
flow->irq = -EINVAL;
|
||||
goto err_flow;
|
||||
goto err_request_irq;
|
||||
}
|
||||
|
||||
netif_napi_add(common->dma_ndev, &flow->napi_rx,
|
||||
am65_cpsw_nuss_rx_poll);
|
||||
}
|
||||
|
||||
/* setup classifier to route priorities to flows */
|
||||
@@ -2589,11 +2590,14 @@ static int am65_cpsw_nuss_init_rx_chns(struct am65_cpsw_common *common)
|
||||
|
||||
return 0;
|
||||
|
||||
err_request_irq:
|
||||
netif_napi_del(&flow->napi_rx);
|
||||
|
||||
err_flow:
|
||||
for (--i; i >= 0 ; i--) {
|
||||
for (--i; i >= 0; i--) {
|
||||
flow = &rx_chn->flows[i];
|
||||
netif_napi_del(&flow->napi_rx);
|
||||
devm_free_irq(dev, flow->irq, flow);
|
||||
netif_napi_del(&flow->napi_rx);
|
||||
}
|
||||
|
||||
err:
|
||||
|
||||
@@ -1679,6 +1679,7 @@ static int prueth_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
spin_lock_init(&prueth->vtbl_lock);
|
||||
spin_lock_init(&prueth->stats_lock);
|
||||
/* setup netdev interfaces */
|
||||
if (eth0_node) {
|
||||
ret = prueth_netdev_init(prueth, eth0_node);
|
||||
|
||||
@@ -305,6 +305,8 @@ struct prueth {
|
||||
int default_vlan;
|
||||
/** @vtbl_lock: Lock for vtbl in shared memory */
|
||||
spinlock_t vtbl_lock;
|
||||
/** @stats_lock: Lock for reading icssg stats */
|
||||
spinlock_t stats_lock;
|
||||
};
|
||||
|
||||
struct emac_tx_ts_response {
|
||||
|
||||
@@ -26,6 +26,8 @@ void emac_update_hardware_stats(struct prueth_emac *emac)
|
||||
u32 val, reg;
|
||||
int i;
|
||||
|
||||
spin_lock(&prueth->stats_lock);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(icssg_all_miig_stats); i++) {
|
||||
regmap_read(prueth->miig_rt,
|
||||
base + icssg_all_miig_stats[i].offset,
|
||||
@@ -51,6 +53,8 @@ void emac_update_hardware_stats(struct prueth_emac *emac)
|
||||
emac->pa_stats[i] += val;
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock(&prueth->stats_lock);
|
||||
}
|
||||
|
||||
void icssg_stats_work_handler(struct work_struct *work)
|
||||
|
||||
@@ -73,7 +73,7 @@ int phy_link_topo_add_phy(struct net_device *dev,
|
||||
xa_limit_32b, &topo->next_phy_index,
|
||||
GFP_KERNEL);
|
||||
|
||||
if (ret)
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -683,7 +683,7 @@ enum {
|
||||
#define HCI_ERROR_REMOTE_POWER_OFF 0x15
|
||||
#define HCI_ERROR_LOCAL_HOST_TERM 0x16
|
||||
#define HCI_ERROR_PAIRING_NOT_ALLOWED 0x18
|
||||
#define HCI_ERROR_UNSUPPORTED_REMOTE_FEATURE 0x1e
|
||||
#define HCI_ERROR_UNSUPPORTED_REMOTE_FEATURE 0x1a
|
||||
#define HCI_ERROR_INVALID_LL_PARAMS 0x1e
|
||||
#define HCI_ERROR_UNSPECIFIED 0x1f
|
||||
#define HCI_ERROR_ADVERTISING_TIMEOUT 0x3c
|
||||
|
||||
@@ -408,8 +408,6 @@ struct gdma_context {
|
||||
struct gdma_dev mana_ib;
|
||||
};
|
||||
|
||||
#define MAX_NUM_GDMA_DEVICES 4
|
||||
|
||||
static inline bool mana_gd_is_mana(struct gdma_dev *gd)
|
||||
{
|
||||
return gd->dev_id.type == GDMA_DEVICE_MANA;
|
||||
@@ -556,11 +554,15 @@ enum {
|
||||
#define GDMA_DRV_CAP_FLAG_1_HWC_TIMEOUT_RECONFIG BIT(3)
|
||||
#define GDMA_DRV_CAP_FLAG_1_VARIABLE_INDIRECTION_TABLE_SUPPORT BIT(5)
|
||||
|
||||
/* Driver can handle holes (zeros) in the device list */
|
||||
#define GDMA_DRV_CAP_FLAG_1_DEV_LIST_HOLES_SUP BIT(11)
|
||||
|
||||
#define GDMA_DRV_CAP_FLAGS1 \
|
||||
(GDMA_DRV_CAP_FLAG_1_EQ_SHARING_MULTI_VPORT | \
|
||||
GDMA_DRV_CAP_FLAG_1_NAPI_WKDONE_FIX | \
|
||||
GDMA_DRV_CAP_FLAG_1_HWC_TIMEOUT_RECONFIG | \
|
||||
GDMA_DRV_CAP_FLAG_1_VARIABLE_INDIRECTION_TABLE_SUPPORT)
|
||||
GDMA_DRV_CAP_FLAG_1_VARIABLE_INDIRECTION_TABLE_SUPPORT | \
|
||||
GDMA_DRV_CAP_FLAG_1_DEV_LIST_HOLES_SUP)
|
||||
|
||||
#define GDMA_DRV_CAP_FLAGS2 0
|
||||
|
||||
@@ -621,11 +623,12 @@ struct gdma_query_max_resources_resp {
|
||||
}; /* HW DATA */
|
||||
|
||||
/* GDMA_LIST_DEVICES */
|
||||
#define GDMA_DEV_LIST_SIZE 64
|
||||
struct gdma_list_devices_resp {
|
||||
struct gdma_resp_hdr hdr;
|
||||
u32 num_of_devs;
|
||||
u32 reserved;
|
||||
struct gdma_dev_id devs[64];
|
||||
struct gdma_dev_id devs[GDMA_DEV_LIST_SIZE];
|
||||
}; /* HW DATA */
|
||||
|
||||
/* GDMA_REGISTER_DEVICE */
|
||||
|
||||
@@ -181,6 +181,7 @@ static void
|
||||
lec_send(struct atm_vcc *vcc, struct sk_buff *skb)
|
||||
{
|
||||
struct net_device *dev = skb->dev;
|
||||
unsigned int len = skb->len;
|
||||
|
||||
ATM_SKB(skb)->vcc = vcc;
|
||||
atm_account_tx(vcc, skb);
|
||||
@@ -191,7 +192,7 @@ lec_send(struct atm_vcc *vcc, struct sk_buff *skb)
|
||||
}
|
||||
|
||||
dev->stats.tx_packets++;
|
||||
dev->stats.tx_bytes += skb->len;
|
||||
dev->stats.tx_bytes += len;
|
||||
}
|
||||
|
||||
static void lec_tx_timeout(struct net_device *dev, unsigned int txqueue)
|
||||
|
||||
@@ -325,8 +325,7 @@ batadv_iv_ogm_aggr_packet(int buff_pos, int packet_len,
|
||||
/* check if there is enough space for the optional TVLV */
|
||||
next_buff_pos += ntohs(ogm_packet->tvlv_len);
|
||||
|
||||
return (next_buff_pos <= packet_len) &&
|
||||
(next_buff_pos <= BATADV_MAX_AGGREGATION_BYTES);
|
||||
return next_buff_pos <= packet_len;
|
||||
}
|
||||
|
||||
/* send a batman ogm to a given interface */
|
||||
|
||||
@@ -839,8 +839,7 @@ batadv_v_ogm_aggr_packet(int buff_pos, int packet_len,
|
||||
/* check if there is enough space for the optional TVLV */
|
||||
next_buff_pos += ntohs(ogm2_packet->tvlv_len);
|
||||
|
||||
return (next_buff_pos <= packet_len) &&
|
||||
(next_buff_pos <= BATADV_MAX_AGGREGATION_BYTES);
|
||||
return next_buff_pos <= packet_len;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -825,11 +825,16 @@ static struct sk_buff *chan_alloc_skb_cb(struct l2cap_chan *chan,
|
||||
unsigned long hdr_len,
|
||||
unsigned long len, int nb)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
/* Note that we must allocate using GFP_ATOMIC here as
|
||||
* this function is called originally from netdev hard xmit
|
||||
* function in atomic context.
|
||||
*/
|
||||
return bt_skb_alloc(hdr_len + len, GFP_ATOMIC);
|
||||
skb = bt_skb_alloc(hdr_len + len, GFP_ATOMIC);
|
||||
if (!skb)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
return skb;
|
||||
}
|
||||
|
||||
static void chan_suspend_cb(struct l2cap_chan *chan)
|
||||
|
||||
@@ -287,8 +287,8 @@ int can_send(struct sk_buff *skb, int loop)
|
||||
netif_rx(newskb);
|
||||
|
||||
/* update statistics */
|
||||
pkg_stats->tx_frames++;
|
||||
pkg_stats->tx_frames_delta++;
|
||||
atomic_long_inc(&pkg_stats->tx_frames);
|
||||
atomic_long_inc(&pkg_stats->tx_frames_delta);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -647,8 +647,8 @@ static void can_receive(struct sk_buff *skb, struct net_device *dev)
|
||||
int matches;
|
||||
|
||||
/* update statistics */
|
||||
pkg_stats->rx_frames++;
|
||||
pkg_stats->rx_frames_delta++;
|
||||
atomic_long_inc(&pkg_stats->rx_frames);
|
||||
atomic_long_inc(&pkg_stats->rx_frames_delta);
|
||||
|
||||
/* create non-zero unique skb identifier together with *skb */
|
||||
while (!(can_skb_prv(skb)->skbcnt))
|
||||
@@ -669,8 +669,8 @@ static void can_receive(struct sk_buff *skb, struct net_device *dev)
|
||||
consume_skb(skb);
|
||||
|
||||
if (matches > 0) {
|
||||
pkg_stats->matches++;
|
||||
pkg_stats->matches_delta++;
|
||||
atomic_long_inc(&pkg_stats->matches);
|
||||
atomic_long_inc(&pkg_stats->matches_delta);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -66,9 +66,9 @@ struct receiver {
|
||||
struct can_pkg_stats {
|
||||
unsigned long jiffies_init;
|
||||
|
||||
unsigned long rx_frames;
|
||||
unsigned long tx_frames;
|
||||
unsigned long matches;
|
||||
atomic_long_t rx_frames;
|
||||
atomic_long_t tx_frames;
|
||||
atomic_long_t matches;
|
||||
|
||||
unsigned long total_rx_rate;
|
||||
unsigned long total_tx_rate;
|
||||
@@ -82,9 +82,9 @@ struct can_pkg_stats {
|
||||
unsigned long max_tx_rate;
|
||||
unsigned long max_rx_match_ratio;
|
||||
|
||||
unsigned long rx_frames_delta;
|
||||
unsigned long tx_frames_delta;
|
||||
unsigned long matches_delta;
|
||||
atomic_long_t rx_frames_delta;
|
||||
atomic_long_t tx_frames_delta;
|
||||
atomic_long_t matches_delta;
|
||||
};
|
||||
|
||||
/* persistent statistics */
|
||||
|
||||
@@ -118,6 +118,13 @@ void can_stat_update(struct timer_list *t)
|
||||
struct can_pkg_stats *pkg_stats = net->can.pkg_stats;
|
||||
unsigned long j = jiffies; /* snapshot */
|
||||
|
||||
long rx_frames = atomic_long_read(&pkg_stats->rx_frames);
|
||||
long tx_frames = atomic_long_read(&pkg_stats->tx_frames);
|
||||
long matches = atomic_long_read(&pkg_stats->matches);
|
||||
long rx_frames_delta = atomic_long_read(&pkg_stats->rx_frames_delta);
|
||||
long tx_frames_delta = atomic_long_read(&pkg_stats->tx_frames_delta);
|
||||
long matches_delta = atomic_long_read(&pkg_stats->matches_delta);
|
||||
|
||||
/* restart counting in timer context on user request */
|
||||
if (user_reset)
|
||||
can_init_stats(net);
|
||||
@@ -127,35 +134,33 @@ void can_stat_update(struct timer_list *t)
|
||||
can_init_stats(net);
|
||||
|
||||
/* prevent overflow in calc_rate() */
|
||||
if (pkg_stats->rx_frames > (ULONG_MAX / HZ))
|
||||
if (rx_frames > (LONG_MAX / HZ))
|
||||
can_init_stats(net);
|
||||
|
||||
/* prevent overflow in calc_rate() */
|
||||
if (pkg_stats->tx_frames > (ULONG_MAX / HZ))
|
||||
if (tx_frames > (LONG_MAX / HZ))
|
||||
can_init_stats(net);
|
||||
|
||||
/* matches overflow - very improbable */
|
||||
if (pkg_stats->matches > (ULONG_MAX / 100))
|
||||
if (matches > (LONG_MAX / 100))
|
||||
can_init_stats(net);
|
||||
|
||||
/* calc total values */
|
||||
if (pkg_stats->rx_frames)
|
||||
pkg_stats->total_rx_match_ratio = (pkg_stats->matches * 100) /
|
||||
pkg_stats->rx_frames;
|
||||
if (rx_frames)
|
||||
pkg_stats->total_rx_match_ratio = (matches * 100) / rx_frames;
|
||||
|
||||
pkg_stats->total_tx_rate = calc_rate(pkg_stats->jiffies_init, j,
|
||||
pkg_stats->tx_frames);
|
||||
tx_frames);
|
||||
pkg_stats->total_rx_rate = calc_rate(pkg_stats->jiffies_init, j,
|
||||
pkg_stats->rx_frames);
|
||||
rx_frames);
|
||||
|
||||
/* calc current values */
|
||||
if (pkg_stats->rx_frames_delta)
|
||||
if (rx_frames_delta)
|
||||
pkg_stats->current_rx_match_ratio =
|
||||
(pkg_stats->matches_delta * 100) /
|
||||
pkg_stats->rx_frames_delta;
|
||||
(matches_delta * 100) / rx_frames_delta;
|
||||
|
||||
pkg_stats->current_tx_rate = calc_rate(0, HZ, pkg_stats->tx_frames_delta);
|
||||
pkg_stats->current_rx_rate = calc_rate(0, HZ, pkg_stats->rx_frames_delta);
|
||||
pkg_stats->current_tx_rate = calc_rate(0, HZ, tx_frames_delta);
|
||||
pkg_stats->current_rx_rate = calc_rate(0, HZ, rx_frames_delta);
|
||||
|
||||
/* check / update maximum values */
|
||||
if (pkg_stats->max_tx_rate < pkg_stats->current_tx_rate)
|
||||
@@ -168,9 +173,9 @@ void can_stat_update(struct timer_list *t)
|
||||
pkg_stats->max_rx_match_ratio = pkg_stats->current_rx_match_ratio;
|
||||
|
||||
/* clear values for 'current rate' calculation */
|
||||
pkg_stats->tx_frames_delta = 0;
|
||||
pkg_stats->rx_frames_delta = 0;
|
||||
pkg_stats->matches_delta = 0;
|
||||
atomic_long_set(&pkg_stats->tx_frames_delta, 0);
|
||||
atomic_long_set(&pkg_stats->rx_frames_delta, 0);
|
||||
atomic_long_set(&pkg_stats->matches_delta, 0);
|
||||
|
||||
/* restart timer (one second) */
|
||||
mod_timer(&net->can.stattimer, round_jiffies(jiffies + HZ));
|
||||
@@ -214,9 +219,12 @@ static int can_stats_proc_show(struct seq_file *m, void *v)
|
||||
struct can_rcv_lists_stats *rcv_lists_stats = net->can.rcv_lists_stats;
|
||||
|
||||
seq_putc(m, '\n');
|
||||
seq_printf(m, " %8ld transmitted frames (TXF)\n", pkg_stats->tx_frames);
|
||||
seq_printf(m, " %8ld received frames (RXF)\n", pkg_stats->rx_frames);
|
||||
seq_printf(m, " %8ld matched frames (RXMF)\n", pkg_stats->matches);
|
||||
seq_printf(m, " %8ld transmitted frames (TXF)\n",
|
||||
atomic_long_read(&pkg_stats->tx_frames));
|
||||
seq_printf(m, " %8ld received frames (RXF)\n",
|
||||
atomic_long_read(&pkg_stats->rx_frames));
|
||||
seq_printf(m, " %8ld matched frames (RXMF)\n",
|
||||
atomic_long_read(&pkg_stats->matches));
|
||||
|
||||
seq_putc(m, '\n');
|
||||
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
#include <net/ip6_fib.h>
|
||||
#include <net/rtnh.h>
|
||||
|
||||
#include "dev.h"
|
||||
|
||||
DEFINE_STATIC_KEY_FALSE(nf_hooks_lwtunnel_enabled);
|
||||
EXPORT_SYMBOL_GPL(nf_hooks_lwtunnel_enabled);
|
||||
|
||||
@@ -325,13 +327,23 @@ EXPORT_SYMBOL_GPL(lwtunnel_cmp_encap);
|
||||
|
||||
int lwtunnel_output(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
struct dst_entry *dst = skb_dst(skb);
|
||||
const struct lwtunnel_encap_ops *ops;
|
||||
struct lwtunnel_state *lwtstate;
|
||||
int ret = -EINVAL;
|
||||
struct dst_entry *dst;
|
||||
int ret;
|
||||
|
||||
if (!dst)
|
||||
if (dev_xmit_recursion()) {
|
||||
net_crit_ratelimited("%s(): recursion limit reached on datapath\n",
|
||||
__func__);
|
||||
ret = -ENETDOWN;
|
||||
goto drop;
|
||||
}
|
||||
|
||||
dst = skb_dst(skb);
|
||||
if (!dst) {
|
||||
ret = -EINVAL;
|
||||
goto drop;
|
||||
}
|
||||
lwtstate = dst->lwtstate;
|
||||
|
||||
if (lwtstate->type == LWTUNNEL_ENCAP_NONE ||
|
||||
@@ -341,8 +353,11 @@ int lwtunnel_output(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
ret = -EOPNOTSUPP;
|
||||
rcu_read_lock();
|
||||
ops = rcu_dereference(lwtun_encaps[lwtstate->type]);
|
||||
if (likely(ops && ops->output))
|
||||
if (likely(ops && ops->output)) {
|
||||
dev_xmit_recursion_inc();
|
||||
ret = ops->output(net, sk, skb);
|
||||
dev_xmit_recursion_dec();
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
if (ret == -EOPNOTSUPP)
|
||||
@@ -359,13 +374,23 @@ EXPORT_SYMBOL_GPL(lwtunnel_output);
|
||||
|
||||
int lwtunnel_xmit(struct sk_buff *skb)
|
||||
{
|
||||
struct dst_entry *dst = skb_dst(skb);
|
||||
const struct lwtunnel_encap_ops *ops;
|
||||
struct lwtunnel_state *lwtstate;
|
||||
int ret = -EINVAL;
|
||||
struct dst_entry *dst;
|
||||
int ret;
|
||||
|
||||
if (!dst)
|
||||
if (dev_xmit_recursion()) {
|
||||
net_crit_ratelimited("%s(): recursion limit reached on datapath\n",
|
||||
__func__);
|
||||
ret = -ENETDOWN;
|
||||
goto drop;
|
||||
}
|
||||
|
||||
dst = skb_dst(skb);
|
||||
if (!dst) {
|
||||
ret = -EINVAL;
|
||||
goto drop;
|
||||
}
|
||||
|
||||
lwtstate = dst->lwtstate;
|
||||
|
||||
@@ -376,8 +401,11 @@ int lwtunnel_xmit(struct sk_buff *skb)
|
||||
ret = -EOPNOTSUPP;
|
||||
rcu_read_lock();
|
||||
ops = rcu_dereference(lwtun_encaps[lwtstate->type]);
|
||||
if (likely(ops && ops->xmit))
|
||||
if (likely(ops && ops->xmit)) {
|
||||
dev_xmit_recursion_inc();
|
||||
ret = ops->xmit(skb);
|
||||
dev_xmit_recursion_dec();
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
if (ret == -EOPNOTSUPP)
|
||||
@@ -394,13 +422,23 @@ EXPORT_SYMBOL_GPL(lwtunnel_xmit);
|
||||
|
||||
int lwtunnel_input(struct sk_buff *skb)
|
||||
{
|
||||
struct dst_entry *dst = skb_dst(skb);
|
||||
const struct lwtunnel_encap_ops *ops;
|
||||
struct lwtunnel_state *lwtstate;
|
||||
int ret = -EINVAL;
|
||||
struct dst_entry *dst;
|
||||
int ret;
|
||||
|
||||
if (!dst)
|
||||
if (dev_xmit_recursion()) {
|
||||
net_crit_ratelimited("%s(): recursion limit reached on datapath\n",
|
||||
__func__);
|
||||
ret = -ENETDOWN;
|
||||
goto drop;
|
||||
}
|
||||
|
||||
dst = skb_dst(skb);
|
||||
if (!dst) {
|
||||
ret = -EINVAL;
|
||||
goto drop;
|
||||
}
|
||||
lwtstate = dst->lwtstate;
|
||||
|
||||
if (lwtstate->type == LWTUNNEL_ENCAP_NONE ||
|
||||
@@ -410,8 +448,11 @@ int lwtunnel_input(struct sk_buff *skb)
|
||||
ret = -EOPNOTSUPP;
|
||||
rcu_read_lock();
|
||||
ops = rcu_dereference(lwtun_encaps[lwtstate->type]);
|
||||
if (likely(ops && ops->input))
|
||||
if (likely(ops && ops->input)) {
|
||||
dev_xmit_recursion_inc();
|
||||
ret = ops->input(skb);
|
||||
dev_xmit_recursion_dec();
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
if (ret == -EOPNOTSUPP)
|
||||
|
||||
@@ -2250,6 +2250,7 @@ static const struct nla_policy nl_neightbl_policy[NDTA_MAX+1] = {
|
||||
static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = {
|
||||
[NDTPA_IFINDEX] = { .type = NLA_U32 },
|
||||
[NDTPA_QUEUE_LEN] = { .type = NLA_U32 },
|
||||
[NDTPA_QUEUE_LENBYTES] = { .type = NLA_U32 },
|
||||
[NDTPA_PROXY_QLEN] = { .type = NLA_U32 },
|
||||
[NDTPA_APP_PROBES] = { .type = NLA_U32 },
|
||||
[NDTPA_UCAST_PROBES] = { .type = NLA_U32 },
|
||||
|
||||
@@ -117,7 +117,7 @@ static struct devlink_rel *devlink_rel_alloc(void)
|
||||
|
||||
err = xa_alloc_cyclic(&devlink_rels, &rel->index, rel,
|
||||
xa_limit_32b, &next, GFP_KERNEL);
|
||||
if (err) {
|
||||
if (err < 0) {
|
||||
kfree(rel);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
@@ -3209,13 +3209,16 @@ static void add_v4_addrs(struct inet6_dev *idev)
|
||||
struct in6_addr addr;
|
||||
struct net_device *dev;
|
||||
struct net *net = dev_net(idev->dev);
|
||||
int scope, plen;
|
||||
int scope, plen, offset = 0;
|
||||
u32 pflags = 0;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
memset(&addr, 0, sizeof(struct in6_addr));
|
||||
memcpy(&addr.s6_addr32[3], idev->dev->dev_addr, 4);
|
||||
/* in case of IP6GRE the dev_addr is an IPv6 and therefore we use only the last 4 bytes */
|
||||
if (idev->dev->addr_len == sizeof(struct in6_addr))
|
||||
offset = sizeof(struct in6_addr) - 4;
|
||||
memcpy(&addr.s6_addr32[3], idev->dev->dev_addr + offset, 4);
|
||||
|
||||
if (!(idev->dev->flags & IFF_POINTOPOINT) && idev->dev->type == ARPHRD_SIT) {
|
||||
scope = IPV6_ADDR_COMPATv4;
|
||||
@@ -3526,13 +3529,7 @@ static void addrconf_gre_config(struct net_device *dev)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Generate the IPv6 link-local address using addrconf_addr_gen(),
|
||||
* unless we have an IPv4 GRE device not bound to an IP address and
|
||||
* which is in EUI64 mode (as __ipv6_isatap_ifid() would fail in this
|
||||
* case). Such devices fall back to add_v4_addrs() instead.
|
||||
*/
|
||||
if (!(dev->type == ARPHRD_IPGRE && *(__be32 *)dev->dev_addr == 0 &&
|
||||
idev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_EUI64)) {
|
||||
if (dev->type == ARPHRD_ETHER) {
|
||||
addrconf_addr_gen(idev, true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -337,7 +337,6 @@ static int ioam6_do_encap(struct net *net, struct sk_buff *skb,
|
||||
static int ioam6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
struct dst_entry *dst = skb_dst(skb), *cache_dst = NULL;
|
||||
struct in6_addr orig_daddr;
|
||||
struct ioam6_lwt *ilwt;
|
||||
int err = -EINVAL;
|
||||
u32 pkt_cnt;
|
||||
@@ -352,8 +351,6 @@ static int ioam6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
if (pkt_cnt % ilwt->freq.n >= ilwt->freq.k)
|
||||
goto out;
|
||||
|
||||
orig_daddr = ipv6_hdr(skb)->daddr;
|
||||
|
||||
local_bh_disable();
|
||||
cache_dst = dst_cache_get(&ilwt->cache);
|
||||
local_bh_enable();
|
||||
@@ -422,7 +419,10 @@ do_encap:
|
||||
goto drop;
|
||||
}
|
||||
|
||||
if (!ipv6_addr_equal(&orig_daddr, &ipv6_hdr(skb)->daddr)) {
|
||||
/* avoid lwtunnel_output() reentry loop when destination is the same
|
||||
* after transformation (e.g., with the inline mode)
|
||||
*/
|
||||
if (dst->lwtstate != cache_dst->lwtstate) {
|
||||
skb_dst_drop(skb);
|
||||
skb_dst_set(skb, cache_dst);
|
||||
return dst_output(net, sk, skb);
|
||||
|
||||
@@ -3644,7 +3644,8 @@ out:
|
||||
in6_dev_put(idev);
|
||||
|
||||
if (err) {
|
||||
lwtstate_put(fib6_nh->fib_nh_lws);
|
||||
fib_nh_common_release(&fib6_nh->nh_common);
|
||||
fib6_nh->nh_common.nhc_pcpu_rth_output = NULL;
|
||||
fib6_nh->fib_nh_lws = NULL;
|
||||
netdev_put(dev, dev_tracker);
|
||||
}
|
||||
@@ -3802,10 +3803,12 @@ static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg,
|
||||
if (nh) {
|
||||
if (rt->fib6_src.plen) {
|
||||
NL_SET_ERR_MSG(extack, "Nexthops can not be used with source routing");
|
||||
err = -EINVAL;
|
||||
goto out_free;
|
||||
}
|
||||
if (!nexthop_get(nh)) {
|
||||
NL_SET_ERR_MSG(extack, "Nexthop has been deleted");
|
||||
err = -ENOENT;
|
||||
goto out_free;
|
||||
}
|
||||
rt->nh = nh;
|
||||
|
||||
@@ -94,14 +94,23 @@ INDIRECT_CALLABLE_SCOPE int tcp6_gro_complete(struct sk_buff *skb, int thoff)
|
||||
}
|
||||
|
||||
static void __tcpv6_gso_segment_csum(struct sk_buff *seg,
|
||||
struct in6_addr *oldip,
|
||||
const struct in6_addr *newip,
|
||||
__be16 *oldport, __be16 newport)
|
||||
{
|
||||
struct tcphdr *th;
|
||||
struct tcphdr *th = tcp_hdr(seg);
|
||||
|
||||
if (!ipv6_addr_equal(oldip, newip)) {
|
||||
inet_proto_csum_replace16(&th->check, seg,
|
||||
oldip->s6_addr32,
|
||||
newip->s6_addr32,
|
||||
true);
|
||||
*oldip = *newip;
|
||||
}
|
||||
|
||||
if (*oldport == newport)
|
||||
return;
|
||||
|
||||
th = tcp_hdr(seg);
|
||||
inet_proto_csum_replace2(&th->check, seg, *oldport, newport, false);
|
||||
*oldport = newport;
|
||||
}
|
||||
@@ -129,10 +138,10 @@ static struct sk_buff *__tcpv6_gso_segment_list_csum(struct sk_buff *segs)
|
||||
th2 = tcp_hdr(seg);
|
||||
iph2 = ipv6_hdr(seg);
|
||||
|
||||
iph2->saddr = iph->saddr;
|
||||
iph2->daddr = iph->daddr;
|
||||
__tcpv6_gso_segment_csum(seg, &th2->source, th->source);
|
||||
__tcpv6_gso_segment_csum(seg, &th2->dest, th->dest);
|
||||
__tcpv6_gso_segment_csum(seg, &iph2->saddr, &iph->saddr,
|
||||
&th2->source, th->source);
|
||||
__tcpv6_gso_segment_csum(seg, &iph2->daddr, &iph->daddr,
|
||||
&th2->dest, th->dest);
|
||||
}
|
||||
|
||||
return segs;
|
||||
|
||||
@@ -651,6 +651,7 @@ static bool mptcp_established_options_add_addr(struct sock *sk, struct sk_buff *
|
||||
struct mptcp_sock *msk = mptcp_sk(subflow->conn);
|
||||
bool drop_other_suboptions = false;
|
||||
unsigned int opt_size = *size;
|
||||
struct mptcp_addr_info addr;
|
||||
bool echo;
|
||||
int len;
|
||||
|
||||
@@ -659,7 +660,7 @@ static bool mptcp_established_options_add_addr(struct sock *sk, struct sk_buff *
|
||||
*/
|
||||
if (!mptcp_pm_should_add_signal(msk) ||
|
||||
(opts->suboptions & (OPTION_MPTCP_MPJ_ACK | OPTION_MPTCP_MPC_ACK)) ||
|
||||
!mptcp_pm_add_addr_signal(msk, skb, opt_size, remaining, &opts->addr,
|
||||
!mptcp_pm_add_addr_signal(msk, skb, opt_size, remaining, &addr,
|
||||
&echo, &drop_other_suboptions))
|
||||
return false;
|
||||
|
||||
@@ -672,7 +673,7 @@ static bool mptcp_established_options_add_addr(struct sock *sk, struct sk_buff *
|
||||
else if (opts->suboptions & OPTION_MPTCP_DSS)
|
||||
return false;
|
||||
|
||||
len = mptcp_add_addr_len(opts->addr.family, echo, !!opts->addr.port);
|
||||
len = mptcp_add_addr_len(addr.family, echo, !!addr.port);
|
||||
if (remaining < len)
|
||||
return false;
|
||||
|
||||
@@ -689,6 +690,7 @@ static bool mptcp_established_options_add_addr(struct sock *sk, struct sk_buff *
|
||||
opts->ahmac = 0;
|
||||
*size -= opt_size;
|
||||
}
|
||||
opts->addr = addr;
|
||||
opts->suboptions |= OPTION_MPTCP_ADD_ADDR;
|
||||
if (!echo) {
|
||||
MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_ADDADDRTX);
|
||||
|
||||
@@ -105,7 +105,7 @@ struct xsk_buff_pool *xp_create_and_assign_umem(struct xdp_sock *xs,
|
||||
if (pool->unaligned)
|
||||
pool->free_heads[i] = xskb;
|
||||
else
|
||||
xp_init_xskb_addr(xskb, pool, i * pool->chunk_size);
|
||||
xp_init_xskb_addr(xskb, pool, (u64)i * pool->chunk_size);
|
||||
}
|
||||
|
||||
return pool;
|
||||
|
||||
@@ -612,6 +612,40 @@ out:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xfrm_output_resume);
|
||||
|
||||
static int xfrm_dev_direct_output(struct sock *sk, struct xfrm_state *x,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct dst_entry *dst = skb_dst(skb);
|
||||
struct net *net = xs_net(x);
|
||||
int err;
|
||||
|
||||
dst = skb_dst_pop(skb);
|
||||
if (!dst) {
|
||||
XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR);
|
||||
kfree_skb(skb);
|
||||
return -EHOSTUNREACH;
|
||||
}
|
||||
skb_dst_set(skb, dst);
|
||||
nf_reset_ct(skb);
|
||||
|
||||
err = skb_dst(skb)->ops->local_out(net, sk, skb);
|
||||
if (unlikely(err != 1)) {
|
||||
kfree_skb(skb);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* In transport mode, network destination is
|
||||
* directly reachable, while in tunnel mode,
|
||||
* inner packet network may not be. In packet
|
||||
* offload type, HW is responsible for hard
|
||||
* header packet mangling so directly xmit skb
|
||||
* to netdevice.
|
||||
*/
|
||||
skb->dev = x->xso.dev;
|
||||
__skb_push(skb, skb->dev->hard_header_len);
|
||||
return dev_queue_xmit(skb);
|
||||
}
|
||||
|
||||
static int xfrm_output2(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
return xfrm_output_resume(sk, skb, 1);
|
||||
@@ -735,6 +769,13 @@ int xfrm_output(struct sock *sk, struct sk_buff *skb)
|
||||
return -EHOSTUNREACH;
|
||||
}
|
||||
|
||||
/* Exclusive direct xmit for tunnel mode, as
|
||||
* some filtering or matching rules may apply
|
||||
* in transport mode.
|
||||
*/
|
||||
if (x->props.mode == XFRM_MODE_TUNNEL)
|
||||
return xfrm_dev_direct_output(sk, x, skb);
|
||||
|
||||
return xfrm_output_resume(sk, skb, 0);
|
||||
}
|
||||
|
||||
@@ -758,7 +799,7 @@ int xfrm_output(struct sock *sk, struct sk_buff *skb)
|
||||
skb->encapsulation = 1;
|
||||
|
||||
if (skb_is_gso(skb)) {
|
||||
if (skb->inner_protocol)
|
||||
if (skb->inner_protocol && x->props.mode == XFRM_MODE_TUNNEL)
|
||||
return xfrm_output_gso(net, sk, skb);
|
||||
|
||||
skb_shinfo(skb)->gso_type |= SKB_GSO_ESP;
|
||||
|
||||
@@ -119,14 +119,31 @@
|
||||
|
||||
#define SO_DETACH_REUSEPORT_BPF 68
|
||||
|
||||
#define SO_PREFER_BUSY_POLL 69
|
||||
#define SO_BUSY_POLL_BUDGET 70
|
||||
|
||||
#define SO_NETNS_COOKIE 71
|
||||
|
||||
#define SO_BUF_LOCK 72
|
||||
|
||||
#define SO_RESERVE_MEM 73
|
||||
|
||||
#define SO_TXREHASH 74
|
||||
|
||||
#define SO_RCVMARK 75
|
||||
|
||||
#define SO_PASSPIDFD 76
|
||||
#define SO_PEERPIDFD 77
|
||||
|
||||
#define SCM_TS_OPT_ID 78
|
||||
#define SO_DEVMEM_LINEAR 78
|
||||
#define SCM_DEVMEM_LINEAR SO_DEVMEM_LINEAR
|
||||
#define SO_DEVMEM_DMABUF 79
|
||||
#define SCM_DEVMEM_DMABUF SO_DEVMEM_DMABUF
|
||||
#define SO_DEVMEM_DONTNEED 80
|
||||
|
||||
#define SO_RCVPRIORITY 79
|
||||
#define SCM_TS_OPT_ID 81
|
||||
|
||||
#define SO_RCVPRIORITY 82
|
||||
|
||||
#if !defined(__KERNEL__)
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ from lib.py import ksft_run, ksft_exit
|
||||
from lib.py import ksft_eq, KsftSkipEx, KsftFailEx
|
||||
from lib.py import EthtoolFamily, NetDrvEpEnv
|
||||
from lib.py import bkg, cmd, wait_port_listen, rand_port
|
||||
from lib.py import ethtool, ip
|
||||
from lib.py import defer, ethtool, ip
|
||||
|
||||
remote_ifname=""
|
||||
no_sleep=False
|
||||
@@ -60,6 +60,7 @@ def _set_xdp_generic_sb_on(cfg) -> None:
|
||||
prog = test_dir + "/../../net/lib/xdp_dummy.bpf.o"
|
||||
cmd(f"ip link set dev {remote_ifname} mtu 1500", shell=True, host=cfg.remote)
|
||||
cmd(f"ip link set dev {cfg.ifname} mtu 1500 xdpgeneric obj {prog} sec xdp", shell=True)
|
||||
defer(cmd, f"ip link set dev {cfg.ifname} xdpgeneric off")
|
||||
|
||||
if no_sleep != True:
|
||||
time.sleep(10)
|
||||
@@ -68,7 +69,9 @@ def _set_xdp_generic_mb_on(cfg) -> None:
|
||||
test_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
prog = test_dir + "/../../net/lib/xdp_dummy.bpf.o"
|
||||
cmd(f"ip link set dev {remote_ifname} mtu 9000", shell=True, host=cfg.remote)
|
||||
defer(ip, f"link set dev {remote_ifname} mtu 1500", host=cfg.remote)
|
||||
ip("link set dev %s mtu 9000 xdpgeneric obj %s sec xdp.frags" % (cfg.ifname, prog))
|
||||
defer(ip, f"link set dev {cfg.ifname} mtu 1500 xdpgeneric off")
|
||||
|
||||
if no_sleep != True:
|
||||
time.sleep(10)
|
||||
@@ -78,6 +81,7 @@ def _set_xdp_native_sb_on(cfg) -> None:
|
||||
prog = test_dir + "/../../net/lib/xdp_dummy.bpf.o"
|
||||
cmd(f"ip link set dev {remote_ifname} mtu 1500", shell=True, host=cfg.remote)
|
||||
cmd(f"ip -j link set dev {cfg.ifname} mtu 1500 xdp obj {prog} sec xdp", shell=True)
|
||||
defer(ip, f"link set dev {cfg.ifname} mtu 1500 xdp off")
|
||||
xdp_info = ip("-d link show %s" % (cfg.ifname), json=True)[0]
|
||||
if xdp_info['xdp']['mode'] != 1:
|
||||
"""
|
||||
@@ -94,10 +98,11 @@ def _set_xdp_native_mb_on(cfg) -> None:
|
||||
test_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
prog = test_dir + "/../../net/lib/xdp_dummy.bpf.o"
|
||||
cmd(f"ip link set dev {remote_ifname} mtu 9000", shell=True, host=cfg.remote)
|
||||
defer(ip, f"link set dev {remote_ifname} mtu 1500", host=cfg.remote)
|
||||
try:
|
||||
cmd(f"ip link set dev {cfg.ifname} mtu 9000 xdp obj {prog} sec xdp.frags", shell=True)
|
||||
defer(ip, f"link set dev {cfg.ifname} mtu 1500 xdp off")
|
||||
except Exception as e:
|
||||
cmd(f"ip link set dev {remote_ifname} mtu 1500", shell=True, host=cfg.remote)
|
||||
raise KsftSkipEx('device does not support native-multi-buffer XDP')
|
||||
|
||||
if no_sleep != True:
|
||||
@@ -111,6 +116,7 @@ def _set_xdp_offload_on(cfg) -> None:
|
||||
cmd(f"ip link set dev {cfg.ifname} xdpoffload obj {prog} sec xdp", shell=True)
|
||||
except Exception as e:
|
||||
raise KsftSkipEx('device does not support offloaded XDP')
|
||||
defer(ip, f"link set dev {cfg.ifname} xdpoffload off")
|
||||
cmd(f"ip link set dev {remote_ifname} mtu 1500", shell=True, host=cfg.remote)
|
||||
|
||||
if no_sleep != True:
|
||||
@@ -157,7 +163,6 @@ def test_xdp_generic_sb(cfg, netnl) -> None:
|
||||
_test_v4(cfg)
|
||||
_test_v6(cfg)
|
||||
_test_tcp(cfg)
|
||||
ip("link set dev %s xdpgeneric off" % cfg.ifname)
|
||||
|
||||
def test_xdp_generic_mb(cfg, netnl) -> None:
|
||||
_set_xdp_generic_mb_on(cfg)
|
||||
@@ -169,7 +174,6 @@ def test_xdp_generic_mb(cfg, netnl) -> None:
|
||||
_test_v4(cfg)
|
||||
_test_v6(cfg)
|
||||
_test_tcp(cfg)
|
||||
ip("link set dev %s xdpgeneric off" % cfg.ifname)
|
||||
|
||||
def test_xdp_native_sb(cfg, netnl) -> None:
|
||||
_set_xdp_native_sb_on(cfg)
|
||||
@@ -181,7 +185,6 @@ def test_xdp_native_sb(cfg, netnl) -> None:
|
||||
_test_v4(cfg)
|
||||
_test_v6(cfg)
|
||||
_test_tcp(cfg)
|
||||
ip("link set dev %s xdp off" % cfg.ifname)
|
||||
|
||||
def test_xdp_native_mb(cfg, netnl) -> None:
|
||||
_set_xdp_native_mb_on(cfg)
|
||||
@@ -193,14 +196,12 @@ def test_xdp_native_mb(cfg, netnl) -> None:
|
||||
_test_v4(cfg)
|
||||
_test_v6(cfg)
|
||||
_test_tcp(cfg)
|
||||
ip("link set dev %s xdp off" % cfg.ifname)
|
||||
|
||||
def test_xdp_offload(cfg, netnl) -> None:
|
||||
_set_xdp_offload_on(cfg)
|
||||
_test_v4(cfg)
|
||||
_test_v6(cfg)
|
||||
_test_tcp(cfg)
|
||||
ip("link set dev %s xdpoffload off" % cfg.ifname)
|
||||
|
||||
def main() -> None:
|
||||
with NetDrvEpEnv(__file__) as cfg:
|
||||
@@ -213,7 +214,6 @@ def main() -> None:
|
||||
test_xdp_native_mb,
|
||||
test_xdp_offload],
|
||||
args=(cfg, EthtoolFamily()))
|
||||
set_interface_init(cfg)
|
||||
ksft_exit()
|
||||
|
||||
|
||||
|
||||
@@ -31,7 +31,6 @@ TEST_PROGS += veth.sh
|
||||
TEST_PROGS += ioam6.sh
|
||||
TEST_PROGS += gro.sh
|
||||
TEST_PROGS += gre_gso.sh
|
||||
TEST_PROGS += gre_ipv6_lladdr.sh
|
||||
TEST_PROGS += cmsg_so_mark.sh
|
||||
TEST_PROGS += cmsg_so_priority.sh
|
||||
TEST_PROGS += cmsg_time.sh cmsg_ipv6.sh
|
||||
@@ -101,6 +100,7 @@ TEST_PROGS += vlan_bridge_binding.sh
|
||||
TEST_PROGS += bpf_offload.py
|
||||
TEST_PROGS += ipv6_route_update_soft_lockup.sh
|
||||
TEST_PROGS += busy_poll_test.sh
|
||||
TEST_PROGS += lwt_dst_cache_ref_loop.sh
|
||||
|
||||
# YNL files, must be before "include ..lib.mk"
|
||||
YNL_GEN_FILES := busy_poller netlink-dumps
|
||||
|
||||
@@ -107,3 +107,5 @@ CONFIG_XFRM_INTERFACE=m
|
||||
CONFIG_XFRM_USER=m
|
||||
CONFIG_IP_NF_MATCH_RPFILTER=m
|
||||
CONFIG_IP6_NF_MATCH_RPFILTER=m
|
||||
CONFIG_IPV6_ILA=m
|
||||
CONFIG_IPV6_RPL_LWTUNNEL=y
|
||||
|
||||
@@ -1,177 +0,0 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
source ./lib.sh
|
||||
|
||||
PAUSE_ON_FAIL="no"
|
||||
|
||||
# The trap function handler
|
||||
#
|
||||
exit_cleanup_all()
|
||||
{
|
||||
cleanup_all_ns
|
||||
|
||||
exit "${EXIT_STATUS}"
|
||||
}
|
||||
|
||||
# Add fake IPv4 and IPv6 networks on the loopback device, to be used as
|
||||
# underlay by future GRE devices.
|
||||
#
|
||||
setup_basenet()
|
||||
{
|
||||
ip -netns "${NS0}" link set dev lo up
|
||||
ip -netns "${NS0}" address add dev lo 192.0.2.10/24
|
||||
ip -netns "${NS0}" address add dev lo 2001:db8::10/64 nodad
|
||||
}
|
||||
|
||||
# Check if network device has an IPv6 link-local address assigned.
|
||||
#
|
||||
# Parameters:
|
||||
#
|
||||
# * $1: The network device to test
|
||||
# * $2: An extra regular expression that should be matched (to verify the
|
||||
# presence of extra attributes)
|
||||
# * $3: The expected return code from grep (to allow checking the absence of
|
||||
# a link-local address)
|
||||
# * $4: The user visible name for the scenario being tested
|
||||
#
|
||||
check_ipv6_ll_addr()
|
||||
{
|
||||
local DEV="$1"
|
||||
local EXTRA_MATCH="$2"
|
||||
local XRET="$3"
|
||||
local MSG="$4"
|
||||
|
||||
RET=0
|
||||
set +e
|
||||
ip -netns "${NS0}" -6 address show dev "${DEV}" scope link | grep "fe80::" | grep -q "${EXTRA_MATCH}"
|
||||
check_err_fail "${XRET}" $? ""
|
||||
log_test "${MSG}"
|
||||
set -e
|
||||
}
|
||||
|
||||
# Create a GRE device and verify that it gets an IPv6 link-local address as
|
||||
# expected.
|
||||
#
|
||||
# Parameters:
|
||||
#
|
||||
# * $1: The device type (gre, ip6gre, gretap or ip6gretap)
|
||||
# * $2: The local underlay IP address (can be an IPv4, an IPv6 or "any")
|
||||
# * $3: The remote underlay IP address (can be an IPv4, an IPv6 or "any")
|
||||
# * $4: The IPv6 interface identifier generation mode to use for the GRE
|
||||
# device (eui64, none, stable-privacy or random).
|
||||
#
|
||||
test_gre_device()
|
||||
{
|
||||
local GRE_TYPE="$1"
|
||||
local LOCAL_IP="$2"
|
||||
local REMOTE_IP="$3"
|
||||
local MODE="$4"
|
||||
local ADDR_GEN_MODE
|
||||
local MATCH_REGEXP
|
||||
local MSG
|
||||
|
||||
ip link add netns "${NS0}" name gretest type "${GRE_TYPE}" local "${LOCAL_IP}" remote "${REMOTE_IP}"
|
||||
|
||||
case "${MODE}" in
|
||||
"eui64")
|
||||
ADDR_GEN_MODE=0
|
||||
MATCH_REGEXP=""
|
||||
MSG="${GRE_TYPE}, mode: 0 (EUI64), ${LOCAL_IP} -> ${REMOTE_IP}"
|
||||
XRET=0
|
||||
;;
|
||||
"none")
|
||||
ADDR_GEN_MODE=1
|
||||
MATCH_REGEXP=""
|
||||
MSG="${GRE_TYPE}, mode: 1 (none), ${LOCAL_IP} -> ${REMOTE_IP}"
|
||||
XRET=1 # No link-local address should be generated
|
||||
;;
|
||||
"stable-privacy")
|
||||
ADDR_GEN_MODE=2
|
||||
MATCH_REGEXP="stable-privacy"
|
||||
MSG="${GRE_TYPE}, mode: 2 (stable privacy), ${LOCAL_IP} -> ${REMOTE_IP}"
|
||||
XRET=0
|
||||
# Initialise stable_secret (required for stable-privacy mode)
|
||||
ip netns exec "${NS0}" sysctl -qw net.ipv6.conf.gretest.stable_secret="2001:db8::abcd"
|
||||
;;
|
||||
"random")
|
||||
ADDR_GEN_MODE=3
|
||||
MATCH_REGEXP="stable-privacy"
|
||||
MSG="${GRE_TYPE}, mode: 3 (random), ${LOCAL_IP} -> ${REMOTE_IP}"
|
||||
XRET=0
|
||||
;;
|
||||
esac
|
||||
|
||||
# Check that IPv6 link-local address is generated when device goes up
|
||||
ip netns exec "${NS0}" sysctl -qw net.ipv6.conf.gretest.addr_gen_mode="${ADDR_GEN_MODE}"
|
||||
ip -netns "${NS0}" link set dev gretest up
|
||||
check_ipv6_ll_addr gretest "${MATCH_REGEXP}" "${XRET}" "config: ${MSG}"
|
||||
|
||||
# Now disable link-local address generation
|
||||
ip -netns "${NS0}" link set dev gretest down
|
||||
ip netns exec "${NS0}" sysctl -qw net.ipv6.conf.gretest.addr_gen_mode=1
|
||||
ip -netns "${NS0}" link set dev gretest up
|
||||
|
||||
# Check that link-local address generation works when re-enabled while
|
||||
# the device is already up
|
||||
ip netns exec "${NS0}" sysctl -qw net.ipv6.conf.gretest.addr_gen_mode="${ADDR_GEN_MODE}"
|
||||
check_ipv6_ll_addr gretest "${MATCH_REGEXP}" "${XRET}" "update: ${MSG}"
|
||||
|
||||
ip -netns "${NS0}" link del dev gretest
|
||||
}
|
||||
|
||||
test_gre4()
|
||||
{
|
||||
local GRE_TYPE
|
||||
local MODE
|
||||
|
||||
for GRE_TYPE in "gre" "gretap"; do
|
||||
printf "\n####\nTesting IPv6 link-local address generation on ${GRE_TYPE} devices\n####\n\n"
|
||||
|
||||
for MODE in "eui64" "none" "stable-privacy" "random"; do
|
||||
test_gre_device "${GRE_TYPE}" 192.0.2.10 192.0.2.11 "${MODE}"
|
||||
test_gre_device "${GRE_TYPE}" any 192.0.2.11 "${MODE}"
|
||||
test_gre_device "${GRE_TYPE}" 192.0.2.10 any "${MODE}"
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
test_gre6()
|
||||
{
|
||||
local GRE_TYPE
|
||||
local MODE
|
||||
|
||||
for GRE_TYPE in "ip6gre" "ip6gretap"; do
|
||||
printf "\n####\nTesting IPv6 link-local address generation on ${GRE_TYPE} devices\n####\n\n"
|
||||
|
||||
for MODE in "eui64" "none" "stable-privacy" "random"; do
|
||||
test_gre_device "${GRE_TYPE}" 2001:db8::10 2001:db8::11 "${MODE}"
|
||||
test_gre_device "${GRE_TYPE}" any 2001:db8::11 "${MODE}"
|
||||
test_gre_device "${GRE_TYPE}" 2001:db8::10 any "${MODE}"
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
usage()
|
||||
{
|
||||
echo "Usage: $0 [-p]"
|
||||
exit 1
|
||||
}
|
||||
|
||||
while getopts :p o
|
||||
do
|
||||
case $o in
|
||||
p) PAUSE_ON_FAIL="yes";;
|
||||
*) usage;;
|
||||
esac
|
||||
done
|
||||
|
||||
setup_ns NS0
|
||||
|
||||
set -e
|
||||
trap exit_cleanup_all EXIT
|
||||
|
||||
setup_basenet
|
||||
|
||||
test_gre4
|
||||
test_gre6
|
||||
246
tools/testing/selftests/net/lwt_dst_cache_ref_loop.sh
Executable file
246
tools/testing/selftests/net/lwt_dst_cache_ref_loop.sh
Executable file
@@ -0,0 +1,246 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# Author: Justin Iurman <justin.iurman@uliege.be>
|
||||
#
|
||||
# WARNING
|
||||
# -------
|
||||
# This is just a dummy script that triggers encap cases with possible dst cache
|
||||
# reference loops in affected lwt users (see list below). Some cases are
|
||||
# pathological configurations for simplicity, others are valid. Overall, we
|
||||
# don't want this issue to happen, no matter what. In order to catch any
|
||||
# reference loops, kmemleak MUST be used. The results alone are always blindly
|
||||
# successful, don't rely on them. Note that the following tests may crash the
|
||||
# kernel if the fix to prevent lwtunnel_{input|output|xmit}() reentry loops is
|
||||
# not present.
|
||||
#
|
||||
# Affected lwt users so far (please update accordingly if needed):
|
||||
# - ila_lwt (output only)
|
||||
# - ioam6_iptunnel (output only)
|
||||
# - rpl_iptunnel (both input and output)
|
||||
# - seg6_iptunnel (both input and output)
|
||||
|
||||
source lib.sh
|
||||
|
||||
check_compatibility()
|
||||
{
|
||||
setup_ns tmp_node &>/dev/null
|
||||
if [ $? != 0 ]; then
|
||||
echo "SKIP: Cannot create netns."
|
||||
exit $ksft_skip
|
||||
fi
|
||||
|
||||
ip link add name veth0 netns $tmp_node type veth \
|
||||
peer name veth1 netns $tmp_node &>/dev/null
|
||||
local ret=$?
|
||||
|
||||
ip -netns $tmp_node link set veth0 up &>/dev/null
|
||||
ret=$((ret + $?))
|
||||
|
||||
ip -netns $tmp_node link set veth1 up &>/dev/null
|
||||
ret=$((ret + $?))
|
||||
|
||||
if [ $ret != 0 ]; then
|
||||
echo "SKIP: Cannot configure links."
|
||||
cleanup_ns $tmp_node
|
||||
exit $ksft_skip
|
||||
fi
|
||||
|
||||
lsmod 2>/dev/null | grep -q "ila"
|
||||
ila_lsmod=$?
|
||||
[ $ila_lsmod != 0 ] && modprobe ila &>/dev/null
|
||||
|
||||
ip -netns $tmp_node route add 2001:db8:1::/64 \
|
||||
encap ila 1:2:3:4 csum-mode no-action ident-type luid \
|
||||
hook-type output \
|
||||
dev veth0 &>/dev/null
|
||||
|
||||
ip -netns $tmp_node route add 2001:db8:2::/64 \
|
||||
encap ioam6 trace prealloc type 0x800000 ns 0 size 4 \
|
||||
dev veth0 &>/dev/null
|
||||
|
||||
ip -netns $tmp_node route add 2001:db8:3::/64 \
|
||||
encap rpl segs 2001:db8:3::1 dev veth0 &>/dev/null
|
||||
|
||||
ip -netns $tmp_node route add 2001:db8:4::/64 \
|
||||
encap seg6 mode inline segs 2001:db8:4::1 dev veth0 &>/dev/null
|
||||
|
||||
ip -netns $tmp_node -6 route 2>/dev/null | grep -q "encap ila"
|
||||
skip_ila=$?
|
||||
|
||||
ip -netns $tmp_node -6 route 2>/dev/null | grep -q "encap ioam6"
|
||||
skip_ioam6=$?
|
||||
|
||||
ip -netns $tmp_node -6 route 2>/dev/null | grep -q "encap rpl"
|
||||
skip_rpl=$?
|
||||
|
||||
ip -netns $tmp_node -6 route 2>/dev/null | grep -q "encap seg6"
|
||||
skip_seg6=$?
|
||||
|
||||
cleanup_ns $tmp_node
|
||||
}
|
||||
|
||||
setup()
|
||||
{
|
||||
setup_ns alpha beta gamma &>/dev/null
|
||||
|
||||
ip link add name veth-alpha netns $alpha type veth \
|
||||
peer name veth-betaL netns $beta &>/dev/null
|
||||
|
||||
ip link add name veth-betaR netns $beta type veth \
|
||||
peer name veth-gamma netns $gamma &>/dev/null
|
||||
|
||||
ip -netns $alpha link set veth-alpha name veth0 &>/dev/null
|
||||
ip -netns $beta link set veth-betaL name veth0 &>/dev/null
|
||||
ip -netns $beta link set veth-betaR name veth1 &>/dev/null
|
||||
ip -netns $gamma link set veth-gamma name veth0 &>/dev/null
|
||||
|
||||
ip -netns $alpha addr add 2001:db8:1::2/64 dev veth0 &>/dev/null
|
||||
ip -netns $alpha link set veth0 up &>/dev/null
|
||||
ip -netns $alpha link set lo up &>/dev/null
|
||||
ip -netns $alpha route add 2001:db8:2::/64 \
|
||||
via 2001:db8:1::1 dev veth0 &>/dev/null
|
||||
|
||||
ip -netns $beta addr add 2001:db8:1::1/64 dev veth0 &>/dev/null
|
||||
ip -netns $beta addr add 2001:db8:2::1/64 dev veth1 &>/dev/null
|
||||
ip -netns $beta link set veth0 up &>/dev/null
|
||||
ip -netns $beta link set veth1 up &>/dev/null
|
||||
ip -netns $beta link set lo up &>/dev/null
|
||||
ip -netns $beta route del 2001:db8:2::/64
|
||||
ip -netns $beta route add 2001:db8:2::/64 dev veth1
|
||||
ip netns exec $beta \
|
||||
sysctl -wq net.ipv6.conf.all.forwarding=1 &>/dev/null
|
||||
|
||||
ip -netns $gamma addr add 2001:db8:2::2/64 dev veth0 &>/dev/null
|
||||
ip -netns $gamma link set veth0 up &>/dev/null
|
||||
ip -netns $gamma link set lo up &>/dev/null
|
||||
ip -netns $gamma route add 2001:db8:1::/64 \
|
||||
via 2001:db8:2::1 dev veth0 &>/dev/null
|
||||
|
||||
sleep 1
|
||||
|
||||
ip netns exec $alpha ping6 -c 5 -W 1 2001:db8:2::2 &>/dev/null
|
||||
if [ $? != 0 ]; then
|
||||
echo "SKIP: Setup failed."
|
||||
exit $ksft_skip
|
||||
fi
|
||||
|
||||
sleep 1
|
||||
}
|
||||
|
||||
cleanup()
|
||||
{
|
||||
cleanup_ns $alpha $beta $gamma
|
||||
[ $ila_lsmod != 0 ] && modprobe -r ila &>/dev/null
|
||||
}
|
||||
|
||||
run_ila()
|
||||
{
|
||||
if [ $skip_ila != 0 ]; then
|
||||
echo "SKIP: ila (output)"
|
||||
return
|
||||
fi
|
||||
|
||||
ip -netns $beta route del 2001:db8:2::/64
|
||||
ip -netns $beta route add 2001:db8:2:0:0:0:0:2/128 \
|
||||
encap ila 2001:db8:2:0 csum-mode no-action ident-type luid \
|
||||
hook-type output \
|
||||
dev veth1 &>/dev/null
|
||||
sleep 1
|
||||
|
||||
echo "TEST: ila (output)"
|
||||
ip netns exec $beta ping6 -c 2 -W 1 2001:db8:2::2 &>/dev/null
|
||||
sleep 1
|
||||
|
||||
ip -netns $beta route del 2001:db8:2:0:0:0:0:2/128
|
||||
ip -netns $beta route add 2001:db8:2::/64 dev veth1
|
||||
sleep 1
|
||||
}
|
||||
|
||||
run_ioam6()
|
||||
{
|
||||
if [ $skip_ioam6 != 0 ]; then
|
||||
echo "SKIP: ioam6 (output)"
|
||||
return
|
||||
fi
|
||||
|
||||
ip -netns $beta route change 2001:db8:2::/64 \
|
||||
encap ioam6 trace prealloc type 0x800000 ns 1 size 4 \
|
||||
dev veth1 &>/dev/null
|
||||
sleep 1
|
||||
|
||||
echo "TEST: ioam6 (output)"
|
||||
ip netns exec $beta ping6 -c 2 -W 1 2001:db8:2::2 &>/dev/null
|
||||
sleep 1
|
||||
}
|
||||
|
||||
run_rpl()
|
||||
{
|
||||
if [ $skip_rpl != 0 ]; then
|
||||
echo "SKIP: rpl (input)"
|
||||
echo "SKIP: rpl (output)"
|
||||
return
|
||||
fi
|
||||
|
||||
ip -netns $beta route change 2001:db8:2::/64 \
|
||||
encap rpl segs 2001:db8:2::2 \
|
||||
dev veth1 &>/dev/null
|
||||
sleep 1
|
||||
|
||||
echo "TEST: rpl (input)"
|
||||
ip netns exec $alpha ping6 -c 2 -W 1 2001:db8:2::2 &>/dev/null
|
||||
sleep 1
|
||||
|
||||
echo "TEST: rpl (output)"
|
||||
ip netns exec $beta ping6 -c 2 -W 1 2001:db8:2::2 &>/dev/null
|
||||
sleep 1
|
||||
}
|
||||
|
||||
run_seg6()
|
||||
{
|
||||
if [ $skip_seg6 != 0 ]; then
|
||||
echo "SKIP: seg6 (input)"
|
||||
echo "SKIP: seg6 (output)"
|
||||
return
|
||||
fi
|
||||
|
||||
ip -netns $beta route change 2001:db8:2::/64 \
|
||||
encap seg6 mode inline segs 2001:db8:2::2 \
|
||||
dev veth1 &>/dev/null
|
||||
sleep 1
|
||||
|
||||
echo "TEST: seg6 (input)"
|
||||
ip netns exec $alpha ping6 -c 2 -W 1 2001:db8:2::2 &>/dev/null
|
||||
sleep 1
|
||||
|
||||
echo "TEST: seg6 (output)"
|
||||
ip netns exec $beta ping6 -c 2 -W 1 2001:db8:2::2 &>/dev/null
|
||||
sleep 1
|
||||
}
|
||||
|
||||
run()
|
||||
{
|
||||
run_ila
|
||||
run_ioam6
|
||||
run_rpl
|
||||
run_seg6
|
||||
}
|
||||
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
echo "SKIP: Need root privileges."
|
||||
exit $ksft_skip
|
||||
fi
|
||||
|
||||
if [ ! -x "$(command -v ip)" ]; then
|
||||
echo "SKIP: Could not run test without ip tool."
|
||||
exit $ksft_skip
|
||||
fi
|
||||
|
||||
check_compatibility
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
setup
|
||||
run
|
||||
|
||||
exit $ksft_pass
|
||||
Reference in New Issue
Block a user