* [PATCH] net: mvneta: implement .set_wol and .get_wol
From: Jingju Hou @ 2017-01-22 10:06 UTC (permalink / raw)
To: davem; +Cc: thomas.petazzoni, netdev, Jingju Hou
Signed-off-by: Jingju Hou <houjingj@marvell.com>
---
drivers/net/ethernet/marvell/mvneta.c | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c
index e05e227..b684f43 100644
--- a/drivers/net/ethernet/marvell/mvneta.c
+++ b/drivers/net/ethernet/marvell/mvneta.c
@@ -3908,6 +3908,29 @@ static int mvneta_ethtool_get_rxfh(struct net_device *dev, u32 *indir, u8 *key,
return 0;
}
+static void
+mvneta_ethtool_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ struct mvneta_port *pp = netdev_priv(dev);
+
+ wol->supported = 0;
+ wol->wolopts = 0;
+
+ if (pp->phy_dev)
+ return phy_ethtool_get_wol(pp->phy_dev, wol);
+}
+
+static int
+mvneta_ethtool_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ struct mvneta_port *pp = netdev_priv(dev);
+
+ if (!pp->phy_dev)
+ return -EOPNOTSUPP;
+
+ return phy_ethtool_set_wol(pp->phy_dev, wol);
+}
+
static const struct net_device_ops mvneta_netdev_ops = {
.ndo_open = mvneta_open,
.ndo_stop = mvneta_stop,
@@ -3937,6 +3960,8 @@ static int mvneta_ethtool_get_rxfh(struct net_device *dev, u32 *indir, u8 *key,
.set_rxfh = mvneta_ethtool_set_rxfh,
.get_link_ksettings = phy_ethtool_get_link_ksettings,
.set_link_ksettings = mvneta_ethtool_set_link_ksettings,
+ .get_wol = mvneta_ethtool_get_wol,
+ .set_wol = mvneta_ethtool_set_wol,
};
/* Initialize hw */
--
1.9.1
^ permalink raw reply related
* [PATCH] net: phy: marvell: Add Wake from LAN support for 88E1510 PHY
From: Jingju Hou @ 2017-01-22 10:20 UTC (permalink / raw)
To: davem; +Cc: netdev, Jingju Hou
Signed-off-by: Jingju Hou <houjingj@marvell.com>
---
drivers/net/phy/marvell.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index 0b78210..ed0d235 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -1679,6 +1679,8 @@ static int marvell_probe(struct phy_device *phydev)
.ack_interrupt = &marvell_ack_interrupt,
.config_intr = &marvell_config_intr,
.did_interrupt = &m88e1121_did_interrupt,
+ .get_wol = &m88e1318_get_wol,
+ .set_wol = &m88e1318_set_wol,
.resume = &marvell_resume,
.suspend = &marvell_suspend,
.get_sset_count = marvell_get_sset_count,
--
1.9.1
^ permalink raw reply related
* Re: [PATCH] net: mvneta: implement .set_wol and .get_wol
From: kbuild test robot @ 2017-01-22 11:13 UTC (permalink / raw)
To: Jingju Hou; +Cc: kbuild-all, davem, thomas.petazzoni, netdev, Jingju Hou
In-Reply-To: <1485079590-6392-1-git-send-email-houjingj@marvell.com>
[-- Attachment #1: Type: text/plain, Size: 2693 bytes --]
Hi Jingju,
[auto build test ERROR on net-next/master]
[also build test ERROR on v4.10-rc4 next-20170120]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Jingju-Hou/net-mvneta-implement-set_wol-and-get_wol/20170122-181651
config: xtensa-allmodconfig (attached as .config)
compiler: xtensa-linux-gcc (GCC) 4.9.0
reproduce:
wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=xtensa
All error/warnings (new ones prefixed by >>):
drivers/net/ethernet/marvell/mvneta.c: In function 'mvneta_ethtool_get_wol':
>> drivers/net/ethernet/marvell/mvneta.c:3940:8: error: 'struct mvneta_port' has no member named 'phy_dev'
if (pp->phy_dev)
^
drivers/net/ethernet/marvell/mvneta.c:3941:32: error: 'struct mvneta_port' has no member named 'phy_dev'
return phy_ethtool_get_wol(pp->phy_dev, wol);
^
>> drivers/net/ethernet/marvell/mvneta.c:3941:3: warning: 'return' with a value, in function returning void
return phy_ethtool_get_wol(pp->phy_dev, wol);
^
drivers/net/ethernet/marvell/mvneta.c: In function 'mvneta_ethtool_set_wol':
drivers/net/ethernet/marvell/mvneta.c:3949:9: error: 'struct mvneta_port' has no member named 'phy_dev'
if (!pp->phy_dev)
^
drivers/net/ethernet/marvell/mvneta.c:3952:31: error: 'struct mvneta_port' has no member named 'phy_dev'
return phy_ethtool_set_wol(pp->phy_dev, wol);
^
>> drivers/net/ethernet/marvell/mvneta.c:3953:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
vim +3940 drivers/net/ethernet/marvell/mvneta.c
3934 {
3935 struct mvneta_port *pp = netdev_priv(dev);
3936
3937 wol->supported = 0;
3938 wol->wolopts = 0;
3939
> 3940 if (pp->phy_dev)
> 3941 return phy_ethtool_get_wol(pp->phy_dev, wol);
3942 }
3943
3944 static int
3945 mvneta_ethtool_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
3946 {
3947 struct mvneta_port *pp = netdev_priv(dev);
3948
> 3949 if (!pp->phy_dev)
3950 return -EOPNOTSUPP;
3951
3952 return phy_ethtool_set_wol(pp->phy_dev, wol);
> 3953 }
3954
3955 static const struct net_device_ops mvneta_netdev_ops = {
3956 .ndo_open = mvneta_open,
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 48135 bytes --]
^ permalink raw reply
* Re: [PATCH] net: mvneta: implement .set_wol and .get_wol
From: kbuild test robot @ 2017-01-22 11:21 UTC (permalink / raw)
To: Jingju Hou; +Cc: kbuild-all, davem, thomas.petazzoni, netdev, Jingju Hou
In-Reply-To: <1485079590-6392-1-git-send-email-houjingj@marvell.com>
[-- Attachment #1: Type: text/plain, Size: 2611 bytes --]
Hi Jingju,
[auto build test ERROR on net-next/master]
[also build test ERROR on v4.10-rc4 next-20170120]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Jingju-Hou/net-mvneta-implement-set_wol-and-get_wol/20170122-181651
config: sparc64-allmodconfig (attached as .config)
compiler: sparc64-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705
reproduce:
wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=sparc64
All errors (new ones prefixed by >>):
drivers/net/ethernet/marvell/mvneta.c: In function 'mvneta_ethtool_get_wol':
>> drivers/net/ethernet/marvell/mvneta.c:3940:8: error: 'struct mvneta_port' has no member named 'phy_dev'; did you mean 'phy_node'?
if (pp->phy_dev)
^~
drivers/net/ethernet/marvell/mvneta.c:3941:32: error: 'struct mvneta_port' has no member named 'phy_dev'; did you mean 'phy_node'?
return phy_ethtool_get_wol(pp->phy_dev, wol);
^~
drivers/net/ethernet/marvell/mvneta.c:3941:10: warning: 'return' with a value, in function returning void
return phy_ethtool_get_wol(pp->phy_dev, wol);
^~~~~~~~~~~~~~~~~~~
drivers/net/ethernet/marvell/mvneta.c:3933:1: note: declared here
mvneta_ethtool_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
^~~~~~~~~~~~~~~~~~~~~~
drivers/net/ethernet/marvell/mvneta.c: In function 'mvneta_ethtool_set_wol':
drivers/net/ethernet/marvell/mvneta.c:3949:9: error: 'struct mvneta_port' has no member named 'phy_dev'; did you mean 'phy_node'?
if (!pp->phy_dev)
^~
drivers/net/ethernet/marvell/mvneta.c:3952:31: error: 'struct mvneta_port' has no member named 'phy_dev'; did you mean 'phy_node'?
return phy_ethtool_set_wol(pp->phy_dev, wol);
^~
drivers/net/ethernet/marvell/mvneta.c:3953:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
vim +3940 drivers/net/ethernet/marvell/mvneta.c
3934 {
3935 struct mvneta_port *pp = netdev_priv(dev);
3936
3937 wol->supported = 0;
3938 wol->wolopts = 0;
3939
> 3940 if (pp->phy_dev)
3941 return phy_ethtool_get_wol(pp->phy_dev, wol);
3942 }
3943
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 48616 bytes --]
^ permalink raw reply
* Re: [RFC PATCH net-next 2/5] vxlan: make COLLECT_METADATA mode bridge friendly
From: Nikolay Aleksandrov @ 2017-01-22 11:40 UTC (permalink / raw)
To: Roopa Prabhu, netdev
Cc: davem, stephen, tgraf, hannes, jbenc, pshelar, dsa, hadi
In-Reply-To: <1484977616-1541-3-git-send-email-roopa@cumulusnetworks.com>
On 21/01/17 06:46, Roopa Prabhu wrote:
> From: Roopa Prabhu <roopa@cumulusnetworks.com>
>
> This patch series makes vxlan COLLECT_METADATA mode bridge
> and layer2 network friendly. Vxlan COLLECT_METADATA mode today
> solves the per-vni netdev scalability problem in l3 networks.
> When vxlan collect metadata device participates in bridging
> vlan to vn-segments, It can only get the vlan mapped vni in
> the xmit tunnel dst metadata. It will need the vxlan driver to
> continue learn, hold forwarding state and remote destination
> information similar to how it already does for non COLLECT_METADATA
> vxlan netdevices today.
>
> Changes introduced by this patch:
> - allow learning and forwarding database state to vxlan netdev in
> COLLECT_METADATA mode. Current behaviour is not changed
> by default. tunnel info flag IP_TUNNEL_INFO_BRIDGE is used
> to support the new bridge friendly mode.
> - A single fdb table hashed by (mac, vni) to allow fdb entries with
> multiple vnis in the same fdb table
> - rx path already has the vni
> - tx path expects a vni in the packet with dst_metadata
> - prior to this series, fdb remote_dsts carried remote vni and
> the vxlan device carrying the fdb table represented the
> source vni. With the vxlan device now representing multiple vnis,
> this patch adds a src vni attribute to the fdb entry. The remote
> vni already uses NDA_VNI attribute. This patch introduces
> NDA_SRC_VNI netlink attribute to represent the src vni in a multi
> vni fdb table.
>
> Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com>
> ---
[snip]
> @@ -2173,23 +2221,29 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
> bool did_rsc = false;
> struct vxlan_rdst *rdst, *fdst = NULL;
> struct vxlan_fdb *f;
> + __be32 vni = 0;
>
> info = skb_tunnel_info(skb);
>
> skb_reset_mac_header(skb);
>
> if (vxlan->flags & VXLAN_F_COLLECT_METADATA) {
> - if (info && info->mode & IP_TUNNEL_INFO_TX)
> - vxlan_xmit_one(skb, dev, NULL, false);
> - else
> - kfree_skb(skb);
> - return NETDEV_TX_OK;
> + if (info && info->mode & IP_TUNNEL_INFO_BRIDGE &&
> + info->mode & IP_TUNNEL_INFO_TX) {
nit: parentheses around the IP_TUNNEL_INFO_TX check
> + vni = tunnel_id_to_key32(info->key.tun_id);
> + } else {
> + if (info && info->mode & IP_TUNNEL_INFO_TX)
nit: parentheses around the IP_TUNNEL_INFO_TX check
> + vxlan_xmit_one(skb, dev, vni, NULL, false);
> + else
> + kfree_skb(skb);
> + return NETDEV_TX_OK;
> + }
> }
>
> if (vxlan->flags & VXLAN_F_PROXY) {
> eth = eth_hdr(skb);
> if (ntohs(eth->h_proto) == ETH_P_ARP)
> - return arp_reduce(dev, skb);
> + return arp_reduce(dev, skb, vni);
> #if IS_ENABLED(CONFIG_IPV6)
> else if (ntohs(eth->h_proto) == ETH_P_IPV6 &&
> pskb_may_pull(skb, sizeof(struct ipv6hdr)
> @@ -2200,13 +2254,13 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
> msg = (struct nd_msg *)skb_transport_header(skb);
> if (msg->icmph.icmp6_code == 0 &&
> msg->icmph.icmp6_type == NDISC_NEIGHBOUR_SOLICITATION)
> - return neigh_reduce(dev, skb);
> + return neigh_reduce(dev, skb, vni);
> }
> #endif
> }
>
> eth = eth_hdr(skb);
> - f = vxlan_find_mac(vxlan, eth->h_dest);
> + f = vxlan_find_mac(vxlan, eth->h_dest, vni);
> did_rsc = false;
>
> if (f && (f->flags & NTF_ROUTER) && (vxlan->flags & VXLAN_F_RSC) &&
> @@ -2214,11 +2268,11 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
> ntohs(eth->h_proto) == ETH_P_IPV6)) {
> did_rsc = route_shortcircuit(dev, skb);
> if (did_rsc)
> - f = vxlan_find_mac(vxlan, eth->h_dest);
> + f = vxlan_find_mac(vxlan, eth->h_dest, vni);
> }
>
> if (f == NULL) {
> - f = vxlan_find_mac(vxlan, all_zeros_mac);
> + f = vxlan_find_mac(vxlan, all_zeros_mac, vni);
> if (f == NULL) {
> if ((vxlan->flags & VXLAN_F_L2MISS) &&
> !is_multicast_ether_addr(eth->h_dest))
> @@ -2239,11 +2293,11 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
> }
> skb1 = skb_clone(skb, GFP_ATOMIC);
> if (skb1)
> - vxlan_xmit_one(skb1, dev, rdst, did_rsc);
> + vxlan_xmit_one(skb1, dev, vni, rdst, did_rsc);
> }
>
> if (fdst)
> - vxlan_xmit_one(skb, dev, fdst, did_rsc);
> + vxlan_xmit_one(skb, dev, vni, fdst, did_rsc);
> else
> kfree_skb(skb);
> return NETDEV_TX_OK;
> @@ -2307,12 +2361,12 @@ static int vxlan_init(struct net_device *dev)
> return 0;
> }
>
> -static void vxlan_fdb_delete_default(struct vxlan_dev *vxlan)
> +static void vxlan_fdb_delete_default(struct vxlan_dev *vxlan, __be32 vni)
> {
> struct vxlan_fdb *f;
>
> spin_lock_bh(&vxlan->hash_lock);
> - f = __vxlan_find_mac(vxlan, all_zeros_mac);
> + f = __vxlan_find_mac(vxlan, all_zeros_mac, vni);
> if (f)
> vxlan_fdb_destroy(vxlan, f);
> spin_unlock_bh(&vxlan->hash_lock);
> @@ -2322,7 +2376,7 @@ static void vxlan_uninit(struct net_device *dev)
> {
> struct vxlan_dev *vxlan = netdev_priv(dev);
>
> - vxlan_fdb_delete_default(vxlan);
> + vxlan_fdb_delete_default(vxlan, vxlan->cfg.vni);
>
> free_percpu(dev->tstats);
> }
> @@ -2536,6 +2590,8 @@ static void vxlan_setup(struct net_device *dev)
> dev->vlan_features = dev->features;
> dev->hw_features |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_RXCSUM;
> dev->hw_features |= NETIF_F_GSO_SOFTWARE;
> + dev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX;
> + dev->features |= dev->hw_features;
> netif_keep_dst(dev);
> dev->priv_flags |= IFF_NO_QUEUE;
>
> @@ -2921,6 +2977,7 @@ static int vxlan_dev_configure(struct net *src_net, struct net_device *dev,
> NLM_F_EXCL|NLM_F_CREATE,
> vxlan->cfg.dst_port,
> vxlan->default_dst.remote_vni,
> + vxlan->default_dst.remote_vni,
> vxlan->default_dst.remote_ifindex,
> NTF_SELF);
> if (err)
> @@ -2929,7 +2986,7 @@ static int vxlan_dev_configure(struct net *src_net, struct net_device *dev,
>
> err = register_netdevice(dev);
> if (err) {
> - vxlan_fdb_delete_default(vxlan);
> + vxlan_fdb_delete_default(vxlan, vxlan->cfg.vni);
> return err;
> }
>
> @@ -3023,19 +3080,19 @@ static int vxlan_newlink(struct net *src_net, struct net_device *dev,
> conf.flags |= VXLAN_F_UDP_ZERO_CSUM_TX;
>
> if (data[IFLA_VXLAN_UDP_ZERO_CSUM6_TX] &&
> - nla_get_u8(data[IFLA_VXLAN_UDP_ZERO_CSUM6_TX]))
> + !nla_get_u8(data[IFLA_VXLAN_UDP_ZERO_CSUM6_TX]))
> conf.flags |= VXLAN_F_UDP_ZERO_CSUM6_TX;
>
> if (data[IFLA_VXLAN_UDP_ZERO_CSUM6_RX] &&
> - nla_get_u8(data[IFLA_VXLAN_UDP_ZERO_CSUM6_RX]))
> + !nla_get_u8(data[IFLA_VXLAN_UDP_ZERO_CSUM6_RX]))
> conf.flags |= VXLAN_F_UDP_ZERO_CSUM6_RX;
>
> if (data[IFLA_VXLAN_REMCSUM_TX] &&
> - nla_get_u8(data[IFLA_VXLAN_REMCSUM_TX]))
> + !nla_get_u8(data[IFLA_VXLAN_REMCSUM_TX]))
> conf.flags |= VXLAN_F_REMCSUM_TX;
>
> if (data[IFLA_VXLAN_REMCSUM_RX] &&
> - nla_get_u8(data[IFLA_VXLAN_REMCSUM_RX]))
> + !nla_get_u8(data[IFLA_VXLAN_REMCSUM_RX]))
> conf.flags |= VXLAN_F_REMCSUM_RX;
Aren't these going to break user-space ?
>
> if (data[IFLA_VXLAN_GBP])
> diff --git a/include/uapi/linux/neighbour.h b/include/uapi/linux/neighbour.h
> index bd99a8d..f3d16db 100644
> --- a/include/uapi/linux/neighbour.h
> +++ b/include/uapi/linux/neighbour.h
> @@ -26,6 +26,7 @@ enum {
> NDA_IFINDEX,
> NDA_MASTER,
> NDA_LINK_NETNSID,
> + NDA_SRC_VNI,
> __NDA_MAX
> };
>
>
^ permalink raw reply
* [patch net-next 0/4] Add support for offloading packet-sampling
From: Jiri Pirko @ 2017-01-22 11:44 UTC (permalink / raw)
To: netdev
Cc: davem, yotamg, idosch, eladr, nogahf, ogerlitz, jhs,
geert+renesas, stephen, xiyou.wangcong, linux, roopa,
john.fastabend, simon.horman, mrv
From: Jiri Pirko <jiri@mellanox.com>
Yotam says:
The first patch introduces the psample module, a netlink channel dedicated
to packet sampling implemented using generic netlink. This module provides
a generic way for kernel modules to sample packets, while not being tied
to any specific subsystem like NFLOG.
The second patch adds the sample tc action, which uses psample to randomly
sample packets that match a classifier. The user can configure the psample
group number, the sampling rate and the packet's truncation (to save
kernel-user traffic).
The last two patches add the support for offloading the matchall-sample
tc command in the mlxsw driver, for ingress qdiscs.
An example for psample usage can be found in the libpsample project at:
https://github.com/Mellanox/libpsample
Yotam Gigi (4):
net: Introduce psample, a new genetlink channel for packet sampling
net/sched: Introduce sample tc action
mlxsw: reg: add the Monitoring Packet Sampling Configuration Register
mlxsw: spectrum: Add packet sample offloading support
MAINTAINERS | 7 +
drivers/net/ethernet/mellanox/mlxsw/reg.h | 41 ++++
drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 111 +++++++++
drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 10 +
drivers/net/ethernet/mellanox/mlxsw/trap.h | 1 +
include/net/psample.h | 36 +++
include/net/tc_act/tc_sample.h | 50 ++++
include/uapi/linux/Kbuild | 1 +
include/uapi/linux/psample.h | 35 +++
include/uapi/linux/tc_act/Kbuild | 1 +
include/uapi/linux/tc_act/tc_sample.h | 26 +++
net/Kconfig | 1 +
net/Makefile | 1 +
net/psample/Kconfig | 15 ++
net/psample/Makefile | 5 +
net/psample/psample.c | 301 +++++++++++++++++++++++++
net/sched/Kconfig | 12 +
net/sched/Makefile | 1 +
net/sched/act_sample.c | 274 ++++++++++++++++++++++
19 files changed, 929 insertions(+)
create mode 100644 include/net/psample.h
create mode 100644 include/net/tc_act/tc_sample.h
create mode 100644 include/uapi/linux/psample.h
create mode 100644 include/uapi/linux/tc_act/tc_sample.h
create mode 100644 net/psample/Kconfig
create mode 100644 net/psample/Makefile
create mode 100644 net/psample/psample.c
create mode 100644 net/sched/act_sample.c
--
2.7.4
^ permalink raw reply
* [patch net-next 1/4] net: Introduce psample, a new genetlink channel for packet sampling
From: Jiri Pirko @ 2017-01-22 11:44 UTC (permalink / raw)
To: netdev
Cc: davem, yotamg, idosch, eladr, nogahf, ogerlitz, jhs,
geert+renesas, stephen, xiyou.wangcong, linux, roopa,
john.fastabend, simon.horman, mrv
In-Reply-To: <1485085487-2652-1-git-send-email-jiri@resnulli.us>
From: Yotam Gigi <yotamg@mellanox.com>
Add a general way for kernel modules to sample packets, without being tied
to any specific subsystem. This netlink channel can be used by tc,
iptables, etc. and allow to standardize packet sampling in the kernel.
For every sampled packet, the psample module adds the following metadata
fields:
PSAMPLE_ATTR_IIFINDEX - the packets input ifindex, if applicable
PSAMPLE_ATTR_OIFINDEX - the packet output ifindex, if applicable
PSAMPLE_ATTR_ORIGSIZE - the packet's original size, in case it has been
truncated during sampling
PSAMPLE_ATTR_SAMPLE_GROUP - the packet's sample group, which is set by the
user who initiated the sampling. This field allows the user to
differentiate between several samplers working simultaneously and
filter packets relevant to him
PSAMPLE_ATTR_GROUP_SEQ - sequence counter of last sent packet. The
sequence is kept for each group
PSAMPLE_ATTR_SAMPLE_RATE - the sampling rate used for sampling the packets
PSAMPLE_ATTR_DATA - the actual packet bits
In addition, add the GET_GROUPS netlink command which allows the user to
see the current sample groups, their refcount and sequence number. This
command currently supports only netlink dump mode.
Signed-off-by: Yotam Gigi <yotamg@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
MAINTAINERS | 7 +
include/net/psample.h | 36 ++++++
include/uapi/linux/Kbuild | 1 +
include/uapi/linux/psample.h | 35 +++++
net/Kconfig | 1 +
net/Makefile | 1 +
net/psample/Kconfig | 15 +++
net/psample/Makefile | 5 +
net/psample/psample.c | 301 +++++++++++++++++++++++++++++++++++++++++++
9 files changed, 402 insertions(+)
create mode 100644 include/net/psample.h
create mode 100644 include/uapi/linux/psample.h
create mode 100644 net/psample/Kconfig
create mode 100644 net/psample/Makefile
create mode 100644 net/psample/psample.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 3c84a8f..d76fccd 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9957,6 +9957,13 @@ L: linuxppc-dev@lists.ozlabs.org
S: Maintained
F: drivers/block/ps3vram.c
+PSAMPLE PACKET SAMPLING SUPPORT:
+M: Yotam Gigi <yotamg@mellanox.com>
+S: Maintained
+F: net/psample
+F: include/net/psample.h
+F: include/uapi/linux/psample.h
+
PSTORE FILESYSTEM
M: Anton Vorontsov <anton@enomsg.org>
M: Colin Cross <ccross@android.com>
diff --git a/include/net/psample.h b/include/net/psample.h
new file mode 100644
index 0000000..8888b0e
--- /dev/null
+++ b/include/net/psample.h
@@ -0,0 +1,36 @@
+#ifndef __NET_PSAMPLE_H
+#define __NET_PSAMPLE_H
+
+#include <uapi/linux/psample.h>
+#include <linux/module.h>
+#include <linux/list.h>
+
+struct psample_group {
+ struct list_head list;
+ struct net *net;
+ u32 group_num;
+ u32 refcount;
+ u32 seq;
+};
+
+struct psample_group *psample_group_get(struct net *net, u32 group_num);
+void psample_group_put(struct psample_group *group);
+
+#if IS_ENABLED(CONFIG_PSAMPLE)
+
+void psample_sample_packet(struct psample_group *group, struct sk_buff *skb,
+ u32 trunc_size, int in_ifindex, int out_ifindex,
+ u32 sample_rate);
+
+#else
+
+static inline void psample_sample_packet(struct psample_group *group,
+ struct sk_buff *skb, u32 trunc_size,
+ int in_ifindex, int out_ifindex,
+ u32 sample_rate)
+{
+}
+
+#endif
+
+#endif /* __NET_PSAMPLE_H */
diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
index e600b50..80ad741 100644
--- a/include/uapi/linux/Kbuild
+++ b/include/uapi/linux/Kbuild
@@ -305,6 +305,7 @@ header-y += netrom.h
header-y += net_namespace.h
header-y += net_tstamp.h
header-y += nfc.h
+header-y += psample.h
header-y += nfs2.h
header-y += nfs3.h
header-y += nfs4.h
diff --git a/include/uapi/linux/psample.h b/include/uapi/linux/psample.h
new file mode 100644
index 0000000..ed48996
--- /dev/null
+++ b/include/uapi/linux/psample.h
@@ -0,0 +1,35 @@
+#ifndef __UAPI_PSAMPLE_H
+#define __UAPI_PSAMPLE_H
+
+enum {
+ /* sampled packet metadata */
+ PSAMPLE_ATTR_IIFINDEX,
+ PSAMPLE_ATTR_OIFINDEX,
+ PSAMPLE_ATTR_ORIGSIZE,
+ PSAMPLE_ATTR_SAMPLE_GROUP,
+ PSAMPLE_ATTR_GROUP_SEQ,
+ PSAMPLE_ATTR_SAMPLE_RATE,
+ PSAMPLE_ATTR_DATA,
+
+ /* commands attributes */
+ PSAMPLE_ATTR_GROUP_REFCOUNT,
+
+ __PSAMPLE_ATTR_MAX
+};
+
+enum psample_command {
+ PSAMPLE_CMD_SAMPLE,
+ PSAMPLE_CMD_GET_GROUP,
+ PSAMPLE_CMD_NEW_GROUP,
+ PSAMPLE_CMD_DEL_GROUP,
+};
+
+/* Can be overridden at runtime by module option */
+#define PSAMPLE_ATTR_MAX (__PSAMPLE_ATTR_MAX - 1)
+
+#define PSAMPLE_NL_MCGRP_CONFIG_NAME "config"
+#define PSAMPLE_NL_MCGRP_SAMPLE_NAME "packets"
+#define PSAMPLE_GENL_NAME "psample"
+#define PSAMPLE_GENL_VERSION 1
+
+#endif
diff --git a/net/Kconfig b/net/Kconfig
index 92ae150..ce4aee6 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -390,6 +390,7 @@ source "net/9p/Kconfig"
source "net/caif/Kconfig"
source "net/ceph/Kconfig"
source "net/nfc/Kconfig"
+source "net/psample/Kconfig"
config LWTUNNEL
bool "Network light weight tunnels"
diff --git a/net/Makefile b/net/Makefile
index 5d6e0e5f..7d41de4 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -70,6 +70,7 @@ obj-$(CONFIG_DNS_RESOLVER) += dns_resolver/
obj-$(CONFIG_CEPH_LIB) += ceph/
obj-$(CONFIG_BATMAN_ADV) += batman-adv/
obj-$(CONFIG_NFC) += nfc/
+obj-$(CONFIG_PSAMPLE) += psample/
obj-$(CONFIG_OPENVSWITCH) += openvswitch/
obj-$(CONFIG_VSOCKETS) += vmw_vsock/
obj-$(CONFIG_MPLS) += mpls/
diff --git a/net/psample/Kconfig b/net/psample/Kconfig
new file mode 100644
index 0000000..d850246
--- /dev/null
+++ b/net/psample/Kconfig
@@ -0,0 +1,15 @@
+#
+# psample packet sampling configuration
+#
+
+menuconfig PSAMPLE
+ depends on NET
+ tristate "Packet-sampling netlink channel"
+ default n
+ help
+ Say Y here to add support for packet-sampling netlink channel
+ This netlink channel allows transferring packets alongside some
+ metadata to userspace.
+
+ To compile this support as a module, choose M here: the module will
+ be called psample.
diff --git a/net/psample/Makefile b/net/psample/Makefile
new file mode 100644
index 0000000..609b0a7
--- /dev/null
+++ b/net/psample/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the psample netlink channel
+#
+
+obj-$(CONFIG_PSAMPLE) += psample.o
diff --git a/net/psample/psample.c b/net/psample/psample.c
new file mode 100644
index 0000000..8aa58a9
--- /dev/null
+++ b/net/psample/psample.c
@@ -0,0 +1,301 @@
+/*
+ * net/psample/psample.c - Netlink channel for packet sampling
+ * Copyright (c) 2017 Yotam Gigi <yotamg@mellanox.com>
+ *
+ * This program 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.
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/module.h>
+#include <net/net_namespace.h>
+#include <net/sock.h>
+#include <net/netlink.h>
+#include <net/genetlink.h>
+#include <net/psample.h>
+#include <linux/spinlock.h>
+
+#define PSAMPLE_MAX_PACKET_SIZE 0xffff
+
+static LIST_HEAD(psample_groups_list);
+static DEFINE_SPINLOCK(psample_groups_lock);
+
+/* multicast groups */
+enum psample_nl_multicast_groups {
+ PSAMPLE_NL_MCGRP_CONFIG,
+ PSAMPLE_NL_MCGRP_SAMPLE,
+};
+
+static const struct genl_multicast_group psample_nl_mcgrps[] = {
+ [PSAMPLE_NL_MCGRP_CONFIG] = { .name = PSAMPLE_NL_MCGRP_CONFIG_NAME },
+ [PSAMPLE_NL_MCGRP_SAMPLE] = { .name = PSAMPLE_NL_MCGRP_SAMPLE_NAME },
+};
+
+static struct genl_family psample_nl_family __ro_after_init;
+
+static int psample_group_nl_fill(struct sk_buff *msg,
+ struct psample_group *group,
+ enum psample_command cmd, u32 portid, u32 seq,
+ int flags)
+{
+ void *hdr;
+ int ret;
+
+ hdr = genlmsg_put(msg, portid, seq, &psample_nl_family, flags, cmd);
+ if (!hdr)
+ return -EMSGSIZE;
+
+ ret = nla_put_u32(msg, PSAMPLE_ATTR_SAMPLE_GROUP, group->group_num);
+ if (ret < 0)
+ goto error;
+
+ ret = nla_put_u32(msg, PSAMPLE_ATTR_GROUP_REFCOUNT, group->refcount);
+ if (ret < 0)
+ goto error;
+
+ ret = nla_put_u32(msg, PSAMPLE_ATTR_GROUP_SEQ, group->seq);
+ if (ret < 0)
+ goto error;
+
+ genlmsg_end(msg, hdr);
+ return 0;
+
+error:
+ genlmsg_cancel(msg, hdr);
+ return -EMSGSIZE;
+}
+
+static int psample_nl_cmd_get_group_dumpit(struct sk_buff *msg,
+ struct netlink_callback *cb)
+{
+ struct psample_group *group;
+ int start = cb->args[0];
+ int idx = 0;
+ int err;
+
+ spin_lock(&psample_groups_lock);
+ list_for_each_entry(group, &psample_groups_list, list) {
+ if (!net_eq(group->net, sock_net(msg->sk)))
+ continue;
+ if (idx < start) {
+ idx++;
+ continue;
+ }
+ err = psample_group_nl_fill(msg, group, PSAMPLE_CMD_NEW_GROUP,
+ NETLINK_CB(cb->skb).portid,
+ cb->nlh->nlmsg_seq, NLM_F_MULTI);
+ if (err)
+ break;
+ idx++;
+ }
+
+ spin_unlock(&psample_groups_lock);
+ cb->args[0] = idx;
+ return msg->len;
+}
+
+static const struct genl_ops psample_nl_ops[] = {
+ {
+ .cmd = PSAMPLE_CMD_GET_GROUP,
+ .dumpit = psample_nl_cmd_get_group_dumpit,
+ /* can be retrieved by unprivileged users */
+ }
+};
+
+static struct genl_family psample_nl_family __ro_after_init = {
+ .name = PSAMPLE_GENL_NAME,
+ .version = PSAMPLE_GENL_VERSION,
+ .maxattr = PSAMPLE_ATTR_MAX,
+ .netnsok = true,
+ .module = THIS_MODULE,
+ .mcgrps = psample_nl_mcgrps,
+ .ops = psample_nl_ops,
+ .n_ops = ARRAY_SIZE(psample_nl_ops),
+ .n_mcgrps = ARRAY_SIZE(psample_nl_mcgrps),
+};
+
+static void psample_group_notify(struct psample_group *group,
+ enum psample_command cmd)
+{
+ struct sk_buff *msg;
+ int err;
+
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
+ if (!msg)
+ return;
+
+ err = psample_group_nl_fill(msg, group, cmd, 0, 0, NLM_F_MULTI);
+ if (!err)
+ genlmsg_multicast_netns(&psample_nl_family, group->net, msg, 0,
+ PSAMPLE_NL_MCGRP_CONFIG, GFP_ATOMIC);
+ else
+ nlmsg_free(msg);
+}
+
+static struct psample_group *psample_group_create(struct net *net,
+ u32 group_num)
+{
+ struct psample_group *group;
+
+ group = kzalloc(sizeof(*group), GFP_ATOMIC);
+ if (!group)
+ return NULL;
+
+ group->net = net;
+ group->group_num = group_num;
+ list_add_tail(&group->list, &psample_groups_list);
+
+ psample_group_notify(group, PSAMPLE_CMD_NEW_GROUP);
+ return group;
+}
+
+static void psample_group_destroy(struct psample_group *group)
+{
+ psample_group_notify(group, PSAMPLE_CMD_DEL_GROUP);
+ list_del(&group->list);
+ kfree(group);
+}
+
+static struct psample_group *
+psample_group_lookup(struct net *net, u32 group_num)
+{
+ struct psample_group *group;
+
+ list_for_each_entry(group, &psample_groups_list, list)
+ if ((group->group_num == group_num) && (group->net == net))
+ return group;
+ return NULL;
+}
+
+struct psample_group *psample_group_get(struct net *net, u32 group_num)
+{
+ struct psample_group *group;
+
+ spin_lock(&psample_groups_lock);
+
+ group = psample_group_lookup(net, group_num);
+ if (!group) {
+ group = psample_group_create(net, group_num);
+ if (!group)
+ goto out;
+ }
+ group->refcount++;
+
+out:
+ spin_unlock(&psample_groups_lock);
+ return group;
+}
+EXPORT_SYMBOL_GPL(psample_group_get);
+
+void psample_group_put(struct psample_group *group)
+{
+ spin_lock(&psample_groups_lock);
+
+ if (--group->refcount == 0)
+ psample_group_destroy(group);
+
+ spin_unlock(&psample_groups_lock);
+}
+EXPORT_SYMBOL_GPL(psample_group_put);
+
+void psample_sample_packet(struct psample_group *group, struct sk_buff *skb,
+ u32 trunc_size, int in_ifindex, int out_ifindex,
+ u32 sample_rate)
+{
+ struct sk_buff *nl_skb;
+ int data_len;
+ int meta_len;
+ void *data;
+ int ret;
+
+ meta_len = (in_ifindex ? nla_total_size(sizeof(u16)) : 0) +
+ (out_ifindex ? nla_total_size(sizeof(u16)) : 0) +
+ nla_total_size(sizeof(u32)) + /* sample_rate */
+ nla_total_size(sizeof(u32)) + /* orig_size */
+ nla_total_size(sizeof(u32)) + /* group_num */
+ nla_total_size(sizeof(u32)); /* seq */
+
+ data_len = min(skb->len, trunc_size);
+ if (meta_len + nla_total_size(data_len) > PSAMPLE_MAX_PACKET_SIZE)
+ data_len = PSAMPLE_MAX_PACKET_SIZE - meta_len - NLA_HDRLEN
+ - NLA_ALIGNTO;
+
+ nl_skb = genlmsg_new(meta_len + data_len, GFP_ATOMIC);
+ if (unlikely(!nl_skb))
+ return;
+
+ data = genlmsg_put(nl_skb, 0, 0, &psample_nl_family, 0,
+ PSAMPLE_CMD_SAMPLE);
+ if (unlikely(!data))
+ goto error;
+
+ if (in_ifindex) {
+ ret = nla_put_u16(nl_skb, PSAMPLE_ATTR_IIFINDEX, in_ifindex);
+ if (unlikely(ret < 0))
+ goto error;
+ }
+
+ if (out_ifindex) {
+ ret = nla_put_u16(nl_skb, PSAMPLE_ATTR_OIFINDEX, out_ifindex);
+ if (unlikely(ret < 0))
+ goto error;
+ }
+
+ ret = nla_put_u32(nl_skb, PSAMPLE_ATTR_SAMPLE_RATE, sample_rate);
+ if (unlikely(ret < 0))
+ goto error;
+
+ ret = nla_put_u32(nl_skb, PSAMPLE_ATTR_ORIGSIZE, skb->len);
+ if (unlikely(ret < 0))
+ goto error;
+
+ ret = nla_put_u32(nl_skb, PSAMPLE_ATTR_SAMPLE_GROUP, group->group_num);
+ if (unlikely(ret < 0))
+ goto error;
+
+ ret = nla_put_u32(nl_skb, PSAMPLE_ATTR_GROUP_SEQ, group->seq++);
+ if (unlikely(ret < 0))
+ goto error;
+
+ if (data_len) {
+ int nla_len = nla_total_size(data_len);
+ struct nlattr *nla;
+
+ nla = (struct nlattr *)skb_put(nl_skb, nla_len);
+ nla->nla_type = PSAMPLE_ATTR_DATA;
+ nla->nla_len = nla_attr_size(data_len);
+
+ if (skb_copy_bits(skb, 0, nla_data(nla), data_len))
+ goto error;
+ }
+
+ genlmsg_end(nl_skb, data);
+ genlmsg_multicast_netns(&psample_nl_family, group->net, nl_skb, 0,
+ PSAMPLE_NL_MCGRP_SAMPLE, GFP_ATOMIC);
+
+ return;
+error:
+ pr_err_ratelimited("Could not create psample log message\n");
+ nlmsg_free(nl_skb);
+}
+EXPORT_SYMBOL_GPL(psample_sample_packet);
+
+static int __init psample_module_init(void)
+{
+ return genl_register_family(&psample_nl_family);
+}
+
+static void __exit psample_module_exit(void)
+{
+ genl_unregister_family(&psample_nl_family);
+}
+
+module_init(psample_module_init);
+module_exit(psample_module_exit);
+
+MODULE_AUTHOR("Yotam Gigi <yotamg@mellanox.com>");
+MODULE_DESCRIPTION("netlink channel for packet sampling");
+MODULE_LICENSE("GPL v2");
--
2.7.4
^ permalink raw reply related
* [patch net-next 2/4] net/sched: Introduce sample tc action
From: Jiri Pirko @ 2017-01-22 11:44 UTC (permalink / raw)
To: netdev
Cc: davem, yotamg, idosch, eladr, nogahf, ogerlitz, jhs,
geert+renesas, stephen, xiyou.wangcong, linux, roopa,
john.fastabend, simon.horman, mrv
In-Reply-To: <1485085487-2652-1-git-send-email-jiri@resnulli.us>
From: Yotam Gigi <yotamg@mellanox.com>
This action allows the user to sample traffic matched by tc classifier.
The sampling consists of choosing packets randomly and sampling them using
the psample module. The user can configure the psample group number, the
sampling rate and the packet's truncation (to save kernel-user traffic).
Example:
To sample ingress traffic from interface eth1, one may use the commands:
tc qdisc add dev eth1 handle ffff: ingress
tc filter add dev eth1 parent ffff: \
matchall action sample rate 12 group 4
Where the first command adds an ingress qdisc and the second starts
sampling randomly with an average of one sampled packet per 12 packets on
dev eth1 to psample group 4.
Signed-off-by: Yotam Gigi <yotamg@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
include/net/tc_act/tc_sample.h | 50 +++++++
include/uapi/linux/tc_act/Kbuild | 1 +
include/uapi/linux/tc_act/tc_sample.h | 26 ++++
net/sched/Kconfig | 12 ++
net/sched/Makefile | 1 +
net/sched/act_sample.c | 274 ++++++++++++++++++++++++++++++++++
6 files changed, 364 insertions(+)
create mode 100644 include/net/tc_act/tc_sample.h
create mode 100644 include/uapi/linux/tc_act/tc_sample.h
create mode 100644 net/sched/act_sample.c
diff --git a/include/net/tc_act/tc_sample.h b/include/net/tc_act/tc_sample.h
new file mode 100644
index 0000000..89e9305
--- /dev/null
+++ b/include/net/tc_act/tc_sample.h
@@ -0,0 +1,50 @@
+#ifndef __NET_TC_SAMPLE_H
+#define __NET_TC_SAMPLE_H
+
+#include <net/act_api.h>
+#include <linux/tc_act/tc_sample.h>
+#include <net/psample.h>
+
+struct tcf_sample {
+ struct tc_action common;
+ u32 rate;
+ bool truncate;
+ u32 trunc_size;
+ struct psample_group __rcu *psample_group;
+ u32 psample_group_num;
+ struct list_head tcfm_list;
+ struct rcu_head rcu;
+};
+#define to_sample(a) ((struct tcf_sample *)a)
+
+static inline bool is_tcf_sample(const struct tc_action *a)
+{
+#ifdef CONFIG_NET_CLS_ACT
+ return a->ops && a->ops->type == TCA_ACT_SAMPLE;
+#else
+ return false;
+#endif
+}
+
+static inline __u32 tcf_sample_rate(const struct tc_action *a)
+{
+ return to_sample(a)->rate;
+}
+
+static inline bool tcf_sample_truncate(const struct tc_action *a)
+{
+ return to_sample(a)->truncate;
+}
+
+static inline int tcf_sample_trunc_size(const struct tc_action *a)
+{
+ return to_sample(a)->trunc_size;
+}
+
+static inline struct psample_group *
+tcf_sample_psample_group(const struct tc_action *a)
+{
+ return rcu_dereference(to_sample(a)->psample_group);
+}
+
+#endif /* __NET_TC_SAMPLE_H */
diff --git a/include/uapi/linux/tc_act/Kbuild b/include/uapi/linux/tc_act/Kbuild
index e3db740..ba62ddf 100644
--- a/include/uapi/linux/tc_act/Kbuild
+++ b/include/uapi/linux/tc_act/Kbuild
@@ -4,6 +4,7 @@ header-y += tc_defact.h
header-y += tc_gact.h
header-y += tc_ipt.h
header-y += tc_mirred.h
+header-y += tc_sample.h
header-y += tc_nat.h
header-y += tc_pedit.h
header-y += tc_skbedit.h
diff --git a/include/uapi/linux/tc_act/tc_sample.h b/include/uapi/linux/tc_act/tc_sample.h
new file mode 100644
index 0000000..21378bc
--- /dev/null
+++ b/include/uapi/linux/tc_act/tc_sample.h
@@ -0,0 +1,26 @@
+#ifndef __LINUX_TC_SAMPLE_H
+#define __LINUX_TC_SAMPLE_H
+
+#include <linux/types.h>
+#include <linux/pkt_cls.h>
+#include <linux/if_ether.h>
+
+#define TCA_ACT_SAMPLE 26
+
+struct tc_sample {
+ tc_gen;
+};
+
+enum {
+ TCA_SAMPLE_UNSPEC,
+ TCA_SAMPLE_PARMS,
+ TCA_SAMPLE_TM,
+ TCA_SAMPLE_RATE,
+ TCA_SAMPLE_TRUNC_SIZE,
+ TCA_SAMPLE_PSAMPLE_GROUP,
+ TCA_SAMPLE_PAD,
+ __TCA_SAMPLE_MAX
+};
+#define TCA_SAMPLE_MAX (__TCA_SAMPLE_MAX - 1)
+
+#endif
diff --git a/net/sched/Kconfig b/net/sched/Kconfig
index a9aa38d..72cfa3a 100644
--- a/net/sched/Kconfig
+++ b/net/sched/Kconfig
@@ -650,6 +650,18 @@ config NET_ACT_MIRRED
To compile this code as a module, choose M here: the
module will be called act_mirred.
+config NET_ACT_SAMPLE
+ tristate "Traffic Sampling"
+ depends on NET_CLS_ACT
+ select PSAMPLE
+ ---help---
+ Say Y here to allow packet sampling tc action. The packet sample
+ action consists of statistically choosing packets and sampling
+ them using the psample module.
+
+ To compile this code as a module, choose M here: the
+ module will be called act_sample.
+
config NET_ACT_IPT
tristate "IPtables targets"
depends on NET_CLS_ACT && NETFILTER && IP_NF_IPTABLES
diff --git a/net/sched/Makefile b/net/sched/Makefile
index 4bdda36..7b915d2 100644
--- a/net/sched/Makefile
+++ b/net/sched/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_NET_CLS_ACT) += act_api.o
obj-$(CONFIG_NET_ACT_POLICE) += act_police.o
obj-$(CONFIG_NET_ACT_GACT) += act_gact.o
obj-$(CONFIG_NET_ACT_MIRRED) += act_mirred.o
+obj-$(CONFIG_NET_ACT_SAMPLE) += act_sample.o
obj-$(CONFIG_NET_ACT_IPT) += act_ipt.o
obj-$(CONFIG_NET_ACT_NAT) += act_nat.o
obj-$(CONFIG_NET_ACT_PEDIT) += act_pedit.o
diff --git a/net/sched/act_sample.c b/net/sched/act_sample.c
new file mode 100644
index 0000000..24e20e4
--- /dev/null
+++ b/net/sched/act_sample.c
@@ -0,0 +1,274 @@
+/*
+ * net/sched/act_sample.c - Packet samplig tc action
+ * Copyright (c) 2017 Yotam Gigi <yotamg@mellanox.com>
+ *
+ * This program 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.
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/skbuff.h>
+#include <linux/rtnetlink.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/gfp.h>
+#include <net/net_namespace.h>
+#include <net/netlink.h>
+#include <net/pkt_sched.h>
+#include <linux/tc_act/tc_sample.h>
+#include <net/tc_act/tc_sample.h>
+#include <net/psample.h>
+
+#include <linux/if_arp.h>
+
+#define SAMPLE_TAB_MASK 7
+static unsigned int sample_net_id;
+static struct tc_action_ops act_sample_ops;
+
+static const struct nla_policy sample_policy[TCA_SAMPLE_MAX + 1] = {
+ [TCA_SAMPLE_PARMS] = { .len = sizeof(struct tc_sample) },
+ [TCA_SAMPLE_RATE] = { .type = NLA_U32 },
+ [TCA_SAMPLE_TRUNC_SIZE] = { .type = NLA_U32 },
+ [TCA_SAMPLE_PSAMPLE_GROUP] = { .type = NLA_U32 },
+};
+
+static int tcf_sample_init(struct net *net, struct nlattr *nla,
+ struct nlattr *est, struct tc_action **a, int ovr,
+ int bind)
+{
+ struct tc_action_net *tn = net_generic(net, sample_net_id);
+ struct nlattr *tb[TCA_SAMPLE_MAX + 1];
+ struct psample_group *psample_group;
+ struct tc_sample *parm;
+ struct tcf_sample *s;
+ bool exists = false;
+ int ret;
+
+ if (!nla)
+ return -EINVAL;
+ ret = nla_parse_nested(tb, TCA_SAMPLE_MAX, nla, sample_policy);
+ if (ret < 0)
+ return ret;
+ if (!tb[TCA_SAMPLE_PARMS] || !tb[TCA_SAMPLE_RATE] ||
+ !tb[TCA_SAMPLE_PSAMPLE_GROUP])
+ return -EINVAL;
+
+ parm = nla_data(tb[TCA_SAMPLE_PARMS]);
+
+ exists = tcf_hash_check(tn, parm->index, a, bind);
+ if (exists && bind)
+ return 0;
+
+ if (!exists) {
+ ret = tcf_hash_create(tn, parm->index, est, a,
+ &act_sample_ops, bind, false);
+ if (ret)
+ return ret;
+ ret = ACT_P_CREATED;
+ } else {
+ tcf_hash_release(*a, bind);
+ if (!ovr)
+ return -EEXIST;
+ }
+ s = to_sample(*a);
+
+ ASSERT_RTNL();
+ s->tcf_action = parm->action;
+ s->rate = nla_get_u32(tb[TCA_SAMPLE_RATE]);
+ s->psample_group_num = nla_get_u32(tb[TCA_SAMPLE_PSAMPLE_GROUP]);
+ psample_group = psample_group_get(net, s->psample_group_num);
+ if (!psample_group)
+ return -ENOMEM;
+ RCU_INIT_POINTER(s->psample_group, psample_group);
+
+ if (tb[TCA_SAMPLE_TRUNC_SIZE]) {
+ s->truncate = true;
+ s->trunc_size = nla_get_u32(tb[TCA_SAMPLE_TRUNC_SIZE]);
+ }
+
+ if (ret == ACT_P_CREATED)
+ tcf_hash_insert(tn, *a);
+ return ret;
+}
+
+static void tcf_sample_cleanup_rcu(struct rcu_head *rcu)
+{
+ struct tcf_sample *s = container_of(rcu, struct tcf_sample, rcu);
+ struct psample_group *psample_group;
+
+ psample_group = rcu_dereference_protected(s->psample_group, 1);
+ RCU_INIT_POINTER(s->psample_group, NULL);
+ psample_group_put(psample_group);
+}
+
+static void tcf_sample_cleanup(struct tc_action *a, int bind)
+{
+ struct tcf_sample *s = to_sample(a);
+
+ call_rcu(&s->rcu, tcf_sample_cleanup_rcu);
+}
+
+static bool tcf_sample_dev_ok_push(struct net_device *dev)
+{
+ switch (dev->type) {
+ case ARPHRD_TUNNEL:
+ case ARPHRD_TUNNEL6:
+ case ARPHRD_SIT:
+ case ARPHRD_IPGRE:
+ case ARPHRD_VOID:
+ case ARPHRD_NONE:
+ return false;
+ default:
+ return true;
+ }
+}
+
+static int tcf_sample(struct sk_buff *skb, const struct tc_action *a,
+ struct tcf_result *res)
+{
+ struct tcf_sample *s = to_sample(a);
+ struct psample_group *psample_group;
+ int retval;
+ int size;
+ int iif;
+ int oif;
+
+ tcf_lastuse_update(&s->tcf_tm);
+ bstats_cpu_update(this_cpu_ptr(s->common.cpu_bstats), skb);
+ retval = READ_ONCE(s->tcf_action);
+
+ rcu_read_lock();
+ psample_group = rcu_dereference(s->psample_group);
+
+ /* randomly sample packets according to rate */
+ if (psample_group && (prandom_u32() % s->rate == 0)) {
+ if (!skb_at_tc_ingress(skb)) {
+ iif = skb->skb_iif;
+ oif = skb->dev->ifindex;
+ } else {
+ iif = skb->dev->ifindex;
+ oif = 0;
+ }
+
+ /* on ingress, the mac header gets popped, so push it back */
+ if (skb_at_tc_ingress(skb) && tcf_sample_dev_ok_push(skb->dev))
+ skb_push(skb, skb->mac_len);
+
+ size = s->truncate ? s->trunc_size : skb->len;
+ psample_sample_packet(psample_group, skb, size, iif, oif,
+ s->rate);
+
+ if (skb_at_tc_ingress(skb) && tcf_sample_dev_ok_push(skb->dev))
+ skb_pull(skb, skb->mac_len);
+ }
+
+ rcu_read_unlock();
+ return retval;
+}
+
+static int tcf_sample_dump(struct sk_buff *skb, struct tc_action *a,
+ int bind, int ref)
+{
+ unsigned char *b = skb_tail_pointer(skb);
+ struct tcf_sample *s = to_sample(a);
+ struct tc_sample opt = {
+ .index = s->tcf_index,
+ .action = s->tcf_action,
+ .refcnt = s->tcf_refcnt - ref,
+ .bindcnt = s->tcf_bindcnt - bind,
+ };
+ struct tcf_t t;
+
+ if (nla_put(skb, TCA_SAMPLE_PARMS, sizeof(opt), &opt))
+ goto nla_put_failure;
+
+ tcf_tm_dump(&t, &s->tcf_tm);
+ if (nla_put_64bit(skb, TCA_SAMPLE_TM, sizeof(t), &t, TCA_SAMPLE_PAD))
+ goto nla_put_failure;
+
+ if (nla_put_u32(skb, TCA_SAMPLE_RATE, s->rate))
+ goto nla_put_failure;
+
+ if (s->truncate)
+ if (nla_put_u32(skb, TCA_SAMPLE_TRUNC_SIZE, s->trunc_size))
+ goto nla_put_failure;
+
+ if (nla_put_u32(skb, TCA_SAMPLE_PSAMPLE_GROUP, s->psample_group_num))
+ goto nla_put_failure;
+ return skb->len;
+
+nla_put_failure:
+ nlmsg_trim(skb, b);
+ return -1;
+}
+
+static int tcf_sample_walker(struct net *net, struct sk_buff *skb,
+ struct netlink_callback *cb, int type,
+ const struct tc_action_ops *ops)
+{
+ struct tc_action_net *tn = net_generic(net, sample_net_id);
+
+ return tcf_generic_walker(tn, skb, cb, type, ops);
+}
+
+static int tcf_sample_search(struct net *net, struct tc_action **a, u32 index)
+{
+ struct tc_action_net *tn = net_generic(net, sample_net_id);
+
+ return tcf_hash_search(tn, a, index);
+}
+
+static struct tc_action_ops act_sample_ops = {
+ .kind = "sample",
+ .type = TCA_ACT_SAMPLE,
+ .owner = THIS_MODULE,
+ .act = tcf_sample,
+ .dump = tcf_sample_dump,
+ .init = tcf_sample_init,
+ .cleanup = tcf_sample_cleanup,
+ .walk = tcf_sample_walker,
+ .lookup = tcf_sample_search,
+ .size = sizeof(struct tcf_sample),
+};
+
+static __net_init int sample_init_net(struct net *net)
+{
+ struct tc_action_net *tn = net_generic(net, sample_net_id);
+
+ return tc_action_net_init(tn, &act_sample_ops, SAMPLE_TAB_MASK);
+}
+
+static void __net_exit sample_exit_net(struct net *net)
+{
+ struct tc_action_net *tn = net_generic(net, sample_net_id);
+
+ tc_action_net_exit(tn);
+}
+
+static struct pernet_operations sample_net_ops = {
+ .init = sample_init_net,
+ .exit = sample_exit_net,
+ .id = &sample_net_id,
+ .size = sizeof(struct tc_action_net),
+};
+
+static int __init sample_init_module(void)
+{
+ return tcf_register_action(&act_sample_ops, &sample_net_ops);
+}
+
+static void __exit sample_cleanup_module(void)
+{
+ tcf_unregister_action(&act_sample_ops, &sample_net_ops);
+}
+
+module_init(sample_init_module);
+module_exit(sample_cleanup_module);
+
+MODULE_AUTHOR("Yotam Gigi <yotamg@mellanox.com>");
+MODULE_DESCRIPTION("Packet sampling action");
+MODULE_LICENSE("GPL v2");
--
2.7.4
^ permalink raw reply related
* [patch net-next 3/4] mlxsw: reg: add the Monitoring Packet Sampling Configuration Register
From: Jiri Pirko @ 2017-01-22 11:44 UTC (permalink / raw)
To: netdev
Cc: davem, yotamg, idosch, eladr, nogahf, ogerlitz, jhs,
geert+renesas, stephen, xiyou.wangcong, linux, roopa,
john.fastabend, simon.horman, mrv
In-Reply-To: <1485085487-2652-1-git-send-email-jiri@resnulli.us>
From: Yotam Gigi <yotamg@mellanox.com>
The MPSC register allows to configure ingress packet sampling on specific
port of the mlxsw device. The sampled packets are then trapped via
PKT_SAMPLE trap.
Signed-off-by: Yotam Gigi <yotamg@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Reviewed-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
drivers/net/ethernet/mellanox/mlxsw/reg.h | 41 +++++++++++++++++++++++++++++++
1 file changed, 41 insertions(+)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h
index 1357fe0..9fb0316 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h
@@ -4965,6 +4965,46 @@ static inline void mlxsw_reg_mlcr_pack(char *payload, u8 local_port,
MLXSW_REG_MLCR_DURATION_MAX : 0);
}
+/* MPSC - Monitoring Packet Sampling Configuration Register
+ * --------------------------------------------------------
+ * MPSC Register is used to configure the Packet Sampling mechanism.
+ */
+#define MLXSW_REG_MPSC_ID 0x9080
+#define MLXSW_REG_MPSC_LEN 0x1C
+
+MLXSW_REG_DEFINE(mpsc, MLXSW_REG_MPSC_ID, MLXSW_REG_MPSC_LEN);
+
+/* reg_mpsc_local_port
+ * Local port number
+ * Not supported for CPU port
+ * Access: Index
+ */
+MLXSW_ITEM32(reg, mpsc, local_port, 0x00, 16, 8);
+
+/* reg_mpsc_e
+ * Enable sampling on port local_port
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, mpsc, e, 0x04, 30, 1);
+
+#define MLXSW_REG_MPSC_RATE_MAX 3500000000UL
+
+/* reg_mpsc_rate
+ * Sampling rate = 1 out of rate packets (with randomization around
+ * the point). Valid values are: 1 to MLXSW_REG_MPSC_RATE_MAX
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, mpsc, rate, 0x08, 0, 32);
+
+static inline void mlxsw_reg_mpsc_pack(char *payload, u8 local_port, bool e,
+ u32 rate)
+{
+ MLXSW_REG_ZERO(mpsc, payload);
+ mlxsw_reg_mpsc_local_port_set(payload, local_port);
+ mlxsw_reg_mpsc_e_set(payload, e);
+ mlxsw_reg_mpsc_rate_set(payload, rate);
+}
+
/* SBPR - Shared Buffer Pools Register
* -----------------------------------
* The SBPR configures and retrieves the shared buffer pools and configuration.
@@ -5429,6 +5469,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = {
MLXSW_REG(mpat),
MLXSW_REG(mpar),
MLXSW_REG(mlcr),
+ MLXSW_REG(mpsc),
MLXSW_REG(sbpr),
MLXSW_REG(sbcm),
MLXSW_REG(sbpm),
--
2.7.4
^ permalink raw reply related
* [patch net-next 4/4] mlxsw: spectrum: Add packet sample offloading support
From: Jiri Pirko @ 2017-01-22 11:44 UTC (permalink / raw)
To: netdev
Cc: davem, yotamg, idosch, eladr, nogahf, ogerlitz, jhs,
geert+renesas, stephen, xiyou.wangcong, linux, roopa,
john.fastabend, simon.horman, mrv
In-Reply-To: <1485085487-2652-1-git-send-email-jiri@resnulli.us>
From: Yotam Gigi <yotamg@mellanox.com>
Using the MPSC register, add the functions that configure port-based
packet sampling in hardware and the necessary datatypes in the
mlxsw_sp_port struct. In addition, add the necessary trap for sampled
packets and integrate with matchall offloading to allow offloading of the
sample tc action.
The current offload support is for the tc command:
tc filter add dev <DEV> parent ffff: \
matchall skip_sw \
action sample rate <RATE> group <GROUP> [trunc <SIZE>]
Where only ingress qdiscs are supported, and only a combination of
matchall classifier and sample action will lead to activating hardware
packet sampling.
Signed-off-by: Yotam Gigi <yotamg@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 111 +++++++++++++++++++++++++
drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 10 +++
drivers/net/ethernet/mellanox/mlxsw/trap.h | 1 +
3 files changed, 122 insertions(+)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
index 3dbd82e..467aa52 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -57,6 +57,7 @@
#include <net/pkt_cls.h>
#include <net/tc_act/tc_mirred.h>
#include <net/netevent.h>
+#include <net/tc_act/tc_sample.h>
#include "spectrum.h"
#include "pci.h"
@@ -469,6 +470,16 @@ static void mlxsw_sp_span_mirror_remove(struct mlxsw_sp_port *from,
mlxsw_sp_span_inspected_port_unbind(from, span_entry, type);
}
+static int mlxsw_sp_port_sample_set(struct mlxsw_sp_port *mlxsw_sp_port,
+ bool enable, u32 rate)
+{
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
+ char mpsc_pl[MLXSW_REG_MPSC_LEN];
+
+ mlxsw_reg_mpsc_pack(mpsc_pl, mlxsw_sp_port->local_port, enable, rate);
+ return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpsc), mpsc_pl);
+}
+
static int mlxsw_sp_port_admin_status_set(struct mlxsw_sp_port *mlxsw_sp_port,
bool is_up)
{
@@ -1218,6 +1229,51 @@ mlxsw_sp_port_del_cls_matchall_mirror(struct mlxsw_sp_port *mlxsw_sp_port,
mlxsw_sp_span_mirror_remove(mlxsw_sp_port, to_port, span_type);
}
+static int
+mlxsw_sp_port_add_cls_matchall_sample(struct mlxsw_sp_port *mlxsw_sp_port,
+ struct tc_cls_matchall_offload *cls,
+ const struct tc_action *a,
+ bool ingress)
+{
+ int err;
+
+ if (!mlxsw_sp_port->sample)
+ return -EOPNOTSUPP;
+ if (rtnl_dereference(mlxsw_sp_port->sample->psample_group)) {
+ netdev_err(mlxsw_sp_port->dev, "sample already active\n");
+ return -EEXIST;
+ }
+ if (tcf_sample_rate(a) > MLXSW_REG_MPSC_RATE_MAX) {
+ netdev_err(mlxsw_sp_port->dev, "sample rate not supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ rcu_assign_pointer(mlxsw_sp_port->sample->psample_group,
+ tcf_sample_psample_group(a));
+ mlxsw_sp_port->sample->truncate = tcf_sample_truncate(a);
+ mlxsw_sp_port->sample->trunc_size = tcf_sample_trunc_size(a);
+ mlxsw_sp_port->sample->rate = tcf_sample_rate(a);
+
+ err = mlxsw_sp_port_sample_set(mlxsw_sp_port, true, tcf_sample_rate(a));
+ if (err)
+ goto err_port_sample_set;
+ return 0;
+
+err_port_sample_set:
+ RCU_INIT_POINTER(mlxsw_sp_port->sample->psample_group, NULL);
+ return err;
+}
+
+static void
+mlxsw_sp_port_del_cls_matchall_sample(struct mlxsw_sp_port *mlxsw_sp_port)
+{
+ if (!mlxsw_sp_port->sample)
+ return;
+
+ mlxsw_sp_port_sample_set(mlxsw_sp_port, false, 1);
+ RCU_INIT_POINTER(mlxsw_sp_port->sample->psample_group, NULL);
+}
+
static int mlxsw_sp_port_add_cls_matchall(struct mlxsw_sp_port *mlxsw_sp_port,
__be16 protocol,
struct tc_cls_matchall_offload *cls,
@@ -1248,6 +1304,10 @@ static int mlxsw_sp_port_add_cls_matchall(struct mlxsw_sp_port *mlxsw_sp_port,
mirror = &mall_tc_entry->mirror;
err = mlxsw_sp_port_add_cls_matchall_mirror(mlxsw_sp_port,
mirror, a, ingress);
+ } else if (is_tcf_sample(a) && protocol == htons(ETH_P_ALL)) {
+ mall_tc_entry->type = MLXSW_SP_PORT_MALL_SAMPLE;
+ err = mlxsw_sp_port_add_cls_matchall_sample(mlxsw_sp_port, cls,
+ a, ingress);
} else {
err = -EOPNOTSUPP;
}
@@ -1281,6 +1341,9 @@ static void mlxsw_sp_port_del_cls_matchall(struct mlxsw_sp_port *mlxsw_sp_port,
mlxsw_sp_port_del_cls_matchall_mirror(mlxsw_sp_port,
&mall_tc_entry->mirror);
break;
+ case MLXSW_SP_PORT_MALL_SAMPLE:
+ mlxsw_sp_port_del_cls_matchall_sample(mlxsw_sp_port);
+ break;
default:
WARN_ON(1);
}
@@ -2259,6 +2322,13 @@ static int __mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port,
goto err_alloc_stats;
}
+ mlxsw_sp_port->sample = kzalloc(sizeof(*mlxsw_sp_port->sample),
+ GFP_KERNEL);
+ if (!mlxsw_sp_port->sample) {
+ err = -ENOMEM;
+ goto err_alloc_sample;
+ }
+
mlxsw_sp_port->hw_stats.cache =
kzalloc(sizeof(*mlxsw_sp_port->hw_stats.cache), GFP_KERNEL);
@@ -2387,6 +2457,8 @@ static int __mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port,
err_port_swid_set:
kfree(mlxsw_sp_port->hw_stats.cache);
err_alloc_hw_stats:
+ kfree(mlxsw_sp_port->sample);
+err_alloc_sample:
free_percpu(mlxsw_sp_port->pcpu_stats);
err_alloc_stats:
kfree(mlxsw_sp_port->untagged_vlans);
@@ -2433,6 +2505,7 @@ static void __mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port)
mlxsw_sp_port_swid_set(mlxsw_sp_port, MLXSW_PORT_SWID_DISABLED_PORT);
mlxsw_sp_port_module_unmap(mlxsw_sp, mlxsw_sp_port->local_port);
kfree(mlxsw_sp_port->hw_stats.cache);
+ kfree(mlxsw_sp_port->sample);
free_percpu(mlxsw_sp_port->pcpu_stats);
kfree(mlxsw_sp_port->untagged_vlans);
kfree(mlxsw_sp_port->active_vlans);
@@ -2734,6 +2807,41 @@ static void mlxsw_sp_rx_listener_mark_func(struct sk_buff *skb, u8 local_port,
return mlxsw_sp_rx_listener_no_mark_func(skb, local_port, priv);
}
+static void mlxsw_sp_rx_listener_sample_func(struct sk_buff *skb, u8 local_port,
+ void *priv)
+{
+ struct mlxsw_sp *mlxsw_sp = priv;
+ struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp->ports[local_port];
+ struct psample_group *psample_group;
+ u32 size;
+
+ if (unlikely(!mlxsw_sp_port)) {
+ dev_warn_ratelimited(mlxsw_sp->bus_info->dev, "Port %d: sample skb received for non-existent port\n",
+ local_port);
+ goto out;
+ }
+ if (unlikely(!mlxsw_sp_port->sample)) {
+ dev_warn_ratelimited(mlxsw_sp->bus_info->dev, "Port %d: sample skb received on unsupported port\n",
+ local_port);
+ goto out;
+ }
+
+ size = mlxsw_sp_port->sample->truncate ?
+ mlxsw_sp_port->sample->trunc_size : skb->len;
+
+ rcu_read_lock();
+ psample_group = rcu_dereference(mlxsw_sp_port->sample->psample_group);
+ if (!psample_group)
+ goto out_unlock;
+ psample_sample_packet(psample_group, skb, size,
+ mlxsw_sp_port->dev->ifindex, 0,
+ mlxsw_sp_port->sample->rate);
+out_unlock:
+ rcu_read_unlock();
+out:
+ consume_skb(skb);
+}
+
#define MLXSW_SP_RXL_NO_MARK(_trap_id, _action, _trap_group, _is_ctrl) \
MLXSW_RXL(mlxsw_sp_rx_listener_no_mark_func, _trap_id, _action, \
_is_ctrl, SP_##_trap_group, DISCARD)
@@ -2769,6 +2877,9 @@ static const struct mlxsw_listener mlxsw_sp_listener[] = {
MLXSW_SP_RXL_NO_MARK(RTR_INGRESS0, TRAP_TO_CPU, REMOTE_ROUTE, false),
MLXSW_SP_RXL_NO_MARK(HOST_MISS_IPV4, TRAP_TO_CPU, ARP_MISS, false),
MLXSW_SP_RXL_NO_MARK(BGP_IPV4, TRAP_TO_CPU, BGP_IPV4, false),
+ /* PKT Sample trap */
+ MLXSW_RXL(mlxsw_sp_rx_listener_sample_func, PKT_SAMPLE, MIRROR_TO_CPU,
+ false, SP_IP2ME, DISCARD)
};
static int mlxsw_sp_cpu_policers_set(struct mlxsw_core *mlxsw_core)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
index cc1af19..bc3efe1 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
@@ -46,6 +46,7 @@
#include <linux/dcbnl.h>
#include <linux/in6.h>
#include <linux/notifier.h>
+#include <net/psample.h>
#include "port.h"
#include "core.h"
@@ -229,6 +230,7 @@ struct mlxsw_sp_span_entry {
enum mlxsw_sp_port_mall_action_type {
MLXSW_SP_PORT_MALL_MIRROR,
+ MLXSW_SP_PORT_MALL_SAMPLE,
};
struct mlxsw_sp_port_mall_mirror_tc_entry {
@@ -315,6 +317,13 @@ struct mlxsw_sp_port_pcpu_stats {
u32 tx_dropped;
};
+struct mlxsw_sp_port_sample {
+ struct psample_group __rcu *psample_group;
+ u32 trunc_size;
+ u32 rate;
+ bool truncate;
+};
+
struct mlxsw_sp_port {
struct net_device *dev;
struct mlxsw_sp_port_pcpu_stats __percpu *pcpu_stats;
@@ -361,6 +370,7 @@ struct mlxsw_sp_port {
struct rtnl_link_stats64 *cache;
struct delayed_work update_dw;
} hw_stats;
+ struct mlxsw_sp_port_sample *sample;
};
struct mlxsw_sp_port *mlxsw_sp_port_lower_dev_hold(struct net_device *dev);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/trap.h b/drivers/net/ethernet/mellanox/mlxsw/trap.h
index 7ab275d..02ea48b 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/trap.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/trap.h
@@ -54,6 +54,7 @@ enum {
MLXSW_TRAP_ID_IGMP_V2_REPORT = 0x32,
MLXSW_TRAP_ID_IGMP_V2_LEAVE = 0x33,
MLXSW_TRAP_ID_IGMP_V3_REPORT = 0x34,
+ MLXSW_TRAP_ID_PKT_SAMPLE = 0x38,
MLXSW_TRAP_ID_ARPBC = 0x50,
MLXSW_TRAP_ID_ARPUC = 0x51,
MLXSW_TRAP_ID_MTUERROR = 0x52,
--
2.7.4
^ permalink raw reply related
* Re: [patch net-next 4/4] mlxsw: spectrum: Add packet sample offloading support
From: Ido Schimmel @ 2017-01-22 12:04 UTC (permalink / raw)
To: Jiri Pirko
Cc: netdev, davem, yotamg, idosch, eladr, nogahf, ogerlitz, jhs,
geert+renesas, stephen, xiyou.wangcong, linux, roopa,
john.fastabend, simon.horman, mrv
In-Reply-To: <1485085487-2652-5-git-send-email-jiri@resnulli.us>
On Sun, Jan 22, 2017 at 12:44:47PM +0100, Jiri Pirko wrote:
> From: Yotam Gigi <yotamg@mellanox.com>
>
> Using the MPSC register, add the functions that configure port-based
> packet sampling in hardware and the necessary datatypes in the
> mlxsw_sp_port struct. In addition, add the necessary trap for sampled
> packets and integrate with matchall offloading to allow offloading of the
> sample tc action.
>
> The current offload support is for the tc command:
>
> tc filter add dev <DEV> parent ffff: \
> matchall skip_sw \
> action sample rate <RATE> group <GROUP> [trunc <SIZE>]
>
> Where only ingress qdiscs are supported, and only a combination of
> matchall classifier and sample action will lead to activating hardware
> packet sampling.
>
> Signed-off-by: Yotam Gigi <yotamg@mellanox.com>
> Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Reviewed-by: Ido Schimmel <idosch@mellanox.com>
^ permalink raw reply
* Re: [net, 6/6] net: korina: version bump
From: Roman Yeryomin @ 2017-01-22 12:10 UTC (permalink / raw)
To: Felix Fietkau; +Cc: netdev
In-Reply-To: <CACiydbLu+sKihjKsGVV5kiruSAEwcpJFsUOyASxnBd6=5+xddQ@mail.gmail.com>
On 17 January 2017 at 21:19, Roman Yeryomin <leroi.lists@gmail.com> wrote:
> On 17 January 2017 at 20:55, Felix Fietkau <nbd@nbd.name> wrote:
>> On 2017-01-17 18:33, Roman Yeryomin wrote:
>>> Signed-off-by: Roman Yeryomin <roman@advem.lv>
>>> ---
>>> drivers/net/ethernet/korina.c | 4 ++--
>>> 1 file changed, 2 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/drivers/net/ethernet/korina.c b/drivers/net/ethernet/korina.c
>>> index 83c994f..c8fed01 100644
>>> --- a/drivers/net/ethernet/korina.c
>>> +++ b/drivers/net/ethernet/korina.c
>>> @@ -66,8 +66,8 @@
>>> #include <asm/mach-rc32434/dma_v.h>
>>>
>>> #define DRV_NAME "korina"
>>> -#define DRV_VERSION "0.10"
>>> -#define DRV_RELDATE "04Mar2008"
>>> +#define DRV_VERSION "0.20"
>>> +#define DRV_RELDATE "15Jan2017"
>> I think it would make more sense to remove this version instead of
>> bumping it. Individual driver versions are rather pointless, the kernel
>> version is more meaningful anyway.
>
> OK, makes sense
Actually, after thinking a bit more about this, not really...
How about ethtool, which uses driver name and version?
I see most ethernet drivers define some version. And it's pretty
useful, when using backports.
IMO, it should be kept and bumped.
Regards,
Roman
^ permalink raw reply
* Re: [RFC PATCH net-next 4/5] bridge: vlan lwt and dst_metadata netlink support
From: Nikolay Aleksandrov @ 2017-01-22 12:05 UTC (permalink / raw)
To: Roopa Prabhu, netdev
Cc: davem, stephen, tgraf, hannes, jbenc, pshelar, dsa, hadi
In-Reply-To: <1484977616-1541-5-git-send-email-roopa@cumulusnetworks.com>
On 21/01/17 06:46, Roopa Prabhu wrote:
> From: Roopa Prabhu <roopa@cumulusnetworks.com>
>
> This patch adds support to attach per vlan tunnel info dst
> metadata. This enables bridge driver to map vlan to tunnel_info
> at ingress and egress
>
> The initial use case is vlan to vni bridging, but the api is generic
> to extend to any tunnel_info in the future:
> - Uapi to configure/unconfigure/dump per vlan tunnel data
> - netlink functions to configure vlan and tunnel_info mapping
> - Introduces bridge port flag BR_LWT_VLAN to enable attach/detach
> dst_metadata to bridged packets on ports.
>
> Use case:
> example use for this is a vxlan bridging gateway or vtep
> which maps vlans to vn-segments (or vnis). User can configure
> per-vlan tunnel information which the bridge driver can use
> to bridge vlan into the corresponding tunnel.
>
> CC: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
> Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com>
> ---
> CC'ing Nikolay for some more eyes as he has been trying to keep the
> bridge driver fast path lite.
>
> include/linux/if_bridge.h | 1 +
> net/bridge/br_input.c | 1 +
> net/bridge/br_netlink.c | 410 ++++++++++++++++++++++++++++++++++++++-------
> net/bridge/br_private.h | 18 ++
> net/bridge/br_vlan.c | 138 ++++++++++++++-
> 5 files changed, 507 insertions(+), 61 deletions(-)
>
> diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
> index c6587c0..36ff611 100644
> --- a/include/linux/if_bridge.h
> +++ b/include/linux/if_bridge.h
> @@ -46,6 +46,7 @@ struct br_ip_list {
> #define BR_LEARNING_SYNC BIT(9)
> #define BR_PROXYARP_WIFI BIT(10)
> #define BR_MCAST_FLOOD BIT(11)
> +#define BR_LWT_VLAN BIT(12)
>
> #define BR_DEFAULT_AGEING_TIME (300 * HZ)
>
> diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
> index 855b72f..83f356f 100644
> --- a/net/bridge/br_input.c
> +++ b/net/bridge/br_input.c
> @@ -20,6 +20,7 @@
> #include <net/arp.h>
> #include <linux/export.h>
> #include <linux/rculist.h>
> +#include <net/dst_metadata.h>
> #include "br_private.h"
>
> /* Hook for brouter */
> diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
> index 71c7453..df997ad 100644
> --- a/net/bridge/br_netlink.c
> +++ b/net/bridge/br_netlink.c
> @@ -17,17 +17,30 @@
> #include <net/net_namespace.h>
> #include <net/sock.h>
> #include <uapi/linux/if_bridge.h>
> +#include <net/dst_metadata.h>
>
> #include "br_private.h"
> #include "br_private_stp.h"
>
> -static int __get_num_vlan_infos(struct net_bridge_vlan_group *vg,
> - u32 filter_mask)
> +static size_t br_get_vlan_tinfo_size(void)
> {
> + return nla_total_size(0) + /* nest IFLA_BRIDGE_VLAN_TUNNEL_INFO */
> + nla_total_size(sizeof(u32)) + /* IFLA_BRIDGE_VLAN_TUNNEL_ID */
> + nla_total_size(sizeof(u16)) + /* IFLA_BRIDGE_VLAN_TUNNEL_VID */
> + nla_total_size(sizeof(u16)); /* IFLA_BRIDGE_VLAN_TUNNEL_FLAGS */
> +}
> +
> +static int __get_num_vlan_infos(struct net_bridge_port *p,
> + struct net_bridge_vlan_group *vg,
> + u32 filter_mask, int *num_vtinfos)
> +{
> + struct net_bridge_vlan *vbegin = NULL, *vend = NULL;
> + struct net_bridge_vlan *vtbegin = NULL, *vtend = NULL;
> struct net_bridge_vlan *v;
> - u16 vid_range_start = 0, vid_range_end = 0, vid_range_flags = 0;
> + bool get_tinfos = (p && p->flags & BR_LWT_VLAN) ? true: false;
> + bool vcontinue, vtcontinue;
> + int num_vinfos = 0;
> u16 flags, pvid;
> - int num_vlans = 0;
>
> if (!(filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED))
> return 0;
> @@ -36,6 +49,8 @@ static int __get_num_vlan_infos(struct net_bridge_vlan_group *vg,
> /* Count number of vlan infos */
> list_for_each_entry_rcu(v, &vg->vlan_list, vlist) {
> flags = 0;
> + vcontinue = false;
> + vtcontinue = false;
> /* only a context, bridge vlan not activated */
> if (!br_vlan_should_use(v))
> continue;
> @@ -45,47 +60,79 @@ static int __get_num_vlan_infos(struct net_bridge_vlan_group *vg,
> if (v->flags & BRIDGE_VLAN_INFO_UNTAGGED)
> flags |= BRIDGE_VLAN_INFO_UNTAGGED;
>
> - if (vid_range_start == 0) {
> - goto initvars;
> - } else if ((v->vid - vid_range_end) == 1 &&
> - flags == vid_range_flags) {
> - vid_range_end = v->vid;
> + if (!vbegin) {
> + vbegin = v;
> + vend = v;
> + vcontinue = true;
> + } else if ((v->vid - vend->vid) == 1 &&
> + flags == vbegin->flags) {
> + vend = v;
> + vcontinue = true;
> + }
> +
> + if (!vcontinue) {
> + if ((vend->vid - vbegin->vid) > 0)
> + num_vinfos += 2;
> + else
> + num_vinfos += 1;
> + }
> +
> + if (!get_tinfos && !v->tinfo.tunnel_id)
> continue;
> - } else {
> - if ((vid_range_end - vid_range_start) > 0)
> - num_vlans += 2;
> +
> + if (!vtbegin) {
> + vtbegin = v;
> + vtend = v;
> + vtcontinue = true;
> + } else if ((v->vid - vtend->vid) == 1 &&
> + vlan_tunnel_id_isrange(vtend, v)) {
> + vtend = v;
> + vtcontinue = true;
> + }
> +
> + if (!vtcontinue) {
> + if ((vtend->vid - vtbegin->vid) > 0)
> + num_vtinfos += 2;
> else
> - num_vlans += 1;
> + num_vtinfos += 1;
> + vbegin = NULL;
> + vend = NULL;
> }
> -initvars:
> - vid_range_start = v->vid;
> - vid_range_end = v->vid;
> - vid_range_flags = flags;
> }
>
> - if (vid_range_start != 0) {
> - if ((vid_range_end - vid_range_start) > 0)
> - num_vlans += 2;
> + if (vbegin) {
> + if ((vend->vid - vbegin->vid) > 0)
> + num_vinfos += 2;
> else
> - num_vlans += 1;
> + num_vinfos += 1;
> }
>
> - return num_vlans;
> + if (get_tinfos && vtbegin && vtbegin->tinfo.tunnel_id) {
> + if ((vtend->vid - vtbegin->vid) > 0)
> + *num_vtinfos += 2;
> + else
> + *num_vtinfos += 1;
> + }
> +
> + return num_vinfos;
> }
I think this whole function should be broken into at least a few. It's really difficult
to parse what's going on.
>
> -static int br_get_num_vlan_infos(struct net_bridge_vlan_group *vg,
> - u32 filter_mask)
> +static int br_get_num_vlan_infos(struct net_bridge_port *p,
> + struct net_bridge_vlan_group *vg,
> + int *num_tinfos, u32 filter_mask)
> {
> int num_vlans;
>
> if (!vg)
> return 0;
>
> - if (filter_mask & RTEXT_FILTER_BRVLAN)
> + if (filter_mask & RTEXT_FILTER_BRVLAN) {
> + *num_tinfos = vg->num_vlans;
> return vg->num_vlans;
> + }
>
> rcu_read_lock();
> - num_vlans = __get_num_vlan_infos(vg, filter_mask);
> + num_vlans = __get_num_vlan_infos(p, vg, filter_mask, num_tinfos);
> rcu_read_unlock();
>
> return num_vlans;
> @@ -95,9 +142,10 @@ static size_t br_get_link_af_size_filtered(const struct net_device *dev,
> u32 filter_mask)
> {
> struct net_bridge_vlan_group *vg = NULL;
> - struct net_bridge_port *p;
> + struct net_bridge_port *p = NULL;
> struct net_bridge *br;
> - int num_vlan_infos;
> + int num_vlan_infos, num_vlan_tinfos = 0;
> + size_t retsize = 0;
>
> rcu_read_lock();
> if (br_port_exists(dev)) {
> @@ -107,11 +155,15 @@ static size_t br_get_link_af_size_filtered(const struct net_device *dev,
> br = netdev_priv(dev);
> vg = br_vlan_group_rcu(br);
> }
> - num_vlan_infos = br_get_num_vlan_infos(vg, filter_mask);
> + num_vlan_infos = br_get_num_vlan_infos(p, vg, &num_vlan_tinfos,
> + filter_mask);
> rcu_read_unlock();
>
> /* Each VLAN is returned in bridge_vlan_info along with flags */
> - return num_vlan_infos * nla_total_size(sizeof(struct bridge_vlan_info));
> + retsize = num_vlan_infos * nla_total_size(sizeof(struct bridge_vlan_info)) +
> + num_vlan_tinfos * br_get_vlan_tinfo_size();
> +
> + return retsize;
> }
>
> static inline size_t br_port_info_size(void)
> @@ -191,7 +243,8 @@ static int br_port_fill_attrs(struct sk_buff *skb,
> nla_put_u16(skb, IFLA_BRPORT_NO, p->port_no) ||
> nla_put_u8(skb, IFLA_BRPORT_TOPOLOGY_CHANGE_ACK,
> p->topology_change_ack) ||
> - nla_put_u8(skb, IFLA_BRPORT_CONFIG_PENDING, p->config_pending))
> + nla_put_u8(skb, IFLA_BRPORT_CONFIG_PENDING, p->config_pending) ||
> + nla_put_u8(skb, IFLA_BRPORT_LWT_VLAN, !!(p->flags & BR_LWT_VLAN)))
> return -EMSGSIZE;
>
> timerval = br_timer_value(&p->message_age_timer);
> @@ -216,6 +269,34 @@ static int br_port_fill_attrs(struct sk_buff *skb,
> return 0;
> }
>
> +static int br_fill_vlan_tinfo(struct sk_buff *skb, u16 vid,
> + __be64 tunnel_id, u16 flags)
> +{
> + __be32 tid = tunnel_id_to_key32(tunnel_id);
> + struct nlattr *tmap;
> +
> + tmap = nla_nest_start(skb, IFLA_BRIDGE_VLAN_TUNNEL_INFO);
> + if (!tmap)
> + return -EMSGSIZE;
> + if (nla_put_u32(skb, IFLA_BRIDGE_VLAN_TUNNEL_ID,
> + be32_to_cpu(tid)))
> + goto nla_put_failure;
> + if (nla_put_u16(skb, IFLA_BRIDGE_VLAN_TUNNEL_VID,
> + vid))
> + goto nla_put_failure;
> + if (nla_put_u16(skb, IFLA_BRIDGE_VLAN_TUNNEL_FLAGS,
> + flags))
> + goto nla_put_failure;
> + nla_nest_end(skb, tmap);
> +
> + return 0;
> +
> +nla_put_failure:
> + nla_nest_cancel(skb, tmap);
> +
> + return -EMSGSIZE;
> +}
> +
> static int br_fill_ifvlaninfo_range(struct sk_buff *skb, u16 vid_start,
> u16 vid_end, u16 flags)
> {
> @@ -249,20 +330,24 @@ static int br_fill_ifvlaninfo_range(struct sk_buff *skb, u16 vid_start,
> }
>
> static int br_fill_ifvlaninfo_compressed(struct sk_buff *skb,
> + struct net_bridge_port *p,
> struct net_bridge_vlan_group *vg)
> {
> + struct net_bridge_vlan *vbegin = NULL, *vend = NULL;
> + struct net_bridge_vlan *vtbegin = NULL, *vtend = NULL;
> + bool fill_tinfos = (p && p->flags & BR_LWT_VLAN) ? true: false;
> struct net_bridge_vlan *v;
> - u16 vid_range_start = 0, vid_range_end = 0, vid_range_flags = 0;
> + bool vcontinue, vtcontinue;
> u16 flags, pvid;
> - int err = 0;
> + int err;
>
> - /* Pack IFLA_BRIDGE_VLAN_INFO's for every vlan
> - * and mark vlan info with begin and end flags
> - * if vlaninfo represents a range
> - */
> pvid = br_get_pvid(vg);
> + /* Count number of vlan infos */
> list_for_each_entry_rcu(v, &vg->vlan_list, vlist) {
> flags = 0;
> + vcontinue = false;
> + vtcontinue = false;
> + /* only a context, bridge vlan not activated */
> if (!br_vlan_should_use(v))
> continue;
> if (v->vid == pvid)
> @@ -271,44 +356,103 @@ static int br_fill_ifvlaninfo_compressed(struct sk_buff *skb,
> if (v->flags & BRIDGE_VLAN_INFO_UNTAGGED)
> flags |= BRIDGE_VLAN_INFO_UNTAGGED;
>
> - if (vid_range_start == 0) {
> - goto initvars;
> - } else if ((v->vid - vid_range_end) == 1 &&
> - flags == vid_range_flags) {
> - vid_range_end = v->vid;
> - continue;
> - } else {
> - err = br_fill_ifvlaninfo_range(skb, vid_range_start,
> - vid_range_end,
> - vid_range_flags);
> + if (!vbegin) {
> + vbegin = v;
> + vend = v;
> + vcontinue = true;
> + } else if ((v->vid - vend->vid) == 1 &&
> + flags == vbegin->flags) {
> + vend = v;
> + vcontinue = true;
> + }
> +
> + if (!vcontinue) {
> + err = br_fill_ifvlaninfo_range(skb,
> + vbegin->vid,
> + vend->vid,
> + vbegin->flags);
> if (err)
> return err;
> + vbegin = vend = NULL;
> + }
> +
> + if (!fill_tinfos || !v->tinfo.tunnel_id)
> + continue;
> +
> + if (!vtbegin) {
> + vtbegin = v;
> + vtend = v;
> + vtcontinue = true;
> + } else if ((v->vid - vtend->vid) == 1 &&
> + vlan_tunnel_id_isrange(vtend, v)) {
> + vtend = v;
> + vtcontinue = true;
> }
>
> -initvars:
> - vid_range_start = v->vid;
> - vid_range_end = v->vid;
> - vid_range_flags = flags;
> + if (!vtcontinue && vtbegin->tinfo.tunnel_id) {
> + if ((vtend->vid - vtbegin->vid) > 0) {
> + err = br_fill_vlan_tinfo(skb, vbegin->vid,
> + vbegin->tinfo.tunnel_id,
> + BRIDGE_VLAN_INFO_RANGE_BEGIN);
> + if (err)
> + return err;
> + err = br_fill_vlan_tinfo(skb, vend->vid,
> + vend->tinfo.tunnel_id,
> + BRIDGE_VLAN_INFO_RANGE_END);
> + if (err)
> + return err;
> + } else {
> + err = br_fill_vlan_tinfo(skb, vbegin->vid,
> + vbegin->tinfo.tunnel_id,
> + 0);
> + if (err)
> + return err;
> + }
> + vbegin = NULL;
> + vend = NULL;
> + }
> }
>
> - if (vid_range_start != 0) {
> - /* Call it once more to send any left over vlans */
> - err = br_fill_ifvlaninfo_range(skb, vid_range_start,
> - vid_range_end,
> - vid_range_flags);
> + if (vbegin) {
> + err = br_fill_ifvlaninfo_range(skb, vbegin->vid,
> + vend->vid,
> + vbegin->flags);
> if (err)
> return err;
> }
>
> + if (fill_tinfos && vtbegin && vtbegin->tinfo.tunnel_id) {
> + if ((vtend->vid - vtbegin->vid) > 0) {
> + err = br_fill_vlan_tinfo(skb, vbegin->vid,
> + vbegin->tinfo.tunnel_id,
> + BRIDGE_VLAN_INFO_RANGE_BEGIN);
> + if (err)
> + return err;
> + err = br_fill_vlan_tinfo(skb, vend->vid,
> + vend->tinfo.tunnel_id,
> + BRIDGE_VLAN_INFO_RANGE_END);
> + if (err)
> + return err;
> + } else {
> + err = br_fill_vlan_tinfo(skb, vbegin->vid,
> + vbegin->tinfo.tunnel_id, 0);
> + if (err)
> + return err;
> + }
> + }
> +
> return 0;
> }
Maybe look into breaking this one, too. It's getting huge and hard to follow..
>
> static int br_fill_ifvlaninfo(struct sk_buff *skb,
> + struct net_bridge_port *p,
> struct net_bridge_vlan_group *vg)
> {
> struct bridge_vlan_info vinfo;
> struct net_bridge_vlan *v;
> + bool fill_tinfos = (p && p->flags & BR_LWT_VLAN) ? true : false;
> u16 pvid;
> + int err;
>
> pvid = br_get_pvid(vg);
> list_for_each_entry_rcu(v, &vg->vlan_list, vlist) {
> @@ -326,6 +470,14 @@ static int br_fill_ifvlaninfo(struct sk_buff *skb,
> if (nla_put(skb, IFLA_BRIDGE_VLAN_INFO,
> sizeof(vinfo), &vinfo))
> goto nla_put_failure;
> +
> + if (!fill_tinfos || !v->tinfo.tunnel_id)
> + continue;
> +
> + err = br_fill_vlan_tinfo(skb, v->vid,
> + v->tinfo.tunnel_id, 0);
> + if (err)
> + return err;
> }
>
> return 0;
> @@ -411,9 +563,9 @@ static int br_fill_ifinfo(struct sk_buff *skb,
> goto nla_put_failure;
> }
> if (filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED)
> - err = br_fill_ifvlaninfo_compressed(skb, vg);
> + err = br_fill_ifvlaninfo_compressed(skb, port, vg);
> else
> - err = br_fill_ifvlaninfo(skb, vg);
> + err = br_fill_ifvlaninfo(skb, port, vg);
> rcu_read_unlock();
> if (err)
> goto nla_put_failure;
> @@ -514,6 +666,127 @@ static int br_vlan_info(struct net_bridge *br, struct net_bridge_port *p,
> return err;
> }
>
> +static const struct nla_policy vlan_tunnel_policy[IFLA_BRIDGE_VLAN_TUNNEL_MAX + 1] = {
> + [IFLA_BRIDGE_VLAN_TUNNEL_ID]= { .type = NLA_U32 },
> + [IFLA_BRIDGE_VLAN_TUNNEL_VID] = { .type = NLA_U16 },
> + [IFLA_BRIDGE_VLAN_TUNNEL_FLAGS] = { .type = NLA_U16 },
> +};
> +
> +static int br_add_vlan_tunnel_info(struct net_bridge *br,
> + struct net_bridge_port *p, int cmd,
> + u16 vid, u32 tun_id)
> +{
> + int err;
> +
> + switch (cmd) {
> + case RTM_SETLINK:
> + if (p) {
> + /* if the MASTER flag is set this will act on the global
> + * per-VLAN entry as well
> + */
> + err = nbp_vlan_tunnel_info_add(p, vid, tun_id);
> + if (err)
> + break;
> + } else {
> + return -EINVAL;
> + }
> +
> + break;
> +
> + case RTM_DELLINK:
> + if (p)
> + nbp_vlan_tunnel_info_delete(p, vid);
> + else
> + return -EINVAL;
> + break;
> + }
so if (!p) return -einval in the beginning ? :-)
> +
> + return 0;
> +}
> +
> +struct vtunnel_info {
> + u32 tunid;
> + u16 vid;
> + u16 flags;
> +};
> +
> +static int br_parse_vlan_tunnel_info(struct nlattr *attr,
> + struct vtunnel_info *tinfo)
> +{
> + struct nlattr *tb[IFLA_BRIDGE_VLAN_TUNNEL_MAX + 1];
> + u32 tun_id;
> + u16 vid, flags;
> + int err;
> +
> + err = nla_parse_nested(tb, IFLA_BRIDGE_VLAN_TUNNEL_MAX,
> + attr, vlan_tunnel_policy);
> + if (err < 0)
> + return err;
> +
> + if (tb[IFLA_BRIDGE_VLAN_TUNNEL_ID])
> + tun_id = nla_get_u32(tb[IFLA_BRIDGE_VLAN_TUNNEL_ID]);
> + else
> + return -EINVAL;
> +
> + if (tb[IFLA_BRIDGE_VLAN_TUNNEL_VID]) {
> + vid = nla_get_u16(tb[IFLA_BRIDGE_VLAN_TUNNEL_VID]);
> + if (vid >= VLAN_VID_MASK)
> + return -ERANGE;
!vid ||
> + } else {
> + return -EINVAL;
> + }
these attr checks can be moved in the beginning, usually there's a check for existence
of the mandatory attributes, then you can continue just using them and avoid these
"else" statements
> +
> + if (tb[IFLA_BRIDGE_VLAN_TUNNEL_FLAGS])
> + flags = nla_get_u16(tb[IFLA_BRIDGE_VLAN_TUNNEL_FLAGS]);
> +
> + tinfo->tunid = tun_id;
> + tinfo->vid = vid;
> + tinfo->flags = flags;
> +
> + return 0;
> +}
> +
> +static int br_process_vlan_tunnel_info(struct net_bridge *br,
> + struct net_bridge_port *p, int cmd,
> + struct vtunnel_info *tinfo_curr,
> + struct vtunnel_info *tinfo_last)
> +{
> + int t, v;
> + int err;
> +
> + if (tinfo_curr->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) {
> + if (tinfo_last->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN)
> + return -EINVAL;
> + memcpy(tinfo_last, tinfo_curr, sizeof(struct vtunnel_info));
> + } else if (tinfo_curr->flags & BRIDGE_VLAN_INFO_RANGE_END) {
> + if (!(tinfo_last->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN))
> + return -EINVAL;
> + if ((tinfo_curr->vid - tinfo_last->vid) !=
> + (tinfo_curr->tunid - tinfo_last->tunid))
> + return -EINVAL;
> + /* XXX: tun id and vlan id attrs must be same
> + */
> + t = tinfo_last->tunid;
> + for (v = tinfo_last->vid; v <= tinfo_curr->vid; v++) {
> + err = br_add_vlan_tunnel_info(br, p, cmd,
> + v, t);
> + if (err)
> + return err;
> + t++;
> + }
> + memset(tinfo_last, 0, sizeof(struct vtunnel_info));
> + memset(tinfo_curr, 0, sizeof(struct vtunnel_info));
> + } else {
> + err = br_add_vlan_tunnel_info(br, p, cmd,
> + tinfo_curr->vid,
> + tinfo_curr->tunid);
> + if (err)
> + return err;
> + }
> +
> + return 0;
> +}
> +
> static int br_afspec(struct net_bridge *br,
> struct net_bridge_port *p,
> struct nlattr *af_spec,
> @@ -522,10 +795,30 @@ static int br_afspec(struct net_bridge *br,
> struct bridge_vlan_info *vinfo_start = NULL;
> struct bridge_vlan_info *vinfo = NULL;
> struct nlattr *attr;
> + struct vtunnel_info tinfo_last = {
> + .tunid = 0,
> + .vid = 0,
> + .flags = 0};
> + struct vtunnel_info tinfo_curr = {
> + .tunid = 0,
> + .vid = 0,
> + .flags = 0};
just { } should be enough to zero the structs
> int err = 0;
> int rem;
>
> nla_for_each_nested(attr, af_spec, rem) {
> + if (nla_type(attr) == IFLA_BRIDGE_VLAN_TUNNEL_INFO) {
> + err = br_parse_vlan_tunnel_info(attr, &tinfo_curr);
> + if (err)
> + return err;
> + err = br_process_vlan_tunnel_info(br, p, cmd,
> + &tinfo_curr,
> + &tinfo_last);
> + if (err)
> + return err;
> + continue;
> + }
> +
> if (nla_type(attr) != IFLA_BRIDGE_VLAN_INFO)
> continue;
> if (nla_len(attr) != sizeof(struct bridge_vlan_info))
> @@ -638,6 +931,7 @@ static int br_setport(struct net_bridge_port *p, struct nlattr *tb[])
> br_set_port_flag(p, tb, IFLA_BRPORT_MCAST_FLOOD, BR_MCAST_FLOOD);
> br_set_port_flag(p, tb, IFLA_BRPORT_PROXYARP, BR_PROXYARP);
> br_set_port_flag(p, tb, IFLA_BRPORT_PROXYARP_WIFI, BR_PROXYARP_WIFI);
> + br_set_port_flag(p, tb, IFLA_BRPORT_LWT_VLAN, BR_LWT_VLAN);
>
> if (tb[IFLA_BRPORT_COST]) {
> err = br_stp_set_path_cost(p, nla_get_u32(tb[IFLA_BRPORT_COST]));
> diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
> index 8ce621e..f68e360 100644
> --- a/net/bridge/br_private.h
> +++ b/net/bridge/br_private.h
> @@ -91,6 +91,11 @@ struct br_vlan_stats {
> struct u64_stats_sync syncp;
> };
>
> +struct br_tunnel_info {
> + __be64 tunnel_id;
> + struct metadata_dst *tunnel_dst;
> +};
> +
> /**
> * struct net_bridge_vlan - per-vlan entry
> *
> @@ -113,6 +118,7 @@ struct br_vlan_stats {
> */
> struct net_bridge_vlan {
> struct rhash_head vnode;
> + struct rhash_head tnode;
> u16 vid;
> u16 flags;
> struct br_vlan_stats __percpu *stats;
> @@ -124,6 +130,9 @@ struct net_bridge_vlan {
> atomic_t refcnt;
> struct net_bridge_vlan *brvlan;
> };
> +
> + struct br_tunnel_info tinfo;
> +
> struct list_head vlist;
>
> struct rcu_head rcu;
> @@ -145,6 +154,7 @@ struct net_bridge_vlan {
> */
> struct net_bridge_vlan_group {
> struct rhashtable vlan_hash;
> + struct rhashtable tunnel_hash;
> struct list_head vlan_list;
> u16 num_vlans;
> u16 pvid;
> @@ -786,6 +796,14 @@ struct sk_buff *br_handle_vlan(struct net_bridge *br,
> int nbp_get_num_vlan_infos(struct net_bridge_port *p, u32 filter_mask);
> void br_vlan_get_stats(const struct net_bridge_vlan *v,
> struct br_vlan_stats *stats);
> +int __vlan_tunnel_info_add(struct net_bridge_vlan_group *vg,
> + struct net_bridge_vlan *vlan, u32 tun_id);
> +int __vlan_tunnel_info_del(struct net_bridge_vlan_group *vg,
> + struct net_bridge_vlan *vlan);
> +int nbp_vlan_tunnel_info_delete(struct net_bridge_port *port, u16 vid);
> +int nbp_vlan_tunnel_info_add(struct net_bridge_port *port, u16 vid, u32 tun_id);
> +bool vlan_tunnel_id_isrange(struct net_bridge_vlan *v_end,
> + struct net_bridge_vlan *v);
>
> static inline struct net_bridge_vlan_group *br_vlan_group(
> const struct net_bridge *br)
> diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c
> index b6de4f4..2040f08 100644
> --- a/net/bridge/br_vlan.c
> +++ b/net/bridge/br_vlan.c
> @@ -3,6 +3,7 @@
> #include <linux/rtnetlink.h>
> #include <linux/slab.h>
> #include <net/switchdev.h>
> +#include <net/dst_metadata.h>
>
> #include "br_private.h"
>
> @@ -31,6 +32,31 @@ static struct net_bridge_vlan *br_vlan_lookup(struct rhashtable *tbl, u16 vid)
> return rhashtable_lookup_fast(tbl, &vid, br_vlan_rht_params);
> }
>
> +static inline int br_vlan_tunid_cmp(struct rhashtable_compare_arg *arg,
> + const void *ptr)
> +{
> + const struct net_bridge_vlan *vle = ptr;
> + __be64 tunid = *(__be64 *)arg->key;
> +
> + return vle->tinfo.tunnel_id != tunid;
> +}
> +
> +static const struct rhashtable_params br_vlan_tunnel_rht_params = {
> + .head_offset = offsetof(struct net_bridge_vlan, tnode),
> + .key_offset = offsetof(struct net_bridge_vlan, tinfo.tunnel_id),
> + .key_len = sizeof(__be64),
> + .nelem_hint = 3,
> + .locks_mul = 1,
> + .obj_cmpfn = br_vlan_tunid_cmp,
> + .automatic_shrinking = true,
> +};
> +
> +static struct net_bridge_vlan *br_vlan_tunnel_lookup(struct rhashtable *tbl,
> + u64 tunnel_id)
> +{
> + return rhashtable_lookup_fast(tbl, &tunnel_id, br_vlan_tunnel_rht_params);
> +}
> +
> static void __vlan_add_pvid(struct net_bridge_vlan_group *vg, u16 vid)
> {
> if (vg->pvid == vid)
> @@ -325,6 +351,7 @@ static void __vlan_group_free(struct net_bridge_vlan_group *vg)
> {
> WARN_ON(!list_empty(&vg->vlan_list));
> rhashtable_destroy(&vg->vlan_hash);
> + rhashtable_destroy(&vg->tunnel_hash);
> kfree(vg);
> }
>
> @@ -613,6 +640,8 @@ int br_vlan_delete(struct net_bridge *br, u16 vid)
> br_fdb_find_delete_local(br, NULL, br->dev->dev_addr, vid);
> br_fdb_delete_by_port(br, NULL, vid, 0);
>
> + __vlan_tunnel_info_del(vg, v);
> +
> return __vlan_del(v);
> }
>
> @@ -918,6 +947,9 @@ int br_vlan_init(struct net_bridge *br)
> ret = rhashtable_init(&vg->vlan_hash, &br_vlan_rht_params);
> if (ret)
> goto err_rhtbl;
> + ret = rhashtable_init(&vg->tunnel_hash, &br_vlan_tunnel_rht_params);
> + if (ret)
> + goto err_rhtbl2;
> INIT_LIST_HEAD(&vg->vlan_list);
> br->vlan_proto = htons(ETH_P_8021Q);
> br->default_pvid = 1;
> @@ -932,6 +964,8 @@ int br_vlan_init(struct net_bridge *br)
> return ret;
>
> err_vlan_add:
> + rhashtable_destroy(&vg->tunnel_hash);
> +err_rhtbl2:
> rhashtable_destroy(&vg->vlan_hash);
> err_rhtbl:
> kfree(vg);
> @@ -960,7 +994,10 @@ int nbp_vlan_init(struct net_bridge_port *p)
>
> ret = rhashtable_init(&vg->vlan_hash, &br_vlan_rht_params);
> if (ret)
> - goto err_rhtbl;
> + goto err_rhtbl1;
> + ret = rhashtable_init(&vg->tunnel_hash, &br_vlan_tunnel_rht_params);
> + if (ret)
> + goto err_rhtbl2;
> INIT_LIST_HEAD(&vg->vlan_list);
> rcu_assign_pointer(p->vlgrp, vg);
> if (p->br->default_pvid) {
> @@ -976,9 +1013,11 @@ int nbp_vlan_init(struct net_bridge_port *p)
> err_vlan_add:
> RCU_INIT_POINTER(p->vlgrp, NULL);
> synchronize_rcu();
> - rhashtable_destroy(&vg->vlan_hash);
> + rhashtable_destroy(&vg->tunnel_hash);
> err_vlan_enabled:
> -err_rhtbl:
> +err_rhtbl2:
> + rhashtable_destroy(&vg->vlan_hash);
> +err_rhtbl1:
> kfree(vg);
>
> goto out;
> @@ -1081,3 +1120,96 @@ void br_vlan_get_stats(const struct net_bridge_vlan *v,
> stats->tx_packets += txpackets;
> }
> }
> +
> +bool vlan_tunnel_id_isrange(struct net_bridge_vlan *v_end,
> + struct net_bridge_vlan *v)
> +{
> + /* XXX: check other tunnel attributes */
> + return (be32_to_cpu(tunnel_id_to_key32(v_end->tinfo.tunnel_id)) -
> + be32_to_cpu(tunnel_id_to_key32(v->tinfo.tunnel_id)) == 1);
> +}
> +
> +int __vlan_tunnel_info_add(struct net_bridge_vlan_group *vg,
> + struct net_bridge_vlan *vlan, u32 tun_id)
> +{
> + struct metadata_dst *metadata = NULL;
> + __be64 key = key32_to_tunnel_id(cpu_to_be32(tun_id));
> + int err;
> +
> + if (vlan->tinfo.tunnel_dst)
> + return -EEXIST;
> +
> + metadata = __ip_tun_set_dst(0, 0, 0, 0, 0, TUNNEL_KEY,
> + key, 0);
> + if (!metadata)
> + return -EINVAL;
> +
> + metadata->u.tun_info.mode |= IP_TUNNEL_INFO_TX | IP_TUNNEL_INFO_BRIDGE;
> + vlan->tinfo.tunnel_dst = metadata;
> + vlan->tinfo.tunnel_id = key;
> +
> + err = rhashtable_lookup_insert_fast(&vg->tunnel_hash, &vlan->tnode,
> + br_vlan_tunnel_rht_params);
> + if (err)
> + goto out;
> +
> + return 0;
> +out:
> + dst_release(&vlan->tinfo.tunnel_dst->dst);
> +
> + return err;
> +}
> +
> +int __vlan_tunnel_info_del(struct net_bridge_vlan_group *vg,
> + struct net_bridge_vlan *vlan)
> +{
> + if (vlan->tinfo.tunnel_dst) {
> + vlan->tinfo.tunnel_id = 0;
> + dst_release(&vlan->tinfo.tunnel_dst->dst);
> +
> + rhashtable_remove_fast(&vg->tunnel_hash, &vlan->vnode,
> + br_vlan_tunnel_rht_params);
> + }
> +
> + return 0;
> +}
I think all of these should be static, if I haven't missed something I don't see them
being used anywhere else
> +
> +/* Must be protected by RTNL.
> + * Must be called with vid in range from 1 to 4094 inclusive.
> + */
> +int nbp_vlan_tunnel_info_add(struct net_bridge_port *port, u16 vid, u32 tun_id)
> +{
> + struct net_bridge_vlan_group *vg;
> + struct net_bridge_vlan *vlan;
> +
> + ASSERT_RTNL();
> +
> + vg = nbp_vlan_group(port);
> + vlan = br_vlan_find(vg, vid);
> + if (!vlan)
> + return -EINVAL;
> +
> + __vlan_tunnel_info_add(vg, vlan, tun_id);
> +
> + return 0;
> +}
> +
> +/* Must be protected by RTNL.
> + * Must be called with vid in range from 1 to 4094 inclusive.
> + */
> +int nbp_vlan_tunnel_info_delete(struct net_bridge_port *port, u16 vid)
> +{
> + struct net_bridge_vlan_group *vg;
> + struct net_bridge_vlan *v;
> +
> + ASSERT_RTNL();
> +
> + vg = nbp_vlan_group(port);
> + v = br_vlan_find(vg, vid);
> + if (!v)
> + return -ENOENT;
> +
> + __vlan_tunnel_info_del(vg, v);
> +
> + return 0;
> +}
>
^ permalink raw reply
* Re: [RFC PATCH net-next 5/5] bridge: vlan lwt dst_metadata hooks in ingress and egress paths
From: Nikolay Aleksandrov @ 2017-01-22 12:15 UTC (permalink / raw)
To: Roopa Prabhu, netdev
Cc: davem, stephen, tgraf, hannes, jbenc, pshelar, dsa, hadi
In-Reply-To: <1484977616-1541-6-git-send-email-roopa@cumulusnetworks.com>
On 21/01/17 06:46, Roopa Prabhu wrote:
> From: Roopa Prabhu <roopa@cumulusnetworks.com>
>
> - ingress hook:
> - if port is a lwt tunnel port, use tunnel info in
> attached dst_metadata to map it to a local vlan
> - egress hook:
> - if port is a lwt tunnel port, use tunnel info attached to
> vlan to set dst_metadata on the skb
>
> CC: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
> Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com>
> ---
> CC'ing Nikolay for some more eyes as he has been trying to keep the
> bridge driver fast path lite.
>
> net/bridge/br_input.c | 4 ++++
> net/bridge/br_private.h | 4 ++++
> net/bridge/br_vlan.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 63 insertions(+)
>
> diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
> index 83f356f..96602a1 100644
> --- a/net/bridge/br_input.c
> +++ b/net/bridge/br_input.c
> @@ -262,6 +262,10 @@ rx_handler_result_t br_handle_frame(struct sk_buff **pskb)
> return RX_HANDLER_CONSUMED;
>
> p = br_port_get_rcu(skb->dev);
> + if (p->flags & BR_LWT_VLAN) {
> + if (br_handle_ingress_vlan_tunnel(skb, p, nbp_vlan_group_rcu(p)))
> + goto drop;
> + }
Is there any reason to do this so early (perhaps netfilter?) ? If not, you can push it to the vlan __allowed_ingress
(and rename that function to something else, it does a hundred additional things)
and avoid this check for all packets if vlans are disabled, thus people using non-vlan filtering
bridge won't have an additional test in their fast path
>
> if (unlikely(is_link_local_ether_addr(dest))) {
> u16 fwd_mask = p->br->group_fwd_mask_required;
> diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
> index f68e360..68a23c5 100644
> --- a/net/bridge/br_private.h
> +++ b/net/bridge/br_private.h
> @@ -804,6 +804,10 @@ int __vlan_tunnel_info_del(struct net_bridge_vlan_group *vg,
> int nbp_vlan_tunnel_info_add(struct net_bridge_port *port, u16 vid, u32 tun_id);
> bool vlan_tunnel_id_isrange(struct net_bridge_vlan *v_end,
> struct net_bridge_vlan *v);
> +int br_handle_ingress_vlan_tunnel(struct sk_buff *skb, struct net_bridge_port *p,
> + struct net_bridge_vlan_group *vg);
> +int br_handle_egress_vlan_tunnel(struct sk_buff *skb,
> + struct net_bridge_vlan *vlan);
>
> static inline struct net_bridge_vlan_group *br_vlan_group(
> const struct net_bridge *br)
> diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c
> index 2040f08..6cf2344 100644
> --- a/net/bridge/br_vlan.c
> +++ b/net/bridge/br_vlan.c
> @@ -405,6 +405,11 @@ struct sk_buff *br_handle_vlan(struct net_bridge *br,
>
> if (v->flags & BRIDGE_VLAN_INFO_UNTAGGED)
> skb->vlan_tci = 0;
> +
> + if (br_handle_egress_vlan_tunnel(skb, v)) {
> + kfree_skb(skb);
> + return NULL;
> + }
> out:
> return skb;
> }
> @@ -1213,3 +1218,53 @@ int nbp_vlan_tunnel_info_delete(struct net_bridge_port *port, u16 vid)
>
> return 0;
> }
> +
> +int br_handle_ingress_vlan_tunnel(struct sk_buff *skb,
> + struct net_bridge_port *p,
> + struct net_bridge_vlan_group *vg)
> +{
> + struct ip_tunnel_info *tinfo = skb_tunnel_info(skb);
> + struct net_bridge_vlan *vlan;
> +
> + if (!vg || !tinfo)
> + return 0;
> +
> + /* if already tagged, ignore */
> + if (skb_vlan_tagged(skb))
> + return 0;
> +
> + /* lookup vid, given tunnel id */
> + vlan = br_vlan_tunnel_lookup(&vg->tunnel_hash, tinfo->key.tun_id);
> + if (!vlan)
> + return 0;
> +
> + skb_dst_drop(skb);
> +
> + __vlan_hwaccel_put_tag(skb, p->br->vlan_proto, vlan->vid);
> +
> + return 0;
> +}
> +
> +int br_handle_egress_vlan_tunnel(struct sk_buff *skb,
> + struct net_bridge_vlan *vlan)
> +{
> + __be32 tun_id;
> + int err;
> +
> + if (!vlan || !vlan->tinfo.tunnel_id)
> + return 0;
> +
> + if (unlikely(!skb_vlan_tag_present(skb)))
> + return 0;
> +
> + skb_dst_drop(skb);
> + tun_id = tunnel_id_to_key32(vlan->tinfo.tunnel_id);
> +
> + err = skb_vlan_pop(skb);
> + if (err)
> + return err;
> +
> + skb_dst_set(skb, dst_clone(&vlan->tinfo.tunnel_dst->dst));
> +
> + return 0;
> +}
>
^ permalink raw reply
* Re: [PATCH net 1/1] net sched actions: fix refcnt when GETing of action after bind
From: Jamal Hadi Salim @ 2017-01-22 12:56 UTC (permalink / raw)
To: Cong Wang; +Cc: David Miller, Linux Kernel Network Developers
In-Reply-To: <CAM_iQpXZqgcSbK2A0_RYmZxmawNgM9RtUsA2Bf0Jf91meu2SWg@mail.gmail.com>
On 17-01-20 01:20 AM, Cong Wang wrote:
> On Wed, Jan 18, 2017 at 3:33 AM, Jamal Hadi Salim <jhs@mojatatu.com> wrote:
>> On 17-01-17 01:17 PM, Cong Wang wrote:
>>>
>> I did.
>> The issue there (after your original patch) was destroy() would
>> decrement the refcount to zero and a GET was essentially translated
>> to a DEL. Incrementing the refcount earlier protected against that
>> assuming destroy was going to decrement it.
>> However, when an action is bound the destroy() doesnt decrement
>> the refcnt. So the refcnt keeps going up forever (and therefore
>> deleting fails in the future). So we cant use destroy() as is.
>
> Hmm, tcf_action_destroy() should not touch the refcnt at all in this case,
> right? Since the refcnt here is not for readers in kernel code but for
> user-space. We mix the use of this refcnt, which leads to problems.
>
> Your patch is not correct either for DEL, tcf_action_destroy() is not
> needed to call again after tcf_del_notify() fails, right? Probably
> it is not needed at all:
Cong,
Please proceed to separate del from get. The trickery is biting us.
Also - run those tests i had in my patch. There is a difference
between the bound vs not-bound use cases.
cheers,
jamal
^ permalink raw reply
* [PATCH net-next v5 0/1] Add support for tc cookies
From: Jamal Hadi Salim @ 2017-01-22 12:51 UTC (permalink / raw)
To: davem
Cc: netdev, jiri, paulb, john.fastabend, simon.horman, mrv, hadarh,
ogerlitz, roid, xiyou.wangcong, daniel, Jamal Hadi Salim
From: Jamal Hadi Salim <jhs@mojatatu.com>
Changes in V5:
- kill the stylistic changes
- Adopt a new structure with length-valuepointer representation
- rename some things
Changes in v4:
- move stylistic changes out into a separate patch
(and add more stylistic changes)
Changes in v3:
- use TC_ prefix for the max size
- move the cookie struct so visible only to kernel
- remove unneeded void * cast
Changes in V2:
-move from a union to a length-value representation
Jamal Hadi Salim (1):
net sched actions: Add support for user cookies
include/net/act_api.h | 1 +
include/net/pkt_cls.h | 8 ++++++++
include/uapi/linux/pkt_cls.h | 3 +++
net/sched/act_api.c | 35 +++++++++++++++++++++++++++++++++++
4 files changed, 47 insertions(+)
--
1.9.1
^ permalink raw reply
* [PATCH net-next v5 1/1] net sched actions: Add support for user cookies
From: Jamal Hadi Salim @ 2017-01-22 12:51 UTC (permalink / raw)
To: davem
Cc: netdev, jiri, paulb, john.fastabend, simon.horman, mrv, hadarh,
ogerlitz, roid, xiyou.wangcong, daniel, Jamal Hadi Salim
In-Reply-To: <1485089498-6673-1-git-send-email-jhs@emojatatu.com>
From: Jamal Hadi Salim <jhs@mojatatu.com>
Introduce optional 128-bit action cookie.
Like all other cookie schemes in the networking world (eg in protocols
like http or existing kernel fib protocol field, etc) the idea is to save
user state that when retrieved serves as a correlator. The kernel
_should not_ intepret it. The user can store whatever they wish in the
128 bits.
Sample exercise(showing variable length use of cookie)
.. create an accept action with cookie a1b2c3d4
sudo $TC actions add action ok index 1 cookie a1b2c3d4
.. dump all gact actions..
sudo $TC -s actions ls action gact
action order 0: gact action pass
random type none pass val 0
index 1 ref 1 bind 0 installed 5 sec used 5 sec
Action statistics:
Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
backlog 0b 0p requeues 0
cookie a1b2c3d4
.. bind the accept action to a filter..
sudo $TC filter add dev lo parent ffff: protocol ip prio 1 \
u32 match ip dst 127.0.0.1/32 flowid 1:1 action gact index 1
... send some traffic..
$ ping 127.0.0.1 -c 3
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.020 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.027 ms
64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.038 ms
--- 127.0.0.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2109ms
rtt min/avg/max/mdev = 0.020/0.028/0.038/0.008 ms 1
... show some stats
$ sudo $TC -s actions get action gact index 1
action order 1: gact action pass
random type none pass val 0
index 1 ref 2 bind 1 installed 204 sec used 5 sec
Action statistics:
Sent 12168 bytes 164 pkt (dropped 0, overlimits 0 requeues 0)
backlog 0b 0p requeues 0
cookie a1b2c3d4
.. try longer cookie...
$ sudo $TC actions replace action ok index 1 cookie 1234567890abcdef
.. dump..
$ sudo $TC -s actions ls action gact
action order 1: gact action pass
random type none pass val 0
index 1 ref 2 bind 1 installed 204 sec used 5 sec
Action statistics:
Sent 12168 bytes 164 pkt (dropped 0, overlimits 0 requeues 0)
backlog 0b 0p requeues 0
cookie 1234567890abcdef
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
---
include/net/act_api.h | 1 +
include/net/pkt_cls.h | 8 ++++++++
include/uapi/linux/pkt_cls.h | 3 +++
net/sched/act_api.c | 35 +++++++++++++++++++++++++++++++++++
4 files changed, 47 insertions(+)
diff --git a/include/net/act_api.h b/include/net/act_api.h
index 1d71644..cfa2ae3 100644
--- a/include/net/act_api.h
+++ b/include/net/act_api.h
@@ -41,6 +41,7 @@ struct tc_action {
struct rcu_head tcfa_rcu;
struct gnet_stats_basic_cpu __percpu *cpu_bstats;
struct gnet_stats_queue __percpu *cpu_qstats;
+ struct tc_cookie *act_cookie;
};
#define tcf_head common.tcfa_head
#define tcf_index common.tcfa_index
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index f0a0514..b43077e 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -515,4 +515,12 @@ struct tc_cls_bpf_offload {
u32 gen_flags;
};
+
+/* This structure holds cookie structure that is passed from user
+ * to the kernel for actions and classifiers
+ */
+struct tc_cookie {
+ u8 *data;
+ u32 len;
+};
#endif
diff --git a/include/uapi/linux/pkt_cls.h b/include/uapi/linux/pkt_cls.h
index fd373eb..345551e 100644
--- a/include/uapi/linux/pkt_cls.h
+++ b/include/uapi/linux/pkt_cls.h
@@ -4,6 +4,8 @@
#include <linux/types.h>
#include <linux/pkt_sched.h>
+#define TC_COOKIE_MAX_SIZE 16
+
/* Action attributes */
enum {
TCA_ACT_UNSPEC,
@@ -12,6 +14,7 @@ enum {
TCA_ACT_INDEX,
TCA_ACT_STATS,
TCA_ACT_PAD,
+ TCA_ACT_COOKIE,
__TCA_ACT_MAX
};
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index cd08df9..84052630 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -24,6 +24,7 @@
#include <net/net_namespace.h>
#include <net/sock.h>
#include <net/sch_generic.h>
+#include <net/pkt_cls.h>
#include <net/act_api.h>
#include <net/netlink.h>
@@ -33,6 +34,8 @@ static void free_tcf(struct rcu_head *head)
free_percpu(p->cpu_bstats);
free_percpu(p->cpu_qstats);
+ kfree(p->act_cookie->data);
+ kfree(p->act_cookie);
kfree(p);
}
@@ -475,6 +478,12 @@ int tcf_action_destroy(struct list_head *actions, int bind)
goto nla_put_failure;
if (tcf_action_copy_stats(skb, a, 0))
goto nla_put_failure;
+ if (a->act_cookie) {
+ if (nla_put(skb, TCA_ACT_COOKIE, a->act_cookie->len,
+ a->act_cookie->data))
+ goto nla_put_failure;
+ }
+
nest = nla_nest_start(skb, TCA_OPTIONS);
if (nest == NULL)
goto nla_put_failure;
@@ -575,6 +584,32 @@ struct tc_action *tcf_action_init_1(struct net *net, struct nlattr *nla,
if (err < 0)
goto err_mod;
+ if (tb[TCA_ACT_COOKIE]) {
+ int cklen = nla_len(tb[TCA_ACT_COOKIE]);
+
+ if (cklen > TC_COOKIE_MAX_SIZE) {
+ err = -EINVAL;
+ tcf_hash_release(a, bind);
+ goto err_mod;
+ }
+
+ a->act_cookie = kzalloc(sizeof(*a->act_cookie), GFP_KERNEL);
+ if (!a->act_cookie) {
+ err = -ENOMEM;
+ tcf_hash_release(a, bind);
+ goto err_mod;
+ }
+
+ a->act_cookie->data = nla_memdup(tb[TCA_ACT_COOKIE],
+ GFP_KERNEL);
+ if (!a->act_cookie->data) {
+ err = -ENOMEM;
+ tcf_hash_release(a, bind);
+ goto err_mod;
+ }
+ a->act_cookie->len = cklen;
+ }
+
/* module count goes up only when brand new policy is created
* if it exists and is only bound to in a_o->init() then
* ACT_P_CREATED is not returned (a zero is).
--
1.9.1
^ permalink raw reply related
* Re: [PATCH net-next v5 0/1] Add support for tc cookies
From: Jamal Hadi Salim @ 2017-01-22 12:54 UTC (permalink / raw)
To: davem
Cc: netdev, jiri, paulb, john.fastabend, simon.horman, mrv, hadarh,
ogerlitz, roid, xiyou.wangcong, daniel
In-Reply-To: <1485089498-6673-1-git-send-email-jhs@emojatatu.com>
I removed people's reviewed/Acked because i changed the data structure
per Daniel's suggestions.
cheers,
jamal
On 17-01-22 07:51 AM, Jamal Hadi Salim wrote:
> From: Jamal Hadi Salim <jhs@mojatatu.com>
>
> Changes in V5:
> - kill the stylistic changes
> - Adopt a new structure with length-valuepointer representation
> - rename some things
>
> Changes in v4:
> - move stylistic changes out into a separate patch
> (and add more stylistic changes)
>
> Changes in v3:
> - use TC_ prefix for the max size
> - move the cookie struct so visible only to kernel
> - remove unneeded void * cast
>
> Changes in V2:
> -move from a union to a length-value representation
>
> Jamal Hadi Salim (1):
> net sched actions: Add support for user cookies
>
> include/net/act_api.h | 1 +
> include/net/pkt_cls.h | 8 ++++++++
> include/uapi/linux/pkt_cls.h | 3 +++
> net/sched/act_api.c | 35 +++++++++++++++++++++++++++++++++++
> 4 files changed, 47 insertions(+)
>
^ permalink raw reply
* Re: [patch net-next 2/4] net/sched: Introduce sample tc action
From: Jamal Hadi Salim @ 2017-01-22 13:16 UTC (permalink / raw)
To: Jiri Pirko, netdev
Cc: davem, yotamg, idosch, eladr, nogahf, ogerlitz, geert+renesas,
stephen, xiyou.wangcong, linux, roopa, john.fastabend,
simon.horman, mrv
In-Reply-To: <1485085487-2652-3-git-send-email-jiri@resnulli.us>
On 17-01-22 06:44 AM, Jiri Pirko wrote:
> diff --git a/net/sched/act_sample.c b/net/sched/act_sample.c
> new file mode 100644
> index 0000000..24e20e4
> --- /dev/null
> +++ b/net/sched/act_sample.c
> @@ -0,0 +1,274 @@
> +/*
> + * net/sched/act_sample.c - Packet samplig tc action
typo: "Sampling"
> +static int tcf_sample(struct sk_buff *skb, const struct tc_action *a,
> + struct tcf_result *res)
Can you rename this function because it is also the name of the data
structure? It makes it easier to grep.
I know we have this all over the place in other actions (and i hope
those are cleaned up at some point).
otherwise:
Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
cheers,
jamal
^ permalink raw reply
* Re: [patch net-next 1/4] net: Introduce psample, a new genetlink channel for packet sampling
From: Jamal Hadi Salim @ 2017-01-22 13:19 UTC (permalink / raw)
To: Jiri Pirko, netdev
Cc: davem, yotamg, idosch, eladr, nogahf, ogerlitz, geert+renesas,
stephen, xiyou.wangcong, linux, roopa, john.fastabend,
simon.horman, mrv
In-Reply-To: <1485085487-2652-2-git-send-email-jiri@resnulli.us>
On 17-01-22 06:44 AM, Jiri Pirko wrote:
> From: Yotam Gigi <yotamg@mellanox.com>
>
> Add a general way for kernel modules to sample packets, without being tied
> to any specific subsystem. This netlink channel can be used by tc,
> iptables, etc. and allow to standardize packet sampling in the kernel.
>
> For every sampled packet, the psample module adds the following metadata
> fields:
>
> PSAMPLE_ATTR_IIFINDEX - the packets input ifindex, if applicable
>
> PSAMPLE_ATTR_OIFINDEX - the packet output ifindex, if applicable
>
> PSAMPLE_ATTR_ORIGSIZE - the packet's original size, in case it has been
> truncated during sampling
>
> PSAMPLE_ATTR_SAMPLE_GROUP - the packet's sample group, which is set by the
> user who initiated the sampling. This field allows the user to
> differentiate between several samplers working simultaneously and
> filter packets relevant to him
>
> PSAMPLE_ATTR_GROUP_SEQ - sequence counter of last sent packet. The
> sequence is kept for each group
>
> PSAMPLE_ATTR_SAMPLE_RATE - the sampling rate used for sampling the packets
>
> PSAMPLE_ATTR_DATA - the actual packet bits
>
> In addition, add the GET_GROUPS netlink command which allows the user to
> see the current sample groups, their refcount and sequence number. This
> command currently supports only netlink dump mode.
>
> Signed-off-by: Yotam Gigi <yotamg@mellanox.com>
> Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Will be useful to describe in the commit log that one needs to listen
to PSAMPLE_NL_MCGRP_SAMPLE to see the samples.
Reviewed-by: Jamal Hadi Salim <jhs@mojatatu.com>
cheers,
jamal
^ permalink raw reply
* Re: [net, 6/6] net: korina: version bump
From: Felix Fietkau @ 2017-01-22 13:21 UTC (permalink / raw)
To: Roman Yeryomin; +Cc: netdev
In-Reply-To: <CACiydbKPNZyN+_+TDkHsbg0uGR51iDcqSTAQUMKyVCJ+u9wL7w@mail.gmail.com>
On 2017-01-22 13:10, Roman Yeryomin wrote:
> On 17 January 2017 at 21:19, Roman Yeryomin <leroi.lists@gmail.com> wrote:
>> On 17 January 2017 at 20:55, Felix Fietkau <nbd@nbd.name> wrote:
>>> On 2017-01-17 18:33, Roman Yeryomin wrote:
>>>> Signed-off-by: Roman Yeryomin <roman@advem.lv>
>>>> ---
>>>> drivers/net/ethernet/korina.c | 4 ++--
>>>> 1 file changed, 2 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/drivers/net/ethernet/korina.c b/drivers/net/ethernet/korina.c
>>>> index 83c994f..c8fed01 100644
>>>> --- a/drivers/net/ethernet/korina.c
>>>> +++ b/drivers/net/ethernet/korina.c
>>>> @@ -66,8 +66,8 @@
>>>> #include <asm/mach-rc32434/dma_v.h>
>>>>
>>>> #define DRV_NAME "korina"
>>>> -#define DRV_VERSION "0.10"
>>>> -#define DRV_RELDATE "04Mar2008"
>>>> +#define DRV_VERSION "0.20"
>>>> +#define DRV_RELDATE "15Jan2017"
>>> I think it would make more sense to remove this version instead of
>>> bumping it. Individual driver versions are rather pointless, the kernel
>>> version is more meaningful anyway.
>>
>> OK, makes sense
>
> Actually, after thinking a bit more about this, not really...
> How about ethtool, which uses driver name and version?
> I see most ethernet drivers define some version. And it's pretty
> useful, when using backports.
> IMO, it should be kept and bumped.
I don't really care, I just wanted to point out that the exact kernel
version is a much more useful indicator, especially since not all patch
submitters do the useless version bump dance.
- Felix
^ permalink raw reply
* RE: [patch net-next 2/4] net/sched: Introduce sample tc action
From: Yotam Gigi @ 2017-01-22 13:28 UTC (permalink / raw)
To: Jamal Hadi Salim, Jiri Pirko, netdev@vger.kernel.org
Cc: davem@davemloft.net, Ido Schimmel, Elad Raz, Nogah Frankel,
Or Gerlitz, geert+renesas@glider.be, stephen@networkplumber.org,
xiyou.wangcong@gmail.com, linux@roeck-us.net,
roopa@cumulusnetworks.com, john.fastabend@gmail.com,
simon.horman@netronome.com, mrv@mojatatu.com
In-Reply-To: <52d57d84-6e0d-0ff3-5027-6dea06f4a683@mojatatu.com>
>-----Original Message-----
>From: Jamal Hadi Salim [mailto:jhs@mojatatu.com]
>Sent: Sunday, January 22, 2017 3:17 PM
>To: Jiri Pirko <jiri@resnulli.us>; netdev@vger.kernel.org
>Cc: davem@davemloft.net; Yotam Gigi <yotamg@mellanox.com>; Ido Schimmel
><idosch@mellanox.com>; Elad Raz <eladr@mellanox.com>; Nogah Frankel
><nogahf@mellanox.com>; Or Gerlitz <ogerlitz@mellanox.com>;
>geert+renesas@glider.be; stephen@networkplumber.org;
>xiyou.wangcong@gmail.com; linux@roeck-us.net; roopa@cumulusnetworks.com;
>john.fastabend@gmail.com; simon.horman@netronome.com; mrv@mojatatu.com
>Subject: Re: [patch net-next 2/4] net/sched: Introduce sample tc action
>
>On 17-01-22 06:44 AM, Jiri Pirko wrote:
>
>> diff --git a/net/sched/act_sample.c b/net/sched/act_sample.c
>> new file mode 100644
>> index 0000000..24e20e4
>> --- /dev/null
>> +++ b/net/sched/act_sample.c
>> @@ -0,0 +1,274 @@
>> +/*
>> + * net/sched/act_sample.c - Packet samplig tc action
>
>typo: "Sampling"
It took me a while to see it. Will fix :)
>
>
>> +static int tcf_sample(struct sk_buff *skb, const struct tc_action *a,
>> + struct tcf_result *res)
>
>
>Can you rename this function because it is also the name of the data
>structure? It makes it easier to grep.
>I know we have this all over the place in other actions (and i hope
>those are cleaned up at some point).
OK, makes sense.
>
>otherwise:
>Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
Thanks!
>
>cheers,
>jamal
^ permalink raw reply
* [PATCH iproute2 1/1] tc: distinguish Add/Replace action operations.
From: Roman Mashak @ 2017-01-22 13:55 UTC (permalink / raw)
To: stephen; +Cc: netdev, Roman Mashak, Jamal Hadi Salim
Signed-off-by: Roman Mashak <mrv@mojatatu.com>
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
---
tc/m_action.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/tc/m_action.c b/tc/m_action.c
index bb19df8..05ef07e 100644
--- a/tc/m_action.c
+++ b/tc/m_action.c
@@ -365,12 +365,18 @@ int print_action(const struct sockaddr_nl *who,
fprintf(fp, "Flushed table ");
tab_flush = 1;
} else {
- fprintf(fp, "deleted action ");
+ fprintf(fp, "Deleted action ");
}
}
- if (n->nlmsg_type == RTM_NEWACTION)
- fprintf(fp, "Added action ");
+ if (n->nlmsg_type == RTM_NEWACTION) {
+ if ((n->nlmsg_flags & NLM_F_CREATE) &&
+ !(n->nlmsg_flags & NLM_F_REPLACE)) {
+ fprintf(fp, "Added action ");
+ } else if (n->nlmsg_flags & NLM_F_REPLACE) {
+ fprintf(fp, "Replaced action ");
+ }
+ }
tc_print_action(fp, tb[TCA_ACT_TAB]);
return 0;
--
1.9.1
^ permalink raw reply related
* Re: [patch net-next 2/4] net/sched: Introduce sample tc action
From: Roman Mashak @ 2017-01-22 14:29 UTC (permalink / raw)
To: Jiri Pirko
Cc: netdev, davem, yotamg, idosch, eladr, nogahf, ogerlitz, jhs,
geert+renesas, stephen, xiyou.wangcong, linux, roopa,
john.fastabend, simon.horman
In-Reply-To: <1485085487-2652-3-git-send-email-jiri@resnulli.us>
Jiri Pirko <jiri@resnulli.us> writes:
> From: Yotam Gigi <yotamg@mellanox.com>
>
> This action allows the user to sample traffic matched by tc classifier.
> The sampling consists of choosing packets randomly and sampling them using
> the psample module. The user can configure the psample group number, the
> sampling rate and the packet's truncation (to save kernel-user traffic).
>
[skip]
> diff --git a/include/uapi/linux/tc_act/tc_sample.h b/include/uapi/linux/tc_act/tc_sample.h
> new file mode 100644
> index 0000000..21378bc
> --- /dev/null
> +++ b/include/uapi/linux/tc_act/tc_sample.h
> @@ -0,0 +1,26 @@
> +#ifndef __LINUX_TC_SAMPLE_H
> +#define __LINUX_TC_SAMPLE_H
> +
> +#include <linux/types.h>
> +#include <linux/pkt_cls.h>
> +#include <linux/if_ether.h>
> +
> +#define TCA_ACT_SAMPLE 26
> +
> +struct tc_sample {
> + tc_gen;
> +};
> +
> +enum {
> + TCA_SAMPLE_UNSPEC,
> + TCA_SAMPLE_PARMS,
> + TCA_SAMPLE_TM,
> + TCA_SAMPLE_RATE,
> + TCA_SAMPLE_TRUNC_SIZE,
> + TCA_SAMPLE_PSAMPLE_GROUP,
> + TCA_SAMPLE_PAD,
> + __TCA_SAMPLE_MAX
> +};
Most of action implementations define TCA_X_TM attribute as 1,
and TCA_X_PARMS as 2 followed by action specific tlvs, it is better to
adhere this style in newly designed actions.
[skip]
--
Roman Mashak
^ permalink raw reply
* Re: [PATCH] net/mlx4: use rb_entry()
From: Geliang Tang @ 2017-01-22 14:42 UTC (permalink / raw)
To: Leon Romanovsky; +Cc: Yishai Hadas, netdev, linux-rdma, linux-kernel
In-Reply-To: <20170122074839.GD28570@mtr-leonro.local>
On Sun, Jan 22, 2017 at 09:48:39AM +0200, Leon Romanovsky wrote:
> On Fri, Jan 20, 2017 at 10:36:57PM +0800, Geliang Tang wrote:
> > To make the code clearer, use rb_entry() instead of container_of() to
> > deal with rbtree.
> >
> > Signed-off-by: Geliang Tang <geliangtang@gmail.com>
> > ---
> > drivers/net/ethernet/mellanox/mlx4/resource_tracker.c | 8 ++++----
> > 1 file changed, 4 insertions(+), 4 deletions(-)
>
> I don't understand completely the rationale behind this conversion.
> rb_entry == container_of, why do we need another name for it?
>
There are several *_entry macros which are defined in kernel data
structures, like list_entry, hlist_entry, rb_entry, etc. Each of them is
just another name for container_of. We use different *_entry so that we
could identify the specific type of data structure that we are dealing
with.
-Geliang
^ permalink raw reply
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