ASR_BASE

Change-Id: Icf3719cc0afe3eeb3edc7fa80a2eb5199ca9dda1
diff --git a/external/subpack/net/openvswitch/Config.in b/external/subpack/net/openvswitch/Config.in
new file mode 100644
index 0000000..ba17072
--- /dev/null
+++ b/external/subpack/net/openvswitch/Config.in
@@ -0,0 +1,8 @@
+menu "Configuration"
+	depends on PACKAGE_openvswitch
+
+	config	OPENVSWITCH_WITH_LIBUNBOUND
+		bool
+		default y
+		prompt "Build with libunbound library."
+endmenu
diff --git a/external/subpack/net/openvswitch/Makefile b/external/subpack/net/openvswitch/Makefile
new file mode 100644
index 0000000..cf27b0e
--- /dev/null
+++ b/external/subpack/net/openvswitch/Makefile
@@ -0,0 +1,283 @@
+#
+# Copyright (C) 2013 Julius Schulz-Zander <julius@net.t-labs.tu-berlin.de>
+# Copyright (C) 2014-2017 OpenWrt.org
+# Copyright (C) 2018-2020 Yousong Zhou <yszhou4tech@gmail.com>
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+include ./openvswitch.mk
+
+# Checklist on version bump
+#
+#  - Check acinclude.m4 for range of supported kernel versions: "but version newer than .* is not supported"
+#  - Check and update kmod dependencies when necessary (runtime module load check in the least)
+#
+PKG_NAME:=openvswitch
+PKG_VERSION:=$(ovs_version)
+PKG_RELEASE:=1
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=https://www.openvswitch.org/releases/
+PKG_HASH:=e1b3fa472676626853f22d63f959e5ad061e1bf57e1bbd444d0ed88f947ef8b1
+
+PKG_LICENSE:=Apache-2.0
+PKG_LICENSE_FILES:=LICENSE
+PKG_CPE_ID:=cpe:/a:openvswitch:openvswitch
+
+PKG_BUILD_DIR:=$(ovs_builddir)
+PKG_BUILD_DEPENDS+=python3/host
+PKG_BUILD_FLAGS:=no-mips16 lto
+PKG_BUILD_PARALLEL:=1
+PKG_FIXUP:=autoreconf
+PKG_INSTALL:=1
+PYTHON3_PKG_BUILD:=0
+
+PKG_MAINTAINER:=Yousong Zhou <yszhou4tech@gmail.com>
+
+include $(INCLUDE_DIR)/package.mk
+include ../../lang/python/python3-host.mk
+include ../../lang/python/python3-package.mk
+
+define Package/openvswitch/config
+source "$(SOURCE)/Config.in"
+endef
+
+ovs_kmod_packages:=
+ovs_kmod_intree_kernel_patchver_min:=3.10
+ovs_kmod_intree_kernel_patchver_max:=5.5
+ovs_kmod_intree_not_supported:=$(strip $(call kernel_patchver_lt,$(ovs_kmod_intree_kernel_patchver_min))$(call kernel_patchver_gt,$(ovs_kmod_intree_kernel_patchver_max)))
+ovs_kmod_intree_dir:=$(PKG_BUILD_DIR)/datapath/linux
+ovs_kmod_upstream_dir:=$(LINUX_DIR)/net/openvswitch
+ovs_kmod_package_name=$(if $(filter openvswitch,$(1)),openvswitch,$(1))
+ovs_kmod_is_intree=$(filter %-intree,$(1))
+ovs_kmod_upstream_name=kmod-$(call ovs_kmod_package_name,$(patsubst %-intree,%,$(1)))
+ovs_kmod_package_provides=$(call ovs_kmod_upstream_name,$(1))
+define OvsKmodPackageTemplate
+ifeq ($(if $(call ovs_kmod_is_intree,$(1)),$(ovs_kmod_intree_not_supported)),)
+  define KernelPackage/$(call ovs_kmod_package_name,$(1))
+     SECTION:=kernel
+     CATEGORY:=Kernel modules
+     SUBMENU:=Network Support
+     TITLE:=$(ovs_kmod_$(1)_title)
+     DEPENDS:=$(ovs_kmod_$(1)_depends) $(if $(call ovs_kmod_is_intree,$(1)),@IPV6 @DEVEL)
+     PROVIDES:=$(call ovs_kmod_package_provides,$(1))
+     KCONFIG:=$(ovs_kmod_$(1)_kconfig)
+     FILES:=$(ovs_kmod_$(1)_files)
+     AUTOLOAD:=$(call AutoProbe,$(foreach m,$(ovs_kmod_$(1)_files),$(notdir $(patsubst %.ko,%,$(basename $(m))))))
+  endef
+
+  ovs_kmod_packages+=$(call ovs_kmod_package_name,$(1))
+endif
+endef
+
+ovs_kmod_openvswitch_title:=Open vSwitch kernel datapath (upstream)
+ovs_kmod_openvswitch_kconfig:=CONFIG_OPENVSWITCH
+ovs_kmod_openvswitch_depends:=\
+	  +kmod-lib-crc32c \
+	  +kmod-mpls \
+	  +kmod-nf-nat \
+	  +IPV6:kmod-nf-nat6 \
+	  +kmod-nf-conntrack \
+	  +IPV6:kmod-nf-conntrack6 \
+	  +kmod-nsh \
+	  +kmod-ipt-conntrack-extra \
+
+ovs_kmod_openvswitch_files:=$(ovs_kmod_upstream_dir)/openvswitch.ko
+$(eval $(call OvsKmodPackageTemplate,openvswitch))
+
+ovs_kmod_openvswitch-gre_title:=Open vSwitch GRE tunneling support (upstream)
+ovs_kmod_openvswitch-gre_kconfig:= CONFIG_OPENVSWITCH_GRE
+ovs_kmod_openvswitch-gre_depends:= +kmod-openvswitch +kmod-gre
+ovs_kmod_openvswitch-gre_files:= $(ovs_kmod_upstream_dir)/vport-gre.ko
+$(eval $(call OvsKmodPackageTemplate,openvswitch-gre))
+
+ovs_kmod_openvswitch-vxlan_title:=Open vSwitch VXLAN tunneling support (upstream)
+ovs_kmod_openvswitch-vxlan_kconfig:= CONFIG_OPENVSWITCH_VXLAN
+ovs_kmod_openvswitch-vxlan_depends:= +kmod-openvswitch +kmod-vxlan
+ovs_kmod_openvswitch-vxlan_files:= $(ovs_kmod_upstream_dir)/vport-vxlan.ko
+$(eval $(call OvsKmodPackageTemplate,openvswitch-vxlan))
+
+ovs_kmod_openvswitch-geneve_title:=Open vSwitch Geneve tunneling support (upstream)
+ovs_kmod_openvswitch-geneve_kconfig:= CONFIG_OPENVSWITCH_GENEVE
+ovs_kmod_openvswitch-geneve_depends:= +kmod-openvswitch +kmod-geneve
+ovs_kmod_openvswitch-geneve_files:= $(ovs_kmod_upstream_dir)/vport-geneve.ko
+$(eval $(call OvsKmodPackageTemplate,openvswitch-geneve))
+
+# NOTE depends
+#
+#  - kmod-ipt-conntrack-extra: required for nf_conncount.ko
+#
+ovs_kmod_openvswitch-intree_title:=Open vSwitch kernel datapath (in tree)
+ovs_kmod_openvswitch-intree_depends:=\
+	  +kmod-lib-crc32c \
+	  +kmod-nf-nat \
+	  +IPV6:kmod-nf-nat6 \
+	  +kmod-nf-conntrack \
+	  +kmod-udptunnel4 \
+	  +kmod-ipt-conntrack-extra \
+
+ovs_kmod_openvswitch-intree_files:= $(ovs_kmod_intree_dir)/openvswitch.ko
+$(eval $(call OvsKmodPackageTemplate,openvswitch-intree))
+
+ovs_kmod_openvswitch-gre-intree_title:=Open vSwitch GRE tunneling support (in tree)
+ovs_kmod_openvswitch-gre-intree_depends:= +kmod-openvswitch-intree +kmod-gre
+ovs_kmod_openvswitch-gre-intree_files:= $(ovs_kmod_intree_dir)/vport-gre.ko
+$(eval $(call OvsKmodPackageTemplate,openvswitch-gre-intree))
+
+ovs_kmod_openvswitch-vxlan-intree_title:=Open vSwitch VXLAN tunneling support (in tree)
+ovs_kmod_openvswitch-vxlan-intree_depends:= +kmod-openvswitch-intree +kmod-vxlan
+ovs_kmod_openvswitch-vxlan-intree_files:= $(ovs_kmod_intree_dir)/vport-vxlan.ko
+$(eval $(call OvsKmodPackageTemplate,openvswitch-vxlan-intree))
+
+ovs_kmod_openvswitch-geneve-intree_title:=Open vSwitch Geneve tunneling support (in tree)
+ovs_kmod_openvswitch-geneve-intree_depends:= +kmod-openvswitch-intree +kmod-geneve
+ovs_kmod_openvswitch-geneve-intree_files:= $(ovs_kmod_intree_dir)/vport-geneve.ko
+$(eval $(call OvsKmodPackageTemplate,openvswitch-geneve-intree))
+
+ovs_kmod_openvswitch-stt-intree_title:=Open vSwitch STT tunneling support (in tree)
+ovs_kmod_openvswitch-stt-intree_depends:= +kmod-openvswitch-intree
+ovs_kmod_openvswitch-stt-intree_files:= $(ovs_kmod_intree_dir)/vport-stt.ko
+$(eval $(call OvsKmodPackageTemplate,openvswitch-stt-intree))
+
+ovs_kmod_openvswitch-lisp-intree_title:=Open vSwitch LISP tunneling support (in tree)
+ovs_kmod_openvswitch-lisp-intree_depends:= +kmod-openvswitch-intree
+ovs_kmod_openvswitch-lisp-intree_files:= $(ovs_kmod_intree_dir)/vport-lisp.ko
+$(eval $(call OvsKmodPackageTemplate,openvswitch-lisp-intree))
+
+# Dependency review
+#
+#	for f in sbin/*;   do echo $f; readelf -d $f | grep -i shared; done
+#	for f in bin/*;    do echo $f; readelf -d $f | grep -i shared; done
+#	for f in lib/*.so; do echo $f; readelf -d $f | grep -i shared; done
+#
+ovs_libopenvswitch_title:=Open vSwitch (libopenvswitch.so)
+ovs_libopenvswitch_hidden:=1
+ovs_libopenvswitch_depends:= \
+	+libatomic +libopenssl +OPENVSWITCH_WITH_LIBUNBOUND:libunbound \
+	+!(arc||arceb):libunwind
+ovs_libopenvswitch_files:=usr/lib/libopenvswitch*.so*
+$(eval $(call OvsPackageTemplate,libopenvswitch))
+
+
+ovs_libofproto_title:=Open vSwitch (libofproto.so libsflow.so)
+ovs_libofproto_hidden:=1
+ovs_libofproto_depends:= +libatomic
+ovs_libofproto_files:=usr/lib/libofproto*.so* usr/lib/libsflow*.so*
+$(eval $(call OvsPackageTemplate,libofproto))
+
+
+ovs_libovsdb_title:=Open vSwitch (libovsdb.so)
+ovs_libovsdb_hidden:=1
+ovs_libovsdb_depends:= +libatomic
+ovs_libovsdb_files:=usr/lib/libovsdb*.so*
+$(eval $(call OvsPackageTemplate,libovsdb))
+
+
+ovs_vswitchd_title:=Open vSwitch (ovs-vswitchd)
+ovs_vswitchd_hidden:=1
+ovs_vswitchd_depends:= \
+	+libatomic +openvswitch-libofproto +openvswitch-libopenvswitch
+ovs_vswitchd_files:=usr/sbin/ovs-vswitchd
+$(eval $(call OvsPackageTemplate,vswitchd))
+
+
+ovs_ovsdb_title:=Open vSwitch (ovsdb-server)
+ovs_ovsdb_hidden:=1
+ovs_ovsdb_depends:= \
+	+libatomic +openvswitch-libopenvswitch +openvswitch-libovsdb
+ovs_ovsdb_files:=usr/sbin/ovsdb-server
+$(eval $(call OvsPackageTemplate,ovsdb))
+
+
+ovs_common_title:=Open vSwitch (common files)
+ovs_common_hidden:=1
+ovs_common_depends:= \
+	+libatomic +openvswitch-libofproto +openvswitch-libopenvswitch \
+	+openvswitch-libovsdb
+ovs_common_files:= \
+	usr/share/openvswitch/scripts/ovs-lib \
+	usr/share/openvswitch/scripts/ovs-ctl \
+	usr/share/openvswitch/scripts/ovs-kmod-ctl \
+	usr/share/openvswitch/scripts/ovs-save \
+	$(foreach b,ovs-appctl ovs-dpctl ovs-ofctl ovs-vsctl ovsdb-client ovsdb-tool,usr/bin/$(b))
+define ovs_common_install
+	$$(INSTALL_DIR) $$(1)/etc/openvswitch
+	$$(INSTALL_DIR) $$(1)/etc/init.d
+	$$(INSTALL_BIN) ./files/openvswitch.init $$(1)/etc/init.d/openvswitch
+	$$(INSTALL_DIR) $$(1)/etc/config
+	$$(INSTALL_DATA) ./files/openvswitch.config $$(1)/etc/config/openvswitch
+	$$(INSTALL_DIR) $$(1)/usr/share/openvswitch/scripts
+	$$(INSTALL_BIN) ./files/ovs-ctl-wrapper $$(1)/usr/share/openvswitch/scripts/
+	$$(LN) /usr/share/openvswitch/scripts/ovs-ctl-wrapper $$(1)/usr/bin/ovs-ctl
+	$$(LN) /usr/share/openvswitch/scripts/ovs-ctl-wrapper $$(1)/usr/bin/ovs-kmod-ctl
+endef
+define Package/openvswitch-common/conffiles
+/etc/config/openvswitch
+/etc/openvswitch
+endef
+$(eval $(call OvsPackageTemplate,common))
+
+
+# coreutils-sleep is required by ovs-lib for sleeping a fraction of second
+#
+# uuidgen is required for generating system-id
+ovs_openvswitch_title:=Open vSwitch
+ovs_openvswitch_hidden:=
+ovs_openvswitch_depends:= \
+	+coreutils +coreutils-sleep +kmod-openvswitch +libatomic +openvswitch-common \
+	+openvswitch-ovsdb +openvswitch-vswitchd +uuidgen
+ovs_openvswitch_files:= usr/share/openvswitch/vswitch.ovsschema
+$(eval $(call OvsPackageTemplate,openvswitch))
+
+
+ovs_python3_title:=Open vSwitch (Python3 library)
+ovs_python3_hidden:=
+ovs_python3_depends:=+PACKAGE_openvswitch-python3:python3
+define ovs_python3_install
+	$$(INSTALL_DIR) $$(1)$$(PYTHON3_PKG_DIR)
+	$$(CP) $$(PKG_INSTALL_DIR)/usr/share/openvswitch/python/ovs $$(1)$$(PYTHON3_PKG_DIR)
+endef
+$(eval $(call OvsPackageTemplate,python3))
+
+
+CONFIGURE_ARGS+= \
+	--enable-ndebug \
+	--enable-shared \
+	--disable-libcapng \
+	--disable-silent-rules \
+
+CONFIGURE_VARS += \
+	$(if $(CONFIG_OPENVSWITCH_WITH_LIBUNBOUND),,ac_cv_lib_unbound_ub_ctx_create=no) \
+	ovs_cv_flake8=no \
+	ovs_cv_groff=no \
+	ovs_cv_python3=$(PYTHON3) \
+	ovs_cv_python3_host=$(HOST_PYTHON3_BIN) \
+	SPHINXBUILD=none \
+	KARCH=$(LINUX_KARCH) \
+
+ovs_intree_kmod_configs:=CONFIG_PACKAGE_kmod-openvswitch-intree
+ovs_intree_kmod_enabled:=$(strip $(foreach c,$(ovs_intree_kmod_configs),$($(c))))
+PKG_CONFIG_DEPENDS+=$(ovs_intree_kmod_configs)
+ifneq ($(ovs_intree_kmod_enabled),)
+  ifeq ($(ovs_kmod_intree_not_supported),)
+    CONFIGURE_ARGS += --with-linux=$(LINUX_DIR)
+  else
+    $(warning XXX: openvswitch: intree kmods selected but not supported)
+  endif
+endif
+
+TARGET_CFLAGS += -std=gnu99
+MAKE_VARS += PYTHONPATH="$(HOST_PYTHON3PATH)"
+
+export OVS_KERNEL_MAKE_FLAGS=$(KERNEL_MAKE_FLAGS)
+
+override CONFIG_AUTOREMOVE=
+
+$(foreach p,$(ovs_kmod_packages),\
+  $(eval $(call KernelPackage,$(p)))\
+)
+$(foreach p,$(ovs_packages),\
+  $(eval $(call BuildPackage,$(p)))\
+)
diff --git a/external/subpack/net/openvswitch/README.md b/external/subpack/net/openvswitch/README.md
new file mode 100644
index 0000000..bfc19a0
--- /dev/null
+++ b/external/subpack/net/openvswitch/README.md
@@ -0,0 +1,108 @@
+# Which packages to install
+
+Install `openvswitch` if you need OpenFlow virtual switch function.  It
+contains ovs-vswitchd, ovsdb-server and helper utilities such as ovs-vsctl,
+ovs-ofctl, ovs-ctl etc.
+
+Linux kernel datapath module openvswitch.ko will also be installed along with
+package `openvswitch`.  Tunnel encap support for gre, geneve, vxlan can be
+included by installing `kmod-openvswitch-{gre,geneve,vxlan}` respectively
+
+For OVN deployment
+
+- Install `openvswitch-ovn-north` for ovs-northd, ovsdb-server, ovn helper utitlies
+- Install `openvswitch-ovn-host` for ovn-controller and `openvswitch`
+
+# How to use them
+
+Open vSwitch provides a few very useful helper script in
+`/usr/share/openvswitch/scripts/`.  A simple initscript is provided.  It's
+mainly a wrapper around `ovs-ctl` and `ovn-ctl` with simple knobs from
+`/etc/config/openvswitch`.  Procd is not used here.
+
+	/etc/init.d/openvswitch start
+	/etc/init.d/openvswitch stop
+	/etc/init.d/openvswitch stop north
+	/etc/init.d/openvswitch restart ovs
+	/etc/init.d/openvswitch status
+
+Use `ovs-ctl` and `ovn-ctl` directly for more functionalities
+
+# Open vSwitch in-tree Linux datapath modules
+
+The Open vSwitch build system uses regexp and conditional-compilation
+heuristics to support building the shipped kernel module source code against a
+wide range of kernels, as of openvswitch-2.10, the list is supposed to include
+vanilla linux 3.10 to 4.15, plus a few distro kernels.
+
+It may NOT work
+
+ - Sometimes the code does not compile
+ - Sometimes the code compiles but insmod will fail
+ - Sometimes modules are loaded okay but actually does not function right
+
+For these reasons, the in-tree datapath modules are NOT visible/enabled by
+default.
+
+Building and using in-tree datapath modules requires some level of devel
+abilities to proceed.  You are expected to configure build options and build
+the code on your own
+
+E.g. pair openvswitch userspace with in-tree datapath module
+
+	CONFIG_DEVEL=y
+	CONFIG_PACKAGE_openvswitch=y
+	# CONFIG_PACKAGE_kmod-openvswitch is not set
+	CONFIG_PACKAGE_kmod-openvswitch-intree=y
+
+E.g. replace in-tree datapath module with upstream version
+
+	opkg remove --force-depends kmod-openvswitch-intree
+	opkg install kmod-openvswitch
+	ovs-ctl force-reload-kmod
+
+# UCI configuration options
+
+There are 5 config section types in package openvswitch:
+ovs ovn_northd, ovn_controller & ovs_bridge.
+
+Each of these supports a disabled option, which should be 
+set to 0 to launch the respective daemons.
+
+The ovs section section also supports the options below, to configure a set of
+SSL CA, certificate and private key. After adding these to Open vSwitch, you
+may specify ssl: connection methods for e.g. the OpenFlow controller. Note that
+Open vSwitch only reads these files during startup, so it needs to be restarted
+after adding or changing these options.
+
+| Name     | Type    | Required | Default | Description                       |
+|----------|---------|----------|---------|-----------------------------------|
+| disabled | boolean | no       | 0       | If set to 1, do not configure SSL |
+| ca       | string  | no       | (none)  | Path to CA certificate            |
+| cert     | string  | no       | (none)  | Path to certificate               |
+| key      | string  | no       | (none)  | Path to private key               |
+
+The ovs_bridge section also supports the options below,
+for initialising a virtual bridge with an OpenFlow controller.
+
+| Name               | Type    | Required | Default                        | Description                                                |
+|--------------------|---------|----------|--------------------------------|------------------------------------------------------------|
+| disabled           | boolean | no       | 0                              | If set to true, disable initialisation of the named bridge |
+| name               | string  | no       | Inherits UCI config block name | The name of the switch in the OVS daemon                   |
+| controller         | string  | no       | (none)                         | The endpoint of an OpenFlow controller for this bridge     |
+| datapath_id        | string  | no       | (none)                         | The OpenFlow datapath ID for this bridge                   |
+| datapath_desc      | string  | no       | (none)                         | The OpenFlow datapath description for this bridge          |
+| drop_unknown_ports | boolean | no       | 0                              | Remove ports not defined in UCI from the bridge            |
+| fail_mode          | string  | no       | standalone                     | The bridge failure mode                                    |
+| ports              | list    | no       | (none)                         | List of ports to add to the bridge                         |
+
+The ovs_port section can be used to add ports to a bridge. It supports the options below.
+
+| Name     | Type    | Required | Default | Description
+| ---------|---------|----------|---------|------------------------------------------------|
+| disabled | boolean | no       | 0       | If set to 1, do not add the port to the bridge |
+| bridge   | string  | yes      | (none)  | Name of the bridge to add the port to          |
+| port     | string  | yes      | (none)  | Name of the port to add to the bridge          |
+| ofport   | integer | no       | (none)  | OpenFlow port number to be used by the port    |
+| tag      | integer | no       | (none)  | 802.1Q VLAN tag to set on the port             |
+| type     | string  | no       | (none)  | Port type, e.g. internal, erspan, type, ...    |
diff --git a/external/subpack/net/openvswitch/files/openvswitch.config b/external/subpack/net/openvswitch/files/openvswitch.config
new file mode 100644
index 0000000..8fb9d1a
--- /dev/null
+++ b/external/subpack/net/openvswitch/files/openvswitch.config
@@ -0,0 +1,27 @@
+config ovs ovs
+	option disabled 1
+	option ca '/etc/openvswitch/example_ca.crt'
+	option cert '/etc/openvswitch/example_cert.crt'
+	option key '/etc/openvswitch/example_key.crt'
+
+config ovn_northd north
+	option disabled 1
+
+config ovn_controller controller
+	option disabled 1
+
+config ovs_bridge
+	option disabled 1
+	option name 'my-bridge'
+	option controller 'tcp:192.168.0.1'
+	option datapath_desc ''
+	option datapath_id ''
+	option fail_mode 'standalone'
+
+config ovs_port
+	option disabled 1
+	option bridge 'my-bridge'
+	option port 'ovs-port1'
+	option ofport '1'
+	option tag '123'
+	option type 'internal'
diff --git a/external/subpack/net/openvswitch/files/openvswitch.init b/external/subpack/net/openvswitch/files/openvswitch.init
new file mode 100755
index 0000000..abbbbf7
--- /dev/null
+++ b/external/subpack/net/openvswitch/files/openvswitch.init
@@ -0,0 +1,281 @@
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2013 Julius Schulz-Zander <julius@net.t-labs.tu-berlin.de>
+# Copyright (C) 2014-2017 OpenWrt.org
+# Copyright (C) 2018 Yousong Zhou <yszhou4tech@gmail.com>
+# Copyright (C) 2021 Felix Fietkau <nbd@nbd.name>
+
+. /lib/functions/procd.sh
+START=15
+
+basescript=$(readlink "$initscript")
+
+ovs_ctl="/usr/share/openvswitch/scripts/ovs-ctl"; [ -x "$ovs_ctl" ] || ovs_ctl=:
+ovn_ctl="/usr/share/ovn/scripts/ovn-ctl"; [ -x "$ovn_ctl" ] || ovn_ctl=:
+
+extra_command "status" "Get status information"
+
+service_triggers() {
+	procd_add_reload_trigger openvswitch
+}
+
+init_triggers() {
+	procd_open_service "$(basename ${basescript:-$initscript})" "$initscript"
+	procd_close_service set
+}
+
+start() {
+	init_triggers
+	ovs_action start "$@"
+}
+
+reload() {
+	start
+}
+
+running() {
+	return 0
+}
+
+stop() {
+	procd_kill "$(basename ${basescript:-$initscript})"
+	ovs_action stop "$@"
+}
+
+restart() {
+	init_triggers
+	ovs_action restart "$@"
+}
+
+status() {
+	ovs_action status "$@"
+}
+
+ovs_action_cfgs=
+ovs_action() {
+	local action="$1"; shift
+	local cfgtype
+
+	ovs_action_cfgs="$*"
+	config_load openvswitch
+	for cfgtype in ovs ovn_northd ovn_controller; do
+		config_foreach "ovs_xx" "$cfgtype" "$action" "$cfgtype"
+	done
+
+	case "$action" in
+		restart|start)
+			config_foreach ovs_bridge_init "ovs_bridge"
+			;;
+	esac
+
+}
+
+ovs_xx() {
+	local cfg="$1"
+	local action="$2"
+	local cfgtype="$3"
+	local disabled
+
+	if [ -n "$ovs_action_cfgs" ] && ! list_contains "ovs_action_cfgs" "$cfg"; then
+		return
+	fi
+	case "$action" in
+		status|stop) ;;
+		*)
+			config_get_bool disabled "$cfg" disabled 0
+			[ "$disabled" == "0" ] || return
+			;;
+	esac
+
+	case "$cfgtype" in
+		ovs)
+			"$ovs_ctl" "$action" \
+				--system-id=random 1000>&-
+			ovs_set_ssl
+			;;
+		ovn_*)
+			"$ovn_ctl" "${action}_${cfgtype#ovn_}"
+			;;
+	esac
+}
+
+ovs_bridge_parse_port() {
+	case "$1" in
+		*:*)
+			port="${1%%:*}"
+			type="${1#*:}"
+		;;
+		*)
+			port="$1"
+			type=""
+		;;
+	esac
+}
+
+ovs_bridge_port_add() {
+	[ -n "$1" ] || return
+
+	ovs_bridge_parse_port "$1"
+	cur_type="$(ovs-vsctl get interface "$port" type 2>/dev/null)"
+	[ "$?" = 0 ] && {
+		[ "$type" = "$cur_type" ] || ovs-vsctl del-port "$port"
+	}
+
+	ovs-vsctl --may-exist add-port "$name" "$port" ${type:+ -- set interface "$port" type="$type"}
+	ovs_bridge_port_up "$port"
+	__port_list="$__port_list ${port} "
+}
+
+ovs_bridge_port_add_complex() {
+	local cfg="$1"
+	local cur_bridge="$2"
+
+	local bridge disabled ofport port tag type
+	local cur_tag cur_type del_port
+
+	config_get_bool disabled "$cfg" disabled 0
+	[ "$disabled" = "0" ] || return
+
+	config_get bridge "$cfg" bridge
+	[ "$bridge" = "$cur_bridge" ] || return
+	ovs-vsctl br-exists "$bridge" || return
+
+	config_get port "$cfg" port
+	[ -n "$port" ] || return
+
+	config_get ofport "$cfg" ofport
+
+	config_get tag "$cfg" tag
+	if [ -n "$tag" ]; then
+		if cur_tag="$(ovs-vsctl get port "$port" tag 2>/dev/null)"; then
+			[ "$tag" = "$cur_tag" ] || del_port=1
+		fi
+	fi
+
+	config_get type "$cfg" type
+	if [ -n "$type" ]; then
+		if cur_type="$(ovs-vsctl get interface "$port" type 2>/dev/null)"; then
+			[ "$type" = "$cur_type" ] || del_port=1
+		fi
+	fi
+
+	[ "${del_port:-0}" -eq 1 ] && ovs-vsctl --if-exists del-port "$bridge" "$port"
+
+	ovs-vsctl --may-exist add-port "$bridge" "$port" ${tag:+tag="$tag"} \
+		${ofport:+ -- set interface "$port" ofport_request="$ofport"} \
+		${type:+ -- set interface "$port" type="$type"}
+	ovs_bridge_port_up "$port"
+	__port_list="$__port_list ${port} "
+}
+
+ovs_bridge_port_cleanup() {
+	for port in `ovs-vsctl list-ports "$name"`; do
+		case "$__port_list" in
+			*" $port "*);;
+			*) ovs-vsctl del-port "$port";;
+		esac
+	done
+}
+
+ovs_bridge_port_up() {
+	local port="$1"
+
+	ip link set dev "$port" up
+}
+
+ovs_bridge_validate_datapath_id() {
+	local dpid="$1"
+
+	if expr "$dpid" : '[[:xdigit:]]\{16\}$' > /dev/null; then
+		return 0
+	elif expr "$dpid" : '0x[[:xdigit:]]\{1,16\}$' > /dev/null; then
+		return 0
+	else
+		logger -t openvswitch "invalid datapath_id: $dpid"
+		return 1
+	fi
+}
+
+ovs_bridge_validate_datapath_desc() {
+	local dpdesc="$1"
+
+	if [ "$(echo $dpdesc | wc -c)" -le 255 ]; then
+		return 0
+	else
+		logger -t openvswitch "invalid datapath_desc: $dpdesc"
+		return 1
+	fi
+}
+
+ovs_bridge_validate_fail_mode() {
+	local fail_mode="$1"
+
+	case "$fail_mode" in
+		secure|standalone)
+			return 0
+			;;
+		*)
+			logger -t openvswitch "invalid fail_mode: $fail_mode"
+			return 1
+			;;
+	esac
+}
+
+ovs_bridge_init() {
+	local cfg="$1"
+
+	local disabled
+	local name
+	local controller
+	local datapath_id
+
+	config_get_bool disabled "$cfg" disabled 0
+	[ "$disabled" == "0" ] || return
+
+	config_get name "$cfg" name $cfg
+	ovs-vsctl --may-exist add-br "$name"
+
+	config_get datapath_id "$cfg" datapath_id
+	[ -n "$datapath_id" ] && {
+		ovs_bridge_validate_datapath_id "$datapath_id" && {
+			ovs-vsctl --if-exists set bridge "$name" other-config:datapath-id="$datapath_id"
+		}
+	}
+
+	config_get datapath_desc "$cfg" datapath_desc
+	[ -n "$datapath_desc" ] && {
+		ovs_bridge_validate_datapath_desc "$datapath_desc" && {
+			ovs-vsctl --if-exists set bridge "$name" other-config:dp-desc="$datapath_desc"
+		}
+	}
+
+	config_get fail_mode "$cfg" fail_mode
+	[ -n "$fail_mode" ] && {
+		ovs_bridge_validate_fail_mode "$fail_mode" && {
+			ovs-vsctl set-fail-mode "$name" "$fail_mode" 2> /dev/null
+		} || {
+			ovs-vsctl del-fail-mode "$name" 2> /dev/null
+		}
+	} || {
+		ovs-vsctl del-fail-mode "$name" 2> /dev/null
+	}
+
+	config_list_foreach "$cfg" "ports" ovs_bridge_port_add
+	config_foreach ovs_bridge_port_add_complex ovs_port "$name"
+	config_get_bool drop "$cfg" "drop_unknown_ports" 0
+	[ "$drop" == 1 ] && ovs_bridge_port_cleanup
+
+	config_get controller "$cfg" controller
+	[ -n "$controller" ] && \
+		ovs-vsctl set-controller "$name" "$controller"
+}
+
+ovs_set_ssl() {
+	local ca="$(uci -q get openvswitch.ovs.ca)"
+	[ -f "$ca" ] || return
+	local cert="$(uci get openvswitch.ovs.cert)"
+	[ -f "$cert" ] || return
+	local key="$(uci get openvswitch.ovs.key)"
+	[ -f "$key" ] || return
+
+	ovs-vsctl set-ssl "$key" "$cert" "$ca"
+}
diff --git a/external/subpack/net/openvswitch/files/ovs-ctl-wrapper b/external/subpack/net/openvswitch/files/ovs-ctl-wrapper
new file mode 100755
index 0000000..ee71755
--- /dev/null
+++ b/external/subpack/net/openvswitch/files/ovs-ctl-wrapper
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+s=/usr/share/openvswitch/scripts
+case "$0" in
+	*ovs-ctl) "$s/ovs-ctl" "$@" ;;
+	*ovs-kmod-ctl) "$s/ovs-kmod-ctl" "$@" ;;
+	*ovn-ctl) "/usr/share/ovn/scripts/ovn-ctl" "$@" ;;
+	*) exit 1;;
+esac
diff --git a/external/subpack/net/openvswitch/openvswitch.mk b/external/subpack/net/openvswitch/openvswitch.mk
new file mode 100644
index 0000000..4de376e
--- /dev/null
+++ b/external/subpack/net/openvswitch/openvswitch.mk
@@ -0,0 +1,36 @@
+# Copyright (C) 2020 Yousong Zhou <yszhou4tech@gmail.com>
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+
+# Versions
+
+ovs_version:=2.17.9
+ovs_builddir=$(KERNEL_BUILD_DIR)/openvswitch-$(ovs_version)
+
+# Shared vars, macros
+
+ovs_packages:=
+
+ovs_package_name=$(if $(filter openvswitch,$(1)),openvswitch,openvswitch-$(1))
+define OvsPackageTemplate
+  define Package/$(call ovs_package_name,$(1))
+     SECTION:=net
+     SUBMENU:=Open vSwitch
+     CATEGORY:=Network
+     URL:=https://www.openvswitch.org
+     TITLE:=$(ovs_$(1)_title)
+     HIDDEN:=$(ovs_$(1)_hidden)
+     DEPENDS:=$(ovs_$(1)_depends)
+  endef
+
+  define Package/$(call ovs_package_name,$(1))/install
+	$(foreach f,$(ovs_$(1)_files),
+		$(INSTALL_DIR) $$(1)/$(dir $(f))
+		$(CP) $(PKG_INSTALL_DIR)/$(f) $$(1)/$(dir $(f))
+	)
+	$(ovs_$(1)_install)
+  endef
+
+  ovs_packages+=$(call ovs_package_name,$(1))
+endef
diff --git a/external/subpack/net/openvswitch/patches/0001-netdev-linux-Let-interface-flag-survive-internal-por.patch b/external/subpack/net/openvswitch/patches/0001-netdev-linux-Let-interface-flag-survive-internal-por.patch
new file mode 100644
index 0000000..243b2a9
--- /dev/null
+++ b/external/subpack/net/openvswitch/patches/0001-netdev-linux-Let-interface-flag-survive-internal-por.patch
@@ -0,0 +1,35 @@
+From 974dc36a87274d7bae13e7dddd3364fecf5b3e7c Mon Sep 17 00:00:00 2001
+From: Helmut Schaa <helmut.schaa@googlemail.com>
+Date: Wed, 8 Jan 2014 13:48:49 +0100
+Subject: [PATCH] netdev-linux: Let interface flag survive internal port setup
+
+Due to a race condition when bringing up an internal port on Linux
+some interface flags (e.g. IFF_MULTICAST) are falsely reset. This
+happens because netlink events may be processed after the according
+netdev has been brought up (which sets interface flags).
+
+Fix this by reading the interface flags just before updating them
+if they have not been updated by from the kernel yet.
+
+Signed-off-by: Helmut Schaa <helmut.schaa@googlemail.com>
+---
+ lib/netdev-linux.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+--- a/lib/netdev-linux.c
++++ b/lib/netdev-linux.c
+@@ -3571,7 +3571,13 @@ update_flags(struct netdev_linux *netdev
+     unsigned int old_flags, new_flags;
+     int error = 0;
+ 
+-    old_flags = netdev->ifi_flags;
++    if (!(netdev->cache_valid & VALID_DRVINFO)) {
++        /* Most likely the debvice flags are not in sync yet, fetch them now */
++        get_flags(&netdev->up, &old_flags);
++    } else {
++        old_flags = netdev->ifi_flags;
++    }
++
+     *old_flagsp = iff_to_nd_flags(old_flags);
+     new_flags = (old_flags & ~nd_to_iff_flags(off)) | nd_to_iff_flags(on);
+     if (new_flags != old_flags) {
diff --git a/external/subpack/net/openvswitch/patches/0002-python-separate-host-target-python-for-cross-compile.patch b/external/subpack/net/openvswitch/patches/0002-python-separate-host-target-python-for-cross-compile.patch
new file mode 100644
index 0000000..5cd8d70
--- /dev/null
+++ b/external/subpack/net/openvswitch/patches/0002-python-separate-host-target-python-for-cross-compile.patch
@@ -0,0 +1,51 @@
+From 54484e79aca0981ebc42ddc68487e6531da9b59d Mon Sep 17 00:00:00 2001
+From: Yousong Zhou <yszhou4tech@gmail.com>
+Date: Fri, 20 Mar 2020 15:11:31 +0800
+Subject: [PATCH] python: separate host/target python for cross-compile
+
+Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com>
+---
+ Makefile.am       | 2 +-
+ m4/openvswitch.m4 | 2 ++
+ 2 files changed, 3 insertions(+), 1 deletion(-)
+
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -60,7 +60,7 @@ endif
+ # foo/__init__.pyc will cause Python to ignore foo.py.
+ run_python = \
+ 	PYTHONPATH=$(top_srcdir)/python$(psep)$$PYTHONPATH \
+-	PYTHONDONTWRITEBYTECODE=yes $(PYTHON3)
++	PYTHONDONTWRITEBYTECODE=yes $(PYTHON3_HOST)
+ 
+ ALL_LOCAL =
+ BUILT_SOURCES =
+@@ -148,7 +148,7 @@ ro_shell = printf '\043 Generated automa
+ 
+ SUFFIXES += .in
+ .in:
+-	$(AM_V_GEN)PYTHONPATH=$$PYTHONPATH$(psep)$(srcdir)/python $(PYTHON3) $(srcdir)/build-aux/soexpand.py -I$(srcdir) < $< | \
++	$(AM_V_GEN)$(run_python) $(srcdir)/build-aux/soexpand.py -I$(srcdir) < $< | \
+ 	  $(PYTHON3) $(srcdir)/build-aux/dpdkstrip.py $(DPDKSTRIP_FLAGS) | \
+ 	  sed \
+ 	    -e 's,[@]PKIDIR[@],$(PKIDIR),g' \
+@@ -415,7 +415,7 @@ CLEANFILES += flake8-check
+ 
+ -include manpages.mk
+ manpages.mk: $(MAN_ROOTS) build-aux/sodepends.py python/ovs_build_helpers/soutil.py
+-	@PYTHONPATH=$$PYTHONPATH$(psep)$(srcdir)/python $(PYTHON3) $(srcdir)/build-aux/sodepends.py -I. -I$(srcdir) $(MAN_ROOTS) >$(@F).tmp
++	@$(run_python) $(srcdir)/build-aux/sodepends.py -I. -I$(srcdir) $(MAN_ROOTS) >$(@F).tmp
+ 	@if cmp -s $(@F).tmp $@; then \
+ 	  touch $@; \
+ 	  rm -f $(@F).tmp; \
+--- a/m4/openvswitch.m4
++++ b/m4/openvswitch.m4
+@@ -400,6 +400,8 @@ else:
+      AC_MSG_ERROR([Python 3.4 or later is required but not found in $PATH, please install it or set $PYTHON3 to point to it])
+    fi
+    AC_ARG_VAR([PYTHON3])
++   PYTHON3_HOST=$ovs_cv_python3_host
++   AM_MISSING_PROG([PYTHON3_HOST], [python3])
+    PYTHON3=$ovs_cv_python3])
+ 
+ dnl Checks for flake8.
diff --git a/external/subpack/net/openvswitch/patches/0003-ovs-lib-fix-install_dir.patch b/external/subpack/net/openvswitch/patches/0003-ovs-lib-fix-install_dir.patch
new file mode 100644
index 0000000..373c6a6
--- /dev/null
+++ b/external/subpack/net/openvswitch/patches/0003-ovs-lib-fix-install_dir.patch
@@ -0,0 +1,26 @@
+From 444991b95ed25d58c3cd1646fa823620380b6ce6 Mon Sep 17 00:00:00 2001
+From: Yousong Zhou <yszhou4tech@gmail.com>
+Date: Wed, 14 Mar 2018 16:44:13 +0800
+Subject: [PATCH] ovs-lib: fix install_dir()
+
+The command "install" is not available in OpenWrt by default
+
+Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com>
+---
+ utilities/ovs-lib.in | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/utilities/ovs-lib.in
++++ b/utilities/ovs-lib.in
+@@ -159,7 +159,10 @@ install_dir () {
+     [ "${OVS_USER##*:}" != "" ] && INSTALL_GROUP="${OVS_USER##*:}"
+ 
+     if test ! -d "$DIR"; then
+-        install -d -m "$INSTALL_MODE" -o "$INSTALL_USER" -g "$INSTALL_GROUP" "$DIR"
++        mkdir -p "$DIR"
++        chmod "$INSTALL_MODE" "$DIR"
++        chown "$INSTALL_USER" "$DIR"
++        chgrp "$INSTALL_GROUP" "$DIR"
+         restorecon "$DIR" >/dev/null 2>&1
+     fi
+ }
diff --git a/external/subpack/net/openvswitch/patches/0004-build-trim-build.patch b/external/subpack/net/openvswitch/patches/0004-build-trim-build.patch
new file mode 100644
index 0000000..3e0eca5
--- /dev/null
+++ b/external/subpack/net/openvswitch/patches/0004-build-trim-build.patch
@@ -0,0 +1,25 @@
+From 31514742de07d595ac23c2b0abf0e092f8b26140 Mon Sep 17 00:00:00 2001
+From: Yousong Zhou <zhouyousong@yunionyun.com>
+Date: Tue, 21 Aug 2018 13:02:21 +0000
+Subject: [PATCH] build: trim build
+
+Signed-off-by: Yousong Zhou <zhouyousong@yunionyun.com>
+---
+ Makefile.am | 2 --
+ 1 file changed, 2 deletions(-)
+
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -477,12 +477,10 @@ dist-docs:
+ 	VERSION=$(VERSION) MAKE='$(MAKE)' $(srcdir)/build-aux/dist-docs $(srcdir) $(docs)
+ .PHONY: dist-docs
+ 
+-include Documentation/automake.mk
+ include m4/automake.mk
+ include lib/automake.mk
+ include ofproto/automake.mk
+ include utilities/automake.mk
+-include tests/automake.mk
+ include include/automake.mk
+ include third-party/automake.mk
+ include debian/automake.mk
diff --git a/external/subpack/net/openvswitch/patches/0006-datapath-allow-passing-additional-OVS_KERNEL_MAKE_FL.patch b/external/subpack/net/openvswitch/patches/0006-datapath-allow-passing-additional-OVS_KERNEL_MAKE_FL.patch
new file mode 100644
index 0000000..3993c60
--- /dev/null
+++ b/external/subpack/net/openvswitch/patches/0006-datapath-allow-passing-additional-OVS_KERNEL_MAKE_FL.patch
@@ -0,0 +1,23 @@
+From 1df5a0eaf78e93e21d21f1438afbe5fa8a37ea61 Mon Sep 17 00:00:00 2001
+From: Yousong Zhou <yszhou4tech@gmail.com>
+Date: Tue, 26 May 2020 22:45:53 +0800
+Subject: [PATCH] datapath: allow passing additional $(OVS_KERNEL_MAKE_FLAGS)
+
+This can be useful for passing args like -iremap for reproducible builds
+
+Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com>
+---
+ datapath/linux/Makefile.main.in | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/datapath/linux/Makefile.main.in
++++ b/datapath/linux/Makefile.main.in
+@@ -68,7 +68,7 @@ ifeq (,$(wildcard $(CONFIG_FILE)))
+ endif
+ 
+ default:
+-	$(MAKE) -C $(KSRC) $(if @KARCH@,ARCH=@KARCH@) M=$(builddir) modules
++	$(MAKE) -C $(KSRC) $(OVS_KERNEL_MAKE_FLAGS) $(if @KARCH@,ARCH=@KARCH@) M=$(builddir) modules
+ 
+ modules_install:
+ 	$(MAKE) -C $(KSRC) $(if @KARCH@,ARCH=@KARCH@) M=$(builddir) modules_install
diff --git a/external/subpack/net/openvswitch/patches/0007-build-only-link-libopenvswitch-with-libunwind-libunb.patch b/external/subpack/net/openvswitch/patches/0007-build-only-link-libopenvswitch-with-libunwind-libunb.patch
new file mode 100644
index 0000000..3da8dc1
--- /dev/null
+++ b/external/subpack/net/openvswitch/patches/0007-build-only-link-libopenvswitch-with-libunwind-libunb.patch
@@ -0,0 +1,54 @@
+From e81ccb671014db62bf622cd8f960d7930d27d9dc Mon Sep 17 00:00:00 2001
+From: Yousong Zhou <yszhou4tech@gmail.com>
+Date: Wed, 29 Jul 2020 17:29:14 +0800
+Subject: [PATCH] build: only link libopenvswitch with libunwind, libunbound
+
+Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com>
+---
+ lib/automake.mk          | 2 ++
+ lib/libopenvswitch.pc.in | 2 +-
+ m4/openvswitch.m4        | 6 ++++--
+ 3 files changed, 7 insertions(+), 3 deletions(-)
+
+--- a/lib/automake.mk
++++ b/lib/automake.mk
+@@ -10,6 +10,8 @@ lib_LTLIBRARIES += lib/libopenvswitch.la
+ lib_libopenvswitch_la_LIBADD = $(SSL_LIBS)
+ lib_libopenvswitch_la_LIBADD += $(CAPNG_LDADD)
+ lib_libopenvswitch_la_LIBADD += $(LIBBPF_LDADD)
++lib_libopenvswitch_la_LIBADD += $(LIBUNBOUND_LDADD)
++lib_libopenvswitch_la_LIBADD += $(LIBUNWIND_LDADD)
+ 
+ 
+ if WIN32
+--- a/lib/libopenvswitch.pc.in
++++ b/lib/libopenvswitch.pc.in
+@@ -7,5 +7,5 @@ Name: libopenvswitch
+ Description: Open vSwitch library
+ Version: @VERSION@
+ Libs: -L${libdir} -lopenvswitch
+-Libs.private: @LIBS@ @SSL_LIBS@ @CAPNG_LDADD@ @LIBBPF_LDADD@
++Libs.private: @LIBS@ @SSL_LIBS@ @CAPNG_LDADD@ @LIBBPF_LDADD@ @LIBUNBOUND_LDADD@ @LIBUNWIND_LDADD@
+ Cflags: -I${includedir}
+--- a/m4/openvswitch.m4
++++ b/m4/openvswitch.m4
+@@ -677,7 +677,8 @@ AC_DEFUN([OVS_CHECK_UNBOUND],
+   [AC_CHECK_LIB(unbound, ub_ctx_create, [HAVE_UNBOUND=yes], [HAVE_UNBOUND=no])
+    if test "$HAVE_UNBOUND" = yes; then
+      AC_DEFINE([HAVE_UNBOUND], [1], [Define to 1 if unbound is detected.])
+-     LIBS="$LIBS -lunbound"
++     LIBUNBOUND_LDADD="-lunbound"
++     AC_SUBST(LIBUNBOUND_LDADD)
+    fi
+    AM_CONDITIONAL([HAVE_UNBOUND], [test "$HAVE_UNBOUND" = yes])
+    AC_SUBST([HAVE_UNBOUND])])
+@@ -689,7 +690,8 @@ AC_DEFUN([OVS_CHECK_UNWIND],
+    [HAVE_UNWIND=no])
+    if test "$HAVE_UNWIND" = yes; then
+      AC_DEFINE([HAVE_UNWIND], [1], [Define to 1 if unwind is detected.])
+-     LIBS="$LIBS -lunwind"
++     LIBUNWIND_LDADD="-lunwind"
++     AC_SUBST(LIBUNWIND_LDADD)
+    fi
+    AM_CONDITIONAL([HAVE_UNWIND], [test "$HAVE_UNWIND" = yes])
+    AC_SUBST([HAVE_UNWIND])])
diff --git a/external/subpack/net/openvswitch/patches/0008-backport-d94cd0d-ovsdb-idl-Support-write-only-change.patch b/external/subpack/net/openvswitch/patches/0008-backport-d94cd0d-ovsdb-idl-Support-write-only-change.patch
new file mode 100644
index 0000000..c39141f
--- /dev/null
+++ b/external/subpack/net/openvswitch/patches/0008-backport-d94cd0d-ovsdb-idl-Support-write-only-change.patch
@@ -0,0 +1,318 @@
+From d94cd0d3eec33e4290d7ca81918f5ac61444886e Mon Sep 17 00:00:00 2001
+From: Dumitru Ceara <dceara@redhat.com>
+Date: Tue, 26 Apr 2022 12:37:08 +0200
+Subject: [PATCH] ovsdb-idl: Support write-only-changed IDL monitor mode.
+
+At a first glance, change tracking should never be allowed for
+write-only columns.  However, some clients (e.g., ovn-northd) that are
+mostly exclusive writers of a database, use change tracking to avoid
+duplicating the IDL row records into a local cache when implementing
+incremental processing.
+
+The default behavior of the IDL is to automatically turn a write-only
+column into a read-write column whenever the client enables change
+tracking for that column.
+
+For the afore mentioned clients, this becomes a performance issue.
+Commit 1cc618c32524 ("ovsdb-idl: Fix atomicity of writes that don't
+change a column's value.") explains why writes that don't change a
+column's value cannot be optimized out early if the column is
+read/write.
+
+Furthermore, if there is at least one record in any table that
+changed during a transaction, then *all* records that have been
+written are added to the transaction, even if their values didn't
+change.  If there are many such rows (e.g., like in ovn-northd's
+case) this incurs a significant overhead because:
+a. the client has to build this large transaction
+b. the transaction has to be sent over the network
+c. the server needs to parse this (mostly) no-op update
+
+We now introduce new IDL APIs allowing users to set a new monitoring
+mode flag, OVSDB_IDL_WRITE_CHANGED_ONLY, to indicate to the IDL that the
+atomicity constraints may be relaxed and written columns that don't
+change value can be skipped from the current transaction.
+
+We benchmarked ovn-northd performance when using this new mode
+against NB and SB databases taken from ovn-kubernetes scale tests.
+We noticed that when a minor change is performed to the Northbound
+database (e.g., NB_Global.nb_cfg is incremented) the time it takes to
+build the Southbound transaction becomes negligible (vs ~1.5 seconds
+before this change).
+
+End-to-end ovn-kubernetes scale tests on 120-node clusters also show
+significant reduction of latency to bring up pods; both average and P99
+latency decreased by ~30%.
+
+Acked-by: Han Zhou <hzhou@ovn.org>
+Signed-off-by: Dumitru Ceara <dceara@redhat.com>
+Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
+---
+ lib/ovsdb-idl.c    | 60 +++++++++++++++++++++++++++++++++++++++++-----
+ lib/ovsdb-idl.h    | 16 +++++++++++--
+ tests/ovsdb-idl.at | 31 +++++++++++++++++++++++-
+ tests/test-ovsdb.c | 18 ++++++++++----
+ 5 files changed, 115 insertions(+), 14 deletions(-)
+
+--- a/lib/ovsdb-idl.c
++++ b/lib/ovsdb-idl.c
+@@ -1398,6 +1398,45 @@ ovsdb_idl_track_clear(struct ovsdb_idl *
+ {
+     ovsdb_idl_track_clear__(idl, false);
+ }
++
++/* Sets or clears (depending on 'enable') OVSDB_IDL_WRITE_CHANGED_ONLY
++ * for 'column' in 'idl', ensuring that the column will be included in a
++ * transaction only if its value has actually changed locally.  Normally
++ * read/write columns that are written to are always included in the
++ * transaction but, in specific cases, when the application doesn't
++ * require atomicity of writes across different columns, the ones that
++ * don't change value may be skipped.
++ *
++ * This function should be called between ovsdb_idl_create() and
++ * the first call to ovsdb_idl_run().
++ */
++void
++ovsdb_idl_set_write_changed_only(struct ovsdb_idl *idl,
++                                 const struct ovsdb_idl_column *column,
++                                 bool enable)
++{
++    if (enable) {
++        *ovsdb_idl_get_mode(idl, column) |= OVSDB_IDL_WRITE_CHANGED_ONLY;
++    } else {
++        *ovsdb_idl_get_mode(idl, column) &= ~OVSDB_IDL_WRITE_CHANGED_ONLY;
++    }
++}
++
++/* Helper function to wrap calling ovsdb_idl_set_write_changed_only() for
++ * all columns that are part of 'idl'.
++ */
++void
++ovsdb_idl_set_write_changed_only_all(struct ovsdb_idl *idl, bool enable)
++{
++    for (size_t i = 0; i < idl->class_->n_tables; i++) {
++        const struct ovsdb_idl_table_class *tc = &idl->class_->tables[i];
++
++        for (size_t j = 0; j < tc->n_columns; j++) {
++            const struct ovsdb_idl_column *column = &tc->columns[j];
++            ovsdb_idl_set_write_changed_only(idl, column, enable);
++        }
++    }
++}
+ 
+ static void
+ log_parse_update_error(struct ovsdb_error *error)
+@@ -3502,6 +3541,8 @@ ovsdb_idl_txn_write__(const struct ovsdb
+ {
+     struct ovsdb_idl_row *row = CONST_CAST(struct ovsdb_idl_row *, row_);
+     const struct ovsdb_idl_table_class *class;
++    unsigned char column_mode;
++    bool optimize_rewritten;
+     size_t column_idx;
+     bool write_only;
+ 
+@@ -3512,12 +3553,15 @@ ovsdb_idl_txn_write__(const struct ovsdb
+ 
+     class = row->table->class_;
+     column_idx = column - class->columns;
+-    write_only = row->table->modes[column_idx] == OVSDB_IDL_MONITOR;
++    column_mode = row->table->modes[column_idx];
++    write_only = column_mode == OVSDB_IDL_MONITOR;
++    optimize_rewritten =
++        write_only || (column_mode & OVSDB_IDL_WRITE_CHANGED_ONLY);
++
+ 
+     ovs_assert(row->new_datum != NULL);
+     ovs_assert(column_idx < class->n_columns);
+-    ovs_assert(row->old_datum == NULL ||
+-               row->table->modes[column_idx] & OVSDB_IDL_MONITOR);
++    ovs_assert(row->old_datum == NULL || column_mode & OVSDB_IDL_MONITOR);
+ 
+     if (row->table->idl->verify_write_only && !write_only) {
+         VLOG_ERR("Bug: Attempt to write to a read/write column (%s:%s) when"
+@@ -3535,9 +3579,13 @@ ovsdb_idl_txn_write__(const struct ovsdb
+      * different value in that column since we read it.  (But if a whole
+      * transaction only does writes of existing values, without making any real
+      * changes, we will drop the whole transaction later in
+-     * ovsdb_idl_txn_commit().) */
+-    if (write_only && ovsdb_datum_equals(ovsdb_idl_read(row, column),
+-                                         datum, &column->type)) {
++     * ovsdb_idl_txn_commit().)
++     *
++     * The application may choose to bypass this restriction and always
++     * optimize by setting OVSDB_IDL_WRITE_CHANGED_ONLY.
++     */
++    if (optimize_rewritten && ovsdb_datum_equals(ovsdb_idl_read(row, column),
++                                                 datum, &column->type)) {
+         goto discard_datum;
+     }
+ 
+--- a/lib/ovsdb-idl.h
++++ b/lib/ovsdb-idl.h
+@@ -158,7 +158,7 @@ bool ovsdb_idl_server_has_column(const s
+  * IDL will change the value returned by ovsdb_idl_get_seqno() when the
+  * column's value changes in any row.
+  *
+- * The possible mode combinations are:
++ * Typical mode combinations are:
+  *
+  *   - 0, for a column that a client doesn't care about.  This is the default
+  *     for every column in every table, if the client passes false for
+@@ -181,10 +181,17 @@ bool ovsdb_idl_server_has_column(const s
+  *   - (OVSDB_IDL_MONITOR | OVSDB_IDL_ALERT | OVSDB_IDL_TRACK), for a column
+  *     that a client wants to track using the change tracking
+  *     ovsdb_idl_track_get_*() functions.
++ *
++ *   - (OVSDB_IDL_MONITOR | OVSDB_IDL_ALERT | OVSDB_IDL_WRITE_CHANGED_ONLY)
++ *     is similar to (OVSDB_IDL_MONITOR | OVSDB_IDL_ALERT) except that it
++ *     only adds a written column to a transaction if the column's value
++ *     has actually changed.
+  */
+ #define OVSDB_IDL_MONITOR (1 << 0) /* Replicate this column? */
+ #define OVSDB_IDL_ALERT   (1 << 1) /* Alert client when column changes? */
+-#define OVSDB_IDL_TRACK   (1 << 2)
++#define OVSDB_IDL_TRACK   (1 << 2) /* Track column changes? */
++#define OVSDB_IDL_WRITE_CHANGED_ONLY \
++                          (1 << 3) /* Write back only changed columns? */
+ 
+ void ovsdb_idl_add_column(struct ovsdb_idl *, const struct ovsdb_idl_column *);
+ void ovsdb_idl_add_table(struct ovsdb_idl *,
+@@ -233,6 +240,11 @@ bool ovsdb_idl_track_is_updated(const st
+                                 const struct ovsdb_idl_column *column);
+ void ovsdb_idl_track_clear(struct ovsdb_idl *);
+ 
++void ovsdb_idl_set_write_changed_only(struct ovsdb_idl *idl,
++                                      const struct ovsdb_idl_column *column,
++                                      bool enable);
++void ovsdb_idl_set_write_changed_only_all(struct ovsdb_idl *idl, bool enable);
++
+ 
+ /* Reading the database replica. */
+ 
+--- a/tests/ovsdb-idl.at
++++ b/tests/ovsdb-idl.at
+@@ -94,6 +94,20 @@ m4_define([OVSDB_CHECK_IDL_C],
+    OVSDB_SERVER_SHUTDOWN
+    AT_CLEANUP])
+ 
++# same as OVSDB_CHECK_IDL but uses OVSDB_IDL_WRITE_CHANGED_ONLY.
++m4_define([OVSDB_CHECK_IDL_WRITE_CHANGED_ONLY_C],
++  [AT_SETUP([$1 - write-changed-only - C])
++   AT_KEYWORDS([ovsdb server idl positive $5])
++   AT_CHECK([ovsdb_start_idltest])
++   m4_if([$2], [], [],
++     [AT_CHECK([ovsdb-client transact unix:socket $2], [0], [ignore], [ignore])])
++   AT_CHECK([test-ovsdb '-vPATTERN:console:test-ovsdb|%c|%m' -vjsonrpc -t10 idl unix:socket $3],
++            [0], [stdout], [ignore])
++   AT_CHECK([sort stdout | uuidfilt]m4_if([$6],,, [[| $6]]),
++            [0], [$4])
++   OVSDB_SERVER_SHUTDOWN
++   AT_CLEANUP])
++
+ # same as OVSDB_CHECK_IDL but uses tcp.
+ m4_define([OVSDB_CHECK_IDL_TCP_C],
+   [AT_SETUP([$1 - C - tcp])
+@@ -264,6 +278,7 @@ m4_define([OVSDB_CHECK_IDL_SSL_PY],
+ 
+ m4_define([OVSDB_CHECK_IDL],
+   [OVSDB_CHECK_IDL_C($@)
++  OVSDB_CHECK_IDL_WRITE_CHANGED_ONLY_C($@)
+    OVSDB_CHECK_IDL_TCP_C($@)
+    OVSDB_CHECK_IDL_TCP6_C($@)
+    OVSDB_CHECK_IDL_PY($@)
+@@ -1202,8 +1217,22 @@ m4_define([OVSDB_CHECK_IDL_TRACK_C],
+    OVSDB_SERVER_SHUTDOWN
+    AT_CLEANUP])
+ 
++m4_define([OVSDB_CHECK_IDL_TRACK_WRITE_CHANGED_ONLY_C],
++  [AT_SETUP([$1 - write-changed-only - C])
++   AT_KEYWORDS([ovsdb server idl tracking positive $5])
++   AT_CHECK([ovsdb_start_idltest])
++   m4_if([$2], [], [],
++     [AT_CHECK([ovsdb-client transact unix:socket $2], [0], [ignore], [ignore])])
++   AT_CHECK([test-ovsdb '-vPATTERN:console:test-ovsdb|%c|%m' -vjsonrpc -t10 -c -w idl unix:socket $3],
++            [0], [stdout], [ignore])
++   AT_CHECK([sort stdout | uuidfilt]m4_if([$6],,, [[| $6]]),
++            [0], [$4])
++   OVSDB_SERVER_SHUTDOWN
++   AT_CLEANUP])
++
+ m4_define([OVSDB_CHECK_IDL_TRACK],
+-  [OVSDB_CHECK_IDL_TRACK_C($@)])
++  [OVSDB_CHECK_IDL_TRACK_C($@)
++   OVSDB_CHECK_IDL_TRACK_WRITE_CHANGED_ONLY_C($@)])
+ 
+ OVSDB_CHECK_IDL_TRACK([track, simple idl, initially populated],
+   [['["idltest",
+--- a/tests/test-ovsdb.c
++++ b/tests/test-ovsdb.c
+@@ -56,6 +56,7 @@
+ VLOG_DEFINE_THIS_MODULE(test_ovsdb);
+ 
+ struct test_ovsdb_pvt_context {
++    bool write_changed_only;
+     bool track;
+ };
+ 
+@@ -91,6 +92,7 @@ parse_options(int argc, char *argv[], st
+         {"timeout", required_argument, NULL, 't'},
+         {"verbose", optional_argument, NULL, 'v'},
+         {"change-track", optional_argument, NULL, 'c'},
++        {"write-changed-only", optional_argument, NULL, 'w'},
+         {"magic", required_argument, NULL, OPT_MAGIC},
+         {"no-rename-open-files", no_argument, NULL, OPT_NO_RENAME_OPEN_FILES},
+         {"help", no_argument, NULL, 'h'},
+@@ -125,6 +127,10 @@ parse_options(int argc, char *argv[], st
+             pvt->track = true;
+             break;
+ 
++        case 'w':
++            pvt->write_changed_only = true;
++            break;
++
+         case OPT_MAGIC:
+             magic = optarg;
+             break;
+@@ -2681,6 +2687,7 @@ update_conditions(struct ovsdb_idl *idl,
+ static void
+ do_idl(struct ovs_cmdl_context *ctx)
+ {
++    struct test_ovsdb_pvt_context *pvt = ctx->pvt;
+     struct jsonrpc *rpc;
+     struct ovsdb_idl *idl;
+     unsigned int next_cond_seqno = 0;
+@@ -2690,9 +2697,6 @@ do_idl(struct ovs_cmdl_context *ctx)
+     int step = 0;
+     int error;
+     int i;
+-    bool track;
+-
+-    track = ((struct test_ovsdb_pvt_context *)(ctx->pvt))->track;
+ 
+     idl = ovsdb_idl_create(ctx->argv[1], &idltest_idl_class, true, true);
+     ovsdb_idl_set_leader_only(idl, false);
+@@ -2709,10 +2713,14 @@ do_idl(struct ovs_cmdl_context *ctx)
+         rpc = NULL;
+     }
+ 
+-    if (track) {
++    if (pvt->track) {
+         ovsdb_idl_track_add_all(idl);
+     }
+ 
++    if (pvt->write_changed_only) {
++        ovsdb_idl_set_write_changed_only_all(idl, true);
++    }
++
+     setvbuf(stdout, NULL, _IONBF, 0);
+ 
+     symtab = ovsdb_symbol_table_create();
+@@ -2770,7 +2778,7 @@ do_idl(struct ovs_cmdl_context *ctx)
+             }
+ 
+             /* Print update. */
+-            if (track) {
++            if (pvt->track) {
+                 print_idl_track(idl, step++, terse);
+                 ovsdb_idl_track_clear(idl);
+             } else {