Re: [ovs-dev] [PATCH ovn] pinctrl: Reply with correct destination for ICMPv6 RA packets

2023-10-05 Thread Mark Michelson

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

2023-09-19 Thread Mark Michelson

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

2023-09-15 Thread Brian Haley

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