* Re: [PATCH net-next] net: ndisc.c: reduce size of __ndisc_fill_addr_option()
From: Alexey Dobriyan @ 2017-05-27 15:15 UTC (permalink / raw)
To: Linyu.Yuan; +Cc: netdev, davem
> --- a/net/ipv6/ndisc.c
> +++ b/net/ipv6/ndisc.c
> @@ -148,17 +148,18 @@ void __ndisc_fill_addr_option(struct sk_buff *skb, int type, void *data,
> space -= data_len;
> - if (space > 0)
> - memset(opt, 0, space);
> +
> + memset(opt, 0, space);
This can't be right.
And what size are you reducing?
^ permalink raw reply
* Re: [PATCH net-next] net: phy: Relax error checking on sysfs_create_link()
From: Florian Fainelli @ 2017-05-27 15:40 UTC (permalink / raw)
To: netdev; +Cc: davem, andrew, Woojung.Huh
In-Reply-To: <20170527033418.3583-1-f.fainelli@gmail.com>
On May 26, 2017 8:34:18 PM PDT, Florian Fainelli <f.fainelli@gmail.com> wrote:
>Some Ethernet drivers will attach/connect to a PHY device before
>calling
>register_netdevice() which is responsible for calling
>netdev_register_kobject()
>which would do the network device's kobject initialization. In such a
>case,
>sysfs_create_link() would return -ENOENT because the network device's
>kobject
>is not ready yet, and we would fail to connect to the PHY device.
>
>In order to keep things simple and symetrical, we just take the success
>path as
>indicative of the ability to access the network device's kobject, and
>create
>the second link if that's the case.
>
>Fixes: 5568363f0cb3 ("net: phy: Create sysfs reciprocal links for
>attached_dev/phydev")
>Reported-by: Woojung Hung <Woojung.Huh@microchip.com>
>Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
>---
> drivers/net/phy/phy_device.c | 28 ++++++++++++++++++++--------
> include/linux/phy.h | 2 ++
> 2 files changed, 22 insertions(+), 8 deletions(-)
>
>diff --git a/drivers/net/phy/phy_device.c
>b/drivers/net/phy/phy_device.c
>index f84414b8f2ee..523366bd705a 100644
>--- a/drivers/net/phy/phy_device.c
>+++ b/drivers/net/phy/phy_device.c
>@@ -960,15 +960,25 @@ int phy_attach_direct(struct net_device *dev,
>struct phy_device *phydev,
>
> phydev->attached_dev = dev;
> dev->phydev = phydev;
>+
>+ /* Some Ethernet drivers try to connect to a PHY device before
>+ * calling register_netdevice() -> netdev_register_kobject() and
>+ * does the dev->dev.kobj initialization. Here we only check for
>+ * success which indicates that the network device kobject is
>+ * ready. Once we do that we still need to keep track of whether
>+ * links were successfully set up or not for phy_detach() to
>+ * remove them accordingly.
>+ */
> err = sysfs_create_link(&phydev->mdio.dev.kobj, &dev->dev.kobj,
> "attached_dev");
>- if (err)
>- goto error;
>+ if (!err) {
>+ err = sysfs_create_link(&dev->dev.kobj, &phydev->mdio.dev.kobj,
>+ "phydev");
>+ if (err)
>+ goto error;
>
>- err = sysfs_create_link(&dev->dev.kobj, &phydev->mdio.dev.kobj,
>- "phydev");
>- if (err)
>- goto error;
>+ phydev->sysfs_links = true;
>+ }
>
We should not assume that this Boolean will be true or false if we enter this function a second time, v2 coming.
--
Florian
^ permalink raw reply
* [PATCH net-next] liquidio: add support for OVS offload
From: Felix Manlunas @ 2017-05-27 15:56 UTC (permalink / raw)
To: davem
Cc: netdev, veerasenareddy.burru, raghu.vatsavayi, derek.chickles,
satananda.burla
From: VSR Burru <veerasenareddy.burru@cavium.com>
Add support for OVS offload. By default PF driver runs in basic NIC mode
as usual. To run in OVS mode, use the insmod parameter "fw_type=ovs".
For OVS mode, create a management interface for communication with NIC
firmware. This communication channel uses PF0's I/O rings.
Bump up driver version to 1.6.0 to match newer firmware.
Signed-off-by: VSR Burru <veerasenareddy.burru@cavium.com>
Signed-off-by: Felix Manlunas <felix.manlunas@cavium.com>
---
drivers/net/ethernet/cavium/liquidio/Makefile | 1 +
drivers/net/ethernet/cavium/liquidio/lio_main.c | 27 +-
.../net/ethernet/cavium/liquidio/liquidio_common.h | 23 +-
.../net/ethernet/cavium/liquidio/liquidio_image.h | 1 +
.../net/ethernet/cavium/liquidio/liquidio_mgmt.c | 439 +++++++++++++++++++++
.../net/ethernet/cavium/liquidio/octeon_console.c | 27 +-
drivers/net/ethernet/cavium/liquidio/octeon_main.h | 9 +
7 files changed, 516 insertions(+), 11 deletions(-)
diff --git a/drivers/net/ethernet/cavium/liquidio/Makefile b/drivers/net/ethernet/cavium/liquidio/Makefile
index c4d411d..2064157 100644
--- a/drivers/net/ethernet/cavium/liquidio/Makefile
+++ b/drivers/net/ethernet/cavium/liquidio/Makefile
@@ -15,6 +15,7 @@ liquidio-$(CONFIG_LIQUIDIO) += lio_ethtool.o \
octeon_mailbox.o \
octeon_mem_ops.o \
octeon_droq.o \
+ liquidio_mgmt.o \
octeon_nic.o
liquidio-objs := lio_main.o octeon_console.o $(liquidio-y)
diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c
index ba01242..b22eb74 100644
--- a/drivers/net/ethernet/cavium/liquidio/lio_main.c
+++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c
@@ -43,6 +43,8 @@ MODULE_FIRMWARE(LIO_FW_DIR LIO_FW_BASE_NAME LIO_210SV_NAME LIO_FW_NAME_SUFFIX);
MODULE_FIRMWARE(LIO_FW_DIR LIO_FW_BASE_NAME LIO_210NV_NAME LIO_FW_NAME_SUFFIX);
MODULE_FIRMWARE(LIO_FW_DIR LIO_FW_BASE_NAME LIO_410NV_NAME LIO_FW_NAME_SUFFIX);
MODULE_FIRMWARE(LIO_FW_DIR LIO_FW_BASE_NAME LIO_23XX_NAME LIO_FW_NAME_SUFFIX);
+MODULE_FIRMWARE(LIO_FW_DIR LIO_FW_BASE_NAME LIO_23XX_NAME "_"
+ LIO_FW_NAME_TYPE_OVS LIO_FW_NAME_SUFFIX);
static int ddr_timeout = 10000;
module_param(ddr_timeout, int, 0644);
@@ -57,7 +59,7 @@ MODULE_PARM_DESC(debug, "NETIF_MSG debug bits");
static char fw_type[LIO_MAX_FW_TYPE_LEN];
module_param_string(fw_type, fw_type, sizeof(fw_type), 0000);
-MODULE_PARM_DESC(fw_type, "Type of firmware to be loaded. Default \"nic\"");
+MODULE_PARM_DESC(fw_type, "Type of firmware to be loaded (nic,ovs,none). Default \"nic\". Use \"none\" to load firmware from flash on LiquidIO adapter.");
static int ptp_enable = 1;
@@ -1414,6 +1416,12 @@ static bool fw_type_is_none(void)
sizeof(LIO_FW_NAME_TYPE_NONE)) == 0;
}
+static bool is_fw_type_ovs(void)
+{
+ return strncmp(fw_type, LIO_FW_NAME_TYPE_OVS,
+ sizeof(LIO_FW_NAME_TYPE_OVS)) == 0;
+}
+
/**
*\brief Destroy resources associated with octeon device
* @param pdev PCI device structure
@@ -1776,6 +1784,9 @@ static void liquidio_remove(struct pci_dev *pdev)
dev_dbg(&oct_dev->pci_dev->dev, "Stopping device\n");
+ if (is_fw_type_ovs())
+ lio_mgmt_exit();
+
if (oct_dev->watchdog_task)
kthread_stop(oct_dev->watchdog_task);
@@ -3933,6 +3944,8 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
u32 resp_size, ctx_size, data_size;
u32 ifidx_or_pfnum;
struct lio_version *vdata;
+ union oct_nic_vf_info vf_info;
+
/* This is to handle link status changes */
octeon_register_dispatch_fn(octeon_dev, OPCODE_NIC,
@@ -4001,9 +4014,16 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
sc->iq_no = 0;
+ /* Populate VF info for OVS firmware */
+ vf_info.u64 = 0;
+
+ vf_info.s.bus_num = octeon_dev->pci_dev->bus->number;
+ vf_info.s.dev_fn = octeon_dev->pci_dev->devfn;
+ vf_info.s.max_vfs = octeon_dev->sriov_info.max_vfs;
+
octeon_prepare_soft_command(octeon_dev, sc, OPCODE_NIC,
OPCODE_NIC_IF_CFG, 0,
- if_cfg.u64, 0);
+ if_cfg.u64, vf_info.u64);
sc->callback = if_cfg_callback;
sc->callback_arg = sc;
@@ -4382,6 +4402,9 @@ static int liquidio_init_nic_module(struct octeon_device *oct)
goto octnet_init_failure;
}
+ if (is_fw_type_ovs())
+ lio_mgmt_init(oct);
+
liquidio_ptp_init(oct);
dev_dbg(&oct->pci_dev->dev, "Network interfaces ready\n");
diff --git a/drivers/net/ethernet/cavium/liquidio/liquidio_common.h b/drivers/net/ethernet/cavium/liquidio/liquidio_common.h
index 8ea2323..d8a1a1d 100644
--- a/drivers/net/ethernet/cavium/liquidio/liquidio_common.h
+++ b/drivers/net/ethernet/cavium/liquidio/liquidio_common.h
@@ -27,8 +27,8 @@
#define LIQUIDIO_PACKAGE ""
#define LIQUIDIO_BASE_MAJOR_VERSION 1
-#define LIQUIDIO_BASE_MINOR_VERSION 5
-#define LIQUIDIO_BASE_MICRO_VERSION 1
+#define LIQUIDIO_BASE_MINOR_VERSION 6
+#define LIQUIDIO_BASE_MICRO_VERSION 0
#define LIQUIDIO_BASE_VERSION __stringify(LIQUIDIO_BASE_MAJOR_VERSION) "." \
__stringify(LIQUIDIO_BASE_MINOR_VERSION)
#define LIQUIDIO_MICRO_VERSION "." __stringify(LIQUIDIO_BASE_MICRO_VERSION)
@@ -63,6 +63,8 @@ enum octeon_tag_type {
*/
#define OPCODE_CORE 0 /* used for generic core operations */
#define OPCODE_NIC 1 /* used for NIC operations */
+#define OPCODE_OVS 2 /* used for OVS operations */
+
/* Subcodes are used by host driver/apps to identify the sub-operation
* for the core. They only need to by unique for a given subsystem.
*/
@@ -890,4 +892,21 @@ union oct_nic_if_cfg {
} s;
};
+union oct_nic_vf_info {
+ u64 u64;
+ struct {
+#ifdef __BIG_ENDIAN_BITFIELD
+ u64 max_vfs:32;
+ u64 bus_num:8;
+ u64 dev_fn:8;
+ u64 reserved:16;
+#else
+ u64 reserved:16;
+ u64 dev_fn:8;
+ u64 bus_num:8;
+ u64 max_vfs:32;
+#endif
+ } s;
+};
+
#endif
diff --git a/drivers/net/ethernet/cavium/liquidio/liquidio_image.h b/drivers/net/ethernet/cavium/liquidio/liquidio_image.h
index 78a3685..cbd03f5 100644
--- a/drivers/net/ethernet/cavium/liquidio/liquidio_image.h
+++ b/drivers/net/ethernet/cavium/liquidio/liquidio_image.h
@@ -24,6 +24,7 @@
#define LIO_FW_BASE_NAME "lio_"
#define LIO_FW_NAME_SUFFIX ".bin"
#define LIO_FW_NAME_TYPE_NIC "nic"
+#define LIO_FW_NAME_TYPE_OVS "ovs"
#define LIO_FW_NAME_TYPE_NONE "none"
#define LIO_MAX_FIRMWARE_VERSION_LEN 16
diff --git a/drivers/net/ethernet/cavium/liquidio/liquidio_mgmt.c b/drivers/net/ethernet/cavium/liquidio/liquidio_mgmt.c
new file mode 100644
index 0000000..1fd7497
--- /dev/null
+++ b/drivers/net/ethernet/cavium/liquidio/liquidio_mgmt.c
@@ -0,0 +1,439 @@
+/**********************************************************************
+ * Author: Cavium, Inc.
+ *
+ * Contact: support@cavium.com
+ * Please include "LiquidIO" in the subject.
+ *
+ * Copyright (c) 2003-2017 Cavium, Inc.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
+ * NONINFRINGEMENT. See the GNU General Public License for more details.
+ ***********************************************************************/
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/crc32.h>
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/ip.h>
+#include <net/ip.h>
+#include <linux/ipv6.h>
+#include <linux/net_tstamp.h>
+#include <linux/if_vlan.h>
+#include <linux/firmware.h>
+#include <linux/ethtool.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include "octeon_config.h"
+#include "liquidio_common.h"
+#include "octeon_droq.h"
+#include "octeon_iq.h"
+#include "response_manager.h"
+#include "octeon_device.h"
+#include "octeon_nic.h"
+#include "octeon_main.h"
+#include "octeon_network.h"
+
+/* VSW specific opcodes. these should match with those in cvmcs-vsw-msg.h */
+#define OPCODE_VSW_HOST_COMM_PKT_DATA 0x10
+
+static struct net_device *netdev;
+struct lio_mgmt {
+ atomic_t ifstate;
+ struct tasklet_struct rx_tasklet;
+ struct list_head rx_pkts_list;
+ struct net_device *parent_netdev;
+ struct octeon_device *oct_dev;
+ struct net_device *netdev;
+ u64 dev_capability;
+ u64 enc_dev_capability;
+ struct oct_link_info linfo;
+ u32 intf_open;
+};
+
+struct lio_mgmt_rx_pkt {
+ struct list_head list;
+ struct sk_buff *skb;
+};
+
+#define LIO_MGMT_SIZE (sizeof(struct lio_mgmt))
+#define GET_LIO_MGMT(netdev) ((struct lio_mgmt *)netdev_priv(netdev))
+
+/**
+ * \brief Stop Tx queues
+ * @param netdev network device
+ */
+static inline void txqs_stop(struct net_device *netdev)
+{
+ if (netif_is_multiqueue(netdev)) {
+ int i;
+
+ for (i = 0; i < netdev->num_tx_queues; i++)
+ netif_stop_subqueue(netdev, i);
+ } else {
+ netif_stop_queue(netdev);
+ }
+}
+
+/**
+ * \brief Start Tx queues
+ * @param netdev network device
+ */
+static inline void txqs_start(struct net_device *netdev)
+{
+ if (netif_is_multiqueue(netdev)) {
+ int i;
+
+ for (i = 0; i < netdev->num_tx_queues; i++)
+ netif_start_subqueue(netdev, i);
+ } else {
+ netif_start_queue(netdev);
+ }
+}
+
+/**
+ * \brief Stop Tx queue
+ * @param netdev network device
+ */
+static void stop_txq(struct net_device *netdev)
+{
+ txqs_stop(netdev);
+}
+
+/**
+ * \brief Start Tx queue
+ * @param netdev network device
+ */
+static void start_txq(struct net_device *netdev)
+{
+ txqs_start(netdev);
+}
+
+static int lio_mgmt_open(struct net_device *netdev)
+{
+ struct lio_mgmt *lio_mgmt = GET_LIO_MGMT(netdev);
+
+ ifstate_set((struct lio *)lio_mgmt, LIO_IFSTATE_RUNNING);
+ netif_carrier_on(netdev);
+
+ start_txq(netdev);
+
+ /* Ready for link status updates */
+ lio_mgmt->intf_open = 1;
+
+ return 0;
+}
+
+/**
+ * \brief Net device stop for LiquidIO
+ * @param netdev network device
+ */
+static int lio_mgmt_stop(struct net_device *netdev)
+{
+ struct lio_mgmt *lio_mgmt = GET_LIO_MGMT(netdev);
+
+ ifstate_reset((struct lio *)lio_mgmt, LIO_IFSTATE_RUNNING);
+
+ netif_tx_disable(netdev);
+
+ /* Inform that netif carrier is down */
+ netif_carrier_off(netdev);
+ lio_mgmt->intf_open = 0;
+
+ return 0;
+}
+
+static void packet_sent_callback(struct octeon_device *oct,
+ u32 status, void *buf)
+{
+ struct octeon_soft_command *sc = (struct octeon_soft_command *)buf;
+ struct sk_buff *skb = sc->ctxptr;
+
+ dma_unmap_single(&oct->pci_dev->dev, sc->dmadptr,
+ sc->datasize, DMA_TO_DEVICE);
+ dev_kfree_skb_any(skb);
+ kfree(sc);
+}
+
+/** \brief Transmit networks packets to the Octeon interface
+ * @param skbuff skbuff struct to be passed to network layer.
+ * @param netdev pointer to network device
+ * @returns whether the packet was transmitted to the device okay or not
+ * (NETDEV_TX_OK or NETDEV_TX_BUSY)
+ */
+static int lio_mgmt_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct lio_mgmt *lio_mgmt;
+ struct lio *parent_lio;
+ struct octeon_soft_command *sc;
+ int status;
+ struct octeon_instr_pki_ih3 *pki_ih3;
+
+ lio_mgmt = GET_LIO_MGMT(netdev);
+ parent_lio = GET_LIO(lio_mgmt->parent_netdev);
+
+ /* Check for all conditions in which the current packet cannot be
+ * transmitted.
+ */
+ if (!(atomic_read(&lio_mgmt->ifstate) & LIO_IFSTATE_RUNNING) ||
+ (skb->len <= 0)) {
+ goto lio_xmit_failed;
+ }
+
+ if (octnet_iq_is_full(lio_mgmt->oct_dev, parent_lio->txq)) {
+ /* defer sending if queue is full */
+ return NETDEV_TX_BUSY;
+ }
+
+ sc = kzalloc(sizeof(*sc), GFP_ATOMIC);
+ if (!sc)
+ goto lio_xmit_failed;
+
+ if (skb_shinfo(skb)->nr_frags == 0) {
+ sc->dmadptr = dma_map_single(&lio_mgmt->oct_dev->pci_dev->dev,
+ skb->data,
+ skb->len, DMA_TO_DEVICE);
+ if (dma_mapping_error
+ (&lio_mgmt->oct_dev->pci_dev->dev, sc->dmadptr)) {
+ return NETDEV_TX_BUSY;
+ }
+ sc->virtdptr = skb->data;
+ sc->datasize = skb->len;
+ sc->ctxptr = skb; /* to be freed in sent callback */
+ sc->dmarptr = 0;
+ sc->rdatasize = 0;
+ sc->iq_no = parent_lio->txq; /* default input queue */
+ octeon_prepare_soft_command(lio_mgmt->oct_dev, sc, OPCODE_OVS,
+ OPCODE_VSW_HOST_COMM_PKT_DATA, 0, 0,
+ 0);
+
+ /*prepare softcommand uses ATOMIC TAG, change it to ORDERED */
+ pki_ih3 = (struct octeon_instr_pki_ih3 *)&sc->cmd.cmd3.pki_ih3;
+ pki_ih3->tag = LIO_DATA((lio_mgmt->oct_dev->instr_queue
+ [sc->iq_no]->txpciq.s.port));
+ pki_ih3->tagtype = ORDERED_TAG;
+
+ sc->callback = packet_sent_callback;
+ sc->callback_arg = sc;
+ status = octeon_send_soft_command(lio_mgmt->oct_dev, sc);
+ if (status == IQ_SEND_FAILED) {
+ dma_unmap_single(&lio_mgmt->oct_dev->pci_dev->dev,
+ sc->dmadptr, sc->datasize,
+ DMA_TO_DEVICE);
+ goto lio_xmit_failed;
+ }
+
+ if (status == IQ_SEND_STOP)
+ stop_txq(netdev);
+ } else {
+ goto lio_xmit_failed;
+ }
+
+ netdev->stats.tx_packets++;
+ netdev->stats.tx_bytes += skb->len;
+
+ return NETDEV_TX_OK;
+
+lio_xmit_failed:
+ netdev->stats.tx_dropped++;
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+}
+
+static void rx_tasklet(unsigned long data)
+{
+ struct net_device *netdev = (struct net_device *)(data);
+ struct lio_mgmt *lio_mgmt = GET_LIO_MGMT(netdev);
+ struct lio_mgmt_rx_pkt *rxpkt, *tmp;
+
+ list_for_each_entry_safe(rxpkt, tmp, &lio_mgmt->rx_pkts_list, list) {
+ netif_rx(rxpkt->skb);
+ list_del(&rxpkt->list);
+ kfree(rxpkt);
+ }
+}
+
+static int lio_mgmt_rx(struct octeon_recv_info *recv_info, void *buf)
+{
+ struct octeon_recv_pkt *recv_pkt = recv_info->recv_pkt;
+ struct sk_buff *skb;
+ struct lio_mgmt *lio_mgmt = GET_LIO_MGMT(netdev);
+ unsigned int pkt_size = 0;
+ unsigned char *pkt_ptr;
+ struct lio_mgmt_rx_pkt *rxpkt;
+ int i;
+
+ /* Do not proceed if the interface is not in RUNNING state. */
+ if (!ifstate_check((struct lio *)lio_mgmt, LIO_IFSTATE_RUNNING)) {
+ for (i = 0; i < recv_pkt->buffer_count; i++)
+ recv_buffer_free(recv_pkt->buffer_ptr[i]);
+
+ octeon_free_recv_info(recv_info);
+ return 0;
+ }
+
+ pkt_size = recv_pkt->buffer_size[0];
+ pkt_ptr = get_rbd(recv_pkt->buffer_ptr[0]);
+
+ skb = netdev_alloc_skb_ip_align(netdev, pkt_size);
+ if (likely(skb))
+ skb_copy_to_linear_data(skb, pkt_ptr, pkt_size);
+
+ skb_put(skb, pkt_size);
+ netdev->stats.rx_packets++;
+ netdev->stats.rx_bytes += skb->len;
+
+ skb->dev = netdev;
+ skb->protocol = eth_type_trans(skb, skb->dev);
+ /* checksum has already been verified */
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ rxpkt = kmalloc(sizeof(*rxpkt), GFP_ATOMIC);
+ if (rxpkt) {
+ INIT_LIST_HEAD(&rxpkt->list);
+ rxpkt->skb = skb;
+ list_add_tail(&rxpkt->list, &lio_mgmt->rx_pkts_list);
+ }
+
+ tasklet_schedule(&lio_mgmt->rx_tasklet);
+
+ for (i = 0; i < recv_pkt->buffer_count; i++)
+ recv_buffer_free(recv_pkt->buffer_ptr[i]);
+
+ octeon_free_recv_info(recv_info);
+ return 0;
+}
+
+const struct net_device_ops liocomdevops = {
+ .ndo_open = lio_mgmt_open,
+ .ndo_stop = lio_mgmt_stop,
+ .ndo_start_xmit = lio_mgmt_xmit,
+};
+
+static int __lio_mgmt_init(struct octeon_device *octdev)
+{
+ struct lio_mgmt *lio_mgmt = NULL;
+ struct lio *parent_lio;
+
+ /* Register netdev only for pf 0 */
+ if (octdev->pf_num == 0) {
+ netdev = alloc_etherdev(LIO_MGMT_SIZE);
+ if (!netdev) {
+ dev_err(&octdev->pci_dev->dev, "Mgmt: Device allocation failed\n");
+ goto nic_dev_fail;
+ }
+
+ /* SET_NETDEV_DEV(netdev, &octdev->pci_dev->dev); */
+ netdev->netdev_ops = &liocomdevops;
+
+ lio_mgmt = GET_LIO_MGMT(netdev);
+ memset(lio_mgmt, 0, LIO_MGMT_SIZE);
+ lio_mgmt->oct_dev = octdev;
+
+ /*use ifidx zero of pf */
+ lio_mgmt->parent_netdev = octdev->props[0].netdev;
+ parent_lio = GET_LIO(lio_mgmt->parent_netdev);
+
+ lio_mgmt->dev_capability = NETIF_F_HIGHDMA
+ | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM;
+ lio_mgmt->enc_dev_capability = NETIF_F_IP_CSUM
+ | NETIF_F_IPV6_CSUM | NETIF_F_HW_CSUM | NETIF_F_RXCSUM;
+
+ netdev->vlan_features = lio_mgmt->dev_capability;
+ netdev->features = lio_mgmt->dev_capability;
+ netdev->hw_features = lio_mgmt->dev_capability;
+
+ lio_mgmt->linfo = parent_lio->linfo;
+
+ eth_hw_addr_random(netdev);
+ }
+ if (octdev->pf_num == 0) {
+ char name[IFNAMSIZ];
+ int dev_id, fn;
+
+ tasklet_init(&lio_mgmt->rx_tasklet, rx_tasklet, (u64)netdev);
+ INIT_LIST_HEAD(&lio_mgmt->rx_pkts_list);
+
+ dev_id = (octdev->pci_dev->devfn & 0xff) >> 3;
+ fn = octdev->pci_dev->devfn & 0x7;
+
+ if (fn) {
+ snprintf(name, IFNAMSIZ, "lio-p%ds%df%d-mgmt",
+ octdev->pci_dev->bus->number, dev_id, fn);
+ } else {
+ snprintf(name, IFNAMSIZ, "lio-p%ds%d-mgmt",
+ octdev->pci_dev->bus->number, dev_id);
+ }
+
+ strncpy(netdev->name, name, sizeof(netdev->name) - 1);
+
+ /* Register the network device with the OS */
+ if (register_netdev(netdev)) {
+ dev_err(&octdev->pci_dev->dev, "Mgmt: Device registration failed\n");
+ goto nic_dev_fail;
+ }
+
+ netif_carrier_on(netdev);
+ ifstate_set((struct lio *)lio_mgmt, LIO_IFSTATE_REGISTERED);
+ /* Register RX dispatch function */
+ if (octeon_register_dispatch_fn(octdev, OPCODE_OVS,
+ OPCODE_VSW_HOST_COMM_PKT_DATA,
+ lio_mgmt_rx, octdev)) {
+ goto nic_dev_fail;
+ }
+ }
+
+ return 0;
+
+nic_dev_fail:
+ if (netdev) {
+ struct lio_mgmt *lio_mgmt = GET_LIO_MGMT(netdev);
+
+ if (atomic_read(&lio_mgmt->ifstate) &
+ LIO_IFSTATE_REGISTERED)
+ unregister_netdev(netdev);
+
+ free_netdev(netdev);
+ netdev = NULL;
+ }
+
+ netdev = NULL;
+ return -ENOMEM;
+}
+
+static void __lio_mgmt_exit(void)
+{
+ pr_info("LiquidIO Communication module is now unloaded\n");
+
+ if (netdev) {
+ struct lio_mgmt *lio_mgmt = GET_LIO_MGMT(netdev);
+
+ if (atomic_read(&lio_mgmt->ifstate) & LIO_IFSTATE_RUNNING)
+ txqs_stop(netdev);
+
+ if (atomic_read(&lio_mgmt->ifstate) &
+ LIO_IFSTATE_REGISTERED)
+ unregister_netdev(netdev);
+
+ free_netdev(netdev);
+ netdev = NULL;
+ }
+}
+
+int lio_mgmt_init(struct octeon_device *octdev)
+{
+ return __lio_mgmt_init(octdev);
+}
+
+void lio_mgmt_exit(void)
+{
+ __lio_mgmt_exit();
+}
diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_console.c b/drivers/net/ethernet/cavium/liquidio/octeon_console.c
index 53f38d0..c7b05b7 100644
--- a/drivers/net/ethernet/cavium/liquidio/octeon_console.c
+++ b/drivers/net/ethernet/cavium/liquidio/octeon_console.c
@@ -724,18 +724,22 @@ static int octeon_console_read(struct octeon_device *oct, u32 console_num,
}
#define FBUF_SIZE (4 * 1024 * 1024)
-u8 fbuf[FBUF_SIZE];
int octeon_download_firmware(struct octeon_device *oct, const u8 *data,
size_t size)
{
int ret = 0;
- u8 *p = fbuf;
u32 crc32_result;
u64 load_addr;
u32 image_len;
struct octeon_firmware_file_header *h;
u32 i, rem;
+ char *bootcmd;
+ char date[30];
+ struct timeval time;
+ struct tm tm;
+ size_t cmdlen;
+
if (size < sizeof(struct octeon_firmware_file_header)) {
dev_err(&oct->pci_dev->dev, "Firmware file too small (%d < %d).\n",
@@ -805,10 +809,9 @@ int octeon_download_firmware(struct octeon_device *oct, const u8 *data,
else
size = FBUF_SIZE;
- memcpy(p, data, size);
-
/* download the image */
- octeon_pci_write_core_mem(oct, load_addr, p, (u32)size);
+ octeon_pci_write_core_mem(
+ oct, load_addr, (u8 *)data, (u32)size);
data += size;
rem -= (u32)size;
@@ -818,8 +821,18 @@ int octeon_download_firmware(struct octeon_device *oct, const u8 *data,
dev_info(&oct->pci_dev->dev, "Writing boot command: %s\n",
h->bootcmd);
- /* Invoke the bootcmd */
- ret = octeon_console_send_cmd(oct, h->bootcmd, 50);
+ /*Get time of the day*/
+ do_gettimeofday(&time);
+ time_to_tm(time.tv_sec, (-sys_tz.tz_minuteswest) * 60, &tm);
+ snprintf(date, 30, " date=%04ld.%02d.%02d-%02d:%02d:%02d",
+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec);
+ cmdlen = strlen(h->bootcmd) + sizeof(date) + 1;
+ bootcmd = kmalloc(cmdlen, GFP_KERNEL);
+ strncpy(bootcmd, h->bootcmd, cmdlen);
+ strcat(bootcmd, date);
+ ret = octeon_console_send_cmd(oct, bootcmd, 50);
+ kfree(bootcmd);
return 0;
}
diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_main.h b/drivers/net/ethernet/cavium/liquidio/octeon_main.h
index bed9ef1..3a36105 100644
--- a/drivers/net/ethernet/cavium/liquidio/octeon_main.h
+++ b/drivers/net/ethernet/cavium/liquidio/octeon_main.h
@@ -198,4 +198,13 @@ sleep_timeout_cond(wait_queue_head_t *wait_queue,
#define ROUNDUP128(val) (((val) + 127) & 0xffffff80)
#endif
+/* Initializes the LiquidIO management interface module
+ * @param octdev - octeon device pointer
+ * @returns 0 if init is success, -1 otherwise
+ */
+int lio_mgmt_init(struct octeon_device *octdev);
+
+/* De-initializes the LiquidIO management interface module */
+void lio_mgmt_exit(void);
+
#endif /* _OCTEON_MAIN_H_ */
^ permalink raw reply related
* Re: [PATCH] net/core: remove explicit do_softirq() from busy_poll_stop()
From: Sebastian Andrzej Siewior @ 2017-05-27 16:23 UTC (permalink / raw)
To: Eric Dumazet; +Cc: netdev, David S. Miller, Thomas Gleixner
In-Reply-To: <CANn89iJx0-z2KZWMRZdqmYUNAWcqQo4nBbRwK7pLz2-WAymqrQ@mail.gmail.com>
On 2017-05-22 14:26:44 [-0700], Eric Dumazet wrote:
> On Mon, May 22, 2017 at 12:26 PM, Sebastian Andrzej Siewior
> <bigeasy@linutronix.de> wrote:
> > Since commit 217f69743681 ("net: busy-poll: allow preemption in
> > sk_busy_loop()") there is an explicit do_softirq() invocation after
> > local_bh_enable() has been invoked.
> > I don't understand why we need this because local_bh_enable() will
> > invoke do_softirq() once the softirq counter reached zero and we have
> > softirq-related work pending.
> >
> > Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> > ---
> > net/core/dev.c | 2 --
> > 1 file changed, 2 deletions(-)
> >
> > diff --git a/net/core/dev.c b/net/core/dev.c
> > index fca407b4a6ea..e84eb0ec5529 100644
> > --- a/net/core/dev.c
> > +++ b/net/core/dev.c
> > @@ -5199,8 +5199,6 @@ static void busy_poll_stop(struct napi_struct *napi, void *have_poll_lock)
> > if (rc == BUSY_POLL_BUDGET)
> > __napi_schedule(napi);
> > local_bh_enable();
> > - if (local_softirq_pending())
> > - do_softirq();
> > }
>
> preemption is disabled.
so? This patch:
diff --git a/init/main.c b/init/main.c
--- a/init/main.c
+++ b/init/main.c
@@ -1001,6 +1001,21 @@ static int __ref kernel_init(void *unused)
"See Linux Documentation/admin-guide/init.rst for guidance.");
}
+static void delay_thingy_func(struct work_struct *x)
+{
+ preempt_disable();
+ local_bh_disable();
+ pr_err("one %s\n", current->comm);
+ raise_softirq(TASKLET_SOFTIRQ);
+ pr_err("two %s\n", current->comm);
+ local_bh_enable();
+ pr_err("three %s\n", current->comm);
+ preempt_enable();
+ pr_err("four %s\n", current->comm);
+}
+
+static DECLARE_DELAYED_WORK(delay_thingy, delay_thingy_func);
+
static noinline void __init kernel_init_freeable(void)
{
/*
@@ -1038,6 +1053,7 @@ static noinline void __init kernel_init_freeable(void)
do_basic_setup();
+ schedule_delayed_work(&delay_thingy, HZ * 5);
/* Open the /dev/console on the rootfs, this should never fail */
if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)
pr_err("Warning: unable to open an initial console.\n");
diff --git a/kernel/softirq.c b/kernel/softirq.c
index 4e09821f9d9e..b8dcb9dc5692 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -500,6 +500,7 @@ static __latent_entropy void tasklet_action(struct softirq_action *a)
{
struct tasklet_struct *list;
+ pr_err("%s() %s\n", __func__, current->comm);
local_irq_disable();
list = __this_cpu_read(tasklet_vec.head);
__this_cpu_write(tasklet_vec.head, NULL);
gives me this output:
[ 7.132439] one kworker/4:2
[ 7.132806] two kworker/4:2
[ 7.133120] softirq: tasklet_action() kworker/4:2
[ 7.133623] three kworker/4:2
[ 7.133940] four kworker/4:2
which means after the last local_bh_enable() we already invoke the
raised softirq handler. It does not matter that we are in a
preempt_disable() region.
>
> Look at netif_rx_ni() for a similar construct.
correct, this is old and it is already patched in -RT. And I have no
clue why this is required by because netif_rx_internal() itself does
preempt_disable() / get_cpu() so this one already disables preemption.
Looking at it, I *think* you want local_bh_disable() instead of
preempt_disable() and do_softirq() removed, too.
Let me browse at the musuem a little bit… ahhh, here -> "[PATCH] Make
netif_rx_ni preempt-safe" [0]. There we got the preempt_disable() from
which protects against parallel invocations of do_softirq() in user
context. And we only do the check for pending softirqs (and invoke
do_softirq()) because netif_rx() sets the pending bits without raising
the softirq and it is done in a BH-enabled section. And in interrupt
context we check for those in the interrupt-exit path. So in this case
we have to do it manually.
[0] http://oss.sgi.com/projects/netdev/archive/2004-10/msg02211.html
> What exact problem do you have with existing code, that is worth
> adding this change ?
I need to workaround the non-existing do_softirq() function in RT and my
current workaround is the patch I posted. I don't see the need for the
two lines. And it seems that the other construct in netif_rx_ni() can be
simplified / removed, too.
> Thanks.
Sebastian
^ permalink raw reply related
* Re: [PATCH net-next 1/4] net/flow_dissector: add support for dissection of misc ip header fields
From: Or Gerlitz @ 2017-05-27 16:29 UTC (permalink / raw)
To: Tom Herbert
Cc: Or Gerlitz, David S. Miller, Linux Kernel Network Developers,
Saeed Mahameed, Roi Dayan, Paul Blakey
In-Reply-To: <CALx6S379RzD+t=mDHgs+u-BrWgd7Jt4W_C-kNarA7t+HwEJ3jQ@mail.gmail.com>
On Thu, May 25, 2017 at 6:42 PM, Tom Herbert <tom@herbertland.com> wrote:
> On Thu, May 25, 2017 at 6:24 AM, Or Gerlitz <ogerlitz@mellanox.com> wrote:
>> Add support for dissection of ip tos and ttl and ipv6 traffic-class
>> and hoplimit. Both are dissected into the same struct.
>> --- a/include/net/flow_dissector.h
>> +++ b/include/net/flow_dissector.h
>> +/**
>> + * struct flow_dissector_key_ip:
>> + * @tos: tos
>> + * @ttl: ttl
>> + */
>> +struct flow_dissector_key_ip {
>> + __u8 tos;
>> + __u8 ttl;
>> +};
>> +
> Looks like yet more complexity be piled onto flow dissector. Instead
> of splitting out individual fields can we just return a pointer to the
> IP header and let the caller extract the fields they're interested in?
Do you mean that struct flow_dissector_key_ip will only contain
(union?) const struct iphdr * and const struct ipv6hdr * ? I wasn't
sure how would that further look on the kernel SW classification path
(the non offloaded case)
^ permalink raw reply
* Re: [PATCH net-next 1/4] net/flow_dissector: add support for dissection of misc ip header fields
From: Or Gerlitz @ 2017-05-27 16:31 UTC (permalink / raw)
To: Tom Herbert
Cc: Or Gerlitz, David S. Miller, Linux Kernel Network Developers,
Saeed Mahameed, Roi Dayan, Paul Blakey
In-Reply-To: <CALx6S36uJrFA+TO7RDaRAxZi0vuEEc90_TnWP8a2yNP+V3X2qQ@mail.gmail.com>
On Thu, May 25, 2017 at 7:22 PM, Tom Herbert <tom@herbertland.com> wrote:
> On Thu, May 25, 2017 at 6:24 AM, Or Gerlitz <ogerlitz@mellanox.com> wrote:
>> Add support for dissection of ip tos and ttl and ipv6 traffic-class
>> and hoplimit. Both are dissected into the same struct.
>> Uses similar call to ip dissection function as with tcp, arp and others.
>> +/**
>> + * struct flow_dissector_key_ip:
>> + * @tos: tos
>> + * @ttl: ttl
>> + */
>> +struct flow_dissector_key_ip {
>> + __u8 tos;
>> + __u8 ttl;
>> +};
>> --- a/net/core/flow_dissector.c
>> +++ b/net/core/flow_dissector.c
>> +static void
>> +__skb_flow_dissect_ipv4(const struct sk_buff *skb,
>> + struct flow_dissector *flow_dissector,
>> + void *target_container, void *data, const struct iphdr *iph)
>> +{
>> + struct flow_dissector_key_ip *key_ip;
>> +
>> + if (!dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_IP))
>> + return;
>> +
>> + key_ip = skb_flow_dissector_target(flow_dissector,
>> + FLOW_DISSECTOR_KEY_IP,
>> + target_container);
>> + key_ip->tos = iph->tos;
>> + key_ip->ttl = iph->ttl;
>
> In an encapsulation this returns the tos and ttl of the encapsulated
> packet. Is that really useful to the caller? Seems more likely that
> they need the outer tos and ttl for forwarding.
In what we are dealing with, classification is carried after the
packet is decapsulated by the shared tunnel device. So even today,e.g
for the src/dst IP, the dissection is carried on what were the inner
fields before decap.
When we did the the flower patches for being able to classify on both
the inner and outer fields (say outer src/dst ip, tunnel key) for what
related to the macs/ips/ports/etc -- I don't think we touched the
existing dissection, I will look on that to see if I am wrong..
^ permalink raw reply
* Re: [PATCH net-next 1/4] net/flow_dissector: add support for dissection of misc ip header fields
From: Tom Herbert @ 2017-05-27 17:18 UTC (permalink / raw)
To: Or Gerlitz
Cc: Or Gerlitz, David S. Miller, Linux Kernel Network Developers,
Saeed Mahameed, Roi Dayan, Paul Blakey
In-Reply-To: <CAJ3xEMgsYi_=0Sv7Wd9GajN5Oym3dKdw3QNDpU9jJR+T6z3Pmw@mail.gmail.com>
On Sat, May 27, 2017 at 9:31 AM, Or Gerlitz <gerlitz.or@gmail.com> wrote:
> On Thu, May 25, 2017 at 7:22 PM, Tom Herbert <tom@herbertland.com> wrote:
>> On Thu, May 25, 2017 at 6:24 AM, Or Gerlitz <ogerlitz@mellanox.com> wrote:
>>> Add support for dissection of ip tos and ttl and ipv6 traffic-class
>>> and hoplimit. Both are dissected into the same struct.
>
>>> Uses similar call to ip dissection function as with tcp, arp and others.
>
>
>>> +/**
>>> + * struct flow_dissector_key_ip:
>>> + * @tos: tos
>>> + * @ttl: ttl
>>> + */
>>> +struct flow_dissector_key_ip {
>>> + __u8 tos;
>>> + __u8 ttl;
>>> +};
>>> --- a/net/core/flow_dissector.c
>>> +++ b/net/core/flow_dissector.c
>
>>> +static void
>>> +__skb_flow_dissect_ipv4(const struct sk_buff *skb,
>>> + struct flow_dissector *flow_dissector,
>>> + void *target_container, void *data, const struct iphdr *iph)
>>> +{
>>> + struct flow_dissector_key_ip *key_ip;
>>> +
>>> + if (!dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_IP))
>>> + return;
>>> +
>>> + key_ip = skb_flow_dissector_target(flow_dissector,
>>> + FLOW_DISSECTOR_KEY_IP,
>>> + target_container);
>>> + key_ip->tos = iph->tos;
>>> + key_ip->ttl = iph->ttl;
>>
>> In an encapsulation this returns the tos and ttl of the encapsulated
>> packet. Is that really useful to the caller? Seems more likely that
>> they need the outer tos and ttl for forwarding.
>
> In what we are dealing with, classification is carried after the
> packet is decapsulated by the shared tunnel device. So even today,e.g
> for the src/dst IP, the dissection is carried on what were the inner
> fields before decap.
>
Or,
I think the problem is I don't know what you're dealing with. The only
thing I can derive from the commit log is that tos and ttl are being
extracted, but I don't know why they are needed. I do know this is
adding complexity to an already overly complex function, and this
introduces new conditionals and code into the primary use case of
flow_dissector which is to create a key for deriving skb->hash. I
don't see that the cost of this patch has been justified.
Tom
> When we did the the flower patches for being able to classify on both
> the inner and outer fields (say outer src/dst ip, tunnel key) for what
> related to the macs/ips/ports/etc -- I don't think we touched the
> existing dissection, I will look on that to see if I am wrong..
^ permalink raw reply
* [PATCH net-next v2] net: phy: Relax error checking on sysfs_create_link()
From: Florian Fainelli @ 2017-05-27 17:42 UTC (permalink / raw)
To: netdev; +Cc: davem, andrew, Woojung.Huh, Florian Fainelli
Some Ethernet drivers will attach/connect to a PHY device before calling
register_netdevice() which is responsible for calling netdev_register_kobject()
which would do the network device's kobject initialization. In such a case,
sysfs_create_link() would return -ENOENT because the network device's kobject
is not ready yet, and we would fail to connect to the PHY device.
In order to keep things simple and symetrical, we just take the success path as
indicative of the ability to access the network device's kobject, and create
the second link if that's the case.
Fixes: 5568363f0cb3 ("net: phy: Create sysfs reciprocal links for attached_dev/phydev")
Reported-by: Woojung Hung <Woojung.Huh@microchip.com>
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
Changes in v2:
- make sure phydev->sysfs_links is set to false before setting again
drivers/net/phy/phy_device.c | 30 ++++++++++++++++++++++--------
include/linux/phy.h | 2 ++
2 files changed, 24 insertions(+), 8 deletions(-)
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index f84414b8f2ee..37a1e98908e3 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -960,15 +960,27 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
phydev->attached_dev = dev;
dev->phydev = phydev;
+
+ /* Some Ethernet drivers try to connect to a PHY device before
+ * calling register_netdevice() -> netdev_register_kobject() and
+ * does the dev->dev.kobj initialization. Here we only check for
+ * success which indicates that the network device kobject is
+ * ready. Once we do that we still need to keep track of whether
+ * links were successfully set up or not for phy_detach() to
+ * remove them accordingly.
+ */
+ phydev->sysfs_links = false;
+
err = sysfs_create_link(&phydev->mdio.dev.kobj, &dev->dev.kobj,
"attached_dev");
- if (err)
- goto error;
+ if (!err) {
+ err = sysfs_create_link(&dev->dev.kobj, &phydev->mdio.dev.kobj,
+ "phydev");
+ if (err)
+ goto error;
- err = sysfs_create_link(&dev->dev.kobj, &phydev->mdio.dev.kobj,
- "phydev");
- if (err)
- goto error;
+ phydev->sysfs_links = true;
+ }
phydev->dev_flags = flags;
@@ -1059,8 +1071,10 @@ void phy_detach(struct phy_device *phydev)
struct mii_bus *bus;
int i;
- sysfs_remove_link(&dev->dev.kobj, "phydev");
- sysfs_remove_link(&phydev->mdio.dev.kobj, "attached_dev");
+ if (phydev->sysfs_links) {
+ sysfs_remove_link(&dev->dev.kobj, "phydev");
+ sysfs_remove_link(&phydev->mdio.dev.kobj, "attached_dev");
+ }
phydev->attached_dev->phydev = NULL;
phydev->attached_dev = NULL;
phy_suspend(phydev);
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 5a808a26e4cf..58f1b45a4c44 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -363,6 +363,7 @@ struct phy_c45_device_ids {
* is_pseudo_fixed_link: Set to true if this phy is an Ethernet switch, etc.
* has_fixups: Set to true if this phy has fixups/quirks.
* suspended: Set to true if this phy has been suspended successfully.
+ * sysfs_links: Internal boolean tracking sysfs symbolic links setup/removal.
* state: state of the PHY for management purposes
* dev_flags: Device-specific flags used by the PHY driver.
* link_timeout: The number of timer firings to wait before the
@@ -399,6 +400,7 @@ struct phy_device {
bool is_pseudo_fixed_link;
bool has_fixups;
bool suspended;
+ bool sysfs_links;
enum phy_state state;
--
2.11.0
^ permalink raw reply related
* GREETINGS
From: mis.sborte09 @ 2017-05-27 20:20 UTC (permalink / raw)
GREETINGS,
I AM BORTE ,I WAS DIAGNOSE WITH OVARIAN CANCER,WHICH DOCTORS HAVE
CONFIRMED THAT I HAVE ONLY FEW WEEKS TO LIVE, SO I HAVE DECIDED TO
DONATE EVERYTHING I HAVE TO THE ORPHANAGE AND THE POOR WIDOWS THROUGH
YOU IN YOUR AREA.PLEASE KINDLY REPLY ME ONLY ON MY EMAIL ADDRES HERE
(borteogorta@gmail.com) AS SOON AS POSIBLE TO ENABLE ME GIVE YOU MORE
INFORMATION ABOUT MYSELF AND HOW TO GO ABOUT IT .
THANKS
MISS BORTE
^ permalink raw reply
* Re: running an eBPF program
From: Y Song @ 2017-05-27 20:23 UTC (permalink / raw)
To: Adel Fuchs; +Cc: netdev
In-Reply-To: <CAErYV9EjKGh9ta8TZ9PRmaATH5VcXQH4cd=WuL5NfMOpcuoLfw@mail.gmail.com>
>From verifier error message:
======
0: (bf) r6 = r1
1: (18) r9 = 0xffe0000e
3: (69) r0 = *(u16 *)(r6 +16)
invalid bpf_context access off=16 size=2
======
The offset 16 of struct __sk_buff is hash.
What instruction #3 tries to do is to access 2 bytes of the hash value
instead of full 4 bytes.
This is explicitly not allowed in verifier due to endianness issue.
Look at iproute2 example code, it looks like the following may be responsible:
bpf_tailcall.c:#define MAX_JMP_SIZE 2
bpf_tailcall.c: tail_call(skb, &jmp_tc, skb->hash & (MAX_JMP_SIZE - 1));
I am thinking of implementing something in LLVM to prevent
optimization from LD4=>LD2/DL1 for context access like this.
On Fri, May 26, 2017 at 4:00 AM, Adel Fuchs <adelfuchs@gmail.com> wrote:
> Hi
>
> I'm trying to run this eBPF program:
>
> https://git.kernel.org/pub/scm/linux/kernel/git/shemminger/iproute2.git/tree/examples/bpf
>
>
> and I get this error:
>
>
> :~/iproute2/examples/bpf$sudo tc filter add dev enx00e11100329b parent
> 1: bpf obj bpf.o exp /tmp/bpf-uds flowid 1:1 action bpf obj bpf.o sec
> action-mark action bpf obj bpf.o sec action-rand ok
>
> [sudo] password for adel:
>
>
>
> Prog section 'classifier' rejected: Permission denied (13)!
>
> - Type: 3
>
> - Instructions: 218 (0 over limit)
>
> - License: GPL
>
>
>
> Verifier analysis:
>
>
>
> 0: (bf) r6 = r1
>
> 1: (18) r9 = 0xffe0000e
>
> 3: (69) r0 = *(u16 *)(r6 +16)
>
> invalid bpf_context access off=16 size=2
>
>
>
> Error fetching program/map!
>
> Failed to retrieve (e)BPF data!
>
>
> Any suggestions?
>
> Thanks,
>
> Adel
^ permalink raw reply
* Re: running an eBPF program
From: Y Song @ 2017-05-27 20:52 UTC (permalink / raw)
To: Adel Fuchs; +Cc: netdev
In-Reply-To: <CAH3MdRVMixv8s10gKF1jQjtSY7MHeB-Rs16hX6HwAgUOQ0g=EA@mail.gmail.com>
On Sat, May 27, 2017 at 1:23 PM, Y Song <ys114321@gmail.com> wrote:
>
> From verifier error message:
> ======
> 0: (bf) r6 = r1
>
> 1: (18) r9 = 0xffe0000e
>
> 3: (69) r0 = *(u16 *)(r6 +16)
>
> invalid bpf_context access off=16 size=2
> ======
>
> The offset 16 of struct __sk_buff is hash.
> What instruction #3 tries to do is to access 2 bytes of the hash value
> instead of full 4 bytes.
> This is explicitly not allowed in verifier due to endianness issue.
I can reproduce the issue now. My previous statement saying to access
"hash" field is not correct. It is accessing the protocol field.
static __inline__ bool flow_dissector(struct __sk_buff *skb,
struct flow_keys *flow)
{
int poff, nh_off = BPF_LL_OFF + ETH_HLEN;
__be16 proto = skb->protocol;
__u8 ip_proto;
The plan so far is to see whether we can fix the issue in LLVM side.
Yonghong
>
>
> Look at iproute2 example code, it looks like the following may be responsible:
>
> bpf_tailcall.c:#define MAX_JMP_SIZE 2
> bpf_tailcall.c: tail_call(skb, &jmp_tc, skb->hash & (MAX_JMP_SIZE - 1));
>
> I am thinking of implementing something in LLVM to prevent
> optimization from LD4=>LD2/DL1 for context access like this.
>
>
> On Fri, May 26, 2017 at 4:00 AM, Adel Fuchs <adelfuchs@gmail.com> wrote:
> > Hi
> >
> > I'm trying to run this eBPF program:
> >
> > https://git.kernel.org/pub/scm/linux/kernel/git/shemminger/iproute2.git/tree/examples/bpf
> >
> >
> > and I get this error:
> >
> >
> > :~/iproute2/examples/bpf$sudo tc filter add dev enx00e11100329b parent
> > 1: bpf obj bpf.o exp /tmp/bpf-uds flowid 1:1 action bpf obj bpf.o sec
> > action-mark action bpf obj bpf.o sec action-rand ok
> >
> > [sudo] password for adel:
> >
> >
> >
> > Prog section 'classifier' rejected: Permission denied (13)!
> >
> > - Type: 3
> >
> > - Instructions: 218 (0 over limit)
> >
> > - License: GPL
> >
> >
> >
> > Verifier analysis:
> >
> >
> >
> > 0: (bf) r6 = r1
> >
> > 1: (18) r9 = 0xffe0000e
> >
> > 3: (69) r0 = *(u16 *)(r6 +16)
> >
> > invalid bpf_context access off=16 size=2
> >
> >
> >
> > Error fetching program/map!
> >
> > Failed to retrieve (e)BPF data!
> >
> >
> > Any suggestions?
> >
> > Thanks,
> >
> > Adel
^ permalink raw reply
* Re: [PATCH net-next 1/4] net/flow_dissector: add support for dissection of misc ip header fields
From: Or Gerlitz @ 2017-05-27 20:56 UTC (permalink / raw)
To: Tom Herbert
Cc: Or Gerlitz, David S. Miller, Linux Kernel Network Developers,
Saeed Mahameed, Roi Dayan, Paul Blakey
In-Reply-To: <CALx6S35LoybyU-NN8RTk4YMOmuOZTkJeZ6GVBnWbX6rtd2uM6Q@mail.gmail.com>
On Sat, May 27, 2017 at 8:18 PM, Tom Herbert <tom@herbertland.com> wrote:
> I think the problem is I don't know what you're dealing with. The only
> thing I can derive from the commit log is that tos and ttl are being
> extracted, but I don't know why they are needed.
The current case for matching on TTL I am dealing with is for using
TC/flower for offloading OVS in flow based VM traffic routing env
(Open-Stack and ODL
DVR - Distributed Virtual Routing) -- where packet headers are
re-written to set the next hop MACs and the TTL is changed. Fields
which are modified are also matched beforhand, and here comes the
matching on TTL.
> I do know this is
> adding complexity to an already overly complex function, and this
> introduces new conditionals and code into the primary use case of
> flow_dissector which is to create a key for deriving skb->hash. I
> don't see that the cost of this patch has been justified.
I hear what you're saying, but part of the rules is that everything to
be offloaded can also be carried out in the kernel SW data-path, so
here comes the touching that area. I have used the minimal foot print
I could and set the code to run in a separate helper called from the
main dissection function.
>> When we did the the flower patches for being able to classify on both
>> the inner and outer fields (say outer src/dst ip, tunnel key) for what
>> related to the macs/ips/ports/etc -- I don't think we touched the
>> existing dissection, I will look on that to see if I am wrong..
^ permalink raw reply
* Re: [PATCH 7/7] mlx5: Do not build eswitch_offloads if CONFIG_MLX5_EN_ESWITCH_OFFLOADS is set
From: Or Gerlitz @ 2017-05-27 21:02 UTC (permalink / raw)
To: Jes Sorensen
Cc: Linux Netdev List, Kernel Team, Saeed Mahameed, Ilan Tayari,
Jes Sorensen
In-Reply-To: <20170526211624.23133-8-jsorensen@fb.com>
On Sat, May 27, 2017 at 12:16 AM, Jes Sorensen <jes.sorensen@gmail.com> wrote:
> This gets rid of the temporary #ifdef spaghetti and allows the code to
> compile without offload support enabled.
Hi Jes,
I am pretty sure we can do that exercise you're up to without any
spaghetti cooking and even put more code under that CONFIG directive
(en_rep.c), I'll take that with Saeed.
Just wondering, you are motivated by a wish to put some mlx5
functionalities under their own CONFIG directives which could be
useful when backporting the latest upstream driver into older kernel
and being able not to deal with parts of it, right? in that respect,
are you using SRIOV but not the offloads mode?
Or.
^ permalink raw reply
* Re: [PATCH V6 net-next 1/2] rtnl: Add support for netdev event to link messages
From: David Ahern @ 2017-05-27 21:41 UTC (permalink / raw)
To: Vladislav Yasevich, netdev; +Cc: roopa, jiri, vfalico, andy, Vladislav Yasevich
In-Reply-To: <1495894476-9726-2-git-send-email-vyasevic@redhat.com>
On 5/27/17 8:14 AM, Vladislav Yasevich wrote:
> When netdev events happen, a rtnetlink_event() handler will send
> messages for every event in it's white list. These messages contain
> current information about a particular device, but they do not include
> the iformation about which event just happened. So, it is impossible
> to tell what just happend for these events.
>
> This patch adds a new extension to RTM_NEWLINK message called IFLA_EVENT
> that would have an encoding of event that triggered this
> message. This would allow the the message consumer to easily determine
> if it needs to perform certain actions.
>
> Signed-off-by: Vladislav Yasevich <vyasevic@redhat.com>
> ---
> include/linux/rtnetlink.h | 3 +-
> include/uapi/linux/if_link.h | 11 ++++++++
> net/core/dev.c | 2 +-
> net/core/rtnetlink.c | 65 ++++++++++++++++++++++++++++++++++++++------
> 4 files changed, 70 insertions(+), 11 deletions(-)
Acked-by: David Ahern <dsahern@gmail.com>
^ permalink raw reply
* Re: [PATCH V6 net-next 2/2] bonding: Prevent duplicate userspace notification
From: David Ahern @ 2017-05-27 21:41 UTC (permalink / raw)
To: Vladislav Yasevich, netdev
Cc: roopa, jiri, vfalico, andy, Vladislav Yasevich, David Ahern
In-Reply-To: <1495894476-9726-3-git-send-email-vyasevic@redhat.com>
On 5/27/17 8:14 AM, Vladislav Yasevich wrote:
> Whenever a user changes bonding options, a NETDEV_CHANGEINFODATA
> notificatin is generated which results in a rtnelink message to
> be sent. While runnig 'ip monitor', we can actually see 2 messages,
> one a result of the event, and the other a result of state change
> that is generated bo netdev_state_change(). However, this is not
> always the case. If bonding changes were done via sysfs or ifenslave
> (old ioctl interface), then only 1 message is seen.
>
> This patch removes duplicate messages in the case of using netlink
> to configure bonding. It introduceds a separte function that
> triggers a netdev event and uses that function in the syfs and ioctl
> cases.
>
> This was discovered while auditing all the different envents and
> continues the effort of cleaning up duplicated netlink messages.
>
> CC: David Ahern <dsa@cumulusnetworks.com>
> CC: Jiri Pirko <jiri@resnulli.us>
> Signed-off-by: Vladislav Yasevich <vyasevic@redhat.com>
> ---
> drivers/net/bonding/bond_main.c | 3 ++-
> drivers/net/bonding/bond_options.c | 27 +++++++++++++++++++++++++--
> include/net/bond_options.h | 2 ++
> 3 files changed, 29 insertions(+), 3 deletions(-)
>
Acked-by: David Ahern <dsahern@gmail.com>
^ permalink raw reply
* [PATCH v2] mac80211: Invoke TX LED in more code paths
From: Bjorn Andersson @ 2017-05-27 21:59 UTC (permalink / raw)
To: Kalle Valo, Johannes Berg, David S. Miller
Cc: open list:MAC80211, open list:NETWORKING [GENERAL], open list,
linux-arm-msm
ieee80211_tx_status() is only one of the possible ways a driver can
report a handled packet, some drivers call this for every packet while
others calls it rarely or never.
In order to invoke the TX LED in the non-status reporting cases this
patch pushes the call to ieee80211_led_tx() into
ieee80211_report_used_skb(), which is shared between the various code
paths.
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
net/mac80211/status.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index be47ac5cd8c8..a9fa6ee57e8f 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -546,6 +546,8 @@ static void ieee80211_report_used_skb(struct ieee80211_local *local,
skb->wifi_acked_valid = 1;
skb->wifi_acked = acked;
}
+
+ ieee80211_led_tx(local);
}
/*
@@ -823,8 +825,6 @@ static void __ieee80211_tx_status(struct ieee80211_hw *hw,
}
}
- ieee80211_led_tx(local);
-
/* SNMP counters
* Fragments are passed to low-level drivers as separate skbs, so these
* are actually fragments, not frames. Update frame counters only for
--
2.12.0
^ permalink raw reply related
* Re: [PATCH net-next] net: stmmac: use correct pointer when printing normal descriptor ring
From: Andy Shevchenko @ 2017-05-27 21:59 UTC (permalink / raw)
To: Niklas Cassel
Cc: Giuseppe Cavallaro, Alexandre Torgue, Niklas Cassel, netdev,
linux-kernel@vger.kernel.org
In-Reply-To: <20170509165202.19023-1-niklass@axis.com>
On Tue, May 9, 2017 at 7:52 PM, Niklas Cassel <niklas.cassel@axis.com> wrote:
> From: Niklas Cassel <niklas.cassel@axis.com>
Commit message?
> seq_printf(seq, "%d [0x%x]: 0x%x 0x%x 0x%x 0x%x\n",
> - i, (unsigned int)virt_to_phys(ep),
> + i, (unsigned int)virt_to_phys(p),
There is should not be casting. Pointer might be 64-bit, thus %pap
must be used instead with a reference to the physical address.
> le32_to_cpu(p->des0), le32_to_cpu(p->des1),
> le32_to_cpu(p->des2), le32_to_cpu(p->des3));
> p++;
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* [PATCH v2 net-next 0/9] net: another round of extack handling for routing
From: David Ahern @ 2017-05-27 22:19 UTC (permalink / raw)
To: netdev; +Cc: roopa, David Ahern
This set focuses on passing extack through lwtunnel and MPLS with
additional catches for IPv4 route add and minor cleanups in MPLS
encountered passing the extack arg around.
v2
- mindful of bloat adding duplicate messages
+ refactored prefix and prefix length checks in ipv4's fib_table_insert
and fib_table_del
+ refactored label check in mpls
- split mpls cleanups into 2 patches
+ move nla_get_via up in af_mpls to avoid forward declaration
David Ahern (9):
net: ipv4: refactor key and length checks
net: ipv4: Add extack message for invalid prefix or length
net: lwtunnel: Add extack to encap attr validation
net: add extack arg to lwtunnel build state
net: Fill in extack for mpls lwt encap
net: mpls: Pull common label check into helper
net: mpls: Add extack messages for route add and delete failures
net: mpls: Make nla_get_via in af_mpls.c
net: mpls: remove unnecessary initialization of err
include/linux/netlink.h | 10 ++
include/net/ip_fib.h | 3 +-
include/net/lwtunnel.h | 22 ++--
net/core/lwt_bpf.c | 5 +-
net/core/lwtunnel.c | 38 +++++--
net/ipv4/fib_frontend.c | 13 ++-
net/ipv4/fib_lookup.h | 3 +-
net/ipv4/fib_semantics.c | 20 ++--
net/ipv4/fib_trie.c | 34 +++---
net/ipv4/ip_tunnel_core.c | 11 +-
net/ipv6/ila/ila_lwt.c | 5 +-
net/ipv6/route.c | 6 +-
net/ipv6/seg6_iptunnel.c | 5 +-
net/mpls/af_mpls.c | 266 +++++++++++++++++++++++++++++-----------------
net/mpls/internal.h | 4 +-
net/mpls/mpls_iptunnel.c | 17 +--
16 files changed, 301 insertions(+), 161 deletions(-)
--
2.11.0 (Apple Git-81)
^ permalink raw reply
* [PATCH v2 net-next 1/9] net: ipv4: refactor key and length checks
From: David Ahern @ 2017-05-27 22:19 UTC (permalink / raw)
To: netdev; +Cc: roopa, David Ahern
In-Reply-To: <20170527221933.57644-1-dsahern@gmail.com>
fib_table_insert and fib_table_delete have the same checks on the prefix
and length. Refactor into a helper. Avoids duplicate extack messages in
the next patch.
Signed-off-by: David Ahern <dsahern@gmail.com>
---
net/ipv4/fib_trie.c | 25 +++++++++++++++----------
1 file changed, 15 insertions(+), 10 deletions(-)
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index 6e9df7d9bcc2..9bd46e1e1037 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -1099,6 +1099,17 @@ static int fib_insert_alias(struct trie *t, struct key_vector *tp,
return 0;
}
+static bool fib_valid_key_len(u32 key, u8 plen)
+{
+ if (plen > KEYLENGTH)
+ return false;
+
+ if ((plen < KEYLENGTH) && (key << plen))
+ return false;
+
+ return true;
+}
+
/* Caller must hold RTNL. */
int fib_table_insert(struct net *net, struct fib_table *tb,
struct fib_config *cfg, struct netlink_ext_ack *extack)
@@ -1115,16 +1126,13 @@ int fib_table_insert(struct net *net, struct fib_table *tb,
u32 key;
int err;
- if (plen > KEYLENGTH)
- return -EINVAL;
-
key = ntohl(cfg->fc_dst);
- pr_debug("Insert table=%u %08x/%d\n", tb->tb_id, key, plen);
-
- if ((plen < KEYLENGTH) && (key << plen))
+ if (!fib_valid_key_len(key, plen))
return -EINVAL;
+ pr_debug("Insert table=%u %08x/%d\n", tb->tb_id, key, plen);
+
fi = fib_create_info(cfg, extack);
if (IS_ERR(fi)) {
err = PTR_ERR(fi);
@@ -1518,12 +1526,9 @@ int fib_table_delete(struct net *net, struct fib_table *tb,
u8 tos = cfg->fc_tos;
u32 key;
- if (plen > KEYLENGTH)
- return -EINVAL;
-
key = ntohl(cfg->fc_dst);
- if ((plen < KEYLENGTH) && (key << plen))
+ if (!fib_valid_key_len(key, plen))
return -EINVAL;
l = fib_find_node(t, &tp, key);
--
2.11.0 (Apple Git-81)
^ permalink raw reply related
* [PATCH v2 net-next 2/9] net: ipv4: Add extack message for invalid prefix or length
From: David Ahern @ 2017-05-27 22:19 UTC (permalink / raw)
To: netdev; +Cc: roopa, David Ahern
In-Reply-To: <20170527221933.57644-1-dsahern@gmail.com>
Add extack error message for invalid prefix length and invalid prefix.
Example of the latter is a route spec containing 172.16.100.1/24, where
the /24 mask means the lower 8-bits should be 0. Amazing how easy that
one is to overlook when an EINVAL is returned.
Signed-off-by: David Ahern <dsahern@gmail.com>
---
include/net/ip_fib.h | 3 ++-
net/ipv4/fib_frontend.c | 7 ++++---
net/ipv4/fib_trie.c | 17 +++++++++++------
3 files changed, 17 insertions(+), 10 deletions(-)
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index 25f5c516afd1..c3fa1f0438c1 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -266,7 +266,8 @@ int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp,
struct fib_result *res, int fib_flags);
int fib_table_insert(struct net *, struct fib_table *, struct fib_config *,
struct netlink_ext_ack *extack);
-int fib_table_delete(struct net *, struct fib_table *, struct fib_config *);
+int fib_table_delete(struct net *, struct fib_table *, struct fib_config *,
+ struct netlink_ext_ack *extack);
int fib_table_dump(struct fib_table *table, struct sk_buff *skb,
struct netlink_callback *cb);
int fib_table_flush(struct net *net, struct fib_table *table);
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 14d2f7bd7c76..715b7967d8ea 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -588,7 +588,8 @@ int ip_rt_ioctl(struct net *net, unsigned int cmd, void __user *arg)
if (cmd == SIOCDELRT) {
tb = fib_get_table(net, cfg.fc_table);
if (tb)
- err = fib_table_delete(net, tb, &cfg);
+ err = fib_table_delete(net, tb, &cfg,
+ NULL);
else
err = -ESRCH;
} else {
@@ -732,7 +733,7 @@ static int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh,
goto errout;
}
- err = fib_table_delete(net, tb, &cfg);
+ err = fib_table_delete(net, tb, &cfg, extack);
errout:
return err;
}
@@ -851,7 +852,7 @@ static void fib_magic(int cmd, int type, __be32 dst, int dst_len, struct in_ifad
if (cmd == RTM_NEWROUTE)
fib_table_insert(net, tb, &cfg, NULL);
else
- fib_table_delete(net, tb, &cfg);
+ fib_table_delete(net, tb, &cfg, NULL);
}
void fib_add_ifaddr(struct in_ifaddr *ifa)
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index 9bd46e1e1037..a624d380c81d 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -1099,13 +1099,18 @@ static int fib_insert_alias(struct trie *t, struct key_vector *tp,
return 0;
}
-static bool fib_valid_key_len(u32 key, u8 plen)
+static bool fib_valid_key_len(u32 key, u8 plen, struct netlink_ext_ack *extack)
{
- if (plen > KEYLENGTH)
+ if (plen > KEYLENGTH) {
+ NL_SET_ERR_MSG(extack, "Invalid prefix length");
return false;
+ }
- if ((plen < KEYLENGTH) && (key << plen))
+ if ((plen < KEYLENGTH) && (key << plen)) {
+ NL_SET_ERR_MSG(extack,
+ "Invalid prefix for given prefix length");
return false;
+ }
return true;
}
@@ -1128,7 +1133,7 @@ int fib_table_insert(struct net *net, struct fib_table *tb,
key = ntohl(cfg->fc_dst);
- if (!fib_valid_key_len(key, plen))
+ if (!fib_valid_key_len(key, plen, extack))
return -EINVAL;
pr_debug("Insert table=%u %08x/%d\n", tb->tb_id, key, plen);
@@ -1516,7 +1521,7 @@ static void fib_remove_alias(struct trie *t, struct key_vector *tp,
/* Caller must hold RTNL. */
int fib_table_delete(struct net *net, struct fib_table *tb,
- struct fib_config *cfg)
+ struct fib_config *cfg, struct netlink_ext_ack *extack)
{
struct trie *t = (struct trie *) tb->tb_data;
struct fib_alias *fa, *fa_to_delete;
@@ -1528,7 +1533,7 @@ int fib_table_delete(struct net *net, struct fib_table *tb,
key = ntohl(cfg->fc_dst);
- if (!fib_valid_key_len(key, plen))
+ if (!fib_valid_key_len(key, plen, extack))
return -EINVAL;
l = fib_find_node(t, &tp, key);
--
2.11.0 (Apple Git-81)
^ permalink raw reply related
* [PATCH v2 net-next 3/9] net: lwtunnel: Add extack to encap attr validation
From: David Ahern @ 2017-05-27 22:19 UTC (permalink / raw)
To: netdev; +Cc: roopa, David Ahern
In-Reply-To: <20170527221933.57644-1-dsahern@gmail.com>
Pass extack down to lwtunnel_valid_encap_type and
lwtunnel_valid_encap_type_attr. Add messages for unknown
or unsupported encap types.
Signed-off-by: David Ahern <dsahern@gmail.com>
---
include/net/lwtunnel.h | 13 +++++++++----
net/core/lwtunnel.c | 18 +++++++++++++-----
net/ipv4/fib_frontend.c | 6 ++++--
net/ipv6/route.c | 4 ++--
4 files changed, 28 insertions(+), 13 deletions(-)
diff --git a/include/net/lwtunnel.h b/include/net/lwtunnel.h
index ebfe237aad7e..ca6f002774ef 100644
--- a/include/net/lwtunnel.h
+++ b/include/net/lwtunnel.h
@@ -107,8 +107,10 @@ int lwtunnel_encap_add_ops(const struct lwtunnel_encap_ops *op,
unsigned int num);
int lwtunnel_encap_del_ops(const struct lwtunnel_encap_ops *op,
unsigned int num);
-int lwtunnel_valid_encap_type(u16 encap_type);
-int lwtunnel_valid_encap_type_attr(struct nlattr *attr, int len);
+int lwtunnel_valid_encap_type(u16 encap_type,
+ struct netlink_ext_ack *extack);
+int lwtunnel_valid_encap_type_attr(struct nlattr *attr, int len,
+ struct netlink_ext_ack *extack);
int lwtunnel_build_state(u16 encap_type,
struct nlattr *encap,
unsigned int family, const void *cfg,
@@ -172,11 +174,14 @@ static inline int lwtunnel_encap_del_ops(const struct lwtunnel_encap_ops *op,
return -EOPNOTSUPP;
}
-static inline int lwtunnel_valid_encap_type(u16 encap_type)
+static inline int lwtunnel_valid_encap_type(u16 encap_type,
+ struct netlink_ext_ack *extack)
{
+ NL_SET_ERR_MSG(extack, "CONFIG_LWTUNNEL is not enabled in this kernel");
return -EOPNOTSUPP;
}
-static inline int lwtunnel_valid_encap_type_attr(struct nlattr *attr, int len)
+static inline int lwtunnel_valid_encap_type_attr(struct nlattr *attr, int len,
+ struct netlink_ext_ack *extack)
{
/* return 0 since we are not walking attr looking for
* RTA_ENCAP_TYPE attribute on nexthops.
diff --git a/net/core/lwtunnel.c b/net/core/lwtunnel.c
index cfae3d5fe11f..ab840386a74d 100644
--- a/net/core/lwtunnel.c
+++ b/net/core/lwtunnel.c
@@ -126,14 +126,16 @@ int lwtunnel_build_state(u16 encap_type,
}
EXPORT_SYMBOL(lwtunnel_build_state);
-int lwtunnel_valid_encap_type(u16 encap_type)
+int lwtunnel_valid_encap_type(u16 encap_type, struct netlink_ext_ack *extack)
{
const struct lwtunnel_encap_ops *ops;
int ret = -EINVAL;
if (encap_type == LWTUNNEL_ENCAP_NONE ||
- encap_type > LWTUNNEL_ENCAP_MAX)
+ encap_type > LWTUNNEL_ENCAP_MAX) {
+ NL_SET_ERR_MSG(extack, "Unknown lwt encapsulation type");
return ret;
+ }
rcu_read_lock();
ops = rcu_dereference(lwtun_encaps[encap_type]);
@@ -153,11 +155,16 @@ int lwtunnel_valid_encap_type(u16 encap_type)
}
}
#endif
- return ops ? 0 : -EOPNOTSUPP;
+ ret = ops ? 0 : -EOPNOTSUPP;
+ if (ret < 0)
+ NL_SET_ERR_MSG(extack, "lwt encapsulation type not supported");
+
+ return ret;
}
EXPORT_SYMBOL(lwtunnel_valid_encap_type);
-int lwtunnel_valid_encap_type_attr(struct nlattr *attr, int remaining)
+int lwtunnel_valid_encap_type_attr(struct nlattr *attr, int remaining,
+ struct netlink_ext_ack *extack)
{
struct rtnexthop *rtnh = (struct rtnexthop *)attr;
struct nlattr *nla_entype;
@@ -174,7 +181,8 @@ int lwtunnel_valid_encap_type_attr(struct nlattr *attr, int remaining)
if (nla_entype) {
encap_type = nla_get_u16(nla_entype);
- if (lwtunnel_valid_encap_type(encap_type) != 0)
+ if (lwtunnel_valid_encap_type(encap_type,
+ extack) != 0)
return -EOPNOTSUPP;
}
}
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 715b7967d8ea..4e678fa892dd 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -685,7 +685,8 @@ static int rtm_to_fib_config(struct net *net, struct sk_buff *skb,
break;
case RTA_MULTIPATH:
err = lwtunnel_valid_encap_type_attr(nla_data(attr),
- nla_len(attr));
+ nla_len(attr),
+ extack);
if (err < 0)
goto errout;
cfg->fc_mp = nla_data(attr);
@@ -702,7 +703,8 @@ static int rtm_to_fib_config(struct net *net, struct sk_buff *skb,
break;
case RTA_ENCAP_TYPE:
cfg->fc_encap_type = nla_get_u16(attr);
- err = lwtunnel_valid_encap_type(cfg->fc_encap_type);
+ err = lwtunnel_valid_encap_type(cfg->fc_encap_type,
+ extack);
if (err < 0)
goto errout;
break;
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 2fe84bdc4e60..524a76b5206e 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -3016,7 +3016,7 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
cfg->fc_mp_len = nla_len(tb[RTA_MULTIPATH]);
err = lwtunnel_valid_encap_type_attr(cfg->fc_mp,
- cfg->fc_mp_len);
+ cfg->fc_mp_len, extack);
if (err < 0)
goto errout;
}
@@ -3035,7 +3035,7 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
if (tb[RTA_ENCAP_TYPE]) {
cfg->fc_encap_type = nla_get_u16(tb[RTA_ENCAP_TYPE]);
- err = lwtunnel_valid_encap_type(cfg->fc_encap_type);
+ err = lwtunnel_valid_encap_type(cfg->fc_encap_type, extack);
if (err < 0)
goto errout;
}
--
2.11.0 (Apple Git-81)
^ permalink raw reply related
* [PATCH v2 net-next 4/9] net: add extack arg to lwtunnel build state
From: David Ahern @ 2017-05-27 22:19 UTC (permalink / raw)
To: netdev; +Cc: roopa, David Ahern
In-Reply-To: <20170527221933.57644-1-dsahern@gmail.com>
Pass extack arg down to lwtunnel_build_state and the build_state callbacks.
Add messages for failures in lwtunnel_build_state, and add the extarg to
nla_parse where possible in the build_state callbacks.
Signed-off-by: David Ahern <dsahern@gmail.com>
---
include/linux/netlink.h | 10 ++++++++++
include/net/lwtunnel.h | 9 ++++++---
net/core/lwt_bpf.c | 5 +++--
net/core/lwtunnel.c | 20 +++++++++++++++++---
net/ipv4/fib_lookup.h | 3 ++-
net/ipv4/fib_semantics.c | 20 +++++++++++---------
net/ipv4/fib_trie.c | 2 +-
net/ipv4/ip_tunnel_core.c | 11 +++++++----
net/ipv6/ila/ila_lwt.c | 5 +++--
net/ipv6/route.c | 2 +-
net/ipv6/seg6_iptunnel.c | 5 +++--
net/mpls/mpls_iptunnel.c | 5 +++--
12 files changed, 67 insertions(+), 30 deletions(-)
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index a68aad484c69..8664fd26eb5d 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -102,6 +102,16 @@ struct netlink_ext_ack {
(extack)->bad_attr = (attr); \
} while (0)
+#define NL_SET_ERR_MSG_ATTR(extack, attr, msg) do { \
+ static const char __msg[] = (msg); \
+ struct netlink_ext_ack *__extack = (extack); \
+ \
+ if (__extack) { \
+ __extack->_msg = __msg; \
+ __extack->bad_attr = (attr); \
+ } \
+} while (0)
+
extern void netlink_kernel_release(struct sock *sk);
extern int __netlink_change_ngroups(struct sock *sk, unsigned int groups);
extern int netlink_change_ngroups(struct sock *sk, unsigned int groups);
diff --git a/include/net/lwtunnel.h b/include/net/lwtunnel.h
index ca6f002774ef..7c26863b8cf4 100644
--- a/include/net/lwtunnel.h
+++ b/include/net/lwtunnel.h
@@ -35,7 +35,8 @@ struct lwtunnel_state {
struct lwtunnel_encap_ops {
int (*build_state)(struct nlattr *encap,
unsigned int family, const void *cfg,
- struct lwtunnel_state **ts);
+ struct lwtunnel_state **ts,
+ struct netlink_ext_ack *extack);
void (*destroy_state)(struct lwtunnel_state *lws);
int (*output)(struct net *net, struct sock *sk, struct sk_buff *skb);
int (*input)(struct sk_buff *skb);
@@ -114,7 +115,8 @@ int lwtunnel_valid_encap_type_attr(struct nlattr *attr, int len,
int lwtunnel_build_state(u16 encap_type,
struct nlattr *encap,
unsigned int family, const void *cfg,
- struct lwtunnel_state **lws);
+ struct lwtunnel_state **lws,
+ struct netlink_ext_ack *extack);
int lwtunnel_fill_encap(struct sk_buff *skb,
struct lwtunnel_state *lwtstate);
int lwtunnel_get_encap_size(struct lwtunnel_state *lwtstate);
@@ -192,7 +194,8 @@ static inline int lwtunnel_valid_encap_type_attr(struct nlattr *attr, int len,
static inline int lwtunnel_build_state(u16 encap_type,
struct nlattr *encap,
unsigned int family, const void *cfg,
- struct lwtunnel_state **lws)
+ struct lwtunnel_state **lws,
+ struct netlink_ext_ack *extack)
{
return -EOPNOTSUPP;
}
diff --git a/net/core/lwt_bpf.c b/net/core/lwt_bpf.c
index b3bc0a31af9f..1307731ddfe4 100644
--- a/net/core/lwt_bpf.c
+++ b/net/core/lwt_bpf.c
@@ -240,7 +240,8 @@ static const struct nla_policy bpf_nl_policy[LWT_BPF_MAX + 1] = {
static int bpf_build_state(struct nlattr *nla,
unsigned int family, const void *cfg,
- struct lwtunnel_state **ts)
+ struct lwtunnel_state **ts,
+ struct netlink_ext_ack *extack)
{
struct nlattr *tb[LWT_BPF_MAX + 1];
struct lwtunnel_state *newts;
@@ -250,7 +251,7 @@ static int bpf_build_state(struct nlattr *nla,
if (family != AF_INET && family != AF_INET6)
return -EAFNOSUPPORT;
- ret = nla_parse_nested(tb, LWT_BPF_MAX, nla, bpf_nl_policy, NULL);
+ ret = nla_parse_nested(tb, LWT_BPF_MAX, nla, bpf_nl_policy, extack);
if (ret < 0)
return ret;
diff --git a/net/core/lwtunnel.c b/net/core/lwtunnel.c
index ab840386a74d..d9cb3532f1dd 100644
--- a/net/core/lwtunnel.c
+++ b/net/core/lwtunnel.c
@@ -103,25 +103,39 @@ EXPORT_SYMBOL(lwtunnel_encap_del_ops);
int lwtunnel_build_state(u16 encap_type,
struct nlattr *encap, unsigned int family,
- const void *cfg, struct lwtunnel_state **lws)
+ const void *cfg, struct lwtunnel_state **lws,
+ struct netlink_ext_ack *extack)
{
const struct lwtunnel_encap_ops *ops;
+ bool found = false;
int ret = -EINVAL;
if (encap_type == LWTUNNEL_ENCAP_NONE ||
- encap_type > LWTUNNEL_ENCAP_MAX)
+ encap_type > LWTUNNEL_ENCAP_MAX) {
+ NL_SET_ERR_MSG_ATTR(extack, encap,
+ "Unknown LWT encapsulation type");
return ret;
+ }
ret = -EOPNOTSUPP;
rcu_read_lock();
ops = rcu_dereference(lwtun_encaps[encap_type]);
if (likely(ops && ops->build_state && try_module_get(ops->owner))) {
- ret = ops->build_state(encap, family, cfg, lws);
+ found = true;
+ ret = ops->build_state(encap, family, cfg, lws, extack);
if (ret)
module_put(ops->owner);
}
rcu_read_unlock();
+ /* don't rely on -EOPNOTSUPP to detect match as build_state
+ * handlers could return it
+ */
+ if (!found) {
+ NL_SET_ERR_MSG_ATTR(extack, encap,
+ "LWT encapsulation type not supported");
+ }
+
return ret;
}
EXPORT_SYMBOL(lwtunnel_build_state);
diff --git a/net/ipv4/fib_lookup.h b/net/ipv4/fib_lookup.h
index 2704e08545da..769ab87ebc4b 100644
--- a/net/ipv4/fib_lookup.h
+++ b/net/ipv4/fib_lookup.h
@@ -30,7 +30,8 @@ static inline void fib_alias_accessed(struct fib_alias *fa)
void fib_release_info(struct fib_info *);
struct fib_info *fib_create_info(struct fib_config *cfg,
struct netlink_ext_ack *extack);
-int fib_nh_match(struct fib_config *cfg, struct fib_info *fi);
+int fib_nh_match(struct fib_config *cfg, struct fib_info *fi,
+ struct netlink_ext_ack *extack);
int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, u32 tb_id,
u8 type, __be32 dst, int dst_len, u8 tos, struct fib_info *fi,
unsigned int);
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index 4852e183afe0..89e8fcc8449b 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -530,7 +530,7 @@ static int fib_get_nhs(struct fib_info *fi, struct rtnexthop *rtnh,
ret = lwtunnel_build_state(nla_get_u16(
nla_entype),
nla, AF_INET, cfg,
- &lwtstate);
+ &lwtstate, extack);
if (ret)
goto errout;
nexthop_nh->nh_lwtstate =
@@ -612,7 +612,8 @@ static inline void fib_add_weight(struct fib_info *fi,
static int fib_encap_match(u16 encap_type,
struct nlattr *encap,
const struct fib_nh *nh,
- const struct fib_config *cfg)
+ const struct fib_config *cfg,
+ struct netlink_ext_ack *extack)
{
struct lwtunnel_state *lwtstate;
int ret, result = 0;
@@ -620,8 +621,8 @@ static int fib_encap_match(u16 encap_type,
if (encap_type == LWTUNNEL_ENCAP_NONE)
return 0;
- ret = lwtunnel_build_state(encap_type, encap,
- AF_INET, cfg, &lwtstate);
+ ret = lwtunnel_build_state(encap_type, encap, AF_INET,
+ cfg, &lwtstate, extack);
if (!ret) {
result = lwtunnel_cmp_encap(lwtstate, nh->nh_lwtstate);
lwtstate_free(lwtstate);
@@ -630,7 +631,8 @@ static int fib_encap_match(u16 encap_type,
return result;
}
-int fib_nh_match(struct fib_config *cfg, struct fib_info *fi)
+int fib_nh_match(struct fib_config *cfg, struct fib_info *fi,
+ struct netlink_ext_ack *extack)
{
#ifdef CONFIG_IP_ROUTE_MULTIPATH
struct rtnexthop *rtnh;
@@ -642,9 +644,9 @@ int fib_nh_match(struct fib_config *cfg, struct fib_info *fi)
if (cfg->fc_oif || cfg->fc_gw) {
if (cfg->fc_encap) {
- if (fib_encap_match(cfg->fc_encap_type,
- cfg->fc_encap, fi->fib_nh, cfg))
- return 1;
+ if (fib_encap_match(cfg->fc_encap_type, cfg->fc_encap,
+ fi->fib_nh, cfg, extack))
+ return 1;
}
if ((!cfg->fc_oif || cfg->fc_oif == fi->fib_nh->nh_oif) &&
(!cfg->fc_gw || cfg->fc_gw == fi->fib_nh->nh_gw))
@@ -1145,7 +1147,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg,
}
err = lwtunnel_build_state(cfg->fc_encap_type,
cfg->fc_encap, AF_INET, cfg,
- &lwtstate);
+ &lwtstate, extack);
if (err)
goto failure;
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index a624d380c81d..d56659e97a6e 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -1562,7 +1562,7 @@ int fib_table_delete(struct net *net, struct fib_table *tb,
fi->fib_prefsrc == cfg->fc_prefsrc) &&
(!cfg->fc_protocol ||
fi->fib_protocol == cfg->fc_protocol) &&
- fib_nh_match(cfg, fi) == 0) {
+ fib_nh_match(cfg, fi, extack) == 0) {
fa_to_delete = fa;
break;
}
diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c
index baf196eaf1d8..90e11479c725 100644
--- a/net/ipv4/ip_tunnel_core.c
+++ b/net/ipv4/ip_tunnel_core.c
@@ -228,14 +228,16 @@ static const struct nla_policy ip_tun_policy[LWTUNNEL_IP_MAX + 1] = {
static int ip_tun_build_state(struct nlattr *attr,
unsigned int family, const void *cfg,
- struct lwtunnel_state **ts)
+ struct lwtunnel_state **ts,
+ struct netlink_ext_ack *extack)
{
struct ip_tunnel_info *tun_info;
struct lwtunnel_state *new_state;
struct nlattr *tb[LWTUNNEL_IP_MAX + 1];
int err;
- err = nla_parse_nested(tb, LWTUNNEL_IP_MAX, attr, ip_tun_policy, NULL);
+ err = nla_parse_nested(tb, LWTUNNEL_IP_MAX, attr, ip_tun_policy,
+ extack);
if (err < 0)
return err;
@@ -325,7 +327,8 @@ static const struct nla_policy ip6_tun_policy[LWTUNNEL_IP6_MAX + 1] = {
static int ip6_tun_build_state(struct nlattr *attr,
unsigned int family, const void *cfg,
- struct lwtunnel_state **ts)
+ struct lwtunnel_state **ts,
+ struct netlink_ext_ack *extack)
{
struct ip_tunnel_info *tun_info;
struct lwtunnel_state *new_state;
@@ -333,7 +336,7 @@ static int ip6_tun_build_state(struct nlattr *attr,
int err;
err = nla_parse_nested(tb, LWTUNNEL_IP6_MAX, attr, ip6_tun_policy,
- NULL);
+ extack);
if (err < 0)
return err;
diff --git a/net/ipv6/ila/ila_lwt.c b/net/ipv6/ila/ila_lwt.c
index f4a413aba423..0c02a09bc351 100644
--- a/net/ipv6/ila/ila_lwt.c
+++ b/net/ipv6/ila/ila_lwt.c
@@ -117,7 +117,8 @@ static const struct nla_policy ila_nl_policy[ILA_ATTR_MAX + 1] = {
static int ila_build_state(struct nlattr *nla,
unsigned int family, const void *cfg,
- struct lwtunnel_state **ts)
+ struct lwtunnel_state **ts,
+ struct netlink_ext_ack *extack)
{
struct ila_lwt *ilwt;
struct ila_params *p;
@@ -146,7 +147,7 @@ static int ila_build_state(struct nlattr *nla,
return -EINVAL;
}
- ret = nla_parse_nested(tb, ILA_ATTR_MAX, nla, ila_nl_policy, NULL);
+ ret = nla_parse_nested(tb, ILA_ATTR_MAX, nla, ila_nl_policy, extack);
if (ret < 0)
return ret;
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 524a76b5206e..9d9b5bbea153 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -1939,7 +1939,7 @@ static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg,
err = lwtunnel_build_state(cfg->fc_encap_type,
cfg->fc_encap, AF_INET6, cfg,
- &lwtstate);
+ &lwtstate, extack);
if (err)
goto out;
rt->dst.lwtstate = lwtstate_get(lwtstate);
diff --git a/net/ipv6/seg6_iptunnel.c b/net/ipv6/seg6_iptunnel.c
index 6a495490d43e..264d772d3c7d 100644
--- a/net/ipv6/seg6_iptunnel.c
+++ b/net/ipv6/seg6_iptunnel.c
@@ -326,7 +326,8 @@ static int seg6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
static int seg6_build_state(struct nlattr *nla,
unsigned int family, const void *cfg,
- struct lwtunnel_state **ts)
+ struct lwtunnel_state **ts,
+ struct netlink_ext_ack *extack)
{
struct nlattr *tb[SEG6_IPTUNNEL_MAX + 1];
struct seg6_iptunnel_encap *tuninfo;
@@ -336,7 +337,7 @@ static int seg6_build_state(struct nlattr *nla,
int err;
err = nla_parse_nested(tb, SEG6_IPTUNNEL_MAX, nla,
- seg6_iptunnel_policy, NULL);
+ seg6_iptunnel_policy, extack);
if (err < 0)
return err;
diff --git a/net/mpls/mpls_iptunnel.c b/net/mpls/mpls_iptunnel.c
index 369c7a23c86c..15e1aa708e50 100644
--- a/net/mpls/mpls_iptunnel.c
+++ b/net/mpls/mpls_iptunnel.c
@@ -159,7 +159,8 @@ static int mpls_xmit(struct sk_buff *skb)
static int mpls_build_state(struct nlattr *nla,
unsigned int family, const void *cfg,
- struct lwtunnel_state **ts)
+ struct lwtunnel_state **ts,
+ struct netlink_ext_ack *extack)
{
struct mpls_iptunnel_encap *tun_encap_info;
struct nlattr *tb[MPLS_IPTUNNEL_MAX + 1];
@@ -168,7 +169,7 @@ static int mpls_build_state(struct nlattr *nla,
int ret;
ret = nla_parse_nested(tb, MPLS_IPTUNNEL_MAX, nla,
- mpls_iptunnel_policy, NULL);
+ mpls_iptunnel_policy, extack);
if (ret < 0)
return ret;
--
2.11.0 (Apple Git-81)
^ permalink raw reply related
* [PATCH v2 net-next 5/9] net: Fill in extack for mpls lwt encap
From: David Ahern @ 2017-05-27 22:19 UTC (permalink / raw)
To: netdev; +Cc: roopa, David Ahern
In-Reply-To: <20170527221933.57644-1-dsahern@gmail.com>
Fill in extack for errors in build_state for mpls lwt encap including
passing extack to nla_get_labels and adding error messages for failures
in it.
Signed-off-by: David Ahern <dsahern@gmail.com>
---
net/mpls/af_mpls.c | 49 ++++++++++++++++++++++++++++++++++++++----------
net/mpls/internal.h | 2 +-
net/mpls/mpls_iptunnel.c | 12 +++++++-----
3 files changed, 47 insertions(+), 16 deletions(-)
diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c
index 257ec66009da..f3830951fb1c 100644
--- a/net/mpls/af_mpls.c
+++ b/net/mpls/af_mpls.c
@@ -728,8 +728,8 @@ static int mpls_nh_build(struct net *net, struct mpls_route *rt,
goto errout;
if (newdst) {
- err = nla_get_labels(newdst, max_labels,
- &nh->nh_labels, nh->nh_label);
+ err = nla_get_labels(newdst, max_labels, &nh->nh_labels,
+ nh->nh_label, NULL);
if (err)
goto errout;
}
@@ -782,7 +782,8 @@ static u8 mpls_count_nexthops(struct rtnexthop *rtnh, int len,
nla = nla_find(attrs, attrlen, RTA_NEWDST);
if (nla &&
- nla_get_labels(nla, MAX_NEW_LABELS, &n_labels, NULL) != 0)
+ nla_get_labels(nla, MAX_NEW_LABELS, &n_labels,
+ NULL, NULL) != 0)
return 0;
*max_labels = max_t(u8, *max_labels, n_labels);
@@ -1541,8 +1542,8 @@ int nla_put_labels(struct sk_buff *skb, int attrtype,
}
EXPORT_SYMBOL_GPL(nla_put_labels);
-int nla_get_labels(const struct nlattr *nla,
- u8 max_labels, u8 *labels, u32 label[])
+int nla_get_labels(const struct nlattr *nla, u8 max_labels, u8 *labels,
+ u32 label[], struct netlink_ext_ack *extack)
{
unsigned len = nla_len(nla);
struct mpls_shim_hdr *nla_label;
@@ -1553,13 +1554,18 @@ int nla_get_labels(const struct nlattr *nla,
/* len needs to be an even multiple of 4 (the label size). Number
* of labels is a u8 so check for overflow.
*/
- if (len & 3 || len / 4 > 255)
+ if (len & 3 || len / 4 > 255) {
+ NL_SET_ERR_MSG_ATTR(extack, nla,
+ "Invalid length for labels attribute");
return -EINVAL;
+ }
/* Limit the number of new labels allowed */
nla_labels = len/4;
- if (nla_labels > max_labels)
+ if (nla_labels > max_labels) {
+ NL_SET_ERR_MSG(extack, "Too many labels");
return -EINVAL;
+ }
/* when label == NULL, caller wants number of labels */
if (!label)
@@ -1574,8 +1580,29 @@ int nla_get_labels(const struct nlattr *nla,
/* Ensure the bottom of stack flag is properly set
* and ttl and tc are both clear.
*/
- if ((dec.bos != bos) || dec.ttl || dec.tc)
+ if (dec.ttl) {
+ NL_SET_ERR_MSG_ATTR(extack, nla,
+ "TTL in label must be 0");
+ return -EINVAL;
+ }
+
+ if (dec.tc) {
+ NL_SET_ERR_MSG_ATTR(extack, nla,
+ "Traffic class in label must be 0");
return -EINVAL;
+ }
+
+ if (dec.bos != bos) {
+ NL_SET_BAD_ATTR(extack, nla);
+ if (bos) {
+ NL_SET_ERR_MSG(extack,
+ "BOS bit must be set in first label");
+ } else {
+ NL_SET_ERR_MSG(extack,
+ "BOS bit can only be set in first label");
+ }
+ return -EINVAL;
+ }
switch (dec.label) {
case MPLS_LABEL_IMPLNULL:
@@ -1583,6 +1610,8 @@ int nla_get_labels(const struct nlattr *nla,
* assign and distribute, but which never
* actually appears in the encapsulation.
*/
+ NL_SET_ERR_MSG_ATTR(extack, nla,
+ "Implicit NULL Label (3) can not be used in encapsulation");
return -EINVAL;
}
@@ -1696,14 +1725,14 @@ static int rtm_to_route_config(struct sk_buff *skb, struct nlmsghdr *nlh,
case RTA_NEWDST:
if (nla_get_labels(nla, MAX_NEW_LABELS,
&cfg->rc_output_labels,
- cfg->rc_output_label))
+ cfg->rc_output_label, NULL))
goto errout;
break;
case RTA_DST:
{
u8 label_count;
if (nla_get_labels(nla, 1, &label_count,
- &cfg->rc_label))
+ &cfg->rc_label, NULL))
goto errout;
/* Reserved labels may not be set */
diff --git a/net/mpls/internal.h b/net/mpls/internal.h
index 4db6a5971322..e59f299ceb3f 100644
--- a/net/mpls/internal.h
+++ b/net/mpls/internal.h
@@ -203,7 +203,7 @@ static inline struct mpls_dev *mpls_dev_get(const struct net_device *dev)
int nla_put_labels(struct sk_buff *skb, int attrtype, u8 labels,
const u32 label[]);
int nla_get_labels(const struct nlattr *nla, u8 max_labels, u8 *labels,
- u32 label[]);
+ u32 label[], struct netlink_ext_ack *extack);
int nla_get_via(const struct nlattr *nla, u8 *via_alen, u8 *via_table,
u8 via[]);
bool mpls_output_possible(const struct net_device *dev);
diff --git a/net/mpls/mpls_iptunnel.c b/net/mpls/mpls_iptunnel.c
index 15e1aa708e50..6e558a419f60 100644
--- a/net/mpls/mpls_iptunnel.c
+++ b/net/mpls/mpls_iptunnel.c
@@ -173,13 +173,14 @@ static int mpls_build_state(struct nlattr *nla,
if (ret < 0)
return ret;
- if (!tb[MPLS_IPTUNNEL_DST])
+ if (!tb[MPLS_IPTUNNEL_DST]) {
+ NL_SET_ERR_MSG(extack, "MPLS_IPTUNNEL_DST attribute is missing");
return -EINVAL;
-
+ }
/* determine number of labels */
- if (nla_get_labels(tb[MPLS_IPTUNNEL_DST],
- MAX_NEW_LABELS, &n_labels, NULL))
+ if (nla_get_labels(tb[MPLS_IPTUNNEL_DST], MAX_NEW_LABELS,
+ &n_labels, NULL, extack))
return -EINVAL;
newts = lwtunnel_state_alloc(sizeof(*tun_encap_info) +
@@ -189,7 +190,8 @@ static int mpls_build_state(struct nlattr *nla,
tun_encap_info = mpls_lwtunnel_encap(newts);
ret = nla_get_labels(tb[MPLS_IPTUNNEL_DST], n_labels,
- &tun_encap_info->labels, tun_encap_info->label);
+ &tun_encap_info->labels, tun_encap_info->label,
+ extack);
if (ret)
goto errout;
--
2.11.0 (Apple Git-81)
^ permalink raw reply related
* [PATCH v2 net-next 7/9] net: mpls: Add extack messages for route add and delete failures
From: David Ahern @ 2017-05-27 22:19 UTC (permalink / raw)
To: netdev; +Cc: roopa, David Ahern
In-Reply-To: <20170527221933.57644-1-dsahern@gmail.com>
Add error messages for failures in adding and deleting mpls routes.
This covers most of the annoying EINVAL errors.
Signed-off-by: David Ahern <dsahern@gmail.com>
---
net/mpls/af_mpls.c | 125 ++++++++++++++++++++++++++++++++++++----------------
net/mpls/internal.h | 2 +-
2 files changed, 87 insertions(+), 40 deletions(-)
diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c
index 726eafecc793..0133d1ad9032 100644
--- a/net/mpls/af_mpls.c
+++ b/net/mpls/af_mpls.c
@@ -720,7 +720,8 @@ static int mpls_nh_build_from_cfg(struct mpls_route_config *cfg,
static int mpls_nh_build(struct net *net, struct mpls_route *rt,
struct mpls_nh *nh, int oif, struct nlattr *via,
- struct nlattr *newdst, u8 max_labels)
+ struct nlattr *newdst, u8 max_labels,
+ struct netlink_ext_ack *extack)
{
int err = -ENOMEM;
@@ -729,14 +730,14 @@ static int mpls_nh_build(struct net *net, struct mpls_route *rt,
if (newdst) {
err = nla_get_labels(newdst, max_labels, &nh->nh_labels,
- nh->nh_label, NULL);
+ nh->nh_label, extack);
if (err)
goto errout;
}
if (via) {
err = nla_get_via(via, &nh->nh_via_alen, &nh->nh_via_table,
- __mpls_nh_via(rt, nh));
+ __mpls_nh_via(rt, nh), extack);
if (err)
goto errout;
} else {
@@ -803,7 +804,8 @@ static u8 mpls_count_nexthops(struct rtnexthop *rtnh, int len,
}
static int mpls_nh_build_multi(struct mpls_route_config *cfg,
- struct mpls_route *rt, u8 max_labels)
+ struct mpls_route *rt, u8 max_labels,
+ struct netlink_ext_ack *extack)
{
struct rtnexthop *rtnh = cfg->rc_mp;
struct nlattr *nla_via, *nla_newdst;
@@ -837,7 +839,7 @@ static int mpls_nh_build_multi(struct mpls_route_config *cfg,
err = mpls_nh_build(cfg->rc_nlinfo.nl_net, rt, nh,
rtnh->rtnh_ifindex, nla_via, nla_newdst,
- max_labels);
+ max_labels, extack);
if (err)
goto errout;
@@ -856,20 +858,28 @@ static int mpls_nh_build_multi(struct mpls_route_config *cfg,
return err;
}
-static bool mpls_label_ok(struct net *net, unsigned int index)
+static bool mpls_label_ok(struct net *net, unsigned int index,
+ struct netlink_ext_ack *extack)
{
/* Reserved labels may not be set */
- if (index < MPLS_LABEL_FIRST_UNRESERVED)
+ if (index < MPLS_LABEL_FIRST_UNRESERVED) {
+ NL_SET_ERR_MSG(extack,
+ "Invalid label - must be MPLS_LABEL_FIRST_UNRESERVED or higher");
return false;
+ }
/* The full 20 bit range may not be supported. */
- if (index >= net->mpls.platform_labels)
+ if (index >= net->mpls.platform_labels) {
+ NL_SET_ERR_MSG(extack,
+ "Label >= configured maximum in platform_labels");
return false;
+ }
return true;
}
-static int mpls_route_add(struct mpls_route_config *cfg)
+static int mpls_route_add(struct mpls_route_config *cfg,
+ struct netlink_ext_ack *extack)
{
struct mpls_route __rcu **platform_label;
struct net *net = cfg->rc_nlinfo.nl_net;
@@ -888,13 +898,15 @@ static int mpls_route_add(struct mpls_route_config *cfg)
index = find_free_label(net);
}
- if (!mpls_label_ok(net, index))
+ if (!mpls_label_ok(net, index, extack))
goto errout;
/* Append makes no sense with mpls */
err = -EOPNOTSUPP;
- if (cfg->rc_nlflags & NLM_F_APPEND)
+ if (cfg->rc_nlflags & NLM_F_APPEND) {
+ NL_SET_ERR_MSG(extack, "MPLS does not support route append");
goto errout;
+ }
err = -EEXIST;
platform_label = rtnl_dereference(net->mpls.platform_label);
@@ -921,8 +933,10 @@ static int mpls_route_add(struct mpls_route_config *cfg)
nhs = 1;
}
- if (nhs == 0)
+ if (nhs == 0) {
+ NL_SET_ERR_MSG(extack, "Route does not contain a nexthop");
goto errout;
+ }
err = -ENOMEM;
rt = mpls_rt_alloc(nhs, max_via_alen, max_labels);
@@ -936,7 +950,7 @@ static int mpls_route_add(struct mpls_route_config *cfg)
rt->rt_ttl_propagate = cfg->rc_ttl_propagate;
if (cfg->rc_mp)
- err = mpls_nh_build_multi(cfg, rt, max_labels);
+ err = mpls_nh_build_multi(cfg, rt, max_labels, extack);
else
err = mpls_nh_build_from_cfg(cfg, rt);
if (err)
@@ -952,7 +966,8 @@ static int mpls_route_add(struct mpls_route_config *cfg)
return err;
}
-static int mpls_route_del(struct mpls_route_config *cfg)
+static int mpls_route_del(struct mpls_route_config *cfg,
+ struct netlink_ext_ack *extack)
{
struct net *net = cfg->rc_nlinfo.nl_net;
unsigned index;
@@ -960,7 +975,7 @@ static int mpls_route_del(struct mpls_route_config *cfg)
index = cfg->rc_label;
- if (!mpls_label_ok(net, index))
+ if (!mpls_label_ok(net, index, extack))
goto errout;
mpls_route_update(net, index, NULL, &cfg->rc_nlinfo);
@@ -1626,19 +1641,25 @@ int nla_get_labels(const struct nlattr *nla, u8 max_labels, u8 *labels,
}
EXPORT_SYMBOL_GPL(nla_get_labels);
-int nla_get_via(const struct nlattr *nla, u8 *via_alen,
- u8 *via_table, u8 via_addr[])
+int nla_get_via(const struct nlattr *nla, u8 *via_alen, u8 *via_table,
+ u8 via_addr[], struct netlink_ext_ack *extack)
{
struct rtvia *via = nla_data(nla);
int err = -EINVAL;
int alen;
- if (nla_len(nla) < offsetof(struct rtvia, rtvia_addr))
+ if (nla_len(nla) < offsetof(struct rtvia, rtvia_addr)) {
+ NL_SET_ERR_MSG_ATTR(extack, nla,
+ "Invalid attribute length for RTA_VIA");
goto errout;
+ }
alen = nla_len(nla) -
offsetof(struct rtvia, rtvia_addr);
- if (alen > MAX_VIA_ALEN)
+ if (alen > MAX_VIA_ALEN) {
+ NL_SET_ERR_MSG_ATTR(extack, nla,
+ "Invalid address length for RTA_VIA");
goto errout;
+ }
/* Validate the address family */
switch (via->rtvia_family) {
@@ -1668,8 +1689,10 @@ int nla_get_via(const struct nlattr *nla, u8 *via_alen,
return err;
}
-static int rtm_to_route_config(struct sk_buff *skb, struct nlmsghdr *nlh,
- struct mpls_route_config *cfg)
+static int rtm_to_route_config(struct sk_buff *skb,
+ struct nlmsghdr *nlh,
+ struct mpls_route_config *cfg,
+ struct netlink_ext_ack *extack)
{
struct rtmsg *rtm;
struct nlattr *tb[RTA_MAX+1];
@@ -1677,35 +1700,54 @@ static int rtm_to_route_config(struct sk_buff *skb, struct nlmsghdr *nlh,
int err;
err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_mpls_policy,
- NULL);
+ extack);
if (err < 0)
goto errout;
err = -EINVAL;
rtm = nlmsg_data(nlh);
- if (rtm->rtm_family != AF_MPLS)
+ if (rtm->rtm_family != AF_MPLS) {
+ NL_SET_ERR_MSG(extack, "Invalid address family in rtmsg");
goto errout;
- if (rtm->rtm_dst_len != 20)
+ }
+ if (rtm->rtm_dst_len != 20) {
+ NL_SET_ERR_MSG(extack, "rtm_dst_len must be 20 for MPLS");
goto errout;
- if (rtm->rtm_src_len != 0)
+ }
+ if (rtm->rtm_src_len != 0) {
+ NL_SET_ERR_MSG(extack, "rtm_src_len must be 0 for MPLS");
goto errout;
- if (rtm->rtm_tos != 0)
+ }
+ if (rtm->rtm_tos != 0) {
+ NL_SET_ERR_MSG(extack, "rtm_tos must be 0 for MPLS");
goto errout;
- if (rtm->rtm_table != RT_TABLE_MAIN)
+ }
+ if (rtm->rtm_table != RT_TABLE_MAIN) {
+ NL_SET_ERR_MSG(extack,
+ "MPLS only supports the main route table");
goto errout;
+ }
/* Any value is acceptable for rtm_protocol */
/* As mpls uses destination specific addresses
* (or source specific address in the case of multicast)
* all addresses have universal scope.
*/
- if (rtm->rtm_scope != RT_SCOPE_UNIVERSE)
+ if (rtm->rtm_scope != RT_SCOPE_UNIVERSE) {
+ NL_SET_ERR_MSG(extack,
+ "Invalid route scope - MPLS only supports UNIVERSE");
goto errout;
- if (rtm->rtm_type != RTN_UNICAST)
+ }
+ if (rtm->rtm_type != RTN_UNICAST) {
+ NL_SET_ERR_MSG(extack,
+ "Invalid route type - MPLS only supports UNICAST");
goto errout;
- if (rtm->rtm_flags != 0)
+ }
+ if (rtm->rtm_flags != 0) {
+ NL_SET_ERR_MSG(extack, "rtm_flags must be 0 for MPLS");
goto errout;
+ }
cfg->rc_label = LABEL_NOT_SPECIFIED;
cfg->rc_protocol = rtm->rtm_protocol;
@@ -1728,25 +1770,26 @@ static int rtm_to_route_config(struct sk_buff *skb, struct nlmsghdr *nlh,
case RTA_NEWDST:
if (nla_get_labels(nla, MAX_NEW_LABELS,
&cfg->rc_output_labels,
- cfg->rc_output_label, NULL))
+ cfg->rc_output_label, extack))
goto errout;
break;
case RTA_DST:
{
u8 label_count;
if (nla_get_labels(nla, 1, &label_count,
- &cfg->rc_label, NULL))
+ &cfg->rc_label, extack))
goto errout;
if (!mpls_label_ok(cfg->rc_nlinfo.nl_net,
- cfg->rc_label))
+ cfg->rc_label, extack))
goto errout;
break;
}
case RTA_VIA:
{
if (nla_get_via(nla, &cfg->rc_via_alen,
- &cfg->rc_via_table, cfg->rc_via))
+ &cfg->rc_via_table, cfg->rc_via,
+ extack))
goto errout;
break;
}
@@ -1760,14 +1803,18 @@ static int rtm_to_route_config(struct sk_buff *skb, struct nlmsghdr *nlh,
{
u8 ttl_propagate = nla_get_u8(nla);
- if (ttl_propagate > 1)
+ if (ttl_propagate > 1) {
+ NL_SET_ERR_MSG_ATTR(extack, nla,
+ "RTA_TTL_PROPAGATE can only be 0 or 1");
goto errout;
+ }
cfg->rc_ttl_propagate = ttl_propagate ?
MPLS_TTL_PROP_ENABLED :
MPLS_TTL_PROP_DISABLED;
break;
}
default:
+ NL_SET_ERR_MSG_ATTR(extack, nla, "Unknown attribute");
/* Unsupported attribute */
goto errout;
}
@@ -1788,11 +1835,11 @@ static int mpls_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh,
if (!cfg)
return -ENOMEM;
- err = rtm_to_route_config(skb, nlh, cfg);
+ err = rtm_to_route_config(skb, nlh, cfg, extack);
if (err < 0)
goto out;
- err = mpls_route_del(cfg);
+ err = mpls_route_del(cfg, extack);
out:
kfree(cfg);
@@ -1810,11 +1857,11 @@ static int mpls_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh,
if (!cfg)
return -ENOMEM;
- err = rtm_to_route_config(skb, nlh, cfg);
+ err = rtm_to_route_config(skb, nlh, cfg, extack);
if (err < 0)
goto out;
- err = mpls_route_add(cfg);
+ err = mpls_route_add(cfg, extack);
out:
kfree(cfg);
diff --git a/net/mpls/internal.h b/net/mpls/internal.h
index e59f299ceb3f..a015a6a1143b 100644
--- a/net/mpls/internal.h
+++ b/net/mpls/internal.h
@@ -205,7 +205,7 @@ int nla_put_labels(struct sk_buff *skb, int attrtype, u8 labels,
int nla_get_labels(const struct nlattr *nla, u8 max_labels, u8 *labels,
u32 label[], struct netlink_ext_ack *extack);
int nla_get_via(const struct nlattr *nla, u8 *via_alen, u8 *via_table,
- u8 via[]);
+ u8 via[], struct netlink_ext_ack *extack);
bool mpls_output_possible(const struct net_device *dev);
unsigned int mpls_dev_mtu(const struct net_device *dev);
bool mpls_pkt_too_big(const struct sk_buff *skb, unsigned int mtu);
--
2.11.0 (Apple Git-81)
^ permalink raw reply related
* [PATCH v2 net-next 8/9] net: mpls: Make nla_get_via in af_mpls.c
From: David Ahern @ 2017-05-27 22:19 UTC (permalink / raw)
To: netdev; +Cc: roopa, David Ahern
In-Reply-To: <20170527221933.57644-1-dsahern@gmail.com>
nla_get_via is only used in af_mpls.c. Remove declaration from internal.h
and move up in af_mpls.c before first use. Code move only; no
functional change intended.
Signed-off-by: David Ahern <dsahern@gmail.com>
---
net/mpls/af_mpls.c | 96 ++++++++++++++++++++++++++---------------------------
net/mpls/internal.h | 2 --
2 files changed, 48 insertions(+), 50 deletions(-)
diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c
index 0133d1ad9032..a953fcf169ba 100644
--- a/net/mpls/af_mpls.c
+++ b/net/mpls/af_mpls.c
@@ -684,6 +684,54 @@ static int mpls_nh_assign_dev(struct net *net, struct mpls_route *rt,
return err;
}
+static int nla_get_via(const struct nlattr *nla, u8 *via_alen, u8 *via_table,
+ u8 via_addr[], struct netlink_ext_ack *extack)
+{
+ struct rtvia *via = nla_data(nla);
+ int err = -EINVAL;
+ int alen;
+
+ if (nla_len(nla) < offsetof(struct rtvia, rtvia_addr)) {
+ NL_SET_ERR_MSG_ATTR(extack, nla,
+ "Invalid attribute length for RTA_VIA");
+ goto errout;
+ }
+ alen = nla_len(nla) -
+ offsetof(struct rtvia, rtvia_addr);
+ if (alen > MAX_VIA_ALEN) {
+ NL_SET_ERR_MSG_ATTR(extack, nla,
+ "Invalid address length for RTA_VIA");
+ goto errout;
+ }
+
+ /* Validate the address family */
+ switch (via->rtvia_family) {
+ case AF_PACKET:
+ *via_table = NEIGH_LINK_TABLE;
+ break;
+ case AF_INET:
+ *via_table = NEIGH_ARP_TABLE;
+ if (alen != 4)
+ goto errout;
+ break;
+ case AF_INET6:
+ *via_table = NEIGH_ND_TABLE;
+ if (alen != 16)
+ goto errout;
+ break;
+ default:
+ /* Unsupported address family */
+ goto errout;
+ }
+
+ memcpy(via_addr, via->rtvia_addr, alen);
+ *via_alen = alen;
+ err = 0;
+
+errout:
+ return err;
+}
+
static int mpls_nh_build_from_cfg(struct mpls_route_config *cfg,
struct mpls_route *rt)
{
@@ -1641,54 +1689,6 @@ int nla_get_labels(const struct nlattr *nla, u8 max_labels, u8 *labels,
}
EXPORT_SYMBOL_GPL(nla_get_labels);
-int nla_get_via(const struct nlattr *nla, u8 *via_alen, u8 *via_table,
- u8 via_addr[], struct netlink_ext_ack *extack)
-{
- struct rtvia *via = nla_data(nla);
- int err = -EINVAL;
- int alen;
-
- if (nla_len(nla) < offsetof(struct rtvia, rtvia_addr)) {
- NL_SET_ERR_MSG_ATTR(extack, nla,
- "Invalid attribute length for RTA_VIA");
- goto errout;
- }
- alen = nla_len(nla) -
- offsetof(struct rtvia, rtvia_addr);
- if (alen > MAX_VIA_ALEN) {
- NL_SET_ERR_MSG_ATTR(extack, nla,
- "Invalid address length for RTA_VIA");
- goto errout;
- }
-
- /* Validate the address family */
- switch (via->rtvia_family) {
- case AF_PACKET:
- *via_table = NEIGH_LINK_TABLE;
- break;
- case AF_INET:
- *via_table = NEIGH_ARP_TABLE;
- if (alen != 4)
- goto errout;
- break;
- case AF_INET6:
- *via_table = NEIGH_ND_TABLE;
- if (alen != 16)
- goto errout;
- break;
- default:
- /* Unsupported address family */
- goto errout;
- }
-
- memcpy(via_addr, via->rtvia_addr, alen);
- *via_alen = alen;
- err = 0;
-
-errout:
- return err;
-}
-
static int rtm_to_route_config(struct sk_buff *skb,
struct nlmsghdr *nlh,
struct mpls_route_config *cfg,
diff --git a/net/mpls/internal.h b/net/mpls/internal.h
index a015a6a1143b..cf65aec2e551 100644
--- a/net/mpls/internal.h
+++ b/net/mpls/internal.h
@@ -204,8 +204,6 @@ int nla_put_labels(struct sk_buff *skb, int attrtype, u8 labels,
const u32 label[]);
int nla_get_labels(const struct nlattr *nla, u8 max_labels, u8 *labels,
u32 label[], struct netlink_ext_ack *extack);
-int nla_get_via(const struct nlattr *nla, u8 *via_alen, u8 *via_table,
- u8 via[], struct netlink_ext_ack *extack);
bool mpls_output_possible(const struct net_device *dev);
unsigned int mpls_dev_mtu(const struct net_device *dev);
bool mpls_pkt_too_big(const struct sk_buff *skb, unsigned int mtu);
--
2.11.0 (Apple Git-81)
^ 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