forked from Minki/linux
Merge branch 'rocker-next'
Jiri Pirko says: ==================== introduce rocker switch driver with hardware accelerated datapath api - phase 1: bridge fdb offload This patchset is just the first phase of switch and switch-ish device support api in kernel. Note that the api will extend. So what this patchset includes: - introduce switchdev api skeleton for implementing switch drivers - introduce rocker switch driver which implements switchdev api fdb and bridge set/get link ndos As to the discussion if there is need to have specific class of device representing the switch itself, so far we found no need to introduce that. But we are generally ok with the idea and when the time comes and it will be needed, it can be easily introduced without any disturbance. This patchset introduces switch id export through rtnetlink and sysfs, which is similar to what we have for port id in SR-IOV. I will send iproute2 patchset for showing the switch id for port netdevs once this is applied. This applies also for the PF_BRIDGE and fdb iproute2 patches. iproute2 patches are now available here: https://github.com/jpirko/iproute2-rocker For detailed description and version history, please see individual patches. In v4 I reordered the patches leaving rocker patches on the end of the patchset. In v5 I only fixed whitespace issues of patch #13 We have a TODO for related items we want to work on in near future: https://etherpad.wikimedia.org/p/netdev-swdev-todo ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
cbc24658ba
@ -216,3 +216,11 @@ Contact: netdev@vger.kernel.org
|
||||
Description:
|
||||
Indicates the interface protocol type as a decimal value. See
|
||||
include/uapi/linux/if_arp.h for all possible values.
|
||||
|
||||
What: /sys/class/net/<iface>/phys_switch_id
|
||||
Date: November 2014
|
||||
KernelVersion: 3.19
|
||||
Contact: netdev@vger.kernel.org
|
||||
Description:
|
||||
Indicates the unique physical switch identifier of a switch this
|
||||
port belongs to, as a string.
|
||||
|
59
Documentation/networking/switchdev.txt
Normal file
59
Documentation/networking/switchdev.txt
Normal file
@ -0,0 +1,59 @@
|
||||
Switch (and switch-ish) device drivers HOWTO
|
||||
===========================
|
||||
|
||||
Please note that the word "switch" is here used in very generic meaning.
|
||||
This include devices supporting L2/L3 but also various flow offloading chips,
|
||||
including switches embedded into SR-IOV NICs.
|
||||
|
||||
Lets describe a topology a bit. Imagine the following example:
|
||||
|
||||
+----------------------------+ +---------------+
|
||||
| SOME switch chip | | CPU |
|
||||
+----------------------------+ +---------------+
|
||||
port1 port2 port3 port4 MNGMNT | PCI-E |
|
||||
| | | | | +---------------+
|
||||
PHY PHY | | | | NIC0 NIC1
|
||||
| | | | | |
|
||||
| | +- PCI-E -+ | |
|
||||
| +------- MII -------+ |
|
||||
+------------- MII ------------+
|
||||
|
||||
In this example, there are two independent lines between the switch silicon
|
||||
and CPU. NIC0 and NIC1 drivers are not aware of a switch presence. They are
|
||||
separate from the switch driver. SOME switch chip is by managed by a driver
|
||||
via PCI-E device MNGMNT. Note that MNGMNT device, NIC0 and NIC1 may be
|
||||
connected to some other type of bus.
|
||||
|
||||
Now, for the previous example show the representation in kernel:
|
||||
|
||||
+----------------------------+ +---------------+
|
||||
| SOME switch chip | | CPU |
|
||||
+----------------------------+ +---------------+
|
||||
sw0p0 sw0p1 sw0p2 sw0p3 MNGMNT | PCI-E |
|
||||
| | | | | +---------------+
|
||||
PHY PHY | | | | eth0 eth1
|
||||
| | | | | |
|
||||
| | +- PCI-E -+ | |
|
||||
| +------- MII -------+ |
|
||||
+------------- MII ------------+
|
||||
|
||||
Lets call the example switch driver for SOME switch chip "SOMEswitch". This
|
||||
driver takes care of PCI-E device MNGMNT. There is a netdevice instance sw0pX
|
||||
created for each port of a switch. These netdevices are instances
|
||||
of "SOMEswitch" driver. sw0pX netdevices serve as a "representation"
|
||||
of the switch chip. eth0 and eth1 are instances of some other existing driver.
|
||||
|
||||
The only difference of the switch-port netdevice from the ordinary netdevice
|
||||
is that is implements couple more NDOs:
|
||||
|
||||
ndo_switch_parent_id_get - This returns the same ID for two port netdevices
|
||||
of the same physical switch chip. This is
|
||||
mandatory to be implemented by all switch drivers
|
||||
and serves the caller for recognition of a port
|
||||
netdevice.
|
||||
ndo_switch_parent_* - Functions that serve for a manipulation of the switch
|
||||
chip itself (it can be though of as a "parent" of the
|
||||
port, therefore the name). They are not port-specific.
|
||||
Caller might use arbitrary port netdevice of the same
|
||||
switch and it will make no difference.
|
||||
ndo_switch_port_* - Functions that serve for a port-specific manipulation.
|
14
MAINTAINERS
14
MAINTAINERS
@ -7865,6 +7865,13 @@ F: drivers/hid/hid-roccat*
|
||||
F: include/linux/hid-roccat*
|
||||
F: Documentation/ABI/*/sysfs-driver-hid-roccat*
|
||||
|
||||
ROCKER DRIVER
|
||||
M: Jiri Pirko <jiri@resnulli.us>
|
||||
M: Scott Feldman <sfeldma@gmail.com>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/net/ethernet/rocker/
|
||||
|
||||
ROCKETPORT DRIVER
|
||||
P: Comtrol Corp.
|
||||
W: http://www.comtrol.com
|
||||
@ -9059,6 +9066,13 @@ F: lib/swiotlb.c
|
||||
F: arch/*/kernel/pci-swiotlb.c
|
||||
F: include/linux/swiotlb.h
|
||||
|
||||
SWITCHDEV
|
||||
M: Jiri Pirko <jiri@resnulli.us>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Supported
|
||||
F: net/switchdev/
|
||||
F: include/net/switchdev.h
|
||||
|
||||
SYNOPSYS ARC ARCHITECTURE
|
||||
M: Vineet Gupta <vgupta@synopsys.com>
|
||||
S: Supported
|
||||
|
@ -155,6 +155,7 @@ source "drivers/net/ethernet/qualcomm/Kconfig"
|
||||
source "drivers/net/ethernet/realtek/Kconfig"
|
||||
source "drivers/net/ethernet/renesas/Kconfig"
|
||||
source "drivers/net/ethernet/rdc/Kconfig"
|
||||
source "drivers/net/ethernet/rocker/Kconfig"
|
||||
|
||||
config S6GMAC
|
||||
tristate "S6105 GMAC ethernet support"
|
||||
|
@ -65,6 +65,7 @@ obj-$(CONFIG_NET_VENDOR_QUALCOMM) += qualcomm/
|
||||
obj-$(CONFIG_NET_VENDOR_REALTEK) += realtek/
|
||||
obj-$(CONFIG_SH_ETH) += renesas/
|
||||
obj-$(CONFIG_NET_VENDOR_RDC) += rdc/
|
||||
obj-$(CONFIG_NET_VENDOR_ROCKER) += rocker/
|
||||
obj-$(CONFIG_S6GMAC) += s6gmac.o
|
||||
obj-$(CONFIG_NET_VENDOR_SAMSUNG) += samsung/
|
||||
obj-$(CONFIG_NET_VENDOR_SEEQ) += seeq/
|
||||
|
@ -12537,7 +12537,7 @@ static int bnx2x_validate_addr(struct net_device *dev)
|
||||
}
|
||||
|
||||
static int bnx2x_get_phys_port_id(struct net_device *netdev,
|
||||
struct netdev_phys_port_id *ppid)
|
||||
struct netdev_phys_item_id *ppid)
|
||||
{
|
||||
struct bnx2x *bp = netdev_priv(netdev);
|
||||
|
||||
|
@ -4367,7 +4367,8 @@ static int be_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
|
||||
|
||||
return ndo_dflt_bridge_getlink(skb, pid, seq, dev,
|
||||
hsw_mode == PORT_FWD_TYPE_VEPA ?
|
||||
BRIDGE_MODE_VEPA : BRIDGE_MODE_VEB);
|
||||
BRIDGE_MODE_VEPA : BRIDGE_MODE_VEB,
|
||||
0, 0);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BE2NET_VXLAN
|
||||
|
@ -7511,7 +7511,7 @@ static void i40e_del_vxlan_port(struct net_device *netdev,
|
||||
|
||||
#endif
|
||||
static int i40e_get_phys_port_id(struct net_device *netdev,
|
||||
struct netdev_phys_port_id *ppid)
|
||||
struct netdev_phys_item_id *ppid)
|
||||
{
|
||||
struct i40e_netdev_priv *np = netdev_priv(netdev);
|
||||
struct i40e_pf *pf = np->vsi->back;
|
||||
@ -7536,7 +7536,7 @@ static int i40e_get_phys_port_id(struct net_device *netdev,
|
||||
*/
|
||||
static int i40e_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
|
||||
struct net_device *dev,
|
||||
const unsigned char *addr,
|
||||
const unsigned char *addr, u16 vid,
|
||||
u16 flags)
|
||||
{
|
||||
struct i40e_netdev_priv *np = netdev_priv(dev);
|
||||
|
@ -7708,7 +7708,7 @@ static int ixgbe_set_features(struct net_device *netdev,
|
||||
|
||||
static int ixgbe_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
|
||||
struct net_device *dev,
|
||||
const unsigned char *addr,
|
||||
const unsigned char *addr, u16 vid,
|
||||
u16 flags)
|
||||
{
|
||||
/* guarantee we can provide a unique filter for the unicast address */
|
||||
@ -7717,7 +7717,7 @@ static int ixgbe_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return ndo_dflt_fdb_add(ndm, tb, dev, addr, flags);
|
||||
return ndo_dflt_fdb_add(ndm, tb, dev, addr, vid, flags);
|
||||
}
|
||||
|
||||
static int ixgbe_ndo_bridge_setlink(struct net_device *dev,
|
||||
@ -7778,7 +7778,7 @@ static int ixgbe_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
|
||||
else
|
||||
mode = BRIDGE_MODE_VEPA;
|
||||
|
||||
return ndo_dflt_bridge_getlink(skb, pid, seq, dev, mode);
|
||||
return ndo_dflt_bridge_getlink(skb, pid, seq, dev, mode, 0, 0);
|
||||
}
|
||||
|
||||
static void *ixgbe_fwd_add(struct net_device *pdev, struct net_device *vdev)
|
||||
|
@ -2259,7 +2259,7 @@ static int mlx4_en_set_vf_link_state(struct net_device *dev, int vf, int link_st
|
||||
|
||||
#define PORT_ID_BYTE_LEN 8
|
||||
static int mlx4_en_get_phys_port_id(struct net_device *dev,
|
||||
struct netdev_phys_port_id *ppid)
|
||||
struct netdev_phys_item_id *ppid)
|
||||
{
|
||||
struct mlx4_en_priv *priv = netdev_priv(dev);
|
||||
struct mlx4_dev *mdev = priv->mdev->dev;
|
||||
|
@ -376,13 +376,14 @@ static int qlcnic_set_mac(struct net_device *netdev, void *p)
|
||||
}
|
||||
|
||||
static int qlcnic_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
|
||||
struct net_device *netdev, const unsigned char *addr)
|
||||
struct net_device *netdev,
|
||||
const unsigned char *addr, u16 vid)
|
||||
{
|
||||
struct qlcnic_adapter *adapter = netdev_priv(netdev);
|
||||
int err = -EOPNOTSUPP;
|
||||
|
||||
if (!adapter->fdb_mac_learn)
|
||||
return ndo_dflt_fdb_del(ndm, tb, netdev, addr);
|
||||
return ndo_dflt_fdb_del(ndm, tb, netdev, addr, vid);
|
||||
|
||||
if ((adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
|
||||
qlcnic_sriov_check(adapter)) {
|
||||
@ -401,13 +402,13 @@ static int qlcnic_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
|
||||
|
||||
static int qlcnic_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
|
||||
struct net_device *netdev,
|
||||
const unsigned char *addr, u16 flags)
|
||||
const unsigned char *addr, u16 vid, u16 flags)
|
||||
{
|
||||
struct qlcnic_adapter *adapter = netdev_priv(netdev);
|
||||
int err = 0;
|
||||
|
||||
if (!adapter->fdb_mac_learn)
|
||||
return ndo_dflt_fdb_add(ndm, tb, netdev, addr, flags);
|
||||
return ndo_dflt_fdb_add(ndm, tb, netdev, addr, vid, flags);
|
||||
|
||||
if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) &&
|
||||
!qlcnic_sriov_check(adapter)) {
|
||||
@ -460,7 +461,7 @@ static void qlcnic_82xx_cancel_idc_work(struct qlcnic_adapter *adapter)
|
||||
}
|
||||
|
||||
static int qlcnic_get_phys_port_id(struct net_device *netdev,
|
||||
struct netdev_phys_port_id *ppid)
|
||||
struct netdev_phys_item_id *ppid)
|
||||
{
|
||||
struct qlcnic_adapter *adapter = netdev_priv(netdev);
|
||||
struct qlcnic_hardware_context *ahw = adapter->ahw;
|
||||
|
27
drivers/net/ethernet/rocker/Kconfig
Normal file
27
drivers/net/ethernet/rocker/Kconfig
Normal file
@ -0,0 +1,27 @@
|
||||
#
|
||||
# Rocker device configuration
|
||||
#
|
||||
|
||||
config NET_VENDOR_ROCKER
|
||||
bool "Rocker devices"
|
||||
default y
|
||||
---help---
|
||||
If you have a network device belonging to this class, say Y.
|
||||
|
||||
Note that the answer to this question doesn't directly affect the
|
||||
kernel: saying N will just cause the configurator to skip all
|
||||
the questions about Rocker devices. If you say Y, you will be asked for
|
||||
your specific card in the following questions.
|
||||
|
||||
if NET_VENDOR_ROCKER
|
||||
|
||||
config ROCKER
|
||||
tristate "Rocker switch driver (EXPERIMENTAL)"
|
||||
depends on PCI && NET_SWITCHDEV
|
||||
---help---
|
||||
This driver supports Rocker switch device.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called rocker.
|
||||
|
||||
endif # NET_VENDOR_ROCKER
|
5
drivers/net/ethernet/rocker/Makefile
Normal file
5
drivers/net/ethernet/rocker/Makefile
Normal file
@ -0,0 +1,5 @@
|
||||
#
|
||||
# Makefile for the Rocker network device drivers.
|
||||
#
|
||||
|
||||
obj-$(CONFIG_ROCKER) += rocker.o
|
4374
drivers/net/ethernet/rocker/rocker.c
Normal file
4374
drivers/net/ethernet/rocker/rocker.c
Normal file
File diff suppressed because it is too large
Load Diff
428
drivers/net/ethernet/rocker/rocker.h
Normal file
428
drivers/net/ethernet/rocker/rocker.h
Normal file
@ -0,0 +1,428 @@
|
||||
/*
|
||||
* drivers/net/ethernet/rocker/rocker.h - Rocker switch device driver
|
||||
* Copyright (c) 2014 Jiri Pirko <jiri@resnulli.us>
|
||||
* Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef _ROCKER_H
|
||||
#define _ROCKER_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#define PCI_VENDOR_ID_REDHAT 0x1b36
|
||||
#define PCI_DEVICE_ID_REDHAT_ROCKER 0x0006
|
||||
|
||||
#define ROCKER_PCI_BAR0_SIZE 0x2000
|
||||
|
||||
/* MSI-X vectors */
|
||||
enum {
|
||||
ROCKER_MSIX_VEC_CMD,
|
||||
ROCKER_MSIX_VEC_EVENT,
|
||||
ROCKER_MSIX_VEC_TEST,
|
||||
ROCKER_MSIX_VEC_RESERVED0,
|
||||
__ROCKER_MSIX_VEC_TX,
|
||||
__ROCKER_MSIX_VEC_RX,
|
||||
#define ROCKER_MSIX_VEC_TX(port) \
|
||||
(__ROCKER_MSIX_VEC_TX + ((port) * 2))
|
||||
#define ROCKER_MSIX_VEC_RX(port) \
|
||||
(__ROCKER_MSIX_VEC_RX + ((port) * 2))
|
||||
#define ROCKER_MSIX_VEC_COUNT(portcnt) \
|
||||
(ROCKER_MSIX_VEC_RX((portcnt - 1)) + 1)
|
||||
};
|
||||
|
||||
/* Rocker bogus registers */
|
||||
#define ROCKER_BOGUS_REG0 0x0000
|
||||
#define ROCKER_BOGUS_REG1 0x0004
|
||||
#define ROCKER_BOGUS_REG2 0x0008
|
||||
#define ROCKER_BOGUS_REG3 0x000c
|
||||
|
||||
/* Rocker test registers */
|
||||
#define ROCKER_TEST_REG 0x0010
|
||||
#define ROCKER_TEST_REG64 0x0018 /* 8-byte */
|
||||
#define ROCKER_TEST_IRQ 0x0020
|
||||
#define ROCKER_TEST_DMA_ADDR 0x0028 /* 8-byte */
|
||||
#define ROCKER_TEST_DMA_SIZE 0x0030
|
||||
#define ROCKER_TEST_DMA_CTRL 0x0034
|
||||
|
||||
/* Rocker test register ctrl */
|
||||
#define ROCKER_TEST_DMA_CTRL_CLEAR (1 << 0)
|
||||
#define ROCKER_TEST_DMA_CTRL_FILL (1 << 1)
|
||||
#define ROCKER_TEST_DMA_CTRL_INVERT (1 << 2)
|
||||
|
||||
/* Rocker DMA ring register offsets */
|
||||
#define ROCKER_DMA_DESC_ADDR(x) (0x1000 + (x) * 32) /* 8-byte */
|
||||
#define ROCKER_DMA_DESC_SIZE(x) (0x1008 + (x) * 32)
|
||||
#define ROCKER_DMA_DESC_HEAD(x) (0x100c + (x) * 32)
|
||||
#define ROCKER_DMA_DESC_TAIL(x) (0x1010 + (x) * 32)
|
||||
#define ROCKER_DMA_DESC_CTRL(x) (0x1014 + (x) * 32)
|
||||
#define ROCKER_DMA_DESC_CREDITS(x) (0x1018 + (x) * 32)
|
||||
#define ROCKER_DMA_DESC_RES1(x) (0x101c + (x) * 32)
|
||||
|
||||
/* Rocker dma ctrl register bits */
|
||||
#define ROCKER_DMA_DESC_CTRL_RESET (1 << 0)
|
||||
|
||||
/* Rocker DMA ring types */
|
||||
enum rocker_dma_type {
|
||||
ROCKER_DMA_CMD,
|
||||
ROCKER_DMA_EVENT,
|
||||
__ROCKER_DMA_TX,
|
||||
__ROCKER_DMA_RX,
|
||||
#define ROCKER_DMA_TX(port) (__ROCKER_DMA_TX + (port) * 2)
|
||||
#define ROCKER_DMA_RX(port) (__ROCKER_DMA_RX + (port) * 2)
|
||||
};
|
||||
|
||||
/* Rocker DMA ring size limits and default sizes */
|
||||
#define ROCKER_DMA_SIZE_MIN 2ul
|
||||
#define ROCKER_DMA_SIZE_MAX 65536ul
|
||||
#define ROCKER_DMA_CMD_DEFAULT_SIZE 32ul
|
||||
#define ROCKER_DMA_EVENT_DEFAULT_SIZE 32ul
|
||||
#define ROCKER_DMA_TX_DEFAULT_SIZE 64ul
|
||||
#define ROCKER_DMA_TX_DESC_SIZE 256
|
||||
#define ROCKER_DMA_RX_DEFAULT_SIZE 64ul
|
||||
#define ROCKER_DMA_RX_DESC_SIZE 256
|
||||
|
||||
/* Rocker DMA descriptor struct */
|
||||
struct rocker_desc {
|
||||
u64 buf_addr;
|
||||
u64 cookie;
|
||||
u16 buf_size;
|
||||
u16 tlv_size;
|
||||
u16 resv[5];
|
||||
u16 comp_err;
|
||||
};
|
||||
|
||||
#define ROCKER_DMA_DESC_COMP_ERR_GEN (1 << 15)
|
||||
|
||||
/* Rocker DMA TLV struct */
|
||||
struct rocker_tlv {
|
||||
u32 type;
|
||||
u16 len;
|
||||
};
|
||||
|
||||
/* TLVs */
|
||||
enum {
|
||||
ROCKER_TLV_CMD_UNSPEC,
|
||||
ROCKER_TLV_CMD_TYPE, /* u16 */
|
||||
ROCKER_TLV_CMD_INFO, /* nest */
|
||||
|
||||
__ROCKER_TLV_CMD_MAX,
|
||||
ROCKER_TLV_CMD_MAX = __ROCKER_TLV_CMD_MAX - 1,
|
||||
};
|
||||
|
||||
enum {
|
||||
ROCKER_TLV_CMD_TYPE_UNSPEC,
|
||||
ROCKER_TLV_CMD_TYPE_GET_PORT_SETTINGS,
|
||||
ROCKER_TLV_CMD_TYPE_SET_PORT_SETTINGS,
|
||||
ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_ADD,
|
||||
ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_MOD,
|
||||
ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_DEL,
|
||||
ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_GET_STATS,
|
||||
ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_ADD,
|
||||
ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_MOD,
|
||||
ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_DEL,
|
||||
ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_GET_STATS,
|
||||
|
||||
__ROCKER_TLV_CMD_TYPE_MAX,
|
||||
ROCKER_TLV_CMD_TYPE_MAX = __ROCKER_TLV_CMD_TYPE_MAX - 1,
|
||||
};
|
||||
|
||||
enum {
|
||||
ROCKER_TLV_CMD_PORT_SETTINGS_UNSPEC,
|
||||
ROCKER_TLV_CMD_PORT_SETTINGS_LPORT, /* u32 */
|
||||
ROCKER_TLV_CMD_PORT_SETTINGS_SPEED, /* u32 */
|
||||
ROCKER_TLV_CMD_PORT_SETTINGS_DUPLEX, /* u8 */
|
||||
ROCKER_TLV_CMD_PORT_SETTINGS_AUTONEG, /* u8 */
|
||||
ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR, /* binary */
|
||||
ROCKER_TLV_CMD_PORT_SETTINGS_MODE, /* u8 */
|
||||
ROCKER_TLV_CMD_PORT_SETTINGS_LEARNING, /* u8 */
|
||||
|
||||
__ROCKER_TLV_CMD_PORT_SETTINGS_MAX,
|
||||
ROCKER_TLV_CMD_PORT_SETTINGS_MAX =
|
||||
__ROCKER_TLV_CMD_PORT_SETTINGS_MAX - 1,
|
||||
};
|
||||
|
||||
enum rocker_port_mode {
|
||||
ROCKER_PORT_MODE_OF_DPA,
|
||||
};
|
||||
|
||||
enum {
|
||||
ROCKER_TLV_EVENT_UNSPEC,
|
||||
ROCKER_TLV_EVENT_TYPE, /* u16 */
|
||||
ROCKER_TLV_EVENT_INFO, /* nest */
|
||||
|
||||
__ROCKER_TLV_EVENT_MAX,
|
||||
ROCKER_TLV_EVENT_MAX = __ROCKER_TLV_EVENT_MAX - 1,
|
||||
};
|
||||
|
||||
enum {
|
||||
ROCKER_TLV_EVENT_TYPE_UNSPEC,
|
||||
ROCKER_TLV_EVENT_TYPE_LINK_CHANGED,
|
||||
ROCKER_TLV_EVENT_TYPE_MAC_VLAN_SEEN,
|
||||
|
||||
__ROCKER_TLV_EVENT_TYPE_MAX,
|
||||
ROCKER_TLV_EVENT_TYPE_MAX = __ROCKER_TLV_EVENT_TYPE_MAX - 1,
|
||||
};
|
||||
|
||||
enum {
|
||||
ROCKER_TLV_EVENT_LINK_CHANGED_UNSPEC,
|
||||
ROCKER_TLV_EVENT_LINK_CHANGED_LPORT, /* u32 */
|
||||
ROCKER_TLV_EVENT_LINK_CHANGED_LINKUP, /* u8 */
|
||||
|
||||
__ROCKER_TLV_EVENT_LINK_CHANGED_MAX,
|
||||
ROCKER_TLV_EVENT_LINK_CHANGED_MAX =
|
||||
__ROCKER_TLV_EVENT_LINK_CHANGED_MAX - 1,
|
||||
};
|
||||
|
||||
enum {
|
||||
ROCKER_TLV_EVENT_MAC_VLAN_UNSPEC,
|
||||
ROCKER_TLV_EVENT_MAC_VLAN_LPORT, /* u32 */
|
||||
ROCKER_TLV_EVENT_MAC_VLAN_MAC, /* binary */
|
||||
ROCKER_TLV_EVENT_MAC_VLAN_VLAN_ID, /* __be16 */
|
||||
|
||||
__ROCKER_TLV_EVENT_MAC_VLAN_MAX,
|
||||
ROCKER_TLV_EVENT_MAC_VLAN_MAX = __ROCKER_TLV_EVENT_MAC_VLAN_MAX - 1,
|
||||
};
|
||||
|
||||
enum {
|
||||
ROCKER_TLV_RX_UNSPEC,
|
||||
ROCKER_TLV_RX_FLAGS, /* u16, see ROCKER_RX_FLAGS_ */
|
||||
ROCKER_TLV_RX_CSUM, /* u16 */
|
||||
ROCKER_TLV_RX_FRAG_ADDR, /* u64 */
|
||||
ROCKER_TLV_RX_FRAG_MAX_LEN, /* u16 */
|
||||
ROCKER_TLV_RX_FRAG_LEN, /* u16 */
|
||||
|
||||
__ROCKER_TLV_RX_MAX,
|
||||
ROCKER_TLV_RX_MAX = __ROCKER_TLV_RX_MAX - 1,
|
||||
};
|
||||
|
||||
#define ROCKER_RX_FLAGS_IPV4 (1 << 0)
|
||||
#define ROCKER_RX_FLAGS_IPV6 (1 << 1)
|
||||
#define ROCKER_RX_FLAGS_CSUM_CALC (1 << 2)
|
||||
#define ROCKER_RX_FLAGS_IPV4_CSUM_GOOD (1 << 3)
|
||||
#define ROCKER_RX_FLAGS_IP_FRAG (1 << 4)
|
||||
#define ROCKER_RX_FLAGS_TCP (1 << 5)
|
||||
#define ROCKER_RX_FLAGS_UDP (1 << 6)
|
||||
#define ROCKER_RX_FLAGS_TCP_UDP_CSUM_GOOD (1 << 7)
|
||||
|
||||
enum {
|
||||
ROCKER_TLV_TX_UNSPEC,
|
||||
ROCKER_TLV_TX_OFFLOAD, /* u8, see ROCKER_TX_OFFLOAD_ */
|
||||
ROCKER_TLV_TX_L3_CSUM_OFF, /* u16 */
|
||||
ROCKER_TLV_TX_TSO_MSS, /* u16 */
|
||||
ROCKER_TLV_TX_TSO_HDR_LEN, /* u16 */
|
||||
ROCKER_TLV_TX_FRAGS, /* array */
|
||||
|
||||
__ROCKER_TLV_TX_MAX,
|
||||
ROCKER_TLV_TX_MAX = __ROCKER_TLV_TX_MAX - 1,
|
||||
};
|
||||
|
||||
#define ROCKER_TX_OFFLOAD_NONE 0
|
||||
#define ROCKER_TX_OFFLOAD_IP_CSUM 1
|
||||
#define ROCKER_TX_OFFLOAD_TCP_UDP_CSUM 2
|
||||
#define ROCKER_TX_OFFLOAD_L3_CSUM 3
|
||||
#define ROCKER_TX_OFFLOAD_TSO 4
|
||||
|
||||
#define ROCKER_TX_FRAGS_MAX 16
|
||||
|
||||
enum {
|
||||
ROCKER_TLV_TX_FRAG_UNSPEC,
|
||||
ROCKER_TLV_TX_FRAG, /* nest */
|
||||
|
||||
__ROCKER_TLV_TX_FRAG_MAX,
|
||||
ROCKER_TLV_TX_FRAG_MAX = __ROCKER_TLV_TX_FRAG_MAX - 1,
|
||||
};
|
||||
|
||||
enum {
|
||||
ROCKER_TLV_TX_FRAG_ATTR_UNSPEC,
|
||||
ROCKER_TLV_TX_FRAG_ATTR_ADDR, /* u64 */
|
||||
ROCKER_TLV_TX_FRAG_ATTR_LEN, /* u16 */
|
||||
|
||||
__ROCKER_TLV_TX_FRAG_ATTR_MAX,
|
||||
ROCKER_TLV_TX_FRAG_ATTR_MAX = __ROCKER_TLV_TX_FRAG_ATTR_MAX - 1,
|
||||
};
|
||||
|
||||
/* cmd info nested for OF-DPA msgs */
|
||||
enum {
|
||||
ROCKER_TLV_OF_DPA_UNSPEC,
|
||||
ROCKER_TLV_OF_DPA_TABLE_ID, /* u16 */
|
||||
ROCKER_TLV_OF_DPA_PRIORITY, /* u32 */
|
||||
ROCKER_TLV_OF_DPA_HARDTIME, /* u32 */
|
||||
ROCKER_TLV_OF_DPA_IDLETIME, /* u32 */
|
||||
ROCKER_TLV_OF_DPA_COOKIE, /* u64 */
|
||||
ROCKER_TLV_OF_DPA_IN_LPORT, /* u32 */
|
||||
ROCKER_TLV_OF_DPA_IN_LPORT_MASK, /* u32 */
|
||||
ROCKER_TLV_OF_DPA_OUT_LPORT, /* u32 */
|
||||
ROCKER_TLV_OF_DPA_GOTO_TABLE_ID, /* u16 */
|
||||
ROCKER_TLV_OF_DPA_GROUP_ID, /* u32 */
|
||||
ROCKER_TLV_OF_DPA_GROUP_ID_LOWER, /* u32 */
|
||||
ROCKER_TLV_OF_DPA_GROUP_COUNT, /* u16 */
|
||||
ROCKER_TLV_OF_DPA_GROUP_IDS, /* u32 array */
|
||||
ROCKER_TLV_OF_DPA_VLAN_ID, /* __be16 */
|
||||
ROCKER_TLV_OF_DPA_VLAN_ID_MASK, /* __be16 */
|
||||
ROCKER_TLV_OF_DPA_VLAN_PCP, /* __be16 */
|
||||
ROCKER_TLV_OF_DPA_VLAN_PCP_MASK, /* __be16 */
|
||||
ROCKER_TLV_OF_DPA_VLAN_PCP_ACTION, /* u8 */
|
||||
ROCKER_TLV_OF_DPA_NEW_VLAN_ID, /* __be16 */
|
||||
ROCKER_TLV_OF_DPA_NEW_VLAN_PCP, /* u8 */
|
||||
ROCKER_TLV_OF_DPA_TUNNEL_ID, /* u32 */
|
||||
ROCKER_TLV_OF_DPA_TUN_LOG_LPORT, /* u32 */
|
||||
ROCKER_TLV_OF_DPA_ETHERTYPE, /* __be16 */
|
||||
ROCKER_TLV_OF_DPA_DST_MAC, /* binary */
|
||||
ROCKER_TLV_OF_DPA_DST_MAC_MASK, /* binary */
|
||||
ROCKER_TLV_OF_DPA_SRC_MAC, /* binary */
|
||||
ROCKER_TLV_OF_DPA_SRC_MAC_MASK, /* binary */
|
||||
ROCKER_TLV_OF_DPA_IP_PROTO, /* u8 */
|
||||
ROCKER_TLV_OF_DPA_IP_PROTO_MASK, /* u8 */
|
||||
ROCKER_TLV_OF_DPA_IP_DSCP, /* u8 */
|
||||
ROCKER_TLV_OF_DPA_IP_DSCP_MASK, /* u8 */
|
||||
ROCKER_TLV_OF_DPA_IP_DSCP_ACTION, /* u8 */
|
||||
ROCKER_TLV_OF_DPA_NEW_IP_DSCP, /* u8 */
|
||||
ROCKER_TLV_OF_DPA_IP_ECN, /* u8 */
|
||||
ROCKER_TLV_OF_DPA_IP_ECN_MASK, /* u8 */
|
||||
ROCKER_TLV_OF_DPA_DST_IP, /* __be32 */
|
||||
ROCKER_TLV_OF_DPA_DST_IP_MASK, /* __be32 */
|
||||
ROCKER_TLV_OF_DPA_SRC_IP, /* __be32 */
|
||||
ROCKER_TLV_OF_DPA_SRC_IP_MASK, /* __be32 */
|
||||
ROCKER_TLV_OF_DPA_DST_IPV6, /* binary */
|
||||
ROCKER_TLV_OF_DPA_DST_IPV6_MASK, /* binary */
|
||||
ROCKER_TLV_OF_DPA_SRC_IPV6, /* binary */
|
||||
ROCKER_TLV_OF_DPA_SRC_IPV6_MASK, /* binary */
|
||||
ROCKER_TLV_OF_DPA_SRC_ARP_IP, /* __be32 */
|
||||
ROCKER_TLV_OF_DPA_SRC_ARP_IP_MASK, /* __be32 */
|
||||
ROCKER_TLV_OF_DPA_L4_DST_PORT, /* __be16 */
|
||||
ROCKER_TLV_OF_DPA_L4_DST_PORT_MASK, /* __be16 */
|
||||
ROCKER_TLV_OF_DPA_L4_SRC_PORT, /* __be16 */
|
||||
ROCKER_TLV_OF_DPA_L4_SRC_PORT_MASK, /* __be16 */
|
||||
ROCKER_TLV_OF_DPA_ICMP_TYPE, /* u8 */
|
||||
ROCKER_TLV_OF_DPA_ICMP_TYPE_MASK, /* u8 */
|
||||
ROCKER_TLV_OF_DPA_ICMP_CODE, /* u8 */
|
||||
ROCKER_TLV_OF_DPA_ICMP_CODE_MASK, /* u8 */
|
||||
ROCKER_TLV_OF_DPA_IPV6_LABEL, /* __be32 */
|
||||
ROCKER_TLV_OF_DPA_IPV6_LABEL_MASK, /* __be32 */
|
||||
ROCKER_TLV_OF_DPA_QUEUE_ID_ACTION, /* u8 */
|
||||
ROCKER_TLV_OF_DPA_NEW_QUEUE_ID, /* u8 */
|
||||
ROCKER_TLV_OF_DPA_CLEAR_ACTIONS, /* u32 */
|
||||
ROCKER_TLV_OF_DPA_POP_VLAN, /* u8 */
|
||||
ROCKER_TLV_OF_DPA_TTL_CHECK, /* u8 */
|
||||
ROCKER_TLV_OF_DPA_COPY_CPU_ACTION, /* u8 */
|
||||
|
||||
__ROCKER_TLV_OF_DPA_MAX,
|
||||
ROCKER_TLV_OF_DPA_MAX = __ROCKER_TLV_OF_DPA_MAX - 1,
|
||||
};
|
||||
|
||||
/* OF-DPA table IDs */
|
||||
|
||||
enum rocker_of_dpa_table_id {
|
||||
ROCKER_OF_DPA_TABLE_ID_INGRESS_PORT = 0,
|
||||
ROCKER_OF_DPA_TABLE_ID_VLAN = 10,
|
||||
ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC = 20,
|
||||
ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING = 30,
|
||||
ROCKER_OF_DPA_TABLE_ID_MULTICAST_ROUTING = 40,
|
||||
ROCKER_OF_DPA_TABLE_ID_BRIDGING = 50,
|
||||
ROCKER_OF_DPA_TABLE_ID_ACL_POLICY = 60,
|
||||
};
|
||||
|
||||
/* OF-DPA flow stats */
|
||||
enum {
|
||||
ROCKER_TLV_OF_DPA_FLOW_STAT_UNSPEC,
|
||||
ROCKER_TLV_OF_DPA_FLOW_STAT_DURATION, /* u32 */
|
||||
ROCKER_TLV_OF_DPA_FLOW_STAT_RX_PKTS, /* u64 */
|
||||
ROCKER_TLV_OF_DPA_FLOW_STAT_TX_PKTS, /* u64 */
|
||||
|
||||
__ROCKER_TLV_OF_DPA_FLOW_STAT_MAX,
|
||||
ROCKER_TLV_OF_DPA_FLOW_STAT_MAX = __ROCKER_TLV_OF_DPA_FLOW_STAT_MAX - 1,
|
||||
};
|
||||
|
||||
/* OF-DPA group types */
|
||||
enum rocker_of_dpa_group_type {
|
||||
ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE = 0,
|
||||
ROCKER_OF_DPA_GROUP_TYPE_L2_REWRITE,
|
||||
ROCKER_OF_DPA_GROUP_TYPE_L3_UCAST,
|
||||
ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST,
|
||||
ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD,
|
||||
ROCKER_OF_DPA_GROUP_TYPE_L3_INTERFACE,
|
||||
ROCKER_OF_DPA_GROUP_TYPE_L3_MCAST,
|
||||
ROCKER_OF_DPA_GROUP_TYPE_L3_ECMP,
|
||||
ROCKER_OF_DPA_GROUP_TYPE_L2_OVERLAY,
|
||||
};
|
||||
|
||||
/* OF-DPA group L2 overlay types */
|
||||
enum rocker_of_dpa_overlay_type {
|
||||
ROCKER_OF_DPA_OVERLAY_TYPE_FLOOD_UCAST = 0,
|
||||
ROCKER_OF_DPA_OVERLAY_TYPE_FLOOD_MCAST,
|
||||
ROCKER_OF_DPA_OVERLAY_TYPE_MCAST_UCAST,
|
||||
ROCKER_OF_DPA_OVERLAY_TYPE_MCAST_MCAST,
|
||||
};
|
||||
|
||||
/* OF-DPA group ID encoding */
|
||||
#define ROCKER_GROUP_TYPE_SHIFT 28
|
||||
#define ROCKER_GROUP_TYPE_MASK 0xf0000000
|
||||
#define ROCKER_GROUP_VLAN_SHIFT 16
|
||||
#define ROCKER_GROUP_VLAN_MASK 0x0fff0000
|
||||
#define ROCKER_GROUP_PORT_SHIFT 0
|
||||
#define ROCKER_GROUP_PORT_MASK 0x0000ffff
|
||||
#define ROCKER_GROUP_TUNNEL_ID_SHIFT 12
|
||||
#define ROCKER_GROUP_TUNNEL_ID_MASK 0x0ffff000
|
||||
#define ROCKER_GROUP_SUBTYPE_SHIFT 10
|
||||
#define ROCKER_GROUP_SUBTYPE_MASK 0x00000c00
|
||||
#define ROCKER_GROUP_INDEX_SHIFT 0
|
||||
#define ROCKER_GROUP_INDEX_MASK 0x0000ffff
|
||||
#define ROCKER_GROUP_INDEX_LONG_SHIFT 0
|
||||
#define ROCKER_GROUP_INDEX_LONG_MASK 0x0fffffff
|
||||
|
||||
#define ROCKER_GROUP_TYPE_GET(group_id) \
|
||||
(((group_id) & ROCKER_GROUP_TYPE_MASK) >> ROCKER_GROUP_TYPE_SHIFT)
|
||||
#define ROCKER_GROUP_TYPE_SET(type) \
|
||||
(((type) << ROCKER_GROUP_TYPE_SHIFT) & ROCKER_GROUP_TYPE_MASK)
|
||||
#define ROCKER_GROUP_VLAN_GET(group_id) \
|
||||
(((group_id) & ROCKER_GROUP_VLAN_ID_MASK) >> ROCKER_GROUP_VLAN_ID_SHIFT)
|
||||
#define ROCKER_GROUP_VLAN_SET(vlan_id) \
|
||||
(((vlan_id) << ROCKER_GROUP_VLAN_SHIFT) & ROCKER_GROUP_VLAN_MASK)
|
||||
#define ROCKER_GROUP_PORT_GET(group_id) \
|
||||
(((group_id) & ROCKER_GROUP_PORT_MASK) >> ROCKER_GROUP_PORT_SHIFT)
|
||||
#define ROCKER_GROUP_PORT_SET(port) \
|
||||
(((port) << ROCKER_GROUP_PORT_SHIFT) & ROCKER_GROUP_PORT_MASK)
|
||||
#define ROCKER_GROUP_INDEX_GET(group_id) \
|
||||
(((group_id) & ROCKER_GROUP_INDEX_MASK) >> ROCKER_GROUP_INDEX_SHIFT)
|
||||
#define ROCKER_GROUP_INDEX_SET(index) \
|
||||
(((index) << ROCKER_GROUP_INDEX_SHIFT) & ROCKER_GROUP_INDEX_MASK)
|
||||
#define ROCKER_GROUP_INDEX_LONG_GET(group_id) \
|
||||
(((group_id) & ROCKER_GROUP_INDEX_LONG_MASK) >> \
|
||||
ROCKER_GROUP_INDEX_LONG_SHIFT)
|
||||
#define ROCKER_GROUP_INDEX_LONG_SET(index) \
|
||||
(((index) << ROCKER_GROUP_INDEX_LONG_SHIFT) & \
|
||||
ROCKER_GROUP_INDEX_LONG_MASK)
|
||||
|
||||
#define ROCKER_GROUP_NONE 0
|
||||
#define ROCKER_GROUP_L2_INTERFACE(vlan_id, port) \
|
||||
(ROCKER_GROUP_TYPE_SET(ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE) |\
|
||||
ROCKER_GROUP_VLAN_SET(ntohs(vlan_id)) | ROCKER_GROUP_PORT_SET(port))
|
||||
#define ROCKER_GROUP_L2_REWRITE(index) \
|
||||
(ROCKER_GROUP_TYPE_SET(ROCKER_OF_DPA_GROUP_TYPE_L2_REWRITE) |\
|
||||
ROCKER_GROUP_INDEX_LONG_SET(index))
|
||||
#define ROCKER_GROUP_L2_MCAST(vlan_id, index) \
|
||||
(ROCKER_GROUP_TYPE_SET(ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST) |\
|
||||
ROCKER_GROUP_VLAN_SET(ntohs(vlan_id)) | ROCKER_GROUP_INDEX_SET(index))
|
||||
#define ROCKER_GROUP_L2_FLOOD(vlan_id, index) \
|
||||
(ROCKER_GROUP_TYPE_SET(ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD) |\
|
||||
ROCKER_GROUP_VLAN_SET(ntohs(vlan_id)) | ROCKER_GROUP_INDEX_SET(index))
|
||||
#define ROCKER_GROUP_L3_UNICAST(index) \
|
||||
(ROCKER_GROUP_TYPE_SET(ROCKER_OF_DPA_GROUP_TYPE_L3_UCAST) |\
|
||||
ROCKER_GROUP_INDEX_LONG_SET(index))
|
||||
|
||||
/* Rocker general purpose registers */
|
||||
#define ROCKER_CONTROL 0x0300
|
||||
#define ROCKER_PORT_PHYS_COUNT 0x0304
|
||||
#define ROCKER_PORT_PHYS_LINK_STATUS 0x0310 /* 8-byte */
|
||||
#define ROCKER_PORT_PHYS_ENABLE 0x0318 /* 8-byte */
|
||||
#define ROCKER_SWITCH_ID 0x0320 /* 8-byte */
|
||||
|
||||
/* Rocker control bits */
|
||||
#define ROCKER_CONTROL_RESET (1 << 0)
|
||||
|
||||
#endif
|
@ -873,7 +873,7 @@ static int macvlan_vlan_rx_kill_vid(struct net_device *dev,
|
||||
|
||||
static int macvlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
|
||||
struct net_device *dev,
|
||||
const unsigned char *addr,
|
||||
const unsigned char *addr, u16 vid,
|
||||
u16 flags)
|
||||
{
|
||||
struct macvlan_dev *vlan = netdev_priv(dev);
|
||||
@ -898,7 +898,7 @@ static int macvlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
|
||||
|
||||
static int macvlan_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
|
||||
struct net_device *dev,
|
||||
const unsigned char *addr)
|
||||
const unsigned char *addr, u16 vid)
|
||||
{
|
||||
struct macvlan_dev *vlan = netdev_priv(dev);
|
||||
int err = -EINVAL;
|
||||
|
@ -849,7 +849,7 @@ static int vxlan_fdb_parse(struct nlattr *tb[], struct vxlan_dev *vxlan,
|
||||
/* Add static entry (via netlink) */
|
||||
static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
|
||||
struct net_device *dev,
|
||||
const unsigned char *addr, u16 flags)
|
||||
const unsigned char *addr, u16 vid, u16 flags)
|
||||
{
|
||||
struct vxlan_dev *vxlan = netdev_priv(dev);
|
||||
/* struct net *net = dev_net(vxlan->dev); */
|
||||
@ -885,7 +885,7 @@ static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
|
||||
/* Delete entry (via netlink) */
|
||||
static int vxlan_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[],
|
||||
struct net_device *dev,
|
||||
const unsigned char *addr)
|
||||
const unsigned char *addr, u16 vid)
|
||||
{
|
||||
struct vxlan_dev *vxlan = netdev_priv(dev);
|
||||
struct vxlan_fdb *f;
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
#include <uapi/linux/if_bridge.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
struct br_ip {
|
||||
union {
|
||||
@ -32,11 +33,41 @@ struct br_ip_list {
|
||||
struct br_ip addr;
|
||||
};
|
||||
|
||||
#define BR_HAIRPIN_MODE BIT(0)
|
||||
#define BR_BPDU_GUARD BIT(1)
|
||||
#define BR_ROOT_BLOCK BIT(2)
|
||||
#define BR_MULTICAST_FAST_LEAVE BIT(3)
|
||||
#define BR_ADMIN_COST BIT(4)
|
||||
#define BR_LEARNING BIT(5)
|
||||
#define BR_FLOOD BIT(6)
|
||||
#define BR_AUTO_MASK (BR_FLOOD | BR_LEARNING)
|
||||
#define BR_PROMISC BIT(7)
|
||||
#define BR_PROXYARP BIT(8)
|
||||
#define BR_LEARNING_SYNC BIT(9)
|
||||
|
||||
extern void brioctl_set(int (*ioctl_hook)(struct net *, unsigned int, void __user *));
|
||||
|
||||
typedef int br_should_route_hook_t(struct sk_buff *skb);
|
||||
extern br_should_route_hook_t __rcu *br_should_route_hook;
|
||||
|
||||
#if IS_ENABLED(CONFIG_BRIDGE)
|
||||
int br_fdb_external_learn_add(struct net_device *dev,
|
||||
const unsigned char *addr, u16 vid);
|
||||
int br_fdb_external_learn_del(struct net_device *dev,
|
||||
const unsigned char *addr, u16 vid);
|
||||
#else
|
||||
static inline int br_fdb_external_learn_add(struct net_device *dev,
|
||||
const unsigned char *addr, u16 vid)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int br_fdb_external_learn_del(struct net_device *dev,
|
||||
const unsigned char *addr, u16 vid)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_BRIDGE) && IS_ENABLED(CONFIG_BRIDGE_IGMP_SNOOPING)
|
||||
int br_multicast_list_adjacent(struct net_device *dev,
|
||||
struct list_head *br_ip_list);
|
||||
|
@ -754,13 +754,13 @@ struct netdev_fcoe_hbainfo {
|
||||
};
|
||||
#endif
|
||||
|
||||
#define MAX_PHYS_PORT_ID_LEN 32
|
||||
#define MAX_PHYS_ITEM_ID_LEN 32
|
||||
|
||||
/* This structure holds a unique identifier to identify the
|
||||
* physical port used by a netdevice.
|
||||
/* This structure holds a unique identifier to identify some
|
||||
* physical item (port for example) used by a netdevice.
|
||||
*/
|
||||
struct netdev_phys_port_id {
|
||||
unsigned char id[MAX_PHYS_PORT_ID_LEN];
|
||||
struct netdev_phys_item_id {
|
||||
unsigned char id[MAX_PHYS_ITEM_ID_LEN];
|
||||
unsigned char id_len;
|
||||
};
|
||||
|
||||
@ -951,11 +951,11 @@ typedef u16 (*select_queue_fallback_t)(struct net_device *dev,
|
||||
*
|
||||
* int (*ndo_fdb_add)(struct ndmsg *ndm, struct nlattr *tb[],
|
||||
* struct net_device *dev,
|
||||
* const unsigned char *addr, u16 flags)
|
||||
* const unsigned char *addr, u16 vid, u16 flags)
|
||||
* Adds an FDB entry to dev for addr.
|
||||
* int (*ndo_fdb_del)(struct ndmsg *ndm, struct nlattr *tb[],
|
||||
* struct net_device *dev,
|
||||
* const unsigned char *addr)
|
||||
* const unsigned char *addr, u16 vid)
|
||||
* Deletes the FDB entry from dev coresponding to addr.
|
||||
* int (*ndo_fdb_dump)(struct sk_buff *skb, struct netlink_callback *cb,
|
||||
* struct net_device *dev, struct net_device *filter_dev,
|
||||
@ -976,7 +976,7 @@ typedef u16 (*select_queue_fallback_t)(struct net_device *dev,
|
||||
* USB_CDC_NOTIFY_NETWORK_CONNECTION) should NOT implement this function.
|
||||
*
|
||||
* int (*ndo_get_phys_port_id)(struct net_device *dev,
|
||||
* struct netdev_phys_port_id *ppid);
|
||||
* struct netdev_phys_item_id *ppid);
|
||||
* Called to get ID of physical port of this device. If driver does
|
||||
* not implement this, it is assumed that the hw is not able to have
|
||||
* multiple net devices on single physical port.
|
||||
@ -1018,6 +1018,15 @@ typedef u16 (*select_queue_fallback_t)(struct net_device *dev,
|
||||
* performing GSO on a packet. The device returns true if it is
|
||||
* able to GSO the packet, false otherwise. If the return value is
|
||||
* false the stack will do software GSO.
|
||||
*
|
||||
* int (*ndo_switch_parent_id_get)(struct net_device *dev,
|
||||
* struct netdev_phys_item_id *psid);
|
||||
* Called to get an ID of the switch chip this port is part of.
|
||||
* If driver implements this, it indicates that it represents a port
|
||||
* of a switch chip.
|
||||
* int (*ndo_switch_port_stp_update)(struct net_device *dev, u8 state);
|
||||
* Called to notify switch device port of bridge port STP
|
||||
* state change.
|
||||
*/
|
||||
struct net_device_ops {
|
||||
int (*ndo_init)(struct net_device *dev);
|
||||
@ -1128,11 +1137,13 @@ struct net_device_ops {
|
||||
struct nlattr *tb[],
|
||||
struct net_device *dev,
|
||||
const unsigned char *addr,
|
||||
u16 vid,
|
||||
u16 flags);
|
||||
int (*ndo_fdb_del)(struct ndmsg *ndm,
|
||||
struct nlattr *tb[],
|
||||
struct net_device *dev,
|
||||
const unsigned char *addr);
|
||||
const unsigned char *addr,
|
||||
u16 vid);
|
||||
int (*ndo_fdb_dump)(struct sk_buff *skb,
|
||||
struct netlink_callback *cb,
|
||||
struct net_device *dev,
|
||||
@ -1150,7 +1161,7 @@ struct net_device_ops {
|
||||
int (*ndo_change_carrier)(struct net_device *dev,
|
||||
bool new_carrier);
|
||||
int (*ndo_get_phys_port_id)(struct net_device *dev,
|
||||
struct netdev_phys_port_id *ppid);
|
||||
struct netdev_phys_item_id *ppid);
|
||||
void (*ndo_add_vxlan_port)(struct net_device *dev,
|
||||
sa_family_t sa_family,
|
||||
__be16 port);
|
||||
@ -1169,6 +1180,12 @@ struct net_device_ops {
|
||||
int (*ndo_get_lock_subclass)(struct net_device *dev);
|
||||
bool (*ndo_gso_check) (struct sk_buff *skb,
|
||||
struct net_device *dev);
|
||||
#ifdef CONFIG_NET_SWITCHDEV
|
||||
int (*ndo_switch_parent_id_get)(struct net_device *dev,
|
||||
struct netdev_phys_item_id *psid);
|
||||
int (*ndo_switch_port_stp_update)(struct net_device *dev,
|
||||
u8 state);
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
@ -2868,7 +2885,7 @@ void dev_set_group(struct net_device *, int);
|
||||
int dev_set_mac_address(struct net_device *, struct sockaddr *);
|
||||
int dev_change_carrier(struct net_device *, bool new_carrier);
|
||||
int dev_get_phys_port_id(struct net_device *dev,
|
||||
struct netdev_phys_port_id *ppid);
|
||||
struct netdev_phys_item_id *ppid);
|
||||
struct sk_buff *validate_xmit_skb_list(struct sk_buff *skb, struct net_device *dev);
|
||||
struct sk_buff *dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
|
||||
struct netdev_queue *txq, int *ret);
|
||||
|
@ -94,12 +94,15 @@ extern int ndo_dflt_fdb_add(struct ndmsg *ndm,
|
||||
struct nlattr *tb[],
|
||||
struct net_device *dev,
|
||||
const unsigned char *addr,
|
||||
u16 flags);
|
||||
u16 vid,
|
||||
u16 flags);
|
||||
extern int ndo_dflt_fdb_del(struct ndmsg *ndm,
|
||||
struct nlattr *tb[],
|
||||
struct net_device *dev,
|
||||
const unsigned char *addr);
|
||||
const unsigned char *addr,
|
||||
u16 vid);
|
||||
|
||||
extern int ndo_dflt_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
|
||||
struct net_device *dev, u16 mode);
|
||||
struct net_device *dev, u16 mode,
|
||||
u32 flags, u32 mask);
|
||||
#endif /* __LINUX_RTNETLINK_H */
|
||||
|
37
include/net/switchdev.h
Normal file
37
include/net/switchdev.h
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* include/net/switchdev.h - Switch device API
|
||||
* Copyright (c) 2014 Jiri Pirko <jiri@resnulli.us>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
#ifndef _LINUX_SWITCHDEV_H_
|
||||
#define _LINUX_SWITCHDEV_H_
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
#ifdef CONFIG_NET_SWITCHDEV
|
||||
|
||||
int netdev_switch_parent_id_get(struct net_device *dev,
|
||||
struct netdev_phys_item_id *psid);
|
||||
int netdev_switch_port_stp_update(struct net_device *dev, u8 state);
|
||||
|
||||
#else
|
||||
|
||||
static inline int netdev_switch_parent_id_get(struct net_device *dev,
|
||||
struct netdev_phys_item_id *psid)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int netdev_switch_port_stp_update(struct net_device *dev,
|
||||
u8 state)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _LINUX_SWITCHDEV_H_ */
|
@ -105,6 +105,7 @@ struct __fdb_entry {
|
||||
|
||||
#define BRIDGE_MODE_VEB 0 /* Default loopback mode */
|
||||
#define BRIDGE_MODE_VEPA 1 /* 802.1Qbg defined VEPA mode */
|
||||
#define BRIDGE_MODE_SWDEV 2 /* Full switch device offload */
|
||||
|
||||
/* Bridge management nested attributes
|
||||
* [IFLA_AF_SPEC] = {
|
||||
|
@ -145,6 +145,7 @@ enum {
|
||||
IFLA_CARRIER,
|
||||
IFLA_PHYS_PORT_ID,
|
||||
IFLA_CARRIER_CHANGES,
|
||||
IFLA_PHYS_SWITCH_ID,
|
||||
__IFLA_MAX
|
||||
};
|
||||
|
||||
@ -244,6 +245,7 @@ enum {
|
||||
IFLA_BRPORT_LEARNING, /* mac learning */
|
||||
IFLA_BRPORT_UNICAST_FLOOD, /* flood unicast traffic */
|
||||
IFLA_BRPORT_PROXYARP, /* proxy ARP */
|
||||
IFLA_BRPORT_LEARNING_SYNC, /* mac learning sync from device */
|
||||
__IFLA_BRPORT_MAX
|
||||
};
|
||||
#define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
|
||||
|
@ -35,11 +35,11 @@ enum {
|
||||
*/
|
||||
|
||||
#define NTF_USE 0x01
|
||||
#define NTF_PROXY 0x08 /* == ATF_PUBL */
|
||||
#define NTF_ROUTER 0x80
|
||||
|
||||
#define NTF_SELF 0x02
|
||||
#define NTF_MASTER 0x04
|
||||
#define NTF_PROXY 0x08 /* == ATF_PUBL */
|
||||
#define NTF_EXT_LEARNED 0x10
|
||||
#define NTF_ROUTER 0x80
|
||||
|
||||
/*
|
||||
* Neighbor Cache Entry States.
|
||||
|
@ -228,6 +228,7 @@ source "net/vmw_vsock/Kconfig"
|
||||
source "net/netlink/Kconfig"
|
||||
source "net/mpls/Kconfig"
|
||||
source "net/hsr/Kconfig"
|
||||
source "net/switchdev/Kconfig"
|
||||
|
||||
config RPS
|
||||
boolean
|
||||
|
@ -73,3 +73,6 @@ obj-$(CONFIG_OPENVSWITCH) += openvswitch/
|
||||
obj-$(CONFIG_VSOCKETS) += vmw_vsock/
|
||||
obj-$(CONFIG_NET_MPLS_GSO) += mpls/
|
||||
obj-$(CONFIG_HSR) += hsr/
|
||||
ifneq ($(CONFIG_NET_SWITCHDEV),)
|
||||
obj-y += switchdev/
|
||||
endif
|
||||
|
@ -90,7 +90,7 @@ static void fdb_rcu_free(struct rcu_head *head)
|
||||
* are then updated with the new information.
|
||||
* Called under RTNL.
|
||||
*/
|
||||
static void fdb_add_hw(struct net_bridge *br, const unsigned char *addr)
|
||||
static void fdb_add_hw_addr(struct net_bridge *br, const unsigned char *addr)
|
||||
{
|
||||
int err;
|
||||
struct net_bridge_port *p;
|
||||
@ -118,7 +118,7 @@ undo:
|
||||
* the ports with needed information.
|
||||
* Called under RTNL.
|
||||
*/
|
||||
static void fdb_del_hw(struct net_bridge *br, const unsigned char *addr)
|
||||
static void fdb_del_hw_addr(struct net_bridge *br, const unsigned char *addr)
|
||||
{
|
||||
struct net_bridge_port *p;
|
||||
|
||||
@ -133,7 +133,7 @@ static void fdb_del_hw(struct net_bridge *br, const unsigned char *addr)
|
||||
static void fdb_delete(struct net_bridge *br, struct net_bridge_fdb_entry *f)
|
||||
{
|
||||
if (f->is_static)
|
||||
fdb_del_hw(br, f->addr.addr);
|
||||
fdb_del_hw_addr(br, f->addr.addr);
|
||||
|
||||
hlist_del_rcu(&f->hlist);
|
||||
fdb_notify(br, f, RTM_DELNEIGH);
|
||||
@ -481,6 +481,7 @@ static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head,
|
||||
fdb->is_local = 0;
|
||||
fdb->is_static = 0;
|
||||
fdb->added_by_user = 0;
|
||||
fdb->added_by_external_learn = 0;
|
||||
fdb->updated = fdb->used = jiffies;
|
||||
hlist_add_head_rcu(&fdb->hlist, head);
|
||||
}
|
||||
@ -514,7 +515,7 @@ static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
|
||||
return -ENOMEM;
|
||||
|
||||
fdb->is_local = fdb->is_static = 1;
|
||||
fdb_add_hw(br, addr);
|
||||
fdb_add_hw_addr(br, addr);
|
||||
fdb_notify(br, fdb, RTM_NEWNEIGH);
|
||||
return 0;
|
||||
}
|
||||
@ -613,7 +614,7 @@ static int fdb_fill_info(struct sk_buff *skb, const struct net_bridge *br,
|
||||
ndm->ndm_family = AF_BRIDGE;
|
||||
ndm->ndm_pad1 = 0;
|
||||
ndm->ndm_pad2 = 0;
|
||||
ndm->ndm_flags = 0;
|
||||
ndm->ndm_flags = fdb->added_by_external_learn ? NTF_EXT_LEARNED : 0;
|
||||
ndm->ndm_type = 0;
|
||||
ndm->ndm_ifindex = fdb->dst ? fdb->dst->dev->ifindex : br->dev->ifindex;
|
||||
ndm->ndm_state = fdb_to_nud(fdb);
|
||||
@ -754,19 +755,19 @@ static int fdb_add_entry(struct net_bridge_port *source, const __u8 *addr,
|
||||
fdb->is_local = 1;
|
||||
if (!fdb->is_static) {
|
||||
fdb->is_static = 1;
|
||||
fdb_add_hw(br, addr);
|
||||
fdb_add_hw_addr(br, addr);
|
||||
}
|
||||
} else if (state & NUD_NOARP) {
|
||||
fdb->is_local = 0;
|
||||
if (!fdb->is_static) {
|
||||
fdb->is_static = 1;
|
||||
fdb_add_hw(br, addr);
|
||||
fdb_add_hw_addr(br, addr);
|
||||
}
|
||||
} else {
|
||||
fdb->is_local = 0;
|
||||
if (fdb->is_static) {
|
||||
fdb->is_static = 0;
|
||||
fdb_del_hw(br, addr);
|
||||
fdb_del_hw_addr(br, addr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -805,33 +806,17 @@ static int __br_fdb_add(struct ndmsg *ndm, struct net_bridge_port *p,
|
||||
/* Add new permanent fdb entry with RTM_NEWNEIGH */
|
||||
int br_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
|
||||
struct net_device *dev,
|
||||
const unsigned char *addr, u16 nlh_flags)
|
||||
const unsigned char *addr, u16 vid, u16 nlh_flags)
|
||||
{
|
||||
struct net_bridge_port *p;
|
||||
int err = 0;
|
||||
struct net_port_vlans *pv;
|
||||
unsigned short vid = VLAN_N_VID;
|
||||
|
||||
if (!(ndm->ndm_state & (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE))) {
|
||||
pr_info("bridge: RTM_NEWNEIGH with invalid state %#x\n", ndm->ndm_state);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (tb[NDA_VLAN]) {
|
||||
if (nla_len(tb[NDA_VLAN]) != sizeof(unsigned short)) {
|
||||
pr_info("bridge: RTM_NEWNEIGH with invalid vlan\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
vid = nla_get_u16(tb[NDA_VLAN]);
|
||||
|
||||
if (!vid || vid >= VLAN_VID_MASK) {
|
||||
pr_info("bridge: RTM_NEWNEIGH with invalid vlan id %d\n",
|
||||
vid);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_zero_ether_addr(addr)) {
|
||||
pr_info("bridge: RTM_NEWNEIGH with invalid ether address\n");
|
||||
return -EINVAL;
|
||||
@ -845,7 +830,7 @@ int br_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
|
||||
}
|
||||
|
||||
pv = nbp_get_vlan_info(p);
|
||||
if (vid != VLAN_N_VID) {
|
||||
if (vid) {
|
||||
if (!pv || !test_bit(vid, pv->vlan_bitmap)) {
|
||||
pr_info("bridge: RTM_NEWNEIGH with unconfigured "
|
||||
"vlan %d on port %s\n", vid, dev->name);
|
||||
@ -903,27 +888,12 @@ static int __br_fdb_delete(struct net_bridge_port *p,
|
||||
/* Remove neighbor entry with RTM_DELNEIGH */
|
||||
int br_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[],
|
||||
struct net_device *dev,
|
||||
const unsigned char *addr)
|
||||
const unsigned char *addr, u16 vid)
|
||||
{
|
||||
struct net_bridge_port *p;
|
||||
int err;
|
||||
struct net_port_vlans *pv;
|
||||
unsigned short vid = VLAN_N_VID;
|
||||
|
||||
if (tb[NDA_VLAN]) {
|
||||
if (nla_len(tb[NDA_VLAN]) != sizeof(unsigned short)) {
|
||||
pr_info("bridge: RTM_NEWNEIGH with invalid vlan\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
vid = nla_get_u16(tb[NDA_VLAN]);
|
||||
|
||||
if (!vid || vid >= VLAN_VID_MASK) {
|
||||
pr_info("bridge: RTM_NEWNEIGH with invalid vlan id %d\n",
|
||||
vid);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
p = br_port_get_rtnl(dev);
|
||||
if (p == NULL) {
|
||||
pr_info("bridge: RTM_DELNEIGH %s not a bridge port\n",
|
||||
@ -932,7 +902,7 @@ int br_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[],
|
||||
}
|
||||
|
||||
pv = nbp_get_vlan_info(p);
|
||||
if (vid != VLAN_N_VID) {
|
||||
if (vid) {
|
||||
if (!pv || !test_bit(vid, pv->vlan_bitmap)) {
|
||||
pr_info("bridge: RTM_DELNEIGH with unconfigured "
|
||||
"vlan %d on port %s\n", vid, dev->name);
|
||||
@ -1014,3 +984,91 @@ void br_fdb_unsync_static(struct net_bridge *br, struct net_bridge_port *p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int br_fdb_external_learn_add(struct net_device *dev,
|
||||
const unsigned char *addr, u16 vid)
|
||||
{
|
||||
struct net_bridge_port *p;
|
||||
struct net_bridge *br;
|
||||
struct hlist_head *head;
|
||||
struct net_bridge_fdb_entry *fdb;
|
||||
int err = 0;
|
||||
|
||||
rtnl_lock();
|
||||
|
||||
p = br_port_get_rtnl(dev);
|
||||
if (!p) {
|
||||
pr_info("bridge: %s not a bridge port\n", dev->name);
|
||||
err = -EINVAL;
|
||||
goto err_rtnl_unlock;
|
||||
}
|
||||
|
||||
br = p->br;
|
||||
|
||||
spin_lock_bh(&br->hash_lock);
|
||||
|
||||
head = &br->hash[br_mac_hash(addr, vid)];
|
||||
fdb = fdb_find(head, addr, vid);
|
||||
if (!fdb) {
|
||||
fdb = fdb_create(head, p, addr, vid);
|
||||
if (!fdb) {
|
||||
err = -ENOMEM;
|
||||
goto err_unlock;
|
||||
}
|
||||
fdb->added_by_external_learn = 1;
|
||||
fdb_notify(br, fdb, RTM_NEWNEIGH);
|
||||
} else if (fdb->added_by_external_learn) {
|
||||
/* Refresh entry */
|
||||
fdb->updated = fdb->used = jiffies;
|
||||
} else if (!fdb->added_by_user) {
|
||||
/* Take over SW learned entry */
|
||||
fdb->added_by_external_learn = 1;
|
||||
fdb->updated = jiffies;
|
||||
fdb_notify(br, fdb, RTM_NEWNEIGH);
|
||||
}
|
||||
|
||||
err_unlock:
|
||||
spin_unlock_bh(&br->hash_lock);
|
||||
err_rtnl_unlock:
|
||||
rtnl_unlock();
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(br_fdb_external_learn_add);
|
||||
|
||||
int br_fdb_external_learn_del(struct net_device *dev,
|
||||
const unsigned char *addr, u16 vid)
|
||||
{
|
||||
struct net_bridge_port *p;
|
||||
struct net_bridge *br;
|
||||
struct hlist_head *head;
|
||||
struct net_bridge_fdb_entry *fdb;
|
||||
int err = 0;
|
||||
|
||||
rtnl_lock();
|
||||
|
||||
p = br_port_get_rtnl(dev);
|
||||
if (!p) {
|
||||
pr_info("bridge: %s not a bridge port\n", dev->name);
|
||||
err = -EINVAL;
|
||||
goto err_rtnl_unlock;
|
||||
}
|
||||
|
||||
br = p->br;
|
||||
|
||||
spin_lock_bh(&br->hash_lock);
|
||||
|
||||
head = &br->hash[br_mac_hash(addr, vid)];
|
||||
fdb = fdb_find(head, addr, vid);
|
||||
if (fdb && fdb->added_by_external_learn)
|
||||
fdb_delete(br, fdb);
|
||||
else
|
||||
err = -ENOENT;
|
||||
|
||||
spin_unlock_bh(&br->hash_lock);
|
||||
err_rtnl_unlock:
|
||||
rtnl_unlock();
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(br_fdb_external_learn_del);
|
||||
|
@ -98,9 +98,10 @@ struct net_bridge_fdb_entry
|
||||
unsigned long updated;
|
||||
unsigned long used;
|
||||
mac_addr addr;
|
||||
unsigned char is_local;
|
||||
unsigned char is_static;
|
||||
unsigned char added_by_user;
|
||||
unsigned char is_local:1,
|
||||
is_static:1,
|
||||
added_by_user:1,
|
||||
added_by_external_learn:1;
|
||||
__u16 vlan_id;
|
||||
};
|
||||
|
||||
@ -163,16 +164,6 @@ struct net_bridge_port
|
||||
struct rcu_head rcu;
|
||||
|
||||
unsigned long flags;
|
||||
#define BR_HAIRPIN_MODE 0x00000001
|
||||
#define BR_BPDU_GUARD 0x00000002
|
||||
#define BR_ROOT_BLOCK 0x00000004
|
||||
#define BR_MULTICAST_FAST_LEAVE 0x00000008
|
||||
#define BR_ADMIN_COST 0x00000010
|
||||
#define BR_LEARNING 0x00000020
|
||||
#define BR_FLOOD 0x00000040
|
||||
#define BR_AUTO_MASK (BR_FLOOD | BR_LEARNING)
|
||||
#define BR_PROMISC 0x00000080
|
||||
#define BR_PROXYARP 0x00000100
|
||||
|
||||
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
|
||||
struct bridge_mcast_own_query ip4_own_query;
|
||||
@ -404,9 +395,9 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
|
||||
const unsigned char *addr, u16 vid, bool added_by_user);
|
||||
|
||||
int br_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[],
|
||||
struct net_device *dev, const unsigned char *addr);
|
||||
struct net_device *dev, const unsigned char *addr, u16 vid);
|
||||
int br_fdb_add(struct ndmsg *nlh, struct nlattr *tb[], struct net_device *dev,
|
||||
const unsigned char *addr, u16 nlh_flags);
|
||||
const unsigned char *addr, u16 vid, u16 nlh_flags);
|
||||
int br_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb,
|
||||
struct net_device *dev, struct net_device *fdev, int idx);
|
||||
int br_fdb_sync_static(struct net_bridge *br, struct net_bridge_port *p);
|
||||
|
@ -12,6 +12,7 @@
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/rculist.h>
|
||||
#include <net/switchdev.h>
|
||||
|
||||
#include "br_private.h"
|
||||
#include "br_private_stp.h"
|
||||
@ -38,7 +39,13 @@ void br_log_state(const struct net_bridge_port *p)
|
||||
|
||||
void br_set_state(struct net_bridge_port *p, unsigned int state)
|
||||
{
|
||||
int err;
|
||||
|
||||
p->state = state;
|
||||
err = netdev_switch_port_stp_update(p->dev, state);
|
||||
if (err && err != -EOPNOTSUPP)
|
||||
br_warn(p->br, "error setting offload STP state on port %u(%s)\n",
|
||||
(unsigned int) p->port_no, p->dev->name);
|
||||
}
|
||||
|
||||
/* called under bridge lock */
|
||||
|
@ -5846,7 +5846,7 @@ EXPORT_SYMBOL(dev_change_carrier);
|
||||
* Get device physical port ID
|
||||
*/
|
||||
int dev_get_phys_port_id(struct net_device *dev,
|
||||
struct netdev_phys_port_id *ppid)
|
||||
struct netdev_phys_item_id *ppid)
|
||||
{
|
||||
const struct net_device_ops *ops = dev->netdev_ops;
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <linux/capability.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <net/switchdev.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/nsproxy.h>
|
||||
@ -404,7 +405,7 @@ static ssize_t phys_port_id_show(struct device *dev,
|
||||
return restart_syscall();
|
||||
|
||||
if (dev_isalive(netdev)) {
|
||||
struct netdev_phys_port_id ppid;
|
||||
struct netdev_phys_item_id ppid;
|
||||
|
||||
ret = dev_get_phys_port_id(netdev, &ppid);
|
||||
if (!ret)
|
||||
@ -416,6 +417,28 @@ static ssize_t phys_port_id_show(struct device *dev,
|
||||
}
|
||||
static DEVICE_ATTR_RO(phys_port_id);
|
||||
|
||||
static ssize_t phys_switch_id_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct net_device *netdev = to_net_dev(dev);
|
||||
ssize_t ret = -EINVAL;
|
||||
|
||||
if (!rtnl_trylock())
|
||||
return restart_syscall();
|
||||
|
||||
if (dev_isalive(netdev)) {
|
||||
struct netdev_phys_item_id ppid;
|
||||
|
||||
ret = netdev_switch_parent_id_get(netdev, &ppid);
|
||||
if (!ret)
|
||||
ret = sprintf(buf, "%*phN\n", ppid.id_len, ppid.id);
|
||||
}
|
||||
rtnl_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
static DEVICE_ATTR_RO(phys_switch_id);
|
||||
|
||||
static struct attribute *net_class_attrs[] = {
|
||||
&dev_attr_netdev_group.attr,
|
||||
&dev_attr_type.attr,
|
||||
@ -441,6 +464,7 @@ static struct attribute *net_class_attrs[] = {
|
||||
&dev_attr_tx_queue_len.attr,
|
||||
&dev_attr_gro_flush_timeout.attr,
|
||||
&dev_attr_phys_port_id.attr,
|
||||
&dev_attr_phys_switch_id.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(net_class);
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/if_addr.h>
|
||||
#include <linux/if_bridge.h>
|
||||
#include <linux/if_vlan.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/etherdevice.h>
|
||||
|
||||
@ -43,6 +44,7 @@
|
||||
|
||||
#include <linux/inet.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <net/switchdev.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/protocol.h>
|
||||
#include <net/arp.h>
|
||||
@ -868,7 +870,8 @@ static noinline size_t if_nlmsg_size(const struct net_device *dev,
|
||||
+ rtnl_port_size(dev, ext_filter_mask) /* IFLA_VF_PORTS + IFLA_PORT_SELF */
|
||||
+ rtnl_link_get_size(dev) /* IFLA_LINKINFO */
|
||||
+ rtnl_link_get_af_size(dev) /* IFLA_AF_SPEC */
|
||||
+ nla_total_size(MAX_PHYS_PORT_ID_LEN); /* IFLA_PHYS_PORT_ID */
|
||||
+ nla_total_size(MAX_PHYS_ITEM_ID_LEN) /* IFLA_PHYS_PORT_ID */
|
||||
+ nla_total_size(MAX_PHYS_ITEM_ID_LEN); /* IFLA_PHYS_SWITCH_ID */
|
||||
}
|
||||
|
||||
static int rtnl_vf_ports_fill(struct sk_buff *skb, struct net_device *dev)
|
||||
@ -952,7 +955,7 @@ static int rtnl_port_fill(struct sk_buff *skb, struct net_device *dev,
|
||||
static int rtnl_phys_port_id_fill(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
int err;
|
||||
struct netdev_phys_port_id ppid;
|
||||
struct netdev_phys_item_id ppid;
|
||||
|
||||
err = dev_get_phys_port_id(dev, &ppid);
|
||||
if (err) {
|
||||
@ -967,6 +970,24 @@ static int rtnl_phys_port_id_fill(struct sk_buff *skb, struct net_device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rtnl_phys_switch_id_fill(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
int err;
|
||||
struct netdev_phys_item_id psid;
|
||||
|
||||
err = netdev_switch_parent_id_get(dev, &psid);
|
||||
if (err) {
|
||||
if (err == -EOPNOTSUPP)
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
if (nla_put(skb, IFLA_PHYS_SWITCH_ID, psid.id_len, psid.id))
|
||||
return -EMSGSIZE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
|
||||
int type, u32 pid, u32 seq, u32 change,
|
||||
unsigned int flags, u32 ext_filter_mask)
|
||||
@ -1039,6 +1060,9 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
|
||||
if (rtnl_phys_port_id_fill(skb, dev))
|
||||
goto nla_put_failure;
|
||||
|
||||
if (rtnl_phys_switch_id_fill(skb, dev))
|
||||
goto nla_put_failure;
|
||||
|
||||
attr = nla_reserve(skb, IFLA_STATS,
|
||||
sizeof(struct rtnl_link_stats));
|
||||
if (attr == NULL)
|
||||
@ -1196,8 +1220,9 @@ static const struct nla_policy ifla_policy[IFLA_MAX+1] = {
|
||||
[IFLA_PROMISCUITY] = { .type = NLA_U32 },
|
||||
[IFLA_NUM_TX_QUEUES] = { .type = NLA_U32 },
|
||||
[IFLA_NUM_RX_QUEUES] = { .type = NLA_U32 },
|
||||
[IFLA_PHYS_PORT_ID] = { .type = NLA_BINARY, .len = MAX_PHYS_PORT_ID_LEN },
|
||||
[IFLA_PHYS_PORT_ID] = { .type = NLA_BINARY, .len = MAX_PHYS_ITEM_ID_LEN },
|
||||
[IFLA_CARRIER_CHANGES] = { .type = NLA_U32 }, /* ignored */
|
||||
[IFLA_PHYS_SWITCH_ID] = { .type = NLA_BINARY, .len = MAX_PHYS_ITEM_ID_LEN },
|
||||
};
|
||||
|
||||
static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = {
|
||||
@ -2312,7 +2337,7 @@ errout:
|
||||
int ndo_dflt_fdb_add(struct ndmsg *ndm,
|
||||
struct nlattr *tb[],
|
||||
struct net_device *dev,
|
||||
const unsigned char *addr,
|
||||
const unsigned char *addr, u16 vid,
|
||||
u16 flags)
|
||||
{
|
||||
int err = -EINVAL;
|
||||
@ -2338,6 +2363,28 @@ int ndo_dflt_fdb_add(struct ndmsg *ndm,
|
||||
}
|
||||
EXPORT_SYMBOL(ndo_dflt_fdb_add);
|
||||
|
||||
static int fdb_vid_parse(struct nlattr *vlan_attr, u16 *p_vid)
|
||||
{
|
||||
u16 vid = 0;
|
||||
|
||||
if (vlan_attr) {
|
||||
if (nla_len(vlan_attr) != sizeof(u16)) {
|
||||
pr_info("PF_BRIDGE: RTM_NEWNEIGH with invalid vlan\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
vid = nla_get_u16(vlan_attr);
|
||||
|
||||
if (!vid || vid >= VLAN_VID_MASK) {
|
||||
pr_info("PF_BRIDGE: RTM_NEWNEIGH with invalid vlan id %d\n",
|
||||
vid);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
*p_vid = vid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||||
{
|
||||
struct net *net = sock_net(skb->sk);
|
||||
@ -2345,6 +2392,7 @@ static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||||
struct nlattr *tb[NDA_MAX+1];
|
||||
struct net_device *dev;
|
||||
u8 *addr;
|
||||
u16 vid;
|
||||
int err;
|
||||
|
||||
err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL);
|
||||
@ -2370,6 +2418,10 @@ static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||||
|
||||
addr = nla_data(tb[NDA_LLADDR]);
|
||||
|
||||
err = fdb_vid_parse(tb[NDA_VLAN], &vid);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = -EOPNOTSUPP;
|
||||
|
||||
/* Support fdb on master device the net/bridge default case */
|
||||
@ -2378,7 +2430,8 @@ static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||||
struct net_device *br_dev = netdev_master_upper_dev_get(dev);
|
||||
const struct net_device_ops *ops = br_dev->netdev_ops;
|
||||
|
||||
err = ops->ndo_fdb_add(ndm, tb, dev, addr, nlh->nlmsg_flags);
|
||||
err = ops->ndo_fdb_add(ndm, tb, dev, addr, vid,
|
||||
nlh->nlmsg_flags);
|
||||
if (err)
|
||||
goto out;
|
||||
else
|
||||
@ -2389,9 +2442,10 @@ static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||||
if ((ndm->ndm_flags & NTF_SELF)) {
|
||||
if (dev->netdev_ops->ndo_fdb_add)
|
||||
err = dev->netdev_ops->ndo_fdb_add(ndm, tb, dev, addr,
|
||||
vid,
|
||||
nlh->nlmsg_flags);
|
||||
else
|
||||
err = ndo_dflt_fdb_add(ndm, tb, dev, addr,
|
||||
err = ndo_dflt_fdb_add(ndm, tb, dev, addr, vid,
|
||||
nlh->nlmsg_flags);
|
||||
|
||||
if (!err) {
|
||||
@ -2409,7 +2463,7 @@ out:
|
||||
int ndo_dflt_fdb_del(struct ndmsg *ndm,
|
||||
struct nlattr *tb[],
|
||||
struct net_device *dev,
|
||||
const unsigned char *addr)
|
||||
const unsigned char *addr, u16 vid)
|
||||
{
|
||||
int err = -EINVAL;
|
||||
|
||||
@ -2438,6 +2492,7 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||||
struct net_device *dev;
|
||||
int err = -EINVAL;
|
||||
__u8 *addr;
|
||||
u16 vid;
|
||||
|
||||
if (!netlink_capable(skb, CAP_NET_ADMIN))
|
||||
return -EPERM;
|
||||
@ -2465,6 +2520,10 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||||
|
||||
addr = nla_data(tb[NDA_LLADDR]);
|
||||
|
||||
err = fdb_vid_parse(tb[NDA_VLAN], &vid);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = -EOPNOTSUPP;
|
||||
|
||||
/* Support fdb on master device the net/bridge default case */
|
||||
@ -2474,7 +2533,7 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||||
const struct net_device_ops *ops = br_dev->netdev_ops;
|
||||
|
||||
if (ops->ndo_fdb_del)
|
||||
err = ops->ndo_fdb_del(ndm, tb, dev, addr);
|
||||
err = ops->ndo_fdb_del(ndm, tb, dev, addr, vid);
|
||||
|
||||
if (err)
|
||||
goto out;
|
||||
@ -2485,9 +2544,10 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||||
/* Embedded bridge, macvlan, and any other device support */
|
||||
if (ndm->ndm_flags & NTF_SELF) {
|
||||
if (dev->netdev_ops->ndo_fdb_del)
|
||||
err = dev->netdev_ops->ndo_fdb_del(ndm, tb, dev, addr);
|
||||
err = dev->netdev_ops->ndo_fdb_del(ndm, tb, dev, addr,
|
||||
vid);
|
||||
else
|
||||
err = ndo_dflt_fdb_del(ndm, tb, dev, addr);
|
||||
err = ndo_dflt_fdb_del(ndm, tb, dev, addr, vid);
|
||||
|
||||
if (!err) {
|
||||
rtnl_fdb_notify(dev, addr, RTM_DELNEIGH);
|
||||
@ -2627,12 +2687,22 @@ static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
return skb->len;
|
||||
}
|
||||
|
||||
static int brport_nla_put_flag(struct sk_buff *skb, u32 flags, u32 mask,
|
||||
unsigned int attrnum, unsigned int flag)
|
||||
{
|
||||
if (mask & flag)
|
||||
return nla_put_u8(skb, attrnum, !!(flags & flag));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ndo_dflt_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
|
||||
struct net_device *dev, u16 mode)
|
||||
struct net_device *dev, u16 mode,
|
||||
u32 flags, u32 mask)
|
||||
{
|
||||
struct nlmsghdr *nlh;
|
||||
struct ifinfomsg *ifm;
|
||||
struct nlattr *br_afspec;
|
||||
struct nlattr *protinfo;
|
||||
u8 operstate = netif_running(dev) ? dev->operstate : IF_OPER_DOWN;
|
||||
struct net_device *br_dev = netdev_master_upper_dev_get(dev);
|
||||
|
||||
@ -2671,6 +2741,33 @@ int ndo_dflt_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
|
||||
}
|
||||
nla_nest_end(skb, br_afspec);
|
||||
|
||||
protinfo = nla_nest_start(skb, IFLA_PROTINFO | NLA_F_NESTED);
|
||||
if (!protinfo)
|
||||
goto nla_put_failure;
|
||||
|
||||
if (brport_nla_put_flag(skb, flags, mask,
|
||||
IFLA_BRPORT_MODE, BR_HAIRPIN_MODE) ||
|
||||
brport_nla_put_flag(skb, flags, mask,
|
||||
IFLA_BRPORT_GUARD, BR_BPDU_GUARD) ||
|
||||
brport_nla_put_flag(skb, flags, mask,
|
||||
IFLA_BRPORT_FAST_LEAVE,
|
||||
BR_MULTICAST_FAST_LEAVE) ||
|
||||
brport_nla_put_flag(skb, flags, mask,
|
||||
IFLA_BRPORT_PROTECT, BR_ROOT_BLOCK) ||
|
||||
brport_nla_put_flag(skb, flags, mask,
|
||||
IFLA_BRPORT_LEARNING, BR_LEARNING) ||
|
||||
brport_nla_put_flag(skb, flags, mask,
|
||||
IFLA_BRPORT_LEARNING_SYNC, BR_LEARNING_SYNC) ||
|
||||
brport_nla_put_flag(skb, flags, mask,
|
||||
IFLA_BRPORT_UNICAST_FLOOD, BR_FLOOD) ||
|
||||
brport_nla_put_flag(skb, flags, mask,
|
||||
IFLA_BRPORT_PROXYARP, BR_PROXYARP)) {
|
||||
nla_nest_cancel(skb, protinfo);
|
||||
goto nla_put_failure;
|
||||
}
|
||||
|
||||
nla_nest_end(skb, protinfo);
|
||||
|
||||
return nlmsg_end(skb, nlh);
|
||||
nla_put_failure:
|
||||
nlmsg_cancel(skb, nlh);
|
||||
|
13
net/switchdev/Kconfig
Normal file
13
net/switchdev/Kconfig
Normal file
@ -0,0 +1,13 @@
|
||||
#
|
||||
# Configuration for Switch device support
|
||||
#
|
||||
|
||||
config NET_SWITCHDEV
|
||||
boolean "Switch (and switch-ish) device support (EXPERIMENTAL)"
|
||||
depends on INET
|
||||
---help---
|
||||
This module provides glue between core networking code and device
|
||||
drivers in order to support hardware switch chips in very generic
|
||||
meaning of the word "switch". This include devices supporting L2/L3 but
|
||||
also various flow offloading chips, including switches embedded into
|
||||
SR-IOV NICs.
|
5
net/switchdev/Makefile
Normal file
5
net/switchdev/Makefile
Normal file
@ -0,0 +1,5 @@
|
||||
#
|
||||
# Makefile for the Switch device API
|
||||
#
|
||||
|
||||
obj-$(CONFIG_NET_SWITCHDEV) += switchdev.o
|
52
net/switchdev/switchdev.c
Normal file
52
net/switchdev/switchdev.c
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* net/switchdev/switchdev.c - Switch device API
|
||||
* Copyright (c) 2014 Jiri Pirko <jiri@resnulli.us>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <net/switchdev.h>
|
||||
|
||||
/**
|
||||
* netdev_switch_parent_id_get - Get ID of a switch
|
||||
* @dev: port device
|
||||
* @psid: switch ID
|
||||
*
|
||||
* Get ID of a switch this port is part of.
|
||||
*/
|
||||
int netdev_switch_parent_id_get(struct net_device *dev,
|
||||
struct netdev_phys_item_id *psid)
|
||||
{
|
||||
const struct net_device_ops *ops = dev->netdev_ops;
|
||||
|
||||
if (!ops->ndo_switch_parent_id_get)
|
||||
return -EOPNOTSUPP;
|
||||
return ops->ndo_switch_parent_id_get(dev, psid);
|
||||
}
|
||||
EXPORT_SYMBOL(netdev_switch_parent_id_get);
|
||||
|
||||
/**
|
||||
* netdev_switch_port_stp_update - Notify switch device port of STP
|
||||
* state change
|
||||
* @dev: port device
|
||||
* @state: port STP state
|
||||
*
|
||||
* Notify switch device port of bridge port STP state change.
|
||||
*/
|
||||
int netdev_switch_port_stp_update(struct net_device *dev, u8 state)
|
||||
{
|
||||
const struct net_device_ops *ops = dev->netdev_ops;
|
||||
|
||||
if (!ops->ndo_switch_port_stp_update)
|
||||
return -EOPNOTSUPP;
|
||||
WARN_ON(!ops->ndo_switch_parent_id_get);
|
||||
return ops->ndo_switch_port_stp_update(dev, state);
|
||||
}
|
||||
EXPORT_SYMBOL(netdev_switch_port_stp_update);
|
Loading…
Reference in New Issue
Block a user