* [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
* 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
* 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: [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: [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: [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
* [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
* [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 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 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 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
* 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
* 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: [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
* [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
* [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
* Re: [PATCH net] virtio-net: restore VIRTIO_HDR_F_DATA_VALID on receiving
From: Jason Wang @ 2017-01-22 8:18 UTC (permalink / raw)
To: Michael S. Tsirkin; +Cc: netdev, Rolf Neugebauer, linux-kernel, virtualization
In-Reply-To: <20170122061838-mutt-send-email-mst@kernel.org>
On 2017年01月22日 12:22, Michael S. Tsirkin wrote:
> On Sun, Jan 22, 2017 at 10:41:22AM +0800, Jason Wang wrote:
>>
>> On 2017年01月21日 00:45, Michael S. Tsirkin wrote:
>>> On Fri, Jan 20, 2017 at 02:32:42PM +0800, Jason Wang wrote:
>>>> Commit 501db511397f ("virtio: don't set VIRTIO_NET_HDR_F_DATA_VALID on
>>>> xmit") in fact disables VIRTIO_HDR_F_DATA_VALID on receiving path too,
>>>> fixing this by adding a hint (has_data_valid) and set it only on the
>>>> receiving path.
>>>>
>>>> Cc: Rolf Neugebauer<rolf.neugebauer@docker.com>
>>>> Signed-off-by: Jason Wang<jasowang@redhat.com>
>>>> ---
>>>> drivers/net/macvtap.c | 2 +-
>>>> drivers/net/tun.c | 2 +-
>>>> drivers/net/virtio_net.c | 2 +-
>>>> include/linux/virtio_net.h | 6 +++++-
>>>> net/packet/af_packet.c | 4 ++--
>>>> 5 files changed, 10 insertions(+), 6 deletions(-)
>>>>
>>>> diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
>>>> index 5c26653..4026185 100644
>>>> --- a/drivers/net/macvtap.c
>>>> +++ b/drivers/net/macvtap.c
>>>> @@ -825,7 +825,7 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q,
>>>> return -EINVAL;
>>>> if (virtio_net_hdr_from_skb(skb, &vnet_hdr,
>>>> - macvtap_is_little_endian(q)))
>>>> + macvtap_is_little_endian(q), true))
>>>> BUG();
>>>> if (copy_to_iter(&vnet_hdr, sizeof(vnet_hdr), iter) !=
>>>> diff --git a/drivers/net/tun.c b/drivers/net/tun.c
>>>> index cd8e02c..2cd10b2 100644
>>>> --- a/drivers/net/tun.c
>>>> +++ b/drivers/net/tun.c
>>>> @@ -1360,7 +1360,7 @@ static ssize_t tun_put_user(struct tun_struct *tun,
>>>> return -EINVAL;
>>>> if (virtio_net_hdr_from_skb(skb, &gso,
>>>> - tun_is_little_endian(tun))) {
>>>> + tun_is_little_endian(tun), true)) {
>>>> struct skb_shared_info *sinfo = skb_shinfo(skb);
>>>> pr_err("unexpected GSO type: "
>>>> "0x%x, gso_size %d, hdr_len %d\n",
>>>> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
>>>> index 4a10500..3474243 100644
>>>> --- a/drivers/net/virtio_net.c
>>>> +++ b/drivers/net/virtio_net.c
>>>> @@ -1104,7 +1104,7 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
>>>> hdr = skb_vnet_hdr(skb);
>>>> if (virtio_net_hdr_from_skb(skb, &hdr->hdr,
>>>> - virtio_is_little_endian(vi->vdev)))
>>>> + virtio_is_little_endian(vi->vdev), false))
>>>> BUG();
>>>> if (vi->mergeable_rx_bufs)
>>>> diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h
>>>> index 5643647..5209b5e 100644
>>>> --- a/include/linux/virtio_net.h
>>>> +++ b/include/linux/virtio_net.h
>>>> @@ -56,7 +56,8 @@ static inline int virtio_net_hdr_to_skb(struct sk_buff *skb,
>>>> static inline int virtio_net_hdr_from_skb(const struct sk_buff *skb,
>>>> struct virtio_net_hdr *hdr,
>>>> - bool little_endian)
>>>> + bool little_endian,
>>>> + bool has_data_valid)
>>>> {
>>>> memset(hdr, 0, sizeof(*hdr)); /* no info leak */
>>> I would prefer naming it is_rx. Callers should not know about
>>> internal details like data valid, the issue we are trying to fix
>>> here is that tx and tx headers are slightly different.
>>>
>> Actually, I've considered something like this, but the problem is:
>>
>> - tun use this on xmit, so is_rx = true may cause some confusion here
> tun is generally weird, yes. how about rx_format?
Ok.
>
>> - I believe we may want to support DATA_VALID (like xen-netback) on tx
>> (probably with a feature) in the future.
>>
>> Thanks
> We'll put that knowledge within virtio_net_hdr_from_skb not
> in the callers I think.
>
Maybe, will prepare a patch for net-next.
Thanks
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
^ permalink raw reply
* Re: [PATCH] net/mlx4: use rb_entry()
From: Leon Romanovsky @ 2017-01-22 7:48 UTC (permalink / raw)
To: Geliang Tang; +Cc: Yishai Hadas, netdev, linux-rdma, linux-kernel
In-Reply-To: <6c1c772de8f70113580dade04f89a377174d8c88.1484817025.git.geliangtang@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 1750 bytes --]
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?
>
> diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
> index 1822382..6da6e01 100644
> --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
> +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
> @@ -236,8 +236,8 @@ static void *res_tracker_lookup(struct rb_root *root, u64 res_id)
> struct rb_node *node = root->rb_node;
>
> while (node) {
> - struct res_common *res = container_of(node, struct res_common,
> - node);
> + struct res_common *res = rb_entry(node, struct res_common,
> + node);
>
> if (res_id < res->res_id)
> node = node->rb_left;
> @@ -255,8 +255,8 @@ static int res_tracker_insert(struct rb_root *root, struct res_common *res)
>
> /* Figure out where to put new node */
> while (*new) {
> - struct res_common *this = container_of(*new, struct res_common,
> - node);
> + struct res_common *this = rb_entry(*new, struct res_common,
> + node);
>
> parent = *new;
> if (res->res_id < this->res_id)
> --
> 2.9.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* [PULL] vhost/virtio: cleanups and fixes
From: Michael S. Tsirkin @ 2017-01-22 7:35 UTC (permalink / raw)
To: Linus Torvalds
Cc: gcampana, kvm, mst, netdev, pmorel, linux-kernel, virtualization,
dan.carpenter, colin.king, bhumirks, silbe
The following changes since commit 49def1853334396f948dcb4cedb9347abb318df5:
Linux 4.10-rc4 (2017-01-15 16:21:59 -0800)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost.git tags/for_linus
for you to fetch changes up to 0db1dba5dfaf70fb3baf07973996db2078528cde:
virtio/s390: virtio: constify virtio_config_ops structures (2017-01-19 23:46:34 +0200)
----------------------------------------------------------------
virtio, vhost: fixes, cleanups
Random fixes and cleanups that accumulated over the time.
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
----------------------------------------------------------------
Bhumika Goyal (2):
vhost: scsi: constify target_core_fabric_ops structures
virtio/s390: virtio: constify virtio_config_ops structures
Colin Ian King (1):
virtio/s390: add missing \n to end of dev_err message
Dan Carpenter (1):
vhost/scsi: silence uninitialized variable warning
G. Campana (1):
virtio_console: fix a crash in config_work_handler
Halil Pasic (2):
tools/virtio/ringtest: fix run-on-all.sh for offline cpus
tools/virtio/ringtest: tweaks for s390
Pierre Morel (1):
virtio/s390: support READ_STATUS command for virtio-ccw
drivers/char/virtio_console.c | 2 +-
drivers/s390/virtio/virtio_ccw.c | 29 +++++++++++++++++++++++++++--
drivers/vhost/scsi.c | 4 ++--
tools/virtio/ringtest/main.h | 12 ++++++++++++
tools/virtio/ringtest/run-on-all.sh | 5 +++--
5 files changed, 45 insertions(+), 7 deletions(-)
^ permalink raw reply
* Re: [PATCH net] virtio-net: restore VIRTIO_HDR_F_DATA_VALID on receiving
From: Michael S. Tsirkin @ 2017-01-22 4:22 UTC (permalink / raw)
To: Jason Wang; +Cc: netdev, linux-kernel, virtualization, Rolf Neugebauer
In-Reply-To: <268cadeb-433c-7960-5fe6-a06f849493a8@redhat.com>
On Sun, Jan 22, 2017 at 10:41:22AM +0800, Jason Wang wrote:
>
>
> On 2017年01月21日 00:45, Michael S. Tsirkin wrote:
> > On Fri, Jan 20, 2017 at 02:32:42PM +0800, Jason Wang wrote:
> > > Commit 501db511397f ("virtio: don't set VIRTIO_NET_HDR_F_DATA_VALID on
> > > xmit") in fact disables VIRTIO_HDR_F_DATA_VALID on receiving path too,
> > > fixing this by adding a hint (has_data_valid) and set it only on the
> > > receiving path.
> > >
> > > Cc: Rolf Neugebauer<rolf.neugebauer@docker.com>
> > > Signed-off-by: Jason Wang<jasowang@redhat.com>
> > > ---
> > > drivers/net/macvtap.c | 2 +-
> > > drivers/net/tun.c | 2 +-
> > > drivers/net/virtio_net.c | 2 +-
> > > include/linux/virtio_net.h | 6 +++++-
> > > net/packet/af_packet.c | 4 ++--
> > > 5 files changed, 10 insertions(+), 6 deletions(-)
> > >
> > > diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
> > > index 5c26653..4026185 100644
> > > --- a/drivers/net/macvtap.c
> > > +++ b/drivers/net/macvtap.c
> > > @@ -825,7 +825,7 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q,
> > > return -EINVAL;
> > > if (virtio_net_hdr_from_skb(skb, &vnet_hdr,
> > > - macvtap_is_little_endian(q)))
> > > + macvtap_is_little_endian(q), true))
> > > BUG();
> > > if (copy_to_iter(&vnet_hdr, sizeof(vnet_hdr), iter) !=
> > > diff --git a/drivers/net/tun.c b/drivers/net/tun.c
> > > index cd8e02c..2cd10b2 100644
> > > --- a/drivers/net/tun.c
> > > +++ b/drivers/net/tun.c
> > > @@ -1360,7 +1360,7 @@ static ssize_t tun_put_user(struct tun_struct *tun,
> > > return -EINVAL;
> > > if (virtio_net_hdr_from_skb(skb, &gso,
> > > - tun_is_little_endian(tun))) {
> > > + tun_is_little_endian(tun), true)) {
> > > struct skb_shared_info *sinfo = skb_shinfo(skb);
> > > pr_err("unexpected GSO type: "
> > > "0x%x, gso_size %d, hdr_len %d\n",
> > > diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> > > index 4a10500..3474243 100644
> > > --- a/drivers/net/virtio_net.c
> > > +++ b/drivers/net/virtio_net.c
> > > @@ -1104,7 +1104,7 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
> > > hdr = skb_vnet_hdr(skb);
> > > if (virtio_net_hdr_from_skb(skb, &hdr->hdr,
> > > - virtio_is_little_endian(vi->vdev)))
> > > + virtio_is_little_endian(vi->vdev), false))
> > > BUG();
> > > if (vi->mergeable_rx_bufs)
> > > diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h
> > > index 5643647..5209b5e 100644
> > > --- a/include/linux/virtio_net.h
> > > +++ b/include/linux/virtio_net.h
> > > @@ -56,7 +56,8 @@ static inline int virtio_net_hdr_to_skb(struct sk_buff *skb,
> > > static inline int virtio_net_hdr_from_skb(const struct sk_buff *skb,
> > > struct virtio_net_hdr *hdr,
> > > - bool little_endian)
> > > + bool little_endian,
> > > + bool has_data_valid)
> > > {
> > > memset(hdr, 0, sizeof(*hdr)); /* no info leak */
> > I would prefer naming it is_rx. Callers should not know about
> > internal details like data valid, the issue we are trying to fix
> > here is that tx and tx headers are slightly different.
> >
>
> Actually, I've considered something like this, but the problem is:
>
> - tun use this on xmit, so is_rx = true may cause some confusion here
tun is generally weird, yes. how about rx_format?
> - I believe we may want to support DATA_VALID (like xen-netback) on tx
> (probably with a feature) in the future.
>
> Thanks
We'll put that knowledge within virtio_net_hdr_from_skb not
in the callers I think.
--
MST
^ permalink raw reply
* Re: [net PATCH v5 6/6] virtio_net: XDP support for adjust_head
From: John Fastabend @ 2017-01-22 4:14 UTC (permalink / raw)
To: Jason Wang, Michael S. Tsirkin, David Laight
Cc: john.r.fastabend@intel.com, netdev@vger.kernel.org,
alexei.starovoitov@gmail.com, daniel@iogearbox.net
In-Reply-To: <bcf017d4-96b9-9ccf-cc7b-06ec9301251d@redhat.com>
On 17-01-21 06:51 PM, Jason Wang wrote:
>
>
> On 2017年01月21日 01:48, Michael S. Tsirkin wrote:
>> On Fri, Jan 20, 2017 at 04:59:11PM +0000, David Laight wrote:
>>> From: Michael S. Tsirkin
>>>> Sent: 19 January 2017 21:12
>>>>> On 2017?01?18? 23:15, Michael S. Tsirkin wrote:
>>>>>> On Tue, Jan 17, 2017 at 02:22:59PM -0800, John Fastabend wrote:
>>>>>>> Add support for XDP adjust head by allocating a 256B header region
>>>>>>> that XDP programs can grow into. This is only enabled when a XDP
>>>>>>> program is loaded.
>>>>>>>
>>>>>>> In order to ensure that we do not have to unwind queue headroom push
>>>>>>> queue setup below bpf_prog_add. It reads better to do a prog ref
>>>>>>> unwind vs another queue setup call.
>>>>>>>
>>>>>>> At the moment this code must do a full reset to ensure old buffers
>>>>>>> without headroom on program add or with headroom on program removal
>>>>>>> are not used incorrectly in the datapath. Ideally we would only
>>>>>>> have to disable/enable the RX queues being updated but there is no
>>>>>>> API to do this at the moment in virtio so use the big hammer. In
>>>>>>> practice it is likely not that big of a problem as this will only
>>>>>>> happen when XDP is enabled/disabled changing programs does not
>>>>>>> require the reset. There is some risk that the driver may either
>>>>>>> have an allocation failure or for some reason fail to correctly
>>>>>>> negotiate with the underlying backend in this case the driver will
>>>>>>> be left uninitialized. I have not seen this ever happen on my test
>>>>>>> systems and for what its worth this same failure case can occur
>>>>>>> from probe and other contexts in virtio framework.
>>>>>>>
>>>>>>> Signed-off-by: John Fastabend<john.r.fastabend@intel.com>
>>>>>> I've been thinking about it - can't we drop
>>>>>> old buffers without the head room which were posted before
>>>>>> xdp attached?
>>>>>>
>>>>>> Avoiding the reset would be much nicer.
>>>>>>
>>>>>> Thoughts?
>>>>>>
>>>>> As been discussed before, device may use them in the same time so it's not
>>>>> safe. Or do you mean detect them after xdp were set and drop the buffer
>>>>> without head room, this looks sub-optimal.
>>>>>
>>>>> Thanks
>>>> Yes, this is what I mean. Why is this suboptimal? It's a single branch
>>>> in code. Yes we might lose some packets but the big hammer of device
>>>> reset will likely lose more.
>>> Why not leave let the hardware receive into the 'small' buffer (without
>>> headroom) and do a copy when a frame is received.
>>> Replace the buffers with 'big' ones for the next receive.
>>> A data copy on a ring full of buffers won't really be noticed.
>>>
>>> David
>>>
>> I like that. John?
>>
>
> This works, I prefer this only if it uses simpler code (but I suspect) than reset.
>
> Thanks
Before the reset path I looked at doing this but it seems to require tracking
if a buffer had headroom on a per buffer basis. I don't see a good spot to
put a bit like this? It could go in the inbuf 'ctx' added by virtqueue_add_inbuf
but I would need to change the current usage of ctx which in the mergeable case
at least is just a simple pointer today. I don't like this because it
complicates the normal path and the XDP hotpath.
Otherwise we could somehow mark the ring at the point where XDP is enabled so
that it can learn when a full iteration around the ring. But I can't see a
simple way to make this work either.
I don't know the reset look straight forward to me and although not ideal is
fairly common on hardware based drivers during configuration changes. I'm open
to any ideas on where to put the metadata to track headroom though.
Thanks,
John
^ permalink raw reply
* Re: [net PATCH v5 6/6] virtio_net: XDP support for adjust_head
From: Jason Wang @ 2017-01-22 2:51 UTC (permalink / raw)
To: Michael S. Tsirkin, David Laight
Cc: John Fastabend, john.r.fastabend@intel.com,
netdev@vger.kernel.org, alexei.starovoitov@gmail.com,
daniel@iogearbox.net
In-Reply-To: <20170120194824-mutt-send-email-mst@kernel.org>
On 2017年01月21日 01:48, Michael S. Tsirkin wrote:
> On Fri, Jan 20, 2017 at 04:59:11PM +0000, David Laight wrote:
>> From: Michael S. Tsirkin
>>> Sent: 19 January 2017 21:12
>>>> On 2017?01?18? 23:15, Michael S. Tsirkin wrote:
>>>>> On Tue, Jan 17, 2017 at 02:22:59PM -0800, John Fastabend wrote:
>>>>>> Add support for XDP adjust head by allocating a 256B header region
>>>>>> that XDP programs can grow into. This is only enabled when a XDP
>>>>>> program is loaded.
>>>>>>
>>>>>> In order to ensure that we do not have to unwind queue headroom push
>>>>>> queue setup below bpf_prog_add. It reads better to do a prog ref
>>>>>> unwind vs another queue setup call.
>>>>>>
>>>>>> At the moment this code must do a full reset to ensure old buffers
>>>>>> without headroom on program add or with headroom on program removal
>>>>>> are not used incorrectly in the datapath. Ideally we would only
>>>>>> have to disable/enable the RX queues being updated but there is no
>>>>>> API to do this at the moment in virtio so use the big hammer. In
>>>>>> practice it is likely not that big of a problem as this will only
>>>>>> happen when XDP is enabled/disabled changing programs does not
>>>>>> require the reset. There is some risk that the driver may either
>>>>>> have an allocation failure or for some reason fail to correctly
>>>>>> negotiate with the underlying backend in this case the driver will
>>>>>> be left uninitialized. I have not seen this ever happen on my test
>>>>>> systems and for what its worth this same failure case can occur
>>>>>> from probe and other contexts in virtio framework.
>>>>>>
>>>>>> Signed-off-by: John Fastabend<john.r.fastabend@intel.com>
>>>>> I've been thinking about it - can't we drop
>>>>> old buffers without the head room which were posted before
>>>>> xdp attached?
>>>>>
>>>>> Avoiding the reset would be much nicer.
>>>>>
>>>>> Thoughts?
>>>>>
>>>> As been discussed before, device may use them in the same time so it's not
>>>> safe. Or do you mean detect them after xdp were set and drop the buffer
>>>> without head room, this looks sub-optimal.
>>>>
>>>> Thanks
>>> Yes, this is what I mean. Why is this suboptimal? It's a single branch
>>> in code. Yes we might lose some packets but the big hammer of device
>>> reset will likely lose more.
>> Why not leave let the hardware receive into the 'small' buffer (without
>> headroom) and do a copy when a frame is received.
>> Replace the buffers with 'big' ones for the next receive.
>> A data copy on a ring full of buffers won't really be noticed.
>>
>> David
>>
> I like that. John?
>
This works, I prefer this only if it uses simpler code (but I suspect)
than reset.
Thanks
^ permalink raw reply
* Re: [PATCH net] virtio-net: restore VIRTIO_HDR_F_DATA_VALID on receiving
From: Jason Wang @ 2017-01-22 2:41 UTC (permalink / raw)
To: Michael S. Tsirkin; +Cc: netdev, Rolf Neugebauer, linux-kernel, virtualization
In-Reply-To: <20170120184220-mutt-send-email-mst@kernel.org>
On 2017年01月21日 00:45, Michael S. Tsirkin wrote:
> On Fri, Jan 20, 2017 at 02:32:42PM +0800, Jason Wang wrote:
>> Commit 501db511397f ("virtio: don't set VIRTIO_NET_HDR_F_DATA_VALID on
>> xmit") in fact disables VIRTIO_HDR_F_DATA_VALID on receiving path too,
>> fixing this by adding a hint (has_data_valid) and set it only on the
>> receiving path.
>>
>> Cc: Rolf Neugebauer<rolf.neugebauer@docker.com>
>> Signed-off-by: Jason Wang<jasowang@redhat.com>
>> ---
>> drivers/net/macvtap.c | 2 +-
>> drivers/net/tun.c | 2 +-
>> drivers/net/virtio_net.c | 2 +-
>> include/linux/virtio_net.h | 6 +++++-
>> net/packet/af_packet.c | 4 ++--
>> 5 files changed, 10 insertions(+), 6 deletions(-)
>>
>> diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
>> index 5c26653..4026185 100644
>> --- a/drivers/net/macvtap.c
>> +++ b/drivers/net/macvtap.c
>> @@ -825,7 +825,7 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q,
>> return -EINVAL;
>>
>> if (virtio_net_hdr_from_skb(skb, &vnet_hdr,
>> - macvtap_is_little_endian(q)))
>> + macvtap_is_little_endian(q), true))
>> BUG();
>>
>> if (copy_to_iter(&vnet_hdr, sizeof(vnet_hdr), iter) !=
>> diff --git a/drivers/net/tun.c b/drivers/net/tun.c
>> index cd8e02c..2cd10b2 100644
>> --- a/drivers/net/tun.c
>> +++ b/drivers/net/tun.c
>> @@ -1360,7 +1360,7 @@ static ssize_t tun_put_user(struct tun_struct *tun,
>> return -EINVAL;
>>
>> if (virtio_net_hdr_from_skb(skb, &gso,
>> - tun_is_little_endian(tun))) {
>> + tun_is_little_endian(tun), true)) {
>> struct skb_shared_info *sinfo = skb_shinfo(skb);
>> pr_err("unexpected GSO type: "
>> "0x%x, gso_size %d, hdr_len %d\n",
>> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
>> index 4a10500..3474243 100644
>> --- a/drivers/net/virtio_net.c
>> +++ b/drivers/net/virtio_net.c
>> @@ -1104,7 +1104,7 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
>> hdr = skb_vnet_hdr(skb);
>>
>> if (virtio_net_hdr_from_skb(skb, &hdr->hdr,
>> - virtio_is_little_endian(vi->vdev)))
>> + virtio_is_little_endian(vi->vdev), false))
>> BUG();
>>
>> if (vi->mergeable_rx_bufs)
>> diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h
>> index 5643647..5209b5e 100644
>> --- a/include/linux/virtio_net.h
>> +++ b/include/linux/virtio_net.h
>> @@ -56,7 +56,8 @@ static inline int virtio_net_hdr_to_skb(struct sk_buff *skb,
>>
>> static inline int virtio_net_hdr_from_skb(const struct sk_buff *skb,
>> struct virtio_net_hdr *hdr,
>> - bool little_endian)
>> + bool little_endian,
>> + bool has_data_valid)
>> {
>> memset(hdr, 0, sizeof(*hdr)); /* no info leak */
>>
> I would prefer naming it is_rx. Callers should not know about
> internal details like data valid, the issue we are trying to fix
> here is that tx and tx headers are slightly different.
>
Actually, I've considered something like this, but the problem is:
- tun use this on xmit, so is_rx = true may cause some confusion here
- I believe we may want to support DATA_VALID (like xen-netback) on tx
(probably with a feature) in the future.
Thanks
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
^ permalink raw reply
* Металлические бытовки и домики для дач в Москве.
From: Стройбыт @ 2017-01-21 2:29 UTC (permalink / raw)
Предлагаем дачные домики и строительные бытовки (6x2,4м)
От 125 000 р.
Фото и более детальную информацию можно найти на нашем сайте:
http://модуль-домики.рф
^ permalink raw reply
* Re: [PATCH 1/2] qed: Add support for hardware offloaded FCoE.
From: kbuild test robot @ 2017-01-22 1:24 UTC (permalink / raw)
To: Dupuis, Chad
Cc: kbuild-all, martin.petersen, linux-scsi, fcoe-devel, netdev,
yuval.mintz, QLogic-Storage-Upstream
In-Reply-To: <1484596437-27637-2-git-send-email-chad.dupuis@cavium.com>
[-- Attachment #1: Type: text/plain, Size: 3385 bytes --]
Hi Arun,
[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/Dupuis-Chad/Add-QLogic-FastLinQ-FCoE-qedf-driver/20170117-052438
config: i386-randconfig-x0-01220741 (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
# save the attached .config to linux build tree
make ARCH=i386
All errors (new ones prefixed by >>):
In file included from drivers/net/ethernet/qlogic/qed/qed.h:49:0,
from drivers/net/ethernet/qlogic/qed/qed_dcbx.c:41:
include/linux/qed/qed_if.h:428:37: warning: 'struct qed_dcbx_get' declared inside parameter list will not be visible outside of this definition or declaration
void (*dcbx_aen)(void *dev, struct qed_dcbx_get *get, u32 mib_type);
^~~~~~~~~~~~
drivers/net/ethernet/qlogic/qed/qed_dcbx.c: In function 'qed_dcbx_aen':
>> drivers/net/ethernet/qlogic/qed/qed_dcbx.c:873:42: error: 'struct qed_dcbx_info' has no member named 'get'
op->dcbx_aen(cookie, &hwfn->p_dcbx_info->get, mib_type);
^~
drivers/net/ethernet/qlogic/qed/qed_dcbx.c: In function 'qed_dcbx_mib_update_event':
>> drivers/net/ethernet/qlogic/qed/qed_dcbx.c:902:2: error: implicit declaration of function 'qed_dcbx_get_params' [-Werror=implicit-function-declaration]
qed_dcbx_get_params(p_hwfn, p_ptt, &p_hwfn->p_dcbx_info->get, type);
^~~~~~~~~~~~~~~~~~~
drivers/net/ethernet/qlogic/qed/qed_dcbx.c:902:57: error: 'struct qed_dcbx_info' has no member named 'get'
qed_dcbx_get_params(p_hwfn, p_ptt, &p_hwfn->p_dcbx_info->get, type);
^~
cc1: some warnings being treated as errors
vim +873 drivers/net/ethernet/qlogic/qed/qed_dcbx.c
867 void qed_dcbx_aen(struct qed_hwfn *hwfn, u32 mib_type)
868 {
869 struct qed_common_cb_ops *op = hwfn->cdev->protocol_ops.common;
870 void *cookie = hwfn->cdev->ops_cookie;
871
872 if (cookie && op->dcbx_aen)
> 873 op->dcbx_aen(cookie, &hwfn->p_dcbx_info->get, mib_type);
874 }
875
876 /* Read updated MIB.
877 * Reconfigure QM and invoke PF update ramrod command if operational MIB
878 * change is detected.
879 */
880 int
881 qed_dcbx_mib_update_event(struct qed_hwfn *p_hwfn,
882 struct qed_ptt *p_ptt, enum qed_mib_read_type type)
883 {
884 int rc = 0;
885
886 rc = qed_dcbx_read_mib(p_hwfn, p_ptt, type);
887 if (rc)
888 return rc;
889
890 if (type == QED_DCBX_OPERATIONAL_MIB) {
891 rc = qed_dcbx_process_mib_info(p_hwfn);
892 if (!rc) {
893 /* reconfigure tcs of QM queues according
894 * to negotiation results
895 */
896 qed_qm_reconf(p_hwfn, p_ptt);
897
898 /* update storm FW with negotiation results */
899 qed_sp_pf_update(p_hwfn);
900 }
901 }
> 902 qed_dcbx_get_params(p_hwfn, p_ptt, &p_hwfn->p_dcbx_info->get, type);
903 qed_dcbx_aen(p_hwfn, type);
904
905 return rc;
---
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: 26973 bytes --]
^ 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