Re: [ovs-dev] [PATCH ovn v1 1/2] tests: Updated expected log message

2019-12-08 Thread Dumitru Ceara
On Sun, Dec 8, 2019 at 5:18 AM Russell Bryant  wrote:
>
> A previous commit added more detail to this log message.  Fix the test
> to reflect the new text.
>
> Signed-off-by: Russell Bryant 

Hi Russell,

Thanks for fixing the failing test case.

Acked-by: Dumitru Ceara 

> ---
>  tests/ovn.at | 12 ++--
>  1 file changed, 6 insertions(+), 6 deletions(-)
>
> diff --git a/tests/ovn.at b/tests/ovn.at
> index 8f4d9a440..1d5369341 100644
> --- a/tests/ovn.at
> +++ b/tests/ovn.at
> @@ -13618,22 +13618,22 @@ ovn-nbctl list logical_switch_port
>  # Now try to add duplicate addresses on a new port. These should all fail
>  ovn-nbctl --wait=sb lsp-add sw1 sw1-p5
>  AT_CHECK([ovn-nbctl lsp-set-addresses sw1-p5 "00:00:00:00:00:04 10.0.0.1"], 
> [1], [],
> -[ovn-nbctl: Error on switch sw1: duplicate IPv4 address 10.0.0.1
> +[ovn-nbctl: Error on switch sw1: duplicate IPv4 address '10.0.0.1' found on 
> logical switch port 'sw1-p1'
>  ])
>  AT_CHECK([ovn-nbctl lsp-set-addresses sw1-p5 "00:00:00:00:00:04 10.0.0.2"], 
> [1], [],
> -[ovn-nbctl: Error on switch sw1: duplicate IPv4 address 10.0.0.2
> +[ovn-nbctl: Error on switch sw1: duplicate IPv4 address '10.0.0.2' found on 
> logical switch port 'sw1-p1'
>  ])
>  AT_CHECK([ovn-nbctl lsp-set-addresses sw1-p5 "00:00:00:00:00:04 aef0::1"], 
> [1], [],
> -[ovn-nbctl: Error on switch sw1: duplicate IPv6 address aef0::1
> +[ovn-nbctl: Error on switch sw1: duplicate IPv6 address 'aef0::1' found on 
> logical switch port 'sw1-p1'
>  ])
>  AT_CHECK([ovn-nbctl lsp-set-addresses sw1-p5 "00:00:00:00:00:04 aef0::2"], 
> [1], [],
> -[ovn-nbctl: Error on switch sw1: duplicate IPv6 address aef0::2
> +[ovn-nbctl: Error on switch sw1: duplicate IPv6 address 'aef0::2' found on 
> logical switch port 'sw1-p1'
>  ])
>  AT_CHECK([ovn-nbctl lsp-set-addresses sw1-p5 "00:00:00:00:00:04 
> 192.168.0.2"], [1], [],
> -[ovn-nbctl: Error on switch sw1: duplicate IPv4 address 192.168.0.2
> +[ovn-nbctl: Error on switch sw1: duplicate IPv4 address '192.168.0.2' found 
> on logical switch port 'sw1-p2'
>  ])
>  AT_CHECK([ovn-nbctl lsp-set-addresses sw1-p5 "00:00:00:00:00:04 
> 192.168.0.3"], [1], [],
> -[ovn-nbctl: Error on switch sw1: duplicate IPv4 address 192.168.0.3
> +[ovn-nbctl: Error on switch sw1: duplicate IPv4 address '192.168.0.3' found 
> on logical switch port 'sw1-p3'
>  ])
>
>  # Now try re-setting sw1-p1. This should succeed
> --
> 2.23.0
>
> ___
> dev mailing list
> d...@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>

___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


Re: [ovs-dev] [PATCH V3 08/19] netdev-offload-dpdk: Protect UFID map by mutex

2019-12-08 Thread Eli Britstein

On 12/9/2019 9:15 AM, 贺鹏 wrote:
> Hi,
>
>
> cmap support multiple readers and one writer.
> since all write operations are performed in the offload thread,
> why need a mutex here? Maybe I miss some patches.
Collecting statistics using netdev_flow_get in patch 10/20 is another 
thread. There, it gets the rte_flow, but if not protected it might get 
destroyed by the offload thread before it uses it.
>
>
>
> Eli Britstein  于2019年12月8日周日 下午9:23写道:
>
>> Flow deletion and dumping for statistics collection are called from
>> different threads. As a pre-step towards collecting HW statistics,
>> protect the UFID map by mutex to make it thread safe.
>>
>> Signed-off-by: Eli Britstein 
>> ---
>>   lib/netdev-offload-dpdk.c | 7 ++-
>>   1 file changed, 6 insertions(+), 1 deletion(-)
>>
>> diff --git a/lib/netdev-offload-dpdk.c b/lib/netdev-offload-dpdk.c
>> index b2ec05cec..5568400b6 100644
>> --- a/lib/netdev-offload-dpdk.c
>> +++ b/lib/netdev-offload-dpdk.c
>> @@ -51,6 +51,7 @@ static struct vlog_rate_limit error_rl = 
>> VLOG_RATE_LIMIT_INIT(100, 5);
>>* A mapping from ufid to dpdk rte_flow.
>>*/
>>   static struct cmap ufid_to_rte_flow = CMAP_INITIALIZER;
>> +static struct ovs_mutex ufid_map_mutex = OVS_MUTEX_INITIALIZER;
>>
>>   struct ufid_to_rte_flow_data {
>>   struct cmap_node node;
>> @@ -630,8 +631,11 @@ netdev_offload_dpdk_destroy_flow(struct netdev *netdev,
>>struct rte_flow *rte_flow)
>>   {
>>   struct rte_flow_error error;
>> -int ret = netdev_dpdk_rte_flow_destroy(netdev, rte_flow, );
>> +int ret;
>> +
>> +ovs_mutex_lock(_map_mutex);
>>
>> +ret = netdev_dpdk_rte_flow_destroy(netdev, rte_flow, );
>>   if (ret == 0) {
>>   ufid_to_rte_flow_disassociate(ufid);
>>   VLOG_DBG("%s: removed rte flow %p associated with ufid " UUID_FMT 
>> "\n",
>> @@ -642,6 +646,7 @@ netdev_offload_dpdk_destroy_flow(struct netdev *netdev,
>>netdev_get_name(netdev), error.message, error.type);
>>   }
>>
>> +ovs_mutex_unlock(_map_mutex);
>>   return ret;
>>   }
>>
>> --
>> 2.14.5
>>
>> ___
>> dev mailing list
>> d...@openvswitch.org
>> https://eur03.safelinks.protection.outlook.com/?url=https%3A%2F%2Fmail.openvswitch.org%2Fmailman%2Flistinfo%2Fovs-devdata=02%7C01%7Celibr%40mellanox.com%7C9af2f119de544768711408d77c779a66%7Ca652971c7d2e4d9ba6a4d149256f461b%7C0%7C0%7C637114725449215533sdata=VyrLUh6%2BP0ne9dXUSDjME31NBj0tHTV%2FEciNZY%2Baugo%3Dreserved=0
>
>
> --
> hepeng
> ICT
___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


Re: [ovs-dev] [PATCH V3 08/19] netdev-offload-dpdk: Protect UFID map by mutex

2019-12-08 Thread 贺鹏
Hi,


cmap support multiple readers and one writer.
since all write operations are performed in the offload thread,
why need a mutex here? Maybe I miss some patches.



Eli Britstein  于2019年12月8日周日 下午9:23写道:

>
> Flow deletion and dumping for statistics collection are called from
> different threads. As a pre-step towards collecting HW statistics,
> protect the UFID map by mutex to make it thread safe.
>
> Signed-off-by: Eli Britstein 
> ---
>  lib/netdev-offload-dpdk.c | 7 ++-
>  1 file changed, 6 insertions(+), 1 deletion(-)
>
> diff --git a/lib/netdev-offload-dpdk.c b/lib/netdev-offload-dpdk.c
> index b2ec05cec..5568400b6 100644
> --- a/lib/netdev-offload-dpdk.c
> +++ b/lib/netdev-offload-dpdk.c
> @@ -51,6 +51,7 @@ static struct vlog_rate_limit error_rl = 
> VLOG_RATE_LIMIT_INIT(100, 5);
>   * A mapping from ufid to dpdk rte_flow.
>   */
>  static struct cmap ufid_to_rte_flow = CMAP_INITIALIZER;
> +static struct ovs_mutex ufid_map_mutex = OVS_MUTEX_INITIALIZER;
>
>  struct ufid_to_rte_flow_data {
>  struct cmap_node node;
> @@ -630,8 +631,11 @@ netdev_offload_dpdk_destroy_flow(struct netdev *netdev,
>   struct rte_flow *rte_flow)
>  {
>  struct rte_flow_error error;
> -int ret = netdev_dpdk_rte_flow_destroy(netdev, rte_flow, );
> +int ret;
> +
> +ovs_mutex_lock(_map_mutex);
>
> +ret = netdev_dpdk_rte_flow_destroy(netdev, rte_flow, );
>  if (ret == 0) {
>  ufid_to_rte_flow_disassociate(ufid);
>  VLOG_DBG("%s: removed rte flow %p associated with ufid " UUID_FMT 
> "\n",
> @@ -642,6 +646,7 @@ netdev_offload_dpdk_destroy_flow(struct netdev *netdev,
>   netdev_get_name(netdev), error.message, error.type);
>  }
>
> +ovs_mutex_unlock(_map_mutex);
>  return ret;
>  }
>
> --
> 2.14.5
>
> ___
> dev mailing list
> d...@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev



--
hepeng
ICT
___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


[ovs-dev] [PATCH 3/3] checkpatch: Check spelling in commit messages.

2019-12-08 Thread Ilya Maximets
This seems useful as I'm usually making a lot of typing mistakes.
Also, few commonly used words added to the extended dictionary.

Signed-off-by: Ilya Maximets 
---
 utilities/checkpatch.py | 33 ++---
 1 file changed, 22 insertions(+), 11 deletions(-)

diff --git a/utilities/checkpatch.py b/utilities/checkpatch.py
index 1b14ca5d5..3378e8c3e 100755
--- a/utilities/checkpatch.py
+++ b/utilities/checkpatch.py
@@ -32,7 +32,7 @@ print_file_name = None
 checking_file = False
 total_line = 0
 colors = False
-spellcheck_comments = False
+spellcheck = False
 quiet = False
 spell_check_dict = None
 
@@ -84,7 +84,12 @@ def open_spell_check_dict():
   'cacheline', 'xlate', 'skiplist', 'idl',
   'comparator', 'natting', 'alg', 'pasv', 'epasv',
   'wildcard', 'nated', 'amd64', 'x86_64',
-  'recirculation']
+  'recirculation', 'linux', 'afxdp', 'promisc', 'goto',
+  'misconfigured', 'misconfiguration', 'checkpatch',
+  'debian', 'travis', 'cirrus', 'appveyor', 'faq',
+  'erspan', 'const', 'hotplug', 'addresssanitizer',
+  'ovsdb', 'dpif', 'veth', 'rhel', 'jsonrpc', 'json',
+  'syscall', 'lacp', 'ipf', 'skb', 'valgrind']
 
 global spell_check_dict
 spell_check_dict = enchant.Dict("en_US")
@@ -372,12 +377,14 @@ def filter_comments(current_line, keep=False):
 return sanitized_line
 
 
-def check_comment_spelling(line):
-if not spell_check_dict or not spellcheck_comments:
+def check_spelling(line, comment):
+if not spell_check_dict or not spellcheck:
 return False
 
-comment_words = filter_comments(line, True).replace(':', ' ').split(' ')
-for word in comment_words:
+words = filter_comments(line, True) if comment else line
+words = words.replace(':', ' ').split(' ')
+
+for word in words:
 skip = False
 strword = re.subn(r'\W+', '', word)[0].replace(',', '')
 if (len(strword)
@@ -561,7 +568,7 @@ checks = [
 
 {'regex': r'(\.c|\.h)(\.in)?$', 'match_name': None,
  'prereq': lambda x: has_comment(x),
- 'check': lambda x: check_comment_spelling(x)},
+ 'check': lambda x: check_spelling(x, True)},
 
 {'regex': r'(\.c|\.h)(\.in)?$', 'match_name': None,
  'check': lambda x: empty_return_with_brace(x),
@@ -811,6 +818,9 @@ def ovs_checkpatch_parse(text, filename, author=None, 
committer=None):
 print_error(
 "Remove Gerrit Change-Id's before submitting upstream.")
 print("%d: %s\n" % (lineno, line))
+elif spellcheck:
+check_spelling(line, False)
+
 elif parse == PARSE_STATE_CHANGE_BODY:
 newfile = hunks.match(line)
 if newfile:
@@ -873,7 +883,8 @@ Check options:
 -l|--skip-leading-whitespace   Skips the leading whitespace test
 -q|--quiet Only print error and warning information
 -s|--skip-signoff-linesTolerate missing Signed-off-by line
--S|--spellcheck-comments   Check C comments for possible spelling mistakes
+-S|--spellcheckCheck C comments and commit-message for possible
+   spelling mistakes
 -t|--skip-trailing-whitespace  Skips the trailing whitespace test"""
   % sys.argv[0])
 
@@ -931,7 +942,7 @@ if __name__ == '__main__':
"skip-leading-whitespace",
"skip-signoff-lines",
"skip-trailing-whitespace",
-   "spellcheck-comments",
+   "spellcheck",
"quiet"])
 except:
 print("Unknown option encountered. Please rerun with -h for help.")
@@ -951,12 +962,12 @@ if __name__ == '__main__':
 skip_trailing_whitespace_check = True
 elif o in ("-f", "--check-file"):
 checking_file = True
-elif o in ("-S", "--spellcheck-comments"):
+elif o in ("-S", "--spellcheck"):
 if not open_spell_check_dict():
 print("WARNING: The enchant library isn't available.")
 print(" Please install python enchant.")
 else:
-spellcheck_comments = True
+spellcheck = True
 elif o in ("-q", "--quiet"):
 quiet = True
 else:
-- 
2.17.1

___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


[ovs-dev] [PATCH 2/3] checkpatch: Skip words containing numbers.

2019-12-08 Thread Ilya Maximets
Words like 'br0' are common and usually references some code or
database objects that should not be targets for spell checking.
So, it's better to skip all the words that has digits inside instead
of ones that starts with numbers.

Signed-off-by: Ilya Maximets 
---
 utilities/checkpatch.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/utilities/checkpatch.py b/utilities/checkpatch.py
index 6d95b0e2f..1b14ca5d5 100755
--- a/utilities/checkpatch.py
+++ b/utilities/checkpatch.py
@@ -396,8 +396,8 @@ def check_comment_spelling(line):
  strword[1:].islower()):
 skip = True
 
-# skip words that start with numbers
-if strword.startswith(tuple('0123456789')):
+# skip words containing numbers
+if any(check_char.isdigit() for check_char in strword):
 skip = True
 
 if not skip:
-- 
2.17.1

___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


[ovs-dev] [PATCH 1/3] checkpatch: Allow common abbreviations for spell checking.

2019-12-08 Thread Ilya Maximets
Abbreviations of Latin expressions like 'i.e.' or 'e.g.' are common
and known by the dictionary.  However, our spell checker is not able
to recognize them because it strips dots out of them.  To avoid this
issue we could pass non-stripped version of the word to the dictionary
checker too.

Signed-off-by: Ilya Maximets 
---
 utilities/checkpatch.py | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/utilities/checkpatch.py b/utilities/checkpatch.py
index 9b79d268f..6d95b0e2f 100755
--- a/utilities/checkpatch.py
+++ b/utilities/checkpatch.py
@@ -380,7 +380,9 @@ def check_comment_spelling(line):
 for word in comment_words:
 skip = False
 strword = re.subn(r'\W+', '', word)[0].replace(',', '')
-if len(strword) and not spell_check_dict.check(strword.lower()):
+if (len(strword)
+and not spell_check_dict.check(strword.lower())
+and not spell_check_dict.check(word.lower())):
 if any([check_char in word
 for check_char in ['=', '(', '-', '_', '/', '\'']]):
 skip = True
-- 
2.17.1

___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


[ovs-dev] [PATCH 0/3] checkpatch: Spell checker enhancements.

2019-12-08 Thread Ilya Maximets
Ilya Maximets (3):
  checkpatch: Allow common abbreviations for spell checking.
  checkpatch: Skip words containing numbers.
  checkpatch: Check spelling in commit messages.

 utilities/checkpatch.py | 41 +++--
 1 file changed, 27 insertions(+), 14 deletions(-)

-- 
2.17.1

___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


[ovs-dev] [PATCH 0/2] Get rid of broken dpif pointer in dp_netdev structure.

2019-12-08 Thread Ilya Maximets
Ilya Maximets (2):
  dpif: Turn dpif_flow_hash function into generic odp_flow_key_hash.
  dpif-netdev: Get rid of broken dpif pointer in dp_netdev structure.

 lib/dpif-netdev.c  | 12 +---
 lib/dpif-netlink.c | 27 ---
 lib/dpif.c | 16 
 lib/dpif.h |  4 +---
 lib/odp-util.c | 17 +
 lib/odp-util.h |  2 +-
 ofproto/ofproto-dpif.c |  2 +-
 7 files changed, 33 insertions(+), 47 deletions(-)

-- 
2.17.1

___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


[ovs-dev] [PATCH 2/2] dpif-netdev: Get rid of broken dpif pointer in dp_netdev structure.

2019-12-08 Thread Ilya Maximets
This pointer was introduced in July 2014 by commit
6b31e07347ad ("dpif-netdev: Polling threads directly call ofproto upcall 
functions.")
and it was broken right from this point because dpif_netdev_open()
updates it on each call with the pointer to a newly allocated
'dpif' structure that becomes invalid on the next dpif_netdev_close().
Since dpif_open/close() always happens asynchronously from different
threads and pointer is not protected by rcu or mutex (it's not even
atomic) it's not possible to safely use it.  Thankfully the actual
usage was in repository for less than 3 weeks and was removed by
commit 623540e4617e ("dpif-netdev: Streamline miss handling.").  Until
recently this pointer was used in order to pass it to dpif_flow_hash().
Another luck is that dpif_flow_hash() didn't use the 'dpif' argument.

However, we tried to use it while netdev offloading by commit
30115809da2e ("dpif-netdev: Use netdev-offload API for port lookup while 
offloading.")
and that unveiled the issue.

Now that all the code that used this pointer was cleaned up we can
just remove it from the structure to avoid possible misuse in the
future.

Signed-off-by: Ilya Maximets 
---
 lib/dpif-netdev.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index ffb3cd420..38d1f12ef 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -303,7 +303,6 @@ struct pmd_auto_lb {
 struct dp_netdev {
 const struct dpif_class *const class;
 const char *const name;
-struct dpif *dpif;
 struct ovs_refcount ref_cnt;
 atomic_flag destroyed;
 
@@ -1618,7 +1617,6 @@ dpif_netdev_open(const struct dpif_class *class, const 
char *name,
 }
 if (!error) {
 *dpifp = create_dpif_netdev(dp);
-dp->dpif = *dpifp;
 }
 ovs_mutex_unlock(_netdev_mutex);
 
-- 
2.17.1

___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


[ovs-dev] [PATCH 1/2] dpif: Turn dpif_flow_hash function into generic odp_flow_key_hash.

2019-12-08 Thread Ilya Maximets
Current implementation of dpif_flow_hash() doesn't depend on datapath
interface and only complicates the callers by forcing them to figure
out what is their current 'dpif'.  If we'll need different hashing
for different 'dpif's we'll implement an API for dpif-providers
and each dpif implementation will be able to use their local function
directly without calling it via dpif API.

This change will allow us to not store 'dpif' pointer in the userspace
datapath implementation which is broken and will be removed in next
commits.

This patch moves dpif_flow_hash() to odp-util module and replaces
unused odp_flow_key_hash() by it, along with removing of unused 'dpif'
argument.

Signed-off-by: Ilya Maximets 
---
 lib/dpif-netdev.c  | 10 +-
 lib/dpif-netlink.c | 27 ---
 lib/dpif.c | 16 
 lib/dpif.h |  4 +---
 lib/odp-util.c | 17 +
 lib/odp-util.h |  2 +-
 ofproto/ofproto-dpif.c |  2 +-
 7 files changed, 33 insertions(+), 45 deletions(-)

diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 7ebf4ef87..ffb3cd420 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -2984,7 +2984,7 @@ dp_netdev_pmd_find_flow(const struct dp_netdev_pmd_thread 
*pmd,
 /* If a UFID is not provided, determine one based on the key. */
 if (!ufidp && key && key_len
 && !dpif_netdev_flow_from_nlattrs(key, key_len, , false)) {
-dpif_flow_hash(pmd->dp->dpif, , sizeof flow, );
+odp_flow_key_hash(, sizeof flow, );
 ufidp = 
 }
 
@@ -3203,7 +3203,7 @@ dp_netdev_get_mega_ufid(const struct match *match, 
ovs_u128 *mega_ufid)
 ((uint8_t *)_flow)[i] = ((uint8_t *)>flow)[i] &
((uint8_t *)>wc)[i];
 }
-dpif_flow_hash(NULL, _flow, sizeof(struct flow), mega_ufid);
+odp_flow_key_hash(_flow, sizeof masked_flow, mega_ufid);
 }
 
 static struct dp_netdev_flow *
@@ -3407,7 +3407,7 @@ dpif_netdev_flow_put(struct dpif *dpif, const struct 
dpif_flow_put *put)
 if (put->ufid) {
 ufid = *put->ufid;
 } else {
-dpif_flow_hash(dpif, , sizeof match.flow, );
+odp_flow_key_hash(, sizeof match.flow, );
 }
 
 /* The Netlink encoding of datapath flow keys cannot express
@@ -6615,7 +6615,7 @@ handle_packet_upcall(struct dp_netdev_pmd_thread *pmd,
 ofpbuf_clear(actions);
 ofpbuf_clear(put_actions);
 
-dpif_flow_hash(pmd->dp->dpif, , sizeof match.flow, );
+odp_flow_key_hash(, sizeof match.flow, );
 error = dp_netdev_upcall(pmd, packet, , ,
  , DPIF_UC_MISS, NULL, actions,
  put_actions);
@@ -7152,7 +7152,7 @@ dp_execute_cb(void *aux_, struct dp_packet_batch 
*packets_,
 struct dp_packet *packet;
 DP_PACKET_BATCH_FOR_EACH (i, packet, packets_) {
 flow_extract(packet, );
-dpif_flow_hash(dp->dpif, , sizeof flow, );
+odp_flow_key_hash(, sizeof flow, );
 dp_execute_userspace_action(pmd, packet, should_steal, ,
 , , userdata);
 }
diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c
index e9a6887f7..23e513eff 100644
--- a/lib/dpif-netlink.c
+++ b/lib/dpif-netlink.c
@@ -153,7 +153,7 @@ static int dpif_netlink_flow_transact(struct 
dpif_netlink_flow *request,
   struct ofpbuf **bufp);
 static void dpif_netlink_flow_get_stats(const struct dpif_netlink_flow *,
 struct dpif_flow_stats *);
-static void dpif_netlink_flow_to_dpif_flow(struct dpif *, struct dpif_flow *,
+static void dpif_netlink_flow_to_dpif_flow(struct dpif_flow *,
const struct dpif_netlink_flow *);
 
 /* One of the dpif channels between the kernel and userspace. */
@@ -1527,7 +1527,7 @@ dpif_netlink_flow_dump_thread_destroy(struct 
dpif_flow_dump_thread *thread_)
 }
 
 static void
-dpif_netlink_flow_to_dpif_flow(struct dpif *dpif, struct dpif_flow *dpif_flow,
+dpif_netlink_flow_to_dpif_flow(struct dpif_flow *dpif_flow,
const struct dpif_netlink_flow *datapath_flow)
 {
 dpif_flow->key = datapath_flow->key;
@@ -1542,8 +1542,8 @@ dpif_netlink_flow_to_dpif_flow(struct dpif *dpif, struct 
dpif_flow *dpif_flow,
 dpif_flow->ufid = datapath_flow->ufid;
 } else {
 ovs_assert(datapath_flow->key && datapath_flow->key_len);
-dpif_flow_hash(dpif, datapath_flow->key, datapath_flow->key_len,
-   _flow->ufid);
+odp_flow_key_hash(datapath_flow->key, datapath_flow->key_len,
+  _flow->ufid);
 }
 dpif_netlink_flow_get_stats(datapath_flow, _flow->stats);
 dpif_flow->attrs.offloaded = false;
@@ -1716,8 +1716,7 @@ dpif_netlink_flow_dump_next(struct dpif_flow_dump_thread 
*thread_,
 if (dump->up.terse || 

Re: [ovs-dev] [PATCH v1] dpif-netdev: Retrieve dpif_class from struct dp_netdev

2019-12-08 Thread Ilya Maximets
On 08.12.2019 15:42, Ilya Maximets wrote:
> On 08.12.2019 15:29, Ophir Munk wrote:
>> In case a pmd pointer (struct dp_netdev_pmd_thread *) needs to retrieve
>> the dpif_class it points at - it can access it as:  pmd->dp->class.  A
>> second option is to access it as: pmd->dp->dpif->dpif_class. The first
>> option is safe since there is one dp netdev with a constant pointer to
>> the dpif class. The second option is not safe since the pointer
>> pmd->dp->dpif may be changed under the hood, for example, in case there
>> is a call to dpif_open(). One such scenario is when a netdev bridge is
>> running while dumping flows statistics with dpctl in parallel:
>> ovs-appctl dpctl/dump-flows. This commit makes usage of the first
>> safe option instead of the second option.
>>
>> Fixes: 30115809da2e ("dpif-netdev: Use netdev-offload API for port lookup 
>> while offloading")
>> Signed-off-by: Ophir Munk 
> 
> 
> Thanks Ophir!
> 
> I reproduced the issue locally and this patch will fix current case.
> I'll re-check it and apply to master.

Applied.
___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


Re: [ovs-dev] [RFC v3 0/4] netdev-offload: Prerequisites of vport offloading via DPDK.

2019-12-08 Thread Ophir Munk
Hi Ilya,
I think the root cause for the issues mentioned below is the usage of 
pmd->dp->dpif->dpif_class
rather than pmd->dp->class. Please see a fixing patch 
https://patchwork.ozlabs.org/patch/1205684/
("dpif-netdev: Retrieve dpif_class from struct dp_netdev ").

When running dpctl statistics there is a call to dpif_open(). As part of this 
call dp->dpif is assigned a new dpif pointer value.
However pmd->dp->dpif should assume that dp->dpif is fixed throughout its life 
time. 
Hence it is better to access the dpif_class through fixed pointers that do not 
change (pmd->dp->class).

With the fixing patch Eli issues are fixes.
Also when I updated your RFCs series to use pmd->dp->class - there is no more 
crash and everything works fine.
Ilya - can you please update the RFC series and send them as V1 patches? 
I will test them again and hopefully will be able to ACK them.

Regards,
Ophir

> -Original Message-
> From: Eli Britstein 
> Sent: Sunday, December 8, 2019 2:29 PM
> To: Ilya Maximets ; Ophir Munk
> ; ovs-dev@openvswitch.org
> Cc: Roni Bar Yanai ; Simon Horman
> ; Ameer Mahagneh
> 
> Subject: Re: [RFC v3 0/4] netdev-offload: Prerequisites of vport offloading 
> via
> DPDK.
> 
> 
> On 12/6/2019 4:34 PM, Ilya Maximets wrote:
> > On 06.12.2019 14:09, Ophir Munk wrote:
> >> Hi Ilya,
> >> I applied this series on master ("dpdk: Update to use DPDK 19.11.") and
> PINGed between two "dpdk" ports (hw-offload=true).
> >> It worked fine.
> >> Then I watched flow statistics (dpif based) by executing the command in
> (1):
> >> (1) watch ovs-appctl dpif/dump-flows -m  It worked fine.
> >> Then I watched flow statistics (dpctl based) by executing the command in
> (2):
> >> (2) watch ovs-appctl dpctl/dump-flows In this case OVS crashed after
> >> a few seconds.
> >>
> >> When inspecting the calls trace I notice that pmd->dp->dpif->dpif_class-
> >type is a corrupted memory address.
> >>
> >> (gdb) bt
> >> #0  0x00c26fda in dpif_normalize_type (type=0x7372  >> 0x7372 out of bounds>) at lib/dpif.c:517
> >> #1  0x00c19864 in dp_netdev_flow_offload_put
> >> (offload=offload@entry=0x7f11fc00b790) at lib/dpif-netdev.c:2378
> >> #2  0x00c19ca8 in dp_netdev_flow_offload_main
> >> (data=) at lib/dpif-netdev.c:2467
> >> #3  0x00ca3c9d in ovsthread_wrapper (aux_=)
> at
> >> lib/ovs-thread.c:383
> >> #4  0x7f12a2a08e25 in start_thread () from /lib64/libpthread.so.0
> >> #5  0x7f12a222c34d in clone () from /lib64/libc.so.6
> >>
> >> This scenario repeats whenever running the command in (2) and when
> the code calls dpif_normalize_type().
> >> It seems to me that the memory corruption was there for a while but only
> now it is exposed due to your rfc series.
> >>
> >> In order to observe this memory corruption I added the following
> printouts.
> >> I tested it with hw-offload=false:
> >> ovs-vsctl set Open_vSwitch . other_config:hw-offload=false I tested
> >> it on latest master without your rfc series.
> >>
> >> diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index
> >> 1e54936..18a804a 100644
> >> --- a/lib/dpif-netdev.c
> >> +++ b/lib/dpif-netdev.c
> >> @@ -3625,6 +3625,10 @@ dpif_netdev_flow_dump_next(struct
> dpif_flow_dump_thread *thread_,
> >>   }
> >>   }
> >>
> >> +VLOG_ERR("pmd->dp=%p pmd->dp->dpif=%p pmd->dp->dpif-
> >dpif_class=%p \
> >> + pmd->dp->dpif->full_name=%s",
> >> + pmd->dp, pmd->dp->dpif, pmd->dp->dpif->dpif_class,
> >> + pmd->dp->dpif->full_name);
> >>   do {
> >>   for (n_flows = 0; n_flows < flow_limit; n_flows++) {
> >>   struct cmap_node *node;
> >>
> >>
> >> Looking at the printouts the memory corruption is observed.
> >>
> >> Initially all printouts are identical and correct as expected.
> >>
> >> dpif_netdev(revalidator82)|ERR|pmd->dp=0x7fdfea3ea010
> >> pmd->dp->dpif=0x2525e70 pmd->dp->dpif->dpif_class=0xef3e80
> >> pmd->dp->dpif->full_name=netdev@ovs-netdev
> >> dpif_netdev(revalidator82)|ERR|pmd->dp=0x7fdfea3ea010
> >> pmd->dp->dpif=0x2525e70 pmd->dp->dpif->dpif_class=0xef3e80
> >> pmd->dp->dpif->full_name=netdev@ovs-netdev
> >> dpif_netdev(revalidator82)|ERR|pmd->dp=0x7fdfea3ea010
> >> pmd->dp->dpif=0x2525e70 pmd->dp->dpif->dpif_class=0xef3e80
> >> pmd->dp->dpif->full_name=netdev@ovs-netdev
> >>
> >> Around this point I executed the dpctl command in (2) and you can notice
> that the pointers pmd->dp->dp_dpif and beyond became modified.
> >>
> >> dpif_netdev(revalidator82)|ERR|pmd->dp=0x7fdfea3ea010
> >> pmd->dp->dpif=0x25c3280 pmd->dp->dpif->dpif_class=0x251c790
> >> pmd->dp->dpif->full_name=(null)
> >> dpif_netdev(revalidator82)|ERR|pmd->dp=0x7fdfea3ea010
> >> pmd->dp->dpif=0x25c3280 pmd->dp->dpif->dpif_class=0x33c03608
> >> pmd->dp->dpif->full_name=
> >> dpif_netdev(revalidator82)|ERR|pmd->dp=0x7fdfea3ea010
> >> pmd->dp->dpif=0x25c3280 pmd->dp->dpif->dpif_class=0x2605700
> >> pmd->dp->dpif->full_name=
> >> 

Re: [ovs-dev] [PATCH v1] dpif-netdev: Retrieve dpif_class from struct dp_netdev

2019-12-08 Thread Ilya Maximets
On 08.12.2019 15:29, Ophir Munk wrote:
> In case a pmd pointer (struct dp_netdev_pmd_thread *) needs to retrieve
> the dpif_class it points at - it can access it as:  pmd->dp->class.  A
> second option is to access it as: pmd->dp->dpif->dpif_class. The first
> option is safe since there is one dp netdev with a constant pointer to
> the dpif class. The second option is not safe since the pointer
> pmd->dp->dpif may be changed under the hood, for example, in case there
> is a call to dpif_open(). One such scenario is when a netdev bridge is
> running while dumping flows statistics with dpctl in parallel:
> ovs-appctl dpctl/dump-flows. This commit makes usage of the first
> safe option instead of the second option.
> 
> Fixes: 30115809da2e ("dpif-netdev: Use netdev-offload API for port lookup 
> while offloading")
> Signed-off-by: Ophir Munk 


Thanks Ophir!

I reproduced the issue locally and this patch will fix current case.
I'll re-check it and apply to master.

However, the root cause is that dpif_netdev_open() updates the 'dpif'
pointer on each call that ends up in using of a freed 'dpif'.  I'm
working on getting rid of this pointer from the dp_netdev strucutre,
so we'll not have same issue again.  Also, 'prerequisites' patch-set
still uses this pointer, so I'll need to update it.

Best regards, Ilya Maximets.
___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


[ovs-dev] [PATCH v1] dpif-netdev: Retrieve dpif_class from struct dp_netdev

2019-12-08 Thread Ophir Munk
In case a pmd pointer (struct dp_netdev_pmd_thread *) needs to retrieve
the dpif_class it points at - it can access it as:  pmd->dp->class.  A
second option is to access it as: pmd->dp->dpif->dpif_class. The first
option is safe since there is one dp netdev with a constant pointer to
the dpif class. The second option is not safe since the pointer
pmd->dp->dpif may be changed under the hood, for example, in case there
is a call to dpif_open(). One such scenario is when a netdev bridge is
running while dumping flows statistics with dpctl in parallel:
ovs-appctl dpctl/dump-flows. This commit makes usage of the first
safe option instead of the second option.

Fixes: 30115809da2e ("dpif-netdev: Use netdev-offload API for port lookup while 
offloading")
Signed-off-by: Ophir Munk 
---
 lib/dpif-netdev.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 1e54936..7ebf4ef 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -2269,7 +2269,7 @@ mark_to_flow_disassociate(struct dp_netdev_pmd_thread 
*pmd,
 struct netdev *port;
 odp_port_t in_port = flow->flow.in_port.odp_port;
 
-port = netdev_ports_get(in_port, pmd->dp->dpif->dpif_class);
+port = netdev_ports_get(in_port, pmd->dp->class);
 if (port) {
 ret = netdev_flow_del(port, >mega_ufid, NULL);
 netdev_close(port);
@@ -2410,7 +2410,7 @@ dp_netdev_flow_offload_put(struct dp_flow_offload_item 
*offload)
 }
 info.flow_mark = mark;
 
-port = netdev_ports_get(in_port, pmd->dp->dpif->dpif_class);
+port = netdev_ports_get(in_port, pmd->dp->class);
 if (!port || netdev_vport_is_vport_class(port->netdev_class)) {
 netdev_close(port);
 goto err_free;
-- 
2.8.4

___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


Re: [ovs-dev] [PATCH V3 10/19] dpif-netdev: Read hw stats during flow_dump_next() call

2019-12-08 Thread 0-day Robot
Bleep bloop.  Greetings Eli Britstein, I am a robot and I have tried out your 
patch.
Thanks for your contribution.

I encountered some error that I wasn't expecting.  See the details below.


checkpatch:
WARNING: Line is 81 characters long (recommended limit is 79)
#88 FILE: lib/dpif-netdev.c:3631:
non_atomic_ullong_add(_flow->stats.packet_count, 
stats.n_packets);

Lines checked: 112, Warnings: 1, Errors: 0


Please check this out.  If you feel there has been an error, please email 
acon...@redhat.com

Thanks,
0-day Robot
___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


Re: [ovs-dev] [PATCH V3 06/19] netdev-offload-dpdk: Framework for actions offload

2019-12-08 Thread 0-day Robot
Bleep bloop.  Greetings Eli Britstein, I am a robot and I have tried out your 
patch.
Thanks for your contribution.

I encountered some error that I wasn't expecting.  See the details below.


checkpatch:
WARNING: Line is 80 characters long (recommended limit is 79)
#159 FILE: lib/netdev-offload-dpdk.c:540:
flow = netdev_offload_dpdk_mark_rss(, netdev, info->flow_mark);

Lines checked: 190, Warnings: 1, Errors: 0


Please check this out.  If you feel there has been an error, please email 
acon...@redhat.com

Thanks,
0-day Robot
___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


[ovs-dev] [PATCH V3 04/19] netdev-offload-dpdk: Fix typo

2019-12-08 Thread Eli Britstein
Fixes: e8a2b5bf92bb ("netdev-dpdk: implement flow offload with rte flow")
Signed-off-by: Eli Britstein 
Reviewed-by: Oz Shlomo 
---
 lib/netdev-offload-dpdk.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/netdev-offload-dpdk.c b/lib/netdev-offload-dpdk.c
index e48ac3b63..041b72d53 100644
--- a/lib/netdev-offload-dpdk.c
+++ b/lib/netdev-offload-dpdk.c
@@ -656,7 +656,7 @@ netdev_offload_dpdk_add_flow(struct netdev *netdev,
actions.actions, );
 
 if (!flow) {
-VLOG_ERR("%s: rte flow creat error: %u : message : %s\n",
+VLOG_ERR("%s: rte flow create error: %u : message : %s\n",
  netdev_get_name(netdev), error.type, error.message);
 ret = -1;
 goto out;
-- 
2.14.5

___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


[ovs-dev] [PATCH V3 16/19] netdev-offload-dpdk: Support offload of set MAC actions

2019-12-08 Thread Eli Britstein
Signed-off-by: Eli Britstein 
Reviewed-by: Oz Shlomo 
---
 Documentation/howto/dpdk.rst |   1 +
 NEWS |   3 +-
 lib/netdev-dpdk.c|  15 ++
 lib/netdev-offload-dpdk.c| 107 +++
 4 files changed, 125 insertions(+), 1 deletion(-)

diff --git a/Documentation/howto/dpdk.rst b/Documentation/howto/dpdk.rst
index 6cedd7f63..d228493e9 100644
--- a/Documentation/howto/dpdk.rst
+++ b/Documentation/howto/dpdk.rst
@@ -392,6 +392,7 @@ Supported actions for hardware offload are:
 
 - Output (a single output, as the last action).
 - Drop.
+- Modification of Ethernet (mod_dl_src/mod_dl_dst).
 
 Further Reading
 ---
diff --git a/NEWS b/NEWS
index d019e066f..3ade86d49 100644
--- a/NEWS
+++ b/NEWS
@@ -26,7 +26,8 @@ Post-v2.12.0
  * DPDK ring ports (dpdkr) are deprecated and will be removed in next
releases.
  * Add support for DPDK 19.11.
- * Add hardware offload support for output and drop actions (experimental).
+ * Add hardware offload support for output, drop and set MAC actions
+   (experimental).
 
 v2.12.0 - 03 Sep 2019
 -
diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c
index 872a45e75..e67a3dd76 100644
--- a/lib/netdev-dpdk.c
+++ b/lib/netdev-dpdk.c
@@ -4723,6 +4723,21 @@ ds_put_flow_action(struct ds *s, const struct 
rte_flow_action *actions)
 }
 } else if (actions->type == RTE_FLOW_ACTION_TYPE_DROP) {
 ds_put_cstr(s, "rte flow drop action\n");
+} else if (actions->type == RTE_FLOW_ACTION_TYPE_SET_MAC_SRC ||
+   actions->type == RTE_FLOW_ACTION_TYPE_SET_MAC_DST) {
+const struct rte_flow_action_set_mac *set_mac = actions->conf;
+
+char *dirstr = actions->type == RTE_FLOW_ACTION_TYPE_SET_MAC_DST
+   ? "dst" : "src";
+
+ds_put_format(s, "rte flow set-mac-%s action:\n", dirstr);
+if (set_mac) {
+ds_put_format(s,
+  "  Set-mac-%s: "ETH_ADDR_FMT"\n",
+  dirstr, ETH_ADDR_BYTES_ARGS(set_mac->mac_addr));
+} else {
+ds_put_format(s, "  Set-mac-%s = null\n", dirstr);
+}
 } else {
 ds_put_format(s, "unknown rte flow action (%d)\n", actions->type);
 }
diff --git a/lib/netdev-offload-dpdk.c b/lib/netdev-offload-dpdk.c
index bffb69cad..07f5d4687 100644
--- a/lib/netdev-offload-dpdk.c
+++ b/lib/netdev-offload-dpdk.c
@@ -511,6 +511,103 @@ add_output_action(struct netdev *netdev,
 return ret;
 }
 
+struct set_action_info {
+const uint8_t *value, *mask;
+const uint8_t size;
+uint8_t *spec;
+const int attr;
+};
+
+static int
+add_set_flow_action(struct flow_actions *actions,
+struct set_action_info *sa_info_arr,
+size_t sa_info_arr_size)
+{
+int field, i;
+
+for (field = 0; field < sa_info_arr_size; field++) {
+if (sa_info_arr[field].mask) {
+/* DPDK does not support partially masked set actions. In such
+ * case, fail the offload.
+ */
+if (sa_info_arr[field].mask[0] != 0x00 &&
+sa_info_arr[field].mask[0] != 0xFF) {
+VLOG_DBG_RL(_rl,
+"Partial mask is not supported");
+return -1;
+}
+
+for (i = 1; i < sa_info_arr[field].size; i++) {
+if (sa_info_arr[field].mask[i] !=
+sa_info_arr[field].mask[i - 1]) {
+VLOG_DBG_RL(_rl,
+"Partial mask is not supported");
+return -1;
+}
+}
+
+if (sa_info_arr[field].mask[0] == 0x00) {
+/* mask bytes are all 0 - no rewrite action required */
+continue;
+}
+}
+
+memcpy(sa_info_arr[field].spec, sa_info_arr[field].value,
+   sa_info_arr[field].size);
+add_flow_action(actions, sa_info_arr[field].attr,
+sa_info_arr[field].spec);
+}
+
+return 0;
+}
+
+/* Mask is at the midpoint of the data. */
+#define get_mask(a, type) ((const type *)(const void *)(a + 1) + 1)
+
+#define SA_INFO(_field, _spec, _attr) { \
+.value = (uint8_t *)>_field, \
+.mask = (masked) ? (uint8_t *)>_field : NULL, \
+.size = sizeof key->_field, \
+.spec = (uint8_t *)&_spec, \
+.attr = _attr }
+
+static int
+parse_set_actions(struct flow_actions *actions,
+  const struct nlattr *set_actions,
+  const size_t set_actions_len,
+  bool masked)
+{
+const struct nlattr *sa;
+unsigned int sleft;
+
+NL_ATTR_FOR_EACH_UNSAFE (sa, sleft, set_actions, set_actions_len) {
+if (nl_attr_type(sa) == OVS_KEY_ATTR_ETHERNET) {
+const struct ovs_key_ethernet *key = nl_attr_get(sa);
+const struct ovs_key_ethernet *mask = masked ?
+

[ovs-dev] [PATCH V3 15/19] netdev-offload-dpdk: Support offload of drop action

2019-12-08 Thread Eli Britstein
Signed-off-by: Eli Britstein 
Reviewed-by: Oz Shlomo 
---
 Documentation/howto/dpdk.rst | 1 +
 NEWS | 2 +-
 lib/netdev-dpdk.c| 2 ++
 lib/netdev-offload-dpdk.c| 4 +---
 4 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/Documentation/howto/dpdk.rst b/Documentation/howto/dpdk.rst
index f62ce82af..6cedd7f63 100644
--- a/Documentation/howto/dpdk.rst
+++ b/Documentation/howto/dpdk.rst
@@ -391,6 +391,7 @@ Supported protocols for hardware offload matches are:
 Supported actions for hardware offload are:
 
 - Output (a single output, as the last action).
+- Drop.
 
 Further Reading
 ---
diff --git a/NEWS b/NEWS
index c430999a0..d019e066f 100644
--- a/NEWS
+++ b/NEWS
@@ -26,7 +26,7 @@ Post-v2.12.0
  * DPDK ring ports (dpdkr) are deprecated and will be removed in next
releases.
  * Add support for DPDK 19.11.
- * Add hardware offload support for output actions (experimental).
+ * Add hardware offload support for output and drop actions (experimental).
 
 v2.12.0 - 03 Sep 2019
 -
diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c
index d9a2c2004..872a45e75 100644
--- a/lib/netdev-dpdk.c
+++ b/lib/netdev-dpdk.c
@@ -4721,6 +4721,8 @@ ds_put_flow_action(struct ds *s, const struct 
rte_flow_action *actions)
 } else {
 ds_put_cstr(s, "  Port-id = null\n");
 }
+} else if (actions->type == RTE_FLOW_ACTION_TYPE_DROP) {
+ds_put_cstr(s, "rte flow drop action\n");
 } else {
 ds_put_format(s, "unknown rte flow action (%d)\n", actions->type);
 }
diff --git a/lib/netdev-offload-dpdk.c b/lib/netdev-offload-dpdk.c
index 0b9087192..bffb69cad 100644
--- a/lib/netdev-offload-dpdk.c
+++ b/lib/netdev-offload-dpdk.c
@@ -536,9 +536,7 @@ parse_flow_actions(struct netdev *netdev,
 }
 
 if (nl_actions_len == 0) {
-VLOG_DBG_RL(_rl,
-"Unsupported action type drop");
-return -1;
+add_flow_action(actions, RTE_FLOW_ACTION_TYPE_DROP, NULL);
 }
 
 add_flow_action(actions, RTE_FLOW_ACTION_TYPE_END, NULL);
-- 
2.14.5

___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


[ovs-dev] [PATCH V3 10/19] dpif-netdev: Read hw stats during flow_dump_next() call

2019-12-08 Thread Eli Britstein
From: Ophir Munk 

Use netdev flow get API in order to update the statistics of fully
offloaded flows.

Co-authored-by: Eli Britstein 
Signed-off-by: Ophir Munk 
Reviewed-by: Oz Shlomo 
Signed-off-by: Eli Britstein 
---
 lib/dpif-netdev.c | 47 +--
 1 file changed, 45 insertions(+), 2 deletions(-)

diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 1e5493615..37e7e5c38 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -527,6 +527,7 @@ struct dp_netdev_flow {
 
 bool dead;
 uint32_t mark;   /* Unique flow mark assigned to a flow */
+bool actions_offloaded;  /* true if flow is fully offloaded. */
 
 /* Statistics. */
 struct dp_netdev_flow_stats stats;
@@ -2409,6 +2410,7 @@ dp_netdev_flow_offload_put(struct dp_flow_offload_item 
*offload)
 }
 }
 info.flow_mark = mark;
+info.actions_offloaded = >actions_offloaded;
 
 port = netdev_ports_get(in_port, pmd->dp->dpif->dpif_class);
 if (!port || netdev_vport_is_vport_class(port->netdev_class)) {
@@ -3071,8 +3073,8 @@ dp_netdev_flow_to_dpif_flow(const struct dp_netdev_flow 
*netdev_flow,
 flow->pmd_id = netdev_flow->pmd_id;
 get_dpif_flow_stats(netdev_flow, >stats);
 
-flow->attrs.offloaded = false;
-flow->attrs.dp_layer = "ovs";
+flow->attrs.offloaded = netdev_flow->actions_offloaded;
+flow->attrs.dp_layer = flow->attrs.offloaded ? "in_hw" : "ovs";
 }
 
 static int
@@ -3242,6 +3244,7 @@ dp_netdev_flow_add(struct dp_netdev_pmd_thread *pmd,
 flow->dead = false;
 flow->batch = NULL;
 flow->mark = INVALID_FLOW_MARK;
+flow->actions_offloaded = false;
 *CONST_CAST(unsigned *, >pmd_id) = pmd->core_id;
 *CONST_CAST(struct flow *, >flow) = match->flow;
 *CONST_CAST(ovs_u128 *, >ufid) = *ufid;
@@ -3596,6 +3599,42 @@ dpif_netdev_flow_dump_thread_destroy(struct 
dpif_flow_dump_thread *thread_)
 free(thread);
 }
 
+static int
+dpif_netdev_offload_used(struct dp_netdev_flow *netdev_flow,
+ struct dp_netdev_pmd_thread *pmd)
+{
+struct dpif_flow_stats stats;
+struct netdev *netdev;
+struct match match;
+struct nlattr *actions;
+struct dpif_flow_attrs attrs;
+struct ofpbuf wbuffer;
+
+ovs_u128 ufid;
+int ret = 0;
+
+netdev = netdev_ports_get(netdev_flow->flow.in_port.odp_port,
+  pmd->dp->class);
+if (!netdev) {
+return -1;
+}
+/* get offloaded stats */
+ufid = netdev_flow->mega_ufid;
+ret = netdev_flow_get(netdev, , , , , ,
+  );
+netdev_close(netdev);
+if (ret) {
+return -1;
+}
+if (stats.n_packets) {
+atomic_store_relaxed(_flow->stats.used, pmd->ctx.now / 1000);
+non_atomic_ullong_add(_flow->stats.packet_count, 
stats.n_packets);
+non_atomic_ullong_add(_flow->stats.byte_count, stats.n_bytes);
+}
+
+return 0;
+}
+
 static int
 dpif_netdev_flow_dump_next(struct dpif_flow_dump_thread *thread_,
struct dpif_flow *flows, int max_flows)
@@ -3636,6 +3675,10 @@ dpif_netdev_flow_dump_next(struct dpif_flow_dump_thread 
*thread_,
 netdev_flows[n_flows] = CONTAINER_OF(node,
  struct dp_netdev_flow,
  node);
+/* Read hardware stats in case of hardware offload */
+if (netdev_flows[n_flows]->actions_offloaded) {
+dpif_netdev_offload_used(netdev_flows[n_flows], pmd);
+}
 }
 /* When finishing dumping the current pmd thread, moves to
  * the next. */
-- 
2.14.5

___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


[ovs-dev] [PATCH V3 18/19] netdev-offload-dpdk: Support offload of clone tnl_push/output actions

2019-12-08 Thread Eli Britstein
Signed-off-by: Eli Britstein 
Reviewed-by: Oz Shlomo 
---
 Documentation/howto/dpdk.rst |  2 ++
 NEWS |  4 ++--
 lib/netdev-dpdk.c| 14 +
 lib/netdev-offload-dpdk.c| 48 
 4 files changed, 66 insertions(+), 2 deletions(-)

diff --git a/Documentation/howto/dpdk.rst b/Documentation/howto/dpdk.rst
index b9be83002..b9aaf26bf 100644
--- a/Documentation/howto/dpdk.rst
+++ b/Documentation/howto/dpdk.rst
@@ -394,6 +394,8 @@ Supported actions for hardware offload are:
 - Drop.
 - Modification of Ethernet (mod_dl_src/mod_dl_dst).
 - Modification of IPv4 (mod_nw_src/mod_nw_dst/mod_nw_ttl).
+- Clone with tnl_push and output (a single clone, as the last action,
+  with a single output, as the last nested clone action).
 
 Further Reading
 ---
diff --git a/NEWS b/NEWS
index 297ca6fff..25125801b 100644
--- a/NEWS
+++ b/NEWS
@@ -26,8 +26,8 @@ Post-v2.12.0
  * DPDK ring ports (dpdkr) are deprecated and will be removed in next
releases.
  * Add support for DPDK 19.11.
- * Add hardware offload support for output, drop and set actions of
-   MAC and IPv4 (experimental).
+ * Add hardware offload support for output, drop, set of MAC, IPv4
+   and tunnel push-output actions (experimental).
 
 v2.12.0 - 03 Sep 2019
 -
diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c
index c4606363d..14f5d6f3b 100644
--- a/lib/netdev-dpdk.c
+++ b/lib/netdev-dpdk.c
@@ -4762,6 +4762,20 @@ ds_put_flow_action(struct ds *s, const struct 
rte_flow_action *actions)
 } else {
 ds_put_cstr(s, "  Set-ttl = null\n");
 }
+} else if (actions->type == RTE_FLOW_ACTION_TYPE_RAW_ENCAP) {
+const struct rte_flow_action_raw_encap *raw_encap = actions->conf;
+
+ds_put_cstr(s, "rte flow raw-encap action:\n");
+if (raw_encap) {
+ds_put_format(s,
+  "  Raw-encap: size=%ld\n",
+  raw_encap->size);
+ds_put_format(s,
+  "  Raw-encap: encap=\n");
+ds_put_hex_dump(s, raw_encap->data, raw_encap->size, 0, false);
+} else {
+ds_put_cstr(s, "  Raw-encap = null\n");
+}
 } else {
 ds_put_format(s, "unknown rte flow action (%d)\n", actions->type);
 }
diff --git a/lib/netdev-offload-dpdk.c b/lib/netdev-offload-dpdk.c
index 3fccac956..b0403a085 100644
--- a/lib/netdev-offload-dpdk.c
+++ b/lib/netdev-offload-dpdk.c
@@ -634,6 +634,45 @@ parse_set_actions(struct flow_actions *actions,
 return 0;
 }
 
+static int
+parse_clone_actions(struct netdev *netdev,
+struct flow_actions *actions,
+const struct nlattr *clone_actions,
+const size_t clone_actions_len,
+struct offload_info *info)
+{
+const struct nlattr *ca;
+unsigned int cleft;
+
+NL_ATTR_FOR_EACH_UNSAFE (ca, cleft, clone_actions, clone_actions_len) {
+int clone_type = nl_attr_type(ca);
+
+if (clone_type == OVS_ACTION_ATTR_TUNNEL_PUSH) {
+const struct ovs_action_push_tnl *tnl_push = nl_attr_get(ca);
+struct rte_flow_action_raw_encap *raw_encap =
+xzalloc(sizeof *raw_encap);
+
+raw_encap->data = (uint8_t *)tnl_push->header;
+raw_encap->preserve = NULL;
+raw_encap->size = tnl_push->header_len;
+
+add_flow_action(actions, RTE_FLOW_ACTION_TYPE_RAW_ENCAP,
+raw_encap);
+} else if (clone_type == OVS_ACTION_ATTR_OUTPUT) {
+if (!(cleft <= NLA_ALIGN(ca->nla_len)) ||
+add_output_action(netdev, actions, ca, info)) {
+return -1;
+}
+} else {
+VLOG_DBG_RL(_rl,
+"Unsupported clone action. clone_type=%d", clone_type);
+return -1;
+}
+}
+
+return 0;
+}
+
 static int
 parse_flow_actions(struct netdev *netdev,
struct flow_actions *actions,
@@ -661,6 +700,15 @@ parse_flow_actions(struct netdev *netdev,
   masked)) {
 return -1;
 }
+} else if (nl_attr_type(nla) == OVS_ACTION_ATTR_CLONE) {
+const struct nlattr *clone_actions = nl_attr_get(nla);
+size_t clone_actions_len = nl_attr_get_size(nla);
+
+if (!(left <= NLA_ALIGN(nla->nla_len)) ||
+parse_clone_actions(netdev, actions, clone_actions,
+clone_actions_len, info)) {
+return -1;
+}
 } else {
 VLOG_DBG_RL(_rl,
 "Unsupported action type %d", nl_attr_type(nla));
-- 
2.14.5

___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


[ovs-dev] [PATCH V3 09/19] netdev-offload-dpdk: Implement flow get method

2019-12-08 Thread Eli Britstein
Implement the flow get method for DPDK, to get the statistics of the
provided ufid, towards reading statistics of fully offloaded flows.

Signed-off-by: Eli Britstein 
Reviewed-by: Oz Shlomo 
---
 lib/netdev-offload-dpdk.c | 40 
 1 file changed, 40 insertions(+)

diff --git a/lib/netdev-offload-dpdk.c b/lib/netdev-offload-dpdk.c
index 5568400b6..10ab9240a 100644
--- a/lib/netdev-offload-dpdk.c
+++ b/lib/netdev-offload-dpdk.c
@@ -705,9 +705,49 @@ netdev_offload_dpdk_init_flow_api(struct netdev *netdev)
 return netdev_dpdk_flow_api_supported(netdev) ? 0 : EOPNOTSUPP;
 }
 
+static int
+netdev_offload_dpdk_flow_get(struct netdev *netdev,
+ struct match *match OVS_UNUSED,
+ struct nlattr **actions OVS_UNUSED,
+ const ovs_u128 *ufid,
+ struct dpif_flow_stats *stats,
+ struct dpif_flow_attrs *attrs OVS_UNUSED,
+ struct ofpbuf *buf OVS_UNUSED)
+{
+struct rte_flow_query_count query = { .reset = 1 };
+struct rte_flow_error error;
+struct rte_flow *rte_flow;
+int ret = 0;
+
+ovs_mutex_lock(_map_mutex);
+rte_flow = ufid_to_rte_flow_find(ufid);
+if (!rte_flow) {
+ret = -1;
+goto out;
+}
+
+memset(stats, 0, sizeof *stats);
+ret = netdev_dpdk_rte_flow_query(netdev, rte_flow, , );
+if (ret) {
+VLOG_DBG_RL(_rl,
+"%s: Failed to query ufid "UUID_FMT" flow: %p\n",
+netdev_get_name(netdev), UUID_ARGS((struct uuid *)ufid),
+rte_flow);
+ret = -1;
+goto out;
+}
+stats->n_packets += (query.hits_set) ? query.hits : 0;
+stats->n_bytes += (query.bytes_set) ? query.bytes : 0;
+
+out:
+ovs_mutex_unlock(_map_mutex);
+return ret;
+}
+
 const struct netdev_flow_api netdev_offload_dpdk = {
 .type = "dpdk_flow_api",
 .flow_put = netdev_offload_dpdk_flow_put,
 .flow_del = netdev_offload_dpdk_flow_del,
 .init_flow_api = netdev_offload_dpdk_init_flow_api,
+.flow_get = netdev_offload_dpdk_flow_get,
 };
-- 
2.14.5

___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


[ovs-dev] [PATCH V3 07/19] netdev-dpdk: Introduce rte flow query function

2019-12-08 Thread Eli Britstein
Introduce a rte flow query function as a pre-step towards reading HW
statistics of fully offloaded flows.

Signed-off-by: Eli Britstein 
Reviewed-by: Oz Shlomo 
---
 lib/netdev-dpdk.c | 25 +
 lib/netdev-dpdk.h |  6 ++
 2 files changed, 31 insertions(+)

diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c
index da1349b69..e63a496c1 100644
--- a/lib/netdev-dpdk.c
+++ b/lib/netdev-dpdk.c
@@ -4737,6 +4737,31 @@ netdev_dpdk_rte_flow_create(struct netdev *netdev,
 return flow;
 }
 
+int
+netdev_dpdk_rte_flow_query(struct netdev *netdev,
+   struct rte_flow *rte_flow,
+   struct rte_flow_query_count *query,
+   struct rte_flow_error *error)
+{
+struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
+struct rte_flow_action_count count = {};
+const struct rte_flow_action actions[] = {
+{
+.type = RTE_FLOW_ACTION_TYPE_COUNT,
+.conf = ,
+},
+{
+.type = RTE_FLOW_ACTION_TYPE_END,
+},
+};
+int ret;
+
+ovs_mutex_lock(>mutex);
+ret = rte_flow_query(dev->port_id, rte_flow, actions, query, error);
+ovs_mutex_unlock(>mutex);
+return ret;
+}
+
 #define NETDEV_DPDK_CLASS_COMMON\
 .is_pmd = true, \
 .alloc = netdev_dpdk_alloc, \
diff --git a/lib/netdev-dpdk.h b/lib/netdev-dpdk.h
index 60631c4f0..ed7cb235a 100644
--- a/lib/netdev-dpdk.h
+++ b/lib/netdev-dpdk.h
@@ -31,6 +31,7 @@ struct rte_flow_error;
 struct rte_flow_attr;
 struct rte_flow_item;
 struct rte_flow_action;
+struct rte_flow_query_count;
 
 void netdev_dpdk_register(void);
 void free_dpdk_buf(struct dp_packet *);
@@ -47,6 +48,11 @@ netdev_dpdk_rte_flow_create(struct netdev *netdev,
 const struct rte_flow_item *items,
 const struct rte_flow_action *actions,
 struct rte_flow_error *error);
+int
+netdev_dpdk_rte_flow_query(struct netdev *netdev,
+   struct rte_flow *rte_flow,
+   struct rte_flow_query_count *query,
+   struct rte_flow_error *error);
 
 #else
 
-- 
2.14.5

___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


[ovs-dev] [PATCH V3 08/19] netdev-offload-dpdk: Protect UFID map by mutex

2019-12-08 Thread Eli Britstein
Flow deletion and dumping for statistics collection are called from
different threads. As a pre-step towards collecting HW statistics,
protect the UFID map by mutex to make it thread safe.

Signed-off-by: Eli Britstein 
---
 lib/netdev-offload-dpdk.c | 7 ++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/lib/netdev-offload-dpdk.c b/lib/netdev-offload-dpdk.c
index b2ec05cec..5568400b6 100644
--- a/lib/netdev-offload-dpdk.c
+++ b/lib/netdev-offload-dpdk.c
@@ -51,6 +51,7 @@ static struct vlog_rate_limit error_rl = 
VLOG_RATE_LIMIT_INIT(100, 5);
  * A mapping from ufid to dpdk rte_flow.
  */
 static struct cmap ufid_to_rte_flow = CMAP_INITIALIZER;
+static struct ovs_mutex ufid_map_mutex = OVS_MUTEX_INITIALIZER;
 
 struct ufid_to_rte_flow_data {
 struct cmap_node node;
@@ -630,8 +631,11 @@ netdev_offload_dpdk_destroy_flow(struct netdev *netdev,
  struct rte_flow *rte_flow)
 {
 struct rte_flow_error error;
-int ret = netdev_dpdk_rte_flow_destroy(netdev, rte_flow, );
+int ret;
+
+ovs_mutex_lock(_map_mutex);
 
+ret = netdev_dpdk_rte_flow_destroy(netdev, rte_flow, );
 if (ret == 0) {
 ufid_to_rte_flow_disassociate(ufid);
 VLOG_DBG("%s: removed rte flow %p associated with ufid " UUID_FMT "\n",
@@ -642,6 +646,7 @@ netdev_offload_dpdk_destroy_flow(struct netdev *netdev,
  netdev_get_name(netdev), error.message, error.type);
 }
 
+ovs_mutex_unlock(_map_mutex);
 return ret;
 }
 
-- 
2.14.5

___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


[ovs-dev] [PATCH V3 13/19] netdev-offload: Introduce a function to validate same flow api handle

2019-12-08 Thread Eli Britstein
Signed-off-by: Eli Britstein 
---
 lib/netdev-offload-provider.h |  1 +
 lib/netdev-offload.c  | 12 
 2 files changed, 13 insertions(+)

diff --git a/lib/netdev-offload-provider.h b/lib/netdev-offload-provider.h
index 4e1c4251d..5a809c0cd 100644
--- a/lib/netdev-offload-provider.h
+++ b/lib/netdev-offload-provider.h
@@ -89,6 +89,7 @@ struct netdev_flow_api {
 
 int netdev_register_flow_api_provider(const struct netdev_flow_api *);
 int netdev_unregister_flow_api_provider(const char *type);
+bool netdev_flow_api_equals(const struct netdev *, const struct netdev *);
 
 #ifdef __linux__
 extern const struct netdev_flow_api netdev_offload_tc;
diff --git a/lib/netdev-offload.c b/lib/netdev-offload.c
index ae01acda6..32eab5910 100644
--- a/lib/netdev-offload.c
+++ b/lib/netdev-offload.c
@@ -156,6 +156,18 @@ netdev_unregister_flow_api_provider(const char *type)
 return error;
 }
 
+bool
+netdev_flow_api_equals(const struct netdev *netdev1,
+   const struct netdev *netdev2)
+{
+const struct netdev_flow_api *netdev_flow_api1 =
+ovsrcu_get(const struct netdev_flow_api *, >flow_api);
+const struct netdev_flow_api *netdev_flow_api2 =
+ovsrcu_get(const struct netdev_flow_api *, >flow_api);
+
+return netdev_flow_api1 == netdev_flow_api2;
+}
+
 static int
 netdev_assign_flow_api(struct netdev *netdev)
 {
-- 
2.14.5

___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


[ovs-dev] [PATCH V3 05/19] netdev-dpdk: Improve HW offload flow debuggability

2019-12-08 Thread Eli Britstein
Add debug prints when creating and destroying rte flows, with all the
flow details (attributes, patterns, actions).

Signed-off-by: Eli Britstein 
Reviewed-by: Oz Shlomo 
---
 lib/netdev-dpdk.c | 260 ++
 lib/netdev-offload-dpdk.c | 207 +---
 2 files changed, 264 insertions(+), 203 deletions(-)

diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c
index 89c73a29b..da1349b69 100644
--- a/lib/netdev-dpdk.c
+++ b/lib/netdev-dpdk.c
@@ -4458,9 +4458,252 @@ netdev_dpdk_rte_flow_destroy(struct netdev *netdev,
 ovs_mutex_lock(>mutex);
 ret = rte_flow_destroy(dev->port_id, rte_flow, error);
 ovs_mutex_unlock(>mutex);
+if (!ret) {
+VLOG_DBG_RL(, "Destroy rte_flow %p: netdev=%s, port=%d\n",
+rte_flow, netdev_get_name(netdev), dev->port_id);
+} else {
+VLOG_ERR_RL(, "Destroy rte_flow %p: netdev=%s, port=%d\n"
+"FAILED. error %u : message : %s",
+rte_flow, netdev_get_name(netdev), dev->port_id,
+error->type, error->message);
+}
 return ret;
 }
 
+static void
+ds_put_flow_attr(struct ds *s, const struct rte_flow_attr *attr)
+{
+ds_put_format(s,
+  "  Attributes: "
+  "ingress=%d, egress=%d, prio=%d, group=%d, transfer=%d\n",
+  attr->ingress, attr->egress, attr->priority, attr->group,
+  attr->transfer);
+}
+
+static void
+ds_put_flow_pattern(struct ds *s, const struct rte_flow_item *item)
+{
+if (item->type == RTE_FLOW_ITEM_TYPE_ETH) {
+const struct rte_flow_item_eth *eth_spec = item->spec;
+const struct rte_flow_item_eth *eth_mask = item->mask;
+
+ds_put_cstr(s, "rte flow eth pattern:\n");
+if (eth_spec) {
+ds_put_format(s,
+  "  Spec: src="ETH_ADDR_FMT", dst="ETH_ADDR_FMT", "
+  "type=0x%04" PRIx16"\n",
+  ETH_ADDR_BYTES_ARGS(eth_spec->src.addr_bytes),
+  ETH_ADDR_BYTES_ARGS(eth_spec->dst.addr_bytes),
+  ntohs(eth_spec->type));
+} else {
+ds_put_cstr(s, "  Spec = null\n");
+}
+if (eth_mask) {
+ds_put_format(s,
+  "  Mask: src="ETH_ADDR_FMT", dst="ETH_ADDR_FMT", "
+  "type=0x%04"PRIx16"\n",
+  ETH_ADDR_BYTES_ARGS(eth_mask->src.addr_bytes),
+  ETH_ADDR_BYTES_ARGS(eth_mask->dst.addr_bytes),
+  ntohs(eth_mask->type));
+} else {
+ds_put_cstr(s, "  Mask = null\n");
+}
+} else if (item->type == RTE_FLOW_ITEM_TYPE_VLAN) {
+const struct rte_flow_item_vlan *vlan_spec = item->spec;
+const struct rte_flow_item_vlan *vlan_mask = item->mask;
+
+ds_put_cstr(s, "rte flow vlan pattern:\n");
+if (vlan_spec) {
+ds_put_format(s,
+  "  Spec: inner_type=0x%"PRIx16", tci=0x%"PRIx16"\n",
+  ntohs(vlan_spec->inner_type), ntohs(vlan_spec->tci));
+} else {
+ds_put_cstr(s, "  Spec = null\n");
+}
+
+if (vlan_mask) {
+ds_put_format(s,
+  "  Mask: inner_type=0x%"PRIx16", tci=0x%"PRIx16"\n",
+  ntohs(vlan_mask->inner_type), ntohs(vlan_mask->tci));
+} else {
+ds_put_cstr(s, "  Mask = null\n");
+}
+} else if (item->type == RTE_FLOW_ITEM_TYPE_IPV4) {
+const struct rte_flow_item_ipv4 *ipv4_spec = item->spec;
+const struct rte_flow_item_ipv4 *ipv4_mask = item->mask;
+
+ds_put_cstr(s, "rte flow ipv4 pattern:\n");
+if (ipv4_spec) {
+ds_put_format(s,
+  "  Spec: tos=0x%"PRIx8", ttl=%"PRIx8
+  ", proto=0x%"PRIx8
+  ", src="IP_FMT", dst="IP_FMT"\n",
+  ipv4_spec->hdr.type_of_service,
+  ipv4_spec->hdr.time_to_live,
+  ipv4_spec->hdr.next_proto_id,
+  IP_ARGS(ipv4_spec->hdr.src_addr),
+  IP_ARGS(ipv4_spec->hdr.dst_addr));
+} else {
+ds_put_cstr(s, "  Spec = null\n");
+}
+if (ipv4_mask) {
+ds_put_format(s,
+  "  Mask: tos=0x%"PRIx8", ttl=%"PRIx8
+  ", proto=0x%"PRIx8
+  ", src="IP_FMT", dst="IP_FMT"\n",
+  ipv4_mask->hdr.type_of_service,
+  ipv4_mask->hdr.time_to_live,
+  ipv4_mask->hdr.next_proto_id,
+  IP_ARGS(ipv4_mask->hdr.src_addr),
+  IP_ARGS(ipv4_mask->hdr.dst_addr));
+} else {
+ds_put_cstr(s, "  Mask = null\n");
+

[ovs-dev] [PATCH V3 14/19] netdev-offload-dpdk: Support offload of output action

2019-12-08 Thread Eli Britstein
Support offload of output action, also configuring count action for
allowing query statistics of HW offloaded flows.

Signed-off-by: Eli Britstein 
Reviewed-by: Oz Shlomo 
---
 Documentation/howto/dpdk.rst | 17 ---
 NEWS |  1 +
 lib/netdev-dpdk.c| 22 +
 lib/netdev-offload-dpdk.c| 73 +---
 4 files changed, 104 insertions(+), 9 deletions(-)

diff --git a/Documentation/howto/dpdk.rst b/Documentation/howto/dpdk.rst
index 766a7950c..f62ce82af 100644
--- a/Documentation/howto/dpdk.rst
+++ b/Documentation/howto/dpdk.rst
@@ -370,19 +370,28 @@ The flow hardware offload is disabled by default and can 
be enabled by::
 
 $ ovs-vsctl set Open_vSwitch . other_config:hw-offload=true
 
-So far only partial flow offload is implemented. Moreover, it only works
-with PMD drivers have the rte_flow action "MARK + RSS" support.
+Matches and actions are programmed into HW to achieve full offload of
+the flow. If not all actions are supported, fallback to partial flow
+offload (offloading matches only). Moreover, it only works with PMD
+drivers that support the configured rte_flow actions.
+Partial flow offload requires support of "MARK + RSS" actions. Full
+hardware offload requires support of the actions listed below.
 
 The validated NICs are:
 
 - Mellanox (ConnectX-4, ConnectX-4 Lx, ConnectX-5)
 - Napatech (NT200B01)
 
-Supported protocols for hardware offload are:
+Supported protocols for hardware offload matches are:
+
 - L2: Ethernet, VLAN
-- L3: IPv4, IPv6
+- L3: IPv4
 - L4: TCP, UDP, SCTP, ICMP
 
+Supported actions for hardware offload are:
+
+- Output (a single output, as the last action).
+
 Further Reading
 ---
 
diff --git a/NEWS b/NEWS
index 2acde3fe8..c430999a0 100644
--- a/NEWS
+++ b/NEWS
@@ -26,6 +26,7 @@ Post-v2.12.0
  * DPDK ring ports (dpdkr) are deprecated and will be removed in next
releases.
  * Add support for DPDK 19.11.
+ * Add hardware offload support for output actions (experimental).
 
 v2.12.0 - 03 Sep 2019
 -
diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c
index 16baae0c4..d9a2c2004 100644
--- a/lib/netdev-dpdk.c
+++ b/lib/netdev-dpdk.c
@@ -4699,6 +4699,28 @@ ds_put_flow_action(struct ds *s, const struct 
rte_flow_action *actions)
 } else {
 ds_put_cstr(s, "  RSS = null\n");
 }
+} else if (actions->type == RTE_FLOW_ACTION_TYPE_COUNT) {
+const struct rte_flow_action_count *count = actions->conf;
+
+ds_put_cstr(s, "rte flow count action:\n");
+if (count) {
+ds_put_format(s,
+  "  Count: shared=%d, id=%d\n",
+  count->shared, count->id);
+} else {
+ds_put_cstr(s, "  Count = null\n");
+}
+} else if (actions->type == RTE_FLOW_ACTION_TYPE_PORT_ID) {
+const struct rte_flow_action_port_id *port_id = actions->conf;
+
+ds_put_cstr(s, "rte flow port-id action:\n");
+if (port_id) {
+ds_put_format(s,
+  "  Port-id: original=%d, id=%d\n",
+  port_id->original, port_id->id);
+} else {
+ds_put_cstr(s, "  Port-id = null\n");
+}
 } else {
 ds_put_format(s, "unknown rte flow action (%d)\n", actions->type);
 }
diff --git a/lib/netdev-offload-dpdk.c b/lib/netdev-offload-dpdk.c
index 10ab9240a..0b9087192 100644
--- a/lib/netdev-offload-dpdk.c
+++ b/lib/netdev-offload-dpdk.c
@@ -456,20 +456,83 @@ netdev_offload_dpdk_mark_rss(struct flow_patterns 
*patterns,
 return flow;
 }
 
+static void
+add_count_action(struct flow_actions *actions)
+{
+struct rte_flow_action_count *count = xzalloc(sizeof *count);
+
+count->shared = 0;
+/* Each flow has a single count action, so no need of id */
+count->id = 0;
+add_flow_action(actions, RTE_FLOW_ACTION_TYPE_COUNT, count);
+}
+
 static int
-parse_flow_actions(struct netdev *netdev OVS_UNUSED,
+add_port_id_action(struct flow_actions *actions,
+   struct netdev *outdev)
+{
+struct rte_flow_action_port_id *port_id = xzalloc(sizeof *port_id);
+int outdev_id;
+
+outdev_id = netdev_dpdk_get_port_id(outdev);
+if (outdev_id < 0) {
+return -1;
+}
+port_id->id = outdev_id;
+add_flow_action(actions, RTE_FLOW_ACTION_TYPE_PORT_ID, port_id);
+return 0;
+}
+
+static int
+add_output_action(struct netdev *netdev,
+  struct flow_actions *actions,
+  const struct nlattr *nla,
+  struct offload_info *info)
+{
+struct netdev *outdev;
+odp_port_t port;
+int ret = 0;
+
+port = nl_attr_get_odp_port(nla);
+outdev = netdev_ports_get(port, info->dpif_class);
+if (outdev == NULL) {
+VLOG_DBG_RL(_rl,
+"Cannot find netdev for odp port %d", port);
+return -1;
+}
+if 

[ovs-dev] [PATCH V3 17/19] netdev-offload-dpdk: Support offload of set IPv4 actions

2019-12-08 Thread Eli Britstein
Signed-off-by: Eli Britstein 
Reviewed-by: Oz Shlomo 
---
 Documentation/howto/dpdk.rst |  1 +
 NEWS |  4 ++--
 lib/netdev-dpdk.c| 24 
 lib/netdev-offload-dpdk.c| 26 ++
 4 files changed, 53 insertions(+), 2 deletions(-)

diff --git a/Documentation/howto/dpdk.rst b/Documentation/howto/dpdk.rst
index d228493e9..b9be83002 100644
--- a/Documentation/howto/dpdk.rst
+++ b/Documentation/howto/dpdk.rst
@@ -393,6 +393,7 @@ Supported actions for hardware offload are:
 - Output (a single output, as the last action).
 - Drop.
 - Modification of Ethernet (mod_dl_src/mod_dl_dst).
+- Modification of IPv4 (mod_nw_src/mod_nw_dst/mod_nw_ttl).
 
 Further Reading
 ---
diff --git a/NEWS b/NEWS
index 3ade86d49..297ca6fff 100644
--- a/NEWS
+++ b/NEWS
@@ -26,8 +26,8 @@ Post-v2.12.0
  * DPDK ring ports (dpdkr) are deprecated and will be removed in next
releases.
  * Add support for DPDK 19.11.
- * Add hardware offload support for output, drop and set MAC actions
-   (experimental).
+ * Add hardware offload support for output, drop and set actions of
+   MAC and IPv4 (experimental).
 
 v2.12.0 - 03 Sep 2019
 -
diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c
index e67a3dd76..c4606363d 100644
--- a/lib/netdev-dpdk.c
+++ b/lib/netdev-dpdk.c
@@ -4738,6 +4738,30 @@ ds_put_flow_action(struct ds *s, const struct 
rte_flow_action *actions)
 } else {
 ds_put_format(s, "  Set-mac-%s = null\n", dirstr);
 }
+} else if (actions->type == RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC ||
+   actions->type == RTE_FLOW_ACTION_TYPE_SET_IPV4_DST) {
+const struct rte_flow_action_set_ipv4 *set_ipv4 = actions->conf;
+char *dirstr = actions->type == RTE_FLOW_ACTION_TYPE_SET_IPV4_DST
+   ? "dst" : "src";
+
+ds_put_format(s, "rte flow set-ipv4-%s action:\n", dirstr);
+if (set_ipv4) {
+ds_put_format(s,
+  "  Set-ipv4-%s: "IP_FMT"\n",
+  dirstr, IP_ARGS(set_ipv4->ipv4_addr));
+} else {
+ds_put_format(s, "  Set-ipv4-%s = null\n", dirstr);
+}
+} else if (actions->type == RTE_FLOW_ACTION_TYPE_SET_TTL) {
+const struct rte_flow_action_set_ttl *set_ttl = actions->conf;
+
+ds_put_cstr(s, "rte flow set-ttl action:\n");
+if (set_ttl) {
+ds_put_format(s,
+  "  Set-ttl: %d\n", set_ttl->ttl_value);
+} else {
+ds_put_cstr(s, "  Set-ttl = null\n");
+}
 } else {
 ds_put_format(s, "unknown rte flow action (%d)\n", actions->type);
 }
diff --git a/lib/netdev-offload-dpdk.c b/lib/netdev-offload-dpdk.c
index 07f5d4687..3fccac956 100644
--- a/lib/netdev-offload-dpdk.c
+++ b/lib/netdev-offload-dpdk.c
@@ -594,6 +594,32 @@ parse_set_actions(struct flow_actions *actions,
 RTE_FLOW_ACTION_TYPE_SET_MAC_DST),
 };
 
+if (add_set_flow_action(actions, sa_info_arr,
+ARRAY_SIZE(sa_info_arr))) {
+return -1;
+}
+} else if (nl_attr_type(sa) == OVS_KEY_ATTR_IPV4) {
+const struct ovs_key_ipv4 *key = nl_attr_get(sa);
+const struct ovs_key_ipv4 *mask = masked ?
+get_mask(sa, struct ovs_key_ipv4) : NULL;
+struct rte_flow_action_set_ipv4 *src = xzalloc(sizeof *src);
+struct rte_flow_action_set_ipv4 *dst = xzalloc(sizeof *dst);
+struct rte_flow_action_set_ttl *ttl = xzalloc(sizeof *ttl);
+struct set_action_info sa_info_arr[] = {
+SA_INFO(ipv4_src, src->ipv4_addr,
+RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC),
+SA_INFO(ipv4_dst, dst->ipv4_addr,
+RTE_FLOW_ACTION_TYPE_SET_IPV4_DST),
+SA_INFO(ipv4_ttl, ttl->ttl_value,
+RTE_FLOW_ACTION_TYPE_SET_TTL),
+};
+
+if (mask && (mask->ipv4_proto || mask->ipv4_tos ||
+mask->ipv4_frag)) {
+VLOG_DBG_RL(_rl, "Unsupported IPv4 set action");
+return -1;
+}
+
 if (add_set_flow_action(actions, sa_info_arr,
 ARRAY_SIZE(sa_info_arr))) {
 return -1;
-- 
2.14.5

___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


[ovs-dev] [PATCH V3 01/19] netdev-offload-dpdk: Refactor flow patterns

2019-12-08 Thread Eli Britstein
Refactor the flow patterns code to a helper function for better
readability and towards supporting more matches.

Signed-off-by: Eli Britstein 
Reviewed-by: Oz Shlomo 
---
 lib/netdev-offload-dpdk.c | 208 +-
 1 file changed, 112 insertions(+), 96 deletions(-)

diff --git a/lib/netdev-offload-dpdk.c b/lib/netdev-offload-dpdk.c
index 96794dc4d..a008e642f 100644
--- a/lib/netdev-offload-dpdk.c
+++ b/lib/netdev-offload-dpdk.c
@@ -410,54 +410,42 @@ add_flow_rss_action(struct flow_actions *actions,
 return rss_data;
 }
 
+struct flow_items {
+struct rte_flow_item_eth  eth;
+struct rte_flow_item_vlan vlan;
+struct rte_flow_item_ipv4 ipv4;
+union {
+struct rte_flow_item_tcp  tcp;
+struct rte_flow_item_udp  udp;
+struct rte_flow_item_sctp sctp;
+struct rte_flow_item_icmp icmp;
+};
+};
+
 static int
-netdev_offload_dpdk_add_flow(struct netdev *netdev,
- const struct match *match,
- struct nlattr *nl_actions OVS_UNUSED,
- size_t actions_len OVS_UNUSED,
- const ovs_u128 *ufid,
- struct offload_info *info)
+parse_flow_match(struct flow_patterns *patterns,
+ struct flow_items *spec,
+ struct flow_items *mask,
+ const struct match *match)
 {
-const struct rte_flow_attr flow_attr = {
-.group = 0,
-.priority = 0,
-.ingress = 1,
-.egress = 0
-};
-struct flow_patterns patterns = { .items = NULL, .cnt = 0 };
-struct flow_actions actions = { .actions = NULL, .cnt = 0 };
-struct rte_flow *flow;
-struct rte_flow_error error;
 uint8_t proto = 0;
-int ret = 0;
-struct flow_items {
-struct rte_flow_item_eth  eth;
-struct rte_flow_item_vlan vlan;
-struct rte_flow_item_ipv4 ipv4;
-union {
-struct rte_flow_item_tcp  tcp;
-struct rte_flow_item_udp  udp;
-struct rte_flow_item_sctp sctp;
-struct rte_flow_item_icmp icmp;
-};
-} spec, mask;
-
-memset(, 0, sizeof spec);
-memset(, 0, sizeof mask);
+
+memset(spec, 0, sizeof *spec);
+memset(mask, 0, sizeof *mask);
 
 /* Eth */
 if (!eth_addr_is_zero(match->wc.masks.dl_src) ||
 !eth_addr_is_zero(match->wc.masks.dl_dst)) {
-memcpy(, >flow.dl_dst, sizeof spec.eth.dst);
-memcpy(, >flow.dl_src, sizeof spec.eth.src);
-spec.eth.type = match->flow.dl_type;
+memcpy(>eth.dst, >flow.dl_dst, sizeof spec->eth.dst);
+memcpy(>eth.src, >flow.dl_src, sizeof spec->eth.src);
+spec->eth.type = match->flow.dl_type;
 
-memcpy(, >wc.masks.dl_dst, sizeof mask.eth.dst);
-memcpy(, >wc.masks.dl_src, sizeof mask.eth.src);
-mask.eth.type = match->wc.masks.dl_type;
+memcpy(>eth.dst, >wc.masks.dl_dst, sizeof mask->eth.dst);
+memcpy(>eth.src, >wc.masks.dl_src, sizeof mask->eth.src);
+mask->eth.type = match->wc.masks.dl_type;
 
-add_flow_pattern(, RTE_FLOW_ITEM_TYPE_ETH,
- , );
+add_flow_pattern(patterns, RTE_FLOW_ITEM_TYPE_ETH,
+ >eth, >eth);
 } else {
 /*
  * If user specifies a flow (like UDP flow) without L2 patterns,
@@ -466,41 +454,41 @@ netdev_offload_dpdk_add_flow(struct netdev *netdev,
  * NIC (such as XL710) doesn't support that. Below is a workaround,
  * which simply matches any L2 pkts.
  */
-add_flow_pattern(, RTE_FLOW_ITEM_TYPE_ETH, NULL, NULL);
+add_flow_pattern(patterns, RTE_FLOW_ITEM_TYPE_ETH, NULL, NULL);
 }
 
 /* VLAN */
 if (match->wc.masks.vlans[0].tci && match->flow.vlans[0].tci) {
-spec.vlan.tci  = match->flow.vlans[0].tci & ~htons(VLAN_CFI);
-mask.vlan.tci  = match->wc.masks.vlans[0].tci & ~htons(VLAN_CFI);
+spec->vlan.tci  = match->flow.vlans[0].tci & ~htons(VLAN_CFI);
+mask->vlan.tci  = match->wc.masks.vlans[0].tci & ~htons(VLAN_CFI);
 
 /* Match any protocols. */
-mask.vlan.inner_type = 0;
+mask->vlan.inner_type = 0;
 
-add_flow_pattern(, RTE_FLOW_ITEM_TYPE_VLAN,
- , );
+add_flow_pattern(patterns, RTE_FLOW_ITEM_TYPE_VLAN,
+ >vlan, >vlan);
 }
 
 /* IP v4 */
 if (match->flow.dl_type == htons(ETH_TYPE_IP)) {
-spec.ipv4.hdr.type_of_service = match->flow.nw_tos;
-spec.ipv4.hdr.time_to_live= match->flow.nw_ttl;
-spec.ipv4.hdr.next_proto_id   = match->flow.nw_proto;
-spec.ipv4.hdr.src_addr= match->flow.nw_src;
-spec.ipv4.hdr.dst_addr= match->flow.nw_dst;
+spec->ipv4.hdr.type_of_service = match->flow.nw_tos;
+spec->ipv4.hdr.time_to_live= match->flow.nw_ttl;
+spec->ipv4.hdr.next_proto_id   = 

[ovs-dev] [PATCH V3 06/19] netdev-offload-dpdk: Framework for actions offload

2019-12-08 Thread Eli Britstein
Currently HW offload is accelerating only the rule matching sequence.
Introduce a framework for offloading rule actions as a pre-step for
processing the rule actions in HW. In case of a failure, fallback to the
legacy partial offload scheme.

Note: a flow will be fully offloaded only if it can process all its
actions in HW.

Signed-off-by: Eli Britstein 
Reviewed-by: Oz Shlomo 
---
 lib/netdev-offload-dpdk.c | 112 +++---
 lib/netdev-offload.h  |   1 +
 2 files changed, 97 insertions(+), 16 deletions(-)

diff --git a/lib/netdev-offload-dpdk.c b/lib/netdev-offload-dpdk.c
index c272da340..b2ec05cec 100644
--- a/lib/netdev-offload-dpdk.c
+++ b/lib/netdev-offload-dpdk.c
@@ -28,6 +28,7 @@
 #include "uuid.h"
 
 VLOG_DEFINE_THIS_MODULE(netdev_offload_dpdk);
+static struct vlog_rate_limit error_rl = VLOG_RATE_LIMIT_INIT(100, 5);
 
 /* Thread-safety
  * =
@@ -424,6 +425,93 @@ add_flow_mark_rss_actions(struct flow_actions *actions,
 add_flow_action(actions, RTE_FLOW_ACTION_TYPE_END, NULL);
 }
 
+static struct rte_flow *
+netdev_offload_dpdk_mark_rss(struct flow_patterns *patterns,
+ struct netdev *netdev,
+ uint32_t flow_mark)
+{
+struct flow_actions actions = { .actions = NULL, .cnt = 0 };
+const struct rte_flow_attr flow_attr = {
+.group = 0,
+.priority = 0,
+.ingress = 1,
+.egress = 0
+};
+struct rte_flow_error error;
+struct rte_flow *flow;
+
+add_flow_mark_rss_actions(, flow_mark, netdev);
+
+flow = netdev_dpdk_rte_flow_create(netdev, _attr,
+   patterns->items,
+   actions.actions, );
+
+if (!flow) {
+VLOG_ERR("%s: Failed to create flow: %s (%u)\n",
+ netdev_get_name(netdev), error.message, error.type);
+}
+
+free_flow_actions();
+return flow;
+}
+
+static int
+parse_flow_actions(struct netdev *netdev OVS_UNUSED,
+   struct flow_actions *actions,
+   struct nlattr *nl_actions,
+   size_t nl_actions_len,
+   struct offload_info *info OVS_UNUSED)
+{
+struct nlattr *nla;
+size_t left;
+
+NL_ATTR_FOR_EACH_UNSAFE (nla, left, nl_actions, nl_actions_len) {
+VLOG_DBG_RL(_rl,
+"Unsupported action type %d", nl_attr_type(nla));
+return -1;
+}
+
+if (nl_actions_len == 0) {
+VLOG_DBG_RL(_rl,
+"Unsupported action type drop");
+return -1;
+}
+
+add_flow_action(actions, RTE_FLOW_ACTION_TYPE_END, NULL);
+return 0;
+}
+
+static struct rte_flow *
+netdev_offload_dpdk_actions(struct netdev *netdev,
+struct flow_patterns *patterns,
+struct nlattr *nl_actions,
+size_t actions_len,
+struct offload_info *info)
+{
+const struct rte_flow_attr flow_attr = { .ingress = 1, .transfer = 1 };
+struct flow_actions actions = { .actions = NULL, .cnt = 0 };
+struct rte_flow *flow = NULL;
+struct rte_flow_error error;
+int ret;
+
+ret = parse_flow_actions(netdev, , nl_actions, actions_len, info);
+if (ret) {
+goto out;
+}
+flow = netdev_dpdk_rte_flow_create(netdev, _attr, patterns->items,
+   actions.actions, );
+if (!flow) {
+VLOG_ERR("%s: Failed to create flow: %s (%u)\n",
+ netdev_get_name(netdev), error.message, error.type);
+}
+if (flow && info->actions_offloaded) {
+*info->actions_offloaded = true;
+}
+out:
+free_flow_actions();
+return flow;
+}
+
 static int
 netdev_offload_dpdk_add_flow(struct netdev *netdev,
  const struct match *match,
@@ -432,16 +520,8 @@ netdev_offload_dpdk_add_flow(struct netdev *netdev,
  const ovs_u128 *ufid,
  struct offload_info *info)
 {
-const struct rte_flow_attr flow_attr = {
-.group = 0,
-.priority = 0,
-.ingress = 1,
-.egress = 0
-};
 struct flow_patterns patterns = { .items = NULL, .cnt = 0 };
-struct flow_actions actions = { .actions = NULL, .cnt = 0 };
 struct rte_flow *flow;
-struct rte_flow_error error;
 int ret = 0;
 
 ret = parse_flow_match(, match);
@@ -450,15 +530,16 @@ netdev_offload_dpdk_add_flow(struct netdev *netdev,
 goto out;
 }
 
-add_flow_mark_rss_actions(, info->flow_mark, netdev);
-
-flow = netdev_dpdk_rte_flow_create(netdev, _attr,
-   patterns.items,
-   actions.actions, );
+flow = netdev_offload_dpdk_actions(netdev, , nl_actions,
+   actions_len, info);
+if (!flow) {
+/* if we failed to offload the rule 

[ovs-dev] [PATCH V3 03/19] netdev-offload-dpdk: Dynamically allocate pattern items

2019-12-08 Thread Eli Britstein
Instead of statically allocated pattern items on the stack, dynamically
allocate only the required items while parsing the matches, to simplify
the parsing and make it self-contained, without need of external types,
making it easier to support more matches in the future.

Signed-off-by: Eli Britstein 
Reviewed-by: Oz Shlomo 
---
 lib/netdev-offload-dpdk.c | 206 ++
 1 file changed, 118 insertions(+), 88 deletions(-)

diff --git a/lib/netdev-offload-dpdk.c b/lib/netdev-offload-dpdk.c
index c3b595a0a..e48ac3b63 100644
--- a/lib/netdev-offload-dpdk.c
+++ b/lib/netdev-offload-dpdk.c
@@ -374,6 +374,24 @@ add_flow_action(struct flow_actions *actions, enum 
rte_flow_action_type type,
 actions->cnt++;
 }
 
+static void
+free_flow_patterns(struct flow_patterns *patterns)
+{
+int i;
+
+for (i = 0; i < patterns->cnt; i++) {
+if (patterns->items[i].spec) {
+free((void *)patterns->items[i].spec);
+}
+if (patterns->items[i].mask) {
+free((void *)patterns->items[i].mask);
+}
+}
+free(patterns->items);
+patterns->items = NULL;
+patterns->cnt = 0;
+}
+
 static void
 free_flow_actions(struct flow_actions *actions)
 {
@@ -389,42 +407,30 @@ free_flow_actions(struct flow_actions *actions)
 actions->cnt = 0;
 }
 
-struct flow_items {
-struct rte_flow_item_eth  eth;
-struct rte_flow_item_vlan vlan;
-struct rte_flow_item_ipv4 ipv4;
-union {
-struct rte_flow_item_tcp  tcp;
-struct rte_flow_item_udp  udp;
-struct rte_flow_item_sctp sctp;
-struct rte_flow_item_icmp icmp;
-};
-};
-
 static int
 parse_flow_match(struct flow_patterns *patterns,
- struct flow_items *spec,
- struct flow_items *mask,
  const struct match *match)
 {
+uint8_t *next_proto_mask = NULL;
 uint8_t proto = 0;
 
-memset(spec, 0, sizeof *spec);
-memset(mask, 0, sizeof *mask);
-
 /* Eth */
 if (!eth_addr_is_zero(match->wc.masks.dl_src) ||
 !eth_addr_is_zero(match->wc.masks.dl_dst)) {
-memcpy(>eth.dst, >flow.dl_dst, sizeof spec->eth.dst);
-memcpy(>eth.src, >flow.dl_src, sizeof spec->eth.src);
-spec->eth.type = match->flow.dl_type;
+struct rte_flow_item_eth *spec, *mask;
+
+spec = xzalloc(sizeof *spec);
+mask = xzalloc(sizeof *mask);
 
-memcpy(>eth.dst, >wc.masks.dl_dst, sizeof mask->eth.dst);
-memcpy(>eth.src, >wc.masks.dl_src, sizeof mask->eth.src);
-mask->eth.type = match->wc.masks.dl_type;
+memcpy(>dst, >flow.dl_dst, sizeof spec->dst);
+memcpy(>src, >flow.dl_src, sizeof spec->src);
+spec->type = match->flow.dl_type;
 
-add_flow_pattern(patterns, RTE_FLOW_ITEM_TYPE_ETH,
- >eth, >eth);
+memcpy(>dst, >wc.masks.dl_dst, sizeof mask->dst);
+memcpy(>src, >wc.masks.dl_src, sizeof mask->src);
+mask->type = match->wc.masks.dl_type;
+
+add_flow_pattern(patterns, RTE_FLOW_ITEM_TYPE_ETH, spec, mask);
 } else {
 /*
  * If user specifies a flow (like UDP flow) without L2 patterns,
@@ -438,36 +444,45 @@ parse_flow_match(struct flow_patterns *patterns,
 
 /* VLAN */
 if (match->wc.masks.vlans[0].tci && match->flow.vlans[0].tci) {
-spec->vlan.tci  = match->flow.vlans[0].tci & ~htons(VLAN_CFI);
-mask->vlan.tci  = match->wc.masks.vlans[0].tci & ~htons(VLAN_CFI);
+struct rte_flow_item_vlan *spec, *mask;
+
+spec = xzalloc(sizeof *spec);
+mask = xzalloc(sizeof *mask);
+
+spec->tci = match->flow.vlans[0].tci & ~htons(VLAN_CFI);
+mask->tci = match->wc.masks.vlans[0].tci & ~htons(VLAN_CFI);
 
 /* Match any protocols. */
-mask->vlan.inner_type = 0;
+mask->inner_type = 0;
 
-add_flow_pattern(patterns, RTE_FLOW_ITEM_TYPE_VLAN,
- >vlan, >vlan);
+add_flow_pattern(patterns, RTE_FLOW_ITEM_TYPE_VLAN, spec, mask);
 }
 
 /* IP v4 */
 if (match->flow.dl_type == htons(ETH_TYPE_IP)) {
-spec->ipv4.hdr.type_of_service = match->flow.nw_tos;
-spec->ipv4.hdr.time_to_live= match->flow.nw_ttl;
-spec->ipv4.hdr.next_proto_id   = match->flow.nw_proto;
-spec->ipv4.hdr.src_addr= match->flow.nw_src;
-spec->ipv4.hdr.dst_addr= match->flow.nw_dst;
+struct rte_flow_item_ipv4 *spec, *mask;
+
+spec = xzalloc(sizeof *spec);
+mask = xzalloc(sizeof *mask);
 
-mask->ipv4.hdr.type_of_service = match->wc.masks.nw_tos;
-mask->ipv4.hdr.time_to_live= match->wc.masks.nw_ttl;
-mask->ipv4.hdr.next_proto_id   = match->wc.masks.nw_proto;
-mask->ipv4.hdr.src_addr= match->wc.masks.nw_src;
-mask->ipv4.hdr.dst_addr= match->wc.masks.nw_dst;
+spec->hdr.type_of_service = match->flow.nw_tos;
+

[ovs-dev] [PATCH V3 19/19] netdev-offload-dpdk: Support offload of set TCP/UDP ports actions

2019-12-08 Thread Eli Britstein
Signed-off-by: Eli Britstein 
Reviewed-by: Oz Shlomo 
---
 Documentation/howto/dpdk.rst |  1 +
 NEWS |  4 ++--
 lib/netdev-dpdk.c| 14 ++
 lib/netdev-offload-dpdk.c| 34 ++
 4 files changed, 51 insertions(+), 2 deletions(-)

diff --git a/Documentation/howto/dpdk.rst b/Documentation/howto/dpdk.rst
index b9aaf26bf..df863e4f1 100644
--- a/Documentation/howto/dpdk.rst
+++ b/Documentation/howto/dpdk.rst
@@ -396,6 +396,7 @@ Supported actions for hardware offload are:
 - Modification of IPv4 (mod_nw_src/mod_nw_dst/mod_nw_ttl).
 - Clone with tnl_push and output (a single clone, as the last action,
   with a single output, as the last nested clone action).
+- Modification of TCP/UDP (mod_tp_src/mod_tp_dst).
 
 Further Reading
 ---
diff --git a/NEWS b/NEWS
index 25125801b..d01b8983b 100644
--- a/NEWS
+++ b/NEWS
@@ -26,8 +26,8 @@ Post-v2.12.0
  * DPDK ring ports (dpdkr) are deprecated and will be removed in next
releases.
  * Add support for DPDK 19.11.
- * Add hardware offload support for output, drop, set of MAC, IPv4
-   and tunnel push-output actions (experimental).
+ * Add hardware offload support for output, drop, set of MAC, IPv4,
+   TCP/UDP ports and tunnel push-output actions (experimental).
 
 v2.12.0 - 03 Sep 2019
 -
diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c
index 14f5d6f3b..377e8ae07 100644
--- a/lib/netdev-dpdk.c
+++ b/lib/netdev-dpdk.c
@@ -4776,6 +4776,20 @@ ds_put_flow_action(struct ds *s, const struct 
rte_flow_action *actions)
 } else {
 ds_put_cstr(s, "  Raw-encap = null\n");
 }
+} else if (actions->type == RTE_FLOW_ACTION_TYPE_SET_TP_SRC ||
+   actions->type == RTE_FLOW_ACTION_TYPE_SET_TP_DST) {
+const struct rte_flow_action_set_tp *set_tp = actions->conf;
+char *dirstr = actions->type == RTE_FLOW_ACTION_TYPE_SET_TP_DST
+   ? "dst" : "src";
+
+ds_put_format(s, "rte flow set-tcp/udp-port-%s action:\n", dirstr);
+if (set_tp) {
+ds_put_format(s,
+  "  Set-%s-tcp/udp-port: %"PRIu16"\n",
+  dirstr, ntohs(set_tp->port));
+} else {
+ds_put_format(s, "  Set-%s-tcp/udp-port = null\n", dirstr);
+}
 } else {
 ds_put_format(s, "unknown rte flow action (%d)\n", actions->type);
 }
diff --git a/lib/netdev-offload-dpdk.c b/lib/netdev-offload-dpdk.c
index b0403a085..6a5d00276 100644
--- a/lib/netdev-offload-dpdk.c
+++ b/lib/netdev-offload-dpdk.c
@@ -620,6 +620,40 @@ parse_set_actions(struct flow_actions *actions,
 return -1;
 }
 
+if (add_set_flow_action(actions, sa_info_arr,
+ARRAY_SIZE(sa_info_arr))) {
+return -1;
+}
+} else if (nl_attr_type(sa) == OVS_KEY_ATTR_TCP) {
+const struct ovs_key_tcp *key = nl_attr_get(sa);
+const struct ovs_key_tcp *mask = masked ?
+get_mask(sa, struct ovs_key_tcp) : NULL;
+struct rte_flow_action_set_tp *src = xzalloc(sizeof *src);
+struct rte_flow_action_set_tp *dst = xzalloc(sizeof *dst);
+struct set_action_info sa_info_arr[] = {
+SA_INFO(tcp_src, src->port,
+RTE_FLOW_ACTION_TYPE_SET_TP_SRC),
+SA_INFO(tcp_dst, dst->port,
+RTE_FLOW_ACTION_TYPE_SET_TP_DST),
+};
+
+if (add_set_flow_action(actions, sa_info_arr,
+ARRAY_SIZE(sa_info_arr))) {
+return -1;
+}
+} else if (nl_attr_type(sa) == OVS_KEY_ATTR_UDP) {
+const struct ovs_key_udp *key = nl_attr_get(sa);
+const struct ovs_key_udp *mask = masked ?
+get_mask(sa, struct ovs_key_udp) : NULL;
+struct rte_flow_action_set_tp *src = xzalloc(sizeof *src);
+struct rte_flow_action_set_tp *dst = xzalloc(sizeof *dst);
+struct set_action_info sa_info_arr[] = {
+SA_INFO(udp_src, src->port,
+RTE_FLOW_ACTION_TYPE_SET_TP_SRC),
+SA_INFO(udp_dst, dst->port,
+RTE_FLOW_ACTION_TYPE_SET_TP_DST),
+};
+
 if (add_set_flow_action(actions, sa_info_arr,
 ARRAY_SIZE(sa_info_arr))) {
 return -1;
-- 
2.14.5

___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


[ovs-dev] [PATCH V3 11/19] dpif-netdev: Populate dpif class field in offload struct

2019-12-08 Thread Eli Britstein
Populate dpif class field in offload struct to be used in offloading
flow put.

Signed-off-by: Eli Britstein 
Reviewed-by: Oz Shlomo 
---
 lib/dpif-netdev.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 37e7e5c38..1d1de94de 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -2373,6 +2373,7 @@ static int
 dp_netdev_flow_offload_put(struct dp_flow_offload_item *offload)
 {
 struct dp_netdev_pmd_thread *pmd = offload->pmd;
+const struct dpif_class *dpif_class = pmd->dp->class;
 struct dp_netdev_flow *flow = offload->flow;
 odp_port_t in_port = flow->flow.in_port.odp_port;
 bool modification = offload->op == DP_NETDEV_FLOW_OFFLOAD_OP_MOD;
@@ -2411,6 +2412,7 @@ dp_netdev_flow_offload_put(struct dp_flow_offload_item 
*offload)
 }
 info.flow_mark = mark;
 info.actions_offloaded = >actions_offloaded;
+info.dpif_class = dpif_class;
 
 port = netdev_ports_get(in_port, pmd->dp->dpif->dpif_class);
 if (!port || netdev_vport_is_vport_class(port->netdev_class)) {
-- 
2.14.5

___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


[ovs-dev] [PATCH V3 00/19] netdev datapath actions offload

2019-12-08 Thread Eli Britstein
Currently, netdev datapath offload only accelerates the flow match
sequence by associating a mark per flow. This series introduces the full
offload of netdev datapath flows by having the HW also perform the flow
actions.

This series adds HW offload for output, drop, set MAC, set IPv4, set
TCP/UDP ports and tunnel push actions using the DPDK rte_flow API.

v1 Travis passed: https://travis-ci.org/elibritstein/OVS/builds/614511472
v2 Travis passed: https://travis-ci.org/elibritstein/OVS/builds/619262148
v3 Travis passed: https://travis-ci.org/elibritstein/OVS/builds/622253870

v1-v2:
- fallback to mark/rss in case of any failure of action offload.
- dp_layer changed to "in_hw" in case the flow is offloaded.
- using netdev_ports_get instead of dp_netdev_lookup_port in stats reading.
- using flow_dump_next API instead of a new API.
- validity checks for last action of output and clone.
- count action should be done for drop as well.
- validity check for output action.
- added doc in Documentation/howto/dpdk.rst.
v2-v3:
- removed refactoring for netdev-offload-dpdk-flow.c file.
- dropped flush commits.
- dbg prints rate-limited, and outside lock.
- added validity check for output action - same flow_api handle for both 
netdevs.
- added a mutex to protect possible concurrent deletion/querying of a flow.
- statistics are collected using flow_get API.
- added more documentation in Documentation/howto/dpdk.rst.

Eli Britstein (18):
  netdev-offload-dpdk: Refactor flow patterns
  netdev-offload-dpdk: Refactor action items freeing scheme
  netdev-offload-dpdk: Dynamically allocate pattern items
  netdev-offload-dpdk: Fix typo
  netdev-dpdk: Improve HW offload flow debuggability
  netdev-offload-dpdk: Framework for actions offload
  netdev-dpdk: Introduce rte flow query function
  netdev-offload-dpdk: Protect UFID map by mutex
  netdev-offload-dpdk: Implement flow get method
  dpif-netdev: Populate dpif class field in offload struct
  netdev-dpdk: Getter function for dpdk port id API
  netdev-offload: Introduce a function to validate same flow api handle
  netdev-offload-dpdk: Support offload of output action
  netdev-offload-dpdk: Support offload of drop action
  netdev-offload-dpdk: Support offload of set MAC actions
  netdev-offload-dpdk: Support offload of set IPv4 actions
  netdev-offload-dpdk: Support offload of clone tnl_push/output actions
  netdev-offload-dpdk: Support offload of set TCP/UDP ports actions

Ophir Munk (1):
  dpif-netdev: Read hw stats during flow_dump_next() call

 Documentation/howto/dpdk.rst  |  23 +-
 NEWS  |   2 +
 lib/dpif-netdev.c |  49 ++-
 lib/netdev-dpdk.c | 394 +
 lib/netdev-dpdk.h |   8 +
 lib/netdev-offload-dpdk.c | 954 +++---
 lib/netdev-offload-provider.h |   1 +
 lib/netdev-offload.c  |  12 +
 lib/netdev-offload.h  |   1 +
 9 files changed, 1091 insertions(+), 353 deletions(-)

-- 
2.14.5

___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


[ovs-dev] [PATCH V3 02/19] netdev-offload-dpdk: Refactor action items freeing scheme

2019-12-08 Thread Eli Britstein
Action item data structures are pointed by rte_flow_action items.
Refactor the code to free the data structures when freeing the
rte_flow_action items, allowing simpler future actions simpler to add to
the code.

Signed-off-by: Eli Britstein 
---
 lib/netdev-offload-dpdk.c | 92 ++-
 1 file changed, 52 insertions(+), 40 deletions(-)

diff --git a/lib/netdev-offload-dpdk.c b/lib/netdev-offload-dpdk.c
index a008e642f..c3b595a0a 100644
--- a/lib/netdev-offload-dpdk.c
+++ b/lib/netdev-offload-dpdk.c
@@ -374,40 +374,19 @@ add_flow_action(struct flow_actions *actions, enum 
rte_flow_action_type type,
 actions->cnt++;
 }
 
-struct action_rss_data {
-struct rte_flow_action_rss conf;
-uint16_t queue[0];
-};
-
-static struct action_rss_data *
-add_flow_rss_action(struct flow_actions *actions,
-struct netdev *netdev)
+static void
+free_flow_actions(struct flow_actions *actions)
 {
 int i;
-struct action_rss_data *rss_data;
-
-rss_data = xmalloc(sizeof *rss_data +
-   netdev_n_rxq(netdev) * sizeof rss_data->queue[0]);
-*rss_data = (struct action_rss_data) {
-.conf = (struct rte_flow_action_rss) {
-.func = RTE_ETH_HASH_FUNCTION_DEFAULT,
-.level = 0,
-.types = 0,
-.queue_num = netdev_n_rxq(netdev),
-.queue = rss_data->queue,
-.key_len = 0,
-.key  = NULL
-},
-};
 
-/* Override queue array with default. */
-for (i = 0; i < netdev_n_rxq(netdev); i++) {
-   rss_data->queue[i] = i;
+for (i = 0; i < actions->cnt; i++) {
+if (actions->actions[i].conf) {
+free((void *)actions->actions[i].conf);
+}
 }
-
-add_flow_action(actions, RTE_FLOW_ACTION_TYPE_RSS, _data->conf);
-
-return rss_data;
+free(actions->actions);
+actions->actions = NULL;
+actions->cnt = 0;
 }
 
 struct flow_items {
@@ -572,6 +551,47 @@ parse_flow_match(struct flow_patterns *patterns,
 return 0;
 }
 
+static void
+add_flow_mark_rss_actions(struct flow_actions *actions,
+  uint32_t flow_mark,
+  struct netdev *netdev)
+{
+struct rte_flow_action_mark *mark;
+struct action_rss_data {
+struct rte_flow_action_rss conf;
+uint16_t queue[0];
+} *rss_data;
+int i;
+
+mark = xzalloc(sizeof *mark);
+
+mark->id = flow_mark;
+add_flow_action(actions, RTE_FLOW_ACTION_TYPE_MARK, mark);
+
+rss_data = xmalloc(sizeof *rss_data +
+   netdev_n_rxq(netdev) * sizeof rss_data->queue[0]);
+*rss_data = (struct action_rss_data) {
+.conf = (struct rte_flow_action_rss) {
+.func = RTE_ETH_HASH_FUNCTION_DEFAULT,
+.level = 0,
+.types = 0,
+.queue_num = netdev_n_rxq(netdev),
+.queue = rss_data->queue,
+.key_len = 0,
+.key  = NULL
+},
+};
+
+/* Override queue array with default. */
+for (i = 0; i < netdev_n_rxq(netdev); i++) {
+   rss_data->queue[i] = i;
+}
+
+add_flow_action(actions, RTE_FLOW_ACTION_TYPE_RSS, _data->conf);
+
+add_flow_action(actions, RTE_FLOW_ACTION_TYPE_END, NULL);
+}
+
 static int
 netdev_offload_dpdk_add_flow(struct netdev *netdev,
  const struct match *match,
@@ -599,20 +619,12 @@ netdev_offload_dpdk_add_flow(struct netdev *netdev,
 goto out;
 }
 
-struct rte_flow_action_mark mark;
-struct action_rss_data *rss;
-
-mark.id = info->flow_mark;
-add_flow_action(, RTE_FLOW_ACTION_TYPE_MARK, );
-
-rss = add_flow_rss_action(, netdev);
-add_flow_action(, RTE_FLOW_ACTION_TYPE_END, NULL);
+add_flow_mark_rss_actions(, info->flow_mark, netdev);
 
 flow = netdev_dpdk_rte_flow_create(netdev, _attr,
patterns.items,
actions.actions, );
 
-free(rss);
 if (!flow) {
 VLOG_ERR("%s: rte flow creat error: %u : message : %s\n",
  netdev_get_name(netdev), error.type, error.message);
@@ -625,7 +637,7 @@ netdev_offload_dpdk_add_flow(struct netdev *netdev,
 
 out:
 free(patterns.items);
-free(actions.actions);
+free_flow_actions();
 return ret;
 }
 
-- 
2.14.5

___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


[ovs-dev] [PATCH V3 12/19] netdev-dpdk: Getter function for dpdk port id API

2019-12-08 Thread Eli Britstein
Add a getter function for using the dpdk port id outside the scope of
netdev-dpdk.c to be used for HW offload.

Signed-off-by: Eli Britstein 
Reviewed-by: Oz Shlomo 
---
 lib/netdev-dpdk.c | 18 ++
 lib/netdev-dpdk.h |  2 ++
 2 files changed, 20 insertions(+)

diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c
index e63a496c1..16baae0c4 100644
--- a/lib/netdev-dpdk.c
+++ b/lib/netdev-dpdk.c
@@ -4426,6 +4426,24 @@ unlock:
 return err;
 }
 
+int
+netdev_dpdk_get_port_id(struct netdev *netdev)
+{
+struct netdev_dpdk *dev;
+int ret = -1;
+
+if (!is_dpdk_class(netdev->netdev_class)) {
+goto out;
+}
+
+dev = netdev_dpdk_cast(netdev);
+ovs_mutex_lock(>mutex);
+ret = dev->port_id;
+ovs_mutex_unlock(>mutex);
+out:
+return ret;
+}
+
 bool
 netdev_dpdk_flow_api_supported(struct netdev *netdev)
 {
diff --git a/lib/netdev-dpdk.h b/lib/netdev-dpdk.h
index ed7cb235a..65f6eedf3 100644
--- a/lib/netdev-dpdk.h
+++ b/lib/netdev-dpdk.h
@@ -53,6 +53,8 @@ netdev_dpdk_rte_flow_query(struct netdev *netdev,
struct rte_flow *rte_flow,
struct rte_flow_query_count *query,
struct rte_flow_error *error);
+int
+netdev_dpdk_get_port_id(struct netdev *netdev);
 
 #else
 
-- 
2.14.5

___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


Re: [ovs-dev] [PATCH ovn] ovn-controller: Run I-P engine even when no SB txn is available.

2019-12-08 Thread Dumitru Ceara
On Sat, Dec 7, 2019 at 4:53 PM Han Zhou  wrote:
>
>
>
> On Sat, Dec 7, 2019 at 3:21 AM Dumitru Ceara  wrote:
> >
> > On Sat, Dec 7, 2019 at 1:36 AM Han Zhou  wrote:
> > >
> > > Thanks Dumitru for the patch. Please see my comments below.
> > >
> >
> > Hi Han,
> >
> > Thanks for the review.
> >
> > > On Fri, Dec 6, 2019 at 5:38 AM Dumitru Ceara  wrote:
> > > >
> > > > If the last ovn-controller main loop run started a transaction to the
> > > > Southbound DB and the transaction is still in progress, ovn-controller
> > > > will not call engine_run(). In case there were changes to the DB,
> > > > engine_need_run() would return true which would trigger an immediate
> > > > forced recompute in the next processing loop iteration.
> > > >
> > > > However, there are scenarios when updates can be processed incrementally
> > > > even if no Southbound DB transaction is available. One example, often
> > > > seen in the field, is when the MAC_Binding table is updated. Currently
> > > > such an update received while a transaction is still committing would
> > > > trigger a forced recompute.
> > > >
> > > > To minimize the number of forced recomputes, we now call
> > > > engine_run(false), i.e., try to process updates incrementally without
> > > > allowing recompute, also when ovnsb_idl_txn == NULL. This is safe
> > > > because ovnsb_idl_txn is not used by change_handlers and run handlers
> > > > are not allowed to execute when calling engine_run(false).
> > > >
> > > This patch assumes we will never need to do SB updates when handling 
> > > changes incrementally. There are two problems:
> > > 1. I don't see a reason why a change_handler (for doing incremental 
> > > compute) can't update SB DB. For example Numan mentioned about working on 
> > > incremental processing for port-bindings on local chassis. I believe 
> > > those change handling would trigger SB updates, e.g. claiming/releasing a 
> > > port.
> > > 2. Even if we can keep this assumption and never do incremental 
> > > processing for changes that require updating SB DB, how do we ensure this 
> > > constraint is enforced in coding?
> > >
> >
> > I think my commit message is not clear enough. I didn't mean that
> > change handlers will never perform SB updates. What I meant was that
> > if a change handler needs to perform SB updates it needs to validate
> > that ovnsb_idl_txn != NULL and if it's NULL return "false" to trigger
> > a recompute. At this moment we have no change handler that updates the
> > SB database but as you pointed out we might have them in the future.
> > Then, the new change handlers will have to make sure that
> > ovnsb_idl_txn is not NULL.
> >
>
> OK, maybe I missed the point. Now let me rephrase your idea.
> This patch is to do only incremental processing when txn is NULL, which means 
> executing change handlers instead of run() methods. Assume some change 
> handlers need to update SB DB, some don't.
> If the incoming change (when txn is NULL) doesn't trigger SB update, then 
> change handlers can complete without aborting. - this seems to happen in most 
> cases.
> If the incoming change happen to require another SB update, since txn is 
> NULL, the change handlers that are supposed to do the update will need to 
> return false and result in aborting. - this may not happen very often, so the 
> approach of this patch should be effective.

Exactly.

>
> > > For 2), it may be easy. We could hide the interface get_context(), and 
> > > always pass the context to xxx_run() interface, so that ovnsb_idl_txn can 
> > > be accessed by recompute but never by change_handlers.
> > > What I am really concerned is 1). I think the long term solution is to 
> > > make the OVSDB change tracking available across iterations. Maybe it is 
> > > not a trivial work.
> > >
> >
> > As mentioned above, I don't think we need this as long as the contract
> > of get_context() is clear and the users know to check for NULL txn
> > pointers in change handlers.
> >
> Agree, but I'd suggest to document the patter more clearly, that a run() 
> handler never expects NULL txn, and a change handler need to check if txn is 
> NULL before using it. If it is NULL, it should return false (can't process 
> the change).

I'll send a v2 soon and document this requirement better.

Thanks,
Dumitru

>
> > > If we believe there is a big performance gain here and we are sure we 
> > > don't need to update SB DB in change handlers (in short term), we may 
> > > proceed with this approach as long as 2) is addressed, and revert this 
> > > whenever the long term solution (OVSDB change tracking over iterations) 
> > > is ready.
> >
> > There's no real reason to not try to process changes incrementally
> > even when a SB txn is in progress (ovnsb_idl_txn == NULL). We use the
> > same reasoning for !ofctrl_can_put() in order to avoid forced
> > recomputes. We saw it on customer deployments that MAC_Binding updates
> > received while a SB transaction was still in progress were 

Re: [ovs-dev] [RFC v3 0/4] netdev-offload: Prerequisites of vport offloading via DPDK.

2019-12-08 Thread Eli Britstein

On 12/6/2019 4:34 PM, Ilya Maximets wrote:
> On 06.12.2019 14:09, Ophir Munk wrote:
>> Hi Ilya,
>> I applied this series on master ("dpdk: Update to use DPDK 19.11.") and 
>> PINGed between two "dpdk" ports (hw-offload=true).
>> It worked fine.
>> Then I watched flow statistics (dpif based) by executing the command in (1):
>> (1) watch ovs-appctl dpif/dump-flows -m 
>> It worked fine.
>> Then I watched flow statistics (dpctl based) by executing the command in (2):
>> (2) watch ovs-appctl dpctl/dump-flows
>> In this case OVS crashed after a few seconds.
>>
>> When inspecting the calls trace I notice that 
>> pmd->dp->dpif->dpif_class->type is a corrupted memory address.
>>
>> (gdb) bt
>> #0  0x00c26fda in dpif_normalize_type (type=0x7372 > out of bounds>) at lib/dpif.c:517
>> #1  0x00c19864 in dp_netdev_flow_offload_put 
>> (offload=offload@entry=0x7f11fc00b790) at lib/dpif-netdev.c:2378
>> #2  0x00c19ca8 in dp_netdev_flow_offload_main (data=) 
>> at lib/dpif-netdev.c:2467
>> #3  0x00ca3c9d in ovsthread_wrapper (aux_=) at 
>> lib/ovs-thread.c:383
>> #4  0x7f12a2a08e25 in start_thread () from /lib64/libpthread.so.0
>> #5  0x7f12a222c34d in clone () from /lib64/libc.so.6
>>
>> This scenario repeats whenever running the command in (2) and when the code 
>> calls dpif_normalize_type().
>> It seems to me that the memory corruption was there for a while but only now 
>> it is exposed due to your rfc series.
>>
>> In order to observe this memory corruption I added the following printouts.
>> I tested it with hw-offload=false:
>> ovs-vsctl set Open_vSwitch . other_config:hw-offload=false
>> I tested it on latest master without your rfc series.
>>
>> diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
>> index 1e54936..18a804a 100644
>> --- a/lib/dpif-netdev.c
>> +++ b/lib/dpif-netdev.c
>> @@ -3625,6 +3625,10 @@ dpif_netdev_flow_dump_next(struct 
>> dpif_flow_dump_thread *thread_,
>>   }
>>   }
>>   
>> +VLOG_ERR("pmd->dp=%p pmd->dp->dpif=%p pmd->dp->dpif->dpif_class=%p \
>> + pmd->dp->dpif->full_name=%s",
>> + pmd->dp, pmd->dp->dpif, pmd->dp->dpif->dpif_class,
>> + pmd->dp->dpif->full_name);
>>   do {
>>   for (n_flows = 0; n_flows < flow_limit; n_flows++) {
>>   struct cmap_node *node;
>>
>>
>> Looking at the printouts the memory corruption is observed.
>>
>> Initially all printouts are identical and correct as expected.
>>
>> dpif_netdev(revalidator82)|ERR|pmd->dp=0x7fdfea3ea010 
>> pmd->dp->dpif=0x2525e70 pmd->dp->dpif->dpif_class=0xef3e80 
>> pmd->dp->dpif->full_name=netdev@ovs-netdev
>> dpif_netdev(revalidator82)|ERR|pmd->dp=0x7fdfea3ea010 
>> pmd->dp->dpif=0x2525e70 pmd->dp->dpif->dpif_class=0xef3e80 
>> pmd->dp->dpif->full_name=netdev@ovs-netdev
>> dpif_netdev(revalidator82)|ERR|pmd->dp=0x7fdfea3ea010 
>> pmd->dp->dpif=0x2525e70 pmd->dp->dpif->dpif_class=0xef3e80 
>> pmd->dp->dpif->full_name=netdev@ovs-netdev
>>
>> Around this point I executed the dpctl command in (2) and you can notice 
>> that the pointers pmd->dp->dp_dpif and beyond became modified.
>>
>> dpif_netdev(revalidator82)|ERR|pmd->dp=0x7fdfea3ea010 
>> pmd->dp->dpif=0x25c3280 pmd->dp->dpif->dpif_class=0x251c790 
>> pmd->dp->dpif->full_name=(null)
>> dpif_netdev(revalidator82)|ERR|pmd->dp=0x7fdfea3ea010 
>> pmd->dp->dpif=0x25c3280 pmd->dp->dpif->dpif_class=0x33c03608 
>> pmd->dp->dpif->full_name=
>> dpif_netdev(revalidator82)|ERR|pmd->dp=0x7fdfea3ea010 
>> pmd->dp->dpif=0x25c3280 pmd->dp->dpif->dpif_class=0x2605700 
>> pmd->dp->dpif->full_name=
>> dpif_netdev(revalidator82)|ERR|pmd->dp=0x7fdfea3ea010 
>> pmd->dp->dpif=0x25c3280 pmd->dp->dpif->dpif_class=0xe784250b 
>> pmd->dp->dpif->full_name=memseg-2048k-0-3
>> dpif_netdev|ERR|pmd->dp=0x7fdfea3ea010 pmd->dp->dpif=0x2602430 
>> pmd->dp->dpif->dpif_class=0xef3e80 pmd->dp->dpif->full_name=netdev@ovs-netdev
>> dpif_netdev(revalidator82)|ERR|pmd->dp=0x7fdfea3ea010 
>> pmd->dp->dpif=0x2602430 pmd->dp->dpif->dpif_class=0x2606200 
>> pmd->dp->dpif->full_name=(null)
>>
>> The same happens if I test it with hw-offload=true.
>>
>> I hope this scenario can be recreated on other setups as well.
> This is interesting.  I'll try to reproduce this issue on my setup.

Hi Ilya,

I see that this bug is not only with this new patch-set, but now also 
came into effect in master, with acceptance of

30115809da2e ("dpif-netdev: Use netdev-offload API for port lookup while 
offloading.")

-    port = dp_netdev_lookup_port(pmd->dp, in_port);
+    port = netdev_ports_get(in_port, pmd->dp->dpif->dpif_class);
As of the corruption, the "port" is not retrieved by netdev_ports_get, 
and the offloading is not done. I have reverted this commits in my tests.

Though this commit is correct (but should not have any effect before 
vport offloading), maybe we should revert it until this corruption bug 
is fixed.

Thanks,

Eli

>
>> I will look more into it.
> Thanks!
>
> 

[ovs-dev] [ovs-dev, v2] datapath-windows: Don't delete internal port

2019-12-08 Thread Jinjun Gao via dev
According to the microsoft doc:
https://docs.microsoft.com/en-us/windows-hardware/drivers/network/hyper-v-extensible-switch-port-and-network-adapter-states
Below OID request sequence is validation:
 OID_SWITCH_NIC_CONNECT -> OID_SWITCH_NIC_DISCONNECT
  ^   |
  |   V
 OID_SWITCH_NIC_CREATE  <- OID_SWITCH_NIC_DELETE

In above sequence, the windows extensible switch interface assumes the
OID_SWITCH_PORT_CREATE has issued and the port has been created
successfully. If delete the internal port in HvDisconnectNic(),
HvCreateNic() will fail when received OID_SWITCH_NIC_CREATE late because
there is no corresponding port.

Signed-off-by: Jinjun Gao 
---
datapath-windows/ovsext/Vport.c | 12 +---
1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/datapath-windows/ovsext/Vport.c b/datapath-windows/ovsext/Vport.c
index 57e7510..9f1587f 100644
--- a/datapath-windows/ovsext/Vport.c
+++ b/datapath-windows/ovsext/Vport.c
@@ -628,6 +628,7 @@ HvDisconnectNic(POVS_SWITCH_CONTEXT switchContext,
 event.upcallPid = vport->upcallPid;
 RtlCopyMemory(, >ovsName, sizeof event.ovsName);
 event.type = OVS_EVENT_LINK_DOWN;
+OvsPostVportEvent();

 /*
  * Delete the port from the hash tables accessible to userspace. After this
@@ -635,13 +636,18 @@ HvDisconnectNic(POVS_SWITCH_CONTEXT switchContext,
  */
 if (OvsIsRealExternalVport(vport)) {
 OvsRemoveAndDeleteVport(NULL, switchContext, vport, FALSE, TRUE);
-OvsPostVportEvent();
 }

 if (isInternalPort) {
 OvsUnBindVportWithIpHelper(vport, switchContext);
-OvsRemoveAndDeleteVport(NULL, switchContext, vport, TRUE, TRUE);
-OvsPostVportEvent();
+/*
+ * Don't delete the port from the hash tables here for internal port
+ * because the internal port cannot be recreated in HvCreateNic(). It
+ * only can be created in HvCreatePort() by issuing
+ * OID_SWITCH_PORT_CREATE. We should wait extensible switch interface
+ * to issue OID_SWITCH_PORT_TEARDOWN and OID_SWITCH_PORT_DELETE to
+ * delete the internal port.
+ */
 }
 NdisReleaseRWLock(switchContext->dispatchLock, );

--
1.8.5.6

___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


Re: [ovs-dev] [PATCH 15/20] netdev-offload-dpdk-flow: Support offload of output action

2019-12-08 Thread Eli Britstein


On 12/5/2019 6:46 PM, Sriharsha Basavapatna wrote:
> On Wed, Dec 4, 2019 at 8:55 PM Eli Britstein  wrote:
>>
>> On 12/3/2019 5:19 PM, Sriharsha Basavapatna wrote:
>>> On Wed, Nov 20, 2019 at 9:07 PM Eli Britstein  wrote:
 Signed-off-by: Eli Britstein 
 Reviewed-by: Oz Shlomo 
 ---
NEWS   |  2 +
lib/netdev-offload-dpdk-flow.c | 87 
 --
2 files changed, 85 insertions(+), 4 deletions(-)

 diff --git a/NEWS b/NEWS
 index 88b818948..ca9c2b230 100644
 --- a/NEWS
 +++ b/NEWS
 @@ -10,6 +10,8 @@ Post-v2.12.0
   if supported by libbpf.
 * Add option to enable, disable and query TCP sequence checking in
   conntrack.
 +   - DPDK:
 + * Add hardware offload support for output actions.

v2.12.0 - 03 Sep 2019
-
 diff --git a/lib/netdev-offload-dpdk-flow.c 
 b/lib/netdev-offload-dpdk-flow.c
 index dbbc45e99..6e7efb315 100644
 --- a/lib/netdev-offload-dpdk-flow.c
 +++ b/lib/netdev-offload-dpdk-flow.c
 @@ -274,6 +274,28 @@ ds_put_flow_action(struct ds *s, const struct 
 rte_flow_action *actions)
} else {
ds_put_cstr(s, "  RSS = null\n");
}
 +} else if (actions->type == RTE_FLOW_ACTION_TYPE_COUNT) {
 +const struct rte_flow_action_count *count = actions->conf;
 +
 +ds_put_cstr(s, "rte flow count action:\n");
 +if (count) {
 +ds_put_format(s,
 +  "  Count: shared=%d, id=%d\n",
 +  count->shared, count->id);
 +} else {
 +ds_put_cstr(s, "  Count = null\n");
 +}
 +} else if (actions->type == RTE_FLOW_ACTION_TYPE_PORT_ID) {
 +const struct rte_flow_action_port_id *port_id = actions->conf;
 +
 +ds_put_cstr(s, "rte flow port-id action:\n");
 +if (port_id) {
 +ds_put_format(s,
 +  "  Port-id: original=%d, id=%d\n",
 +  port_id->original, port_id->id);
 +} else {
 +ds_put_cstr(s, "  Port-id = null\n");
 +}
} else {
ds_put_format(s, "unknown rte flow action (%d)\n", 
 actions->type);
}
 @@ -531,19 +553,76 @@ netdev_dpdk_flow_patterns_add(struct flow_patterns 
 *patterns,
return 0;
}

 +static void
 +netdev_dpdk_flow_add_count_action(struct flow_actions *actions)
 +{
 +struct rte_flow_action_count *count = xzalloc(sizeof *count);
 +
 +count->shared = 0;
 +/* Each flow has a single count action, so no need of id */
 +count->id = 0;
 +add_flow_action(actions, RTE_FLOW_ACTION_TYPE_COUNT, count);
 +}
 +
 +static void
 +netdev_dpdk_flow_add_port_id_action(struct flow_actions *actions,
 +struct netdev *outdev)
 +{
 +struct rte_flow_action_port_id *port_id = xzalloc(sizeof *port_id);
 +
 +port_id->id = netdev_dpdk_get_port_id(outdev);
 +add_flow_action(actions, RTE_FLOW_ACTION_TYPE_PORT_ID, port_id);
 +}
 +
 +static int
 +netdev_dpdk_flow_add_output_action(struct flow_actions *actions,
 +   const struct nlattr *nla,
 +   struct offload_info *info)
 +{
 +struct netdev *outdev;
 +odp_port_t port;
 +
 +port = nl_attr_get_odp_port(nla);
 +outdev = netdev_ports_get(port, info->dpif_class);
 +if (outdev == NULL) {
 +VLOG_DBG_RL(_rl,
 +"Cannot find netdev for odp port %d", port);
 +return -1;
 +}
 +if (!netdev_dpdk_flow_api_supported(outdev)) {
 +VLOG_DBG_RL(_rl,
 +"Output to %s cannot be offloaded",
 +netdev_get_name(outdev));
 +return -1;
 +}
 +
 +netdev_dpdk_flow_add_count_action(actions);
 +netdev_dpdk_flow_add_port_id_action(actions, outdev);
 +netdev_close(outdev);
 +
 +return 0;
 +}
 +
int
netdev_dpdk_flow_actions_add(struct flow_actions *actions,
 struct nlattr *nl_actions,
 size_t nl_actions_len,
 - struct offload_info *info OVS_UNUSED)
 + struct offload_info *info)
{
struct nlattr *nla;
size_t left;

NL_ATTR_FOR_EACH_UNSAFE (nla, left, nl_actions, nl_actions_len) {
 -VLOG_DBG_RL(_rl,
 -"Unsupported action type %d", nl_attr_type(nla));
 -return -1;
 + 

Re: [ovs-dev] [PATCHv4] userspace: Add GTP-U support.

2019-12-08 Thread Roni Bar Yanai
Hi William,

GTP-U header size is not constant, you *must* take into account the flags, 
mainly
 the sequence. The use of sequence in GTP-U is optional but some devices do use
 it.  see from 3GPP definition:
"For PGW, SGW and eNodeB the usage of sequence numbers in G-PDUs is optional, 
but
 if GTP-U protocol entities in these nodes are relaying G-PDUs to other nodes, 
they 
 shall relay the sequence numbers as well. An RNC, SGSN or GGSN shall reorder 
out 
 of sequence T-PDUs when in sequence delivery is required. This is optional"

The assumption that GTP-U is only data is not correct, you have some signaling
for example END MARKER (like you wrote). This message is sent when there is a 
mobility
 between cells, and the message contains a TEID and indicates that last packet 
sent from 
the origin cell, to prevent packet re-order as handover might have packets
on the fly. So I would expected that END MARKER will do the exact same 
forwarding as the GTP-U data.

see inline

>-Original Message-
>From: dev  On Behalf Of William Tu
>Sent: Thursday, December 5, 2019 10:44 PM
>To: d...@openvswitch.org
>Subject: [ovs-dev] [PATCHv4] userspace: Add GTP-U support.
>
>GTP, GPRS Tunneling Protocol, is a group of IP-based communications
>protocols used to carry general packet radio service (GPRS) within
>GSM, UMTS and LTE networks.  GTP protocol has two parts: Signalling
>(GTP-Control, GTP-C) and User data (GTP-User, GTP-U). GTP-C is used
>for setting up GTP-U protocol, which is an IP-in-UDP tunneling
>protocol. Usually GTP is used in connecting between base station for
>radio, Serving Gateway (S-GW), and PDN Gateway (P-GW).
>
>This patch implements GTP-U protocol for userspace datapath,
>supporting only required header fields and G-PDU message type.
>See spec in:
>https://eur03.safelinks.protection.outlook.com/?url=https%3A%2F%2Ftools.ietf.o
>rg%2Fhtml%2Fdraft-hmm-dmm-5g-uplane-analysis-
>00data=02%7C01%7Croniba%40mellanox.com%7Cb73529a0bea34637f9ed0
>8d779c3f1e4%7Ca652971c7d2e4d9ba6a4d149256f461b%7C0%7C0%7C63711175479
>1292921sdata=tY0GruNTBV9NWZg9gO2Lo4PWQZ1swHkB1AwdEg3AJUE%3
>Dreserved=0
>
>Signed-off-by: Yi Yang 
>Co-authored-by: Yi Yang 
>Signed-off-by: William Tu 
>---
>v3 -> v4:
>  - applied Ben's doc revise
>  - increment FLOW_WC_SEQ to 42
>  - minor fixes
>  - travis:
>https://eur03.safelinks.protection.outlook.com/?url=https%3A%2F%2Ftravis-
>ci.org%2Fwilliamtu%2Fovs-
>travis%2Fbuilds%2F621289678data=02%7C01%7Croniba%40mellanox.com%
>7Cb73529a0bea34637f9ed08d779c3f1e4%7Ca652971c7d2e4d9ba6a4d149256f461b
>%7C0%7C0%7C637111754791292921sdata=eYRkIjcPUQqJwBQndsjCgtcPGG1
>l4QFUnAWW4vwPjpI%3Dreserved=0
>
>v2 -> v3:
>  - pick up the code from v2, rebase to master
>  - many fixes in code, docs, and add more tests
>  - travis:
>https://eur03.safelinks.protection.outlook.com/?url=https%3A%2F%2Ftravis-
>ci.org%2Fwilliamtu%2Fovs-
>travis%2Fbuilds%2F619799361data=02%7C01%7Croniba%40mellanox.com%
>7Cb73529a0bea34637f9ed08d779c3f1e4%7Ca652971c7d2e4d9ba6a4d149256f461b
>%7C0%7C0%7C637111754791292921sdata=cu5bdmJ4ydInKt4chxOcGy33K5E
>9BMDzxgk5%2F7Cq%2FtI%3Dreserved=0
>
>v1 -> v2:
>  - Add new packet_type PT_GTPU_MSG to handle GTP-U signaling message,
>GTP-U signaling message should be steered into a control plane handler
>by explicit openflow entry in flow table.
>  - Fix gtpu_flags and gptu_msgtype set issue.
>  - Verify communication with kernel GTP implementation from Jiannan
>Ouyang.
>  - Fix unit test issue and make sure all the unit tests can pass.
>  - This patch series add GTP-U tunnel support in DPDK userspace,
>GTP-U is used for carrying user data within the GPRS core network and
>between the radio access network and the core network. The user data
>transported can be packets in any of IPv4, IPv6, or PPP formats.
>---
> Documentation/faq/configuration.rst   |  13 +++
> Documentation/faq/releases.rst|   1 +
> NEWS  |   3 +
> datapath/linux/compat/include/linux/openvswitch.h |   2 +
> include/openvswitch/flow.h|   4 +-
> include/openvswitch/match.h   |   6 ++
> include/openvswitch/meta-flow.h   |  28 ++
> include/openvswitch/packets.h |   4 +-
> lib/dpif-netlink-rtnl.c   |   5 +
> lib/dpif-netlink.c|   5 +
> lib/flow.c|  22 +++--
> lib/flow.h|   2 +-
> lib/match.c   |  30 +-
> lib/meta-flow.c   |  38 
> lib/meta-flow.xml |  79 ++-
> lib/netdev-native-tnl.c   |  85 
> lib/netdev-native-tnl.h   |   8 ++
> lib/netdev-vport.c|  25 -
> lib/nx-match.c