On Fri, Sep 8, 2023 at 8:12 AM Ales Musil <[email protected]> wrote:
>
> The release message indicates that the address is
> no longer in use. Simply reply with status code success
> without any special handling as we do not store the
> information about address being in use.
>
> Reported-at: https://bugzilla.redhat.com/2237855
> Signed-off-by: Ales Musil <[email protected]>
Hi Ales,
I applied this patch to the main branch and also backported to
branch-23.09 (considering this as a bug fix).
I also updated the NEWS entry for this
diff --git a/NEWS b/NEWS
index 005afabb1..e7edecd1a 100644
--- a/NEWS
+++ b/NEWS
@@ -23,6 +23,8 @@ OVN v23.09.0 - xx xxx xxxx
cap the time between when ovn-controller sends gARP packets.
- Introduce support for binding remote ports in ovn-northd if the CMS sets
requested-chassis option for a remote logical switch port.
+ - Added support to reply success for DHCPv6 Release messages.
+
OVN v23.06.0 - 01 Jun 2023
--------------------------
Do you think we should backport to other branches too ?
Numan
> ---
> controller/pinctrl.c | 94 +++++++++++++++++------
> lib/ovn-l7.h | 8 ++
> tests/ovn.at | 174 ++++++++++++++++++++++++-------------------
> 3 files changed, 175 insertions(+), 101 deletions(-)
>
> diff --git a/controller/pinctrl.c b/controller/pinctrl.c
> index 1884e9f1b..ff5a3444c 100644
> --- a/controller/pinctrl.c
> +++ b/controller/pinctrl.c
> @@ -2290,6 +2290,26 @@ exit:
> }
> }
>
> +static void
> +encode_dhcpv6_server_id_opt(struct ofpbuf *opts, struct eth_addr *mac)
> +{
> + /* The Server Identifier option carries a DUID
> + * identifying a server between a client and a server.
> + * See RFC 3315 Sec 9 and Sec 22.3.
> + *
> + * We use DUID Based on Link-layer Address [DUID-LL].
> + */
> + struct dhcpv6_opt_server_id *server_id =
> + ofpbuf_put_zeros(opts, sizeof *server_id);
> + *server_id = (struct dhcpv6_opt_server_id) {
> + .opt.code = htons(DHCPV6_OPT_SERVER_ID_CODE),
> + .opt.len = htons(DHCP6_OPT_SERVER_ID_LEN - DHCP6_OPT_HEADER_LEN),
> + .duid_type = htons(DHCPV6_DUID_LL),
> + .hw_type = htons(DHCPV6_HW_TYPE_ETH),
> + .mac = *mac
> + };
> +}
> +
> static bool
> compose_out_dhcpv6_opts(struct ofpbuf *userdata,
> struct ofpbuf *out_dhcpv6_opts,
> @@ -2303,33 +2323,15 @@ compose_out_dhcpv6_opts(struct ofpbuf *userdata,
> }
>
> size_t size = ntohs(userdata_opt->len);
> - uint8_t *userdata_opt_data = ofpbuf_try_pull(userdata, size);
> + void *userdata_opt_data = ofpbuf_try_pull(userdata, size);
> if (!userdata_opt_data) {
> return false;
> }
>
> switch (ntohs(userdata_opt->code)) {
> case DHCPV6_OPT_SERVER_ID_CODE:
> - {
> - /* The Server Identifier option carries a DUID
> - * identifying a server between a client and a server.
> - * See RFC 3315 Sec 9 and Sec 22.3.
> - *
> - * We use DUID Based on Link-layer Address [DUID-LL].
> - */
> - struct dhcpv6_opt_server_id opt_server_id = {
> - .opt.code = htons(DHCPV6_OPT_SERVER_ID_CODE),
> - .opt.len = htons(size + 4),
> - .duid_type = htons(DHCPV6_DUID_LL),
> - .hw_type = htons(DHCPV6_HW_TYPE_ETH),
> - };
> - memcpy(&opt_server_id.mac, userdata_opt_data,
> - sizeof(struct eth_addr));
> - void *ptr = ofpbuf_put_zeros(out_dhcpv6_opts,
> - sizeof(struct
> dhcpv6_opt_server_id));
> - memcpy(ptr, &opt_server_id, sizeof(struct dhcpv6_opt_server_id));
> + encode_dhcpv6_server_id_opt(out_dhcpv6_opts, userdata_opt_data);
> break;
> - }
>
> case DHCPV6_OPT_IA_ADDR_CODE:
> {
> @@ -2442,6 +2444,40 @@ compose_out_dhcpv6_opts(struct ofpbuf *userdata,
> return true;
> }
>
> +static bool
> +compose_dhcpv6_status(struct ofpbuf *userdata, struct ofpbuf *opts)
> +{
> + while (userdata->size) {
> + struct dhcpv6_opt_header *userdata_opt = ofpbuf_try_pull(
> + userdata, sizeof *userdata_opt);
> + if (!userdata_opt) {
> + return false;
> + }
> +
> + size_t size = ntohs(userdata_opt->len);
> + void *userdata_opt_data = ofpbuf_try_pull(userdata, size);
> + if (!userdata_opt_data) {
> + return false;
> + }
> +
> + /* We care only about server id. Ignore everything else. */
> + if (ntohs(userdata_opt->code) == DHCPV6_OPT_SERVER_ID_CODE) {
> + encode_dhcpv6_server_id_opt(opts, userdata_opt_data);
> + break;
> + }
> + }
> +
> + /* Put success status code to the end. */
> + struct dhcpv6_opt_status *status = ofpbuf_put_zeros(opts, sizeof
> *status);
> + *status = (struct dhcpv6_opt_status) {
> + .opt.code = htons(DHCPV6_OPT_STATUS_CODE),
> + .opt.len = htons(DHCP6_OPT_STATUS_LEN - DHCP6_OPT_HEADER_LEN),
> + .status_code = htons(DHCPV6_STATUS_CODE_SUCCESS),
> + };
> +
> + return true;
> +}
> +
> /* Called with in the pinctrl_handler thread context. */
> static void
> pinctrl_handle_put_dhcpv6_opts(
> @@ -2492,6 +2528,7 @@ pinctrl_handle_put_dhcpv6_opts(
>
> uint8_t out_dhcpv6_msg_type;
> uint8_t in_dhcpv6_msg_type = *in_dhcpv6_data;
> + bool status_only = false;
> switch (in_dhcpv6_msg_type) {
> case DHCPV6_MSG_TYPE_SOLICIT:
> out_dhcpv6_msg_type = DHCPV6_MSG_TYPE_ADVT;
> @@ -2504,11 +2541,15 @@ pinctrl_handle_put_dhcpv6_opts(
> out_dhcpv6_msg_type = DHCPV6_MSG_TYPE_REPLY;
> break;
>
> + case DHCPV6_MSG_TYPE_RELEASE:
> + out_dhcpv6_msg_type = DHCPV6_MSG_TYPE_REPLY;
> + status_only = true;
> + break;
> +
> default:
> /* Invalid or unsupported DHCPv6 message type */
> goto exit;
> }
> -
> /* Skip 4 bytes (message type (1 byte) + transaction ID (3 bytes). */
> in_dhcpv6_data += 4;
> /* We need to extract IAID from the IA-NA option of the client's DHCPv6
> @@ -2574,8 +2615,15 @@ 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, ipxe_req, fqdn_flags)) {
> + bool compose = false;
> + if (status_only) {
> + compose = compose_dhcpv6_status(userdata, &out_dhcpv6_opts);
> + } else {
> + compose = compose_out_dhcpv6_opts(userdata, &out_dhcpv6_opts, iaid,
> + ipxe_req, fqdn_flags);
> + }
> +
> + if (!compose) {
> VLOG_WARN_RL(&rl, "Invalid userdata");
> goto exit;
> }
> diff --git a/lib/ovn-l7.h b/lib/ovn-l7.h
> index 9dc331421..ad514a922 100644
> --- a/lib/ovn-l7.h
> +++ b/lib/ovn-l7.h
> @@ -255,6 +255,7 @@ BUILD_ASSERT_DECL(DHCP_OPT_HEADER_LEN == sizeof(struct
> dhcp_opt_header));
> #define DHCPV6_MSG_TYPE_REBIND 6
>
> #define DHCPV6_MSG_TYPE_REPLY 7
> +#define DHCPV6_MSG_TYPE_RELEASE 8
> #define DHCPV6_MSG_TYPE_DECLINE 9
> #define DHCPV6_MSG_TYPE_INFO_REQ 11
>
> @@ -274,6 +275,9 @@ BUILD_ASSERT_DECL(DHCP_OPT_HEADER_LEN == sizeof(struct
> dhcp_opt_header));
> #define DHCPV6_OPT_BOOT_FILE_URL 59
> #define DHCPV6_OPT_BOOT_FILE_URL_ALT 254
>
> +/* DHCPv6 Status codes */
> +#define DHCPV6_STATUS_CODE_SUCCESS 0
> +
> #define DHCPV6_OPT_SERVER_ID \
> DHCP_OPTION("server_id", DHCPV6_OPT_SERVER_ID_CODE, "mac")
>
> @@ -301,11 +305,13 @@ BUILD_ASSERT_DECL(DHCP_OPT_HEADER_LEN == sizeof(struct
> dhcp_opt_header));
> #define DHCPV6_FQDN_FLAGS_O 1 << 1
> #define DHCPV6_FQDN_FLAGS_N 1 << 2
>
> +#define DHCP6_OPT_HEADER_LEN 4
> OVS_PACKED(
> struct dhcpv6_opt_header {
> ovs_be16 code;
> ovs_be16 len;
> });
> +BUILD_ASSERT_DECL(DHCP6_OPT_HEADER_LEN == sizeof(struct dhcpv6_opt_header));
>
> #define DHCP6_OPT_SERVER_ID_LEN 14
> struct dhcpv6_opt_server_id {
> @@ -377,12 +383,14 @@ struct dhcpv6_opt_ia_prefix {
> struct in6_addr ipv6;
> });
>
> +#define DHCP6_OPT_STATUS_LEN 6
> OVS_PACKED(
> struct dhcpv6_opt_status {
> struct dhcpv6_opt_header opt;
> ovs_be16 status_code;
> uint8_t msg[];
> });
> +BUILD_ASSERT_DECL(DHCP6_OPT_STATUS_LEN == sizeof(struct dhcpv6_opt_status));
>
> #define DHCPV6_DUID_LL 3
> #define DHCPV6_HW_TYPE_ETH 1
> diff --git a/tests/ovn.at b/tests/ovn.at
> index 2576a659b..e127530f6 100644
> --- a/tests/ovn.at
> +++ b/tests/ovn.at
> @@ -7292,6 +7292,9 @@ OVN_POPULATE_ARP
> wait_for_ports_up
> check ovn-nbctl --wait=hv sync
>
> +# Start with 0 because the first request will not have NXT_RESUME
> +n_resume=0
> +
> trim_zeros() {
> sed 's/\(00\)\{1,\}$//'
> }
> @@ -7360,6 +7363,59 @@ test_dhcpv6() {
> fi
>
> as hv1 ovs-appctl netdev-dummy/receive hv1-vif$inport $request
> + OVS_WAIT_UNTIL([test $n_resume = `cat ofctl_monitor*.log | grep -c
> NXT_RESUME`])
> + n_resume=$((n_resume + 1))
> +}
> +
> +test_dhcpv6_release() {
> + local inport=$1 src_mac=$2 src_lla=$3 offer_ip=$4
> +
> + local ip_scapy="DHCP6OptIAAddress(addr='${offer_ip}',
> preflft=0xffffffff, validlft=0xffffffff)"
> + local req_scapy="Ether(dst='00:00:00:10:00:01', src='${src_mac}')/ \
> + IPv6(dst='ff02::1:2', src='${src_lla}')/ \
> + UDP(sport=546, dport=547)/ \
> + DHCP6(msgtype=8, trid=0x010203)/ \
> + DHCP6OptClientId(duid=DUID_LL(lladdr='${src_mac}'))/ \
> +
> DHCP6OptServerId(duid=DUID_LL(lladdr='00:00:00:10:00:01'))/ \
> + DHCP6OptIA_NA(iaid=0x01020304, T1=0xffffffff,
> T2=0xffffffff, ianaopts=[[${ip_scapy}]])"
> +
> + request=$(fmt_pkt "${req_scapy}")
> +
> + local rep_scapy="Ether(dst='${src_mac}', src='00:00:00:10:00:01')/ \
> + IPv6(dst='${src_lla}',
> src='fe80::0200:00ff:fe10:0001')/ \
> + UDP(sport=547, dport=546)/ \
> + DHCP6(msgtype=7, trid=0x010203)/ \
> + DHCP6OptClientId(duid=DUID_LL(lladdr='${src_mac}'))/ \
> +
> DHCP6OptServerId(duid=DUID_LL(lladdr='00:00:00:10:00:01'))/ \
> + DHCP6OptStatusCode(statuscode=0)"
> +
> + reply=$(fmt_pkt "${rep_scapy}")
> + echo $reply | trim_zeros >> $inport.expected
> +
> + as hv1 ovs-appctl netdev-dummy/receive hv1-vif$inport $request
> + OVS_WAIT_UNTIL([test $n_resume = `cat ofctl_monitor*.log | grep -c
> NXT_RESUME`])
> + n_resume=$((n_resume + 1))
> +}
> +
> +check_packets() {
> + local port=$1
> +
> + $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif$port-tx.pcap |
> trim_zeros > $port.packets
> + # Skipping UDP checksum
> + cat $port.expected | cut -c 1-120,125- > expout
> + AT_CHECK([cat $port.packets | cut -c 1-120,125- ], [0], [expout])
> +
> + rm $port.packets
> + rm $port.expected
> +}
> +
> +check_empty_packets() {
> + local port=$1
> +
> + $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif$port-tx.pcap |
> trim_zeros > $port.packets
> + AT_CHECK([cat $port.packets], [0], [])
> +
> + rm $port.packets
> }
>
> AT_CAPTURE_FILE([ofctl_monitor0.log])
> @@ -7381,23 +7437,31 @@ AT_CAPTURE_FILE([sbflows])
> echo "------ hv1 dump ----------"
> as hv1 ovs-ofctl dump-flows br-int
>
> +# Send DHCPv6 packet on ls2-lp1. native DHCPv6 is disabled on this port.
> +# There should be no DHCPv6 reply from ovn-controller and the request packet
> +# should be received by ls2-lp2.
> +
> +src_mac="f0:00:00:00:00:03"
> +src_lla="fe80::f200:00ff:fe00:0003"
> +test_dhcpv6 3 $src_mac $src_lla 1 0 "" "" 4
> +
> +# vif3-tx.pcap should not have received the DHCPv6 reply packet
> +check_empty 3
> +
> +# vif4-tx.pcap should have received the DHCPv6 request packet
> +check_packets 4
> +
> src_mac="f0:00:00:00:00:01"
> src_lla="fe80::f200:00ff:fe00:0001"
> offer_ip="ae70::4"
> -test_dhcpv6 1 $src_mac $src_lla 1 $offer_ip "" ""
>
> -# NXT_RESUMEs should be 1.
> -OVS_WAIT_UNTIL([test 1 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
> +test_dhcpv6 1 $src_mac $src_lla 1 $offer_ip "" ""
> +check_packets 1
>
> -$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif1-tx.pcap | trim_zeros >
> 1.packets
> -# cat 1.expected | trim_zeros > expout
> -cat 1.expected | cut -c -120 > expout
> -AT_CHECK([cat 1.packets | cut -c -120], [0], [expout])
> -# Skipping the UDP checksum
> -cat 1.expected | cut -c 125- > expout
> -AT_CHECK([cat 1.packets | cut -c 125-], [0], [expout])
> +reset_pcap_file hv1-vif1 hv1/vif1
>
> -rm 1.expected
> +test_dhcpv6_release 1 $src_mac $src_lla $offer_ip
> +check_packets 1
>
> # Send invalid packet on ls1-lp2. ovn-controller should resume the packet
> # without any modifications and the packet should be received by ls1-lp1.
> @@ -7414,70 +7478,29 @@ offer_ip="ae70::5"
>
> test_dhcpv6 2 $src_mac $src_lla 16 0 "" "" 1 1
>
> -# NXT_RESUMEs should be 2.
> -OVS_WAIT_UNTIL([test 2 = `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
> -AT_CHECK([cat 2.packets], [0], [])
> +check_empty 2
>
> # vif1-tx.pcap should have received the DHCPv6 (invalid) request packet
> -$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif1-tx.pcap | trim_zeros >
> 1.packets
> -cat 1.expected > expout
> -AT_CHECK([cat 1.packets], [0], [expout])
> -
> -# Send DHCPv6 packet on ls2-lp1. native DHCPv6 is disabled on this port.
> -# There should be no DHCPv6 reply from ovn-controller and the request packet
> -# should be received by ls2-lp2.
> -
> -src_mac="f0:00:00:00:00:03"
> -src_lla="fe80::f200:00ff:fe00:0003"
> -test_dhcpv6 3 $src_mac $src_lla 1 0 "" "" 4
> -
> -# NXT_RESUMEs should be 2 only.
> -OVS_WAIT_UNTIL([test 2 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
> -
> -# vif3-tx.pcap should not have received the DHCPv6 reply packet
> -$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif3-tx.pcap | trim_zeros >
> 3.packets
> -AT_CHECK([cat 3.packets], [0], [])
> -
> -# vif4-tx.pcap should have received the DHCPv6 request packet
> -$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif4-tx.pcap | trim_zeros >
> 4.packets
> -cat 4.expected > expout
> -AT_CHECK([cat 4.packets], [0], [expout])
> +check_packets 1
>
> # Send DHCPv6 packet on ls1-lp3. native DHCPv6 works as stateless mode for
> this port.
> # The DHCPv6 reply shouldn't contain offer_ip.
> src_mac="f0:00:00:00:00:22"
> src_lla="fe80::f200:00ff:fe00:0022"
> reset_pcap_file hv1-vif5 hv1/vif5
> -test_dhcpv6 5 $src_mac $src_lla 1 1 "" "" 5
>
> -# 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/vif5-tx.pcap | trim_zeros >
> 5.packets
> -# Skipping the UDP checksum
> -cat 5.expected | cut -c 1-120,125- > expout
> -AT_CHECK([cat 5.packets | cut -c 1-120,125- ], [0], [expout])
> +test_dhcpv6 5 $src_mac $src_lla 1 1 "" "" 5
> +check_packets 5
>
> # Send DHCPv6 information request (code 11) on ls1-lp3. The DHCPv6 reply
> # shouldn't contain offer_ip
> src_mac="f0:00:00:00:00:22"
> src_lla="fe80::f200:00ff:fe00:0022"
> reset_pcap_file hv1-vif5 hv1/vif5
> -rm -f 5.expected
> -test_dhcpv6 5 $src_mac $src_lla 11 1 "" "" 5
>
> -# 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/vif5-tx.pcap |
> -trim_zeros > 5.packets
> -# Skipping the UDP checksum
> -cat 5.expected | cut -c 1-120,125- > expout
> -AT_CHECK([cat 5.packets | cut -c 1-120,125- ], [0], [expout])
> +test_dhcpv6 5 $src_mac $src_lla 11 1 "" "" 5
> +check_packets 5
>
> ovn-nbctl --all destroy dhcp-option
> d1="$(ovn-nbctl create DHCP_Options cidr="ae70\:\:/64")"
> @@ -7494,26 +7517,22 @@ src_lla="fe80::f200:00ff:fe00:0002"
> offer_ip="ae70::5"
>
> test_dhcpv6 2 $src_mac $src_lla 1 $offer_ip "bootfile_name_alt" ""
> -# NXT_RESUMEs should be 5.
> -OVS_WAIT_UNTIL([test 5 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
> +check_packets 2
>
> -# 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
> +
> +test_dhcpv6_release 2 $src_mac $src_lla $offer_ip
> +check_packets 2
>
> reset_pcap_file hv1-vif2 hv1/vif2
> -rm 2.packets 2.expected
>
> test_dhcpv6 2 $src_mac $src_lla 1 $offer_ip "bootfile_name" ""
> -# NXT_RESUMEs should be 6.
> -OVS_WAIT_UNTIL([test 6 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
> +check_packets 2
> +
> +reset_pcap_file hv1-vif2 hv1/vif2
>
> -$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])
> +test_dhcpv6_release 2 $src_mac $src_lla $offer_ip
> +check_packets 2
>
> ovn-nbctl --all destroy dhcp-option
> d1="$(ovn-nbctl create DHCP_Options cidr="ae70\:\:/64")"
> @@ -7523,15 +7542,14 @@ ovn-nbctl dhcp-options-set-options $d1 \
> ovn-nbctl --wait=hv lsp-set-dhcpv6-options ls1-lp2 ${d1}
>
> reset_pcap_file hv1-vif2 hv1/vif2
> -rm 2.packets 2.expected
>
> test_dhcpv6 2 $src_mac $src_lla 1 $offer_ip "" "ovn.org"
> -# NXT_RESUMEs should be 7.
> -OVS_WAIT_UNTIL([test 7 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
> +check_packets 2
> +
> +reset_pcap_file hv1-vif2 hv1/vif2
>
> -$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])
> +test_dhcpv6_release 2 $src_mac $src_lla $offer_ip
> +check_packets 2
>
> OVN_CLEANUP([hv1])
>
> --
> 2.41.0
>
> _______________________________________________
> dev mailing list
> [email protected]
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev