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