diff --git a/.ovn2.13.metadata b/.ovn2.13.metadata
new file mode 100644
index 0000000..543429b
--- /dev/null
+++ b/.ovn2.13.metadata
@@ -0,0 +1,5 @@
+002450621b33c5690060345b0aac25bc2426d675 SOURCES/docutils-0.12.tar.gz
+b5734e2bdf09d15d8950b3423dbecec9825d129a SOURCES/openvswitch-2.13.0.tar.gz
+3fac0d814f52e9744195042bb9a5e93561eec9bc SOURCES/ovn-2.13.0.tar.gz
+d34f96421a86004aa5d26ecf975edefd09f948b1 SOURCES/Pygments-1.4.tar.gz
+6beb30f18ffac3de7689b7fd63e9a8a7d9c8df3a SOURCES/Sphinx-1.1.3.tar.gz
diff --git a/SOURCES/0001-Add-SCTP-support-to-load-balancers.patch b/SOURCES/0001-Add-SCTP-support-to-load-balancers.patch
new file mode 100644
index 0000000..2c966fa
--- /dev/null
+++ b/SOURCES/0001-Add-SCTP-support-to-load-balancers.patch
@@ -0,0 +1,364 @@
+From 080b77af805d1c48f48c617c1fab095edcebaffd Mon Sep 17 00:00:00 2001
+From: Mark Michelson <mmichels@redhat.com>
+Date: Mon, 9 Mar 2020 17:09:15 -0400
+Subject: [PATCH] Add SCTP support to load balancers.
+
+This allows for load balancers to use SCTP as a supported protocol in
+addition to the already-supported UDP and TCP.
+
+With this patch, health checks are not supported for SCTP load
+balancers. A test has been added to ensure that this is the case. Health
+checks should be added for SCTP load balancers in the near future. When
+that's done, the existing test can be updated to ensure that the SCTP
+health check works properly.
+
+Signed-off-by: Mark Michelson <mmichels@redhat.com>
+Acked-by: Numan Siddique <numans@ovn.org>
+(cherry picked from upstream commit c4700eed17da8615107553aec82852a37d401821)
+
+Change-Id: Iecbc4a2329716aaa0f37a5f53acd5b5cfa74d133
+---
+ lib/actions.c         |   8 ++--
+ northd/ovn-northd.c   |  55 ++++++++++++++---------
+ ovn-nb.ovsschema      |   6 +--
+ ovn-nb.xml            |  10 ++---
+ tests/ovn.at          | 121 +++++++++++++++++++++++++++++++++++++++++++++++++-
+ utilities/ovn-nbctl.c |   8 ++--
+ 6 files changed, 170 insertions(+), 38 deletions(-)
+
+diff --git a/lib/actions.c b/lib/actions.c
+index f22acdd..6351db7 100644
+--- a/lib/actions.c
++++ b/lib/actions.c
+@@ -1957,10 +1957,12 @@ validate_empty_lb_backends(struct action_context *ctx,
+             }
+             break;
+         case EMPTY_LB_PROTOCOL:
+-            if (strcmp(c->string, "tcp") && strcmp(c->string, "udp")) {
++            if (strcmp(c->string, "tcp") &&
++                strcmp(c->string, "udp") &&
++                strcmp(c->string, "sctp")) {
+                 lexer_error(ctx->lexer,
+-                    "Load balancer protocol '%s' is not 'tcp' or 'udp'",
+-                    c->string);
++                    "Load balancer protocol '%s' is not 'tcp', 'udp', "
++                    "or 'sctp'", c->string);
+                 return;
+             }
+             break;
+diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
+index 75c19df..bb68b8f 100644
+--- a/northd/ovn-northd.c
++++ b/northd/ovn-northd.c
+@@ -3173,10 +3173,21 @@ ovn_lb_create(struct northd_context *ctx, struct hmap *lbs,
+         lb->vips[n_vips].backend_ips = xstrdup(node->value);
+ 
+         struct nbrec_load_balancer_health_check *lb_health_check = NULL;
+-        for (size_t i = 0; i < nbrec_lb->n_health_check; i++) {
+-            if (!strcmp(nbrec_lb->health_check[i]->vip, node->key)) {
+-                lb_health_check = nbrec_lb->health_check[i];
+-                break;
++        if (nbrec_lb->protocol && !strcmp(nbrec_lb->protocol, "sctp")) {
++            if (nbrec_lb->n_health_check > 0) {
++                static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
++                VLOG_WARN_RL(&rl,
++                             "SCTP load balancers do not currently support "
++                             "health checks. Not creating health checks for "
++                             "load balancer " UUID_FMT,
++                             UUID_ARGS(&nbrec_lb->header_.uuid));
++            }
++        } else {
++            for (size_t i = 0; i < nbrec_lb->n_health_check; i++) {
++                if (!strcmp(nbrec_lb->health_check[i]->vip, node->key)) {
++                    lb_health_check = nbrec_lb->health_check[i];
++                    break;
++                }
+             }
+         }
+ 
+@@ -5558,10 +5569,13 @@ build_lb_rules(struct ovn_datapath *od, struct hmap *lflows, struct ovn_lb *lb)
+ 
+         const char *proto = NULL;
+         if (lb_vip->vip_port) {
+-            if (lb->nlb->protocol && !strcmp(lb->nlb->protocol, "udp")) {
+-                proto = "udp";
+-            } else {
+-                proto = "tcp";
++            proto = "tcp";
++            if (lb->nlb->protocol) {
++                if (!strcmp(lb->nlb->protocol, "udp")) {
++                    proto = "udp";
++                } else if (!strcmp(lb->nlb->protocol, "sctp")) {
++                    proto = "sctp";
++                }
+             }
+         }
+ 
+@@ -7569,7 +7583,7 @@ static void
+ add_router_lb_flow(struct hmap *lflows, struct ovn_datapath *od,
+                    struct ds *match, struct ds *actions, int priority,
+                    const char *lb_force_snat_ip, struct lb_vip *lb_vip,
+-                   bool is_udp, struct nbrec_load_balancer *lb,
++                   const char *proto, struct nbrec_load_balancer *lb,
+                    struct shash *meter_groups, struct sset *nat_entries)
+ {
+     build_empty_lb_event_flow(od, lflows, lb_vip, lb, S_ROUTER_IN_DNAT,
+@@ -7624,11 +7638,10 @@ add_router_lb_flow(struct hmap *lflows, struct ovn_datapath *od,
+          * S_ROUTER_IN_DNAT stage. */
+         struct ds unsnat_match = DS_EMPTY_INITIALIZER;
+         ds_put_format(&unsnat_match, "%s && %s.dst == %s && %s",
+-                      ip_match, ip_match, lb_vip->vip,
+-                      is_udp ? "udp" : "tcp");
++                      ip_match, ip_match, lb_vip->vip, proto);
+         if (lb_vip->vip_port) {
+-            ds_put_format(&unsnat_match, " && %s.dst == %d",
+-                          is_udp ? "udp" : "tcp", lb_vip->vip_port);
++            ds_put_format(&unsnat_match, " && %s.dst == %d", proto,
++                          lb_vip->vip_port);
+         }
+ 
+         ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_UNSNAT, 120,
+@@ -7654,7 +7667,7 @@ add_router_lb_flow(struct hmap *lflows, struct ovn_datapath *od,
+ 
+         if (backend->port) {
+             ds_put_format(&undnat_match, " && %s.src == %d) || ",
+-                          is_udp ? "udp" : "tcp", backend->port);
++                          proto, backend->port);
+         } else {
+             ds_put_cstr(&undnat_match, ") || ");
+         }
+@@ -9203,15 +9216,13 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
+ 
+                 int prio = 110;
+                 bool is_udp = nullable_string_is_equal(nb_lb->protocol, "udp");
++                bool is_sctp = nullable_string_is_equal(nb_lb->protocol,
++                                                        "sctp");
++                const char *proto = is_udp ? "udp" : is_sctp ? "sctp" : "tcp";
+ 
+                 if (lb_vip->vip_port) {
+-                    if (is_udp) {
+-                        ds_put_format(&match, " && udp && udp.dst == %d",
+-                                      lb_vip->vip_port);
+-                    } else {
+-                        ds_put_format(&match, " && tcp && tcp.dst == %d",
+-                                      lb_vip->vip_port);
+-                    }
++                    ds_put_format(&match, " && %s && %s.dst == %d", proto,
++                                  proto, lb_vip->vip_port);
+                     prio = 120;
+                 }
+ 
+@@ -9220,7 +9231,7 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
+                                   od->l3redirect_port->json_key);
+                 }
+                 add_router_lb_flow(lflows, od, &match, &actions, prio,
+-                                   lb_force_snat_ip, lb_vip, is_udp,
++                                   lb_force_snat_ip, lb_vip, proto,
+                                    nb_lb, meter_groups, &nat_entries);
+             }
+         }
+diff --git a/ovn-nb.ovsschema b/ovn-nb.ovsschema
+index 843e979..ea6f4e3 100644
+--- a/ovn-nb.ovsschema
++++ b/ovn-nb.ovsschema
+@@ -1,7 +1,7 @@
+ {
+     "name": "OVN_Northbound",
+-    "version": "5.20.0",
+-    "cksum": "2846067333 25243",
++    "version": "5.20.1",
++    "cksum": "721375950 25251",
+     "tables": {
+         "NB_Global": {
+             "columns": {
+@@ -168,7 +168,7 @@
+                              "min": 0, "max": "unlimited"}},
+                 "protocol": {
+                     "type": {"key": {"type": "string",
+-                             "enum": ["set", ["tcp", "udp"]]},
++                             "enum": ["set", ["tcp", "udp", "sctp"]]},
+                              "min": 0, "max": 1}},
+                 "health_check": {"type": {
+                     "key": {"type": "uuid",
+diff --git a/ovn-nb.xml b/ovn-nb.xml
+index 4a422bb..f7ba9c3 100644
+--- a/ovn-nb.xml
++++ b/ovn-nb.xml
+@@ -1458,11 +1458,11 @@
+ 
+     <column name="protocol">
+       <p>
+-        Valid protocols are <code>tcp</code> or <code>udp</code>.  This column
+-        is useful when a port number is provided as part of the
+-        <code>vips</code> column.  If this column is empty and a port number
+-        is provided as part of <code>vips</code> column, OVN assumes the
+-        protocol to be <code>tcp</code>.
++        Valid protocols are <code>tcp</code>, <code>udp</code>, or
++        <code>sctp</code>.  This column is useful when a port number is
++        provided as part of the <code>vips</code> column.  If this column is
++        empty and a port number is provided as part of <code>vips</code>
++        column, OVN assumes the protocol to be <code>tcp</code>.
+       </p>
+     </column>
+ 
+diff --git a/tests/ovn.at b/tests/ovn.at
+index 1402fae..9f3d9d3 100644
+--- a/tests/ovn.at
++++ b/tests/ovn.at
+@@ -1423,8 +1423,8 @@ trigger_event(event = "empty_lb_backends", meter="event-elb" vip = "10.0.0.1:80"
+     encodes as controller(userdata=00.00.00.0f.00.00.00.00.00.00.00.00.00.01.00.0b.31.30.2e.30.2e.30.2e.31.3a.38.30.00.02.00.03.74.63.70.00.03.00.24.31.32.33.34.35.36.37.38.2d.61.62.63.64.2d.39.38.37.36.2d.66.65.64.63.2d.31.31.31.31.39.66.38.65.37.64.36.63,meter_id=5)
+ 
+ # Testing invalid vip results in extra error messages from socket-util.c
+-trigger_event(event = "empty_lb_backends", vip = "10.0.0.1:80", protocol = "sctp", load_balancer = "12345678-abcd-9876-fedc-11119f8e7d6c");
+-    Load balancer protocol 'sctp' is not 'tcp' or 'udp'
++trigger_event(event = "empty_lb_backends", vip = "10.0.0.1:80", protocol = "aarp", load_balancer = "12345678-abcd-9876-fedc-11119f8e7d6c");
++    Load balancer protocol 'aarp' is not 'tcp', 'udp', or 'sctp'
+ trigger_event(event = "empty_lb_backends", vip = "10.0.0.1:80", protocol = "tcp", load_balancer = "bacon");
+     Load balancer 'bacon' is not a UUID
+ 
+@@ -17894,6 +17894,123 @@ AT_CHECK([cat lflows.txt], [0], [dnl
+ OVN_CLEANUP([hv1], [hv2])
+ AT_CLEANUP
+ 
++AT_SETUP([ovn -- SCTP Load balancer health checks])
++AT_KEYWORDS([lb sctp])
++
++# Currently this test just ensures that no service monitors get created when
++# An SCTP load balancer is configured to use health checks. Once SCTP load
++# balancers are modified to allow health checks, this test should be altered
++# to ensure the health check succeeds.
++
++ovn_start
++
++# Set up same network as previous health check test. As long as health checks
++# aren't allowed for SCTP load balancers, the network will not be used for
++# much. However, having the network in place will make it easy to alter when
++# health checks are allowed.
++
++net_add n1
++
++sim_add hv1
++as hv1
++ovs-vsctl add-br br-phys
++ovn_attach n1 br-phys 192.168.0.1
++ovs-vsctl -- add-port br-int hv1-vif1 -- \
++    set interface hv1-vif1 external-ids:iface-id=sw0-p1 \
++    options:tx_pcap=hv1/vif1-tx.pcap \
++    options:rxq_pcap=hv1/vif1-rx.pcap \
++    ofport-request=1
++ovs-vsctl -- add-port br-int hv1-vif2 -- \
++    set interface hv1-vif2 external-ids:iface-id=sw0-p2 \
++    options:tx_pcap=hv1/vif2-tx.pcap \
++    options:rxq_pcap=hv1/vif2-rx.pcap \
++    ofport-request=2
++
++sim_add hv2
++as hv2
++ovs-vsctl add-br br-phys
++ovn_attach n1 br-phys 192.168.0.2
++ovs-vsctl -- add-port br-int hv2-vif1 -- \
++    set interface hv2-vif1 external-ids:iface-id=sw1-p1 \
++    options:tx_pcap=hv2/vif1-tx.pcap \
++    options:rxq_pcap=hv2/vif1-rx.pcap \
++    ofport-request=1
++
++ovn-nbctl ls-add sw0
++
++ovn-nbctl lsp-add sw0 sw0-p1
++ovn-nbctl lsp-set-addresses sw0-p1 "50:54:00:00:00:03 10.0.0.3"
++ovn-nbctl lsp-set-port-security sw0-p1 "50:54:00:00:00:03 10.0.0.3"
++
++ovn-nbctl lsp-add sw0 sw0-p2
++ovn-nbctl lsp-set-addresses sw0-p2 "50:54:00:00:00:04 10.0.0.4"
++ovn-nbctl lsp-set-port-security sw0-p2 "50:54:00:00:00:04 10.0.0.4"
++
++# Create the second logical switch with one port
++ovn-nbctl ls-add sw1
++ovn-nbctl lsp-add sw1 sw1-p1
++ovn-nbctl lsp-set-addresses sw1-p1 "40:54:00:00:00:03 20.0.0.3"
++ovn-nbctl lsp-set-port-security sw1-p1 "40:54:00:00:00:03 20.0.0.3"
++
++# Create a logical router and attach both logical switches
++ovn-nbctl lr-add lr0
++ovn-nbctl lrp-add lr0 lr0-sw0 00:00:00:00:ff:01 10.0.0.1/24
++ovn-nbctl lsp-add sw0 sw0-lr0
++ovn-nbctl lsp-set-type sw0-lr0 router
++ovn-nbctl lsp-set-addresses sw0-lr0 router
++ovn-nbctl lsp-set-options sw0-lr0 router-port=lr0-sw0
++
++ovn-nbctl lrp-add lr0 lr0-sw1 00:00:00:00:ff:02 20.0.0.1/24
++ovn-nbctl lsp-add sw1 sw1-lr0
++ovn-nbctl lsp-set-type sw1-lr0 router
++ovn-nbctl lsp-set-addresses sw1-lr0 router
++ovn-nbctl lsp-set-options sw1-lr0 router-port=lr0-sw1
++
++ovn-nbctl lb-add lb1 10.0.0.10:80 10.0.0.3:80,20.0.0.3:80 sctp
++
++ovn-nbctl --wait=sb set load_balancer . ip_port_mappings:10.0.0.3=sw0-p1:10.0.0.2
++ovn-nbctl --wait=sb set load_balancer . ip_port_mappings:20.0.0.3=sw1-p1:10.0.0.2
++
++ovn-nbctl --wait=sb -- --id=@hc create \
++Load_Balancer_Health_Check vip="10.0.0.10\:80" -- add Load_Balancer . \
++health_check @hc
++
++ovn-nbctl --wait=sb ls-lb-add sw0 lb1
++ovn-nbctl --wait=sb ls-lb-add sw1 lb1
++ovn-nbctl --wait=sb lr-lb-add lr0 lb1
++
++ovn-nbctl ls-add public
++ovn-nbctl lrp-add lr0 lr0-public 00:00:20:20:12:13 172.168.0.100/24
++ovn-nbctl lsp-add public public-lr0
++ovn-nbctl lsp-set-type public-lr0 router
++ovn-nbctl lsp-set-addresses public-lr0 router
++ovn-nbctl lsp-set-options public-lr0 router-port=lr0-public
++
++# localnet port
++ovn-nbctl lsp-add public ln-public
++ovn-nbctl lsp-set-type ln-public localnet
++ovn-nbctl lsp-set-addresses ln-public unknown
++ovn-nbctl lsp-set-options ln-public network_name=public
++
++# schedule the gw router port to a chassis. Change the name of the chassis
++ovn-nbctl --wait=hv lrp-set-gateway-chassis lr0-public hv1 20
++
++OVN_POPULATE_ARP
++ovn-nbctl --wait=hv sync
++
++# And now for the anticlimax. We need to ensure that there is no
++# service monitor in the southbound db.
++
++AT_CHECK([test 0 = `ovn-sbctl --bare --columns _uuid find \
++service_monitor | sed '/^$/d' | wc -l`])
++
++# Let's also be sure the warning message about SCTP load balancers is
++# is in the ovn-northd log
++
++AT_CHECK([test 1 = `grep -c "SCTP load balancers do not currently support health checks" northd/ovn-northd.log`])
++
++AT_CLEANUP
++
+ AT_SETUP([ovn -- ARP/ND request broadcast limiting])
+ ovn_start
+ 
+diff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c
+index e80058e..59abe00 100644
+--- a/utilities/ovn-nbctl.c
++++ b/utilities/ovn-nbctl.c
+@@ -2734,9 +2734,11 @@ nbctl_lb_add(struct ctl_context *ctx)
+         /* Validate protocol. */
+         lb_proto = ctx->argv[4];
+         is_update_proto = true;
+-        if (strcmp(lb_proto, "tcp") && strcmp(lb_proto, "udp")) {
+-            ctl_error(ctx, "%s: protocol must be one of \"tcp\", \"udp\".",
+-                      lb_proto);
++        if (strcmp(lb_proto, "tcp") &&
++            strcmp(lb_proto, "udp") &&
++            strcmp(lb_proto, "sctp")) {
++            ctl_error(ctx, "%s: protocol must be one of \"tcp\", \"udp\", "
++                      " or \"sctp\".", lb_proto);
+             return;
+         }
+     }
+-- 
+1.8.3.1
+
diff --git a/SOURCES/0001-Add-external_ids-column-for-tables-in-nb-schema.patch b/SOURCES/0001-Add-external_ids-column-for-tables-in-nb-schema.patch
new file mode 100644
index 0000000..928a1f1
--- /dev/null
+++ b/SOURCES/0001-Add-external_ids-column-for-tables-in-nb-schema.patch
@@ -0,0 +1,93 @@
+From aff9c19d5fb9bb2cfba220d32ec68111d1adb1c5 Mon Sep 17 00:00:00 2001
+From: Tao YunXiang <taoyunxiang@cmss.chinamobile.com>
+Date: Wed, 11 Mar 2020 11:37:53 +0800
+Subject: [PATCH] Add external_ids column for tables in nb schema
+
+"Logical_Router_Policy"  and "Forwarding_Group" tables doesn't have
+"external_ids" column. I think it is better to add it, so CMS could
+fill it with useful information.
+
+Author: Tao YunXiang <taoyunxiang@cmss.chinamobile.com>
+Co-authored-by: Liu Chang <liuchang@cmss.chinamobile.com>
+Co-authored-by: Rong Yin <rongyin@cmss.chinamobile.com>
+Signed-off-by: Tao YunXiang <taoyunxiang@cmss.chinamobile.com>
+Signed-off-by: Liu Chang <liuchang@cmss.chinamobile.com>
+Signed-off-by: Rong Yin <rongyin@cmss.chinamobile.com>
+Acked-by: Numan Siddique <numans@ovn.org>
+Signed-off-by: Numan Siddique <numans@ovn.org>
+(cherry picked from upstream commit 45de84bff0224e61847ff52d480c6500153ce699)
+
+Change-Id: I85671ce34238dd8989756b395d85785c25c8842c
+---
+ ovn-nb.ovsschema | 10 ++++++++--
+ ovn-nb.xml       | 12 ++++++++++++
+ 2 files changed, 20 insertions(+), 2 deletions(-)
+
+diff --git a/ovn-nb.ovsschema b/ovn-nb.ovsschema
+index bbd6c25..843e979 100644
+--- a/ovn-nb.ovsschema
++++ b/ovn-nb.ovsschema
+@@ -1,7 +1,7 @@
+ {
+     "name": "OVN_Northbound",
+     "version": "5.20.0",
+-    "cksum": "987891875 24923",
++    "cksum": "2846067333 25243",
+     "tables": {
+         "NB_Global": {
+             "columns": {
+@@ -125,6 +125,9 @@
+                 "vip": {"type": "string"},
+                 "vmac": {"type": "string"},
+                 "liveness": {"type": "boolean"},
++                "external_ids": {
++                    "type": {"key": "string", "value": "string",
++                             "min": 0, "max": "unlimited"}},
+                 "child_port": {"type": {"key": "string",
+                                         "min": 1, "max": "unlimited"}}},
+             "isRoot": false},
+@@ -366,7 +369,10 @@
+                 "action": {"type": {
+                     "key": {"type": "string",
+                             "enum": ["set", ["allow", "drop", "reroute"]]}}},
+-                "nexthop": {"type": {"key": "string", "min": 0, "max": 1}}},
++                "nexthop": {"type": {"key": "string", "min": 0, "max": 1}},
++                "external_ids": {
++                    "type": {"key": "string", "value": "string",
++                             "min": 0, "max": "unlimited"}}},
+             "isRoot": false},
+         "NAT": {
+             "columns": {
+diff --git a/ovn-nb.xml b/ovn-nb.xml
+index f30cc9e..4a422bb 100644
+--- a/ovn-nb.xml
++++ b/ovn-nb.xml
+@@ -1313,6 +1313,12 @@
+     <column name="child_port">
+       List of child ports in the forwarding group.
+     </column>
++
++    <group title="Common Columns">
++      <column name="external_ids">
++        See <em>External IDs</em> at the beginning of this document.
++      </column>
++    </group>
+   </table>
+ 
+   <table name="Address_Set" title="Address Sets">
+@@ -2498,6 +2504,12 @@
+         address of a connected router port or the IP address of a logical port.
+       </p>
+     </column>
++
++    <group title="Common Columns">
++      <column name="external_ids">
++        See <em>External IDs</em> at the beginning of this document.
++      </column>
++    </group>
+   </table>
+ 
+   <table name="NAT" title="NAT rules">
+-- 
+1.8.3.1
+
diff --git a/SOURCES/0001-DNS-Make-DNS-lookups-case-insensitive.patch b/SOURCES/0001-DNS-Make-DNS-lookups-case-insensitive.patch
new file mode 100644
index 0000000..f4c91ae
--- /dev/null
+++ b/SOURCES/0001-DNS-Make-DNS-lookups-case-insensitive.patch
@@ -0,0 +1,269 @@
+From a60b2826bd4eb0144d2dc9b25b63b3a6ca5106c7 Mon Sep 17 00:00:00 2001
+From: Mark Michelson <mmichels@redhat.com>
+Date: Mon, 20 Apr 2020 09:25:09 -0400
+Subject: [PATCH 1/2] DNS: Make DNS lookups case insensitive.
+
+From RFC 1035 Section 2.3.3:
+
+"For all parts of the DNS that are part of the official protocol, all
+comparisons between character strings (e.g., labels, domain names, etc.)
+are done in a case-insensitive manner."
+
+OVN was using case-sensitive lookups and therefore was not complying.
+This change makes lookups case insensitive by storing lowercase record
+names in the southbound database and converting incoming query names to
+lowercase.
+
+Signed-off-by: Mark Michelson <mmichels@redhat.com>
+Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=1819069
+Reported-by: Jianlin Shi <jishi@redhat.com>
+Acked-by: Numan Siddique <numans@ovn.org>
+---
+ controller/pinctrl.c |  7 ++++-
+ lib/ovn-util.c       | 15 +++++++++++
+ lib/ovn-util.h       |  5 ++++
+ northd/ovn-northd.c  | 15 ++++++++++-
+ ovn-sb.xml           |  3 ++-
+ tests/ovn.at         | 61 ++++++++++++++++++++++++++++++++------------
+ 6 files changed, 87 insertions(+), 19 deletions(-)
+
+diff --git a/controller/pinctrl.c b/controller/pinctrl.c
+index 8703641c2..8592d4e3f 100644
+--- a/controller/pinctrl.c
++++ b/controller/pinctrl.c
+@@ -2368,7 +2368,12 @@ pinctrl_handle_dns_lookup(
+         struct dns_data *d = iter->data;
+         for (size_t i = 0; i < d->n_dps; i++) {
+             if (d->dps[i] == dp_key) {
+-                answer_ips = smap_get(&d->records, ds_cstr(&query_name));
++                /* DNS records in SBDB are stored in lowercase. Convert to
++                 * lowercase to perform case insensitive lookup
++                 */
++                char *query_name_lower = str_tolower(ds_cstr(&query_name));
++                answer_ips = smap_get(&d->records, query_name_lower);
++                free(query_name_lower);
+                 if (answer_ips) {
+                     break;
+                 }
+diff --git a/lib/ovn-util.c b/lib/ovn-util.c
+index 514e2489f..1b30c2e9a 100644
+--- a/lib/ovn-util.c
++++ b/lib/ovn-util.c
+@@ -21,6 +21,7 @@
+ #include "openvswitch/ofp-parse.h"
+ #include "ovn-nb-idl.h"
+ #include "ovn-sb-idl.h"
++#include <ctype.h>
+ 
+ VLOG_DEFINE_THIS_MODULE(ovn_util);
+ 
+@@ -550,3 +551,17 @@ ip46_equals(const struct v46_ip *addr1, const struct v46_ip *addr2)
+             (addr1->family == AF_INET ? addr1->ipv4 == addr2->ipv4 :
+              IN6_ARE_ADDR_EQUAL(&addr1->ipv6, &addr2->ipv6)));
+ }
++
++char *
++str_tolower(const char *orig)
++{
++    char *copy = xmalloc(strlen(orig) + 1);
++    char *p = copy;
++
++    while (*orig) {
++        *p++ = tolower(*orig++);
++    }
++    *p = '\0';
++
++    return copy;
++}
+diff --git a/lib/ovn-util.h b/lib/ovn-util.h
+index 11238f61c..4076e8b9a 100644
+--- a/lib/ovn-util.h
++++ b/lib/ovn-util.h
+@@ -124,4 +124,9 @@ struct v46_ip {
+ bool ip46_parse_cidr(const char *str, struct v46_ip *prefix,
+                      unsigned int *plen);
+ bool ip46_equals(const struct v46_ip *addr1, const struct v46_ip *addr2);
++
++/* Returns a lowercase copy of orig.
++ * Caller must free the returned string.
++ */
++char *str_tolower(const char *orig);
+ #endif
+diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
+index f7d3988d7..515722c5d 100644
+--- a/northd/ovn-northd.c
++++ b/northd/ovn-northd.c
+@@ -10698,7 +10698,20 @@ sync_dns_entries(struct northd_context *ctx, struct hmap *datapaths)
+             dns_info->sb_dns,
+             (struct sbrec_datapath_binding **)dns_info->sbs,
+             dns_info->n_sbs);
+-        sbrec_dns_set_records(dns_info->sb_dns, &dns_info->nb_dns->records);
++
++        /* DNS lookups are case-insensitive. Convert records to lowercase so
++         * we can do consistent lookups when DNS requests arrive
++         */
++        struct smap lower_records = SMAP_INITIALIZER(&lower_records);
++        struct smap_node *node;
++        SMAP_FOR_EACH (node, &dns_info->nb_dns->records) {
++            smap_add_nocopy(&lower_records, xstrdup(node->key),
++                            str_tolower(node->value));
++        }
++
++        sbrec_dns_set_records(dns_info->sb_dns, &lower_records);
++
++        smap_destroy(&lower_records);
+         free(dns_info->sbs);
+         free(dns_info);
+     }
+diff --git a/ovn-sb.xml b/ovn-sb.xml
+index 72466b97e..5f8da534c 100644
+--- a/ovn-sb.xml
++++ b/ovn-sb.xml
+@@ -3597,7 +3597,8 @@ tcp.flags = RST;
+     <column name="records">
+       Key-value pair of DNS records with <code>DNS query name</code> as the key
+       and a string of IP address(es) separated by comma or space as the
+-      value.
++      value. ovn-northd stores the DNS query name in all lowercase in order to
++      facilitate case-insensitive lookups.
+ 
+       <p><b>Example: </b> "vm1.ovn.org" = "10.0.0.4 aef0::4"</p>
+     </column>
+diff --git a/tests/ovn.at b/tests/ovn.at
+index 0f02e8144..b78637044 100644
+--- a/tests/ovn.at
++++ b/tests/ovn.at
+@@ -8328,6 +8328,12 @@ set_dns_params() {
+         # IPv4 address - 10.0.0.4
+         expected_dns_answer=${query_name}00010001${ttl}00040a000004
+         ;;
++    VM1)
++        # VM1.OVN.ORG
++        query_name=03564d31034f564e034f524700
++        # IPv4 address - 10.0.0.4
++        expected_dns_answer=${query_name}00010001${ttl}00040a000004
++        ;;
+     vm2)
+         # vm2.ovn.org
+         query_name=03766d32036f766e036f726700
+@@ -8490,6 +8496,29 @@ reset_pcap_file hv1-vif2 hv1/vif2
+ rm -f 1.expected
+ rm -f 2.expected
+ 
++# Try vm1 again but an all-caps query name
++
++set_dns_params VM1
++src_ip=`ip_to_hex 10 0 0 6`
++dst_ip=`ip_to_hex 10 0 0 1`
++dns_reply=1
++test_dns 2 f00000000002 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data $dns_resp_data
++
++# NXT_RESUMEs should be 3.
++OVS_WAIT_UNTIL([test 3 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
++
++$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > 2.packets
++cat 2.expected | cut -c -48 > expout
++AT_CHECK([cat 2.packets | cut -c -48], [0], [expout])
++# Skipping the IPv4 checksum.
++cat 2.expected | cut -c 53- > expout
++AT_CHECK([cat 2.packets | cut -c 53-], [0], [expout])
++
++reset_pcap_file hv1-vif1 hv1/vif1
++reset_pcap_file hv1-vif2 hv1/vif2
++rm -f 1.expected
++rm -f 2.expected
++
+ # Clear the query name options for ls1-lp2
+ ovn-nbctl --wait=hv remove DNS $DNS1 records vm2.ovn.org
+ 
+@@ -8499,8 +8528,8 @@ dst_ip=`ip_to_hex 10 0 0 1`
+ dns_reply=0
+ test_dns 1 f00000000001 f00000000002 $src_ip $dst_ip $dns_reply $dns_req_data
+ 
+-# NXT_RESUMEs should be 3.
+-OVS_WAIT_UNTIL([test 3 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
++# NXT_RESUMEs should be 4.
++OVS_WAIT_UNTIL([test 4 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
+ 
+ $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif1-tx.pcap > 1.packets
+ AT_CHECK([cat 1.packets], [0], [])
+@@ -8521,8 +8550,8 @@ dst_ip=`ip_to_hex 10 0 0 1`
+ dns_reply=0
+ test_dns 2 f00000000002 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data
+ 
+-# NXT_RESUMEs should be 3 only.
+-OVS_WAIT_UNTIL([test 3 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
++# NXT_RESUMEs should be 4 only.
++OVS_WAIT_UNTIL([test 4 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
+ 
+ $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > 2.packets
+ AT_CHECK([cat 2.packets], [0], [])
+@@ -8542,8 +8571,8 @@ dst_ip=`ip_to_hex 10 0 0 1`
+ dns_reply=1
+ test_dns 2 f00000000002 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data $dns_resp_data
+ 
+-# NXT_RESUMEs should be 4.
+-OVS_WAIT_UNTIL([test 4 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
++# NXT_RESUMEs should be 5.
++OVS_WAIT_UNTIL([test 5 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
+ 
+ $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > 2.packets
+ cat 2.expected | cut -c -48 > expout
+@@ -8564,8 +8593,8 @@ dst_ip=`ip_to_hex 10 0 0 1`
+ dns_reply=1
+ test_dns 2 f00000000002 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data $dns_resp_data
+ 
+-# NXT_RESUMEs should be 5.
+-OVS_WAIT_UNTIL([test 5 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
++# NXT_RESUMEs should be 6.
++OVS_WAIT_UNTIL([test 6 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
+ 
+ $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > 2.packets
+ cat 2.expected | cut -c -48 > expout
+@@ -8586,8 +8615,8 @@ dst_ip=`ip_to_hex 10 0 0 1`
+ dns_reply=0
+ test_dns 2 f00000000002 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data
+ 
+-# NXT_RESUMEs should be 6.
+-OVS_WAIT_UNTIL([test 6 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
++# NXT_RESUMEs should be 7.
++OVS_WAIT_UNTIL([test 7 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
+ 
+ $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > 2.packets
+ AT_CHECK([cat 2.packets], [0], [])
+@@ -8604,8 +8633,8 @@ dst_ip=`ip_to_hex 10 0 0 1`
+ dns_reply=0
+ test_dns 2 f00000000002 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data
+ 
+-# NXT_RESUMEs should be 7.
+-OVS_WAIT_UNTIL([test 7 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
++# NXT_RESUMEs should be 8.
++OVS_WAIT_UNTIL([test 8 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
+ 
+ $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > 2.packets
+ AT_CHECK([cat 2.packets], [0], [])
+@@ -8624,8 +8653,8 @@ dst_ip=`ip_to_hex 10 0 0 1`
+ dns_reply=1
+ test_dns 1 f00000000001 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data $dns_resp_data
+ 
+-# NXT_RESUMEs should be 8.
+-OVS_WAIT_UNTIL([test 8 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
++# NXT_RESUMEs should be 9.
++OVS_WAIT_UNTIL([test 9 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
+ 
+ $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif1-tx.pcap > 1.packets
+ cat 1.expected | cut -c -48 > expout
+@@ -8646,8 +8675,8 @@ dst_ip=aef00000000000000000000000000001
+ dns_reply=1
+ test_dns6 1 f00000000001 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data $dns_resp_data
+ 
+-# NXT_RESUMEs should be 9.
+-OVS_WAIT_UNTIL([test 9 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
++# NXT_RESUMEs should be 10
++OVS_WAIT_UNTIL([test 10 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
+ 
+ $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif1-tx.pcap > 1.packets
+ # Skipping the UDP checksum.
+-- 
+2.25.1
+
diff --git a/SOURCES/0001-Disable-IPv6-prefix-reporting-if-IPv6-PD-is-disabled.patch b/SOURCES/0001-Disable-IPv6-prefix-reporting-if-IPv6-PD-is-disabled.patch
new file mode 100644
index 0000000..5168b84
--- /dev/null
+++ b/SOURCES/0001-Disable-IPv6-prefix-reporting-if-IPv6-PD-is-disabled.patch
@@ -0,0 +1,88 @@
+From 0b9d16670d5561d8300d2448cbd4686a3acdc57e Mon Sep 17 00:00:00 2001
+Message-Id: <0b9d16670d5561d8300d2448cbd4686a3acdc57e.1588608928.git.lorenzo.bianconi@redhat.com>
+From: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
+Date: Wed, 22 Apr 2020 16:13:03 +0200
+Subject: [PATCH 1/3] Disable IPv6 prefix reporting if IPv6 PD is disabled
+
+Disable IPv6 prefix delegation reporting in Logical_Router_Port table if
+IPv6 prefix delegation state machine has been disabled for the related
+logical router port
+
+Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
+Signed-off-by: Numan Siddique <numans@ovn.org>
+---
+ northd/ovn-northd.c | 28 ++++++++++++++++------------
+ tests/system-ovn.at |  7 +++++++
+ 2 files changed, 23 insertions(+), 12 deletions(-)
+
+diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
+index bc1ea0bd3..431c511c3 100644
+--- a/northd/ovn-northd.c
++++ b/northd/ovn-northd.c
+@@ -2703,6 +2703,10 @@ ovn_update_ipv6_prefix(struct hmap *ports)
+             continue;
+         }
+ 
++        if (!smap_get_bool(&op->nbrp->options, "prefix", false)) {
++            continue;
++        }
++
+         char prefix[IPV6_SCAN_LEN + 6];
+         unsigned aid;
+         const char *ipv6_pd_list = smap_get(&op->sb->options,
+@@ -9364,22 +9368,22 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
+         }
+ 
+         struct smap options;
++        smap_clone(&options, &op->sb->options);
++
+         /* enable IPv6 prefix delegation */
+         bool prefix_delegation = smap_get_bool(&op->nbrp->options,
+                                                "prefix_delegation", false);
+-        if (prefix_delegation) {
+-            smap_clone(&options, &op->sb->options);
+-            smap_add(&options, "ipv6_prefix_delegation", "true");
+-            sbrec_port_binding_set_options(op->sb, &options);
+-            smap_destroy(&options);
+-        }
++        smap_add(&options, "ipv6_prefix_delegation",
++                 prefix_delegation ? "true" : "false");
++        sbrec_port_binding_set_options(op->sb, &options);
+ 
+-        if (smap_get_bool(&op->nbrp->options, "prefix", false)) {
+-            smap_clone(&options, &op->sb->options);
+-            smap_add(&options, "ipv6_prefix", "true");
+-            sbrec_port_binding_set_options(op->sb, &options);
+-            smap_destroy(&options);
+-        }
++        bool ipv6_prefix = smap_get_bool(&op->nbrp->options,
++                                         "prefix", false);
++        smap_add(&options, "ipv6_prefix",
++                 ipv6_prefix ? "true" : "false");
++        sbrec_port_binding_set_options(op->sb, &options);
++
++        smap_destroy(&options);
+ 
+         const char *address_mode = smap_get(
+             &op->nbrp->ipv6_ra_configs, "address_mode");
+diff --git a/tests/system-ovn.at b/tests/system-ovn.at
+index 3b11cf92b..fa3b83cb1 100644
+--- a/tests/system-ovn.at
++++ b/tests/system-ovn.at
+@@ -3946,6 +3946,13 @@ OVS_WAIT_UNTIL([
+     test "${total_pkts}" = "1"
+ ])
+ 
++ovn-nbctl set logical_router_port rp-sw0 options:prefix=false
++ovn-nbctl clear logical_router_port rp-sw0 ipv6_prefix
++OVS_WAIT_WHILE([test "$(ovn-nbctl get logical_router_port rp-sw0 ipv6_prefix | cut -c3-16)" = "[2001:1db8:3333]"])
++AT_CHECK([ovn-nbctl get logical_router_port rp-sw0 ipv6_prefix | cut -c3-16], [0], [dnl
++[]
++])
++
+ kill $(pidof tcpdump)
+ kill $(pidof ovn-controller)
+ 
+-- 
+2.26.2
+
diff --git a/SOURCES/0001-Fix-ACL-reject-action-for-UDP-packets.patch b/SOURCES/0001-Fix-ACL-reject-action-for-UDP-packets.patch
new file mode 100644
index 0000000..c32d975
--- /dev/null
+++ b/SOURCES/0001-Fix-ACL-reject-action-for-UDP-packets.patch
@@ -0,0 +1,525 @@
+From cfb0f49b644f2a253cc1365c219d1bb78c2cacac Mon Sep 17 00:00:00 2001
+From: Numan Siddique <numans@ovn.org>
+Date: Fri, 24 Apr 2020 12:19:09 +0530
+Subject: [PATCH] Fix ACL reject action for UDP packets.
+
+The icmp packet generated by ovn-controller for reject ACL action
+for non TCP packets is not getting delivered to the sender of
+the original packet. This is because the icmp packets are skipped
+from out_pre_lb/out_pre_acl logical switch egress pipeline and this
+results in these icmp packets getting dropped in the ACL stage because
+of invalid ct flags. This patch fixes this issue by removing those logical
+flows. The IP checksum generated by ovn-controller is invalid. This patch
+fixes this issue as well.
+
+Tested-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
+Signed-off-by: Numan Siddique <numans@ovn.org>
+
+(cherry-picked from upstream commit f792b1a00b439a949e3b7aae4951f8513340c1a1)
+
+Change-Id: I9837991cf0981f57dc92d1309f0f453c800d7937
+---
+ controller/pinctrl.c | 102 ++++++++++++++++++++++++++++---------------
+ northd/ovn-northd.c  |  22 +++++-----
+ tests/ovn.at         |  46 +++++++++----------
+ tests/system-ovn.at  |  95 ++++++++++++++++++++++++++++++++--------
+ 4 files changed, 177 insertions(+), 88 deletions(-)
+
+diff --git a/controller/pinctrl.c b/controller/pinctrl.c
+index f0d63b9a6..9d5b7c3c0 100644
+--- a/controller/pinctrl.c
++++ b/controller/pinctrl.c
+@@ -1465,7 +1465,7 @@ static void
+ pinctrl_handle_icmp(struct rconn *swconn, const struct flow *ip_flow,
+                     struct dp_packet *pkt_in,
+                     const struct match *md, struct ofpbuf *userdata,
+-                    bool include_orig_ip_datagram)
++                    bool set_icmp_code)
+ {
+     /* This action only works for IP packets, and the switch should only send
+      * us IP packets this way, but check here just to be sure. */
+@@ -1512,46 +1512,51 @@ pinctrl_handle_icmp(struct rconn *swconn, const struct flow *ip_flow,
+         packet_set_ipv4(&packet, ip_flow->nw_src, ip_flow->nw_dst,
+                         ip_flow->nw_tos, 255);
+ 
++        uint8_t icmp_code =  1;
++        if (set_icmp_code && in_ip->ip_proto == IPPROTO_UDP) {
++            icmp_code = 3;
++        }
++
+         struct icmp_header *ih = dp_packet_put_zeros(&packet, sizeof *ih);
+         dp_packet_set_l4(&packet, ih);
+-        packet_set_icmp(&packet, ICMP4_DST_UNREACH, 1);
+-
+-        if (include_orig_ip_datagram) {
+-            /* RFC 1122: 3.2.2	MUST send at least the IP header and 8 bytes
+-             * of header. MAY send more.
+-             * RFC says return as much as we can without exceeding 576
+-             * bytes.
+-             * So, lets return as much as we can. */
+-
+-            /* Calculate available room to include the original IP + data. */
+-            nh = dp_packet_l3(&packet);
+-            uint16_t room = 576 - (sizeof *eh + ntohs(nh->ip_tot_len));
+-            if (in_ip_len > room) {
+-                in_ip_len = room;
+-            }
+-            dp_packet_put(&packet, in_ip, in_ip_len);
+-
+-            /* dp_packet_put may reallocate the buffer. Get the l3 and l4
+-             * header pointers again. */
+-            nh = dp_packet_l3(&packet);
+-            ih = dp_packet_l4(&packet);
+-            uint16_t ip_total_len = ntohs(nh->ip_tot_len) + in_ip_len;
+-            nh->ip_tot_len = htons(ip_total_len);
+-            ih->icmp_csum = 0;
+-            ih->icmp_csum = csum(ih, sizeof *ih + in_ip_len);
+-            nh->ip_csum = 0;
+-            nh->ip_csum = csum(nh, sizeof *nh);
+-        }
++        packet_set_icmp(&packet, ICMP4_DST_UNREACH, icmp_code);
++
++        /* RFC 1122: 3.2.2	MUST send at least the IP header and 8 bytes
++         * of header. MAY send more.
++         * RFC says return as much as we can without exceeding 576
++         * bytes.
++         * So, lets return as much as we can. */
++
++        /* Calculate available room to include the original IP + data. */
++        nh = dp_packet_l3(&packet);
++        uint16_t room = 576 - (sizeof *eh + ntohs(nh->ip_tot_len));
++        if (in_ip_len > room) {
++            in_ip_len = room;
++        }
++        dp_packet_put(&packet, in_ip, in_ip_len);
++
++        /* dp_packet_put may reallocate the buffer. Get the l3 and l4
++            * header pointers again. */
++        nh = dp_packet_l3(&packet);
++        ih = dp_packet_l4(&packet);
++        uint16_t ip_total_len = ntohs(nh->ip_tot_len) + in_ip_len;
++        nh->ip_tot_len = htons(ip_total_len);
++        ih->icmp_csum = 0;
++        ih->icmp_csum = csum(ih, sizeof *ih + in_ip_len);
++        nh->ip_csum = 0;
++        nh->ip_csum = csum(nh, sizeof *nh);
++
+     } else {
+         struct ip6_hdr *nh = dp_packet_put_zeros(&packet, sizeof *nh);
+         struct icmp6_data_header *ih;
+         uint32_t icmpv6_csum;
++        struct ip6_hdr *in_ip = dp_packet_l3(pkt_in);
+ 
+         eh->eth_type = htons(ETH_TYPE_IPV6);
+         dp_packet_set_l3(&packet, nh);
+         nh->ip6_vfc = 0x60;
+         nh->ip6_nxt = IPPROTO_ICMPV6;
+-        nh->ip6_plen = htons(sizeof(*nh) + ICMP6_DATA_HEADER_LEN);
++        nh->ip6_plen = htons(ICMP6_DATA_HEADER_LEN);
+         packet_set_ipv6(&packet, &ip_flow->ipv6_src, &ip_flow->ipv6_dst,
+                         ip_flow->nw_tos, ip_flow->ipv6_label, 255);
+ 
+@@ -1559,15 +1564,42 @@ pinctrl_handle_icmp(struct rconn *swconn, const struct flow *ip_flow,
+         dp_packet_set_l4(&packet, ih);
+         ih->icmp6_base.icmp6_type = ICMP6_DST_UNREACH;
+         ih->icmp6_base.icmp6_code = 1;
++
++        if (set_icmp_code && in_ip->ip6_nxt == IPPROTO_UDP) {
++            ih->icmp6_base.icmp6_code = ICMP6_DST_UNREACH_NOPORT;
++        }
+         ih->icmp6_base.icmp6_cksum = 0;
+ 
+-        uint8_t *data = dp_packet_put_zeros(&packet, sizeof *nh);
+-        memcpy(data, dp_packet_l3(pkt_in), sizeof(*nh));
++        nh = dp_packet_l3(&packet);
++
++        /* RFC 4443: 3.1.
++         *
++         * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++         * |     Type      |     Code      |          Checksum             |
++         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++         * |                             Unused                            |
++         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++         * |                    As much of invoking packet                 |
++         * +                as possible without the ICMPv6 packet          +
++         * |                exceeding the minimum IPv6 MTU [IPv6]          |
++         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++         */
++
++        uint16_t room = 1280 - (sizeof *eh + sizeof *nh +
++                                ICMP6_DATA_HEADER_LEN);
++        uint16_t in_ip_len = (uint16_t) sizeof *in_ip + ntohs(in_ip->ip6_plen);
++        if (in_ip_len > room) {
++            in_ip_len = room;
++        }
++
++        dp_packet_put(&packet, in_ip, in_ip_len);
++        nh->ip6_plen = htons(ICMP6_DATA_HEADER_LEN + in_ip_len);
+ 
+         icmpv6_csum = packet_csum_pseudoheader6(dp_packet_l3(&packet));
+         ih->icmp6_base.icmp6_cksum = csum_finish(
+             csum_continue(icmpv6_csum, ih,
+-                          sizeof(*nh) + ICMP6_DATA_HEADER_LEN));
++                          in_ip_len + ICMP6_DATA_HEADER_LEN));
+     }
+ 
+     if (ip_flow->vlans[0].tci & htons(VLAN_CFI)) {
+@@ -2658,12 +2690,12 @@ process_packet_in(struct rconn *swconn, const struct ofp_header *msg)
+ 
+     case ACTION_OPCODE_ICMP:
+         pinctrl_handle_icmp(swconn, &headers, &packet, &pin.flow_metadata,
+-                            &userdata, false);
++                            &userdata, true);
+         break;
+ 
+     case ACTION_OPCODE_ICMP4_ERROR:
+         pinctrl_handle_icmp(swconn, &headers, &packet, &pin.flow_metadata,
+-                            &userdata, true);
++                            &userdata, false);
+         break;
+ 
+     case ACTION_OPCODE_TCP_RESET:
+diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
+index 4efe4a0c3..ec77ae1a8 100644
+--- a/northd/ovn-northd.c
++++ b/northd/ovn-northd.c
+@@ -4736,12 +4736,10 @@ build_pre_acls(struct ovn_datapath *od, struct hmap *lflows)
+          * Not to do conntrack on ND and ICMP destination
+          * unreachable packets. */
+         ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 110,
+-                      "nd || nd_rs || nd_ra || icmp4.type == 3 || "
+-                      "icmp6.type == 1 || "
++                      "nd || nd_rs || nd_ra || "
+                       "(udp && udp.src == 546 && udp.dst == 547)", "next;");
+         ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 110,
+-                      "nd || nd_rs || nd_ra || icmp4.type == 3 || "
+-                      "icmp6.type == 1 || "
++                      "nd || nd_rs || nd_ra || "
+                       "(udp && udp.src == 546 && udp.dst == 547)", "next;");
+ 
+         /* Ingress and Egress Pre-ACL Table (Priority 100).
+@@ -4853,12 +4851,10 @@ build_pre_lb(struct ovn_datapath *od, struct hmap *lflows,
+ {
+     /* Do not send ND packets to conntrack */
+     ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, 110,
+-                  "nd || nd_rs || nd_ra || icmp4.type == 3 ||"
+-                  "icmp6.type == 1",
++                  "nd || nd_rs || nd_ra",
+                   "next;");
+     ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, 110,
+-                  "nd || nd_rs || nd_ra || icmp4.type == 3 ||"
+-                  "icmp6.type == 1",
++                  "nd || nd_rs || nd_ra",
+                   "next;");
+ 
+     /* Do not send service monitor packets to conntrack. */
+@@ -5037,9 +5033,10 @@ build_reject_acl_rules(struct ovn_datapath *od, struct hmap *lflows,
+         ds_put_format(&actions, "%s ", extra_actions->string);
+     }
+     ds_put_format(&actions, "reg0 = 0; "
+-                  "eth.dst <-> eth.src; ip4.dst <-> ip4.src; "
+-                  "icmp4 { outport <-> inport; %s };",
+-                  ingress ? "output;" : "next(pipeline=ingress,table=0);");
++                  "icmp4 { eth.dst <-> eth.src; ip4.dst <-> ip4.src; "
++                  "outport <-> inport; %s };",
++                  ingress ? "next(pipeline=egress,table=5);"
++                          : "next(pipeline=ingress,table=19);");
+     ovn_lflow_add_with_hint(lflows, od, stage,
+                             acl->priority + OVN_ACL_PRI_OFFSET,
+                             ds_cstr(&match), ds_cstr(&actions), stage_hint);
+@@ -5056,7 +5053,8 @@ build_reject_acl_rules(struct ovn_datapath *od, struct hmap *lflows,
+     ds_put_format(&actions, "reg0 = 0; icmp6 { "
+                   "eth.dst <-> eth.src; ip6.dst <-> ip6.src; "
+                   "outport <-> inport; %s };",
+-                  ingress ? "output;" : "next(pipeline=ingress,table=0);");
++                  ingress ? "next(pipeline=egress,table=5);"
++                          : "next(pipeline=ingress,table=19);");
+     ovn_lflow_add_with_hint(lflows, od, stage,
+                             acl->priority + OVN_ACL_PRI_OFFSET,
+                             ds_cstr(&match), ds_cstr(&actions), stage_hint);
+diff --git a/tests/ovn.at b/tests/ovn.at
+index defe00a40..35415f2b6 100644
+--- a/tests/ovn.at
++++ b/tests/ovn.at
+@@ -11737,13 +11737,13 @@ test_ip_packet() {
+ 
+     local ip_ttl=ff
+     local packet=${eth_dst}${eth_src}08004500001400004000${ip_ttl}01${ip_chksum}${ipv4_src}${ipv4_dst}
+-
++    local orig_pkt_in_reply=4500001400004000${ip_ttl}01${ip_chksum}${ipv4_src}${ipv4_dst}
+     local reply_icmp_ttl=ff
+     local icmp_type_code_response=0301
+     local icmp_data=00000000
+     local reply_icmp_payload=${icmp_type_code_response}${exp_icmp_chksum}${icmp_data}
+-    local reply=${eth_src}${eth_dst}08004500001c00004000${reply_icmp_ttl}01${exp_ip_chksum}${ipv4_dst}${ipv4_src}${reply_icmp_payload}
+-    echo $reply >> vif$inport.expected
++    local reply=${eth_src}${eth_dst}08004500003000004000${reply_icmp_ttl}01${exp_ip_chksum}${ipv4_dst}${ipv4_src}${reply_icmp_payload}
++    echo $reply$orig_pkt_in_reply >> vif$inport.expected
+ 
+     as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet
+ }
+@@ -11760,7 +11760,7 @@ test_ipv6_packet() {
+     local ip6_hdr=6000000000083aff${ipv6_src}${ipv6_dst}
+     local packet=${eth_dst}${eth_src}86dd${ip6_hdr}0000000000000000
+ 
+-    local reply=${eth_src}${eth_dst}86dd6000000000303aff${ipv6_dst}${ipv6_src}0101${exp_icmp_chksum}00000000${ip6_hdr}
++    local reply=${eth_src}${eth_dst}86dd6000000000383aff${ipv6_dst}${ipv6_src}0101${exp_icmp_chksum}00000000${ip6_hdr}0000000000000000
+     echo $reply >> vif$inport.expected
+ 
+     as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet
+@@ -11838,11 +11838,11 @@ ovn-nbctl --log acl-add sw0 from-lport 1000 "inport == \"sw0-p21\"" reject
+ # Allow some time for ovn-northd and ovn-controller to catch up.
+ ovn-nbctl --timeout=3 --wait=hv sync
+ 
+-test_ip_packet 11 1 000000000011 000000000021 $(ip_to_hex 192 168 1 11) $(ip_to_hex 192 168 1 21) 0000 7d8d fcfe
+-test_ip_packet 21 2 000000000021 000000000011 $(ip_to_hex 192 168 1 21) $(ip_to_hex 192 168 1 11) 0000 7d8d fcfe
+-test_ip_packet 31 3 000000000031 000000000012 $(ip_to_hex 192 168 1 31) $(ip_to_hex 192 168 1 12) 0000 7d82 fcfe
++test_ip_packet 11 1 000000000011 000000000021 $(ip_to_hex 192 168 1 11) $(ip_to_hex 192 168 1 21) 0000 f85b f576
++test_ip_packet 21 2 000000000021 000000000011 $(ip_to_hex 192 168 1 21) $(ip_to_hex 192 168 1 11) 0000 f85b f576
++test_ip_packet 31 3 000000000031 000000000012 $(ip_to_hex 192 168 1 31) $(ip_to_hex 192 168 1 12) 0000 f850 f56b
+ 
+-test_ipv6_packet 11 1 000000000011 000000000021 fe80000000000000020001fffe000001 fe80000000000000020001fffe000002 6183
++test_ipv6_packet 11 1 000000000011 000000000021 fe80000000000000020001fffe000001 fe80000000000000020001fffe000002 617b
+ 
+ test_tcp_syn_packet 11 1 000000000011 000000000021 $(ip_to_hex 192 168 1 11) $(ip_to_hex 192 168 1 21) 0000 8b40 3039 0000 b85f 70e4
+ test_tcp_syn_packet 21 2 000000000021 000000000011 $(ip_to_hex 192 168 1 21) $(ip_to_hex 192 168 1 11) 0000 8b40 3039 0000 b85f 70e4
+@@ -12795,13 +12795,13 @@ test_ip_packet() {
+ 
+     local ip_ttl=01
+     local packet=${eth_dst}${eth_src}08004500001400004000${ip_ttl}01${ip_chksum}${ipv4_src}${ipv4_dst}
+-
++    local orig_pkt_in_reply=4500001400004000${ip_ttl}01${ip_chksum}${ipv4_src}${ipv4_dst}
+     local reply_icmp_ttl=fe
+     local icmp_type_code_response=0b00
+     local icmp_data=00000000
+     local reply_icmp_payload=${icmp_type_code_response}${exp_icmp_chksum}${icmp_data}
+-    local reply=${eth_src}${eth_dst}08004500001c00004000${reply_icmp_ttl}01${exp_ip_chksum}${ip_router}${ipv4_src}${reply_icmp_payload}
+-    echo $reply >> vif$inport.expected
++    local reply=${eth_src}${eth_dst}08004500003000004000${reply_icmp_ttl}01${exp_ip_chksum}${ip_router}${ipv4_src}${reply_icmp_payload}
++    echo $reply$orig_pkt_in_reply >> vif$inport.expected
+ 
+     as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet
+ }
+@@ -12819,7 +12819,7 @@ test_ip6_packet() {
+     local ip6_hdr=6000000000151101${ipv6_src}${ipv6_dst}
+     local packet=${eth_dst}${eth_src}86dd${ip6_hdr}dbb8303900155bac6b646f65206676676e6d66720a
+ 
+-    local reply=${eth_src}${eth_dst}86dd6000000000303afe${ipv6_router}${ipv6_src}0300${exp_icmp_chksum}00000000${ip6_hdr}
++    local reply=${eth_src}${eth_dst}86dd6000000000453afe${ipv6_router}${ipv6_src}0300${exp_icmp_chksum}00000000${ip6_hdr}dbb8303900155bac6b646f65206676676e6d66720a
+     echo $reply >> vif$inport.expected
+ 
+     as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet
+@@ -12861,8 +12861,8 @@ OVN_POPULATE_ARP
+ # allow some time for ovn-northd and ovn-controller to catch up.
+ ovn-nbctl --wait=hv sync
+ 
+-test_ip_packet 1 1 000000000001 00000000ff01 $(ip_to_hex 192 168 1 1) $(ip_to_hex 192 168 2 1) $(ip_to_hex 192 168 1 254) 0000 7dae f4ff
+-test_ip6_packet 1 1 000000000001 00000000ff01 20010db8000100000000000000000011 20010db8000200000000000000000011 20010db8000100000000000000000001 d461
++test_ip_packet 1 1 000000000001 00000000ff01 $(ip_to_hex 192 168 1 1) $(ip_to_hex 192 168 2 1) $(ip_to_hex 192 168 1 254) 0000 f87c ea96
++test_ip6_packet 1 1 000000000001 00000000ff01 20010db8000100000000000000000011 20010db8000200000000000000000011 20010db8000100000000000000000001 1c22
+ OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [vif1.expected])
+ 
+ OVN_CLEANUP([hv1], [hv2])
+@@ -12891,12 +12891,12 @@ test_ip_packet() {
+ 
+     local ip_ttl=ff
+     local packet=${eth_dst}${eth_src}08004500001400004000${ip_ttl}${l4_proto}${ip_chksum}${ipv4_src}${ip_router}
+-
++    local orig_pkt_in_reply=4500001400004000${ip_ttl}${l4_proto}${ip_chksum}${ipv4_src}${ip_router}
+     local reply_icmp_ttl=fe
+     local icmp_data=00000000
+     local reply_icmp_payload=${exp_icmp_code}${exp_icmp_chksum}${icmp_data}
+-    local reply=${eth_src}${eth_dst}08004500001c00004000${reply_icmp_ttl}01${exp_ip_chksum}${ip_router}${ipv4_src}${reply_icmp_payload}
+-    echo $reply >> vif$inport.expected
++    local reply=${eth_src}${eth_dst}08004500003000004000${reply_icmp_ttl}01${exp_ip_chksum}${ip_router}${ipv4_src}${reply_icmp_payload}
++    echo $reply$orig_pkt_in_reply >> vif$inport.expected
+ 
+     as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet
+ }
+@@ -12962,7 +12962,9 @@ test_ip6_packet() {
+     local ip6_hdr=60000000${ipv6_len}${ipv6_proto}ff${ipv6_src}${ipv6_dst}
+     local packet=${eth_dst}${eth_src}86dd${ip6_hdr}${data}
+ 
+-    local reply=${eth_src}${eth_dst}86dd6000000000303afe${ipv6_dst}${ipv6_src}${exp_icmp_code}${exp_icmp_chksum}00000000${ip6_hdr}
++    local reply_ip_len=`expr 48 + ${#data} / 2`
++    reply_ip_len=$(printf "%x" $reply_ip_len)
++    local reply=${eth_src}${eth_dst}86dd6000000000${reply_ip_len}3afe${ipv6_dst}${ipv6_src}${exp_icmp_code}${exp_icmp_chksum}00000000${ip6_hdr}${data}
+     echo $reply >> vif$inport.expected
+ 
+     as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet
+@@ -13004,13 +13006,13 @@ OVN_POPULATE_ARP
+ # allow some time for ovn-northd and ovn-controller to catch up.
+ ovn-nbctl --wait=hv sync
+ 
+-test_ip_packet 1 1 000000000001 00000000ff01 $(ip_to_hex 192 168 1 1) $(ip_to_hex 192 168 1 254) 11 0000 7dae fcfc 0303
+-test_ip_packet 1 1 000000000001 00000000ff01 $(ip_to_hex 192 168 1 1) $(ip_to_hex 192 168 1 254) 84 0000 7dae fcfd 0302
+-test_ip6_packet 1 1 000000000001 00000000ff01 20010db8000100000000000000000011 20010db8000100000000000000000001 11 0015 dbb8303900155bac6b646f65206676676e6d66720a 0104 d570
++test_ip_packet 1 1 000000000001 00000000ff01 $(ip_to_hex 192 168 1 1) $(ip_to_hex 192 168 1 254) 11 0000 f87c f485 0303
++test_ip_packet 1 1 000000000001 00000000ff01 $(ip_to_hex 192 168 1 1) $(ip_to_hex 192 168 1 254) 84 0000 f87c f413 0302
++test_ip6_packet 1 1 000000000001 00000000ff01 20010db8000100000000000000000011 20010db8000100000000000000000001 11 0015 dbb8303900155bac6b646f65206676676e6d66720a 0104 1d31
+ OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [vif1.expected])
+ 
+ test_tcp_syn_packet 2 2 000000000002 00000000ff02 $(ip_to_hex 192 168 2 1) $(ip_to_hex 192 168 2 254) 0000 8b40 3039 0000 b680 6e05
+-test_ip6_packet 2 2 000000000002 00000000ff02 20010db8000200000000000000000011 20010db8000200000000000000000001 84 0004 01020304 0103 627e
++test_ip6_packet 2 2 000000000002 00000000ff02 20010db8000200000000000000000011 20010db8000200000000000000000001 84 0004 01020304 0103 5e74
+ test_tcp6_packet 2 2 000000000002 00000000ff02 20010db8000200000000000000000011 20010db8000200000000000000000001 8b40 3039 0000 98cd
+ OVN_CHECK_PACKETS([hv2/vif2-tx.pcap], [vif2.expected])
+ 
+diff --git a/tests/system-ovn.at b/tests/system-ovn.at
+index fa3b83cb1..117f1e835 100644
+--- a/tests/system-ovn.at
++++ b/tests/system-ovn.at
+@@ -3697,7 +3697,7 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
+ AT_CLEANUP
+ 
+ 
+-AT_SETUP([ovn -- ACL reject - TCP reset])
++AT_SETUP([ovn -- ACL reject])
+ AT_SKIP_IF([test $HAVE_NC = no])
+ AT_KEYWORDS([lb])
+ 
+@@ -3736,13 +3736,14 @@ ovn-nbctl acl-add pg0_drop from-lport 1001 "inport == @pg0_drop && ip" drop
+ ovn-nbctl acl-add pg0_drop to-lport 1001 "outport == @pg0_drop && ip" drop
+ 
+ ovn-nbctl pg-add pg0 sw0-p1-rej sw0-p2-rej
+-ovn-nbctl acl-add pg0 from-lport 1002 "inport == @pg0 && ip4" allow-related
++ovn-nbctl acl-add pg0 from-lport 1002 "inport == @pg0 && ip" allow-related
+ ovn-nbctl --log acl-add pg0 from-lport 1004 "inport == @pg0 && ip && tcp && tcp.dst == 80" reject
++ovn-nbctl --log acl-add pg0 from-lport 1004 "inport == @pg0 && ip && udp && udp.dst == 90" reject
+ 
+-ovn-nbctl acl-add pg0 to-lport 1002 "outport == @pg0 && ip4 && ip4.src == 0.0.0.0/0 && icmp4" allow-related
+ ovn-nbctl acl-add pg0 to-lport 1002 "outport == @pg0 && ip4 && ip4.src == 0.0.0.0/0 && tcp && tcp.dst == 82" allow-related
+ ovn-nbctl acl-add pg0 to-lport 1002 "outport == @pg0 && ip4 && ip4.src == 0.0.0.0/0 && udp && udp.dst == 82" allow-related
+ ovn-nbctl --log acl-add pg0 to-lport 1004 "inport == @pg0 && ip && tcp && tcp.dst == 84" reject
++ovn-nbctl --log acl-add pg0 to-lport 1004 "inport == @pg0 && ip && udp && udp.dst == 94" reject
+ 
+ OVN_POPULATE_ARP
+ ovn-nbctl --wait=hv sync
+@@ -3758,33 +3759,38 @@ ADD_VETH(sw0-p2-rej, sw0-p2-rej, br-int, "10.0.0.4/24", "50:54:00:00:00:04", \
+ NS_CHECK_EXEC([sw0-p1-rej], [ip a a aef0::3/64 dev sw0-p1-rej], [0])
+ NS_CHECK_EXEC([sw0-p2-rej], [ip a a aef0::4/64 dev sw0-p2-rej], [0])
+ 
+-# Capture packets in sw0-p1-rej.
+-NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -n -c 2 -i sw0-p1-rej tcp port 80 > sw0-p1-rej-ip4.pcap &], [0])
+ sleep 1
+ 
+-NS_CHECK_EXEC([sw0-p1-rej], [nc 10.0.0.4 80], [1], [],
+-[dnl
+-Ncat: Connection refused.
+-])
++# Capture packets in sw0-p1-rej.
++NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -n -c 4 -i sw0-p1-rej tcp > sw0-p1-rej-ip4.pcap &], [0])
++
++sleep 1
+ 
+ OVS_WAIT_UNTIL([
+-    total=`cat sw0-p1-rej-ip4.pcap |  wc -l`
+-    echo "total = $total"
+-    test "${total}" = "2"
++    ip netns exec sw0-p1-rej nc  10.0.0.4 80 2> r
++    res=$(cat r)
++    test "$res" = "Ncat: Connection refused."
+ ])
+ 
+ # Now send traffic to port 84
+-NS_CHECK_EXEC([sw0-p1-rej], [nc 10.0.0.4 84], [1], [],
+-[dnl
+-Ncat: Connection refused.
++OVS_WAIT_UNTIL([
++    ip netns exec sw0-p1-rej nc  10.0.0.4 84 2> r
++    res=$(cat r)
++    test "$res" = "Ncat: Connection refused."
+ ])
+ 
+-AT_CHECK([
++OVS_WAIT_UNTIL([
+     n_pkt=$(ovs-ofctl dump-flows br-int table=44 | grep -v n_packets=0 | \
+ grep controller | grep tp_dst=84 -c)
+     test $n_pkt -eq 1
+ ])
+ 
++OVS_WAIT_UNTIL([
++    total=`cat sw0-p1-rej-ip4.pcap |  wc -l`
++    echo "total = $total"
++    test "${total}" = "4"
++])
++
+ # Without this sleep, test case fails intermittently.
+ sleep 3
+ 
+@@ -3792,17 +3798,68 @@ NS_CHECK_EXEC([sw0-p2-rej], [tcpdump -n -c 2 -i sw0-p2-rej tcp port 80 > sw0-p2-
+ 
+ sleep 1
+ 
+-NS_CHECK_EXEC([sw0-p2-rej], [nc -6 aef0::3 80], [1], [],
+-[dnl
+-Ncat: Connection refused.
++OVS_WAIT_UNTIL([
++    ip netns exec sw0-p2-rej nc -6 aef0::3 80 2> r
++    res=$(cat r)
++    test "$res" = "Ncat: Connection refused."
+ ])
+ 
++
+ OVS_WAIT_UNTIL([
+     total=`cat sw0-p2-rej-ip6.pcap |  wc -l`
+     echo "total = $total"
+     test "${total}" = "2"
+ ])
+ 
++# Now test for IPv4 UDP.
++NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -n -c 1 -i sw0-p1-rej udp port 90 > sw0-p1-rej-udp.pcap &], [0])
++NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -n -c 1 -i sw0-p1-rej icmp > sw0-p1-rej-icmp.pcap &], [0])
++
++echo "foo" > foo
++OVS_WAIT_UNTIL([
++    ip netns exec sw0-p1-rej nc -u 10.0.0.4 90 < foo
++    c=$(cat sw0-p1-rej-icmp.pcap | grep \
++"10.0.0.4 > 10.0.0.3: ICMP 10.0.0.4 udp port dnsix unreachable" | uniq | wc -l)
++    test $c -eq 1
++])
++
++rm -f *.pcap
++
++NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -n -c 1 -i sw0-p1-rej udp port 94 > sw0-p1-rej-udp.pcap &], [0])
++NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -n -c 1 -i sw0-p1-rej icmp > sw0-p1-rej-icmp.pcap &], [0])
++
++OVS_WAIT_UNTIL([
++    ip netns exec sw0-p1-rej nc -u 10.0.0.4 94 < foo
++    c=$(cat sw0-p1-rej-icmp.pcap | grep \
++"10.0.0.4 > 10.0.0.3: ICMP 10.0.0.4 udp port objcall unreachable" | uniq | wc -l)
++    test $c -eq 1
++])
++
++# Now test for IPv6 UDP.
++NS_CHECK_EXEC([sw0-p2-rej], [tcpdump -n -c 1 -i sw0-p2-rej udp port 90 > sw0-p2-rej-ip6-udp.pcap &], [0])
++NS_CHECK_EXEC([sw0-p2-rej], [tcpdump -n -c 1 -i sw0-p2-rej icmp6 > sw0-p2-rej-icmp6.pcap &], [0])
++
++OVS_WAIT_UNTIL([
++    ip netns exec sw0-p2-rej nc -u -6 aef0::3 90 < foo
++    c=$(cat sw0-p2-rej-icmp6.pcap | grep \
++"IP6 aef0::3 > aef0::4: ICMP6, destination unreachable, unreachable port, \
++aef0::3 udp port dnsix" | uniq | wc -l)
++    test $c -eq 1
++])
++
++rm -f *.pcap
++
++NS_CHECK_EXEC([sw0-p2-rej], [tcpdump -n -c 1 -i sw0-p2-rej udp port 94 > sw0-p2-rej-ip6-udp.pcap &], [0])
++NS_CHECK_EXEC([sw0-p2-rej], [tcpdump -n -c 1 -i sw0-p2-rej icmp6 > sw0-p2-rej-icmp6.pcap &], [0])
++
++OVS_WAIT_UNTIL([
++    ip netns exec sw0-p2-rej nc -u -6 aef0::3 94 < foo
++    c=$(cat sw0-p2-rej-icmp6.pcap | grep \
++"IP6 aef0::3 > aef0::4: ICMP6, destination unreachable, unreachable port, \
++aef0::3 udp port objcall" | uniq | wc -l)
++    test $c -eq 1
++])
++
+ OVS_APP_EXIT_AND_WAIT([ovn-controller])
+ 
+ as ovn-sb
+-- 
+2.26.2
+
diff --git a/SOURCES/0001-Fix-conntrack-entry-leaks-because-of-TCP-RST-packets.patch b/SOURCES/0001-Fix-conntrack-entry-leaks-because-of-TCP-RST-packets.patch
new file mode 100644
index 0000000..2ec0cb6
--- /dev/null
+++ b/SOURCES/0001-Fix-conntrack-entry-leaks-because-of-TCP-RST-packets.patch
@@ -0,0 +1,473 @@
+From 685c685b0070731524869459f96b7b690e12ae74 Mon Sep 17 00:00:00 2001
+From: Numan Siddique <numans@ovn.org>
+Date: Thu, 23 Apr 2020 18:08:48 +0530
+Subject: [PATCH] Fix conntrack entry leaks because of TCP RST packets not sent
+ to conntrack.
+
+The commit [1] - 28097d5adb95("Fix tcp_reset action handling") fixed an issue
+with tcp_reset OVN action. In order to fix that issue, this commit added
+logical flows to skip all the TCP RST packets from conntrack.
+Ideally it should have skipped only the TCP RST packets generated by
+ovn-controller from conntrack. Since all the TCP RST packets are
+skipped from conntrack, the connections in conntrack remain in
+ESTABLISHED state even if the client/server sends TCP RST to close the
+connection.  And these entries live for a long time and this is
+causing performance issues as reported in the BZ.
+
+This patch reverts the logical flows added in [1] and modifies the inner
+actions of tcp_reset in the ingress logical switch pipeline
+from - "tcp_reset { outport <-> inport; output; }"
+to "tcp_reset { output <-> inport; next(pipeline=egress,table=5); }".
+This causes the packet to resubmit to the egress table ls_out_qos_mark
+skipping the egress ACL stage. Prior to this packet, next action was
+not allowing a resubmit from ingress to egress pipeline. This patch
+relaxes this limitation.
+
+For the tcp_reset action in the egress logical switch pipeline, this patch
+modifies the inner action
+from - "tcp_reset { outport <-> inport; next(pipeline=ingress,table=0); }"
+to - "tcp_reset { outport <-> inport; next(pipeline=ingress,table=19); }".
+This causes the packet to enter the ingress table ls_in_l2_lkup.
+
+We don't see similar conntrack leaks with UDP. Although there is an issue
+with the acl reject action for UDP packets. When ovn-controller generates icmp
+destination unreachable packet, it doesn't get delivered. And the IP checksum is
+incorrect in this packet. A follow up patch will fix these issues.
+
+[1] - 28097d5adb95("Fix tcp_reset action handling")
+
+Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=1819785
+Co-Authored-by: Tim Rozet <trozet@redhat.com>
+Signed-off-by: Tim Rozet <trozet@redhat.com>
+Acked-by: Dumitru Ceara <dceara@redhat.com>
+Acked-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
+Signed-off-by: Numan Siddique <numans@ovn.org>
+---
+ AUTHORS.rst             |   1 +
+ lib/actions.c           |   6 +-
+ northd/ovn-northd.8.xml |   8 ++
+ northd/ovn-northd.c     |  14 ++--
+ ovn-sb.xml              |  10 ++-
+ tests/automake.mk       |   3 +-
+ tests/ovn.at            |   6 +-
+ tests/system-ovn.at     | 170 +++++++++++++++++++++++++++++++++++-----
+ tests/test-tcp-rst.py   |  37 +++++++++
+ 9 files changed, 217 insertions(+), 38 deletions(-)
+ create mode 100644 tests/test-tcp-rst.py
+
+diff --git a/AUTHORS.rst b/AUTHORS.rst
+index 230e487f0..c80fc1bae 100644
+--- a/AUTHORS.rst
++++ b/AUTHORS.rst
+@@ -355,6 +355,7 @@ Thomas F. Herbert                  thomasfherbert@gmail.com
+ Thomas Goirand                     zigo@debian.org
+ Thomas Graf                        tgraf@noironetworks.com
+ Thomas Lacroix                     thomas.lacroix@citrix.com
++Tim Rozet                          trozet@redhat.com
+ Timo Puha                          timox.puha@intel.com
+ Timothy Redaelli                   tredaelli@redhat.com
+ Todd Deshane                       deshantm@gmail.com
+diff --git a/lib/actions.c b/lib/actions.c
+index 02141af30..41a742064 100644
+--- a/lib/actions.c
++++ b/lib/actions.c
+@@ -319,11 +319,7 @@ parse_NEXT(struct action_context *ctx)
+         }
+     }
+ 
+-    if (pipeline == OVNACT_P_EGRESS && ctx->pp->pipeline == OVNACT_P_INGRESS) {
+-        lexer_error(ctx->lexer,
+-                    "\"next\" action cannot advance from ingress to egress "
+-                    "pipeline (use \"output\" action instead)");
+-    } else if (table >= ctx->pp->n_tables) {
++    if (table >= ctx->pp->n_tables) {
+         lexer_error(ctx->lexer,
+                     "\"next\" action cannot advance beyond table %d.",
+                     ctx->pp->n_tables - 1);
+diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
+index efcc4b7fc..d39e259f6 100644
+--- a/northd/ovn-northd.8.xml
++++ b/northd/ovn-northd.8.xml
+@@ -373,6 +373,14 @@
+         for new connections and <code>reg0[1] = 1; next;</code> for existing
+         connections.
+       </li>
++      <li>
++        <code>reject</code> ACLs translate into logical
++        flows with the
++        <code>tcp_reset { output &lt;-&gt; inport;
++        next(pipeline=egress,table=5);}</code>
++        action for TCP connections and <code>icmp4/icmp6</code> action
++        for UDP connections.
++      </li>
+       <li>
+         Other ACLs translate to <code>drop;</code> for new or untracked
+         connections and <code>ct_commit(ct_label=1/1);</code> for known
+diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
+index d3d481ab8..0082e2e8b 100644
+--- a/northd/ovn-northd.c
++++ b/northd/ovn-northd.c
+@@ -4717,11 +4717,11 @@ build_pre_acls(struct ovn_datapath *od, struct hmap *lflows)
+          * unreachable packets. */
+         ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 110,
+                       "nd || nd_rs || nd_ra || icmp4.type == 3 || "
+-                      "icmp6.type == 1 || (tcp && tcp.flags == 20) || "
++                      "icmp6.type == 1 || "
+                       "(udp && udp.src == 546 && udp.dst == 547)", "next;");
+         ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 110,
+                       "nd || nd_rs || nd_ra || icmp4.type == 3 || "
+-                      "icmp6.type == 1 || (tcp && tcp.flags == 20) ||"
++                      "icmp6.type == 1 || "
+                       "(udp && udp.src == 546 && udp.dst == 547)", "next;");
+ 
+         /* Ingress and Egress Pre-ACL Table (Priority 100).
+@@ -4834,11 +4834,11 @@ build_pre_lb(struct ovn_datapath *od, struct hmap *lflows,
+     /* Do not send ND packets to conntrack */
+     ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, 110,
+                   "nd || nd_rs || nd_ra || icmp4.type == 3 ||"
+-                  "icmp6.type == 1 || (tcp && tcp.flags == 20)",
++                  "icmp6.type == 1",
+                   "next;");
+     ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, 110,
+                   "nd || nd_rs || nd_ra || icmp4.type == 3 ||"
+-                  "icmp6.type == 1 || (tcp && tcp.flags == 20)",
++                  "icmp6.type == 1",
+                   "next;");
+ 
+     /* Do not send service monitor packets to conntrack. */
+@@ -4984,7 +4984,8 @@ build_reject_acl_rules(struct ovn_datapath *od, struct hmap *lflows,
+     ds_put_format(&actions, "reg0 = 0; "
+                   "eth.dst <-> eth.src; ip4.dst <-> ip4.src; "
+                   "tcp_reset { outport <-> inport; %s };",
+-                  ingress ? "output;" : "next(pipeline=ingress,table=0);");
++                  ingress ? "next(pipeline=egress,table=5);"
++                          : "next(pipeline=ingress,table=19);");
+     ovn_lflow_add_with_hint(lflows, od, stage,
+                             acl->priority + OVN_ACL_PRI_OFFSET + 10,
+                             ds_cstr(&match), ds_cstr(&actions), stage_hint);
+@@ -4998,7 +4999,8 @@ build_reject_acl_rules(struct ovn_datapath *od, struct hmap *lflows,
+     ds_put_format(&actions, "reg0 = 0; "
+                   "eth.dst <-> eth.src; ip6.dst <-> ip6.src; "
+                   "tcp_reset { outport <-> inport; %s };",
+-                  ingress ? "output;" : "next(pipeline=ingress,table=0);");
++                  ingress ? "next(pipeline=egress,table=5);"
++                          : "next(pipeline=ingress,table=19);");
+     ovn_lflow_add_with_hint(lflows, od, stage,
+                             acl->priority + OVN_ACL_PRI_OFFSET + 10,
+                             ds_cstr(&match), ds_cstr(&actions), stage_hint);
+diff --git a/ovn-sb.xml b/ovn-sb.xml
+index 5f8da534c..3aa7cd4da 100644
+--- a/ovn-sb.xml
++++ b/ovn-sb.xml
+@@ -1112,10 +1112,12 @@
+           <var>pipeline</var> as a subroutine.  The default <var>table</var> is
+           just after the current one.  If <var>pipeline</var> is specified, it
+           may be <code>ingress</code> or <code>egress</code>; the default
+-          <var>pipeline</var> is the one currently executing.  Actions in the
+-          ingress pipeline may not use <code>next</code> to jump into the
+-          egress pipeline (use the <code>output</code> instead), but
+-          transitions in the opposite direction are allowed.
++          <var>pipeline</var> is the one currently executing. Actions in the
++          both ingress and egress pipeline can use <code>next</code> to jump
++          across the other pipeline.  Actions in the ingress pipeline should
++          use <code>next</code> to jump into the specific table of egress
++          pipeline only if it is certain that the packets are local and not
++          tunnelled and wants to skip certain stages in the packet processing.
+         </dd>
+ 
+         <dt><code><var>field</var> = <var>constant</var>;</code></dt>
+diff --git a/tests/automake.mk b/tests/automake.mk
+index 215fb432b..ed530dd77 100644
+--- a/tests/automake.mk
++++ b/tests/automake.mk
+@@ -205,7 +205,8 @@ tests_ovstest_LDADD = $(OVS_LIBDIR)/libopenvswitch.la lib/libovn.la
+ # Python tests.
+ CHECK_PYFILES = \
+ 	tests/test-l7.py \
+-	tests/uuidfilt.py
++	tests/uuidfilt.py \
++	tests/test-tcp-rst.py
+ 
+ EXTRA_DIST += $(CHECK_PYFILES)
+ PYCOV_CLEAN_FILES += $(CHECK_PYFILES:.py=.py,cover) .coverage
+diff --git a/tests/ovn.at b/tests/ovn.at
+index b78637044..6da975554 100644
+--- a/tests/ovn.at
++++ b/tests/ovn.at
+@@ -850,7 +850,11 @@ next(pipeline=ingress, table=11);
+     encodes as resubmit(,19)
+ 
+ next(pipeline=egress);
+-    "next" action cannot advance from ingress to egress pipeline (use "output" action instead)
++    formats as next(pipeline=egress, table=11);
++    encodes as resubmit(,51)
++
++next(pipeline=egress, table=5);
++    encodes as resubmit(,45)
+ 
+ next(table=10);
+     formats as next(10);
+diff --git a/tests/system-ovn.at b/tests/system-ovn.at
+index bdb9768d2..3b11cf92b 100644
+--- a/tests/system-ovn.at
++++ b/tests/system-ovn.at
+@@ -3719,60 +3719,86 @@ start_daemon ovn-controller
+ 
+ ovn-nbctl ls-add sw0
+ 
+-ovn-nbctl lsp-add sw0 sw0-p1
+-ovn-nbctl lsp-set-addresses sw0-p1 "50:54:00:00:00:03 10.0.0.3 aef0::3"
+-ovn-nbctl lsp-set-port-security sw0-p1 "50:54:00:00:00:03 10.0.0.3 aef0::3"
++ovn-nbctl lsp-add sw0 sw0-p1-rej
++ovn-nbctl lsp-set-addresses sw0-p1-rej "50:54:00:00:00:03 10.0.0.3 aef0::3"
++ovn-nbctl lsp-set-port-security sw0-p1-rej "50:54:00:00:00:03 10.0.0.3 aef0::3"
+ 
+-ovn-nbctl lsp-add sw0 sw0-p2
+-ovn-nbctl lsp-set-addresses sw0-p2 "50:54:00:00:00:04 10.0.0.4 aef0::4"
+-ovn-nbctl lsp-set-port-security sw0-p2 "50:54:00:00:00:04 10.0.0.4 aef0::4"
++ovn-nbctl lsp-add sw0 sw0-p2-rej
++ovn-nbctl lsp-set-addresses sw0-p2-rej "50:54:00:00:00:04 10.0.0.4 aef0::4"
++ovn-nbctl lsp-set-port-security sw0-p2-rej "50:54:00:00:00:04 10.0.0.4 aef0::4"
++
++#ovn-nbctl --log acl-add sw0 from-lport 1000 "inport == \"sw0-p1\" && tcp && tcp.dst == 80" reject
++#ovn-nbctl --log acl-add sw0 from-lport 1000 "inport == \"sw0-p2\" && ip6 && tcp && tcp.dst == 80" reject
++
++# Create port group and ACLs for sw0 ports.
++ovn-nbctl pg-add pg0_drop sw0-p1-rej sw0-p2-rej
++ovn-nbctl acl-add pg0_drop from-lport 1001 "inport == @pg0_drop && ip" drop
++ovn-nbctl acl-add pg0_drop to-lport 1001 "outport == @pg0_drop && ip" drop
++
++ovn-nbctl pg-add pg0 sw0-p1-rej sw0-p2-rej
++ovn-nbctl acl-add pg0 from-lport 1002 "inport == @pg0 && ip4" allow-related
++ovn-nbctl --log acl-add pg0 from-lport 1004 "inport == @pg0 && ip && tcp && tcp.dst == 80" reject
+ 
+-ovn-nbctl --log acl-add sw0 from-lport 1000 "inport == \"sw0-p1\" && tcp && tcp.dst == 80" reject
+-ovn-nbctl --log acl-add sw0 from-lport 1000 "inport == \"sw0-p2\" && ip6 && tcp && tcp.dst == 80" reject
++ovn-nbctl acl-add pg0 to-lport 1002 "outport == @pg0 && ip4 && ip4.src == 0.0.0.0/0 && icmp4" allow-related
++ovn-nbctl acl-add pg0 to-lport 1002 "outport == @pg0 && ip4 && ip4.src == 0.0.0.0/0 && tcp && tcp.dst == 82" allow-related
++ovn-nbctl acl-add pg0 to-lport 1002 "outport == @pg0 && ip4 && ip4.src == 0.0.0.0/0 && udp && udp.dst == 82" allow-related
++ovn-nbctl --log acl-add pg0 to-lport 1004 "inport == @pg0 && ip && tcp && tcp.dst == 84" reject
+ 
+ OVN_POPULATE_ARP
+ ovn-nbctl --wait=hv sync
+ 
+-ADD_NAMESPACES(sw0-p1)
+-ADD_VETH(sw0-p1, sw0-p1, br-int, "10.0.0.3/24", "50:54:00:00:00:03", \
++ADD_NAMESPACES(sw0-p1-rej)
++ADD_VETH(sw0-p1-rej, sw0-p1-rej, br-int, "10.0.0.3/24", "50:54:00:00:00:03", \
+          "10.0.0.1")
+ 
+-ADD_NAMESPACES(sw0-p2)
+-ADD_VETH(sw0-p2, sw0-p2, br-int, "10.0.0.4/24", "50:54:00:00:00:04", \
++ADD_NAMESPACES(sw0-p2-rej)
++ADD_VETH(sw0-p2-rej, sw0-p2-rej, br-int, "10.0.0.4/24", "50:54:00:00:00:04", \
+          "10.0.0.1")
+ 
+-NS_CHECK_EXEC([sw0-p1], [ip a a aef0::3/64 dev sw0-p1], [0])
+-NS_CHECK_EXEC([sw0-p2], [ip a a aef0::4/64 dev sw0-p2], [0])
++NS_CHECK_EXEC([sw0-p1-rej], [ip a a aef0::3/64 dev sw0-p1-rej], [0])
++NS_CHECK_EXEC([sw0-p2-rej], [ip a a aef0::4/64 dev sw0-p2-rej], [0])
+ 
+-# Capture packets in sw0-p1.
+-NS_CHECK_EXEC([sw0-p1], [tcpdump -n -c 2 -i sw0-p1 tcp port 80 > sw0-p1-ip4.pcap &], [0])
++# Capture packets in sw0-p1-rej.
++NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -n -c 2 -i sw0-p1-rej tcp port 80 > sw0-p1-rej-ip4.pcap &], [0])
+ sleep 1
+ 
+-NS_CHECK_EXEC([sw0-p1], [nc 10.0.0.4 80], [1], [],
++NS_CHECK_EXEC([sw0-p1-rej], [nc 10.0.0.4 80], [1], [],
+ [dnl
+ Ncat: Connection refused.
+ ])
+ 
+ OVS_WAIT_UNTIL([
+-    total=`cat sw0-p1-ip4.pcap |  wc -l`
++    total=`cat sw0-p1-rej-ip4.pcap |  wc -l`
+     echo "total = $total"
+     test "${total}" = "2"
+ ])
+ 
++# Now send traffic to port 84
++NS_CHECK_EXEC([sw0-p1-rej], [nc 10.0.0.4 84], [1], [],
++[dnl
++Ncat: Connection refused.
++])
++
++AT_CHECK([
++    n_pkt=$(ovs-ofctl dump-flows br-int table=44 | grep -v n_packets=0 | \
++grep controller | grep tp_dst=84 -c)
++    test $n_pkt -eq 1
++])
++
+ # Without this sleep, test case fails intermittently.
+ sleep 3
+ 
+-NS_CHECK_EXEC([sw0-p2], [tcpdump -n -c 2 -i sw0-p2 tcp port 80 > sw0-p2-ip6.pcap &], [0])
++NS_CHECK_EXEC([sw0-p2-rej], [tcpdump -n -c 2 -i sw0-p2-rej tcp port 80 > sw0-p2-rej-ip6.pcap &], [0])
+ 
+ sleep 1
+ 
+-NS_CHECK_EXEC([sw0-p2], [nc -6 aef0::3 80], [1], [],
++NS_CHECK_EXEC([sw0-p2-rej], [nc -6 aef0::3 80], [1], [],
+ [dnl
+ Ncat: Connection refused.
+ ])
+ 
+ OVS_WAIT_UNTIL([
+-    total=`cat sw0-p2-ip6.pcap |  wc -l`
++    total=`cat sw0-p2-rej-ip6.pcap |  wc -l`
+     echo "total = $total"
+     test "${total}" = "2"
+ ])
+@@ -3936,3 +3962,105 @@ as
+ OVS_TRAFFIC_VSWITCHD_STOP(["/.*error receiving.*/d
+ /.*terminating with signal 15.*/d"])
+ AT_CLEANUP
++
++# Tests that when an established connection sends TCP reset,
++# the conntrack entry is not in established state.
++AT_SETUP([ovn -- conntrack TCP reset])
++AT_KEYWORDS([conntrack])
++ovn_start
++
++OVS_TRAFFIC_VSWITCHD_START()
++ADD_BR([br-int])
++
++# Set external-ids in br-int needed for ovn-controller
++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
++
++ovn-nbctl ls-add sw0
++
++ovn-nbctl lsp-add sw0 rst-p1
++ovn-nbctl lsp-set-addresses rst-p1 "50:54:00:00:00:03"
++ovn-nbctl lsp-set-port-security rst-p1 "50:54:00:00:00:03"
++
++ovn-nbctl lsp-add sw0 rst-p2
++ovn-nbctl lsp-set-addresses rst-p2 "50:54:00:00:00:04 10.0.0.4"
++ovn-nbctl lsp-set-port-security rst-p2 "50:54:00:00:00:04 10.0.0.4"
++
++# Create port group and ACLs for sw0 ports.
++ovn-nbctl pg-add pg0_drop rst-p1 rst-p2
++ovn-nbctl acl-add pg0_drop from-lport 1001 "inport == @pg0_drop && ip" drop
++ovn-nbctl acl-add pg0_drop to-lport 1001 "outport == @pg0_drop && ip" drop
++
++ovn-nbctl pg-add pg0 rst-p1 rst-p2
++ovn-nbctl acl-add pg0 from-lport 1002 "inport == @pg0 && ip4" allow-related
++ovn-nbctl acl-add pg0 to-lport 1002 "outport == @pg0 && ip4 && ip4.src == 0.0.0.0/0 && icmp4" allow-related
++ovn-nbctl acl-add pg0 to-lport 1002 "outport == @pg0 && ip4 && ip4.src == 0.0.0.0/0 && tcp && tcp.dst == 80" allow-related
++ovn-nbctl acl-add pg0 to-lport 1002 "outport == @pg0 && ip4 && ip4.src == 0.0.0.0/0 && udp && udp.dst == 80" allow-related
++
++# Create a logical router and attach to logical switch.
++ovn-nbctl lr-add lr0
++ovn-nbctl lrp-add lr0 lr0-sw0 00:00:00:00:ff:01 10.0.0.1/24
++ovn-nbctl lsp-add sw0 sw0-lr0
++ovn-nbctl lsp-set-type sw0-lr0 router
++ovn-nbctl lsp-set-addresses sw0-lr0 router
++ovn-nbctl lsp-set-options sw0-lr0 router-port=lr0-sw0
++
++ovn-nbctl lb-add lb1 10.0.0.10:80 10.0.0.3:80
++ovn-nbctl --wait=sb ls-lb-add sw0 lb1
++ovn-nbctl --wait=sb lr-lb-add lr0 lb1
++
++OVN_POPULATE_ARP
++ovn-nbctl --wait=hv sync
++
++ADD_NAMESPACES(rst-p1)
++ADD_VETH(rst-p1, rst-p1, br-int, "10.0.0.3/24", "50:54:00:00:00:03", \
++         "10.0.0.1")
++
++ADD_NAMESPACES(rst-p2)
++ADD_VETH(rst-p2, rst-p2, br-int, "10.0.0.4/24", "50:54:00:00:00:04", \
++         "10.0.0.1")
++
++OVS_WAIT_UNTIL([test x$(ovn-nbctl lsp-get-up rst-p1) = xup])
++OVS_WAIT_UNTIL([test x$(ovn-nbctl lsp-get-up rst-p2) = xup])
++
++# Start webservers in 'rst-p1'.
++OVS_START_L7([rst-p1], [http])
++
++NS_CHECK_EXEC([rst-p2], [$PYTHON $srcdir/test-tcp-rst.py --dst-port 80 --dst-ip 10.0.0.10])
++
++# When tcp reset is sent, conntrack entry should be in the state - CLOSED or CLOSING.
++# But there is a bug where tcp reset packet was not sent to the conntrack.
++# This test case checks that the tcp reset packet is sent to conntrack
++# and the state is not in established state.
++AT_CHECK([
++    ct_est_count=$(ovs-appctl dpctl/dump-conntrack | grep 10.0.0.10 | grep state=ESTABLISHED -c)
++    test $ct_est_count -eq 0
++
++    ct_est_count=$(ovs-appctl dpctl/dump-conntrack | grep 10.0.0.10 | grep state=CLOS -c)
++    test $ct_est_count -eq 1
++])
++
++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(["/failed to query port patch-.*/d
++/connection dropped.*/d
++/Service monitor not found.*/d"])
++
++AT_CLEANUP
+diff --git a/tests/test-tcp-rst.py b/tests/test-tcp-rst.py
+new file mode 100644
+index 000000000..6f96c5706
+--- /dev/null
++++ b/tests/test-tcp-rst.py
+@@ -0,0 +1,37 @@
++#!/usr/bin/env python3
++# Copyright (c) 2020 Red Hat, Inc.
++#
++# Licensed under the Apache License, Version 2.0 (the "License");
++# you may not use this file except in compliance with the License.
++# You may obtain a copy of the License at:
++#
++#     http://www.apache.org/licenses/LICENSE-2.0
++#
++# Unless required by applicable law or agreed to in writing, software
++# distributed under the License is distributed on an "AS IS" BASIS,
++# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++# See the License for the specific language governing permissions and
++# limitations under the License.
++
++# Simple python script which connects to tcp server and then
++# resets the connection.
++import argparse
++import socket
++import sys
++import struct
++import time
++
++parser = argparse.ArgumentParser(description='')
++parser.add_argument("--src-port", type=int, default=11337, help="source port to use")
++parser.add_argument("--dst-port", type=int, help="dst port to use")
++parser.add_argument("--dst-ip", help="server ip to use")
++args = parser.parse_args()
++sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
++server_address = (args.dst_ip, args.dst_port)
++sock.bind(('0.0.0.0', args.src_port))
++sock.connect(server_address)
++l_onoff = 1
++l_linger = 0
++time.sleep(1)
++sock.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', l_onoff, l_linger))
++sock.close()
+-- 
+2.25.1
+
diff --git a/SOURCES/0001-Fix-ovn-controller-generated-packets-from-getting-dr.patch b/SOURCES/0001-Fix-ovn-controller-generated-packets-from-getting-dr.patch
new file mode 100644
index 0000000..1aadd22
--- /dev/null
+++ b/SOURCES/0001-Fix-ovn-controller-generated-packets-from-getting-dr.patch
@@ -0,0 +1,152 @@
+From 14f9bf6ba4bfa459f2e924dbf273a6337aab4107 Mon Sep 17 00:00:00 2001
+From: Numan Siddique <numans@ovn.org>
+Date: Sun, 14 Jun 2020 18:40:07 +0530
+Subject: [PATCH 1/3] Fix ovn-controller generated packets from getting dropped
+ for reject ACL action.
+
+TCP reset/ICMP packet generated by ovn-controller for the ACL reject action
+gets dropped by ovs-vswithd with the below messages in ovs-vswitchd log
+even though ovn-controller sets the in_port as OFPP_CONTROLLER.
+
+----
+ofproto_dpif_upcall(handler1)|INFO|received packet on unassociated datapath port 4294967295
+ofproto_dpif_upcall(revalidator37)|WARN|Failed to acquire udpif_key corresponding to
+unexpected flow (Invalid argument): ufid:0daac824-bda7-44d8-ad38-cdd9c5f0fc97
+----
+
+ovs-vswitchd drops the packet because the in_port is 0.
+
+The below OF flow sets the in_port to 0 if 'MLF_ALLOW_LOOPBACK_BIT' is set in the REG0
+in table 64.
+
+priority=100,reg10=0x1/0x1,reg15=0x2,metadata=0x2 actions=push:NXM_OF_IN_PORT[],load:0->NXM_OF_IN_PORT[],resubmit(,65),pop:NXM_OF_IN_PORT[]
+
+This patch fixes this issue by setting the in_port to OFPP_NONE so that ovs-vswitchd
+doesn't drop the packet.
+
+Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=1832176
+Acked-by: Mark Michelson <mmichels@redhat.com>
+Signed-off-by: Numan Siddique <numans@ovn.org>
+
+(cherry-picked from upstream master commit cfa5478211318b686ad0981e7b0620f96edd7168)
+
+Change-Id: Ia8e134013c30a6865322083c8054fa45b57c9353
+---
+ controller/physical.c | 18 ++++++++++++------
+ tests/system-ovn.at   | 32 ++++++++++++++++++++++++++++++++
+ 2 files changed, 44 insertions(+), 6 deletions(-)
+
+diff --git a/controller/physical.c b/controller/physical.c
+index 144aeb7bd..3c5bbe027 100644
+--- a/controller/physical.c
++++ b/controller/physical.c
+@@ -765,12 +765,18 @@ put_local_common_flows(uint32_t dp_key, uint32_t port_key,
+      *   - or if the destination is a nested container
+      *   - or if "nested_container" flag is set and the destination is the
+      *     parent port,
+-     * temporarily set the in_port to zero, resubmit to
++     * temporarily set the in_port to OFPP_NONE, resubmit to
+      * table 65 for logical-to-physical translation, then restore
+      * the port number.
+      *
+      * If 'parent_port_key' is set, then the 'port_key' represents a nested
+-     * container. */
++     * container.
++     *
++     * Note:We can set in_port to 0 too. But if recirculation happens
++     * later (eg. clone action to enter peer pipeline and a subsequent
++     * ct action), ovs-vswitchd will drop the packet if the frozen metadata
++     * in_port is 0.
++     * */
+ 
+     bool nested_container = parent_port_key ? true: false;
+     match_init_catchall(&match);
+@@ -783,7 +789,7 @@ put_local_common_flows(uint32_t dp_key, uint32_t port_key,
+     }
+ 
+     put_stack(MFF_IN_PORT, ofpact_put_STACK_PUSH(ofpacts_p));
+-    put_load(0, MFF_IN_PORT, 0, 16, ofpacts_p);
++    put_load(ofp_to_u16(OFPP_NONE), MFF_IN_PORT, 0, 16, ofpacts_p);
+     put_resubmit(OFTABLE_LOG_TO_PHY, ofpacts_p);
+     put_stack(MFF_IN_PORT, ofpact_put_STACK_POP(ofpacts_p));
+     ofctrl_add_flow(flow_table, OFTABLE_SAVE_INPORT, 100, 0,
+@@ -792,8 +798,8 @@ put_local_common_flows(uint32_t dp_key, uint32_t port_key,
+     if (nested_container) {
+         /* It's a nested container and when the packet from the nested
+          * container is to be sent to the parent port, "nested_container"
+-         * flag will be set. We need to temporarily set the in_port to zero
+-         * as mentioned in the comment above.
++         * flag will be set. We need to temporarily set the in_port to
++         * OFPP_NONE as mentioned in the comment above.
+          *
+          * If a parent port has multiple child ports, then this if condition
+          * will be hit multiple times, but we want to add only one flow.
+@@ -814,7 +820,7 @@ put_local_common_flows(uint32_t dp_key, uint32_t port_key,
+                              MLF_NESTED_CONTAINER, MLF_NESTED_CONTAINER);
+ 
+         put_stack(MFF_IN_PORT, ofpact_put_STACK_PUSH(ofpacts_p));
+-        put_load(0, MFF_IN_PORT, 0, 16, ofpacts_p);
++        put_load(ofp_to_u16(OFPP_NONE), MFF_IN_PORT, 0, 16, ofpacts_p);
+         put_resubmit(OFTABLE_LOG_TO_PHY, ofpacts_p);
+         put_stack(MFF_IN_PORT, ofpact_put_STACK_POP(ofpacts_p));
+         ofctrl_check_and_add_flow(flow_table, OFTABLE_SAVE_INPORT, 100, 0,
+diff --git a/tests/system-ovn.at b/tests/system-ovn.at
+index 9dfe6a4ad..52f05f07e 100644
+--- a/tests/system-ovn.at
++++ b/tests/system-ovn.at
+@@ -3927,6 +3927,24 @@ ovn-nbctl acl-add pg0 to-lport 1002 "outport == @pg0 && ip4 && ip4.src == 0.0.0.
+ ovn-nbctl --log acl-add pg0 to-lport 1004 "inport == @pg0 && ip && tcp && tcp.dst == 84" reject
+ ovn-nbctl --log acl-add pg0 to-lport 1004 "inport == @pg0 && ip && udp && udp.dst == 94" reject
+ 
++ovn-nbctl ls-add sw1
++ovn-nbctl lsp-add sw1 sw1-p1-rej
++ovn-nbctl lsp-set-addresses sw1-p1-rej "40:54:00:00:00:03 20.0.0.3"
++ovn-nbctl lsp-set-port-security sw1-p1-rej "40:54:00:00:00:03 20.0.0.3"
++
++ovn-nbctl lr-add lr0
++ovn-nbctl lrp-add lr0 lr0-sw0 00:00:00:00:ff:01 10.0.0.1/24
++ovn-nbctl lsp-add sw0 sw0-lr0
++ovn-nbctl lsp-set-type sw0-lr0 router
++ovn-nbctl lsp-set-addresses sw0-lr0 router
++ovn-nbctl lsp-set-options sw0-lr0 router-port=lr0-sw0
++
++ovn-nbctl lrp-add lr0 lr0-sw1 00:00:00:00:ff:02 20.0.0.1/24
++ovn-nbctl lsp-add sw1 sw1-lr0
++ovn-nbctl lsp-set-type sw1-lr0 router
++ovn-nbctl lsp-set-addresses sw1-lr0 router
++ovn-nbctl lsp-set-options sw1-lr0 router-port=lr0-sw1
++
+ OVN_POPULATE_ARP
+ ovn-nbctl --wait=hv sync
+ 
+@@ -3941,6 +3959,10 @@ ADD_VETH(sw0-p2-rej, sw0-p2-rej, br-int, "10.0.0.4/24", "50:54:00:00:00:04", \
+ NS_CHECK_EXEC([sw0-p1-rej], [ip a a aef0::3/64 dev sw0-p1-rej], [0])
+ NS_CHECK_EXEC([sw0-p2-rej], [ip a a aef0::4/64 dev sw0-p2-rej], [0])
+ 
++ADD_NAMESPACES(sw1-p1-rej)
++ADD_VETH(sw1-p1-rej, sw1-p1-rej, br-int, "20.0.0.3/24", "40:54:00:00:00:03", \
++         "20.0.0.1")
++
+ sleep 1
+ 
+ # Capture packets in sw0-p1-rej.
+@@ -3993,6 +4015,16 @@ OVS_WAIT_UNTIL([
+     test "${total}" = "2"
+ ])
+ 
++ovn-nbctl acl-add sw1 from-lport 1004 "ip" allow-related
++ovn-nbctl acl-add sw1 to-lport 1004 "ip" allow-related
++ovn-nbctl --log acl-add pg0 to-lport 1004 "outport == @pg0 && ip && tcp && tcp.dst == 84" reject
++
++OVS_WAIT_UNTIL([
++    ip netns exec sw1-p1-rej nc  10.0.0.4 84 2> r
++    res=$(cat r)
++    test "$res" = "Ncat: Connection refused."
++])
++
+ # Now test for IPv4 UDP.
+ NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -n -c 1 -i sw0-p1-rej udp port 90 > sw0-p1-rej-udp.pcap &], [0])
+ NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -n -c 1 -i sw0-p1-rej icmp > sw0-p1-rej-icmp.pcap &], [0])
+-- 
+2.26.2
+
diff --git a/SOURCES/0001-IPv6-PD-assume-status-to-be-Success-if-not-present.patch b/SOURCES/0001-IPv6-PD-assume-status-to-be-Success-if-not-present.patch
new file mode 100644
index 0000000..2ef8f34
--- /dev/null
+++ b/SOURCES/0001-IPv6-PD-assume-status-to-be-Success-if-not-present.patch
@@ -0,0 +1,36 @@
+From f3f604a41e44a17b1953ebd3d2162c1fc046f49f Mon Sep 17 00:00:00 2001
+Message-Id: <f3f604a41e44a17b1953ebd3d2162c1fc046f49f.1588582791.git.lorenzo.bianconi@redhat.com>
+From: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
+Date: Sat, 25 Apr 2020 12:18:12 +0200
+Subject: [PATCH] IPv6 PD: assume status to be Success if not present
+
+According to the RFC3315 (section 22.13. Status Code Option),
+if status code option is not present in the delegation server
+reply, it will be assumed to be Success. In this particular case,
+do not stop IPv6 PD state machine
+
+Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
+Signed-off-by: Numan Siddique <numans@ovn.org>
+---
+ controller/pinctrl.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/controller/pinctrl.c
++++ b/controller/pinctrl.c
+@@ -835,12 +835,15 @@ pinctrl_parse_dhcpv6_reply(struct dp_pac
+                     plife_time = ntohl(ia_hdr->plife_time);
+                     vlife_time = ntohl(ia_hdr->vlife_time);
+                     memcpy(&ipv6, &ia_hdr->ipv6, sizeof (struct in6_addr));
++                    status = true;
+                 }
+                 if (ntohs(in_opt->code) == DHCPV6_OPT_STATUS_CODE) {
+                    struct dhcpv6_opt_status *status_hdr;
+ 
+                    status_hdr = (struct dhcpv6_opt_status *)in_opt;
+-                   status = ntohs(status_hdr->status_code) == 0;
++                   if (ntohs(status_hdr->status_code)) {
++                       status = false;
++                   }
+                 }
+                 size += sizeof *in_opt + ntohs(in_opt->len);
+                 in_opt = (struct dhcpv6_opt_header *)(in_dhcpv6_data + size);
diff --git a/SOURCES/0001-IPv6-PD-time-parameter-checks.patch b/SOURCES/0001-IPv6-PD-time-parameter-checks.patch
new file mode 100644
index 0000000..1221fb8
--- /dev/null
+++ b/SOURCES/0001-IPv6-PD-time-parameter-checks.patch
@@ -0,0 +1,68 @@
+From 942f7b2b9e3acfc7b1d6ea5c48fc22171b14549a Mon Sep 17 00:00:00 2001
+Message-Id: <942f7b2b9e3acfc7b1d6ea5c48fc22171b14549a.1588586761.git.lorenzo.bianconi@redhat.com>
+From: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
+Date: Thu, 23 Apr 2020 18:25:20 +0200
+Subject: [PATCH] IPv6 PD: time parameter checks
+
+RFC3633 imposes the following constraints for IPv6 pd time parameters:
+
+Identity Association for Prefix Delegation Option:
+--------------------------------------------------
+t1 must not be greater than t2 if both of them are greater than 0
+
+IA_PD Prefix option:
+--------------------
+preferred lifetime must not be greater than valid lifetime
+
+Add checks for previous constraints in ovn implementation
+
+Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
+Signed-off-by: Numan Siddique <numans@ovn.org>
+---
+ controller/pinctrl.c | 19 ++++++++++++++++++-
+ 1 file changed, 18 insertions(+), 1 deletion(-)
+
+--- a/controller/pinctrl.c
++++ b/controller/pinctrl.c
+@@ -653,6 +653,11 @@ pinctrl_parse_dhcpv6_advt(struct rconn *
+         case DHCPV6_OPT_IA_PD: {
+             struct dhcpv6_opt_ia_na *ia_na = (struct dhcpv6_opt_ia_na *)in_opt;
+             int orig_len = len, hdr_len = 0, size = sizeof *in_opt + 12;
++            uint32_t t1 = ntohl(ia_na->t1), t2 = ntohl(ia_na->t2);
++
++            if (t1 > t2 && t2 > 0) {
++                goto out;
++            }
+ 
+             aid = ntohl(ia_na->iaid);
+             memcpy(&data[len], in_opt, size);
+@@ -667,6 +672,15 @@ pinctrl_parse_dhcpv6_advt(struct rconn *
+                 }
+ 
+                 if (ntohs(in_opt->code) == DHCPV6_OPT_IA_PREFIX) {
++                    struct dhcpv6_opt_ia_prefix *ia_hdr =
++                        (struct dhcpv6_opt_ia_prefix *)in_opt;
++                    uint32_t plife_time = ntohl(ia_hdr->plife_time);
++                    uint32_t vlife_time = ntohl(ia_hdr->vlife_time);
++
++                    if (plife_time > vlife_time) {
++                        goto out;
++                    }
++
+                     memcpy(&data[len], in_opt, flen);
+                     hdr_len += flen;
+                     len += flen;
+@@ -831,9 +845,12 @@ pinctrl_parse_dhcpv6_reply(struct dp_pac
+                     struct dhcpv6_opt_ia_prefix *ia_hdr =
+                         (struct dhcpv6_opt_ia_prefix *)(in_dhcpv6_data + size);
+ 
+-                    prefix_len = ia_hdr->plen;
+                     plife_time = ntohl(ia_hdr->plife_time);
+                     vlife_time = ntohl(ia_hdr->vlife_time);
++                    if (plife_time > vlife_time) {
++                        break;
++                    }
++                    prefix_len = ia_hdr->plen;
+                     memcpy(&ipv6, &ia_hdr->ipv6, sizeof (struct in6_addr));
+                     status = true;
+                 }
diff --git a/SOURCES/0001-Make-the-notify-calls-work-with-IPv6-in-the-OCF-reso.patch b/SOURCES/0001-Make-the-notify-calls-work-with-IPv6-in-the-OCF-reso.patch
new file mode 100644
index 0000000..262e59b
--- /dev/null
+++ b/SOURCES/0001-Make-the-notify-calls-work-with-IPv6-in-the-OCF-reso.patch
@@ -0,0 +1,44 @@
+From 5d47f08c60600708aae354b021da9779a9c8e5e6 Mon Sep 17 00:00:00 2001
+From: Michele Baldessari <michele@acksyn.org>
+Date: Wed, 3 Jun 2020 14:43:47 +0200
+Subject: [PATCH] Make the notify() calls work with IPv6 in the OCF
+ resource-agent
+
+When the VIP is an IPv6 address we get the following error in the
+resource agent:
+ovndb_servers_notify_0:355:stderr [ + ovn-sbctl -- --id=@conn_uuid create Connection 'target=ptcp\:6642\:[fd00:fd00:fd00:2000::a2]' inactivity_probe=180000 -- set SB_Global . connections=@conn_uuid ]
+ovndb_servers_notify_0:355:stderr [ ovn-sbctl: ptcp\:6642\:[fd00:fd00:fd00:2000::a2]: unexpected "[" parsing string ]
+
+This is because MASTER_IP is an IPv6 address and is being passed to
+ovn-[ns]bctl without being escaped and the command errors out with
+unexpected parsing string errors. The rest of the create Connection
+command was already escaping the columns, we are just missing the ip
+address bits in case of IPv6.
+
+Let's make sure we escape the '[]:' characters and avoid this problem.
+Tested this on an OpenStack environment on both IPv6 and IPv4.
+
+Signed-off-by: Michele Baldessari <michele@acksyn.org>
+Signed-off-by: Numan Siddique <numans@ovn.org>
+---
+ utilities/ovndb-servers.ocf | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/utilities/ovndb-servers.ocf b/utilities/ovndb-servers.ocf
+index 56c2bc322..7351c7d64 100755
+--- a/utilities/ovndb-servers.ocf
++++ b/utilities/ovndb-servers.ocf
+@@ -249,7 +249,9 @@ ovsdb_server_notify() {
+         if [ "x${LISTEN_ON_MASTER_IP_ONLY}" = xno ]; then
+            LISTEN_ON_IP="0.0.0.0"
+         else
+-           LISTEN_ON_IP=${MASTER_IP}
++           # ovn-[sn]bctl want ':[]' characters to be escaped. We do so in
++           # order to make this work when MASTER_IP is an IPv6 address.
++           LISTEN_ON_IP=$(sed -e 's/\(\[\|\]\|:\)/\\\1/g' <<< ${MASTER_IP})
+         fi
+         conn=`ovn-nbctl get NB_global . connections`
+         if [ "$conn" == "[]" ]
+-- 
+2.26.2
+
diff --git a/SOURCES/0001-Rely-on-unique-name-for-ovn-qos-meters.patch b/SOURCES/0001-Rely-on-unique-name-for-ovn-qos-meters.patch
new file mode 100644
index 0000000..04bf3fd
--- /dev/null
+++ b/SOURCES/0001-Rely-on-unique-name-for-ovn-qos-meters.patch
@@ -0,0 +1,73 @@
+From ab7a370f24ec88a019f1aa4da76f1a050bf398c6 Mon Sep 17 00:00:00 2001
+Message-Id: <ab7a370f24ec88a019f1aa4da76f1a050bf398c6.1588167268.git.lorenzo.bianconi@redhat.com>
+From: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
+Date: Mon, 27 Apr 2020 17:45:20 +0200
+Subject: [PATCH] Rely on unique name for ovn qos meters
+
+ovn currently identifies qos meters according to the rate and burst values
+configured. Doing so 2 meters on the same hv assigned to 2 different logical
+switch ports and configured with the same values for rate and burst will be
+mapped to the same ovs kernel mater and will share the bandwidth.
+Fix this behavior making qos meter name unique
+
+Tested-By: Maciej Jozefczyk <mjozefcz@redhat.com>
+Acked-by: Han Zhou <hzhou@ovn.org>
+Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
+Signed-off-by: Numan Siddique <numans@ovn.org>
+---
+ controller/ofctrl.c |  2 +-
+ lib/actions.c       | 11 ++++++-----
+ tests/ovn.at        | 10 ++++++++++
+ 3 files changed, 17 insertions(+), 6 deletions(-)
+
+--- a/controller/ofctrl.c
++++ b/controller/ofctrl.c
+@@ -970,7 +970,7 @@ add_meter_string(struct ovn_extend_table
+     enum ofputil_protocol usable_protocols;
+     char *meter_string = xasprintf("meter=%"PRIu32",%s",
+                                    m_desired->table_id,
+-                                   &m_desired->name[9]);
++                                   &m_desired->name[52]);
+     char *error = parse_ofp_meter_mod_str(&mm, meter_string, OFPMC13_ADD,
+                                           &usable_protocols);
+     if (!error) {
+--- a/lib/actions.c
++++ b/lib/actions.c
+@@ -2796,12 +2796,13 @@ encode_SET_METER(const struct ovnact_set
+      * describes the meter itself. */
+     char *name;
+     if (cl->burst) {
+-        name = xasprintf("__string: kbps burst stats bands=type=drop "
+-                         "rate=%"PRId64" burst_size=%"PRId64"", cl->rate,
+-                         cl->burst);
++        name = xasprintf("__string: uuid "UUID_FMT" kbps burst stats "
++                         "bands=type=drop rate=%"PRId64" burst_size=%"PRId64,
++                         UUID_ARGS(&ep->lflow_uuid), cl->rate, cl->burst);
+     } else {
+-        name = xasprintf("__string: kbps stats bands=type=drop "
+-                         "rate=%"PRId64"", cl->rate);
++        name = xasprintf("__string: uuid "UUID_FMT" kbps stats "
++                         "bands=type=drop rate=%"PRId64,
++                         UUID_ARGS(&ep->lflow_uuid), cl->rate);
+     }
+ 
+     table_id = ovn_extend_table_assign_id(ep->meter_table, name,
+--- a/tests/ovn.at
++++ b/tests/ovn.at
+@@ -7653,6 +7653,16 @@ AT_CHECK([as hv ovs-ofctl dump-flows br-
+ AT_CHECK([as hv ovs-ofctl dump-meters br-int -O OpenFlow13 | grep rate=11123 | wc -l], [0], [0
+ ])
+ 
++# Check multiple qos meters
++ovn-nbctl qos-del lsw0
++ovn-nbctl qos-add lsw0 to-lport 1001 'inport=="lp1" && is_chassis_resident("lp1")' rate=100000 burst=100000
++ovn-nbctl qos-add lsw0 to-lport 1001 'inport=="lp2" && is_chassis_resident("lp2")' rate=100000 burst=100000
++ovn-nbctl qos-add lsw0 to-lport 1002 'inport=="lp1" && is_chassis_resident("lp1")' rate=100001 burst=100001
++ovn-nbctl qos-add lsw0 to-lport 1002 'inport=="lp2" && is_chassis_resident("lp2")' rate=100001 burst=100001
++
++AT_CHECK([as hv ovs-ofctl dump-meters br-int -O OpenFlow13 | grep meter | wc -l], [0], [4
++])
++
+ OVN_CLEANUP([hv])
+ AT_CLEANUP
+ 
diff --git a/SOURCES/0001-Revert-ovsdb-idl-Avoid-sending-redundant-conditional.patch b/SOURCES/0001-Revert-ovsdb-idl-Avoid-sending-redundant-conditional.patch
new file mode 100644
index 0000000..8cb059a
--- /dev/null
+++ b/SOURCES/0001-Revert-ovsdb-idl-Avoid-sending-redundant-conditional.patch
@@ -0,0 +1,67 @@
+From 7d3fe4b24896304bc1d832f95a425fa62c48f7f8 Mon Sep 17 00:00:00 2001
+From: Dumitru Ceara <dceara@redhat.com>
+Date: Wed, 25 Mar 2020 21:15:23 +0100
+Subject: [PATCH] Revert "ovsdb-idl: Avoid sending redundant conditional
+ monitoring updates"
+
+This reverts commit 5351980b047f4dd40be7a59a1e4b910df21eca0a.
+
+If the ovsdb-server reply to "monitor_cond_since" requests has
+"found" == false then ovsdb_idl_db_parse_monitor_reply() calls
+ovsdb_idl_db_clear() which iterates through all tables and
+unconditionally sets table->cond_changed to false.
+
+However, if the client had already set a new condition for some of the
+tables, this new condition request will never be sent to ovsdb-server
+until the condition is reset to a different value. This is due to the
+check in ovsdb_idl_db_set_condition().
+
+One way to replicate the issue is described in the bugzilla reporting
+the bug, when ovn-controller is configured to use "ovn-monitor-all":
+https://bugzilla.redhat.com/show_bug.cgi?id=1808125#c6
+
+Commit 5351980b047f tried to optimize sending redundant conditional
+monitoring updates but the chances that this scenario happens with the
+latest code is quite low since commit 403a6a0cb003 ("ovsdb-idl: Fast
+resync from server when connection reset.") changed the behavior of
+ovsdb_idl_db_parse_monitor_reply() to avoid calling ovsdb_idl_db_clear()
+in most cases.
+
+Reported-by: Dan Williams <dcbw@redhat.com>
+Reported-at: https://bugzilla.redhat.com/1808125
+CC: Andy Zhou <azhou@ovn.org>
+Fixes: 5351980b047f ("ovsdb-idl: Avoid sending redundant conditional monitoring updates")
+Acked-by: Han Zhou <hzhou@ovn.org>
+Acked-by: Ilya Maximets <i.maximets@ovn.org>
+Signed-off-by: Dumitru Ceara <dceara@redhat.com>
+Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
+(cherry picked from upstream OVS commit 2b7e536fa5e20be10e620b959e05557f88862d2c)
+
+Change-Id: Iaa24bc949d648e8fa29abea1fe8fb5878ba45864
+---
+ openvswitch-2.13.0/lib/ovsdb-idl.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/openvswitch-2.13.0/lib/ovsdb-idl.c b/openvswitch-2.13.0/lib/ovsdb-idl.c
+index 190143f..1535ad7 100644
+--- a/openvswitch-2.13.0/lib/ovsdb-idl.c
++++ b/openvswitch-2.13.0/lib/ovsdb-idl.c
+@@ -610,7 +610,6 @@ ovsdb_idl_db_clear(struct ovsdb_idl_db *db)
+         struct ovsdb_idl_table *table = &db->tables[i];
+         struct ovsdb_idl_row *row, *next_row;
+ 
+-        table->cond_changed = false;
+         if (hmap_is_empty(&table->rows)) {
+             continue;
+         }
+@@ -634,7 +633,6 @@ ovsdb_idl_db_clear(struct ovsdb_idl_db *db)
+     }
+     ovsdb_idl_row_destroy_postprocess(db);
+ 
+-    db->cond_changed = false;
+     db->cond_seqno = 0;
+     ovsdb_idl_db_track_clear(db);
+ 
+-- 
+1.8.3.1
+
diff --git a/SOURCES/0001-Split-SB-Port_Group-per-datapath.patch b/SOURCES/0001-Split-SB-Port_Group-per-datapath.patch
new file mode 100644
index 0000000..695a0fe
--- /dev/null
+++ b/SOURCES/0001-Split-SB-Port_Group-per-datapath.patch
@@ -0,0 +1,556 @@
+From 3cdc2f9cdd9b4911a236c731dfa76535e3af38e6 Mon Sep 17 00:00:00 2001
+From: Dumitru Ceara <dceara@redhat.com>
+Date: Mon, 29 Jun 2020 17:24:41 +0200
+Subject: [PATCH] Split SB Port_Group per datapath.
+
+In order to avoid ovn-controller reinstalling all logical flows that
+refer a port_group when some ports are added/removed from the port group
+we now change the way ovn-northd populates the Southbound DB Port_Group
+table.
+
+Instead of copying NB.Port_Group.name to SB.Port_Group.name we now
+create one SB.Port_Group record for every datapath that has ports
+referenced by the NB.Port_Group.ports field. In order to maintain the
+SB.Port_Group.name uniqueness constraint, ovn-northd populates the field
+with the value: <SB.Logical_Datapath.tunnel_key>_<NB.Port_Group.name>.
+
+In specific scenarios we see significant improvements in time to
+install/remove all logical flows to/from OVS. One such scenario, in the
+BZ referenced below has:
+
+$ ovn-nbctl acl-list pg
+  from-lport  1001 (inport == @pg && ip) drop
+    to-lport  1001 (outport == @pg && ip) drop
+
+Then, incrementally, creates new logical ports on different logical
+switches, binds them to OVS interfaces and adds them to the port_group.
+
+Measuring the total time to perform the above steps 500 times (for 500
+new ports attached to 100 switches, 5 per switch) on a test setup
+we observe an improvement of 50% in time it takes to install all
+openflow rules when port_groups are split in the SB database.
+
+Suggested-by: Numan Siddique <numans@ovn.org>
+Reported-by: Venkata Anil <anilvenkata@redhat.com>
+Reported-at: https://bugzilla.redhat.com/1818128
+Signed-off-by: Dumitru Ceara <dceara@redhat.com>
+Acked-by: Numan Siddique <numans@ovn.org>
+Signed-off-by: Mark Michelson <mmichels@redhat.com>
+
+Conflicts:
+	TODO.rst
+	lib/ovn-util.h
+
+Change-Id: Ibb8ffc5dbf4deb33a46e94b3f7b57c248d669073
+---
+ TODO.rst              |  8 ++++++
+ controller/lflow.c    |  4 ++-
+ include/ovn/expr.h    |  4 ++-
+ lib/actions.c         |  2 +-
+ lib/expr.c            | 48 ++++++++++++++++++++++++-------
+ lib/ovn-util.h        |  7 +++++
+ northd/ovn-northd.c   | 79 ++++++++++++++++++++++++++++++++++-----------------
+ tests/ovn-northd.at   | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ tests/test-ovn.c      | 10 +++----
+ utilities/ovn-trace.c |  3 +-
+ 10 files changed, 198 insertions(+), 46 deletions(-)
+
+diff --git a/TODO.rst b/TODO.rst
+index 809d1c9..cfd33be 100644
+--- a/TODO.rst
++++ b/TODO.rst
+@@ -149,3 +149,11 @@ OVN To-do List
+ * OVN Interconnection
+ 
+   * Packaging for RHEL, Debian, etc.
++
++* ovn-controller: Remove backwards compatibility for Southbound DB Port_Group
++  names in expr.c a few releases after the 20.09 version. Right now
++  ovn-controller maintains backwards compatibility when connecting to a
++  SB database that doesn't store Port_Group.name as
++  <Logical_Datapath.tunnel_key_NB-Port_Group.name>. This causes an additional
++  hashtable lookup in parse_port_group() which can be avoided when we are sure
++  that the Southbound DB uses the new format.
+diff --git a/controller/lflow.c b/controller/lflow.c
+index 01214a3..0e57327 100644
+--- a/controller/lflow.c
++++ b/controller/lflow.c
+@@ -552,7 +552,9 @@ consider_logical_flow(const struct sbrec_logical_flow *lflow,
+     struct sset port_groups_ref = SSET_INITIALIZER(&port_groups_ref);
+     expr = expr_parse_string(lflow->match, &symtab, l_ctx_in->addr_sets,
+                              l_ctx_in->port_groups,
+-                             &addr_sets_ref, &port_groups_ref, &error);
++                             &addr_sets_ref, &port_groups_ref,
++                             lflow->logical_datapath->tunnel_key,
++                             &error);
+     const char *addr_set_name;
+     SSET_FOR_EACH (addr_set_name, &addr_sets_ref) {
+         lflow_resource_add(l_ctx_out->lfrr, REF_TYPE_ADDRSET, addr_set_name,
+diff --git a/include/ovn/expr.h b/include/ovn/expr.h
+index 21bf51c..9838251 100644
+--- a/include/ovn/expr.h
++++ b/include/ovn/expr.h
+@@ -391,12 +391,14 @@ struct expr *expr_parse(struct lexer *, const struct shash *symtab,
+                         const struct shash *addr_sets,
+                         const struct shash *port_groups,
+                         struct sset *addr_sets_ref,
+-                        struct sset *port_groups_ref);
++                        struct sset *port_groups_ref,
++                        int64_t dp_id);
+ struct expr *expr_parse_string(const char *, const struct shash *symtab,
+                                const struct shash *addr_sets,
+                                const struct shash *port_groups,
+                                struct sset *addr_sets_ref,
+                                struct sset *port_groups_ref,
++                               int64_t dp_id,
+                                char **errorp);
+ 
+ struct expr *expr_clone(struct expr *);
+diff --git a/lib/actions.c b/lib/actions.c
+index 3181126..d107871 100644
+--- a/lib/actions.c
++++ b/lib/actions.c
+@@ -242,7 +242,7 @@ add_prerequisite(struct action_context *ctx, const char *prerequisite)
+     char *error;
+ 
+     expr = expr_parse_string(prerequisite, ctx->pp->symtab, NULL, NULL,
+-                             NULL, NULL, &error);
++                             NULL, NULL, 0, &error);
+     ovs_assert(!error);
+     ctx->prereqs = expr_combine(EXPR_T_AND, ctx->prereqs, expr);
+ }
+diff --git a/lib/expr.c b/lib/expr.c
+index 078d178..497b2ac 100644
+--- a/lib/expr.c
++++ b/lib/expr.c
+@@ -29,6 +29,7 @@
+ #include "simap.h"
+ #include "sset.h"
+ #include "util.h"
++#include "ovn-util.h"
+ 
+ VLOG_DEFINE_THIS_MODULE(expr);
+ 
+@@ -482,6 +483,10 @@ struct expr_context {
+     const struct shash *port_groups; /* Port group table. */
+     struct sset *addr_sets_ref;      /* The set of address set referenced. */
+     struct sset *port_groups_ref;    /* The set of port groups referenced. */
++    int64_t dp_id;                   /* The tunnel_key of the datapath for
++                                        which we're parsing the current
++                                        expression. */
++
+     bool not;                    /* True inside odd number of NOT operators. */
+     unsigned int paren_depth;    /* Depth of nested parentheses. */
+ };
+@@ -783,14 +788,32 @@ static bool
+ parse_port_group(struct expr_context *ctx, struct expr_constant_set *cs,
+                  size_t *allocated_values)
+ {
++    struct ds sb_name = DS_EMPTY_INITIALIZER;
++
++    get_sb_port_group_name(ctx->lexer->token.s, ctx->dp_id, &sb_name);
+     if (ctx->port_groups_ref) {
+-        sset_add(ctx->port_groups_ref, ctx->lexer->token.s);
++        sset_add(ctx->port_groups_ref, ds_cstr(&sb_name));
++    }
++
++    struct expr_constant_set *port_group = NULL;
++
++    if (ctx->port_groups) {
++        port_group = shash_find_data(ctx->port_groups, ds_cstr(&sb_name));
++        if (!port_group) {
++            /* For backwards compatibility (e.g., ovn-controller was
++             * upgraded but ovn-northd not yet), perform an additional
++             * lookup because the NB Port_Group.name might have been
++             * stored as is in the SB Port_Group.name field.
++             */
++            port_group = shash_find_data(ctx->port_groups,
++                                         ctx->lexer->token.s);
++            if (ctx->port_groups_ref) {
++                sset_add(ctx->port_groups_ref, ctx->lexer->token.s);
++            }
++        }
+     }
++    ds_destroy(&sb_name);
+ 
+-    struct expr_constant_set *port_group
+-        = (ctx->port_groups
+-           ? shash_find_data(ctx->port_groups, ctx->lexer->token.s)
+-           : NULL);
+     if (!port_group) {
+         lexer_syntax_error(ctx->lexer, "expecting port group name");
+         return false;
+@@ -1302,14 +1325,16 @@ expr_parse(struct lexer *lexer, const struct shash *symtab,
+            const struct shash *addr_sets,
+            const struct shash *port_groups,
+            struct sset *addr_sets_ref,
+-           struct sset *port_groups_ref)
++           struct sset *port_groups_ref,
++           int64_t dp_id)
+ {
+     struct expr_context ctx = { .lexer = lexer,
+                                 .symtab = symtab,
+                                 .addr_sets = addr_sets,
+                                 .port_groups = port_groups,
+                                 .addr_sets_ref = addr_sets_ref,
+-                                .port_groups_ref = port_groups_ref };
++                                .port_groups_ref = port_groups_ref,
++                                .dp_id = dp_id };
+     return lexer->error ? NULL : expr_parse__(&ctx);
+ }
+ 
+@@ -1325,6 +1350,7 @@ expr_parse_string(const char *s, const struct shash *symtab,
+                   const struct shash *port_groups,
+                   struct sset *addr_sets_ref,
+                   struct sset *port_groups_ref,
++                  int64_t dp_id,
+                   char **errorp)
+ {
+     struct lexer lexer;
+@@ -1332,7 +1358,7 @@ expr_parse_string(const char *s, const struct shash *symtab,
+     lexer_init(&lexer, s);
+     lexer_get(&lexer);
+     struct expr *expr = expr_parse(&lexer, symtab, addr_sets, port_groups,
+-                                   addr_sets_ref, port_groups_ref);
++                                   addr_sets_ref, port_groups_ref, dp_id);
+     lexer_force_end(&lexer);
+     *errorp = lexer_steal_error(&lexer);
+     if (*errorp) {
+@@ -1558,7 +1584,7 @@ expr_get_level(const struct expr *expr)
+ static enum expr_level
+ expr_parse_level(const char *s, const struct shash *symtab, char **errorp)
+ {
+-    struct expr *expr = expr_parse_string(s, symtab, NULL, NULL, NULL, NULL,
++    struct expr *expr = expr_parse_string(s, symtab, NULL, NULL, NULL, NULL, 0,
+                                           errorp);
+     enum expr_level level = expr ? expr_get_level(expr) : EXPR_L_NOMINAL;
+     expr_destroy(expr);
+@@ -1730,7 +1756,7 @@ parse_and_annotate(const char *s, const struct shash *symtab,
+     char *error;
+     struct expr *expr;
+ 
+-    expr = expr_parse_string(s, symtab, NULL, NULL, NULL, NULL, &error);
++    expr = expr_parse_string(s, symtab, NULL, NULL, NULL, NULL, 0, &error);
+     if (expr) {
+         expr = expr_annotate_(expr, symtab, nesting, &error);
+     }
+@@ -3456,7 +3482,7 @@ expr_parse_microflow(const char *s, const struct shash *symtab,
+     lexer_get(&lexer);
+ 
+     struct expr *e = expr_parse(&lexer, symtab, addr_sets, port_groups,
+-                                NULL, NULL);
++                                NULL, NULL, 0);
+     lexer_force_end(&lexer);
+ 
+     if (e) {
+diff --git a/lib/ovn-util.h b/lib/ovn-util.h
+index ec5f2cf..9c6d357 100644
+--- a/lib/ovn-util.h
++++ b/lib/ovn-util.h
+@@ -111,6 +111,13 @@ bool ovn_tnlid_in_use(const struct hmap *set, uint32_t tnlid);
+ uint32_t ovn_allocate_tnlid(struct hmap *set, const char *name, uint32_t min,
+                             uint32_t max, uint32_t *hint);
+ 
++static inline void
++get_sb_port_group_name(const char *nb_pg_name, int64_t dp_tunnel_key,
++                       struct ds *sb_pg_name)
++{
++    ds_put_format(sb_pg_name, "%"PRId64"_%s", dp_tunnel_key, nb_pg_name);
++}
++
+ char *ovn_chassis_redirect_name(const char *port_name);
+ void ovn_set_pidfile(const char *name);
+ 
+diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
+index fc25031..8a809d0 100644
+--- a/northd/ovn-northd.c
++++ b/northd/ovn-northd.c
+@@ -4457,7 +4457,11 @@ build_dhcpv6_action(struct ovn_port *op, struct in6_addr *offer_ip,
+ struct ovn_port_group_ls {
+     struct hmap_node key_node;  /* Index on 'key'. */
+     struct uuid key;            /* nb_ls->header_.uuid. */
+-    const struct nbrec_logical_switch *nb_ls;
++    struct ovn_datapath *od;
++
++    struct ovn_port **ports; /* Ports in 'od' referrenced by the PG. */
++    size_t n_ports;
++    size_t n_allocated_ports;
+ };
+ 
+ struct ovn_port_group {
+@@ -4467,14 +4471,14 @@ struct ovn_port_group {
+     struct hmap nb_lswitches;   /* NB lswitches related to the port group */
+ };
+ 
+-static void
+-ovn_port_group_ls_add(struct ovn_port_group *pg,
+-                      const struct nbrec_logical_switch *nb_ls)
++static struct ovn_port_group_ls *
++ovn_port_group_ls_add(struct ovn_port_group *pg, struct ovn_datapath *od)
+ {
+     struct ovn_port_group_ls *pg_ls = xzalloc(sizeof *pg_ls);
+-    pg_ls->key = nb_ls->header_.uuid;
+-    pg_ls->nb_ls = nb_ls;
++    pg_ls->key = od->nbs->header_.uuid;
++    pg_ls->od = od;
+     hmap_insert(&pg->nb_lswitches, &pg_ls->key_node, uuid_hash(&pg_ls->key));
++    return pg_ls;
+ }
+ 
+ static struct ovn_port_group_ls *
+@@ -4491,6 +4495,18 @@ ovn_port_group_ls_find(struct ovn_port_group *pg, const struct uuid *ls_uuid)
+     return NULL;
+ }
+ 
++static void
++ovn_port_group_ls_add_port(struct ovn_port_group_ls *pg_ls,
++                           struct ovn_port *op)
++{
++    if (pg_ls->n_ports == pg_ls->n_allocated_ports) {
++        pg_ls->ports = x2nrealloc(pg_ls->ports,
++                                  &pg_ls->n_allocated_ports,
++                                  sizeof *pg_ls->ports);
++    }
++    pg_ls->ports[pg_ls->n_ports++] = op;
++}
++
+ struct ovn_ls_port_group {
+     struct hmap_node key_node;  /* Index on 'key'. */
+     struct uuid key;            /* nb_pg->header_.uuid. */
+@@ -5250,6 +5266,7 @@ ovn_port_group_destroy(struct hmap *pgs, struct ovn_port_group *pg)
+         hmap_remove(pgs, &pg->key_node);
+         struct ovn_port_group_ls *ls;
+         HMAP_FOR_EACH_POP (ls, key_node, &pg->nb_lswitches) {
++            free(ls->ports);
+             free(ls);
+         }
+         hmap_destroy(&pg->nb_lswitches);
+@@ -5287,9 +5304,10 @@ build_port_group_lswitches(struct northd_context *ctx, struct hmap *pgs,
+             struct ovn_port_group_ls *pg_ls =
+                 ovn_port_group_ls_find(pg, &op->od->nbs->header_.uuid);
+             if (!pg_ls) {
+-                ovn_port_group_ls_add(pg, op->od->nbs);
++                pg_ls = ovn_port_group_ls_add(pg, op->od);
+                 ovn_ls_port_group_add(&op->od->nb_pgs, nb_pg);
+             }
++            ovn_port_group_ls_add_port(pg_ls, op);
+         }
+     }
+ }
+@@ -10454,7 +10472,7 @@ sync_address_sets(struct northd_context *ctx)
+  * contains lport uuids, while in OVN_Southbound we store the lport names.
+  */
+ static void
+-sync_port_groups(struct northd_context *ctx)
++sync_port_groups(struct northd_context *ctx, struct hmap *pgs)
+ {
+     struct shash sb_port_groups = SHASH_INITIALIZER(&sb_port_groups);
+ 
+@@ -10463,26 +10481,35 @@ sync_port_groups(struct northd_context *ctx)
+         shash_add(&sb_port_groups, sb_port_group->name, sb_port_group);
+     }
+ 
+-    const struct nbrec_port_group *nb_port_group;
+-    NBREC_PORT_GROUP_FOR_EACH (nb_port_group, ctx->ovnnb_idl) {
+-        sb_port_group = shash_find_and_delete(&sb_port_groups,
+-                                               nb_port_group->name);
+-        if (!sb_port_group) {
+-            sb_port_group = sbrec_port_group_insert(ctx->ovnsb_txn);
+-            sbrec_port_group_set_name(sb_port_group, nb_port_group->name);
+-        }
++    struct ds sb_name = DS_EMPTY_INITIALIZER;
+ 
+-        const char **nb_port_names = xcalloc(nb_port_group->n_ports,
+-                                             sizeof *nb_port_names);
+-        int i;
+-        for (i = 0; i < nb_port_group->n_ports; i++) {
+-            nb_port_names[i] = nb_port_group->ports[i]->name;
++    struct ovn_port_group *pg;
++    HMAP_FOR_EACH (pg, key_node, pgs) {
++
++        struct ovn_port_group_ls *pg_ls;
++        HMAP_FOR_EACH (pg_ls, key_node, &pg->nb_lswitches) {
++            ds_clear(&sb_name);
++            get_sb_port_group_name(pg->nb_pg->name, pg_ls->od->sb->tunnel_key,
++                                   &sb_name);
++            sb_port_group = shash_find_and_delete(&sb_port_groups,
++                                                  ds_cstr(&sb_name));
++            if (!sb_port_group) {
++                sb_port_group = sbrec_port_group_insert(ctx->ovnsb_txn);
++                sbrec_port_group_set_name(sb_port_group, ds_cstr(&sb_name));
++            }
++
++            const char **nb_port_names = xcalloc(pg_ls->n_ports,
++                                                 sizeof *nb_port_names);
++            for (size_t i = 0; i < pg_ls->n_ports; i++) {
++                nb_port_names[i] = pg_ls->ports[i]->nbsp->name;
++            }
++            sbrec_port_group_set_ports(sb_port_group,
++                                       nb_port_names,
++                                       pg_ls->n_ports);
++            free(nb_port_names);
+         }
+-        sbrec_port_group_set_ports(sb_port_group,
+-                                   nb_port_names,
+-                                   nb_port_group->n_ports);
+-        free(nb_port_names);
+     }
++    ds_destroy(&sb_name);
+ 
+     struct shash_node *node, *next;
+     SHASH_FOR_EACH_SAFE (node, next, &sb_port_groups) {
+@@ -11081,7 +11108,7 @@ ovnnb_db_run(struct northd_context *ctx,
+     ovn_update_ipv6_prefix(ports);
+ 
+     sync_address_sets(ctx);
+-    sync_port_groups(ctx);
++    sync_port_groups(ctx, &port_groups);
+     sync_meters(ctx);
+     sync_dns_entries(ctx, datapaths);
+     destroy_ovn_lbs(&lbs);
+diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
+index e6a8c04..37805d3 100644
+--- a/tests/ovn-northd.at
++++ b/tests/ovn-northd.at
+@@ -1406,3 +1406,82 @@ AT_CHECK([ovn-nbctl --wait=sb sync], [0])
+ AT_CHECK([test 0 = $(ovn-sbctl list Ha_Chassis_Group | wc -l)])
+ 
+ AT_CLEANUP
++
++AT_SETUP([ovn -- check NB/SB Port_Group translation (lsp add/del)])
++ovn_start
++
++ovn-nbctl ls-add ls1
++ovn-nbctl ls-add ls2
++ovn-nbctl lsp-add ls1 lsp1
++ovn-nbctl lsp-add ls2 lsp2
++ovn-nbct --wait=sb sync
++ls1_key=$(ovn-sbctl --columns tunnel_key --bare list Datapath_Binding ls1)
++ls2_key=$(ovn-sbctl --columns tunnel_key --bare list Datapath_Binding ls2)
++
++# Add an empty port group. This should generate no entry in the SB.
++ovn-nbctl --wait=sb pg-add pg_test
++AT_CHECK([test 0 = $(ovn-sbctl --columns _uuid list Port_Group | grep uuid -c)])
++
++# Add lsp1 to the port group. This should generate an entry in the SB only
++# for ls1.
++ovn-nbctl --wait=sb pg-set-ports pg_test lsp1
++AT_CHECK([test 1 = $(ovn-sbctl --columns _uuid list Port_Group | grep uuid -c)])
++AT_CHECK([ovn-sbctl --columns ports --bare find Port_Group name=${ls1_key}_pg_test], [0], [dnl
++lsp1
++])
++
++# Add lsp2 to the port group. This should generate a new entry in the SB, for
++# ls2.
++ovn-nbctl --wait=sb pg-set-ports pg_test lsp1 lsp2
++AT_CHECK([test 2 = $(ovn-sbctl --columns _uuid list Port_Group | grep uuid -c)])
++AT_CHECK([ovn-sbctl --columns ports --bare find Port_Group name=${ls1_key}_pg_test], [0], [dnl
++lsp1
++])
++AT_CHECK([ovn-sbctl --columns ports --bare find Port_Group name=${ls2_key}_pg_test], [0], [dnl
++lsp2
++])
++
++# Remove lsp1 from the port group. The SB Port_Group for ls1 should be
++# removed.
++ovn-nbctl --wait=sb pg-set-ports pg_test lsp2
++AT_CHECK([test 1 = $(ovn-sbctl --columns _uuid list Port_Group | grep uuid -c)])
++AT_CHECK([ovn-sbctl --columns ports --bare find Port_Group name=${ls2_key}_pg_test], [0], [dnl
++lsp2
++])
++
++# Remove lsp2 from the port group. All SB Port_Groups should be purged.
++ovn-nbctl --wait=sb clear Port_Group pg_test ports
++AT_CHECK([test 0 = $(ovn-sbctl --columns _uuid list Port_Group | grep uuid -c)])
++
++AT_CLEANUP
++
++AT_SETUP([ovn -- check NB/SB Port_Group translation (ls del)])
++ovn_start
++
++ovn-nbctl ls-add ls1
++ovn-nbctl ls-add ls2
++ovn-nbctl lsp-add ls1 lsp1
++ovn-nbctl lsp-add ls2 lsp2
++ovn-nbct --wait=sb sync
++ls1_key=$(ovn-sbctl --columns tunnel_key --bare list Datapath_Binding ls1)
++ls2_key=$(ovn-sbctl --columns tunnel_key --bare list Datapath_Binding ls2)
++
++# Add lsp1 & lsp2 to a port group. This should generate two entries in the
++# SB (one per logical switch).
++ovn-nbctl --wait=sb pg-add pg_test lsp1 lsp2
++AT_CHECK([test 2 = $(ovn-sbctl --columns _uuid list Port_Group | grep uuid -c)])
++AT_CHECK([ovn-sbctl --columns ports --bare find Port_Group name=${ls1_key}_pg_test], [0], [dnl
++lsp1
++])
++AT_CHECK([ovn-sbctl --columns ports --bare find Port_Group name=${ls2_key}_pg_test], [0], [dnl
++lsp2
++])
++
++# Delete logical switch ls1. This should remove the associated SB Port_Group.
++ovn-nbctl --wait=sb ls-del ls1
++AT_CHECK([test 1 = $(ovn-sbctl --columns _uuid list Port_Group | grep uuid -c)])
++AT_CHECK([ovn-sbctl --columns ports --bare find Port_Group name=${ls2_key}_pg_test], [0], [dnl
++lsp2
++])
++
++AT_CLEANUP
+diff --git a/tests/test-ovn.c b/tests/test-ovn.c
+index 11697eb..9f74c5c 100644
+--- a/tests/test-ovn.c
++++ b/tests/test-ovn.c
+@@ -235,8 +235,8 @@ create_port_groups(struct shash *port_groups)
+     };
+     static const char *const pg2[] = { NULL };
+ 
+-    expr_const_sets_add(port_groups, "pg1", pg1, 3, false);
+-    expr_const_sets_add(port_groups, "pg_empty", pg2, 0, false);
++    expr_const_sets_add(port_groups, "0_pg1", pg1, 3, false);
++    expr_const_sets_add(port_groups, "0_pg_empty", pg2, 0, false);
+ }
+ 
+ static bool
+@@ -302,7 +302,7 @@ test_parse_expr__(int steps)
+         char *error;
+ 
+         expr = expr_parse_string(ds_cstr(&input), &symtab, &addr_sets,
+-                                 &port_groups, NULL, NULL, &error);
++                                 &port_groups, NULL, NULL, 0, &error);
+         if (!error && steps > 0) {
+             expr = expr_annotate(expr, &symtab, &error);
+         }
+@@ -428,7 +428,7 @@ test_evaluate_expr(struct ovs_cmdl_context *ctx)
+         struct expr *expr;
+ 
+         expr = expr_parse_string(ds_cstr(&input), &symtab, NULL, NULL,
+-                                 NULL, NULL, &error);
++                                 NULL, NULL, 0, &error);
+         if (!error) {
+             expr = expr_annotate(expr, &symtab, &error);
+         }
+@@ -903,7 +903,7 @@ test_tree_shape_exhaustively(struct expr *expr, struct shash *symtab,
+ 
+             char *error;
+             modified = expr_parse_string(ds_cstr(&s), symtab, NULL,
+-                                         NULL, NULL, NULL, &error);
++                                         NULL, NULL, NULL, 0, &error);
+             if (error) {
+                 fprintf(stderr, "%s fails to parse (%s)\n",
+                         ds_cstr(&s), error);
+diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c
+index d7251e7..2666c10 100644
+--- a/utilities/ovn-trace.c
++++ b/utilities/ovn-trace.c
+@@ -889,7 +889,8 @@ read_flows(void)
+         char *error;
+         struct expr *match;
+         match = expr_parse_string(sblf->match, &symtab, &address_sets,
+-                                  &port_groups, NULL, NULL, &error);
++                                  &port_groups, NULL, NULL, dp->tunnel_key,
++                                  &error);
+         if (error) {
+             VLOG_WARN("%s: parsing expression failed (%s)",
+                       sblf->match, error);
+-- 
+1.8.3.1
+
diff --git a/SOURCES/0001-controller-Use-OpenFlow-version-1.5.patch b/SOURCES/0001-controller-Use-OpenFlow-version-1.5.patch
new file mode 100644
index 0000000..b979eea
--- /dev/null
+++ b/SOURCES/0001-controller-Use-OpenFlow-version-1.5.patch
@@ -0,0 +1,259 @@
+From a8fcc8cc07ff9acbf9ff328e6ac2e781d73d3f8b Mon Sep 17 00:00:00 2001
+From: Numan Siddique <numans@ovn.org>
+Date: Tue, 21 Apr 2020 19:28:23 +0530
+Subject: [PATCH 1/4] controller: Use OpenFlow version 1.5
+
+When adding flows to the group table, we need to use OFP15_VERSION to
+set the selection_method. Right now ovn-controller is setting
+select_method=dp_hash for OVN load balancers, but when encoding the
+group mod, it is ignored.
+
+Acked-by: Han Zhou <hzhou@ovn.org>
+Signed-off-by: Numan Siddique <numans@ovn.org>
+---
+ NEWS                        |  1 +
+ controller/ofctrl.c         | 14 +++++++-------
+ controller/ovn-controller.c |  2 +-
+ controller/pinctrl.c        |  2 +-
+ lib/actions.c               | 10 +++++-----
+ lib/expr.c                  |  2 +-
+ tests/ovn.at                |  6 +++---
+ utilities/ovn-sbctl.c       |  4 ++--
+ utilities/ovn-trace.c       |  4 ++--
+ 9 files changed, 23 insertions(+), 22 deletions(-)
+
+diff --git a/NEWS b/NEWS
+index 21c80f0dc..e77343c89 100644
+--- a/NEWS
++++ b/NEWS
+@@ -8,6 +8,7 @@ OVN v20.03.0 - 28 Feb 2020
+    - Added support for MLD Snooping and MLD Querier.
+    - Added support for ECMP routes in OVN router.
+    - Added IPv6 Prefix Delegation support in OVN.
++   - OVN now uses OpenFlow 1.5.
+ 
+    - OVN Interconnection:
+      * Support for L3 interconnection of multiple OVN deployments with tunnels
+diff --git a/controller/ofctrl.c b/controller/ofctrl.c
+index 485a857d1..4b51cd86e 100644
+--- a/controller/ofctrl.c
++++ b/controller/ofctrl.c
+@@ -178,7 +178,7 @@ ofctrl_init(struct ovn_extend_table *group_table,
+             int inactivity_probe_interval)
+ {
+     swconn = rconn_create(inactivity_probe_interval, 0,
+-                          DSCP_DEFAULT, 1 << OFP13_VERSION);
++                          DSCP_DEFAULT, 1 << OFP15_VERSION);
+     tx_counter = rconn_packet_counter_create();
+     hmap_init(&installed_flows);
+     ovs_list_init(&flow_updates);
+@@ -282,8 +282,8 @@ process_tlv_table_reply(const struct ofputil_tlv_table_reply *reply)
+     ovs_list_init(&ttm.mappings);
+     ovs_list_push_back(&ttm.mappings, &tm.list_node);
+ 
+-    xid = queue_msg(ofputil_encode_tlv_table_mod(OFP13_VERSION, &ttm));
+-    xid2 = queue_msg(ofputil_encode_barrier_request(OFP13_VERSION));
++    xid = queue_msg(ofputil_encode_tlv_table_mod(OFP15_VERSION, &ttm));
++    xid2 = queue_msg(ofputil_encode_barrier_request(OFP15_VERSION));
+     state = S_TLV_TABLE_MOD_SENT;
+ 
+     return true;
+@@ -911,7 +911,7 @@ encode_flow_mod(struct ofputil_flow_mod *fm)
+     fm->buffer_id = UINT32_MAX;
+     fm->out_port = OFPP_ANY;
+     fm->out_group = OFPG_ANY;
+-    return ofputil_encode_flow_mod(fm, OFPUTIL_P_OF13_OXM);
++    return ofputil_encode_flow_mod(fm, OFPUTIL_P_OF15_OXM);
+ }
+ 
+ static void
+@@ -926,7 +926,7 @@ add_flow_mod(struct ofputil_flow_mod *fm, struct ovs_list *msgs)
+ static struct ofpbuf *
+ encode_group_mod(const struct ofputil_group_mod *gm)
+ {
+-    return ofputil_encode_group_mod(OFP13_VERSION, gm, NULL, -1);
++    return ofputil_encode_group_mod(OFP15_VERSION, gm, NULL, -1);
+ }
+ 
+ static void
+@@ -940,7 +940,7 @@ add_group_mod(const struct ofputil_group_mod *gm, struct ovs_list *msgs)
+ static struct ofpbuf *
+ encode_meter_mod(const struct ofputil_meter_mod *mm)
+ {
+-    return ofputil_encode_meter_mod(OFP13_VERSION, mm);
++    return ofputil_encode_meter_mod(OFP15_VERSION, mm);
+ }
+ 
+ static void
+@@ -1281,7 +1281,7 @@ ofctrl_put(struct ovn_desired_flow_table *flow_table,
+ 
+     if (!ovs_list_is_empty(&msgs)) {
+         /* Add a barrier to the list of messages. */
+-        struct ofpbuf *barrier = ofputil_encode_barrier_request(OFP13_VERSION);
++        struct ofpbuf *barrier = ofputil_encode_barrier_request(OFP15_VERSION);
+         const struct ofp_header *oh = barrier->data;
+         ovs_be32 xid_ = oh->xid;
+         ovs_list_push_back(&msgs, &barrier->list_node);
+diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c
+index 6ff897325..a2d92429c 100644
+--- a/controller/ovn-controller.c
++++ b/controller/ovn-controller.c
+@@ -2297,7 +2297,7 @@ parse_options(int argc, char *argv[])
+             usage();
+ 
+         case 'V':
+-            ovs_print_version(OFP13_VERSION, OFP13_VERSION);
++            ovs_print_version(OFP15_VERSION, OFP15_VERSION);
+             exit(EXIT_SUCCESS);
+ 
+         VLOG_OPTION_HANDLERS
+diff --git a/controller/pinctrl.c b/controller/pinctrl.c
+index 9d5b7c3c0..6b0ac3483 100644
+--- a/controller/pinctrl.c
++++ b/controller/pinctrl.c
+@@ -2805,7 +2805,7 @@ pinctrl_handler(void *arg_)
+     static long long int svc_monitors_next_run_time = LLONG_MAX;
+     static long long int send_prefixd_time = LLONG_MAX;
+ 
+-    swconn = rconn_create(5, 0, DSCP_DEFAULT, 1 << OFP13_VERSION);
++    swconn = rconn_create(5, 0, DSCP_DEFAULT, 1 << OFP15_VERSION);
+ 
+     while (!latch_is_set(&pctrl->pinctrl_thread_exit)) {
+         if (pctrl->br_int_name) {
+diff --git a/lib/actions.c b/lib/actions.c
+index 2dba9a922..605dbffe4 100644
+--- a/lib/actions.c
++++ b/lib/actions.c
+@@ -1457,7 +1457,7 @@ encode_nested_actions(const struct ovnact_nest *on,
+     size_t oc_offset = encode_start_controller_op(opcode, false,
+                                                   NX_CTLR_NO_METER, ofpacts);
+     ofpacts_put_openflow_actions(inner_ofpacts.data, inner_ofpacts.size,
+-                                 ofpacts, OFP13_VERSION);
++                                 ofpacts, OFP15_VERSION);
+     encode_finish_controller_op(oc_offset, ofpacts);
+ 
+     /* Free memory. */
+@@ -2260,7 +2260,7 @@ encode_PUT_DHCPV4_OPTS(const struct ovnact_put_opts *pdo,
+     size_t oc_offset = encode_start_controller_op(ACTION_OPCODE_PUT_DHCP_OPTS,
+                                                   true, NX_CTLR_NO_METER,
+                                                   ofpacts);
+-    nx_put_header(ofpacts, dst.field->id, OFP13_VERSION, false);
++    nx_put_header(ofpacts, dst.field->id, OFP15_VERSION, false);
+     ovs_be32 ofs = htonl(dst.ofs);
+     ofpbuf_put(ofpacts, &ofs, sizeof ofs);
+ 
+@@ -2291,7 +2291,7 @@ encode_PUT_DHCPV6_OPTS(const struct ovnact_put_opts *pdo,
+ 
+     size_t oc_offset = encode_start_controller_op(
+         ACTION_OPCODE_PUT_DHCPV6_OPTS, true, NX_CTLR_NO_METER, ofpacts);
+-    nx_put_header(ofpacts, dst.field->id, OFP13_VERSION, false);
++    nx_put_header(ofpacts, dst.field->id, OFP15_VERSION, false);
+     ovs_be32 ofs = htonl(dst.ofs);
+     ofpbuf_put(ofpacts, &ofs, sizeof ofs);
+ 
+@@ -2401,7 +2401,7 @@ encode_DNS_LOOKUP(const struct ovnact_dns_lookup *dl,
+     size_t oc_offset = encode_start_controller_op(ACTION_OPCODE_DNS_LOOKUP,
+                                                   true, NX_CTLR_NO_METER,
+                                                   ofpacts);
+-    nx_put_header(ofpacts, dst.field->id, OFP13_VERSION, false);
++    nx_put_header(ofpacts, dst.field->id, OFP15_VERSION, false);
+     ovs_be32 ofs = htonl(dst.ofs);
+     ofpbuf_put(ofpacts, &ofs, sizeof ofs);
+     encode_finish_controller_op(oc_offset, ofpacts);
+@@ -2565,7 +2565,7 @@ encode_PUT_ND_RA_OPTS(const struct ovnact_put_opts *po,
+ 
+     size_t oc_offset = encode_start_controller_op(
+         ACTION_OPCODE_PUT_ND_RA_OPTS, true, NX_CTLR_NO_METER, ofpacts);
+-    nx_put_header(ofpacts, dst.field->id, OFP13_VERSION, false);
++    nx_put_header(ofpacts, dst.field->id, OFP15_VERSION, false);
+     ovs_be32 ofs = htonl(dst.ofs);
+     ofpbuf_put(ofpacts, &ofs, sizeof ofs);
+ 
+diff --git a/lib/expr.c b/lib/expr.c
+index 78646a1af..078d17840 100644
+--- a/lib/expr.c
++++ b/lib/expr.c
+@@ -1414,7 +1414,7 @@ expr_symbol_format(const struct expr_symbol *symbol, struct ds *s)
+     } else if (symbol->ovn_field) {
+         ds_put_cstr(s, symbol->name);
+     } else {
+-        nx_format_field_name(symbol->field->id, OFP13_VERSION, s);
++        nx_format_field_name(symbol->field->id, OFP15_VERSION, s);
+     }
+ }
+ 
+diff --git a/tests/ovn.at b/tests/ovn.at
+index 35415f2b6..5fb100ad4 100644
+--- a/tests/ovn.at
++++ b/tests/ovn.at
+@@ -1186,7 +1186,7 @@ reg1[0] = put_dhcp_opts(offerip=1.2.3.4, domain_name=1.2.3.4);
+ 
+ # nd_ns
+ nd_ns { nd.target = xxreg0; output; };
+-    encodes as controller(userdata=00.00.00.09.00.00.00.00.ff.ff.00.18.00.00.23.20.00.06.00.80.00.00.00.00.00.01.de.10.00.01.2e.10.ff.ff.00.10.00.00.23.20.00.0e.ff.f8.40.00.00.00)
++    encodes as controller(userdata=00.00.00.09.00.00.00.00.00.1c.00.18.00.80.00.00.00.00.00.00.00.01.de.10.80.00.3e.10.00.00.00.00.ff.ff.00.10.00.00.23.20.00.0e.ff.f8.40.00.00.00)
+     has prereqs ip6
+ 
+ nd_ns { };
+@@ -1197,12 +1197,12 @@ nd_ns { };
+ # nd_na
+ nd_na { eth.src = 12:34:56:78:9a:bc; nd.tll = 12:34:56:78:9a:bc; outport = inport; inport = ""; /* Allow sending out inport. */ output; };
+     formats as nd_na { eth.src = 12:34:56:78:9a:bc; nd.tll = 12:34:56:78:9a:bc; outport = inport; inport = ""; output; };
+-    encodes as controller(userdata=00.00.00.03.00.00.00.00.00.19.00.10.80.00.08.06.12.34.56.78.9a.bc.00.00.00.19.00.10.80.00.42.06.12.34.56.78.9a.bc.00.00.ff.ff.00.18.00.00.23.20.00.06.00.20.00.00.00.00.00.01.1c.04.00.01.1e.04.00.19.00.10.00.01.1c.04.00.00.00.00.00.00.00.00.ff.ff.00.10.00.00.23.20.00.0e.ff.f8.40.00.00.00)
++    encodes as controller(userdata=00.00.00.03.00.00.00.00.00.19.00.10.80.00.08.06.12.34.56.78.9a.bc.00.00.00.19.00.10.80.00.42.06.12.34.56.78.9a.bc.00.00.00.1c.00.18.00.20.00.00.00.00.00.00.00.01.1c.04.00.01.1e.04.00.00.00.00.00.19.00.10.00.01.1c.04.00.00.00.00.00.00.00.00.ff.ff.00.10.00.00.23.20.00.0e.ff.f8.40.00.00.00)
+     has prereqs nd_ns
+ # nd_na_router
+ nd_na_router { eth.src = 12:34:56:78:9a:bc; nd.tll = 12:34:56:78:9a:bc; outport = inport; inport = ""; /* Allow sending out inport. */ output; };
+     formats as nd_na_router { eth.src = 12:34:56:78:9a:bc; nd.tll = 12:34:56:78:9a:bc; outport = inport; inport = ""; output; };
+-    encodes as controller(userdata=00.00.00.0c.00.00.00.00.00.19.00.10.80.00.08.06.12.34.56.78.9a.bc.00.00.00.19.00.10.80.00.42.06.12.34.56.78.9a.bc.00.00.ff.ff.00.18.00.00.23.20.00.06.00.20.00.00.00.00.00.01.1c.04.00.01.1e.04.00.19.00.10.00.01.1c.04.00.00.00.00.00.00.00.00.ff.ff.00.10.00.00.23.20.00.0e.ff.f8.40.00.00.00)
++    encodes as controller(userdata=00.00.00.0c.00.00.00.00.00.19.00.10.80.00.08.06.12.34.56.78.9a.bc.00.00.00.19.00.10.80.00.42.06.12.34.56.78.9a.bc.00.00.00.1c.00.18.00.20.00.00.00.00.00.00.00.01.1c.04.00.01.1e.04.00.00.00.00.00.19.00.10.00.01.1c.04.00.00.00.00.00.00.00.00.ff.ff.00.10.00.00.23.20.00.0e.ff.f8.40.00.00.00)
+     has prereqs nd_ns
+ 
+ # get_nd
+diff --git a/utilities/ovn-sbctl.c b/utilities/ovn-sbctl.c
+index d8bb3dcbc..04e082c70 100644
+--- a/utilities/ovn-sbctl.c
++++ b/utilities/ovn-sbctl.c
+@@ -795,7 +795,7 @@ sbctl_open_vconn(struct shash *options)
+ 
+     char *remote = ovs->data ? xstrdup(ovs->data) : default_ovs();
+     struct vconn *vconn;
+-    int retval = vconn_open_block(remote, 1 << OFP13_VERSION, 0, -1, &vconn);
++    int retval = vconn_open_block(remote, 1 << OFP15_VERSION, 0, -1, &vconn);
+     if (retval) {
+         VLOG_WARN("%s: connection failed (%s)", remote, ovs_strerror(retval));
+     }
+@@ -816,7 +816,7 @@ sbctl_dump_openflow(struct vconn *vconn, const struct uuid *uuid, bool stats)
+ 
+     struct ofputil_flow_stats *fses;
+     size_t n_fses;
+-    int error = vconn_dump_flows(vconn, &fsr, OFPUTIL_P_OF13_OXM,
++    int error = vconn_dump_flows(vconn, &fsr, OFPUTIL_P_OF15_OXM,
+                                  &fses, &n_fses);
+     if (error) {
+         VLOG_WARN("%s: error obtaining flow stats (%s)",
+diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c
+index c9d72285c..d7251e7ed 100644
+--- a/utilities/ovn-trace.c
++++ b/utilities/ovn-trace.c
+@@ -2326,7 +2326,7 @@ trace_openflow(const struct ovntrace_flow *f, struct ovs_list *super)
+ 
+     struct ofputil_flow_stats *fses;
+     size_t n_fses;
+-    int error = vconn_dump_flows(vconn, &fsr, OFPUTIL_P_OF13_OXM,
++    int error = vconn_dump_flows(vconn, &fsr, OFPUTIL_P_OF15_OXM,
+                                  &fses, &n_fses);
+     if (error) {
+         ovntrace_node_append(super, OVNTRACE_NODE_ERROR,
+@@ -2435,7 +2435,7 @@ trace(const char *dp_s, const char *flow_s)
+     ds_put_char(&output, '\n');
+ 
+     if (ovs) {
+-        int retval = vconn_open_block(ovs, 1 << OFP13_VERSION, 0, -1, &vconn);
++        int retval = vconn_open_block(ovs, 1 << OFP15_VERSION, 0, -1, &vconn);
+         if (retval) {
+             VLOG_WARN("%s: connection failed (%s)", ovs, ovs_strerror(retval));
+         }
+-- 
+2.26.2
+
diff --git a/SOURCES/0001-controller-use-LLA-IPv6-address-as-NS-source-address.patch b/SOURCES/0001-controller-use-LLA-IPv6-address-as-NS-source-address.patch
new file mode 100644
index 0000000..091ee2d
--- /dev/null
+++ b/SOURCES/0001-controller-use-LLA-IPv6-address-as-NS-source-address.patch
@@ -0,0 +1,105 @@
+From 7f60417ae6c7438565a21d5aee0bb8ae0b3a9b68 Mon Sep 17 00:00:00 2001
+Message-Id: <7f60417ae6c7438565a21d5aee0bb8ae0b3a9b68.1585835882.git.me@lorenzobianconi.net>
+From: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
+Date: Tue, 24 Mar 2020 20:33:27 +0100
+Subject: [PATCH] controller: use LLA IPv6 address as NS source address
+
+Use router LLA IPv6 address as IPv6 source address for Neighbor
+Solicitation packets
+
+Fixes: c0bf32d72 ("Manage ARP process locally in a DVR scenario")
+Change-Id: Iafa26f4b3c20e181bd5b54a357d468ce61b589b6
+Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
+Signed-off-by: Numan Siddique <numans@ovn.org>
+Signed-off-by: Lorenzo Bianconi <me@lorenzobianconi.net>
+---
+ controller/pinctrl.c |  4 +++-
+ tests/ovn.at         | 15 +++++++++------
+ 2 files changed, 12 insertions(+), 7 deletions(-)
+
+--- a/controller/pinctrl.c
++++ b/controller/pinctrl.c
+@@ -4563,9 +4563,11 @@ pinctrl_handle_nd_ns(struct rconn *swcon
+ 
+     uint64_t packet_stub[128 / 8];
+     struct dp_packet packet;
++    struct in6_addr ipv6_src;
+     dp_packet_use_stub(&packet, packet_stub, sizeof packet_stub);
+ 
+-    compose_nd_ns(&packet, ip_flow->dl_src, &ip_flow->ipv6_src,
++    in6_generate_lla(ip_flow->dl_src, &ipv6_src);
++    compose_nd_ns(&packet, ip_flow->dl_src, &ipv6_src,
+                   &ip_flow->ipv6_dst);
+ 
+     /* Reload previous packet metadata and set actions from userdata. */
+--- a/tests/ovn.at
++++ b/tests/ovn.at
+@@ -11280,13 +11280,13 @@ options:rxq_pcap=${pcap_file}-rx.pcap
+ # This function sends ipv6 packet
+ test_ipv6() {
+     local inport=$1 src_mac=$2 dst_mac=$3 src_ip=$4 dst_ip=$5
+-    local dst_mcast_mac=$6 mcast_node_ip=$7 nd_target=$8
++    local dst_mcast_mac=$6 mcast_node_ip=$7 nd_target=$8 nd_src_ip=$9
+ 
+     local packet=${dst_mac}${src_mac}86dd6000000000083aff${src_ip}${dst_ip}
+     packet=${packet}8000000000000000
+ 
+     src_mac=000002010204
+-    expected_packet=${dst_mcast_mac}${src_mac}86dd6000000000203aff${src_ip}
++    expected_packet=${dst_mcast_mac}${src_mac}86dd6000000000203aff${nd_src_ip}
+     expected_packet=${expected_packet}${mcast_node_ip}8700XXXX00000000
+     expected_packet=${expected_packet}${nd_target}0101${src_mac}
+ 
+@@ -11298,6 +11298,7 @@ test_ipv6() {
+ src_mac=506400000002
+ dst_mac=00000000af01
+ src_ip=aef0000000000000526400fffe000002
++nd_src_ip=fe80000000000000020002fffe010204
+ dst_ip=20010db800010000020002fffe010205
+ dst_mcast_mac=3333ff010205
+ mcast_node_ip=ff0200000000000000000001ff010205
+@@ -11305,7 +11306,7 @@ nd_target=20010db800010000020002fffe0102
+ # Send an IPv6 packet. Generated IPv6 Neighbor solicitation packet
+ # should be received by the ports attached to br-phys.
+ test_ipv6 1 $src_mac $dst_mac $src_ip $dst_ip $dst_mcast_mac \
+-$mcast_node_ip $nd_target
++$mcast_node_ip $nd_target $nd_src_ip
+ 
+ OVS_WAIT_WHILE([test 24 = $(wc -c hv1/br-phys_n1-tx.pcap | cut -d " " -f1)])
+ OVS_WAIT_WHILE([test 24 = $(wc -c hv1/br-phys-tx.pcap | cut -d " " -f1)])
+@@ -11338,7 +11339,7 @@ dst_mcast_mac=3333ff011305
+ mcast_node_ip=ff0200000000000000000001ff011305
+ nd_target=20010db800010000020002fffe011305
+ test_ipv6 1 $src_mac $dst_mac $src_ip $dst_ip $dst_mcast_mac \
+-$mcast_node_ip $nd_target
++$mcast_node_ip $nd_target $nd_src_ip
+ 
+ OVS_WAIT_WHILE([test 24 = $(wc -c hv1/br-phys_n1-tx.pcap | cut -d " " -f1)])
+ OVS_WAIT_WHILE([test 24 = $(wc -c hv1/br-phys-tx.pcap | cut -d " " -f1)])
+@@ -14262,7 +14263,7 @@ send_na() {
+ get_nd() {
+     local eth_src=$1 src_ip=$2 dst_ip=$3 ta=$4
+     local ip6_hdr=6000000000203aff${src_ip}${dst_ip}
+-    request=3333ff000010${eth_src}86dd${ip6_hdr}8700357600000000${ta}0101${eth_src}
++    request=3333ff000010${eth_src}86dd${ip6_hdr}870051f400000000${ta}0101${eth_src}
+ 
+     echo $request
+ }
+@@ -14325,6 +14326,8 @@ router_mac1=000002010203
+ router_ip=$(ip_to_hex 172 16 1 1)
+ router_ip6=20020000000000000000000000000001
+ 
++nd_src_ip6=fe80000000000000020002fffe010203
++
+ dst_mac=001122334455
+ dst_ip=$(ip_to_hex 172 16 1 10)
+ dst_ip6=20020000000000000000000000000010
+@@ -14342,7 +14345,7 @@ nd_ip=ff0200000000000000000001ff000010
+ ip6_hdr=6000000000083afe${src_ip6}${dst_ip6}
+ 
+ send_icmp6_packet 1 1 $src_mac $router_mac0 $src_ip6 $dst_ip6
+-echo $(get_nd $router_mac1 $src_ip6 $nd_ip $dst_ip6) >> expected
++echo $(get_nd $router_mac1 $nd_src_ip6 $nd_ip $dst_ip6) >> expected
+ echo "${dst_mac}${router_mac1}86dd${ip6_hdr}8000dcb662f00001" >> expected
+ send_na 2 1 $dst_mac $router_mac1 $dst_ip6 $router_ip6
+ 
diff --git a/SOURCES/0001-northd-By-pass-IPv6-Router-Adv-and-Router-Solicitati.patch b/SOURCES/0001-northd-By-pass-IPv6-Router-Adv-and-Router-Solicitati.patch
new file mode 100644
index 0000000..2352aab
--- /dev/null
+++ b/SOURCES/0001-northd-By-pass-IPv6-Router-Adv-and-Router-Solicitati.patch
@@ -0,0 +1,65 @@
+From d64f501d787571a50eb2e5380947d1d0a3e2ca74 Mon Sep 17 00:00:00 2001
+From: Numan Siddique <numans@ovn.org>
+Date: Thu, 11 Jun 2020 18:44:41 +0530
+Subject: [PATCH] northd: By pass IPv6 Router Adv and Router Solicitation
+ packets from ACL stages.
+
+We already add below logical flows to by pass IPv6 Neighbor discovery packets
+from in/out ACL stage.
+
+table=6 (ls_in_acl          ), priority=65535, match=(nd), action=(next;)
+table=4 (ls_out_acl         ), priority=65535, match=(nd), action=(next;)
+
+This patch also adds nd_rs and nd_ra to these logical flows. Without these
+the IPv6 Router Adv packets generated by ovn-controller are dropped if
+CMS has configured ACLs.
+
+Reported-by: Jakub Libosvar <jlibosva@redhat.com>
+Signed-off-by: Numan Siddique <numans@ovn.org>
+Acked-by: Mark Michelson <mmichels@redhat.com>
+
+(cherry-picked from upstream master commit 90e5971018277ab0f383a56f59ffcfe17466a2c6)
+
+Change-Id: I33fcb3032fe946f2b2333a8cf2791af75dceaf44
+---
+ northd/ovn-northd.8.xml | 6 ++++++
+ northd/ovn-northd.c     | 6 ++++--
+ 2 files changed, 10 insertions(+), 2 deletions(-)
+
+diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
+index dc56de273..081536ab4 100644
+--- a/northd/ovn-northd.8.xml
++++ b/northd/ovn-northd.8.xml
+@@ -439,6 +439,12 @@
+         ACL re-allow this connection.
+       </li>
+ 
++      <li>
++        A priority-65535 flow that allows IPv6 Neighbor solicitation,
++        Neighbor discover, Router solicitation and Router advertisement
++        packets.
++      </li>
++
+       <li>
+         A priority 34000 logical flow is added for each logical switch datapath
+         with the match <code>eth.dst = <var>E</var></code> to allow the service
+diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
+index cffe3de17..fc250318f 100644
+--- a/northd/ovn-northd.c
++++ b/northd/ovn-northd.c
+@@ -5390,8 +5390,10 @@ build_acls(struct ovn_datapath *od, struct hmap *lflows,
+         /* Ingress and Egress ACL Table (Priority 65535).
+          *
+          * Not to do conntrack on ND packets. */
+-        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX, "nd", "next;");
+-        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX, "nd", "next;");
++        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX,
++                      "nd || nd_ra || nd_rs", "next;");
++        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX,
++                      "nd || nd_ra || nd_rs", "next;");
+     }
+ 
+     /* Ingress or Egress ACL Table (Various priorities). */
+-- 
+2.26.2
+
diff --git a/SOURCES/0001-northd-do-not-insert-identical-lflows-in-S_ROUTER_IN.patch b/SOURCES/0001-northd-do-not-insert-identical-lflows-in-S_ROUTER_IN.patch
new file mode 100644
index 0000000..d000815
--- /dev/null
+++ b/SOURCES/0001-northd-do-not-insert-identical-lflows-in-S_ROUTER_IN.patch
@@ -0,0 +1,85 @@
+From 5f3e15c3d5809134d70892b4f65031e5bd110c8f Mon Sep 17 00:00:00 2001
+From: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
+Date: Wed, 11 Mar 2020 17:41:59 +0100
+Subject: [PATCH 1/2] northd: do not insert identical lflows in
+ S_ROUTER_IN_ARP_RESOLVE
+
+Avoid to configure multiple identical logical flows in
+S_ROUTER_IN_ARP_RESOLVE stage. This can happen adding L2 destination
+address info about snat since multiple nat entries will use the same
+external_ip
+
+Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
+Signed-off-by: Numan Siddique <numans@ovn.org>
+
+(cherry picked from upstream OVS branch20.03 commit 20aa8c3c5a1930805a32ec8121affa07b2ac7dff)
+
+Change-Id: Ic5c1df529363469092a55454fdfbcae31a06ccf5
+---
+ northd/ovn-northd.c | 36 ++++++++++++++++++++++--------------
+ 1 file changed, 22 insertions(+), 14 deletions(-)
+
+diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
+index 787ca2f80..cdaeff401 100644
+--- a/northd/ovn-northd.c
++++ b/northd/ovn-northd.c
+@@ -8630,6 +8630,8 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
+             continue;
+         }
+ 
++        struct sset nat_entries = SSET_INITIALIZER(&nat_entries);
++
+         struct v46_ip snat_ip, lb_snat_ip;
+         const char *dnat_force_snat_ip = get_force_snat_ip(od, "dnat",
+                                                            &snat_ip);
+@@ -8855,20 +8857,24 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
+                                             &nat->header_);
+                 }
+ 
+-                ds_clear(&match);
+-                ds_put_format(
+-                    &match, "outport == %s && %s == %s",
+-                    od->l3dgw_port->json_key,
+-                    is_v6 ? "xxreg0" : "reg0", nat->external_ip);
+-                ds_clear(&actions);
+-                ds_put_format(
+-                    &actions, "eth.dst = %s; next;",
+-                    distributed ? nat->external_mac :
+-                    od->l3dgw_port->lrp_networks.ea_s);
+-                ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ARP_RESOLVE,
+-                                        100, ds_cstr(&match),
+-                                        ds_cstr(&actions),
+-                                        &nat->header_);
++                if (!sset_contains(&nat_entries, nat->external_ip)) {
++                    ds_clear(&match);
++                    ds_put_format(
++                        &match, "outport == %s && %s == %s",
++                        od->l3dgw_port->json_key,
++                        is_v6 ? "xxreg0" : "reg0", nat->external_ip);
++                    ds_clear(&actions);
++                    ds_put_format(
++                        &actions, "eth.dst = %s; next;",
++                        distributed ? nat->external_mac :
++                        od->l3dgw_port->lrp_networks.ea_s);
++                    ovn_lflow_add_with_hint(lflows, od,
++                                            S_ROUTER_IN_ARP_RESOLVE,
++                                            100, ds_cstr(&match),
++                                            ds_cstr(&actions),
++                                            &nat->header_);
++                    sset_add(&nat_entries, nat->external_ip);
++                }
+             }
+ 
+             /* Egress UNDNAT table: It is for already established connections'
+@@ -9049,6 +9055,8 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
+             }
+         }
+ 
++        sset_destroy(&nat_entries);
++
+         /* Handle force SNAT options set in the gateway router. */
+         if (dnat_force_snat_ip && !od->l3dgw_port) {
+             /* If a packet with destination IP address as that of the
+-- 
+2.25.1
+
diff --git a/SOURCES/0001-ofctrl-Split-large-group_mod-messages-up.patch b/SOURCES/0001-ofctrl-Split-large-group_mod-messages-up.patch
new file mode 100644
index 0000000..6f7f2ec
--- /dev/null
+++ b/SOURCES/0001-ofctrl-Split-large-group_mod-messages-up.patch
@@ -0,0 +1,161 @@
+From 88056d15bffe67c033322de16c01a013e7bc7c7c Mon Sep 17 00:00:00 2001
+From: Mark Michelson <mmichels@redhat.com>
+Date: Wed, 6 May 2020 09:49:55 -0400
+Subject: [PATCH] ofctrl: Split large group_mod messages up.
+
+Group mod messages have the possibility of growing very large if OVN
+installs a load balancer with a great many backends. The current
+approach is to send a single ADD message with the entire group contents.
+If the size of this message exceeds UINT16_MAX, then OpenFlow cannot
+properly express the length of the message since the OpenFlow header's
+length is limited to 16 bits.
+
+This patch solves the problem by breaking the message into pieces. The
+first piece is an ADD, and subsequent messages are INSERT_BUCKET
+messages. This way, we end up being able to express the entire size of
+the group through multiple OpenFlow messages.
+
+Signed-off-by: Mark Michelson <mmichels@redhat.com>
+Acked-by: Numan Siddique <numans@ovn.org>
+---
+ controller/ofctrl.c | 70 ++++++++++++++++++++++++++++++++++++++++++---
+ tests/ovn.at        | 29 +++++++++++++++++++
+ 2 files changed, 95 insertions(+), 4 deletions(-)
+
+diff --git a/controller/ofctrl.c b/controller/ofctrl.c
+index 4b51cd86e..073e076c7 100644
+--- a/controller/ofctrl.c
++++ b/controller/ofctrl.c
+@@ -930,10 +930,72 @@ encode_group_mod(const struct ofputil_group_mod *gm)
+ }
+ 
+ static void
+-add_group_mod(const struct ofputil_group_mod *gm, struct ovs_list *msgs)
++add_group_mod(struct ofputil_group_mod *gm, struct ovs_list *msgs)
+ {
+     struct ofpbuf *msg = encode_group_mod(gm);
+-    ovs_list_push_back(msgs, &msg->list_node);
++    if (msg->size <= UINT16_MAX) {
++        ovs_list_push_back(msgs, &msg->list_node);
++        return;
++    }
++    /* This group mod request is too large to fit in a single OF message
++     * since the header can only specify a 16-bit size. We need to break
++     * this into multiple group_mod requests.
++     */
++
++    /* Pull the first bucket. All buckets are approximately the same length
++     * since they contain near-identical actions. Using its length can give
++     * us a good approximation of how many buckets we can fit in a single
++     * OF message.
++     */
++    ofpraw_pull_assert(msg);
++    struct ofp15_group_mod *ogm = ofpbuf_pull(msg, sizeof(*ogm));
++    struct ofp15_bucket *of_bucket = ofpbuf_pull(msg, sizeof(*of_bucket));
++    uint16_t bucket_size = ntohs(of_bucket->len);
++
++    ofpbuf_delete(msg);
++
++    /* Dividing by 2 here ensures that just in case there are variations in
++     * the size of the buckets, we will not put too many in our new group_mod
++     * message.
++     */
++    size_t max_buckets = ((UINT16_MAX - sizeof *ogm) / bucket_size) / 2;
++
++    ovs_assert(max_buckets < ovs_list_size(&gm->buckets));
++
++    uint16_t command = OFPGC15_INSERT_BUCKET;
++    if (gm->command == OFPGC15_DELETE ||
++        gm->command == OFPGC15_REMOVE_BUCKET) {
++        command = OFPGC15_REMOVE_BUCKET;
++    }
++    struct ofputil_group_mod split = {
++        .command = command,
++        .type = gm->type,
++        .group_id = gm->group_id,
++        .command_bucket_id = OFPG15_BUCKET_LAST,
++    };
++    ovs_list_init(&split.buckets);
++
++    size_t i = 0;
++    struct ofputil_bucket *bucket;
++    LIST_FOR_EACH (bucket, list_node, &gm->buckets) {
++        if (i++ < max_buckets) {
++            continue;
++        }
++        break;
++    }
++
++    ovs_list_splice(&split.buckets, &bucket->list_node, &gm->buckets);
++
++    struct ofpbuf *orig = encode_group_mod(gm);
++    ovs_list_push_back(msgs, &orig->list_node);
++
++    /* We call this recursively just in case our new
++     * INSERT_BUCKET/REMOVE_BUCKET group_mod is still too
++     * large for an OF message. This will allow for it to
++     * be broken into pieces, too.
++     */
++    add_group_mod(&split, msgs);
++    ofputil_uninit_group_mod(&split);
+ }
+ 
+ 
+@@ -1124,7 +1186,7 @@ ofctrl_put(struct ovn_desired_flow_table *flow_table,
+         char *group_string = xasprintf("group_id=%"PRIu32",%s",
+                                        desired->table_id,
+                                        desired->name);
+-        char *error = parse_ofp_group_mod_str(&gm, OFPGC11_ADD, group_string,
++        char *error = parse_ofp_group_mod_str(&gm, OFPGC15_ADD, group_string,
+                                               NULL, NULL, &usable_protocols);
+         if (!error) {
+             add_group_mod(&gm, &msgs);
+@@ -1243,7 +1305,7 @@ ofctrl_put(struct ovn_desired_flow_table *flow_table,
+         enum ofputil_protocol usable_protocols;
+         char *group_string = xasprintf("group_id=%"PRIu32"",
+                                        installed->table_id);
+-        char *error = parse_ofp_group_mod_str(&gm, OFPGC11_DELETE,
++        char *error = parse_ofp_group_mod_str(&gm, OFPGC15_DELETE,
+                                               group_string, NULL, NULL,
+                                               &usable_protocols);
+         if (!error) {
+diff --git a/tests/ovn.at b/tests/ovn.at
+index 52d994972..f39fda2e4 100644
+--- a/tests/ovn.at
++++ b/tests/ovn.at
+@@ -19179,3 +19179,32 @@ OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [expected])
+ 
+ OVN_CLEANUP([hv1])
+ AT_CLEANUP
++
++AT_SETUP([ovn -- Big Load Balancer])
++ovn_start
++
++ovn-nbctl ls-add ls1
++ovn-nbctl lsp-add ls1 lsp1
++
++net_add n1
++sim_add hv1
++
++as hv1
++ovs-vsctl add-br br-phys
++ovn_attach n1 br-phys 192.168.0.1
++ovs-vsctl add-port br-int p1 -- set Interface p1 external-ids:iface-id=lsp1
++
++IPS=192.169.0.1:80
++for i in `seq 1 9` ; do
++    for j in `seq 1 254` ; do
++        IPS=${IPS},192.169.$i.$j:80
++    done
++done
++
++ovn-nbctl lb-add lb0 172.172.0.1:8080 "${IPS}"
++ovn-nbctl --wait=hv ls-lb-add ls1 lb0
++
++AT_CHECK([test 2287 = `ovs-ofctl dump-group-stats br-int | grep -o bucket | wc -l`])
++
++OVN_CLEANUP([hv1])
++AT_CLEANUP
+-- 
+2.25.4
+
diff --git a/SOURCES/0001-ovn-controller-Fix-potential-segfault-with-virtual-p.patch b/SOURCES/0001-ovn-controller-Fix-potential-segfault-with-virtual-p.patch
new file mode 100644
index 0000000..34b4c29
--- /dev/null
+++ b/SOURCES/0001-ovn-controller-Fix-potential-segfault-with-virtual-p.patch
@@ -0,0 +1,104 @@
+From 08dfddbe4b1559dd91747cee435eb8945555b348 Mon Sep 17 00:00:00 2001
+From: Dumitru Ceara <dceara@redhat.com>
+Date: Tue, 31 Mar 2020 13:47:04 +0200
+Subject: [PATCH] ovn-controller: Fix potential segfault with "virtual" port
+ bindings.
+
+Even though ovn-controller tries to set port_binding->chassis to NULL
+every time port_binding->virtual_parent is set to NULL for bindings of
+type="virtual", there's no way to enforce that an operator doesn't
+manually clear the "virtual_parent" column in the Southbound database.
+
+In such scenario ovn-controller would crash because of trying to
+dereference the NULL port_binding->virtual_parent column.
+
+Add an extra check and release "virtual" port bindings that have
+"virtual_parent" NULL.
+
+Reported-at: https://bugzilla.redhat.com/1818844
+CC: Numan Siddique <nusiddiq@redhat.com>
+Fixes: 054f4c85c413 ("Add a new logical switch port type - 'virtual'")
+Signed-off-by: Dumitru Ceara <dceara@redhat.com>
+Signed-off-by: Numan Siddique <numans@ovn.org>
+(cherry picked from upstream commit 5b3e9879be2b6c9b07ed5c9e073f1c24080a49f7)
+
+Change-Id: I10c2a8dd3731b34f606c4fa2db42711c81f431cc
+---
+ controller/binding.c | 26 +++++++++++++++-----------
+ tests/ovn.at         | 18 ++++++++++++++++++
+ 2 files changed, 33 insertions(+), 11 deletions(-)
+
+diff --git a/controller/binding.c b/controller/binding.c
+index c3376e2..5ea12a8 100644
+--- a/controller/binding.c
++++ b/controller/binding.c
+@@ -625,22 +625,26 @@ consider_local_virtual_port(struct ovsdb_idl_index *sbrec_port_binding_by_name,
+                             const struct sbrec_chassis *chassis_rec,
+                             const struct sbrec_port_binding *binding_rec)
+ {
++    if (binding_rec->virtual_parent) {
++        const struct sbrec_port_binding *parent =
++            lport_lookup_by_name(sbrec_port_binding_by_name,
++                                 binding_rec->virtual_parent);
++        if (parent && parent->chassis == chassis_rec) {
++            return;
++        }
++    }
++
+     /* pinctrl module takes care of binding the ports of type 'virtual'.
+      * Release such ports if their virtual parents are no longer claimed by
+      * this chassis.
+      */
+-    const struct sbrec_port_binding *parent =
+-        lport_lookup_by_name(sbrec_port_binding_by_name,
+-                             binding_rec->virtual_parent);
+-    if (!parent || parent->chassis != chassis_rec) {
+-        VLOG_INFO("Releasing lport %s from this chassis.",
+-                  binding_rec->logical_port);
+-        if (binding_rec->encap) {
+-            sbrec_port_binding_set_encap(binding_rec, NULL);
+-        }
+-        sbrec_port_binding_set_chassis(binding_rec, NULL);
+-        sbrec_port_binding_set_virtual_parent(binding_rec, NULL);
++    VLOG_INFO("Releasing lport %s from this chassis.",
++              binding_rec->logical_port);
++    if (binding_rec->encap) {
++        sbrec_port_binding_set_encap(binding_rec, NULL);
+     }
++    sbrec_port_binding_set_chassis(binding_rec, NULL);
++    sbrec_port_binding_set_virtual_parent(binding_rec, NULL);
+ }
+ 
+ static void
+diff --git a/tests/ovn.at b/tests/ovn.at
+index 9a44f0a..1402fae 100644
+--- a/tests/ovn.at
++++ b/tests/ovn.at
+@@ -15007,6 +15007,24 @@ AT_CHECK([cat lflows.txt], [0], [dnl
+   table=12(lr_in_arp_resolve  ), priority=100  , match=(outport == "lr0-sw0" && reg0 == 10.0.0.10), action=(eth.dst = 50:54:00:00:00:03; next;)
+ ])
+ 
++# Forcibly clear virtual_parent. ovn-controller should release the binding
++# gracefully.
++pb_uuid=$(ovn-sbctl --bare --columns _uuid find port_binding logical_port=sw0-vir)
++ovn-sbctl clear port_binding $pb_uuid virtual_parent
++
++OVS_WAIT_UNTIL([test x$(ovn-sbctl --bare --columns chassis find port_binding \
++logical_port=sw0-vir) = x])
++
++# From sw0-p0 resend GARP for 10.0.0.10. hv1 should reclaim sw0-vir
++# and sw0-p1 should be its virtual_parent.
++send_garp 1 1 $eth_src $eth_dst $spa $tpa
++
++OVS_WAIT_UNTIL([test x$(ovn-sbctl --bare --columns chassis find port_binding \
++logical_port=sw0-vir) = x$hv1_ch_uuid], [0], [])
++
++AT_CHECK([test x$(ovn-sbctl --bare --columns virtual_parent find port_binding \
++logical_port=sw0-vir) = xsw0-p1])
++
+ # From sw0-p3 send GARP for 10.0.0.10. hv1 should claim sw0-vir
+ # and sw0-p3 should be its virtual_parent.
+ eth_src=505400000005
+-- 
+1.8.3.1
+
diff --git a/SOURCES/0001-ovn-controller-Skip-vport-bindings-done-through-OVS-.patch b/SOURCES/0001-ovn-controller-Skip-vport-bindings-done-through-OVS-.patch
new file mode 100644
index 0000000..85088c5
--- /dev/null
+++ b/SOURCES/0001-ovn-controller-Skip-vport-bindings-done-through-OVS-.patch
@@ -0,0 +1,90 @@
+From a8acc52e37d5a74487b0a787bf8a519debc3a031 Mon Sep 17 00:00:00 2001
+From: Dumitru Ceara <dceara@redhat.com>
+Date: Thu, 2 Apr 2020 10:35:32 +0200
+Subject: [PATCH] ovn-controller: Skip vport bindings done through OVS
+ external_ids:iface-id.
+
+Port bindings of type "virtual" should not have an associated OVS port
+in the integration bridge. If this is the case, it's a misconfig and
+ovn-controller should ignore it.
+
+If such a situation is detected, ovn-controller will also log a warning
+message to inform the user about the wrong configuration.
+
+Reported-at: https://bugzilla.redhat.com/1818844
+CC: Numan Siddique <nusiddiq@redhat.com>
+Fixes: 054f4c85c413 ("Add a new logical switch port type - 'virtual'")
+Signed-off-by: Dumitru Ceara <dceara@redhat.com>
+Signed-off-by: Numan Siddique <numans@ovn.org>
+(cherry picked from upstream commit 523b1f5f45682bd6dd454281a97a09c3f429c457)
+
+Change-Id: Ie35818921a6e67c637feaea3be41c59880bb1b96
+---
+ controller/binding.c | 12 ++++++++++++
+ tests/ovn.at         | 20 ++++++++++++++++++++
+ 2 files changed, 32 insertions(+)
+
+diff --git a/controller/binding.c b/controller/binding.c
+index 5ea12a8..20a89d0 100644
+--- a/controller/binding.c
++++ b/controller/binding.c
+@@ -447,6 +447,18 @@ is_our_chassis(const struct sbrec_chassis *chassis_rec,
+     const struct ovsrec_interface *iface_rec
+         = shash_find_data(lport_to_iface, binding_rec->logical_port);
+ 
++    /* Ports of type "virtual" should never be explicitly bound to an OVS
++     * port in the integration bridge. If that's the case, ignore the binding
++     * and log a warning.
++     */
++    if (iface_rec && !strcmp(binding_rec->type, "virtual")) {
++        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
++        VLOG_WARN_RL(&rl,
++                     "Virtual port %s should not be bound to OVS port %s",
++                     binding_rec->logical_port, iface_rec->name);
++        return false;
++    }
++
+     bool our_chassis = false;
+     if (iface_rec
+         || (binding_rec->parent_port && binding_rec->parent_port[0] &&
+diff --git a/tests/ovn.at b/tests/ovn.at
+index 0135838..e8554f6 100644
+--- a/tests/ovn.at
++++ b/tests/ovn.at
+@@ -14894,6 +14894,11 @@ ovs-vsctl -- add-port br-int hv1-vif2 -- \
+     options:tx_pcap=hv1/vif2-tx.pcap \
+     options:rxq_pcap=hv1/vif2-rx.pcap \
+     ofport-request=2
++ovs-vsctl -- add-port br-int hv1-vif3 -- \
++    set interface hv1-vif3 \
++    options:tx_pcap=hv1/vif3-tx.pcap \
++    options:rxq_pcap=hv1/vif3-rx.pcap \
++    ofport-request=3
+ 
+ sim_add hv2
+ as hv2
+@@ -14987,6 +14992,21 @@ logical_port=sw0-vir) = x], [0], [])
+ AT_CHECK([test x$(ovn-sbctl --bare --columns virtual_parent find port_binding \
+ logical_port=sw0-vir) = x])
+ 
++# Try to bind sw0-vir directly to an OVS port. This should be ignored by
++# ovn-controller.
++as hv1
++ovs-vsctl set interface hv1-vif3 external-ids:iface-id=sw0-vir
++
++AT_CHECK([test x$(ovn-sbctl --bare --columns chassis find port_binding \
++logical_port=sw0-vir) = x], [0], [])
++
++# Cleanup hv1-vif3.
++as hv1
++ovs-vsctl del-port hv1-vif3
++
++AT_CHECK([test x$(ovn-sbctl --bare --columns chassis find port_binding \
++logical_port=sw0-vir) = x], [0], [])
++
+ # From sw0-p0 send GARP for 10.0.0.10. hv1 should claim sw0-vir
+ # and sw0-p1 should be its virtual_parent.
+ eth_src=505400000003
+-- 
+1.8.3.1
+
diff --git a/SOURCES/0001-ovn-ctl-Provide-the-option-to-configure-inactive-pro.patch b/SOURCES/0001-ovn-ctl-Provide-the-option-to-configure-inactive-pro.patch
new file mode 100644
index 0000000..8f7266e
--- /dev/null
+++ b/SOURCES/0001-ovn-ctl-Provide-the-option-to-configure-inactive-pro.patch
@@ -0,0 +1,182 @@
+From 1a34ed1dee90ad3ae82d91725bf8f5e86cf007c6 Mon Sep 17 00:00:00 2001
+From: Numan Siddique <numans@ovn.org>
+Date: Mon, 17 Feb 2020 11:23:45 +0530
+Subject: [PATCH] ovn-ctl: Provide the option to configure inactive probe from
+ standby to active.
+
+Recently ovsdb-server supported an unixctl command -
+ovsdb-server/set-active-ovsdb-server-probe-interval to configure inactive probe
+interval from standby connection to the active. This patch provides the
+option to configure this from ovn-ctl and the pacemaker OVN OCF script.
+
+Signed-off-by: Numan Siddique <numans@ovn.org>
+Acked-by: Han Zhou <hzhou@ovn.org>
+---
+ utilities/ovn-ctl           | 14 +++++++++++---
+ utilities/ovn-ctl.8.xml     |  8 ++++++--
+ utilities/ovndb-servers.ocf | 23 +++++++++++++++++++----
+ 3 files changed, 36 insertions(+), 9 deletions(-)
+
+diff --git a/utilities/ovn-ctl b/utilities/ovn-ctl
+index c7cb42bc1..2a337ae27 100755
+--- a/utilities/ovn-ctl
++++ b/utilities/ovn-ctl
+@@ -82,7 +82,8 @@ demote_xx_ovsdb () {
+     local sync_from_proto=$2
+     local sync_from_port=$3
+     local active_conf_file=$4
+-    local ctl_file=$5
++    local inactive_probe_to_active=$5
++    local ctl_file=$6
+ 
+     if test ! -z "$sync_from_addr"; then
+         echo "$sync_from_proto:$sync_from_addr:$sync_from_port" > $active_conf_file
+@@ -91,6 +92,7 @@ demote_xx_ovsdb () {
+     if test -e $active_conf_file; then
+         ovn-appctl -t $OVN_RUNDIR/$ctl_file ovsdb-server/set-active-ovsdb-server `cat $active_conf_file`
+         ovn-appctl -t $OVN_RUNDIR/$ctl_file ovsdb-server/connect-active-ovsdb-server
++        ovn-appctl -t $OVN_RUNDIR/$ctl_file ovsdb-server/set-active-ovsdb-server-probe-interval $inactive_probe_to_active
+     else
+         echo >&2 "$0: active server details not set"
+         exit 1
+@@ -99,12 +101,14 @@ demote_xx_ovsdb () {
+ 
+ demote_ovnnb() {
+     demote_xx_ovsdb $DB_NB_SYNC_FROM_ADDR $DB_NB_SYNC_FROM_PROTO \
+-                    $DB_NB_SYNC_FROM_PORT $ovnnb_active_conf_file ovnnb_db.ctl
++                    $DB_NB_SYNC_FROM_PORT $ovnnb_active_conf_file \
++                    $DB_NB_PROBE_INTERVAL_TO_ACTIVE ovnnb_db.ctl
+ }
+ 
+ demote_ovnsb() {
+     demote_xx_ovsdb $DB_SB_SYNC_FROM_ADDR $DB_SB_SYNC_FROM_PROTO \
+-                    $DB_SB_SYNC_FROM_PORT $ovnsb_active_conf_file ovnsb_db.ctl
++                    $DB_SB_SYNC_FROM_PORT $ovnsb_active_conf_file \
++                    $DB_SB_PROBE_INTERVAL_TO_ACTIVE ovnsb_db.ctl
+ }
+ 
+ demote_ic_nb() {
+@@ -642,6 +646,7 @@ set_defaults () {
+     DB_NB_SYNC_FROM_PROTO=tcp
+     DB_NB_SYNC_FROM_ADDR=
+     DB_NB_SYNC_FROM_PORT=6641
++    DB_NB_PROBE_INTERVAL_TO_ACTIVE=60000
+ 
+     DB_SB_SOCK=$OVN_RUNDIR/ovnsb_db.sock
+     DB_SB_PID=$OVN_RUNDIR/ovnsb_db.pid
+@@ -652,6 +657,7 @@ set_defaults () {
+     DB_SB_SYNC_FROM_PROTO=tcp
+     DB_SB_SYNC_FROM_ADDR=
+     DB_SB_SYNC_FROM_PORT=6642
++    DB_SB_PROBE_INTERVAL_TO_ACTIVE=60000
+ 
+     DB_IC_NB_SOCK=$OVN_RUNDIR/ovn_ic_nb_db.sock
+     DB_IC_NB_PID=$OVN_RUNDIR/ovn_ic_nb_db.pid
+@@ -923,10 +929,12 @@ File location options:
+   --db-nb-sync-from-port=PORT OVN Northbound active db tcp port (default: $DB_NB_SYNC_FROM_PORT)
+   --db-nb-sync-from-proto=PROTO OVN Northbound active db transport (default: $DB_NB_SYNC_FROM_PROTO)
+   --db-nb-create-insecure-remote=yes|no Create ptcp OVN Northbound remote (default: $DB_NB_CREATE_INSECURE_REMOTE)
++  --db-nb-probe-interval-to-active Active probe interval from standby to active ovsdb-server remote (default: $DB_NB_PROBE_INTERVAL_TO_ACTIVE)
+   --db-sb-sync-from-addr=ADDR OVN Southbound active db tcp address (default: $DB_SB_SYNC_FROM_ADDR)
+   --db-sb-sync-from-port=ADDR OVN Southbound active db tcp port (default: $DB_SB_SYNC_FROM_PORT)
+   --db-sb-sync-from-proto=PROTO OVN Southbound active db transport (default: $DB_SB_SYNC_FROM_PROTO)
+   --db-sb-create-insecure-remote=yes|no Create ptcp OVN Southbound remote (default: $DB_SB_CREATE_INSECURE_REMOTE)
++  --db-sb-probe-interval-to-active Active probe interval from standby to active ovsdb-server remote (default: $DB_SB_PROBE_INTERVAL_TO_ACTIVE)
+   --db-nb-cluster-local-addr=ADDR OVN_Northbound cluster local address \
+   (default: $DB_NB_CLUSTER_LOCAL_ADDR)
+   --db-nb-cluster-local-port=PORT OVN_Northbound cluster local tcp port \
+diff --git a/utilities/ovn-ctl.8.xml b/utilities/ovn-ctl.8.xml
+index 816701379..f5b7f7aeb 100644
+--- a/utilities/ovn-ctl.8.xml
++++ b/utilities/ovn-ctl.8.xml
+@@ -150,6 +150,10 @@
+     <p><code>--db-ic-sb-cluster-remote-port=<var>PORT NUMBER</var></code></p>
+     <p><code>--db-ic-sb-cluster-remote-proto=<var>PROTO (tcp/ssl)</var></code></p>
+ 
++    <h1> Probe interval options </h1>
++    <p><code>--db-nb-probe-interval-to-active=<var>Time in milliseconds</var></code></p>
++    <p><code>--db-sb-probe-interval-to-active=<var>Time in milliseconds</var></code></p>
++
+     <h1>Configuration files</h1>
+     <p>Following are the optional configuration files. If present, it should be located in the etc dir</p>
+ 
+@@ -241,8 +245,8 @@
+     <h2>Promote and demote ovsdb servers</h2>
+     <p><code># ovn-ctl promote_ovnnb</code></p>
+     <p><code># ovn-ctl promote_ovnsb</code></p>
+-    <p><code># ovn-ctl --db-nb-sync-from-addr=x.x.x.x --db-nb-sync-from-port=6641 demote_ovnnb</code></p>
+-    <p><code># ovn-ctl --db-sb-sync-from-addr=x.x.x.x --db-sb-sync-from-port=6642 demote_ovnsb</code></p>
++    <p><code># ovn-ctl --db-nb-sync-from-addr=x.x.x.x --db-nb-sync-from-port=6641 --db-nb-probe-interval-to-active=60000 demote_ovnnb</code></p>
++    <p><code># ovn-ctl --db-sb-sync-from-addr=x.x.x.x --db-sb-sync-from-port=6642 --db-sb-probe-interval-to-active=60000 demote_ovnsb</code></p>
+ 
+     <h2>Creating a clustered db on 3 nodes with IPs x.x.x.x, y.y.y.y and z.z.z.z</h2>
+     <h3>Starting OVN ovsdb servers and ovn-northd on the node with IP x.x.x.x</h3>
+diff --git a/utilities/ovndb-servers.ocf b/utilities/ovndb-servers.ocf
+index 42e0412ad..56c2bc322 100755
+--- a/utilities/ovndb-servers.ocf
++++ b/utilities/ovndb-servers.ocf
+@@ -9,6 +9,7 @@
+ : ${SB_MASTER_PROTO_DEFAULT="tcp"}
+ : ${MANAGE_NORTHD_DEFAULT="no"}
+ : ${INACTIVE_PROBE_DEFAULT="5000"}
++: ${INACTIVE_PROBE_TO_MASTER_DEFAULT="60000"}
+ : ${LISTEN_ON_MASTER_IP_ONLY_DEFAULT="yes"}
+ : ${NB_SSL_KEY_DEFAULT="/etc/openvswitch/ovnnb-privkey.pem"}
+ : ${NB_SSL_CERT_DEFAULT="/etc/openvswitch/ovnnb-cert.pem"}
+@@ -27,6 +28,7 @@ SB_MASTER_PORT=${OCF_RESKEY_sb_master_port:-${SB_MASTER_PORT_DEFAULT}}
+ SB_MASTER_PROTO=${OCF_RESKEY_sb_master_protocol:-${SB_MASTER_PROTO_DEFAULT}}
+ MANAGE_NORTHD=${OCF_RESKEY_manage_northd:-${MANAGE_NORTHD_DEFAULT}}
+ INACTIVE_PROBE=${OCF_RESKEY_inactive_probe_interval:-${INACTIVE_PROBE_DEFAULT}}
++INACTIVE_PROBE_TO_MASTER=${OCF_RESKEY_inactive_probe_interval_to_master:-${INACTIVE_PROBE_TO_MASTER_DEFAULT}}
+ NB_PRIVKEY=${OCF_RESKEY_ovn_nb_db_privkey:-${NB_SSL_KEY_DEFAULT}}
+ NB_CERT=${OCF_RESKEY_ovn_nb_db_cert:-${NB_SSL_CERT_DEFAULT}}
+ NB_CACERT=${OCF_RESKEY_ovn_nb_db_cacert:-${NB_SSL_CACERT_DEFAULT}}
+@@ -135,6 +137,15 @@ ovsdb_server_metadata() {
+   <content type="string" />
+   </parameter>
+ 
++  <parameter name="inactive_probe_interval_to_master" unique="1">
++  <longdesc lang="en">
++  Inactive probe interval to use for the connection from standby
++  ovsdb-server to master ovsdb-server.
++  </longdesc>
++  <shortdesc lang="en">Set inactive probe interval to master</shortdesc>
++  <content type="string" />
++  </parameter>
++
+   <parameter name="listen_on_master_ip_only" unique="1">
+   <longdesc lang="en">
+   If set to yes, the OVNDBs will listen on master IP. Otherwise, it will
+@@ -266,10 +277,12 @@ inactivity_probe=$INACTIVE_PROBE -- set SB_Global . connections=@conn_uuid
+         ocf_log debug "ovndb_server: Connecting to the new master ${OCF_RESKEY_CRM_meta_notify_promote_uname}"
+         ${OVN_CTL} demote_ovnnb --db-nb-sync-from-addr=${MASTER_IP} \
+                                 --db-nb-sync-from-port=${NB_MASTER_PORT} \
+-                                --db-nb-sync-from-proto=${NB_MASTER_PROTO}
++                                --db-nb-sync-from-proto=${NB_MASTER_PROTO} \
++                                --db-nb-probe-interval-to-active=${INACTIVE_PROBE_TO_MASTER}
+         ${OVN_CTL} demote_ovnsb --db-sb-sync-from-addr=${MASTER_IP} \
+                                 --db-sb-sync-from-port=${SB_MASTER_PORT} \
+-                                --db-sb-sync-from-proto=${SB_MASTER_PROTO}
++                                --db-sb-sync-from-proto=${SB_MASTER_PROTO} \
++                                --db-sb-probe-interval-to-active=${INACTIVE_PROBE_TO_MASTER}
+     fi
+ }
+ 
+@@ -596,10 +609,12 @@ ovsdb_server_demote() {
+         # being demoted. Sync to the surviving one
+         ${OVN_CTL} demote_ovnnb --db-nb-sync-from-addr=${MASTER_IP} \
+                                 --db-nb-sync-from-port=${NB_MASTER_PORT} \
+-                                --db-nb-sync-from-proto=${NB_MASTER_PROTO}
++                                --db-nb-sync-from-proto=${NB_MASTER_PROTO} \
++                                --db-nb-probe-interval-to-active=${INACTIVE_PROBE_TO_MASTER}
+         ${OVN_CTL} demote_ovnsb --db-sb-sync-from-addr=${MASTER_IP} \
+                                 --db-sb-sync-from-port=${SB_MASTER_PORT} \
+-                                --db-sb-sync-from-proto=${SB_MASTER_PROTO}
++                                --db-sb-sync-from-proto=${SB_MASTER_PROTO} \
++                                --db-sb-probe-interval-to-active=${INACTIVE_PROBE_TO_MASTER}
+ 
+     else
+         # For completeness, should never be called
+-- 
+2.25.1
+
diff --git a/SOURCES/0001-ovn-nbctl-Create-daemon-control-socket-in-ovn-run-di.patch b/SOURCES/0001-ovn-nbctl-Create-daemon-control-socket-in-ovn-run-di.patch
new file mode 100644
index 0000000..999a5dc
--- /dev/null
+++ b/SOURCES/0001-ovn-nbctl-Create-daemon-control-socket-in-ovn-run-di.patch
@@ -0,0 +1,180 @@
+From 0319176e1d1fa741868d822100d0dde89a585ca3 Mon Sep 17 00:00:00 2001
+From: Numan Siddique <numans@ovn.org>
+Date: Wed, 8 Apr 2020 20:16:49 +0530
+Subject: [PATCH] ovn-nbctl: Create daemon control socket in ovn run dir
+
+ovn-nbctl when run as a daemon is creating the ctl socket in
+the ovs rundir. This patch fixes this issue by creating it in
+the ovn rundir.
+
+When an ovn service is run with -u option (which specifies the
+ctl socket path) and if this path is not absolute, the ovn
+ctl socket path is created in the ovs run dir. This patch
+also fixes this issue by creating it in the ovn run dir.
+
+Reported-by: Dan Williams <dcbw@redhat.com>
+Acked-by: Dumitru Ceara <dceara@redhat.com>
+Signed-off-by: Numan Siddique <numans@ovn.org>
+
+(cherry-picked from upstream branch-20.03 commit 29927708242044696a49051c77c3d4b38ba02392)
+
+Change-Id: I17b3ab45f591fa9793ae8d95cf78c2113a1e4d65
+---
+ controller-vtep/ovn-controller-vtep.c |  5 ++++-
+ controller/ovn-controller.c           |  2 +-
+ ic/ovn-ic.c                           | 10 +++-------
+ lib/ovn-util.c                        |  9 +++++----
+ lib/ovn-util.h                        |  2 +-
+ northd/ovn-northd.c                   | 10 +++-------
+ utilities/ovn-nbctl.c                 |  6 +++++-
+ utilities/ovn-trace.c                 |  6 +++++-
+ 8 files changed, 27 insertions(+), 23 deletions(-)
+
+diff --git a/controller-vtep/ovn-controller-vtep.c b/controller-vtep/ovn-controller-vtep.c
+index b30a731d4..253a709ab 100644
+--- a/controller-vtep/ovn-controller-vtep.c
++++ b/controller-vtep/ovn-controller-vtep.c
+@@ -67,7 +67,10 @@ main(int argc, char *argv[])
+ 
+     daemonize_start(false);
+ 
+-    retval = unixctl_server_create(NULL, &unixctl);
++    char *abs_unixctl_path = get_abs_unix_ctl_path(NULL);
++    retval = unixctl_server_create(abs_unixctl_path, &unixctl);
++    free(abs_unixctl_path);
++
+     if (retval) {
+         exit(EXIT_FAILURE);
+     }
+diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c
+index 2893eaac1..4d21ba0fd 100644
+--- a/controller/ovn-controller.c
++++ b/controller/ovn-controller.c
+@@ -1729,7 +1729,7 @@ main(int argc, char *argv[])
+ 
+     daemonize_start(true);
+ 
+-    char *abs_unixctl_path = get_abs_unix_ctl_path();
++    char *abs_unixctl_path = get_abs_unix_ctl_path(NULL);
+     retval = unixctl_server_create(abs_unixctl_path, &unixctl);
+     free(abs_unixctl_path);
+     if (retval) {
+diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c
+index bf8205de2..d931ca50f 100644
+--- a/ic/ovn-ic.c
++++ b/ic/ovn-ic.c
+@@ -1575,13 +1575,9 @@ main(int argc, char *argv[])
+ 
+     daemonize_start(false);
+ 
+-    if (!unixctl_path) {
+-        char *abs_unixctl_path = get_abs_unix_ctl_path();
+-        retval = unixctl_server_create(abs_unixctl_path, &unixctl);
+-        free(abs_unixctl_path);
+-    } else {
+-        retval = unixctl_server_create(unixctl_path, &unixctl);
+-    }
++    char *abs_unixctl_path = get_abs_unix_ctl_path(unixctl_path);
++    retval = unixctl_server_create(abs_unixctl_path, &unixctl);
++    free(abs_unixctl_path);
+ 
+     if (retval) {
+         exit(EXIT_FAILURE);
+diff --git a/lib/ovn-util.c b/lib/ovn-util.c
+index df18fda89..514e2489f 100644
+--- a/lib/ovn-util.c
++++ b/lib/ovn-util.c
+@@ -377,7 +377,7 @@ default_ic_sb_db(void)
+ }
+ 
+ char *
+-get_abs_unix_ctl_path(void)
++get_abs_unix_ctl_path(const char *path)
+ {
+ #ifdef _WIN32
+     enum { WINDOWS = 1 };
+@@ -386,9 +386,10 @@ get_abs_unix_ctl_path(void)
+ #endif
+ 
+     long int pid = getpid();
+-    char *abs_path =
+-        WINDOWS ? xasprintf("%s/%s.ctl", ovn_rundir(), program_name)
+-                : xasprintf("%s/%s.%ld.ctl", ovn_rundir(), program_name, pid);
++    char *abs_path
++        = (path ? abs_file_name(ovn_rundir(), path)
++           : WINDOWS ? xasprintf("%s/%s.ctl", ovn_rundir(), program_name)
++           : xasprintf("%s/%s.%ld.ctl", ovn_rundir(), program_name, pid));
+     return abs_path;
+ }
+ 
+diff --git a/lib/ovn-util.h b/lib/ovn-util.h
+index 32c8334b0..11238f61c 100644
+--- a/lib/ovn-util.h
++++ b/lib/ovn-util.h
+@@ -82,7 +82,7 @@ const char *default_nb_db(void);
+ const char *default_sb_db(void);
+ const char *default_ic_nb_db(void);
+ const char *default_ic_sb_db(void);
+-char *get_abs_unix_ctl_path(void);
++char *get_abs_unix_ctl_path(const char *path);
+ 
+ struct ovsdb_idl_table_class;
+ const char *db_table_usage(struct ds *tables,
+diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
+index fd1be5b27..1f1238d23 100644
+--- a/northd/ovn-northd.c
++++ b/northd/ovn-northd.c
+@@ -11673,13 +11673,9 @@ main(int argc, char *argv[])
+ 
+     daemonize_start(false);
+ 
+-    if (!unixctl_path) {
+-        char *abs_unixctl_path = get_abs_unix_ctl_path();
+-        retval = unixctl_server_create(abs_unixctl_path, &unixctl);
+-        free(abs_unixctl_path);
+-    } else {
+-        retval = unixctl_server_create(unixctl_path, &unixctl);
+-    }
++    char *abs_unixctl_path = get_abs_unix_ctl_path(unixctl_path);
++    retval = unixctl_server_create(abs_unixctl_path, &unixctl);
++    free(abs_unixctl_path);
+ 
+     if (retval) {
+         exit(EXIT_FAILURE);
+diff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c
+index 59abe0051..a88c1ddc2 100644
+--- a/utilities/ovn-nbctl.c
++++ b/utilities/ovn-nbctl.c
+@@ -6436,7 +6436,11 @@ server_loop(struct ovsdb_idl *idl, int argc, char *argv[])
+ 
+     service_start(&argc, &argv);
+     daemonize_start(false);
+-    int error = unixctl_server_create(unixctl_path, &server);
++
++    char *abs_unixctl_path = get_abs_unix_ctl_path(unixctl_path);
++    int error = unixctl_server_create(abs_unixctl_path, &server);
++    free(abs_unixctl_path);
++
+     if (error) {
+         ctl_fatal("failed to create unixctl server (%s)",
+                   ovs_retval_to_string(error));
+diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c
+index e59698ec4..eae9622d3 100644
+--- a/utilities/ovn-trace.c
++++ b/utilities/ovn-trace.c
+@@ -125,7 +125,11 @@ main(int argc, char *argv[])
+     bool exiting = false;
+     if (get_detach()) {
+         daemonize_start(false);
+-        int error = unixctl_server_create(unixctl_path, &server);
++
++        char *abs_unixctl_path = get_abs_unix_ctl_path(unixctl_path);
++        int error = unixctl_server_create(abs_unixctl_path, &server);
++        free(abs_unixctl_path);
++
+         if (error) {
+             ovs_fatal(error, "failed to create unixctl server");
+         }
+-- 
+2.25.1
+
diff --git a/SOURCES/0001-ovn-northd-Add-lflows-to-by-pass-the-svc-monitor-pac.patch b/SOURCES/0001-ovn-northd-Add-lflows-to-by-pass-the-svc-monitor-pac.patch
new file mode 100644
index 0000000..5e35cab
--- /dev/null
+++ b/SOURCES/0001-ovn-northd-Add-lflows-to-by-pass-the-svc-monitor-pac.patch
@@ -0,0 +1,197 @@
+From 8e0b2c54726c666db7163dd18673683dfd06d89c Mon Sep 17 00:00:00 2001
+From: Numan Siddique <numans@ovn.org>
+Date: Thu, 12 Mar 2020 15:58:38 +0530
+Subject: [PATCH] ovn-northd: Add lflows to by pass the svc monitor packets
+ from conntrack.
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The commit [1] added lflows to by pass the service monitor health check
+packets from conntrack. But it missed out adding in the ingress pre_acl
+and egress pre_acl of logical switch pipeline.
+
+This patch adds these missing lflows. It also enhanced the system lb health
+check tests to add the acls to test this scenario.
+
+[1] - bb9f2b9ce56c("ovn-northd: Consider load balancer active backends in router pipeline)
+Fixes: bb9f2b9ce56c("ovn-northd: Consider load balancer active backends in router pipeline)
+
+Reported-by: Maciej Józefczyk <mjozefcz@redhat.com>
+Acked-by: Dumitru Ceara <dceara@redhat.com>
+Acked-by: Maciej Jozefczyk <mjozefcz@redhat.com>
+Signed-off-by: Numan Siddique <numans@ovn.org>
+
+(cherry-picked from upstream branch-20.03 commit f70a0f7c485f13cbbae8bc6f8d78225238c308b9)
+
+Change-Id: I8980d306ea67c2aaa3bfa8f907a0f71a55fe0f9d
+---
+ northd/ovn-northd.8.xml | 22 +++++++++++++++++++++-
+ northd/ovn-northd.c     | 15 ++++++++++++++-
+ tests/ovn.at            | 22 ++++++++++++++++++++++
+ tests/system-ovn.at     | 22 ++++++++++++++++++++++
+ 4 files changed, 79 insertions(+), 2 deletions(-)
+
+diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
+index b6cfa3e90..9b44720d1 100644
+--- a/northd/ovn-northd.8.xml
++++ b/northd/ovn-northd.8.xml
+@@ -293,6 +293,16 @@
+       priority-110 flow is added to skip over stateful ACLs.
+     </p>
+ 
++    <p>
++      This table also has a priority-110 flow with the match
++      <code>eth.dst == <var>E</var></code> for all logical switch
++      datapaths to move traffic to the next table. Where <var>E</var>
++      is the service monitor mac defined in the
++      <ref column="options:svc_monitor_mac" table="NB_Global"
++      db="OVN_Northbound"/> colum of <ref table="NB_Global"
++      db="OVN_Northbound"/> table.
++    </p>
++
+     <h3>Ingress Table 4: Pre-LB</h3>
+ 
+     <p>
+@@ -320,7 +330,7 @@
+ 
+     <p>
+       This table also has a priority-110 flow with the match
+-      <code>eth.src == <var>E</var></code> for all logical switch
++      <code>eth.dst == <var>E</var></code> for all logical switch
+       datapaths to move traffic to the next table. Where <var>E</var>
+       is the service monitor mac defined in the
+       <ref column="options:svc_monitor_mac" table="NB_Global"
+@@ -1295,6 +1305,16 @@ output;
+      <code>to-lport</code> traffic.
+     </p>
+ 
++    <p>
++      This table also has a priority-110 flow with the match
++      <code>eth.src == <var>E</var></code> for all logical switch
++      datapaths to move traffic to the next table. Where <var>E</var>
++      is the service monitor mac defined in the
++      <ref column="options:svc_monitor_mac" table="NB_Global"
++      db="OVN_Northbound"/> colum of <ref table="NB_Global"
++      db="OVN_Northbound"/> table.
++    </p>
++
+     <h3>Egress Table 2: Pre-stateful</h3>
+ 
+     <p>
+diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
+index 217a8c894..3a77f2e3a 100644
+--- a/northd/ovn-northd.c
++++ b/northd/ovn-northd.c
+@@ -4601,6 +4601,16 @@ build_pre_acls(struct ovn_datapath *od, struct hmap *lflows)
+     ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 0, "1", "next;");
+     ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 0, "1", "next;");
+ 
++    char *svc_check_match = xasprintf("eth.dst == %s", svc_monitor_mac);
++    ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 110, svc_check_match,
++                  "next;");
++    free(svc_check_match);
++
++    svc_check_match = xasprintf("eth.src == %s", svc_monitor_mac);
++    ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 110, svc_check_match,
++                  "next;");
++    free(svc_check_match);
++
+     /* If there are any stateful ACL rules in this datapath, we must
+      * send all IP packets through the conntrack action, which handles
+      * defragmentation, in order to match L4 headers. */
+@@ -4784,9 +4794,12 @@ build_pre_lb(struct ovn_datapath *od, struct hmap *lflows,
+                   "next;");
+ 
+     /* Do not send service monitor packets to conntrack. */
+-    char *svc_check_match = xasprintf("eth.src == %s", svc_monitor_mac);
++    char *svc_check_match = xasprintf("eth.dst == %s", svc_monitor_mac);
+     ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, 110,
+                   svc_check_match, "next;");
++    free(svc_check_match);
++
++    svc_check_match = xasprintf("eth.src == %s", svc_monitor_mac);
+     ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, 110,
+                   svc_check_match, "next;");
+     free(svc_check_match);
+diff --git a/tests/ovn.at b/tests/ovn.at
+index 8de4b5ceb..8cdbad743 100644
+--- a/tests/ovn.at
++++ b/tests/ovn.at
+@@ -17739,12 +17739,34 @@ ovn-nbctl lsp-set-port-security sw0-p1 "50:54:00:00:00:03 10.0.0.3"
+ ovn-nbctl lsp-set-addresses sw0-p2 "50:54:00:00:00:04 10.0.0.4"
+ ovn-nbctl lsp-set-port-security sw0-p2 "50:54:00:00:00:04 10.0.0.4"
+ 
++# Create port group and ACLs for sw0 ports.
++ovn-nbctl pg-add pg0_drop sw0-p1 sw0-p2
++ovn-nbctl acl-add pg0_drop from-lport 1001 "inport == @pg0_drop && ip" drop
++ovn-nbctl acl-add pg0_drop to-lport 1001 "outport == @pg0_drop && ip" drop
++
++ovn-nbctl pg-add pg0 sw0-p1 sw0-p2
++ovn-nbctl acl-add pg0 from-lport 1002 "inport == @pg0 && ip4" allow-related
++ovn-nbctl acl-add pg0 to-lport 1002 "outport == @pg0 && ip4 && ip4.src == 0.0.0.0/0 && icmp4" allow-related
++ovn-nbctl acl-add pg0 to-lport 1002 "outport == @pg0 && ip4 && ip4.src == 0.0.0.0/0 && tcp && tcp.dst == 80" allow-related
++ovn-nbctl acl-add pg0 to-lport 1002 "outport == @pg0 && ip4 && ip4.src == 0.0.0.0/0 && udp && udp.dst == 80" allow-related
++
+ # Create the second logical switch with one port
+ ovn-nbctl ls-add sw1
+ ovn-nbctl lsp-add sw1 sw1-p1
+ ovn-nbctl lsp-set-addresses sw1-p1 "40:54:00:00:00:03 20.0.0.3"
+ ovn-nbctl lsp-set-port-security sw1-p1 "40:54:00:00:00:03 20.0.0.3"
+ 
++# Create port group and ACLs for sw1 ports.
++ovn-nbctl pg-add pg1_drop sw1-p1
++ovn-nbctl acl-add pg1_drop from-lport 1001 "inport == @pg1_drop && ip" drop
++ovn-nbctl acl-add pg1_drop to-lport 1001 "outport == @pg1_drop && ip" drop
++
++ovn-nbctl pg-add pg1 sw1-p1
++ovn-nbctl acl-add pg1 from-lport 1002 "inport == @pg1 && ip4" allow-related
++ovn-nbctl acl-add pg1 to-lport 1002 "outport == @pg1 && ip4 && ip4.src == 0.0.0.0/0 && icmp4" allow-related
++ovn-nbctl acl-add pg1 to-lport 1002 "outport == @pg1 && ip4 && ip4.src == 0.0.0.0/0 && tcp && tcp.dst == 80" allow-related
++ovn-nbctl acl-add pg1 to-lport 1002 "outport == @pg1 && ip4 && ip4.src == 0.0.0.0/0 && udp && udp.dst == 80" allow-related
++
+ # Create a logical router and attach both logical switches
+ ovn-nbctl lr-add lr0
+ ovn-nbctl lrp-add lr0 lr0-sw0 00:00:00:00:ff:01 10.0.0.1/24
+diff --git a/tests/system-ovn.at b/tests/system-ovn.at
+index 9ed3df754..3b3379840 100644
+--- a/tests/system-ovn.at
++++ b/tests/system-ovn.at
+@@ -3314,12 +3314,34 @@ ovn-nbctl lsp-add sw0 sw0-p2
+ ovn-nbctl lsp-set-addresses sw0-p2 "50:54:00:00:00:04 10.0.0.4"
+ ovn-nbctl lsp-set-port-security sw0-p2 "50:54:00:00:00:04 10.0.0.4"
+ 
++# Create port group and ACLs for sw0 ports.
++ovn-nbctl pg-add pg0_drop sw0-p1 sw0-p2
++ovn-nbctl acl-add pg0_drop from-lport 1001 "inport == @pg0_drop && ip" drop
++ovn-nbctl acl-add pg0_drop to-lport 1001 "outport == @pg0_drop && ip" drop
++
++ovn-nbctl pg-add pg0 sw0-p1 sw0-p2
++ovn-nbctl acl-add pg0 from-lport 1002 "inport == @pg0 && ip4" allow-related
++ovn-nbctl acl-add pg0 to-lport 1002 "outport == @pg0 && ip4 && ip4.src == 0.0.0.0/0 && icmp4" allow-related
++ovn-nbctl acl-add pg0 to-lport 1002 "outport == @pg0 && ip4 && ip4.src == 0.0.0.0/0 && tcp && tcp.dst == 80" allow-related
++ovn-nbctl acl-add pg0 to-lport 1002 "outport == @pg0 && ip4 && ip4.src == 0.0.0.0/0 && udp && udp.dst == 80" allow-related
++
+ # Create the second logical switch with one port
+ ovn-nbctl ls-add sw1
+ ovn-nbctl lsp-add sw1 sw1-p1
+ ovn-nbctl lsp-set-addresses sw1-p1 "40:54:00:00:00:03 20.0.0.3"
+ ovn-nbctl lsp-set-port-security sw1-p1 "40:54:00:00:00:03 20.0.0.3"
+ 
++# Create port group and ACLs for sw1 ports.
++ovn-nbctl pg-add pg1_drop sw1-p1
++ovn-nbctl acl-add pg1_drop from-lport 1001 "inport == @pg1_drop && ip" drop
++ovn-nbctl acl-add pg1_drop to-lport 1001 "outport == @pg1_drop && ip" drop
++
++ovn-nbctl pg-add pg1 sw1-p1
++ovn-nbctl acl-add pg1 from-lport 1002 "inport == @pg1 && ip4" allow-related
++ovn-nbctl acl-add pg1 to-lport 1002 "outport == @pg1 && ip4 && ip4.src == 0.0.0.0/0 && icmp4" allow-related
++ovn-nbctl acl-add pg1 to-lport 1002 "outport == @pg1 && ip4 && ip4.src == 0.0.0.0/0 && tcp && tcp.dst == 80" allow-related
++ovn-nbctl acl-add pg1 to-lport 1002 "outport == @pg1 && ip4 && ip4.src == 0.0.0.0/0 && udp && udp.dst == 80" allow-related
++
+ # Create a logical router and attach both logical switches
+ ovn-nbctl lr-add lr0
+ ovn-nbctl lrp-add lr0 lr0-sw0 00:00:00:00:ff:01 10.0.0.1/24
+-- 
+2.24.1
+
diff --git a/SOURCES/0001-ovn-northd-Clear-SB-records-depending-on-stale-datap.patch b/SOURCES/0001-ovn-northd-Clear-SB-records-depending-on-stale-datap.patch
new file mode 100644
index 0000000..3538655
--- /dev/null
+++ b/SOURCES/0001-ovn-northd-Clear-SB-records-depending-on-stale-datap.patch
@@ -0,0 +1,189 @@
+From e5b87cf915c0061355f9c4cdea0df1fe1c26cd38 Mon Sep 17 00:00:00 2001
+From: Dumitru Ceara <dceara@redhat.com>
+Date: Thu, 30 Apr 2020 20:32:17 +0200
+Subject: [PATCH 1/2] ovn-northd: Clear SB records depending on stale
+ datapaths.
+
+When purging stale SB Datapath_Binding records ovn-northd doesn't
+properly clean records from other tables that might refer the
+datapaths being deleted.
+
+One way to reproduce the issue is:
+$ ovn-nbctl lr-add lr
+$ ovn-nbctl lrp-add lr p 00:00:00:00:00:01 1.1.1.1/24
+$ ovn-nbctl --wait=sb sync
+$ dp=$(ovn-sbctl --bare --columns _uuid list datapath .)
+$ ovn-sbctl create mac_binding logical_port="p" ip="1.1.1.2" datapath="$dp"
+$ ovn-nbctl lrp-del p -- lr-del lr -- \
+    lr-add lr -- lrp-add lr p 00:00:00:00:00:01 1.1.1.1/24
+
+Reported-by: Dan Williams <dcbw@redhat.com>
+Reported-at: https://bugzilla.redhat.com/1828637
+Signed-off-by: Dumitru Ceara <dceara@redhat.com>
+Acked-by: Numan Siddique <numans@ovn.org>
+Signed-off-by: Han Zhou <hzhou@ovn.org>
+(cherry picked from upstream commit 6856adc616a7181723ce5201110cc95de1aba92b)
+
+Change-Id: I1cbcb5fc34927368e6655420126b2492c4fce9df
+---
+ northd/ovn-northd.c | 45 ++++++++++++++++++++++++++++++++-------------
+ tests/ovn-northd.at | 24 ++++++++++++++++++++++++
+ 2 files changed, 56 insertions(+), 13 deletions(-)
+
+diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
+index 5ada3ae..5e649d0 100644
+--- a/northd/ovn-northd.c
++++ b/northd/ovn-northd.c
+@@ -634,6 +634,12 @@ ovn_datapath_find(struct hmap *datapaths, const struct uuid *uuid)
+     return NULL;
+ }
+ 
++static bool
++ovn_datapath_is_stale(const struct ovn_datapath *od)
++{
++    return !od->nbr && !od->nbs;
++}
++
+ static struct ovn_datapath *
+ ovn_datapath_from_sbrec(struct hmap *datapaths,
+                         const struct sbrec_datapath_binding *sb)
+@@ -3067,11 +3073,16 @@ ovn_port_update_sbrec(struct northd_context *ctx,
+ /* Remove mac_binding entries that refer to logical_ports which are
+  * deleted. */
+ static void
+-cleanup_mac_bindings(struct northd_context *ctx, struct hmap *ports)
++cleanup_mac_bindings(struct northd_context *ctx, struct hmap *datapaths,
++                     struct hmap *ports)
+ {
+     const struct sbrec_mac_binding *b, *n;
+     SBREC_MAC_BINDING_FOR_EACH_SAFE (b, n, ctx->ovnsb_idl) {
+-        if (!ovn_port_find(ports, b->logical_port)) {
++        const struct ovn_datapath *od =
++            ovn_datapath_from_sbrec(datapaths, b->datapath);
++
++        if (!od || ovn_datapath_is_stale(od) ||
++                !ovn_port_find(ports, b->logical_port)) {
+             sbrec_mac_binding_delete(b);
+         }
+     }
+@@ -3439,6 +3450,9 @@ build_ports(struct northd_context *ctx,
+     join_logical_ports(ctx, datapaths, ports, &chassis_qdisc_queues,
+                        &tag_alloc_table, &sb_only, &nb_only, &both);
+ 
++    /* Purge stale Mac_Bindings if ports are deleted. */
++    bool remove_mac_bindings = !ovs_list_is_empty(&sb_only);
++
+     struct ovn_port *op, *next;
+     /* For logical ports that are in both databases, index the in-use
+      * tunnel_keys. */
+@@ -3453,6 +3467,12 @@ build_ports(struct northd_context *ctx,
+      * For logical ports that are in NB database, do any tag allocation
+      * needed. */
+     LIST_FOR_EACH_SAFE (op, next, list, &both) {
++        /* When reusing stale Port_Bindings, make sure that stale
++         * Mac_Bindings are purged.
++         */
++        if (op->od->sb != op->sb->datapath) {
++            remove_mac_bindings = true;
++        }
+         if (op->nbsp) {
+             tag_alloc_create_new_tag(&tag_alloc_table, op->nbsp);
+         }
+@@ -3488,19 +3508,15 @@ build_ports(struct northd_context *ctx,
+         sbrec_port_binding_set_tunnel_key(op->sb, tunnel_key);
+     }
+ 
+-    bool remove_mac_bindings = false;
+-    if (!ovs_list_is_empty(&sb_only)) {
+-        remove_mac_bindings = true;
+-    }
+-
+     /* Delete southbound records without northbound matches. */
+     LIST_FOR_EACH_SAFE(op, next, list, &sb_only) {
+         ovs_list_remove(&op->list);
+         sbrec_port_binding_delete(op->sb);
+         ovn_port_destroy(ports, op);
+     }
++
+     if (remove_mac_bindings) {
+-        cleanup_mac_bindings(ctx, ports);
++        cleanup_mac_bindings(ctx, datapaths, ports);
+     }
+ 
+     tag_alloc_destroy(&tag_alloc_table);
+@@ -10258,7 +10274,8 @@ build_lflows(struct northd_context *ctx, struct hmap *datapaths,
+     SBREC_LOGICAL_FLOW_FOR_EACH_SAFE (sbflow, next_sbflow, ctx->ovnsb_idl) {
+         struct ovn_datapath *od
+             = ovn_datapath_from_sbrec(datapaths, sbflow->logical_datapath);
+-        if (!od) {
++
++        if (!od || ovn_datapath_is_stale(od)) {
+             sbrec_logical_flow_delete(sbflow);
+             continue;
+         }
+@@ -10318,7 +10335,8 @@ build_lflows(struct northd_context *ctx, struct hmap *datapaths,
+     SBREC_MULTICAST_GROUP_FOR_EACH_SAFE (sbmc, next_sbmc, ctx->ovnsb_idl) {
+         struct ovn_datapath *od = ovn_datapath_from_sbrec(datapaths,
+                                                           sbmc->datapath);
+-        if (!od) {
++
++        if (!od || ovn_datapath_is_stale(od)) {
+             sbrec_multicast_group_delete(sbmc);
+             continue;
+         }
+@@ -10800,8 +10818,8 @@ build_ip_mcast(struct northd_context *ctx, struct hmap *datapaths)
+     const struct sbrec_ip_multicast *sb, *sb_next;
+ 
+     SBREC_IP_MULTICAST_FOR_EACH_SAFE (sb, sb_next, ctx->ovnsb_idl) {
+-        if (!sb->datapath ||
+-                !ovn_datapath_from_sbrec(datapaths, sb->datapath)) {
++        od = ovn_datapath_from_sbrec(datapaths, sb->datapath);
++        if (!od || ovn_datapath_is_stale(od)) {
+             sbrec_ip_multicast_delete(sb);
+         }
+     }
+@@ -10870,7 +10888,8 @@ build_mcast_groups(struct northd_context *ctx,
+         /* If the datapath value is stale, purge the group. */
+         struct ovn_datapath *od =
+             ovn_datapath_from_sbrec(datapaths, sb_igmp->datapath);
+-        if (!od) {
++
++        if (!od || ovn_datapath_is_stale(od)) {
+             sbrec_igmp_group_delete(sb_igmp);
+             continue;
+         }
+diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
+index d127152..94f892b 100644
+--- a/tests/ovn-northd.at
++++ b/tests/ovn-northd.at
+@@ -1326,3 +1326,27 @@ AT_CHECK([test 0 = $(ovn-sbctl dump-flows lr0 | grep lr_in_unsnat | \
+ grep "ip4 && ip4.dst == 192.168.2.6 && tcp && tcp.dst == 8080" -c) ])
+ 
+ AT_CLEANUP
++
++AT_SETUP([ovn -- check reconcile stale Datapath_Binding])
++ovn_start
++
++ovn-nbctl lr-add lr
++ovn-nbctl lrp-add lr p 00:00:00:00:00:01 1.1.1.1/24
++
++AT_CHECK([ovn-nbctl --wait=sb sync], [0])
++
++# Create a MAC_Binding referring the router datapath.
++dp=$(ovn-sbctl --bare --columns _uuid list datapath .)
++ovn-sbctl create mac_binding logical_port="p" ip="1.1.1.2" datapath="$dp"
++
++ovn-nbctl lrp-del p -- lr-del lr -- \
++    lr-add lr -- lrp-add lr p 00:00:00:00:00:01 1.1.1.1/24
++AT_CHECK([ovn-nbctl --wait=sb sync], [0])
++
++AT_CHECK([test 1 = $(ovn-sbctl --columns _uuid list Datapath_Binding | wc -l)])
++
++nb_uuid=$(ovn-sbctl get Datapath_Binding . external_ids:logical-router)
++lr_uuid=$(ovn-nbctl --columns _uuid list Logical_Router .)
++AT_CHECK[test ${nb_uuid} = ${lr_uuid}]
++
++AT_CLEANUP
+-- 
+1.8.3.1
+
diff --git a/SOURCES/0001-ovn-northd-Don-t-add-arp-responder-flows-for-lports-.patch b/SOURCES/0001-ovn-northd-Don-t-add-arp-responder-flows-for-lports-.patch
new file mode 100644
index 0000000..da692e0
--- /dev/null
+++ b/SOURCES/0001-ovn-northd-Don-t-add-arp-responder-flows-for-lports-.patch
@@ -0,0 +1,126 @@
+From 5521da70830446373265999b6d994d986a02ce01 Mon Sep 17 00:00:00 2001
+From: Numan Siddique <numans@ovn.org>
+Date: Thu, 19 Mar 2020 16:52:17 +0530
+Subject: [PATCH] ovn-northd: Don't add arp responder flows for lports with
+ 'unknown' address.
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+If a logical port has 'unknown' address, it means it can send and receive
+packet with any IP and MAC and generally port security is not set for
+such logical ports. If an lport has addresses set to - ["MAC1 IP1", unknown],
+right now we add arp responder flows for IP1 and respond MAC1 in the arp
+response. But it's possible that the VIF of the logical port can use the IP1
+with a different MAC. This patch supports this usecase. When another logical port
+sends ARP request for IP1, the VIF of the logical port will anyway respond.
+
+Reported-by: Maciej Józefczyk <mjozefcz@redhat.com>
+Acked-by: Han Zhou <hzhou@ovn.org>
+Signed-off-by: Numan Siddique <numans@ovn.org>
+---
+ northd/ovn-northd.8.xml |  5 +++--
+ northd/ovn-northd.c     | 13 ++++++++-----
+ tests/ovn.at            | 16 ++++++++++++----
+ 3 files changed, 23 insertions(+), 11 deletions(-)
+
+diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
+index 9b44720d1..7d03cbc83 100644
+--- a/northd/ovn-northd.8.xml
++++ b/northd/ovn-northd.8.xml
+@@ -699,8 +699,9 @@ output;
+ 
+         <p>
+           These flows are omitted for logical ports (other than router ports or
+-          <code>localport</code> ports) that are down and for logical ports of
+-          type <code>virtual</code>.
++          <code>localport</code> ports) that are down, for logical ports of
++          type <code>virtual</code> and for logical ports with 'unknown'
++          address set.
+         </p>
+       </li>
+ 
+diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
+index 3a77f2e3a..356c5436c 100644
+--- a/northd/ovn-northd.c
++++ b/northd/ovn-northd.c
+@@ -1148,7 +1148,7 @@ struct ovn_port {
+ 
+     bool derived; /* Indicates whether this is an additional port
+                    * derived from nbsp or nbrp. */
+-
++    bool has_unknown; /* If the addresses have 'unknown' defined. */
+     /* The port's peer:
+      *
+      *     - A switch port S of type "router" has a router port R as a peer,
+@@ -2055,8 +2055,11 @@ join_logical_ports(struct northd_context *ctx,
+                 op->lsp_addrs
+                     = xmalloc(sizeof *op->lsp_addrs * nbsp->n_addresses);
+                 for (size_t j = 0; j < nbsp->n_addresses; j++) {
+-                    if (!strcmp(nbsp->addresses[j], "unknown")
+-                        || !strcmp(nbsp->addresses[j], "router")) {
++                    if (!strcmp(nbsp->addresses[j], "unknown")) {
++                        op->has_unknown = true;
++                        continue;
++                    }
++                    if (!strcmp(nbsp->addresses[j], "router")) {
+                         continue;
+                     }
+                     if (is_dynamic_lsp_address(nbsp->addresses[j])) {
+@@ -6123,7 +6126,7 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
+         } else {
+             /*
+              * Add ARP/ND reply flows if either the
+-             *  - port is up or
++             *  - port is up and it doesn't have 'unknown' address defined or
+              *  - port type is router or
+              *  - port type is localport
+              */
+@@ -6132,7 +6135,7 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
+                 continue;
+             }
+ 
+-            if (lsp_is_external(op->nbsp)) {
++            if (lsp_is_external(op->nbsp) || op->has_unknown) {
+                 continue;
+             }
+ 
+diff --git a/tests/ovn.at b/tests/ovn.at
+index 8cdbad743..1b6073ff0 100644
+--- a/tests/ovn.at
++++ b/tests/ovn.at
+@@ -1758,11 +1758,13 @@ for is in 1 2 3; do
+                 sip=`ip_to_hex 192 168 0 $is$js`
+                 tip=`ip_to_hex 192 168 0 $id$jd`
+                 tip_unknown=`ip_to_hex 11 11 11 11`
++                reply_ha=;
+                 if test $d != $s; then
+-                    reply_ha=f000000000$d
+-                else
+-                    reply_ha=
++                    if test $jd != 1; then
++                        reply_ha=f000000000$d
++                    fi
+                 fi
++
+                 test_arp $s f000000000$s $sip $tip $reply_ha               #9
+                 test_arp $s f000000000$s $sip $tip_unknown                 #10
+ 
+@@ -2199,7 +2201,13 @@ for s in 1 2 3; do
+         sip=192.168.0.$s
+         tip=192.168.0.$d
+         tip_unknown=11.11.11.11
+-        if test $d != $s; then reply_ha=f0:00:00:00:00:0$d; else reply_ha=; fi
++        reply_ha=;
++        if test $d != $s; then
++            if test $d != 1; then
++                reply_ha=f0:00:00:00:00:0$d;
++            fi
++        fi
++
+         test_arp $s f0:00:00:00:00:0$s $sip $tip $reply_ha                 #9
+         test_arp $s f0:00:00:00:00:0$s $sip $tip_unknown                   #10
+ 
+-- 
+2.24.1
+
diff --git a/SOURCES/0001-ovn-northd-Fix-leak-of-lport-addresses-during-DHCPv6.patch b/SOURCES/0001-ovn-northd-Fix-leak-of-lport-addresses-during-DHCPv6.patch
new file mode 100644
index 0000000..7d1d91b
--- /dev/null
+++ b/SOURCES/0001-ovn-northd-Fix-leak-of-lport-addresses-during-DHCPv6.patch
@@ -0,0 +1,62 @@
+From c0d305f985cb1a8533950d4f17107d9a71635644 Mon Sep 17 00:00:00 2001
+From: Ilya Maximets <i.maximets@ovn.org>
+Date: Tue, 12 May 2020 12:44:06 +0200
+Subject: [PATCH 1/2] ovn-northd: Fix leak of lport addresses during DHCPv6
+ reply handling.
+
+'lrp_networks' never destroyed but constantly overwritten in a loop that
+handles DHCPv6 replies.  In some cases this point leaks several MB per
+minute making ovn-northd to constantly growing its memory consumption:
+
+ 399,820,764 bytes in 1,885,947 blocks are definitely lost in loss record 182 of 182
+    at 0x4839748: malloc (vg_replace_malloc.c:308)
+    by 0x483BD63: realloc (vg_replace_malloc.c:836)
+    by 0x1E7BF8: xrealloc (util.c:149)
+    by 0x152723: add_ipv6_netaddr.isra.0 (ovn-util.c:55)
+    by 0x152F1C: extract_lrp_networks (ovn-util.c:275)
+    by 0x142EE2: build_lrouter_flows (ovn-northd.c:8607)
+    by 0x142EE2: build_lflows.isra.0 (ovn-northd.c:10296)
+    by 0x14E4F8: ovnnb_db_run (ovn-northd.c:11128)
+    by 0x14E4F8: ovn_db_run (ovn-northd.c:11672)
+    by 0x13304D: main (ovn-northd.c:12035)
+
+In fact, there is no need to allocate this memory at all, since all the
+required information is already available in 'op->lrp_networks'.
+
+Reported-by: Joe Talerico <jtaleric@redhat.com>
+Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=1827769
+Fixes: 5c1d2d230773 ("northd: Add logical flows for dhcpv6 pfd parsing")
+Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
+Acked-by: Mark Michelson <mmichels@redhat.com>
+Signed-off-by: Numan Siddique <numans@ovn.org>
+---
+ northd/ovn-northd.c | 9 ++-------
+ 1 file changed, 2 insertions(+), 7 deletions(-)
+
+diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
+index b07e68cfa..c1cdb2280 100644
+--- a/northd/ovn-northd.c
++++ b/northd/ovn-northd.c
+@@ -8603,17 +8603,12 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
+             continue;
+         }
+ 
+-        struct lport_addresses lrp_networks;
+-        if (!extract_lrp_networks(op->nbrp, &lrp_networks)) {
+-            continue;
+-        }
+-
+-        for (size_t i = 0; i < lrp_networks.n_ipv6_addrs; i++) {
++        for (size_t i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) {
+             ds_clear(&actions);
+             ds_clear(&match);
+             ds_put_format(&match, "ip6.dst == %s && udp.src == 547 &&"
+                           " udp.dst == 546",
+-                          lrp_networks.ipv6_addrs[i].addr_s);
++                          op->lrp_networks.ipv6_addrs[i].addr_s);
+             ds_put_format(&actions, "reg0 = 0; handle_dhcpv6_reply;");
+             ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 100,
+                           ds_cstr(&match), ds_cstr(&actions));
+-- 
+2.26.2
+
diff --git a/SOURCES/0001-ovn-northd-Fix-the-missing-lflow-issue-in-LS_OUT_PRE.patch b/SOURCES/0001-ovn-northd-Fix-the-missing-lflow-issue-in-LS_OUT_PRE.patch
new file mode 100644
index 0000000..3d0d04c
--- /dev/null
+++ b/SOURCES/0001-ovn-northd-Fix-the-missing-lflow-issue-in-LS_OUT_PRE.patch
@@ -0,0 +1,131 @@
+From 7aa75981dfc17eb7f0ac9ee7300e346f3b6a0c8e Mon Sep 17 00:00:00 2001
+From: Numan Siddique <numans@ovn.org>
+Date: Tue, 7 Jul 2020 18:30:20 +0530
+Subject: [PATCH 1/5] ovn-northd: Fix the missing lflow issue in LS_OUT_PRE_LB.
+
+When load balancer(s) configured with VIPs are associated to a logical switch,
+then ovn-northd adds the below logical flow so that the packets in the egress
+switch pipeline enter the conntrack.
+
+table=0 (ls_out_pre_lb      ), priority=100  , match=(ip), action=(reg0[[0]] = 1; next;)
+
+ovn-northd maintains a local boolean variable 'vip_configured' in
+build_pre_lb() and adds the above lflow if this is true at the end.
+But this variable is overriden as -> vip_configured = !!lb->n_vips;
+when it loops through every load balancer associated with the logical switch.
+
+This is wrong and this patch fixes this issue.
+
+A test case is addd to test this scenario and the test case fails without the
+fix in this patch.
+
+Fixes: bb9f2b9ce56c("ovn-northd: Consider load balancer active backends in router pipeline")
+
+Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=1849162
+Reported-by: Tim Rozet <trozet@redhat.com>
+Acked-by: Dumitru Ceara <dceara@redhat.com>
+Signed-off-by: Numan Siddique <numans@ovn.org>
+
+(cherry-picked from master commit 59af6f9048946e16813ad7ad4e453b85989670e4)
+---
+ northd/ovn-northd.c |  2 +-
+ tests/ovn-northd.at | 73 +++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 74 insertions(+), 1 deletion(-)
+
+diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
+index 8a809d020..2b891c68f 100644
+--- a/northd/ovn-northd.c
++++ b/northd/ovn-northd.c
+@@ -4932,7 +4932,7 @@ build_pre_lb(struct ovn_datapath *od, struct hmap *lflows,
+              * table, we will eventually look at L4 information. */
+         }
+ 
+-        vip_configured = !!lb->n_vips;
++        vip_configured = (vip_configured || lb->n_vips);
+     }
+ 
+     /* 'REGBIT_CONNTRACK_DEFRAG' is set to let the pre-stateful table send
+diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
+index 37805d3d8..842800b90 100644
+--- a/tests/ovn-northd.at
++++ b/tests/ovn-northd.at
+@@ -1485,3 +1485,76 @@ lsp2
+ ])
+ 
+ AT_CLEANUP
++
++# This test case tests that when a logical switch has load balancers associated
++# (with VIPs configured), the below logical flow is added by ovn-northd.
++# table=0 (ls_out_pre_lb      ), priority=100  , match=(ip), action=(reg0[[0]] = 1; next;)
++# This test case is added for the BZ -
++# https://bugzilla.redhat.com/show_bug.cgi?id=1849162
++#
++# ovn-northd was not adding the above lflow if the last load balancer associated
++# to the logical switch doesn't have the VIP configured even if other load
++# balancers before the last one in the last have VIPs configured.
++# So make sure that the above lflow is added even if one load balancer has VIP
++# associated.
++
++AT_SETUP([ovn -- Load balancer - missing ls_out_pre_lb flows])
++ovn_start
++
++ovn-nbctl ls-add sw0
++ovn-nbctl lsp-add sw0 sw0-p1
++
++ovn-nbctl lb-add lb1 "10.0.0.10" "10.0.0.3"
++ovn-nbctl lb-add lb2 "10.0.0.11" "10.0.0.4"
++
++ovn-nbctl --wait=sb sync
++AT_CHECK([ovn-sbctl lflow-list | grep "ls_out_pre_lb.*priority=100" | grep reg0 | sort], [0], [dnl
++])
++
++ovn-nbctl ls-lb-add sw0 lb1
++ovn-nbctl --wait=sb sync
++AT_CHECK([ovn-sbctl lflow-list | grep "ls_out_pre_lb.*priority=100" | grep reg0 | sort], [0], [dnl
++  table=0 (ls_out_pre_lb      ), priority=100  , match=(ip), action=(reg0[[0]] = 1; next;)
++])
++
++ovn-nbctl ls-lb-add sw0 lb2
++ovn-nbctl --wait=sb sync
++AT_CHECK([ovn-sbctl lflow-list | grep "ls_out_pre_lb.*priority=100" | grep reg0 | sort], [0], [dnl
++  table=0 (ls_out_pre_lb      ), priority=100  , match=(ip), action=(reg0[[0]] = 1; next;)
++])
++
++lb1_uuid=$(ovn-nbctl --bare --columns _uuid find load_balancer name=lb1)
++lb2_uuid=$(ovn-nbctl --bare --columns _uuid find load_balancer name=lb2)
++
++ovn-nbctl clear load_balancer $lb1_uuid vips
++ovn-nbctl --wait=sb sync
++AT_CHECK([ovn-sbctl lflow-list | grep "ls_out_pre_lb.*priority=100" | grep reg0 | sort], [0], [dnl
++  table=0 (ls_out_pre_lb      ), priority=100  , match=(ip), action=(reg0[[0]] = 1; next;)
++])
++
++ovn-nbctl clear load_balancer $lb2_uuid vips
++ovn-nbctl --wait=sb sync
++AT_CHECK([ovn-sbctl lflow-list | grep "ls_out_pre_lb.*priority=100" | grep reg0 | sort], [0], [dnl
++])
++
++ovn-nbctl set load_balancer $lb1_uuid vips:"10.0.0.10"="10.0.0.3"
++ovn-nbctl set load_balancer $lb2_uuid vips:"10.0.0.11"="10.0.0.4"
++
++ovn-nbctl --wait=sb sync
++AT_CHECK([ovn-sbctl lflow-list | grep "ls_out_pre_lb.*priority=100" | grep reg0 | sort], [0], [dnl
++  table=0 (ls_out_pre_lb      ), priority=100  , match=(ip), action=(reg0[[0]] = 1; next;)
++])
++
++# Now reverse the order of clearing the vip.
++ovn-nbctl clear load_balancer $lb2_uuid vips
++ovn-nbctl --wait=sb sync
++AT_CHECK([ovn-sbctl lflow-list | grep "ls_out_pre_lb.*priority=100" | grep reg0 | sort], [0], [dnl
++  table=0 (ls_out_pre_lb      ), priority=100  , match=(ip), action=(reg0[[0]] = 1; next;)
++])
++
++ovn-nbctl clear load_balancer $lb1_uuid vips
++ovn-nbctl --wait=sb sync
++AT_CHECK([ovn-sbctl lflow-list | grep "ls_out_pre_lb.*priority=100" | grep reg0 | sort], [0], [dnl
++])
++
++AT_CLEANUP
+-- 
+2.26.2
+
diff --git a/SOURCES/0001-ovn-northd-Forward-ARP-requests-on-localnet-ports.patch b/SOURCES/0001-ovn-northd-Forward-ARP-requests-on-localnet-ports.patch
new file mode 100644
index 0000000..742c212
--- /dev/null
+++ b/SOURCES/0001-ovn-northd-Forward-ARP-requests-on-localnet-ports.patch
@@ -0,0 +1,321 @@
+From 20bf8b836703f3ad984e6679510ea215655479a5 Mon Sep 17 00:00:00 2001
+From: Dumitru Ceara <dceara@redhat.com>
+Date: Tue, 24 Mar 2020 11:03:29 +0100
+Subject: [PATCH ovn] ovn-northd: Forward ARP requests on localnet ports.
+
+Commit 32f5ebb06226 limited the ARP/ND broadcast domain but in scenarios
+where ARP responder flows are installed only on chassis that own the
+associated logical ports ARP requests should still be forwarded on
+localnet ports because the router pipeline should be executed on the
+chassis that owns the logical port. Only that chassis will reply to the
+ARP/ND request.
+
+Reported-by: Michael Plato <michael.plato@tu-berlin.de>
+Reported-at: https://mail.openvswitch.org/pipermail/ovs-discuss/2020-March/049856.html
+Fixes: 32f5ebb06226 ("ovn-northd: Limit ARP/ND broadcast domain whenever possible.")
+Signed-off-by: Dumitru Ceara <dceara@redhat.com>
+Signed-off-by: Numan Siddique <numans@ovn.org>
+(cherry picked from upstream commit 9f13732ae232aa0c872527d948435125b3a6cbce)
+
+Change-Id: I86b18043821f24bf491c9b85381c5d008f7f2307
+---
+ northd/ovn-northd.8.xml |   3 +-
+ northd/ovn-northd.c     |   6 +-
+ tests/ovn.at            | 169 ++++++++++++++++++++++++++++++++++++++++++++----
+ 3 files changed, 162 insertions(+), 16 deletions(-)
+
+diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
+index 7d03cbc..1e0993e 100644
+--- a/northd/ovn-northd.8.xml
++++ b/northd/ovn-northd.8.xml
+@@ -1194,7 +1194,8 @@ output;
+         Priority-75 flows for each IP address/VIP/NAT address owned by a
+         router port connected to the switch. These flows match ARP requests
+         and ND packets for the specific IP addresses.  Matched packets are
+-        forwarded only to the router that owns the IP address.
++        forwarded only to the router that owns the IP address and, if
++        present, to the localnet port of the logical switch.
+       </li>
+ 
+       <li>
+diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
+index 356c543..787ca2f 100644
+--- a/northd/ovn-northd.c
++++ b/northd/ovn-northd.c
+@@ -5899,8 +5899,12 @@ build_lswitch_rport_arp_req_flow_for_ip(struct sset *ips,
+     ds_put_cstr(&match, "}");
+ 
+     /* Send a the packet only to the router pipeline and skip flooding it
+-     * in the broadcast domain.
++     * in the broadcast domain (except for the localnet port).
+      */
++    if (od->localnet_port) {
++        ds_put_format(&actions, "clone { outport = %s; output; }; ",
++                      od->localnet_port->json_key);
++    }
+     ds_put_format(&actions, "outport = %s; output;", patch_op->json_key);
+     ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_L2_LKUP, priority,
+                             ds_cstr(&match), ds_cstr(&actions), stage_hint);
+diff --git a/tests/ovn.at b/tests/ovn.at
+index 1b6073f..4baf2e9 100644
+--- a/tests/ovn.at
++++ b/tests/ovn.at
+@@ -17928,13 +17928,14 @@ net_add n1
+ sim_add hv1
+ as hv1
+ ovs-vsctl add-br br-phys
++ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys
+ ovn_attach n1 br-phys 192.168.0.1
+ 
+-ovs-vsctl -- add-port br-int hv1-vif1 -- \
+-    set interface hv1-vif1 external-ids:iface-id=sw-agg-ext \
+-    options:tx_pcap=hv1/vif1-tx.pcap \
+-    options:rxq_pcap=hv1/vif1-rx.pcap \
+-    ofport-request=1
++sim_add hv2
++as hv2
++ovs-vsctl add-br br-phys
++ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys
++ovn_attach n1 br-phys 192.168.0.2
+ 
+ # One Aggregation Switch connected to two Logical networks (routers).
+ ovn-nbctl ls-add sw-agg
+@@ -17950,18 +17951,66 @@ ovn-nbctl lsp-add sw-agg sw-rtr2                   \
+     -- lsp-set-addresses sw-rtr2 00:00:00:00:02:00 \
+     -- lsp-set-options sw-rtr2 router-port=rtr2-sw
+ 
+-# Configure L3 interface IPv4 & IPv6 on both routers
++# Localnet port on the Aggregation Switch.
++ovn-nbctl lsp-add sw-agg sw-agg-ln
++ovn-nbctl lsp-set-addresses sw-agg-ln unknown
++ovn-nbctl lsp-set-type sw-agg-ln localnet
++ovn-nbctl lsp-set-options sw-agg-ln network_name=phys
++
++# Configure L3 interface IPv4 & IPv6 on both routers.
+ ovn-nbctl lr-add rtr1
+ ovn-nbctl lrp-add rtr1 rtr1-sw 00:00:00:00:01:00 10.0.0.1/24 10::1/64
+ 
++ovn-nbctl lrp-add rtr1 rtr1-sw1 00:00:01:00:00:00 20.0.0.1/24 20::1/64
++
+ ovn-nbctl lr-add rtr2
+ ovn-nbctl lrp-add rtr2 rtr2-sw 00:00:00:00:02:00 10.0.0.2/24 10::2/64
+ 
++# Configure router gateway ports.
++ovn-nbctl lrp-set-gateway-chassis rtr1-sw hv1 20
++ovn-nbctl lrp-set-gateway-chassis rtr2-sw hv1 20
++
++# One private network behind rtr1 with two VMs.
++ovn-nbctl ls-add sw1
++ovn-nbctl lsp-add sw1 sw1-p1 \
++    -- lsp-set-addresses sw1-p1 00:00:00:01:00:00
++ovn-nbctl lsp-add sw1 sw1-p2 \
++    -- lsp-set-addresses sw1-p2 00:00:00:02:00:00
++ovn-nbctl lsp-add sw1 sw1-rtr1                       \
++    -- lsp-set-type sw1-rtr1 router                  \
++    -- lsp-set-addresses sw1-rtr1 00:00:01:00:00:00  \
++    -- lsp-set-options sw1-rtr1 router-port=rtr1-sw1
++
++# Bind a "VM" connected to sw-agg on hv1.
++as hv1
++ovs-vsctl -- add-port br-int hv1-vif0 -- \
++    set interface hv1-vif0 external-ids:iface-id=sw-agg-ext \
++    options:tx_pcap=hv1/vif0-tx.pcap \
++    options:rxq_pcap=hv1/vif0-rx.pcap \
++    ofport-request=1
++
++# Bind a "VM" connected to sw1 on hv1.
++as hv1
++ovs-vsctl -- add-port br-int hv1-vif1 -- \
++    set interface hv1-vif1 external-ids:iface-id=sw1-p1 \
++    options:tx_pcap=hv1/vif1-tx.pcap \
++    options:rxq_pcap=hv1/vif1-rx.pcap \
++    ofport-request=2
++
++# Bind a "VM" connected to sw1 on hv2.
++as hv2
++ovs-vsctl -- add-port br-int hv1-vif2 -- \
++    set interface hv1-vif2 external-ids:iface-id=sw1-p2 \
++    options:tx_pcap=hv1/vif2-tx.pcap \
++    options:rxq_pcap=hv1/vif2-rx.pcap \
++    ofport-request=3
++
+ OVN_POPULATE_ARP
+ ovn-nbctl --wait=hv sync
+ 
+ sw_dp_uuid=$(ovn-sbctl --bare --columns _uuid list datapath_binding sw-agg)
+ sw_dp_key=$(ovn-sbctl --bare --columns tunnel_key list datapath_binding sw-agg)
++r1_dp_key=$(ovn-sbctl --bare --columns tunnel_key list datapath_binding rtr1)
+ 
+ r1_tnl_key=$(ovn-sbctl --bare --columns tunnel_key list port_binding sw-rtr1)
+ r2_tnl_key=$(ovn-sbctl --bare --columns tunnel_key list port_binding sw-rtr2)
+@@ -17970,9 +18019,10 @@ mc_key=$(ovn-sbctl --bare --columns tunnel_key find multicast_group datapath=${s
+ mc_key=$(printf "%04x" $mc_key)
+ 
+ match_sw_metadata="metadata=0x${sw_dp_key}"
++match_r1_metadata="metadata=0x${r1_dp_key}"
+ 
+ # Inject ARP request for first router owned IP address.
+-send_arp_request 1 1 ${src_mac} $(ip_to_hex 10 0 0 254) $(ip_to_hex 10 0 0 1)
++send_arp_request 1 0 ${src_mac} $(ip_to_hex 10 0 0 254) $(ip_to_hex 10 0 0 1)
+ 
+ # Verify that the ARP request is sent only to rtr1.
+ match_arp_req="priority=75.*${match_sw_metadata}.*arp_tpa=10.0.0.1,arp_op=1"
+@@ -18001,7 +18051,7 @@ OVS_WAIT_UNTIL([
+ # Inject ND_NS for ofirst router owned IP address.
+ src_ipv6=00100000000000000000000000000254
+ dst_ipv6=00100000000000000000000000000001
+-send_nd_ns 1 1 ${src_mac} ${src_ipv6} ${dst_ipv6} 751d
++send_nd_ns 1 0 ${src_mac} ${src_ipv6} ${dst_ipv6} 751d
+ 
+ # Verify that the ND_NS is sent only to rtr1.
+ match_nd_ns="priority=75.*${match_sw_metadata}.*icmp_type=135.*nd_target=10::1"
+@@ -18038,7 +18088,7 @@ ovn-nbctl lr-lb-add rtr2 lb2-v6
+ ovn-nbctl --wait=hv sync
+ 
+ # Inject ARP request for first router owned VIP address.
+-send_arp_request 1 1 ${src_mac} $(ip_to_hex 10 0 0 254) $(ip_to_hex 10 0 0 11)
++send_arp_request 1 0 ${src_mac} $(ip_to_hex 10 0 0 254) $(ip_to_hex 10 0 0 11)
+ 
+ # Verify that the ARP request is sent only to rtr1.
+ match_arp_req="priority=75.*${match_sw_metadata}.*arp_tpa=10.0.0.11,arp_op=1"
+@@ -18067,7 +18117,7 @@ OVS_WAIT_UNTIL([
+ # Inject ND_NS for first router owned VIP address.
+ src_ipv6=00100000000000000000000000000254
+ dst_ipv6=00100000000000000000000000000011
+-send_nd_ns 1 1 ${src_mac} ${src_ipv6} ${dst_ipv6} 751d
++send_nd_ns 1 0 ${src_mac} ${src_ipv6} ${dst_ipv6} 751d
+ 
+ # Verify that the ND_NS is sent only to rtr1.
+ match_nd_ns="priority=75.*${match_sw_metadata}.*icmp_type=135.*nd_target=10::11"
+@@ -18091,14 +18141,21 @@ OVS_WAIT_UNTIL([
+     test "0" = "${pkts_flooded}"
+ ])
+ 
+-# Configure NAT on both routers
++# Configure NAT on both routers.
+ ovn-nbctl lr-nat-add rtr1 dnat_and_snat 10.0.0.111 42.42.42.1
+ ovn-nbctl lr-nat-add rtr1 dnat_and_snat 10::111 42::1
+ ovn-nbctl lr-nat-add rtr2 dnat_and_snat 10.0.0.222 42.42.42.2
+ ovn-nbctl lr-nat-add rtr2 dnat_and_snat 10::222 42::2
+ 
++# Configure FIP1 and FIP2 on rtr1 for sw1-p1 and sw1-p2.
++ovn-nbctl lr-nat-add rtr1 dnat_and_snat 10.0.0.121 20.0.0.11 sw1-p1 00:00:00:01:00:00
++ovn-nbctl lr-nat-add rtr1 dnat_and_snat 10::121 20::11 sw1-p1 00:00:00:01:00:00
++ovn-nbctl lr-nat-add rtr1 dnat_and_snat 10.0.0.122 20.0.0.12 sw1-p2 00:00:00:02:00:00
++ovn-nbctl lr-nat-add rtr1 dnat_and_snat 10::122 20::12 sw1-p2 00:00:00:02:00:00
++ovn-nbctl --wait=hv sync
++
+ # Inject ARP request for first router owned NAT address.
+-send_arp_request 1 1 ${src_mac} $(ip_to_hex 10 0 0 254) $(ip_to_hex 10 0 0 111)
++send_arp_request 1 0 ${src_mac} $(ip_to_hex 10 0 0 254) $(ip_to_hex 10 0 0 111)
+ 
+ # Verify that the ARP request is sent only to rtr1.
+ match_arp_req="priority=75.*${match_sw_metadata}.*arp_tpa=10.0.0.111,arp_op=1"
+@@ -18124,10 +18181,50 @@ OVS_WAIT_UNTIL([
+     test "0" = "${pkts_flooded}"
+ ])
+ 
++# Inject ARP request for FIP1.
++send_arp_request 1 0 ${src_mac} $(ip_to_hex 10 0 0 254) $(ip_to_hex 10 0 0 121)
++
++# Verify that the ARP request is replied to from hv1 and not hv2.
++match_arp_req="priority=90.*${match_r1_metadata}.*arp_tpa=10.0.0.121,arp_op=1"
++
++as hv1
++OVS_WAIT_UNTIL([
++    pkts_on_rtr1=$(ovs-ofctl dump-flows br-int | \
++    grep -E "${match_arp_req}" | grep n_packets=1 -c)
++    test "1" = "${pkts_on_rtr1}"
++])
++
++as hv2
++OVS_WAIT_UNTIL([
++    pkts_on_rtr1=$(ovs-ofctl dump-flows br-int | \
++    grep -E "${match_arp_req}" | grep n_packets=1 -c)
++    test "0" = "${pkts_on_rtr1}"
++])
++
++# Inject ARP request for FIP2.
++send_arp_request 1 0 ${src_mac} $(ip_to_hex 10 0 0 254) $(ip_to_hex 10 0 0 122)
++
++# Verify that the ARP request is replied to from hv2 and not hv1.
++match_arp_req="priority=90.*${match_r1_metadata}.*arp_tpa=10.0.0.122,arp_op=1"
++
++as hv2
++OVS_WAIT_UNTIL([
++    pkts_on_rtr1=$(ovs-ofctl dump-flows br-int | \
++    grep -E "${match_arp_req}" | grep n_packets=1 -c)
++    test "1" = "${pkts_on_rtr1}"
++])
++
++as hv1
++OVS_WAIT_UNTIL([
++    pkts_on_rtr1=$(ovs-ofctl dump-flows br-int | \
++    grep -E "${match_arp_req}" | grep n_packets=1 -c)
++    test "0" = "${pkts_on_rtr1}"
++])
++
+ # Inject ND_NS for first router owned IP address.
+ src_ipv6=00100000000000000000000000000254
+ dst_ipv6=00100000000000000000000000000111
+-send_nd_ns 1 1 ${src_mac} ${src_ipv6} ${dst_ipv6} 751d
++send_nd_ns 1 0 ${src_mac} ${src_ipv6} ${dst_ipv6} 751d
+ 
+ # Verify that the ND_NS is sent only to rtr1.
+ match_nd_ns="priority=75.*${match_sw_metadata}.*icmp_type=135.*nd_target=10::111"
+@@ -18151,7 +18248,51 @@ OVS_WAIT_UNTIL([
+     test "0" = "${pkts_flooded}"
+ ])
+ 
+-OVN_CLEANUP([hv1])
++# Inject ND_NS for FIP1.
++src_ipv6=00100000000000000000000000000254
++dst_ipv6=00100000000000000000000000000121
++send_nd_ns 1 0 ${src_mac} ${src_ipv6} ${dst_ipv6} 72dd
++
++# Verify that the ND_NS is replied to from hv1 and not hv2.
++match_nd_ns="priority=90.*${match_r1_metadata}.*icmp_type=135.*nd_target=10::121"
++
++as hv1
++OVS_WAIT_UNTIL([
++    pkts_on_rtr1=$(ovs-ofctl dump-flows br-int | \
++    grep -E "${match_nd_ns}" | grep n_packets=1 -c)
++    test "1" = "${pkts_on_rtr1}"
++])
++
++as hv2
++OVS_WAIT_UNTIL([
++    pkts_on_rtr1=$(ovs-ofctl dump-flows br-int | \
++    grep -E "${match_nd_ns}" | grep n_packets=1 -c)
++    test "0" = "${pkts_on_rtr1}"
++])
++
++# Inject ND_NS for FIP2.
++src_ipv6=00100000000000000000000000000254
++dst_ipv6=00100000000000000000000000000122
++send_nd_ns 1 0 ${src_mac} ${src_ipv6} ${dst_ipv6} 72db
++
++# Verify that the ND_NS is replied to from hv2 and not hv1.
++match_nd_ns="priority=90.*${match_r1_metadata}.*icmp_type=135.*nd_target=10::122"
++
++as hv2
++OVS_WAIT_UNTIL([
++    pkts_on_rtr1=$(ovs-ofctl dump-flows br-int | \
++    grep -E "${match_nd_ns}" | grep n_packets=1 -c)
++    test "1" = "${pkts_on_rtr1}"
++])
++
++as hv1
++OVS_WAIT_UNTIL([
++    pkts_on_rtr1=$(ovs-ofctl dump-flows br-int | \
++    grep -E "${match_nd_ns}" | grep n_packets=1 -c)
++    test "0" = "${pkts_on_rtr1}"
++])
++
++OVN_CLEANUP([hv1], [hv2])
+ AT_CLEANUP
+ 
+ AT_SETUP([ovn -- trace when flow cookie updated])
+-- 
+1.8.3.1
+
diff --git a/SOURCES/0001-ovn-northd-Limit-IPv6-ND-NS-RA-RS-to-the-local-netwo.patch b/SOURCES/0001-ovn-northd-Limit-IPv6-ND-NS-RA-RS-to-the-local-netwo.patch
new file mode 100644
index 0000000..9ef0d78
--- /dev/null
+++ b/SOURCES/0001-ovn-northd-Limit-IPv6-ND-NS-RA-RS-to-the-local-netwo.patch
@@ -0,0 +1,205 @@
+From d46b2e1f3b31509849441cde28475a8d48a6624f Mon Sep 17 00:00:00 2001
+From: Dumitru Ceara <dceara@redhat.com>
+Date: Fri, 17 Apr 2020 23:54:25 +0200
+Subject: [PATCH] ovn-northd: Limit IPv6 ND NS/RA/RS to the local network.
+
+Neighbor solicitation packets for router owned IPs are replied to in
+table IN_IP_INPUT at a higher priority than flows relay IPv6 multicast
+traffic when needed. All other NS/NA packets received at this point can
+be safely dropped.
+
+However, router advertisement and router solicitation packets are
+processed at a later stage, in ND_RA_OPTIONS/ND_RA_RESPONSE. These
+packets need to be allowed in table IN_IP_INPUT.
+
+Commit 677a3ba4d66b incorrectly allowed all IPv6 multicast traffic
+destined to all-nodes in table IN_IP_INPUT. Instead, only ND_RA and
+ND_RS packets should be allowed. All others were either already
+processed or should be dropped. If multicast relay is enabled then IPv6
+multicast traffic that's not destined to reserved groups should also be
+allowed.
+
+Furthermore, router solicitation and advertisement packets that don't
+get processed in tables ND_RA_OPTIONS/ND_RA_RESPONSE should be dropped
+in IN_IP_ROUTING because they should never be routed.
+
+Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=1825334
+Reported-by: Jakub Libosvar <jlibosva@redhat.com>
+Fixes: 677a3ba4d66b ("ovn: Add MLD support.")
+Signed-off-by: Dumitru Ceara <dceara@redhat.com>
+Signed-off-by: Numan Siddique <numans@ovn.org>
+
+(cherry-picked from upstream branch-20.03 commit 0924bcb07ef25f93fde683fe8f15d376eca005ec)
+
+Change-Id: I1d060e5d40f344b890974e6ad0c0960ea280f050
+---
+ northd/ovn-northd.8.xml | 49 +++++++++++++++++++++++++++--------------
+ northd/ovn-northd.c     | 43 +++++++++++++++++++++++++-----------
+ 2 files changed, 62 insertions(+), 30 deletions(-)
+
+diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
+index 82c86f636..efcc4b7fc 100644
+--- a/northd/ovn-northd.8.xml
++++ b/northd/ovn-northd.8.xml
+@@ -1668,22 +1668,6 @@ next;
+           router.
+       </li>
+ 
+-      <li>
+-        <p>
+-          A priority-87 flow explicitly allows IPv6 multicast traffic that is
+-          supposed to reach the router pipeline (e.g., neighbor solicitations
+-          and traffic destined to the All-Routers multicast group).
+-        </p>
+-      </li>
+-
+-      <li>
+-        <p>
+-          A priority-86 flow allows IP multicast traffic if
+-          <ref column="options" table="Logical_Router"/>:mcast_relay='true',
+-          otherwise drops it.
+-        </p>
+-      </li>
+-
+       <li>
+         <p>
+           ICMP echo reply.  These flows reply to ICMP echo requests received
+@@ -1944,6 +1928,29 @@ nd.tll = <var>external_mac</var>;
+         packets.
+       </li>
+ 
++      <li>
++        <p>
++          A priority-84 flow explicitly allows IPv6 multicast traffic that is
++          supposed to reach the router pipeline (i.e., router solicitation
++          and router advertisement packets).
++        </p>
++      </li>
++
++      <li>
++        <p>
++          A priority-83 flow explicitly drops IPv6 multicast traffic that is
++          destined to reserved multicast groups.
++        </p>
++      </li>
++
++      <li>
++        <p>
++          A priority-82 flow allows IP multicast traffic if
++          <ref column="options" table="Logical_Router"/>:mcast_relay='true',
++          otherwise drops it.
++        </p>
++      </li>
++
+       <li>
+         <p>
+           UDP port unreachable.  Priority-80 flows generate ICMP port
+@@ -2440,6 +2447,13 @@ output;
+     </p>
+ 
+     <ul>
++      <li>
++        <p>
++          Priority-550 flow that drops IPv6 Router Solicitation/Advertisement
++          packets that were not processed in previous tables.
++        </p>
++      </li>
++
+       <li>
+         <p>
+           Priority-500 flows that match IP multicast traffic destined to
+@@ -2457,7 +2471,8 @@ output;
+           multicast group, which <code>ovn-northd</code> populates with the
+           logical ports that have
+           <ref column="options" table="Logical_Router_Port"/>
+-          <code>:mcast_flood='true'</code>.
++          <code>:mcast_flood='true'</code>. If no router ports are configured
++          to flood multicast traffic the packets are dropped.
+         </p>
+       </li>
+ 
+diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
+index 1f1238d23..f7d3988d7 100644
+--- a/northd/ovn-northd.c
++++ b/northd/ovn-northd.c
+@@ -8002,17 +8002,6 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
+ 
+         /* Priority-90 flows reply to ARP requests and ND packets. */
+ 
+-        /* Allow IPv6 multicast traffic that's supposed to reach the
+-         * router pipeline (e.g., neighbor solicitations).
+-         */
+-        ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 87, "ip6.mcast_flood",
+-                      "next;");
+-
+-        /* Allow multicast if relay enabled (priority 86). */
+-        ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 86,
+-                      "ip4.mcast || ip6.mcast",
+-                      od->mcast_info.rtr.relay ? "next;" : "drop;");
+-
+         /* Drop ARP packets (priority 85). ARP request packets for router's own
+          * IPs are handled with priority-90 flows.
+          * Drop IPv6 ND packets (priority 85). ND NA packets for router's own
+@@ -8021,6 +8010,21 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
+         ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 85,
+                       "arp || nd", "drop;");
+ 
++        /* Allow IPv6 multicast traffic that's supposed to reach the
++         * router pipeline (e.g., router solicitations).
++         */
++        ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 84, "nd_rs || nd_ra",
++                      "next;");
++
++        /* Drop other reserved multicast. */
++        ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 83,
++                      "ip6.mcast_rsvd", "drop;");
++
++        /* Allow other multicast if relay enabled (priority 82). */
++        ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 82,
++                      "ip4.mcast || ip6.mcast",
++                      od->mcast_info.rtr.relay ? "next;" : "drop;");
++
+         /* Drop Ethernet local broadcast.  By definition this traffic should
+          * not be forwarded.*/
+         ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 50,
+@@ -9520,7 +9524,17 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
+      * advance to next table (priority 500).
+      */
+     HMAP_FOR_EACH (od, key_node, datapaths) {
+-        if (!od->nbr || !od->mcast_info.rtr.relay) {
++        if (!od->nbr) {
++            continue;
++        }
++
++        /* Drop IPv6 multicast traffic that shouldn't be forwarded,
++         * i.e., router solicitation and router advertisement.
++         */
++        ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 550,
++                      "nd_rs || nd_ra", "drop;");
++
++        if (!od->mcast_info.rtr.relay) {
+             continue;
+         }
+ 
+@@ -9551,7 +9565,7 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
+         }
+ 
+         /* If needed, flood unregistered multicast on statically configured
+-         * ports.
++         * ports. Otherwise drop any multicast traffic.
+          */
+         if (od->mcast_info.rtr.flood_static) {
+             ds_clear(&actions);
+@@ -9562,6 +9576,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
+                                 "ip.ttl--; "
+                                 "next; "
+                           "};");
++        } else {
++            ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 450,
++                          "ip4.mcast || ip6.mcast", "drop;");
+         }
+     }
+ 
+-- 
+2.25.1
+
diff --git a/SOURCES/0001-ovn-northd-Optimize-flows-for-LB-Hairpin-traffic.patch b/SOURCES/0001-ovn-northd-Optimize-flows-for-LB-Hairpin-traffic.patch
new file mode 100644
index 0000000..6299b4e
--- /dev/null
+++ b/SOURCES/0001-ovn-northd-Optimize-flows-for-LB-Hairpin-traffic.patch
@@ -0,0 +1,185 @@
+From 74e1bf4dd0f6c62602ab708eabb5534a274a4d75 Mon Sep 17 00:00:00 2001
+From: Dumitru Ceara <dceara@redhat.com>
+Date: Tue, 28 Apr 2020 12:39:26 +0200
+Subject: [PATCH] ovn-northd: Optimize flows for LB Hairpin traffic.
+
+In order to detect that traffic was hairpinned due to logical switch load
+balancers we need to match on source and destination IPs of packets (and
+protocol ports potentially) in table ls_in_pre_hairpin.
+
+For this, until now, we created 2 logical flows for each backend of a load
+balancer VIP. However, in scenarios where large load balancers (i.e.,
+with large numbers of backends) are applied to multiple logical
+switches, this might generate logical flow count explosion.
+
+One optimization is to generate a single logical flow per VIP that
+combines all conditions generated for each backend. This reduces load on
+the SB DB because of lower number of logical flows and also reduces
+overall DB size because of less overhead due to other fields on the
+logical_flow records.
+
+Comparison of various performance aspects when running OVN with the NB
+database attached to the bug report on a deployment with all VIFs bound
+to a single node (62 load balancer VIPs with 513 load balancer
+backends, applied on 106 logical switches):
+
+Without this patch:
+- SB database size: 60MB
+- # of pre-hairpin logical flows: 109074
+- # of logical flows: 159414
+- ovn-controller max loop iteration time when processing SB DB: 8803ms
+- ovn-northd max loop iteration time: 3988ms
+
+With this patch:
+- SB database size: 29MB (~50% decrease)
+- # of pre-hairpin logical flows: 13250 (~88% decrease)
+- # of logical flows: 63590 (~60% decrease)
+- ovn-controller max loop iteration time when processing SB DB: 5585ms
+- ovn-northd max loop iteration time: 1594ms
+
+Reported-by: Aniket Bhat <anbhat@redhat.com>
+Reported-at: https://bugzilla.redhat.com/1827403
+Fixes: 1be8ac65bc60 ("ovn-northd: Support hairpinning for logical switch load balancing.")
+Signed-off-by: Dumitru Ceara <dceara@redhat.com>
+Signed-off-by: Numan Siddique <numans@ovn.org>
+(cherry picked from upstream commit 97e82ae5f135a088c9e95b49122d8217718d23f4)
+
+Change-Id: Id713209f8bd159e8ad924e91681bab784606faff
+---
+ northd/ovn-northd.8.xml |  4 +--
+ northd/ovn-northd.c     | 79 ++++++++++++++++++++++++++++++++-----------------
+ 2 files changed, 54 insertions(+), 29 deletions(-)
+
+diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
+index d39e259..1f81742 100644
+--- a/northd/ovn-northd.8.xml
++++ b/northd/ovn-northd.8.xml
+@@ -559,14 +559,14 @@
+     <h3>Ingress Table 11: Pre-Hairpin</h3>
+     <ul>
+       <li>
+-        For all configured load balancer backends a priority-2 flow that
++        For all configured load balancer VIPs a priority-2 flow that
+         matches on traffic that needs to be hairpinned, i.e., after load
+         balancing the destination IP matches the source IP, which sets
+         <code>reg0[6] = 1 </code> and executes <code>ct_snat(VIP)</code>
+         to force replies to these packets to come back through OVN.
+       </li>
+       <li>
+-        For all configured load balancer backends a priority-1 flow that
++        For all configured load balancer VIPs a priority-1 flow that
+         matches on replies to hairpinned traffic, i.e., destination IP is VIP,
+         source IP is the backend IP and source L4 port is backend port, which
+         sets <code>reg0[6] = 1 </code> and executes <code>ct_snat;</code>.
+diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
+index 0082e2e..5ada3ae 100644
+--- a/northd/ovn-northd.c
++++ b/northd/ovn-northd.c
+@@ -5542,52 +5542,77 @@ build_lb_hairpin_rules(struct ovn_datapath *od, struct hmap *lflows,
+                        struct ovn_lb *lb, struct lb_vip *lb_vip,
+                        const char *ip_match, const char *proto)
+ {
++    if (lb_vip->n_backends == 0) {
++        return;
++    }
++
++    struct ds action = DS_EMPTY_INITIALIZER;
++    struct ds match_initiator = DS_EMPTY_INITIALIZER;
++    struct ds match_reply = DS_EMPTY_INITIALIZER;
++    struct ds proto_match = DS_EMPTY_INITIALIZER;
++
+     /* Ingress Pre-Hairpin table.
+-     * - Priority 2: SNAT load balanced traffic that needs to be hairpinned.
++     * - Priority 2: SNAT load balanced traffic that needs to be hairpinned:
++     *   - Both SRC and DST IP match backend->ip and destination port
++     *     matches backend->port.
+      * - Priority 1: unSNAT replies to hairpinned load balanced traffic.
++     *   - SRC IP matches backend->ip, DST IP matches LB VIP and source port
++     *     matches backend->port.
+      */
++    ds_put_char(&match_reply, '(');
+     for (size_t i = 0; i < lb_vip->n_backends; i++) {
+         struct lb_vip_backend *backend = &lb_vip->backends[i];
+-        struct ds action = DS_EMPTY_INITIALIZER;
+-        struct ds match = DS_EMPTY_INITIALIZER;
+-        struct ds proto_match = DS_EMPTY_INITIALIZER;
+ 
+         /* Packets that after load balancing have equal source and
+-         * destination IPs should be hairpinned. SNAT them so that the reply
+-         * traffic is directed also through OVN.
++         * destination IPs should be hairpinned.
+          */
+         if (lb_vip->vip_port) {
+-            ds_put_format(&proto_match, " && %s && %s.dst == %"PRIu16,
+-                          proto, proto, backend->port);
++            ds_put_format(&proto_match, " && %s.dst == %"PRIu16,
++                          proto, backend->port);
+         }
+-        ds_put_format(&match, "%s.src == %s && %s.dst == %s%s",
++        ds_put_format(&match_initiator, "(%s.src == %s && %s.dst == %s%s)",
+                       ip_match, backend->ip, ip_match, backend->ip,
+                       ds_cstr(&proto_match));
+-        ds_put_format(&action, REGBIT_HAIRPIN " = 1; ct_snat(%s);",
+-                      lb_vip->vip);
+-        ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_PRE_HAIRPIN, 2,
+-                                ds_cstr(&match), ds_cstr(&action),
+-                                &lb->nlb->header_);
+ 
+-        /* If the packets are replies for hairpinned traffic, UNSNAT them. */
++        /* Replies to hairpinned traffic are originated by backend->ip:port. */
+         ds_clear(&proto_match);
+-        ds_clear(&match);
+         if (lb_vip->vip_port) {
+-            ds_put_format(&proto_match, " && %s && %s.src == %"PRIu16,
+-                          proto, proto, backend->port);
++            ds_put_format(&proto_match, " && %s.src == %"PRIu16, proto,
++                          backend->port);
+         }
+-        ds_put_format(&match, "%s.src == %s && %s.dst == %s%s",
+-                      ip_match, backend->ip, ip_match, lb_vip->vip,
++        ds_put_format(&match_reply, "(%s.src == %s%s)", ip_match, backend->ip,
+                       ds_cstr(&proto_match));
+-        ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_PRE_HAIRPIN, 1,
+-                                ds_cstr(&match),
+-                                REGBIT_HAIRPIN " = 1; ct_snat;",
+-                                &lb->nlb->header_);
++        ds_clear(&proto_match);
+ 
+-        ds_destroy(&action);
+-        ds_destroy(&match);
+-        ds_destroy(&proto_match);
++        if (i < lb_vip->n_backends - 1) {
++            ds_put_cstr(&match_initiator, " || ");
++            ds_put_cstr(&match_reply, " || ");
++        }
+     }
++    ds_put_char(&match_reply, ')');
++
++    /* SNAT hairpinned initiator traffic so that the reply traffic is
++     * also directed through OVN.
++     */
++    ds_put_format(&action, REGBIT_HAIRPIN " = 1; ct_snat(%s);",
++                  lb_vip->vip);
++    ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_PRE_HAIRPIN, 2,
++                            ds_cstr(&match_initiator), ds_cstr(&action),
++                            &lb->nlb->header_);
++
++    /* Replies to hairpinned traffic are destined to the LB VIP. */
++    ds_put_format(&match_reply, " && %s.dst == %s", ip_match, lb_vip->vip);
++
++    /* UNSNAT replies for hairpinned traffic. */
++    ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_PRE_HAIRPIN, 1,
++                            ds_cstr(&match_reply),
++                            REGBIT_HAIRPIN " = 1; ct_snat;",
++                            &lb->nlb->header_);
++
++    ds_destroy(&action);
++    ds_destroy(&match_initiator);
++    ds_destroy(&match_reply);
++    ds_destroy(&proto_match);
+ }
+ 
+ static void
+-- 
+1.8.3.1
+
diff --git a/SOURCES/0001-ovn-northd-Remove-useless-flow-for-GW_REDIRECT.patch b/SOURCES/0001-ovn-northd-Remove-useless-flow-for-GW_REDIRECT.patch
new file mode 100644
index 0000000..89b38d8
--- /dev/null
+++ b/SOURCES/0001-ovn-northd-Remove-useless-flow-for-GW_REDIRECT.patch
@@ -0,0 +1,74 @@
+From 32972260b50f39d493cc42a78d9648ed668c2aec Mon Sep 17 00:00:00 2001
+Message-Id: <32972260b50f39d493cc42a78d9648ed668c2aec.1590584789.git.lorenzo.bianconi@redhat.com>
+From: Han Zhou <hzhou@ovn.org>
+Date: Tue, 5 May 2020 23:16:09 -0700
+Subject: [PATCH ovn] ovn-northd: Remove useless flow for GW_REDIRECT.
+
+Remove the flow in lr_in_gw_redirect stage:
+
+        A priority-150 logical flow with match
+        <code>outport == <var>GW</var> &amp;&amp;
+        eth.dst == 00:00:00:00:00:00</code> has actions
+        <code>outport = <var>CR</var>; next;</code>, where
+        <var>GW</var> is the logical router distributed gateway
+        port and <var>CR</var> is the <code>chassisredirect</code>
+        port representing the instance of the logical router
+        distributed gateway port on the
+        <code>redirect-chassis</code>.
+
+The commit c0bf32d ("Manage ARP process locally in a DVR scenario") updated
+the priority-100 flow in this stage to priority 200, which makes this
+priority-150 flow useless, because whatever packets matching this flow
+would also match the priority-50 flow.
+
+Cc: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
+Tested-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
+Acked-by: Numan Siddique <numans@ovn.org>
+Signed-off-by: Han Zhou <hzhou@ovn.org>
+Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
+---
+ northd/ovn-northd.8.xml | 12 ------------
+ northd/ovn-northd.c     | 11 -----------
+ 2 files changed, 23 deletions(-)
+
+--- a/northd/ovn-northd.8.xml
++++ b/northd/ovn-northd.8.xml
+@@ -2909,18 +2909,6 @@ icmp4 {
+ 
+     <ul>
+       <li>
+-        A priority-150 logical flow with match
+-        <code>outport == <var>GW</var> &amp;&amp;
+-        eth.dst == 00:00:00:00:00:00</code> has actions
+-        <code>outport = <var>CR</var>; next;</code>, where
+-        <var>GW</var> is the logical router distributed gateway
+-        port and <var>CR</var> is the <code>chassisredirect</code>
+-        port representing the instance of the logical router
+-        distributed gateway port on the
+-        <code>redirect-chassis</code>.
+-      </li>
+-
+-      <li>
+         For each NAT rule in the OVN Northbound database that can
+         be handled in a distributed manner, a priority-200 logical
+         flow with match <code>ip4.src == <var>B</var> &amp;&amp;
+--- a/northd/ovn-northd.c
++++ b/northd/ovn-northd.c
+@@ -10143,17 +10143,6 @@ build_lrouter_flows(struct hmap *datapat
+             ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_GW_REDIRECT, 50,
+                                     ds_cstr(&match), ds_cstr(&actions),
+                                     stage_hint);
+-
+-            /* If the Ethernet destination has not been resolved,
+-             * redirect to the central instance of the l3dgw_port.
+-             * Such traffic will be replaced by an ARP request or ND
+-             * Neighbor Solicitation in the ARP request ingress
+-             * table, before being redirected to the central instance.
+-             */
+-            ds_put_format(&match, " && eth.dst == 00:00:00:00:00:00");
+-            ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_GW_REDIRECT, 150,
+-                                    ds_cstr(&match), ds_cstr(&actions),
+-                                    stage_hint);
+         }
+ 
+         /* Packets are allowed by default. */
diff --git a/SOURCES/0001-ovn.at-Fix-ARP-test-that-fails-due-to-timing.patch b/SOURCES/0001-ovn.at-Fix-ARP-test-that-fails-due-to-timing.patch
new file mode 100644
index 0000000..ffc9db8
--- /dev/null
+++ b/SOURCES/0001-ovn.at-Fix-ARP-test-that-fails-due-to-timing.patch
@@ -0,0 +1,113 @@
+From 356501f3246ddb99aef8cd6016467b7c1861b3ff Mon Sep 17 00:00:00 2001
+From: Dumitru Ceara <dceara@redhat.com>
+Date: Tue, 24 Mar 2020 14:35:41 +0100
+Subject: [PATCH ovn] ovn.at: Fix ARP test that fails due to timing.
+
+The test for "ARP/ND request broadcast limiting" checks that injected
+ARP packets are not flooded using the MC_FLOOD multicast group. However,
+this introduces a race condition in the test because GARPs generated by
+OVN would also hit the same openflow rules.
+
+Remove the checks that use the MC_FLOOD group. They are also redundant
+as the rest of the test checks that packets are forwarded according to
+the newly added, higher priority rules.
+
+Fixes: 32f5ebb06226 ("ovn-northd: Limit ARP/ND broadcast domain whenever possible.")
+Signed-off-by: Dumitru Ceara <dceara@redhat.com>
+Signed-off-by: Numan Siddique <numans@ovn.org>
+(cherry picked from upstream commit 598a07cd240d7d01de3d7f04ca7abc58a33977a1)
+
+Change-Id: I4519f441245a5f1ecf7da73257f97aff0c7bc967
+---
+ tests/ovn.at | 33 ---------------------------------
+ 1 file changed, 33 deletions(-)
+
+diff --git a/tests/ovn.at b/tests/ovn.at
+index 4baf2e9..9a44f0a 100644
+--- a/tests/ovn.at
++++ b/tests/ovn.at
+@@ -18015,9 +18015,6 @@ r1_dp_key=$(ovn-sbctl --bare --columns tunnel_key list datapath_binding rtr1)
+ r1_tnl_key=$(ovn-sbctl --bare --columns tunnel_key list port_binding sw-rtr1)
+ r2_tnl_key=$(ovn-sbctl --bare --columns tunnel_key list port_binding sw-rtr2)
+ 
+-mc_key=$(ovn-sbctl --bare --columns tunnel_key find multicast_group datapath=${sw_dp_uuid} name="_MC_flood")
+-mc_key=$(printf "%04x" $mc_key)
+-
+ match_sw_metadata="metadata=0x${sw_dp_key}"
+ match_r1_metadata="metadata=0x${r1_dp_key}"
+ 
+@@ -18042,11 +18039,6 @@ OVS_WAIT_UNTIL([
+     grep n_packets=1 -c)
+     test "0" = "${pkts_to_rtr2}"
+ ])
+-OVS_WAIT_UNTIL([
+-    pkts_flooded=$(ovs-ofctl dump-flows br-int | \
+-    grep -E "${match_sw_metadata}" | grep ${mc_key} | grep -v n_packets=0 -c)
+-    test "0" = "${pkts_flooded}"
+-])
+ 
+ # Inject ND_NS for ofirst router owned IP address.
+ src_ipv6=00100000000000000000000000000254
+@@ -18069,11 +18061,6 @@ OVS_WAIT_UNTIL([
+     grep n_packets=1 -c)
+     test "0" = "${pkts_to_rtr2}"
+ ])
+-OVS_WAIT_UNTIL([
+-    pkts_flooded=$(ovs-ofctl dump-flows br-int | \
+-    grep -E "${match_sw_metadata}" | grep ${mc_key} | grep -v n_packets=0 -c)
+-    test "0" = "${pkts_flooded}"
+-])
+ 
+ # Configure load balancing on both routers.
+ ovn-nbctl lb-add lb1-v4 10.0.0.11 42.42.42.1
+@@ -18108,11 +18095,6 @@ OVS_WAIT_UNTIL([
+     grep n_packets=1 -c)
+     test "0" = "${pkts_to_rtr2}"
+ ])
+-OVS_WAIT_UNTIL([
+-    pkts_flooded=$(ovs-ofctl dump-flows br-int | \
+-    grep -E "${match_sw_metadata}" | grep ${mc_key} | grep -v n_packets=0 -c)
+-    test "0" = "${pkts_flooded}"
+-])
+ 
+ # Inject ND_NS for first router owned VIP address.
+ src_ipv6=00100000000000000000000000000254
+@@ -18135,11 +18117,6 @@ OVS_WAIT_UNTIL([
+     grep n_packets=1 -c)
+     test "0" = "${pkts_to_rtr2}"
+ ])
+-OVS_WAIT_UNTIL([
+-    pkts_flooded=$(ovs-ofctl dump-flows br-int | \
+-    grep -E "${match_sw_metadata}" | grep ${mc_key} | grep -v n_packets=0 -c)
+-    test "0" = "${pkts_flooded}"
+-])
+ 
+ # Configure NAT on both routers.
+ ovn-nbctl lr-nat-add rtr1 dnat_and_snat 10.0.0.111 42.42.42.1
+@@ -18175,11 +18152,6 @@ OVS_WAIT_UNTIL([
+     grep n_packets=1 -c)
+     test "0" = "${pkts_to_rtr2}"
+ ])
+-OVS_WAIT_UNTIL([
+-    pkts_flooded=$(ovs-ofctl dump-flows br-int | \
+-    grep -E "${match_sw_metadata}" | grep ${mc_key} | grep -v n_packets=0 -c)
+-    test "0" = "${pkts_flooded}"
+-])
+ 
+ # Inject ARP request for FIP1.
+ send_arp_request 1 0 ${src_mac} $(ip_to_hex 10 0 0 254) $(ip_to_hex 10 0 0 121)
+@@ -18242,11 +18214,6 @@ OVS_WAIT_UNTIL([
+     grep n_packets=1 -c)
+     test "0" = "${pkts_to_rtr2}"
+ ])
+-OVS_WAIT_UNTIL([
+-    pkts_flooded=$(ovs-ofctl dump-flows br-int | \
+-    grep -E "${match_sw_metadata}" | grep ${mc_key} | grep -v n_packets=0 -c)
+-    test "0" = "${pkts_flooded}"
+-])
+ 
+ # Inject ND_NS for FIP1.
+ src_ipv6=00100000000000000000000000000254
+-- 
+1.8.3.1
+
diff --git a/SOURCES/0001-ovsdb-idl-Avoid-inconsistent-IDL-state-with-OVSDB_MO.patch b/SOURCES/0001-ovsdb-idl-Avoid-inconsistent-IDL-state-with-OVSDB_MO.patch
new file mode 100644
index 0000000..5df4118
--- /dev/null
+++ b/SOURCES/0001-ovsdb-idl-Avoid-inconsistent-IDL-state-with-OVSDB_MO.patch
@@ -0,0 +1,460 @@
+From 966dd7bc7fb7931d7616ca886dc24ecb1f34cced Mon Sep 17 00:00:00 2001
+From: Dumitru Ceara <dceara@redhat.com>
+Date: Thu, 28 May 2020 14:32:31 +0200
+Subject: [PATCH] ovsdb-idl: Avoid inconsistent IDL state with
+ OVSDB_MONITOR_V3.
+
+Assuming an ovsdb client connected to a database using OVSDB_MONITOR_V3
+(i.e., "monitor_cond_since" method) with the initial monitor condition
+MC1.
+
+Assuming the following two transactions are executed on the
+ovsdb-server:
+TXN1: "insert record R1 in table T1"
+TXN2: "insert record R2 in table T2"
+
+If the client's monitor condition MC1 for table T2 matches R2 then the
+client will receive the following update3 message:
+method="update3", "insert record R2 in table T2", last-txn-id=TXN2
+
+At this point, if the presence of the new record R2 in the IDL triggers
+the client to update its monitor condition to MC2 and add a clause for
+table T1 which matches R1, a monitor_cond_change message is sent to the
+server:
+method="monitor_cond_change", "clauses from MC2"
+
+In normal operation the ovsdb-server will reply with a new update3
+message of the form:
+method="update3", "insert record R1 in table T1", last-txn-id=TXN2
+
+However, if the connection drops in the meantime, this last update might
+get lost.
+
+It might happen that during the reconnect a new transaction happens
+that modifies the original record R1:
+TXN3: "modify record R1 in table T1"
+
+When the client reconnects, it will try to perform a fast resync by
+sending:
+method="monitor_cond_since", "clauses from MC2", last-txn-id=TXN2
+
+Because TXN2 is still in the ovsdb-server transaction history, the
+server replies with the changes from the most recent transactions only,
+i.e., TXN3:
+result="true", last-txbb-id=TXN3, "modify record R1 in table T1"
+
+This causes the IDL on the client in to end up in an inconsistent
+state because it has never seen the update that created R1.
+
+Such a scenario is described in:
+https://bugzilla.redhat.com/show_bug.cgi?id=1808580#c22
+
+To avoid this issue, the IDL will now maintain (up to) 3 different
+types of conditions for each DB table:
+- new_cond: condition that has been set by the IDL client but has
+  not yet been sent to the server through monitor_cond_change.
+- req_cond: condition that has been sent to the server but the reply
+  acknowledging the change hasn't been received yet.
+- ack_cond: condition that has been acknowledged by the server.
+
+Whenever the IDL FSM is restarted (e.g., voluntary or involuntary
+disconnect):
+- if there is a known last_id txn-id the code ensures that new_cond
+  will contain the most recent condition set by the IDL client
+  (either req_cond if there was a request in flight, or new_cond
+  if the IDL client set a condition while the IDL was disconnected)
+- if there is no known last_id txn-id the code ensures that ack_cond will
+  contain the most recent conditions set by the IDL client regardless
+  whether they were acked by the server or not.
+
+When monitor_cond_since/monitor_cond requests are sent they will
+always include ack_cond and if new_cond is not NULL a follow up
+monitor_cond_change will be generated afterwards.
+
+On the other hand ovsdb_idl_db_set_condition() will always modify new_cond.
+
+This ensures that updates of type "insert" that happened before the last
+transaction known by the IDL but didn't match old monitor conditions are
+sent upon reconnect if the monitor condition has changed to include them
+in the meantime.
+
+Fixes: 403a6a0cb003 ("ovsdb-idl: Fast resync from server when connection reset.")
+Signed-off-by: Dumitru Ceara <dceara@redhat.com>
+Acked-by: Han Zhou <hzhou@ovn.org>
+Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
+(cherry picked from upstream OVS commit ae25f8c8fff80a58cd0a15e2d3ae7ab1b4994e48)
+
+Change-Id: I4f3cd43cf69dfe76eb65c9709b759e5062c29e89
+---
+ openvswitch-2.13.0/lib/ovsdb-idl-provider.h |   8 +-
+ openvswitch-2.13.0/lib/ovsdb-idl.c          | 167 ++++++++++++++++++++++++----
+ openvswitch-2.13.0/tests/ovsdb-idl.at       |  56 ++++++++++
+ 3 files changed, 206 insertions(+), 25 deletions(-)
+
+diff --git a/openvswitch-2.13.0/lib/ovsdb-idl-provider.h b/openvswitch-2.13.0/lib/ovsdb-idl-provider.h
+index 30d1d08..00497d9 100644
+--- a/openvswitch-2.13.0/lib/ovsdb-idl-provider.h
++++ b/openvswitch-2.13.0/lib/ovsdb-idl-provider.h
+@@ -122,8 +122,12 @@ struct ovsdb_idl_table {
+     unsigned int change_seqno[OVSDB_IDL_CHANGE_MAX];
+     struct ovs_list indexes;    /* Contains "struct ovsdb_idl_index"s */
+     struct ovs_list track_list; /* Tracked rows (ovsdb_idl_row.track_node). */
+-    struct ovsdb_idl_condition condition;
+-    bool cond_changed;
++    struct ovsdb_idl_condition *ack_cond; /* Last condition acked by the
++                                           * server. */
++    struct ovsdb_idl_condition *req_cond; /* Last condition requested to the
++                                           * server. */
++    struct ovsdb_idl_condition *new_cond; /* Latest condition set by the IDL
++                                           * client. */
+ };
+ 
+ struct ovsdb_idl_class {
+diff --git a/openvswitch-2.13.0/lib/ovsdb-idl.c b/openvswitch-2.13.0/lib/ovsdb-idl.c
+index 2d35179..8eb4213 100644
+--- a/openvswitch-2.13.0/lib/ovsdb-idl.c
++++ b/openvswitch-2.13.0/lib/ovsdb-idl.c
+@@ -240,6 +240,10 @@ static void ovsdb_idl_send_monitor_request(struct ovsdb_idl *,
+                                            struct ovsdb_idl_db *,
+                                            enum ovsdb_idl_monitor_method);
+ static void ovsdb_idl_db_clear(struct ovsdb_idl_db *db);
++static void ovsdb_idl_db_ack_condition(struct ovsdb_idl_db *db);
++static void ovsdb_idl_db_sync_condition(struct ovsdb_idl_db *db);
++static void ovsdb_idl_condition_move(struct ovsdb_idl_condition **dst,
++                                     struct ovsdb_idl_condition **src);
+ 
+ struct ovsdb_idl {
+     struct ovsdb_idl_db server;
+@@ -424,9 +428,11 @@ ovsdb_idl_db_init(struct ovsdb_idl_db *db, const struct ovsdb_idl_class *class,
+             = table->change_seqno[OVSDB_IDL_CHANGE_MODIFY]
+             = table->change_seqno[OVSDB_IDL_CHANGE_DELETE] = 0;
+         table->db = db;
+-        ovsdb_idl_condition_init(&table->condition);
+-        ovsdb_idl_condition_add_clause_true(&table->condition);
+-        table->cond_changed = false;
++        table->ack_cond = NULL;
++        table->req_cond = NULL;
++        table->new_cond = xmalloc(sizeof *table->new_cond);
++        ovsdb_idl_condition_init(table->new_cond);
++        ovsdb_idl_condition_add_clause_true(table->new_cond);
+     }
+     db->monitor_id = json_array_create_2(json_string_create("monid"),
+                                          json_string_create(class->database));
+@@ -558,12 +564,15 @@ ovsdb_idl_set_shuffle_remotes(struct ovsdb_idl *idl, bool shuffle)
+ static void
+ ovsdb_idl_db_destroy(struct ovsdb_idl_db *db)
+ {
++    struct ovsdb_idl_condition *null_cond = NULL;
+     ovs_assert(!db->txn);
+     ovsdb_idl_db_txn_abort_all(db);
+     ovsdb_idl_db_clear(db);
+     for (size_t i = 0; i < db->class_->n_tables; i++) {
+         struct ovsdb_idl_table *table = &db->tables[i];
+-        ovsdb_idl_condition_destroy(&table->condition);
++        ovsdb_idl_condition_move(&table->ack_cond, &null_cond);
++        ovsdb_idl_condition_move(&table->req_cond, &null_cond);
++        ovsdb_idl_condition_move(&table->new_cond, &null_cond);
+         ovsdb_idl_destroy_indexes(table);
+         shash_destroy(&table->columns);
+         hmap_destroy(&table->rows);
+@@ -692,6 +701,12 @@ ovsdb_idl_send_request(struct ovsdb_idl *idl, struct jsonrpc_msg *request)
+ static void
+ ovsdb_idl_restart_fsm(struct ovsdb_idl *idl)
+ {
++    /* Resync data DB table conditions to avoid missing updates due to
++     * conditions that were in flight or changed locally while the connection
++     * was down.
++     */
++    ovsdb_idl_db_sync_condition(&idl->data);
++
+     ovsdb_idl_send_schema_request(idl, &idl->server);
+     ovsdb_idl_transition(idl, IDL_S_SERVER_SCHEMA_REQUESTED);
+     idl->data.monitoring = OVSDB_IDL_NOT_MONITORING;
+@@ -799,7 +814,9 @@ ovsdb_idl_process_response(struct ovsdb_idl *idl, struct jsonrpc_msg *msg)
+          * do, it's a "monitor_cond_change", which means that the conditional
+          * monitor clauses were updated.
+          *
+-         * If further condition changes were pending, send them now. */
++         * Mark the last requested conditions as acked and if further
++         * condition changes were pending, send them now. */
++        ovsdb_idl_db_ack_condition(&idl->data);
+         ovsdb_idl_send_cond_change(idl);
+         idl->data.cond_seqno++;
+         break;
+@@ -1495,30 +1512,60 @@ ovsdb_idl_condition_equals(const struct ovsdb_idl_condition *a,
+ }
+ 
+ static void
+-ovsdb_idl_condition_clone(struct ovsdb_idl_condition *dst,
++ovsdb_idl_condition_clone(struct ovsdb_idl_condition **dst,
+                           const struct ovsdb_idl_condition *src)
+ {
+-    ovsdb_idl_condition_init(dst);
++    if (*dst) {
++        ovsdb_idl_condition_destroy(*dst);
++    } else {
++        *dst = xmalloc(sizeof **dst);
++    }
++    ovsdb_idl_condition_init(*dst);
+ 
+-    dst->is_true = src->is_true;
++    (*dst)->is_true = src->is_true;
+ 
+     const struct ovsdb_idl_clause *clause;
+     HMAP_FOR_EACH (clause, hmap_node, &src->clauses) {
+-        ovsdb_idl_condition_add_clause__(dst, clause, clause->hmap_node.hash);
++        ovsdb_idl_condition_add_clause__(*dst, clause, clause->hmap_node.hash);
+     }
+ }
+ 
++static void
++ovsdb_idl_condition_move(struct ovsdb_idl_condition **dst,
++                         struct ovsdb_idl_condition **src)
++{
++    if (*dst) {
++        ovsdb_idl_condition_destroy(*dst);
++        free(*dst);
++    }
++    *dst = *src;
++    *src = NULL;
++}
++
+ static unsigned int
+ ovsdb_idl_db_set_condition(struct ovsdb_idl_db *db,
+                            const struct ovsdb_idl_table_class *tc,
+                            const struct ovsdb_idl_condition *condition)
+ {
++    struct ovsdb_idl_condition *table_cond;
+     struct ovsdb_idl_table *table = ovsdb_idl_db_table_from_class(db, tc);
+     unsigned int seqno = db->cond_seqno;
+-    if (!ovsdb_idl_condition_equals(condition, &table->condition)) {
+-        ovsdb_idl_condition_destroy(&table->condition);
+-        ovsdb_idl_condition_clone(&table->condition, condition);
+-        db->cond_changed = table->cond_changed = true;
++
++    /* Compare the new condition to the last known condition which can be
++     * either "new" (not sent yet), "requested" or "acked", in this order.
++     */
++    if (table->new_cond) {
++        table_cond = table->new_cond;
++    } else if (table->req_cond) {
++        table_cond = table->req_cond;
++    } else {
++        table_cond = table->ack_cond;
++    }
++    ovs_assert(table_cond);
++
++    if (!ovsdb_idl_condition_equals(condition, table_cond)) {
++        ovsdb_idl_condition_clone(&table->new_cond, condition);
++        db->cond_changed = true;
+         poll_immediate_wake();
+         return seqno + 1;
+     }
+@@ -1563,9 +1610,8 @@ ovsdb_idl_condition_to_json(const struct ovsdb_idl_condition *cnd)
+ }
+ 
+ static struct json *
+-ovsdb_idl_create_cond_change_req(struct ovsdb_idl_table *table)
++ovsdb_idl_create_cond_change_req(const struct ovsdb_idl_condition *cond)
+ {
+-    const struct ovsdb_idl_condition *cond = &table->condition;
+     struct json *monitor_cond_change_request = json_object_create();
+     struct json *cond_json = ovsdb_idl_condition_to_json(cond);
+ 
+@@ -1585,8 +1631,12 @@ ovsdb_idl_db_compose_cond_change(struct ovsdb_idl_db *db)
+     for (size_t i = 0; i < db->class_->n_tables; i++) {
+         struct ovsdb_idl_table *table = &db->tables[i];
+ 
+-        if (table->cond_changed) {
+-            struct json *req = ovsdb_idl_create_cond_change_req(table);
++        /* Always use the most recent conditions set by the IDL client when
++         * requesting monitor_cond_change, i.e., table->new_cond.
++         */
++        if (table->new_cond) {
++            struct json *req =
++                ovsdb_idl_create_cond_change_req(table->new_cond);
+             if (req) {
+                 if (!monitor_cond_change_requests) {
+                     monitor_cond_change_requests = json_object_create();
+@@ -1595,7 +1645,11 @@ ovsdb_idl_db_compose_cond_change(struct ovsdb_idl_db *db)
+                              table->class_->name,
+                              json_array_create_1(req));
+             }
+-            table->cond_changed = false;
++            /* Mark the new condition as requested by moving it to req_cond.
++             * If there's already requested condition that's a bug.
++             */
++            ovs_assert(table->req_cond == NULL);
++            ovsdb_idl_condition_move(&table->req_cond, &table->new_cond);
+         }
+     }
+ 
+@@ -1610,6 +1664,73 @@ ovsdb_idl_db_compose_cond_change(struct ovsdb_idl_db *db)
+     return jsonrpc_create_request("monitor_cond_change", params, NULL);
+ }
+ 
++/* Marks all requested table conditions in 'db' as acked by the server.
++ * It should be called when the server replies to monitor_cond_change
++ * requests.
++ */
++static void
++ovsdb_idl_db_ack_condition(struct ovsdb_idl_db *db)
++{
++    for (size_t i = 0; i < db->class_->n_tables; i++) {
++        struct ovsdb_idl_table *table = &db->tables[i];
++
++        if (table->req_cond) {
++            ovsdb_idl_condition_move(&table->ack_cond, &table->req_cond);
++        }
++    }
++}
++
++/* Should be called when the IDL fsm is restarted and resyncs table conditions
++ * based on the state the DB is in:
++ * - if a non-zero last_id is available for the DB then upon reconnect
++ *   the IDL should first request acked conditions to avoid missing updates
++ *   about records that were added before the transaction with
++ *   txn-id == last_id. If there were requested condition changes in flight
++ *   (i.e., req_cond not NULL) and the IDL client didn't set new conditions
++ *   (i.e., new_cond is NULL) then move req_cond to new_cond to trigger a
++ *   follow up monitor_cond_change request.
++ * - if there's no last_id available for the DB then it's safe to use the
++ *   latest conditions set by the IDL client even if they weren't acked yet.
++ */
++static void
++ovsdb_idl_db_sync_condition(struct ovsdb_idl_db *db)
++{
++    bool ack_all = uuid_is_zero(&db->last_id);
++
++    db->cond_changed = false;
++    for (size_t i = 0; i < db->class_->n_tables; i++) {
++        struct ovsdb_idl_table *table = &db->tables[i];
++
++        /* When monitor_cond_since requests will be issued, the
++         * table->ack_cond condition will be added to the "where" clause".
++         * Follow up monitor_cond_change requests will use table->new_cond.
++         */
++        if (ack_all) {
++            if (table->new_cond) {
++                ovsdb_idl_condition_move(&table->req_cond, &table->new_cond);
++            }
++
++            if (table->req_cond) {
++                ovsdb_idl_condition_move(&table->ack_cond, &table->req_cond);
++            }
++        } else {
++            /* If there was no "unsent" condition but instead a
++             * monitor_cond_change request was in flight, move table->req_cond
++             * to table->new_cond and set db->cond_changed to trigger a new
++             * monitor_cond_change request.
++             *
++             * However, if a new condition has been set by the IDL client,
++             * monitor_cond_change will be sent anyway and will use the most
++             * recent table->new_cond so there's no need to update it here.
++             */
++            if (table->req_cond && !table->new_cond) {
++                ovsdb_idl_condition_move(&table->new_cond, &table->req_cond);
++                db->cond_changed = true;
++            }
++        }
++    }
++}
++
+ static void
+ ovsdb_idl_send_cond_change(struct ovsdb_idl *idl)
+ {
+@@ -2064,13 +2185,15 @@ ovsdb_idl_send_monitor_request(struct ovsdb_idl *idl, struct ovsdb_idl_db *db,
+             monitor_request = json_object_create();
+             json_object_put(monitor_request, "columns", columns);
+ 
+-            const struct ovsdb_idl_condition *cond = &table->condition;
++            /* Always use acked conditions when requesting
++             * monitor_cond/monitor_cond_since.
++             */
++            const struct ovsdb_idl_condition *cond = table->ack_cond;
+             if ((monitor_method == OVSDB_IDL_MM_MONITOR_COND ||
+                  monitor_method == OVSDB_IDL_MM_MONITOR_COND_SINCE) &&
+-                !ovsdb_idl_condition_is_true(cond)) {
++                cond && !ovsdb_idl_condition_is_true(cond)) {
+                 json_object_put(monitor_request, "where",
+                                 ovsdb_idl_condition_to_json(cond));
+-                table->cond_changed = false;
+             }
+             json_object_put(monitor_requests, tc->name,
+                             json_array_create_1(monitor_request));
+@@ -2078,8 +2201,6 @@ ovsdb_idl_send_monitor_request(struct ovsdb_idl *idl, struct ovsdb_idl_db *db,
+     }
+     free_schema(schema);
+ 
+-    db->cond_changed = false;
+-
+     struct json *params = json_array_create_3(
+                               json_string_create(db->class_->database),
+                               json_clone(db->monitor_id),
+diff --git a/openvswitch-2.13.0/tests/ovsdb-idl.at b/openvswitch-2.13.0/tests/ovsdb-idl.at
+index cc38d69..a5ca966 100644
+--- a/openvswitch-2.13.0/tests/ovsdb-idl.at
++++ b/openvswitch-2.13.0/tests/ovsdb-idl.at
+@@ -1814,3 +1814,59 @@ m4_define([OVSDB_CHECK_IDL_LEADER_ONLY_PY],
+ 
+ OVSDB_CHECK_IDL_LEADER_ONLY_PY([Check Python IDL connects to leader], 3, ['remote'])
+ OVSDB_CHECK_IDL_LEADER_ONLY_PY([Check Python IDL reconnects to leader], 3, ['remote' '+remotestop' 'remote'])
++
++# same as OVSDB_CHECK_IDL but uses C IDL implementation with tcp
++# with multiple remotes.
++m4_define([OVSDB_CHECK_CLUSTER_IDL_C],
++  [AT_SETUP([$1 - C - tcp])
++   AT_KEYWORDS([ovsdb server idl positive tcp socket $5])
++   m4_define([LPBK],[127.0.0.1])
++   AT_CHECK([ovsdb_cluster_start_idltest $2 "ptcp:0:"LPBK])
++   PARSE_LISTENING_PORT([s1.log], [TCP_PORT_1])
++   PARSE_LISTENING_PORT([s2.log], [TCP_PORT_2])
++   PARSE_LISTENING_PORT([s3.log], [TCP_PORT_3])
++   remotes=tcp:LPBK:$TCP_PORT_1,tcp:LPBK:$TCP_PORT_2,tcp:LPBK:$TCP_PORT_3
++
++   m4_if([$3], [], [],
++     [AT_CHECK([ovsdb-client transact $remotes $3], [0], [ignore], [ignore])])
++   AT_CHECK([test-ovsdb '-vPATTERN:console:test-ovsdb|%c|%m' -vjsonrpc -t10 idl tcp:LPBK:$TCP_PORT_1 $4],
++            [0], [stdout], [ignore])
++   AT_CHECK([sort stdout | uuidfilt]m4_if([$7],,, [[| $7]]),
++            [0], [$5])
++   AT_CLEANUP])
++
++# Checks that monitor_cond_since works fine when disconnects happen
++# with cond_change requests in flight (i.e., IDL is properly updated).
++OVSDB_CHECK_CLUSTER_IDL_C([simple idl, monitor_cond_since, cluster disconnect],
++  3,
++  [['["idltest",
++       {"op": "insert",
++       "table": "simple",
++       "row": {"i": 1,
++               "r": 1.0,
++               "b": true}},
++       {"op": "insert",
++       "table": "simple",
++       "row": {"i": 2,
++               "r": 1.0,
++               "b": true}}]']],
++  [['condition simple []' \
++    'condition simple [["i","==",2]]' \
++    'condition simple [["i","==",1]]' \
++    '+reconnect' \
++    '["idltest",
++      {"op": "update",
++       "table": "simple",
++       "where": [["i", "==", 1]],
++       "row": {"r": 2.0 }}]']],
++  [[000: change conditions
++001: empty
++002: change conditions
++003: i=2 r=1 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
++004: change conditions
++005: reconnect
++006: i=2 r=1 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
++007: {"error":null,"result":[{"count":1}]}
++008: i=1 r=2 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<2>
++009: done
++]])
+-- 
+1.8.3.1
+
diff --git a/SOURCES/0001-pinctrl-Fix-icmp6-packet-corruption-issue.patch b/SOURCES/0001-pinctrl-Fix-icmp6-packet-corruption-issue.patch
new file mode 100644
index 0000000..adc0e60
--- /dev/null
+++ b/SOURCES/0001-pinctrl-Fix-icmp6-packet-corruption-issue.patch
@@ -0,0 +1,62 @@
+From a069dc4106bc641cbc8596e90b95308950b0bffa Mon Sep 17 00:00:00 2001
+From: Numan Siddique <numans@ovn.org>
+Date: Tue, 12 May 2020 14:21:33 +0530
+Subject: [PATCH] pinctrl: Fix icmp6 packet corruption issue
+
+The commit f792b1a00b43("Fix ACL reject action for UDP packets.")
+didn't updated the 'struct ip6_hdr' pointer after calling
+dp_packet_put(), as dp_packet_put() can reallocate memory making the
+old references to packet pointers invalid.
+
+This patch fixes this issue.
+
+Fixes: f792b1a00b43("Fix ACL reject action for UDP packets.")
+Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=1834655
+Acked-by: Dumitru Ceara <dceara@redhat.com>
+Signed-off-by: Numan Siddique <numans@ovn.org>
+---
+ controller/pinctrl.c | 4 ++--
+ tests/system-ovn.at  | 2 +-
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/controller/pinctrl.c b/controller/pinctrl.c
+index 6b0ac3483..d976ec82b 100644
+--- a/controller/pinctrl.c
++++ b/controller/pinctrl.c
+@@ -1570,8 +1570,6 @@ pinctrl_handle_icmp(struct rconn *swconn, const struct flow *ip_flow,
+         }
+         ih->icmp6_base.icmp6_cksum = 0;
+ 
+-        nh = dp_packet_l3(&packet);
+-
+         /* RFC 4443: 3.1.
+          *
+          * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+@@ -1594,9 +1592,11 @@ pinctrl_handle_icmp(struct rconn *swconn, const struct flow *ip_flow,
+         }
+ 
+         dp_packet_put(&packet, in_ip, in_ip_len);
++        nh = dp_packet_l3(&packet);
+         nh->ip6_plen = htons(ICMP6_DATA_HEADER_LEN + in_ip_len);
+ 
+         icmpv6_csum = packet_csum_pseudoheader6(dp_packet_l3(&packet));
++        ih = dp_packet_l4(&packet);
+         ih->icmp6_base.icmp6_cksum = csum_finish(
+             csum_continue(icmpv6_csum, ih,
+                           in_ip_len + ICMP6_DATA_HEADER_LEN));
+diff --git a/tests/system-ovn.at b/tests/system-ovn.at
+index 9a5ef1ec3..9ae6c6b1f 100644
+--- a/tests/system-ovn.at
++++ b/tests/system-ovn.at
+@@ -3967,7 +3967,7 @@ OVS_WAIT_UNTIL([
+ NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -n -c 1 -i sw0-p1-rej udp port 90 > sw0-p1-rej-udp.pcap &], [0])
+ NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -n -c 1 -i sw0-p1-rej icmp > sw0-p1-rej-icmp.pcap &], [0])
+ 
+-echo "foo" > foo
++printf '.%.0s' {1..100} > foo
+ OVS_WAIT_UNTIL([
+     ip netns exec sw0-p1-rej nc -u 10.0.0.4 90 < foo
+     c=$(cat sw0-p1-rej-icmp.pcap | grep \
+-- 
+2.26.2
+
diff --git a/SOURCES/0001-pinctrl-Handle-service-monitors-even-if-the-lport-do.patch b/SOURCES/0001-pinctrl-Handle-service-monitors-even-if-the-lport-do.patch
new file mode 100644
index 0000000..5932a4f
--- /dev/null
+++ b/SOURCES/0001-pinctrl-Handle-service-monitors-even-if-the-lport-do.patch
@@ -0,0 +1,95 @@
+From 88677e5c2051a1880db61cbb22e4ab48659bc1a8 Mon Sep 17 00:00:00 2001
+From: Numan Siddique <numans@ovn.org>
+Date: Fri, 17 Apr 2020 11:45:56 +0530
+Subject: [PATCH] pinctrl: Handle service monitors even if the lport doesn't
+ have IPv4 addresses set.
+
+If a logical port is only configured with MAC address(es) in the
+Logical_Switch_Port.addresses, pinctrl is ignoring the service monitors
+configured for that logical port. This patch allows that.
+
+Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=1801058
+Acked-by: Mark Michelson <mmichels@redhat.com>
+Signed-off-by: Numan Siddique <numans@ovn.org>
+---
+ controller/pinctrl.c |  5 +++++
+ tests/ovn.at         | 31 +++++++++++++++++++++++++++++++
+ tests/system-ovn.at  |  4 ++--
+ 3 files changed, 38 insertions(+), 2 deletions(-)
+
+diff --git a/controller/pinctrl.c b/controller/pinctrl.c
+index a053938ec..8703641c2 100644
+--- a/controller/pinctrl.c
++++ b/controller/pinctrl.c
+@@ -5786,6 +5786,11 @@ sync_svc_monitors(struct ovsdb_idl_txn *ovnsb_idl_txn,
+ 
+             if (mac_found) {
+                 break;
++            } else if (!laddrs.n_ipv4_addrs) {
++                /* IPv4 address(es) are not configured. Use the first mac. */
++                ea = laddrs.ea;
++                mac_found = true;
++                break;
+             }
+         }
+ 
+diff --git a/tests/ovn.at b/tests/ovn.at
+index 3bc435e6d..0f02e8144 100644
+--- a/tests/ovn.at
++++ b/tests/ovn.at
+@@ -17918,6 +17918,37 @@ AT_CHECK([cat lflows.txt], [0], [dnl
+   table=6 (lr_in_dnat         ), priority=120  , match=(ct.new && ip && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80 && is_chassis_resident("cr-lr0-public")), action=(drop;)
+ ])
+ 
++# Delete sw0-p1
++ovn-nbctl lsp-del sw0-p1
++
++OVS_WAIT_UNTIL([test 1 = $(ovn-sbctl --bare --columns _uuid find \
++service_monitor | sed '/^$/d' | wc -l)])
++
++# Add back sw0-p1 but without any IP address.
++ovn-nbctl lsp-add sw0 sw0-p1
++ovn-nbctl lsp-set-addresses sw0-p1 "50:54:00:00:00:03" -- \
++lsp-set-port-security sw0-p1 "50:54:00:00:00:03"
++
++OVS_WAIT_UNTIL([test 2 = $(ovn-sbctl --bare --columns status find \
++service_monitor | grep offline | wc -l)])
++
++ovn-nbctl lsp-del sw0-p1
++ovn-nbctl lsp-del sw1-p1
++OVS_WAIT_UNTIL([test 0 = $(ovn-sbctl --bare --columns _uuid find \
++service_monitor | sed '/^$/d' | wc -l)])
++
++# Add back sw0-p1 but without any address set.
++ovn-nbctl lsp-add sw0 sw0-p1
++
++OVS_WAIT_UNTIL([test 1 = $(ovn-sbctl --bare --columns _uuid find \
++service_monitor | sed '/^$/d' | wc -l)])
++
++OVS_WAIT_UNTIL([test 0 = $(ovn-sbctl --bare --columns status find \
++service_monitor | grep offline | wc -l)])
++
++OVS_WAIT_UNTIL([test 0 = $(ovn-sbctl --bare --columns status find \
++service_monitor | grep online | wc -l)])
++
+ OVN_CLEANUP([hv1], [hv2])
+ AT_CLEANUP
+ 
+diff --git a/tests/system-ovn.at b/tests/system-ovn.at
+index 000b3f13b..bdb9768d2 100644
+--- a/tests/system-ovn.at
++++ b/tests/system-ovn.at
+@@ -3356,8 +3356,8 @@ start_daemon ovn-controller
+ ovn-nbctl ls-add sw0
+ 
+ ovn-nbctl lsp-add sw0 sw0-p1
+-ovn-nbctl lsp-set-addresses sw0-p1 "50:54:00:00:00:03 10.0.0.3"
+-ovn-nbctl lsp-set-port-security sw0-p1 "50:54:00:00:00:03 10.0.0.3"
++ovn-nbctl lsp-set-addresses sw0-p1 "50:54:00:00:00:03"
++ovn-nbctl lsp-set-port-security sw0-p1 "50:54:00:00:00:03"
+ 
+ ovn-nbctl lsp-add sw0 sw0-p2
+ ovn-nbctl lsp-set-addresses sw0-p2 "50:54:00:00:00:04 10.0.0.4"
+-- 
+2.25.1
+
diff --git a/SOURCES/0001-system-tests-Fix-occasional-failure-of-the-test-Load.patch b/SOURCES/0001-system-tests-Fix-occasional-failure-of-the-test-Load.patch
new file mode 100644
index 0000000..335fe6d
--- /dev/null
+++ b/SOURCES/0001-system-tests-Fix-occasional-failure-of-the-test-Load.patch
@@ -0,0 +1,35 @@
+From b1a0a1aecc5e49e465f7ff42b179f6c5ce683397 Mon Sep 17 00:00:00 2001
+From: Numan Siddique <numans@ovn.org>
+Date: Fri, 28 Feb 2020 22:09:43 +0530
+Subject: [PATCH 1/3] system tests: Fix occasional failure of the test - "Load
+ balancer health checks".
+
+Due to some timing issues, ovn-controller logs the warning message -
+"handle service check: Service monitor not found". This can happen
+if the service monitor is created in SB DB before the port for
+the service is bound. This patch adds this warning message to the
+WHITELIST of OVS_TRAFFIC_VSWITCHD_STOP.
+
+Signed-off-by: Numan Siddique <numans@ovn.org>
+Acked-by: Dumitru Ceara <dceara@redhat.com>
+---
+ tests/system-ovn.at | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/tests/system-ovn.at b/tests/system-ovn.at
+index 53da910cb..9ed3df754 100644
+--- a/tests/system-ovn.at
++++ b/tests/system-ovn.at
+@@ -3462,7 +3462,8 @@ OVS_APP_EXIT_AND_WAIT([ovn-northd])
+ 
+ as
+ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
+-/connection dropped.*/d"])
++/connection dropped.*/d
++/Service monitor not found.*/d"])
+ 
+ AT_CLEANUP
+ 
+-- 
+2.24.1
+
diff --git a/SOURCES/0001-tests-Wait-up-to-OVS_CTL_TIMEOUT-seconds.patch b/SOURCES/0001-tests-Wait-up-to-OVS_CTL_TIMEOUT-seconds.patch
new file mode 100644
index 0000000..bedc1da
--- /dev/null
+++ b/SOURCES/0001-tests-Wait-up-to-OVS_CTL_TIMEOUT-seconds.patch
@@ -0,0 +1,45 @@
+From 2e84aada0b45d2f8739c2fdbc351098fc1c09c26 Mon Sep 17 00:00:00 2001
+Message-Id: <2e84aada0b45d2f8739c2fdbc351098fc1c09c26.1586727203.git.lorenzo.bianconi@redhat.com>
+From: Ilya Maximets <i.maximets@ovn.org>
+Date: Wed, 6 Nov 2019 17:29:58 +0100
+Subject: [PATCH 1/3] tests: Wait up to OVS_CTL_TIMEOUT seconds.
+
+While running tests under valgrind, it could take more than 10 seconds
+for process to disappear after successful 'ovs-appctl exit' command.
+
+Same applies to some other events that tests are waiting for with
+OVS_WAIT macro.  This makes tests to fail frequently under valgrind.
+
+Using OVS_CTL_TIMEOUT variable instead of constant 10 seconds seems
+reasonable to avoid this issue because it controls timeouts of all
+control utilities and needs to be adjusted while running under valgrind
+anyway.
+
+Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
+Acked-by: Aaron Conole <aconole@redhat.com>
+Signed-off-by: William Tu <u9012063@gmail.com>
+Signed-off-by: Numan Siddique <numans@ovn.org>
+Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
+---
+ tests/ovs-macros.at | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/tests/ovs-macros.at b/tests/ovs-macros.at
+index b2e619f76..3dcf8f96d 100644
+--- a/tests/ovs-macros.at
++++ b/tests/ovs-macros.at
+@@ -208,9 +208,9 @@ ovs_wait () {
+     sleep 0.1
+     if ovs_wait_cond; then echo "$1: wait succeeded quickly" >&AS_MESSAGE_LOG_FD; return 0; fi
+ 
+-    # Then wait up to 10 seconds.
++    # Then wait up to OVS_CTL_TIMEOUT seconds.
+     local d
+-    for d in 1 2 3 4 5 6 7 8 9 10; do
++    for d in `seq 1 "$OVS_CTL_TIMEOUT"`; do
+         sleep 1
+         if ovs_wait_cond; then echo "$1: wait succeeded after $d seconds" >&AS_MESSAGE_LOG_FD; return 0; fi
+     done
+-- 
+2.25.2
+
diff --git a/SOURCES/0002-Broadcast-DHCPREPLY-when-BROADCAST-flag-is-set.patch b/SOURCES/0002-Broadcast-DHCPREPLY-when-BROADCAST-flag-is-set.patch
new file mode 100644
index 0000000..f11664d
--- /dev/null
+++ b/SOURCES/0002-Broadcast-DHCPREPLY-when-BROADCAST-flag-is-set.patch
@@ -0,0 +1,400 @@
+From e982e99e5ee4eb9b65e0d3fe59d0975505ea625b Mon Sep 17 00:00:00 2001
+From: Ihar Hrachyshka <ihrachys@redhat.com>
+Date: Thu, 5 Mar 2020 20:44:24 -0500
+Subject: [PATCH 2/3] Broadcast DHCPREPLY when BROADCAST flag is set
+
+As per RFC2131, section 4.1:
+   A server or relay agent sending or relaying a DHCP message directly
+   to a DHCP client (i.e., not to a relay agent specified in the
+   'giaddr' field) SHOULD examine the BROADCAST bit in the 'flags'
+   field.  If this bit is set to 1, the DHCP message SHOULD be sent as
+   an IP broadcast using an IP broadcast address (preferably 0xffffffff)
+   as the IP destination address and the link-layer broadcast address as
+   the link-layer destination address.
+
+This patch changes destination IP address to 255.255.255.255 when client
+set BROADCAST flag in their DHCPREQUEST. Note: the offered IP address is
+still part of the DHCP payload.
+
+While the new DHCP response is sent as a broadcast IP frame, it's
+handled locally, as any other DHCP reply by the native responder.
+Meaning, the reply is sent to the client port that initiated the DHCP
+session only.
+
+Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=1801006
+
+Signed-off-by: Ihar Hrachyshka <ihrachys@redhat.com>
+Signed-off-by: Numan Siddique <numans@ovn.org>
+
+(cherry-picked from upstream commit 4f8045b3b5f2c3376f86f5edc4e3f7507c2b1148)
+---
+ controller/pinctrl.c    | 15 +++++++
+ lib/ovn-l7.h            |  2 +
+ northd/ovn-northd.8.xml |  5 +--
+ northd/ovn-northd.c     |  7 ++-
+ tests/ovn.at            | 98 +++++++++++++++++++++++++++++------------
+ 5 files changed, 93 insertions(+), 34 deletions(-)
+
+diff --git a/controller/pinctrl.c b/controller/pinctrl.c
+index dc8d3fd28..8bf19776c 100644
+--- a/controller/pinctrl.c
++++ b/controller/pinctrl.c
+@@ -966,6 +966,12 @@ pinctrl_handle_tcp_reset(struct rconn *swconn, const struct flow *ip_flow,
+     dp_packet_uninit(&packet);
+ }
+ 
++static bool
++is_dhcp_flags_broadcast(ovs_be16 flags)
++{
++    return flags & htons(DHCP_BROADCAST_FLAG);
++}
++
+ /* Called with in the pinctrl_handler thread context. */
+ static void
+ pinctrl_handle_put_dhcp_opts(
+@@ -1190,7 +1196,16 @@ pinctrl_handle_put_dhcp_opts(
+ 
+     udp->udp_len = htons(new_l4_size);
+ 
++    /* Send a broadcast IP frame when BROADCAST flag is set. */
+     struct ip_header *out_ip = dp_packet_l3(&pkt_out);
++    ovs_be32 ip_dst;
++    if (!is_dhcp_flags_broadcast(dhcp_data->flags)) {
++        ip_dst = *offer_ip;
++    } else {
++        ip_dst = htonl(0xffffffff);
++    }
++    put_16aligned_be32(&out_ip->ip_dst, ip_dst);
++
+     out_ip->ip_tot_len = htons(pkt_out.l4_ofs - pkt_out.l3_ofs + new_l4_size);
+     udp->udp_csum = 0;
+     /* Checksum needs to be initialized to zero. */
+diff --git a/lib/ovn-l7.h b/lib/ovn-l7.h
+index f20d86c39..931e6ffcf 100644
+--- a/lib/ovn-l7.h
++++ b/lib/ovn-l7.h
+@@ -34,6 +34,8 @@ struct gen_opts_map {
+     size_t code;
+ };
+ 
++#define DHCP_BROADCAST_FLAG 0x8000
++
+ #define DHCP_OPTION(NAME, CODE, TYPE) \
+     {.name = NAME, .code = CODE, .type = TYPE}
+ 
+diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
+index d80f8cf8d..b6cfa3e90 100644
+--- a/northd/ovn-northd.8.xml
++++ b/northd/ovn-northd.8.xml
+@@ -937,7 +937,6 @@ next;
+         <pre>
+ eth.dst = eth.src;
+ eth.src = <var>E</var>;
+-ip4.dst = <var>A</var>;
+ ip4.src = <var>S</var>;
+ udp.src = 67;
+ udp.dst = 68;
+@@ -948,8 +947,8 @@ output;
+ 
+         <p>
+           where <var>E</var> is the server MAC address and <var>S</var> is the
+-          server IPv4 address defined in the DHCPv4 options and <var>A</var> is
+-          the IPv4 address defined in the logical port's addresses column.
++          server IPv4 address defined in the DHCPv4 options. Note that
++          <code>ip4.dst</code> field is handled by <code>put_dhcp_opts</code>.
+         </p>
+ 
+         <p>
+diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
+index 0d43322cf..217a8c894 100644
+--- a/northd/ovn-northd.c
++++ b/northd/ovn-northd.c
+@@ -4276,10 +4276,9 @@ build_dhcpv4_action(struct ovn_port *op, ovs_be32 offer_ip,
+     ds_put_cstr(options_action, "); next;");
+ 
+     ds_put_format(response_action, "eth.dst = eth.src; eth.src = %s; "
+-                  "ip4.dst = "IP_FMT"; ip4.src = %s; udp.src = 67; "
+-                  "udp.dst = 68; outport = inport; flags.loopback = 1; "
+-                  "output;",
+-                  server_mac, IP_ARGS(offer_ip), server_ip);
++                  "ip4.src = %s; udp.src = 67; udp.dst = 68; "
++                  "outport = inport; flags.loopback = 1; output;",
++                  server_mac, server_ip);
+ 
+     ds_put_format(ipv4_addr_match,
+                   "ip4.src == "IP_FMT" && ip4.dst == {%s, 255.255.255.255}",
+diff --git a/tests/ovn.at b/tests/ovn.at
+index a04f22c4c..8de4b5ceb 100644
+--- a/tests/ovn.at
++++ b/tests/ovn.at
+@@ -4595,10 +4595,11 @@ sleep 2
+ as hv1 ovs-vsctl show
+ 
+ # This shell function sends a DHCP request packet
+-# test_dhcp INPORT SRC_MAC DHCP_TYPE OFFER_IP REQUEST_IP ...
++# test_dhcp INPORT SRC_MAC DHCP_TYPE BROADCAST CIADDR OFFER_IP REQUEST_IP USE_IP ...
+ test_dhcp() {
+-    local inport=$1 src_mac=$2 dhcp_type=$3 ciaddr=$4 offer_ip=$5 request_ip=$6 use_ip=$7
+-    shift; shift; shift; shift; shift; shift; shift;
++    local inport=$1 src_mac=$2 dhcp_type=$3 broadcast=$4 ciaddr=$5 offer_ip=$6 request_ip=$7 use_ip=$8
++    shift; shift; shift; shift; shift; shift; shift; shift;
++
+     if test $use_ip != 0; then
+         src_ip=$1
+         dst_ip=$2
+@@ -4607,6 +4608,7 @@ test_dhcp() {
+         src_ip=`ip_to_hex 0 0 0 0`
+         dst_ip=`ip_to_hex 255 255 255 255`
+     fi
++
+     if test $request_ip != 0; then
+         ip_len=0120
+         udp_len=010b
+@@ -4614,10 +4616,19 @@ test_dhcp() {
+         ip_len=011a
+         udp_len=0106
+     fi
++
++    if test $broadcast != 0; then
++        flags=8000
++        reply_dst_ip=`ip_to_hex 255 255 255 255`
++    else
++        flags=0000
++        reply_dst_ip=${offer_ip}
++    fi
++
+     local request=ffffffffffff${src_mac}08004510${ip_len}0000000080110000${src_ip}${dst_ip}
+     # udp header and dhcp header
+     request=${request}00440043${udp_len}0000
+-    request=${request}010106006359aa7600000000${ciaddr}000000000000000000000000${src_mac}
++    request=${request}010106006359aa760000${flags}${ciaddr}000000000000000000000000${src_mac}
+     # client hardware padding
+     request=${request}00000000000000000000
+     # server hostname
+@@ -4655,10 +4666,10 @@ test_dhcp() {
+         ip_len=$(printf "%x" $ip_len)
+         udp_len=$(printf "%x" $udp_len)
+         # $ip_len var will be in 3 digits i.e 134. So adding a '0' before $ip_len
+-        local reply=${src_mac}${srv_mac}080045100${ip_len}000000008011XXXX${srv_ip}${offer_ip}
++        local reply=${src_mac}${srv_mac}080045100${ip_len}000000008011XXXX${srv_ip}${reply_dst_ip}
+         # udp header and dhcp header.
+         # $udp_len var will be in 3 digits. So adding a '0' before $udp_len
+-        reply=${reply}004300440${udp_len}0000020106006359aa7600000000${ciaddr}
++        reply=${reply}004300440${udp_len}0000020106006359aa760000${flags}${ciaddr}
+         # your ip address; 0 for NAK
+         if test $dhcp_reply_type = 06; then
+             reply=${reply}00000000
+@@ -4729,7 +4740,7 @@ server_ip=`ip_to_hex 10 0 0 1`
+ ciaddr=`ip_to_hex 0 0 0 0`
+ request_ip=0
+ expected_dhcp_opts=330400000e100104ffffff0003040a00000136040a000001
+-test_dhcp 1 f00000000001 01 $ciaddr $offer_ip $request_ip 0 ff1000000001 $server_ip 02 $expected_dhcp_opts
++test_dhcp 1 f00000000001 01 0 $ciaddr $offer_ip $request_ip 0 ff1000000001 $server_ip 02 $expected_dhcp_opts
+ 
+ # NXT_RESUMEs should be 1.
+ OVS_WAIT_UNTIL([test 1 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
+@@ -4755,7 +4766,7 @@ server_ip=`ip_to_hex 10 0 0 1`
+ ciaddr=`ip_to_hex 0 0 0 0`
+ request_ip=$offer_ip
+ expected_dhcp_opts=330400000e100104ffffff0003040a00000136040a000001
+-test_dhcp 2 f00000000002 03 $ciaddr $offer_ip $request_ip 0 ff1000000001 $server_ip 05 $expected_dhcp_opts
++test_dhcp 2 f00000000002 03 0 $ciaddr $offer_ip $request_ip 0 ff1000000001 $server_ip 05 $expected_dhcp_opts
+ 
+ # NXT_RESUMEs should be 2.
+ OVS_WAIT_UNTIL([test 2 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
+@@ -4779,7 +4790,7 @@ server_ip=`ip_to_hex 10 0 0 1`
+ ciaddr=`ip_to_hex 0 0 0 0`
+ request_ip=`ip_to_hex 10 0 0 7`
+ expected_dhcp_opts=""
+-test_dhcp 2 f00000000002 03 $ciaddr $offer_ip $request_ip 0 ff1000000001 $server_ip 06 $expected_dhcp_opts
++test_dhcp 2 f00000000002 03 0 $ciaddr $offer_ip $request_ip 0 ff1000000001 $server_ip 06 $expected_dhcp_opts
+ 
+ # NXT_RESUMEs should be 3.
+ OVS_WAIT_UNTIL([test 3 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
+@@ -4803,7 +4814,7 @@ rm -f 2.expected
+ ciaddr=`ip_to_hex 0 0 0 0`
+ offer_ip=0
+ request_ip=0
+-test_dhcp 2 f00000000002 08 $ciaddr $offer_ip $request_ip 0 1 1
++test_dhcp 2 f00000000002 08 0 $ciaddr $offer_ip $request_ip 0 1 1
+ 
+ # NXT_RESUMEs should be 4.
+ OVS_WAIT_UNTIL([test 4 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
+@@ -4820,12 +4831,12 @@ rm -f 2.expected
+ # ls2-lp2 (vif4-tx.pcap) should receive the DHCPv4 request packet once.
+ 
+ ciaddr=`ip_to_hex 0 0 0 0`
+-test_dhcp 3 f00000000003 01 $ciaddr 0 0 4 0
++test_dhcp 3 f00000000003 01 0 $ciaddr 0 0 4 0
+ 
+ # Send DHCPv4 packet on ls2-lp2. "router" DHCPv4 option is not defined for
+ # this lport.
+ ciaddr=`ip_to_hex 0 0 0 0`
+-test_dhcp 4 f00000000004 01 $ciaddr 0 0 3 0
++test_dhcp 4 f00000000004 01 0 $ciaddr 0 0 3 0
+ 
+ # NXT_RESUMEs should be 4.
+ OVS_WAIT_UNTIL([test 4 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
+@@ -4842,7 +4853,7 @@ request_ip=0
+ src_ip=$offer_ip
+ dst_ip=$server_ip
+ expected_dhcp_opts=330400000e100104ffffff0003040a00000136040a000001
+-test_dhcp 2 f00000000002 03 $ciaddr $offer_ip $request_ip 1 $src_ip $dst_ip ff1000000001 $server_ip 05 $expected_dhcp_opts
++test_dhcp 2 f00000000002 03 0 $ciaddr $offer_ip $request_ip 1 $src_ip $dst_ip ff1000000001 $server_ip 05 $expected_dhcp_opts
+ 
+ # NXT_RESUMEs should be 5.
+ OVS_WAIT_UNTIL([test 5 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
+@@ -4868,7 +4879,7 @@ request_ip=0
+ src_ip=$offer_ip
+ dst_ip=`ip_to_hex 255 255 255 255`
+ expected_dhcp_opts=330400000e100104ffffff0003040a00000136040a000001
+-test_dhcp 2 f00000000002 03 $ciaddr $offer_ip $request_ip 1 $src_ip $dst_ip ff1000000001 $server_ip 05 $expected_dhcp_opts
++test_dhcp 2 f00000000002 03 0 $ciaddr $offer_ip $request_ip 1 $src_ip $dst_ip ff1000000001 $server_ip 05 $expected_dhcp_opts
+ 
+ # NXT_RESUMEs should be 6.
+ OVS_WAIT_UNTIL([test 6 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
+@@ -4894,7 +4905,7 @@ request_ip=0
+ src_ip=$offer_ip
+ dst_ip=`ip_to_hex 255 255 255 255`
+ expected_dhcp_opts=""
+-test_dhcp 2 f00000000002 03 $ciaddr $offer_ip $request_ip 1 $src_ip $dst_ip ff1000000001 $server_ip 06 $expected_dhcp_opts
++test_dhcp 2 f00000000002 03 0 $ciaddr $offer_ip $request_ip 1 $src_ip $dst_ip ff1000000001 $server_ip 06 $expected_dhcp_opts
+ 
+ # NXT_RESUMEs should be 7.
+ OVS_WAIT_UNTIL([test 7 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
+@@ -4920,7 +4931,7 @@ request_ip=0
+ src_ip=$offer_ip
+ dst_ip=`ip_to_hex 255 255 255 255`
+ expected_dhcp_opts=""
+-test_dhcp 2 f00000000002 03 $ciaddr $offer_ip $request_ip 1 $src_ip $dst_ip ff1000000001 $server_ip 06 $expected_dhcp_opts
++test_dhcp 2 f00000000002 03 0 $ciaddr $offer_ip $request_ip 1 $src_ip $dst_ip ff1000000001 $server_ip 06 $expected_dhcp_opts
+ 
+ # NXT_RESUMEs should be 8.
+ OVS_WAIT_UNTIL([test 8 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
+@@ -4942,7 +4953,7 @@ rm -f 2.expected
+ ciaddr=`ip_to_hex 0 0 0 0`
+ src_ip=`ip_to_hex 10 0 0 6`
+ dst_ip=`ip_to_hex 10 0 0 4`
+-test_dhcp 2 f00000000002 03 $ciaddr 0 0 1 $src_ip $dst_ip 1
++test_dhcp 2 f00000000002 03 0 $ciaddr 0 0 1 $src_ip $dst_ip 1
+ 
+ # NXT_RESUMEs should be 8.
+ OVS_WAIT_UNTIL([test 8 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
+@@ -4950,6 +4961,29 @@ OVS_WAIT_UNTIL([test 8 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
+ # vif1-tx.pcap should have received the DHCPv4 request packet
+ OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [1.expected])
+ 
++reset_pcap_file hv1-vif1 hv1/vif1
++reset_pcap_file hv1-vif2 hv1/vif2
++rm -f 1.expected
++rm -f 2.expected
++
++# Send DHCPDISCOVER with BROADCAST flag on.
++offer_ip=`ip_to_hex 10 0 0 4`
++server_ip=`ip_to_hex 10 0 0 1`
++ciaddr=`ip_to_hex 0 0 0 0`
++request_ip=0
++expected_dhcp_opts=330400000e100104ffffff0003040a00000136040a000001
++test_dhcp 1 f00000000001 01 1 $ciaddr $offer_ip $request_ip 0 ff1000000001 $server_ip 02 $expected_dhcp_opts
++
++# NXT_RESUMEs should be 9.
++OVS_WAIT_UNTIL([test 9 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
++
++$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif1-tx.pcap > 1.packets
++cat 1.expected | cut -c -48 > expout
++AT_CHECK([cat 1.packets | cut -c -48], [0], [expout])
++# Skipping the IPv4 checksum.
++cat 1.expected | cut -c 53- > expout
++AT_CHECK([cat 1.packets | cut -c 53-], [0], [expout])
++
+ OVN_CLEANUP([hv1])
+ 
+ AT_CLEANUP
+@@ -13220,10 +13254,11 @@ as hv1
+ ovs-vsctl show
+ 
+ # This shell function sends a DHCP request packet
+-# test_dhcp INPORT SRC_MAC DHCP_TYPE OFFER_IP ...
++# test_dhcp INPORT SRC_MAC DHCP_TYPE BROADCAST OFFER_IP ...
+ test_dhcp() {
+-    local inport=$1 src_mac=$2 dhcp_type=$3 offer_ip=$4 use_ip=$5
+-    shift; shift; shift; shift; shift;
++    local inport=$1 src_mac=$2 dhcp_type=$3 broadcast=$4 offer_ip=$5 use_ip=$6
++    shift; shift; shift; shift; shift; shift;
++
+     if test $use_ip != 0; then
+         src_ip=$1
+         dst_ip=$2
+@@ -13232,10 +13267,19 @@ test_dhcp() {
+         src_ip=`ip_to_hex 0 0 0 0`
+         dst_ip=`ip_to_hex 255 255 255 255`
+     fi
++
++    if test $broadcast != 0; then
++        flags=8000
++        reply_dst_ip=`ip_to_hex 255 255 255 255`
++    else
++        flags=0000
++        reply_dst_ip=${offer_ip}
++    fi
++
+     local request=ffffffffffff${src_mac}0800451001100000000080110000${src_ip}${dst_ip}
+     # udp header and dhcp header
+     request=${request}0044004300fc0000
+-    request=${request}010106006359aa760000000000000000000000000000000000000000${src_mac}
++    request=${request}010106006359aa760000${flags}00000000000000000000000000000000${src_mac}
+     # client hardware padding
+     request=${request}00000000000000000000
+     # server hostname
+@@ -13259,10 +13303,10 @@ test_dhcp() {
+     ip_len=$(printf "%x" $ip_len)
+     udp_len=$(printf "%x" $udp_len)
+     # $ip_len var will be in 3 digits i.e 134. So adding a '0' before $ip_len
+-    local reply=${src_mac}${srv_mac}080045100${ip_len}000000008011XXXX${srv_ip}${offer_ip}
++    local reply=${src_mac}${srv_mac}080045100${ip_len}000000008011XXXX${srv_ip}${reply_dst_ip}
+     # udp header and dhcp header.
+     # $udp_len var will be in 3 digits. So adding a '0' before $udp_len
+-    reply=${reply}004300440${udp_len}0000020106006359aa760000000000000000
++    reply=${reply}004300440${udp_len}0000020106006359aa760000${flags}00000000
+     # your ip address
+     reply=${reply}${offer_ip}
+     # next server ip address, relay agent ip address, client mac address
+@@ -13381,7 +13425,7 @@ offer_ip=`ip_to_hex 10 0 0 6`
+ server_ip=`ip_to_hex 10 0 0 1`
+ server_mac=ff1000000001
+ expected_dhcp_opts=330400000e100104ffffff0003040a00000136040a000001
+-test_dhcp 1 f00000000003 01 $offer_ip 0 $server_mac $server_ip \
++test_dhcp 1 f00000000003 01 0 $offer_ip 0 $server_mac $server_ip \
+ $expected_dhcp_opts
+ 
+ # NXT_RESUMEs should be 1 in hv1.
+@@ -13479,7 +13523,7 @@ offer_ip=`ip_to_hex 10 0 0 6`
+ server_ip=`ip_to_hex 10 0 0 1`
+ server_mac=ff1000000001
+ expected_dhcp_opts=330400000e100104ffffff0003040a00000136040a000001
+-test_dhcp 1 f00000000003 01 $offer_ip 0 $server_mac $server_ip \
++test_dhcp 1 f00000000003 01 0 $offer_ip 0 $server_mac $server_ip \
+ $expected_dhcp_opts
+ 
+ # NXT_RESUMEs should be 2 in hv1.
+@@ -13589,7 +13633,7 @@ offer_ip=`ip_to_hex 10 0 0 6`
+ server_ip=`ip_to_hex 10 0 0 1`
+ server_mac=ff1000000001
+ expected_dhcp_opts=330400000e100104ffffff0003040a00000136040a000001
+-test_dhcp 1 f00000000003 01 $offer_ip 0 $server_mac $server_ip \
++test_dhcp 1 f00000000003 01 0 $offer_ip 0 $server_mac $server_ip \
+ $expected_dhcp_opts
+ 
+ # NXT_RESUMEs should be 3 in hv1.
+@@ -13669,7 +13713,7 @@ offer_ip=`ip_to_hex 10 0 0 6`
+ server_ip=`ip_to_hex 10 0 0 1`
+ server_mac=ff1000000001
+ expected_dhcp_opts=330400000e100104ffffff0003040a00000136040a000001
+-test_dhcp 1 f00000000003 01 $offer_ip 0 $server_mac $server_ip \
++test_dhcp 1 f00000000003 01 0 $offer_ip 0 $server_mac $server_ip \
+ $expected_dhcp_opts
+ 
+ # NXT_RESUMEs should be 4 in hv1.
+-- 
+2.24.1
+
diff --git a/SOURCES/0002-Create-daemon-pidfiles-in-ovn-run-dir.patch b/SOURCES/0002-Create-daemon-pidfiles-in-ovn-run-dir.patch
new file mode 100644
index 0000000..45129b5
--- /dev/null
+++ b/SOURCES/0002-Create-daemon-pidfiles-in-ovn-run-dir.patch
@@ -0,0 +1,351 @@
+From d80be07ca318603524508402e044474571c1f642 Mon Sep 17 00:00:00 2001
+From: Numan Siddique <numans@ovn.org>
+Date: Thu, 23 Apr 2020 12:53:23 +0530
+Subject: [PATCH 2/2] Create daemon pidfiles in ovn run dir.
+
+If an OVN service is started with --pidfile option, the pidfile
+is created in the ovs rundir. This patch fixes it by using the ovn rundir
+if either the pidfile is not specified or if specified, it is not
+absolute path.
+
+Signed-off-by: Numan Siddique <numans@ovn.org>
+Acked-by: Dumitru Ceara <dceara@redhat.com>
+Signed-off-by: Mark Michelson <mmichels@redhat.com>
+---
+ controller-vtep/ovn-controller-vtep.c |  6 +--
+ controller/ovn-controller.c           |  6 +--
+ ic/ovn-ic.c                           |  6 +--
+ lib/ovn-util.c                        | 26 ++++++++++++
+ lib/ovn-util.h                        | 60 +++++++++++++++++++++++++++
+ northd/ovn-northd.c                   |  6 +--
+ utilities/ovn-nbctl.c                 | 10 ++---
+ utilities/ovn-trace.c                 |  6 +--
+ 8 files changed, 106 insertions(+), 20 deletions(-)
+
+diff --git a/controller-vtep/ovn-controller-vtep.c b/controller-vtep/ovn-controller-vtep.c
+index 253a709ab..c13280bc0 100644
+--- a/controller-vtep/ovn-controller-vtep.c
++++ b/controller-vtep/ovn-controller-vtep.c
+@@ -169,7 +169,7 @@ parse_options(int argc, char *argv[])
+         OPT_PEER_CA_CERT = UCHAR_MAX + 1,
+         OPT_BOOTSTRAP_CA_CERT,
+         VLOG_OPTION_ENUMS,
+-        DAEMON_OPTION_ENUMS,
++        OVN_DAEMON_OPTION_ENUMS,
+         SSL_OPTION_ENUMS,
+     };
+ 
+@@ -179,7 +179,7 @@ parse_options(int argc, char *argv[])
+         {"help", no_argument, NULL, 'h'},
+         {"version", no_argument, NULL, 'V'},
+         VLOG_LONG_OPTIONS,
+-        DAEMON_LONG_OPTIONS,
++        OVN_DAEMON_LONG_OPTIONS,
+         STREAM_SSL_LONG_OPTIONS,
+         {"peer-ca-cert", required_argument, NULL, OPT_PEER_CA_CERT},
+         {"bootstrap-ca-cert", required_argument, NULL, OPT_BOOTSTRAP_CA_CERT},
+@@ -212,7 +212,7 @@ parse_options(int argc, char *argv[])
+             exit(EXIT_SUCCESS);
+ 
+         VLOG_OPTION_HANDLERS
+-        DAEMON_OPTION_HANDLERS
++        OVN_DAEMON_OPTION_HANDLERS
+         STREAM_SSL_OPTION_HANDLERS
+ 
+         case OPT_PEER_CA_CERT:
+diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c
+index 4d21ba0fd..6ff897325 100644
+--- a/controller/ovn-controller.c
++++ b/controller/ovn-controller.c
+@@ -2268,7 +2268,7 @@ parse_options(int argc, char *argv[])
+         OPT_PEER_CA_CERT = UCHAR_MAX + 1,
+         OPT_BOOTSTRAP_CA_CERT,
+         VLOG_OPTION_ENUMS,
+-        DAEMON_OPTION_ENUMS,
++        OVN_DAEMON_OPTION_ENUMS,
+         SSL_OPTION_ENUMS,
+     };
+ 
+@@ -2276,7 +2276,7 @@ parse_options(int argc, char *argv[])
+         {"help", no_argument, NULL, 'h'},
+         {"version", no_argument, NULL, 'V'},
+         VLOG_LONG_OPTIONS,
+-        DAEMON_LONG_OPTIONS,
++        OVN_DAEMON_LONG_OPTIONS,
+         STREAM_SSL_LONG_OPTIONS,
+         {"peer-ca-cert", required_argument, NULL, OPT_PEER_CA_CERT},
+         {"bootstrap-ca-cert", required_argument, NULL, OPT_BOOTSTRAP_CA_CERT},
+@@ -2301,7 +2301,7 @@ parse_options(int argc, char *argv[])
+             exit(EXIT_SUCCESS);
+ 
+         VLOG_OPTION_HANDLERS
+-        DAEMON_OPTION_HANDLERS
++        OVN_DAEMON_OPTION_HANDLERS
+         STREAM_SSL_OPTION_HANDLERS
+ 
+         case OPT_PEER_CA_CERT:
+diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c
+index d931ca50f..a1ed25623 100644
+--- a/ic/ovn-ic.c
++++ b/ic/ovn-ic.c
+@@ -1461,7 +1461,7 @@ static void
+ parse_options(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
+ {
+     enum {
+-        DAEMON_OPTION_ENUMS,
++        OVN_DAEMON_OPTION_ENUMS,
+         VLOG_OPTION_ENUMS,
+         SSL_OPTION_ENUMS,
+     };
+@@ -1474,7 +1474,7 @@ parse_options(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
+         {"help", no_argument, NULL, 'h'},
+         {"options", no_argument, NULL, 'o'},
+         {"version", no_argument, NULL, 'V'},
+-        DAEMON_LONG_OPTIONS,
++        OVN_DAEMON_LONG_OPTIONS,
+         VLOG_LONG_OPTIONS,
+         STREAM_SSL_LONG_OPTIONS,
+         {NULL, 0, NULL, 0},
+@@ -1490,7 +1490,7 @@ parse_options(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
+         }
+ 
+         switch (c) {
+-        DAEMON_OPTION_HANDLERS;
++        OVN_DAEMON_OPTION_HANDLERS;
+         VLOG_OPTION_HANDLERS;
+         STREAM_SSL_OPTION_HANDLERS;
+ 
+diff --git a/lib/ovn-util.c b/lib/ovn-util.c
+index 1b30c2e9a..3482edb8d 100644
+--- a/lib/ovn-util.c
++++ b/lib/ovn-util.c
+@@ -15,6 +15,7 @@
+ #include <config.h>
+ #include <unistd.h>
+ 
++#include "daemon.h"
+ #include "ovn-util.h"
+ #include "ovn-dirs.h"
+ #include "openvswitch/vlog.h"
+@@ -394,6 +395,31 @@ get_abs_unix_ctl_path(const char *path)
+     return abs_path;
+ }
+ 
++void
++ovn_set_pidfile(const char *name)
++{
++    char *pidfile_name = NULL;
++
++#ifndef _WIN32
++    pidfile_name = name ? abs_file_name(ovn_rundir(), name)
++                        : xasprintf("%s/%s.pid", ovn_rundir(), program_name);
++#else
++    if (name) {
++        if (strchr(name, ':')) {
++            pidfile_name = xstrdup(name);
++        } else {
++            pidfile_name = xasprintf("%s/%s", ovn_rundir(), name);
++        }
++    } else {
++        pidfile_name = xasprintf("%s/%s.pid", ovn_rundir(), program_name);
++    }
++#endif
++
++    /* Call openvswitch lib function. */
++    set_pidfile(pidfile_name);
++    free(pidfile_name);
++}
++
+ /* l3gateway, chassisredirect, and patch
+  * are not in this list since they are
+  * only set in the SB DB by northd
+diff --git a/lib/ovn-util.h b/lib/ovn-util.h
+index 4076e8b9a..ec5f2cf5a 100644
+--- a/lib/ovn-util.h
++++ b/lib/ovn-util.h
+@@ -112,6 +112,7 @@ uint32_t ovn_allocate_tnlid(struct hmap *set, const char *name, uint32_t min,
+                             uint32_t max, uint32_t *hint);
+ 
+ char *ovn_chassis_redirect_name(const char *port_name);
++void ovn_set_pidfile(const char *name);
+ 
+ /* An IPv4 or IPv6 address */
+ struct v46_ip {
+@@ -129,4 +130,63 @@ bool ip46_equals(const struct v46_ip *addr1, const struct v46_ip *addr2);
+  * Caller must free the returned string.
+  */
+ char *str_tolower(const char *orig);
++
++/* OVN daemon options. Taken from ovs/lib/daemon.h. */
++#define OVN_DAEMON_OPTION_ENUMS                     \
++    OVN_OPT_DETACH,                                 \
++    OVN_OPT_NO_SELF_CONFINEMENT,                    \
++    OVN_OPT_NO_CHDIR,                               \
++    OVN_OPT_OVERWRITE_PIDFILE,                      \
++    OVN_OPT_PIDFILE,                                \
++    OVN_OPT_MONITOR,                                \
++    OVN_OPT_USER_GROUP
++
++#define OVN_DAEMON_LONG_OPTIONS                                              \
++        {"detach",            no_argument, NULL, OVN_OPT_DETACH},            \
++        {"no-self-confinement", no_argument, NULL,                           \
++         OVN_OPT_NO_SELF_CONFINEMENT},                                       \
++        {"no-chdir",          no_argument, NULL, OVN_OPT_NO_CHDIR},          \
++        {"pidfile",           optional_argument, NULL, OVN_OPT_PIDFILE},     \
++        {"overwrite-pidfile", no_argument, NULL, OVN_OPT_OVERWRITE_PIDFILE}, \
++        {"monitor",           no_argument, NULL, OVN_OPT_MONITOR},           \
++        {"user",              required_argument, NULL, OVN_OPT_USER_GROUP}
++
++#define OVN_DAEMON_OPTION_HANDLERS                  \
++        case OVN_OPT_DETACH:                        \
++            set_detach();                           \
++            break;                                  \
++                                                    \
++        case OVN_OPT_NO_SELF_CONFINEMENT:           \
++            daemon_disable_self_confinement();      \
++            break;                                  \
++                                                    \
++        case OVN_OPT_NO_CHDIR:                      \
++            set_no_chdir();                         \
++            break;                                  \
++                                                    \
++        case OVN_OPT_PIDFILE:                       \
++            ovn_set_pidfile(optarg);                \
++            break;                                  \
++                                                    \
++        case OVN_OPT_OVERWRITE_PIDFILE:             \
++            ignore_existing_pidfile();              \
++            break;                                  \
++                                                    \
++        case OVN_OPT_MONITOR:                       \
++            daemon_set_monitor();                   \
++            break;                                  \
++                                                    \
++        case OVN_OPT_USER_GROUP:                    \
++            daemon_set_new_user(optarg);            \
++            break;
++
++#define OVN_DAEMON_OPTION_CASES                     \
++        case OVN_OPT_DETACH:                        \
++        case OVN_OPT_NO_SELF_CONFINEMENT:           \
++        case OVN_OPT_NO_CHDIR:                      \
++        case OVN_OPT_PIDFILE:                       \
++        case OVN_OPT_OVERWRITE_PIDFILE:             \
++        case OVN_OPT_MONITOR:                       \
++        case OVN_OPT_USER_GROUP:
++
+ #endif
+diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
+index 515722c5d..d3d481ab8 100644
+--- a/northd/ovn-northd.c
++++ b/northd/ovn-northd.c
+@@ -11607,7 +11607,7 @@ static void
+ parse_options(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
+ {
+     enum {
+-        DAEMON_OPTION_ENUMS,
++        OVN_DAEMON_OPTION_ENUMS,
+         VLOG_OPTION_ENUMS,
+         SSL_OPTION_ENUMS,
+     };
+@@ -11618,7 +11618,7 @@ parse_options(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
+         {"help", no_argument, NULL, 'h'},
+         {"options", no_argument, NULL, 'o'},
+         {"version", no_argument, NULL, 'V'},
+-        DAEMON_LONG_OPTIONS,
++        OVN_DAEMON_LONG_OPTIONS,
+         VLOG_LONG_OPTIONS,
+         STREAM_SSL_LONG_OPTIONS,
+         {NULL, 0, NULL, 0},
+@@ -11634,7 +11634,7 @@ parse_options(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
+         }
+ 
+         switch (c) {
+-        DAEMON_OPTION_HANDLERS;
++        OVN_DAEMON_OPTION_HANDLERS;
+         VLOG_OPTION_HANDLERS;
+         STREAM_SSL_OPTION_HANDLERS;
+ 
+diff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c
+index a88c1ddc2..3f4731d40 100644
+--- a/utilities/ovn-nbctl.c
++++ b/utilities/ovn-nbctl.c
+@@ -324,7 +324,7 @@ enum {
+     OPT_NO_SHUFFLE_REMOTES,
+     OPT_BOOTSTRAP_CA_CERT,
+     MAIN_LOOP_OPTION_ENUMS,
+-    DAEMON_OPTION_ENUMS,
++    OVN_DAEMON_OPTION_ENUMS,
+     VLOG_OPTION_ENUMS,
+     TABLE_OPTION_ENUMS,
+     SSL_OPTION_ENUMS,
+@@ -428,7 +428,7 @@ get_all_options(void)
+         {"version", no_argument, NULL, 'V'},
+         {"unixctl", required_argument, NULL, 'u'},
+         MAIN_LOOP_LONG_OPTIONS,
+-        DAEMON_LONG_OPTIONS,
++        OVN_DAEMON_LONG_OPTIONS,
+         VLOG_LONG_OPTIONS,
+         STREAM_SSL_LONG_OPTIONS,
+         {"bootstrap-ca-cert", required_argument, NULL, OPT_BOOTSTRAP_CA_CERT},
+@@ -460,7 +460,7 @@ has_option(const struct ovs_cmdl_parsed_option *parsed_options, size_t n,
+ static bool
+ will_detach(const struct ovs_cmdl_parsed_option *parsed_options, size_t n)
+ {
+-    return has_option(parsed_options, n, OPT_DETACH);
++    return has_option(parsed_options, n, OVN_OPT_DETACH);
+ }
+ 
+ static char * OVS_WARN_UNUSED_RESULT
+@@ -547,7 +547,7 @@ apply_options_direct(const struct ovs_cmdl_parsed_option *parsed_options,
+             printf("DB Schema %s\n", nbrec_get_db_version());
+             exit(EXIT_SUCCESS);
+ 
+-        DAEMON_OPTION_HANDLERS
++        OVN_DAEMON_OPTION_HANDLERS
+         VLOG_OPTION_HANDLERS
+         TABLE_OPTION_HANDLERS(&table_style)
+         STREAM_SSL_OPTION_HANDLERS
+@@ -6512,7 +6512,7 @@ nbctl_client(const char *socket_name,
+         case OPT_NO_SHUFFLE_REMOTES:
+         case OPT_BOOTSTRAP_CA_CERT:
+         STREAM_SSL_CASES
+-        DAEMON_OPTION_CASES
++        OVN_DAEMON_OPTION_CASES
+             VLOG_INFO("using ovn-nbctl daemon, ignoring %s option",
+                       po->o->name);
+             break;
+diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c
+index eae9622d3..c9d72285c 100644
+--- a/utilities/ovn-trace.c
++++ b/utilities/ovn-trace.c
+@@ -239,7 +239,7 @@ parse_options(int argc, char *argv[])
+         OPT_CT,
+         OPT_FRIENDLY_NAMES,
+         OPT_NO_FRIENDLY_NAMES,
+-        DAEMON_OPTION_ENUMS,
++        OVN_DAEMON_OPTION_ENUMS,
+         SSL_OPTION_ENUMS,
+         VLOG_OPTION_ENUMS,
+         OPT_LB_DST,
+@@ -260,7 +260,7 @@ parse_options(int argc, char *argv[])
+         {"version", no_argument, NULL, 'V'},
+         {"lb-dst", required_argument, NULL, OPT_LB_DST},
+         {"select-id", required_argument, NULL, OPT_SELECT_ID},
+-        DAEMON_LONG_OPTIONS,
++        OVN_DAEMON_LONG_OPTIONS,
+         VLOG_LONG_OPTIONS,
+         STREAM_SSL_LONG_OPTIONS,
+         {NULL, 0, NULL, 0},
+@@ -333,7 +333,7 @@ parse_options(int argc, char *argv[])
+             printf("DB Schema %s\n", sbrec_get_db_version());
+             exit(EXIT_SUCCESS);
+ 
+-        DAEMON_OPTION_HANDLERS
++        OVN_DAEMON_OPTION_HANDLERS
+         VLOG_OPTION_HANDLERS
+         STREAM_SSL_OPTION_HANDLERS
+ 
+-- 
+2.25.1
+
diff --git a/SOURCES/0002-Honour-router_preference-for-solicited-RA.patch b/SOURCES/0002-Honour-router_preference-for-solicited-RA.patch
new file mode 100644
index 0000000..a73b677
--- /dev/null
+++ b/SOURCES/0002-Honour-router_preference-for-solicited-RA.patch
@@ -0,0 +1,209 @@
+From 17d3f4f18878ef706008575cd1565745c5936819 Mon Sep 17 00:00:00 2001
+From: Gabriele Cerami <gcerami@redhat.com>
+Date: Sat, 13 Jun 2020 10:20:23 +0100
+Subject: [PATCH 2/3] Honour router_preference for solicited RA
+
+Replies to router solicitation follow a different flow than periodic RA.
+This flow currently does not honour the router_preference configuration.
+
+This patch modifies the flow to honour the flag, and send
+router-preference indications in the reply RA following RFC4191
+specifications
+
+Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=1804576
+Signed-off-by: Gabriele Cerami <gcerami@redhat.com>
+Signed-off-by: Numan Siddique <numans@ovn.org>
+---
+ AUTHORS.rst         |  1 +
+ lib/actions.c       | 29 +++++++++++++++++++++++++++--
+ lib/ovn-l7.h        |  5 +++++
+ northd/ovn-northd.c |  6 ++++++
+ tests/ovn.at        | 26 ++++++++++++++++----------
+ 5 files changed, 55 insertions(+), 12 deletions(-)
+
+diff --git a/AUTHORS.rst b/AUTHORS.rst
+index c80fc1bae..bba0d1d6f 100644
+--- a/AUTHORS.rst
++++ b/AUTHORS.rst
+@@ -145,6 +145,7 @@ Frédéric Tobias Christ             fchrist@live.de
+ Frode Nordahl                      frode.nordahl@gmail.com
+ FUJITA Tomonori                    fujita.tomonori@lab.ntt.co.jp
+ Gabe Beged-Dov                     gabe@begeddov.com
++Gabriele Cerami                    gcerami@redhat.com
+ Gaetano Catalli                    gaetano.catalli@gmail.com
+ Gal Sagie                          gal.sagie@gmail.com
+ Genevieve LEsperance               glesperance@pivotal.io
+diff --git a/lib/actions.c b/lib/actions.c
+index ee7ccae0d..3181126e6 100644
+--- a/lib/actions.c
++++ b/lib/actions.c
+@@ -2484,6 +2484,12 @@ parse_put_nd_ra_opts(struct action_context *ctx, const struct expr_field *dst,
+             }
+             break;
+ 
++        case ND_RA_FLAG_PRF:
++            ok = (c->string && (!strcmp(c->string, "MEDIUM") ||
++                                !strcmp(c->string, "HIGH") ||
++                                !strcmp(c->string, "LOW")));
++            break;
++
+         case ND_OPT_SOURCE_LINKADDR:
+             ok = c->format == LEX_F_ETHERNET;
+             slla_present = true;
+@@ -2538,9 +2544,22 @@ encode_put_nd_ra_option(const struct ovnact_gen_option *o,
+     {
+         struct ovs_ra_msg *ra = ofpbuf_at(ofpacts, ra_offset, sizeof *ra);
+         if (!strcmp(c->string, "dhcpv6_stateful")) {
+-            ra->mo_flags = IPV6_ND_RA_FLAG_MANAGED_ADDR_CONFIG;
++            ra->mo_flags |= IPV6_ND_RA_FLAG_MANAGED_ADDR_CONFIG;
+         } else if (!strcmp(c->string, "dhcpv6_stateless")) {
+-            ra->mo_flags = IPV6_ND_RA_FLAG_OTHER_ADDR_CONFIG;
++            ra->mo_flags |= IPV6_ND_RA_FLAG_OTHER_ADDR_CONFIG;
++        }
++        break;
++    }
++
++    case ND_RA_FLAG_PRF:
++    {
++        struct ovs_ra_msg *ra = ofpbuf_at(ofpacts, ra_offset, sizeof *ra);
++        if (!strcmp(c->string, "LOW")) {
++            ra->mo_flags |= IPV6_ND_RA_OPT_PRF_LOW;
++        } else if (!strcmp(c->string, "HIGH")) {
++            ra->mo_flags |= IPV6_ND_RA_OPT_PRF_HIGH;
++        } else {
++            ra->mo_flags |= IPV6_ND_RA_OPT_PRF_NORMAL;
+         }
+         break;
+     }
+@@ -2621,6 +2640,12 @@ encode_PUT_ND_RA_OPTS(const struct ovnact_put_opts *po,
+         encode_put_nd_ra_option(o, ofpacts, ra_offset);
+     }
+ 
++    /* RFC4191 section 2.2 */
++    struct ovs_ra_msg *new_ra = ofpbuf_at(ofpacts, ra_offset, sizeof *new_ra);
++    if (ntohs(new_ra->router_lifetime) == 0) {
++        new_ra->mo_flags &= IPV6_ND_RA_OPT_PRF_RESET_MASK;
++    }
++
+     encode_finish_controller_op(oc_offset, ofpacts);
+ }
+ 
+diff --git a/lib/ovn-l7.h b/lib/ovn-l7.h
+index cbea2a0c8..2da38fb65 100644
+--- a/lib/ovn-l7.h
++++ b/lib/ovn-l7.h
+@@ -304,6 +304,9 @@ nd_ra_opts_destroy(struct hmap *nd_ra_opts)
+ 
+ 
+ #define ND_RA_FLAG_ADDR_MODE    0
++/* all small numbers seems to be all already taken but nothing guarantees this
++ * code will not be assigned by IANA to another option */
++#define ND_RA_FLAG_PRF          255
+ 
+ 
+ /* Default values of various IPv6 Neighbor Discovery protocol options and
+@@ -325,11 +328,13 @@ nd_ra_opts_destroy(struct hmap *nd_ra_opts)
+ #define IPV6_ND_RA_OPT_PRF_NORMAL                   0x00
+ #define IPV6_ND_RA_OPT_PRF_HIGH                     0x08
+ #define IPV6_ND_RA_OPT_PRF_LOW                      0x18
++#define IPV6_ND_RA_OPT_PRF_RESET_MASK               0xe7
+ 
+ static inline void
+ nd_ra_opts_init(struct hmap *nd_ra_opts)
+ {
+     nd_ra_opt_add(nd_ra_opts, "addr_mode", ND_RA_FLAG_ADDR_MODE, "str");
++    nd_ra_opt_add(nd_ra_opts, "router_preference", ND_RA_FLAG_PRF, "str");
+     nd_ra_opt_add(nd_ra_opts, "slla", ND_OPT_SOURCE_LINKADDR, "mac");
+     nd_ra_opt_add(nd_ra_opts, "prefix", ND_OPT_PREFIX_INFORMATION, "ipv6");
+     nd_ra_opt_add(nd_ra_opts, "mtu", ND_OPT_MTU, "uint32");
+diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
+index c1b4c13b7..cffe3de17 100644
+--- a/northd/ovn-northd.c
++++ b/northd/ovn-northd.c
+@@ -9408,6 +9408,12 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
+             ds_put_format(&actions, ", mtu = %u", mtu);
+         }
+ 
++        const char *prf = smap_get_def(
++            &op->nbrp->ipv6_ra_configs, "router_preference", "MEDIUM");
++        if (strcmp(prf, "MEDIUM")) {
++            ds_put_format(&actions, ", router_preference = \"%s\"", prf);
++        }
++
+         bool add_rs_response_flow = false;
+ 
+         for (size_t i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) {
+diff --git a/tests/ovn.at b/tests/ovn.at
+index 57c1d90e4..d9df393d5 100644
+--- a/tests/ovn.at
++++ b/tests/ovn.at
+@@ -1346,14 +1346,14 @@ log(severity=notice);
+     Syntax error at `;' expecting verdict.
+ 
+ # put_nd_ra_opts
+-reg1[0] = put_nd_ra_opts(addr_mode = "slaac", mtu = 1500, prefix = aef0::/64, slla = ae:01:02:03:04:05);
+-    encodes as controller(userdata=00.00.00.08.00.00.00.00.00.01.de.10.00.00.00.40.86.00.00.00.ff.00.ff.ff.00.00.00.00.00.00.00.00.05.01.00.00.00.00.05.dc.03.04.40.c0.ff.ff.ff.ff.ff.ff.ff.ff.00.00.00.00.ae.f0.00.00.00.00.00.00.00.00.00.00.00.00.00.00.01.01.ae.01.02.03.04.05,pause)
++reg1[0] = put_nd_ra_opts(addr_mode = "slaac", mtu = 1500, router_preference = "HIGH", prefix = aef0::/64, slla = ae:01:02:03:04:05);
++    encodes as controller(userdata=00.00.00.08.00.00.00.00.00.01.de.10.00.00.00.40.86.00.00.00.ff.08.ff.ff.00.00.00.00.00.00.00.00.05.01.00.00.00.00.05.dc.03.04.40.c0.ff.ff.ff.ff.ff.ff.ff.ff.00.00.00.00.ae.f0.00.00.00.00.00.00.00.00.00.00.00.00.00.00.01.01.ae.01.02.03.04.05,pause)
+     has prereqs ip6
+-reg1[0] = put_nd_ra_opts(addr_mode = "dhcpv6_stateful", slla = ae:01:02:03:04:10, mtu = 1450);
++reg1[0] = put_nd_ra_opts(addr_mode = "dhcpv6_stateful", router_preference = "MEDIUM", slla = ae:01:02:03:04:10, mtu = 1450);
+     encodes as controller(userdata=00.00.00.08.00.00.00.00.00.01.de.10.00.00.00.40.86.00.00.00.ff.80.ff.ff.00.00.00.00.00.00.00.00.01.01.ae.01.02.03.04.10.05.01.00.00.00.00.05.aa,pause)
+     has prereqs ip6
+-reg1[0] = put_nd_ra_opts(addr_mode = "dhcpv6_stateless", slla = ae:01:02:03:04:06, prefix = aef0::/64);
+-    encodes as controller(userdata=00.00.00.08.00.00.00.00.00.01.de.10.00.00.00.40.86.00.00.00.ff.40.ff.ff.00.00.00.00.00.00.00.00.01.01.ae.01.02.03.04.06.03.04.40.c0.ff.ff.ff.ff.ff.ff.ff.ff.00.00.00.00.ae.f0.00.00.00.00.00.00.00.00.00.00.00.00.00.00,pause)
++reg1[0] = put_nd_ra_opts(addr_mode = "dhcpv6_stateless", router_preference = "LOW", slla = ae:01:02:03:04:06, prefix = aef0::/64);
++    encodes as controller(userdata=00.00.00.08.00.00.00.00.00.01.de.10.00.00.00.40.86.00.00.00.ff.58.ff.ff.00.00.00.00.00.00.00.00.01.01.ae.01.02.03.04.06.03.04.40.c0.ff.ff.ff.ff.ff.ff.ff.ff.00.00.00.00.ae.f0.00.00.00.00.00.00.00.00.00.00.00.00.00.00,pause)
+     has prereqs ip6
+ reg1[0] = put_nd_ra_opts(addr_mode = "slaac", mtu = 1500, prefix = aef0::/64);
+     slla option not present
+@@ -10083,13 +10083,16 @@ reset_pcap_file hv1-vif1 hv1/vif1
+ reset_pcap_file hv1-vif2 hv1/vif2
+ reset_pcap_file hv1-vif3 hv1/vif3
+ 
+-# Set the MTU to 1500
++# Set the MTU to 1500, send_periodic to false, preference to LOW
+ ovn-nbctl --wait=hv set Logical_Router_Port lrp0 ipv6_ra_configs:mtu=1500
++ovn-nbctl --wait=hv set Logical_Router_Port lrp0 ipv6_ra_configs:send_periodic="false"
++ovn-nbctl --wait=hv set Logical_Router_Port lrp0 ipv6_ra_configs:router_preference="LOW"
+ 
+ # Make sure that ovn-controller has installed the corresponding OF Flow.
+ OVS_WAIT_UNTIL([test 1 = `as hv1 ovs-ofctl dump-flows br-int | grep -c "ipv6_dst=ff02::2,nw_ttl=255,icmp_type=133,icmp_code=0"`])
+ 
+-addr_mode=00
++# addr_mode byte also includes router preference information
++addr_mode=18
+ default_prefix_option_config=030440c0ffffffffffffffff00000000
+ src_mac=fa163e000003
+ src_lla=fe80000000000000f8163efffe000003
+@@ -10114,12 +10117,14 @@ reset_pcap_file hv1-vif1 hv1/vif1
+ reset_pcap_file hv1-vif2 hv1/vif2
+ reset_pcap_file hv1-vif3 hv1/vif3
+ 
+-# Set the address mode to dhcpv6_stateful
++# Set the address mode to dhcpv6_stateful, router_preference to HIGH
+ ovn-nbctl --wait=hv set Logical_Router_Port lrp0 ipv6_ra_configs:address_mode=dhcpv6_stateful
++ovn-nbctl --wait=hv set Logical_Router_Port lrp0 ipv6_ra_configs:router_preference="HIGH"
+ # Make sure that ovn-controller has installed the corresponding OF Flow.
+ OVS_WAIT_UNTIL([test 1 = `as hv1 ovs-ofctl dump-flows br-int | grep -c "ipv6_dst=ff02::2,nw_ttl=255,icmp_type=133,icmp_code=0"`])
+ 
+-addr_mode=80
++# addr_mode byte also includes router preference information
++addr_mode=88
+ default_prefix_option_config=03044080ffffffffffffffff00000000
+ src_mac=fa163e000004
+ src_lla=fe80000000000000f8163efffe000004
+@@ -10144,8 +10149,9 @@ reset_pcap_file hv1-vif1 hv1/vif1
+ reset_pcap_file hv1-vif2 hv1/vif2
+ reset_pcap_file hv1-vif3 hv1/vif3
+ 
+-# Set the address mode to dhcpv6_stateless
++# Set the address mode to dhcpv6_stateless, reset router preference to default
+ ovn-nbctl --wait=hv set Logical_Router_Port lrp0 ipv6_ra_configs:address_mode=dhcpv6_stateless
++ovn-nbctl --wait=hv set Logical_Router_Port lrp0 ipv6_ra_configs:router_preference="MEDIUM"
+ # Make sure that ovn-controller has installed the corresponding OF Flow.
+ OVS_WAIT_UNTIL([test 1 = `as hv1 ovs-ofctl dump-flows br-int | grep -c "ipv6_dst=ff02::2,nw_ttl=255,icmp_type=133,icmp_code=0"`])
+ 
+-- 
+2.26.2
+
diff --git a/SOURCES/0002-Revert-Manage-ARP-process-locally-in-a-DVR-scenario.patch b/SOURCES/0002-Revert-Manage-ARP-process-locally-in-a-DVR-scenario.patch
new file mode 100644
index 0000000..d6bd9d1
--- /dev/null
+++ b/SOURCES/0002-Revert-Manage-ARP-process-locally-in-a-DVR-scenario.patch
@@ -0,0 +1,186 @@
+From d9ed450713eda62af1bec5009694b2d206c9f435 Mon Sep 17 00:00:00 2001
+Message-Id: <d9ed450713eda62af1bec5009694b2d206c9f435.1590585469.git.lorenzo.bianconi@redhat.com>
+From: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
+Date: Mon, 25 May 2020 23:55:06 +0200
+Subject: [PATCH ovn 1/3] Revert "Manage ARP process locally in a DVR scenario"
+
+This reverts commit c0bf32d72f8b893bbe3cb64912b0fd259d71555f.
+
+Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
+Signed-off-by: Han Zhou <hzhou@ovn.org>
+---
+ northd/ovn-northd.8.xml | 37 ++--------------------------
+ northd/ovn-northd.c     | 53 +----------------------------------------
+ tests/ovn.at            | 14 -----------
+ 3 files changed, 3 insertions(+), 101 deletions(-)
+
+--- a/northd/ovn-northd.8.xml
++++ b/northd/ovn-northd.8.xml
+@@ -2486,44 +2486,11 @@ output;
+ 
+       <li>
+         <p>
+-          For distributed logical routers where one of the logical router ports
+-          specifies a <code>redirect-chassis</code>, a priority-400 logical
+-          flow for each <code>dnat_and_snat</code> NAT rules configured.
+-          These flows will allow to properly forward traffic to the external
+-          connections if available and avoid sending it through the tunnel.
+-          Assuming the following NAT rule has been configured:
+-        </p>
+-
+-        <pre>
+-external_ip = <var>A</var>;
+-external_mac = <var>B</var>;
+-logical_ip = <var>C</var>;
+-        </pre>
+-
+-        <p>
+-          the following action will be applied:
+-        </p>
+-
+-        <pre>
+-ip.ttl--;
+-reg0 = <var>ip.dst</var>;
+-reg1 = <var>A</var>;
+-eth.src = <var>B</var>;
+-outport = <var>router-port</var>;
+-next;
+-        </pre>
+-
+-      </li>
+-
+-      <li>
+-        <p>
+           IPv4 routing table.  For each route to IPv4 network <var>N</var> with
+           netmask <var>M</var>, on router port <var>P</var> with IP address
+           <var>A</var> and Ethernet
+           address <var>E</var>, a logical flow with match <code>ip4.dst ==
+-          <var>N</var>/<var>M</var></code>, whose priority is <code>400</code>
+-          + the number of 1-bits in <var>M</var> if the router port is not a
+-          distributed gateway port, else the priority is the number of
++          <var>N</var>/<var>M</var></code>, whose priority is the number of
+           1-bits in <var>M</var>, has the following actions:
+         </p>
+ 
+@@ -2910,7 +2877,7 @@ icmp4 {
+     <ul>
+       <li>
+         For each NAT rule in the OVN Northbound database that can
+-        be handled in a distributed manner, a priority-200 logical
++        be handled in a distributed manner, a priority-100 logical
+         flow with match <code>ip4.src == <var>B</var> &amp;&amp;
+         outport == <var>GW</var></code>, where <var>GW</var> is
+         the logical router distributed gateway port, with actions
+--- a/northd/ovn-northd.c
++++ b/northd/ovn-northd.c
+@@ -7102,8 +7102,6 @@ build_routing_policy_flow(struct hmap *l
+     ds_destroy(&actions);
+ }
+ 
+-/* default logical flow prioriry for distributed routes */
+-#define DROUTE_PRIO 400
+ struct parsed_route {
+     struct ovs_list list_node;
+     struct v46_ip prefix;
+@@ -7492,40 +7490,6 @@ build_ecmp_route_flow(struct hmap *lflow
+ }
+ 
+ static void
+-add_distributed_routes(struct hmap *lflows, struct ovn_datapath *od)
+-{
+-    struct ds actions = DS_EMPTY_INITIALIZER;
+-    struct ds match = DS_EMPTY_INITIALIZER;
+-
+-    for (size_t i = 0; i < od->nbr->n_nat; i++) {
+-        const struct nbrec_nat *nat = od->nbr->nat[i];
+-
+-        if (strcmp(nat->type, "dnat_and_snat") ||
+-            !nat->external_mac) {
+-            continue;
+-        }
+-
+-        bool is_ipv4 = strchr(nat->logical_ip, '.') ? true : false;
+-        ds_put_format(&match, "ip%s.src == %s && is_chassis_resident(\"%s\")",
+-                      is_ipv4 ? "4" : "6", nat->logical_ip,
+-                      nat->logical_port);
+-        char *prefix = is_ipv4 ? "" : "xx";
+-        ds_put_format(&actions, "outport = %s; eth.src = %s; "
+-                      "%sreg0 = ip%s.dst; %sreg1 = %s; next;",
+-                      od->l3dgw_port->json_key, nat->external_mac,
+-                      prefix, is_ipv4 ? "4" : "6",
+-                      prefix, nat->external_ip);
+-        ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, DROUTE_PRIO,
+-                      ds_cstr(&match), ds_cstr(&actions));
+-        ds_clear(&match);
+-        ds_clear(&actions);
+-    }
+-
+-    ds_destroy(&actions);
+-    ds_destroy(&match);
+-}
+-
+-static void
+ add_route(struct hmap *lflows, const struct ovn_port *op,
+           const char *lrp_addr_s, const char *network_s, int plen,
+           const char *gateway, bool is_src_route,
+@@ -7546,12 +7510,6 @@ add_route(struct hmap *lflows, const str
+     }
+     build_route_match(op_inport, network_s, plen, is_src_route, is_ipv4,
+                       &match, &priority);
+-    /* traffic for internal IPs of logical switch ports must be sent to
+-     * the gw controller through the overlay tunnels
+-     */
+-    if (op->nbrp && !op->nbrp->n_gateway_chassis) {
+-        priority += DROUTE_PRIO;
+-    }
+ 
+     struct ds actions = DS_EMPTY_INITIALIZER;
+     ds_put_format(&actions, "ip.ttl--; "REG_ECMP_GROUP_ID" = 0; %sreg0 = ",
+@@ -9187,7 +9145,7 @@ build_lrouter_flows(struct hmap *datapat
+                               nat->logical_ip,
+                               od->l3dgw_port->json_key);
+                 ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_GW_REDIRECT,
+-                                        200, ds_cstr(&match), "next;",
++                                        100, ds_cstr(&match), "next;",
+                                         &nat->header_);
+             }
+ 
+@@ -9493,15 +9451,6 @@ build_lrouter_flows(struct hmap *datapat
+         ovn_lflow_add(lflows, od, S_ROUTER_IN_ND_RA_RESPONSE, 0, "1", "next;");
+     }
+ 
+-    /* Logical router ingress table IP_ROUTING - IP routing for distributed
+-     * logical router
+-     */
+-    HMAP_FOR_EACH (od, key_node, datapaths) {
+-        if (od->nbr && od->l3dgw_port) {
+-            add_distributed_routes(lflows, od);
+-        }
+-    }
+-
+     /* Logical router ingress table IP_ROUTING & IP_ROUTING_ECMP: IP Routing.
+      *
+      * A packet that arrives at this table is an IP packet that should be
+--- a/tests/ovn.at
++++ b/tests/ovn.at
+@@ -9605,20 +9605,6 @@ AT_CHECK([as hv3 ovs-vsctl set Open_vSwi
+ OVS_WAIT_UNTIL([test 1 = `as hv3 ovs-vsctl show | \
+ grep "Port patch-br-int-to-ln_port" | wc -l`])
+ 
+-AT_CHECK([test 1 = `ovn-sbctl dump-flows lr0 | grep lr_in_ip_routing | \
+-grep "ip4.src == 10.0.0.3 && is_chassis_resident(\"foo1\")" -c`])
+-AT_CHECK([test 1 = `ovn-sbctl dump-flows lr0 | grep lr_in_ip_routing | \
+-grep "ip4.src == 10.0.0.4 && is_chassis_resident(\"foo2\")" -c`])
+-
+-key=`ovn-sbctl --bare --columns tunnel_key list datapath_Binding lr0`
+-# Check that the OVS flows appear for the dnat_and_snat entries in
+-# lr_in_ip_routing table.
+-OVS_WAIT_UNTIL([test 1 = `as hv3 ovs-ofctl dump-flows br-int table=17 | \
+-grep "priority=400,ip,metadata=0x$key,nw_src=10.0.0.3" -c`])
+-
+-OVS_WAIT_UNTIL([test 1 = `as hv3 ovs-ofctl dump-flows br-int table=17 | \
+-grep "priority=400,ip,metadata=0x$key,nw_src=10.0.0.4" -c`])
+-
+ # Re-add nat-addresses option
+ ovn-nbctl lsp-set-options lrp0-rp router-port=lrp0 nat-addresses="router"
+ 
diff --git a/SOURCES/0002-controller-Add-garbage-collector-for-ipv6_prefixd.patch b/SOURCES/0002-controller-Add-garbage-collector-for-ipv6_prefixd.patch
new file mode 100644
index 0000000..7b48c56
--- /dev/null
+++ b/SOURCES/0002-controller-Add-garbage-collector-for-ipv6_prefixd.patch
@@ -0,0 +1,65 @@
+From 85b13870020facf5f4441df51df64ee647c6abd9 Mon Sep 17 00:00:00 2001
+Message-Id: <85b13870020facf5f4441df51df64ee647c6abd9.1588608928.git.lorenzo.bianconi@redhat.com>
+In-Reply-To: <0b9d16670d5561d8300d2448cbd4686a3acdc57e.1588608928.git.lorenzo.bianconi@redhat.com>
+References: <0b9d16670d5561d8300d2448cbd4686a3acdc57e.1588608928.git.lorenzo.bianconi@redhat.com>
+From: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
+Date: Wed, 29 Apr 2020 18:05:30 +0200
+Subject: [PATCH 2/3] controller: Add garbage collector for ipv6_prefixd.
+
+Introduce a garbage collector for stale entries in ipv6_prefixd that are
+no longer managed by the controller (e.g. if the processing has been
+disabled setting ipv6_prefix_delegation to false on all logical router
+ports).
+
+Tested-by: Jianlin Shi <jishi@redhat.com>
+Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
+Signed-off-by: Numan Siddique <numans@ovn.org>
+---
+ controller/pinctrl.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/controller/pinctrl.c b/controller/pinctrl.c
+index 3230bb386..f0d63b9a6 100644
+--- a/controller/pinctrl.c
++++ b/controller/pinctrl.c
+@@ -578,6 +578,7 @@ enum {
+ 
+ struct ipv6_prefixd_state {
+     long long int next_announce;
++    long long int last_used;
+     struct in6_addr ipv6_addr;
+     struct eth_addr ea;
+     struct eth_addr cmac;
+@@ -1128,11 +1129,13 @@ fill_ipv6_prefix_state(struct ovsdb_idl_txn *ovnsb_idl_txn,
+             sbrec_port_binding_set_options(pb, &options);
+             smap_destroy(&options);
+         }
++        pfd->last_used = time_msec();
+     }
+ 
+     return changed;
+ }
+ 
++#define IPV6_PREFIXD_STALE_TIMEOUT  180000LL
+ static void
+ prepare_ipv6_prefixd(struct ovsdb_idl_txn *ovnsb_idl_txn,
+                      struct ovsdb_idl_index *sbrec_port_binding_by_name,
+@@ -1210,6 +1213,15 @@ prepare_ipv6_prefixd(struct ovsdb_idl_txn *ovnsb_idl_txn,
+         }
+     }
+ 
++    struct shash_node *iter, *next;
++    SHASH_FOR_EACH_SAFE (iter, next, &ipv6_prefixd) {
++        struct ipv6_prefixd_state *pfd = iter->data;
++        if (pfd->last_used + IPV6_PREFIXD_STALE_TIMEOUT < time_msec()) {
++            free(pfd);
++            shash_delete(&ipv6_prefixd, iter);
++        }
++    }
++
+     if (changed) {
+         notify_pinctrl_handler();
+     }
+-- 
+2.26.2
+
diff --git a/SOURCES/0002-controller-Add-ipv6-prefix-delegation-state-machine.patch b/SOURCES/0002-controller-Add-ipv6-prefix-delegation-state-machine.patch
new file mode 100644
index 0000000..b715219
--- /dev/null
+++ b/SOURCES/0002-controller-Add-ipv6-prefix-delegation-state-machine.patch
@@ -0,0 +1,934 @@
+From aa0139f28628bb869866e4c35cb31f8005b99994 Mon Sep 17 00:00:00 2001
+Message-Id: <aa0139f28628bb869866e4c35cb31f8005b99994.1586727203.git.lorenzo.bianconi@redhat.com>
+In-Reply-To: <2e84aada0b45d2f8739c2fdbc351098fc1c09c26.1586727203.git.lorenzo.bianconi@redhat.com>
+References: <2e84aada0b45d2f8739c2fdbc351098fc1c09c26.1586727203.git.lorenzo.bianconi@redhat.com>
+From: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
+Date: Wed, 1 Apr 2020 18:37:30 +0200
+Subject: [PATCH 2/3] controller: Add ipv6 prefix delegation state machine
+
+Introduce IPv6 Prefix delegation state machine according to RFC 3633
+https://tools.ietf.org/html/rfc3633.
+Add handle_dhcpv6_reply controller action to parse advertise/reply from
+IPv6 delegation server. Advertise/reply are parsed running respectively:
+- pinctrl_parse_dhcv6_advt
+- pinctrl_parse_dhcv6_reply
+The IPv6 requesting router starts sending dhcpv6 solicit through the logical
+router port marked with ipv6_prefix_delegation set to true.
+An IPv6 prefix will be requested for each logical router port marked
+with "prefix" set to true in option column of logical router port table.
+Save IPv6 prefix received by IPv6 delegation router in the options columns of
+SB port binding table in order to be reused by Router Advertisement framework
+run by ovn logical router pipeline.
+IPv6 Prefix delegation state machine is enabled on Gateway Router or on
+a Gateway Router Port
+
+Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
+Signed-off-by: Numan Siddique <numans@ovn.org>
+---
+ controller/pinctrl.c  | 651 ++++++++++++++++++++++++++++++++++++++++++
+ include/ovn/actions.h |   8 +-
+ lib/actions.c         |  16 ++
+ lib/ovn-l7.h          |  19 ++
+ ovn-sb.xml            |  18 ++
+ tests/ovn.at          |   4 +
+ utilities/ovn-trace.c |   2 +
+ 7 files changed, 717 insertions(+), 1 deletion(-)
+
+diff --git a/controller/pinctrl.c b/controller/pinctrl.c
+index 3fa8923e7..a053938ec 100644
+--- a/controller/pinctrl.c
++++ b/controller/pinctrl.c
+@@ -270,6 +270,8 @@ static void pinctrl_ip_mcast_handle(
+     const struct match *md,
+     struct ofpbuf *userdata);
+ 
++static void init_ipv6_prefixd(void);
++
+ static bool may_inject_pkts(void);
+ 
+ static void init_put_vport_bindings(void);
+@@ -313,6 +315,13 @@ static void pinctrl_compose_ipv6(struct dp_packet *packet,
+                                  uint8_t ip_proto, uint8_t ttl,
+                                  uint16_t ip_payload_len);
+ 
++static void
++put_load(uint64_t value, enum mf_field_id dst, int ofs, int n_bits,
++         struct ofpbuf *ofpacts);
++
++static void notify_pinctrl_main(void);
++static void notify_pinctrl_handler(void);
++
+ COVERAGE_DEFINE(pinctrl_drop_put_mac_binding);
+ COVERAGE_DEFINE(pinctrl_drop_buffered_packets_map);
+ COVERAGE_DEFINE(pinctrl_drop_controller_event);
+@@ -470,6 +479,7 @@ pinctrl_init(void)
+     init_put_mac_bindings();
+     init_send_garps_rarps();
+     init_ipv6_ras();
++    init_ipv6_prefixd();
+     init_buffered_packets_map();
+     init_event_table();
+     ip_mcast_snoop_init();
+@@ -557,6 +567,634 @@ set_actions_and_enqueue_msg(struct rconn *swconn,
+     ofpbuf_uninit(&ofpacts);
+ }
+ 
++static struct shash ipv6_prefixd;
++
++enum {
++    PREFIX_SOLICIT,
++    PREFIX_REQUEST,
++    PREFIX_PENDING,
++    PREFIX_DONE,
++};
++
++struct ipv6_prefixd_state {
++    long long int next_announce;
++    struct in6_addr ipv6_addr;
++    struct eth_addr ea;
++    struct eth_addr cmac;
++    int64_t port_key;
++    int64_t metadata;
++    struct in6_addr prefix;
++    uint32_t plife_time;
++    uint32_t vlife_time;
++    uint32_t aid;
++    uint32_t t1;
++    uint32_t t2;
++    uint32_t plen;
++    int state;
++};
++
++static void
++init_ipv6_prefixd(void)
++{
++    shash_init(&ipv6_prefixd);
++}
++
++static void
++destroy_ipv6_prefixd(void)
++{
++    struct shash_node *iter, *next;
++    SHASH_FOR_EACH_SAFE (iter, next, &ipv6_prefixd) {
++        struct ipv6_prefixd_state *pfd = iter->data;
++        free(pfd);
++        shash_delete(&ipv6_prefixd, iter);
++    }
++    shash_destroy(&ipv6_prefixd);
++}
++
++static struct ipv6_prefixd_state *
++pinctrl_find_prefixd_state(const struct flow *ip_flow, unsigned aid)
++{
++    struct shash_node *iter;
++
++    SHASH_FOR_EACH (iter, &ipv6_prefixd) {
++        struct ipv6_prefixd_state *pfd = iter->data;
++        if (IN6_ARE_ADDR_EQUAL(&pfd->ipv6_addr, &ip_flow->ipv6_dst) &&
++            eth_addr_equals(pfd->ea, ip_flow->dl_dst) &&
++            pfd->aid == aid) {
++            return pfd;
++        }
++    }
++    return NULL;
++}
++
++static void
++pinctrl_parse_dhcpv6_advt(struct rconn *swconn, const struct flow *ip_flow,
++                          struct dp_packet *pkt_in, const struct match *md)
++{
++    struct udp_header *udp_in = dp_packet_l4(pkt_in);
++    size_t dlen = MIN(ntohs(udp_in->udp_len), dp_packet_l4_size(pkt_in));
++    unsigned char *in_dhcpv6_data = (unsigned char *)(udp_in + 1);
++    uint8_t *data, *end = (uint8_t *)udp_in + dlen;
++    int len = 0, aid = 0;
++
++    data = xmalloc(dlen);
++    /* skip DHCPv6 common header */
++    in_dhcpv6_data += 4;
++    while (in_dhcpv6_data < end) {
++        struct dhcpv6_opt_header *in_opt =
++             (struct dhcpv6_opt_header *)in_dhcpv6_data;
++        int opt_len = sizeof *in_opt + ntohs(in_opt->len);
++
++        if (dlen < opt_len + len) {
++            goto out;
++        }
++
++        switch (ntohs(in_opt->code)) {
++        case DHCPV6_OPT_IA_PD: {
++            struct dhcpv6_opt_ia_na *ia_na = (struct dhcpv6_opt_ia_na *)in_opt;
++            int orig_len = len, hdr_len = 0, size = sizeof *in_opt + 12;
++
++            aid = ntohl(ia_na->iaid);
++            memcpy(&data[len], in_opt, size);
++            in_opt = (struct dhcpv6_opt_header *)(in_dhcpv6_data + size);
++            len += size;
++
++            while (size < opt_len) {
++                int flen = sizeof *in_opt + ntohs(in_opt->len);
++
++                if (dlen < flen + len) {
++                    goto out;
++                }
++
++                if (ntohs(in_opt->code) == DHCPV6_OPT_IA_PREFIX) {
++                    memcpy(&data[len], in_opt, flen);
++                    hdr_len += flen;
++                    len += flen;
++                }
++                if (ntohs(in_opt->code) == DHCPV6_OPT_STATUS_CODE) {
++                   struct dhcpv6_opt_status *status;
++
++                   status = (struct dhcpv6_opt_status *)in_opt;
++                   if (ntohs(status->status_code)) {
++                       goto out;
++                   }
++                }
++                size += flen;
++                in_opt = (struct dhcpv6_opt_header *)(in_dhcpv6_data + size);
++            }
++            in_opt = (struct dhcpv6_opt_header *)&data[orig_len];
++            in_opt->len = htons(hdr_len + 12);
++            break;
++        }
++        case DHCPV6_OPT_SERVER_ID_CODE:
++        case DHCPV6_OPT_CLIENT_ID_CODE:
++            memcpy(&data[len], in_opt, opt_len);
++            len += opt_len;
++            break;
++        default:
++            break;
++        }
++        in_dhcpv6_data += opt_len;
++    }
++
++    struct ipv6_prefixd_state *pfd = pinctrl_find_prefixd_state(ip_flow, aid);
++    if (!pfd) {
++        goto out;
++    }
++
++    pfd->state = PREFIX_REQUEST;
++
++    uint64_t packet_stub[256 / 8];
++    struct dp_packet packet;
++
++    dp_packet_use_stub(&packet, packet_stub, sizeof packet_stub);
++    eth_compose(&packet, ip_flow->dl_src, ip_flow->dl_dst, ETH_TYPE_IPV6,
++                IPV6_HEADER_LEN);
++
++    struct udp_header *udp_h = compose_ipv6(&packet, IPPROTO_UDP,
++                                            &ip_flow->ipv6_dst,
++                                            &ip_flow->ipv6_src, 0, 0, 255,
++                                            len + UDP_HEADER_LEN + 4);
++    udp_h->udp_len = htons(len + UDP_HEADER_LEN + 4);
++    udp_h->udp_csum = 0;
++    packet_set_udp_port(&packet, htons(546), htons(547));
++
++    unsigned char *dhcp_hdr = (unsigned char *)(udp_h + 1);
++    *dhcp_hdr = DHCPV6_MSG_TYPE_REQUEST;
++    memcpy(dhcp_hdr + 4, data, len);
++
++    uint32_t csum = packet_csum_pseudoheader6(dp_packet_l3(&packet));
++    csum = csum_continue(csum, udp_h, dp_packet_size(&packet) -
++                         ((const unsigned char *)udp_h -
++                          (const unsigned char *)dp_packet_eth(&packet)));
++    udp_h->udp_csum = csum_finish(csum);
++    if (!udp_h->udp_csum) {
++        udp_h->udp_csum = htons(0xffff);
++    }
++
++    if (ip_flow->vlans[0].tci & htons(VLAN_CFI)) {
++        eth_push_vlan(&packet, htons(ETH_TYPE_VLAN_8021Q),
++                      ip_flow->vlans[0].tci);
++    }
++
++    uint64_t ofpacts_stub[4096 / 8];
++    struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(ofpacts_stub);
++    enum ofp_version version = rconn_get_version(swconn);
++    put_load(ntohll(md->flow.metadata), MFF_LOG_DATAPATH, 0, 64, &ofpacts);
++    put_load(md->flow.regs[MFF_LOG_INPORT - MFF_REG0], MFF_LOG_OUTPORT,
++             0, 32, &ofpacts);
++    struct ofpact_resubmit *resubmit = ofpact_put_RESUBMIT(&ofpacts);
++    resubmit->in_port = OFPP_CONTROLLER;
++    resubmit->table_id = OFTABLE_REMOTE_OUTPUT;
++
++    struct ofputil_packet_out po = {
++        .packet = dp_packet_data(&packet),
++        .packet_len = dp_packet_size(&packet),
++        .buffer_id = UINT32_MAX,
++        .ofpacts = ofpacts.data,
++        .ofpacts_len = ofpacts.size,
++    };
++    match_set_in_port(&po.flow_metadata, OFPP_CONTROLLER);
++    enum ofputil_protocol proto = ofputil_protocol_from_ofp_version(version);
++    queue_msg(swconn, ofputil_encode_packet_out(&po, proto));
++    dp_packet_uninit(&packet);
++    ofpbuf_uninit(&ofpacts);
++
++out:
++    free(data);
++}
++
++static void
++pinctrl_prefixd_state_handler(const struct flow *ip_flow,
++                              struct in6_addr addr, unsigned aid,
++                              char prefix_len, unsigned t1, unsigned t2,
++                              unsigned plife_time, unsigned vlife_time)
++{
++    struct ipv6_prefixd_state *pfd;
++
++    pfd = pinctrl_find_prefixd_state(ip_flow, aid);
++    if (pfd) {
++        pfd->state = PREFIX_PENDING;
++        pfd->plife_time = plife_time;
++        pfd->vlife_time = vlife_time;
++        pfd->plen = prefix_len;
++        pfd->prefix = addr;
++        pfd->t1 = t1;
++        pfd->t2 = t2;
++        notify_pinctrl_main();
++    }
++}
++
++static void
++pinctrl_parse_dhcpv6_reply(struct dp_packet *pkt_in,
++                           const struct flow *ip_flow)
++    OVS_REQUIRES(pinctrl_mutex)
++{
++    struct udp_header *udp_in = dp_packet_l4(pkt_in);
++    unsigned char *in_dhcpv6_data = (unsigned char *)(udp_in + 1);
++    size_t dlen = MIN(ntohs(udp_in->udp_len), dp_packet_l4_size(pkt_in));
++    unsigned t1 = 0, t2 = 0, vlife_time = 0, plife_time = 0;
++    uint8_t *end = (uint8_t *)udp_in + dlen;
++    uint8_t prefix_len = 0;
++    struct in6_addr ipv6;
++    bool status = false;
++    unsigned aid = 0;
++
++    memset(&ipv6, 0, sizeof (struct in6_addr));
++    /* skip DHCPv6 common header */
++    in_dhcpv6_data += 4;
++    while (in_dhcpv6_data < end) {
++        struct dhcpv6_opt_header *in_opt =
++             (struct dhcpv6_opt_header *)in_dhcpv6_data;
++        int opt_len = sizeof *in_opt + ntohs(in_opt->len);
++
++        if (in_dhcpv6_data + opt_len > end) {
++            break;
++        }
++
++        switch (ntohs(in_opt->code)) {
++        case DHCPV6_OPT_IA_PD: {
++            int size = sizeof *in_opt + 12;
++            in_opt = (struct dhcpv6_opt_header *)(in_dhcpv6_data + size);
++            struct dhcpv6_opt_ia_na *ia_na =
++                (struct dhcpv6_opt_ia_na *)in_dhcpv6_data;
++
++            aid = ntohl(ia_na->iaid);
++            t1 = ntohl(ia_na->t1);
++            t2 = ntohl(ia_na->t2);
++            if (t1 > t2 && t2 > 0) {
++                break;
++            }
++
++            while (size < opt_len) {
++                if (ntohs(in_opt->code) == DHCPV6_OPT_IA_PREFIX) {
++                    struct dhcpv6_opt_ia_prefix *ia_hdr =
++                        (struct dhcpv6_opt_ia_prefix *)(in_dhcpv6_data + size);
++
++                    prefix_len = ia_hdr->plen;
++                    plife_time = ntohl(ia_hdr->plife_time);
++                    vlife_time = ntohl(ia_hdr->vlife_time);
++                    memcpy(&ipv6, &ia_hdr->ipv6, sizeof (struct in6_addr));
++                }
++                if (ntohs(in_opt->code) == DHCPV6_OPT_STATUS_CODE) {
++                   struct dhcpv6_opt_status *status_hdr;
++
++                   status_hdr = (struct dhcpv6_opt_status *)in_opt;
++                   status = ntohs(status_hdr->status_code) == 0;
++                }
++                size += sizeof *in_opt + ntohs(in_opt->len);
++                in_opt = (struct dhcpv6_opt_header *)(in_dhcpv6_data + size);
++            }
++            break;
++        }
++        default:
++            break;
++        }
++        in_dhcpv6_data += opt_len;
++    }
++    if (status) {
++        pinctrl_prefixd_state_handler(ip_flow, ipv6, aid, prefix_len,
++                                      t1, t2, plife_time, vlife_time);
++    }
++}
++
++static void
++pinctrl_handle_dhcp6_server(struct rconn *swconn, const struct flow *ip_flow,
++                            struct dp_packet *pkt_in, const struct match *md)
++    OVS_REQUIRES(pinctrl_mutex)
++{
++    if (ip_flow->dl_type != htons(ETH_TYPE_IPV6) ||
++        ip_flow->nw_proto != IPPROTO_UDP) {
++        return;
++    }
++
++    struct udp_header *udp_in = dp_packet_l4(pkt_in);
++    unsigned char *dhcp_hdr = (unsigned char *)(udp_in + 1);
++
++    switch (*dhcp_hdr) {
++    case DHCPV6_MSG_TYPE_ADVT:
++        pinctrl_parse_dhcpv6_advt(swconn, ip_flow, pkt_in, md);
++        break;
++    case DHCPV6_MSG_TYPE_REPLY:
++        pinctrl_parse_dhcpv6_reply(pkt_in, ip_flow);
++        break;
++    default:
++        break;
++    }
++}
++
++static void
++compose_prefixd_solicit(struct dp_packet *b,
++                        struct ipv6_prefixd_state *pfd,
++                        const struct eth_addr eth_dst,
++                        const struct in6_addr *ipv6_dst)
++{
++    eth_compose(b, eth_dst, pfd->ea, ETH_TYPE_IPV6, IPV6_HEADER_LEN);
++
++    int payload = sizeof(struct dhcpv6_opt_server_id) +
++                  sizeof(struct dhcpv6_opt_ia_na);
++    if (ipv6_addr_is_set(&pfd->prefix)) {
++        payload += sizeof(struct dhcpv6_opt_ia_prefix);
++    }
++    int len = UDP_HEADER_LEN + 4 + payload;
++    struct udp_header *udp_h = compose_ipv6(b, IPPROTO_UDP, &pfd->ipv6_addr,
++                                            ipv6_dst, 0, 0, 255, len);
++    udp_h->udp_len = htons(len);
++    udp_h->udp_csum = 0;
++    packet_set_udp_port(b, htons(546), htons(547));
++
++    unsigned char *dhcp_hdr = (unsigned char *)(udp_h + 1);
++    *dhcp_hdr = DHCPV6_MSG_TYPE_SOLICIT;
++
++    struct dhcpv6_opt_server_id *opt_client_id =
++        (struct dhcpv6_opt_server_id *)(dhcp_hdr + 4);
++    opt_client_id->opt.code = htons(DHCPV6_OPT_CLIENT_ID_CODE);
++    opt_client_id->opt.len = htons(sizeof(struct dhcpv6_opt_server_id) -
++                                   sizeof(struct dhcpv6_opt_header));
++    opt_client_id->duid_type = htons(DHCPV6_DUID_LL);
++    opt_client_id->hw_type = htons(DHCPV6_HW_TYPE_ETH);
++    opt_client_id->mac = pfd->cmac;
++
++    if (!ipv6_addr_is_set(&pfd->prefix)) {
++        pfd->aid = random_uint16();
++    }
++    struct dhcpv6_opt_ia_na *ia_pd =
++            (struct dhcpv6_opt_ia_na *)(opt_client_id + 1);
++    ia_pd->opt.code = htons(DHCPV6_OPT_IA_PD);
++    int opt_len = sizeof(struct dhcpv6_opt_ia_na) -
++                  sizeof(struct dhcpv6_opt_header);
++    if (ipv6_addr_is_set(&pfd->prefix)) {
++        opt_len += sizeof(struct dhcpv6_opt_ia_prefix);
++    }
++    ia_pd->opt.len = htons(opt_len);
++    ia_pd->iaid = htonl(pfd->aid);
++    ia_pd->t1 = OVS_BE32_MAX;
++    ia_pd->t2 = OVS_BE32_MAX;
++    if (ipv6_addr_is_set(&pfd->prefix)) {
++        struct dhcpv6_opt_ia_prefix *ia_prefix =
++            (struct dhcpv6_opt_ia_prefix *)(ia_pd + 1);
++        ia_prefix->opt.code = htons(DHCPV6_OPT_IA_PREFIX);
++        ia_prefix->opt.len = htons(sizeof(struct dhcpv6_opt_ia_prefix) -
++                                   sizeof(struct dhcpv6_opt_header));
++        ia_prefix->plife_time = OVS_BE32_MAX;
++        ia_prefix->vlife_time = OVS_BE32_MAX;
++        ia_prefix->plen = pfd->plen;
++        ia_prefix->ipv6 = pfd->prefix;
++    }
++
++    uint32_t csum = packet_csum_pseudoheader6(dp_packet_l3(b));
++    csum = csum_continue(csum, udp_h, dp_packet_size(b) -
++                         ((const unsigned char *)udp_h -
++                          (const unsigned char *)dp_packet_eth(b)));
++    udp_h->udp_csum = csum_finish(csum);
++    if (!udp_h->udp_csum) {
++        udp_h->udp_csum = htons(0xffff);
++    }
++}
++
++#define IPV6_PREFIXD_TIMEOUT    3000LL
++static long long int
++ipv6_prefixd_send(struct rconn *swconn, struct ipv6_prefixd_state *pfd)
++{
++    long long int cur_time = time_msec();
++    if (cur_time < pfd->next_announce) {
++        return pfd->next_announce;
++    }
++
++    uint64_t packet_stub[256 / 8];
++    struct dp_packet packet;
++
++    struct eth_addr eth_dst;
++    eth_dst = (struct eth_addr) ETH_ADDR_C(33,33,00,01,00,02);
++    struct in6_addr ipv6_dst;
++    ipv6_parse("ff02::1:2", &ipv6_dst);
++
++    dp_packet_use_stub(&packet, packet_stub, sizeof packet_stub);
++    compose_prefixd_solicit(&packet, pfd, eth_dst, &ipv6_dst);
++
++    uint64_t ofpacts_stub[4096 / 8];
++    struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(ofpacts_stub);
++
++    /* Set MFF_LOG_DATAPATH and MFF_LOG_INPORT. */
++    uint32_t dp_key = pfd->metadata;
++    uint32_t port_key = pfd->port_key;
++    put_load(dp_key, MFF_LOG_DATAPATH, 0, 64, &ofpacts);
++    put_load(port_key, MFF_LOG_INPORT, 0, 32, &ofpacts);
++    put_load(1, MFF_LOG_FLAGS, MLF_LOCAL_ONLY_BIT, 1, &ofpacts);
++    struct ofpact_resubmit *resubmit = ofpact_put_RESUBMIT(&ofpacts);
++    resubmit->in_port = OFPP_CONTROLLER;
++    resubmit->table_id = OFTABLE_LOG_INGRESS_PIPELINE;
++
++    struct ofputil_packet_out po = {
++        .packet = dp_packet_data(&packet),
++        .packet_len = dp_packet_size(&packet),
++        .buffer_id = UINT32_MAX,
++        .ofpacts = ofpacts.data,
++        .ofpacts_len = ofpacts.size,
++    };
++
++    match_set_in_port(&po.flow_metadata, OFPP_CONTROLLER);
++    enum ofp_version version = rconn_get_version(swconn);
++    enum ofputil_protocol proto = ofputil_protocol_from_ofp_version(version);
++    queue_msg(swconn, ofputil_encode_packet_out(&po, proto));
++    dp_packet_uninit(&packet);
++    ofpbuf_uninit(&ofpacts);
++    pfd->next_announce = cur_time + random_range(IPV6_PREFIXD_TIMEOUT);
++    pfd->state = PREFIX_SOLICIT;
++
++    return pfd->next_announce;
++}
++
++static bool ipv6_prefixd_should_inject(void)
++{
++    struct shash_node *iter;
++
++    SHASH_FOR_EACH (iter, &ipv6_prefixd) {
++        struct ipv6_prefixd_state *pfd = iter->data;
++        if (pfd->state == PREFIX_SOLICIT) {
++            return true;
++        }
++        if (pfd->state && pfd->next_announce < time_msec()) {
++            return true;
++        }
++    }
++    return false;
++}
++
++static void
++ipv6_prefixd_wait(long long int timeout)
++{
++    if (ipv6_prefixd_should_inject()) {
++        poll_timer_wait_until(timeout);
++    }
++}
++
++static void
++send_ipv6_prefixd(struct rconn *swconn, long long int *send_prefixd_time)
++    OVS_REQUIRES(pinctrl_mutex)
++{
++    struct shash_node *iter;
++
++    *send_prefixd_time = LLONG_MAX;
++    SHASH_FOR_EACH (iter, &ipv6_prefixd) {
++        struct ipv6_prefixd_state *pfd = iter->data;
++        long long int next_msg = ipv6_prefixd_send(swconn, pfd);
++        if (*send_prefixd_time > next_msg) {
++            *send_prefixd_time = next_msg;
++        }
++    }
++}
++
++static bool
++fill_ipv6_prefix_state(struct ovsdb_idl_txn *ovnsb_idl_txn,
++                       const struct local_datapath *ld,
++                       struct eth_addr ea, struct in6_addr ipv6_addr,
++                       int64_t tunnel_key, int64_t dp_tunnel_key)
++    OVS_REQUIRES(pinctrl_mutex)
++{
++    bool changed = false;
++
++    for (size_t i = 0; i < ld->n_peer_ports; i++) {
++        const struct sbrec_port_binding *pb = ld->peer_ports[i].local;
++        struct ipv6_prefixd_state *pfd;
++
++        if (!smap_get_bool(&pb->options, "ipv6_prefix", false)) {
++            pfd = shash_find_and_delete(&ipv6_prefixd, pb->logical_port);
++            if (pfd) {
++                free(pfd);
++            }
++            continue;
++        }
++
++        struct lport_addresses c_addrs;
++        for (size_t j = 0; j < pb->n_mac; j++) {
++            if (extract_lsp_addresses(pb->mac[j], &c_addrs)) {
++                    break;
++            }
++        }
++
++        pfd = shash_find_data(&ipv6_prefixd, pb->logical_port);
++        if (!pfd) {
++            pfd = xzalloc(sizeof *pfd);
++            pfd->ipv6_addr = ipv6_addr;
++            pfd->ea = ea;
++            pfd->cmac = c_addrs.ea;
++            pfd->metadata = dp_tunnel_key;
++            pfd->port_key = tunnel_key;
++            shash_add(&ipv6_prefixd, pb->logical_port, pfd);
++            pfd->next_announce = time_msec() +
++                                 random_range(IPV6_PREFIXD_TIMEOUT);
++            changed = true;
++
++            char prefix_s[IPV6_SCAN_LEN + 6];
++            const char *ipv6_pd_list = smap_get(&pb->options,
++                                                "ipv6_ra_pd_list");
++            if (!ipv6_pd_list ||
++                !ovs_scan(ipv6_pd_list, "%u:"IPV6_SCAN_FMT"/%d",
++                          &pfd->aid, prefix_s, &pfd->plen) ||
++                !ipv6_parse(prefix_s, &pfd->prefix)) {
++                pfd->prefix = in6addr_any;
++            }
++        } else if (pfd->state == PREFIX_PENDING && ovnsb_idl_txn) {
++            char prefix_str[INET6_ADDRSTRLEN + 1] = {};
++            struct smap options;
++
++            pfd->state = PREFIX_DONE;
++            pfd->next_announce = time_msec() + pfd->t1 * 1000;
++            ipv6_string_mapped(prefix_str, &pfd->prefix);
++            smap_clone(&options, &pb->options);
++            smap_add_format(&options, "ipv6_ra_pd_list", "%d:%s/%d",
++                            pfd->aid, prefix_str, pfd->plen);
++            sbrec_port_binding_set_options(pb, &options);
++            smap_destroy(&options);
++        }
++    }
++
++    return changed;
++}
++
++static void
++prepare_ipv6_prefixd(struct ovsdb_idl_txn *ovnsb_idl_txn,
++                     struct ovsdb_idl_index *sbrec_port_binding_by_name,
++                     const struct hmap *local_datapaths,
++                     const struct sbrec_chassis *chassis,
++                     const struct sset *active_tunnels)
++    OVS_REQUIRES(pinctrl_mutex)
++{
++    const struct local_datapath *ld;
++    bool changed = false;
++
++    HMAP_FOR_EACH (ld, hmap_node, local_datapaths) {
++        if (datapath_is_switch(ld->datapath)) {
++            /* logical switch */
++            continue;
++        }
++
++        for (size_t i = 0; i < ld->n_peer_ports; i++) {
++            const struct sbrec_port_binding *pb = ld->peer_ports[i].local;
++            int j;
++
++            if (!smap_get_bool(&pb->options, "ipv6_prefix_delegation",
++                               false)) {
++                continue;
++            }
++
++            const char *peer_s = smap_get(&pb->options, "peer");
++            if (!peer_s) {
++                continue;
++            }
++
++            const struct sbrec_port_binding *peer
++                = lport_lookup_by_name(sbrec_port_binding_by_name, peer_s);
++            if (!peer) {
++                continue;
++            }
++
++            char *redirect_name = xasprintf("cr-%s", pb->logical_port);
++            bool resident = lport_is_chassis_resident(
++                    sbrec_port_binding_by_name, chassis, active_tunnels,
++                    redirect_name);
++            free(redirect_name);
++            if (!resident && strcmp(pb->type, "l3gateway")) {
++                continue;
++            }
++
++            struct in6_addr ip6_addr;
++            struct eth_addr ea;
++            for (j = 0; j < pb->n_mac; j++) {
++                struct lport_addresses laddrs;
++
++                if (!extract_lsp_addresses(pb->mac[j], &laddrs)) {
++                    continue;
++                }
++
++                ea = laddrs.ea;
++                if (laddrs.n_ipv6_addrs > 0) {
++                    ip6_addr = laddrs.ipv6_addrs[0].addr;
++                    break;
++                }
++            }
++
++            if (eth_addr_is_zero(ea)) {
++                continue;
++            }
++
++            if (j == pb->n_mac) {
++                in6_generate_lla(ea, &ip6_addr);
++            }
++
++            changed |= fill_ipv6_prefix_state(ovnsb_idl_txn, ld,
++                                              ea, ip6_addr,
++                                              peer->tunnel_key,
++                                              peer->datapath->tunnel_key);
++        }
++    }
++
++    if (changed) {
++        notify_pinctrl_handler();
++    }
++}
++
+ struct buffer_info {
+     struct ofpbuf ofpacts;
+     ofp_port_t ofp_port;
+@@ -2012,6 +2650,12 @@ process_packet_in(struct rconn *swconn, const struct ofp_header *msg)
+         pinctrl_handle_bind_vport(&pin.flow_metadata.flow, &userdata);
+         ovs_mutex_unlock(&pinctrl_mutex);
+         break;
++    case ACTION_OPCODE_DHCP6_SERVER:
++        ovs_mutex_lock(&pinctrl_mutex);
++        pinctrl_handle_dhcp6_server(swconn, &headers, &packet,
++                                    &pin.flow_metadata);
++        ovs_mutex_unlock(&pinctrl_mutex);
++        break;
+ 
+     case ACTION_OPCODE_HANDLE_SVC_CHECK:
+         ovs_mutex_lock(&pinctrl_mutex);
+@@ -2090,6 +2734,7 @@ pinctrl_handler(void *arg_)
+     /* Next multicast query (IGMP) in ms. */
+     static long long int send_mcast_query_time = LLONG_MAX;
+     static long long int svc_monitors_next_run_time = LLONG_MAX;
++    static long long int send_prefixd_time = LLONG_MAX;
+ 
+     swconn = rconn_create(5, 0, DSCP_DEFAULT, 1 << OFP13_VERSION);
+ 
+@@ -2143,6 +2788,7 @@ pinctrl_handler(void *arg_)
+                 ovs_mutex_lock(&pinctrl_mutex);
+                 send_garp_rarp_run(swconn, &send_garp_rarp_time);
+                 send_ipv6_ras(swconn, &send_ipv6_ra_time);
++                send_ipv6_prefixd(swconn, &send_prefixd_time);
+                 send_mac_binding_buffered_pkts(swconn);
+                 ovs_mutex_unlock(&pinctrl_mutex);
+ 
+@@ -2160,6 +2806,7 @@ pinctrl_handler(void *arg_)
+         ipv6_ra_wait(send_ipv6_ra_time);
+         ip_mcast_querier_wait(send_mcast_query_time);
+         svc_monitors_wait(svc_monitors_next_run_time);
++        ipv6_prefixd_wait(send_prefixd_time);
+ 
+         new_seq = seq_read(pinctrl_handler_seq);
+         seq_wait(pinctrl_handler_seq, new_seq);
+@@ -2211,6 +2858,8 @@ pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn,
+                            sbrec_port_binding_by_name, br_int, chassis,
+                            local_datapaths, active_tunnels);
+     prepare_ipv6_ras(local_datapaths);
++    prepare_ipv6_prefixd(ovnsb_idl_txn, sbrec_port_binding_by_name,
++                         local_datapaths, chassis, active_tunnels);
+     sync_dns_cache(dns_table);
+     controller_event_run(ovnsb_idl_txn, ce_table, chassis);
+     ip_mcast_sync(ovnsb_idl_txn, chassis, local_datapaths,
+@@ -2757,6 +3406,7 @@ pinctrl_destroy(void)
+     free(pinctrl.br_int_name);
+     destroy_send_garps_rarps();
+     destroy_ipv6_ras();
++    destroy_ipv6_prefixd();
+     destroy_buffered_packets_map();
+     event_table_destroy();
+     destroy_put_mac_bindings();
+@@ -4471,6 +5121,7 @@ may_inject_pkts(void)
+ {
+     return (!shash_is_empty(&ipv6_ras) ||
+             !shash_is_empty(&send_garp_rarp_data) ||
++            ipv6_prefixd_should_inject() ||
+             !ovs_list_is_empty(&mcast_query_list) ||
+             !ovs_list_is_empty(&buffered_mac_bindings));
+ }
+diff --git a/include/ovn/actions.h b/include/ovn/actions.h
+index 9b014925b..e3dec99b2 100644
+--- a/include/ovn/actions.h
++++ b/include/ovn/actions.h
+@@ -91,7 +91,8 @@ struct ovn_extend_table;
+     OVNACT(TRIGGER_EVENT,     ovnact_controller_event) \
+     OVNACT(BIND_VPORT,        ovnact_bind_vport)       \
+     OVNACT(HANDLE_SVC_CHECK,  ovnact_handle_svc_check) \
+-    OVNACT(FWD_GROUP,         ovnact_fwd_group)
++    OVNACT(FWD_GROUP,         ovnact_fwd_group)       \
++    OVNACT(DHCP6_REPLY,       ovnact_null)
+ 
+ /* enum ovnact_type, with a member OVNACT_<ENUM> for each action. */
+ enum OVS_PACKED_ENUM ovnact_type {
+@@ -577,6 +578,11 @@ enum action_opcode {
+      *     MFF_LOG_INPORT = port
+      */
+     ACTION_OPCODE_HANDLE_SVC_CHECK,
++    /* handle_dhcpv6_reply { ...actions ...}."
++     *
++     *  The actions, in OpenFlow 1.3 format, follow the action_header.
++     */
++    ACTION_OPCODE_DHCP6_SERVER,
+ };
+ 
+ /* Header. */
+diff --git a/lib/actions.c b/lib/actions.c
+index 6351db765..02141af30 100644
+--- a/lib/actions.c
++++ b/lib/actions.c
+@@ -2313,6 +2313,20 @@ ovnact_put_opts_free(struct ovnact_put_opts *pdo)
+     free_gen_options(pdo->options, pdo->n_options);
+ }
+ 
++static void
++format_DHCP6_REPLY(const struct ovnact_null *a OVS_UNUSED, struct ds *s)
++{
++    ds_put_cstr(s, "handle_dhcpv6_reply;");
++}
++
++static void
++encode_DHCP6_REPLY(const struct ovnact_null *a OVS_UNUSED,
++                   const struct ovnact_encode_params *ep OVS_UNUSED,
++                   struct ofpbuf *ofpacts)
++{
++    encode_controller_op(ACTION_OPCODE_DHCP6_SERVER, ofpacts);
++}
++
+ static void
+ parse_SET_QUEUE(struct action_context *ctx)
+ {
+@@ -3260,6 +3274,8 @@ parse_action(struct action_context *ctx)
+         parse_handle_svc_check(ctx);
+     } else if (lexer_match_id(ctx->lexer, "fwd_group")) {
+         parse_fwd_group_action(ctx);
++    } else if (lexer_match_id(ctx->lexer, "handle_dhcpv6_reply")) {
++        ovnact_put_DHCP6_REPLY(ctx->ovnacts);
+     } else {
+         lexer_syntax_error(ctx->lexer, "expecting action");
+     }
+diff --git a/lib/ovn-l7.h b/lib/ovn-l7.h
+index 931e6ffcf..cbea2a0c8 100644
+--- a/lib/ovn-l7.h
++++ b/lib/ovn-l7.h
+@@ -178,8 +178,11 @@ struct dhcp_opt6_header {
+ #define DHCPV6_OPT_SERVER_ID_CODE        2
+ #define DHCPV6_OPT_IA_NA_CODE            3
+ #define DHCPV6_OPT_IA_ADDR_CODE          5
++#define DHCPV6_OPT_STATUS_CODE           13
+ #define DHCPV6_OPT_DNS_SERVER_CODE       23
+ #define DHCPV6_OPT_DOMAIN_SEARCH_CODE    24
++#define DHCPV6_OPT_IA_PD                 25
++#define DHCPV6_OPT_IA_PREFIX             26
+ 
+ #define DHCPV6_OPT_SERVER_ID \
+     DHCP_OPTION("server_id", DHCPV6_OPT_SERVER_ID_CODE, "mac")
+@@ -258,6 +261,22 @@ struct ovs_nd_route_info {
+ };
+ BUILD_ASSERT_DECL(ND_ROUTE_INFO_OPT_LEN == sizeof(struct ovs_nd_route_info));
+ 
++OVS_PACKED(
++struct dhcpv6_opt_ia_prefix {
++    struct dhcpv6_opt_header opt;
++    ovs_be32 plife_time;
++    ovs_be32 vlife_time;
++    uint8_t plen;
++    struct in6_addr ipv6;
++});
++
++OVS_PACKED(
++struct dhcpv6_opt_status {
++    struct dhcpv6_opt_header opt;
++    ovs_be16 status_code;
++    uint8_t msg[];
++});
++
+ #define DHCPV6_DUID_LL      3
+ #define DHCPV6_HW_TYPE_ETH  1
+ 
+diff --git a/ovn-sb.xml b/ovn-sb.xml
+index 3ae9d4f92..72466b97e 100644
+--- a/ovn-sb.xml
++++ b/ovn-sb.xml
+@@ -2149,6 +2149,17 @@ tcp.flags = RST;
+           <p><b>Example:</b> <code>handle_svc_check(inport);</code></p>
+         </dd>
+ 
++        <dt><code>handle_dhcpv6_reply;</code></dt>
++        <dd>
++          <p>
++            Handle DHCPv6 prefix delegation advertisements/replies from
++            a IPv6 delegation server. <code>ovn-controller</code> will
++            add an entry <code>ipv6_ra_pd_list</code> in the
++            <ref table="Port_Binding" column="options"/> table for each
++            prefix received from the delegation server
++          </p>
++        </dd>
++
+         <dt><code><var>R</var> = select(<var>N1</var>[=<var>W1</var>], <var>N2</var>[=<var>W2</var>], ...);</code></dt>
+         <dd>
+           <p>
+@@ -2182,6 +2193,13 @@ tcp.flags = RST;
+           </p>
+         </dd>
+ 
++        <dt><code>handle_dhcpv6_reply;</code></dt>
++        <dd>
++          <p>
++            This action is used to parse DHCPv6 replies from IPv6
++            Delegation Router and managed IPv6 Prefix delegation state machine
++          </p>
++        </dd>
+       </dl>
+     </column>
+ 
+diff --git a/tests/ovn.at b/tests/ovn.at
+index e8554f60d..3bc435e6d 100644
+--- a/tests/ovn.at
++++ b/tests/ovn.at
+@@ -1525,6 +1525,10 @@ fwd_group();
+ fwd_group(liveness="false", childports="eth0", "lsp1");
+     Syntax error at `"false"' expecting `,'.
+ 
++# prefix delegation
++handle_dhcpv6_reply;
++    encodes as controller(userdata=00.00.00.13.00.00.00.00)
++
+ # Miscellaneous negative tests.
+ ;
+     Syntax error at `;'.
+diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c
+index 84e5f2b5c..e59698ec4 100644
+--- a/utilities/ovn-trace.c
++++ b/utilities/ovn-trace.c
+@@ -2292,6 +2292,8 @@ trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len,
+ 
+         case OVNACT_FWD_GROUP:
+             break;
++        case OVNACT_DHCP6_REPLY:
++            break;
+         }
+     }
+     ds_destroy(&s);
+-- 
+2.25.2
+
diff --git a/SOURCES/0002-ovn-northd-Fix-memory-leak-and-incorrect-limiting-of.patch b/SOURCES/0002-ovn-northd-Fix-memory-leak-and-incorrect-limiting-of.patch
new file mode 100644
index 0000000..b82edf3
--- /dev/null
+++ b/SOURCES/0002-ovn-northd-Fix-memory-leak-and-incorrect-limiting-of.patch
@@ -0,0 +1,47 @@
+From ccaeae4261bc7d35d48a511f71cfc25728786b24 Mon Sep 17 00:00:00 2001
+From: Ilya Maximets <i.maximets@ovn.org>
+Date: Tue, 5 May 2020 13:08:50 +0200
+Subject: [PATCH 2/4] ovn-northd: Fix memory leak and incorrect limiting of
+ ECMP routes.
+
+If route count reaches UINT16_MAX, ecmp_groups_add_route() will leak the
+allocated route structure.  Also, since group->route_count incremented
+unconditionally, next attempt to add new route will succeed, because the
+value of 'route_count' is zero now and out of sync with the real number
+of routes.
+
+Fixes: 4e53974bdc4e ("ovn-northd: Support ECMP routes.")
+Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
+Acked-by: Mark Michelson <mmichels@redhat.com>
+Signed-off-by: Han Zhou <hzhou@ovn.org>
+---
+ northd/ovn-northd.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
+index ec77ae1a8..dc647d7c5 100644
+--- a/northd/ovn-northd.c
++++ b/northd/ovn-northd.c
+@@ -7188,15 +7188,15 @@ static void
+ ecmp_groups_add_route(struct ecmp_groups_node *group,
+                       const struct parsed_route *route)
+ {
+-    struct ecmp_route_list_node *er = xmalloc(sizeof *er);
+-    er->route = route;
+-    er->id = ++group->route_count;
+-    if (er->id == 0) {
++   if (group->route_count == UINT16_MAX) {
+         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
+         VLOG_WARN_RL(&rl, "too many routes in a single ecmp group.");
+         return;
+     }
+ 
++    struct ecmp_route_list_node *er = xmalloc(sizeof *er);
++    er->route = route;
++    er->id = ++group->route_count;
+     ovs_list_insert(&group->route_list, &er->list_node);
+ }
+ 
+-- 
+2.26.2
+
diff --git a/SOURCES/0002-ovn-northd-Fix-memory-leak-in-case-of-duplicate-logi.patch b/SOURCES/0002-ovn-northd-Fix-memory-leak-in-case-of-duplicate-logi.patch
new file mode 100644
index 0000000..3c0eb4c
--- /dev/null
+++ b/SOURCES/0002-ovn-northd-Fix-memory-leak-in-case-of-duplicate-logi.patch
@@ -0,0 +1,30 @@
+From 2fdce8ec0e631b759bb03a35457b17060605d887 Mon Sep 17 00:00:00 2001
+From: Ilya Maximets <i.maximets@ovn.org>
+Date: Tue, 12 May 2020 12:46:18 +0200
+Subject: [PATCH 2/2] ovn-northd: Fix memory leak in case of duplicate logical
+ router port.
+
+'lrp_networks' must be destroyed on error path.
+
+Fixes: 8e83e561879a ("ovn: Support multiple addresses on a single logical router port.")
+Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
+Signed-off-by: Numan Siddique <numans@ovn.org>
+---
+ northd/ovn-northd.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
+index c1cdb2280..a41e3d46e 100644
+--- a/northd/ovn-northd.c
++++ b/northd/ovn-northd.c
+@@ -2125,6 +2125,7 @@ join_logical_ports(struct northd_context *ctx,
+                             = VLOG_RATE_LIMIT_INIT(5, 1);
+                         VLOG_WARN_RL(&rl, "duplicate logical router port %s",
+                                      nbrp->name);
++                        destroy_lport_addresses(&lrp_networks);
+                         continue;
+                     }
+                     ovn_port_set_nb(op, NULL, nbrp);
+-- 
+2.26.2
+
diff --git a/SOURCES/0002-ovn-northd-Fix-tunnel_key-allocation-for-SB-Port_Bin.patch b/SOURCES/0002-ovn-northd-Fix-tunnel_key-allocation-for-SB-Port_Bin.patch
new file mode 100644
index 0000000..0da2b8f
--- /dev/null
+++ b/SOURCES/0002-ovn-northd-Fix-tunnel_key-allocation-for-SB-Port_Bin.patch
@@ -0,0 +1,146 @@
+From 0cda584a6ee05830c0611650fe22c642cb39b09f Mon Sep 17 00:00:00 2001
+From: Dumitru Ceara <dceara@redhat.com>
+Date: Thu, 30 Apr 2020 20:32:35 +0200
+Subject: [PATCH 2/2] ovn-northd: Fix tunnel_key allocation for SB
+ Port_Bindings.
+
+When generating Port_Binding records ovn-northd tries to reuse the
+tunnel_key value from the original SB record, if any available.
+
+However, there's no check for tunnel_keys that would conflict with
+newly allocated keys for new records. In order to avoid that, we
+don't reuse stale Port_Binding entries, i.e., their "datapath" field
+doesn't match the Datapath_Binding record associated with the
+logical switch/router they're part of.
+
+One way to reproduce the issue is:
+$ ovn-nbctl ls-add ls1
+$ ovn-nbctl ls-add ls2
+$ ovn-nbctl lsp-add ls1 lsp1
+$ ovn-nbctl lsp-add ls2 lsp2
+$ ovn-nbctl --wait=sb sync
+$ ovn-nbctl lsp-del lsp2 -- lsp-add ls1 lsp2
+
+Another option to reproduce the issue is with HA_Chassis_Group:
+$ ovn-nbctl ls-add ls1
+$ ovn-nbctl ls-add ls2
+$ ovn-nbctl lsp-add ls1 lsp1
+$ ovn-nbctl lsp-add ls2 lsp2
+$ ovn-nbctl lsp-set-type lsp2 external
+$ ovn-nbctl ha-chassis-group-add chg1
+$ ovn-nbctl ha-chassis-group-add-chassis chg1 chassis-1 30
+$ chg1_uuid=$(ovn-nbctl --bare --columns _uuid list ha_Chassis_Group .)
+$ ovn-nbctl set logical_switch_port lsp2 ha_chassis_group=${chg1_uuid}
+$ ovn-nbctl lsp-del lsp2 -- lsp-add ls1 lsp2
+
+Reported-by: Dan Williams <dcbw@redhat.com>
+Reported-at: https://bugzilla.redhat.com/1828637
+Signed-off-by: Dumitru Ceara <dceara@redhat.com>
+Acked-by: Numan Siddique <numans@ovn.org>
+Signed-off-by: Han Zhou <hzhou@ovn.org>
+(cherry picked from upstream commit 8bf9075968ac8b26f1d4d32697f4b117a61a2c49)
+
+Change-Id: I03146f0778ff50375c3f843c0e650e76008bba94
+---
+ northd/ovn-northd.c |  6 +++---
+ tests/ovn-northd.at | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 59 insertions(+), 3 deletions(-)
+
+diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
+index 5e649d0..bc1ea0b 100644
+--- a/northd/ovn-northd.c
++++ b/northd/ovn-northd.c
+@@ -2025,7 +2025,7 @@ join_logical_ports(struct northd_context *ctx,
+                 const struct nbrec_logical_switch_port *nbsp
+                     = od->nbs->ports[i];
+                 struct ovn_port *op = ovn_port_find(ports, nbsp->name);
+-                if (op) {
++                if (op && op->sb->datapath == od->sb) {
+                     if (op->nbsp || op->nbrp) {
+                         static struct vlog_rate_limit rl
+                             = VLOG_RATE_LIMIT_INIT(5, 1);
+@@ -2119,7 +2119,7 @@ join_logical_ports(struct northd_context *ctx,
+                 }
+ 
+                 struct ovn_port *op = ovn_port_find(ports, nbrp->name);
+-                if (op) {
++                if (op && op->sb->datapath == od->sb) {
+                     if (op->nbsp || op->nbrp) {
+                         static struct vlog_rate_limit rl
+                             = VLOG_RATE_LIMIT_INIT(5, 1);
+@@ -2171,7 +2171,7 @@ join_logical_ports(struct northd_context *ctx,
+                     char *redirect_name =
+                         ovn_chassis_redirect_name(nbrp->name);
+                     struct ovn_port *crp = ovn_port_find(ports, redirect_name);
+-                    if (crp) {
++                    if (crp && crp->sb->datapath == od->sb) {
+                         crp->derived = true;
+                         ovn_port_set_nb(crp, NULL, nbrp);
+                         ovs_list_remove(&crp->list);
+diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
+index 94f892b..569390c 100644
+--- a/tests/ovn-northd.at
++++ b/tests/ovn-northd.at
+@@ -1350,3 +1350,59 @@ lr_uuid=$(ovn-nbctl --columns _uuid list Logical_Router .)
+ AT_CHECK[test ${nb_uuid} = ${lr_uuid}]
+ 
+ AT_CLEANUP
++
++AT_SETUP([ovn -- check reconcile stale tunnel keys])
++ovn_start
++
++ovn-nbctl ls-add ls1
++ovn-nbctl ls-add ls2
++ovn-nbctl lsp-add ls1 lsp1
++ovn-nbctl lsp-add ls2 lsp2
++AT_CHECK([ovn-nbctl --wait=sb sync], [0])
++
++# Ports are bound on different datapaths so it's expected that they both
++# get tunnel_key == 1.
++AT_CHECK([test 1 = $(ovn-sbctl --bare --columns tunnel_key find \
++port_binding logical_port=lsp1)])
++AT_CHECK([test 1 = $(ovn-sbctl --bare --columns tunnel_key find \
++port_binding logical_port=lsp2)])
++
++ovn-nbctl lsp-del lsp2 -- lsp-add ls1 lsp2
++AT_CHECK([ovn-nbctl --wait=sb sync], [0])
++
++AT_CHECK([test 1 = $(ovn-sbctl --bare --columns tunnel_key find \
++port_binding logical_port=lsp1)])
++AT_CHECK([test 2 = $(ovn-sbctl --bare --columns tunnel_key find \
++port_binding logical_port=lsp2)])
++
++# ovn-northd should allocate a new tunnel_key for lsp1 or lsp2 to maintain
++# unique DB indices.
++AT_CHECK([test ${pb1_key} != ${pb2_key}])
++
++AT_CLEANUP
++
++AT_SETUP([ovn -- check reconcile stale Ha_Chassis_Group])
++ovn_start
++
++ovn-nbctl ls-add ls1
++ovn-nbctl ls-add ls2
++ovn-nbctl lsp-add ls1 lsp1
++ovn-nbctl lsp-add ls2 lsp2
++
++ovn-nbctl lsp-set-type lsp2 external
++
++ovn-nbctl ha-chassis-group-add chg1
++ovn-nbctl ha-chassis-group-add-chassis chg1 chassis-1 30
++
++chg1_uuid=$(ovn-nbctl --bare --columns _uuid list Ha_Chassis_Group .)
++ovn-nbctl set logical_switch_port lsp2 ha_chassis_group=${chg1_uuid}
++AT_CHECK([ovn-nbctl --wait=sb sync], [0])
++
++# Move lsp2 from ls2 to ls1. This should also remove the SB HA_Chassis_Group
++# record.
++ovn-nbctl lsp-del lsp2 -- lsp-add ls1 lsp2
++AT_CHECK([ovn-nbctl --wait=sb sync], [0])
++
++AT_CHECK([test 0 = $(ovn-sbctl list Ha_Chassis_Group | wc -l)])
++
++AT_CLEANUP
+-- 
+1.8.3.1
+
diff --git a/SOURCES/0002-ovn-northd-Skip-unsnat-flows-for-load-balancer-vips-.patch b/SOURCES/0002-ovn-northd-Skip-unsnat-flows-for-load-balancer-vips-.patch
new file mode 100644
index 0000000..c64e616
--- /dev/null
+++ b/SOURCES/0002-ovn-northd-Skip-unsnat-flows-for-load-balancer-vips-.patch
@@ -0,0 +1,340 @@
+From f075920452dbcaab7c185efd4f63a02bd6e384ce Mon Sep 17 00:00:00 2001
+From: Numan Siddique <numans@ovn.org>
+Date: Thu, 26 Mar 2020 20:19:12 +0530
+Subject: [PATCH 2/2] ovn-northd: Skip unsnat flows for load balancer vips in
+ router ingress pipeline
+
+Suppose there is below NAT entry with external_ip = 172.168.0.100
+
+nat <UUID>
+    external ip: "172.168.0.100"
+    logical ip: "10.0.0.0/24"
+    type: "snat"
+
+And a load balancer with the VIP - 172.168.0.100
+
+_uuid               : <UUID>
+external_ids        : {}
+name                : lb1
+protocol            : tcp
+vips                : {"172.168.0.100:8080"="10.0.0.4:8080"}
+
+And if these are associated to a gateway logical router
+
+Then we will see the below lflows in the router pipeline
+
+...
+table=5 (lr_in_unsnat       ), priority=90   , match=(ip && ip4.dst == 172.168.0.100), action=(ct_snat;)
+...
+table=6 (lr_in_dnat         ), priority=120  , match=(ct.new && ip && ip4.dst == 172.168.0.100 && tcp && tcp.dst == 8080), action=(ct_lb(10.0.0.4:8080);)
+table=6 (lr_in_dnat         ), priority=120  , match=(ct.est && ip && ip4.dst == 172.168.0.100 && tcp && tcp.dst == 8080), action=(ct_dnat;)
+
+When a new connection packet destinated for the lb vip 172.168.0.100 and tcp.dst = 8080
+is received, the ct.new flow in the lr_in_dnat is hit and the packet's ip4.dst is
+dnatted to 10.0.0.4 in the dnat conntrack zone.
+
+But for the subsequent packet destined to the vip, the ct.est lflow in the lr_in_dnat
+stage doesn't get hit. In this case, the packet first hits the lr_in_unsnat pri 90 flow
+as mentioned above with the action ct_snat. Even though ct_snat should have no effect,
+looks like it is resetting the ct flags.
+
+In the case of tcp, the ct.new flow is hit instead of ct.est. In the the case of sctp, neither of the above
+lflows in lr_in_dnat stage hit.
+
+This needs to be investigated further. But we can avoid this scenario in OVN
+by adding the below lflow.
+
+table=5 (lr_in_unsnat       ), priority=120  , match=(ip4 && ip4.dst == 172.168.0.100 && tcp.dst == 8080), action=(next;)
+
+This patch adds the above lflow if the lb vip also has an entry in the NAT table.
+
+This patch is also required to support sctp load balancers in OVN.
+
+Reported-by: Tim Rozet <trozet@redhat.com>
+Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=1815217
+Signed-off-by: Numan Siddique <numans@ovn.org>
+Acked-by: Mark Michelson <mmichels@redhat.com>
+(cherry picked from upstream OVS branch20.03 commit 3cf40e8b35c5d6a4e593b42b96c284a8742235d5)
+
+Change-Id: Ibf609537189e80a9e69e6c968b8e4041ecc9cc40
+---
+ northd/ovn-northd.8.xml | 27 +++++++++++++++++++
+ northd/ovn-northd.c     | 59 +++++++++++++++++++++++++++++++----------
+ tests/ovn-northd.at     | 38 ++++++++++++++++++++++++++
+ tests/system-ovn.at     | 51 ++++++++++++++++++++++++++++++++++-
+ 4 files changed, 160 insertions(+), 15 deletions(-)
+
+diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
+index 1e0993e07..b5e4d6d84 100644
+--- a/northd/ovn-northd.8.xml
++++ b/northd/ovn-northd.8.xml
+@@ -2075,6 +2075,33 @@ icmp6 {
+       unSNATted here.
+     </p>
+ 
++    <p>Ingress Table 5: UNSNAT on Gateway and Distributed Routers</p>
++    <ul>
++      <li>
++        <p>
++          If the Router (Gateway or Distributed) is configured with
++          load balancers, then below lflows are added:
++        </p>
++
++        <p>
++          For each IPv4 address <var>A</var> defined as load balancer
++          VIP with the protocol <var>P</var> (and the protocol port
++          <var>T</var> if defined) is also present as an
++          <code>external_ip</code> in the NAT table,
++          a priority-120 logical flow is added with the match
++          <code>ip4 &amp;&amp; ip4.dst == <var>A</var> &amp;&amp;
++          <var>P</var></code> with the action <code>next;</code> to
++          advance the packet to the next table. If the load balancer
++          has protocol port <code>B</code> defined, then the match also has
++          <code><var>P</var>.dst == <var>B</var></code>.
++        </p>
++
++        <p>
++          The above flows are also added for IPv6 load balancers.
++        </p>
++      </li>
++    </ul>
++
+     <p>Ingress Table 5: UNSNAT on Gateway Routers</p>
+ 
+     <ul>
+diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
+index cdaeff401..75c19df62 100644
+--- a/northd/ovn-northd.c
++++ b/northd/ovn-northd.c
+@@ -7570,7 +7570,7 @@ add_router_lb_flow(struct hmap *lflows, struct ovn_datapath *od,
+                    struct ds *match, struct ds *actions, int priority,
+                    const char *lb_force_snat_ip, struct lb_vip *lb_vip,
+                    bool is_udp, struct nbrec_load_balancer *lb,
+-                   struct shash *meter_groups)
++                   struct shash *meter_groups, struct sset *nat_entries)
+ {
+     build_empty_lb_event_flow(od, lflows, lb_vip, lb, S_ROUTER_IN_DNAT,
+                               meter_groups);
+@@ -7603,6 +7603,40 @@ add_router_lb_flow(struct hmap *lflows, struct ovn_datapath *od,
+     free(new_match);
+     free(est_match);
+ 
++    const char *ip_match = NULL;
++    if (lb_vip->addr_family == AF_INET) {
++        ip_match = "ip4";
++    } else {
++        ip_match = "ip6";
++    }
++
++    if (sset_contains(nat_entries, lb_vip->vip)) {
++        /* The load balancer vip is also present in the NAT entries.
++         * So add a high priority lflow to advance the the packet
++         * destined to the vip (and the vip port if defined)
++         * in the S_ROUTER_IN_UNSNAT stage.
++         * There seems to be an issue with ovs-vswitchd. When the new
++         * connection packet destined for the lb vip is received,
++         * it is dnat'ed in the S_ROUTER_IN_DNAT stage in the dnat
++         * conntrack zone. For the next packet, if it goes through
++         * unsnat stage, the conntrack flags are not set properly, and
++         * it doesn't hit the established state flows in
++         * S_ROUTER_IN_DNAT stage. */
++        struct ds unsnat_match = DS_EMPTY_INITIALIZER;
++        ds_put_format(&unsnat_match, "%s && %s.dst == %s && %s",
++                      ip_match, ip_match, lb_vip->vip,
++                      is_udp ? "udp" : "tcp");
++        if (lb_vip->vip_port) {
++            ds_put_format(&unsnat_match, " && %s.dst == %d",
++                          is_udp ? "udp" : "tcp", lb_vip->vip_port);
++        }
++
++        ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_UNSNAT, 120,
++                                ds_cstr(&unsnat_match), "next;", &lb->header_);
++
++        ds_destroy(&unsnat_match);
++    }
++
+     if (!od->l3dgw_port || !od->l3redirect_port || !lb_vip->n_backends) {
+         return;
+     }
+@@ -7612,19 +7646,11 @@ add_router_lb_flow(struct hmap *lflows, struct ovn_datapath *od,
+      * router has a gateway router port associated.
+      */
+     struct ds undnat_match = DS_EMPTY_INITIALIZER;
+-    if (lb_vip->addr_family == AF_INET) {
+-        ds_put_cstr(&undnat_match, "ip4 && (");
+-    } else {
+-        ds_put_cstr(&undnat_match, "ip6 && (");
+-    }
++    ds_put_format(&undnat_match, "%s && (", ip_match);
+ 
+     for (size_t i = 0; i < lb_vip->n_backends; i++) {
+         struct lb_vip_backend *backend = &lb_vip->backends[i];
+-        if (backend->addr_family == AF_INET) {
+-            ds_put_format(&undnat_match, "(ip4.src == %s", backend->ip);
+-        } else {
+-            ds_put_format(&undnat_match, "(ip6.src == %s", backend->ip);
+-        }
++        ds_put_format(&undnat_match, "(%s.src == %s", ip_match, backend->ip);
+ 
+         if (backend->port) {
+             ds_put_format(&undnat_match, " && %s.src == %d) || ",
+@@ -8875,6 +8901,11 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
+                                             &nat->header_);
+                     sset_add(&nat_entries, nat->external_ip);
+                 }
++            } else {
++                /* Add the NAT external_ip to the nat_entries even for
++                 * gateway routers. This is required for adding load balancer
++                 * flows.*/
++                sset_add(&nat_entries, nat->external_ip);
+             }
+ 
+             /* Egress UNDNAT table: It is for already established connections'
+@@ -9055,8 +9086,6 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
+             }
+         }
+ 
+-        sset_destroy(&nat_entries);
+-
+         /* Handle force SNAT options set in the gateway router. */
+         if (dnat_force_snat_ip && !od->l3dgw_port) {
+             /* If a packet with destination IP address as that of the
+@@ -9117,6 +9146,7 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
+         /* Load balancing and packet defrag are only valid on
+          * Gateway routers or router with gateway port. */
+         if (!smap_get(&od->nbr->options, "chassis") && !od->l3dgw_port) {
++            sset_destroy(&nat_entries);
+             continue;
+         }
+ 
+@@ -9191,10 +9221,11 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
+                 }
+                 add_router_lb_flow(lflows, od, &match, &actions, prio,
+                                    lb_force_snat_ip, lb_vip, is_udp,
+-                                   nb_lb, meter_groups);
++                                   nb_lb, meter_groups, &nat_entries);
+             }
+         }
+         sset_destroy(&all_ips);
++        sset_destroy(&nat_entries);
+     }
+ 
+     /* Logical router ingress table ND_RA_OPTIONS & ND_RA_RESPONSE: IPv6 Router
+diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
+index a2989e78e..d127152f5 100644
+--- a/tests/ovn-northd.at
++++ b/tests/ovn-northd.at
+@@ -1288,3 +1288,41 @@ ovn-nbctl --wait=sb lb-del lb2
+ OVS_WAIT_UNTIL([test 0 = `ovn-sbctl list service_monitor |  wc -l`])
+ 
+ AT_CLEANUP
++
++AT_SETUP([ovn -- Load balancer VIP in NAT entries])
++AT_SKIP_IF([test $HAVE_PYTHON = no])
++ovn_start
++
++ovn-nbctl lr-add lr0
++ovn-nbctl lrp-add lr0 lr0-public 00:00:01:01:02:04 192.168.2.1/24
++ovn-nbctl lrp-add lr0 lr0-join 00:00:01:01:02:04 10.10.0.1/24
++
++ovn-nbctl set logical_router lr0 options:chassis=ch1
++
++ovn-nbctl lb-add lb1 "192.168.2.1:8080" "10.0.0.4:8080"
++ovn-nbctl lb-add lb2 "192.168.2.4:8080" "10.0.0.5:8080" udp
++ovn-nbctl lb-add lb3 "192.168.2.5:8080" "10.0.0.6:8080"
++ovn-nbctl lb-add lb4 "192.168.2.6:8080" "10.0.0.7:8080"
++
++ovn-nbctl lr-lb-add lr0 lb1
++ovn-nbctl lr-lb-add lr0 lb2
++ovn-nbctl lr-lb-add lr0 lb3
++ovn-nbctl lr-lb-add lr0 lb4
++
++ovn-nbctl lr-nat-add lr0 snat 192.168.2.1 10.0.0.0/24
++ovn-nbctl lr-nat-add lr0 dnat_and_snat 192.168.2.4 10.0.0.4
++ovn-nbctl lr-nat-add lr0 dnat 192.168.2.5 10.0.0.5
++
++OVS_WAIT_UNTIL([test 1 = $(ovn-sbctl dump-flows lr0 | grep lr_in_unsnat | \
++grep "ip4 && ip4.dst == 192.168.2.1 && tcp && tcp.dst == 8080" -c) ])
++
++AT_CHECK([test 1 = $(ovn-sbctl dump-flows lr0 | grep lr_in_unsnat | \
++grep "ip4 && ip4.dst == 192.168.2.4 && udp && udp.dst == 8080" -c) ])
++
++AT_CHECK([test 1 = $(ovn-sbctl dump-flows lr0 | grep lr_in_unsnat | \
++grep "ip4 && ip4.dst == 192.168.2.5 && tcp && tcp.dst == 8080" -c) ])
++
++AT_CHECK([test 0 = $(ovn-sbctl dump-flows lr0 | grep lr_in_unsnat | \
++grep "ip4 && ip4.dst == 192.168.2.6 && tcp && tcp.dst == 8080" -c) ])
++
++AT_CLEANUP
+diff --git a/tests/system-ovn.at b/tests/system-ovn.at
+index 3b3379840..f1ae69b20 100644
+--- a/tests/system-ovn.at
++++ b/tests/system-ovn.at
+@@ -1635,7 +1635,6 @@ ovn-nbctl set load_balancer $uuid vips:'"30.0.0.2:8000"'='"192.168.1.2:80,192.16
+ ovn-nbctl -- --id=@nat create nat type="snat" logical_ip=192.168.2.2 \
+     external_ip=30.0.0.2 -- add logical_router R2 nat @nat
+ 
+-
+ # Wait for ovn-controller to catch up.
+ ovn-nbctl --wait=hv sync
+ OVS_WAIT_UNTIL([ovs-ofctl -O OpenFlow13 dump-groups br-int | \
+@@ -1671,6 +1670,56 @@ tcp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(sr
+ tcp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.2.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+ ])
+ 
++check_est_flows () {
++    n=$(ovs-ofctl dump-flows br-int table=14 | grep \
++"priority=120,ct_state=+est+trk,tcp,metadata=0x2,nw_dst=30.0.0.2,tp_dst=8000" \
++| grep nat | sed -n 's/.*n_packets=\([[0-9]]\{1,\}\).*/\1/p')
++
++    echo "n_packets=$n"
++    test "$n" != 0
++}
++
++OVS_WAIT_UNTIL([check_est_flows], [check established flows])
++
++
++ovn-nbctl set logical_router R2 options:lb_force_snat_ip="20.0.0.2"
++
++# Destroy the load balancer and create again. ovn-controller will
++# clear the OF flows and re add again and clears the n_packets
++# for these flows.
++ovn-nbctl destroy load_balancer $uuid
++uuid=`ovn-nbctl  create load_balancer vips:30.0.0.1="192.168.1.2,192.168.2.2"`
++ovn-nbctl set logical_router R2 load_balancer=$uuid
++
++# Config OVN load-balancer with another VIP (this time with ports).
++ovn-nbctl set load_balancer $uuid vips:'"30.0.0.2:8000"'='"192.168.1.2:80,192.168.2.2:80"'
++
++ovn-nbctl list load_balancer
++ovn-sbctl dump-flows R2
++OVS_WAIT_UNTIL([ovs-ofctl -O OpenFlow13 dump-flows br-int table=41 | \
++grep 'nat(src=20.0.0.2)'])
++
++dnl Test load-balancing that includes L4 ports in NAT.
++for i in `seq 1 20`; do
++    echo Request $i
++    NS_CHECK_EXEC([alice1], [wget 30.0.0.2:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
++done
++
++dnl Each server should have at least one connection.
++AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.2) |
++sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
++tcp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
++tcp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.2.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
++])
++
++AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(20.0.0.2) |
++sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
++tcp,orig=(src=172.16.1.2,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=20.0.0.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
++tcp,orig=(src=172.16.1.2,dst=192.168.2.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.2.2,dst=20.0.0.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
++])
++
++OVS_WAIT_UNTIL([check_est_flows], [check established flows])
++
+ OVS_APP_EXIT_AND_WAIT([ovn-controller])
+ 
+ as ovn-sb
+-- 
+2.25.1
+
diff --git a/SOURCES/0003-IPv6-PD-Disable-pd-processing-if-the-router-port-is-.patch b/SOURCES/0003-IPv6-PD-Disable-pd-processing-if-the-router-port-is-.patch
new file mode 100644
index 0000000..57864aa
--- /dev/null
+++ b/SOURCES/0003-IPv6-PD-Disable-pd-processing-if-the-router-port-is-.patch
@@ -0,0 +1,37 @@
+From fe499ffd96efda2ffd3f7f066faebe6ec41a83f4 Mon Sep 17 00:00:00 2001
+Message-Id: <fe499ffd96efda2ffd3f7f066faebe6ec41a83f4.1588608928.git.lorenzo.bianconi@redhat.com>
+In-Reply-To: <0b9d16670d5561d8300d2448cbd4686a3acdc57e.1588608928.git.lorenzo.bianconi@redhat.com>
+References: <0b9d16670d5561d8300d2448cbd4686a3acdc57e.1588608928.git.lorenzo.bianconi@redhat.com>
+From: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
+Date: Wed, 29 Apr 2020 18:05:31 +0200
+Subject: [PATCH 3/3] IPv6 PD: Disable pd processing if the router port is
+ disabled.
+
+Tested-by: Jianlin Shi <jishi@redhat.com>
+Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
+Signed-off-by: Numan Siddique <numans@ovn.org>
+---
+ northd/ovn-northd.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/northd/ovn-northd.c
++++ b/northd/ovn-northd.c
+@@ -9373,12 +9373,18 @@ build_lrouter_flows(struct hmap *datapat
+         /* enable IPv6 prefix delegation */
+         bool prefix_delegation = smap_get_bool(&op->nbrp->options,
+                                                "prefix_delegation", false);
++        if (!lrport_is_enabled(op->nbrp)) {
++            prefix_delegation = false;
++        }
+         smap_add(&options, "ipv6_prefix_delegation",
+                  prefix_delegation ? "true" : "false");
+         sbrec_port_binding_set_options(op->sb, &options);
+ 
+         bool ipv6_prefix = smap_get_bool(&op->nbrp->options,
+                                          "prefix", false);
++        if (!lrport_is_enabled(op->nbrp)) {
++            ipv6_prefix = false;
++        }
+         smap_add(&options, "ipv6_prefix",
+                  ipv6_prefix ? "true" : "false");
+         sbrec_port_binding_set_options(op->sb, &options);
diff --git a/SOURCES/0003-Support-selection-fields-in-load-balancer.patch b/SOURCES/0003-Support-selection-fields-in-load-balancer.patch
new file mode 100644
index 0000000..97a7296
--- /dev/null
+++ b/SOURCES/0003-Support-selection-fields-in-load-balancer.patch
@@ -0,0 +1,741 @@
+From 2ee7fb81b5f396972ce279547456fd6d57891180 Mon Sep 17 00:00:00 2001
+From: Numan Siddique <numans@ovn.org>
+Date: Wed, 22 Apr 2020 18:03:57 +0530
+Subject: [PATCH 3/4] Support selection fields in load balancer.
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This patch add a new column 'selection_fields' in Load_Balancer
+table in NB DB. CMS can define a set of packet headers to use
+while selecting a backend. If this column is set, OVN will add the
+flow in group table with selection method as 'hash' with the set fields.
+Otherwise it will use the default 'dp_hash' selection method.
+
+If a load balancer is configured with the selection_fields as
+selection_fields    : [ip_dst, ip_src, tp_dst, tp_src]
+
+then with this patch, the modified ct_lb action will look like
+ - ct_lb(backends=IP1:P1,IP2:P1; hash_fields="ip_dst,ip_src,tp_dst,tp_src");
+
+And the OF flow will look like
+ - group_id=2,type=select,selection_method=hash,
+   fields(ip_src,ip_dst,tcp_src,tcp_dst),bucket=bucket_id:0,weight:100,actions=ct(....
+
+Change-Id: Iac595d50d77783fd28bcb1af7b63e9274b94f622
+Tested-by: Maciej Józefczyk <mjozefcz@redhat.com>
+Acked-by: Maciej Józefczyk <mjozefcz@redhat.com>
+Acked-by: Han Zhou <hzhou@ovn.org>
+Acked-by: Mark Michelson <mmichels@redhat.com>
+Signed-off-by: Numan Siddique <numans@ovn.org>
+---
+ NEWS                  |   6 ++
+ include/ovn/actions.h |   1 +
+ lib/actions.c         |  45 +++++++++--
+ northd/ovn-northd.c   |  30 ++++++--
+ ovn-nb.ovsschema      |  10 ++-
+ ovn-nb.xml            |  27 +++++++
+ tests/ovn-northd.at   |  24 +++---
+ tests/ovn.at          |  49 +++++++-----
+ tests/system-ovn.at   | 172 +++++++++++++++++++++++++++++++++++++++---
+ 9 files changed, 311 insertions(+), 53 deletions(-)
+
+diff --git a/NEWS b/NEWS
+index e77343c89..15c3453f8 100644
+--- a/NEWS
++++ b/NEWS
+@@ -9,6 +9,12 @@ OVN v20.03.0 - 28 Feb 2020
+    - Added support for ECMP routes in OVN router.
+    - Added IPv6 Prefix Delegation support in OVN.
+    - OVN now uses OpenFlow 1.5.
++   - Added support to choose selection methods - dp_hash or
++     hash (with specified hash fields) for OVN load balancer
++     backend selection. This is incompatible with older versions.
++     Care should be taken while upgrading as the existing
++     load balancer traffic will be affected if ovn-controllers
++     are not stopped before uprading northd services.
+ 
+    - OVN Interconnection:
+      * Support for L3 interconnection of multiple OVN deployments with tunnels
+diff --git a/include/ovn/actions.h b/include/ovn/actions.h
+index e3dec99b2..df11a5713 100644
+--- a/include/ovn/actions.h
++++ b/include/ovn/actions.h
+@@ -252,6 +252,7 @@ struct ovnact_ct_lb {
+     struct ovnact_ct_lb_dst *dsts;
+     size_t n_dsts;
+     uint8_t ltable;             /* Logical table ID of next table. */
++    char *hash_fields;
+ };
+ 
+ struct ovnact_select_dst {
+diff --git a/lib/actions.c b/lib/actions.c
+index 605dbffe4..ee7ccae0d 100644
+--- a/lib/actions.c
++++ b/lib/actions.c
+@@ -900,9 +900,18 @@ parse_ct_lb_action(struct action_context *ctx)
+     struct ovnact_ct_lb_dst *dsts = NULL;
+     size_t allocated_dsts = 0;
+     size_t n_dsts = 0;
++    char *hash_fields = NULL;
+ 
+-    if (lexer_match(ctx->lexer, LEX_T_LPAREN)) {
+-        while (!lexer_match(ctx->lexer, LEX_T_RPAREN)) {
++    if (lexer_match(ctx->lexer, LEX_T_LPAREN) &&
++        !lexer_match(ctx->lexer, LEX_T_RPAREN)) {
++        if (!lexer_match_id(ctx->lexer, "backends") ||
++            !lexer_force_match(ctx->lexer, LEX_T_EQUALS)) {
++            lexer_syntax_error(ctx->lexer, "expecting backends");
++            return;
++        }
++
++        while (!lexer_match(ctx->lexer, LEX_T_SEMICOLON) &&
++               !lexer_match(ctx->lexer, LEX_T_RPAREN)) {
+             struct ovnact_ct_lb_dst dst;
+             if (lexer_match(ctx->lexer, LEX_T_LSQUARE)) {
+                 /* IPv6 address and port */
+@@ -969,12 +978,27 @@ parse_ct_lb_action(struct action_context *ctx)
+             }
+             dsts[n_dsts++] = dst;
+         }
++
++        if (lexer_match_id(ctx->lexer, "hash_fields")) {
++            if (!lexer_match(ctx->lexer, LEX_T_EQUALS) ||
++                ctx->lexer->token.type != LEX_T_STRING ||
++                lexer_lookahead(ctx->lexer) != LEX_T_RPAREN) {
++                lexer_syntax_error(ctx->lexer, "invalid hash_fields");
++                free(dsts);
++                return;
++            }
++
++            hash_fields = xstrdup(ctx->lexer->token.s);
++            lexer_get(ctx->lexer);
++            lexer_get(ctx->lexer);
++        }
+     }
+ 
+     struct ovnact_ct_lb *cl = ovnact_put_CT_LB(ctx->ovnacts);
+     cl->ltable = ctx->pp->cur_ltable + 1;
+     cl->dsts = dsts;
+     cl->n_dsts = n_dsts;
++    cl->hash_fields = hash_fields;
+ }
+ 
+ static void
+@@ -982,10 +1006,10 @@ format_CT_LB(const struct ovnact_ct_lb *cl, struct ds *s)
+ {
+     ds_put_cstr(s, "ct_lb");
+     if (cl->n_dsts) {
+-        ds_put_char(s, '(');
++        ds_put_cstr(s, "(backends=");
+         for (size_t i = 0; i < cl->n_dsts; i++) {
+             if (i) {
+-                ds_put_cstr(s, ", ");
++                ds_put_char(s, ',');
+             }
+ 
+             const struct ovnact_ct_lb_dst *dst = &cl->dsts[i];
+@@ -1005,7 +1029,13 @@ format_CT_LB(const struct ovnact_ct_lb *cl, struct ds *s)
+             }
+         }
+         ds_put_char(s, ')');
++
++        if (cl->hash_fields) {
++            ds_chomp(s, ')');
++            ds_put_format(s, "; hash_fields=\"%s\")", cl->hash_fields);
++        }
+     }
++
+     ds_put_char(s, ';');
+ }
+ 
+@@ -1052,7 +1082,11 @@ encode_CT_LB(const struct ovnact_ct_lb *cl,
+                             : MFF_LOG_DNAT_ZONE - MFF_REG0;
+ 
+     struct ds ds = DS_EMPTY_INITIALIZER;
+-    ds_put_format(&ds, "type=select,selection_method=dp_hash");
++    ds_put_format(&ds, "type=select,selection_method=%s",
++                  cl->hash_fields ? "hash": "dp_hash");
++    if (cl->hash_fields) {
++        ds_put_format(&ds, ",fields(%s)", cl->hash_fields);
++    }
+ 
+     BUILD_ASSERT(MFF_LOG_CT_ZONE >= MFF_REG0);
+     BUILD_ASSERT(MFF_LOG_CT_ZONE < MFF_REG0 + FLOW_N_REGS);
+@@ -1094,6 +1128,7 @@ static void
+ ovnact_ct_lb_free(struct ovnact_ct_lb *ct_lb)
+ {
+     free(ct_lb->dsts);
++    free(ct_lb->hash_fields);
+ }
+ 
+ static void
+diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
+index dc647d7c5..b07e68cfa 100644
+--- a/northd/ovn-northd.c
++++ b/northd/ovn-northd.c
+@@ -3108,7 +3108,7 @@ struct ovn_lb {
+     struct hmap_node hmap_node;
+ 
+     const struct nbrec_load_balancer *nlb; /* May be NULL. */
+-
++    char *selection_fields;
+     struct lb_vip *vips;
+     size_t n_vips;
+ };
+@@ -3336,6 +3336,15 @@ ovn_lb_create(struct northd_context *ctx, struct hmap *lbs,
+         n_vips++;
+     }
+ 
++    if (lb->nlb->n_selection_fields) {
++        struct ds sel_fields = DS_EMPTY_INITIALIZER;
++        for (size_t i = 0; i < lb->nlb->n_selection_fields; i++) {
++            ds_put_format(&sel_fields, "%s,", lb->nlb->selection_fields[i]);
++        }
++        ds_chomp(&sel_fields, ',');
++        lb->selection_fields = ds_steal_cstr(&sel_fields);
++    }
++
+     return lb;
+ }
+ 
+@@ -3354,13 +3363,15 @@ ovn_lb_destroy(struct ovn_lb *lb)
+         free(lb->vips[i].backends);
+     }
+     free(lb->vips);
++    free(lb->selection_fields);
+ }
+ 
+ static void build_lb_vip_ct_lb_actions(struct lb_vip *lb_vip,
+-                                       struct ds *action)
++                                       struct ds *action,
++                                       char *selection_fields)
+ {
+     if (lb_vip->health_check) {
+-        ds_put_cstr(action, "ct_lb(");
++        ds_put_cstr(action, "ct_lb(backends=");
+ 
+         size_t n_active_backends = 0;
+         for (size_t k = 0; k < lb_vip->n_backends; k++) {
+@@ -3384,7 +3395,13 @@ static void build_lb_vip_ct_lb_actions(struct lb_vip *lb_vip,
+             ds_put_cstr(action, ");");
+         }
+     } else {
+-        ds_put_format(action, "ct_lb(%s);", lb_vip->backend_ips);
++        ds_put_format(action, "ct_lb(backends=%s);", lb_vip->backend_ips);
++    }
++
++    if (selection_fields && selection_fields[0]) {
++        ds_chomp(action, ';');
++        ds_chomp(action, ')');
++        ds_put_format(action, "; hash_fields=\"%s\");", selection_fields);
+     }
+ }
+ 
+@@ -5660,7 +5677,7 @@ build_lb_rules(struct ovn_datapath *od, struct hmap *lflows, struct ovn_lb *lb)
+ 
+         /* New connections in Ingress table. */
+         struct ds action = DS_EMPTY_INITIALIZER;
+-        build_lb_vip_ct_lb_actions(lb_vip, &action);
++        build_lb_vip_ct_lb_actions(lb_vip, &action, lb->selection_fields);
+ 
+         struct ds match = DS_EMPTY_INITIALIZER;
+         ds_put_format(&match, "ct.new && %s.dst == %s", ip_match, lb_vip->vip);
+@@ -9290,7 +9307,8 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
+             for (size_t j = 0; j < lb->n_vips; j++) {
+                 struct lb_vip *lb_vip = &lb->vips[j];
+                 ds_clear(&actions);
+-                build_lb_vip_ct_lb_actions(lb_vip, &actions);
++                build_lb_vip_ct_lb_actions(lb_vip, &actions,
++                                           lb->selection_fields);
+ 
+                 if (!sset_contains(&all_ips, lb_vip->vip)) {
+                     sset_add(&all_ips, lb_vip->vip);
+diff --git a/ovn-nb.ovsschema b/ovn-nb.ovsschema
+index 949f6258b..359201c26 100644
+--- a/ovn-nb.ovsschema
++++ b/ovn-nb.ovsschema
+@@ -1,7 +1,7 @@
+ {
+     "name": "OVN_Northbound",
+-    "version": "5.22.0",
+-    "cksum": "170077561 25417",
++    "version": "5.23.0",
++    "cksum": "3367447924 25747",
+     "tables": {
+         "NB_Global": {
+             "columns": {
+@@ -179,6 +179,12 @@
+                 "ip_port_mappings": {
+                     "type": {"key": "string", "value": "string",
+                              "min": 0, "max": "unlimited"}},
++                "selection_fields": {
++                    "type": {"key": {"type": "string",
++                             "enum": ["set",
++                                ["eth_src", "eth_dst", "ip_src", "ip_dst",
++                                 "tp_src", "tp_dst"]]},
++                             "min": 0, "max": "unlimited"}},
+                 "external_ids": {
+                     "type": {"key": "string", "value": "string",
+                              "min": 0, "max": "unlimited"}}},
+diff --git a/ovn-nb.xml b/ovn-nb.xml
+index 045c63fb0..55f0ef9f6 100644
+--- a/ovn-nb.xml
++++ b/ovn-nb.xml
+@@ -1497,6 +1497,33 @@
+       </p>
+     </column>
+ 
++    <column name="selection_fields">
++      <p>
++        OVN native load balancers are supported using the OpenFlow groups
++        of type <code>select</code>. OVS supports two selection methods:
++        <code>dp_hash</code> and <code>hash (with optional fields
++        specified)</code> in selecting the buckets of a group.
++        Please see the OVS documentation (man ovs-ofctl)
++        for more details on the selection methods. Each endpoint IP (and port
++        if set) is mapped to a bucket in the group flow.
++      </p>
++
++      <p>
++        CMS can choose the <code>hash</code> selection method by setting the
++        selection fields in this column. <code>ovs-vswitchd</code> uses the
++        specified fields in generating the hash.
++      </p>
++
++      <p>
++        <code>dp_hash</code> selection method uses the assistance of
++        datapath to calculate the hash and it is expected to be
++        faster than <code>hash</code> selection method. So CMS should take
++        this into consideration before using the <code>hash</code> method.
++        Please consult the OVS documentation and OVS sources for the
++        implementation details.
++      </p>
++    </column>
++
+     <group title="Common Columns">
+       <column name="external_ids">
+         See <em>External IDs</em> at the beginning of this document.
+diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
+index 569390cee..e6a8c04da 100644
+--- a/tests/ovn-northd.at
++++ b/tests/ovn-northd.at
+@@ -1119,7 +1119,7 @@ ovn-nbctl --wait=sb ls-lb-add sw0 lb1
+ 
+ ovn-sbctl dump-flows sw0 | grep ct_lb | grep priority=120 > lflows.txt
+ AT_CHECK([cat lflows.txt], [0], [dnl
+-  table=10(ls_in_stateful     ), priority=120  , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(ct_lb(10.0.0.3:80,20.0.0.3:80);)
++  table=10(ls_in_stateful     ), priority=120  , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(ct_lb(backends=10.0.0.3:80,20.0.0.3:80);)
+ ])
+ 
+ # Delete the Load_Balancer_Health_Check
+@@ -1128,7 +1128,7 @@ OVS_WAIT_UNTIL([test 0 = `ovn-sbctl list service_monitor |  wc -l`])
+ 
+ ovn-sbctl dump-flows sw0 | grep ct_lb | grep priority=120 > lflows.txt
+ AT_CHECK([cat lflows.txt], [0], [dnl
+-  table=10(ls_in_stateful     ), priority=120  , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(ct_lb(10.0.0.3:80,20.0.0.3:80);)
++  table=10(ls_in_stateful     ), priority=120  , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(ct_lb(backends=10.0.0.3:80,20.0.0.3:80);)
+ ])
+ 
+ # Create the Load_Balancer_Health_Check again.
+@@ -1141,7 +1141,7 @@ service_monitor | sed '/^$/d' | wc -l`])
+ 
+ ovn-sbctl dump-flows sw0 | grep ct_lb | grep priority=120 > lflows.txt
+ AT_CHECK([cat lflows.txt], [0], [dnl
+-  table=10(ls_in_stateful     ), priority=120  , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(ct_lb(10.0.0.3:80,20.0.0.3:80);)
++  table=10(ls_in_stateful     ), priority=120  , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(ct_lb(backends=10.0.0.3:80,20.0.0.3:80);)
+ ])
+ 
+ # Get the uuid of both the service_monitor
+@@ -1157,7 +1157,7 @@ OVS_WAIT_UNTIL([
+ 
+ ovn-sbctl dump-flows sw0 | grep ct_lb | grep priority=120 > lflows.txt
+ AT_CHECK([cat lflows.txt], [0], [dnl
+-  table=10(ls_in_stateful     ), priority=120  , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(ct_lb(10.0.0.3:80);)
++  table=10(ls_in_stateful     ), priority=120  , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(ct_lb(backends=10.0.0.3:80);)
+ ])
+ 
+ # Set the service monitor for sw0-p1 to offline
+@@ -1187,7 +1187,7 @@ OVS_WAIT_UNTIL([
+ 
+ ovn-sbctl dump-flows sw0 | grep ct_lb | grep priority=120 > lflows.txt
+ AT_CHECK([cat lflows.txt], [0], [dnl
+-  table=10(ls_in_stateful     ), priority=120  , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(ct_lb(10.0.0.3:80,20.0.0.3:80);)
++  table=10(ls_in_stateful     ), priority=120  , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(ct_lb(backends=10.0.0.3:80,20.0.0.3:80);)
+ ])
+ 
+ # Set the service monitor for sw1-p1 to error
+@@ -1199,7 +1199,7 @@ OVS_WAIT_UNTIL([
+ ovn-sbctl dump-flows sw0 | grep "ip4.dst == 10.0.0.10 && tcp.dst == 80" \
+ | grep priority=120 > lflows.txt
+ AT_CHECK([cat lflows.txt], [0], [dnl
+-  table=10(ls_in_stateful     ), priority=120  , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(ct_lb(10.0.0.3:80);)
++  table=10(ls_in_stateful     ), priority=120  , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(ct_lb(backends=10.0.0.3:80);)
+ ])
+ 
+ # Add one more vip to lb1
+@@ -1229,8 +1229,8 @@ service_monitor port=1000 | sed '/^$/d' | wc -l`])
+ 
+ ovn-sbctl dump-flows sw0 | grep ct_lb | grep priority=120 > lflows.txt
+ AT_CHECK([cat lflows.txt], [0], [dnl
+-  table=10(ls_in_stateful     ), priority=120  , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(ct_lb(10.0.0.3:80);)
+-  table=10(ls_in_stateful     ), priority=120  , match=(ct.new && ip4.dst == 10.0.0.40 && tcp.dst == 1000), action=(ct_lb(10.0.0.3:1000);)
++  table=10(ls_in_stateful     ), priority=120  , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(ct_lb(backends=10.0.0.3:80);)
++  table=10(ls_in_stateful     ), priority=120  , match=(ct.new && ip4.dst == 10.0.0.40 && tcp.dst == 1000), action=(ct_lb(backends=10.0.0.3:1000);)
+ ])
+ 
+ # Set the service monitor for sw1-p1 to online
+@@ -1242,16 +1242,16 @@ OVS_WAIT_UNTIL([
+ 
+ ovn-sbctl dump-flows sw0 | grep ct_lb | grep priority=120 > lflows.txt
+ AT_CHECK([cat lflows.txt], [0], [dnl
+-  table=10(ls_in_stateful     ), priority=120  , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(ct_lb(10.0.0.3:80,20.0.0.3:80);)
+-  table=10(ls_in_stateful     ), priority=120  , match=(ct.new && ip4.dst == 10.0.0.40 && tcp.dst == 1000), action=(ct_lb(10.0.0.3:1000,20.0.0.3:80);)
++  table=10(ls_in_stateful     ), priority=120  , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(ct_lb(backends=10.0.0.3:80,20.0.0.3:80);)
++  table=10(ls_in_stateful     ), priority=120  , match=(ct.new && ip4.dst == 10.0.0.40 && tcp.dst == 1000), action=(ct_lb(backends=10.0.0.3:1000,20.0.0.3:80);)
+ ])
+ 
+ # Associate lb1 to sw1
+ ovn-nbctl --wait=sb ls-lb-add sw1 lb1
+ ovn-sbctl dump-flows sw1 | grep ct_lb | grep priority=120 > lflows.txt
+ AT_CHECK([cat lflows.txt], [0], [dnl
+-  table=10(ls_in_stateful     ), priority=120  , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(ct_lb(10.0.0.3:80,20.0.0.3:80);)
+-  table=10(ls_in_stateful     ), priority=120  , match=(ct.new && ip4.dst == 10.0.0.40 && tcp.dst == 1000), action=(ct_lb(10.0.0.3:1000,20.0.0.3:80);)
++  table=10(ls_in_stateful     ), priority=120  , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(ct_lb(backends=10.0.0.3:80,20.0.0.3:80);)
++  table=10(ls_in_stateful     ), priority=120  , match=(ct.new && ip4.dst == 10.0.0.40 && tcp.dst == 1000), action=(ct_lb(backends=10.0.0.3:1000,20.0.0.3:80);)
+ ])
+ 
+ # Now create lb2 same as lb1 but udp protocol.
+diff --git a/tests/ovn.at b/tests/ovn.at
+index 5fb100ad4..ae3b44cb3 100644
+--- a/tests/ovn.at
++++ b/tests/ovn.at
+@@ -968,29 +968,42 @@ ct_lb();
+     encodes as ct(table=19,zone=NXM_NX_REG13[0..15],nat)
+     has prereqs ip
+ ct_lb(192.168.1.2:80, 192.168.1.3:80);
++    Syntax error at `192.168.1.2' expecting backends.
++ct_lb(backends=192.168.1.2:80,192.168.1.3:80);
+     encodes as group:1
+     uses group: id(1), name(type=select,selection_method=dp_hash,bucket=bucket_id=0,weight:100,actions=ct(nat(dst=192.168.1.2:80),commit,table=19,zone=NXM_NX_REG13[0..15]),bucket=bucket_id=1,weight:100,actions=ct(nat(dst=192.168.1.3:80),commit,table=19,zone=NXM_NX_REG13[0..15]))
+     has prereqs ip
+-ct_lb(192.168.1.2, 192.168.1.3, );
+-    formats as ct_lb(192.168.1.2, 192.168.1.3);
++ct_lb(backends=192.168.1.2, 192.168.1.3, );
++    formats as ct_lb(backends=192.168.1.2,192.168.1.3);
+     encodes as group:2
+     uses group: id(2), name(type=select,selection_method=dp_hash,bucket=bucket_id=0,weight:100,actions=ct(nat(dst=192.168.1.2),commit,table=19,zone=NXM_NX_REG13[0..15]),bucket=bucket_id=1,weight:100,actions=ct(nat(dst=192.168.1.3),commit,table=19,zone=NXM_NX_REG13[0..15]))
+     has prereqs ip
+-ct_lb(fd0f::2, fd0f::3, );
+-    formats as ct_lb(fd0f::2, fd0f::3);
++ct_lb(backends=fd0f::2, fd0f::3, );
++    formats as ct_lb(backends=fd0f::2,fd0f::3);
+     encodes as group:3
+     uses group: id(3), name(type=select,selection_method=dp_hash,bucket=bucket_id=0,weight:100,actions=ct(nat(dst=fd0f::2),commit,table=19,zone=NXM_NX_REG13[0..15]),bucket=bucket_id=1,weight:100,actions=ct(nat(dst=fd0f::3),commit,table=19,zone=NXM_NX_REG13[0..15]))
+     has prereqs ip
+ 
+-ct_lb(192.168.1.2:);
++ct_lb(backends=192.168.1.2:);
+     Syntax error at `)' expecting port number.
+-ct_lb(192.168.1.2:123456);
++ct_lb(backends=192.168.1.2:123456);
+     Syntax error at `123456' expecting port number.
+-ct_lb(foo);
++ct_lb(backends=foo);
+     Syntax error at `foo' expecting IP address.
+-ct_lb([192.168.1.2]);
++ct_lb(backends=[192.168.1.2]);
+     Syntax error at `192.168.1.2' expecting IPv6 address.
+ 
++ct_lb(backends=192.168.1.2:80,192.168.1.3:80; hash_fields=eth_src,eth_dst,ip_src);
++    Syntax error at `eth_src' invalid hash_fields.
++ct_lb(backends=192.168.1.2:80,192.168.1.3:80; hash_fields="eth_src,eth_dst,ip_src");
++    encodes as group:4
++    uses group: id(4), name(type=select,selection_method=hash,fields(eth_src,eth_dst,ip_src),bucket=bucket_id=0,weight:100,actions=ct(nat(dst=192.168.1.2:80),commit,table=19,zone=NXM_NX_REG13[0..15]),bucket=bucket_id=1,weight:100,actions=ct(nat(dst=192.168.1.3:80),commit,table=19,zone=NXM_NX_REG13[0..15]))
++    has prereqs ip
++ct_lb(backends=fd0f::2,fd0f::3; hash_fields="eth_src,eth_dst,ip_src,ip_dst,tp_src,tp_dst");
++    encodes as group:5
++    uses group: id(5), name(type=select,selection_method=hash,fields(eth_src,eth_dst,ip_src,ip_dst,tp_src,tp_dst),bucket=bucket_id=0,weight:100,actions=ct(nat(dst=fd0f::2),commit,table=19,zone=NXM_NX_REG13[0..15]),bucket=bucket_id=1,weight:100,actions=ct(nat(dst=fd0f::3),commit,table=19,zone=NXM_NX_REG13[0..15]))
++    has prereqs ip
++
+ # ct_next
+ ct_next;
+     encodes as ct(table=19,zone=NXM_NX_REG13[0..15])
+@@ -1491,13 +1504,13 @@ handle_svc_check(reg0);
+ # select
+ reg9[16..31] = select(1=50, 2=100, 3, );
+     formats as reg9[16..31] = select(1=50, 2=100, 3=100);
+-    encodes as group:4
+-    uses group: id(4), name(type=select,selection_method=dp_hash,bucket=bucket_id=0,weight:50,actions=load:1->xreg4[16..31],resubmit(,19),bucket=bucket_id=1,weight:100,actions=load:2->xreg4[16..31],resubmit(,19),bucket=bucket_id=2,weight:100,actions=load:3->xreg4[16..31],resubmit(,19))
++    encodes as group:6
++    uses group: id(6), name(type=select,selection_method=dp_hash,bucket=bucket_id=0,weight:50,actions=load:1->xreg4[16..31],resubmit(,19),bucket=bucket_id=1,weight:100,actions=load:2->xreg4[16..31],resubmit(,19),bucket=bucket_id=2,weight:100,actions=load:3->xreg4[16..31],resubmit(,19))
+ 
+ reg0 = select(1, 2);
+     formats as reg0 = select(1=100, 2=100);
+-    encodes as group:5
+-    uses group: id(5), name(type=select,selection_method=dp_hash,bucket=bucket_id=0,weight:100,actions=load:1->xxreg0[96..127],resubmit(,19),bucket=bucket_id=1,weight:100,actions=load:2->xxreg0[96..127],resubmit(,19))
++    encodes as group:7
++    uses group: id(7), name(type=select,selection_method=dp_hash,bucket=bucket_id=0,weight:100,actions=load:1->xxreg0[96..127],resubmit(,19),bucket=bucket_id=1,weight:100,actions=load:2->xxreg0[96..127],resubmit(,19))
+ 
+ reg0 = select(1=, 2);
+     Syntax error at `,' expecting weight.
+@@ -1513,12 +1526,12 @@ reg0[0..14] = select(1, 2, 3);
+     cannot use 15-bit field reg0[0..14] for "select", which requires at least 16 bits.
+ 
+ fwd_group(liveness="true", childports="eth0", "lsp1");
+-    encodes as group:6
+-    uses group: id(6), name(type=select,selection_method=dp_hash,bucket=watch_port:5,load=0x5->NXM_NX_REG15[0..15],resubmit(,64),bucket=watch_port:17,load=0x17->NXM_NX_REG15[0..15],resubmit(,64))
++    encodes as group:8
++    uses group: id(8), name(type=select,selection_method=dp_hash,bucket=watch_port:5,load=0x5->NXM_NX_REG15[0..15],resubmit(,64),bucket=watch_port:17,load=0x17->NXM_NX_REG15[0..15],resubmit(,64))
+ 
+ fwd_group(childports="eth0", "lsp1");
+-    encodes as group:7
+-    uses group: id(7), name(type=select,selection_method=dp_hash,bucket=load=0x5->NXM_NX_REG15[0..15],resubmit(,64),bucket=load=0x17->NXM_NX_REG15[0..15],resubmit(,64))
++    encodes as group:9
++    uses group: id(9), name(type=select,selection_method=dp_hash,bucket=load=0x5->NXM_NX_REG15[0..15],resubmit(,64),bucket=load=0x17->NXM_NX_REG15[0..15],resubmit(,64))
+ 
+ fwd_group(childports=eth0);
+     Syntax error at `eth0' expecting logical switch port.
+@@ -17916,12 +17929,12 @@ service_monitor | sed '/^$/d' | wc -l`])
+ 
+ ovn-sbctl dump-flows sw0 | grep ct_lb | grep priority=120 > lflows.txt
+ AT_CHECK([cat lflows.txt], [0], [dnl
+-  table=10(ls_in_stateful     ), priority=120  , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(ct_lb(10.0.0.3:80,20.0.0.3:80);)
++  table=10(ls_in_stateful     ), priority=120  , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(ct_lb(backends=10.0.0.3:80,20.0.0.3:80);)
+ ])
+ 
+ ovn-sbctl dump-flows lr0 | grep ct_lb | grep priority=120 > lflows.txt
+ AT_CHECK([cat lflows.txt], [0], [dnl
+-  table=6 (lr_in_dnat         ), priority=120  , match=(ct.new && ip && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80 && is_chassis_resident("cr-lr0-public")), action=(ct_lb(10.0.0.3:80,20.0.0.3:80);)
++  table=6 (lr_in_dnat         ), priority=120  , match=(ct.new && ip && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80 && is_chassis_resident("cr-lr0-public")), action=(ct_lb(backends=10.0.0.3:80,20.0.0.3:80);)
+ ])
+ 
+ # get the svc monitor mac.
+diff --git a/tests/system-ovn.at b/tests/system-ovn.at
+index 117f1e835..9a5ef1ec3 100644
+--- a/tests/system-ovn.at
++++ b/tests/system-ovn.at
+@@ -1095,15 +1095,15 @@ ovn-nbctl lsp-add bar bar3 \
+ -- lsp-set-addresses bar3 "f0:00:0f:01:02:05 172.16.1.4"
+ 
+ # Config OVN load-balancer with a VIP.
+-uuid=`ovn-nbctl  create load_balancer vips:30.0.0.1="172.16.1.2,172.16.1.3,172.16.1.4"`
+-ovn-nbctl set logical_switch foo load_balancer=$uuid
++ovn-nbctl lb-add lb1 30.0.0.1 "172.16.1.2,172.16.1.3,172.16.1.4"
++ovn-nbctl ls-lb-add foo lb1
+ 
+ # Create another load-balancer with another VIP.
+-uuid=`ovn-nbctl create load_balancer vips:30.0.0.3="172.16.1.2,172.16.1.3,172.16.1.4"`
+-ovn-nbctl add logical_switch foo load_balancer $uuid
++lb2_uuid=`ovn-nbctl create load_balancer name=lb2 vips:30.0.0.3="172.16.1.2,172.16.1.3,172.16.1.4"`
++ovn-nbctl ls-lb-add foo lb2
+ 
+ # Config OVN load-balancer with another VIP (this time with ports).
+-ovn-nbctl set load_balancer $uuid vips:'"30.0.0.2:8000"'='"172.16.1.2:80,172.16.1.3:80,172.16.1.4:80"'
++ovn-nbctl set load_balancer $lb2_uuid vips:'"30.0.0.2:8000"'='"172.16.1.2:80,172.16.1.3:80,172.16.1.4:80"'
+ 
+ # Wait for ovn-controller to catch up.
+ ovn-nbctl --wait=hv sync
+@@ -1157,6 +1157,82 @@ tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(s
+ tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=172.16.1.4,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+ ])
+ 
++# Configure selection_fields.
++ovn-nbctl set load_balancer $lb2_uuid selection_fields="ip_src,ip_dst,tp_src,tp_dst"
++OVS_WAIT_UNTIL([
++    test $(ovs-ofctl dump-groups br-int | \
++    grep "selection_method=hash,fields(ip_src,ip_dst,tcp_src,tcp_dst)" -c) -eq 2
++])
++
++AT_CHECK([ovs-appctl dpctl/flush-conntrack])
++
++dnl Test load-balancing that includes L4 ports in NAT.
++for i in `seq 1 20`; do
++    echo Request $i
++    NS_CHECK_EXEC([foo1], [wget 30.0.0.2:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
++done
++
++dnl Each server should have at least one connection.
++AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.2) | \
++sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
++tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=172.16.1.2,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
++tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=172.16.1.3,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
++tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=172.16.1.4,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
++])
++
++AT_CHECK([ovs-appctl dpctl/flush-conntrack])
++
++echo "foo" > foo
++for i in `seq 1 20`; do
++    echo Request $i
++    ip netns exec foo1 nc -p 30000 30.0.0.2 8000 < foo
++done
++
++dnl Only one backend should be chosen.
++AT_CHECK([test $(ovs-appctl dpctl/dump-conntrack | grep 30.0.0.2 -c) -eq 1])
++
++ovn-nbctl set load_balancer $lb2_uuid selection_fields="ip_src"
++OVS_WAIT_UNTIL([
++    test $(ovs-ofctl dump-groups br-int | \
++    grep "selection_method=hash,fields=ip_src" -c) -eq 2
++])
++
++AT_CHECK([ovs-appctl dpctl/flush-conntrack])
++for i in `seq 1 20`; do
++    echo Request $i
++    ip netns exec foo1 nc 30.0.0.2 8000 < foo
++done
++
++dnl Only one backend should be chosen as eth_src and ip_src is fixed.
++bar1_ct=$(ovs-appctl dpctl/dump-conntrack | grep 30.0.0.2 | grep 172.16.1.2 -c)
++bar2_ct=$(ovs-appctl dpctl/dump-conntrack | grep 30.0.0.2 | grep 172.16.1.3 -c)
++bar3_ct=$(ovs-appctl dpctl/dump-conntrack | grep 30.0.0.2 | grep 172.16.1.4 -c)
++
++AT_CHECK([test $(ovs-appctl dpctl/dump-conntrack | grep 30.0.0.2 | grep 172.16.1 -c) -ne 0])
++
++if [[ "$bar1_ct" == "20" ]]; then
++    AT_CHECK([test $bar1_ct -eq 20])
++    AT_CHECK([test $bar2_ct -eq 0])
++    AT_CHECK([test $bar3_ct -eq 0])
++else
++    AT_CHECK([test $bar1_ct -eq 0])
++fi
++
++if [[ "$bar2_ct" == "20" ]]; then
++    AT_CHECK([test $bar1_ct -eq 20])
++    AT_CHECK([test $bar2_ct -eq 0])
++    AT_CHECK([test $bar3_ct -eq 0])
++else
++    AT_CHECK([test $bar2_ct -eq 0])
++fi
++
++if [[ "$bar3_ct" == "20" ]]; then
++    AT_CHECK([test $bar1_ct -eq 20])
++    AT_CHECK([test $bar2_ct -eq 0])
++    AT_CHECK([test $bar3_ct -eq 0])
++else
++    AT_CHECK([test $bar3_ct -eq 0])
++fi
+ 
+ OVS_APP_EXIT_AND_WAIT([ovn-controller])
+ 
+@@ -1246,11 +1322,11 @@ uuid=`ovn-nbctl  create load_balancer vips:\"fd03::1\"=\"fd02::2,fd02::3,fd02::4
+ ovn-nbctl set logical_switch foo load_balancer=$uuid
+ 
+ # Create another load-balancer with another VIP.
+-uuid=`ovn-nbctl create load_balancer vips:\"fd03::3\"=\"fd02::2,fd02::3,fd02::4\"`
+-ovn-nbctl add logical_switch foo load_balancer $uuid
++lb2_uuid=`ovn-nbctl create load_balancer vips:\"fd03::3\"=\"fd02::2,fd02::3,fd02::4\"`
++ovn-nbctl add logical_switch foo load_balancer $lb2_uuid
+ 
+ # Config OVN load-balancer with another VIP (this time with ports).
+-ovn-nbctl set load_balancer $uuid vips:'"[[fd03::2]]:8000"'='"@<:@fd02::2@:>@:80,@<:@fd02::3@:>@:80,@<:@fd02::4@:>@:80"'
++ovn-nbctl set load_balancer $lb2_uuid vips:'"[[fd03::2]]:8000"'='"@<:@fd02::2@:>@:80,@<:@fd02::3@:>@:80,@<:@fd02::4@:>@:80"'
+ 
+ # Wait for ovn-controller to catch up.
+ ovn-nbctl --wait=hv sync
+@@ -1304,7 +1380,83 @@ tcp,orig=(src=fd01::2,dst=fd03::2,sport=<cleared>,dport=<cleared>),reply=(src=fd
+ tcp,orig=(src=fd01::2,dst=fd03::2,sport=<cleared>,dport=<cleared>),reply=(src=fd02::4,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+ ])
+ 
++# Configure selection_fields.
++ovn-nbctl set load_balancer $lb2_uuid selection_fields="ip_src,ip_dst,tp_src,tp_dst"
++OVS_WAIT_UNTIL([
++    test $(ovs-ofctl dump-groups br-int | \
++    grep "selection_method=hash,fields(ip_src,ip_dst,tcp_src,tcp_dst)" -c) -eq 2
++])
++
++AT_CHECK([ovs-appctl dpctl/flush-conntrack])
++
++dnl Test load-balancing that includes L4 ports in NAT.
++for i in `seq 1 20`; do
++    echo Request $i
++    NS_CHECK_EXEC([foo1], [wget http://[[fd03::2]]:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
++done
++
++dnl Each server should have at least one connection.
++AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd03::2) | grep -v fe80 | \
++sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
++tcp,orig=(src=fd01::2,dst=fd03::2,sport=<cleared>,dport=<cleared>),reply=(src=fd02::2,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
++tcp,orig=(src=fd01::2,dst=fd03::2,sport=<cleared>,dport=<cleared>),reply=(src=fd02::3,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
++tcp,orig=(src=fd01::2,dst=fd03::2,sport=<cleared>,dport=<cleared>),reply=(src=fd02::4,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
++])
++
++AT_CHECK([ovs-appctl dpctl/flush-conntrack])
++
++echo "foo" > foo
++for i in `seq 1 20`; do
++    echo Request $i
++    ip netns exec foo1 nc -6 -p 30000 fd03::2 8000 < foo
++done
++
++# Only one backend should be chosen. Since the source port is fixed,
++# there should be only one conntrack entry.
++AT_CHECK([test $(ovs-appctl dpctl/dump-conntrack | grep fd03::2 -c) -eq 1])
++
++ovn-nbctl set load_balancer $lb2_uuid selection_fields="eth_src,ip_src"
++OVS_WAIT_UNTIL([
++    test $(ovs-ofctl dump-groups br-int | \
++    grep "selection_method=hash,fields(eth_src,ip_src)" -c) -eq 2
++])
++
++AT_CHECK([ovs-appctl dpctl/flush-conntrack])
++for i in `seq 1 20`; do
++    echo Request $i
++    ip netns exec foo1 nc -6 fd03::2 8000 < foo
++done
+ 
++dnl Only one backend should be chosen as eth_src and ip_src is fixed.
++bar1_ct=$(ovs-appctl dpctl/dump-conntrack | grep fd03::2 | grep fd02::2 -c)
++bar2_ct=$(ovs-appctl dpctl/dump-conntrack | grep 30.0.0.2 | grep fd02::3 -c)
++bar3_ct=$(ovs-appctl dpctl/dump-conntrack | grep 30.0.0.2 | grep fd02::4 -c)
++
++AT_CHECK([test $(ovs-appctl dpctl/dump-conntrack | grep fd03::2 | grep fd02 -c) -ne 0])
++
++if [[ "$bar1_ct" == "20" ]]; then
++    AT_CHECK([test $bar1_ct -eq 20])
++    AT_CHECK([test $bar2_ct -eq 0])
++    AT_CHECK([test $bar3_ct -eq 0])
++else
++    AT_CHECK([test $bar1_ct -eq 0])
++fi
++
++if [[ "$bar2_ct" == "20" ]]; then
++    AT_CHECK([test $bar1_ct -eq 20])
++    AT_CHECK([test $bar2_ct -eq 0])
++    AT_CHECK([test $bar3_ct -eq 0])
++else
++    AT_CHECK([test $bar2_ct -eq 0])
++fi
++
++if [[ "$bar3_ct" == "20" ]]; then
++    AT_CHECK([test $bar1_ct -eq 20])
++    AT_CHECK([test $bar2_ct -eq 0])
++    AT_CHECK([test $bar3_ct -eq 0])
++else
++    AT_CHECK([test $bar3_ct -eq 0])
++fi
+ OVS_APP_EXIT_AND_WAIT([ovn-controller])
+ 
+ as ovn-sb
+@@ -3448,7 +3600,7 @@ service_monitor | sed '/^$/d' | grep online | wc -l`])
+ 
+ OVS_WAIT_UNTIL(
+     [ovn-sbctl dump-flows sw0 | grep ct_lb | grep priority=120 | grep "ip4.dst == 10.0.0.10" > lflows.txt
+-     test 1 = `cat lflows.txt | grep "ct_lb(10.0.0.3:80,20.0.0.3:80)" | wc -l`]
++     test 1 = `cat lflows.txt | grep "ct_lb(backends=10.0.0.3:80,20.0.0.3:80)" | wc -l`]
+ )
+ 
+ # From sw0-p2 send traffic to vip - 10.0.0.10
+@@ -3474,7 +3626,7 @@ service_monitor logical_port=sw0-p1 | sed '/^$/d' | grep offline | wc -l`])
+ 
+ OVS_WAIT_UNTIL(
+     [ovn-sbctl dump-flows sw0 | grep ct_lb | grep priority=120 | grep "ip4.dst == 10.0.0.10" > lflows.txt
+-     test 1 = `cat lflows.txt | grep "ct_lb(20.0.0.3:80)" | wc -l`]
++     test 1 = `cat lflows.txt | grep "ct_lb(backends=20.0.0.3:80)" | wc -l`]
+ )
+ 
+ ovs-appctl dpctl/flush-conntrack
+-- 
+2.26.2
+
diff --git a/SOURCES/0003-controller-fix-ip-buffering-with-static-routes.patch b/SOURCES/0003-controller-fix-ip-buffering-with-static-routes.patch
new file mode 100644
index 0000000..9f3209d
--- /dev/null
+++ b/SOURCES/0003-controller-fix-ip-buffering-with-static-routes.patch
@@ -0,0 +1,61 @@
+From 754d5581fa9d5de97f7c2acf8c2900e105f588c9 Mon Sep 17 00:00:00 2001
+Message-Id: <754d5581fa9d5de97f7c2acf8c2900e105f588c9.1590585469.git.lorenzo.bianconi@redhat.com>
+In-Reply-To: <d9ed450713eda62af1bec5009694b2d206c9f435.1590585469.git.lorenzo.bianconi@redhat.com>
+References: <d9ed450713eda62af1bec5009694b2d206c9f435.1590585469.git.lorenzo.bianconi@redhat.com>
+From: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
+Date: Wed, 20 May 2020 22:01:16 +0200
+Subject: [PATCH ovn 2/3] controller: fix ip buffering with static routes
+
+When the arp request is sent to a gw router and not to the final
+destination of the packet buffered_packets_map needs to be updated using
+next-hop ip address and not the destionation one.
+
+Fixes: 2e5cdb4b1392 ("OVN: add buffering support for ip packets")
+Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
+---
+ controller/pinctrl.c | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+--- a/controller/pinctrl.c
++++ b/controller/pinctrl.c
+@@ -1378,8 +1378,7 @@ pinctrl_find_buffered_packets(const stru
+ 
+ /* Called with in the pinctrl_handler thread context. */
+ static int
+-pinctrl_handle_buffered_packets(const struct flow *ip_flow,
+-                                struct dp_packet *pkt_in,
++pinctrl_handle_buffered_packets(struct dp_packet *pkt_in,
+                                 const struct match *md, bool is_arp)
+     OVS_REQUIRES(pinctrl_mutex)
+ {
+@@ -1388,9 +1387,10 @@ pinctrl_handle_buffered_packets(const st
+     struct in6_addr addr;
+ 
+     if (is_arp) {
+-        addr = in6_addr_mapped_ipv4(ip_flow->nw_dst);
++        addr = in6_addr_mapped_ipv4(htonl(md->flow.regs[0]));
+     } else {
+-        addr = ip_flow->ipv6_dst;
++        ovs_be128 ip6 = hton128(flow_get_xxreg(&md->flow, 0));
++        memcpy(&addr, &ip6, sizeof addr);
+     }
+ 
+     uint32_t hash = hash_bytes(&addr, sizeof addr, 0);
+@@ -1431,7 +1431,7 @@ pinctrl_handle_arp(struct rconn *swconn,
+     }
+ 
+     ovs_mutex_lock(&pinctrl_mutex);
+-    pinctrl_handle_buffered_packets(ip_flow, pkt_in, md, true);
++    pinctrl_handle_buffered_packets(pkt_in, md, true);
+     ovs_mutex_unlock(&pinctrl_mutex);
+ 
+     /* Compose an ARP packet. */
+@@ -5278,7 +5278,7 @@ pinctrl_handle_nd_ns(struct rconn *swcon
+     }
+ 
+     ovs_mutex_lock(&pinctrl_mutex);
+-    pinctrl_handle_buffered_packets(ip_flow, pkt_in, md, false);
++    pinctrl_handle_buffered_packets(pkt_in, md, false);
+     ovs_mutex_unlock(&pinctrl_mutex);
+ 
+     uint64_t packet_stub[128 / 8];
diff --git a/SOURCES/0003-logical-fields-fix-memory-leak-caused-by-initialize-.patch b/SOURCES/0003-logical-fields-fix-memory-leak-caused-by-initialize-.patch
new file mode 100644
index 0000000..26e8773
--- /dev/null
+++ b/SOURCES/0003-logical-fields-fix-memory-leak-caused-by-initialize-.patch
@@ -0,0 +1,120 @@
+From e6b687cc23212e0c007d9f69dfa89536c8f92306 Mon Sep 17 00:00:00 2001
+From: Damijan Skvarc <damjan.skvarc@gmail.com>
+Date: Thu, 5 Mar 2020 07:21:41 +0100
+Subject: [PATCH 3/3] logical-fields: fix memory leak caused by initialize
+ ovnfield_by_name twice
+
+ovnfield_by_name is hash of strings which is used to quickly find
+field by name. This hash is initialized from ovn_init_symtab(). In case
+the latter function is called multiple times then also ovnfield_by_name is
+initialized multiple times but without freeing previously allocated
+memory resources what cause memory leaks.  This actually happens in
+ovn-controller which calls ovn_init_symtab() function twice, once from
+ofctrl.c and the other time from lflow.c files.
+
+Problem was solved by initializing ovnfield_by_name entity only once
+and using design pattern from stopwatch.c or meta_flow.c files (ovs).
+
+Problem was reported by valgrind with flood of messages (190) while executing
+ovn test suite:
+
+    ==5999== 47 (32 direct, 15 indirect) bytes in 1 blocks are definitely lost in loss record 86 of 102
+    ==5999==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
+    ==5999==    by 0x50635D: xmalloc (util.c:138)
+    ==5999==    by 0x4F6513: shash_add_nocopy__ (shash.c:109)
+    ==5999==    by 0x4F6585: shash_add_nocopy (shash.c:121)
+    ==5999==    by 0x4F65BD: shash_add (shash.c:129)
+    ==5999==    by 0x4F6602: shash_add_once (shash.c:136)
+    ==5999==    by 0x4395B7: ovn_init_symtab (logical-fields.c:261)
+    ==5999==    by 0x406C91: main (ovn-controller.c:1750)
+
+Signed-off-by: Damijan Skvarc <damjan.skvarc@gmail.com>
+Signed-off-by: Ben Pfaff <blp@ovn.org>
+---
+ controller/lflow.c           |  1 -
+ include/ovn/logical-fields.h |  1 -
+ lib/logical-fields.c         | 39 +++++++++++++++++++++++++-----------
+ 3 files changed, 27 insertions(+), 14 deletions(-)
+
+diff --git a/controller/lflow.c b/controller/lflow.c
+index ee11fc617..01214a3a6 100644
+--- a/controller/lflow.c
++++ b/controller/lflow.c
+@@ -846,5 +846,4 @@ lflow_destroy(void)
+ {
+     expr_symtab_destroy(&symtab);
+     shash_destroy(&symtab);
+-    ovn_destroy_ovnfields();
+ }
+diff --git a/include/ovn/logical-fields.h b/include/ovn/logical-fields.h
+index 9b7c34fb7..c7bd2dba9 100644
+--- a/include/ovn/logical-fields.h
++++ b/include/ovn/logical-fields.h
+@@ -130,5 +130,4 @@ ovn_field_from_id(enum ovn_field_id id)
+ const char *event_to_string(enum ovn_controller_event event);
+ int string_to_event(const char *s);
+ const struct ovn_field *ovn_field_from_name(const char *name);
+-void ovn_destroy_ovnfields(void);
+ #endif /* ovn/lib/logical-fields.h */
+diff --git a/lib/logical-fields.c b/lib/logical-fields.c
+index 25ace5840..a007085b3 100644
+--- a/lib/logical-fields.c
++++ b/lib/logical-fields.c
+@@ -254,12 +254,6 @@ ovn_init_symtab(struct shash *symtab)
+     expr_symtab_add_field(symtab, "sctp.src", MFF_SCTP_SRC, "sctp", false);
+     expr_symtab_add_field(symtab, "sctp.dst", MFF_SCTP_DST, "sctp", false);
+ 
+-    shash_init(&ovnfield_by_name);
+-    for (int i = 0; i < OVN_FIELD_N_IDS; i++) {
+-        const struct ovn_field *of = &ovn_fields[i];
+-        ovs_assert(of->id == i); /* Fields must be in the enum order. */
+-        shash_add_once(&ovnfield_by_name, of->name, of);
+-    }
+     expr_symtab_add_ovn_field(symtab, "icmp4.frag_mtu", OVN_ICMP4_FRAG_MTU);
+ }
+ 
+@@ -284,14 +278,35 @@ string_to_event(const char *s)
+     return -1;
+ }
+ 
+-const struct ovn_field *
+-ovn_field_from_name(const char *name)
++static void
++ovn_destroy_ovnfields(void)
+ {
+-    return shash_find_data(&ovnfield_by_name, name);
++    shash_destroy(&ovnfield_by_name);
+ }
+ 
+-void
+-ovn_destroy_ovnfields(void)
++static void
++ovn_do_init_ovnfields(void)
+ {
+-    shash_destroy(&ovnfield_by_name);
++    shash_init(&ovnfield_by_name);
++    for (int i = 0; i < OVN_FIELD_N_IDS; i++) {
++       const struct ovn_field *of = &ovn_fields[i];
++       ovs_assert(of->id == i); /* Fields must be in the enum order. */
++       shash_add_once(&ovnfield_by_name, of->name, of);
++    }
++    atexit(ovn_destroy_ovnfields);
++}
++
++static void
++ovn_init_ovnfields(void)
++{
++    static pthread_once_t once = PTHREAD_ONCE_INIT;
++    pthread_once(&once, ovn_do_init_ovnfields);
++}
++
++const struct ovn_field *
++ovn_field_from_name(const char *name)
++{
++    ovn_init_ovnfields();
++
++    return shash_find_data(&ovnfield_by_name, name);
+ }
+-- 
+2.24.1
+
diff --git a/SOURCES/0003-northd-Add-logical-flows-for-dhcpv6-pfd-parsing.patch b/SOURCES/0003-northd-Add-logical-flows-for-dhcpv6-pfd-parsing.patch
new file mode 100644
index 0000000..79d5a4f
--- /dev/null
+++ b/SOURCES/0003-northd-Add-logical-flows-for-dhcpv6-pfd-parsing.patch
@@ -0,0 +1,449 @@
+From 643d4be1b3f40c3075af584d0cbc83e34a5e51ca Mon Sep 17 00:00:00 2001
+Message-Id: <643d4be1b3f40c3075af584d0cbc83e34a5e51ca.1586727203.git.lorenzo.bianconi@redhat.com>
+In-Reply-To: <2e84aada0b45d2f8739c2fdbc351098fc1c09c26.1586727203.git.lorenzo.bianconi@redhat.com>
+References: <2e84aada0b45d2f8739c2fdbc351098fc1c09c26.1586727203.git.lorenzo.bianconi@redhat.com>
+From: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
+Date: Wed, 1 Apr 2020 18:37:31 +0200
+Subject: [PATCH 3/3] northd: Add logical flows for dhcpv6 pfd parsing
+
+Introduce logical flows in ovn router pipeline in order to parse dhcpv6
+advertise/reply from IPv6 prefix delegation router.
+Do not overwrite ipv6_ra_pd_list info in options column of SB port_binding
+table written by ovn-controller
+Introduce ipv6_prefix column in NB Logical_router_port table to report
+IPv6 prefix received from delegation router to the CMS
+
+Change-Id: Ibc1bd83bf3d9d4671f70610df5635e6266580a18
+Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
+Signed-off-by: Numan Siddique <numans@ovn.org>
+---
+ NEWS                    |   1 +
+ northd/ovn-northd.8.xml |   8 +++
+ northd/ovn-northd.c     |  95 ++++++++++++++++++++++++--
+ ovn-nb.ovsschema        |   7 +-
+ ovn-nb.xml              |  21 ++++++
+ tests/atlocal.in        |   5 +-
+ tests/system-ovn.at     | 143 ++++++++++++++++++++++++++++++++++++++++
+ 7 files changed, 272 insertions(+), 8 deletions(-)
+
+diff --git a/NEWS b/NEWS
+index 9b36bfd17..21c80f0dc 100644
+--- a/NEWS
++++ b/NEWS
+@@ -7,6 +7,7 @@ OVN v20.03.0 - 28 Feb 2020
+    - Added Forwarding Group support in OVN.
+    - Added support for MLD Snooping and MLD Querier.
+    - Added support for ECMP routes in OVN router.
++   - Added IPv6 Prefix Delegation support in OVN.
+ 
+    - OVN Interconnection:
+      * Support for L3 interconnection of multiple OVN deployments with tunnels
+diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
+index b5e4d6d84..82c86f636 100644
+--- a/northd/ovn-northd.8.xml
++++ b/northd/ovn-northd.8.xml
+@@ -1660,6 +1660,14 @@ next;
+         </ul>
+       </li>
+ 
++      <li>
++          A priority-100 flow parses DHCPv6 replies from IPv6 prefix
++          delegation routers (<code>udp.src == 547 &amp;&amp;
++          udp.dst == 546</code>). The <code>handle_dhcpv6_reply</code>
++          is used to send IPv6 prefix delegation messages to the delegation
++          router.
++      </li>
++
+       <li>
+         <p>
+           A priority-87 flow explicitly allows IPv6 multicast traffic that is
+diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
+index bb68b8fe9..fd1be5b27 100644
+--- a/northd/ovn-northd.c
++++ b/northd/ovn-northd.c
+@@ -2688,6 +2688,33 @@ op_get_name(const struct ovn_port *op)
+     return name;
+ }
+ 
++static void
++ovn_update_ipv6_prefix(struct hmap *ports)
++{
++    const struct ovn_port *op;
++    HMAP_FOR_EACH (op, key_node, ports) {
++        if (!op->nbrp) {
++            continue;
++        }
++
++        char prefix[IPV6_SCAN_LEN + 6];
++        unsigned aid;
++        const char *ipv6_pd_list = smap_get(&op->sb->options,
++                                            "ipv6_ra_pd_list");
++        if (!ipv6_pd_list ||
++            !ovs_scan(ipv6_pd_list, "%u:%s", &aid, prefix)) {
++            continue;
++        }
++
++        struct sset ipv6_prefix_set = SSET_INITIALIZER(&ipv6_prefix_set);
++        sset_add(&ipv6_prefix_set, prefix);
++        nbrec_logical_router_port_set_ipv6_prefix(op->nbrp,
++                                            sset_array(&ipv6_prefix_set),
++                                            sset_count(&ipv6_prefix_set));
++        sset_destroy(&ipv6_prefix_set);
++    }
++}
++
+ static void
+ ovn_port_update_sbrec(struct northd_context *ctx,
+                       struct ovsdb_idl_index *sbrec_chassis_by_name,
+@@ -2818,6 +2845,13 @@ ovn_port_update_sbrec(struct northd_context *ctx,
+                 smap_add(&new, "l3gateway-chassis", chassis_name);
+             }
+         }
++
++        const char *ipv6_pd_list = smap_get(&op->sb->options,
++                                            "ipv6_ra_pd_list");
++        if (ipv6_pd_list) {
++            smap_add(&new, "ipv6_ra_pd_list", ipv6_pd_list);
++        }
++
+         sbrec_port_binding_set_options(op->sb, &new);
+         smap_destroy(&new);
+ 
+@@ -4683,12 +4717,12 @@ build_pre_acls(struct ovn_datapath *od, struct hmap *lflows)
+          * unreachable packets. */
+         ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 110,
+                       "nd || nd_rs || nd_ra || icmp4.type == 3 || "
+-                      "icmp6.type == 1 || (tcp && tcp.flags == 20)",
+-                      "next;");
++                      "icmp6.type == 1 || (tcp && tcp.flags == 20) || "
++                      "(udp && udp.src == 546 && udp.dst == 547)", "next;");
+         ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 110,
+                       "nd || nd_rs || nd_ra || icmp4.type == 3 || "
+-                      "icmp6.type == 1 || (tcp && tcp.flags == 20)",
+-                      "next;");
++                      "icmp6.type == 1 || (tcp && tcp.flags == 20) ||"
++                      "(udp && udp.src == 546 && udp.dst == 547)", "next;");
+ 
+         /* Ingress and Egress Pre-ACL Table (Priority 100).
+          *
+@@ -7744,6 +7778,11 @@ copy_ra_to_sb(struct ovn_port *op, const char *address_mode)
+         }
+         ds_put_format(&s, "%s/%u ", addrs->network_s, addrs->plen);
+     }
++
++    const char *ra_pd_list = smap_get(&op->sb->options, "ipv6_ra_pd_list");
++    if (ra_pd_list) {
++        ds_put_cstr(&s, ra_pd_list);
++    }
+     /* Remove trailing space */
+     ds_chomp(&s, ' ');
+     smap_add(&options, "ipv6_ra_prefixes", ds_cstr(&s));
+@@ -8488,7 +8527,34 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
+         free(snat_ips);
+     }
+ 
+-    /* Logical router ingress table 3: IP Input for IPv6. */
++    /* DHCPv6 reply handling */
++    HMAP_FOR_EACH (op, key_node, ports) {
++        if (!op->nbrp) {
++            continue;
++        }
++
++        if (op->derived) {
++            continue;
++        }
++
++        struct lport_addresses lrp_networks;
++        if (!extract_lrp_networks(op->nbrp, &lrp_networks)) {
++            continue;
++        }
++
++        for (size_t i = 0; i < lrp_networks.n_ipv6_addrs; i++) {
++            ds_clear(&actions);
++            ds_clear(&match);
++            ds_put_format(&match, "ip6.dst == %s && udp.src == 547 &&"
++                          " udp.dst == 546",
++                          lrp_networks.ipv6_addrs[i].addr_s);
++            ds_put_format(&actions, "reg0 = 0; handle_dhcpv6_reply;");
++            ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 100,
++                          ds_cstr(&match), ds_cstr(&actions));
++        }
++    }
++
++    /* Logical router ingress table 1: IP Input for IPv6. */
+     HMAP_FOR_EACH (op, key_node, ports) {
+         if (!op->nbrp) {
+             continue;
+@@ -9250,6 +9316,24 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
+             continue;
+         }
+ 
++        struct smap options;
++        /* enable IPv6 prefix delegation */
++        bool prefix_delegation = smap_get_bool(&op->nbrp->options,
++                                               "prefix_delegation", false);
++        if (prefix_delegation) {
++            smap_clone(&options, &op->sb->options);
++            smap_add(&options, "ipv6_prefix_delegation", "true");
++            sbrec_port_binding_set_options(op->sb, &options);
++            smap_destroy(&options);
++        }
++
++        if (smap_get_bool(&op->nbrp->options, "prefix", false)) {
++            smap_clone(&options, &op->sb->options);
++            smap_add(&options, "ipv6_prefix", "true");
++            sbrec_port_binding_set_options(op->sb, &options);
++            smap_destroy(&options);
++        }
++
+         const char *address_mode = smap_get(
+             &op->nbrp->ipv6_ra_configs, "address_mode");
+ 
+@@ -10941,6 +11025,7 @@ ovnnb_db_run(struct northd_context *ctx,
+     build_meter_groups(ctx, &meter_groups);
+     build_lflows(ctx, datapaths, ports, &port_groups, &mcast_groups,
+                  &igmp_groups, &meter_groups, &lbs);
++    ovn_update_ipv6_prefix(ports);
+ 
+     sync_address_sets(ctx);
+     sync_port_groups(ctx);
+diff --git a/ovn-nb.ovsschema b/ovn-nb.ovsschema
+index ea6f4e354..949f6258b 100644
+--- a/ovn-nb.ovsschema
++++ b/ovn-nb.ovsschema
+@@ -1,7 +1,7 @@
+ {
+     "name": "OVN_Northbound",
+-    "version": "5.20.1",
+-    "cksum": "721375950 25251",
++    "version": "5.22.0",
++    "cksum": "170077561 25417",
+     "tables": {
+         "NB_Global": {
+             "columns": {
+@@ -342,6 +342,9 @@
+                 "ipv6_ra_configs": {
+                     "type": {"key": "string", "value": "string",
+                              "min": 0, "max": "unlimited"}},
++                "ipv6_prefix": {"type": {"key": "string",
++                                      "min": 0,
++                                      "max": "unlimited"}},
+                 "external_ids": {
+                     "type": {"key": "string", "value": "string",
+                              "min": 0, "max": "unlimited"}}},
+diff --git a/ovn-nb.xml b/ovn-nb.xml
+index f7ba9c334..045c63fb0 100644
+--- a/ovn-nb.xml
++++ b/ovn-nb.xml
+@@ -2065,6 +2065,11 @@
+       port has all ingress and egress traffic dropped.
+     </column>
+ 
++    <column name="ipv6_prefix">
++       This column contains IPv6 prefix obtained by prefix delegation
++       router according to RFC 3633
++    </column>
++
+     <group title="ipv6_ra_configs">
+       <p>
+         This column defines the IPv6 ND RA address mode and ND MTU Option to be
+@@ -2320,6 +2325,22 @@
+         <code>ovn-northd</code> honors the configured value.
+       </column>
+ 
++      <column name="options" key="prefix_delegation"
++              type='{"type": "boolean"}'>
++        <p>
++          If set to <code>true</code>, enable IPv6 prefix delegation state
++          machine on this logical router port (RFC3633). IPv6 prefix
++          delegation is available just on a gateway router or on a gateway
++          router port.
++        </p>
++      </column>
++
++      <column name="options" key="prefix" type='{"type": "boolean"}'>
++        <p>
++          If set to <code>true</code>, this interface will receive an IPv6
++          prefix according to RFC3663
++        </p>
++      </column>
+     </group>
+ 
+     <group title="Attachment">
+diff --git a/tests/atlocal.in b/tests/atlocal.in
+index 5f14c3da0..8f3ff03b9 100644
+--- a/tests/atlocal.in
++++ b/tests/atlocal.in
+@@ -157,7 +157,7 @@ find_command()
+ {
+     which $1 > /dev/null 2>&1
+     status=$?
+-    var=HAVE_`echo "$1" | tr '[a-z]' '[A-Z]'`
++    var=HAVE_`echo "$1" | tr '-' '_' | tr '[a-z]' '[A-Z]'`
+     if test "$status" = "0"; then
+         eval ${var}="yes"
+     else
+@@ -192,6 +192,9 @@ else
+     DIFF_SUPPORTS_NORMAL_FORMAT=no
+ fi
+ 
++# Set HAVE_DIBBLER-SERVER
++find_command dibbler-server
++
+ # Turn off proxies.
+ unset http_proxy
+ unset https_proxy
+diff --git a/tests/system-ovn.at b/tests/system-ovn.at
+index f1ae69b20..000b3f13b 100644
+--- a/tests/system-ovn.at
++++ b/tests/system-ovn.at
+@@ -3793,3 +3793,146 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
+ /connection dropped.*/d"])
+ 
+ AT_CLEANUP
++
++AT_SETUP([ovn -- IPv6 prefix delegation])
++AT_SKIP_IF([test $HAVE_DIBBLER_SERVER = no])
++AT_SKIP_IF([test $HAVE_TCPDUMP = no])
++AT_KEYWORDS([ovn-ipv6-prefix_d])
++
++ovn_start
++OVS_TRAFFIC_VSWITCHD_START()
++
++ADD_BR([br-int])
++ADD_BR([br-ext])
++
++ovs-ofctl add-flow br-ext action=normal
++# Set external-ids in br-int needed for ovn-controller
++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
++
++ovn-nbctl lr-add R1
++
++ovn-nbctl ls-add sw0
++ovn-nbctl ls-add sw1
++ovn-nbctl ls-add public
++
++ovn-nbctl lrp-add R1 rp-sw0 00:00:01:01:02:03 192.168.1.1/24
++ovn-nbctl lrp-add R1 rp-sw1 00:00:03:01:02:03 192.168.2.1/24
++ovn-nbctl lrp-add R1 rp-public 00:00:02:01:02:03 172.16.1.1/24 \
++    -- set Logical_Router_Port rp-public options:redirect-chassis=hv1
++
++ovn-nbctl lsp-add sw0 sw0-rp -- set Logical_Switch_Port sw0-rp \
++    type=router options:router-port=rp-sw0 \
++    -- lsp-set-addresses sw0-rp router
++ovn-nbctl lsp-add sw1 sw1-rp -- set Logical_Switch_Port sw1-rp \
++    type=router options:router-port=rp-sw1 \
++    -- lsp-set-addresses sw1-rp router
++
++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
++
++ADD_NAMESPACES(sw01)
++ADD_VETH(sw01, sw01, br-int, "192.168.1.2/24", "f0:00:00:01:02:03", \
++         "192.168.1.1")
++ovn-nbctl lsp-add sw0 sw01 \
++    -- lsp-set-addresses sw01 "f0:00:00:01:02:03 192.168.1.2"
++
++ADD_NAMESPACES(sw11)
++ADD_VETH(sw11, sw11, br-int, "192.168.2.2/24", "f0:00:00:02:02:03", \
++         "192.168.2.1")
++ovn-nbctl lsp-add sw1 sw11 \
++    -- lsp-set-addresses sw11 "f0:00:00:02:02:03 192.168.2.2"
++
++ADD_NAMESPACES(server)
++ADD_VETH(s1, server, br-ext, "2001:1db8:3333::2/64", "f0:00:00:01:02:05", \
++         "2001:1db8:3333::1")
++
++OVS_WAIT_UNTIL([test "$(ip netns exec server ip a | grep 2001:1db8:3333::2 | grep tentative)" = ""])
++OVS_WAIT_UNTIL([test "$(ip netns exec server ip a | grep fe80 | grep tentative)" = ""])
++
++AT_CHECK([ovs-vsctl set Open_vSwitch . external-ids:ovn-bridge-mappings=phynet:br-ext])
++ovn-nbctl lsp-add public public1 \
++        -- lsp-set-addresses public1 unknown \
++        -- lsp-set-type public1 localnet \
++        -- lsp-set-options public1 network_name=phynet
++
++ovn-nbctl set logical_router_port rp-public options:prefix_delegation=true
++ovn-nbctl set logical_router_port rp-public options:prefix=true
++ovn-nbctl set logical_router_port rp-sw0 options:prefix=true
++ovn-nbctl set logical_router_port rp-sw1 options:prefix=true
++
++# reset dibbler state
++sed s/^iface.*/"iface \"s1\" {"/g -i /etc/dibbler/server.conf
++sed s/pd-pool.*/"pd-pool 2001:1db8:3333::\/80"/g -i /etc/dibbler/server.conf
++sed s/t1.*/"t1 10"/g -i /etc/dibbler/server.conf
++sed s/t2.*/"t2 15"/g -i /etc/dibbler/server.conf
++cat > /var/lib/dibbler/server-AddrMgr.xml <<EOF
++<AddrMgr>
++  <timestamp>1575481348</timestamp>
++  <replayDetection>0</replayDetection>
++</AddrMgr>
++EOF
++cat > /var/lib/dibbler/server-CfgMgr.xml <<EOF
++<SrvCfgMgr>
++  <workDir>/var/lib/dibbler</workDir>
++  <LogName>Server</LogName>
++  <LogLevel>8</LogLevel>
++  <InactiveMode>0</InactiveMode>
++  <GuessMode>0</GuessMode>
++</SrvCfgMgr>
++EOF
++
++NS_CHECK_EXEC([server], [dibbler-server run > dibbler.log &])
++ovn-nbctl --wait=hv sync
++
++OVS_WAIT_WHILE([test "$(ovn-nbctl get logical_router_port rp-public ipv6_prefix | cut -c4-15)" = ""])
++OVS_WAIT_WHILE([test "$(ovn-nbctl get logical_router_port rp-sw0 ipv6_prefix | cut -c4-15)" = ""])
++OVS_WAIT_WHILE([test "$(ovn-nbctl get logical_router_port rp-sw1 ipv6_prefix | cut -c4-15)" = ""])
++
++AT_CHECK([ovn-nbctl get logical_router_port rp-public ipv6_prefix | cut -c3-16], [0], [dnl
++[2001:1db8:3333]
++])
++AT_CHECK([ovn-nbctl get logical_router_port rp-sw0 ipv6_prefix | cut -c3-16], [0], [dnl
++[2001:1db8:3333]
++])
++AT_CHECK([ovn-nbctl get logical_router_port rp-sw1 ipv6_prefix | cut -c3-16], [0], [dnl
++[2001:1db8:3333]
++])
++
++kill $(pidof dibbler-server)
++
++prefix=$(ovn-nbctl list logical_router_port rp-public | awk -F/ '/ipv6_prefix/{print substr($1,25,9)}' | sed 's/://g')
++ovn-nbctl set logical_router_port rp-sw0 options:prefix=false
++ovn-nbctl set logical_router_port rp-sw1 options:prefix=false
++
++NS_CHECK_EXEC([server], [tcpdump -c 1 -nni s1 ip6[[95:4]]=0x${prefix} > public.pcap &])
++
++OVS_WAIT_UNTIL([
++    total_pkts=$(cat public.pcap | wc -l)
++    test "${total_pkts}" = "1"
++])
++
++kill $(pidof tcpdump)
++kill $(pidof 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
+-- 
+2.25.2
+
diff --git a/SOURCES/0003-ovsdb-idl-Try-committing-the-pending-txn-in-ovsdb_id.patch b/SOURCES/0003-ovsdb-idl-Try-committing-the-pending-txn-in-ovsdb_id.patch
new file mode 100644
index 0000000..64e808e
--- /dev/null
+++ b/SOURCES/0003-ovsdb-idl-Try-committing-the-pending-txn-in-ovsdb_id.patch
@@ -0,0 +1,217 @@
+From 22a9d1b20218d2467f30c9a87205344ff787bcf8 Mon Sep 17 00:00:00 2001
+From: Numan Siddique <numans@ovn.org>
+Date: Fri, 5 Jun 2020 14:00:29 +0530
+Subject: [PATCH 3/3] ovsdb idl: Try committing the pending txn in
+ ovsdb_idl_loop_run.
+
+The function ovsdb_idl_loop_run(), after calling ovsdb_idl_run(),
+returns a transaction object (of type 'struct ovsdb_idl_txn').
+The returned transaction object can be NULL if there is a pending
+transaction (loop->committing_txn) in the idl loop object.
+
+Normally the clients of idl library, first call ovsdb_idl_loop_run(),
+then do their own processing and create any idl transactions during
+this processing and then finally call ovsdb_idl_loop_commit_and_wait().
+
+If ovsdb_idl_loop_run() returns NULL transaction object, then much
+of the processing done by the client gets wasted as in the case
+of ovn-controller.
+
+The client (in this case ovn-controller), can skip the processing
+and instead call ovsdb_idl_loop_commit_and_wait() if the transaction
+oject is NULL. But ovn-controller uses IDL tracking and it may
+loose the tracked changes in that run.
+
+This patch tries to improve this scenario, by checking if the
+pending transaction can be committed in the ovsdb_idl_loop_run()
+itself and if the pending transaction is cleared (because of the
+response messages from ovsdb-server due to a transaction message
+in the previous run), ovsdb_idl_loop_run() can return a valid
+transaction object.
+
+CC: Han Zhou <hzhou@ovn.org>
+Signed-off-by: Numan Siddique <numans@ovn.org>
+Signed-off-by: Ben Pfaff <blp@ovn.org>
+---
+ openvswitch-2.13.0/lib/ovsdb-idl.c | 143 +++++++++++++++++++----------
+ 1 file changed, 93 insertions(+), 50 deletions(-)
+
+diff --git a/openvswitch-2.13.0/lib/ovsdb-idl.c b/openvswitch-2.13.0/lib/ovsdb-idl.c
+index 1535ad7b5..2d351791f 100644
+--- a/openvswitch-2.13.0/lib/ovsdb-idl.c
++++ b/openvswitch-2.13.0/lib/ovsdb-idl.c
+@@ -385,6 +385,8 @@ static void ovsdb_idl_send_cond_change(struct ovsdb_idl *idl);
+ static void ovsdb_idl_destroy_indexes(struct ovsdb_idl_table *);
+ static void ovsdb_idl_add_to_indexes(const struct ovsdb_idl_row *);
+ static void ovsdb_idl_remove_from_indexes(const struct ovsdb_idl_row *);
++static int ovsdb_idl_try_commit_loop_txn(struct ovsdb_idl_loop *loop,
++                                         bool *may_need_wakeup);
+ 
+ static void
+ ovsdb_idl_db_init(struct ovsdb_idl_db *db, const struct ovsdb_idl_class *class,
+@@ -5329,6 +5331,12 @@ struct ovsdb_idl_txn *
+ ovsdb_idl_loop_run(struct ovsdb_idl_loop *loop)
+ {
+     ovsdb_idl_run(loop->idl);
++
++    /* See if we can commit the loop->committing_txn. */
++    if (loop->committing_txn) {
++        ovsdb_idl_try_commit_loop_txn(loop, NULL);
++    }
++
+     loop->open_txn = (loop->committing_txn
+                       || ovsdb_idl_get_seqno(loop->idl) == loop->skip_seqno
+                       ? NULL
+@@ -5336,6 +5344,87 @@ ovsdb_idl_loop_run(struct ovsdb_idl_loop *loop)
+     return loop->open_txn;
+ }
+ 
++/* Attempts to commit the current transaction, if one is open.
++ *
++ * If a transaction was open, in this or a previous iteration of the main loop,
++ * and had not before finished committing (successfully or unsuccessfully), the
++ * return value is one of:
++ *
++ *  1: The transaction committed successfully (or it did not change anything in
++ *     the database).
++ *  0: The transaction failed.
++ * -1: The commit is still in progress.
++ *
++ * Thus, the return value is -1 if the transaction is in progress and otherwise
++ * true for success, false for failure.
++ *
++ * (In the corner case where the IDL sends a transaction to the database and
++ * the database commits it, and the connection between the IDL and the database
++ * drops before the IDL receives the message confirming the commit, this
++ * function can return 0 even though the transaction succeeded.)
++ */
++static int
++ovsdb_idl_try_commit_loop_txn(struct ovsdb_idl_loop *loop,
++                              bool *may_need_wakeup)
++{
++    if (!loop->committing_txn) {
++        /* Not a meaningful return value: no transaction was in progress. */
++        return 1;
++    }
++
++    int retval;
++    struct ovsdb_idl_txn *txn = loop->committing_txn;
++
++    enum ovsdb_idl_txn_status status = ovsdb_idl_txn_commit(txn);
++    if (status != TXN_INCOMPLETE) {
++        switch (status) {
++        case TXN_TRY_AGAIN:
++            /* We want to re-evaluate the database when it's changed from
++             * the contents that it had when we started the commit.  (That
++             * might have already happened.) */
++            loop->skip_seqno = loop->precommit_seqno;
++            if (ovsdb_idl_get_seqno(loop->idl) != loop->skip_seqno
++                && may_need_wakeup) {
++                *may_need_wakeup = true;
++            }
++            retval = 0;
++            break;
++
++        case TXN_SUCCESS:
++            /* Possibly some work on the database was deferred because no
++             * further transaction could proceed.  Wake up again. */
++            retval = 1;
++            loop->cur_cfg = loop->next_cfg;
++            if (may_need_wakeup) {
++                *may_need_wakeup =  true;
++            }
++            break;
++
++        case TXN_UNCHANGED:
++            retval = 1;
++            loop->cur_cfg = loop->next_cfg;
++            break;
++
++        case TXN_ABORTED:
++        case TXN_NOT_LOCKED:
++        case TXN_ERROR:
++            retval = 0;
++            break;
++
++        case TXN_UNCOMMITTED:
++        case TXN_INCOMPLETE:
++        default:
++            OVS_NOT_REACHED();
++        }
++        ovsdb_idl_txn_destroy(txn);
++        loop->committing_txn = NULL;
++    } else {
++        retval = -1;
++    }
++
++    return retval;
++}
++
+ /* Attempts to commit the current transaction, if one is open, and sets up the
+  * poll loop to wake up when some more work might be needed.
+  *
+@@ -5366,57 +5455,11 @@ ovsdb_idl_loop_commit_and_wait(struct ovsdb_idl_loop *loop)
+         loop->precommit_seqno = ovsdb_idl_get_seqno(loop->idl);
+     }
+ 
+-    struct ovsdb_idl_txn *txn = loop->committing_txn;
+-    int retval;
+-    if (txn) {
+-        enum ovsdb_idl_txn_status status = ovsdb_idl_txn_commit(txn);
+-        if (status != TXN_INCOMPLETE) {
+-            switch (status) {
+-            case TXN_TRY_AGAIN:
+-                /* We want to re-evaluate the database when it's changed from
+-                 * the contents that it had when we started the commit.  (That
+-                 * might have already happened.) */
+-                loop->skip_seqno = loop->precommit_seqno;
+-                if (ovsdb_idl_get_seqno(loop->idl) != loop->skip_seqno) {
+-                    poll_immediate_wake();
+-                }
+-                retval = 0;
+-                break;
+-
+-            case TXN_SUCCESS:
+-                /* Possibly some work on the database was deferred because no
+-                 * further transaction could proceed.  Wake up again. */
+-                retval = 1;
+-                loop->cur_cfg = loop->next_cfg;
+-                poll_immediate_wake();
+-                break;
+-
+-            case TXN_UNCHANGED:
+-                retval = 1;
+-                loop->cur_cfg = loop->next_cfg;
+-                break;
+-
+-            case TXN_ABORTED:
+-            case TXN_NOT_LOCKED:
+-            case TXN_ERROR:
+-                retval = 0;
+-                break;
+-
+-            case TXN_UNCOMMITTED:
+-            case TXN_INCOMPLETE:
+-            default:
+-                OVS_NOT_REACHED();
+-            }
+-            ovsdb_idl_txn_destroy(txn);
+-            loop->committing_txn = NULL;
+-        } else {
+-            retval = -1;
+-        }
+-    } else {
+-        /* Not a meaningful return value: no transaction was in progress. */
+-        retval = 1;
++    bool may_need_wakeup = false;
++    int retval = ovsdb_idl_try_commit_loop_txn(loop, &may_need_wakeup);
++    if (may_need_wakeup) {
++        poll_immediate_wake();
+     }
+-
+     ovsdb_idl_wait(loop->idl);
+ 
+     return retval;
+-- 
+2.26.2
+
diff --git a/SOURCES/0004-northd-manage-ARP-request-locally-for-FIP-traffic.patch b/SOURCES/0004-northd-manage-ARP-request-locally-for-FIP-traffic.patch
new file mode 100644
index 0000000..de2a192
--- /dev/null
+++ b/SOURCES/0004-northd-manage-ARP-request-locally-for-FIP-traffic.patch
@@ -0,0 +1,187 @@
+From 92f6a2f668708c677a8b10b0ac861bfd712f6a20 Mon Sep 17 00:00:00 2001
+Message-Id: <92f6a2f668708c677a8b10b0ac861bfd712f6a20.1590585469.git.lorenzo.bianconi@redhat.com>
+In-Reply-To: <d9ed450713eda62af1bec5009694b2d206c9f435.1590585469.git.lorenzo.bianconi@redhat.com>
+References: <d9ed450713eda62af1bec5009694b2d206c9f435.1590585469.git.lorenzo.bianconi@redhat.com>
+From: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
+Date: Mon, 25 May 2020 18:31:27 +0200
+Subject: [PATCH ovn 3/3] northd: manage ARP request locally for FIP traffic
+
+Modify 100-priority logical flows in Gateway Redirect table of
+logical router ingress pipeline (table 15) in order to manage ARP
+request locally for FIP traffic. In particular set reg1 and eth.src
+to NAT external ip and NAT external mac respectively and do not
+distribute ARP traffic using FIP
+
+Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
+---
+ northd/ovn-northd.8.xml | 10 +++++++---
+ northd/ovn-northd.c     | 23 ++++++++++++++++-------
+ tests/ovn.at            | 28 +++++++++++++++++++++++++---
+ tests/system-ovn.at     | 30 ++++++++++++++++++++++++++++++
+ 4 files changed, 78 insertions(+), 13 deletions(-)
+
+--- a/northd/ovn-northd.8.xml
++++ b/northd/ovn-northd.8.xml
+@@ -2879,9 +2879,13 @@ icmp4 {
+         For each NAT rule in the OVN Northbound database that can
+         be handled in a distributed manner, a priority-100 logical
+         flow with match <code>ip4.src == <var>B</var> &amp;&amp;
+-        outport == <var>GW</var></code>, where <var>GW</var> is
+-        the logical router distributed gateway port, with actions
+-        <code>next;</code>.
++        outport == <var>GW</var></code> &amp;&amp;
++        is_chassis_resident(<var>P</var>), where <var>GW</var> is
++        the logical router distributed gateway port and <var>P</var>
++        is the NAT logical port. IP traffic matching the above rule
++        will be managed locally setting <code>reg1</code> to <var>C</var>
++        and <code>eth.src</code> to <var>D</var>, where <var>C</var> is NAT
++        external ip and <var>D</var> is NAT external mac.
+       </li>
+ 
+       <li>
+--- a/northd/ovn-northd.c
++++ b/northd/ovn-northd.c
+@@ -9137,16 +9137,25 @@ build_lrouter_flows(struct hmap *datapat
+             /* Ingress Gateway Redirect Table: For NAT on a distributed
+              * router, add flows that are specific to a NAT rule.  These
+              * flows indicate the presence of an applicable NAT rule that
+-             * can be applied in a distributed manner. */
++             * can be applied in a distributed manner.
++             * In particulr reg1 and eth.src are set to NAT external IP and
++             * NAT external mac so the ARP request generated in the following
++             * stage is sent out with proper IP/MAC src addresses
++             */
+             if (distributed) {
+                 ds_clear(&match);
+-                ds_put_format(&match, "ip%s.src == %s && outport == %s",
+-                              is_v6 ? "6" : "4",
+-                              nat->logical_ip,
+-                              od->l3dgw_port->json_key);
++                ds_clear(&actions);
++                ds_put_format(&match,
++                              "ip%s.src == %s && outport == %s && "
++                              "is_chassis_resident(\"%s\")",
++                              is_v6 ? "6" : "4", nat->logical_ip,
++                              od->l3dgw_port->json_key, nat->logical_port);
++                ds_put_format(&actions, "eth.src = %s; %sreg1 = %s; next;",
++                              nat->external_mac, is_v6 ? "xx" : "",
++                              nat->external_ip);
+                 ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_GW_REDIRECT,
+-                                        100, ds_cstr(&match), "next;",
+-                                        &nat->header_);
++                                        100, ds_cstr(&match),
++                                        ds_cstr(&actions), &nat->header_);
+             }
+ 
+             /* Egress Loopback table: For NAT on a distributed router.
+--- a/tests/ovn.at
++++ b/tests/ovn.at
+@@ -14353,9 +14353,14 @@ ovs-vsctl -- add-port br-int hv2-vif1 --
+     set interface hv2-vif1 external-ids:iface-id=sw1-p0 \
+     options:tx_pcap=hv2/vif1-tx.pcap \
+     options:rxq_pcap=hv2/vif1-rx.pcap \
+-    ofport-request=1
++    ofport-request=2
++ovs-vsctl -- add-port br-int hv2-vif2 -- \
++    set interface hv2-vif2 external-ids:iface-id=sw0-p1 \
++    options:tx_pcap=hv2/vif2-tx.pcap \
++    options:rxq_pcap=hv2/vif2-rx.pcap \
++    ofport-request=3
+ 
+-ovn-nbctl create Logical_Router name=lr0 options:chassis=hv1
++ovn-nbctl create Logical_Router name=lr0
+ ovn-nbctl ls-add sw0
+ ovn-nbctl ls-add sw1
+ 
+@@ -14364,13 +14369,16 @@ ovn-nbctl lsp-add sw0 rp-sw0 -- set Logi
+     type=router options:router-port=sw0 \
+     -- lsp-set-addresses rp-sw0 router
+ 
+-ovn-nbctl lrp-add lr0 sw1 00:00:02:01:02:03 172.16.1.1/24 2002:0:0:0:0:0:0:1/64
++ovn-nbctl lrp-add lr0 sw1 00:00:02:01:02:03 172.16.1.1/24 2002:0:0:0:0:0:0:1/64 \
++    -- set Logical_Router_Port sw1 options:redirect-chassis="hv2"
+ ovn-nbctl lsp-add sw1 rp-sw1 -- set Logical_Switch_Port rp-sw1 \
+     type=router options:router-port=sw1 \
+     -- lsp-set-addresses rp-sw1 router
+ 
+ ovn-nbctl lsp-add sw0 sw0-p0 \
+     -- lsp-set-addresses sw0-p0 "f0:00:00:01:02:03 192.168.1.2 2001::2"
++ovn-nbctl lsp-add sw0 sw0-p1 \
++    -- lsp-set-addresses sw0-p1 "f0:00:00:11:02:03 192.168.1.3 2001::3"
+ 
+ ovn-nbctl lsp-add sw1 sw1-p0 \
+     -- lsp-set-addresses sw1-p0 unknown
+@@ -14416,6 +14424,20 @@ send_na 2 1 $dst_mac $router_mac1 $dst_i
+ 
+ OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected])
+ 
++# Create FIP on sw0-p0, add a route on logical router pipeline and
++# ARP request for a unkwon destination is sent using FIP MAC/IP
++ovn-nbctl lr-nat-add lr0 dnat_and_snat 172.16.1.2 192.168.1.3 sw0-p1 f0:00:00:01:02:04
++ovn-nbctl lr-route-add lr0 172.16.2.0/24 172.16.1.11
++
++dst_ip=$(ip_to_hex 172 16 2 10)
++fip_ip=$(ip_to_hex 172 16 1 2)
++src_ip=$(ip_to_hex 192 168 1 3)
++gw_router=$(ip_to_hex 172 16 1 11)
++send_icmp_packet 2 2 f00000110203 $router_mac0 $src_ip $dst_ip 0000 $data
++echo $(get_arp_req f00000010204 $fip_ip $gw_router) >> expected
++
++OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected])
++
+ OVN_CLEANUP([hv1],[hv2])
+ AT_CLEANUP
+ 
+--- a/tests/system-ovn.at
++++ b/tests/system-ovn.at
+@@ -2747,6 +2747,19 @@ ADD_VETH(alice1, alice1, br-int, "172.16
+ ovn-nbctl lsp-add alice alice1 \
+ -- lsp-set-addresses alice1 "f0:00:00:01:02:05 172.16.1.2"
+ 
++# Add external network
++ADD_NAMESPACES(ext-net)
++AT_CHECK([ip link add alice-ext netns alice1 type veth peer name ext-veth netns ext-net])
++NS_CHECK_EXEC([ext-net], [ip link set dev ext-veth up], [0], [])
++NS_CHECK_EXEC([ext-net], [ip addr add 10.0.0.1/24 dev ext-veth], [0], [])
++NS_CHECK_EXEC([ext-net], [ip route add default via 10.0.0.2], [0], [])
++
++NS_CHECK_EXEC([alice1], [ip link set dev alice-ext up], [0], [])
++NS_CHECK_EXEC([alice1], [ip addr add 10.0.0.2/24 dev alice-ext], [0], [])
++NS_CHECK_EXEC([alice1], [sysctl -w net.ipv4.conf.all.forwarding=1],[0], [dnl
++net.ipv4.conf.all.forwarding = 1
++])
++
+ # Add DNAT rules
+ AT_CHECK([ovn-nbctl lr-nat-add R1 dnat_and_snat 172.16.1.3 192.168.1.2 foo1 00:00:02:02:03:04])
+ 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])
+@@ -2754,6 +2767,9 @@ AT_CHECK([ovn-nbctl lr-nat-add R1 dnat_a
+ # Add a SNAT rule
+ AT_CHECK([ovn-nbctl lr-nat-add R1 snat 172.16.1.1 192.168.0.0/16])
+ 
++# Add default route to ext-net
++AT_CHECK([ovn-nbctl lr-route-add R1 10.0.0.0/24 172.16.1.2])
++
+ ovn-nbctl --wait=hv sync
+ OVS_WAIT_UNTIL([ovs-ofctl dump-flows br-int | grep 'nat(src=172.16.1.1)'])
+ 
+@@ -2797,6 +2813,20 @@ sed -e 's/zone=[[0-9]]*/zone=<cleared>/'
+ icmp,orig=(src=192.168.2.2,dst=172.16.1.2,id=<cleared>,type=8,code=0),reply=(src=172.16.1.2,dst=172.16.1.1,id=<cleared>,type=0,code=0),zone=<cleared>
+ ])
+ 
++# Try to ping external network
++NS_CHECK_EXEC([ext-net], [tcpdump -n -c 3 -i ext-veth dst 172.16.1.3 and icmp > ext-net.pcap &])
++sleep 1
++AT_CHECK([ovn-nbctl lr-nat-del R1 snat])
++NS_CHECK_EXEC([foo1], [ping -q -c 3 -i 0.3 -w 2 10.0.0.1 | FORMAT_PING], \
++[0], [dnl
++3 packets transmitted, 3 received, 0% packet loss, time 0ms
++])
++
++OVS_WAIT_UNTIL([
++    total_pkts=$(cat ext-net.pcap | wc -l)
++    test "${total_pkts}" = "3"
++])
++
+ OVS_APP_EXIT_AND_WAIT([ovn-controller])
+ 
+ as ovn-sb
diff --git a/SOURCES/0004-tests-Fix-occasional-failures-for-test-85.patch b/SOURCES/0004-tests-Fix-occasional-failures-for-test-85.patch
new file mode 100644
index 0000000..eaaf3c0
--- /dev/null
+++ b/SOURCES/0004-tests-Fix-occasional-failures-for-test-85.patch
@@ -0,0 +1,69 @@
+From 9735eeff2b736145fe7ab444eb77686a595a9c8e Mon Sep 17 00:00:00 2001
+From: Numan Siddique <numans@ovn.org>
+Date: Fri, 17 Apr 2020 20:09:24 +0530
+Subject: [PATCH 4/4] tests: Fix occasional failures for test 85.
+
+The test case "85: ovn -- send gratuitous ARP for NAT rules on HA distributed router"
+fails occaionally. On faster systems, chances of failure are higher.
+
+This patch fixes this.
+
+Tested-by: Flavio Fernandes <flavio@flaviof.com>
+Signed-off-by: Numan Siddique <numans@ovn.org>
+---
+ tests/ovn.at | 21 +++++++++++++++++++--
+ 1 file changed, 19 insertions(+), 2 deletions(-)
+
+diff --git a/tests/ovn.at b/tests/ovn.at
+index ae3b44cb3..91d0a8fec 100644
+--- a/tests/ovn.at
++++ b/tests/ovn.at
+@@ -11062,6 +11062,12 @@ only_broadcast_from_lrp1() {
+ garp="fffffffffffff0000000000108060001080006040001f00000000001c0a80064000000000000c0a80064"
+ echo $garp > expout
+ 
++OVS_WAIT_UNTIL(
++    [$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/snoopvif-tx.pcap > rcv_text
++     exp_rcvd=$(cat rcv_text | grep $garp | wc -l)
++     echo "expected received = $exp_rcvd"
++     test $exp_rcvd -ge 1])
++
+ $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/snoopvif-tx.pcap | trim_zeros | only_broadcast_from_lrp1 | uniq > hv1_snoop_tx
+ echo "packets on hv1-snoopvif:"
+ cat hv1_snoop_tx
+@@ -11090,12 +11096,17 @@ as hv1 reset_pcap_file snoopvif hv1/snoopvif
+ as hv2 reset_pcap_file br-phys_n1 hv2/br-phys_n1
+ as hv3 reset_pcap_file br-phys_n1 hv3/br-phys_n1
+ 
+-# Wait for packets to be received.
+-OVS_WAIT_UNTIL([test `wc -c < "hv1/snoopvif-tx.pcap"` -ge 100])
+ trim_zeros() {
+     sed 's/\(00\)\{1,\}$//'
+ }
+ 
++# Wait for packets to be received.
++OVS_WAIT_UNTIL(
++    [$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/snoopvif-tx.pcap > rcv_text
++     exp_rcvd=$(cat rcv_text | grep $garp | wc -l)
++     echo "expected received = $exp_rcvd"
++     test $exp_rcvd -ge 1])
++
+ $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/snoopvif-tx.pcap | trim_zeros | only_broadcast_from_lrp1 | uniq >  hv1_snoopvif_tx
+ AT_CHECK([sort hv1_snoopvif_tx], [0], [expout])
+ $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv3/br-phys_n1-tx.pcap | trim_zeros | only_broadcast_from_lrp1 | uniq > hv3_br_phys_tx
+@@ -11141,6 +11152,12 @@ trim_zeros() {
+ garp="fffffffffffff00000000001810007de08060001080006040001f00000000001c0a80064000000000000c0a80064"
+ echo $garp > expout
+ 
++OVS_WAIT_UNTIL(
++    [$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/snoopvif-tx.pcap > rcv_text
++     exp_rcvd=$(cat rcv_text | grep $garp | wc -l)
++     echo "expected received = $exp_rcvd"
++     test $exp_rcvd -ge 1])
++
+ $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/snoopvif-tx.pcap | trim_zeros | only_broadcast_from_lrp1 | uniq >  hv1_snoopvif_tx
+ AT_CHECK([sort hv1_snoopvif_tx], [0], [expout])
+ $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv3/br-phys_n1-tx.pcap | trim_zeros | only_broadcast_from_lrp1 | uniq > hv3_br_phys_tx
+-- 
+2.26.2
+
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..651a0c5
--- /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
+
+echo -n "For each arch ( "
+for ((i=0; i < ${#OVS_DPDK_CONF_MACH_ARCH[@]}; i++));
+do
+    echo -n "${OVS_DPDK_CONF_MACH_ARCH[i]} "
+done
+echo "):"
+echo "1. ensure you enable the requisite hw"
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/ovn2.13.spec b/SPECS/ovn2.13.spec
new file mode 100644
index 0000000..bc9e75b
--- /dev/null
+++ b/SPECS/ovn2.13.spec
@@ -0,0 +1,1011 @@
+# Spec file for Open Virtual Network (OVN).
+
+# Copyright (C) 2020 Red Hat, 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/ovn-fedora.spec
+#
+
+# This defines the base package name's version.
+%define pkgver 2.13
+%define pkgname ovn%{pkgver}
+
+#%%global commit0 7886ac9ed807d6ff942edde624a3f9331da7332a
+#%%global date 20200217
+#%%global shortcommit0 %(c=%{commit0}; echo ${c:0:7})
+
+# openvswitch commit
+#%%global commit1 8ae6a5f98c3ad57d10220596054f6a0c4d6ea358
+#%%global shortcommit1 %(c=%{commit1}; echo ${c:0:7})
+
+# 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
+
+# some distros (e.g: RHEL-7) don't define _rundir macro yet
+# Fedora 15 onwards uses /run as _rundir
+%if 0%{!?_rundir:1}
+%define _rundir /run
+%endif
+
+%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.openvswitch.org/
+Version: %{pkgver}.0
+Release: 39%{?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
+
+%if 0%{?commit0:1}
+Source: https://github.com/ovn-org/ovn/archive/%{commit0}.tar.gz#/ovn-%{shortcommit0}.tar.gz
+%else
+# Upstream version is called 20.03, not 2.13. Once we switch to using the
+# same versioning scheme for RH, we can reference %{version} here.
+# XXX Are OVN releases listed on openvswitch.org?
+Source: https://www.openvswitch.org/releases/ovn-%{version}.tar.gz
+%endif
+
+
+%define ovsver %{version}
+
+%if 0%{?commit1:1}
+Source10: https://github.com/openvswitch/ovs/archive/%{commit1}.tar.gz#/openvswitch-%{shortcommit1}.tar.gz
+%define ovsdir ovs-%{commit1}
+%else
+Source10: https://openvswitch.org/releases/openvswitch-%{ovsver}.tar.gz
+%define ovsdir openvswitch-%{ovsver}
+%endif
+
+%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
+
+# ovn-patches
+
+# OVN (including OVS if required) backports (0 - 399)
+# Bug 1812038
+Patch0: 0001-system-tests-Fix-occasional-failure-of-the-test-Load.patch
+Patch1: 0002-Broadcast-DHCPREPLY-when-BROADCAST-flag-is-set.patch
+Patch2: 0003-logical-fields-fix-memory-leak-caused-by-initialize-.patch
+
+# Bug 1813046
+Patch10: 0001-ovn-northd-Add-lflows-to-by-pass-the-svc-monitor-pac.patch
+
+# Bug 1816087
+Patch20: 0001-ovn-northd-Don-t-add-arp-responder-flows-for-lports-.patch
+
+# Bug 1816616
+Patch30: 0001-ovn-northd-Forward-ARP-requests-on-localnet-ports.patch
+Patch31: 0001-ovn.at-Fix-ARP-test-that-fails-due-to-timing.patch
+
+# Bug 1815217
+Patch040: 0001-northd-do-not-insert-identical-lflows-in-S_ROUTER_IN.patch
+Patch041: 0002-ovn-northd-Skip-unsnat-flows-for-load-balancer-vips-.patch
+
+# Bug 1819604
+Patch050: 0001-ovn-controller-Fix-potential-segfault-with-virtual-p.patch
+Patch051: 0001-ovn-controller-Skip-vport-bindings-done-through-OVS-.patch
+
+# Bug 1718372
+Patch060: 0001-Add-external_ids-column-for-tables-in-nb-schema.patch
+Patch061: 0001-Add-SCTP-support-to-load-balancers.patch
+
+# Bug 1815009
+Patch070: 0001-controller-use-LLA-IPv6-address-as-NS-source-address.patch
+
+# Bug 1822859
+Patch080: 0001-ovn-ctl-Provide-the-option-to-configure-inactive-pro.patch
+
+# Bug 1823226
+Patch090: 0001-tests-Wait-up-to-OVS_CTL_TIMEOUT-seconds.patch
+Patch091: 0002-controller-Add-ipv6-prefix-delegation-state-machine.patch
+Patch092: 0003-northd-Add-logical-flows-for-dhcpv6-pfd-parsing.patch
+
+# Bug 1778016
+Patch100: 0001-ovn-nbctl-Create-daemon-control-socket-in-ovn-run-di.patch
+
+# Bug 1801058
+Patch110: 0001-pinctrl-Handle-service-monitors-even-if-the-lport-do.patch
+
+# Bug 1825334
+Patch120: 0001-ovn-northd-Limit-IPv6-ND-NS-RA-RS-to-the-local-netwo.patch
+
+# Bug 1819069
+# Bug 1778016
+Patch130: 0001-DNS-Make-DNS-lookups-case-insensitive.patch
+Patch131: 0002-Create-daemon-pidfiles-in-ovn-run-dir.patch
+
+# Bug 1819785
+Patch140: 0001-Fix-conntrack-entry-leaks-because-of-TCP-RST-packets.patch
+
+# Bug 1827403
+Patch150: 0001-ovn-northd-Optimize-flows-for-LB-Hairpin-traffic.patch
+
+# Bug 1817606
+Patch160: 0001-Rely-on-unique-name-for-ovn-qos-meters.patch
+
+# Bug 1826623
+Patch170: 0001-IPv6-PD-assume-status-to-be-Success-if-not-present.patch
+
+# Bug 1827090
+Patch180: 0001-IPv6-PD-time-parameter-checks.patch
+
+# Bug 1828637
+Patch190: 0001-ovn-northd-Clear-SB-records-depending-on-stale-datap.patch
+Patch191: 0002-ovn-northd-Fix-tunnel_key-allocation-for-SB-Port_Bin.patch
+
+# Bug 1826683 and 1827084
+Patch200: 0001-Disable-IPv6-prefix-reporting-if-IPv6-PD-is-disabled.patch
+Patch201: 0002-controller-Add-garbage-collector-for-ipv6_prefixd.patch
+Patch202: 0003-IPv6-PD-Disable-pd-processing-if-the-router-port-is-.patch
+
+# Bug 1823755
+Patch210: 0001-Fix-ACL-reject-action-for-UDP-packets.patch
+
+# Bug 1707513
+# Bug 1825073
+Patch220: 0001-controller-Use-OpenFlow-version-1.5.patch
+Patch221: 0002-ovn-northd-Fix-memory-leak-and-incorrect-limiting-of.patch
+Patch222: 0003-Support-selection-fields-in-load-balancer.patch
+Patch223: 0004-tests-Fix-occasional-failures-for-test-85.patch
+
+# Bug 1834655
+Patch230: 0001-pinctrl-Fix-icmp6-packet-corruption-issue.patch
+
+# Bug 1827769
+Patch240: 0001-ovn-northd-Fix-leak-of-lport-addresses-during-DHCPv6.patch
+Patch241: 0002-ovn-northd-Fix-memory-leak-in-case-of-duplicate-logi.patch
+
+# Bug 1779854
+Patch250: 0001-ofctrl-Split-large-group_mod-messages-up.patch
+
+# Bug 1836976
+Patch260: 0001-ovn-northd-Remove-useless-flow-for-GW_REDIRECT.patch
+Patch261: 0002-Revert-Manage-ARP-process-locally-in-a-DVR-scenario.patch
+Patch262: 0003-controller-fix-ip-buffering-with-static-routes.patch
+Patch263: 0004-northd-manage-ARP-request-locally-for-FIP-traffic.patch
+
+# Bug 1843512
+Patch270: 0001-Make-the-notify-calls-work-with-IPv6-in-the-OCF-reso.patch
+
+# Bug 1832176
+# Bug 1804576
+Patch280: 0001-Fix-ovn-controller-generated-packets-from-getting-dr.patch
+Patch281: 0002-Honour-router_preference-for-solicited-RA.patch
+
+# Bug 1848398
+Patch290: 0001-northd-By-pass-IPv6-Router-Adv-and-Router-Solicitati.patch
+
+# Bug 1818128
+Patch300: 0001-Split-SB-Port_Group-per-datapath.patch
+
+# Bug 1849162
+Patch310: 0001-ovn-northd-Fix-the-missing-lflow-issue-in-LS_OUT_PRE.patch
+
+# OpenvSwitch backports (800-) if required.
+Patch800: 0001-Revert-ovsdb-idl-Avoid-sending-redundant-conditional.patch
+
+Patch810: 0003-ovsdb-idl-Try-committing-the-pending-txn-in-ovsdb_id.patch
+
+# Bug 1808580
+Patch820: 0001-ovsdb-idl-Avoid-inconsistent-IDL-state-with-OVSDB_MO.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} > 7 || 0%{?fedora}
+BuildRequires: python3-pyOpenSSL
+%endif
+
+%if %{with libcapng}
+BuildRequires: libcap-ng libcap-ng-devel
+%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
+# Disable Tests due to https://bugs.centos.org/view.php?id=16969, tests failing
+# as build is running on CentOS7 builder, once builders are CentOS8 based tests can
+# be re enabled.
+%bcond_with 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
+%if 0%{?commit0:1}
+%autosetup -n ovn-%{commit0} -a 10 -p 1
+%else
+%autosetup -n ovn-%{version} -a 10 -p 1
+%endif
+
+%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} -k ovn'; 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-appctl
+%{_bindir}/ovn-ic-nbctl
+%{_bindir}/ovn-ic-sbctl
+%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}/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
+* Wed Jul 08 2020 Numan Siddique <dceara@redhat.com> - 2.13.0-39
+- Backport "ovn-northd: Fix the missing lflow issue in LS_OUT_PRE_LB." (#1849162)
+
+* Wed Jul 08 2020 Numan Siddique <dceara@redhat.com> - 2.13.0-38
+- Backport "Split SB Port_Group per datapath." (#1818128)
+
+* Fri Jun 19 2020 Dumitru Ceara <dceara@redhat.com> - 2.13.0-37
+- Backport "ovsdb-idl: Avoid inconsistent IDL state with OVSDB_MONITOR_V3." (#1808580)
+
+* Thu Jun 18 2020 Numan Siddique <nusiddiq@redhat.com> - 2.13.0-36
+- Backport "northd: By pass IPv6 Router Adv and Router Solicitation packets from ACL stages." (#1848398)
+
+* Thu Jun 18 2020 Numan Siddique <nusiddiq@redhat.com> - 2.13.0-35
+- Backport "Fix ovn-controller generated packets from getting dropped for reject ACL action." (#1832176)
+- Backport "Honour router_preference for solicited RA" (#1804576)
+- Backport "ovsdb idl: Try committing the pending txn in ovsdb_idl_loop_run."
+
+* Mon Jun 08 2020 Numan Siddique <nusiddiq@redhat.com> - 2.13.0-34
+- Backport "Make the notify() calls work with IPv6 in the OCF resource-agent" (#1843512)
+
+* Fri Jun 5 2020 Lorenzo Bianconi <lorenzo.bianconi@redhat.com> - 2.13.0-33
+- Backport "ovn-northd: Remove useless flow for GW_REDIRECT" (#1836976)
+- Backport "Revert "Manage ARP process locally in a DVR scenario" (#1836976)
+- Backport "controller: fix ip buffering with static routes" (#1836976)
+- Backport "northd: manage ARP request locally for FIP traffic" (#1836976)
+
+* Tue Jun 02 2020 Mark Michelson <mmichels@redhat.com> - 2.13.0-32
+- No change. Just bumping revision to appease errata system.
+
+* Fri May 15 2020 Mark Michelson <mmichels@redhat.com> - 2.13.0-31
+- Backport "ofctrl: Split large group_mod messages up." (#1779854)
+
+* Tue May 12 2020 Numan Siddique <nusiddiq@redhat.com> - 2.13.0-30
+- Backport "ovn-northd: Fix leak of lport addresses during DHCPv6 reply handling." (#1827769)
+- Backport "ovn-northd: Fix memory leak in case of duplicate logical router port." (#1827769)
+
+* Tue May 12 2020 Numan Siddique <nusiddiq@redhat.com> - 2.13.0-29
+- Backport "pinctrl: Fix icmp6 packet corruption issue" (#1834655)
+
+* Sun May 10 2020 Numan Siddique <nusiddiq@redhat.com> - 2.13.0-28
+- Backport "controller: Use OpenFlow version 1.5" (#1825073, #1707513)
+- Backport "ovn-northd: Fix memory leak and incorrect limiting of ECMP routes."
+- Backport "Support selection fields in load balancer." (#1825073, #1707513)
+- Backport "tests: Fix occasional failures for test 85."
+
+* Wed May 06 2020 Numan Siddique <nusiddiq@redhat.com> - 2.13.0-27
+- Backport "Fix ACL reject action for UDP packets." (#1823755)
+
+* Mon May 04 2020 Lorenzo Bianconi <lorenzo.bianconi@redhat.com> - 2.13.0-26
+- Backport "0001-Disable-IPv6-prefix-reporting-if-IPv6-PD-is-disabled.patch" (#1826683)
+- Backport "0002-controller-Add-garbage-collector-for-ipv6_prefixd.patch" (#1827084)
+- Backport "0003-IPv6-PD-Disable-pd-processing-if-the-router-port-is-.patch" (#1827084)
+
+* Mon May 04 2020 Dumitru Ceara <dceara@redhat.com> - 2.13.0-25
+- Backport "ovn-northd: Clear SB records depending on stale datapaths." (#1828637)
+- Backport "ovn-northd: Fix tunnel_key allocation for SB Port_Bindings." (#1828637)
+
+* Mon May 04 2020 Lorenzo Bianconi <lorenzo.bianconi@redhat.com> - 2.13.0-24
+- Backport "IPv6 PD: time parameter checks" (#1827090)
+
+* Mon May 04 2020 Lorenzo Bianconi <lorenzo.bianconi@redhat.com> - 2.13.0-23
+- Backport "IPv6 PD: assume status to be Success if not present" (#1826623)
+
+* Wed Apr 29 2020 Lorenzo Bianconi <lorenzo.bianconi@redhat.com> - 2.13.0-22
+- Backport "Rely on unique name for ovn qos meters" (#1817606)
+
+* Tue Apr 28 2020 Dumitru Ceara <dceara@redhat.com> - 2.13.0-21
+- Backport "ovn-northd: Optimize flows for LB Hairpin traffic." (#1827403)
+
+* Mon Apr 27 2020 Numan Siddique <nusiddiq@redhat.com> - 2.13.0-20
+- Backport "Fix conntrack entry leaks because of TCP RST packets not sent to conntrack." (#1819785)
+
+* Mon Apr 27 2020 Numan Siddique <nusiddiq@redhat.com> - 2.13.0-19
+- Backport "DNS: Make DNS lookups case insensitive." (#1819069)
+- Backport "Create daemon pidfiles in ovn run dir." (#1778016)
+
+* Mon Apr 20 2020 Numan Siddique <nusiddiq@redhat.com> - 2.13.0-18
+- Backport "ovn-northd: Limit IPv6 ND NS/RA/RS to the local network." (#1825334)
+
+* Sat Apr 18 2020 Numan Siddique <nusiddiq@redhat.com> - 2.13.0-17
+- Backport "pinctrl: Handle service monitors even if the lport doesn't have IPv4 addresses set." (#1801058)
+
+* Fri Apr 17 2020 Numan Siddique <nusiddiq@redhat.com> - 2.13.0-16
+- Backport "ovn-nbctl: Create daemon control socket in ovn run dir". (#1778016)
+
+* Sun Apr 12 2020 Lorenzo Bianconi <lorenzo.bianconi@redhat.com> - 2.13.0-15
+- Backport "OVN - Support IPv6 Prefix Delegation" (#1823226)
+
+* Fri Apr 10 2020 Numan Siddique <nusiddiq@redhat.com> - 2.13.0-14
+- Backport "ovn-ctl: Provide the option to configure inactive probe from standby to active". (#1822859)
+
+* Thu Apr 09 2020 Dumitru Ceara <dceara@redhat.com> - 2.13.0-13
+- Backport "ovn-controller: Skip vport bindings done through OVS external_ids:iface-id." (#1819604)
+
+* Thu Apr 02 2020 Lorenzo Bianconi <lorenzo.bianconi@redhat.com> - 2.13.0-12
+- Backport "controller: use LLA IPv6 address as NS source address" (#1815009)
+
+* Wed Apr 01 2020 Dumitru Ceara <dceara@redhat.com> - 2.13.0-11
+- Backport "Add SCTP support to Load Balancers" (#1718372)
+- Also backport "Add external_ids column for tables in nb schema" to avoid
+  conflicts.
+
+* Wed Apr 01 2020 Dumitru Ceara <dceara@redhat.com> - 2.13.0-10
+- Backport "ovn-controller: Fix potential segfault with "virtual" port bindings." (#1819604)
+
+* Mon Mar 30 2020 Numan Siddique <nusiddiq@redhat.com> - 2.13.0-9
+- Backport "ovn-northd: Skip unsnat flows for load balancer vips in router ingress pipeline" (#1815217)
+- Backport "northd: do not insert identical lflows in S_ROUTER_IN_ARP_RESOLVE" (required for #1815217)
+
+* Mon Mar 30 2020 Dumitru Ceara <dceara@redhat.com> - 2.13.0-8
+- Backport "Revert "ovsdb-idl: Avoid sending redundant conditional monitoring updates"" (#1818754)
+
+* Tue Mar 24 2020 Dumitru Ceara <dceara@redhat.com> - 2.13.0-7
+- Backport "ovn.at: Fix ARP test that fails due to timing." (#1816616)
+
+* Tue Mar 24 2020 Dumitru Ceara <dceara@redhat.com> - 2.13.0-6
+- Backport "ovn-northd: Forward ARP requests on localnet ports." (#1816616)
+
+* Mon Mar 23 2020 Numan Siddique <nusiddiq@redhat.com> - 2.13.0-5
+- Backport "ovn-northd: Don't add arp responder flows for lports with 'unknown' address." (#1816087)
+
+* Fri Mar 13 2020 Numan Siddique <nusiddiq@redhat.com> - 2.13.0-4
+- Backport "ovn-northd: Add lflows to by pass the svc monitor packets from conntrack". (#1813046)
+
+* Tue Mar 10 2020 Numan Siddique <nusiddiq@redhat.com> - 2.13.0-3
+- Backport "Broadcast DHCPREPLY when BROADCAST flag is set" (#1812038)
+- Also backported 2 other patches to sync with 20.03 (to fix the sparse compilation issue)
+
+* Wed Mar 04 2020 Numan Siddique <nusiddiq@redhat.com> - 2.13.0-2
+- Update to use openvswitch-2.13.0.tar.gz from v2.13.0 tag.
+
+* Tue Mar 03 2020 Mark Michelson <mmichels@redhat.com> - 2.13.0-1
+- Update to upstream release of OVN 20.03.0
+
+* Tue Feb 18 2020 Open vSwitch Bot <null@redhat.com> - 2.13.0-0.20200217git7886ac9
+- Snapshot of branch-20.03 7886ac9ed807
+
+* Mon Feb 10 2020 Mark Michelson <mmichels@redhat.com> - 2.13.0-0
+* Initial repository setup using snapshot build of OVN 20.03 branch
+
+* Tue Feb 4 2020 Numan Siddique <nusiddiq@redhat.com> - 2.12.0-27
+* Backport "ovn-northd: Address scale issues with DNAT flows." (#1798173)
+
+* Thu Jan 30 2020 Numan Siddique <nusiddiq@redhat.com> - 2.12.0-26
+* Backport "[RFE] LB health check : ovn-northd: Consider load balancer active backends in router pipeline" (#1703162)
+
+* Fri Jan 24 2020 Dumitru Ceara <dceara@redhat.com> - 2.12.0-25
+* Backport "tests: Updated expected log message" (#1794671)
+
+* Thu Jan 16 2020 Mark Michelson <mmichels@redhat.com> - 2.12.0-24
+- Backport "nbctl: Log the source of duplicate IP addresses" (#1794671)
+- Backport "northd: Log all dynamic address assignments" (#1794671)
+- Backport "northd: Load config before processing nbdb contents" (#1794671)
+
+* Fri Jan 10 2020 Numan Siddique <nusiddiq@redhat.com> - 2.12.0-23
+- Backport "ovn-controller: Don't monitor connection table columns"
+- Backport "Restrict ARP/IPv6 ND replies for LB VIP only on chassis redirect port" (#1788456)
+
+* Thu Jan 09 2020 Lorenzo Bianconi <lorenzo.bianconi@redhat.com> - 2.12.0-22
+- Backport "pinctrl.c: Fix maybe-uninitialized warnings with old GCC versions" (#1789476)
+- Backport "DNSSL: copy dnssl string in order to avoid truncated value" (#1789476)
+- Backport "RA Route Info Option: copy route info string in order to avoid truncated value" (#1789476)
+
+* Thu Jan 02 2020 Dumitru Ceara <dceara@redhat.com> - 2.12.0-21
+- Backport "ovn-controller: Run I-P engine even when no SB txn is available." (#1787360)
+
+* Thu Jan 02 2020 Dumitru Ceara <dceara@redhat.com> - 2.12.0-20
+- Backport "ovn-controller: Refactor I-P engine_run() tracking." (#1787318)
+- Backport "ovn-controller: Add per node states to I-P engine." (#1787318)
+- Backport "ovn-controller: Add separate I-P engine node for processing ct-zones." (#1787318)
+- Backport "ovn-controller.c: Fix memory leak of local_datapath->ports."
+- Backport "ovn-controller: Fix use of dangling pointers in I-P runtime_data." (#1787318)
+
+* Thu Dec 05 2019 Numan Siddique <nusiddiq@redhat.com> - 2.12.0-19
+- Backport "[RFE] Support for load balancing health checks in OVN" (#1703162)
+- Backport "Stateless NAT support (backported due to conflicts)"
+
+* Tue Dec 03 2019 Lorenzo Bianconi <lorenzo.bianconi@redhat.com> - 2.12.0-18
+- Backport "Add support to Default Router Preference (PRF) - RFC4191" (#1769849)
+- Backport "Add support for Route Info Option in RA - RFC4191"
+
+* Tue Dec 3 2019 Dumitru Ceara <dceara@redhat.com> - 2.12.0-17
+- Backport "ovn-controller: Consider non-virtual ports first when updating bindings." (#1779110)
+- Backport "ovn-controller: Add missing port group lflow references." (#1779115)
+- Backport "ovn-controller: Add command to trigger an I-P full recompute." (#1779121)
+
+* Tue Nov 26 2019 Dumitru Ceara <dceara@redhat.com> - 2.12.0-16
+- Backport "ovn-northd: Fix get_router_load_balancer_ips() for mixed address families."
+- Backport "ovn-northd: Limit ARP/ND broadcast domain whenever possible." (#1776712)
+- Backport "ovn-northd: Avoid empty address list when limiting ARP/ND broadcast." (#1776712)
+
+* Wed Nov 20 2019 Numan Siddique <nusiddiq@redhat.com> - 2.12.0-15
+- Backport "Skip IPv6 NS packets in router egress SNAT pipeline" (#1773605)
+- Backport "northd: Match IPv4 or IPv6 for MAC resolution"
+
+* Tue Nov 19 2019 Dumitru Ceara <dceara@redhat.com> - 2.12.0-14
+- Backport "Fix virtual port binding when the parents are scheduled in the same chassis" (#1762341)
+
+* Mon Nov 18 2019 Lorenzo Bianconi <lorenzo.bianconi@redhat.com> - 2.12.0-13
+- Backport "Add DNSSL support to OVN" (#1764718)
+
+* Mon Nov 18 2019 Lorenzo Bianconi <lorenzo.bianconi@redhat.com> - 2.12.0-12
+- Backport "Add RDNSS support to OVN" (#1699332)
+
+* Fri Nov 15 2019 Mark Michelson <mmichels@redhat.com> - 2.12.0-11
+- Update user of logrotate file to be "openvswitch"
+
+* Fri Nov 15 2019 Mark Michelson <mmichels@redhat.com> - 2.12.0-10
+- Update verification of sysconfig and logrotate files
+
+* Wed Nov 13 2019 Numan Siddique <nusiddiq@redhat.com> - 2.12.0-9
+- Backport "Support IPv6 NAT" (#1768347)
+- Backport "Add IPv6 load balancer tests in OVN" (#1768477)
+
+* Mon Nov 11 2019 Dumitru Ceara <dceara@redhat.com> - 2.12.0-8
+- Backport "lflow.c: Fix memory leak of lflow_ref_list_node->ref_name." (#1770953)
+
+* Fri Nov 8 2019  Numan Siddique <nusiddiq@redhat.com> - 2.12.0-7
+- Backport: "ovn-ctl related changes" (#1770127)
+
+* Fri Nov 8 2019  Numan Siddique <nusiddiq@redhat.com> - 2.12.0-6
+- Backport: "Fix ha chassis failover issues for stale ha chassis entries" (#1762777)
+- Backport: "ovn-northd: Validate dnat_and_snat external_mac/logical_ip. (#1769709)
+
+* Fri Nov 8 2019  Numan Siddique <nusiddiq@redhat.com> - 2.12.0-5
+- Backport: "ovndb-servers.ocf: Change from 'openvswitch' to 'ovn' in OVN_CTL_DEFAULT var" (#1770127)
+
+* Sun Nov 3 2019 Mark Michelson <mmichels@redhat.com> - 2.12.0-4
+- Backport "Revert conjunctive match removal patches" (#1764032)
+- Backport "Combine conjunctions with identical matches into one" (#1764032)
+
+* Wed Oct 16 2019  Dumitru Ceara <dceara@redhat.com> - 2.12.0-3
+- Backport: "ovn-northd: Fix IP multicast flooding to mrouter." (#1757714)
+
+* Sun Oct 13 2019  Numan Siddique <nusiddiq@redhat.com> - 2.12.0-2
+- Backport: "ovn-ctl: Create etcdir when starting ovsdb servers" (#1761182)
+
+* Thu Oct 10 2019  Numan Siddique <nusiddiq@redhat.com> - 2.12.0-1
+- Update to OVN master from new repo with the commit 79308138891ae04a02a07068501696ef78157912
+- This will be the base for OVN 2.12.
+
+* Mon Aug 05 2019  Numan Siddique <nusiddiq@redhat.com> - 2.12.0-0.20190804git38a85a0
+- Snapshot build of ovn2.12 38a85a041dd8
+
+* Mon Aug 05 2019  Numan Siddique <nusiddiq@redhat.com> - 2.11.0-27
+- Backport ovn-northd pause/resume support (#1720728)
+
+* Wed Jul 17 2019  Lorenzo Bianconi <lorenzo.bianconi@redhat.com> - 2.11.0-26
+- Backport ovn uindling support (#1730759)
+
+* Wed Jul 17 2019  Numan Siddique <nusiddiq@redhat.com> - 2.11.0-25
+- Backport related to GARP handling for router ips (#1561880)
+
+* Tue Jul 9 2019 Lorenzo Bianconi <lorenzo.bianconi@redhat.com> - 2.11.0-24
+- Backport related to ip buffering with gw router port issue (#1728318)
+
+* Mon Jul 1 2019 Lorenzo Bianconi <lorenzo.bianconi@redhat.com> - 2.11.0-23
+- Backport "OVN: add the possibility to specify tunnel dst port" (#1720371)
+
+* Mon Jun 24 2019 Dumitru Ceara <dceara@redhat.com> - 2.11.0-22
+- Backport "ovn-controller: Fix parsing of OVN tunnel IDs" (#1708131)
+
+* Mon Jun 24 2019 Numan Siddique <nusiddiq@redhat.com> - 2.11.0-21
+- Backport "ovn-nbctl.8.xml: Fix typo." (#1720194)
+
+* Mon Jun 17 2019 Numan Siddique <nusiddiq@redhat.com> - 2.11.0-20
+- Backport "ovn: Add support for DHCP option 15 - domain name" (#1721012)
+
+* Thu Jun 06 2019 Timothy Redaelli <tredaelli@redhat.com> - 2.11.0-19
+- Avoid collisions during installation of sources in debuginfo package (#1717933)
+
+* Mon May 27 2019 Dumitru Ceara <dceara@redhat.com> - 2.11.0-18
+- Backport "ovn: Properly set the index for chassis lookup" (#1698462)
+
+* Tue May 14 2019 Dumitru Ceara <dceara@redhat.com> - 2.11.0-17
+- Backport "stopwatch: Free stopwatch packets after processing" (#1698462)
+
+* Fri Apr 26 2019 Numan Siddique <nusiddiq@redhat.com> - 2.11.0-16
+- Fix the ovn-northd sync issue with HA_Chassis group (#1666673)
+
+* Wed Apr 24 2019 Numan Siddique <nusiddiq@redhat.com> - 2.11.0-15
+- Backport "RFE: Limit Geneve to within Transport Zones" (#1702550)
+
+* Wed Apr 24 2019 Numan Siddique <nusiddiq@redhat.com> - 2.11.0-14
+- Backport "RFE: [OVN] Fragmentation support" (#1702331)
+
+* Sat Apr 20 2019 Numan Siddique <nusiddiq@redhat.com> - 2.11.0-13
+- Backport "RFE: OVN - Support Logical ports of type external" (#1666673)
+
+* Thu Apr 18 2019 Lorenzo Bianconi <lorenzo.bianconi@redhat.com> - 2.11.0-12
+- Backport "OVN: fix DVR Floating IP support" (#1701183)
+
+* Wed Apr 17 2019 Timothy Redaelli <tredaelli@redhat.com> - 2.11.0-11
+- Add 'Obsoletes' to the old OVN openvswitch2.11 sub-packages to allow to upgrade from FDP.A
+
+* Wed Apr 17 2019 Lorenzo Bianconi <lorenzo.bianconi@redhat.com> - 2.11.0-10
+- Backport "OVN: add the possibility to configure a static IPv4/IPv6 address and dynamic MAC"
+
+* Tue Apr 16 2019 Timothy Redaelli <tredaelli@redhat.com> - 2.11.0-9
+- Remove 'Obsoletes' lines like on openvswitch2.11 package
+
+* Tue Apr 16 2019 Numan Siddique <nusiddiq@redhat.com> - 2.11.0-8
+- Fix the 'Provides' to include '%pkgver'
+
+* Tue Mar 26 2019 Numan Siddique <nusiddiq@redhat.com> - 2.11.0-7
+- Backport Fixes for #1677616 (pinctrl thread) and fixes related to IPv6 RA."
+
+* Tue Mar 19 2019 Numan Siddique <nusiddiq@redhat.com> - 2.11.0-6
+- Removed ovn-common package and moved all the related files to main 'ovn' package.
+
+* Tue Mar 19 2019 Timothy Redaelli <tredaelli@redhat.com> - 2.11.0-5
+- Disable ovn-docker subpackage by default
+
+* Thu Mar 07 2019 Mark Michelson <mmichels@redhat.com> - 2.11.0-4
+- Backport "OVN: Add port addresses to IPAM after all ports are joined."
+
+* Sat Mar 02 2019 Numan Siddique <nusiddiq@redhat.com> - 2.11.0-3
+- Backport "ovn-controller: Provide the option to set the datapath-type of br-int" (#1684796)
+
+* Fri Mar 01 2019 Timothy Redaelli <tredaelli@redhat.com> - 2.11.0-2
+- Backport "rhel: Use PIDFile on forking systemd service files" (#1684477)
+
+* Thu Feb 28 2019 Numan Siddique <nusiddiq@redhat.com> - 2.11.0-1
+- Update to official 2.11 release
+
+* Wed Jan 23 2019 Numan Siddique <nusiddiq@redhat.com> - 2.11.0-0.20190117git4e4f80e
+- Update to OVS 2.11 branch
+
+* Thu Jan 17 2019 Numan Siddique <nusiddiq@redhat.com> - 2.11.0-0.20190117gitab66223
+- Update to a snapshot of OVS 2.11 from master
+
+* Thu Dec 20 2018 Numan Siddique <nusiddiq@redhat.com>
+- OVS/OVN split.
+