On Thu, May 4, 2023 at 12:15 PM Lorenzo Bianconi < [email protected]> wrote:
> Similar to IPv4 support, add IPv6 support for iPXE chainload. > > Signed-off-by: Lorenzo Bianconi <[email protected]> > --- > controller/pinctrl.c | 36 ++++++++++++++++++-- > lib/ovn-l7.h | 9 +++++ > northd/ovn-northd.c | 4 ++- > tests/ovn.at | 78 +++++++++++++++++++++++++++++++++++++------- > tests/test-ovn.c | 2 ++ > 5 files changed, 115 insertions(+), 14 deletions(-) > > diff --git a/controller/pinctrl.c b/controller/pinctrl.c > index bf285c9e5..a0b98a52c 100644 > --- a/controller/pinctrl.c > +++ b/controller/pinctrl.c > @@ -2441,7 +2441,8 @@ exit: > > static bool > compose_out_dhcpv6_opts(struct ofpbuf *userdata, > - struct ofpbuf *out_dhcpv6_opts, ovs_be32 iaid) > + struct ofpbuf *out_dhcpv6_opts, > + ovs_be32 iaid, bool ipxe_req) > { > while (userdata->size) { > ovs_be16 opt_size, opt_code; > @@ -2546,6 +2547,27 @@ compose_out_dhcpv6_opts(struct ofpbuf *userdata, > break; > } > > + case DHCPV6_OPT_BOOT_FILE_URL: > + if (ipxe_req) { > + struct dhcpv6_opt_header *opt_dsl = ofpbuf_put_zeros( > + out_dhcpv6_opts, sizeof *opt_dsl); > + opt_dsl->code = htons(DHCPV6_OPT_BOOT_FILE_URL); > + opt_dsl->len = htons(size); > + ofpbuf_put(out_dhcpv6_opts, userdata_opt_data, size); > + } > + break; > + > + case DHCPV6_OPT_BOOT_FILE_URL_ALT: { > + if (!ipxe_req) { > + struct dhcpv6_opt_header *opt_dsl = ofpbuf_put_zeros( > + out_dhcpv6_opts, sizeof *opt_dsl); > + opt_dsl->code = htons(DHCPV6_OPT_BOOT_FILE_URL); > + opt_dsl->len = htons(size); > + ofpbuf_put(out_dhcpv6_opts, userdata_opt_data, size); > + } > + break; > + } > + > default: > return false; > } > @@ -2633,6 +2655,7 @@ pinctrl_handle_put_dhcpv6_opts( > size_t udp_len = ntohs(in_udp->udp_len); > size_t l4_len = dp_packet_l4_size(pkt_in); > uint8_t *end = (uint8_t *)in_udp + MIN(udp_len, l4_len); > + bool ipxe_req = false; > while (in_dhcpv6_data < end) { > struct dhcpv6_opt_header const *in_opt = > (struct dhcpv6_opt_header *)in_dhcpv6_data; > @@ -2649,6 +2672,14 @@ pinctrl_handle_put_dhcpv6_opts( > in_opt_client_id = in_opt; > break; > > + case DHCPV6_OPT_USER_CLASS: { > + char *user_class = (char *)(in_opt + 1); > + if (!strcmp(user_class + 2, "iPXE")) { > + ipxe_req = true; > + } > + break; > + } > + > default: > break; > } > @@ -2671,7 +2702,8 @@ pinctrl_handle_put_dhcpv6_opts( > struct ofpbuf out_dhcpv6_opts = > OFPBUF_STUB_INITIALIZER(out_ofpacts_dhcpv6_opts_stub); > > - if (!compose_out_dhcpv6_opts(userdata, &out_dhcpv6_opts, iaid)) { > + if (!compose_out_dhcpv6_opts(userdata, &out_dhcpv6_opts, > + iaid, ipxe_req)) { > VLOG_WARN_RL(&rl, "Invalid userdata"); > goto exit; > } > diff --git a/lib/ovn-l7.h b/lib/ovn-l7.h > index 2b20bc380..621251e84 100644 > --- a/lib/ovn-l7.h > +++ b/lib/ovn-l7.h > @@ -270,10 +270,13 @@ struct dhcp_opt6_header { > #define DHCPV6_OPT_IA_NA_CODE 3 > #define DHCPV6_OPT_IA_ADDR_CODE 5 > #define DHCPV6_OPT_STATUS_CODE 13 > +#define DHCPV6_OPT_USER_CLASS 15 > #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_BOOT_FILE_URL 59 > +#define DHCPV6_OPT_BOOT_FILE_URL_ALT 254 > > #define DHCPV6_OPT_SERVER_ID \ > DHCP_OPTION("server_id", DHCPV6_OPT_SERVER_ID_CODE, "mac") > @@ -287,6 +290,12 @@ struct dhcp_opt6_header { > #define DHCPV6_OPT_DOMAIN_SEARCH \ > DHCP_OPTION("domain_search", DHCPV6_OPT_DOMAIN_SEARCH_CODE, "str") > > +#define DHCPV6_OPT_BOOTFILE_NAME \ > + DHCP_OPTION("bootfile_name", DHCPV6_OPT_BOOT_FILE_URL, "str") > + > +#define DHCPV6_OPT_BOOTFILE_NAME_ALT \ > + DHCP_OPTION("bootfile_name_alt", DHCPV6_OPT_BOOT_FILE_URL_ALT, "str") > + > OVS_PACKED( > struct dhcpv6_opt_header { > ovs_be16 code; > diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c > index 116b6e801..3515b68a2 100644 > --- a/northd/ovn-northd.c > +++ b/northd/ovn-northd.c > @@ -271,7 +271,9 @@ static struct gen_opts_map supported_dhcpv6_opts[] = { > DHCPV6_OPT_IA_ADDR, > DHCPV6_OPT_SERVER_ID, > DHCPV6_OPT_DOMAIN_SEARCH, > - DHCPV6_OPT_DNS_SERVER > + DHCPV6_OPT_DNS_SERVER, > + DHCPV6_OPT_BOOTFILE_NAME, > + DHCPV6_OPT_BOOTFILE_NAME_ALT > }; > > static bool > diff --git a/tests/ovn.at b/tests/ovn.at > index 213ad18fa..6c2aeb318 100644 > --- a/tests/ovn.at > +++ b/tests/ovn.at > @@ -1691,6 +1691,12 @@ reg1[0] = put_dhcpv6_opts(ia_addr="ae70::4"); > DHCPv6 option ia_addr requires numeric value. > reg1[0] = put_dhcpv6_opts(ia_addr=ae70::4, domain_search=ae70::1); > DHCPv6 option domain_search requires string value. > +reg1[0] = put_dhcpv6_opts(bootfile_name="https://127.0.0.1/boot.ipxe"); > + formats as reg1[0] = put_dhcpv6_opts(bootfile_name = " > https://127.0.0.1/boot.ipxe"); > + encodes as > controller(userdata=00.00.00.05.00.00.00.00.00.01.de.10.00.00.00.40.00.3b.00.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,pause) > +reg1[0] = put_dhcpv6_opts(bootfile_name_alt="https://127.0.0.1/boot.ipxe > "); > + formats as reg1[0] = put_dhcpv6_opts(bootfile_name_alt = " > https://127.0.0.1/boot.ipxe"); > + encodes as > controller(userdata=00.00.00.05.00.00.00.00.00.01.de.10.00.00.00.40.00.fe.00.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,pause) > > # lookup_nd > reg2[0] = lookup_nd(inport, ip6.dst, eth.src); > @@ -7176,13 +7182,15 @@ trim_zeros() { > # packet should be received twice (one from ovn-controller and the other > # from the "ovs-ofctl monitor br-int resume" > test_dhcpv6() { > - local inport=$1 src_mac=$2 src_lla=$3 msg_code=$4 offer_ip=$5 > - if test $msg_code != 0b; then > + local inport=$1 src_mac=$2 src_lla=$3 msg_code=$4 offer_ip=$5 ipxe=$6 > + if test $ipxe -eq 2; then > + req_len=34 > + elif test $msg_code != 0b; then > req_len=2a > else > req_len=1a > fi > - local > request=ffffffffffff${src_mac}86dd0000000000${req_len}1101${src_lla} > + local > request=ffffffffffff${src_mac}86dd6000000000${req_len}1101${src_lla} > # dst ip ff02::1:2 > request=${request}ff020000000000000000000000010002 > # udp header and dhcpv6 header > @@ -7194,7 +7202,10 @@ test_dhcpv6() { > if test $msg_code != 0b; then > request=${request}0003000c0102030400000e1000001518 > fi > - shift; shift; shift; shift; shift; > + if test $ipxe -eq 2; then > + request=${request}000f0006000669505845 > + fi > + shift; shift; shift; shift; shift; shift; > if test $offer_ip != 0; then > local server_mac=000000100001 > local server_lla=fe80000000000000020000fffe100001 > @@ -7203,10 +7214,14 @@ test_dhcpv6() { > reply_code=02 > fi > local msg_len=54 > - if test $offer_ip = 1; then > + if test $ipxe -eq 1; then > + msg_len=69 > + elif test $ipxe -eq 2; then > + msg_len=65 > + elif test $offer_ip = 1; then > msg_len=28 > fi > - local > reply=${src_mac}${server_mac}86dd0000000000${msg_len}1101${server_lla}${src_lla} > + local > reply=${src_mac}${server_mac}86dd6000000000${msg_len}1101${server_lla}${src_lla} > # udp header and dhcpv6 header > reply=${reply}0223022200${msg_len}ffff${reply_code}010203 > # Client identifier > @@ -7215,6 +7230,11 @@ test_dhcpv6() { > if test $offer_ip != 1; then > > > reply=${reply}0003002801020304ffffffffffffffff00050018${offer_ip}ffffffffffffffff > fi > + if test $ipxe -eq 1; then > + reply=${reply}003b0011626f6f7466696c655f6e616d655f616c74 > + elif test $ipxe -eq 2; then > + reply=${reply}003b000d626f6f7466696c655f6e616d65 > + fi > # Server identifier > reply=${reply}0002000a00030001${server_mac} > echo $reply | trim_zeros >> $inport.expected > @@ -7249,7 +7269,7 @@ as hv1 ovs-ofctl dump-flows br-int > src_mac=f00000000001 > src_lla=fe80000000000000f20000fffe000001 > offer_ip=ae700000000000000000000000000004 > -test_dhcpv6 1 $src_mac $src_lla 01 $offer_ip > +test_dhcpv6 1 $src_mac $src_lla 01 $offer_ip 0 > > # NXT_RESUMEs should be 1. > OVS_WAIT_UNTIL([test 1 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) > @@ -7277,7 +7297,7 @@ src_lla=fe80000000000000f20000fffe000002 > offer_ip=ae700000000000000000000000000005 > # Set invalid msg_type > > -test_dhcpv6 2 $src_mac $src_lla 10 0 1 1 > +test_dhcpv6 2 $src_mac $src_lla 10 0 0 1 1 > > # NXT_RESUMEs should be 2. > OVS_WAIT_UNTIL([test 2 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) > @@ -7298,7 +7318,7 @@ AT_CHECK([cat 1.packets], [0], [expout]) > > src_mac=f00000000003 > src_lla=fe80000000000000f20000fffe000003 > -test_dhcpv6 3 $src_mac $src_lla 01 0 4 > +test_dhcpv6 3 $src_mac $src_lla 01 0 0 4 > > # NXT_RESUMEs should be 2 only. > OVS_WAIT_UNTIL([test 2 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) > @@ -7317,7 +7337,7 @@ AT_CHECK([cat 4.packets], [0], [expout]) > src_mac=f00000000022 > src_lla=fe80000000000000f20000fffe000022 > reset_pcap_file hv1-vif5 hv1/vif5 > -test_dhcpv6 5 $src_mac $src_lla 01 1 5 > +test_dhcpv6 5 $src_mac $src_lla 01 1 0 5 > > # NXT_RESUMEs should be 3. > OVS_WAIT_UNTIL([test 3 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) > @@ -7333,7 +7353,7 @@ src_mac=f00000000022 > src_lla=fe80000000000000f20000fffe000022 > reset_pcap_file hv1-vif5 hv1/vif5 > rm -f 5.expected > -test_dhcpv6 5 $src_mac $src_lla 0b 1 5 > +test_dhcpv6 5 $src_mac $src_lla 0b 1 0 5 > > # NXT_RESUMEs should be 4. > OVS_WAIT_UNTIL([test 4 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) > @@ -7344,6 +7364,42 @@ trim_zeros > 5.packets > cat 5.expected | cut -c 1-120,125- > expout > AT_CHECK([cat 5.packets | cut -c 1-120,125- ], [0], [expout]) > > +ovn-nbctl --all destroy dhcp-option > +d1="$(ovn-nbctl create DHCP_Options cidr="ae70\:\:/64")" > +ovn-nbctl dhcp-options-set-options $d1 \ > + server_id=00:00:00:10:00:01 \ > + bootfile_name_alt=\"bootfile_name_alt\" \ > + bootfile_name=\"bootfile_name\" > +ovn-nbctl lsp-set-dhcpv6-options ls1-lp2 ${d1} > + > +reset_pcap_file hv1-vif2 hv1/vif2 > + > +src_mac=f00000000002 > +src_lla=fe80000000000000f20000fffe000002 > +offer_ip=ae700000000000000000000000000005 > + > +test_dhcpv6 2 $src_mac $src_lla 01 $offer_ip 1 > +# NXT_RESUMEs should be 5. > +OVS_WAIT_UNTIL([test 5 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) > + > +# vif2-tx.pcap should not have received the DHCPv6 reply packet > +rm 2.packets > +$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap | > trim_zeros > 2.packets > +# Skipping the UDP checksum > +cat 2.expected | cut -c 1-120,125- > expout > +AT_CHECK([cat 2.packets | cut -c 1-120,125- ], [0], [expout]) > + > +reset_pcap_file hv1-vif2 hv1/vif2 > +rm 2.packets 2.expected > + > +test_dhcpv6 2 $src_mac $src_lla 01 $offer_ip 2 > +# 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 | > trim_zeros > 2.packets > +cat 2.expected | cut -c 1-120,125- > expout > +AT_CHECK([cat 2.packets | cut -c 1-120,125- ], [0], [expout]) > + > OVN_CLEANUP([hv1]) > > AT_CLEANUP > diff --git a/tests/test-ovn.c b/tests/test-ovn.c > index d58350dcf..ce9213c1d 100644 > --- a/tests/test-ovn.c > +++ b/tests/test-ovn.c > @@ -205,6 +205,8 @@ create_gen_opts(struct hmap *dhcp_opts, struct hmap > *dhcpv6_opts, > dhcp_opt_add(dhcpv6_opts, "ia_addr", 5, "ipv6"); > dhcp_opt_add(dhcpv6_opts, "dns_server", 23, "ipv6"); > dhcp_opt_add(dhcpv6_opts, "domain_search", 24, "str"); > + dhcp_opt_add(dhcpv6_opts, "bootfile_name", 59, "str"); > + dhcp_opt_add(dhcpv6_opts, "bootfile_name_alt", 254, "str"); > > /* IPv6 ND RA options. */ > hmap_init(nd_ra_opts); > -- > 2.40.1 > > _______________________________________________ > dev mailing list > [email protected] > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > > Looks good to me, thanks. Acked-by: Ales Musil <[email protected]> -- Ales Musil Senior Software Engineer - OVN Core Red Hat EMEA <https://www.redhat.com> [email protected] IM: amusil <https://red.ht/sig> _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
