diff --git a/.openvswitch.metadata b/.openvswitch.metadata
index e69de29..aaf8dec 100644
--- a/.openvswitch.metadata
+++ b/.openvswitch.metadata
@@ -0,0 +1,5 @@
+002450621b33c5690060345b0aac25bc2426d675  SOURCES/docutils-0.12.tar.gz
+4d592defad14e76bf656e6c01525da8b15fc0cf6  SOURCES/openvswitch-2.15.0.tar.gz
+d34f96421a86004aa5d26ecf975edefd09f948b1  SOURCES/Pygments-1.4.tar.gz
+3a11f130c63b057532ca37fe49c8967d0cbae1d5  SOURCES/Sphinx-1.2.3.tar.gz
+cee6b23d62e0a19f6c6d652f4a415b7d62e95796  SOURCES/dpdk-20.11.tar.xz
diff --git a/SOURCES/openvswitch-2.15.0.patch b/SOURCES/openvswitch-2.15.0.patch
new file mode 100644
index 0000000..939148e
--- /dev/null
+++ b/SOURCES/openvswitch-2.15.0.patch
@@ -0,0 +1,725 @@
+diff --git a/.ci/linux-build.sh b/.ci/linux-build.sh
+index 3e5136fd4e..dd29a4182d 100755
+--- a/.ci/linux-build.sh
++++ b/.ci/linux-build.sh
+@@ -235,7 +235,7 @@ if [ "$TESTSUITE" ]; then
+     configure_ovs
+ 
+     export DISTCHECK_CONFIGURE_FLAGS="$OPTS"
+-    if ! make distcheck CFLAGS="${CFLAGS_FOR_OVS}" \
++    if ! make distcheck -j4 CFLAGS="${CFLAGS_FOR_OVS}" \
+          TESTSUITEFLAGS=-j4 RECHECK=yes; then
+         # testsuite.log is necessary for debugging.
+         cat */_build/sub/tests/testsuite.log
+diff --git a/Documentation/topics/dpdk/qos.rst b/Documentation/topics/dpdk/qos.rst
+index 103495415a..a98ec672fc 100644
+--- a/Documentation/topics/dpdk/qos.rst
++++ b/Documentation/topics/dpdk/qos.rst
+@@ -69,22 +69,24 @@ to prioritize certain traffic over others at a port level.
+ 
+ For example, the following configuration will limit the traffic rate at a
+ port level to a maximum of 2000 packets a second (64 bytes IPv4 packets).
+-100pps as CIR (Committed Information Rate) and 1000pps as EIR (Excess
+-Information Rate). High priority traffic is routed to queue 10, which marks
++1000pps as CIR (Committed Information Rate) and 1000pps as EIR (Excess
++Information Rate). CIR and EIR are measured in bytes without Ethernet header.
++As a result, 1000pps means (64-byte - 14-byte) * 1000 = 50,000 in the
++configuration below. High priority traffic is routed to queue 10, which marks
+ all traffic as CIR, i.e. Green. All low priority traffic, queue 20, is
+ marked as EIR, i.e. Yellow::
+ 
+     $ ovs-vsctl --timeout=5 set port dpdk1 qos=@myqos -- \
+         --id=@myqos create qos type=trtcm-policer \
+-        other-config:cir=52000 other-config:cbs=2048 \
+-        other-config:eir=52000 other-config:ebs=2048  \
++        other-config:cir=50000 other-config:cbs=2048 \
++        other-config:eir=50000 other-config:ebs=2048  \
+         queues:10=@dpdk1Q10 queues:20=@dpdk1Q20 -- \
+          --id=@dpdk1Q10 create queue \
+-          other-config:cir=41600000 other-config:cbs=2048 \
++          other-config:cir=100000 other-config:cbs=2048 \
+           other-config:eir=0 other-config:ebs=0 -- \
+          --id=@dpdk1Q20 create queue \
+            other-config:cir=0 other-config:cbs=0 \
+-           other-config:eir=41600000 other-config:ebs=2048 \
++           other-config:eir=50000 other-config:ebs=2048
+ 
+ This configuration accomplishes that the high priority traffic has a
+ guaranteed bandwidth egressing the ports at CIR (1000pps), but it can also
+diff --git a/NEWS b/NEWS
+index bc901efdb1..036d4032c4 100644
+--- a/NEWS
++++ b/NEWS
+@@ -1,3 +1,11 @@
++v2.15.1 - xx xxx xxxx
++---------------------
++   - ovs-ctl:
++     * New option '--no-record-hostname' to disable hostname configuration
++       in ovsdb on startup.
++     * New command 'record-hostname-if-not-set' to update hostname in ovsdb.
++
++
+ v2.15.0 - 15 Feb 2021
+ ---------------------
+    - OVSDB:
+diff --git a/configure.ac b/configure.ac
+index fd82d7d270..9299342960 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -13,7 +13,7 @@
+ # limitations under the License.
+ 
+ AC_PREREQ(2.63)
+-AC_INIT(openvswitch, 2.15.0, bugs@openvswitch.org)
++AC_INIT(openvswitch, 2.15.1, bugs@openvswitch.org)
+ AC_CONFIG_SRCDIR([datapath/datapath.c])
+ AC_CONFIG_MACRO_DIR([m4])
+ AC_CONFIG_AUX_DIR([build-aux])
+diff --git a/debian/changelog b/debian/changelog
+index 1f2b7a3668..8b5d075840 100644
+--- a/debian/changelog
++++ b/debian/changelog
+@@ -1,3 +1,9 @@
++openvswitch (2.15.1-1) unstable; urgency=low
++   [ Open vSwitch team ]
++   * New upstream version
++
++ -- Open vSwitch team <dev@openvswitch.org>  Mon, 15 Feb 2021 17:35:33 +0100
++
+ openvswitch (2.15.0-1) unstable; urgency=low
+ 
+    * New upstream version
+diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
+index 4381c618f1..816945375b 100644
+--- a/lib/dpif-netdev.c
++++ b/lib/dpif-netdev.c
+@@ -3834,6 +3834,15 @@ dpif_netdev_flow_put(struct dpif *dpif, const struct dpif_flow_put *put)
+         return error;
+     }
+ 
++    if (match.wc.masks.in_port.odp_port != ODPP_NONE) {
++        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
++
++        VLOG_ERR_RL(&rl, "failed to put%s flow: in_port is not an exact match",
++                    (put->flags & DPIF_FP_CREATE) ? "[create]"
++                    : (put->flags & DPIF_FP_MODIFY) ? "[modify]" : "[zero]");
++        return EINVAL;
++    }
++
+     if (put->ufid) {
+         ufid = *put->ufid;
+     } else {
+diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c
+index 6be23dbeed..15b25084b3 100644
+--- a/lib/netdev-linux.c
++++ b/lib/netdev-linux.c
+@@ -1255,21 +1255,21 @@ netdev_linux_batch_rxq_recv_sock(struct netdev_rxq_linux *rx, int mtu,
+      * aux_buf is allocated so that it can be prepended to TSO buffer. */
+     std_len = virtio_net_hdr_size + VLAN_ETH_HEADER_LEN + mtu;
+     for (i = 0; i < NETDEV_MAX_BURST; i++) {
+-         buffers[i] = dp_packet_new_with_headroom(std_len, DP_NETDEV_HEADROOM);
+-         iovs[i][IOV_PACKET].iov_base = dp_packet_data(buffers[i]);
+-         iovs[i][IOV_PACKET].iov_len = std_len;
+-         if (iovlen == IOV_TSO_SIZE) {
+-             iovs[i][IOV_AUXBUF].iov_base = dp_packet_data(rx->aux_bufs[i]);
+-             iovs[i][IOV_AUXBUF].iov_len = dp_packet_tailroom(rx->aux_bufs[i]);
+-         }
++        buffers[i] = dp_packet_new_with_headroom(std_len, DP_NETDEV_HEADROOM);
++        iovs[i][IOV_PACKET].iov_base = dp_packet_data(buffers[i]);
++        iovs[i][IOV_PACKET].iov_len = std_len;
++        if (iovlen == IOV_TSO_SIZE) {
++            iovs[i][IOV_AUXBUF].iov_base = dp_packet_data(rx->aux_bufs[i]);
++            iovs[i][IOV_AUXBUF].iov_len = dp_packet_tailroom(rx->aux_bufs[i]);
++        }
+ 
+-         mmsgs[i].msg_hdr.msg_name = NULL;
+-         mmsgs[i].msg_hdr.msg_namelen = 0;
+-         mmsgs[i].msg_hdr.msg_iov = iovs[i];
+-         mmsgs[i].msg_hdr.msg_iovlen = iovlen;
+-         mmsgs[i].msg_hdr.msg_control = &cmsg_buffers[i];
+-         mmsgs[i].msg_hdr.msg_controllen = sizeof cmsg_buffers[i];
+-         mmsgs[i].msg_hdr.msg_flags = 0;
++        mmsgs[i].msg_hdr.msg_name = NULL;
++        mmsgs[i].msg_hdr.msg_namelen = 0;
++        mmsgs[i].msg_hdr.msg_iov = iovs[i];
++        mmsgs[i].msg_hdr.msg_iovlen = iovlen;
++        mmsgs[i].msg_hdr.msg_control = &cmsg_buffers[i];
++        mmsgs[i].msg_hdr.msg_controllen = sizeof cmsg_buffers[i];
++        mmsgs[i].msg_hdr.msg_flags = 0;
+     }
+ 
+     do {
+diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c
+index e2e829772a..0342a228b7 100644
+--- a/lib/ofp-actions.c
++++ b/lib/ofp-actions.c
+@@ -4431,6 +4431,7 @@ decode_NXAST_RAW_ENCAP(const struct nx_action_encap *nae,
+ {
+     struct ofpact_encap *encap;
+     const struct ofp_ed_prop_header *ofp_prop;
++    const size_t encap_ofs = out->size;
+     size_t props_len;
+     uint16_t n_props = 0;
+     int err;
+@@ -4458,6 +4459,7 @@ decode_NXAST_RAW_ENCAP(const struct nx_action_encap *nae,
+         }
+         n_props++;
+     }
++    encap = ofpbuf_at_assert(out, encap_ofs, sizeof *encap);
+     encap->n_props = n_props;
+     out->header = &encap->ofpact;
+     ofpact_finish_ENCAP(out, &encap);
+diff --git a/lib/ovsdb-cs.c b/lib/ovsdb-cs.c
+index ff8adaefb5..6f9f912ac4 100644
+--- a/lib/ovsdb-cs.c
++++ b/lib/ovsdb-cs.c
+@@ -1367,7 +1367,7 @@ ovsdb_cs_send_transaction(struct ovsdb_cs *cs, struct json *operations)
+                               sizeof *cs->txns);
+     }
+     cs->txns[cs->n_txns++] = request_id;
+-    return request_id;
++    return json_clone(request_id);
+ }
+ 
+ /* Makes 'cs' drop its record of transaction 'request_id'.  If a reply arrives
+@@ -1380,6 +1380,7 @@ ovsdb_cs_forget_transaction(struct ovsdb_cs *cs, const struct json *request_id)
+ {
+     for (size_t i = 0; i < cs->n_txns; i++) {
+         if (json_equal(request_id, cs->txns[i])) {
++            json_destroy(cs->txns[i]);
+             cs->txns[i] = cs->txns[--cs->n_txns];
+             return true;
+         }
+diff --git a/ofproto/connmgr.c b/ofproto/connmgr.c
+index 9c5c633b41..fa8f6cd0e8 100644
+--- a/ofproto/connmgr.c
++++ b/ofproto/connmgr.c
+@@ -2140,7 +2140,7 @@ ofmonitor_report(struct connmgr *mgr, struct rule *rule,
+                  const struct rule_actions *old_actions)
+     OVS_REQUIRES(ofproto_mutex)
+ {
+-    if (rule_is_hidden(rule)) {
++    if (!mgr || rule_is_hidden(rule)) {
+         return;
+     }
+ 
+@@ -2244,6 +2244,10 @@ ofmonitor_flush(struct connmgr *mgr)
+ {
+     struct ofconn *ofconn;
+ 
++    if (!mgr) {
++        return;
++    }
++
+     LIST_FOR_EACH (ofconn, connmgr_node, &mgr->conns) {
+         struct rconn_packet_counter *counter = ofconn->monitor_counter;
+ 
+diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c
+index 5fae46adfc..ccf97266c0 100644
+--- a/ofproto/ofproto-dpif-upcall.c
++++ b/ofproto/ofproto-dpif-upcall.c
+@@ -491,6 +491,11 @@ udpif_destroy(struct udpif *udpif)
+     dpif_register_upcall_cb(udpif->dpif, NULL, udpif);
+ 
+     for (int i = 0; i < N_UMAPS; i++) {
++        struct udpif_key *ukey;
++
++        CMAP_FOR_EACH (ukey, cmap_node, &udpif->ukeys[i].cmap) {
++            ukey_delete__(ukey);
++        }
+         cmap_destroy(&udpif->ukeys[i].cmap);
+         ovs_mutex_destroy(&udpif->ukeys[i].mutex);
+     }
+diff --git a/ovsdb/ovsdb-client.c b/ovsdb/ovsdb-client.c
+index 72756eb1f2..ba28e36d78 100644
+--- a/ovsdb/ovsdb-client.c
++++ b/ovsdb/ovsdb-client.c
+@@ -1664,14 +1664,15 @@ static void
+ do_needs_conversion(struct jsonrpc *rpc, const char *database_ OVS_UNUSED,
+                     int argc OVS_UNUSED, char *argv[])
+ {
++    const char *schema_file_name = argv[argc - 1];
+     struct ovsdb_schema *schema1;
+-    check_ovsdb_error(ovsdb_schema_from_file(argv[0], &schema1));
++    check_ovsdb_error(ovsdb_schema_from_file(schema_file_name, &schema1));
+ 
+     char *database = schema1->name;
+     open_rpc(1, NEED_DATABASE, argc, argv, &rpc, &database);
+ 
+     if (is_database_clustered(rpc, database)) {
+-        ovsdb_schema_persist_ephemeral_columns(schema1, argv[0]);
++        ovsdb_schema_persist_ephemeral_columns(schema1, schema_file_name);
+     }
+ 
+     struct ovsdb_schema *schema2 = fetch_schema(rpc, schema1->name);
+diff --git a/ovsdb/raft.c b/ovsdb/raft.c
+index ea91d1fdba..192f7f0a96 100644
+--- a/ovsdb/raft.c
++++ b/ovsdb/raft.c
+@@ -940,6 +940,34 @@ raft_reset_ping_timer(struct raft *raft)
+     raft->ping_timeout = time_msec() + raft->election_timer / 3;
+ }
+ 
++static void
++raft_conn_update_probe_interval(struct raft *raft, struct raft_conn *r_conn)
++{
++    /* Inactivity probe will be sent if connection will remain idle for the
++     * time of an election timeout.  Connection will be dropped if inactivity
++     * will last twice that time.
++     *
++     * It's not enough to just have heartbeats if connection is still
++     * established, but no packets received from the other side.  Without
++     * inactivity probe follower will just try to initiate election
++     * indefinitely staying in 'candidate' role.  And the leader will continue
++     * to send heartbeats to the dead connection thinking that remote server
++     * is still part of the cluster. */
++    int probe_interval = raft->election_timer + ELECTION_RANGE_MSEC;
++
++    jsonrpc_session_set_probe_interval(r_conn->js, probe_interval);
++}
++
++static void
++raft_update_probe_intervals(struct raft *raft)
++{
++    struct raft_conn *r_conn;
++
++    LIST_FOR_EACH (r_conn, list_node, &raft->conns) {
++        raft_conn_update_probe_interval(raft, r_conn);
++    }
++}
++
+ static void
+ raft_add_conn(struct raft *raft, struct jsonrpc_session *js,
+               const struct uuid *sid, bool incoming)
+@@ -954,7 +982,7 @@ raft_add_conn(struct raft *raft, struct jsonrpc_session *js,
+                                               &conn->sid);
+     conn->incoming = incoming;
+     conn->js_seqno = jsonrpc_session_get_seqno(conn->js);
+-    jsonrpc_session_set_probe_interval(js, 0);
++    raft_conn_update_probe_interval(raft, conn);
+     jsonrpc_session_set_backlog_threshold(js, raft->conn_backlog_max_n_msgs,
+                                               raft->conn_backlog_max_n_bytes);
+ }
+@@ -2804,6 +2832,7 @@ raft_update_commit_index(struct raft *raft, uint64_t new_commit_index)
+                           raft->election_timer, e->election_timer);
+                 raft->election_timer = e->election_timer;
+                 raft->election_timer_new = 0;
++                raft_update_probe_intervals(raft);
+             }
+             if (e->servers) {
+                 /* raft_run_reconfigure() can write a new Raft entry, which can
+@@ -2820,6 +2849,7 @@ raft_update_commit_index(struct raft *raft, uint64_t new_commit_index)
+                 VLOG_INFO("Election timer changed from %"PRIu64" to %"PRIu64,
+                           raft->election_timer, e->election_timer);
+                 raft->election_timer = e->election_timer;
++                raft_update_probe_intervals(raft);
+             }
+         }
+         /* Check if any pending command can be completed, and complete it.
+@@ -4468,6 +4498,8 @@ raft_unixctl_status(struct unixctl_conn *conn,
+                   : raft->leaving ? "leaving cluster"
+                   : raft->left ? "left cluster"
+                   : raft->failed ? "failed"
++                  : raft->candidate_retrying
++                      ? "disconnected from the cluster (election timeout)"
+                   : "cluster member");
+     if (raft->joining) {
+         ds_put_format(&s, "Remotes for joining:");
+diff --git a/python/ovs/db/idl.py b/python/ovs/db/idl.py
+index 5850ac7abf..4226d1cb2f 100644
+--- a/python/ovs/db/idl.py
++++ b/python/ovs/db/idl.py
+@@ -12,6 +12,7 @@
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+ 
++import collections
+ import functools
+ import uuid
+ 
+@@ -39,6 +40,10 @@ OVSDB_UPDATE2 = 1
+ CLUSTERED = "clustered"
+ 
+ 
++Notice = collections.namedtuple('Notice', ('event', 'row', 'updates'))
++Notice.__new__.__defaults__ = (None,)  # default updates=None
++
++
+ class Idl(object):
+     """Open vSwitch Database Interface Definition Language (OVSDB IDL).
+ 
+@@ -614,6 +619,7 @@ class Idl(object):
+             raise error.Error("<table-updates> is not an object",
+                               table_updates)
+ 
++        notices = []
+         for table_name, table_update in table_updates.items():
+             table = tables.get(table_name)
+             if not table:
+@@ -639,7 +645,9 @@ class Idl(object):
+                                       % (table_name, uuid_string))
+ 
+                 if version == OVSDB_UPDATE2:
+-                    if self.__process_update2(table, uuid, row_update):
++                    changes = self.__process_update2(table, uuid, row_update)
++                    if changes:
++                        notices.append(changes)
+                         self.change_seqno += 1
+                     continue
+ 
+@@ -652,17 +660,20 @@ class Idl(object):
+                     raise error.Error('<row-update> missing "old" and '
+                                       '"new" members', row_update)
+ 
+-                if self.__process_update(table, uuid, old, new):
++                changes = self.__process_update(table, uuid, old, new)
++                if changes:
++                    notices.append(changes)
+                     self.change_seqno += 1
++        for notice in notices:
++            self.notify(*notice)
+ 
+     def __process_update2(self, table, uuid, row_update):
++        """Returns Notice if a column changed, False otherwise."""
+         row = table.rows.get(uuid)
+-        changed = False
+         if "delete" in row_update:
+             if row:
+                 del table.rows[uuid]
+-                self.notify(ROW_DELETE, row)
+-                changed = True
++                return Notice(ROW_DELETE, row)
+             else:
+                 # XXX rate-limit
+                 vlog.warn("cannot delete missing row %s from table"
+@@ -681,29 +692,27 @@ class Idl(object):
+             changed = self.__row_update(table, row, row_update)
+             table.rows[uuid] = row
+             if changed:
+-                self.notify(ROW_CREATE, row)
++                return Notice(ROW_CREATE, row)
+         elif "modify" in row_update:
+             if not row:
+                 raise error.Error('Modify non-existing row')
+ 
+             old_row = self.__apply_diff(table, row, row_update['modify'])
+-            self.notify(ROW_UPDATE, row, Row(self, table, uuid, old_row))
+-            changed = True
++            return Notice(ROW_UPDATE, row, Row(self, table, uuid, old_row))
+         else:
+             raise error.Error('<row-update> unknown operation',
+                               row_update)
+-        return changed
++        return False
+ 
+     def __process_update(self, table, uuid, old, new):
+-        """Returns True if a column changed, False otherwise."""
++        """Returns Notice if a column changed, False otherwise."""
+         row = table.rows.get(uuid)
+         changed = False
+         if not new:
+             # Delete row.
+             if row:
+                 del table.rows[uuid]
+-                changed = True
+-                self.notify(ROW_DELETE, row)
++                return Notice(ROW_DELETE, row)
+             else:
+                 # XXX rate-limit
+                 vlog.warn("cannot delete missing row %s from table %s"
+@@ -723,7 +732,7 @@ class Idl(object):
+             if op == ROW_CREATE:
+                 table.rows[uuid] = row
+             if changed:
+-                self.notify(ROW_CREATE, row)
++                return Notice(ROW_CREATE, row)
+         else:
+             op = ROW_UPDATE
+             if not row:
+@@ -737,8 +746,8 @@ class Idl(object):
+             if op == ROW_CREATE:
+                 table.rows[uuid] = row
+             if changed:
+-                self.notify(op, row, Row.from_json(self, table, uuid, old))
+-        return changed
++                return Notice(op, row, Row.from_json(self, table, uuid, old))
++        return False
+ 
+     def __check_server_db(self):
+         """Returns True if this is a valid server database, False otherwise."""
+diff --git a/tests/automake.mk b/tests/automake.mk
+index 677b99a6b4..fc80e027df 100644
+--- a/tests/automake.mk
++++ b/tests/automake.mk
+@@ -134,7 +134,8 @@ FUZZ_REGRESSION_TESTS = \
+ 	tests/fuzz-regression/ofp_print_fuzzer-5722747668791296 \
+ 	tests/fuzz-regression/ofp_print_fuzzer-6285128790704128 \
+ 	tests/fuzz-regression/ofp_print_fuzzer-6470117922701312 \
+-	tests/fuzz-regression/ofp_print_fuzzer-6502620041576448
++	tests/fuzz-regression/ofp_print_fuzzer-6502620041576448 \
++	tests/fuzz-regression/ofp_print_fuzzer-6540965472632832
+ $(srcdir)/tests/fuzz-regression-list.at: tests/automake.mk
+ 	$(AM_V_GEN)for name in $(FUZZ_REGRESSION_TESTS); do \
+             basename=`echo $$name | sed 's,^.*/,,'`; \
+diff --git a/tests/daemon.at b/tests/daemon.at
+index a7982de381..39d9aa391e 100644
+--- a/tests/daemon.at
++++ b/tests/daemon.at
+@@ -218,11 +218,11 @@ OVS_WAIT_UNTIL([test -s ovsdb-server.pid])
+ OVS_WAIT_UNTIL([sc query ovsdb-server | grep STATE | grep RUNNING > /dev/null 2>&1])
+ AT_CHECK([kill -0 `cat ovsdb-server.pid`], [0], [ignore])
+ AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-dbs], [0],
+-[Open_vSwitch
++[_Server
+ ])
+ AT_CHECK([sc stop ovsdb-server], [0], [ignore])
+ OVS_WAIT_UNTIL([test ! -s ovsdb-server.pid])
+-AT_CHECK([sc query ovsdb-server | grep STATE | grep STOPPED], [0], [ignore])
++OVS_WAIT_UNTIL([sc query ovsdb-server | grep STATE | grep STOPPED > /dev/null 2>&1])
+ AT_CHECK([sc delete ovsdb-server], [0], [[[SC]] DeleteService SUCCESS
+ ])
+ AT_CLEANUP
+diff --git a/tests/dpif-netdev.at b/tests/dpif-netdev.at
+index 2862a3c9b9..3e62225571 100644
+--- a/tests/dpif-netdev.at
++++ b/tests/dpif-netdev.at
+@@ -589,3 +589,20 @@ arp,in_port=ANY,dl_vlan=11,dl_vlan_pcp=7,vlan_tci1=0x0000,dl_src=00:06:07:08:09:
+ 
+ DPIF_NETDEV_FLOW_HW_OFFLOAD_OFFSETS_VID_ARP([dummy])
+ DPIF_NETDEV_FLOW_HW_OFFLOAD_OFFSETS_VID_ARP([dummy-pmd])
++
++AT_SETUP([dpif-netdev - check dpctl/add-flow in_port exact match])
++OVS_VSWITCHD_START(
++  [add-port br0 p1 \
++   -- set interface p1 type=dummy options:pstream=punix:$OVS_RUNDIR/p0.sock \
++   -- set bridge br0 datapath-type=dummy \
++                     other-config:datapath-id=1234 fail-mode=secure])
++
++AT_CHECK([ovs-appctl dpctl/add-flow "eth(),eth_type(0x0800),ipv4()" "3"], [2],
++[], [dnl
++ovs-vswitchd: updating flow table (Invalid argument)
++ovs-appctl: ovs-vswitchd: server returned an error
++])
++OVS_WAIT_UNTIL([grep "flow: in_port is not an exact match" ovs-vswitchd.log])
++OVS_VSWITCHD_STOP(["/flow: in_port is not an exact match/d
++/failed to put/d"])
++AT_CLEANUP
+diff --git a/tests/fuzz-regression-list.at b/tests/fuzz-regression-list.at
+index e3173fb88f..2347c690ef 100644
+--- a/tests/fuzz-regression-list.at
++++ b/tests/fuzz-regression-list.at
+@@ -21,3 +21,4 @@ TEST_FUZZ_REGRESSION([ofp_print_fuzzer-5722747668791296])
+ TEST_FUZZ_REGRESSION([ofp_print_fuzzer-6285128790704128])
+ TEST_FUZZ_REGRESSION([ofp_print_fuzzer-6470117922701312])
+ TEST_FUZZ_REGRESSION([ofp_print_fuzzer-6502620041576448])
++TEST_FUZZ_REGRESSION([ofp_print_fuzzer-6540965472632832])
+diff --git a/tests/fuzz-regression/ofp_print_fuzzer-6540965472632832 b/tests/fuzz-regression/ofp_print_fuzzer-6540965472632832
+new file mode 100644
+index 0000000000..e69de29bb2
+diff --git a/tests/ovsdb-client.at b/tests/ovsdb-client.at
+index 8d777a0275..5e3b26aea8 100644
+--- a/tests/ovsdb-client.at
++++ b/tests/ovsdb-client.at
+@@ -12,6 +12,30 @@ AT_CHECK([ovsdb-client get-schema-cksum unix:socket ordinals], [0], [12345678 9
+ OVSDB_SERVER_SHUTDOWN
+ AT_CLEANUP
+ 
++AT_SETUP([ovsdb-client needs-conversion (no conversion needed)])
++AT_KEYWORDS([ovsdb client file positive])
++ordinal_schema > schema
++touch .db.~lock~
++AT_CHECK([ovsdb-tool create db schema], [0], [], [ignore])
++AT_CHECK([ovsdb-server --detach --no-chdir --pidfile --remote=punix:socket db], [0], [ignore], [ignore])
++AT_CHECK([ovsdb-client needs-conversion unix:socket schema], [0], [no
++])
++OVSDB_SERVER_SHUTDOWN
++AT_CLEANUP
++
++AT_SETUP([ovsdb-client needs-conversion (conversion needed)])
++AT_KEYWORDS([ovsdb client file positive])
++ordinal_schema > schema
++touch .db.~lock~
++AT_CHECK([ovsdb-tool create db schema], [0], [], [ignore])
++AT_CHECK([ovsdb-server --detach --no-chdir --pidfile --remote=punix:socket db], [0], [ignore], [ignore])
++sed 's/5\.1\.3/5.1.4/' < schema > schema2
++AT_CHECK([diff schema schema2], [1], [ignore])
++AT_CHECK([ovsdb-client needs-conversion unix:socket schema2], [0], [yes
++])
++OVSDB_SERVER_SHUTDOWN
++AT_CLEANUP
++
+ AT_SETUP([ovsdb-client backup and restore])
+ AT_KEYWORDS([ovsdb client positive])
+ 
+diff --git a/tests/ovsdb-idl.at b/tests/ovsdb-idl.at
+index 4b4791a7da..e00e67e949 100644
+--- a/tests/ovsdb-idl.at
++++ b/tests/ovsdb-idl.at
+@@ -1486,6 +1486,28 @@ m4_define([OVSDB_CHECK_IDL_NOTIFY],
+    [OVSDB_CHECK_IDL_PY([$1], [], [$2], [$3], [notify $4], [$5])
+     OVSDB_CHECK_IDL_SSL_PY([$1], [], [$2], [$3], [notify $4], [$5])])
+ 
++OVSDB_CHECK_IDL_NOTIFY([simple link idl verify notify],
++  [['track-notify' \
++    '["idltest",
++       {"op": "insert",
++       "table": "link1",
++       "row": {"i": 1, "k": ["named-uuid", "l1row"], "l2": ["set", [["named-uuid", "l2row"]]]},
++       "uuid-name": "l1row"},
++      {"op": "insert",
++       "table": "link2",
++       "uuid-name": "l2row",
++       "row": {"i": 2, "l1": ["set", [["named-uuid", "l1row"]]]}}]']],
++[[000: empty
++000: event:create, row={uuid=<0>}, updates=None
++000: event:create, row={uuid=<1>}, updates=None
++001: {"error":null,"result":[{"uuid":["uuid","<2>"]},{"uuid":["uuid","<3>"]}]}
++002: event:create, row={i=1 uuid=<2> l2=[<3>]}, updates=None
++002: event:create, row={i=2 uuid=<3> l1=[<2>]}, updates=None
++002: i=1 k=1 ka=[] l2=2 uuid=<2>
++002: i=2 l1=1 uuid=<3>
++003: done
++]])
++
+ OVSDB_CHECK_IDL_NOTIFY([simple idl verify notify],
+   [['track-notify' \
+     '["idltest",
+diff --git a/tests/test-ovsdb.py b/tests/test-ovsdb.py
+index a196802743..9d3228f234 100644
+--- a/tests/test-ovsdb.py
++++ b/tests/test-ovsdb.py
+@@ -162,6 +162,8 @@ def get_simple_printable_row_string(row, columns):
+             if isinstance(value, dict):
+                 value = sorted((row_to_uuid(k), row_to_uuid(v))
+                                for k, v in value.items())
++            if isinstance(value, (list, tuple)):
++                value = sorted((row_to_uuid(v) for v in value))
+             s += "%s=%s " % (column, value)
+     s = s.strip()
+     s = re.sub('""|,|u?\'', "", s)
+@@ -172,9 +174,10 @@ def get_simple_printable_row_string(row, columns):
+     return s
+ 
+ 
+-def get_simple_table_printable_row(row):
++def get_simple_table_printable_row(row, *additional_columns):
+     simple_columns = ["i", "r", "b", "s", "u", "ia",
+                       "ra", "ba", "sa", "ua", "uuid"]
++    simple_columns.extend(additional_columns)
+     return get_simple_printable_row_string(row, simple_columns)
+ 
+ 
+@@ -637,7 +640,8 @@ def do_idl(schema_file, remote, *commands):
+     def mock_notify(event, row, updates=None):
+         output = "%03d: " % step
+         output += "event:" + str(event) + ", row={"
+-        output += get_simple_table_printable_row(row) + "}, updates="
++        output += get_simple_table_printable_row(row,
++                                                 'l2', 'l1') + "}, updates="
+         if updates is None:
+             output += "None"
+         else:
+diff --git a/utilities/ovs-ctl.in b/utilities/ovs-ctl.in
+index d71c34e691..4156da20ef 100644
+--- a/utilities/ovs-ctl.in
++++ b/utilities/ovs-ctl.in
+@@ -226,7 +226,9 @@ start_forwarding () {
+     if test X"$OVS_VSWITCHD" = Xyes; then
+         do_start_forwarding || return 1
+     fi
+-    set_hostname &
++    if test X"$RECORD_HOSTNAME" = Xyes; then
++        set_hostname &
++    fi
+     return 0
+ }
+ 
+@@ -317,6 +319,7 @@ set_defaults () {
+     SYSTEM_ID=
+ 
+     FULL_HOSTNAME=yes
++    RECORD_HOSTNAME=yes
+ 
+     DELETE_BRIDGES=no
+     DELETE_TRANSIENT_PORTS=no
+@@ -378,19 +381,24 @@ This program is intended to be invoked internally by Open vSwitch startup
+ scripts.  System administrators should not normally invoke it directly.
+ 
+ Commands:
+-  start                   start Open vSwitch daemons
+-  stop                    stop Open vSwitch daemons
+-  restart                 stop and start Open vSwitch daemons
+-  status                  check whether Open vSwitch daemons are running
+-  version                 print versions of Open vSwitch daemons
+-  load-kmod               insert modules if not already present
+-  force-reload-kmod       save OVS network device state, stop OVS, unload kernel
+-                          module, reload kernel module, start OVS, restore state
+-  enable-protocol         enable protocol specified in options with iptables
+-  delete-transient-ports  delete transient (other_config:transient=true) ports
+-  start-ovs-ipsec         start Open vSwitch ipsec daemon
+-  stop-ovs-ipsec          stop Open vSwitch ipsec daemon
+-  help                    display this help message
++  start                       start Open vSwitch daemons
++  stop                        stop Open vSwitch daemons
++  restart                     stop and start Open vSwitch daemons
++  status                      check whether Open vSwitch daemons are running
++  version                     print versions of Open vSwitch daemons
++  load-kmod                   insert modules if not already present
++  force-reload-kmod           save OVS network device state, stop OVS, unload
++                              kernel module, reload kernel module, start OVS,
++                              restore state
++  enable-protocol             enable protocol specified in options with
++                              iptables
++  delete-transient-ports      delete transient (other_config:transient=true)
++                              ports
++  start-ovs-ipsec             start Open vSwitch ipsec daemon
++  stop-ovs-ipsec              stop Open vSwitch ipsec daemon
++  record-hostname-if-not-set  determine the system hostname and record it in
++                              the Open vSwitch database if not already set
++  help                        display this help message
+ 
+ One of the following options is required for "start", "restart" and "force-reload-kmod":
+   --system-id=UUID   set specific ID to uniquely identify this system
+@@ -411,6 +419,8 @@ Less important options for "start", "restart" and "force-reload-kmod":
+   --ovsdb-server-priority=NICE   set ovsdb-server's niceness (default: $OVSDB_SERVER_PRIORITY)
+   --ovs-vswitchd-priority=NICE   set ovs-vswitchd's niceness (default: $OVS_VSWITCHD_PRIORITY)
+   --no-full-hostname             set short hostname instead of full hostname
++  --no-record-hostname           do not attempt to determine/record system
++                                 hostname as part of start command
+ 
+ Debugging options for "start", "restart" and "force-reload-kmod":
+   --ovsdb-server-wrapper=WRAPPER
+@@ -569,6 +579,9 @@ case $command in
+     stop-ovs-ipsec)
+         stop_ovs_ipsec
+         ;;
++    record-hostname-if-not-set)
++        set_hostname
++        ;;
+     help)
+         usage
+         ;;
+diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml
+index a2ad84edef..4597a215d9 100644
+--- a/vswitchd/vswitch.xml
++++ b/vswitchd/vswitch.xml
+@@ -4660,7 +4660,8 @@ ovs-vsctl add-port br0 p0 -- set Interface p0 type=patch options:peer=p1 \
+         packets per second the CIR would be set to to to 46000000. This value
+         can be broken into '1,000,000 x 46'. Where 1,000,000 is the policing
+         rate for the number of packets per second and 46 represents the size
+-        of the packet data for a 64 byte ip packet.
++        of the packet data for a 64 bytes IP packet without 14 bytes Ethernet
++        and 4 bytes FCS header.
+       </column>
+       <column name="other_config" key="cbs" type='{"type": "integer"}'>
+         The Committed Burst Size (CBS) is measured in bytes and represents a
+@@ -4681,7 +4682,8 @@ ovs-vsctl add-port br0 p0 -- set Interface p0 type=patch options:peer=p1 \
+         packets per second the EIR would be set to to to 46000000. This value
+         can be broken into '1,000,000 x 46'. Where 1,000,000 is the policing
+         rate for the number of packets per second and 46 represents the size
+-        of the packet data for a 64 byte ip packet.
++        of the packet data for a 64 bytes IP packet without 14 bytes Ethernet
++        and 4 bytes FCS header.
+       </column>
+       <column name="other_config" key="ebs" type='{"type": "integer"}'>
+         The Excess Burst Size (EBS) is measured in bytes and represents a
diff --git a/SPECS/openvswitch2.15.spec b/SPECS/openvswitch2.15.spec
new file mode 100644
index 0000000..331808d
--- /dev/null
+++ b/SPECS/openvswitch2.15.spec
@@ -0,0 +1,711 @@
+# 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 pkgname openvswitch2.15
+
+
+%if 0%{?commit:1}
+%global shortcommit %(c=%{commit}; echo ${c:0:7})
+%endif
+
+# 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
+
+# FIXME Test "STP - flush the fdb and mdb when topology changed" fails on s390x
+# FIXME 2 tests fails on ppc64le. They will be hopefully fixed before official 2.11
+%ifarch %{ix86} x86_64 aarch64
+%bcond_without check
+%else
+%bcond_with check
+%endif
+# option to run kernel datapath tests, requires building as root!
+%bcond_with check_datapath_kernel
+# option to build with libcap-ng, needed for running OVS as regular user
+%bcond_without libcapng
+# option to build with ipsec support
+%bcond_without ipsec
+
+# 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
+
+Name: %{pkgname}
+Summary: Open vSwitch
+Group: System Environment/Daemons daemon/database/utilities
+URL: http://www.openvswitch.org/
+Version: 2.15.0
+Release: 3%{?dist}
+
+# Nearly all of openvswitch is ASL 2.0.  The bugtool is LGPLv2+, and the
+# lib/sflow*.[ch] files are SISSL
+# datapath/ is GPLv2 (although not built into any of the binary packages)
+License: ASL 2.0 and LGPLv2+ and SISSL
+
+%define dpdkver 20.11
+%define dpdkdir dpdk
+%define dpdksver %(echo %{dpdkver} | cut -d. -f-2)
+# NOTE: DPDK does not currently build for s390x
+# DPDK on aarch64 is not stable enough to be enabled in FDP
+%if 0%{?rhel} > 7 || 0%{?fedora}
+%define dpdkarches x86_64 ppc64le
+%else
+%define dpdkarches
+%endif
+
+%if 0%{?commit:1}
+Source: https://github.com/openvswitch/ovs/archive/%{commit}.tar.gz#/openvswitch-%{commit}.tar.gz
+%else
+Source: https://github.com/openvswitch/ovs/archive/v%{version}.tar.gz#/openvswitch-%{version}.tar.gz
+%endif
+Source10: https://fast.dpdk.org/rel/dpdk-%{dpdkver}.tar.xz
+
+%define docutilsver 0.12
+%define pygmentsver 1.4
+%define sphinxver   1.2.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
+
+Patch:     openvswitch-%{version}.patch
+
+# The DPDK is designed to optimize througput of network traffic using, among
+# other techniques, carefully crafted assembly instructions.  As such it
+# needs extensive work to port it to other architectures.
+ExclusiveArch: x86_64 aarch64 ppc64le s390x
+
+# Do not enable this otherwise YUM will break on any upgrade.
+# Provides: openvswitch
+Conflicts: openvswitch < 2.15
+Conflicts: openvswitch-dpdk < 2.15
+Conflicts: openvswitch2.10
+Conflicts: openvswitch2.11
+Conflicts: openvswitch2.12
+Conflicts: openvswitch2.13
+Conflicts: openvswitch2.14
+
+# 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} > 7 || 0%{?fedora}
+BuildRequires: python3-pyOpenSSL
+%endif
+%if %{with check_datapath_kernel}
+BuildRequires: nmap-ncat
+# would be useful but not available in RHEL or EPEL
+#BuildRequires: pyftpdlib
+%endif
+
+%if %{with libcapng}
+BuildRequires: libcap-ng libcap-ng-devel
+%endif
+
+%ifarch %{dpdkarches}
+BuildRequires: meson
+# DPDK driver dependencies
+BuildRequires: zlib-devel numactl-devel
+%ifarch x86_64
+BuildRequires: rdma-core-devel >= 15 libmnl-devel
+%endif
+
+# Required by packaging policy for the bundled DPDK
+Provides: bundled(dpdk) = %{dpdkver}
+%endif
+
+Requires: openssl iproute module-init-tools
+#Upstream kernel commit 4f647e0a3c37b8d5086214128614a136064110c3
+#Requires: kernel >= 3.15.0-0
+Requires: openvswitch-selinux-extra-policy
+
+Requires(pre): shadow-utils
+Requires(post): /bin/sed
+Requires(post): /usr/sbin/usermod
+Requires(post): /usr/sbin/groupadd
+Requires(post): systemd-units
+Requires(preun): systemd-units
+Requires(postun): systemd-units
+Obsoletes: openvswitch-controller <= 0:2.1.0-1
+
+%description
+Open vSwitch provides standard network bridging functions and
+support for the OpenFlow protocol for remote per-flow control of
+traffic.
+
+%package -n python3-%{pkgname}
+Summary: Open vSwitch python3 bindings
+License: ASL 2.0
+Requires: %{pkgname} = %{?epoch:%{epoch}:}%{version}-%{release}
+Provides: python-%{pkgname} = %{?epoch:%{epoch}:}%{version}-%{release}
+
+%description -n python3-%{pkgname}
+Python bindings for the Open vSwitch database
+
+%package test
+Summary: Open vSwitch testing utilities
+License: ASL 2.0
+BuildArch: noarch
+Requires: python3-%{pkgname} = %{?epoch:%{epoch}:}%{version}-%{release}
+Requires: tcpdump
+
+%description test
+Utilities that are useful to diagnose performance and connectivity
+issues in Open vSwitch setup.
+
+%package devel
+Summary: Open vSwitch OpenFlow development package (library, headers)
+License: ASL 2.0
+Requires: %{pkgname} = %{?epoch:%{epoch}:}%{version}-%{release}
+
+%description devel
+This provides shared library, libopenswitch.so and the openvswitch header
+files needed to build an external application.
+
+%if 0%{?rhel} > 7 || 0%{?fedora} > 28
+%package -n network-scripts-%{name}
+Summary: Open vSwitch legacy network service support
+License: ASL 2.0
+Requires: network-scripts
+Supplements: (%{name} and network-scripts)
+
+%description -n network-scripts-%{name}
+This provides the ifup and ifdown scripts for use with the legacy network
+service.
+%endif
+
+%if %{with ipsec}
+%package ipsec
+Summary: Open vSwitch IPsec tunneling support
+License: ASL 2.0
+Requires: python3-%{pkgname} = %{?epoch:%{epoch}:}%{version}-%{release}
+Requires: libreswan
+
+%description ipsec
+This package provides IPsec tunneling support for OVS tunnels.
+%endif
+
+%prep
+%if 0%{?commit:1}
+%setup -q -n ovs-%{commit} -a 10
+%else
+%setup -q -n ovs-%{version} -a 10
+%endif
+%if ! %{external_sphinx}
+%if 0%{?commit:1}
+%setup -n ovs-%{commit} -q -D -T -a 100 -a 101 -a 102
+%else
+%setup -n ovs-%{version} -q -D -T -a 100 -a 101 -a 102
+%endif
+%endif
+
+mv dpdk-*/ %{dpdkdir}/
+
+# FIXME should we propose a way to do that upstream?
+sed -ri "/^subdir\('(usertools|app)'\)/d" %{dpdkdir}/meson.build
+
+%patch -p1
+
+%build
+# Build Sphinx on RHEL
+%if ! %{external_sphinx}
+export PYTHONPATH="${PYTHONPATH:+$PYTHONPATH:}%{_builddir}/pytmp/lib/python"
+for x in docutils-%{docutilsver} Pygments-%{pygmentsver} Sphinx-%{sphinxver}; do
+    pushd "$x"
+    python2 setup.py install --home %{_builddir}/pytmp
+    popd
+done
+
+export PATH="$PATH:%{_builddir}/pytmp/bin"
+%endif
+
+./boot.sh
+
+%ifarch %{dpdkarches}    # build dpdk
+# Lets build DPDK first
+cd %{dpdkdir}
+
+ENABLED_DRIVERS=(
+    bus/pci
+    bus/vdev
+    mempool/ring
+    net/failsafe
+    net/i40e
+    net/ring
+    net/vhost
+    net/virtio
+    net/tap
+)
+
+%ifarch x86_64
+ENABLED_DRIVERS+=(
+    bus/vmbus
+    common/iavf
+    common/mlx5
+    net/bnxt
+    net/enic
+    net/iavf
+    net/ice
+    net/mlx4
+    net/mlx5
+    net/netvsc
+    net/nfp
+    net/qede
+    net/vdev_netvsc
+)
+%endif
+
+%ifarch aarch64 x86_64
+ENABLED_DRIVERS+=(
+    net/e1000
+    net/ixgbe
+)
+%endif
+
+# Since upstream doesn't have a way
+for driver in drivers/*/*/; do
+    driver=${driver#drivers/}
+    driver=${driver%/}
+    [[ " ${ENABLED_DRIVERS[@]} " == *" $driver "* ]] || \
+        disable_drivers="${disable_drivers:+$disable_drivers,}"$driver
+done
+
+#CFLAGS="$(echo %{optflags} | sed -e 's:-Wall::g' -e 's:-march=[[:alnum:]]* ::g') -Wformat -fPIC %{_hardening_ldflags}" \
+%set_build_flags
+%__meson --prefix=%{_builddir}/dpdk-build \
+         --buildtype=plain \
+         -Ddisable_drivers="$disable_drivers" \
+         -Dmachine=default \
+         -Dmax_ethports=128 \
+         -Dmax_numa_nodes=8 \
+         -Dtests=false \
+         %{_vpath_builddir}
+%meson_build
+%__meson install -C %{_vpath_builddir} --no-rebuild
+
+# FIXME currently with LTO enabled OVS tries to link with both static and shared libraries
+rm -v %{_builddir}/dpdk-build/%{_lib}/*.so*
+
+# Generate a list of supported drivers, its hard to tell otherwise.
+cat << EOF > README.DPDK-PMDS
+DPDK drivers included in this package:
+
+EOF
+
+for f in %{_builddir}/dpdk-build/%{_lib}/librte_net_*.a; do
+    basename ${f} | cut -c12- | cut -d. -f1 | tr [:lower:] [:upper:]
+done >> README.DPDK-PMDS
+
+cat << EOF >> README.DPDK-PMDS
+
+For further information about the drivers, see
+http://dpdk.org/doc/guides-%{dpdksver}/nics/index.html
+EOF
+
+cd -
+%endif    # build dpdk
+
+# And now for OVS...
+mkdir build-shared build-static
+pushd build-shared
+ln -s ../configure
+%configure \
+%if %{with libcapng}
+        --enable-libcapng \
+%else
+        --disable-libcapng \
+%endif
+        --disable-static \
+        --enable-shared \
+        --enable-ssl \
+        --with-pkidir=%{_sharedstatedir}/openvswitch/pki
+make %{?_smp_mflags}
+popd
+pushd build-static
+ln -s ../configure
+%ifarch %{dpdkarches}
+PKG_CONFIG_PATH=%{_builddir}/dpdk-build/%{_lib}/pkgconfig \
+%endif
+%configure \
+%if %{with libcapng}
+        --enable-libcapng \
+%else
+        --disable-libcapng \
+%endif
+        --enable-ssl \
+%ifarch %{dpdkarches}
+        --with-dpdk=static \
+%endif
+        --with-pkidir=%{_sharedstatedir}/openvswitch/pki
+make %{?_smp_mflags}
+popd
+
+/usr/bin/python3 build-aux/dpdkstrip.py \
+        --dpdk \
+        < rhel/usr_lib_systemd_system_ovs-vswitchd.service.in \
+        > rhel/usr_lib_systemd_system_ovs-vswitchd.service
+
+%install
+rm -rf $RPM_BUILD_ROOT
+make -C build-shared install-libLTLIBRARIES DESTDIR=$RPM_BUILD_ROOT
+make -C build-static install DESTDIR=$RPM_BUILD_ROOT
+
+install -d -m 0755 $RPM_BUILD_ROOT%{_rundir}/openvswitch
+install -d -m 0750 $RPM_BUILD_ROOT%{_localstatedir}/log/openvswitch
+install -d -m 0755 $RPM_BUILD_ROOT%{_sysconfdir}/openvswitch
+
+install -p -D -m 0644 rhel/usr_lib_udev_rules.d_91-vfio.rules \
+        $RPM_BUILD_ROOT%{_udevrulesdir}/91-vfio.rules
+
+install -p -D -m 0644 \
+        rhel/usr_share_openvswitch_scripts_systemd_sysconfig.template \
+        $RPM_BUILD_ROOT/%{_sysconfdir}/sysconfig/openvswitch
+
+for service in openvswitch ovsdb-server ovs-vswitchd \
+               ovs-delete-transient-ports; do
+        install -p -D -m 0644 \
+                        rhel/usr_lib_systemd_system_${service}.service \
+                        $RPM_BUILD_ROOT%{_unitdir}/${service}.service
+done
+
+%if %{with ipsec}
+install -p -D -m 0644 rhel/usr_lib_systemd_system_openvswitch-ipsec.service \
+                      $RPM_BUILD_ROOT%{_unitdir}/openvswitch-ipsec.service
+%endif
+
+install -m 0755 rhel/etc_init.d_openvswitch \
+        $RPM_BUILD_ROOT%{_datadir}/openvswitch/scripts/openvswitch.init
+
+install -p -D -m 0644 rhel/etc_openvswitch_default.conf \
+        $RPM_BUILD_ROOT/%{_sysconfdir}/openvswitch/default.conf
+
+install -p -D -m 0644 rhel/etc_logrotate.d_openvswitch \
+        $RPM_BUILD_ROOT/%{_sysconfdir}/logrotate.d/openvswitch
+
+install -m 0644 vswitchd/vswitch.ovsschema \
+        $RPM_BUILD_ROOT/%{_datadir}/openvswitch/vswitch.ovsschema
+
+install -d -m 0755 $RPM_BUILD_ROOT/%{_sysconfdir}/sysconfig/network-scripts/
+install -p -m 0755 rhel/etc_sysconfig_network-scripts_ifdown-ovs \
+        $RPM_BUILD_ROOT/%{_sysconfdir}/sysconfig/network-scripts/ifdown-ovs
+install -p -m 0755 rhel/etc_sysconfig_network-scripts_ifup-ovs \
+        $RPM_BUILD_ROOT/%{_sysconfdir}/sysconfig/network-scripts/ifup-ovs
+
+install -d -m 0755 $RPM_BUILD_ROOT%{python3_sitelib}
+cp -a $RPM_BUILD_ROOT/%{_datadir}/openvswitch/python/ovstest \
+        $RPM_BUILD_ROOT%{python3_sitelib}
+
+# Build the JSON C extension for the Python lib (#1417738)
+pushd python
+(
+export CPPFLAGS="-I ../include -I ../build-shared/include"
+export LDFLAGS="%{__global_ldflags} -L $RPM_BUILD_ROOT%{_libdir}"
+%py3_build
+%py3_install
+[ -f "$RPM_BUILD_ROOT/%{python3_sitearch}/ovs/_json$(python3-config --extension-suffix)" ]
+)
+popd
+
+rm -rf $RPM_BUILD_ROOT/%{_datadir}/openvswitch/python/
+
+install -d -m 0755 $RPM_BUILD_ROOT/%{_sharedstatedir}/openvswitch
+
+install -d -m 0755 $RPM_BUILD_ROOT%{_prefix}/lib/firewalld/services/
+
+install -p -D -m 0755 \
+        rhel/usr_share_openvswitch_scripts_ovs-systemd-reload \
+        $RPM_BUILD_ROOT%{_datadir}/openvswitch/scripts/ovs-systemd-reload
+
+touch $RPM_BUILD_ROOT%{_sysconfdir}/openvswitch/conf.db
+# The db needs special permission as IPsec Pre-shared keys are stored in it.
+chmod 0640 $RPM_BUILD_ROOT%{_sysconfdir}/openvswitch/conf.db
+
+touch $RPM_BUILD_ROOT%{_sysconfdir}/openvswitch/system-id.conf
+
+# remove unpackaged files
+rm -f $RPM_BUILD_ROOT/%{_bindir}/ovs-benchmark \
+        $RPM_BUILD_ROOT/%{_bindir}/ovs-docker \
+        $RPM_BUILD_ROOT/%{_bindir}/ovs-parse-backtrace \
+        $RPM_BUILD_ROOT/%{_bindir}/ovs-testcontroller \
+        $RPM_BUILD_ROOT/%{_sbindir}/ovs-vlan-bug-workaround \
+        $RPM_BUILD_ROOT/%{_mandir}/man1/ovs-benchmark.1* \
+        $RPM_BUILD_ROOT/%{_mandir}/man8/ovs-testcontroller.* \
+        $RPM_BUILD_ROOT/%{_mandir}/man8/ovs-vlan-bug-workaround.8*
+
+%if ! %{with ipsec}
+rm -f $RPM_BUILD_ROOT/%{_datadir}/openvswitch/scripts/ovs-monitor-ipsec
+%endif
+
+# remove ovn unpackages files
+rm -f $RPM_BUILD_ROOT%{_bindir}/ovn*
+rm -f $RPM_BUILD_ROOT%{_mandir}/man1/ovn*
+rm -f $RPM_BUILD_ROOT%{_mandir}/man5/ovn*
+rm -f $RPM_BUILD_ROOT%{_mandir}/man7/ovn*
+rm -f $RPM_BUILD_ROOT%{_mandir}/man8/ovn*
+rm -f $RPM_BUILD_ROOT%{_datadir}/openvswitch/ovn*
+rm -f $RPM_BUILD_ROOT%{_datadir}/openvswitch/scripts/ovn*
+rm -f $RPM_BUILD_ROOT%{_includedir}/ovn/*
+
+%check
+%if %{with check}
+    pushd build-static
+    touch resolv.conf
+    export OVS_RESOLV_CONF=$(pwd)/resolv.conf
+    if make check TESTSUITEFLAGS='%{_smp_mflags}' ||
+       make check TESTSUITEFLAGS='--recheck'; then :;
+    else
+        cat tests/testsuite.log
+        exit 1
+    fi
+    popd
+%endif
+%if %{with check_datapath_kernel}
+    pushd build-static
+    if make check-kernel RECHECK=yes; then :;
+    else
+        cat tests/system-kmod-testsuite.log
+        exit 1
+    fi
+    popd
+%endif
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%preun
+%if 0%{?systemd_preun:1}
+    %systemd_preun openvswitch.service
+%else
+    if [ $1 -eq 0 ] ; then
+    # Package removal, not upgrade
+        /bin/systemctl --no-reload disable openvswitch.service >/dev/null 2>&1 || :
+        /bin/systemctl stop openvswitch.service >/dev/null 2>&1 || :
+    fi
+%endif
+
+%pre
+getent group openvswitch >/dev/null || groupadd -r openvswitch
+getent passwd openvswitch >/dev/null || \
+    useradd -r -g openvswitch -d / -s /sbin/nologin \
+    -c "Open vSwitch Daemons" openvswitch
+
+%ifarch %{dpdkarches}
+    getent group hugetlbfs >/dev/null || groupadd hugetlbfs
+    usermod -a -G hugetlbfs openvswitch
+%endif
+exit 0
+
+%post
+if [ $1 -eq 1 ]; then
+    sed -i 's:^#OVS_USER_ID=:OVS_USER_ID=:' /etc/sysconfig/openvswitch
+
+%ifarch %{dpdkarches}
+    sed -i \
+        's@OVS_USER_ID="openvswitch:openvswitch"@OVS_USER_ID="openvswitch:hugetlbfs"@'\
+        /etc/sysconfig/openvswitch
+%endif
+fi
+chown -R openvswitch:openvswitch /etc/openvswitch
+
+%if 0%{?systemd_post:1}
+    %systemd_post openvswitch.service
+%else
+    # Package install, not upgrade
+    if [ $1 -eq 1 ]; then
+        /bin/systemctl daemon-reload >dev/null || :
+    fi
+%endif
+
+%postun
+%if 0%{?systemd_postun:1}
+    %systemd_postun openvswitch.service
+%else
+    /bin/systemctl daemon-reload >/dev/null 2>&1 || :
+%endif
+
+%triggerun -- openvswitch < 2.5.0-22.git20160727%{?dist}
+# old rpm versions restart the service in postun, but
+# due to systemd some preparation is needed.
+if systemctl is-active openvswitch >/dev/null 2>&1 ; then
+    /usr/share/openvswitch/scripts/ovs-ctl stop >/dev/null 2>&1 || :
+    systemctl daemon-reload >/dev/null 2>&1 || :
+    systemctl stop openvswitch ovsdb-server ovs-vswitchd >/dev/null 2>&1 || :
+    systemctl start openvswitch >/dev/null 2>&1 || :
+fi
+exit 0
+
+%files -n python3-%{pkgname}
+%{python3_sitearch}/ovs
+%{python3_sitearch}/ovs-*.egg-info
+%doc LICENSE
+
+%files test
+%{_bindir}/ovs-pcap
+%{_bindir}/ovs-tcpdump
+%{_bindir}/ovs-tcpundump
+%{_mandir}/man1/ovs-pcap.1*
+%{_mandir}/man8/ovs-tcpdump.8*
+%{_mandir}/man1/ovs-tcpundump.1*
+%{_bindir}/ovs-test
+%{_bindir}/ovs-vlan-test
+%{_bindir}/ovs-l3ping
+%{_mandir}/man8/ovs-test.8*
+%{_mandir}/man8/ovs-vlan-test.8*
+%{_mandir}/man8/ovs-l3ping.8*
+%{python3_sitelib}/ovstest
+
+%files devel
+%{_libdir}/*.so
+%{_libdir}/pkgconfig/*.pc
+%{_includedir}/openvswitch/*
+%{_includedir}/openflow/*
+%exclude %{_libdir}/*.a
+%exclude %{_libdir}/*.la
+
+%if 0%{?rhel} > 7 || 0%{?fedora} > 28
+%files -n network-scripts-%{name}
+%{_sysconfdir}/sysconfig/network-scripts/ifup-ovs
+%{_sysconfdir}/sysconfig/network-scripts/ifdown-ovs
+%endif
+
+%files
+%defattr(-,openvswitch,openvswitch)
+%dir %{_sysconfdir}/openvswitch
+%{_sysconfdir}/openvswitch/default.conf
+%config %ghost %verify(not owner group md5 size mtime) %{_sysconfdir}/openvswitch/conf.db
+%ghost %attr(0600,-,-) %verify(not owner group md5 size mtime) %{_sysconfdir}/openvswitch/.conf.db.~lock~
+%config %ghost %{_sysconfdir}/openvswitch/system-id.conf
+%defattr(-,root,root)
+%config(noreplace) %verify(not md5 size mtime) %{_sysconfdir}/sysconfig/openvswitch
+%{_sysconfdir}/bash_completion.d/ovs-appctl-bashcomp.bash
+%{_sysconfdir}/bash_completion.d/ovs-vsctl-bashcomp.bash
+%config(noreplace) %{_sysconfdir}/logrotate.d/openvswitch
+%{_unitdir}/openvswitch.service
+%{_unitdir}/ovsdb-server.service
+%{_unitdir}/ovs-vswitchd.service
+%{_unitdir}/ovs-delete-transient-ports.service
+%{_datadir}/openvswitch/scripts/openvswitch.init
+%{_datadir}/openvswitch/scripts/ovs-check-dead-ifs
+%{_datadir}/openvswitch/scripts/ovs-lib
+%{_datadir}/openvswitch/scripts/ovs-save
+%{_datadir}/openvswitch/scripts/ovs-vtep
+%{_datadir}/openvswitch/scripts/ovs-ctl
+%{_datadir}/openvswitch/scripts/ovs-kmod-ctl
+%{_datadir}/openvswitch/scripts/ovs-systemd-reload
+%config %{_datadir}/openvswitch/vswitch.ovsschema
+%config %{_datadir}/openvswitch/vtep.ovsschema
+%{_bindir}/ovs-appctl
+%{_bindir}/ovs-dpctl
+%{_bindir}/ovs-ofctl
+%{_bindir}/ovs-vsctl
+%{_bindir}/ovsdb-client
+%{_bindir}/ovsdb-tool
+%{_bindir}/ovs-pki
+%{_bindir}/vtep-ctl
+%{_libdir}/*.so.*
+%{_sbindir}/ovs-vswitchd
+%{_sbindir}/ovsdb-server
+%{_mandir}/man1/ovsdb-client.1*
+%{_mandir}/man1/ovsdb-server.1*
+%{_mandir}/man1/ovsdb-tool.1*
+%{_mandir}/man5/ovsdb.5*
+%{_mandir}/man5/ovsdb-server.5.*
+%{_mandir}/man5/ovs-vswitchd.conf.db.5*
+%{_mandir}/man5/vtep.5*
+%{_mandir}/man7/ovsdb-server.7*
+%{_mandir}/man7/ovsdb.7*
+%{_mandir}/man7/ovs-actions.7*
+%{_mandir}/man7/ovs-fields.7*
+%{_mandir}/man8/vtep-ctl.8*
+%{_mandir}/man8/ovs-appctl.8*
+%{_mandir}/man8/ovs-ctl.8*
+%{_mandir}/man8/ovs-dpctl.8*
+%{_mandir}/man8/ovs-kmod-ctl.8.*
+%{_mandir}/man8/ovs-ofctl.8*
+%{_mandir}/man8/ovs-pki.8*
+%{_mandir}/man8/ovs-vsctl.8*
+%{_mandir}/man8/ovs-vswitchd.8*
+%{_mandir}/man8/ovs-parse-backtrace.8*
+%{_udevrulesdir}/91-vfio.rules
+%doc LICENSE NOTICE README.rst NEWS rhel/README.RHEL.rst
+%ifarch %{dpdkarches}
+%doc %{dpdkdir}/README.DPDK-PMDS
+%endif
+/var/lib/openvswitch
+%attr(750,openvswitch,openvswitch) %verify(not owner group) /var/log/openvswitch
+%ghost %attr(755,root,root) %verify(not owner group) %{_rundir}/openvswitch
+%{_datadir}/openvswitch/bugtool-plugins/
+%{_datadir}/openvswitch/scripts/ovs-bugtool-*
+%{_bindir}/ovs-dpctl-top
+%{_sbindir}/ovs-bugtool
+%{_mandir}/man8/ovs-dpctl-top.8*
+%{_mandir}/man8/ovs-bugtool.8*
+%if (0%{?rhel} && 0%{?rhel} <= 7) || (0%{?fedora} && 0%{?fedora} < 29)
+%{_sysconfdir}/sysconfig/network-scripts/ifup-ovs
+%{_sysconfdir}/sysconfig/network-scripts/ifdown-ovs
+%endif
+
+%if %{with ipsec}
+%files ipsec
+%{_datadir}/openvswitch/scripts/ovs-monitor-ipsec
+%{_unitdir}/openvswitch-ipsec.service
+%endif
+
+%changelog
+* Tue Mar 16 2021 Open vSwitch CI <ovs-team@redhat.com> - 2.15.0-3
+- Merging upstream branch-2.15
+  [c4fc969d7eeee55f3b6b248018c9575a83710044]
+
+* Tue Feb 16 2021 Timothy Redaelli <tredaelli@redhat.com> - 2.15.0-2
+- build with ipsec support by default
+  [105482aee70fd8c98e848e260e82a135bc84d2ed]
+
+* Mon Feb 15 2021 Timothy Redaelli <tredaelli@redhat.com> - 2.15.0-1
+- Use official 2.15.0 tarball
+  [9e107c6359c1fe18fb0083ffea5de739a62b21a6]
+