diff --git a/ovs.patch b/ovs.patch
deleted file mode 100644
index dda8a68c1ac57c3f30a84906d02e6bc6c65d6fb4..0000000000000000000000000000000000000000
--- a/ovs.patch
+++ /dev/null
@@ -1,5360 +0,0 @@
-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/automake.mk b/openvswitch-2.14.2/lib/automake.mk
-index 380a672..8c926fc 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 \
-@@ -454,6 +455,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 +603,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.c b/openvswitch-2.14.2/lib/conntrack.c
-index 6938dcb..17804df 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->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->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;
-@@ -1295,7 +1315,7 @@ process_one(struct conntrack *ct, struct dp_packet *pkt,
- if (OVS_UNLIKELY(force && ctx->reply && conn)) {
- ovs_mutex_lock(&ct->ct_lock);
- if (conn_lookup(ct, &conn->key, now, NULL, NULL)) {
-- conn_clean(ct, conn);
-+ conn_clean(ct, conn);
- }
- ovs_mutex_unlock(&ct->ct_lock);
- conn = NULL;
-@@ -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->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
-@@ -1494,6 +1521,13 @@ ct_sweep(struct conntrack *ct, long long now, size_t limit)
- for (unsigned i = 0; i < N_CT_TM; i++) {
- LIST_FOR_EACH_SAFE (conn, next, exp_node, &ct->exp_lists[i]) {
- ovs_mutex_lock(&conn->lock);
-+#ifdef HAVE_HWOFF_AGENT
-+ if (now < conn->expiration) {
-+ if (ct->offload_class) {
-+ ct->offload_class->update_conn_statistics(conn);
-+ }
-+ }
-+#endif
- if (now < conn->expiration || count >= limit) {
- min_expiration = MIN(min_expiration, conn->expiration);
- ovs_mutex_unlock(&conn->lock);
-@@ -1657,6 +1691,55 @@ extract_l3_ipv6(struct conn_key *key, const void *data, size_t size,
- return true;
- }
-
-+#ifdef HAVE_HWOFF_AGENT
-+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 (size < sizeof *tcp) {
-+ return false;
-+ }
-+
-+ size_t tcp_len = TCP_OFFSET(tcp->tcp_ctl) * 4;
-+ if (OVS_UNLIKELY(tcp_len < TCP_HEADER_LEN || tcp_len > size)) {
-+ return false;
-+ }
-+
-+ return true;
-+}
-+
-+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 (size < sizeof *udp) {
-+ return false;
-+ }
-+
-+ size_t udp_len = ntohs(udp->udp_len);
-+ if (OVS_UNLIKELY(udp_len < UDP_HEADER_LEN || udp_len > 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 +1808,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 +2071,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 +2172,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 +2445,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 +2561,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 +2581,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;
-diff --git a/openvswitch-2.14.2/lib/ct-dpif.c b/openvswitch-2.14.2/lib/ct-dpif.c
-index 8c2480e..a55dc81 100644
---- a/openvswitch-2.14.2/lib/ct-dpif.c
-+++ b/openvswitch-2.14.2/lib/ct-dpif.c
-@@ -328,6 +328,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..874c559 100644
---- a/openvswitch-2.14.2/lib/ct-dpif.h
-+++ b/openvswitch-2.14.2/lib/ct-dpif.h
-@@ -197,6 +197,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 {
-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..196021e
---- /dev/null
-+++ b/openvswitch-2.14.2/lib/ct_dump_extend/ct_dump_extend.c
-@@ -0,0 +1,188 @@
-+/*
-+ * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
-+ * Description: dump conntrack extend implementations
-+ * Author: huawei
-+ * 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 MAX_CT_FLOWS_DUMP_ONCE (5000)
-+
-+enum dump_ct_status {
-+ DUMP_CT_RUNNING,
-+ DUMP_CT_STOP,
-+};
-+
-+struct dump_ct_mgmt {
-+ FILE *file;
-+ char file_name[PATH_MAX];
-+ bool verbose;
-+ bool print_stats;
-+ uint32_t cnt;
-+ uint16_t zone;
-+ const uint16_t *pzone;
-+ atomic_count dumping;
-+ pthread_t thread;
-+ pthread_mutex_t mutex;
-+ struct ct_dpif_dump_state *dump_state;
-+ struct dpif *dpif;
-+};
-+
-+VLOG_DEFINE_THIS_MODULE(ct_dump_extend);
-+
-+static struct dump_ct_mgmt g_dump_mgmt = {
-+ .verbose = false,
-+ .print_stats = false,
-+ .cnt = 0,
-+ .dumping = ATOMIC_COUNT_INIT(DUMP_CT_STOP),
-+ .file = NULL,
-+ .dump_state = NULL,
-+ .zone = 0,
-+ .pzone = NULL,
-+};
-+
-+static void
-+ct_dump_to_file_stop(void)
-+{
-+ struct dump_ct_mgmt *m = &g_dump_mgmt;
-+
-+ if (m->dump_state != NULL) {
-+ ct_dpif_dump_done(m->dump_state);
-+ m->dump_state = NULL;
-+ }
-+
-+ if (m->file != NULL) {
-+ fclose(m->file);
-+ m->file = NULL;
-+ }
-+
-+ if (m->dpif != NULL) {
-+ dpif_close(m->dpif);
-+ m->dpif = NULL;
-+ }
-+
-+ atomic_count_set(&m->dumping, DUMP_CT_STOP);
-+}
-+
-+static int
-+ct_dump_open_file(const char *file_name, struct ds *ds)
-+{
-+ struct dump_ct_mgmt *m = &g_dump_mgmt;
-+
-+ if (file_name[0] != '/') {
-+ ds_put_format(ds, "file name \"%s\"error: Need absolute path\n", file_name);
-+ return -1;
-+ }
-+
-+ m->file = fopen(file_name, "w+");
-+ if (m->file == NULL) {
-+ ds_put_format(ds, "can not open file :%s\n", file_name);
-+ return -1;
-+ }
-+
-+ return 0;
-+};
-+
-+static void ct_dump_to_file_run(void)
-+{
-+ int ret = 0;
-+ int i = 0;
-+ struct ct_dpif_entry cte;
-+ struct dump_ct_mgmt *m = &g_dump_mgmt;
-+ struct ds s = DS_EMPTY_INITIALIZER;
-+ int tot_bkts;
-+
-+ ret = ct_dpif_dump_start(m->dpif, &m->dump_state, m->pzone, &tot_bkts);
-+ if (ret != 0) {
-+ VLOG_ERR("starting conntrack dump error\n");
-+ ct_dump_to_file_stop();
-+ return;
-+ }
-+ ret = ct_dump_open_file(m->file_name, &s);
-+ if (ret != 0) {
-+ ds_destroy(&s);
-+ ct_dump_to_file_stop();
-+ return;
-+ }
-+
-+ m->cnt = 0;
-+ for (;;) {
-+ if (ct_dpif_dump_next(m->dump_state, &cte)) {
-+ VLOG_INFO("dump ct to file end !");
-+ ret = fwrite(ds_cstr(&s), strlen(ds_cstr(&s)), 1, m->file);
-+ if ((ret != 1) && (ferror(m->file) != 0)) {
-+ VLOG_WARN("dump ct to file end failed ! ret %d\n", ret);
-+ };
-+ break;
-+ }
-+ ct_dpif_format_entry(&cte, &s, m->verbose,
-+ m->print_stats);
-+ ct_dpif_entry_uninit(&cte);
-+ ds_put_format(&s, "\n");
-+ i++;
-+ if (i == MAX_CT_FLOWS_DUMP_ONCE) {
-+ ret = fwrite(ds_cstr(&s), strlen(ds_cstr(&s)), 1, m->file);
-+ if ((ret != 1) && (ferror(m->file) != 0)) {
-+ VLOG_WARN("dump ct to file failed ! ret %d\n", ret);
-+ break;
-+ }
-+ ds_clear(&s);
-+ m->cnt += MAX_CT_FLOWS_DUMP_ONCE;
-+ i = 0;
-+ }
-+ }
-+
-+ ds_destroy(&s);
-+ ct_dump_to_file_stop();
-+}
-+
-+int
-+ct_dump_to_file(struct ct_dump_extend *dump)
-+{
-+ struct dump_ct_mgmt *m = &g_dump_mgmt;
-+
-+ pthread_mutex_lock(&m->mutex);
-+ if (DUMP_CT_STOP != atomic_count_get(&m->dumping)) {
-+ ds_put_format(dump->ds, "dump all ct flows is busy, please try again after a moment\n");
-+ pthread_mutex_unlock(&m->mutex);
-+ return -1;
-+ }
-+ atomic_count_set(&m->dumping, DUMP_CT_RUNNING);
-+ pthread_mutex_unlock(&m->mutex);
-+
-+ 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;
-+ }
-+ memset(m->file_name, 0, PATH_MAX);
-+ strncpy(m->file_name, dump->file_name, PATH_MAX - 1);
-+ m->verbose = dump->verbose;
-+ m->print_stats = dump->print_stats;
-+ m->dpif = dump->dpif;
-+ if (dump->pzone != NULL) {
-+ m->zone = *dump->pzone;
-+ m->pzone = &m->zone;
-+ }
-+ ds_put_format(dump->ds, "starting dump ct into file: %s.\n", dump->file_name);
-+ m->thread = ovs_thread_create("ct_dump", (void *)ct_dump_to_file_run, NULL);
-+ VLOG_INFO("dump thread created thread id=%lu", m->thread);
-+ 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..6abc6d8
---- /dev/null
-+++ b/openvswitch-2.14.2/lib/ct_dump_extend/ct_dump_extend.h
-@@ -0,0 +1,22 @@
-+/*
-+ * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
-+ * Description: dump conntrack extend definitions
-+ * Author: huawei
-+ * Create: 2022-03-24
-+ *
-+ */
-+#ifndef _CT_DUMP_EXTEND_CT_H_
-+#define _CT_DUMP_EXTEND_CT_H_
-+
-+struct ct_dump_extend {
-+ bool verbose;
-+ bool print_stats;
-+ const char *file_name;
-+ const uint16_t *pzone;
-+ struct ds *ds;
-+ struct dpif *dpif;
-+};
-+
-+int ct_dump_to_file(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..b4244db
---- /dev/null
-+++ b/openvswitch-2.14.2/lib/ct_offload_provider.h
-@@ -0,0 +1,36 @@
-+/*
-+ * Copyright (c) Huawei Technologies Co., Ltd. 2021-2021. All rights reserved.
-+ * Description: ct_offload_privider
-+ * Author: lch
-+ * Create: 2021-07-09
-+ * History: 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);
-+} 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..d503ba9 100644
---- a/openvswitch-2.14.2/lib/dp-packet.h
-+++ b/openvswitch-2.14.2/lib/dp-packet.h
-@@ -58,29 +58,29 @@ enum OVS_PACKED_ENUM dp_packet_source {
- enum dp_packet_offload_mask {
- /* Value 0 is not used. */
- /* Is the 'rss_hash' valid? */
-- DEF_OL_FLAG(DP_PACKET_OL_RSS_HASH, PKT_RX_RSS_HASH, 0x1),
-+ 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, PKT_RX_FDIR_ID, 0x2),
-+ 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, PKT_RX_L4_CKSUM_BAD, 0x4),
-+ 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, PKT_RX_IP_CKSUM_BAD, 0x8),
-+ 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, PKT_RX_L4_CKSUM_GOOD, 0x10),
-+ 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, PKT_RX_IP_CKSUM_GOOD, 0x20),
-+ 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, PKT_TX_TCP_SEG, 0x40),
-+ 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, PKT_TX_IPV4, 0x80),
-+ 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, PKT_TX_IPV6, 0x100),
-+ 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, PKT_TX_TCP_CKSUM, 0x200),
-+ 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, PKT_TX_UDP_CKSUM, 0x400),
-+ 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, PKT_TX_SCTP_CKSUM, 0x800),
-+ 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. */
- };
-
-@@ -558,6 +558,40 @@ 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
-+dp_nolinear_packet_set_size(struct dp_packet *b, uint32_t v)
-+{
-+ if (v < b->mbuf.pkt_len) {
-+ b->mbuf.data_len -= (b->mbuf.pkt_len - v);
-+ } else if (v > b->mbuf.pkt_len) {
-+ b->mbuf.data_len += (v - b->mbuf.pkt_len);
-+ }
-+
-+ 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) {
-+ return dp_nolinear_packet_set_size(b, v);
-+ }
-+
-+ /* Current seg length. */
-+ rte_pktmbuf_data_len(&(b->mbuf)) = v;
-+ /* Total length of all segments linked to this segment. */
-+ rte_pktmbuf_pkt_len(&(b->mbuf)) = v;
-+}
-+
-+#else
-+
- static inline uint32_t
- dp_packet_size(const struct dp_packet *b)
- {
-@@ -579,6 +613,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..8539d38 100644
---- a/openvswitch-2.14.2/lib/dpctl.c
-+++ b/openvswitch-2.14.2/lib/dpctl.c
-@@ -51,6 +51,9 @@
- #include "util.h"
- #include "openvswitch/ofp-flow.h"
- #include "openvswitch/ofp-port.h"
-+#ifdef HAVE_HWOFF_AGENT
-+#include "ct_dump_extend/ct_dump_extend.h"
-+#endif
-
- typedef int dpctl_command_handler(int argc, const char *argv[],
- struct dpctl_params *);
-@@ -811,6 +814,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 +1429,16 @@ dpctl_dump_conntrack(int argc, const char *argv[],
- int tot_bkts;
- struct dpif *dpif;
- int error;
-+#ifdef HAVE_HWOFF_AGENT
-+ bool dump_file = false;
-+ const char *file_name = NULL;
-+
-+ if (argc >= 2 && (strncmp(argv[argc - 2], "-w", sizeof("-w")) == 0)) {
-+ dump_file = true;
-+ file_name = argv[argc - 1];
-+ argc -= 2;
-+ }
-+#endif
-
- if (argc > 1 && ovs_scan(argv[argc - 1], "zone=%"SCNu16, &zone)) {
- pzone = &zone;
-@@ -1432,6 +1450,30 @@ dpctl_dump_conntrack(int argc, const char *argv[],
- return error;
- }
-
-+#ifdef HAVE_HWOFF_AGENT
-+ if (dump_file) {
-+ struct ds d = DS_EMPTY_INITIALIZER;
-+ struct ct_dump_extend ct_dump = {
-+ .file_name = file_name,
-+ .verbose = dpctl_p->verbosity,
-+ .print_stats = dpctl_p->print_statistics,
-+ .dpif = dpif,
-+ .pzone = pzone,
-+ .ds = &d,
-+ };
-+ error = ct_dump_to_file(&ct_dump);
-+ if (error) {
-+ dpctl_print(dpctl_p, "%s\n", ds_cstr(&d));
-+ ds_destroy(&d);
-+ dpif_close(dpif);
-+ return error;
-+ }
-+ dpctl_print(dpctl_p, "%s\n", ds_cstr(&d));
-+ ds_destroy(&d);
-+ return error;
-+ }
-+#endif
-+
- error = ct_dpif_dump_start(dpif, &dump, pzone, &tot_bkts);
- if (error) {
- dpctl_error(dpctl_p, error, "starting conntrack dump");
-@@ -2529,8 +2571,13 @@ 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 },
-+#else
- { "dump-conntrack", "[-m] [-s] [dp] [zone=N]",
- 0, 4, dpctl_dump_conntrack, DP_RO },
-+#endif
- { "flush-conntrack", "[dp] [zone=N] [ct-tuple]", 0, 3,
- dpctl_flush_conntrack, DP_RW },
- { "ct-stats-show", "[dp] [zone=N]",
-@@ -2675,6 +2722,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..f8437db 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,9 +351,17 @@ dpdk_unixctl_log_set(struct unixctl_conn *conn, int argc, const char *argv[],
- }
-
- level = dpdk_parse_log_level(level_string);
-+#ifdef HAVE_HWOFF_AGENT
-+ hwoff_func* funcs = hwoff_get_funcs();
-+#endif
- if (level == -1) {
- err_msg = xasprintf("invalid log level: '%s'", level_string);
-+#ifdef HAVE_HWOFF_AGENT
-+ } else if (rte_log_set_level_pattern(pattern, level) < 0 ||
-+ (funcs && funcs->hwoff_set_module_log_level(pattern, level) < 0)) {
-+#else
- } else if (rte_log_set_level_pattern(pattern, level) < 0) {
-+#endif
- err_msg = xasprintf("cannot set log level for '%s'", argv[i]);
- }
-
-@@ -356,6 +376,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 +599,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..bd1c190 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,144 @@ 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.
-+*/
-+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 (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 +2862,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 +2898,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 +2998,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 +3011,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 +3035,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 +3670,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 +3880,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 +3944,109 @@ dp_netdev_flow_add(struct dp_netdev_pmd_thread *pmd,
- return flow;
- }
-
-+
-+#ifdef HAVE_HWOFF_AGENT
-+static bool
-+is_clear_reverse_flow_needed(struct dp_netdev_flow *netdev_flow, struct eth_addr *temp_mac)
-+{
-+ struct migrate_rarp_mac_entry *e = NULL;
-+ bool clear_reverse_flow = false;
-+ struct migrate_rarp_macs *hwoff_rarp_record = hwoff_rarp_record_get();
-+ if (rarp_record_status_get()) {
-+ ovs_rwlock_wrlock(&hwoff_rarp_record->rwlock);
-+ if (unlikely(hwoff_rarp_record->count)) {
-+ e = rarp_mac_lookup(netdev_flow->flow.dl_dst);
-+ if (e && e->need_del_flow) {
-+ rarp_mac_remove(e);
-+ (void)memcpy(&temp_mac->ea, &netdev_flow->flow.dl_dst.ea, RTE_ETHER_ADDR_LEN);
-+ clear_reverse_flow = true;
-+ }
-+ }
-+ ovs_rwlock_unlock(&hwoff_rarp_record->rwlock);
-+ }
-+ return clear_reverse_flow;
-+}
-+
-+static bool
-+is_clear_forward_flow_needed(struct dp_netdev_flow *netdev_flow,
-+ struct eth_addr *temp_mac, uint32_t *dp_in_port)
-+{
-+ struct migrate_rarp_mac_entry *e = NULL;
-+ bool clear_flow = false;
-+ struct migrate_rarp_macs *hwoff_rarp_record = hwoff_rarp_record_get();
-+ if (netdev_flow == NULL) {
-+ return false;
-+ }
-+ if (rarp_record_status_get()) {
-+ ovs_rwlock_wrlock(&hwoff_rarp_record->rwlock);
-+ if (unlikely(hwoff_rarp_record->count)) {
-+ e = rarp_mac_lookup(netdev_flow->flow.dl_src);
-+ if (e && e->need_del_flow) {
-+ rarp_mac_remove(e);
-+ (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_rarp_record->rwlock);
-+ }
-+ 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 (rarp_record_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 (rarp_record_status_get() && is_clear_forward_flow_needed(flow, &temp_mac, &dp_in_port)) {
-+ dp_netdev_clear_flow(pmd, temp_mac, dp_in_port);
-+ }
-+}
-+
-+static void
-+dp_netdev_clear_reverse_flow_by_smac(struct dp_netdev_pmd_thread *pmd, struct eth_addr smac)
-+{
-+ 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 (rarp_record_status_get() && eth_addr_equals(netdev_flow->flow.dl_src, smac) &&
-+ !eth_addr_is_broadcast(netdev_flow->flow.dl_dst)) {
-+ 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);
-+ }
-+}
-+#endif
-+
- static int
- flow_put_on_pmd(struct dp_netdev_pmd_thread *pmd,
- struct netdev_flow_key *key,
-@@ -3748,7 +4057,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 +4082,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 +4109,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;
- }
-
-@@ -3890,6 +4201,28 @@ flow_del_on_pmd(struct dp_netdev_pmd_thread *pmd,
- {
- struct dp_netdev_flow *netdev_flow;
- int error = 0;
-+#ifdef HAVE_HWOFF_AGENT
-+ struct dp_netdev_flow *temp_del_flow = NULL;
-+ bool clear_reverse_flow = false;
-+ struct eth_addr temp_mac;
-+ (void)memset(&temp_mac, 0, sizeof(struct eth_addr));
-+
-+ ovs_mutex_lock(&pmd->flow_mutex);
-+ netdev_flow = dp_netdev_pmd_find_flow(pmd, del->ufid, del->key,
-+ del->key_len);
-+ if (netdev_flow) {
-+ temp_del_flow = xcalloc(1, sizeof(struct dp_netdev_flow));
-+ (void)memcpy(temp_del_flow, netdev_flow, sizeof(struct dp_netdev_flow));
-+ }
-+ ovs_mutex_unlock(&pmd->flow_mutex);
-+ if (temp_del_flow) {
-+ clear_reverse_flow = is_clear_reverse_flow_needed(temp_del_flow, &temp_mac);
-+ if (unlikely(clear_reverse_flow)) {
-+ dp_netdev_clear_reverse_flow_by_smac(pmd, temp_mac);
-+ }
-+ }
-+ free(temp_del_flow);
-+#endif
-
- ovs_mutex_lock(&pmd->flow_mutex);
- netdev_flow = dp_netdev_pmd_find_flow(pmd, del->ufid, del->key,
-@@ -3903,7 +4236,6 @@ flow_del_on_pmd(struct dp_netdev_pmd_thread *pmd,
- error = ENOENT;
- }
- ovs_mutex_unlock(&pmd->flow_mutex);
--
- return error;
- }
-
-@@ -4619,6 +4951,20 @@ 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);
-
-+#ifdef HAVE_HWOFF_AGENT
-+ hwoff_func* funcs;
-+ struct hwoff_dp_hook_arg hook_arg;
-+
-+ hook_arg.hook_pos = HWOFF_DP_HOOK_TX_PRE;
-+ hook_arg.pmd = pmd;
-+ hook_arg.in_port = p->port->port_no;
-+ hook_arg.pkt_batch = &p->output_pkts;
-+ funcs = hwoff_get_funcs();
-+ if (funcs->hwoff_dp_hook_entry) {
-+ funcs->hwoff_dp_hook_entry(&hook_arg);
-+ }
-+#endif
-+
- netdev_send(p->port->netdev, tx_qid, &p->output_pkts, dynamic_txqs);
- dp_packet_batch_init(&p->output_pkts);
-
-@@ -4678,6 +5024,11 @@ dp_netdev_process_rxq_port(struct dp_netdev_pmd_thread *pmd,
- int rem_qlen = 0, *qlen_p = NULL;
- uint64_t cycles;
-
-+#ifdef HAVE_HWOFF_AGENT
-+ hwoff_func* funcs;
-+ struct hwoff_dp_hook_arg hook_arg;
-+#endif
-+
- /* Measure duration for polling and processing rx burst. */
- cycle_timer_start(&pmd->perf_stats, &timer);
-
-@@ -4689,6 +5040,17 @@ dp_netdev_process_rxq_port(struct dp_netdev_pmd_thread *pmd,
- qlen_p = &rem_qlen;
- }
-
-+#ifdef HAVE_HWOFF_AGENT
-+ hook_arg.hook_pos = HWOFF_DP_HOOK_RX_PRE;
-+ hook_arg.pmd = pmd;
-+ hook_arg.in_port = port_no;
-+ hook_arg.pkt_batch = &batch;
-+ funcs = hwoff_get_funcs();
-+ if (funcs->hwoff_dp_hook_entry) {
-+ funcs->hwoff_dp_hook_entry(&hook_arg);
-+ }
-+#endif
-+
- error = netdev_rxq_recv(rxq->rx, &batch, qlen_p);
- if (!error) {
- /* At least one packet received. */
-@@ -4707,6 +5069,18 @@ dp_netdev_process_rxq_port(struct dp_netdev_pmd_thread *pmd,
- }
- }
- }
-+
-+#ifdef HAVE_HWOFF_AGENT
-+ hook_arg.hook_pos = HWOFF_DP_HOOK_RX_POST;
-+ hook_arg.pmd = pmd;
-+ hook_arg.in_port = port_no;
-+ hook_arg.pkt_batch = &batch;
-+ funcs = hwoff_get_funcs();
-+ if (funcs->hwoff_dp_hook_entry) {
-+ funcs->hwoff_dp_hook_entry(&hook_arg);
-+ }
-+#endif
-+
- /* Process packet batch. */
- dp_netdev_input(pmd, &batch, port_no);
-
-@@ -5102,7 +5476,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 +6881,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 +7227,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 +7235,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 +7272,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 +7594,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 +7667,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 +7779,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 +7832,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 +7924,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,
-@@ -8459,6 +8881,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..ba2e69a 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,11 @@ 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);
-+#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..7faebfd 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;
-@@ -4012,6 +4013,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..a797168 100644
---- a/openvswitch-2.14.2/lib/dpif-provider.h
-+++ b/openvswitch-2.14.2/lib/dpif-provider.h
-@@ -628,6 +628,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..55713cd
---- /dev/null
-+++ b/openvswitch-2.14.2/lib/hwoff_init_func.c
-@@ -0,0 +1,78 @@
-+/*
-+ * 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_agent_construct),
-+ ADD_FUNC(hwoff_agent_destruct),
-+ 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_dp_hook_entry),
-+ ADD_FUNC(hwoff_set_module_log_level),
-+ 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..5d84aae
---- /dev/null
-+++ b/openvswitch-2.14.2/lib/hwoff_init_func.h
-@@ -0,0 +1,55 @@
-+/*
-+ * 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_agent_construct)(const struct smap *ovs_other_config, const char *pf_pci_addr_str, int pmd_nums,
-+ hwoff_rte_pktmbuf_init_cb cb_func);
-+ void (*hwoff_agent_destruct)(void *aux);
-+ 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)(uint32_t vxlan_dstip);
-+ int (*hwoff_global_del_vxlan_vtep)(uint32_t vxlan_dstip);
-+ uint16_t (*hwoff_tnl_get_src_port)(struct dp_packet *one_pkt);
-+ void (*hwoff_dp_hook_entry)(struct hwoff_dp_hook_arg *arg);
-+ int (*hwoff_set_module_log_level)(const char *module, uint32_t level);
-+ 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..f93bd2e 100644
---- a/openvswitch-2.14.2/lib/mac-learning.c
-+++ b/openvswitch-2.14.2/lib/mac-learning.c
-@@ -29,12 +29,96 @@
- #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 migrate_rarp_macs hwoff_rarp_record;
-+static bool rarp_record_enabled = false;
-+
-+struct migrate_rarp_macs *hwoff_rarp_record_get(void)
-+{
-+ return &hwoff_rarp_record;
-+}
-+
-+bool rarp_record_status_get(void)
-+{
-+ return rarp_record_enabled;
-+}
-+
-+struct migrate_rarp_mac_entry *rarp_mac_lookup(struct eth_addr mac)
-+{
-+ struct migrate_rarp_mac_entry *e = NULL;
-+
-+ HMAP_FOR_EACH_WITH_HASH (e, hmap_node, hash_mac(mac, 0, 0),
-+ &hwoff_rarp_record.table) {
-+ if (eth_addr_equals(e->mac, mac)) {
-+ break;
-+ }
-+ }
-+
-+ return e;
-+}
-+
-+struct migrate_rarp_mac_entry *rarp_mac_insert(struct eth_addr mac)
-+{
-+ struct migrate_rarp_mac_entry *e = NULL;
-+ uint32_t hash= 0;
-+
-+ if (hwoff_rarp_record.count >= MIGRATE_MAC_MAX) {
-+ return NULL;
-+ }
-+
-+ e = rarp_mac_lookup(mac);
-+ if (!e) {
-+ hash = hash_mac(mac, 0, 0);
-+ e = xmalloc(sizeof *e);
-+ e->need_del_flow = true;
-+ memcpy(&e->mac.ea, &mac.ea, ETH_ADDR_LEN);
-+ hmap_insert(&hwoff_rarp_record.table, &e->hmap_node, hash);
-+ hwoff_rarp_record.count++;
-+ } else {
-+ e->need_del_flow = true;
-+ }
-+
-+ return e;
-+}
-+
-+void rarp_mac_remove(struct migrate_rarp_mac_entry *e)
-+{
-+ hmap_remove(&hwoff_rarp_record.table, &e->hmap_node);
-+ free(e);
-+ hwoff_rarp_record.count--;
-+}
-+
-+void rarp_mac_table_init(void)
-+{
-+ hmap_init(&hwoff_rarp_record.table);
-+ ovs_rwlock_init(&hwoff_rarp_record.rwlock);
-+ hwoff_rarp_record.count = 0;
-+ rarp_record_enabled = true;
-+}
-+
-+void rarp_mac_table_uninit(void)
-+{
-+ struct migrate_rarp_mac_entry *e = NULL, *next = NULL;
-+
-+ rarp_record_enabled = false;
-+ ovs_rwlock_wrlock(&hwoff_rarp_record.rwlock);
-+ HMAP_FOR_EACH_SAFE (e, next, hmap_node, &hwoff_rarp_record.table) {
-+ rarp_mac_remove(e);
-+ }
-+ hmap_destroy(&hwoff_rarp_record.table);
-+ hwoff_rarp_record.count = 0;
-+ ovs_rwlock_unlock(&hwoff_rarp_record.rwlock);
-+}
-+#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 +494,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 +530,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 +551,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 +561,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 +590,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..e74296d 100644
---- a/openvswitch-2.14.2/lib/mac-learning.h
-+++ b/openvswitch-2.14.2/lib/mac-learning.h
-@@ -118,6 +118,35 @@ struct mac_entry {
- struct ovs_list port_lru_node; /* In mac_learning_port's "port_lru"s. */
- };
-
-+#ifdef HAVE_HWOFF_AGENT
-+#define MIGRATE_MAC_MAX 8192
-+
-+struct migrate_rarp_mac_entry {
-+ struct hmap_node hmap_node;
-+ struct eth_addr mac;
-+ bool need_del_flow;
-+};
-+
-+struct migrate_rarp_macs {
-+ struct hmap table;
-+ uint64_t count;
-+ struct ovs_rwlock rwlock;
-+};
-+
-+bool rarp_record_status_get(void);
-+
-+struct migrate_rarp_macs *hwoff_rarp_record_get(void);
-+
-+struct migrate_rarp_mac_entry *rarp_mac_lookup(struct eth_addr mac);
-+
-+struct migrate_rarp_mac_entry *rarp_mac_insert(struct eth_addr mac);
-+
-+void rarp_mac_remove(struct migrate_rarp_mac_entry *e);
-+
-+void rarp_mac_table_init(void);
-+
-+void rarp_mac_table_uninit(void);
-+#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 +243,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..e71f0f8 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};
-
-@@ -187,7 +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);
-
--static const struct vhost_device_ops virtio_net_device_ops =
-+static const struct rte_vhost_device_ops virtio_net_device_ops =
- {
- .new_device = new_device,
- .destroy_device = destroy_device,
-@@ -432,6 +439,9 @@ struct netdev_dpdk {
- /* If true, rte_eth_dev_start() was successfully called */
- bool started;
- bool reset_needed;
-+#ifdef HAVE_HWOFF_AGENT
-+ bool hwoff_reconfigure;
-+#endif
- /* 1 pad byte here. */
- struct eth_addr hwaddr;
- int mtu;
-@@ -1247,6 +1257,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 +1298,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 +1451,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 +1458,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.",
-@@ -1974,7 +1982,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 +2054,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 +2154,14 @@ netdev_dpdk_prep_hwol_packet(struct netdev_dpdk *dev, struct rte_mbuf *mbuf)
- {
- struct dp_packet *pkt = CONTAINER_OF(mbuf, struct dp_packet, mbuf);
-
-- if (mbuf->ol_flags & PKT_TX_L4_MASK) {
-+ if (mbuf->ol_flags & RTE_MBUF_F_TX_L4_MASK) {
- 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;
- }
-
-- if (mbuf->ol_flags & PKT_TX_TCP_SEG) {
-+ if (mbuf->ol_flags & RTE_MBUF_F_TX_TCP_SEG) {
- struct tcp_header *th = dp_packet_l4(pkt);
-
- if (!th) {
-@@ -2162,11 +2171,11 @@ netdev_dpdk_prep_hwol_packet(struct netdev_dpdk *dev, struct rte_mbuf *mbuf)
- }
-
- mbuf->l4_len = TCP_OFFSET(th->tcp_ctl) * 4;
-- mbuf->ol_flags |= PKT_TX_TCP_CKSUM;
-+ mbuf->ol_flags |= RTE_MBUF_F_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;
-+ if (mbuf->ol_flags & RTE_MBUF_F_TX_IPV4) {
-+ mbuf->ol_flags |= RTE_MBUF_F_TX_IP_CKSUM;
- }
- }
- return true;
-@@ -2513,7 +2522,7 @@ 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)
-- && !(pkt->ol_flags & PKT_TX_TCP_SEG))) {
-+ && !(pkt->ol_flags & RTE_MBUF_F_TX_TCP_SEG))) {
- VLOG_WARN_RL(&rl, "%s: Too big size %" PRIu32 " "
- "max_packet_len %d", dev->up.name, pkt->pkt_len,
- dev->max_packet_len);
-@@ -2735,12 +2744,12 @@ 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;
- mbuf_dest->ol_flags |= (pkt_orig->mbuf.ol_flags &
-- ~(EXT_ATTACHED_MBUF | IND_ATTACHED_MBUF));
-+ ~(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 & PKT_TX_L4_MASK) {
-+ if (mbuf_dest->ol_flags & RTE_MBUF_F_TX_L4_MASK) {
- 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 +2794,7 @@ 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
-- && !(packet->mbuf.ol_flags & PKT_TX_TCP_SEG)) {
-+ && !(packet->mbuf.ol_flags & RTE_MBUF_F_TX_TCP_SEG)) {
- VLOG_WARN_RL(&rl, "Too big size %u max_packet_len %d", size,
- dev->max_packet_len);
- mtu_drops++;
-@@ -3353,8 +3362,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 +3659,8 @@ 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;
-- uint16_t vendor_id = PCI_ANY_ID;
-- uint16_t device_id = PCI_ANY_ID;
-+ uint16_t vendor_id = RTE_PCI_ANY_ID;
-+ uint16_t device_id = RTE_PCI_ANY_ID;
- 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 +3768,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 +3783,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 +3809,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 +4311,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 +4965,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 +5085,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 +5110,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 +5126,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 +5186,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 +5201,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 +5228,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 +5242,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 +5252,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 +5270,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-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..dc95c68 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, ptr=%p\n",
-+ funcs->hwoff_rte_flow_deleted_get(flow_data->rte_flow), flow_data->ref_cnt, flow_data);
-+ 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..78632fb 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,69 @@ 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;
-+ const char *pmd_mask = NULL;
-+ struct ovs_numa_dump *pmd_cores = NULL;
-+ const char *hwoff_pf_pci_addr_str = NULL;
-+ static bool hwoff_agent_init = false;
-+ static int hwoff_agent_uninit = 0;
-+
-+ if (OVS_LIKELY(hwoff_agent_init)) {
-+ return 0;
-+ }
-+
-+ hwoff_pf_pci_addr_str = smap_get(ovs_other_config, "hwoff-pf-pci");
-+
-+ if (hwoff_pf_pci_addr_str == NULL) {
-+ return -1;
-+ }
-+
-+ if (smap_get_bool(ovs_other_config, "hw-offload", false)) {
-+ ret = hwoff_funcs_init();
-+ if (ret != 0) {
-+ return ret;
-+ }
-+
-+ hwoff_func *funcs = hwoff_get_funcs();
-+ if (funcs->hwoff_agent_construct == NULL) {
-+ return -1;
-+ }
-+
-+ pmd_mask = smap_get(ovs_other_config, "pmd-cpu-mask");
-+ if (pmd_mask && pmd_mask[0]) {
-+ pmd_cores = ovs_numa_dump_cores_with_cmask(pmd_mask);
-+ } else {
-+ /* default pmd mask */
-+ pmd_cores = ovs_numa_dump_n_cores_per_numa(1);
-+ }
-+
-+ ret = funcs->hwoff_agent_construct(ovs_other_config, hwoff_pf_pci_addr_str, ovs_numa_dump_count(pmd_cores),
-+ hiovs_rte_pktmbuf_init);
-+ if (!ret) {
-+ (void)hiovs_netdev_offload_init();
-+ netdev_register_flow_api_provider(&hiovs_netdev_offload_api);
-+ fatal_signal_add_hook(funcs->hwoff_agent_destruct, NULL, &hwoff_agent_uninit, true);
-+ 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..4928641 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,23 @@ vxlan_get_port_ext_gbp_str(uint16_t port, bool gbp,
- return namebuf;
- }
-
-+#ifdef HAVE_HWOFF_AGENT
-+static bool
-+hwoff_convert_to_ipv4(struct in6_addr *ip6,
-+ uint32_t *ip4)
-+{
-+ /* 现在只支持ipv4, ipv6需要更新判断逻辑 */
-+ if ((ip6->__in6_u.__u6_addr32[0] == 0 ||
-+ ip6->__in6_u.__u6_addr32[1] == 0 ||
-+ ip6->__in6_u.__u6_addr32[2] == 0) &&
-+ ip6->__in6_u.__u6_addr32[3] != 0) {
-+ *ip4 = ip6->__in6_u.__u6_addr32[3];
-+ return true;
-+ }
-+ return false;
-+}
-+#endif
-+
- static void
- update_vxlan_global_cfg(struct netdev *netdev,
- struct netdev_tunnel_config *old_cfg,
-@@ -468,6 +489,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();
-+ uint32_t ip4;
-+ if (strcmp(type, "vxlan") == 0 && new_cfg &&
-+ funcs->hwoff_global_add_vxlan_vtep &&
-+ hwoff_convert_to_ipv4(&new_cfg->ipv6_src, &ip4) &&
-+ (old_cfg == NULL || memcmp(&new_cfg->ipv6_src, &old_cfg->ipv6_src, sizeof(struct in6_addr)))) {
-+ funcs->hwoff_global_add_vxlan_vtep(ip4);
-+ }
-+#endif
-+
- if (strcmp(type, "vxlan") ||
- (old_cfg != NULL && new_cfg != NULL &&
- old_cfg->dst_port == new_cfg->dst_port &&
-@@ -487,6 +519,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 &&
-+ hwoff_convert_to_ipv4(&old_cfg->ipv6_src, &ip4)) {
-+ funcs->hwoff_global_del_vxlan_vtep(ip4);
-+ }
-+#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/ofproto/ofproto-dpif-upcall.c b/openvswitch-2.14.2/ofproto/ofproto-dpif-upcall.c
-index b24547d..9c8c407 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);
-@@ -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..7180258 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"
-@@ -2590,13 +2591,54 @@ 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_rarp, bool is_ipv6_nd)
-+{
-+ struct migrate_rarp_macs *hwoff_rarp_record = hwoff_rarp_record_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 (rarp_record_status_get() && (!strcmp(ctx->xbridge->dpif->dpif_class->type, "netdev")) &&
-+ (unlikely(is_rarp) || unlikely(is_grat_arp) || unlikely(is_ipv6_nd))) {
-+ ovs_rwlock_wrlock(&hwoff_rarp_record->rwlock);
-+ rarp_mac_insert(dl_src);
-+ ovs_rwlock_unlock(&hwoff_rarp_record->rwlock);
-+ }
-+ }
-+}
-+#else
- static void
- update_learning_table(const struct xlate_ctx *ctx,
- struct xbundle *in_xbundle, struct eth_addr dl_src,
-@@ -2609,6 +2651,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. */
-@@ -2949,6 +2992,18 @@ is_ip_local_multicast(const struct flow *flow, struct flow_wildcards *wc)
- }
- }
-
-+#ifdef HAVE_HWOFF_AGENT
-+static bool
-+is_reverse_arp(const struct flow *flow)
-+{
-+ if (flow->dl_type == htons(ETH_TYPE_RARP)) {
-+ return true;
-+ }
-+
-+ return false;
-+}
-+#endif
-+
- static void
- xlate_normal(struct xlate_ctx *ctx)
- {
-@@ -3010,15 +3065,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_rarp = is_reverse_arp(flow);
-+ 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_rarp, 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..4e43367 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 *);
-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/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..c5631f4 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
-@@ -3291,6 +3300,15 @@ 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/patch/openvswitch-2.14.2-20230308.patch b/patch/openvswitch-2.14.2-20230308.patch
deleted file mode 100644
index 0e92551bfa4572dc8916d8feaa3235a340f1bf9c..0000000000000000000000000000000000000000
--- a/patch/openvswitch-2.14.2-20230308.patch
+++ /dev/null
@@ -1,6833 +0,0 @@
-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..24855bd
---- /dev/null
-+++ b/openvswitch-2.14.2/lib/adapter/ovs_adapter.h
-@@ -0,0 +1,121 @@
-+/*
-+ * 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);
-+
-+#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_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..f23239a 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,18 @@ 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
-
- if WIN32
- lib_libopenvswitch_la_SOURCES += \
-@@ -454,6 +466,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 +614,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..fdc1d2d 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,55 @@ extract_l3_ipv6(struct conn_key *key, const void *data, size_t size,
- return true;
- }
-
-+#ifdef HAVE_HWOFF_AGENT
-+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 (size < sizeof *tcp) {
-+ return false;
-+ }
-+
-+ size_t tcp_len = TCP_OFFSET(tcp->tcp_ctl) * 4;
-+ if (OVS_UNLIKELY(tcp_len < TCP_HEADER_LEN || tcp_len > size)) {
-+ return false;
-+ }
-+
-+ return true;
-+}
-+
-+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 (size < sizeof *udp) {
-+ return false;
-+ }
-+
-+ size_t udp_len = ntohs(udp->udp_len);
-+ if (OVS_UNLIKELY(udp_len < UDP_HEADER_LEN || udp_len > 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 +1819,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 +2082,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 +2183,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 +2456,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 +2572,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 +2592,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 +2662,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 +2742,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..be24982 100644
---- a/openvswitch-2.14.2/lib/ct-dpif.c
-+++ b/openvswitch-2.14.2/lib/ct-dpif.c
-@@ -118,6 +118,24 @@ 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
-+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)
-+{
-+ if (zone) {
-+ VLOG_DBG("%s: ct_flush: %"PRIu16, dpif_name(dpif), *zone);
-+ } else {
-+ VLOG_DBG("%s: ct_flush: ", dpif_name(dpif));
-+ }
-+
-+ return (dpif->dpif_class->ct_flush
-+ ? dpif->dpif_class->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 +156,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 +347,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..1576ce5
---- /dev/null
-+++ b/openvswitch-2.14.2/lib/ct_dump_extend/ct_dump_extend.c
-@@ -0,0 +1,227 @@
-+/*
-+ * 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 MAX_CT_FLOWS_DUMP_ONCE (5000)
-+
-+enum dump_ct_status {
-+ DUMP_CT_RUNNING,
-+ DUMP_CT_STOP,
-+};
-+
-+struct dump_ct_mgmt {
-+ FILE *file;
-+ char file_name[PATH_MAX];
-+ bool verbose;
-+ bool print_stats;
-+ uint32_t cnt;
-+ uint16_t zone;
-+ const uint16_t *pzone;
-+ atomic_count dumping;
-+ pthread_t thread;
-+ pthread_mutex_t mutex;
-+ struct ct_dpif_dump_state *dump_state;
-+ struct dpif *dpif;
-+};
-+
-+VLOG_DEFINE_THIS_MODULE(ct_dump_extend);
-+
-+static struct dump_ct_mgmt g_dump_mgmt = {
-+ .verbose = false,
-+ .print_stats = false,
-+ .cnt = 0,
-+ .dumping = ATOMIC_COUNT_INIT(DUMP_CT_STOP),
-+ .file = NULL,
-+ .dump_state = NULL,
-+ .zone = 0,
-+ .pzone = NULL,
-+};
-+
-+static void
-+ct_dump_to_file_stop(void)
-+{
-+ struct dump_ct_mgmt *m = &g_dump_mgmt;
-+
-+ if (m->dump_state != NULL) {
-+ ct_dpif_dump_done(m->dump_state);
-+ m->dump_state = NULL;
-+ }
-+
-+ if (m->file != NULL) {
-+ fclose(m->file);
-+ m->file = NULL;
-+ }
-+
-+ if (m->dpif != NULL) {
-+ dpif_close(m->dpif);
-+ m->dpif = NULL;
-+ }
-+
-+ atomic_count_set(&m->dumping, DUMP_CT_STOP);
-+}
-+
-+static int
-+ct_dump_open_file(const char *file_name, struct ds *ds)
-+{
-+ struct dump_ct_mgmt *m = &g_dump_mgmt;
-+
-+ if (file_name[0] != '/') {
-+ ds_put_format(ds, "file name \"%s\"error: Need absolute path\n", file_name);
-+ return -1;
-+ }
-+
-+ m->file = fopen(file_name, "w+");
-+ if (m->file == NULL) {
-+ ds_put_format(ds, "can not open file :%s\n", file_name);
-+ return -1;
-+ }
-+
-+ return 0;
-+};
-+
-+static void ct_dump_to_file_run(void)
-+{
-+ int ret = 0;
-+ int i = 0;
-+ struct ct_dpif_entry cte;
-+ struct dump_ct_mgmt *m = &g_dump_mgmt;
-+ struct ds s = DS_EMPTY_INITIALIZER;
-+ int tot_bkts;
-+
-+ ret = ct_dpif_dump_start(m->dpif, &m->dump_state, m->pzone, &tot_bkts);
-+ if (ret != 0) {
-+ VLOG_ERR("starting conntrack dump error\n");
-+ ct_dump_to_file_stop();
-+ return;
-+ }
-+ ret = ct_dump_open_file(m->file_name, &s);
-+ if (ret != 0) {
-+ ds_destroy(&s);
-+ ct_dump_to_file_stop();
-+ return;
-+ }
-+
-+ m->cnt = 0;
-+ for (;;) {
-+ if (ct_dpif_dump_next(m->dump_state, &cte)) {
-+ VLOG_INFO("dump ct to file end !");
-+ ret = fwrite(ds_cstr(&s), strlen(ds_cstr(&s)), 1, m->file);
-+ if ((ret != 1) && (ferror(m->file) != 0)) {
-+ VLOG_WARN("dump ct to file end failed ! ret %d\n", ret);
-+ };
-+ break;
-+ }
-+ ct_dpif_format_entry(&cte, &s, m->verbose,
-+ m->print_stats);
-+ ct_dpif_entry_uninit(&cte);
-+ ds_put_format(&s, "\n");
-+ i++;
-+ if (i == MAX_CT_FLOWS_DUMP_ONCE) {
-+ ret = fwrite(ds_cstr(&s), strlen(ds_cstr(&s)), 1, m->file);
-+ if ((ret != 1) && (ferror(m->file) != 0)) {
-+ VLOG_WARN("dump ct to file failed ! ret %d\n", ret);
-+ break;
-+ }
-+ ds_clear(&s);
-+ m->cnt += MAX_CT_FLOWS_DUMP_ONCE;
-+ i = 0;
-+ }
-+ }
-+
-+ ds_destroy(&s);
-+ ct_dump_to_file_stop();
-+}
-+
-+int
-+ct_dump_to_file(struct ct_dump_extend *dump)
-+{
-+ struct dump_ct_mgmt *m = &g_dump_mgmt;
-+ 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(m->file_name, 0, PATH_MAX);
-+ strncpy(m->file_name, resolve_path, PATH_MAX - 1);
-+ free(resolve_path);
-+
-+ m->verbose = dump->verbose;
-+ m->print_stats = dump->print_stats;
-+ m->dpif = dump->dpif;
-+ if (dump->pzone != NULL) {
-+ m->zone = *dump->pzone;
-+ m->pzone = &m->zone;
-+ }
-+
-+ pthread_mutex_lock(&m->mutex);
-+ if (DUMP_CT_STOP != atomic_count_get(&m->dumping)) {
-+ ds_put_format(dump->ds, "dump all ct flows is busy, please try again after a moment\n");
-+ pthread_mutex_unlock(&m->mutex);
-+ return -1;
-+ }
-+ atomic_count_set(&m->dumping, DUMP_CT_RUNNING);
-+ pthread_mutex_unlock(&m->mutex);
-+
-+ ds_put_format(dump->ds, "starting dump ct into file: %s.\n", dump->file_name);
-+ m->thread = ovs_thread_create("ct_dump", (void *)ct_dump_to_file_run, NULL);
-+ VLOG_INFO("dump thread created thread id=%lu", m->thread);
-+ 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..a420cc8
---- /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 verbose;
-+ bool print_stats;
-+ const char *file_name;
-+ const uint16_t *pzone;
-+ struct ds *ds;
-+ struct dpif *dpif;
-+};
-+
-+int ct_dump_to_file(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..76e0ecc 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,40 @@ 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
-+dp_nolinear_packet_set_size(struct dp_packet *b, uint32_t v)
-+{
-+ if (v < b->mbuf.pkt_len) {
-+ b->mbuf.data_len -= (b->mbuf.pkt_len - v);
-+ } else if (v > b->mbuf.pkt_len) {
-+ b->mbuf.data_len += (v - b->mbuf.pkt_len);
-+ }
-+
-+ 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) {
-+ return dp_nolinear_packet_set_size(b, v);
-+ }
-+
-+ /* Current seg length. */
-+ rte_pktmbuf_data_len(&(b->mbuf)) = v;
-+ /* Total length of all segments linked to this segment. */
-+ rte_pktmbuf_pkt_len(&(b->mbuf)) = v;
-+}
-+
-+#else
-+
- static inline uint32_t
- dp_packet_size(const struct dp_packet *b)
- {
-@@ -579,6 +644,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..5a84070 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 dump_file = false;
-+ const char *file_name = NULL;
-+
-+ if (argc >= 2 && (strncmp(argv[argc - 2], "-w", sizeof("-w")) == 0)) {
-+ dump_file = true;
-+ 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 (dump_file) {
-+ struct ds d = DS_EMPTY_INITIALIZER;
-+ struct ct_dump_extend ct_dump = {
-+ .file_name = file_name,
-+ .verbose = dpctl_p->verbosity,
-+ .print_stats = dpctl_p->print_statistics,
-+ .dpif = dpif,
-+ .pzone = pzone,
-+ .ds = &d,
-+ };
-+ error = ct_dump_to_file(&ct_dump);
-+ if (error) {
-+ dpctl_print(dpctl_p, "%s\n", ds_cstr(&d));
-+ ds_destroy(&d);
-+ dpif_close(dpif);
-+ return error;
-+ }
-+ dpctl_print(dpctl_p, "%s\n", ds_cstr(&d));
-+ ds_destroy(&d);
-+ 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)
-+{
-+ struct dpif *dpif = NULL;
-+ struct ds ds = DS_EMPTY_INITIALIZER;
-+ uint16_t zone, *pzone = NULL;
-+ int args = argc - 1;
-+ int error;
-+ union ct_addr s_addr;
-+ union ct_addr d_addr;
-+ union ct_addr s_mask;
-+ union ct_addr d_mask;
-+ bool dst_is_ipv6 = false;
-+ bool src_is_ipv6 = false;
-+ bool dst_is_ipv4 = false;
-+ bool src_is_ipv4 = false;
-+ uint16_t dl_type;
-+ bool is_force = false;
-+ char *ip;
-+
-+ memset(&s_addr, 0, sizeof(union ct_addr));
-+ memset(&d_addr, 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, &d_addr, &d_mask, &dst_is_ipv6);
-+ free(ip);
-+ if (error) {
-+ dpctl_error(dpctl_p, error, "parse dip error.");
-+ return error;
-+ }
-+ dst_is_ipv4 = !dst_is_ipv6;
-+ args--;
-+ }
-+
-+ if (args && !strncmp(argv[args], "sip=", sizeof("sip=") - 1)) {
-+ ip = xstrdup(argv[args] + (sizeof("sip=") - 1));
-+ error = conntrack_flush_get_ip(ip, &s_addr, &s_mask, &src_is_ipv6);
-+ free(ip);
-+ if (error) {
-+ dpctl_error(dpctl_p, error, "parse sip error.");
-+ return error;
-+ }
-+ src_is_ipv4 = !src_is_ipv6;
-+ args--;
-+ }
-+
-+ if ((src_is_ipv6 && dst_is_ipv4) ||
-+ (src_is_ipv4 && dst_is_ipv6)) {
-+ dpctl_error(dpctl_p, EINVAL, "sip/dip mismatch.");
-+ return EINVAL;
-+ }
-+
-+ if (dst_is_ipv6 || src_is_ipv6) {
-+ dl_type = ETH_TYPE_IPV6;
-+ } else if (dst_is_ipv4 || src_is_ipv4) {
-+ 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,
-+ (src_is_ipv6 || src_is_ipv4) ? &s_addr : 0,
-+ (dst_is_ipv6 || dst_is_ipv4) ? &d_addr : 0,
-+ (src_is_ipv6 || src_is_ipv4) ? &s_mask : 0,
-+ (dst_is_ipv6 || dst_is_ipv4) ? &d_mask : 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..f8437db 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,9 +351,17 @@ dpdk_unixctl_log_set(struct unixctl_conn *conn, int argc, const char *argv[],
- }
-
- level = dpdk_parse_log_level(level_string);
-+#ifdef HAVE_HWOFF_AGENT
-+ hwoff_func* funcs = hwoff_get_funcs();
-+#endif
- if (level == -1) {
- err_msg = xasprintf("invalid log level: '%s'", level_string);
-+#ifdef HAVE_HWOFF_AGENT
-+ } else if (rte_log_set_level_pattern(pattern, level) < 0 ||
-+ (funcs && funcs->hwoff_set_module_log_level(pattern, level) < 0)) {
-+#else
- } else if (rte_log_set_level_pattern(pattern, level) < 0) {
-+#endif
- err_msg = xasprintf("cannot set log level for '%s'", argv[i]);
- }
-
-@@ -356,6 +376,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 +599,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..390cb23 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,9 +3045,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 +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,109 @@ dp_netdev_flow_add(struct dp_netdev_pmd_thread *pmd,
- return flow;
- }
-
-+
-+#ifdef HAVE_HWOFF_AGENT
-+static bool
-+is_clear_reverse_flow_needed(struct dp_netdev_flow *netdev_flow, struct eth_addr *temp_mac)
-+{
-+ struct migrate_rarp_mac_entry *e = NULL;
-+ bool clear_reverse_flow = false;
-+ struct migrate_rarp_macs *hwoff_rarp_record = hwoff_rarp_record_get();
-+ if (rarp_record_status_get()) {
-+ ovs_rwlock_wrlock(&hwoff_rarp_record->rwlock);
-+ if (unlikely(hwoff_rarp_record->count)) {
-+ e = rarp_mac_lookup(netdev_flow->flow.dl_dst);
-+ if (e && e->need_del_flow) {
-+ rarp_mac_remove(e);
-+ (void)memcpy(&temp_mac->ea, &netdev_flow->flow.dl_dst.ea, RTE_ETHER_ADDR_LEN);
-+ clear_reverse_flow = true;
-+ }
-+ }
-+ ovs_rwlock_unlock(&hwoff_rarp_record->rwlock);
-+ }
-+ return clear_reverse_flow;
-+}
-+
-+static bool
-+is_clear_forward_flow_needed(struct dp_netdev_flow *netdev_flow,
-+ struct eth_addr *temp_mac, uint32_t *dp_in_port)
-+{
-+ struct migrate_rarp_mac_entry *e = NULL;
-+ bool clear_flow = false;
-+ struct migrate_rarp_macs *hwoff_rarp_record = hwoff_rarp_record_get();
-+ if (netdev_flow == NULL) {
-+ return false;
-+ }
-+ if (rarp_record_status_get()) {
-+ ovs_rwlock_wrlock(&hwoff_rarp_record->rwlock);
-+ if (unlikely(hwoff_rarp_record->count)) {
-+ e = rarp_mac_lookup(netdev_flow->flow.dl_src);
-+ if (e && e->need_del_flow) {
-+ rarp_mac_remove(e);
-+ (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_rarp_record->rwlock);
-+ }
-+ 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 (rarp_record_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 (rarp_record_status_get() && is_clear_forward_flow_needed(flow, &temp_mac, &dp_in_port)) {
-+ dp_netdev_clear_flow(pmd, temp_mac, dp_in_port);
-+ }
-+}
-+
-+static void
-+dp_netdev_clear_reverse_flow_by_smac(struct dp_netdev_pmd_thread *pmd, struct eth_addr smac)
-+{
-+ 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 (rarp_record_status_get() && eth_addr_equals(netdev_flow->flow.dl_src, smac) &&
-+ !eth_addr_is_broadcast(netdev_flow->flow.dl_dst)) {
-+ 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);
-+ }
-+}
-+#endif
-+
- static int
- flow_put_on_pmd(struct dp_netdev_pmd_thread *pmd,
- struct netdev_flow_key *key,
-@@ -3748,7 +4067,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 +4092,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 +4119,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;
- }
-
-@@ -3890,6 +4211,28 @@ flow_del_on_pmd(struct dp_netdev_pmd_thread *pmd,
- {
- struct dp_netdev_flow *netdev_flow;
- int error = 0;
-+#ifdef HAVE_HWOFF_AGENT
-+ struct dp_netdev_flow *temp_del_flow = NULL;
-+ bool clear_reverse_flow = false;
-+ struct eth_addr temp_mac;
-+ (void)memset(&temp_mac, 0, sizeof(struct eth_addr));
-+
-+ ovs_mutex_lock(&pmd->flow_mutex);
-+ netdev_flow = dp_netdev_pmd_find_flow(pmd, del->ufid, del->key,
-+ del->key_len);
-+ if (netdev_flow) {
-+ temp_del_flow = xcalloc(1, sizeof(struct dp_netdev_flow));
-+ (void)memcpy(temp_del_flow, netdev_flow, sizeof(struct dp_netdev_flow));
-+ }
-+ ovs_mutex_unlock(&pmd->flow_mutex);
-+ if (temp_del_flow) {
-+ clear_reverse_flow = is_clear_reverse_flow_needed(temp_del_flow, &temp_mac);
-+ if (unlikely(clear_reverse_flow)) {
-+ dp_netdev_clear_reverse_flow_by_smac(pmd, temp_mac);
-+ }
-+ }
-+ free(temp_del_flow);
-+#endif
-
- ovs_mutex_lock(&pmd->flow_mutex);
- netdev_flow = dp_netdev_pmd_find_flow(pmd, del->ufid, del->key,
-@@ -3903,7 +4246,6 @@ flow_del_on_pmd(struct dp_netdev_pmd_thread *pmd,
- error = ENOENT;
- }
- ovs_mutex_unlock(&pmd->flow_mutex);
--
- return error;
- }
-
-@@ -4619,6 +4961,20 @@ 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);
-
-+#ifdef HAVE_HWOFF_AGENT
-+ hwoff_func* funcs;
-+ struct hwoff_dp_hook_arg hook_arg;
-+
-+ hook_arg.hook_pos = HWOFF_DP_HOOK_TX_PRE;
-+ hook_arg.pmd = pmd;
-+ hook_arg.in_port = p->port->port_no;
-+ hook_arg.pkt_batch = &p->output_pkts;
-+ funcs = hwoff_get_funcs();
-+ if (funcs->hwoff_dp_hook_entry) {
-+ funcs->hwoff_dp_hook_entry(&hook_arg);
-+ }
-+#endif
-+
- netdev_send(p->port->netdev, tx_qid, &p->output_pkts, dynamic_txqs);
- dp_packet_batch_init(&p->output_pkts);
-
-@@ -4678,6 +5034,11 @@ dp_netdev_process_rxq_port(struct dp_netdev_pmd_thread *pmd,
- int rem_qlen = 0, *qlen_p = NULL;
- uint64_t cycles;
-
-+#ifdef HAVE_HWOFF_AGENT
-+ hwoff_func* funcs;
-+ struct hwoff_dp_hook_arg hook_arg;
-+#endif
-+
- /* Measure duration for polling and processing rx burst. */
- cycle_timer_start(&pmd->perf_stats, &timer);
-
-@@ -4689,6 +5050,17 @@ dp_netdev_process_rxq_port(struct dp_netdev_pmd_thread *pmd,
- qlen_p = &rem_qlen;
- }
-
-+#ifdef HAVE_HWOFF_AGENT
-+ hook_arg.hook_pos = HWOFF_DP_HOOK_RX_PRE;
-+ hook_arg.pmd = pmd;
-+ hook_arg.in_port = port_no;
-+ hook_arg.pkt_batch = &batch;
-+ funcs = hwoff_get_funcs();
-+ if (funcs->hwoff_dp_hook_entry) {
-+ funcs->hwoff_dp_hook_entry(&hook_arg);
-+ }
-+#endif
-+
- error = netdev_rxq_recv(rxq->rx, &batch, qlen_p);
- if (!error) {
- /* At least one packet received. */
-@@ -4707,6 +5079,18 @@ dp_netdev_process_rxq_port(struct dp_netdev_pmd_thread *pmd,
- }
- }
- }
-+
-+#ifdef HAVE_HWOFF_AGENT
-+ hook_arg.hook_pos = HWOFF_DP_HOOK_RX_POST;
-+ hook_arg.pmd = pmd;
-+ hook_arg.in_port = port_no;
-+ hook_arg.pkt_batch = &batch;
-+ funcs = hwoff_get_funcs();
-+ if (funcs->hwoff_dp_hook_entry) {
-+ funcs->hwoff_dp_hook_entry(&hook_arg);
-+ }
-+#endif
-+
- /* Process packet batch. */
- dp_netdev_input(pmd, &batch, port_no);
-
-@@ -5102,7 +5486,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 +6891,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 +7237,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 +7245,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 +7282,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 +7604,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 +7677,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 +7789,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 +7842,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 +7934,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 +8478,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 +8501,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 +8904,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..55713cd
---- /dev/null
-+++ b/openvswitch-2.14.2/lib/hwoff_init_func.c
-@@ -0,0 +1,78 @@
-+/*
-+ * 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_agent_construct),
-+ ADD_FUNC(hwoff_agent_destruct),
-+ 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_dp_hook_entry),
-+ ADD_FUNC(hwoff_set_module_log_level),
-+ 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..5d84aae
---- /dev/null
-+++ b/openvswitch-2.14.2/lib/hwoff_init_func.h
-@@ -0,0 +1,55 @@
-+/*
-+ * 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_agent_construct)(const struct smap *ovs_other_config, const char *pf_pci_addr_str, int pmd_nums,
-+ hwoff_rte_pktmbuf_init_cb cb_func);
-+ void (*hwoff_agent_destruct)(void *aux);
-+ 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)(uint32_t vxlan_dstip);
-+ int (*hwoff_global_del_vxlan_vtep)(uint32_t vxlan_dstip);
-+ uint16_t (*hwoff_tnl_get_src_port)(struct dp_packet *one_pkt);
-+ void (*hwoff_dp_hook_entry)(struct hwoff_dp_hook_arg *arg);
-+ int (*hwoff_set_module_log_level)(const char *module, uint32_t level);
-+ 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..bd7c3f4 100644
---- a/openvswitch-2.14.2/lib/mac-learning.c
-+++ b/openvswitch-2.14.2/lib/mac-learning.c
-@@ -29,12 +29,96 @@
- #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 migrate_rarp_macs hwoff_rarp_record;
-+static bool rarp_record_enabled = false;
-+
-+struct migrate_rarp_macs *hwoff_rarp_record_get(void)
-+{
-+ return &hwoff_rarp_record;
-+}
-+
-+bool rarp_record_status_get(void)
-+{
-+ return rarp_record_enabled;
-+}
-+
-+struct migrate_rarp_mac_entry *rarp_mac_lookup(struct eth_addr mac)
-+{
-+ struct migrate_rarp_mac_entry *e = NULL;
-+
-+ HMAP_FOR_EACH_WITH_HASH (e, hmap_node, hash_mac(mac, 0, 0),
-+ &hwoff_rarp_record.table) {
-+ if (eth_addr_equals(e->mac, mac)) {
-+ break;
-+ }
-+ }
-+
-+ return e;
-+}
-+
-+struct migrate_rarp_mac_entry *rarp_mac_insert(struct eth_addr mac)
-+{
-+ struct migrate_rarp_mac_entry *e = NULL;
-+ uint32_t hash= 0;
-+
-+ if (hwoff_rarp_record.count >= MIGRATE_MAC_MAX) {
-+ return NULL;
-+ }
-+
-+ e = rarp_mac_lookup(mac);
-+ if (!e) {
-+ hash = hash_mac(mac, 0, 0);
-+ e = xmalloc(sizeof *e);
-+ e->need_del_flow = true;
-+ memcpy(&e->mac.ea, &mac.ea, ETH_ADDR_LEN);
-+ hmap_insert(&hwoff_rarp_record.table, &e->hmap_node, hash);
-+ hwoff_rarp_record.count++;
-+ } else {
-+ e->need_del_flow = true;
-+ }
-+
-+ return e;
-+}
-+
-+void rarp_mac_remove(struct migrate_rarp_mac_entry *e)
-+{
-+ hmap_remove(&hwoff_rarp_record.table, &e->hmap_node);
-+ free(e);
-+ hwoff_rarp_record.count--;
-+}
-+
-+void rarp_mac_table_init(void)
-+{
-+ hmap_init(&hwoff_rarp_record.table);
-+ ovs_rwlock_init(&hwoff_rarp_record.rwlock);
-+ hwoff_rarp_record.count = 0;
-+ rarp_record_enabled = true;
-+}
-+
-+void rarp_mac_table_uninit(void)
-+{
-+ struct migrate_rarp_mac_entry *e = NULL, *next = NULL;
-+
-+ rarp_record_enabled = false;
-+ ovs_rwlock_wrlock(&hwoff_rarp_record.rwlock);
-+ HMAP_FOR_EACH_SAFE (e, next, hmap_node, &hwoff_rarp_record.table) {
-+ rarp_mac_remove(e);
-+ }
-+ hmap_destroy(&hwoff_rarp_record.table);
-+ hwoff_rarp_record.count = 0;
-+ ovs_rwlock_unlock(&hwoff_rarp_record.rwlock);
-+}
-+#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 +494,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 +530,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 +551,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 +561,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 +590,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..e74296d 100644
---- a/openvswitch-2.14.2/lib/mac-learning.h
-+++ b/openvswitch-2.14.2/lib/mac-learning.h
-@@ -118,6 +118,35 @@ struct mac_entry {
- struct ovs_list port_lru_node; /* In mac_learning_port's "port_lru"s. */
- };
-
-+#ifdef HAVE_HWOFF_AGENT
-+#define MIGRATE_MAC_MAX 8192
-+
-+struct migrate_rarp_mac_entry {
-+ struct hmap_node hmap_node;
-+ struct eth_addr mac;
-+ bool need_del_flow;
-+};
-+
-+struct migrate_rarp_macs {
-+ struct hmap table;
-+ uint64_t count;
-+ struct ovs_rwlock rwlock;
-+};
-+
-+bool rarp_record_status_get(void);
-+
-+struct migrate_rarp_macs *hwoff_rarp_record_get(void);
-+
-+struct migrate_rarp_mac_entry *rarp_mac_lookup(struct eth_addr mac);
-+
-+struct migrate_rarp_mac_entry *rarp_mac_insert(struct eth_addr mac);
-+
-+void rarp_mac_remove(struct migrate_rarp_mac_entry *e);
-+
-+void rarp_mac_table_init(void);
-+
-+void rarp_mac_table_uninit(void);
-+#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 +243,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..1cf323b 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};
-
-@@ -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,9 @@ struct netdev_dpdk {
- /* If true, rte_eth_dev_start() was successfully called */
- bool started;
- bool reset_needed;
-+#ifdef HAVE_HWOFF_AGENT
-+ bool hwoff_reconfigure;
-+#endif
- /* 1 pad byte here. */
- struct eth_addr hwaddr;
- int mtu;
-@@ -1247,6 +1271,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 +1312,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 +1465,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 +1472,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.",
-@@ -1974,7 +1996,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 +2068,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 +2168,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 +2192,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 +2550,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 +2775,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 +2832,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 +3404,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 +3701,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 +3815,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 +3830,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 +3856,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 +4358,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 +5012,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 +5132,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 +5157,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 +5173,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 +5233,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 +5248,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 +5275,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 +5289,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 +5299,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 +5317,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-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..78632fb 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,69 @@ 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;
-+ const char *pmd_mask = NULL;
-+ struct ovs_numa_dump *pmd_cores = NULL;
-+ const char *hwoff_pf_pci_addr_str = NULL;
-+ static bool hwoff_agent_init = false;
-+ static int hwoff_agent_uninit = 0;
-+
-+ if (OVS_LIKELY(hwoff_agent_init)) {
-+ return 0;
-+ }
-+
-+ hwoff_pf_pci_addr_str = smap_get(ovs_other_config, "hwoff-pf-pci");
-+
-+ if (hwoff_pf_pci_addr_str == NULL) {
-+ return -1;
-+ }
-+
-+ if (smap_get_bool(ovs_other_config, "hw-offload", false)) {
-+ ret = hwoff_funcs_init();
-+ if (ret != 0) {
-+ return ret;
-+ }
-+
-+ hwoff_func *funcs = hwoff_get_funcs();
-+ if (funcs->hwoff_agent_construct == NULL) {
-+ return -1;
-+ }
-+
-+ pmd_mask = smap_get(ovs_other_config, "pmd-cpu-mask");
-+ if (pmd_mask && pmd_mask[0]) {
-+ pmd_cores = ovs_numa_dump_cores_with_cmask(pmd_mask);
-+ } else {
-+ /* default pmd mask */
-+ pmd_cores = ovs_numa_dump_n_cores_per_numa(1);
-+ }
-+
-+ ret = funcs->hwoff_agent_construct(ovs_other_config, hwoff_pf_pci_addr_str, ovs_numa_dump_count(pmd_cores),
-+ hiovs_rte_pktmbuf_init);
-+ if (!ret) {
-+ (void)hiovs_netdev_offload_init();
-+ netdev_register_flow_api_provider(&hiovs_netdev_offload_api);
-+ fatal_signal_add_hook(funcs->hwoff_agent_destruct, NULL, &hwoff_agent_uninit, true);
-+ 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..4928641 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,23 @@ vxlan_get_port_ext_gbp_str(uint16_t port, bool gbp,
- return namebuf;
- }
-
-+#ifdef HAVE_HWOFF_AGENT
-+static bool
-+hwoff_convert_to_ipv4(struct in6_addr *ip6,
-+ uint32_t *ip4)
-+{
-+ /* 现在只支持ipv4, ipv6需要更新判断逻辑 */
-+ if ((ip6->__in6_u.__u6_addr32[0] == 0 ||
-+ ip6->__in6_u.__u6_addr32[1] == 0 ||
-+ ip6->__in6_u.__u6_addr32[2] == 0) &&
-+ ip6->__in6_u.__u6_addr32[3] != 0) {
-+ *ip4 = ip6->__in6_u.__u6_addr32[3];
-+ return true;
-+ }
-+ return false;
-+}
-+#endif
-+
- static void
- update_vxlan_global_cfg(struct netdev *netdev,
- struct netdev_tunnel_config *old_cfg,
-@@ -468,6 +489,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();
-+ uint32_t ip4;
-+ if (strcmp(type, "vxlan") == 0 && new_cfg &&
-+ funcs->hwoff_global_add_vxlan_vtep &&
-+ hwoff_convert_to_ipv4(&new_cfg->ipv6_src, &ip4) &&
-+ (old_cfg == NULL || memcmp(&new_cfg->ipv6_src, &old_cfg->ipv6_src, sizeof(struct in6_addr)))) {
-+ funcs->hwoff_global_add_vxlan_vtep(ip4);
-+ }
-+#endif
-+
- if (strcmp(type, "vxlan") ||
- (old_cfg != NULL && new_cfg != NULL &&
- old_cfg->dst_port == new_cfg->dst_port &&
-@@ -487,6 +519,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 &&
-+ hwoff_convert_to_ipv4(&old_cfg->ipv6_src, &ip4)) {
-+ funcs->hwoff_global_del_vxlan_vtep(ip4);
-+ }
-+#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..9c8c407 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);
-@@ -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..7180258 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"
-@@ -2590,13 +2591,54 @@ 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_rarp, bool is_ipv6_nd)
-+{
-+ struct migrate_rarp_macs *hwoff_rarp_record = hwoff_rarp_record_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 (rarp_record_status_get() && (!strcmp(ctx->xbridge->dpif->dpif_class->type, "netdev")) &&
-+ (unlikely(is_rarp) || unlikely(is_grat_arp) || unlikely(is_ipv6_nd))) {
-+ ovs_rwlock_wrlock(&hwoff_rarp_record->rwlock);
-+ rarp_mac_insert(dl_src);
-+ ovs_rwlock_unlock(&hwoff_rarp_record->rwlock);
-+ }
-+ }
-+}
-+#else
- static void
- update_learning_table(const struct xlate_ctx *ctx,
- struct xbundle *in_xbundle, struct eth_addr dl_src,
-@@ -2609,6 +2651,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. */
-@@ -2949,6 +2992,18 @@ is_ip_local_multicast(const struct flow *flow, struct flow_wildcards *wc)
- }
- }
-
-+#ifdef HAVE_HWOFF_AGENT
-+static bool
-+is_reverse_arp(const struct flow *flow)
-+{
-+ if (flow->dl_type == htons(ETH_TYPE_RARP)) {
-+ return true;
-+ }
-+
-+ return false;
-+}
-+#endif
-+
- static void
- xlate_normal(struct xlate_ctx *ctx)
- {
-@@ -3010,15 +3065,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_rarp = is_reverse_arp(flow);
-+ 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_rarp, 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