From 9f539bff2e7f23aa70786a8feeb2a6953a76a77e Mon Sep 17 00:00:00 2001
From: Mark Michelson
Date: Oct 16 2024 17:49:36 +0000
Subject: Create ovn24.09 branch based on RHEL ovn24.09 disgit.
---
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5651078
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+SOURCES/*.tar.gz
+SRPMS
diff --git a/.ovn.metadata b/.ovn.metadata
new file mode 100644
index 0000000..c06f182
--- /dev/null
+++ b/.ovn.metadata
@@ -0,0 +1,5 @@
+002450621b33c5690060345b0aac25bc2426d675 SOURCES/docutils-0.12.tar.gz
+3de4c32ea0b8076955ee1c5fee5cf33d08208598 SOURCES/openvswitch-c598c05.tar.gz
+ed85aed0acfee4eca42a63b0a979a141525ebdc9 SOURCES/ovn-24.09.0.tar.gz
+d34f96421a86004aa5d26ecf975edefd09f948b1 SOURCES/Pygments-1.4.tar.gz
+6beb30f18ffac3de7689b7fd63e9a8a7d9c8df3a SOURCES/Sphinx-1.1.3.tar.gz
diff --git a/SOURCES/arm64-armv8a-linuxapp-gcc-config b/SOURCES/arm64-armv8a-linuxapp-gcc-config
new file mode 100644
index 0000000..5813d7a
--- /dev/null
+++ b/SOURCES/arm64-armv8a-linuxapp-gcc-config
@@ -0,0 +1,540 @@
+# -*- cfg-sha: 9fc8b53ccd53cc8b64391f6252e1dba558ae660a73a72f10dcadff2ca5462243
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2015 Cavium, Inc
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2017 Cavium, Inc
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2010-2016 Intel Corporation
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2010-2017 Intel Corporation
+# RTE_EXEC_ENV values are the directories in mk/exec-env/
+CONFIG_RTE_EXEC_ENV="linuxapp"
+# RTE_ARCH values are architecture we compile for. directories in mk/arch/
+CONFIG_RTE_ARCH="arm64"
+# machine can define specific variables or action for a specific board
+# RTE_MACHINE values are architecture we compile for. directories in mk/machine/
+CONFIG_RTE_MACHINE="armv8a"
+# The compiler we use.
+# RTE_TOOLCHAIN values are architecture we compile for. directories in mk/toolchain/
+CONFIG_RTE_TOOLCHAIN="gcc"
+# Use intrinsics or assembly code for key routines
+CONFIG_RTE_FORCE_INTRINSICS=y
+# Machine forces strict alignment constraints.
+CONFIG_RTE_ARCH_STRICT_ALIGN=n
+# Compile to share library
+CONFIG_RTE_BUILD_SHARED_LIB=n
+# Use newest code breaking previous ABI
+CONFIG_RTE_NEXT_ABI=n
+# Major ABI to overwrite library specific LIBABIVER
+CONFIG_RTE_MAJOR_ABI=
+# Machine's cache line size
+CONFIG_RTE_CACHE_LINE_SIZE=128
+# Memory model
+CONFIG_RTE_USE_C11_MEM_MODEL=y
+# Compile Environment Abstraction Layer
+CONFIG_RTE_LIBRTE_EAL=y
+CONFIG_RTE_MAX_LCORE=256
+CONFIG_RTE_MAX_NUMA_NODES=8
+CONFIG_RTE_MAX_HEAPS=32
+CONFIG_RTE_MAX_MEMSEG_LISTS=64
+# each memseg list will be limited to either RTE_MAX_MEMSEG_PER_LIST pages
+# or RTE_MAX_MEM_MB_PER_LIST megabytes worth of memory, whichever is smaller
+CONFIG_RTE_MAX_MEMSEG_PER_LIST=8192
+CONFIG_RTE_MAX_MEM_MB_PER_LIST=32768
+# a "type" is a combination of page size and NUMA node. total number of memseg
+# lists per type will be limited to either RTE_MAX_MEMSEG_PER_TYPE pages (split
+# over multiple lists of RTE_MAX_MEMSEG_PER_LIST pages), or
+# RTE_MAX_MEM_MB_PER_TYPE megabytes of memory (split over multiple lists of
+# RTE_MAX_MEM_MB_PER_LIST), whichever is smaller
+CONFIG_RTE_MAX_MEMSEG_PER_TYPE=32768
+CONFIG_RTE_MAX_MEM_MB_PER_TYPE=131072
+# global maximum usable amount of VA, in megabytes
+CONFIG_RTE_MAX_MEM_MB=524288
+CONFIG_RTE_MAX_MEMZONE=2560
+CONFIG_RTE_MAX_TAILQ=32
+CONFIG_RTE_ENABLE_ASSERT=n
+CONFIG_RTE_LOG_DP_LEVEL=RTE_LOG_INFO
+CONFIG_RTE_LOG_HISTORY=256
+CONFIG_RTE_BACKTRACE=y
+CONFIG_RTE_LIBEAL_USE_HPET=n
+CONFIG_RTE_EAL_ALLOW_INV_SOCKET_ID=n
+CONFIG_RTE_EAL_ALWAYS_PANIC_ON_ERROR=n
+CONFIG_RTE_EAL_IGB_UIO=n
+CONFIG_RTE_EAL_VFIO=y
+CONFIG_RTE_MAX_VFIO_GROUPS=64
+CONFIG_RTE_MAX_VFIO_CONTAINERS=64
+CONFIG_RTE_MALLOC_DEBUG=n
+CONFIG_RTE_EAL_NUMA_AWARE_HUGEPAGES=y
+CONFIG_RTE_USE_LIBBSD=n
+# Recognize/ignore architecture we compile for. AVX/AVX512 CPU flags for performance/power testing.
+# AVX512 is marked as experimental for now, will enable it after enough
+# field test and possible optimization.
+CONFIG_RTE_ENABLE_AVX=y
+CONFIG_RTE_ENABLE_AVX512=n
+# Default driver path (or "" to disable)
+CONFIG_RTE_EAL_PMD_PATH=""
+# Compile Environment Abstraction Layer to support Vmware TSC map
+CONFIG_RTE_LIBRTE_EAL_VMWARE_TSC_MAP_SUPPORT=y
+# Compile architecture we compile for. PCI library
+CONFIG_RTE_LIBRTE_PCI=y
+# Compile architecture we compile for. argument parser library
+CONFIG_RTE_LIBRTE_KVARGS=y
+# Compile generic ethernet library
+CONFIG_RTE_LIBRTE_ETHER=y
+CONFIG_RTE_LIBRTE_ETHDEV_DEBUG=n
+CONFIG_RTE_MAX_ETHPORTS=32
+CONFIG_RTE_MAX_QUEUES_PER_PORT=1024
+CONFIG_RTE_LIBRTE_IEEE1588=n
+CONFIG_RTE_ETHDEV_QUEUE_STAT_CNTRS=16
+CONFIG_RTE_ETHDEV_RXTX_CALLBACKS=y
+CONFIG_RTE_ETHDEV_PROFILE_WITH_VTUNE=n
+# Turn off Tx preparation stage
+# Warning: rte_eth_tx_prepare() can be safely disabled only if using a
+# driver which do not implement any Tx preparation.
+CONFIG_RTE_ETHDEV_TX_PREPARE_NOOP=n
+# Common libraries, before Bus/PMDs
+CONFIG_RTE_LIBRTE_COMMON_DPAAX=n
+# Compile architecture we compile for. Intel FPGA bus
+CONFIG_RTE_LIBRTE_IFPGA_BUS=n
+# Compile PCI bus driver
+CONFIG_RTE_LIBRTE_PCI_BUS=y
+# Compile architecture we compile for. vdev bus
+CONFIG_RTE_LIBRTE_VDEV_BUS=y
+# Compile ARK PMD
+CONFIG_RTE_LIBRTE_ARK_PMD=n
+CONFIG_RTE_LIBRTE_ARK_PAD_TX=y
+CONFIG_RTE_LIBRTE_ARK_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_ARK_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_ARK_DEBUG_STATS=n
+CONFIG_RTE_LIBRTE_ARK_DEBUG_TRACE=n
+# Compile Aquantia Atlantic PMD driver
+CONFIG_RTE_LIBRTE_ATLANTIC_PMD=n
+# Compile AMD PMD
+CONFIG_RTE_LIBRTE_AXGBE_PMD=n
+CONFIG_RTE_LIBRTE_AXGBE_PMD_DEBUG=n
+# Compile burst-oriented Broadcom PMD driver
+CONFIG_RTE_LIBRTE_BNX2X_PMD=n
+CONFIG_RTE_LIBRTE_BNX2X_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_BNX2X_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_BNX2X_MF_SUPPORT=n
+CONFIG_RTE_LIBRTE_BNX2X_DEBUG_PERIODIC=n
+# Compile burst-oriented Broadcom BNXT PMD driver
+CONFIG_RTE_LIBRTE_BNXT_PMD=n
+# Compile burst-oriented Chelsio Terminator (CXGBE) PMD
+CONFIG_RTE_LIBRTE_CXGBE_PMD=n
+CONFIG_RTE_LIBRTE_CXGBE_DEBUG=n
+CONFIG_RTE_LIBRTE_CXGBE_DEBUG_REG=n
+CONFIG_RTE_LIBRTE_CXGBE_DEBUG_MBOX=n
+CONFIG_RTE_LIBRTE_CXGBE_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_CXGBE_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_CXGBE_TPUT=y
+# NXP DPAA Bus
+CONFIG_RTE_LIBRTE_DPAA_BUS=n
+CONFIG_RTE_LIBRTE_DPAA_MEMPOOL=n
+CONFIG_RTE_LIBRTE_DPAA_PMD=n
+CONFIG_RTE_LIBRTE_DPAA_HWDEBUG=n
+# Compile NXP DPAA2 FSL-MC Bus
+CONFIG_RTE_LIBRTE_FSLMC_BUS=n
+# Compile Support Libraries for NXP DPAA2
+CONFIG_RTE_LIBRTE_DPAA2_MEMPOOL=n
+CONFIG_RTE_LIBRTE_DPAA2_USE_PHYS_IOVA=y
+# Compile burst-oriented NXP DPAA2 PMD driver
+CONFIG_RTE_LIBRTE_DPAA2_PMD=n
+CONFIG_RTE_LIBRTE_DPAA2_DEBUG_DRIVER=n
+# Compile NXP ENETC PMD Driver
+CONFIG_RTE_LIBRTE_ENETC_PMD=n
+# Compile burst-oriented Amazon ENA PMD driver
+CONFIG_RTE_LIBRTE_ENA_PMD=n
+CONFIG_RTE_LIBRTE_ENA_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_ENA_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_ENA_DEBUG_TX_FREE=n
+CONFIG_RTE_LIBRTE_ENA_COM_DEBUG=n
+# Compile burst-oriented Cisco ENIC PMD driver
+CONFIG_RTE_LIBRTE_ENIC_PMD=n
+# Compile burst-oriented IGB & EM PMD drivers
+CONFIG_RTE_LIBRTE_EM_PMD=n
+CONFIG_RTE_LIBRTE_IGB_PMD=y
+CONFIG_RTE_LIBRTE_E1000_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_E1000_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_E1000_DEBUG_TX_FREE=n
+CONFIG_RTE_LIBRTE_E1000_PF_DISABLE_STRIP_CRC=n
+# Compile burst-oriented IXGBE PMD driver
+CONFIG_RTE_LIBRTE_IXGBE_PMD=y
+CONFIG_RTE_LIBRTE_IXGBE_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_IXGBE_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_IXGBE_DEBUG_TX_FREE=n
+CONFIG_RTE_LIBRTE_IXGBE_PF_DISABLE_STRIP_CRC=n
+CONFIG_RTE_IXGBE_INC_VECTOR=y
+CONFIG_RTE_LIBRTE_IXGBE_BYPASS=n
+# Compile burst-oriented I40E PMD driver
+CONFIG_RTE_LIBRTE_I40E_PMD=y
+CONFIG_RTE_LIBRTE_I40E_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_I40E_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_I40E_DEBUG_TX_FREE=n
+CONFIG_RTE_LIBRTE_I40E_RX_ALLOW_BULK_ALLOC=y
+CONFIG_RTE_LIBRTE_I40E_INC_VECTOR=y
+CONFIG_RTE_LIBRTE_I40E_16BYTE_RX_DESC=n
+CONFIG_RTE_LIBRTE_I40E_QUEUE_NUM_PER_PF=64
+CONFIG_RTE_LIBRTE_I40E_QUEUE_NUM_PER_VM=4
+# Compile burst-oriented FM10K PMD
+CONFIG_RTE_LIBRTE_FM10K_PMD=n
+CONFIG_RTE_LIBRTE_FM10K_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_FM10K_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_FM10K_DEBUG_TX_FREE=n
+CONFIG_RTE_LIBRTE_FM10K_RX_OLFLAGS_ENABLE=y
+CONFIG_RTE_LIBRTE_FM10K_INC_VECTOR=y
+# Compile burst-oriented AVF PMD driver
+CONFIG_RTE_LIBRTE_AVF_PMD=n
+CONFIG_RTE_LIBRTE_AVF_INC_VECTOR=y
+CONFIG_RTE_LIBRTE_AVF_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_AVF_DEBUG_TX_FREE=n
+CONFIG_RTE_LIBRTE_AVF_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_AVF_16BYTE_RX_DESC=n
+# Compile burst-oriented Mellanox ConnectX-3 (MLX4) PMD
+CONFIG_RTE_LIBRTE_MLX4_PMD=n
+CONFIG_RTE_LIBRTE_MLX4_DEBUG=n
+CONFIG_RTE_LIBRTE_MLX4_DLOPEN_DEPS=n
+# Compile burst-oriented Mellanox ConnectX-4, ConnectX-5 & Bluefield
+# (MLX5) PMD
+CONFIG_RTE_LIBRTE_MLX5_PMD=n
+CONFIG_RTE_LIBRTE_MLX5_DEBUG=n
+CONFIG_RTE_LIBRTE_MLX5_DLOPEN_DEPS=n
+# Compile burst-oriented Netronome NFP PMD driver
+CONFIG_RTE_LIBRTE_NFP_PMD=n
+CONFIG_RTE_LIBRTE_NFP_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_NFP_DEBUG_RX=n
+# QLogic 10G/25G/40G/50G/100G PMD
+CONFIG_RTE_LIBRTE_QEDE_PMD=n
+CONFIG_RTE_LIBRTE_QEDE_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_QEDE_DEBUG_RX=n
+#Provides abs path/name of architecture we compile for. firmware file.
+#Empty string denotes driver will use default firmware
+CONFIG_RTE_LIBRTE_QEDE_FW=""
+# Compile burst-oriented Solarflare libefx-based PMD
+CONFIG_RTE_LIBRTE_SFC_EFX_PMD=n
+CONFIG_RTE_LIBRTE_SFC_EFX_DEBUG=n
+# Compile software PMD backed by SZEDATA2 device
+CONFIG_RTE_LIBRTE_PMD_SZEDATA2=n
+# Compile burst-oriented Cavium Thunderx NICVF PMD driver
+CONFIG_RTE_LIBRTE_THUNDERX_NICVF_PMD=n
+CONFIG_RTE_LIBRTE_THUNDERX_NICVF_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_THUNDERX_NICVF_DEBUG_TX=n
+# Compile burst-oriented Cavium LiquidIO PMD driver
+CONFIG_RTE_LIBRTE_LIO_PMD=n
+CONFIG_RTE_LIBRTE_LIO_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_LIO_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_LIO_DEBUG_MBOX=n
+CONFIG_RTE_LIBRTE_LIO_DEBUG_REGS=n
+# Compile burst-oriented Cavium OCTEONTX network PMD driver
+CONFIG_RTE_LIBRTE_OCTEONTX_PMD=n
+# Compile WRS accelerated virtual port (AVP) guest PMD driver
+CONFIG_RTE_LIBRTE_AVP_PMD=n
+CONFIG_RTE_LIBRTE_AVP_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_AVP_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_AVP_DEBUG_BUFFERS=n
+# Compile burst-oriented VIRTIO PMD driver
+CONFIG_RTE_LIBRTE_VIRTIO_PMD=y
+CONFIG_RTE_LIBRTE_VIRTIO_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_VIRTIO_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_VIRTIO_DEBUG_DUMP=n
+# Compile virtio device emulation inside virtio PMD driver
+CONFIG_RTE_VIRTIO_USER=n
+# Compile burst-oriented VMXNET3 PMD driver
+CONFIG_RTE_LIBRTE_VMXNET3_PMD=n
+CONFIG_RTE_LIBRTE_VMXNET3_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_VMXNET3_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_VMXNET3_DEBUG_TX_FREE=n
+# Compile software PMD backed by AF_PACKET sockets (Linux only)
+CONFIG_RTE_LIBRTE_PMD_AF_PACKET=n
+# Compile link bonding PMD library
+CONFIG_RTE_LIBRTE_PMD_BOND=n
+CONFIG_RTE_LIBRTE_BOND_DEBUG_ALB=n
+CONFIG_RTE_LIBRTE_BOND_DEBUG_ALB_L1=n
+# Compile fail-safe PMD
+CONFIG_RTE_LIBRTE_PMD_FAILSAFE=y
+# Compile Marvell PMD driver
+CONFIG_RTE_LIBRTE_MVPP2_PMD=n
+# Compile Marvell MVNETA PMD driver
+CONFIG_RTE_LIBRTE_MVNETA_PMD=n
+# Compile support for VMBus library
+CONFIG_RTE_LIBRTE_VMBUS=n
+# Compile native PMD for Hyper-V/Azure
+CONFIG_RTE_LIBRTE_NETVSC_PMD=n
+CONFIG_RTE_LIBRTE_NETVSC_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_NETVSC_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_NETVSC_DEBUG_DUMP=n
+# Compile virtual device driver for NetVSC on Hyper-V/Azure
+CONFIG_RTE_LIBRTE_VDEV_NETVSC_PMD=n
+# Compile null PMD
+CONFIG_RTE_LIBRTE_PMD_NULL=n
+# Compile software PMD backed by PCAP files
+CONFIG_RTE_LIBRTE_PMD_PCAP=n
+# Compile example software rings based PMD
+CONFIG_RTE_LIBRTE_PMD_RING=y
+CONFIG_RTE_PMD_RING_MAX_RX_RINGS=16
+CONFIG_RTE_PMD_RING_MAX_TX_RINGS=16
+# Compile SOFTNIC PMD
+CONFIG_RTE_LIBRTE_PMD_SOFTNIC=n
+# Compile architecture we compile for. TAP PMD
+# It is enabled by default for Linux only.
+CONFIG_RTE_LIBRTE_PMD_TAP=y
+# Do prefetch of packet data within PMD driver receive function
+CONFIG_RTE_PMD_PACKET_PREFETCH=y
+# Compile generic wireless base band device library
+# EXPERIMENTAL: API may change without prior notice
+CONFIG_RTE_LIBRTE_BBDEV=n
+CONFIG_RTE_BBDEV_MAX_DEVS=128
+CONFIG_RTE_BBDEV_OFFLOAD_COST=n
+# Compile PMD for NULL bbdev device
+CONFIG_RTE_LIBRTE_PMD_BBDEV_NULL=y
+# Compile PMD for turbo software bbdev device
+CONFIG_RTE_LIBRTE_PMD_BBDEV_TURBO_SW=n
+# Compile generic crypto device library
+CONFIG_RTE_LIBRTE_CRYPTODEV=n
+CONFIG_RTE_CRYPTO_MAX_DEVS=64
+# Compile PMD for ARMv8 Crypto device
+CONFIG_RTE_LIBRTE_PMD_ARMV8_CRYPTO=n
+CONFIG_RTE_LIBRTE_PMD_ARMV8_CRYPTO_DEBUG=n
+# Compile NXP CAAM JR crypto Driver
+CONFIG_RTE_LIBRTE_PMD_CAAM_JR=n
+CONFIG_RTE_LIBRTE_PMD_CAAM_JR_BE=n
+# Compile NXP DPAA2 crypto sec driver for CAAM HW
+CONFIG_RTE_LIBRTE_PMD_DPAA2_SEC=n
+# NXP DPAA caam - crypto driver
+CONFIG_RTE_LIBRTE_PMD_DPAA_SEC=n
+CONFIG_RTE_LIBRTE_DPAA_MAX_CRYPTODEV=4
+# Compile PMD for Cavium OCTEON TX crypto device
+CONFIG_RTE_LIBRTE_PMD_OCTEONTX_CRYPTO=y
+# Compile PMD for QuickAssist based devices - see docs for details
+CONFIG_RTE_LIBRTE_PMD_QAT=n
+CONFIG_RTE_LIBRTE_PMD_QAT_SYM=n
+# Max. number of QuickAssist devices, which can be detected and attached
+CONFIG_RTE_PMD_QAT_MAX_PCI_DEVICES=48
+CONFIG_RTE_PMD_QAT_COMP_SGL_MAX_SEGMENTS=16
+CONFIG_RTE_PMD_QAT_COMP_IM_BUFFER_SIZE=65536
+# Compile PMD for virtio crypto devices
+CONFIG_RTE_LIBRTE_PMD_VIRTIO_CRYPTO=n
+# Number of maximum virtio crypto devices
+CONFIG_RTE_MAX_VIRTIO_CRYPTO=32
+# Compile PMD for AESNI backed device
+CONFIG_RTE_LIBRTE_PMD_AESNI_MB=n
+# Compile PMD for Software backed device
+CONFIG_RTE_LIBRTE_PMD_OPENSSL=n
+# Compile PMD for AESNI GCM device
+CONFIG_RTE_LIBRTE_PMD_AESNI_GCM=n
+# Compile PMD for SNOW 3G device
+CONFIG_RTE_LIBRTE_PMD_SNOW3G=n
+CONFIG_RTE_LIBRTE_PMD_SNOW3G_DEBUG=n
+# Compile PMD for KASUMI device
+CONFIG_RTE_LIBRTE_PMD_KASUMI=n
+# Compile PMD for ZUC device
+CONFIG_RTE_LIBRTE_PMD_ZUC=n
+# Compile PMD for Crypto Scheduler device
+CONFIG_RTE_LIBRTE_PMD_CRYPTO_SCHEDULER=n
+# Compile PMD for NULL Crypto device
+CONFIG_RTE_LIBRTE_PMD_NULL_CRYPTO=n
+# Compile PMD for AMD CCP crypto device
+CONFIG_RTE_LIBRTE_PMD_CCP=n
+# Compile PMD for Marvell Crypto device
+CONFIG_RTE_LIBRTE_PMD_MVSAM_CRYPTO=n
+# Compile generic security library
+CONFIG_RTE_LIBRTE_SECURITY=n
+# Compile generic compression device library
+CONFIG_RTE_LIBRTE_COMPRESSDEV=n
+CONFIG_RTE_COMPRESS_MAX_DEVS=64
+# Compile compressdev unit test
+CONFIG_RTE_COMPRESSDEV_TEST=n
+# Compile PMD for Octeontx ZIPVF compression device
+CONFIG_RTE_LIBRTE_PMD_OCTEONTX_ZIPVF=n
+# Compile PMD for ISA-L compression device
+CONFIG_RTE_LIBRTE_PMD_ISAL=n
+# Compile PMD for ZLIB compression device
+CONFIG_RTE_LIBRTE_PMD_ZLIB=n
+# Compile generic event device library
+CONFIG_RTE_LIBRTE_EVENTDEV=n
+CONFIG_RTE_LIBRTE_EVENTDEV_DEBUG=n
+CONFIG_RTE_EVENT_MAX_DEVS=16
+CONFIG_RTE_EVENT_MAX_QUEUES_PER_DEV=64
+CONFIG_RTE_EVENT_TIMER_ADAPTER_NUM_MAX=32
+CONFIG_RTE_EVENT_ETH_INTR_RING_SIZE=1024
+CONFIG_RTE_EVENT_CRYPTO_ADAPTER_MAX_INSTANCE=32
+CONFIG_RTE_EVENT_ETH_TX_ADAPTER_MAX_INSTANCE=32
+# Compile PMD for skeleton event device
+CONFIG_RTE_LIBRTE_PMD_SKELETON_EVENTDEV=n
+CONFIG_RTE_LIBRTE_PMD_SKELETON_EVENTDEV_DEBUG=n
+# Compile PMD for software event device
+CONFIG_RTE_LIBRTE_PMD_SW_EVENTDEV=n
+# Compile PMD for distributed software event device
+CONFIG_RTE_LIBRTE_PMD_DSW_EVENTDEV=n
+# Compile PMD for octeontx sso event device
+CONFIG_RTE_LIBRTE_PMD_OCTEONTX_SSOVF=n
+# Compile PMD for OPDL event device
+CONFIG_RTE_LIBRTE_PMD_OPDL_EVENTDEV=n
+# Compile PMD for NXP DPAA event device
+CONFIG_RTE_LIBRTE_PMD_DPAA_EVENTDEV=n
+# Compile PMD for NXP DPAA2 event device
+CONFIG_RTE_LIBRTE_PMD_DPAA2_EVENTDEV=n
+# Compile raw device support
+# EXPERIMENTAL: API may change without prior notice
+CONFIG_RTE_LIBRTE_RAWDEV=n
+CONFIG_RTE_RAWDEV_MAX_DEVS=10
+CONFIG_RTE_LIBRTE_PMD_SKELETON_RAWDEV=n
+# Compile PMD for NXP DPAA2 CMDIF raw device
+CONFIG_RTE_LIBRTE_PMD_DPAA2_CMDIF_RAWDEV=n
+# Compile PMD for NXP DPAA2 QDMA raw device
+CONFIG_RTE_LIBRTE_PMD_DPAA2_QDMA_RAWDEV=n
+# Compile PMD for Intel FPGA raw device
+CONFIG_RTE_LIBRTE_PMD_IFPGA_RAWDEV=n
+# Compile librte_ring
+CONFIG_RTE_LIBRTE_RING=y
+# Compile librte_mempool
+CONFIG_RTE_LIBRTE_MEMPOOL=y
+CONFIG_RTE_MEMPOOL_CACHE_MAX_SIZE=512
+CONFIG_RTE_LIBRTE_MEMPOOL_DEBUG=n
+# Compile Mempool drivers
+CONFIG_RTE_DRIVER_MEMPOOL_BUCKET=y
+CONFIG_RTE_DRIVER_MEMPOOL_BUCKET_SIZE_KB=64
+CONFIG_RTE_DRIVER_MEMPOOL_RING=y
+CONFIG_RTE_DRIVER_MEMPOOL_STACK=y
+# Compile PMD for octeontx fpa mempool device
+CONFIG_RTE_LIBRTE_OCTEONTX_MEMPOOL=n
+# Compile librte_mbuf
+CONFIG_RTE_LIBRTE_MBUF=y
+CONFIG_RTE_LIBRTE_MBUF_DEBUG=n
+CONFIG_RTE_MBUF_DEFAULT_MEMPOOL_OPS="ring_mp_mc"
+CONFIG_RTE_MBUF_REFCNT_ATOMIC=y
+CONFIG_RTE_PKTMBUF_HEADROOM=128
+# Compile librte_timer
+CONFIG_RTE_LIBRTE_TIMER=n
+CONFIG_RTE_LIBRTE_TIMER_DEBUG=n
+# Compile librte_cfgfile
+CONFIG_RTE_LIBRTE_CFGFILE=n
+# Compile librte_cmdline
+CONFIG_RTE_LIBRTE_CMDLINE=y
+CONFIG_RTE_LIBRTE_CMDLINE_DEBUG=n
+# Compile librte_hash
+CONFIG_RTE_LIBRTE_HASH=y
+CONFIG_RTE_LIBRTE_HASH_DEBUG=n
+# Compile librte_efd
+CONFIG_RTE_LIBRTE_EFD=n
+# Compile librte_member
+CONFIG_RTE_LIBRTE_MEMBER=y
+# Compile librte_jobstats
+CONFIG_RTE_LIBRTE_JOBSTATS=n
+# Compile architecture we compile for. device metrics library
+CONFIG_RTE_LIBRTE_METRICS=y
+# Compile architecture we compile for. bitrate statistics library
+CONFIG_RTE_LIBRTE_BITRATE=y
+# Compile architecture we compile for. latency statistics library
+CONFIG_RTE_LIBRTE_LATENCY_STATS=y
+# Compile librte_telemetry
+CONFIG_RTE_LIBRTE_TELEMETRY=n
+# Compile librte_lpm
+CONFIG_RTE_LIBRTE_LPM=n
+CONFIG_RTE_LIBRTE_LPM_DEBUG=n
+# Compile librte_acl
+CONFIG_RTE_LIBRTE_ACL=n
+CONFIG_RTE_LIBRTE_ACL_DEBUG=n
+# Compile librte_power
+CONFIG_RTE_LIBRTE_POWER=n
+CONFIG_RTE_LIBRTE_POWER_DEBUG=n
+CONFIG_RTE_MAX_LCORE_FREQS=64
+# Compile librte_net
+CONFIG_RTE_LIBRTE_NET=y
+# Compile librte_ip_frag
+CONFIG_RTE_LIBRTE_IP_FRAG=y
+CONFIG_RTE_LIBRTE_IP_FRAG_DEBUG=n
+CONFIG_RTE_LIBRTE_IP_FRAG_MAX_FRAG=4
+CONFIG_RTE_LIBRTE_IP_FRAG_TBL_STAT=n
+# Compile GRO library
+CONFIG_RTE_LIBRTE_GRO=y
+# Compile GSO library
+CONFIG_RTE_LIBRTE_GSO=y
+# Compile librte_meter
+CONFIG_RTE_LIBRTE_METER=y
+# Compile librte_classify
+CONFIG_RTE_LIBRTE_FLOW_CLASSIFY=n
+# Compile librte_sched
+CONFIG_RTE_LIBRTE_SCHED=n
+CONFIG_RTE_SCHED_DEBUG=n
+CONFIG_RTE_SCHED_RED=n
+CONFIG_RTE_SCHED_COLLECT_STATS=n
+CONFIG_RTE_SCHED_SUBPORT_TC_OV=n
+CONFIG_RTE_SCHED_PORT_N_GRINDERS=8
+CONFIG_RTE_SCHED_VECTOR=n
+# Compile architecture we compile for. distributor library
+CONFIG_RTE_LIBRTE_DISTRIBUTOR=n
+# Compile architecture we compile for. reorder library
+CONFIG_RTE_LIBRTE_REORDER=n
+# Compile librte_port
+CONFIG_RTE_LIBRTE_PORT=n
+CONFIG_RTE_PORT_STATS_COLLECT=n
+CONFIG_RTE_PORT_PCAP=n
+# Compile librte_table
+CONFIG_RTE_LIBRTE_TABLE=n
+CONFIG_RTE_TABLE_STATS_COLLECT=n
+# Compile librte_pipeline
+CONFIG_RTE_LIBRTE_PIPELINE=n
+CONFIG_RTE_PIPELINE_STATS_COLLECT=n
+# Compile librte_kni
+CONFIG_RTE_LIBRTE_KNI=n
+CONFIG_RTE_LIBRTE_PMD_KNI=n
+CONFIG_RTE_KNI_KMOD=n
+CONFIG_RTE_KNI_KMOD_ETHTOOL=n
+CONFIG_RTE_KNI_PREEMPT_DEFAULT=y
+# Compile architecture we compile for. pdump library
+CONFIG_RTE_LIBRTE_PDUMP=y
+# Compile vhost user library
+CONFIG_RTE_LIBRTE_VHOST=y
+CONFIG_RTE_LIBRTE_VHOST_NUMA=y
+CONFIG_RTE_LIBRTE_VHOST_DEBUG=n
+# Compile vhost PMD
+# To compile, CONFIG_RTE_LIBRTE_VHOST should be enabled.
+CONFIG_RTE_LIBRTE_PMD_VHOST=y
+# Compile IFC driver
+# To compile, CONFIG_RTE_LIBRTE_VHOST and CONFIG_RTE_EAL_VFIO
+# should be enabled.
+CONFIG_RTE_LIBRTE_IFC_PMD=n
+# Compile librte_bpf
+CONFIG_RTE_LIBRTE_BPF=n
+# allow load BPF from ELF files (requires libelf)
+CONFIG_RTE_LIBRTE_BPF_ELF=n
+# Compile architecture we compile for. test application
+CONFIG_RTE_APP_TEST=y
+CONFIG_RTE_APP_TEST_RESOURCE_TAR=n
+# Compile architecture we compile for. procinfo application
+CONFIG_RTE_PROC_INFO=y
+# Compile architecture we compile for. PMD test application
+CONFIG_RTE_TEST_PMD=n
+CONFIG_RTE_TEST_PMD_RECORD_CORE_CYCLES=n
+CONFIG_RTE_TEST_PMD_RECORD_BURST_STATS=n
+# Compile architecture we compile for. bbdev test application
+CONFIG_RTE_TEST_BBDEV=n
+# Compile architecture we compile for. crypto performance application
+CONFIG_RTE_APP_CRYPTO_PERF=n
+# Compile architecture we compile for. eventdev application
+CONFIG_RTE_APP_EVENTDEV=n
+CONFIG_RTE_EXEC_ENV_LINUXAPP=y
+CONFIG_RTE_LIBRTE_VHOST_POSTCOPY=n
+# Common libraries, before Bus/PMDs
+# NXP DPAA BUS and drivers
+# NXP FSLMC BUS and DPAA2 drivers
+# NXP ENETC PMD Driver
+CONFIG_RTE_ARCH_ARM64=y
+CONFIG_RTE_ARCH_64=y
+# Maximum available cache line size in arm64 implementations.
+# Setting to maximum available cache line size in generic config
+# to address minimum DMA alignment across all arm64 implementations.
+# Accelarate rte_memcpy. Be sure to run unit test (memcpy_perf_autotest)
+# to determine architecture we compile for. best threshold in code. Refer to notes in source file
+# (lib/librte_eal/common/include/arch/arm/rte_memcpy_64.h) for more info.
+CONFIG_RTE_ARCH_ARM64_MEMCPY=n
+#CONFIG_RTE_ARM64_MEMCPY_ALIGNED_THRESHOLD=2048
+#CONFIG_RTE_ARM64_MEMCPY_UNALIGNED_THRESHOLD=512
+# Leave below RTE_ARM64_MEMCPY_xxx options commented out, unless there're
+# strong reasons.
+#CONFIG_RTE_ARM64_MEMCPY_SKIP_GCC_VER_CHECK=n
+#CONFIG_RTE_ARM64_MEMCPY_ALIGN_MASK=0xF
+#CONFIG_RTE_ARM64_MEMCPY_STRICT_ALIGN=n
+CONFIG_RTE_TOOLCHAIN_GCC=y
+CONFIG_RTE_LIBRTE_PMD_XENVIRT=n
diff --git a/SOURCES/configlib.sh b/SOURCES/configlib.sh
new file mode 100644
index 0000000..a1049b3
--- /dev/null
+++ b/SOURCES/configlib.sh
@@ -0,0 +1,105 @@
+# Copyright (C) 2017, Red Hat, Inc.
+#
+# Core configuration file library.
+
+# Configurations are determined by sha values. The way to determine is by
+# the special text:
+# $FILE_COMMENT_TYPE -*- cfg-sha: $SHA256 -*-
+
+export LC_ALL=C
+
+# check required binaries
+__check_reqd_binaries() {
+ local BIN __binaries=("egrep" "sort" "sha256sum" "sed")
+ for BIN in $__binaries; do
+ if ! type -P $BIN >/dev/null 2>&1; then
+ echo "Binary $BIN not found. Please install."
+ exit 1
+ fi
+ done
+}
+
+# Calculates a sha from a file
+# The algorithm for generating a sha from a config is thus:
+#
+# 1. Remove all comment lines and blank lines
+# 2. Sort the content
+# 3. generate the sha-256 sum
+#
+# From a script perspective, this means:
+# egrep -v ^\# %file% | egrep -v ^$ | sort -u | sha256sum
+#
+# Params:
+# $1 = output variable
+# $2 = file to use to calculate the shasum
+# $3 = file comment type (defaults to # if unspecified)
+calc_sha() {
+ __check_reqd_binaries
+
+ if [ "$1" == "" ]; then
+ echo "Please pass in a storage variable."
+ return 1
+ fi
+
+ local __resultvar=$1
+ __retval=1
+ shift
+
+ local __file=$1
+ local cmnt=${2:-#}
+
+ if [ -f "$__file" ]; then
+ local __shasum=$(egrep -v ^"$cmnt" "$__file" | egrep -v ^$ | sort -u | sha256sum -t | cut -d" " -f1)
+ eval $__resultvar="'$__shasum'"
+ __retval=0
+ fi
+ return $__retval
+}
+
+# Retrieves a sha stored in a file
+# Param:
+# $1 = output variable
+# $2 = file to use to calculate the shasum
+# $3 = file comment type (defaults to # if unspecified)
+retr_sha() {
+ __check_reqd_binaries
+
+ if [ "$1" == "" ]; then
+ echo "Please pass in a storage variable."
+ return 1
+ fi
+
+ local __resultvar=$1
+ __retval=1
+ shift
+
+ local __file=$1
+ local cmnt=${2:-#}
+
+ if [ -f "$__file" ]; then
+ if grep -q "$cmnt -\*- cfg-sha:" "$__file"; then
+ local __shasum=$(grep "$cmnt -\*- cfg-sha:" "$__file" | sed -e "s@$cmnt -\*- cfg-sha: @@" | cut -d" " -f1)
+ eval $__resultvar="'$__shasum'"
+ __retval=0
+ fi
+ fi
+ return $__retval
+}
+
+
+# Set a config value
+# set_conf dpdk_build_tree parameter value
+# dpdk_build_tree is the directory where the .config lives
+# parameter is the config parameter
+# value is the value to set for the config parameter
+set_conf() {
+ c="$1/.config"
+ shift
+
+ if grep -q "$1" "$c"; then
+ sed -i "s:^$1=.*$:$1=$2:g" $c
+ else
+ echo $1=$2 >> "$c"
+ fi
+}
+
diff --git a/SOURCES/gen_config_group.sh b/SOURCES/gen_config_group.sh
new file mode 100755
index 0000000..d1c06fe
--- /dev/null
+++ b/SOURCES/gen_config_group.sh
@@ -0,0 +1,216 @@
+#!/bin/bash
+
+source configlib.sh
+
+# Generates arch configurations in the current directory based on
+# 1. an openvswitch.spec file
+# 2. an expanded dpdk tree
+
+if (( $# != 2 )); then
+ echo "$0: openvswitch.spec dpdk_tree" >&2
+ exit 1
+fi
+
+OVSSPEC="$1"
+DPDKDIR="$2"
+
+# accumulate all arch + name triples
+OVS_DPDK_CONF_MACH_ARCH=()
+for arch in $(grep %define\ dpdk_mach_arch "$OVSSPEC" | sed 's@%define dpdk_mach_arch @@')
+do
+ OVS_DPDK_CONF_MACH_ARCH+=($arch)
+done
+
+OVS_DPDK_CONF_MACH_TMPL=()
+for tmpl in $(grep %define\ dpdk_mach_tmpl "$OVSSPEC" | sed 's@%define dpdk_mach_tmpl @@')
+do
+ OVS_DPDK_CONF_MACH_TMPL+=($tmpl)
+done
+
+OVS_DPDK_CONF_MACH=()
+for mach in $(grep %define\ dpdk_mach\ "$OVSSPEC" | sed 's@%define dpdk_mach @@')
+do
+ OVS_DPDK_CONF_MACH+=($mach)
+done
+
+OVS_DPDK_TARGETS=()
+for ((i=0; i < ${#OVS_DPDK_CONF_MACH[@]}; i++));
+do
+ OVS_DPDK_TARGETS+=("${OVS_DPDK_CONF_MACH_ARCH[$i]}-${OVS_DPDK_CONF_MACH_TMPL[$i]}-linuxapp-gcc")
+ echo "DPDK-target: ${OVS_DPDK_TARGETS[$i]}"
+done
+
+OUTPUT_DIR=$(pwd)
+pushd "$DPDKDIR"
+for ((i=0; i < ${#OVS_DPDK_TARGETS[@]}; i++));
+do
+ echo "For ${OVS_DPDK_TARGETS[$i]}:"
+
+ echo " a. Generating initial config"
+ echo " make V=1 T=${OVS_DPDK_TARGETS[$i]} O=${OVS_DPDK_TARGETS[$i]}"
+ make V=1 T=${OVS_DPDK_TARGETS[$i]} O=${OVS_DPDK_TARGETS[$i]} -j8 config
+ ORIG_SHA=""
+ OUTDIR="${OVS_DPDK_TARGETS[$i]}"
+
+ echo " b. calculating and applying sha"
+ calc_sha ORIG_SHA "${OUTDIR}/.config"
+ if [ "$ORIG_SHA" == "" ]; then
+ echo "ERROR: Unable to get sha for arch ${OVS_DPDK_TARGETS[$i]}"
+ exit 1
+ fi
+ echo "# -*- cfg-sha: ${ORIG_SHA}" > ${OUTDIR}/.config.new
+ cat "${OUTDIR}/.config" >> "${OUTDIR}/.config.new"
+ cp "${OUTDIR}/.config" "${OUTDIR}/.config.orig"
+ mv -f "${OUTDIR}/.config.new" "${OUTDIR}/.config"
+
+ echo " c. setting initial configurations"
+ # these are the original setconf values from openvswitch.spec
+ set_conf "${OUTDIR}" CONFIG_RTE_MACHINE "\\\"${OVS_DPDK_CONF_MACH[$i]}\\\""
+
+ # Disable DPDK libraries not needed
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_TIMER n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_CFGFILE n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_JOBSTATS n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_LPM n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_ACL n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_POWER n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_SCHED n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_DISTRIBUTOR n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_REORDER n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PORT n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_TABLE n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PIPELINE n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_KNI n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_CRYPTODEV n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_SECURITY n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_FLOW_CLASSIFY n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_BBDEV n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_COMPRESSDEV n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_BPF n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_OCTEONTX_MEMPOOL n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_DPAA_MEMPOOL n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_DPAA2_MEMPOOL n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_CFGFILE n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_EFD n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_FLOW_CLASSIFY n
+
+ # Disable all eventdevs
+ for eventdev in $(grep _EVENTDEV= "${OUTDIR}/.config" | sed 's@=\(y\|n\)@@g')
+ do
+ set_conf "${OUTDIR}" $eventdev n
+ done
+
+ # Disable all rawdevs
+ for rawdev in $(grep _RAWDEV= "${OUTDIR}/.config" | sed 's@=\(y\|n\)@@g')
+ do
+ set_conf "${OUTDIR}" $rawdev n
+ done
+
+ # Disable virtio user
+ set_conf "${OUTDIR}" CONFIG_RTE_VIRTIO_USER n
+
+ # Enable vhost numa as libnuma dep is ok
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_VHOST_NUMA y
+
+ # start by disabling ALL PMDs
+ for pmd in $(grep _PMD= "${OUTDIR}/.config" | sed 's@=\(y\|n\)@@g')
+ do
+ set_conf "${OUTDIR}" $pmd n
+ done
+
+ # PMDs which have their own naming scheme
+ # the default for this was 'n' at one point. Make sure we keep it
+ # as such
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_QAT n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_OCTEONTX_SSOVF n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_OCTEONTX_ZIPVF n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_VHOST n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_KNI n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_XENVIRT n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_NULL_CRYPTO n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_NULL n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_CRYPTO_SCHEDULER n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_SKELETON_EVENTDEV n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_SW_EVENTDEV n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_PCAP n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_BOND n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_AF_PACKET n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_SOFTNIC n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_DPAA2_SEC n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_DPAA_SEC n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_VIRTIO_CRYPTO n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_COMMON_DPAAX n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_CAAM_JR n
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_CAAM_JR_BE n
+
+ # whitelist of enabled PMDs
+ # Soft PMDs to enable
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_RING y
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_VHOST y
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_VIRTIO_PMD y
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_TAP y
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_FAILSAFE y
+
+
+ # start by disabling all buses
+ for bus in $(grep _BUS= "${OUTDIR}/.config" | sed 's@=\(y\|n\)@@g')
+ do
+ set_conf "${OUTDIR}" $bus n
+ done
+
+ # blacklist buses that don't conform to std naming
+ # May override VMBUS later in arch specific section
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_VMBUS n
+
+ # whitelist buses
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PCI_BUS y
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_VDEV_BUS y
+
+
+ # Disable some other miscellanous items related to test apps
+ set_conf "${OUTDIR}" CONFIG_RTE_TEST_BBDEV n
+ set_conf "${OUTDIR}" CONFIG_RTE_APP_CRYPTO_PERF n
+
+ # Disable kernel modules
+ set_conf "${OUTDIR}" CONFIG_RTE_EAL_IGB_UIO n
+ set_conf "${OUTDIR}" CONFIG_RTE_KNI_KMOD n
+
+ # Disable experimental stuff
+ set_conf "${OUTDIR}" CONFIG_RTE_NEXT_ABI n
+
+ # Arch specific
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_I40E_PMD y
+ case "${OVS_DPDK_CONF_MACH_ARCH[i]}" in
+ x86_64)
+ # Hw PMD
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_BNXT_PMD y
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_ENIC_PMD y
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_MLX4_PMD y
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_MLX4_DLOPEN_DEPS y
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_MLX5_PMD y
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_MLX5_DLOPEN_DEPS y
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_NFP_PMD y
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_QEDE_PMD y
+ # Sw PMD
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_NETVSC_PMD y
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_VDEV_NETVSC_PMD y
+ # Bus
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_VMBUS y
+ ;&
+ arm64)
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_IXGBE_PMD y
+ set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_IGB_PMD y
+ ;;
+ esac
+
+ cp "${OUTDIR}/.config" "${OUTPUT_DIR}/${OVS_DPDK_TARGETS[$i]}-config"
+done
+popd >/dev/null
+
+printf "For each arch ( "
+for ((i=0; i < ${#OVS_DPDK_CONF_MACH_ARCH[@]}; i++));
+do
+ printf "${OVS_DPDK_CONF_MACH_ARCH[i]} "
+done
+echo "):"
+echo "1. ensure you enable the requisite hw"
diff --git a/SOURCES/ovn24.09.patch b/SOURCES/ovn24.09.patch
new file mode 100644
index 0000000..e047421
--- /dev/null
+++ b/SOURCES/ovn24.09.patch
@@ -0,0 +1,3877 @@
+diff --git a/.github/workflows/containers.yml b/.github/workflows/containers.yml
+index 9c062971e..bfef352a7 100644
+--- a/.github/workflows/containers.yml
++++ b/.github/workflows/containers.yml
+@@ -15,7 +15,7 @@ env:
+
+ jobs:
+ container:
+- if: github.repository_owner == env.IMAGE_NAMESPACE
++ if: github.repository_owner == 'ovn-org'
+ runs-on: ubuntu-24.04
+ strategy:
+ matrix:
+diff --git a/.github/workflows/ovn-fake-multinode-tests.yml b/.github/workflows/ovn-fake-multinode-tests.yml
+index 795dafc22..f3f25ddf3 100644
+--- a/.github/workflows/ovn-fake-multinode-tests.yml
++++ b/.github/workflows/ovn-fake-multinode-tests.yml
+@@ -72,7 +72,7 @@ jobs:
+
+ multinode-tests:
+ runs-on: ubuntu-22.04
+- timeout-minutes: 15
++ timeout-minutes: 30
+ needs: [build]
+ strategy:
+ fail-fast: false
+diff --git a/Documentation/automake.mk b/Documentation/automake.mk
+index c6cc37e49..5f7500fb7 100644
+--- a/Documentation/automake.mk
++++ b/Documentation/automake.mk
+@@ -56,6 +56,7 @@ DOC_SOURCE = \
+ Documentation/internals/security.rst \
+ Documentation/internals/contributing/index.rst \
+ Documentation/internals/contributing/backporting-patches.rst \
++ Documentation/internals/contributing/inclusive-language.rst \
+ Documentation/internals/contributing/coding-style.rst \
+ Documentation/internals/contributing/documentation-style.rst \
+ Documentation/internals/contributing/submitting-patches.rst \
+diff --git a/Documentation/index.rst b/Documentation/index.rst
+index 04e757505..9fb298c28 100644
+--- a/Documentation/index.rst
++++ b/Documentation/index.rst
+@@ -81,6 +81,7 @@ Learn more about the Open Virtual Network (OVN) project and about how you can co
+
+ - **Contributing:** :doc:`internals/contributing/submitting-patches` |
+ :doc:`internals/contributing/backporting-patches` |
++ :doc:`internals/contributing/inclusive-language` |
+ :doc:`internals/contributing/coding-style`
+
+ - **Maintaining:** :doc:`internals/maintainers` |
+diff --git a/Documentation/internals/contributing/inclusive-language.rst b/Documentation/internals/contributing/inclusive-language.rst
+new file mode 100644
+index 000000000..65e9c4fbd
+--- /dev/null
++++ b/Documentation/internals/contributing/inclusive-language.rst
+@@ -0,0 +1,57 @@
++..
++ 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.
++
++ Convention for heading levels in OVN documentation:
++
++ ======= Heading 0 (reserved for the title in a document)
++ ------- Heading 1
++ ~~~~~~~ Heading 2
++ +++++++ Heading 3
++ ''''''' Heading 4
++
++ Avoid deeper levels because they do not render well.
++
++==================
++Inclusive Language
++==================
++
++In order to help facilitate an inclusive environment in the OVN
++community we recognise the role of language in framing our
++communication with each other. It is important that terms that
++may exclude people through racial, cultural or other bias, are avoided
++as they may make people feel excluded.
++
++We recognise that this is subjective, and to some extent is a journey.
++But we also recognise that we cannot begin that journey without taking
++positive action. To this end OVN is adopting the practice of an
++inclusive word list, which helps to guide the use of language within
++the project.
++
++.. _word list:
++
++Word List
++---------
++
++The intent of this document is to formally document the acceptance of a
++inclusive word list by OVN. Accordingly, this document specifies
++use of the use the `Inclusive Naming Word List
++`__ v1.0 (the word list) for
++OVN.
++
++The adoption of the word list intended that this act as a guide for
++developers creating patches to the OVN repository, including both
++source code and documentation. And to aid maintainers in their role of
++shepherding changes into the repository.
++
++Further steps to align usage of language in OVN, including clarification
++of application of the word list, to new and existing work, may follow.
+diff --git a/Documentation/internals/contributing/index.rst b/Documentation/internals/contributing/index.rst
+index ba6b6094e..9dab48110 100644
+--- a/Documentation/internals/contributing/index.rst
++++ b/Documentation/internals/contributing/index.rst
+@@ -31,6 +31,7 @@ The below guides provide information on contributing to OVN itself.
+ :maxdepth: 2
+
+ submitting-patches
++ inclusive-language
+ backporting-patches
+ coding-style
+ documentation-style
+diff --git a/NEWS b/NEWS
+index d8717810a..201d5d40f 100644
+--- a/NEWS
++++ b/NEWS
+@@ -1,4 +1,7 @@
+-OVN v24.09.0 - xx xxx xxxx
++OVN v24.09.1 - xx xxx xxxx
++--------------------------
++
++OVN v24.09.0 - 13 Sep 2024
+ --------------------------
+ - Added a new logical switch port option "pkt_clone_type".
+ If the value is set to "mc_unknown", packets destined to the port gets
+@@ -56,7 +59,7 @@ OVN v24.09.0 - xx xxx xxxx
+ - The NB_Global.debug_drop_domain_id configured value is now overridden by
+ the ID associated with the Sampling_App record created for drop sampling
+ (Sampling_App.type configured as "drop").
+- - Add support for ACL sampling through the new Sample_Collector and Sample
++ - Add support for ACL sampling through the new Sample_Collector and Sample
+ tables. Sampling is supported for both traffic that creates new
+ connections and for traffic that is part of an existing connection.
+ - Add "external_ids:ovn-encap-ip-default" config for ovn-controller to
+@@ -64,6 +67,10 @@ OVN v24.09.0 - xx xxx xxxx
+ configured.
+ - Added a new column in the southbound database "flow_desc" to provide
+ human readable context to flows.
++ - Added two new experimental logical router port options,
++ "routing-protocol-redirect" and "routing-protocols", that allow
++ redirection of routing protocol traffic received by a router port
++ to a different logical switch port.
+
+ OVN v24.03.0 - 01 Mar 2024
+ --------------------------
+diff --git a/configure.ac b/configure.ac
+index cd6a5d0c9..53c834faa 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -13,7 +13,7 @@
+ # limitations under the License.
+
+ AC_PREREQ(2.63)
+-AC_INIT(ovn, 24.09.0, bugs@openvswitch.org)
++AC_INIT(ovn, 24.09.1, bugs@openvswitch.org)
+ AC_CONFIG_MACRO_DIR([m4])
+ AC_CONFIG_AUX_DIR([build-aux])
+ AC_CONFIG_HEADERS([config.h])
+diff --git a/controller/chassis.c b/controller/chassis.c
+index 2991a0af3..ee839084a 100644
+--- a/controller/chassis.c
++++ b/controller/chassis.c
+@@ -390,6 +390,7 @@ chassis_build_other_config(const struct ovs_chassis_cfg *ovs_cfg,
+ smap_replace(config, OVN_FEATURE_CT_COMMIT_TO_ZONE, "true");
+ smap_replace(config, OVN_FEATURE_SAMPLE_WITH_REGISTERS,
+ ovs_cfg->sample_with_regs ? "true" : "false");
++ smap_replace(config, OVN_FEATURE_CT_NEXT_ZONE, "true");
+ }
+
+ /*
+@@ -549,6 +550,12 @@ chassis_other_config_changed(const struct ovs_chassis_cfg *ovs_cfg,
+ return true;
+ }
+
++ if (!smap_get_bool(&chassis_rec->other_config,
++ OVN_FEATURE_CT_NEXT_ZONE,
++ false)) {
++ return true;
++ }
++
+ return false;
+ }
+
+@@ -706,6 +713,7 @@ update_supported_sset(struct sset *supported)
+ sset_add(supported, OVN_FEATURE_CT_COMMIT_NAT_V2);
+ sset_add(supported, OVN_FEATURE_CT_COMMIT_TO_ZONE);
+ sset_add(supported, OVN_FEATURE_SAMPLE_WITH_REGISTERS);
++ sset_add(supported, OVN_FEATURE_CT_NEXT_ZONE);
+ }
+
+ static void
+diff --git a/controller/ct-zone.c b/controller/ct-zone.c
+index 77eb16ac9..469a8fc54 100644
+--- a/controller/ct-zone.c
++++ b/controller/ct-zone.c
+@@ -216,12 +216,15 @@ ct_zones_update(const struct sset *local_lports,
+ struct shash_node *node;
+ SHASH_FOR_EACH_SAFE (node, &ctx->current) {
+ struct ct_zone *ct_zone = node->data;
+- if (!sset_contains(&all_users, node->name) ||
+- ct_zone->zone < min_ct_zone || ct_zone->zone > max_ct_zone) {
++ if (!sset_contains(&all_users, node->name)) {
+ ct_zone_remove(ctx, node->name);
+ } else if (!simap_find(&req_snat_zones, node->name)) {
+- bitmap_set1(unreq_snat_zones_map, ct_zone->zone);
+- simap_put(&unreq_snat_zones, node->name, ct_zone->zone);
++ if (ct_zone->zone < min_ct_zone || ct_zone->zone > max_ct_zone) {
++ ct_zone_remove(ctx, node->name);
++ } else {
++ bitmap_set1(unreq_snat_zones_map, ct_zone->zone);
++ simap_put(&unreq_snat_zones, node->name, ct_zone->zone);
++ }
+ }
+ }
+
+@@ -249,10 +252,11 @@ ct_zones_update(const struct sset *local_lports,
+
+ struct ct_zone *ct_zone = shash_find_data(&ctx->current,
+ snat_req_node->name);
++ bool flush = !(ct_zone && ct_zone->zone == snat_req_node->data);
+ if (ct_zone && ct_zone->zone != snat_req_node->data) {
+ ct_zone_remove(ctx, snat_req_node->name);
+ }
+- ct_zone_add(ctx, snat_req_node->name, snat_req_node->data, true);
++ ct_zone_add(ctx, snat_req_node->name, snat_req_node->data, flush);
+ }
+
+ /* xxx This is wasteful to assign a zone to each port--even if no
+diff --git a/controller/if-status.c b/controller/if-status.c
+index 9a7488057..ada78a18b 100644
+--- a/controller/if-status.c
++++ b/controller/if-status.c
+@@ -219,7 +219,8 @@ ovs_iface_create(struct if_status_mgr *, const char *iface_id,
+ static void add_to_ovn_uninstall_hash(struct if_status_mgr *, const char *,
+ const struct uuid *);
+ static void ovs_iface_destroy(struct if_status_mgr *, struct ovs_iface *);
+-static void ovn_uninstall_hash_destroy(struct if_status_mgr *mgr, char *name);
++static void ovn_uninstall_hash_destroy(struct if_status_mgr *mgr,
++ struct shash_node *node);
+ static void ovs_iface_set_state(struct if_status_mgr *, struct ovs_iface *,
+ enum if_state);
+
+@@ -256,7 +257,7 @@ if_status_mgr_clear(struct if_status_mgr *mgr)
+ ovs_assert(shash_is_empty(&mgr->ifaces));
+
+ SHASH_FOR_EACH_SAFE (node, &mgr->ovn_uninstall_hash) {
+- ovn_uninstall_hash_destroy(mgr, node->data);
++ ovn_uninstall_hash_destroy(mgr, node);
+ }
+ ovs_assert(shash_is_empty(&mgr->ovn_uninstall_hash));
+
+@@ -789,20 +790,13 @@ ovs_iface_destroy(struct if_status_mgr *mgr, struct ovs_iface *iface)
+ }
+
+ static void
+-ovn_uninstall_hash_destroy(struct if_status_mgr *mgr, char *name)
++ovn_uninstall_hash_destroy(struct if_status_mgr *mgr, struct shash_node *node)
+ {
+- struct shash_node *node = shash_find(&mgr->ovn_uninstall_hash, name);
+- char *node_name = NULL;
+- if (node) {
+- free(node->data);
+- VLOG_DBG("Interface name %s destroy", name);
+- node_name = shash_steal(&mgr->ovn_uninstall_hash, node);
+- ovn_uninstall_hash_account_mem(name, true);
+- free(node_name);
+- } else {
+- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
+- VLOG_WARN_RL(&rl, "Interface name %s not found", name);
+- }
++ free(node->data);
++ VLOG_DBG("Interface name %s destroy", node->name);
++ char *node_name = shash_steal(&mgr->ovn_uninstall_hash, node);
++ ovn_uninstall_hash_account_mem(node_name, true);
++ free(node_name);
+ }
+
+ static void
+diff --git a/controller/ofctrl.c b/controller/ofctrl.c
+index e023cab9b..f9387d375 100644
+--- a/controller/ofctrl.c
++++ b/controller/ofctrl.c
+@@ -45,7 +45,6 @@
+ #include "ovn/actions.h"
+ #include "lib/extend-table.h"
+ #include "lib/lb.h"
+-#include "lib/ovn-util.h"
+ #include "openvswitch/poll-loop.h"
+ #include "physical.h"
+ #include "openvswitch/rconn.h"
+@@ -390,16 +389,9 @@ struct meter_band_entry {
+
+ static struct shash meter_bands;
+
+-static unsigned long *ecmp_nexthop_ids;
+-
+ static void ofctrl_meter_bands_destroy(void);
+ static void ofctrl_meter_bands_clear(void);
+
+-static void ecmp_nexthop_monitor_run(
+- const struct sbrec_ecmp_nexthop_table *enh_table,
+- struct ovs_list *msgs);
+-
+-
+ /* MFF_* field ID for our Geneve option. In S_TLV_TABLE_MOD_SENT, this is
+ * the option we requested (we don't know whether we obtained it yet). In
+ * S_CLEAR_FLOWS or S_UPDATE_FLOWS, this is really the option we have. */
+@@ -438,7 +430,6 @@ ofctrl_init(struct ovn_extend_table *group_table,
+ groups = group_table;
+ meters = meter_table;
+ shash_init(&meter_bands);
+- ecmp_nexthop_ids = bitmap_allocate(ECMP_NEXTHOP_IDS_LEN);
+ }
+
+ /* S_NEW, for a new connection.
+@@ -886,7 +877,6 @@ ofctrl_destroy(void)
+ expr_symtab_destroy(&symtab);
+ shash_destroy(&symtab);
+ ofctrl_meter_bands_destroy();
+- bitmap_free(ecmp_nexthop_ids);
+ }
+
+ uint64_t
+@@ -2316,47 +2306,6 @@ add_meter(struct ovn_extend_table_info *m_desired,
+ ofctrl_meter_bands_alloc(sb_meter, m_desired, msgs);
+ }
+
+-static void
+-ecmp_nexthop_monitor_flush_ct_entry(uint64_t id, struct ovs_list *msgs)
+-{
+- ovs_u128 mask = {
+- /* ct_labels.label BITS[96-127] */
+- .u64.hi = 0xffffffff00000000,
+- };
+- ovs_u128 nexthop = {
+- .u64.hi = id << 32,
+- };
+- struct ofp_ct_match match = {
+- .labels = nexthop,
+- .labels_mask = mask,
+- };
+- struct ofpbuf *msg = ofp_ct_match_encode(&match, NULL,
+- rconn_get_version(swconn));
+- ovs_list_push_back(msgs, &msg->list_node);
+-}
+-
+-static void
+-ecmp_nexthop_monitor_run(const struct sbrec_ecmp_nexthop_table *enh_table,
+- struct ovs_list *msgs)
+-{
+- unsigned long *ids = bitmap_allocate(ECMP_NEXTHOP_IDS_LEN);
+-
+- const struct sbrec_ecmp_nexthop *sbrec_ecmp_nexthop;
+- SBREC_ECMP_NEXTHOP_TABLE_FOR_EACH (sbrec_ecmp_nexthop, enh_table) {
+- bitmap_set1(ids, sbrec_ecmp_nexthop->id);
+- }
+-
+- int id;
+- BITMAP_FOR_EACH_1 (id, ECMP_NEXTHOP_IDS_LEN, ecmp_nexthop_ids) {
+- if (!bitmap_is_set(ids, id)) {
+- ecmp_nexthop_monitor_flush_ct_entry(id, msgs);
+- }
+- }
+-
+- bitmap_free(ecmp_nexthop_ids);
+- ecmp_nexthop_ids = ids;
+-}
+-
+ static void
+ installed_flow_add(struct ovn_flow *d,
+ struct ofputil_bundle_ctrl_msg *bc,
+@@ -2715,7 +2664,6 @@ ofctrl_put(struct ovn_desired_flow_table *lflow_table,
+ struct shash *pending_ct_zones,
+ struct hmap *pending_lb_tuples,
+ struct ovsdb_idl_index *sbrec_meter_by_name,
+- const struct sbrec_ecmp_nexthop_table *enh_table,
+ uint64_t req_cfg,
+ bool lflows_changed,
+ bool pflows_changed)
+@@ -2756,8 +2704,6 @@ ofctrl_put(struct ovn_desired_flow_table *lflow_table,
+ /* OpenFlow messages to send to the switch to bring it up-to-date. */
+ struct ovs_list msgs = OVS_LIST_INITIALIZER(&msgs);
+
+- ecmp_nexthop_monitor_run(enh_table, &msgs);
+-
+ /* Iterate through ct zones that need to be flushed. */
+ struct shash_node *iter;
+ SHASH_FOR_EACH(iter, pending_ct_zones) {
+diff --git a/controller/ofctrl.h b/controller/ofctrl.h
+index 33953a8a4..129e3b6ad 100644
+--- a/controller/ofctrl.h
++++ b/controller/ofctrl.h
+@@ -31,7 +31,6 @@ struct ofpbuf;
+ struct ovsrec_bridge;
+ struct ovsrec_open_vswitch_table;
+ struct sbrec_meter_table;
+-struct sbrec_ecmp_nexthop_table;
+ struct shash;
+
+ struct ovn_desired_flow_table {
+@@ -60,7 +59,6 @@ void ofctrl_put(struct ovn_desired_flow_table *lflow_table,
+ struct shash *pending_ct_zones,
+ struct hmap *pending_lb_tuples,
+ struct ovsdb_idl_index *sbrec_meter_by_name,
+- const struct sbrec_ecmp_nexthop_table *enh_table,
+ uint64_t nb_cfg,
+ bool lflow_changed,
+ bool pflow_changed);
+diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c
+index 27a4996a8..3b2a0d6bb 100644
+--- a/controller/ovn-controller.c
++++ b/controller/ovn-controller.c
+@@ -4456,22 +4456,7 @@ pflow_output_if_status_mgr_handler(struct engine_node *node,
+ }
+ if (pb->n_additional_chassis) {
+ /* Update flows for all ports in datapath. */
+- struct sbrec_port_binding *target =
+- sbrec_port_binding_index_init_row(
+- p_ctx.sbrec_port_binding_by_datapath);
+- sbrec_port_binding_index_set_datapath(target, pb->datapath);
+-
+- const struct sbrec_port_binding *binding;
+- SBREC_PORT_BINDING_FOR_EACH_EQUAL (
+- binding, target, p_ctx.sbrec_port_binding_by_datapath) {
+- bool removed = sbrec_port_binding_is_deleted(binding);
+- if (!physical_handle_flows_for_lport(binding, removed, &p_ctx,
+- &pfo->flow_table)) {
+- destroy_physical_ctx(&p_ctx);
+- return false;
+- }
+- }
+- sbrec_port_binding_index_destroy_row(target);
++ physical_multichassis_reprocess(pb, &p_ctx, &pfo->flow_table);
+ } else {
+ /* If any multichassis ports, update flows for the port. */
+ bool removed = sbrec_port_binding_is_deleted(pb);
+@@ -5501,17 +5486,14 @@ main(int argc, char *argv[])
+ br_int_remote.probe_interval)) {
+ VLOG_INFO("OVS feature set changed, force recompute.");
+ engine_set_force_recompute(true);
+- if (ovs_feature_set_discovered()) {
+- uint32_t max_groups = ovs_feature_max_select_groups_get();
+- uint32_t max_meters = ovs_feature_max_meters_get();
+- struct ed_type_lflow_output *lflow_out_data =
+- engine_get_internal_data(&en_lflow_output);
+-
+- ovn_extend_table_reinit(&lflow_out_data->group_table,
+- max_groups);
+- ovn_extend_table_reinit(&lflow_out_data->meter_table,
+- max_meters);
+- }
++
++ struct ed_type_lflow_output *lflow_out_data =
++ engine_get_internal_data(&en_lflow_output);
++
++ ovn_extend_table_reinit(&lflow_out_data->group_table,
++ ovs_feature_max_select_groups_get());
++ ovn_extend_table_reinit(&lflow_out_data->meter_table,
++ ovs_feature_max_meters_get());
+ }
+
+ if (br_int) {
+@@ -5725,8 +5707,6 @@ main(int argc, char *argv[])
+ &ct_zones_data->ctx.pending,
+ &lb_data->removed_tuples,
+ sbrec_meter_by_name,
+- sbrec_ecmp_nexthop_table_get(
+- ovnsb_idl_loop.idl),
+ ofctrl_seqno_get_req_cfg(),
+ engine_node_changed(&en_lflow_output),
+ engine_node_changed(&en_pflow_output));
+diff --git a/controller/physical.c b/controller/physical.c
+index 9e04ad5f2..c6db4f376 100644
+--- a/controller/physical.c
++++ b/controller/physical.c
+@@ -1258,6 +1258,12 @@ reply_imcp_error_if_pkt_too_big(struct ovn_desired_flow_table *flow_table,
+ ofpact_put_set_field(
+ &inner_ofpacts, mf_from_id(MFF_LOG_FLAGS), &value, &mask);
+
++ /* inport <-> outport */
++ put_stack(MFF_LOG_INPORT, ofpact_put_STACK_PUSH(&inner_ofpacts));
++ put_stack(MFF_LOG_OUTPORT, ofpact_put_STACK_PUSH(&inner_ofpacts));
++ put_stack(MFF_LOG_INPORT, ofpact_put_STACK_POP(&inner_ofpacts));
++ put_stack(MFF_LOG_OUTPORT, ofpact_put_STACK_POP(&inner_ofpacts));
++
+ /* eth.src <-> eth.dst */
+ put_stack(MFF_ETH_DST, ofpact_put_STACK_PUSH(&inner_ofpacts));
+ put_stack(MFF_ETH_SRC, ofpact_put_STACK_PUSH(&inner_ofpacts));
+@@ -1658,7 +1664,8 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name,
+ sbrec_port_binding_by_name, binding->parent_port);
+
+ if (parent_port
+- && !lport_can_bind_on_this_chassis(chassis, parent_port)) {
++ && (lport_can_bind_on_this_chassis(chassis,
++ parent_port) != CAN_BIND_AS_MAIN)) {
+ /* Even though there is an ofport for this container
+ * parent port, it is requested on different chassis ignore
+ * this container port.
+@@ -2397,33 +2404,9 @@ physical_handle_flows_for_lport(const struct sbrec_port_binding *pb,
+ }
+ }
+
+- if (ldp) {
+- bool multichassis_state_changed = (
+- !!pb->additional_chassis ==
+- !!shash_find(&ldp->multichassis_ports, pb->logical_port)
+- );
+- if (multichassis_state_changed) {
+- if (pb->additional_chassis) {
+- add_local_datapath_multichassis_port(
+- ldp, pb->logical_port, pb);
+- } else {
+- remove_local_datapath_multichassis_port(
+- ldp, pb->logical_port);
+- }
+-
+- struct sbrec_port_binding *target =
+- sbrec_port_binding_index_init_row(
+- p_ctx->sbrec_port_binding_by_datapath);
+- sbrec_port_binding_index_set_datapath(target, ldp->datapath);
+-
+- const struct sbrec_port_binding *port;
+- SBREC_PORT_BINDING_FOR_EACH_EQUAL (
+- port, target, p_ctx->sbrec_port_binding_by_datapath) {
+- ofctrl_remove_flows(flow_table, &port->header_.uuid);
+- physical_eval_port_binding(p_ctx, port, flow_table);
+- }
+- sbrec_port_binding_index_destroy_row(target);
+- }
++ if (sbrec_port_binding_is_updated(
++ pb, SBREC_PORT_BINDING_COL_ADDITIONAL_CHASSIS) || removed) {
++ physical_multichassis_reprocess(pb, p_ctx, flow_table);
+ }
+
+ if (!removed) {
+@@ -2440,6 +2423,25 @@ physical_handle_flows_for_lport(const struct sbrec_port_binding *pb,
+ return true;
+ }
+
++void
++physical_multichassis_reprocess(const struct sbrec_port_binding *pb,
++ struct physical_ctx *p_ctx,
++ struct ovn_desired_flow_table *flow_table)
++{
++ struct sbrec_port_binding *target =
++ sbrec_port_binding_index_init_row(
++ p_ctx->sbrec_port_binding_by_datapath);
++ sbrec_port_binding_index_set_datapath(target, pb->datapath);
++
++ const struct sbrec_port_binding *port;
++ SBREC_PORT_BINDING_FOR_EACH_EQUAL (port, target,
++ p_ctx->sbrec_port_binding_by_datapath) {
++ ofctrl_remove_flows(flow_table, &port->header_.uuid);
++ physical_eval_port_binding(p_ctx, port, flow_table);
++ }
++ sbrec_port_binding_index_destroy_row(target);
++}
++
+ void
+ physical_handle_mc_group_changes(struct physical_ctx *p_ctx,
+ struct ovn_desired_flow_table *flow_table)
+diff --git a/controller/physical.h b/controller/physical.h
+index dd4be7041..f0aecc852 100644
+--- a/controller/physical.h
++++ b/controller/physical.h
+@@ -81,4 +81,7 @@ bool physical_handle_flows_for_lport(const struct sbrec_port_binding *,
+ bool removed,
+ struct physical_ctx *,
+ struct ovn_desired_flow_table *);
++void physical_multichassis_reprocess(const struct sbrec_port_binding *,
++ struct physical_ctx *,
++ struct ovn_desired_flow_table *);
+ #endif /* controller/physical.h */
+diff --git a/controller/pinctrl.c b/controller/pinctrl.c
+index 7cbb0cf81..c86b4f940 100644
+--- a/controller/pinctrl.c
++++ b/controller/pinctrl.c
+@@ -1756,6 +1756,7 @@ pinctrl_handle_icmp(struct rconn *swconn, const struct flow *ip_flow,
+ if (mtu) {
+ put_16aligned_be32(ih->icmp6_data.be32, *mtu);
+ ih->icmp6_base.icmp6_type = ICMP6_PACKET_TOO_BIG;
++ ih->icmp6_base.icmp6_code = 0;
+ }
+
+ void *data = ih + 1;
+diff --git a/debian/changelog b/debian/changelog
+index 8168d1e83..dc867602c 100644
+--- a/debian/changelog
++++ b/debian/changelog
+@@ -1,8 +1,14 @@
++ovn (24.09.1-1) unstable; urgency=low
++ [ OVN team ]
++ * New upstream version
++
++ -- OVN team Fri, 13 Sep 2024 19:09:31 -0400
++
+ ovn (24.09.0-1) unstable; urgency=low
+
+ * New upstream version
+
+- -- OVN team Fri, 09 Aug 2024 09:56:41 -0400
++ -- OVN team Fri, 13 Sep 2024 19:09:31 -0400
+
+ ovn (24.03.0-1) unstable; urgency=low
+
+diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c
+index 69bac4ab2..db17630be 100644
+--- a/ic/ovn-ic.c
++++ b/ic/ovn-ic.c
+@@ -137,7 +137,7 @@ az_run(struct ic_context *ctx)
+ * "ovn-ic-sbctl destroy avail ". */
+ static char *az_name;
+ const struct icsbrec_availability_zone *az;
+- if (az_name && strcmp(az_name, nb_global->name)) {
++ if (ctx->ovnisb_txn && az_name && strcmp(az_name, nb_global->name)) {
+ ICSBREC_AVAILABILITY_ZONE_FOR_EACH (az, ctx->ovnisb_idl) {
+ /* AZ name update locally need to update az in ISB. */
+ if (nb_global->name[0] && !strcmp(az->name, az_name)) {
+diff --git a/include/ovn/actions.h b/include/ovn/actions.h
+index c8dd66ed8..a95a0daf7 100644
+--- a/include/ovn/actions.h
++++ b/include/ovn/actions.h
+@@ -260,6 +260,7 @@ struct ovnact_push_pop {
+ /* OVNACT_CT_NEXT. */
+ struct ovnact_ct_next {
+ struct ovnact ovnact;
++ bool dnat_zone;
+ uint8_t ltable; /* Logical table ID of next table. */
+ };
+
+diff --git a/include/ovn/features.h b/include/ovn/features.h
+index 4275f7526..3566ab60f 100644
+--- a/include/ovn/features.h
++++ b/include/ovn/features.h
+@@ -30,6 +30,7 @@
+ #define OVN_FEATURE_CT_COMMIT_NAT_V2 "ct-commit-nat-v2"
+ #define OVN_FEATURE_CT_COMMIT_TO_ZONE "ct-commit-to-zone"
+ #define OVN_FEATURE_SAMPLE_WITH_REGISTERS "ovn-sample-with-registers"
++#define OVN_FEATURE_CT_NEXT_ZONE "ct-next-zone"
+
+ /* OVS datapath supported features. Based on availability OVN might generate
+ * different types of openflows.
+diff --git a/lib/actions.c b/lib/actions.c
+index c12d087e7..2e05d4134 100644
+--- a/lib/actions.c
++++ b/lib/actions.c
+@@ -701,13 +701,32 @@ parse_CT_NEXT(struct action_context *ctx)
+ }
+
+ add_prerequisite(ctx, "ip");
+- ovnact_put_CT_NEXT(ctx->ovnacts)->ltable = ctx->pp->cur_ltable + 1;
++ struct ovnact_ct_next *ct_next = ovnact_put_CT_NEXT(ctx->ovnacts);
++ ct_next->dnat_zone = true;
++ ct_next->ltable = ctx->pp->cur_ltable + 1;
++
++ if (!lexer_match(ctx->lexer, LEX_T_LPAREN)) {
++ return;
++ }
++
++ if (lexer_match_id(ctx->lexer, "dnat")) {
++ ct_next->dnat_zone = true;
++ } else if (lexer_match_id(ctx->lexer, "snat")) {
++ ct_next->dnat_zone = false;
++ } else {
++ lexer_error(ctx->lexer, "\"ct_next\" action accepts only"
++ " \"dnat\" or \"snat\" parameter.");
++ return;
++ }
++
++ lexer_force_match(ctx->lexer, LEX_T_RPAREN);
+ }
+
+ static void
+ format_CT_NEXT(const struct ovnact_ct_next *ct_next OVS_UNUSED, struct ds *s)
+ {
+- ds_put_cstr(s, "ct_next;");
++ ds_put_cstr(s, "ct_next");
++ ds_put_cstr(s, ct_next->dnat_zone ? "(dnat);" : "(snat);");
+ }
+
+ static void
+@@ -719,11 +738,17 @@ encode_CT_NEXT(const struct ovnact_ct_next *ct_next,
+
+ struct ofpact_conntrack *ct = ofpact_put_CT(ofpacts);
+ ct->recirc_table = first_ptable(ep, ep->pipeline) + ct_next->ltable;
+- ct->zone_src.field = ep->is_switch ? mf_from_id(MFF_LOG_CT_ZONE)
+- : mf_from_id(MFF_LOG_DNAT_ZONE);
+ ct->zone_src.ofs = 0;
+ ct->zone_src.n_bits = 16;
+
++ if (ep->is_switch) {
++ ct->zone_src.field = mf_from_id(MFF_LOG_CT_ZONE);
++ } else {
++ ct->zone_src.field = mf_from_id(ct_next->dnat_zone
++ ? MFF_LOG_DNAT_ZONE
++ : MFF_LOG_SNAT_ZONE);
++ }
++
+ ct = ofpbuf_at_assert(ofpacts, ct_offset, sizeof *ct);
+ ofpacts->header = ct;
+ ofpact_finish_CT(ofpacts, &ct);
+diff --git a/lib/logical-fields.c b/lib/logical-fields.c
+index 2c9d3c61b..5a8b53f2b 100644
+--- a/lib/logical-fields.c
++++ b/lib/logical-fields.c
+@@ -293,6 +293,9 @@ ovn_init_symtab(struct shash *symtab)
+ "icmp6.type == {135, 136} && icmp6.code == 0 && ip.ttl == 255");
+ expr_symtab_add_predicate(symtab, "nd_ns",
+ "icmp6.type == 135 && icmp6.code == 0 && ip.ttl == 255");
++ expr_symtab_add_predicate(symtab, "nd_ns_mcast",
++ "ip6.mcast && icmp6.type == 135 && icmp6.code == 0 && "
++ "ip.ttl == 255");
+ expr_symtab_add_predicate(symtab, "nd_na",
+ "icmp6.type == 136 && icmp6.code == 0 && ip.ttl == 255");
+ expr_symtab_add_predicate(symtab, "nd_rs",
+diff --git a/lib/ovn-util.h b/lib/ovn-util.h
+index 622fec531..7b98b9b9a 100644
+--- a/lib/ovn-util.h
++++ b/lib/ovn-util.h
+@@ -38,8 +38,6 @@
+ #define STT_TUNNEL_OVERHEAD 18
+ #define VXLAN_TUNNEL_OVERHEAD 30
+
+-#define ECMP_NEXTHOP_IDS_LEN 65535
+-
+ struct eth_addr;
+ struct nbrec_logical_router_port;
+ struct ovsrec_flow_sample_collector_set_table;
+diff --git a/northd/en-global-config.c b/northd/en-global-config.c
+index 0ce7f8308..fff2aaa16 100644
+--- a/northd/en-global-config.c
++++ b/northd/en-global-config.c
+@@ -382,6 +382,7 @@ northd_enable_all_features(struct ed_type_global_config *data)
+ .ct_commit_nat_v2 = true,
+ .ct_commit_to_zone = true,
+ .sample_with_reg = true,
++ .ct_next_zone = true,
+ };
+ }
+
+@@ -452,6 +453,15 @@ build_chassis_features(const struct sbrec_chassis_table *sbrec_chassis_table,
+ chassis_features->sample_with_reg) {
+ chassis_features->sample_with_reg = false;
+ }
++
++ bool ct_next_zone =
++ smap_get_bool(&chassis->other_config,
++ OVN_FEATURE_CT_NEXT_ZONE,
++ false);
++ if (!ct_next_zone &&
++ chassis_features->ct_next_zone) {
++ chassis_features->ct_next_zone = false;
++ }
+ }
+ }
+
+diff --git a/northd/en-global-config.h b/northd/en-global-config.h
+index 0cf34482a..767810542 100644
+--- a/northd/en-global-config.h
++++ b/northd/en-global-config.h
+@@ -20,6 +20,7 @@ struct chassis_features {
+ bool ct_commit_nat_v2;
+ bool ct_commit_to_zone;
+ bool sample_with_reg;
++ bool ct_next_zone;
+ };
+
+ struct global_config_tracked_data {
+diff --git a/northd/en-lflow.c b/northd/en-lflow.c
+index f9d7f2459..469d7c6b5 100644
+--- a/northd/en-lflow.c
++++ b/northd/en-lflow.c
+@@ -42,7 +42,8 @@ lflow_get_input_data(struct engine_node *node,
+ struct lflow_input *lflow_input)
+ {
+ struct northd_data *northd_data = engine_get_input_data("northd", node);
+- struct bfd_data *bfd_data = engine_get_input_data("bfd_sync", node);
++ struct bfd_sync_data *bfd_sync_data =
++ engine_get_input_data("bfd_sync", node);
+ struct static_routes_data *static_routes_data =
+ engine_get_input_data("static_routes", node);
+ struct route_policies_data *route_policies_data =
+@@ -55,8 +56,6 @@ lflow_get_input_data(struct engine_node *node,
+ engine_get_input_data("lr_stateful", node);
+ struct ed_type_ls_stateful *ls_stateful_data =
+ engine_get_input_data("ls_stateful", node);
+- struct ecmp_nexthop_data *nexthop_data =
+- engine_get_input_data("ecmp_nexthop", node);
+
+ lflow_input->sbrec_logical_flow_table =
+ EN_OVSDB_GET(engine_get_input("SB_logical_flow", node));
+@@ -82,11 +81,10 @@ lflow_get_input_data(struct engine_node *node,
+ lflow_input->meter_groups = &sync_meters_data->meter_groups;
+ lflow_input->lb_datapaths_map = &northd_data->lb_datapaths_map;
+ lflow_input->svc_monitor_map = &northd_data->svc_monitor_map;
+- lflow_input->bfd_connections = &bfd_data->bfd_connections;
++ lflow_input->bfd_ports = &bfd_sync_data->bfd_ports;
+ lflow_input->parsed_routes = &static_routes_data->parsed_routes;
+ lflow_input->route_tables = &static_routes_data->route_tables;
+ lflow_input->route_policies = &route_policies_data->route_policies;
+- lflow_input->nexthops_table = &nexthop_data->nexthops;
+
+ struct ed_type_global_config *global_config =
+ engine_get_input_data("global_config", node);
+diff --git a/northd/en-northd.c b/northd/en-northd.c
+index 63f93bbf4..24ed31517 100644
+--- a/northd/en-northd.c
++++ b/northd/en-northd.c
+@@ -392,34 +392,15 @@ en_bfd_sync_run(struct engine_node *node, void *data)
+ = engine_get_input_data("static_routes", node);
+ const struct nbrec_bfd_table *nbrec_bfd_table =
+ EN_OVSDB_GET(engine_get_input("NB_bfd", node));
+- struct bfd_data *bfd_sync_data = data;
++ struct bfd_sync_data *bfd_sync_data = data;
+
+- bfd_destroy(data);
+- bfd_init(data);
++ bfd_sync_destroy(data);
++ bfd_sync_init(data);
+ bfd_table_sync(eng_ctx->ovnsb_idl_txn, nbrec_bfd_table,
+ &northd_data->lr_ports, &bfd_data->bfd_connections,
+ &route_policies_data->bfd_active_connections,
+ &static_routes_data->bfd_active_connections,
+- &bfd_sync_data->bfd_connections);
+- engine_set_node_state(node, EN_UPDATED);
+-}
+-
+-void
+-en_ecmp_nexthop_run(struct engine_node *node, void *data)
+-{
+- const struct engine_context *eng_ctx = engine_get_context();
+- struct static_routes_data *static_routes_data =
+- engine_get_input_data("static_routes", node);
+- struct ecmp_nexthop_data *enh_data = data;
+- const struct sbrec_ecmp_nexthop_table *sbrec_ecmp_nexthop_table =
+- EN_OVSDB_GET(engine_get_input("SB_ecmp_nexthop", node));
+-
+- ecmp_nexthop_destroy(data);
+- ecmp_nexthop_init(data);
+- build_ecmp_nexthop_table(eng_ctx->ovnsb_idl_txn,
+- &static_routes_data->parsed_routes,
+- &enh_data->nexthops,
+- sbrec_ecmp_nexthop_table);
++ &bfd_sync_data->bfd_ports);
+ engine_set_node_state(node, EN_UPDATED);
+ }
+
+@@ -468,18 +449,8 @@ void
+ *en_bfd_sync_init(struct engine_node *node OVS_UNUSED,
+ struct engine_arg *arg OVS_UNUSED)
+ {
+- struct bfd_data *data = xzalloc(sizeof *data);
+- bfd_init(data);
+- return data;
+-}
+-
+-void
+-*en_ecmp_nexthop_init(struct engine_node *node OVS_UNUSED,
+- struct engine_arg *arg OVS_UNUSED)
+-{
+- struct ecmp_nexthop_data *data = xzalloc(sizeof *data);
+-
+- ecmp_nexthop_init(data);
++ struct bfd_sync_data *data = xzalloc(sizeof *data);
++ bfd_sync_init(data);
+ return data;
+ }
+
+@@ -553,11 +524,5 @@ en_bfd_cleanup(void *data)
+ void
+ en_bfd_sync_cleanup(void *data)
+ {
+- bfd_destroy(data);
+-}
+-
+-void
+-en_ecmp_nexthop_cleanup(void *data)
+-{
+- ecmp_nexthop_destroy(data);
++ bfd_sync_destroy(data);
+ }
+diff --git a/northd/en-northd.h b/northd/en-northd.h
+index 2666cc67e..631a7c17a 100644
+--- a/northd/en-northd.h
++++ b/northd/en-northd.h
+@@ -42,9 +42,5 @@ bool bfd_sync_northd_change_handler(struct engine_node *node,
+ void *data OVS_UNUSED);
+ void en_bfd_sync_run(struct engine_node *node, void *data);
+ void en_bfd_sync_cleanup(void *data OVS_UNUSED);
+-void en_ecmp_nexthop_run(struct engine_node *node, void *data);
+-void *en_ecmp_nexthop_init(struct engine_node *node OVS_UNUSED,
+- struct engine_arg *arg OVS_UNUSED);
+-void en_ecmp_nexthop_cleanup(void *data);
+
+ #endif /* EN_NORTHD_H */
+diff --git a/northd/inc-proc-northd.c b/northd/inc-proc-northd.c
+index cb880b439..1f79916a5 100644
+--- a/northd/inc-proc-northd.c
++++ b/northd/inc-proc-northd.c
+@@ -103,8 +103,7 @@ static unixctl_cb_func chassis_features_list;
+ SB_NODE(fdb, "fdb") \
+ SB_NODE(static_mac_binding, "static_mac_binding") \
+ SB_NODE(chassis_template_var, "chassis_template_var") \
+- SB_NODE(logical_dp_group, "logical_dp_group") \
+- SB_NODE(ecmp_nexthop, "ecmp_nexthop")
++ SB_NODE(logical_dp_group, "logical_dp_group")
+
+ enum sb_engine_node {
+ #define SB_NODE(NAME, NAME_STR) SB_##NAME,
+@@ -163,7 +162,6 @@ static ENGINE_NODE(route_policies, "route_policies");
+ static ENGINE_NODE(static_routes, "static_routes");
+ static ENGINE_NODE(bfd, "bfd");
+ static ENGINE_NODE(bfd_sync, "bfd_sync");
+-static ENGINE_NODE(ecmp_nexthop, "ecmp_nexthop");
+
+ void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
+ struct ovsdb_idl_loop *sb)
+@@ -266,9 +264,6 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
+ engine_add_input(&en_bfd_sync, &en_route_policies, NULL);
+ engine_add_input(&en_bfd_sync, &en_northd, bfd_sync_northd_change_handler);
+
+- engine_add_input(&en_ecmp_nexthop, &en_sb_ecmp_nexthop, NULL);
+- engine_add_input(&en_ecmp_nexthop, &en_static_routes, NULL);
+-
+ engine_add_input(&en_sync_meters, &en_nb_acl, NULL);
+ engine_add_input(&en_sync_meters, &en_nb_meter, NULL);
+ engine_add_input(&en_sync_meters, &en_sb_meter, NULL);
+@@ -282,7 +277,6 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
+ engine_add_input(&en_lflow, &en_bfd_sync, NULL);
+ engine_add_input(&en_lflow, &en_route_policies, NULL);
+ engine_add_input(&en_lflow, &en_static_routes, NULL);
+- engine_add_input(&en_lflow, &en_ecmp_nexthop, NULL);
+ engine_add_input(&en_lflow, &en_global_config,
+ node_global_config_handler);
+
+diff --git a/northd/northd.c b/northd/northd.c
+index 5ad30d854..2c4703301 100644
+--- a/northd/northd.c
++++ b/northd/northd.c
+@@ -1126,7 +1126,7 @@ is_l3dgw_port(const struct ovn_port *op)
+ /* This function returns true if 'op' is a chassis resident
+ * derived port. False otherwise.
+ * There are 2 ways to check if 'op' is chassis resident port.
+- * 1. op->sb->type is "chassisresident"
++ * 1. op->sb->type is "chassisredirect"
+ * 2. op->primary_port is not NULL. If op->primary_port is set,
+ * it means 'op' is derived from the ovn_port op->primary_port.
+ *
+@@ -2136,7 +2136,7 @@ create_cr_port(struct ovn_port *op, struct hmap *ports,
+
+ struct ovn_port *crp = ovn_port_find(ports, redirect_name);
+ if (crp && crp->sb && crp->sb->datapath == op->od->sb) {
+- ovn_port_set_nb(crp, NULL, op->nbrp);
++ ovn_port_set_nb(crp, op->nbsp, op->nbrp);
+ ovs_list_remove(&crp->list);
+ ovs_list_push_back(both_dbs, &crp->list);
+ } else {
+@@ -2466,7 +2466,7 @@ join_logical_ports(const struct sbrec_port_binding_table *sbrec_pb_table,
+ }
+
+
+- /* Create chassisresident port for the distributed gateway port's (DGP)
++ /* Create chassisredirect port for the distributed gateway port's (DGP)
+ * peer if
+ * - DGP's router has only one DGP and
+ * - Its peer is a logical switch port and
+@@ -9633,16 +9633,21 @@ build_lswitch_arp_nd_responder_known_ips(struct ovn_port *op,
+ op->lflow_ref);
+ }
+
+- /* For ND solicitations, we need to listen for both the
+- * unicast IPv6 address and its all-nodes multicast address,
+- * but always respond with the unicast IPv6 address. */
++ /* For ND solicitations:
++ * - Reply only for the all-nodes multicast address(es) of the
++ * logical port IPv6 address(es).
++ *
++ * - Do not reply for unicast ND solicitations. Let the target
++ * reply to it, so that the sender has the ability to monitor
++ * the target liveness via the unicast ND solicitations.
++ */
+ for (size_t j = 0; j < op->lsp_addrs[i].n_ipv6_addrs; j++) {
+ ds_clear(match);
+- ds_put_format(match,
+- "nd_ns && ip6.dst == {%s, %s} && nd.target == %s",
+- op->lsp_addrs[i].ipv6_addrs[j].addr_s,
+- op->lsp_addrs[i].ipv6_addrs[j].sn_addr_s,
+- op->lsp_addrs[i].ipv6_addrs[j].addr_s);
++ ds_put_format(
++ match,
++ "nd_ns_mcast && ip6.dst == %s && nd.target == %s",
++ op->lsp_addrs[i].ipv6_addrs[j].sn_addr_s,
++ op->lsp_addrs[i].ipv6_addrs[j].addr_s);
+
+ ds_clear(actions);
+ ds_put_format(actions,
+@@ -10437,18 +10442,11 @@ bfd_port_lookup(const struct hmap *bfd_map, const char *logical_port,
+ }
+
+ static bool
+-bfd_is_port_running(const struct hmap *bfd_map, const char *port)
++bfd_is_port_running(const struct sset *bfd_ports, const char *port)
+ {
+- struct bfd_entry *bfd_e;
+- HMAP_FOR_EACH (bfd_e, hmap_node, bfd_map) {
+- if (!strcmp(bfd_e->logical_port, port)) {
+- return true;
+- }
+- }
+- return false;
++ return !!sset_find(bfd_ports, port);
+ }
+
+-
+ #define BFD_DEF_MINTX 1000 /* 1s */
+ #define BFD_DEF_MINRX 1000 /* 1s */
+ #define BFD_DEF_DETECT_MULT 5
+@@ -10536,17 +10534,18 @@ bfd_table_sync(struct ovsdb_idl_txn *ovnsb_txn,
+ const struct hmap *bfd_connections,
+ const struct hmap *rp_bfd_connections,
+ const struct hmap *sr_bfd_connections,
+- struct hmap *sync_bfd_connections)
++ struct sset *bfd_ports)
+ {
+ if (!ovnsb_txn) {
+ return;
+ }
+
+ unsigned long *bfd_src_ports = bitmap_allocate(BFD_UDP_SRC_PORT_LEN);
++ struct hmap sync_bfd_connections = HMAP_INITIALIZER(&sync_bfd_connections);
+
+ struct bfd_entry *bfd_e;
+ HMAP_FOR_EACH (bfd_e, hmap_node, bfd_connections) {
+- struct bfd_entry *e = bfd_alloc_entry(sync_bfd_connections,
++ struct bfd_entry *e = bfd_alloc_entry(&sync_bfd_connections,
+ bfd_e->logical_port,
+ bfd_e->dst_ip, bfd_e->status);
+ e->nb_bt = bfd_e->nb_bt;
+@@ -10561,7 +10560,7 @@ bfd_table_sync(struct ovsdb_idl_txn *ovnsb_txn,
+
+ const struct nbrec_bfd *nb_bt;
+ NBREC_BFD_TABLE_FOR_EACH (nb_bt, nbrec_bfd_table) {
+- bfd_e = bfd_port_lookup(sync_bfd_connections, nb_bt->logical_port,
++ bfd_e = bfd_port_lookup(&sync_bfd_connections, nb_bt->logical_port,
+ nb_bt->dst_ip);
+ if (!bfd_e) {
+ continue;
+@@ -10619,16 +10618,17 @@ bfd_table_sync(struct ovsdb_idl_txn *ovnsb_txn,
+ }
+ }
+
++ sset_add(bfd_ports, nb_bt->logical_port);
+ bfd_e->stale = false;
+ }
+
+- HMAP_FOR_EACH_SAFE (bfd_e, hmap_node, sync_bfd_connections) {
++ HMAP_FOR_EACH_POP (bfd_e, hmap_node, &sync_bfd_connections) {
+ if (bfd_e->stale) {
+- hmap_remove(sync_bfd_connections, &bfd_e->hmap_node);
+ sbrec_bfd_delete(bfd_e->sb_bt);
+- bfd_erase_entry(bfd_e);
+ }
++ bfd_erase_entry(bfd_e);
+ }
++ hmap_destroy(&sync_bfd_connections);
+
+ bitmap_free(bfd_src_ports);
+ }
+@@ -10665,64 +10665,6 @@ build_bfd_map(const struct nbrec_bfd_table *nbrec_bfd_table,
+ }
+ }
+
+-void
+-build_ecmp_nexthop_table(
+- struct ovsdb_idl_txn *ovnsb_txn,
+- struct hmap *routes,
+- struct simap *nexthops,
+- const struct sbrec_ecmp_nexthop_table *sbrec_ecmp_nexthop_table)
+-{
+- if (!ovnsb_txn) {
+- return;
+- }
+-
+- unsigned long *nexthop_ids = bitmap_allocate(ECMP_NEXTHOP_IDS_LEN);
+- const struct sbrec_ecmp_nexthop *sb_ecmp_nexthop;
+- SBREC_ECMP_NEXTHOP_TABLE_FOR_EACH (sb_ecmp_nexthop,
+- sbrec_ecmp_nexthop_table) {
+- simap_put(nexthops, sb_ecmp_nexthop->nexthop,
+- sb_ecmp_nexthop->id);
+- bitmap_set1(nexthop_ids, sb_ecmp_nexthop->id);
+- }
+-
+- struct sset nb_nexthops_sset = SSET_INITIALIZER(&nb_nexthops_sset);
+-
+- struct parsed_route *pr;
+- HMAP_FOR_EACH (pr, key_node, routes) {
+- if (!pr->ecmp_symmetric_reply) {
+- continue;
+- }
+-
+- const struct nbrec_logical_router_static_route *r = pr->route;
+- if (!simap_contains(nexthops, r->nexthop)) {
+- int id = bitmap_scan(nexthop_ids, 0, 1, ECMP_NEXTHOP_IDS_LEN);
+- if (id == ECMP_NEXTHOP_IDS_LEN) {
+- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
+- VLOG_WARN_RL(&rl, "nexthop id address space is exhausted");
+- continue;
+- }
+- bitmap_set1(nexthop_ids, id);
+- simap_put(nexthops, r->nexthop, id);
+-
+- sb_ecmp_nexthop = sbrec_ecmp_nexthop_insert(ovnsb_txn);
+- sbrec_ecmp_nexthop_set_nexthop(sb_ecmp_nexthop, r->nexthop);
+- sbrec_ecmp_nexthop_set_id(sb_ecmp_nexthop, id);
+- }
+- sset_add(&nb_nexthops_sset, r->nexthop);
+- }
+-
+- SBREC_ECMP_NEXTHOP_TABLE_FOR_EACH_SAFE (sb_ecmp_nexthop,
+- sbrec_ecmp_nexthop_table) {
+- if (!sset_contains(&nb_nexthops_sset, sb_ecmp_nexthop->nexthop)) {
+- simap_find_and_delete(nexthops, sb_ecmp_nexthop->nexthop);
+- sbrec_ecmp_nexthop_delete(sb_ecmp_nexthop);
+- }
+- }
+-
+- sset_destroy(&nb_nexthops_sset);
+- bitmap_free(nexthop_ids);
+-}
+-
+ /* Returns a string of the IP address of the router port 'op' that
+ * overlaps with 'ip_s". If one is not found, returns NULL.
+ *
+@@ -11113,7 +11055,7 @@ parsed_route_lookup(struct hmap *routes, size_t hash,
+ static void
+ parsed_routes_add(struct ovn_datapath *od, const struct hmap *lr_ports,
+ const struct nbrec_logical_router_static_route *route,
+- struct hmap *bfd_connections,
++ const struct hmap *bfd_connections,
+ struct hmap *routes, struct simap *route_tables,
+ struct hmap *bfd_active_connections)
+ {
+@@ -11226,7 +11168,7 @@ parsed_routes_add(struct ovn_datapath *od, const struct hmap *lr_ports,
+
+ void
+ build_parsed_routes(struct ovn_datapath *od, const struct hmap *lr_ports,
+- struct hmap *bfd_connections, struct hmap *routes,
++ const struct hmap *bfd_connections, struct hmap *routes,
+ struct simap *route_tables,
+ struct hmap *bfd_active_connections)
+ {
+@@ -11512,8 +11454,7 @@ add_ecmp_symmetric_reply_flows(struct lflow_table *lflows,
+ struct ovn_port *out_port,
+ const struct parsed_route *route,
+ struct ds *route_match,
+- struct lflow_ref *lflow_ref,
+- struct simap *nexthops_table)
++ struct lflow_ref *lflow_ref)
+ {
+ const struct nbrec_logical_router_static_route *st_route = route->route;
+ struct ds match = DS_EMPTY_INITIALIZER;
+@@ -11548,15 +11489,9 @@ add_ecmp_symmetric_reply_flows(struct lflow_table *lflows,
+ ds_put_cstr(&match, " && (ct.new || ct.est)");
+ ds_put_format(&actions,
+ "ct_commit { ct_label.ecmp_reply_eth = eth.src; "
+- "ct_mark.ecmp_reply_port = %" PRId64 ";",
++ "ct_mark.ecmp_reply_port = %" PRId64 ";}; "
++ "next;",
+ out_port->sb->tunnel_key);
+-
+- struct simap_node *n = simap_find(nexthops_table, st_route->nexthop);
+- if (n) {
+- ds_put_format(&actions, " ct_label.label = %d;", n->data);
+- }
+- ds_put_cstr(&actions, " }; next;");
+-
+ ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ECMP_STATEFUL, 100,
+ ds_cstr(&match), ds_cstr(&actions),
+ &st_route->header_,
+@@ -11613,8 +11548,7 @@ add_ecmp_symmetric_reply_flows(struct lflow_table *lflows,
+ static void
+ build_ecmp_route_flow(struct lflow_table *lflows, struct ovn_datapath *od,
+ const struct hmap *lr_ports, struct ecmp_groups_node *eg,
+- struct lflow_ref *lflow_ref,
+- struct simap *nexthops_table)
++ struct lflow_ref *lflow_ref)
+
+ {
+ bool is_ipv4 = IN6_IS_ADDR_V4MAPPED(&eg->prefix);
+@@ -11631,21 +11565,27 @@ build_ecmp_route_flow(struct lflow_table *lflows, struct ovn_datapath *od,
+
+ struct ds actions = DS_EMPTY_INITIALIZER;
+ ds_put_format(&actions, "ip.ttl--; flags.loopback = 1; %s = %"PRIu16
+- "; %s = select(", REG_ECMP_GROUP_ID, eg->id,
+- REG_ECMP_MEMBER_ID);
++ "; %s = ", REG_ECMP_GROUP_ID, eg->id, REG_ECMP_MEMBER_ID);
+
+- bool is_first = true;
+- LIST_FOR_EACH (er, list_node, &eg->route_list) {
+- if (is_first) {
+- is_first = false;
+- } else {
+- ds_put_cstr(&actions, ", ");
++ if (!ovs_list_is_singleton(&eg->route_list)) {
++ bool is_first = true;
++
++ ds_put_cstr(&actions, "select(");
++ LIST_FOR_EACH (er, list_node, &eg->route_list) {
++ if (is_first) {
++ is_first = false;
++ } else {
++ ds_put_cstr(&actions, ", ");
++ }
++ ds_put_format(&actions, "%"PRIu16, er->id);
+ }
+- ds_put_format(&actions, "%"PRIu16, er->id);
++ ds_put_cstr(&actions, ");");
++ } else {
++ er = CONTAINER_OF(ovs_list_front(&eg->route_list),
++ struct ecmp_route_list_node, list_node);
++ ds_put_format(&actions, "%"PRIu16"; next;", er->id);
+ }
+
+- ds_put_cstr(&actions, ");");
+-
+ ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, priority,
+ ds_cstr(&route_match), ds_cstr(&actions),
+ lflow_ref);
+@@ -11671,7 +11611,7 @@ build_ecmp_route_flow(struct lflow_table *lflows, struct ovn_datapath *od,
+ out_port->key)) {
+ add_ecmp_symmetric_reply_flows(lflows, od, lrp_addr_s, out_port,
+ route_, &route_match,
+- lflow_ref, nexthops_table);
++ lflow_ref);
+ }
+ ds_clear(&match);
+ ds_put_format(&match, REG_ECMP_GROUP_ID" == %"PRIu16" && "
+@@ -11704,7 +11644,7 @@ add_route(struct lflow_table *lflows, struct ovn_datapath *od,
+ const struct ovn_port *op, const char *lrp_addr_s,
+ const char *network_s, int plen, const char *gateway,
+ bool is_src_route, const uint32_t rtb_id,
+- const struct hmap *bfd_connections,
++ const struct sset *bfd_ports,
+ const struct ovsdb_idl_row *stage_hint, bool is_discard_route,
+ int ofs, struct lflow_ref *lflow_ref)
+ {
+@@ -11753,7 +11693,7 @@ add_route(struct lflow_table *lflows, struct ovn_datapath *od,
+ priority, ds_cstr(&match),
+ ds_cstr(&actions), stage_hint,
+ lflow_ref);
+- if (op && bfd_is_port_running(bfd_connections, op->key)) {
++ if (op && bfd_is_port_running(bfd_ports, op->key)) {
+ ds_put_format(&match, " && udp.dst == 3784");
+ ovn_lflow_add_with_hint(lflows, op->od,
+ S_ROUTER_IN_IP_ROUTING,
+@@ -11770,7 +11710,7 @@ static void
+ build_static_route_flow(struct lflow_table *lflows, struct ovn_datapath *od,
+ const struct hmap *lr_ports,
+ const struct parsed_route *route_,
+- const struct hmap *bfd_connections,
++ const struct sset *bfd_ports,
+ struct lflow_ref *lflow_ref)
+ {
+ const char *lrp_addr_s = NULL;
+@@ -11795,7 +11735,7 @@ build_static_route_flow(struct lflow_table *lflows, struct ovn_datapath *od,
+ add_route(lflows, route_->is_discard_route ? od : out_port->od, out_port,
+ lrp_addr_s, prefix_s, route_->plen, route->nexthop,
+ route_->is_src_route, route_->route_table_id,
+- bfd_connections, &route->header_, route_->is_discard_route,
++ bfd_ports, &route->header_, route_->is_discard_route,
+ ofs, lflow_ref);
+
+ free(prefix_s);
+@@ -12617,7 +12557,7 @@ build_lrouter_port_nat_arp_nd_flow(struct ovn_port *op,
+
+ if (op->peer && op->peer->cr_port) {
+ /* We don't add the below flows if the router port's peer has
+- * a chassisresident port. That's because routing is centralized on
++ * a chassisredirect port. That's because routing is centralized on
+ * the gateway chassis for the router port networks/subnets.
+ */
+ return;
+@@ -12947,10 +12887,10 @@ build_lrouter_force_snat_flows_op(struct ovn_port *op,
+ static void
+ build_lrouter_bfd_flows(struct lflow_table *lflows, struct ovn_port *op,
+ const struct shash *meter_groups,
+- const struct hmap *bfd_connections,
++ const struct sset *bfd_ports,
+ struct lflow_ref *lflow_ref)
+ {
+- if (!bfd_is_port_running(bfd_connections, op->key)) {
++ if (!bfd_is_port_running(bfd_ports, op->key)) {
+ return;
+ }
+
+@@ -13546,7 +13486,7 @@ build_ip_routing_pre_flows_for_lrouter(struct ovn_datapath *od,
+ */
+ static void
+ build_ip_routing_flows_for_lrp(struct ovn_port *op,
+- const struct hmap *bfd_connections,
++ const struct sset *bfd_ports,
+ struct lflow_table *lflows,
+ struct lflow_ref *lflow_ref)
+ {
+@@ -13555,7 +13495,7 @@ build_ip_routing_flows_for_lrp(struct ovn_port *op,
+ add_route(lflows, op->od, op, op->lrp_networks.ipv4_addrs[i].addr_s,
+ op->lrp_networks.ipv4_addrs[i].network_s,
+ op->lrp_networks.ipv4_addrs[i].plen, NULL, false, 0,
+- bfd_connections, &op->nbrp->header_, false,
++ bfd_ports, &op->nbrp->header_, false,
+ ROUTE_PRIO_OFFSET_CONNECTED, lflow_ref);
+ }
+
+@@ -13563,7 +13503,7 @@ build_ip_routing_flows_for_lrp(struct ovn_port *op,
+ add_route(lflows, op->od, op, op->lrp_networks.ipv6_addrs[i].addr_s,
+ op->lrp_networks.ipv6_addrs[i].network_s,
+ op->lrp_networks.ipv6_addrs[i].plen, NULL, false, 0,
+- bfd_connections, &op->nbrp->header_, false,
++ bfd_ports, &op->nbrp->header_, false,
+ ROUTE_PRIO_OFFSET_CONNECTED, lflow_ref);
+ }
+ }
+@@ -13572,8 +13512,8 @@ static void
+ build_static_route_flows_for_lrouter(
+ struct ovn_datapath *od, struct lflow_table *lflows,
+ const struct hmap *lr_ports, struct hmap *parsed_routes,
+- struct simap *route_tables, const struct hmap *bfd_connections,
+- struct lflow_ref *lflow_ref, struct simap *nexthops_table)
++ struct simap *route_tables, const struct sset *bfd_ports,
++ struct lflow_ref *lflow_ref)
+ {
+ ovs_assert(od->nbr);
+ ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_IP_ROUTING_ECMP,
+@@ -13607,6 +13547,11 @@ build_static_route_flows_for_lrouter(
+ if (group) {
+ ecmp_groups_add_route(group, route);
+ }
++ } else if (route->ecmp_symmetric_reply) {
++ /* Traffic for symmetric reply routes has to be conntracked
++ * even if there is only one next-hop, in case another next-hop
++ * is added later. */
++ ecmp_groups_add(&ecmp_groups, route);
+ } else {
+ unique_routes_add(&unique_routes, route);
+ }
+@@ -13615,13 +13560,12 @@ build_static_route_flows_for_lrouter(
+ HMAP_FOR_EACH (group, hmap_node, &ecmp_groups) {
+ /* add a flow in IP_ROUTING, and one flow for each member in
+ * IP_ROUTING_ECMP. */
+- build_ecmp_route_flow(lflows, od, lr_ports, group, lflow_ref,
+- nexthops_table);
++ build_ecmp_route_flow(lflows, od, lr_ports, group, lflow_ref);
+ }
+ const struct unique_routes_node *ur;
+ HMAP_FOR_EACH (ur, hmap_node, &unique_routes) {
+ build_static_route_flow(lflows, od, lr_ports, ur->route,
+- bfd_connections, lflow_ref);
++ bfd_ports, lflow_ref);
+ }
+ ecmp_groups_destroy(&ecmp_groups);
+ unique_routes_destroy(&unique_routes);
+@@ -14002,6 +13946,234 @@ build_arp_resolve_flows_for_lrp(struct ovn_port *op,
+ }
+ }
+
++static void
++build_routing_protocols_redirect_rule__(
++ const char *s_addr, const char *redirect_port_name, int protocol_port,
++ const char *proto, bool is_ipv6, struct ovn_port *ls_peer,
++ struct lflow_table *lflows, struct ds *match, struct ds *actions,
++ struct lflow_ref *lflow_ref)
++{
++ int ip_ver = is_ipv6 ? 6 : 4;
++ ds_clear(actions);
++ ds_put_format(actions, "outport = \"%s\"; output;", redirect_port_name);
++
++ /* Redirect packets in the input pipeline destined for LR's IP
++ * and the routing protocol's port to the LSP specified in
++ * 'routing-protocol-redirect' option.*/
++ ds_clear(match);
++ ds_put_format(match, "ip%d.dst == %s && %s.dst == %d", ip_ver, s_addr,
++ proto, protocol_port);
++ ovn_lflow_add(lflows, ls_peer->od, S_SWITCH_IN_L2_LKUP, 100,
++ ds_cstr(match),
++ ds_cstr(actions),
++ lflow_ref);
++
++ /* To accomodate "peer" nature of the routing daemons, redirect also
++ * replies to the daemons' client requests. */
++ ds_clear(match);
++ ds_put_format(match, "ip%d.dst == %s && %s.src == %d", ip_ver, s_addr,
++ proto, protocol_port);
++ ovn_lflow_add(lflows, ls_peer->od, S_SWITCH_IN_L2_LKUP, 100,
++ ds_cstr(match),
++ ds_cstr(actions),
++ lflow_ref);
++}
++
++static void
++apply_routing_protocols_redirect__(
++ const char *s_addr, const char *redirect_port_name, int protocol_flags,
++ bool is_ipv6, struct ovn_port *ls_peer, struct lflow_table *lflows,
++ struct ds *match, struct ds *actions, struct lflow_ref *lflow_ref)
++{
++ if (protocol_flags & REDIRECT_BGP) {
++ build_routing_protocols_redirect_rule__(s_addr, redirect_port_name,
++ 179, "tcp", is_ipv6, ls_peer,
++ lflows, match, actions,
++ lflow_ref);
++ }
++
++ if (protocol_flags & REDIRECT_BFD) {
++ build_routing_protocols_redirect_rule__(s_addr, redirect_port_name,
++ 3784, "udp", is_ipv6, ls_peer,
++ lflows, match, actions,
++ lflow_ref);
++ }
++
++ /* Because the redirected port shares IP and MAC addresses with the LRP,
++ * special consideration needs to be given to the signaling protocols. */
++ ds_clear(actions);
++ ds_put_format(actions,
++ "clone { outport = \"%s\"; output; }; "
++ "outport = %s; output;",
++ redirect_port_name, ls_peer->json_key);
++ if (is_ipv6) {
++ /* Ensure that redirect port receives copy of NA messages destined to
++ * its IP.*/
++ ds_clear(match);
++ ds_put_format(match, "ip6.dst == %s && nd_na", s_addr);
++ ovn_lflow_add(lflows, ls_peer->od, S_SWITCH_IN_L2_LKUP, 100,
++ ds_cstr(match),
++ ds_cstr(actions),
++ lflow_ref);
++ } else {
++ /* Ensure that redirect port receives copy of ARP replies destined to
++ * its IP */
++ ds_clear(match);
++ ds_put_format(match, "arp.op == 2 && arp.tpa == %s", s_addr);
++ ovn_lflow_add(lflows, ls_peer->od, S_SWITCH_IN_L2_LKUP, 100,
++ ds_cstr(match),
++ ds_cstr(actions),
++ lflow_ref);
++ }
++}
++
++static int
++parse_redirected_routing_protocols(struct ovn_port *lrp) {
++ int redirected_protocol_flags = 0;
++ const char *redirect_protocols = smap_get(&lrp->nbrp->options,
++ "routing-protocols");
++ if (!redirect_protocols) {
++ return redirected_protocol_flags;
++ }
++
++ char *proto;
++ char *save_ptr = NULL;
++ char *tokstr = xstrdup(redirect_protocols);
++ for (proto = strtok_r(tokstr, ",", &save_ptr); proto != NULL;
++ proto = strtok_r(NULL, ",", &save_ptr)) {
++ if (!strcmp(proto, "BGP")) {
++ redirected_protocol_flags |= REDIRECT_BGP;
++ continue;
++ }
++
++ if (!strcmp(proto, "BFD")) {
++ redirected_protocol_flags |= REDIRECT_BFD;
++ continue;
++ }
++
++ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
++ VLOG_WARN_RL(&rl, "Option 'routing-protocols' encountered unknown "
++ "value %s",
++ proto);
++ }
++ free(tokstr);
++ return redirected_protocol_flags;
++}
++
++static void
++build_lrouter_routing_protocol_redirect(
++ struct ovn_port *op, struct lflow_table *lflows, struct ds *match,
++ struct ds *actions, struct lflow_ref *lflow_ref,
++ const struct hmap *ls_ports)
++{
++ /* LRP has to have a peer.*/
++ if (!op->peer) {
++ return;
++ }
++
++ /* LRP has to have NB record.*/
++ if (!op->nbrp) {
++ return;
++ }
++
++ /* Proceed only for LRPs that have 'routing-protocol-redirect' option set.
++ * Value of this option is the name of LSP to which the routing protocol
++ * traffic will be redirected. */
++ const char *redirect_port_name = smap_get(&op->nbrp->options,
++ "routing-protocol-redirect");
++ if (!redirect_port_name) {
++ return;
++ }
++
++ if (op->cr_port) {
++ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
++ VLOG_WARN_RL(&rl, "Option 'routing-protocol-redirect' is not "
++ "supported on Distributed Gateway Port '%s'",
++ op->key);
++ return;
++ }
++
++ /* Ensure that LSP, to which the routing protocol traffic is redirected,
++ * exists. */
++ struct ovn_port *lsp_in_peer = ovn_port_find(ls_ports,
++ redirect_port_name);
++ if (!lsp_in_peer) {
++ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
++ VLOG_WARN_RL(&rl, "Option 'routing-protocol-redirect' set on Logical "
++ "Router Port '%s' refers to non-existent Logical "
++ "Switch Port. Routing protocol redirecting won't be "
++ "configured.",
++ op->key);
++ return;
++ }
++ if (lsp_in_peer->od != op->peer->od) {
++ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
++ VLOG_WARN_RL(&rl, "Logical Router Port '%s' is connected to a "
++ "different switch than the Logical Switch Port "
++ "'%s' defined in its 'routing-protocol-redirect' "
++ "option. Routing protocol redirecting won't be "
++ "configured.",
++ op->key, redirect_port_name);
++ return;
++ }
++
++ int redirected_protocols = parse_redirected_routing_protocols(op);
++ if (!redirected_protocols) {
++ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
++ VLOG_WARN_RL(&rl, "Option 'routing-protocol-redirect' is set on "
++ "Logical Router Port '%s' but no known protocols "
++ "were set via 'routing-protocols' options. This "
++ "configuration has no effect.",
++ op->key);
++ return;
++ }
++
++ /* Redirect traffic destined for LRP's IPs and the specified routing
++ * protocol ports to the port defined in 'routing-protocol-redirect'
++ * option.*/
++ for (size_t i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) {
++ const char *ip_s = op->lrp_networks.ipv4_addrs[i].addr_s;
++ apply_routing_protocols_redirect__(ip_s, redirect_port_name,
++ redirected_protocols, false,
++ op->peer, lflows, match, actions,
++ lflow_ref);
++ }
++ for (size_t i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) {
++ const char *ip_s = op->lrp_networks.ipv6_addrs[i].addr_s;
++ apply_routing_protocols_redirect__(ip_s, redirect_port_name,
++ redirected_protocols, true,
++ op->peer, lflows, match, actions,
++ lflow_ref);
++ }
++
++ /* Drop ARP replies and IPv6 RA/NA packets originating from
++ * 'routing-protocol-redirect' LSP. As this port shares IP and MAC
++ * addresses with LRP, we don't want to create duplicates.*/
++ ds_clear(match);
++ ds_put_format(match, "inport == \"%s\" && arp.op == 2",
++ redirect_port_name);
++ ovn_lflow_add(lflows, op->peer->od, S_SWITCH_IN_CHECK_PORT_SEC, 80,
++ ds_cstr(match),
++ REGBIT_PORT_SEC_DROP " = 1; next;",
++ lflow_ref);
++
++ ds_clear(match);
++ ds_put_format(match, "inport == \"%s\" && nd_na",
++ redirect_port_name);
++ ovn_lflow_add(lflows, op->peer->od, S_SWITCH_IN_CHECK_PORT_SEC, 80,
++ ds_cstr(match),
++ REGBIT_PORT_SEC_DROP " = 1; next;",
++ lflow_ref);
++
++ ds_clear(match);
++ ds_put_format(match, "inport == \"%s\" && nd_ra",
++ redirect_port_name);
++ ovn_lflow_add(lflows, op->peer->od, S_SWITCH_IN_CHECK_PORT_SEC, 80,
++ ds_cstr(match),
++ REGBIT_PORT_SEC_DROP " = 1; next;",
++ lflow_ref);
++}
++
+ /* This function adds ARP resolve flows related to a LSP. */
+ static void
+ build_arp_resolve_flows_for_lsp(
+@@ -15095,7 +15267,7 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op,
+ struct lflow_table *lflows,
+ struct ds *match, struct ds *actions,
+ const struct shash *meter_groups,
+- const struct hmap *bfd_connections,
++ const struct sset *bfd_ports,
+ struct lflow_ref *lflow_ref)
+ {
+ ovs_assert(op->nbrp);
+@@ -15137,8 +15309,7 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op,
+ }
+
+ /* BFD msg handling */
+- build_lrouter_bfd_flows(lflows, op, meter_groups, bfd_connections,
+- lflow_ref);
++ build_lrouter_bfd_flows(lflows, op, meter_groups, bfd_ports, lflow_ref);
+
+ /* ICMP time exceeded */
+ struct ds ip_ds = DS_EMPTY_INITIALIZER;
+@@ -15824,7 +15995,6 @@ build_lrouter_out_snat_flow(struct lflow_table *lflows,
+ build_lrouter_out_snat_match(lflows, od, nat, match, distributed_nat,
+ cidr_bits, is_v6, l3dgw_port, lflow_ref,
+ false);
+- size_t original_match_len = match->length;
+
+ if (!od->is_gw_router && distributed_nat) {
+ ds_put_format(actions, "eth.src = "ETH_ADDR_FMT"; ",
+@@ -15846,14 +16016,13 @@ build_lrouter_out_snat_flow(struct lflow_table *lflows,
+ /* For the SNAT networks, we need to make sure that connections are
+ * properly tracked so we can decide whether to perform SNAT on traffic
+ * exiting the network. */
+- if (features->ct_commit_to_zone && !strcmp(nat->type, "snat") &&
+- !od->is_gw_router) {
++ if (features->ct_commit_to_zone && features->ct_next_zone &&
++ !strcmp(nat->type, "snat") && !od->is_gw_router) {
+ /* For traffic that comes from SNAT network, initiate CT state before
+ * entering S_ROUTER_OUT_SNAT to allow matching on various CT states.
+ */
+- ds_truncate(match, original_match_len);
+ ovn_lflow_add(lflows, od, S_ROUTER_OUT_POST_UNDNAT, 70,
+- ds_cstr(match), "ct_snat;",
++ ds_cstr(match), "ct_next(snat);",
+ lflow_ref);
+
+ build_lrouter_out_snat_match(lflows, od, nat, match,
+@@ -16116,7 +16285,7 @@ lrouter_check_nat_entry(const struct ovn_datapath *od,
+ *distributed = false;
+
+ /* NAT cannnot be distributed if the DGP's peer
+- * has a chassisresident port (as the routing is centralized
++ * has a chassisredirect port (as the routing is centralized
+ * on the gateway chassis for the DGP's networks/subnets.)
+ */
+ struct ovn_port *l3dgw_port = *nat_l3dgw_port;
+@@ -16591,7 +16760,7 @@ build_lsp_lflows_for_lbnats(struct ovn_port *lsp,
+ static void
+ build_routable_flows_for_router_port(
+ struct ovn_port *lrp, const struct lr_stateful_record *lr_stateful_rec,
+- const struct hmap *bfd_connections,
++ const struct sset *bfd_ports,
+ struct lflow_table *lflows,
+ struct ds *match,
+ struct ds *actions)
+@@ -16628,7 +16797,7 @@ build_routable_flows_for_router_port(
+ router_port->lrp_networks.ipv4_addrs[0].addr_s,
+ laddrs->ipv4_addrs[k].network_s,
+ laddrs->ipv4_addrs[k].plen, NULL, false, 0,
+- bfd_connections, &router_port->nbrp->header_,
++ bfd_ports, &router_port->nbrp->header_,
+ false, ROUTE_PRIO_OFFSET_CONNECTED,
+ lrp->stateful_lflow_ref);
+ }
+@@ -16739,7 +16908,7 @@ build_lrp_lflows_for_lbnats(struct ovn_port *op,
+ static void
+ build_lbnat_lflows_iterate_by_lrp(
+ struct ovn_port *op, const struct lr_stateful_table *lr_stateful_table,
+- const struct shash *meter_groups, const struct hmap *bfd_connections,
++ const struct shash *meter_groups, const struct sset *bfd_ports,
+ struct ds *match, struct ds *actions, struct lflow_table *lflows)
+ {
+ ovs_assert(op->nbrp);
+@@ -16752,7 +16921,7 @@ build_lbnat_lflows_iterate_by_lrp(
+ build_lrp_lflows_for_lbnats(op, lr_stateful_rec, meter_groups, match,
+ actions, lflows);
+
+- build_routable_flows_for_router_port(op, lr_stateful_rec, bfd_connections,
++ build_routable_flows_for_router_port(op, lr_stateful_rec, bfd_ports,
+ lflows, match, actions);
+ }
+
+@@ -16816,7 +16985,7 @@ struct lswitch_flow_build_info {
+ const struct shash *meter_groups;
+ const struct hmap *lb_dps_map;
+ const struct hmap *svc_monitor_map;
+- const struct hmap *bfd_connections;
++ const struct sset *bfd_ports;
+ const struct chassis_features *features;
+ char *svc_check_match;
+ struct ds match;
+@@ -16827,7 +16996,6 @@ struct lswitch_flow_build_info {
+ struct hmap *parsed_routes;
+ struct hmap *route_policies;
+ struct simap *route_tables;
+- struct simap *nexthops_table;
+ };
+
+ /* Helper function to combine all lflow generation which is iterated by
+@@ -16874,8 +17042,7 @@ build_lswitch_and_lrouter_iterate_by_lr(struct ovn_datapath *od,
+ build_ip_routing_pre_flows_for_lrouter(od, lsi->lflows, NULL);
+ build_static_route_flows_for_lrouter(od, lsi->lflows, lsi->lr_ports,
+ lsi->parsed_routes, lsi->route_tables,
+- lsi->bfd_connections, NULL,
+- lsi->nexthops_table);
++ lsi->bfd_ports, NULL);
+ build_mcast_lookup_flows_for_lrouter(od, lsi->lflows, &lsi->match,
+ &lsi->actions, NULL);
+ build_ingress_policy_flows_for_lrouter(od, lsi->lflows, lsi->lr_ports,
+@@ -16946,7 +17113,7 @@ build_lswitch_and_lrouter_iterate_by_lrp(struct ovn_port *op,
+ &lsi->actions, op->lflow_ref);
+ build_neigh_learning_flows_for_lrouter_port(op, lsi->lflows, &lsi->match,
+ &lsi->actions, op->lflow_ref);
+- build_ip_routing_flows_for_lrp(op, lsi->bfd_connections,
++ build_ip_routing_flows_for_lrp(op, lsi->bfd_ports,
+ lsi->lflows, op->lflow_ref);
+ build_ND_RA_flows_for_lrouter_port(op, lsi->lflows, &lsi->match,
+ &lsi->actions, lsi->meter_groups,
+@@ -16965,10 +17132,13 @@ build_lswitch_and_lrouter_iterate_by_lrp(struct ovn_port *op,
+ lsi->meter_groups,
+ op->lflow_ref);
+ build_lrouter_ipv4_ip_input(op, lsi->lflows, &lsi->match, &lsi->actions,
+- lsi->meter_groups, lsi->bfd_connections,
++ lsi->meter_groups, lsi->bfd_ports,
+ op->lflow_ref);
+ build_lrouter_icmp_packet_toobig_admin_flows(op, lsi->lflows, &lsi->match,
+ &lsi->actions, op->lflow_ref);
++ build_lrouter_routing_protocol_redirect(op, lsi->lflows, &lsi->match,
++ &lsi->actions, op->lflow_ref,
++ lsi->ls_ports);
+ }
+
+ static void *
+@@ -17055,7 +17225,7 @@ build_lflows_thread(void *arg)
+ build_lswitch_and_lrouter_iterate_by_lrp(op, lsi);
+ build_lbnat_lflows_iterate_by_lrp(
+ op, lsi->lr_stateful_table, lsi->meter_groups,
+- lsi->bfd_connections, &lsi->match, &lsi->actions,
++ lsi->bfd_ports, &lsi->match, &lsi->actions,
+ lsi->lflows);
+ }
+ }
+@@ -17196,14 +17366,13 @@ build_lswitch_and_lrouter_flows(
+ const struct shash *meter_groups,
+ const struct hmap *lb_dps_map,
+ const struct hmap *svc_monitor_map,
+- const struct hmap *bfd_connections,
++ const struct sset *bfd_ports,
+ const struct chassis_features *features,
+ const char *svc_monitor_mac,
+ const struct sampling_app_table *sampling_apps,
+ struct hmap *parsed_routes,
+ struct hmap *route_policies,
+- struct simap *route_tables,
+- struct simap *nexthops_table)
++ struct simap *route_tables)
+ {
+
+ char *svc_check_match = xasprintf("eth.dst == %s", svc_monitor_mac);
+@@ -17232,7 +17401,7 @@ build_lswitch_and_lrouter_flows(
+ lsiv[index].meter_groups = meter_groups;
+ lsiv[index].lb_dps_map = lb_dps_map;
+ lsiv[index].svc_monitor_map = svc_monitor_map;
+- lsiv[index].bfd_connections = bfd_connections;
++ lsiv[index].bfd_ports = bfd_ports;
+ lsiv[index].features = features;
+ lsiv[index].svc_check_match = svc_check_match;
+ lsiv[index].thread_lflow_counter = 0;
+@@ -17241,7 +17410,6 @@ build_lswitch_and_lrouter_flows(
+ lsiv[index].parsed_routes = parsed_routes;
+ lsiv[index].route_tables = route_tables;
+ lsiv[index].route_policies = route_policies;
+- lsiv[index].nexthops_table = nexthops_table;
+ ds_init(&lsiv[index].match);
+ ds_init(&lsiv[index].actions);
+
+@@ -17278,7 +17446,7 @@ build_lswitch_and_lrouter_flows(
+ .meter_groups = meter_groups,
+ .lb_dps_map = lb_dps_map,
+ .svc_monitor_map = svc_monitor_map,
+- .bfd_connections = bfd_connections,
++ .bfd_ports = bfd_ports,
+ .features = features,
+ .svc_check_match = svc_check_match,
+ .svc_monitor_mac = svc_monitor_mac,
+@@ -17288,7 +17456,6 @@ build_lswitch_and_lrouter_flows(
+ .route_policies = route_policies,
+ .match = DS_EMPTY_INITIALIZER,
+ .actions = DS_EMPTY_INITIALIZER,
+- .nexthops_table = nexthops_table,
+ };
+
+ /* Combined build - all lflow generation from lswitch and lrouter
+@@ -17318,7 +17485,7 @@ build_lswitch_and_lrouter_flows(
+ build_lswitch_and_lrouter_iterate_by_lrp(op, &lsi);
+ build_lbnat_lflows_iterate_by_lrp(op, lsi.lr_stateful_table,
+ lsi.meter_groups,
+- lsi.bfd_connections,
++ lsi.bfd_ports,
+ &lsi.match,
+ &lsi.actions,
+ lsi.lflows);
+@@ -17449,14 +17616,13 @@ void build_lflows(struct ovsdb_idl_txn *ovnsb_txn,
+ input_data->meter_groups,
+ input_data->lb_datapaths_map,
+ input_data->svc_monitor_map,
+- input_data->bfd_connections,
++ input_data->bfd_ports,
+ input_data->features,
+ input_data->svc_monitor_mac,
+ input_data->sampling_apps,
+ input_data->parsed_routes,
+ input_data->route_policies,
+- input_data->route_tables,
+- input_data->nexthops_table);
++ input_data->route_tables);
+
+ if (parallelization_state == STATE_INIT_HASH_SIZES) {
+ parallelization_state = STATE_USE_PARALLELIZATION;
+@@ -17818,7 +17984,7 @@ lflow_handle_lr_stateful_changes(struct ovsdb_idl_txn *ovnsb_txn,
+ build_lbnat_lflows_iterate_by_lrp(op,
+ lflow_input->lr_stateful_table,
+ lflow_input->meter_groups,
+- lflow_input->bfd_connections,
++ lflow_input->bfd_ports,
+ &match, &actions,
+ lflows);
+
+@@ -18409,7 +18575,8 @@ build_static_mac_binding_table(
+ struct hmap *lr_ports)
+ {
+ /* Cleanup SB Static_MAC_Binding entries which do not have corresponding
+- * NB Static_MAC_Binding entries. */
++ * NB Static_MAC_Binding entries, and SB Static_MAC_Binding entries for
++ * which there is not a NB Logical_Router_Port of the same name. */
+ const struct nbrec_static_mac_binding *nb_smb;
+ const struct sbrec_static_mac_binding *sb_smb;
+ SBREC_STATIC_MAC_BINDING_TABLE_FOR_EACH_SAFE (sb_smb,
+@@ -18419,6 +18586,12 @@ build_static_mac_binding_table(
+ sb_smb->ip);
+ if (!nb_smb) {
+ sbrec_static_mac_binding_delete(sb_smb);
++ continue;
++ }
++
++ struct ovn_port *op = ovn_port_find(lr_ports, nb_smb->logical_port);
++ if (!op || !op->nbrp || !op->od || !op->od->sb) {
++ sbrec_static_mac_binding_delete(sb_smb);
+ }
+ }
+
+@@ -18554,9 +18727,9 @@ bfd_init(struct bfd_data *data)
+ }
+
+ void
+-ecmp_nexthop_init(struct ecmp_nexthop_data *data)
++bfd_sync_init(struct bfd_sync_data *data)
+ {
+- simap_init(&data->nexthops);
++ sset_init(&data->bfd_ports);
+ }
+
+ void
+@@ -18615,6 +18788,12 @@ bfd_destroy(struct bfd_data *data)
+ __bfd_destroy(&data->bfd_connections);
+ }
+
++void
++bfd_sync_destroy(struct bfd_sync_data *data)
++{
++ sset_destroy(&data->bfd_ports);
++}
++
+ void
+ route_policies_destroy(struct route_policies_data *data)
+ {
+@@ -18640,12 +18819,6 @@ static_routes_destroy(struct static_routes_data *data)
+ __bfd_destroy(&data->bfd_active_connections);
+ }
+
+-void
+-ecmp_nexthop_destroy(struct ecmp_nexthop_data *data)
+-{
+- simap_destroy(&data->nexthops);
+-}
+-
+ void
+ ovnnb_db_run(struct northd_input *input_data,
+ struct northd_data *data,
+diff --git a/northd/northd.h b/northd/northd.h
+index 6e0258ff4..8f76d642d 100644
+--- a/northd/northd.h
++++ b/northd/northd.h
+@@ -93,6 +93,13 @@ ovn_datapath_find_by_key(struct hmap *datapaths, uint32_t dp_key);
+
+ bool od_has_lb_vip(const struct ovn_datapath *od);
+
++/* List of routing and routing-related protocols which
++ * OVN is capable of redirecting from LRP to specific LSP. */
++enum redirected_routing_protcol_flag_type {
++ REDIRECT_BGP = (1 << 0),
++ REDIRECT_BFD = (1 << 1),
++};
++
+ struct tracked_ovn_ports {
+ /* tracked created ports.
+ * hmapx node data is 'struct ovn_port *' */
+@@ -188,8 +195,8 @@ struct bfd_data {
+ struct hmap bfd_connections;
+ };
+
+-struct ecmp_nexthop_data {
+- struct simap nexthops;
++struct bfd_sync_data {
++ struct sset bfd_ports;
+ };
+
+ struct lr_nat_table;
+@@ -213,7 +220,7 @@ struct lflow_input {
+ const struct ls_stateful_table *ls_stateful_table;
+ const struct shash *meter_groups;
+ const struct hmap *lb_datapaths_map;
+- const struct hmap *bfd_connections;
++ const struct sset *bfd_ports;
+ const struct chassis_features *features;
+ const struct hmap *svc_monitor_map;
+ bool ovn_internal_version_changed;
+@@ -222,7 +229,6 @@ struct lflow_input {
+ struct hmap *parsed_routes;
+ struct hmap *route_policies;
+ struct simap *route_tables;
+- struct simap *nexthops_table;
+ };
+
+ extern int parallelization_state;
+@@ -727,7 +733,7 @@ void northd_indices_create(struct northd_data *data,
+ void route_policies_init(struct route_policies_data *);
+ void route_policies_destroy(struct route_policies_data *);
+ void build_parsed_routes(struct ovn_datapath *, const struct hmap *,
+- struct hmap *, struct hmap *, struct simap *,
++ const struct hmap *, struct hmap *, struct simap *,
+ struct hmap *);
+ uint32_t get_route_table_id(struct simap *, const char *);
+ void static_routes_init(struct static_routes_data *);
+@@ -736,11 +742,8 @@ void static_routes_destroy(struct static_routes_data *);
+ void bfd_init(struct bfd_data *);
+ void bfd_destroy(struct bfd_data *);
+
+-void build_ecmp_nexthop_table(struct ovsdb_idl_txn *,
+- struct hmap *, struct simap *,
+- const struct sbrec_ecmp_nexthop_table *);
+-void ecmp_nexthop_init(struct ecmp_nexthop_data *);
+-void ecmp_nexthop_destroy(struct ecmp_nexthop_data *);
++void bfd_sync_init(struct bfd_sync_data *);
++void bfd_sync_destroy(struct bfd_sync_data *);
+
+ struct lflow_table;
+ struct lr_stateful_tracked_data;
+@@ -783,7 +786,8 @@ void build_route_policies(struct ovn_datapath *, const struct hmap *,
+ const struct hmap *, struct hmap *, struct hmap *);
+ void bfd_table_sync(struct ovsdb_idl_txn *, const struct nbrec_bfd_table *,
+ const struct hmap *, const struct hmap *,
+- const struct hmap *, const struct hmap *, struct hmap *);
++ const struct hmap *, const struct hmap *,
++ struct sset *);
+ void build_bfd_map(const struct nbrec_bfd_table *,
+ const struct sbrec_bfd_table *, struct hmap *);
+ void run_update_worker_pool(int n_threads);
+diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
+index 3abd5f75b..ef5cd0c8c 100644
+--- a/northd/ovn-northd.8.xml
++++ b/northd/ovn-northd.8.xml
+@@ -284,6 +284,32 @@
+ dropped in the next stage.
+
+
++
++
++ For each logical port that's defined as a target of routing protocol
++ redirecting (via routing-protocol-redirect
option set on
++ Logical Router Port), a filter is set in place that disallows
++ following traffic exiting this port:
++
++
++ -
++ ARP replies
++
++ -
++ IPv6 Neighbor Discovery - Router Advertisements
++
++ -
++ IPv6 Neighbor Discovery - Neighbor Advertisements
++
++
++
++ Since this port shares IP and MAC addresses with the Logical Router
++ Port, we wan't to prevent duplicate replies and advertisements. This
++ is achieved by a rule with priority 80 that sets
++ REGBIT_PORT_SEC_DROP" = 1; next;"
.
++
++
++
+
+ For each (enabled) vtep logical port, a priority 70 flow is added which
+ matches on all packets and applies the action
+@@ -2002,6 +2028,34 @@ output;
+ on the logical switch.
+
+
++
++
++ For any logical port that's defined as a target of routing protocol
++ redirecting (via routing-protocol-redirect
option set on
++ Logical Router Port), we redirect the traffic related to protocols
++ specified in routing-protocols
option. It's acoomplished
++ with following priority-100 flows:
++
++
++ -
++ Flows that match Logical Router Port's IPs and destination port of
++ the routing daemon are redirected to this port to allow external
++ peers' connection to the daemon listening on this port.
++
++ -
++ Flows that match Logical Router Port's IPs and source port of
++ the routing daemon are redirected to this port to allow replies
++ from the peers.
++
++
++
++ In addition to this, we add priority-100 rules that
++ clone
ARP replies and IPv6 Neighbor Advertisements to
++ this port as well. These allow to build proper ARP/IPv6 neighbor
++ list on this port.
++
++
++
+
+ Priority-90 flows for transit switches that forward registered
+ IP multicast traffic to their corresponding multicast group , which
+@@ -4274,7 +4328,18 @@ next;
+ ip.ttl--;
+ flags.loopback = 1;
+ reg8[0..15] = GID;
+-select(reg8[16..31], MID1, MID2, ...);
++reg8[16..31] = select(MID1, MID2, ...);
++
++
++ However, when there is only one route in an ECMP group, group actions
++ will be:
++
++
++
++ip.ttl--;
++flags.loopback = 1;
++reg8[0..15] = GID;
++reg8[16..31] = MID1);
+
+
+
+diff --git a/ovn-nb.xml b/ovn-nb.xml
+index bbda423a5..2836f58f5 100644
+--- a/ovn-nb.xml
++++ b/ovn-nb.xml
+@@ -3575,6 +3575,48 @@ or
+
+
+
++
++
++ NOTE: this feature is experimental and may be subject to
++ removal/change in the future.
++
++
++ This option expects a name of a Logical Switch Port that's present
++ in the peer's Logical Switch. If set, it causes any traffic
++ that's destined for Logical Router Port's IP addresses (including
++ its IPv6 LLA) and the ports associated with routing protocols defined
++ ip routing-protocols
option, to be redirected
++ to the specified Logical Switch Port.
++
++ This allows external routing daemons to be bound to a port in OVN's
++ Logical Switch and act as if they were listening on Logical Router
++ Port's IP addresses.
++
++
++
++
++
++ NOTE: this feature is experimental and may be subject to
++ removal/change in the future.
++
++
++ This option expects a comma-separated list of routing, and
++ routing-related protocols, whose control plane traffic will be
++ redirected to a port specified in
++ routing-protocol-redirect
option. Currently supported
++ options are:
++
++
++ -
++
BGP
(forwards TCP port 179)
++
++ -
++
BFD
(forwards UDP port 3784)
++
++
++
++
+
+
+ When configured, represents a match expression, in the same
+diff --git a/ovn-sb.ovsschema b/ovn-sb.ovsschema
+index 9d8e0ac46..73abf2c8d 100644
+--- a/ovn-sb.ovsschema
++++ b/ovn-sb.ovsschema
+@@ -1,7 +1,7 @@
+ {
+ "name": "OVN_Southbound",
+- "version": "20.36.0",
+- "cksum": "1845967275 32154",
++ "version": "20.37.0",
++ "cksum": "1950136776 31493",
+ "tables": {
+ "SB_Global": {
+ "columns": {
+@@ -610,20 +610,6 @@
+ "refTable": "Datapath_Binding"}}}},
+ "indexes": [["logical_port", "ip"]],
+ "isRoot": true},
+- "ECMP_Nexthop": {
+- "columns": {
+- "nexthop": {"type": "string"},
+- "id": {"type": {"key": {"type": "integer",
+- "minInteger": 0,
+- "maxInteger": 65535}}},
+- "external_ids": {
+- "type": {"key": "string", "value": "string",
+- "min": 0, "max": "unlimited"}},
+- "options": {
+- "type": {"key": "string", "value": "string",
+- "min": 0, "max": "unlimited"}}},
+- "indexes": [["nexthop"]],
+- "isRoot": true},
+ "Chassis_Template_Var": {
+ "columns": {
+ "chassis": {"type": "string"},
+diff --git a/ovn-sb.xml b/ovn-sb.xml
+index de0bd636f..5285cae30 100644
+--- a/ovn-sb.xml
++++ b/ovn-sb.xml
+@@ -1146,6 +1146,7 @@
+
+ eth.bcast
expands to eth.dst == ff:ff:ff:ff:ff:ff
+ eth.mcast
expands to eth.dst[40]
++ eth.mcastv6
expands to eth.dst[32..47] == 0x3333
+ vlan.present
expands to vlan.tci[12]
+ ip4
expands to eth.type == 0x800
+ ip4.src_mcast
expands to
+@@ -1161,8 +1162,10 @@
+ ip.first_frag
expands to ip.is_frag && !ip.later_frag
+ arp
expands to eth.type == 0x806
+ rarp
expands to eth.type == 0x8035
++ ip6.mcast
expands to eth.mcastv6 && ip6.dst[120..127] == 0xff
+ nd
expands to icmp6.type == {135, 136} && icmp6.code == 0 && ip.ttl == 255
+ nd_ns
expands to icmp6.type == 135 && icmp6.code == 0 && ip.ttl == 255
++ nd_ns_mcast
expands to ip6.mcast && icmp6.type == 135 && icmp6.code == 0 && ip.ttl == 255
+ nd_na
expands to icmp6.type == 136 && icmp6.code == 0 && ip.ttl == 255
+ nd_rs
expands to icmp6.type == 133 &&
+ icmp6.code == 0 && ip.ttl == 255
+@@ -1366,6 +1369,8 @@
+
+
+ ct_next;
++ ct_next(dnat);
++ ct_next(snat);
+ -
+
+ Apply connection tracking to the flow, initializing
+@@ -5175,35 +5180,4 @@ tcp.flags = RST;
+ The set of variable values for a given chassis.
+
+
+-
+-
+-
+- Each record in this table represents an active ECMP route committed by
+- ovn-northd
to ovs
connection-tracking table.
+- ECMP_Nexthop
table is used by ovn-controller
+- to track active ct entries and to flush stale ones.
+-
+-
+-
+- Nexthop IP address for this ECMP route. Nexthop IP address should
+- be the IP address of a connected router port or the IP address of
+- an external device used as nexthop for the given destination.
+-
+-
+-
+-
+-
+- Nexthop unique identifier. Nexthop ID is used to track active
+- ecmp-symmetric-reply connections and flush stale ones.
+-
+-
+-
+-
+- Reserved for future use.
+-
+-
+-
+- See External IDs at the beginning of this document.
+-
+-
+
+diff --git a/tests/multinode.at b/tests/multinode.at
+index a04ce7597..a0eb8fc67 100644
+--- a/tests/multinode.at
++++ b/tests/multinode.at
+@@ -1062,6 +1062,10 @@ check_fake_multinode_setup
+ # Delete the multinode NB and OVS resources before starting the test.
+ cleanup_multinode_resources
+
++m_as ovn-chassis-1 ip link del sw0p1-p
++m_as ovn-chassis-2 ip link del sw0p2-p
++m_as ovn-chassis-2 ip link del sw1p1-p
++
+ check multinode_nbctl ls-add sw0
+ check multinode_nbctl lsp-add sw0 sw0-port1
+ check multinode_nbctl lsp-set-addresses sw0-port1 "50:54:00:00:00:03 10.0.0.3 1000::3"
+diff --git a/tests/ovn-controller.at b/tests/ovn-controller.at
+index dcab5f2e9..a2e451880 100644
+--- a/tests/ovn-controller.at
++++ b/tests/ovn-controller.at
+@@ -3140,62 +3140,116 @@ ovn_start
+
+ check_ct_zone_min() {
+ min_val=$1
+- OVS_WAIT_UNTIL([test $(ovn-appctl -t ovn-controller ct-zone-list | awk '{print $2}' | sort | head -n1) -ge ${min_val}])
++ OVS_WAIT_UNTIL([test $(ovn-appctl -t ovn-controller ct-zone-list | awk '{printf "%02d\n", $2}' | sort | head -n1) -ge ${min_val}])
+ }
+
+ check_ct_zone_max() {
+ max_val=$1
+- AT_CHECK([test $(ovn-appctl -t ovn-controller ct-zone-list | awk '{print $2}' | sort | tail -n1) -le ${max_val}])
++ OVS_WAIT_UNTIL([test $(ovn-appctl -t ovn-controller ct-zone-list | awk '{printf "%02d\n", $2}' | sort | tail -n1) -le ${max_val}])
+ }
+
+ net_add n1
+ sim_add hv1
+ as hv1
+ check ovs-vsctl add-br br-phys
++check ovs-appctl vlog/disable-rate-limit
++check ovs-appctl vlog/set vconn:DBG
++
+ ovn_attach n1 br-phys 192.168.0.1
+
+ check ovn-appctl -t ovn-controller vlog/set dbg:ct_zone
+
+ check ovs-vsctl add-port br-int lsp0 \
+ -- set Interface lsp0 external-ids:iface-id=lsp0
++check ovs-vsctl add-port br-int lsp1 \
++ -- set Interface lsp1 external-ids:iface-id=lsp1
+
+ check ovn-nbctl lr-add lr
++check ovn-nbctl ls-add ls0
++check ovn-nbctl ls-add ls1
+
+-check ovn-nbctl ls-add ls
+-check ovn-nbctl lsp-add ls ls-lr
+-check ovn-nbctl lsp-set-type ls-lr router
+-check ovn-nbctl lsp-set-addresses ls-lr router
+-check ovn-nbctl lrp-add lr lr-ls 00:00:00:00:00:01 10.0.0.1
++check ovn-nbctl set logical_router lr options:chassis=hv1
++
++check ovn-nbctl lrp-add lr lr-ls0 00:00:00:00:ff:01 10.0.0.1/24
++check ovn-nbctl lsp-add ls0 ls0-lr
++check ovn-nbctl lsp-set-type ls0-lr router
++check ovn-nbctl lsp-set-addresses ls0-lr 00:00:00:00:ff:01
++check ovn-nbctl lsp-set-options ls0-lr router-port=lr-ls0
+
+-check ovn-nbctl lsp-add ls lsp0
++check ovn-nbctl lsp-add ls0 lsp0
+ check ovn-nbctl lsp-set-addresses lsp0 "00:00:00:00:00:02 10.0.0.2"
+
+-check ovn-nbctl lrp-add lr lrp-gw 01:00:00:00:00:01 172.16.0.1
+-check ovn-nbctl lrp-set-gateway-chassis lrp-gw hv1
++check ovn-nbctl lrp-add lr lr-ls1 00:00:00:00:ff:02 172.16.0.1/24
++check ovn-nbctl lsp-add ls1 ls1-lr
++check ovn-nbctl lsp-set-type ls1-lr router
++check ovn-nbctl lsp-set-addresses ls1-lr 00:00:00:00:ff:02
++check ovn-nbctl lsp-set-options ls1-lr router-port=lr-ls1
+
+-# check regular boundaries
++check ovn-nbctl lsp-add ls1 lsp1
++check ovn-nbctl lsp-set-addresses lsp1 "00:00:00:00:00:02 172.16.0.2"
++wait_for_ports_up
++check ovn-nbctl --wait=hv sync
++
++AS_BOX([Check regular boundaries])
+ check_ct_zone_min 1
+-check_ct_zone_max 10
++check_ct_zone_max 12
++
++AS_BOX([Increase boundaries])
++ovs-vsctl set Open_vSwitch . external_ids:ct-zone-range=\"10-30\"
+
+-# increase boundaries
+-ovs-vsctl set Open_vSwitch . external_ids:ct-zone-range=\"10-20\"
+ check_ct_zone_min 10
+-check_ct_zone_max 20
++check_ct_zone_max 22
+
+-# reset min boundary
+-ovs-vsctl set Open_vSwitch . external_ids:ct-zone-range=\"5-20\"
++AS_BOX([Reset min boundary])
++check ovs-vsctl set Open_vSwitch . external_ids:ct-zone-range=\"5-30\"
+
+-# add a new port to the switch
+-check ovs-vsctl add-port br-int lsp1 \
+- -- set Interface lsp1 external-ids:iface-id=lsp1
+-check ovn-nbctl lsp-add ls lsp1
+-check ovn-nbctl lsp-set-addresses lsp1 "00:00:00:00:00:03 10.0.0.3"
++# Add a new port to the ls0 switch
++check ovs-vsctl add-port br-int lsp2 \
++ -- set Interface lsp2 external-ids:iface-id=lsp2
++check ovn-nbctl lsp-add ls0 lsp2
++check ovn-nbctl lsp-set-addresses lsp2 "00:00:00:00:00:03 10.0.0.3"
+ check_ct_zone_min 5
+-check_ct_zone_max 20
++check_ct_zone_max 22
+
+ check ovn-nbctl set logical_router lr options:snat-ct-zone=2
++wait_for_ports_up
++check ovn-nbctl --wait=hv sync
++
+ check_ct_zone_min 2
+-check_ct_zone_max 20
++check_ct_zone_max 22
++
++AS_BOX([Check LR snat requested zone 2])
++AT_CHECK([test $(ovn-appctl -t ovn-controller ct-zone-list | awk '/lr_snat/{print $2}') -eq 2])
++
++n_flush=$(grep -c -i flush hv1/ovs-vswitchd.log)
++check ovn-appctl -t ovn-controller exit --restart
++# Make sure ovn-controller stopped before restarting it
++OVS_WAIT_UNTIL([test "$(ovn-appctl -t ovn-controller debug/status)" != "running"])
++start_daemon ovn-controller --verbose="ct_zone:dbg"
++wait_for_ports_up
++check ovn-nbctl --wait=hv sync
++
++# Check we do not have unexpected ct-flush restarting ovn-controller
++AT_CHECK([test $(grep -c -i flush hv1/ovs-vswitchd.log) -eq ${n_flush}])
++
++AS_BOX([Check LR snat allowed requested zone 0])
++check ovn-nbctl set logical_router lr options:snat-ct-zone=0
++check ovn-nbctl --wait=hv sync
++
++check_ct_zone_min 0
++check_ct_zone_max 22
++AT_CHECK([test $(ovn-appctl -t ovn-controller ct-zone-list | awk '/lr_snat/{print $2}') -eq 0])
++
++n_flush=$(grep -c -i flush hv1/ovs-vswitchd.log)
++check ovn-appctl -t ovn-controller exit --restart
++# Make sure ovn-controller stopped before restarting it
++OVS_WAIT_UNTIL([test "$(ovn-appctl -t ovn-controller debug/status)" != "running"])
++start_daemon ovn-controller --verbose="ct_zone:dbg"
++wait_for_ports_up
++check ovn-nbctl --wait=hv sync
++
++# Check we do not have unexpected ct-flush restarting ovn-controller
++AT_CHECK([test $(grep -c -i flush hv1/ovs-vswitchd.log) -eq ${n_flush}])
+
+ OVN_CLEANUP([hv1])
+ AT_CLEANUP
+diff --git a/tests/ovn-ic.at b/tests/ovn-ic.at
+index 8497cb194..9fa41200e 100644
+--- a/tests/ovn-ic.at
++++ b/tests/ovn-ic.at
+@@ -173,7 +173,7 @@ done
+ create_ic_infra() {
+ az_id=$1
+ ts_id=$2
+- az=az$i
++ az=az$1
+
+ lsp=lsp${az_id}-${ts_id}
+ lrp=lrp${az_id}-${ts_id}
+@@ -184,7 +184,7 @@ create_ic_infra() {
+
+ check ovn-ic-nbctl --wait=sb ts-add $ts
+ check ovn-nbctl lr-add $lr
+- check ovn-nbctl lrp-add $lr $lrp 00:00:00:00:00:0$az_id 10.0.$az_id.1/24
++ check ovn-nbctl --wait=sb lrp-add $lr $lrp 00:00:00:00:00:0$az_id 10.0.$az_id.1/24
+ check ovn-nbctl lrp-set-gateway-chassis $lrp gw-$az
+
+ check ovn-nbctl lsp-add $ts $lsp -- \
+@@ -192,7 +192,7 @@ create_ic_infra() {
+ lsp-set-type $lsp router -- \
+ lsp-set-options $lsp router-port=$lrp
+
+- check ovn-nbctl lr-route-add $lr 192.168.0.0/16 10.0.$az_id.10
++ check ovn-nbctl --wait=sb lr-route-add $lr 192.168.0.0/16 10.0.$az_id.10
+ }
+
+ create_ic_infra 1 1
+@@ -209,7 +209,7 @@ check_row_count ic-sb:Route 3 ip_prefix=192.168.0.0/16
+ check ovn-ic-nbctl --wait=sb ts-del ts1-1
+ ovn-ic-sbctl list route
+ ovn-ic-nbctl list transit_switch
+-checl_row_count ic-sb:route 2 ip_prefix=192.168.0.0/16
++check_row_count ic-sb:route 2 ip_prefix=192.168.0.0/16
+ ovn-ic-sbctl list route
+
+ for i in 1 2; do
+@@ -255,7 +255,7 @@ for i in 1 2; do
+ check ovn-nbctl lrp-add lr1 lrp$i 00:00:00:00:0$i:01 10.0.$i.1/24
+ check ovn-nbctl lrp-set-gateway-chassis lrp$i gw-az$i
+
+- check ovn-nbctl lsp-add ts1 lsp$i -- \
++ check ovn-nbctl --wait=sb lsp-add ts1 lsp$i -- \
+ lsp-set-addresses lsp$i router -- \
+ lsp-set-type lsp$i router -- \
+ lsp-set-options lsp$i router-port=lrp$i
+@@ -263,13 +263,11 @@ done
+
+ ovn_as az1
+
+-ovn-nbctl \
+- --id=@id create logical-router-static-route ip_prefix=1.1.1.1/32 nexthop=10.0.1.10 -- \
+- add logical-router lr1 static_routes @id
+ ovn-nbctl \
+ --id=@id create logical-router-static-route ip_prefix=1.1.1.1/32 nexthop=10.0.1.10 -- \
+ add logical-router lr1 static_routes @id
+
++check ovn-ic-nbctl --wait=sb sync
+ check ovn-ic-nbctl --wait=sb sync
+ check_row_count ic-sb:route 1 ip_prefix=1.1.1.1/32
+
+@@ -455,6 +453,7 @@ Route Table :
+ # Delete route in AZ1, AZ2's learned route should be deleted.
+ ovn_as az1 ovn-nbctl lr-route-del lr1 10.11.1.0/24
+ ovn-ic-nbctl --wait=sb sync
++ovn-ic-nbctl --wait=sb sync
+ AT_CHECK([ovn_as az2 ovn-nbctl lr-route-list lr2 | grep -c learned], [1], [dnl
+ 0
+ ])
+@@ -462,6 +461,7 @@ AT_CHECK([ovn_as az2 ovn-nbctl lr-route-list lr2 | grep -c learned], [1], [dnl
+ # Add the route back
+ ovn_as az1 ovn-nbctl lr-route-add lr1 10.11.1.0/24 169.254.0.1
+ ovn-ic-nbctl --wait=sb sync
++ovn-ic-nbctl --wait=sb sync
+ AT_CHECK([ovn_as az2 ovn-nbctl lr-route-list lr2 | grep -c learned], [0], [dnl
+ 1
+ ])
+@@ -485,6 +485,7 @@ ovn_as az1 ovn-nbctl set nb_global . options:ic-route-adv=false
+ # AZ2 shouldn't have the route learned, because AZ1 should have stopped
+ # advertising.
+ check ovn-ic-nbctl --wait=sb sync
++check ovn-ic-nbctl --wait=sb sync
+ AT_CHECK([ovn_as az2 ovn-nbctl lr-route-list lr2], [0], [dnl
+ IPv4 Routes
+ Route Table :
+@@ -499,6 +500,7 @@ ovn_as az1 ovn-nbctl lr-route-add lr1 0.0.0.0/0 169.254.0.3
+ ovn_as az1 ovn-nbctl set nb_global . options:ic-route-adv=true
+ ovn_as az1 ovn-nbctl set nb_global . options:ic-route-learn=true
+ check ovn-ic-nbctl --wait=sb sync
++check ovn-ic-nbctl --wait=sb sync
+
+ # Default route should NOT get advertised or learned, by default.
+ AT_CHECK([ovn_as az2 ovn-nbctl lr-route-list lr2], [0], [dnl
+@@ -576,7 +578,7 @@ for i in 1 2; do
+ done
+
+ # Create directly-connected routes
+-ovn_as az2 ovn-nbctl lrp-add lr12 lrp-lr12-ls2 aa:aa:aa:aa:bb:01 "192.168.0.1/24"
++ovn_as az2 ovn-nbctl --wait=sb lrp-add lr12 lrp-lr12-ls2 aa:aa:aa:aa:bb:01 "192.168.0.1/24"
+ ovn_as az2 ovn-nbctl lr-route-add lr12 10.10.10.0/24 192.168.0.10
+ ovn_as az1 ovn-nbctl --wait=sb sync
+
+@@ -585,6 +587,7 @@ ovn_as az1 ovn-nbctl show
+ echo az2
+ ovn_as az2 ovn-nbctl show
+ check ovn-ic-nbctl --wait=sb sync
++check ovn-ic-nbctl --wait=sb sync
+
+ # Test routes from lr12 were learned to lr11
+ AT_CHECK([ovn_as az1 ovn-nbctl lr-route-list lr11 |
+@@ -626,7 +629,7 @@ for i in 1 2; do
+ ovn-nbctl lrp-add lr$i lrp-lr$i-p$i 00:00:00:00:00:0$i 192.168.$i.1/24
+
+ # Create static routes
+- ovn-nbctl lr-route-add lr$i 10.11.$i.0/24 169.254.0.1
++ ovn-nbctl --wait=sb lr-route-add lr$i 10.11.$i.0/24 169.254.0.1
+
+ # Create a src-ip route, which shouldn't be synced
+ ovn-nbctl --policy=src-ip lr-route-add lr$i 10.22.$i.0/24 169.254.0.2
+@@ -665,7 +668,6 @@ ovn-ic-nbctl ts-add ts1
+ for i in 1 2; do
+ ovn_start az$i
+ ovn_as az$i
+-
+ # Enable route learning at AZ level
+ ovn-nbctl set nb_global . options:ic-route-learn=true
+ # Enable route advertising at AZ level
+@@ -680,9 +682,10 @@ for i in 1 2; do
+ -- lsp-set-type lsp-ts1-lr$i router \
+ -- lsp-set-options lsp-ts1-lr$i router-port=lrp-lr$i-ts1
+
+- ovn-nbctl lrp-add lr$i lrp-lr$i-p$i 00:00:00:00:00:0$i 2002:db8:1::$i/64
++ ovn-nbctl --wait=sb lrp-add lr$i lrp-lr$i-p$i 00:00:00:00:00:0$i 2002:db8:1::$i/64
+ done
+
++check ovn-ic-nbctl --wait=sb sync
+ check ovn-ic-nbctl --wait=sb sync
+ AT_CHECK([ovn_as az1 ovn-nbctl lr-route-list lr1 | awk '/learned/{print $1, $2}'], [0], [dnl
+ 2002:db8:1::/64 2001:db8:1::2
+@@ -733,6 +736,7 @@ for i in 1 2; do
+ ovn-nbctl --policy=src-ip --route-table=rtb1 lr-route-add lr$i 10.22.$i.0/24 169.254.0.2
+ done
+
++check ovn-ic-nbctl --wait=sb sync
+ check ovn-ic-nbctl --wait=sb sync
+ AT_CHECK([ovn_as az1 ovn-nbctl lr-route-list lr1], [0], [dnl
+ IPv4 Routes
+@@ -750,6 +754,7 @@ for i in 1 2; do
+ ovn_as az$i ovn-nbctl --route-table=rtb1 lr-route-add lr$i 10.11.$i.0/24 169.254.0.1
+ done
+
++check ovn-ic-nbctl --wait=sb sync
+ check ovn-ic-nbctl --wait=sb sync
+ # ensure route from rtb1 is not learned to any route table as route table is
+ # not set to TS port
+@@ -975,6 +980,7 @@ ovn_as az2 ovn-nbctl --route-table=rtb3 lr-route-add lr12 10.10.10.0/24 192.168.
+ # Create directly-connected route in VPC2
+ ovn_as az2 ovn-nbctl --wait=sb lrp-add lr22 lrp-lr22 aa:aa:aa:aa:bb:01 "192.168.0.1/24"
+ check ovn-ic-nbctl --wait=sb sync
++check ovn-ic-nbctl --wait=sb sync
+ # Test direct routes from lr12 were learned to lr11
+ OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep 192.168 |
+ grep learned | awk '{print $1, $2, $5}' | sort ], [0], [dnl
+@@ -1102,6 +1108,10 @@ ovn_as az2 ovn-nbctl --route-table=rtb3 lr-route-add lr12 2001:db8:aaaa::/64 200
+ ovn_as az2 ovn-nbctl --wait=sb lrp-add lr22 lrp-lr22 aa:aa:aa:aa:bb:01 "2001:db8:200::1/64"
+
+ # Test direct routes from lr12 were learned to lr11
++#
++# We need to wait twice: first time for az2/ic to handle port addition and update ic/sb and
++# second time for az1/ic to handle ic/sb update.
++check ovn-ic-nbctl --wait=sb sync
+ check ovn-ic-nbctl --wait=sb sync
+ AT_CHECK([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep 2001:db8:200 |
+ grep learned | awk '{print $1, $2, $5}' | sort], [0], [dnl
+@@ -1177,6 +1187,7 @@ for i in 1 2; do
+ check ovn-nbctl --wait=sb lr-route-add $lr 0.0.0.0/0 192.168.$i.11
+ done
+
++check ovn-ic-nbctl --wait=sb sync
+ check ovn-ic-nbctl --wait=sb sync
+ AT_CHECK([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep dst-ip | sort] , [0], [dnl
+ 0.0.0.0/0 192.168.1.11 dst-ip
+@@ -1249,14 +1260,14 @@ for i in 1 2; do
+ -- lsp-set-options $lsp router-port=$lrp
+ done
+
+-
+ # Create directly-connected routes
+ ovn_as az1 ovn-nbctl lrp-add lr11 lrp-lr11 aa:aa:aa:aa:bb:01 "192.168.0.1/24"
+ ovn_as az2 ovn-nbctl lrp-add lr21 lrp-lr21 aa:aa:aa:aa:bc:01 "192.168.1.1/24"
+-ovn_as az2 ovn-nbctl lrp-add lr22 lrp-lr22 aa:aa:aa:aa:bc:02 "192.168.2.1/24"
++ovn_as az2 ovn-nbctl --wait=sb lrp-add lr22 lrp-lr22 aa:aa:aa:aa:bc:02 "192.168.2.1/24"
+
+ # Test direct routes from lr21 and lr22 were learned to lr11
+ check ovn-ic-nbctl --wait=sb sync
++check ovn-ic-nbctl --wait=sb sync
+ AT_CHECK([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep 192.168 |
+ grep learned | awk '{print $1, $2}' | sort ], [0], [dnl
+ 192.168.1.0/24 169.254.10.21
+@@ -1335,7 +1346,6 @@ check ovn-ic-nbctl ts-add ts1
+ for i in 1 2; do
+ ovn_start az$i
+ ovn_as az$i
+-
+ # Enable route learning at AZ level
+ check ovn-nbctl set nb_global . options:ic-route-learn=true
+ # Enable route advertising at AZ level
+@@ -1369,10 +1379,11 @@ for i in 1 2; do
+ 33:33:33:33:33:3$i 2005:1734:5678::$i/50
+
+ # additional not filtered prefix -> different subnet bits
+- check ovn-nbctl lrp-add lr$i lrp-lr$i-p-ext4$i \
++ check ovn-nbctl --wait=sb lrp-add lr$i lrp-lr$i-p-ext4$i \
+ 44:44:44:44:44:4$i 2005:1834:5678::$i/50
+ done
+
++check ovn-ic-nbctl --wait=sb sync
+ check ovn-ic-nbctl --wait=sb sync
+ AT_CHECK([ovn_as az1 ovn-nbctl lr-route-list lr1 |
+ awk '/learned/{print $1, $2}' ], [0], [dnl
+@@ -1387,6 +1398,7 @@ for i in 1 2; do
+ check ovn-nbctl remove nb_global . options ic-route-denylist
+ done
+
++check ovn-ic-nbctl --wait=sb sync
+ check ovn-ic-nbctl --wait=sb sync
+ AT_CHECK([ovn_as az1 ovn-nbctl lr-route-list lr1 |
+ awk '/learned/{print $1, $2}' | sort ], [0], [dnl
+@@ -1750,6 +1762,7 @@ check ovn-nbctl lsp-add ts ts-lr3 \
+
+ wait_for_ports_up
+ check ovn-ic-nbctl --wait=sb sync
++check ovn-ic-nbctl --wait=sb sync
+
+ ovn_as az1
+ check ovn-nbctl lsp-set-options ts-lr2 requested-chassis=hv2
+@@ -1970,6 +1983,7 @@ check ovn-nbctl lsp-add ts ts-lr3 \
+
+ wait_for_ports_up
+ check ovn-ic-nbctl --wait=sb sync
++check ovn-ic-nbctl --wait=sb sync
+ ovn_as az1
+ check ovn-nbctl lsp-set-options ts-lr2 requested-chassis=hv2
+ check ovn-nbctl lsp-set-options ts-lr3 requested-chassis=hv2
+@@ -2223,6 +2237,7 @@ check ovn-nbctl lsp-add ts ts-lr3 \
+
+ wait_for_ports_up
+ check ovn-ic-nbctl --wait=sb sync
++check ovn-ic-nbctl --wait=sb sync
+ ovn_as az1
+ check ovn-nbctl lsp-set-options ts-lr2 requested-chassis=hv2
+ check ovn-nbctl lsp-set-options ts-lr3 requested-chassis=hv2
+diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
+index e4c882265..d6a8c4640 100644
+--- a/tests/ovn-northd.at
++++ b/tests/ovn-northd.at
+@@ -1133,7 +1133,8 @@ ovn_start
+ # DR is connected to S1 and CR is connected to S2
+
+ check ovn-sbctl chassis-add gw1 geneve 127.0.0.1 \
+- -- set chassis gw1 other_config:ct-commit-to-zone="true"
++ -- set chassis gw1 other_config:ct-commit-to-zone="true" \
++ -- set chassis gw1 other_config:ct-next-zone="true"
+
+ check ovn-nbctl lr-add DR
+ check ovn-nbctl lrp-add DR DR-S1 02:ac:10:01:00:01 172.16.1.1/24
+@@ -5721,7 +5722,8 @@ AT_CHECK([grep "lr_out_snat" lr0flows | ovn_strip_lflows], [0], [dnl
+ ])
+
+ check ovn-sbctl chassis-add gw1 geneve 127.0.0.1 \
+- -- set chassis gw1 other_config:ct-commit-to-zone="true"
++ -- set chassis gw1 other_config:ct-commit-to-zone="true" \
++ -- set chassis gw1 other_config:ct-next-zone="true"
+
+ # Create a distributed gw port on lr0
+ check ovn-nbctl ls-add public
+@@ -5822,8 +5824,8 @@ AT_CHECK([grep "lr_out_undnat" lr0flows | ovn_strip_lflows], [0], [dnl
+
+ AT_CHECK([grep "lr_out_post_undnat" lr0flows | ovn_strip_lflows], [0], [dnl
+ table=??(lr_out_post_undnat ), priority=0 , match=(1), action=(next;)
+- table=??(lr_out_post_undnat ), priority=70 , match=(ip && ip4.src == 10.0.0.0/24 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_snat;)
+- table=??(lr_out_post_undnat ), priority=70 , match=(ip && ip4.src == 10.0.0.10 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_snat;)
++ table=??(lr_out_post_undnat ), priority=70 , match=(ip && ip4.src == 10.0.0.0/24 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)), action=(ct_next(snat);)
++ table=??(lr_out_post_undnat ), priority=70 , match=(ip && ip4.src == 10.0.0.10 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)), action=(ct_next(snat);)
+ ])
+
+ AT_CHECK([grep "lr_out_snat" lr0flows | ovn_strip_lflows], [0], [dnl
+@@ -5980,8 +5982,8 @@ AT_CHECK([grep "lr_out_undnat" lr0flows | ovn_strip_lflows], [0], [dnl
+
+ AT_CHECK([grep "lr_out_post_undnat" lr0flows | ovn_strip_lflows], [0], [dnl
+ table=??(lr_out_post_undnat ), priority=0 , match=(1), action=(next;)
+- table=??(lr_out_post_undnat ), priority=70 , match=(ip && ip4.src == 10.0.0.0/24 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_snat;)
+- table=??(lr_out_post_undnat ), priority=70 , match=(ip && ip4.src == 10.0.0.10 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_snat;)
++ table=??(lr_out_post_undnat ), priority=70 , match=(ip && ip4.src == 10.0.0.0/24 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)), action=(ct_next(snat);)
++ table=??(lr_out_post_undnat ), priority=70 , match=(ip && ip4.src == 10.0.0.10 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)), action=(ct_next(snat);)
+ ])
+
+ AT_CHECK([grep "lr_out_snat" lr0flows | ovn_strip_lflows], [0], [dnl
+@@ -6799,26 +6801,27 @@ check ovn-nbctl lsp-set-type public-lr0 router
+ check ovn-nbctl lsp-set-addresses public-lr0 router
+ check ovn-nbctl lsp-set-options public-lr0 router-port=lr0-public
+
++# ECMP flows will be added even if there is only one next-hop.
+ check ovn-nbctl --wait=sb --ecmp-symmetric-reply lr-route-add lr0 1.0.0.1 192.168.0.10
+-check_row_count ECMP_Nexthop 1
+
+ ovn-sbctl dump-flows lr0 > lr0flows
+
+ AT_CHECK([grep -w "lr_in_ip_routing" lr0flows | ovn_strip_lflows], [0], [dnl
+ table=??(lr_in_ip_routing ), priority=0 , match=(1), action=(drop;)
++ table=??(lr_in_ip_routing ), priority=10300, match=(ct_mark.ecmp_reply_port == 1 && reg7 == 0 && ip4.dst == 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; eth.src = 00:00:20:20:12:13; reg1 = 192.168.0.1; outport = "lr0-public"; next;)
+ table=??(lr_in_ip_routing ), priority=10550, match=(nd_rs || nd_ra), action=(drop;)
+ table=??(lr_in_ip_routing ), priority=194 , match=(inport == "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;)
+ table=??(lr_in_ip_routing ), priority=74 , match=(ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;)
+- table=??(lr_in_ip_routing ), priority=97 , match=(reg7 == 0 && ip4.dst == 1.0.0.1/32), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.10; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;)
++ table=??(lr_in_ip_routing ), priority=97 , match=(reg7 == 0 && ip4.dst == 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; reg8[[0..15]] = 1; reg8[[16..31]] = 1; next;)
+ ])
+
+ AT_CHECK([grep -e "lr_in_ip_routing_ecmp" lr0flows | ovn_strip_lflows], [0], [dnl
+ table=??(lr_in_ip_routing_ecmp), priority=0 , match=(1), action=(drop;)
++ table=??(lr_in_ip_routing_ecmp), priority=100 , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = 192.168.0.10; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; next;)
+ table=??(lr_in_ip_routing_ecmp), priority=150 , match=(reg8[[0..15]] == 0), action=(next;)
+ ])
+
+ check ovn-nbctl --wait=sb --ecmp-symmetric-reply lr-route-add lr0 1.0.0.1 192.168.0.20
+-check_row_count ECMP_Nexthop 2
+
+ ovn-sbctl dump-flows lr0 > lr0flows
+ AT_CHECK([grep -w "lr_in_ip_routing" lr0flows | ovn_strip_lflows], [0], [dnl
+@@ -6848,7 +6851,6 @@ AT_CHECK([grep -e "lr_in_arp_resolve.*ecmp" lr0flows | ovn_strip_lflows], [0], [
+
+ # add ecmp route with wrong nexthop
+ check ovn-nbctl --wait=sb --ecmp-symmetric-reply lr-route-add lr0 1.0.0.1 192.168.1.20
+-check_row_count ECMP_Nexthop 2
+
+ ovn-sbctl dump-flows lr0 > lr0flows
+ AT_CHECK([grep -w "lr_in_ip_routing" lr0flows | ovn_strip_lflows], [0], [dnl
+@@ -6868,7 +6870,6 @@ AT_CHECK([grep -e "lr_in_ip_routing_ecmp" lr0flows | sed 's/192\.168\.0\..0/192.
+
+ check ovn-nbctl lr-route-del lr0
+ wait_row_count nb:Logical_Router_Static_Route 0
+-check_row_count ECMP_Nexthop 0
+
+ check ovn-nbctl --wait=sb lr-route-add lr0 1.0.0.0/24 192.168.0.10
+ ovn-sbctl dump-flows lr0 > lr0flows
+@@ -7876,13 +7877,16 @@ ovn_start
+ # distributed gateway LRPs.
+
+ check ovn-sbctl chassis-add gw1 geneve 127.0.0.1 \
+- -- set chassis gw1 other_config:ct-commit-to-zone="true"
++ -- set chassis gw1 other_config:ct-commit-to-zone="true" \
++ -- set chassis gw1 other_config:ct-next-zone="true"
+
+ check ovn-sbctl chassis-add gw2 geneve 128.0.0.1 \
+- -- set chassis gw2 other_config:ct-commit-to-zone="true"
++ -- set chassis gw2 other_config:ct-commit-to-zone="true" \
++ -- set chassis gw2 other_config:ct-next-zone="true"
+
+ check ovn-sbctl chassis-add gw3 geneve 129.0.0.1 \
+- -- set chassis gw3 other_config:ct-commit-to-zone="true"
++ -- set chassis gw3 other_config:ct-commit-to-zone="true" \
++ -- set chassis gw3 other_config:ct-next-zone="true"
+
+ check ovn-nbctl lr-add DR
+ check ovn-nbctl lrp-add DR DR-S1 02:ac:10:01:00:01 172.16.1.1/24
+@@ -8084,6 +8088,19 @@ wait_row_count Static_MAC_Binding 1 logical_port=lr0-p0 ip=192.168.10.100 mac="0
+ AT_CLEANUP
+ ])
+
++OVN_FOR_EACH_NORTHD_NO_HV([
++AT_SETUP([LR NB Static_MAC_Binding garbage collection])
++ovn_start
++
++check ovn-nbctl lr-add lr -- lrp-add lr lr-lrp 00:00:00:00:00:01 1.1.1.1/24
++check ovn-nbctl static-mac-binding-add lr-lrp 1.1.1.2 00:00:00:00:00:02
++wait_row_count sb:Static_MAC_Binding 1 logical_port=lr-lrp ip=1.1.1.2 mac="00\:00\:00\:00\:00\:02"
++check ovn-nbctl lr-del lr
++wait_row_count sb:Static_MAC_Binding 0
++
++AT_CLEANUP
++])
++
+ OVN_FOR_EACH_NORTHD_NO_HV([
+ AT_SETUP([LR neighbor lookup and learning flows])
+ ovn_start
+@@ -9490,9 +9507,9 @@ AT_CAPTURE_FILE([S1flows])
+ AT_CHECK([grep -e "ls_in_arp_rsp" S1flows | ovn_strip_lflows], [0], [dnl
+ table=??(ls_in_arp_rsp ), priority=0 , match=(1), action=(next;)
+ table=??(ls_in_arp_rsp ), priority=100 , match=(arp.tpa == 192.168.0.10 && arp.op == 1 && eth.dst == ff:ff:ff:ff:ff:ff && inport == "S1-vm1"), action=(next;)
+- table=??(ls_in_arp_rsp ), priority=100 , match=(nd_ns && ip6.dst == {fd00::10, ff02::1:ff00:10} && nd.target == fd00::10 && inport == "S1-vm1"), action=(next;)
++ table=??(ls_in_arp_rsp ), priority=100 , match=(nd_ns_mcast && ip6.dst == ff02::1:ff00:10 && nd.target == fd00::10 && inport == "S1-vm1"), action=(next;)
+ table=??(ls_in_arp_rsp ), priority=50 , match=(arp.tpa == 192.168.0.10 && arp.op == 1 && eth.dst == ff:ff:ff:ff:ff:ff), action=(eth.dst = eth.src; eth.src = 50:54:00:00:00:10; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; arp.sha = 50:54:00:00:00:10; arp.tpa = arp.spa; arp.spa = 192.168.0.10; outport = inport; flags.loopback = 1; output;)
+- table=??(ls_in_arp_rsp ), priority=50 , match=(nd_ns && ip6.dst == {fd00::10, ff02::1:ff00:10} && nd.target == fd00::10), action=(nd_na { eth.src = 50:54:00:00:00:10; ip6.src = fd00::10; nd.target = fd00::10; nd.tll = 50:54:00:00:00:10; outport = inport; flags.loopback = 1; output; };)
++ table=??(ls_in_arp_rsp ), priority=50 , match=(nd_ns_mcast && ip6.dst == ff02::1:ff00:10 && nd.target == fd00::10), action=(nd_na { eth.src = 50:54:00:00:00:10; ip6.src = fd00::10; nd.target = fd00::10; nd.tll = 50:54:00:00:00:10; outport = inport; flags.loopback = 1; output; };)
+ ])
+
+ #Set the disable_arp_nd_rsp option and verify the flow
+@@ -12615,6 +12632,7 @@ AT_SETUP([Sampling_App incremental processing])
+
+ ovn_start
+
++ovn-nbctl --wait=sb sync
+ check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats
+
+ ovn-nbctl create Sampling_App type="acl-new" id="42"
+@@ -13761,3 +13779,96 @@ AT_CHECK([grep -e "172.168.0.110" -e "172.168.0.120" -e "10.0.0.3" -e "20.0.0.3"
+
+ AT_CLEANUP
+ ])
++
++OVN_FOR_EACH_NORTHD_NO_HV([
++AT_SETUP([Routing protocol control plane redirect])
++ovn_start
++
++check ovn-sbctl chassis-add hv1 geneve 127.0.0.1
++
++check ovn-nbctl lr-add lr -- \
++ lrp-add lr lr-ls 02:ac:10:01:00:01 172.16.1.1/24
++check ovn-nbctl --wait=sb set logical_router lr options:chassis=hv1
++
++check ovn-nbctl ls-add ls -- \
++ lsp-add ls ls-lr -- \
++ lsp-set-type ls-lr router -- \
++ lsp-set-addresses ls-lr router -- \
++ lsp-set-options ls-lr router-port=lr-ls
++
++check ovn-nbctl lsp-add ls lsp-bgp -- \
++ lsp-set-addresses lsp-bgp unknown
++
++# Function that ensures that no redirect rules are installed.
++check_no_redirect() {
++ AT_CHECK([ovn-sbctl dump-flows ls | grep ls_in_l2_lkup | grep -E "tcp.dst == 179|tcp.src == 179" | wc -l], [0], [0
++])
++
++ AT_CHECK([ovn-sbctl dump-flows ls | grep ls_in_check_port_sec | grep -E "priority=80" | wc -l], [0], [0
++])
++ check_no_bfd_redirect
++}
++
++# Function that ensures that no BFD redirect rules are installed.
++check_no_bfd_redirect() {
++ AT_CHECK([ovn-sbctl dump-flows ls | grep ls_in_l2_lkup | grep -E "udp.dst == 3784|udp.src == 3784" | wc -l], [0], [0
++])
++}
++
++# By default, no rules related to routing protocol redirect are present
++check_no_redirect
++
++# Set "lsp-bgp" port as target of BGP control plane redirected traffic
++check ovn-nbctl --wait=sb set logical_router_port lr-ls options:routing-protocol-redirect=lsp-bgp
++check ovn-nbctl --wait=sb set logical_router_port lr-ls options:routing-protocols=BGP
++
++# Check that BGP control plane traffic is redirected "lsp-bgp"
++AT_CHECK([ovn-sbctl dump-flows ls | grep ls_in_l2_lkup | grep -E "tcp.dst == 179|tcp.src == 179" | ovn_strip_lflows], [0], [dnl
++ table=??(ls_in_l2_lkup ), priority=100 , match=(ip4.dst == 172.16.1.1 && tcp.dst == 179), action=(outport = "lsp-bgp"; output;)
++ table=??(ls_in_l2_lkup ), priority=100 , match=(ip4.dst == 172.16.1.1 && tcp.src == 179), action=(outport = "lsp-bgp"; output;)
++ table=??(ls_in_l2_lkup ), priority=100 , match=(ip6.dst == fe80::ac:10ff:fe01:1 && tcp.dst == 179), action=(outport = "lsp-bgp"; output;)
++ table=??(ls_in_l2_lkup ), priority=100 , match=(ip6.dst == fe80::ac:10ff:fe01:1 && tcp.src == 179), action=(outport = "lsp-bgp"; output;)
++])
++
++# Check that ARP/ND traffic is cloned to the "lsp-bgp"
++AT_CHECK([ovn-sbctl dump-flows ls | grep ls_in_l2_lkup | grep "arp.op == 2 && arp.tpa == 172.16.1.1" | ovn_strip_lflows], [0], [dnl
++ table=??(ls_in_l2_lkup ), priority=100 , match=(arp.op == 2 && arp.tpa == 172.16.1.1), action=(clone { outport = "lsp-bgp"; output; }; outport = "ls-lr"; output;)
++])
++AT_CHECK([ovn-sbctl dump-flows ls | grep ls_in_l2_lkup | grep "&& nd_na" | ovn_strip_lflows], [0], [dnl
++ table=??(ls_in_l2_lkup ), priority=100 , match=(ip6.dst == fe80::ac:10ff:fe01:1 && nd_na), action=(clone { outport = "lsp-bgp"; output; }; outport = "ls-lr"; output;)
++])
++
++# Check that at this point no BFD redirecting is present
++check_no_bfd_redirect
++
++# Add BFD traffic redirect
++check ovn-nbctl --wait=sb set logical_router_port lr-ls options:routing-protocols=BGP,BFD
++
++# Check that BFD traffic is redirected to "lsp-bgp"
++AT_CHECK([ovn-sbctl dump-flows ls | grep ls_in_l2_lkup | grep -E "udp.dst == 3784|udp.src == 3784" | ovn_strip_lflows], [0], [dnl
++ table=??(ls_in_l2_lkup ), priority=100 , match=(ip4.dst == 172.16.1.1 && udp.dst == 3784), action=(outport = "lsp-bgp"; output;)
++ table=??(ls_in_l2_lkup ), priority=100 , match=(ip4.dst == 172.16.1.1 && udp.src == 3784), action=(outport = "lsp-bgp"; output;)
++ table=??(ls_in_l2_lkup ), priority=100 , match=(ip6.dst == fe80::ac:10ff:fe01:1 && udp.dst == 3784), action=(outport = "lsp-bgp"; output;)
++ table=??(ls_in_l2_lkup ), priority=100 , match=(ip6.dst == fe80::ac:10ff:fe01:1 && udp.src == 3784), action=(outport = "lsp-bgp"; output;)
++])
++
++
++# Check that ARP replies and ND advertisements are blocked from exiting "lsp-bgp"
++AT_CHECK([ovn-sbctl dump-flows ls | grep ls_in_check_port_sec | grep "priority=80" | ovn_strip_lflows], [0], [dnl
++ table=??(ls_in_check_port_sec), priority=80 , match=(inport == "lsp-bgp" && arp.op == 2), action=(reg0[[15]] = 1; next;)
++ table=??(ls_in_check_port_sec), priority=80 , match=(inport == "lsp-bgp" && nd_na), action=(reg0[[15]] = 1; next;)
++ table=??(ls_in_check_port_sec), priority=80 , match=(inport == "lsp-bgp" && nd_ra), action=(reg0[[15]] = 1; next;)
++])
++
++# Remove 'bgp-redirect' option from LRP and check that rules are removed
++check ovn-nbctl --wait=sb remove logical_router_port lr-ls options routing-protocol-redirect
++check ovn-nbctl --wait=sb remove logical_router_port lr-ls options routing-protocols
++check_no_redirect
++
++# Set non-existent LSP as target of 'bgp-redirect' and check that no rules are added
++check ovn-nbctl --wait=sb set logical_router_port lr-ls options:routing-protocol-redirect=lsp-foo
++check ovn-nbctl --wait=sb set logical_router_port lr-ls options:routing-protocols=BGP,BFD
++check_no_redirect
++
++AT_CLEANUP
++])
+diff --git a/tests/ovn.at b/tests/ovn.at
+index a1d689e84..ec6e6c100 100644
+--- a/tests/ovn.at
++++ b/tests/ovn.at
+@@ -1263,11 +1263,27 @@ ct_lb_mark(backends=192.168.1.2:80,192.168.1.3:80; hash_fields="eth_src,eth_dst,
+
+ # ct_next
+ ct_next;
++ formats as ct_next(dnat);
++ encodes as ct(table=oflow_in_table,zone=NXM_NX_REG13[[0..15]])
++ has prereqs ip
++ct_next(dnat);
++ encodes as ct(table=oflow_in_table,zone=NXM_NX_REG13[[0..15]])
++ has prereqs ip
++ct_next(snat);
+ encodes as ct(table=oflow_in_table,zone=NXM_NX_REG13[[0..15]])
+ has prereqs ip
+ ct_clear; ct_next;
++ formats as ct_clear; ct_next(dnat);
+ encodes as ct_clear,ct(table=oflow_in_table,zone=NXM_NX_REG13[[0..15]])
+ has prereqs ip
++ct_next(snat, dnat);
++ Syntax error at `,' expecting `)'.
++ct_next(dnat, ignore);
++ Syntax error at `,' expecting `)'.
++ct_next(ignore);
++ "ct_next" action accepts only "dnat" or "snat" parameter.
++ct_next();
++ "ct_next" action accepts only "dnat" or "snat" parameter.
+
+ # ct_commit
+ ct_commit;
+@@ -8617,7 +8633,7 @@ done
+ # Complete Neighbor Solicitation packet and Neighbor Advertisement packet
+ # vif1 -> NS -> vif2. vif1 <- NA <- ovn-controller.
+ # vif2 will not receive NS packet, since ovn-controller will reply for it.
+-ns_packet=3333ffa1f9aefa163e94059886dd6000000000203afffd81ce49a9480000f8163efffe940598fd81ce49a9480000f8163efffea1f9ae8700e01160000000fd81ce49a9480000f8163efffea1f9ae0101fa163e940598
++ns_packet=3333ffa1f9aefa163e94059886dd6000000000203afffd81ce49a9480000f8163efffe940598ff0200000000000000000001ffa1f9ae8700e01160000000fd81ce49a9480000f8163efffea1f9ae0101fa163e940598
+ na_packet=fa163e940598fa163ea1f9ae86dd6000000000203afffd81ce49a9480000f8163efffea1f9aefd81ce49a9480000f8163efffe9405988800e9ed60000000fd81ce49a9480000f8163efffea1f9ae0201fa163ea1f9ae
+
+ as hv1 ovs-appctl netdev-dummy/receive vif1 $ns_packet
+@@ -14417,7 +14433,7 @@ test_ns_na() {
+ local inport=$1 src_mac=$2 dst_mac=$3 src_ip=$4 dst_ip=$5
+
+ packet=$(fmt_pkt "
+- Ether(dst='ff:ff:ff:ff:ff:ff', src='${src_mac}') /
++ Ether(dst='33:33:ff:ff:ff:ff', src='${src_mac}') /
+ IPv6(src='${src_ip}', dst='ff02::1:ff00:2') /
+ ICMPv6ND_NS(tgt='${dst_ip}')
+ ")
+@@ -15740,14 +15756,17 @@ m4_define([MULTICHASSIS_PATH_MTU_DISCOVERY_TEST],
+ second_mac=00:00:00:00:00:02
+ multi1_mac=00:00:00:00:00:f0
+ multi2_mac=00:00:00:00:00:f1
++ external_mac=00:00:00:00:ee:ff
+ first_ip=10.0.0.1
+ second_ip=10.0.0.2
+ multi1_ip=10.0.0.10
+ multi2_ip=10.0.0.20
++ external_ip=10.0.0.30
+ first_ip6=abcd::1
+ second_ip6=abcd::2
+ multi1_ip6=abcd::f0
+ multi2_ip6=abcd::f1
++ external_ip6=abcd::eeff
+
+ check ovn-nbctl ls-add ls0
+ check ovn-nbctl lsp-add ls0 first
+@@ -15866,6 +15885,24 @@ m4_define([MULTICHASSIS_PATH_MTU_DISCOVERY_TEST],
+
+ reset_env
+
++ AS_BOX([Multi with "unknown" to external doesn't produce wrong FDB])
++ len=3000
++ check ovn-nbctl --wait=hv lsp-set-addresses multi1 unknown
++
++ packet=$(send_ip_packet multi1 1 $multi1_mac $external_mac $multi1_ip $external_ip $(payload $len) 1 ${expected_ip_mtu})
++ echo $packet >> hv1/multi1.expected
++
++ packet=$(send_ip6_packet multi1 1 $multi1_mac $external_mac $multi1_ip6 $external_ip6 $(payload $len) 1 ${expected_ip_mtu})
++ echo $packet >> hv1/multi1.expected
++
++ check_pkts
++ reset_env
++
++ check_row_count fdb 0 mac="$external_mac"
++ ovn-sbctl --all destroy fdb
++
++ check ovn-nbctl --wait=hv lsp-set-addresses multi1 "${multi1_mac} ${multi1_ip} ${multi1_ip6}"
++
+ AS_BOX([Packets of proper size are delivered from multichassis to regular ports])
+
+ len=1000
+@@ -15965,9 +16002,6 @@ m4_define([MULTICHASSIS_PATH_MTU_DISCOVERY_TEST],
+ packet=$(send_ip6_packet multi1 1 $multi1_mac $multi2_mac $multi1_ip6 $multi2_ip6 $(payload $len) 1)
+ echo $packet >> hv1/multi1.expected
+
+- check_pkts
+- reset_env
+-
+ AS_BOX([MTU updates are honored in ICMP Path MTU calculation])
+
+ set_mtu() {
+@@ -28717,7 +28751,7 @@ AT_CHECK([
+ for hv in 1 2; do
+ grep table=$ecmp_stateful hv${hv}flows | \
+ grep "priority=100" | \
+- grep -c "ct(commit,zone=NXM_NX_REG11\\[[0..15\\]],.*exec(move:NXM_OF_ETH_SRC\\[[\\]]->NXM_NX_CT_LABEL\\[[32..79\\]],load:0x[[0-9]]->NXM_NX_CT_MARK\\[[16..31\\]],load:0x[[0-9]]->NXM_NX_CT_LABEL\\[[96..127\\]]))"
++ grep -c "ct(commit,zone=NXM_NX_REG11\\[[0..15\\]],.*exec(move:NXM_OF_ETH_SRC\\[[\\]]->NXM_NX_CT_LABEL\\[[32..79\\]],load:0x[[0-9]]->NXM_NX_CT_MARK\\[[16..31\\]]))"
+
+ grep table=$arp_resolve hv${hv}flows | \
+ grep "priority=200" | \
+@@ -28846,7 +28880,7 @@ AT_CHECK([
+ for hv in 1 2; do
+ grep table=$ecmp_stateful hv${hv}flows | \
+ grep "priority=100" | \
+- grep -c "ct(commit,zone=NXM_NX_REG11\\[[0..15\\]],.*exec(move:NXM_OF_ETH_SRC\\[[\\]]->NXM_NX_CT_LABEL\\[[32..79\\]],load:0x[[0-9]]->NXM_NX_CT_MARK\\[[16..31\\]],load:0x[[0-9]]->NXM_NX_CT_LABEL\\[[96..127\\]]))"
++ grep -c "ct(commit,zone=NXM_NX_REG11\\[[0..15\\]],.*exec(move:NXM_OF_ETH_SRC\\[[\\]]->NXM_NX_CT_LABEL\\[[32..79\\]],load:0x[[0-9]]->NXM_NX_CT_MARK\\[[16..31\\]]))"
+
+ grep table=$arp_resolve hv${hv}flows | \
+ grep "priority=200" | \
+@@ -34709,11 +34743,13 @@ port_key_1=$(printf "0x%x" $(as hv1 fetch_column port_binding tunnel_key logical
+ dp_key_2=$(printf "0x%x" $(as hv1 fetch_column datapath tunnel_key external_ids:name=gw-2))
+ port_key_2=$(printf "0x%x" $(as hv1 fetch_column port_binding tunnel_key logical_port=gw-2-public))
+
+-AT_CHECK_UNQUOTED([as hv1 ovs-ofctl dump-flows br-int table=OFTABLE_MAC_CACHE_USE --no-stats | strip_cookie | sort], [0], [dnl
+- table=OFTABLE_MAC_CACHE_USE, priority=100,ip,reg14=${port_key_1},metadata=${dp_key_1},dl_src=00:00:00:00:10:10,nw_src=192.168.10.10 actions=drop
++table=" table=OFTABLE_MAC_CACHE_USE, priority=100,ip,reg14=${port_key_1},metadata=${dp_key_1},dl_src=00:00:00:00:10:10,nw_src=192.168.10.10 actions=drop
+ table=OFTABLE_MAC_CACHE_USE, priority=100,ip,reg14=${port_key_1},metadata=${dp_key_1},dl_src=00:00:00:00:10:20,nw_src=192.168.10.20 actions=drop
+ table=OFTABLE_MAC_CACHE_USE, priority=100,ip,reg14=${port_key_2},metadata=${dp_key_2},dl_src=00:00:00:00:10:10,nw_src=192.168.10.10 actions=drop
+- table=OFTABLE_MAC_CACHE_USE, priority=100,ip,reg14=${port_key_2},metadata=${dp_key_2},dl_src=00:00:00:00:10:20,nw_src=192.168.10.20 actions=drop
++ table=OFTABLE_MAC_CACHE_USE, priority=100,ip,reg14=${port_key_2},metadata=${dp_key_2},dl_src=00:00:00:00:10:20,nw_src=192.168.10.20 actions=drop"
++sorted_table=$(printf '%s\n' "$table" | sort)
++AT_CHECK_UNQUOTED([as hv1 ovs-ofctl dump-flows br-int table=OFTABLE_MAC_CACHE_USE --no-stats | strip_cookie | sort], [0], [dnl
++$sorted_table
+ ])
+
+ timestamp=$(fetch_column mac_binding timestamp ip="192.168.10.20")
+@@ -38238,49 +38274,60 @@ AT_CLEANUP
+ OVN_FOR_EACH_NORTHD([
+ AT_SETUP([ovn-controller - cleanup VIF/CIF related flows/fields when updating requested-chassis])
+ ovn_start
+-
+ net_add n1
+-sim_add hv1
+-ovs-vsctl add-br br-phys
+-ovn_attach n1 br-phys 192.168.0.1
+-check ovs-vsctl -- add-port br-int vif1 -- \
+- set Interface vif1 external-ids:iface-id=lsp1 \
+- ofport-request=8
+
+-check ovn-nbctl ls-add lsw0
++for i in 1 2; do
++ sim_add hv$i
++ as hv$i
++ ovs-vsctl add-br br-phys
++ ovn_attach n1 br-phys 192.168.0.$i
++ check ovs-vsctl -- add-port br-int vif1 -- \
++ set Interface vif1 ofport-request=8
++done
+
++check ovn-nbctl ls-add lsw0
++as hv1
++check ovs-vsctl set Interface vif1 external-ids:iface-id=lsp1
+ check ovn-nbctl lsp-add lsw0 lsp1
+ check ovn-nbctl lsp-add lsw0 sw0-port1.1 lsp1 7
+
+ # wait for the VIF to be claimed to this chassis
+ wait_row_count Chassis 1 name=hv1
++wait_row_count Chassis 1 name=hv2
+ hv1_uuid=$(fetch_column Chassis _uuid name=hv1)
++hv2_uuid=$(fetch_column Chassis _uuid name=hv2)
++
+ wait_for_ports_up lsp1
+ wait_for_ports_up sw0-port1.1
+ wait_column "$hv1_uuid" Port_Binding chassis logical_port=lsp1
+ wait_column "$hv1_uuid" Port_Binding chassis logical_port=sw0-port1.1
+
+ # check that flows is installed
+-OVS_WAIT_FOR_OUTPUT([as hv1 ovs-ofctl dump-flows br-int table=0 |grep priority=100 | grep -c in_port=8], [0],[dnl
++OVS_WAIT_FOR_OUTPUT([as hv1 ovs-ofctl dump-flows br-int table=OFTABLE_PHY_TO_LOG |grep priority=150|grep dl_vlan=7| grep -c in_port=8], [0],[dnl
+ 1
+ ])
+-OVS_WAIT_FOR_OUTPUT([as hv1 ovs-ofctl dump-flows br-int table=0 |grep priority=150|grep dl_vlan=7| grep -c in_port=8], [0],[dnl
+-1
++
++OVS_WAIT_FOR_OUTPUT([as hv2 ovs-ofctl dump-flows br-int table=OFTABLE_PHY_TO_LOG |grep priority=150|grep dl_vlan=7| grep -c in_port=8], [1],[dnl
++0
+ ])
+
+-# set lport requested-chassis to differant chassis
++# Add hv2 to lport Additional requested chassis as MAIN chassis
++# and check that no flows installed in table 0 in hv1
+ check ovn-nbctl set Logical_Switch_Port lsp1 \
+- options:requested-chassis=foo
++ options:requested-chassis=hv2,hv1
+
+-OVS_WAIT_UNTIL([test `ovn-sbctl get Port_Binding lsp1 up` = 'false'])
+-OVS_WAIT_UNTIL([test `ovn-sbctl get Port_Binding sw0-port1.1 up` = 'false'])
+-wait_column "" Port_Binding chassis logical_port=lsp1
+-wait_column "" Port_Binding chassis logical_port=sw0-port1.1
++as hv2
++check ovs-vsctl set Interface vif1 external-ids:iface-id=lsp1
++ovn-nbctl --wait=hv sync
+
+-OVS_WAIT_FOR_OUTPUT([as hv1 ovs-ofctl dump-flows br-int table=0 |grep priority=100 |grep -c in_port=8], [1],[dnl
+-0
++wait_for_ports_up lsp1
++wait_for_ports_up sw0-port1.1
++wait_column "$hv2_uuid" Port_Binding chassis logical_port=lsp1
++
++OVS_WAIT_FOR_OUTPUT([as hv2 ovs-ofctl dump-flows br-int table=OFTABLE_PHY_TO_LOG |grep priority=150|grep dl_vlan=7| grep -c in_port=8], [0],[dnl
++1
+ ])
+-OVS_WAIT_FOR_OUTPUT([as hv1 ovs-ofctl dump-flows br-int table=0 |grep priority=150|grep dl_vlan=7| grep -c in_port=8], [1],[dnl
++OVS_WAIT_FOR_OUTPUT([as hv1 ovs-ofctl dump-flows br-int table=OFTABLE_PHY_TO_LOG |grep priority=150|grep dl_vlan=7| grep -c in_port=8], [1],[dnl
+ 0
+ ])
+
+@@ -38756,3 +38803,238 @@ OVN_CLEANUP([hv1],[hv2])
+
+ AT_CLEANUP
+ ])
++
++dnl This test checks that the megaflows translated by ovs-vswitchd
++dnl don't match on IPv6 source and destination addresses for
++dnl simple switching.
++OVN_FOR_EACH_NORTHD([
++AT_SETUP([IPv6 switching - megaflow check for IPv6 src/dst matches])
++AT_SKIP_IF([test $HAVE_SCAPY = no])
++ovn_start
++
++check ovn-nbctl ls-add sw0
++
++check ovn-nbctl lsp-add sw0 vm0
++check ovn-nbctl lsp-set-addresses vm0 "f0:00:0f:01:02:03 10.0.0.3 1000::3"
++
++check ovn-nbctl lsp-add sw0 vm1
++check ovn-nbctl lsp-set-addresses vm1 "f0:00:0f:01:02:04 10.0.0.4 1000::4"
++
++check ovn-nbctl lr-add lr0
++check ovn-nbctl lrp-add lr0 lr0-sw0 fa:16:3e:00:00:01 10.0.0.1 1000::1/64
++check ovn-nbctl lsp-add sw0 sw0-lr0
++check ovn-nbctl lsp-set-type sw0-lr0 router
++check ovn-nbctl lsp-set-addresses sw0-lr0 router
++check ovn-nbctl --wait=hv lsp-set-options sw0-lr0 router-port=lr0-sw0
++
++net_add n1
++sim_add hv
++as hv
++check ovs-vsctl add-br br-phys
++ovn_attach n1 br-phys 192.168.0.1
++check ovs-vsctl add-port br-int vif1 -- \
++ set Interface vif1 external-ids:iface-id=vm0 \
++ options:tx_pcap=hv/vif1-tx.pcap \
++ options:rxq_pcap=hv/vif1-rx.pcap \
++ ofport-request=1
++check ovs-vsctl add-port br-int vif2 -- \
++ set Interface vif2 external-ids:iface-id=vm1 \
++ options:tx_pcap=hv/vif2-tx.pcap \
++ options:rxq_pcap=hv/vif2-rx.pcap \
++ ofport-request=2
++
++check ovn-nbctl --wait=sb sync
++wait_for_ports_up
++
++AS_BOX([No port security, to vm1])
++packet=$(fmt_pkt "Ether(dst='f0:00:0f:01:02:04', src='f0:00:0f:01:02:03')/ \
++ IPv6(dst='1000::4', src='1000::3')/ \
++ UDP(sport=53, dport=4369)")
++
++as hv
++ovs-appctl ofproto/trace br-int in_port=1 $packet > vm0_ip6_ofproto_trace.txt
++ovs-appctl netdev-dummy/receive vif1 $packet
++
++AT_CAPTURE_FILE([vm0_ip6_ofproto_trace.txt])
++
++AT_CHECK([grep Megaflow vm0_ip6_ofproto_trace.txt | grep -e ipv6_src -e ipv6_dst -c], [1], [dnl
++0
++])
++
++dnl Make sure that the packet was received by vm1. This ensures that the
++dnl packet was delivered as expected and the megaflow didn't have any matches
++dnl on IPv6 src or dst.
++
++echo $packet >> expected-vif2
++OVN_CHECK_PACKETS([hv/vif2-tx.pcap], [expected-vif2])
++
++AS_BOX([No port security, to vm0])
++packet=$(fmt_pkt "Ether(dst='f0:00:0f:01:02:03', src='f0:00:0f:01:02:04')/ \
++ IPv6(dst='1000::3', src='1000::4')/ \
++ UDP(sport=53, dport=4369)")
++
++as hv
++ovs-appctl ofproto/trace br-int in_port=2 $packet > vm1_ip6_ofproto_trace.txt
++ovs-appctl netdev-dummy/receive vif2 $packet
++
++AT_CAPTURE_FILE([vm1_ip6_ofproto_trace.txt])
++
++AT_CHECK([grep Megaflow vm0_ip6_ofproto_trace.txt | grep -e ipv6_src -e ipv6_dst -c], [1], [dnl
++0
++])
++
++dnl Make sure that the packet was received by vm0. This ensures that the
++dnl packet was delivered as expected and the megaflow didn't have any matches
++dnl on IPv6 src or dst.
++echo $packet >> expected-vif1
++OVN_CHECK_PACKETS([hv/vif1-tx.pcap], [expected-vif1])
++
++AS_BOX([With port security, to vm1])
++dnl Add port security to vm0. The megaflow should now match on ipv6 src/dst.
++check ovn-nbctl lsp-set-port-security vm0 "f0:00:0f:01:02:03 10.0.0.3 1000::3"
++check ovn-nbctl --wait=hv sync
++
++packet=$(fmt_pkt "Ether(dst='f0:00:0f:01:02:04', src='f0:00:0f:01:02:03')/ \
++ IPv6(dst='1000::4', src='1000::3')/ \
++ UDP(sport=53, dport=4369)")
++
++as hv
++ovs-appctl ofproto/trace br-int in_port=1 $packet > vm0_ip6_ofproto_trace.txt
++ovs-appctl netdev-dummy/receive vif1 $packet
++
++AT_CAPTURE_FILE([vm0_ip6_ofproto_trace.txt])
++
++AT_CHECK([grep Megaflow vm0_ip6_ofproto_trace.txt | grep -e ipv6_src -e ipv6_dst -c], [0], [dnl
++1
++])
++
++dnl Make sure that the packet was received by vm1.
++echo $packet >> expected-vif2
++OVN_CHECK_PACKETS([hv/vif2-tx.pcap], [expected-vif2])
++
++AS_BOX([Clear port security, to vm1])
++dnl Clear port security.
++check ovn-nbctl lsp-set-port-security vm0 ""
++check ovn-nbctl --wait=hv sync
++
++as hv
++ovs-appctl ofproto/trace br-int in_port=1 $packet > vm0_ip6_ofproto_trace.txt
++ovs-appctl netdev-dummy/receive vif1 $packet
++
++AT_CAPTURE_FILE([vm0_ip6_ofproto_trace.txt])
++
++AT_CHECK([grep Megaflow vm0_ip6_ofproto_trace.txt | grep -e ipv6_src -e ipv6_dst -c], [1], [dnl
++0
++])
++
++dnl Make sure that the packet was received by vm1.
++echo $packet >> expected-vif2
++OVN_CHECK_PACKETS([hv/vif2-tx.pcap], [expected-vif2])
++
++AS_BOX([With proxy arp/nd, to vm1])
++dnl Configure proxy arp/nd on the router port. The megaflow should now match
++dnl on ipv6 src/dst.
++check ovn-nbctl --wait=hv lsp-set-options sw0-lr0 router-port=lr0-sw0 arp_proxy="2000::1/64"
++
++as hv
++ovs-appctl ofproto/trace br-int in_port=1 $packet > vm0_ip6_ofproto_trace.txt
++ovs-appctl netdev-dummy/receive vif1 $packet
++
++AT_CAPTURE_FILE([vm0_ip6_ofproto_trace.txt])
++
++AT_CHECK([grep Megaflow vm0_ip6_ofproto_trace.txt | grep -e ipv6_src -e ipv6_dst -c], [0], [dnl
++1
++])
++
++dnl Make sure that the packet was received by vm1.
++echo $packet >> expected-vif2
++OVN_CHECK_PACKETS([hv/vif2-tx.pcap], [expected-vif2])
++
++AS_BOX([With proxy arp/nd, to vm0])
++packet=$(fmt_pkt "Ether(dst='f0:00:0f:01:02:03', src='f0:00:0f:01:02:04')/ \
++ IPv6(dst='1000::3', src='1000::4')/ \
++ UDP(sport=53, dport=4369)")
++
++as hv
++ovs-appctl ofproto/trace br-int in_port=2 $packet > vm1_ip6_ofproto_trace.txt
++ovs-appctl netdev-dummy/receive vif2 $packet
++
++AT_CAPTURE_FILE([vm1_ip6_ofproto_trace.txt])
++
++AT_CHECK([grep Megaflow vm0_ip6_ofproto_trace.txt | grep -e ipv6_src -e ipv6_dst -c], [0], [dnl
++1
++])
++
++dnl Make sure that the packet was received by vm0.
++echo $packet >> expected-vif1
++OVN_CHECK_PACKETS([hv/vif1-tx.pcap], [expected-vif1])
++
++AT_CLEANUP
++])
++
++
++OVN_FOR_EACH_NORTHD([
++AT_SETUP([Multichassis port I-P processing])
++ovn_start
++
++net_add n1
++
++sim_add hv1
++as hv1
++check ovs-vsctl add-br br-phys
++ovn_attach n1 br-phys 192.168.0.11
++check ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys
++
++sim_add hv2
++as hv2
++check ovs-vsctl add-br br-phys
++ovn_attach n1 br-phys 192.168.0.12
++check ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys
++
++check ovn-nbctl ls-add ls
++check ovn-nbctl lsp-add ls multi
++check ovn-nbctl lsp-set-options multi requested-chassis=hv1
++
++check ovn-nbctl lsp-add ls ln
++check ovn-nbctl lsp-set-type ln localnet
++check ovn-nbctl lsp-set-addresses ln unknown
++check ovn-nbctl lsp-set-options ln network_name=phys
++
++check ovn-nbctl lsp-add ls lsp1 \
++ -- lsp-set-options lsp1 requested-chassis=hv1
++as hv1 check ovs-vsctl -- add-port br-int lsp1 \
++ -- set Interface lsp1 external-ids:iface-id=lsp1
++
++for hv in hv1 hv2; do
++ as $hv check ovs-vsctl -- add-port br-int multi \
++ -- set Interface multi external-ids:iface-id=multi
++done
++
++wait_for_ports_up
++ovn-nbctl --wait=hv sync
++
++OVS_WAIT_UNTIL([test $(as hv2 ovs-ofctl dump-flows br-int table=OFTABLE_OUTPUT_LARGE_PKT_DETECT | grep -c check_pkt_larger) -eq 0])
++
++check ovn-nbctl --wait=hv lsp-set-options multi requested-chassis=hv1,hv2
++OVS_WAIT_UNTIL([test $(as hv2 ovs-ofctl dump-flows br-int table=OFTABLE_OUTPUT_LARGE_PKT_DETECT | grep -c check_pkt_larger) -eq 4])
++
++check ovn-nbctl --wait=hv lsp-set-options multi requested-chassis=hv1
++OVS_WAIT_UNTIL([test $(as hv2 ovs-ofctl dump-flows br-int table=OFTABLE_OUTPUT_LARGE_PKT_DETECT | grep -c check_pkt_larger) -eq 0])
++
++check ovn-nbctl --wait=hv lsp-set-options multi requested-chassis=hv1,hv2
++OVS_WAIT_UNTIL([test $(as hv2 ovs-ofctl dump-flows br-int table=OFTABLE_OUTPUT_LARGE_PKT_DETECT | grep -c check_pkt_larger) -eq 4])
++
++as hv2 check ovs-vsctl del-port multi
++OVS_WAIT_UNTIL([test $(as hv2 ovs-ofctl dump-flows br-int table=OFTABLE_OUTPUT_LARGE_PKT_DETECT | grep -c check_pkt_larger) -eq 0])
++
++as hv2 check ovs-vsctl -- add-port br-int multi \
++ -- set Interface multi external-ids:iface-id=multi
++OVS_WAIT_UNTIL([test $(as hv2 ovs-ofctl dump-flows br-int table=OFTABLE_OUTPUT_LARGE_PKT_DETECT | grep -c check_pkt_larger) -eq 4])
++
++check ovn-nbctl --wait=hv lsp-del multi
++OVS_WAIT_UNTIL([test $(as hv2 ovs-ofctl dump-flows br-int table=OFTABLE_OUTPUT_LARGE_PKT_DETECT | grep -c check_pkt_larger) -eq 0])
++
++OVN_CLEANUP([hv1],[hv2])
++
++AT_CLEANUP
++])
+diff --git a/tests/system-ovn.at b/tests/system-ovn.at
+index c54b0f3a5..861b1cb99 100644
+--- a/tests/system-ovn.at
++++ b/tests/system-ovn.at
+@@ -3518,7 +3518,7 @@ AT_CHECK([ovn-nbctl lr-nat-add R1 dnat_and_snat 172.16.1.3 192.168.1.2 foo1 00:0
+ AT_CHECK([ovn-nbctl lr-nat-add R1 dnat_and_snat 172.16.1.4 192.168.1.3 foo2 00:00:02:02:03:05])
+
+ # Add a SNAT rule
+-AT_CHECK([ovn-nbctl lr-nat-add R1 snat 172.16.1.1 192.168.0.0/16])
++AT_CHECK([ovn-nbctl lr-nat-add R1 snat 172.16.1.1 0.0.0.0/0])
+
+ # Add default route to ext-net
+ AT_CHECK([ovn-nbctl lr-route-add R1 10.0.0.0/24 172.16.1.2])
+@@ -3724,8 +3724,7 @@ AT_CHECK([ovn-nbctl lr-nat-add R1 dnat_and_snat fd20::3 fd11::2 foo1 00:00:02:02
+ AT_CHECK([ovn-nbctl lr-nat-add R1 dnat_and_snat fd20::4 fd11::3 foo2 00:00:02:02:03:05])
+
+ # Add a SNAT rule
+-AT_CHECK([ovn-nbctl lr-nat-add R1 snat fd20::1 fd11::/64])
+-AT_CHECK([ovn-nbctl lr-nat-add R1 snat fd20::1 fd12::/64])
++AT_CHECK([ovn-nbctl lr-nat-add R1 snat fd20::1 ::/0])
+
+ ovn-nbctl --wait=hv sync
+ OVS_WAIT_UNTIL([ovs-ofctl dump-flows br-int | grep 'nat(src=fd20::1)'])
+@@ -3920,7 +3919,7 @@ AT_CHECK([ovn-nbctl lr-nat-add R1 dnat_and_snat 172.16.1.3 192.168.1.2 foo1 00:0
+ AT_CHECK([ovn-nbctl lr-nat-add R1 dnat_and_snat 172.16.1.4 192.168.2.2 bar1 00:00:02:02:03:05])
+
+ # Add a SNAT rule
+-AT_CHECK([ovn-nbctl lr-nat-add R1 snat 172.16.1.1 192.168.0.0/16])
++AT_CHECK([ovn-nbctl lr-nat-add R1 snat 172.16.1.1 0.0.0.0/0])
+
+ ovn-nbctl --wait=hv sync
+ OVS_WAIT_UNTIL([ovs-ofctl dump-flows br-int | grep 'nat(src=172.16.1.1)'])
+@@ -4104,8 +4103,7 @@ AT_CHECK([ovn-nbctl lr-nat-add R1 dnat_and_snat fd20::3 fd11::2 foo1 00:00:02:02
+ AT_CHECK([ovn-nbctl lr-nat-add R1 dnat_and_snat fd20::4 fd12::2 bar1 00:00:02:02:03:05])
+
+ # Add a SNAT rule
+-AT_CHECK([ovn-nbctl lr-nat-add R1 snat fd20::1 fd11::/64])
+-AT_CHECK([ovn-nbctl lr-nat-add R1 snat fd20::1 fd12::/64])
++AT_CHECK([ovn-nbctl lr-nat-add R1 snat fd20::1 ::/0])
+
+ ovn-nbctl --wait=hv sync
+ OVS_WAIT_UNTIL([ovs-ofctl dump-flows br-int | grep 'nat(src=fd20::1)'])
+@@ -6172,21 +6170,18 @@ NS_CHECK_EXEC([bob1], [ping -q -c 3 -i 0.3 -w 2 10.0.0.2 | FORMAT_PING], \
+ # and just ensure that the known ethernet address is present.
+ AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(172.16.0.1) | \
+ sed -e 's/zone=[[0-9]]*/zone=/' |
+-sed -e 's/mark=[[0-9]]*/mark=/' |
+-sed -e 's/labels=0x[[0-9]]/labels=0x?/'], [0], [dnl
+-icmp,orig=(src=172.16.0.1,dst=10.0.0.2,id=,type=8,code=0),reply=(src=10.0.0.2,dst=172.16.0.1,id=,type=0,code=0),zone=,mark=,labels=0x?000000000401020400000000
+-tcp,orig=(src=172.16.0.1,dst=10.0.0.2,sport=,dport=),reply=(src=10.0.0.2,dst=172.16.0.1,sport=,dport=),zone=,mark=,labels=0x?000000000401020400000000,protoinfo=(state=)
++sed -e 's/mark=[[0-9]]*/mark=/'], [0], [dnl
++icmp,orig=(src=172.16.0.1,dst=10.0.0.2,id=,type=8,code=0),reply=(src=10.0.0.2,dst=172.16.0.1,id=,type=0,code=0),zone=,mark=,labels=0x401020400000000
++tcp,orig=(src=172.16.0.1,dst=10.0.0.2,sport=,dport=),reply=(src=10.0.0.2,dst=172.16.0.1,sport=,dport=),zone=,mark=,labels=0x401020400000000,protoinfo=(state=)
+ ])
+
+ # Ensure datapaths show conntrack states as expected
+ # Like with conntrack entries, we shouldn't try to predict
+ # port binding tunnel keys. So omit them from expected labels.
+-AT_CHECK([ovs-appctl dpctl/dump-flows | sed -e 's/label=0x[[0-9]]/label=0x?/' | \
+-grep 'ct_state(+new-est+trk).*ct(.*label=0x?000000000401020400000000/.*)' -c], [0], [dnl
++AT_CHECK([ovs-appctl dpctl/dump-flows | grep 'ct_state(+new-est+trk).*ct(.*label=0x401020400000000/.*)' -c], [0], [dnl
+ 2
+ ])
+-AT_CHECK([[ovs-appctl dpctl/dump-flows | sed -e 's/ct_label(0x[0-9]/ct_label(0x?/' | \
+-grep 'ct_state(-new+est+trk).*ct_label(0x?000000000401020400000000)' -c]], [0], [dnl
++AT_CHECK([ovs-appctl dpctl/dump-flows | grep 'ct_state(-new+est+trk).*ct_label(0x401020400000000)' -c], [0], [dnl
+ 2
+ ])
+
+@@ -6205,21 +6200,18 @@ NS_CHECK_EXEC([bob1], [ping -q -c 3 -i 0.3 -w 2 10.0.0.2 | FORMAT_PING], \
+ [0], [dnl
+ 3 packets transmitted, 3 received, 0% packet loss, time 0ms
+ ])
+-AT_CHECK([ovs-appctl dpctl/dump-flows | sed -e 's/label=0x[[0-9]]/label=0x?/' | \
+-grep 'ct_state(+new-est+trk).*ct(.*label=0x?000000001001020400000000/.*)' -c], [0], [dnl
++AT_CHECK([ovs-appctl dpctl/dump-flows | grep 'ct_state(+new-est+trk).*ct(.*label=0x1001020400000000/.*)' -c], [0], [dnl
+ 2
+ ])
+-AT_CHECK([[ovs-appctl dpctl/dump-flows | sed -e 's/ct_label(0x[0-9]/ct_label(0x?/' | \
+-grep 'ct_state(-new+est+trk).*ct_label(0x?000000001001020400000000)' -c]], [0], [dnl
++AT_CHECK([ovs-appctl dpctl/dump-flows | grep 'ct_state(-new+est+trk).*ct_label(0x1001020400000000)' -c], [0], [dnl
+ 2
+ ])
+
+-AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep 1001020400000000 | FORMAT_CT(172.16.0.1) | \
++AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep 0x1001020400000000 | FORMAT_CT(172.16.0.1) | \
+ sed -e 's/zone=[[0-9]]*/zone=/' |
+-sed -e 's/mark=[[0-9]]*/mark=/' |
+-sed -e 's/labels=0x[[0-9]]/labels=0x?/' | sort], [0], [dnl
+-icmp,orig=(src=172.16.0.1,dst=10.0.0.2,id=,type=8,code=0),reply=(src=10.0.0.2,dst=172.16.0.1,id=,type=0,code=0),zone=,mark=,labels=0x?000000001001020400000000
+-tcp,orig=(src=172.16.0.1,dst=10.0.0.2,sport=,dport=),reply=(src=10.0.0.2,dst=172.16.0.1,sport=,dport=),zone=,mark=,labels=0x?000000001001020400000000,protoinfo=(state=)
++sed -e 's/mark=[[0-9]]*/mark=/' | sort], [0], [dnl
++icmp,orig=(src=172.16.0.1,dst=10.0.0.2,id=,type=8,code=0),reply=(src=10.0.0.2,dst=172.16.0.1,id=,type=0,code=0),zone=,mark=,labels=0x1001020400000000
++tcp,orig=(src=172.16.0.1,dst=10.0.0.2,sport=,dport=),reply=(src=10.0.0.2,dst=172.16.0.1,sport=,dport=),zone=,mark=,labels=0x1001020400000000,protoinfo=(state=)
+ ])
+ # Check entries in table 76 and 77 expires w/o traffic
+ OVS_WAIT_UNTIL([
+@@ -6241,16 +6233,27 @@ NS_CHECK_EXEC([alice1], [ping -q -c 3 -i 0.3 -w 2 172.16.0.1 | FORMAT_PING], \
+ 3 packets transmitted, 3 received, 0% packet loss, time 0ms
+ ])
+
+-AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep 401020500000000 | FORMAT_CT(172.16.0.1) | \
++AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep 0x401020500000000 | FORMAT_CT(172.16.0.1) | \
+ sed -e 's/zone=[[0-9]]*/zone=/' |
+-sed -e 's/mark=[[0-9]]*/mark=/' |
+-sed -e 's/labels=0x[[0-9]]/labels=0x?/' | sort], [0], [dnl
+-tcp,orig=(src=172.16.0.1,dst=10.0.0.2,sport=,dport=),reply=(src=10.0.0.2,dst=172.16.0.1,sport=,dport=),zone=,mark=,labels=0x?000000000401020500000000,protoinfo=(state=)
++sed -e 's/mark=[[0-9]]*/mark=/' | sort], [0], [dnl
++tcp,orig=(src=172.16.0.1,dst=10.0.0.2,sport=,dport=),reply=(src=10.0.0.2,dst=172.16.0.1,sport=,dport=),zone=,mark=,labels=0x401020500000000,protoinfo=(state=)
+ ])
+
+-# Flush connection tracking entries
+-ovn-nbctl --wait=hv lr-route-del R1
+-AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(172.16.0.1)])
++# Now remove one ECMP route and check that traffic is still being conntracked.
++check ovn-nbctl --policy="src-ip" lr-route-del R1 10.0.0.0/24 20.0.0.3
++check ovn-nbctl --wait=hv sync
++AT_CHECK([ovs-appctl dpctl/flush-conntrack])
++NETNS_DAEMONIZE([bob1], [nc -l -k 8081], [bob2.pid])
++NS_CHECK_EXEC([alice1], [nc -z 172.16.0.1 8081], [0])
++NS_CHECK_EXEC([alice1], [ping -q -c 3 -i 0.3 -w 2 172.16.0.1 | FORMAT_PING], \
++[0], [dnl
++3 packets transmitted, 3 received, 0% packet loss, time 0ms
++])
++AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep 0x401020500000000 | FORMAT_CT(172.16.0.1) | \
++sed -e 's/zone=[[0-9]]*/zone=/' |
++sed -e 's/mark=[[0-9]]*/mark=/' | sort], [0], [dnl
++tcp,orig=(src=172.16.0.1,dst=10.0.0.2,sport=,dport=),reply=(src=10.0.0.2,dst=172.16.0.1,sport=,dport=),zone=,mark=,labels=0x401020500000000,protoinfo=(state=)
++])
+
+ OVS_APP_EXIT_AND_WAIT([ovn-controller])
+
+@@ -6399,12 +6402,11 @@ NS_CHECK_EXEC([bob1], [ping -q -c 3 -i 0.3 -w 2 fd01::2 | FORMAT_PING], \
+ # Ensure datapaths show conntrack states as expected
+ # Like with conntrack entries, we shouldn't try to predict
+ # port binding tunnel keys. So omit them from expected labels.
+-AT_CHECK([ovs-appctl dpctl/dump-flows | sed -e 's/label=0x[[0-9]]/label=0x?/' | \
+-grep 'ct_state(+new-est+trk).*ct(.*label=0x?000000000401020400000000/.*)' -c], [0], [dnl
++AT_CHECK([ovs-appctl dpctl/dump-flows | grep 'ct_state(+new-est+trk).*ct(.*label=0x401020400000000/.*)' -c], [0], [dnl
+ 2
+ ])
+-AT_CHECK([[ovs-appctl dpctl/dump-flows | sed -e 's/ct_label(0x[0-9]/ct_label(0x?/' | \
+-grep 'ct_state(-new+est+trk).*ct_label(0x?000000000401020400000000)' -c]], [0], [dnl
++
++AT_CHECK([ovs-appctl dpctl/dump-flows | grep 'ct_state(-new+est+trk).*ct_label(0x401020400000000)' -c], [0], [dnl
+ 2
+ ])
+
+@@ -6413,10 +6415,9 @@ grep 'ct_state(-new+est+trk).*ct_label(0x?000000000401020400000000)' -c]], [0],
+ # and just ensure that the known ethernet address is present.
+ AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd01::2) | \
+ sed -e 's/zone=[[0-9]]*/zone=/' |
+-sed -e 's/mark=[[0-9]]*/mark=/' |
+-sed -e 's/labels=0x[[0-9]]/labels=0x?/' | sort], [0], [dnl
+-icmpv6,orig=(src=fd07::1,dst=fd01::2,id=,type=128,code=0),reply=(src=fd01::2,dst=fd07::1,id=,type=129,code=0),zone=,mark=,labels=0x?000000000401020400000000
+-tcp,orig=(src=fd07::1,dst=fd01::2,sport=,dport=),reply=(src=fd01::2,dst=fd07::1,sport=,dport=),zone=,mark=,labels=0x?000000000401020400000000,protoinfo=(state=)
++sed -e 's/mark=[[0-9]]*/mark=/' | sort], [0], [dnl
++icmpv6,orig=(src=fd07::1,dst=fd01::2,id=,type=128,code=0),reply=(src=fd01::2,dst=fd07::1,id=,type=129,code=0),zone=,mark=,labels=0x401020400000000
++tcp,orig=(src=fd07::1,dst=fd01::2,sport=,dport=),reply=(src=fd01::2,dst=fd07::1,sport=,dport=),zone=,mark=,labels=0x401020400000000,protoinfo=(state=)
+ ])
+
+ # Flush conntrack entries for easier output parsing of next test.
+@@ -6433,21 +6434,18 @@ NS_CHECK_EXEC([bob1], [ping -q -c 3 -i 0.3 -w 2 fd01::2 | FORMAT_PING], \
+ 3 packets transmitted, 3 received, 0% packet loss, time 0ms
+ ])
+
+-AT_CHECK([ovs-appctl dpctl/dump-flows | sed -e 's/label=0x[[0-9]]/label=0x?/' | \
+-grep 'ct_state(+new-est+trk).*ct(.*label=0x?000000001001020400000000/.*)' -c], [0], [dnl
++AT_CHECK([ovs-appctl dpctl/dump-flows | grep 'ct_state(+new-est+trk).*ct(.*label=0x1001020400000000/.*)' -c], [0], [dnl
+ 2
+ ])
+-AT_CHECK([[ovs-appctl dpctl/dump-flows | sed -e 's/ct_label(0x[0-9]/ct_label(0x?/' | \
+-grep 'ct_state(-new+est+trk).*ct_label(0x?000000001001020400000000)' -c]], [0], [dnl
++AT_CHECK([ovs-appctl dpctl/dump-flows | grep 'ct_state(-new+est+trk).*ct_label(0x1001020400000000)' -c], [0], [dnl
+ 2
+ ])
+
+-AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep 1001020400000000 | FORMAT_CT(fd01::2) | \
++AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep 0x1001020400000000 | FORMAT_CT(fd01::2) | \
+ sed -e 's/zone=[[0-9]]*/zone=/' |
+-sed -e 's/mark=[[0-9]]*/mark=/' |
+-sed -e 's/labels=0x[[0-9]]/labels=0x?/'], [0], [dnl
+-icmpv6,orig=(src=fd07::1,dst=fd01::2,id=,type=128,code=0),reply=(src=fd01::2,dst=fd07::1,id=,type=129,code=0),zone=,mark=,labels=0x?000000001001020400000000
+-tcp,orig=(src=fd07::1,dst=fd01::2,sport=,dport=),reply=(src=fd01::2,dst=fd07::1,sport=,dport=),zone=,mark=,labels=0x?000000001001020400000000,protoinfo=(state=)
++sed -e 's/mark=[[0-9]]*/mark=/'], [0], [dnl
++icmpv6,orig=(src=fd07::1,dst=fd01::2,id=,type=128,code=0),reply=(src=fd01::2,dst=fd07::1,id=,type=129,code=0),zone=,mark=,labels=0x1001020400000000
++tcp,orig=(src=fd07::1,dst=fd01::2,sport=,dport=),reply=(src=fd01::2,dst=fd07::1,sport=,dport=),zone=,mark=,labels=0x1001020400000000,protoinfo=(state=)
+ ])
+
+ # Check entries in table 76 and 77 expires w/o traffic
+@@ -6467,16 +6465,27 @@ NS_CHECK_EXEC([alice1], [ping -q -c 3 -i 0.3 -w 2 fd07::1 | FORMAT_PING], \
+ 3 packets transmitted, 3 received, 0% packet loss, time 0ms
+ ])
+
+-AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep 1001020400000000 | FORMAT_CT(fd07::1) | \
++AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep 0x1001020400000000 | FORMAT_CT(fd07::1) | \
+ sed -e 's/zone=[[0-9]]*/zone=/' |
+-sed -e 's/mark=[[0-9]]*/mark=/' |
+-sed -e 's/labels=0x[[0-9]]/labels=0x?/' | sort], [0], [dnl
+-tcp,orig=(src=fd07::1,dst=fd01::2,sport=,dport=),reply=(src=fd01::2,dst=fd07::1,sport=,dport=),zone=,mark=,labels=0x?000000001001020400000000,protoinfo=(state=)
++sed -e 's/mark=[[0-9]]*/mark=/' | sort], [0], [dnl
++tcp,orig=(src=fd07::1,dst=fd01::2,sport=,dport=),reply=(src=fd01::2,dst=fd07::1,sport=,dport=),zone=,mark=,labels=0x1001020400000000,protoinfo=(state=)
+ ])
+
+-# Flush connection tracking entries
+-check ovn-nbctl --wait=hv lr-route-del R1
+-AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd01::2)])
++# Now remove one ECMP route and check that traffic is still being conntracked.
++check ovn-nbctl --policy="src-ip" lr-route-del R1 fd01::/126 fd02::3
++check ovn-nbctl --wait=hv sync
++AT_CHECK([ovs-appctl dpctl/flush-conntrack])
++NETNS_DAEMONIZE([bob1], [nc -6 -l -k 8081], [bob2.pid])
++NS_CHECK_EXEC([alice1], [nc -6 -z fd07::1 8081], [0])
++NS_CHECK_EXEC([alice1], [ping -q -c 3 -i 0.3 -w 2 fd07::1 | FORMAT_PING], \
++[0], [dnl
++3 packets transmitted, 3 received, 0% packet loss, time 0ms
++])
++AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep 0x1001020400000000 | FORMAT_CT(fd07::1) | \
++sed -e 's/zone=[[0-9]]*/zone=/' |
++sed -e 's/mark=[[0-9]]*/mark=/' | sort], [0], [dnl
++tcp,orig=(src=fd07::1,dst=fd01::2,sport=,dport=),reply=(src=fd01::2,dst=fd07::1,sport=,dport=),zone=,mark=,labels=0x1001020400000000,protoinfo=(state=)
++])
+
+ OVS_APP_EXIT_AND_WAIT([ovn-controller])
+
+@@ -6941,7 +6950,8 @@ check ovn-nbctl lsp-add public public1 \
+ -- lsp-set-type public1 localnet \
+ -- lsp-set-options public1 network_name=phynet
+
+-NS_CHECK_EXEC([server], [bfdd-beacon --listen=172.16.1.50], [0])
++NETNS_DAEMONIZE([server], [bfdd-beacon --nofork --tee --listen=172.16.1.50 >beacon.stdout 2>&1], [beacon.pid])
++OVS_WAIT_UNTIL([grep -q "Listening for BFD connections" beacon.stdout])
+ NS_CHECK_EXEC([server], [bfdd-control allow 172.16.1.1], [0], [dnl
+ Allowing connections from 172.16.1.1
+ ])
+@@ -7001,7 +7011,8 @@ check ovn-nbctl set logical_router R1 options:chassis=hv1
+ check ovn-nbctl set logical_router_static_route $route_uuid bfd=$uuid
+
+ # restart bfdd
+-NS_CHECK_EXEC([server], [bfdd-beacon --listen=172.16.1.50], [0])
++NETNS_DAEMONIZE([server], [bfdd-beacon --nofork --tee --listen=172.16.1.50 >beacon.stdout 2>&1], [beacon.pid])
++OVS_WAIT_UNTIL([grep -q "Listening for BFD connections" beacon.stdout])
+ NS_CHECK_EXEC([server], [bfdd-control allow 172.16.1.1], [0], [dnl
+ Allowing connections from 172.16.1.1
+ ])
+@@ -7043,7 +7054,8 @@ check ovn-nbctl lr-route-add R1 2000::/64 1000::b
+ route_uuid_v6=$(fetch_column nb:logical_router_static_route _uuid ip_prefix=\"2000::/64\")
+ ovn-nbctl set logical_router_static_route $route_uuid_v6 bfd=$uuid_v6
+ check ovn-nbctl --wait=hv sync
+-NS_CHECK_EXEC([server], [bfdd-beacon --listen=1000::b], [0])
++NETNS_DAEMONIZE([server], [bfdd-beacon --nofork --tee --listen=1000::b >beacon.stdout 2>&1], [beacon.pid])
++OVS_WAIT_UNTIL([grep -q "Listening for BFD connections" beacon.stdout])
+ NS_CHECK_EXEC([server], [bfdd-control allow 1000::a], [0], [dnl
+ Allowing connections from 1000::a
+ ])
+@@ -9374,7 +9386,7 @@ name: 'vport4' value: '999'
+ NETNS_DAEMONIZE([vm1], [nc -k -l 42.42.42.2 4242], [nc-vm1.pid])
+
+ NETNS_START_TCPDUMP([vm1],
+- [-n -i vm1 -nnleX -c6 udp and dst 42.42.42.2 and dst port 4343],
++ [-n -i vm1 -nnqleX -c6 udp and dst 42.42.42.2 and dst port 4343],
+ [vm1])
+
+ # Make sure connecting to the VIP works (hairpin, via ls and via lr).
+@@ -9525,7 +9537,7 @@ name: 'vport4' value: '999'
+ NETNS_DAEMONIZE([vm1], [nc -k -l 4242::2 4242], [nc-vm1.pid])
+
+ NETNS_START_TCPDUMP([vm1],
+- [-n -i vm1 -nnleX -c6 udp and dst 4242::2 and dst port 4343],
++ [-n -i vm1 -nnqleX -c6 udp and dst 4242::2 and dst port 4343],
+ [vm1])
+
+ # Make sure connecting to the VIP works (hairpin, via ls and via lr).
+@@ -11363,7 +11375,25 @@ check_ovn_installed
+ check_ports_up
+ check_ports_bound
+
+-OVS_APP_EXIT_AND_WAIT([ovn-controller])
++AS_BOX(["Leave some ovn-installed while closing ovn-controller"])
++# Block IDL from ovn-controller to OVSDB
++stop_ovsdb_controller_updates $TCP_PORT
++remove_iface_id vif2
++ensure_controller_run
++
++# OVSDB should now be seen as read-only by ovn-controller
++remove_iface_id vif1
++check ovn-nbctl --wait=hv sync
++
++# Stop ovsdb before ovn-controller to ensure it's not updated
++as
++OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
++/connection dropped.*/d"])
++
++# Don't use OVS_APP_EXIT... to use --restart to avoid cleaning up the databases.
++TMPPID=$(cat $OVS_RUNDIR/ovn-controller.pid)
++check ovs-appctl -t ovn-controller exit --restart
++OVS_WAIT_WHILE([kill -0 $TMPPID 2>/dev/null])
+
+ as ovn-sb
+ OVS_APP_EXIT_AND_WAIT([ovsdb-server])
+@@ -11374,9 +11404,6 @@ OVS_APP_EXIT_AND_WAIT([ovsdb-server])
+ as northd
+ OVS_APP_EXIT_AND_WAIT([ovn-northd])
+
+-as
+-OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
+-/connection dropped.*/d"])
+ AT_CLEANUP
+ ])
+
+@@ -13186,16 +13213,17 @@ ovs-vsctl --id=@br get Bridge br-int \
+ -- --id=@ipfix create IPFIX targets=\"127.0.0.1:4242\" template_interval=1 \
+ -- --id=@cs create Flow_Sample_Collector_Set id=100 bridge=@br ipfix=@ipfix
+
++ovn-nbctl --wait=hv sync
+ dnl And wait for it to be up and running.
+ OVS_WAIT_UNTIL([ovs-ofctl dump-ipfix-flow br-int | grep -q '1 ids'])
+
+ dnl Start UDP echo server on vm2.
+-NETNS_DAEMONIZE([vm2], [nc -e /bin/cat -k -u -v -l 1000], [nc-vm2-1000.pid])
+-NETNS_DAEMONIZE([vm2], [nc -e /bin/cat -k -u -v -l 1010], [nc-vm2-1010.pid])
+-NETNS_DAEMONIZE([vm2], [nc -e /bin/cat -k -u -v -l 2000], [nc-vm2-2000.pid])
+-NETNS_DAEMONIZE([vm2], [nc -e /bin/cat -k -u -v -l 2010], [nc-vm2-2010.pid])
+-NETNS_DAEMONIZE([vm2], [nc -e /bin/cat -k -u -v -l 3000], [nc-vm2-3000.pid])
+-NETNS_DAEMONIZE([vm2], [nc -e /bin/cat -k -u -v -l 3010], [nc-vm2-3010.pid])
++NETNS_DAEMONIZE([vm2], [nc -e /bin/cat -k -u -v -l -m 1 1000], [nc-vm2-1000.pid])
++NETNS_DAEMONIZE([vm2], [nc -e /bin/cat -k -u -v -l -m 1 1010], [nc-vm2-1010.pid])
++NETNS_DAEMONIZE([vm2], [nc -e /bin/cat -k -u -v -l -m 1 2000], [nc-vm2-2000.pid])
++NETNS_DAEMONIZE([vm2], [nc -e /bin/cat -k -u -v -l -m 1 2010], [nc-vm2-2010.pid])
++NETNS_DAEMONIZE([vm2], [nc -e /bin/cat -k -u -v -l -m 1 3000], [nc-vm2-3000.pid])
++NETNS_DAEMONIZE([vm2], [nc -e /bin/cat -k -u -v -l -m 1 3010], [nc-vm2-3010.pid])
+
+ dnl Send traffic (2 packets) to the UDP LB1 (hits the from-lport ACL).
+ NS_CHECK_EXEC([vm1], [(echo a; sleep 1; echo a) | nc --send-only -u 43.43.43.43 1000])
+@@ -13354,11 +13382,12 @@ ovs-vsctl --id=@br get Bridge br-int \
+ -- --id=@ipfix create IPFIX targets=\"127.0.0.1:4242\" template_interval=1 \
+ -- --id=@cs create Flow_Sample_Collector_Set id=100 bridge=@br ipfix=@ipfix
+
++ovn-nbctl --wait=hv sync
+ dnl And wait for it to be up and running.
+ OVS_WAIT_UNTIL([ovs-ofctl dump-ipfix-flow br-int | grep -q '1 ids'])
+
+ dnl Start UDP echo server on vm2.
+-NETNS_DAEMONIZE([vm2], [nc -e /bin/cat -k -u -v -l 1000], [nc-vm2-1000.pid])
++NETNS_DAEMONIZE([vm2], [nc -e /bin/cat -k -u -v -l -m 1 1000], [nc-vm2-1000.pid])
+
+ dnl Send traffic to the UDP server (hits both ACL tiers).
+ NS_CHECK_EXEC([vm1], [echo a | nc --send-only -u 42.42.42.3 1000])
+@@ -13483,6 +13512,7 @@ ovs-vsctl --id=@br get Bridge br-int \
+ -- --id=@ipfix create IPFIX targets=\"127.0.0.1:4242\" template_interval=1 \
+ -- --id=@cs create Flow_Sample_Collector_Set id=100 bridge=@br ipfix=@ipfix
+
++ovn-nbctl --wait=hv sync
+ dnl And wait for it to be up and running.
+ OVS_WAIT_UNTIL([ovs-ofctl dump-ipfix-flow br-int | grep -q '1 ids'])
+
+@@ -13750,3 +13780,152 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/.*error receiving.*/d
+ /.*terminating with signal 15.*/d"])
+ AT_CLEANUP
+ ])
++
++OVN_FOR_EACH_NORTHD([
++AT_SETUP([Routing protocol redirect])
++AT_SKIP_IF([test $HAVE_NC = no])
++
++ovn_start
++OVS_TRAFFIC_VSWITCHD_START()
++
++ADD_BR([br-int])
++ADD_BR([br-ext])
++
++check ovs-ofctl add-flow br-ext action=normal
++# Set external-ids in br-int needed for ovn-controller
++check ovs-vsctl \
++ -- set Open_vSwitch . external-ids:system-id=hv1 \
++ -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \
++ -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \
++ -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \
++ -- set bridge br-int fail-mode=secure other-config:disable-in-band=true
++
++# Start ovn-controller
++start_daemon ovn-controller
++
++check ovn-nbctl lr-add R1 \
++ -- set Logical_Router R1 options:chassis=hv1
++
++check ovn-nbctl ls-add public
++check ovn-nbctl ls-add bar
++
++check ovn-nbctl lrp-add R1 rp-public 00:00:02:01:02:03 172.16.1.1/24
++check ovn-nbctl lrp-add R1 rp-bar 00:00:ff:00:00:01 192.168.10.1/24
++
++check ovn-nbctl lsp-add public public-rp -- set Logical_Switch_Port public-rp \
++ type=router options:router-port=rp-public \
++ -- lsp-set-addresses public-rp router
++
++check ovn-nbctl lsp-add bar bar-rp -- set Logical_Switch_Port bar-rp \
++ type=router options:router-port=rp-bar \
++ -- lsp-set-addresses bar-rp router
++
++check ovn-nbctl lsp-add public bgp-daemon \
++ -- lsp-set-addresses bgp-daemon unknown
++
++# Setup container "bar1" representing host on an internal network
++ADD_NAMESPACES(bar1)
++ADD_VETH(bar1, bar1, br-int, "192.168.10.2/24", "00:00:ff:ff:ff:01", \
++ "192.168.10.1")
++check ovn-nbctl lsp-add bar bar1 \
++ -- lsp-set-addresses bar1 "00:00:ff:ff:ff:01 192.168.10.2"
++
++# Setup SNAT for the internal host
++check ovn-nbctl lr-nat-add R1 snat 172.16.1.1 192.168.10.2
++
++# Configure external connectivity
++check ovs-vsctl set Open_vSwitch . external-ids:ovn-bridge-mappings=phynet:br-ext
++check ovn-nbctl lsp-add public public1 \
++ -- lsp-set-addresses public1 unknown \
++ -- lsp-set-type public1 localnet \
++ -- lsp-set-options public1 network_name=phynet
++
++check ovn-nbctl --wait=hv sync
++
++# Set option that redirects BGP and BFD traffic to a LSP "bgp-daemon"
++check ovn-nbctl --wait=sb set logical_router_port rp-public options:routing-protocol-redirect=bgp-daemon
++check ovn-nbctl --wait=sb set logical_router_port rp-public options:routing-protocols=BGP,BFD
++
++# Create "bgp-daemon" interface in a namespace with IP and MAC matching LRP "rp-public"
++ADD_NAMESPACES(bgp-daemon)
++ADD_VETH(bgp-daemon, bgp-daemon, br-int, "172.16.1.1/24", "00:00:02:01:02:03")
++
++ADD_NAMESPACES(ext-foo)
++ADD_VETH(ext-foo, ext-foo, br-ext, "172.16.1.100/24", "00:10:10:01:02:13", \
++ "172.16.1.1")
++
++# Flip the interface down/up to get proper IPv6 LLA
++NS_EXEC([bgp-daemon], [ip link set down bgp-daemon])
++NS_EXEC([bgp-daemon], [ip link set up bgp-daemon])
++NS_EXEC([ext-foo], [ip link set down ext-foo])
++NS_EXEC([ext-foo], [ip link set up ext-foo])
++
++# Wait until IPv6 LLA loses the "tentative" flag otherwise it can't be bound to.
++OVS_WAIT_UNTIL([NS_EXEC([bgp-daemon], [ip a show dev bgp-daemon | grep "fe80::" | grep -v tentative])])
++OVS_WAIT_UNTIL([NS_EXEC([ext-foo], [ip a show dev ext-foo | grep "fe80::" | grep -v tentative])])
++
++# Verify that BGP control plane traffic is delivered to the "bgp-daemon"
++# interface on both IPv4 and IPv6 LLA addresses
++NETNS_DAEMONIZE([bgp-daemon], [nc -l -k 172.16.1.1 179], [bgp_v4.pid])
++NS_CHECK_EXEC([ext-foo], [echo "BGP IPv4 server traffic" | nc --send-only 172.16.1.1 179])
++
++NETNS_DAEMONIZE([bgp-daemon], [nc -l -6 -k fe80::200:2ff:fe01:203%bgp-daemon 179], [bgp_v6.pid])
++NS_CHECK_EXEC([ext-foo], [echo "BGP IPv6 server traffic" | nc --send-only -6 fe80::200:2ff:fe01:203%ext-foo 179])
++
++# Perform same set of checks as above for BFD daemon.
++# We need to manually check that the message arrived on the receiving end as Ncat will
++# produce false positive results over UDP due to lack of ICMP port unreachable messages
++# from LRP's IP.
++NETNS_DAEMONIZE([bgp-daemon], [nc -l -u 172.16.1.1 3784 > bgp-daemon_bfd_v4.out], [bfd_v4.pid])
++NS_CHECK_EXEC([ext-foo], [echo "from ext-foo: BFD IPv4 server traffic" | nc -u 172.16.1.1 3784])
++AT_CHECK([cat bgp-daemon_bfd_v4.out], [0], [dnl
++from ext-foo: BFD IPv4 server traffic
++])
++
++NETNS_DAEMONIZE([bgp-daemon], [nc -l -6 -u fe80::200:2ff:fe01:203%bgp-daemon 3784 > bgp-daemon_bfd_v6.out], [bfd_v6.pid])
++NS_CHECK_EXEC([ext-foo], [echo "from ext-foo: BFD IPv6 server traffic" | nc -u -6 fe80::200:2ff:fe01:203%ext-foo 3784])
++AT_CHECK([cat bgp-daemon_bfd_v6.out], [0], [dnl
++from ext-foo: BFD IPv6 server traffic
++])
++
++# Verify connection in other direction. i.e when BGP daemon running on "bgp-daemon" port
++# makes a client connection to its peer
++NETNS_DAEMONIZE([ext-foo], [nc -l -k 172.16.1.100 179], [reply_bgp_v4.pid])
++NS_CHECK_EXEC([bgp-daemon], [echo "BGP IPv4 client traffic" | nc --send-only 172.16.1.100 179])
++
++NETNS_DAEMONIZE([ext-foo], [nc -l -6 -k fe80::210:10ff:fe01:213%ext-foo 179], [reply_bgp_v6.pid])
++NS_CHECK_EXEC([bgp-daemon], [echo "BGP IPv6 client traffic" | nc --send-only -6 fe80::210:10ff:fe01:213%bgp-daemon 179])
++
++# Perform same checks in other direction for BFD daemon
++NETNS_DAEMONIZE([ext-foo], [nc -l -u 172.16.1.100 3784 > ext-foo_bfd_v4.out], [reply_bfd_v4.pid])
++NS_CHECK_EXEC([bgp-daemon], [echo "from bgp-daemon: BFD IPv4 client traffic" | nc -u 172.16.1.100 3784])
++AT_CHECK([cat ext-foo_bfd_v4.out], [0], [dnl
++from bgp-daemon: BFD IPv4 client traffic
++])
++
++NETNS_DAEMONIZE([ext-foo], [nc -l -6 -u fe80::210:10ff:fe01:213%ext-foo 3784 > ext-foo_bfd_v6.out], [reply_bfd_v6.pid])
++NS_CHECK_EXEC([bgp-daemon], [echo "from bgp-daemon: BFD IPv6 client traffic" | nc -u -6 fe80::210:10ff:fe01:213%bgp-daemon 3784])
++AT_CHECK([cat ext-foo_bfd_v6.out], [0], [dnl
++from bgp-daemon: BFD IPv6 client traffic
++])
++
++# Verify that hosts on the internal network can reach external networks
++NETNS_DAEMONIZE([ext-foo], [nc -l -k 172.16.1.100 2222], [nc_external.pid])
++NS_CHECK_EXEC([bar1], [echo "TCP test" | nc -w 1 --send-only 172.16.1.100 2222])
++
++OVS_APP_EXIT_AND_WAIT([ovn-controller])
++
++as ovn-sb
++OVS_APP_EXIT_AND_WAIT([ovsdb-server])
++
++as ovn-nb
++OVS_APP_EXIT_AND_WAIT([ovsdb-server])
++
++as northd
++OVS_APP_EXIT_AND_WAIT([ovn-northd])
++
++as
++OVS_TRAFFIC_VSWITCHD_STOP(["/.*error receiving.*/d
++/.*terminating with signal 15.*/d"])
++AT_CLEANUP
++])
+diff --git a/utilities/containers/py-requirements.txt b/utilities/containers/py-requirements.txt
+index 8a3e977aa..1b55042c8 100644
+--- a/utilities/containers/py-requirements.txt
++++ b/utilities/containers/py-requirements.txt
+@@ -1,6 +1,6 @@
+ flake8>=6.1.0
+ meson>=1.4,<1.5
+-scapy
++scapy==2.5.0
+ sphinx<8.0 # https://github.com/sphinx-doc/sphinx/issues/12711
+ setuptools
+ pyelftools
diff --git a/SOURCES/ppc_64-power8-linuxapp-gcc-config b/SOURCES/ppc_64-power8-linuxapp-gcc-config
new file mode 100644
index 0000000..2319b68
--- /dev/null
+++ b/SOURCES/ppc_64-power8-linuxapp-gcc-config
@@ -0,0 +1,550 @@
+# -*- cfg-sha: ac783e64ca20c977a7c1c42e72e6dce151b31aa9aecfbfa121b45e49e938f418
+# BSD LICENSE
+# Copyright (C) IBM Corporation 2014.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of IBM Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2010-2016 Intel Corporation
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2010-2017 Intel Corporation
+# RTE_EXEC_ENV values are the directories in mk/exec-env/
+CONFIG_RTE_EXEC_ENV="linuxapp"
+# RTE_ARCH values are architecture we compile for. directories in mk/arch/
+CONFIG_RTE_ARCH="ppc_64"
+# machine can define specific variables or action for a specific board
+# RTE_MACHINE values are architecture we compile for. directories in mk/machine/
+CONFIG_RTE_MACHINE="power8"
+# The compiler we use.
+# RTE_TOOLCHAIN values are architecture we compile for. directories in mk/toolchain/
+CONFIG_RTE_TOOLCHAIN="gcc"
+# Use intrinsics or assembly code for key routines
+CONFIG_RTE_FORCE_INTRINSICS=n
+# Machine forces strict alignment constraints.
+CONFIG_RTE_ARCH_STRICT_ALIGN=n
+# Compile to share library
+CONFIG_RTE_BUILD_SHARED_LIB=n
+# Use newest code breaking previous ABI
+CONFIG_RTE_NEXT_ABI=n
+# Major ABI to overwrite library specific LIBABIVER
+CONFIG_RTE_MAJOR_ABI=
+# Machine's cache line size
+CONFIG_RTE_CACHE_LINE_SIZE=128
+# Memory model
+CONFIG_RTE_USE_C11_MEM_MODEL=n
+# Compile Environment Abstraction Layer
+CONFIG_RTE_LIBRTE_EAL=y
+CONFIG_RTE_MAX_LCORE=256
+CONFIG_RTE_MAX_NUMA_NODES=32
+CONFIG_RTE_MAX_HEAPS=32
+CONFIG_RTE_MAX_MEMSEG_LISTS=64
+# each memseg list will be limited to either RTE_MAX_MEMSEG_PER_LIST pages
+# or RTE_MAX_MEM_MB_PER_LIST megabytes worth of memory, whichever is smaller
+CONFIG_RTE_MAX_MEMSEG_PER_LIST=8192
+CONFIG_RTE_MAX_MEM_MB_PER_LIST=32768
+# a "type" is a combination of page size and NUMA node. total number of memseg
+# lists per type will be limited to either RTE_MAX_MEMSEG_PER_TYPE pages (split
+# over multiple lists of RTE_MAX_MEMSEG_PER_LIST pages), or
+# RTE_MAX_MEM_MB_PER_TYPE megabytes of memory (split over multiple lists of
+# RTE_MAX_MEM_MB_PER_LIST), whichever is smaller
+CONFIG_RTE_MAX_MEMSEG_PER_TYPE=32768
+CONFIG_RTE_MAX_MEM_MB_PER_TYPE=131072
+# global maximum usable amount of VA, in megabytes
+CONFIG_RTE_MAX_MEM_MB=524288
+CONFIG_RTE_MAX_MEMZONE=2560
+CONFIG_RTE_MAX_TAILQ=32
+CONFIG_RTE_ENABLE_ASSERT=n
+CONFIG_RTE_LOG_DP_LEVEL=RTE_LOG_INFO
+CONFIG_RTE_LOG_HISTORY=256
+CONFIG_RTE_BACKTRACE=y
+CONFIG_RTE_LIBEAL_USE_HPET=n
+CONFIG_RTE_EAL_ALLOW_INV_SOCKET_ID=n
+CONFIG_RTE_EAL_ALWAYS_PANIC_ON_ERROR=n
+CONFIG_RTE_EAL_IGB_UIO=n
+CONFIG_RTE_EAL_VFIO=y
+CONFIG_RTE_MAX_VFIO_GROUPS=64
+CONFIG_RTE_MAX_VFIO_CONTAINERS=64
+CONFIG_RTE_MALLOC_DEBUG=n
+CONFIG_RTE_EAL_NUMA_AWARE_HUGEPAGES=y
+CONFIG_RTE_USE_LIBBSD=n
+# Recognize/ignore architecture we compile for. AVX/AVX512 CPU flags for performance/power testing.
+# AVX512 is marked as experimental for now, will enable it after enough
+# field test and possible optimization.
+CONFIG_RTE_ENABLE_AVX=y
+CONFIG_RTE_ENABLE_AVX512=n
+# Default driver path (or "" to disable)
+CONFIG_RTE_EAL_PMD_PATH=""
+# Compile Environment Abstraction Layer to support Vmware TSC map
+CONFIG_RTE_LIBRTE_EAL_VMWARE_TSC_MAP_SUPPORT=n
+# Compile architecture we compile for. PCI library
+CONFIG_RTE_LIBRTE_PCI=y
+# Compile architecture we compile for. argument parser library
+CONFIG_RTE_LIBRTE_KVARGS=y
+# Compile generic ethernet library
+CONFIG_RTE_LIBRTE_ETHER=y
+CONFIG_RTE_LIBRTE_ETHDEV_DEBUG=n
+CONFIG_RTE_MAX_ETHPORTS=32
+CONFIG_RTE_MAX_QUEUES_PER_PORT=1024
+CONFIG_RTE_LIBRTE_IEEE1588=n
+CONFIG_RTE_ETHDEV_QUEUE_STAT_CNTRS=16
+CONFIG_RTE_ETHDEV_RXTX_CALLBACKS=y
+CONFIG_RTE_ETHDEV_PROFILE_WITH_VTUNE=n
+# Turn off Tx preparation stage
+# Warning: rte_eth_tx_prepare() can be safely disabled only if using a
+# driver which do not implement any Tx preparation.
+CONFIG_RTE_ETHDEV_TX_PREPARE_NOOP=n
+# Common libraries, before Bus/PMDs
+CONFIG_RTE_LIBRTE_COMMON_DPAAX=n
+# Compile architecture we compile for. Intel FPGA bus
+CONFIG_RTE_LIBRTE_IFPGA_BUS=n
+# Compile PCI bus driver
+CONFIG_RTE_LIBRTE_PCI_BUS=y
+# Compile architecture we compile for. vdev bus
+CONFIG_RTE_LIBRTE_VDEV_BUS=y
+# Compile ARK PMD
+CONFIG_RTE_LIBRTE_ARK_PMD=n
+CONFIG_RTE_LIBRTE_ARK_PAD_TX=y
+CONFIG_RTE_LIBRTE_ARK_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_ARK_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_ARK_DEBUG_STATS=n
+CONFIG_RTE_LIBRTE_ARK_DEBUG_TRACE=n
+# Compile Aquantia Atlantic PMD driver
+CONFIG_RTE_LIBRTE_ATLANTIC_PMD=n
+# Compile AMD PMD
+CONFIG_RTE_LIBRTE_AXGBE_PMD=n
+CONFIG_RTE_LIBRTE_AXGBE_PMD_DEBUG=n
+# Compile burst-oriented Broadcom PMD driver
+CONFIG_RTE_LIBRTE_BNX2X_PMD=n
+CONFIG_RTE_LIBRTE_BNX2X_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_BNX2X_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_BNX2X_MF_SUPPORT=n
+CONFIG_RTE_LIBRTE_BNX2X_DEBUG_PERIODIC=n
+# Compile burst-oriented Broadcom BNXT PMD driver
+CONFIG_RTE_LIBRTE_BNXT_PMD=n
+# Compile burst-oriented Chelsio Terminator (CXGBE) PMD
+CONFIG_RTE_LIBRTE_CXGBE_PMD=n
+CONFIG_RTE_LIBRTE_CXGBE_DEBUG=n
+CONFIG_RTE_LIBRTE_CXGBE_DEBUG_REG=n
+CONFIG_RTE_LIBRTE_CXGBE_DEBUG_MBOX=n
+CONFIG_RTE_LIBRTE_CXGBE_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_CXGBE_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_CXGBE_TPUT=y
+# NXP DPAA Bus
+CONFIG_RTE_LIBRTE_DPAA_BUS=n
+CONFIG_RTE_LIBRTE_DPAA_MEMPOOL=n
+CONFIG_RTE_LIBRTE_DPAA_PMD=n
+CONFIG_RTE_LIBRTE_DPAA_HWDEBUG=n
+# Compile NXP DPAA2 FSL-MC Bus
+CONFIG_RTE_LIBRTE_FSLMC_BUS=n
+# Compile Support Libraries for NXP DPAA2
+CONFIG_RTE_LIBRTE_DPAA2_MEMPOOL=n
+CONFIG_RTE_LIBRTE_DPAA2_USE_PHYS_IOVA=y
+# Compile burst-oriented NXP DPAA2 PMD driver
+CONFIG_RTE_LIBRTE_DPAA2_PMD=n
+CONFIG_RTE_LIBRTE_DPAA2_DEBUG_DRIVER=n
+# Compile NXP ENETC PMD Driver
+CONFIG_RTE_LIBRTE_ENETC_PMD=n
+# Compile burst-oriented Amazon ENA PMD driver
+CONFIG_RTE_LIBRTE_ENA_PMD=n
+CONFIG_RTE_LIBRTE_ENA_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_ENA_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_ENA_DEBUG_TX_FREE=n
+CONFIG_RTE_LIBRTE_ENA_COM_DEBUG=n
+# Compile burst-oriented Cisco ENIC PMD driver
+CONFIG_RTE_LIBRTE_ENIC_PMD=n
+# Compile burst-oriented IGB & EM PMD drivers
+CONFIG_RTE_LIBRTE_EM_PMD=n
+CONFIG_RTE_LIBRTE_IGB_PMD=n
+CONFIG_RTE_LIBRTE_E1000_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_E1000_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_E1000_DEBUG_TX_FREE=n
+CONFIG_RTE_LIBRTE_E1000_PF_DISABLE_STRIP_CRC=n
+# Compile burst-oriented IXGBE PMD driver
+CONFIG_RTE_LIBRTE_IXGBE_PMD=n
+CONFIG_RTE_LIBRTE_IXGBE_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_IXGBE_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_IXGBE_DEBUG_TX_FREE=n
+CONFIG_RTE_LIBRTE_IXGBE_PF_DISABLE_STRIP_CRC=n
+CONFIG_RTE_IXGBE_INC_VECTOR=y
+CONFIG_RTE_LIBRTE_IXGBE_BYPASS=n
+# Compile burst-oriented I40E PMD driver
+CONFIG_RTE_LIBRTE_I40E_PMD=y
+CONFIG_RTE_LIBRTE_I40E_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_I40E_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_I40E_DEBUG_TX_FREE=n
+CONFIG_RTE_LIBRTE_I40E_RX_ALLOW_BULK_ALLOC=y
+CONFIG_RTE_LIBRTE_I40E_INC_VECTOR=y
+CONFIG_RTE_LIBRTE_I40E_16BYTE_RX_DESC=n
+CONFIG_RTE_LIBRTE_I40E_QUEUE_NUM_PER_PF=64
+CONFIG_RTE_LIBRTE_I40E_QUEUE_NUM_PER_VM=4
+# Compile burst-oriented FM10K PMD
+CONFIG_RTE_LIBRTE_FM10K_PMD=n
+CONFIG_RTE_LIBRTE_FM10K_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_FM10K_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_FM10K_DEBUG_TX_FREE=n
+CONFIG_RTE_LIBRTE_FM10K_RX_OLFLAGS_ENABLE=y
+CONFIG_RTE_LIBRTE_FM10K_INC_VECTOR=y
+# Compile burst-oriented AVF PMD driver
+CONFIG_RTE_LIBRTE_AVF_PMD=n
+CONFIG_RTE_LIBRTE_AVF_INC_VECTOR=y
+CONFIG_RTE_LIBRTE_AVF_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_AVF_DEBUG_TX_FREE=n
+CONFIG_RTE_LIBRTE_AVF_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_AVF_16BYTE_RX_DESC=n
+# Compile burst-oriented Mellanox ConnectX-3 (MLX4) PMD
+CONFIG_RTE_LIBRTE_MLX4_PMD=n
+CONFIG_RTE_LIBRTE_MLX4_DEBUG=n
+CONFIG_RTE_LIBRTE_MLX4_DLOPEN_DEPS=n
+# Compile burst-oriented Mellanox ConnectX-4, ConnectX-5 & Bluefield
+# (MLX5) PMD
+CONFIG_RTE_LIBRTE_MLX5_PMD=n
+CONFIG_RTE_LIBRTE_MLX5_DEBUG=n
+CONFIG_RTE_LIBRTE_MLX5_DLOPEN_DEPS=n
+# Compile burst-oriented Netronome NFP PMD driver
+CONFIG_RTE_LIBRTE_NFP_PMD=n
+CONFIG_RTE_LIBRTE_NFP_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_NFP_DEBUG_RX=n
+# QLogic 10G/25G/40G/50G/100G PMD
+CONFIG_RTE_LIBRTE_QEDE_PMD=n
+CONFIG_RTE_LIBRTE_QEDE_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_QEDE_DEBUG_RX=n
+#Provides abs path/name of architecture we compile for. firmware file.
+#Empty string denotes driver will use default firmware
+CONFIG_RTE_LIBRTE_QEDE_FW=""
+# Compile burst-oriented Solarflare libefx-based PMD
+CONFIG_RTE_LIBRTE_SFC_EFX_PMD=n
+CONFIG_RTE_LIBRTE_SFC_EFX_DEBUG=n
+# Compile software PMD backed by SZEDATA2 device
+CONFIG_RTE_LIBRTE_PMD_SZEDATA2=n
+# Compile burst-oriented Cavium Thunderx NICVF PMD driver
+CONFIG_RTE_LIBRTE_THUNDERX_NICVF_PMD=n
+CONFIG_RTE_LIBRTE_THUNDERX_NICVF_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_THUNDERX_NICVF_DEBUG_TX=n
+# Compile burst-oriented Cavium LiquidIO PMD driver
+CONFIG_RTE_LIBRTE_LIO_PMD=n
+CONFIG_RTE_LIBRTE_LIO_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_LIO_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_LIO_DEBUG_MBOX=n
+CONFIG_RTE_LIBRTE_LIO_DEBUG_REGS=n
+# Compile burst-oriented Cavium OCTEONTX network PMD driver
+CONFIG_RTE_LIBRTE_OCTEONTX_PMD=n
+# Compile WRS accelerated virtual port (AVP) guest PMD driver
+CONFIG_RTE_LIBRTE_AVP_PMD=n
+CONFIG_RTE_LIBRTE_AVP_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_AVP_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_AVP_DEBUG_BUFFERS=n
+# Compile burst-oriented VIRTIO PMD driver
+CONFIG_RTE_LIBRTE_VIRTIO_PMD=y
+CONFIG_RTE_LIBRTE_VIRTIO_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_VIRTIO_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_VIRTIO_DEBUG_DUMP=n
+# Compile virtio device emulation inside virtio PMD driver
+CONFIG_RTE_VIRTIO_USER=n
+# Compile burst-oriented VMXNET3 PMD driver
+CONFIG_RTE_LIBRTE_VMXNET3_PMD=n
+CONFIG_RTE_LIBRTE_VMXNET3_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_VMXNET3_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_VMXNET3_DEBUG_TX_FREE=n
+# Compile software PMD backed by AF_PACKET sockets (Linux only)
+CONFIG_RTE_LIBRTE_PMD_AF_PACKET=n
+# Compile link bonding PMD library
+CONFIG_RTE_LIBRTE_PMD_BOND=n
+CONFIG_RTE_LIBRTE_BOND_DEBUG_ALB=n
+CONFIG_RTE_LIBRTE_BOND_DEBUG_ALB_L1=n
+# Compile fail-safe PMD
+CONFIG_RTE_LIBRTE_PMD_FAILSAFE=y
+# Compile Marvell PMD driver
+CONFIG_RTE_LIBRTE_MVPP2_PMD=n
+# Compile Marvell MVNETA PMD driver
+CONFIG_RTE_LIBRTE_MVNETA_PMD=n
+# Compile support for VMBus library
+CONFIG_RTE_LIBRTE_VMBUS=n
+# Compile native PMD for Hyper-V/Azure
+CONFIG_RTE_LIBRTE_NETVSC_PMD=n
+CONFIG_RTE_LIBRTE_NETVSC_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_NETVSC_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_NETVSC_DEBUG_DUMP=n
+# Compile virtual device driver for NetVSC on Hyper-V/Azure
+CONFIG_RTE_LIBRTE_VDEV_NETVSC_PMD=n
+# Compile null PMD
+CONFIG_RTE_LIBRTE_PMD_NULL=n
+# Compile software PMD backed by PCAP files
+CONFIG_RTE_LIBRTE_PMD_PCAP=n
+# Compile example software rings based PMD
+CONFIG_RTE_LIBRTE_PMD_RING=y
+CONFIG_RTE_PMD_RING_MAX_RX_RINGS=16
+CONFIG_RTE_PMD_RING_MAX_TX_RINGS=16
+# Compile SOFTNIC PMD
+CONFIG_RTE_LIBRTE_PMD_SOFTNIC=n
+# Compile architecture we compile for. TAP PMD
+# It is enabled by default for Linux only.
+CONFIG_RTE_LIBRTE_PMD_TAP=y
+# Do prefetch of packet data within PMD driver receive function
+CONFIG_RTE_PMD_PACKET_PREFETCH=y
+# Compile generic wireless base band device library
+# EXPERIMENTAL: API may change without prior notice
+CONFIG_RTE_LIBRTE_BBDEV=n
+CONFIG_RTE_BBDEV_MAX_DEVS=128
+CONFIG_RTE_BBDEV_OFFLOAD_COST=n
+# Compile PMD for NULL bbdev device
+CONFIG_RTE_LIBRTE_PMD_BBDEV_NULL=y
+# Compile PMD for turbo software bbdev device
+CONFIG_RTE_LIBRTE_PMD_BBDEV_TURBO_SW=n
+# Compile generic crypto device library
+CONFIG_RTE_LIBRTE_CRYPTODEV=n
+CONFIG_RTE_CRYPTO_MAX_DEVS=64
+# Compile PMD for ARMv8 Crypto device
+CONFIG_RTE_LIBRTE_PMD_ARMV8_CRYPTO=n
+CONFIG_RTE_LIBRTE_PMD_ARMV8_CRYPTO_DEBUG=n
+# Compile NXP CAAM JR crypto Driver
+CONFIG_RTE_LIBRTE_PMD_CAAM_JR=n
+CONFIG_RTE_LIBRTE_PMD_CAAM_JR_BE=n
+# Compile NXP DPAA2 crypto sec driver for CAAM HW
+CONFIG_RTE_LIBRTE_PMD_DPAA2_SEC=n
+# NXP DPAA caam - crypto driver
+CONFIG_RTE_LIBRTE_PMD_DPAA_SEC=n
+CONFIG_RTE_LIBRTE_DPAA_MAX_CRYPTODEV=4
+# Compile PMD for Cavium OCTEON TX crypto device
+CONFIG_RTE_LIBRTE_PMD_OCTEONTX_CRYPTO=y
+# Compile PMD for QuickAssist based devices - see docs for details
+CONFIG_RTE_LIBRTE_PMD_QAT=n
+CONFIG_RTE_LIBRTE_PMD_QAT_SYM=n
+# Max. number of QuickAssist devices, which can be detected and attached
+CONFIG_RTE_PMD_QAT_MAX_PCI_DEVICES=48
+CONFIG_RTE_PMD_QAT_COMP_SGL_MAX_SEGMENTS=16
+CONFIG_RTE_PMD_QAT_COMP_IM_BUFFER_SIZE=65536
+# Compile PMD for virtio crypto devices
+CONFIG_RTE_LIBRTE_PMD_VIRTIO_CRYPTO=n
+# Number of maximum virtio crypto devices
+CONFIG_RTE_MAX_VIRTIO_CRYPTO=32
+# Compile PMD for AESNI backed device
+CONFIG_RTE_LIBRTE_PMD_AESNI_MB=n
+# Compile PMD for Software backed device
+CONFIG_RTE_LIBRTE_PMD_OPENSSL=n
+# Compile PMD for AESNI GCM device
+CONFIG_RTE_LIBRTE_PMD_AESNI_GCM=n
+# Compile PMD for SNOW 3G device
+CONFIG_RTE_LIBRTE_PMD_SNOW3G=n
+CONFIG_RTE_LIBRTE_PMD_SNOW3G_DEBUG=n
+# Compile PMD for KASUMI device
+CONFIG_RTE_LIBRTE_PMD_KASUMI=n
+# Compile PMD for ZUC device
+CONFIG_RTE_LIBRTE_PMD_ZUC=n
+# Compile PMD for Crypto Scheduler device
+CONFIG_RTE_LIBRTE_PMD_CRYPTO_SCHEDULER=n
+# Compile PMD for NULL Crypto device
+CONFIG_RTE_LIBRTE_PMD_NULL_CRYPTO=n
+# Compile PMD for AMD CCP crypto device
+CONFIG_RTE_LIBRTE_PMD_CCP=n
+# Compile PMD for Marvell Crypto device
+CONFIG_RTE_LIBRTE_PMD_MVSAM_CRYPTO=n
+# Compile generic security library
+CONFIG_RTE_LIBRTE_SECURITY=n
+# Compile generic compression device library
+CONFIG_RTE_LIBRTE_COMPRESSDEV=n
+CONFIG_RTE_COMPRESS_MAX_DEVS=64
+# Compile compressdev unit test
+CONFIG_RTE_COMPRESSDEV_TEST=n
+# Compile PMD for Octeontx ZIPVF compression device
+CONFIG_RTE_LIBRTE_PMD_OCTEONTX_ZIPVF=n
+# Compile PMD for ISA-L compression device
+CONFIG_RTE_LIBRTE_PMD_ISAL=n
+# Compile PMD for ZLIB compression device
+CONFIG_RTE_LIBRTE_PMD_ZLIB=n
+# Compile generic event device library
+CONFIG_RTE_LIBRTE_EVENTDEV=n
+CONFIG_RTE_LIBRTE_EVENTDEV_DEBUG=n
+CONFIG_RTE_EVENT_MAX_DEVS=16
+CONFIG_RTE_EVENT_MAX_QUEUES_PER_DEV=64
+CONFIG_RTE_EVENT_TIMER_ADAPTER_NUM_MAX=32
+CONFIG_RTE_EVENT_ETH_INTR_RING_SIZE=1024
+CONFIG_RTE_EVENT_CRYPTO_ADAPTER_MAX_INSTANCE=32
+CONFIG_RTE_EVENT_ETH_TX_ADAPTER_MAX_INSTANCE=32
+# Compile PMD for skeleton event device
+CONFIG_RTE_LIBRTE_PMD_SKELETON_EVENTDEV=n
+CONFIG_RTE_LIBRTE_PMD_SKELETON_EVENTDEV_DEBUG=n
+# Compile PMD for software event device
+CONFIG_RTE_LIBRTE_PMD_SW_EVENTDEV=n
+# Compile PMD for distributed software event device
+CONFIG_RTE_LIBRTE_PMD_DSW_EVENTDEV=n
+# Compile PMD for octeontx sso event device
+CONFIG_RTE_LIBRTE_PMD_OCTEONTX_SSOVF=n
+# Compile PMD for OPDL event device
+CONFIG_RTE_LIBRTE_PMD_OPDL_EVENTDEV=n
+# Compile PMD for NXP DPAA event device
+CONFIG_RTE_LIBRTE_PMD_DPAA_EVENTDEV=n
+# Compile PMD for NXP DPAA2 event device
+CONFIG_RTE_LIBRTE_PMD_DPAA2_EVENTDEV=n
+# Compile raw device support
+# EXPERIMENTAL: API may change without prior notice
+CONFIG_RTE_LIBRTE_RAWDEV=n
+CONFIG_RTE_RAWDEV_MAX_DEVS=10
+CONFIG_RTE_LIBRTE_PMD_SKELETON_RAWDEV=n
+# Compile PMD for NXP DPAA2 CMDIF raw device
+CONFIG_RTE_LIBRTE_PMD_DPAA2_CMDIF_RAWDEV=n
+# Compile PMD for NXP DPAA2 QDMA raw device
+CONFIG_RTE_LIBRTE_PMD_DPAA2_QDMA_RAWDEV=n
+# Compile PMD for Intel FPGA raw device
+CONFIG_RTE_LIBRTE_PMD_IFPGA_RAWDEV=n
+# Compile librte_ring
+CONFIG_RTE_LIBRTE_RING=y
+# Compile librte_mempool
+CONFIG_RTE_LIBRTE_MEMPOOL=y
+CONFIG_RTE_MEMPOOL_CACHE_MAX_SIZE=512
+CONFIG_RTE_LIBRTE_MEMPOOL_DEBUG=n
+# Compile Mempool drivers
+CONFIG_RTE_DRIVER_MEMPOOL_BUCKET=y
+CONFIG_RTE_DRIVER_MEMPOOL_BUCKET_SIZE_KB=64
+CONFIG_RTE_DRIVER_MEMPOOL_RING=y
+CONFIG_RTE_DRIVER_MEMPOOL_STACK=y
+# Compile PMD for octeontx fpa mempool device
+CONFIG_RTE_LIBRTE_OCTEONTX_MEMPOOL=n
+# Compile librte_mbuf
+CONFIG_RTE_LIBRTE_MBUF=y
+CONFIG_RTE_LIBRTE_MBUF_DEBUG=n
+CONFIG_RTE_MBUF_DEFAULT_MEMPOOL_OPS="ring_mp_mc"
+CONFIG_RTE_MBUF_REFCNT_ATOMIC=y
+CONFIG_RTE_PKTMBUF_HEADROOM=128
+# Compile librte_timer
+CONFIG_RTE_LIBRTE_TIMER=n
+CONFIG_RTE_LIBRTE_TIMER_DEBUG=n
+# Compile librte_cfgfile
+CONFIG_RTE_LIBRTE_CFGFILE=n
+# Compile librte_cmdline
+CONFIG_RTE_LIBRTE_CMDLINE=y
+CONFIG_RTE_LIBRTE_CMDLINE_DEBUG=n
+# Compile librte_hash
+CONFIG_RTE_LIBRTE_HASH=y
+CONFIG_RTE_LIBRTE_HASH_DEBUG=n
+# Compile librte_efd
+CONFIG_RTE_LIBRTE_EFD=n
+# Compile librte_member
+CONFIG_RTE_LIBRTE_MEMBER=y
+# Compile librte_jobstats
+CONFIG_RTE_LIBRTE_JOBSTATS=n
+# Compile architecture we compile for. device metrics library
+CONFIG_RTE_LIBRTE_METRICS=y
+# Compile architecture we compile for. bitrate statistics library
+CONFIG_RTE_LIBRTE_BITRATE=y
+# Compile architecture we compile for. latency statistics library
+CONFIG_RTE_LIBRTE_LATENCY_STATS=y
+# Compile librte_telemetry
+CONFIG_RTE_LIBRTE_TELEMETRY=n
+# Compile librte_lpm
+CONFIG_RTE_LIBRTE_LPM=n
+CONFIG_RTE_LIBRTE_LPM_DEBUG=n
+# Compile librte_acl
+CONFIG_RTE_LIBRTE_ACL=n
+CONFIG_RTE_LIBRTE_ACL_DEBUG=n
+# Compile librte_power
+CONFIG_RTE_LIBRTE_POWER=n
+CONFIG_RTE_LIBRTE_POWER_DEBUG=n
+CONFIG_RTE_MAX_LCORE_FREQS=64
+# Compile librte_net
+CONFIG_RTE_LIBRTE_NET=y
+# Compile librte_ip_frag
+CONFIG_RTE_LIBRTE_IP_FRAG=y
+CONFIG_RTE_LIBRTE_IP_FRAG_DEBUG=n
+CONFIG_RTE_LIBRTE_IP_FRAG_MAX_FRAG=4
+CONFIG_RTE_LIBRTE_IP_FRAG_TBL_STAT=n
+# Compile GRO library
+CONFIG_RTE_LIBRTE_GRO=y
+# Compile GSO library
+CONFIG_RTE_LIBRTE_GSO=y
+# Compile librte_meter
+CONFIG_RTE_LIBRTE_METER=y
+# Compile librte_classify
+CONFIG_RTE_LIBRTE_FLOW_CLASSIFY=n
+# Compile librte_sched
+CONFIG_RTE_LIBRTE_SCHED=n
+CONFIG_RTE_SCHED_DEBUG=n
+CONFIG_RTE_SCHED_RED=n
+CONFIG_RTE_SCHED_COLLECT_STATS=n
+CONFIG_RTE_SCHED_SUBPORT_TC_OV=n
+CONFIG_RTE_SCHED_PORT_N_GRINDERS=8
+CONFIG_RTE_SCHED_VECTOR=n
+# Compile architecture we compile for. distributor library
+CONFIG_RTE_LIBRTE_DISTRIBUTOR=n
+# Compile architecture we compile for. reorder library
+CONFIG_RTE_LIBRTE_REORDER=n
+# Compile librte_port
+CONFIG_RTE_LIBRTE_PORT=n
+CONFIG_RTE_PORT_STATS_COLLECT=n
+CONFIG_RTE_PORT_PCAP=n
+# Compile librte_table
+CONFIG_RTE_LIBRTE_TABLE=n
+CONFIG_RTE_TABLE_STATS_COLLECT=n
+# Compile librte_pipeline
+CONFIG_RTE_LIBRTE_PIPELINE=n
+CONFIG_RTE_PIPELINE_STATS_COLLECT=n
+# Compile librte_kni
+CONFIG_RTE_LIBRTE_KNI=n
+CONFIG_RTE_LIBRTE_PMD_KNI=n
+CONFIG_RTE_KNI_KMOD=n
+CONFIG_RTE_KNI_KMOD_ETHTOOL=n
+CONFIG_RTE_KNI_PREEMPT_DEFAULT=y
+# Compile architecture we compile for. pdump library
+CONFIG_RTE_LIBRTE_PDUMP=y
+# Compile vhost user library
+CONFIG_RTE_LIBRTE_VHOST=y
+CONFIG_RTE_LIBRTE_VHOST_NUMA=y
+CONFIG_RTE_LIBRTE_VHOST_DEBUG=n
+# Compile vhost PMD
+# To compile, CONFIG_RTE_LIBRTE_VHOST should be enabled.
+CONFIG_RTE_LIBRTE_PMD_VHOST=y
+# Compile IFC driver
+# To compile, CONFIG_RTE_LIBRTE_VHOST and CONFIG_RTE_EAL_VFIO
+# should be enabled.
+CONFIG_RTE_LIBRTE_IFC_PMD=n
+# Compile librte_bpf
+CONFIG_RTE_LIBRTE_BPF=n
+# allow load BPF from ELF files (requires libelf)
+CONFIG_RTE_LIBRTE_BPF_ELF=n
+# Compile architecture we compile for. test application
+CONFIG_RTE_APP_TEST=y
+CONFIG_RTE_APP_TEST_RESOURCE_TAR=n
+# Compile architecture we compile for. procinfo application
+CONFIG_RTE_PROC_INFO=y
+# Compile architecture we compile for. PMD test application
+CONFIG_RTE_TEST_PMD=n
+CONFIG_RTE_TEST_PMD_RECORD_CORE_CYCLES=n
+CONFIG_RTE_TEST_PMD_RECORD_BURST_STATS=n
+# Compile architecture we compile for. bbdev test application
+CONFIG_RTE_TEST_BBDEV=n
+# Compile architecture we compile for. crypto performance application
+CONFIG_RTE_APP_CRYPTO_PERF=n
+# Compile architecture we compile for. eventdev application
+CONFIG_RTE_APP_EVENTDEV=n
+CONFIG_RTE_EXEC_ENV_LINUXAPP=y
+CONFIG_RTE_LIBRTE_VHOST_POSTCOPY=n
+# Common libraries, before Bus/PMDs
+# NXP DPAA BUS and drivers
+# NXP FSLMC BUS and DPAA2 drivers
+# NXP ENETC PMD Driver
+CONFIG_RTE_ARCH_PPC_64=y
+CONFIG_RTE_ARCH_64=y
+CONFIG_RTE_TOOLCHAIN_GCC=y
+# Note: Power doesn't have this support
+# Note: Initially, all of architecture we compile for. PMD drivers compilation are turned off on Power
+# Will turn on them only after architecture we compile for. successful testing on Power
+CONFIG_RTE_LIBRTE_PMD_XENVIRT=n
diff --git a/SOURCES/set_config.sh b/SOURCES/set_config.sh
new file mode 100755
index 0000000..002386b
--- /dev/null
+++ b/SOURCES/set_config.sh
@@ -0,0 +1,48 @@
+#!/bin/bash
+# Copyright (C) 2017, Red Hat, Inc.
+#
+# set_config.sh will copy a configuration from $1 to $2, in the process
+# checking that the sha header for $1 matches the header in $2
+
+source configlib.sh
+
+if (( $# < 2 )); then
+ echo "$0: source dest [comment-marker]"
+ exit 1
+fi
+
+if [ ! -f "$1" ]; then
+ echo "Source file $1 must exist."
+ exit 1
+fi
+src_file=$1
+shift
+
+if [ ! -f "$1" ]; then
+ echo "Dest file $1 must exist."
+ exit 1
+fi
+dst_file=$1
+shift
+
+comment_sep=${1:-#}
+
+export LANG=en_US.utf8
+
+DEST_FILE_SHA=""
+SRC_FILE_SHA=""
+
+calc_sha DEST_FILE_SHA "$dst_file" "$comment_sep" || echo "Failed to calc sha"
+retr_sha SRC_FILE_SHA "$src_file" "$comment_sep" || echo "Failed to retrieve sha"
+
+if [ "$DEST_FILE_SHA" != "$SRC_FILE_SHA" ]; then
+ echo "ERROR: The requisite starting sha from $dst_file does not match the"
+ echo " specified sha in $src_file."
+ echo "[ $DEST_FILE_SHA ] vs [ $SRC_FILE_SHA ]"
+ exit 1
+fi
+
+mv "$dst_file" "$dst_file".OLD
+cp "$src_file" "$dst_file"
+echo "copied 1 config file."
+exit 0
diff --git a/SOURCES/x86_64-native-linuxapp-gcc-config b/SOURCES/x86_64-native-linuxapp-gcc-config
new file mode 100644
index 0000000..4b7a7ea
--- /dev/null
+++ b/SOURCES/x86_64-native-linuxapp-gcc-config
@@ -0,0 +1,525 @@
+# -*- cfg-sha: 2ba93102021dc5d38494cf5090c3ecaca37db13153dd558b1511a56f2a3d9b10
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2010-2014 Intel Corporation
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2010-2016 Intel Corporation
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2010-2017 Intel Corporation
+# RTE_EXEC_ENV values are the directories in mk/exec-env/
+CONFIG_RTE_EXEC_ENV="linuxapp"
+# RTE_ARCH values are architecture we compile for. directories in mk/arch/
+CONFIG_RTE_ARCH="x86_64"
+# machine can define specific variables or action for a specific board
+# RTE_MACHINE values are architecture we compile for. directories in mk/machine/
+CONFIG_RTE_MACHINE="default"
+# The compiler we use.
+# RTE_TOOLCHAIN values are architecture we compile for. directories in mk/toolchain/
+CONFIG_RTE_TOOLCHAIN="gcc"
+# Use intrinsics or assembly code for key routines
+CONFIG_RTE_FORCE_INTRINSICS=n
+# Machine forces strict alignment constraints.
+CONFIG_RTE_ARCH_STRICT_ALIGN=n
+# Compile to share library
+CONFIG_RTE_BUILD_SHARED_LIB=n
+# Use newest code breaking previous ABI
+CONFIG_RTE_NEXT_ABI=n
+# Major ABI to overwrite library specific LIBABIVER
+CONFIG_RTE_MAJOR_ABI=
+# Machine's cache line size
+CONFIG_RTE_CACHE_LINE_SIZE=64
+# Memory model
+CONFIG_RTE_USE_C11_MEM_MODEL=n
+# Compile Environment Abstraction Layer
+CONFIG_RTE_LIBRTE_EAL=y
+CONFIG_RTE_MAX_LCORE=128
+CONFIG_RTE_MAX_NUMA_NODES=8
+CONFIG_RTE_MAX_HEAPS=32
+CONFIG_RTE_MAX_MEMSEG_LISTS=64
+# each memseg list will be limited to either RTE_MAX_MEMSEG_PER_LIST pages
+# or RTE_MAX_MEM_MB_PER_LIST megabytes worth of memory, whichever is smaller
+CONFIG_RTE_MAX_MEMSEG_PER_LIST=8192
+CONFIG_RTE_MAX_MEM_MB_PER_LIST=32768
+# a "type" is a combination of page size and NUMA node. total number of memseg
+# lists per type will be limited to either RTE_MAX_MEMSEG_PER_TYPE pages (split
+# over multiple lists of RTE_MAX_MEMSEG_PER_LIST pages), or
+# RTE_MAX_MEM_MB_PER_TYPE megabytes of memory (split over multiple lists of
+# RTE_MAX_MEM_MB_PER_LIST), whichever is smaller
+CONFIG_RTE_MAX_MEMSEG_PER_TYPE=32768
+CONFIG_RTE_MAX_MEM_MB_PER_TYPE=131072
+# global maximum usable amount of VA, in megabytes
+CONFIG_RTE_MAX_MEM_MB=524288
+CONFIG_RTE_MAX_MEMZONE=2560
+CONFIG_RTE_MAX_TAILQ=32
+CONFIG_RTE_ENABLE_ASSERT=n
+CONFIG_RTE_LOG_DP_LEVEL=RTE_LOG_INFO
+CONFIG_RTE_LOG_HISTORY=256
+CONFIG_RTE_BACKTRACE=y
+CONFIG_RTE_LIBEAL_USE_HPET=n
+CONFIG_RTE_EAL_ALLOW_INV_SOCKET_ID=n
+CONFIG_RTE_EAL_ALWAYS_PANIC_ON_ERROR=n
+CONFIG_RTE_EAL_IGB_UIO=n
+CONFIG_RTE_EAL_VFIO=y
+CONFIG_RTE_MAX_VFIO_GROUPS=64
+CONFIG_RTE_MAX_VFIO_CONTAINERS=64
+CONFIG_RTE_MALLOC_DEBUG=n
+CONFIG_RTE_EAL_NUMA_AWARE_HUGEPAGES=y
+CONFIG_RTE_USE_LIBBSD=n
+# Recognize/ignore architecture we compile for. AVX/AVX512 CPU flags for performance/power testing.
+# AVX512 is marked as experimental for now, will enable it after enough
+# field test and possible optimization.
+CONFIG_RTE_ENABLE_AVX=y
+CONFIG_RTE_ENABLE_AVX512=n
+# Default driver path (or "" to disable)
+CONFIG_RTE_EAL_PMD_PATH=""
+# Compile Environment Abstraction Layer to support Vmware TSC map
+CONFIG_RTE_LIBRTE_EAL_VMWARE_TSC_MAP_SUPPORT=y
+# Compile architecture we compile for. PCI library
+CONFIG_RTE_LIBRTE_PCI=y
+# Compile architecture we compile for. argument parser library
+CONFIG_RTE_LIBRTE_KVARGS=y
+# Compile generic ethernet library
+CONFIG_RTE_LIBRTE_ETHER=y
+CONFIG_RTE_LIBRTE_ETHDEV_DEBUG=n
+CONFIG_RTE_MAX_ETHPORTS=32
+CONFIG_RTE_MAX_QUEUES_PER_PORT=1024
+CONFIG_RTE_LIBRTE_IEEE1588=n
+CONFIG_RTE_ETHDEV_QUEUE_STAT_CNTRS=16
+CONFIG_RTE_ETHDEV_RXTX_CALLBACKS=y
+CONFIG_RTE_ETHDEV_PROFILE_WITH_VTUNE=n
+# Turn off Tx preparation stage
+# Warning: rte_eth_tx_prepare() can be safely disabled only if using a
+# driver which do not implement any Tx preparation.
+CONFIG_RTE_ETHDEV_TX_PREPARE_NOOP=n
+# Common libraries, before Bus/PMDs
+CONFIG_RTE_LIBRTE_COMMON_DPAAX=n
+# Compile architecture we compile for. Intel FPGA bus
+CONFIG_RTE_LIBRTE_IFPGA_BUS=n
+# Compile PCI bus driver
+CONFIG_RTE_LIBRTE_PCI_BUS=y
+# Compile architecture we compile for. vdev bus
+CONFIG_RTE_LIBRTE_VDEV_BUS=y
+# Compile ARK PMD
+CONFIG_RTE_LIBRTE_ARK_PMD=n
+CONFIG_RTE_LIBRTE_ARK_PAD_TX=y
+CONFIG_RTE_LIBRTE_ARK_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_ARK_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_ARK_DEBUG_STATS=n
+CONFIG_RTE_LIBRTE_ARK_DEBUG_TRACE=n
+# Compile Aquantia Atlantic PMD driver
+CONFIG_RTE_LIBRTE_ATLANTIC_PMD=n
+# Compile AMD PMD
+CONFIG_RTE_LIBRTE_AXGBE_PMD=n
+CONFIG_RTE_LIBRTE_AXGBE_PMD_DEBUG=n
+# Compile burst-oriented Broadcom PMD driver
+CONFIG_RTE_LIBRTE_BNX2X_PMD=n
+CONFIG_RTE_LIBRTE_BNX2X_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_BNX2X_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_BNX2X_MF_SUPPORT=n
+CONFIG_RTE_LIBRTE_BNX2X_DEBUG_PERIODIC=n
+# Compile burst-oriented Broadcom BNXT PMD driver
+CONFIG_RTE_LIBRTE_BNXT_PMD=y
+# Compile burst-oriented Chelsio Terminator (CXGBE) PMD
+CONFIG_RTE_LIBRTE_CXGBE_PMD=n
+CONFIG_RTE_LIBRTE_CXGBE_DEBUG=n
+CONFIG_RTE_LIBRTE_CXGBE_DEBUG_REG=n
+CONFIG_RTE_LIBRTE_CXGBE_DEBUG_MBOX=n
+CONFIG_RTE_LIBRTE_CXGBE_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_CXGBE_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_CXGBE_TPUT=y
+# NXP DPAA Bus
+CONFIG_RTE_LIBRTE_DPAA_BUS=n
+CONFIG_RTE_LIBRTE_DPAA_MEMPOOL=n
+CONFIG_RTE_LIBRTE_DPAA_PMD=n
+CONFIG_RTE_LIBRTE_DPAA_HWDEBUG=n
+# Compile NXP DPAA2 FSL-MC Bus
+CONFIG_RTE_LIBRTE_FSLMC_BUS=n
+# Compile Support Libraries for NXP DPAA2
+CONFIG_RTE_LIBRTE_DPAA2_MEMPOOL=n
+CONFIG_RTE_LIBRTE_DPAA2_USE_PHYS_IOVA=y
+# Compile burst-oriented NXP DPAA2 PMD driver
+CONFIG_RTE_LIBRTE_DPAA2_PMD=n
+CONFIG_RTE_LIBRTE_DPAA2_DEBUG_DRIVER=n
+# Compile NXP ENETC PMD Driver
+CONFIG_RTE_LIBRTE_ENETC_PMD=n
+# Compile burst-oriented Amazon ENA PMD driver
+CONFIG_RTE_LIBRTE_ENA_PMD=n
+CONFIG_RTE_LIBRTE_ENA_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_ENA_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_ENA_DEBUG_TX_FREE=n
+CONFIG_RTE_LIBRTE_ENA_COM_DEBUG=n
+# Compile burst-oriented Cisco ENIC PMD driver
+CONFIG_RTE_LIBRTE_ENIC_PMD=y
+# Compile burst-oriented IGB & EM PMD drivers
+CONFIG_RTE_LIBRTE_EM_PMD=n
+CONFIG_RTE_LIBRTE_IGB_PMD=y
+CONFIG_RTE_LIBRTE_E1000_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_E1000_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_E1000_DEBUG_TX_FREE=n
+CONFIG_RTE_LIBRTE_E1000_PF_DISABLE_STRIP_CRC=n
+# Compile burst-oriented IXGBE PMD driver
+CONFIG_RTE_LIBRTE_IXGBE_PMD=y
+CONFIG_RTE_LIBRTE_IXGBE_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_IXGBE_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_IXGBE_DEBUG_TX_FREE=n
+CONFIG_RTE_LIBRTE_IXGBE_PF_DISABLE_STRIP_CRC=n
+CONFIG_RTE_IXGBE_INC_VECTOR=y
+CONFIG_RTE_LIBRTE_IXGBE_BYPASS=n
+# Compile burst-oriented I40E PMD driver
+CONFIG_RTE_LIBRTE_I40E_PMD=y
+CONFIG_RTE_LIBRTE_I40E_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_I40E_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_I40E_DEBUG_TX_FREE=n
+CONFIG_RTE_LIBRTE_I40E_RX_ALLOW_BULK_ALLOC=y
+CONFIG_RTE_LIBRTE_I40E_INC_VECTOR=y
+CONFIG_RTE_LIBRTE_I40E_16BYTE_RX_DESC=n
+CONFIG_RTE_LIBRTE_I40E_QUEUE_NUM_PER_PF=64
+CONFIG_RTE_LIBRTE_I40E_QUEUE_NUM_PER_VM=4
+# Compile burst-oriented FM10K PMD
+CONFIG_RTE_LIBRTE_FM10K_PMD=n
+CONFIG_RTE_LIBRTE_FM10K_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_FM10K_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_FM10K_DEBUG_TX_FREE=n
+CONFIG_RTE_LIBRTE_FM10K_RX_OLFLAGS_ENABLE=y
+CONFIG_RTE_LIBRTE_FM10K_INC_VECTOR=y
+# Compile burst-oriented AVF PMD driver
+CONFIG_RTE_LIBRTE_AVF_PMD=n
+CONFIG_RTE_LIBRTE_AVF_INC_VECTOR=y
+CONFIG_RTE_LIBRTE_AVF_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_AVF_DEBUG_TX_FREE=n
+CONFIG_RTE_LIBRTE_AVF_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_AVF_16BYTE_RX_DESC=n
+# Compile burst-oriented Mellanox ConnectX-3 (MLX4) PMD
+CONFIG_RTE_LIBRTE_MLX4_PMD=y
+CONFIG_RTE_LIBRTE_MLX4_DEBUG=n
+CONFIG_RTE_LIBRTE_MLX4_DLOPEN_DEPS=y
+# Compile burst-oriented Mellanox ConnectX-4, ConnectX-5 & Bluefield
+# (MLX5) PMD
+CONFIG_RTE_LIBRTE_MLX5_PMD=y
+CONFIG_RTE_LIBRTE_MLX5_DEBUG=n
+CONFIG_RTE_LIBRTE_MLX5_DLOPEN_DEPS=y
+# Compile burst-oriented Netronome NFP PMD driver
+CONFIG_RTE_LIBRTE_NFP_PMD=y
+CONFIG_RTE_LIBRTE_NFP_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_NFP_DEBUG_RX=n
+# QLogic 10G/25G/40G/50G/100G PMD
+CONFIG_RTE_LIBRTE_QEDE_PMD=y
+CONFIG_RTE_LIBRTE_QEDE_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_QEDE_DEBUG_RX=n
+#Provides abs path/name of architecture we compile for. firmware file.
+#Empty string denotes driver will use default firmware
+CONFIG_RTE_LIBRTE_QEDE_FW=""
+# Compile burst-oriented Solarflare libefx-based PMD
+CONFIG_RTE_LIBRTE_SFC_EFX_PMD=n
+CONFIG_RTE_LIBRTE_SFC_EFX_DEBUG=n
+# Compile software PMD backed by SZEDATA2 device
+CONFIG_RTE_LIBRTE_PMD_SZEDATA2=n
+# Compile burst-oriented Cavium Thunderx NICVF PMD driver
+CONFIG_RTE_LIBRTE_THUNDERX_NICVF_PMD=n
+CONFIG_RTE_LIBRTE_THUNDERX_NICVF_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_THUNDERX_NICVF_DEBUG_TX=n
+# Compile burst-oriented Cavium LiquidIO PMD driver
+CONFIG_RTE_LIBRTE_LIO_PMD=n
+CONFIG_RTE_LIBRTE_LIO_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_LIO_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_LIO_DEBUG_MBOX=n
+CONFIG_RTE_LIBRTE_LIO_DEBUG_REGS=n
+# Compile burst-oriented Cavium OCTEONTX network PMD driver
+CONFIG_RTE_LIBRTE_OCTEONTX_PMD=n
+# Compile WRS accelerated virtual port (AVP) guest PMD driver
+CONFIG_RTE_LIBRTE_AVP_PMD=n
+CONFIG_RTE_LIBRTE_AVP_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_AVP_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_AVP_DEBUG_BUFFERS=n
+# Compile burst-oriented VIRTIO PMD driver
+CONFIG_RTE_LIBRTE_VIRTIO_PMD=y
+CONFIG_RTE_LIBRTE_VIRTIO_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_VIRTIO_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_VIRTIO_DEBUG_DUMP=n
+# Compile virtio device emulation inside virtio PMD driver
+CONFIG_RTE_VIRTIO_USER=n
+# Compile burst-oriented VMXNET3 PMD driver
+CONFIG_RTE_LIBRTE_VMXNET3_PMD=n
+CONFIG_RTE_LIBRTE_VMXNET3_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_VMXNET3_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_VMXNET3_DEBUG_TX_FREE=n
+# Compile software PMD backed by AF_PACKET sockets (Linux only)
+CONFIG_RTE_LIBRTE_PMD_AF_PACKET=n
+# Compile link bonding PMD library
+CONFIG_RTE_LIBRTE_PMD_BOND=n
+CONFIG_RTE_LIBRTE_BOND_DEBUG_ALB=n
+CONFIG_RTE_LIBRTE_BOND_DEBUG_ALB_L1=n
+# Compile fail-safe PMD
+CONFIG_RTE_LIBRTE_PMD_FAILSAFE=y
+# Compile Marvell PMD driver
+CONFIG_RTE_LIBRTE_MVPP2_PMD=n
+# Compile Marvell MVNETA PMD driver
+CONFIG_RTE_LIBRTE_MVNETA_PMD=n
+# Compile support for VMBus library
+CONFIG_RTE_LIBRTE_VMBUS=y
+# Compile native PMD for Hyper-V/Azure
+CONFIG_RTE_LIBRTE_NETVSC_PMD=y
+CONFIG_RTE_LIBRTE_NETVSC_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_NETVSC_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_NETVSC_DEBUG_DUMP=n
+# Compile virtual device driver for NetVSC on Hyper-V/Azure
+CONFIG_RTE_LIBRTE_VDEV_NETVSC_PMD=y
+# Compile null PMD
+CONFIG_RTE_LIBRTE_PMD_NULL=n
+# Compile software PMD backed by PCAP files
+CONFIG_RTE_LIBRTE_PMD_PCAP=n
+# Compile example software rings based PMD
+CONFIG_RTE_LIBRTE_PMD_RING=y
+CONFIG_RTE_PMD_RING_MAX_RX_RINGS=16
+CONFIG_RTE_PMD_RING_MAX_TX_RINGS=16
+# Compile SOFTNIC PMD
+CONFIG_RTE_LIBRTE_PMD_SOFTNIC=n
+# Compile architecture we compile for. TAP PMD
+# It is enabled by default for Linux only.
+CONFIG_RTE_LIBRTE_PMD_TAP=y
+# Do prefetch of packet data within PMD driver receive function
+CONFIG_RTE_PMD_PACKET_PREFETCH=y
+# Compile generic wireless base band device library
+# EXPERIMENTAL: API may change without prior notice
+CONFIG_RTE_LIBRTE_BBDEV=n
+CONFIG_RTE_BBDEV_MAX_DEVS=128
+CONFIG_RTE_BBDEV_OFFLOAD_COST=n
+# Compile PMD for NULL bbdev device
+CONFIG_RTE_LIBRTE_PMD_BBDEV_NULL=y
+# Compile PMD for turbo software bbdev device
+CONFIG_RTE_LIBRTE_PMD_BBDEV_TURBO_SW=n
+# Compile generic crypto device library
+CONFIG_RTE_LIBRTE_CRYPTODEV=n
+CONFIG_RTE_CRYPTO_MAX_DEVS=64
+# Compile PMD for ARMv8 Crypto device
+CONFIG_RTE_LIBRTE_PMD_ARMV8_CRYPTO=n
+CONFIG_RTE_LIBRTE_PMD_ARMV8_CRYPTO_DEBUG=n
+# Compile NXP CAAM JR crypto Driver
+CONFIG_RTE_LIBRTE_PMD_CAAM_JR=n
+CONFIG_RTE_LIBRTE_PMD_CAAM_JR_BE=n
+# Compile NXP DPAA2 crypto sec driver for CAAM HW
+CONFIG_RTE_LIBRTE_PMD_DPAA2_SEC=n
+# NXP DPAA caam - crypto driver
+CONFIG_RTE_LIBRTE_PMD_DPAA_SEC=n
+CONFIG_RTE_LIBRTE_DPAA_MAX_CRYPTODEV=4
+# Compile PMD for Cavium OCTEON TX crypto device
+CONFIG_RTE_LIBRTE_PMD_OCTEONTX_CRYPTO=y
+# Compile PMD for QuickAssist based devices - see docs for details
+CONFIG_RTE_LIBRTE_PMD_QAT=n
+CONFIG_RTE_LIBRTE_PMD_QAT_SYM=n
+# Max. number of QuickAssist devices, which can be detected and attached
+CONFIG_RTE_PMD_QAT_MAX_PCI_DEVICES=48
+CONFIG_RTE_PMD_QAT_COMP_SGL_MAX_SEGMENTS=16
+CONFIG_RTE_PMD_QAT_COMP_IM_BUFFER_SIZE=65536
+# Compile PMD for virtio crypto devices
+CONFIG_RTE_LIBRTE_PMD_VIRTIO_CRYPTO=n
+# Number of maximum virtio crypto devices
+CONFIG_RTE_MAX_VIRTIO_CRYPTO=32
+# Compile PMD for AESNI backed device
+CONFIG_RTE_LIBRTE_PMD_AESNI_MB=n
+# Compile PMD for Software backed device
+CONFIG_RTE_LIBRTE_PMD_OPENSSL=n
+# Compile PMD for AESNI GCM device
+CONFIG_RTE_LIBRTE_PMD_AESNI_GCM=n
+# Compile PMD for SNOW 3G device
+CONFIG_RTE_LIBRTE_PMD_SNOW3G=n
+CONFIG_RTE_LIBRTE_PMD_SNOW3G_DEBUG=n
+# Compile PMD for KASUMI device
+CONFIG_RTE_LIBRTE_PMD_KASUMI=n
+# Compile PMD for ZUC device
+CONFIG_RTE_LIBRTE_PMD_ZUC=n
+# Compile PMD for Crypto Scheduler device
+CONFIG_RTE_LIBRTE_PMD_CRYPTO_SCHEDULER=n
+# Compile PMD for NULL Crypto device
+CONFIG_RTE_LIBRTE_PMD_NULL_CRYPTO=n
+# Compile PMD for AMD CCP crypto device
+CONFIG_RTE_LIBRTE_PMD_CCP=n
+# Compile PMD for Marvell Crypto device
+CONFIG_RTE_LIBRTE_PMD_MVSAM_CRYPTO=n
+# Compile generic security library
+CONFIG_RTE_LIBRTE_SECURITY=n
+# Compile generic compression device library
+CONFIG_RTE_LIBRTE_COMPRESSDEV=n
+CONFIG_RTE_COMPRESS_MAX_DEVS=64
+# Compile compressdev unit test
+CONFIG_RTE_COMPRESSDEV_TEST=n
+# Compile PMD for Octeontx ZIPVF compression device
+CONFIG_RTE_LIBRTE_PMD_OCTEONTX_ZIPVF=n
+# Compile PMD for ISA-L compression device
+CONFIG_RTE_LIBRTE_PMD_ISAL=n
+# Compile PMD for ZLIB compression device
+CONFIG_RTE_LIBRTE_PMD_ZLIB=n
+# Compile generic event device library
+CONFIG_RTE_LIBRTE_EVENTDEV=n
+CONFIG_RTE_LIBRTE_EVENTDEV_DEBUG=n
+CONFIG_RTE_EVENT_MAX_DEVS=16
+CONFIG_RTE_EVENT_MAX_QUEUES_PER_DEV=64
+CONFIG_RTE_EVENT_TIMER_ADAPTER_NUM_MAX=32
+CONFIG_RTE_EVENT_ETH_INTR_RING_SIZE=1024
+CONFIG_RTE_EVENT_CRYPTO_ADAPTER_MAX_INSTANCE=32
+CONFIG_RTE_EVENT_ETH_TX_ADAPTER_MAX_INSTANCE=32
+# Compile PMD for skeleton event device
+CONFIG_RTE_LIBRTE_PMD_SKELETON_EVENTDEV=n
+CONFIG_RTE_LIBRTE_PMD_SKELETON_EVENTDEV_DEBUG=n
+# Compile PMD for software event device
+CONFIG_RTE_LIBRTE_PMD_SW_EVENTDEV=n
+# Compile PMD for distributed software event device
+CONFIG_RTE_LIBRTE_PMD_DSW_EVENTDEV=n
+# Compile PMD for octeontx sso event device
+CONFIG_RTE_LIBRTE_PMD_OCTEONTX_SSOVF=n
+# Compile PMD for OPDL event device
+CONFIG_RTE_LIBRTE_PMD_OPDL_EVENTDEV=n
+# Compile PMD for NXP DPAA event device
+CONFIG_RTE_LIBRTE_PMD_DPAA_EVENTDEV=n
+# Compile PMD for NXP DPAA2 event device
+CONFIG_RTE_LIBRTE_PMD_DPAA2_EVENTDEV=n
+# Compile raw device support
+# EXPERIMENTAL: API may change without prior notice
+CONFIG_RTE_LIBRTE_RAWDEV=n
+CONFIG_RTE_RAWDEV_MAX_DEVS=10
+CONFIG_RTE_LIBRTE_PMD_SKELETON_RAWDEV=n
+# Compile PMD for NXP DPAA2 CMDIF raw device
+CONFIG_RTE_LIBRTE_PMD_DPAA2_CMDIF_RAWDEV=n
+# Compile PMD for NXP DPAA2 QDMA raw device
+CONFIG_RTE_LIBRTE_PMD_DPAA2_QDMA_RAWDEV=n
+# Compile PMD for Intel FPGA raw device
+CONFIG_RTE_LIBRTE_PMD_IFPGA_RAWDEV=n
+# Compile librte_ring
+CONFIG_RTE_LIBRTE_RING=y
+# Compile librte_mempool
+CONFIG_RTE_LIBRTE_MEMPOOL=y
+CONFIG_RTE_MEMPOOL_CACHE_MAX_SIZE=512
+CONFIG_RTE_LIBRTE_MEMPOOL_DEBUG=n
+# Compile Mempool drivers
+CONFIG_RTE_DRIVER_MEMPOOL_BUCKET=y
+CONFIG_RTE_DRIVER_MEMPOOL_BUCKET_SIZE_KB=64
+CONFIG_RTE_DRIVER_MEMPOOL_RING=y
+CONFIG_RTE_DRIVER_MEMPOOL_STACK=y
+# Compile PMD for octeontx fpa mempool device
+CONFIG_RTE_LIBRTE_OCTEONTX_MEMPOOL=n
+# Compile librte_mbuf
+CONFIG_RTE_LIBRTE_MBUF=y
+CONFIG_RTE_LIBRTE_MBUF_DEBUG=n
+CONFIG_RTE_MBUF_DEFAULT_MEMPOOL_OPS="ring_mp_mc"
+CONFIG_RTE_MBUF_REFCNT_ATOMIC=y
+CONFIG_RTE_PKTMBUF_HEADROOM=128
+# Compile librte_timer
+CONFIG_RTE_LIBRTE_TIMER=n
+CONFIG_RTE_LIBRTE_TIMER_DEBUG=n
+# Compile librte_cfgfile
+CONFIG_RTE_LIBRTE_CFGFILE=n
+# Compile librte_cmdline
+CONFIG_RTE_LIBRTE_CMDLINE=y
+CONFIG_RTE_LIBRTE_CMDLINE_DEBUG=n
+# Compile librte_hash
+CONFIG_RTE_LIBRTE_HASH=y
+CONFIG_RTE_LIBRTE_HASH_DEBUG=n
+# Compile librte_efd
+CONFIG_RTE_LIBRTE_EFD=n
+# Compile librte_member
+CONFIG_RTE_LIBRTE_MEMBER=y
+# Compile librte_jobstats
+CONFIG_RTE_LIBRTE_JOBSTATS=n
+# Compile architecture we compile for. device metrics library
+CONFIG_RTE_LIBRTE_METRICS=y
+# Compile architecture we compile for. bitrate statistics library
+CONFIG_RTE_LIBRTE_BITRATE=y
+# Compile architecture we compile for. latency statistics library
+CONFIG_RTE_LIBRTE_LATENCY_STATS=y
+# Compile librte_telemetry
+CONFIG_RTE_LIBRTE_TELEMETRY=n
+# Compile librte_lpm
+CONFIG_RTE_LIBRTE_LPM=n
+CONFIG_RTE_LIBRTE_LPM_DEBUG=n
+# Compile librte_acl
+CONFIG_RTE_LIBRTE_ACL=n
+CONFIG_RTE_LIBRTE_ACL_DEBUG=n
+# Compile librte_power
+CONFIG_RTE_LIBRTE_POWER=n
+CONFIG_RTE_LIBRTE_POWER_DEBUG=n
+CONFIG_RTE_MAX_LCORE_FREQS=64
+# Compile librte_net
+CONFIG_RTE_LIBRTE_NET=y
+# Compile librte_ip_frag
+CONFIG_RTE_LIBRTE_IP_FRAG=y
+CONFIG_RTE_LIBRTE_IP_FRAG_DEBUG=n
+CONFIG_RTE_LIBRTE_IP_FRAG_MAX_FRAG=4
+CONFIG_RTE_LIBRTE_IP_FRAG_TBL_STAT=n
+# Compile GRO library
+CONFIG_RTE_LIBRTE_GRO=y
+# Compile GSO library
+CONFIG_RTE_LIBRTE_GSO=y
+# Compile librte_meter
+CONFIG_RTE_LIBRTE_METER=y
+# Compile librte_classify
+CONFIG_RTE_LIBRTE_FLOW_CLASSIFY=n
+# Compile librte_sched
+CONFIG_RTE_LIBRTE_SCHED=n
+CONFIG_RTE_SCHED_DEBUG=n
+CONFIG_RTE_SCHED_RED=n
+CONFIG_RTE_SCHED_COLLECT_STATS=n
+CONFIG_RTE_SCHED_SUBPORT_TC_OV=n
+CONFIG_RTE_SCHED_PORT_N_GRINDERS=8
+CONFIG_RTE_SCHED_VECTOR=n
+# Compile architecture we compile for. distributor library
+CONFIG_RTE_LIBRTE_DISTRIBUTOR=n
+# Compile architecture we compile for. reorder library
+CONFIG_RTE_LIBRTE_REORDER=n
+# Compile librte_port
+CONFIG_RTE_LIBRTE_PORT=n
+CONFIG_RTE_PORT_STATS_COLLECT=n
+CONFIG_RTE_PORT_PCAP=n
+# Compile librte_table
+CONFIG_RTE_LIBRTE_TABLE=n
+CONFIG_RTE_TABLE_STATS_COLLECT=n
+# Compile librte_pipeline
+CONFIG_RTE_LIBRTE_PIPELINE=n
+CONFIG_RTE_PIPELINE_STATS_COLLECT=n
+# Compile librte_kni
+CONFIG_RTE_LIBRTE_KNI=n
+CONFIG_RTE_LIBRTE_PMD_KNI=n
+CONFIG_RTE_KNI_KMOD=n
+CONFIG_RTE_KNI_KMOD_ETHTOOL=n
+CONFIG_RTE_KNI_PREEMPT_DEFAULT=y
+# Compile architecture we compile for. pdump library
+CONFIG_RTE_LIBRTE_PDUMP=y
+# Compile vhost user library
+CONFIG_RTE_LIBRTE_VHOST=y
+CONFIG_RTE_LIBRTE_VHOST_NUMA=y
+CONFIG_RTE_LIBRTE_VHOST_DEBUG=n
+# Compile vhost PMD
+# To compile, CONFIG_RTE_LIBRTE_VHOST should be enabled.
+CONFIG_RTE_LIBRTE_PMD_VHOST=y
+# Compile IFC driver
+# To compile, CONFIG_RTE_LIBRTE_VHOST and CONFIG_RTE_EAL_VFIO
+# should be enabled.
+CONFIG_RTE_LIBRTE_IFC_PMD=n
+# Compile librte_bpf
+CONFIG_RTE_LIBRTE_BPF=n
+# allow load BPF from ELF files (requires libelf)
+CONFIG_RTE_LIBRTE_BPF_ELF=n
+# Compile architecture we compile for. test application
+CONFIG_RTE_APP_TEST=y
+CONFIG_RTE_APP_TEST_RESOURCE_TAR=n
+# Compile architecture we compile for. procinfo application
+CONFIG_RTE_PROC_INFO=y
+# Compile architecture we compile for. PMD test application
+CONFIG_RTE_TEST_PMD=n
+CONFIG_RTE_TEST_PMD_RECORD_CORE_CYCLES=n
+CONFIG_RTE_TEST_PMD_RECORD_BURST_STATS=n
+# Compile architecture we compile for. bbdev test application
+CONFIG_RTE_TEST_BBDEV=n
+# Compile architecture we compile for. crypto performance application
+CONFIG_RTE_APP_CRYPTO_PERF=n
+# Compile architecture we compile for. eventdev application
+CONFIG_RTE_APP_EVENTDEV=n
+CONFIG_RTE_EXEC_ENV_LINUXAPP=y
+CONFIG_RTE_LIBRTE_VHOST_POSTCOPY=n
+# Common libraries, before Bus/PMDs
+# NXP DPAA BUS and drivers
+# NXP FSLMC BUS and DPAA2 drivers
+# NXP ENETC PMD Driver
+CONFIG_RTE_ARCH_X86_64=y
+CONFIG_RTE_ARCH_X86=y
+CONFIG_RTE_ARCH_64=y
+CONFIG_RTE_TOOLCHAIN_GCC=y
+CONFIG_RTE_LIBRTE_PMD_XENVIRT=n
diff --git a/SPECS/ovn24.09.spec b/SPECS/ovn24.09.spec
new file mode 100644
index 0000000..a485f74
--- /dev/null
+++ b/SPECS/ovn24.09.spec
@@ -0,0 +1,686 @@
+# Copyright (C) 2009, 2010, 2013, 2014 Nicira Networks, Inc.
+#
+# Copying and distribution of this file, with or without modification,
+# are permitted in any medium without royalty provided the copyright
+# notice and this notice are preserved. This file is offered as-is,
+# without warranty of any kind.
+#
+# If tests have to be skipped while building, specify the '--without check'
+# option. For example:
+# rpmbuild -bb --without check rhel/openvswitch-fedora.spec
+
+# This defines the base package name's version.
+
+%define pkgver 2.13
+%define pkgname ovn24.09
+
+# If libcap-ng isn't available and there is no need for running OVS
+# as regular user, specify the '--without libcapng'
+%bcond_without libcapng
+
+# Enable PIE, bz#955181
+%global _hardened_build 1
+
+# RHEL-7 doesn't define _rundir macro yet
+# Fedora 15 onwards uses /run as _rundir
+%if 0%{!?_rundir:1}
+%define _rundir /run
+%endif
+
+# Build python2 (that provides python) and python3 subpackages on Fedora
+# Build only python3 (that provides python) subpackage on RHEL8
+# Build only python subpackage on RHEL7
+%if 0%{?rhel} > 7 || 0%{?fedora}
+# On RHEL8 Sphinx is included in buildroot
+%global external_sphinx 1
+%else
+# Don't use external sphinx (RHV doesn't have optional repositories enabled)
+%global external_sphinx 0
+%endif
+
+# We would see rpmlinit error - E: hardcoded-library-path in '% {_prefix}/lib'.
+# But there is no solution to fix this. Using {_lib} macro will solve the
+# rpmlink error, but will install the files in /usr/lib64/.
+# OVN pacemaker ocf script file is copied in /usr/lib/ocf/resource.d/ovn/
+# and we are not sure if pacemaker looks into this path to find the
+# OVN resource agent script.
+%global ovnlibdir %{_prefix}/lib
+
+Name: %{pkgname}
+Summary: Open Virtual Network support
+Group: System Environment/Daemons
+URL: http://www.ovn.org/
+Version: 24.09.0
+Release: 41%{?commit0:.%{date}git%{shortcommit0}}%{?dist}
+Provides: openvswitch%{pkgver}-ovn-common = %{?epoch:%{epoch}:}%{version}-%{release}
+Obsoletes: openvswitch%{pkgver}-ovn-common < 2.11.0-1
+
+# Nearly all of openvswitch is ASL 2.0. The bugtool is LGPLv2+, and the
+# lib/sflow*.[ch] files are SISSL
+License: ASL 2.0 and LGPLv2+ and SISSL
+
+%define ovncommit 6c74ef66a877010a7cc43da61bc90c123d2b8b9d
+
+# Always pull an upstream release, since this is what we rebase to.
+Source: https://github.com/ovn-org/ovn/archive/%{ovncommit}.tar.gz#/ovn-%{version}.tar.gz
+
+%define ovscommit c598c05c85b2d38874a0ce8f7f088f6aae4fdabc
+%define ovsshortcommit c598c05
+
+Source10: https://github.com/openvswitch/ovs/archive/%{ovscommit}.tar.gz#/openvswitch-%{ovsshortcommit}.tar.gz
+%define ovsdir ovs-%{ovscommit}
+
+%define docutilsver 0.12
+%define pygmentsver 1.4
+%define sphinxver 1.1.3
+Source100: https://pypi.io/packages/source/d/docutils/docutils-%{docutilsver}.tar.gz
+Source101: https://pypi.io/packages/source/P/Pygments/Pygments-%{pygmentsver}.tar.gz
+Source102: https://pypi.io/packages/source/S/Sphinx/Sphinx-%{sphinxver}.tar.gz
+
+Source500: configlib.sh
+Source501: gen_config_group.sh
+Source502: set_config.sh
+
+# Important: source503 is used as the actual copy file
+# @TODO: this causes a warning - fix it?
+Source504: arm64-armv8a-linuxapp-gcc-config
+Source505: ppc_64-power8-linuxapp-gcc-config
+Source506: x86_64-native-linuxapp-gcc-config
+
+Patch: %{pkgname}.patch
+
+# FIXME Sphinx is used to generate some manpages, unfortunately, on RHEL, it's
+# in the -optional repository and so we can't require it directly since RHV
+# doesn't have the -optional repository enabled and so TPS fails
+%if %{external_sphinx}
+BuildRequires: python3-sphinx
+%else
+# Sphinx dependencies
+BuildRequires: python-devel
+BuildRequires: python-setuptools
+#BuildRequires: python2-docutils
+BuildRequires: python-jinja2
+BuildRequires: python-nose
+#BuildRequires: python2-pygments
+# docutils dependencies
+BuildRequires: python-imaging
+# pygments dependencies
+BuildRequires: python-nose
+%endif
+
+BuildRequires: gcc gcc-c++ make
+BuildRequires: autoconf automake libtool
+BuildRequires: systemd-units openssl openssl-devel
+BuildRequires: python3-devel python3-setuptools
+BuildRequires: desktop-file-utils
+BuildRequires: groff-base graphviz
+BuildRequires: unbound-devel
+
+# make check dependencies
+BuildRequires: procps-ng
+%if 0%{?rhel} == 8 || 0%{?fedora}
+BuildRequires: python3-pyOpenSSL
+%endif
+BuildRequires: tcpdump
+
+%if %{with libcapng}
+BuildRequires: libcap-ng libcap-ng-devel
+%endif
+
+%if 0%{?rhel} >= 9
+BuildRequires: python3-scapy
+%endif
+
+Requires: hostname openssl iproute module-init-tools
+
+Requires(post): systemd-units
+Requires(preun): systemd-units
+Requires(postun): systemd-units
+
+# to skip running checks, pass --without check
+%bcond_without check
+
+%description
+OVN, the Open Virtual Network, is a system to support virtual network
+abstraction. OVN complements the existing capabilities of OVS to add
+native support for virtual network abstractions, such as virtual L2 and L3
+overlays and security groups.
+
+%package central
+Summary: Open Virtual Network support
+License: ASL 2.0
+Requires: %{pkgname}
+Requires: firewalld-filesystem
+Provides: openvswitch%{pkgver}-ovn-central = %{?epoch:%{epoch}:}%{version}-%{release}
+Obsoletes: openvswitch%{pkgver}-ovn-central < 2.11.0-1
+
+%description central
+OVN DB servers and ovn-northd running on a central node.
+
+%package host
+Summary: Open Virtual Network support
+License: ASL 2.0
+Requires: %{pkgname}
+Requires: firewalld-filesystem
+Provides: openvswitch%{pkgver}-ovn-host = %{?epoch:%{epoch}:}%{version}-%{release}
+Obsoletes: openvswitch%{pkgver}-ovn-host < 2.11.0-1
+
+%description host
+OVN controller running on each host.
+
+%package vtep
+Summary: Open Virtual Network support
+License: ASL 2.0
+Requires: %{pkgname}
+Provides: openvswitch%{pkgver}-ovn-vtep = %{?epoch:%{epoch}:}%{version}-%{release}
+Obsoletes: openvswitch%{pkgver}-ovn-vtep < 2.11.0-1
+
+%description vtep
+OVN vtep controller
+
+%prep
+%autosetup -n ovn-%{ovncommit} -a 10 -p 1
+
+%build
+%if 0%{?commit0:1}
+# fix the snapshot unreleased version to be the released one.
+sed -i.old -e "s/^AC_INIT(openvswitch,.*,/AC_INIT(openvswitch, %{version},/" configure.ac
+%endif
+./boot.sh
+
+# OVN source code is now separate.
+# Build openvswitch first.
+# XXX Current openvswitch2.13 doesn't
+# use "2.13.0" for version. It's a commit hash
+pushd %{ovsdir}
+./boot.sh
+%configure \
+%if %{with libcapng}
+ --enable-libcapng \
+%else
+ --disable-libcapng \
+%endif
+ --enable-ssl \
+ --with-pkidir=%{_sharedstatedir}/openvswitch/pki
+
+make %{?_smp_mflags}
+popd
+
+# Build OVN.
+# XXX OVS version needs to be updated when ovs2.13 is updated.
+%configure \
+ --with-ovs-source=$PWD/%{ovsdir} \
+%if %{with libcapng}
+ --enable-libcapng \
+%else
+ --disable-libcapng \
+%endif
+ --enable-ssl \
+ --with-pkidir=%{_sharedstatedir}/openvswitch/pki
+
+make %{?_smp_mflags}
+
+%install
+%make_install
+install -p -D -m 0644 \
+ rhel/usr_share_ovn_scripts_systemd_sysconfig.template \
+ $RPM_BUILD_ROOT/%{_sysconfdir}/sysconfig/ovn
+
+for service in ovn-controller ovn-controller-vtep ovn-northd; do
+ install -p -D -m 0644 \
+ rhel/usr_lib_systemd_system_${service}.service \
+ $RPM_BUILD_ROOT%{_unitdir}/${service}.service
+done
+
+install -d -m 0755 $RPM_BUILD_ROOT/%{_sharedstatedir}/ovn
+
+install -d $RPM_BUILD_ROOT%{ovnlibdir}/firewalld/services/
+install -p -m 0644 rhel/usr_lib_firewalld_services_ovn-central-firewall-service.xml \
+ $RPM_BUILD_ROOT%{ovnlibdir}/firewalld/services/ovn-central-firewall-service.xml
+install -p -m 0644 rhel/usr_lib_firewalld_services_ovn-host-firewall-service.xml \
+ $RPM_BUILD_ROOT%{ovnlibdir}/firewalld/services/ovn-host-firewall-service.xml
+
+install -d -m 0755 $RPM_BUILD_ROOT%{ovnlibdir}/ocf/resource.d/ovn
+ln -s %{_datadir}/ovn/scripts/ovndb-servers.ocf \
+ $RPM_BUILD_ROOT%{ovnlibdir}/ocf/resource.d/ovn/ovndb-servers
+
+install -p -D -m 0644 rhel/etc_logrotate.d_ovn \
+ $RPM_BUILD_ROOT/%{_sysconfdir}/logrotate.d/ovn
+
+# remove unneeded files.
+rm -f $RPM_BUILD_ROOT%{_bindir}/ovs*
+rm -f $RPM_BUILD_ROOT%{_bindir}/vtep-ctl
+rm -f $RPM_BUILD_ROOT%{_sbindir}/ovs*
+rm -f $RPM_BUILD_ROOT%{_mandir}/man1/ovs*
+rm -f $RPM_BUILD_ROOT%{_mandir}/man5/ovs*
+rm -f $RPM_BUILD_ROOT%{_mandir}/man5/vtep*
+rm -f $RPM_BUILD_ROOT%{_mandir}/man7/ovs*
+rm -f $RPM_BUILD_ROOT%{_mandir}/man8/ovs*
+rm -f $RPM_BUILD_ROOT%{_mandir}/man8/vtep*
+rm -rf $RPM_BUILD_ROOT%{_datadir}/ovn/python
+rm -f $RPM_BUILD_ROOT%{_datadir}/ovn/scripts/ovs*
+rm -rf $RPM_BUILD_ROOT%{_datadir}/ovn/bugtool-plugins
+rm -f $RPM_BUILD_ROOT%{_libdir}/*.a
+rm -f $RPM_BUILD_ROOT%{_libdir}/*.la
+rm -f $RPM_BUILD_ROOT%{_libdir}/pkgconfig/*.pc
+rm -f $RPM_BUILD_ROOT%{_includedir}/ovn/*
+rm -f $RPM_BUILD_ROOT%{_sysconfdir}/bash_completion.d/ovs-appctl-bashcomp.bash
+rm -f $RPM_BUILD_ROOT%{_sysconfdir}/bash_completion.d/ovs-vsctl-bashcomp.bash
+rm -rf $RPM_BUILD_ROOT%{_sysconfdir}/logrotate.d/openvswitch
+rm -f $RPM_BUILD_ROOT%{_datadir}/ovn/scripts/ovn-bugtool*
+rm -f $RPM_BUILD_ROOT/%{_bindir}/ovn-docker-overlay-driver \
+ $RPM_BUILD_ROOT/%{_bindir}/ovn-docker-underlay-driver
+
+%check
+%if %{with check}
+ touch resolv.conf
+ export OVS_RESOLV_CONF=$(pwd)/resolv.conf
+ if ! make check TESTSUITEFLAGS='%{_smp_mflags}'; then
+ cat tests/testsuite.log
+ if ! make check TESTSUITEFLAGS='--recheck'; then
+ cat tests/testsuite.log
+ # Presently a test case - "2796: ovn -- ovn-controller incremental processing"
+ # is failing on aarch64 arch. Let's not exit for this arch
+ # until we figure out why it is failing.
+ # Test case 93: ovn.at:12105 ovn -- ACLs on Port Groups is failing
+ # repeatedly on s390x. This needs to be investigated.
+ %ifnarch aarch64
+ %ifnarch ppc64le
+ %ifnarch s390x
+ exit 1
+ %endif
+ %endif
+ %endif
+ fi
+ fi
+%endif
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%pre central
+if [ $1 -eq 1 ] ; then
+ # Package install.
+ /bin/systemctl status ovn-northd.service >/dev/null
+ ovn_status=$?
+ rpm -ql openvswitch-ovn-central > /dev/null
+ if [[ "$?" = "0" && "$ovn_status" = "0" ]]; then
+ # ovn-northd service is running which means old openvswitch-ovn-central
+ # is already installed and it will be cleaned up. So start ovn-northd
+ # service when posttrans central is called.
+ touch %{_localstatedir}/lib/rpm-state/ovn-northd
+ fi
+fi
+
+%pre host
+if [ $1 -eq 1 ] ; then
+ # Package install.
+ /bin/systemctl status ovn-controller.service >/dev/null
+ ovn_status=$?
+ rpm -ql openvswitch-ovn-host > /dev/null
+ if [[ "$?" = "0" && "$ovn_status" = "0" ]]; then
+ # ovn-controller service is running which means old
+ # openvswitch-ovn-host is installed and it will be cleaned up. So
+ # start ovn-controller service when posttrans host is called.
+ touch %{_localstatedir}/lib/rpm-state/ovn-controller
+ fi
+fi
+
+%pre vtep
+if [ $1 -eq 1 ] ; then
+ # Package install.
+ /bin/systemctl status ovn-controller-vtep.service >/dev/null
+ ovn_status=$?
+ rpm -ql openvswitch-ovn-vtep > /dev/null
+ if [[ "$?" = "0" && "$ovn_status" = "0" ]]; then
+ # ovn-controller-vtep service is running which means old
+ # openvswitch-ovn-vtep is installed and it will be cleaned up. So
+ # start ovn-controller-vtep service when posttrans host is called.
+ touch %{_localstatedir}/lib/rpm-state/ovn-controller-vtep
+ fi
+fi
+
+%preun central
+%if 0%{?systemd_preun:1}
+ %systemd_preun ovn-northd.service
+%else
+ if [ $1 -eq 0 ] ; then
+ # Package removal, not upgrade
+ /bin/systemctl --no-reload disable ovn-northd.service >/dev/null 2>&1 || :
+ /bin/systemctl stop ovn-northd.service >/dev/null 2>&1 || :
+ fi
+%endif
+
+%preun host
+%if 0%{?systemd_preun:1}
+ %systemd_preun ovn-controller.service
+%else
+ if [ $1 -eq 0 ] ; then
+ # Package removal, not upgrade
+ /bin/systemctl --no-reload disable ovn-controller.service >/dev/null 2>&1 || :
+ /bin/systemctl stop ovn-controller.service >/dev/null 2>&1 || :
+ fi
+%endif
+
+%preun vtep
+%if 0%{?systemd_preun:1}
+ %systemd_preun ovn-controller-vtep.service
+%else
+ if [ $1 -eq 0 ] ; then
+ # Package removal, not upgrade
+ /bin/systemctl --no-reload disable ovn-controller-vtep.service >/dev/null 2>&1 || :
+ /bin/systemctl stop ovn-controller-vtep.service >/dev/null 2>&1 || :
+ fi
+%endif
+
+%post
+%if %{with libcapng}
+if [ $1 -eq 1 ]; then
+ sed -i 's:^#OVN_USER_ID=:OVN_USER_ID=:' %{_sysconfdir}/sysconfig/ovn
+ sed -i 's:\(.*su\).*:\1 openvswitch openvswitch:' %{_sysconfdir}/logrotate.d/ovn
+fi
+%endif
+
+%post central
+%if 0%{?systemd_post:1}
+ %systemd_post ovn-northd.service
+%else
+ # Package install, not upgrade
+ if [ $1 -eq 1 ]; then
+ /bin/systemctl daemon-reload >dev/null || :
+ fi
+%endif
+
+%post host
+%if 0%{?systemd_post:1}
+ %systemd_post ovn-controller.service
+%else
+ # Package install, not upgrade
+ if [ $1 -eq 1 ]; then
+ /bin/systemctl daemon-reload >dev/null || :
+ fi
+%endif
+
+%post vtep
+%if 0%{?systemd_post:1}
+ %systemd_post ovn-controller-vtep.service
+%else
+ # Package install, not upgrade
+ if [ $1 -eq 1 ]; then
+ /bin/systemctl daemon-reload >dev/null || :
+ fi
+%endif
+
+%postun
+
+%postun central
+%if 0%{?systemd_postun_with_restart:1}
+ %systemd_postun_with_restart ovn-northd.service
+%else
+ /bin/systemctl daemon-reload >/dev/null 2>&1 || :
+ if [ "$1" -ge "1" ] ; then
+ # Package upgrade, not uninstall
+ /bin/systemctl try-restart ovn-northd.service >/dev/null 2>&1 || :
+ fi
+%endif
+
+%postun host
+%if 0%{?systemd_postun_with_restart:1}
+ %systemd_postun_with_restart ovn-controller.service
+%else
+ /bin/systemctl daemon-reload >/dev/null 2>&1 || :
+ if [ "$1" -ge "1" ] ; then
+ # Package upgrade, not uninstall
+ /bin/systemctl try-restart ovn-controller.service >/dev/null 2>&1 || :
+ fi
+%endif
+
+%postun vtep
+%if 0%{?systemd_postun_with_restart:1}
+ %systemd_postun_with_restart ovn-controller-vtep.service
+%else
+ /bin/systemctl daemon-reload >/dev/null 2>&1 || :
+ if [ "$1" -ge "1" ] ; then
+ # Package upgrade, not uninstall
+ /bin/systemctl try-restart ovn-controller-vtep.service >/dev/null 2>&1 || :
+ fi
+%endif
+
+%posttrans central
+if [ $1 -eq 1 ]; then
+ # Package install, not upgrade
+ if [ -e %{_localstatedir}/lib/rpm-state/ovn-northd ]; then
+ rm %{_localstatedir}/lib/rpm-state/ovn-northd
+ /bin/systemctl start ovn-northd.service >/dev/null 2>&1 || :
+ fi
+fi
+
+
+%posttrans host
+if [ $1 -eq 1 ]; then
+ # Package install, not upgrade
+ if [ -e %{_localstatedir}/lib/rpm-state/ovn-controller ]; then
+ rm %{_localstatedir}/lib/rpm-state/ovn-controller
+ /bin/systemctl start ovn-controller.service >/dev/null 2>&1 || :
+ fi
+fi
+
+%posttrans vtep
+if [ $1 -eq 1 ]; then
+ # Package install, not upgrade
+ if [ -e %{_localstatedir}/lib/rpm-state/ovn-controller-vtep ]; then
+ rm %{_localstatedir}/lib/rpm-state/ovn-controller-vtep
+ /bin/systemctl start ovn-controller-vtep.service >/dev/null 2>&1 || :
+ fi
+fi
+
+%files
+%{_bindir}/ovn-nbctl
+%{_bindir}/ovn-sbctl
+%{_bindir}/ovn-trace
+%{_bindir}/ovn-detrace
+%{_bindir}/ovn_detrace.py
+%{_bindir}/ovn-appctl
+%{_bindir}/ovn-ic-nbctl
+%{_bindir}/ovn-ic-sbctl
+%{_bindir}/ovn-debug
+%dir %{_datadir}/ovn/
+%dir %{_datadir}/ovn/scripts/
+%{_datadir}/ovn/scripts/ovn-ctl
+%{_datadir}/ovn/scripts/ovn-lib
+%{_datadir}/ovn/scripts/ovndb-servers.ocf
+%{_mandir}/man8/ovn-ctl.8*
+%{_mandir}/man8/ovn-appctl.8*
+%{_mandir}/man8/ovn-nbctl.8*
+%{_mandir}/man8/ovn-ic-nbctl.8*
+%{_mandir}/man8/ovn-trace.8*
+%{_mandir}/man1/ovn-detrace.1*
+%{_mandir}/man7/ovn-architecture.7*
+%{_mandir}/man8/ovn-sbctl.8*
+%{_mandir}/man8/ovn-ic-sbctl.8*
+%{_mandir}/man8/ovn-debug.8*
+%{_mandir}/man5/ovn-nb.5*
+%{_mandir}/man5/ovn-ic-nb.5*
+%{_mandir}/man5/ovn-sb.5*
+%{_mandir}/man5/ovn-ic-sb.5*
+%dir %{ovnlibdir}/ocf/resource.d/ovn/
+%{ovnlibdir}/ocf/resource.d/ovn/ovndb-servers
+%config(noreplace) %verify(not md5 size mtime) %{_sysconfdir}/logrotate.d/ovn
+%config(noreplace) %verify(not md5 size mtime) %{_sysconfdir}/sysconfig/ovn
+
+%files central
+%{_bindir}/ovn-northd
+%{_bindir}/ovn-ic
+%{_mandir}/man8/ovn-northd.8*
+%{_mandir}/man8/ovn-ic.8*
+%{_datadir}/ovn/ovn-nb.ovsschema
+%{_datadir}/ovn/ovn-ic-nb.ovsschema
+%{_datadir}/ovn/ovn-sb.ovsschema
+%{_datadir}/ovn/ovn-ic-sb.ovsschema
+%{_unitdir}/ovn-northd.service
+%{ovnlibdir}/firewalld/services/ovn-central-firewall-service.xml
+
+%files host
+%{_bindir}/ovn-controller
+%{_mandir}/man8/ovn-controller.8*
+%{_unitdir}/ovn-controller.service
+%{ovnlibdir}/firewalld/services/ovn-host-firewall-service.xml
+
+%files vtep
+%{_bindir}/ovn-controller-vtep
+%{_mandir}/man8/ovn-controller-vtep.8*
+%{_unitdir}/ovn-controller-vtep.service
+
+%changelog
+* Fri Oct 11 2024 Xavier Simonart - 24.09.0-41
+- ovn-ic: Fix potential segmentation violation.
+[Upstream: 0611308a7a2e58911a18d974b1e8c7b2d8f0541f]
+
+* Wed Oct 09 2024 Mohammad Heib - 24.09.0-40
+- controller: Container lport install flows in MAIN chassis only. (#FDP-772)
+[Upstream: 809d4aac64c4343f3bf845f2df497be2af6cba26]
+
+* Fri Oct 04 2024 Ales Musil - 24.09.0-39
+- northd, controller: Use ct_next to get the CT state for direct SNAT. (#FDP-744)
+[Upstream: 2a60ba94f99486f1eb44134e693a8393059d4869]
+
+* Tue Oct 01 2024 Ales Musil - 24.09.0-38
+- ci: Pin scapy version.
+[Upstream: 4579cb66599fedb433f8fc2fa0d9167e54feb457]
+
+* Thu Sep 26 2024 Rosemarie O'Riorden - 24.09.0-37
+- northd: Respect --ecmp-symmetric-reply for single routes. (#FDP-786)
+[Upstream: 7b00627433f3ee066cf6a5b727fec614c5e6eb77]
+
+* Fri Sep 20 2024 Ales Musil - 24.09.0-36
+- controller: Avoid quadratic complexity for multi-chassis ports.
+[Upstream: b3e47dc70ad6bd2f92ffbe64a39ae4d98c0e8398]
+
+* Fri Sep 20 2024 Ales Musil - 24.09.0-35
+- physical: Prevent wrong FDB to be learned with multichassis port. (#FDP-620)
+[Upstream: 8b3e276e228407068e0a9e72ad3e02969da2de1d]
+
+* Thu Sep 19 2024 Xavier Simonart - 24.09.0-34
+- ovn-controller: Fix potential assert when exiting.
+[Upstream: 8488c3c0aff73d1037a4af205ac3ba2ed22106a3]
+
+* Fri Sep 13 2024 Mark Michelson - 24.09.0-33
+- Prepare for 24.09.1.
+[Upstream: 2282ae8501faa5fe9bd607a5f0a81d863441f10f]
+
+* Fri Sep 13 2024 Mark Michelson - 24.09.0-32
+- Set release date for 24.09.0.
+[Upstream: f04e445562597909038f663a5da0699183002bcf]
+
+* Wed Sep 11 2024 Xavier Simonart - 24.09.0-31
+- tests: Fix flaky BFD system test.
+[Upstream: 7be7d8df2704eae6cc26111bc347bd0d5601fb09]
+
+* Wed Sep 11 2024 Xavier Simonart - 24.09.0-30
+- tests: Fix flaky ACL Sampling system tests.
+[Upstream: 88e80a3b8ef21fef7418b03c49735dfd6af11931]
+
+* Wed Sep 11 2024 Xavier Simonart - 24.09.0-29
+- tests: Fix multiple ovn-ic race conditions.
+[Upstream: 2e6cdfdf18da671d462bc2b575cd48fa20a7e903]
+
+* Wed Sep 11 2024 Xavier Simonart - 24.09.0-28
+- tests: Fix flaky "load-balancer template IPv4".
+[Upstream: 1a69a5d4c7fc37c3aee8e4fa07fe50aada59b997]
+
+* Wed Sep 11 2024 Xavier Simonart - 24.09.0-27
+- tests: Fix flaky "Sampling_App incremental processing".
+[Upstream: ecdc7bb7b46e16321679b9a3f064897f7cae90cd]
+
+* Wed Sep 11 2024 Xavier Simonart - 24.09.0-26
+- tests: Fix flaky "MAC binding aging".
+[Upstream: afed92ce6839473fd56278aa1879ad5e6b5c086e]
+
+* Wed Sep 11 2024 Ilya Maximets - 24.09.0-25
+- ovs: Move the submodule to the official v3.4.0 release.
+[Upstream: 2f14de89f05d1fce901d374e3f2dd7e9d6e50365]
+
+* Wed Sep 11 2024 Lorenzo Bianconi - 24.09.0-24
+- controller: Do not remove snat-ct-zone requested by the CMS. (#FDP-773)
+[Upstream: 76bd54eb36d52d1b3fa663d185f53dcaa2cff06b]
+
+* Tue Sep 03 2024 Vladislav Odintsov - 24.09.0-23
+- news: Fix indentation for an entry.
+[Upstream: 360f669b16ec2ed64657ea1d4c75b73263812bad]
+
+* Thu Aug 29 2024 Ales Musil - 24.09.0-22
+- pinctrl: Explicitly set ICMPv6 code for packet too big. (#FDP-763)
+[Upstream: 8efac26f6637fc35fd1d3e5b41b935ebcb074a1d]
+
+* Wed Aug 28 2024 Ales Musil - 24.09.0-21
+- tests: Prevent netcat from forking.
+[Upstream: dc5b666d7dba02c0a5617605463967c86739568e]
+
+* Tue Aug 27 2024 Mark Michelson - 24.09.0-20
+- Documentation: Add inclusive-language documentation.
+[Upstream: ea24d593e921c1e35fe281b9c1de449ab7b5c56f]
+
+* Tue Aug 27 2024 Lorenzo Bianconi - 24.09.0-19
+- Revert "northd: Introduce ECMP_Nexthop table in SB db.". (#FDP-750)
+[Upstream: cb8e5433281b8ab5f3a65e52e41f46839e32d4fc]
+
+* Tue Aug 27 2024 Lorenzo Bianconi - 24.09.0-18
+- Revert "northd: Add nexhop id in ct_label.label.". (#FDP-750)
+[Upstream: 7b937370bb4befb0d69f310f14d6068589d6740c]
+
+* Tue Aug 27 2024 Lorenzo Bianconi - 24.09.0-17
+- Revert "ofctrl: Introduce ecmp_nexthop_monitor.". (#FDP-750)
+[Upstream: 42148ffe8c6aa95f732f4c2444b4d10dbbf2fd93]
+
+* Thu Aug 22 2024 Lorenzo Bianconi - 24.09.0-16
+- northd: Make bfd_connections static in build_parsed_routes.
+[Upstream: fc8a015434f18b6b8ef05b11179f89d099fee2ce]
+
+* Thu Aug 22 2024 Lorenzo Bianconi - 24.09.0-15
+- northd: Get rid of bfd_connections in bfd_sync_data.
+[Upstream: f29fc462e3e5313d6e7bb234fb7864c587e11c32]
+
+* Thu Aug 22 2024 Lorenzo Bianconi - 24.09.0-14
+- northd: Optimize lookup in bfd_is_port_running.
+[Upstream: 8b08b23dc14130e6e5425f132a5be8a2866f8b54]
+
+* Thu Aug 22 2024 Lorenzo Bianconi - 24.09.0-13
+- northd: Introduce bfd_sync_data data structure.
+[Upstream: 8f085f0bd1c0f70b0260729d6b4ad4223b920d54]
+
+* Tue Aug 20 2024 Numan Siddique - 24.09.0-12
+- northd: Fix potential crash when creating chassisredirect port.
+[Upstream: 97fc54f10f2c55a30df01d8f2c4f772d0960c114]
+
+* Mon Aug 19 2024 Numan Siddique - 24.09.0-11
+- tests: Skip "IPv6 switching - megaflow check" if scapy is not installed.
+[Upstream: 34fa3c1d4db31e2b840e6592b418f53dc6efcf5a]
+
+* Fri Aug 16 2024 Numan Siddique - 24.09.0-10
+- Reply only for the multicast ND solicitations. (#FDP-728)
+[Upstream: 30a502e9f3a8f66370acdc9b4c1c2ae96af5451f]
+
+* Wed Aug 14 2024 Xavier Simonart - 24.09.0-9
+- multinode: Fix test "ovn multinode NAT ...".
+[Upstream: 0fbe412a1e96790f16c9015f89473c30730966ce]
+
+* Wed Aug 14 2024 Xavier Simonart - 24.09.0-8
+- multinode: Increase maximum execution time.
+[Upstream: 155637d986730dd5af18b936f3ac736931d164fe]
+
+* Tue Aug 13 2024 Martin Kalcok - 24.09.0-7
+- northd: Routing protocol port redirection.
+[Upstream: 158597a1fa4ef253e3c461da9eaf26b638d68b69]
+
+* Mon Aug 12 2024 Rosemarie O'Riorden - 24.09.0-6
+- northd: Clean up SB MAC bindings for deleted ports. (#FDP-723)
+[Upstream: 11d92550b15c4aa03cc28386d89fb09df47aa2b5]
+
+* Mon Aug 12 2024 Ales Musil - 24.09.0-5
+- controller: Make sure the meter and group tables are initialized.
+[Upstream: 4ded211f808185da5ff16a67d6daf1759204cbab]
+
+* Mon Aug 12 2024 Ilya Maximets - 24.09.0-4
+- github: containers: Fix job condition.
+[Upstream: 07d51ea3cbf17f1fa354d5982d4026ac15c94d40]
+