diff options
-rw-r--r-- | ovn/northd/ovn-northd.8.xml | 16 | ||||
-rw-r--r-- | ovn/northd/ovn-northd.c | 38 | ||||
-rw-r--r-- | 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 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 |