* [PATCH] net: stmmac_tc: use 64-bit arithmetic instead of 32-bit
From: Gustavo A. R. Silva @ 2018-07-02 12:09 UTC (permalink / raw)
To: Giuseppe Cavallaro, Alexandre Torgue, Jose Abreu, David S. Miller
Cc: netdev, linux-kernel, Gustavo A. R. Silva
Add suffix UL to constant 1024 in order to give the compiler complete
information about the proper arithmetic to use. Notice that this
constant is used in a context that expects an expression of type
u64 (64 bits, unsigned) and following expressions are currently
being evaluated using 32-bit arithmetic:
qopt->idleslope * 1024 * ptr
qopt->hicredit * 1024 * 8
qopt->locredit * 1024 * 8
Addresses-Coverity-ID: 1470246 ("Unintentional integer overflow")
Addresses-Coverity-ID: 1470248 ("Unintentional integer overflow")
Addresses-Coverity-ID: 1470249 ("Unintentional integer overflow")
Signed-off-by: Gustavo A. R. Silva <gustavo@embeddedor.com>
---
drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
index 0b0fca0..8fedc28 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
@@ -321,7 +321,7 @@ static int tc_setup_cbs(struct stmmac_priv *priv,
speed_div = (priv->speed == SPEED_100) ? 100000 : 1000000;
/* Final adjustments for HW */
- value = qopt->idleslope * 1024 * ptr;
+ value = qopt->idleslope * 1024UL * ptr;
do_div(value, speed_div);
priv->plat->tx_queues_cfg[queue].idle_slope = value & GENMASK(31, 0);
@@ -329,10 +329,10 @@ static int tc_setup_cbs(struct stmmac_priv *priv,
do_div(value, speed_div);
priv->plat->tx_queues_cfg[queue].send_slope = value & GENMASK(31, 0);
- value = qopt->hicredit * 1024 * 8;
+ value = qopt->hicredit * 1024UL * 8;
priv->plat->tx_queues_cfg[queue].high_credit = value & GENMASK(31, 0);
- value = qopt->locredit * 1024 * 8;
+ value = qopt->locredit * 1024UL * 8;
priv->plat->tx_queues_cfg[queue].low_credit = value & GENMASK(31, 0);
ret = stmmac_config_cbs(priv, priv->hw,
--
2.7.4
^ permalink raw reply related
* RE: [RFC net-next 15/15] net: lora: Add Semtech SX1301
From: Ben Whitten @ 2018-07-02 11:51 UTC (permalink / raw)
To: Andreas Färber, netdev@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, Jian-Hong Pan, Jiri Pirko,
Marcel Holtmann, David S . Miller, Matthias Brugger, Janus Piwek,
Michael Röder, Dollar Chen, Ken Yu, Steve deRosier,
Mark Brown, linux-spi@vger.kernel.org
In-Reply-To: <20180701110804.32415-16-afaerber@suse.de>
Hi Andreas,
Excellent work on doing this I have also been working on and off
this personally for some time.
Have a look at my repository [1] for sx1301 and sx1257 drivers,
I use regmaps capability of switching pages which should simplify
your driver considerably, I also have a full register map and bit field.
I have also been trying to use the clk framework to capture the various
routing that the cards have.
I will dig into this series this evening.
[1] https://github.com/BWhitten/linux-stable/tree/971aadc8fdfe842020d912449bdd71b33d576fe3/drivers/net/lora
> Subject: [RFC net-next 15/15] net: lora: Add Semtech SX1301
>
> The Semtech SX1301 was the first multi-channel LoRa "concentrator".
> It uses a SPI interface to the host as well as a dual SPI interface to
> its radios. These two have been implemented as spi_controller, so that
> the Device Tree can specify whether the respective module uses two
> SX1257, two SX1255 or a combination of these or some unforeseen chipset.
>
> This implementation is the most recent - initialization is not yet
> complete, it will need to load firmware into the two on-chip MCUs.
>
> Unfortunately there is no full datasheet with register descriptions,
> only a BSD-licensed userspace HAL implementation using spidev devices.
> Therefore some register names are unknown.
>
> Cc: Ben Whitten <ben.whitten@lairdtech.com>
> Cc: Steve deRosier <derosier@gmail.com>
> Cc: Mark Brown <broonie@kernel.org>
> Cc: Michael Röder <michael.roeder@avnet.eu>
> Cc: Ken Yu (禹凯) <ken.yu@rakwireless.com>
> Cc: linux-spi@vger.kernel.org
> Signed-off-by: Andreas Färber <afaerber@suse.de>
> ---
> drivers/net/lora/Kconfig | 7 +
> drivers/net/lora/Makefile | 3 +
> drivers/net/lora/sx1301.c | 446
> ++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 456 insertions(+)
> create mode 100644 drivers/net/lora/sx1301.c
>
> diff --git a/drivers/net/lora/Kconfig b/drivers/net/lora/Kconfig
> index 68c7480d7812..950450e353b4 100644
> --- a/drivers/net/lora/Kconfig
> +++ b/drivers/net/lora/Kconfig
> @@ -45,6 +45,13 @@ config LORA_SX1276
> help
> Semtech SX1272/1276/1278
>
> +config LORA_SX1301
> + tristate "Semtech SX1301 SPI driver"
> + default y
> + depends on SPI
> + help
> + Semtech SX1301
> +
> config LORA_USI
> tristate "USI WM-SG-SM-42 driver"
> default y
> diff --git a/drivers/net/lora/Makefile b/drivers/net/lora/Makefile
> index 44c578bde7d5..1cc1e3aa189b 100644
> --- a/drivers/net/lora/Makefile
> +++ b/drivers/net/lora/Makefile
> @@ -22,6 +22,9 @@ lora-sx1257-y := sx1257.o
> obj-$(CONFIG_LORA_SX1276) += lora-sx1276.o
> lora-sx1276-y := sx1276.o
>
> +obj-$(CONFIG_LORA_SX1301) += lora-sx1301.o
> +lora-sx1301-y := sx1301.o
> +
> obj-$(CONFIG_LORA_USI) += lora-usi.o
> lora-usi-y := usi.o
>
> diff --git a/drivers/net/lora/sx1301.c b/drivers/net/lora/sx1301.c
> new file mode 100644
> index 000000000000..5c936c1116d1
> --- /dev/null
> +++ b/drivers/net/lora/sx1301.c
> @@ -0,0 +1,446 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Semtech SX1301 LoRa concentrator
> + *
> + * Copyright (c) 2018 Andreas Färber
> + *
> + * Based on SX1301 HAL code:
> + * Copyright (c) 2013 Semtech-Cycleo
> + */
> +
> +#include <linux/bitops.h>
> +#include <linux/delay.h>
> +#include <linux/lora.h>
> +#include <linux/module.h>
> +#include <linux/netdevice.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/of_gpio.h>
> +#include <linux/lora/dev.h>
> +#include <linux/spi/spi.h>
> +
> +#define REG_PAGE_RESET 0
> +#define REG_VERSION 1
> +#define REG_2_SPI_RADIO_A_DATA 33
> +#define REG_2_SPI_RADIO_A_DATA_READBACK 34
> +#define REG_2_SPI_RADIO_A_ADDR 35
> +#define REG_2_SPI_RADIO_A_CS 37
> +#define REG_2_SPI_RADIO_B_DATA 38
> +#define REG_2_SPI_RADIO_B_DATA_READBACK 39
> +#define REG_2_SPI_RADIO_B_ADDR 40
> +#define REG_2_SPI_RADIO_B_CS 42
> +
> +#define REG_PAGE_RESET_SOFT_RESET BIT(7)
> +
> +#define REG_16_GLOBAL_EN BIT(3)
> +
> +#define REG_17_CLK32M_EN BIT(0)
> +
> +#define REG_2_43_RADIO_A_EN BIT(0)
> +#define REG_2_43_RADIO_B_EN BIT(1)
> +#define REG_2_43_RADIO_RST BIT(2)
> +
> +struct spi_sx1301 {
> + struct spi_device *parent;
> + u8 page;
> + u8 regs;
> +};
> +
> +struct sx1301_priv {
> + struct lora_priv lora;
> + struct gpio_desc *rst_gpio;
> + u8 cur_page;
> + struct spi_controller *radio_a_ctrl, *radio_b_ctrl;
> +};
> +
> +static int sx1301_read(struct spi_device *spi, u8 reg, u8 *val)
> +{
> + u8 addr = reg & 0x7f;
> + return spi_write_then_read(spi, &addr, 1, val, 1);
> +}
> +
> +static int sx1301_write(struct spi_device *spi, u8 reg, u8 val)
> +{
> + u8 buf[2];
> +
> + buf[0] = reg | BIT(7);
> + buf[1] = val;
> + return spi_write(spi, buf, 2);
> +}
> +
> +static int sx1301_page_switch(struct spi_device *spi, u8 page)
> +{
> + struct sx1301_priv *priv = spi_get_drvdata(spi);
> + int ret;
> +
> + if (priv->cur_page == page)
> + return 0;
> +
> + dev_dbg(&spi->dev, "switching to page %u\n", (unsigned)page);
> + ret = sx1301_write(spi, REG_PAGE_RESET, page & 0x3);
> + if (ret) {
> + dev_err(&spi->dev, "switching to page %u failed\n",
> (unsigned)page);
> + return ret;
> + }
> +
> + priv->cur_page = page;
> +
> + return 0;
> +}
> +
> +static int sx1301_soft_reset(struct spi_device *spi)
> +{
> + return sx1301_write(spi, REG_PAGE_RESET,
> REG_PAGE_RESET_SOFT_RESET);
> +}
> +
> +#define REG_RADIO_X_DATA 0
> +#define REG_RADIO_X_DATA_READBACK 1
> +#define REG_RADIO_X_ADDR 2
> +#define REG_RADIO_X_CS 4
> +
> +static int sx1301_radio_set_cs(struct spi_controller *ctrl, bool enable)
> +{
> + struct spi_sx1301 *ssx = spi_controller_get_devdata(ctrl);
> + u8 cs;
> + int ret;
> +
> + dev_dbg(&ctrl->dev, "setting CS to %s\n", enable ? "1" : "0");
> +
> + ret = sx1301_page_switch(ssx->parent, ssx->page);
> + if (ret) {
> + dev_warn(&ctrl->dev, "failed to switch page for CS (%d)\n",
> ret);
> + return ret;
> + }
> +
> + ret = sx1301_read(ssx->parent, ssx->regs + REG_RADIO_X_CS, &cs);
> + if (ret) {
> + dev_warn(&ctrl->dev, "failed to read CS (%d)\n", ret);
> + cs = 0;
> + }
> +
> + if (enable)
> + cs |= BIT(0);
> + else
> + cs &= ~BIT(0);
> +
> + ret = sx1301_write(ssx->parent, ssx->regs + REG_RADIO_X_CS, cs);
> + if (ret)
> + dev_warn(&ctrl->dev, "failed to write CS (%d)\n", ret);
> +
> + return 0;
> +}
> +
> +static void sx1301_radio_spi_set_cs(struct spi_device *spi, bool enable)
> +{
> + int ret;
> +
> + dev_dbg(&spi->dev, "setting SPI CS to %s\n", enable ? "1" : "0");
> +
> + if (enable)
> + return;
> +
> + ret = sx1301_radio_set_cs(spi->controller, enable);
> + if (ret)
> + dev_warn(&spi->dev, "failed to write CS (%d)\n", ret);
> +}
> +
> +static int sx1301_radio_spi_transfer_one(struct spi_controller *ctrl,
> + struct spi_device *spi, struct spi_transfer *xfr)
> +{
> + struct spi_sx1301 *ssx = spi_controller_get_devdata(ctrl);
> + const u8 *tx_buf = xfr->tx_buf;
> + u8 *rx_buf = xfr->rx_buf;
> + int ret;
> +
> + if (xfr->len == 0 || xfr->len > 3)
> + return -EINVAL;
> +
> + dev_dbg(&spi->dev, "transferring one (%u)\n", xfr->len);
> +
> + ret = sx1301_page_switch(ssx->parent, ssx->page);
> + if (ret) {
> + dev_err(&spi->dev, "failed to switch page for transfer
> (%d)\n", ret);
> + return ret;
> + }
> +
> + if (tx_buf) {
> + ret = sx1301_write(ssx->parent, ssx->regs +
> REG_RADIO_X_ADDR, tx_buf ? tx_buf[0] : 0);
> + if (ret) {
> + dev_err(&spi->dev, "SPI radio address write
> failed\n");
> + return ret;
> + }
> +
> + ret = sx1301_write(ssx->parent, ssx->regs +
> REG_RADIO_X_DATA, (tx_buf && xfr->len >= 2) ? tx_buf[1] : 0);
> + if (ret) {
> + dev_err(&spi->dev, "SPI radio data write failed\n");
> + return ret;
> + }
> +
> + ret = sx1301_radio_set_cs(ctrl, true);
> + if (ret) {
> + dev_err(&spi->dev, "SPI radio CS set failed\n");
> + return ret;
> + }
> +
> + ret = sx1301_radio_set_cs(ctrl, false);
> + if (ret) {
> + dev_err(&spi->dev, "SPI radio CS unset failed\n");
> + return ret;
> + }
> + }
> +
> + if (rx_buf) {
> + ret = sx1301_read(ssx->parent, ssx->regs +
> REG_RADIO_X_DATA_READBACK, &rx_buf[xfr->len - 1]);
> + if (ret) {
> + dev_err(&spi->dev, "SPI radio data read failed\n");
> + return ret;
> + }
> + }
> +
> + return 0;
> +}
> +
> +static void sx1301_radio_setup(struct spi_controller *ctrl)
> +{
> + ctrl->mode_bits = SPI_CS_HIGH | SPI_NO_CS;
> + ctrl->bits_per_word_mask = SPI_BPW_MASK(8);
> + ctrl->num_chipselect = 1;
> + ctrl->set_cs = sx1301_radio_spi_set_cs;
> + ctrl->transfer_one = sx1301_radio_spi_transfer_one;
> +}
> +
> +static int sx1301_probe(struct spi_device *spi)
> +{
> + struct net_device *netdev;
> + struct sx1301_priv *priv;
> + struct spi_sx1301 *radio;
> + struct gpio_desc *rst;
> + int ret;
> + u8 val;
> +
> + rst = devm_gpiod_get_optional(&spi->dev, "reset",
> GPIOD_OUT_LOW);
> + if (IS_ERR(rst))
> + return PTR_ERR(rst);
> +
> + gpiod_set_value_cansleep(rst, 1);
> + msleep(100);
> + gpiod_set_value_cansleep(rst, 0);
> + msleep(100);
> +
> + spi->bits_per_word = 8;
> + spi_setup(spi);
> +
> + ret = sx1301_read(spi, REG_VERSION, &val);
> + if (ret) {
> + dev_err(&spi->dev, "version read failed\n");
> + goto err_version;
> + }
> +
> + if (val != 103) {
> + dev_err(&spi->dev, "unexpected version: %u\n", val);
> + ret = -ENXIO;
> + goto err_version;
> + }
> +
> + netdev = alloc_loradev(sizeof(*priv));
> + if (!netdev) {
> + ret = -ENOMEM;
> + goto err_alloc_loradev;
> + }
> +
> + priv = netdev_priv(netdev);
> + priv->rst_gpio = rst;
> + priv->cur_page = 0xff;
> +
> + spi_set_drvdata(spi, netdev);
> + SET_NETDEV_DEV(netdev, &spi->dev);
> +
> + ret = sx1301_write(spi, REG_PAGE_RESET, 0);
> + if (ret) {
> + dev_err(&spi->dev, "page/reset write failed\n");
> + return ret;
> + }
> +
> + ret = sx1301_soft_reset(spi);
> + if (ret) {
> + dev_err(&spi->dev, "soft reset failed\n");
> + return ret;
> + }
> +
> + ret = sx1301_read(spi, 16, &val);
> + if (ret) {
> + dev_err(&spi->dev, "16 read failed\n");
> + return ret;
> + }
> +
> + val &= ~REG_16_GLOBAL_EN;
> +
> + ret = sx1301_write(spi, 16, val);
> + if (ret) {
> + dev_err(&spi->dev, "16 write failed\n");
> + return ret;
> + }
> +
> + ret = sx1301_read(spi, 17, &val);
> + if (ret) {
> + dev_err(&spi->dev, "17 read failed\n");
> + return ret;
> + }
> +
> + val &= ~REG_17_CLK32M_EN;
> +
> + ret = sx1301_write(spi, 17, val);
> + if (ret) {
> + dev_err(&spi->dev, "17 write failed\n");
> + return ret;
> + }
> +
> + ret = sx1301_page_switch(spi, 2);
> + if (ret) {
> + dev_err(&spi->dev, "page 2 switch failed\n");
> + return ret;
> + }
> +
> + ret = sx1301_read(spi, 43, &val);
> + if (ret) {
> + dev_err(&spi->dev, "2|43 read failed\n");
> + return ret;
> + }
> +
> + val |= REG_2_43_RADIO_B_EN | REG_2_43_RADIO_A_EN;
> +
> + ret = sx1301_write(spi, 43, val);
> + if (ret) {
> + dev_err(&spi->dev, "2|43 write failed\n");
> + return ret;
> + }
> +
> + msleep(500);
> +
> + ret = sx1301_read(spi, 43, &val);
> + if (ret) {
> + dev_err(&spi->dev, "2|43 read failed\n");
> + return ret;
> + }
> +
> + val |= REG_2_43_RADIO_RST;
> +
> + ret = sx1301_write(spi, 43, val);
> + if (ret) {
> + dev_err(&spi->dev, "2|43 write failed\n");
> + return ret;
> + }
> +
> + msleep(5);
> +
> + ret = sx1301_read(spi, 43, &val);
> + if (ret) {
> + dev_err(&spi->dev, "2|43 read failed\n");
> + return ret;
> + }
> +
> + val &= ~REG_2_43_RADIO_RST;
> +
> + ret = sx1301_write(spi, 43, val);
> + if (ret) {
> + dev_err(&spi->dev, "2|43 write failed\n");
> + return ret;
> + }
> +
> + /* radio A */
> +
> + priv->radio_a_ctrl = spi_alloc_master(&spi->dev, sizeof(*radio));
> + if (!priv->radio_a_ctrl) {
> + ret = -ENOMEM;
> + goto err_radio_a_alloc;
> + }
> +
> + sx1301_radio_setup(priv->radio_a_ctrl);
> + priv->radio_a_ctrl->dev.of_node = of_get_child_by_name(spi-
> >dev.of_node, "radio-a");
> +
> + radio = spi_controller_get_devdata(priv->radio_a_ctrl);
> + radio->page = 2;
> + radio->regs = REG_2_SPI_RADIO_A_DATA;
> + radio->parent = spi;
> +
> + dev_info(&spi->dev, "registering radio A SPI\n");
> +
> + ret = devm_spi_register_controller(&spi->dev, priv->radio_a_ctrl);
> + if (ret) {
> + dev_err(&spi->dev, "radio A SPI register failed\n");
> + goto err_radio_a_register;
> + }
> +
> + /* radio B */
> +
> + priv->radio_b_ctrl = spi_alloc_master(&spi->dev, sizeof(*radio));
> + if (!priv->radio_b_ctrl) {
> + ret = -ENOMEM;
> + goto err_radio_b_alloc;
> + }
> +
> + sx1301_radio_setup(priv->radio_b_ctrl);
> + priv->radio_b_ctrl->dev.of_node = of_get_child_by_name(spi-
> >dev.of_node, "radio-b");
> +
> + radio = spi_controller_get_devdata(priv->radio_b_ctrl);
> + radio->page = 2;
> + radio->regs = REG_2_SPI_RADIO_B_DATA;
> + radio->parent = spi;
> +
> + dev_info(&spi->dev, "registering radio B SPI\n");
> +
> + ret = devm_spi_register_controller(&spi->dev, priv->radio_b_ctrl);
> + if (ret) {
> + dev_err(&spi->dev, "radio B SPI register failed\n");
> + goto err_radio_b_register;
> + }
> +
> + dev_info(&spi->dev, "SX1301 module probed\n");
> +
> + return 0;
> +err_radio_b_register:
> + spi_controller_put(priv->radio_b_ctrl);
> +err_radio_b_alloc:
> +err_radio_a_register:
> + spi_controller_put(priv->radio_a_ctrl);
> +err_radio_a_alloc:
> + free_loradev(netdev);
> +err_alloc_loradev:
> +err_version:
> + return ret;
> +}
> +
> +static int sx1301_remove(struct spi_device *spi)
> +{
> + struct net_device *netdev = spi_get_drvdata(spi);
> +
> + //unregister_loradev(netdev);
> + free_loradev(netdev);
> +
> + dev_info(&spi->dev, "SX1301 module removed\n");
> +
> + return 0;
> +}
> +
> +#ifdef CONFIG_OF
> +static const struct of_device_id sx1301_dt_ids[] = {
> + { .compatible = "semtech,sx1301" },
> + {}
> +};
> +MODULE_DEVICE_TABLE(of, sx1301_dt_ids);
> +#endif
> +
> +static struct spi_driver sx1301_spi_driver = {
> + .driver = {
> + .name = "sx1301",
> + .of_match_table = of_match_ptr(sx1301_dt_ids),
> + },
> + .probe = sx1301_probe,
> + .remove = sx1301_remove,
> +};
> +
> +module_spi_driver(sx1301_spi_driver);
> +
> +MODULE_DESCRIPTION("SX1301 SPI driver");
> +MODULE_AUTHOR("Andreas Färber <afaerber@suse.de>");
> +MODULE_LICENSE("GPL");
> --
> 2.16.4
^ permalink raw reply
* Re: [PATCH net] sctp: fix the issue that pathmtu may be set lower than MINSEGMENT
From: Neil Horman @ 2018-07-02 11:45 UTC (permalink / raw)
To: Xin Long; +Cc: network dev, linux-sctp, davem, Marcelo Ricardo Leitner,
syzkaller
In-Reply-To: <0928f7dda7db59c8aa01e97a87792d9e643e70ab.1530514276.git.lucien.xin@gmail.com>
On Mon, Jul 02, 2018 at 02:51:16PM +0800, Xin Long wrote:
> After commit b6c5734db070 ("sctp: fix the handling of ICMP Frag Needed
> for too small MTUs"), sctp_transport_update_pmtu would refetch pathmtu
> from the dst and set it to transport's pathmtu without any check.
>
> The new pathmtu may be lower than MINSEGMENT if the dst is obsolete and
> updated by .get_dst() in sctp_transport_update_pmtu.
>
> Syzbot reported a warning in sctp_mtu_payload caused by this.
>
> This fix uses the refetched pathmtu only when it's greater than the
> frag_needed pmtu.
>
> Fixes: b6c5734db070 ("sctp: fix the handling of ICMP Frag Needed for too small MTUs")
> Reported-by: syzbot+f0d9d7cba052f9344b03@syzkaller.appspotmail.com
> Signed-off-by: Xin Long <lucien.xin@gmail.com>
> ---
> net/sctp/transport.c | 5 ++++-
> 1 file changed, 4 insertions(+), 1 deletion(-)
>
> diff --git a/net/sctp/transport.c b/net/sctp/transport.c
> index 445b7ef..ddfb687 100644
> --- a/net/sctp/transport.c
> +++ b/net/sctp/transport.c
> @@ -282,7 +282,10 @@ bool sctp_transport_update_pmtu(struct sctp_transport *t, u32 pmtu)
>
> if (dst) {
> /* Re-fetch, as under layers may have a higher minimum size */
> - pmtu = SCTP_TRUNC4(dst_mtu(dst));
> + u32 mtu = SCTP_TRUNC4(dst_mtu(dst));
> +
> + if (pmtu < mtu)
> + pmtu = mtu;
nit, but why not u32 mtu = min(pmtu, SCTP_TRUNC4(dst_mtu(dst))) here ?
Neil
> change = t->pathmtu != pmtu;
> }
> t->pathmtu = pmtu;
> --
> 2.1.0
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-sctp" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* Re: [PATCH][net-next] net: increase MAX_GRO_SKBS to 64
From: David Miller @ 2018-07-02 11:44 UTC (permalink / raw)
To: lirongqing; +Cc: netdev, eric.dumazet
In-Reply-To: <1530531703-11368-1-git-send-email-lirongqing@baidu.com>
From: Li RongQing <lirongqing@baidu.com>
Date: Mon, 2 Jul 2018 19:41:43 +0800
> After 07d78363dcffd [net: Convert NAPI gro list into a small hash table]
> there is 8 hash buckets, which allow more flows to be held for merging.
>
> keep each as original list length, so increase MAX_GRO_SKBS to 64
>
> Signed-off-by: Li RongQing <lirongqing@baidu.com>
I would like to hear some feedback from Eric, 64 might be too big.
^ permalink raw reply
* [PATCH][net-next] net: increase MAX_GRO_SKBS to 64
From: Li RongQing @ 2018-07-02 11:41 UTC (permalink / raw)
To: netdev
After 07d78363dcffd [net: Convert NAPI gro list into a small hash table]
there is 8 hash buckets, which allow more flows to be held for merging.
keep each as original list length, so increase MAX_GRO_SKBS to 64
Signed-off-by: Li RongQing <lirongqing@baidu.com>
---
net/core/dev.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/net/core/dev.c b/net/core/dev.c
index 08d58e0debe5..ac315e41d5e7 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -149,8 +149,7 @@
#include "net-sysfs.h"
-/* Instead of increasing this, you should create a hash table. */
-#define MAX_GRO_SKBS 8
+#define MAX_GRO_SKBS 64
/* This should be increased if a protocol with a bigger head is added. */
#define GRO_MAX_HEAD (MAX_HEADER + 128)
--
2.16.2
^ permalink raw reply related
* Re: [PATCHv2 net] ipvlan: call dev_change_flags when ipvlan mode is reset
From: David Miller @ 2018-07-02 11:38 UTC (permalink / raw)
To: liuhangbin; +Cc: netdev, sbrivio, pabeni, maheshb, xiyou.wangcong, sd
In-Reply-To: <1530433281-22743-1-git-send-email-liuhangbin@gmail.com>
From: Hangbin Liu <liuhangbin@gmail.com>
Date: Sun, 1 Jul 2018 16:21:21 +0800
> After we change the ipvlan mode from l3 to l2, or vice versa, we only
> reset IFF_NOARP flag, but don't flush the ARP table cache, which will
> cause eth->h_dest to be equal to eth->h_source in ipvlan_xmit_mode_l2().
> Then the message will not come out of host.
>
> Here is the reproducer on local host:
>
> ip link set eth1 up
> ip addr add 192.168.1.1/24 dev eth1
> ip link add link eth1 ipvlan1 type ipvlan mode l3
>
> ip netns add net1
> ip link set ipvlan1 netns net1
> ip netns exec net1 ip link set ipvlan1 up
> ip netns exec net1 ip addr add 192.168.2.1/24 dev ipvlan1
>
> ip route add 192.168.2.0/24 via 192.168.1.2
> ping 192.168.2.2 -c 2
>
> ip netns exec net1 ip link set ipvlan1 type ipvlan mode l2
> ping 192.168.2.2 -c 2
>
> Add the same configuration on remote host. After we set the mode to l2,
> we could find that the src/dst MAC addresses are the same on eth1:
>
> 21:26:06.648565 00:b7:13:ad:d3:05 > 00:b7:13:ad:d3:05, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 64, id 58356, offset 0, flags [DF], proto ICMP (1), length 84)
> 192.168.2.1 > 192.168.2.2: ICMP echo request, id 22686, seq 1, length 64
>
> Fix this by calling dev_change_flags(), which will call netdevice notifier
> with flag change info.
>
> v2:
> a) As pointed out by Wang Cong, check return value for dev_change_flags() when
> change dev flags.
> b) As suggested by Stefano and Sabrina, move flags setting before l3mdev_ops.
> So we don't need to redo ipvlan_{, un}register_nf_hook() again in err path.
>
> Reported-by: Jianlin Shi <jishi@redhat.com>
> Reviewed-by: Stefano Brivio <sbrivio@redhat.com>
> Reviewed-by: Sabrina Dubroca <sd@queasysnail.net>
> Fixes: 2ad7bf3638411 ("ipvlan: Initial check-in of the IPVLAN driver.")
> Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
Applied, thank you.
^ permalink raw reply
* Re: [PATCH net] ipv6: sr: fix passing wrong flags to crypto_alloc_shash()
From: David Miller @ 2018-07-02 11:37 UTC (permalink / raw)
To: ebiggers3; +Cc: netdev, david.lebrun, linux-crypto, ebiggers
In-Reply-To: <20180630222656.333-1-ebiggers3@gmail.com>
From: Eric Biggers <ebiggers3@gmail.com>
Date: Sat, 30 Jun 2018 15:26:56 -0700
> From: Eric Biggers <ebiggers@google.com>
>
> The 'mask' argument to crypto_alloc_shash() uses the CRYPTO_ALG_* flags,
> not 'gfp_t'. So don't pass GFP_KERNEL to it.
>
> Fixes: bf355b8d2c30 ("ipv6: sr: add core files for SR HMAC support")
> Signed-off-by: Eric Biggers <ebiggers@google.com>
Oops, applied and queued up for -stable, thanks!
^ permalink raw reply
* Re: [PATCH][next] netdevsim: fix sa_idx out of bounds check
From: David Miller @ 2018-07-02 11:36 UTC (permalink / raw)
To: colin.king; +Cc: jakub.kicinski, netdev, kernel-janitors, linux-kernel
In-Reply-To: <20180630203924.5121-1-colin.king@canonical.com>
From: Colin King <colin.king@canonical.com>
Date: Sat, 30 Jun 2018 21:39:24 +0100
> From: Colin Ian King <colin.king@canonical.com>
>
> Currently if sa_idx is equal to NSIM_IPSEC_MAX_SA_COUNT then
> an out-of-bounds read on ipsec->sa will occur. Fix the
> incorrect bounds check by using >= rather than >.
>
> Detected by CoverityScan, CID#1470226 ("Out-of-bounds-read")
>
> Fixes: 7699353da875 ("netdevsim: add ipsec offload testing")
> Signed-off-by: Colin Ian King <colin.king@canonical.com>
Applied, thank you.
^ permalink raw reply
* Re: [PATCH net] net: fix use-after-free in GRO with ESP
From: David Miller @ 2018-07-02 11:34 UTC (permalink / raw)
To: sd; +Cc: netdev, sbrivio, steffen.klassert
In-Reply-To: <62edcac57b52aa0546936700f7a0b50a2327806a.1530368567.git.sd@queasysnail.net>
From: Sabrina Dubroca <sd@queasysnail.net>
Date: Sat, 30 Jun 2018 17:38:55 +0200
> Since the addition of GRO for ESP, gro_receive can consume the skb and
> return -EINPROGRESS. In that case, the lower layer GRO handler cannot
> touch the skb anymore.
>
> Commit 5f114163f2f5 ("net: Add a skb_gro_flush_final helper.") converted
> some of the gro_receive handlers that can lead to ESP's gro_receive so
> that they wouldn't access the skb when -EINPROGRESS is returned, but
> missed other spots, mainly in tunneling protocols.
>
> This patch finishes the conversion to using skb_gro_flush_final(), and
> adds a new helper, skb_gro_flush_final_remcsum(), used in VXLAN and
> GUE.
>
> Fixes: 5f114163f2f5 ("net: Add a skb_gro_flush_final helper.")
> Signed-off-by: Sabrina Dubroca <sd@queasysnail.net>
> Reviewed-by: Stefano Brivio <sbrivio@redhat.com>
Applied and queued up for -stable, thank you.
^ permalink raw reply
* Re: [PATCH] wlcore: Fix memory leak in wlcore_cmd_wait_for_event_or_timeout
From: Tony Lindgren @ 2018-07-02 11:30 UTC (permalink / raw)
To: Gustavo A. R. Silva
Cc: Kalle Valo, David S. Miller, linux-wireless, netdev, linux-kernel
In-Reply-To: <20180628130809.GA8147@embeddedor.com>
* Gustavo A. R. Silva <gustavo@embeddedor.com> [180628 13:11]:
> In case memory resources for *events_vector* were allocated, release
> them before return.
>
> Addresses-Coverity-ID: 1470194 ("Resource leak")
> Fixes: 4ec7cece87b3 ("wlcore: Add missing PM call for wlcore_cmd_wait_for_event_or_timeout()")
> Signed-off-by: Gustavo A. R. Silva <gustavo@embeddedor.com>
Thanks for catching this one:
Acked-by: Tony Lindgren <tony@atomide.com>
> ---
> drivers/net/wireless/ti/wlcore/cmd.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c
> index 836c616..9039687 100644
> --- a/drivers/net/wireless/ti/wlcore/cmd.c
> +++ b/drivers/net/wireless/ti/wlcore/cmd.c
> @@ -195,8 +195,7 @@ int wlcore_cmd_wait_for_event_or_timeout(struct wl1271 *wl,
> ret = pm_runtime_get_sync(wl->dev);
> if (ret < 0) {
> pm_runtime_put_noidle(wl->dev);
> -
> - return ret;
> + goto free_vector;
> }
>
> do {
> @@ -232,6 +231,7 @@ int wlcore_cmd_wait_for_event_or_timeout(struct wl1271 *wl,
> out:
> pm_runtime_mark_last_busy(wl->dev);
> pm_runtime_put_autosuspend(wl->dev);
> +free_vector:
> kfree(events_vector);
> return ret;
> }
> --
> 2.7.4
>
^ permalink raw reply
* [PATCH v4 1/4] Use dev->intf to get interface information
From: Miguel Rodríguez Pérez @ 2018-07-02 11:28 UTC (permalink / raw)
To: oliver, linux-usb, netdev, gregkh; +Cc: Miguel Rodríguez Pérez
In-Reply-To: <e3e25aa6-9f9a-0643-a644-e8efdf12a562@det.uvigo.gal>
usbnet_cdc_update_filter was getting the interface number from the
usb_interface struct in cdc_state->control. However, cdc_ncm does
not initialize that structure in its bind function, but uses
cdc_ncm_cts instead. Getting intf directly from struct usbnet solves
the problem.
Signed-off-by: Miguel Rodríguez Pérez <miguel@det.uvigo.gal>
---
drivers/net/usb/cdc_ether.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c
index 178b956501a7..beac02cbde51 100644
--- a/drivers/net/usb/cdc_ether.c
+++ b/drivers/net/usb/cdc_ether.c
@@ -77,8 +77,6 @@ static const u8 mbm_guid[16] = {
static void usbnet_cdc_update_filter(struct usbnet *dev)
{
- struct cdc_state *info = (void *) &dev->data;
- struct usb_interface *intf = info->control;
struct net_device *net = dev->net;
u16 cdc_filter = USB_CDC_PACKET_TYPE_DIRECTED
@@ -98,7 +96,7 @@ static void usbnet_cdc_update_filter(struct usbnet *dev)
USB_CDC_SET_ETHERNET_PACKET_FILTER,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
cdc_filter,
- intf->cur_altsetting->desc.bInterfaceNumber,
+ dev->intf->cur_altsetting->desc.bInterfaceNumber,
NULL,
0,
USB_CTRL_SET_TIMEOUT
--
2.17.1
^ permalink raw reply related
* Re: [PATCH v3 1/4] Simplify usbnet_cdc_update_filter
From: Miguel Rodríguez Pérez @ 2018-07-02 11:19 UTC (permalink / raw)
To: Oliver Neukum, gregkh, linux-usb, netdev
In-Reply-To: <1530519944.18402.10.camel@suse.com>
I get a panic if I remove this patch, because intf comes NULL for
cdc_ncm devices. I'll send an updated patch that solves this issue while
still using usb_control_msg.
On 02/07/18 10:25, Oliver Neukum wrote:
> On So, 2018-07-01 at 11:05 +0200, Miguel Rodríguez Pérez wrote:
>> Remove some unneded varibles to make the code easier to read
>> and, replace the generic usb_control_msg function for the
>> more specific usbnet_write_cmd.
>>
>> Signed-off-by: Miguel Rodríguez Pérez <miguel@det.uvigo.gal>
>
> No,
>
> sorry, but this is not good. The reason is a bit subtle.
> Drivers need to reset the filters when handling post_reset()
> [ and reset_resume() ] usbnet_write_cmd() falls back to
> kmemdup() with GFP_KERNEL. Usbnet is a framework with class
> drivers and some of the devices we drive have a storage
> interface. Thence we are on the block error handling path here.
>
> The simplest solution is to leave out this patch in the sequence.
>
> Regards
> Oliver
>
>
> NACKED-BY: Oliver Neukum <oneukum@suse.com>
>
>
>> ---
>> drivers/net/usb/cdc_ether.c | 15 +++++----------
>> 1 file changed, 5 insertions(+), 10 deletions(-)
>>
>> diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c
>> index 178b956501a7..815ed0dc18fe 100644
>> --- a/drivers/net/usb/cdc_ether.c
>> +++ b/drivers/net/usb/cdc_ether.c
>> @@ -77,9 +77,7 @@ static const u8 mbm_guid[16] = {
>>
>> static void usbnet_cdc_update_filter(struct usbnet *dev)
>> {
>> - struct cdc_state *info = (void *) &dev->data;
>> - struct usb_interface *intf = info->control;
>> - struct net_device *net = dev->net;
>> + struct net_device *net = dev->net;
>>
>> u16 cdc_filter = USB_CDC_PACKET_TYPE_DIRECTED
>> | USB_CDC_PACKET_TYPE_BROADCAST;
>> @@ -93,16 +91,13 @@ static void usbnet_cdc_update_filter(struct usbnet *dev)
>> if (!netdev_mc_empty(net) || (net->flags & IFF_ALLMULTI))
>> cdc_filter |= USB_CDC_PACKET_TYPE_ALL_MULTICAST;
>>
>> - usb_control_msg(dev->udev,
>> - usb_sndctrlpipe(dev->udev, 0),
>> + usbnet_write_cmd(dev,
>> USB_CDC_SET_ETHERNET_PACKET_FILTER,
>> - USB_TYPE_CLASS | USB_RECIP_INTERFACE,
>> + USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE,
>> cdc_filter,
>> - intf->cur_altsetting->desc.bInterfaceNumber,
>> + dev->intf->cur_altsetting->desc.bInterfaceNumber,
>> NULL,
>> - 0,
>> - USB_CTRL_SET_TIMEOUT
>> - );
>> + 0);
>> }
>>
>> /* probes control interface, claims data interface, collects the bulk
>
--
Miguel Rodríguez Pérez
Laboratorio de Redes
EE Telecomunicación – Universidade de Vigo
^ permalink raw reply
* Re: [RFC PATCH] ipv6: make ipv6_renew_options() interrupt/kernel safe
From: Paul Moore @ 2018-07-02 11:03 UTC (permalink / raw)
To: netdev; +Cc: Al Viro, selinux, linux-security-module
In-Reply-To: <153050046203.740.13741366203375982437.stgit@chester>
On July 1, 2018 11:01:04 PM Paul Moore <pmoore@redhat.com> wrote:
> From: Paul Moore <paul@paul-moore.com>
>
> At present the ipv6_renew_options_kern() function ends up calling into
> access_ok() which is problematic if done from inside an interrupt as
> access_ok() calls WARN_ON_IN_IRQ() on some (all?) architectures
> (x86-64 is affected). Example warning/backtrace is shown below:
>
> WARNING: CPU: 1 PID: 3144 at lib/usercopy.c:11 _copy_from_user+0x85/0x90
> ...
> Call Trace:
> <IRQ>
> ipv6_renew_option+0xb2/0xf0
> ipv6_renew_options+0x26a/0x340
> ipv6_renew_options_kern+0x2c/0x40
> calipso_req_setattr+0x72/0xe0
> netlbl_req_setattr+0x126/0x1b0
> selinux_netlbl_inet_conn_request+0x80/0x100
> selinux_inet_conn_request+0x6d/0xb0
> security_inet_conn_request+0x32/0x50
> tcp_conn_request+0x35f/0xe00
> ? __lock_acquire+0x250/0x16c0
> ? selinux_socket_sock_rcv_skb+0x1ae/0x210
> ? tcp_rcv_state_process+0x289/0x106b
> tcp_rcv_state_process+0x289/0x106b
> ? tcp_v6_do_rcv+0x1a7/0x3c0
> tcp_v6_do_rcv+0x1a7/0x3c0
> tcp_v6_rcv+0xc82/0xcf0
> ip6_input_finish+0x10d/0x690
> ip6_input+0x45/0x1e0
> ? ip6_rcv_finish+0x1d0/0x1d0
> ipv6_rcv+0x32b/0x880
> ? ip6_make_skb+0x1e0/0x1e0
> __netif_receive_skb_core+0x6f2/0xdf0
> ? process_backlog+0x85/0x250
> ? process_backlog+0x85/0x250
> ? process_backlog+0xec/0x250
> process_backlog+0xec/0x250
> net_rx_action+0x153/0x480
> __do_softirq+0xd9/0x4f7
> do_softirq_own_stack+0x2a/0x40
> </IRQ>
> ...
>
> While not present in the backtrace, ipv6_renew_option() ends up calling
> access_ok() via the following chain:
>
> access_ok()
> _copy_from_user()
> copy_from_user()
> ipv6_renew_option()
>
> The fix presented in this patch is to perform the userspace copy
> earlier in the call chain such that it is only called when the option
> data is actually coming from userspace; that place is
> do_ipv6_setsockopt(). Not only does this solve the problem seen in
> the backtrace above, it also allows us to simplify the code quite a
> bit by removing ipv6_renew_options_kern() completely. We also take
> this opportunity to cleanup ipv6_renew_options()/ipv6_renew_option()
> a small amount as well.
>
> This patch is heavily based on a rough patch by Al Viro. I've taken
> his original patch, converted a kmemdup() call in do_ipv6_setsockopt()
> to a memdup_user() call, made better use of the e_inval jump target in
> the same function, and cleaned up the use ipv6_renew_option() by
> ipv6_renew_options().
>
> CC: Al Viro <viro@zeniv.linux.org.uk>
> Signed-off-by: Paul Moore <paul@paul-moore.com>
> ---
> include/net/ipv6.h | 9 ----
> net/ipv6/calipso.c | 9 +---
> net/ipv6/exthdrs.c | 108 ++++++++++++----------------------------------
> net/ipv6/ipv6_sockglue.c | 27 ++++++++----
> 4 files changed, 50 insertions(+), 103 deletions(-)
Hold off on this patch, while it worked for me, I just received a bug report from Intel's 0day robot that I want to chase down.
> diff --git a/include/net/ipv6.h b/include/net/ipv6.h
> index 16475c269749..d02881e4ad1f 100644
> --- a/include/net/ipv6.h
> +++ b/include/net/ipv6.h
> @@ -355,14 +355,7 @@ struct ipv6_txoptions *ipv6_dup_options(struct sock *sk,
> struct ipv6_txoptions *ipv6_renew_options(struct sock *sk,
> struct ipv6_txoptions *opt,
> int newtype,
> - struct ipv6_opt_hdr __user *newopt,
> - int newoptlen);
> -struct ipv6_txoptions *
> -ipv6_renew_options_kern(struct sock *sk,
> - struct ipv6_txoptions *opt,
> - int newtype,
> - struct ipv6_opt_hdr *newopt,
> - int newoptlen);
> + struct ipv6_opt_hdr *newopt);
> struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space,
> struct ipv6_txoptions *opt);
>
> diff --git a/net/ipv6/calipso.c b/net/ipv6/calipso.c
> index 1323b9679cf7..1c0bb9fb76e6 100644
> --- a/net/ipv6/calipso.c
> +++ b/net/ipv6/calipso.c
> @@ -799,8 +799,7 @@ static int calipso_opt_update(struct sock *sk, struct ipv6_opt_hdr *hop)
> {
> struct ipv6_txoptions *old = txopt_get(inet6_sk(sk)), *txopts;
>
> - txopts = ipv6_renew_options_kern(sk, old, IPV6_HOPOPTS,
> - hop, hop ? ipv6_optlen(hop) : 0);
> + txopts = ipv6_renew_options(sk, old, IPV6_HOPOPTS, hop);
> txopt_put(old);
> if (IS_ERR(txopts))
> return PTR_ERR(txopts);
> @@ -1222,8 +1221,7 @@ static int calipso_req_setattr(struct request_sock *req,
> if (IS_ERR(new))
> return PTR_ERR(new);
>
> - txopts = ipv6_renew_options_kern(sk, req_inet->ipv6_opt, IPV6_HOPOPTS,
> - new, new ? ipv6_optlen(new) : 0);
> + txopts = ipv6_renew_options(sk, req_inet->ipv6_opt, IPV6_HOPOPTS, new);
>
> kfree(new);
>
> @@ -1260,8 +1258,7 @@ static void calipso_req_delattr(struct request_sock *req)
> if (calipso_opt_del(req_inet->ipv6_opt->hopopt, &new))
> return; /* Nothing to do */
>
> - txopts = ipv6_renew_options_kern(sk, req_inet->ipv6_opt, IPV6_HOPOPTS,
> - new, new ? ipv6_optlen(new) : 0);
> + txopts = ipv6_renew_options(sk, req_inet->ipv6_opt, IPV6_HOPOPTS, new);
>
> if (!IS_ERR(txopts)) {
> txopts = xchg(&req_inet->ipv6_opt, txopts);
> diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
> index 5bc2bf3733ab..1e1d9bc2fd3d 100644
> --- a/net/ipv6/exthdrs.c
> +++ b/net/ipv6/exthdrs.c
> @@ -1015,29 +1015,21 @@ ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt)
> }
> EXPORT_SYMBOL_GPL(ipv6_dup_options);
>
> -static int ipv6_renew_option(void *ohdr,
> - struct ipv6_opt_hdr __user *newopt, int newoptlen,
> - int inherit,
> - struct ipv6_opt_hdr **hdr,
> - char **p)
> +static void ipv6_renew_option(int renewtype,
> + struct ipv6_opt_hdr **dest,
> + struct ipv6_opt_hdr *old,
> + struct ipv6_opt_hdr *new,
> + int newtype, char **p)
> {
> - if (inherit) {
> - if (ohdr) {
> - memcpy(*p, ohdr, ipv6_optlen((struct ipv6_opt_hdr *)ohdr));
> - *hdr = (struct ipv6_opt_hdr *)*p;
> - *p += CMSG_ALIGN(ipv6_optlen(*hdr));
> - }
> - } else {
> - if (newopt) {
> - if (copy_from_user(*p, newopt, newoptlen))
> - return -EFAULT;
> - *hdr = (struct ipv6_opt_hdr *)*p;
> - if (ipv6_optlen(*hdr) > newoptlen)
> - return -EINVAL;
> - *p += CMSG_ALIGN(newoptlen);
> - }
> - }
> - return 0;
> + struct ipv6_opt_hdr *src;
> +
> + src = (renewtype == newtype ? new : old);
> + if (!src)
> + return;
> +
> + memcpy(*p, src, ipv6_optlen(src));
> + *dest = (struct ipv6_opt_hdr *)*p;
> + p += CMSG_ALIGN(ipv6_optlen(*dest));
> }
>
> /**
> @@ -1063,13 +1055,11 @@ static int ipv6_renew_option(void *ohdr,
> */
> struct ipv6_txoptions *
> ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt,
> - int newtype,
> - struct ipv6_opt_hdr __user *newopt, int newoptlen)
> + int newtype, struct ipv6_opt_hdr *newopt)
> {
> int tot_len = 0;
> char *p;
> struct ipv6_txoptions *opt2;
> - int err;
>
> if (opt) {
> if (newtype != IPV6_HOPOPTS && opt->hopopt)
> @@ -1082,8 +1072,8 @@ ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt,
> tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst1opt));
> }
>
> - if (newopt && newoptlen)
> - tot_len += CMSG_ALIGN(newoptlen);
> + if (newopt)
> + tot_len += CMSG_ALIGN(ipv6_optlen(newopt));
>
> if (!tot_len)
> return NULL;
> @@ -1098,29 +1088,16 @@ ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt,
> opt2->tot_len = tot_len;
> p = (char *)(opt2 + 1);
>
> - err = ipv6_renew_option(opt ? opt->hopopt : NULL, newopt, newoptlen,
> - newtype != IPV6_HOPOPTS,
> - &opt2->hopopt, &p);
> - if (err)
> - goto out;
> -
> - err = ipv6_renew_option(opt ? opt->dst0opt : NULL, newopt, newoptlen,
> - newtype != IPV6_RTHDRDSTOPTS,
> - &opt2->dst0opt, &p);
> - if (err)
> - goto out;
> -
> - err = ipv6_renew_option(opt ? opt->srcrt : NULL, newopt, newoptlen,
> - newtype != IPV6_RTHDR,
> - (struct ipv6_opt_hdr **)&opt2->srcrt, &p);
> - if (err)
> - goto out;
> -
> - err = ipv6_renew_option(opt ? opt->dst1opt : NULL, newopt, newoptlen,
> - newtype != IPV6_DSTOPTS,
> - &opt2->dst1opt, &p);
> - if (err)
> - goto out;
> + ipv6_renew_option(IPV6_HOPOPTS, &opt2->hopopt, opt->hopopt,
> + newopt, newtype, &p);
> + ipv6_renew_option(IPV6_RTHDRDSTOPTS, &opt2->dst0opt, opt->dst0opt,
> + newopt, newtype, &p);
> + ipv6_renew_option(IPV6_RTHDR,
> + (struct ipv6_opt_hdr **)&opt2->srcrt,
> + (struct ipv6_opt_hdr *)opt->srcrt,
> + newopt, newtype, &p);
> + ipv6_renew_option(IPV6_DSTOPTS, &opt2->dst1opt, opt->dst1opt,
> + newopt, newtype, &p);
>
> opt2->opt_nflen = (opt2->hopopt ? ipv6_optlen(opt2->hopopt) : 0) +
> (opt2->dst0opt ? ipv6_optlen(opt2->dst0opt) : 0) +
> @@ -1128,37 +1105,6 @@ ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt,
> opt2->opt_flen = (opt2->dst1opt ? ipv6_optlen(opt2->dst1opt) : 0);
>
> return opt2;
> -out:
> - sock_kfree_s(sk, opt2, opt2->tot_len);
> - return ERR_PTR(err);
> -}
> -
> -/**
> - * ipv6_renew_options_kern - replace a specific ext hdr with a new one.
> - *
> - * @sk: sock from which to allocate memory
> - * @opt: original options
> - * @newtype: option type to replace in @opt
> - * @newopt: new option of type @newtype to replace (kernel-mem)
> - * @newoptlen: length of @newopt
> - *
> - * See ipv6_renew_options(). The difference is that @newopt is
> - * kernel memory, rather than user memory.
> - */
> -struct ipv6_txoptions *
> -ipv6_renew_options_kern(struct sock *sk, struct ipv6_txoptions *opt,
> - int newtype, struct ipv6_opt_hdr *newopt,
> - int newoptlen)
> -{
> - struct ipv6_txoptions *ret_val;
> - const mm_segment_t old_fs = get_fs();
> -
> - set_fs(KERNEL_DS);
> - ret_val = ipv6_renew_options(sk, opt, newtype,
> - (struct ipv6_opt_hdr __user *)newopt,
> - newoptlen);
> - set_fs(old_fs);
> - return ret_val;
> }
>
> struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space,
> diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
> index 4d780c7f0130..c95c3486d904 100644
> --- a/net/ipv6/ipv6_sockglue.c
> +++ b/net/ipv6/ipv6_sockglue.c
> @@ -398,6 +398,12 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
> case IPV6_DSTOPTS:
> {
> struct ipv6_txoptions *opt;
> + struct ipv6_opt_hdr *new = NULL;
> +
> + /* hop-by-hop / destination options are privileged option */
> + retv = -EPERM;
> + if (optname != IPV6_RTHDR && !ns_capable(net->user_ns, CAP_NET_RAW))
> + break;
>
> /* remove any sticky options header with a zero option
> * length, per RFC3542.
> @@ -409,17 +415,22 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
> else if (optlen < sizeof(struct ipv6_opt_hdr) ||
> optlen & 0x7 || optlen > 8 * 255)
> goto e_inval;
> -
> - /* hop-by-hop / destination options are privileged option */
> - retv = -EPERM;
> - if (optname != IPV6_RTHDR && !ns_capable(net->user_ns, CAP_NET_RAW))
> - break;
> + else {
> + new = memdup_user(optval, optlen);
> + if (IS_ERR(new)) {
> + retv = PTR_ERR(new);
> + break;
> + }
> + if (unlikely(ipv6_optlen(new) > optlen)) {
> + kfree(new);
> + goto e_inval;
> + }
> + }
>
> opt = rcu_dereference_protected(np->opt,
> lockdep_sock_is_held(sk));
> - opt = ipv6_renew_options(sk, opt, optname,
> - (struct ipv6_opt_hdr __user *)optval,
> - optlen);
> + opt = ipv6_renew_options(sk, opt, optname, new);
> + kfree(new);
> if (IS_ERR(opt)) {
> retv = PTR_ERR(opt);
> break;
^ permalink raw reply
* Re: [PATCH net] tcp: prevent bogus FRTO undos with non-SACK flows
From: Ilpo Järvinen @ 2018-07-02 10:26 UTC (permalink / raw)
To: Neal Cardwell; +Cc: Netdev, Yuchung Cheng, Eric Dumazet, Michal Kubecek
In-Reply-To: <CADVnQymia_drxUkUP1V8MvqCObyKUXhg+xjrssef9S5D8GYnKw@mail.gmail.com>
On Sat, 30 Jun 2018, Neal Cardwell wrote:
> As I mentioned, I ran your patch through all our team's TCP
> packetdrill tests, and it passes all of the tests. One of our tests
> needed updating, because if there is a non-SACK connection with a
> spurious RTO due to a delayed flight of ACKs then the FRTO undo now
> happens one ACK later (when we get an ACK that doesn't cover a
> retransmit). But that seems fine to me.
Yes, this is what is wanted. The non-SACK FRTO cannot make decision on
the first cumulative ACK because that could be (often is) triggered by the
retransmit but only from the next ACK after that.
Even with SACK FRTO, there is a hazard on doing it that early as tail ACK
losses can lead to discovery of newly SACKed skbs from ACK of the
retransmitted segment. For that to occur, however, the cumulative ACK
cannot cover those skbs implying more holes that need to be recovered.
Therefore, the window reduction will eventually occur anyway but it would
still first do a bogus undo also in that case.
> I also cooked the new packetdrill test below to explicitly cover this
> case you are addressing (please let me know if you have an alternate
> suggestion).
>
> Tested-by: Neal Cardwell <ncardwell@google.com>
> Acked-by: Neal Cardwell <ncardwell@google.com>
>
> Thanks!
> neal
>
> ---
>
> 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
> +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
> +0 bind(3, ..., ...) = 0
> +0 listen(3, 1) = 0
>
> +0 < S 0:0(0) win 32792 <mss 1000,nop,wscale 7>
> +0 > S. 0:0(0) ack 1 <mss 1460,nop,wscale 8>
> +.02 < . 1:1(0) ack 1 win 257
> +0 accept(3, ..., ...) = 4
>
> // Send 3 packets. First is really lost. And the dupacks
> // for the data packets that arrived at the reciver are slow in arriving.
> +0 write(4, ..., 3000) = 3000
> +0 > P. 1:3001(3000) ack 1
>
> // RTO and retransmit head. This fills a real loss.
> +.22 > . 1:1001(1000) ack 1
>
> // Dupacks for packets 2 and 3 arrive.
> +.02 < . 1:1(0) ack 1 win 257
> +0 < . 1:1(0) ack 1 win 257
>
> // The cumulative ACK for all the data arrives. We do not undo, because
> // this is a non-SACK connection, and retransmitted data was ACKed.
> // It's good that there's no FRTO undo, since a packet was really lost.
> // Because this is non-SACK, tcp_try_undo_recovery() holds CA_Loss
> // until something beyond high_seq is ACKed.
> +.005 < . 1:1(0) ack 3001 win 257
> +0 %{ assert tcpi_ca_state == TCP_CA_Loss, tcpi_ca_state }%
> +0 %{ assert tcpi_snd_cwnd == 4, tcpi_snd_cwnd }%
> +0 %{ assert tcpi_snd_ssthresh == 7, tcpi_snd_ssthresh }%
I think that the snd_cwnd is still fishy there but that would
require also the other patch from my series (cwnd was 1 so it should be 2
after the cumulative ACK).
--
i.
^ permalink raw reply
* [PATCHv2 net-next 5/5] sctp: check for ipv6_pinfo legal sndflow with flowlabel in sctp_v6_get_dst
From: Xin Long @ 2018-07-02 10:21 UTC (permalink / raw)
To: network dev, linux-sctp
Cc: Marcelo Ricardo Leitner, Neil Horman, davem, hideaki.yoshifuji
In-Reply-To: <cover.1530526661.git.lucien.xin@gmail.com>
The transport with illegal flowlabel should not be allowed to send
packets. Other transport protocols already denies this.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
net/sctp/ipv6.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index 772513d..d83ddc4 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -262,6 +262,15 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
if (t->flowlabel & SCTP_FLOWLABEL_SET_MASK)
fl6->flowlabel = htonl(t->flowlabel & SCTP_FLOWLABEL_VAL_MASK);
+ if (np->sndflow && (fl6->flowlabel & IPV6_FLOWLABEL_MASK)) {
+ struct ip6_flowlabel *flowlabel;
+
+ flowlabel = fl6_sock_lookup(sk, fl6->flowlabel);
+ if (!flowlabel)
+ goto out;
+ fl6_sock_release(flowlabel);
+ }
+
pr_debug("%s: dst=%pI6 ", __func__, &fl6->daddr);
if (asoc)
--
2.1.0
^ permalink raw reply related
* [PATCHv2 net-next 4/5] sctp: add support for setting flowlabel when adding a transport
From: Xin Long @ 2018-07-02 10:21 UTC (permalink / raw)
To: network dev, linux-sctp
Cc: Marcelo Ricardo Leitner, Neil Horman, davem, hideaki.yoshifuji
In-Reply-To: <cover.1530526661.git.lucien.xin@gmail.com>
Struct sockaddr_in6 has the member sin6_flowinfo that includes the
ipv6 flowlabel, it should also support for setting flowlabel when
adding a transport whose ipaddr is from userspace.
Note that addrinfo in sctp_sendmsg is using struct in6_addr for
the secondary addrs, which doesn't contain sin6_flowinfo, and
it needs to copy sin6_flowinfo from the primary addr.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
net/sctp/associola.c | 12 ++++++++++--
net/sctp/socket.c | 5 +++++
2 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index 16ecfbc..297d9cf 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -650,8 +650,16 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
peer->sackdelay = asoc->sackdelay;
peer->sackfreq = asoc->sackfreq;
- if (addr->sa.sa_family == AF_INET6)
- peer->flowlabel = asoc->flowlabel;
+ if (addr->sa.sa_family == AF_INET6) {
+ __be32 info = addr->v6.sin6_flowinfo;
+
+ if (info) {
+ peer->flowlabel = ntohl(info & IPV6_FLOWLABEL_MASK);
+ peer->flowlabel |= SCTP_FLOWLABEL_SET_MASK;
+ } else {
+ peer->flowlabel = asoc->flowlabel;
+ }
+ }
peer->dscp = asoc->dscp;
/* Enable/disable heartbeat, SACK delay, and path MTU discovery
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 452029f..2607b50 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -1697,6 +1697,7 @@ static int sctp_sendmsg_new_asoc(struct sock *sk, __u16 sflags,
struct sctp_association *asoc;
enum sctp_scope scope;
struct cmsghdr *cmsg;
+ __be32 flowinfo = 0;
struct sctp_af *af;
int err;
@@ -1781,6 +1782,9 @@ static int sctp_sendmsg_new_asoc(struct sock *sk, __u16 sflags,
if (!cmsgs->addrs_msg)
return 0;
+ if (daddr->sa.sa_family == AF_INET6)
+ flowinfo = daddr->v6.sin6_flowinfo;
+
/* sendv addr list parse */
for_each_cmsghdr(cmsg, cmsgs->addrs_msg) {
struct sctp_transport *transport;
@@ -1813,6 +1817,7 @@ static int sctp_sendmsg_new_asoc(struct sock *sk, __u16 sflags,
}
dlen = sizeof(struct in6_addr);
+ daddr->v6.sin6_flowinfo = flowinfo;
daddr->v6.sin6_family = AF_INET6;
daddr->v6.sin6_port = htons(asoc->peer.port);
memcpy(&daddr->v6.sin6_addr, CMSG_DATA(cmsg), dlen);
--
2.1.0
^ permalink raw reply related
* [PATCHv2 net-next 3/5] sctp: add spp_ipv6_flowlabel and spp_dscp for sctp_paddrparams
From: Xin Long @ 2018-07-02 10:21 UTC (permalink / raw)
To: network dev, linux-sctp
Cc: Marcelo Ricardo Leitner, Neil Horman, davem, hideaki.yoshifuji
In-Reply-To: <cover.1530526661.git.lucien.xin@gmail.com>
spp_ipv6_flowlabel and spp_dscp are added in sctp_paddrparams in
this patch so that users could set sctp_sock/asoc/transport dscp
and flowlabel with spp_flags SPP_IPV6_FLOWLABEL or SPP_DSCP by
SCTP_PEER_ADDR_PARAMS , as described section 8.1.12 in RFC6458.
As said in last patch, it uses '| 0x100000' or '|0x1' to mark
flowlabel or dscp is set, so that their values could be set
to 0.
Note that to guarantee that an old app built with old kernel
headers could work on the newer kernel, the param's check in
sctp_g/setsockopt_peer_addr_params() is also improved, which
follows the way that sctp_g/setsockopt_delayed_ack() or some
other sockopts' process that accept two types of params does.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
include/uapi/linux/sctp.h | 4 ++
net/sctp/socket.c | 177 ++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 175 insertions(+), 6 deletions(-)
diff --git a/include/uapi/linux/sctp.h b/include/uapi/linux/sctp.h
index c02986a..b479db5 100644
--- a/include/uapi/linux/sctp.h
+++ b/include/uapi/linux/sctp.h
@@ -763,6 +763,8 @@ enum sctp_spp_flags {
SPP_SACKDELAY_DISABLE = 1<<6, /*Disable SACK*/
SPP_SACKDELAY = SPP_SACKDELAY_ENABLE | SPP_SACKDELAY_DISABLE,
SPP_HB_TIME_IS_ZERO = 1<<7, /* Set HB delay to 0 */
+ SPP_IPV6_FLOWLABEL = 1<<8,
+ SPP_DSCP = 1<<9,
};
struct sctp_paddrparams {
@@ -773,6 +775,8 @@ struct sctp_paddrparams {
__u32 spp_pathmtu;
__u32 spp_sackdelay;
__u32 spp_flags;
+ __u32 spp_ipv6_flowlabel;
+ __u8 spp_dscp;
} __attribute__((packed, aligned(4)));
/*
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index bf11f9c..452029f 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -2393,6 +2393,8 @@ static int sctp_setsockopt_autoclose(struct sock *sk, char __user *optval,
* uint32_t spp_pathmtu;
* uint32_t spp_sackdelay;
* uint32_t spp_flags;
+ * uint32_t spp_ipv6_flowlabel;
+ * uint8_t spp_dscp;
* };
*
* spp_assoc_id - (one-to-many style socket) This is filled in the
@@ -2472,6 +2474,45 @@ static int sctp_setsockopt_autoclose(struct sock *sk, char __user *optval,
* also that this field is mutually exclusive to
* SPP_SACKDELAY_ENABLE, setting both will have undefined
* results.
+ *
+ * SPP_IPV6_FLOWLABEL: Setting this flag enables the
+ * setting of the IPV6 flow label value. The value is
+ * contained in the spp_ipv6_flowlabel field.
+ * Upon retrieval, this flag will be set to indicate that
+ * the spp_ipv6_flowlabel field has a valid value returned.
+ * If a specific destination address is set (in the
+ * spp_address field), then the value returned is that of
+ * the address. If just an association is specified (and
+ * no address), then the association's default flow label
+ * is returned. If neither an association nor a destination
+ * is specified, then the socket's default flow label is
+ * returned. For non-IPv6 sockets, this flag will be left
+ * cleared.
+ *
+ * SPP_DSCP: Setting this flag enables the setting of the
+ * Differentiated Services Code Point (DSCP) value
+ * associated with either the association or a specific
+ * address. The value is obtained in the spp_dscp field.
+ * Upon retrieval, this flag will be set to indicate that
+ * the spp_dscp field has a valid value returned. If a
+ * specific destination address is set when called (in the
+ * spp_address field), then that specific destination
+ * address's DSCP value is returned. If just an association
+ * is specified, then the association's default DSCP is
+ * returned. If neither an association nor a destination is
+ * specified, then the socket's default DSCP is returned.
+ *
+ * spp_ipv6_flowlabel
+ * - This field is used in conjunction with the
+ * SPP_IPV6_FLOWLABEL flag and contains the IPv6 flow label.
+ * The 20 least significant bits are used for the flow
+ * label. This setting has precedence over any IPv6-layer
+ * setting.
+ *
+ * spp_dscp - This field is used in conjunction with the SPP_DSCP flag
+ * and contains the DSCP. The 6 most significant bits are
+ * used for the DSCP. This setting has precedence over any
+ * IPv4- or IPv6- layer setting.
*/
static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params,
struct sctp_transport *trans,
@@ -2611,6 +2652,51 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params,
}
}
+ if (params->spp_flags & SPP_IPV6_FLOWLABEL) {
+ if (trans && trans->ipaddr.sa.sa_family == AF_INET6) {
+ trans->flowlabel = params->spp_ipv6_flowlabel &
+ SCTP_FLOWLABEL_VAL_MASK;
+ trans->flowlabel |= SCTP_FLOWLABEL_SET_MASK;
+ } else if (asoc) {
+ list_for_each_entry(trans,
+ &asoc->peer.transport_addr_list,
+ transports) {
+ if (trans->ipaddr.sa.sa_family != AF_INET6)
+ continue;
+ trans->flowlabel = params->spp_ipv6_flowlabel &
+ SCTP_FLOWLABEL_VAL_MASK;
+ trans->flowlabel |= SCTP_FLOWLABEL_SET_MASK;
+ }
+ asoc->flowlabel = params->spp_ipv6_flowlabel &
+ SCTP_FLOWLABEL_VAL_MASK;
+ asoc->flowlabel |= SCTP_FLOWLABEL_SET_MASK;
+ } else if (sctp_opt2sk(sp)->sk_family == AF_INET6) {
+ sp->flowlabel = params->spp_ipv6_flowlabel &
+ SCTP_FLOWLABEL_VAL_MASK;
+ sp->flowlabel |= SCTP_FLOWLABEL_SET_MASK;
+ }
+ }
+
+ if (params->spp_flags & SPP_DSCP) {
+ if (trans) {
+ trans->dscp = params->spp_dscp & SCTP_DSCP_VAL_MASK;
+ trans->dscp |= SCTP_DSCP_SET_MASK;
+ } else if (asoc) {
+ list_for_each_entry(trans,
+ &asoc->peer.transport_addr_list,
+ transports) {
+ trans->dscp = params->spp_dscp &
+ SCTP_DSCP_VAL_MASK;
+ trans->dscp |= SCTP_DSCP_SET_MASK;
+ }
+ asoc->dscp = params->spp_dscp & SCTP_DSCP_VAL_MASK;
+ asoc->dscp |= SCTP_DSCP_SET_MASK;
+ } else {
+ sp->dscp = params->spp_dscp & SCTP_DSCP_VAL_MASK;
+ sp->dscp |= SCTP_DSCP_SET_MASK;
+ }
+ }
+
return 0;
}
@@ -2625,11 +2711,18 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk,
int error;
int hb_change, pmtud_change, sackdelay_change;
- if (optlen != sizeof(struct sctp_paddrparams))
+ if (optlen == sizeof(params)) {
+ if (copy_from_user(¶ms, optval, optlen))
+ return -EFAULT;
+ } else if (optlen == ALIGN(offsetof(struct sctp_paddrparams,
+ spp_ipv6_flowlabel), 4)) {
+ if (copy_from_user(¶ms, optval, optlen))
+ return -EFAULT;
+ if (params.spp_flags & (SPP_DSCP | SPP_IPV6_FLOWLABEL))
+ return -EINVAL;
+ } else {
return -EINVAL;
-
- if (copy_from_user(¶ms, optval, optlen))
- return -EFAULT;
+ }
/* Validate flags and value parameters. */
hb_change = params.spp_flags & SPP_HB;
@@ -5453,6 +5546,45 @@ static int sctp_getsockopt_peeloff_flags(struct sock *sk, int len,
* also that this field is mutually exclusive to
* SPP_SACKDELAY_ENABLE, setting both will have undefined
* results.
+ *
+ * SPP_IPV6_FLOWLABEL: Setting this flag enables the
+ * setting of the IPV6 flow label value. The value is
+ * contained in the spp_ipv6_flowlabel field.
+ * Upon retrieval, this flag will be set to indicate that
+ * the spp_ipv6_flowlabel field has a valid value returned.
+ * If a specific destination address is set (in the
+ * spp_address field), then the value returned is that of
+ * the address. If just an association is specified (and
+ * no address), then the association's default flow label
+ * is returned. If neither an association nor a destination
+ * is specified, then the socket's default flow label is
+ * returned. For non-IPv6 sockets, this flag will be left
+ * cleared.
+ *
+ * SPP_DSCP: Setting this flag enables the setting of the
+ * Differentiated Services Code Point (DSCP) value
+ * associated with either the association or a specific
+ * address. The value is obtained in the spp_dscp field.
+ * Upon retrieval, this flag will be set to indicate that
+ * the spp_dscp field has a valid value returned. If a
+ * specific destination address is set when called (in the
+ * spp_address field), then that specific destination
+ * address's DSCP value is returned. If just an association
+ * is specified, then the association's default DSCP is
+ * returned. If neither an association nor a destination is
+ * specified, then the socket's default DSCP is returned.
+ *
+ * spp_ipv6_flowlabel
+ * - This field is used in conjunction with the
+ * SPP_IPV6_FLOWLABEL flag and contains the IPv6 flow label.
+ * The 20 least significant bits are used for the flow
+ * label. This setting has precedence over any IPv6-layer
+ * setting.
+ *
+ * spp_dscp - This field is used in conjunction with the SPP_DSCP flag
+ * and contains the DSCP. The 6 most significant bits are
+ * used for the DSCP. This setting has precedence over any
+ * IPv4- or IPv6- layer setting.
*/
static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len,
char __user *optval, int __user *optlen)
@@ -5462,9 +5594,15 @@ static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len,
struct sctp_association *asoc = NULL;
struct sctp_sock *sp = sctp_sk(sk);
- if (len < sizeof(struct sctp_paddrparams))
+ if (len >= sizeof(params))
+ len = sizeof(params);
+ else if (len >= ALIGN(offsetof(struct sctp_paddrparams,
+ spp_ipv6_flowlabel), 4))
+ len = ALIGN(offsetof(struct sctp_paddrparams,
+ spp_ipv6_flowlabel), 4);
+ else
return -EINVAL;
- len = sizeof(struct sctp_paddrparams);
+
if (copy_from_user(¶ms, optval, len))
return -EFAULT;
@@ -5499,6 +5637,15 @@ static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len,
/*draft-11 doesn't say what to return in spp_flags*/
params.spp_flags = trans->param_flags;
+ if (trans->flowlabel & SCTP_FLOWLABEL_SET_MASK) {
+ params.spp_ipv6_flowlabel = trans->flowlabel &
+ SCTP_FLOWLABEL_VAL_MASK;
+ params.spp_flags |= SPP_IPV6_FLOWLABEL;
+ }
+ if (trans->dscp & SCTP_DSCP_SET_MASK) {
+ params.spp_dscp = trans->dscp & SCTP_DSCP_VAL_MASK;
+ params.spp_flags |= SPP_DSCP;
+ }
} else if (asoc) {
/* Fetch association values. */
params.spp_hbinterval = jiffies_to_msecs(asoc->hbinterval);
@@ -5508,6 +5655,15 @@ static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len,
/*draft-11 doesn't say what to return in spp_flags*/
params.spp_flags = asoc->param_flags;
+ if (asoc->flowlabel & SCTP_FLOWLABEL_SET_MASK) {
+ params.spp_ipv6_flowlabel = asoc->flowlabel &
+ SCTP_FLOWLABEL_VAL_MASK;
+ params.spp_flags |= SPP_IPV6_FLOWLABEL;
+ }
+ if (asoc->dscp & SCTP_DSCP_SET_MASK) {
+ params.spp_dscp = asoc->dscp & SCTP_DSCP_VAL_MASK;
+ params.spp_flags |= SPP_DSCP;
+ }
} else {
/* Fetch socket values. */
params.spp_hbinterval = sp->hbinterval;
@@ -5517,6 +5673,15 @@ static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len,
/*draft-11 doesn't say what to return in spp_flags*/
params.spp_flags = sp->param_flags;
+ if (sp->flowlabel & SCTP_FLOWLABEL_SET_MASK) {
+ params.spp_ipv6_flowlabel = sp->flowlabel &
+ SCTP_FLOWLABEL_VAL_MASK;
+ params.spp_flags |= SPP_IPV6_FLOWLABEL;
+ }
+ if (sp->dscp & SCTP_DSCP_SET_MASK) {
+ params.spp_dscp = sp->dscp & SCTP_DSCP_VAL_MASK;
+ params.spp_flags |= SPP_DSCP;
+ }
}
if (copy_to_user(optval, ¶ms, len))
--
2.1.0
^ permalink raw reply related
* [PATCHv2 net-next 2/5] sctp: add support for dscp and flowlabel per transport
From: Xin Long @ 2018-07-02 10:21 UTC (permalink / raw)
To: network dev, linux-sctp
Cc: Marcelo Ricardo Leitner, Neil Horman, davem, hideaki.yoshifuji
In-Reply-To: <cover.1530526661.git.lucien.xin@gmail.com>
Like some other per transport params, flowlabel and dscp are added
in transport, asoc and sctp_sock. By default, transport sets its
value from asoc's, and asoc does it from sctp_sock. flowlabel
only works for ipv6 transport.
Other than that they need to be passed down in sctp_xmit, flow4/6
also needs to set them before looking up route in get_dst.
Note that it uses '& 0x100000' to check if flowlabel is set and
'& 0x1' (tos 1st bit is unused) to check if dscp is set by users,
so that they could be set to 0 by sockopt in next patch.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
include/linux/sctp.h | 7 +++++++
include/net/sctp/structs.h | 9 +++++++++
net/sctp/associola.c | 7 +++++++
net/sctp/ipv6.c | 11 +++++++++--
net/sctp/protocol.c | 16 ++++++++++++----
5 files changed, 44 insertions(+), 6 deletions(-)
diff --git a/include/linux/sctp.h b/include/linux/sctp.h
index b36c766..83d9434 100644
--- a/include/linux/sctp.h
+++ b/include/linux/sctp.h
@@ -801,4 +801,11 @@ struct sctp_strreset_resptsn {
__be32 receivers_next_tsn;
};
+enum {
+ SCTP_DSCP_SET_MASK = 0x1,
+ SCTP_DSCP_VAL_MASK = 0xfc,
+ SCTP_FLOWLABEL_SET_MASK = 0x100000,
+ SCTP_FLOWLABEL_VAL_MASK = 0xfffff
+};
+
#endif /* __LINUX_SCTP_H__ */
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index 701a517..ab869e0 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -193,6 +193,9 @@ struct sctp_sock {
/* This is the max_retrans value for new associations. */
__u16 pathmaxrxt;
+ __u32 flowlabel;
+ __u8 dscp;
+
/* The initial Path MTU to use for new associations. */
__u32 pathmtu;
@@ -895,6 +898,9 @@ struct sctp_transport {
*/
__u16 pathmaxrxt;
+ __u32 flowlabel;
+ __u8 dscp;
+
/* This is the partially failed retrans value for the transport
* and will be initialized from the assocs value. This can be changed
* using the SCTP_PEER_ADDR_THLDS socket option
@@ -1772,6 +1778,9 @@ struct sctp_association {
*/
__u16 pathmaxrxt;
+ __u32 flowlabel;
+ __u8 dscp;
+
/* Flag that path mtu update is pending */
__u8 pmtu_pending;
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index 5d5a162..16ecfbc 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -115,6 +115,9 @@ static struct sctp_association *sctp_association_init(
/* Initialize path max retrans value. */
asoc->pathmaxrxt = sp->pathmaxrxt;
+ asoc->flowlabel = sp->flowlabel;
+ asoc->dscp = sp->dscp;
+
/* Initialize default path MTU. */
asoc->pathmtu = sp->pathmtu;
@@ -647,6 +650,10 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
peer->sackdelay = asoc->sackdelay;
peer->sackfreq = asoc->sackfreq;
+ if (addr->sa.sa_family == AF_INET6)
+ peer->flowlabel = asoc->flowlabel;
+ peer->dscp = asoc->dscp;
+
/* Enable/disable heartbeat, SACK delay, and path MTU discovery
* based on association setting.
*/
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index 7339918..772513d 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -209,12 +209,17 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport)
struct sock *sk = skb->sk;
struct ipv6_pinfo *np = inet6_sk(sk);
struct flowi6 *fl6 = &transport->fl.u.ip6;
+ __u8 tclass = np->tclass;
int res;
pr_debug("%s: skb:%p, len:%d, src:%pI6 dst:%pI6\n", __func__, skb,
skb->len, &fl6->saddr, &fl6->daddr);
- IP6_ECN_flow_xmit(sk, fl6->flowlabel);
+ if (transport->dscp & SCTP_DSCP_SET_MASK)
+ tclass = transport->dscp & SCTP_DSCP_VAL_MASK;
+
+ if (INET_ECN_is_capable(tclass))
+ IP6_ECN_flow_xmit(sk, fl6->flowlabel);
if (!(transport->param_flags & SPP_PMTUD_ENABLE))
skb->ignore_df = 1;
@@ -223,7 +228,7 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport)
rcu_read_lock();
res = ip6_xmit(sk, skb, fl6, sk->sk_mark, rcu_dereference(np->opt),
- np->tclass);
+ tclass);
rcu_read_unlock();
return res;
}
@@ -254,6 +259,8 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
fl6->flowi6_oif = daddr->v6.sin6_scope_id;
else if (asoc)
fl6->flowi6_oif = asoc->base.sk->sk_bound_dev_if;
+ if (t->flowlabel & SCTP_FLOWLABEL_SET_MASK)
+ fl6->flowlabel = htonl(t->flowlabel & SCTP_FLOWLABEL_VAL_MASK);
pr_debug("%s: dst=%pI6 ", __func__, &fl6->daddr);
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index 5dffbc4..d57fd30 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -426,13 +426,16 @@ static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
struct dst_entry *dst = NULL;
union sctp_addr *daddr = &t->ipaddr;
union sctp_addr dst_saddr;
+ __u8 tos = inet_sk(sk)->tos;
+ if (t->dscp & SCTP_DSCP_SET_MASK)
+ tos = t->dscp & SCTP_DSCP_VAL_MASK;
memset(fl4, 0x0, sizeof(struct flowi4));
fl4->daddr = daddr->v4.sin_addr.s_addr;
fl4->fl4_dport = daddr->v4.sin_port;
fl4->flowi4_proto = IPPROTO_SCTP;
if (asoc) {
- fl4->flowi4_tos = RT_CONN_FLAGS(asoc->base.sk);
+ fl4->flowi4_tos = RT_CONN_FLAGS_TOS(asoc->base.sk, tos);
fl4->flowi4_oif = asoc->base.sk->sk_bound_dev_if;
fl4->fl4_sport = htons(asoc->base.bind_addr.port);
}
@@ -495,7 +498,7 @@ static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
fl4->fl4_sport = laddr->a.v4.sin_port;
flowi4_update_output(fl4,
asoc->base.sk->sk_bound_dev_if,
- RT_CONN_FLAGS(asoc->base.sk),
+ RT_CONN_FLAGS_TOS(asoc->base.sk, tos),
daddr->v4.sin_addr.s_addr,
laddr->a.v4.sin_addr.s_addr);
@@ -971,16 +974,21 @@ static inline int sctp_v4_xmit(struct sk_buff *skb,
struct sctp_transport *transport)
{
struct inet_sock *inet = inet_sk(skb->sk);
+ __u8 dscp = inet->tos;
pr_debug("%s: skb:%p, len:%d, src:%pI4, dst:%pI4\n", __func__, skb,
- skb->len, &transport->fl.u.ip4.saddr, &transport->fl.u.ip4.daddr);
+ skb->len, &transport->fl.u.ip4.saddr,
+ &transport->fl.u.ip4.daddr);
+
+ if (transport->dscp & SCTP_DSCP_SET_MASK)
+ dscp = transport->dscp & SCTP_DSCP_VAL_MASK;
inet->pmtudisc = transport->param_flags & SPP_PMTUD_ENABLE ?
IP_PMTUDISC_DO : IP_PMTUDISC_DONT;
SCTP_INC_STATS(sock_net(&inet->sk), SCTP_MIB_OUTSCTPPACKS);
- return ip_queue_xmit(&inet->sk, skb, &transport->fl);
+ return __ip_queue_xmit(&inet->sk, skb, &transport->fl, dscp);
}
static struct sctp_af sctp_af_inet;
--
2.1.0
^ permalink raw reply related
* [PATCHv2 net-next 1/5] ipv4: add __ip_queue_xmit() that supports tos param
From: Xin Long @ 2018-07-02 10:21 UTC (permalink / raw)
To: network dev, linux-sctp
Cc: Marcelo Ricardo Leitner, Neil Horman, davem, hideaki.yoshifuji
In-Reply-To: <cover.1530526661.git.lucien.xin@gmail.com>
This patch introduces __ip_queue_xmit(), through which the callers
can pass tos param into it without having to set inet->tos. For
ipv6, ip6_xmit() already allows passing tclass parameter.
It's needed when some transport protocol doesn't use inet->tos,
like sctp's per transport dscp, which will be added in next patch.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
include/net/ip.h | 9 ++++++++-
net/ipv4/ip_output.c | 9 +++++----
2 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/include/net/ip.h b/include/net/ip.h
index 0d2281b..09da79d 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -148,7 +148,8 @@ void ip_send_check(struct iphdr *ip);
int __ip_local_out(struct net *net, struct sock *sk, struct sk_buff *skb);
int ip_local_out(struct net *net, struct sock *sk, struct sk_buff *skb);
-int ip_queue_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl);
+int __ip_queue_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
+ __u8 tos);
void ip_init(void);
int ip_append_data(struct sock *sk, struct flowi4 *fl4,
int getfrag(void *from, char *to, int offset, int len,
@@ -174,6 +175,12 @@ struct sk_buff *ip_make_skb(struct sock *sk, struct flowi4 *fl4,
struct ipcm_cookie *ipc, struct rtable **rtp,
struct inet_cork *cork, unsigned int flags);
+static inline int ip_queue_xmit(struct sock *sk, struct sk_buff *skb,
+ struct flowi *fl)
+{
+ return __ip_queue_xmit(sk, skb, fl, inet_sk(sk)->tos);
+}
+
static inline struct sk_buff *ip_finish_skb(struct sock *sk, struct flowi4 *fl4)
{
return __ip_make_skb(sk, fl4, &sk->sk_write_queue, &inet_sk(sk)->cork.base);
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index b3308e9..188cc58 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -423,7 +423,8 @@ static void ip_copy_addrs(struct iphdr *iph, const struct flowi4 *fl4)
}
/* Note: skb->sk can be different from sk, in case of tunnels */
-int ip_queue_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl)
+int __ip_queue_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
+ __u8 tos)
{
struct inet_sock *inet = inet_sk(sk);
struct net *net = sock_net(sk);
@@ -462,7 +463,7 @@ int ip_queue_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl)
inet->inet_dport,
inet->inet_sport,
sk->sk_protocol,
- RT_CONN_FLAGS(sk),
+ RT_CONN_FLAGS_TOS(sk, tos),
sk->sk_bound_dev_if);
if (IS_ERR(rt))
goto no_route;
@@ -478,7 +479,7 @@ int ip_queue_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl)
skb_push(skb, sizeof(struct iphdr) + (inet_opt ? inet_opt->opt.optlen : 0));
skb_reset_network_header(skb);
iph = ip_hdr(skb);
- *((__be16 *)iph) = htons((4 << 12) | (5 << 8) | (inet->tos & 0xff));
+ *((__be16 *)iph) = htons((4 << 12) | (5 << 8) | (tos & 0xff));
if (ip_dont_fragment(sk, &rt->dst) && !skb->ignore_df)
iph->frag_off = htons(IP_DF);
else
@@ -511,7 +512,7 @@ int ip_queue_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl)
kfree_skb(skb);
return -EHOSTUNREACH;
}
-EXPORT_SYMBOL(ip_queue_xmit);
+EXPORT_SYMBOL(__ip_queue_xmit);
static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from)
{
--
2.1.0
^ permalink raw reply related
* [PATCHv2 net-next 0/5] sctp: fully support for dscp and flowlabel per transport
From: Xin Long @ 2018-07-02 10:21 UTC (permalink / raw)
To: network dev, linux-sctp
Cc: Marcelo Ricardo Leitner, Neil Horman, davem, hideaki.yoshifuji
Now dscp and flowlabel are set from sock when sending the packets,
but being multi-homing, sctp also supports for dscp and flowlabel
per transport, which is described in section 8.1.12 in RFC6458.
v1->v2:
- define ip_queue_xmit as inline in net/ip.h, instead of exporting
it in Patch 1/5 according to David's suggestion.
- fix the param len check in sctp_s/getsockopt_peer_addr_params()
in Patch 3/5 to guarantee that an old app built with old kernel
headers could work on the newer kernel per Marcelo's point.
Xin Long (5):
ipv4: add __ip_queue_xmit() that supports tos param
sctp: add support for dscp and flowlabel per transport
sctp: add spp_ipv6_flowlabel and spp_dscp for sctp_paddrparams
sctp: add support for setting flowlabel when adding a transport
sctp: check for ipv6_pinfo legal sndflow with flowlabel in
sctp_v6_get_dst
include/linux/sctp.h | 7 ++
include/net/ip.h | 9 ++-
include/net/sctp/structs.h | 9 +++
include/uapi/linux/sctp.h | 4 +
net/ipv4/ip_output.c | 9 ++-
net/sctp/associola.c | 15 ++++
net/sctp/ipv6.c | 20 ++++-
net/sctp/protocol.c | 16 +++-
net/sctp/socket.c | 182 +++++++++++++++++++++++++++++++++++++++++++--
9 files changed, 254 insertions(+), 17 deletions(-)
--
2.1.0
^ permalink raw reply
* Re: [PATCHv2 net-next 1/2] route: add support for directed broadcast forwarding
From: Davide Caratti @ 2018-07-02 9:57 UTC (permalink / raw)
To: Xin Long, network dev; +Cc: davem, David Ahern, idosch
In-Reply-To: <62ecbcf0c905dde3bfde51cd260e2f7c59e21028.1530512974.git.lucien.xin@gmail.com>
On Mon, 2018-07-02 at 14:30 +0800, Xin Long wrote:
> This patch implements the feature described in rfc1812#section-5.3.5.2
> and rfc2644. It allows the router to forward directed broadcast when
> sysctl bc_forwarding is enabled.
>
> Note that this feature could be done by iptables -j TEE, but it would
> cause some problems:
> - target TEE's gateway param has to be set with a specific address,
> and it's not flexible especially when the route wants forward all
> directed broadcasts.
> - this duplicates the directed broadcasts so this may cause side
> effects to applications.
>
> Besides, to keep consistent with other os router like BSD, it's also
> necessary to implement it in the route rx path.
>
> Note that route cache needs to be flushed when bc_forwarding is
> changed.
>
> Signed-off-by: Xin Long <lucien.xin@gmail.com>
> ---
> include/linux/inetdevice.h | 1 +
> include/uapi/linux/ip.h | 1 +
> include/uapi/linux/netconf.h | 1 +
> net/ipv4/devinet.c | 11 +++++++++++
> net/ipv4/route.c | 6 +++++-
> 5 files changed, 19 insertions(+), 1 deletion(-)
>
> diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h
> index 27650f1..c759d1c 100644
> --- a/include/linux/inetdevice.h
> +++ b/include/linux/inetdevice.h
> @@ -93,6 +93,7 @@ static inline void ipv4_devconf_setall(struct in_device *in_dev)
>
> #define IN_DEV_FORWARD(in_dev) IN_DEV_CONF_GET((in_dev), FORWARDING)
> #define IN_DEV_MFORWARD(in_dev) IN_DEV_ANDCONF((in_dev), MC_FORWARDING)
> +#define IN_DEV_BFORWARD(in_dev) IN_DEV_ANDCONF((in_dev), BC_FORWARDING)
> #define IN_DEV_RPFILTER(in_dev) IN_DEV_MAXCONF((in_dev), RP_FILTER)
> #define IN_DEV_SRC_VMARK(in_dev) IN_DEV_ORCONF((in_dev), SRC_VMARK)
> #define IN_DEV_SOURCE_ROUTE(in_dev) IN_DEV_ANDCONF((in_dev), \
> diff --git a/include/uapi/linux/ip.h b/include/uapi/linux/ip.h
> index b24a742..e42d13b 100644
> --- a/include/uapi/linux/ip.h
> +++ b/include/uapi/linux/ip.h
> @@ -168,6 +168,7 @@ enum
> IPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN,
> IPV4_DEVCONF_DROP_UNICAST_IN_L2_MULTICAST,
> IPV4_DEVCONF_DROP_GRATUITOUS_ARP,
> + IPV4_DEVCONF_BC_FORWARDING,
> __IPV4_DEVCONF_MAX
> };
>
> diff --git a/include/uapi/linux/netconf.h b/include/uapi/linux/netconf.h
> index c84fcdf..fac4edd 100644
> --- a/include/uapi/linux/netconf.h
> +++ b/include/uapi/linux/netconf.h
> @@ -18,6 +18,7 @@ enum {
> NETCONFA_PROXY_NEIGH,
> NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
> NETCONFA_INPUT,
> + NETCONFA_BC_FORWARDING,
> __NETCONFA_MAX
> };
> #define NETCONFA_MAX (__NETCONFA_MAX - 1)
> diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
> index d7585ab..80cb464 100644
> --- a/net/ipv4/devinet.c
> +++ b/net/ipv4/devinet.c
> @@ -1827,6 +1827,8 @@ static int inet_netconf_msgsize_devconf(int type)
> size += nla_total_size(4);
> if (all || type == NETCONFA_MC_FORWARDING)
> size += nla_total_size(4);
> + if (all || type == NETCONFA_BC_FORWARDING)
> + size += nla_total_size(4);
> if (all || type == NETCONFA_PROXY_NEIGH)
> size += nla_total_size(4);
> if (all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN)
> @@ -1873,6 +1875,10 @@ static int inet_netconf_fill_devconf(struct sk_buff *skb, int ifindex,
> nla_put_s32(skb, NETCONFA_MC_FORWARDING,
> IPV4_DEVCONF(*devconf, MC_FORWARDING)) < 0)
> goto nla_put_failure;
> + if ((all || type == NETCONFA_BC_FORWARDING) &&
> + nla_put_s32(skb, NETCONFA_BC_FORWARDING,
> + IPV4_DEVCONF(*devconf, BC_FORWARDING)) < 0)
> + goto nla_put_failure;
> if ((all || type == NETCONFA_PROXY_NEIGH) &&
> nla_put_s32(skb, NETCONFA_PROXY_NEIGH,
> IPV4_DEVCONF(*devconf, PROXY_ARP)) < 0)
> @@ -2143,6 +2149,10 @@ static int devinet_conf_proc(struct ctl_table *ctl, int write,
> if ((new_value == 0) && (old_value != 0))
> rt_cache_flush(net);
>
> + if (i == IPV4_DEVCONF_BC_FORWARDING - 1 ||
> + new_value != old_value)
> + rt_cache_flush(net);
> +
> if (i == IPV4_DEVCONF_RP_FILTER - 1 &&
> new_value != old_value) {
> ifindex = devinet_conf_ifindex(net, cnf);
> @@ -2259,6 +2269,7 @@ static struct devinet_sysctl_table {
> DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding",
> devinet_sysctl_forward),
> DEVINET_SYSCTL_RO_ENTRY(MC_FORWARDING, "mc_forwarding"),
> + DEVINET_SYSCTL_RW_ENTRY(BC_FORWARDING, "bc_forwarding"),
>
> DEVINET_SYSCTL_RW_ENTRY(ACCEPT_REDIRECTS, "accept_redirects"),
> DEVINET_SYSCTL_RW_ENTRY(SECURE_REDIRECTS, "secure_redirects"),
> diff --git a/net/ipv4/route.c b/net/ipv4/route.c
> index 1df6e97..b678466 100644
> --- a/net/ipv4/route.c
> +++ b/net/ipv4/route.c
> @@ -1996,8 +1996,11 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
> goto no_route;
> }
>
> - if (res->type == RTN_BROADCAST)
> + if (res->type == RTN_BROADCAST) {
> + if (IN_DEV_BFORWARD(in_dev))
> + goto make_route;
> goto brd_input;
> + }
>
> if (res->type == RTN_LOCAL) {
> err = fib_validate_source(skb, saddr, daddr, tos,
> @@ -2014,6 +2017,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
> if (res->type != RTN_UNICAST)
> goto martian_destination;
>
> +make_route:
> err = ip_mkroute_input(skb, res, in_dev, daddr, saddr, tos, flkeys);
> out: return err;
>
Acked-by: Davide Caratti <dcaratti@redhat.com>
^ permalink raw reply
* Re: [PATCH 3/4] samples/bpf: Check the error of write() and read()
From: Taeung Song @ 2018-07-02 9:47 UTC (permalink / raw)
To: David Laight, Alexei Starovoitov, Daniel Borkmann
Cc: Teng Qin, netdev@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <c8fd15978e6642158c7e64190e4dee13@AcuMS.aculab.com>
Hi David Laight,
On 07/02/2018 06:25 PM, David Laight wrote:
> From: Taeung Song
>> Sent: 02 July 2018 10:15
>> test_task_rename() and test_urandom_read()
>> can be failed during write() and read(),
>> So check the result of them.
>>
>> Signed-off-by: Taeung Song <treeze.taeung@gmail.com>
>> ---
>> samples/bpf/test_overhead_user.c | 20 +++++++++++++++-----
>> 1 file changed, 15 insertions(+), 5 deletions(-)
>>
>> diff --git a/samples/bpf/test_overhead_user.c b/samples/bpf/test_overhead_user.c
>> index 6caf47a..8a88d9c 100644
>> --- a/samples/bpf/test_overhead_user.c
>> +++ b/samples/bpf/test_overhead_user.c
>> @@ -6,6 +6,7 @@
>> */
>> #define _GNU_SOURCE
>> #include <sched.h>
>> +#include <errno.h>
>> #include <stdio.h>
>> #include <sys/types.h>
>> #include <asm/unistd.h>
>> @@ -44,8 +45,12 @@ static void test_task_rename(int cpu)
>> exit(1);
>> }
>> start_time = time_get_ns();
>> - for (i = 0; i < MAX_CNT; i++)
>> - write(fd, buf, sizeof(buf));
>> + for (i = 0; i < MAX_CNT; i++) {
>> + if (write(fd, buf, sizeof(buf)) < 0) {
>> + printf("task rename failed: %s\n", strerror(errno));
>> + break;
>
> I'm not sure 'break' generates sensible output.
>
OK,
it seems to be better to off on the above error case instead of break;
>> + }
>> + }
>
> What about partial writes??
>
Hum..
do you mean just skipping several errors of the above write() ?
>> printf("task_rename:%d: %lld events per sec\n",
>> cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time));
>> close(fd);
>> @@ -55,7 +60,7 @@ static void test_urandom_read(int cpu)
>> {
>> __u64 start_time;
>> char buf[4];
>> - int i, fd;
>> + int i, fd, err = 0;
>>
>> fd = open("/dev/urandom", O_RDONLY);
>> if (fd < 0) {
>> @@ -63,8 +68,13 @@ static void test_urandom_read(int cpu)
>> exit(1);
>> }
>> start_time = time_get_ns();
>> - for (i = 0; i < MAX_CNT; i++)
>> - read(fd, buf, sizeof(buf));
>> + for (i = 0; i < MAX_CNT; i++) {
>> + err = read(fd, buf, sizeof(buf));
>> + if (err < 0 || err >= sizeof(buf)) {
>
> Overlong reads indicate that something is seriously awry.
> Short reads are valid - but maybe not expected.
>> + printf("failed to read from /dev/urandom: %s\n", strerror(errno));
>
>
> strerror() won't give anything sensible unless err == -1;
> You probably want to include the loop count.
>
>> + break;
>
> The summary print will be gibberish after break.
>
Ditto, will change the code to do exit(1);
on the err == -1 case.
What do you think about it ?
Thanks,
Taeung
>> + }
>> + }
>> printf("urandom_read:%d: %lld events per sec\n",
>> cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time));
>> close(fd);
>> --
>> 2.7.4
>
^ permalink raw reply
* RE: [PATCH 3/4] samples/bpf: Check the error of write() and read()
From: David Laight @ 2018-07-02 9:25 UTC (permalink / raw)
To: 'Taeung Song', Alexei Starovoitov, Daniel Borkmann
Cc: Teng Qin, netdev@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <1530522893-8961-4-git-send-email-treeze.taeung@gmail.com>
From: Taeung Song
> Sent: 02 July 2018 10:15
> test_task_rename() and test_urandom_read()
> can be failed during write() and read(),
> So check the result of them.
>
> Signed-off-by: Taeung Song <treeze.taeung@gmail.com>
> ---
> samples/bpf/test_overhead_user.c | 20 +++++++++++++++-----
> 1 file changed, 15 insertions(+), 5 deletions(-)
>
> diff --git a/samples/bpf/test_overhead_user.c b/samples/bpf/test_overhead_user.c
> index 6caf47a..8a88d9c 100644
> --- a/samples/bpf/test_overhead_user.c
> +++ b/samples/bpf/test_overhead_user.c
> @@ -6,6 +6,7 @@
> */
> #define _GNU_SOURCE
> #include <sched.h>
> +#include <errno.h>
> #include <stdio.h>
> #include <sys/types.h>
> #include <asm/unistd.h>
> @@ -44,8 +45,12 @@ static void test_task_rename(int cpu)
> exit(1);
> }
> start_time = time_get_ns();
> - for (i = 0; i < MAX_CNT; i++)
> - write(fd, buf, sizeof(buf));
> + for (i = 0; i < MAX_CNT; i++) {
> + if (write(fd, buf, sizeof(buf)) < 0) {
> + printf("task rename failed: %s\n", strerror(errno));
> + break;
I'm not sure 'break' generates sensible output.
> + }
> + }
What about partial writes??
> printf("task_rename:%d: %lld events per sec\n",
> cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time));
> close(fd);
> @@ -55,7 +60,7 @@ static void test_urandom_read(int cpu)
> {
> __u64 start_time;
> char buf[4];
> - int i, fd;
> + int i, fd, err = 0;
>
> fd = open("/dev/urandom", O_RDONLY);
> if (fd < 0) {
> @@ -63,8 +68,13 @@ static void test_urandom_read(int cpu)
> exit(1);
> }
> start_time = time_get_ns();
> - for (i = 0; i < MAX_CNT; i++)
> - read(fd, buf, sizeof(buf));
> + for (i = 0; i < MAX_CNT; i++) {
> + err = read(fd, buf, sizeof(buf));
> + if (err < 0 || err >= sizeof(buf)) {
Overlong reads indicate that something is seriously awry.
Short reads are valid - but maybe not expected.
> + printf("failed to read from /dev/urandom: %s\n", strerror(errno));
strerror() won't give anything sensible unless err == -1;
You probably want to include the loop count.
> + break;
The summary print will be gibberish after break.
> + }
> + }
> printf("urandom_read:%d: %lld events per sec\n",
> cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time));
> close(fd);
> --
> 2.7.4
^ permalink raw reply
* [PATCH 2/4] samples/bpf: Check the result of system()
From: Taeung Song @ 2018-07-02 9:14 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann
Cc: Teng Qin, netdev, linux-kernel, Taeung Song
In-Reply-To: <1530522893-8961-1-git-send-email-treeze.taeung@gmail.com>
To avoid the below build warning message,
use new generate_load() checking the return value.
ignoring return value of ‘system’, declared with attribute warn_unused_result
And it also refactors the duplicate code of both
test_perf_event_all_cpu() and test_perf_event_task()
Cc: Teng Qin <qinteng@fb.com>
Signed-off-by: Taeung Song <treeze.taeung@gmail.com>
---
samples/bpf/trace_event_user.c | 27 ++++++++++++++++++++++++---
1 file changed, 24 insertions(+), 3 deletions(-)
diff --git a/samples/bpf/trace_event_user.c b/samples/bpf/trace_event_user.c
index 1fa1bec..d08046ab8 100644
--- a/samples/bpf/trace_event_user.c
+++ b/samples/bpf/trace_event_user.c
@@ -122,6 +122,16 @@ static void print_stacks(void)
}
}
+static inline int generate_load(void)
+{
+ if (system("dd if=/dev/zero of=/dev/null count=5000k status=none") < 0) {
+ printf("failed to generate some load with dd: %s\n", strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
static void test_perf_event_all_cpu(struct perf_event_attr *attr)
{
int nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
@@ -142,7 +152,11 @@ static void test_perf_event_all_cpu(struct perf_event_attr *attr)
assert(ioctl(pmu_fd[i], PERF_EVENT_IOC_SET_BPF, prog_fd[0]) == 0);
assert(ioctl(pmu_fd[i], PERF_EVENT_IOC_ENABLE) == 0);
}
- system("dd if=/dev/zero of=/dev/null count=5000k status=none");
+
+ if (generate_load() < 0) {
+ error = 1;
+ goto all_cpu_err;
+ }
print_stacks();
all_cpu_err:
for (i--; i >= 0; i--) {
@@ -156,7 +170,7 @@ static void test_perf_event_all_cpu(struct perf_event_attr *attr)
static void test_perf_event_task(struct perf_event_attr *attr)
{
- int pmu_fd;
+ int pmu_fd, error = 0;
/* per task perf event, enable inherit so the "dd ..." command can be traced properly.
* Enabling inherit will cause bpf_perf_prog_read_time helper failure.
@@ -171,10 +185,17 @@ static void test_perf_event_task(struct perf_event_attr *attr)
}
assert(ioctl(pmu_fd, PERF_EVENT_IOC_SET_BPF, prog_fd[0]) == 0);
assert(ioctl(pmu_fd, PERF_EVENT_IOC_ENABLE) == 0);
- system("dd if=/dev/zero of=/dev/null count=5000k status=none");
+
+ if (generate_load() < 0) {
+ error = 1;
+ goto err;
+ }
print_stacks();
+err:
ioctl(pmu_fd, PERF_EVENT_IOC_DISABLE);
close(pmu_fd);
+ if (error)
+ int_exit(0);
}
static void test_bpf_perf_event(void)
--
2.7.4
^ permalink raw reply related
* [PATCH 4/4] samples/bpf: add .gitignore file
From: Taeung Song @ 2018-07-02 9:14 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann
Cc: Teng Qin, netdev, linux-kernel, Taeung Song
In-Reply-To: <1530522893-8961-1-git-send-email-treeze.taeung@gmail.com>
For untracked executables of samples/bpf, add this.
Untracked files:
(use "git add <file>..." to include in what will be committed)
samples/bpf/cpustat
samples/bpf/fds_example
samples/bpf/lathist
samples/bpf/load_sock_ops
...
Signed-off-by: Taeung Song <treeze.taeung@gmail.com>
---
samples/bpf/.gitignore | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 49 insertions(+)
create mode 100644 samples/bpf/.gitignore
diff --git a/samples/bpf/.gitignore b/samples/bpf/.gitignore
new file mode 100644
index 0000000..8ae4940
--- /dev/null
+++ b/samples/bpf/.gitignore
@@ -0,0 +1,49 @@
+cpustat
+fds_example
+lathist
+load_sock_ops
+lwt_len_hist
+map_perf_test
+offwaketime
+per_socket_stats_example
+sampleip
+sock_example
+sockex1
+sockex2
+sockex3
+spintest
+syscall_nrs.h
+syscall_tp
+task_fd_query
+tc_l2_redirect
+test_cgrp2_array_pin
+test_cgrp2_attach
+test_cgrp2_attach2
+test_cgrp2_sock
+test_cgrp2_sock2
+test_current_task_under_cgroup
+test_lru_dist
+test_map_in_map
+test_overhead
+test_probe_write_user
+trace_event
+trace_output
+tracex1
+tracex2
+tracex3
+tracex4
+tracex5
+tracex6
+tracex7
+xdp1
+xdp2
+xdp_adjust_tail
+xdp_fwd
+xdp_monitor
+xdp_redirect
+xdp_redirect_cpu
+xdp_redirect_map
+xdp_router_ipv4
+xdp_rxq_info
+xdp_tx_iptunnel
+xdpsock
--
2.7.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox