summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ovn/northd/ovn-northd.8.xml16
-rw-r--r--ovn/northd/ovn-northd.c38
-rw-r--r--tests/ovn.at24
3 files changed, 73 insertions, 5 deletions
diff --git a/ovn/northd/ovn-northd.8.xml b/ovn/northd/ovn-northd.8.xml
index 970c352cd..2665ed542 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 44e9430e4..ad1f38138 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 e6ac1d718..5f224838e 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -1789,6 +1789,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" "$@"
}
@@ -1926,8 +1941,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