[ovs-dev] [ovs-dev, v2][PATCH] ovn-northd: Restrict use of unspecified source addresses

Dustin Lundquist dustin at null-ptr.net
Fri May 20 19:48:16 UTC 2016


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.

Signed-off-by: Dustin Lundquist <dustin at null-ptr.net>
---
 ovn/northd/ovn-northd.8.xml | 16 ++++++++++++++++
 ovn/northd/ovn-northd.c     | 38 ++++++++++++++++++++++++++++++++++----
 tests/ovn.at                | 24 +++++++++++++++++++++++-
 3 files changed, 73 insertions(+), 5 deletions(-)

diff --git a/ovn/northd/ovn-northd.8.xml b/ovn/northd/ovn-northd.8.xml
index 970c352..2665ed5 100644
--- a/ovn/northd/ovn-northd.8.xml
+++ b/ovn/northd/ovn-northd.8.xml
@@ -160,12 +160,28 @@
           </li>

           <li>
+            Priority 90 flow to allow IPv4 DHCP discovery traffic if it has a
+            valid <code>eth.src</code>. This is necessary since DHCP discovery
+            messages are sent from the unspecified IPv4 address (0.0.0.0) since
+            the IPv4 address has not yet been assigned.
+          </li>
+
+          <li>
             Priority 90 flow to allow IPv6 traffic if it has IPv6 addresses
             which match the <code>inport</code>, valid <code>eth.src</code> and
             valid <code>ip6.src</code> address(es).
           </li>

           <li>
+            Priority 90 flow to allow IPv6 DAD (Duplicate Address Detection)
+            traffic if it has a valid <code>eth.src</code>. This is is
+            necessary since DAD include requires joining an multicast group and
+            sending neighbor solicitations for the newly assigned address. Since
+            no address is yet assigned, these are sent from the unspecified
+            IPv6 address (::).
+          </li>
+
+          <li>
             Priority 80 flow to drop IP (both IPv4 and IPv6) traffic which
             match the <code>inport</code> and valid <code>eth.src</code>.
           </li>
diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c
index 44e9430..ad1f381 100644
--- a/ovn/northd/ovn-northd.c
+++ b/ovn/northd/ovn-northd.c
@@ -1033,12 +1033,17 @@ 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 +1179,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 +1235,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..b93ba0e 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -1786,6 +1786,21 @@ test_ipv6() {
     done
 }

+# test_icmpv6 INPORT  SRC_MAC DST_MAC SRC_IP DST_IP ICMP_TYPE OUTPORT...
+# This function is similar to test_ipv6() except it specifies the ICMPv6 type
+# of the test 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 +1938,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




More information about the dev mailing list