diff --git a/0000-openvswitch-add-stack-protector-strong.patch b/0000-openvswitch-add-stack-protector-strong.patch deleted file mode 100644 index 36dbe8c96245b7cbd1e7bdff67320f6101e60459..0000000000000000000000000000000000000000 --- a/0000-openvswitch-add-stack-protector-strong.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/Makefile.am b/Makefile.am -index ff1f94b..cca6cf0 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -30,7 +30,7 @@ AM_CPPFLAGS += -I $(top_builddir)/lib - - AM_CPPFLAGS += $(SSL_INCLUDES) - --AM_CFLAGS = -Wstrict-prototypes -+AM_CFLAGS = -Wstrict-prototypes -fstack-protector-strong - AM_CFLAGS += $(WARNING_FLAGS) - AM_CFLAGS += $(OVS_CFLAGS) - diff --git a/Avoid-indeterminate-statistics-in-offload-implementa.patch b/Avoid-indeterminate-statistics-in-offload-implementa.patch deleted file mode 100644 index 208a1ea9c6b7cc743a7241be699512ba3f1a4195..0000000000000000000000000000000000000000 --- a/Avoid-indeterminate-statistics-in-offload-implementa.patch +++ /dev/null @@ -1,127 +0,0 @@ -From def4468defed9fb5418dc7311972b04ac3bf579a Mon Sep 17 00:00:00 2001 -From: Ben Pfaff -Date: Fri, 25 Oct 2019 11:46:24 -0700 -Subject: Avoid indeterminate statistics in offload implementations. - -A lot of the offload implementations didn't bother to initialize the -statistics they were supposed to return. I don't know whether any of -the callers actually use them, but it looked wrong. - -Found by inspection. - -Acked-by: Ilya Maximets -Signed-off-by: Ben Pfaff ---- - lib/netdev-dummy.c | 10 ++++++++-- - lib/netdev-offload-dpdk.c | 10 ++++++++-- - lib/netdev-offload-tc.c | 5 ++++- - 3 files changed, 20 insertions(+), 5 deletions(-) - -diff --git a/lib/netdev-dummy.c b/lib/netdev-dummy.c -index f0c0fbae8..d2201420c 100644 ---- a/lib/netdev-dummy.c -+++ b/lib/netdev-dummy.c -@@ -1434,7 +1434,7 @@ netdev_dummy_flow_put(struct netdev *netdev, struct match *match, - struct nlattr *actions OVS_UNUSED, - size_t actions_len OVS_UNUSED, - const ovs_u128 *ufid, struct offload_info *info, -- struct dpif_flow_stats *stats OVS_UNUSED) -+ struct dpif_flow_stats *stats) - { - struct netdev_dummy *dev = netdev_dummy_cast(netdev); - struct offloaded_flow *off_flow; -@@ -1476,12 +1476,15 @@ netdev_dummy_flow_put(struct netdev *netdev, struct match *match, - ds_destroy(&ds); - } - -+ if (stats) { -+ memset(stats, 0, sizeof *stats); -+ } - return 0; - } - - static int - netdev_dummy_flow_del(struct netdev *netdev, const ovs_u128 *ufid, -- struct dpif_flow_stats *stats OVS_UNUSED) -+ struct dpif_flow_stats *stats) - { - struct netdev_dummy *dev = netdev_dummy_cast(netdev); - struct offloaded_flow *off_flow; -@@ -1521,6 +1524,9 @@ exit: - ds_destroy(&ds); - } - -+ if (stats) { -+ memset(stats, 0, sizeof *stats); -+ } - return error ? -1 : 0; - } - -diff --git a/lib/netdev-offload-dpdk.c b/lib/netdev-offload-dpdk.c -index 01e900461..96794dc4d 100644 ---- a/lib/netdev-offload-dpdk.c -+++ b/lib/netdev-offload-dpdk.c -@@ -710,7 +710,7 @@ static int - netdev_offload_dpdk_flow_put(struct netdev *netdev, struct match *match, - struct nlattr *actions, size_t actions_len, - const ovs_u128 *ufid, struct offload_info *info, -- struct dpif_flow_stats *stats OVS_UNUSED) -+ struct dpif_flow_stats *stats) - { - struct rte_flow *rte_flow; - int ret; -@@ -732,13 +732,16 @@ netdev_offload_dpdk_flow_put(struct netdev *netdev, struct match *match, - return ret; - } - -+ if (stats) { -+ memset(stats, 0, sizeof *stats); -+ } - return netdev_offload_dpdk_add_flow(netdev, match, actions, - actions_len, ufid, info); - } - - static int - netdev_offload_dpdk_flow_del(struct netdev *netdev, const ovs_u128 *ufid, -- struct dpif_flow_stats *stats OVS_UNUSED) -+ struct dpif_flow_stats *stats) - { - struct rte_flow *rte_flow = ufid_to_rte_flow_find(ufid); - -@@ -746,6 +749,9 @@ netdev_offload_dpdk_flow_del(struct netdev *netdev, const ovs_u128 *ufid, - return -1; - } - -+ if (stats) { -+ memset(stats, 0, sizeof *stats); -+ } - return netdev_offload_dpdk_destroy_flow(netdev, ufid, rte_flow); - } - -diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c -index ad637b48c..a6b03015d 100644 ---- a/lib/netdev-offload-tc.c -+++ b/lib/netdev-offload-tc.c -@@ -1086,7 +1086,7 @@ static int - netdev_tc_flow_put(struct netdev *netdev, struct match *match, - struct nlattr *actions, size_t actions_len, - const ovs_u128 *ufid, struct offload_info *info, -- struct dpif_flow_stats *stats OVS_UNUSED) -+ struct dpif_flow_stats *stats) - { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20); - enum tc_qdisc_hook hook = get_tc_qdisc_hook(netdev); -@@ -1377,6 +1377,9 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, - - err = tc_replace_flower(ifindex, prio, handle, &flower, block_id, hook); - if (!err) { -+ if (stats) { -+ memset(stats, 0, sizeof *stats); -+ } - add_ufid_tc_mapping(ufid, flower.prio, flower.handle, netdev, ifindex); - } - --- -2.14.1 - - diff --git a/Documentation-Fix-security-mailing-list-address.patch b/Documentation-Fix-security-mailing-list-address.patch deleted file mode 100644 index 81a332d6e7dbe83c408e2cb961fb2c903214da53..0000000000000000000000000000000000000000 --- a/Documentation-Fix-security-mailing-list-address.patch +++ /dev/null @@ -1,28 +0,0 @@ -From c11a25f2a105bc81322fa605d947bc53ea9814de Mon Sep 17 00:00:00 2001 -From: Ben Pfaff -Date: Mon, 23 Sep 2019 12:38:56 -0700 -Subject: Documentation: Fix security mailing list address. - -We don't own ovs.org, and I doubt Ojai Valley School would enjoy -receiving our email. - -Reviewed-by: Greg Rose -Signed-off-by: Ben Pfaff ---- - Documentation/internals/mailing-lists.rst | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/Documentation/internals/mailing-lists.rst b/Documentation/internals/mailing-lists.rst -index 33f20277b..e8b344094 100644 ---- a/Documentation/internals/mailing-lists.rst -+++ b/Documentation/internals/mailing-lists.rst -@@ -93,4 +93,4 @@ security - The `security`__ mailing list is for submitting security vulnerabilities to the - security team. - --__ security@ovs.org -+__ security@openvswitch.org --- -2.14.1 - - diff --git a/Prepare-for-2.12.1.patch b/Prepare-for-2.12.1.patch deleted file mode 100644 index 39b8263b821a6c5b0d8baf8bb9e28c81745a9a40..0000000000000000000000000000000000000000 --- a/Prepare-for-2.12.1.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 014a2b02bb5f7e3030a57f6a7bd0e03b4a5823aa Mon Sep 17 00:00:00 2001 -From: Justin Pettit -Date: Tue, 3 Sep 2019 14:57:37 -0700 -Subject: Prepare for 2.12.1. - -Signed-off-by: Justin Pettit -Acked-by: Flavio Leitner ---- - NEWS | 3 +++ - configure.ac | 2 +- - debian/changelog | 6 ++++++ - 3 files changed, 10 insertions(+), 1 deletion(-) - -diff --git a/NEWS b/NEWS -index 474d1f3c4..c81890b7e 100644 ---- a/NEWS -+++ b/NEWS -@@ -1,3 +1,6 @@ -+v2.12.1 - xx xxx xxxx -+--------------------- -+ - v2.12.0 - 03 Sep 2019 - --------------------- - - DPDK: -diff --git a/configure.ac b/configure.ac -index 5fee8e9eb..a4322176c 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -13,7 +13,7 @@ - # limitations under the License. - - AC_PREREQ(2.63) --AC_INIT(openvswitch, 2.12.0, bugs@openvswitch.org) -+AC_INIT(openvswitch, 2.12.1, bugs@openvswitch.org) - AC_CONFIG_SRCDIR([datapath/datapath.c]) - AC_CONFIG_MACRO_DIR([m4]) - AC_CONFIG_AUX_DIR([build-aux]) -diff --git a/debian/changelog b/debian/changelog -index b6d0568ef..bb9ea31a0 100644 ---- a/debian/changelog -+++ b/debian/changelog -@@ -1,3 +1,9 @@ -+openvswitch (2.12.1-1) unstable; urgency=low -+ [ Open vSwitch team ] -+ * New upstream version -+ -+ -- Open vSwitch team Tue, 03 Sep 2019 14:57:37 -0700 -+ - openvswitch (2.12.0-1) unstable; urgency=low - [ Open vSwitch team ] - * New upstream version --- -2.14.1 - - diff --git a/cirrus-Use-FreeBSD-12.1-stable-release.patch b/cirrus-Use-FreeBSD-12.1-stable-release.patch deleted file mode 100644 index df286ab80a9052111e319298460990eb36729686..0000000000000000000000000000000000000000 --- a/cirrus-Use-FreeBSD-12.1-stable-release.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 303b3ab0a81270f7bbd258086a8b61e2cefb5dbb Mon Sep 17 00:00:00 2001 -From: Ilya Maximets -Date: Fri, 13 Dec 2019 13:52:10 +0100 -Subject: cirrus: Use FreeBSD 12.1 stable release. - -freebsd-12-0-snap image family suddenly removed from the gCloud, -so can not be used anymore. Updating to more recent 12.1 releases. - -Signed-off-by: Ilya Maximets -Acked-by: Ben Pfaff ---- - .cirrus.yml | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/.cirrus.yml b/.cirrus.yml -index aaa5e3eeb..48ad3e3c2 100644 ---- a/.cirrus.yml -+++ b/.cirrus.yml -@@ -2,7 +2,7 @@ freebsd_build_task: - - freebsd_instance: - matrix: -- image_family: freebsd-12-0-snap -+ image_family: freebsd-12-1-snap - image_family: freebsd-11-3-snap - cpu: 4 - memory: 8G --- -2.14.1 - - diff --git a/cirrus-Use-latest-stable-FreeBSD-images.patch b/cirrus-Use-latest-stable-FreeBSD-images.patch deleted file mode 100644 index 95bb7f4da9895c496123f02e5fcf86812ecd64b9..0000000000000000000000000000000000000000 --- a/cirrus-Use-latest-stable-FreeBSD-images.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 25a8cb21251d4c45164a03be78d0730590f03ca5 Mon Sep 17 00:00:00 2001 -From: Ilya Maximets -Date: Tue, 1 Oct 2019 14:28:45 +0300 -Subject: cirrus: Use latest stable FreeBSD images. - -CirrusCI recently introduced [1] new feature to use image families -instead of bare image names for gCloud based instances. -This allows us to use most recent stable builds. All the stable builds -are in the same image family in gCloud and it will run instances using -the most recent one. -This also allows us to simply use 11.3 image instead of 11.2. There -was no such ability previously, because base freebsd-11-3-release-amd64 -image has issues[2] that doesn't allow CirrusCI to use it. However, -later stable 11.3 images from freebsd-11-3-snap family works fine. - -[1] https://github.com/cirruslabs/cirrus-ci-docs/issues/422 -[2] https://github.com/cirruslabs/cirrus-ci-docs/issues/359 - -Signed-off-by: Ilya Maximets -Acked-by: Aaron Conole ---- - .cirrus.yml | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/.cirrus.yml b/.cirrus.yml -index eb6af0a71..aaa5e3eeb 100644 ---- a/.cirrus.yml -+++ b/.cirrus.yml -@@ -2,8 +2,8 @@ freebsd_build_task: - - freebsd_instance: - matrix: -- image: freebsd-12-0-release-amd64 -- image: freebsd-11-2-release-amd64 -+ image_family: freebsd-12-0-snap -+ image_family: freebsd-11-3-snap - cpu: 4 - memory: 8G - --- -2.14.1 - - diff --git a/compat-Add-compat-fix-for-old-kernels.patch b/compat-Add-compat-fix-for-old-kernels.patch deleted file mode 100644 index 3733b5b367a4aebb6d1f03574668d7adc961bb0f..0000000000000000000000000000000000000000 --- a/compat-Add-compat-fix-for-old-kernels.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 3000160ef611af0851014212357e9bfe057dae03 Mon Sep 17 00:00:00 2001 -From: Roi Dayan -Date: Wed, 6 Nov 2019 09:34:46 +0200 -Subject: compat: Add compat fix for old kernels - -In kernels older than 4.8, struct tcf_t didn't have the firstuse. -If openvswitch is compiled with the compat pkt_cls.h then there is -a struct size mismatch between openvswitch and the kernel which cause -parsing netlink actions to fail. -After this commit parsing the netlink actions pass even if compiled with -the compat pkt_cls.h. - -Signed-off-by: Roi Dayan -Signed-off-by: Simon Horman ---- - acinclude.m4 | 2 ++ - include/linux/pkt_cls.h | 2 ++ - 2 files changed, 4 insertions(+) - -diff --git a/acinclude.m4 b/acinclude.m4 -index fcb45c647..a581e1ef2 100644 ---- a/acinclude.m4 -+++ b/acinclude.m4 -@@ -185,6 +185,8 @@ AC_DEFUN([OVS_CHECK_LINUX_TC], [ - [AC_DEFINE([HAVE_TCA_FLOWER_KEY_ENC_IP_TTL_MASK], [1], - [Define to 1 if TCA_FLOWER_KEY_ENC_IP_TTL_MASK is available.])]) - -+ AC_CHECK_MEMBERS([struct tcf_t.firstuse], [], [], [#include ]) -+ - AC_COMPILE_IFELSE([ - AC_LANG_PROGRAM([#include ], [ - int x = TCA_VLAN_PUSH_VLAN_PRIORITY; -diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h -index 4adea59e7..2f7e328c4 100644 ---- a/include/linux/pkt_cls.h -+++ b/include/linux/pkt_cls.h -@@ -64,7 +64,9 @@ struct tcf_t { - __u64 install; - __u64 lastuse; - __u64 expires; -+#ifdef HAVE_STRUCT_TCF_T_FIRSTUSE - __u64 firstuse; -+#endif - }; - - #define tc_gen \ --- -2.14.1 - - diff --git a/conntrack-Fix-check_orig_tuple-Valgrind-false-positi.patch b/conntrack-Fix-check_orig_tuple-Valgrind-false-positi.patch deleted file mode 100644 index 7980b0ad13f3631207c224c9cdea334660131420..0000000000000000000000000000000000000000 --- a/conntrack-Fix-check_orig_tuple-Valgrind-false-positi.patch +++ /dev/null @@ -1,55 +0,0 @@ -From cc213ea8956059adadf378ca454678f3d2055e04 Mon Sep 17 00:00:00 2001 -From: Darrell Ball -Date: Mon, 23 Sep 2019 16:44:33 -0700 -Subject: conntrack: Fix 'check_orig_tuple()' Valgrind false positive. - -Valgrind reported that 'pkt->md.ct_orig_tuple.ipv4.ipv4_proto' is -uninitialized in 'check_orig_tuple()', if 'ct_state' is zero. Although -this is true, the check is superceded, as even if it succeeds the check -for natted packets based on 'ct_state' is an ORed condition and is intended -to catch this case. -The check is '!(pkt->md.ct_state & (CS_SRC_NAT | CS_DST_NAT))' which -filters out all packets excepted natted ones. Move this check up to -prevent the Valgrind complaint, which also helps performance and also remove -recenlty added redundant check adding extra cycles. - -Fixes: f44733c527da ("conntrack: Validate accessing of conntrack data in pkt_metadata.") -CC: Yifeng Sun -Signed-off-by: Darrell Ball -Signed-off-by: Ben Pfaff ---- - lib/conntrack.c | 7 +++---- - 1 file changed, 3 insertions(+), 4 deletions(-) - -diff --git a/lib/conntrack.c b/lib/conntrack.c -index 86c16b2fb..0c917543c 100644 ---- a/lib/conntrack.c -+++ b/lib/conntrack.c -@@ -1001,11 +1001,11 @@ check_orig_tuple(struct conntrack *ct, struct dp_packet *pkt, - struct conn **conn, - const struct nat_action_info_t *nat_action_info) - { -- if ((ctx_in->key.dl_type == htons(ETH_TYPE_IP) && -+ if (!(pkt->md.ct_state & (CS_SRC_NAT | CS_DST_NAT)) || -+ (ctx_in->key.dl_type == htons(ETH_TYPE_IP) && - !pkt->md.ct_orig_tuple.ipv4.ipv4_proto) || - (ctx_in->key.dl_type == htons(ETH_TYPE_IPV6) && - !pkt->md.ct_orig_tuple.ipv6.ipv6_proto) || -- !(pkt->md.ct_state & (CS_SRC_NAT | CS_DST_NAT)) || - nat_action_info) { - return false; - } -@@ -1138,8 +1138,7 @@ process_one(struct conntrack *ct, struct dp_packet *pkt, - handle_nat(pkt, conn, zone, ctx->reply, ctx->icmp_related); - } - -- } else if (pkt->md.ct_state -- && check_orig_tuple(ct, pkt, ctx, now, &conn, nat_action_info)) { -+ } else if (check_orig_tuple(ct, pkt, ctx, now, &conn, nat_action_info)) { - create_new_conn = conn_update_state(ct, pkt, ctx, conn, now); - } else { - if (ctx->icmp_related) { --- -2.14.1 - - diff --git a/conntrack-Fix-reverse_nat_packet-variable-datatype.patch b/conntrack-Fix-reverse_nat_packet-variable-datatype.patch deleted file mode 100644 index ee2fd5fc83bc4b16096a5b151aa385824107d170..0000000000000000000000000000000000000000 --- a/conntrack-Fix-reverse_nat_packet-variable-datatype.patch +++ /dev/null @@ -1,53 +0,0 @@ -From e6aebc90210baa35d252486d998074e2365a4b26 Mon Sep 17 00:00:00 2001 -From: Darrell Ball -Date: Fri, 30 Aug 2019 09:13:19 -0700 -Subject: conntrack: Fix 'reverse_nat_packet()' variable datatype. - -The datatype 'pad' in the function 'reverse_nat_packet()' was incorrectly -declared as 'char' instead of 'uint8_t'. This can affect reverse natting -of icmpX packets with padding > 127 bytes. At the same time, add some -comments regarding 'extract_l3_ipvX' usage in this function. Found by -inspection. - -Fixes: edd1bef468c0 ("dpdk: Add more ICMP Related NAT support.") -Signed-off-by: Darrell Ball -Signed-off-by: Ben Pfaff ---- - lib/conntrack.c | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/lib/conntrack.c b/lib/conntrack.c -index 0c917543c..b56ef06ac 100644 ---- a/lib/conntrack.c -+++ b/lib/conntrack.c -@@ -688,7 +688,7 @@ static void - reverse_nat_packet(struct dp_packet *pkt, const struct conn *conn) - { - char *tail = dp_packet_tail(pkt); -- char pad = dp_packet_l2_pad_size(pkt); -+ uint8_t pad = dp_packet_l2_pad_size(pkt); - struct conn_key inner_key; - const char *inner_l4 = NULL; - uint16_t orig_l3_ofs = pkt->l3_ofs; -@@ -698,6 +698,8 @@ reverse_nat_packet(struct dp_packet *pkt, const struct conn *conn) - struct ip_header *nh = dp_packet_l3(pkt); - struct icmp_header *icmp = dp_packet_l4(pkt); - struct ip_header *inner_l3 = (struct ip_header *) (icmp + 1); -+ /* This call is already verified to succeed during the code path from -+ * 'conn_key_extract()' which calls 'extract_l4_icmp()'. */ - extract_l3_ipv4(&inner_key, inner_l3, tail - ((char *)inner_l3) - pad, - &inner_l4, false); - pkt->l3_ofs += (char *) inner_l3 - (char *) nh; -@@ -719,6 +721,8 @@ reverse_nat_packet(struct dp_packet *pkt, const struct conn *conn) - struct icmp6_error_header *icmp6 = dp_packet_l4(pkt); - struct ovs_16aligned_ip6_hdr *inner_l3_6 = - (struct ovs_16aligned_ip6_hdr *) (icmp6 + 1); -+ /* This call is already verified to succeed during the code path from -+ * 'conn_key_extract()' which calls 'extract_l4_icmp6()'. */ - extract_l3_ipv6(&inner_key, inner_l3_6, - tail - ((char *)inner_l3_6) - pad, - &inner_l4); --- -2.14.1 - - diff --git a/conntrack-Validate-accessing-of-conntrack-data-in-pk.patch b/conntrack-Validate-accessing-of-conntrack-data-in-pk.patch deleted file mode 100644 index 34007e659f26a7934ea76f599237e50065a22528..0000000000000000000000000000000000000000 --- a/conntrack-Validate-accessing-of-conntrack-data-in-pk.patch +++ /dev/null @@ -1,102 +0,0 @@ -From e3b0c19781969c913936904aa2689ceae25f9424 Mon Sep 17 00:00:00 2001 -From: Yifeng Sun -Date: Wed, 11 Sep 2019 14:18:36 -0700 -Subject: conntrack: Validate accessing of conntrack data in pkt_metadata - -Valgrind reported: - -1305: ofproto-dpif - conntrack - ipv6 - -==26942== Conditional jump or move depends on uninitialised value(s) -==26942== at 0x587C00: check_orig_tuple (conntrack.c:1006) -==26942== by 0x587C00: process_one (conntrack.c:1141) -==26942== by 0x587C00: conntrack_execute (conntrack.c:1220) -==26942== by 0x47B00F: dp_execute_cb (dpif-netdev.c:7305) -==26942== by 0x4AF756: odp_execute_actions (odp-execute.c:794) -==26942== by 0x477532: dp_netdev_execute_actions (dpif-netdev.c:7349) -==26942== by 0x477532: handle_packet_upcall (dpif-netdev.c:6630) -==26942== by 0x477532: fast_path_processing (dpif-netdev.c:6726) -==26942== by 0x47933C: dp_netdev_input__ (dpif-netdev.c:6814) -==26942== by 0x479AB8: dp_netdev_input (dpif-netdev.c:6852) -==26942== by 0x479AB8: dp_netdev_process_rxq_port (dpif-netdev.c:4287) -==26942== by 0x47A6A9: dpif_netdev_run (dpif-netdev.c:5264) -==26942== by 0x4324E7: type_run (ofproto-dpif.c:342) -==26942== by 0x41C5FE: ofproto_type_run (ofproto.c:1734) -==26942== by 0x40BAAC: bridge_run__ (bridge.c:2965) -==26942== by 0x410CF3: bridge_run (bridge.c:3029) -==26942== by 0x407614: main (ovs-vswitchd.c:127) -==26942== Uninitialised value was created by a heap allocation -==26942== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) -==26942== by 0x532574: xmalloc (util.c:138) -==26942== by 0x46CD62: dp_packet_new (dp-packet.c:153) -==26942== by 0x4A0431: eth_from_flow_str (netdev-dummy.c:1644) -==26942== by 0x4A0431: netdev_dummy_receive (netdev-dummy.c:1783) -==26942== by 0x531990: process_command (unixctl.c:308) -==26942== by 0x531990: run_connection (unixctl.c:342) -==26942== by 0x531990: unixctl_server_run (unixctl.c:393) -==26942== by 0x40761E: main (ovs-vswitchd.c:128) - -1316: ofproto-dpif - conntrack - tcp port reuse - -==24039== Conditional jump or move depends on uninitialised value(s) -==24039== at 0x587BF5: check_orig_tuple (conntrack.c:1004) -==24039== by 0x587BF5: process_one (conntrack.c:1141) -==24039== by 0x587BF5: conntrack_execute (conntrack.c:1220) -==24039== by 0x47B02F: dp_execute_cb (dpif-netdev.c:7306) -==24039== by 0x4AF7A6: odp_execute_actions (odp-execute.c:794) -==24039== by 0x47755B: dp_netdev_execute_actions (dpif-netdev.c:7350) -==24039== by 0x47755B: handle_packet_upcall (dpif-netdev.c:6631) -==24039== by 0x47755B: fast_path_processing (dpif-netdev.c:6727) -==24039== by 0x47935C: dp_netdev_input__ (dpif-netdev.c:6815) -==24039== by 0x479AD8: dp_netdev_input (dpif-netdev.c:6853) -==24039== by 0x479AD8: dp_netdev_process_rxq_port -(dpif-netdev.c:4287) -==24039== by 0x47A6C9: dpif_netdev_run (dpif-netdev.c:5264) -==24039== by 0x4324F7: type_run (ofproto-dpif.c:342) -==24039== by 0x41C5FE: ofproto_type_run (ofproto.c:1734) -==24039== by 0x40BAAC: bridge_run__ (bridge.c:2965) -==24039== by 0x410CF3: bridge_run (bridge.c:3029) -==24039== by 0x407614: main (ovs-vswitchd.c:127) -==24039== Uninitialised value was created by a heap allocation -==24039== at 0x4C2DB8F: malloc (in -/usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) -==24039== by 0x5325C4: xmalloc (util.c:138) -==24039== by 0x46D144: dp_packet_new (dp-packet.c:153) -==24039== by 0x46D144: dp_packet_new_with_headroom (dp-packet.c:163) -==24039== by 0x51191E: eth_from_hex (packets.c:498) -==24039== by 0x4A03B9: eth_from_packet (netdev-dummy.c:1609) -==24039== by 0x4A03B9: netdev_dummy_receive (netdev-dummy.c:1765) -==24039== by 0x5319E0: process_command (unixctl.c:308) -==24039== by 0x5319E0: run_connection (unixctl.c:342) -==24039== by 0x5319E0: unixctl_server_run (unixctl.c:393) -==24039== by 0x40761E: main (ovs-vswitchd.c:128) - -According to comments in pkt_metadata_init(), conntrack data is valid -only if pkt_metadata.ct_state != 0. This patch prevents -check_orig_tuple() get called when conntrack data is uninitialized. - -Acked-by: William Tu -Signed-off-by: Yifeng Sun -Signed-off-by: Ben Pfaff ---- - lib/conntrack.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/lib/conntrack.c b/lib/conntrack.c -index e5266e579..86c16b2fb 100644 ---- a/lib/conntrack.c -+++ b/lib/conntrack.c -@@ -1138,7 +1138,8 @@ process_one(struct conntrack *ct, struct dp_packet *pkt, - handle_nat(pkt, conn, zone, ctx->reply, ctx->icmp_related); - } - -- } else if (check_orig_tuple(ct, pkt, ctx, now, &conn, nat_action_info)) { -+ } else if (pkt->md.ct_state -+ && check_orig_tuple(ct, pkt, ctx, now, &conn, nat_action_info)) { - create_new_conn = conn_update_state(ct, pkt, ctx, conn, now); - } else { - if (ctx->icmp_related) { --- -2.14.1 - - diff --git a/datapath-compat-Backports-bugfixes-for-nf_conncount.patch b/datapath-compat-Backports-bugfixes-for-nf_conncount.patch deleted file mode 100644 index 8cb2aadea0c21548c95faca359179607d6fd8dea..0000000000000000000000000000000000000000 --- a/datapath-compat-Backports-bugfixes-for-nf_conncount.patch +++ /dev/null @@ -1,682 +0,0 @@ -From 74eab93900625f22152b537c0c50a3c925152728 Mon Sep 17 00:00:00 2001 -From: Yifeng Sun -Date: Wed, 7 Aug 2019 15:25:33 -0700 -Subject: datapath: compat: Backports bugfixes for nf_conncount - -This patch backports several critical bug fixes related to -locking and data consistency in nf_conncount code. - -This backport is based on the following upstream net-next upstream commits. -a007232 ("netfilter: nf_conncount: fix argument order to find_next_bit") -c80f10b ("netfilter: nf_conncount: speculative garbage collection on empty lists") -2f971a8 ("netfilter: nf_conncount: move all list iterations under spinlock") -df4a902 ("netfilter: nf_conncount: merge lookup and add functions") -e8cfb37 ("netfilter: nf_conncount: restart search when nodes have been erased") -f7fcc98 ("netfilter: nf_conncount: split gc in two phases") -4cd273b ("netfilter: nf_conncount: don't skip eviction when age is negative") -c78e781 ("netfilter: nf_conncount: replace CONNCOUNT_LOCK_SLOTS with CONNCOUNT_SLOTS") -d4e7df1 ("netfilter: nf_conncount: use rb_link_node_rcu() instead of rb_link_node()") -53ca0f2 ("netfilter: nf_conncount: remove wrong condition check routine") -3c5cdb1 ("netfilter: nf_conncount: fix unexpected permanent node of list.") -31568ec ("netfilter: nf_conncount: fix list_del corruption in conn_free") -fd3e71a ("netfilter: nf_conncount: use spin_lock_bh instead of spin_lock") - -This patch adds additional compat code so that it can build on -all supported kernel versions. - -In addition, this patch helps OVS datapath to always choose bug-fixed -nf_conncount code. If kernel already has these fixes, then kernel's -nf_conncount is being used. Otherwise, OVS falls back to use compat -nf_conncount functions. - -Travis tests are at -https://travis-ci.org/yifsun/ovs-travis/builds/569056850 -On latest RHEL kernel, 'make check-kmod' runs good. - -VMware-BZ: #2396471 - -Signed-off-by: Yifeng Sun -Signed-off-by: Ben Pfaff ---- - acinclude.m4 | 6 +- - datapath/linux/Modules.mk | 3 +- - datapath/linux/compat/include/linux/rbtree.h | 19 ++ - .../include/net/netfilter/nf_conntrack_count.h | 7 - - datapath/linux/compat/nf_conncount.c | 290 ++++++++++----------- - 5 files changed, 161 insertions(+), 164 deletions(-) - create mode 100644 datapath/linux/compat/include/linux/rbtree.h - -diff --git a/acinclude.m4 b/acinclude.m4 -index 9e1569b07..fcb45c647 100644 ---- a/acinclude.m4 -+++ b/acinclude.m4 -@@ -706,7 +706,9 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [ - OVS_GREP_IFELSE([$KSRC/include/net/netfilter/nf_nat.h], [nf_nat_range2]) - OVS_GREP_IFELSE([$KSRC/include/net/netfilter/nf_conntrack_seqadj.h], [nf_ct_seq_adjust]) - OVS_GREP_IFELSE([$KSRC/include/net/netfilter/nf_conntrack_count.h], [nf_conncount_gc_list], -- [OVS_DEFINE([HAVE_UPSTREAM_NF_CONNCOUNT])]) -+ [OVS_GREP_IFELSE([$KSRC/include/net/netfilter/nf_conntrack_count.h], -+ [int nf_conncount_add], -+ [], [OVS_DEFINE([HAVE_UPSTREAM_NF_CONNCOUNT])])]) - - OVS_GREP_IFELSE([$KSRC/include/linux/random.h], [prandom_u32]) - OVS_GREP_IFELSE([$KSRC/include/linux/random.h], [prandom_u32_max]) -@@ -1005,6 +1007,8 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [ - [OVS_DEFINE([HAVE_GRE_CALC_HLEN])]) - OVS_GREP_IFELSE([$KSRC/include/net/gre.h], [ip_gre_calc_hlen], - [OVS_DEFINE([HAVE_IP_GRE_CALC_HLEN])]) -+ OVS_GREP_IFELSE([$KSRC/include/linux/rbtree.h], [rb_link_node_rcu], -+ [OVS_DEFINE([HAVE_RBTREE_RB_LINK_NODE_RCU])]) - - if cmp -s datapath/linux/kcompat.h.new \ - datapath/linux/kcompat.h >/dev/null 2>&1; then -diff --git a/datapath/linux/Modules.mk b/datapath/linux/Modules.mk -index cbb29f1c6..69d7faeac 100644 ---- a/datapath/linux/Modules.mk -+++ b/datapath/linux/Modules.mk -@@ -116,5 +116,6 @@ openvswitch_headers += \ - linux/compat/include/uapi/linux/netfilter.h \ - linux/compat/include/linux/mm.h \ - linux/compat/include/linux/netfilter.h \ -- linux/compat/include/linux/overflow.h -+ linux/compat/include/linux/overflow.h \ -+ linux/compat/include/linux/rbtree.h - EXTRA_DIST += linux/compat/build-aux/export-check-whitelist -diff --git a/datapath/linux/compat/include/linux/rbtree.h b/datapath/linux/compat/include/linux/rbtree.h -new file mode 100644 -index 000000000..dbf20ff0e ---- /dev/null -+++ b/datapath/linux/compat/include/linux/rbtree.h -@@ -0,0 +1,19 @@ -+#ifndef __LINUX_RBTREE_WRAPPER_H -+#define __LINUX_RBTREE_WRAPPER_H 1 -+ -+#include_next -+ -+#ifndef HAVE_RBTREE_RB_LINK_NODE_RCU -+#include -+ -+static inline void rb_link_node_rcu(struct rb_node *node, struct rb_node *parent, -+ struct rb_node **rb_link) -+{ -+ node->__rb_parent_color = (unsigned long)parent; -+ node->rb_left = node->rb_right = NULL; -+ -+ rcu_assign_pointer(*rb_link, node); -+} -+#endif -+ -+#endif /* __LINUX_RBTREE_WRAPPER_H */ -diff --git a/datapath/linux/compat/include/net/netfilter/nf_conntrack_count.h b/datapath/linux/compat/include/net/netfilter/nf_conntrack_count.h -index 614017309..2143136aa 100644 ---- a/datapath/linux/compat/include/net/netfilter/nf_conntrack_count.h -+++ b/datapath/linux/compat/include/net/netfilter/nf_conntrack_count.h -@@ -21,17 +21,10 @@ static inline void rpl_nf_conncount_modexit(void) - #define CONFIG_NETFILTER_CONNCOUNT 1 - struct nf_conncount_data; - --enum nf_conncount_list_add { -- NF_CONNCOUNT_ADDED, /* list add was ok */ -- NF_CONNCOUNT_ERR, /* -ENOMEM, must drop skb */ -- NF_CONNCOUNT_SKIP, /* list is already reclaimed by gc */ --}; -- - struct nf_conncount_list { - spinlock_t list_lock; - struct list_head head; /* connections with the same filtering key */ - unsigned int count; /* length of list */ -- bool dead; - }; - - struct nf_conncount_data -diff --git a/datapath/linux/compat/nf_conncount.c b/datapath/linux/compat/nf_conncount.c -index eeae440f8..97bdfb933 100644 ---- a/datapath/linux/compat/nf_conncount.c -+++ b/datapath/linux/compat/nf_conncount.c -@@ -38,12 +38,6 @@ - - #define CONNCOUNT_SLOTS 256U - --#ifdef CONFIG_LOCKDEP --#define CONNCOUNT_LOCK_SLOTS 8U --#else --#define CONNCOUNT_LOCK_SLOTS 256U --#endif -- - #define CONNCOUNT_GC_MAX_NODES 8 - #define MAX_KEYLEN 5 - -@@ -54,7 +48,6 @@ struct nf_conncount_tuple { - struct nf_conntrack_zone zone; - int cpu; - u32 jiffies32; -- struct rcu_head rcu_head; - }; - - struct nf_conncount_rb { -@@ -64,7 +57,7 @@ struct nf_conncount_rb { - struct rcu_head rcu_head; - }; - --static spinlock_t nf_conncount_locks[CONNCOUNT_LOCK_SLOTS] __cacheline_aligned_in_smp; -+static spinlock_t nf_conncount_locks[CONNCOUNT_SLOTS] __cacheline_aligned_in_smp; - - struct nf_conncount_data { - unsigned int keylen; -@@ -93,74 +86,25 @@ static int key_diff(const u32 *a, const u32 *b, unsigned int klen) - return memcmp(a, b, klen * sizeof(u32)); - } - --static enum nf_conncount_list_add --nf_conncount_add(struct nf_conncount_list *list, -- const struct nf_conntrack_tuple *tuple, -- const struct nf_conntrack_zone *zone) --{ -- struct nf_conncount_tuple *conn; -- -- if (WARN_ON_ONCE(list->count > INT_MAX)) -- return NF_CONNCOUNT_ERR; -- -- conn = kmem_cache_alloc(conncount_conn_cachep, GFP_ATOMIC); -- if (conn == NULL) -- return NF_CONNCOUNT_ERR; -- -- conn->tuple = *tuple; -- conn->zone = *zone; -- conn->cpu = raw_smp_processor_id(); -- conn->jiffies32 = (u32)jiffies; -- spin_lock(&list->list_lock); -- if (list->dead == true) { -- kmem_cache_free(conncount_conn_cachep, conn); -- spin_unlock(&list->list_lock); -- return NF_CONNCOUNT_SKIP; -- } -- list_add_tail(&conn->node, &list->head); -- list->count++; -- spin_unlock(&list->list_lock); -- return NF_CONNCOUNT_ADDED; --} -- --static void __conn_free(struct rcu_head *h) --{ -- struct nf_conncount_tuple *conn; -- -- conn = container_of(h, struct nf_conncount_tuple, rcu_head); -- kmem_cache_free(conncount_conn_cachep, conn); --} -- --static bool conn_free(struct nf_conncount_list *list, -+static void conn_free(struct nf_conncount_list *list, - struct nf_conncount_tuple *conn) - { -- bool free_entry = false; -- -- spin_lock(&list->list_lock); -- -- if (list->count == 0) { -- spin_unlock(&list->list_lock); -- return free_entry; -- } -+ lockdep_assert_held(&list->list_lock); - - list->count--; -- list_del_rcu(&conn->node); -- if (list->count == 0) -- free_entry = true; -+ list_del(&conn->node); - -- spin_unlock(&list->list_lock); -- call_rcu(&conn->rcu_head, __conn_free); -- return free_entry; -+ kmem_cache_free(conncount_conn_cachep, conn); - } - - static const struct nf_conntrack_tuple_hash * - find_or_evict(struct net *net, struct nf_conncount_list *list, -- struct nf_conncount_tuple *conn, bool *free_entry) -+ struct nf_conncount_tuple *conn) - { - const struct nf_conntrack_tuple_hash *found; - unsigned long a, b; - int cpu = raw_smp_processor_id(); -- __s32 age; -+ u32 age; - - found = nf_conntrack_find_get(net, &conn->zone, &conn->tuple); - if (found) -@@ -175,52 +119,45 @@ find_or_evict(struct net *net, struct nf_conncount_list *list, - */ - age = a - b; - if (conn->cpu == cpu || age >= 2) { -- *free_entry = conn_free(list, conn); -+ conn_free(list, conn); - return ERR_PTR(-ENOENT); - } - - return ERR_PTR(-EAGAIN); - } - --static void nf_conncount_lookup(struct net *net, -- struct nf_conncount_list *list, -- const struct nf_conntrack_tuple *tuple, -- const struct nf_conntrack_zone *zone, -- bool *addit) -+static int __nf_conncount_add(struct net *net, -+ struct nf_conncount_list *list, -+ const struct nf_conntrack_tuple *tuple, -+ const struct nf_conntrack_zone *zone) - { - const struct nf_conntrack_tuple_hash *found; - struct nf_conncount_tuple *conn, *conn_n; - struct nf_conn *found_ct; - unsigned int collect = 0; -- bool free_entry = false; -- -- /* best effort only */ -- *addit = tuple ? true : false; - - /* check the saved connections */ - list_for_each_entry_safe(conn, conn_n, &list->head, node) { - if (collect > CONNCOUNT_GC_MAX_NODES) - break; - -- found = find_or_evict(net, list, conn, &free_entry); -+ found = find_or_evict(net, list, conn); - if (IS_ERR(found)) { - /* Not found, but might be about to be confirmed */ - if (PTR_ERR(found) == -EAGAIN) { -- if (!tuple) -- continue; -- - if (nf_ct_tuple_equal(&conn->tuple, tuple) && - nf_ct_zone_id(&conn->zone, conn->zone.dir) == - nf_ct_zone_id(zone, zone->dir)) -- *addit = false; -- } else if (PTR_ERR(found) == -ENOENT) -+ return 0; /* already exists */ -+ } else { - collect++; -+ } - continue; - } - - found_ct = nf_ct_tuplehash_to_ctrack(found); - -- if (tuple && nf_ct_tuple_equal(&conn->tuple, tuple) && -+ if (nf_ct_tuple_equal(&conn->tuple, tuple) && - nf_ct_zone_equal(found_ct, zone, zone->dir)) { - /* - * We should not see tuples twice unless someone hooks -@@ -228,7 +165,8 @@ static void nf_conncount_lookup(struct net *net, - * - * Attempt to avoid a re-add in this case. - */ -- *addit = false; -+ nf_ct_put(found_ct); -+ return 0; - } else if (already_closed(found_ct)) { - /* - * we do not care about connections which are -@@ -242,34 +180,64 @@ static void nf_conncount_lookup(struct net *net, - - nf_ct_put(found_ct); - } -+ -+ if (WARN_ON_ONCE(list->count > INT_MAX)) -+ return -EOVERFLOW; -+ -+ conn = kmem_cache_alloc(conncount_conn_cachep, GFP_ATOMIC); -+ if (conn == NULL) -+ return -ENOMEM; -+ -+ conn->tuple = *tuple; -+ conn->zone = *zone; -+ conn->cpu = raw_smp_processor_id(); -+ conn->jiffies32 = (u32)jiffies; -+ list_add_tail(&conn->node, &list->head); -+ list->count++; -+ return 0; -+} -+ -+int nf_conncount_add(struct net *net, -+ struct nf_conncount_list *list, -+ const struct nf_conntrack_tuple *tuple, -+ const struct nf_conntrack_zone *zone) -+{ -+ int ret; -+ -+ /* check the saved connections */ -+ spin_lock_bh(&list->list_lock); -+ ret = __nf_conncount_add(net, list, tuple, zone); -+ spin_unlock_bh(&list->list_lock); -+ -+ return ret; - } - - static void nf_conncount_list_init(struct nf_conncount_list *list) - { - spin_lock_init(&list->list_lock); - INIT_LIST_HEAD(&list->head); -- list->count = 1; -- list->dead = false; -+ list->count = 0; - } - --/* Return true if the list is empty */ -+/* Return true if the list is empty. Must be called with BH disabled. */ - static bool nf_conncount_gc_list(struct net *net, -- struct nf_conncount_list *list) -+ struct nf_conncount_list *list) - { - const struct nf_conntrack_tuple_hash *found; - struct nf_conncount_tuple *conn, *conn_n; - struct nf_conn *found_ct; - unsigned int collected = 0; -- bool free_entry = false; -+ bool ret = false; -+ -+ /* don't bother if other cpu is already doing GC */ -+ if (!spin_trylock(&list->list_lock)) -+ return false; - - list_for_each_entry_safe(conn, conn_n, &list->head, node) { -- found = find_or_evict(net, list, conn, &free_entry); -+ found = find_or_evict(net, list, conn); - if (IS_ERR(found)) { -- if (PTR_ERR(found) == -ENOENT) { -- if (free_entry) -- return true; -+ if (PTR_ERR(found) == -ENOENT) - collected++; -- } - continue; - } - -@@ -280,17 +248,21 @@ static bool nf_conncount_gc_list(struct net *net, - * closed already -> ditch it - */ - nf_ct_put(found_ct); -- if (conn_free(list, conn)) -- return true; -+ conn_free(list, conn); - collected++; - continue; - } - - nf_ct_put(found_ct); - if (collected > CONNCOUNT_GC_MAX_NODES) -- return false; -+ break; - } -- return false; -+ -+ if (!list->count) -+ ret = true; -+ spin_unlock(&list->list_lock); -+ -+ return ret; - } - - static void __tree_nodes_free(struct rcu_head *h) -@@ -301,6 +273,7 @@ static void __tree_nodes_free(struct rcu_head *h) - kmem_cache_free(conncount_rb_cachep, rbconn); - } - -+/* caller must hold tree nf_conncount_locks[] lock */ - static void tree_nodes_free(struct rb_root *root, - struct nf_conncount_rb *gc_nodes[], - unsigned int gc_count) -@@ -310,8 +283,7 @@ static void tree_nodes_free(struct rb_root *root, - while (gc_count) { - rbconn = gc_nodes[--gc_count]; - spin_lock(&rbconn->list.list_lock); -- if (rbconn->list.count == 0 && rbconn->list.dead == false) { -- rbconn->list.dead = true; -+ if (!rbconn->list.count) { - rb_erase(&rbconn->node, root); - call_rcu(&rbconn->rcu_head, __tree_nodes_free); - } -@@ -331,20 +303,19 @@ insert_tree(struct net *net, - struct rb_root *root, - unsigned int hash, - const u32 *key, -- u8 keylen, - const struct nf_conntrack_tuple *tuple, - const struct nf_conntrack_zone *zone) - { -- enum nf_conncount_list_add ret; - struct nf_conncount_rb *gc_nodes[CONNCOUNT_GC_MAX_NODES]; - struct rb_node **rbnode, *parent; - struct nf_conncount_rb *rbconn; - struct nf_conncount_tuple *conn; - unsigned int count = 0, gc_count = 0; -- bool node_found = false; -- -- spin_lock_bh(&nf_conncount_locks[hash % CONNCOUNT_LOCK_SLOTS]); -+ u8 keylen = data->keylen; -+ bool do_gc = true; - -+ spin_lock_bh(&nf_conncount_locks[hash]); -+restart: - parent = NULL; - rbnode = &(root->rb_node); - while (*rbnode) { -@@ -358,45 +329,32 @@ insert_tree(struct net *net, - } else if (diff > 0) { - rbnode = &((*rbnode)->rb_right); - } else { -- /* unlikely: other cpu added node already */ -- node_found = true; -- ret = nf_conncount_add(&rbconn->list, tuple, zone); -- if (ret == NF_CONNCOUNT_ERR) { -+ int ret; -+ -+ ret = nf_conncount_add(net, &rbconn->list, tuple, zone); -+ if (ret) - count = 0; /* hotdrop */ -- } else if (ret == NF_CONNCOUNT_ADDED) { -+ else - count = rbconn->list.count; -- } else { -- /* NF_CONNCOUNT_SKIP, rbconn is already -- * reclaimed by gc, insert a new tree node -- */ -- node_found = false; -- } -- break; -+ tree_nodes_free(root, gc_nodes, gc_count); -+ goto out_unlock; - } - - if (gc_count >= ARRAY_SIZE(gc_nodes)) - continue; - -- if (nf_conncount_gc_list(net, &rbconn->list)) -+ if (do_gc && nf_conncount_gc_list(net, &rbconn->list)) - gc_nodes[gc_count++] = rbconn; - } - - if (gc_count) { - tree_nodes_free(root, gc_nodes, gc_count); -- /* tree_node_free before new allocation permits -- * allocator to re-use newly free'd object. -- * -- * This is a rare event; in most cases we will find -- * existing node to re-use. (or gc_count is 0). -- */ -- -- if (gc_count >= ARRAY_SIZE(gc_nodes)) -- schedule_gc_worker(data, hash); -+ schedule_gc_worker(data, hash); -+ gc_count = 0; -+ do_gc = false; -+ goto restart; - } - -- if (node_found) -- goto out_unlock; -- - /* expected case: match, insert new node */ - rbconn = kmem_cache_alloc(conncount_rb_cachep, GFP_ATOMIC); - if (rbconn == NULL) -@@ -415,11 +373,12 @@ insert_tree(struct net *net, - nf_conncount_list_init(&rbconn->list); - list_add(&conn->node, &rbconn->list.head); - count = 1; -+ rbconn->list.count = count; - -- rb_link_node(&rbconn->node, parent, rbnode); -+ rb_link_node_rcu(&rbconn->node, parent, rbnode); - rb_insert_color(&rbconn->node, root); - out_unlock: -- spin_unlock_bh(&nf_conncount_locks[hash % CONNCOUNT_LOCK_SLOTS]); -+ spin_unlock_bh(&nf_conncount_locks[hash]); - return count; - } - -@@ -430,7 +389,6 @@ count_tree(struct net *net, - const struct nf_conntrack_tuple *tuple, - const struct nf_conntrack_zone *zone) - { -- enum nf_conncount_list_add ret; - struct rb_root *root; - struct rb_node *parent; - struct nf_conncount_rb *rbconn; -@@ -443,7 +401,6 @@ count_tree(struct net *net, - parent = rcu_dereference_raw(root->rb_node); - while (parent) { - int diff; -- bool addit; - - rbconn = rb_entry(parent, struct nf_conncount_rb, node); - -@@ -453,31 +410,36 @@ count_tree(struct net *net, - } else if (diff > 0) { - parent = rcu_dereference_raw(parent->rb_right); - } else { -- /* same source network -> be counted! */ -- nf_conncount_lookup(net, &rbconn->list, tuple, zone, -- &addit); -+ int ret; - -- if (!addit) -+ if (!tuple) { -+ nf_conncount_gc_list(net, &rbconn->list); - return rbconn->list.count; -+ } - -- ret = nf_conncount_add(&rbconn->list, tuple, zone); -- if (ret == NF_CONNCOUNT_ERR) { -- return 0; /* hotdrop */ -- } else if (ret == NF_CONNCOUNT_ADDED) { -- return rbconn->list.count; -- } else { -- /* NF_CONNCOUNT_SKIP, rbconn is already -- * reclaimed by gc, insert a new tree node -- */ -+ spin_lock_bh(&rbconn->list.list_lock); -+ /* Node might be about to be free'd. -+ * We need to defer to insert_tree() in this case. -+ */ -+ if (rbconn->list.count == 0) { -+ spin_unlock_bh(&rbconn->list.list_lock); - break; - } -+ -+ /* same source network -> be counted! */ -+ ret = __nf_conncount_add(net, &rbconn->list, tuple, zone); -+ spin_unlock_bh(&rbconn->list.list_lock); -+ if (ret) -+ return 0; /* hotdrop */ -+ else -+ return rbconn->list.count; - } - } - - if (!tuple) - return 0; - -- return insert_tree(net, data, root, hash, key, keylen, tuple, zone); -+ return insert_tree(net, data, root, hash, key, tuple, zone); - } - - static void tree_gc_worker(struct work_struct *work) -@@ -488,27 +450,48 @@ static void tree_gc_worker(struct work_struct *work) - struct rb_node *node; - unsigned int tree, next_tree, gc_count = 0; - -- tree = data->gc_tree % CONNCOUNT_LOCK_SLOTS; -+ tree = data->gc_tree % CONNCOUNT_SLOTS; - root = &data->root[tree]; - -+ local_bh_disable(); - rcu_read_lock(); - for (node = rb_first(root); node != NULL; node = rb_next(node)) { - rbconn = rb_entry(node, struct nf_conncount_rb, node); - if (nf_conncount_gc_list(data->net, &rbconn->list)) -- gc_nodes[gc_count++] = rbconn; -+ gc_count++; - } - rcu_read_unlock(); -+ local_bh_enable(); -+ -+ cond_resched(); - - spin_lock_bh(&nf_conncount_locks[tree]); -+ if (gc_count < ARRAY_SIZE(gc_nodes)) -+ goto next; /* do not bother */ - -- if (gc_count) { -- tree_nodes_free(root, gc_nodes, gc_count); -+ gc_count = 0; -+ node = rb_first(root); -+ while (node != NULL) { -+ rbconn = rb_entry(node, struct nf_conncount_rb, node); -+ node = rb_next(node); -+ -+ if (rbconn->list.count > 0) -+ continue; -+ -+ gc_nodes[gc_count++] = rbconn; -+ if (gc_count >= ARRAY_SIZE(gc_nodes)) { -+ tree_nodes_free(root, gc_nodes, gc_count); -+ gc_count = 0; -+ } - } - -+ tree_nodes_free(root, gc_nodes, gc_count); -+next: -+ - clear_bit(tree, data->pending_trees); - - next_tree = (tree + 1) % CONNCOUNT_SLOTS; -- next_tree = find_next_bit(data->pending_trees, next_tree, CONNCOUNT_SLOTS); -+ next_tree = find_next_bit(data->pending_trees, CONNCOUNT_SLOTS, next_tree); - - if (next_tree < CONNCOUNT_SLOTS) { - data->gc_tree = next_tree; -@@ -533,7 +516,7 @@ unsigned int rpl_nf_conncount_count(struct net *net, - EXPORT_SYMBOL_GPL(rpl_nf_conncount_count); - - struct nf_conncount_data *rpl_nf_conncount_init(struct net *net, unsigned int family, -- unsigned int keylen) -+ unsigned int keylen) - { - struct nf_conncount_data *data; - int ret, i; -@@ -609,10 +592,7 @@ int rpl_nf_conncount_modinit(void) - { - int i; - -- BUILD_BUG_ON(CONNCOUNT_LOCK_SLOTS > CONNCOUNT_SLOTS); -- BUILD_BUG_ON((CONNCOUNT_SLOTS % CONNCOUNT_LOCK_SLOTS) != 0); -- -- for (i = 0; i < CONNCOUNT_LOCK_SLOTS; ++i) -+ for (i = 0; i < CONNCOUNT_SLOTS; ++i) - spin_lock_init(&nf_conncount_locks[i]); - - conncount_conn_cachep = kmem_cache_create("nf_conncount_tuple", --- -2.14.1 - - diff --git a/db-ctl-base-Free-leaked-ovsdb_datum.patch b/db-ctl-base-Free-leaked-ovsdb_datum.patch deleted file mode 100644 index f60d91f15664da0ff8740c608e461d175f2161b8..0000000000000000000000000000000000000000 --- a/db-ctl-base-Free-leaked-ovsdb_datum.patch +++ /dev/null @@ -1,81 +0,0 @@ -From f4e6978ca49266448190e8e5bac68a8539795eb7 Mon Sep 17 00:00:00 2001 -From: Yifeng Sun -Date: Wed, 11 Sep 2019 14:18:35 -0700 -Subject: db-ctl-base: Free leaked ovsdb_datum - -Valgrind reported: - -2491: database commands -- negative checks - -==19245== 36 (32 direct, 4 indirect) bytes in 1 blocks are definitely lost in loss record 36 of 53 -==19245== at 0x4C2FD5F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) -==19245== by 0x431AB4: xrealloc (util.c:149) -==19245== by 0x41656D: ovsdb_datum_reallocate (ovsdb-data.c:1883) -==19245== by 0x41656D: ovsdb_datum_union (ovsdb-data.c:1961) -==19245== by 0x4107B2: cmd_add (db-ctl-base.c:1494) -==19245== by 0x406E2E: do_vsctl (ovs-vsctl.c:2626) -==19245== by 0x406E2E: main (ovs-vsctl.c:183) - -==19252== 16 bytes in 1 blocks are definitely lost in loss record 9 of 52 -==19252== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) -==19252== by 0x430F74: xmalloc (util.c:138) -==19252== by 0x414D07: clone_atoms (ovsdb-data.c:990) -==19252== by 0x4153F6: ovsdb_datum_clone (ovsdb-data.c:1012) -==19252== by 0x4104D3: cmd_remove (db-ctl-base.c:1564) -==19252== by 0x406E2E: do_vsctl (ovs-vsctl.c:2626) -==19252== by 0x406E2E: main (ovs-vsctl.c:183) - -This patch fixes them. - -Acked-by: William Tu -Signed-off-by: Yifeng Sun -Signed-off-by: Ben Pfaff ---- - lib/db-ctl-base.c | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/lib/db-ctl-base.c b/lib/db-ctl-base.c -index 3bd9f006a..6878d6326 100644 ---- a/lib/db-ctl-base.c -+++ b/lib/db-ctl-base.c -@@ -1489,6 +1489,7 @@ cmd_add(struct ctl_context *ctx) - ctx->error = ovsdb_datum_from_string(&add, &add_type, ctx->argv[i], - ctx->symtab); - if (ctx->error) { -+ ovsdb_datum_destroy(&old, &column->type); - return; - } - ovsdb_datum_union(&old, &add, type, false); -@@ -1500,6 +1501,7 @@ cmd_add(struct ctl_context *ctx) - old.n, - type->value.type == OVSDB_TYPE_VOID ? "values" : "pairs", - column->name, table->name, type->n_max); -+ ovsdb_datum_destroy(&old, &column->type); - return; - } - ovsdb_idl_txn_verify(row, column); -@@ -1581,10 +1583,12 @@ cmd_remove(struct ctl_context *ctx) - ctx->argv[i], - ctx->symtab); - if (ctx->error) { -+ ovsdb_datum_destroy(&old, &column->type); - return; - } - } else { - ctx->error = error; -+ ovsdb_datum_destroy(&old, &column->type); - return; - } - } -@@ -1596,6 +1600,7 @@ cmd_remove(struct ctl_context *ctx) - "table %s but the minimum number is %u", old.n, - type->value.type == OVSDB_TYPE_VOID ? "values" : "pairs", - column->name, table->name, type->n_min); -+ ovsdb_datum_destroy(&old, &column->type); - return; - } - ovsdb_idl_txn_verify(row, column); --- -2.14.1 - - diff --git a/dns-resolve-Free-struct-ub_result-when-callback-retu.patch b/dns-resolve-Free-struct-ub_result-when-callback-retu.patch deleted file mode 100644 index ed5e2da70e9e6ee2dfd68dacaff5dbb0f731c94c..0000000000000000000000000000000000000000 --- a/dns-resolve-Free-struct-ub_result-when-callback-retu.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 2f4232d58d414f1e0e5cfe82ce4f7ff7fc5de621 Mon Sep 17 00:00:00 2001 -From: Yifeng Sun -Date: Wed, 11 Sep 2019 14:18:33 -0700 -Subject: dns-resolve: Free 'struct ub_result' when callback returns error results - -Valgrind reported: - -1074: ofproto - flush flows, groups, and meters for controller change - -==5499== 695 (288 direct, 407 indirect) bytes in 3 blocks are definitely lost in loss record 344 of 355 -==5499== at 0x4C2FB55: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) -==5499== by 0x5E7F145: ??? (in /usr/lib/x86_64-linux-gnu/libunbound.so.2.4.0) -==5499== by 0x5E6EBDE: ub_resolve_async (in /usr/lib/x86_64-linux-gnu/libunbound.so.2.4.0) -==5499== by 0x55C739: resolve_async__.part.5 (dns-resolve.c:233) -==5499== by 0x55C85C: resolve_async__ (dns-resolve.c:261) -==5499== by 0x55C85C: resolve_callback__ (dns-resolve.c:262) -==5499== by 0x5E6FEF1: ub_process (in /usr/lib/x86_64-linux-gnu/libunbound.so.2.4.0) -==5499== by 0x55CAF3: dns_resolve (dns-resolve.c:153) -==5499== by 0x523864: parse_sockaddr_components_dns (socket-util.c:438) -==5499== by 0x523864: parse_sockaddr_components (socket-util.c:504) -==5499== by 0x524468: inet_parse_active (socket-util.c:541) -==5499== by 0x524564: inet_open_active (socket-util.c:579) -==5499== by 0x5959F9: tcp_open (stream-tcp.c:56) -==5499== by 0x529192: stream_open (stream.c:228) -==5499== by 0x529910: stream_open_with_default_port (stream.c:724) -==5499== by 0x595FAE: vconn_stream_open (vconn-stream.c:81) -==5499== by 0x535C9B: vconn_open (vconn.c:250) -==5499== by 0x517C59: reconnect (rconn.c:467) -==5499== by 0x5184C7: run_BACKOFF (rconn.c:492) -==5499== by 0x5184C7: rconn_run (rconn.c:660) -==5499== by 0x457FE8: ofservice_run (connmgr.c:1992) -==5499== by 0x457FE8: connmgr_run (connmgr.c:367) -==5499== by 0x41E0F5: ofproto_run (ofproto.c:1845) -==5499== by 0x40BA63: bridge_run__ (bridge.c:2971) - -In ub_resolve_async's callback function, 'struct ub_result' should be -finally freed even if there is a resolving error. This patch fixes it. - -Acked-by: William Tu -Signed-off-by: Yifeng Sun -Signed-off-by: Ben Pfaff ---- - lib/dns-resolve.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/lib/dns-resolve.c b/lib/dns-resolve.c -index e98e65f49..1ff58960f 100644 ---- a/lib/dns-resolve.c -+++ b/lib/dns-resolve.c -@@ -251,6 +251,7 @@ resolve_callback__(void *req_, int err, struct ub_result *result) - struct resolve_request *req = req_; - - if (err != 0 || (result->qtype == ns_t_aaaa && !result->havedata)) { -+ ub_resolve_free(result); - req->state = RESOLVE_ERROR; - VLOG_ERR_RL(&rl, "%s: failed to resolve", req->name); - return; -@@ -265,6 +266,7 @@ resolve_callback__(void *req_, int err, struct ub_result *result) - - char *addr; - if (!resolve_result_to_addr__(result, &addr)) { -+ ub_resolve_free(result); - req->state = RESOLVE_ERROR; - VLOG_ERR_RL(&rl, "%s: failed to resolve", req->name); - return; --- -2.14.1 - - diff --git a/doc-Fix-incorrect-reference-for-dpdk-testpmd.patch b/doc-Fix-incorrect-reference-for-dpdk-testpmd.patch deleted file mode 100644 index d6272c2a74eed74d8276395ba64768de0b18f9c1..0000000000000000000000000000000000000000 --- a/doc-Fix-incorrect-reference-for-dpdk-testpmd.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 093fd99a4c12d902110ac15cd583c37ee6f2ea12 Mon Sep 17 00:00:00 2001 -From: David Marchand -Date: Thu, 3 Oct 2019 20:45:20 +0200 -Subject: doc: Fix incorrect reference for dpdk-testpmd. - -Move back the dpdk-testpmd reference to the right section of this -document so that the link in howto/dpdk does not point to -"vhost-user-client tx retries config". - -Fixes: 080f080c3bc1 ("netdev-dpdk: Enable tx-retries-max config.") - -Signed-off-by: David Marchand -Acked-by: Kevin Traynor -Signed-off-by: Ilya Maximets ---- - Documentation/topics/dpdk/vhost-user.rst | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/Documentation/topics/dpdk/vhost-user.rst b/Documentation/topics/dpdk/vhost-user.rst -index 724aa62f6..fab87bd3d 100644 ---- a/Documentation/topics/dpdk/vhost-user.rst -+++ b/Documentation/topics/dpdk/vhost-user.rst -@@ -348,8 +348,6 @@ The default value is ``false``. - across a 10Gbps link possibly unacceptably slow. So recommended hugepage - size is 2MB. - --.. _dpdk-testpmd: -- - vhost-user-client tx retries config - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -@@ -375,6 +373,8 @@ Tx retries max can be set for vhost-user-client ports:: - - Configurable vhost tx retries are not supported with vhost-user ports. - -+.. _dpdk-testpmd: -+ - DPDK in the Guest - ----------------- - --- -2.14.1 - - diff --git a/dp-packet-Fix-clearing-copying-of-memory-layout-flag.patch b/dp-packet-Fix-clearing-copying-of-memory-layout-flag.patch deleted file mode 100644 index d2e0c932e692509312a3c6b8f484cc1bf05cff0b..0000000000000000000000000000000000000000 --- a/dp-packet-Fix-clearing-copying-of-memory-layout-flag.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 8c3af9f8819bc4ec17134708a6611dd513278d1f Mon Sep 17 00:00:00 2001 -From: Ilya Maximets -Date: Thu, 21 Nov 2019 14:14:52 +0100 -Subject: dp-packet: Fix clearing/copying of memory layout flags. - -'ol_flags' of DPDK mbuf could contain bits responsible for external -or indirect buffers which are not actually offload flags in a common -sense. Clearing/copying of these flags could lead to memory leaks of -external memory chunks and crashes due to access to wrong memory. - -OVS should not clear these flags while resetting offloads and also -should not copy them to the newly allocated packets. - -This change is required to support DPDK 19.11, as some drivers may -return mbufs with these flags set. However, it might be good to do -the same for DPDK 18.11, because these flags are present and should -be taken into account. - -Fixes: 03f3f9c0faf8 ("dpdk: Update to use DPDK 18.11.") -Signed-off-by: Ilya Maximets -Reviewed-by: David Marchand -Acked-by: Ben Pfaff -Acked-by: Kevin Traynor ---- - lib/dp-packet.c | 1 + - lib/dp-packet.h | 7 ++++++- - 2 files changed, 7 insertions(+), 1 deletion(-) - -diff --git a/lib/dp-packet.c b/lib/dp-packet.c -index 62d7faa4c..8dfedcb7c 100644 ---- a/lib/dp-packet.c -+++ b/lib/dp-packet.c -@@ -194,6 +194,7 @@ dp_packet_clone_with_headroom(const struct dp_packet *buffer, size_t headroom) - - #ifdef DPDK_NETDEV - new_buffer->mbuf.ol_flags = buffer->mbuf.ol_flags; -+ new_buffer->mbuf.ol_flags &= ~DPDK_MBUF_NON_OFFLOADING_FLAGS; - #endif - - if (dp_packet_rss_valid(buffer)) { -diff --git a/lib/dp-packet.h b/lib/dp-packet.h -index 14f0897fa..3dd59e25d 100644 ---- a/lib/dp-packet.h -+++ b/lib/dp-packet.h -@@ -54,6 +54,11 @@ enum dp_packet_offload_mask { - DP_PACKET_OL_RSS_HASH_MASK = 0x1, /* Is the 'rss_hash' valid? */ - DP_PACKET_OL_FLOW_MARK_MASK = 0x2, /* Is the 'flow_mark' valid? */ - }; -+#else -+/* DPDK mbuf ol_flags that are not really an offload flags. These are mostly -+ * related to mbuf memory layout and OVS should not touch/clear them. */ -+#define DPDK_MBUF_NON_OFFLOADING_FLAGS (EXT_ATTACHED_MBUF | \ -+ IND_ATTACHED_MBUF) - #endif - - /* Buffer for holding packet data. A dp_packet is automatically reallocated -@@ -538,7 +543,7 @@ dp_packet_rss_valid(const struct dp_packet *p) - static inline void - dp_packet_reset_offload(struct dp_packet *p) - { -- p->mbuf.ol_flags = 0; -+ p->mbuf.ol_flags &= DPDK_MBUF_NON_OFFLOADING_FLAGS; - } - - static inline bool --- -2.14.1 - - diff --git a/dpdk-Use-DPDK-18.11.5-release.patch b/dpdk-Use-DPDK-18.11.5-release.patch deleted file mode 100644 index f39cb7db33b7fc1c99e2fd9b163709422612ac8e..0000000000000000000000000000000000000000 --- a/dpdk-Use-DPDK-18.11.5-release.patch +++ /dev/null @@ -1,107 +0,0 @@ -From a835ee279bf88650c0eba0442f08bbc86620aac3 Mon Sep 17 00:00:00 2001 -From: Ian Stokes -Date: Tue, 26 Nov 2019 12:03:29 +0000 -Subject: dpdk: Use DPDK 18.11.5 release. - -Modify travis linux build script to use the latest DPDK stable release -18.11.5. Update docs for latest DPDK stable releases. - -Signed-off-by: Ian Stokes -Acked-by: Ilya Maximets -Acked-by: Kevin Traynor ---- - .travis/linux-build.sh | 2 +- - Documentation/faq/releases.rst | 4 ++-- - Documentation/intro/install/dpdk.rst | 8 ++++---- - Documentation/topics/dpdk/vhost-user.rst | 6 +++--- - NEWS | 3 +++ - 5 files changed, 13 insertions(+), 10 deletions(-) - -diff --git a/.travis/linux-build.sh b/.travis/linux-build.sh -index 17428fa6b..1afa42914 100755 ---- a/.travis/linux-build.sh -+++ b/.travis/linux-build.sh -@@ -105,7 +105,7 @@ fi - - if [ "$DPDK" ] || [ "$DPDK_SHARED" ]; then - if [ -z "$DPDK_VER" ]; then -- DPDK_VER="18.11.2" -+ DPDK_VER="18.11.5" - fi - install_dpdk $DPDK_VER - if [ "$CC" = "clang" ]; then -diff --git a/Documentation/faq/releases.rst b/Documentation/faq/releases.rst -index e18f5db75..cc06571f5 100644 ---- a/Documentation/faq/releases.rst -+++ b/Documentation/faq/releases.rst -@@ -178,8 +178,8 @@ Q: What DPDK version does each Open vSwitch release work with? - 2.8.x 17.05.2 - 2.9.x 17.11.4 - 2.10.x 17.11.4 -- 2.11.x 18.11.2 -- 2.12.x 18.11.2 -+ 2.11.x 18.11.5 -+ 2.12.x 18.11.5 - ============ ======= - - Q: Are all the DPDK releases that OVS versions work with maintained? -diff --git a/Documentation/intro/install/dpdk.rst b/Documentation/intro/install/dpdk.rst -index 6e5f1ea60..13aa8a16f 100644 ---- a/Documentation/intro/install/dpdk.rst -+++ b/Documentation/intro/install/dpdk.rst -@@ -42,7 +42,7 @@ Build requirements - In addition to the requirements described in :doc:`general`, building Open - vSwitch with DPDK will require the following: - --- DPDK 18.11.2 -+- DPDK 18.11.5 - - - A `DPDK supported NIC`_ - -@@ -71,9 +71,9 @@ Install DPDK - #. Download the `DPDK sources`_, extract the file and set ``DPDK_DIR``:: - - $ cd /usr/src/ -- $ wget http://fast.dpdk.org/rel/dpdk-18.11.2.tar.xz -- $ tar xf dpdk-18.11.2.tar.xz -- $ export DPDK_DIR=/usr/src/dpdk-stable-18.11.2 -+ $ wget http://fast.dpdk.org/rel/dpdk-18.11.5.tar.xz -+ $ tar xf dpdk-18.11.5.tar.xz -+ $ export DPDK_DIR=/usr/src/dpdk-stable-18.11.5 - $ cd $DPDK_DIR - - #. (Optional) Configure DPDK as a shared library -diff --git a/Documentation/topics/dpdk/vhost-user.rst b/Documentation/topics/dpdk/vhost-user.rst -index fab87bd3d..a0d35cdd4 100644 ---- a/Documentation/topics/dpdk/vhost-user.rst -+++ b/Documentation/topics/dpdk/vhost-user.rst -@@ -392,9 +392,9 @@ To begin, instantiate a guest as described in :ref:`dpdk-vhost-user` or - DPDK sources to VM and build DPDK:: - - $ cd /root/dpdk/ -- $ wget http://fast.dpdk.org/rel/dpdk-18.11.2.tar.xz -- $ tar xf dpdk-18.11.2.tar.xz -- $ export DPDK_DIR=/root/dpdk/dpdk-stable-18.11.2 -+ $ wget http://fast.dpdk.org/rel/dpdk-18.11.5.tar.xz -+ $ tar xf dpdk-18.11.5.tar.xz -+ $ export DPDK_DIR=/root/dpdk/dpdk-stable-18.11.5 - $ export DPDK_TARGET=x86_64-native-linuxapp-gcc - $ export DPDK_BUILD=$DPDK_DIR/$DPDK_TARGET - $ cd $DPDK_DIR -diff --git a/NEWS b/NEWS -index c81890b7e..b9be7f7ce 100644 ---- a/NEWS -+++ b/NEWS -@@ -1,5 +1,8 @@ - v2.12.1 - xx xxx xxxx - --------------------- -+ - DPDK: -+ * OVS validated with DPDK 18.11.5, due to the inclusion of a fix for -+ CVE-2019-14818, this DPDK version is strongly recommended to be used. - - v2.12.0 - 03 Sep 2019 - --------------------- --- -2.14.1 - - diff --git a/dpif-netdev-Avoid-infinite-re-addition-of-misconfigu.patch b/dpif-netdev-Avoid-infinite-re-addition-of-misconfigu.patch deleted file mode 100644 index 59571bab061113c4e64f4b8940b48778e88ed34b..0000000000000000000000000000000000000000 --- a/dpif-netdev-Avoid-infinite-re-addition-of-misconfigu.patch +++ /dev/null @@ -1,112 +0,0 @@ -From 002cb62160cba242d49f918fd49aa54f957413b1 Mon Sep 17 00:00:00 2001 -From: Ilya Maximets -Date: Sat, 7 Dec 2019 15:46:16 +0100 -Subject: dpif-netdev: Avoid infinite re-addition of misconfigured ports. - -Infinite re-addition of failed ports happens if the device in userspace -datapath has a linux network interface and it's not able to be -configured. For example, if the first reconfiguration fails because of -misconfiguration or bad initial device state. -In current code victims are afxdp ports and the Mellanox NIC ports -opened by the DPDK due to their bifurcated drivers (It's unlikely for -usual netdev-linux ports to fail). - -The root cause: Every change in the state of the network interface -of a linux kernel device generates if-notifier event and if-notifier -event triggers the OVS code to re-apply the configuration of ports, -i.e. add broken ports back. The most obvious part is that dpif-netdev -changes the device flags before trying to configure it: - - 1. add_port() - 2. set_flags() --> if-notifier event - 3. reconfigure() --> port removal from the datapath due to - misconfiguration or any other issue in - the underlying device. - 4. setting flags back --> another if-notifier event. - 5. There was new if-notifier event? - yes --> re-apply all settings. --> goto step 1. - -Easy way to reproduce is to add afxdp port with n_rxq=N, where N is -bigger than device supports. - -This patch fixes the most obvious case for this issue by moving -enabling of a promisc mode later to the place where we already know -that device could be added to datapath without errors, i.e. after -its first successful reconfiguration. - -Reported-at: https://mail.openvswitch.org/pipermail/ovs-dev/2019-September/363038.html -Signed-off-by: Ilya Maximets -Acked-by: William Tu ---- - lib/dpif-netdev.c | 29 ++++++++++++++++++++--------- - 1 file changed, 20 insertions(+), 9 deletions(-) - -diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c -index 370840fa0..1f405b7d2 100644 ---- a/lib/dpif-netdev.c -+++ b/lib/dpif-netdev.c -@@ -1793,7 +1793,6 @@ static int - port_create(const char *devname, const char *type, - odp_port_t port_no, struct dp_netdev_port **portp) - { -- struct netdev_saved_flags *sf; - struct dp_netdev_port *port; - enum netdev_flags flags; - struct netdev *netdev; -@@ -1815,17 +1814,11 @@ port_create(const char *devname, const char *type, - goto out; - } - -- error = netdev_turn_flags_on(netdev, NETDEV_PROMISC, &sf); -- if (error) { -- VLOG_ERR("%s: cannot set promisc flag", devname); -- goto out; -- } -- - port = xzalloc(sizeof *port); - port->port_no = port_no; - port->netdev = netdev; - port->type = xstrdup(type); -- port->sf = sf; -+ port->sf = NULL; - port->emc_enabled = true; - port->need_reconfigure = true; - ovs_mutex_init(&port->txq_used_mutex); -@@ -1844,6 +1837,7 @@ do_add_port(struct dp_netdev *dp, const char *devname, const char *type, - odp_port_t port_no) - OVS_REQUIRES(dp->port_mutex) - { -+ struct netdev_saved_flags *sf; - struct dp_netdev_port *port; - int error; - -@@ -1863,7 +1857,24 @@ do_add_port(struct dp_netdev *dp, const char *devname, const char *type, - reconfigure_datapath(dp); - - /* Check that port was successfully configured. */ -- return dp_netdev_lookup_port(dp, port_no) ? 0 : EINVAL; -+ if (!dp_netdev_lookup_port(dp, port_no)) { -+ return EINVAL; -+ } -+ -+ /* Updating device flags triggers an if_notifier, which triggers a bridge -+ * reconfiguration and another attempt to add this port, leading to an -+ * infinite loop if the device is configured incorrectly and cannot be -+ * added. Setting the promisc mode after a successful reconfiguration, -+ * since we already know that the device is somehow properly configured. */ -+ error = netdev_turn_flags_on(port->netdev, NETDEV_PROMISC, &sf); -+ if (error) { -+ VLOG_ERR("%s: cannot set promisc flag", devname); -+ do_del_port(dp, port); -+ return error; -+ } -+ port->sf = sf; -+ -+ return 0; - } - - static int --- -2.14.1 - - diff --git a/dpif-netdev-Do-not-mix-recirculation-depth-into-RSS-.patch b/dpif-netdev-Do-not-mix-recirculation-depth-into-RSS-.patch deleted file mode 100644 index 05e3929d486c9aadc3f7bfedeffb9485fe0a4b35..0000000000000000000000000000000000000000 --- a/dpif-netdev-Do-not-mix-recirculation-depth-into-RSS-.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 492856b16e0673184987e402c41a42f991853b7c Mon Sep 17 00:00:00 2001 -From: Ilya Maximets -Date: Thu, 24 Oct 2019 12:55:15 +0200 -Subject: dpif-netdev: Do not mix recirculation depth into RSS hash itself. - -Mixing of RSS hash with recirculation depth is useful for flow lookup -because same packet after recirculation should match with different -datapath rule. Setting of the mixed value back to the packet is -completely unnecessary because recirculation depth is different on -each recirculation, i.e. we will have different packet hash for -flow lookup anyway. - -This should fix the issue that packets from the same flow could be -directed to different buckets based on a dp_hash or different ports of -a balanced bonding in case they were recirculated different number of -times (e.g. due to conntrack rules). -With this change, the original RSS hash will remain the same making -it possible to calculate equal dp_hash values for such packets. - -Reported-at: https://mail.openvswitch.org/pipermail/ovs-dev/2019-September/363127.html -Fixes: 048963aa8507 ("dpif-netdev: Reset RSS hash when recirculating.") -Signed-off-by: Ilya Maximets -Acked-by: Jan Scheurich ---- - lib/dpif-netdev.c | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c -index 133c9b9a4..f71deb718 100644 ---- a/lib/dpif-netdev.c -+++ b/lib/dpif-netdev.c -@@ -6272,7 +6272,6 @@ dpif_netdev_packet_get_rss_hash(struct dp_packet *packet, - recirc_depth = *recirc_depth_get_unsafe(); - if (OVS_UNLIKELY(recirc_depth)) { - hash = hash_finish(hash, recirc_depth); -- dp_packet_set_rss_hash(packet, hash); - } - return hash; - } --- -2.14.1 - - diff --git a/dpif-netdev-Fix-time-delta-overflow-in-case-of-race-.patch b/dpif-netdev-Fix-time-delta-overflow-in-case-of-race-.patch deleted file mode 100644 index fd4bbd0d075b1271973f86f4b004921bdcc7794e..0000000000000000000000000000000000000000 --- a/dpif-netdev-Fix-time-delta-overflow-in-case-of-race-.patch +++ /dev/null @@ -1,48 +0,0 @@ -From aa49a6d46edfaeb414fcd70d3138ee8b28ffb343 Mon Sep 17 00:00:00 2001 -From: Ilya Maximets -Date: Thu, 24 Oct 2019 15:15:07 +0200 -Subject: dpif-netdev: Fix time delta overflow in case of race for meter lock. - -There is a race window between getting the time and getting the meter -lock. This could lead to situation where the thread with larger -current time (this thread called time_{um}sec() later than others) -will acquire meter lock first and update meter->used to the large -value. Next threads will try to calculate time delta by subtracting -the large meter->used from their lower time getting the negative value -which will be converted to a big unsigned delta. - -Fix that by assuming that all these threads received packets in the -same time in this case, i.e. dropping negative delta to 0. - -CC: Jarno Rajahalme -Fixes: 4b27db644a8c ("dpif-netdev: Simple DROP meter implementation.") -Reported-at: https://mail.openvswitch.org/pipermail/ovs-dev/2019-September/363126.html -Signed-off-by: Ilya Maximets -Acked-by: William Tu ---- - lib/dpif-netdev.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c -index f71deb718..370840fa0 100644 ---- a/lib/dpif-netdev.c -+++ b/lib/dpif-netdev.c -@@ -5630,6 +5630,14 @@ dp_netdev_run_meter(struct dp_netdev *dp, struct dp_packet_batch *packets_, - /* All packets will hit the meter at the same time. */ - long_delta_t = now / 1000 - meter->used / 1000; /* msec */ - -+ if (long_delta_t < 0) { -+ /* This condition means that we have several threads fighting for a -+ meter lock, and the one who received the packets a bit later wins. -+ Assuming that all racing threads received packets at the same time -+ to avoid overflow. */ -+ long_delta_t = 0; -+ } -+ - /* Make sure delta_t will not be too large, so that bucket will not - * wrap around below. */ - delta_t = (long_delta_t > (long long int)meter->max_delta_t) --- -2.14.1 - - diff --git a/dpif-netdev-Handle-uninitialized-value-error-for-mat.patch b/dpif-netdev-Handle-uninitialized-value-error-for-mat.patch deleted file mode 100644 index 3322c92c2a2826a784307d6322933cf509b3875e..0000000000000000000000000000000000000000 --- a/dpif-netdev-Handle-uninitialized-value-error-for-mat.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 3198ae3f423320cc21d40a995a6693b5fa56aade Mon Sep 17 00:00:00 2001 -From: Yifeng Sun -Date: Wed, 11 Sep 2019 14:18:29 -0700 -Subject: dpif-netdev: Handle uninitialized value error for 'match.wc' - -Valgrind reported that match.wc was not initialized, as below: - -1176: ofproto-dpif - fragment handling - actions - -==21214== Conditional jump or move depends on uninitialised value(s) -==21214== at 0x4B77C1: odp_flow_key_from_flow__ (odp-util.c:6143) -==21214== by 0x46DB58: dp_netdev_upcall (dpif-netdev.c:6239) -==21214== by 0x4774A7: handle_packet_upcall (dpif-netdev.c:6608) -==21214== by 0x4774A7: fast_path_processing (dpif-netdev.c:6726) -==21214== by 0x47933C: dp_netdev_input__ (dpif-netdev.c:6814) -==21214== by 0x479AB8: dp_netdev_input (dpif-netdev.c:6852) -==21214== by 0x479AB8: dp_netdev_process_rxq_port (dpif-netdev.c:4287) -==21214== by 0x47A6A9: dpif_netdev_run (dpif-netdev.c:5264) -==21214== by 0x4324E7: type_run (ofproto-dpif.c:342) -==21214== by 0x41C5FE: ofproto_type_run (ofproto.c:1734) -==21214== by 0x40BAAC: bridge_run__ (bridge.c:2965) -==21214== by 0x410CF3: bridge_run (bridge.c:3029) -==21214== by 0x407614: main (ovs-vswitchd.c:127) -==21214== Uninitialised value was created by a stack allocation -==21214== at 0x4769C3: fast_path_processing (dpif-netdev.c:6672) - -'match' is allocated on stack but its 'wc' is accessed in -odp_flow_key_from_flow__ without proper initialization. -This patch fixes it. - -Acked-by: William Tu -Signed-off-by: Yifeng Sun -Signed-off-by: Ben Pfaff ---- - lib/dpif-netdev.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c -index 75d85b2fd..133c9b9a4 100644 ---- a/lib/dpif-netdev.c -+++ b/lib/dpif-netdev.c -@@ -6584,6 +6584,7 @@ handle_packet_upcall(struct dp_netdev_pmd_thread *pmd, - - match.tun_md.valid = false; - miniflow_expand(&key->mf, &match.flow); -+ memset(&match.wc, 0, sizeof match.wc); - - ofpbuf_clear(actions); - ofpbuf_clear(put_actions); --- -2.14.1 - - diff --git a/dpif-netlink-Free-leaked-nl_sock.patch b/dpif-netlink-Free-leaked-nl_sock.patch deleted file mode 100644 index 7bf3ee8ca8c4fbee92da9fe8a8e4f53f57c84364..0000000000000000000000000000000000000000 --- a/dpif-netlink-Free-leaked-nl_sock.patch +++ /dev/null @@ -1,49 +0,0 @@ -From a73c04ae00b2eb39c91ae6dddb3981e1a14c967e Mon Sep 17 00:00:00 2001 -From: Yifeng Sun -Date: Fri, 11 Oct 2019 15:50:47 -0700 -Subject: dpif-netlink: Free leaked nl_sock - -Valgrind reports: -20 bytes in 1 blocks are definitely lost in loss record 94 of 353 - by 0x532594: xmalloc (util.c:138) - by 0x553EAD: nl_sock_create (netlink-socket.c:146) - by 0x54331D: create_nl_sock (dpif-netlink.c:255) - by 0x54331D: dpif_netlink_port_add__ (dpif-netlink.c:756) - by 0x5435F6: dpif_netlink_port_add_compat (dpif-netlink.c:876) - by 0x5435F6: dpif_netlink_port_add (dpif-netlink.c:922) - by 0x47EC1D: dpif_port_add (dpif.c:584) - by 0x42B35F: port_add (ofproto-dpif.c:3721) - by 0x41E64A: ofproto_port_add (ofproto.c:2032) - by 0x40B3FE: iface_do_create (bridge.c:1817) - by 0x40B3FE: iface_create (bridge.c:1855) - by 0x40B3FE: bridge_add_ports__ (bridge.c:943) - by 0x40D14A: bridge_add_ports (bridge.c:959) - by 0x40D14A: bridge_reconfigure (bridge.c:673) - by 0x410D75: bridge_run (bridge.c:3050) - by 0x407614: main (ovs-vswitchd.c:127) - -This leak is because when vport_add_channel() returns 0, it is expected -to take the ownership of 'socksp'. This patch fixes this issue. - -Signed-off-by: Yifeng Sun -Signed-off-by: Ben Pfaff ---- - lib/dpif-netlink.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c -index 7bc71d6d1..efdb9acfc 100644 ---- a/lib/dpif-netlink.c -+++ b/lib/dpif-netlink.c -@@ -457,6 +457,7 @@ vport_add_channel(struct dpif_netlink *dpif, odp_port_t port_no, - int error; - - if (dpif->handlers == NULL) { -+ close_nl_sock(socksp); - return 0; - } - --- -2.14.1 - - diff --git a/faq-Update-OVS-DPDK-version-table-for-OVS-2.12.patch b/faq-Update-OVS-DPDK-version-table-for-OVS-2.12.patch deleted file mode 100644 index c76c9c0fa20d6ed2c0af505958191aa0c58ce2a2..0000000000000000000000000000000000000000 --- a/faq-Update-OVS-DPDK-version-table-for-OVS-2.12.patch +++ /dev/null @@ -1,29 +0,0 @@ -From e40063a8c268a937902b29fa32e71335481ea0ff Mon Sep 17 00:00:00 2001 -From: Kevin Traynor -Date: Mon, 23 Sep 2019 16:59:11 +0100 -Subject: faq: Update OVS/DPDK version table for OVS 2.12. - -Indicate that OVS 2.12 uses DPDK 18.11.2. - -Signed-off-by: Kevin Traynor -Signed-off-by: Ben Pfaff ---- - Documentation/faq/releases.rst | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/Documentation/faq/releases.rst b/Documentation/faq/releases.rst -index 8c29e32ef..e18f5db75 100644 ---- a/Documentation/faq/releases.rst -+++ b/Documentation/faq/releases.rst -@@ -179,6 +179,7 @@ Q: What DPDK version does each Open vSwitch release work with? - 2.9.x 17.11.4 - 2.10.x 17.11.4 - 2.11.x 18.11.2 -+ 2.12.x 18.11.2 - ============ ======= - - Q: Are all the DPDK releases that OVS versions work with maintained? --- -2.14.1 - - diff --git a/faq-Update-list-of-kernels-supported-by-2.12.patch b/faq-Update-list-of-kernels-supported-by-2.12.patch deleted file mode 100644 index 25df1d941608efca69a6757c16cd827a341784fd..0000000000000000000000000000000000000000 --- a/faq-Update-list-of-kernels-supported-by-2.12.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 25cf170d88f98b8f7a2009d560b017b2b4f5fc83 Mon Sep 17 00:00:00 2001 -From: Justin Pettit -Date: Fri, 6 Sep 2019 16:30:46 -0700 -Subject: faq: Update list of kernels supported by 2.12. - -Signed-off-by: Justin Pettit -Reviewed-by: Yifeng Sun ---- - Documentation/faq/releases.rst | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/Documentation/faq/releases.rst b/Documentation/faq/releases.rst -index 8daa23bb2..8c29e32ef 100644 ---- a/Documentation/faq/releases.rst -+++ b/Documentation/faq/releases.rst -@@ -69,6 +69,7 @@ Q: What Linux kernel versions does each Open vSwitch release work with? - 2.9.x 3.10 to 4.13 - 2.10.x 3.10 to 4.17 - 2.11.x 3.10 to 4.18 -+ 2.12.x 3.10 to 5.0 - ============ ============== - - Open vSwitch userspace should also work with the Linux kernel module built --- -2.14.1 - - diff --git a/flow-Fix-IPv6-header-parser-with-partial-offloading.patch b/flow-Fix-IPv6-header-parser-with-partial-offloading.patch deleted file mode 100644 index aff374fcd9e3ad1520284fc4e0254e9f6c080a87..0000000000000000000000000000000000000000 --- a/flow-Fix-IPv6-header-parser-with-partial-offloading.patch +++ /dev/null @@ -1,34 +0,0 @@ -From b24353da63d84420b5a103a91d475b4669ad4122 Mon Sep 17 00:00:00 2001 -From: Zhike Wang -Date: Fri, 8 Nov 2019 17:02:44 +0800 -Subject: flow: Fix IPv6 header parser with partial offloading. - -Set nw_proto before it is used in parse_ipv6_ext_hdrs__(). - -Signed-off-by: Zhike Wang -Signed-off-by: Ben Pfaff ---- - lib/flow.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/lib/flow.c b/lib/flow.c -index b7f35e33b..6c7c08fd8 100644 ---- a/lib/flow.c -+++ b/lib/flow.c -@@ -1139,11 +1139,11 @@ parse_tcp_flags(struct dp_packet *packet) - dp_packet_set_l2_pad_size(packet, size - plen); - size = plen; - const struct ovs_16aligned_ip6_frag *frag_hdr; -+ nw_proto = nh->ip6_nxt; - if (!parse_ipv6_ext_hdrs__(&data, &size, &nw_proto, &nw_frag, - &frag_hdr)) { - return 0; - } -- nw_proto = nh->ip6_nxt; - } else { - return 0; - } --- -2.14.1 - - diff --git a/flow-Fix-crash-on-vlan-packets-with-partial-offloadi.patch b/flow-Fix-crash-on-vlan-packets-with-partial-offloadi.patch deleted file mode 100644 index 632dc898c7175943e62eb76f1745754716b36929..0000000000000000000000000000000000000000 --- a/flow-Fix-crash-on-vlan-packets-with-partial-offloadi.patch +++ /dev/null @@ -1,186 +0,0 @@ -From 16c647479e4e4931b45bdaa0b995c9cadb16d5a6 Mon Sep 17 00:00:00 2001 -From: Ilya Maximets -Date: Wed, 23 Oct 2019 22:26:52 +0200 -Subject: flow: Fix crash on vlan packets with partial offloading. - -parse_tcp_flags() does not care about vlan tags in a packet thus -not able to parse them. As a result, if partial offloading is -enabled in userspace datapath vlan packets are not parsed, i.e. -has no initialized offsets. This causes OVS crash on any attempt -to access/modify packet header fields. - -For example, having the flow with following actions: - in_port=1,ip,actions=mod_nw_src:192.168.0.7,output:IN_PORT - -will lead to OVS crash on vlan packet handling: - - Process terminating with default action of signal 11 (SIGSEGV) - Invalid read of size 4 - at 0x785657: get_16aligned_be32 (unaligned.h:249) - by 0x785657: odp_set_ipv4 (odp-execute.c:82) - by 0x785657: odp_execute_masked_set_action (odp-execute.c:527) - by 0x785657: odp_execute_actions (odp-execute.c:894) - by 0x74CDA9: dp_netdev_execute_actions (dpif-netdev.c:7355) - by 0x74CDA9: packet_batch_per_flow_execute (dpif-netdev.c:6339) - by 0x74CDA9: dp_netdev_input__ (dpif-netdev.c:6845) - by 0x74DB6E: dp_netdev_input (dpif-netdev.c:6854) - by 0x74DB6E: dp_netdev_process_rxq_port (dpif-netdev.c:4287) - by 0x74E863: dpif_netdev_run (dpif-netdev.c:5264) - by 0x703F57: type_run (ofproto-dpif.c:370) - by 0x6EC8B8: ofproto_type_run (ofproto.c:1760) - by 0x6DA52B: bridge_run__ (bridge.c:3188) - by 0x6E083F: bridge_run (bridge.c:3252) - by 0x1642E4: main (ovs-vswitchd.c:127) - Address 0xc is not stack'd, malloc'd or (recently) free'd - -Fix that by properly parsing vlan tags first. Function 'parse_dl_type' -transformed for that purpose as it had no users anyway. - -Added unit test for packet modification with partial offloading that -triggers above crash. - -Fixes: aab96ec4d81e ("dpif-netdev: retrieve flow directly from the flow mark") -Signed-off-by: Ilya Maximets -Acked-by: Ben Pfaff ---- - lib/flow.c | 12 ++++---- - lib/flow.h | 1 - - tests/dpif-netdev.at | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 83 insertions(+), 8 deletions(-) - -diff --git a/lib/flow.c b/lib/flow.c -index 0ba146272..b7f35e33b 100644 ---- a/lib/flow.c -+++ b/lib/flow.c -@@ -1076,15 +1076,14 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst) - dst->map = mf.map; - } - --ovs_be16 --parse_dl_type(const struct eth_header *data_, size_t size) -+static ovs_be16 -+parse_dl_type(const void **datap, size_t *sizep) - { -- const void *data = data_; - union flow_vlan_hdr vlans[FLOW_MAX_VLAN_HEADERS]; - -- parse_vlan(&data, &size, vlans); -+ parse_vlan(datap, sizep, vlans); - -- return parse_ethertype(&data, &size); -+ return parse_ethertype(datap, sizep); - } - - /* Parses and return the TCP flags in 'packet', converted to host byte order. -@@ -1107,8 +1106,7 @@ parse_tcp_flags(struct dp_packet *packet) - - dp_packet_reset_offsets(packet); - -- data_pull(&data, &size, ETH_ADDR_LEN * 2); -- dl_type = parse_ethertype(&data, &size); -+ dl_type = parse_dl_type(&data, &size); - if (OVS_UNLIKELY(eth_type_mpls(dl_type))) { - packet->l2_5_ofs = (char *)data - frame; - } -diff --git a/lib/flow.h b/lib/flow.h -index 7298c71f3..75751763c 100644 ---- a/lib/flow.h -+++ b/lib/flow.h -@@ -133,7 +133,6 @@ void packet_expand(struct dp_packet *, const struct flow *, size_t size); - bool parse_ipv6_ext_hdrs(const void **datap, size_t *sizep, uint8_t *nw_proto, - uint8_t *nw_frag, - const struct ovs_16aligned_ip6_frag **frag_hdr); --ovs_be16 parse_dl_type(const struct eth_header *data_, size_t size); - bool parse_nsh(const void **datap, size_t *sizep, struct ovs_key_nsh *key); - uint16_t parse_tcp_flags(struct dp_packet *packet); - -diff --git a/tests/dpif-netdev.at b/tests/dpif-netdev.at -index af8a29e44..ef521ddb8 100644 ---- a/tests/dpif-netdev.at -+++ b/tests/dpif-netdev.at -@@ -420,3 +420,81 @@ p1: flow del: mark: 0 - - DPIF_NETDEV_FLOW_HW_OFFLOAD([dummy]) - DPIF_NETDEV_FLOW_HW_OFFLOAD([dummy-pmd]) -+ -+ -+m4_define([DPIF_NETDEV_FLOW_HW_OFFLOAD_OFFSETS], -+ [AT_SETUP([dpif-netdev - partial hw offload with packet modifications - $1]) -+ OVS_VSWITCHD_START( -+ [add-port br0 p1 -- \ -+ set interface p1 type=$1 ofport_request=1 options:pcap=p1.pcap options:ifindex=1 -- \ -+ set bridge br0 datapath-type=dummy \ -+ other-config:datapath-id=1234 fail-mode=secure], [], [], -+ [m4_if([$1], [dummy-pmd], [--dummy-numa="0,0,0,0,1,1,1,1"], [])]) -+ AT_CHECK([ovs-appctl vlog/set dpif:file:dbg dpif_netdev:file:dbg netdev_dummy:file:dbg]) -+ -+ AT_CHECK([ovs-vsctl set Open_vSwitch . other_config:hw-offload=true]) -+ OVS_WAIT_UNTIL([grep "netdev: Flow API Enabled" ovs-vswitchd.log]) -+ -+ AT_CHECK([ovs-ofctl del-flows br0]) -+ -+ # Setting flow to modify ipv4 src address and udp dst port to be sure that -+ # offloaded packets has correctly initialized l3/l4 offsets. -+ AT_CHECK([ovs-ofctl add-flow br0 in_port=1,udp,actions=mod_nw_src:192.168.0.7,mod_tp_dst:3773,output:IN_PORT]) -+ -+ packet="packet_type(ns=0,id=0),eth(src=00:06:07:08:09:0a,dst=00:01:02:03:04:05),eth_type(0x8100),vlan(vid=99,pcp=7),encap(eth_type(0x0800),ipv4(src=127.0.0.1,dst=127.0.0.1,proto=17,ttl=64,frag=no),udp(src=81,dst=82))" -+ AT_CHECK([ovs-appctl netdev-dummy/receive p1 $packet --len 64], [0]) -+ -+ OVS_WAIT_UNTIL([grep "miss upcall" ovs-vswitchd.log]) -+ AT_CHECK([grep -A 1 'miss upcall' ovs-vswitchd.log | tail -n 1], [0], [dnl -+skb_priority(0),skb_mark(0),ct_state(0),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),dnl -+packet_type(ns=0,id=0),eth(src=00:06:07:08:09:0a,dst=00:01:02:03:04:05),eth_type(0x8100),vlan(vid=99,pcp=7),encap(eth_type(0x0800),ipv4(src=127.0.0.1,dst=127.0.0.1,proto=17,tos=0,ttl=64,frag=no),udp(src=81,dst=82)) -+]) -+ # Check that flow successfully offloaded. -+ OVS_WAIT_UNTIL([grep "succeed to add netdev flow" ovs-vswitchd.log]) -+ AT_CHECK([filter_hw_flow_install < ovs-vswitchd.log | strip_xout], [0], [dnl -+p1: flow put[[create]]: flow match: recirc_id=0,eth,udp,in_port=1,dl_vlan=99,dl_vlan_pcp=7,nw_src=127.0.0.1,nw_frag=no,tp_dst=82, mark: 0 -+]) -+ # Check that datapath flow installed successfully. -+ AT_CHECK([filter_flow_install < ovs-vswitchd.log | strip_xout], [0], [dnl -+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x8100),vlan(vid=99,pcp=7),encap(eth_type(0x0800),ipv4(src=127.0.0.1,proto=17,frag=no),udp(dst=82)), actions: -+]) -+ # Inject the same packet again. -+ AT_CHECK([ovs-appctl netdev-dummy/receive p1 $packet --len 64], [0]) -+ -+ # Check for succesfull packet matching with installed offloaded flow. -+ AT_CHECK([filter_hw_packet_netdev_dummy < ovs-vswitchd.log | strip_xout], [0], [dnl -+p1: packet: udp,dl_vlan=99,dl_vlan_pcp=7,vlan_tci1=0x0000,dl_src=00:06:07:08:09:0a,dl_dst=00:01:02:03:04:05,nw_src=127.0.0.1,nw_dst=127.0.0.1,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=81,tp_dst=82 dnl -+matches with flow: recirc_id=0,eth,udp,dl_vlan=99,dl_vlan_pcp=7,nw_src=127.0.0.1,nw_frag=no,tp_dst=82 with mark: 0 -+]) -+ -+ ovs-appctl revalidator/wait -+ # Dump the datapath flow to see that actions was executed for a packet. -+ AT_CHECK([ovs-appctl dpif/dump-flows br0 | strip_timers], [0], [dnl -+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x8100),vlan(vid=99,pcp=7),encap(eth_type(0x0800),ipv4(src=127.0.0.1,proto=17,frag=no),udp(dst=82)), dnl -+packets:1, bytes:64, used:0.0s, actions:set(ipv4(src=192.168.0.7)),set(udp(dst=3773)),1 -+]) -+ -+ # Wait for datapath flow expiration. -+ ovs-appctl time/stop -+ ovs-appctl time/warp 15000 -+ ovs-appctl revalidator/wait -+ -+ # Check that flow successfully deleted from HW. -+ OVS_WAIT_UNTIL([grep "succeed to delete netdev flow" ovs-vswitchd.log]) -+ AT_CHECK([filter_hw_flow_del < ovs-vswitchd.log | strip_xout], [0], [dnl -+p1: flow del: mark: 0 -+]) -+ -+ # Check that ip address and udp port were correctly modified in output packets. -+ AT_CHECK([ovs-ofctl parse-pcap p1.pcap], [0], [dnl -+udp,in_port=ANY,dl_vlan=99,dl_vlan_pcp=7,vlan_tci1=0x0000,dl_src=00:06:07:08:09:0a,dl_dst=00:01:02:03:04:05,nw_src=127.0.0.1,nw_dst=127.0.0.1,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=81,tp_dst=82 -+udp,in_port=ANY,dl_vlan=99,dl_vlan_pcp=7,vlan_tci1=0x0000,dl_src=00:06:07:08:09:0a,dl_dst=00:01:02:03:04:05,nw_src=192.168.0.7,nw_dst=127.0.0.1,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=81,tp_dst=3773 -+udp,in_port=ANY,dl_vlan=99,dl_vlan_pcp=7,vlan_tci1=0x0000,dl_src=00:06:07:08:09:0a,dl_dst=00:01:02:03:04:05,nw_src=127.0.0.1,nw_dst=127.0.0.1,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=81,tp_dst=82 -+udp,in_port=ANY,dl_vlan=99,dl_vlan_pcp=7,vlan_tci1=0x0000,dl_src=00:06:07:08:09:0a,dl_dst=00:01:02:03:04:05,nw_src=192.168.0.7,nw_dst=127.0.0.1,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=81,tp_dst=3773 -+]) -+ -+ OVS_VSWITCHD_STOP -+ AT_CLEANUP]) -+ -+DPIF_NETDEV_FLOW_HW_OFFLOAD_OFFSETS([dummy]) -+DPIF_NETDEV_FLOW_HW_OFFLOAD_OFFSETS([dummy-pmd]) --- -2.14.1 - - diff --git a/flow-Fix-using-pointer-to-member-of-packed-struct-ic.patch b/flow-Fix-using-pointer-to-member-of-packed-struct-ic.patch deleted file mode 100644 index 0e4c6d411d9b26066584e0a15f64551f484b6628..0000000000000000000000000000000000000000 --- a/flow-Fix-using-pointer-to-member-of-packed-struct-ic.patch +++ /dev/null @@ -1,256 +0,0 @@ -From f94b6e0f9997b5c0f9a278f1f365462dff03da51 Mon Sep 17 00:00:00 2001 -From: Ilya Maximets -Date: Tue, 1 Oct 2019 18:18:23 +0300 -Subject: flow: Fix using pointer to member of packed struct icmp6_hdr. - -OVS has no structure definition for ICMPv6 header with additional -data. More precisely, it has, but this structure named as -'icmp6_error_header' and only suitable to store error related -extended information. 'flow_compose_l4' stores additional -information in reserved bits by using system defined structure -'icmp6_hdr', which is marked as 'packed' and this leads to -build failure with gcc >= 9: - - lib/flow.c:3041:34: error: - taking address of packed member of 'struct icmp6_hdr' may result - in an unaligned pointer value [-Werror=address-of-packed-member] - - uint32_t *reserved = &icmp->icmp6_dataun.icmp6_un_data32[0]; - ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Fix that by renaming 'icmp6_error_header' to 'icmp6_data_header' -and allowing it to store not only errors, but any type of additional -information by analogue with 'struct icmp6_hdr'. -All the usages of 'struct icmp6_hdr' replaced with this new structure. -Removed redundant conversions between network and host representations. -Now fields are always in be. - -This also, probably, makes flow_compose_l4 more robust by avoiding -possible unaligned accesses to 32 bit value. - -Fixes: 9b2b84973db7 ("Support for match & set ICMPv6 reserved and options type fields") -Signed-off-by: Ilya Maximets -Acked-by: William Tu -Acked-by: Ben Pfaff ---- - lib/conntrack.c | 2 +- - lib/flow.c | 77 ++++++++++++++++++++++++------------------------ - lib/packets.h | 12 +++++--- - ovn/controller/pinctrl.c | 6 ++-- - 4 files changed, 51 insertions(+), 46 deletions(-) - -diff --git a/lib/conntrack.c b/lib/conntrack.c -index b56ef06ac..43fd510ef 100644 ---- a/lib/conntrack.c -+++ b/lib/conntrack.c -@@ -718,7 +718,7 @@ reverse_nat_packet(struct dp_packet *pkt, const struct conn *conn) - icmp->icmp_csum = csum(icmp, tail - (char *) icmp - pad); - } else { - struct ovs_16aligned_ip6_hdr *nh6 = dp_packet_l3(pkt); -- struct icmp6_error_header *icmp6 = dp_packet_l4(pkt); -+ struct icmp6_data_header *icmp6 = dp_packet_l4(pkt); - struct ovs_16aligned_ip6_hdr *inner_l3_6 = - (struct ovs_16aligned_ip6_hdr *) (icmp6 + 1); - /* This call is already verified to succeed during the code path from -diff --git a/lib/flow.c b/lib/flow.c -index db84b01f2..0ba146272 100644 ---- a/lib/flow.c -+++ b/lib/flow.c -@@ -399,14 +399,14 @@ parse_ethertype(const void **datap, size_t *sizep) - * and 'arp_buf[]' are filled in. If the packet is not an ND packet, 'false' - * is returned and no values are filled in on '*nd_target' or 'arp_buf[]'. */ - static inline bool --parse_icmpv6(const void **datap, size_t *sizep, const struct icmp6_hdr *icmp, -- uint32_t *rso_flags, const struct in6_addr **nd_target, -+parse_icmpv6(const void **datap, size_t *sizep, -+ const struct icmp6_data_header *icmp6, -+ ovs_be32 *rso_flags, const struct in6_addr **nd_target, - struct eth_addr arp_buf[2], uint8_t *opt_type) - { -- const uint32_t *reserved; -- if (icmp->icmp6_code != 0 || -- (icmp->icmp6_type != ND_NEIGHBOR_SOLICIT && -- icmp->icmp6_type != ND_NEIGHBOR_ADVERT)) { -+ if (icmp6->icmp6_base.icmp6_code != 0 || -+ (icmp6->icmp6_base.icmp6_type != ND_NEIGHBOR_SOLICIT && -+ icmp6->icmp6_base.icmp6_type != ND_NEIGHBOR_ADVERT)) { - return false; - } - -@@ -414,12 +414,7 @@ parse_icmpv6(const void **datap, size_t *sizep, const struct icmp6_hdr *icmp, - arp_buf[1] = eth_addr_zero; - *opt_type = 0; - -- reserved = data_try_pull(datap, sizep, sizeof(uint32_t)); -- if (OVS_UNLIKELY(!reserved)) { -- /* Invalid ND packet. */ -- return false; -- } -- *rso_flags = *reserved; -+ *rso_flags = get_16aligned_be32(icmp6->icmp6_data.be32); - - *nd_target = data_try_pull(datap, sizep, sizeof **nd_target); - if (OVS_UNLIKELY(!*nd_target)) { -@@ -1027,17 +1022,18 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst) - miniflow_pad_to_64(mf, igmp_group_ip4); - } - } else if (OVS_LIKELY(nw_proto == IPPROTO_ICMPV6)) { -- if (OVS_LIKELY(size >= sizeof(struct icmp6_hdr))) { -+ if (OVS_LIKELY(size >= sizeof(struct icmp6_data_header))) { - const struct in6_addr *nd_target; - struct eth_addr arp_buf[2]; - /* This will populate whether we received Option 1 - * or Option 2. */ - uint8_t opt_type; - /* This holds the ND Reserved field. */ -- uint32_t rso_flags; -- const struct icmp6_hdr *icmp = data_pull(&data, -- &size,ICMP6_HEADER_LEN); -- if (parse_icmpv6(&data, &size, icmp, -+ ovs_be32 rso_flags; -+ const struct icmp6_data_header *icmp6; -+ -+ icmp6 = data_pull(&data, &size, sizeof *icmp6); -+ if (parse_icmpv6(&data, &size, icmp6, - &rso_flags, &nd_target, arp_buf, &opt_type)) { - if (nd_target) { - miniflow_push_words(mf, nd_target, nd_target, -@@ -1056,16 +1052,20 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst) - * This will zero out the tcp_flags & pad3 field. */ - miniflow_pad_to_64(mf, arp_tha); - } -- miniflow_push_be16(mf, tp_src, htons(icmp->icmp6_type)); -- miniflow_push_be16(mf, tp_dst, htons(icmp->icmp6_code)); -+ miniflow_push_be16(mf, tp_src, -+ htons(icmp6->icmp6_base.icmp6_type)); -+ miniflow_push_be16(mf, tp_dst, -+ htons(icmp6->icmp6_base.icmp6_code)); - miniflow_pad_to_64(mf, tp_dst); - /* Fill ND reserved field. */ -- miniflow_push_be32(mf, igmp_group_ip4, htonl(rso_flags)); -+ miniflow_push_be32(mf, igmp_group_ip4, rso_flags); - miniflow_pad_to_64(mf, igmp_group_ip4); - } else { - /* ICMPv6 but not ND. */ -- miniflow_push_be16(mf, tp_src, htons(icmp->icmp6_type)); -- miniflow_push_be16(mf, tp_dst, htons(icmp->icmp6_code)); -+ miniflow_push_be16(mf, tp_src, -+ htons(icmp6->icmp6_base.icmp6_type)); -+ miniflow_push_be16(mf, tp_dst, -+ htons(icmp6->icmp6_base.icmp6_code)); - miniflow_push_be16(mf, ct_tp_src, ct_tp_src); - miniflow_push_be16(mf, ct_tp_dst, ct_tp_dst); - } -@@ -3038,15 +3038,16 @@ flow_compose_l4(struct dp_packet *p, const struct flow *flow, - igmp->igmp_code = ntohs(flow->tp_dst); - put_16aligned_be32(&igmp->group, flow->igmp_group_ip4); - } else if (flow->nw_proto == IPPROTO_ICMPV6) { -- struct icmp6_hdr *icmp = dp_packet_put_zeros(p, sizeof *icmp); -- icmp->icmp6_type = ntohs(flow->tp_src); -- icmp->icmp6_code = ntohs(flow->tp_dst); -- uint32_t *reserved = &icmp->icmp6_dataun.icmp6_un_data32[0]; -- *reserved = ntohl(flow->igmp_group_ip4); -- -- if (icmp->icmp6_code == 0 && -- (icmp->icmp6_type == ND_NEIGHBOR_SOLICIT || -- icmp->icmp6_type == ND_NEIGHBOR_ADVERT)) { -+ struct icmp6_data_header *icmp6; -+ -+ icmp6 = dp_packet_put_zeros(p, sizeof *icmp6); -+ icmp6->icmp6_base.icmp6_type = ntohs(flow->tp_src); -+ icmp6->icmp6_base.icmp6_code = ntohs(flow->tp_dst); -+ put_16aligned_be32(icmp6->icmp6_data.be32, flow->igmp_group_ip4); -+ -+ if (icmp6->icmp6_base.icmp6_code == 0 && -+ (icmp6->icmp6_base.icmp6_type == ND_NEIGHBOR_SOLICIT || -+ icmp6->icmp6_base.icmp6_type == ND_NEIGHBOR_ADVERT)) { - struct in6_addr *nd_target; - struct ovs_nd_lla_opt *lla_opt; - -@@ -3065,9 +3066,9 @@ flow_compose_l4(struct dp_packet *p, const struct flow *flow, - lla_opt->type = ND_OPT_TARGET_LINKADDR; - lla_opt->mac = flow->arp_tha; - } -- } else if (icmp->icmp6_code == 0 && -- (icmp->icmp6_type == ICMP6_ECHO_REQUEST || -- icmp->icmp6_type == ICMP6_ECHO_REPLY)) { -+ } else if (icmp6->icmp6_base.icmp6_code == 0 && -+ (icmp6->icmp6_base.icmp6_type == ICMP6_ECHO_REQUEST || -+ icmp6->icmp6_base.icmp6_type == ICMP6_ECHO_REPLY)) { - flow_compose_l7(p, l7, l7_len); - } else { - /* XXX Add inner IP packet for e.g. destination unreachable? */ -@@ -3112,11 +3113,11 @@ flow_compose_l4_csum(struct dp_packet *p, const struct flow *flow, - igmp->igmp_csum = 0; - igmp->igmp_csum = csum(igmp, l4_len); - } else if (flow->nw_proto == IPPROTO_ICMPV6) { -- struct icmp6_hdr *icmp = dp_packet_l4(p); -+ struct icmp6_data_header *icmp6 = dp_packet_l4(p); - -- icmp->icmp6_cksum = 0; -- icmp->icmp6_cksum = (OVS_FORCE uint16_t) -- csum_finish(csum_continue(pseudo_hdr_csum, icmp, l4_len)); -+ icmp6->icmp6_base.icmp6_cksum = 0; -+ icmp6->icmp6_base.icmp6_cksum = -+ csum_finish(csum_continue(pseudo_hdr_csum, icmp6, l4_len)); - } - } - } -diff --git a/lib/packets.h b/lib/packets.h -index 05040a8e0..648dbd770 100644 ---- a/lib/packets.h -+++ b/lib/packets.h -@@ -961,12 +961,16 @@ struct icmp6_header { - }; - BUILD_ASSERT_DECL(ICMP6_HEADER_LEN == sizeof(struct icmp6_header)); - --#define ICMP6_ERROR_HEADER_LEN 8 --struct icmp6_error_header { -+#define ICMP6_DATA_HEADER_LEN 8 -+struct icmp6_data_header { - struct icmp6_header icmp6_base; -- ovs_be32 icmp6_error_ext; -+ union { -+ ovs_16aligned_be32 be32[1]; -+ ovs_be16 be16[2]; -+ uint8_t u8[4]; -+ } icmp6_data; - }; --BUILD_ASSERT_DECL(ICMP6_ERROR_HEADER_LEN == sizeof(struct icmp6_error_header)); -+BUILD_ASSERT_DECL(ICMP6_DATA_HEADER_LEN == sizeof(struct icmp6_data_header)); - - uint32_t packet_csum_pseudoheader6(const struct ovs_16aligned_ip6_hdr *); - ovs_be16 packet_csum_upperlayer6(const struct ovs_16aligned_ip6_hdr *, -diff --git a/ovn/controller/pinctrl.c b/ovn/controller/pinctrl.c -index af68f0f6b..d74e0bc7a 100644 ---- a/ovn/controller/pinctrl.c -+++ b/ovn/controller/pinctrl.c -@@ -842,14 +842,14 @@ pinctrl_handle_icmp(struct rconn *swconn, const struct flow *ip_flow, - } - } else { - struct ip6_hdr *nh = dp_packet_put_zeros(&packet, sizeof *nh); -- struct icmp6_error_header *ih; -+ struct icmp6_data_header *ih; - uint32_t icmpv6_csum; - - eh->eth_type = htons(ETH_TYPE_IPV6); - dp_packet_set_l3(&packet, nh); - nh->ip6_vfc = 0x60; - nh->ip6_nxt = IPPROTO_ICMPV6; -- nh->ip6_plen = htons(sizeof(*nh) + ICMP6_ERROR_HEADER_LEN); -+ nh->ip6_plen = htons(sizeof(*nh) + ICMP6_DATA_HEADER_LEN); - packet_set_ipv6(&packet, &ip_flow->ipv6_src, &ip_flow->ipv6_dst, - ip_flow->nw_tos, ip_flow->ipv6_label, 255); - -@@ -865,7 +865,7 @@ pinctrl_handle_icmp(struct rconn *swconn, const struct flow *ip_flow, - icmpv6_csum = packet_csum_pseudoheader6(dp_packet_l3(&packet)); - ih->icmp6_base.icmp6_cksum = csum_finish( - csum_continue(icmpv6_csum, ih, -- sizeof(*nh) + ICMP6_ERROR_HEADER_LEN)); -+ sizeof(*nh) + ICMP6_DATA_HEADER_LEN)); - } - - if (ip_flow->vlans[0].tci & htons(VLAN_CFI)) { --- -2.14.1 - - diff --git a/flow-fix-incorrect-padding-length-checking-in-ipv6_s.patch b/flow-fix-incorrect-padding-length-checking-in-ipv6_s.patch deleted file mode 100644 index ac0e70a33c81b4d673d2f25c5a34d948b71eb5eb..0000000000000000000000000000000000000000 --- a/flow-fix-incorrect-padding-length-checking-in-ipv6_s.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 3c22f70994279bc206a78d9a1f40702beb9864d1 Mon Sep 17 00:00:00 2001 -From: Yanqin Wei -Date: Mon, 2 Sep 2019 16:36:47 +0800 -Subject: flow: fix incorrect padding length checking in ipv6_sanity_check - -The padding length is (packet size - ipv6 header length - ipv6 plen). This -patch fixes incorrect padding size checking in ipv6_sanity_check. - -Acked-by: William Tu -Reviewed-by: Gavin Hu -Signed-off-by: Yanqin Wei -Signed-off-by: Ben Pfaff ---- - lib/flow.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/lib/flow.c b/lib/flow.c -index e54fd2e52..db84b01f2 100644 ---- a/lib/flow.c -+++ b/lib/flow.c -@@ -699,7 +699,7 @@ ipv6_sanity_check(const struct ovs_16aligned_ip6_hdr *nh, size_t size) - return false; - } - /* Jumbo Payload option not supported yet. */ -- if (OVS_UNLIKELY(size - plen > UINT8_MAX)) { -+ if (OVS_UNLIKELY(size - (plen + IPV6_HEADER_LEN) > UINT8_MAX)) { - return false; - } - --- -2.14.1 - - diff --git a/ipf-bail-out-when-ipf-state-is-COMPLETED.patch b/ipf-bail-out-when-ipf-state-is-COMPLETED.patch deleted file mode 100644 index 58e1297d6be50c6a37917ab263e7a2b00494f185..0000000000000000000000000000000000000000 --- a/ipf-bail-out-when-ipf-state-is-COMPLETED.patch +++ /dev/null @@ -1,41 +0,0 @@ -From af2cab63f95dfd84f3ae105524bd3fb7377a7391 Mon Sep 17 00:00:00 2001 -From: Li RongQing -Date: Thu, 14 Nov 2019 17:18:18 +0800 -Subject: ipf: bail out when ipf state is COMPLETED - -it is easy to crash ovs when a packet with same id -hits a list that already reassembled completedly -but have not been sent out yet, and this packet is -not duplicate with this hit ipf list due to bigger -offset - - 1 0x00007f9fef0ae2d9 in __GI_abort () at abort.c:89 - 2 0x0000000000464042 in ipf_list_state_transition at lib/ipf.c:545 - -Fixes: 4ea96698f667 ("Userspace datapath: Add fragmentation handling.") -Co-authored-by: Wang Li -Signed-off-by: Wang Li -Signed-off-by: Li RongQing -Signed-off-by: Ben Pfaff ---- - lib/ipf.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/lib/ipf.c b/lib/ipf.c -index 4cc0f2df6..45c489122 100644 ---- a/lib/ipf.c -+++ b/lib/ipf.c -@@ -899,7 +899,8 @@ ipf_handle_frag(struct ipf *ipf, struct dp_packet *pkt, ovs_be16 dl_type, - MIN(max_frag_list_size, IPF_FRAG_LIST_MIN_INCREMENT)); - hmap_insert(&ipf->frag_lists, &ipf_list->node, hash); - ipf_expiry_list_add(&ipf->frag_exp_list, ipf_list, now); -- } else if (ipf_list->state == IPF_LIST_STATE_REASS_FAIL) { -+ } else if (ipf_list->state == IPF_LIST_STATE_REASS_FAIL || -+ ipf_list->state == IPF_LIST_STATE_COMPLETED) { - /* Bail out as early as possible. */ - return false; - } else if (ipf_list->last_inuse_idx + 1 >= ipf_list->size) { --- -2.14.1 - - diff --git a/jsonrpc-increase-input-buffer-size-from-512-to-4096.patch b/jsonrpc-increase-input-buffer-size-from-512-to-4096.patch deleted file mode 100644 index b81b58461f1a2545d98be276dcd958c922a4a988..0000000000000000000000000000000000000000 --- a/jsonrpc-increase-input-buffer-size-from-512-to-4096.patch +++ /dev/null @@ -1,32 +0,0 @@ -From a451bfa8b0b7d5930d92497eccd29a6d2b781b8b Mon Sep 17 00:00:00 2001 -From: Lorenzo Bianconi -Date: Wed, 6 Nov 2019 11:19:44 +0200 -Subject: jsonrpc: increase input buffer size from 512 to 4096 - -Increase jsonrpc input buffer size from 512 to 4096 bytes in order to -reduce the syscall overhead when downloading huge db size - -Acked-by: Mark Michelson -Signed-off-by: Lorenzo Bianconi -Signed-off-by: Ben Pfaff ---- - lib/jsonrpc.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/lib/jsonrpc.c b/lib/jsonrpc.c -index b9619b822..ed748dbde 100644 ---- a/lib/jsonrpc.c -+++ b/lib/jsonrpc.c -@@ -43,7 +43,7 @@ struct jsonrpc { - - /* Input. */ - struct byteq input; -- uint8_t input_buffer[512]; -+ uint8_t input_buffer[4096]; - struct json_parser *parser; - - /* Output. */ --- -2.14.1 - - diff --git a/lflow.c-Fix-memory-leak-of-lflow_ref_list_node-ref_n.patch b/lflow.c-Fix-memory-leak-of-lflow_ref_list_node-ref_n.patch deleted file mode 100644 index a1bb3523ff2a5b5ae5ac752e473a5ce37a122dc5..0000000000000000000000000000000000000000 --- a/lflow.c-Fix-memory-leak-of-lflow_ref_list_node-ref_n.patch +++ /dev/null @@ -1,50 +0,0 @@ -From e4c825d1826d8de5dfec9534b18421de4e46b300 Mon Sep 17 00:00:00 2001 -From: Han Zhou -Date: Wed, 30 Oct 2019 22:51:12 -0700 -Subject: lflow.c: Fix memory leak of lflow_ref_list_node->ref_name. - -The ref_name is copied in lflow_resource_add(), but forgot to free in -lflow_resource_destroy_lflow(). It can be fixed by freeing it in -lflow_resource_destroy_lflow(). However, this field is never really -used, so just delete it from lflow_ref_list_node, together with the -"type" field. - -Fixes: 43e6900a7991 ("ovn-controller: Maintain resource references for logical flows.") -Acked-by: Numan Siddique -Signed-off-by: Han Zhou -Signed-off-by: Ben Pfaff ---- - ovn/controller/lflow.c | 2 -- - ovn/controller/lflow.h | 2 -- - 2 files changed, 4 deletions(-) - -diff --git a/ovn/controller/lflow.c b/ovn/controller/lflow.c -index 1aafafb33..dd72a5b46 100644 ---- a/ovn/controller/lflow.c -+++ b/ovn/controller/lflow.c -@@ -230,8 +230,6 @@ lflow_resource_add(struct lflow_resource_ref *lfrr, enum ref_type type, - } - - struct lflow_ref_list_node *lrln = xzalloc(sizeof *lrln); -- lrln->type = type; -- lrln->ref_name = xstrdup(ref_name); - lrln->lflow_uuid = *lflow_uuid; - ovs_list_push_back(&rlfn->ref_lflow_head, &lrln->ref_list); - ovs_list_push_back(&lfrn->lflow_ref_head, &lrln->lflow_list); -diff --git a/ovn/controller/lflow.h b/ovn/controller/lflow.h -index 4e1086eb6..752bd5906 100644 ---- a/ovn/controller/lflow.h -+++ b/ovn/controller/lflow.h -@@ -79,8 +79,6 @@ enum ref_type { - struct lflow_ref_list_node { - struct ovs_list lflow_list; /* list for same lflow */ - struct ovs_list ref_list; /* list for same ref */ -- enum ref_type type; -- char *ref_name; - struct uuid lflow_uuid; - }; - --- -2.14.1 - - diff --git a/lib-tc-Fix-flow-dump-for-tunnel-id-equal-zero.patch b/lib-tc-Fix-flow-dump-for-tunnel-id-equal-zero.patch deleted file mode 100644 index 6f171655e0a2d82f96e838d5275018e5281626f7..0000000000000000000000000000000000000000 --- a/lib-tc-Fix-flow-dump-for-tunnel-id-equal-zero.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 9de253c75f2ed8fe298a49e0927e079369f17d31 Mon Sep 17 00:00:00 2001 -From: Dmytro Linkin -Date: Wed, 30 Oct 2019 14:40:35 +0200 -Subject: lib/tc: Fix flow dump for tunnel id equal zero - -Tunnel id 0 is not printed unless tunnel flag FLOW_TNL_F_KEY is set. -Fix that by always setting FLOW_TNL_F_KEY when tunnel id is valid. - -Fixes: 0227bf092ee6 ("lib/tc: Support optional tunnel id") -Signed-off-by: Dmytro Linkin -Reviewed-by: Roi Dayan -Signed-off-by: Simon Horman ---- - lib/netdev-offload-tc.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c -index a6b03015d..45d02ba21 100644 ---- a/lib/netdev-offload-tc.c -+++ b/lib/netdev-offload-tc.c -@@ -600,6 +600,7 @@ parse_tc_flower_to_match(struct tc_flower *flower, - if (flower->tunnel) { - if (flower->mask.tunnel.id) { - match_set_tun_id(match, flower->key.tunnel.id); -+ match->flow.tunnel.flags |= FLOW_TNL_F_KEY; - } - if (flower->key.tunnel.ipv4.ipv4_dst) { - match_set_tun_src(match, flower->key.tunnel.ipv4.ipv4_src); --- -2.14.1 - - diff --git a/lldp-Fix-for-OVS-crashes-when-a-LLDP-enabled-port-is.patch b/lldp-Fix-for-OVS-crashes-when-a-LLDP-enabled-port-is.patch deleted file mode 100644 index 4d725404f40dabe722f1baba2b596eed06111bcc..0000000000000000000000000000000000000000 --- a/lldp-Fix-for-OVS-crashes-when-a-LLDP-enabled-port-is.patch +++ /dev/null @@ -1,78 +0,0 @@ -From 3642294da976cf090755e9df823fd67d0ff86e4d Mon Sep 17 00:00:00 2001 -From: Surya Rudra -Date: Mon, 21 Oct 2019 12:42:02 +0530 -Subject: lldp: Fix for OVS crashes when a LLDP-enabled port is deleted - -Issue: -When LLDP is enabled on a port, a structure to hold LLDP related state -is created and that structure has a reference to the port. The ofproto -monitor thread accesses the LLDP structure to periodically send packets -over the associated port. When the port is deleted, the LLDP structure -is not cleaned up and it continues to refer to the deleted port. - -When the monitor thread attempts to access the deleted port OVS crashes. -Crash can happen with bridge delete and bond delete also. - -Fix: -Remove all references to the LLDP structure and free it when -the port is deleted. - -Signed-off-by: Surya Rudra -Signed-off-by: Ben Pfaff ---- - ofproto/ofproto-dpif.c | 10 +++++----- - ofproto/ofproto.c | 3 +++ - 2 files changed, 8 insertions(+), 5 deletions(-) - -diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c -index 7bb0f7bdb..a8c7369d0 100644 ---- a/ofproto/ofproto-dpif.c -+++ b/ofproto/ofproto-dpif.c -@@ -2280,24 +2280,24 @@ set_lldp(struct ofport *ofport_, - const struct smap *cfg) - { - struct ofport_dpif *ofport = ofport_dpif_cast(ofport_); -+ struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofport->up.ofproto); - int error = 0; - - if (cfg) { - if (!ofport->lldp) { -- struct ofproto_dpif *ofproto; -- -- ofproto = ofproto_dpif_cast(ofport->up.ofproto); - ofproto->backer->need_revalidate = REV_RECONFIGURE; - ofport->lldp = lldp_create(ofport->up.netdev, ofport_->mtu, cfg); - } - - if (!lldp_configure(ofport->lldp, cfg)) { -+ lldp_unref(ofport->lldp); -+ ofport->lldp = NULL; - error = EINVAL; - } -- } -- if (error) { -+ } else if (ofport->lldp) { - lldp_unref(ofport->lldp); - ofport->lldp = NULL; -+ ofproto->backer->need_revalidate = REV_RECONFIGURE; - } - - ofproto_dpif_monitor_port_update(ofport, -diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c -index 1d6fc0069..6ffaced18 100644 ---- a/ofproto/ofproto.c -+++ b/ofproto/ofproto.c -@@ -2511,6 +2511,9 @@ ofproto_port_unregister(struct ofproto *ofproto, ofp_port_t ofp_port) - { - struct ofport *port = ofproto_get_port(ofproto, ofp_port); - if (port) { -+ if (port->ofproto->ofproto_class->set_lldp) { -+ port->ofproto->ofproto_class->set_lldp(port, NULL); -+ } - if (port->ofproto->ofproto_class->set_stp_port) { - port->ofproto->ofproto_class->set_stp_port(port, NULL); - } --- -2.14.1 - - diff --git a/netdev-afxdp-Avoid-removing-of-XDP-program-if-not-lo.patch b/netdev-afxdp-Avoid-removing-of-XDP-program-if-not-lo.patch deleted file mode 100644 index 2010cfbf802a1aa6f34e571eda62c3fc6b621707..0000000000000000000000000000000000000000 --- a/netdev-afxdp-Avoid-removing-of-XDP-program-if-not-lo.patch +++ /dev/null @@ -1,61 +0,0 @@ -From c0ce219ead0086f1bf79ff6071df1822ee0804c9 Mon Sep 17 00:00:00 2001 -From: Ilya Maximets -Date: Sat, 7 Dec 2019 15:46:17 +0100 -Subject: netdev-afxdp: Avoid removing of XDP program if not loaded. - -'bpf_set_link_xdp_fd' generates netlink event regardless of actual -changes it does, so if-notifier will receive link update even if -there was no XDP program previously loaded on the interface. - -OVS tries to remove XDP program if device configuration was not -successful triggering if-notifier that triggers bridge reconfiguration -and another attempt to add failed port. And so on in the infinite -loop. - -This patch avoids the issue by not removing XDP program if it wasn't -loaded. Since loading of the XDP program is one of the last steps -of port configuration, this should help to avoid infinite re-addition -for most types of misconfiguration. - -Signed-off-by: Ilya Maximets -Acked-by: William Tu ---- - lib/netdev-afxdp.c | 14 +++++++++++++- - 1 file changed, 13 insertions(+), 1 deletion(-) - -diff --git a/lib/netdev-afxdp.c b/lib/netdev-afxdp.c -index 7b452c459..ad66e8e7c 100644 ---- a/lib/netdev-afxdp.c -+++ b/lib/netdev-afxdp.c -@@ -568,7 +568,7 @@ netdev_afxdp_get_numa_id(const struct netdev *netdev) - static void - xsk_remove_xdp_program(uint32_t ifindex, int xdpmode) - { -- uint32_t flags; -+ uint32_t ret, flags, prog_id = 0; - - flags = XDP_FLAGS_UPDATE_IF_NOEXIST; - -@@ -578,6 +578,18 @@ xsk_remove_xdp_program(uint32_t ifindex, int xdpmode) - flags |= XDP_FLAGS_DRV_MODE; - } - -+ /* Check whether XDP program is loaded. */ -+ ret = bpf_get_link_xdp_id(ifindex, &prog_id, flags); -+ if (ret) { -+ VLOG_ERR("Failed to get XDP prog id (%s)", ovs_strerror(errno)); -+ return; -+ } -+ -+ if (!prog_id) { -+ VLOG_INFO("No XDP program is loaded at ifindex %d", ifindex); -+ return; -+ } -+ - bpf_set_link_xdp_fd(ifindex, -1, flags); - } - --- -2.14.1 - - diff --git a/netdev-afxdp-Fix-umem-creation-failure-due-to-uninit.patch b/netdev-afxdp-Fix-umem-creation-failure-due-to-uninit.patch deleted file mode 100644 index 6820be743cdfd6dc79580f7ee71eade13ac7ad00..0000000000000000000000000000000000000000 --- a/netdev-afxdp-Fix-umem-creation-failure-due-to-uninit.patch +++ /dev/null @@ -1,37 +0,0 @@ -From e3d50e225545b6307aa7157fd5740bfdc040223e Mon Sep 17 00:00:00 2001 -From: Ilya Maximets -Date: Wed, 9 Oct 2019 16:17:58 +0200 -Subject: netdev-afxdp: Fix umem creation failure due to uninitialized config. - -Later version of 'struct xsk_umem_config' contains additional field -'flags'. OVS doesn't use that field passing uninitialized stack -memory to the 'xsk_umem__create()' call that could fail with -'Invalid argument' if 'flags' are non-zero or, even worse, create -umem with unexpected properties. - -We need to clear the whole structure explicitly to avoid this kind -of issues. - -Fixes: 0de1b425962d ("netdev-afxdp: add new netdev type for AF_XDP.") -Signed-off-by: Ilya Maximets -Signed-off-by: William Tu ---- - lib/netdev-afxdp.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/lib/netdev-afxdp.c b/lib/netdev-afxdp.c -index 6486c8233..47b4af59d 100644 ---- a/lib/netdev-afxdp.c -+++ b/lib/netdev-afxdp.c -@@ -168,6 +168,7 @@ xsk_configure_umem(void *buffer, uint64_t size, int xdpmode) - - umem = xzalloc(sizeof *umem); - -+ memset(&uconfig, 0, sizeof uconfig); - uconfig.fill_size = PROD_NUM_DESCS; - uconfig.comp_size = CONS_NUM_DESCS; - uconfig.frame_size = FRAME_SIZE; --- -2.14.1 - - diff --git a/netdev-afxdp-Update-memory-locking-limits-unconditio.patch b/netdev-afxdp-Update-memory-locking-limits-unconditio.patch deleted file mode 100644 index 0c47e1bb969c47b0913aac5edf782a34f6a588fb..0000000000000000000000000000000000000000 --- a/netdev-afxdp-Update-memory-locking-limits-unconditio.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 069c80b47ff2fa4e7b4e455568c995e4fe8f3a18 Mon Sep 17 00:00:00 2001 -From: Ilya Maximets -Date: Wed, 9 Oct 2019 16:23:31 +0200 -Subject: netdev-afxdp: Update memory locking limits unconditionally. - -Any type of AF_XDP socket in all modes implies creation of BPF map of -type BPF_MAP_TYPE_XSKMAP. This leads to BPF_MAP_CREATE syscall and -subsequently 'xsk_map_alloc()' function that will charge required -memory from the memlock limit and fail with EPERM if we're trying -to allocate more. - -On my system with 64K bytes of max locked memory by default, OVS -frequently starts to fail after addition of 3rd afxdp port in SKB -mode: - - netdev_afxdp|ERR|xsk_socket__create failed (Operation not permitted) - mode: SKB qid: 0 - -Fixes: 0de1b425962d ("netdev-afxdp: add new netdev type for AF_XDP.") -Signed-off-by: Ilya Maximets -Signed-off-by: William Tu ---- - lib/netdev-afxdp.c | 19 ++++++------------- - 1 file changed, 6 insertions(+), 13 deletions(-) - -diff --git a/lib/netdev-afxdp.c b/lib/netdev-afxdp.c -index 47b4af59d..7b452c459 100644 ---- a/lib/netdev-afxdp.c -+++ b/lib/netdev-afxdp.c -@@ -536,19 +536,12 @@ netdev_afxdp_reconfigure(struct netdev *netdev) - netdev->n_rxq = dev->requested_n_rxq; - netdev->n_txq = netdev->n_rxq; - -- if (dev->requested_xdpmode == XDP_ZEROCOPY) { -- dev->xdpmode = XDP_ZEROCOPY; -- VLOG_INFO("AF_XDP device %s in DRV mode.", netdev_get_name(netdev)); -- if (setrlimit(RLIMIT_MEMLOCK, &r)) { -- VLOG_ERR("ERROR: setrlimit(RLIMIT_MEMLOCK): %s", -- ovs_strerror(errno)); -- } -- } else { -- dev->xdpmode = XDP_COPY; -- VLOG_INFO("AF_XDP device %s in SKB mode.", netdev_get_name(netdev)); -- /* TODO: set rlimit back to previous value -- * when no device is in DRV mode. -- */ -+ dev->xdpmode = dev->requested_xdpmode; -+ VLOG_INFO("%s: Setting XDP mode to %s.", netdev_get_name(netdev), -+ dev->xdpmode == XDP_ZEROCOPY ? "DRV" : "SKB"); -+ -+ if (setrlimit(RLIMIT_MEMLOCK, &r)) { -+ VLOG_ERR("setrlimit(RLIMIT_MEMLOCK) failed: %s", ovs_strerror(errno)); - } - - err = xsk_configure_all(netdev); --- -2.14.1 - - diff --git a/netdev-dpdk-Fix-flow-control-not-configuring.patch b/netdev-dpdk-Fix-flow-control-not-configuring.patch deleted file mode 100644 index 0436cdbb52d7da0cfc7acfcbe8f86aa540e921b2..0000000000000000000000000000000000000000 --- a/netdev-dpdk-Fix-flow-control-not-configuring.patch +++ /dev/null @@ -1,76 +0,0 @@ -From cb7e9a8240d6a46de831bf549abc6282a59d5edd Mon Sep 17 00:00:00 2001 -From: Tomasz Konieczny -Date: Thu, 12 Sep 2019 12:43:20 +0200 -Subject: netdev-dpdk: Fix flow control not configuring. - -Currently OVS is unable to change flow control configuration in DPDK -because new settings are being overwritten by current settings with -rte_eth_dev_flow_ctrl_get(). The fix restores correct order of -operations and at the same time does not trigger error on devices -without flow control support when flow control not requested. - -Fixes: 7e1de65e8dfb ("netdev-dpdk: Fix failure to configure flow control at netdev-init.") -Signed-off-by: Tomasz Konieczny -Co-authored-by: Ilya Maximets -Signed-off-by: Ilya Maximets ---- - lib/netdev-dpdk.c | 32 ++++++++++++++++++++++++++------ - 1 file changed, 26 insertions(+), 6 deletions(-) - -diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c -index 5466499b4..0bb826111 100644 ---- a/lib/netdev-dpdk.c -+++ b/lib/netdev-dpdk.c -@@ -1805,6 +1805,7 @@ netdev_dpdk_set_config(struct netdev *netdev, const struct smap *args, - { - struct netdev_dpdk *dev = netdev_dpdk_cast(netdev); - bool rx_fc_en, tx_fc_en, autoneg, lsc_interrupt_mode; -+ bool flow_control_requested = true; - enum rte_eth_fc_mode fc_mode; - static const enum rte_eth_fc_mode fc_mode_set[2][2] = { - {RTE_FC_NONE, RTE_FC_TX_PAUSE}, -@@ -1892,15 +1893,34 @@ netdev_dpdk_set_config(struct netdev *netdev, const struct smap *args, - autoneg = smap_get_bool(args, "flow-ctrl-autoneg", false); - - fc_mode = fc_mode_set[tx_fc_en][rx_fc_en]; -+ -+ if (!smap_get(args, "rx-flow-ctrl") && !smap_get(args, "tx-flow-ctrl") -+ && !smap_get(args, "flow-ctrl-autoneg")) { -+ /* FIXME: User didn't ask for flow control configuration. -+ * For now we'll not print a warning if flow control is not -+ * supported by the DPDK port. */ -+ flow_control_requested = false; -+ } -+ -+ /* Get the Flow control configuration. */ -+ err = -rte_eth_dev_flow_ctrl_get(dev->port_id, &dev->fc_conf); -+ if (err) { -+ if (err == ENOTSUP) { -+ if (flow_control_requested) { -+ VLOG_WARN("%s: Flow control is not supported.", -+ netdev_get_name(netdev)); -+ } -+ err = 0; /* Not fatal. */ -+ } else { -+ VLOG_WARN("%s: Cannot get flow control parameters: %s", -+ netdev_get_name(netdev), rte_strerror(err)); -+ } -+ goto out; -+ } -+ - if (dev->fc_conf.mode != fc_mode || autoneg != dev->fc_conf.autoneg) { - dev->fc_conf.mode = fc_mode; - dev->fc_conf.autoneg = autoneg; -- /* Get the Flow control configuration for DPDK-ETH */ -- err = rte_eth_dev_flow_ctrl_get(dev->port_id, &dev->fc_conf); -- if (err) { -- VLOG_WARN("Cannot get flow control parameters on port " -- DPDK_PORT_ID_FMT", err=%d", dev->port_id, err); -- } - dpdk_eth_flow_ctrl_setup(dev); - } - --- -2.14.1 - - diff --git a/netdev-dpdk-Fix-padding-info-comment.patch b/netdev-dpdk-Fix-padding-info-comment.patch deleted file mode 100644 index 8ea89422b53d0f7fb3bceef95e95cc25c1f5a2e8..0000000000000000000000000000000000000000 --- a/netdev-dpdk-Fix-padding-info-comment.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 0976ef00a5e5a1e79ce74f8bbb2e9243851c4c00 Mon Sep 17 00:00:00 2001 -From: Kevin Traynor -Date: Thu, 5 Sep 2019 14:21:09 +0100 -Subject: netdev-dpdk: Fix padding info comment. - -The comment was incorrectly updated. Fix it to the -correct value of 36 pad bytes. - -/* --- cacheline 5 boundary (320 bytes) --- */ -union { - struct { - struct netdev_stats stats; /* 320 336 */ - /* --- cacheline 5 boundary (320 bytes) was 16 bytes ago --- */ - uint64_t tx_retries; /* 656 8 */ - rte_spinlock_t stats_lock; /* 664 4 */ - }; /* 352 */ - uint8_t pad52[384]; /* 384 */ -}; /* 320 384 */ - -Fixes: c161357d5d96 ("netdev-dpdk: Add custom stat for vhost tx retries.") -Reported-by: Ilya Maximets -Signed-off-by: Kevin Traynor -Signed-off-by: Ian Stokes ---- - lib/netdev-dpdk.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c -index 48057835f..5466499b4 100644 ---- a/lib/netdev-dpdk.c -+++ b/lib/netdev-dpdk.c -@@ -451,7 +451,7 @@ struct netdev_dpdk { - uint64_t tx_retries; - /* Protects stats */ - rte_spinlock_t stats_lock; -- /* 4 pad bytes here. */ -+ /* 36 pad bytes here. */ - ); - - PADDED_MEMBERS(CACHE_LINE_SIZE, --- -2.14.1 - - diff --git a/ofproto-Fix-crash-on-PACKET_OUT-due-to-recursive-loc.patch b/ofproto-Fix-crash-on-PACKET_OUT-due-to-recursive-loc.patch deleted file mode 100644 index afd934ce5874bf4d9e6cd4fd3297aa39d4fe6fa7..0000000000000000000000000000000000000000 --- a/ofproto-Fix-crash-on-PACKET_OUT-due-to-recursive-loc.patch +++ /dev/null @@ -1,259 +0,0 @@ -From 458e91300ee08abb6a3936f2549cc5d944c02107 Mon Sep 17 00:00:00 2001 -From: Ilya Maximets -Date: Fri, 1 Nov 2019 22:24:39 +0100 -Subject: ofproto: Fix crash on PACKET_OUT due to recursive locking after upcall. - -Handling of OpenFlow PACKET_OUT implies pushing the packet through -the datapath and packet processing inside the datapath could trigger -an upcall. In case of system datapath, 'dpif_execute()' sends packet -to the kernel module and returns. If any, upcall will be triggered -inside the kernel and handled by a separate thread in userspace. -But in case of userspace datapath full processing of the packet happens -inside the 'dpif_execute()' in the same thread that handled PACKET_OUT. -This causes an issue if upcall will lead to modification of flow rules. -For example, it could happen while processing of 'learn' actions. -Since whole handling of PACKET_OUT is protected by 'ofproto_mutex', -OVS will assert on attempt to take it recursively while processing -'learn' actions: - - 0 __GI_raise (sig=sig@entry=6) - 1 __GI_abort () - 2 ovs_abort_valist () - 3 ovs_abort () - 4 ovs_mutex_lock_at (where=where@entry=0xad4199 "ofproto/ofproto.c:5391") - - 5 ofproto_flow_mod_learn () at ofproto/ofproto.c:5391 - - 6 xlate_learn_action () at ofproto/ofproto-dpif-xlate.c:5378 - <'learn' action found> - 7 do_xlate_actions () at ofproto/ofproto-dpif-xlate.c:6893 - 8 xlate_recursively () at ofproto/ofproto-dpif-xlate.c:4233 - 9 xlate_table_action () at ofproto/ofproto-dpif-xlate.c:4361 - 10 in xlate_ofpact_resubmit () at ofproto/ofproto-dpif-xlate.c:4672 - 11 do_xlate_actions () at ofproto/ofproto-dpif-xlate.c:6773 - 12 xlate_actions () at ofproto/ofproto-dpif-xlate.c:7570 - - 13 upcall_xlate () at ofproto/ofproto-dpif-upcall.c:1197 - 14 process_upcall () at ofproto/ofproto-dpif-upcall.c:1413 - 15 upcall_cb () at ofproto/ofproto-dpif-upcall.c:1315 - 16 dp_netdev_upcall (DPIF_UC_MISS) at lib/dpif-netdev.c:6236 - - 17 handle_packet_upcall () at lib/dpif-netdev.c:6591 - 18 fast_path_processing () at lib/dpif-netdev.c:6709 - 19 dp_netdev_input__ () at lib/dpif-netdev.c:6797 - 20 dp_netdev_recirculate () at lib/dpif-netdev.c:6842 - 21 dp_execute_cb () at lib/dpif-netdev.c:7158 - 22 odp_execute_actions () at lib/odp-execute.c:794 - 23 dp_netdev_execute_actions () at lib/dpif-netdev.c:7332 - 24 dpif_netdev_execute () at lib/dpif-netdev.c:3725 - 25 dpif_netdev_operate () at lib/dpif-netdev.c:3756 - - 26 dpif_operate () at lib/dpif.c:1367 - 27 dpif_execute () at lib/dpif.c:1321 - 28 packet_execute () at ofproto/ofproto-dpif.c:4760 - 29 ofproto_packet_out_finish () at ofproto/ofproto.c:3594 - - 30 handle_packet_out () at ofproto/ofproto.c:3635 - 31 handle_single_part_openflow (OFPTYPE_PACKET_OUT) at ofproto/ofproto.c:8400 - 32 handle_openflow () at ofproto/ofproto.c:8587 - 33 ofconn_run () - 34 connmgr_run () - 35 ofproto_run () - 36 bridge_run__ () - 37 bridge_run () - 38 main () - -Fix that by splitting the 'ofproto_packet_out_finish()' in two parts. -First one that translates side-effects and requires holding 'ofproto_mutex' -and the second that only pushes packet to datapath. The second part moved -out of 'ofproto_mutex' because 'ofproto_mutex' is not required and actually -should not be taken in order to avoid recursive locking. - -Reported-by: Anil Kumar Koli -Reported-at: https://mail.openvswitch.org/pipermail/ovs-discuss/2019-April/048494.html -Signed-off-by: Ilya Maximets -Acked-by: Ben Pfaff ---- - ofproto/ofproto-dpif.c | 40 ++++++++++++++++++++++++++++++---------- - ofproto/ofproto-provider.h | 12 +++++++++--- - ofproto/ofproto.c | 29 +++++++++++++++++++++++++---- - 3 files changed, 64 insertions(+), 17 deletions(-) - -diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c -index c7c70062c..3d6d72a40 100644 ---- a/ofproto/ofproto-dpif.c -+++ b/ofproto/ofproto-dpif.c -@@ -4786,12 +4786,13 @@ ofproto_dpif_xcache_execute(struct ofproto_dpif *ofproto, - } - - static void --packet_execute(struct ofproto *ofproto_, struct ofproto_packet_out *opo) -+packet_execute_prepare(struct ofproto *ofproto_, -+ struct ofproto_packet_out *opo) - OVS_REQUIRES(ofproto_mutex) - { - struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); - struct dpif_flow_stats stats; -- struct dpif_execute execute; -+ struct dpif_execute *execute; - - struct ofproto_dpif_packet_out *aux = opo->aux; - ovs_assert(aux); -@@ -4800,22 +4801,40 @@ packet_execute(struct ofproto *ofproto_, struct ofproto_packet_out *opo) - dpif_flow_stats_extract(opo->flow, opo->packet, time_msec(), &stats); - ofproto_dpif_xcache_execute(ofproto, &aux->xcache, &stats); - -- execute.actions = aux->odp_actions.data; -- execute.actions_len = aux->odp_actions.size; -+ execute = xzalloc(sizeof *execute); -+ execute->actions = xmemdup(aux->odp_actions.data, aux->odp_actions.size); -+ execute->actions_len = aux->odp_actions.size; - - pkt_metadata_from_flow(&opo->packet->md, opo->flow); -- execute.packet = opo->packet; -- execute.flow = opo->flow; -- execute.needs_help = aux->needs_help; -- execute.probe = false; -- execute.mtu = 0; -+ execute->packet = opo->packet; -+ execute->flow = opo->flow; -+ execute->needs_help = aux->needs_help; -+ execute->probe = false; -+ execute->mtu = 0; - - /* Fix up in_port. */ - ofproto_dpif_set_packet_odp_port(ofproto, opo->flow->in_port.ofp_port, - opo->packet); - -- dpif_execute(ofproto->backer->dpif, &execute); - ofproto_dpif_packet_out_delete(aux); -+ opo->aux = execute; -+} -+ -+static void -+packet_execute(struct ofproto *ofproto_, struct ofproto_packet_out *opo) -+ OVS_EXCLUDED(ofproto_mutex) -+{ -+ struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); -+ struct dpif_execute *execute = opo->aux; -+ -+ if (!execute) { -+ return; -+ } -+ -+ dpif_execute(ofproto->backer->dpif, execute); -+ -+ free(CONST_CAST(struct nlattr *, execute->actions)); -+ free(execute); - opo->aux = NULL; - } - -@@ -6194,6 +6213,7 @@ const struct ofproto_class ofproto_dpif_class = { - rule_get_stats, - packet_xlate, - packet_xlate_revert, -+ packet_execute_prepare, - packet_execute, - set_frag_handling, - nxt_resume, -diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h -index 7907d4bfb..d520a6380 100644 ---- a/ofproto/ofproto-provider.h -+++ b/ofproto/ofproto-provider.h -@@ -1368,9 +1368,15 @@ struct ofproto_class { - * packet_xlate_revert() calls have to be made in reverse order. */ - void (*packet_xlate_revert)(struct ofproto *, struct ofproto_packet_out *); - -- /* Executes the datapath actions, translation side-effects, and stats as -- * produced by ->packet_xlate(). The caller retains ownership of 'opo'. -- */ -+ /* Translates side-effects, and stats as produced by ->packet_xlate(). -+ * Prepares to execute datapath actions. The caller retains ownership -+ * of 'opo'. */ -+ void (*packet_execute_prepare)(struct ofproto *, -+ struct ofproto_packet_out *opo); -+ -+ /* Executes the datapath actions. The caller retains ownership of 'opo'. -+ * Should be called after successful packet_execute_prepare(). -+ * No-op if called after packet_xlate_revert(). */ - void (*packet_execute)(struct ofproto *, struct ofproto_packet_out *opo); - - /* Changes the OpenFlow IP fragment handling policy to 'frag_handling', -diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c -index 6ffaced18..715da0607 100644 ---- a/ofproto/ofproto.c -+++ b/ofproto/ofproto.c -@@ -3589,10 +3589,21 @@ ofproto_packet_out_revert(struct ofproto *ofproto, - ofproto->ofproto_class->packet_xlate_revert(ofproto, opo); - } - -+static void -+ofproto_packet_out_prepare(struct ofproto *ofproto, -+ struct ofproto_packet_out *opo) -+ OVS_REQUIRES(ofproto_mutex) -+{ -+ ofproto->ofproto_class->packet_execute_prepare(ofproto, opo); -+} -+ -+/* Execution of packet_out action in datapath could end up in upcall with -+ * subsequent flow translations and possible rule modifications. -+ * So, the caller should not hold 'ofproto_mutex'. */ - static void - ofproto_packet_out_finish(struct ofproto *ofproto, - struct ofproto_packet_out *opo) -- OVS_REQUIRES(ofproto_mutex) -+ OVS_EXCLUDED(ofproto_mutex) - { - ofproto->ofproto_class->packet_execute(ofproto, opo); - } -@@ -3635,10 +3646,13 @@ handle_packet_out(struct ofconn *ofconn, const struct ofp_header *oh) - opo.version = p->tables_version; - error = ofproto_packet_out_start(p, &opo); - if (!error) { -- ofproto_packet_out_finish(p, &opo); -+ ofproto_packet_out_prepare(p, &opo); - } - ovs_mutex_unlock(&ofproto_mutex); - -+ if (!error) { -+ ofproto_packet_out_finish(p, &opo); -+ } - ofproto_packet_out_uninit(&opo); - return error; - } -@@ -8157,7 +8171,7 @@ do_bundle_commit(struct ofconn *ofconn, uint32_t id, uint16_t flags) - } else if (be->type == OFPTYPE_GROUP_MOD) { - ofproto_group_mod_finish(ofproto, &be->ogm, &req); - } else if (be->type == OFPTYPE_PACKET_OUT) { -- ofproto_packet_out_finish(ofproto, &be->opo); -+ ofproto_packet_out_prepare(ofproto, &be->opo); - } - } - if (error) { -@@ -8168,7 +8182,7 @@ do_bundle_commit(struct ofconn *ofconn, uint32_t id, uint16_t flags) - /* Send error referring to the original message. */ - ofconn_send_error(ofconn, be->msg, error); - error = OFPERR_OFPBFC_MSG_FAILED; -- -+ - /* Revert. Undo all the changes made above. */ - LIST_FOR_EACH_REVERSE_CONTINUE (be, node, &bundle->msg_list) { - if (be->type == OFPTYPE_FLOW_MOD) { -@@ -8187,6 +8201,13 @@ do_bundle_commit(struct ofconn *ofconn, uint32_t id, uint16_t flags) - ovs_mutex_unlock(&ofproto_mutex); - } - -+ /* Executing remaining datapath actions. */ -+ LIST_FOR_EACH (be, node, &bundle->msg_list) { -+ if (be->type == OFPTYPE_PACKET_OUT) { -+ ofproto_packet_out_finish(ofproto, &be->opo); -+ } -+ } -+ - /* The bundle is discarded regardless the outcome. */ - ofp_bundle_remove__(ofconn, bundle); - return error; --- -2.14.1 - - diff --git a/ofproto-dpif-Allow-IPv6-ND-Extensions-only-if-suppor.patch b/ofproto-dpif-Allow-IPv6-ND-Extensions-only-if-suppor.patch deleted file mode 100644 index 70ad7206158f35b512e605fd2babb02583dda8cf..0000000000000000000000000000000000000000 --- a/ofproto-dpif-Allow-IPv6-ND-Extensions-only-if-suppor.patch +++ /dev/null @@ -1,180 +0,0 @@ -From df5db2a7a0fe9a4b6f5eafaada20a9b834aebbac Mon Sep 17 00:00:00 2001 -From: Flavio Leitner -Date: Wed, 20 Nov 2019 11:21:13 -0300 -Subject: ofproto-dpif: Allow IPv6 ND Extensions only if supported - -The IPv6 ND Extensions is only implemented in userspace datapath, -but nothing prevents that to be used with other datapaths. - -This patch probes the datapath and only allows if the support -is available. - -Fixes: 9b2b84973 ("Support for match & set ICMPv6 reserved and options type fields") -Acked-by: Eelco Chaudron -Acked-by: Aaron Conole -Signed-off-by: Flavio Leitner -Signed-off-by: Ben Pfaff ---- - lib/odp-util.c | 17 ++++++++------- - lib/odp-util.h | 6 ++++- - ofproto/ofproto-dpif.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++- - tests/test-odp.c | 1 + - 4 files changed, 73 insertions(+), 10 deletions(-) - -diff --git a/lib/odp-util.c b/lib/odp-util.c -index 84ea4c148..df06f8026 100644 ---- a/lib/odp-util.c -+++ b/lib/odp-util.c -@@ -6180,23 +6180,24 @@ odp_flow_key_from_flow__(const struct odp_flow_key_parms *parms, - && (!export_mask || (data->tp_src == htons(0xff) - && data->tp_dst == htons(0xff)))) { - struct ovs_key_nd *nd_key; -- struct ovs_key_nd_extensions *nd_ext_key; - nd_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_ND, - sizeof *nd_key); - nd_key->nd_target = data->nd_target; - nd_key->nd_sll = data->arp_sha; - nd_key->nd_tll = data->arp_tha; - -- /* Add ND Extensions Attr only if reserved field -+ /* Add ND Extensions Attr only if supported and reserved field - * or options type is set. */ -- if (data->igmp_group_ip4 != 0 || -- data->tcp_flags != 0) { -- nd_ext_key = -- nl_msg_put_unspec_uninit(buf, -+ if (parms->support.nd_ext) { -+ struct ovs_key_nd_extensions *nd_ext_key; -+ -+ if (data->igmp_group_ip4 != 0 || data->tcp_flags != 0) { -+ nd_ext_key = nl_msg_put_unspec_uninit(buf, - OVS_KEY_ATTR_ND_EXTENSIONS, - sizeof *nd_ext_key); -- nd_ext_key->nd_reserved = data->igmp_group_ip4; -- nd_ext_key->nd_options_type = ntohs(data->tcp_flags); -+ nd_ext_key->nd_reserved = data->igmp_group_ip4; -+ nd_ext_key->nd_options_type = ntohs(data->tcp_flags); -+ } - } - } - } -diff --git a/lib/odp-util.h b/lib/odp-util.h -index a03e82532..f15e258e6 100644 ---- a/lib/odp-util.h -+++ b/lib/odp-util.h -@@ -203,7 +203,11 @@ int odp_flow_from_string(const char *s, const struct simap *port_names, - \ - /* Conntrack original direction tuple matching * supported. */ \ - ODP_SUPPORT_FIELD(bool, ct_orig_tuple, "CT orig tuple") \ -- ODP_SUPPORT_FIELD(bool, ct_orig_tuple6, "CT orig tuple for IPv6") -+ ODP_SUPPORT_FIELD(bool, ct_orig_tuple6, "CT orig tuple for IPv6") \ -+ \ -+ /* If true, it means that the datapath supports the IPv6 Neigh \ -+ * Discovery Extension bits. */ \ -+ ODP_SUPPORT_FIELD(bool, nd_ext, "IPv6 ND Extension") - - /* Indicates support for various fields. This defines how flows will be - * serialised. */ -diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c -index a8c7369d0..c7c70062c 100644 ---- a/ofproto/ofproto-dpif.c -+++ b/ofproto/ofproto-dpif.c -@@ -1377,6 +1377,55 @@ check_max_dp_hash_alg(struct dpif_backer *backer) - return max_alg; - } - -+/* Tests whether 'backer''s datapath supports IPv6 ND extensions. -+ * Only userspace datapath support OVS_KEY_ATTR_ND_EXTENSIONS in keys. -+ * -+ * Returns false if 'backer' definitely does not support matching and -+ * setting reserved and options type, true if it seems to support. */ -+static bool -+check_nd_extensions(struct dpif_backer *backer) -+{ -+ struct eth_header *eth; -+ struct ofpbuf actions; -+ struct dpif_execute execute; -+ struct dp_packet packet; -+ struct flow flow; -+ int error; -+ struct ovs_key_nd_extensions key, mask; -+ -+ ofpbuf_init(&actions, 64); -+ memset(&key, 0x53, sizeof key); -+ memset(&mask, 0x7f, sizeof mask); -+ commit_masked_set_action(&actions, OVS_KEY_ATTR_ND_EXTENSIONS, &key, &mask, -+ sizeof key); -+ -+ /* Compose a dummy ethernet packet. */ -+ dp_packet_init(&packet, ETH_HEADER_LEN); -+ eth = dp_packet_put_zeros(&packet, ETH_HEADER_LEN); -+ eth->eth_type = htons(0x1234); -+ -+ flow_extract(&packet, &flow); -+ -+ /* Execute the actions. On datapaths without support fails with EINVAL. */ -+ execute.actions = actions.data; -+ execute.actions_len = actions.size; -+ execute.packet = &packet; -+ execute.flow = &flow; -+ execute.needs_help = false; -+ execute.probe = true; -+ execute.mtu = 0; -+ -+ error = dpif_execute(backer->dpif, &execute); -+ -+ dp_packet_uninit(&packet); -+ ofpbuf_uninit(&actions); -+ -+ VLOG_INFO("%s: Datapath %s IPv6 ND Extensions", dpif_name(backer->dpif), -+ error ? "does not support" : "supports"); -+ -+ return !error; -+} -+ - #define CHECK_FEATURE__(NAME, SUPPORT, FIELD, VALUE, ETHTYPE) \ - static bool \ - check_##NAME(struct dpif_backer *backer) \ -@@ -1447,10 +1496,10 @@ check_support(struct dpif_backer *backer) - backer->rt_support.odp.ct_zone = check_ct_zone(backer); - backer->rt_support.odp.ct_mark = check_ct_mark(backer); - backer->rt_support.odp.ct_label = check_ct_label(backer); -- - backer->rt_support.odp.ct_state_nat = check_ct_state_nat(backer); - backer->rt_support.odp.ct_orig_tuple = check_ct_orig_tuple(backer); - backer->rt_support.odp.ct_orig_tuple6 = check_ct_orig_tuple6(backer); -+ backer->rt_support.odp.nd_ext = check_nd_extensions(backer); - } - - static int -@@ -4453,6 +4502,14 @@ check_actions(const struct ofproto_dpif *ofproto, - "ct original direction tuple"); - return OFPERR_NXBAC_CT_DATAPATH_SUPPORT; - } -+ } else if (!support->nd_ext && ofpact->type == OFPACT_SET_FIELD) { -+ const struct mf_field *dst = ofpact_get_mf_dst(ofpact); -+ -+ if (dst->id == MFF_ND_RESERVED || dst->id == MFF_ND_OPTIONS_TYPE) { -+ report_unsupported_act("set field", -+ "setting IPv6 ND Extensions fields"); -+ return OFPERR_OFPBAC_BAD_SET_ARGUMENT; -+ } - } - } - -diff --git a/tests/test-odp.c b/tests/test-odp.c -index 09fec706a..0ddfd4070 100644 ---- a/tests/test-odp.c -+++ b/tests/test-odp.c -@@ -65,6 +65,7 @@ parse_keys(bool wc_keys) - .ct_mark = true, - .ct_label = true, - .max_vlan_headers = SIZE_MAX, -+ .nd_ext = true, - }, - }; - --- -2.14.1 - - diff --git a/ofproto-dpif-Free-leaked-webster.patch b/ofproto-dpif-Free-leaked-webster.patch deleted file mode 100644 index 9dd03262f2b145263ffacf80f5f79f25a2938376..0000000000000000000000000000000000000000 --- a/ofproto-dpif-Free-leaked-webster.patch +++ /dev/null @@ -1,53 +0,0 @@ -From d49777c9d7f1241bb38687ece237eb4135285ce9 Mon Sep 17 00:00:00 2001 -From: Yifeng Sun -Date: Wed, 11 Sep 2019 14:18:34 -0700 -Subject: ofproto-dpif: Free leaked 'webster' - -Valgrind reported: - -1122: ofproto-dpif - select group with explicit dp_hash selection method - -==16884== 64 bytes in 1 blocks are definitely lost in loss record 320 of 346 -==16884== at 0x4C2FB55: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) -==16884== by 0x532512: xcalloc (util.c:121) -==16884== by 0x4262B9: group_setup_dp_hash_table (ofproto-dpif.c:4846) -==16884== by 0x4267CB: group_set_selection_method (ofproto-dpif.c:4938) -==16884== by 0x4267CB: group_construct (ofproto-dpif.c:4984) -==16884== by 0x417250: init_group (ofproto.c:7286) -==16884== by 0x41B4FC: add_group_start (ofproto.c:7316) -==16884== by 0x42247A: ofproto_group_mod_start (ofproto.c:7589) -==16884== by 0x4250EC: handle_group_mod (ofproto.c:7744) -==16884== by 0x4250EC: handle_single_part_openflow (ofproto.c:8428) -==16884== by 0x4250EC: handle_openflow (ofproto.c:8606) -==16884== by 0x4579E2: ofconn_run (connmgr.c:1318) -==16884== by 0x4579E2: connmgr_run (connmgr.c:355) -==16884== by 0x41E0F5: ofproto_run (ofproto.c:1845) -==16884== by 0x40BA63: bridge_run__ (bridge.c:2971) -==16884== by 0x410CF3: bridge_run (bridge.c:3029) -==16884== by 0x407614: main (ovs-vswitchd.c:127) - -This patch fixes it. - -Acked-by: William Tu -Signed-off-by: Yifeng Sun -Signed-off-by: Ben Pfaff ---- - ofproto/ofproto-dpif.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c -index 46fa13571..7bb0f7bdb 100644 ---- a/ofproto/ofproto-dpif.c -+++ b/ofproto/ofproto-dpif.c -@@ -4871,6 +4871,7 @@ group_setup_dp_hash_table(struct group_dpif *group, size_t max_hash) - if (n_hash > MAX_SELECT_GROUP_HASH_VALUES || - (max_hash != 0 && n_hash > max_hash)) { - VLOG_DBG(" Too many hash values required: %"PRIu64, n_hash); -+ free(webster); - return false; - } - --- -2.14.1 - - diff --git a/ofproto-dpif-Uninitialize-xlate_cache-to-free-resour.patch b/ofproto-dpif-Uninitialize-xlate_cache-to-free-resour.patch deleted file mode 100644 index 4cc0e51bd679050b3b8f2dd3cbd0d2d56977d81a..0000000000000000000000000000000000000000 --- a/ofproto-dpif-Uninitialize-xlate_cache-to-free-resour.patch +++ /dev/null @@ -1,49 +0,0 @@ -From f1afa83349efb7622d986574211f3bd24d16e642 Mon Sep 17 00:00:00 2001 -From: Yifeng Sun -Date: Wed, 11 Sep 2019 14:18:28 -0700 -Subject: ofproto-dpif: Uninitialize 'xlate_cache' to free resources - -Valgrind reported: - -1210: ofproto-dpif - continuation after clone - -==32205== 4,392 (1,440 direct, 2,952 indirect) bytes in 12 blocks are definitely lost in loss record 359 of 362 -==32205== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) -==32205== by 0x532574: xmalloc (util.c:138) -==32205== by 0x4F98CA: ofpbuf_init (ofpbuf.c:123) -==32205== by 0x42C07B: nxt_resume (ofproto-dpif.c:5110) -==32205== by 0x41796F: handle_nxt_resume (ofproto.c:3677) -==32205== by 0x424583: handle_single_part_openflow (ofproto.c:8473) -==32205== by 0x424583: handle_openflow (ofproto.c:8606) -==32205== by 0x4579E2: ofconn_run (connmgr.c:1318) -==32205== by 0x4579E2: connmgr_run (connmgr.c:355) -==32205== by 0x41E0F5: ofproto_run (ofproto.c:1845) -==32205== by 0x40BA63: bridge_run__ (bridge.c:2971) -==32205== by 0x410CF3: bridge_run (bridge.c:3029) -==32205== by 0x407614: main (ovs-vswitchd.c:127) - -This is because 'xcache' was not destroyed properly. This patch fixes it. - -Acked-by: William Tu -Signed-off-by: Yifeng Sun -Signed-off-by: Ben Pfaff ---- - ofproto/ofproto-dpif.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c -index 751535249..46fa13571 100644 ---- a/ofproto/ofproto-dpif.c -+++ b/ofproto/ofproto-dpif.c -@@ -5148,6 +5148,7 @@ nxt_resume(struct ofproto *ofproto_, - /* Clean up. */ - ofpbuf_uninit(&odp_actions); - dp_packet_uninit(&packet); -+ xlate_cache_uninit(&xcache); - - return error; - } --- -2.14.1 - - diff --git a/ofproto-dpif-xlate-Restore-table-ID-on-error-in-xlat.patch b/ofproto-dpif-xlate-Restore-table-ID-on-error-in-xlat.patch deleted file mode 100644 index 4ad1df1a333f1b462d3ce373e4a6f3a1e69fcb48..0000000000000000000000000000000000000000 --- a/ofproto-dpif-xlate-Restore-table-ID-on-error-in-xlat.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 8cdf840f1af1c6da0459cb3a056c122762cd7fd6 Mon Sep 17 00:00:00 2001 -From: Ben Pfaff -Date: Mon, 14 Oct 2019 15:34:21 -0700 -Subject: ofproto-dpif-xlate: Restore table ID on error in xlate_table_action(). - -Found by inspection. - -Acked-by: Yi-Hung Wei -Signed-off-by: Ben Pfaff ---- - ofproto/ofproto-dpif-xlate.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c -index 0dc43d17a..09096ed6f 100644 ---- a/ofproto/ofproto-dpif-xlate.c -+++ b/ofproto/ofproto-dpif-xlate.c -@@ -4331,6 +4331,7 @@ xlate_table_action(struct xlate_ctx *ctx, ofp_port_t in_port, uint8_t table_id, - !is_ip_any(&ctx->xin->flow)) { - xlate_report_error(ctx, - "resubmit(ct) with non-tracked or non-IP packet!"); -+ ctx->table_id = old_table_id; - return; - } - tuple_swap(&ctx->xin->flow, ctx->wc); --- -2.14.1 - - diff --git a/ofproto-fix-a-typo-for-ttl-in-dpif_sflow_actions.patch b/ofproto-fix-a-typo-for-ttl-in-dpif_sflow_actions.patch deleted file mode 100644 index ceafcf43f14c333242db062129f4760ad3f9bb4d..0000000000000000000000000000000000000000 --- a/ofproto-fix-a-typo-for-ttl-in-dpif_sflow_actions.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 58bc4f3b43ff959bec4a6d1293465ec75c7d6bb5 Mon Sep 17 00:00:00 2001 -From: Martin Zhang -Date: Mon, 7 Oct 2019 00:34:55 -0400 -Subject: ofproto: fix a typo for ttl in dpif_sflow_actions - -Signed-off-by: Martin Zhang -Signed-off-by: Ben Pfaff ---- - ofproto/ofproto-dpif-sflow.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ofproto/ofproto-dpif-sflow.c b/ofproto/ofproto-dpif-sflow.c -index 03bd763c6..9abaab61b 100644 ---- a/ofproto/ofproto-dpif-sflow.c -+++ b/ofproto/ofproto-dpif-sflow.c -@@ -1026,7 +1026,7 @@ sflow_read_set_action(const struct nlattr *attr, - sflow_actions->tunnel.ip_tos = key->ipv4_tos; - } - if (key->ipv4_ttl) { -- sflow_actions->tunnel.ip_tos = key->ipv4_ttl; -+ sflow_actions->tunnel.ip_ttl = key->ipv4_ttl; - } - } - break; --- -2.14.1 - - diff --git a/ofproto-fix-stack-buffer-overflow.patch b/ofproto-fix-stack-buffer-overflow.patch deleted file mode 100644 index 0a7523de68050e6b0362b693f61f754a5bf5d22d..0000000000000000000000000000000000000000 --- a/ofproto-fix-stack-buffer-overflow.patch +++ /dev/null @@ -1,102 +0,0 @@ -From e4d2627cf5fcecdc64c1bacc2917ecdbcf00cf70 Mon Sep 17 00:00:00 2001 -From: Linhaifeng -Date: Fri, 29 Nov 2019 06:13:35 +0000 -Subject: ofproto: fix stack-buffer-overflow - -Should use flow->actions not &flow->actions. - -here is ASAN report: -================================================================= -==57189==ERROR: AddressSanitizer: stack-buffer-overflow on address 0xffff428fa0e8 at pc 0xffff7f61a520 bp 0xffff428f9420 sp 0xffff428f9498 READ of size 196 at 0xffff428fa0e8 thread T150 (revalidator22) - #0 0xffff7f61a51f in __interceptor_memcpy (/lib64/libasan.so.4+0xa251f) - #1 0xaaaad26a3b2b in ofpbuf_put lib/ofpbuf.c:426 - #2 0xaaaad26a30cb in ofpbuf_clone_data_with_headroom lib/ofpbuf.c:248 - #3 0xaaaad26a2e77 in ofpbuf_clone_with_headroom lib/ofpbuf.c:218 - #4 0xaaaad26a2dc3 in ofpbuf_clone lib/ofpbuf.c:208 - #5 0xaaaad23e3993 in ukey_set_actions ofproto/ofproto-dpif-upcall.c:1640 - #6 0xaaaad23e3f03 in ukey_create__ ofproto/ofproto-dpif-upcall.c:1696 - #7 0xaaaad23e553f in ukey_create_from_dpif_flow ofproto/ofproto-dpif-upcall.c:1806 - #8 0xaaaad23e65fb in ukey_acquire ofproto/ofproto-dpif-upcall.c:1984 - #9 0xaaaad23eb583 in revalidate ofproto/ofproto-dpif-upcall.c:2625 - #10 0xaaaad23dee5f in udpif_revalidator ofproto/ofproto-dpif-upcall.c:1076 - #11 0xaaaad26b84ef in ovsthread_wrapper lib/ovs-thread.c:708 - #12 0xffff7e74a8bb in start_thread (/lib64/libpthread.so.0+0x78bb) - #13 0xffff7e0665cb in thread_start (/lib64/libc.so.6+0xd55cb) - -Address 0xffff428fa0e8 is located in stack of thread T150 (revalidator22) at offset 328 in frame - #0 0xaaaad23e4cab in ukey_create_from_dpif_flow ofproto/ofproto-dpif-upcall.c:1762 - - This frame has 4 object(s): - [32, 96) 'actions' - [128, 192) 'buf' - [224, 328) 'full_flow' - [384, 2432) 'stub' <== Memory access at offset 328 partially underflows this variable -HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext - (longjmp and C++ exceptions *are* supported) Thread T150 (revalidator22) created by T0 here: - #0 0xffff7f5b0f7f in __interceptor_pthread_create (/lib64/libasan.so.4+0x38f7f) - #1 0xaaaad26b891f in ovs_thread_create lib/ovs-thread.c:792 - #2 0xaaaad23dc62f in udpif_start_threads ofproto/ofproto-dpif-upcall.c:639 - #3 0xaaaad23daf87 in ofproto_set_flow_table ofproto/ofproto-dpif-upcall.c:446 - #4 0xaaaad230ff7f in dpdk_evs_cfg_set vswitchd/bridge.c:1134 - #5 0xaaaad2310097 in bridge_reconfigure vswitchd/bridge.c:1148 - #6 0xaaaad23279d7 in bridge_run vswitchd/bridge.c:3944 - #7 0xaaaad23365a3 in main vswitchd/ovs-vswitchd.c:240 - #8 0xffff7dfb1adf in __libc_start_main (/lib64/libc.so.6+0x20adf) - #9 0xaaaad230a3d3 (/usr/sbin/ovs-vswitchd-2.7.0-1.1.RC5.001.asan+0x26f3d3) - -SUMMARY: AddressSanitizer: stack-buffer-overflow (/lib64/libasan.so.4+0xa251f) in __interceptor_memcpy Shadow bytes around the buggy address: - 0x200fe851f3c0: 00 00 00 00 f1 f1 f1 f1 f8 f2 f2 f2 00 00 00 00 - 0x200fe851f3d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 0x200fe851f3e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 0x200fe851f3f0: 00 00 00 00 f1 f1 f1 f1 00 00 00 00 00 00 00 00 - 0x200fe851f400: f2 f2 f2 f2 f8 f8 f8 f8 f8 f8 f8 f8 f2 f2 f2 f2 -=>0x200fe851f410: 00 00 00 00 00 00 00 00 00 00 00 00 00[f2]f2 f2 - 0x200fe851f420: f2 f2 f2 f2 00 00 00 00 00 00 00 00 00 00 00 00 - 0x200fe851f430: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 0x200fe851f440: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 0x200fe851f450: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 0x200fe851f460: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Shadow byte legend (one shadow byte represents 8 application bytes): - Addressable: 00 - Partially addressable: 01 02 03 04 05 06 07 - Heap left redzone: fa - Freed heap region: fd - Stack left redzone: f1 - Stack mid redzone: f2 - Stack right redzone: f3 - Stack after return: f5 - Stack use after scope: f8 - Global redzone: f9 - Global init order: f6 - Poisoned by user: f7 - Container overflow: fc - Array cookie: ac - Intra object redzone: bb - ASan internal: fe - Left alloca redzone: ca - Right alloca redzone: cb -==57189==ABORTING - -Acked-by: Numan Siddique -Signed-off-by: Linhaifeng -Signed-off-by: Ben Pfaff ---- - ofproto/ofproto-dpif-upcall.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c -index f46cdf213..0237f9451 100644 ---- a/ofproto/ofproto-dpif-upcall.c -+++ b/ofproto/ofproto-dpif-upcall.c -@@ -1798,7 +1798,7 @@ ukey_create_from_dpif_flow(const struct udpif *udpif, - } - - reval_seq = seq_read(udpif->reval_seq) - 1; /* Ensure revalidation. */ -- ofpbuf_use_const(&actions, &flow->actions, flow->actions_len); -+ ofpbuf_use_const(&actions, flow->actions, flow->actions_len); - *ukey = ukey_create__(flow->key, flow->key_len, - flow->mask, flow->mask_len, flow->ufid_present, - &flow->ufid, flow->pmd_id, &actions, --- -2.14.1 - - diff --git a/openvswitch-2.14.2-20240117.patch b/openvswitch-2.14.2-20240117.patch new file mode 100644 index 0000000000000000000000000000000000000000..27c634530d1747b9d54f11be588a99aa65f6527e --- /dev/null +++ b/openvswitch-2.14.2-20240117.patch @@ -0,0 +1,7462 @@ +diff --git a/openvswitch-2.14.2/Makefile.in b/openvswitch-2.14.2/Makefile.in +index f9ce1c6..b151099 100644 +--- a/openvswitch-2.14.2/Makefile.in ++++ b/openvswitch-2.14.2/Makefile.in +@@ -256,15 +256,16 @@ noinst_PROGRAMS = $(am__EXEEXT_2) tests/test-ovsdb$(EXEEXT) \ + @HAVE_AF_XDP_TRUE@ lib/netdev-afxdp.c \ + @HAVE_AF_XDP_TRUE@ lib/netdev-afxdp.h + +-@DPDK_NETDEV_TRUE@am__append_23 = \ ++@HAVE_HWOFF_AGENT_TRUE@am__append_23 = -lhwoffagent ++@DPDK_NETDEV_TRUE@am__append_24 = \ + @DPDK_NETDEV_TRUE@ lib/dpdk.c \ + @DPDK_NETDEV_TRUE@ lib/netdev-dpdk.c \ + @DPDK_NETDEV_TRUE@ lib/netdev-offload-dpdk.c + +-@DPDK_NETDEV_FALSE@am__append_24 = \ ++@DPDK_NETDEV_FALSE@am__append_25 = \ + @DPDK_NETDEV_FALSE@ lib/dpdk-stub.c + +-@WIN32_TRUE@am__append_25 = \ ++@WIN32_TRUE@am__append_26 = \ + @WIN32_TRUE@ lib/dpif-netlink.c \ + @WIN32_TRUE@ lib/dpif-netlink.h \ + @WIN32_TRUE@ lib/dpif-netlink-rtnl.h \ +@@ -279,41 +280,41 @@ noinst_PROGRAMS = $(am__EXEEXT_2) tests/test-ovsdb$(EXEEXT) \ + @WIN32_TRUE@ lib/wmi.c \ + @WIN32_TRUE@ lib/wmi.h + +-@HAVE_POSIX_AIO_TRUE@am__append_26 = lib/async-append-aio.c +-@HAVE_POSIX_AIO_FALSE@am__append_27 = lib/async-append-null.c +-@HAVE_IF_DL_TRUE@am__append_28 = \ ++@HAVE_POSIX_AIO_TRUE@am__append_27 = lib/async-append-aio.c ++@HAVE_POSIX_AIO_FALSE@am__append_28 = lib/async-append-null.c ++@HAVE_IF_DL_TRUE@am__append_29 = \ + @HAVE_IF_DL_TRUE@ lib/if-notifier-bsd.c \ + @HAVE_IF_DL_TRUE@ lib/netdev-bsd.c \ + @HAVE_IF_DL_TRUE@ lib/rtbsd.c \ + @HAVE_IF_DL_TRUE@ lib/rtbsd.h \ + @HAVE_IF_DL_TRUE@ lib/route-table-bsd.c + +-@HAVE_OPENSSL_TRUE@am__append_29 = lib/stream-ssl.c lib/dhparams.c +-@HAVE_OPENSSL_FALSE@am__append_30 = lib/stream-nossl.c +-@HAVE_UNBOUND_TRUE@am__append_31 = lib/dns-resolve.c +-@HAVE_UNBOUND_FALSE@am__append_32 = lib/dns-resolve-stub.c +-@WIN32_TRUE@am__append_33 = ${PTHREAD_LIBS} +-@LINUX_TRUE@am__append_34 = utilities/nlmon +-@WIN32_FALSE@am__append_35 = \ ++@HAVE_OPENSSL_TRUE@am__append_30 = lib/stream-ssl.c lib/dhparams.c ++@HAVE_OPENSSL_FALSE@am__append_31 = lib/stream-nossl.c ++@HAVE_UNBOUND_TRUE@am__append_32 = lib/dns-resolve.c ++@HAVE_UNBOUND_FALSE@am__append_33 = lib/dns-resolve-stub.c ++@WIN32_TRUE@am__append_34 = ${PTHREAD_LIBS} ++@LINUX_TRUE@am__append_35 = utilities/nlmon ++@WIN32_FALSE@am__append_36 = \ + @WIN32_FALSE@ tests/test-unix-socket.c + +-@LINUX_TRUE@am__append_36 = \ ++@LINUX_TRUE@am__append_37 = \ + @LINUX_TRUE@ tests/test-netlink-conntrack.c + +-@HAVE_OPENSSL_TRUE@am__append_37 = $(TESTPKI_FILES) +-@HAVE_OPENSSL_TRUE@am__append_38 = $(TESTPKI_FILES) tests/ovs-pki.log +-@HAVE_OPENSSL_TRUE@am__append_39 = clean-pki ++@HAVE_OPENSSL_TRUE@am__append_38 = $(TESTPKI_FILES) ++@HAVE_OPENSSL_TRUE@am__append_39 = $(TESTPKI_FILES) tests/ovs-pki.log ++@HAVE_OPENSSL_TRUE@am__append_40 = clean-pki + + # OVS does not use C++ itself, but it provides public header files + # that a C++ compiler should accept, so when --enable-Werror is in + # effect and a C++ compiler is available, we build a C++ source file + # that #includes all the public headers, as a way to ensure that they + # are acceptable as C++. +-@HAVE_CXX_TRUE@am__append_40 = include/openvswitch/libcxxtest.la +-@HAVE_CXX_TRUE@am__append_41 = include/openvswitch/cxxtest.cc +-@HAVE_DOT_TRUE@am__append_42 = vswitchd/vswitch.gv vswitchd/vswitch.pic +-@HAVE_DOT_TRUE@am__append_43 = vtep/vtep.gv vtep/vtep.pic +-@WIN32_TRUE@am__append_44 = $(srcdir)/datapath-windows/include/OvsDpInterface.h ++@HAVE_CXX_TRUE@am__append_41 = include/openvswitch/libcxxtest.la ++@HAVE_CXX_TRUE@am__append_42 = include/openvswitch/cxxtest.cc ++@HAVE_DOT_TRUE@am__append_43 = vswitchd/vswitch.gv vswitchd/vswitch.pic ++@HAVE_DOT_TRUE@am__append_44 = vtep/vtep.gv vtep/vtep.pic ++@WIN32_TRUE@am__append_45 = $(srcdir)/datapath-windows/include/OvsDpInterface.h + subdir = . + ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 + am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ +@@ -409,7 +410,7 @@ am__DEPENDENCIES_1 = + @WIN32_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) + lib_libopenvswitch_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ +- $(am__DEPENDENCIES_2) $(am__append_16) ++ $(am__DEPENDENCIES_2) $(am__append_16) $(am__DEPENDENCIES_1) + am__lib_libopenvswitch_la_SOURCES_DIST = lib/aes128.c lib/aes128.h \ + lib/async-append.h lib/backtrace.c lib/backtrace.h lib/bfd.c \ + lib/bfd.h lib/bitmap.h lib/bundle.c lib/bundle.h \ +@@ -418,16 +419,17 @@ am__lib_libopenvswitch_la_SOURCES_DIST = lib/aes128.c lib/aes128.h \ + lib/ccmap.c lib/ccmap.h lib/cmap.c lib/cmap.h lib/colors.c \ + lib/colors.h lib/command-line.c lib/command-line.h \ + lib/compiler.h lib/connectivity.c lib/connectivity.h \ +- lib/conntrack-icmp.c lib/conntrack-private.h \ +- lib/conntrack-tcp.c lib/conntrack-tp.c lib/conntrack-tp.h \ +- lib/conntrack-other.c lib/conntrack.c lib/conntrack.h \ +- lib/coverage.c lib/coverage.h lib/crc32c.c lib/crc32c.h \ +- lib/csum.c lib/csum.h lib/ct-dpif.c lib/ct-dpif.h lib/daemon.c \ +- lib/daemon.h lib/daemon-private.h lib/db-ctl-base.c \ +- lib/db-ctl-base.h lib/dhcp.h lib/dummy.c lib/dummy.h \ +- lib/dhparams.h lib/dirs.h lib/dpctl.c lib/dpctl.h \ +- lib/dp-packet.h lib/dp-packet.c lib/dpdk.h \ +- lib/dpif-netdev-lookup.h lib/dpif-netdev-lookup.c \ ++ lib/hwoff_init_func.c lib/hwoff_init_func.h \ ++ lib/dpak_ovs.h lib/conntrack-icmp.c \ ++ lib/conntrack-private.h lib/conntrack-tcp.c lib/conntrack-tp.c \ ++ lib/conntrack-tp.h lib/conntrack-other.c lib/conntrack.c \ ++ lib/conntrack.h lib/ct_offload_provider.h lib/coverage.c \ ++ lib/coverage.h lib/crc32c.c lib/crc32c.h lib/csum.c lib/csum.h \ ++ lib/ct-dpif.c lib/ct-dpif.h lib/daemon.c lib/daemon.h \ ++ lib/daemon-private.h lib/db-ctl-base.c lib/db-ctl-base.h \ ++ lib/dhcp.h lib/dummy.c lib/dummy.h lib/dhparams.h lib/dirs.h \ ++ lib/dpctl.c lib/dpctl.h lib/dp-packet.h lib/dp-packet.c \ ++ lib/dpdk.h lib/dpif-netdev-lookup.h lib/dpif-netdev-lookup.c \ + lib/dpif-netdev-lookup-autovalidator.c \ + lib/dpif-netdev-lookup-generic.c lib/dpif-netdev.c \ + lib/dpif-netdev.h lib/dpif-netdev-private.h \ +@@ -563,8 +565,8 @@ am__lib_libopenvswitch_la_SOURCES_DIST = lib/aes128.c lib/aes128.h \ + am_lib_libopenvswitch_la_OBJECTS = lib/aes128.lo lib/backtrace.lo \ + lib/bfd.lo lib/bundle.lo lib/byteq.lo lib/cfm.lo \ + lib/classifier.lo lib/ccmap.lo lib/cmap.lo lib/colors.lo \ +- lib/command-line.lo lib/connectivity.lo lib/conntrack-icmp.lo \ +- lib/conntrack-tcp.lo lib/conntrack-tp.lo \ ++ lib/command-line.lo lib/connectivity.lo lib/hwoff_init_func.lo \ ++ lib/conntrack-icmp.lo lib/conntrack-tcp.lo lib/conntrack-tp.lo \ + lib/conntrack-other.lo lib/conntrack.lo lib/coverage.lo \ + lib/crc32c.lo lib/csum.lo lib/ct-dpif.lo lib/daemon.lo \ + lib/db-ctl-base.lo lib/dummy.lo lib/dpctl.lo lib/dp-packet.lo \ +@@ -807,7 +809,7 @@ am_tests_ovstest_OBJECTS = tests/ovstest.$(OBJEXT) \ + tests/test-stp.$(OBJEXT) tests/test-unixctl.$(OBJEXT) \ + tests/test-util.$(OBJEXT) tests/test-uuid.$(OBJEXT) \ + tests/test-bitmap.$(OBJEXT) tests/test-vconn.$(OBJEXT) \ +- tests/test-aa.$(OBJEXT) tests/test-stopwatch.$(OBJEXT) \ ++ tests/test-aa.$(OBJEXT) tests/test-stopwatch.$(OBJEXT) tests/test-hiovs-offload.$(OBJEXT) \ + $(am__objects_15) $(am__objects_16) + tests_ovstest_OBJECTS = $(am_tests_ovstest_OBJECTS) + tests_ovstest_DEPENDENCIES = lib/libopenvswitch.la +@@ -920,7 +922,8 @@ am__depfiles_remade = include/openvswitch/$(DEPDIR)/cxxtest.Plo \ + lib/$(DEPDIR)/guarded-list.Plo lib/$(DEPDIR)/hash.Plo \ + lib/$(DEPDIR)/heap.Plo lib/$(DEPDIR)/hindex.Plo \ + lib/$(DEPDIR)/hmap.Plo lib/$(DEPDIR)/hmapx.Plo \ +- lib/$(DEPDIR)/id-pool.Plo lib/$(DEPDIR)/if-notifier-bsd.Plo \ ++ lib/$(DEPDIR)/hwoff_init_func.Plo lib/$(DEPDIR)/id-pool.Plo \ ++ lib/$(DEPDIR)/if-notifier-bsd.Plo \ + lib/$(DEPDIR)/if-notifier-manual.Plo \ + lib/$(DEPDIR)/if-notifier-stub.Plo \ + lib/$(DEPDIR)/if-notifier.Plo lib/$(DEPDIR)/ipf.Plo \ +@@ -1563,7 +1566,7 @@ ALL_LOCAL = dist-hook-git config-h-check printf-check static-check \ + $(srcdir)/python/ovs/version.py $(srcdir)/python/ovs/dirs.py \ + vtep/vtep.ovsschema.stamp + BUILT_SOURCES = ofproto/ipfix-entities.def include/odp-netlink.h \ +- include/odp-netlink-macros.h $(OVSIDL_BUILT) $(am__append_44) ++ include/odp-netlink-macros.h $(OVSIDL_BUILT) $(am__append_45) + + # Clean up generated files from older OVS versions. (This is important so that + # #include "vswitch-idl.h" doesn't get the wrong copy.) +@@ -1583,10 +1586,10 @@ CLEANFILES = all-distfiles all-gitfiles missing-distfiles distfiles \ + utilities/ovs-tcpundump utilities/ovs-test \ + utilities/ovs-vlan-test utilities/ovs-vsctl.8 \ + utilities/bugtool/ovs-bugtool utilities/bugtool/ovs-bugtool.8 \ +- $(valgrind_wrappers) $(am__append_38) include/odp-netlink.h \ +- include/odp-netlink-macros.h $(HSTAMP_FILES) $(am__append_41) \ ++ $(valgrind_wrappers) $(am__append_39) include/odp-netlink.h \ ++ include/odp-netlink-macros.h $(HSTAMP_FILES) $(am__append_42) \ + cxx-check debian/copyright ipsec/ovs-monitor-ipsec \ +- vswitchd/ovs-vswitchd.8 $(am__append_42) \ ++ vswitchd/ovs-vswitchd.8 $(am__append_43) \ + vswitchd/ovs-vswitchd.conf.db.5 \ + vswitchd/vswitch.ovsschema.stamp vswitchd/vswitch-idl.c \ + vswitchd/vswitch-idl.h ovsdb/ovsdb-tool.1 ovsdb/ovsdb-client.1 \ +@@ -1594,7 +1597,7 @@ CLEANFILES = all-distfiles all-gitfiles missing-distfiles distfiles \ + ovsdb/ovsdb-dot ovsdb/_server.ovsschema.inc \ + ovsdb/_server.ovsschema.stamp ovsdb/ovsdb-server.5 \ + python/ovs/dirs.py vtep/vtep-ctl.8 vtep/ovs-vtep \ +- $(am__append_43) vtep/vtep.5 vtep/vtep.ovsschema.stamp \ ++ $(am__append_44) vtep/vtep.5 vtep/vtep.ovsschema.stamp \ + $(srcdir)/datapath-windows/include/OvsDpInterface.h \ + selinux/openvswitch-custom.te selinux/openvswitch-custom.pp \ + selinux/openvswitch-custom.fc selinux/openvswitch-custom.if +@@ -1602,7 +1605,7 @@ CLEANFILES = all-distfiles all-gitfiles missing-distfiles distfiles \ + # lcov support + # Requires build with --enable-coverage and lcov/genhtml in $PATH + CLEAN_LOCAL = clean-pycov $(am__append_10) $(am__append_13) clean-lcov \ +- $(am__append_39) ++ $(am__append_40) + DISTCLEANFILES = tests/atconfig tests/atlocal \ + rhel/usr_lib_systemd_system_ovs-vswitchd.service + PYCOV_CLEAN_FILES = build-aux/check-structs,cover \ +@@ -1986,7 +1989,7 @@ noinst_HEADERS = $(EXTRA_DIST) include/sparse/rte_byteorder.h \ + lib_LTLIBRARIES = lib/libopenvswitch.la $(am__append_15) \ + lib/libsflow.la ofproto/libofproto.la ovsdb/libovsdb.la \ + vtep/libvtep.la +-noinst_LTLIBRARIES = $(am__append_40) ++noinst_LTLIBRARIES = $(am__append_41) + noinst_man_MANS = + + # ovsdb-idlc +@@ -2015,7 +2018,7 @@ completion_SCRIPTS = utilities/ovs-appctl-bashcomp.bash \ + utilities/ovs-vsctl-bashcomp.bash + scripts_DATA = utilities/ovs-lib + SUFFIXES = .in .xml .h .hstamp .ovsidl .ovsschema +-check_DATA = $(am__append_37) ++check_DATA = $(am__append_38) + check_SCRIPTS = utilities/ovs-appctl-bashcomp.bash \ + utilities/ovs-vsctl-bashcomp.bash tests/atlocal + pkgconfig_DATA = lib/libopenvswitch.pc lib/libsflow.pc \ +@@ -2256,7 +2259,8 @@ extract_stem_and_section = \ + test -n "$$mandir" || { echo "unknown directory for manpage section $$section"; continue; } + + lib_libopenvswitch_la_LIBADD = $(SSL_LIBS) $(CAPNG_LDADD) \ +- $(LIBBPF_LDADD) $(am__append_14) $(am__append_16) ++ $(LIBBPF_LDADD) $(am__append_14) $(am__append_16) \ ++ $(am__append_23) + lib_libopenvswitch_la_LDFLAGS = \ + $(OVS_LTINFO) \ + -Wl,--version-script=$(top_builddir)/lib/libopenvswitch.sym \ +@@ -2286,16 +2290,17 @@ lib_libopenvswitch_la_SOURCES = lib/aes128.c lib/aes128.h \ + lib/ccmap.c lib/ccmap.h lib/cmap.c lib/cmap.h lib/colors.c \ + lib/colors.h lib/command-line.c lib/command-line.h \ + lib/compiler.h lib/connectivity.c lib/connectivity.h \ +- lib/conntrack-icmp.c lib/conntrack-private.h \ +- lib/conntrack-tcp.c lib/conntrack-tp.c lib/conntrack-tp.h \ +- lib/conntrack-other.c lib/conntrack.c lib/conntrack.h \ +- lib/coverage.c lib/coverage.h lib/crc32c.c lib/crc32c.h \ +- lib/csum.c lib/csum.h lib/ct-dpif.c lib/ct-dpif.h lib/daemon.c \ +- lib/daemon.h lib/daemon-private.h lib/db-ctl-base.c \ +- lib/db-ctl-base.h lib/dhcp.h lib/dummy.c lib/dummy.h \ +- lib/dhparams.h lib/dirs.h lib/dpctl.c lib/dpctl.h \ +- lib/dp-packet.h lib/dp-packet.c lib/dpdk.h \ +- lib/dpif-netdev-lookup.h lib/dpif-netdev-lookup.c \ ++ lib/hwoff_init_func.c lib/hwoff_init_func.h \ ++ lib/dpak_ovs.h lib/conntrack-icmp.c \ ++ lib/conntrack-private.h lib/conntrack-tcp.c lib/conntrack-tp.c \ ++ lib/conntrack-tp.h lib/conntrack-other.c lib/conntrack.c \ ++ lib/conntrack.h lib/ct_offload_provider.h lib/coverage.c \ ++ lib/coverage.h lib/crc32c.c lib/crc32c.h lib/csum.c lib/csum.h \ ++ lib/ct-dpif.c lib/ct-dpif.h lib/daemon.c lib/daemon.h \ ++ lib/daemon-private.h lib/db-ctl-base.c lib/db-ctl-base.h \ ++ lib/dhcp.h lib/dummy.c lib/dummy.h lib/dhparams.h lib/dirs.h \ ++ lib/dpctl.c lib/dpctl.h lib/dp-packet.h lib/dp-packet.c \ ++ lib/dpdk.h lib/dpif-netdev-lookup.h lib/dpif-netdev-lookup.c \ + lib/dpif-netdev-lookup-autovalidator.c \ + lib/dpif-netdev-lookup-generic.c lib/dpif-netdev.c \ + lib/dpif-netdev.h lib/dpif-netdev-private.h \ +@@ -2377,10 +2382,10 @@ lib_libopenvswitch_la_SOURCES = lib/aes128.c lib/aes128.h \ + lib/lldp/lldp-tlv.h lib/lldp/lldpd.c lib/lldp/lldpd.h \ + lib/lldp/lldpd-structs.c lib/lldp/lldpd-structs.h \ + $(am__append_17) $(am__append_18) $(am__append_21) \ +- $(am__append_22) $(am__append_23) $(am__append_24) \ +- $(am__append_25) $(am__append_26) $(am__append_27) \ +- $(am__append_28) $(am__append_29) $(am__append_30) \ +- lib/dns-resolve.h $(am__append_31) $(am__append_32) ++ $(am__append_22) $(am__append_24) $(am__append_25) \ ++ $(am__append_26) $(am__append_27) $(am__append_28) \ ++ $(am__append_29) $(am__append_30) $(am__append_31) \ ++ lib/dns-resolve.h $(am__append_32) $(am__append_33) + nodist_lib_libopenvswitch_la_SOURCES = \ + lib/dirs.c \ + lib/ovsdb-server-idl.c \ +@@ -2433,7 +2438,7 @@ ofproto_libofproto_la_SOURCES = ofproto/bond.c ofproto/bond.h \ + ofproto/bundles.c ofproto/bundles.h ofproto/ipfix-entities.def + ofproto_libofproto_la_CPPFLAGS = $(AM_CPPFLAGS) + ofproto_libofproto_la_CFLAGS = $(AM_CFLAGS) +-ofproto_libofproto_la_LIBADD = lib/libsflow.la $(am__append_33) ++ofproto_libofproto_la_LIBADD = lib/libsflow.la $(am__append_34) + dist_noinst_SCRIPTS = ofproto/ipfix-gen-entities + utilities_ovs_appctl_SOURCES = utilities/ovs-appctl.c + utilities_ovs_appctl_LDADD = lib/libopenvswitch.la +@@ -2692,7 +2697,7 @@ tests_ovstest_SOURCES = tests/ovstest.c tests/ovstest.h \ + tests/test-sha1.c tests/test-skiplist.c tests/test-stp.c \ + tests/test-unixctl.c tests/test-util.c tests/test-uuid.c \ + tests/test-bitmap.c tests/test-vconn.c tests/test-aa.c \ +- tests/test-stopwatch.c $(am__append_35) $(am__append_36) ++ tests/test-stopwatch.c $(am__append_36) $(am__append_37) + tests_ovstest_LDADD = lib/libopenvswitch.la + tests_test_stream_SOURCES = tests/test-stream.c + tests_test_stream_LDADD = lib/libopenvswitch.la +@@ -3257,6 +3262,8 @@ lib/cmap.lo: lib/$(am__dirstamp) lib/$(DEPDIR)/$(am__dirstamp) + lib/colors.lo: lib/$(am__dirstamp) lib/$(DEPDIR)/$(am__dirstamp) + lib/command-line.lo: lib/$(am__dirstamp) lib/$(DEPDIR)/$(am__dirstamp) + lib/connectivity.lo: lib/$(am__dirstamp) lib/$(DEPDIR)/$(am__dirstamp) ++lib/hwoff_init_func.lo: lib/$(am__dirstamp) \ ++ lib/$(DEPDIR)/$(am__dirstamp) + lib/conntrack-icmp.lo: lib/$(am__dirstamp) \ + lib/$(DEPDIR)/$(am__dirstamp) + lib/conntrack-tcp.lo: lib/$(am__dirstamp) \ +@@ -4218,6 +4225,7 @@ distclean-compile: + @AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/hindex.Plo@am__quote@ # am--include-marker + @AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/hmap.Plo@am__quote@ # am--include-marker + @AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/hmapx.Plo@am__quote@ # am--include-marker ++@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/hwoff_init_func.Plo@am__quote@ # am--include-marker + @AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/id-pool.Plo@am__quote@ # am--include-marker + @AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/if-notifier-bsd.Plo@am__quote@ # am--include-marker + @AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/if-notifier-manual.Plo@am__quote@ # am--include-marker +@@ -5670,6 +5678,7 @@ distclean: distclean-recursive + -rm -f lib/$(DEPDIR)/hindex.Plo + -rm -f lib/$(DEPDIR)/hmap.Plo + -rm -f lib/$(DEPDIR)/hmapx.Plo ++ -rm -f lib/$(DEPDIR)/hwoff_init_func.Plo + -rm -f lib/$(DEPDIR)/id-pool.Plo + -rm -f lib/$(DEPDIR)/if-notifier-bsd.Plo + -rm -f lib/$(DEPDIR)/if-notifier-manual.Plo +@@ -6048,6 +6057,7 @@ maintainer-clean: maintainer-clean-recursive + -rm -f lib/$(DEPDIR)/hindex.Plo + -rm -f lib/$(DEPDIR)/hmap.Plo + -rm -f lib/$(DEPDIR)/hmapx.Plo ++ -rm -f lib/$(DEPDIR)/hwoff_init_func.Plo + -rm -f lib/$(DEPDIR)/id-pool.Plo + -rm -f lib/$(DEPDIR)/if-notifier-bsd.Plo + -rm -f lib/$(DEPDIR)/if-notifier-manual.Plo +diff --git a/openvswitch-2.14.2/acinclude.m4 b/openvswitch-2.14.2/acinclude.m4 +index 237b221..7b64d53 100644 +--- a/openvswitch-2.14.2/acinclude.m4 ++++ b/openvswitch-2.14.2/acinclude.m4 +@@ -334,8 +334,9 @@ dnl + dnl Configure DPDK source tree + AC_DEFUN([OVS_CHECK_DPDK], [ + AC_ARG_WITH([dpdk], +- [AC_HELP_STRING([--with-dpdk=/path/to/dpdk], +- [Specify the DPDK build directory])], ++ [AC_HELP_STRING([--with-dpdk=static|shared|yes], ++ [Specify "static" or "shared" depending on the ++ DPDK libraries to use])], + [have_dpdk=true]) + + AC_MSG_CHECKING([whether dpdk is enabled]) +@@ -345,27 +346,36 @@ AC_DEFUN([OVS_CHECK_DPDK], [ + else + AC_MSG_RESULT([yes]) + case "$with_dpdk" in +- yes) +- DPDK_AUTO_DISCOVER="true" +- PKG_CHECK_MODULES_STATIC([DPDK], [libdpdk], [ +- DPDK_INCLUDE="$DPDK_CFLAGS" +- DPDK_LIB="$DPDK_LIBS"], [ +- DPDK_INCLUDE="-I/usr/local/include/dpdk -I/usr/include/dpdk" +- DPDK_LIB="-ldpdk"]) +- ;; +- *) +- DPDK_AUTO_DISCOVER="false" +- DPDK_INCLUDE_PATH="$with_dpdk/include" +- # If 'with_dpdk' is passed install directory, point to headers +- # installed in $DESTDIR/$prefix/include/dpdk +- if test -e "$DPDK_INCLUDE_PATH/rte_config.h"; then +- DPDK_INCLUDE="-I$DPDK_INCLUDE_PATH" +- elif test -e "$DPDK_INCLUDE_PATH/dpdk/rte_config.h"; then +- DPDK_INCLUDE="-I$DPDK_INCLUDE_PATH/dpdk" +- fi +- DPDK_LIB_DIR="$with_dpdk/lib" +- DPDK_LIB="-ldpdk" +- ;; ++ "shared") ++ PKG_CHECK_MODULES([DPDK], [libdpdk], [ ++ DPDK_INCLUDE="$DPDK_CFLAGS" ++ DPDK_LIB="$DPDK_LIBS"]) ++ ;; ++ "static" | "yes") ++ PKG_CHECK_MODULES_STATIC([DPDK], [libdpdk], [ ++ DPDK_INCLUDE="$DPDK_CFLAGS" ++ DPDK_LIB="$DPDK_LIBS"]) ++ ++ dnl Statically linked private DPDK objects of form ++ dnl -l:file.a must be positioned between ++ dnl --whole-archive ... --no-whole-archive linker parameters. ++ dnl Old pkg-config versions misplace --no-whole-archive parameter ++ dnl and put it next to --whole-archive. ++ AC_MSG_CHECKING([for faulty pkg-config version]) ++ echo "$DPDK_LIB" | grep -q 'whole-archive.*l:lib.*no-whole-archive' ++ status=$? ++ case $status in ++ 0) ++ AC_MSG_RESULT([no]) ++ ;; ++ 1) ++ AC_MSG_RESULT([yes]) ++ AC_MSG_ERROR([Please upgrade pkg-config]) ++ ;; ++ *) ++ AC_MSG_ERROR([grep exited with status $status]) ++ ;; ++ esac + esac + + ovs_save_CFLAGS="$CFLAGS" +@@ -454,17 +464,15 @@ AC_DEFUN([OVS_CHECK_DPDK], [ + # This happens because the rest of the DPDK code doesn't use any symbol in + # the pmd driver objects, and the drivers register themselves using an + # __attribute__((constructor)) function. +- # +- # These options are specified inside a single -Wl directive to prevent +- # autotools from reordering them. +- # +- # OTOH newer versions of dpdk pkg-config (generated with Meson) +- # will already have flagged just the right set of libs with +- # --whole-archive - in those cases do not wrap it once more. +- case "$DPDK_LIB" in +- *whole-archive*) DPDK_vswitchd_LDFLAGS=$DPDK_LIB;; +- *) DPDK_vswitchd_LDFLAGS=-Wl,--whole-archive,$DPDK_LIB,--no-whole-archive +- esac ++ # Wrap the DPDK libraries inside a single -Wl directive ++ # after comma separation to prevent autotools from reordering them. ++ DPDK_vswitchd_LDFLAGS=$(echo "$DPDK_LIB"| tr -s ' ' ',' | sed 's/-Wl,//g') ++ # Replace -pthread with -lpthread for LD and remove the last extra comma. ++ DPDK_vswitchd_LDFLAGS=$(echo "$DPDK_vswitchd_LDFLAGS"| sed 's/,$//' | \ ++ sed 's/-pthread/-lpthread/g') ++ # Prepend "-Wl,". ++ DPDK_vswitchd_LDFLAGS="-Wl,$DPDK_vswitchd_LDFLAGS" ++ + AC_SUBST([DPDK_vswitchd_LDFLAGS]) + AC_DEFINE([DPDK_NETDEV], [1], [System uses the DPDK module.]) + fi +@@ -472,6 +480,22 @@ AC_DEFUN([OVS_CHECK_DPDK], [ + AM_CONDITIONAL([DPDK_NETDEV], test "$DPDKLIB_FOUND" = true) + ]) + ++dnl OVS_CHECK_HWOFF_AGENT ++dnl ++dnl Check whether we're building with ipu. ++AC_DEFUN([OVS_CHECK_HWOFF_AGENT], ++ [AC_ARG_ENABLE( ++ [hwoff], ++ [AC_HELP_STRING([--enable-hwoff], [Enable OVS hwoff support])], ++ [], [enable_hwoff=no]) ++ ++ if test "x$enable_hwoff" = xyes; then ++ AC_DEFINE([HAVE_HWOFF_AGENT], [1], [ovs enable hwoff]) ++ CFLAGS="$CFLAGS -I/usr/include/hwoff_agent" ++ fi ++ AM_CONDITIONAL([HAVE_HWOFF_AGENT], [test $enable_hwoff = yes]) ++ ]) ++ + dnl OVS_GREP_IFELSE(FILE, REGEX, [IF-MATCH], [IF-NO-MATCH]) + dnl + dnl Greps FILE for REGEX. If it matches, runs IF-MATCH, otherwise IF-NO-MATCH. +@@ -1220,7 +1244,7 @@ dnl with or without modifications, as long as this notice is preserved. + + AC_DEFUN([_OVS_CHECK_CC_OPTION], [dnl + m4_define([ovs_cv_name], [ovs_cv_[]m4_translit([$1], [-= ], [__])])dnl +- AC_CACHE_CHECK([whether $CC accepts $1], [ovs_cv_name], ++ AC_CACHE_CHECK([whether $CC accepts $1], [ovs_cv_name], + [ovs_save_CFLAGS="$CFLAGS" + dnl Include -Werror in the compiler options, because without -Werror + dnl clang's GCC-compatible compiler driver does not return a failure +@@ -1275,7 +1299,7 @@ dnl OVS_ENABLE_OPTION([OPTION]) + dnl Check whether the given C compiler OPTION is accepted. + dnl If so, add it to WARNING_FLAGS. + dnl Example: OVS_ENABLE_OPTION([-Wdeclaration-after-statement]) +-AC_DEFUN([OVS_ENABLE_OPTION], ++AC_DEFUN([OVS_ENABLE_OPTION], + [OVS_CHECK_CC_OPTION([$1], [WARNING_FLAGS="$WARNING_FLAGS $1"]) + AC_SUBST([WARNING_FLAGS])]) + +diff --git a/openvswitch-2.14.2/configure b/openvswitch-2.14.2/configure +index cb32f48..22658cc 100644 +--- a/openvswitch-2.14.2/configure ++++ b/openvswitch-2.14.2/configure +@@ -1599,8 +1599,9 @@ Optional Packages: + Specify the Linux kernel source directory (usually + figured out automatically from build directory) + +- --with-dpdk=/path/to/dpdk +- Specify the DPDK build directory ++ --with-dpdk=static|shared|yes ++ Specify "static" or "shared" depending on the DPDK ++ libraries to use + + Some influential environment variables: + CC C compiler command +@@ -30699,9 +30700,103 @@ $as_echo "no" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 + $as_echo "yes" >&6; } + case "$with_dpdk" in +- yes) +- DPDK_AUTO_DISCOVER="true" +- _save_PKG_CONFIG=$PKG_CONFIG ++ "shared") ++ ++pkg_failed=no ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for DPDK" >&5 ++$as_echo_n "checking for DPDK... " >&6; } ++ ++if test -n "$DPDK_CFLAGS"; then ++ pkg_cv_DPDK_CFLAGS="$DPDK_CFLAGS" ++ elif test -n "$PKG_CONFIG"; then ++ if test -n "$PKG_CONFIG" && \ ++ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libdpdk\""; } >&5 ++ ($PKG_CONFIG --exists --print-errors "libdpdk") 2>&5 ++ ac_status=$? ++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 ++ test $ac_status = 0; }; then ++ pkg_cv_DPDK_CFLAGS=`$PKG_CONFIG --cflags "libdpdk" 2>/dev/null` ++ test "x$?" != "x0" && pkg_failed=yes ++else ++ pkg_failed=yes ++fi ++ else ++ pkg_failed=untried ++fi ++if test -n "$DPDK_LIBS"; then ++ pkg_cv_DPDK_LIBS="$DPDK_LIBS" ++ elif test -n "$PKG_CONFIG"; then ++ if test -n "$PKG_CONFIG" && \ ++ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libdpdk\""; } >&5 ++ ($PKG_CONFIG --exists --print-errors "libdpdk") 2>&5 ++ ac_status=$? ++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 ++ test $ac_status = 0; }; then ++ pkg_cv_DPDK_LIBS=`$PKG_CONFIG --libs "libdpdk" 2>/dev/null` ++ test "x$?" != "x0" && pkg_failed=yes ++else ++ pkg_failed=yes ++fi ++ else ++ pkg_failed=untried ++fi ++ ++ ++ ++if test $pkg_failed = yes; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++ ++if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then ++ _pkg_short_errors_supported=yes ++else ++ _pkg_short_errors_supported=no ++fi ++ if test $_pkg_short_errors_supported = yes; then ++ DPDK_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libdpdk" 2>&1` ++ else ++ DPDK_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libdpdk" 2>&1` ++ fi ++ # Put the nasty error message in config.log where it belongs ++ echo "$DPDK_PKG_ERRORS" >&5 ++ ++ as_fn_error $? "Package requirements (libdpdk) were not met: ++ ++$DPDK_PKG_ERRORS ++ ++Consider adjusting the PKG_CONFIG_PATH environment variable if you ++installed software in a non-standard prefix. ++ ++Alternatively, you may set the environment variables DPDK_CFLAGS ++and DPDK_LIBS to avoid the need to call pkg-config. ++See the pkg-config man page for more details." "$LINENO" 5 ++elif test $pkg_failed = untried; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 ++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} ++as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it ++is in your PATH or set the PKG_CONFIG environment variable to the full ++path to pkg-config. ++ ++Alternatively, you may set the environment variables DPDK_CFLAGS ++and DPDK_LIBS to avoid the need to call pkg-config. ++See the pkg-config man page for more details. ++ ++To get pkg-config, see . ++See \`config.log' for more details" "$LINENO" 5; } ++else ++ DPDK_CFLAGS=$pkg_cv_DPDK_CFLAGS ++ DPDK_LIBS=$pkg_cv_DPDK_LIBS ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 ++$as_echo "yes" >&6; } ++ ++ DPDK_INCLUDE="$DPDK_CFLAGS" ++ DPDK_LIB="$DPDK_LIBS" ++fi ++ ;; ++ "static" | "yes") ++ _save_PKG_CONFIG=$PKG_CONFIG + PKG_CONFIG="$PKG_CONFIG --static" + + pkg_failed=no +@@ -31499,17 +31594,15 @@ $as_echo "$ovs_cv__mssse3" >&6; } + # This happens because the rest of the DPDK code doesn't use any symbol in + # the pmd driver objects, and the drivers register themselves using an + # __attribute__((constructor)) function. +- # +- # These options are specified inside a single -Wl directive to prevent +- # autotools from reordering them. +- # +- # OTOH newer versions of dpdk pkg-config (generated with Meson) +- # will already have flagged just the right set of libs with +- # --whole-archive - in those cases do not wrap it once more. +- case "$DPDK_LIB" in +- *whole-archive*) DPDK_vswitchd_LDFLAGS=$DPDK_LIB;; +- *) DPDK_vswitchd_LDFLAGS=-Wl,--whole-archive,$DPDK_LIB,--no-whole-archive +- esac ++ # Wrap the DPDK libraries inside a single -Wl directive ++ # after comma separation to prevent autotools from reordering them. ++ DPDK_vswitchd_LDFLAGS=$(echo "$DPDK_LIB"| tr -s ' ' ',' | sed 's/-Wl,//g') ++ # Replace -pthread with -lpthread for LD and remove the last extra comma. ++ DPDK_vswitchd_LDFLAGS=$(echo "$DPDK_vswitchd_LDFLAGS"| sed 's/,$//' | \ ++ sed 's/-pthread/-lpthread/g') ++ # Prepend "-Wl,". ++ DPDK_vswitchd_LDFLAGS="-Wl,$DPDK_vswitchd_LDFLAGS" ++ + + + $as_echo "#define DPDK_NETDEV 1" >>confdefs.h +diff --git a/openvswitch-2.14.2/configure.ac b/openvswitch-2.14.2/configure.ac +index ee52e33..44dcc97 100644 +--- a/openvswitch-2.14.2/configure.ac ++++ b/openvswitch-2.14.2/configure.ac +@@ -195,6 +195,7 @@ OVS_CHECK_LINUX_TC + OVS_CHECK_LINUX_SCTP_CT + OVS_CHECK_LINUX_VIRTIO_TYPES + OVS_CHECK_DPDK ++OVS_CHECK_HWOFF_AGENT + OVS_CHECK_PRAGMA_MESSAGE + AC_SUBST([OVS_CFLAGS]) + AC_SUBST([OVS_LDFLAGS]) +diff --git a/openvswitch-2.14.2/include/openflow/openflow-1.3.h b/openvswitch-2.14.2/include/openflow/openflow-1.3.h +index c48a8ea..924ed31 100644 +--- a/openvswitch-2.14.2/include/openflow/openflow-1.3.h ++++ b/openvswitch-2.14.2/include/openflow/openflow-1.3.h +@@ -156,7 +156,10 @@ enum ofp13_meter_flags { + OFPMF13_KBPS = 1 << 0, /* Rate value in kb/s (kilo-bit per second). */ + OFPMF13_PKTPS = 1 << 1, /* Rate value in packet/sec. */ + OFPMF13_BURST = 1 << 2, /* Do burst size. */ +- OFPMF13_STATS = 1 << 3 /* Collect statistics. */ ++ OFPMF13_STATS = 1 << 3, /* Collect statistics. */ ++#ifdef HAVE_HWOFF_AGENT ++ OFPMF13_OFFLOAD = 1 << 4 ++#endif + }; + + /* Meter band types */ +@@ -328,6 +331,7 @@ struct ofp13_meter_band_stats { + OFP_ASSERT(sizeof(struct ofp13_meter_band_stats) == 16); + + /* Body of reply to OFPMP13_METER request. Meter statistics. */ ++#ifdef HAVE_HWOFF_AGENT + struct ofp13_meter_stats { + ovs_be32 meter_id; /* Meter instance. */ + ovs_be16 len; /* Length in bytes of this stats. */ +@@ -338,11 +342,30 @@ struct ofp13_meter_stats { + ovs_be32 duration_sec; /* Time meter has been alive in seconds. */ + ovs_be32 duration_nsec; /* Time meter has been alive in nanoseconds + beyond duration_sec. */ ++ ovs_be64 n_pkts_dropped; ++ ovs_be64 n_bytes_dropped; + struct ofp13_meter_band_stats band_stats[0]; /* The band_stats length is + inferred from the length field. */ ++ + }; +-OFP_ASSERT(sizeof(struct ofp13_meter_stats) == 40); ++OFP_ASSERT(sizeof(struct ofp13_meter_stats) == 56); ++#else ++struct ofp13_meter_stats { ++ ovs_be32 meter_id; /* Meter instance. */ ++ ovs_be16 len; /* Length in bytes of this stats. */ ++ uint8_t pad[6]; ++ ovs_be32 flow_count; /* Number of flows bound to meter. */ ++ ovs_be64 packet_in_count; /* Number of packets in input. */ ++ ovs_be64 byte_in_count; /* Number of bytes in input. */ ++ ovs_be32 duration_sec; /* Time meter has been alive in seconds. */ ++ ovs_be32 duration_nsec; /* Time meter has been alive in nanoseconds ++ beyond duration_sec. */ ++ struct ofp13_meter_band_stats band_stats[0]; /* The band_stats length is ++ inferred from the length field. */ + ++}; ++OFP_ASSERT(sizeof(struct ofp13_meter_stats) == 40); ++#endif + /* Body of reply to OFPMP13_METER_CONFIG request. Meter configuration. */ + struct ofp13_meter_config { + ovs_be16 length; /* Length of this entry. */ +diff --git a/openvswitch-2.14.2/include/openvswitch/ofp-meter.h b/openvswitch-2.14.2/include/openvswitch/ofp-meter.h +index 6776eae..a35f9a9 100644 +--- a/openvswitch-2.14.2/include/openvswitch/ofp-meter.h ++++ b/openvswitch-2.14.2/include/openvswitch/ofp-meter.h +@@ -88,6 +88,10 @@ struct ofputil_meter_stats { + uint32_t duration_nsec; + uint16_t n_bands; + struct ofputil_meter_band_stats *bands; ++#ifdef HAVE_HWOFF_AGENT ++ uint64_t n_num_dropped_byte; ++ uint64_t n_num_dropped_pkts; ++#endif + }; + + void ofputil_append_meter_stats(struct ovs_list *replies, +diff --git a/openvswitch-2.14.2/lib/adapter/ovs_adapter.h b/openvswitch-2.14.2/lib/adapter/ovs_adapter.h +new file mode 100644 +index 0000000..caa705c +--- /dev/null ++++ b/openvswitch-2.14.2/lib/adapter/ovs_adapter.h +@@ -0,0 +1,124 @@ ++/* ++ * Copyright (c) 2022-2022. Huawei Technologies Co., Ltd. ++ * Description: ovs adapter file ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ * ++ * Create: 2022-09-24 ++ */ ++ ++#ifndef _OVS_ADAPTER_H ++#define _OVS_ADAPTER_H ++ ++#include ++#include "ovs-atomic.h" ++#include "cmap.h" ++#include "conntrack-private.h" ++#include "conntrack-tp.h" ++#include "conntrack.h" ++#include "dp-packet.h" ++#include "dpif-netdev.h" ++#include "hash.h" ++#include "latch.h" ++#include "mac-learning.h" ++#include "netdev-provider.h" ++#include "netdev-dpdk.h" ++#include "packets.h" ++#include "random.h" ++#include "ovs-rcu.h" ++#include "smap.h" ++#include "ovs-thread.h" ++#include "timeval.h" ++#include "unaligned.h" ++#include "unixctl.h" ++#include "util.h" ++#include "uuid.h" ++#include "openvswitch/dynamic-string.h" ++#include "openvswitch/hmap.h" ++#include "openvswitch/ofpbuf.h" ++#include "openvswitch/util.h" ++#include "openvswitch/poll-loop.h" ++#include "openvswitch/shash.h" ++ ++void atomic_count_init_ext(atomic_count *count, unsigned int value); ++unsigned int atomic_count_inc_ext(atomic_count *count); ++unsigned int atomic_count_dec_ext(atomic_count *count); ++unsigned int atomic_count_get_ext(atomic_count *count); ++void atomic_count_set_ext(atomic_count *count, unsigned int value); ++ ++struct cmap_node* cmap_node_next_ext(const struct cmap_node *node); ++struct cmap_node* cmap_node_next_protected_ext(const struct cmap_node *node); ++size_t cmap_remove_ext(struct cmap *cmap, struct cmap_node *node, uint32_t hash); ++ ++void conn_update_expiration_int(struct conntrack *ct, struct conn *conn, ++ int tm, long long now); ++void conn_update_expiration_no_lock_int(struct conntrack *ct, struct conn *conn, ++ int tm, long long now); ++uint32_t ct_get_hash_basis(struct conntrack *ct); ++struct conn_key* conn_get_key_addr(const struct conn *conn); ++struct conn_key* conn_get_rev_key_addr(const struct conn *conn); ++struct conn* conn_get_nat_conn(const struct conn *conn); ++void* conn_get_offload_info_addr(const struct conn *conn); ++void* conn_get_nat_info(const struct conn *conn); ++bool conn_get_cleaned(const struct conn *conn); ++struct ovs_mutex* conn_get_lock_addr(const struct conn *conn); ++int tcp_conn_timeout_get_int(const struct conn *conn); ++int icmp_conn_timeout_get_int(const struct conn *conn); ++int other_conn_timeout_get_int(const struct conn *conn); ++void ct_dpif_entry_set_print_offload(struct ct_dpif_entry *entry, ++ bool print_offload); ++void ct_dpif_entry_set_init_dir_offload_state(struct ct_dpif_entry *entry, ++ const char *state); ++void ct_dpif_entry_set_reply_dir_offload_state(struct ct_dpif_entry *entry, ++ const char *state); ++ ++size_t dp_packet_struct_size(void); ++void* dp_packet_data_ext(const struct dp_packet *b); ++struct rte_mbuf* dp_packet_get_mbuf_addr(const struct dp_packet *b); ++struct pkt_metadata* dp_packet_get_md_addr(const struct dp_packet *b); ++uint32_t dp_packet_size_ext(const struct dp_packet *b); ++ ++uint32_t hash_int_ext(uint32_t x, uint32_t basis); ++uint32_t hash_bytes_ext(const void *arg, size_t n_bytes, uint32_t basis); ++uint32_t hash_uint64_ext(const uint64_t x); ++uint32_t hash_add_ext(uint32_t hash, uint32_t data); ++ ++bool hmap_is_empty_ext(const struct hmap *hmap); ++size_t hmap_count_ext(const struct hmap *hmap); ++struct hmap_node* hmap_first_ext(const struct hmap *hmap); ++struct hmap_node* hmap_next_ext(const struct hmap *hmap, const struct hmap_node *node); ++void hmap_insert_at_ext(struct hmap *hmap, struct hmap_node *node, size_t hash, const char *where); ++void hmap_remove_ext(struct hmap *hmap, struct hmap_node *node); ++struct hmap_node* hmap_first_with_hash_ext(const struct hmap *hmap, size_t hash); ++struct hmap_node* hmap_next_with_hash_ext(const struct hmap *hmap); ++ ++const char* netdev_class_get_type(struct netdev_class *netdev_class); ++uint16_t netdev_class_get_if_index(struct netdev_class *netdev_class, struct netdev *netdev); ++ ++uint16_t vlan_tci_to_vid_ext(ovs_be16 vlan_tci); ++void ipv6_format_addr_ext(const struct in6_addr *addr, struct ds *ds); ++struct conn* pkt_metadata_get_conn(struct pkt_metadata *md); ++bool pkt_metadata_get_reply(struct pkt_metadata *md); ++bool* pkt_metadata_get_reply_addr(struct pkt_metadata *md); ++ ++void poll_timer_wait_ext(long long int msec); ++ ++bool ovsthread_once_start_ext(struct ovsthread_once *once); ++void ovs_mutex_lock_ext(const struct ovs_mutex *mutex); ++ ++ovs_be32 get_16aligned_be32_ext(const ovs_16aligned_be32 *x); ++ ++uint32_t hiovs_rte_flow_list_get_ext(ovs_u128 ufid_list[], struct rte_flow *flow_list[], uint32_t ufid_cnt); ++void hiovs_rte_flow_data_list_put_ext(void *flow_data_list[], uint32_t count); ++ ++#endif +\ No newline at end of file +diff --git a/openvswitch-2.14.2/lib/adapter/ovs_atomic_adapter.c b/openvswitch-2.14.2/lib/adapter/ovs_atomic_adapter.c +new file mode 100644 +index 0000000..3bcbec1 +--- /dev/null ++++ b/openvswitch-2.14.2/lib/adapter/ovs_atomic_adapter.c +@@ -0,0 +1,47 @@ ++/* ++ * Copyright (c) 2022-2022. Huawei Technologies Co., Ltd. ++ * Description: ovs atomic adapter file ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ * ++ * Create: 2022-09-24 ++ */ ++ ++#include ++#include "ovs-atomic.h" ++#include "ovs_adapter.h" ++ ++void atomic_count_init_ext(atomic_count *count, unsigned int value) ++{ ++ atomic_count_init(count, value); ++} ++ ++unsigned int atomic_count_inc_ext(atomic_count *count) ++{ ++ return atomic_count_inc(count); ++} ++ ++unsigned int atomic_count_dec_ext(atomic_count *count) ++{ ++ return atomic_count_dec(count); ++} ++ ++unsigned int atomic_count_get_ext(atomic_count *count) ++{ ++ return atomic_count_get(count); ++} ++ ++void atomic_count_set_ext(atomic_count *count, unsigned int value) ++{ ++ atomic_count_set(count, value); ++} +diff --git a/openvswitch-2.14.2/lib/adapter/ovs_cmap_adapter.c b/openvswitch-2.14.2/lib/adapter/ovs_cmap_adapter.c +new file mode 100644 +index 0000000..c18a2f6 +--- /dev/null ++++ b/openvswitch-2.14.2/lib/adapter/ovs_cmap_adapter.c +@@ -0,0 +1,37 @@ ++/* ++ * Copyright (c) 2022-2022. Huawei Technologies Co., Ltd. ++ * Description: ovs cmap adapter file ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ * ++ * Create: 2022-09-24 ++ */ ++ ++#include ++#include "cmap.h" ++#include "ovs_adapter.h" ++ ++struct cmap_node* cmap_node_next_ext(const struct cmap_node *node) ++{ ++ return cmap_node_next(node); ++} ++ ++struct cmap_node* cmap_node_next_protected_ext(const struct cmap_node *node) ++{ ++ return cmap_node_next_protected(node); ++} ++ ++size_t cmap_remove_ext(struct cmap *cmap, struct cmap_node *node, uint32_t hash) ++{ ++ return cmap_remove(cmap, node, hash); ++} +diff --git a/openvswitch-2.14.2/lib/adapter/ovs_conntrack_adapter.c b/openvswitch-2.14.2/lib/adapter/ovs_conntrack_adapter.c +new file mode 100644 +index 0000000..09fc667 +--- /dev/null ++++ b/openvswitch-2.14.2/lib/adapter/ovs_conntrack_adapter.c +@@ -0,0 +1,113 @@ ++/* ++ * Copyright (c) 2022-2022. Huawei Technologies Co., Ltd. ++ * Description: ovs conntrack adapter file ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ * ++ * Create: 2022-09-24 ++ */ ++ ++#include ++#include "conntrack-private.h" ++#include "conntrack-tp.h" ++#include "conntrack.h" ++#include "ovs_adapter.h" ++ ++uint32_t conn_key_hash(const struct conn_key *, uint32_t basis); ++bool conn_key_lookup(struct conntrack *ct, const struct conn_key *key, ++ uint32_t hash, long long now, struct conn **conn_out, bool *reply); ++ ++void conn_update_expiration_int(struct conntrack *ct, struct conn *conn, ++ int tm, long long now) ++{ ++ conn_update_expiration(ct, conn, tm, now); ++} ++ ++void conn_update_expiration_no_lock_int(struct conntrack *ct, struct conn *conn, ++ int tm, long long now) ++{ ++ conn_update_expiration_no_lock(ct, conn, tm, now); ++} ++ ++uint32_t ct_get_hash_basis(struct conntrack *ct) ++{ ++ return ct->hash_basis; ++} ++ ++struct conn_key* conn_get_key_addr(const struct conn *conn) ++{ ++ return &conn->key; ++} ++ ++struct conn_key* conn_get_rev_key_addr(const struct conn *conn) ++{ ++ return &conn->rev_key; ++} ++ ++struct conn* conn_get_nat_conn(const struct conn *conn) ++{ ++ return conn->nat_conn; ++} ++ ++void* conn_get_offload_info_addr(const struct conn *conn) ++{ ++ return &conn->offload_info; ++} ++ ++void* conn_get_nat_info(const struct conn *conn) ++{ ++ return conn->nat_info; ++} ++ ++bool conn_get_cleaned(const struct conn *conn) ++{ ++ return conn->cleaned; ++} ++ ++struct ovs_mutex* conn_get_lock_addr(const struct conn *conn) ++{ ++ return &conn->lock; ++} ++ ++int tcp_conn_timeout_get_int(const struct conn *conn) ++{ ++ return (int)tcp_conn_timeout_get(conn); ++} ++ ++int icmp_conn_timeout_get_int(const struct conn *conn) ++{ ++ return (int)icmp_conn_timeout_get(conn); ++} ++ ++int other_conn_timeout_get_int(const struct conn *conn) ++{ ++ return (int)other_conn_timeout_get(conn); ++} ++ ++void ct_dpif_entry_set_print_offload(struct ct_dpif_entry *entry, ++ bool print_offload) ++{ ++ entry->print_offload = print_offload; ++} ++ ++void ct_dpif_entry_set_init_dir_offload_state(struct ct_dpif_entry *entry, ++ const char *state) ++{ ++ entry->init_dir_offload_state = state; ++} ++ ++void ct_dpif_entry_set_reply_dir_offload_state(struct ct_dpif_entry *entry, ++ const char *state) ++{ ++ entry->reply_dir_offload_state = state; ++} +diff --git a/openvswitch-2.14.2/lib/adapter/ovs_dp_adapter.c b/openvswitch-2.14.2/lib/adapter/ovs_dp_adapter.c +new file mode 100644 +index 0000000..00d54bb +--- /dev/null ++++ b/openvswitch-2.14.2/lib/adapter/ovs_dp_adapter.c +@@ -0,0 +1,48 @@ ++/* ++ * Copyright (c) 2022-2022. Huawei Technologies Co., Ltd. ++ * Description: ovs dp_packet adapter file ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ * ++ * Create: 2022-09-24 ++ */ ++ ++#include "config.h" ++#include "dp-packet.h" ++#include "dpif-netdev.h" ++#include "ovs_adapter.h" ++ ++size_t dp_packet_struct_size(void) ++{ ++ return sizeof(struct dp_packet); ++} ++ ++void* dp_packet_data_ext(const struct dp_packet *b) ++{ ++ return dp_packet_data(b); ++} ++ ++struct rte_mbuf* dp_packet_get_mbuf_addr(const struct dp_packet *b) ++{ ++ return &b->mbuf; ++} ++ ++struct pkt_metadata* dp_packet_get_md_addr(const struct dp_packet *b) ++{ ++ return &b->md; ++} ++ ++uint32_t dp_packet_size_ext(const struct dp_packet *b) ++{ ++ return dp_packet_size(b); ++} +diff --git a/openvswitch-2.14.2/lib/adapter/ovs_hash_adapter.c b/openvswitch-2.14.2/lib/adapter/ovs_hash_adapter.c +new file mode 100644 +index 0000000..d638ff0 +--- /dev/null ++++ b/openvswitch-2.14.2/lib/adapter/ovs_hash_adapter.c +@@ -0,0 +1,42 @@ ++/* ++ * Copyright (c) 2022-2022. Huawei Technologies Co., Ltd. ++ * Description: ovs hash adapter file ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ * ++ * Create: 2022-09-24 ++ */ ++ ++#include "config.h" ++#include "hash.h" ++#include "ovs_adapter.h" ++ ++uint32_t hash_int_ext(uint32_t x, uint32_t basis) ++{ ++ return hash_int(x, basis); ++} ++ ++uint32_t hash_bytes_ext(const void *arg, size_t n_bytes, uint32_t basis) ++{ ++ return hash_bytes(arg, n_bytes, basis); ++} ++ ++uint32_t hash_uint64_ext(const uint64_t x) ++{ ++ return hash_uint64(x); ++} ++ ++uint32_t hash_add_ext(uint32_t hash, uint32_t data) ++{ ++ return hash_add(hash, data); ++} +diff --git a/openvswitch-2.14.2/lib/adapter/ovs_hiovs_flow_adapter.c b/openvswitch-2.14.2/lib/adapter/ovs_hiovs_flow_adapter.c +new file mode 100644 +index 0000000..57e36d1 +--- /dev/null ++++ b/openvswitch-2.14.2/lib/adapter/ovs_hiovs_flow_adapter.c +@@ -0,0 +1,31 @@ ++/* ++ * Copyright (c) 2022-2022. Huawei Technologies Co., Ltd. ++ * Description: ovs hiovs flow adapter file ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ * ++ * Create: 2022-09-24 ++ */ ++#include "config.h" ++#include "openvswitch/util.h" ++#include "ovs_adapter.h" ++ ++uint32_t hiovs_rte_flow_list_get_ext(ovs_u128 ufid_list[], struct rte_flow *flow_list[], uint32_t ufid_cnt) ++{ ++ return hiovs_rte_flow_list_get(ufid_list, flow_list, ufid_cnt); ++} ++ ++void hiovs_rte_flow_data_list_put_ext(void *flow_data_list[], uint32_t count) ++{ ++ return hiovs_rte_flow_data_list_put(flow_data_list, count); ++} +\ No newline at end of file +diff --git a/openvswitch-2.14.2/lib/adapter/ovs_hmap_adapter.c b/openvswitch-2.14.2/lib/adapter/ovs_hmap_adapter.c +new file mode 100644 +index 0000000..fee67f9 +--- /dev/null ++++ b/openvswitch-2.14.2/lib/adapter/ovs_hmap_adapter.c +@@ -0,0 +1,62 @@ ++/* ++ * Copyright (c) 2022-2022. Huawei Technologies Co., Ltd. ++ * Description: ovs hmap adapter file ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ * ++ * Create: 2022-09-24 ++ */ ++ ++#include "ovs_adapter.h" ++#include "config.h" ++#include "openvswitch/hmap.h" ++ ++bool hmap_is_empty_ext(const struct hmap *hmap) ++{ ++ return hmap_is_empty(hmap); ++} ++ ++size_t hmap_count_ext(const struct hmap *hmap) ++{ ++ return hmap_count(hmap); ++} ++ ++struct hmap_node* hmap_first_ext(const struct hmap *hmap) ++{ ++ return hmap_first(hmap); ++} ++ ++struct hmap_node* hmap_next_ext(const struct hmap *hmap, const struct hmap_node *node) ++{ ++ return hmap_next(hmap, node); ++} ++ ++void hmap_insert_at_ext(struct hmap *hmap, struct hmap_node *node, size_t hash, const char *where) ++{ ++ return hmap_insert_at(hmap, node, hash, where); ++} ++ ++void hmap_remove_ext(struct hmap *hmap, struct hmap_node *node) ++{ ++ return hmap_remove(hmap, node); ++} ++ ++struct hmap_node* hmap_first_with_hash_ext(const struct hmap *hmap, size_t hash) ++{ ++ return hmap_first_with_hash(hmap, hash); ++} ++ ++struct hmap_node* hmap_next_with_hash_ext(const struct hmap *hmap) ++{ ++ return hmap_next_with_hash(hmap); ++} +diff --git a/openvswitch-2.14.2/lib/adapter/ovs_netdev_adapter.c b/openvswitch-2.14.2/lib/adapter/ovs_netdev_adapter.c +new file mode 100644 +index 0000000..0692f6c +--- /dev/null ++++ b/openvswitch-2.14.2/lib/adapter/ovs_netdev_adapter.c +@@ -0,0 +1,32 @@ ++/* ++ * Copyright (c) 2022-2022. Huawei Technologies Co., Ltd. ++ * Description: ovs netdev adapter file ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ * ++ * Create: 2022-09-24 ++ */ ++ ++#include "config.h" ++#include "netdev-provider.h" ++#include "ovs_adapter.h" ++ ++const char* netdev_class_get_type(struct netdev_class *netdev_class) ++{ ++ return netdev_class->type; ++} ++ ++uint16_t netdev_class_get_if_index(struct netdev_class *netdev_class, struct netdev *netdev) ++{ ++ return netdev_class->get_ifindex(netdev); ++} +diff --git a/openvswitch-2.14.2/lib/adapter/ovs_packet_adapter.c b/openvswitch-2.14.2/lib/adapter/ovs_packet_adapter.c +new file mode 100644 +index 0000000..89608d7 +--- /dev/null ++++ b/openvswitch-2.14.2/lib/adapter/ovs_packet_adapter.c +@@ -0,0 +1,47 @@ ++/* ++ * Copyright (c) 2022-2022. Huawei Technologies Co., Ltd. ++ * Description: ovs packet adapter file ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ * ++ * Create: 2022-09-24 ++ */ ++ ++#include "config.h" ++#include "packets.h" ++#include "ovs_adapter.h" ++ ++uint16_t vlan_tci_to_vid_ext(ovs_be16 vlan_tci) ++{ ++ return vlan_tci_to_vid(vlan_tci); ++} ++ ++void ipv6_format_addr_ext(const struct in6_addr *addr, struct ds *ds) ++{ ++ ipv6_format_addr(addr, ds); ++} ++ ++struct conn* pkt_metadata_get_conn(struct pkt_metadata *md) ++{ ++ return md->conn; ++} ++ ++bool pkt_metadata_get_reply(struct pkt_metadata *md) ++{ ++ return md->reply; ++} ++ ++bool* pkt_metadata_get_reply_addr(struct pkt_metadata *md) ++{ ++ return &md->reply; ++} +diff --git a/openvswitch-2.14.2/lib/adapter/ovs_poll_adapter.c b/openvswitch-2.14.2/lib/adapter/ovs_poll_adapter.c +new file mode 100644 +index 0000000..a21f62b +--- /dev/null ++++ b/openvswitch-2.14.2/lib/adapter/ovs_poll_adapter.c +@@ -0,0 +1,27 @@ ++/* ++ * Copyright (c) 2022-2022. Huawei Technologies Co., Ltd. ++ * Description: ovs poll adapter file ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ * ++ * Create: 2022-09-24 ++ */ ++#include "config.h" ++#include "openvswitch/util.h" ++#include "openvswitch/poll-loop.h" ++#include "ovs_adapter.h" ++ ++void poll_timer_wait_ext(long long int msec) ++{ ++ poll_timer_wait(msec); ++} +diff --git a/openvswitch-2.14.2/lib/adapter/ovs_thread_adapter.c b/openvswitch-2.14.2/lib/adapter/ovs_thread_adapter.c +new file mode 100644 +index 0000000..fa797c3 +--- /dev/null ++++ b/openvswitch-2.14.2/lib/adapter/ovs_thread_adapter.c +@@ -0,0 +1,31 @@ ++/* ++ * Copyright (c) 2022-2022. Huawei Technologies Co., Ltd. ++ * Description: ovs thread adapter file ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ * ++ * Create: 2022-09-24 ++ */ ++#include "config.h" ++#include "ovs-thread.h" ++#include "ovs_adapter.h" ++ ++bool ovsthread_once_start_ext(struct ovsthread_once *once) ++{ ++ return ovsthread_once_start(once); ++} ++ ++void ovs_mutex_lock_ext(const struct ovs_mutex *mutex) ++{ ++ ovs_mutex_lock(mutex); ++} +diff --git a/openvswitch-2.14.2/lib/adapter/ovs_unaligned_adapter.c b/openvswitch-2.14.2/lib/adapter/ovs_unaligned_adapter.c +new file mode 100644 +index 0000000..9ab0760 +--- /dev/null ++++ b/openvswitch-2.14.2/lib/adapter/ovs_unaligned_adapter.c +@@ -0,0 +1,27 @@ ++/* ++ * Copyright (c) 2022-2022. Huawei Technologies Co., Ltd. ++ * Description: ovs unalign adapter file ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ * ++ * Create: 2022-09-24 ++ */ ++ ++#include "config.h" ++#include "unaligned.h" ++#include "ovs_adapter.h" ++ ++ovs_be32 get_16aligned_be32_ext(const ovs_16aligned_be32 *x) ++{ ++ return get_16aligned_be32(x); ++} +diff --git a/openvswitch-2.14.2/lib/automake.mk b/openvswitch-2.14.2/lib/automake.mk +index 380a672..897bd1d 100644 +--- a/openvswitch-2.14.2/lib/automake.mk ++++ b/openvswitch-2.14.2/lib/automake.mk +@@ -82,6 +82,7 @@ lib_libopenvswitch_la_SOURCES = \ + lib/conntrack-other.c \ + lib/conntrack.c \ + lib/conntrack.h \ ++ lib/ct_offload_provider.h \ + lib/coverage.c \ + lib/coverage.h \ + lib/crc32c.c \ +@@ -365,7 +366,19 @@ lib_libopenvswitch_la_SOURCES = \ + lib/lldp/lldpd.c \ + lib/lldp/lldpd.h \ + lib/lldp/lldpd-structs.c \ +- lib/lldp/lldpd-structs.h ++ lib/lldp/lldpd-structs.h \ ++ lib/adapter/ovs_atomic_adapter.c \ ++ lib/adapter/ovs_cmap_adapter.c \ ++ lib/adapter/ovs_conntrack_adapter.c \ ++ lib/adapter/ovs_dp_adapter.c \ ++ lib/adapter/ovs_hash_adapter.c \ ++ lib/adapter/ovs_hmap_adapter.c \ ++ lib/adapter/ovs_netdev_adapter.c \ ++ lib/adapter/ovs_packet_adapter.c \ ++ lib/adapter/ovs_poll_adapter.c \ ++ lib/adapter/ovs_thread_adapter.c \ ++ lib/adapter/ovs_unaligned_adapter.c \ ++ lib/adapter/ovs_hiovs_flow_adapter.c + + if WIN32 + lib_libopenvswitch_la_SOURCES += \ +@@ -454,6 +467,14 @@ lib_libopenvswitch_la_SOURCES += \ + lib/netdev-afxdp.h + endif + ++if HAVE_HWOFF_AGENT ++lib_libopenvswitch_la_SOURCES += \ ++ lib/hwoff_init_func.c \ ++ lib/hwoff_init_func.h \ ++ lib/ct_dump_extend/ct_dump_extend.c \ ++ lib/ct_dump_extend/ct_dump_extend.h ++endif ++ + if DPDK_NETDEV + lib_libopenvswitch_la_SOURCES += \ + lib/dpdk.c \ +@@ -594,7 +615,7 @@ lib/meta-flow.inc: $(srcdir)/build-aux/extract-ofp-fields include/openvswitch/me + $(AM_V_GEN)$(run_python) $< meta-flow $(srcdir)/include/openvswitch/meta-flow.h > $@.tmp + $(AM_V_at)mv $@.tmp $@ + lib/meta-flow.lo: lib/meta-flow.inc +-lib/nx-match.inc: $(srcdir)/build-aux/extract-ofp-fields include/openvswitch/meta-flow.h ++lib/nx-match.inc: $(srcdir)/build-aux/extract-ofp-fields include/openvswitch/meta-flow.h + $(AM_V_GEN)$(run_python) $< nx-match $(srcdir)/include/openvswitch/meta-flow.h > $@.tmp + $(AM_V_at)mv $@.tmp $@ + lib/nx-match.lo: lib/nx-match.inc +diff --git a/openvswitch-2.14.2/lib/conntrack-icmp.c b/openvswitch-2.14.2/lib/conntrack-icmp.c +index b402970..4ea703c 100644 +--- a/openvswitch-2.14.2/lib/conntrack-icmp.c ++++ b/openvswitch-2.14.2/lib/conntrack-icmp.c +@@ -104,3 +104,9 @@ struct ct_l4_proto ct_proto_icmp6 = { + .valid_new = icmp6_valid_new, + .conn_update = icmp_conn_update, + }; ++ ++enum ct_timeout icmp_conn_timeout_get(const struct conn *conn) ++{ ++ struct conn_icmp *conn_icmp = conn_icmp_cast(conn); ++ return icmp_timeouts[conn_icmp->state]; ++} +diff --git a/openvswitch-2.14.2/lib/conntrack-other.c b/openvswitch-2.14.2/lib/conntrack-other.c +index d3b4601..67c7405 100644 +--- a/openvswitch-2.14.2/lib/conntrack-other.c ++++ b/openvswitch-2.14.2/lib/conntrack-other.c +@@ -88,3 +88,10 @@ struct ct_l4_proto ct_proto_other = { + .valid_new = other_valid_new, + .conn_update = other_conn_update, + }; ++ ++enum ct_timeout other_conn_timeout_get(const struct conn *conn) ++{ ++ struct conn_other *conn_other = conn_other_cast(conn); ++ return other_timeouts[conn_other->state]; ++} ++ +diff --git a/openvswitch-2.14.2/lib/conntrack-private.h b/openvswitch-2.14.2/lib/conntrack-private.h +index 3434753..f74eea5 100644 +--- a/openvswitch-2.14.2/lib/conntrack-private.h ++++ b/openvswitch-2.14.2/lib/conntrack-private.h +@@ -32,6 +32,10 @@ + #include "unaligned.h" + #include "dp-packet.h" + ++#ifdef HAVE_HWOFF_AGENT ++#include "ct_offload_provider.h" ++#endif ++ + struct ct_endpoint { + union ct_addr addr; + union { +@@ -88,6 +92,14 @@ enum OVS_PACKED_ENUM ct_conn_type { + CT_CONN_TYPE_UN_NAT, + }; + ++#ifdef HAVE_HWOFF_AGENT ++typedef struct { ++ conn_id conn_id; ++ bool is_ct_established; ++ void *conn_private_data; ++} ct_offload_info; ++#endif ++ + struct conn { + /* Immutable data. */ + struct conn_key key; +@@ -120,6 +132,17 @@ struct conn { + enum ct_conn_type conn_type; + + uint32_t tp_id; /* Timeout policy ID. */ ++#ifdef HAVE_HWOFF_AGENT ++ ct_offload_info offload_info; ++#endif ++}; ++ ++struct conn_lookup_ctx { ++ struct conn_key key; ++ struct conn *conn; ++ uint32_t hash; ++ bool reply; ++ bool icmp_related; + }; + + enum ct_update_res { +@@ -177,8 +200,15 @@ struct conntrack { + struct ipf *ipf; /* Fragmentation handling context. */ + uint32_t zone_limit_seq; /* Used to disambiguate zone limit counts. */ + atomic_bool tcp_seq_chk; /* Check TCP sequence numbers. */ ++#ifdef HAVE_HWOFF_AGENT ++ ct_offload_class *offload_class; ++#endif + }; + ++#ifdef HAVE_HWOFF_AGENT ++void reg_ct_offload_class(ct_offload_class *class); ++#endif ++ + /* Lock acquisition order: + * 1. 'ct_lock' + * 2. 'conn->lock' +@@ -213,4 +243,7 @@ tcp_payload_length(struct dp_packet *pkt) + } + } + ++enum ct_timeout tcp_conn_timeout_get(const struct conn *conn); ++enum ct_timeout icmp_conn_timeout_get(const struct conn *conn); ++enum ct_timeout other_conn_timeout_get(const struct conn *conn); + #endif /* conntrack-private.h */ +diff --git a/openvswitch-2.14.2/lib/conntrack-tcp.c b/openvswitch-2.14.2/lib/conntrack-tcp.c +index 18a2aa7..56334e0 100644 +--- a/openvswitch-2.14.2/lib/conntrack-tcp.c ++++ b/openvswitch-2.14.2/lib/conntrack-tcp.c +@@ -160,6 +160,43 @@ tcp_bypass_seq_chk(struct conntrack *ct) + return false; + } + ++static void ++tcp_conn_update_status(struct conntrack *ct, struct conn_tcp *conn, ++ bool reply, uint16_t tcp_flags, long long now) ++{ ++ struct tcp_peer *src = &conn->peer[reply ? 1 : 0]; ++ struct tcp_peer *dst = &conn->peer[reply ? 0 : 1]; ++ ++ if (tcp_flags & TCP_SYN && src->state < CT_DPIF_TCPS_SYN_SENT) { ++ src->state = CT_DPIF_TCPS_SYN_SENT; ++ } ++ if (tcp_flags & TCP_FIN && src->state < CT_DPIF_TCPS_CLOSING) { ++ src->state = CT_DPIF_TCPS_CLOSING; ++ } ++ if (tcp_flags & TCP_ACK) { ++ if (dst->state == CT_DPIF_TCPS_SYN_SENT) { ++ dst->state = CT_DPIF_TCPS_ESTABLISHED; ++ } else if (dst->state == CT_DPIF_TCPS_CLOSING) { ++ dst->state = CT_DPIF_TCPS_FIN_WAIT_2; ++ } ++ } ++ if (tcp_flags & TCP_RST) { ++ src->state = dst->state = CT_DPIF_TCPS_TIME_WAIT; ++ } ++ ++ if (src->state >= CT_DPIF_TCPS_FIN_WAIT_2 && dst->state >= CT_DPIF_TCPS_FIN_WAIT_2) { ++ conn_update_expiration(ct, &conn->up, CT_TM_TCP_CLOSED, now); ++ } else if (src->state >= CT_DPIF_TCPS_CLOSING && dst->state >= CT_DPIF_TCPS_CLOSING) { ++ conn_update_expiration(ct, &conn->up, CT_TM_TCP_FIN_WAIT, now); ++ } else if (src->state < CT_DPIF_TCPS_ESTABLISHED || dst->state < CT_DPIF_TCPS_ESTABLISHED) { ++ conn_update_expiration(ct, &conn->up, CT_TM_TCP_OPENING, now); ++ } else if (src->state >= CT_DPIF_TCPS_CLOSING || dst->state >= CT_DPIF_TCPS_CLOSING) { ++ conn_update_expiration(ct, &conn->up, CT_TM_TCP_CLOSING, now); ++ } else { ++ conn_update_expiration(ct, &conn->up, CT_TM_TCP_ESTABLISHED, now); ++ } ++} ++ + static enum ct_update_res + tcp_conn_update(struct conntrack *ct, struct conn *conn_, + struct dp_packet *pkt, bool reply, long long now) +@@ -408,8 +445,12 @@ tcp_conn_update(struct conntrack *ct, struct conn *conn_, + src->state = dst->state = CT_DPIF_TCPS_TIME_WAIT; + } + } else { ++#ifdef HAVE_HWOFF_AGENT ++ tcp_conn_update_status(ct, conn, reply, tcp_flags, now); ++#else + COVERAGE_INC(conntrack_tcp_seq_chk_failed); + return CT_UPDATE_INVALID; ++#endif + } + + return CT_UPDATE_VALID; +@@ -518,3 +559,25 @@ struct ct_l4_proto ct_proto_tcp = { + .conn_update = tcp_conn_update, + .conn_get_protoinfo = tcp_conn_get_protoinfo, + }; ++ ++enum ct_timeout tcp_conn_timeout_get(const struct conn *conn) ++{ ++ struct conn_tcp *conn_tcp = conn_tcp_cast(conn); ++ struct tcp_peer *src = &conn_tcp->peer[0]; ++ struct tcp_peer *dst = &conn_tcp->peer[1]; ++ enum ct_timeout tm; ++ ++ if (src->state >= CT_DPIF_TCPS_FIN_WAIT_2 && dst->state >= CT_DPIF_TCPS_FIN_WAIT_2) { ++ tm = CT_TM_TCP_CLOSED; ++ } else if (src->state >= CT_DPIF_TCPS_CLOSING && dst->state >= CT_DPIF_TCPS_CLOSING) { ++ tm = CT_TM_TCP_FIN_WAIT; ++ } else if (src->state < CT_DPIF_TCPS_ESTABLISHED || dst->state < CT_DPIF_TCPS_ESTABLISHED) { ++ tm = CT_TM_TCP_OPENING; ++ } else if (src->state >= CT_DPIF_TCPS_CLOSING || dst->state >= CT_DPIF_TCPS_CLOSING) { ++ tm = CT_TM_TCP_CLOSING; ++ } else { ++ tm = CT_TM_TCP_ESTABLISHED; ++ } ++ return tm; ++} ++ +diff --git a/openvswitch-2.14.2/lib/conntrack-tp.c b/openvswitch-2.14.2/lib/conntrack-tp.c +index a586d3a..ac2c48c 100644 +--- a/openvswitch-2.14.2/lib/conntrack-tp.c ++++ b/openvswitch-2.14.2/lib/conntrack-tp.c +@@ -281,6 +281,29 @@ conn_update_expiration(struct conntrack *ct, struct conn *conn, + conn_update_expiration__(ct, conn, tm, now, val); + } + ++#ifdef HAVE_HWOFF_AGENT ++/* The conn entry lock and ct_lock must be held by user */ ++void ++conn_update_expiration_no_lock(struct conntrack *ct, struct conn *conn, ++ enum ct_timeout tm, long long now) ++{ ++ struct timeout_policy *tp; ++ uint32_t val; ++ tp = timeout_policy_lookup(ct, conn->tp_id); ++ if (tp) { ++ val = tp->policy.attrs[tm_to_ct_dpif_tp(tm)]; ++ } else { ++ val = ct_dpif_netdev_tp_def[tm_to_ct_dpif_tp(tm)]; ++ } ++ ++ if (!conn->cleaned) { ++ conn->expiration = now + val * 1000; ++ ovs_list_remove(&conn->exp_node); ++ ovs_list_push_back(&ct->exp_lists[tm], &conn->exp_node); ++ } ++} ++#endif ++ + static void + conn_init_expiration__(struct conntrack *ct, struct conn *conn, + enum ct_timeout tm, long long now, +diff --git a/openvswitch-2.14.2/lib/conntrack-tp.h b/openvswitch-2.14.2/lib/conntrack-tp.h +index 4d411d1..58d9c89 100644 +--- a/openvswitch-2.14.2/lib/conntrack-tp.h ++++ b/openvswitch-2.14.2/lib/conntrack-tp.h +@@ -27,4 +27,8 @@ void conn_init_expiration(struct conntrack *ct, struct conn *conn, + enum ct_timeout tm, long long now); + void conn_update_expiration(struct conntrack *ct, struct conn *conn, + enum ct_timeout tm, long long now); ++#ifdef HAVE_HWOFF_AGENT ++void conn_update_expiration_no_lock(struct conntrack *ct, struct conn *conn, ++ enum ct_timeout tm, long long now); ++#endif + #endif +diff --git a/openvswitch-2.14.2/lib/conntrack.c b/openvswitch-2.14.2/lib/conntrack.c +index 6938dcb..9b3f743 100644 +--- a/openvswitch-2.14.2/lib/conntrack.c ++++ b/openvswitch-2.14.2/lib/conntrack.c +@@ -47,13 +47,7 @@ COVERAGE_DEFINE(conntrack_full); + COVERAGE_DEFINE(conntrack_long_cleanup); + COVERAGE_DEFINE(conntrack_l4csum_err); + +-struct conn_lookup_ctx { +- struct conn_key key; +- struct conn *conn; +- uint32_t hash; +- bool reply; +- bool icmp_related; +-}; ++ + + enum ftp_ctl_pkt { + /* Control packets with address and/or port specifiers. */ +@@ -83,10 +77,13 @@ struct zone_limit { + struct conntrack_zone_limit czl; + }; + +-static bool conn_key_extract(struct conntrack *, struct dp_packet *, +- ovs_be16 dl_type, struct conn_lookup_ctx *, +- uint16_t zone); +-static uint32_t conn_key_hash(const struct conn_key *, uint32_t basis); ++bool conn_key_extract(struct conntrack *, struct dp_packet *, ++ ovs_be16 dl_type, struct conn_lookup_ctx *, ++ uint16_t zone); ++uint32_t conn_key_hash(const struct conn_key *, uint32_t basis); ++bool conn_key_lookup(struct conntrack *ct, const struct conn_key *key, ++ uint32_t hash, long long now, struct conn **conn_out, bool *reply); ++void conn_to_ct_dpif_entry(const struct conn *conn, struct ct_dpif_entry *entry, long long now); + static void conn_key_reverse(struct conn_key *); + static bool valid_new(struct dp_packet *pkt, struct conn_key *); + static struct conn *new_conn(struct conntrack *ct, struct dp_packet *pkt, +@@ -288,6 +285,15 @@ ct_print_conn_info(const struct conn *c, const char *log_msg, + } + } + ++#ifdef HAVE_HWOFF_AGENT ++static ct_offload_class *g_ct_offload_class = NULL; ++void reg_ct_offload_class(ct_offload_class *class) ++{ ++ /* save in global var for now, because hwoff_agent is inited before conntrack is created. ++ will be used in conntrack_init */ ++ g_ct_offload_class = class; ++} ++#endif + /* Initializes the connection tracker 'ct'. The caller is responsible for + * calling 'conntrack_destroy()', when the instance is not needed anymore */ + struct conntrack * +@@ -301,7 +307,7 @@ conntrack_init(void) + hindex_init(&ct->alg_expectation_refs); + ovs_rwlock_unlock(&ct->resources_lock); + +- ovs_mutex_init_adaptive(&ct->ct_lock); ++ ovs_mutex_init_recursive(&ct->ct_lock); + ovs_mutex_lock(&ct->ct_lock); + cmap_init(&ct->conns); + for (unsigned i = 0; i < ARRAY_SIZE(ct->exp_lists); i++) { +@@ -319,7 +325,12 @@ conntrack_init(void) + latch_init(&ct->clean_thread_exit); + ct->clean_thread = ovs_thread_create("ct_clean", clean_thread_main, ct); + ct->ipf = ipf_init(); +- ++#ifdef HAVE_HWOFF_AGENT ++ ct->offload_class = g_ct_offload_class; ++ if (ct->offload_class != NULL && ct->offload_class->cleaned == 0) { ++ ct->offload_class->ovs_ct_init_notify(ct); ++ } ++#endif + return ct; + } + +@@ -432,6 +443,12 @@ static void + conn_clean_cmn(struct conntrack *ct, struct conn *conn) + OVS_REQUIRES(ct->ct_lock) + { ++#ifdef HAVE_HWOFF_AGENT ++ if (ct->offload_class && ct->offload_class->cleaned == 0) { ++ ct->offload_class->conn_state_notify(conn, CONN_STATE_DELETE); ++ } ++#endif ++ + if (conn->alg) { + expectation_clean(ct, &conn->key); + } +@@ -524,7 +541,7 @@ conntrack_destroy(struct conntrack *ct) + } + + +-static bool ++bool + conn_key_lookup(struct conntrack *ct, const struct conn_key *key, + uint32_t hash, long long now, struct conn **conn_out, + bool *reply) +@@ -1098,6 +1115,9 @@ conn_update_state(struct conntrack *ct, struct dp_packet *pkt, + switch (res) { + case CT_UPDATE_VALID: + pkt->md.ct_state |= CS_ESTABLISHED; ++#ifdef HAVE_HWOFF_AGENT ++ conn->offload_info.is_ct_established = true; ++#endif + pkt->md.ct_state &= ~CS_NEW; + if (ctx->reply) { + pkt->md.ct_state |= CS_REPLY_DIR; +@@ -1382,8 +1402,15 @@ process_one(struct conntrack *ct, struct dp_packet *pkt, + handle_alg_ctl(ct, ctx, pkt, ct_alg_ctl, conn, now, !!nat_action_info); + + set_cached_conn(nat_action_info, ctx, conn, pkt); ++ ++#ifdef HAVE_HWOFF_AGENT ++ if (ct->offload_class && ct->offload_class->cleaned == 0) { ++ ct->offload_class->complete_ct_info(conn, pkt); ++ } ++#endif + } + ++ + /* Sends the packets in '*pkt_batch' through the connection tracker 'ct'. All + * the packets must have the same 'dl_type' (IPv4 or IPv6) and should have + * the l3 and and l4 offset properly set. Performs fragment reassembly with +@@ -1478,6 +1505,21 @@ set_label(struct dp_packet *pkt, struct conn *conn, + } + + ++#ifdef HAVE_HWOFF_AGENT ++static void ++ct_update_expiration(struct conntrack *ct) ++{ ++ struct conn *conn; ++ if (!ovs_mutex_trylock(&ct->ct_lock)) { ++ CMAP_FOR_EACH(conn, cm_node, &ct->conns) { ++ if (ct->offload_class && ct->offload_class->cleaned == 0) { ++ ct->offload_class->update_conn_statistics(conn); ++ } ++ } ++ ovs_mutex_unlock(&ct->ct_lock); ++ } ++} ++#endif + /* Delete the expired connections from 'ctb', up to 'limit'. Returns the + * earliest expiration time among the remaining connections in 'ctb'. Returns + * LLONG_MAX if 'ctb' is empty. The return value might be smaller than 'now', +@@ -1563,6 +1605,9 @@ clean_thread_main(void *f_) + + while (!latch_is_set(&ct->clean_thread_exit)) { + long long next_wake; ++#ifdef HAVE_HWOFF_AGENT ++ ct_update_expiration(ct); ++#endif + long long now = time_msec(); + next_wake = conntrack_clean(ct, now); + +@@ -1657,6 +1702,65 @@ extract_l3_ipv6(struct conn_key *key, const void *data, size_t size, + return true; + } + ++#ifdef HAVE_HWOFF_AGENT ++#define TCP_LEN_SHIFT 2 ++static inline bool ++is_vaild_tcp_length(const struct tcp_header *tcp, size_t size) ++{ ++ if (size < sizeof *tcp) { ++ return false; ++ } ++ size_t tcp_len = TCP_OFFSET(tcp->tcp_ctl) << TCP_LEN_SHIFT; ++ return !(OVS_UNLIKELY(tcp_len > size || tcp_len < TCP_HEADER_LEN)); ++} ++ ++static inline bool ++check_l4_tcp(const struct conn_key *key OVS_UNUSED, const void *data, size_t size, ++ const void *l3 OVS_UNUSED, bool validate_checksum OVS_UNUSED) ++{ ++ const struct tcp_header *tcp = data; ++ if(!is_vaild_tcp_length(tcp, size)) { ++ return false; ++ } ++ ++ return true; ++} ++ ++static inline bool ++is_vaild_udp_length(const struct udp_header *udp, size_t size) ++{ ++ if (size < sizeof *udp) { ++ return false; ++ } ++ size_t udp_len = ntohs(udp->udp_len); ++ return !(OVS_UNLIKELY(udp_len > size || udp_len < UDP_HEADER_LEN)); ++} ++ ++static inline bool ++check_l4_udp(const struct conn_key *key OVS_UNUSED, const void *data, size_t size, ++ const void *l3 OVS_UNUSED, bool validate_checksum OVS_UNUSED) ++{ ++ const struct udp_header *udp = data; ++ if(!is_vaild_udp_length(udp, size)) { ++ return false; ++ } ++ return true; ++} ++ ++static inline bool ++check_l4_icmp(const void *data OVS_UNUSED, size_t size OVS_UNUSED, bool validate_checksum OVS_UNUSED) ++{ ++ return true; ++} ++ ++static inline bool ++check_l4_icmp6(const struct conn_key *key OVS_UNUSED, const void *data OVS_UNUSED, size_t size OVS_UNUSED, ++ const void *l3 OVS_UNUSED, bool validate_checksum OVS_UNUSED) ++{ ++ return true; ++} ++#else ++ + static inline bool + checksum_valid(const struct conn_key *key, const void *data, size_t size, + const void *l3) +@@ -1725,6 +1829,7 @@ check_l4_icmp6(const struct conn_key *key, const void *data, size_t size, + { + return validate_checksum ? checksum_valid(key, data, size, l3) : true; + } ++#endif + + static inline bool + extract_l4_tcp(struct conn_key *key, const void *data, size_t size, +@@ -1987,7 +2092,7 @@ extract_l4(struct conn_key *key, const void *data, size_t size, bool *related, + } + } + +-static bool ++bool + conn_key_extract(struct conntrack *ct, struct dp_packet *pkt, ovs_be16 dl_type, + struct conn_lookup_ctx *ctx, uint16_t zone) + { +@@ -2088,7 +2193,7 @@ ct_endpoint_hash_add(uint32_t hash, const struct ct_endpoint *ep) + } + + /* Symmetric */ +-static uint32_t ++uint32_t + conn_key_hash(const struct conn_key *key, uint32_t basis) + { + uint32_t hsrc, hdst, hash; +@@ -2361,7 +2466,9 @@ static struct conn * + new_conn(struct conntrack *ct, struct dp_packet *pkt, struct conn_key *key, + long long now, uint32_t tp_id) + { +- return l4_protos[key->nw_proto]->new_conn(ct, pkt, now, tp_id); ++ ++ struct conn *conn = l4_protos[key->nw_proto]->new_conn(ct, pkt, now, tp_id); ++ return conn; + } + + static void +@@ -2475,7 +2582,7 @@ tuple_to_conn_key(const struct ct_dpif_tuple *tuple, uint16_t zone, + key->zone = zone; + } + +-static void ++void + conn_to_ct_dpif_entry(const struct conn *conn, struct ct_dpif_entry *entry, + long long now) + { +@@ -2495,6 +2602,14 @@ conn_to_ct_dpif_entry(const struct conn *conn, struct ct_dpif_entry *entry, + if (class->conn_get_protoinfo) { + class->conn_get_protoinfo(conn, &entry->protoinfo); + } ++ ++#ifdef HAVE_HWOFF_AGENT ++ if (g_ct_offload_class) { ++ entry->print_offload = false; ++ g_ct_offload_class->get_ct_offload_info(conn, entry); ++ } ++#endif ++ + ovs_mutex_unlock(&conn->lock); + + entry->timeout = (expiration > 0) ? expiration / 1000 : 0; +@@ -2557,6 +2672,71 @@ conntrack_dump_done(struct conntrack_dump *dump OVS_UNUSED) + return 0; + } + ++#ifdef HAVE_HWOFF_AGENT ++static bool ++conntrack_ipv6_compare(struct in6_addr *sip1, struct in6_addr *sip2, ++ struct in6_addr *mask) ++{ ++ struct in6_addr src_ip = ipv6_addr_bitand(sip1, mask); ++ struct in6_addr dst_ip = ipv6_addr_bitand(sip2, mask); ++ return !memcmp(&src_ip, &dst_ip, sizeof(struct in6_addr)); ++} ++ ++static bool ++conntrack_ipv4_compare(ovs_be32 sip1, ovs_be32 sip2, ++ ovs_be32 mask) ++{ ++ return ((sip1 & mask) == (sip2 & mask)); ++} ++ ++static bool ++conntrack_ip_compare(union ct_addr *ip1, union ct_addr *ip2, ++ union ct_addr *mask, uint16_t dl_type, uint16_t conn_dl_type) ++{ ++ if (ip1 == NULL || ip2 == NULL || mask == NULL) { ++ return false; ++ } ++ ++ if (htons(dl_type) != conn_dl_type) { ++ return false; ++ } ++ ++ if (dl_type == ETH_TYPE_IP) { ++ return conntrack_ipv4_compare(ip1->ipv4, ip2->ipv4, mask->ipv4); ++ } ++ ++ return conntrack_ipv6_compare(&ip1->ipv6, &ip2->ipv6, &mask->ipv6); ++} ++ ++int ++conntrack_flush(struct conntrack *ct, const uint16_t *zone, ++ union ct_addr *sip, union ct_addr *dip, ++ union ct_addr *smask, union ct_addr *dmask, ++ uint16_t dl_type, bool is_force) ++{ ++ struct conn *conn; ++ ++ ovs_mutex_lock(&ct->ct_lock); ++ CMAP_FOR_EACH(conn, cm_node, &ct->conns) { ++ if ((!zone || *zone == conn->key.zone) ++ && (conn->conn_type == CT_CONN_TYPE_DEFAULT) ++ && (!sip || !smask || conntrack_ip_compare(sip, &conn->key.src.addr, ++ smask, dl_type, conn->key.dl_type)) ++ && (!dip || !dmask || conntrack_ip_compare(dip, &conn->key.dst.addr, ++ dmask, dl_type, conn->key.dl_type))) { ++ /* Special deal for elb streams, keep it */ ++ if (!is_force && conn->label.u32[0]) { ++ continue; ++ } ++ conn_clean_one(ct, conn); ++ } ++ ++ } ++ ovs_mutex_unlock(&ct->ct_lock); ++ ++ return 0; ++} ++#else + int + conntrack_flush(struct conntrack *ct, const uint16_t *zone) + { +@@ -2572,6 +2752,7 @@ conntrack_flush(struct conntrack *ct, const uint16_t *zone) + + return 0; + } ++#endif + + int + conntrack_flush_tuple(struct conntrack *ct, const struct ct_dpif_tuple *tuple, +diff --git a/openvswitch-2.14.2/lib/conntrack.h b/openvswitch-2.14.2/lib/conntrack.h +index 9553b18..7e342c5 100644 +--- a/openvswitch-2.14.2/lib/conntrack.h ++++ b/openvswitch-2.14.2/lib/conntrack.h +@@ -132,7 +132,14 @@ int conntrack_dump_start(struct conntrack *, struct conntrack_dump *, + int conntrack_dump_next(struct conntrack_dump *, struct ct_dpif_entry *); + int conntrack_dump_done(struct conntrack_dump *); + ++#ifdef HAVE_HWOFF_AGENT ++int conntrack_flush(struct conntrack *ct, const uint16_t *zone, ++ union ct_addr *sip, union ct_addr *dip, ++ union ct_addr *smask, union ct_addr *dmask, ++ uint16_t dl_type, bool is_force); ++#else + int conntrack_flush(struct conntrack *, const uint16_t *zone); ++#endif + int conntrack_flush_tuple(struct conntrack *, const struct ct_dpif_tuple *, + uint16_t zone); + int conntrack_set_maxconns(struct conntrack *ct, uint32_t maxconns); +diff --git a/openvswitch-2.14.2/lib/ct-dpif.c b/openvswitch-2.14.2/lib/ct-dpif.c +index 8c2480e..d7566c9 100644 +--- a/openvswitch-2.14.2/lib/ct-dpif.c ++++ b/openvswitch-2.14.2/lib/ct-dpif.c +@@ -118,6 +118,36 @@ ct_dpif_dump_done(struct ct_dpif_dump_state *dump) + * entries in '*zone'. + * - If 'tuple' is not NULL, flush the conntrack entry specified by 'tuple' + * in '*zone'. If 'zone' is NULL, use the default zone (zone 0). */ ++#ifdef HAVE_HWOFF_AGENT ++typedef int (*ct_flush_t)(struct dpif *, const uint16_t *zone, ++ union ct_addr *sip, union ct_addr *dip, ++ union ct_addr *smask, union ct_addr *dmask, uint16_t dl_type, bool is_force); ++static inline void ++log_ct_flush(struct dpif *dpif, const uint16_t *zone) ++{ ++ if (zone) { ++ VLOG_DBG("%s: ct_flush: %"PRIu16, dpif_name(dpif), *zone); ++ } else { ++ VLOG_DBG("%s: ct_flush: ", dpif_name(dpif)); ++ } ++ ++} ++ ++int ++ct_dpif_flush(struct dpif *dpif, const uint16_t *zone, ++ union ct_addr *sip, union ct_addr *dip, ++ union ct_addr *smask, union ct_addr *dmask, ++ uint16_t dl_type, bool is_force) ++{ ++ ct_flush_t ct_flush = NULL; ++ ++ log_ct_flush(dpif, zone); ++ ++ ct_flush = dpif->dpif_class->ct_flush; ++ ++ return ct_flush ? ct_flush(dpif, zone, sip, dip, smask, dmask, dl_type, is_force) : EOPNOTSUPP; ++} ++#else + int + ct_dpif_flush(struct dpif *dpif, const uint16_t *zone, + const struct ct_dpif_tuple *tuple) +@@ -138,6 +168,7 @@ ct_dpif_flush(struct dpif *dpif, const uint16_t *zone, + ? dpif->dpif_class->ct_flush(dpif, zone, tuple) + : EOPNOTSUPP); + } ++#endif + + int + ct_dpif_set_maxconns(struct dpif *dpif, uint32_t maxconns) +@@ -328,6 +359,11 @@ ct_dpif_format_entry(const struct ct_dpif_entry *entry, struct ds *ds, + ct_dpif_format_tuple(ds, &entry->tuple_master); + ds_put_cstr(ds, ")"); + } ++ ++ if (entry->print_offload) { ++ ds_put_format(ds, ",offloaded=(orig=%s,", entry->init_dir_offload_state); ++ ds_put_format(ds, "reply=%s)", entry->reply_dir_offload_state); ++ } + } + + void +diff --git a/openvswitch-2.14.2/lib/ct-dpif.h b/openvswitch-2.14.2/lib/ct-dpif.h +index e4c7a64..cee924c 100644 +--- a/openvswitch-2.14.2/lib/ct-dpif.h ++++ b/openvswitch-2.14.2/lib/ct-dpif.h +@@ -20,6 +20,8 @@ + #include "openvswitch/types.h" + #include "packets.h" + ++union ct_addr; ++ + union ct_dpif_inet_addr { + ovs_be32 ip; + ovs_be32 ip6[4]; +@@ -197,6 +199,9 @@ struct ct_dpif_entry { + uint32_t timeout; + uint32_t mark; + uint32_t bkt; /* CT bucket number. */ ++ bool print_offload; ++ const char *init_dir_offload_state; ++ const char *reply_dir_offload_state; + }; + + enum { +@@ -275,8 +280,15 @@ int ct_dpif_dump_start(struct dpif *, struct ct_dpif_dump_state **, + const uint16_t *zone, int *); + int ct_dpif_dump_next(struct ct_dpif_dump_state *, struct ct_dpif_entry *); + int ct_dpif_dump_done(struct ct_dpif_dump_state *); ++#ifdef HAVE_HWOFF_AGENT ++int ct_dpif_flush(struct dpif *dpif, const uint16_t *zone, ++ union ct_addr *sip, union ct_addr *dip, ++ union ct_addr *smask, union ct_addr *dmask, ++ uint16_t dl_type, bool is_force); ++#else + int ct_dpif_flush(struct dpif *, const uint16_t *zone, + const struct ct_dpif_tuple *); ++#endif + int ct_dpif_set_maxconns(struct dpif *dpif, uint32_t maxconns); + int ct_dpif_get_maxconns(struct dpif *dpif, uint32_t *maxconns); + int ct_dpif_get_nconns(struct dpif *dpif, uint32_t *nconns); +diff --git a/openvswitch-2.14.2/lib/ct_dump_extend/ct_dump_extend.c b/openvswitch-2.14.2/lib/ct_dump_extend/ct_dump_extend.c +new file mode 100644 +index 0000000..5ff5085 +--- /dev/null ++++ b/openvswitch-2.14.2/lib/ct_dump_extend/ct_dump_extend.c +@@ -0,0 +1,202 @@ ++/* ++ * Copyright (c) 2022-2022. Huawei Technologies Co., Ltd. ++ * Description: dump conntrack extend implementations ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ * ++ * Create: 2022-03-24 ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "conntrack.h" ++#include "conntrack-private.h" ++#include "ct-dpif.h" ++#include "dpif-netdev.h" ++#include "openvswitch/vlog.h" ++#include "ct_dump_extend.h" ++ ++#include "ovs-atomic.h" ++ ++#define CT_DPIF_DUMP_FLOWS_MAX 3000U ++ ++enum ct_dpif_dump_status { ++ CT_DPIF_DUMP_END, ++ CT_DPIF_DUMP_START, ++}; ++ ++struct ct_dpif_dump_context { ++ pthread_mutex_t mutex; ++ FILE *file; ++ char file_name[PATH_MAX]; ++ bool verbosity; ++ bool print_statistics; ++ uint16_t zone; ++ const uint16_t *pzone; ++ atomic_count dump_flag; ++ pthread_t thread_id; ++ struct ct_dpif_dump_state *dump_state; ++ struct dpif *ct_dpif; ++}; ++ ++VLOG_DEFINE_THIS_MODULE(ct_dump_extend); ++ ++static struct ct_dpif_dump_context g_ct_dpif_dump_context = { 0 }; ++ ++static int ++ct_dump_open_file(const char *file_name, struct ds *ds) ++{ ++ struct ct_dpif_dump_context *dump_context = &g_ct_dpif_dump_context; ++ ++ if (file_name[0] != '/') { ++ ds_put_format(ds, "file name \"%s\"error: Need absolute path\n", file_name); ++ return -1; ++ } ++ ++ dump_context->file = fopen(file_name, "w+"); ++ if (dump_context->file == NULL) { ++ ds_put_format(ds, "file : %s open failed.\n", file_name); ++ return -1; ++ } ++ ++ return 0; ++}; ++ ++static void hwoff_ct_dump_flow_to_file_start(void) ++{ ++ int ret = 0; ++ int count = 0; ++ int error; ++ int tot_bkts; ++ struct ct_dpif_entry entry; ++ struct ds ds = DS_EMPTY_INITIALIZER; ++ struct ct_dpif_dump_context *dump_context = &g_ct_dpif_dump_context; ++ ++ ret = ct_dpif_dump_start(dump_context->ct_dpif, &dump_context->dump_state, ++ dump_context->pzone, &tot_bkts); ++ if (ret != 0) { ++ VLOG_ERR("ct dpif dump flow start filed ! ret = %d", ret); ++ goto start_err; ++ } ++ ret = ct_dump_open_file(dump_context->file_name, &ds); ++ if (ret != 0) { ++ goto open_err; ++ } ++ ++ while (!(error = ct_dpif_dump_next(dump_context->dump_state, &entry))) { ++ count++; ++ ct_dpif_format_entry(&entry, &ds, dump_context->verbosity, ++ dump_context->print_statistics); ++ ct_dpif_entry_uninit(&entry); ++ ds_put_format(&ds, "\n"); ++ if (count >= CT_DPIF_DUMP_FLOWS_MAX) { ++ ret = fwrite(ds_cstr(&ds), strlen(ds_cstr(&ds)), 1, dump_context->file); ++ if (ret != 1 && ferror(dump_context->file) != 0) { ++ VLOG_ERR("ct flow write to file failed ! ret = %d\n", ret); ++ break; ++ } ++ count = 0; ++ ds_clear(&ds); ++ } ++ } ++ /* Any CT entry was dumped with no issue. */ ++ if (error == EOF) { ++ VLOG_INFO("ct flow dump to file done.\n"); ++ ret = fwrite(ds_cstr(&ds), strlen(ds_cstr(&ds)), 1, dump_context->file); ++ if (ret != 1 && ferror(dump_context->file) != 0) { ++ VLOG_ERR("ct flow write to file failed ! ret = %d\n", ret); ++ } ++ } else if (error) { ++ VLOG_ERR("ct flow dump to file failed ! error = %d\n", error); ++ } ++ ++ fclose(dump_context->file); ++ dump_context->file = NULL; ++open_err: ++ ds_destroy(&ds); ++ ct_dpif_dump_done(dump_context->dump_state); ++ dump_context->dump_state = NULL; ++start_err: ++ dpif_close(dump_context->ct_dpif); ++ dump_context->ct_dpif = NULL; ++ atomic_count_set(&dump_context->dump_flag, CT_DPIF_DUMP_END); ++} ++ ++int ++hwoff_dpctl_dump_write(struct ct_dump_extend *dump) ++{ ++ struct ct_dpif_dump_context *dump_context = &g_ct_dpif_dump_context; ++ char *resolve_path = NULL; ++ char *result = NULL; ++ ++ if (strnlen(dump->file_name, PATH_MAX) == 0) { ++ ds_put_format(dump->ds, "file name length is 0\n"); ++ return -1; ++ } ++ if (strnlen(dump->file_name, PATH_MAX) >= PATH_MAX) { ++ ds_put_format(dump->ds, "file name too long, length need less than %d, actually %zu\n", ++ PATH_MAX, strnlen(dump->file_name, PATH_MAX)); ++ return -1; ++ } ++ ++ resolve_path = (char *)malloc(PATH_MAX); ++ if (!resolve_path) { ++ ds_put_format(dump->ds, "malloc memmory for ct file real path failed\n"); ++ return -1; ++ } ++ memset(resolve_path, 0, PATH_MAX); ++ result = realpath(dump->file_name, resolve_path); ++ (void)result; ++ ++ if ((strlen(resolve_path) == 0) || (strlen(resolve_path) >= PATH_MAX)) { ++ ds_put_format(dump->ds, "resolve path %s is invalid\n", resolve_path); ++ free(resolve_path); ++ return -1; ++ } ++ ++ if (strcmp(resolve_path, dump->file_name) != 0) { ++ ds_put_format(dump->ds, "file path is incorrect, please check the file path\n"); ++ free(resolve_path); ++ return -1; ++ } ++ ++ memset(dump_context->file_name, 0, PATH_MAX); ++ strncpy(dump_context->file_name, resolve_path, PATH_MAX - 1); ++ free(resolve_path); ++ ++ dump_context->verbosity = dump->verbosity; ++ dump_context->print_statistics = dump->print_statistics; ++ dump_context->ct_dpif = dump->ct_dpif; ++ if (dump->pzone != NULL) { ++ dump_context->zone = *dump->pzone; ++ dump_context->pzone = &dump_context->zone; ++ } ++ ++ pthread_mutex_lock(&dump_context->mutex); ++ if (CT_DPIF_DUMP_END != atomic_count_get(&dump_context->dump_flag)) { ++ ds_put_format(dump->ds, "A threads for dumping CT flows is running. Try again later. thread id = %lu\n", ++ dump_context->thread_id); ++ pthread_mutex_unlock(&dump_context->mutex); ++ return -1; ++ } ++ atomic_count_set(&dump_context->dump_flag, CT_DPIF_DUMP_START); ++ pthread_mutex_unlock(&dump_context->mutex); ++ ++ ds_put_format(dump->ds, "starting dump ct flow to file: %s.\n", dump->file_name); ++ dump_context->thread_id = ovs_thread_create("hwoff_dump_ct_flow_to_file", (void *)hwoff_ct_dump_flow_to_file_start, NULL); ++ VLOG_INFO("dump ct flow to file thread id = %lu", dump_context->thread_id); ++ return 0; ++} +diff --git a/openvswitch-2.14.2/lib/ct_dump_extend/ct_dump_extend.h b/openvswitch-2.14.2/lib/ct_dump_extend/ct_dump_extend.h +new file mode 100644 +index 0000000..1551573 +--- /dev/null ++++ b/openvswitch-2.14.2/lib/ct_dump_extend/ct_dump_extend.h +@@ -0,0 +1,34 @@ ++/* ++ * Copyright (c) 2022-2022. Huawei Technologies Co., Ltd. ++ * Description: dump conntrack extend definitions ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ * ++ * Create: 2022-03-24 ++ */ ++ ++#ifndef CT_DUMP_EXTEND_CT_H ++#define CT_DUMP_EXTEND_CT_H ++ ++struct ct_dump_extend { ++ bool verbosity; ++ bool print_statistics; ++ const char *file_name; ++ const uint16_t *pzone; ++ struct ds *ds; ++ struct dpif *ct_dpif; ++}; ++ ++int hwoff_dpctl_dump_write(struct ct_dump_extend *dump); ++ ++#endif +diff --git a/openvswitch-2.14.2/lib/ct_offload_provider.h b/openvswitch-2.14.2/lib/ct_offload_provider.h +new file mode 100644 +index 0000000..fb37bc8 +--- /dev/null ++++ b/openvswitch-2.14.2/lib/ct_offload_provider.h +@@ -0,0 +1,49 @@ ++/* ++ * Copyright (c) 2021-2022. Huawei Technologies Co., Ltd. ++ * Description: ct_offload_privider ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ * ++ * Create: 2021-07-09 ++ */ ++#ifndef CT_OFFLOAD_PROVIDER_H ++#define CT_OFFLOAD_PROVIDER_H ++ ++#include "openvswitch/types.h" ++#include "dp-packet.h" ++ ++#ifdef HAVE_HWOFF_AGENT ++#define INVALID_CONN_ID 0 ++ ++typedef uint32_t conn_id; ++struct conn; ++struct conntrack; ++struct ct_dpif_entry; ++ ++enum { ++ CONN_STATE_DELETE, ++}; ++ ++typedef struct { ++ int (*ovs_ct_init_notify)(struct conntrack *ovs_ct); ++ int (*complete_ct_info)(struct conn *conn, struct dp_packet *packet); ++ int (*conn_state_notify)(struct conn *conn, int new_state); ++ int (*get_ct_offload_info)(const struct conn *conn, struct ct_dpif_entry *entry); ++ void (*update_conn_statistics)(struct conn *conn); ++ volatile uint16_t cleaned; ++ volatile uint16_t reserved[3]; ++} ct_offload_class; ++ ++#endif // HAVE_HWOFF_AGENT ++ ++#endif +\ No newline at end of file +diff --git a/openvswitch-2.14.2/lib/dp-packet.h b/openvswitch-2.14.2/lib/dp-packet.h +index 9e2d06b..9dd7421 100644 +--- a/openvswitch-2.14.2/lib/dp-packet.h ++++ b/openvswitch-2.14.2/lib/dp-packet.h +@@ -55,6 +55,7 @@ enum OVS_PACKED_ENUM dp_packet_source { + #endif + + /* Bit masks for the 'ol_flags' member of the 'dp_packet' structure. */ ++#ifdef DPDK_2011_AND_BEFORE + enum dp_packet_offload_mask { + /* Value 0 is not used. */ + /* Is the 'rss_hash' valid? */ +@@ -83,6 +84,36 @@ enum dp_packet_offload_mask { + DEF_OL_FLAG(DP_PACKET_OL_TX_SCTP_CKSUM, PKT_TX_SCTP_CKSUM, 0x800), + /* Adding new field requires adding to DP_PACKET_OL_SUPPORTED_MASK. */ + }; ++#else ++enum dp_packet_offload_mask { ++ /* Value 0 is not used. */ ++ /* Is the 'rss_hash' valid? */ ++ DEF_OL_FLAG(DP_PACKET_OL_RSS_HASH, RTE_MBUF_F_RX_RSS_HASH, 0x1), ++ /* Is the 'flow_mark' valid? */ ++ DEF_OL_FLAG(DP_PACKET_OL_FLOW_MARK, RTE_MBUF_F_RX_FDIR_ID, 0x2), ++ /* Bad L4 checksum in the packet. */ ++ DEF_OL_FLAG(DP_PACKET_OL_RX_L4_CKSUM_BAD, RTE_MBUF_F_RX_L4_CKSUM_BAD, 0x4), ++ /* Bad IP checksum in the packet. */ ++ DEF_OL_FLAG(DP_PACKET_OL_RX_IP_CKSUM_BAD, RTE_MBUF_F_RX_IP_CKSUM_BAD, 0x8), ++ /* Valid L4 checksum in the packet. */ ++ DEF_OL_FLAG(DP_PACKET_OL_RX_L4_CKSUM_GOOD, RTE_MBUF_F_RX_L4_CKSUM_GOOD, 0x10), ++ /* Valid IP checksum in the packet. */ ++ DEF_OL_FLAG(DP_PACKET_OL_RX_IP_CKSUM_GOOD, RTE_MBUF_F_RX_IP_CKSUM_GOOD, 0x20), ++ /* TCP Segmentation Offload. */ ++ DEF_OL_FLAG(DP_PACKET_OL_TX_TCP_SEG, RTE_MBUF_F_TX_TCP_SEG, 0x40), ++ /* Offloaded packet is IPv4. */ ++ DEF_OL_FLAG(DP_PACKET_OL_TX_IPV4, RTE_MBUF_F_TX_IPV4, 0x80), ++ /* Offloaded packet is IPv6. */ ++ DEF_OL_FLAG(DP_PACKET_OL_TX_IPV6, RTE_MBUF_F_TX_IPV6, 0x100), ++ /* Offload TCP checksum. */ ++ DEF_OL_FLAG(DP_PACKET_OL_TX_TCP_CKSUM, RTE_MBUF_F_TX_TCP_CKSUM, 0x200), ++ /* Offload UDP checksum. */ ++ DEF_OL_FLAG(DP_PACKET_OL_TX_UDP_CKSUM, RTE_MBUF_F_TX_UDP_CKSUM, 0x400), ++ /* Offload SCTP checksum. */ ++ DEF_OL_FLAG(DP_PACKET_OL_TX_SCTP_CKSUM, RTE_MBUF_F_TX_SCTP_CKSUM, 0x800), ++ /* Adding new field requires adding to DP_PACKET_OL_SUPPORTED_MASK. */ ++}; ++#endif + + #define DP_PACKET_OL_SUPPORTED_MASK (DP_PACKET_OL_RSS_HASH | \ + DP_PACKET_OL_FLOW_MARK | \ +@@ -558,6 +589,36 @@ dp_packet_set_base(struct dp_packet *b, void *d) + b->mbuf.buf_addr = d; + } + ++#ifdef HAVE_HWOFF_AGENT ++static inline uint32_t ++dp_packet_size(const struct dp_packet *b) ++{ ++ return rte_pktmbuf_pkt_len(&(b->mbuf)); ++} ++ ++static inline void ++hwoff_nonlinear_pkt_set_size(struct dp_packet *b, uint32_t v) ++{ ++ int pack_len_diff = v - b->mbuf.pkt_len; ++ b->mbuf.data_len += pack_len_diff; ++ ++ rte_pktmbuf_pkt_len(&(b->mbuf)) = v; ++} ++ ++static inline void ++dp_packet_set_size(struct dp_packet *b, uint32_t v) ++{ ++ if (b->mbuf.nb_segs <= 1) { ++ rte_pktmbuf_pkt_len(&(b->mbuf)) = v; ++ rte_pktmbuf_data_len(&(b->mbuf)) = v; ++ return; ++ } ++ ++ hwoff_nonlinear_pkt_set_size(b, v); ++} ++ ++#else ++ + static inline uint32_t + dp_packet_size(const struct dp_packet *b) + { +@@ -579,6 +640,7 @@ dp_packet_set_size(struct dp_packet *b, uint32_t v) + b->mbuf.pkt_len = v; /* Total length of all segments linked to + * this segment. */ + } ++#endif + + static inline uint16_t + __packet_data(const struct dp_packet *b) +diff --git a/openvswitch-2.14.2/lib/dpctl.c b/openvswitch-2.14.2/lib/dpctl.c +index b232d43..3ab83c8 100644 +--- a/openvswitch-2.14.2/lib/dpctl.c ++++ b/openvswitch-2.14.2/lib/dpctl.c +@@ -51,6 +51,10 @@ + #include "util.h" + #include "openvswitch/ofp-flow.h" + #include "openvswitch/ofp-port.h" ++#ifdef HAVE_HWOFF_AGENT ++#include "conntrack.h" ++#include "ct_dump_extend/ct_dump_extend.h" ++#endif + + typedef int dpctl_command_handler(int argc, const char *argv[], + struct dpctl_params *); +@@ -811,6 +815,11 @@ format_dpif_flow(struct ds *ds, const struct dpif_flow *f, struct hmap *ports, + if (dpctl_p->verbosity && f->ufid_present) { + odp_format_ufid(&f->ufid, ds); + ds_put_cstr(ds, ", "); ++#ifdef HAVE_HWOFF_AGENT ++ odp_format_mega_ufid(&f->mega_ufid, ds); ++ ds_put_cstr(ds, ", "); ++#endif ++ + } + odp_flow_format(f->key, f->key_len, f->mask, f->mask_len, ports, ds, + dpctl_p->verbosity); +@@ -1421,6 +1430,16 @@ dpctl_dump_conntrack(int argc, const char *argv[], + int tot_bkts; + struct dpif *dpif; + int error; ++#ifdef HAVE_HWOFF_AGENT ++ bool is_need_dump_to_file = false; ++ const char *dump_file_name = NULL; ++ ++ if (argc >= 2 && (strncmp(argv[argc - 2], "-w", sizeof("-w")) == 0)) { ++ is_need_dump_to_file = true; ++ dump_file_name = argv[argc - 1]; ++ argc -= 2; ++ } ++#endif + + if (argc > 1 && ovs_scan(argv[argc - 1], "zone=%"SCNu16, &zone)) { + pzone = &zone; +@@ -1432,6 +1451,30 @@ dpctl_dump_conntrack(int argc, const char *argv[], + return error; + } + ++#ifdef HAVE_HWOFF_AGENT ++ if (is_need_dump_to_file) { ++ struct ds ds = DS_EMPTY_INITIALIZER; ++ struct ct_dump_extend ct_dump = { ++ .file_name = dump_file_name, ++ .verbosity = dpctl_p->verbosity, ++ .print_statistics = dpctl_p->print_statistics, ++ .ct_dpif = dpif, ++ .pzone = pzone, ++ .ds = &ds, ++ }; ++ error = hwoff_dpctl_dump_write(&ct_dump); ++ if (error) { ++ dpctl_error(dpctl_p, error, ds_cstr(&ds)); ++ ds_destroy(&ds); ++ dpif_close(dpif); ++ return error; ++ } ++ dpctl_print(dpctl_p, "%s\n", ds_cstr(&ds)); ++ ds_destroy(&ds); ++ return error; ++ } ++#endif ++ + error = ct_dpif_dump_start(dpif, &dump, pzone, &tot_bkts); + if (error) { + dpctl_error(dpctl_p, error, "starting conntrack dump"); +@@ -1461,6 +1504,188 @@ dpctl_dump_conntrack(int argc, const char *argv[], + return error; + } + ++#ifdef HAVE_HWOFF_AGENT ++static int conntrack_parse_ipv4_mask_len(char *str, union ct_addr *ip, union ct_addr *mask) ++{ ++ /* Mask has the same format with ip, %d prefix */ ++ char *ip_str = NULL; ++ char *mask_str = NULL; ++ uint8_t prefix; ++ ++ if (str == NULL || ip == NULL || mask == NULL) { ++ return -EINVAL; ++ } ++ ++ ip_str = strtok_r(str, "/", &mask_str); ++ if (ip_str != NULL && mask_str != NULL && (*mask_str != '\0')) { ++ if (1 == inet_pton(AF_INET, ip_str, &ip->ipv4) && ++ 1 == sscanf(mask_str, "%"SCNu8, &prefix) && prefix <= IP_MAX_MASK_LEN) { ++ mask->ipv4 = be32_prefix_mask(prefix); ++ /* restore the original str */ ++ *(mask_str - 1) = '/'; ++ return 0; ++ } ++ ++ /* restore the original str */ ++ *(mask_str - 1) = '/'; ++ } else if (ip_str != NULL && inet_pton(AF_INET, ip_str, ip) == 1) { ++ mask->ipv4 = be32_prefix_mask(IP_MAX_MASK_LEN); ++ return 0; ++ } ++ return -EINVAL; ++} ++ ++static int conntrack_parse_ipv6_mask_len(char *str, union ct_addr *ip, union ct_addr *mask) ++{ ++ /* Mask has the same format with ip, %d prefix */ ++ char *ip_str = NULL; ++ char *mask_str = NULL; ++ uint8_t prefix; ++ ++ if (str == NULL || ip == NULL || mask == NULL) { ++ return -EINVAL; ++ } ++ ++ ip_str = strtok_r(str, "/", &mask_str); ++ if (ip_str != NULL && mask_str != NULL && (*mask_str != '\0')) { ++ if (1 == inet_pton(AF_INET6, ip_str, &ip->ipv6) && ++ 1 == sscanf(mask_str, "%"SCNu8, &prefix) && prefix <= IPV6_MAX_MASK_LEN) { ++ mask->ipv6 = ipv6_create_mask(prefix); ++ /* restore the orignal str */ ++ *(mask_str - 1) = '/'; ++ return 0; ++ } ++ /* restore the original str */ ++ *(mask_str - 1) = '/'; ++ } else if (ip_str != NULL && inet_pton(AF_INET6, ip_str, &ip->ipv6) == 1) { ++ (void)memset(mask, sizeof(*mask), 0xff); ++ return 0; ++ } ++ return -EINVAL; ++} ++ ++static int conntrack_flush_get_ip(char *ip_str, union ct_addr *ip, ++ union ct_addr *mask, bool *is_ipv6) ++{ ++ if (conntrack_parse_ipv4_mask_len(ip_str, ip, mask) == 0) { ++ *is_ipv6 = false; ++ return 0; ++ } ++ ++ if (conntrack_parse_ipv6_mask_len(ip_str, ip, mask) == 0) { ++ *is_ipv6 = true; ++ return 0; ++ } ++ ++ return -1; ++} ++ ++static int ++dpctl_flush_conntrack(int argc, const char *argv[], ++ struct dpctl_params *dpctl_p) ++{ ++ int error; ++ uint16_t dl_type; ++ char *ip = NULL; ++ int args = argc - 1; ++ bool is_force = false; ++ struct dpif *dpif = NULL; ++ uint16_t zone, *pzone = NULL; ++ union ct_addr addr_src; ++ union ct_addr mask_src; ++ union ct_addr addr_dst; ++ union ct_addr mask_dst; ++ bool d_addr_ipv4_flag = false; ++ bool d_addr_ipv6_flag = false; ++ bool s_addr_ipv4_flag = false; ++ bool s_addr_ipv6_flag = false; ++ struct ds ds = DS_EMPTY_INITIALIZER; ++ ++ memset(&addr_src, 0, sizeof(union ct_addr)); ++ memset(&addr_dst, 0, sizeof(union ct_addr)); ++ ++ if (args && !strncmp(argv[args], "--force", sizeof("--force") - 1)) { ++ is_force = true; ++ args--; ++ } ++ ++ if (args && !strncmp(argv[args], "dip=", sizeof("dip") - 1)) { ++ ip = xstrdup(argv[args] + (sizeof("dip=") - 1)); ++ error = conntrack_flush_get_ip(ip, &addr_dst, &mask_dst, &d_addr_ipv6_flag); ++ free(ip); ++ if (error) { ++ dpctl_error(dpctl_p, error, "parse dip error."); ++ return error; ++ } ++ d_addr_ipv4_flag = !d_addr_ipv6_flag; ++ args--; ++ } ++ ++ if (args && !strncmp(argv[args], "sip=", sizeof("sip=") - 1)) { ++ ip = xstrdup(argv[args] + (sizeof("sip=") - 1)); ++ error = conntrack_flush_get_ip(ip, &addr_src, &mask_src, &s_addr_ipv6_flag); ++ free(ip); ++ if (error) { ++ dpctl_error(dpctl_p, error, "parse sip error."); ++ return error; ++ } ++ s_addr_ipv4_flag = !s_addr_ipv6_flag; ++ args--; ++ } ++ ++ if ((s_addr_ipv6_flag && d_addr_ipv4_flag) || ++ (s_addr_ipv4_flag && d_addr_ipv6_flag)) { ++ dpctl_error(dpctl_p, EINVAL, "sip/dip mismatch."); ++ return EINVAL; ++ } ++ ++ if (d_addr_ipv6_flag || s_addr_ipv6_flag) { ++ dl_type = ETH_TYPE_IPV6; ++ } else if (d_addr_ipv4_flag || s_addr_ipv4_flag) { ++ dl_type = ETH_TYPE_IP; ++ } else { ++ dl_type = 0; ++ } ++ ++ /* Parse zone */ ++ if (args && ovs_scan(argv[args], "zone=%"SCNu16, &zone)) { ++ pzone = &zone; ++ args--; ++ } ++ ++ /* Report error if there are more than one unparsed argument */ ++ if (args > 1) { ++ ds_put_cstr(&ds, "invalid argument"); ++ error = EINVAL; ++ goto error; ++ } ++ ++ error = opt_dpif_open(argc, argv, dpctl_p, 6, &dpif); ++ if (error) { ++ return error; ++ } ++ ++ error = ct_dpif_flush(dpif, pzone, ++ (s_addr_ipv6_flag || s_addr_ipv4_flag) ? &addr_src : 0, ++ (d_addr_ipv6_flag || d_addr_ipv4_flag) ? &addr_dst : 0, ++ (s_addr_ipv6_flag || s_addr_ipv4_flag) ? &mask_src : 0, ++ (d_addr_ipv6_flag || d_addr_ipv4_flag) ? &mask_dst : 0, ++ dl_type, is_force); ++ ++ if (!error) { ++ dpif_close(dpif); ++ return 0; ++ } ++ ++ ds_put_cstr(&ds, "failed to flush conntrack"); ++ ++error: ++ dpctl_error(dpctl_p, error, "%s", ds_cstr(&ds)); ++ ds_destroy(&ds); ++ dpif_close(dpif); ++ return error; ++} ++#else + static int + dpctl_flush_conntrack(int argc, const char *argv[], + struct dpctl_params *dpctl_p) +@@ -1510,6 +1735,7 @@ error: + dpif_close(dpif); + return error; + } ++#endif + + static int + dpctl_ct_stats_show(int argc, const char *argv[], +@@ -2529,10 +2755,17 @@ static const struct dpctl_command all_commands[] = { + { "get-flow", "[dp] ufid", 1, 2, dpctl_get_flow, DP_RO }, + { "del-flow", "[dp] flow", 1, 2, dpctl_del_flow, DP_RW }, + { "del-flows", "[dp]", 0, 1, dpctl_del_flows, DP_RW }, ++#ifdef HAVE_HWOFF_AGENT ++ { "dump-conntrack", "[-m] [-s] [dp] [zone=N] [-w file]", ++ 0, 4, dpctl_dump_conntrack, DP_RO }, ++ { "flush-conntrack", "[dp] [zone=N] [sip=x.x.x.x/x] [dip=x.x.x.x/x] [--force]", ++ 0, 5, dpctl_flush_conntrack, DP_RW }, ++#else + { "dump-conntrack", "[-m] [-s] [dp] [zone=N]", + 0, 4, dpctl_dump_conntrack, DP_RO }, + { "flush-conntrack", "[dp] [zone=N] [ct-tuple]", 0, 3, + dpctl_flush_conntrack, DP_RW }, ++#endif + { "ct-stats-show", "[dp] [zone=N]", + 0, 3, dpctl_ct_stats_show, DP_RO }, + { "ct-bkts", "[dp] [gt=N]", 0, 2, dpctl_ct_bkts, DP_RO }, +@@ -2675,6 +2908,8 @@ dpctl_unixctl_handler(struct unixctl_conn *conn, int argc, const char *argv[], + case 's': + dpctl_p.print_statistics = true; + break; ++ case 'w': ++ break; + default: + ds_put_format(&ds, "Unrecognized option -%c", *opt); + error = true; +diff --git a/openvswitch-2.14.2/lib/dpdk.c b/openvswitch-2.14.2/lib/dpdk.c +index 2f235a7..df849e3 100644 +--- a/openvswitch-2.14.2/lib/dpdk.c ++++ b/openvswitch-2.14.2/lib/dpdk.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -40,6 +41,17 @@ + #include "unixctl.h" + #include "util.h" + #include "vswitch-idl.h" ++#ifdef HAVE_HWOFF_AGENT ++#include ++#include ++#include "hwoff_init_func.h" ++ ++#define HWOFF_DPDK_HUGEPAGES_PREFIX "rte_dpak_" ++#define HWOFF_DPDK_HUGEPAGES_PATH "/dev/hugepages" ++#define HWOFF_DPDK_RUN_FILE "/var/run/dpdk" ++#define HWOFF_FUNCTION_FLUSH_PF "1" ++#define HWOFF_FUNCTION_FLUSH "/proc/hwoff_function_flush" ++#endif + + VLOG_DEFINE_THIS_MODULE(dpdk); + +@@ -339,6 +351,7 @@ dpdk_unixctl_log_set(struct unixctl_conn *conn, int argc, const char *argv[], + } + + level = dpdk_parse_log_level(level_string); ++ + if (level == -1) { + err_msg = xasprintf("invalid log level: '%s'", level_string); + } else if (rte_log_set_level_pattern(pattern, level) < 0) { +@@ -356,6 +369,104 @@ dpdk_unixctl_log_set(struct unixctl_conn *conn, int argc, const char *argv[], + unixctl_command_reply(conn, NULL); + } + ++#ifdef HAVE_HWOFF_AGENT ++static void ++hwoff_remove_fbarray(const char *path) ++{ ++ char barray_path[PATH_MAX] = {0}; ++ DIR *dir_barray = NULL; ++ struct dirent *barray_dirent = NULL; ++ ++ dir_barray = opendir(path); ++ while ((barray_dirent = readdir(dir_barray)) != NULL) { ++ if (strcmp(barray_dirent->d_name, ".") == 0) { ++ continue; ++ } ++ if (strcmp(barray_dirent->d_name, "..") == 0) { ++ continue; ++ } ++ sprintf(barray_path, "%s/%s", path, barray_dirent->d_name); ++ ++ remove(barray_path); ++ memset(barray_path, 0, sizeof(barray_path)); ++ } ++ closedir(dir_barray); ++ rmdir(path); ++} ++ ++void hwoff_clear_pf_access_hugepages(void) ++{ ++ int flr_file = -1; ++ ++ flr_file = open(HWOFF_FUNCTION_FLUSH, O_WRONLY); ++ if (flr_file < 0) { ++ VLOG_ERR("failed to open file %s with fd %d error %d", ++ HWOFF_FUNCTION_FLUSH, flr_file, errno); ++ return; ++ } ++ if (write(flr_file, HWOFF_FUNCTION_FLUSH_PF, ++ sizeof(HWOFF_FUNCTION_FLUSH_PF)) <= 0) { ++ VLOG_ERR("failed to write to %s", HWOFF_FUNCTION_FLUSH); ++ goto OUT; ++ } ++ VLOG_INFO("PF upall huge_pages flush success"); ++OUT: ++ close(flr_file); ++} ++ ++void ++hwoff_free_hugepages(void) ++{ ++ char path[PATH_MAX] = {0}; ++ char hugepages_path[PATH_MAX] = HWOFF_DPDK_HUGEPAGES_PATH; ++ char run_path[PATH_MAX] = HWOFF_DPDK_RUN_FILE; ++ DIR *dir = NULL; ++ DIR *hugepages_dir = NULL; ++ struct dirent *dir_item = NULL; ++ struct dirent *rte_dirent = NULL; ++ char prefix[] = HWOFF_DPDK_HUGEPAGES_PREFIX; ++ ++ /* unlink hugepages file */ ++ hugepages_dir = opendir(hugepages_path); ++ if (hugepages_dir) { ++ while ((dir_item = readdir(hugepages_dir)) != NULL) { ++ if (strncmp(dir_item->d_name, prefix, strlen(prefix)) == 0) { ++ sprintf(path, "%s/%s", hugepages_path, dir_item->d_name); ++ ++ unlink(path); ++ memset(path, 0, sizeof(path)); ++ } ++ } ++ closedir(hugepages_dir); ++ } ++ ++ /* remove dpdk run file */ ++ dir = opendir(run_path); ++ if (dir) { ++ while ((rte_dirent = readdir(dir)) != NULL) { ++ if (strncmp(rte_dirent->d_name, prefix, strlen(prefix)) == 0) { ++ sprintf(path, "%s/%s", run_path, rte_dirent->d_name); ++ ++ hwoff_remove_fbarray(path); ++ memset(path, 0, sizeof(path)); ++ } ++ } ++ closedir(dir); ++ } ++} ++ ++static void ++hwoff_hugepages_pre_process(struct svec *svec) ++{ ++ char ovs_prefix[64] = {0}; ++ hwoff_clear_pf_access_hugepages(); ++ hwoff_free_hugepages(); ++ ++ sprintf(ovs_prefix, "--file-prefix=%s%d", HWOFF_DPDK_HUGEPAGES_PREFIX, getpid()); ++ svec_add(svec, ovs_prefix); ++} ++#endif ++ + static bool + dpdk_init__(const struct smap *ovs_other_config) + { +@@ -481,6 +592,10 @@ dpdk_init__(const struct smap *ovs_other_config) + free(joined_args); + } + ++#ifdef HAVE_HWOFF_AGENT ++ hwoff_hugepages_pre_process(&args); ++#endif ++ + /* Copy because 'rte_eal_init' will change the argv, i.e. it will remove + * some arguments from it. '+1' to copy the terminating NULL. */ + argv = xmemdup(args.names, (args.n + 1) * sizeof args.names[0]); +diff --git a/openvswitch-2.14.2/lib/dpdk.h b/openvswitch-2.14.2/lib/dpdk.h +index 445a51d..3c08d56 100644 +--- a/openvswitch-2.14.2/lib/dpdk.h ++++ b/openvswitch-2.14.2/lib/dpdk.h +@@ -45,5 +45,9 @@ bool dpdk_available(void); + void print_dpdk_version(void); + void dpdk_status(const struct ovsrec_open_vswitch *); + bool dpdk_get_cpu_has_isa(const char *arch, const char *feature); ++#ifdef HAVE_HWOFF_AGENT ++void hwoff_free_hugepages(void); ++void hwoff_clear_pf_access_hugepages(void); ++#endif + + #endif /* dpdk.h */ +diff --git a/openvswitch-2.14.2/lib/dpif-netdev.c b/openvswitch-2.14.2/lib/dpif-netdev.c +index 02df8f1..eb5ffe2 100644 +--- a/openvswitch-2.14.2/lib/dpif-netdev.c ++++ b/openvswitch-2.14.2/lib/dpif-netdev.c +@@ -33,6 +33,12 @@ + #include + #include + ++#ifdef HAVE_HWOFF_AGENT ++#include "hwoff_init_func.h" ++#include "mac-learning.h" ++#include "rte_mtr.h" ++#endif ++ + #include "bitmap.h" + #include "cmap.h" + #include "conntrack.h" +@@ -271,9 +277,13 @@ static bool dpcls_lookup(struct dpcls *cls, + int *num_lookups_p); + + /* Set of supported meter flags */ ++#ifdef HAVE_HWOFF_AGENT + #define DP_SUPPORTED_METER_FLAGS_MASK \ +- (OFPMF13_STATS | OFPMF13_PKTPS | OFPMF13_KBPS | OFPMF13_BURST) +- ++ (OFPMF13_STATS | OFPMF13_PKTPS | OFPMF13_KBPS | OFPMF13_BURST | OFPMF13_OFFLOAD) ++#else ++ #define DP_SUPPORTED_METER_FLAGS_MASK \ ++ (OFPMF13_STATS | OFPMF13_PKTPS | OFPMF13_KBPS | OFPMF13_BURST) ++#endif + /* Set of supported meter band types */ + #define DP_SUPPORTED_METER_BAND_TYPES \ + ( 1 << OFPMBT13_DROP ) +@@ -387,6 +397,11 @@ struct dp_netdev { + /* Bonds. */ + struct ovs_mutex bond_mutex; /* Protects updates of 'tx_bonds'. */ + struct cmap tx_bonds; /* Contains 'struct tx_bond'. */ ++#ifdef HAVE_HWOFF_AGENT ++ /* callback when flush flows */ ++ dp_pmd_ukey_purge_callback *dp_pmd_ukey_purge_cb; ++ void *dp_pmd_ukey_purge_aux; ++#endif + }; + + static void meter_lock(const struct dp_netdev *dp, uint32_t meter_id) +@@ -498,6 +513,15 @@ struct dp_netdev_flow_attrs { + ATOMIC(const char *) dp_layer; /* DP layer the flow is handled in. */ + }; + ++#ifdef HAVE_HWOFF_AGENT ++struct packet_batch_per_flow { ++ unsigned int byte_count; ++ uint16_t tcp_flags; ++ struct dp_netdev_flow *flow; ++ struct dp_packet_batch array; ++}; ++#endif ++ + /* A flow in 'dp_netdev_pmd_thread's 'flow_table'. + * + * +@@ -921,6 +945,13 @@ static inline bool + pmd_perf_metrics_enabled(const struct dp_netdev_pmd_thread *pmd); + static void queue_netdev_flow_del(struct dp_netdev_pmd_thread *pmd, + struct dp_netdev_flow *flow); ++uint32_t flow_mark_alloc(void); ++void megaflow_to_mark_associate(const ovs_u128 *mega_ufid, uint32_t mark); ++void mark_to_flow_associate(const uint32_t mark, struct dp_netdev_flow *flow); ++int mark_to_flow_disassociate(struct dp_netdev_pmd_thread *pmd, struct dp_netdev_flow *flow); ++static void * ++dp_netdev_flow_offload_main(void *data OVS_UNUSED); ++ + + static void + emc_cache_init(struct emc_cache *flow_cache) +@@ -2261,6 +2292,25 @@ get_port_by_name(struct dp_netdev *dp, + return ENODEV; + } + ++odp_port_t ++dpif_netdev_get_odp_no_by_name(const char *devname) ++{ ++ struct dp_netdev_port *port = NULL; ++ struct dp_netdev *dp = shash_find_data(&dp_netdevs, "ovs-netdev"); ++ int error; ++ ++ if (dp == NULL) { ++ return ODPP_NONE; ++ } ++ ++ error = get_port_by_name(dp, devname, &port); ++ if (error != 0) { ++ return ODPP_NONE; ++ } ++ ++ return port->port_no; ++} ++ + /* Returns 'true' if there is a port with pmd netdev. */ + static bool + has_pmd_port(struct dp_netdev *dp) +@@ -2413,7 +2463,7 @@ static struct flow_mark flow_mark = { + .mark_to_flow = CMAP_INITIALIZER, + }; + +-static uint32_t ++uint32_t + flow_mark_alloc(void) + { + uint32_t mark; +@@ -2437,7 +2487,7 @@ flow_mark_free(uint32_t mark) + } + + /* associate megaflow with a mark, which is a 1:1 mapping */ +-static void ++void + megaflow_to_mark_associate(const ovs_u128 *mega_ufid, uint32_t mark) + { + size_t hash = dp_netdev_flow_hash(mega_ufid); +@@ -2488,7 +2538,7 @@ megaflow_to_mark_find(const ovs_u128 *mega_ufid) + } + + /* associate mark with a flow, which is 1:N mapping */ +-static void ++void + mark_to_flow_associate(const uint32_t mark, struct dp_netdev_flow *flow) + { + dp_netdev_flow_ref(flow); +@@ -2517,7 +2567,7 @@ flow_mark_has_no_ref(uint32_t mark) + return true; + } + +-static int ++int + mark_to_flow_disassociate(struct dp_netdev_pmd_thread *pmd, + struct dp_netdev_flow *flow) + { +@@ -2565,18 +2615,6 @@ mark_to_flow_disassociate(struct dp_netdev_pmd_thread *pmd, + return ret; + } + +-static void +-flow_mark_flush(struct dp_netdev_pmd_thread *pmd) +-{ +- struct dp_netdev_flow *flow; +- +- CMAP_FOR_EACH (flow, mark_node, &flow_mark.mark_to_flow) { +- if (flow->pmd_id == pmd->core_id) { +- queue_netdev_flow_del(pmd, flow); +- } +- } +-} +- + static struct dp_netdev_flow * + mark_to_flow_find(const struct dp_netdev_pmd_thread *pmd, + const uint32_t mark) +@@ -2631,6 +2669,152 @@ dp_netdev_append_flow_offload(struct dp_flow_offload_item *offload) + ovs_mutex_unlock(&dp_flow_offload.mutex); + } + ++#ifdef HAVE_HWOFF_AGENT ++/* Original offload solution use the flow_mark to identify the offload dp_netdev_flow, it works well ++ in one thread environment. In our solution we offload flow in pmd threads, and delete run in offload_thread, ++ so there are multi-theads process the flow_mark, flow_mark not working anymore. So we change our solution not ++ to process flow_mark at all. ++*/ ++int g_hwoff_offload_switch = 1; ++void dp_netdev_hwoff_switch_set(int value) ++{ ++ g_hwoff_offload_switch = value; ++} ++ ++static int ++dp_netdev_flow_offload_add(struct dp_netdev_pmd_thread *pmd, struct dp_netdev_flow *flow, struct match *match, ++ struct dp_packet_batch *pkts, const struct nlattr *actions, size_t actions_len) ++{ ++ int ret; ++ struct netdev *dev = NULL; ++ struct offload_info info; ++ odp_port_t in_port = flow->flow.in_port.odp_port; ++ const char *dpif_type_str = dpif_normalize_type(pmd->dp->class->type); ++ ++ if (g_hwoff_offload_switch != 1) { ++ return 0; ++ } ++ ++ if (flow->dead || (!pkts)) { ++ return -1; ++ } ++ ++ dev = netdev_ports_get(in_port, dpif_type_str); ++ if (!dev) { ++ return -1; ++ } ++ ++ hwoff_func* funcs = hwoff_get_funcs(); ++ if (!funcs->hwoff_is_support_offload(dev)) { ++ netdev_close(dev); ++ return -1; ++ } ++ ++ if (funcs->hwoff_is_ethdev(dev)) { ++ info.in_port_type = HWOFF_PORT_TYPE_HIOVS; ++ } else { ++ info.in_port_type = HWOFF_PORT_TYPE_OTHER; ++ } ++ info.pkts_info = pkts; ++ info.pmd_core_id = pmd->core_id; ++ info.pmd = pmd; ++ info.flow = flow; ++ info.modification = false; ++ ++ /* no need to take a port_mutex in pmd thread */ ++ ret = netdev_flow_put(dev, match, ++ CONST_CAST(struct nlattr *, actions), ++ actions_len, &flow->mega_ufid, &info, NULL); ++ netdev_close(dev); ++ if (ret) { ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int ++dp_netdev_flow_offload_del(struct dp_flow_offload_item *offload) ++{ ++ int ret; ++ struct netdev *dev = NULL; ++ hwoff_func* funcs = hwoff_get_funcs(); ++ struct dp_netdev_pmd_thread *pmd = offload->pmd; ++ struct dp_netdev_flow *flow = offload->flow; ++ odp_port_t in_port = flow->flow.in_port.odp_port; ++ const char *dpif_type_str = dpif_normalize_type(pmd->dp->class->type); ++ ++ dev = netdev_ports_get(in_port, dpif_type_str); ++ if (!dev) { ++ VLOG_DBG("device=%u is deleted when dp_netdev_flow_offload_del, mega_ufid="UUID_FMT, in_port, ++ UUID_ARGS((struct uuid *) &flow->mega_ufid)); ++ hiovs_offload_flow_api_del(NULL, &flow->mega_ufid, NULL); ++ return 0; ++ } ++ ++ if (!funcs->hwoff_is_support_offload(dev)) { ++ netdev_close(dev); ++ return 0; ++ } ++ ++ ovs_mutex_lock(&pmd->dp->port_mutex); ++ ret = netdev_flow_del(dev, &flow->mega_ufid, NULL); ++ ovs_mutex_unlock(&pmd->dp->port_mutex); ++ netdev_close(dev); ++ return ret; ++} ++ ++static int ++dp_netdev_flow_offload_put(struct dp_flow_offload_item *offload) ++{ ++ /* We do offload in pmd thread useing dp_netdev_flow_offload_add, here we just process modification. ++ We process modification just same as delete, thren packet will upcall then reoffload. ++ */ ++ bool modification = offload->op == DP_NETDEV_FLOW_OFFLOAD_OP_MOD; ++ ++ if (!modification) { ++ return 0; ++ } ++ ++ return dp_netdev_flow_offload_del(offload); ++} ++ ++static void ++queue_netdev_flow_put(struct dp_netdev_pmd_thread *pmd, ++ struct dp_netdev_flow *flow, struct match *match, ++ const struct nlattr *actions, size_t actions_len, bool is_modify) ++{ ++ int op; ++ struct dp_flow_offload_item *offload; ++ ++ if (!netdev_is_flow_api_enabled()) { ++ return; ++ } ++ ++ if (ovsthread_once_start(&offload_thread_once)) { ++ xpthread_cond_init(&dp_flow_offload.cond, NULL); ++ ovs_thread_create("dp_netdev_flow_offload", ++ dp_netdev_flow_offload_main, NULL); ++ ovsthread_once_done(&offload_thread_once); ++ } ++ ++ op = is_modify ? DP_NETDEV_FLOW_OFFLOAD_OP_MOD : DP_NETDEV_FLOW_OFFLOAD_OP_ADD; ++ offload = dp_netdev_alloc_flow_offload(pmd, flow, op); ++ offload->match = *match; ++ offload->actions = xmalloc(actions_len); ++ memcpy(offload->actions, actions, actions_len); ++ offload->actions_len = actions_len; ++ ++ dp_netdev_append_flow_offload(offload); ++} ++ ++bool dp_netdev_flow_dead_status_get(void *flow) ++{ ++ struct dp_netdev_flow *net_flow = (struct dp_netdev_flow *)flow; ++ return net_flow->dead; ++} ++#else ++ + static int + dp_netdev_flow_offload_del(struct dp_flow_offload_item *offload) + { +@@ -2691,6 +2875,7 @@ dp_netdev_flow_offload_put(struct dp_flow_offload_item *offload) + } + } + info.flow_mark = mark; ++ info.pmd = NULL; + + port = netdev_ports_get(in_port, dpif_type_str); + if (!port || netdev_vport_is_vport_class(port->netdev_class)) { +@@ -2726,6 +2911,41 @@ err_free: + return -1; + } + ++static void ++queue_netdev_flow_put(struct dp_netdev_pmd_thread *pmd, ++ struct dp_netdev_flow *flow, struct match *match, ++ const struct nlattr *actions, size_t actions_len, bool is_modify) ++{ ++ struct dp_flow_offload_item *offload; ++ int op; ++ ++ if (!netdev_is_flow_api_enabled()) { ++ return; ++ } ++ ++ if (ovsthread_once_start(&offload_thread_once)) { ++ xpthread_cond_init(&dp_flow_offload.cond, NULL); ++ ovs_thread_create("dp_netdev_flow_offload", ++ dp_netdev_flow_offload_main, NULL); ++ ovsthread_once_done(&offload_thread_once); ++ } ++ ++ if (flow->mark != INVALID_FLOW_MARK) { ++ op = DP_NETDEV_FLOW_OFFLOAD_OP_MOD; ++ } else { ++ op = DP_NETDEV_FLOW_OFFLOAD_OP_ADD; ++ } ++ offload = dp_netdev_alloc_flow_offload(pmd, flow, op); ++ offload->match = *match; ++ offload->actions = xmalloc(actions_len); ++ memcpy(offload->actions, actions, actions_len); ++ offload->actions_len = actions_len; ++ ++ dp_netdev_append_flow_offload(offload); ++} ++ ++#endif ++ + static void * + dp_netdev_flow_offload_main(void *data OVS_UNUSED) + { +@@ -2791,39 +3011,6 @@ queue_netdev_flow_del(struct dp_netdev_pmd_thread *pmd, + dp_netdev_append_flow_offload(offload); + } + +-static void +-queue_netdev_flow_put(struct dp_netdev_pmd_thread *pmd, +- struct dp_netdev_flow *flow, struct match *match, +- const struct nlattr *actions, size_t actions_len) +-{ +- struct dp_flow_offload_item *offload; +- int op; +- +- if (!netdev_is_flow_api_enabled()) { +- return; +- } +- +- if (ovsthread_once_start(&offload_thread_once)) { +- xpthread_cond_init(&dp_flow_offload.cond, NULL); +- ovs_thread_create("dp_netdev_flow_offload", +- dp_netdev_flow_offload_main, NULL); +- ovsthread_once_done(&offload_thread_once); +- } +- +- if (flow->mark != INVALID_FLOW_MARK) { +- op = DP_NETDEV_FLOW_OFFLOAD_OP_MOD; +- } else { +- op = DP_NETDEV_FLOW_OFFLOAD_OP_ADD; +- } +- offload = dp_netdev_alloc_flow_offload(pmd, flow, op); +- offload->match = *match; +- offload->actions = xmalloc(actions_len); +- memcpy(offload->actions, actions, actions_len); +- offload->actions_len = actions_len; +- +- dp_netdev_append_flow_offload(offload); +-} +- + static void + dp_netdev_pmd_remove_flow(struct dp_netdev_pmd_thread *pmd, + struct dp_netdev_flow *flow) +@@ -2837,10 +3024,8 @@ dp_netdev_pmd_remove_flow(struct dp_netdev_pmd_thread *pmd, + ovs_assert(cls != NULL); + dpcls_remove(cls, &flow->cr); + cmap_remove(&pmd->flow_table, node, dp_netdev_flow_hash(&flow->ufid)); +- if (flow->mark != INVALID_FLOW_MARK) { +- queue_netdev_flow_del(pmd, flow); +- } + flow->dead = true; ++ queue_netdev_flow_del(pmd, flow); + + dp_netdev_flow_unref(flow); + } +@@ -2863,9 +3048,27 @@ dpif_netdev_flow_flush(struct dpif *dpif) + struct dp_netdev *dp = get_dp_netdev(dpif); + struct dp_netdev_pmd_thread *pmd; + ++#ifdef HAVE_HWOFF_AGENT ++ hwoff_func* funcs = hwoff_get_funcs(); ++ if (funcs->hwoff_set_offload_state != NULL) { ++ funcs->hwoff_set_offload_state(HWOFF_OFFLOAD_DISABLE); ++ } ++#endif ++ + CMAP_FOR_EACH (pmd, node, &dp->poll_threads) { + dp_netdev_pmd_flow_flush(pmd); ++#ifdef HAVE_HWOFF_AGENT ++ if (dp->dp_pmd_ukey_purge_cb) { ++ dp->dp_pmd_ukey_purge_cb(dp->dp_pmd_ukey_purge_aux, pmd->core_id); ++ } ++#endif ++ } ++ ++#ifdef HAVE_HWOFF_AGENT ++ if (funcs->hwoff_set_offload_state != NULL) { ++ funcs->hwoff_set_offload_state(HWOFF_OFFLOAD_ENABLE); + } ++#endif + + return 0; + } +@@ -3480,6 +3683,9 @@ dp_netdev_flow_to_dpif_flow(const struct dp_netdev *dp, + } + + flow->ufid = netdev_flow->ufid; ++#ifdef HAVE_HWOFF_AGENT ++ flow->mega_ufid = netdev_flow->mega_ufid; ++#endif + flow->ufid_present = true; + flow->pmd_id = netdev_flow->pmd_id; + +@@ -3687,7 +3893,20 @@ dp_netdev_flow_add(struct dp_netdev_pmd_thread *pmd, + cmap_insert(&pmd->flow_table, CONST_CAST(struct cmap_node *, &flow->node), + dp_netdev_flow_hash(&flow->ufid)); + +- queue_netdev_flow_put(pmd, flow, match, actions, actions_len); ++#ifdef HAVE_HWOFF_AGENT ++ struct netdev *upcall_dev = NULL; ++ const char *dpif_type_str = dpif_normalize_type(pmd->dp->class->type); ++ ++ upcall_dev = netdev_ports_get(in_port, dpif_type_str); ++ hwoff_func* funcs = hwoff_get_funcs(); ++ if ((funcs->hwoff_is_support_offload == NULL) || ++ !funcs->hwoff_is_support_offload(upcall_dev)) { ++ queue_netdev_flow_put(pmd, flow, match, actions, actions_len, false); ++ } ++ netdev_close(upcall_dev); ++#else ++ queue_netdev_flow_put(pmd, flow, match, actions, actions_len, false); ++#endif + + if (OVS_UNLIKELY(!VLOG_DROP_DBG((&upcall_rl)))) { + struct ds ds = DS_EMPTY_INITIALIZER; +@@ -3738,6 +3957,70 @@ dp_netdev_flow_add(struct dp_netdev_pmd_thread *pmd, + return flow; + } + ++ ++#ifdef HAVE_HWOFF_AGENT ++static bool ++is_need_clear_forward_flow(struct dp_netdev_flow *netdev_flow, ++ struct eth_addr *temp_mac, uint32_t *dp_in_port) ++{ ++ struct hwoff_migrate_rarp_mac_entry *entry = NULL; ++ bool clear_flow = false; ++ struct hwoff_migrate_rarp_mac_infos *hwoff_migrate_rarp_mac_infos = hwoff_migrate_rarp_mac_infos_get(); ++ if (netdev_flow == NULL) { ++ return false; ++ } ++ if (hwoff_rarp_status_get()) { ++ ovs_rwlock_wrlock(&hwoff_migrate_rarp_mac_infos->rw); ++ if (unlikely(hwoff_migrate_rarp_mac_infos->length)) { ++ entry = hwoff_get_entry_by_mac(netdev_flow->flow.dl_src); ++ if (entry && entry->is_need_del) { ++ hwoff_rarp_mac_remove_from_list(entry); ++ (void)memcpy(&temp_mac->ea, &netdev_flow->flow.dl_src.ea, RTE_ETHER_ADDR_LEN); ++ *dp_in_port = netdev_flow->flow.in_port.odp_port; ++ clear_flow = true; ++ } ++ } ++ ovs_rwlock_unlock(&hwoff_migrate_rarp_mac_infos->rw); ++ } ++ return clear_flow; ++} ++ ++static void dp_netdev_clear_flow(struct dp_netdev_pmd_thread *pmd, struct eth_addr smac, uint32_t dp_in_port) ++{ ++ struct dp_netdev *dp = pmd->dp; ++ struct dp_netdev_flow *netdev_flow = NULL; ++ ovs_mutex_lock(&pmd->flow_mutex); ++ CMAP_FOR_EACH(netdev_flow, node, &pmd->flow_table) ++ { ++ if (hwoff_rarp_status_get() && ((eth_addr_equals(netdev_flow->flow.dl_src, smac) && ++ !eth_addr_is_broadcast(netdev_flow->flow.dl_dst) && dp_in_port != netdev_flow->flow.in_port.odp_port) || ++ (eth_addr_equals(netdev_flow->flow.dl_dst, smac) && !eth_addr_is_broadcast(netdev_flow->flow.dl_src)))) { ++ dp_netdev_pmd_remove_flow(pmd, netdev_flow); ++ } ++ } ++ ovs_mutex_unlock(&pmd->flow_mutex); ++ if (dp->dp_pmd_ukey_purge_cb) { ++ dp->dp_pmd_ukey_purge_cb(dp->dp_pmd_ukey_purge_aux, pmd->core_id); ++ } ++} ++ ++static void ++dp_netdev_clear_flow_by_rarp(struct dp_netdev_pmd_thread *pmd, struct dp_netdev_flow *flow) ++ OVS_ACQUIRES(pmd->flow_mutex) ++{ ++ uint32_t dp_in_port = 0; ++ struct eth_addr temp_mac; ++ (void)memset(&temp_mac, 0, sizeof(struct eth_addr)); ++ if (flow == NULL) { ++ return; ++ } ++ ++ if (hwoff_rarp_status_get() && is_need_clear_forward_flow(flow, &temp_mac, &dp_in_port)) { ++ dp_netdev_clear_flow(pmd, temp_mac, dp_in_port); ++ } ++} ++#endif ++ + static int + flow_put_on_pmd(struct dp_netdev_pmd_thread *pmd, + struct netdev_flow_key *key, +@@ -3748,7 +4031,6 @@ flow_put_on_pmd(struct dp_netdev_pmd_thread *pmd, + { + struct dp_netdev_flow *netdev_flow; + int error = 0; +- + if (stats) { + memset(stats, 0, sizeof *stats); + } +@@ -3774,7 +4056,7 @@ flow_put_on_pmd(struct dp_netdev_pmd_thread *pmd, + ovsrcu_set(&netdev_flow->actions, new_actions); + + queue_netdev_flow_put(pmd, netdev_flow, match, +- put->actions, put->actions_len); ++ put->actions, put->actions_len, true); + + if (stats) { + get_dpif_flow_status(pmd->dp, netdev_flow, stats, NULL); +@@ -3801,6 +4083,9 @@ flow_put_on_pmd(struct dp_netdev_pmd_thread *pmd, + } + } + ovs_mutex_unlock(&pmd->flow_mutex); ++#ifdef HAVE_HWOFF_AGENT ++ dp_netdev_clear_flow_by_rarp(pmd, netdev_flow); ++#endif + return error; + } + +@@ -3883,6 +4168,41 @@ dpif_netdev_flow_put(struct dpif *dpif, const struct dpif_flow_put *put) + return error; + } + ++#ifdef HAVE_HWOFF_AGENT ++static void ++hwoff_pmd_del_reverse_flow(struct dp_netdev_flow *netdev_flow, struct dp_netdev_pmd_thread *pmd) ++{ ++ bool clear_flag = false; ++ struct dp_netdev *dp = pmd->dp; ++ struct eth_addr del_flow_smac = { 0 }; ++ struct dp_netdev_flow *netdev_flow_iter = NULL; ++ struct hwoff_migrate_rarp_mac_entry *entry = NULL; ++ struct hwoff_migrate_rarp_mac_infos *migrate_rarp_mac_infos = hwoff_migrate_rarp_mac_infos_get(); ++ ++ if (!hwoff_rarp_status_get()) { ++ return; ++ } ++ ++ if (unlikely(migrate_rarp_mac_infos->length) != 0) { ++ ovs_rwlock_wrlock(&migrate_rarp_mac_infos->rw); ++ entry = hwoff_get_entry_by_mac(netdev_flow->flow.dl_dst); ++ if (entry != NULL && entry->is_need_del == true) { ++ hwoff_rarp_mac_remove_from_list(entry); ++ CMAP_FOR_EACH(netdev_flow_iter, node, &pmd->flow_table) { ++ if (eth_addr_equals(netdev_flow_iter->flow.dl_src, netdev_flow->flow.dl_dst) && ++ !(eth_addr_is_broadcast(netdev_flow_iter->flow.dl_dst))) { ++ dp_netdev_pmd_remove_flow(pmd, netdev_flow_iter); ++ } ++ } ++ if (dp->dp_pmd_ukey_purge_cb) { ++ dp->dp_pmd_ukey_purge_cb(dp->dp_pmd_ukey_purge_aux, pmd->core_id); ++ } ++ } ++ ovs_rwlock_unlock(&migrate_rarp_mac_infos->rw); ++ } ++} ++#endif ++ + static int + flow_del_on_pmd(struct dp_netdev_pmd_thread *pmd, + struct dpif_flow_stats *stats, +@@ -3895,6 +4215,9 @@ flow_del_on_pmd(struct dp_netdev_pmd_thread *pmd, + netdev_flow = dp_netdev_pmd_find_flow(pmd, del->ufid, del->key, + del->key_len); + if (netdev_flow) { ++#ifdef HAVE_HWOFF_AGENT ++ hwoff_pmd_del_reverse_flow(netdev_flow, pmd); ++#endif + if (stats) { + get_dpif_flow_status(pmd->dp, netdev_flow, stats, NULL); + } +@@ -3903,7 +4226,6 @@ flow_del_on_pmd(struct dp_netdev_pmd_thread *pmd, + error = ENOENT; + } + ovs_mutex_unlock(&pmd->flow_mutex); +- + return error; + } + +@@ -4618,7 +4940,6 @@ dp_netdev_pmd_flush_output_on_port(struct dp_netdev_pmd_thread *pmd, + + output_cnt = dp_packet_batch_size(&p->output_pkts); + ovs_assert(output_cnt > 0); +- + netdev_send(p->port->netdev, tx_qid, &p->output_pkts, dynamic_txqs); + dp_packet_batch_init(&p->output_pkts); + +@@ -4665,6 +4986,76 @@ dp_netdev_pmd_flush_output_packets(struct dp_netdev_pmd_thread *pmd, + return output_cnt; + } + ++#ifdef HAVE_HWOFF_AGENT ++/* The struct is use to classift batch's packets into different batch according to ++ * packet's input port*/ ++#define HWOFF_NETDEV_NAME_LENGTH 100 ++struct hwoff_dpif_port_classifier_node { ++ odp_port_t port; ++ struct dp_packet_batch batch; ++}; ++ ++struct hwoff_dpif_port_classifier { ++ size_t node_count; ++ struct hwoff_dpif_port_classifier_node node[NETDEV_MAX_BURST]; ++}; ++ ++static odp_port_t ++hwoff_dpif_port_get_by_mbuf(struct dp_packet *packet) ++{ ++ uint16_t dpdk_port = 0; ++ char dev_name[HWOFF_NETDEV_NAME_LENGTH] = {0}; ++ odp_port_t port_no = ODPP_NONE; ++ ++ if (packet != NULL) { ++ dpdk_port = packet->mbuf.port; ++ hwoff_netdev_name_get(dpdk_port, dev_name, HWOFF_NETDEV_NAME_LENGTH); ++ port_no = dpif_netdev_get_odp_no_by_name(dev_name); ++ } ++ return port_no; ++} ++ ++static void ++hwoff_dpif_port_classift_insert(odp_port_t port_no, struct dp_packet *packet, ++ struct hwoff_dpif_port_classifier *port_classifile) ++{ ++ struct hwoff_dpif_port_classifier_node *node = NULL; ++ for (int i = 0; i < port_classifile->node_count; ++i) { ++ if (port_classifile->node[i].port == port_no) { ++ node = &port_classifile->node[i]; ++ node->batch.packets[node->batch.count++] = packet; ++ return; ++ } ++ } ++ ++ node = &port_classifile->node[port_classifile->node_count++]; ++ node->port = port_no; ++ node->batch.packets[node->batch.count++] = packet; ++ return; ++} ++ ++/* redistribute batch's packets, current scheme is to iterate through an packets array ++ of max size 32*/ ++static void ++hwoff_dpif_mbuf_packets_classify(const struct dp_packet_batch *packets, ++ struct hwoff_dpif_port_classifier *port_classifile) ++{ ++ if (packets == NULL || port_classifile == NULL) { ++ return; ++ } ++ ++ odp_port_t port_no = ODPP_NONE; ++ ++ for (int i = 0; i < packets->count; ++i) { ++ port_no = hwoff_dpif_port_get_by_mbuf(packets->packets[i]); ++ if (port_no != ODPP_NONE) { ++ hwoff_dpif_port_classift_insert(port_no, packets->packets[i], port_classifile); ++ } ++ } ++ return; ++} ++#endif ++ + static int + dp_netdev_process_rxq_port(struct dp_netdev_pmd_thread *pmd, + struct dp_netdev_rxq *rxq, +@@ -4707,9 +5098,24 @@ dp_netdev_process_rxq_port(struct dp_netdev_pmd_thread *pmd, + } + } + } ++ ++#ifdef HAVE_HWOFF_AGENT ++ struct hwoff_dpif_port_classifier port_classifier = {0}; ++ /* When the rxq is be shared, redistribute packets in batch ++ * according to packet's input port */ ++ if (hwoff_netdev_is_shared(rxq->rx->netdev)) { ++ hwoff_dpif_mbuf_packets_classify(&batch, &port_classifier); ++ for (int i = 0; i < port_classifier.node_count; ++i) { ++ dp_netdev_input(pmd, &port_classifier.node[i].batch, ++ port_classifier.node[i].port); ++ } ++ } else { ++ dp_netdev_input(pmd, &batch, port_no); ++ } ++#else + /* Process packet batch. */ + dp_netdev_input(pmd, &batch, port_no); +- ++#endif + /* Assign processing cycles to rx queue. */ + cycles = cycle_timer_stop(&pmd->perf_stats, &timer); + dp_netdev_rxq_add_cycles(rxq, RXQ_CYCLES_PROC_CURR, cycles); +@@ -4991,11 +5397,23 @@ rxq_scheduling(struct dp_netdev *dp, bool pinned) OVS_REQUIRES(dp->port_mutex) + int numa_id; + bool assign_cyc = dp->pmd_rxq_assign_cyc; + ++#ifdef HAVE_HWOFF_AGENT ++ /* share upcall queues just will be assigned once to avoid invalid poll*/ ++ bool share_upcall_scheduled = false; ++#endif ++ + HMAP_FOR_EACH (port, node, &dp->ports) { + if (!netdev_is_pmd(port->netdev)) { + continue; + } + ++#ifdef HAVE_HWOFF_AGENT ++ bool is_share_upcall_dev = hwoff_netdev_is_shared(port->netdev); ++ if (share_upcall_scheduled && is_share_upcall_dev) { ++ continue; ++ } ++#endif ++ + for (int qid = 0; qid < port->n_rxq; qid++) { + struct dp_netdev_rxq *q = &port->rxqs[qid]; + +@@ -5037,6 +5455,11 @@ rxq_scheduling(struct dp_netdev *dp, bool pinned) OVS_REQUIRES(dp->port_mutex) + rxqs[n_rxqs++] = q; + } + } ++#ifdef HAVE_HWOFF_AGENT ++ if (is_share_upcall_dev) { ++ share_upcall_scheduled = true; ++ } ++#endif + } + + if (n_rxqs > 1 && assign_cyc) { +@@ -5102,7 +5525,6 @@ reload_affected_pmds(struct dp_netdev *dp) + + CMAP_FOR_EACH (pmd, node, &dp->poll_threads) { + if (pmd->need_reload) { +- flow_mark_flush(pmd); + dp_netdev_reload_pmd__(pmd); + } + } +@@ -6300,6 +6722,43 @@ dpif_netdev_meter_set(struct dpif *dpif, ofproto_meter_id meter_id, + meter_lock(dp, mid); + dp_delete_meter(dp, mid); /* Free existing meter, if any */ + dp->meters[mid] = meter; ++ ++#ifdef HAVE_HWOFF_AGENT ++ int ret; ++ if (meter != NULL && (meter->flags & OFPMF13_OFFLOAD)) { ++ struct rte_mtr_meter_profile profile = {0}; ++ if (config->n_bands > 2) { ++ meter_unlock(dp, mid); ++ return EINVAL; ++ } ++ ++ hwoff_func* funcs = hwoff_get_funcs(); ++ if (funcs->hwoff_set_flow_qos == NULL) { ++ meter_unlock(dp, mid); ++ return EINVAL; ++ } ++ ++ if (config->n_bands == 1) { ++ profile.trtcm_rfc2698.cir = dp->meters[mid]->bands[0].up.rate; ++ profile.trtcm_rfc2698.cbs = dp->meters[mid]->bands[0].up.burst_size; ++ profile.trtcm_rfc2698.pir = dp->meters[mid]->bands[0].up.rate; ++ profile.trtcm_rfc2698.pbs = dp->meters[mid]->bands[0].up.burst_size; ++ } else if (config->n_bands == 2) { ++ profile.trtcm_rfc2698.cir = dp->meters[mid]->bands[1].up.rate; ++ profile.trtcm_rfc2698.cbs = dp->meters[mid]->bands[1].up.burst_size; ++ profile.trtcm_rfc2698.pir = dp->meters[mid]->bands[0].up.rate; ++ profile.trtcm_rfc2698.pbs = dp->meters[mid]->bands[0].up.burst_size; ++ } ++ ++ profile.packet_mode = ((config->flags & OFPMF13_PKTPS) != 0); ++ ++ ret = funcs->hwoff_set_flow_qos(mid, &profile, config->meter_id); ++ if (ret != 0) { ++ meter_unlock(dp, mid); ++ return -1; ++ } ++ } ++#endif + meter_unlock(dp, mid); + + return 0; +@@ -6324,6 +6783,24 @@ dpif_netdev_meter_get(const struct dpif *dpif, + retval = ENOENT; + goto done; + } ++ ++#ifdef HAVE_HWOFF_AGENT ++ if (meter != NULL && (meter->flags & OFPMF13_OFFLOAD)) { ++ struct rte_mtr_stats stat; ++ hwoff_func* funcs = hwoff_get_funcs(); ++ if (funcs->hwoff_query_flow_qos_stats== NULL) { ++ goto done; ++ } ++ ++ retval = funcs->hwoff_query_flow_qos_stats(meter_id, &stat); ++ if (retval == 0 && stats != NULL) { ++ stats->n_num_dropped_byte = stat.n_bytes_dropped; ++ stats->n_num_dropped_pkts = stat.n_pkts_dropped; ++ goto done; ++ } ++ } ++#endif ++ + if (stats) { + int i = 0; + +@@ -6356,6 +6833,23 @@ dpif_netdev_meter_del(struct dpif *dpif, + uint32_t meter_id = meter_id_.uint32; + + meter_lock(dp, meter_id); ++#ifdef HAVE_HWOFF_AGENT ++ int ret; ++ const struct dp_meter *meter = dp->meters[meter_id_.uint32]; ++ if (meter != NULL && (meter->flags & OFPMF13_OFFLOAD)) { ++ hwoff_func* funcs = hwoff_get_funcs(); ++ if (funcs->hwoff_del_flow_qos == NULL) { ++ error = ENOENT; ++ goto end; ++ } ++ ++ ret = funcs->hwoff_del_flow_qos(meter_id_.uint32); ++ if (ret != 0) { ++ error = ENOENT; ++ } ++ } ++ end: ++#endif + dp_delete_meter(dp, meter_id); + meter_unlock(dp, meter_id); + } +@@ -6508,7 +7002,19 @@ dp_netdev_destroy_pmd(struct dp_netdev_pmd_thread *pmd) + { + struct dpcls *cls; + ++#ifdef HAVE_HWOFF_AGENT ++ hwoff_func* funcs = hwoff_get_funcs(); ++ if (funcs->hwoff_set_offload_state != NULL) { ++ funcs->hwoff_set_offload_state(HWOFF_OFFLOAD_DISABLE); ++ } ++#endif + dp_netdev_pmd_flow_flush(pmd); ++#ifdef HAVE_HWOFF_AGENT ++ if (funcs->hwoff_set_offload_state != NULL) { ++ funcs->hwoff_set_offload_state(HWOFF_OFFLOAD_ENABLE); ++ } ++#endif ++ + hmap_destroy(&pmd->send_port_cache); + hmap_destroy(&pmd->tnl_port_cache); + hmap_destroy(&pmd->tx_ports); +@@ -6842,6 +7348,7 @@ dpif_netdev_packet_get_rss_hash(struct dp_packet *packet, + return hash; + } + ++#ifndef HAVE_HWOFF_AGENT + struct packet_batch_per_flow { + unsigned int byte_count; + uint16_t tcp_flags; +@@ -6849,6 +7356,7 @@ struct packet_batch_per_flow { + + struct dp_packet_batch array; + }; ++#endif + + static inline void + packet_batch_per_flow_update(struct packet_batch_per_flow *batch, +@@ -6885,6 +7393,10 @@ packet_batch_per_flow_execute(struct packet_batch_per_flow *batch, + + actions = dp_netdev_flow_get_actions(flow); + ++#ifdef HAVE_HWOFF_AGENT ++ dp_netdev_flow_offload_add(pmd, flow, NULL, &batch->array, actions->actions, actions->size); ++#endif ++ + dp_netdev_execute_actions(pmd, &batch->array, true, &flow->flow, + actions->actions, actions->size); + } +@@ -7203,6 +7715,9 @@ handle_packet_upcall(struct dp_netdev_pmd_thread *pmd, + uint32_t hash = dp_netdev_flow_hash(&netdev_flow->ufid); + smc_insert(pmd, key, hash); + emc_probabilistic_insert(pmd, key, netdev_flow); ++#ifdef HAVE_HWOFF_AGENT ++ dp_netdev_clear_flow_by_rarp(pmd, netdev_flow); ++#endif + } + if (pmd_perf_metrics_enabled(pmd)) { + /* Update upcall stats. */ +@@ -7273,6 +7788,9 @@ fast_path_processing(struct dp_netdev_pmd_thread *pmd, + if (netdev_flow) { + lookup_cnt += add_lookup_cnt; + rules[i] = &netdev_flow->cr; ++#ifdef HAVE_HWOFF_AGENT ++ dp_netdev_clear_flow_by_rarp(pmd, netdev_flow); ++#endif + continue; + } + +@@ -7382,12 +7900,12 @@ dp_netdev_input__(struct dp_netdev_pmd_thread *pmd, + + /* All the flow batches need to be reset before any call to + * packet_batch_per_flow_execute() as it could potentially trigger +- * recirculation. When a packet matching flow ‘j’ happens to be ++ * recirculation. When a packet matching flow 'j' happens to be + * recirculated, the nested call to dp_netdev_input__() could potentially + * classify the packet as matching another flow - say 'k'. It could happen + * that in the previous call to dp_netdev_input__() that same flow 'k' had + * already its own batches[k] still waiting to be served. So if its +- * ‘batch’ member is not reset, the recirculated packet would be wrongly ++ * 'batch' member is not reset, the recirculated packet would be wrongly + * appended to batches[k] of the 1st call to dp_netdev_input__(). */ + for (i = 0; i < n_batches; i++) { + batches[i].flow->batch = NULL; +@@ -7435,6 +7953,16 @@ dpif_netdev_register_upcall_cb(struct dpif *dpif, upcall_callback *cb, + dp->upcall_aux = aux; + dp->upcall_cb = cb; + } ++#ifdef HAVE_HWOFF_AGENT ++static void ++dpif_netdev_register_pmd_ukey_purge_cb(struct dpif *dpif, dp_pmd_ukey_purge_callback *cb, ++ void *aux) ++{ ++ struct dp_netdev *dp = get_dp_netdev(dpif); ++ dp->dp_pmd_ukey_purge_cb = cb; ++ dp->dp_pmd_ukey_purge_aux = aux; ++} ++#endif + + static void + dpif_netdev_xps_revalidate_pmd(const struct dp_netdev_pmd_thread *pmd, +@@ -7517,6 +8045,21 @@ pmd_send_port_cache_lookup(const struct dp_netdev_pmd_thread *pmd, + return tx_port_lookup(&pmd->send_port_cache, port_no); + } + ++#ifdef HAVE_HWOFF_AGENT ++struct netdev * ++dp_get_outdev_from_pmd(odp_port_t port_no, void *tmp_pmd) ++{ ++ struct dp_netdev_pmd_thread *pmd = (struct dp_netdev_pmd_thread *)tmp_pmd; ++ struct tx_port *p = pmd_send_port_cache_lookup(pmd, port_no); ++ ++ if (p != NULL && p->port != NULL) { ++ return p->port->netdev; ++ } ++ ++ return NULL; ++} ++#endif ++ + static int + push_tnl_action(const struct dp_netdev_pmd_thread *pmd, + const struct nlattr *attr, +@@ -7669,6 +8212,11 @@ dp_execute_cb(void *aux_, struct dp_packet_batch *packets_, + int type = nl_attr_type(a); + struct tx_port *p; + uint32_t packet_count, packets_dropped; ++#ifdef HAVE_HWOFF_AGENT ++ struct dp_meter *meter; ++ struct rte_flow_action_meter *meter_usr_data; ++ uint32_t meter_id = nl_attr_get_u32(a); ++#endif + + switch ((enum ovs_action_attr)type) { + case OVS_ACTION_ATTR_OUTPUT: +@@ -7952,8 +8500,19 @@ dp_execute_cb(void *aux_, struct dp_packet_batch *packets_, + } + + case OVS_ACTION_ATTR_METER: ++#ifdef HAVE_HWOFF_AGENT ++ meter = pmd->dp->meters[meter_id]; ++ if (meter != NULL && (meter->flags & OFPMF13_OFFLOAD)) { ++ meter_usr_data = (struct rte_flow_action_meter *)(&packets_->packets[0]->mbuf.dynfield1[8]); ++ meter_usr_data->mtr_id = meter_id + 1; ++ } else { ++ dp_netdev_run_meter(pmd->dp, packets_, meter_id, ++ pmd->ctx.now); ++ } ++#else + dp_netdev_run_meter(pmd->dp, packets_, nl_attr_get_u32(a), + pmd->ctx.now); ++#endif + break; + + case OVS_ACTION_ATTR_PUSH_VLAN: +@@ -8046,6 +8605,18 @@ dpif_netdev_ct_dump_done(struct dpif *dpif OVS_UNUSED, + return err; + } + ++#ifdef HAVE_HWOFF_AGENT ++static int ++dpif_netdev_ct_flush(struct dpif *dpif, const uint16_t *zone, ++ union ct_addr *sip, union ct_addr *dip, ++ union ct_addr *smask, union ct_addr *dmask, ++ uint16_t dl_type, bool is_force) ++{ ++ struct dp_netdev *dp = get_dp_netdev(dpif); ++ ++ return conntrack_flush(dp->conntrack, zone, sip, dip, smask, dmask, dl_type, is_force); ++} ++#else + static int + dpif_netdev_ct_flush(struct dpif *dpif, const uint16_t *zone, + const struct ct_dpif_tuple *tuple) +@@ -8057,6 +8628,7 @@ dpif_netdev_ct_flush(struct dpif *dpif, const uint16_t *zone, + } + return conntrack_flush(dp->conntrack, zone); + } ++#endif + + static int + dpif_netdev_ct_set_maxconns(struct dpif *dpif, uint32_t maxconns) +@@ -8459,6 +9031,9 @@ const struct dpif_class dpif_netdev_class = { + dpif_netdev_bond_add, + dpif_netdev_bond_del, + dpif_netdev_bond_stats_get, ++#ifdef HAVE_HWOFF_AGENT ++ dpif_netdev_register_pmd_ukey_purge_cb, ++#endif + }; + + static void +diff --git a/openvswitch-2.14.2/lib/dpif-netdev.h b/openvswitch-2.14.2/lib/dpif-netdev.h +index 6db6ed2..84e8b6c 100644 +--- a/openvswitch-2.14.2/lib/dpif-netdev.h ++++ b/openvswitch-2.14.2/lib/dpif-netdev.h +@@ -24,6 +24,9 @@ + #include "openvswitch/types.h" + #include "dp-packet.h" + #include "packets.h" ++#ifdef HAVE_HWOFF_AGENT ++#include "ovs-atomic.h" ++#endif + + #ifdef __cplusplus + extern "C" { +@@ -34,6 +37,12 @@ extern "C" { + enum { DP_NETDEV_HEADROOM = 2 + VLAN_HEADER_LEN }; + + bool dpif_is_netdev(const struct dpif *); ++odp_port_t dpif_netdev_get_odp_no_by_name(const char *devname); ++#ifdef HAVE_HWOFF_AGENT ++struct netdev * dp_get_outdev_from_pmd(odp_port_t port_no, void *tmp_pmd); ++bool dp_netdev_flow_dead_status_get(void *flow); ++void dp_netdev_hwoff_switch_set(int value); ++#endif + + #define NR_QUEUE 1 + #define NR_PMD_THREADS 1 +diff --git a/openvswitch-2.14.2/lib/dpif-netlink.c b/openvswitch-2.14.2/lib/dpif-netlink.c +index 2f881e4..6ad0f59 100644 +--- a/openvswitch-2.14.2/lib/dpif-netlink.c ++++ b/openvswitch-2.14.2/lib/dpif-netlink.c +@@ -2098,6 +2098,7 @@ parse_flow_put(struct dpif_netlink *dpif, struct dpif_flow_put *put) + + info.tp_dst_port = dst_port; + info.tunnel_csum_on = csum_on; ++ info.pmd = NULL; + info.recirc_id_shared_with_tc = (dpif->user_features + & OVS_DP_F_TC_RECIRC_SHARING); + info.tc_modify_flow_deleted = false; +@@ -2900,6 +2901,20 @@ dpif_netlink_ct_dump_done(struct dpif *dpif OVS_UNUSED, + return err; + } + ++#ifdef HAVE_HWOFF_AGENT ++static int ++dpif_netlink_ct_flush(struct dpif *dpif OVS_UNUSED, const uint16_t *zone, ++ union ct_addr *sip OVS_UNUSED, union ct_addr *dip OVS_UNUSED, ++ union ct_addr *smask OVS_UNUSED, union ct_addr *dmask OVS_UNUSED, ++ uint16_t dl_type OVS_UNUSED, bool is_force OVS_UNUSED) ++{ ++ if (zone) { ++ return nl_ct_flush_zone(*zone); ++ } else { ++ return nl_ct_flush(); ++ } ++} ++#else + static int + dpif_netlink_ct_flush(struct dpif *dpif OVS_UNUSED, const uint16_t *zone, + const struct ct_dpif_tuple *tuple) +@@ -2912,6 +2927,7 @@ dpif_netlink_ct_flush(struct dpif *dpif OVS_UNUSED, const uint16_t *zone, + return nl_ct_flush(); + } + } ++#endif + + static int + dpif_netlink_ct_set_limits(struct dpif *dpif OVS_UNUSED, +@@ -4012,6 +4028,9 @@ const struct dpif_class dpif_netlink_class = { + NULL, /* bond_add */ + NULL, /* bond_del */ + NULL, /* bond_stats_get */ ++#ifdef HAVE_HWOFF_AGENT ++ NULL, ++#endif + }; + + static int +diff --git a/openvswitch-2.14.2/lib/dpif-provider.h b/openvswitch-2.14.2/lib/dpif-provider.h +index 0e024c1..c7463a7 100644 +--- a/openvswitch-2.14.2/lib/dpif-provider.h ++++ b/openvswitch-2.14.2/lib/dpif-provider.h +@@ -25,6 +25,7 @@ + #include "openflow/openflow.h" + #include "dpif.h" + #include "util.h" ++#include "conntrack.h" + + #ifdef __cplusplus + extern "C" { +@@ -463,8 +464,14 @@ struct dpif_class { + * - If 'tuple' is not NULL, flush the conntrack entry specified by + * 'tuple' in '*zone'. If 'zone' is NULL, use the default zone + * (zone 0). */ ++#ifdef HAVE_HWOFF_AGENT ++ int (*ct_flush)(struct dpif *, const uint16_t *zone, ++ union ct_addr *sip, union ct_addr *dip, ++ union ct_addr *smask, union ct_addr *dmask, uint16_t dl_type, bool is_force); ++#else + int (*ct_flush)(struct dpif *, const uint16_t *zone, + const struct ct_dpif_tuple *tuple); ++#endif + /* Set max connections allowed. */ + int (*ct_set_maxconns)(struct dpif *, uint32_t maxconns); + /* Get max connections allowed. */ +@@ -628,6 +635,9 @@ struct dpif_class { + * sufficient to store BOND_BUCKETS number of elements. */ + int (*bond_stats_get)(struct dpif *dpif, uint32_t bond_id, + uint64_t *n_bytes); ++#ifdef HAVE_HWOFF_AGENT ++ void (*register_dp_pmd_ukey_purge_cb)(struct dpif *, dp_pmd_ukey_purge_callback *, void *aux); ++#endif + }; + + extern const struct dpif_class dpif_netlink_class; +diff --git a/openvswitch-2.14.2/lib/dpif.c b/openvswitch-2.14.2/lib/dpif.c +index 7cac3a6..0579dd2 100644 +--- a/openvswitch-2.14.2/lib/dpif.c ++++ b/openvswitch-2.14.2/lib/dpif.c +@@ -597,7 +597,7 @@ dpif_port_add(struct dpif *dpif, struct netdev *netdev, odp_port_t *port_nop) + VLOG_DBG_RL(&dpmsg_rl, "%s: added %s as port %"PRIu32, + dpif_name(dpif), netdev_name, port_no); + +- if (!dpif_is_tap_port(netdev_get_type(netdev))) { ++ // if (!dpif_is_tap_port(netdev_get_type(netdev))) { + + const char *dpif_type_str = dpif_normalize_type(dpif_type(dpif)); + struct dpif_port dpif_port; +@@ -606,7 +606,7 @@ dpif_port_add(struct dpif *dpif, struct netdev *netdev, odp_port_t *port_nop) + dpif_port.name = CONST_CAST(char *, netdev_name); + dpif_port.port_no = port_no; + netdev_ports_insert(netdev, dpif_type_str, &dpif_port); +- } ++ // } + } else { + VLOG_WARN_RL(&error_rl, "%s: failed to add %s as port: %s", + dpif_name(dpif), netdev_name, ovs_strerror(error)); +@@ -1504,6 +1504,15 @@ dpif_register_upcall_cb(struct dpif *dpif, upcall_callback *cb, void *aux) + } + } + ++#ifdef HAVE_HWOFF_AGENT ++void ++dpif_register_dp_pmd_ukey_purge_cb(struct dpif *dpif, dp_pmd_ukey_purge_callback *cb, void *aux) ++{ ++ if (dpif->dpif_class->register_dp_pmd_ukey_purge_cb) { ++ dpif->dpif_class->register_dp_pmd_ukey_purge_cb(dpif, cb, aux); ++ } ++} ++#endif + void + dpif_enable_upcall(struct dpif *dpif) + { +diff --git a/openvswitch-2.14.2/lib/dpif.h b/openvswitch-2.14.2/lib/dpif.h +index 2d52f01..9b7a1d0 100644 +--- a/openvswitch-2.14.2/lib/dpif.h ++++ b/openvswitch-2.14.2/lib/dpif.h +@@ -598,6 +598,9 @@ struct dpif_flow { + const struct nlattr *actions; /* Actions, as OVS_ACTION_ATTR_ */ + size_t actions_len; /* 'actions' length in bytes. */ + ovs_u128 ufid; /* Unique flow identifier. */ ++#ifdef HAVE_HWOFF_AGENT ++ ovs_u128 mega_ufid; /* Flow mega identifier. */ ++#endif + bool ufid_present; /* True if 'ufid' was provided by datapath.*/ + unsigned pmd_id; /* Datapath poll mode driver id. */ + struct dpif_flow_stats stats; /* Flow statistics. */ +@@ -838,6 +841,10 @@ struct dpif_upcall { + + void dpif_register_dp_purge_cb(struct dpif *, dp_purge_callback *, void *aux); + ++#ifdef HAVE_HWOFF_AGENT ++typedef void dp_pmd_ukey_purge_callback(void *auc, unsigned pmd_id); ++void dpif_register_dp_pmd_ukey_purge_cb(struct dpif * dpif, dp_pmd_ukey_purge_callback *, void * aux); ++#endif + /* A callback to process an upcall, currently implemented only by dpif-netdev. + * + * The caller provides the 'packet' and 'flow' to process, the corresponding +diff --git a/openvswitch-2.14.2/lib/hwoff_init_func.c b/openvswitch-2.14.2/lib/hwoff_init_func.c +new file mode 100644 +index 0000000..9ad55f8 +--- /dev/null ++++ b/openvswitch-2.14.2/lib/hwoff_init_func.c +@@ -0,0 +1,146 @@ ++/* ++ * Copyright (c) 2021 Cloudbase Solutions Srl ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++#include "hwoff_init_func.h" ++#include "mac-learning.h" ++#include ++ ++#define HWOFF_SHARED_LIB "libdpak_ovs.so" ++#define ADD_FUNC(name) {#name, (void**)&hwoff_funcs.name} ++ ++typedef struct { ++ const char *name; ++ void **func; ++} func_cfg; ++ ++static hwoff_func hwoff_funcs = {0}; ++ ++static func_cfg func_cfgs[] = { ++ ADD_FUNC(hwoff_get_eth_vport_id), ++ ADD_FUNC(hwoff_is_support_offload), ++ ADD_FUNC(hwoff_global_add_vxlan_vtep), ++ ADD_FUNC(hwoff_global_del_vxlan_vtep), ++ ADD_FUNC(hwoff_tnl_get_src_port), ++ ADD_FUNC(hwoff_parse_ovs_other_config), ++ ADD_FUNC(hwoff_is_ethdev), ++ ADD_FUNC(hwoff_set_offload_state), ++ ADD_FUNC(hwoff_set_qos), ++ ADD_FUNC(hwoff_set_ingress_policing), ++ ADD_FUNC(hwoff_parse_vf_extra_options), ++ ADD_FUNC(hwoff_ovs_init), ++ ADD_FUNC(hwoff_ovs_flow_create), ++ ADD_FUNC(hwoff_ovs_flow_query), ++ ADD_FUNC(hwoff_ovs_flow_destroy), ++ ADD_FUNC(hwoff_set_flow_qos), ++ ADD_FUNC(hwoff_del_flow_qos), ++ ADD_FUNC(hwoff_query_flow_qos_stats), ++}; ++ ++hwoff_func* hwoff_get_funcs(void) ++{ ++ return &hwoff_funcs; ++} ++ ++static int hwoff_offload_agent_init(void) ++{ ++ int ret = 0; ++ hwoff_func* func = NULL; ++ func = hwoff_get_funcs(); ++ ++ if (func->hwoff_ovs_init != NULL) { ++ ret = func->hwoff_ovs_init(); ++ if (ret != 0) { ++ return -1; ++ } ++ } ++ ++ hwoff_rarp_mac_list_init(); ++ return ret; ++} ++ ++int hwoff_funcs_init(void) ++{ ++ void *handler = dlopen(HWOFF_SHARED_LIB, RTLD_NOW); ++ int ret = 0; ++ ++ if (handler == NULL) { ++ RTE_LOG(ERR, EAL, "%s load err %s \n", HWOFF_SHARED_LIB, dlerror()); ++ return -1; ++ } ++ ++ for (int index = 0; index < ARRAY_SIZE(func_cfgs); index++) { ++ *func_cfgs[index].func = dlsym(handler, func_cfgs[index].name); ++ if (*func_cfgs[index].func == NULL) { ++ RTE_LOG(ERR, EAL, "%s load func %s fail: %s", HWOFF_SHARED_LIB, func_cfgs[index].name, dlerror()); ++ dlclose(handler); ++ return -1; ++ } ++ } ++ ++ ret = hwoff_offload_agent_init(); ++ if (ret != 0) { ++ RTE_LOG(ERR, EAL, "hwoff offload agent init failed"); ++ } ++ return ret; ++} ++ ++int hwoff_key_val_init(struct hwoff_key_val_node **dst,const struct smap *src) ++{ ++ size_t num_pairs = smap_count(src); ++ *dst = xmalloc(num_pairs * sizeof(struct hwoff_key_val_node)); ++ ++ struct smap_node *node; ++ int i = 0; ++ SMAP_FOR_EACH (node, src) { ++ (*dst)[i].key = xstrdup(node->key); ++ (*dst)[i].value = xstrdup(node->value); ++ if ((*dst)[i].key == NULL ||(*dst)[i].value == NULL) { ++ if((*dst)[i].key != NULL) { ++ free((*dst)[i].key); ++ (*dst)[i].key = NULL; ++ } ++ if((*dst)[i].value != NULL) { ++ free((*dst)[i].value); ++ (*dst)[i].value = NULL; ++ } ++ for (int j = 0; j < i; j++) { ++ free((*dst)[i].key); ++ free((*dst)[i].value); ++ (*dst)[i].key = NULL; ++ (*dst)[i].value = NULL; ++ } ++ free((*dst)); ++ (*dst) = NULL; ++ return -1; ++ } ++ i++; ++ } ++ return 0; ++} ++ ++void hwoff_key_val_destroy(struct hwoff_key_val_node *hwoff_key_val,size_t size) ++{ ++ if (hwoff_key_val == NULL) { ++ return; ++ } ++ for (int i = 0; i < size; i++) { ++ free(hwoff_key_val[i].key); ++ free(hwoff_key_val[i].value); ++ hwoff_key_val[i].key = NULL; ++ hwoff_key_val[i].value = NULL; ++ } ++ free(hwoff_key_val); ++ hwoff_key_val = NULL; ++} +\ No newline at end of file +diff --git a/openvswitch-2.14.2/lib/hwoff_init_func.h b/openvswitch-2.14.2/lib/hwoff_init_func.h +new file mode 100644 +index 0000000..2229203 +--- /dev/null ++++ b/openvswitch-2.14.2/lib/hwoff_init_func.h +@@ -0,0 +1,49 @@ ++/* ++ * Copyright (c) 2021 Cloudbase Solutions Srl ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef HWOFF_INIT_FUNC_H ++#define HWOFF_INIT_FUNC_H 1 ++ ++#include "dpak_ovs.h" ++#include "smap.h" ++typedef struct { ++ uint32_t (*hwoff_get_eth_vport_id)(struct netdev *netdev); ++ bool (*hwoff_is_ethdev)(const struct netdev *netdev); ++ bool (*hwoff_is_support_offload)(const struct netdev *netdev); ++ int (*hwoff_global_add_vxlan_vtep)(bool is_ipv6, uint8_t *vxlan_dstip, uint32_t length, uint16_t dst_port); ++ int (*hwoff_global_del_vxlan_vtep)(bool is_ipv6, uint8_t *vxlan_dstip, uint32_t length); ++ uint16_t (*hwoff_tnl_get_src_port)(struct dp_packet *one_pkt); ++ void (*hwoff_parse_ovs_other_config)(const struct hwoff_key_val_node *ovs_other_config, size_t size); ++ void (*hwoff_set_offload_state)(hwoff_offload_state_t offload); ++ void (*hwoff_set_qos)(uint16_t port_id, const char *type, ++ const struct hwoff_key_val_node *details, size_t size); ++ void (*hwoff_set_ingress_policing)(uint16_t port_id, uint32_t policer_rate, uint32_t policer_burst); ++ int (*hwoff_parse_vf_extra_options)(uint16_t dpdk_port_id, const struct hwoff_key_val_node *details, size_t size); ++ int (*hwoff_ovs_init)(void); ++ struct rte_flow* (*hwoff_ovs_flow_create)(struct rte_eth_dev *dev, struct hwoff_key_val_node *offload_info, uint8_t info_size, ++ struct rte_flow_action *mega_action, struct rte_flow_error *error); ++ int (*hwoff_ovs_flow_query)(struct rte_eth_dev *dev, struct rte_flow *mega_flow, void *data, struct rte_flow_error *error); ++ int (*hwoff_ovs_flow_destroy)(struct rte_eth_dev *dev, struct rte_flow *mega_flow, struct rte_flow_error *error); ++ int (*hwoff_set_flow_qos)(uint32_t mtr_id, struct rte_mtr_meter_profile *profile, uint32_t user_meter_id); ++ int (*hwoff_del_flow_qos)(uint32_t mtr_id); ++ int (*hwoff_query_flow_qos_stats)(uint32_t mtr_id, struct rte_mtr_stats *meter_stat); ++} hwoff_func; ++ ++hwoff_func* hwoff_get_funcs(void); ++int hwoff_funcs_init(void); ++int hwoff_key_val_init(struct hwoff_key_val_node **dst,const struct smap *src); ++void hwoff_key_val_destroy(struct hwoff_key_val_node *hwoff_key_val,size_t size); ++#endif +diff --git a/openvswitch-2.14.2/lib/mac-learning.c b/openvswitch-2.14.2/lib/mac-learning.c +index f618348..d0644b3 100644 +--- a/openvswitch-2.14.2/lib/mac-learning.c ++++ b/openvswitch-2.14.2/lib/mac-learning.c +@@ -29,12 +29,95 @@ + #include "unaligned.h" + #include "util.h" + #include "vlan-bitmap.h" +- ++#include "openvswitch/vlog.h" ++VLOG_DEFINE_THIS_MODULE(mac_learning); + COVERAGE_DEFINE(mac_learning_learned); + COVERAGE_DEFINE(mac_learning_expired); + COVERAGE_DEFINE(mac_learning_evicted); + COVERAGE_DEFINE(mac_learning_moved); + ++ ++#ifdef HAVE_HWOFF_AGENT ++static struct hwoff_migrate_rarp_mac_infos g_hwoff_migrate_rarp_mac_infos; ++static bool g_hwoff_rarp_enabled = false; ++ ++struct hwoff_migrate_rarp_mac_infos *hwoff_migrate_rarp_mac_infos_get(void) ++{ ++ return &g_hwoff_migrate_rarp_mac_infos; ++} ++ ++bool hwoff_rarp_status_get(void) ++{ ++ return g_hwoff_rarp_enabled; ++} ++ ++struct hwoff_migrate_rarp_mac_entry *hwoff_get_entry_by_mac(struct eth_addr mac) ++{ ++ struct hwoff_migrate_rarp_mac_entry *entry_iter = NULL; ++ ++ HMAP_FOR_EACH_WITH_HASH (entry_iter, mac_entry_node, hash_mac(mac, 0, 0), ++ &g_hwoff_migrate_rarp_mac_infos.mac_info_list) { ++ if (eth_addr_equals(entry_iter->mac_addr, mac)) { ++ return entry_iter; ++ } ++ } ++ ++ return NULL; ++} ++ ++struct hwoff_migrate_rarp_mac_entry * hwoff_rarp_mac_insert_to_list(struct eth_addr mac) ++{ ++ if (g_hwoff_migrate_rarp_mac_infos.length >= HWOFF_MIGRATE_MAC_MAX_NUM) { ++ return NULL; ++ } ++ ++ uint32_t hash = hash_mac(mac, 0, 0); ++ struct hwoff_migrate_rarp_mac_entry *entry = hwoff_get_entry_by_mac(mac); ++ if (entry == NULL) { ++ entry = xmalloc(sizeof *entry); ++ memcpy(&entry->mac_addr.ea, &mac.ea, ETH_ADDR_LEN); ++ hmap_insert(&g_hwoff_migrate_rarp_mac_infos.mac_info_list, &entry->mac_entry_node, hash); ++ g_hwoff_migrate_rarp_mac_infos.length++; ++ } ++ ++ entry->is_need_del = true; ++ return entry; ++} ++ ++void hwoff_rarp_mac_remove_from_list(struct hwoff_migrate_rarp_mac_entry *entry) ++{ ++ if (OVS_UNLIKELY(entry == NULL)) { ++ return; ++ } ++ hmap_remove(&g_hwoff_migrate_rarp_mac_infos.mac_info_list, &entry->mac_entry_node); ++ g_hwoff_migrate_rarp_mac_infos.length--; ++ free(entry); ++ entry = NULL; ++} ++ ++void hwoff_rarp_mac_list_init(void) ++{ ++ hmap_init(&g_hwoff_migrate_rarp_mac_infos.mac_info_list); ++ ovs_rwlock_init(&g_hwoff_migrate_rarp_mac_infos.rw); ++ g_hwoff_migrate_rarp_mac_infos.length = 0; ++ g_hwoff_rarp_enabled = true; ++} ++ ++void hwoff_rarp_mac_list_uninit(void) ++{ ++ struct hwoff_migrate_rarp_mac_entry *entry_iter = NULL, *next_entry_iter = NULL; ++ ++ ovs_rwlock_wrlock(&g_hwoff_migrate_rarp_mac_infos.rw); ++ HMAP_FOR_EACH_SAFE (entry_iter, next_entry_iter, mac_entry_node, &g_hwoff_migrate_rarp_mac_infos.mac_info_list) { ++ hwoff_rarp_mac_remove_from_list(entry_iter); ++ } ++ hmap_destroy(&g_hwoff_migrate_rarp_mac_infos.mac_info_list); ++ g_hwoff_migrate_rarp_mac_infos.length = 0; ++ ovs_rwlock_unlock(&g_hwoff_migrate_rarp_mac_infos.rw); ++ g_hwoff_rarp_enabled = false; ++} ++#endif ++ + /* Returns the number of seconds since 'e' (within 'ml') was last learned. */ + int + mac_entry_age(const struct mac_learning *ml, const struct mac_entry *e) +@@ -410,12 +493,21 @@ is_mac_learning_update_needed(const struct mac_learning *ml, + * Keep the code here synchronized with that in is_mac_learning_update_needed() + * above. */ + static bool ++#ifdef HAVE_HWOFF_AGENT ++update_learning_table__(struct mac_learning *ml, struct eth_addr src, ++ int vlan, bool is_gratuitous_arp, bool is_bond, ++ void *in_port, void **out_port) ++#else + update_learning_table__(struct mac_learning *ml, struct eth_addr src, + int vlan, bool is_gratuitous_arp, bool is_bond, + void *in_port) ++#endif + OVS_REQ_WRLOCK(ml->rwlock) + { + struct mac_entry *mac; ++#ifdef HAVE_HWOFF_AGENT ++ void *mac_port = NULL; ++#endif + + if (!mac_learning_may_learn(ml, src, vlan)) { + return false; +@@ -437,7 +529,19 @@ update_learning_table__(struct mac_learning *ml, struct eth_addr src, + return false; + } + } +- ++#ifdef HAVE_HWOFF_AGENT ++ mac_port = mac_entry_get_port(ml, mac); ++ if (mac_port != in_port) { ++ if (mac_port) { ++ COVERAGE_INC(mac_learning_moved); ++ if (out_port) { ++ *out_port = mac_port; ++ } ++ } ++ mac_entry_set_port(ml, mac, in_port); ++ return true; ++ } ++#else + if (mac_entry_get_port(ml, mac) != in_port) { + if (mac_entry_get_port(ml, mac) != NULL) { + COVERAGE_INC(mac_learning_moved); +@@ -446,6 +550,7 @@ update_learning_table__(struct mac_learning *ml, struct eth_addr src, + mac_entry_set_port(ml, mac, in_port); + return true; + } ++#endif + return false; + } + +@@ -455,11 +560,19 @@ update_learning_table__(struct mac_learning *ml, struct eth_addr src, + * 'is_bond' is 'true'. + * + * Returns 'true' if 'ml' was updated, 'false' otherwise. */ ++#ifdef HAVE_HWOFF_AGENT ++bool ++mac_learning_update(struct mac_learning *ml, struct eth_addr src, ++ int vlan, bool is_gratuitous_arp, bool is_bond, ++ void *in_port, void **out_port) ++ OVS_EXCLUDED(ml->rwlock) ++#else + bool + mac_learning_update(struct mac_learning *ml, struct eth_addr src, + int vlan, bool is_gratuitous_arp, bool is_bond, + void *in_port) + OVS_EXCLUDED(ml->rwlock) ++#endif + { + bool need_update; + bool updated = false; +@@ -476,8 +589,13 @@ mac_learning_update(struct mac_learning *ml, struct eth_addr src, + if (need_update) { + /* Slow path: MAC learning table might need an update. */ + ovs_rwlock_wrlock(&ml->rwlock); ++#ifdef HAVE_HWOFF_AGENT ++ updated = update_learning_table__(ml, src, vlan, is_gratuitous_arp, ++ is_bond, in_port, out_port); ++#else + updated = update_learning_table__(ml, src, vlan, is_gratuitous_arp, + is_bond, in_port); ++#endif + ovs_rwlock_unlock(&ml->rwlock); + } + } +diff --git a/openvswitch-2.14.2/lib/mac-learning.h b/openvswitch-2.14.2/lib/mac-learning.h +index ad2f1fe..dd53a0e 100644 +--- a/openvswitch-2.14.2/lib/mac-learning.h ++++ b/openvswitch-2.14.2/lib/mac-learning.h +@@ -118,6 +118,30 @@ struct mac_entry { + struct ovs_list port_lru_node; /* In mac_learning_port's "port_lru"s. */ + }; + ++#ifdef HAVE_HWOFF_AGENT ++#define HWOFF_MIGRATE_MAC_MAX_NUM 8192 ++ ++struct hwoff_migrate_rarp_mac_entry { ++ bool is_need_del; ++ struct eth_addr mac_addr; ++ struct hmap_node mac_entry_node; ++}; ++ ++struct hwoff_migrate_rarp_mac_infos { ++ struct ovs_rwlock rw; ++ struct hmap mac_info_list; ++ uint64_t length; ++}; ++ ++void hwoff_rarp_mac_list_init(void); ++bool hwoff_rarp_status_get(void); ++void hwoff_rarp_mac_list_uninit(void); ++struct hwoff_migrate_rarp_mac_infos *hwoff_migrate_rarp_mac_infos_get(void); ++void hwoff_rarp_mac_remove_from_list(struct hwoff_migrate_rarp_mac_entry *e); ++struct hwoff_migrate_rarp_mac_entry *hwoff_get_entry_by_mac(struct eth_addr mac); ++struct hwoff_migrate_rarp_mac_entry * hwoff_rarp_mac_insert_to_list(struct eth_addr mac); ++ ++#endif + static inline void *mac_entry_get_port(const struct mac_learning *ml, + const struct mac_entry *); + void mac_entry_set_port(struct mac_learning *, struct mac_entry *, void *port); +@@ -214,10 +238,19 @@ struct mac_entry *mac_learning_insert(struct mac_learning *ml, + const struct eth_addr src, + uint16_t vlan) + OVS_REQ_WRLOCK(ml->rwlock); +-bool mac_learning_update(struct mac_learning *ml, struct eth_addr src, +- int vlan, bool is_gratuitous_arp, bool is_bond, +- void *in_port) ++#ifdef HAVE_HWOFF_AGENT ++bool ++mac_learning_update(struct mac_learning *ml, struct eth_addr src, ++ int vlan, bool is_gratuitous_arp, bool is_bond, ++ void *in_port, void **out_port) ++ OVS_EXCLUDED(ml->rwlock); ++#else ++bool ++mac_learning_update(struct mac_learning *ml, struct eth_addr src, ++ int vlan, bool is_gratuitous_arp, bool is_bond, ++ void *in_port) + OVS_EXCLUDED(ml->rwlock); ++#endif + + /* Lookup. */ + struct mac_entry *mac_learning_lookup(const struct mac_learning *ml, +diff --git a/openvswitch-2.14.2/lib/netdev-dpdk.c b/openvswitch-2.14.2/lib/netdev-dpdk.c +index f9284d0..41ece0d 100644 +--- a/openvswitch-2.14.2/lib/netdev-dpdk.c ++++ b/openvswitch-2.14.2/lib/netdev-dpdk.c +@@ -26,6 +26,10 @@ + #include + #include + ++#ifdef HAVE_HWOFF_AGENT ++#include "hwoff_init_func.h" ++#endif ++ + /* Include rte_compat.h first to allow experimental API's needed for the + * rte_meter.h rfc4115 functions. Once they are no longer marked as + * experimental the #define and rte_compat.h include can be removed. +@@ -74,6 +78,9 @@ + #include "userspace-tso.h" + #include "util.h" + #include "uuid.h" ++#ifdef HAVE_HWOFF_AGENT ++#include "hwoff_init_func.h" ++#endif + + enum {VIRTIO_RXQ, VIRTIO_TXQ, VIRTIO_QNUM}; + +@@ -109,7 +116,7 @@ COVERAGE_DEFINE(vhost_notification); + * enough hugepages) we keep halving the number until the allocation succeeds + * or we reach MIN_NB_MBUF */ + +-#define MAX_NB_MBUF (4096 * 64) ++#define MAX_NB_MBUF (512 * 320 * 2) // queue_desc * queue_num * rx/tx + #define MIN_NB_MBUF (4096 * 4) + #define MP_CACHE_SZ RTE_MEMPOOL_CACHE_MAX_SIZE + +@@ -187,6 +194,7 @@ static int vring_state_changed(int vid, uint16_t queue_id, int enable); + static void destroy_connection(int vid); + static void vhost_guest_notified(int vid); + ++#ifdef DPDK_2011_AND_BEFORE + static const struct vhost_device_ops virtio_net_device_ops = + { + .new_device = new_device, +@@ -197,6 +205,19 @@ static const struct vhost_device_ops virtio_net_device_ops = + .destroy_connection = destroy_connection, + .guest_notified = vhost_guest_notified, + }; ++#else ++static const struct rte_vhost_device_ops virtio_net_device_ops = ++{ ++ .new_device = new_device, ++ .destroy_device = destroy_device, ++ .vring_state_changed = vring_state_changed, ++ .features_changed = NULL, ++ .new_connection = NULL, ++ .destroy_connection = destroy_connection, ++ .guest_notified = vhost_guest_notified, ++}; ++#endif ++ + + /* Custom software stats for dpdk ports */ + struct netdev_dpdk_sw_stats { +@@ -432,6 +453,10 @@ struct netdev_dpdk { + /* If true, rte_eth_dev_start() was successfully called */ + bool started; + bool reset_needed; ++#ifdef HAVE_HWOFF_AGENT ++ bool hwoff_reconfigure; ++ bool hwoff_used_share_upcall; ++#endif + /* 1 pad byte here. */ + struct eth_addr hwaddr; + int mtu; +@@ -675,6 +700,7 @@ dpdk_calculate_mbufs(struct netdev_dpdk *dev, int mtu, bool per_port_mp) + return n_mbufs; + } + ++#define HWOFF_MBUF_SIZE 2176 + static struct dpdk_mp * + dpdk_mp_create(struct netdev_dpdk *dev, int mtu, bool per_port_mp) + { +@@ -699,8 +725,11 @@ dpdk_mp_create(struct netdev_dpdk *dev, int mtu, bool per_port_mp) + dmp->refcount = 1; + + /* Get the size of each mbuf, based on the MTU */ ++#ifdef HAVE_HWOFF_AGENT ++ mbuf_size = HWOFF_MBUF_SIZE; ++#else + mbuf_size = MTU_TO_FRAME_LEN(mtu); +- ++#endif + n_mbufs = dpdk_calculate_mbufs(dev, mtu, per_port_mp); + + do { +@@ -1146,8 +1175,13 @@ dpdk_eth_dev_init(struct netdev_dpdk *dev) + } + } + +- n_rxq = MIN(info.max_rx_queues, dev->up.n_rxq); + n_txq = MIN(info.max_tx_queues, dev->up.n_txq); ++ if(info.max_rx_queues < (dev->up.n_rxq)) { ++ n_rxq = info.max_rx_queues; ++ VLOG_INFO("option:n_rxq is out of range, it has changed to default maximum value:%d", info.max_rx_queues); ++ } else { ++ n_rxq = dev->up.n_rxq; ++ } + + diag = dpdk_eth_dev_port_config(dev, n_rxq, n_txq); + if (diag) { +@@ -1247,6 +1281,9 @@ common_construct(struct netdev *netdev, dpdk_port_t port_no, + dev->attached = false; + dev->started = false; + dev->reset_needed = false; ++#ifdef HAVE_HWOFF_AGENT ++ dev->hwoff_reconfigure = false; ++#endif + + ovsrcu_init(&dev->qos_conf, NULL); + +@@ -1285,31 +1322,11 @@ common_construct(struct netdev *netdev, dpdk_port_t port_no, + return 0; + } + +-/* Get the number of OVS interfaces which have the same DPDK +- * rte device (e.g. same pci bus address). +- * FIXME: avoid direct access to DPDK internal array rte_eth_devices. +- */ +-static int +-netdev_dpdk_get_num_ports(struct rte_device *device) +- OVS_REQUIRES(dpdk_mutex) +-{ +- struct netdev_dpdk *dev; +- int count = 0; +- +- LIST_FOR_EACH (dev, list_node, &dpdk_list) { +- if (rte_eth_devices[dev->port_id].device == device +- && rte_eth_devices[dev->port_id].state != RTE_ETH_DEV_UNUSED) { +- count++; +- } +- } +- return count; +-} +- + static int + vhost_common_construct(struct netdev *netdev) + OVS_REQUIRES(dpdk_mutex) + { +- int socket_id = rte_lcore_to_socket_id(rte_get_master_lcore()); ++ int socket_id = rte_lcore_to_socket_id(rte_get_main_lcore()); + struct netdev_dpdk *dev = netdev_dpdk_cast(netdev); + + dev->vhost_rxq_enabled = dpdk_rte_mzalloc(OVS_VHOST_MAX_QUEUE_NUM * +@@ -1458,9 +1475,6 @@ static void + netdev_dpdk_destruct(struct netdev *netdev) + { + struct netdev_dpdk *dev = netdev_dpdk_cast(netdev); +- struct rte_device *rte_dev; +- struct rte_eth_dev *eth_dev; +- bool remove_on_close; + + ovs_mutex_lock(&dpdk_mutex); + +@@ -1468,25 +1482,43 @@ netdev_dpdk_destruct(struct netdev *netdev) + dev->started = false; + + if (dev->attached) { +- /* Retrieve eth device data before closing it. +- * FIXME: avoid direct access to DPDK internal array rte_eth_devices. +- */ +- eth_dev = &rte_eth_devices[dev->port_id]; +- remove_on_close = +- eth_dev->data && +- (eth_dev->data->dev_flags & RTE_ETH_DEV_CLOSE_REMOVE); +- rte_dev = eth_dev->device; ++ bool dpdk_resources_still_used = false; ++ struct rte_eth_dev_info dev_info; ++ dpdk_port_t sibling_port_id; ++ ++ /* Check if this netdev has siblings (i.e. shares DPDK resources) among ++ * other OVS netdevs. */ ++ RTE_ETH_FOREACH_DEV_SIBLING (sibling_port_id, dev->port_id) { ++ struct netdev_dpdk *sibling; ++ ++ /* RTE_ETH_FOREACH_DEV_SIBLING lists dev->port_id as part of the ++ * loop. */ ++ if (sibling_port_id == dev->port_id) { ++ continue; ++ } ++ LIST_FOR_EACH (sibling, list_node, &dpdk_list) { ++ if (sibling->port_id != sibling_port_id) { ++ continue; ++ } ++ dpdk_resources_still_used = true; ++ break; ++ } ++ if (dpdk_resources_still_used) { ++ break; ++ } ++ } ++ ++ /* Retrieve eth device data before closing it. */ ++ rte_eth_dev_info_get(dev->port_id, &dev_info); + + /* Remove the eth device. */ + rte_eth_dev_close(dev->port_id); + +- /* Remove this rte device and all its eth devices if flag +- * RTE_ETH_DEV_CLOSE_REMOVE is not supported (which means representors +- * are not supported), or if all the eth devices belonging to the rte +- * device are closed. +- */ +- if (!remove_on_close || !netdev_dpdk_get_num_ports(rte_dev)) { +- int ret = rte_dev_remove(rte_dev); ++ /* Remove the rte device if no associated eth device is used by OVS. ++ * Note: any remaining eth devices associated to this rte device are ++ * closed by DPDK ethdev layer. */ ++ if (!dpdk_resources_still_used) { ++ int ret = rte_dev_remove(dev_info.device); + + if (ret < 0) { + VLOG_ERR("Device '%s' can not be detached: %s.", +@@ -1787,6 +1819,103 @@ static dpdk_port_t netdev_dpdk_get_port_by_devargs(const char *devargs) + return port_id; + } + ++#ifdef HAVE_HWOFF_AGENT ++#define HWOFF_SPLIT_STR_LENGTH 30 ++int ++hwoff_netdev_name_get(uint16_t port_id, char name_buffer[], int buffer_size) ++{ ++ struct netdev_dpdk *dev = NULL; ++ dev = netdev_dpdk_lookup_by_port_id(port_id); ++ if (dev == NULL) { ++ return -1; ++ } ++ ovs_strlcpy(name_buffer, dev->up.name, buffer_size); ++ return 0; ++} ++ ++bool ++hwoff_netdev_is_shared(struct netdev *dev) ++{ ++ if (!is_dpdk_class(dev->netdev_class)) { ++ return false; ++ } ++ ++ struct netdev_dpdk *dpdk_dev = NULL; ++ dpdk_dev = netdev_dpdk_cast(dev); ++ return dpdk_dev == NULL ? false : dpdk_dev->hwoff_used_share_upcall; ++} ++ ++static int ++open_share_upcall(const char *key, const char *value, void *extra_args) ++{ ++ uint8_t *share_upcall = (uint8_t *)extra_args; ++ if (value == NULL || share_upcall == NULL) { ++ return -1; ++ } ++ ++ if (strcmp("true", value) == 0) { ++ *share_upcall = true; ++ } else if (strcmp("false", value) == 0) { ++ *share_upcall = false; ++ } else { ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int ++hwoff_get_share_upcall_str(const char *src, char *dst) ++{ ++ char *sub_str = strstr(src ,"share-upcall-queues"); ++ if (sub_str == NULL) { ++ return -1; ++ } ++ ++ for (int i = 0; i < HWOFF_SPLIT_STR_LENGTH; ++i) { ++ if (sub_str[i] == '\0') { ++ dst[i] = sub_str[i]; ++ return 0; ++ } ++ ++ if (sub_str[i] == ',') { ++ return 0; ++ } ++ dst[i] = sub_str[i]; ++ } ++ ++ return 0; ++} ++ ++static bool hwoff_port_share_upcall(const char *args) ++{ ++ const char *valid_key_list[] = {"share-upcall-queues", NULL}; ++ struct rte_kvargs *kvargs = NULL; ++ int ret = 0; ++ bool share_upcall = false; ++ char share_upcall_str[HWOFF_SPLIT_STR_LENGTH] = {0}; ++ ++ ret = hwoff_get_share_upcall_str(args, share_upcall_str); ++ if (ret < 0) { ++ return false; ++ } ++ ++ kvargs = rte_kvargs_parse(share_upcall_str, valid_key_list); ++ if (kvargs == NULL) { ++ return false; ++ } ++ ++ ret = rte_kvargs_process(kvargs, "share-upcall-queues", open_share_upcall, &share_upcall); ++ if (ret != 0) { ++ rte_kvargs_free(kvargs); ++ return false; ++ } ++ ++ rte_kvargs_free(kvargs); ++ return share_upcall; ++} ++#endif ++ + /* + * Normally, a PCI id (optionally followed by a representor number) + * is enough for identifying a specific DPDK port. +@@ -1826,6 +1955,13 @@ netdev_dpdk_process_devargs(struct netdev_dpdk *dev, + } + } + } ++#ifdef HAVE_HWOFF_AGENT ++ /* Add share upcall queue flag on dpdk_device according to input args */ ++ if (new_port_id != DPDK_ETH_PORT_ID_INVALID && ++ hwoff_port_share_upcall(devargs)) { ++ dev->hwoff_used_share_upcall = true; ++ } ++#endif + + if (new_port_id == DPDK_ETH_PORT_ID_INVALID) { + VLOG_WARN_BUF(errp, "Error attaching device '%s' to DPDK", devargs); +@@ -1868,7 +2004,12 @@ dpdk_set_rxq_config(struct netdev_dpdk *dev, const struct smap *args) + { + int new_n_rxq; + +- new_n_rxq = MAX(smap_get_int(args, "n_rxq", NR_QUEUE), 1); ++ if(smap_get_int(args, "n_rxq", NR_QUEUE) < 1) { ++ new_n_rxq = 1; ++ VLOG_INFO("option:n_rxq is out of range, it has changed to default minimum value:%d", new_n_rxq); ++ } else { ++ new_n_rxq = smap_get_int(args, "n_rxq", NR_QUEUE); ++ } + if (new_n_rxq != dev->requested_n_rxq) { + dev->requested_n_rxq = new_n_rxq; + netdev_request_reconfigure(&dev->up); +@@ -1974,7 +2115,23 @@ netdev_dpdk_set_config(struct netdev *netdev, const struct smap *args, + if (err) { + goto out; + } ++#ifdef HAVE_HWOFF_AGENT ++ hwoff_func* funcs = hwoff_get_funcs(); ++ ++ size_t num_pairs = smap_count(args); ++ struct hwoff_key_val_node *hwoff_key_val = NULL; ++ err = hwoff_key_val_init(&hwoff_key_val, args); ++ if (err != 0){ ++ goto out; ++ } + ++ err = funcs->hwoff_parse_vf_extra_options(dev->port_id, hwoff_key_val, num_pairs); ++ if (err == 0) { ++ dev->hwoff_reconfigure = true; ++ netdev_request_reconfigure(netdev); ++ } ++ hwoff_key_val_destroy(hwoff_key_val, num_pairs); ++#endif + lsc_interrupt_mode = smap_get_bool(args, "dpdk-lsc-interrupt", false); + if (dev->requested_lsc_interrupt_mode != lsc_interrupt_mode) { + dev->requested_lsc_interrupt_mode = lsc_interrupt_mode; +@@ -2039,12 +2196,6 @@ netdev_dpdk_vhost_client_set_config(struct netdev *netdev, + if (!nullable_string_is_equal(path, dev->vhost_id)) { + free(dev->vhost_id); + dev->vhost_id = nullable_xstrdup(path); +- /* check zero copy configuration */ +- if (smap_get_bool(args, "dq-zero-copy", false)) { +- dev->vhost_driver_flags |= RTE_VHOST_USER_DEQUEUE_ZERO_COPY; +- } else { +- dev->vhost_driver_flags &= ~RTE_VHOST_USER_DEQUEUE_ZERO_COPY; +- } + netdev_request_reconfigure(netdev); + } + } +@@ -2145,14 +2296,21 @@ netdev_dpdk_prep_hwol_packet(struct netdev_dpdk *dev, struct rte_mbuf *mbuf) + { + struct dp_packet *pkt = CONTAINER_OF(mbuf, struct dp_packet, mbuf); + ++#ifdef DPDK_2011_AND_BEFORE + if (mbuf->ol_flags & PKT_TX_L4_MASK) { ++#else ++ if (mbuf->ol_flags & RTE_MBUF_F_TX_L4_MASK) { ++#endif + mbuf->l2_len = (char *)dp_packet_l3(pkt) - (char *)dp_packet_eth(pkt); + mbuf->l3_len = (char *)dp_packet_l4(pkt) - (char *)dp_packet_l3(pkt); + mbuf->outer_l2_len = 0; + mbuf->outer_l3_len = 0; + } +- ++#ifdef DPDK_2011_AND_BEFORE + if (mbuf->ol_flags & PKT_TX_TCP_SEG) { ++#else ++ if (mbuf->ol_flags & RTE_MBUF_F_TX_TCP_SEG) { ++#endif + struct tcp_header *th = dp_packet_l4(pkt); + + if (!th) { +@@ -2162,12 +2320,19 @@ netdev_dpdk_prep_hwol_packet(struct netdev_dpdk *dev, struct rte_mbuf *mbuf) + } + + mbuf->l4_len = TCP_OFFSET(th->tcp_ctl) * 4; ++#ifdef DPDK_2011_AND_BEFORE + mbuf->ol_flags |= PKT_TX_TCP_CKSUM; + mbuf->tso_segsz = dev->mtu - mbuf->l3_len - mbuf->l4_len; +- + if (mbuf->ol_flags & PKT_TX_IPV4) { + mbuf->ol_flags |= PKT_TX_IP_CKSUM; + } ++#else ++ mbuf->ol_flags |= RTE_MBUF_F_TX_TCP_CKSUM; ++ mbuf->tso_segsz = dev->mtu - mbuf->l3_len - mbuf->l4_len; ++ if (mbuf->ol_flags & RTE_MBUF_F_TX_IPV4) { ++ mbuf->ol_flags |= RTE_MBUF_F_TX_IP_CKSUM; ++ } ++#endif + } + return true; + } +@@ -2513,7 +2678,11 @@ netdev_dpdk_filter_packet_len(struct netdev_dpdk *dev, struct rte_mbuf **pkts, + for (i = 0; i < pkt_cnt; i++) { + pkt = pkts[i]; + if (OVS_UNLIKELY((pkt->pkt_len > dev->max_packet_len) ++#ifdef DPDK_2011_AND_BEFORE + && !(pkt->ol_flags & PKT_TX_TCP_SEG))) { ++#else ++ && !(pkt->ol_flags & RTE_MBUF_F_TX_TCP_SEG))) { ++#endif + VLOG_WARN_RL(&rl, "%s: Too big size %" PRIu32 " " + "max_packet_len %d", dev->up.name, pkt->pkt_len, + dev->max_packet_len); +@@ -2734,13 +2903,19 @@ dpdk_copy_dp_packet_to_mbuf(struct rte_mempool *mp, struct dp_packet *pkt_orig) + + mbuf_dest->tx_offload = pkt_orig->mbuf.tx_offload; + mbuf_dest->packet_type = pkt_orig->mbuf.packet_type; ++#ifdef DPDK_2011_AND_BEFORE + mbuf_dest->ol_flags |= (pkt_orig->mbuf.ol_flags & + ~(EXT_ATTACHED_MBUF | IND_ATTACHED_MBUF)); +- + memcpy(&pkt_dest->l2_pad_size, &pkt_orig->l2_pad_size, + sizeof(struct dp_packet) - offsetof(struct dp_packet, l2_pad_size)); +- + if (mbuf_dest->ol_flags & PKT_TX_L4_MASK) { ++#else ++ mbuf_dest->ol_flags |= (pkt_orig->mbuf.ol_flags & ++ ~(RTE_MBUF_F_EXTERNAL | RTE_MBUF_F_INDIRECT)); ++ memcpy(&pkt_dest->l2_pad_size, &pkt_orig->l2_pad_size, ++ sizeof(struct dp_packet) - offsetof(struct dp_packet, l2_pad_size)); ++ if (mbuf_dest->ol_flags & RTE_MBUF_F_TX_L4_MASK) { ++#endif + mbuf_dest->l2_len = (char *)dp_packet_l3(pkt_dest) + - (char *)dp_packet_eth(pkt_dest); + mbuf_dest->l3_len = (char *)dp_packet_l4(pkt_dest) +@@ -2785,7 +2960,11 @@ dpdk_do_tx_copy(struct netdev *netdev, int qid, struct dp_packet_batch *batch) + uint32_t size = dp_packet_size(packet); + + if (size > dev->max_packet_len ++#ifdef DPDK_2011_AND_BEFORE + && !(packet->mbuf.ol_flags & PKT_TX_TCP_SEG)) { ++#else ++ && !(packet->mbuf.ol_flags & RTE_MBUF_F_TX_TCP_SEG)) { ++#endif + VLOG_WARN_RL(&rl, "Too big size %u max_packet_len %d", size, + dev->max_packet_len); + mtu_drops++; +@@ -3353,8 +3532,29 @@ netdev_dpdk_set_policing(struct netdev* netdev, uint32_t policer_rate, + : !policer_burst ? 8000 + : policer_burst); + ++#if HAVE_HWOFF_AGENT ++ bool eth_flag = false; ++ hwoff_func* funcs = hwoff_get_funcs(); ++ /* This function obtains dev->mutex, which conflicts with the following open source lock obtaining. ++ * Therefore, the function needs to be split into two parts. ++ */ ++ if (funcs->hwoff_is_ethdev(netdev)) { ++ eth_flag = true; ++ } ++#endif ++ + ovs_mutex_lock(&dev->mutex); + ++#if HAVE_HWOFF_AGENT ++ if (eth_flag) { ++ if (funcs->hwoff_set_ingress_policing) { ++ funcs->hwoff_set_ingress_policing(dev->port_id, policer_rate, policer_burst); ++ } ++ ovs_mutex_unlock(&dev->mutex); ++ return 0; ++ } ++#endif ++ + policer = ovsrcu_get_protected(struct ingress_policer *, + &dev->ingress_policer); + +@@ -3629,8 +3829,13 @@ netdev_dpdk_get_status(const struct netdev *netdev, struct smap *args) + ovs_mutex_unlock(&dev->mutex); + const struct rte_bus *bus; + const struct rte_pci_device *pci_dev; ++#ifdef DPDK_2011_AND_BEFORE + uint16_t vendor_id = PCI_ANY_ID; + uint16_t device_id = PCI_ANY_ID; ++#else ++ uint16_t vendor_id = RTE_PCI_ANY_ID; ++ uint16_t device_id = RTE_PCI_ANY_ID; ++#endif + bus = rte_bus_find_by_device(dev_info.device); + if (bus && !strcmp(bus->name, "pci")) { + pci_dev = RTE_DEV_TO_PCI(dev_info.device); +@@ -3738,12 +3943,12 @@ static void + netdev_dpdk_detach(struct unixctl_conn *conn, int argc OVS_UNUSED, + const char *argv[], void *aux OVS_UNUSED) + { +- char *response; +- dpdk_port_t port_id; +- struct netdev_dpdk *dev; +- struct rte_device *rte_dev; + struct ds used_interfaces = DS_EMPTY_INITIALIZER; ++ struct rte_eth_dev_info dev_info; ++ dpdk_port_t sibling_port_id; ++ dpdk_port_t port_id; + bool used = false; ++ char *response; + + ovs_mutex_lock(&dpdk_mutex); + +@@ -3753,18 +3958,21 @@ netdev_dpdk_detach(struct unixctl_conn *conn, int argc OVS_UNUSED, + goto error; + } + +- rte_dev = rte_eth_devices[port_id].device; + ds_put_format(&used_interfaces, + "Device '%s' is being used by the following interfaces:", + argv[1]); + +- LIST_FOR_EACH (dev, list_node, &dpdk_list) { +- /* FIXME: avoid direct access to DPDK array rte_eth_devices. */ +- if (rte_eth_devices[dev->port_id].device == rte_dev +- && rte_eth_devices[dev->port_id].state != RTE_ETH_DEV_UNUSED) { ++ RTE_ETH_FOREACH_DEV_SIBLING (sibling_port_id, port_id) { ++ struct netdev_dpdk *dev; ++ ++ LIST_FOR_EACH (dev, list_node, &dpdk_list) { ++ if (dev->port_id != sibling_port_id) { ++ continue; ++ } + used = true; + ds_put_format(&used_interfaces, " %s", + netdev_get_name(&dev->up)); ++ break; + } + } + +@@ -3776,8 +3984,9 @@ netdev_dpdk_detach(struct unixctl_conn *conn, int argc OVS_UNUSED, + } + ds_destroy(&used_interfaces); + ++ rte_eth_dev_info_get(port_id, &dev_info); + rte_eth_dev_close(port_id); +- if (rte_dev_remove(rte_dev) < 0) { ++ if (rte_dev_remove(dev_info.device) < 0) { + response = xasprintf("Device '%s' can not be detached", argv[1]); + goto error; + } +@@ -4277,8 +4486,38 @@ netdev_dpdk_set_qos(struct netdev *netdev, const char *type, + struct qos_conf *qos_conf, *new_qos_conf = NULL; + int error = 0; + ++#if HAVE_HWOFF_AGENT ++ bool eth_flag = false; ++ hwoff_func* funcs = hwoff_get_funcs(); ++ /* This function obtains dev->mutex, which conflicts with the following open source lock obtaining. ++ * Therefore, the function needs to be split into two parts. ++ */ ++ if (funcs->hwoff_is_ethdev(netdev)) { ++ eth_flag = true; ++ } ++#endif ++ + ovs_mutex_lock(&dev->mutex); + ++#if HAVE_HWOFF_AGENT ++ size_t num_pairs = smap_count(details); ++ struct hwoff_key_val_node *hwoff_key_val = NULL; ++ error = hwoff_key_val_init(&hwoff_key_val, details); ++ if (error != 0){ ++ return error; ++ } ++ ++ if (eth_flag) { ++ if (funcs->hwoff_set_qos) { ++ funcs->hwoff_set_qos(dev->port_id, type, hwoff_key_val, num_pairs); ++ } ++ hwoff_key_val_destroy(hwoff_key_val, num_pairs); ++ ovs_mutex_unlock(&dev->mutex); ++ return error; ++ } ++ hwoff_key_val_destroy(hwoff_key_val, num_pairs); ++#endif ++ + qos_conf = ovsrcu_get_protected(struct qos_conf *, &dev->qos_conf); + + new_ops = qos_lookup_name(type); +@@ -4910,7 +5149,12 @@ netdev_dpdk_reconfigure(struct netdev *netdev) + && dev->rxq_size == dev->requested_rxq_size + && dev->txq_size == dev->requested_txq_size + && dev->socket_id == dev->requested_socket_id ++#ifdef HAVE_HWOFF_AGENT ++ && dev->started && !dev->reset_needed ++ && !dev->hwoff_reconfigure) { ++#else + && dev->started && !dev->reset_needed) { ++#endif + /* Reconfiguration is unnecessary */ + + goto out; +@@ -5025,7 +5269,6 @@ netdev_dpdk_vhost_client_reconfigure(struct netdev *netdev) + int err; + uint64_t vhost_flags = 0; + uint64_t vhost_unsup_flags; +- bool zc_enabled; + + ovs_mutex_lock(&dev->mutex); + +@@ -5051,19 +5294,6 @@ netdev_dpdk_vhost_client_reconfigure(struct netdev *netdev) + vhost_flags |= RTE_VHOST_USER_POSTCOPY_SUPPORT; + } + +- zc_enabled = dev->vhost_driver_flags +- & RTE_VHOST_USER_DEQUEUE_ZERO_COPY; +- /* Enable zero copy flag, if requested */ +- if (zc_enabled) { +- vhost_flags |= RTE_VHOST_USER_DEQUEUE_ZERO_COPY; +- /* DPDK vHost library doesn't allow zero-copy with linear buffers. +- * Hence disable Linear buffer. +- */ +- vhost_flags &= ~RTE_VHOST_USER_LINEARBUF_SUPPORT; +- VLOG_WARN("Zero copy enabled, disabling linear buffer" +- " check for vHost port %s", dev->up.name); +- } +- + /* Enable External Buffers if TCP Segmentation Offload is enabled. */ + if (userspace_tso_enabled()) { + vhost_flags |= RTE_VHOST_USER_EXTBUF_SUPPORT; +@@ -5080,11 +5310,6 @@ netdev_dpdk_vhost_client_reconfigure(struct netdev *netdev) + VLOG_INFO("vHost User device '%s' created in 'client' mode, " + "using client socket '%s'", + dev->up.name, dev->vhost_id); +- if (zc_enabled) { +- VLOG_INFO("Zero copy enabled for vHost port %s", dev->up.name); +- VLOG_WARN("Zero copy support is deprecated and will be " +- "removed in the next OVS release."); +- } + } + + err = rte_vhost_driver_callback_register(dev->vhost_id, +@@ -5145,9 +5370,7 @@ netdev_dpdk_get_port_id(struct netdev *netdev) + } + + dev = netdev_dpdk_cast(netdev); +- ovs_mutex_lock(&dev->mutex); + ret = dev->port_id; +- ovs_mutex_unlock(&dev->mutex); + out: + return ret; + } +@@ -5162,6 +5385,14 @@ netdev_dpdk_flow_api_supported(struct netdev *netdev) + goto out; + } + ++#ifdef HAVE_HWOFF_AGENT ++ hwoff_func* funcs = hwoff_get_funcs(); ++ bool flag = funcs->hwoff_is_ethdev(netdev); ++ if (flag == true) { ++ return false; ++ } ++#endif ++ + dev = netdev_dpdk_cast(netdev); + ovs_mutex_lock(&dev->mutex); + if (dev->type == DPDK_DEV_ETH) { +@@ -5181,9 +5412,7 @@ netdev_dpdk_rte_flow_destroy(struct netdev *netdev, + struct netdev_dpdk *dev = netdev_dpdk_cast(netdev); + int ret; + +- ovs_mutex_lock(&dev->mutex); + ret = rte_flow_destroy(dev->port_id, rte_flow, error); +- ovs_mutex_unlock(&dev->mutex); + return ret; + } + +@@ -5197,9 +5426,7 @@ netdev_dpdk_rte_flow_create(struct netdev *netdev, + struct rte_flow *flow; + struct netdev_dpdk *dev = netdev_dpdk_cast(netdev); + +- ovs_mutex_lock(&dev->mutex); + flow = rte_flow_create(dev->port_id, attr, items, actions, error); +- ovs_mutex_unlock(&dev->mutex); + return flow; + } + +@@ -5209,7 +5436,7 @@ netdev_dpdk_rte_flow_query_count(struct netdev *netdev, + struct rte_flow_query_count *query, + struct rte_flow_error *error) + { +- struct rte_flow_action_count count = { .shared = 0, .id = 0 }; ++ struct rte_flow_action_count count = { .id = 0, }; + const struct rte_flow_action actions[] = { + { + .type = RTE_FLOW_ACTION_TYPE_COUNT, +@@ -5227,9 +5454,7 @@ netdev_dpdk_rte_flow_query_count(struct netdev *netdev, + } + + dev = netdev_dpdk_cast(netdev); +- ovs_mutex_lock(&dev->mutex); + ret = rte_flow_query(dev->port_id, rte_flow, actions, query, error); +- ovs_mutex_unlock(&dev->mutex); + return ret; + } + +diff --git a/openvswitch-2.14.2/lib/netdev-dpdk.h b/openvswitch-2.14.2/lib/netdev-dpdk.h +index 848346c..6853aeb 100644 +--- a/openvswitch-2.14.2/lib/netdev-dpdk.h ++++ b/openvswitch-2.14.2/lib/netdev-dpdk.h +@@ -20,6 +20,9 @@ + #include + + #include "openvswitch/compiler.h" ++#ifdef HAVE_HWOFF_AGENT ++#include ++#endif + + struct dp_packet; + struct netdev; +@@ -56,6 +59,14 @@ netdev_dpdk_rte_flow_query_count(struct netdev *netdev, + int + netdev_dpdk_get_port_id(struct netdev *netdev); + ++#ifdef HAVE_HWOFF_AGENT ++int ++hwoff_netdev_name_get(uint16_t port_id, char name_buffer[], int buffer_size); ++ ++bool ++hwoff_netdev_is_shared(struct netdev *dev); ++#endif ++ + #else + + static inline void +diff --git a/openvswitch-2.14.2/lib/netdev-native-tnl.c b/openvswitch-2.14.2/lib/netdev-native-tnl.c +index b89dfdd..0b3a745 100644 +--- a/openvswitch-2.14.2/lib/netdev-native-tnl.c ++++ b/openvswitch-2.14.2/lib/netdev-native-tnl.c +@@ -44,6 +44,9 @@ + #include "unaligned.h" + #include "unixctl.h" + #include "openvswitch/vlog.h" ++#ifdef HAVE_HWOFF_AGENT ++#include "hwoff_init_func.h" ++#endif + + VLOG_DEFINE_THIS_MODULE(native_tnl); + static struct vlog_rate_limit err_rl = VLOG_RATE_LIMIT_INIT(60, 5); +@@ -248,7 +251,16 @@ netdev_tnl_push_udp_header(const struct netdev *netdev OVS_UNUSED, + udp = netdev_tnl_push_ip_header(packet, data->header, data->header_len, &ip_tot_size); + + /* set udp src port */ ++#ifdef HAVE_HWOFF_AGENT ++ hwoff_func* funcs = hwoff_get_funcs(); ++ if (funcs->hwoff_tnl_get_src_port) { ++ udp->udp_src = funcs->hwoff_tnl_get_src_port(packet); ++ } else { ++ udp->udp_src = netdev_tnl_get_src_port(packet); ++ } ++#else + udp->udp_src = netdev_tnl_get_src_port(packet); ++#endif + udp->udp_len = htons(ip_tot_size); + + if (udp->udp_csum) { +diff --git a/openvswitch-2.14.2/lib/netdev-offload-dpdk.c b/openvswitch-2.14.2/lib/netdev-offload-dpdk.c +index 17b08ca..1b9d305 100644 +--- a/openvswitch-2.14.2/lib/netdev-offload-dpdk.c ++++ b/openvswitch-2.14.2/lib/netdev-offload-dpdk.c +@@ -28,6 +28,11 @@ + #include "openvswitch/vlog.h" + #include "packets.h" + #include "uuid.h" ++#ifdef HAVE_HWOFF_AGENT ++#include "odp-util.h" ++#include "unixctl.h" ++#include "hwoff_init_func.h" ++#endif + + VLOG_DEFINE_THIS_MODULE(netdev_offload_dpdk); + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(100, 5); +@@ -58,6 +63,7 @@ struct ufid_to_rte_flow_data { + struct cmap_node node; + ovs_u128 ufid; + struct rte_flow *rte_flow; ++ int ref_cnt; + bool actions_offloaded; + struct dpif_flow_stats stats; + }; +@@ -1018,6 +1024,7 @@ add_port_id_action(struct flow_actions *actions, + int outdev_id; + + outdev_id = netdev_dpdk_get_port_id(outdev); ++ + if (outdev_id < 0) { + return -1; + } +@@ -1030,14 +1037,19 @@ add_port_id_action(struct flow_actions *actions, + static int + add_output_action(struct netdev *netdev, + struct flow_actions *actions, +- const struct nlattr *nla) ++ const struct nlattr *nla, ++ void *pmd) + { + struct netdev *outdev; + odp_port_t port; + int ret = 0; + + port = nl_attr_get_odp_port(nla); +- outdev = netdev_ports_get(port, netdev->dpif_type); ++ if (pmd) { ++ outdev = dp_get_outdev_from_pmd(port, pmd); ++ } else { ++ outdev = netdev_ports_get(port, netdev->dpif_type); ++ } + if (outdev == NULL) { + VLOG_DBG_RL(&rl, "Cannot find netdev for odp port %"PRIu32, port); + return -1; +@@ -1048,7 +1060,10 @@ add_output_action(struct netdev *netdev, + netdev_get_name(netdev), netdev_get_name(outdev)); + ret = -1; + } +- netdev_close(outdev); ++ ++ if (pmd == NULL) { ++ netdev_close(outdev); ++ } + return ret; + } + +@@ -1076,10 +1091,12 @@ add_set_flow_action__(struct flow_actions *actions, + memcpy(spec, value, size); + add_flow_action(actions, attr, spec); + ++#ifndef HAVE_HWOFF_AGENT + /* Clear used mask for later checking. */ + if (mask) { + memset(mask, 0, size); + } ++#endif + return 0; + } + +@@ -1108,6 +1125,104 @@ BUILD_ASSERT_DECL(sizeof(struct rte_flow_action_set_tp) == + BUILD_ASSERT_DECL(sizeof(struct rte_flow_action_set_tp) == + MEMBER_SIZEOF(struct ovs_key_udp, udp_dst)); + ++#ifdef HAVE_HWOFF_AGENT ++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; ++ ++#define add_set_flow_action(field, type) \ ++ if (add_set_flow_action__(actions, &key->field, \ ++ mask ? CONST_CAST(void *, &mask->field) : NULL, \ ++ sizeof key->field, type)) { \ ++ return -1; \ ++ } ++ ++ 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 ? key + 1 : NULL; ++ ++ add_set_flow_action(eth_src, RTE_FLOW_ACTION_TYPE_SET_MAC_SRC); ++ add_set_flow_action(eth_dst, RTE_FLOW_ACTION_TYPE_SET_MAC_DST); ++ } 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 ? key + 1 : NULL; ++ ++ add_set_flow_action(ipv4_src, RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC); ++ add_set_flow_action(ipv4_dst, RTE_FLOW_ACTION_TYPE_SET_IPV4_DST); ++ add_set_flow_action(ipv4_ttl, RTE_FLOW_ACTION_TYPE_SET_TTL); ++ } else if (nl_attr_type(sa) == OVS_KEY_ATTR_IPV6) { ++ const struct ovs_key_ipv6 *key = nl_attr_get(sa); ++ const struct ovs_key_ipv6 *mask = masked ? key + 1 : NULL; ++ ++ add_set_flow_action(ipv6_src, RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC); ++ add_set_flow_action(ipv6_dst, RTE_FLOW_ACTION_TYPE_SET_IPV6_DST); ++ add_set_flow_action(ipv6_hlimit, RTE_FLOW_ACTION_TYPE_SET_TTL); ++ } 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 ? key + 1 : NULL; ++ ++ add_set_flow_action(tcp_src, RTE_FLOW_ACTION_TYPE_SET_TP_SRC); ++ add_set_flow_action(tcp_dst, RTE_FLOW_ACTION_TYPE_SET_TP_DST); ++ } 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 ? key + 1 : NULL; ++ ++ add_set_flow_action(udp_src, RTE_FLOW_ACTION_TYPE_SET_TP_SRC); ++ add_set_flow_action(udp_dst, RTE_FLOW_ACTION_TYPE_SET_TP_DST); ++ } else { ++ VLOG_DBG_RL(&rl, ++ "Unsupported set action type %d", nl_attr_type(sa)); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++static void add_vlan_to_vxlan_action(const struct nlattr *ca, struct flow_actions *actions) ++{ ++ struct rte_flow_action *real_actions = actions->actions; ++ struct rte_flow_action *one_act = NULL; ++ struct rte_flow_action *dst_act = NULL; ++ ++ one_act = real_actions; ++ while (one_act && (one_act->type != RTE_FLOW_ACTION_TYPE_END)) { ++ if (one_act->type != RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP) { ++ one_act = one_act + 1; ++ continue; ++ } ++ ++ dst_act = one_act; ++ break; ++ } ++ ++ if (dst_act == NULL) { ++ return; ++ } ++ ++ struct rte_flow_action_vxlan_encap *vxlan_info = (struct rte_flow_action_vxlan_encap *)dst_act->conf; ++ struct rte_flow_item *item = vxlan_info->definition; ++ ++ while (item->type != RTE_FLOW_ITEM_TYPE_END) { ++ item = item + 1; ++ } ++ ++ item->type = RTE_FLOW_ITEM_TYPE_VLAN; ++ const struct ovs_action_push_vlan *vlan_push = nl_attr_get(ca); ++ item->spec = &vlan_push->vlan_tci; ++ item->mask = NULL; ++ ++ item = item + 1; ++ item->type = RTE_FLOW_ITEM_TYPE_END; ++ return; ++} ++#else + static int + parse_set_actions(struct flow_actions *actions, + const struct nlattr *set_actions, +@@ -1191,11 +1306,12 @@ parse_set_actions(struct flow_actions *actions, + + return 0; + } ++#endif + + /* Maximum number of items in struct rte_flow_action_vxlan_encap. +- * ETH / IPv4(6) / UDP / VXLAN / END ++ * ETH / IPv4(6) / UDP / VXLAN / vlan /END + */ +-#define ACTION_VXLAN_ENCAP_ITEMS_NUM 5 ++#define ACTION_VXLAN_ENCAP_ITEMS_NUM 6 + + static int + add_vxlan_encap_action(struct flow_actions *actions, +@@ -1305,7 +1421,8 @@ static int + parse_clone_actions(struct netdev *netdev, + struct flow_actions *actions, + const struct nlattr *clone_actions, +- const size_t clone_actions_len) ++ const size_t clone_actions_len, ++ void *pmd) + { + const struct nlattr *ca; + unsigned int cleft; +@@ -1330,9 +1447,13 @@ parse_clone_actions(struct netdev *netdev, + add_flow_action(actions, RTE_FLOW_ACTION_TYPE_RAW_ENCAP, + raw_encap); + } else if (clone_type == OVS_ACTION_ATTR_OUTPUT) { +- if (add_output_action(netdev, actions, ca)) { ++ if (add_output_action(netdev, actions, ca, pmd)) { + return -1; + } ++#ifdef HAVE_HWOFF_AGENT ++ } else if (clone_type == OVS_ACTION_ATTR_PUSH_VLAN) { ++ add_vlan_to_vxlan_action(ca, actions); ++#endif + } else { + VLOG_DBG_RL(&rl, + "Unsupported nested action inside clone(), " +@@ -1347,19 +1468,29 @@ static int + parse_flow_actions(struct netdev *netdev, + struct flow_actions *actions, + struct nlattr *nl_actions, +- size_t nl_actions_len) ++ size_t nl_actions_len, ++ void *pmd) + { ++ bool have_hard_output = false; + struct nlattr *nla; + size_t left; + + add_count_action(actions); + NL_ATTR_FOR_EACH_UNSAFE (nla, left, nl_actions, nl_actions_len) { + if (nl_attr_type(nla) == OVS_ACTION_ATTR_OUTPUT) { +- if (add_output_action(netdev, actions, nla)) { +- return -1; ++ if (add_output_action(netdev, actions, nla, pmd)) { ++ /* to support vxlan and set action both modify ++ * set action will output tap port which don't supoort offload, ++ * then return -1. ++ * continue to use vxlan output port. ++ */ ++ continue; ++ } else { ++ have_hard_output = true; + } + } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_DROP) { + add_flow_action(actions, RTE_FLOW_ACTION_TYPE_DROP, NULL); ++ have_hard_output = true; + } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_SET || + nl_attr_type(nla) == OVS_ACTION_ATTR_SET_MASKED) { + const struct nlattr *set_actions = nl_attr_get(nla); +@@ -1378,14 +1509,41 @@ parse_flow_actions(struct netdev *netdev, + } + } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_POP_VLAN) { + add_flow_action(actions, RTE_FLOW_ACTION_TYPE_OF_POP_VLAN, NULL); ++#ifdef HAVE_HWOFF_AGENT ++ } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_TUNNEL_POP) { ++ odp_port_t port = nl_attr_get_odp_port(nla); ++ struct netdev *vport = netdev_ports_get(port, netdev->dpif_type); ++ if (!vport) { ++ continue; ++ } ++ if (!strcmp(netdev_get_type(vport), "vxlan")) { ++ /* if exists tunnel_pop action, it should be the first action */ ++ free_flow_actions(actions); ++ add_flow_action(actions, RTE_FLOW_ACTION_TYPE_VXLAN_DECAP, NULL); ++ } ++ netdev_close(vport); ++ have_hard_output = true; ++ } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_METER) { ++ struct rte_flow_action_meter *mtr = xzalloc(sizeof *mtr); ++ mtr->mtr_id = nl_attr_get_u32(nla); ++ add_flow_action(actions, RTE_FLOW_ACTION_TYPE_METER, mtr); ++ } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_RECIRC) { ++ } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_CT) { ++ } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_CLONE) { ++/* if there is multi output, clone will not be the last atcion, so left would be longer than nla->nla_len, ++ we let it go here, offload will fail in agent because multi output. ++*/ ++#else + } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_CLONE && + left <= NLA_ALIGN(nla->nla_len)) { ++#endif + const struct nlattr *clone_actions = nl_attr_get(nla); + size_t clone_actions_len = nl_attr_get_size(nla); +- + if (parse_clone_actions(netdev, actions, clone_actions, +- clone_actions_len)) { ++ clone_actions_len, pmd)) { + return -1; ++ } else { ++ have_hard_output = true; + } + } else { + VLOG_DBG_RL(&rl, "Unsupported action type %d", nl_attr_type(nla)); +@@ -1398,6 +1556,9 @@ parse_flow_actions(struct netdev *netdev, + return -1; + } + ++#ifdef HAVE_HWOFF_AGENT ++ have_hard_output = have_hard_output; ++#endif + add_flow_action(actions, RTE_FLOW_ACTION_TYPE_END, NULL); + return 0; + } +@@ -1414,7 +1575,7 @@ netdev_offload_dpdk_actions(struct netdev *netdev, + struct rte_flow_error error; + int ret; + +- ret = parse_flow_actions(netdev, &actions, nl_actions, actions_len); ++ ret = parse_flow_actions(netdev, &actions, nl_actions, actions_len, NULL); + if (ret) { + goto out; + } +@@ -1609,3 +1770,538 @@ const struct netdev_flow_api netdev_offload_dpdk = { + .init_flow_api = netdev_offload_dpdk_init_flow_api, + .flow_get = netdev_offload_dpdk_flow_get, + }; ++ ++#ifdef HAVE_HWOFF_AGENT ++#define HWOFF_OFFLOAD_INFO_NUM 10 ++#define HIOVS_RTE_FLOW_BATCH_SIZE 16 ++static struct cmap hiovs_ufid_rte_flow_map = CMAP_INITIALIZER; ++static struct ovs_mutex hiovs_map_lock = OVS_MUTEX_INITIALIZER; ++ ++static void hiovs_rte_flow_map_lock(void) ++{ ++ ovs_mutex_lock(&hiovs_map_lock); ++} ++ ++static void hiovs_rte_flow_map_unlock(void) ++{ ++ ovs_mutex_unlock(&hiovs_map_lock); ++} ++ ++static void free_no_copy_flow_patterns(struct flow_patterns *patterns) ++{ ++ free(patterns->items); ++ patterns->items = NULL; ++ patterns->cnt = 0; ++} ++ ++static void hiovs_rte_flow_data_dealloc(struct ufid_to_rte_flow_data *flow_data) ++{ ++ free(flow_data); ++} ++ ++static struct ufid_to_rte_flow_data* hiovs_rte_flow_data_alloc(const ovs_u128 *ufid) ++{ ++ struct ufid_to_rte_flow_data *flow_data = NULL; ++ ++ flow_data = (struct ufid_to_rte_flow_data *)malloc(sizeof(*flow_data)); ++ if (flow_data == NULL) { ++ return NULL; ++ } ++ ++ (void)memset(flow_data, 0, sizeof(struct ufid_to_rte_flow_data)); ++ ++ flow_data->ufid = *ufid; ++ flow_data->actions_offloaded = false; ++ flow_data->ref_cnt = 1; ++ return flow_data; ++} ++ ++static struct ufid_to_rte_flow_data* hiovs_rte_flow_data_add(const ovs_u128 *ufid) ++{ ++ size_t hash; ++ struct ufid_to_rte_flow_data *flow_data = NULL; ++ flow_data = hiovs_rte_flow_data_alloc(ufid); ++ if (flow_data == NULL) { ++ VLOG_ERR("hiovs_rte_flow_data_alloc fail, ufid="UUID_FMT, UUID_ARGS((struct uuid *)ufid)); ++ return NULL; ++ } ++ hash = hash_bytes(&flow_data->ufid, sizeof(ovs_u128), 0); ++ cmap_insert(&hiovs_ufid_rte_flow_map, &flow_data->node, hash); ++ return flow_data; ++} ++static struct ufid_to_rte_flow_data* hiovs_rte_flow_data_find(const ovs_u128 *ufid) ++{ ++ struct ufid_to_rte_flow_data *flow_data = NULL; ++ size_t hash = hash_bytes(ufid, sizeof *ufid, 0); ++ ++ CMAP_FOR_EACH_WITH_HASH (flow_data, node, hash, &hiovs_ufid_rte_flow_map) { ++ if (ovs_u128_equals(*ufid, flow_data->ufid)) { ++ return flow_data; ++ } ++ } ++ ++ return NULL; ++} ++ ++static struct ufid_to_rte_flow_data* hiovs_rte_flow_data_get(const ovs_u128 *ufid) ++{ ++ struct ufid_to_rte_flow_data *flow_data = NULL; ++ ++ hiovs_rte_flow_map_lock(); ++ flow_data = hiovs_rte_flow_data_find(ufid); ++ if (flow_data == NULL) { ++ hiovs_rte_flow_map_unlock(); ++ ++ return NULL; ++ } ++ ++ flow_data->ref_cnt++; ++ hiovs_rte_flow_map_unlock(); ++ return flow_data; ++} ++ ++static void hiovs_rte_flow_data_close(struct ufid_to_rte_flow_data *flow_data) ++{ ++ hiovs_rte_flow_map_lock(); ++ flow_data->ref_cnt--; ++ if (flow_data->ref_cnt <= 0) { ++ hiovs_rte_flow_data_dealloc(flow_data); ++ } ++ hiovs_rte_flow_map_unlock(); ++} ++ ++uint32_t hiovs_rte_flow_list_get(ovs_u128 ufid_list[], struct rte_flow *flow_list[], uint32_t ufid_cnt) ++{ ++ int i; ++ ovs_u128 *one_ufid = NULL; ++ struct ufid_to_rte_flow_data *flow_data_list[HIOVS_RTE_FLOW_BATCH_SIZE]; ++ struct ufid_to_rte_flow_data *flow_data = NULL; ++ ++ if (ufid_cnt > HIOVS_RTE_FLOW_BATCH_SIZE) { ++ return -1; ++ } ++ ++ hiovs_rte_flow_map_lock(); ++ for (i = 0; i < ufid_cnt; i++) { ++ one_ufid = &ufid_list[i]; ++ flow_data = hiovs_rte_flow_data_find(one_ufid); ++ if (!flow_data) { ++ break; ++ } ++ ++ flow_data_list[i] = flow_data; ++ flow_list[i] = flow_data->rte_flow; ++ } ++ ++ if (i != ufid_cnt) { ++ hiovs_rte_flow_map_unlock(); ++ return -1; ++ } ++ ++ for (i = 0; i < ufid_cnt; i++) { ++ flow_data_list[i]->ref_cnt++; ++ } ++ ++ hiovs_rte_flow_map_unlock(); ++ return 0; ++} ++static struct ufid_to_rte_flow_data* hiovs_rte_flow_data_process(const ovs_u128 *ufid, void *flow) ++{ ++ bool is_dead = false; ++ struct ufid_to_rte_flow_data *flow_data = NULL; ++ hiovs_rte_flow_map_lock(); ++ is_dead = dp_netdev_flow_dead_status_get(flow); ++ if (is_dead == true) { ++ hiovs_rte_flow_map_unlock(); ++ return NULL; ++ } ++ flow_data = hiovs_rte_flow_data_find(ufid); ++ if (flow_data != NULL) { ++ flow_data->ref_cnt++; ++ hiovs_rte_flow_map_unlock(); ++ return flow_data; ++ } ++ flow_data = hiovs_rte_flow_data_add(ufid); ++ if (flow_data == NULL) { ++ hiovs_rte_flow_map_unlock(); ++ return NULL; ++ } ++ flow_data->ref_cnt++; ++ hiovs_rte_flow_map_unlock(); ++ return flow_data; ++} ++ ++void hiovs_rte_flow_data_list_put(void *flow_data_list[], uint32_t count) ++{ ++ int i; ++ struct ufid_to_rte_flow_data *flow_data = NULL; ++ ++ hiovs_rte_flow_map_lock(); ++ for (i = 0; i < count; i++) { ++ flow_data = (struct ufid_to_rte_flow_data *)(flow_data_list[i]); ++ flow_data->ref_cnt--; ++ if (flow_data->ref_cnt <= 0) { ++ hiovs_rte_flow_data_dealloc(flow_data); ++ } ++ } ++ hiovs_rte_flow_map_unlock(); ++} ++ ++static void hiovs_offload_info_parse(struct hwoff_key_val_node *offload_node, ++ struct offload_info *info, ++ const ovs_u128 *sw_ufid) ++{ ++ offload_node[0].type = HWOFF_OVS_INPUT_KEY_PMD_IDX; ++ offload_node[0].value = (char*)&info->pmd_core_id; ++ ++ offload_node[1].type = HWOFF_OVS_INPUT_KEY_PORT_ID; ++ offload_node[1].value = (char*)&info->in_port_id; ++ ++ offload_node[2].type = HWOFF_OVS_INPUT_KEY_PORT_TYPE; ++ offload_node[2].value = (char*)&info->in_port_type; ++ ++ offload_node[3].type = HWOFF_OVS_INPUT_KET_PACKET_BACTH; ++ offload_node[3].value = (char*)info->pkts_info; ++ ++ offload_node[4].type = HWOFF_OVS_INPUT_KEY_MEGA_UFID; ++ offload_node[4].value = (char *)sw_ufid; ++ return; ++} ++ ++static int hiovs_offload_flow_get_exec(struct netdev *netdev, struct rte_flow *rte_flow, ++ struct rte_flow_query_count *query, struct rte_flow_error *error) ++{ ++ int ret = 0; ++ bool flag = false; ++ hwoff_func* funcs = hwoff_get_funcs(); ++ ++ flag = funcs->hwoff_is_support_offload(netdev); ++ if (flag == true) { ++ ret = funcs->hwoff_ovs_flow_query(netdev, rte_flow, query, error); ++ return ret; ++ } ++ return ret; ++} ++ ++static int hiovs_offload_flow_del_exec(struct netdev *netdev, struct rte_flow *rte_flow, struct rte_flow_error *error) ++{ ++ if (rte_flow == NULL) { ++ return 0; ++ } ++ ++ int ret = 0; ++ bool flag = false; ++ hwoff_func* funcs = hwoff_get_funcs(); ++ flag = funcs->hwoff_is_support_offload(netdev); ++ if (flag == true) { ++ ret = funcs->hwoff_ovs_flow_destroy(netdev, rte_flow, error); ++ return ret; ++ } ++ ++ return ret; ++} ++ ++static struct rte_flow* hiovs_offload_flow_add_exec(struct netdev *netdev, ++ struct hwoff_key_val_node *offload_info, ++ uint8_t info_size, ++ struct rte_flow_action *mega_action, ++ struct rte_flow_error *error) ++{ ++ bool flag = false; ++ struct rte_flow *flow = NULL; ++ hwoff_func* funcs = hwoff_get_funcs(); ++ ++ flag = funcs->hwoff_is_support_offload(netdev); ++ if (flag == true) { ++ flow = funcs->hwoff_ovs_flow_create(netdev, offload_info, info_size, mega_action, error); ++ return flow; ++ } ++ ++ return flow; ++} ++ ++static void hwoff_offload_packet_is_recirc(struct flow_actions *actions, bool *is_recirc, bool *is_ct, ++ struct nlattr *nl_actions, size_t nl_actions_len) ++{ ++ struct nlattr *nla; ++ size_t left; ++ ++ add_count_action(actions); ++ NL_ATTR_FOR_EACH_UNSAFE (nla, left, nl_actions, nl_actions_len) { ++ if (nl_attr_type(nla) == OVS_ACTION_ATTR_CT) { ++ *is_ct = true; ++ continue; ++ } ++ ++ if (nl_attr_type(nla) == OVS_ACTION_ATTR_RECIRC) { ++ *is_recirc = true; ++ continue; ++ } ++ ++ 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); ++ 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_CT) { ++ *is_ct = true; ++ continue; ++ } ++ if (clone_type == OVS_ACTION_ATTR_RECIRC) { ++ *is_recirc = true; ++ continue; ++ } ++ } ++ } ++ } ++ ++ for (int i = 0; i < actions->cnt; ++i) { ++ if (actions->actions[i].type == RTE_FLOW_ACTION_TYPE_VXLAN_DECAP) { ++ *is_recirc = true; ++ return; ++ } ++ ++ if (actions->actions[i].type == RTE_FLOW_ACTION_TYPE_END) { ++ break; ++ } ++ } ++ ++ return; ++} ++ ++static int hiovs_offload_flow_add(struct netdev *netdev, ++ struct ufid_to_rte_flow_data *flow_data, ++ struct nlattr *nl_actions, ++ size_t actions_len, ++ struct offload_info *info) ++{ ++ int ret; ++ struct rte_flow *flow = NULL; ++ struct rte_flow_error error; ++ struct flow_actions actions = { .actions = NULL, .cnt = 0 }; ++ struct flow_patterns patterns = { .items = NULL, .cnt = 0 }; ++ ++ struct hwoff_key_val_node hwoff_offload_info[HWOFF_OFFLOAD_INFO_NUM] = {0}; ++ bool is_recirc = false; ++ bool is_ct = false; ++ ++ ++ hiovs_offload_info_parse(hwoff_offload_info, info, &flow_data->ufid); ++ ret = parse_flow_actions(netdev, &actions, nl_actions, actions_len, info->pmd); ++ if (ret != 0) { ++ goto out; ++ } ++ ++ hwoff_offload_packet_is_recirc(&actions, &is_recirc, &is_ct, nl_actions, actions_len); ++ if (is_recirc) { ++ hwoff_offload_info[5].type = HWOFF_OVS_INPUT_KEY_NEED_REIRC; ++ } ++ if (is_ct) { ++ hwoff_offload_info[6].type = HWOFF_OVS_INPUT_KEY_IS_CT; ++ } ++ ++ if (flow_data->rte_flow != NULL) { ++ hwoff_offload_info[7].type = HWOFF_OVS_MEGA_FLOW; ++ hwoff_offload_info[7].value = (char *)flow_data->rte_flow; ++ } ++ ++ memset(&error, 0, sizeof(error)); ++ flow = hiovs_offload_flow_add_exec(netdev, hwoff_offload_info, HWOFF_OFFLOAD_INFO_NUM, actions.actions, &error); ++ if (flow == NULL) { ++ ret = -1; ++ goto out; ++ } ++ ++ if (flow_data->rte_flow == NULL) { ++ flow_data->rte_flow = flow; ++ } ++ ++ flow_data->actions_offloaded = true; ++ ret = 0; ++out: ++ free_no_copy_flow_patterns(&patterns); ++ free_flow_actions(&actions); ++ return ret; ++} ++ ++int hiovs_offload_flow_api_del(struct netdev *netdev, const ovs_u128 *ufid, struct dpif_flow_stats *stats) ++{ ++ int ret; ++ struct rte_flow_error error; ++ struct ufid_to_rte_flow_data *flow_data; ++ struct hwoff_flow_node *flow_node = NULL; ++ struct hwoff_flow_node *next_flow_node = NULL; ++ ++ size_t hash; ++ ++ hiovs_rte_flow_map_lock(); ++ flow_data = hiovs_rte_flow_data_find(ufid); ++ if (flow_data == NULL) { ++ hiovs_rte_flow_map_unlock(); ++ return 0; ++ } ++ ++ ret = hiovs_offload_flow_del_exec(netdev, flow_data->rte_flow, &error); ++ if (ret != 0) { ++ hiovs_rte_flow_map_unlock(); ++ return ret; ++ } ++ hash = hash_bytes(&flow_data->ufid, sizeof(ovs_u128), 0); ++ ++ cmap_remove(&hiovs_ufid_rte_flow_map, &flow_data->node, hash); ++ flow_data->ref_cnt--; ++ if (flow_data->ref_cnt <= 0) { ++ hiovs_rte_flow_data_dealloc(flow_data); ++ } ++ ++ hiovs_rte_flow_map_unlock(); ++ if (stats) { ++ memset(stats, 0, sizeof *stats); ++ } ++ return ret; ++} ++ ++static int hiovs_offload_flow_api_put(struct netdev *netdev, struct match *match OVS_UNUSED, ++ struct nlattr *actions, size_t actions_len, ++ const ovs_u128 *ufid, struct offload_info *info, ++ struct dpif_flow_stats *stats) ++{ ++ int ret; ++ struct ufid_to_rte_flow_data *flow_data = NULL; ++ ++ /* When modification is true, we just destroy rte_flow. */ ++ if (info->modification) { ++ ret = hiovs_offload_flow_api_del(netdev, ufid, stats); ++ return ret; ++ } ++ flow_data = hiovs_rte_flow_data_process(ufid, info->flow); ++ if (flow_data == NULL) { ++ return -1; ++ } ++ ++ if (info->in_port_type == HWOFF_PORT_TYPE_HIOVS) { ++ info->in_port_id = netdev_dpdk_get_port_id(netdev); ++ } else { ++ info->in_port_id = 0; ++ } ++ ++ ret = hiovs_offload_flow_add(netdev, flow_data, actions, actions_len, info); ++ if (ret != 0) { ++ hiovs_rte_flow_data_close(flow_data); ++ return ret; ++ } ++ ++ if (stats) { ++ *stats = flow_data->stats; ++ } ++ hiovs_rte_flow_data_close(flow_data); ++ return 0; ++} ++ ++static int hiovs_offload_flow_api_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, ++ struct ofpbuf *buf OVS_UNUSED) ++{ ++ int ret = 0; ++ struct rte_flow_query_count query = { .reset = 1 }; ++ struct ufid_to_rte_flow_data *flow_data = NULL; ++ struct rte_flow_error error; ++ ++ flow_data = hiovs_rte_flow_data_get(ufid); ++ if (flow_data == NULL) { ++ attrs->dp_extra_info = NULL; ++ return -1; ++ } ++ ++ attrs->offloaded = true; ++ if (flow_data->actions_offloaded == false) { ++ attrs->dp_layer = "ovs"; ++ memset(stats, 0, sizeof *stats); ++ goto out; ++ } ++ ++ attrs->dp_layer = "dpdk"; ++ if (flow_data->rte_flow != NULL) { ++ ret = hiovs_offload_flow_get_exec(netdev, flow_data->rte_flow, &query, &error); ++ if (ret) { ++ VLOG_DBG_RL(&rl, "%s: Failed to query ufid "UUID_FMT" flow: %p", ++ netdev_get_name(netdev), UUID_ARGS((struct uuid *) ufid), flow_data->rte_flow); ++ goto out; ++ } ++ } ++ ++ flow_data->stats.n_packets += query.hits; ++ flow_data->stats.n_bytes += query.bytes; ++ if (query.hits_set && query.hits) { ++ flow_data->stats.used = time_msec(); ++ } ++ memcpy(stats, &flow_data->stats, sizeof *stats); ++out: ++ hiovs_rte_flow_data_close(flow_data); ++ attrs->dp_extra_info = NULL; ++ return ret; ++} ++ ++static int hiovs_offload_flow_api_init(struct netdev *netdev) ++{ ++ bool flag = false; ++ hwoff_func* funcs = hwoff_get_funcs(); ++ ++ if (strcmp(netdev->netdev_class->type, "vxlan") == 0) { ++ return 0; ++ } ++ ++ if (strcmp(netdev->netdev_class->type, "tap") == 0) { ++ return 0; ++ } ++ ++ flag = funcs->hwoff_is_ethdev(netdev); ++ if (flag == true) { ++ return 0; ++ } ++ ++ return -1; ++} ++ ++static void hiovs_offload_dump_rte_flows(struct unixctl_conn *conn, int argc OVS_UNUSED, ++ const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED) ++{ ++ int count = 0; ++ struct ds ds = DS_EMPTY_INITIALIZER; ++ struct cmap_cursor cursor; ++ struct ufid_to_rte_flow_data *flow_data = NULL; ++ ++ hiovs_rte_flow_map_lock(); ++ CMAP_CURSOR_FOR_EACH(flow_data, node, &cursor, &hiovs_ufid_rte_flow_map) { ++ odp_format_ufid(&flow_data->ufid, &ds); ++ ds_put_format(&ds, "ref_cnt=%d\n", flow_data->ref_cnt); ++ count++; ++ } ++ hiovs_rte_flow_map_unlock(); ++ ds_put_format(&ds, "rte_flow_count=%d\n", count); ++ unixctl_command_reply(conn, ds_cstr(&ds)); ++ ds_destroy(&ds); ++ return; ++} ++ ++int hiovs_netdev_offload_init(void) ++{ ++ ovs_mutex_init(&hiovs_map_lock); ++ unixctl_command_register("hwoff/dump-rte-flows", "", 0, 0, hiovs_offload_dump_rte_flows, NULL); ++ return 0; ++} ++ ++const struct netdev_flow_api hiovs_netdev_offload_api = { ++ .type = "hiovs_netdev_offload_api", ++ .flow_put = hiovs_offload_flow_api_put, ++ .flow_del = hiovs_offload_flow_api_del, ++ .init_flow_api = hiovs_offload_flow_api_init, ++ .flow_get = hiovs_offload_flow_api_get, ++}; ++#endif +\ No newline at end of file +diff --git a/openvswitch-2.14.2/lib/netdev-offload-provider.h b/openvswitch-2.14.2/lib/netdev-offload-provider.h +index 0bed7bf..83f393d 100644 +--- a/openvswitch-2.14.2/lib/netdev-offload-provider.h ++++ b/openvswitch-2.14.2/lib/netdev-offload-provider.h +@@ -100,6 +100,13 @@ extern const struct netdev_flow_api netdev_offload_tc; + extern const struct netdev_flow_api netdev_offload_dpdk; + #endif + ++#ifdef HAVE_HWOFF_AGENT ++extern const struct netdev_flow_api hiovs_netdev_offload_api; ++int hiovs_netdev_offload_init(void); ++uint32_t hiovs_rte_flow_list_get(ovs_u128 *ufid, struct rte_flow **flow_list, uint32_t ufid_cnt); ++void hiovs_rte_flow_data_list_put(void *flow_data_list[], uint32_t count); ++#endif ++ + #ifdef __cplusplus + } + #endif +diff --git a/openvswitch-2.14.2/lib/netdev-offload.c b/openvswitch-2.14.2/lib/netdev-offload.c +index 2da3bc7..cefb4b7 100644 +--- a/openvswitch-2.14.2/lib/netdev-offload.c ++++ b/openvswitch-2.14.2/lib/netdev-offload.c +@@ -26,10 +26,15 @@ + #include + #include + ++#ifdef HAVE_HWOFF_AGENT ++#include "dp-packet.h" ++#include "ovs-numa.h" ++#include "hwoff_init_func.h" ++#endif ++ + #include "cmap.h" + #include "coverage.h" + #include "dpif.h" +-#include "dp-packet.h" + #include "openvswitch/dynamic-string.h" + #include "fatal-signal.h" + #include "hash.h" +@@ -174,6 +179,12 @@ netdev_assign_flow_api(struct netdev *netdev) + struct netdev_registered_flow_api *rfa; + + CMAP_FOR_EACH (rfa, cmap_node, &netdev_flow_apis) { ++ if (strcmp(rfa->flow_api->type, "linux_tc") == 0) { ++ if (strcmp(netdev->netdev_class->type, "tap") == 0) { ++ continue; ++ } ++ } ++ + if (!rfa->flow_api->init_flow_api(netdev)) { + ovs_refcount_ref(&rfa->refcnt); + ovsrcu_set(&netdev->flow_api, rfa->flow_api); +@@ -531,6 +542,40 @@ netdev_ports_lookup(odp_port_t port_no, const char *dpif_type) + return NULL; + } + ++#ifdef HAVE_HWOFF_AGENT ++int ++netdev_ports_insert(struct netdev *netdev, const char *dpif_type, ++ struct dpif_port *dpif_port) ++{ ++ struct port_to_netdev_data *data; ++ int ifindex = netdev_get_ifindex(netdev); ++ ++ ovs_rwlock_wrlock(&netdev_hmap_rwlock); ++ if (netdev_ports_lookup(dpif_port->port_no, dpif_type)) { ++ ovs_rwlock_unlock(&netdev_hmap_rwlock); ++ return EEXIST; ++ } ++ ++ data = xzalloc(sizeof *data); ++ data->netdev = netdev_ref(netdev); ++ dpif_port_clone(&data->dpif_port, dpif_port); ++ data->ifindex = ifindex; ++ ++ netdev_set_dpif_type(netdev, dpif_type); ++ ++ hmap_insert(&port_to_netdev, &data->portno_node, ++ netdev_ports_hash(dpif_port->port_no, dpif_type)); ++ if (ifindex >= 0) { ++ hmap_insert(&ifindex_to_port, &data->ifindex_node, ifindex); ++ } ++ ovs_rwlock_unlock(&netdev_hmap_rwlock); ++ ++ netdev_init_flow_api(netdev); ++ ++ return 0; ++} ++ ++#else + int + netdev_ports_insert(struct netdev *netdev, const char *dpif_type, + struct dpif_port *dpif_port) +@@ -564,6 +609,7 @@ netdev_ports_insert(struct netdev *netdev, const char *dpif_type, + + return 0; + } ++#endif + + struct netdev * + netdev_ports_get(odp_port_t port_no, const char *dpif_type) +@@ -593,7 +639,13 @@ netdev_ports_remove(odp_port_t port_no, const char *dpif_type) + dpif_port_destroy(&data->dpif_port); + netdev_close(data->netdev); /* unref and possibly close */ + hmap_remove(&port_to_netdev, &data->portno_node); ++#ifdef HAVE_HWOFF_AGENT ++ if (data->ifindex >= 0) { ++ hmap_remove(&ifindex_to_port, &data->ifindex_node); ++ } ++#else + hmap_remove(&ifindex_to_port, &data->ifindex_node); ++#endif + free(data); + ret = 0; + } +@@ -666,3 +718,40 @@ netdev_set_flow_api_enabled(const struct smap *ovs_other_config) + } + } + } ++ ++#ifdef HAVE_HWOFF_AGENT ++static void ++hiovs_rte_pktmbuf_init(struct rte_mempool *mp OVS_UNUSED, ++ void *opaque_arg OVS_UNUSED, ++ void *_p, ++ unsigned i OVS_UNUSED) ++{ ++ struct rte_mbuf *pkt = _p; ++ ++ dp_packet_init_dpdk((struct dp_packet *) pkt); ++} ++ ++int ++netdev_offload_hw_init(const struct smap *ovs_other_config) ++{ ++ int ret; ++ static bool hwoff_agent_init = false; ++ ++ if (OVS_LIKELY(hwoff_agent_init)) { ++ return 0; ++ } ++ ++ if (smap_get_bool(ovs_other_config, "hw-offload", false)) { ++ ret = hwoff_funcs_init(); ++ if (ret != 0) { ++ return ret; ++ } ++ (void)hiovs_netdev_offload_init(); ++ netdev_register_flow_api_provider(&hiovs_netdev_offload_api); ++ hwoff_agent_init = true; ++ return ret; ++ } ++ ++ return 0; ++} ++#endif +diff --git a/openvswitch-2.14.2/lib/netdev-offload.h b/openvswitch-2.14.2/lib/netdev-offload.h +index 4c0ed2a..5a9b02f 100644 +--- a/openvswitch-2.14.2/lib/netdev-offload.h ++++ b/openvswitch-2.14.2/lib/netdev-offload.h +@@ -22,13 +22,18 @@ + #include "openvswitch/types.h" + #include "packets.h" + #include "flow.h" ++#ifdef HAVE_HWOFF_AGENT ++#include "dp-packet.h" ++#endif + + #ifdef __cplusplus + extern "C" { + #endif + ++#ifndef HAVE_HWOFF_AGENT + struct dp_packet_batch; + struct dp_packet; ++#endif + struct netdev_class; + struct netdev_rxq; + struct netdev_saved_flags; +@@ -73,7 +78,15 @@ struct offload_info { + * it will be in the pkt meta data. + */ + uint32_t flow_mark; +- ++#ifdef HAVE_HWOFF_AGENT ++ uint32_t in_port_id; ++ uint32_t in_port_type; ++ unsigned int pmd_core_id; ++ void *pmd; ++ void *flow; ++ struct dp_packet_batch *pkts_info; ++ bool modification; ++#endif + bool tc_modify_flow_deleted; /* Indicate the tc modify flow put success + * to delete the original flow. */ + }; +@@ -125,6 +138,11 @@ int netdev_ports_flow_get(const char *dpif_type, struct match *match, + struct dpif_flow_attrs *attrs, + struct ofpbuf *buf); + ++#ifdef HAVE_HWOFF_AGENT ++int netdev_offload_hw_init(const struct smap *ovs_other_config); ++int hwoff_offload_flow_api_del(struct netdev *netdev, const ovs_u128 *ufid, struct dpif_flow_stats *stats); ++#endif ++ + #ifdef __cplusplus + } + #endif +diff --git a/openvswitch-2.14.2/lib/netdev-vport.c b/openvswitch-2.14.2/lib/netdev-vport.c +index 7c99f79..48c8399 100644 +--- a/openvswitch-2.14.2/lib/netdev-vport.c ++++ b/openvswitch-2.14.2/lib/netdev-vport.c +@@ -50,6 +50,10 @@ + #ifdef __linux__ + #include "netdev-linux.h" + #endif ++#ifdef HAVE_HWOFF_AGENT ++#include ++#include "hwoff_init_func.h" ++#endif + + VLOG_DEFINE_THIS_MODULE(netdev_vport); + +@@ -458,6 +462,20 @@ vxlan_get_port_ext_gbp_str(uint16_t port, bool gbp, + return namebuf; + } + ++#ifdef HAVE_HWOFF_AGENT ++static bool ++hwoff_is_ipv6_addr(struct in6_addr *ip6) ++{ ++ if (ip6->__in6_u.__u6_addr32[0] == 0 && ++ ip6->__in6_u.__u6_addr32[1] == 0 && ++ ip6->__in6_u.__u6_addr32[2] == 0xffff0000 && ++ ip6->__in6_u.__u6_addr32[3] != 0) { ++ return false; ++ } ++ return true; ++} ++#endif ++ + static void + update_vxlan_global_cfg(struct netdev *netdev, + struct netdev_tunnel_config *old_cfg, +@@ -468,6 +486,17 @@ update_vxlan_global_cfg(struct netdev *netdev, + const char *type = netdev_get_type(netdev); + struct vport_class *vclass = vport_class_cast(netdev_get_class(netdev)); + ++#ifdef HAVE_HWOFF_AGENT ++ hwoff_func* funcs = hwoff_get_funcs(); ++ bool is_ipv6 = false; ++ if (strcmp(type, "vxlan") == 0 && new_cfg && ++ funcs->hwoff_global_add_vxlan_vtep && ++ (old_cfg == NULL || memcmp(&new_cfg->ipv6_src, &old_cfg->ipv6_src, sizeof(struct in6_addr)))) { ++ is_ipv6 = hwoff_is_ipv6_addr(&new_cfg->ipv6_src); ++ funcs->hwoff_global_add_vxlan_vtep(is_ipv6, &new_cfg->ipv6_src, sizeof(struct in6_addr), new_cfg->dst_port); ++ } ++#endif ++ + if (strcmp(type, "vxlan") || + (old_cfg != NULL && new_cfg != NULL && + old_cfg->dst_port == new_cfg->dst_port && +@@ -487,6 +516,12 @@ update_vxlan_global_cfg(struct netdev *netdev, + simap_put(&vclass->global_cfg_tracker, namebuf, count); + } else { + simap_find_and_delete(&vclass->global_cfg_tracker, namebuf); ++#ifdef HAVE_HWOFF_AGENT ++ if (funcs->hwoff_global_del_vxlan_vtep) { ++ is_ipv6 = hwoff_is_ipv6_addr(&old_cfg->ipv6_src); ++ funcs->hwoff_global_del_vxlan_vtep(is_ipv6, &old_cfg->ipv6_src, sizeof(struct in6_addr)); ++ } ++#endif + } + } + } +diff --git a/openvswitch-2.14.2/lib/odp-util.c b/openvswitch-2.14.2/lib/odp-util.c +index a8598d5..7ca937a 100644 +--- a/openvswitch-2.14.2/lib/odp-util.c ++++ b/openvswitch-2.14.2/lib/odp-util.c +@@ -4511,6 +4511,12 @@ odp_format_ufid(const ovs_u128 *ufid, struct ds *ds) + ds_put_format(ds, "ufid:"UUID_FMT, UUID_ARGS((struct uuid *)ufid)); + } + ++void ++odp_format_mega_ufid(const ovs_u128 *ufid, struct ds *ds) ++{ ++ ds_put_format(ds, "mega_ufid:"UUID_FMT, UUID_ARGS((struct uuid *)ufid)); ++} ++ + /* Appends to 'ds' a string representation of the 'key_len' bytes of + * OVS_KEY_ATTR_* attributes in 'key'. If non-null, additionally formats the + * 'mask_len' bytes of 'mask' which apply to 'key'. If 'portno_names' is +diff --git a/openvswitch-2.14.2/lib/odp-util.h b/openvswitch-2.14.2/lib/odp-util.h +index a1d0d0f..ca2e3e6 100644 +--- a/openvswitch-2.14.2/lib/odp-util.h ++++ b/openvswitch-2.14.2/lib/odp-util.h +@@ -166,8 +166,8 @@ enum odp_key_fitness odp_nsh_hdr_from_attr(const struct nlattr *, + struct nsh_hdr *, size_t); + + int odp_ufid_from_string(const char *s_, ovs_u128 *ufid); +-void odp_format_ufid(const ovs_u128 *ufid, struct ds *); +- ++void odp_format_ufid(const ovs_u128 *ufid, struct ds *); ++void odp_format_mega_ufid(const ovs_u128 *ufid, struct ds *); + void odp_flow_format(const struct nlattr *key, size_t key_len, + const struct nlattr *mask, size_t mask_len, + const struct hmap *portno_names, struct ds *, +diff --git a/openvswitch-2.14.2/lib/ofp-meter.c b/openvswitch-2.14.2/lib/ofp-meter.c +index 9ea40a0..2439a8e 100644 +--- a/openvswitch-2.14.2/lib/ofp-meter.c ++++ b/openvswitch-2.14.2/lib/ofp-meter.c +@@ -261,6 +261,10 @@ ofputil_append_meter_stats(struct ovs_list *replies, + reply->byte_in_count = htonll(ms->byte_in_count); + reply->duration_sec = htonl(ms->duration_sec); + reply->duration_nsec = htonl(ms->duration_nsec); ++ #ifdef HAVE_HWOFF_AGENT ++ reply->n_pkts_dropped = ntohll(ms->n_num_dropped_pkts); ++ reply->n_bytes_dropped = ntohll(ms->n_num_dropped_byte); ++ #endif + + for (n = 0; n < ms->n_bands; ++n) { + const struct ofputil_meter_band_stats *src = &ms->bands[n]; +@@ -433,6 +437,10 @@ ofputil_decode_meter_stats(struct ofpbuf *msg, + ms->byte_in_count = ntohll(oms->byte_in_count); + ms->duration_sec = ntohl(oms->duration_sec); + ms->duration_nsec = ntohl(oms->duration_nsec); ++#ifdef HAVE_HWOFF_AGENT ++ ms->n_num_dropped_byte = ntohll(oms->n_bytes_dropped); ++ ms->n_num_dropped_pkts = ntohll(oms->n_pkts_dropped); ++#endif + ms->bands = bands->data; + + return 0; +@@ -458,6 +466,10 @@ ofputil_format_meter_stats(struct ds *s, const struct ofputil_meter_stats *ms) + ds_put_format(s, "packet_count:%"PRIu64" ", ms->bands[i].packet_count); + ds_put_format(s, "byte_count:%"PRIu64"\n", ms->bands[i].byte_count); + } ++#ifdef HAVE_HWOFF_AGENT ++ ds_put_format(s, "offload_n_pkts_dropped:%"PRIu64" ", ms->n_num_dropped_pkts); ++ ds_put_format(s, "offload_n_bytes_dropped:%"PRIu64"\n", ms->n_num_dropped_byte); ++#endif + } + + void +@@ -631,6 +643,10 @@ parse_ofp_meter_mod_str__(struct ofputil_meter_mod *mm, char *string, + mm->meter.flags |= OFPMF13_BURST; + } else if (fields & F_FLAGS && !strcmp(name, "stats")) { + mm->meter.flags |= OFPMF13_STATS; ++#ifdef HAVE_HWOFF_AGENT ++ } else if (fields & F_FLAGS && !strcmp(name, "offload")) { ++ mm->meter.flags |= OFPMF13_OFFLOAD; ++#endif + } else { + char *value; + +diff --git a/openvswitch-2.14.2/lib/packets.h b/openvswitch-2.14.2/lib/packets.h +index 395bc86..02c3932 100644 +--- a/openvswitch-2.14.2/lib/packets.h ++++ b/openvswitch-2.14.2/lib/packets.h +@@ -1537,6 +1537,8 @@ BUILD_ASSERT_DECL(sizeof(struct vxlanhdr) == 8); + + #define VXLAN_FLAGS 0x08000000 /* struct vxlanhdr.vx_flags required value. */ + ++#define IP_MAX_MASK_LEN 32 ++#define IPV6_MAX_MASK_LEN 128 + /* + * VXLAN Generic Protocol Extension (VXLAN_F_GPE): + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +diff --git a/openvswitch-2.14.2/lib/smap.c b/openvswitch-2.14.2/lib/smap.c +index 149b8b2..e4f4527 100644 +--- a/openvswitch-2.14.2/lib/smap.c ++++ b/openvswitch-2.14.2/lib/smap.c +@@ -393,6 +393,17 @@ smap_add__(struct smap *smap, char *key, void *value, size_t hash) + return node; + } + ++void ++smap_add_format_varg(struct smap *smap, const char *key, const char *format, va_list args) ++{ ++ char *value; ++ size_t key_len; ++ ++ value = xvasprintf(format, args); ++ key_len = strlen(key); ++ smap_add__(smap, xmemdup0(key, key_len), value, hash_bytes(key, key_len, 0)); ++} ++ + static struct smap_node * + smap_find__(const struct smap *smap, const char *key, size_t key_len, + size_t hash) +diff --git a/openvswitch-2.14.2/lib/smap.h b/openvswitch-2.14.2/lib/smap.h +index 766c65f..3d9d1c6 100644 +--- a/openvswitch-2.14.2/lib/smap.h ++++ b/openvswitch-2.14.2/lib/smap.h +@@ -89,6 +89,7 @@ struct smap_node *smap_add_nocopy(struct smap *, char *, char *); + bool smap_add_once(struct smap *, const char *, const char *); + void smap_add_format(struct smap *, const char *key, const char *, ...) + OVS_PRINTF_FORMAT(3, 4); ++void smap_add_format_varg(struct smap *smap, const char *key, const char *format, va_list args); + void smap_add_ipv6(struct smap *, const char *, struct in6_addr *); + void smap_replace(struct smap *, const char *, const char *); + void smap_replace_nocopy(struct smap *, const char *, char *); +diff --git a/openvswitch-2.14.2/ofproto/ofproto-dpif-upcall.c b/openvswitch-2.14.2/ofproto/ofproto-dpif-upcall.c +index b24547d..dfec310 100644 +--- a/openvswitch-2.14.2/ofproto/ofproto-dpif-upcall.c ++++ b/openvswitch-2.14.2/ofproto/ofproto-dpif-upcall.c +@@ -409,6 +409,9 @@ static int udpif_flow_unprogram(struct udpif *udpif, struct udpif_key *ukey, + static upcall_callback upcall_cb; + static dp_purge_callback dp_purge_cb; + ++#ifdef HAVE_HWOFF_AGENT ++static dp_pmd_ukey_purge_callback dp_pmd_ukey_purge_cb; ++#endif + static atomic_bool enable_megaflows = ATOMIC_VAR_INIT(true); + static atomic_bool enable_ufid = ATOMIC_VAR_INIT(true); + +@@ -463,6 +466,9 @@ udpif_create(struct dpif_backer *backer, struct dpif *dpif) + dpif_register_upcall_cb(dpif, upcall_cb, udpif); + dpif_register_dp_purge_cb(dpif, dp_purge_cb, udpif); + ++#ifdef HAVE_HWOFF_AGENT ++ dpif_register_dp_pmd_ukey_purge_cb(dpif, dp_pmd_ukey_purge_cb, udpif); ++#endif + return udpif; + } + +@@ -489,6 +495,9 @@ udpif_destroy(struct udpif *udpif) + dpif_register_dp_purge_cb(udpif->dpif, NULL, udpif); + dpif_register_upcall_cb(udpif->dpif, NULL, udpif); + ++#ifdef HAVE_HWOFF_AGENT ++ dpif_register_dp_pmd_ukey_purge_cb(udpif->dpif, NULL, udpif); ++#endif + for (int i = 0; i < N_UMAPS; i++) { + cmap_destroy(&udpif->ukeys[i].cmap); + ovs_mutex_destroy(&udpif->ukeys[i].mutex); +@@ -965,7 +974,7 @@ udpif_revalidator(void *arg) + flow_limit < n_flows * 1000 / duration) { + flow_limit += 1000; + } +- flow_limit = MIN(ofproto_flow_limit, MAX(flow_limit, 1000)); ++ flow_limit = MIN(ofproto_flow_limit, MAX(flow_limit, 3000)); + atomic_store_relaxed(&udpif->flow_limit, flow_limit); + + if (duration > 2000) { +@@ -2874,7 +2883,24 @@ dp_purge_cb(void *aux, unsigned pmd_id) + } + udpif_resume_revalidators(udpif); + } +- ++#ifdef HAVE_HWOFF_AGENT ++static void dp_pmd_ukey_purge_cb(void *aux, unsigned pmd_id) ++{ ++ struct udpif *udpif = aux; ++ int i; ++ for (i = 0; i < N_UMAPS; i++) { ++ struct udpif_key *ukey; ++ struct umap *umap = &udpif->ukeys[i]; ++ ovs_mutex_lock(&umap->mutex); ++ CMAP_FOR_EACH(ukey, cmap_node, &umap->cmap) { ++ if (ukey->pmd_id == pmd_id) { ++ ukey_delete(umap, ukey); ++ } ++ } ++ ovs_mutex_unlock(&umap->mutex); ++ } ++} ++#endif + static void + upcall_unixctl_show(struct unixctl_conn *conn, int argc OVS_UNUSED, + const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED) +diff --git a/openvswitch-2.14.2/ofproto/ofproto-dpif-xlate.c b/openvswitch-2.14.2/ofproto/ofproto-dpif-xlate.c +index 1f78da1..1713578 100644 +--- a/openvswitch-2.14.2/ofproto/ofproto-dpif-xlate.c ++++ b/openvswitch-2.14.2/ofproto/ofproto-dpif-xlate.c +@@ -33,6 +33,7 @@ + #include "coverage.h" + #include "csum.h" + #include "dp-packet.h" ++#include "dpif-provider.h" + #include "dpif.h" + #include "in-band.h" + #include "lacp.h" +@@ -87,6 +88,10 @@ VLOG_DEFINE_THIS_MODULE(ofproto_dpif_xlate); + * Outputs to patch ports and to groups also count against the depth limit. */ + #define MAX_DEPTH 64 + ++#ifdef HAVE_HWOFF_AGENT ++#define NETDEV_NAME "netdev" ++#endif ++ + /* Maximum number of resubmit actions in a flow translation, whether they are + * recursive or not. */ + #define MAX_RESUBMITS (MAX_DEPTH * MAX_DEPTH) +@@ -2590,13 +2595,56 @@ update_learning_table__(const struct xbridge *xbridge, + struct xbundle *in_xbundle, struct eth_addr dl_src, + int vlan, bool is_grat_arp) + { ++#ifdef HAVE_HWOFF_AGENT ++ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5); ++ void *out_ofbundle = NULL; ++ bool update = (in_xbundle == &ofpp_none_bundle); ++ ++ if (update) { ++ return update; ++ } ++ update = mac_learning_update(xbridge->ml, dl_src, vlan, ++ is_grat_arp, ++ in_xbundle->bond != NULL, ++ in_xbundle->ofbundle, &out_ofbundle); ++ if (update && out_ofbundle) { ++ VLOG_INFO_RL(&rl, "mac learning conflicted. "ETH_ADDR_FMT" is on new port %s in VLAN %d, old port is %s", ++ ETH_ADDR_ARGS(dl_src), in_xbundle->name, vlan, ofbundle_get_name(out_ofbundle)); ++ } ++ ++ return !update; ++#else + return (in_xbundle == &ofpp_none_bundle + || !mac_learning_update(xbridge->ml, dl_src, vlan, + is_grat_arp, + in_xbundle->bond != NULL, + in_xbundle->ofbundle)); ++#endif + } ++#ifdef HAVE_HWOFF_AGENT ++static void ++update_learning_table(const struct xlate_ctx *ctx, ++ struct xbundle *in_xbundle, struct eth_addr dl_src, ++ int vlan, bool is_grat_arp, bool is_reverse_arp, bool is_ipv6_nd) ++{ ++ struct hwoff_migrate_rarp_mac_infos *hwoff_migrate_rarp_mac_infos = hwoff_migrate_rarp_mac_infos_get(); ++ if (!update_learning_table__(ctx->xbridge, in_xbundle, dl_src, vlan, ++ is_grat_arp)) { ++ xlate_report_debug(ctx, OFT_DETAIL, "learned that "ETH_ADDR_FMT" is " ++ "on port %s in VLAN %d", ++ ETH_ADDR_ARGS(dl_src), in_xbundle->name, vlan); + ++ if ((unlikely(is_reverse_arp) || unlikely(is_grat_arp) || unlikely(is_ipv6_nd)) && ++ hwoff_rarp_status_get() && (!strcmp(ctx->xbridge->dpif->dpif_class->type, NETDEV_NAME))) { ++ ovs_rwlock_wrlock(&hwoff_migrate_rarp_mac_infos->rw); ++ if (hwoff_rarp_mac_insert_to_list(dl_src) == NULL) { ++ xlate_report(ctx, OFT_WARN, "insert failed ! the rarp mac length exceeds the upper limit."); ++ } ++ ovs_rwlock_unlock(&hwoff_migrate_rarp_mac_infos->rw); ++ } ++ } ++} ++#else + static void + update_learning_table(const struct xlate_ctx *ctx, + struct xbundle *in_xbundle, struct eth_addr dl_src, +@@ -2609,6 +2657,7 @@ update_learning_table(const struct xlate_ctx *ctx, + ETH_ADDR_ARGS(dl_src), in_xbundle->name, vlan); + } + } ++#endif + + /* Updates multicast snooping table 'ms' given that a packet matching 'flow' + * was received on 'in_xbundle' in 'vlan' and is either Report or Query. */ +@@ -3010,15 +3059,23 @@ xlate_normal(struct xlate_ctx *ctx) + if (in_port && !is_admissible(ctx, in_port, vlan)) { + return; + } +- + /* Learn source MAC. */ + bool is_grat_arp = is_gratuitous_arp(flow, wc); ++#ifdef HAVE_HWOFF_AGENT ++ bool is_reverse_arp = (flow->dl_type == htons(ETH_TYPE_RARP)) ? true : false; ++ bool is_ipv6_nd = is_nd(flow, NULL); ++#endif + if (ctx->xin->allow_side_effects + && flow->packet_type == htonl(PT_ETH) + && in_port->pt_mode != NETDEV_PT_LEGACY_L3 + ) { +- update_learning_table(ctx, in_xbundle, flow->dl_src, vlan, ++#ifdef HAVE_HWOFF_AGENT ++ update_learning_table(ctx, in_xbundle, flow->dl_src, vlan, ++ is_grat_arp, is_reverse_arp, is_ipv6_nd); ++#else ++ update_learning_table(ctx, in_xbundle, flow->dl_src, vlan, + is_grat_arp); ++#endif + } + if (ctx->xin->xcache && in_xbundle != &ofpp_none_bundle) { + struct xc_entry *entry; +diff --git a/openvswitch-2.14.2/ofproto/ofproto-dpif.c b/openvswitch-2.14.2/ofproto/ofproto-dpif.c +index 4f0638f..c9dc9c1 100644 +--- a/openvswitch-2.14.2/ofproto/ofproto-dpif.c ++++ b/openvswitch-2.14.2/ofproto/ofproto-dpif.c +@@ -193,6 +193,11 @@ ofport_dpif_cast(const struct ofport *ofport) + return ofport ? CONTAINER_OF(ofport, struct ofport_dpif, up) : NULL; + } + ++char * ++ofbundle_get_name(const void *ofbundle_) ++{ ++ return ((struct ofbundle *)ofbundle_)->name; ++} + static void port_run(struct ofport_dpif *); + static int set_bfd(struct ofport *, const struct smap *); + static int set_cfm(struct ofport *, const struct cfm_settings *); +@@ -5292,6 +5297,18 @@ type_set_config(const char *type, const struct smap *other_config) + dpif_set_config(backer->dpif, other_config); + } + ++#ifdef HAVE_HWOFF_AGENT ++static void ++ct_flush(const struct ofproto *ofproto_, const uint16_t *zone, ++ union ct_addr *sip, union ct_addr *dip, ++ union ct_addr*smask, union ct_addr *dmask, ++ uint16_t dl_type, bool is_force) ++{ ++ struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); ++ ++ ct_dpif_flush(ofproto->backer->dpif, zone, sip, dip, smask, dmask, dl_type, is_force); ++} ++#else + static void + ct_flush(const struct ofproto *ofproto_, const uint16_t *zone) + { +@@ -5299,6 +5316,7 @@ ct_flush(const struct ofproto *ofproto_, const uint16_t *zone) + + ct_dpif_flush(ofproto->backer->dpif, zone, NULL); + } ++#endif + + static struct ct_timeout_policy * + ct_timeout_policy_lookup(const struct hmap *ct_tps, struct simap *tp) +diff --git a/openvswitch-2.14.2/ofproto/ofproto-dpif.h b/openvswitch-2.14.2/ofproto/ofproto-dpif.h +index 1f5794f..9ae0629 100644 +--- a/openvswitch-2.14.2/ofproto/ofproto-dpif.h ++++ b/openvswitch-2.14.2/ofproto/ofproto-dpif.h +@@ -349,6 +349,7 @@ struct ofproto_dpif { + * switch connection. */ + }; + ++char *ofbundle_get_name(const void *ofbundle_); + struct ofproto_dpif *ofproto_dpif_lookup_by_name(const char *name); + struct ofproto_dpif *ofproto_dpif_lookup_by_uuid(const struct uuid *uuid); + +diff --git a/openvswitch-2.14.2/ofproto/ofproto-provider.h b/openvswitch-2.14.2/ofproto/ofproto-provider.h +index afecb24..ff46587 100644 +--- a/openvswitch-2.14.2/ofproto/ofproto-provider.h ++++ b/openvswitch-2.14.2/ofproto/ofproto-provider.h +@@ -58,6 +58,7 @@ + #include "tun-metadata.h" + #include "versions.h" + #include "vl-mff-map.h" ++#include "conntrack.h" + + struct match; + struct ofputil_flow_mod; +@@ -1895,7 +1896,14 @@ struct ofproto_class { + /* ## ------------------- ## */ + /* Flushes the connection tracking tables. If 'zone' is not NULL, + * only deletes connections in '*zone'. */ ++#ifdef HAVE_HWOFF_AGENT ++ void (*ct_flush)(const struct ofproto *, const uint16_t *zone, ++ union ct_addr *sip, union ct_addr *dip, ++ union ct_addr *smask, union ct_addr *dmask, ++ uint16_t dl_type, bool is_force); ++#else + void (*ct_flush)(const struct ofproto *, const uint16_t *zone); ++#endif + + /* Sets conntrack timeout policy specified by 'timeout_policy' to 'zone' + * in datapath type 'dp_type'. */ +diff --git a/openvswitch-2.14.2/ofproto/ofproto.c b/openvswitch-2.14.2/ofproto/ofproto.c +index 59f06aa..d23ad15 100644 +--- a/openvswitch-2.14.2/ofproto/ofproto.c ++++ b/openvswitch-2.14.2/ofproto/ofproto.c +@@ -941,7 +941,11 @@ handle_nxt_ct_flush_zone(struct ofconn *ofconn, const struct ofp_header *oh) + + uint16_t zone = ntohs(nzi->zone_id); + if (ofproto->ofproto_class->ct_flush) { ++#ifdef HAVE_HWOFF_AGENT ++ ofproto->ofproto_class->ct_flush(ofproto, &zone, NULL, NULL, NULL, NULL, 0, false); ++#else + ofproto->ofproto_class->ct_flush(ofproto, &zone); ++#endif + } else { + return EOPNOTSUPP; + } +diff --git a/openvswitch-2.14.2/tests/hiovs-offload.at b/openvswitch-2.14.2/tests/hiovs-offload.at +new file mode 100644 +index 0000000..41d9ea5 +--- /dev/null ++++ b/openvswitch-2.14.2/tests/hiovs-offload.at +@@ -0,0 +1,10 @@ ++AT_BANNER([hiovs offload unit tests]) ++m4_foreach( ++ [testname], ++ [[init_flow_api], ++ [flow_put], ++ [flow_del], ++ [flow_get]], ++ [AT_SETUP([hiovs offload- m4_bpatsubst(testname, [-], [ ])]) ++ AT_CHECK([ovstest test-hiovs-offload m4_bpatsubst(testname, [versioned], [--versioned])], [0], [], []) ++ AT_CLEANUP])]) +diff --git a/openvswitch-2.14.2/tests/test-hiovs-offload.c b/openvswitch-2.14.2/tests/test-hiovs-offload.c +new file mode 100644 +index 0000000..34c29e8 +--- /dev/null ++++ b/openvswitch-2.14.2/tests/test-hiovs-offload.c +@@ -0,0 +1,258 @@ ++/* ++ * Copyright (c) 2015 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#include ++#include ++#include ++ ++#include "ovstest.h" ++#include "util.h" ++#include "hwoff_init_func.h" ++#include "dpif.h" ++#include "cmap.h" ++#include "dp-packet.h" ++#include "netdev-offload-provider.h" ++ ++struct rte_flow { ++ /* rte_flow mega ufid. */ ++ ovs_u128 mega_ufid; ++ /* Number of packets matched. */ ++ uint64_t sw_packets; ++ /* Number of bytes matched. */ ++ uint64_t sw_bytes; ++ /* Time of rte_flow success offload. */ ++ long long sw_offload_time; ++ struct cmap_node node; ++ /* rte_flow mapped hardware flow. */ ++ struct cmap hw_list; ++}; ++ ++static int mock_hwoff_init_flow_api(struct netdev *netdev) ++{ ++ (void)netdev; ++ return 0; ++} ++ ++static struct rte_flow* mock_hwoff_rte_flow_create(struct netdev *netdev, const struct rte_flow_attr *attr, ++ const struct rte_flow_item *items, ++ const struct rte_flow_action *actions, ++ struct rte_flow_error *error) ++{ ++ struct rte_flow *new_rte_flow = NULL; ++ ++ (void)netdev; ++ (void)attr; ++ (void)items; ++ (void)actions; ++ (void)error; ++ new_rte_flow = (struct rte_flow *)malloc(sizeof(*new_rte_flow)); ++ return new_rte_flow; ++} ++ ++static int mock_hwoff_rte_flow_destroy(struct netdev *netdev, struct rte_flow *rte_flow, struct rte_flow_error *error) ++{ ++ (void)netdev; ++ (void)rte_flow; ++ (void)error; ++ return 0; ++} ++ ++static int mock_hwoff_rte_flow_query_count(struct netdev *netdev, struct rte_flow *rte_flow, ++ struct rte_flow_query_count *query, struct rte_flow_error *error) ++{ ++ (void)netdev; ++ (void)rte_flow; ++ (void)query; ++ (void)error; ++ return 0; ++} ++ ++static bool mock_hwoff_is_hiovs_netdev(const struct netdev *netdev) ++{ ++ (void)netdev; ++ return true; ++} ++ ++static bool mock_hwoff_is_support_offload(const struct netdev *netdev) ++{ ++ (void)netdev; ++ return true; ++} ++ ++static void mock_hwoff_funcs(void) ++{ ++ hwoff_func* funcs = hwoff_get_funcs(); ++ ++ funcs->hwoff_init_flow_api = mock_hwoff_init_flow_api; ++ funcs->hwoff_is_support_offload = mock_hwoff_is_support_offload; ++} ++ ++static struct netdev* hiovs_create_fake_netdev(void) ++{ ++ struct netdev *dev; ++ ++ dev = (struct netdev *)malloc(sizeof(struct netdev)); ++ if (!dev) { ++ return NULL; ++ } ++ ++ return dev; ++} ++ ++static void hiovs_fill_offload_info(struct offload_info *tmp_offload_info) ++{ ++ tmp_offload_info->in_port_id = 1; ++ tmp_offload_info->in_port_type = 1; ++ tmp_offload_info->pmd_core_id = 1; ++ tmp_offload_info->modification = false; ++} ++ ++static void hiovs_offload_flow_put(ovs_u128 *ufid, struct netdev *dev) ++{ ++ int ret; ++ uint8_t actions_stub[512]; ++ struct ofpbuf actions; ++ struct dpif_flow_stats stats; ++ struct offload_info tmp_offload_info; ++ struct dp_packet_batch pkt_batch; ++ struct netdev_flow_api *hiovs_class = (struct netdev_flow_api *)&netdev_offload_hiovs; ++ ++ ofpbuf_use_stub(&actions, actions_stub, sizeof(actions_stub)); ++ nl_msg_put_odp_port(&actions, OVS_ACTION_ATTR_OUTPUT, u32_to_odp(1)); ++ ++ tmp_offload_info.pkts_info = &pkt_batch; ++ hiovs_fill_offload_info(&tmp_offload_info); ++ ++ ret = hiovs_class->flow_put(dev, NULL, actions.data, actions.size, ufid, &tmp_offload_info, &stats); ++ if (ret != 0) { ++ ovs_fatal(0, "flow_put fail"); ++ return; ++ } ++ return; ++} ++ ++static void hiovs_fill_ufid(ovs_u128 *ufid, uint32_t value) ++{ ++ ufid->u32[0] = value; ++ ufid->u32[1] = 0; ++ ufid->u32[2] = 0; ++ ufid->u32[3] = 0; ++} ++ ++static void test_hiovs_offload_init_flow_api(struct ovs_cmdl_context *ctx OVS_UNUSED) ++{ ++ int ret; ++ struct netdev *dev = NULL; ++ struct netdev_flow_api *hiovs_class = (struct netdev_flow_api *)&netdev_offload_hiovs; ++ ++ mock_hwoff_funcs(); ++ dev = hiovs_create_fake_netdev(); ++ if (!dev) { ++ ovs_fatal(0, "can't create netdev"); ++ return; ++ } ++ ++ ret = hiovs_class->init_flow_api(dev); ++ if (ret != 0) { ++ ovs_fatal(0, "init_flow_api execute fail"); ++ free(dev); ++ return; ++ } ++ ++ return; ++} ++ ++static void test_hiovs_offload_flow_put(struct ovs_cmdl_context *ctx OVS_UNUSED) ++{ ++ ovs_u128 ufid; ++ struct netdev *dev = NULL; ++ ++ hiovs_fill_ufid(&ufid, 211); ++ mock_hwoff_funcs(); ++ dev = hiovs_create_fake_netdev(); ++ if (!dev) { ++ ovs_fatal(0, "can't create netdev"); ++ return; ++ } ++ ++ hiovs_offload_flow_put(&ufid, dev); ++ free(dev); ++ return; ++} ++ ++static void test_hiovs_offload_flow_delete(struct ovs_cmdl_context *ctx OVS_UNUSED) ++{ ++ ovs_u128 ufid; ++ struct netdev *dev = NULL; ++ struct dpif_flow_stats stats; ++ struct netdev_flow_api *hiovs_class = (struct netdev_flow_api *)&netdev_offload_hiovs; ++ ++ hiovs_fill_ufid(&ufid, 212); ++ mock_hwoff_funcs(); ++ dev = hiovs_create_fake_netdev(); ++ if (!dev) { ++ ovs_fatal(0, "can't create netdev"); ++ return; ++ } ++ ++ hiovs_offload_flow_put(&ufid, dev); ++ hiovs_class->flow_del(dev, &ufid, &stats); ++ free(dev); ++ return; ++} ++ ++static void test_hiovs_offload_flow_get(struct ovs_cmdl_context *ctx OVS_UNUSED) ++{ ++ ovs_u128 ufid; ++ struct netdev *dev = NULL; ++ struct dpif_flow_stats stats; ++ struct dpif_flow_attrs attr; ++ struct netdev_flow_api *hiovs_class = (struct netdev_flow_api *)&netdev_offload_hiovs; ++ ++ hiovs_fill_ufid(&ufid, 212); ++ mock_hwoff_funcs(); ++ dev = hiovs_create_fake_netdev(); ++ if (!dev) { ++ ovs_fatal(0, "can't create netdev"); ++ return; ++ } ++ ++ hiovs_offload_flow_put(&ufid, dev); ++ ++ hiovs_class->flow_get(dev, NULL, NULL, &ufid, &stats, &attr, NULL); ++ free(dev); ++ return; ++} ++ ++static const struct ovs_cmdl_command commands[] = { ++ {"init_flow_api", "init_flow_api", 0, 0, test_hiovs_offload_init_flow_api, OVS_RO}, ++ {"flow_put", "flow_put", 0, 0, test_hiovs_offload_flow_put, OVS_RO}, ++ {"flow_del", "flow_del", 0, 0, test_hiovs_offload_flow_delete, OVS_RO}, ++ {"flow_get", "flow_get", 0, 0, test_hiovs_offload_flow_get, OVS_RO}, ++ {NULL, NULL, 0, 0, NULL, OVS_RO}, ++}; ++ ++static void test_hiovs_offload_main(int argc, char *argv[]) ++{ ++ struct ovs_cmdl_context ctx = { ++ .argc = argc - 1, ++ .argv = argv + 1, ++ }; ++ set_program_name(argv[0]); ++ ovs_cmdl_run_command(&ctx, commands); ++} ++ ++OVSTEST_REGISTER("test-hiovs-offload", test_hiovs_offload_main); +diff --git a/openvswitch-2.14.2/tests/testsuite.at b/openvswitch-2.14.2/tests/testsuite.at +index 7369991..5cc06a8 100644 +--- a/openvswitch-2.14.2/tests/testsuite.at ++++ b/openvswitch-2.14.2/tests/testsuite.at +@@ -77,3 +77,4 @@ m4_include([tests/mcast-snooping.at]) + m4_include([tests/packet-type-aware.at]) + m4_include([tests/nsh.at]) + m4_include([tests/drop-stats.at]) ++m4_include([tests/hiovs-offload.at]) +diff --git a/openvswitch-2.14.2/vswitchd/bridge.c b/openvswitch-2.14.2/vswitchd/bridge.c +index a332517..6d19c79 100644 +--- a/openvswitch-2.14.2/vswitchd/bridge.c ++++ b/openvswitch-2.14.2/vswitchd/bridge.c +@@ -19,6 +19,10 @@ + #include + #include + ++#ifdef HAVE_HWOFF_AGENT ++#include "hwoff_init_func.h" ++#endif ++ + #include "async-append.h" + #include "bfd.h" + #include "bitmap.h" +@@ -553,6 +557,11 @@ bridge_exit(bool delete_datapath) + } + + ovsdb_idl_destroy(idl); ++ ++#ifdef HAVE_HWOFF_AGENT ++ hwoff_clear_pf_access_hugepages(); ++ hwoff_free_hugepages(); ++#endif + } + + /* Looks at the list of managers in 'ovs_cfg' and extracts their remote IP +@@ -3251,6 +3260,9 @@ bridge_run__(void) + } + } + ++extern void rte_adapter_init(void); ++extern void ovs_adapter_init(void); ++ + void + bridge_run(void) + { +@@ -3291,6 +3303,23 @@ bridge_run(void) + netdev_set_flow_api_enabled(&cfg->other_config); + dpdk_init(&cfg->other_config); + userspace_tso_init(&cfg->other_config); ++ ++#ifdef HAVE_HWOFF_AGENT ++ int ret = netdev_offload_hw_init(&cfg->other_config); ++ if (ret == 0) { ++ hwoff_func* funcs = hwoff_get_funcs(); ++ ++ size_t num_pairs = smap_count(&cfg->other_config); ++ struct hwoff_key_val_node *hwoff_key_val = NULL; ++ ret = hwoff_key_val_init(&hwoff_key_val, &cfg->other_config); ++ if (ret == 0) { ++ if (funcs->hwoff_parse_ovs_other_config) { ++ funcs->hwoff_parse_ovs_other_config(hwoff_key_val, num_pairs); ++ } ++ } ++ hwoff_key_val_destroy(hwoff_key_val, num_pairs); ++ } ++#endif + } + + /* Initialize the ofproto library. This only needs to run once, but diff --git a/openvswitch-2.14.2-20241009.patch b/openvswitch-2.14.2-20241009.patch new file mode 100644 index 0000000000000000000000000000000000000000..a244f52cbb9b23bece00350202d78a9bf772d1ee --- /dev/null +++ b/openvswitch-2.14.2-20241009.patch @@ -0,0 +1,7083 @@ +diff --git a/openvswitch-2.14.2/Makefile.in b/openvswitch-2.14.2/Makefile.in +index f9ce1c6..b151099 100644 +--- a/openvswitch-2.14.2/Makefile.in ++++ b/openvswitch-2.14.2/Makefile.in +@@ -256,15 +256,16 @@ noinst_PROGRAMS = $(am__EXEEXT_2) tests/test-ovsdb$(EXEEXT) \ + @HAVE_AF_XDP_TRUE@ lib/netdev-afxdp.c \ + @HAVE_AF_XDP_TRUE@ lib/netdev-afxdp.h + +-@DPDK_NETDEV_TRUE@am__append_23 = \ ++@HAVE_HWOFF_AGENT_TRUE@am__append_23 = -lhwoffagent ++@DPDK_NETDEV_TRUE@am__append_24 = \ + @DPDK_NETDEV_TRUE@ lib/dpdk.c \ + @DPDK_NETDEV_TRUE@ lib/netdev-dpdk.c \ + @DPDK_NETDEV_TRUE@ lib/netdev-offload-dpdk.c + +-@DPDK_NETDEV_FALSE@am__append_24 = \ ++@DPDK_NETDEV_FALSE@am__append_25 = \ + @DPDK_NETDEV_FALSE@ lib/dpdk-stub.c + +-@WIN32_TRUE@am__append_25 = \ ++@WIN32_TRUE@am__append_26 = \ + @WIN32_TRUE@ lib/dpif-netlink.c \ + @WIN32_TRUE@ lib/dpif-netlink.h \ + @WIN32_TRUE@ lib/dpif-netlink-rtnl.h \ +@@ -279,41 +280,41 @@ noinst_PROGRAMS = $(am__EXEEXT_2) tests/test-ovsdb$(EXEEXT) \ + @WIN32_TRUE@ lib/wmi.c \ + @WIN32_TRUE@ lib/wmi.h + +-@HAVE_POSIX_AIO_TRUE@am__append_26 = lib/async-append-aio.c +-@HAVE_POSIX_AIO_FALSE@am__append_27 = lib/async-append-null.c +-@HAVE_IF_DL_TRUE@am__append_28 = \ ++@HAVE_POSIX_AIO_TRUE@am__append_27 = lib/async-append-aio.c ++@HAVE_POSIX_AIO_FALSE@am__append_28 = lib/async-append-null.c ++@HAVE_IF_DL_TRUE@am__append_29 = \ + @HAVE_IF_DL_TRUE@ lib/if-notifier-bsd.c \ + @HAVE_IF_DL_TRUE@ lib/netdev-bsd.c \ + @HAVE_IF_DL_TRUE@ lib/rtbsd.c \ + @HAVE_IF_DL_TRUE@ lib/rtbsd.h \ + @HAVE_IF_DL_TRUE@ lib/route-table-bsd.c + +-@HAVE_OPENSSL_TRUE@am__append_29 = lib/stream-ssl.c lib/dhparams.c +-@HAVE_OPENSSL_FALSE@am__append_30 = lib/stream-nossl.c +-@HAVE_UNBOUND_TRUE@am__append_31 = lib/dns-resolve.c +-@HAVE_UNBOUND_FALSE@am__append_32 = lib/dns-resolve-stub.c +-@WIN32_TRUE@am__append_33 = ${PTHREAD_LIBS} +-@LINUX_TRUE@am__append_34 = utilities/nlmon +-@WIN32_FALSE@am__append_35 = \ ++@HAVE_OPENSSL_TRUE@am__append_30 = lib/stream-ssl.c lib/dhparams.c ++@HAVE_OPENSSL_FALSE@am__append_31 = lib/stream-nossl.c ++@HAVE_UNBOUND_TRUE@am__append_32 = lib/dns-resolve.c ++@HAVE_UNBOUND_FALSE@am__append_33 = lib/dns-resolve-stub.c ++@WIN32_TRUE@am__append_34 = ${PTHREAD_LIBS} ++@LINUX_TRUE@am__append_35 = utilities/nlmon ++@WIN32_FALSE@am__append_36 = \ + @WIN32_FALSE@ tests/test-unix-socket.c + +-@LINUX_TRUE@am__append_36 = \ ++@LINUX_TRUE@am__append_37 = \ + @LINUX_TRUE@ tests/test-netlink-conntrack.c + +-@HAVE_OPENSSL_TRUE@am__append_37 = $(TESTPKI_FILES) +-@HAVE_OPENSSL_TRUE@am__append_38 = $(TESTPKI_FILES) tests/ovs-pki.log +-@HAVE_OPENSSL_TRUE@am__append_39 = clean-pki ++@HAVE_OPENSSL_TRUE@am__append_38 = $(TESTPKI_FILES) ++@HAVE_OPENSSL_TRUE@am__append_39 = $(TESTPKI_FILES) tests/ovs-pki.log ++@HAVE_OPENSSL_TRUE@am__append_40 = clean-pki + + # OVS does not use C++ itself, but it provides public header files + # that a C++ compiler should accept, so when --enable-Werror is in + # effect and a C++ compiler is available, we build a C++ source file + # that #includes all the public headers, as a way to ensure that they + # are acceptable as C++. +-@HAVE_CXX_TRUE@am__append_40 = include/openvswitch/libcxxtest.la +-@HAVE_CXX_TRUE@am__append_41 = include/openvswitch/cxxtest.cc +-@HAVE_DOT_TRUE@am__append_42 = vswitchd/vswitch.gv vswitchd/vswitch.pic +-@HAVE_DOT_TRUE@am__append_43 = vtep/vtep.gv vtep/vtep.pic +-@WIN32_TRUE@am__append_44 = $(srcdir)/datapath-windows/include/OvsDpInterface.h ++@HAVE_CXX_TRUE@am__append_41 = include/openvswitch/libcxxtest.la ++@HAVE_CXX_TRUE@am__append_42 = include/openvswitch/cxxtest.cc ++@HAVE_DOT_TRUE@am__append_43 = vswitchd/vswitch.gv vswitchd/vswitch.pic ++@HAVE_DOT_TRUE@am__append_44 = vtep/vtep.gv vtep/vtep.pic ++@WIN32_TRUE@am__append_45 = $(srcdir)/datapath-windows/include/OvsDpInterface.h + subdir = . + ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 + am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ +@@ -409,7 +410,7 @@ am__DEPENDENCIES_1 = + @WIN32_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) + lib_libopenvswitch_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ +- $(am__DEPENDENCIES_2) $(am__append_16) ++ $(am__DEPENDENCIES_2) $(am__append_16) $(am__DEPENDENCIES_1) + am__lib_libopenvswitch_la_SOURCES_DIST = lib/aes128.c lib/aes128.h \ + lib/async-append.h lib/backtrace.c lib/backtrace.h lib/bfd.c \ + lib/bfd.h lib/bitmap.h lib/bundle.c lib/bundle.h \ +@@ -418,16 +419,17 @@ am__lib_libopenvswitch_la_SOURCES_DIST = lib/aes128.c lib/aes128.h \ + lib/ccmap.c lib/ccmap.h lib/cmap.c lib/cmap.h lib/colors.c \ + lib/colors.h lib/command-line.c lib/command-line.h \ + lib/compiler.h lib/connectivity.c lib/connectivity.h \ +- lib/conntrack-icmp.c lib/conntrack-private.h \ +- lib/conntrack-tcp.c lib/conntrack-tp.c lib/conntrack-tp.h \ +- lib/conntrack-other.c lib/conntrack.c lib/conntrack.h \ +- lib/coverage.c lib/coverage.h lib/crc32c.c lib/crc32c.h \ +- lib/csum.c lib/csum.h lib/ct-dpif.c lib/ct-dpif.h lib/daemon.c \ +- lib/daemon.h lib/daemon-private.h lib/db-ctl-base.c \ +- lib/db-ctl-base.h lib/dhcp.h lib/dummy.c lib/dummy.h \ +- lib/dhparams.h lib/dirs.h lib/dpctl.c lib/dpctl.h \ +- lib/dp-packet.h lib/dp-packet.c lib/dpdk.h \ +- lib/dpif-netdev-lookup.h lib/dpif-netdev-lookup.c \ ++ lib/hwoff_init_func.c lib/hwoff_init_func.h \ ++ lib/dpak_ovs.h lib/conntrack-icmp.c \ ++ lib/conntrack-private.h lib/conntrack-tcp.c lib/conntrack-tp.c \ ++ lib/conntrack-tp.h lib/conntrack-other.c lib/conntrack.c \ ++ lib/conntrack.h lib/ct_offload_provider.h lib/coverage.c \ ++ lib/coverage.h lib/crc32c.c lib/crc32c.h lib/csum.c lib/csum.h \ ++ lib/ct-dpif.c lib/ct-dpif.h lib/daemon.c lib/daemon.h \ ++ lib/daemon-private.h lib/db-ctl-base.c lib/db-ctl-base.h \ ++ lib/dhcp.h lib/dummy.c lib/dummy.h lib/dhparams.h lib/dirs.h \ ++ lib/dpctl.c lib/dpctl.h lib/dp-packet.h lib/dp-packet.c \ ++ lib/dpdk.h lib/dpif-netdev-lookup.h lib/dpif-netdev-lookup.c \ + lib/dpif-netdev-lookup-autovalidator.c \ + lib/dpif-netdev-lookup-generic.c lib/dpif-netdev.c \ + lib/dpif-netdev.h lib/dpif-netdev-private.h \ +@@ -563,8 +565,8 @@ am__lib_libopenvswitch_la_SOURCES_DIST = lib/aes128.c lib/aes128.h \ + am_lib_libopenvswitch_la_OBJECTS = lib/aes128.lo lib/backtrace.lo \ + lib/bfd.lo lib/bundle.lo lib/byteq.lo lib/cfm.lo \ + lib/classifier.lo lib/ccmap.lo lib/cmap.lo lib/colors.lo \ +- lib/command-line.lo lib/connectivity.lo lib/conntrack-icmp.lo \ +- lib/conntrack-tcp.lo lib/conntrack-tp.lo \ ++ lib/command-line.lo lib/connectivity.lo lib/hwoff_init_func.lo \ ++ lib/conntrack-icmp.lo lib/conntrack-tcp.lo lib/conntrack-tp.lo \ + lib/conntrack-other.lo lib/conntrack.lo lib/coverage.lo \ + lib/crc32c.lo lib/csum.lo lib/ct-dpif.lo lib/daemon.lo \ + lib/db-ctl-base.lo lib/dummy.lo lib/dpctl.lo lib/dp-packet.lo \ +@@ -807,7 +809,7 @@ am_tests_ovstest_OBJECTS = tests/ovstest.$(OBJEXT) \ + tests/test-stp.$(OBJEXT) tests/test-unixctl.$(OBJEXT) \ + tests/test-util.$(OBJEXT) tests/test-uuid.$(OBJEXT) \ + tests/test-bitmap.$(OBJEXT) tests/test-vconn.$(OBJEXT) \ +- tests/test-aa.$(OBJEXT) tests/test-stopwatch.$(OBJEXT) \ ++ tests/test-aa.$(OBJEXT) tests/test-stopwatch.$(OBJEXT) tests/test-hiovs-offload.$(OBJEXT) \ + $(am__objects_15) $(am__objects_16) + tests_ovstest_OBJECTS = $(am_tests_ovstest_OBJECTS) + tests_ovstest_DEPENDENCIES = lib/libopenvswitch.la +@@ -920,7 +922,8 @@ am__depfiles_remade = include/openvswitch/$(DEPDIR)/cxxtest.Plo \ + lib/$(DEPDIR)/guarded-list.Plo lib/$(DEPDIR)/hash.Plo \ + lib/$(DEPDIR)/heap.Plo lib/$(DEPDIR)/hindex.Plo \ + lib/$(DEPDIR)/hmap.Plo lib/$(DEPDIR)/hmapx.Plo \ +- lib/$(DEPDIR)/id-pool.Plo lib/$(DEPDIR)/if-notifier-bsd.Plo \ ++ lib/$(DEPDIR)/hwoff_init_func.Plo lib/$(DEPDIR)/id-pool.Plo \ ++ lib/$(DEPDIR)/if-notifier-bsd.Plo \ + lib/$(DEPDIR)/if-notifier-manual.Plo \ + lib/$(DEPDIR)/if-notifier-stub.Plo \ + lib/$(DEPDIR)/if-notifier.Plo lib/$(DEPDIR)/ipf.Plo \ +@@ -1563,7 +1566,7 @@ ALL_LOCAL = dist-hook-git config-h-check printf-check static-check \ + $(srcdir)/python/ovs/version.py $(srcdir)/python/ovs/dirs.py \ + vtep/vtep.ovsschema.stamp + BUILT_SOURCES = ofproto/ipfix-entities.def include/odp-netlink.h \ +- include/odp-netlink-macros.h $(OVSIDL_BUILT) $(am__append_44) ++ include/odp-netlink-macros.h $(OVSIDL_BUILT) $(am__append_45) + + # Clean up generated files from older OVS versions. (This is important so that + # #include "vswitch-idl.h" doesn't get the wrong copy.) +@@ -1583,10 +1586,10 @@ CLEANFILES = all-distfiles all-gitfiles missing-distfiles distfiles \ + utilities/ovs-tcpundump utilities/ovs-test \ + utilities/ovs-vlan-test utilities/ovs-vsctl.8 \ + utilities/bugtool/ovs-bugtool utilities/bugtool/ovs-bugtool.8 \ +- $(valgrind_wrappers) $(am__append_38) include/odp-netlink.h \ +- include/odp-netlink-macros.h $(HSTAMP_FILES) $(am__append_41) \ ++ $(valgrind_wrappers) $(am__append_39) include/odp-netlink.h \ ++ include/odp-netlink-macros.h $(HSTAMP_FILES) $(am__append_42) \ + cxx-check debian/copyright ipsec/ovs-monitor-ipsec \ +- vswitchd/ovs-vswitchd.8 $(am__append_42) \ ++ vswitchd/ovs-vswitchd.8 $(am__append_43) \ + vswitchd/ovs-vswitchd.conf.db.5 \ + vswitchd/vswitch.ovsschema.stamp vswitchd/vswitch-idl.c \ + vswitchd/vswitch-idl.h ovsdb/ovsdb-tool.1 ovsdb/ovsdb-client.1 \ +@@ -1594,7 +1597,7 @@ CLEANFILES = all-distfiles all-gitfiles missing-distfiles distfiles \ + ovsdb/ovsdb-dot ovsdb/_server.ovsschema.inc \ + ovsdb/_server.ovsschema.stamp ovsdb/ovsdb-server.5 \ + python/ovs/dirs.py vtep/vtep-ctl.8 vtep/ovs-vtep \ +- $(am__append_43) vtep/vtep.5 vtep/vtep.ovsschema.stamp \ ++ $(am__append_44) vtep/vtep.5 vtep/vtep.ovsschema.stamp \ + $(srcdir)/datapath-windows/include/OvsDpInterface.h \ + selinux/openvswitch-custom.te selinux/openvswitch-custom.pp \ + selinux/openvswitch-custom.fc selinux/openvswitch-custom.if +@@ -1602,7 +1605,7 @@ CLEANFILES = all-distfiles all-gitfiles missing-distfiles distfiles \ + # lcov support + # Requires build with --enable-coverage and lcov/genhtml in $PATH + CLEAN_LOCAL = clean-pycov $(am__append_10) $(am__append_13) clean-lcov \ +- $(am__append_39) ++ $(am__append_40) + DISTCLEANFILES = tests/atconfig tests/atlocal \ + rhel/usr_lib_systemd_system_ovs-vswitchd.service + PYCOV_CLEAN_FILES = build-aux/check-structs,cover \ +@@ -1986,7 +1989,7 @@ noinst_HEADERS = $(EXTRA_DIST) include/sparse/rte_byteorder.h \ + lib_LTLIBRARIES = lib/libopenvswitch.la $(am__append_15) \ + lib/libsflow.la ofproto/libofproto.la ovsdb/libovsdb.la \ + vtep/libvtep.la +-noinst_LTLIBRARIES = $(am__append_40) ++noinst_LTLIBRARIES = $(am__append_41) + noinst_man_MANS = + + # ovsdb-idlc +@@ -2015,7 +2018,7 @@ completion_SCRIPTS = utilities/ovs-appctl-bashcomp.bash \ + utilities/ovs-vsctl-bashcomp.bash + scripts_DATA = utilities/ovs-lib + SUFFIXES = .in .xml .h .hstamp .ovsidl .ovsschema +-check_DATA = $(am__append_37) ++check_DATA = $(am__append_38) + check_SCRIPTS = utilities/ovs-appctl-bashcomp.bash \ + utilities/ovs-vsctl-bashcomp.bash tests/atlocal + pkgconfig_DATA = lib/libopenvswitch.pc lib/libsflow.pc \ +@@ -2256,7 +2259,8 @@ extract_stem_and_section = \ + test -n "$$mandir" || { echo "unknown directory for manpage section $$section"; continue; } + + lib_libopenvswitch_la_LIBADD = $(SSL_LIBS) $(CAPNG_LDADD) \ +- $(LIBBPF_LDADD) $(am__append_14) $(am__append_16) ++ $(LIBBPF_LDADD) $(am__append_14) $(am__append_16) \ ++ $(am__append_23) + lib_libopenvswitch_la_LDFLAGS = \ + $(OVS_LTINFO) \ + -Wl,--version-script=$(top_builddir)/lib/libopenvswitch.sym \ +@@ -2286,16 +2290,17 @@ lib_libopenvswitch_la_SOURCES = lib/aes128.c lib/aes128.h \ + lib/ccmap.c lib/ccmap.h lib/cmap.c lib/cmap.h lib/colors.c \ + lib/colors.h lib/command-line.c lib/command-line.h \ + lib/compiler.h lib/connectivity.c lib/connectivity.h \ +- lib/conntrack-icmp.c lib/conntrack-private.h \ +- lib/conntrack-tcp.c lib/conntrack-tp.c lib/conntrack-tp.h \ +- lib/conntrack-other.c lib/conntrack.c lib/conntrack.h \ +- lib/coverage.c lib/coverage.h lib/crc32c.c lib/crc32c.h \ +- lib/csum.c lib/csum.h lib/ct-dpif.c lib/ct-dpif.h lib/daemon.c \ +- lib/daemon.h lib/daemon-private.h lib/db-ctl-base.c \ +- lib/db-ctl-base.h lib/dhcp.h lib/dummy.c lib/dummy.h \ +- lib/dhparams.h lib/dirs.h lib/dpctl.c lib/dpctl.h \ +- lib/dp-packet.h lib/dp-packet.c lib/dpdk.h \ +- lib/dpif-netdev-lookup.h lib/dpif-netdev-lookup.c \ ++ lib/hwoff_init_func.c lib/hwoff_init_func.h \ ++ lib/dpak_ovs.h lib/conntrack-icmp.c \ ++ lib/conntrack-private.h lib/conntrack-tcp.c lib/conntrack-tp.c \ ++ lib/conntrack-tp.h lib/conntrack-other.c lib/conntrack.c \ ++ lib/conntrack.h lib/ct_offload_provider.h lib/coverage.c \ ++ lib/coverage.h lib/crc32c.c lib/crc32c.h lib/csum.c lib/csum.h \ ++ lib/ct-dpif.c lib/ct-dpif.h lib/daemon.c lib/daemon.h \ ++ lib/daemon-private.h lib/db-ctl-base.c lib/db-ctl-base.h \ ++ lib/dhcp.h lib/dummy.c lib/dummy.h lib/dhparams.h lib/dirs.h \ ++ lib/dpctl.c lib/dpctl.h lib/dp-packet.h lib/dp-packet.c \ ++ lib/dpdk.h lib/dpif-netdev-lookup.h lib/dpif-netdev-lookup.c \ + lib/dpif-netdev-lookup-autovalidator.c \ + lib/dpif-netdev-lookup-generic.c lib/dpif-netdev.c \ + lib/dpif-netdev.h lib/dpif-netdev-private.h \ +@@ -2377,10 +2382,10 @@ lib_libopenvswitch_la_SOURCES = lib/aes128.c lib/aes128.h \ + lib/lldp/lldp-tlv.h lib/lldp/lldpd.c lib/lldp/lldpd.h \ + lib/lldp/lldpd-structs.c lib/lldp/lldpd-structs.h \ + $(am__append_17) $(am__append_18) $(am__append_21) \ +- $(am__append_22) $(am__append_23) $(am__append_24) \ +- $(am__append_25) $(am__append_26) $(am__append_27) \ +- $(am__append_28) $(am__append_29) $(am__append_30) \ +- lib/dns-resolve.h $(am__append_31) $(am__append_32) ++ $(am__append_22) $(am__append_24) $(am__append_25) \ ++ $(am__append_26) $(am__append_27) $(am__append_28) \ ++ $(am__append_29) $(am__append_30) $(am__append_31) \ ++ lib/dns-resolve.h $(am__append_32) $(am__append_33) + nodist_lib_libopenvswitch_la_SOURCES = \ + lib/dirs.c \ + lib/ovsdb-server-idl.c \ +@@ -2433,7 +2438,7 @@ ofproto_libofproto_la_SOURCES = ofproto/bond.c ofproto/bond.h \ + ofproto/bundles.c ofproto/bundles.h ofproto/ipfix-entities.def + ofproto_libofproto_la_CPPFLAGS = $(AM_CPPFLAGS) + ofproto_libofproto_la_CFLAGS = $(AM_CFLAGS) +-ofproto_libofproto_la_LIBADD = lib/libsflow.la $(am__append_33) ++ofproto_libofproto_la_LIBADD = lib/libsflow.la $(am__append_34) + dist_noinst_SCRIPTS = ofproto/ipfix-gen-entities + utilities_ovs_appctl_SOURCES = utilities/ovs-appctl.c + utilities_ovs_appctl_LDADD = lib/libopenvswitch.la +@@ -2692,7 +2697,7 @@ tests_ovstest_SOURCES = tests/ovstest.c tests/ovstest.h \ + tests/test-sha1.c tests/test-skiplist.c tests/test-stp.c \ + tests/test-unixctl.c tests/test-util.c tests/test-uuid.c \ + tests/test-bitmap.c tests/test-vconn.c tests/test-aa.c \ +- tests/test-stopwatch.c $(am__append_35) $(am__append_36) ++ tests/test-stopwatch.c $(am__append_36) $(am__append_37) + tests_ovstest_LDADD = lib/libopenvswitch.la + tests_test_stream_SOURCES = tests/test-stream.c + tests_test_stream_LDADD = lib/libopenvswitch.la +@@ -3257,6 +3262,8 @@ lib/cmap.lo: lib/$(am__dirstamp) lib/$(DEPDIR)/$(am__dirstamp) + lib/colors.lo: lib/$(am__dirstamp) lib/$(DEPDIR)/$(am__dirstamp) + lib/command-line.lo: lib/$(am__dirstamp) lib/$(DEPDIR)/$(am__dirstamp) + lib/connectivity.lo: lib/$(am__dirstamp) lib/$(DEPDIR)/$(am__dirstamp) ++lib/hwoff_init_func.lo: lib/$(am__dirstamp) \ ++ lib/$(DEPDIR)/$(am__dirstamp) + lib/conntrack-icmp.lo: lib/$(am__dirstamp) \ + lib/$(DEPDIR)/$(am__dirstamp) + lib/conntrack-tcp.lo: lib/$(am__dirstamp) \ +@@ -4218,6 +4225,7 @@ distclean-compile: + @AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/hindex.Plo@am__quote@ # am--include-marker + @AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/hmap.Plo@am__quote@ # am--include-marker + @AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/hmapx.Plo@am__quote@ # am--include-marker ++@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/hwoff_init_func.Plo@am__quote@ # am--include-marker + @AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/id-pool.Plo@am__quote@ # am--include-marker + @AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/if-notifier-bsd.Plo@am__quote@ # am--include-marker + @AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/if-notifier-manual.Plo@am__quote@ # am--include-marker +@@ -5670,6 +5678,7 @@ distclean: distclean-recursive + -rm -f lib/$(DEPDIR)/hindex.Plo + -rm -f lib/$(DEPDIR)/hmap.Plo + -rm -f lib/$(DEPDIR)/hmapx.Plo ++ -rm -f lib/$(DEPDIR)/hwoff_init_func.Plo + -rm -f lib/$(DEPDIR)/id-pool.Plo + -rm -f lib/$(DEPDIR)/if-notifier-bsd.Plo + -rm -f lib/$(DEPDIR)/if-notifier-manual.Plo +@@ -6048,6 +6057,7 @@ maintainer-clean: maintainer-clean-recursive + -rm -f lib/$(DEPDIR)/hindex.Plo + -rm -f lib/$(DEPDIR)/hmap.Plo + -rm -f lib/$(DEPDIR)/hmapx.Plo ++ -rm -f lib/$(DEPDIR)/hwoff_init_func.Plo + -rm -f lib/$(DEPDIR)/id-pool.Plo + -rm -f lib/$(DEPDIR)/if-notifier-bsd.Plo + -rm -f lib/$(DEPDIR)/if-notifier-manual.Plo +diff --git a/openvswitch-2.14.2/acinclude.m4 b/openvswitch-2.14.2/acinclude.m4 +index 237b221..7b64d53 100644 +--- a/openvswitch-2.14.2/acinclude.m4 ++++ b/openvswitch-2.14.2/acinclude.m4 +@@ -334,8 +334,9 @@ dnl + dnl Configure DPDK source tree + AC_DEFUN([OVS_CHECK_DPDK], [ + AC_ARG_WITH([dpdk], +- [AC_HELP_STRING([--with-dpdk=/path/to/dpdk], +- [Specify the DPDK build directory])], ++ [AC_HELP_STRING([--with-dpdk=static|shared|yes], ++ [Specify "static" or "shared" depending on the ++ DPDK libraries to use])], + [have_dpdk=true]) + + AC_MSG_CHECKING([whether dpdk is enabled]) +@@ -345,27 +346,36 @@ AC_DEFUN([OVS_CHECK_DPDK], [ + else + AC_MSG_RESULT([yes]) + case "$with_dpdk" in +- yes) +- DPDK_AUTO_DISCOVER="true" +- PKG_CHECK_MODULES_STATIC([DPDK], [libdpdk], [ +- DPDK_INCLUDE="$DPDK_CFLAGS" +- DPDK_LIB="$DPDK_LIBS"], [ +- DPDK_INCLUDE="-I/usr/local/include/dpdk -I/usr/include/dpdk" +- DPDK_LIB="-ldpdk"]) +- ;; +- *) +- DPDK_AUTO_DISCOVER="false" +- DPDK_INCLUDE_PATH="$with_dpdk/include" +- # If 'with_dpdk' is passed install directory, point to headers +- # installed in $DESTDIR/$prefix/include/dpdk +- if test -e "$DPDK_INCLUDE_PATH/rte_config.h"; then +- DPDK_INCLUDE="-I$DPDK_INCLUDE_PATH" +- elif test -e "$DPDK_INCLUDE_PATH/dpdk/rte_config.h"; then +- DPDK_INCLUDE="-I$DPDK_INCLUDE_PATH/dpdk" +- fi +- DPDK_LIB_DIR="$with_dpdk/lib" +- DPDK_LIB="-ldpdk" +- ;; ++ "shared") ++ PKG_CHECK_MODULES([DPDK], [libdpdk], [ ++ DPDK_INCLUDE="$DPDK_CFLAGS" ++ DPDK_LIB="$DPDK_LIBS"]) ++ ;; ++ "static" | "yes") ++ PKG_CHECK_MODULES_STATIC([DPDK], [libdpdk], [ ++ DPDK_INCLUDE="$DPDK_CFLAGS" ++ DPDK_LIB="$DPDK_LIBS"]) ++ ++ dnl Statically linked private DPDK objects of form ++ dnl -l:file.a must be positioned between ++ dnl --whole-archive ... --no-whole-archive linker parameters. ++ dnl Old pkg-config versions misplace --no-whole-archive parameter ++ dnl and put it next to --whole-archive. ++ AC_MSG_CHECKING([for faulty pkg-config version]) ++ echo "$DPDK_LIB" | grep -q 'whole-archive.*l:lib.*no-whole-archive' ++ status=$? ++ case $status in ++ 0) ++ AC_MSG_RESULT([no]) ++ ;; ++ 1) ++ AC_MSG_RESULT([yes]) ++ AC_MSG_ERROR([Please upgrade pkg-config]) ++ ;; ++ *) ++ AC_MSG_ERROR([grep exited with status $status]) ++ ;; ++ esac + esac + + ovs_save_CFLAGS="$CFLAGS" +@@ -454,17 +464,15 @@ AC_DEFUN([OVS_CHECK_DPDK], [ + # This happens because the rest of the DPDK code doesn't use any symbol in + # the pmd driver objects, and the drivers register themselves using an + # __attribute__((constructor)) function. +- # +- # These options are specified inside a single -Wl directive to prevent +- # autotools from reordering them. +- # +- # OTOH newer versions of dpdk pkg-config (generated with Meson) +- # will already have flagged just the right set of libs with +- # --whole-archive - in those cases do not wrap it once more. +- case "$DPDK_LIB" in +- *whole-archive*) DPDK_vswitchd_LDFLAGS=$DPDK_LIB;; +- *) DPDK_vswitchd_LDFLAGS=-Wl,--whole-archive,$DPDK_LIB,--no-whole-archive +- esac ++ # Wrap the DPDK libraries inside a single -Wl directive ++ # after comma separation to prevent autotools from reordering them. ++ DPDK_vswitchd_LDFLAGS=$(echo "$DPDK_LIB"| tr -s ' ' ',' | sed 's/-Wl,//g') ++ # Replace -pthread with -lpthread for LD and remove the last extra comma. ++ DPDK_vswitchd_LDFLAGS=$(echo "$DPDK_vswitchd_LDFLAGS"| sed 's/,$//' | \ ++ sed 's/-pthread/-lpthread/g') ++ # Prepend "-Wl,". ++ DPDK_vswitchd_LDFLAGS="-Wl,$DPDK_vswitchd_LDFLAGS" ++ + AC_SUBST([DPDK_vswitchd_LDFLAGS]) + AC_DEFINE([DPDK_NETDEV], [1], [System uses the DPDK module.]) + fi +@@ -472,6 +480,22 @@ AC_DEFUN([OVS_CHECK_DPDK], [ + AM_CONDITIONAL([DPDK_NETDEV], test "$DPDKLIB_FOUND" = true) + ]) + ++dnl OVS_CHECK_HWOFF_AGENT ++dnl ++dnl Check whether we're building with ipu. ++AC_DEFUN([OVS_CHECK_HWOFF_AGENT], ++ [AC_ARG_ENABLE( ++ [hwoff], ++ [AC_HELP_STRING([--enable-hwoff], [Enable OVS hwoff support])], ++ [], [enable_hwoff=no]) ++ ++ if test "x$enable_hwoff" = xyes; then ++ AC_DEFINE([HAVE_HWOFF_AGENT], [1], [ovs enable hwoff]) ++ CFLAGS="$CFLAGS -I/usr/include/hwoff_agent" ++ fi ++ AM_CONDITIONAL([HAVE_HWOFF_AGENT], [test $enable_hwoff = yes]) ++ ]) ++ + dnl OVS_GREP_IFELSE(FILE, REGEX, [IF-MATCH], [IF-NO-MATCH]) + dnl + dnl Greps FILE for REGEX. If it matches, runs IF-MATCH, otherwise IF-NO-MATCH. +@@ -1220,7 +1244,7 @@ dnl with or without modifications, as long as this notice is preserved. + + AC_DEFUN([_OVS_CHECK_CC_OPTION], [dnl + m4_define([ovs_cv_name], [ovs_cv_[]m4_translit([$1], [-= ], [__])])dnl +- AC_CACHE_CHECK([whether $CC accepts $1], [ovs_cv_name], ++ AC_CACHE_CHECK([whether $CC accepts $1], [ovs_cv_name], + [ovs_save_CFLAGS="$CFLAGS" + dnl Include -Werror in the compiler options, because without -Werror + dnl clang's GCC-compatible compiler driver does not return a failure +@@ -1275,7 +1299,7 @@ dnl OVS_ENABLE_OPTION([OPTION]) + dnl Check whether the given C compiler OPTION is accepted. + dnl If so, add it to WARNING_FLAGS. + dnl Example: OVS_ENABLE_OPTION([-Wdeclaration-after-statement]) +-AC_DEFUN([OVS_ENABLE_OPTION], ++AC_DEFUN([OVS_ENABLE_OPTION], + [OVS_CHECK_CC_OPTION([$1], [WARNING_FLAGS="$WARNING_FLAGS $1"]) + AC_SUBST([WARNING_FLAGS])]) + +diff --git a/openvswitch-2.14.2/configure b/openvswitch-2.14.2/configure +index cb32f48..22658cc 100644 +--- a/openvswitch-2.14.2/configure ++++ b/openvswitch-2.14.2/configure +@@ -1599,8 +1599,9 @@ Optional Packages: + Specify the Linux kernel source directory (usually + figured out automatically from build directory) + +- --with-dpdk=/path/to/dpdk +- Specify the DPDK build directory ++ --with-dpdk=static|shared|yes ++ Specify "static" or "shared" depending on the DPDK ++ libraries to use + + Some influential environment variables: + CC C compiler command +@@ -30699,9 +30700,103 @@ $as_echo "no" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 + $as_echo "yes" >&6; } + case "$with_dpdk" in +- yes) +- DPDK_AUTO_DISCOVER="true" +- _save_PKG_CONFIG=$PKG_CONFIG ++ "shared") ++ ++pkg_failed=no ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for DPDK" >&5 ++$as_echo_n "checking for DPDK... " >&6; } ++ ++if test -n "$DPDK_CFLAGS"; then ++ pkg_cv_DPDK_CFLAGS="$DPDK_CFLAGS" ++ elif test -n "$PKG_CONFIG"; then ++ if test -n "$PKG_CONFIG" && \ ++ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libdpdk\""; } >&5 ++ ($PKG_CONFIG --exists --print-errors "libdpdk") 2>&5 ++ ac_status=$? ++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 ++ test $ac_status = 0; }; then ++ pkg_cv_DPDK_CFLAGS=`$PKG_CONFIG --cflags "libdpdk" 2>/dev/null` ++ test "x$?" != "x0" && pkg_failed=yes ++else ++ pkg_failed=yes ++fi ++ else ++ pkg_failed=untried ++fi ++if test -n "$DPDK_LIBS"; then ++ pkg_cv_DPDK_LIBS="$DPDK_LIBS" ++ elif test -n "$PKG_CONFIG"; then ++ if test -n "$PKG_CONFIG" && \ ++ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libdpdk\""; } >&5 ++ ($PKG_CONFIG --exists --print-errors "libdpdk") 2>&5 ++ ac_status=$? ++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 ++ test $ac_status = 0; }; then ++ pkg_cv_DPDK_LIBS=`$PKG_CONFIG --libs "libdpdk" 2>/dev/null` ++ test "x$?" != "x0" && pkg_failed=yes ++else ++ pkg_failed=yes ++fi ++ else ++ pkg_failed=untried ++fi ++ ++ ++ ++if test $pkg_failed = yes; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++ ++if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then ++ _pkg_short_errors_supported=yes ++else ++ _pkg_short_errors_supported=no ++fi ++ if test $_pkg_short_errors_supported = yes; then ++ DPDK_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libdpdk" 2>&1` ++ else ++ DPDK_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libdpdk" 2>&1` ++ fi ++ # Put the nasty error message in config.log where it belongs ++ echo "$DPDK_PKG_ERRORS" >&5 ++ ++ as_fn_error $? "Package requirements (libdpdk) were not met: ++ ++$DPDK_PKG_ERRORS ++ ++Consider adjusting the PKG_CONFIG_PATH environment variable if you ++installed software in a non-standard prefix. ++ ++Alternatively, you may set the environment variables DPDK_CFLAGS ++and DPDK_LIBS to avoid the need to call pkg-config. ++See the pkg-config man page for more details." "$LINENO" 5 ++elif test $pkg_failed = untried; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 ++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} ++as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it ++is in your PATH or set the PKG_CONFIG environment variable to the full ++path to pkg-config. ++ ++Alternatively, you may set the environment variables DPDK_CFLAGS ++and DPDK_LIBS to avoid the need to call pkg-config. ++See the pkg-config man page for more details. ++ ++To get pkg-config, see . ++See \`config.log' for more details" "$LINENO" 5; } ++else ++ DPDK_CFLAGS=$pkg_cv_DPDK_CFLAGS ++ DPDK_LIBS=$pkg_cv_DPDK_LIBS ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 ++$as_echo "yes" >&6; } ++ ++ DPDK_INCLUDE="$DPDK_CFLAGS" ++ DPDK_LIB="$DPDK_LIBS" ++fi ++ ;; ++ "static" | "yes") ++ _save_PKG_CONFIG=$PKG_CONFIG + PKG_CONFIG="$PKG_CONFIG --static" + + pkg_failed=no +@@ -31499,17 +31594,15 @@ $as_echo "$ovs_cv__mssse3" >&6; } + # This happens because the rest of the DPDK code doesn't use any symbol in + # the pmd driver objects, and the drivers register themselves using an + # __attribute__((constructor)) function. +- # +- # These options are specified inside a single -Wl directive to prevent +- # autotools from reordering them. +- # +- # OTOH newer versions of dpdk pkg-config (generated with Meson) +- # will already have flagged just the right set of libs with +- # --whole-archive - in those cases do not wrap it once more. +- case "$DPDK_LIB" in +- *whole-archive*) DPDK_vswitchd_LDFLAGS=$DPDK_LIB;; +- *) DPDK_vswitchd_LDFLAGS=-Wl,--whole-archive,$DPDK_LIB,--no-whole-archive +- esac ++ # Wrap the DPDK libraries inside a single -Wl directive ++ # after comma separation to prevent autotools from reordering them. ++ DPDK_vswitchd_LDFLAGS=$(echo "$DPDK_LIB"| tr -s ' ' ',' | sed 's/-Wl,//g') ++ # Replace -pthread with -lpthread for LD and remove the last extra comma. ++ DPDK_vswitchd_LDFLAGS=$(echo "$DPDK_vswitchd_LDFLAGS"| sed 's/,$//' | \ ++ sed 's/-pthread/-lpthread/g') ++ # Prepend "-Wl,". ++ DPDK_vswitchd_LDFLAGS="-Wl,$DPDK_vswitchd_LDFLAGS" ++ + + + $as_echo "#define DPDK_NETDEV 1" >>confdefs.h +diff --git a/openvswitch-2.14.2/configure.ac b/openvswitch-2.14.2/configure.ac +index ee52e33..44dcc97 100644 +--- a/openvswitch-2.14.2/configure.ac ++++ b/openvswitch-2.14.2/configure.ac +@@ -195,6 +195,7 @@ OVS_CHECK_LINUX_TC + OVS_CHECK_LINUX_SCTP_CT + OVS_CHECK_LINUX_VIRTIO_TYPES + OVS_CHECK_DPDK ++OVS_CHECK_HWOFF_AGENT + OVS_CHECK_PRAGMA_MESSAGE + AC_SUBST([OVS_CFLAGS]) + AC_SUBST([OVS_LDFLAGS]) +diff --git a/openvswitch-2.14.2/lib/adapter/ovs_adapter.h b/openvswitch-2.14.2/lib/adapter/ovs_adapter.h +new file mode 100644 +index 0000000..caa705c +--- /dev/null ++++ b/openvswitch-2.14.2/lib/adapter/ovs_adapter.h +@@ -0,0 +1,124 @@ ++/* ++ * Copyright (c) 2022-2022. Huawei Technologies Co., Ltd. ++ * Description: ovs adapter file ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ * ++ * Create: 2022-09-24 ++ */ ++ ++#ifndef _OVS_ADAPTER_H ++#define _OVS_ADAPTER_H ++ ++#include ++#include "ovs-atomic.h" ++#include "cmap.h" ++#include "conntrack-private.h" ++#include "conntrack-tp.h" ++#include "conntrack.h" ++#include "dp-packet.h" ++#include "dpif-netdev.h" ++#include "hash.h" ++#include "latch.h" ++#include "mac-learning.h" ++#include "netdev-provider.h" ++#include "netdev-dpdk.h" ++#include "packets.h" ++#include "random.h" ++#include "ovs-rcu.h" ++#include "smap.h" ++#include "ovs-thread.h" ++#include "timeval.h" ++#include "unaligned.h" ++#include "unixctl.h" ++#include "util.h" ++#include "uuid.h" ++#include "openvswitch/dynamic-string.h" ++#include "openvswitch/hmap.h" ++#include "openvswitch/ofpbuf.h" ++#include "openvswitch/util.h" ++#include "openvswitch/poll-loop.h" ++#include "openvswitch/shash.h" ++ ++void atomic_count_init_ext(atomic_count *count, unsigned int value); ++unsigned int atomic_count_inc_ext(atomic_count *count); ++unsigned int atomic_count_dec_ext(atomic_count *count); ++unsigned int atomic_count_get_ext(atomic_count *count); ++void atomic_count_set_ext(atomic_count *count, unsigned int value); ++ ++struct cmap_node* cmap_node_next_ext(const struct cmap_node *node); ++struct cmap_node* cmap_node_next_protected_ext(const struct cmap_node *node); ++size_t cmap_remove_ext(struct cmap *cmap, struct cmap_node *node, uint32_t hash); ++ ++void conn_update_expiration_int(struct conntrack *ct, struct conn *conn, ++ int tm, long long now); ++void conn_update_expiration_no_lock_int(struct conntrack *ct, struct conn *conn, ++ int tm, long long now); ++uint32_t ct_get_hash_basis(struct conntrack *ct); ++struct conn_key* conn_get_key_addr(const struct conn *conn); ++struct conn_key* conn_get_rev_key_addr(const struct conn *conn); ++struct conn* conn_get_nat_conn(const struct conn *conn); ++void* conn_get_offload_info_addr(const struct conn *conn); ++void* conn_get_nat_info(const struct conn *conn); ++bool conn_get_cleaned(const struct conn *conn); ++struct ovs_mutex* conn_get_lock_addr(const struct conn *conn); ++int tcp_conn_timeout_get_int(const struct conn *conn); ++int icmp_conn_timeout_get_int(const struct conn *conn); ++int other_conn_timeout_get_int(const struct conn *conn); ++void ct_dpif_entry_set_print_offload(struct ct_dpif_entry *entry, ++ bool print_offload); ++void ct_dpif_entry_set_init_dir_offload_state(struct ct_dpif_entry *entry, ++ const char *state); ++void ct_dpif_entry_set_reply_dir_offload_state(struct ct_dpif_entry *entry, ++ const char *state); ++ ++size_t dp_packet_struct_size(void); ++void* dp_packet_data_ext(const struct dp_packet *b); ++struct rte_mbuf* dp_packet_get_mbuf_addr(const struct dp_packet *b); ++struct pkt_metadata* dp_packet_get_md_addr(const struct dp_packet *b); ++uint32_t dp_packet_size_ext(const struct dp_packet *b); ++ ++uint32_t hash_int_ext(uint32_t x, uint32_t basis); ++uint32_t hash_bytes_ext(const void *arg, size_t n_bytes, uint32_t basis); ++uint32_t hash_uint64_ext(const uint64_t x); ++uint32_t hash_add_ext(uint32_t hash, uint32_t data); ++ ++bool hmap_is_empty_ext(const struct hmap *hmap); ++size_t hmap_count_ext(const struct hmap *hmap); ++struct hmap_node* hmap_first_ext(const struct hmap *hmap); ++struct hmap_node* hmap_next_ext(const struct hmap *hmap, const struct hmap_node *node); ++void hmap_insert_at_ext(struct hmap *hmap, struct hmap_node *node, size_t hash, const char *where); ++void hmap_remove_ext(struct hmap *hmap, struct hmap_node *node); ++struct hmap_node* hmap_first_with_hash_ext(const struct hmap *hmap, size_t hash); ++struct hmap_node* hmap_next_with_hash_ext(const struct hmap *hmap); ++ ++const char* netdev_class_get_type(struct netdev_class *netdev_class); ++uint16_t netdev_class_get_if_index(struct netdev_class *netdev_class, struct netdev *netdev); ++ ++uint16_t vlan_tci_to_vid_ext(ovs_be16 vlan_tci); ++void ipv6_format_addr_ext(const struct in6_addr *addr, struct ds *ds); ++struct conn* pkt_metadata_get_conn(struct pkt_metadata *md); ++bool pkt_metadata_get_reply(struct pkt_metadata *md); ++bool* pkt_metadata_get_reply_addr(struct pkt_metadata *md); ++ ++void poll_timer_wait_ext(long long int msec); ++ ++bool ovsthread_once_start_ext(struct ovsthread_once *once); ++void ovs_mutex_lock_ext(const struct ovs_mutex *mutex); ++ ++ovs_be32 get_16aligned_be32_ext(const ovs_16aligned_be32 *x); ++ ++uint32_t hiovs_rte_flow_list_get_ext(ovs_u128 ufid_list[], struct rte_flow *flow_list[], uint32_t ufid_cnt); ++void hiovs_rte_flow_data_list_put_ext(void *flow_data_list[], uint32_t count); ++ ++#endif +\ No newline at end of file +diff --git a/openvswitch-2.14.2/lib/adapter/ovs_atomic_adapter.c b/openvswitch-2.14.2/lib/adapter/ovs_atomic_adapter.c +new file mode 100644 +index 0000000..3bcbec1 +--- /dev/null ++++ b/openvswitch-2.14.2/lib/adapter/ovs_atomic_adapter.c +@@ -0,0 +1,47 @@ ++/* ++ * Copyright (c) 2022-2022. Huawei Technologies Co., Ltd. ++ * Description: ovs atomic adapter file ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ * ++ * Create: 2022-09-24 ++ */ ++ ++#include ++#include "ovs-atomic.h" ++#include "ovs_adapter.h" ++ ++void atomic_count_init_ext(atomic_count *count, unsigned int value) ++{ ++ atomic_count_init(count, value); ++} ++ ++unsigned int atomic_count_inc_ext(atomic_count *count) ++{ ++ return atomic_count_inc(count); ++} ++ ++unsigned int atomic_count_dec_ext(atomic_count *count) ++{ ++ return atomic_count_dec(count); ++} ++ ++unsigned int atomic_count_get_ext(atomic_count *count) ++{ ++ return atomic_count_get(count); ++} ++ ++void atomic_count_set_ext(atomic_count *count, unsigned int value) ++{ ++ atomic_count_set(count, value); ++} +diff --git a/openvswitch-2.14.2/lib/adapter/ovs_cmap_adapter.c b/openvswitch-2.14.2/lib/adapter/ovs_cmap_adapter.c +new file mode 100644 +index 0000000..c18a2f6 +--- /dev/null ++++ b/openvswitch-2.14.2/lib/adapter/ovs_cmap_adapter.c +@@ -0,0 +1,37 @@ ++/* ++ * Copyright (c) 2022-2022. Huawei Technologies Co., Ltd. ++ * Description: ovs cmap adapter file ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ * ++ * Create: 2022-09-24 ++ */ ++ ++#include ++#include "cmap.h" ++#include "ovs_adapter.h" ++ ++struct cmap_node* cmap_node_next_ext(const struct cmap_node *node) ++{ ++ return cmap_node_next(node); ++} ++ ++struct cmap_node* cmap_node_next_protected_ext(const struct cmap_node *node) ++{ ++ return cmap_node_next_protected(node); ++} ++ ++size_t cmap_remove_ext(struct cmap *cmap, struct cmap_node *node, uint32_t hash) ++{ ++ return cmap_remove(cmap, node, hash); ++} +diff --git a/openvswitch-2.14.2/lib/adapter/ovs_conntrack_adapter.c b/openvswitch-2.14.2/lib/adapter/ovs_conntrack_adapter.c +new file mode 100644 +index 0000000..09fc667 +--- /dev/null ++++ b/openvswitch-2.14.2/lib/adapter/ovs_conntrack_adapter.c +@@ -0,0 +1,113 @@ ++/* ++ * Copyright (c) 2022-2022. Huawei Technologies Co., Ltd. ++ * Description: ovs conntrack adapter file ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ * ++ * Create: 2022-09-24 ++ */ ++ ++#include ++#include "conntrack-private.h" ++#include "conntrack-tp.h" ++#include "conntrack.h" ++#include "ovs_adapter.h" ++ ++uint32_t conn_key_hash(const struct conn_key *, uint32_t basis); ++bool conn_key_lookup(struct conntrack *ct, const struct conn_key *key, ++ uint32_t hash, long long now, struct conn **conn_out, bool *reply); ++ ++void conn_update_expiration_int(struct conntrack *ct, struct conn *conn, ++ int tm, long long now) ++{ ++ conn_update_expiration(ct, conn, tm, now); ++} ++ ++void conn_update_expiration_no_lock_int(struct conntrack *ct, struct conn *conn, ++ int tm, long long now) ++{ ++ conn_update_expiration_no_lock(ct, conn, tm, now); ++} ++ ++uint32_t ct_get_hash_basis(struct conntrack *ct) ++{ ++ return ct->hash_basis; ++} ++ ++struct conn_key* conn_get_key_addr(const struct conn *conn) ++{ ++ return &conn->key; ++} ++ ++struct conn_key* conn_get_rev_key_addr(const struct conn *conn) ++{ ++ return &conn->rev_key; ++} ++ ++struct conn* conn_get_nat_conn(const struct conn *conn) ++{ ++ return conn->nat_conn; ++} ++ ++void* conn_get_offload_info_addr(const struct conn *conn) ++{ ++ return &conn->offload_info; ++} ++ ++void* conn_get_nat_info(const struct conn *conn) ++{ ++ return conn->nat_info; ++} ++ ++bool conn_get_cleaned(const struct conn *conn) ++{ ++ return conn->cleaned; ++} ++ ++struct ovs_mutex* conn_get_lock_addr(const struct conn *conn) ++{ ++ return &conn->lock; ++} ++ ++int tcp_conn_timeout_get_int(const struct conn *conn) ++{ ++ return (int)tcp_conn_timeout_get(conn); ++} ++ ++int icmp_conn_timeout_get_int(const struct conn *conn) ++{ ++ return (int)icmp_conn_timeout_get(conn); ++} ++ ++int other_conn_timeout_get_int(const struct conn *conn) ++{ ++ return (int)other_conn_timeout_get(conn); ++} ++ ++void ct_dpif_entry_set_print_offload(struct ct_dpif_entry *entry, ++ bool print_offload) ++{ ++ entry->print_offload = print_offload; ++} ++ ++void ct_dpif_entry_set_init_dir_offload_state(struct ct_dpif_entry *entry, ++ const char *state) ++{ ++ entry->init_dir_offload_state = state; ++} ++ ++void ct_dpif_entry_set_reply_dir_offload_state(struct ct_dpif_entry *entry, ++ const char *state) ++{ ++ entry->reply_dir_offload_state = state; ++} +diff --git a/openvswitch-2.14.2/lib/adapter/ovs_dp_adapter.c b/openvswitch-2.14.2/lib/adapter/ovs_dp_adapter.c +new file mode 100644 +index 0000000..00d54bb +--- /dev/null ++++ b/openvswitch-2.14.2/lib/adapter/ovs_dp_adapter.c +@@ -0,0 +1,48 @@ ++/* ++ * Copyright (c) 2022-2022. Huawei Technologies Co., Ltd. ++ * Description: ovs dp_packet adapter file ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ * ++ * Create: 2022-09-24 ++ */ ++ ++#include "config.h" ++#include "dp-packet.h" ++#include "dpif-netdev.h" ++#include "ovs_adapter.h" ++ ++size_t dp_packet_struct_size(void) ++{ ++ return sizeof(struct dp_packet); ++} ++ ++void* dp_packet_data_ext(const struct dp_packet *b) ++{ ++ return dp_packet_data(b); ++} ++ ++struct rte_mbuf* dp_packet_get_mbuf_addr(const struct dp_packet *b) ++{ ++ return &b->mbuf; ++} ++ ++struct pkt_metadata* dp_packet_get_md_addr(const struct dp_packet *b) ++{ ++ return &b->md; ++} ++ ++uint32_t dp_packet_size_ext(const struct dp_packet *b) ++{ ++ return dp_packet_size(b); ++} +diff --git a/openvswitch-2.14.2/lib/adapter/ovs_hash_adapter.c b/openvswitch-2.14.2/lib/adapter/ovs_hash_adapter.c +new file mode 100644 +index 0000000..d638ff0 +--- /dev/null ++++ b/openvswitch-2.14.2/lib/adapter/ovs_hash_adapter.c +@@ -0,0 +1,42 @@ ++/* ++ * Copyright (c) 2022-2022. Huawei Technologies Co., Ltd. ++ * Description: ovs hash adapter file ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ * ++ * Create: 2022-09-24 ++ */ ++ ++#include "config.h" ++#include "hash.h" ++#include "ovs_adapter.h" ++ ++uint32_t hash_int_ext(uint32_t x, uint32_t basis) ++{ ++ return hash_int(x, basis); ++} ++ ++uint32_t hash_bytes_ext(const void *arg, size_t n_bytes, uint32_t basis) ++{ ++ return hash_bytes(arg, n_bytes, basis); ++} ++ ++uint32_t hash_uint64_ext(const uint64_t x) ++{ ++ return hash_uint64(x); ++} ++ ++uint32_t hash_add_ext(uint32_t hash, uint32_t data) ++{ ++ return hash_add(hash, data); ++} +diff --git a/openvswitch-2.14.2/lib/adapter/ovs_hiovs_flow_adapter.c b/openvswitch-2.14.2/lib/adapter/ovs_hiovs_flow_adapter.c +new file mode 100644 +index 0000000..9b228a4 +--- /dev/null ++++ b/openvswitch-2.14.2/lib/adapter/ovs_hiovs_flow_adapter.c +@@ -0,0 +1,31 @@ ++/* ++ * Copyright (c) 2022-2022. Huawei Technologies Co., Ltd. ++ * Description: ovs hiovs flow adapter file ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ * ++ * Create: 2022-09-24 ++ */ ++#include "config.h" ++#include "openvswitch/util.h" ++#include "ovs_adapter.h" ++ ++uint32_t hiovs_rte_flow_list_get_ext(ovs_u128 ufid_list[], struct rte_flow *flow_list[], uint32_t ufid_cnt) ++{ ++ return hiovs_rte_flow_list_get(ufid_list, flow_list, ufid_cnt); ++} ++ ++void hiovs_rte_flow_data_list_put_ext(void *flow_data_list[], uint32_t count) ++{ ++ return hiovs_rte_flow_data_list_put(flow_data_list, count); ++} +\ No newline at end of file +diff --git a/openvswitch-2.14.2/lib/adapter/ovs_hmap_adapter.c b/openvswitch-2.14.2/lib/adapter/ovs_hmap_adapter.c +new file mode 100644 +index 0000000..fee67f9 +--- /dev/null ++++ b/openvswitch-2.14.2/lib/adapter/ovs_hmap_adapter.c +@@ -0,0 +1,62 @@ ++/* ++ * Copyright (c) 2022-2022. Huawei Technologies Co., Ltd. ++ * Description: ovs hmap adapter file ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ * ++ * Create: 2022-09-24 ++ */ ++ ++#include "ovs_adapter.h" ++#include "config.h" ++#include "openvswitch/hmap.h" ++ ++bool hmap_is_empty_ext(const struct hmap *hmap) ++{ ++ return hmap_is_empty(hmap); ++} ++ ++size_t hmap_count_ext(const struct hmap *hmap) ++{ ++ return hmap_count(hmap); ++} ++ ++struct hmap_node* hmap_first_ext(const struct hmap *hmap) ++{ ++ return hmap_first(hmap); ++} ++ ++struct hmap_node* hmap_next_ext(const struct hmap *hmap, const struct hmap_node *node) ++{ ++ return hmap_next(hmap, node); ++} ++ ++void hmap_insert_at_ext(struct hmap *hmap, struct hmap_node *node, size_t hash, const char *where) ++{ ++ return hmap_insert_at(hmap, node, hash, where); ++} ++ ++void hmap_remove_ext(struct hmap *hmap, struct hmap_node *node) ++{ ++ return hmap_remove(hmap, node); ++} ++ ++struct hmap_node* hmap_first_with_hash_ext(const struct hmap *hmap, size_t hash) ++{ ++ return hmap_first_with_hash(hmap, hash); ++} ++ ++struct hmap_node* hmap_next_with_hash_ext(const struct hmap *hmap) ++{ ++ return hmap_next_with_hash(hmap); ++} +diff --git a/openvswitch-2.14.2/lib/adapter/ovs_netdev_adapter.c b/openvswitch-2.14.2/lib/adapter/ovs_netdev_adapter.c +new file mode 100644 +index 0000000..0692f6c +--- /dev/null ++++ b/openvswitch-2.14.2/lib/adapter/ovs_netdev_adapter.c +@@ -0,0 +1,32 @@ ++/* ++ * Copyright (c) 2022-2022. Huawei Technologies Co., Ltd. ++ * Description: ovs netdev adapter file ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ * ++ * Create: 2022-09-24 ++ */ ++ ++#include "config.h" ++#include "netdev-provider.h" ++#include "ovs_adapter.h" ++ ++const char* netdev_class_get_type(struct netdev_class *netdev_class) ++{ ++ return netdev_class->type; ++} ++ ++uint16_t netdev_class_get_if_index(struct netdev_class *netdev_class, struct netdev *netdev) ++{ ++ return netdev_class->get_ifindex(netdev); ++} +diff --git a/openvswitch-2.14.2/lib/adapter/ovs_packet_adapter.c b/openvswitch-2.14.2/lib/adapter/ovs_packet_adapter.c +new file mode 100644 +index 0000000..89608d7 +--- /dev/null ++++ b/openvswitch-2.14.2/lib/adapter/ovs_packet_adapter.c +@@ -0,0 +1,47 @@ ++/* ++ * Copyright (c) 2022-2022. Huawei Technologies Co., Ltd. ++ * Description: ovs packet adapter file ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ * ++ * Create: 2022-09-24 ++ */ ++ ++#include "config.h" ++#include "packets.h" ++#include "ovs_adapter.h" ++ ++uint16_t vlan_tci_to_vid_ext(ovs_be16 vlan_tci) ++{ ++ return vlan_tci_to_vid(vlan_tci); ++} ++ ++void ipv6_format_addr_ext(const struct in6_addr *addr, struct ds *ds) ++{ ++ ipv6_format_addr(addr, ds); ++} ++ ++struct conn* pkt_metadata_get_conn(struct pkt_metadata *md) ++{ ++ return md->conn; ++} ++ ++bool pkt_metadata_get_reply(struct pkt_metadata *md) ++{ ++ return md->reply; ++} ++ ++bool* pkt_metadata_get_reply_addr(struct pkt_metadata *md) ++{ ++ return &md->reply; ++} +diff --git a/openvswitch-2.14.2/lib/adapter/ovs_poll_adapter.c b/openvswitch-2.14.2/lib/adapter/ovs_poll_adapter.c +new file mode 100644 +index 0000000..a21f62b +--- /dev/null ++++ b/openvswitch-2.14.2/lib/adapter/ovs_poll_adapter.c +@@ -0,0 +1,27 @@ ++/* ++ * Copyright (c) 2022-2022. Huawei Technologies Co., Ltd. ++ * Description: ovs poll adapter file ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ * ++ * Create: 2022-09-24 ++ */ ++#include "config.h" ++#include "openvswitch/util.h" ++#include "openvswitch/poll-loop.h" ++#include "ovs_adapter.h" ++ ++void poll_timer_wait_ext(long long int msec) ++{ ++ poll_timer_wait(msec); ++} +diff --git a/openvswitch-2.14.2/lib/adapter/ovs_thread_adapter.c b/openvswitch-2.14.2/lib/adapter/ovs_thread_adapter.c +new file mode 100644 +index 0000000..fa797c3 +--- /dev/null ++++ b/openvswitch-2.14.2/lib/adapter/ovs_thread_adapter.c +@@ -0,0 +1,31 @@ ++/* ++ * Copyright (c) 2022-2022. Huawei Technologies Co., Ltd. ++ * Description: ovs thread adapter file ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ * ++ * Create: 2022-09-24 ++ */ ++#include "config.h" ++#include "ovs-thread.h" ++#include "ovs_adapter.h" ++ ++bool ovsthread_once_start_ext(struct ovsthread_once *once) ++{ ++ return ovsthread_once_start(once); ++} ++ ++void ovs_mutex_lock_ext(const struct ovs_mutex *mutex) ++{ ++ ovs_mutex_lock(mutex); ++} +diff --git a/openvswitch-2.14.2/lib/adapter/ovs_unaligned_adapter.c b/openvswitch-2.14.2/lib/adapter/ovs_unaligned_adapter.c +new file mode 100644 +index 0000000..9ab0760 +--- /dev/null ++++ b/openvswitch-2.14.2/lib/adapter/ovs_unaligned_adapter.c +@@ -0,0 +1,27 @@ ++/* ++ * Copyright (c) 2022-2022. Huawei Technologies Co., Ltd. ++ * Description: ovs unalign adapter file ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ * ++ * Create: 2022-09-24 ++ */ ++ ++#include "config.h" ++#include "unaligned.h" ++#include "ovs_adapter.h" ++ ++ovs_be32 get_16aligned_be32_ext(const ovs_16aligned_be32 *x) ++{ ++ return get_16aligned_be32(x); ++} +diff --git a/openvswitch-2.14.2/lib/automake.mk b/openvswitch-2.14.2/lib/automake.mk +index 380a672..897bd1d 100644 +--- a/openvswitch-2.14.2/lib/automake.mk ++++ b/openvswitch-2.14.2/lib/automake.mk +@@ -82,6 +82,7 @@ lib_libopenvswitch_la_SOURCES = \ + lib/conntrack-other.c \ + lib/conntrack.c \ + lib/conntrack.h \ ++ lib/ct_offload_provider.h \ + lib/coverage.c \ + lib/coverage.h \ + lib/crc32c.c \ +@@ -365,7 +366,19 @@ lib_libopenvswitch_la_SOURCES = \ + lib/lldp/lldpd.c \ + lib/lldp/lldpd.h \ + lib/lldp/lldpd-structs.c \ +- lib/lldp/lldpd-structs.h ++ lib/lldp/lldpd-structs.h \ ++ lib/adapter/ovs_atomic_adapter.c \ ++ lib/adapter/ovs_cmap_adapter.c \ ++ lib/adapter/ovs_conntrack_adapter.c \ ++ lib/adapter/ovs_dp_adapter.c \ ++ lib/adapter/ovs_hash_adapter.c \ ++ lib/adapter/ovs_hmap_adapter.c \ ++ lib/adapter/ovs_netdev_adapter.c \ ++ lib/adapter/ovs_packet_adapter.c \ ++ lib/adapter/ovs_poll_adapter.c \ ++ lib/adapter/ovs_thread_adapter.c \ ++ lib/adapter/ovs_unaligned_adapter.c \ ++ lib/adapter/ovs_hiovs_flow_adapter.c + + if WIN32 + lib_libopenvswitch_la_SOURCES += \ +@@ -454,6 +467,14 @@ lib_libopenvswitch_la_SOURCES += \ + lib/netdev-afxdp.h + endif + ++if HAVE_HWOFF_AGENT ++lib_libopenvswitch_la_SOURCES += \ ++ lib/hwoff_init_func.c \ ++ lib/hwoff_init_func.h \ ++ lib/ct_dump_extend/ct_dump_extend.c \ ++ lib/ct_dump_extend/ct_dump_extend.h ++endif ++ + if DPDK_NETDEV + lib_libopenvswitch_la_SOURCES += \ + lib/dpdk.c \ +@@ -594,7 +615,7 @@ lib/meta-flow.inc: $(srcdir)/build-aux/extract-ofp-fields include/openvswitch/me + $(AM_V_GEN)$(run_python) $< meta-flow $(srcdir)/include/openvswitch/meta-flow.h > $@.tmp + $(AM_V_at)mv $@.tmp $@ + lib/meta-flow.lo: lib/meta-flow.inc +-lib/nx-match.inc: $(srcdir)/build-aux/extract-ofp-fields include/openvswitch/meta-flow.h ++lib/nx-match.inc: $(srcdir)/build-aux/extract-ofp-fields include/openvswitch/meta-flow.h + $(AM_V_GEN)$(run_python) $< nx-match $(srcdir)/include/openvswitch/meta-flow.h > $@.tmp + $(AM_V_at)mv $@.tmp $@ + lib/nx-match.lo: lib/nx-match.inc +diff --git a/openvswitch-2.14.2/lib/conntrack-icmp.c b/openvswitch-2.14.2/lib/conntrack-icmp.c +index b402970..4ea703c 100644 +--- a/openvswitch-2.14.2/lib/conntrack-icmp.c ++++ b/openvswitch-2.14.2/lib/conntrack-icmp.c +@@ -104,3 +104,9 @@ struct ct_l4_proto ct_proto_icmp6 = { + .valid_new = icmp6_valid_new, + .conn_update = icmp_conn_update, + }; ++ ++enum ct_timeout icmp_conn_timeout_get(const struct conn *conn) ++{ ++ struct conn_icmp *conn_icmp = conn_icmp_cast(conn); ++ return icmp_timeouts[conn_icmp->state]; ++} +diff --git a/openvswitch-2.14.2/lib/conntrack-other.c b/openvswitch-2.14.2/lib/conntrack-other.c +index d3b4601..67c7405 100644 +--- a/openvswitch-2.14.2/lib/conntrack-other.c ++++ b/openvswitch-2.14.2/lib/conntrack-other.c +@@ -88,3 +88,10 @@ struct ct_l4_proto ct_proto_other = { + .valid_new = other_valid_new, + .conn_update = other_conn_update, + }; ++ ++enum ct_timeout other_conn_timeout_get(const struct conn *conn) ++{ ++ struct conn_other *conn_other = conn_other_cast(conn); ++ return other_timeouts[conn_other->state]; ++} ++ +diff --git a/openvswitch-2.14.2/lib/conntrack-private.h b/openvswitch-2.14.2/lib/conntrack-private.h +index 3434753..f74eea5 100644 +--- a/openvswitch-2.14.2/lib/conntrack-private.h ++++ b/openvswitch-2.14.2/lib/conntrack-private.h +@@ -32,6 +32,10 @@ + #include "unaligned.h" + #include "dp-packet.h" + ++#ifdef HAVE_HWOFF_AGENT ++#include "ct_offload_provider.h" ++#endif ++ + struct ct_endpoint { + union ct_addr addr; + union { +@@ -88,6 +92,14 @@ enum OVS_PACKED_ENUM ct_conn_type { + CT_CONN_TYPE_UN_NAT, + }; + ++#ifdef HAVE_HWOFF_AGENT ++typedef struct { ++ conn_id conn_id; ++ bool is_ct_established; ++ void *conn_private_data; ++} ct_offload_info; ++#endif ++ + struct conn { + /* Immutable data. */ + struct conn_key key; +@@ -120,6 +132,17 @@ struct conn { + enum ct_conn_type conn_type; + + uint32_t tp_id; /* Timeout policy ID. */ ++#ifdef HAVE_HWOFF_AGENT ++ ct_offload_info offload_info; ++#endif ++}; ++ ++struct conn_lookup_ctx { ++ struct conn_key key; ++ struct conn *conn; ++ uint32_t hash; ++ bool reply; ++ bool icmp_related; + }; + + enum ct_update_res { +@@ -177,8 +200,15 @@ struct conntrack { + struct ipf *ipf; /* Fragmentation handling context. */ + uint32_t zone_limit_seq; /* Used to disambiguate zone limit counts. */ + atomic_bool tcp_seq_chk; /* Check TCP sequence numbers. */ ++#ifdef HAVE_HWOFF_AGENT ++ ct_offload_class *offload_class; ++#endif + }; + ++#ifdef HAVE_HWOFF_AGENT ++void reg_ct_offload_class(ct_offload_class *class); ++#endif ++ + /* Lock acquisition order: + * 1. 'ct_lock' + * 2. 'conn->lock' +@@ -213,4 +243,7 @@ tcp_payload_length(struct dp_packet *pkt) + } + } + ++enum ct_timeout tcp_conn_timeout_get(const struct conn *conn); ++enum ct_timeout icmp_conn_timeout_get(const struct conn *conn); ++enum ct_timeout other_conn_timeout_get(const struct conn *conn); + #endif /* conntrack-private.h */ +diff --git a/openvswitch-2.14.2/lib/conntrack-tcp.c b/openvswitch-2.14.2/lib/conntrack-tcp.c +index 18a2aa7..56334e0 100644 +--- a/openvswitch-2.14.2/lib/conntrack-tcp.c ++++ b/openvswitch-2.14.2/lib/conntrack-tcp.c +@@ -160,6 +160,43 @@ tcp_bypass_seq_chk(struct conntrack *ct) + return false; + } + ++static void ++tcp_conn_update_status(struct conntrack *ct, struct conn_tcp *conn, ++ bool reply, uint16_t tcp_flags, long long now) ++{ ++ struct tcp_peer *src = &conn->peer[reply ? 1 : 0]; ++ struct tcp_peer *dst = &conn->peer[reply ? 0 : 1]; ++ ++ if (tcp_flags & TCP_SYN && src->state < CT_DPIF_TCPS_SYN_SENT) { ++ src->state = CT_DPIF_TCPS_SYN_SENT; ++ } ++ if (tcp_flags & TCP_FIN && src->state < CT_DPIF_TCPS_CLOSING) { ++ src->state = CT_DPIF_TCPS_CLOSING; ++ } ++ if (tcp_flags & TCP_ACK) { ++ if (dst->state == CT_DPIF_TCPS_SYN_SENT) { ++ dst->state = CT_DPIF_TCPS_ESTABLISHED; ++ } else if (dst->state == CT_DPIF_TCPS_CLOSING) { ++ dst->state = CT_DPIF_TCPS_FIN_WAIT_2; ++ } ++ } ++ if (tcp_flags & TCP_RST) { ++ src->state = dst->state = CT_DPIF_TCPS_TIME_WAIT; ++ } ++ ++ if (src->state >= CT_DPIF_TCPS_FIN_WAIT_2 && dst->state >= CT_DPIF_TCPS_FIN_WAIT_2) { ++ conn_update_expiration(ct, &conn->up, CT_TM_TCP_CLOSED, now); ++ } else if (src->state >= CT_DPIF_TCPS_CLOSING && dst->state >= CT_DPIF_TCPS_CLOSING) { ++ conn_update_expiration(ct, &conn->up, CT_TM_TCP_FIN_WAIT, now); ++ } else if (src->state < CT_DPIF_TCPS_ESTABLISHED || dst->state < CT_DPIF_TCPS_ESTABLISHED) { ++ conn_update_expiration(ct, &conn->up, CT_TM_TCP_OPENING, now); ++ } else if (src->state >= CT_DPIF_TCPS_CLOSING || dst->state >= CT_DPIF_TCPS_CLOSING) { ++ conn_update_expiration(ct, &conn->up, CT_TM_TCP_CLOSING, now); ++ } else { ++ conn_update_expiration(ct, &conn->up, CT_TM_TCP_ESTABLISHED, now); ++ } ++} ++ + static enum ct_update_res + tcp_conn_update(struct conntrack *ct, struct conn *conn_, + struct dp_packet *pkt, bool reply, long long now) +@@ -408,8 +445,12 @@ tcp_conn_update(struct conntrack *ct, struct conn *conn_, + src->state = dst->state = CT_DPIF_TCPS_TIME_WAIT; + } + } else { ++#ifdef HAVE_HWOFF_AGENT ++ tcp_conn_update_status(ct, conn, reply, tcp_flags, now); ++#else + COVERAGE_INC(conntrack_tcp_seq_chk_failed); + return CT_UPDATE_INVALID; ++#endif + } + + return CT_UPDATE_VALID; +@@ -518,3 +559,25 @@ struct ct_l4_proto ct_proto_tcp = { + .conn_update = tcp_conn_update, + .conn_get_protoinfo = tcp_conn_get_protoinfo, + }; ++ ++enum ct_timeout tcp_conn_timeout_get(const struct conn *conn) ++{ ++ struct conn_tcp *conn_tcp = conn_tcp_cast(conn); ++ struct tcp_peer *src = &conn_tcp->peer[0]; ++ struct tcp_peer *dst = &conn_tcp->peer[1]; ++ enum ct_timeout tm; ++ ++ if (src->state >= CT_DPIF_TCPS_FIN_WAIT_2 && dst->state >= CT_DPIF_TCPS_FIN_WAIT_2) { ++ tm = CT_TM_TCP_CLOSED; ++ } else if (src->state >= CT_DPIF_TCPS_CLOSING && dst->state >= CT_DPIF_TCPS_CLOSING) { ++ tm = CT_TM_TCP_FIN_WAIT; ++ } else if (src->state < CT_DPIF_TCPS_ESTABLISHED || dst->state < CT_DPIF_TCPS_ESTABLISHED) { ++ tm = CT_TM_TCP_OPENING; ++ } else if (src->state >= CT_DPIF_TCPS_CLOSING || dst->state >= CT_DPIF_TCPS_CLOSING) { ++ tm = CT_TM_TCP_CLOSING; ++ } else { ++ tm = CT_TM_TCP_ESTABLISHED; ++ } ++ return tm; ++} ++ +diff --git a/openvswitch-2.14.2/lib/conntrack-tp.c b/openvswitch-2.14.2/lib/conntrack-tp.c +index a586d3a..ac2c48c 100644 +--- a/openvswitch-2.14.2/lib/conntrack-tp.c ++++ b/openvswitch-2.14.2/lib/conntrack-tp.c +@@ -281,6 +281,29 @@ conn_update_expiration(struct conntrack *ct, struct conn *conn, + conn_update_expiration__(ct, conn, tm, now, val); + } + ++#ifdef HAVE_HWOFF_AGENT ++/* The conn entry lock and ct_lock must be held by user */ ++void ++conn_update_expiration_no_lock(struct conntrack *ct, struct conn *conn, ++ enum ct_timeout tm, long long now) ++{ ++ struct timeout_policy *tp; ++ uint32_t val; ++ tp = timeout_policy_lookup(ct, conn->tp_id); ++ if (tp) { ++ val = tp->policy.attrs[tm_to_ct_dpif_tp(tm)]; ++ } else { ++ val = ct_dpif_netdev_tp_def[tm_to_ct_dpif_tp(tm)]; ++ } ++ ++ if (!conn->cleaned) { ++ conn->expiration = now + val * 1000; ++ ovs_list_remove(&conn->exp_node); ++ ovs_list_push_back(&ct->exp_lists[tm], &conn->exp_node); ++ } ++} ++#endif ++ + static void + conn_init_expiration__(struct conntrack *ct, struct conn *conn, + enum ct_timeout tm, long long now, +diff --git a/openvswitch-2.14.2/lib/conntrack-tp.h b/openvswitch-2.14.2/lib/conntrack-tp.h +index 4d411d1..58d9c89 100644 +--- a/openvswitch-2.14.2/lib/conntrack-tp.h ++++ b/openvswitch-2.14.2/lib/conntrack-tp.h +@@ -27,4 +27,8 @@ void conn_init_expiration(struct conntrack *ct, struct conn *conn, + enum ct_timeout tm, long long now); + void conn_update_expiration(struct conntrack *ct, struct conn *conn, + enum ct_timeout tm, long long now); ++#ifdef HAVE_HWOFF_AGENT ++void conn_update_expiration_no_lock(struct conntrack *ct, struct conn *conn, ++ enum ct_timeout tm, long long now); ++#endif + #endif +diff --git a/openvswitch-2.14.2/lib/conntrack.c b/openvswitch-2.14.2/lib/conntrack.c +index 6938dcb..9b3f743 100644 +--- a/openvswitch-2.14.2/lib/conntrack.c ++++ b/openvswitch-2.14.2/lib/conntrack.c +@@ -47,13 +47,7 @@ COVERAGE_DEFINE(conntrack_full); + COVERAGE_DEFINE(conntrack_long_cleanup); + COVERAGE_DEFINE(conntrack_l4csum_err); + +-struct conn_lookup_ctx { +- struct conn_key key; +- struct conn *conn; +- uint32_t hash; +- bool reply; +- bool icmp_related; +-}; ++ + + enum ftp_ctl_pkt { + /* Control packets with address and/or port specifiers. */ +@@ -83,10 +77,13 @@ struct zone_limit { + struct conntrack_zone_limit czl; + }; + +-static bool conn_key_extract(struct conntrack *, struct dp_packet *, +- ovs_be16 dl_type, struct conn_lookup_ctx *, +- uint16_t zone); +-static uint32_t conn_key_hash(const struct conn_key *, uint32_t basis); ++bool conn_key_extract(struct conntrack *, struct dp_packet *, ++ ovs_be16 dl_type, struct conn_lookup_ctx *, ++ uint16_t zone); ++uint32_t conn_key_hash(const struct conn_key *, uint32_t basis); ++bool conn_key_lookup(struct conntrack *ct, const struct conn_key *key, ++ uint32_t hash, long long now, struct conn **conn_out, bool *reply); ++void conn_to_ct_dpif_entry(const struct conn *conn, struct ct_dpif_entry *entry, long long now); + static void conn_key_reverse(struct conn_key *); + static bool valid_new(struct dp_packet *pkt, struct conn_key *); + static struct conn *new_conn(struct conntrack *ct, struct dp_packet *pkt, +@@ -288,6 +285,15 @@ ct_print_conn_info(const struct conn *c, const char *log_msg, + } + } + ++#ifdef HAVE_HWOFF_AGENT ++static ct_offload_class *g_ct_offload_class = NULL; ++void reg_ct_offload_class(ct_offload_class *class) ++{ ++ /* save in global var for now, because hwoff_agent is inited before conntrack is created. ++ will be used in conntrack_init */ ++ g_ct_offload_class = class; ++} ++#endif + /* Initializes the connection tracker 'ct'. The caller is responsible for + * calling 'conntrack_destroy()', when the instance is not needed anymore */ + struct conntrack * +@@ -301,7 +307,7 @@ conntrack_init(void) + hindex_init(&ct->alg_expectation_refs); + ovs_rwlock_unlock(&ct->resources_lock); + +- ovs_mutex_init_adaptive(&ct->ct_lock); ++ ovs_mutex_init_recursive(&ct->ct_lock); + ovs_mutex_lock(&ct->ct_lock); + cmap_init(&ct->conns); + for (unsigned i = 0; i < ARRAY_SIZE(ct->exp_lists); i++) { +@@ -319,7 +325,12 @@ conntrack_init(void) + latch_init(&ct->clean_thread_exit); + ct->clean_thread = ovs_thread_create("ct_clean", clean_thread_main, ct); + ct->ipf = ipf_init(); +- ++#ifdef HAVE_HWOFF_AGENT ++ ct->offload_class = g_ct_offload_class; ++ if (ct->offload_class != NULL && ct->offload_class->cleaned == 0) { ++ ct->offload_class->ovs_ct_init_notify(ct); ++ } ++#endif + return ct; + } + +@@ -432,6 +443,12 @@ static void + conn_clean_cmn(struct conntrack *ct, struct conn *conn) + OVS_REQUIRES(ct->ct_lock) + { ++#ifdef HAVE_HWOFF_AGENT ++ if (ct->offload_class && ct->offload_class->cleaned == 0) { ++ ct->offload_class->conn_state_notify(conn, CONN_STATE_DELETE); ++ } ++#endif ++ + if (conn->alg) { + expectation_clean(ct, &conn->key); + } +@@ -524,7 +541,7 @@ conntrack_destroy(struct conntrack *ct) + } + + +-static bool ++bool + conn_key_lookup(struct conntrack *ct, const struct conn_key *key, + uint32_t hash, long long now, struct conn **conn_out, + bool *reply) +@@ -1098,6 +1115,9 @@ conn_update_state(struct conntrack *ct, struct dp_packet *pkt, + switch (res) { + case CT_UPDATE_VALID: + pkt->md.ct_state |= CS_ESTABLISHED; ++#ifdef HAVE_HWOFF_AGENT ++ conn->offload_info.is_ct_established = true; ++#endif + pkt->md.ct_state &= ~CS_NEW; + if (ctx->reply) { + pkt->md.ct_state |= CS_REPLY_DIR; +@@ -1382,8 +1402,15 @@ process_one(struct conntrack *ct, struct dp_packet *pkt, + handle_alg_ctl(ct, ctx, pkt, ct_alg_ctl, conn, now, !!nat_action_info); + + set_cached_conn(nat_action_info, ctx, conn, pkt); ++ ++#ifdef HAVE_HWOFF_AGENT ++ if (ct->offload_class && ct->offload_class->cleaned == 0) { ++ ct->offload_class->complete_ct_info(conn, pkt); ++ } ++#endif + } + ++ + /* Sends the packets in '*pkt_batch' through the connection tracker 'ct'. All + * the packets must have the same 'dl_type' (IPv4 or IPv6) and should have + * the l3 and and l4 offset properly set. Performs fragment reassembly with +@@ -1478,6 +1505,21 @@ set_label(struct dp_packet *pkt, struct conn *conn, + } + + ++#ifdef HAVE_HWOFF_AGENT ++static void ++ct_update_expiration(struct conntrack *ct) ++{ ++ struct conn *conn; ++ if (!ovs_mutex_trylock(&ct->ct_lock)) { ++ CMAP_FOR_EACH(conn, cm_node, &ct->conns) { ++ if (ct->offload_class && ct->offload_class->cleaned == 0) { ++ ct->offload_class->update_conn_statistics(conn); ++ } ++ } ++ ovs_mutex_unlock(&ct->ct_lock); ++ } ++} ++#endif + /* Delete the expired connections from 'ctb', up to 'limit'. Returns the + * earliest expiration time among the remaining connections in 'ctb'. Returns + * LLONG_MAX if 'ctb' is empty. The return value might be smaller than 'now', +@@ -1563,6 +1605,9 @@ clean_thread_main(void *f_) + + while (!latch_is_set(&ct->clean_thread_exit)) { + long long next_wake; ++#ifdef HAVE_HWOFF_AGENT ++ ct_update_expiration(ct); ++#endif + long long now = time_msec(); + next_wake = conntrack_clean(ct, now); + +@@ -1657,6 +1702,65 @@ extract_l3_ipv6(struct conn_key *key, const void *data, size_t size, + return true; + } + ++#ifdef HAVE_HWOFF_AGENT ++#define TCP_LEN_SHIFT 2 ++static inline bool ++is_vaild_tcp_length(const struct tcp_header *tcp, size_t size) ++{ ++ if (size < sizeof *tcp) { ++ return false; ++ } ++ size_t tcp_len = TCP_OFFSET(tcp->tcp_ctl) << TCP_LEN_SHIFT; ++ return !(OVS_UNLIKELY(tcp_len > size || tcp_len < TCP_HEADER_LEN)); ++} ++ ++static inline bool ++check_l4_tcp(const struct conn_key *key OVS_UNUSED, const void *data, size_t size, ++ const void *l3 OVS_UNUSED, bool validate_checksum OVS_UNUSED) ++{ ++ const struct tcp_header *tcp = data; ++ if(!is_vaild_tcp_length(tcp, size)) { ++ return false; ++ } ++ ++ return true; ++} ++ ++static inline bool ++is_vaild_udp_length(const struct udp_header *udp, size_t size) ++{ ++ if (size < sizeof *udp) { ++ return false; ++ } ++ size_t udp_len = ntohs(udp->udp_len); ++ return !(OVS_UNLIKELY(udp_len > size || udp_len < UDP_HEADER_LEN)); ++} ++ ++static inline bool ++check_l4_udp(const struct conn_key *key OVS_UNUSED, const void *data, size_t size, ++ const void *l3 OVS_UNUSED, bool validate_checksum OVS_UNUSED) ++{ ++ const struct udp_header *udp = data; ++ if(!is_vaild_udp_length(udp, size)) { ++ return false; ++ } ++ return true; ++} ++ ++static inline bool ++check_l4_icmp(const void *data OVS_UNUSED, size_t size OVS_UNUSED, bool validate_checksum OVS_UNUSED) ++{ ++ return true; ++} ++ ++static inline bool ++check_l4_icmp6(const struct conn_key *key OVS_UNUSED, const void *data OVS_UNUSED, size_t size OVS_UNUSED, ++ const void *l3 OVS_UNUSED, bool validate_checksum OVS_UNUSED) ++{ ++ return true; ++} ++#else ++ + static inline bool + checksum_valid(const struct conn_key *key, const void *data, size_t size, + const void *l3) +@@ -1725,6 +1829,7 @@ check_l4_icmp6(const struct conn_key *key, const void *data, size_t size, + { + return validate_checksum ? checksum_valid(key, data, size, l3) : true; + } ++#endif + + static inline bool + extract_l4_tcp(struct conn_key *key, const void *data, size_t size, +@@ -1987,7 +2092,7 @@ extract_l4(struct conn_key *key, const void *data, size_t size, bool *related, + } + } + +-static bool ++bool + conn_key_extract(struct conntrack *ct, struct dp_packet *pkt, ovs_be16 dl_type, + struct conn_lookup_ctx *ctx, uint16_t zone) + { +@@ -2088,7 +2193,7 @@ ct_endpoint_hash_add(uint32_t hash, const struct ct_endpoint *ep) + } + + /* Symmetric */ +-static uint32_t ++uint32_t + conn_key_hash(const struct conn_key *key, uint32_t basis) + { + uint32_t hsrc, hdst, hash; +@@ -2361,7 +2466,9 @@ static struct conn * + new_conn(struct conntrack *ct, struct dp_packet *pkt, struct conn_key *key, + long long now, uint32_t tp_id) + { +- return l4_protos[key->nw_proto]->new_conn(ct, pkt, now, tp_id); ++ ++ struct conn *conn = l4_protos[key->nw_proto]->new_conn(ct, pkt, now, tp_id); ++ return conn; + } + + static void +@@ -2475,7 +2582,7 @@ tuple_to_conn_key(const struct ct_dpif_tuple *tuple, uint16_t zone, + key->zone = zone; + } + +-static void ++void + conn_to_ct_dpif_entry(const struct conn *conn, struct ct_dpif_entry *entry, + long long now) + { +@@ -2495,6 +2602,14 @@ conn_to_ct_dpif_entry(const struct conn *conn, struct ct_dpif_entry *entry, + if (class->conn_get_protoinfo) { + class->conn_get_protoinfo(conn, &entry->protoinfo); + } ++ ++#ifdef HAVE_HWOFF_AGENT ++ if (g_ct_offload_class) { ++ entry->print_offload = false; ++ g_ct_offload_class->get_ct_offload_info(conn, entry); ++ } ++#endif ++ + ovs_mutex_unlock(&conn->lock); + + entry->timeout = (expiration > 0) ? expiration / 1000 : 0; +@@ -2557,6 +2672,71 @@ conntrack_dump_done(struct conntrack_dump *dump OVS_UNUSED) + return 0; + } + ++#ifdef HAVE_HWOFF_AGENT ++static bool ++conntrack_ipv6_compare(struct in6_addr *sip1, struct in6_addr *sip2, ++ struct in6_addr *mask) ++{ ++ struct in6_addr src_ip = ipv6_addr_bitand(sip1, mask); ++ struct in6_addr dst_ip = ipv6_addr_bitand(sip2, mask); ++ return !memcmp(&src_ip, &dst_ip, sizeof(struct in6_addr)); ++} ++ ++static bool ++conntrack_ipv4_compare(ovs_be32 sip1, ovs_be32 sip2, ++ ovs_be32 mask) ++{ ++ return ((sip1 & mask) == (sip2 & mask)); ++} ++ ++static bool ++conntrack_ip_compare(union ct_addr *ip1, union ct_addr *ip2, ++ union ct_addr *mask, uint16_t dl_type, uint16_t conn_dl_type) ++{ ++ if (ip1 == NULL || ip2 == NULL || mask == NULL) { ++ return false; ++ } ++ ++ if (htons(dl_type) != conn_dl_type) { ++ return false; ++ } ++ ++ if (dl_type == ETH_TYPE_IP) { ++ return conntrack_ipv4_compare(ip1->ipv4, ip2->ipv4, mask->ipv4); ++ } ++ ++ return conntrack_ipv6_compare(&ip1->ipv6, &ip2->ipv6, &mask->ipv6); ++} ++ ++int ++conntrack_flush(struct conntrack *ct, const uint16_t *zone, ++ union ct_addr *sip, union ct_addr *dip, ++ union ct_addr *smask, union ct_addr *dmask, ++ uint16_t dl_type, bool is_force) ++{ ++ struct conn *conn; ++ ++ ovs_mutex_lock(&ct->ct_lock); ++ CMAP_FOR_EACH(conn, cm_node, &ct->conns) { ++ if ((!zone || *zone == conn->key.zone) ++ && (conn->conn_type == CT_CONN_TYPE_DEFAULT) ++ && (!sip || !smask || conntrack_ip_compare(sip, &conn->key.src.addr, ++ smask, dl_type, conn->key.dl_type)) ++ && (!dip || !dmask || conntrack_ip_compare(dip, &conn->key.dst.addr, ++ dmask, dl_type, conn->key.dl_type))) { ++ /* Special deal for elb streams, keep it */ ++ if (!is_force && conn->label.u32[0]) { ++ continue; ++ } ++ conn_clean_one(ct, conn); ++ } ++ ++ } ++ ovs_mutex_unlock(&ct->ct_lock); ++ ++ return 0; ++} ++#else + int + conntrack_flush(struct conntrack *ct, const uint16_t *zone) + { +@@ -2572,6 +2752,7 @@ conntrack_flush(struct conntrack *ct, const uint16_t *zone) + + return 0; + } ++#endif + + int + conntrack_flush_tuple(struct conntrack *ct, const struct ct_dpif_tuple *tuple, +diff --git a/openvswitch-2.14.2/lib/conntrack.h b/openvswitch-2.14.2/lib/conntrack.h +index 9553b18..7e342c5 100644 +--- a/openvswitch-2.14.2/lib/conntrack.h ++++ b/openvswitch-2.14.2/lib/conntrack.h +@@ -132,7 +132,14 @@ int conntrack_dump_start(struct conntrack *, struct conntrack_dump *, + int conntrack_dump_next(struct conntrack_dump *, struct ct_dpif_entry *); + int conntrack_dump_done(struct conntrack_dump *); + ++#ifdef HAVE_HWOFF_AGENT ++int conntrack_flush(struct conntrack *ct, const uint16_t *zone, ++ union ct_addr *sip, union ct_addr *dip, ++ union ct_addr *smask, union ct_addr *dmask, ++ uint16_t dl_type, bool is_force); ++#else + int conntrack_flush(struct conntrack *, const uint16_t *zone); ++#endif + int conntrack_flush_tuple(struct conntrack *, const struct ct_dpif_tuple *, + uint16_t zone); + int conntrack_set_maxconns(struct conntrack *ct, uint32_t maxconns); +diff --git a/openvswitch-2.14.2/lib/ct-dpif.c b/openvswitch-2.14.2/lib/ct-dpif.c +index 8c2480e..d7566c9 100644 +--- a/openvswitch-2.14.2/lib/ct-dpif.c ++++ b/openvswitch-2.14.2/lib/ct-dpif.c +@@ -118,6 +118,36 @@ ct_dpif_dump_done(struct ct_dpif_dump_state *dump) + * entries in '*zone'. + * - If 'tuple' is not NULL, flush the conntrack entry specified by 'tuple' + * in '*zone'. If 'zone' is NULL, use the default zone (zone 0). */ ++#ifdef HAVE_HWOFF_AGENT ++typedef int (*ct_flush_t)(struct dpif *, const uint16_t *zone, ++ union ct_addr *sip, union ct_addr *dip, ++ union ct_addr *smask, union ct_addr *dmask, uint16_t dl_type, bool is_force); ++static inline void ++log_ct_flush(struct dpif *dpif, const uint16_t *zone) ++{ ++ if (zone) { ++ VLOG_DBG("%s: ct_flush: %"PRIu16, dpif_name(dpif), *zone); ++ } else { ++ VLOG_DBG("%s: ct_flush: ", dpif_name(dpif)); ++ } ++ ++} ++ ++int ++ct_dpif_flush(struct dpif *dpif, const uint16_t *zone, ++ union ct_addr *sip, union ct_addr *dip, ++ union ct_addr *smask, union ct_addr *dmask, ++ uint16_t dl_type, bool is_force) ++{ ++ ct_flush_t ct_flush = NULL; ++ ++ log_ct_flush(dpif, zone); ++ ++ ct_flush = dpif->dpif_class->ct_flush; ++ ++ return ct_flush ? ct_flush(dpif, zone, sip, dip, smask, dmask, dl_type, is_force) : EOPNOTSUPP; ++} ++#else + int + ct_dpif_flush(struct dpif *dpif, const uint16_t *zone, + const struct ct_dpif_tuple *tuple) +@@ -138,6 +168,7 @@ ct_dpif_flush(struct dpif *dpif, const uint16_t *zone, + ? dpif->dpif_class->ct_flush(dpif, zone, tuple) + : EOPNOTSUPP); + } ++#endif + + int + ct_dpif_set_maxconns(struct dpif *dpif, uint32_t maxconns) +@@ -328,6 +359,11 @@ ct_dpif_format_entry(const struct ct_dpif_entry *entry, struct ds *ds, + ct_dpif_format_tuple(ds, &entry->tuple_master); + ds_put_cstr(ds, ")"); + } ++ ++ if (entry->print_offload) { ++ ds_put_format(ds, ",offloaded=(orig=%s,", entry->init_dir_offload_state); ++ ds_put_format(ds, "reply=%s)", entry->reply_dir_offload_state); ++ } + } + + void +diff --git a/openvswitch-2.14.2/lib/ct-dpif.h b/openvswitch-2.14.2/lib/ct-dpif.h +index e4c7a64..cee924c 100644 +--- a/openvswitch-2.14.2/lib/ct-dpif.h ++++ b/openvswitch-2.14.2/lib/ct-dpif.h +@@ -20,6 +20,8 @@ + #include "openvswitch/types.h" + #include "packets.h" + ++union ct_addr; ++ + union ct_dpif_inet_addr { + ovs_be32 ip; + ovs_be32 ip6[4]; +@@ -197,6 +199,9 @@ struct ct_dpif_entry { + uint32_t timeout; + uint32_t mark; + uint32_t bkt; /* CT bucket number. */ ++ bool print_offload; ++ const char *init_dir_offload_state; ++ const char *reply_dir_offload_state; + }; + + enum { +@@ -275,8 +280,15 @@ int ct_dpif_dump_start(struct dpif *, struct ct_dpif_dump_state **, + const uint16_t *zone, int *); + int ct_dpif_dump_next(struct ct_dpif_dump_state *, struct ct_dpif_entry *); + int ct_dpif_dump_done(struct ct_dpif_dump_state *); ++#ifdef HAVE_HWOFF_AGENT ++int ct_dpif_flush(struct dpif *dpif, const uint16_t *zone, ++ union ct_addr *sip, union ct_addr *dip, ++ union ct_addr *smask, union ct_addr *dmask, ++ uint16_t dl_type, bool is_force); ++#else + int ct_dpif_flush(struct dpif *, const uint16_t *zone, + const struct ct_dpif_tuple *); ++#endif + int ct_dpif_set_maxconns(struct dpif *dpif, uint32_t maxconns); + int ct_dpif_get_maxconns(struct dpif *dpif, uint32_t *maxconns); + int ct_dpif_get_nconns(struct dpif *dpif, uint32_t *nconns); +diff --git a/openvswitch-2.14.2/lib/ct_dump_extend/ct_dump_extend.c b/openvswitch-2.14.2/lib/ct_dump_extend/ct_dump_extend.c +new file mode 100644 +index 0000000..5ff5085 +--- /dev/null ++++ b/openvswitch-2.14.2/lib/ct_dump_extend/ct_dump_extend.c +@@ -0,0 +1,202 @@ ++/* ++ * Copyright (c) 2022-2022. Huawei Technologies Co., Ltd. ++ * Description: dump conntrack extend implementations ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ * ++ * Create: 2022-03-24 ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "conntrack.h" ++#include "conntrack-private.h" ++#include "ct-dpif.h" ++#include "dpif-netdev.h" ++#include "openvswitch/vlog.h" ++#include "ct_dump_extend.h" ++ ++#include "ovs-atomic.h" ++ ++#define CT_DPIF_DUMP_FLOWS_MAX 3000U ++ ++enum ct_dpif_dump_status { ++ CT_DPIF_DUMP_END, ++ CT_DPIF_DUMP_START, ++}; ++ ++struct ct_dpif_dump_context { ++ pthread_mutex_t mutex; ++ FILE *file; ++ char file_name[PATH_MAX]; ++ bool verbosity; ++ bool print_statistics; ++ uint16_t zone; ++ const uint16_t *pzone; ++ atomic_count dump_flag; ++ pthread_t thread_id; ++ struct ct_dpif_dump_state *dump_state; ++ struct dpif *ct_dpif; ++}; ++ ++VLOG_DEFINE_THIS_MODULE(ct_dump_extend); ++ ++static struct ct_dpif_dump_context g_ct_dpif_dump_context = { 0 }; ++ ++static int ++ct_dump_open_file(const char *file_name, struct ds *ds) ++{ ++ struct ct_dpif_dump_context *dump_context = &g_ct_dpif_dump_context; ++ ++ if (file_name[0] != '/') { ++ ds_put_format(ds, "file name \"%s\"error: Need absolute path\n", file_name); ++ return -1; ++ } ++ ++ dump_context->file = fopen(file_name, "w+"); ++ if (dump_context->file == NULL) { ++ ds_put_format(ds, "file : %s open failed.\n", file_name); ++ return -1; ++ } ++ ++ return 0; ++}; ++ ++static void hwoff_ct_dump_flow_to_file_start(void) ++{ ++ int ret = 0; ++ int count = 0; ++ int error; ++ int tot_bkts; ++ struct ct_dpif_entry entry; ++ struct ds ds = DS_EMPTY_INITIALIZER; ++ struct ct_dpif_dump_context *dump_context = &g_ct_dpif_dump_context; ++ ++ ret = ct_dpif_dump_start(dump_context->ct_dpif, &dump_context->dump_state, ++ dump_context->pzone, &tot_bkts); ++ if (ret != 0) { ++ VLOG_ERR("ct dpif dump flow start filed ! ret = %d", ret); ++ goto start_err; ++ } ++ ret = ct_dump_open_file(dump_context->file_name, &ds); ++ if (ret != 0) { ++ goto open_err; ++ } ++ ++ while (!(error = ct_dpif_dump_next(dump_context->dump_state, &entry))) { ++ count++; ++ ct_dpif_format_entry(&entry, &ds, dump_context->verbosity, ++ dump_context->print_statistics); ++ ct_dpif_entry_uninit(&entry); ++ ds_put_format(&ds, "\n"); ++ if (count >= CT_DPIF_DUMP_FLOWS_MAX) { ++ ret = fwrite(ds_cstr(&ds), strlen(ds_cstr(&ds)), 1, dump_context->file); ++ if (ret != 1 && ferror(dump_context->file) != 0) { ++ VLOG_ERR("ct flow write to file failed ! ret = %d\n", ret); ++ break; ++ } ++ count = 0; ++ ds_clear(&ds); ++ } ++ } ++ /* Any CT entry was dumped with no issue. */ ++ if (error == EOF) { ++ VLOG_INFO("ct flow dump to file done.\n"); ++ ret = fwrite(ds_cstr(&ds), strlen(ds_cstr(&ds)), 1, dump_context->file); ++ if (ret != 1 && ferror(dump_context->file) != 0) { ++ VLOG_ERR("ct flow write to file failed ! ret = %d\n", ret); ++ } ++ } else if (error) { ++ VLOG_ERR("ct flow dump to file failed ! error = %d\n", error); ++ } ++ ++ fclose(dump_context->file); ++ dump_context->file = NULL; ++open_err: ++ ds_destroy(&ds); ++ ct_dpif_dump_done(dump_context->dump_state); ++ dump_context->dump_state = NULL; ++start_err: ++ dpif_close(dump_context->ct_dpif); ++ dump_context->ct_dpif = NULL; ++ atomic_count_set(&dump_context->dump_flag, CT_DPIF_DUMP_END); ++} ++ ++int ++hwoff_dpctl_dump_write(struct ct_dump_extend *dump) ++{ ++ struct ct_dpif_dump_context *dump_context = &g_ct_dpif_dump_context; ++ char *resolve_path = NULL; ++ char *result = NULL; ++ ++ if (strnlen(dump->file_name, PATH_MAX) == 0) { ++ ds_put_format(dump->ds, "file name length is 0\n"); ++ return -1; ++ } ++ if (strnlen(dump->file_name, PATH_MAX) >= PATH_MAX) { ++ ds_put_format(dump->ds, "file name too long, length need less than %d, actually %zu\n", ++ PATH_MAX, strnlen(dump->file_name, PATH_MAX)); ++ return -1; ++ } ++ ++ resolve_path = (char *)malloc(PATH_MAX); ++ if (!resolve_path) { ++ ds_put_format(dump->ds, "malloc memmory for ct file real path failed\n"); ++ return -1; ++ } ++ memset(resolve_path, 0, PATH_MAX); ++ result = realpath(dump->file_name, resolve_path); ++ (void)result; ++ ++ if ((strlen(resolve_path) == 0) || (strlen(resolve_path) >= PATH_MAX)) { ++ ds_put_format(dump->ds, "resolve path %s is invalid\n", resolve_path); ++ free(resolve_path); ++ return -1; ++ } ++ ++ if (strcmp(resolve_path, dump->file_name) != 0) { ++ ds_put_format(dump->ds, "file path is incorrect, please check the file path\n"); ++ free(resolve_path); ++ return -1; ++ } ++ ++ memset(dump_context->file_name, 0, PATH_MAX); ++ strncpy(dump_context->file_name, resolve_path, PATH_MAX - 1); ++ free(resolve_path); ++ ++ dump_context->verbosity = dump->verbosity; ++ dump_context->print_statistics = dump->print_statistics; ++ dump_context->ct_dpif = dump->ct_dpif; ++ if (dump->pzone != NULL) { ++ dump_context->zone = *dump->pzone; ++ dump_context->pzone = &dump_context->zone; ++ } ++ ++ pthread_mutex_lock(&dump_context->mutex); ++ if (CT_DPIF_DUMP_END != atomic_count_get(&dump_context->dump_flag)) { ++ ds_put_format(dump->ds, "A threads for dumping CT flows is running. Try again later. thread id = %lu\n", ++ dump_context->thread_id); ++ pthread_mutex_unlock(&dump_context->mutex); ++ return -1; ++ } ++ atomic_count_set(&dump_context->dump_flag, CT_DPIF_DUMP_START); ++ pthread_mutex_unlock(&dump_context->mutex); ++ ++ ds_put_format(dump->ds, "starting dump ct flow to file: %s.\n", dump->file_name); ++ dump_context->thread_id = ovs_thread_create("hwoff_dump_ct_flow_to_file", (void *)hwoff_ct_dump_flow_to_file_start, NULL); ++ VLOG_INFO("dump ct flow to file thread id = %lu", dump_context->thread_id); ++ return 0; ++} +diff --git a/openvswitch-2.14.2/lib/ct_dump_extend/ct_dump_extend.h b/openvswitch-2.14.2/lib/ct_dump_extend/ct_dump_extend.h +new file mode 100644 +index 0000000..1551573 +--- /dev/null ++++ b/openvswitch-2.14.2/lib/ct_dump_extend/ct_dump_extend.h +@@ -0,0 +1,34 @@ ++/* ++ * Copyright (c) 2022-2022. Huawei Technologies Co., Ltd. ++ * Description: dump conntrack extend definitions ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ * ++ * Create: 2022-03-24 ++ */ ++ ++#ifndef CT_DUMP_EXTEND_CT_H ++#define CT_DUMP_EXTEND_CT_H ++ ++struct ct_dump_extend { ++ bool verbosity; ++ bool print_statistics; ++ const char *file_name; ++ const uint16_t *pzone; ++ struct ds *ds; ++ struct dpif *ct_dpif; ++}; ++ ++int hwoff_dpctl_dump_write(struct ct_dump_extend *dump); ++ ++#endif +diff --git a/openvswitch-2.14.2/lib/ct_offload_provider.h b/openvswitch-2.14.2/lib/ct_offload_provider.h +new file mode 100644 +index 0000000..fb37bc8 +--- /dev/null ++++ b/openvswitch-2.14.2/lib/ct_offload_provider.h +@@ -0,0 +1,49 @@ ++/* ++ * Copyright (c) 2021-2022. Huawei Technologies Co., Ltd. ++ * Description: ct_offload_privider ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ * ++ * Create: 2021-07-09 ++ */ ++#ifndef CT_OFFLOAD_PROVIDER_H ++#define CT_OFFLOAD_PROVIDER_H ++ ++#include "openvswitch/types.h" ++#include "dp-packet.h" ++ ++#ifdef HAVE_HWOFF_AGENT ++#define INVALID_CONN_ID 0 ++ ++typedef uint32_t conn_id; ++struct conn; ++struct conntrack; ++struct ct_dpif_entry; ++ ++enum { ++ CONN_STATE_DELETE, ++}; ++ ++typedef struct { ++ int (*ovs_ct_init_notify)(struct conntrack *ovs_ct); ++ int (*complete_ct_info)(struct conn *conn, struct dp_packet *packet); ++ int (*conn_state_notify)(struct conn *conn, int new_state); ++ int (*get_ct_offload_info)(const struct conn *conn, struct ct_dpif_entry *entry); ++ void (*update_conn_statistics)(struct conn *conn); ++ volatile uint16_t cleaned; ++ volatile uint16_t reserved[3]; ++} ct_offload_class; ++ ++#endif // HAVE_HWOFF_AGENT ++ ++#endif +\ No newline at end of file +diff --git a/openvswitch-2.14.2/lib/dp-packet.h b/openvswitch-2.14.2/lib/dp-packet.h +index 9e2d06b..9dd7421 100644 +--- a/openvswitch-2.14.2/lib/dp-packet.h ++++ b/openvswitch-2.14.2/lib/dp-packet.h +@@ -55,6 +55,7 @@ enum OVS_PACKED_ENUM dp_packet_source { + #endif + + /* Bit masks for the 'ol_flags' member of the 'dp_packet' structure. */ ++#ifdef DPDK_2011_AND_BEFORE + enum dp_packet_offload_mask { + /* Value 0 is not used. */ + /* Is the 'rss_hash' valid? */ +@@ -83,6 +84,36 @@ enum dp_packet_offload_mask { + DEF_OL_FLAG(DP_PACKET_OL_TX_SCTP_CKSUM, PKT_TX_SCTP_CKSUM, 0x800), + /* Adding new field requires adding to DP_PACKET_OL_SUPPORTED_MASK. */ + }; ++#else ++enum dp_packet_offload_mask { ++ /* Value 0 is not used. */ ++ /* Is the 'rss_hash' valid? */ ++ DEF_OL_FLAG(DP_PACKET_OL_RSS_HASH, RTE_MBUF_F_RX_RSS_HASH, 0x1), ++ /* Is the 'flow_mark' valid? */ ++ DEF_OL_FLAG(DP_PACKET_OL_FLOW_MARK, RTE_MBUF_F_RX_FDIR_ID, 0x2), ++ /* Bad L4 checksum in the packet. */ ++ DEF_OL_FLAG(DP_PACKET_OL_RX_L4_CKSUM_BAD, RTE_MBUF_F_RX_L4_CKSUM_BAD, 0x4), ++ /* Bad IP checksum in the packet. */ ++ DEF_OL_FLAG(DP_PACKET_OL_RX_IP_CKSUM_BAD, RTE_MBUF_F_RX_IP_CKSUM_BAD, 0x8), ++ /* Valid L4 checksum in the packet. */ ++ DEF_OL_FLAG(DP_PACKET_OL_RX_L4_CKSUM_GOOD, RTE_MBUF_F_RX_L4_CKSUM_GOOD, 0x10), ++ /* Valid IP checksum in the packet. */ ++ DEF_OL_FLAG(DP_PACKET_OL_RX_IP_CKSUM_GOOD, RTE_MBUF_F_RX_IP_CKSUM_GOOD, 0x20), ++ /* TCP Segmentation Offload. */ ++ DEF_OL_FLAG(DP_PACKET_OL_TX_TCP_SEG, RTE_MBUF_F_TX_TCP_SEG, 0x40), ++ /* Offloaded packet is IPv4. */ ++ DEF_OL_FLAG(DP_PACKET_OL_TX_IPV4, RTE_MBUF_F_TX_IPV4, 0x80), ++ /* Offloaded packet is IPv6. */ ++ DEF_OL_FLAG(DP_PACKET_OL_TX_IPV6, RTE_MBUF_F_TX_IPV6, 0x100), ++ /* Offload TCP checksum. */ ++ DEF_OL_FLAG(DP_PACKET_OL_TX_TCP_CKSUM, RTE_MBUF_F_TX_TCP_CKSUM, 0x200), ++ /* Offload UDP checksum. */ ++ DEF_OL_FLAG(DP_PACKET_OL_TX_UDP_CKSUM, RTE_MBUF_F_TX_UDP_CKSUM, 0x400), ++ /* Offload SCTP checksum. */ ++ DEF_OL_FLAG(DP_PACKET_OL_TX_SCTP_CKSUM, RTE_MBUF_F_TX_SCTP_CKSUM, 0x800), ++ /* Adding new field requires adding to DP_PACKET_OL_SUPPORTED_MASK. */ ++}; ++#endif + + #define DP_PACKET_OL_SUPPORTED_MASK (DP_PACKET_OL_RSS_HASH | \ + DP_PACKET_OL_FLOW_MARK | \ +@@ -558,6 +589,36 @@ dp_packet_set_base(struct dp_packet *b, void *d) + b->mbuf.buf_addr = d; + } + ++#ifdef HAVE_HWOFF_AGENT ++static inline uint32_t ++dp_packet_size(const struct dp_packet *b) ++{ ++ return rte_pktmbuf_pkt_len(&(b->mbuf)); ++} ++ ++static inline void ++hwoff_nonlinear_pkt_set_size(struct dp_packet *b, uint32_t v) ++{ ++ int pack_len_diff = v - b->mbuf.pkt_len; ++ b->mbuf.data_len += pack_len_diff; ++ ++ rte_pktmbuf_pkt_len(&(b->mbuf)) = v; ++} ++ ++static inline void ++dp_packet_set_size(struct dp_packet *b, uint32_t v) ++{ ++ if (b->mbuf.nb_segs <= 1) { ++ rte_pktmbuf_pkt_len(&(b->mbuf)) = v; ++ rte_pktmbuf_data_len(&(b->mbuf)) = v; ++ return; ++ } ++ ++ hwoff_nonlinear_pkt_set_size(b, v); ++} ++ ++#else ++ + static inline uint32_t + dp_packet_size(const struct dp_packet *b) + { +@@ -579,6 +640,7 @@ dp_packet_set_size(struct dp_packet *b, uint32_t v) + b->mbuf.pkt_len = v; /* Total length of all segments linked to + * this segment. */ + } ++#endif + + static inline uint16_t + __packet_data(const struct dp_packet *b) +diff --git a/openvswitch-2.14.2/lib/dpctl.c b/openvswitch-2.14.2/lib/dpctl.c +index b232d43..3ab83c8 100644 +--- a/openvswitch-2.14.2/lib/dpctl.c ++++ b/openvswitch-2.14.2/lib/dpctl.c +@@ -51,6 +51,10 @@ + #include "util.h" + #include "openvswitch/ofp-flow.h" + #include "openvswitch/ofp-port.h" ++#ifdef HAVE_HWOFF_AGENT ++#include "conntrack.h" ++#include "ct_dump_extend/ct_dump_extend.h" ++#endif + + typedef int dpctl_command_handler(int argc, const char *argv[], + struct dpctl_params *); +@@ -811,6 +815,11 @@ format_dpif_flow(struct ds *ds, const struct dpif_flow *f, struct hmap *ports, + if (dpctl_p->verbosity && f->ufid_present) { + odp_format_ufid(&f->ufid, ds); + ds_put_cstr(ds, ", "); ++#ifdef HAVE_HWOFF_AGENT ++ odp_format_mega_ufid(&f->mega_ufid, ds); ++ ds_put_cstr(ds, ", "); ++#endif ++ + } + odp_flow_format(f->key, f->key_len, f->mask, f->mask_len, ports, ds, + dpctl_p->verbosity); +@@ -1421,6 +1430,16 @@ dpctl_dump_conntrack(int argc, const char *argv[], + int tot_bkts; + struct dpif *dpif; + int error; ++#ifdef HAVE_HWOFF_AGENT ++ bool is_need_dump_to_file = false; ++ const char *dump_file_name = NULL; ++ ++ if (argc >= 2 && (strncmp(argv[argc - 2], "-w", sizeof("-w")) == 0)) { ++ is_need_dump_to_file = true; ++ dump_file_name = argv[argc - 1]; ++ argc -= 2; ++ } ++#endif + + if (argc > 1 && ovs_scan(argv[argc - 1], "zone=%"SCNu16, &zone)) { + pzone = &zone; +@@ -1432,6 +1451,30 @@ dpctl_dump_conntrack(int argc, const char *argv[], + return error; + } + ++#ifdef HAVE_HWOFF_AGENT ++ if (is_need_dump_to_file) { ++ struct ds ds = DS_EMPTY_INITIALIZER; ++ struct ct_dump_extend ct_dump = { ++ .file_name = dump_file_name, ++ .verbosity = dpctl_p->verbosity, ++ .print_statistics = dpctl_p->print_statistics, ++ .ct_dpif = dpif, ++ .pzone = pzone, ++ .ds = &ds, ++ }; ++ error = hwoff_dpctl_dump_write(&ct_dump); ++ if (error) { ++ dpctl_error(dpctl_p, error, ds_cstr(&ds)); ++ ds_destroy(&ds); ++ dpif_close(dpif); ++ return error; ++ } ++ dpctl_print(dpctl_p, "%s\n", ds_cstr(&ds)); ++ ds_destroy(&ds); ++ return error; ++ } ++#endif ++ + error = ct_dpif_dump_start(dpif, &dump, pzone, &tot_bkts); + if (error) { + dpctl_error(dpctl_p, error, "starting conntrack dump"); +@@ -1461,6 +1504,188 @@ dpctl_dump_conntrack(int argc, const char *argv[], + return error; + } + ++#ifdef HAVE_HWOFF_AGENT ++static int conntrack_parse_ipv4_mask_len(char *str, union ct_addr *ip, union ct_addr *mask) ++{ ++ /* Mask has the same format with ip, %d prefix */ ++ char *ip_str = NULL; ++ char *mask_str = NULL; ++ uint8_t prefix; ++ ++ if (str == NULL || ip == NULL || mask == NULL) { ++ return -EINVAL; ++ } ++ ++ ip_str = strtok_r(str, "/", &mask_str); ++ if (ip_str != NULL && mask_str != NULL && (*mask_str != '\0')) { ++ if (1 == inet_pton(AF_INET, ip_str, &ip->ipv4) && ++ 1 == sscanf(mask_str, "%"SCNu8, &prefix) && prefix <= IP_MAX_MASK_LEN) { ++ mask->ipv4 = be32_prefix_mask(prefix); ++ /* restore the original str */ ++ *(mask_str - 1) = '/'; ++ return 0; ++ } ++ ++ /* restore the original str */ ++ *(mask_str - 1) = '/'; ++ } else if (ip_str != NULL && inet_pton(AF_INET, ip_str, ip) == 1) { ++ mask->ipv4 = be32_prefix_mask(IP_MAX_MASK_LEN); ++ return 0; ++ } ++ return -EINVAL; ++} ++ ++static int conntrack_parse_ipv6_mask_len(char *str, union ct_addr *ip, union ct_addr *mask) ++{ ++ /* Mask has the same format with ip, %d prefix */ ++ char *ip_str = NULL; ++ char *mask_str = NULL; ++ uint8_t prefix; ++ ++ if (str == NULL || ip == NULL || mask == NULL) { ++ return -EINVAL; ++ } ++ ++ ip_str = strtok_r(str, "/", &mask_str); ++ if (ip_str != NULL && mask_str != NULL && (*mask_str != '\0')) { ++ if (1 == inet_pton(AF_INET6, ip_str, &ip->ipv6) && ++ 1 == sscanf(mask_str, "%"SCNu8, &prefix) && prefix <= IPV6_MAX_MASK_LEN) { ++ mask->ipv6 = ipv6_create_mask(prefix); ++ /* restore the orignal str */ ++ *(mask_str - 1) = '/'; ++ return 0; ++ } ++ /* restore the original str */ ++ *(mask_str - 1) = '/'; ++ } else if (ip_str != NULL && inet_pton(AF_INET6, ip_str, &ip->ipv6) == 1) { ++ (void)memset(mask, sizeof(*mask), 0xff); ++ return 0; ++ } ++ return -EINVAL; ++} ++ ++static int conntrack_flush_get_ip(char *ip_str, union ct_addr *ip, ++ union ct_addr *mask, bool *is_ipv6) ++{ ++ if (conntrack_parse_ipv4_mask_len(ip_str, ip, mask) == 0) { ++ *is_ipv6 = false; ++ return 0; ++ } ++ ++ if (conntrack_parse_ipv6_mask_len(ip_str, ip, mask) == 0) { ++ *is_ipv6 = true; ++ return 0; ++ } ++ ++ return -1; ++} ++ ++static int ++dpctl_flush_conntrack(int argc, const char *argv[], ++ struct dpctl_params *dpctl_p) ++{ ++ int error; ++ uint16_t dl_type; ++ char *ip = NULL; ++ int args = argc - 1; ++ bool is_force = false; ++ struct dpif *dpif = NULL; ++ uint16_t zone, *pzone = NULL; ++ union ct_addr addr_src; ++ union ct_addr mask_src; ++ union ct_addr addr_dst; ++ union ct_addr mask_dst; ++ bool d_addr_ipv4_flag = false; ++ bool d_addr_ipv6_flag = false; ++ bool s_addr_ipv4_flag = false; ++ bool s_addr_ipv6_flag = false; ++ struct ds ds = DS_EMPTY_INITIALIZER; ++ ++ memset(&addr_src, 0, sizeof(union ct_addr)); ++ memset(&addr_dst, 0, sizeof(union ct_addr)); ++ ++ if (args && !strncmp(argv[args], "--force", sizeof("--force") - 1)) { ++ is_force = true; ++ args--; ++ } ++ ++ if (args && !strncmp(argv[args], "dip=", sizeof("dip") - 1)) { ++ ip = xstrdup(argv[args] + (sizeof("dip=") - 1)); ++ error = conntrack_flush_get_ip(ip, &addr_dst, &mask_dst, &d_addr_ipv6_flag); ++ free(ip); ++ if (error) { ++ dpctl_error(dpctl_p, error, "parse dip error."); ++ return error; ++ } ++ d_addr_ipv4_flag = !d_addr_ipv6_flag; ++ args--; ++ } ++ ++ if (args && !strncmp(argv[args], "sip=", sizeof("sip=") - 1)) { ++ ip = xstrdup(argv[args] + (sizeof("sip=") - 1)); ++ error = conntrack_flush_get_ip(ip, &addr_src, &mask_src, &s_addr_ipv6_flag); ++ free(ip); ++ if (error) { ++ dpctl_error(dpctl_p, error, "parse sip error."); ++ return error; ++ } ++ s_addr_ipv4_flag = !s_addr_ipv6_flag; ++ args--; ++ } ++ ++ if ((s_addr_ipv6_flag && d_addr_ipv4_flag) || ++ (s_addr_ipv4_flag && d_addr_ipv6_flag)) { ++ dpctl_error(dpctl_p, EINVAL, "sip/dip mismatch."); ++ return EINVAL; ++ } ++ ++ if (d_addr_ipv6_flag || s_addr_ipv6_flag) { ++ dl_type = ETH_TYPE_IPV6; ++ } else if (d_addr_ipv4_flag || s_addr_ipv4_flag) { ++ dl_type = ETH_TYPE_IP; ++ } else { ++ dl_type = 0; ++ } ++ ++ /* Parse zone */ ++ if (args && ovs_scan(argv[args], "zone=%"SCNu16, &zone)) { ++ pzone = &zone; ++ args--; ++ } ++ ++ /* Report error if there are more than one unparsed argument */ ++ if (args > 1) { ++ ds_put_cstr(&ds, "invalid argument"); ++ error = EINVAL; ++ goto error; ++ } ++ ++ error = opt_dpif_open(argc, argv, dpctl_p, 6, &dpif); ++ if (error) { ++ return error; ++ } ++ ++ error = ct_dpif_flush(dpif, pzone, ++ (s_addr_ipv6_flag || s_addr_ipv4_flag) ? &addr_src : 0, ++ (d_addr_ipv6_flag || d_addr_ipv4_flag) ? &addr_dst : 0, ++ (s_addr_ipv6_flag || s_addr_ipv4_flag) ? &mask_src : 0, ++ (d_addr_ipv6_flag || d_addr_ipv4_flag) ? &mask_dst : 0, ++ dl_type, is_force); ++ ++ if (!error) { ++ dpif_close(dpif); ++ return 0; ++ } ++ ++ ds_put_cstr(&ds, "failed to flush conntrack"); ++ ++error: ++ dpctl_error(dpctl_p, error, "%s", ds_cstr(&ds)); ++ ds_destroy(&ds); ++ dpif_close(dpif); ++ return error; ++} ++#else + static int + dpctl_flush_conntrack(int argc, const char *argv[], + struct dpctl_params *dpctl_p) +@@ -1510,6 +1735,7 @@ error: + dpif_close(dpif); + return error; + } ++#endif + + static int + dpctl_ct_stats_show(int argc, const char *argv[], +@@ -2529,10 +2755,17 @@ static const struct dpctl_command all_commands[] = { + { "get-flow", "[dp] ufid", 1, 2, dpctl_get_flow, DP_RO }, + { "del-flow", "[dp] flow", 1, 2, dpctl_del_flow, DP_RW }, + { "del-flows", "[dp]", 0, 1, dpctl_del_flows, DP_RW }, ++#ifdef HAVE_HWOFF_AGENT ++ { "dump-conntrack", "[-m] [-s] [dp] [zone=N] [-w file]", ++ 0, 4, dpctl_dump_conntrack, DP_RO }, ++ { "flush-conntrack", "[dp] [zone=N] [sip=x.x.x.x/x] [dip=x.x.x.x/x] [--force]", ++ 0, 5, dpctl_flush_conntrack, DP_RW }, ++#else + { "dump-conntrack", "[-m] [-s] [dp] [zone=N]", + 0, 4, dpctl_dump_conntrack, DP_RO }, + { "flush-conntrack", "[dp] [zone=N] [ct-tuple]", 0, 3, + dpctl_flush_conntrack, DP_RW }, ++#endif + { "ct-stats-show", "[dp] [zone=N]", + 0, 3, dpctl_ct_stats_show, DP_RO }, + { "ct-bkts", "[dp] [gt=N]", 0, 2, dpctl_ct_bkts, DP_RO }, +@@ -2675,6 +2908,8 @@ dpctl_unixctl_handler(struct unixctl_conn *conn, int argc, const char *argv[], + case 's': + dpctl_p.print_statistics = true; + break; ++ case 'w': ++ break; + default: + ds_put_format(&ds, "Unrecognized option -%c", *opt); + error = true; +diff --git a/openvswitch-2.14.2/lib/dpdk.c b/openvswitch-2.14.2/lib/dpdk.c +index 2f235a7..df849e3 100644 +--- a/openvswitch-2.14.2/lib/dpdk.c ++++ b/openvswitch-2.14.2/lib/dpdk.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -40,6 +41,17 @@ + #include "unixctl.h" + #include "util.h" + #include "vswitch-idl.h" ++#ifdef HAVE_HWOFF_AGENT ++#include ++#include ++#include "hwoff_init_func.h" ++ ++#define HWOFF_DPDK_HUGEPAGES_PREFIX "rte_dpak_" ++#define HWOFF_DPDK_HUGEPAGES_PATH "/dev/hugepages" ++#define HWOFF_DPDK_RUN_FILE "/var/run/dpdk" ++#define HWOFF_FUNCTION_FLUSH_PF "1" ++#define HWOFF_FUNCTION_FLUSH "/proc/hwoff_function_flush" ++#endif + + VLOG_DEFINE_THIS_MODULE(dpdk); + +@@ -339,6 +351,7 @@ dpdk_unixctl_log_set(struct unixctl_conn *conn, int argc, const char *argv[], + } + + level = dpdk_parse_log_level(level_string); ++ + if (level == -1) { + err_msg = xasprintf("invalid log level: '%s'", level_string); + } else if (rte_log_set_level_pattern(pattern, level) < 0) { +@@ -356,6 +369,104 @@ dpdk_unixctl_log_set(struct unixctl_conn *conn, int argc, const char *argv[], + unixctl_command_reply(conn, NULL); + } + ++#ifdef HAVE_HWOFF_AGENT ++static void ++hwoff_remove_fbarray(const char *path) ++{ ++ char barray_path[PATH_MAX] = {0}; ++ DIR *dir_barray = NULL; ++ struct dirent *barray_dirent = NULL; ++ ++ dir_barray = opendir(path); ++ while ((barray_dirent = readdir(dir_barray)) != NULL) { ++ if (strcmp(barray_dirent->d_name, ".") == 0) { ++ continue; ++ } ++ if (strcmp(barray_dirent->d_name, "..") == 0) { ++ continue; ++ } ++ sprintf(barray_path, "%s/%s", path, barray_dirent->d_name); ++ ++ remove(barray_path); ++ memset(barray_path, 0, sizeof(barray_path)); ++ } ++ closedir(dir_barray); ++ rmdir(path); ++} ++ ++void hwoff_clear_pf_access_hugepages(void) ++{ ++ int flr_file = -1; ++ ++ flr_file = open(HWOFF_FUNCTION_FLUSH, O_WRONLY); ++ if (flr_file < 0) { ++ VLOG_ERR("failed to open file %s with fd %d error %d", ++ HWOFF_FUNCTION_FLUSH, flr_file, errno); ++ return; ++ } ++ if (write(flr_file, HWOFF_FUNCTION_FLUSH_PF, ++ sizeof(HWOFF_FUNCTION_FLUSH_PF)) <= 0) { ++ VLOG_ERR("failed to write to %s", HWOFF_FUNCTION_FLUSH); ++ goto OUT; ++ } ++ VLOG_INFO("PF upall huge_pages flush success"); ++OUT: ++ close(flr_file); ++} ++ ++void ++hwoff_free_hugepages(void) ++{ ++ char path[PATH_MAX] = {0}; ++ char hugepages_path[PATH_MAX] = HWOFF_DPDK_HUGEPAGES_PATH; ++ char run_path[PATH_MAX] = HWOFF_DPDK_RUN_FILE; ++ DIR *dir = NULL; ++ DIR *hugepages_dir = NULL; ++ struct dirent *dir_item = NULL; ++ struct dirent *rte_dirent = NULL; ++ char prefix[] = HWOFF_DPDK_HUGEPAGES_PREFIX; ++ ++ /* unlink hugepages file */ ++ hugepages_dir = opendir(hugepages_path); ++ if (hugepages_dir) { ++ while ((dir_item = readdir(hugepages_dir)) != NULL) { ++ if (strncmp(dir_item->d_name, prefix, strlen(prefix)) == 0) { ++ sprintf(path, "%s/%s", hugepages_path, dir_item->d_name); ++ ++ unlink(path); ++ memset(path, 0, sizeof(path)); ++ } ++ } ++ closedir(hugepages_dir); ++ } ++ ++ /* remove dpdk run file */ ++ dir = opendir(run_path); ++ if (dir) { ++ while ((rte_dirent = readdir(dir)) != NULL) { ++ if (strncmp(rte_dirent->d_name, prefix, strlen(prefix)) == 0) { ++ sprintf(path, "%s/%s", run_path, rte_dirent->d_name); ++ ++ hwoff_remove_fbarray(path); ++ memset(path, 0, sizeof(path)); ++ } ++ } ++ closedir(dir); ++ } ++} ++ ++static void ++hwoff_hugepages_pre_process(struct svec *svec) ++{ ++ char ovs_prefix[64] = {0}; ++ hwoff_clear_pf_access_hugepages(); ++ hwoff_free_hugepages(); ++ ++ sprintf(ovs_prefix, "--file-prefix=%s%d", HWOFF_DPDK_HUGEPAGES_PREFIX, getpid()); ++ svec_add(svec, ovs_prefix); ++} ++#endif ++ + static bool + dpdk_init__(const struct smap *ovs_other_config) + { +@@ -481,6 +592,10 @@ dpdk_init__(const struct smap *ovs_other_config) + free(joined_args); + } + ++#ifdef HAVE_HWOFF_AGENT ++ hwoff_hugepages_pre_process(&args); ++#endif ++ + /* Copy because 'rte_eal_init' will change the argv, i.e. it will remove + * some arguments from it. '+1' to copy the terminating NULL. */ + argv = xmemdup(args.names, (args.n + 1) * sizeof args.names[0]); +diff --git a/openvswitch-2.14.2/lib/dpdk.h b/openvswitch-2.14.2/lib/dpdk.h +index 445a51d..3c08d56 100644 +--- a/openvswitch-2.14.2/lib/dpdk.h ++++ b/openvswitch-2.14.2/lib/dpdk.h +@@ -45,5 +45,9 @@ bool dpdk_available(void); + void print_dpdk_version(void); + void dpdk_status(const struct ovsrec_open_vswitch *); + bool dpdk_get_cpu_has_isa(const char *arch, const char *feature); ++#ifdef HAVE_HWOFF_AGENT ++void hwoff_free_hugepages(void); ++void hwoff_clear_pf_access_hugepages(void); ++#endif + + #endif /* dpdk.h */ +diff --git a/openvswitch-2.14.2/lib/dpif-netdev.c b/openvswitch-2.14.2/lib/dpif-netdev.c +index 02df8f1..8e0911c 100644 +--- a/openvswitch-2.14.2/lib/dpif-netdev.c ++++ b/openvswitch-2.14.2/lib/dpif-netdev.c +@@ -33,6 +33,11 @@ + #include + #include + ++#ifdef HAVE_HWOFF_AGENT ++#include "hwoff_init_func.h" ++#include "mac-learning.h" ++#endif ++ + #include "bitmap.h" + #include "cmap.h" + #include "conntrack.h" +@@ -387,6 +392,11 @@ struct dp_netdev { + /* Bonds. */ + struct ovs_mutex bond_mutex; /* Protects updates of 'tx_bonds'. */ + struct cmap tx_bonds; /* Contains 'struct tx_bond'. */ ++#ifdef HAVE_HWOFF_AGENT ++ /* callback when flush flows */ ++ dp_pmd_ukey_purge_callback *dp_pmd_ukey_purge_cb; ++ void *dp_pmd_ukey_purge_aux; ++#endif + }; + + static void meter_lock(const struct dp_netdev *dp, uint32_t meter_id) +@@ -498,6 +508,15 @@ struct dp_netdev_flow_attrs { + ATOMIC(const char *) dp_layer; /* DP layer the flow is handled in. */ + }; + ++#ifdef HAVE_HWOFF_AGENT ++struct packet_batch_per_flow { ++ unsigned int byte_count; ++ uint16_t tcp_flags; ++ struct dp_netdev_flow *flow; ++ struct dp_packet_batch array; ++}; ++#endif ++ + /* A flow in 'dp_netdev_pmd_thread's 'flow_table'. + * + * +@@ -921,6 +940,13 @@ static inline bool + pmd_perf_metrics_enabled(const struct dp_netdev_pmd_thread *pmd); + static void queue_netdev_flow_del(struct dp_netdev_pmd_thread *pmd, + struct dp_netdev_flow *flow); ++uint32_t flow_mark_alloc(void); ++void megaflow_to_mark_associate(const ovs_u128 *mega_ufid, uint32_t mark); ++void mark_to_flow_associate(const uint32_t mark, struct dp_netdev_flow *flow); ++int mark_to_flow_disassociate(struct dp_netdev_pmd_thread *pmd, struct dp_netdev_flow *flow); ++static void * ++dp_netdev_flow_offload_main(void *data OVS_UNUSED); ++ + + static void + emc_cache_init(struct emc_cache *flow_cache) +@@ -2261,6 +2287,25 @@ get_port_by_name(struct dp_netdev *dp, + return ENODEV; + } + ++odp_port_t ++dpif_netdev_get_odp_no_by_name(const char *devname) ++{ ++ struct dp_netdev_port *port = NULL; ++ struct dp_netdev *dp = shash_find_data(&dp_netdevs, "ovs-netdev"); ++ int error; ++ ++ if (dp == NULL) { ++ return ODPP_NONE; ++ } ++ ++ error = get_port_by_name(dp, devname, &port); ++ if (error != 0) { ++ return ODPP_NONE; ++ } ++ ++ return port->port_no; ++} ++ + /* Returns 'true' if there is a port with pmd netdev. */ + static bool + has_pmd_port(struct dp_netdev *dp) +@@ -2413,7 +2458,7 @@ static struct flow_mark flow_mark = { + .mark_to_flow = CMAP_INITIALIZER, + }; + +-static uint32_t ++uint32_t + flow_mark_alloc(void) + { + uint32_t mark; +@@ -2437,7 +2482,7 @@ flow_mark_free(uint32_t mark) + } + + /* associate megaflow with a mark, which is a 1:1 mapping */ +-static void ++void + megaflow_to_mark_associate(const ovs_u128 *mega_ufid, uint32_t mark) + { + size_t hash = dp_netdev_flow_hash(mega_ufid); +@@ -2488,7 +2533,7 @@ megaflow_to_mark_find(const ovs_u128 *mega_ufid) + } + + /* associate mark with a flow, which is 1:N mapping */ +-static void ++void + mark_to_flow_associate(const uint32_t mark, struct dp_netdev_flow *flow) + { + dp_netdev_flow_ref(flow); +@@ -2517,7 +2562,7 @@ flow_mark_has_no_ref(uint32_t mark) + return true; + } + +-static int ++int + mark_to_flow_disassociate(struct dp_netdev_pmd_thread *pmd, + struct dp_netdev_flow *flow) + { +@@ -2565,18 +2610,6 @@ mark_to_flow_disassociate(struct dp_netdev_pmd_thread *pmd, + return ret; + } + +-static void +-flow_mark_flush(struct dp_netdev_pmd_thread *pmd) +-{ +- struct dp_netdev_flow *flow; +- +- CMAP_FOR_EACH (flow, mark_node, &flow_mark.mark_to_flow) { +- if (flow->pmd_id == pmd->core_id) { +- queue_netdev_flow_del(pmd, flow); +- } +- } +-} +- + static struct dp_netdev_flow * + mark_to_flow_find(const struct dp_netdev_pmd_thread *pmd, + const uint32_t mark) +@@ -2631,6 +2664,154 @@ dp_netdev_append_flow_offload(struct dp_flow_offload_item *offload) + ovs_mutex_unlock(&dp_flow_offload.mutex); + } + ++#ifdef HAVE_HWOFF_AGENT ++/* Original offload solution use the flow_mark to identify the offload dp_netdev_flow, it works well ++ in one thread environment. In our solution we offload flow in pmd threads, and delete run in offload_thread, ++ so there are multi-theads process the flow_mark, flow_mark not working anymore. So we change our solution not ++ to process flow_mark at all. ++*/ ++int g_hwoff_offload_switch = 1; ++void dp_netdev_hwoff_switch_set(int value) ++{ ++ g_hwoff_offload_switch = value; ++} ++ ++static int ++dp_netdev_flow_offload_add(struct dp_netdev_pmd_thread *pmd, struct dp_netdev_flow *flow, struct match *match, ++ struct dp_packet_batch *pkts, const struct nlattr *actions, size_t actions_len) ++{ ++ int ret; ++ struct netdev *dev = NULL; ++ struct offload_info info; ++ odp_port_t in_port = flow->flow.in_port.odp_port; ++ const char *dpif_type_str = dpif_normalize_type(pmd->dp->class->type); ++ ++ if (g_hwoff_offload_switch != 1) { ++ return 0; ++ } ++ ++ if (flow->dead || (!pkts)) { ++ return -1; ++ } ++ ++ dev = netdev_ports_get(in_port, dpif_type_str); ++ if (!dev) { ++ return -1; ++ } ++ ++ hwoff_func* funcs = hwoff_get_funcs(); ++ if (!funcs->hwoff_is_support_offload(dev)) { ++ netdev_close(dev); ++ return -1; ++ } ++ ++ if (funcs->hwoff_is_ethdev(dev)) { ++ info.in_port_id = funcs->hwoff_get_eth_vport_id(dev); ++ info.in_port_type = HWOFF_PORT_TYPE_HIOVS; ++ } else { ++ info.in_port_id = 0xFFFFFFFF; ++ info.in_port_type = HWOFF_PORT_TYPE_OTHER; ++ } ++ info.pkts_info = pkts; ++ info.pmd_core_id = pmd->core_id; ++ info.pmd = pmd; ++ info.flow = flow; ++ info.modification = false; ++ ++ /* no need to take a port_mutex in pmd thread */ ++ ret = netdev_flow_put(dev, match, ++ CONST_CAST(struct nlattr *, actions), ++ actions_len, &flow->mega_ufid, &info, NULL); ++ netdev_close(dev); ++ if (ret) { ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int ++dp_netdev_flow_offload_del(struct dp_flow_offload_item *offload) ++{ ++ int ret; ++ struct netdev *dev = NULL; ++ hwoff_func* funcs = hwoff_get_funcs(); ++ struct dp_netdev_pmd_thread *pmd = offload->pmd; ++ struct dp_netdev_flow *flow = offload->flow; ++ odp_port_t in_port = flow->flow.in_port.odp_port; ++ const char *dpif_type_str = dpif_normalize_type(pmd->dp->class->type); ++ ++ dev = netdev_ports_get(in_port, dpif_type_str); ++ if (!dev) { ++ VLOG_DBG("device=%u is deleted when dp_netdev_flow_offload_del, mega_ufid="UUID_FMT, in_port, ++ UUID_ARGS((struct uuid *) &flow->mega_ufid)); ++ hiovs_offload_flow_api_del(NULL, &flow->mega_ufid, NULL); ++ return 0; ++ } ++ ++ if (!funcs->hwoff_is_support_offload(dev)) { ++ netdev_close(dev); ++ return 0; ++ } ++ ++ ovs_mutex_lock(&pmd->dp->port_mutex); ++ ret = netdev_flow_del(dev, &flow->mega_ufid, NULL); ++ ovs_mutex_unlock(&pmd->dp->port_mutex); ++ netdev_close(dev); ++ return ret; ++} ++ ++static int ++dp_netdev_flow_offload_put(struct dp_flow_offload_item *offload) ++{ ++ /* We do offload in pmd thread useing dp_netdev_flow_offload_add, here we just process modification. ++ We process modification just same as delete, thren packet will upcall then reoffload. ++ */ ++ bool modification = offload->op == DP_NETDEV_FLOW_OFFLOAD_OP_MOD; ++ ++ if (!modification) { ++ return 0; ++ } ++ ++ return dp_netdev_flow_offload_del(offload); ++} ++ ++static void ++queue_netdev_flow_put(struct dp_netdev_pmd_thread *pmd, ++ struct dp_netdev_flow *flow, struct match *match, ++ const struct nlattr *actions, size_t actions_len, bool is_modify) ++{ ++ int op; ++ struct dp_flow_offload_item *offload; ++ ++ if (!netdev_is_flow_api_enabled()) { ++ return; ++ } ++ ++ if (ovsthread_once_start(&offload_thread_once)) { ++ xpthread_cond_init(&dp_flow_offload.cond, NULL); ++ ovs_thread_create("dp_netdev_flow_offload", ++ dp_netdev_flow_offload_main, NULL); ++ ovsthread_once_done(&offload_thread_once); ++ } ++ ++ op = is_modify ? DP_NETDEV_FLOW_OFFLOAD_OP_MOD : DP_NETDEV_FLOW_OFFLOAD_OP_ADD; ++ offload = dp_netdev_alloc_flow_offload(pmd, flow, op); ++ offload->match = *match; ++ offload->actions = xmalloc(actions_len); ++ memcpy(offload->actions, actions, actions_len); ++ offload->actions_len = actions_len; ++ ++ dp_netdev_append_flow_offload(offload); ++} ++ ++bool dp_netdev_flow_dead_status_get(void *flow) ++{ ++ struct dp_netdev_flow *net_flow = (struct dp_netdev_flow *)flow; ++ return net_flow->dead; ++} ++#else ++ + static int + dp_netdev_flow_offload_del(struct dp_flow_offload_item *offload) + { +@@ -2691,6 +2872,7 @@ dp_netdev_flow_offload_put(struct dp_flow_offload_item *offload) + } + } + info.flow_mark = mark; ++ info.pmd = NULL; + + port = netdev_ports_get(in_port, dpif_type_str); + if (!port || netdev_vport_is_vport_class(port->netdev_class)) { +@@ -2726,6 +2908,41 @@ err_free: + return -1; + } + ++static void ++queue_netdev_flow_put(struct dp_netdev_pmd_thread *pmd, ++ struct dp_netdev_flow *flow, struct match *match, ++ const struct nlattr *actions, size_t actions_len, bool is_modify) ++{ ++ struct dp_flow_offload_item *offload; ++ int op; ++ ++ if (!netdev_is_flow_api_enabled()) { ++ return; ++ } ++ ++ if (ovsthread_once_start(&offload_thread_once)) { ++ xpthread_cond_init(&dp_flow_offload.cond, NULL); ++ ovs_thread_create("dp_netdev_flow_offload", ++ dp_netdev_flow_offload_main, NULL); ++ ovsthread_once_done(&offload_thread_once); ++ } ++ ++ if (flow->mark != INVALID_FLOW_MARK) { ++ op = DP_NETDEV_FLOW_OFFLOAD_OP_MOD; ++ } else { ++ op = DP_NETDEV_FLOW_OFFLOAD_OP_ADD; ++ } ++ offload = dp_netdev_alloc_flow_offload(pmd, flow, op); ++ offload->match = *match; ++ offload->actions = xmalloc(actions_len); ++ memcpy(offload->actions, actions, actions_len); ++ offload->actions_len = actions_len; ++ ++ dp_netdev_append_flow_offload(offload); ++} ++ ++#endif ++ + static void * + dp_netdev_flow_offload_main(void *data OVS_UNUSED) + { +@@ -2791,39 +3008,6 @@ queue_netdev_flow_del(struct dp_netdev_pmd_thread *pmd, + dp_netdev_append_flow_offload(offload); + } + +-static void +-queue_netdev_flow_put(struct dp_netdev_pmd_thread *pmd, +- struct dp_netdev_flow *flow, struct match *match, +- const struct nlattr *actions, size_t actions_len) +-{ +- struct dp_flow_offload_item *offload; +- int op; +- +- if (!netdev_is_flow_api_enabled()) { +- return; +- } +- +- if (ovsthread_once_start(&offload_thread_once)) { +- xpthread_cond_init(&dp_flow_offload.cond, NULL); +- ovs_thread_create("dp_netdev_flow_offload", +- dp_netdev_flow_offload_main, NULL); +- ovsthread_once_done(&offload_thread_once); +- } +- +- if (flow->mark != INVALID_FLOW_MARK) { +- op = DP_NETDEV_FLOW_OFFLOAD_OP_MOD; +- } else { +- op = DP_NETDEV_FLOW_OFFLOAD_OP_ADD; +- } +- offload = dp_netdev_alloc_flow_offload(pmd, flow, op); +- offload->match = *match; +- offload->actions = xmalloc(actions_len); +- memcpy(offload->actions, actions, actions_len); +- offload->actions_len = actions_len; +- +- dp_netdev_append_flow_offload(offload); +-} +- + static void + dp_netdev_pmd_remove_flow(struct dp_netdev_pmd_thread *pmd, + struct dp_netdev_flow *flow) +@@ -2837,10 +3021,8 @@ dp_netdev_pmd_remove_flow(struct dp_netdev_pmd_thread *pmd, + ovs_assert(cls != NULL); + dpcls_remove(cls, &flow->cr); + cmap_remove(&pmd->flow_table, node, dp_netdev_flow_hash(&flow->ufid)); +- if (flow->mark != INVALID_FLOW_MARK) { +- queue_netdev_flow_del(pmd, flow); +- } + flow->dead = true; ++ queue_netdev_flow_del(pmd, flow); + + dp_netdev_flow_unref(flow); + } +@@ -2863,10 +3045,28 @@ dpif_netdev_flow_flush(struct dpif *dpif) + struct dp_netdev *dp = get_dp_netdev(dpif); + struct dp_netdev_pmd_thread *pmd; + ++#ifdef HAVE_HWOFF_AGENT ++ hwoff_func* funcs = hwoff_get_funcs(); ++ if (funcs->hwoff_set_offload_state != NULL) { ++ funcs->hwoff_set_offload_state(HWOFF_OFFLOAD_DISABLE); ++ } ++#endif ++ + CMAP_FOR_EACH (pmd, node, &dp->poll_threads) { + dp_netdev_pmd_flow_flush(pmd); ++#ifdef HAVE_HWOFF_AGENT ++ if (dp->dp_pmd_ukey_purge_cb) { ++ dp->dp_pmd_ukey_purge_cb(dp->dp_pmd_ukey_purge_aux, pmd->core_id); ++ } ++#endif + } + ++#ifdef HAVE_HWOFF_AGENT ++ if (funcs->hwoff_set_offload_state != NULL) { ++ funcs->hwoff_set_offload_state(HWOFF_OFFLOAD_ENABLE); ++ } ++#endif ++ + return 0; + } + +@@ -3480,6 +3680,9 @@ dp_netdev_flow_to_dpif_flow(const struct dp_netdev *dp, + } + + flow->ufid = netdev_flow->ufid; ++#ifdef HAVE_HWOFF_AGENT ++ flow->mega_ufid = netdev_flow->mega_ufid; ++#endif + flow->ufid_present = true; + flow->pmd_id = netdev_flow->pmd_id; + +@@ -3687,7 +3890,20 @@ dp_netdev_flow_add(struct dp_netdev_pmd_thread *pmd, + cmap_insert(&pmd->flow_table, CONST_CAST(struct cmap_node *, &flow->node), + dp_netdev_flow_hash(&flow->ufid)); + +- queue_netdev_flow_put(pmd, flow, match, actions, actions_len); ++#ifdef HAVE_HWOFF_AGENT ++ struct netdev *upcall_dev = NULL; ++ const char *dpif_type_str = dpif_normalize_type(pmd->dp->class->type); ++ ++ upcall_dev = netdev_ports_get(in_port, dpif_type_str); ++ hwoff_func* funcs = hwoff_get_funcs(); ++ if ((funcs->hwoff_is_support_offload == NULL) || ++ !funcs->hwoff_is_support_offload(upcall_dev)) { ++ queue_netdev_flow_put(pmd, flow, match, actions, actions_len, false); ++ } ++ netdev_close(upcall_dev); ++#else ++ queue_netdev_flow_put(pmd, flow, match, actions, actions_len, false); ++#endif + + if (OVS_UNLIKELY(!VLOG_DROP_DBG((&upcall_rl)))) { + struct ds ds = DS_EMPTY_INITIALIZER; +@@ -3738,6 +3954,70 @@ dp_netdev_flow_add(struct dp_netdev_pmd_thread *pmd, + return flow; + } + ++ ++#ifdef HAVE_HWOFF_AGENT ++static bool ++is_need_clear_forward_flow(struct dp_netdev_flow *netdev_flow, ++ struct eth_addr *temp_mac, uint32_t *dp_in_port) ++{ ++ struct hwoff_migrate_rarp_mac_entry *entry = NULL; ++ bool clear_flow = false; ++ struct hwoff_migrate_rarp_mac_infos *hwoff_migrate_rarp_mac_infos = hwoff_migrate_rarp_mac_infos_get(); ++ if (netdev_flow == NULL) { ++ return false; ++ } ++ if (hwoff_rarp_status_get()) { ++ ovs_rwlock_wrlock(&hwoff_migrate_rarp_mac_infos->rw); ++ if (unlikely(hwoff_migrate_rarp_mac_infos->length)) { ++ entry = hwoff_get_entry_by_mac(netdev_flow->flow.dl_src); ++ if (entry && entry->is_need_del) { ++ hwoff_rarp_mac_remove_from_list(entry); ++ (void)memcpy(&temp_mac->ea, &netdev_flow->flow.dl_src.ea, RTE_ETHER_ADDR_LEN); ++ *dp_in_port = netdev_flow->flow.in_port.odp_port; ++ clear_flow = true; ++ } ++ } ++ ovs_rwlock_unlock(&hwoff_migrate_rarp_mac_infos->rw); ++ } ++ return clear_flow; ++} ++ ++static void dp_netdev_clear_flow(struct dp_netdev_pmd_thread *pmd, struct eth_addr smac, uint32_t dp_in_port) ++{ ++ struct dp_netdev *dp = pmd->dp; ++ struct dp_netdev_flow *netdev_flow = NULL; ++ ovs_mutex_lock(&pmd->flow_mutex); ++ CMAP_FOR_EACH(netdev_flow, node, &pmd->flow_table) ++ { ++ if (hwoff_rarp_status_get() && ((eth_addr_equals(netdev_flow->flow.dl_src, smac) && ++ !eth_addr_is_broadcast(netdev_flow->flow.dl_dst) && dp_in_port != netdev_flow->flow.in_port.odp_port) || ++ (eth_addr_equals(netdev_flow->flow.dl_dst, smac) && !eth_addr_is_broadcast(netdev_flow->flow.dl_src)))) { ++ dp_netdev_pmd_remove_flow(pmd, netdev_flow); ++ } ++ } ++ ovs_mutex_unlock(&pmd->flow_mutex); ++ if (dp->dp_pmd_ukey_purge_cb) { ++ dp->dp_pmd_ukey_purge_cb(dp->dp_pmd_ukey_purge_aux, pmd->core_id); ++ } ++} ++ ++static void ++dp_netdev_clear_flow_by_rarp(struct dp_netdev_pmd_thread *pmd, struct dp_netdev_flow *flow) ++ OVS_ACQUIRES(pmd->flow_mutex) ++{ ++ uint32_t dp_in_port = 0; ++ struct eth_addr temp_mac; ++ (void)memset(&temp_mac, 0, sizeof(struct eth_addr)); ++ if (flow == NULL) { ++ return; ++ } ++ ++ if (hwoff_rarp_status_get() && is_need_clear_forward_flow(flow, &temp_mac, &dp_in_port)) { ++ dp_netdev_clear_flow(pmd, temp_mac, dp_in_port); ++ } ++} ++#endif ++ + static int + flow_put_on_pmd(struct dp_netdev_pmd_thread *pmd, + struct netdev_flow_key *key, +@@ -3748,7 +4028,6 @@ flow_put_on_pmd(struct dp_netdev_pmd_thread *pmd, + { + struct dp_netdev_flow *netdev_flow; + int error = 0; +- + if (stats) { + memset(stats, 0, sizeof *stats); + } +@@ -3774,7 +4053,7 @@ flow_put_on_pmd(struct dp_netdev_pmd_thread *pmd, + ovsrcu_set(&netdev_flow->actions, new_actions); + + queue_netdev_flow_put(pmd, netdev_flow, match, +- put->actions, put->actions_len); ++ put->actions, put->actions_len, true); + + if (stats) { + get_dpif_flow_status(pmd->dp, netdev_flow, stats, NULL); +@@ -3801,6 +4080,9 @@ flow_put_on_pmd(struct dp_netdev_pmd_thread *pmd, + } + } + ovs_mutex_unlock(&pmd->flow_mutex); ++#ifdef HAVE_HWOFF_AGENT ++ dp_netdev_clear_flow_by_rarp(pmd, netdev_flow); ++#endif + return error; + } + +@@ -3883,6 +4165,41 @@ dpif_netdev_flow_put(struct dpif *dpif, const struct dpif_flow_put *put) + return error; + } + ++#ifdef HAVE_HWOFF_AGENT ++static void ++hwoff_pmd_del_reverse_flow(struct dp_netdev_flow *netdev_flow, struct dp_netdev_pmd_thread *pmd) ++{ ++ bool clear_flag = false; ++ struct dp_netdev *dp = pmd->dp; ++ struct eth_addr del_flow_smac = { 0 }; ++ struct dp_netdev_flow *netdev_flow_iter = NULL; ++ struct hwoff_migrate_rarp_mac_entry *entry = NULL; ++ struct hwoff_migrate_rarp_mac_infos *migrate_rarp_mac_infos = hwoff_migrate_rarp_mac_infos_get(); ++ ++ if (!hwoff_rarp_status_get()) { ++ return; ++ } ++ ++ if (unlikely(migrate_rarp_mac_infos->length) != 0) { ++ ovs_rwlock_wrlock(&migrate_rarp_mac_infos->rw); ++ entry = hwoff_get_entry_by_mac(netdev_flow->flow.dl_dst); ++ if (entry != NULL && entry->is_need_del == true) { ++ hwoff_rarp_mac_remove_from_list(entry); ++ CMAP_FOR_EACH(netdev_flow_iter, node, &pmd->flow_table) { ++ if (eth_addr_equals(netdev_flow_iter->flow.dl_src, netdev_flow->flow.dl_dst) && ++ !(eth_addr_is_broadcast(netdev_flow_iter->flow.dl_dst))) { ++ dp_netdev_pmd_remove_flow(pmd, netdev_flow_iter); ++ } ++ } ++ if (dp->dp_pmd_ukey_purge_cb) { ++ dp->dp_pmd_ukey_purge_cb(dp->dp_pmd_ukey_purge_aux, pmd->core_id); ++ } ++ } ++ ovs_rwlock_unlock(&migrate_rarp_mac_infos->rw); ++ } ++} ++#endif ++ + static int + flow_del_on_pmd(struct dp_netdev_pmd_thread *pmd, + struct dpif_flow_stats *stats, +@@ -3895,6 +4212,9 @@ flow_del_on_pmd(struct dp_netdev_pmd_thread *pmd, + netdev_flow = dp_netdev_pmd_find_flow(pmd, del->ufid, del->key, + del->key_len); + if (netdev_flow) { ++#ifdef HAVE_HWOFF_AGENT ++ hwoff_pmd_del_reverse_flow(netdev_flow, pmd); ++#endif + if (stats) { + get_dpif_flow_status(pmd->dp, netdev_flow, stats, NULL); + } +@@ -3903,7 +4223,6 @@ flow_del_on_pmd(struct dp_netdev_pmd_thread *pmd, + error = ENOENT; + } + ovs_mutex_unlock(&pmd->flow_mutex); +- + return error; + } + +@@ -4618,7 +4937,6 @@ dp_netdev_pmd_flush_output_on_port(struct dp_netdev_pmd_thread *pmd, + + output_cnt = dp_packet_batch_size(&p->output_pkts); + ovs_assert(output_cnt > 0); +- + netdev_send(p->port->netdev, tx_qid, &p->output_pkts, dynamic_txqs); + dp_packet_batch_init(&p->output_pkts); + +@@ -4665,6 +4983,76 @@ dp_netdev_pmd_flush_output_packets(struct dp_netdev_pmd_thread *pmd, + return output_cnt; + } + ++#ifdef HAVE_HWOFF_AGENT ++/* The struct is use to classift batch's packets into different batch according to ++ * packet's input port*/ ++#define HWOFF_NETDEV_NAME_LENGTH 100 ++struct hwoff_dpif_port_classifier_node { ++ odp_port_t port; ++ struct dp_packet_batch batch; ++}; ++ ++struct hwoff_dpif_port_classifier { ++ size_t node_count; ++ struct hwoff_dpif_port_classifier_node node[NETDEV_MAX_BURST]; ++}; ++ ++static odp_port_t ++hwoff_dpif_port_get_by_mbuf(struct dp_packet *packet) ++{ ++ uint16_t dpdk_port = 0; ++ char dev_name[HWOFF_NETDEV_NAME_LENGTH] = {0}; ++ odp_port_t port_no = ODPP_NONE; ++ ++ if (packet != NULL) { ++ dpdk_port = packet->mbuf.port; ++ hwoff_netdev_name_get(dpdk_port, dev_name, HWOFF_NETDEV_NAME_LENGTH); ++ port_no = dpif_netdev_get_odp_no_by_name(dev_name); ++ } ++ return port_no; ++} ++ ++static void ++hwoff_dpif_port_classift_insert(odp_port_t port_no, struct dp_packet *packet, ++ struct hwoff_dpif_port_classifier *port_classifile) ++{ ++ struct hwoff_dpif_port_classifier_node *node = NULL; ++ for (int i = 0; i < port_classifile->node_count; ++i) { ++ if (port_classifile->node[i].port == port_no) { ++ node = &port_classifile->node[i]; ++ node->batch.packets[node->batch.count++] = packet; ++ return; ++ } ++ } ++ ++ node = &port_classifile->node[port_classifile->node_count++]; ++ node->port = port_no; ++ node->batch.packets[node->batch.count++] = packet; ++ return; ++} ++ ++/* redistribute batch's packets, current scheme is to iterate through an packets array ++ of max size 32*/ ++static void ++hwoff_dpif_mbuf_packets_classify(const struct dp_packet_batch *packets, ++ struct hwoff_dpif_port_classifier *port_classifile) ++{ ++ if (packets == NULL || port_classifile == NULL) { ++ return; ++ } ++ ++ odp_port_t port_no = ODPP_NONE; ++ ++ for (int i = 0; i < packets->count; ++i) { ++ port_no = hwoff_dpif_port_get_by_mbuf(packets->packets[i]); ++ if (port_no != ODPP_NONE) { ++ hwoff_dpif_port_classift_insert(port_no, packets->packets[i], port_classifile); ++ } ++ } ++ return; ++} ++#endif ++ + static int + dp_netdev_process_rxq_port(struct dp_netdev_pmd_thread *pmd, + struct dp_netdev_rxq *rxq, +@@ -4707,9 +5095,24 @@ dp_netdev_process_rxq_port(struct dp_netdev_pmd_thread *pmd, + } + } + } ++ ++#ifdef HAVE_HWOFF_AGENT ++ struct hwoff_dpif_port_classifier port_classifier = {0}; ++ /* When the rxq is be shared, redistribute packets in batch ++ * according to packet's input port */ ++ if (hwoff_netdev_is_shared(rxq->rx->netdev)) { ++ hwoff_dpif_mbuf_packets_classify(&batch, &port_classifier); ++ for (int i = 0; i < port_classifier.node_count; ++i) { ++ dp_netdev_input(pmd, &port_classifier.node[i].batch, ++ port_classifier.node[i].port); ++ } ++ } else { ++ dp_netdev_input(pmd, &batch, port_no); ++ } ++#else + /* Process packet batch. */ + dp_netdev_input(pmd, &batch, port_no); +- ++#endif + /* Assign processing cycles to rx queue. */ + cycles = cycle_timer_stop(&pmd->perf_stats, &timer); + dp_netdev_rxq_add_cycles(rxq, RXQ_CYCLES_PROC_CURR, cycles); +@@ -4991,11 +5394,23 @@ rxq_scheduling(struct dp_netdev *dp, bool pinned) OVS_REQUIRES(dp->port_mutex) + int numa_id; + bool assign_cyc = dp->pmd_rxq_assign_cyc; + ++#ifdef HAVE_HWOFF_AGENT ++ /* share upcall queues just will be assigned once to avoid invalid poll*/ ++ bool share_upcall_scheduled = false; ++#endif ++ + HMAP_FOR_EACH (port, node, &dp->ports) { + if (!netdev_is_pmd(port->netdev)) { + continue; + } + ++#ifdef HAVE_HWOFF_AGENT ++ bool is_share_upcall_dev = hwoff_netdev_is_shared(port->netdev); ++ if (share_upcall_scheduled && is_share_upcall_dev) { ++ continue; ++ } ++#endif ++ + for (int qid = 0; qid < port->n_rxq; qid++) { + struct dp_netdev_rxq *q = &port->rxqs[qid]; + +@@ -5037,6 +5452,11 @@ rxq_scheduling(struct dp_netdev *dp, bool pinned) OVS_REQUIRES(dp->port_mutex) + rxqs[n_rxqs++] = q; + } + } ++#ifdef HAVE_HWOFF_AGENT ++ if (is_share_upcall_dev) { ++ share_upcall_scheduled = true; ++ } ++#endif + } + + if (n_rxqs > 1 && assign_cyc) { +@@ -5102,7 +5522,6 @@ reload_affected_pmds(struct dp_netdev *dp) + + CMAP_FOR_EACH (pmd, node, &dp->poll_threads) { + if (pmd->need_reload) { +- flow_mark_flush(pmd); + dp_netdev_reload_pmd__(pmd); + } + } +@@ -6508,7 +6927,19 @@ dp_netdev_destroy_pmd(struct dp_netdev_pmd_thread *pmd) + { + struct dpcls *cls; + ++#ifdef HAVE_HWOFF_AGENT ++ hwoff_func* funcs = hwoff_get_funcs(); ++ if (funcs->hwoff_set_offload_state != NULL) { ++ funcs->hwoff_set_offload_state(HWOFF_OFFLOAD_DISABLE); ++ } ++#endif + dp_netdev_pmd_flow_flush(pmd); ++#ifdef HAVE_HWOFF_AGENT ++ if (funcs->hwoff_set_offload_state != NULL) { ++ funcs->hwoff_set_offload_state(HWOFF_OFFLOAD_ENABLE); ++ } ++#endif ++ + hmap_destroy(&pmd->send_port_cache); + hmap_destroy(&pmd->tnl_port_cache); + hmap_destroy(&pmd->tx_ports); +@@ -6842,6 +7273,7 @@ dpif_netdev_packet_get_rss_hash(struct dp_packet *packet, + return hash; + } + ++#ifndef HAVE_HWOFF_AGENT + struct packet_batch_per_flow { + unsigned int byte_count; + uint16_t tcp_flags; +@@ -6849,6 +7281,7 @@ struct packet_batch_per_flow { + + struct dp_packet_batch array; + }; ++#endif + + static inline void + packet_batch_per_flow_update(struct packet_batch_per_flow *batch, +@@ -6885,6 +7318,10 @@ packet_batch_per_flow_execute(struct packet_batch_per_flow *batch, + + actions = dp_netdev_flow_get_actions(flow); + ++#ifdef HAVE_HWOFF_AGENT ++ dp_netdev_flow_offload_add(pmd, flow, NULL, &batch->array, actions->actions, actions->size); ++#endif ++ + dp_netdev_execute_actions(pmd, &batch->array, true, &flow->flow, + actions->actions, actions->size); + } +@@ -7203,6 +7640,9 @@ handle_packet_upcall(struct dp_netdev_pmd_thread *pmd, + uint32_t hash = dp_netdev_flow_hash(&netdev_flow->ufid); + smc_insert(pmd, key, hash); + emc_probabilistic_insert(pmd, key, netdev_flow); ++#ifdef HAVE_HWOFF_AGENT ++ dp_netdev_clear_flow_by_rarp(pmd, netdev_flow); ++#endif + } + if (pmd_perf_metrics_enabled(pmd)) { + /* Update upcall stats. */ +@@ -7273,6 +7713,9 @@ fast_path_processing(struct dp_netdev_pmd_thread *pmd, + if (netdev_flow) { + lookup_cnt += add_lookup_cnt; + rules[i] = &netdev_flow->cr; ++#ifdef HAVE_HWOFF_AGENT ++ dp_netdev_clear_flow_by_rarp(pmd, netdev_flow); ++#endif + continue; + } + +@@ -7382,12 +7825,12 @@ dp_netdev_input__(struct dp_netdev_pmd_thread *pmd, + + /* All the flow batches need to be reset before any call to + * packet_batch_per_flow_execute() as it could potentially trigger +- * recirculation. When a packet matching flow ‘j’ happens to be ++ * recirculation. When a packet matching flow 'j' happens to be + * recirculated, the nested call to dp_netdev_input__() could potentially + * classify the packet as matching another flow - say 'k'. It could happen + * that in the previous call to dp_netdev_input__() that same flow 'k' had + * already its own batches[k] still waiting to be served. So if its +- * ‘batch’ member is not reset, the recirculated packet would be wrongly ++ * 'batch' member is not reset, the recirculated packet would be wrongly + * appended to batches[k] of the 1st call to dp_netdev_input__(). */ + for (i = 0; i < n_batches; i++) { + batches[i].flow->batch = NULL; +@@ -7435,6 +7878,16 @@ dpif_netdev_register_upcall_cb(struct dpif *dpif, upcall_callback *cb, + dp->upcall_aux = aux; + dp->upcall_cb = cb; + } ++#ifdef HAVE_HWOFF_AGENT ++static void ++dpif_netdev_register_pmd_ukey_purge_cb(struct dpif *dpif, dp_pmd_ukey_purge_callback *cb, ++ void *aux) ++{ ++ struct dp_netdev *dp = get_dp_netdev(dpif); ++ dp->dp_pmd_ukey_purge_cb = cb; ++ dp->dp_pmd_ukey_purge_aux = aux; ++} ++#endif + + static void + dpif_netdev_xps_revalidate_pmd(const struct dp_netdev_pmd_thread *pmd, +@@ -7517,6 +7970,21 @@ pmd_send_port_cache_lookup(const struct dp_netdev_pmd_thread *pmd, + return tx_port_lookup(&pmd->send_port_cache, port_no); + } + ++#ifdef HAVE_HWOFF_AGENT ++struct netdev * ++dp_get_outdev_from_pmd(odp_port_t port_no, void *tmp_pmd) ++{ ++ struct dp_netdev_pmd_thread *pmd = (struct dp_netdev_pmd_thread *)tmp_pmd; ++ struct tx_port *p = pmd_send_port_cache_lookup(pmd, port_no); ++ ++ if (p != NULL && p->port != NULL) { ++ return p->port->netdev; ++ } ++ ++ return NULL; ++} ++#endif ++ + static int + push_tnl_action(const struct dp_netdev_pmd_thread *pmd, + const struct nlattr *attr, +@@ -8046,6 +8514,18 @@ dpif_netdev_ct_dump_done(struct dpif *dpif OVS_UNUSED, + return err; + } + ++#ifdef HAVE_HWOFF_AGENT ++static int ++dpif_netdev_ct_flush(struct dpif *dpif, const uint16_t *zone, ++ union ct_addr *sip, union ct_addr *dip, ++ union ct_addr *smask, union ct_addr *dmask, ++ uint16_t dl_type, bool is_force) ++{ ++ struct dp_netdev *dp = get_dp_netdev(dpif); ++ ++ return conntrack_flush(dp->conntrack, zone, sip, dip, smask, dmask, dl_type, is_force); ++} ++#else + static int + dpif_netdev_ct_flush(struct dpif *dpif, const uint16_t *zone, + const struct ct_dpif_tuple *tuple) +@@ -8057,6 +8537,7 @@ dpif_netdev_ct_flush(struct dpif *dpif, const uint16_t *zone, + } + return conntrack_flush(dp->conntrack, zone); + } ++#endif + + static int + dpif_netdev_ct_set_maxconns(struct dpif *dpif, uint32_t maxconns) +@@ -8459,6 +8940,9 @@ const struct dpif_class dpif_netdev_class = { + dpif_netdev_bond_add, + dpif_netdev_bond_del, + dpif_netdev_bond_stats_get, ++#ifdef HAVE_HWOFF_AGENT ++ dpif_netdev_register_pmd_ukey_purge_cb, ++#endif + }; + + static void +diff --git a/openvswitch-2.14.2/lib/dpif-netdev.h b/openvswitch-2.14.2/lib/dpif-netdev.h +index 6db6ed2..84e8b6c 100644 +--- a/openvswitch-2.14.2/lib/dpif-netdev.h ++++ b/openvswitch-2.14.2/lib/dpif-netdev.h +@@ -24,6 +24,9 @@ + #include "openvswitch/types.h" + #include "dp-packet.h" + #include "packets.h" ++#ifdef HAVE_HWOFF_AGENT ++#include "ovs-atomic.h" ++#endif + + #ifdef __cplusplus + extern "C" { +@@ -34,6 +37,12 @@ extern "C" { + enum { DP_NETDEV_HEADROOM = 2 + VLAN_HEADER_LEN }; + + bool dpif_is_netdev(const struct dpif *); ++odp_port_t dpif_netdev_get_odp_no_by_name(const char *devname); ++#ifdef HAVE_HWOFF_AGENT ++struct netdev * dp_get_outdev_from_pmd(odp_port_t port_no, void *tmp_pmd); ++bool dp_netdev_flow_dead_status_get(void *flow); ++void dp_netdev_hwoff_switch_set(int value); ++#endif + + #define NR_QUEUE 1 + #define NR_PMD_THREADS 1 +diff --git a/openvswitch-2.14.2/lib/dpif-netlink.c b/openvswitch-2.14.2/lib/dpif-netlink.c +index 2f881e4..6ad0f59 100644 +--- a/openvswitch-2.14.2/lib/dpif-netlink.c ++++ b/openvswitch-2.14.2/lib/dpif-netlink.c +@@ -2098,6 +2098,7 @@ parse_flow_put(struct dpif_netlink *dpif, struct dpif_flow_put *put) + + info.tp_dst_port = dst_port; + info.tunnel_csum_on = csum_on; ++ info.pmd = NULL; + info.recirc_id_shared_with_tc = (dpif->user_features + & OVS_DP_F_TC_RECIRC_SHARING); + info.tc_modify_flow_deleted = false; +@@ -2900,6 +2901,20 @@ dpif_netlink_ct_dump_done(struct dpif *dpif OVS_UNUSED, + return err; + } + ++#ifdef HAVE_HWOFF_AGENT ++static int ++dpif_netlink_ct_flush(struct dpif *dpif OVS_UNUSED, const uint16_t *zone, ++ union ct_addr *sip OVS_UNUSED, union ct_addr *dip OVS_UNUSED, ++ union ct_addr *smask OVS_UNUSED, union ct_addr *dmask OVS_UNUSED, ++ uint16_t dl_type OVS_UNUSED, bool is_force OVS_UNUSED) ++{ ++ if (zone) { ++ return nl_ct_flush_zone(*zone); ++ } else { ++ return nl_ct_flush(); ++ } ++} ++#else + static int + dpif_netlink_ct_flush(struct dpif *dpif OVS_UNUSED, const uint16_t *zone, + const struct ct_dpif_tuple *tuple) +@@ -2912,6 +2927,7 @@ dpif_netlink_ct_flush(struct dpif *dpif OVS_UNUSED, const uint16_t *zone, + return nl_ct_flush(); + } + } ++#endif + + static int + dpif_netlink_ct_set_limits(struct dpif *dpif OVS_UNUSED, +@@ -4012,6 +4028,9 @@ const struct dpif_class dpif_netlink_class = { + NULL, /* bond_add */ + NULL, /* bond_del */ + NULL, /* bond_stats_get */ ++#ifdef HAVE_HWOFF_AGENT ++ NULL, ++#endif + }; + + static int +diff --git a/openvswitch-2.14.2/lib/dpif-provider.h b/openvswitch-2.14.2/lib/dpif-provider.h +index 0e024c1..c7463a7 100644 +--- a/openvswitch-2.14.2/lib/dpif-provider.h ++++ b/openvswitch-2.14.2/lib/dpif-provider.h +@@ -25,6 +25,7 @@ + #include "openflow/openflow.h" + #include "dpif.h" + #include "util.h" ++#include "conntrack.h" + + #ifdef __cplusplus + extern "C" { +@@ -463,8 +464,14 @@ struct dpif_class { + * - If 'tuple' is not NULL, flush the conntrack entry specified by + * 'tuple' in '*zone'. If 'zone' is NULL, use the default zone + * (zone 0). */ ++#ifdef HAVE_HWOFF_AGENT ++ int (*ct_flush)(struct dpif *, const uint16_t *zone, ++ union ct_addr *sip, union ct_addr *dip, ++ union ct_addr *smask, union ct_addr *dmask, uint16_t dl_type, bool is_force); ++#else + int (*ct_flush)(struct dpif *, const uint16_t *zone, + const struct ct_dpif_tuple *tuple); ++#endif + /* Set max connections allowed. */ + int (*ct_set_maxconns)(struct dpif *, uint32_t maxconns); + /* Get max connections allowed. */ +@@ -628,6 +635,9 @@ struct dpif_class { + * sufficient to store BOND_BUCKETS number of elements. */ + int (*bond_stats_get)(struct dpif *dpif, uint32_t bond_id, + uint64_t *n_bytes); ++#ifdef HAVE_HWOFF_AGENT ++ void (*register_dp_pmd_ukey_purge_cb)(struct dpif *, dp_pmd_ukey_purge_callback *, void *aux); ++#endif + }; + + extern const struct dpif_class dpif_netlink_class; +diff --git a/openvswitch-2.14.2/lib/dpif.c b/openvswitch-2.14.2/lib/dpif.c +index 7cac3a6..0579dd2 100644 +--- a/openvswitch-2.14.2/lib/dpif.c ++++ b/openvswitch-2.14.2/lib/dpif.c +@@ -597,7 +597,7 @@ dpif_port_add(struct dpif *dpif, struct netdev *netdev, odp_port_t *port_nop) + VLOG_DBG_RL(&dpmsg_rl, "%s: added %s as port %"PRIu32, + dpif_name(dpif), netdev_name, port_no); + +- if (!dpif_is_tap_port(netdev_get_type(netdev))) { ++ // if (!dpif_is_tap_port(netdev_get_type(netdev))) { + + const char *dpif_type_str = dpif_normalize_type(dpif_type(dpif)); + struct dpif_port dpif_port; +@@ -606,7 +606,7 @@ dpif_port_add(struct dpif *dpif, struct netdev *netdev, odp_port_t *port_nop) + dpif_port.name = CONST_CAST(char *, netdev_name); + dpif_port.port_no = port_no; + netdev_ports_insert(netdev, dpif_type_str, &dpif_port); +- } ++ // } + } else { + VLOG_WARN_RL(&error_rl, "%s: failed to add %s as port: %s", + dpif_name(dpif), netdev_name, ovs_strerror(error)); +@@ -1504,6 +1504,15 @@ dpif_register_upcall_cb(struct dpif *dpif, upcall_callback *cb, void *aux) + } + } + ++#ifdef HAVE_HWOFF_AGENT ++void ++dpif_register_dp_pmd_ukey_purge_cb(struct dpif *dpif, dp_pmd_ukey_purge_callback *cb, void *aux) ++{ ++ if (dpif->dpif_class->register_dp_pmd_ukey_purge_cb) { ++ dpif->dpif_class->register_dp_pmd_ukey_purge_cb(dpif, cb, aux); ++ } ++} ++#endif + void + dpif_enable_upcall(struct dpif *dpif) + { +diff --git a/openvswitch-2.14.2/lib/dpif.h b/openvswitch-2.14.2/lib/dpif.h +index 2d52f01..9b7a1d0 100644 +--- a/openvswitch-2.14.2/lib/dpif.h ++++ b/openvswitch-2.14.2/lib/dpif.h +@@ -598,6 +598,9 @@ struct dpif_flow { + const struct nlattr *actions; /* Actions, as OVS_ACTION_ATTR_ */ + size_t actions_len; /* 'actions' length in bytes. */ + ovs_u128 ufid; /* Unique flow identifier. */ ++#ifdef HAVE_HWOFF_AGENT ++ ovs_u128 mega_ufid; /* Flow mega identifier. */ ++#endif + bool ufid_present; /* True if 'ufid' was provided by datapath.*/ + unsigned pmd_id; /* Datapath poll mode driver id. */ + struct dpif_flow_stats stats; /* Flow statistics. */ +@@ -838,6 +841,10 @@ struct dpif_upcall { + + void dpif_register_dp_purge_cb(struct dpif *, dp_purge_callback *, void *aux); + ++#ifdef HAVE_HWOFF_AGENT ++typedef void dp_pmd_ukey_purge_callback(void *auc, unsigned pmd_id); ++void dpif_register_dp_pmd_ukey_purge_cb(struct dpif * dpif, dp_pmd_ukey_purge_callback *, void * aux); ++#endif + /* A callback to process an upcall, currently implemented only by dpif-netdev. + * + * The caller provides the 'packet' and 'flow' to process, the corresponding +diff --git a/openvswitch-2.14.2/lib/hwoff_init_func.c b/openvswitch-2.14.2/lib/hwoff_init_func.c +new file mode 100644 +index 0000000..6812b57 +--- /dev/null ++++ b/openvswitch-2.14.2/lib/hwoff_init_func.c +@@ -0,0 +1,74 @@ ++/* ++ * Copyright (c) 2021 Cloudbase Solutions Srl ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++#include "hwoff_init_func.h" ++#include ++ ++#define HWOFF_SHARED_LIB "libdpak_ovs.so" ++#define ADD_FUNC(name) {#name, (void**)&hwoff_funcs.name} ++ ++typedef struct { ++ const char *name; ++ void **func; ++} func_cfg; ++ ++static hwoff_func hwoff_funcs = {0}; ++ ++static func_cfg func_cfgs[] = { ++ ADD_FUNC(hwoff_rte_flow_query_count), ++ ADD_FUNC(hwoff_rte_flow_create), ++ ADD_FUNC(hwoff_rte_flow_destroy), ++ ADD_FUNC(hwoff_is_hiovs_netdev), ++ ADD_FUNC(hwoff_get_eth_vport_id), ++ ADD_FUNC(hwoff_is_support_offload), ++ ADD_FUNC(hwoff_rte_flow_alloc), ++ ADD_FUNC(hwoff_rte_flow_dealloc), ++ ADD_FUNC(hwoff_rte_flow_deleted_set), ++ ADD_FUNC(hwoff_rte_flow_deleted_get), ++ ADD_FUNC(hwoff_global_add_vxlan_vtep), ++ ADD_FUNC(hwoff_global_del_vxlan_vtep), ++ ADD_FUNC(hwoff_tnl_get_src_port), ++ ADD_FUNC(hwoff_parse_ovs_other_config), ++ ADD_FUNC(hwoff_is_ethdev), ++ ADD_FUNC(hwoff_set_offload_state), ++ ADD_FUNC(hwoff_set_qos), ++ ADD_FUNC(hwoff_set_ingress_policing), ++ ADD_FUNC(hwoff_parse_vf_extra_options), ++}; ++ ++hwoff_func* hwoff_get_funcs(void) ++{ ++ return &hwoff_funcs; ++} ++ ++int hwoff_funcs_init(void) ++{ ++ void *handler = dlopen(HWOFF_SHARED_LIB, RTLD_NOW); ++ if (handler == NULL) { ++ RTE_LOG(ERR, EAL, "%s load err %s \n", HWOFF_SHARED_LIB, dlerror()); ++ return -1; ++ } ++ ++ for (int index = 0; index < ARRAY_SIZE(func_cfgs); index++) { ++ *func_cfgs[index].func = dlsym(handler, func_cfgs[index].name); ++ if (*func_cfgs[index].func == NULL) { ++ RTE_LOG(ERR, EAL, "%s load func %s fail: %s", HWOFF_SHARED_LIB, func_cfgs[index].name, dlerror()); ++ dlclose(handler); ++ return -1; ++ } ++ } ++ ++ return 0; ++} +diff --git a/openvswitch-2.14.2/lib/hwoff_init_func.h b/openvswitch-2.14.2/lib/hwoff_init_func.h +new file mode 100644 +index 0000000..a13b012 +--- /dev/null ++++ b/openvswitch-2.14.2/lib/hwoff_init_func.h +@@ -0,0 +1,50 @@ ++/* ++ * Copyright (c) 2021 Cloudbase Solutions Srl ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef HWOFF_INIT_FUNC_H ++#define HWOFF_INIT_FUNC_H 1 ++ ++#include "dpak_ovs.h" ++ ++typedef struct { ++ int (*hwoff_rte_flow_query_count)(struct netdev *netdev, struct rte_flow *rte_flow, ++ struct rte_flow_query_count *query, struct rte_flow_error *error); ++ struct rte_flow *(*hwoff_rte_flow_create)(struct netdev *netdev, const struct rte_flow_attr *attr, ++ const struct rte_flow_item *items, const struct rte_flow_action *actions, ++ struct rte_flow_error *error); ++ int (*hwoff_rte_flow_destroy)(struct netdev *netdev, struct rte_flow *rte_flow, ++ struct rte_flow_error *error); ++ uint32_t (*hwoff_get_eth_vport_id)(struct netdev *netdev); ++ bool (*hwoff_is_hiovs_netdev)(const struct netdev *netdev); ++ bool (*hwoff_is_ethdev)(const struct netdev *netdev); ++ bool (*hwoff_is_support_offload)(const struct netdev *netdev); ++ struct rte_flow* (*hwoff_rte_flow_alloc)(ovs_u128 *ufid, void* flow_data); ++ void (*hwoff_rte_flow_dealloc)(struct rte_flow *flow); ++ void (*hwoff_rte_flow_deleted_set)(struct rte_flow *flow, bool flag); ++ bool (*hwoff_rte_flow_deleted_get)(struct rte_flow *flow); ++ int (*hwoff_global_add_vxlan_vtep)(bool is_ipv6, uint8_t *vxlan_dstip, uint32_t length, uint16_t dst_port); ++ int (*hwoff_global_del_vxlan_vtep)(bool is_ipv6, uint8_t *vxlan_dstip, uint32_t length); ++ uint16_t (*hwoff_tnl_get_src_port)(struct dp_packet *one_pkt); ++ void (*hwoff_parse_ovs_other_config)(const struct smap *ovs_other_config); ++ void (*hwoff_set_offload_state)(hwoff_offload_state_t offload); ++ void (*hwoff_set_qos)(uint16_t port_id, const char *type, const struct smap *details); ++ void (*hwoff_set_ingress_policing)(uint16_t port_id, uint32_t policer_rate, uint32_t policer_burst); ++ int (*hwoff_parse_vf_extra_options)(uint16_t dpdk_port_id, const struct smap *port_config); ++} hwoff_func; ++ ++hwoff_func* hwoff_get_funcs(void); ++int hwoff_funcs_init(void); ++#endif +diff --git a/openvswitch-2.14.2/lib/mac-learning.c b/openvswitch-2.14.2/lib/mac-learning.c +index f618348..d0644b3 100644 +--- a/openvswitch-2.14.2/lib/mac-learning.c ++++ b/openvswitch-2.14.2/lib/mac-learning.c +@@ -29,12 +29,95 @@ + #include "unaligned.h" + #include "util.h" + #include "vlan-bitmap.h" +- ++#include "openvswitch/vlog.h" ++VLOG_DEFINE_THIS_MODULE(mac_learning); + COVERAGE_DEFINE(mac_learning_learned); + COVERAGE_DEFINE(mac_learning_expired); + COVERAGE_DEFINE(mac_learning_evicted); + COVERAGE_DEFINE(mac_learning_moved); + ++ ++#ifdef HAVE_HWOFF_AGENT ++static struct hwoff_migrate_rarp_mac_infos g_hwoff_migrate_rarp_mac_infos; ++static bool g_hwoff_rarp_enabled = false; ++ ++struct hwoff_migrate_rarp_mac_infos *hwoff_migrate_rarp_mac_infos_get(void) ++{ ++ return &g_hwoff_migrate_rarp_mac_infos; ++} ++ ++bool hwoff_rarp_status_get(void) ++{ ++ return g_hwoff_rarp_enabled; ++} ++ ++struct hwoff_migrate_rarp_mac_entry *hwoff_get_entry_by_mac(struct eth_addr mac) ++{ ++ struct hwoff_migrate_rarp_mac_entry *entry_iter = NULL; ++ ++ HMAP_FOR_EACH_WITH_HASH (entry_iter, mac_entry_node, hash_mac(mac, 0, 0), ++ &g_hwoff_migrate_rarp_mac_infos.mac_info_list) { ++ if (eth_addr_equals(entry_iter->mac_addr, mac)) { ++ return entry_iter; ++ } ++ } ++ ++ return NULL; ++} ++ ++struct hwoff_migrate_rarp_mac_entry * hwoff_rarp_mac_insert_to_list(struct eth_addr mac) ++{ ++ if (g_hwoff_migrate_rarp_mac_infos.length >= HWOFF_MIGRATE_MAC_MAX_NUM) { ++ return NULL; ++ } ++ ++ uint32_t hash = hash_mac(mac, 0, 0); ++ struct hwoff_migrate_rarp_mac_entry *entry = hwoff_get_entry_by_mac(mac); ++ if (entry == NULL) { ++ entry = xmalloc(sizeof *entry); ++ memcpy(&entry->mac_addr.ea, &mac.ea, ETH_ADDR_LEN); ++ hmap_insert(&g_hwoff_migrate_rarp_mac_infos.mac_info_list, &entry->mac_entry_node, hash); ++ g_hwoff_migrate_rarp_mac_infos.length++; ++ } ++ ++ entry->is_need_del = true; ++ return entry; ++} ++ ++void hwoff_rarp_mac_remove_from_list(struct hwoff_migrate_rarp_mac_entry *entry) ++{ ++ if (OVS_UNLIKELY(entry == NULL)) { ++ return; ++ } ++ hmap_remove(&g_hwoff_migrate_rarp_mac_infos.mac_info_list, &entry->mac_entry_node); ++ g_hwoff_migrate_rarp_mac_infos.length--; ++ free(entry); ++ entry = NULL; ++} ++ ++void hwoff_rarp_mac_list_init(void) ++{ ++ hmap_init(&g_hwoff_migrate_rarp_mac_infos.mac_info_list); ++ ovs_rwlock_init(&g_hwoff_migrate_rarp_mac_infos.rw); ++ g_hwoff_migrate_rarp_mac_infos.length = 0; ++ g_hwoff_rarp_enabled = true; ++} ++ ++void hwoff_rarp_mac_list_uninit(void) ++{ ++ struct hwoff_migrate_rarp_mac_entry *entry_iter = NULL, *next_entry_iter = NULL; ++ ++ ovs_rwlock_wrlock(&g_hwoff_migrate_rarp_mac_infos.rw); ++ HMAP_FOR_EACH_SAFE (entry_iter, next_entry_iter, mac_entry_node, &g_hwoff_migrate_rarp_mac_infos.mac_info_list) { ++ hwoff_rarp_mac_remove_from_list(entry_iter); ++ } ++ hmap_destroy(&g_hwoff_migrate_rarp_mac_infos.mac_info_list); ++ g_hwoff_migrate_rarp_mac_infos.length = 0; ++ ovs_rwlock_unlock(&g_hwoff_migrate_rarp_mac_infos.rw); ++ g_hwoff_rarp_enabled = false; ++} ++#endif ++ + /* Returns the number of seconds since 'e' (within 'ml') was last learned. */ + int + mac_entry_age(const struct mac_learning *ml, const struct mac_entry *e) +@@ -410,12 +493,21 @@ is_mac_learning_update_needed(const struct mac_learning *ml, + * Keep the code here synchronized with that in is_mac_learning_update_needed() + * above. */ + static bool ++#ifdef HAVE_HWOFF_AGENT ++update_learning_table__(struct mac_learning *ml, struct eth_addr src, ++ int vlan, bool is_gratuitous_arp, bool is_bond, ++ void *in_port, void **out_port) ++#else + update_learning_table__(struct mac_learning *ml, struct eth_addr src, + int vlan, bool is_gratuitous_arp, bool is_bond, + void *in_port) ++#endif + OVS_REQ_WRLOCK(ml->rwlock) + { + struct mac_entry *mac; ++#ifdef HAVE_HWOFF_AGENT ++ void *mac_port = NULL; ++#endif + + if (!mac_learning_may_learn(ml, src, vlan)) { + return false; +@@ -437,7 +529,19 @@ update_learning_table__(struct mac_learning *ml, struct eth_addr src, + return false; + } + } +- ++#ifdef HAVE_HWOFF_AGENT ++ mac_port = mac_entry_get_port(ml, mac); ++ if (mac_port != in_port) { ++ if (mac_port) { ++ COVERAGE_INC(mac_learning_moved); ++ if (out_port) { ++ *out_port = mac_port; ++ } ++ } ++ mac_entry_set_port(ml, mac, in_port); ++ return true; ++ } ++#else + if (mac_entry_get_port(ml, mac) != in_port) { + if (mac_entry_get_port(ml, mac) != NULL) { + COVERAGE_INC(mac_learning_moved); +@@ -446,6 +550,7 @@ update_learning_table__(struct mac_learning *ml, struct eth_addr src, + mac_entry_set_port(ml, mac, in_port); + return true; + } ++#endif + return false; + } + +@@ -455,11 +560,19 @@ update_learning_table__(struct mac_learning *ml, struct eth_addr src, + * 'is_bond' is 'true'. + * + * Returns 'true' if 'ml' was updated, 'false' otherwise. */ ++#ifdef HAVE_HWOFF_AGENT ++bool ++mac_learning_update(struct mac_learning *ml, struct eth_addr src, ++ int vlan, bool is_gratuitous_arp, bool is_bond, ++ void *in_port, void **out_port) ++ OVS_EXCLUDED(ml->rwlock) ++#else + bool + mac_learning_update(struct mac_learning *ml, struct eth_addr src, + int vlan, bool is_gratuitous_arp, bool is_bond, + void *in_port) + OVS_EXCLUDED(ml->rwlock) ++#endif + { + bool need_update; + bool updated = false; +@@ -476,8 +589,13 @@ mac_learning_update(struct mac_learning *ml, struct eth_addr src, + if (need_update) { + /* Slow path: MAC learning table might need an update. */ + ovs_rwlock_wrlock(&ml->rwlock); ++#ifdef HAVE_HWOFF_AGENT ++ updated = update_learning_table__(ml, src, vlan, is_gratuitous_arp, ++ is_bond, in_port, out_port); ++#else + updated = update_learning_table__(ml, src, vlan, is_gratuitous_arp, + is_bond, in_port); ++#endif + ovs_rwlock_unlock(&ml->rwlock); + } + } +diff --git a/openvswitch-2.14.2/lib/mac-learning.h b/openvswitch-2.14.2/lib/mac-learning.h +index ad2f1fe..dd53a0e 100644 +--- a/openvswitch-2.14.2/lib/mac-learning.h ++++ b/openvswitch-2.14.2/lib/mac-learning.h +@@ -118,6 +118,30 @@ struct mac_entry { + struct ovs_list port_lru_node; /* In mac_learning_port's "port_lru"s. */ + }; + ++#ifdef HAVE_HWOFF_AGENT ++#define HWOFF_MIGRATE_MAC_MAX_NUM 8192 ++ ++struct hwoff_migrate_rarp_mac_entry { ++ bool is_need_del; ++ struct eth_addr mac_addr; ++ struct hmap_node mac_entry_node; ++}; ++ ++struct hwoff_migrate_rarp_mac_infos { ++ struct ovs_rwlock rw; ++ struct hmap mac_info_list; ++ uint64_t length; ++}; ++ ++void hwoff_rarp_mac_list_init(void); ++bool hwoff_rarp_status_get(void); ++void hwoff_rarp_mac_list_uninit(void); ++struct hwoff_migrate_rarp_mac_infos *hwoff_migrate_rarp_mac_infos_get(void); ++void hwoff_rarp_mac_remove_from_list(struct hwoff_migrate_rarp_mac_entry *e); ++struct hwoff_migrate_rarp_mac_entry *hwoff_get_entry_by_mac(struct eth_addr mac); ++struct hwoff_migrate_rarp_mac_entry * hwoff_rarp_mac_insert_to_list(struct eth_addr mac); ++ ++#endif + static inline void *mac_entry_get_port(const struct mac_learning *ml, + const struct mac_entry *); + void mac_entry_set_port(struct mac_learning *, struct mac_entry *, void *port); +@@ -214,10 +238,19 @@ struct mac_entry *mac_learning_insert(struct mac_learning *ml, + const struct eth_addr src, + uint16_t vlan) + OVS_REQ_WRLOCK(ml->rwlock); +-bool mac_learning_update(struct mac_learning *ml, struct eth_addr src, +- int vlan, bool is_gratuitous_arp, bool is_bond, +- void *in_port) ++#ifdef HAVE_HWOFF_AGENT ++bool ++mac_learning_update(struct mac_learning *ml, struct eth_addr src, ++ int vlan, bool is_gratuitous_arp, bool is_bond, ++ void *in_port, void **out_port) ++ OVS_EXCLUDED(ml->rwlock); ++#else ++bool ++mac_learning_update(struct mac_learning *ml, struct eth_addr src, ++ int vlan, bool is_gratuitous_arp, bool is_bond, ++ void *in_port) + OVS_EXCLUDED(ml->rwlock); ++#endif + + /* Lookup. */ + struct mac_entry *mac_learning_lookup(const struct mac_learning *ml, +diff --git a/openvswitch-2.14.2/lib/netdev-dpdk.c b/openvswitch-2.14.2/lib/netdev-dpdk.c +index f9284d0..858957c 100644 +--- a/openvswitch-2.14.2/lib/netdev-dpdk.c ++++ b/openvswitch-2.14.2/lib/netdev-dpdk.c +@@ -26,6 +26,10 @@ + #include + #include + ++#ifdef HAVE_HWOFF_AGENT ++#include "hwoff_init_func.h" ++#endif ++ + /* Include rte_compat.h first to allow experimental API's needed for the + * rte_meter.h rfc4115 functions. Once they are no longer marked as + * experimental the #define and rte_compat.h include can be removed. +@@ -74,6 +78,9 @@ + #include "userspace-tso.h" + #include "util.h" + #include "uuid.h" ++#ifdef HAVE_HWOFF_AGENT ++#include "hwoff_init_func.h" ++#endif + + enum {VIRTIO_RXQ, VIRTIO_TXQ, VIRTIO_QNUM}; + +@@ -109,7 +116,7 @@ COVERAGE_DEFINE(vhost_notification); + * enough hugepages) we keep halving the number until the allocation succeeds + * or we reach MIN_NB_MBUF */ + +-#define MAX_NB_MBUF (4096 * 64) ++#define MAX_NB_MBUF (512 * 320 * 2) // queue_desc * queue_num * rx/tx + #define MIN_NB_MBUF (4096 * 4) + #define MP_CACHE_SZ RTE_MEMPOOL_CACHE_MAX_SIZE + +@@ -187,6 +194,7 @@ static int vring_state_changed(int vid, uint16_t queue_id, int enable); + static void destroy_connection(int vid); + static void vhost_guest_notified(int vid); + ++#ifdef DPDK_2011_AND_BEFORE + static const struct vhost_device_ops virtio_net_device_ops = + { + .new_device = new_device, +@@ -197,6 +205,19 @@ static const struct vhost_device_ops virtio_net_device_ops = + .destroy_connection = destroy_connection, + .guest_notified = vhost_guest_notified, + }; ++#else ++static const struct rte_vhost_device_ops virtio_net_device_ops = ++{ ++ .new_device = new_device, ++ .destroy_device = destroy_device, ++ .vring_state_changed = vring_state_changed, ++ .features_changed = NULL, ++ .new_connection = NULL, ++ .destroy_connection = destroy_connection, ++ .guest_notified = vhost_guest_notified, ++}; ++#endif ++ + + /* Custom software stats for dpdk ports */ + struct netdev_dpdk_sw_stats { +@@ -432,6 +453,10 @@ struct netdev_dpdk { + /* If true, rte_eth_dev_start() was successfully called */ + bool started; + bool reset_needed; ++#ifdef HAVE_HWOFF_AGENT ++ bool hwoff_reconfigure; ++ bool hwoff_used_share_upcall; ++#endif + /* 1 pad byte here. */ + struct eth_addr hwaddr; + int mtu; +@@ -675,6 +700,7 @@ dpdk_calculate_mbufs(struct netdev_dpdk *dev, int mtu, bool per_port_mp) + return n_mbufs; + } + ++#define HWOFF_MBUF_SIZE 2176 + static struct dpdk_mp * + dpdk_mp_create(struct netdev_dpdk *dev, int mtu, bool per_port_mp) + { +@@ -699,8 +725,11 @@ dpdk_mp_create(struct netdev_dpdk *dev, int mtu, bool per_port_mp) + dmp->refcount = 1; + + /* Get the size of each mbuf, based on the MTU */ ++#ifdef HAVE_HWOFF_AGENT ++ mbuf_size = HWOFF_MBUF_SIZE; ++#else + mbuf_size = MTU_TO_FRAME_LEN(mtu); +- ++#endif + n_mbufs = dpdk_calculate_mbufs(dev, mtu, per_port_mp); + + do { +@@ -1146,8 +1175,13 @@ dpdk_eth_dev_init(struct netdev_dpdk *dev) + } + } + +- n_rxq = MIN(info.max_rx_queues, dev->up.n_rxq); + n_txq = MIN(info.max_tx_queues, dev->up.n_txq); ++ if(info.max_rx_queues < (dev->up.n_rxq)) { ++ n_rxq = info.max_rx_queues; ++ VLOG_INFO("option:n_rxq is out of range, it has changed to default maximum value:%d", info.max_rx_queues); ++ } else { ++ n_rxq = dev->up.n_rxq; ++ } + + diag = dpdk_eth_dev_port_config(dev, n_rxq, n_txq); + if (diag) { +@@ -1247,6 +1281,9 @@ common_construct(struct netdev *netdev, dpdk_port_t port_no, + dev->attached = false; + dev->started = false; + dev->reset_needed = false; ++#ifdef HAVE_HWOFF_AGENT ++ dev->hwoff_reconfigure = false; ++#endif + + ovsrcu_init(&dev->qos_conf, NULL); + +@@ -1285,31 +1322,11 @@ common_construct(struct netdev *netdev, dpdk_port_t port_no, + return 0; + } + +-/* Get the number of OVS interfaces which have the same DPDK +- * rte device (e.g. same pci bus address). +- * FIXME: avoid direct access to DPDK internal array rte_eth_devices. +- */ +-static int +-netdev_dpdk_get_num_ports(struct rte_device *device) +- OVS_REQUIRES(dpdk_mutex) +-{ +- struct netdev_dpdk *dev; +- int count = 0; +- +- LIST_FOR_EACH (dev, list_node, &dpdk_list) { +- if (rte_eth_devices[dev->port_id].device == device +- && rte_eth_devices[dev->port_id].state != RTE_ETH_DEV_UNUSED) { +- count++; +- } +- } +- return count; +-} +- + static int + vhost_common_construct(struct netdev *netdev) + OVS_REQUIRES(dpdk_mutex) + { +- int socket_id = rte_lcore_to_socket_id(rte_get_master_lcore()); ++ int socket_id = rte_lcore_to_socket_id(rte_get_main_lcore()); + struct netdev_dpdk *dev = netdev_dpdk_cast(netdev); + + dev->vhost_rxq_enabled = dpdk_rte_mzalloc(OVS_VHOST_MAX_QUEUE_NUM * +@@ -1458,9 +1475,6 @@ static void + netdev_dpdk_destruct(struct netdev *netdev) + { + struct netdev_dpdk *dev = netdev_dpdk_cast(netdev); +- struct rte_device *rte_dev; +- struct rte_eth_dev *eth_dev; +- bool remove_on_close; + + ovs_mutex_lock(&dpdk_mutex); + +@@ -1468,25 +1482,43 @@ netdev_dpdk_destruct(struct netdev *netdev) + dev->started = false; + + if (dev->attached) { +- /* Retrieve eth device data before closing it. +- * FIXME: avoid direct access to DPDK internal array rte_eth_devices. +- */ +- eth_dev = &rte_eth_devices[dev->port_id]; +- remove_on_close = +- eth_dev->data && +- (eth_dev->data->dev_flags & RTE_ETH_DEV_CLOSE_REMOVE); +- rte_dev = eth_dev->device; ++ bool dpdk_resources_still_used = false; ++ struct rte_eth_dev_info dev_info; ++ dpdk_port_t sibling_port_id; ++ ++ /* Check if this netdev has siblings (i.e. shares DPDK resources) among ++ * other OVS netdevs. */ ++ RTE_ETH_FOREACH_DEV_SIBLING (sibling_port_id, dev->port_id) { ++ struct netdev_dpdk *sibling; ++ ++ /* RTE_ETH_FOREACH_DEV_SIBLING lists dev->port_id as part of the ++ * loop. */ ++ if (sibling_port_id == dev->port_id) { ++ continue; ++ } ++ LIST_FOR_EACH (sibling, list_node, &dpdk_list) { ++ if (sibling->port_id != sibling_port_id) { ++ continue; ++ } ++ dpdk_resources_still_used = true; ++ break; ++ } ++ if (dpdk_resources_still_used) { ++ break; ++ } ++ } ++ ++ /* Retrieve eth device data before closing it. */ ++ rte_eth_dev_info_get(dev->port_id, &dev_info); + + /* Remove the eth device. */ + rte_eth_dev_close(dev->port_id); + +- /* Remove this rte device and all its eth devices if flag +- * RTE_ETH_DEV_CLOSE_REMOVE is not supported (which means representors +- * are not supported), or if all the eth devices belonging to the rte +- * device are closed. +- */ +- if (!remove_on_close || !netdev_dpdk_get_num_ports(rte_dev)) { +- int ret = rte_dev_remove(rte_dev); ++ /* Remove the rte device if no associated eth device is used by OVS. ++ * Note: any remaining eth devices associated to this rte device are ++ * closed by DPDK ethdev layer. */ ++ if (!dpdk_resources_still_used) { ++ int ret = rte_dev_remove(dev_info.device); + + if (ret < 0) { + VLOG_ERR("Device '%s' can not be detached: %s.", +@@ -1787,6 +1819,103 @@ static dpdk_port_t netdev_dpdk_get_port_by_devargs(const char *devargs) + return port_id; + } + ++#ifdef HAVE_HWOFF_AGENT ++#define HWOFF_SPLIT_STR_LENGTH 30 ++int ++hwoff_netdev_name_get(uint16_t port_id, char name_buffer[], int buffer_size) ++{ ++ struct netdev_dpdk *dev = NULL; ++ dev = netdev_dpdk_lookup_by_port_id(port_id); ++ if (dev == NULL) { ++ return -1; ++ } ++ ovs_strlcpy(name_buffer, dev->up.name, buffer_size); ++ return 0; ++} ++ ++bool ++hwoff_netdev_is_shared(struct netdev *dev) ++{ ++ if (!is_dpdk_class(dev->netdev_class)) { ++ return false; ++ } ++ ++ struct netdev_dpdk *dpdk_dev = NULL; ++ dpdk_dev = netdev_dpdk_cast(dev); ++ return dpdk_dev == NULL ? false : dpdk_dev->hwoff_used_share_upcall; ++} ++ ++int ++open_share_upcall(const char *key, const char *value, void *extra_args) ++{ ++ uint8_t *share_upcall = (uint8_t *)extra_args; ++ if (value == NULL || share_upcall == NULL) { ++ return -1; ++ } ++ ++ if (strcmp("true", value) == 0) { ++ *share_upcall = true; ++ } else if (strcmp("false", value) == 0) { ++ *share_upcall = false; ++ } else { ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int ++hwoff_get_share_upcall_str(const char *src, char *dst) ++{ ++ char *sub_str = strstr(src ,"share-upcall-queues"); ++ if (sub_str == NULL) { ++ return -1; ++ } ++ ++ for (int i = 0; i < HWOFF_SPLIT_STR_LENGTH; ++i) { ++ if (sub_str[i] == '\0') { ++ dst[i] = sub_str[i]; ++ return 0; ++ } ++ ++ if (sub_str[i] == ',') { ++ return 0; ++ } ++ dst[i] = sub_str[i]; ++ } ++ ++ return 0; ++} ++ ++static bool hwoff_port_share_upcall(const char *args) ++{ ++ const char *valid_key_list[] = {"share-upcall-queues", NULL}; ++ struct rte_kvargs *kvargs = NULL; ++ int ret = 0; ++ bool share_upcall = false; ++ char share_upcall_str[HWOFF_SPLIT_STR_LENGTH] = {0}; ++ ++ ret = hwoff_get_share_upcall_str(args, share_upcall_str); ++ if (ret < 0) { ++ return false; ++ } ++ ++ kvargs = rte_kvargs_parse(share_upcall_str, valid_key_list); ++ if (kvargs == NULL) { ++ return false; ++ } ++ ++ ret = rte_kvargs_process(kvargs, "share-upcall-queues", open_share_upcall, &share_upcall); ++ if (ret != 0) { ++ rte_kvargs_free(kvargs); ++ return false; ++ } ++ ++ rte_kvargs_free(kvargs); ++ return share_upcall; ++} ++#endif ++ + /* + * Normally, a PCI id (optionally followed by a representor number) + * is enough for identifying a specific DPDK port. +@@ -1826,6 +1955,13 @@ netdev_dpdk_process_devargs(struct netdev_dpdk *dev, + } + } + } ++#ifdef HAVE_HWOFF_AGENT ++ /* Add share upcall queue flag on dpdk_device according to input args */ ++ if (new_port_id != DPDK_ETH_PORT_ID_INVALID && ++ hwoff_port_share_upcall(devargs)) { ++ dev->hwoff_used_share_upcall = true; ++ } ++#endif + + if (new_port_id == DPDK_ETH_PORT_ID_INVALID) { + VLOG_WARN_BUF(errp, "Error attaching device '%s' to DPDK", devargs); +@@ -1868,7 +2004,12 @@ dpdk_set_rxq_config(struct netdev_dpdk *dev, const struct smap *args) + { + int new_n_rxq; + +- new_n_rxq = MAX(smap_get_int(args, "n_rxq", NR_QUEUE), 1); ++ if(smap_get_int(args, "n_rxq", NR_QUEUE) < 1) { ++ new_n_rxq = 1; ++ VLOG_INFO("option:n_rxq is out of range, it has changed to default minimum value:%d", new_n_rxq); ++ } else { ++ new_n_rxq = smap_get_int(args, "n_rxq", NR_QUEUE); ++ } + if (new_n_rxq != dev->requested_n_rxq) { + dev->requested_n_rxq = new_n_rxq; + netdev_request_reconfigure(&dev->up); +@@ -1974,7 +2115,14 @@ netdev_dpdk_set_config(struct netdev *netdev, const struct smap *args, + if (err) { + goto out; + } +- ++#ifdef HAVE_HWOFF_AGENT ++ hwoff_func* funcs = hwoff_get_funcs(); ++ err = funcs->hwoff_parse_vf_extra_options(dev->port_id, args); ++ if (err == 0) { ++ dev->hwoff_reconfigure = true; ++ netdev_request_reconfigure(netdev); ++ } ++#endif + lsc_interrupt_mode = smap_get_bool(args, "dpdk-lsc-interrupt", false); + if (dev->requested_lsc_interrupt_mode != lsc_interrupt_mode) { + dev->requested_lsc_interrupt_mode = lsc_interrupt_mode; +@@ -2039,12 +2187,6 @@ netdev_dpdk_vhost_client_set_config(struct netdev *netdev, + if (!nullable_string_is_equal(path, dev->vhost_id)) { + free(dev->vhost_id); + dev->vhost_id = nullable_xstrdup(path); +- /* check zero copy configuration */ +- if (smap_get_bool(args, "dq-zero-copy", false)) { +- dev->vhost_driver_flags |= RTE_VHOST_USER_DEQUEUE_ZERO_COPY; +- } else { +- dev->vhost_driver_flags &= ~RTE_VHOST_USER_DEQUEUE_ZERO_COPY; +- } + netdev_request_reconfigure(netdev); + } + } +@@ -2145,14 +2287,21 @@ netdev_dpdk_prep_hwol_packet(struct netdev_dpdk *dev, struct rte_mbuf *mbuf) + { + struct dp_packet *pkt = CONTAINER_OF(mbuf, struct dp_packet, mbuf); + ++#ifdef DPDK_2011_AND_BEFORE + if (mbuf->ol_flags & PKT_TX_L4_MASK) { ++#else ++ if (mbuf->ol_flags & RTE_MBUF_F_TX_L4_MASK) { ++#endif + mbuf->l2_len = (char *)dp_packet_l3(pkt) - (char *)dp_packet_eth(pkt); + mbuf->l3_len = (char *)dp_packet_l4(pkt) - (char *)dp_packet_l3(pkt); + mbuf->outer_l2_len = 0; + mbuf->outer_l3_len = 0; + } +- ++#ifdef DPDK_2011_AND_BEFORE + if (mbuf->ol_flags & PKT_TX_TCP_SEG) { ++#else ++ if (mbuf->ol_flags & RTE_MBUF_F_TX_TCP_SEG) { ++#endif + struct tcp_header *th = dp_packet_l4(pkt); + + if (!th) { +@@ -2162,12 +2311,19 @@ netdev_dpdk_prep_hwol_packet(struct netdev_dpdk *dev, struct rte_mbuf *mbuf) + } + + mbuf->l4_len = TCP_OFFSET(th->tcp_ctl) * 4; ++#ifdef DPDK_2011_AND_BEFORE + mbuf->ol_flags |= PKT_TX_TCP_CKSUM; + mbuf->tso_segsz = dev->mtu - mbuf->l3_len - mbuf->l4_len; +- + if (mbuf->ol_flags & PKT_TX_IPV4) { + mbuf->ol_flags |= PKT_TX_IP_CKSUM; + } ++#else ++ mbuf->ol_flags |= RTE_MBUF_F_TX_TCP_CKSUM; ++ mbuf->tso_segsz = dev->mtu - mbuf->l3_len - mbuf->l4_len; ++ if (mbuf->ol_flags & RTE_MBUF_F_TX_IPV4) { ++ mbuf->ol_flags |= RTE_MBUF_F_TX_IP_CKSUM; ++ } ++#endif + } + return true; + } +@@ -2513,7 +2669,11 @@ netdev_dpdk_filter_packet_len(struct netdev_dpdk *dev, struct rte_mbuf **pkts, + for (i = 0; i < pkt_cnt; i++) { + pkt = pkts[i]; + if (OVS_UNLIKELY((pkt->pkt_len > dev->max_packet_len) ++#ifdef DPDK_2011_AND_BEFORE + && !(pkt->ol_flags & PKT_TX_TCP_SEG))) { ++#else ++ && !(pkt->ol_flags & RTE_MBUF_F_TX_TCP_SEG))) { ++#endif + VLOG_WARN_RL(&rl, "%s: Too big size %" PRIu32 " " + "max_packet_len %d", dev->up.name, pkt->pkt_len, + dev->max_packet_len); +@@ -2734,13 +2894,19 @@ dpdk_copy_dp_packet_to_mbuf(struct rte_mempool *mp, struct dp_packet *pkt_orig) + + mbuf_dest->tx_offload = pkt_orig->mbuf.tx_offload; + mbuf_dest->packet_type = pkt_orig->mbuf.packet_type; ++#ifdef DPDK_2011_AND_BEFORE + mbuf_dest->ol_flags |= (pkt_orig->mbuf.ol_flags & + ~(EXT_ATTACHED_MBUF | IND_ATTACHED_MBUF)); +- + memcpy(&pkt_dest->l2_pad_size, &pkt_orig->l2_pad_size, + sizeof(struct dp_packet) - offsetof(struct dp_packet, l2_pad_size)); +- + if (mbuf_dest->ol_flags & PKT_TX_L4_MASK) { ++#else ++ mbuf_dest->ol_flags |= (pkt_orig->mbuf.ol_flags & ++ ~(RTE_MBUF_F_EXTERNAL | RTE_MBUF_F_INDIRECT)); ++ memcpy(&pkt_dest->l2_pad_size, &pkt_orig->l2_pad_size, ++ sizeof(struct dp_packet) - offsetof(struct dp_packet, l2_pad_size)); ++ if (mbuf_dest->ol_flags & RTE_MBUF_F_TX_L4_MASK) { ++#endif + mbuf_dest->l2_len = (char *)dp_packet_l3(pkt_dest) + - (char *)dp_packet_eth(pkt_dest); + mbuf_dest->l3_len = (char *)dp_packet_l4(pkt_dest) +@@ -2785,7 +2951,11 @@ dpdk_do_tx_copy(struct netdev *netdev, int qid, struct dp_packet_batch *batch) + uint32_t size = dp_packet_size(packet); + + if (size > dev->max_packet_len ++#ifdef DPDK_2011_AND_BEFORE + && !(packet->mbuf.ol_flags & PKT_TX_TCP_SEG)) { ++#else ++ && !(packet->mbuf.ol_flags & RTE_MBUF_F_TX_TCP_SEG)) { ++#endif + VLOG_WARN_RL(&rl, "Too big size %u max_packet_len %d", size, + dev->max_packet_len); + mtu_drops++; +@@ -3353,8 +3523,29 @@ netdev_dpdk_set_policing(struct netdev* netdev, uint32_t policer_rate, + : !policer_burst ? 8000 + : policer_burst); + ++#if HAVE_HWOFF_AGENT ++ bool eth_flag = false; ++ hwoff_func* funcs = hwoff_get_funcs(); ++ /* This function obtains dev->mutex, which conflicts with the following open source lock obtaining. ++ * Therefore, the function needs to be split into two parts. ++ */ ++ if (funcs->hwoff_is_ethdev(netdev)) { ++ eth_flag = true; ++ } ++#endif ++ + ovs_mutex_lock(&dev->mutex); + ++#if HAVE_HWOFF_AGENT ++ if (eth_flag) { ++ if (funcs->hwoff_set_ingress_policing) { ++ funcs->hwoff_set_ingress_policing(dev->port_id, policer_rate, policer_burst); ++ } ++ ovs_mutex_unlock(&dev->mutex); ++ return 0; ++ } ++#endif ++ + policer = ovsrcu_get_protected(struct ingress_policer *, + &dev->ingress_policer); + +@@ -3629,8 +3820,13 @@ netdev_dpdk_get_status(const struct netdev *netdev, struct smap *args) + ovs_mutex_unlock(&dev->mutex); + const struct rte_bus *bus; + const struct rte_pci_device *pci_dev; ++#ifdef DPDK_2011_AND_BEFORE + uint16_t vendor_id = PCI_ANY_ID; + uint16_t device_id = PCI_ANY_ID; ++#else ++ uint16_t vendor_id = RTE_PCI_ANY_ID; ++ uint16_t device_id = RTE_PCI_ANY_ID; ++#endif + bus = rte_bus_find_by_device(dev_info.device); + if (bus && !strcmp(bus->name, "pci")) { + pci_dev = RTE_DEV_TO_PCI(dev_info.device); +@@ -3738,12 +3934,12 @@ static void + netdev_dpdk_detach(struct unixctl_conn *conn, int argc OVS_UNUSED, + const char *argv[], void *aux OVS_UNUSED) + { +- char *response; +- dpdk_port_t port_id; +- struct netdev_dpdk *dev; +- struct rte_device *rte_dev; + struct ds used_interfaces = DS_EMPTY_INITIALIZER; ++ struct rte_eth_dev_info dev_info; ++ dpdk_port_t sibling_port_id; ++ dpdk_port_t port_id; + bool used = false; ++ char *response; + + ovs_mutex_lock(&dpdk_mutex); + +@@ -3753,18 +3949,21 @@ netdev_dpdk_detach(struct unixctl_conn *conn, int argc OVS_UNUSED, + goto error; + } + +- rte_dev = rte_eth_devices[port_id].device; + ds_put_format(&used_interfaces, + "Device '%s' is being used by the following interfaces:", + argv[1]); + +- LIST_FOR_EACH (dev, list_node, &dpdk_list) { +- /* FIXME: avoid direct access to DPDK array rte_eth_devices. */ +- if (rte_eth_devices[dev->port_id].device == rte_dev +- && rte_eth_devices[dev->port_id].state != RTE_ETH_DEV_UNUSED) { ++ RTE_ETH_FOREACH_DEV_SIBLING (sibling_port_id, port_id) { ++ struct netdev_dpdk *dev; ++ ++ LIST_FOR_EACH (dev, list_node, &dpdk_list) { ++ if (dev->port_id != sibling_port_id) { ++ continue; ++ } + used = true; + ds_put_format(&used_interfaces, " %s", + netdev_get_name(&dev->up)); ++ break; + } + } + +@@ -3776,8 +3975,9 @@ netdev_dpdk_detach(struct unixctl_conn *conn, int argc OVS_UNUSED, + } + ds_destroy(&used_interfaces); + ++ rte_eth_dev_info_get(port_id, &dev_info); + rte_eth_dev_close(port_id); +- if (rte_dev_remove(rte_dev) < 0) { ++ if (rte_dev_remove(dev_info.device) < 0) { + response = xasprintf("Device '%s' can not be detached", argv[1]); + goto error; + } +@@ -4277,8 +4477,29 @@ netdev_dpdk_set_qos(struct netdev *netdev, const char *type, + struct qos_conf *qos_conf, *new_qos_conf = NULL; + int error = 0; + ++#if HAVE_HWOFF_AGENT ++ bool eth_flag = false; ++ hwoff_func* funcs = hwoff_get_funcs(); ++ /* This function obtains dev->mutex, which conflicts with the following open source lock obtaining. ++ * Therefore, the function needs to be split into two parts. ++ */ ++ if (funcs->hwoff_is_ethdev(netdev)) { ++ eth_flag = true; ++ } ++#endif ++ + ovs_mutex_lock(&dev->mutex); + ++#if HAVE_HWOFF_AGENT ++ if (eth_flag) { ++ if (funcs->hwoff_set_qos) { ++ funcs->hwoff_set_qos(dev->port_id, type, details); ++ } ++ ovs_mutex_unlock(&dev->mutex); ++ return error; ++ } ++#endif ++ + qos_conf = ovsrcu_get_protected(struct qos_conf *, &dev->qos_conf); + + new_ops = qos_lookup_name(type); +@@ -4910,7 +5131,12 @@ netdev_dpdk_reconfigure(struct netdev *netdev) + && dev->rxq_size == dev->requested_rxq_size + && dev->txq_size == dev->requested_txq_size + && dev->socket_id == dev->requested_socket_id ++#ifdef HAVE_HWOFF_AGENT ++ && dev->started && !dev->reset_needed ++ && !dev->hwoff_reconfigure) { ++#else + && dev->started && !dev->reset_needed) { ++#endif + /* Reconfiguration is unnecessary */ + + goto out; +@@ -5025,7 +5251,6 @@ netdev_dpdk_vhost_client_reconfigure(struct netdev *netdev) + int err; + uint64_t vhost_flags = 0; + uint64_t vhost_unsup_flags; +- bool zc_enabled; + + ovs_mutex_lock(&dev->mutex); + +@@ -5051,19 +5276,6 @@ netdev_dpdk_vhost_client_reconfigure(struct netdev *netdev) + vhost_flags |= RTE_VHOST_USER_POSTCOPY_SUPPORT; + } + +- zc_enabled = dev->vhost_driver_flags +- & RTE_VHOST_USER_DEQUEUE_ZERO_COPY; +- /* Enable zero copy flag, if requested */ +- if (zc_enabled) { +- vhost_flags |= RTE_VHOST_USER_DEQUEUE_ZERO_COPY; +- /* DPDK vHost library doesn't allow zero-copy with linear buffers. +- * Hence disable Linear buffer. +- */ +- vhost_flags &= ~RTE_VHOST_USER_LINEARBUF_SUPPORT; +- VLOG_WARN("Zero copy enabled, disabling linear buffer" +- " check for vHost port %s", dev->up.name); +- } +- + /* Enable External Buffers if TCP Segmentation Offload is enabled. */ + if (userspace_tso_enabled()) { + vhost_flags |= RTE_VHOST_USER_EXTBUF_SUPPORT; +@@ -5080,11 +5292,6 @@ netdev_dpdk_vhost_client_reconfigure(struct netdev *netdev) + VLOG_INFO("vHost User device '%s' created in 'client' mode, " + "using client socket '%s'", + dev->up.name, dev->vhost_id); +- if (zc_enabled) { +- VLOG_INFO("Zero copy enabled for vHost port %s", dev->up.name); +- VLOG_WARN("Zero copy support is deprecated and will be " +- "removed in the next OVS release."); +- } + } + + err = rte_vhost_driver_callback_register(dev->vhost_id, +@@ -5145,9 +5352,7 @@ netdev_dpdk_get_port_id(struct netdev *netdev) + } + + dev = netdev_dpdk_cast(netdev); +- ovs_mutex_lock(&dev->mutex); + ret = dev->port_id; +- ovs_mutex_unlock(&dev->mutex); + out: + return ret; + } +@@ -5162,6 +5367,14 @@ netdev_dpdk_flow_api_supported(struct netdev *netdev) + goto out; + } + ++#ifdef HAVE_HWOFF_AGENT ++ hwoff_func* funcs = hwoff_get_funcs(); ++ bool flag = funcs->hwoff_is_ethdev(netdev); ++ if (flag == true) { ++ return false; ++ } ++#endif ++ + dev = netdev_dpdk_cast(netdev); + ovs_mutex_lock(&dev->mutex); + if (dev->type == DPDK_DEV_ETH) { +@@ -5181,9 +5394,7 @@ netdev_dpdk_rte_flow_destroy(struct netdev *netdev, + struct netdev_dpdk *dev = netdev_dpdk_cast(netdev); + int ret; + +- ovs_mutex_lock(&dev->mutex); + ret = rte_flow_destroy(dev->port_id, rte_flow, error); +- ovs_mutex_unlock(&dev->mutex); + return ret; + } + +@@ -5197,9 +5408,7 @@ netdev_dpdk_rte_flow_create(struct netdev *netdev, + struct rte_flow *flow; + struct netdev_dpdk *dev = netdev_dpdk_cast(netdev); + +- ovs_mutex_lock(&dev->mutex); + flow = rte_flow_create(dev->port_id, attr, items, actions, error); +- ovs_mutex_unlock(&dev->mutex); + return flow; + } + +@@ -5209,7 +5418,7 @@ netdev_dpdk_rte_flow_query_count(struct netdev *netdev, + struct rte_flow_query_count *query, + struct rte_flow_error *error) + { +- struct rte_flow_action_count count = { .shared = 0, .id = 0 }; ++ struct rte_flow_action_count count = { .id = 0, }; + const struct rte_flow_action actions[] = { + { + .type = RTE_FLOW_ACTION_TYPE_COUNT, +@@ -5227,9 +5436,7 @@ netdev_dpdk_rte_flow_query_count(struct netdev *netdev, + } + + dev = netdev_dpdk_cast(netdev); +- ovs_mutex_lock(&dev->mutex); + ret = rte_flow_query(dev->port_id, rte_flow, actions, query, error); +- ovs_mutex_unlock(&dev->mutex); + return ret; + } + +diff --git a/openvswitch-2.14.2/lib/netdev-dpdk.h b/openvswitch-2.14.2/lib/netdev-dpdk.h +index 848346c..6853aeb 100644 +--- a/openvswitch-2.14.2/lib/netdev-dpdk.h ++++ b/openvswitch-2.14.2/lib/netdev-dpdk.h +@@ -20,6 +20,9 @@ + #include + + #include "openvswitch/compiler.h" ++#ifdef HAVE_HWOFF_AGENT ++#include ++#endif + + struct dp_packet; + struct netdev; +@@ -56,6 +59,14 @@ netdev_dpdk_rte_flow_query_count(struct netdev *netdev, + int + netdev_dpdk_get_port_id(struct netdev *netdev); + ++#ifdef HAVE_HWOFF_AGENT ++int ++hwoff_netdev_name_get(uint16_t port_id, char name_buffer[], int buffer_size); ++ ++bool ++hwoff_netdev_is_shared(struct netdev *dev); ++#endif ++ + #else + + static inline void +diff --git a/openvswitch-2.14.2/lib/netdev-native-tnl.c b/openvswitch-2.14.2/lib/netdev-native-tnl.c +index b89dfdd..0b3a745 100644 +--- a/openvswitch-2.14.2/lib/netdev-native-tnl.c ++++ b/openvswitch-2.14.2/lib/netdev-native-tnl.c +@@ -44,6 +44,9 @@ + #include "unaligned.h" + #include "unixctl.h" + #include "openvswitch/vlog.h" ++#ifdef HAVE_HWOFF_AGENT ++#include "hwoff_init_func.h" ++#endif + + VLOG_DEFINE_THIS_MODULE(native_tnl); + static struct vlog_rate_limit err_rl = VLOG_RATE_LIMIT_INIT(60, 5); +@@ -248,7 +251,16 @@ netdev_tnl_push_udp_header(const struct netdev *netdev OVS_UNUSED, + udp = netdev_tnl_push_ip_header(packet, data->header, data->header_len, &ip_tot_size); + + /* set udp src port */ ++#ifdef HAVE_HWOFF_AGENT ++ hwoff_func* funcs = hwoff_get_funcs(); ++ if (funcs->hwoff_tnl_get_src_port) { ++ udp->udp_src = funcs->hwoff_tnl_get_src_port(packet); ++ } else { ++ udp->udp_src = netdev_tnl_get_src_port(packet); ++ } ++#else + udp->udp_src = netdev_tnl_get_src_port(packet); ++#endif + udp->udp_len = htons(ip_tot_size); + + if (udp->udp_csum) { +diff --git a/openvswitch-2.14.2/lib/netdev-offload-dpdk.c b/openvswitch-2.14.2/lib/netdev-offload-dpdk.c +index 17b08ca..704ea18 100644 +--- a/openvswitch-2.14.2/lib/netdev-offload-dpdk.c ++++ b/openvswitch-2.14.2/lib/netdev-offload-dpdk.c +@@ -28,6 +28,11 @@ + #include "openvswitch/vlog.h" + #include "packets.h" + #include "uuid.h" ++#ifdef HAVE_HWOFF_AGENT ++#include "odp-util.h" ++#include "unixctl.h" ++#include "hwoff_init_func.h" ++#endif + + VLOG_DEFINE_THIS_MODULE(netdev_offload_dpdk); + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(100, 5); +@@ -58,6 +63,7 @@ struct ufid_to_rte_flow_data { + struct cmap_node node; + ovs_u128 ufid; + struct rte_flow *rte_flow; ++ int ref_cnt; + bool actions_offloaded; + struct dpif_flow_stats stats; + }; +@@ -1017,7 +1023,20 @@ add_port_id_action(struct flow_actions *actions, + struct rte_flow_action_port_id *port_id; + int outdev_id; + ++#ifdef HAVE_HWOFF_AGENT ++ hwoff_func* funcs = hwoff_get_funcs(); ++ if (funcs->hwoff_is_hiovs_netdev && funcs->hwoff_is_hiovs_netdev(outdev)) { ++ if (funcs->hwoff_is_ethdev(outdev)) { ++ outdev_id = funcs->hwoff_get_eth_vport_id(outdev); ++ } else { ++ outdev_id = outdev->netdev_class->get_ifindex(outdev); ++ } ++ } else { ++ outdev_id = netdev_dpdk_get_port_id(outdev); ++ } ++#else + outdev_id = netdev_dpdk_get_port_id(outdev); ++#endif + if (outdev_id < 0) { + return -1; + } +@@ -1030,14 +1049,19 @@ add_port_id_action(struct flow_actions *actions, + static int + add_output_action(struct netdev *netdev, + struct flow_actions *actions, +- const struct nlattr *nla) ++ const struct nlattr *nla, ++ void *pmd) + { + struct netdev *outdev; + odp_port_t port; + int ret = 0; + + port = nl_attr_get_odp_port(nla); +- outdev = netdev_ports_get(port, netdev->dpif_type); ++ if (pmd) { ++ outdev = dp_get_outdev_from_pmd(port, pmd); ++ } else { ++ outdev = netdev_ports_get(port, netdev->dpif_type); ++ } + if (outdev == NULL) { + VLOG_DBG_RL(&rl, "Cannot find netdev for odp port %"PRIu32, port); + return -1; +@@ -1048,7 +1072,10 @@ add_output_action(struct netdev *netdev, + netdev_get_name(netdev), netdev_get_name(outdev)); + ret = -1; + } +- netdev_close(outdev); ++ ++ if (pmd == NULL) { ++ netdev_close(outdev); ++ } + return ret; + } + +@@ -1076,10 +1103,12 @@ add_set_flow_action__(struct flow_actions *actions, + memcpy(spec, value, size); + add_flow_action(actions, attr, spec); + ++#ifndef HAVE_HWOFF_AGENT + /* Clear used mask for later checking. */ + if (mask) { + memset(mask, 0, size); + } ++#endif + return 0; + } + +@@ -1108,6 +1137,104 @@ BUILD_ASSERT_DECL(sizeof(struct rte_flow_action_set_tp) == + BUILD_ASSERT_DECL(sizeof(struct rte_flow_action_set_tp) == + MEMBER_SIZEOF(struct ovs_key_udp, udp_dst)); + ++#ifdef HAVE_HWOFF_AGENT ++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; ++ ++#define add_set_flow_action(field, type) \ ++ if (add_set_flow_action__(actions, &key->field, \ ++ mask ? CONST_CAST(void *, &mask->field) : NULL, \ ++ sizeof key->field, type)) { \ ++ return -1; \ ++ } ++ ++ 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 ? key + 1 : NULL; ++ ++ add_set_flow_action(eth_src, RTE_FLOW_ACTION_TYPE_SET_MAC_SRC); ++ add_set_flow_action(eth_dst, RTE_FLOW_ACTION_TYPE_SET_MAC_DST); ++ } 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 ? key + 1 : NULL; ++ ++ add_set_flow_action(ipv4_src, RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC); ++ add_set_flow_action(ipv4_dst, RTE_FLOW_ACTION_TYPE_SET_IPV4_DST); ++ add_set_flow_action(ipv4_ttl, RTE_FLOW_ACTION_TYPE_SET_TTL); ++ } else if (nl_attr_type(sa) == OVS_KEY_ATTR_IPV6) { ++ const struct ovs_key_ipv6 *key = nl_attr_get(sa); ++ const struct ovs_key_ipv6 *mask = masked ? key + 1 : NULL; ++ ++ add_set_flow_action(ipv6_src, RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC); ++ add_set_flow_action(ipv6_dst, RTE_FLOW_ACTION_TYPE_SET_IPV6_DST); ++ add_set_flow_action(ipv6_hlimit, RTE_FLOW_ACTION_TYPE_SET_TTL); ++ } 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 ? key + 1 : NULL; ++ ++ add_set_flow_action(tcp_src, RTE_FLOW_ACTION_TYPE_SET_TP_SRC); ++ add_set_flow_action(tcp_dst, RTE_FLOW_ACTION_TYPE_SET_TP_DST); ++ } 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 ? key + 1 : NULL; ++ ++ add_set_flow_action(udp_src, RTE_FLOW_ACTION_TYPE_SET_TP_SRC); ++ add_set_flow_action(udp_dst, RTE_FLOW_ACTION_TYPE_SET_TP_DST); ++ } else { ++ VLOG_DBG_RL(&rl, ++ "Unsupported set action type %d", nl_attr_type(sa)); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++static void add_vlan_to_vxlan_action(const struct nlattr *ca, struct flow_actions *actions) ++{ ++ struct rte_flow_action *real_actions = actions->actions; ++ struct rte_flow_action *one_act = NULL; ++ struct rte_flow_action *dst_act = NULL; ++ ++ one_act = real_actions; ++ while (one_act && (one_act->type != RTE_FLOW_ACTION_TYPE_END)) { ++ if (one_act->type != RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP) { ++ one_act = one_act + 1; ++ continue; ++ } ++ ++ dst_act = one_act; ++ break; ++ } ++ ++ if (dst_act == NULL) { ++ return; ++ } ++ ++ struct rte_flow_action_vxlan_encap *vxlan_info = (struct rte_flow_action_vxlan_encap *)dst_act->conf; ++ struct rte_flow_item *item = vxlan_info->definition; ++ ++ while (item->type != RTE_FLOW_ITEM_TYPE_END) { ++ item = item + 1; ++ } ++ ++ item->type = RTE_FLOW_ITEM_TYPE_VLAN; ++ const struct ovs_action_push_vlan *vlan_push = nl_attr_get(ca); ++ item->spec = &vlan_push->vlan_tci; ++ item->mask = NULL; ++ ++ item = item + 1; ++ item->type = RTE_FLOW_ITEM_TYPE_END; ++ return; ++} ++#else + static int + parse_set_actions(struct flow_actions *actions, + const struct nlattr *set_actions, +@@ -1191,11 +1318,12 @@ parse_set_actions(struct flow_actions *actions, + + return 0; + } ++#endif + + /* Maximum number of items in struct rte_flow_action_vxlan_encap. +- * ETH / IPv4(6) / UDP / VXLAN / END ++ * ETH / IPv4(6) / UDP / VXLAN / vlan /END + */ +-#define ACTION_VXLAN_ENCAP_ITEMS_NUM 5 ++#define ACTION_VXLAN_ENCAP_ITEMS_NUM 6 + + static int + add_vxlan_encap_action(struct flow_actions *actions, +@@ -1305,7 +1433,8 @@ static int + parse_clone_actions(struct netdev *netdev, + struct flow_actions *actions, + const struct nlattr *clone_actions, +- const size_t clone_actions_len) ++ const size_t clone_actions_len, ++ void *pmd) + { + const struct nlattr *ca; + unsigned int cleft; +@@ -1330,9 +1459,17 @@ parse_clone_actions(struct netdev *netdev, + add_flow_action(actions, RTE_FLOW_ACTION_TYPE_RAW_ENCAP, + raw_encap); + } else if (clone_type == OVS_ACTION_ATTR_OUTPUT) { +- if (add_output_action(netdev, actions, ca)) { ++ if (add_output_action(netdev, actions, ca, pmd)) { + return -1; + } ++#ifdef HAVE_HWOFF_AGENT ++ } else if (clone_type == OVS_ACTION_ATTR_PUSH_VLAN) { ++ add_vlan_to_vxlan_action(ca, actions); ++ } else if (clone_type == OVS_ACTION_ATTR_CT) { ++ add_flow_action(actions, RTE_FLOW_ACTION_TYPE_CT, NULL); ++ } else if (clone_type == OVS_ACTION_ATTR_RECIRC) { ++ add_flow_action(actions, RTE_FLOW_ACTION_TYPE_RECIRC, NULL); ++#endif + } else { + VLOG_DBG_RL(&rl, + "Unsupported nested action inside clone(), " +@@ -1347,19 +1484,29 @@ static int + parse_flow_actions(struct netdev *netdev, + struct flow_actions *actions, + struct nlattr *nl_actions, +- size_t nl_actions_len) ++ size_t nl_actions_len, ++ void *pmd) + { ++ bool have_hard_output = false; + struct nlattr *nla; + size_t left; + + add_count_action(actions); + NL_ATTR_FOR_EACH_UNSAFE (nla, left, nl_actions, nl_actions_len) { + if (nl_attr_type(nla) == OVS_ACTION_ATTR_OUTPUT) { +- if (add_output_action(netdev, actions, nla)) { +- return -1; ++ if (add_output_action(netdev, actions, nla, pmd)) { ++ /* to support vxlan and set action both modify ++ * set action will output tap port which don't supoort offload, ++ * then return -1. ++ * continue to use vxlan output port. ++ */ ++ continue; ++ } else { ++ have_hard_output = true; + } + } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_DROP) { + add_flow_action(actions, RTE_FLOW_ACTION_TYPE_DROP, NULL); ++ have_hard_output = true; + } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_SET || + nl_attr_type(nla) == OVS_ACTION_ATTR_SET_MASKED) { + const struct nlattr *set_actions = nl_attr_get(nla); +@@ -1378,14 +1525,41 @@ parse_flow_actions(struct netdev *netdev, + } + } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_POP_VLAN) { + add_flow_action(actions, RTE_FLOW_ACTION_TYPE_OF_POP_VLAN, NULL); ++#ifdef HAVE_HWOFF_AGENT ++ } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_TUNNEL_POP) { ++ odp_port_t port = nl_attr_get_odp_port(nla); ++ struct netdev *vport = netdev_ports_get(port, netdev->dpif_type); ++ if (!vport) { ++ continue; ++ } ++ if (!strcmp(netdev_get_type(vport), "vxlan")) { ++ /* if exists tunnel_pop action, it should be the first action */ ++ free_flow_actions(actions); ++ add_flow_action(actions, RTE_FLOW_ACTION_TYPE_VXLAN_DECAP, NULL); ++ } ++ netdev_close(vport); ++ have_hard_output = true; ++ } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_CT) { ++ add_flow_action(actions, RTE_FLOW_ACTION_TYPE_CT, NULL); ++ } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_RECIRC) { ++ add_flow_action(actions, RTE_FLOW_ACTION_TYPE_RECIRC, NULL); ++#endif ++#ifdef HAVE_HWOFF_AGENT ++ } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_CLONE) { ++/* if there is multi output, clone will not be the last atcion, so left would be longer than nla->nla_len, ++ we let it go here, offload will fail in agent because multi output. ++*/ ++#else + } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_CLONE && + left <= NLA_ALIGN(nla->nla_len)) { ++#endif + const struct nlattr *clone_actions = nl_attr_get(nla); + size_t clone_actions_len = nl_attr_get_size(nla); +- + if (parse_clone_actions(netdev, actions, clone_actions, +- clone_actions_len)) { ++ clone_actions_len, pmd)) { + return -1; ++ } else { ++ have_hard_output = true; + } + } else { + VLOG_DBG_RL(&rl, "Unsupported action type %d", nl_attr_type(nla)); +@@ -1398,6 +1572,9 @@ parse_flow_actions(struct netdev *netdev, + return -1; + } + ++#ifdef HAVE_HWOFF_AGENT ++ have_hard_output = have_hard_output; ++#endif + add_flow_action(actions, RTE_FLOW_ACTION_TYPE_END, NULL); + return 0; + } +@@ -1414,7 +1591,7 @@ netdev_offload_dpdk_actions(struct netdev *netdev, + struct rte_flow_error error; + int ret; + +- ret = parse_flow_actions(netdev, &actions, nl_actions, actions_len); ++ ret = parse_flow_actions(netdev, &actions, nl_actions, actions_len, NULL); + if (ret) { + goto out; + } +@@ -1609,3 +1786,493 @@ const struct netdev_flow_api netdev_offload_dpdk = { + .init_flow_api = netdev_offload_dpdk_init_flow_api, + .flow_get = netdev_offload_dpdk_flow_get, + }; ++ ++#ifdef HAVE_HWOFF_AGENT ++#define HIOVS_RTE_FLOW_BATCH_SIZE 16 ++static struct cmap hiovs_ufid_rte_flow_map = CMAP_INITIALIZER; ++static struct ovs_mutex hiovs_map_lock = OVS_MUTEX_INITIALIZER; ++ ++static void hiovs_rte_flow_map_lock(void) ++{ ++ ovs_mutex_lock(&hiovs_map_lock); ++} ++ ++static void hiovs_rte_flow_map_unlock(void) ++{ ++ ovs_mutex_unlock(&hiovs_map_lock); ++} ++ ++static void free_no_copy_flow_patterns(struct flow_patterns *patterns) ++{ ++ free(patterns->items); ++ patterns->items = NULL; ++ patterns->cnt = 0; ++} ++ ++static void hiovs_rte_flow_data_dealloc(struct ufid_to_rte_flow_data *flow_data) ++{ ++ hwoff_func* funcs = hwoff_get_funcs(); ++ ++ if (funcs->hwoff_rte_flow_dealloc == NULL) { ++ return; ++ } ++ funcs->hwoff_rte_flow_dealloc(flow_data->rte_flow); ++ free(flow_data); ++} ++ ++static struct ufid_to_rte_flow_data* hiovs_rte_flow_data_alloc(const ovs_u128 *ufid) ++{ ++ hwoff_func* funcs = hwoff_get_funcs(); ++ struct rte_flow *flow = NULL; ++ struct ufid_to_rte_flow_data *flow_data = NULL; ++ ++ flow_data = (struct ufid_to_rte_flow_data *)malloc(sizeof(*flow_data)); ++ if (flow_data == NULL) { ++ return NULL; ++ } ++ ++ (void)memset(flow_data, 0, sizeof(struct ufid_to_rte_flow_data)); ++ if (funcs->hwoff_rte_flow_alloc == NULL) { ++ free(flow_data); ++ return NULL; ++ } ++ ++ flow = funcs->hwoff_rte_flow_alloc((ovs_u128 *)ufid, flow_data); ++ if (flow == NULL) { ++ free(flow_data); ++ return NULL; ++ } ++ ++ flow_data->rte_flow = flow; ++ flow_data->ufid = *ufid; ++ flow_data->actions_offloaded = false; ++ flow_data->ref_cnt = 1; ++ return flow_data; ++} ++ ++static struct ufid_to_rte_flow_data* hiovs_rte_flow_data_add(const ovs_u128 *ufid) ++{ ++ size_t hash; ++ struct ufid_to_rte_flow_data *flow_data = NULL; ++ flow_data = hiovs_rte_flow_data_alloc(ufid); ++ if (flow_data == NULL) { ++ VLOG_ERR("hiovs_rte_flow_data_alloc fail, ufid="UUID_FMT, UUID_ARGS((struct uuid *)ufid)); ++ return NULL; ++ } ++ hash = hash_bytes(&flow_data->ufid, sizeof(ovs_u128), 0); ++ cmap_insert(&hiovs_ufid_rte_flow_map, &flow_data->node, hash); ++ return flow_data; ++} ++static struct ufid_to_rte_flow_data* hiovs_rte_flow_data_find(const ovs_u128 *ufid) ++{ ++ struct ufid_to_rte_flow_data *flow_data = NULL; ++ size_t hash = hash_bytes(ufid, sizeof *ufid, 0); ++ ++ CMAP_FOR_EACH_WITH_HASH (flow_data, node, hash, &hiovs_ufid_rte_flow_map) { ++ if (ovs_u128_equals(*ufid, flow_data->ufid)) { ++ return flow_data; ++ } ++ } ++ ++ return NULL; ++} ++ ++static struct ufid_to_rte_flow_data* hiovs_rte_flow_data_get(const ovs_u128 *ufid) ++{ ++ struct ufid_to_rte_flow_data *flow_data = NULL; ++ ++ hiovs_rte_flow_map_lock(); ++ flow_data = hiovs_rte_flow_data_find(ufid); ++ if (flow_data == NULL) { ++ hiovs_rte_flow_map_unlock(); ++ ++ return NULL; ++ } ++ ++ flow_data->ref_cnt++; ++ hiovs_rte_flow_map_unlock(); ++ return flow_data; ++} ++ ++static void hiovs_rte_flow_data_close(struct ufid_to_rte_flow_data *flow_data) ++{ ++ hiovs_rte_flow_map_lock(); ++ flow_data->ref_cnt--; ++ if (flow_data->ref_cnt <= 0) { ++ hiovs_rte_flow_data_dealloc(flow_data); ++ } ++ hiovs_rte_flow_map_unlock(); ++} ++ ++uint32_t hiovs_rte_flow_list_get(ovs_u128 ufid_list[], struct rte_flow *flow_list[], uint32_t ufid_cnt) ++{ ++ int i; ++ ovs_u128 *one_ufid = NULL; ++ struct ufid_to_rte_flow_data *flow_data_list[HIOVS_RTE_FLOW_BATCH_SIZE]; ++ struct ufid_to_rte_flow_data *flow_data = NULL; ++ ++ if (ufid_cnt > HIOVS_RTE_FLOW_BATCH_SIZE) { ++ return -1; ++ } ++ ++ hiovs_rte_flow_map_lock(); ++ for (i = 0; i < ufid_cnt; i++) { ++ one_ufid = &ufid_list[i]; ++ flow_data = hiovs_rte_flow_data_find(one_ufid); ++ if (!flow_data) { ++ break; ++ } ++ ++ flow_data_list[i] = flow_data; ++ flow_list[i] = flow_data->rte_flow; ++ } ++ ++ if (i != ufid_cnt) { ++ hiovs_rte_flow_map_unlock(); ++ return -1; ++ } ++ ++ for (i = 0; i < ufid_cnt; i++) { ++ flow_data_list[i]->ref_cnt++; ++ } ++ ++ hiovs_rte_flow_map_unlock(); ++ return 0; ++} ++static struct ufid_to_rte_flow_data* hiovs_rte_flow_data_process(const ovs_u128 *ufid, void *flow) ++{ ++ bool is_dead = false; ++ struct ufid_to_rte_flow_data *flow_data = NULL; ++ hiovs_rte_flow_map_lock(); ++ is_dead = dp_netdev_flow_dead_status_get(flow); ++ if (is_dead == true) { ++ hiovs_rte_flow_map_unlock(); ++ return NULL; ++ } ++ flow_data = hiovs_rte_flow_data_find(ufid); ++ if (flow_data != NULL) { ++ flow_data->ref_cnt++; ++ hiovs_rte_flow_map_unlock(); ++ return flow_data; ++ } ++ flow_data = hiovs_rte_flow_data_add(ufid); ++ if (flow_data == NULL) { ++ hiovs_rte_flow_map_unlock(); ++ return NULL; ++ } ++ flow_data->ref_cnt++; ++ hiovs_rte_flow_map_unlock(); ++ return flow_data; ++} ++ ++void hiovs_rte_flow_data_list_put(void *flow_data_list[], uint32_t count) ++{ ++ int i; ++ struct ufid_to_rte_flow_data *flow_data = NULL; ++ ++ hiovs_rte_flow_map_lock(); ++ for (i = 0; i < count; i++) { ++ flow_data = (struct ufid_to_rte_flow_data *)(flow_data_list[i]); ++ flow_data->ref_cnt--; ++ if (flow_data->ref_cnt <= 0) { ++ hiovs_rte_flow_data_dealloc(flow_data); ++ } ++ } ++ hiovs_rte_flow_map_unlock(); ++} ++ ++static void hiovs_offload_info_parse(struct flow_patterns *patterns, ++ struct offload_info *info, ++ const ovs_u128 *sw_ufid, ++ struct rte_flow *flow) ++{ ++ add_flow_pattern(patterns, RTE_FLOW_ITEM_TYPE_PMD_ID, &info->pmd_core_id, NULL); ++ add_flow_pattern(patterns, RTE_FLOW_ITEM_TYPE_PORT_ID, &info->in_port_id, NULL); ++ add_flow_pattern(patterns, RTE_FLOW_ITEM_TYPE_PORT_TYPE, &info->in_port_type, NULL); ++ add_flow_pattern(patterns, RTE_FLOW_ITEM_TYPE_PACKETS, info->pkts_info, NULL); ++ add_flow_pattern(patterns, RTE_FLOW_ITEM_TYPE_SW_UFID, sw_ufid, NULL); ++ add_flow_pattern(patterns, RTE_FLOW_ITEM_TYPE_FLOW, flow, NULL); ++ return; ++} ++ ++static int hiovs_offload_flow_get_exec(struct netdev *netdev, struct rte_flow *rte_flow, ++ struct rte_flow_query_count *query, struct rte_flow_error *error) ++{ ++ int ret; ++ bool flag = false; ++ hwoff_func* funcs = hwoff_get_funcs(); ++ ++ flag = funcs->hwoff_is_ethdev(netdev); ++ if (flag == true) { ++ ret = netdev_dpdk_rte_flow_query_count(netdev, rte_flow, query, error); ++ return ret; ++ } ++ ++ if (funcs->hwoff_rte_flow_query_count == NULL) { ++ return -1; ++ } ++ ret = funcs->hwoff_rte_flow_query_count(netdev, rte_flow, query, error); ++ return ret; ++} ++ ++static int hiovs_offload_flow_del_exec(struct netdev *netdev, struct rte_flow *rte_flow, struct rte_flow_error *error) ++{ ++ int ret; ++ bool flag = false; ++ hwoff_func* funcs = hwoff_get_funcs(); ++ ++ if (funcs->hwoff_rte_flow_destroy == NULL) { ++ return -1; ++ } ++ ++ if (netdev == NULL) { ++ ret = funcs->hwoff_rte_flow_destroy(netdev, rte_flow, error); ++ return ret; ++ } ++ ++ flag = funcs->hwoff_is_ethdev(netdev); ++ if (flag == true) { ++ ret = netdev_dpdk_rte_flow_destroy(netdev, rte_flow, error); ++ return ret; ++ } ++ ++ ret = funcs->hwoff_rte_flow_destroy(netdev, rte_flow, error); ++ return ret; ++} ++ ++static struct rte_flow* hiovs_offload_flow_add_exec(struct netdev *netdev, ++ const struct rte_flow_attr *attr, ++ const struct rte_flow_item *items, ++ const struct rte_flow_action *actions, ++ struct rte_flow_error *error) ++{ ++ bool flag = false; ++ struct rte_flow *flow = NULL; ++ hwoff_func* funcs = hwoff_get_funcs(); ++ ++ flag = funcs->hwoff_is_ethdev(netdev); ++ if (flag == true) { ++ flow = netdev_dpdk_rte_flow_create(netdev, attr, items, actions, error); ++ return flow; ++ } ++ ++ if (funcs->hwoff_rte_flow_create == NULL) { ++ return NULL; ++ } ++ flow = funcs->hwoff_rte_flow_create(netdev, attr, items, actions, error); ++ return flow; ++} ++ ++static int hiovs_offload_flow_add(struct netdev *netdev, ++ struct ufid_to_rte_flow_data *flow_data, ++ struct nlattr *nl_actions, ++ size_t actions_len, ++ struct offload_info *info) ++{ ++ int ret; ++ struct rte_flow *flow = NULL; ++ struct rte_flow_error error; ++ const struct rte_flow_attr flow_attr = { .ingress = 1, .transfer = 1 }; ++ struct flow_actions actions = { .actions = NULL, .cnt = 0 }; ++ struct flow_patterns patterns = { .items = NULL, .cnt = 0 }; ++ ++ hiovs_offload_info_parse(&patterns, info, &flow_data->ufid, flow_data->rte_flow); ++ ret = parse_flow_actions(netdev, &actions, nl_actions, actions_len, info->pmd); ++ if (ret != 0) { ++ goto out; ++ } ++ ++ memset(&error, 0, sizeof(error)); ++ flow = hiovs_offload_flow_add_exec(netdev, &flow_attr, patterns.items, actions.actions, &error); ++ if (flow == NULL) { ++ ret = -1; ++ goto out; ++ } ++ ++ flow_data->actions_offloaded = true; ++ ret = 0; ++out: ++ free_no_copy_flow_patterns(&patterns); ++ free_flow_actions(&actions); ++ return ret; ++} ++ ++int hiovs_offload_flow_api_del(struct netdev *netdev, const ovs_u128 *ufid, struct dpif_flow_stats *stats) ++{ ++ int ret; ++ hwoff_func* funcs = hwoff_get_funcs(); ++ struct rte_flow_error error; ++ struct ufid_to_rte_flow_data *flow_data; ++ size_t hash; ++ ++ hiovs_rte_flow_map_lock(); ++ flow_data = hiovs_rte_flow_data_find(ufid); ++ if (flow_data == NULL) { ++ hiovs_rte_flow_map_unlock(); ++ return 0; ++ } ++ hiovs_rte_flow_map_unlock(); ++ ++ funcs->hwoff_rte_flow_deleted_set(flow_data->rte_flow, true); ++ ret = hiovs_offload_flow_del_exec(netdev, flow_data->rte_flow, &error); ++ ++ hash = hash_bytes(&flow_data->ufid, sizeof(ovs_u128), 0); ++ hiovs_rte_flow_map_lock(); ++ cmap_remove(&hiovs_ufid_rte_flow_map, &flow_data->node, hash); ++ flow_data->ref_cnt--; ++ if (flow_data->ref_cnt <= 0) { ++ hiovs_rte_flow_data_dealloc(flow_data); ++ } ++ hiovs_rte_flow_map_unlock(); ++ ++ if (stats) { ++ memset(stats, 0, sizeof *stats); ++ } ++ return ret; ++} ++ ++static int hiovs_offload_flow_api_put(struct netdev *netdev, struct match *match OVS_UNUSED, ++ struct nlattr *actions, size_t actions_len, ++ const ovs_u128 *ufid, struct offload_info *info, ++ struct dpif_flow_stats *stats) ++{ ++ int ret; ++ bool is_delete = false; ++ hwoff_func* funcs = hwoff_get_funcs(); ++ struct ufid_to_rte_flow_data *flow_data = NULL; ++ ++ /* When modification is true, we just destroy rte_flow. */ ++ if (info->modification) { ++ ret = hiovs_offload_flow_api_del(netdev, ufid, stats); ++ return ret; ++ } ++ flow_data = hiovs_rte_flow_data_process(ufid, info->flow); ++ if (flow_data == NULL) { ++ return -1; ++ } ++ ++ is_delete = funcs->hwoff_rte_flow_deleted_get(flow_data->rte_flow); ++ if (is_delete) { ++ hiovs_rte_flow_data_close(flow_data); ++ return -1; ++ } ++ ++ ret = hiovs_offload_flow_add(netdev, flow_data, actions, actions_len, info); ++ if (ret != 0) { ++ hiovs_rte_flow_data_close(flow_data); ++ return ret; ++ } ++ ++ if (stats) { ++ *stats = flow_data->stats; ++ } ++ hiovs_rte_flow_data_close(flow_data); ++ return 0; ++} ++ ++static int hiovs_offload_flow_api_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, ++ struct ofpbuf *buf OVS_UNUSED) ++{ ++ int ret = 0; ++ struct rte_flow_query_count query = { .reset = 1 }; ++ struct ufid_to_rte_flow_data *flow_data = NULL; ++ struct rte_flow_error error; ++ ++ flow_data = hiovs_rte_flow_data_get(ufid); ++ if (flow_data == NULL) { ++ attrs->dp_extra_info = NULL; ++ return -1; ++ } ++ ++ attrs->offloaded = true; ++ if (flow_data->actions_offloaded == false) { ++ attrs->dp_layer = "ovs"; ++ memset(stats, 0, sizeof *stats); ++ goto out; ++ } ++ ++ attrs->dp_layer = "dpdk"; ++ ret = hiovs_offload_flow_get_exec(netdev, flow_data->rte_flow, &query, &error); ++ if (ret) { ++ VLOG_DBG_RL(&rl, "%s: Failed to query ufid "UUID_FMT" flow: %p", ++ netdev_get_name(netdev), UUID_ARGS((struct uuid *) ufid), flow_data->rte_flow); ++ goto out; ++ } ++ ++ flow_data->stats.n_packets += query.hits; ++ flow_data->stats.n_bytes += query.bytes; ++ if (query.hits_set && query.hits) { ++ flow_data->stats.used = time_msec(); ++ } ++ memcpy(stats, &flow_data->stats, sizeof *stats); ++out: ++ hiovs_rte_flow_data_close(flow_data); ++ attrs->dp_extra_info = NULL; ++ return ret; ++} ++ ++static int hiovs_offload_flow_api_init(struct netdev *netdev) ++{ ++ bool flag = false; ++ hwoff_func* funcs = hwoff_get_funcs(); ++ ++ if (strcmp(netdev->netdev_class->type, "vxlan") == 0) { ++ return 0; ++ } ++ ++ if (strcmp(netdev->netdev_class->type, "tap") == 0) { ++ return 0; ++ } ++ ++ flag = funcs->hwoff_is_ethdev(netdev); ++ if (flag == true) { ++ return 0; ++ } ++ ++ return -1; ++} ++ ++static void hiovs_offload_dump_rte_flows(struct unixctl_conn *conn, int argc OVS_UNUSED, ++ const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED) ++{ ++ int count = 0; ++ hwoff_func* funcs = hwoff_get_funcs(); ++ struct ds ds = DS_EMPTY_INITIALIZER; ++ struct cmap_cursor cursor; ++ struct ufid_to_rte_flow_data *flow_data = NULL; ++ ++ hiovs_rte_flow_map_lock(); ++ CMAP_CURSOR_FOR_EACH(flow_data, node, &cursor, &hiovs_ufid_rte_flow_map) { ++ odp_format_ufid(&flow_data->ufid, &ds); ++ ds_put_format(&ds, ", is_deleted=%d, ref_cnt=%d\n", ++ funcs->hwoff_rte_flow_deleted_get(flow_data->rte_flow), flow_data->ref_cnt); ++ count++; ++ } ++ hiovs_rte_flow_map_unlock(); ++ ds_put_format(&ds, "rte_flow_count=%d\n", count); ++ unixctl_command_reply(conn, ds_cstr(&ds)); ++ ds_destroy(&ds); ++ return; ++} ++ ++int hiovs_netdev_offload_init(void) ++{ ++ ovs_mutex_init(&hiovs_map_lock); ++ unixctl_command_register("hwoff/dump-rte-flows", "", 0, 0, hiovs_offload_dump_rte_flows, NULL); ++ return 0; ++} ++ ++const struct netdev_flow_api hiovs_netdev_offload_api = { ++ .type = "hiovs_netdev_offload_api", ++ .flow_put = hiovs_offload_flow_api_put, ++ .flow_del = hiovs_offload_flow_api_del, ++ .init_flow_api = hiovs_offload_flow_api_init, ++ .flow_get = hiovs_offload_flow_api_get, ++}; ++#endif ++ +diff --git a/openvswitch-2.14.2/lib/netdev-offload-provider.h b/openvswitch-2.14.2/lib/netdev-offload-provider.h +index 0bed7bf..83f393d 100644 +--- a/openvswitch-2.14.2/lib/netdev-offload-provider.h ++++ b/openvswitch-2.14.2/lib/netdev-offload-provider.h +@@ -100,6 +100,13 @@ extern const struct netdev_flow_api netdev_offload_tc; + extern const struct netdev_flow_api netdev_offload_dpdk; + #endif + ++#ifdef HAVE_HWOFF_AGENT ++extern const struct netdev_flow_api hiovs_netdev_offload_api; ++int hiovs_netdev_offload_init(void); ++uint32_t hiovs_rte_flow_list_get(ovs_u128 *ufid, struct rte_flow **flow_list, uint32_t ufid_cnt); ++void hiovs_rte_flow_data_list_put(void *flow_data_list[], uint32_t count); ++#endif ++ + #ifdef __cplusplus + } + #endif +diff --git a/openvswitch-2.14.2/lib/netdev-offload.c b/openvswitch-2.14.2/lib/netdev-offload.c +index 2da3bc7..cefb4b7 100644 +--- a/openvswitch-2.14.2/lib/netdev-offload.c ++++ b/openvswitch-2.14.2/lib/netdev-offload.c +@@ -26,10 +26,15 @@ + #include + #include + ++#ifdef HAVE_HWOFF_AGENT ++#include "dp-packet.h" ++#include "ovs-numa.h" ++#include "hwoff_init_func.h" ++#endif ++ + #include "cmap.h" + #include "coverage.h" + #include "dpif.h" +-#include "dp-packet.h" + #include "openvswitch/dynamic-string.h" + #include "fatal-signal.h" + #include "hash.h" +@@ -174,6 +179,12 @@ netdev_assign_flow_api(struct netdev *netdev) + struct netdev_registered_flow_api *rfa; + + CMAP_FOR_EACH (rfa, cmap_node, &netdev_flow_apis) { ++ if (strcmp(rfa->flow_api->type, "linux_tc") == 0) { ++ if (strcmp(netdev->netdev_class->type, "tap") == 0) { ++ continue; ++ } ++ } ++ + if (!rfa->flow_api->init_flow_api(netdev)) { + ovs_refcount_ref(&rfa->refcnt); + ovsrcu_set(&netdev->flow_api, rfa->flow_api); +@@ -531,6 +542,40 @@ netdev_ports_lookup(odp_port_t port_no, const char *dpif_type) + return NULL; + } + ++#ifdef HAVE_HWOFF_AGENT ++int ++netdev_ports_insert(struct netdev *netdev, const char *dpif_type, ++ struct dpif_port *dpif_port) ++{ ++ struct port_to_netdev_data *data; ++ int ifindex = netdev_get_ifindex(netdev); ++ ++ ovs_rwlock_wrlock(&netdev_hmap_rwlock); ++ if (netdev_ports_lookup(dpif_port->port_no, dpif_type)) { ++ ovs_rwlock_unlock(&netdev_hmap_rwlock); ++ return EEXIST; ++ } ++ ++ data = xzalloc(sizeof *data); ++ data->netdev = netdev_ref(netdev); ++ dpif_port_clone(&data->dpif_port, dpif_port); ++ data->ifindex = ifindex; ++ ++ netdev_set_dpif_type(netdev, dpif_type); ++ ++ hmap_insert(&port_to_netdev, &data->portno_node, ++ netdev_ports_hash(dpif_port->port_no, dpif_type)); ++ if (ifindex >= 0) { ++ hmap_insert(&ifindex_to_port, &data->ifindex_node, ifindex); ++ } ++ ovs_rwlock_unlock(&netdev_hmap_rwlock); ++ ++ netdev_init_flow_api(netdev); ++ ++ return 0; ++} ++ ++#else + int + netdev_ports_insert(struct netdev *netdev, const char *dpif_type, + struct dpif_port *dpif_port) +@@ -564,6 +609,7 @@ netdev_ports_insert(struct netdev *netdev, const char *dpif_type, + + return 0; + } ++#endif + + struct netdev * + netdev_ports_get(odp_port_t port_no, const char *dpif_type) +@@ -593,7 +639,13 @@ netdev_ports_remove(odp_port_t port_no, const char *dpif_type) + dpif_port_destroy(&data->dpif_port); + netdev_close(data->netdev); /* unref and possibly close */ + hmap_remove(&port_to_netdev, &data->portno_node); ++#ifdef HAVE_HWOFF_AGENT ++ if (data->ifindex >= 0) { ++ hmap_remove(&ifindex_to_port, &data->ifindex_node); ++ } ++#else + hmap_remove(&ifindex_to_port, &data->ifindex_node); ++#endif + free(data); + ret = 0; + } +@@ -666,3 +718,40 @@ netdev_set_flow_api_enabled(const struct smap *ovs_other_config) + } + } + } ++ ++#ifdef HAVE_HWOFF_AGENT ++static void ++hiovs_rte_pktmbuf_init(struct rte_mempool *mp OVS_UNUSED, ++ void *opaque_arg OVS_UNUSED, ++ void *_p, ++ unsigned i OVS_UNUSED) ++{ ++ struct rte_mbuf *pkt = _p; ++ ++ dp_packet_init_dpdk((struct dp_packet *) pkt); ++} ++ ++int ++netdev_offload_hw_init(const struct smap *ovs_other_config) ++{ ++ int ret; ++ static bool hwoff_agent_init = false; ++ ++ if (OVS_LIKELY(hwoff_agent_init)) { ++ return 0; ++ } ++ ++ if (smap_get_bool(ovs_other_config, "hw-offload", false)) { ++ ret = hwoff_funcs_init(); ++ if (ret != 0) { ++ return ret; ++ } ++ (void)hiovs_netdev_offload_init(); ++ netdev_register_flow_api_provider(&hiovs_netdev_offload_api); ++ hwoff_agent_init = true; ++ return ret; ++ } ++ ++ return 0; ++} ++#endif +diff --git a/openvswitch-2.14.2/lib/netdev-offload.h b/openvswitch-2.14.2/lib/netdev-offload.h +index 4c0ed2a..f91c6d0 100644 +--- a/openvswitch-2.14.2/lib/netdev-offload.h ++++ b/openvswitch-2.14.2/lib/netdev-offload.h +@@ -22,13 +22,18 @@ + #include "openvswitch/types.h" + #include "packets.h" + #include "flow.h" ++#ifdef HAVE_HWOFF_AGENT ++#include "dp-packet.h" ++#endif + + #ifdef __cplusplus + extern "C" { + #endif + ++#ifndef HAVE_HWOFF_AGENT + struct dp_packet_batch; + struct dp_packet; ++#endif + struct netdev_class; + struct netdev_rxq; + struct netdev_saved_flags; +@@ -73,7 +78,15 @@ struct offload_info { + * it will be in the pkt meta data. + */ + uint32_t flow_mark; +- ++#ifdef HAVE_HWOFF_AGENT ++ uint32_t in_port_id; ++ uint32_t in_port_type; ++ unsigned int pmd_core_id; ++ void *pmd; ++ void *flow; ++ struct dp_packet_batch *pkts_info; ++ bool modification; ++#endif + bool tc_modify_flow_deleted; /* Indicate the tc modify flow put success + * to delete the original flow. */ + }; +@@ -125,6 +138,11 @@ int netdev_ports_flow_get(const char *dpif_type, struct match *match, + struct dpif_flow_attrs *attrs, + struct ofpbuf *buf); + ++#ifdef HAVE_HWOFF_AGENT ++int netdev_offload_hw_init(const struct smap *ovs_other_config); ++int hiovs_offload_flow_api_del(struct netdev *netdev, const ovs_u128 *ufid, struct dpif_flow_stats *stats); ++#endif ++ + #ifdef __cplusplus + } + #endif +diff --git a/openvswitch-2.14.2/lib/netdev-vport.c b/openvswitch-2.14.2/lib/netdev-vport.c +index 7c99f79..48c8399 100644 +--- a/openvswitch-2.14.2/lib/netdev-vport.c ++++ b/openvswitch-2.14.2/lib/netdev-vport.c +@@ -50,6 +50,10 @@ + #ifdef __linux__ + #include "netdev-linux.h" + #endif ++#ifdef HAVE_HWOFF_AGENT ++#include ++#include "hwoff_init_func.h" ++#endif + + VLOG_DEFINE_THIS_MODULE(netdev_vport); + +@@ -458,6 +462,20 @@ vxlan_get_port_ext_gbp_str(uint16_t port, bool gbp, + return namebuf; + } + ++#ifdef HAVE_HWOFF_AGENT ++static bool ++hwoff_is_ipv6_addr(struct in6_addr *ip6) ++{ ++ if (ip6->__in6_u.__u6_addr32[0] == 0 && ++ ip6->__in6_u.__u6_addr32[1] == 0 && ++ ip6->__in6_u.__u6_addr32[2] == 0xffff0000 && ++ ip6->__in6_u.__u6_addr32[3] != 0) { ++ return false; ++ } ++ return true; ++} ++#endif ++ + static void + update_vxlan_global_cfg(struct netdev *netdev, + struct netdev_tunnel_config *old_cfg, +@@ -468,6 +486,17 @@ update_vxlan_global_cfg(struct netdev *netdev, + const char *type = netdev_get_type(netdev); + struct vport_class *vclass = vport_class_cast(netdev_get_class(netdev)); + ++#ifdef HAVE_HWOFF_AGENT ++ hwoff_func* funcs = hwoff_get_funcs(); ++ bool is_ipv6 = false; ++ if (strcmp(type, "vxlan") == 0 && new_cfg && ++ funcs->hwoff_global_add_vxlan_vtep && ++ (old_cfg == NULL || memcmp(&new_cfg->ipv6_src, &old_cfg->ipv6_src, sizeof(struct in6_addr)))) { ++ is_ipv6 = hwoff_is_ipv6_addr(&new_cfg->ipv6_src); ++ funcs->hwoff_global_add_vxlan_vtep(is_ipv6, &new_cfg->ipv6_src, sizeof(struct in6_addr), new_cfg->dst_port); ++ } ++#endif ++ + if (strcmp(type, "vxlan") || + (old_cfg != NULL && new_cfg != NULL && + old_cfg->dst_port == new_cfg->dst_port && +@@ -487,6 +516,12 @@ update_vxlan_global_cfg(struct netdev *netdev, + simap_put(&vclass->global_cfg_tracker, namebuf, count); + } else { + simap_find_and_delete(&vclass->global_cfg_tracker, namebuf); ++#ifdef HAVE_HWOFF_AGENT ++ if (funcs->hwoff_global_del_vxlan_vtep) { ++ is_ipv6 = hwoff_is_ipv6_addr(&old_cfg->ipv6_src); ++ funcs->hwoff_global_del_vxlan_vtep(is_ipv6, &old_cfg->ipv6_src, sizeof(struct in6_addr)); ++ } ++#endif + } + } + } +diff --git a/openvswitch-2.14.2/lib/odp-util.c b/openvswitch-2.14.2/lib/odp-util.c +index a8598d5..7ca937a 100644 +--- a/openvswitch-2.14.2/lib/odp-util.c ++++ b/openvswitch-2.14.2/lib/odp-util.c +@@ -4511,6 +4511,12 @@ odp_format_ufid(const ovs_u128 *ufid, struct ds *ds) + ds_put_format(ds, "ufid:"UUID_FMT, UUID_ARGS((struct uuid *)ufid)); + } + ++void ++odp_format_mega_ufid(const ovs_u128 *ufid, struct ds *ds) ++{ ++ ds_put_format(ds, "mega_ufid:"UUID_FMT, UUID_ARGS((struct uuid *)ufid)); ++} ++ + /* Appends to 'ds' a string representation of the 'key_len' bytes of + * OVS_KEY_ATTR_* attributes in 'key'. If non-null, additionally formats the + * 'mask_len' bytes of 'mask' which apply to 'key'. If 'portno_names' is +diff --git a/openvswitch-2.14.2/lib/odp-util.h b/openvswitch-2.14.2/lib/odp-util.h +index a1d0d0f..ca2e3e6 100644 +--- a/openvswitch-2.14.2/lib/odp-util.h ++++ b/openvswitch-2.14.2/lib/odp-util.h +@@ -166,8 +166,8 @@ enum odp_key_fitness odp_nsh_hdr_from_attr(const struct nlattr *, + struct nsh_hdr *, size_t); + + int odp_ufid_from_string(const char *s_, ovs_u128 *ufid); +-void odp_format_ufid(const ovs_u128 *ufid, struct ds *); +- ++void odp_format_ufid(const ovs_u128 *ufid, struct ds *); ++void odp_format_mega_ufid(const ovs_u128 *ufid, struct ds *); + void odp_flow_format(const struct nlattr *key, size_t key_len, + const struct nlattr *mask, size_t mask_len, + const struct hmap *portno_names, struct ds *, +diff --git a/openvswitch-2.14.2/lib/packets.h b/openvswitch-2.14.2/lib/packets.h +index 395bc86..02c3932 100644 +--- a/openvswitch-2.14.2/lib/packets.h ++++ b/openvswitch-2.14.2/lib/packets.h +@@ -1537,6 +1537,8 @@ BUILD_ASSERT_DECL(sizeof(struct vxlanhdr) == 8); + + #define VXLAN_FLAGS 0x08000000 /* struct vxlanhdr.vx_flags required value. */ + ++#define IP_MAX_MASK_LEN 32 ++#define IPV6_MAX_MASK_LEN 128 + /* + * VXLAN Generic Protocol Extension (VXLAN_F_GPE): + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +diff --git a/openvswitch-2.14.2/lib/smap.c b/openvswitch-2.14.2/lib/smap.c +index 149b8b2..e4f4527 100644 +--- a/openvswitch-2.14.2/lib/smap.c ++++ b/openvswitch-2.14.2/lib/smap.c +@@ -393,6 +393,17 @@ smap_add__(struct smap *smap, char *key, void *value, size_t hash) + return node; + } + ++void ++smap_add_format_varg(struct smap *smap, const char *key, const char *format, va_list args) ++{ ++ char *value; ++ size_t key_len; ++ ++ value = xvasprintf(format, args); ++ key_len = strlen(key); ++ smap_add__(smap, xmemdup0(key, key_len), value, hash_bytes(key, key_len, 0)); ++} ++ + static struct smap_node * + smap_find__(const struct smap *smap, const char *key, size_t key_len, + size_t hash) +diff --git a/openvswitch-2.14.2/lib/smap.h b/openvswitch-2.14.2/lib/smap.h +index 766c65f..3d9d1c6 100644 +--- a/openvswitch-2.14.2/lib/smap.h ++++ b/openvswitch-2.14.2/lib/smap.h +@@ -89,6 +89,7 @@ struct smap_node *smap_add_nocopy(struct smap *, char *, char *); + bool smap_add_once(struct smap *, const char *, const char *); + void smap_add_format(struct smap *, const char *key, const char *, ...) + OVS_PRINTF_FORMAT(3, 4); ++void smap_add_format_varg(struct smap *smap, const char *key, const char *format, va_list args); + void smap_add_ipv6(struct smap *, const char *, struct in6_addr *); + void smap_replace(struct smap *, const char *, const char *); + void smap_replace_nocopy(struct smap *, const char *, char *); +diff --git a/openvswitch-2.14.2/ofproto/ofproto-dpif-upcall.c b/openvswitch-2.14.2/ofproto/ofproto-dpif-upcall.c +index b24547d..dfec310 100644 +--- a/openvswitch-2.14.2/ofproto/ofproto-dpif-upcall.c ++++ b/openvswitch-2.14.2/ofproto/ofproto-dpif-upcall.c +@@ -409,6 +409,9 @@ static int udpif_flow_unprogram(struct udpif *udpif, struct udpif_key *ukey, + static upcall_callback upcall_cb; + static dp_purge_callback dp_purge_cb; + ++#ifdef HAVE_HWOFF_AGENT ++static dp_pmd_ukey_purge_callback dp_pmd_ukey_purge_cb; ++#endif + static atomic_bool enable_megaflows = ATOMIC_VAR_INIT(true); + static atomic_bool enable_ufid = ATOMIC_VAR_INIT(true); + +@@ -463,6 +466,9 @@ udpif_create(struct dpif_backer *backer, struct dpif *dpif) + dpif_register_upcall_cb(dpif, upcall_cb, udpif); + dpif_register_dp_purge_cb(dpif, dp_purge_cb, udpif); + ++#ifdef HAVE_HWOFF_AGENT ++ dpif_register_dp_pmd_ukey_purge_cb(dpif, dp_pmd_ukey_purge_cb, udpif); ++#endif + return udpif; + } + +@@ -489,6 +495,9 @@ udpif_destroy(struct udpif *udpif) + dpif_register_dp_purge_cb(udpif->dpif, NULL, udpif); + dpif_register_upcall_cb(udpif->dpif, NULL, udpif); + ++#ifdef HAVE_HWOFF_AGENT ++ dpif_register_dp_pmd_ukey_purge_cb(udpif->dpif, NULL, udpif); ++#endif + for (int i = 0; i < N_UMAPS; i++) { + cmap_destroy(&udpif->ukeys[i].cmap); + ovs_mutex_destroy(&udpif->ukeys[i].mutex); +@@ -965,7 +974,7 @@ udpif_revalidator(void *arg) + flow_limit < n_flows * 1000 / duration) { + flow_limit += 1000; + } +- flow_limit = MIN(ofproto_flow_limit, MAX(flow_limit, 1000)); ++ flow_limit = MIN(ofproto_flow_limit, MAX(flow_limit, 3000)); + atomic_store_relaxed(&udpif->flow_limit, flow_limit); + + if (duration > 2000) { +@@ -2874,7 +2883,24 @@ dp_purge_cb(void *aux, unsigned pmd_id) + } + udpif_resume_revalidators(udpif); + } +- ++#ifdef HAVE_HWOFF_AGENT ++static void dp_pmd_ukey_purge_cb(void *aux, unsigned pmd_id) ++{ ++ struct udpif *udpif = aux; ++ int i; ++ for (i = 0; i < N_UMAPS; i++) { ++ struct udpif_key *ukey; ++ struct umap *umap = &udpif->ukeys[i]; ++ ovs_mutex_lock(&umap->mutex); ++ CMAP_FOR_EACH(ukey, cmap_node, &umap->cmap) { ++ if (ukey->pmd_id == pmd_id) { ++ ukey_delete(umap, ukey); ++ } ++ } ++ ovs_mutex_unlock(&umap->mutex); ++ } ++} ++#endif + static void + upcall_unixctl_show(struct unixctl_conn *conn, int argc OVS_UNUSED, + const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED) +diff --git a/openvswitch-2.14.2/ofproto/ofproto-dpif-xlate.c b/openvswitch-2.14.2/ofproto/ofproto-dpif-xlate.c +index 1f78da1..1713578 100644 +--- a/openvswitch-2.14.2/ofproto/ofproto-dpif-xlate.c ++++ b/openvswitch-2.14.2/ofproto/ofproto-dpif-xlate.c +@@ -33,6 +33,7 @@ + #include "coverage.h" + #include "csum.h" + #include "dp-packet.h" ++#include "dpif-provider.h" + #include "dpif.h" + #include "in-band.h" + #include "lacp.h" +@@ -87,6 +88,10 @@ VLOG_DEFINE_THIS_MODULE(ofproto_dpif_xlate); + * Outputs to patch ports and to groups also count against the depth limit. */ + #define MAX_DEPTH 64 + ++#ifdef HAVE_HWOFF_AGENT ++#define NETDEV_NAME "netdev" ++#endif ++ + /* Maximum number of resubmit actions in a flow translation, whether they are + * recursive or not. */ + #define MAX_RESUBMITS (MAX_DEPTH * MAX_DEPTH) +@@ -2590,13 +2595,56 @@ update_learning_table__(const struct xbridge *xbridge, + struct xbundle *in_xbundle, struct eth_addr dl_src, + int vlan, bool is_grat_arp) + { ++#ifdef HAVE_HWOFF_AGENT ++ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5); ++ void *out_ofbundle = NULL; ++ bool update = (in_xbundle == &ofpp_none_bundle); ++ ++ if (update) { ++ return update; ++ } ++ update = mac_learning_update(xbridge->ml, dl_src, vlan, ++ is_grat_arp, ++ in_xbundle->bond != NULL, ++ in_xbundle->ofbundle, &out_ofbundle); ++ if (update && out_ofbundle) { ++ VLOG_INFO_RL(&rl, "mac learning conflicted. "ETH_ADDR_FMT" is on new port %s in VLAN %d, old port is %s", ++ ETH_ADDR_ARGS(dl_src), in_xbundle->name, vlan, ofbundle_get_name(out_ofbundle)); ++ } ++ ++ return !update; ++#else + return (in_xbundle == &ofpp_none_bundle + || !mac_learning_update(xbridge->ml, dl_src, vlan, + is_grat_arp, + in_xbundle->bond != NULL, + in_xbundle->ofbundle)); ++#endif + } ++#ifdef HAVE_HWOFF_AGENT ++static void ++update_learning_table(const struct xlate_ctx *ctx, ++ struct xbundle *in_xbundle, struct eth_addr dl_src, ++ int vlan, bool is_grat_arp, bool is_reverse_arp, bool is_ipv6_nd) ++{ ++ struct hwoff_migrate_rarp_mac_infos *hwoff_migrate_rarp_mac_infos = hwoff_migrate_rarp_mac_infos_get(); ++ if (!update_learning_table__(ctx->xbridge, in_xbundle, dl_src, vlan, ++ is_grat_arp)) { ++ xlate_report_debug(ctx, OFT_DETAIL, "learned that "ETH_ADDR_FMT" is " ++ "on port %s in VLAN %d", ++ ETH_ADDR_ARGS(dl_src), in_xbundle->name, vlan); + ++ if ((unlikely(is_reverse_arp) || unlikely(is_grat_arp) || unlikely(is_ipv6_nd)) && ++ hwoff_rarp_status_get() && (!strcmp(ctx->xbridge->dpif->dpif_class->type, NETDEV_NAME))) { ++ ovs_rwlock_wrlock(&hwoff_migrate_rarp_mac_infos->rw); ++ if (hwoff_rarp_mac_insert_to_list(dl_src) == NULL) { ++ xlate_report(ctx, OFT_WARN, "insert failed ! the rarp mac length exceeds the upper limit."); ++ } ++ ovs_rwlock_unlock(&hwoff_migrate_rarp_mac_infos->rw); ++ } ++ } ++} ++#else + static void + update_learning_table(const struct xlate_ctx *ctx, + struct xbundle *in_xbundle, struct eth_addr dl_src, +@@ -2609,6 +2657,7 @@ update_learning_table(const struct xlate_ctx *ctx, + ETH_ADDR_ARGS(dl_src), in_xbundle->name, vlan); + } + } ++#endif + + /* Updates multicast snooping table 'ms' given that a packet matching 'flow' + * was received on 'in_xbundle' in 'vlan' and is either Report or Query. */ +@@ -3010,15 +3059,23 @@ xlate_normal(struct xlate_ctx *ctx) + if (in_port && !is_admissible(ctx, in_port, vlan)) { + return; + } +- + /* Learn source MAC. */ + bool is_grat_arp = is_gratuitous_arp(flow, wc); ++#ifdef HAVE_HWOFF_AGENT ++ bool is_reverse_arp = (flow->dl_type == htons(ETH_TYPE_RARP)) ? true : false; ++ bool is_ipv6_nd = is_nd(flow, NULL); ++#endif + if (ctx->xin->allow_side_effects + && flow->packet_type == htonl(PT_ETH) + && in_port->pt_mode != NETDEV_PT_LEGACY_L3 + ) { +- update_learning_table(ctx, in_xbundle, flow->dl_src, vlan, ++#ifdef HAVE_HWOFF_AGENT ++ update_learning_table(ctx, in_xbundle, flow->dl_src, vlan, ++ is_grat_arp, is_reverse_arp, is_ipv6_nd); ++#else ++ update_learning_table(ctx, in_xbundle, flow->dl_src, vlan, + is_grat_arp); ++#endif + } + if (ctx->xin->xcache && in_xbundle != &ofpp_none_bundle) { + struct xc_entry *entry; +diff --git a/openvswitch-2.14.2/ofproto/ofproto-dpif.c b/openvswitch-2.14.2/ofproto/ofproto-dpif.c +index 4f0638f..c9dc9c1 100644 +--- a/openvswitch-2.14.2/ofproto/ofproto-dpif.c ++++ b/openvswitch-2.14.2/ofproto/ofproto-dpif.c +@@ -193,6 +193,11 @@ ofport_dpif_cast(const struct ofport *ofport) + return ofport ? CONTAINER_OF(ofport, struct ofport_dpif, up) : NULL; + } + ++char * ++ofbundle_get_name(const void *ofbundle_) ++{ ++ return ((struct ofbundle *)ofbundle_)->name; ++} + static void port_run(struct ofport_dpif *); + static int set_bfd(struct ofport *, const struct smap *); + static int set_cfm(struct ofport *, const struct cfm_settings *); +@@ -5292,6 +5297,18 @@ type_set_config(const char *type, const struct smap *other_config) + dpif_set_config(backer->dpif, other_config); + } + ++#ifdef HAVE_HWOFF_AGENT ++static void ++ct_flush(const struct ofproto *ofproto_, const uint16_t *zone, ++ union ct_addr *sip, union ct_addr *dip, ++ union ct_addr*smask, union ct_addr *dmask, ++ uint16_t dl_type, bool is_force) ++{ ++ struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); ++ ++ ct_dpif_flush(ofproto->backer->dpif, zone, sip, dip, smask, dmask, dl_type, is_force); ++} ++#else + static void + ct_flush(const struct ofproto *ofproto_, const uint16_t *zone) + { +@@ -5299,6 +5316,7 @@ ct_flush(const struct ofproto *ofproto_, const uint16_t *zone) + + ct_dpif_flush(ofproto->backer->dpif, zone, NULL); + } ++#endif + + static struct ct_timeout_policy * + ct_timeout_policy_lookup(const struct hmap *ct_tps, struct simap *tp) +diff --git a/openvswitch-2.14.2/ofproto/ofproto-dpif.h b/openvswitch-2.14.2/ofproto/ofproto-dpif.h +index 1f5794f..9ae0629 100644 +--- a/openvswitch-2.14.2/ofproto/ofproto-dpif.h ++++ b/openvswitch-2.14.2/ofproto/ofproto-dpif.h +@@ -349,6 +349,7 @@ struct ofproto_dpif { + * switch connection. */ + }; + ++char *ofbundle_get_name(const void *ofbundle_); + struct ofproto_dpif *ofproto_dpif_lookup_by_name(const char *name); + struct ofproto_dpif *ofproto_dpif_lookup_by_uuid(const struct uuid *uuid); + +diff --git a/openvswitch-2.14.2/ofproto/ofproto-provider.h b/openvswitch-2.14.2/ofproto/ofproto-provider.h +index afecb24..ff46587 100644 +--- a/openvswitch-2.14.2/ofproto/ofproto-provider.h ++++ b/openvswitch-2.14.2/ofproto/ofproto-provider.h +@@ -58,6 +58,7 @@ + #include "tun-metadata.h" + #include "versions.h" + #include "vl-mff-map.h" ++#include "conntrack.h" + + struct match; + struct ofputil_flow_mod; +@@ -1895,7 +1896,14 @@ struct ofproto_class { + /* ## ------------------- ## */ + /* Flushes the connection tracking tables. If 'zone' is not NULL, + * only deletes connections in '*zone'. */ ++#ifdef HAVE_HWOFF_AGENT ++ void (*ct_flush)(const struct ofproto *, const uint16_t *zone, ++ union ct_addr *sip, union ct_addr *dip, ++ union ct_addr *smask, union ct_addr *dmask, ++ uint16_t dl_type, bool is_force); ++#else + void (*ct_flush)(const struct ofproto *, const uint16_t *zone); ++#endif + + /* Sets conntrack timeout policy specified by 'timeout_policy' to 'zone' + * in datapath type 'dp_type'. */ +diff --git a/openvswitch-2.14.2/ofproto/ofproto.c b/openvswitch-2.14.2/ofproto/ofproto.c +index 59f06aa..d23ad15 100644 +--- a/openvswitch-2.14.2/ofproto/ofproto.c ++++ b/openvswitch-2.14.2/ofproto/ofproto.c +@@ -941,7 +941,11 @@ handle_nxt_ct_flush_zone(struct ofconn *ofconn, const struct ofp_header *oh) + + uint16_t zone = ntohs(nzi->zone_id); + if (ofproto->ofproto_class->ct_flush) { ++#ifdef HAVE_HWOFF_AGENT ++ ofproto->ofproto_class->ct_flush(ofproto, &zone, NULL, NULL, NULL, NULL, 0, false); ++#else + ofproto->ofproto_class->ct_flush(ofproto, &zone); ++#endif + } else { + return EOPNOTSUPP; + } +diff --git a/openvswitch-2.14.2/tests/hiovs-offload.at b/openvswitch-2.14.2/tests/hiovs-offload.at +new file mode 100644 +index 0000000..41d9ea5 +--- /dev/null ++++ b/openvswitch-2.14.2/tests/hiovs-offload.at +@@ -0,0 +1,10 @@ ++AT_BANNER([hiovs offload unit tests]) ++m4_foreach( ++ [testname], ++ [[init_flow_api], ++ [flow_put], ++ [flow_del], ++ [flow_get]], ++ [AT_SETUP([hiovs offload- m4_bpatsubst(testname, [-], [ ])]) ++ AT_CHECK([ovstest test-hiovs-offload m4_bpatsubst(testname, [versioned], [--versioned])], [0], [], []) ++ AT_CLEANUP])]) +diff --git a/openvswitch-2.14.2/tests/test-hiovs-offload.c b/openvswitch-2.14.2/tests/test-hiovs-offload.c +new file mode 100644 +index 0000000..fb7b6fc +--- /dev/null ++++ b/openvswitch-2.14.2/tests/test-hiovs-offload.c +@@ -0,0 +1,262 @@ ++/* ++ * Copyright (c) 2015 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#include ++#include ++#include ++ ++#include "ovstest.h" ++#include "util.h" ++#include "hwoff_init_func.h" ++#include "dpif.h" ++#include "cmap.h" ++#include "dp-packet.h" ++#include "netdev-offload-provider.h" ++ ++struct rte_flow { ++ /* rte_flow mega ufid. */ ++ ovs_u128 mega_ufid; ++ /* Number of packets matched. */ ++ uint64_t sw_packets; ++ /* Number of bytes matched. */ ++ uint64_t sw_bytes; ++ /* Time of rte_flow success offload. */ ++ long long sw_offload_time; ++ struct cmap_node node; ++ /* rte_flow mapped hardware flow. */ ++ struct cmap hw_list; ++}; ++ ++static int mock_hwoff_init_flow_api(struct netdev *netdev) ++{ ++ (void)netdev; ++ return 0; ++} ++ ++static struct rte_flow* mock_hwoff_rte_flow_create(struct netdev *netdev, const struct rte_flow_attr *attr, ++ const struct rte_flow_item *items, ++ const struct rte_flow_action *actions, ++ struct rte_flow_error *error) ++{ ++ struct rte_flow *new_rte_flow = NULL; ++ ++ (void)netdev; ++ (void)attr; ++ (void)items; ++ (void)actions; ++ (void)error; ++ new_rte_flow = (struct rte_flow *)malloc(sizeof(*new_rte_flow)); ++ return new_rte_flow; ++} ++ ++static int mock_hwoff_rte_flow_destroy(struct netdev *netdev, struct rte_flow *rte_flow, struct rte_flow_error *error) ++{ ++ (void)netdev; ++ (void)rte_flow; ++ (void)error; ++ return 0; ++} ++ ++static int mock_hwoff_rte_flow_query_count(struct netdev *netdev, struct rte_flow *rte_flow, ++ struct rte_flow_query_count *query, struct rte_flow_error *error) ++{ ++ (void)netdev; ++ (void)rte_flow; ++ (void)query; ++ (void)error; ++ return 0; ++} ++ ++static bool mock_hwoff_is_hiovs_netdev(const struct netdev *netdev) ++{ ++ (void)netdev; ++ return true; ++} ++ ++static bool mock_hwoff_is_support_offload(const struct netdev *netdev) ++{ ++ (void)netdev; ++ return true; ++} ++ ++static void mock_hwoff_funcs(void) ++{ ++ hwoff_func* funcs = hwoff_get_funcs(); ++ ++ funcs->hwoff_init_flow_api = mock_hwoff_init_flow_api; ++ funcs->hwoff_rte_flow_create = mock_hwoff_rte_flow_create; ++ funcs->hwoff_rte_flow_destroy = mock_hwoff_rte_flow_destroy; ++ funcs->hwoff_rte_flow_query_count = mock_hwoff_rte_flow_query_count; ++ funcs->hwoff_is_hiovs_netdev = mock_hwoff_is_hiovs_netdev; ++ funcs->hwoff_is_support_offload = mock_hwoff_is_support_offload; ++} ++ ++static struct netdev* hiovs_create_fake_netdev(void) ++{ ++ struct netdev *dev; ++ ++ dev = (struct netdev *)malloc(sizeof(struct netdev)); ++ if (!dev) { ++ return NULL; ++ } ++ ++ return dev; ++} ++ ++static void hiovs_fill_offload_info(struct offload_info *tmp_offload_info) ++{ ++ tmp_offload_info->in_port_id = 1; ++ tmp_offload_info->in_port_type = 1; ++ tmp_offload_info->pmd_core_id = 1; ++ tmp_offload_info->modification = false; ++} ++ ++static void hiovs_offload_flow_put(ovs_u128 *ufid, struct netdev *dev) ++{ ++ int ret; ++ uint8_t actions_stub[512]; ++ struct ofpbuf actions; ++ struct dpif_flow_stats stats; ++ struct offload_info tmp_offload_info; ++ struct dp_packet_batch pkt_batch; ++ struct netdev_flow_api *hiovs_class = (struct netdev_flow_api *)&netdev_offload_hiovs; ++ ++ ofpbuf_use_stub(&actions, actions_stub, sizeof(actions_stub)); ++ nl_msg_put_odp_port(&actions, OVS_ACTION_ATTR_OUTPUT, u32_to_odp(1)); ++ ++ tmp_offload_info.pkts_info = &pkt_batch; ++ hiovs_fill_offload_info(&tmp_offload_info); ++ ++ ret = hiovs_class->flow_put(dev, NULL, actions.data, actions.size, ufid, &tmp_offload_info, &stats); ++ if (ret != 0) { ++ ovs_fatal(0, "flow_put fail"); ++ return; ++ } ++ return; ++} ++ ++static void hiovs_fill_ufid(ovs_u128 *ufid, uint32_t value) ++{ ++ ufid->u32[0] = value; ++ ufid->u32[1] = 0; ++ ufid->u32[2] = 0; ++ ufid->u32[3] = 0; ++} ++ ++static void test_hiovs_offload_init_flow_api(struct ovs_cmdl_context *ctx OVS_UNUSED) ++{ ++ int ret; ++ struct netdev *dev = NULL; ++ struct netdev_flow_api *hiovs_class = (struct netdev_flow_api *)&netdev_offload_hiovs; ++ ++ mock_hwoff_funcs(); ++ dev = hiovs_create_fake_netdev(); ++ if (!dev) { ++ ovs_fatal(0, "can't create netdev"); ++ return; ++ } ++ ++ ret = hiovs_class->init_flow_api(dev); ++ if (ret != 0) { ++ ovs_fatal(0, "init_flow_api execute fail"); ++ free(dev); ++ return; ++ } ++ ++ return; ++} ++ ++static void test_hiovs_offload_flow_put(struct ovs_cmdl_context *ctx OVS_UNUSED) ++{ ++ ovs_u128 ufid; ++ struct netdev *dev = NULL; ++ ++ hiovs_fill_ufid(&ufid, 211); ++ mock_hwoff_funcs(); ++ dev = hiovs_create_fake_netdev(); ++ if (!dev) { ++ ovs_fatal(0, "can't create netdev"); ++ return; ++ } ++ ++ hiovs_offload_flow_put(&ufid, dev); ++ free(dev); ++ return; ++} ++ ++static void test_hiovs_offload_flow_delete(struct ovs_cmdl_context *ctx OVS_UNUSED) ++{ ++ ovs_u128 ufid; ++ struct netdev *dev = NULL; ++ struct dpif_flow_stats stats; ++ struct netdev_flow_api *hiovs_class = (struct netdev_flow_api *)&netdev_offload_hiovs; ++ ++ hiovs_fill_ufid(&ufid, 212); ++ mock_hwoff_funcs(); ++ dev = hiovs_create_fake_netdev(); ++ if (!dev) { ++ ovs_fatal(0, "can't create netdev"); ++ return; ++ } ++ ++ hiovs_offload_flow_put(&ufid, dev); ++ hiovs_class->flow_del(dev, &ufid, &stats); ++ free(dev); ++ return; ++} ++ ++static void test_hiovs_offload_flow_get(struct ovs_cmdl_context *ctx OVS_UNUSED) ++{ ++ ovs_u128 ufid; ++ struct netdev *dev = NULL; ++ struct dpif_flow_stats stats; ++ struct dpif_flow_attrs attr; ++ struct netdev_flow_api *hiovs_class = (struct netdev_flow_api *)&netdev_offload_hiovs; ++ ++ hiovs_fill_ufid(&ufid, 212); ++ mock_hwoff_funcs(); ++ dev = hiovs_create_fake_netdev(); ++ if (!dev) { ++ ovs_fatal(0, "can't create netdev"); ++ return; ++ } ++ ++ hiovs_offload_flow_put(&ufid, dev); ++ ++ hiovs_class->flow_get(dev, NULL, NULL, &ufid, &stats, &attr, NULL); ++ free(dev); ++ return; ++} ++ ++static const struct ovs_cmdl_command commands[] = { ++ {"init_flow_api", "init_flow_api", 0, 0, test_hiovs_offload_init_flow_api, OVS_RO}, ++ {"flow_put", "flow_put", 0, 0, test_hiovs_offload_flow_put, OVS_RO}, ++ {"flow_del", "flow_del", 0, 0, test_hiovs_offload_flow_delete, OVS_RO}, ++ {"flow_get", "flow_get", 0, 0, test_hiovs_offload_flow_get, OVS_RO}, ++ {NULL, NULL, 0, 0, NULL, OVS_RO}, ++}; ++ ++static void test_hiovs_offload_main(int argc, char *argv[]) ++{ ++ struct ovs_cmdl_context ctx = { ++ .argc = argc - 1, ++ .argv = argv + 1, ++ }; ++ set_program_name(argv[0]); ++ ovs_cmdl_run_command(&ctx, commands); ++} ++ ++OVSTEST_REGISTER("test-hiovs-offload", test_hiovs_offload_main); +diff --git a/openvswitch-2.14.2/tests/testsuite.at b/openvswitch-2.14.2/tests/testsuite.at +index 7369991..5cc06a8 100644 +--- a/openvswitch-2.14.2/tests/testsuite.at ++++ b/openvswitch-2.14.2/tests/testsuite.at +@@ -77,3 +77,4 @@ m4_include([tests/mcast-snooping.at]) + m4_include([tests/packet-type-aware.at]) + m4_include([tests/nsh.at]) + m4_include([tests/drop-stats.at]) ++m4_include([tests/hiovs-offload.at]) +diff --git a/openvswitch-2.14.2/vswitchd/bridge.c b/openvswitch-2.14.2/vswitchd/bridge.c +index a332517..2b27edd 100644 +--- a/openvswitch-2.14.2/vswitchd/bridge.c ++++ b/openvswitch-2.14.2/vswitchd/bridge.c +@@ -19,6 +19,10 @@ + #include + #include + ++#ifdef HAVE_HWOFF_AGENT ++#include "hwoff_init_func.h" ++#endif ++ + #include "async-append.h" + #include "bfd.h" + #include "bitmap.h" +@@ -553,6 +557,11 @@ bridge_exit(bool delete_datapath) + } + + ovsdb_idl_destroy(idl); ++ ++#ifdef HAVE_HWOFF_AGENT ++ hwoff_clear_pf_access_hugepages(); ++ hwoff_free_hugepages(); ++#endif + } + + /* Looks at the list of managers in 'ovs_cfg' and extracts their remote IP +@@ -3251,6 +3260,9 @@ bridge_run__(void) + } + } + ++extern void rte_adapter_init(void); ++extern void ovs_adapter_init(void); ++ + void + bridge_run(void) + { +@@ -3291,6 +3303,16 @@ bridge_run(void) + netdev_set_flow_api_enabled(&cfg->other_config); + dpdk_init(&cfg->other_config); + userspace_tso_init(&cfg->other_config); ++ ++#ifdef HAVE_HWOFF_AGENT ++ int ret = netdev_offload_hw_init(&cfg->other_config); ++ if (ret == 0) { ++ hwoff_func* funcs = hwoff_get_funcs(); ++ if (funcs->hwoff_parse_ovs_other_config) { ++ funcs->hwoff_parse_ovs_other_config(&cfg->other_config); ++ } ++ } ++#endif + } + + /* Initialize the ofproto library. This only needs to run once, but diff --git a/openvswitch-2.12.0.tar.gz b/openvswitch-2.14.2.tar.gz similarity index 48% rename from openvswitch-2.12.0.tar.gz rename to openvswitch-2.14.2.tar.gz index 5159726406762f8b6a8908fb67f2f68aac3e902d..20f84290cae25397558386d7c2908ed0f44ce3d5 100644 Binary files a/openvswitch-2.12.0.tar.gz and b/openvswitch-2.14.2.tar.gz differ diff --git a/openvswitch-kmod.spec b/openvswitch-kmod.spec deleted file mode 100644 index d572a562e06d072a486f2dff22908d6e28d4e244..0000000000000000000000000000000000000000 --- a/openvswitch-kmod.spec +++ /dev/null @@ -1,188 +0,0 @@ -# Spec file for Open vSwitch kernel modules on openEuler version. - -# Copyright (C) 2011, 2012, 2018 Nicira, Inc. -# -# Copying and distribution of this file, with or without modification, -# are permitted in any medium without royalty provided the copyright -# notice and this notice are preserved. This file is offered as-is, -# without warranty of any kind. - -#needsrootforbuild - -%define kversion $(uname -r) -%{?kversion:%define kernel %kversion} - -Name: openvswitch-kmod -Version: 2.12.0 -Release: 1 -Summary: Open vSwitch Kernel Modules -License: GPLv2 -URL: http://www.openvswitch.org/ -Source: openvswitch-%{version}.tar.gz -Patch0: Prepare-for-2.12.1.patch -Patch1: faq-Update-list-of-kernels-supported-by-2.12.patch -Patch2: raft-Free-leaked-json-data.patch -Patch3: ofproto-dpif-Uninitialize-xlate_cache-to-free-resour.patch -Patch4: dpif-netdev-Handle-uninitialized-value-error-for-mat.patch -Patch5: ovs-ofctl-Free-leaked-minimatch.patch -Patch6: trigger-Free-leaked-ovsdb_schema.patch -Patch7: ovsdb-client-Free-ovsdb_schema.patch -Patch8: dns-resolve-Free-struct-ub_result-when-callback-retu.patch -Patch9: ofproto-dpif-Free-leaked-webster.patch -Patch10: db-ctl-base-Free-leaked-ovsdb_datum.patch -Patch11: conntrack-Validate-accessing-of-conntrack-data-in-pk.patch -Patch12: faq-Update-OVS-DPDK-version-table-for-OVS-2.12.patch -Patch13: datapath-compat-Backports-bugfixes-for-nf_conncount.patch -Patch14: stream_ssl-fix-important-memory-leak-in-ssl_connect-.patch -Patch15: Documentation-Fix-security-mailing-list-address.patch -Patch16: conntrack-Fix-check_orig_tuple-Valgrind-false-positi.patch -Patch17: conntrack-Fix-reverse_nat_packet-variable-datatype.patch -Patch18: ovn-Exclude-inport-and-outport-symbol-tables-from-co.patch -Patch19: flow-fix-incorrect-padding-length-checking-in-ipv6_s.patch -Patch20: netdev-dpdk-Fix-padding-info-comment.patch -Patch21: travis-Drop-MD-related-workaround-for-sparse.patch -Patch22: doc-Fix-incorrect-reference-for-dpdk-testpmd.patch -Patch23: ofproto-fix-a-typo-for-ttl-in-dpif_sflow_actions.patch -Patch24: flow-Fix-using-pointer-to-member-of-packed-struct-ic.patch -Patch25: netdev-afxdp-Fix-umem-creation-failure-due-to-uninit.patch -Patch26: netdev-afxdp-Update-memory-locking-limits-unconditio.patch -Patch27: dpif-netlink-Free-leaked-nl_sock.patch -Patch28: ovsdb-server-Don-t-drop-all-connections-on-read-writ.patch -Patch29: tc-Limit-the-max-action-number-to-16.patch -Patch30: lldp-Fix-for-OVS-crashes-when-a-LLDP-enabled-port-is.patch -Patch31: tests-Fix-indentation-in-userspace-packet-type-aware.patch -Patch32: flow-Fix-crash-on-vlan-packets-with-partial-offloadi.patch -Patch33: ovsdb-server-fix-memory-leak-while-converting-databa.patch -Patch34: dpif-netdev-Do-not-mix-recirculation-depth-into-RSS-.patch -Patch35: dpif-netdev-Fix-time-delta-overflow-in-case-of-race-.patch -Patch36: rhel-openvswitch-fedora.spec.in-Fix-output-redirect-.patch -Patch37: lflow.c-Fix-memory-leak-of-lflow_ref_list_node-ref_n.patch -Patch38: Avoid-indeterminate-statistics-in-offload-implementa.patch -Patch39: lib-tc-Fix-flow-dump-for-tunnel-id-equal-zero.patch -Patch40: netdev-dpdk-Fix-flow-control-not-configuring.patch -Patch41: vswitch.xml-Fix-column-for-xdpmode.patch -Patch42: compat-Add-compat-fix-for-old-kernels.patch -Patch43: rhel-Fix-ovs-kmod-manage.sh-that-may-create-invalid-.patch -Patch44: ovsdb-server-fix-memory-leak-while-deleting-zone.patch -Patch45: ovn-Prevent-erroneous-duplicate-IP-address-messages.patch -Patch46: jsonrpc-increase-input-buffer-size-from-512-to-4096.patch -Patch47: ovsdb-raft-Fix-election-timer-parsing-in-snapshot-RP.patch -Patch48: ipf-bail-out-when-ipf-state-is-COMPLETED.patch -Patch49: ofproto-dpif-Allow-IPv6-ND-Extensions-only-if-suppor.patch -Patch50: flow-Fix-IPv6-header-parser-with-partial-offloading.patch -Patch51: ofproto-Fix-crash-on-PACKET_OUT-due-to-recursive-loc.patch -Patch52: dpdk-Use-DPDK-18.11.5-release.patch -Patch53: dp-packet-Fix-clearing-copying-of-memory-layout-flag.patch -Patch54: rhel-Support-RHEL7.7-build-and-packaging.patch -Patch55: ofproto-fix-stack-buffer-overflow.patch -Patch56: sparse-Get-rid-of-obsolete-rte_flow-header.patch -Patch57: ofproto-dpif-xlate-Restore-table-ID-on-error-in-xlat.patch -Patch58: ovn-controller-Add-missing-port-group-lflow-referenc.patch -Patch59: cirrus-Use-latest-stable-FreeBSD-images.patch -Patch60: cirrus-Use-FreeBSD-12.1-stable-release.patch -Patch61: rhel-Support-RHEL-7.8-kernel-module-rpm-build.patch -Patch62: dpif-netdev-Avoid-infinite-re-addition-of-misconfigu.patch -Patch63: netdev-afxdp-Avoid-removing-of-XDP-program-if-not-lo.patch -Patch64: system-afxdp.at-Add-test-for-infinite-re-addition-of.patch -Patch65: ovsdb-cluster.at-Wait-until-leader-is-elected-before.patch -Patch66: ovsdb-raft-Fix-the-problem-when-cluster-restarted-af.patch - -#Source1: openvswitch-init -Buildroot: /tmp/openvswitch-xen-rpm -Provides: kmod-openvswitch -Conflicts: kmod-openvswitch - -BuildRequires: python-six -BuildRequires: openssl-devel -BuildRequires: checkpolicy, selinux-policy-devel -BuildRequires: autoconf, automake, libtool -BuildRequires: python-sphinx -BuildRequires: kernel kernel-devel -%undefine _enable_debug_packages -%description -Open vSwitch Linux kernel module - -%prep -%setup -q -n openvswitch-%{version} -%autopatch -p1 - -%build -sh boot.sh -for kv in %{kversion}; do - mkdir -p _$kv - (cd _$kv && /bin/cp -f ../configure . && %configure --srcdir=.. \ - --with-linux=/lib/modules/${kv}/build --enable-ssl %{_ovs_config_extra_flags}) - make %{_smp_mflags} -C _$kv/datapath/linux -done - -%install -export INSTALL_MOD_DIR=extra/openvswitch -rm -rf $RPM_BUILD_ROOT -for kv in %{kversion}; do - make INSTALL_MOD_PATH=$RPM_BUILD_ROOT -C _$kv/datapath/linux modules_install -done -mkdir -p $RPM_BUILD_ROOT/etc/depmod.d -for kv in %{kversion}; do - for module in $RPM_BUILD_ROOT/lib/modules/${kv}/extra/openvswitch/*.ko - do - modname="$(basename ${module})" - grep -qsPo "^\s*override ${modname%.ko} \* extra\/openvwitch" \ - $RPM_BUILD_ROOT/etc/depmod.d/kmod-openvswitch.conf || \ - echo "override ${modname%.ko} * extra/openvswitch" >> \ - $RPM_BUILD_ROOT/etc/depmod.d/kmod-openvswitch.conf - grep -qsPo "^\s*override ${modname%.ko} \* weak-updates\/openvwitch" \ - $RPM_BUILD_ROOT/etc/depmod.d/kmod-openvswitch.conf || \ - echo "override ${modname%.ko} * weak-updates/openvswitch" >> \ - $RPM_BUILD_ROOT/etc/depmod.d/kmod-openvswitch.conf - done -done -install -d -m 0755 $RPM_BUILD_ROOT/usr/share/openvswitch/scripts -install -p -m 0755 rhel/usr_share_openvswitch_scripts_ovs-kmod-manage.sh \ - $RPM_BUILD_ROOT/usr/share/openvswitch/scripts/ovs-kmod-manage.sh - -%clean -rm -rf $RPM_BUILD_ROOT - -%post -current_kernel=$(uname -r) -IFS=. read installed_major installed_minor installed_micro installed_arch \ - installed_build <<<"${current_kernel##*-}" -if [ "$installed_major" = "327" ] || [ "$installed_major" = "693" ]; then - # Workaround for RHEL 7.2 and 7.4 - if [ -x "/usr/share/%{oname}/scripts/ovs-kmod-manage.sh" ]; then - /usr/share/%{oname}/scripts/ovs-kmod-manage.sh - fi -else - # Ensure that modprobe will find our modules. - for k in $(cd /lib/modules && /bin/ls); do - [ -d "/lib/modules/$k/kernel/" ] && /sbin/depmod -a "$k" - done - if [ -x "/sbin/weak-modules" ]; then - for m in openvswitch vport-gre vport-stt vport-geneve \ - vport-lisp vport-vxlan; do - echo "/lib/modules/%{kernel}/extra/openvswitch/$m.ko" - done | /sbin/weak-modules --add-modules - fi -fi - -%postun -if [ "$1" = 0 ]; then # Erase, not upgrade - for kname in `ls -d /lib/modules/*` - do - rm -rf $kname/weak-updates/openvswitch - done -fi -/sbin/depmod -a - -%files -%defattr(0644,root,root) -/lib/modules/*/extra/openvswitch/*.ko -%exclude /lib/modules/*/modules.* -/etc/depmod.d/kmod-openvswitch.conf -%attr(755,root,root) /usr/share/openvswitch/scripts/ovs-kmod-manage.sh - -%changelog -* Sat Dec 21 2019 openEuler Buildteam - 2.12.0 -- Add opensource patch -* Fri Nov 22 2019 openEuler Buildteam - 2.12.0 -- First build diff --git a/openvswitch.spec b/openvswitch.spec deleted file mode 100644 index 420b862aba2b495feb44d7a9726175f5c2b7231c..0000000000000000000000000000000000000000 --- a/openvswitch.spec +++ /dev/null @@ -1,212 +0,0 @@ -Name: openvswitch -Summary: Production Quality, Multilayer Open Virtual Switch -URL: http://www.openvswitch.org/ -Version: 2.12.0 -License: ASL 2.0 -Release: 5 -Source: https://www.openvswitch.org/releases/openvswitch-%{version}.tar.gz -Buildroot: /tmp/openvswitch-rpm -Patch0000: 0000-openvswitch-add-stack-protector-strong.patch -Requires: logrotate hostname python >= 2.7 python2-six selinux-policy-targeted -BuildRequires: python2-six, openssl-devel checkpolicy selinux-policy-devel autoconf automake libtool python-sphinx unbound-devel -Provides: openvswitch-selinux-policy = %{version}-%{release} -Obsoletes: openvswitch-selinux-policy < %{version}-%{release} - -%bcond_without check -%bcond_with check_datapath_kernel - -%description -Open vSwitch is a production quality, multilayer virtual switch licensed under -the open source Apache 2.0 license. - -%package devel -Summary: Development tools for Open vSwitch - -%description devel -Libraries, header files, and other development tools for Open vSwitch. - -%package help -Summary: Helpful information for Open vSwitch - -%description help -Documents and helpful information for Open vSwitch. - -%prep -%autosetup - -%build -autoreconf -./configure --prefix=/usr --sysconfdir=/etc --localstatedir=%{_localstatedir} \ - --libdir=%{_libdir} --enable-ssl --enable-shared -%make_build -make selinux-policy - -%install -%make_install - -install -D -m 0755 rhel/etc_init.d_openvswitch $RPM_BUILD_ROOT/etc/init.d/openvswitch -install -D -m 0644 rhel/etc_logrotate.d_openvswitch $RPM_BUILD_ROOT/etc/logrotate.d/openvswitch -install -D -m 0755 rhel/etc_sysconfig_network-scripts_ifup-ovs $RPM_BUILD_ROOT/etc/sysconfig/network-scripts/ifup-ovs -install -D -m 0755 rhel/etc_sysconfig_network-scripts_ifdown-ovs $RPM_BUILD_ROOT/etc/sysconfig/network-scripts/ifdown-ovs -install -D -m 0644 rhel/usr_share_openvswitch_scripts_sysconfig.template $RPM_BUILD_ROOT/usr/share/openvswitch/scripts/sysconfig.template - -install -p -m 644 -D selinux/openvswitch-custom.pp \ - $RPM_BUILD_ROOT%{_datadir}/selinux/packages/%{name}/openvswitch-custom.pp - -rm \ - $RPM_BUILD_ROOT/usr/bin/ovs-testcontroller \ - $RPM_BUILD_ROOT/usr/share/man/man8/ovs-testcontroller.8 \ - $RPM_BUILD_ROOT/usr/bin/ovs-test \ - $RPM_BUILD_ROOT/usr/bin/ovs-l3ping \ - $RPM_BUILD_ROOT/usr/share/man/man8/ovs-test.8 \ - $RPM_BUILD_ROOT/usr/share/man/man8/ovs-l3ping.8 \ - $RPM_BUILD_ROOT/usr/sbin/ovs-vlan-bug-workaround \ - $RPM_BUILD_ROOT/usr/share/man/man8/ovs-vlan-bug-workaround.8 \ - $RPM_BUILD_ROOT/usr/bin/ovn-* \ - $RPM_BUILD_ROOT/usr/share/man/man?/ovn-* \ - $RPM_BUILD_ROOT/usr/share/openvswitch/ovn-* \ - $RPM_BUILD_ROOT/usr/share/openvswitch/scripts/ovn* -(cd "$RPM_BUILD_ROOT" && rm -rf usr/%{_lib}/*.la) -(cd "$RPM_BUILD_ROOT" && rm -rf usr/include) - -install -d -m 0755 $RPM_BUILD_ROOT%{_rundir}/openvswitch -install -d -m 0755 $RPM_BUILD_ROOT%{_localstatedir}/log/openvswitch -install -d -m 0755 $RPM_BUILD_ROOT/var/lib/openvswitch - -install -d -m 0755 $RPM_BUILD_ROOT/%{_includedir}/openvswitch -install -d -m 0755 $RPM_BUILD_ROOT/%{_includedir}/openvswitch/openflow -install -d -m 0755 $RPM_BUILD_ROOT/%{_includedir}/openvswitch/openvswitch -install -d -m 0755 $RPM_BUILD_ROOT/%{_includedir}/openvswitch/sparse -install -d -m 0755 $RPM_BUILD_ROOT/%{_includedir}/openvswitch/sparse/arpa -install -d -m 0755 $RPM_BUILD_ROOT/%{_includedir}/openvswitch/sparse/netinet -install -d -m 0755 $RPM_BUILD_ROOT/%{_includedir}/openvswitch/sparse/sys -install -d -m 0755 $RPM_BUILD_ROOT/%{_includedir}/openvswitch/lib -install -m 0644 include/*.h $RPM_BUILD_ROOT/%{_includedir}/openvswitch -install -m 0644 include/openflow/*.h $RPM_BUILD_ROOT/%{_includedir}/openvswitch/openflow -install -m 0644 include/openvswitch/*.h $RPM_BUILD_ROOT/%{_includedir}/openvswitch/openvswitch -install -m 0644 include/sparse/*.h $RPM_BUILD_ROOT/%{_includedir}/openvswitch/sparse -install -m 0644 include/sparse/arpa/*.h $RPM_BUILD_ROOT/%{_includedir}/openvswitch/sparse/arpa -install -m 0644 include/sparse/netinet/*.h $RPM_BUILD_ROOT/%{_includedir}/openvswitch/sparse/netinet -install -m 0644 include/sparse/sys/*.h $RPM_BUILD_ROOT/%{_includedir}/openvswitch/sparse/sys -install -m 0644 lib/*.h $RPM_BUILD_ROOT/%{_includedir}/openvswitch/lib - -install -D -m 0644 lib/.libs/libopenvswitch.a \ - $RPM_BUILD_ROOT/%{_libdir}/libopenvswitch.a - -%clean -rm -rf $RPM_BUILD_ROOT - -%post -SYSCONFIG=/etc/sysconfig/openvswitch -TEMPLATE=/usr/share/openvswitch/scripts/sysconfig.template -if [ ! -e $SYSCONFIG ]; then - cp $TEMPLATE $SYSCONFIG -else - for var in $(awk -F'[ :]' '/^# [_A-Z0-9]+:/{print $2}' $TEMPLATE) - do - if ! grep $var $SYSCONFIG >/dev/null 2>&1; then - echo >> $SYSCONFIG - sed -n "/$var:/,/$var=/p" $TEMPLATE >> $SYSCONFIG - fi - done -fi - -/sbin/chkconfig --add openvswitch -/sbin/chkconfig openvswitch on - -%selinux_modules_install -s targeted %{_datadir}/selinux/packages/%{name}/openvswitch-custom.pp - -%pre -%selinux_relabel_pre -s targeted - -%preun -if [ "$1" = "0" ]; then # $1 = 0 for uninstall - /sbin/service openvswitch stop - /sbin/chkconfig --del openvswitch -fi - -%postun -if [ "$1" = "0" ]; then # $1 = 0 for uninstall - rm -f /etc/openvswitch/conf.db - rm -f /etc/sysconfig/openvswitch - rm -f /etc/openvswitch/vswitchd.cacert -fi - -if [ $1 -eq 0 ] ; then - %selinux_modules_uninstall -s targeted openvswitch-custom -fi -exit 0 - -%posttrans -%selinux_relabel_post -s targeted - -%files -%defattr(-,root,root) -%dir /etc/openvswitch -/etc/bash_completion.d/ovs-appctl-bashcomp.bash -/etc/bash_completion.d/ovs-vsctl-bashcomp.bash -/etc/init.d/openvswitch -%config(noreplace) /etc/logrotate.d/openvswitch -/etc/sysconfig/network-scripts/ifup-ovs -/etc/sysconfig/network-scripts/ifdown-ovs -/usr/bin/ovs-appctl -/usr/bin/ovs-dpctl -/usr/bin/ovs-dpctl-top -/usr/bin/ovs-docker -/usr/bin/ovs-ofctl -/usr/bin/ovs-parse-backtrace -/usr/bin/ovs-pcap -/usr/bin/ovs-pki -/usr/bin/ovs-tcpdump -/usr/bin/ovs-tcpundump -/usr/bin/ovs-vlan-test -/usr/bin/ovs-vsctl -/usr/bin/ovsdb-client -/usr/bin/ovsdb-tool -/usr/bin/vtep-ctl -%{_libdir}/lib*.so.* -/usr/sbin/ovs-bugtool -/usr/sbin/ovs-vswitchd -/usr/sbin/ovsdb-server -/usr/share/openvswitch/bugtool-plugins/ -/usr/share/openvswitch/python/ -/usr/share/openvswitch/scripts/ovs-bugtool-* -/usr/share/openvswitch/scripts/ovs-check-dead-ifs -/usr/share/openvswitch/scripts/ovs-ctl -/usr/share/openvswitch/scripts/ovs-kmod-ctl -/usr/share/openvswitch/scripts/ovs-lib -/usr/share/openvswitch/scripts/ovs-save -/usr/share/openvswitch/scripts/ovs-vtep -/usr/share/openvswitch/scripts/sysconfig.template -/usr/share/openvswitch/scripts/ovs-monitor-ipsec -/usr/share/openvswitch/vswitch.ovsschema -/usr/share/openvswitch/vtep.ovsschema -%doc NOTICE -/var/lib/openvswitch -/var/log/openvswitch -%{_datadir}/selinux/packages/%{name}/openvswitch-custom.pp - -%files devel -%{_libdir}/lib*.so -%{_libdir}/lib*.a -%{_libdir}/pkgconfig -%{_includedir}/openvswitch/* - -%files help -/usr/share/man/man1/* -/usr/share/man/man5/* -/usr/share/man/man7/* -/usr/share/man/man8/* -%{_mandir}/man5/* -%{_mandir}/man7/* -%doc README.rst NEWS rhel/README.RHEL.rst - -%changelog -* Wed Mar 18 2020 zhangtao - 2.12.0-5 -- add stack protector - -* Tue Mar 17 2020 gulining - 2.12.0-4 -- remove extra spaces to resolve compile error - -* Mon Mar 16 2020 jiangkai - 2.12.0-3 -- Package init diff --git a/ovn-Exclude-inport-and-outport-symbol-tables-from-co.patch b/ovn-Exclude-inport-and-outport-symbol-tables-from-co.patch deleted file mode 100644 index f8792da5e6a571c9ef3689d7c1969166a499855f..0000000000000000000000000000000000000000 --- a/ovn-Exclude-inport-and-outport-symbol-tables-from-co.patch +++ /dev/null @@ -1,124 +0,0 @@ -From 1f82d15cb88333520c367365cf76a7b97bd18e16 Mon Sep 17 00:00:00 2001 -From: Numan Siddique -Date: Sat, 14 Sep 2019 13:19:17 +0530 -Subject: ovn: Exclude inport and outport symbol tables from conjunction - -If there are multiple ACLs associated with a port group and they -match on a range of some field, then ovn-controller doesn't install -the flows properly and this results in broken ACL functionality. - -For example, if there is a port group - pg1 with logical ports - [p1, p2] -and if there are below ACLs (only match condition is shown) - -1 - outport == @pg1 && ip4 && tcp.dst >= 500 && tcp.dst <= 501 -2 - outport == @pg1 && ip4 && tcp.dst >= 600 && tcp.dst <= 601 - -The first ACL will result in the below OF flows - -1. conj_id=1,tcp -2. tcp,reg15=0x11: conjunction(1, 1/2) -3. tcp,reg15=0x12: conjunction(1, 1/2) -5. tcp,tp_dst=500: conjunction(1, 2/2) -6. tcp,tp_dst=501: conjunction(1, 2/2) - -The second ACL will result in the below OF flows -7. conj_id=2,tcp -8. tcp,reg15=0x11: conjunction(2, 1/2) -9. tcp,reg15=0x12: conjunction(2, 1/2) -11. tcp,tp_dst=600: conjunction(2, 2/2) -12. tcp,tp_dst=601: conjunction(2, 3/2) - -The OF flows (2) and (8) have the exact match but with different action. -This results in only one of the flows getting installed. The same goes -for the flows (3) and (9). And this completely breaks the ACL functionality -for such scenarios. - -In order to fix this issue, this patch excludes the 'inport' and 'outport' symbols -from conjunction. With this patch we will have the below flows. - -tcp,reg15=0x11,tp_dst=500 -tcp,reg15=0x11,tp_dst=501 -tcp,reg15=0x12,tp_dst=500 -tcp,reg15=0x12,tp_dst=501 -tcp,reg15=0x13,tp_dst=500 -tcp,reg15=0x13,tp_dst=501 -tcp,reg15=0x11,tp_dst=600 -tcp,reg15=0x11,tp_dst=601 -tcp,reg15=0x12,tp_dst=600 -tcp,reg15=0x12,tp_dst=601 -tcp,reg15=0x13,tp_dst=600 -tcp,reg15=0x13,tp_dst=601 - -Acked-by: Mark Michelson -Acked-by: Daniel Alvarez -Signed-off-by: Numan Siddique - -(cherry-picked from ovn commit 298701dbc99645700be41680a43d049cb061847a) - -Signed-off-by: Ben Pfaff ---- - ovn/lib/expr.c | 2 +- - tests/ovn.at | 26 ++++++++++++++++++++++++++ - 2 files changed, 27 insertions(+), 1 deletion(-) - -diff --git a/ovn/lib/expr.c b/ovn/lib/expr.c -index e4c650f7c..c0871e1e8 100644 ---- a/ovn/lib/expr.c -+++ b/ovn/lib/expr.c -@@ -1499,7 +1499,7 @@ expr_symtab_add_string(struct shash *symtab, const char *name, - const struct mf_field *field = mf_from_id(id); - struct expr_symbol *symbol; - -- symbol = add_symbol(symtab, name, 0, prereqs, EXPR_L_NOMINAL, false, -+ symbol = add_symbol(symtab, name, 0, prereqs, EXPR_L_NOMINAL, true, - field->writable); - symbol->field = field; - return symbol; -diff --git a/tests/ovn.at b/tests/ovn.at -index 2361524ff..54aa19bb2 100644 ---- a/tests/ovn.at -+++ b/tests/ovn.at -@@ -573,6 +573,24 @@ ip,reg14=0x6 - ipv6,reg14=0x5 - ipv6,reg14=0x6 - ]) -+AT_CHECK([expr_to_flow 'inport == {"eth0", "eth1", "eth2"} && ip4 && tcp && tcp.dst == {500, 501}'], [0], [dnl -+tcp,reg14=0x5,tp_dst=500 -+tcp,reg14=0x5,tp_dst=501 -+tcp,reg14=0x6,tp_dst=500 -+tcp,reg14=0x6,tp_dst=501 -+]) -+AT_CHECK([expr_to_flow 'outport == {"eth0", "eth1", "eth2"} && ip4 && tcp && tcp.src == {400, 401} && tcp.dst == {500, 501}'], [0], [dnl -+conj_id=1,tcp,reg15=0x5 -+conj_id=2,tcp,reg15=0x6 -+tcp,reg15=0x5,tp_dst=500: conjunction(1, 0/2) -+tcp,reg15=0x5,tp_dst=501: conjunction(1, 0/2) -+tcp,reg15=0x5,tp_src=400: conjunction(1, 1/2) -+tcp,reg15=0x5,tp_src=401: conjunction(1, 1/2) -+tcp,reg15=0x6,tp_dst=500: conjunction(2, 0/2) -+tcp,reg15=0x6,tp_dst=501: conjunction(2, 0/2) -+tcp,reg15=0x6,tp_src=400: conjunction(2, 1/2) -+tcp,reg15=0x6,tp_src=401: conjunction(2, 1/2) -+]) - AT_CHECK([expr_to_flow 'inport == "eth0" && inport == "eth1"'], [0], [dnl - (no flows) - ]) -@@ -677,6 +695,14 @@ reg15=0x11 - reg15=0x12 - reg15=0x13 - ]) -+AT_CHECK([expr_to_flow 'outport == @pg1 && ip4.src == {10.0.0.4, 10.0.0.5}'], [0], [dnl -+ip,reg15=0x11,nw_src=10.0.0.4 -+ip,reg15=0x11,nw_src=10.0.0.5 -+ip,reg15=0x12,nw_src=10.0.0.4 -+ip,reg15=0x12,nw_src=10.0.0.5 -+ip,reg15=0x13,nw_src=10.0.0.4 -+ip,reg15=0x13,nw_src=10.0.0.5 -+]) - AT_CHECK([expr_to_flow 'outport == {@pg_empty}'], [0], [dnl - (no flows) - ]) --- -2.14.1 - - diff --git a/ovn-Prevent-erroneous-duplicate-IP-address-messages.patch b/ovn-Prevent-erroneous-duplicate-IP-address-messages.patch deleted file mode 100644 index 7bed821f7ceced16c3ed8ba3d10f60fd16bec52d..0000000000000000000000000000000000000000 --- a/ovn-Prevent-erroneous-duplicate-IP-address-messages.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 30227d3b6f82381c3bf0ffa6e988a0799c0682f4 Mon Sep 17 00:00:00 2001 -From: Mark Michelson -Date: Tue, 12 Nov 2019 11:59:31 -0500 -Subject: ovn: Prevent erroneous duplicate IP address messages. - -This is a backport to OVS 2.12 of OVN master commit 21c29d5b0c. - -When using dynamic address assignment for logical switches, OVN reserves -the first address in the subnet for the attached router port to use. - -In commit 488d153ee87841c042af05bc0eb8b5481aaa98cf, the IPAM code was -modified to add assigned router port addresses to IPAM. The use case for -this was when a switch was joined to multiple routers, and all router -addresses were dynamically assigned. - -However, that commit also made it so that when a router rightly claimed -the first address in the subnet, ovn-northd would issue a warning about -a duplicate IP address being set. This change fixes the issue by adding -a special case so that we don't add the router's IP address to IPAM if -it is the first address in the subnet. This prevents the warning message -from appearing. - -Signed-off-by: Mark Michelson -Acked-by: Numan Siddique -Acked-by: Han ZHou -Signed-off-by: Ben Pfaff ---- - ovn/northd/ovn-northd.c | 9 ++++++++- - 1 file changed, 8 insertions(+), 1 deletion(-) - -diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c -index 6c6de2afd..1c9164924 100644 ---- a/ovn/northd/ovn-northd.c -+++ b/ovn/northd/ovn-northd.c -@@ -1194,7 +1194,14 @@ ipam_add_port_addresses(struct ovn_datapath *od, struct ovn_port *op) - - for (size_t i = 0; i < lrp_networks.n_ipv4_addrs; i++) { - uint32_t ip = ntohl(lrp_networks.ipv4_addrs[i].addr); -- ipam_insert_ip(op->peer->od, ip); -+ /* If the router has the first IP address of the subnet, don't add -+ * it to IPAM. We already added this when we initialized IPAM for -+ * the datapath. This will just result in an erroneous message -+ * about a duplicate IP address. -+ */ -+ if (ip != op->peer->od->ipam_info.start_ipv4) { -+ ipam_insert_ip(op->peer->od, ip); -+ } - } - - destroy_lport_addresses(&lrp_networks); --- -2.14.1 - - diff --git a/ovn-controller-Add-missing-port-group-lflow-referenc.patch b/ovn-controller-Add-missing-port-group-lflow-referenc.patch deleted file mode 100644 index 8cecb09e70664a4e48b86e5ebb9ac9bc6373accb..0000000000000000000000000000000000000000 --- a/ovn-controller-Add-missing-port-group-lflow-referenc.patch +++ /dev/null @@ -1,234 +0,0 @@ -From fc7fcb604c863b8eafaa319658e11da6d31e3fb6 Mon Sep 17 00:00:00 2001 -From: Dumitru Ceara -Date: Tue, 3 Dec 2019 10:56:54 +0100 -Subject: ovn-controller: Add missing port group lflow references. - -The commit that adds incremental processing for port-group changes -doesn't store logical flow references for port groups. If a port group -is updated (e.g., a port is added) no logical flow recalculation will be -performed. - -To fix this, when parsing the flow expression also store the referenced -port groups and bind them to the logical flows that depend on them. If -the port group is updated then the logical flows referring them will -also be reinstalled. - -(cherry picked from ovn commit bbcac48d443e98cbe47d3941f7e192c9c3443cb5) - -Reported-by: Daniel Alvarez -Reported-at: https://bugzilla.redhat.com/1778164 -CC: Han Zhou -Fixes: 978f5e90af0a ("ovn-controller: Incremental processing for port-group changes.") -Tested-By: Daniel Alvarez -Signed-off-by: Dumitru Ceara -Signed-off-by: Han Zhou -Signed-off-by: Ben Pfaff ---- - include/ovn/expr.h | 4 +++- - ovn/controller/lflow.c | 9 ++++++++- - ovn/lib/actions.c | 4 ++-- - ovn/lib/expr.c | 24 +++++++++++++++++------- - ovn/utilities/ovn-trace.c | 2 +- - tests/test-ovn.c | 8 ++++---- - 6 files changed, 35 insertions(+), 16 deletions(-) - -diff --git a/include/ovn/expr.h b/include/ovn/expr.h -index 22f633e57..21bf51c22 100644 ---- a/include/ovn/expr.h -+++ b/include/ovn/expr.h -@@ -390,11 +390,13 @@ void expr_print(const struct expr *); - struct expr *expr_parse(struct lexer *, const struct shash *symtab, - const struct shash *addr_sets, - const struct shash *port_groups, -- struct sset *addr_sets_ref); -+ struct sset *addr_sets_ref, -+ struct sset *port_groups_ref); - struct expr *expr_parse_string(const char *, const struct shash *symtab, - const struct shash *addr_sets, - const struct shash *port_groups, - struct sset *addr_sets_ref, -+ struct sset *port_groups_ref, - char **errorp); - - struct expr *expr_clone(struct expr *); -diff --git a/ovn/controller/lflow.c b/ovn/controller/lflow.c -index dd72a5b46..047b4711c 100644 ---- a/ovn/controller/lflow.c -+++ b/ovn/controller/lflow.c -@@ -616,14 +616,21 @@ consider_logical_flow( - struct expr *expr; - - struct sset addr_sets_ref = SSET_INITIALIZER(&addr_sets_ref); -+ struct sset port_groups_ref = SSET_INITIALIZER(&port_groups_ref); - expr = expr_parse_string(lflow->match, &symtab, addr_sets, port_groups, -- &addr_sets_ref, &error); -+ &addr_sets_ref, &port_groups_ref, &error); - const char *addr_set_name; - SSET_FOR_EACH (addr_set_name, &addr_sets_ref) { - lflow_resource_add(lfrr, REF_TYPE_ADDRSET, addr_set_name, - &lflow->header_.uuid); - } -+ const char *port_group_name; -+ SSET_FOR_EACH (port_group_name, &port_groups_ref) { -+ lflow_resource_add(lfrr, REF_TYPE_PORTGROUP, port_group_name, -+ &lflow->header_.uuid); -+ } - sset_destroy(&addr_sets_ref); -+ sset_destroy(&port_groups_ref); - - if (!error) { - if (prereqs) { -diff --git a/ovn/lib/actions.c b/ovn/lib/actions.c -index 274297194..58e0006d9 100644 ---- a/ovn/lib/actions.c -+++ b/ovn/lib/actions.c -@@ -240,8 +240,8 @@ add_prerequisite(struct action_context *ctx, const char *prerequisite) - struct expr *expr; - char *error; - -- expr = expr_parse_string(prerequisite, ctx->pp->symtab, NULL, NULL, NULL, -- &error); -+ expr = expr_parse_string(prerequisite, ctx->pp->symtab, NULL, NULL, -+ NULL, NULL, &error); - ovs_assert(!error); - ctx->prereqs = expr_combine(EXPR_T_AND, ctx->prereqs, expr); - } -diff --git a/ovn/lib/expr.c b/ovn/lib/expr.c -index c0871e1e8..629187a5b 100644 ---- a/ovn/lib/expr.c -+++ b/ovn/lib/expr.c -@@ -467,7 +467,8 @@ struct expr_context { - const struct shash *symtab; /* Symbol table. */ - const struct shash *addr_sets; /* Address set table. */ - const struct shash *port_groups; /* Port group table. */ -- struct sset *addr_sets_ref; /* The set of address set referenced. */ -+ struct sset *addr_sets_ref; /* The set of address set referenced. */ -+ struct sset *port_groups_ref; /* The set of port groups referenced. */ - bool not; /* True inside odd number of NOT operators. */ - unsigned int paren_depth; /* Depth of nested parentheses. */ - }; -@@ -769,6 +770,10 @@ static bool - parse_port_group(struct expr_context *ctx, struct expr_constant_set *cs, - size_t *allocated_values) - { -+ if (ctx->port_groups_ref) { -+ sset_add(ctx->port_groups_ref, ctx->lexer->token.s); -+ } -+ - struct expr_constant_set *port_group - = (ctx->port_groups - ? shash_find_data(ctx->port_groups, ctx->lexer->token.s) -@@ -1283,13 +1288,15 @@ struct expr * - expr_parse(struct lexer *lexer, const struct shash *symtab, - const struct shash *addr_sets, - const struct shash *port_groups, -- struct sset *addr_sets_ref) -+ struct sset *addr_sets_ref, -+ struct sset *port_groups_ref) - { - struct expr_context ctx = { .lexer = lexer, - .symtab = symtab, - .addr_sets = addr_sets, - .port_groups = port_groups, -- .addr_sets_ref = addr_sets_ref }; -+ .addr_sets_ref = addr_sets_ref, -+ .port_groups_ref = port_groups_ref }; - return lexer->error ? NULL : expr_parse__(&ctx); - } - -@@ -1304,6 +1311,7 @@ expr_parse_string(const char *s, const struct shash *symtab, - const struct shash *addr_sets, - const struct shash *port_groups, - struct sset *addr_sets_ref, -+ struct sset *port_groups_ref, - char **errorp) - { - struct lexer lexer; -@@ -1311,7 +1319,7 @@ expr_parse_string(const char *s, const struct shash *symtab, - lexer_init(&lexer, s); - lexer_get(&lexer); - struct expr *expr = expr_parse(&lexer, symtab, addr_sets, port_groups, -- addr_sets_ref); -+ addr_sets_ref, port_groups_ref); - lexer_force_end(&lexer); - *errorp = lexer_steal_error(&lexer); - if (*errorp) { -@@ -1537,7 +1545,8 @@ expr_get_level(const struct expr *expr) - static enum expr_level - expr_parse_level(const char *s, const struct shash *symtab, char **errorp) - { -- struct expr *expr = expr_parse_string(s, symtab, NULL, NULL, NULL, errorp); -+ struct expr *expr = expr_parse_string(s, symtab, NULL, NULL, NULL, NULL, -+ errorp); - enum expr_level level = expr ? expr_get_level(expr) : EXPR_L_NOMINAL; - expr_destroy(expr); - return level; -@@ -1708,7 +1717,7 @@ parse_and_annotate(const char *s, const struct shash *symtab, - char *error; - struct expr *expr; - -- expr = expr_parse_string(s, symtab, NULL, NULL, NULL, &error); -+ expr = expr_parse_string(s, symtab, NULL, NULL, NULL, NULL, &error); - if (expr) { - expr = expr_annotate_(expr, symtab, nesting, &error); - } -@@ -3432,7 +3441,8 @@ expr_parse_microflow(const char *s, const struct shash *symtab, - lexer_init(&lexer, s); - lexer_get(&lexer); - -- struct expr *e = expr_parse(&lexer, symtab, addr_sets, port_groups, NULL); -+ struct expr *e = expr_parse(&lexer, symtab, addr_sets, port_groups, -+ NULL, NULL); - lexer_force_end(&lexer); - - if (e) { -diff --git a/ovn/utilities/ovn-trace.c b/ovn/utilities/ovn-trace.c -index b532b8eaf..9c27131be 100644 ---- a/ovn/utilities/ovn-trace.c -+++ b/ovn/utilities/ovn-trace.c -@@ -850,7 +850,7 @@ read_flows(void) - char *error; - struct expr *match; - match = expr_parse_string(sblf->match, &symtab, &address_sets, -- &port_groups, NULL, &error); -+ &port_groups, NULL, NULL, &error); - if (error) { - VLOG_WARN("%s: parsing expression failed (%s)", - sblf->match, error); -diff --git a/tests/test-ovn.c b/tests/test-ovn.c -index cf1bc5432..6b5e365f0 100644 ---- a/tests/test-ovn.c -+++ b/tests/test-ovn.c -@@ -289,7 +289,7 @@ test_parse_expr__(int steps) - char *error; - - expr = expr_parse_string(ds_cstr(&input), &symtab, &addr_sets, -- &port_groups, NULL, &error); -+ &port_groups, NULL, NULL, &error); - if (!error && steps > 0) { - expr = expr_annotate(expr, &symtab, &error); - } -@@ -413,8 +413,8 @@ test_evaluate_expr(struct ovs_cmdl_context *ctx) - while (!ds_get_test_line(&input, stdin)) { - struct expr *expr; - -- expr = expr_parse_string(ds_cstr(&input), &symtab, NULL, NULL, NULL, -- &error); -+ expr = expr_parse_string(ds_cstr(&input), &symtab, NULL, NULL, -+ NULL, NULL, &error); - if (!error) { - expr = expr_annotate(expr, &symtab, &error); - } -@@ -889,7 +889,7 @@ test_tree_shape_exhaustively(struct expr *expr, struct shash *symtab, - - char *error; - modified = expr_parse_string(ds_cstr(&s), symtab, NULL, -- NULL, NULL, &error); -+ NULL, NULL, NULL, &error); - if (error) { - fprintf(stderr, "%s fails to parse (%s)\n", - ds_cstr(&s), error); --- -2.14.1 - - diff --git a/ovs-ofctl-Free-leaked-minimatch.patch b/ovs-ofctl-Free-leaked-minimatch.patch deleted file mode 100644 index f8ac729c4a56a27f3a7c57a8cfa213b46afa382a..0000000000000000000000000000000000000000 --- a/ovs-ofctl-Free-leaked-minimatch.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 430c292030ffda57f122c282d3eb165a97412b91 Mon Sep 17 00:00:00 2001 -From: Yifeng Sun -Date: Wed, 11 Sep 2019 14:18:30 -0700 -Subject: ovs-ofctl: Free leaked minimatch - -Valgrind reported: - -1056: ofproto - bundle with multiple flow mods (OpenFlow 1.4) - -==19220== 160 bytes in 2 blocks are definitely lost in loss record 24 of 34 -==19220== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) -==19220== by 0x4979A4: xmalloc (util.c:138) -==19220== by 0x42407D: miniflow_alloc (flow.c:3340) -==19220== by 0x4296CF: minimatch_init (match.c:1758) -==19220== by 0x46273D: parse_ofp_str__ (ofp-flow.c:1759) -==19220== by 0x465B9E: parse_ofp_str (ofp-flow.c:1790) -==19220== by 0x465CE0: parse_ofp_flow_mod_str (ofp-flow.c:1817) -==19220== by 0x465DF6: parse_ofp_flow_mod_file (ofp-flow.c:1876) -==19220== by 0x410BA3: ofctl_flow_mod_file.isra.19 (ovs-ofctl.c:1773) -==19220== by 0x417933: ovs_cmdl_run_command__ (command-line.c:223) -==19220== by 0x406F68: main (ovs-ofctl.c:179) - -This patch fixes it. - -Acked-by: William Tu -Signed-off-by: Yifeng Sun -Signed-off-by: Ben Pfaff ---- - utilities/ovs-ofctl.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c -index 754629d3d..06289d296 100644 ---- a/utilities/ovs-ofctl.c -+++ b/utilities/ovs-ofctl.c -@@ -1724,6 +1724,7 @@ bundle_flow_mod__(const char *remote, struct ofputil_flow_mod *fms, - - ovs_list_push_back(&requests, &request->list_node); - free(CONST_CAST(struct ofpact *, fm->ofpacts)); -+ minimatch_destroy(&fm->match); - } - - bundle_transact(vconn, &requests, OFPBF_ORDERED | OFPBF_ATOMIC); --- -2.14.1 - - diff --git a/ovsdb-client-Free-ovsdb_schema.patch b/ovsdb-client-Free-ovsdb_schema.patch deleted file mode 100644 index 5a666da2e4977ac3da1aef2911b2d5c77a46ea85..0000000000000000000000000000000000000000 --- a/ovsdb-client-Free-ovsdb_schema.patch +++ /dev/null @@ -1,43 +0,0 @@ -From f66cb2ec1538330c69f94ea4af252868a3aeb8d4 Mon Sep 17 00:00:00 2001 -From: Yifeng Sun -Date: Wed, 11 Sep 2019 14:18:32 -0700 -Subject: ovsdb-client: Free ovsdb_schema - -Valgrind reported: - -1925: schema conversion online - standalone - -==10727== 689 (56 direct, 633 indirect) bytes in 1 blocks are definitely lost in loss record 64 of 66 -==10727== at 0x4C2FB55: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) -==10727== by 0x449D42: xcalloc (util.c:121) -==10727== by 0x40F45C: ovsdb_schema_create (ovsdb.c:41) -==10727== by 0x40F7F8: ovsdb_schema_from_json (ovsdb.c:217) -==10727== by 0x40FB4E: ovsdb_schema_from_file (ovsdb.c:101) -==10727== by 0x40B156: do_convert (ovsdb-client.c:1639) -==10727== by 0x4061C6: main (ovsdb-client.c:282) - -This patch fixes it. - -Acked-by: William Tu -Signed-off-by: Yifeng Sun -Signed-off-by: Ben Pfaff ---- - ovsdb/ovsdb-client.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/ovsdb/ovsdb-client.c b/ovsdb/ovsdb-client.c -index 9ae15e557..bfc90e6f7 100644 ---- a/ovsdb/ovsdb-client.c -+++ b/ovsdb/ovsdb-client.c -@@ -1654,6 +1654,7 @@ do_convert(struct jsonrpc *rpc, const char *database_ OVS_UNUSED, - ovsdb_schema_to_json(new_schema)), NULL); - check_txn(jsonrpc_transact_block(rpc, request, &reply), &reply); - jsonrpc_msg_destroy(reply); -+ ovsdb_schema_destroy(new_schema); - } - - static void --- -2.14.1 - - diff --git a/ovsdb-cluster.at-Wait-until-leader-is-elected-before.patch b/ovsdb-cluster.at-Wait-until-leader-is-elected-before.patch deleted file mode 100644 index 7006d37f0bdc4a77922b6198e7a17f97cd9bb1c2..0000000000000000000000000000000000000000 --- a/ovsdb-cluster.at-Wait-until-leader-is-elected-before.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 9f301dc92a45206edaeb9cf0f3a9d7e01c32499a Mon Sep 17 00:00:00 2001 -From: Han Zhou -Date: Tue, 3 Dec 2019 17:57:19 -0800 -Subject: ovsdb-cluster.at: Wait until leader is elected before DB compact. - -In test case "election timer change", before testing DB compact, -we had to insert some data. Otherwise, inserting data after DB -compact will cause busy loop as mentioned in the XXX comment. - -The root cause of the busy loop is still not clear, but the test -itself didn't wait until the leader election finish before initiating -DB compact. This patch adds the wait to make sure the test continue -after leader is elected so that the following tests are based on -a clean state. While this wait is added, the busy loop problem is -gone even without inserting the data, so the additional data insertion -is also removed by this patch. - -A separate patch will address the busy loop problem in the scenario: -1. Restart cluster -2. DB compact before the cluster is ready -3. Insert data - -Signed-off-by: Han Zhou -Signed-off-by: Ben Pfaff ---- - tests/ovsdb-cluster.at | 13 +++++-------- - 1 file changed, 5 insertions(+), 8 deletions(-) - -diff --git a/tests/ovsdb-cluster.at b/tests/ovsdb-cluster.at -index 70812a787..ef4ec205a 100644 ---- a/tests/ovsdb-cluster.at -+++ b/tests/ovsdb-cluster.at -@@ -233,17 +233,14 @@ done - OVS_WAIT_UNTIL([ovs-appctl -t "`pwd`"/s1 cluster/status $schema_name | grep "Election timer: 4000"]) - OVS_WAIT_UNTIL([ovs-appctl -t "`pwd`"/s2 cluster/status $schema_name | grep "Election timer: 4000"]) - -+# Wait until cluster is ready -+for i in `seq $n`; do -+ OVS_WAIT_WHILE([ovs-appctl -t "`pwd`"/s$i cluster/status $schema_name | grep "Leader: unknown"]) -+done -+ - # Latest timer should be restored after DB compact and restart. - # This is to test the install_snapshot RPC. - --# XXX: Insert data before compact, because otherwise transaction will trigger --# busy loop after compact. --# poll_loop|DBG|wakeup due to 0-ms timeout at ../ovsdb/trigger.c:164 (89% CPU usage) --AT_CHECK([ovsdb-client transact unix:s1.ovsdb '[["idltest", -- {"op": "insert", -- "table": "simple", -- "row": {"i": 1}}]]'], [0], [ignore], [ignore]) -- - # Compact online - for i in `seq $n`; do - AT_CHECK([ovs-appctl -t "`pwd`"/s$i ovsdb-server/compact]) --- -2.14.1 - - diff --git a/ovsdb-raft-Fix-election-timer-parsing-in-snapshot-RP.patch b/ovsdb-raft-Fix-election-timer-parsing-in-snapshot-RP.patch deleted file mode 100644 index 1b9e9810ca7b6b34f784b94168d375a958d62589..0000000000000000000000000000000000000000 --- a/ovsdb-raft-Fix-election-timer-parsing-in-snapshot-RP.patch +++ /dev/null @@ -1,133 +0,0 @@ -From 0f0cde9132141f2980a542e54dae02887972c162 Mon Sep 17 00:00:00 2001 -From: Han Zhou -Date: Wed, 13 Nov 2019 09:33:59 -0800 -Subject: ovsdb raft: Fix election timer parsing in snapshot RPC. - -Commit a76ba825 took care of saving and restoring election timer in -file header snapshot, but it didn't handle the parsing of election -timer in install_snapshot_request/reply RPC, which results in problems, -e.g. when election timer change log is compacted in snapshot and then a -new node join the cluster, the new node will use the default timer -instead of the new value. This patch fixed it by parsing election -timer in snapshot RPC. - -At the same time the patch updates the test case to cover the DB compact and -join senario. The test reveals another 2 problems related to clustered DB -compact, as commented in the test case's XXX, which need to be addressed -separately. - -Signed-off-by: Han Zhou -Signed-off-by: Ben Pfaff ---- - ovsdb/raft-rpc.c | 5 +++++ - ovsdb/raft.c | 2 +- - tests/ovsdb-cluster.at | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 55 insertions(+), 1 deletion(-) - -diff --git a/ovsdb/raft-rpc.c b/ovsdb/raft-rpc.c -index 56c07d487..18c83fe9c 100644 ---- a/ovsdb/raft-rpc.c -+++ b/ovsdb/raft-rpc.c -@@ -511,6 +511,7 @@ raft_install_snapshot_request_to_jsonrpc( - json_object_put(args, "last_servers", json_clone(rq->last_servers)); - json_object_put_format(args, "last_eid", - UUID_FMT, UUID_ARGS(&rq->last_eid)); -+ raft_put_uint64(args, "election_timer", rq->election_timer); - - json_object_put(args, "data", json_clone(rq->data)); - } -@@ -527,6 +528,9 @@ raft_install_snapshot_request_from_jsonrpc( - rq->last_index = raft_parse_required_uint64(p, "last_index"); - rq->last_term = raft_parse_required_uint64(p, "last_term"); - rq->last_eid = raft_parse_required_uuid(p, "last_eid"); -+ /* election_timer is optional in file header, but is always populated in -+ * install_snapshot_request. */ -+ rq->election_timer = raft_parse_required_uint64(p, "election_timer"); - - rq->data = json_nullable_clone( - ovsdb_parser_member(p, "data", OP_OBJECT | OP_ARRAY)); -@@ -541,6 +545,7 @@ raft_format_install_snapshot_request( - ds_put_format(s, " last_term=%"PRIu64, rq->last_term); - ds_put_format(s, " last_eid="UUID_FMT, UUID_ARGS(&rq->last_eid)); - ds_put_cstr(s, " last_servers="); -+ ds_put_format(s, " election_timer=%"PRIu64, rq->election_timer); - - struct hmap servers; - struct ovsdb_error *error = -diff --git a/ovsdb/raft.c b/ovsdb/raft.c -index a45c7f8ba..f354d50a5 100644 ---- a/ovsdb/raft.c -+++ b/ovsdb/raft.c -@@ -3257,7 +3257,7 @@ raft_send_install_snapshot_request(struct raft *raft, - .last_servers = raft->snap.servers, - .last_eid = raft->snap.eid, - .data = raft->snap.data, -- .election_timer = raft->election_timer, -+ .election_timer = raft->election_timer, /* use latest value */ - } - }; - raft_send(raft, &rpc); -diff --git a/tests/ovsdb-cluster.at b/tests/ovsdb-cluster.at -index de4295a7e..70812a787 100644 ---- a/tests/ovsdb-cluster.at -+++ b/tests/ovsdb-cluster.at -@@ -233,6 +233,55 @@ done - OVS_WAIT_UNTIL([ovs-appctl -t "`pwd`"/s1 cluster/status $schema_name | grep "Election timer: 4000"]) - OVS_WAIT_UNTIL([ovs-appctl -t "`pwd`"/s2 cluster/status $schema_name | grep "Election timer: 4000"]) - -+# Latest timer should be restored after DB compact and restart. -+# This is to test the install_snapshot RPC. -+ -+# XXX: Insert data before compact, because otherwise transaction will trigger -+# busy loop after compact. -+# poll_loop|DBG|wakeup due to 0-ms timeout at ../ovsdb/trigger.c:164 (89% CPU usage) -+AT_CHECK([ovsdb-client transact unix:s1.ovsdb '[["idltest", -+ {"op": "insert", -+ "table": "simple", -+ "row": {"i": 1}}]]'], [0], [ignore], [ignore]) -+ -+# Compact online -+for i in `seq $n`; do -+ AT_CHECK([ovs-appctl -t "`pwd`"/s$i ovsdb-server/compact]) -+done -+ -+# XXX: Insert data after compact, because otherwise vote will fail after -+# cluster restart after compact. There will be error logs like: -+# raft|ERR|internal error: deferred vote_request message completed but not ready to send because message index 9 is past last synced index 0: s2 vote_request: term=6 last_log_index=9 last_log_term=4 -+AT_CHECK([ovsdb-client transact unix:s1.ovsdb '[["idltest", -+ {"op": "insert", -+ "table": "simple", -+ "row": {"i": 1}}]]'], [0], [ignore], [ignore]) -+ -+for i in `seq $n`; do -+ printf "\ns$i: stopping\n" -+ OVS_APP_EXIT_AND_WAIT_BY_TARGET([`pwd`/s$i], [s$i.pid]) -+done -+for i in `seq $n`; do -+ AT_CHECK([ovsdb-server -v -vconsole:off -vsyslog:off --detach --no-chdir --log-file=s$i.log --pidfile=s$i.pid --unixctl=s$i --remote=punix:s$i.ovsdb s$i.db]) -+done -+for i in `seq $n`; do -+ OVS_WAIT_UNTIL([ovs-appctl -t "`pwd`"/s$i cluster/status $schema_name | grep "Election timer: 4000"]) -+done -+ -+# Wait until cluster is ready -+for i in `seq $n`; do -+ OVS_WAIT_WHILE([ovs-appctl -t "`pwd`"/s$i cluster/status $schema_name | grep "Leader: unknown"]) -+done -+ -+# Newly joined member should use latest timer value -+AT_CHECK([ovsdb-tool join-cluster s4.db $schema_name unix:s4.raft unix:s1.raft]) -+AT_CHECK([ovsdb-server -v -vconsole:off -vsyslog:off --detach --no-chdir --log-file=s4.log --pidfile=s4.pid --unixctl=s4 --remote=punix:s4.ovsdb s4.db]) -+OVS_WAIT_UNTIL([ovs-appctl -t "`pwd`"/s4 cluster/status $schema_name | grep "Election timer: 4000"]) -+# for i in `seq 10`; do -+# ovs-appctl -t "`pwd`"/s4 cluster/status $schema_name -+# sleep 1 -+# done -+ - AT_CLEANUP - - --- -2.14.1 - - diff --git a/ovsdb-raft-Fix-the-problem-when-cluster-restarted-af.patch b/ovsdb-raft-Fix-the-problem-when-cluster-restarted-af.patch deleted file mode 100644 index 39827e472dfc12d7da93cef9914c2f8ace5f6d46..0000000000000000000000000000000000000000 --- a/ovsdb-raft-Fix-the-problem-when-cluster-restarted-af.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 62b3f430c29799ee4ef09b058105883939e06d37 Mon Sep 17 00:00:00 2001 -From: Han Zhou -Date: Tue, 3 Dec 2019 17:57:20 -0800 -Subject: ovsdb raft: Fix the problem when cluster restarted after DB compaction. - -Cluster doesn't work after all nodes restarted after DB compaction, -unless there is any transaction after DB compaction before the restart. - -Error log is like: -raft|ERR|internal error: deferred vote_request message completed but not ready -to send because message index 9 is past last synced index 0: s2 vote_request: -term=6 last_log_index=9 last_log_term=4 - -The root cause is that the log_synced member is not initialized when -reading the raft header. This patch fixes it and remove the XXX -from the test case. - -Signed-off-by: Han Zhou -Signed-off-by: Ben Pfaff ---- - ovsdb/raft.c | 2 +- - tests/ovsdb-cluster.at | 8 -------- - 2 files changed, 1 insertion(+), 9 deletions(-) - -diff --git a/ovsdb/raft.c b/ovsdb/raft.c -index f354d50a5..4789bc4f2 100644 ---- a/ovsdb/raft.c -+++ b/ovsdb/raft.c -@@ -849,7 +849,7 @@ raft_read_header(struct raft *raft) - } else { - raft_entry_clone(&raft->snap, &h.snap); - raft->log_start = raft->log_end = h.snap_index + 1; -- raft->commit_index = h.snap_index; -+ raft->log_synced = raft->commit_index = h.snap_index; - raft->last_applied = h.snap_index - 1; - } - -diff --git a/tests/ovsdb-cluster.at b/tests/ovsdb-cluster.at -index ef4ec205a..15f821be6 100644 ---- a/tests/ovsdb-cluster.at -+++ b/tests/ovsdb-cluster.at -@@ -246,14 +246,6 @@ for i in `seq $n`; do - AT_CHECK([ovs-appctl -t "`pwd`"/s$i ovsdb-server/compact]) - done - --# XXX: Insert data after compact, because otherwise vote will fail after --# cluster restart after compact. There will be error logs like: --# raft|ERR|internal error: deferred vote_request message completed but not ready to send because message index 9 is past last synced index 0: s2 vote_request: term=6 last_log_index=9 last_log_term=4 --AT_CHECK([ovsdb-client transact unix:s1.ovsdb '[["idltest", -- {"op": "insert", -- "table": "simple", -- "row": {"i": 1}}]]'], [0], [ignore], [ignore]) -- - for i in `seq $n`; do - printf "\ns$i: stopping\n" - OVS_APP_EXIT_AND_WAIT_BY_TARGET([`pwd`/s$i], [s$i.pid]) --- -2.14.1 - - diff --git a/ovsdb-server-Don-t-drop-all-connections-on-read-writ.patch b/ovsdb-server-Don-t-drop-all-connections-on-read-writ.patch deleted file mode 100644 index 372e81a8364586004a144599f2f5da5915c266d5..0000000000000000000000000000000000000000 --- a/ovsdb-server-Don-t-drop-all-connections-on-read-writ.patch +++ /dev/null @@ -1,92 +0,0 @@ -From 8190df660ca6e8f58a579323bd5503c9357c9f21 Mon Sep 17 00:00:00 2001 -From: Numan Siddique -Date: Mon, 14 Oct 2019 20:50:02 +0530 -Subject: ovsdb-server: Don't drop all connections on read/write status change. - -The commit [1] force drops all connections when the db read/write status changes. -Prior to the commit [1], when there was read/write status change, the existing -jsonrpc sessions with 'db_change_aware' set to true, were not updated with the -changed 'read_only' value. If the db status was changed to 'standby', the existing -clients could still write to the db. - -In the case of pacemaker OVN HA, OVN OCF script 'start' action starts the -ovsdb-servers in read-only state and later, it sets to read-write in the -'promote' action. We have observed that if some ovn-controllers connect to -the SB ovsdb-server (in read-only state) just before the 'promote' action, -the connection is not reset all the times and these ovn-controllers remain connected -to the SB ovsdb-server in read-only state all the time. Even though -the commit [1] calls 'ovsdb_jsonrpc_server_reconnect()' with 'forced' flag -set to true when the db read/write status changes, somehow the FSM misses resetting -the connections of these ovn-controllers. - -I think this needs to be addressed in the FSM. This patch doesn't address -this FSM issue. Instead it changes the behavior of 'ovsdb_jsonrpc_server_set_read_only()' -by setting the 'read_only' flag of all the jsonrpc sessions instead of forcefully -resetting the connection. - -I think there is no need to reset the connection. In large scale production -deployements with OVN, this results in unnecessary waste of CPU cycles as ovn-controllers -will have to connect twice - once during 'start' action and again during 'promote'. - -[1] - 2a9679e3b2c6("ovsdb-server: drop all connections on read/write status change") - -Acked-by: Dumitru Ceara -Signed-off-by: Numan Siddique -Signed-off-by: Ben Pfaff ---- - ovsdb/jsonrpc-server.c | 24 ++++++++++++++++++++---- - 1 file changed, 20 insertions(+), 4 deletions(-) - -diff --git a/ovsdb/jsonrpc-server.c b/ovsdb/jsonrpc-server.c -index ddbbc2e94..4e2dfc3d7 100644 ---- a/ovsdb/jsonrpc-server.c -+++ b/ovsdb/jsonrpc-server.c -@@ -80,6 +80,8 @@ static void ovsdb_jsonrpc_session_unlock_all(struct ovsdb_jsonrpc_session *); - static void ovsdb_jsonrpc_session_unlock__(struct ovsdb_lock_waiter *); - static void ovsdb_jsonrpc_session_send(struct ovsdb_jsonrpc_session *, - struct jsonrpc_msg *); -+static void ovsdb_jsonrpc_session_set_readonly_all( -+ struct ovsdb_jsonrpc_remote *remote, bool read_only); - - /* Triggers. */ - static void ovsdb_jsonrpc_trigger_create(struct ovsdb_jsonrpc_session *, -@@ -365,10 +367,13 @@ ovsdb_jsonrpc_server_set_read_only(struct ovsdb_jsonrpc_server *svr, - { - if (svr->read_only != read_only) { - svr->read_only = read_only; -- ovsdb_jsonrpc_server_reconnect(svr, true, -- xstrdup(read_only -- ? "making server read-only" -- : "making server read/write")); -+ -+ struct shash_node *node; -+ SHASH_FOR_EACH (node, &svr->remotes) { -+ struct ovsdb_jsonrpc_remote *remote = node->data; -+ -+ ovsdb_jsonrpc_session_set_readonly_all(remote, read_only); -+ } - } - } - -@@ -670,6 +675,17 @@ ovsdb_jsonrpc_session_reconnect_all(struct ovsdb_jsonrpc_remote *remote, - } - } - -+static void -+ovsdb_jsonrpc_session_set_readonly_all(struct ovsdb_jsonrpc_remote *remote, -+ bool read_only) -+{ -+ struct ovsdb_jsonrpc_session *s; -+ -+ LIST_FOR_EACH (s, node, &remote->sessions) { -+ s->read_only = read_only; -+ } -+} -+ - /* Sets the options for all of the JSON-RPC sessions managed by 'remote' to - * 'options'. - * --- -2.14.1 - - diff --git a/ovsdb-server-fix-memory-leak-while-converting-databa.patch b/ovsdb-server-fix-memory-leak-while-converting-databa.patch deleted file mode 100644 index 18a4802ab29edb783955f1216530ac58c670cf3a..0000000000000000000000000000000000000000 --- a/ovsdb-server-fix-memory-leak-while-converting-databa.patch +++ /dev/null @@ -1,61 +0,0 @@ -From c70272a165b018ac6808fe27bba0b461ed2894b5 Mon Sep 17 00:00:00 2001 -From: Damijan Skvarc -Date: Fri, 25 Oct 2019 14:22:58 +0200 -Subject: ovsdb-server: fix memory leak while converting database - -Memory leak happens while converting existing database into new -database according to the specified schema (ovsdb-client convert -new-schema). Memory leak was detected by valgrind while executing -functional test "schema conversion online - clustered" - -==16202== 96 bytes in 6 blocks are definitely lost in loss record 326 of 399 -==16202== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) -==16202== by 0x44A5D4: xmalloc (util.c:138) -==16202== by 0x4377A6: alloc_default_atoms (ovsdb-data.c:315) -==16202== by 0x437F18: ovsdb_datum_init_default (ovsdb-data.c:918) -==16202== by 0x413D82: ovsdb_row_create (row.c:59) -==16202== by 0x40AA53: ovsdb_convert_table (file.c:220) -==16202== by 0x40AA53: ovsdb_convert (file.c:275) -==16202== by 0x416BE1: ovsdb_trigger_try (trigger.c:255) -==16202== by 0x40D29E: ovsdb_jsonrpc_trigger_create (jsonrpc-server.c:1119) -==16202== by 0x40D29E: ovsdb_jsonrpc_session_got_request (jsonrpc-server.c:986) -==16202== by 0x40D29E: ovsdb_jsonrpc_session_run (jsonrpc-server.c:556) -==16202== by 0x40D29E: ovsdb_jsonrpc_session_run_all (jsonrpc-server.c:586) -==16202== by 0x40D29E: ovsdb_jsonrpc_server_run (jsonrpc-server.c:401) -==16202== by 0x40682E: main_loop (ovsdb-server.c:209) -==16202== by 0x40682E: main (ovsdb-server.c:460) - -The problem was in ovsdb_datum_convert() function, which overrides -pointers to datum memory allocated in ovsdb_row_create() function. -Fix was done by freeing this memory before ovsdb_datum_convert() -is called. - -Signed-off-by: Damijan Skvarc -Signed-off-by: Ben Pfaff ---- - ovsdb/file.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/ovsdb/file.c b/ovsdb/file.c -index 8d16b097b..0af077fce 100644 ---- a/ovsdb/file.c -+++ b/ovsdb/file.c -@@ -235,10 +235,14 @@ ovsdb_convert_table(struct ovsdb_txn *txn, - continue; - } - -+ ovsdb_datum_destroy(&dst_row->fields[dst_column->index], -+ &dst_column->type); -+ - struct ovsdb_error *error = ovsdb_datum_convert( - &dst_row->fields[dst_column->index], &dst_column->type, - &src_row->fields[src_column->index], &src_column->type); - if (error) { -+ ovsdb_datum_init_empty(&dst_row->fields[dst_column->index]); - ovsdb_row_destroy(dst_row); - return error; - } --- -2.14.1 - - diff --git a/ovsdb-server-fix-memory-leak-while-deleting-zone.patch b/ovsdb-server-fix-memory-leak-while-deleting-zone.patch deleted file mode 100644 index dc3c231262c83f03ffc9b64668223ca8e0e6eb87..0000000000000000000000000000000000000000 --- a/ovsdb-server-fix-memory-leak-while-deleting-zone.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 28eb1e4336bb916437d57000c874a4f55ec229d9 Mon Sep 17 00:00:00 2001 -From: Damijan Skvarc -Date: Tue, 12 Nov 2019 12:32:35 +0100 -Subject: ovsdb-server: fix memory leak while deleting zone - -memory leak was detected by valgrind during execution -of "database commands -- positive checks" test. - -leaked memory was allocated in ovsdb_execute_mutate() function -while parsing mutations from the apparent json entity: - -==19563== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) -==19563== by 0x4652D0: xmalloc (util.c:138) -==19563== by 0x46539E: xmemdup0 (util.c:168) -==19563== by 0x4653F7: xstrdup (util.c:177) -==19563== by 0x450379: ovsdb_base_type_clone (ovsdb-types.c:208) -==19563== by 0x450F8D: ovsdb_type_clone (ovsdb-types.c:550) -==19563== by 0x428C3F: ovsdb_mutation_from_json (mutation.c:108) -==19563== by 0x428F6B: ovsdb_mutation_set_from_json (mutation.c:187) -==19563== by 0x42578D: ovsdb_execute_mutate (execution.c:573) -==19563== by 0x4246B0: ovsdb_execute_compose (execution.c:171) -==19563== by 0x41CDE5: ovsdb_trigger_try (trigger.c:204) -==19563== by 0x41C8DF: ovsdb_trigger_init (trigger.c:61) -==19563== by 0x40E93C: ovsdb_jsonrpc_trigger_create (jsonrpc-server.c:1135) -==19563== by 0x40E20C: ovsdb_jsonrpc_session_got_request (jsonrpc-server.c:1002) -==19563== by 0x40D1C2: ovsdb_jsonrpc_session_run (jsonrpc-server.c:561) -==19563== by 0x40D31E: ovsdb_jsonrpc_session_run_all (jsonrpc-server.c:591) -==19563== by 0x40CD6E: ovsdb_jsonrpc_server_run (jsonrpc-server.c:406) -==19563== by 0x40627E: main_loop (ovsdb-server.c:209) -==19563== by 0x406E66: main (ovsdb-server.c:460) - -This memory is usually freed at the end of ovsdb_execute_mutate() -however in the aforementioned test case this does not happen. Namely -in case of delete mutator and in case of error while calling ovsdb_datum_from_json() -apparent mutation was marked as invalid, what prevents freeing problematic memory. - -Memory leak can be reproduced quickly with the following command sequence: -ovs-vsctl --no-wait -vreconnect:emer add-zone-tp netdev zone=1 icmp_first=1 icmp_reply=2 -ovs-vsctl --no-wait -vreconnect:emer del-zone-tp netdev zone=1 - -Signed-off-by: Damijan Skvarc -Signed-off-by: Ben Pfaff ---- - ovsdb/mutation.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/ovsdb/mutation.c b/ovsdb/mutation.c -index cd20bdb7c..56edc5f00 100644 ---- a/ovsdb/mutation.c -+++ b/ovsdb/mutation.c -@@ -147,6 +147,8 @@ ovsdb_mutation_from_json(const struct ovsdb_table_schema *ts, - if (error && ovsdb_type_is_map(&m->type) - && m->mutator == OVSDB_M_DELETE) { - ovsdb_error_destroy(error); -+ ovsdb_base_type_destroy(&m->type.value); -+ m->type.value.enum_ = NULL; - m->type.value.type = OVSDB_TYPE_VOID; - error = ovsdb_datum_from_json(&m->arg, &m->type, array->elems[2], - symtab); --- -2.14.1 - - diff --git a/raft-Free-leaked-json-data.patch b/raft-Free-leaked-json-data.patch deleted file mode 100644 index 4b00040ef56c8c2c77fcba6781b3dc85576c1bb0..0000000000000000000000000000000000000000 --- a/raft-Free-leaked-json-data.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 71d0bf666b826da8441c3f1bd3f49ff1917423b3 Mon Sep 17 00:00:00 2001 -From: Yifeng Sun -Date: Wed, 11 Sep 2019 14:18:27 -0700 -Subject: raft: Free leaked json data - -Valgrind reported: - -1924: compacting online - cluster - -==29312== 2,886 (240 direct, 2,646 indirect) bytes in 6 blocks are definitely lost in loss record 406 of 413 -==29312== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) -==29312== by 0x44A5F4: xmalloc (util.c:138) -==29312== by 0x4308EA: json_create (json.c:1451) -==29312== by 0x4308EA: json_object_create (json.c:254) -==29312== by 0x430ED0: json_parser_push_object (json.c:1273) -==29312== by 0x430ED0: json_parser_input (json.c:1371) -==29312== by 0x431CF1: json_lex_input (json.c:991) -==29312== by 0x43233B: json_parser_feed (json.c:1149) -==29312== by 0x41D87F: parse_body.isra.0 (log.c:411) -==29312== by 0x41E141: ovsdb_log_read (log.c:476) -==29312== by 0x42646D: raft_read_log (raft.c:866) -==29312== by 0x42646D: raft_open (raft.c:951) -==29312== by 0x4151AF: ovsdb_storage_open__ (storage.c:81) -==29312== by 0x408FFC: open_db (ovsdb-server.c:642) -==29312== by 0x40657F: main (ovsdb-server.c:358) - -This patch fixes it. - -Acked-by: William Tu -Signed-off-by: Yifeng Sun -Signed-off-by: Ben Pfaff ---- - ovsdb/raft.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/ovsdb/raft.c b/ovsdb/raft.c -index 9eabe2cfe..a45c7f8ba 100644 ---- a/ovsdb/raft.c -+++ b/ovsdb/raft.c -@@ -883,6 +883,7 @@ raft_read_log(struct raft *raft) - error = raft_apply_record(raft, i, &r); - raft_record_uninit(&r); - } -+ json_destroy(json); - if (error) { - return ovsdb_wrap_error(error, "error reading record %llu from " - "%s log", i, raft->name); --- -2.14.1 - - diff --git a/rhel-Fix-ovs-kmod-manage.sh-that-may-create-invalid-.patch b/rhel-Fix-ovs-kmod-manage.sh-that-may-create-invalid-.patch deleted file mode 100644 index 06992fa096eeb1af5b5b17cf6dcb2f9519aceb9f..0000000000000000000000000000000000000000 --- a/rhel-Fix-ovs-kmod-manage.sh-that-may-create-invalid-.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 7fbfaf9c5ca7a722bf1887afa6f2a7a45af61b7c Mon Sep 17 00:00:00 2001 -From: Yifeng Sun -Date: Mon, 18 Nov 2019 12:06:26 -0800 -Subject:rhel: Fix ovs-kmod-manage.sh that may create invalid soft links - -Current code iterates every kernel under '/lib/modules' for a matched -version. As a result, this script may create invalid soft links if the -matched kernel doesn't have openvswitch-kmod RPM installed. - -This patch fixes it. - -VMWare-BZ: #2257534 - -Fixes: c3570519 ("rhel: add 4.4 kernel in kmod build with mulitple versions, fedora") -Signed-off-by: Yifeng Sun -Acked-by: Yi-Hung Wei -Signed-off-by: William Tu ---- - rhel/usr_share_openvswitch_scripts_ovs-kmod-manage.sh | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/rhel/usr_share_openvswitch_scripts_ovs-kmod-manage.sh b/rhel/usr_share_openvswitch_scripts_ovs-kmod-manage.sh -index 693fb0b74..8464a6fbc 100644 ---- a/rhel/usr_share_openvswitch_scripts_ovs-kmod-manage.sh -+++ b/rhel/usr_share_openvswitch_scripts_ovs-kmod-manage.sh -@@ -151,7 +151,7 @@ fi - #$kmod_high_ver" - - found_match=false --for kname in `ls -d /lib/modules/*` -+for kname in $kversion; - do - IFS='.\|-' read -r -a pkg_ver_nums <<<"${kname}" - pkg_ver=${pkg_ver_nums[$ver_offset]} -@@ -178,14 +178,14 @@ if [ "$found_match" = "false" ]; then - exit 1 - fi - --if [ "$requested_kernel" != "/lib/modules/$current_kernel" ]; then -+if [ "$requested_kernel" != "$current_kernel" ]; then - if [ ! -d /lib/modules/$current_kernel/weak-updates/openvswitch ]; then - mkdir -p /lib/modules/$current_kernel/weak-updates - mkdir -p /lib/modules/$current_kernel/weak-updates/openvswitch - fi - for m in openvswitch vport-gre vport-stt vport-geneve \ - vport-lisp vport-vxlan; do -- ln -f -s $requested_kernel/extra/openvswitch/$m.ko \ -+ ln -f -s /lib/modules/$requested_kernel/extra/openvswitch/$m.ko \ - /lib/modules/$current_kernel/weak-updates/openvswitch/$m.ko - done - else --- -2.14.1 - - diff --git a/rhel-Support-RHEL-7.8-kernel-module-rpm-build.patch b/rhel-Support-RHEL-7.8-kernel-module-rpm-build.patch deleted file mode 100644 index bbd99cac1e42e36180bb6e7bfcb8d2dbca24a128..0000000000000000000000000000000000000000 --- a/rhel-Support-RHEL-7.8-kernel-module-rpm-build.patch +++ /dev/null @@ -1,78 +0,0 @@ -From b1cbbabb7154478ea938494cfe811586c54df70e Mon Sep 17 00:00:00 2001 -From: Yi-Hung Wei -Date: Wed, 4 Dec 2019 17:10:27 -0800 -Subject: rhel: Support RHEL 7.8 kernel module rpm build - -This patch supports RHEL 7.8 kernel module rpm package building. - -$ make rpm-fedora-kmod \ -RPMBUILD_OPT='-D "kversion 3.10.0-1101.el7.x86_64"' - -Signed-off-by: Yi-Hung Wei -Reviewed-by: Yifeng Sun -Signed-off-by: William Tu ---- - rhel/openvswitch-kmod-fedora.spec.in | 14 +++++++++----- - rhel/usr_share_openvswitch_scripts_ovs-kmod-manage.sh | 6 ++++++ - 2 files changed, 15 insertions(+), 5 deletions(-) - -diff --git a/rhel/openvswitch-kmod-fedora.spec.in b/rhel/openvswitch-kmod-fedora.spec.in -index fbb836699..c94f2f535 100644 ---- a/rhel/openvswitch-kmod-fedora.spec.in -+++ b/rhel/openvswitch-kmod-fedora.spec.in -@@ -12,9 +12,12 @@ - # Use the kversion macro such as - # RPMBUILD_OPT='-D "kversion 3.10.0-693.1.1.el7.x86_64 3.10.0-693.17.1.el7.x86_64"' - # to build package for mulitple kernel versions in the same package --# This only works for kernel 3.10.0 major revision 1062 (RHEL 7.7), --# major revision 957 (RHEL 7.6), major revision 693 (RHEL 7.4) and --# major revision 327 (RHEL 7.2). -+# This only works for the following kernels. -+# - 3.10.0 major revision 327 (RHEL 7.2) -+# - 3.10.0 major revision 693 (RHEL 7.4) -+# - 3.10.0 major revision 957 (RHEL 7.6) -+# - 3.10.0 major revision 1062 (RHEL 7.7) -+# - 3.10.0 major revision 1101 (RHEL 7.8) - # By default, build against the current running kernel version - #%define kernel 3.1.5-1.fc16.x86_64 - #define kernel %{kernel_source} -@@ -93,8 +96,9 @@ if grep -qs "suse" /etc/os-release; then - fi - elif [ "$mainline_major" = "3" ] && [ "$mainline_minor" = "10" ] && - { [ "$major_rev" = "327" ] || [ "$major_rev" = "693" ] || \ -- [ "$major_rev" = "957" ] || [ "$major_rev" == "1062" ]; }; then -- # For RHEL 7.2, 7.4, 7.6 and 7.7 -+ [ "$major_rev" = "957" ] || [ "$major_rev" == "1062" ] || \ -+ [ "$major_rev" = "1101" ]; }; then -+ # For RHEL 7.2, 7.4, 7.6, 7.7, and 7.8 - if [ -x "%{_datadir}/openvswitch/scripts/ovs-kmod-manage.sh" ]; then - %{_datadir}/openvswitch/scripts/ovs-kmod-manage.sh - fi -diff --git a/rhel/usr_share_openvswitch_scripts_ovs-kmod-manage.sh b/rhel/usr_share_openvswitch_scripts_ovs-kmod-manage.sh -index a252b391e..a9b5cdd81 100644 ---- a/rhel/usr_share_openvswitch_scripts_ovs-kmod-manage.sh -+++ b/rhel/usr_share_openvswitch_scripts_ovs-kmod-manage.sh -@@ -19,6 +19,7 @@ - # - 3.10.0 major revision 693 (RHEL 7.4) - # - 3.10.0 major revision 957 (RHEL 7.6) - # - 3.10.0 major revision 1062 (RHEL 7.7) -+# - 3.10.0 major revision 1101 (RHEL 7.8) - # - 4.4.x, x >= 73 (SLES 12 SP3) - # - 4.12.x, x >= 14 (SLES 12 SP4). - # It is packaged in the openvswitch kmod RPM and run in the post-install -@@ -106,6 +107,11 @@ if [ "$mainline_major" = "3" ] && [ "$mainline_minor" = "10" ]; then - comp_ver=10 - ver_offset=4 - installed_ver="$minor_rev" -+ elif [ "$major_rev" = "1101" ]; then -+# echo "rhel78" -+ comp_ver=10 -+ ver_offset=4 -+ installed_ver="$minor_rev" - fi - elif [ "$mainline_major" = "4" ] && [ "$mainline_minor" = "4" ]; then - if [ "$mainline_patch" -ge "73" ]; then --- -2.14.1 - - diff --git a/rhel-Support-RHEL7.7-build-and-packaging.patch b/rhel-Support-RHEL7.7-build-and-packaging.patch deleted file mode 100644 index 6b7af9c14c57baa94171e8fbf8f469698e5e4ba1..0000000000000000000000000000000000000000 --- a/rhel-Support-RHEL7.7-build-and-packaging.patch +++ /dev/null @@ -1,90 +0,0 @@ -From 817fae6b5482911db7610ab7cd5fbd5ad4d6ad36 Mon Sep 17 00:00:00 2001 -From: Yifeng Sun -Date: Fri, 11 Oct 2019 14:49:14 -0700 -Subject: rhel: Support RHEL7.7 build and packaging - -This patch provides essential fixes for OVS to support -RHEL7.7's new kernel. - -make rpm-fedora-kmod \ -RPMBUILD_OPT='-D "kversion 3.10.0-1062.1.2.el7.x86_64"' - -Tested-by: Greg Rose -Reviewed-by: Greg Rose -Signed-off-by: Yifeng Sun -Signed-off-by: Ben Pfaff ---- - rhel/openvswitch-kmod-fedora.spec.in | 9 +++++---- - rhel/usr_share_openvswitch_scripts_ovs-kmod-manage.sh | 14 ++++++++++---- - 2 files changed, 15 insertions(+), 8 deletions(-) - -diff --git a/rhel/openvswitch-kmod-fedora.spec.in b/rhel/openvswitch-kmod-fedora.spec.in -index b3588982e..fbb836699 100644 ---- a/rhel/openvswitch-kmod-fedora.spec.in -+++ b/rhel/openvswitch-kmod-fedora.spec.in -@@ -12,8 +12,9 @@ - # Use the kversion macro such as - # RPMBUILD_OPT='-D "kversion 3.10.0-693.1.1.el7.x86_64 3.10.0-693.17.1.el7.x86_64"' - # to build package for mulitple kernel versions in the same package --# This only works for kernel 3.10.0 major revision 957 (RHEL 7.6), --# major revision 693 (RHEL 7.4) and major revision 327 (RHEL 7.2). -+# This only works for kernel 3.10.0 major revision 1062 (RHEL 7.7), -+# major revision 957 (RHEL 7.6), major revision 693 (RHEL 7.4) and -+# major revision 327 (RHEL 7.2). - # By default, build against the current running kernel version - #%define kernel 3.1.5-1.fc16.x86_64 - #define kernel %{kernel_source} -@@ -92,8 +93,8 @@ if grep -qs "suse" /etc/os-release; then - fi - elif [ "$mainline_major" = "3" ] && [ "$mainline_minor" = "10" ] && - { [ "$major_rev" = "327" ] || [ "$major_rev" = "693" ] || \ -- [ "$major_rev" = "957" ]; }; then -- # For RHEL 7.2, 7.4 and 7.6 -+ [ "$major_rev" = "957" ] || [ "$major_rev" == "1062" ]; }; then -+ # For RHEL 7.2, 7.4, 7.6 and 7.7 - if [ -x "%{_datadir}/openvswitch/scripts/ovs-kmod-manage.sh" ]; then - %{_datadir}/openvswitch/scripts/ovs-kmod-manage.sh - fi -diff --git a/rhel/usr_share_openvswitch_scripts_ovs-kmod-manage.sh b/rhel/usr_share_openvswitch_scripts_ovs-kmod-manage.sh -index 8464a6fbc..a252b391e 100644 ---- a/rhel/usr_share_openvswitch_scripts_ovs-kmod-manage.sh -+++ b/rhel/usr_share_openvswitch_scripts_ovs-kmod-manage.sh -@@ -15,9 +15,10 @@ - # limitations under the License. - - # This script is intended to be used on the following kernels. --# - 3.10.0 major revision 327 (RHEL 7.2) --# - 3.10.0 major revision 693 (RHEL 7.4) --# - 3.10.0 major revision 957 (RHEL 7.6) -+# - 3.10.0 major revision 327 (RHEL 7.2) -+# - 3.10.0 major revision 693 (RHEL 7.4) -+# - 3.10.0 major revision 957 (RHEL 7.6) -+# - 3.10.0 major revision 1062 (RHEL 7.7) - # - 4.4.x, x >= 73 (SLES 12 SP3) - # - 4.12.x, x >= 14 (SLES 12 SP4). - # It is packaged in the openvswitch kmod RPM and run in the post-install -@@ -100,6 +101,11 @@ if [ "$mainline_major" = "3" ] && [ "$mainline_minor" = "10" ]; then - comp_ver=10 - ver_offset=4 - installed_ver="$minor_rev" -+ elif [ "$major_rev" = "1062" ]; then -+# echo "rhel77" -+ comp_ver=10 -+ ver_offset=4 -+ installed_ver="$minor_rev" - fi - elif [ "$mainline_major" = "4" ] && [ "$mainline_minor" = "4" ]; then - if [ "$mainline_patch" -ge "73" ]; then -@@ -111,7 +117,7 @@ elif [ "$mainline_major" = "4" ] && [ "$mainline_minor" = "4" ]; then - elif [ "$mainline_major" = "4" ] && [ "$mainline_minor" = "12" ]; then - if [ "$mainline_patch" -ge "14" ]; then - # echo "sles12sp4" -- comp_ver=14 -+ comp_ver=1 - ver_offset=2 - installed_ver="$mainline_patch" - fi --- -2.14.1 - - diff --git a/rhel-openvswitch-fedora.spec.in-Fix-output-redirect-.patch b/rhel-openvswitch-fedora.spec.in-Fix-output-redirect-.patch deleted file mode 100644 index 94a175f8650b82688fdb96c4a07f4bf0dba508ea..0000000000000000000000000000000000000000 --- a/rhel-openvswitch-fedora.spec.in-Fix-output-redirect-.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 479770e869295df0912da541062064b49a838ab1 Mon Sep 17 00:00:00 2001 -From: Roi Dayan -Date: Mon, 28 Oct 2019 10:37:44 +0200 -Subject: rhel: openvswitch-fedora.spec.in: Fix output redirect to null device - -Add missing slash. - -Fixes: 0447019df7c6 ("fedora-spec: added systemd post/postun/pre/preun sections") -Signed-off-by: Roi Dayan -Signed-off-by: Simon Horman ---- - rhel/openvswitch-fedora.spec.in | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/rhel/openvswitch-fedora.spec.in b/rhel/openvswitch-fedora.spec.in -index 9c752ff4e..aff357263 100644 ---- a/rhel/openvswitch-fedora.spec.in -+++ b/rhel/openvswitch-fedora.spec.in -@@ -396,7 +396,7 @@ fi - %else - # Package install, not upgrade - if [ $1 -eq 1 ]; then -- /bin/systemctl daemon-reload >dev/null || : -+ /bin/systemctl daemon-reload >/dev/null || : - fi - %endif - --- -2.14.1 - - diff --git a/sparse-Get-rid-of-obsolete-rte_flow-header.patch b/sparse-Get-rid-of-obsolete-rte_flow-header.patch deleted file mode 100644 index 58f6d909e16453d5bc937d032db52e14380e47d6..0000000000000000000000000000000000000000 --- a/sparse-Get-rid-of-obsolete-rte_flow-header.patch +++ /dev/null @@ -1,1559 +0,0 @@ -From be6d19b2f162df5341f144cd0970b6cea150b36a Mon Sep 17 00:00:00 2001 -From: David Marchand -Date: Thu, 3 Oct 2019 20:11:24 +0200 -Subject: sparse: Get rid of obsolete rte_flow header. - -This header had been copied to cope with issues on the dpdk side. -Now that the problems have been fixed [1], let's drop this file as it is -now out of sync with dpdk. - -1: https://git.dpdk.org/dpdk/commit/?id=fbb25a3878cc - -Signed-off-by: David Marchand -Signed-off-by: Ian Stokes ---- - include/sparse/automake.mk | 1 - - include/sparse/rte_flow.h | 1518 -------------------------------------------- - 2 files changed, 1519 deletions(-) - delete mode 100644 include/sparse/rte_flow.h - -diff --git a/include/sparse/automake.mk b/include/sparse/automake.mk -index f65c27255..8f3e12dce 100644 ---- a/include/sparse/automake.mk -+++ b/include/sparse/automake.mk -@@ -1,7 +1,6 @@ - noinst_HEADERS += \ - include/sparse/rte_byteorder.h \ - include/sparse/rte_esp.h \ -- include/sparse/rte_flow.h \ - include/sparse/rte_icmp.h \ - include/sparse/rte_ip.h \ - include/sparse/rte_sctp.h \ -diff --git a/include/sparse/rte_flow.h b/include/sparse/rte_flow.h -deleted file mode 100644 -index 02fa523b4..000000000 ---- a/include/sparse/rte_flow.h -+++ /dev/null -@@ -1,1518 +0,0 @@ --/*- -- * BSD LICENSE -- * -- * Copyright 2016 6WIND S.A. -- * Copyright 2016 Mellanox. -- * -- * Redistribution and use in source and binary forms, with or without -- * modification, are permitted provided that the following conditions -- * are met: -- * -- * * Redistributions of source code must retain the above copyright -- * notice, this list of conditions and the following disclaimer. -- * * Redistributions in binary form must reproduce the above copyright -- * notice, this list of conditions and the following disclaimer in -- * the documentation and/or other materials provided with the -- * distribution. -- * * Neither the name of 6WIND S.A. nor the names of its -- * contributors may be used to endorse or promote products derived -- * from this software without specific prior written permission. -- * -- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- */ -- --#ifndef __CHECKER__ --#error "Use this header only with sparse. It is not a correct implementation." --#endif -- --#ifndef RTE_FLOW_H_ --#define RTE_FLOW_H_ -- --/** -- * @file -- * RTE generic flow API -- * -- * This interface provides the ability to program packet matching and -- * associated actions in hardware through flow rules. -- */ -- --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include -- --#ifdef __cplusplus --extern "C" { --#endif -- --/** -- * Flow rule attributes. -- * -- * Priorities are set on two levels: per group and per rule within groups. -- * -- * Lower values denote higher priority, the highest priority for both levels -- * is 0, so that a rule with priority 0 in group 8 is always matched after a -- * rule with priority 8 in group 0. -- * -- * Although optional, applications are encouraged to group similar rules as -- * much as possible to fully take advantage of hardware capabilities -- * (e.g. optimized matching) and work around limitations (e.g. a single -- * pattern type possibly allowed in a given group). -- * -- * Group and priority levels are arbitrary and up to the application, they -- * do not need to be contiguous nor start from 0, however the maximum number -- * varies between devices and may be affected by existing flow rules. -- * -- * If a packet is matched by several rules of a given group for a given -- * priority level, the outcome is undefined. It can take any path, may be -- * duplicated or even cause unrecoverable errors. -- * -- * Note that support for more than a single group and priority level is not -- * guaranteed. -- * -- * Flow rules can apply to inbound and/or outbound traffic (ingress/egress). -- * -- * Several pattern items and actions are valid and can be used in both -- * directions. Those valid for only one direction are described as such. -- * -- * At least one direction must be specified. -- * -- * Specifying both directions at once for a given rule is not recommended -- * but may be valid in a few cases (e.g. shared counter). -- */ --struct rte_flow_attr { -- uint32_t group; /**< Priority group. */ -- uint32_t priority; /**< Priority level within group. */ -- uint32_t ingress:1; /**< Rule applies to ingress traffic. */ -- uint32_t egress:1; /**< Rule applies to egress traffic. */ -- uint32_t reserved:30; /**< Reserved, must be zero. */ --}; -- --/** -- * Matching pattern item types. -- * -- * Pattern items fall in two categories: -- * -- * - Matching protocol headers and packet data (ANY, RAW, ETH, VLAN, IPV4, -- * IPV6, ICMP, UDP, TCP, SCTP, VXLAN and so on), usually associated with a -- * specification structure. These must be stacked in the same order as the -- * protocol layers to match, starting from the lowest. -- * -- * - Matching meta-data or affecting pattern processing (END, VOID, INVERT, -- * PF, VF, PORT and so on), often without a specification structure. Since -- * they do not match packet contents, these can be specified anywhere -- * within item lists without affecting others. -- * -- * See the description of individual types for more information. Those -- * marked with [META] fall into the second category. -- */ --enum rte_flow_item_type { -- /** -- * [META] -- * -- * End marker for item lists. Prevents further processing of items, -- * thereby ending the pattern. -- * -- * No associated specification structure. -- */ -- RTE_FLOW_ITEM_TYPE_END, -- -- /** -- * [META] -- * -- * Used as a placeholder for convenience. It is ignored and simply -- * discarded by PMDs. -- * -- * No associated specification structure. -- */ -- RTE_FLOW_ITEM_TYPE_VOID, -- -- /** -- * [META] -- * -- * Inverted matching, i.e. process packets that do not match the -- * pattern. -- * -- * No associated specification structure. -- */ -- RTE_FLOW_ITEM_TYPE_INVERT, -- -- /** -- * Matches any protocol in place of the current layer, a single ANY -- * may also stand for several protocol layers. -- * -- * See struct rte_flow_item_any. -- */ -- RTE_FLOW_ITEM_TYPE_ANY, -- -- /** -- * [META] -- * -- * Matches packets addressed to the physical function of the device. -- * -- * If the underlying device function differs from the one that would -- * normally receive the matched traffic, specifying this item -- * prevents it from reaching that device unless the flow rule -- * contains a PF action. Packets are not duplicated between device -- * instances by default. -- * -- * No associated specification structure. -- */ -- RTE_FLOW_ITEM_TYPE_PF, -- -- /** -- * [META] -- * -- * Matches packets addressed to a virtual function ID of the device. -- * -- * If the underlying device function differs from the one that would -- * normally receive the matched traffic, specifying this item -- * prevents it from reaching that device unless the flow rule -- * contains a VF action. Packets are not duplicated between device -- * instances by default. -- * -- * See struct rte_flow_item_vf. -- */ -- RTE_FLOW_ITEM_TYPE_VF, -- -- /** -- * [META] -- * -- * Matches packets coming from the specified physical port of the -- * underlying device. -- * -- * The first PORT item overrides the physical port normally -- * associated with the specified DPDK input port (port_id). This -- * item can be provided several times to match additional physical -- * ports. -- * -- * See struct rte_flow_item_port. -- */ -- RTE_FLOW_ITEM_TYPE_PORT, -- -- /** -- * Matches a byte string of a given length at a given offset. -- * -- * See struct rte_flow_item_raw. -- */ -- RTE_FLOW_ITEM_TYPE_RAW, -- -- /** -- * Matches an Ethernet header. -- * -- * See struct rte_flow_item_eth. -- */ -- RTE_FLOW_ITEM_TYPE_ETH, -- -- /** -- * Matches an 802.1Q/ad VLAN tag. -- * -- * See struct rte_flow_item_vlan. -- */ -- RTE_FLOW_ITEM_TYPE_VLAN, -- -- /** -- * Matches an IPv4 header. -- * -- * See struct rte_flow_item_ipv4. -- */ -- RTE_FLOW_ITEM_TYPE_IPV4, -- -- /** -- * Matches an IPv6 header. -- * -- * See struct rte_flow_item_ipv6. -- */ -- RTE_FLOW_ITEM_TYPE_IPV6, -- -- /** -- * Matches an ICMP header. -- * -- * See struct rte_flow_item_icmp. -- */ -- RTE_FLOW_ITEM_TYPE_ICMP, -- -- /** -- * Matches a UDP header. -- * -- * See struct rte_flow_item_udp. -- */ -- RTE_FLOW_ITEM_TYPE_UDP, -- -- /** -- * Matches a TCP header. -- * -- * See struct rte_flow_item_tcp. -- */ -- RTE_FLOW_ITEM_TYPE_TCP, -- -- /** -- * Matches a SCTP header. -- * -- * See struct rte_flow_item_sctp. -- */ -- RTE_FLOW_ITEM_TYPE_SCTP, -- -- /** -- * Matches a VXLAN header. -- * -- * See struct rte_flow_item_vxlan. -- */ -- RTE_FLOW_ITEM_TYPE_VXLAN, -- -- /** -- * Matches a E_TAG header. -- * -- * See struct rte_flow_item_e_tag. -- */ -- RTE_FLOW_ITEM_TYPE_E_TAG, -- -- /** -- * Matches a NVGRE header. -- * -- * See struct rte_flow_item_nvgre. -- */ -- RTE_FLOW_ITEM_TYPE_NVGRE, -- -- /** -- * Matches a MPLS header. -- * -- * See struct rte_flow_item_mpls. -- */ -- RTE_FLOW_ITEM_TYPE_MPLS, -- -- /** -- * Matches a GRE header. -- * -- * See struct rte_flow_item_gre. -- */ -- RTE_FLOW_ITEM_TYPE_GRE, -- -- /** -- * [META] -- * -- * Fuzzy pattern match, expect faster than default. -- * -- * This is for device that support fuzzy matching option. -- * Usually a fuzzy matching is fast but the cost is accuracy. -- * -- * See struct rte_flow_item_fuzzy. -- */ -- RTE_FLOW_ITEM_TYPE_FUZZY, -- -- /** -- * Matches a GTP header. -- * -- * Configure flow for GTP packets. -- * -- * See struct rte_flow_item_gtp. -- */ -- RTE_FLOW_ITEM_TYPE_GTP, -- -- /** -- * Matches a GTP header. -- * -- * Configure flow for GTP-C packets. -- * -- * See struct rte_flow_item_gtp. -- */ -- RTE_FLOW_ITEM_TYPE_GTPC, -- -- /** -- * Matches a GTP header. -- * -- * Configure flow for GTP-U packets. -- * -- * See struct rte_flow_item_gtp. -- */ -- RTE_FLOW_ITEM_TYPE_GTPU, -- -- /** -- * Matches a ESP header. -- * -- * See struct rte_flow_item_esp. -- */ -- RTE_FLOW_ITEM_TYPE_ESP, --}; -- --/** -- * RTE_FLOW_ITEM_TYPE_ANY -- * -- * Matches any protocol in place of the current layer, a single ANY may also -- * stand for several protocol layers. -- * -- * This is usually specified as the first pattern item when looking for a -- * protocol anywhere in a packet. -- * -- * A zeroed mask stands for any number of layers. -- */ --struct rte_flow_item_any { -- uint32_t num; /**< Number of layers covered. */ --}; -- --/** Default mask for RTE_FLOW_ITEM_TYPE_ANY. */ --#ifndef __cplusplus --static const struct rte_flow_item_any rte_flow_item_any_mask = { -- .num = 0x00000000, --}; --#endif -- --/** -- * RTE_FLOW_ITEM_TYPE_VF -- * -- * Matches packets addressed to a virtual function ID of the device. -- * -- * If the underlying device function differs from the one that would -- * normally receive the matched traffic, specifying this item prevents it -- * from reaching that device unless the flow rule contains a VF -- * action. Packets are not duplicated between device instances by default. -- * -- * - Likely to return an error or never match any traffic if this causes a -- * VF device to match traffic addressed to a different VF. -- * - Can be specified multiple times to match traffic addressed to several -- * VF IDs. -- * - Can be combined with a PF item to match both PF and VF traffic. -- * -- * A zeroed mask can be used to match any VF ID. -- */ --struct rte_flow_item_vf { -- uint32_t id; /**< Destination VF ID. */ --}; -- --/** Default mask for RTE_FLOW_ITEM_TYPE_VF. */ --#ifndef __cplusplus --static const struct rte_flow_item_vf rte_flow_item_vf_mask = { -- .id = 0x00000000, --}; --#endif -- --/** -- * RTE_FLOW_ITEM_TYPE_PORT -- * -- * Matches packets coming from the specified physical port of the underlying -- * device. -- * -- * The first PORT item overrides the physical port normally associated with -- * the specified DPDK input port (port_id). This item can be provided -- * several times to match additional physical ports. -- * -- * Note that physical ports are not necessarily tied to DPDK input ports -- * (port_id) when those are not under DPDK control. Possible values are -- * specific to each device, they are not necessarily indexed from zero and -- * may not be contiguous. -- * -- * As a device property, the list of allowed values as well as the value -- * associated with a port_id should be retrieved by other means. -- * -- * A zeroed mask can be used to match any port index. -- */ --struct rte_flow_item_port { -- uint32_t index; /**< Physical port index. */ --}; -- --/** Default mask for RTE_FLOW_ITEM_TYPE_PORT. */ --#ifndef __cplusplus --static const struct rte_flow_item_port rte_flow_item_port_mask = { -- .index = 0x00000000, --}; --#endif -- --/** -- * RTE_FLOW_ITEM_TYPE_RAW -- * -- * Matches a byte string of a given length at a given offset. -- * -- * Offset is either absolute (using the start of the packet) or relative to -- * the end of the previous matched item in the stack, in which case negative -- * values are allowed. -- * -- * If search is enabled, offset is used as the starting point. The search -- * area can be delimited by setting limit to a nonzero value, which is the -- * maximum number of bytes after offset where the pattern may start. -- * -- * Matching a zero-length pattern is allowed, doing so resets the relative -- * offset for subsequent items. -- * -- * This type does not support ranges (struct rte_flow_item.last). -- */ --struct rte_flow_item_raw { -- uint32_t relative:1; /**< Look for pattern after the previous item. */ -- uint32_t search:1; /**< Search pattern from offset (see also limit). */ -- uint32_t reserved:30; /**< Reserved, must be set to zero. */ -- int32_t offset; /**< Absolute or relative offset for pattern. */ -- uint16_t limit; /**< Search area limit for start of pattern. */ -- uint16_t length; /**< Pattern length. */ -- uint8_t pattern[]; /**< Byte string to look for. */ --}; -- --/** Default mask for RTE_FLOW_ITEM_TYPE_RAW. */ --#ifndef __cplusplus --static const struct rte_flow_item_raw rte_flow_item_raw_mask = { -- .relative = 1, -- .search = 1, -- .reserved = 0x3fffffff, -- .offset = 0xffffffff, -- .limit = 0xffff, -- .length = 0xffff, --}; --#endif -- --/** -- * RTE_FLOW_ITEM_TYPE_ETH -- * -- * Matches an Ethernet header. -- */ --struct rte_flow_item_eth { -- struct ether_addr dst; /**< Destination MAC. */ -- struct ether_addr src; /**< Source MAC. */ -- rte_be16_t type; /**< EtherType. */ --}; -- --/** Default mask for RTE_FLOW_ITEM_TYPE_ETH. */ --#ifndef __cplusplus --static const struct rte_flow_item_eth rte_flow_item_eth_mask = { -- .dst.addr_bytes = "\xff\xff\xff\xff\xff\xff", -- .src.addr_bytes = "\xff\xff\xff\xff\xff\xff", -- .type = RTE_BE16(0x0000), --}; --#endif -- --/** -- * RTE_FLOW_ITEM_TYPE_VLAN -- * -- * Matches an 802.1Q/ad VLAN tag. -- * -- * The corresponding standard outer EtherType (TPID) values are -- * ETHER_TYPE_VLAN or ETHER_TYPE_QINQ. It can be overridden by the preceding -- * pattern item. -- */ --struct rte_flow_item_vlan { -- rte_be16_t tci; /**< Tag control information. */ -- rte_be16_t inner_type; /**< Inner EtherType or TPID. */ --}; -- --/** Default mask for RTE_FLOW_ITEM_TYPE_VLAN. */ --#ifndef __cplusplus --static const struct rte_flow_item_vlan rte_flow_item_vlan_mask = { -- .tci = RTE_BE16(0x0fff), -- .inner_type = RTE_BE16(0x0000), --}; --#endif -- --/** -- * RTE_FLOW_ITEM_TYPE_IPV4 -- * -- * Matches an IPv4 header. -- * -- * Note: IPv4 options are handled by dedicated pattern items. -- */ --struct rte_flow_item_ipv4 { -- struct ipv4_hdr hdr; /**< IPv4 header definition. */ --}; -- --/** Default mask for RTE_FLOW_ITEM_TYPE_IPV4. */ --#ifndef __cplusplus --static const struct rte_flow_item_ipv4 rte_flow_item_ipv4_mask = { -- .hdr = { -- .src_addr = RTE_BE32(0xffffffff), -- .dst_addr = RTE_BE32(0xffffffff), -- }, --}; --#endif -- --/** -- * RTE_FLOW_ITEM_TYPE_IPV6. -- * -- * Matches an IPv6 header. -- * -- * Note: IPv6 options are handled by dedicated pattern items. -- */ --struct rte_flow_item_ipv6 { -- struct ipv6_hdr hdr; /**< IPv6 header definition. */ --}; -- --/** Default mask for RTE_FLOW_ITEM_TYPE_IPV6. */ --#ifndef __cplusplus --static const struct rte_flow_item_ipv6 rte_flow_item_ipv6_mask = { -- .hdr = { -- .src_addr = -- "\xff\xff\xff\xff\xff\xff\xff\xff" -- "\xff\xff\xff\xff\xff\xff\xff\xff", -- .dst_addr = -- "\xff\xff\xff\xff\xff\xff\xff\xff" -- "\xff\xff\xff\xff\xff\xff\xff\xff", -- }, --}; --#endif -- --/** -- * RTE_FLOW_ITEM_TYPE_ICMP. -- * -- * Matches an ICMP header. -- */ --struct rte_flow_item_icmp { -- struct icmp_hdr hdr; /**< ICMP header definition. */ --}; -- --/** Default mask for RTE_FLOW_ITEM_TYPE_ICMP. */ --#ifndef __cplusplus --static const struct rte_flow_item_icmp rte_flow_item_icmp_mask = { -- .hdr = { -- .icmp_type = 0xff, -- .icmp_code = 0xff, -- }, --}; --#endif -- --/** -- * RTE_FLOW_ITEM_TYPE_UDP. -- * -- * Matches a UDP header. -- */ --struct rte_flow_item_udp { -- struct udp_hdr hdr; /**< UDP header definition. */ --}; -- --/** Default mask for RTE_FLOW_ITEM_TYPE_UDP. */ --#ifndef __cplusplus --static const struct rte_flow_item_udp rte_flow_item_udp_mask = { -- .hdr = { -- .src_port = RTE_BE16(0xffff), -- .dst_port = RTE_BE16(0xffff), -- }, --}; --#endif -- --/** -- * RTE_FLOW_ITEM_TYPE_TCP. -- * -- * Matches a TCP header. -- */ --struct rte_flow_item_tcp { -- struct tcp_hdr hdr; /**< TCP header definition. */ --}; -- --/** Default mask for RTE_FLOW_ITEM_TYPE_TCP. */ --#ifndef __cplusplus --static const struct rte_flow_item_tcp rte_flow_item_tcp_mask = { -- .hdr = { -- .src_port = RTE_BE16(0xffff), -- .dst_port = RTE_BE16(0xffff), -- }, --}; --#endif -- --/** -- * RTE_FLOW_ITEM_TYPE_SCTP. -- * -- * Matches a SCTP header. -- */ --struct rte_flow_item_sctp { -- struct sctp_hdr hdr; /**< SCTP header definition. */ --}; -- --/** Default mask for RTE_FLOW_ITEM_TYPE_SCTP. */ --#ifndef __cplusplus --static const struct rte_flow_item_sctp rte_flow_item_sctp_mask = { -- .hdr = { -- .src_port = RTE_BE16(0xffff), -- .dst_port = RTE_BE16(0xffff), -- }, --}; --#endif -- --/** -- * RTE_FLOW_ITEM_TYPE_VXLAN. -- * -- * Matches a VXLAN header (RFC 7348). -- */ --struct rte_flow_item_vxlan { -- uint8_t flags; /**< Normally 0x08 (I flag). */ -- uint8_t rsvd0[3]; /**< Reserved, normally 0x000000. */ -- uint8_t vni[3]; /**< VXLAN identifier. */ -- uint8_t rsvd1; /**< Reserved, normally 0x00. */ --}; -- --/** Default mask for RTE_FLOW_ITEM_TYPE_VXLAN. */ --#ifndef __cplusplus --static const struct rte_flow_item_vxlan rte_flow_item_vxlan_mask = { -- .vni = "\xff\xff\xff", --}; --#endif -- --/** -- * RTE_FLOW_ITEM_TYPE_E_TAG. -- * -- * Matches a E-tag header. -- */ --struct rte_flow_item_e_tag { -- rte_be16_t tpid; /**< Tag protocol identifier (0x893F). */ -- /** -- * E-Tag control information (E-TCI). -- * E-PCP (3b), E-DEI (1b), ingress E-CID base (12b). -- */ -- rte_be16_t epcp_edei_in_ecid_b; -- /** Reserved (2b), GRP (2b), E-CID base (12b). */ -- rte_be16_t rsvd_grp_ecid_b; -- uint8_t in_ecid_e; /**< Ingress E-CID ext. */ -- uint8_t ecid_e; /**< E-CID ext. */ --}; -- --/** Default mask for RTE_FLOW_ITEM_TYPE_E_TAG. */ --#ifndef __cplusplus --static const struct rte_flow_item_e_tag rte_flow_item_e_tag_mask = { -- .rsvd_grp_ecid_b = RTE_BE16(0x3fff), --}; --#endif -- --/** -- * RTE_FLOW_ITEM_TYPE_NVGRE. -- * -- * Matches a NVGRE header. -- */ --struct rte_flow_item_nvgre { -- /** -- * Checksum (1b), undefined (1b), key bit (1b), sequence number (1b), -- * reserved 0 (9b), version (3b). -- * -- * c_k_s_rsvd0_ver must have value 0x2000 according to RFC 7637. -- */ -- rte_be16_t c_k_s_rsvd0_ver; -- rte_be16_t protocol; /**< Protocol type (0x6558). */ -- uint8_t tni[3]; /**< Virtual subnet ID. */ -- uint8_t flow_id; /**< Flow ID. */ --}; -- --/** Default mask for RTE_FLOW_ITEM_TYPE_NVGRE. */ --#ifndef __cplusplus --static const struct rte_flow_item_nvgre rte_flow_item_nvgre_mask = { -- .tni = "\xff\xff\xff", --}; --#endif -- --/** -- * RTE_FLOW_ITEM_TYPE_MPLS. -- * -- * Matches a MPLS header. -- */ --struct rte_flow_item_mpls { -- /** -- * Label (20b), TC (3b), Bottom of Stack (1b). -- */ -- uint8_t label_tc_s[3]; -- uint8_t ttl; /** Time-to-Live. */ --}; -- --/** Default mask for RTE_FLOW_ITEM_TYPE_MPLS. */ --#ifndef __cplusplus --static const struct rte_flow_item_mpls rte_flow_item_mpls_mask = { -- .label_tc_s = "\xff\xff\xf0", --}; --#endif -- --/** -- * RTE_FLOW_ITEM_TYPE_GRE. -- * -- * Matches a GRE header. -- */ --struct rte_flow_item_gre { -- /** -- * Checksum (1b), reserved 0 (12b), version (3b). -- * Refer to RFC 2784. -- */ -- rte_be16_t c_rsvd0_ver; -- rte_be16_t protocol; /**< Protocol type. */ --}; -- --/** Default mask for RTE_FLOW_ITEM_TYPE_GRE. */ --#ifndef __cplusplus --static const struct rte_flow_item_gre rte_flow_item_gre_mask = { -- .protocol = RTE_BE16(0xffff), --}; --#endif -- --/** -- * RTE_FLOW_ITEM_TYPE_FUZZY -- * -- * Fuzzy pattern match, expect faster than default. -- * -- * This is for device that support fuzzy match option. -- * Usually a fuzzy match is fast but the cost is accuracy. -- * i.e. Signature Match only match pattern's hash value, but it is -- * possible two different patterns have the same hash value. -- * -- * Matching accuracy level can be configure by threshold. -- * Driver can divide the range of threshold and map to different -- * accuracy levels that device support. -- * -- * Threshold 0 means perfect match (no fuzziness), while threshold -- * 0xffffffff means fuzziest match. -- */ --struct rte_flow_item_fuzzy { -- uint32_t thresh; /**< Accuracy threshold. */ --}; -- --/** Default mask for RTE_FLOW_ITEM_TYPE_FUZZY. */ --#ifndef __cplusplus --static const struct rte_flow_item_fuzzy rte_flow_item_fuzzy_mask = { -- .thresh = 0xffffffff, --}; --#endif -- --/** -- * RTE_FLOW_ITEM_TYPE_GTP. -- * -- * Matches a GTPv1 header. -- */ --struct rte_flow_item_gtp { -- /** -- * Version (3b), protocol type (1b), reserved (1b), -- * Extension header flag (1b), -- * Sequence number flag (1b), -- * N-PDU number flag (1b). -- */ -- uint8_t v_pt_rsv_flags; -- uint8_t msg_type; /**< Message type. */ -- rte_be16_t msg_len; /**< Message length. */ -- rte_be32_t teid; /**< Tunnel endpoint identifier. */ --}; -- --/** Default mask for RTE_FLOW_ITEM_TYPE_GTP. */ --#ifndef __cplusplus --static const struct rte_flow_item_gtp rte_flow_item_gtp_mask = { -- .teid = RTE_BE32(0xffffffff), --}; --#endif -- --/** -- * RTE_FLOW_ITEM_TYPE_ESP -- * -- * Matches an ESP header. -- */ --struct rte_flow_item_esp { -- struct esp_hdr hdr; /**< ESP header definition. */ --}; -- --/** Default mask for RTE_FLOW_ITEM_TYPE_ESP. */ --#ifndef __cplusplus --static const struct rte_flow_item_esp rte_flow_item_esp_mask = { -- .hdr = { -- .spi = OVS_BE32_MAX, -- }, --}; --#endif -- --/** -- * Matching pattern item definition. -- * -- * A pattern is formed by stacking items starting from the lowest protocol -- * layer to match. This stacking restriction does not apply to meta items -- * which can be placed anywhere in the stack without affecting the meaning -- * of the resulting pattern. -- * -- * Patterns are terminated by END items. -- * -- * The spec field should be a valid pointer to a structure of the related -- * item type. It may remain unspecified (NULL) in many cases to request -- * broad (nonspecific) matching. In such cases, last and mask must also be -- * set to NULL. -- * -- * Optionally, last can point to a structure of the same type to define an -- * inclusive range. This is mostly supported by integer and address fields, -- * may cause errors otherwise. Fields that do not support ranges must be set -- * to 0 or to the same value as the corresponding fields in spec. -- * -- * Only the fields defined to nonzero values in the default masks (see -- * rte_flow_item_{name}_mask constants) are considered relevant by -- * default. This can be overridden by providing a mask structure of the -- * same type with applicable bits set to one. It can also be used to -- * partially filter out specific fields (e.g. as an alternate mean to match -- * ranges of IP addresses). -- * -- * Mask is a simple bit-mask applied before interpreting the contents of -- * spec and last, which may yield unexpected results if not used -- * carefully. For example, if for an IPv4 address field, spec provides -- * 10.1.2.3, last provides 10.3.4.5 and mask provides 255.255.0.0, the -- * effective range becomes 10.1.0.0 to 10.3.255.255. -- */ --struct rte_flow_item { -- enum rte_flow_item_type type; /**< Item type. */ -- const void *spec; /**< Pointer to item specification structure. */ -- const void *last; /**< Defines an inclusive range (spec to last). */ -- const void *mask; /**< Bit-mask applied to spec and last. */ --}; -- --/** -- * Action types. -- * -- * Each possible action is represented by a type. Some have associated -- * configuration structures. Several actions combined in a list can be -- * affected to a flow rule. That list is not ordered. -- * -- * They fall in three categories: -- * -- * - Terminating actions (such as QUEUE, DROP, RSS, PF, VF) that prevent -- * processing matched packets by subsequent flow rules, unless overridden -- * with PASSTHRU. -- * -- * - Non terminating actions (PASSTHRU, DUP) that leave matched packets up -- * for additional processing by subsequent flow rules. -- * -- * - Other non terminating meta actions that do not affect the fate of -- * packets (END, VOID, MARK, FLAG, COUNT). -- * -- * When several actions are combined in a flow rule, they should all have -- * different types (e.g. dropping a packet twice is not possible). -- * -- * Only the last action of a given type is taken into account. PMDs still -- * perform error checking on the entire list. -- * -- * Note that PASSTHRU is the only action able to override a terminating -- * rule. -- */ --enum rte_flow_action_type { -- /** -- * [META] -- * -- * End marker for action lists. Prevents further processing of -- * actions, thereby ending the list. -- * -- * No associated configuration structure. -- */ -- RTE_FLOW_ACTION_TYPE_END, -- -- /** -- * [META] -- * -- * Used as a placeholder for convenience. It is ignored and simply -- * discarded by PMDs. -- * -- * No associated configuration structure. -- */ -- RTE_FLOW_ACTION_TYPE_VOID, -- -- /** -- * Leaves packets up for additional processing by subsequent flow -- * rules. This is the default when a rule does not contain a -- * terminating action, but can be specified to force a rule to -- * become non-terminating. -- * -- * No associated configuration structure. -- */ -- RTE_FLOW_ACTION_TYPE_PASSTHRU, -- -- /** -- * [META] -- * -- * Attaches an integer value to packets and sets PKT_RX_FDIR and -- * PKT_RX_FDIR_ID mbuf flags. -- * -- * See struct rte_flow_action_mark. -- */ -- RTE_FLOW_ACTION_TYPE_MARK, -- -- /** -- * [META] -- * -- * Flags packets. Similar to MARK without a specific value; only -- * sets the PKT_RX_FDIR mbuf flag. -- * -- * No associated configuration structure. -- */ -- RTE_FLOW_ACTION_TYPE_FLAG, -- -- /** -- * Assigns packets to a given queue index. -- * -- * See struct rte_flow_action_queue. -- */ -- RTE_FLOW_ACTION_TYPE_QUEUE, -- -- /** -- * Drops packets. -- * -- * PASSTHRU overrides this action if both are specified. -- * -- * No associated configuration structure. -- */ -- RTE_FLOW_ACTION_TYPE_DROP, -- -- /** -- * [META] -- * -- * Enables counters for this rule. -- * -- * These counters can be retrieved and reset through rte_flow_query(), -- * see struct rte_flow_query_count. -- * -- * No associated configuration structure. -- */ -- RTE_FLOW_ACTION_TYPE_COUNT, -- -- /** -- * Duplicates packets to a given queue index. -- * -- * This is normally combined with QUEUE, however when used alone, it -- * is actually similar to QUEUE + PASSTHRU. -- * -- * See struct rte_flow_action_dup. -- */ -- RTE_FLOW_ACTION_TYPE_DUP, -- -- /** -- * Similar to QUEUE, except RSS is additionally performed on packets -- * to spread them among several queues according to the provided -- * parameters. -- * -- * See struct rte_flow_action_rss. -- */ -- RTE_FLOW_ACTION_TYPE_RSS, -- -- /** -- * Redirects packets to the physical function (PF) of the current -- * device. -- * -- * No associated configuration structure. -- */ -- RTE_FLOW_ACTION_TYPE_PF, -- -- /** -- * Redirects packets to the virtual function (VF) of the current -- * device with the specified ID. -- * -- * See struct rte_flow_action_vf. -- */ -- RTE_FLOW_ACTION_TYPE_VF, -- -- /** -- * Traffic metering and policing (MTR). -- * -- * See struct rte_flow_action_meter. -- * See file rte_mtr.h for MTR object configuration. -- */ -- RTE_FLOW_ACTION_TYPE_METER, -- -- /** -- * Redirects packets to security engine of current device for security -- * processing as specified by security session. -- * -- * See struct rte_flow_action_security. -- */ -- RTE_FLOW_ACTION_TYPE_SECURITY --}; -- --/** -- * RTE_FLOW_ACTION_TYPE_MARK -- * -- * Attaches an integer value to packets and sets PKT_RX_FDIR and -- * PKT_RX_FDIR_ID mbuf flags. -- * -- * This value is arbitrary and application-defined. Maximum allowed value -- * depends on the underlying implementation. It is returned in the -- * hash.fdir.hi mbuf field. -- */ --struct rte_flow_action_mark { -- uint32_t id; /**< Integer value to return with packets. */ --}; -- --/** -- * RTE_FLOW_ACTION_TYPE_QUEUE -- * -- * Assign packets to a given queue index. -- * -- * Terminating by default. -- */ --struct rte_flow_action_queue { -- uint16_t index; /**< Queue index to use. */ --}; -- --/** -- * RTE_FLOW_ACTION_TYPE_COUNT (query) -- * -- * Query structure to retrieve and reset flow rule counters. -- */ --struct rte_flow_query_count { -- uint32_t reset:1; /**< Reset counters after query [in]. */ -- uint32_t hits_set:1; /**< hits field is set [out]. */ -- uint32_t bytes_set:1; /**< bytes field is set [out]. */ -- uint32_t reserved:29; /**< Reserved, must be zero [in, out]. */ -- uint64_t hits; /**< Number of hits for this rule [out]. */ -- uint64_t bytes; /**< Number of bytes through this rule [out]. */ --}; -- --/** -- * RTE_FLOW_ACTION_TYPE_DUP -- * -- * Duplicates packets to a given queue index. -- * -- * This is normally combined with QUEUE, however when used alone, it is -- * actually similar to QUEUE + PASSTHRU. -- * -- * Non-terminating by default. -- */ --struct rte_flow_action_dup { -- uint16_t index; /**< Queue index to duplicate packets to. */ --}; -- --/** -- * RTE_FLOW_ACTION_TYPE_RSS -- * -- * Similar to QUEUE, except RSS is additionally performed on packets to -- * spread them among several queues according to the provided parameters. -- * -- * Unlike global RSS settings used by other DPDK APIs, unsetting the -- * @p types field does not disable RSS in a flow rule. Doing so instead -- * requests safe unspecified "best-effort" settings from the underlying PMD, -- * which depending on the flow rule, may result in anything ranging from -- * empty (single queue) to all-inclusive RSS. -- * -- * Note: RSS hash result is stored in the hash.rss mbuf field which overlaps -- * hash.fdir.lo. Since the MARK action sets the hash.fdir.hi field only, -- * both can be requested simultaneously. -- */ --struct rte_flow_action_rss { -- enum rte_eth_hash_function func; /**< RSS hash function to apply. */ -- /** -- * Packet encapsulation level RSS hash @p types apply to. -- * -- * - @p 0 requests the default behavior. Depending on the packet -- * type, it can mean outermost, innermost, anything in between or -- * even no RSS. -- * -- * It basically stands for the innermost encapsulation level RSS -- * can be performed on according to PMD and device capabilities. -- * -- * - @p 1 requests RSS to be performed on the outermost packet -- * encapsulation level. -- * -- * - @p 2 and subsequent values request RSS to be performed on the -- * specified inner packet encapsulation level, from outermost to -- * innermost (lower to higher values). -- * -- * Values other than @p 0 are not necessarily supported. -- * -- * Requesting a specific RSS level on unrecognized traffic results -- * in undefined behavior. For predictable results, it is recommended -- * to make the flow rule pattern match packet headers up to the -- * requested encapsulation level so that only matching traffic goes -- * through. -- */ -- uint32_t level; -- uint64_t types; /**< Specific RSS hash types (see ETH_RSS_*). */ -- uint32_t key_len; /**< Hash key length in bytes. */ -- uint32_t queue_num; /**< Number of entries in @p queue. */ -- const uint8_t *key; /**< Hash key. */ -- const uint16_t *queue; /**< Queue indices to use. */ --}; -- --/** -- * RTE_FLOW_ACTION_TYPE_VF -- * -- * Redirects packets to a virtual function (VF) of the current device. -- * -- * Packets matched by a VF pattern item can be redirected to their original -- * VF ID instead of the specified one. This parameter may not be available -- * and is not guaranteed to work properly if the VF part is matched by a -- * prior flow rule or if packets are not addressed to a VF in the first -- * place. -- * -- * Terminating by default. -- */ --struct rte_flow_action_vf { -- uint32_t original:1; /**< Use original VF ID if possible. */ -- uint32_t reserved:31; /**< Reserved, must be zero. */ -- uint32_t id; /**< VF ID to redirect packets to. */ --}; -- --/** -- * RTE_FLOW_ACTION_TYPE_METER -- * -- * Traffic metering and policing (MTR). -- * -- * Packets matched by items of this type can be either dropped or passed to the -- * next item with their color set by the MTR object. -- * -- * Non-terminating by default. -- */ --struct rte_flow_action_meter { -- uint32_t mtr_id; /**< MTR object ID created with rte_mtr_create(). */ --}; -- --/** -- * RTE_FLOW_ACTION_TYPE_SECURITY -- * -- * Perform the security action on flows matched by the pattern items -- * according to the configuration of the security session. -- * -- * This action modifies the payload of matched flows. For INLINE_CRYPTO, the -- * security protocol headers and IV are fully provided by the application as -- * specified in the flow pattern. The payload of matching packets is -- * encrypted on egress, and decrypted and authenticated on ingress. -- * For INLINE_PROTOCOL, the security protocol is fully offloaded to HW, -- * providing full encapsulation and decapsulation of packets in security -- * protocols. The flow pattern specifies both the outer security header fields -- * and the inner packet fields. The security session specified in the action -- * must match the pattern parameters. -- * -- * The security session specified in the action must be created on the same -- * port as the flow action that is being specified. -- * -- * The ingress/egress flow attribute should match that specified in the -- * security session if the security session supports the definition of the -- * direction. -- * -- * Multiple flows can be configured to use the same security session. -- * -- * Non-terminating by default. -- */ --struct rte_flow_action_security { -- void *security_session; /**< Pointer to security session structure. */ --}; -- --/** -- * Definition of a single action. -- * -- * A list of actions is terminated by a END action. -- * -- * For simple actions without a configuration structure, conf remains NULL. -- */ --struct rte_flow_action { -- enum rte_flow_action_type type; /**< Action type. */ -- const void *conf; /**< Pointer to action configuration structure. */ --}; -- --/** -- * Opaque type returned after successfully creating a flow. -- * -- * This handle can be used to manage and query the related flow (e.g. to -- * destroy it or retrieve counters). -- */ --struct rte_flow; -- --/** -- * Verbose error types. -- * -- * Most of them provide the type of the object referenced by struct -- * rte_flow_error.cause. -- */ --enum rte_flow_error_type { -- RTE_FLOW_ERROR_TYPE_NONE, /**< No error. */ -- RTE_FLOW_ERROR_TYPE_UNSPECIFIED, /**< Cause unspecified. */ -- RTE_FLOW_ERROR_TYPE_HANDLE, /**< Flow rule (handle). */ -- RTE_FLOW_ERROR_TYPE_ATTR_GROUP, /**< Group field. */ -- RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY, /**< Priority field. */ -- RTE_FLOW_ERROR_TYPE_ATTR_INGRESS, /**< Ingress field. */ -- RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, /**< Egress field. */ -- RTE_FLOW_ERROR_TYPE_ATTR, /**< Attributes structure. */ -- RTE_FLOW_ERROR_TYPE_ITEM_NUM, /**< Pattern length. */ -- RTE_FLOW_ERROR_TYPE_ITEM, /**< Specific pattern item. */ -- RTE_FLOW_ERROR_TYPE_ACTION_NUM, /**< Number of actions. */ -- RTE_FLOW_ERROR_TYPE_ACTION, /**< Specific action. */ --}; -- --/** -- * Verbose error structure definition. -- * -- * This object is normally allocated by applications and set by PMDs, the -- * message points to a constant string which does not need to be freed by -- * the application, however its pointer can be considered valid only as long -- * as its associated DPDK port remains configured. Closing the underlying -- * device or unloading the PMD invalidates it. -- * -- * Both cause and message may be NULL regardless of the error type. -- */ --struct rte_flow_error { -- enum rte_flow_error_type type; /**< Cause field and error types. */ -- const void *cause; /**< Object responsible for the error. */ -- const char *message; /**< Human-readable error message. */ --}; -- --/** -- * Check whether a flow rule can be created on a given port. -- * -- * The flow rule is validated for correctness and whether it could be accepted -- * by the device given sufficient resources. The rule is checked against the -- * current device mode and queue configuration. The flow rule may also -- * optionally be validated against existing flow rules and device resources. -- * This function has no effect on the target device. -- * -- * The returned value is guaranteed to remain valid only as long as no -- * successful calls to rte_flow_create() or rte_flow_destroy() are made in -- * the meantime and no device parameter affecting flow rules in any way are -- * modified, due to possible collisions or resource limitations (although in -- * such cases EINVAL should not be returned). -- * -- * @param port_id -- * Port identifier of Ethernet device. -- * @param[in] attr -- * Flow rule attributes. -- * @param[in] pattern -- * Pattern specification (list terminated by the END pattern item). -- * @param[in] actions -- * Associated actions (list terminated by the END action). -- * @param[out] error -- * Perform verbose error reporting if not NULL. PMDs initialize this -- * structure in case of error only. -- * -- * @return -- * 0 if flow rule is valid and can be created. A negative errno value -- * otherwise (rte_errno is also set), the following errors are defined: -- * -- * -ENOSYS: underlying device does not support this functionality. -- * -- * -EINVAL: unknown or invalid rule specification. -- * -- * -ENOTSUP: valid but unsupported rule specification (e.g. partial -- * bit-masks are unsupported). -- * -- * -EEXIST: collision with an existing rule. Only returned if device -- * supports flow rule collision checking and there was a flow rule -- * collision. Not receiving this return code is no guarantee that creating -- * the rule will not fail due to a collision. -- * -- * -ENOMEM: not enough memory to execute the function, or if the device -- * supports resource validation, resource limitation on the device. -- * -- * -EBUSY: action cannot be performed due to busy device resources, may -- * succeed if the affected queues or even the entire port are in a stopped -- * state (see rte_eth_dev_rx_queue_stop() and rte_eth_dev_stop()). -- */ --int --rte_flow_validate(uint16_t port_id, -- const struct rte_flow_attr *attr, -- const struct rte_flow_item pattern[], -- const struct rte_flow_action actions[], -- struct rte_flow_error *error); -- --/** -- * Create a flow rule on a given port. -- * -- * @param port_id -- * Port identifier of Ethernet device. -- * @param[in] attr -- * Flow rule attributes. -- * @param[in] pattern -- * Pattern specification (list terminated by the END pattern item). -- * @param[in] actions -- * Associated actions (list terminated by the END action). -- * @param[out] error -- * Perform verbose error reporting if not NULL. PMDs initialize this -- * structure in case of error only. -- * -- * @return -- * A valid handle in case of success, NULL otherwise and rte_errno is set -- * to the positive version of one of the error codes defined for -- * rte_flow_validate(). -- */ --struct rte_flow * --rte_flow_create(uint16_t port_id, -- const struct rte_flow_attr *attr, -- const struct rte_flow_item pattern[], -- const struct rte_flow_action actions[], -- struct rte_flow_error *error); -- --/** -- * Destroy a flow rule on a given port. -- * -- * Failure to destroy a flow rule handle may occur when other flow rules -- * depend on it, and destroying it would result in an inconsistent state. -- * -- * This function is only guaranteed to succeed if handles are destroyed in -- * reverse order of their creation. -- * -- * @param port_id -- * Port identifier of Ethernet device. -- * @param flow -- * Flow rule handle to destroy. -- * @param[out] error -- * Perform verbose error reporting if not NULL. PMDs initialize this -- * structure in case of error only. -- * -- * @return -- * 0 on success, a negative errno value otherwise and rte_errno is set. -- */ --int --rte_flow_destroy(uint16_t port_id, -- struct rte_flow *flow, -- struct rte_flow_error *error); -- --/** -- * Destroy all flow rules associated with a port. -- * -- * In the unlikely event of failure, handles are still considered destroyed -- * and no longer valid but the port must be assumed to be in an inconsistent -- * state. -- * -- * @param port_id -- * Port identifier of Ethernet device. -- * @param[out] error -- * Perform verbose error reporting if not NULL. PMDs initialize this -- * structure in case of error only. -- * -- * @return -- * 0 on success, a negative errno value otherwise and rte_errno is set. -- */ --int --rte_flow_flush(uint16_t port_id, -- struct rte_flow_error *error); -- --/** -- * Query an existing flow rule. -- * -- * This function allows retrieving flow-specific data such as counters. -- * Data is gathered by special actions which must be present in the flow -- * rule definition. -- * -- * \see RTE_FLOW_ACTION_TYPE_COUNT -- * -- * @param port_id -- * Port identifier of Ethernet device. -- * @param flow -- * Flow rule handle to query. -- * @param action -- * Action type to query. -- * @param[in, out] data -- * Pointer to storage for the associated query data type. -- * @param[out] error -- * Perform verbose error reporting if not NULL. PMDs initialize this -- * structure in case of error only. -- * -- * @return -- * 0 on success, a negative errno value otherwise and rte_errno is set. -- */ --int --rte_flow_query(uint16_t port_id, -- struct rte_flow *flow, -- enum rte_flow_action_type action, -- void *data, -- struct rte_flow_error *error); -- --/** -- * Restrict ingress traffic to the defined flow rules. -- * -- * Isolated mode guarantees that all ingress traffic comes from defined flow -- * rules only (current and future). -- * -- * Besides making ingress more deterministic, it allows PMDs to safely reuse -- * resources otherwise assigned to handle the remaining traffic, such as -- * global RSS configuration settings, VLAN filters, MAC address entries, -- * legacy filter API rules and so on in order to expand the set of possible -- * flow rule types. -- * -- * Calling this function as soon as possible after device initialization, -- * ideally before the first call to rte_eth_dev_configure(), is recommended -- * to avoid possible failures due to conflicting settings. -- * -- * Once effective, leaving isolated mode may not be possible depending on -- * PMD implementation. -- * -- * Additionally, the following functionality has no effect on the underlying -- * port and may return errors such as ENOTSUP ("not supported"): -- * -- * - Toggling promiscuous mode. -- * - Toggling allmulticast mode. -- * - Configuring MAC addresses. -- * - Configuring multicast addresses. -- * - Configuring VLAN filters. -- * - Configuring Rx filters through the legacy API (e.g. FDIR). -- * - Configuring global RSS settings. -- * -- * @param port_id -- * Port identifier of Ethernet device. -- * @param set -- * Nonzero to enter isolated mode, attempt to leave it otherwise. -- * @param[out] error -- * Perform verbose error reporting if not NULL. PMDs initialize this -- * structure in case of error only. -- * -- * @return -- * 0 on success, a negative errno value otherwise and rte_errno is set. -- */ --int --rte_flow_isolate(uint16_t port_id, int set, struct rte_flow_error *error); -- --/** -- * Initialize flow error structure. -- * -- * @param[out] error -- * Pointer to flow error structure (may be NULL). -- * @param code -- * Related error code (rte_errno). -- * @param type -- * Cause field and error types. -- * @param cause -- * Object responsible for the error. -- * @param message -- * Human-readable error message. -- * -- * @return -- * Negative error code (errno value) and rte_errno is set. -- */ --int --rte_flow_error_set(struct rte_flow_error *error, -- int code, -- enum rte_flow_error_type type, -- const void *cause, -- const char *message); -- --/** -- * Generic flow representation. -- * -- * This form is sufficient to describe an rte_flow independently from any -- * PMD implementation and allows for replayability and identification. -- */ --struct rte_flow_desc { -- size_t size; /**< Allocated space including data[]. */ -- struct rte_flow_attr attr; /**< Attributes. */ -- struct rte_flow_item *items; /**< Items. */ -- struct rte_flow_action *actions; /**< Actions. */ -- uint8_t data[]; /**< Storage for items/actions. */ --}; -- --/** -- * Copy an rte_flow rule description. -- * -- * @param[in] fd -- * Flow rule description. -- * @param[in] len -- * Total size of allocated data for the flow description. -- * @param[in] attr -- * Flow rule attributes. -- * @param[in] items -- * Pattern specification (list terminated by the END pattern item). -- * @param[in] actions -- * Associated actions (list terminated by the END action). -- * -- * @return -- * If len is greater or equal to the size of the flow, the total size of the -- * flow description and its data. -- * If len is lower than the size of the flow, the number of bytes that would -- * have been written to desc had it been sufficient. Nothing is written. -- */ --size_t --rte_flow_copy(struct rte_flow_desc *fd, size_t len, -- const struct rte_flow_attr *attr, -- const struct rte_flow_item *items, -- const struct rte_flow_action *actions); -- --#ifdef __cplusplus --} --#endif -- --#endif /* RTE_FLOW_H_ */ --- -2.14.1 - - diff --git a/stream_ssl-fix-important-memory-leak-in-ssl_connect-.patch b/stream_ssl-fix-important-memory-leak-in-ssl_connect-.patch deleted file mode 100644 index c0c3d97a132c4efe9e6bebcb8033adaec1cbd652..0000000000000000000000000000000000000000 --- a/stream_ssl-fix-important-memory-leak-in-ssl_connect-.patch +++ /dev/null @@ -1,249 +0,0 @@ -From 1a860302fd8f547396320669fd896b3aab0c6583 Mon Sep 17 00:00:00 2001 -From: Damijan Skvarc -Date: Fri, 20 Sep 2019 09:51:54 -0700 -Subject: stream_ssl: fix important memory leak in ssl_connect() function - -While checking valgrind reports after running "make check-valgrind" I have noticed -reports for several tests similar to the following: - -.... -==5345== Memcheck, a memory error detector -==5345== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al. -==5345== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info -==5345== Command: ovsdb-client --private-key=/home/damijan.skvarc/doma/ovs/tests/testpki-privkey.pem --certificate=/home/damijan.skvarc/doma/ovs/tests/testpki-cert.pem --ca-cert=/home/damijan.skvarc/doma/ovs/tests/testpki-cacert.pem transact ssl:127.0.0.1:40111 \ \ \ ["ordinals", -==5345== \ \ \ \ \ \ {"op":\ "update", -==5345== \ \ \ \ \ \ \ "table":\ "ordinals", -==5345== \ \ \ \ \ \ \ "where":\ [["number",\ "==",\ 1]], -==5345== \ \ \ \ \ \ \ "row":\ {"number":\ 2,\ "name":\ "old\ two"}}, -==5345== \ \ \ \ \ \ {"op":\ "update", -==5345== \ \ \ \ \ \ \ "table":\ "ordinals", -==5345== \ \ \ \ \ \ \ "where":\ [["name",\ "==",\ "two"]], -==5345== \ \ \ \ \ \ \ "row":\ {"number":\ 1,\ "name":\ "old\ one"}}] -==5345== Parent PID: 5344 -==5345== -==5345== -==5345== HEAP SUMMARY: -==5345== in use at exit: 116,551 bytes in 3,341 blocks -==5345== total heap usage: 5,134 allocs, 1,793 frees, 412,290 bytes allocated -==5345== -==5345== 6,221 (184 direct, 6,037 indirect) bytes in 1 blocks are definitely lost in loss record 498 of 500 -==5345== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) -==5345== by 0x5105E77: CRYPTO_malloc (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0) -==5345== by 0x51E1D23: ??? (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0) -==5345== by 0x51E4861: ??? (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0) -==5345== by 0x51E5414: ASN1_item_ex_d2i (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0) -==5345== by 0x51E546A: ASN1_item_d2i (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0) -==5345== by 0x4E56B27: ??? (in /lib/x86_64-linux-gnu/libssl.so.1.0.0) -==5345== by 0x4E5BA11: ??? (in /lib/x86_64-linux-gnu/libssl.so.1.0.0) -==5345== by 0x4E65145: ??? (in /lib/x86_64-linux-gnu/libssl.so.1.0.0) -==5345== by 0x4522DF: ssl_connect (stream-ssl.c:530) -==5345== by 0x443D38: scs_connecting (stream.c:315) -==5345== by 0x443D38: stream_connect (stream.c:338) -==5345== by 0x443FA1: stream_open_block (stream.c:266) -==5345== by 0x40AB79: open_jsonrpc (ovsdb-client.c:507) -==5345== by 0x40AB79: open_rpc (ovsdb-client.c:143) -==5345== by 0x40B06B: do_transact__ (ovsdb-client.c:871) -==5345== by 0x40B245: do_transact (ovsdb-client.c:893) -==5345== by 0x405F76: main (ovsdb-client.c:282) -==5345== -==5345== LEAK SUMMARY: -==5345== definitely lost: 184 bytes in 1 blocks -==5345== indirectly lost: 6,037 bytes in 117 blocks -==5345== possibly lost: 0 bytes in 0 blocks -==5345== still reachable: 110,330 bytes in 3,223 blocks -==5345== suppressed: 0 bytes in 0 blocks -==5345== Reachable blocks (those to which a pointer was found) are not shown. -==5345== To see them, rerun with: --leak-check=full --show-leak-kinds=all -==5345== -==5345== For counts of detected and suppressed errors, rerun with: -v -==5345== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0) -.... - -This report was extracted from "index uniqueness checking" test and complains about -leaking memory in ovsdb-client application. The problem is not huge, since ovsdb-client -is CLI tool which is constantly reinvoked/restarted, thus leaked memory is not accumulated. - -More problematic issue is that for the same test valgrind reports the similar problem also for -ovsdb-server: - -.... -==5290== Memcheck, a memory error detector -==5290== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al. -==5290== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info -==5290== Command: ovsdb-server --log-file --detach --no-chdir --pidfile --private-key=/home/damijan.skvarc/doma/ovs/tests/testpki-privkey2.pem --certificate=/home/damijan.skvarc/doma/ovs/tests/testpki-cert2.pem --ca-cert=/home/damijan.skvarc/doma/ovs/tests/testpki-cacert.pem --remote=pssl:0:127.0.0.1 db -==5290== Parent PID: 5289 -==5290== -==5292== Warning: noted but unhandled ioctl 0x2403 with no size/direction hints. -==5292== This could cause spurious value errors to appear. -==5292== See README_MISSING_SYSCALL_OR_IOCTL for guidance on writing a proper wrapper. -==5292== Warning: noted but unhandled ioctl 0x2400 with no size/direction hints. -==5292== This could cause spurious value errors to appear. -==5292== See README_MISSING_SYSCALL_OR_IOCTL for guidance on writing a proper wrapper. -==5290== -==5290== HEAP SUMMARY: -==5290== in use at exit: 2,066 bytes in 48 blocks -==5290== total heap usage: 87 allocs, 39 frees, 14,152 bytes allocated -==5290== -==5290== LEAK SUMMARY: -==5290== definitely lost: 0 bytes in 0 blocks -==5290== indirectly lost: 0 bytes in 0 blocks -==5290== possibly lost: 0 bytes in 0 blocks -==5290== still reachable: 2,066 bytes in 48 blocks -==5290== suppressed: 0 bytes in 0 blocks -==5290== Reachable blocks (those to which a pointer was found) are not shown. -==5290== To see them, rerun with: --leak-check=full --show-leak-kinds=all -==5290== -==5290== For counts of detected and suppressed errors, rerun with: -v -==5290== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 1 from 1) -==5292== Warning: noted but unhandled ioctl 0x2401 with no size/direction hints. -==5292== This could cause spurious value errors to appear. -==5292== See README_MISSING_SYSCALL_OR_IOCTL for guidance on writing a proper wrapper. -==5292== -==5292== HEAP SUMMARY: -==5292== in use at exit: 164,018 bytes in 4,252 blocks -==5292== total heap usage: 17,910 allocs, 13,658 frees, 1,907,468 bytes allocated -==5292== -==5292== 49,720 (1,472 direct, 48,248 indirect) bytes in 8 blocks are definitely lost in loss record 580 of 580 -==5292== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) -==5292== by 0x5105E77: CRYPTO_malloc (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0) -==5292== by 0x51E1D23: ??? (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0) -==5292== by 0x51E4861: ??? (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0) -==5292== by 0x51E5414: ASN1_item_ex_d2i (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0) -==5292== by 0x51E546A: ASN1_item_d2i (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0) -==5292== by 0x4E53E00: ??? (in /lib/x86_64-linux-gnu/libssl.so.1.0.0) -==5292== by 0x4E55727: ??? (in /lib/x86_64-linux-gnu/libssl.so.1.0.0) -==5292== by 0x452C4B: ssl_connect (stream-ssl.c:530) -==5292== by 0x445B18: scs_connecting (stream.c:315) -==5292== by 0x445B18: stream_connect (stream.c:338) -==5292== by 0x445B91: stream_recv (stream.c:369) -==5292== by 0x432A9C: jsonrpc_recv.part.7 (jsonrpc.c:310) -==5292== by 0x433977: jsonrpc_recv (jsonrpc.c:1139) -==5292== by 0x433977: jsonrpc_session_recv (jsonrpc.c:1112) -==5292== by 0x40CCE3: ovsdb_jsonrpc_session_run (jsonrpc-server.c:553) -==5292== by 0x40CCE3: ovsdb_jsonrpc_session_run_all (jsonrpc-server.c:586) -==5292== by 0x40CCE3: ovsdb_jsonrpc_server_run (jsonrpc-server.c:401) -==5292== by 0x40682E: main_loop (ovsdb-server.c:209) -==5292== by 0x40682E: main (ovsdb-server.c:460) -==5292== -==5292== LEAK SUMMARY: -==5292== definitely lost: 1,472 bytes in 8 blocks -==5292== indirectly lost: 48,248 bytes in 936 blocks -==5292== possibly lost: 0 bytes in 0 blocks -==5292== still reachable: 114,298 bytes in 3,308 blocks -==5292== suppressed: 0 bytes in 0 blocks -==5292== Reachable blocks (those to which a pointer was found) are not shown. -==5292== To see them, rerun with: --leak-check=full --show-leak-kinds=all -==5292== -==5292== For counts of detected and suppressed errors, rerun with: -v -==5292== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 1 from 1) -.... - -In this case ovsdb-server is running as daemon process (--detach option) and leaking memory is -accumulated whenever ovsdb-client is reconnected. Within observed test ovsdb-client CLI tool -connects 8 times to ovsdb-server. Leaked memory in ovsdb-client (for each invocation) is approx. -6K bytes, while leaked memory in ovsdb-server is aprox. 48Kbytes what is actually 8*6K. Thus per -each connection both ovsdb-client and ovsdb-server leak approx. 6K bytes. - -I have done a small manual test to check if ovsdb-server is indeed accumulating leaked memory -by dumping ovsdb-server in a loop: - -console1: -ovsdb-server \ ---log-file \ ---detach --no-chdir --pidfile \ ---private-key=testpki-privkey2.pem \ ---certificate=testpki-cert2.pem \ ---ca-cert=testpki-cacert.pem \ ---remote=pssl:0:127.0.0.1 \ -db - -while (true); do \ -ovsdb-client \ ---private-key=testpki-privkey.pem \ ---certificate=testpki-cert.pem \ ---ca-cert=testpki-cacert.pem \ -dump ssl:127.0.0.1:42067; \ -done - -console2: -watch -n 0.5 'cat /proc/$(pidof ovsdb-server)/status | grep VmSize' - -In console2 it was evidently seen ovsdb-server is constantly leaking memory. After a while -(i.e. after a certain number of reconnections) the OOM killer jumps out and kills ovsdb-server. - -Very similar situation was already noticed and described in -https://github.com/openvswitch/ovs-issues/issues/168. There, the problem pops up while connecting -controller to ovs-vswitchd daemon. - -Valgrind reports point to a problem in openssl library, however after studying openssl code for -a while I have found out the problem is actually in ovs. When connection through SSL channel is -taken place openssl library allocates memory for keeping track of certificate. Reference to this -memory works very similar as std::shared_ptr pointer in recent C++ dialects. i.e. when allocated -memory is referenced its reference counter is incremented and decremented after the memory is -derefered. When reference counter becomes zero allocated memory is automatically deallocated. - -In openssl library environment certificate is retrieved by calling SSL_get_peer_certificate() -where its reference counter is incremented. After retrieved certificate is not used any more its -reference counter must be decremented by calling X509_free(). If not, allocated memory is never -freed despite the ssl connection is properly closed. - -The problem was caused in stream-ssl.c in function ssl_connect(), which retrieves common peer name -by calling SSL_get_peer_certificate() function and without calling X509_free() function afterwards. - -Signed-off-by: Damijan Skvarc -Signed-off-by: Ben Pfaff ---- - lib/stream-ssl.c | 13 +++++++++---- - 1 file changed, 9 insertions(+), 4 deletions(-) - -diff --git a/lib/stream-ssl.c b/lib/stream-ssl.c -index 723fde9ad..078fcbc3a 100644 ---- a/lib/stream-ssl.c -+++ b/lib/stream-ssl.c -@@ -470,6 +470,7 @@ do_ca_cert_bootstrap(struct stream *stream) - static char * - get_peer_common_name(const struct ssl_stream *sslv) - { -+ char *peer_name = NULL; - X509 *peer_cert = SSL_get_peer_certificate(sslv->ssl); - if (!peer_cert) { - return NULL; -@@ -478,18 +479,18 @@ get_peer_common_name(const struct ssl_stream *sslv) - int cn_index = X509_NAME_get_index_by_NID(X509_get_subject_name(peer_cert), - NID_commonName, -1); - if (cn_index < 0) { -- return NULL; -+ goto error; - } - - X509_NAME_ENTRY *cn_entry = X509_NAME_get_entry( - X509_get_subject_name(peer_cert), cn_index); - if (!cn_entry) { -- return NULL; -+ goto error; - } - - ASN1_STRING *cn_data = X509_NAME_ENTRY_get_data(cn_entry); - if (!cn_data) { -- return NULL; -+ goto error; - } - - const char *cn; -@@ -499,7 +500,11 @@ get_peer_common_name(const struct ssl_stream *sslv) - #else - cn = (const char *)ASN1_STRING_get0_data(cn_data); - #endif -- return xstrdup(cn); -+ peer_name = xstrdup(cn); -+ -+error: -+ X509_free(peer_cert); -+ return peer_name; - } - - static int --- -2.14.1 - - diff --git a/system-afxdp.at-Add-test-for-infinite-re-addition-of.patch b/system-afxdp.at-Add-test-for-infinite-re-addition-of.patch deleted file mode 100644 index 87534a0ec0d8d65ddf57c984d017abbb1ee51ac4..0000000000000000000000000000000000000000 --- a/system-afxdp.at-Add-test-for-infinite-re-addition-of.patch +++ /dev/null @@ -1,74 +0,0 @@ -From 1b3faafb1ee74ff5bc877bf0ef3097ce4d77f8ef Mon Sep 17 00:00:00 2001 -From: Ilya Maximets -Date: Sat, 7 Dec 2019 15:46:18 +0100 -Subject: system-afxdp.at: Add test for infinite re-addition of failed ports. - -New file created for AF_XDP specific tests. - -Signed-off-by: Ilya Maximets -Acked-by: William Tu ---- - tests/automake.mk | 3 ++- - tests/system-afxdp-testsuite.at | 1 + - tests/system-afxdp.at | 24 ++++++++++++++++++++++++ - 3 files changed, 27 insertions(+), 1 deletion(-) - create mode 100644 tests/system-afxdp.at - -diff --git a/tests/automake.mk b/tests/automake.mk -index d6ab51732..657fd690e 100644 ---- a/tests/automake.mk -+++ b/tests/automake.mk -@@ -165,7 +165,8 @@ SYSTEM_USERSPACE_TESTSUITE_AT = \ - SYSTEM_AFXDP_TESTSUITE_AT = \ - tests/system-userspace-macros.at \ - tests/system-afxdp-testsuite.at \ -- tests/system-afxdp-macros.at -+ tests/system-afxdp-macros.at \ -+ tests/system-afxdp.at - - SYSTEM_TESTSUITE_AT = \ - tests/system-common-macros.at \ -diff --git a/tests/system-afxdp-testsuite.at b/tests/system-afxdp-testsuite.at -index 9b7a29066..01c1bf50c 100644 ---- a/tests/system-afxdp-testsuite.at -+++ b/tests/system-afxdp-testsuite.at -@@ -23,4 +23,5 @@ m4_include([tests/system-common-macros.at]) - m4_include([tests/system-userspace-macros.at]) - m4_include([tests/system-afxdp-macros.at]) - -+m4_include([tests/system-afxdp.at]) - m4_include([tests/system-traffic.at]) -diff --git a/tests/system-afxdp.at b/tests/system-afxdp.at -new file mode 100644 -index 000000000..e4451624f ---- /dev/null -+++ b/tests/system-afxdp.at -@@ -0,0 +1,24 @@ -+AT_BANNER([AF_XDP]) -+ -+AT_SETUP([AF_XDP - infinite re-addition of failed ports]) -+AT_KEYWORDS([afxdp infinite]) -+OVS_TRAFFIC_VSWITCHD_START() -+ -+AT_CHECK([ovs-ofctl add-flow br0 "actions=normal"]) -+ -+ADD_NAMESPACES(at_ns0, at_ns1) -+ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24") -+ -+AT_CHECK([ovs-vsctl del-port ovs-p0]) -+AT_CHECK([ovs-vsctl add-port br0 ovs-p0 -- \ -+ set interface ovs-p0 type=afxdp options:n_rxq=42], -+ [0], [], [stderr]) -+OVS_WAIT_UNTIL([grep "ovs-p0: could not set configuration" ovs-vswitchd.log]) -+sleep 5 -+AT_CHECK([grep "ovs-p0: could not set configuration" ovs-vswitchd.log | wc -l], -+ [0], [1 -+]) -+ -+OVS_TRAFFIC_VSWITCHD_STOP(["/ovs-p0: Too big 'n_rxq'/d -+/ovs-p0: could not set configuration/d"]) -+AT_CLEANUP --- -2.14.1 - - diff --git a/tc-Limit-the-max-action-number-to-16.patch b/tc-Limit-the-max-action-number-to-16.patch deleted file mode 100644 index 9b82f76fcebc481801eae22a8f2367b6da2f2ae8..0000000000000000000000000000000000000000 --- a/tc-Limit-the-max-action-number-to-16.patch +++ /dev/null @@ -1,87 +0,0 @@ -From 92f6c44a92cc3247db94fd5fe86bf7e5cb896a91 Mon Sep 17 00:00:00 2001 -From: Chris Mi -Date: Wed, 16 Oct 2019 11:37:14 +0300 -Subject: tc: Limit the max action number to 16 - -Currently, ovs supports to offload max TCA_ACT_MAX_PRIO(32) actions. -But net sched api has a limit of 4K message size which is not enough -for 32 actions when echo flag is set. - -After a lot of testing, we find that 16 actions is a reasonable number. -So in this commit, we introduced a new define to limit the max actions. - -Fixes: 0c70132cd288("tc: Make the actions order consistent") -Signed-off-by: Chris Mi -Reviewed-by: Roi Dayan -Signed-off-by: Simon Horman ---- - lib/netdev-offload-tc.c | 4 ++-- - lib/tc.c | 6 +++--- - lib/tc.h | 4 +++- - 3 files changed, 8 insertions(+), 6 deletions(-) - -diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c -index 4cc044b4b..ad637b48c 100644 ---- a/lib/netdev-offload-tc.c -+++ b/lib/netdev-offload-tc.c -@@ -1303,8 +1303,8 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, - } - - NL_ATTR_FOR_EACH(nla, left, actions, actions_len) { -- if (flower.action_count >= TCA_ACT_MAX_PRIO) { -- VLOG_DBG_RL(&rl, "Can only support %d actions", flower.action_count); -+ if (flower.action_count >= TCA_ACT_MAX_NUM) { -+ VLOG_DBG_RL(&rl, "Can only support %d actions", TCA_ACT_MAX_NUM); - return EOPNOTSUPP; - } - action = &flower.actions[flower.action_count]; -diff --git a/lib/tc.c b/lib/tc.c -index 1eca35620..71418b3f3 100644 ---- a/lib/tc.c -+++ b/lib/tc.c -@@ -1362,7 +1362,7 @@ static int - nl_parse_flower_actions(struct nlattr **attrs, struct tc_flower *flower) - { - const struct nlattr *actions = attrs[TCA_FLOWER_ACT]; -- static struct nl_policy actions_orders_policy[TCA_ACT_MAX_PRIO + 1] = {}; -+ static struct nl_policy actions_orders_policy[TCA_ACT_MAX_NUM + 1] = {}; - struct nlattr *actions_orders[ARRAY_SIZE(actions_orders_policy)]; - const int max_size = ARRAY_SIZE(actions_orders_policy); - -@@ -1381,8 +1381,8 @@ nl_parse_flower_actions(struct nlattr **attrs, struct tc_flower *flower) - if (actions_orders[i]) { - int err; - -- if (flower->action_count >= TCA_ACT_MAX_PRIO) { -- VLOG_DBG_RL(&error_rl, "Can only support %d actions", flower->action_count); -+ if (flower->action_count >= TCA_ACT_MAX_NUM) { -+ VLOG_DBG_RL(&error_rl, "Can only support %d actions", TCA_ACT_MAX_NUM); - return EOPNOTSUPP; - } - err = nl_parse_single_action(actions_orders[i], flower); -diff --git a/lib/tc.h b/lib/tc.h -index 2e0f5e37a..b7c977a14 100644 ---- a/lib/tc.h -+++ b/lib/tc.h -@@ -197,6 +197,8 @@ enum tc_offloaded_state { - TC_OFFLOADED_STATE_NOT_IN_HW, - }; - -+#define TCA_ACT_MAX_NUM 16 -+ - struct tc_flower { - uint32_t handle; - uint32_t prio; -@@ -205,7 +207,7 @@ struct tc_flower { - struct tc_flower_key mask; - - int action_count; -- struct tc_action actions[TCA_ACT_MAX_PRIO]; -+ struct tc_action actions[TCA_ACT_MAX_NUM]; - - struct ovs_flow_stats stats; - uint64_t lastused; --- -2.14.1 - - diff --git a/tests-Fix-indentation-in-userspace-packet-type-aware.patch b/tests-Fix-indentation-in-userspace-packet-type-aware.patch deleted file mode 100644 index 2256fa41e0d6b09cb9853a03cad730ae6ae346df..0000000000000000000000000000000000000000 --- a/tests-Fix-indentation-in-userspace-packet-type-aware.patch +++ /dev/null @@ -1,93 +0,0 @@ -From 3d844530afca789a71e46076babf9cc09325c4bc Mon Sep 17 00:00:00 2001 -From: Ilya Maximets -Date: Thu, 24 Oct 2019 12:28:50 +0000 -Subject: tests: Fix indentation in userspace packet type aware test. - -CC: Ben Pfaff -Fixes: 7be29a47576d ("ofproto-dpif: Remove tabs from output.") -Signed-off-by: Ilya Maximets -Acked-by: Ben Pfaff ---- - tests/system-userspace-packet-type-aware.at | 64 ++++++++++++++--------------- - 1 file changed, 32 insertions(+), 32 deletions(-) - -diff --git a/tests/system-userspace-packet-type-aware.at b/tests/system-userspace-packet-type-aware.at -index 24a7698ab..c2246316d 100644 ---- a/tests/system-userspace-packet-type-aware.at -+++ b/tests/system-userspace-packet-type-aware.at -@@ -252,39 +252,39 @@ AT_CHECK([ - - ### Verify datapath configuration - AT_CHECK([ -- ovs-appctl dpif/show | grep -v hit | sed 's/\t/ /g' -+ ovs-appctl dpif/show | grep -v hit - ], [0], [dnl -- br-in1: -- br-in1 65534/2: (tap) -- gre12 1020/14: (gre: remote_ip=10.0.0.2) -- gre12_l3 1021/14: (gre: packet_type=legacy_l3, remote_ip=10.0.0.2) -- gre13 1030/14: (gre: remote_ip=10.0.0.3) -- ovs-n1 10/15: (system) -- br-in2: -- br-in2 65534/3: (tap) -- gre21 2010/14: (gre: packet_type=ptap, remote_ip=20.0.0.1) -- gre23 2030/14: (gre: packet_type=ptap, remote_ip=20.0.0.3) -- ovs-n2 20/16: (system) -- br-in3: -- br-in3 65534/4: (tap) -- gre31 3010/14: (gre: remote_ip=30.0.0.1) -- gre32 3020/14: (gre: remote_ip=30.0.0.2) -- gre32_l3 3021/14: (gre: packet_type=legacy_l3, remote_ip=30.0.0.2) -- ovs-n3 30/17: (system) -- br-p1: -- br-p1 65534/5: (tap) -- p1-0 2/8: (system) -- br-p2: -- br-p2 65534/6: (tap) -- p2-0 2/9: (system) -- br-p3: -- br-p3 65534/7: (tap) -- p3-0 2/10: (system) -- br0: -- br0 65534/1: (tap) -- p0-1 10/11: (system) -- p0-2 20/12: (system) -- p0-3 30/13: (system) -+ br-in1: -+ br-in1 65534/2: (tap) -+ gre12 1020/14: (gre: remote_ip=10.0.0.2) -+ gre12_l3 1021/14: (gre: packet_type=legacy_l3, remote_ip=10.0.0.2) -+ gre13 1030/14: (gre: remote_ip=10.0.0.3) -+ ovs-n1 10/15: (system) -+ br-in2: -+ br-in2 65534/3: (tap) -+ gre21 2010/14: (gre: packet_type=ptap, remote_ip=20.0.0.1) -+ gre23 2030/14: (gre: packet_type=ptap, remote_ip=20.0.0.3) -+ ovs-n2 20/16: (system) -+ br-in3: -+ br-in3 65534/4: (tap) -+ gre31 3010/14: (gre: remote_ip=30.0.0.1) -+ gre32 3020/14: (gre: remote_ip=30.0.0.2) -+ gre32_l3 3021/14: (gre: packet_type=legacy_l3, remote_ip=30.0.0.2) -+ ovs-n3 30/17: (system) -+ br-p1: -+ br-p1 65534/5: (tap) -+ p1-0 2/8: (system) -+ br-p2: -+ br-p2 65534/6: (tap) -+ p2-0 2/9: (system) -+ br-p3: -+ br-p3 65534/7: (tap) -+ p3-0 2/10: (system) -+ br0: -+ br0 65534/1: (tap) -+ p0-1 10/11: (system) -+ p0-2 20/12: (system) -+ p0-3 30/13: (system) - ]) - - ### Test L3 forwarding flows --- -2.14.1 - - diff --git a/travis-Drop-MD-related-workaround-for-sparse.patch b/travis-Drop-MD-related-workaround-for-sparse.patch deleted file mode 100644 index 7a0ee4f83e528fa712b12ef7aa2a33f36ba1bd99..0000000000000000000000000000000000000000 --- a/travis-Drop-MD-related-workaround-for-sparse.patch +++ /dev/null @@ -1,36 +0,0 @@ -From e92cfbf246df1b0cd48e17de75edcb724efe5620 Mon Sep 17 00:00:00 2001 -From: Ilya Maximets -Date: Thu, 26 Sep 2019 12:03:09 +0300 -Subject: travis: Drop -MD related workaround for sparse. - -The issue was fixed in upstream sparse by the following commit: -d90c0838c101 ("cgcc: fix wrong processing of -MD & -MMD") - -This patch is required to fix our travis build. - -Signed-off-by: Ilya Maximets -Acked-by: Ian Stokes ---- - .travis/linux-prepare.sh | 5 ----- - 1 file changed, 5 deletions(-) - -diff --git a/.travis/linux-prepare.sh b/.travis/linux-prepare.sh -index 65348c9f9..70fd98f71 100755 ---- a/.travis/linux-prepare.sh -+++ b/.travis/linux-prepare.sh -@@ -9,11 +9,6 @@ set -ev - # linking against it fails. - git clone git://git.kernel.org/pub/scm/devel/sparse/sparse.git - cd sparse --# Commit bb1bf748580d ("cgcc: gendeps for -MM, -MD & -MMD too") makes --# sparse ignore almost all source files, because 'make' uses '-MD' to --# generate dependencies as a side effect within compilation commands. --git revert bb1bf748580d --no-commit --git diff HEAD - make -j4 HAVE_LLVM= install - cd .. - --- -2.14.1 - - diff --git a/trigger-Free-leaked-ovsdb_schema.patch b/trigger-Free-leaked-ovsdb_schema.patch deleted file mode 100644 index 44e0347b1a2edaed5001a3a36f2a92cf64964acf..0000000000000000000000000000000000000000 --- a/trigger-Free-leaked-ovsdb_schema.patch +++ /dev/null @@ -1,51 +0,0 @@ -From e345c75b4413e6bdbc0d47df5da35bfd426d8788 Mon Sep 17 00:00:00 2001 -From: Yifeng Sun -Date: Wed, 11 Sep 2019 14:18:31 -0700 -Subject: trigger: Free leaked ovsdb_schema - -Valgrind reported: - -1925: schema conversion online - standalone - -==10884== 689 (56 direct, 633 indirect) bytes in 1 blocks are definitely lost in loss record 384 of 420 -==10884== at 0x4C2FB55: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) -==10884== by 0x44A592: xcalloc (util.c:121) -==10884== by 0x40E2EC: ovsdb_schema_create (ovsdb.c:41) -==10884== by 0x40E688: ovsdb_schema_from_json (ovsdb.c:217) -==10884== by 0x416C6F: ovsdb_trigger_try (trigger.c:246) -==10884== by 0x40D4DE: ovsdb_jsonrpc_trigger_create (jsonrpc-server.c:1119) -==10884== by 0x40D4DE: ovsdb_jsonrpc_session_got_request (jsonrpc-server.c:986) -==10884== by 0x40D4DE: ovsdb_jsonrpc_session_run (jsonrpc-server.c:556) -==10884== by 0x40D4DE: ovsdb_jsonrpc_session_run_all (jsonrpc-server.c:586) -==10884== by 0x40D4DE: ovsdb_jsonrpc_server_run (jsonrpc-server.c:401) -==10884== by 0x406A6E: main_loop (ovsdb-server.c:209) -==10884== by 0x406A6E: main (ovsdb-server.c:460) - -'new_schema' should also be freed when there is no error. -This patch fixes it. - -Acked-by: William Tu -Signed-off-by: Yifeng Sun -Signed-off-by: Ben Pfaff ---- - ovsdb/trigger.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ovsdb/trigger.c b/ovsdb/trigger.c -index 6f4ed96b0..7e62e90ae 100644 ---- a/ovsdb/trigger.c -+++ b/ovsdb/trigger.c -@@ -254,8 +254,8 @@ ovsdb_trigger_try(struct ovsdb_trigger *t, long long int now) - if (!error) { - error = ovsdb_convert(t->db, new_schema, &newdb); - } -+ ovsdb_schema_destroy(new_schema); - if (error) { -- ovsdb_schema_destroy(new_schema); - trigger_convert_error(t, error); - return false; - } --- -2.14.1 - - diff --git a/vswitch.xml-Fix-column-for-xdpmode.patch b/vswitch.xml-Fix-column-for-xdpmode.patch deleted file mode 100644 index 962b673a9126913a44bd53a5a34f39dd4590d912..0000000000000000000000000000000000000000 --- a/vswitch.xml-Fix-column-for-xdpmode.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 7accd13028f1b7d7d6cdd50ffec2657142832527 Mon Sep 17 00:00:00 2001 -From: Ilya Maximets -Date: Tue, 5 Nov 2019 21:54:08 +0100 -Subject: vswitch.xml: Fix column for xdpmode. - -'xdpmode' is part of 'options', not the 'other_config'. - -CC: William Tu -Fixes: 0de1b425962d ("netdev-afxdp: add new netdev type for AF_XDP.") -Signed-off-by: Ilya Maximets -Acked-by: Ben Pfaff -Signed-off-by: William Tu ---- - vswitchd/vswitch.xml | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml -index 027aee2f5..69dbe460f 100644 ---- a/vswitchd/vswitch.xml -+++ b/vswitchd/vswitch.xml -@@ -3107,7 +3107,7 @@ ovs-vsctl add-port br0 p0 -- set Interface p0 type=patch options:peer=p1 \ -

- - -- -

--- -2.14.1 - -