From: Simon Horman <hidden> Date: 2017-06-28 20:31:39
Hi,
this series adds flower offload to the NFP driver. It builds on recent
work to add representor and a skeleton flower app - now the app does what
its name says.
In general the approach taken is to allow some flows within
the universe of possible flower matches and tc actions to be offloaded.
It is planned that this support will grow over time but the support
offered by this patch-set seems to be a reasonable starting point.
Key Changes since RFC:
* Revised locking scheme for flows
* Make generalise tc_setup NDO
* Addressed other review of RFC
* Dropped RFC designation
Pieter Jansen van Vuuren (7):
nfp: provide infrastructure for offloading flower based TC filters
nfp: extend flower add flow offload
nfp: extend flower matching capabilities
nfp: add basic action capabilities to flower offloads
nfp: add metadata to each flow offload
nfp: add a stats handler for flower offloads
nfp: add control message passing capabilities to flower offloads
Simon Horman (2):
net: switchdev: add SET_SWITCHDEV_OPS helper
nfp: add phys_switch_id support
drivers/net/ethernet/netronome/nfp/Makefile | 6 +-
drivers/net/ethernet/netronome/nfp/flower/action.c | 211 +++++++++
drivers/net/ethernet/netronome/nfp/flower/cmsg.c | 11 +-
drivers/net/ethernet/netronome/nfp/flower/cmsg.h | 202 +++++++++
drivers/net/ethernet/netronome/nfp/flower/main.c | 32 +-
drivers/net/ethernet/netronome/nfp/flower/main.h | 159 +++++++
drivers/net/ethernet/netronome/nfp/flower/match.c | 292 ++++++++++++
.../net/ethernet/netronome/nfp/flower/metadata.c | 497 +++++++++++++++++++++
.../net/ethernet/netronome/nfp/flower/offload.c | 397 ++++++++++++++++
.../net/ethernet/netronome/nfp/nfp_net_common.c | 17 +-
drivers/net/ethernet/netronome/nfp/nfp_net_repr.c | 8 +
drivers/net/ethernet/netronome/nfp/nfp_net_repr.h | 9 +
drivers/net/ethernet/netronome/nfp/nfp_port.c | 43 ++
drivers/net/ethernet/netronome/nfp/nfp_port.h | 8 +
include/net/switchdev.h | 4 +
15 files changed, 1869 insertions(+), 27 deletions(-)
create mode 100644 drivers/net/ethernet/netronome/nfp/flower/action.c
create mode 100644 drivers/net/ethernet/netronome/nfp/flower/main.h
create mode 100644 drivers/net/ethernet/netronome/nfp/flower/match.c
create mode 100644 drivers/net/ethernet/netronome/nfp/flower/metadata.c
create mode 100644 drivers/net/ethernet/netronome/nfp/flower/offload.c
--
2.1.4
From: Simon Horman <hidden> Date: 2017-06-28 20:31:36
Add a helper to allow switchdev ops to be set if NET_SWITCHDEV is configured
and do nothing otherwise. This allows for slightly cleaner code which
uses switchdev but does not select NET_SWITCHDEV.
Signed-off-by: Simon Horman <redacted>
---
include/net/switchdev.h | 4 ++++
1 file changed, 4 insertions(+)
From: Simon Horman <hidden> Date: 2017-06-28 20:31:39
Add phys_switch_id support by allowing lookup of
SWITCHDEV_ATTR_ID_PORT_PARENT_ID via the nfp_repr_port_attr_get
switchdev operation.
This is visible to user-space in the phys_switch_id attribute
of a netdev.
e.g.
cd /sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0
find . -name phys_switch_id | xargs grep .
./net/eth3/phys_switch_id:00154d1300bd
./net/eth4/phys_switch_id:00154d1300bd
./net/eth2/phys_switch_id:00154d1300bd
grep: ./net/eth5/phys_switch_id: Operation not supported
In the above eth2 and eth3 and representor netdevs for the first and second
physical port. eth4 is the representor for the PF. And eth5 is the PF netdev.
Signed-off-by: Simon Horman <redacted>
Reviewed-by: Jakub Kicinski <redacted>
---
.../net/ethernet/netronome/nfp/nfp_net_common.c | 3 +++
drivers/net/ethernet/netronome/nfp/nfp_net_repr.c | 2 ++
drivers/net/ethernet/netronome/nfp/nfp_port.c | 28 ++++++++++++++++++++++
drivers/net/ethernet/netronome/nfp/nfp_port.h | 3 +++
4 files changed, 36 insertions(+)
From: Simon Horman <hidden> Date: 2017-06-28 20:31:51
From: Pieter Jansen van Vuuren <redacted>
Adds metadata describing the mask id of each flow and keeps track of
flows installed in hardware. Previously a flow could not be removed
from hardware as there was no way of knowing if that a specific flow
was installed. This is solved by storing the offloaded flows in a
hash table.
Signed-off-by: Pieter Jansen van Vuuren <redacted>
Signed-off-by: Simon Horman <redacted>
---
drivers/net/ethernet/netronome/nfp/Makefile | 1 +
drivers/net/ethernet/netronome/nfp/flower/main.c | 14 +-
drivers/net/ethernet/netronome/nfp/flower/main.h | 53 +++
.../net/ethernet/netronome/nfp/flower/metadata.c | 377 +++++++++++++++++++++
.../net/ethernet/netronome/nfp/flower/offload.c | 22 +-
5 files changed, 456 insertions(+), 11 deletions(-)
create mode 100644 drivers/net/ethernet/netronome/nfp/flower/metadata.c
@@ -0,0 +1,377 @@+/*+*Copyright(C)2017NetronomeSystems,Inc.+*+*ThissoftwareisduallicensedundertheGNUGeneralLicenseVersion2,+*June1991asshowninthefileCOPYINGinthetop-leveldirectoryofthis+*sourcetreeortheBSD2-ClauseLicenseprovidedbelow.Youhavethe+*optiontolicensethissoftwareunderthecompletetermsofeitherlicense.+*+*TheBSD2-ClauseLicense:+*+*Redistributionanduseinsourceandbinaryforms,withor+*withoutmodification,arepermittedprovidedthatthefollowing+*conditionsaremet:+*+*1.Redistributionsofsourcecodemustretaintheabove+*copyrightnotice,thislistofconditionsandthefollowing+*disclaimer.+*+*2.Redistributionsinbinaryformmustreproducetheabove+*copyrightnotice,thislistofconditionsandthefollowing+*disclaimerinthedocumentationand/orothermaterials+*providedwiththedistribution.+*+*THESOFTWAREISPROVIDED"AS IS",WITHOUTWARRANTYOFANYKIND,+*EXPRESSORIMPLIED,INCLUDINGBUTNOTLIMITEDTOTHEWARRANTIESOF+*MERCHANTABILITY,FITNESSFORAPARTICULARPURPOSEAND+*NONINFRINGEMENT.INNOEVENTSHALLTHEAUTHORSORCOPYRIGHTHOLDERS+*BELIABLEFORANYCLAIM,DAMAGESOROTHERLIABILITY,WHETHERINAN+*ACTIONOFCONTRACT,TORTOROTHERWISE,ARISINGFROM,OUTOFORIN+*CONNECTIONWITHTHESOFTWAREORTHEUSEOROTHERDEALINGSINTHE+*SOFTWARE.+*/++#include<linux/hash.h>+#include<linux/hashtable.h>+#include<linux/jhash.h>+#include<linux/vmalloc.h>+#include<net/pkt_cls.h>++#include"cmsg.h"+#include"main.h"+#include"../nfp_app.h"++structnfp_mask_id_table{+structhlist_nodelink;+u32hash_key;+u32ref_cnt;+u8mask_id;+};++structnfp_flower_table{+unsignedlongtc_flower_cookie;+structnfp_fl_payload*nfp_flow;+structhlist_nodelink;+structrcu_headrcu;+};++staticstructnfp_flower_table*+nfp_flower_search_fl_table(structnfp_app*app,unsignedlongtc_flower_cookie)+{+structnfp_flower_priv*priv=app->priv;+structnfp_flower_table*flower_entry;++hash_for_each_possible_rcu(priv->flow_table,flower_entry,link,+tc_flower_cookie)+if(flower_entry->tc_flower_cookie==tc_flower_cookie)+returnflower_entry;++returnNULL;+}++staticint+nfp_flower_add_fl_table(structnfp_app*app,unsignedlongtc_flower_cookie,+structnfp_fl_payload*nfp_flow)+{+structnfp_flower_priv*priv=app->priv;+structnfp_flower_table*flower_entry;++flower_entry=nfp_flower_search_fl_table(app,tc_flower_cookie);+if(flower_entry)+return-EEXIST;++flower_entry=kmalloc(sizeof(*flower_entry),GFP_KERNEL);+if(!flower_entry)+return-ENOMEM;++INIT_HLIST_NODE(&flower_entry->link);+flower_entry->nfp_flow=nfp_flow;+flower_entry->tc_flower_cookie=tc_flower_cookie;+hash_add_rcu(priv->flow_table,&flower_entry->link,tc_flower_cookie);++return0;+}++structnfp_fl_payload*+nfp_flower_find_in_fl_table(structnfp_app*app,unsignedlongtc_flower_cookie)+{+structnfp_flower_table*flow_entry;++flow_entry=nfp_flower_search_fl_table(app,tc_flower_cookie);+if(!flow_entry)+returnNULL;++returnflow_entry->nfp_flow;+}++structnfp_fl_payload*+nfp_flower_remove_fl_table(structnfp_app*app,unsignedlongtc_flower_cookie)+{+structnfp_flower_table*flow_entry;+structnfp_fl_payload*nfp_flow;++flow_entry=nfp_flower_search_fl_table(app,tc_flower_cookie);+if(!flow_entry)+returnNULL;++nfp_flow=flow_entry->nfp_flow;+hash_del_rcu(&flow_entry->link);+/* Allow caller to rely on there being no other references for+*furthercleanupofnfp_flow.Otherwisekfree_rcu()couldbe+*used.+*/+synchronize_rcu();+kfree(flow_entry);++returnnfp_flow;+}++staticintnfp_release_mask_id(structnfp_app*app,u8mask_id)+{+structnfp_flower_priv*priv=app->priv;+structcirc_buf*ring;+structtimespec64now;++ring=&priv->mask_ids.mask_id_free_list;+/* Checking if buffer is full. */+if(CIRC_SPACE(ring->head,ring->tail,NFP_FLOWER_MASK_ENTRY_RS)==0)+return-ENOBUFS;++memcpy(&ring->buf[ring->head],&mask_id,NFP_FLOWER_MASK_ELEMENT_RS);+ring->head=(ring->head+NFP_FLOWER_MASK_ELEMENT_RS)%+(NFP_FLOWER_MASK_ENTRY_RS*NFP_FLOWER_MASK_ELEMENT_RS);++getnstimeofday64(&now);+priv->mask_ids.last_used[mask_id]=now;++return0;+}++staticintnfp_mask_alloc(structnfp_app*app,u8*mask_id)+{+structnfp_flower_priv*priv=app->priv;+structtimespec64delta,now;+structcirc_buf*ring;+u8temp_id,freed_id;++ring=&priv->mask_ids.mask_id_free_list;+freed_id=NFP_FLOWER_MASK_ENTRY_RS-1;+/* Checking for unallocated entries first. */+if(priv->mask_ids.init_unallocated>0){+*mask_id=priv->mask_ids.init_unallocated;+priv->mask_ids.init_unallocated--;+return0;+}++/* Checking if buffer is empty. */+if(ring->head==ring->tail){+*mask_id=freed_id;+return-ENOENT;+}++memcpy(&temp_id,&ring->buf[ring->tail],NFP_FLOWER_MASK_ELEMENT_RS);+*mask_id=temp_id;+memcpy(&ring->buf[ring->tail],&freed_id,NFP_FLOWER_MASK_ELEMENT_RS);+ring->tail=(ring->tail+NFP_FLOWER_MASK_ELEMENT_RS)%+(NFP_FLOWER_MASK_ENTRY_RS*NFP_FLOWER_MASK_ELEMENT_RS);++getnstimeofday64(&now);+delta=timespec64_sub(now,priv->mask_ids.last_used[*mask_id]);++if(timespec64_to_ns(&delta)<NFP_FL_MASK_REUSE_TIME_NS){+nfp_release_mask_id(app,*mask_id);+return-ENOENT;+}++return0;+}++staticint+nfp_add_mask_table(structnfp_app*app,char*mask_data,u32mask_len)+{+structnfp_flower_priv*priv=app->priv;+structnfp_mask_id_table*mask_entry;+unsignedlonghash_key;+u8mask_id;++if(nfp_mask_alloc(app,&mask_id))+return-ENOENT;++mask_entry=kmalloc(sizeof(*mask_entry),GFP_KERNEL);+if(!mask_entry){+nfp_release_mask_id(app,mask_id);+return-ENOMEM;+}++INIT_HLIST_NODE(&mask_entry->link);+mask_entry->mask_id=mask_id;+hash_key=jhash(mask_data,mask_len,NFP_FLOWER_MASK_HASH_SEED);+mask_entry->hash_key=hash_key;+mask_entry->ref_cnt=1;+hash_add(priv->mask_table,&mask_entry->link,hash_key);++returnmask_id;+}++staticstructnfp_mask_id_table*+nfp_search_mask_table(structnfp_app*app,char*mask_data,u32mask_len)+{+structnfp_flower_priv*priv=app->priv;+structnfp_mask_id_table*mask_entry;+unsignedlonghash_key;++hash_key=jhash(mask_data,mask_len,NFP_FLOWER_MASK_HASH_SEED);++hash_for_each_possible(priv->mask_table,mask_entry,link,hash_key)+if(mask_entry->hash_key==hash_key)+returnmask_entry;++returnNULL;+}++staticint+nfp_find_in_mask_table(structnfp_app*app,char*mask_data,u32mask_len)+{+structnfp_mask_id_table*mask_entry;++mask_entry=nfp_search_mask_table(app,mask_data,mask_len);+if(!mask_entry)+return-ENOENT;++mask_entry->ref_cnt++;++/* Casting u8 to int for later use. */+returnmask_entry->mask_id;+}++staticbool+nfp_check_mask_add(structnfp_app*app,char*mask_data,u32mask_len,+u8*meta_flags,u8*mask_id)+{+intid;++id=nfp_find_in_mask_table(app,mask_data,mask_len);+if(id<0){+id=nfp_add_mask_table(app,mask_data,mask_len);+if(id<0)+returnfalse;+*meta_flags|=NFP_FL_META_FLAG_NEW_MASK;+}+*mask_id=id;++returntrue;+}++staticbool+nfp_check_mask_remove(structnfp_app*app,char*mask_data,u32mask_len,+u8*meta_flags,u8*mask_id)+{+structnfp_mask_id_table*mask_entry;++mask_entry=nfp_search_mask_table(app,mask_data,mask_len);+if(!mask_entry)+returnfalse;++*mask_id=mask_entry->mask_id;+mask_entry->ref_cnt--;+if(!mask_entry->ref_cnt){+hash_del(&mask_entry->link);+nfp_release_mask_id(app,*mask_id);+kfree(mask_entry);+if(meta_flags)+*meta_flags|=NFP_FL_META_FLAG_LAST_MASK;+}++returntrue;+}++intnfp_compile_flow_metadata(structnfp_app*app,+structtc_cls_flower_offload*flow,+structnfp_fl_payload*nfp_flow)+{+structnfp_flower_priv*priv=app->priv;+u8new_mask_id;+interr;++new_mask_id=0;+if(!nfp_check_mask_add(app,nfp_flow->mask_data,+nfp_flow->meta.mask_len,+&nfp_flow->meta.flags,&new_mask_id))+return-ENOENT;++nfp_flow->meta.flow_version=cpu_to_be64(priv->flower_version);+priv->flower_version++;++/* Update flow payload with mask ids. */+nfp_flow->unmasked_data[NFP_FL_MASK_ID_LOCATION]=new_mask_id;++err=nfp_flower_add_fl_table(app,flow->cookie,nfp_flow);+if(err<0){+if(!nfp_check_mask_remove(app,nfp_flow->mask_data,+nfp_flow->meta.mask_len,+NULL,&new_mask_id))+return-EINVAL;++returnerr;+}++return0;+}++intnfp_modify_flow_metadata(structnfp_app*app,+structnfp_fl_payload*nfp_flow)+{+structnfp_flower_priv*priv=app->priv;+u8new_mask_id=0;++nfp_check_mask_remove(app,nfp_flow->mask_data,+nfp_flow->meta.mask_len,&nfp_flow->meta.flags,+&new_mask_id);++nfp_flow->meta.flow_version=cpu_to_be64(priv->flower_version);+priv->flower_version++;++/* Update flow payload with mask ids. */+nfp_flow->unmasked_data[NFP_FL_MASK_ID_LOCATION]=new_mask_id;++return0;+}++intnfp_flower_metadata_init(structnfp_app*app)+{+structnfp_flower_priv*priv=app->priv;++hash_init(priv->mask_table);+hash_init(priv->flow_table);++/* Init ring buffer and unallocated mask_ids. */+priv->mask_ids.mask_id_free_list.buf=+kmalloc(NFP_FLOWER_MASK_ENTRY_RS*NFP_FLOWER_MASK_ELEMENT_RS,+GFP_KERNEL);+if(!priv->mask_ids.mask_id_free_list.buf)+return-ENOMEM;++priv->mask_ids.init_unallocated=NFP_FLOWER_MASK_ENTRY_RS-1;++/* Init timestamps for mask id*/+priv->mask_ids.last_used=+kmalloc_array(NFP_FLOWER_MASK_ENTRY_RS,+sizeof(*priv->mask_ids.last_used),GFP_KERNEL);+if(!priv->mask_ids.last_used){+kfree(priv->mask_ids.mask_id_free_list.buf);+return-ENOMEM;+}++return0;+}++voidnfp_flower_metadata_cleanup(structnfp_app*app)+{+structnfp_flower_priv*priv=app->priv;++if(!priv)+return;++kfree(priv->mask_ids.mask_id_free_list.buf);+kfree(priv->mask_ids.last_used);+}
From: Simon Horman <hidden> Date: 2017-06-28 20:31:52
From: Pieter Jansen van Vuuren <redacted>
Adds a flower based TC offload handler for representor devices, this
is in addition to the bpf based offload handler. The changes in this
patch will be used in a follow-up patch to add tc flower offload to
the NFP.
The flower app enables tc offloads on representors by default.
Signed-off-by: Pieter Jansen van Vuuren <redacted>
Signed-off-by: Simon Horman <redacted>
---
drivers/net/ethernet/netronome/nfp/Makefile | 3 +-
drivers/net/ethernet/netronome/nfp/flower/main.c | 20 ++++
drivers/net/ethernet/netronome/nfp/flower/main.h | 45 ++++++++
.../net/ethernet/netronome/nfp/flower/offload.c | 127 +++++++++++++++++++++
.../net/ethernet/netronome/nfp/nfp_net_common.c | 14 +--
drivers/net/ethernet/netronome/nfp/nfp_net_repr.c | 6 +
drivers/net/ethernet/netronome/nfp/nfp_port.c | 15 +++
drivers/net/ethernet/netronome/nfp/nfp_port.h | 5 +
8 files changed, 221 insertions(+), 14 deletions(-)
create mode 100644 drivers/net/ethernet/netronome/nfp/flower/main.h
create mode 100644 drivers/net/ethernet/netronome/nfp/flower/offload.c
From: Simon Horman <hidden> Date: 2017-06-28 20:31:54
From: Pieter Jansen van Vuuren <redacted>
Extends the flower flow add function by calculating which match
fields are present in the flower offload structure and allocating
the appropriate space to describe these.
Signed-off-by: Pieter Jansen van Vuuren <redacted>
Signed-off-by: Simon Horman <redacted>
---
drivers/net/ethernet/netronome/nfp/flower/cmsg.h | 141 +++++++++++++++++
drivers/net/ethernet/netronome/nfp/flower/main.h | 24 +++
.../net/ethernet/netronome/nfp/flower/offload.c | 166 ++++++++++++++++++++-
3 files changed, 330 insertions(+), 1 deletion(-)
@@ -44,6 +44,145 @@#include"../nfp_net.h"#include"../nfp_port.h"+staticboolnfp_flower_check_higher_than_mac(structtc_cls_flower_offload*f)+{+returndissector_uses_key(f->dissector,+FLOW_DISSECTOR_KEY_IPV4_ADDRS)||+dissector_uses_key(f->dissector,+FLOW_DISSECTOR_KEY_IPV6_ADDRS)||+dissector_uses_key(f->dissector,+FLOW_DISSECTOR_KEY_PORTS)||+dissector_uses_key(f->dissector,FLOW_DISSECTOR_KEY_ICMP);+}++staticint+nfp_flower_calculate_key_layers(structnfp_fl_key_ls*ret_key_ls,+structtc_cls_flower_offload*flow)+{+structflow_dissector_key_control*mask_enc_ctl;+structflow_dissector_key_basic*mask_basic;+structflow_dissector_key_basic*key_basic;+u32key_layer_two;+u8key_layer;+intkey_size;++mask_enc_ctl=skb_flow_dissector_target(flow->dissector,+FLOW_DISSECTOR_KEY_ENC_CONTROL,+flow->mask);++mask_basic=skb_flow_dissector_target(flow->dissector,+FLOW_DISSECTOR_KEY_BASIC,+flow->mask);++key_basic=skb_flow_dissector_target(flow->dissector,+FLOW_DISSECTOR_KEY_BASIC,+flow->key);+key_layer_two=0;+key_layer=NFP_FLOWER_LAYER_PORT|NFP_FLOWER_LAYER_MAC;+key_size=sizeof(structnfp_flower_meta_one)++sizeof(structnfp_flower_in_port)++sizeof(structnfp_flower_mac_mpls);++/* We are expecting a tunnel. For now we ignore offloading. */+if(mask_enc_ctl->addr_type)+return-EOPNOTSUPP;++if(mask_basic->n_proto){+/* Ethernet type is present in the key. */+switch(key_basic->n_proto){+casecpu_to_be16(ETH_P_IP):+key_layer|=NFP_FLOWER_LAYER_IPV4;+key_size+=sizeof(structnfp_flower_ipv4);+break;++casecpu_to_be16(ETH_P_IPV6):+key_layer|=NFP_FLOWER_LAYER_IPV6;+key_size+=sizeof(structnfp_flower_ipv6);+break;++/* Currently we do not offload ARP+*becausewerelyonittogettothehost.+*/+casecpu_to_be16(ETH_P_ARP):+return-EOPNOTSUPP;++/* Will be included in layer 2. */+casecpu_to_be16(ETH_P_8021Q):+break;++default:+/* Other ethtype - we need check the masks for the+*remainerofthekeytoensurewecanoffload.+*/+if(nfp_flower_check_higher_than_mac(flow))+return-EOPNOTSUPP;+break;+}+}++if(mask_basic->ip_proto){+/* Ethernet type is present in the key. */+switch(key_basic->ip_proto){+caseIPPROTO_TCP:+caseIPPROTO_UDP:+caseIPPROTO_SCTP:+caseIPPROTO_ICMP:+caseIPPROTO_ICMPV6:+key_layer|=NFP_FLOWER_LAYER_TP;+key_size+=sizeof(structnfp_flower_tp_ports);+break;+default:+/* Other ip proto - we need check the masks for the+*remainerofthekeytoensurewecanoffload.+*/+return-EOPNOTSUPP;+}+}++ret_key_ls->key_layer=key_layer;+ret_key_ls->key_layer_two=key_layer_two;+ret_key_ls->key_size=key_size;++return0;+}++staticstructnfp_fl_payload*+nfp_flower_allocate_new(structnfp_fl_key_ls*key_layer)+{+structnfp_fl_payload*flow_pay;++flow_pay=kmalloc(sizeof(*flow_pay),GFP_KERNEL);+if(!flow_pay)+returnNULL;++flow_pay->meta.key_len=key_layer->key_size;+flow_pay->unmasked_data=kmalloc(key_layer->key_size,GFP_KERNEL);+if(!flow_pay->unmasked_data)+gotoerr_free_flow;++flow_pay->meta.mask_len=key_layer->key_size;+flow_pay->mask_data=kmalloc(key_layer->key_size,GFP_KERNEL);+if(!flow_pay->mask_data)+gotoerr_free_unmasked;++flow_pay->meta.flags=0;++returnflow_pay;++err_free_unmasked:+kfree(flow_pay->unmasked_data);+err_free_flow:+kfree(flow_pay);+returnNULL;+}++staticvoidnfp_flower_deallocate_nfp(structnfp_fl_payload*flow_pay)+{+kfree(flow_pay->mask_data);+kfree(flow_pay->unmasked_data);+kfree(flow_pay);+}+/***nfp_flower_add_offload()-Addsanewflowtohardware.*@app:PointertotheAPPhandle
@@ -0,0 +1,211 @@+/*+*Copyright(C)2017NetronomeSystems,Inc.+*+*ThissoftwareisduallicensedundertheGNUGeneralLicenseVersion2,+*June1991asshowninthefileCOPYINGinthetop-leveldirectoryofthis+*sourcetreeortheBSD2-ClauseLicenseprovidedbelow.Youhavethe+*optiontolicensethissoftwareunderthecompletetermsofeitherlicense.+*+*TheBSD2-ClauseLicense:+*+*Redistributionanduseinsourceandbinaryforms,withor+*withoutmodification,arepermittedprovidedthatthefollowing+*conditionsaremet:+*+*1.Redistributionsofsourcecodemustretaintheabove+*copyrightnotice,thislistofconditionsandthefollowing+*disclaimer.+*+*2.Redistributionsinbinaryformmustreproducetheabove+*copyrightnotice,thislistofconditionsandthefollowing+*disclaimerinthedocumentationand/orothermaterials+*providedwiththedistribution.+*+*THESOFTWAREISPROVIDED"AS IS",WITHOUTWARRANTYOFANYKIND,+*EXPRESSORIMPLIED,INCLUDINGBUTNOTLIMITEDTOTHEWARRANTIESOF+*MERCHANTABILITY,FITNESSFORAPARTICULARPURPOSEAND+*NONINFRINGEMENT.INNOEVENTSHALLTHEAUTHORSORCOPYRIGHTHOLDERS+*BELIABLEFORANYCLAIM,DAMAGESOROTHERLIABILITY,WHETHERINAN+*ACTIONOFCONTRACT,TORTOROTHERWISE,ARISINGFROM,OUTOFORIN+*CONNECTIONWITHTHESOFTWAREORTHEUSEOROTHERDEALINGSINTHE+*SOFTWARE.+*/++#include<linux/bitfield.h>+#include<net/pkt_cls.h>+#include<net/switchdev.h>+#include<net/tc_act/tc_gact.h>+#include<net/tc_act/tc_mirred.h>+#include<net/tc_act/tc_vlan.h>++#include"cmsg.h"+#include"main.h"+#include"../nfp_net_repr.h"++staticvoidnfp_fl_pop_vlan(structnfp_fl_pop_vlan*pop_vlan)+{+size_tact_size=sizeof(structnfp_fl_pop_vlan);+u16tmp_pop_vlan_op;++tmp_pop_vlan_op=+FIELD_PREP(NFP_FL_ACT_LEN_LW,act_size/NFP_FL_LW_SIZ)|+FIELD_PREP(NFP_FL_ACT_JMP_ID,NFP_FL_ACTION_OPCODE_POP_VLAN);++pop_vlan->a_op=cpu_to_be16(tmp_pop_vlan_op);+pop_vlan->reserved=0;+}++staticvoid+nfp_fl_push_vlan(structnfp_fl_push_vlan*push_vlan,+conststructtc_action*action)+{+size_tact_size=sizeof(structnfp_fl_push_vlan);+structtcf_vlan*vlan=to_vlan(action);+u16tmp_push_vlan_tci;+u16tmp_push_vlan_op;++tmp_push_vlan_op=+FIELD_PREP(NFP_FL_ACT_LEN_LW,act_size/NFP_FL_LW_SIZ)|+FIELD_PREP(NFP_FL_ACT_JMP_ID,NFP_FL_ACTION_OPCODE_PUSH_VLAN);++push_vlan->a_op=cpu_to_be16(tmp_push_vlan_op);+/* Set action push vlan parameters. */+push_vlan->reserved=0;+push_vlan->vlan_tpid=tcf_vlan_push_proto(action);++tmp_push_vlan_tci=+FIELD_PREP(NFP_FL_PUSH_VLAN_PRIO,vlan->tcfv_push_prio)|+FIELD_PREP(NFP_FL_PUSH_VLAN_VID,vlan->tcfv_push_vid)|+NFP_FL_PUSH_VLAN_CFI;+push_vlan->vlan_tci=cpu_to_be16(tmp_push_vlan_tci);+}++staticint+nfp_fl_output(structnfp_fl_output*output,conststructtc_action*action,+structnfp_fl_payload*nfp_flow,boollast,+structnet_device*in_dev)+{+size_tact_size=sizeof(structnfp_fl_output);+structnet_device*out_dev;+u16tmp_output_op;+intifindex;++/* Set action opcode to output action. */+tmp_output_op=+FIELD_PREP(NFP_FL_ACT_LEN_LW,act_size/NFP_FL_LW_SIZ)|+FIELD_PREP(NFP_FL_ACT_JMP_ID,NFP_FL_ACTION_OPCODE_OUTPUT);++output->a_op=cpu_to_be16(tmp_output_op);++/* Set action output parameters. */+output->flags=cpu_to_be16(last?NFP_FL_OUT_FLAGS_LAST:0);++ifindex=tcf_mirred_ifindex(action);+out_dev=__dev_get_by_index(dev_net(in_dev),ifindex);+if(!out_dev)+return-EOPNOTSUPP;++/* Only offload egress ports are on the same device as the ingress+*port.+*/+if(!switchdev_port_same_parent_id(in_dev,out_dev))+return-EOPNOTSUPP;++output->port=cpu_to_be32(nfp_repr_get_port_id(out_dev));+if(!output->port)+return-EOPNOTSUPP;++nfp_flow->meta.shortcut=output->port;++return0;+}++staticint+nfp_flower_loop_action(conststructtc_action*a,+structnfp_fl_payload*nfp_fl,int*a_len,+structnet_device*netdev)+{+structnfp_fl_push_vlan*psh_v;+structnfp_fl_pop_vlan*pop_v;+structnfp_fl_output*output;+interr;++if(is_tcf_gact_shot(a)){+nfp_fl->meta.shortcut=cpu_to_be32(NFP_FL_SC_ACT_DROP);+}elseif(is_tcf_mirred_egress_redirect(a)){+if(*a_len+sizeof(structnfp_fl_output)>NFP_FL_MAX_A_SIZ)+return-EOPNOTSUPP;++output=(structnfp_fl_output*)&nfp_fl->action_data[*a_len];+err=nfp_fl_output(output,a,nfp_fl,true,netdev);+if(err)+returnerr;++*a_len+=sizeof(structnfp_fl_output);+}elseif(is_tcf_mirred_egress_mirror(a)){+if(*a_len+sizeof(structnfp_fl_output)>NFP_FL_MAX_A_SIZ)+return-EOPNOTSUPP;++output=(structnfp_fl_output*)&nfp_fl->action_data[*a_len];+err=nfp_fl_output(output,a,nfp_fl,false,netdev);+if(err)+returnerr;++*a_len+=sizeof(structnfp_fl_output);+}elseif(is_tcf_vlan(a)&&tcf_vlan_action(a)==TCA_VLAN_ACT_POP){+if(*a_len+sizeof(structnfp_fl_pop_vlan)>NFP_FL_MAX_A_SIZ)+return-EOPNOTSUPP;++pop_v=(structnfp_fl_pop_vlan*)&nfp_fl->action_data[*a_len];+nfp_fl->meta.shortcut=cpu_to_be32(NFP_FL_SC_ACT_POPV);++nfp_fl_pop_vlan(pop_v);+*a_len+=sizeof(structnfp_fl_pop_vlan);+}elseif(is_tcf_vlan(a)&&tcf_vlan_action(a)==TCA_VLAN_ACT_PUSH){+if(*a_len+sizeof(structnfp_fl_push_vlan)>NFP_FL_MAX_A_SIZ)+return-EOPNOTSUPP;++psh_v=(structnfp_fl_push_vlan*)&nfp_fl->action_data[*a_len];+nfp_fl->meta.shortcut=cpu_to_be32(NFP_FL_SC_ACT_NULL);++nfp_fl_push_vlan(psh_v,a);+*a_len+=sizeof(structnfp_fl_push_vlan);+}else{+/* Currently we do not handle any other actions. */+return-EOPNOTSUPP;+}++return0;+}++intnfp_flower_compile_action(structtc_cls_flower_offload*flow,+structnet_device*netdev,+structnfp_fl_payload*nfp_flow)+{+intact_len,act_cnt,err;+conststructtc_action*a;+LIST_HEAD(actions);++memset(nfp_flow->action_data,0,NFP_FL_MAX_A_SIZ);+nfp_flow->meta.act_len=0;+act_len=0;+act_cnt=0;++tcf_exts_to_list(flow->exts,&actions);+list_for_each_entry(a,&actions,list){+err=nfp_flower_loop_action(a,nfp_flow,&act_len,netdev);+if(err)+returnerr;+act_cnt++;+}++/* We optimise when the action list is small, this can unfortunately+*nothappenoncewehavemorethanoneactionintheactionlist.+*/+if(act_cnt>1)+nfp_flow->meta.shortcut=cpu_to_be32(NFP_FL_SC_ACT_NULL);++nfp_flow->meta.act_len=act_len;++return0;+}
From: Simon Horman <hidden> Date: 2017-06-28 20:31:56
From: Pieter Jansen van Vuuren <redacted>
Previously the flower offloads never sends messages to the hardware,
and never registers a handler for receiving messages from hardware.
This patch enables the flower offloads to send control messages to
hardware when adding and removing flow rules. Additionally it
registers a control message rx handler for receiving stats updates
from hardware for each offloaded flow.
Additionally this patch adds 4 control message types; Add, modify and
delete flow, as well as flow stats. It also allows
nfp_flower_cmsg_get_data() to be used outside of cmsg.c.
Signed-off-by: Pieter Jansen van Vuuren <redacted>
Signed-off-by: Simon Horman <redacted>
---
drivers/net/ethernet/netronome/nfp/flower/cmsg.c | 6 ++-
drivers/net/ethernet/netronome/nfp/flower/cmsg.h | 7 +++
.../net/ethernet/netronome/nfp/flower/offload.c | 56 ++++++++++++++++++++++
3 files changed, 68 insertions(+), 1 deletion(-)
@@ -245,7 +245,11 @@ struct nfp_flower_cmsg_hdr {/* Types defined for port related control messages */enumnfp_flower_cmsg_type_port{+NFP_FLOWER_CMSG_TYPE_FLOW_ADD=0,+NFP_FLOWER_CMSG_TYPE_FLOW_MOD=1,+NFP_FLOWER_CMSG_TYPE_FLOW_DEL=2,NFP_FLOWER_CMSG_TYPE_PORT_MOD=8,+NFP_FLOWER_CMSG_TYPE_FLOW_STATS=15,NFP_FLOWER_CMSG_TYPE_PORT_ECHO=16,NFP_FLOWER_CMSG_TYPE_MAX=32,};
@@ -44,6 +44,52 @@#include"../nfp_net.h"#include"../nfp_port.h"+staticint+nfp_flower_xmit_flow(structnet_device*netdev,+structnfp_fl_payload*nfp_flow,u8mtype)+{+u32meta_len,key_len,mask_len,act_len,tot_len;+structnfp_repr*priv=netdev_priv(netdev);+structsk_buff*skb;+unsignedchar*msg;++meta_len=sizeof(structnfp_fl_rule_metadata);+key_len=nfp_flow->meta.key_len;+mask_len=nfp_flow->meta.mask_len;+act_len=nfp_flow->meta.act_len;++tot_len=meta_len+key_len+mask_len+act_len;++/* Convert to long words as firmware expects+*lengthsinunitsofNFP_FL_LW_SIZ.+*/+nfp_flow->meta.key_len/=NFP_FL_LW_SIZ;+nfp_flow->meta.mask_len/=NFP_FL_LW_SIZ;+nfp_flow->meta.act_len/=NFP_FL_LW_SIZ;++skb=nfp_flower_cmsg_alloc(priv->app,tot_len,mtype);+if(!skb)+return-ENOMEM;++msg=nfp_flower_cmsg_get_data(skb);+memcpy(msg,&nfp_flow->meta,meta_len);+memcpy(&msg[meta_len],nfp_flow->unmasked_data,key_len);+memcpy(&msg[meta_len+key_len],nfp_flow->mask_data,mask_len);+memcpy(&msg[meta_len+key_len+mask_len],+nfp_flow->action_data,act_len);++/* Convert back to bytes as software expects+*lengthsinunitsofbytes.+*/+nfp_flow->meta.key_len*=NFP_FL_LW_SIZ;+nfp_flow->meta.mask_len*=NFP_FL_LW_SIZ;+nfp_flow->meta.act_len*=NFP_FL_LW_SIZ;++nfp_ctrl_tx(priv->app->ctrl,skb);++return0;+}+staticboolnfp_flower_check_higher_than_mac(structtc_cls_flower_offload*f){returndissector_uses_key(f->dissector,
@@ -235,6 +281,11 @@ nfp_flower_add_offload(struct nfp_app *app, struct net_device *netdev,if(err)gotoerr_destroy_flow;+err=nfp_flower_xmit_flow(netdev,flow_pay,+NFP_FLOWER_CMSG_TYPE_FLOW_ADD);+if(err)+gotoerr_destroy_flow;+/* Deallocate flow payload when flower rule has been destroyed. */kfree(key_layer);
From: Simon Horman <hidden> Date: 2017-06-28 20:31:59
From: Pieter Jansen van Vuuren <redacted>
Previously there was no way of updating flow rule stats after they
have been offloaded to hardware. This is solved by keeping track of
stats received from hardware and providing this to the TC handler
on request.
Signed-off-by: Pieter Jansen van Vuuren <redacted>
Signed-off-by: Simon Horman <redacted>
---
drivers/net/ethernet/netronome/nfp/flower/cmsg.c | 5 -
drivers/net/ethernet/netronome/nfp/flower/cmsg.h | 5 +
drivers/net/ethernet/netronome/nfp/flower/main.h | 29 +++++
.../net/ethernet/netronome/nfp/flower/metadata.c | 124 ++++++++++++++++++++-
.../net/ethernet/netronome/nfp/flower/offload.c | 20 +++-
5 files changed, 175 insertions(+), 8 deletions(-)
@@ -55,6 +55,55 @@ struct nfp_flower_table {structrcu_headrcu;};+staticintnfp_release_stats_entry(structnfp_app*app,u32stats_context_id)+{+structnfp_flower_priv*priv=app->priv;+structcirc_buf*ring;++ring=&priv->stats_ids.free_list;+/* Check if buffer is full. */+if(!CIRC_SPACE(ring->head,ring->tail,NFP_FL_STATS_ENTRY_RS*+NFP_FL_STATS_ELEM_RS-+NFP_FL_STATS_ELEM_RS+1))+return-ENOBUFS;++memcpy(&ring->buf[ring->head],&stats_context_id,NFP_FL_STATS_ELEM_RS);+ring->head=(ring->head+NFP_FL_STATS_ELEM_RS)%+(NFP_FL_STATS_ENTRY_RS*NFP_FL_STATS_ELEM_RS);++return0;+}++staticintnfp_get_stats_entry(structnfp_app*app,u32*stats_context_id)+{+structnfp_flower_priv*priv=app->priv;+u32freed_stats_id,temp_stats_id;+structcirc_buf*ring;++ring=&priv->stats_ids.free_list;+freed_stats_id=NFP_FL_STATS_ENTRY_RS;+/* Check for unallocated entries first. */+if(priv->stats_ids.init_unalloc>0){+*stats_context_id=priv->stats_ids.init_unalloc-1;+priv->stats_ids.init_unalloc--;+return0;+}++/* Check if buffer is empty. */+if(ring->head==ring->tail){+*stats_context_id=freed_stats_id;+return-ENOENT;+}++memcpy(&temp_stats_id,&ring->buf[ring->tail],NFP_FL_STATS_ELEM_RS);+*stats_context_id=temp_stats_id;+memcpy(&ring->buf[ring->tail],&freed_stats_id,NFP_FL_STATS_ELEM_RS);+ring->tail=(ring->tail+NFP_FL_STATS_ELEM_RS)%+(NFP_FL_STATS_ENTRY_RS*NFP_FL_STATS_ELEM_RS);++return0;+}+staticstructnfp_flower_table*nfp_flower_search_fl_table(structnfp_app*app,unsignedlongtc_flower_cookie){
@@ -69,6 +118,46 @@ nfp_flower_search_fl_table(struct nfp_app *app, unsigned long tc_flower_cookie)returnNULL;}+staticvoid+nfp_flower_update_stats(structnfp_app*app,structnfp_fl_stats_frame*stats)+{+structnfp_fl_payload*nfp_flow;+unsignedlongflower_cookie;++flower_cookie=be64_to_cpu(stats->stats_cookie);++rcu_read_lock();+nfp_flow=nfp_flower_find_in_fl_table(app,flower_cookie);+if(!nfp_flow)+gotoexit_rcu_unlock;++if(nfp_flow->meta.host_ctx_id!=stats->stats_con_id)+gotoexit_rcu_unlock;++spin_lock(&nfp_flow->lock);+nfp_flow->stats.pkts+=be32_to_cpu(stats->pkt_count);+nfp_flow->stats.bytes+=be64_to_cpu(stats->byte_count);+nfp_flow->stats.used=jiffies;+spin_unlock(&nfp_flow->lock);++exit_rcu_unlock:+rcu_read_unlock();+}++voidnfp_flower_rx_flow_stats(structnfp_app*app,structsk_buff*skb)+{+unsignedintmsg_len=skb->len-NFP_FLOWER_CMSG_HLEN;+structnfp_fl_stats_frame*stats_frame;+unsignedchar*msg;+inti;++msg=nfp_flower_cmsg_get_data(skb);++stats_frame=(structnfp_fl_stats_frame*)msg;+for(i=0;i<msg_len/sizeof(*stats_frame);i++)+nfp_flower_update_stats(app,stats_frame+i);+}+staticintnfp_flower_add_fl_table(structnfp_app*app,unsignedlongtc_flower_cookie,structnfp_fl_payload*nfp_flow)
@@ -291,22 +380,39 @@ int nfp_compile_flow_metadata(struct nfp_app *app,{structnfp_flower_priv*priv=app->priv;u8new_mask_id;+u32stats_cxt;interr;+err=nfp_get_stats_entry(app,&stats_cxt);+if(err<0)+returnerr;++nfp_flow->meta.host_ctx_id=cpu_to_be32(stats_cxt);+nfp_flow->meta.host_cookie=cpu_to_be64(flow->cookie);+new_mask_id=0;if(!nfp_check_mask_add(app,nfp_flow->mask_data,nfp_flow->meta.mask_len,-&nfp_flow->meta.flags,&new_mask_id))+&nfp_flow->meta.flags,&new_mask_id)){+if(nfp_release_stats_entry(app,stats_cxt))+return-EINVAL;return-ENOENT;+}nfp_flow->meta.flow_version=cpu_to_be64(priv->flower_version);priv->flower_version++;/* Update flow payload with mask ids. */nfp_flow->unmasked_data[NFP_FL_MASK_ID_LOCATION]=new_mask_id;+nfp_flow->stats.pkts=0;+nfp_flow->stats.bytes=0;+nfp_flow->stats.used=jiffies;err=nfp_flower_add_fl_table(app,flow->cookie,nfp_flow);if(err<0){+if(nfp_release_stats_entry(app,stats_cxt))+return-EINVAL;+if(!nfp_check_mask_remove(app,nfp_flow->mask_data,nfp_flow->meta.mask_len,NULL,&new_mask_id))
@@ -323,6 +429,7 @@ int nfp_modify_flow_metadata(struct nfp_app *app,{structnfp_flower_priv*priv=app->priv;u8new_mask_id=0;+u32temp_ctx_id;nfp_check_mask_remove(app,nfp_flow->mask_data,nfp_flow->meta.mask_len,&nfp_flow->meta.flags,
@@ -334,7 +441,10 @@ int nfp_modify_flow_metadata(struct nfp_app *app,/* Update flow payload with mask ids. */nfp_flow->unmasked_data[NFP_FL_MASK_ID_LOCATION]=new_mask_id;-return0;+/* Release the stats ctx id. */+temp_ctx_id=be32_to_cpu(nfp_flow->meta.host_ctx_id);++returnnfp_release_stats_entry(app,temp_ctx_id);}intnfp_flower_metadata_init(structnfp_app*app)
@@ -362,6 +472,15 @@ int nfp_flower_metadata_init(struct nfp_app *app)return-ENOMEM;}+/* Init ring buffer and unallocated stats_ids. */+priv->stats_ids.free_list.buf=+vmalloc(NFP_FL_STATS_ENTRY_RS*NFP_FL_STATS_ELEM_RS);+if(!priv->stats_ids.free_list.buf){+vfree(priv->mask_ids.mask_id_free_list.buf);+return-ENOMEM;+}+priv->stats_ids.init_unalloc=NFP_FL_REPEATED_HASH_MAX;+return0;}
From: Jakub Kicinski <hidden> Date: 2017-06-29 01:35:10
On Wed, 28 Jun 2017 22:29:56 +0200, Simon Horman wrote:
From: Pieter Jansen van Vuuren <redacted>
Adds a flower based TC offload handler for representor devices, this
is in addition to the bpf based offload handler. The changes in this
patch will be used in a follow-up patch to add tc flower offload to
the NFP.
The flower app enables tc offloads on representors by default.
Signed-off-by: Pieter Jansen van Vuuren <redacted>
Signed-off-by: Simon Horman <redacted>
Thanks, two nits, since it seems like there will have to be another
respin.
quoted hunk
@@ -313,6 +317,8 @@ static int nfp_flower_vnic_init(struct nfp_app *app, struct nfp_net *nn, static int nfp_flower_init(struct nfp_app *app) { const struct nfp_pf *pf = app->pf;+ u64 version;+ int err; if (!pf->eth_tbl) { nfp_warn(app->cpp, "FlowerNIC requires eth table\n");
@@ -329,6 +335,18 @@ static int nfp_flower_init(struct nfp_app *app) return -EINVAL; }+ version = nfp_rtsym_read_le(app->pf->rtbl, "hw_flower_version", &err);+ if (err) {+ nfp_warn(app->cpp, "FlowerNIC requires hw_flower_version memory symbol\n");+ return err;+ }++ /* We need to ensure hardware has enough flower capabilities. */+ if (version != NFP_FLOWER_ALLOWED_VER) {+ nfp_warn(app->cpp, "FlowerNIC: unspported firmware version\n");
From: Jakub Kicinski <hidden> Date: 2017-06-29 02:33:08
On Wed, 28 Jun 2017 22:30:00 +0200, Simon Horman wrote:
From: Pieter Jansen van Vuuren <redacted>
Adds metadata describing the mask id of each flow and keeps track of
flows installed in hardware. Previously a flow could not be removed
from hardware as there was no way of knowing if that a specific flow
was installed. This is solved by storing the offloaded flows in a
hash table.
Signed-off-by: Pieter Jansen van Vuuren <redacted>
Signed-off-by: Simon Horman <redacted>
@@ -351,6 +343,12 @@ static int nfp_flower_init(struct nfp_app *app)if(!app->priv)return-ENOMEM;+err=nfp_flower_metadata_init(app);+if(nfp_flower_metadata_init(app)){
You're calling init twice here. Also please do the error path with
goto, as explained in review of patch 8 having a proper unwind makes
later patches easier to review.
From: Jakub Kicinski <hidden> Date: 2017-06-29 02:55:21
On Wed, 28 Jun 2017 22:30:01 +0200, Simon Horman wrote:
From: Pieter Jansen van Vuuren <redacted>
Previously there was no way of updating flow rule stats after they
have been offloaded to hardware. This is solved by keeping track of
stats received from hardware and providing this to the TC handler
on request.
Signed-off-by: Pieter Jansen van Vuuren <redacted>
Signed-off-by: Simon Horman <redacted>
quoted hunk
@@ -334,7 +441,10 @@ int nfp_modify_flow_metadata(struct nfp_app *app, /* Update flow payload with mask ids. */ nfp_flow->unmasked_data[NFP_FL_MASK_ID_LOCATION] = new_mask_id;- return 0;+ /* Release the stats ctx id. */+ temp_ctx_id = be32_to_cpu(nfp_flow->meta.host_ctx_id);++ return nfp_release_stats_entry(app, temp_ctx_id); } int nfp_flower_metadata_init(struct nfp_app *app)
@@ -362,6 +472,15 @@ int nfp_flower_metadata_init(struct nfp_app *app) return -ENOMEM; }+ /* Init ring buffer and unallocated stats_ids. */+ priv->stats_ids.free_list.buf =+ vmalloc(NFP_FL_STATS_ENTRY_RS * NFP_FL_STATS_ELEM_RS);+ if (!priv->stats_ids.free_list.buf) {+ vfree(priv->mask_ids.mask_id_free_list.buf);+ return -ENOMEM;
This is hiding a leak, I think. There were 2 things allocate above.
Please add a proper unwind path with goto's - it makes catching bugs
like this much easier.
From: Simon Horman <hidden> Date: 2017-06-29 05:41:48
On Wed, Jun 28, 2017 at 06:35:07PM -0700, Jakub Kicinski wrote:
On Wed, 28 Jun 2017 22:29:56 +0200, Simon Horman wrote:
quoted
From: Pieter Jansen van Vuuren <redacted>
Adds a flower based TC offload handler for representor devices, this
is in addition to the bpf based offload handler. The changes in this
patch will be used in a follow-up patch to add tc flower offload to
the NFP.
The flower app enables tc offloads on representors by default.
Signed-off-by: Pieter Jansen van Vuuren <redacted>
Signed-off-by: Simon Horman <redacted>
Thanks, two nits, since it seems like there will have to be another
respin.
From: Yunsheng Lin <hidden> Date: 2017-06-29 06:21:39
+
+ if (mask_basic->n_proto) {
cpu_to_be16(mask_basic->n_proto)
remove cpu_to_be16 in case.
quoted hunk
+ /* Ethernet type is present in the key. */+ switch (key_basic->n_proto) {+ case cpu_to_be16(ETH_P_IP):+ key_layer |= NFP_FLOWER_LAYER_IPV4;+ key_size += sizeof(struct nfp_flower_ipv4);+ break;++ case cpu_to_be16(ETH_P_IPV6):+ key_layer |= NFP_FLOWER_LAYER_IPV6;+ key_size += sizeof(struct nfp_flower_ipv6);+ break;++ /* Currently we do not offload ARP+ * because we rely on it to get to the host.+ */+ case cpu_to_be16(ETH_P_ARP):+ return -EOPNOTSUPP;++ /* Will be included in layer 2. */+ case cpu_to_be16(ETH_P_8021Q):+ break;++ default:+ /* Other ethtype - we need check the masks for the+ * remainer of the key to ensure we can offload.+ */+ if (nfp_flower_check_higher_than_mac(flow))+ return -EOPNOTSUPP;+ break;+ }+ }++ if (mask_basic->ip_proto) {+ /* Ethernet type is present in the key. */+ switch (key_basic->ip_proto) {+ case IPPROTO_TCP:+ case IPPROTO_UDP:+ case IPPROTO_SCTP:+ case IPPROTO_ICMP:+ case IPPROTO_ICMPV6:+ key_layer |= NFP_FLOWER_LAYER_TP;+ key_size += sizeof(struct nfp_flower_tp_ports);+ break;+ default:+ /* Other ip proto - we need check the masks for the+ * remainer of the key to ensure we can offload.+ */+ return -EOPNOTSUPP;+ }+ }++ ret_key_ls->key_layer = key_layer;+ ret_key_ls->key_layer_two = key_layer_two;+ ret_key_ls->key_size = key_size;++ return 0;+}++static struct nfp_fl_payload *+nfp_flower_allocate_new(struct nfp_fl_key_ls *key_layer)+{+ struct nfp_fl_payload *flow_pay;++ flow_pay = kmalloc(sizeof(*flow_pay), GFP_KERNEL);+ if (!flow_pay)+ return NULL;++ flow_pay->meta.key_len = key_layer->key_size;+ flow_pay->unmasked_data = kmalloc(key_layer->key_size, GFP_KERNEL);+ if (!flow_pay->unmasked_data)+ goto err_free_flow;++ flow_pay->meta.mask_len = key_layer->key_size;+ flow_pay->mask_data = kmalloc(key_layer->key_size, GFP_KERNEL);+ if (!flow_pay->mask_data)+ goto err_free_unmasked;++ flow_pay->meta.flags = 0;++ return flow_pay;++err_free_unmasked:+ kfree(flow_pay->unmasked_data);+err_free_flow:+ kfree(flow_pay);+ return NULL;+}++static void nfp_flower_deallocate_nfp(struct nfp_fl_payload *flow_pay)+{+ kfree(flow_pay->mask_data);+ kfree(flow_pay->unmasked_data);+ kfree(flow_pay);+}+ /** * nfp_flower_add_offload() - Adds a new flow to hardware. * @app: Pointer to the APP handle
From: Simon Horman <hidden> Date: 2017-06-29 08:14:34
On Wed, Jun 28, 2017 at 07:33:02PM -0700, Jakub Kicinski wrote:
On Wed, 28 Jun 2017 22:30:00 +0200, Simon Horman wrote:
quoted
From: Pieter Jansen van Vuuren <redacted>
Adds metadata describing the mask id of each flow and keeps track of
flows installed in hardware. Previously a flow could not be removed
from hardware as there was no way of knowing if that a specific flow
was installed. This is solved by storing the offloaded flows in a
hash table.
Signed-off-by: Pieter Jansen van Vuuren <redacted>
Signed-off-by: Simon Horman <redacted>
@@ -351,6 +343,12 @@ static int nfp_flower_init(struct nfp_app *app)if(!app->priv)return-ENOMEM;+err=nfp_flower_metadata_init(app);+if(nfp_flower_metadata_init(app)){
You're calling init twice here. Also please do the error path with
goto, as explained in review of patch 8 having a proper unwind makes
later patches easier to review.
Sorry, that was a brain-o on my part. Will fix that and add proper unwind
as you suggest.
nfp_release_mask_id() will reset the time stamp and put the mask at the
end of the queue. Is that OK?
I discussed this with Pieter. He believes that it is ok as it would be too
early to use the entry and its better put it to the back of the list and
skip to the next one.
From: Simon Horman <hidden> Date: 2017-06-29 08:15:25
On Wed, Jun 28, 2017 at 07:55:18PM -0700, Jakub Kicinski wrote:
On Wed, 28 Jun 2017 22:30:01 +0200, Simon Horman wrote:
quoted
From: Pieter Jansen van Vuuren <redacted>
Previously there was no way of updating flow rule stats after they
have been offloaded to hardware. This is solved by keeping track of
stats received from hardware and providing this to the TC handler
on request.
Signed-off-by: Pieter Jansen van Vuuren <redacted>
Signed-off-by: Simon Horman <redacted>
quoted
@@ -334,7 +441,10 @@ int nfp_modify_flow_metadata(struct nfp_app *app, /* Update flow payload with mask ids. */ nfp_flow->unmasked_data[NFP_FL_MASK_ID_LOCATION] = new_mask_id;- return 0;+ /* Release the stats ctx id. */+ temp_ctx_id = be32_to_cpu(nfp_flow->meta.host_ctx_id);++ return nfp_release_stats_entry(app, temp_ctx_id); } int nfp_flower_metadata_init(struct nfp_app *app)
@@ -362,6 +472,15 @@ int nfp_flower_metadata_init(struct nfp_app *app) return -ENOMEM; }+ /* Init ring buffer and unallocated stats_ids. */+ priv->stats_ids.free_list.buf =+ vmalloc(NFP_FL_STATS_ENTRY_RS * NFP_FL_STATS_ELEM_RS);+ if (!priv->stats_ids.free_list.buf) {+ vfree(priv->mask_ids.mask_id_free_list.buf);+ return -ENOMEM;
This is hiding a leak, I think. There were 2 things allocate above.
Please add a proper unwind path with goto's - it makes catching bugs
like this much easier.
nfp_release_mask_id() will reset the time stamp and put the mask at the
end of the queue. Is that OK?
I discussed this with Pieter. He believes that it is ok as it would be too
early to use the entry and its better put it to the back of the list and
skip to the next one.
But we shouldn't update the "last use" time if the grace period haven't
elapsed otherwise we can live lock (I know, unlikely). Could we simply
move the time check right after the:
*mask_id = temp_id;
line? I.e. move the check before we actually pick the mask off the
queue?
nfp_release_mask_id() will reset the time stamp and put the mask at the
end of the queue. Is that OK?
I discussed this with Pieter. He believes that it is ok as it would be too
early to use the entry and its better put it to the back of the list and
skip to the next one.
But we shouldn't update the "last use" time if the grace period haven't
elapsed otherwise we can live lock (I know, unlikely). Could we simply
move the time check right after the:
*mask_id = temp_id;
line? I.e. move the check before we actually pick the mask off the
queue?
Thanks, we now have a solution along those lines working.
From: David Laight <hidden> Date: 2017-06-29 13:47:51
From: Jakub Kicinski
Sent: 29 June 2017 07:48
On Thu, 29 Jun 2017 14:18:07 +0800, Yunsheng Lin wrote:
quoted
quoted
+ if (mask_basic->n_proto) {
cpu_to_be16(mask_basic->n_proto)
Should be be16_to_cpu()
quoted
remove cpu_to_be16 in case.
Thanks, but this is incorrect. Byte swapping constants is done at
compilation time - therefore it's preferred.
Except that the 'cpu' values are likely to be dense so the compiler
is likely to generate a jump table for the switch statement instead
of sequence of conditionals.
OTOH the jump table is almost certainly a data cache miss, whereas
the conditionals might be predicted correctly.
The best code might come from an explicitly ordered sequence of
conditionals.
David
+ * nfp_flower_del_offload() - Removes a flow from hardware.+ * @app: Pointer to the APP handle+ * @netdev: netdev structure.+ * @flow: TC flower classifier offload structure
The copy from patchworks has some damage on this line
* @flow: ֲ| ֲ| ֲ| ֲ| ֲ| ֲ| TC flower classifier offload structure
and the same line for get stats, take a look
quoted hunk
+ * nfp_flower_get_stats() - Populates flow stats obatain from hardware.+ * @app: Pointer to the APP handle+ * @flow: TC flower classifier offload structure <-- here too
+ * nfp_flower_del_offload() - Removes a flow from hardware.+ * @app: Pointer to the APP handle+ * @netdev: netdev structure.+ * @flow: TC flower classifier offload structure
The copy from patchworks has some damage on this line
* @flow: ֲ| ֲ| ֲ| ֲ| ֲ| ֲ| TC flower classifier offload structure
and the same line for get stats, take a look
Thanks, I will fix that whitespace damage.
quoted
+ * nfp_flower_get_stats() - Populates flow stats obatain from hardware.+ * @app: Pointer to the APP handle+ * @flow: TC flower classifier offload structure <-- here too
From: Or Gerlitz <hidden> Date: 2017-06-29 14:39:35
On Wed, Jun 28, 2017 at 11:30 PM, Simon Horman
[off-list ref] wrote:
From: Pieter Jansen van Vuuren <redacted>
Previously there was no way of updating flow rule stats after they
have been offloaded to hardware. This is solved by keeping track of
stats received from hardware and providing this to the TC handler
on request.
You are using the term/variable "unmasked_data" across the code, to
make it clear
the keys provided to the driver are masked by the tcflower kernel code
[1] - what do
you mean by unmasked data?
Or.
[1] f93bd17 net/sched: cls_flower: Use masked key when calling HW offloads
From: Simon Horman <hidden> Date: 2017-06-29 14:54:02
On Thu, Jun 29, 2017 at 05:39:34PM +0300, Or Gerlitz wrote:
On Wed, Jun 28, 2017 at 11:30 PM, Simon Horman
[off-list ref] wrote:
quoted
From: Pieter Jansen van Vuuren <redacted>
Previously there was no way of updating flow rule stats after they
have been offloaded to hardware. This is solved by keeping track of
stats received from hardware and providing this to the TC handler
on request.
You are using the term/variable "unmasked_data" across the code, to
make it clear
the keys provided to the driver are masked by the tcflower kernel code
[1] - what do
you mean by unmasked data?
Or.
[1] f93bd17 net/sched: cls_flower: Use masked key when calling HW offloads
From a firmware point of view there is an unmasked key and a mask.
These are referred to as unmasked_data and mask_data although in
TC supplies a masked key which the firmware can also handle.
what's the role of the mask_version flag here and elsewhere in the
sister functions?
Hi Or,
I chatted with Pieter about this and my understanding is that metadata
comes in pairs; masked and umasked. The mask_version parameter controls
which of the pair is compiled.
From: Or Gerlitz <hidden> Date: 2017-06-29 15:16:42
On Wed, Jun 28, 2017 at 11:30 PM, Simon Horman
[off-list ref] wrote:
From: Pieter Jansen van Vuuren <redacted>
Previously there was no way of updating flow rule stats after they
have been offloaded to hardware. This is solved by keeping track of
stats received from hardware and providing this to the TC handler
on request.
@@ -245,7 +245,11 @@ struct nfp_flower_cmsg_hdr {/* Types defined for port related control messages */enumnfp_flower_cmsg_type_port{+NFP_FLOWER_CMSG_TYPE_FLOW_ADD=0,+NFP_FLOWER_CMSG_TYPE_FLOW_MOD=1,
AFAIU flower offload will always use delete and add and not modify,
if you think otherwise, would love to hear that. Didn't see you are using
the MOD define in the code anywhere.
From: Simon Horman <hidden> Date: 2017-06-29 15:28:00
On Thu, Jun 29, 2017 at 06:16:41PM +0300, Or Gerlitz wrote:
On Wed, Jun 28, 2017 at 11:30 PM, Simon Horman
[off-list ref] wrote:
quoted
From: Pieter Jansen van Vuuren <redacted>
Previously there was no way of updating flow rule stats after they
have been offloaded to hardware. This is solved by keeping track of
stats received from hardware and providing this to the TC handler
on request.
@@ -245,7 +245,11 @@ struct nfp_flower_cmsg_hdr {/* Types defined for port related control messages */enumnfp_flower_cmsg_type_port{+NFP_FLOWER_CMSG_TYPE_FLOW_ADD=0,+NFP_FLOWER_CMSG_TYPE_FLOW_MOD=1,
AFAIU flower offload will always use delete and add and not modify,
if you think otherwise, would love to hear that. Didn't see you are using
the MOD define in the code anywhere.
The firmware API has a mod operation but you are correct that
we are not implementing that operation in this patch-set.
@@ -245,7 +245,11 @@ struct nfp_flower_cmsg_hdr {/* Types defined for port related control messages */enumnfp_flower_cmsg_type_port{+NFP_FLOWER_CMSG_TYPE_FLOW_ADD=0,+NFP_FLOWER_CMSG_TYPE_FLOW_MOD=1,
AFAIU flower offload will always use delete and add and not modify,
if you think otherwise, would love to hear that. Didn't see you are using
the MOD define in the code anywhere.
The firmware API has a mod operation but you are correct that
we are not implementing that operation in this patch-set.
that wasn't my comment. I said that AFAIU flower will never ask you to
modify, they
will ask to delete and later add, so I would be happy to know if you
see it differently.
@@ -245,7 +245,11 @@ struct nfp_flower_cmsg_hdr {/* Types defined for port related control messages */enumnfp_flower_cmsg_type_port{+NFP_FLOWER_CMSG_TYPE_FLOW_ADD=0,+NFP_FLOWER_CMSG_TYPE_FLOW_MOD=1,
AFAIU flower offload will always use delete and add and not modify,
if you think otherwise, would love to hear that. Didn't see you are using
the MOD define in the code anywhere.
The firmware API has a mod operation but you are correct that
we are not implementing that operation in this patch-set.
that wasn't my comment. I said that AFAIU flower will never ask you to
modify, they
will ask to delete and later add, so I would be happy to know if you
see it differently.
Yes, I agree.
Sorry for not answering your question properly the first time.