Re: [ovs-dev] [PATCH ovn] pinctrl: Reply with correct destination for ICMPv6 RA packets
I merged this to main and all branches back to 22.03. Thanks Ales and Brian! On 9/19/23 14:32, Mark Michelson wrote: Thanks Ales, Acked-by: Mark Michelson On 9/15/23 08:15, Ales Musil wrote: When client sends RS we reply with RA to the source address, however the client is allowed to send RS with unspecified source address ("::"). In that case we would send the RA to that empty address which is not correct. According to RFC 2461 [0] the server is allowed to reply to the source address directly only if the address isn't unspecified: A router MAY choose to unicast the response directly to the soliciting host's address (if the solicitation's source address is not the unspecified address) Make sure we change the source for all noes address when it is unspecified. [0] https://www.ietf.org/rfc/rfc2461.txt Reported-at: https://issues.redhat.com/browse/FDP-43 Signed-off-by: Ales Musil --- controller/pinctrl.c | 6 ++ tests/ovn.at | 230 +-- 2 files changed, 116 insertions(+), 120 deletions(-) diff --git a/controller/pinctrl.c b/controller/pinctrl.c index ff5a3444c..3c1cecfde 100644 --- a/controller/pinctrl.c +++ b/controller/pinctrl.c @@ -6226,6 +6226,12 @@ pinctrl_handle_put_nd_ra_opts( /* Set the IPv6 payload length and calculate the ICMPv6 checksum. */ struct ovs_16aligned_ip6_hdr *nh = dp_packet_l3(&pkt_out); + + /* Set the source to "ff02::1" if the original source is "::". */ + if (!memcmp(&nh->ip6_src, &in6addr_any, sizeof in6addr_any)) { + memcpy(&nh->ip6_src, &in6addr_all_hosts, sizeof in6addr_all_hosts); + } + nh->ip6_plen = htons(userdata->size); struct ovs_ra_msg *ra = dp_packet_l4(&pkt_out); ra->icmph.icmp6_cksum = 0; diff --git a/tests/ovn.at b/tests/ovn.at index e127530f6..34c3eb06f 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -12643,76 +12643,122 @@ ovs-vsctl -- add-port br-int hv1-vif3 -- \ wait_for_ports_up check ovn-nbctl --wait=hv sync +n_resume=1 + # Make sure that ovn-controller has installed the corresponding OF Flow. OVS_WAIT_UNTIL([test 1 = `as hv1 ovs-ofctl dump-flows br-int | grep -c "ipv6_dst=ff02::2,nw_ttl=255,icmp_type=133,icmp_code=0"`]) # This shell function sends a Router Solicitation packet. -# test_ipv6_ra INPORT SRC_MAC SRC_LLA ADDR_MODE MTU RA_PREFIX_OPT RDNSS DNSSL ROUTE_INFO +# test_ipv6_ra INPORT SRC_MAC SRC_LLA RA_OPT MTU PREFIX RDNSS DNSSL ROUTES test_ipv6_ra() { - local inport=$1 src_mac=$2 src_lla=$3 addr_mode=$4 mtu=$5 prefix_opt=$6 - local rdnss=$7 dnssl=$8 route_info=$9 - local request=0002${src_mac}86dd60103aff${src_lla}ff02000285000efc0101${src_mac} + local inport=$1 src_mac=$2 src_ip=$3 ra=$4 mtu=$5 prefix=$6 + local rdnss=$7 dnssl=$8 routes=$9 - local len=24 - local mtu_opt="" - if test $mtu != 0; then - len=`expr $len + 8` - mtu_opt=0501${mtu} + local request=$(fmt_pkt "Ether(dst='33:33:00:00:00:02', src='${src_mac}')/ \ + IPv6(dst='ff02::2', src='${src_ip}')/ \ + ICMPv6ND_RS()/ \ + ICMPv6NDOptSrcLLAddr(lladdr='${src_mac}')") + + local reply_dst=$src_ip + if test "${reply_dst}" = "::"; then + reply_dst="ff02::1" fi - if test ${#rdnss} != 0; then - len=`expr $len + ${#rdnss} / 2` + local rep_scapy="Ether(dst='${src_mac}', src='fa:16:3e:00:00:01')/ \ + IPv6(dst='${reply_dst}', src='fe80::f816:3eff:fe00:1')/ \ + ${ra}/ \ + ICMPv6NDOptSrcLLAddr(lladdr='fa:16:3e:00:00:01')" + + if test "${mtu}" != "0"; then + rep_scapy="${rep_scapy}/ICMPv6NDOptMTU(mtu=${mtu})" + fi + + if test -n "${rdnss}"; then + rep_scapy="${rep_scapy}/ICMPv6NDOptRDNSS(dns=[['${rdnss}']])" fi - if test ${#dnssl} != 0; then - len=`expr $len + ${#dnssl} / 2` + if test -n "${dnssl}"; then + rep_scapy="${rep_scapy}/ICMPv6NDOptDNSSL(searchlist=[['${dnssl}']])" fi - if test ${#route_info} != 0; then - len=`expr $len + ${#route_info} / 2` + if test -n "${routes}"; then + rep_scapy="${rep_scapy}/${routes}" fi - if test ${#prefix_opt} != 0; then - prefix_opt=${prefix_opt}fdad12345678 - len=`expr $len + ${#prefix_opt} / 2` + if test -n "${prefix}"; then + local a_flag=$(echo $ra | grep -vc "M=1") + rep_scapy="${rep_scapy}/ICMPv6NDOptPrefixInfo(prefix='${prefix}', A=${a_flag})" fi - len=$(printf "%x" $len) - local lrp_mac=fa163e01 - local lrp_lla=fe80f8163efffe01 - local reply=${src_mac}${lrp_mac}86dd60${len}3aff${lrp_lla}${src_lla}8600ff${addr_mode}0101${lrp_mac}${mtu_opt}${rdnss}${dnssl}${route_info}${prefix_opt} + local reply=$(fmt_pkt "${rep_scapy}") echo $reply >> $inp
Re: [ovs-dev] [PATCH ovn] pinctrl: Reply with correct destination for ICMPv6 RA packets
Thanks Ales, Acked-by: Mark Michelson On 9/15/23 08:15, Ales Musil wrote: When client sends RS we reply with RA to the source address, however the client is allowed to send RS with unspecified source address ("::"). In that case we would send the RA to that empty address which is not correct. According to RFC 2461 [0] the server is allowed to reply to the source address directly only if the address isn't unspecified: A router MAY choose to unicast the response directly to the soliciting host's address (if the solicitation's source address is not the unspecified address) Make sure we change the source for all noes address when it is unspecified. [0] https://www.ietf.org/rfc/rfc2461.txt Reported-at: https://issues.redhat.com/browse/FDP-43 Signed-off-by: Ales Musil --- controller/pinctrl.c | 6 ++ tests/ovn.at | 230 +-- 2 files changed, 116 insertions(+), 120 deletions(-) diff --git a/controller/pinctrl.c b/controller/pinctrl.c index ff5a3444c..3c1cecfde 100644 --- a/controller/pinctrl.c +++ b/controller/pinctrl.c @@ -6226,6 +6226,12 @@ pinctrl_handle_put_nd_ra_opts( /* Set the IPv6 payload length and calculate the ICMPv6 checksum. */ struct ovs_16aligned_ip6_hdr *nh = dp_packet_l3(&pkt_out); + +/* Set the source to "ff02::1" if the original source is "::". */ +if (!memcmp(&nh->ip6_src, &in6addr_any, sizeof in6addr_any)) { +memcpy(&nh->ip6_src, &in6addr_all_hosts, sizeof in6addr_all_hosts); +} + nh->ip6_plen = htons(userdata->size); struct ovs_ra_msg *ra = dp_packet_l4(&pkt_out); ra->icmph.icmp6_cksum = 0; diff --git a/tests/ovn.at b/tests/ovn.at index e127530f6..34c3eb06f 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -12643,76 +12643,122 @@ ovs-vsctl -- add-port br-int hv1-vif3 -- \ wait_for_ports_up check ovn-nbctl --wait=hv sync +n_resume=1 + # Make sure that ovn-controller has installed the corresponding OF Flow. OVS_WAIT_UNTIL([test 1 = `as hv1 ovs-ofctl dump-flows br-int | grep -c "ipv6_dst=ff02::2,nw_ttl=255,icmp_type=133,icmp_code=0"`]) # This shell function sends a Router Solicitation packet. -# test_ipv6_ra INPORT SRC_MAC SRC_LLA ADDR_MODE MTU RA_PREFIX_OPT RDNSS DNSSL ROUTE_INFO +# test_ipv6_ra INPORT SRC_MAC SRC_LLA RA_OPT MTU PREFIX RDNSS DNSSL ROUTES test_ipv6_ra() { -local inport=$1 src_mac=$2 src_lla=$3 addr_mode=$4 mtu=$5 prefix_opt=$6 -local rdnss=$7 dnssl=$8 route_info=$9 -local request=0002${src_mac}86dd60103aff${src_lla}ff02000285000efc0101${src_mac} +local inport=$1 src_mac=$2 src_ip=$3 ra=$4 mtu=$5 prefix=$6 +local rdnss=$7 dnssl=$8 routes=$9 -local len=24 -local mtu_opt="" -if test $mtu != 0; then -len=`expr $len + 8` -mtu_opt=0501${mtu} +local request=$(fmt_pkt "Ether(dst='33:33:00:00:00:02', src='${src_mac}')/ \ + IPv6(dst='ff02::2', src='${src_ip}')/ \ + ICMPv6ND_RS()/ \ + ICMPv6NDOptSrcLLAddr(lladdr='${src_mac}')") + +local reply_dst=$src_ip +if test "${reply_dst}" = "::"; then +reply_dst="ff02::1" fi -if test ${#rdnss} != 0; then -len=`expr $len + ${#rdnss} / 2` +local rep_scapy="Ether(dst='${src_mac}', src='fa:16:3e:00:00:01')/ \ + IPv6(dst='${reply_dst}', src='fe80::f816:3eff:fe00:1')/ \ + ${ra}/ \ + ICMPv6NDOptSrcLLAddr(lladdr='fa:16:3e:00:00:01')" + +if test "${mtu}" != "0"; then +rep_scapy="${rep_scapy}/ICMPv6NDOptMTU(mtu=${mtu})" +fi + +if test -n "${rdnss}"; then +rep_scapy="${rep_scapy}/ICMPv6NDOptRDNSS(dns=[['${rdnss}']])" fi -if test ${#dnssl} != 0; then -len=`expr $len + ${#dnssl} / 2` +if test -n "${dnssl}"; then +rep_scapy="${rep_scapy}/ICMPv6NDOptDNSSL(searchlist=[['${dnssl}']])" fi -if test ${#route_info} != 0; then -len=`expr $len + ${#route_info} / 2` +if test -n "${routes}"; then +rep_scapy="${rep_scapy}/${routes}" fi -if test ${#prefix_opt} != 0; then -prefix_opt=${prefix_opt}fdad12345678 -len=`expr $len + ${#prefix_opt} / 2` +if test -n "${prefix}"; then +local a_flag=$(echo $ra | grep -vc "M=1") +rep_scapy="${rep_scapy}/ICMPv6NDOptPrefixInfo(prefix='${prefix}', A=${a_flag})" fi -len=$(printf "%x" $len) -local lrp_mac=fa163e01 -local lrp_lla=fe80f8163efffe01 -local reply=${src_mac}${lrp_mac}86dd60${len}3aff${lrp_lla}${src_lla}8600ff${addr_mode}0101${lrp_mac}${mtu_opt}${rdnss}${dnssl}${route_info}${prefix_opt} +local reply=$(fmt_pkt "${rep_scapy}") echo $reply >> $inport.expected as hv1 ovs-appctl netdev-dummy/receive hv1-vif${inport} $request + +OVS_WAI
Re: [ovs-dev] [PATCH ovn] pinctrl: Reply with correct destination for ICMPv6 RA packets
Hi Ales, On 9/15/23 8:15 AM, Ales Musil wrote: When client sends RS we reply with RA to the source address, however the client is allowed to send RS with unspecified source address ("::"). In that case we would send the RA to that empty address which is not correct. According to RFC 2461 [0] the server is allowed to reply to the source address directly only if the address isn't unspecified: A router MAY choose to unicast the response directly to the soliciting host's address (if the solicitation's source address is not the unspecified address) Make sure we change the source for all noes address when it is unspecified. Looks good to me from an RFC (and tcpdump) perspective, just a typo in the commit message (noes -> nodes). -Brian [0] https://www.ietf.org/rfc/rfc2461.txt Reported-at: https://issues.redhat.com/browse/FDP-43 Signed-off-by: Ales Musil --- controller/pinctrl.c | 6 ++ tests/ovn.at | 230 +-- 2 files changed, 116 insertions(+), 120 deletions(-) diff --git a/controller/pinctrl.c b/controller/pinctrl.c index ff5a3444c..3c1cecfde 100644 --- a/controller/pinctrl.c +++ b/controller/pinctrl.c @@ -6226,6 +6226,12 @@ pinctrl_handle_put_nd_ra_opts( /* Set the IPv6 payload length and calculate the ICMPv6 checksum. */ struct ovs_16aligned_ip6_hdr *nh = dp_packet_l3(&pkt_out); + +/* Set the source to "ff02::1" if the original source is "::". */ +if (!memcmp(&nh->ip6_src, &in6addr_any, sizeof in6addr_any)) { +memcpy(&nh->ip6_src, &in6addr_all_hosts, sizeof in6addr_all_hosts); +} + nh->ip6_plen = htons(userdata->size); struct ovs_ra_msg *ra = dp_packet_l4(&pkt_out); ra->icmph.icmp6_cksum = 0; diff --git a/tests/ovn.at b/tests/ovn.at index e127530f6..34c3eb06f 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -12643,76 +12643,122 @@ ovs-vsctl -- add-port br-int hv1-vif3 -- \ wait_for_ports_up check ovn-nbctl --wait=hv sync +n_resume=1 + # Make sure that ovn-controller has installed the corresponding OF Flow. OVS_WAIT_UNTIL([test 1 = `as hv1 ovs-ofctl dump-flows br-int | grep -c "ipv6_dst=ff02::2,nw_ttl=255,icmp_type=133,icmp_code=0"`]) # This shell function sends a Router Solicitation packet. -# test_ipv6_ra INPORT SRC_MAC SRC_LLA ADDR_MODE MTU RA_PREFIX_OPT RDNSS DNSSL ROUTE_INFO +# test_ipv6_ra INPORT SRC_MAC SRC_LLA RA_OPT MTU PREFIX RDNSS DNSSL ROUTES test_ipv6_ra() { -local inport=$1 src_mac=$2 src_lla=$3 addr_mode=$4 mtu=$5 prefix_opt=$6 -local rdnss=$7 dnssl=$8 route_info=$9 -local request=0002${src_mac}86dd60103aff${src_lla}ff02000285000efc0101${src_mac} +local inport=$1 src_mac=$2 src_ip=$3 ra=$4 mtu=$5 prefix=$6 +local rdnss=$7 dnssl=$8 routes=$9 -local len=24 -local mtu_opt="" -if test $mtu != 0; then -len=`expr $len + 8` -mtu_opt=0501${mtu} +local request=$(fmt_pkt "Ether(dst='33:33:00:00:00:02', src='${src_mac}')/ \ + IPv6(dst='ff02::2', src='${src_ip}')/ \ + ICMPv6ND_RS()/ \ + ICMPv6NDOptSrcLLAddr(lladdr='${src_mac}')") + +local reply_dst=$src_ip +if test "${reply_dst}" = "::"; then +reply_dst="ff02::1" fi -if test ${#rdnss} != 0; then -len=`expr $len + ${#rdnss} / 2` +local rep_scapy="Ether(dst='${src_mac}', src='fa:16:3e:00:00:01')/ \ + IPv6(dst='${reply_dst}', src='fe80::f816:3eff:fe00:1')/ \ + ${ra}/ \ + ICMPv6NDOptSrcLLAddr(lladdr='fa:16:3e:00:00:01')" + +if test "${mtu}" != "0"; then +rep_scapy="${rep_scapy}/ICMPv6NDOptMTU(mtu=${mtu})" +fi + +if test -n "${rdnss}"; then +rep_scapy="${rep_scapy}/ICMPv6NDOptRDNSS(dns=[['${rdnss}']])" fi -if test ${#dnssl} != 0; then -len=`expr $len + ${#dnssl} / 2` +if test -n "${dnssl}"; then +rep_scapy="${rep_scapy}/ICMPv6NDOptDNSSL(searchlist=[['${dnssl}']])" fi -if test ${#route_info} != 0; then -len=`expr $len + ${#route_info} / 2` +if test -n "${routes}"; then +rep_scapy="${rep_scapy}/${routes}" fi -if test ${#prefix_opt} != 0; then -prefix_opt=${prefix_opt}fdad12345678 -len=`expr $len + ${#prefix_opt} / 2` +if test -n "${prefix}"; then +local a_flag=$(echo $ra | grep -vc "M=1") +rep_scapy="${rep_scapy}/ICMPv6NDOptPrefixInfo(prefix='${prefix}', A=${a_flag})" fi -len=$(printf "%x" $len) -local lrp_mac=fa163e01 -local lrp_lla=fe80f8163efffe01 -local reply=${src_mac}${lrp_mac}86dd60${len}3aff${lrp_lla}${src_lla}8600ff${addr_mode}0101${lrp_mac}${mtu_opt}${rdnss}${dnssl}${route_info}${prefix_opt} +local reply=$(fmt_pkt "${rep_scapy}") echo $reply >> $inport.expecte