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

Reply via email to