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]> --- 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
