Restrict use of the unspecified source addresses (:: and 0.0.0.0) to
traffic necessary to obtain an IP address. DHCP discovery messages for
the IPv4 case, and ICMP6 types necessary for duplicate address detection
for IPv6.

This breaks the existing ovn -- portsecurity : 3 HVs, 1 LS, 3 lports/HV
test since it tests sourcing IPv6 packets from the unspecified address
with and invalid ICMPv6 type (0). Modified this test should be extended
to verify ICMPv6 types for DAD are permitted, and other IPv6 traffic
sourced from the unspecified address are dropped.
---
 ovn/northd/ovn-northd.c | 37 +++++++++++++++++++++++++++++++++----
 tests/ovn.at            | 22 +++++++++++++++++++++-
 2 files changed, 54 insertions(+), 5 deletions(-)

diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c
index 44e9430..f59faa2 100644
--- a/ovn/northd/ovn-northd.c
+++ b/ovn/northd/ovn-northd.c
@@ -1033,12 +1033,16 @@ build_port_security_ipv6_flow(
     ipv6_string_mapped(ip6_str, &lla);
     ds_put_format(match, "%s, ", ip6_str);
 
-    /* Allow ip6.src=:: and ip6.dst=ff00::/8 for ND packets */
-    ds_put_cstr(match, pipeline == P_IN ? "::" : "ff00::/8");
+    /* Allow ip6.dst=ff00::/8 for multicast packets */
+    if (pipeline == P_OUT)
+        ds_put_cstr(match, "ff00::/8, ");
     for(int i = 0; i < n_ipv6_addrs; i++) {
         ipv6_string_mapped(ip6_str, &ipv6_addrs[i].addr);
-        ds_put_format(match, ", %s", ip6_str);
+        ds_put_format(match, "%s, ", ip6_str);
     }
+    /* Replace ", " by "}". */
+    ds_chomp(match, ' ');
+    ds_chomp(match, ',');
     ds_put_cstr(match, "}");
 }
 
@@ -1174,8 +1178,19 @@ build_port_security_ip(enum ovn_pipeline pipeline, 
struct ovn_port *op,
         if (ps.n_ipv4_addrs) {
             struct ds match = DS_EMPTY_INITIALIZER;
             if (pipeline == P_IN) {
+                /* Permit use of the unspecified address for DHCP discovery */
+                struct ds dhcp_match = DS_EMPTY_INITIALIZER;
+                ds_put_format(&dhcp_match, "inport == %s"
+                              " && eth.src == "ETH_ADDR_FMT
+                              " && ip4.src == 0.0.0.0"
+                              " && ip4.dst == 255.255.255.255"
+                              " && udp.src == 68 && udp.dst == 67", 
op->json_key,
+                              ETH_ADDR_ARGS(ps.ea));
+                ovn_lflow_add(lflows, op->od, stage, 90,
+                              ds_cstr(&dhcp_match), "next;");
+                ds_destroy(&dhcp_match);
                 ds_put_format(&match, "inport == %s && eth.src == "ETH_ADDR_FMT
-                              " && ip4.src == {0.0.0.0, ", op->json_key,
+                              " && ip4.src == {", op->json_key,
                               ETH_ADDR_ARGS(ps.ea));
             } else {
                 ds_put_format(&match, "outport == %s && eth.dst == 
"ETH_ADDR_FMT
@@ -1219,6 +1234,20 @@ build_port_security_ip(enum ovn_pipeline pipeline, 
struct ovn_port *op,
 
         if (ps.n_ipv6_addrs) {
             struct ds match = DS_EMPTY_INITIALIZER;
+            if (pipeline == P_IN) {
+                /* Permit use of unspecified address for duplicate address
+                 * detection */
+                struct ds dad_match = DS_EMPTY_INITIALIZER;
+                ds_put_format(&dad_match, "inport == %s"
+                              " && eth.src == "ETH_ADDR_FMT
+                              " && ip6.src == ::"
+                              " && ip6.dst == ff02::/16"
+                              " && icmp6.type == {131, 135, 143}", 
op->json_key,
+                              ETH_ADDR_ARGS(ps.ea));
+                ovn_lflow_add(lflows, op->od, stage, 90,
+                              ds_cstr(&dad_match), "next;");
+                ds_destroy(&dad_match);
+            }
             ds_put_format(&match, "%s == %s && %s == "ETH_ADDR_FMT"",
                           port_direction, op->json_key,
                           pipeline == P_IN ? "eth.src" : "eth.dst",
diff --git a/tests/ovn.at b/tests/ovn.at
index cc5c468..011472c 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -1786,6 +1786,19 @@ test_ipv6() {
     done
 }
 
+# ipv6 icmp packet
+test_icmpv6() {
+    local inport=$1 src_mac=$2 dst_mac=$3 src_ip=$4 dst_ip=$5 icmp_type=$6
+    local 
packet=${dst_mac}${src_mac}86dd6000000000083aff${src_ip}${dst_ip}${icmp_type}00000000000000
+    shift; shift; shift; shift; shift; shift
+    hv=`vif_to_hv $inport`
+    as $hv ovs-appctl netdev-dummy/receive vif$inport $packet
+    #as $hv ovs-appctl ofproto/trace br-int in_port=$inport $packet
+    for outport; do
+        echo $packet | trim_zeros >> $outport.expected
+    done
+}
+
 ip_to_hex() {
     printf "%02x%02x%02x%02x" "$@"
 }
@@ -1923,8 +1936,15 @@ for i in 1 2 3; do
     sip=fe80000000000000ea2aeafffe2800${i}3
     test_ipv6 ${i}3 f00000000${i}${i}3 f00000000021 $sip $tip 21
 
+    # Test ICMPv6 MLD reports (v1 and v2) and NS for DAD
     sip=00000000000000000000000000000000
-    test_ipv6 ${i}3 f00000000${i}${i}3 f00000000021 $sip $tip 21
+    test_icmpv6 ${i}3 f00000000${i}${i}3 f00000000021 $sip 
ff020000000000000000000000160000 83 21
+    test_icmpv6 ${i}3 f00000000${i}${i}3 f00000000021 $sip 
ff020000000000000000000000160000 8f 21
+    test_icmpv6 ${i}3 f00000000${i}${i}3 f00000000021 $sip 
ff0200000000000000ea2aeafffe2800 87 21
+    # Traffic to non-multicast traffic should be dropped
+    test_icmpv6 ${i}3 f00000000${i}${i}3 f00000000021 $sip $tip 83
+    # Traffic of other ICMPv6 types should be dropped
+    test_icmpv6 ${i}3 f00000000${i}${i}3 f00000000021 $sip 
ff020000000000000000000000160000 80
 
     # should be dropped
     sip=ae80000000000000ea2aeafffe2800aa
-- 
2.1.4

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to