Blob Blame History Raw
From 335116496aeb5e2d1f40fcc909ce9bc02e293962 Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <me@lorenzobianconi.net>
Date: Fri, 30 Oct 2020 17:06:28 +0100
Subject: [PATCH] Backport "dhcp: add iPXE support to OVN"

Resolve: #1765506
---
 0001-dhcp-add-iPXE-support-to-OVN.patch | 498 ++++++++++++++++++++++++
 ovn2.13.spec                            |   8 +-
 2 files changed, 505 insertions(+), 1 deletion(-)
 create mode 100644 0001-dhcp-add-iPXE-support-to-OVN.patch

diff --git a/0001-dhcp-add-iPXE-support-to-OVN.patch b/0001-dhcp-add-iPXE-support-to-OVN.patch
new file mode 100644
index 0000000..5e08118
--- /dev/null
+++ b/0001-dhcp-add-iPXE-support-to-OVN.patch
@@ -0,0 +1,498 @@
+From e52278861714dc22b666a7cf70b2dba687473060 Mon Sep 17 00:00:00 2001
+Message-Id: <e52278861714dc22b666a7cf70b2dba687473060.1604073622.git.lorenzo.bianconi@redhat.com>
+From: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
+Date: Fri, 23 Oct 2020 12:27:42 +0200
+Subject: [PATCH] dhcp: add iPXE support to OVN
+
+Add iPXE support to OVN introducing "bootfile_name_alt" dhcp option.
+"bootfile_name_alt" dhcp userdata is encoded as option 254 since
+it is not currently used.
+When both "bootfile_name" and "bootfile_name_alt" are provided
+by the CMS, "bootfile_name" will be used for option 67 if the
+dhcp request contains etherboot option (175), otherwise
+"bootfile_name_alt" will be used.
+"bootfile_name" and "bootfile_name_alt" are placed just after offer_ip
+in userdata buffer.
+
+Tested-by: Lucas Alvares Gomes Martins <lmartins@redhat.com>
+Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
+Signed-off-by: Numan Siddique <numans@ovn.org>
+---
+ controller/pinctrl.c |  30 ++++++++++++
+ lib/actions.c        |  33 ++++++++++---
+ lib/ovn-l7.h         |  11 +++++
+ northd/ovn-northd.c  |   1 +
+ ovn-nb.xml           |  10 ++++
+ tests/ovn.at         | 110 ++++++++++++++++++++++++++++++-------------
+ tests/test-ovn.c     |   1 +
+ 7 files changed, 158 insertions(+), 38 deletions(-)
+
+--- a/controller/pinctrl.c
++++ b/controller/pinctrl.c
+@@ -1868,6 +1868,7 @@ pinctrl_handle_put_dhcp_opts(
+     }
+     in_dhcp_ptr += sizeof magic_cookie;
+ 
++    bool ipxe_req = false;
+     const uint8_t *in_dhcp_msg_type = NULL;
+     ovs_be32 request_ip = in_dhcp_data->ciaddr;
+     while (in_dhcp_ptr < end) {
+@@ -1900,6 +1901,9 @@ pinctrl_handle_put_dhcp_opts(
+                 request_ip = get_unaligned_be32(DHCP_OPT_PAYLOAD(in_dhcp_opt));
+             }
+             break;
++        case DHCP_OPT_ETHERBOOT:
++            ipxe_req = true;
++            break;
+         default:
+             break;
+         }
+@@ -2018,6 +2022,32 @@ pinctrl_handle_put_dhcp_opts(
+      *| 4 Bytes padding | 1 Byte (option end 0xFF ) | 4 Bytes padding|
+      * --------------------------------------------------------------
+      */
++    struct dhcp_opt_header *in_dhcp_opt =
++        (struct dhcp_opt_header *)reply_dhcp_opts_ptr->data;
++    if (in_dhcp_opt->code == DHCP_OPT_BOOTFILE_CODE) {
++        unsigned char *ptr = (unsigned char *)in_dhcp_opt;
++        int len = sizeof *in_dhcp_opt + in_dhcp_opt->len;
++        struct dhcp_opt_header *next_dhcp_opt =
++            (struct dhcp_opt_header *)(ptr + len);
++
++        if (next_dhcp_opt->code == DHCP_OPT_BOOTFILE_ALT_CODE) {
++            if (!ipxe_req) {
++                ofpbuf_pull(reply_dhcp_opts_ptr, len);
++                next_dhcp_opt->code = DHCP_OPT_BOOTFILE_CODE;
++            } else {
++                char *buf = xmalloc(len);
++
++                memcpy(buf, in_dhcp_opt, len);
++                ofpbuf_pull(reply_dhcp_opts_ptr,
++                            sizeof *in_dhcp_opt + next_dhcp_opt->len);
++                memcpy(reply_dhcp_opts_ptr->data, buf, len);
++                free(buf);
++            }
++        }
++    } else if (in_dhcp_opt->code == DHCP_OPT_BOOTFILE_ALT_CODE) {
++        in_dhcp_opt->code = DHCP_OPT_BOOTFILE_CODE;
++    }
++
+     uint16_t new_l4_size = UDP_HEADER_LEN + DHCP_HEADER_LEN + 16;
+     if (msg_type != DHCP_MSG_NAK) {
+         new_l4_size += reply_dhcp_opts_ptr->size;
+--- a/lib/actions.c
++++ b/lib/actions.c
+@@ -2086,10 +2086,10 @@ parse_gen_opt(struct action_context *ctx
+ }
+ 
+ static const struct ovnact_gen_option *
+-find_offerip(const struct ovnact_gen_option *options, size_t n)
++find_opt(const struct ovnact_gen_option *options, size_t n, size_t code)
+ {
+     for (const struct ovnact_gen_option *o = options; o < &options[n]; o++) {
+-        if (o->option->code == 0) {
++        if (o->option->code == code) {
+             return o;
+         }
+     }
+@@ -2288,7 +2288,7 @@ parse_put_dhcp_opts(struct action_contex
+     parse_put_opts(ctx, dst, po, dhcp_opts, opts_type);
+ 
+     if (!ctx->lexer->error && po->ovnact.type == OVNACT_PUT_DHCPV4_OPTS
+-        && !find_offerip(po->options, po->n_options)) {
++        && !find_opt(po->options, po->n_options, 0)) {
+         lexer_error(ctx->lexer,
+                     "put_dhcp_opts requires offerip to be specified.");
+         return;
+@@ -2537,14 +2537,35 @@ encode_PUT_DHCPV4_OPTS(const struct ovna
+     /* Encode the offerip option first, because it's a special case and needs
+      * to be first in the actual DHCP response, and then encode the rest
+      * (skipping offerip the second time around). */
+-    const struct ovnact_gen_option *offerip_opt = find_offerip(
+-        pdo->options, pdo->n_options);
++    const struct ovnact_gen_option *offerip_opt = find_opt(
++        pdo->options, pdo->n_options, 0);
+     ovs_be32 offerip = offerip_opt->value.values[0].value.ipv4;
+     ofpbuf_put(ofpacts, &offerip, sizeof offerip);
+ 
++    /* Encode bootfile_name opt (67) */
++    const struct ovnact_gen_option *boot_opt =
++        find_opt(pdo->options, pdo->n_options, DHCP_OPT_BOOTFILE_CODE);
++    if (boot_opt) {
++        uint8_t *opt_header = ofpbuf_put_zeros(ofpacts, 2);
++        const union expr_constant *c = boot_opt->value.values;
++        opt_header[0] = boot_opt->option->code;
++        opt_header[1] = strlen(c->string);
++        ofpbuf_put(ofpacts, c->string, opt_header[1]);
++    }
++    /* Encode bootfile_name_alt opt (254) */
++    const struct ovnact_gen_option *boot_alt_opt =
++        find_opt(pdo->options, pdo->n_options, DHCP_OPT_BOOTFILE_ALT_CODE);
++    if (boot_alt_opt) {
++        uint8_t *opt_header = ofpbuf_put_zeros(ofpacts, 2);
++        const union expr_constant *c = boot_alt_opt->value.values;
++        opt_header[0] = boot_alt_opt->option->code;
++        opt_header[1] = strlen(c->string);
++        ofpbuf_put(ofpacts, c->string, opt_header[1]);
++    }
++
+     for (const struct ovnact_gen_option *o = pdo->options;
+          o < &pdo->options[pdo->n_options]; o++) {
+-        if (o != offerip_opt) {
++        if (o != offerip_opt && o != boot_opt && o != boot_alt_opt) {
+             encode_put_dhcpv4_option(o, ofpacts);
+         }
+     }
+--- a/lib/ovn-l7.h
++++ b/lib/ovn-l7.h
+@@ -93,6 +93,17 @@ struct gen_opts_map {
+ #define DHCP_OPT_DOMAIN_SEARCH_LIST \
+     DHCP_OPTION("domain_search_list", 119, "domains")
+ 
++#define DHCP_OPT_BOOTFILE_CODE 67
++
++/* Use unused 254 option for iPXE bootfile_name_alt userdata DHCP option.
++ * This option code is replaced by 67 when sending the DHCP reply.
++ */
++#define DHCP_OPT_BOOTFILE_ALT_CODE 254
++#define DHCP_OPT_BOOTFILE_ALT DHCP_OPTION("bootfile_name_alt", \
++                                          DHCP_OPT_BOOTFILE_ALT_CODE, "str")
++
++#define DHCP_OPT_ETHERBOOT	175
++
+ #define DHCP_OPT_ARP_CACHE_TIMEOUT \
+     DHCP_OPTION("arp_cache_timeout", 35, "uint32")
+ #define DHCP_OPT_TCP_KEEPALIVE_INTERVAL \
+--- a/northd/ovn-northd.c
++++ b/northd/ovn-northd.c
+@@ -12419,6 +12419,7 @@ static struct gen_opts_map supported_dhc
+     DHCP_OPT_ARP_CACHE_TIMEOUT,
+     DHCP_OPT_TCP_KEEPALIVE_INTERVAL,
+     DHCP_OPT_DOMAIN_SEARCH_LIST,
++    DHCP_OPT_BOOTFILE_ALT,
+ };
+ 
+ static struct gen_opts_map supported_dhcpv6_opts[] = {
+--- a/ovn-nb.xml
++++ b/ovn-nb.xml
+@@ -3096,6 +3096,16 @@
+             resolving hostnames via the Domain Name System.
+           </p>
+         </column>
++
++        <column name="options" key="bootfile_name_alt">
++          <p>
++          </p>
++            "bootfile_name_alt" option is used to support iPXE.
++            When both "bootfile_name" and "bootfile_name_alt" are provided
++            by the CMS, "bootfile_name" will be used for option 67 if the
++            dhcp request contains etherboot option (175), otherwise
++            "bootfile_name_alt" will be used.
++        </column>
+       </group>
+ 
+       <group title="DHCP Options of type host_id">
+--- a/tests/ovn.at
++++ b/tests/ovn.at
+@@ -1280,7 +1280,7 @@ reg1[0] = put_dhcp_opts(offerip = 1.2.3.
+     encodes as controller(userdata=00.00.00.02.00.00.00.00.00.01.de.10.00.00.00.40.01.02.03.04.03.04.0a.00.00.01,pause)
+ reg2[5] = put_dhcp_opts(offerip=10.0.0.4,router=10.0.0.1,netmask=255.255.254.0,mtu=1400,domain_name="ovn.org",wpad="https://example.org",bootfile_name="https://127.0.0.1/boot.ipxe",path_prefix="/tftpboot");
+     formats as reg2[5] = put_dhcp_opts(offerip = 10.0.0.4, router = 10.0.0.1, netmask = 255.255.254.0, mtu = 1400, domain_name = "ovn.org", wpad = "https://example.org", bootfile_name = "https://127.0.0.1/boot.ipxe", path_prefix = "/tftpboot");
+-    encodes as controller(userdata=00.00.00.02.00.00.00.00.00.01.de.10.00.00.00.25.0a.00.00.04.03.04.0a.00.00.01.01.04.ff.ff.fe.00.1a.02.05.78.0f.07.6f.76.6e.2e.6f.72.67.fc.13.68.74.74.70.73.3a.2f.2f.65.78.61.6d.70.6c.65.2e.6f.72.67.43.1b.68.74.74.70.73.3a.2f.2f.31.32.37.2e.30.2e.30.2e.31.2f.62.6f.6f.74.2e.69.70.78.65.d2.09.2f.74.66.74.70.62.6f.6f.74,pause)
++    encodes as controller(userdata=00.00.00.02.00.00.00.00.00.01.de.10.00.00.00.25.0a.00.00.04.43.1b.68.74.74.70.73.3a.2f.2f.31.32.37.2e.30.2e.30.2e.31.2f.62.6f.6f.74.2e.69.70.78.65.03.04.0a.00.00.01.01.04.ff.ff.fe.00.1a.02.05.78.0f.07.6f.76.6e.2e.6f.72.67.fc.13.68.74.74.70.73.3a.2f.2f.65.78.61.6d.70.6c.65.2e.6f.72.67.d2.09.2f.74.66.74.70.62.6f.6f.74,pause)
+ reg0[15] = put_dhcp_opts(offerip=10.0.0.4,router=10.0.0.1,netmask=255.255.255.0,mtu=1400,ip_forward_enable=1,default_ttl=121,dns_server={8.8.8.8,7.7.7.7},classless_static_route={30.0.0.0/24,10.0.0.4,40.0.0.0/16,10.0.0.6,0.0.0.0/0,10.0.0.1},ethernet_encap=1,router_discovery=0,tftp_server_address={10.0.0.4,10.0.0.5},arp_cache_timeout=10,tcp_keepalive_interval=10);
+     formats as reg0[15] = put_dhcp_opts(offerip = 10.0.0.4, router = 10.0.0.1, netmask = 255.255.255.0, mtu = 1400, ip_forward_enable = 1, default_ttl = 121, dns_server = {8.8.8.8, 7.7.7.7}, classless_static_route = {30.0.0.0/24, 10.0.0.4, 40.0.0.0/16, 10.0.0.6, 0.0.0.0/0, 10.0.0.1}, ethernet_encap = 1, router_discovery = 0, tftp_server_address = {10.0.0.4, 10.0.0.5}, arp_cache_timeout = 10, tcp_keepalive_interval = 10);
+     encodes as controller(userdata=00.00.00.02.00.00.00.00.00.01.de.10.00.00.00.6f.0a.00.00.04.03.04.0a.00.00.01.01.04.ff.ff.ff.00.1a.02.05.78.13.01.01.17.01.79.06.08.08.08.08.08.07.07.07.07.79.14.18.1e.00.00.0a.00.00.04.10.28.00.0a.00.00.06.00.0a.00.00.01.24.01.01.1f.01.00.96.08.0a.00.00.04.0a.00.00.05.23.04.00.00.00.0a.26.04.00.00.00.0a,pause)
+@@ -1292,10 +1292,10 @@ reg0[15] = put_dhcp_opts(offerip=10.0.0.
+     encodes as controller(userdata=00.00.00.02.00.00.00.00.00.01.de.10.00.00.00.6f.0a.00.00.04.03.04.0a.00.00.01.01.04.ff.ff.ff.00.1a.02.05.78.13.01.01.17.01.79.06.08.08.08.08.08.07.07.07.07.79.14.18.1e.00.00.0a.00.00.04.10.28.00.0a.00.00.06.00.0a.00.00.01.24.01.01.1f.01.00.42.10.74.66.74.70.5f.73.65.72.76.65.72.5f.74.65.73.74,pause)
+ reg2[5] = put_dhcp_opts(offerip=10.0.0.4,router=10.0.0.1,netmask=255.255.254.0,mtu=1400,domain_name="ovn.org",wpad="https://example.org",bootfile_name="https://127.0.0.1/boot.ipxe",path_prefix="/tftpboot",domain_search_list="ovn.org,abc.ovn.org");
+     formats as reg2[5] = put_dhcp_opts(offerip = 10.0.0.4, router = 10.0.0.1, netmask = 255.255.254.0, mtu = 1400, domain_name = "ovn.org", wpad = "https://example.org", bootfile_name = "https://127.0.0.1/boot.ipxe", path_prefix = "/tftpboot", domain_search_list = "ovn.org,abc.ovn.org");
+-    encodes as controller(userdata=00.00.00.02.00.00.00.00.00.01.de.10.00.00.00.25.0a.00.00.04.03.04.0a.00.00.01.01.04.ff.ff.fe.00.1a.02.05.78.0f.07.6f.76.6e.2e.6f.72.67.fc.13.68.74.74.70.73.3a.2f.2f.65.78.61.6d.70.6c.65.2e.6f.72.67.43.1b.68.74.74.70.73.3a.2f.2f.31.32.37.2e.30.2e.30.2e.31.2f.62.6f.6f.74.2e.69.70.78.65.d2.09.2f.74.66.74.70.62.6f.6f.74.77.0f.03.6f.76.6e.03.6f.72.67.00.03.61.62.63.c0.00,pause)
++    encodes as controller(userdata=00.00.00.02.00.00.00.00.00.01.de.10.00.00.00.25.0a.00.00.04.43.1b.68.74.74.70.73.3a.2f.2f.31.32.37.2e.30.2e.30.2e.31.2f.62.6f.6f.74.2e.69.70.78.65.03.04.0a.00.00.01.01.04.ff.ff.fe.00.1a.02.05.78.0f.07.6f.76.6e.2e.6f.72.67.fc.13.68.74.74.70.73.3a.2f.2f.65.78.61.6d.70.6c.65.2e.6f.72.67.d2.09.2f.74.66.74.70.62.6f.6f.74.77.0f.03.6f.76.6e.03.6f.72.67.00.03.61.62.63.c0.00,pause)
+ reg2[5] = put_dhcp_opts(offerip=10.0.0.4,router=10.0.0.1,netmask=255.255.254.0,mtu=1400,domain_name="ovn.org",wpad="https://example.org",bootfile_name="https://127.0.0.1/boot.ipxe",path_prefix="/tftpboot",domain_search_list="ovn.org,abc.ovn.org,def.ovn.org,ovn.test,def.ovn.test,test.org,abc.com");
+     formats as reg2[5] = put_dhcp_opts(offerip = 10.0.0.4, router = 10.0.0.1, netmask = 255.255.254.0, mtu = 1400, domain_name = "ovn.org", wpad = "https://example.org", bootfile_name = "https://127.0.0.1/boot.ipxe", path_prefix = "/tftpboot", domain_search_list = "ovn.org,abc.ovn.org,def.ovn.org,ovn.test,def.ovn.test,test.org,abc.com");
+-    encodes as controller(userdata=00.00.00.02.00.00.00.00.00.01.de.10.00.00.00.25.0a.00.00.04.03.04.0a.00.00.01.01.04.ff.ff.fe.00.1a.02.05.78.0f.07.6f.76.6e.2e.6f.72.67.fc.13.68.74.74.70.73.3a.2f.2f.65.78.61.6d.70.6c.65.2e.6f.72.67.43.1b.68.74.74.70.73.3a.2f.2f.31.32.37.2e.30.2e.30.2e.31.2f.62.6f.6f.74.2e.69.70.78.65.d2.09.2f.74.66.74.70.62.6f.6f.74.77.35.03.6f.76.6e.03.6f.72.67.00.03.61.62.63.c0.00.03.64.65.66.c0.00.03.6f.76.6e.04.74.65.73.74.00.03.64.65.66.c0.15.04.74.65.73.74.c0.04.03.61.62.63.03.63.6f.6d.00,pause)
++    encodes as controller(userdata=00.00.00.02.00.00.00.00.00.01.de.10.00.00.00.25.0a.00.00.04.43.1b.68.74.74.70.73.3a.2f.2f.31.32.37.2e.30.2e.30.2e.31.2f.62.6f.6f.74.2e.69.70.78.65.03.04.0a.00.00.01.01.04.ff.ff.fe.00.1a.02.05.78.0f.07.6f.76.6e.2e.6f.72.67.fc.13.68.74.74.70.73.3a.2f.2f.65.78.61.6d.70.6c.65.2e.6f.72.67.d2.09.2f.74.66.74.70.62.6f.6f.74.77.35.03.6f.76.6e.03.6f.72.67.00.03.61.62.63.c0.00.03.64.65.66.c0.00.03.6f.76.6e.04.74.65.73.74.00.03.64.65.66.c0.15.04.74.65.73.74.c0.04.03.61.62.63.03.63.6f.6d.00,pause)
+ 
+ reg1[0..1] = put_dhcp_opts(offerip = 1.2.3.4, router = 10.0.0.1);
+     Cannot use 2-bit field reg1[0..1] where 1-bit field is required.
+@@ -5332,10 +5332,10 @@ sleep 2
+ as hv1 ovs-vsctl show
+ 
+ # This shell function sends a DHCP request packet
+-# test_dhcp INPORT SRC_MAC DHCP_TYPE BROADCAST CIADDR OFFER_IP REQUEST_IP USE_IP ...
++# test_dhcp INPORT SRC_MAC DHCP_TYPE BROADCAST CIADDR OFFER_IP REQUEST_IP ETH_BOOT USE_IP ...
+ test_dhcp() {
+-    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;
++    local inport=$1 src_mac=$2 dhcp_type=$3 broadcast=$4 ciaddr=$5 offer_ip=$6 request_ip=$7 eth_boot=$8 use_ip=$9
++    shift; shift; shift; shift; shift; shift; shift; shift; shift;
+ 
+     if test $use_ip != 0; then
+         src_ip=$1
+@@ -5347,11 +5347,21 @@ test_dhcp() {
+     fi
+ 
+     if test $request_ip != 0; then
+-        ip_len=0120
+-        udp_len=010b
++        if test $eth_boot != 0; then
++            ip_len=0124
++            udp_len=010f
++        else
++            ip_len=0120
++            udp_len=010b
++        fi
+     else
+-        ip_len=011a
+-        udp_len=0106
++        if test $eth_boot != 0; then
++            ip_len=011e
++            udp_len=010a
++        else
++            ip_len=011a
++            udp_len=0106
++        fi
+     fi
+ 
+     if test $broadcast != 0; then
+@@ -5392,6 +5402,9 @@ test_dhcp() {
+         # dhcp requested ip
+         request=${request}3204${request_ip}
+     fi
++    if test $eth_boot != 0; then
++        request=${request}af020000
++    fi
+     # dhcp end option
+     request=${request}ff
+ 
+@@ -5487,7 +5500,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 0 $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 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`])
+@@ -5513,7 +5526,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 0 $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 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`])
+@@ -5537,7 +5550,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 0 $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 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`])
+@@ -5561,7 +5574,7 @@ rm -f 2.expected
+ ciaddr=`ip_to_hex 0 0 0 0`
+ offer_ip=0
+ request_ip=0
+-test_dhcp 2 f00000000002 09 0 $ciaddr $offer_ip $request_ip 0 1 1
++test_dhcp 2 f00000000002 09 0 $ciaddr $offer_ip $request_ip 0 0 1 1
+ 
+ # NXT_RESUMEs should be 4.
+ OVS_WAIT_UNTIL([test 4 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
+@@ -5578,18 +5591,18 @@ 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 0 $ciaddr 0 0 4 0
++test_dhcp 3 f00000000003 01 0 $ciaddr 0 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 0 $ciaddr 0 0 3 0
++test_dhcp 4 f00000000004 01 0 $ciaddr 0 0 0 3 0
+ 
+ # NXT_RESUMEs should be 4.
+ OVS_WAIT_UNTIL([test 4 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
+ 
+-#OVN_CHECK_PACKETS([hv1/vif3-tx.pcap], [3.expected])
+-#OVN_CHECK_PACKETS([hv1/vif4-tx.pcap], [4.expected])
++OVN_CHECK_PACKETS([hv1/vif3-tx.pcap], [3.expected])
++OVN_CHECK_PACKETS([hv1/vif4-tx.pcap], [4.expected])
+ 
+ # Send DHCPREQUEST in the RENEWING/REBINDING state with ip4.src set to 10.0.0.6
+ # and ip4.dst set to 10.0.0.1.
+@@ -5600,7 +5613,7 @@ request_ip=0
+ src_ip=$offer_ip
+ dst_ip=$server_ip
+ expected_dhcp_opts=330400000e100104ffffff0003040a00000136040a000001
+-test_dhcp 2 f00000000002 03 0 $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 0 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`])
+@@ -5626,7 +5639,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 0 $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 0 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`])
+@@ -5652,7 +5665,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 0 $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 0 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`])
+@@ -5678,7 +5691,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 0 $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 0 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`])
+@@ -5700,7 +5713,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 0 $ciaddr 0 0 1 $src_ip $dst_ip 1
++test_dhcp 2 f00000000002 03 0 $ciaddr 0 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`])
+@@ -5719,7 +5732,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 1 $ciaddr $offer_ip $request_ip 0 ff1000000001 $server_ip 02 $expected_dhcp_opts
++test_dhcp 1 f00000000001 01 1 $ciaddr $offer_ip $request_ip 0 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`])
+@@ -5742,7 +5755,7 @@ server_ip=`ip_to_hex 10 0 0 1`
+ ciaddr=`ip_to_hex 10 0 0 6`
+ request_ip=0
+ expected_dhcp_opts=0
+-test_dhcp 2 f00000000002 07 0 $ciaddr $offer_ip $request_ip 0 ff1000000001
++test_dhcp 2 f00000000002 07 0 $ciaddr $offer_ip $request_ip 0 0 ff1000000001
+ 
+ # NXT_RESUMEs should be 10.
+ OVS_WAIT_UNTIL([test 10 = $(cat ofctl_monitor*.log | grep -c NXT_RESUME)])
+@@ -5769,7 +5782,7 @@ dst_ip=$server_ip
+ # In the expected_dhcp_opts we should not see 330400000e10 which is
+ # dhcp lease time option and 0104ffffff00 which is subnet mask option.
+ expected_dhcp_opts=03040a00000136040a000001
+-test_dhcp 2 f00000000002 08 0 $ciaddr $offer_ip $request_ip 1 $src_ip $dst_ip ff1000000001 $server_ip 05 $expected_dhcp_opts
++test_dhcp 2 f00000000002 08 0 $ciaddr $offer_ip $request_ip 0 1 $src_ip $dst_ip ff1000000001 $server_ip 05 $expected_dhcp_opts
+ 
+ # NXT_RESUMEs should be 11.
+ OVS_WAIT_UNTIL([test 11 = $(cat ofctl_monitor*.log | grep -c NXT_RESUME)])
+@@ -5799,7 +5812,7 @@ dst_ip=$server_ip
+ # In the expected_dhcp_opts we should not see 330400000e10 which is
+ # dhcp lease time option.
+ expected_dhcp_opts=3a0400000fa0330400000e100104ffffff0003040a00000136040a000001
+-test_dhcp 2 f00000000002 03 0 $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 0 1 $src_ip $dst_ip ff1000000001 $server_ip 05 $expected_dhcp_opts
+ 
+ # NXT_RESUMEs should be 12.
+ OVS_WAIT_UNTIL([test 12 = $(cat ofctl_monitor*.log | grep -c NXT_RESUME)])
+@@ -5826,7 +5839,7 @@ dst_ip=$server_ip
+ # In the expected_dhcp_opts we should not see 330400000e10 which is
+ # dhcp lease time option and 0104ffffff00 which is subnet mask option.
+ expected_dhcp_opts=03040a00000136040a000001
+-test_dhcp 2 f00000000002 08 0 $ciaddr $offer_ip $request_ip 1 $src_ip $dst_ip ff1000000001 $server_ip 05 $expected_dhcp_opts
++test_dhcp 2 f00000000002 08 0 $ciaddr $offer_ip $request_ip 0 1 $src_ip $dst_ip ff1000000001 $server_ip 05 $expected_dhcp_opts
+ 
+ # NXT_RESUMEs should be 13.
+ OVS_WAIT_UNTIL([test 13 = $(cat ofctl_monitor*.log | grep -c NXT_RESUME)])
+@@ -5857,7 +5870,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=330400000e100104ffffff0003040a00000136040a00000142040a0a0a0a
+-test_dhcp 2 f00000000002 03 0 $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 0 ff1000000001 $server_ip 05 $expected_dhcp_opts
+ 
+ # NXT_RESUMEs should be 14.
+ OVS_WAIT_UNTIL([test 14 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
+@@ -5888,7 +5901,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=330400000e100104ffffff0003040a00000136040a0000014210746573745f746674705f736572766572
+-test_dhcp 2 f00000000002 03 0 $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 0 ff1000000001 $server_ip 05 $expected_dhcp_opts
+ 
+ # NXT_RESUMEs should be 15.
+ OVS_WAIT_UNTIL([test 15 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
+@@ -5919,7 +5932,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=771305746573743103636f6d00057465737432c006330400000e100104ffffff0003040a00000136040a000001
+-test_dhcp 2 f00000000002 03 0 $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 0 ff1000000001 $server_ip 05 $expected_dhcp_opts
+ 
+ # NXT_RESUMEs should be 16.
+ OVS_WAIT_UNTIL([test 16 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
+@@ -5937,9 +5950,42 @@ server_ip=`ip_to_hex 10 0 0 1`
+ ciaddr=`ip_to_hex 0 0 0 0`
+ request_ip=0
+ expected_dhcp_opts=""
+-test_dhcp 1 f00000000001 04 0 $ciaddr $offer_ip $request_ip 0 ff1000000001 $server_ip 02 $expected_dhcp_opts
++test_dhcp 1 f00000000001 04 0 $ciaddr $offer_ip $request_ip 0 0 ff1000000001 $server_ip 02 $expected_dhcp_opts
+ AT_CHECK([fgrep -iq 'DHCPDECLINE from f0:00:00:00:00:01, 10.0.0.4 duplicated' hv1/ovn-controller.log], [0], [])
+ 
++# Send Etherboot.
++
++reset_pcap_file hv1-vif1 hv1/vif1
++reset_pcap_file hv1-vif2 hv1/vif2
++rm -f 1.expected
++rm -f 2.expected
++
++ovn-nbctl --all destroy dhcp-option
++
++ovn-nbctl dhcp-options-create 10.0.0.0/24
++d3=$(ovn-nbctl --bare --columns=_uuid find dhcp_options cidr="10.0.0.0/24")
++ovn-nbctl dhcp-options-set-options $d3 \
++   server_id=10.0.0.1 server_mac=ff:10:00:00:00:01 \
++   lease_time=3600 router=10.0.0.1 bootfile_name_alt=\"bootfile_name_alt\" \
++   bootfile_name=\"bootfile\"
++
++ovn-nbctl lsp-set-dhcpv4-options ls1-lp1 $d3
++
++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
++boofile=4308626f6f7466696c65
++expected_dhcp_opts=${boofile}330400000e100104ffffff0003040a00000136040a000001
++test_dhcp 1 f00000000001 01 0 $ciaddr $offer_ip $request_ip 1 0 ff1000000001 $server_ip 02 $expected_dhcp_opts
++
++$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
+--- a/tests/test-ovn.c
++++ b/tests/test-ovn.c
+@@ -191,6 +191,7 @@ create_gen_opts(struct hmap *dhcp_opts,
+     dhcp_opt_add(dhcp_opts, "arp_cache_timeout", 35, "uint32");
+     dhcp_opt_add(dhcp_opts, "tcp_keepalive_interval", 38, "uint32");
+     dhcp_opt_add(dhcp_opts, "domain_search_list", 119, "domains");
++    dhcp_opt_add(dhcp_opts, "bootfile_name_alt", 254, "str");
+ 
+     /* DHCPv6 options. */
+     hmap_init(dhcpv6_opts);
diff --git a/ovn2.13.spec b/ovn2.13.spec
index 0765480..f19af95 100644
--- a/ovn2.13.spec
+++ b/ovn2.13.spec
@@ -60,7 +60,7 @@ Summary: Open Virtual Network support
 Group: System Environment/Daemons
 URL: http://www.openvswitch.org/
 Version: %{upstreamver}.0
-Release: 7%{?commit0:.%{date}git%{shortcommit0}}%{?dist}
+Release: 8%{?commit0:.%{date}git%{shortcommit0}}%{?dist}
 Provides: openvswitch%{pkgver}-ovn-common = %{?epoch:%{epoch}:}%{version}-%{release}
 Obsoletes: openvswitch%{pkgver}-ovn-common < 2.11.0-1
 
@@ -140,6 +140,9 @@ Patch054: 0005-ovn-trace-Handle-IPv6-packets-for-tcp_reset-action.patch
 # Bug 1856898
 Patch060: 0001-ovn-northd-Handle-IPv6-addresses-with-prefixes-for-p.patch
 
+# Bug 1765506
+Patch070: 0001-dhcp-add-iPXE-support-to-OVN.patch
+
 # OpenvSwitch backports (800-) if required.
 Patch800: 0001-Revert-ovsdb-idl-Avoid-sending-redundant-conditional.patch
 Patch801: 0002-ovsdb-idl-Try-committing-the-pending-txn-in-ovsdb_id.patch
@@ -589,6 +592,9 @@ fi
 %{_unitdir}/ovn-controller-vtep.service
 
 %changelog
+* Fri Oct 30 2020 Lorenzo Bianconi <lorenzo.bianconi@redhat.com> - 20.09.0-8
+- Backport "dhcp: add iPXE support to OVN" (#1765506)
+
 * Fri Oct 23 2020 Dumitru Ceara <dceara@redhat.com> - 20.09.0-7
 - Backport "ovn-northd: Handle IPv6 addresses with prefixes for port security." (#1856898)
 
-- 
2.28.0