Modifies the rule responsible for dropping the MLF_LOCAL_ONLY packets
to only drop them if the MLF_KEEP_RA bit flag is not there.

This does also include the addition of MLF_KEEP_RA bitflag applied
if a router announcement is being sent from either a gateway
or distributed router.

This is part of an ongoing unnumbered BGP effort.
Backport specific patch for v24.03.

Signed-off-by: MJ Ponsonby <[email protected]>
---
 controller/physical.c        |   3 +-
 controller/pinctrl.c         |  11 ++-
 include/ovn/logical-fields.h |   3 +
 ovn-architecture.7.xml       |   4 +-
 tests/ovn.at                 | 152 +++++++++++++++++++++++++++++++++++
 5 files changed, 169 insertions(+), 4 deletions(-)

diff --git a/controller/physical.c b/controller/physical.c
index 0073151f8..0b80788fe 100644
--- a/controller/physical.c
+++ b/controller/physical.c
@@ -1843,7 +1843,8 @@ consider_port_binding(struct ovsdb_idl_index 
*sbrec_port_binding_by_name,
             put_drop(debug, OFTABLE_CHECK_LOOPBACK, ofpacts_p);
             match_outport_dp_and_port_keys(&match, dp_key, port_key);
             match_set_reg_masked(&match, MFF_LOG_FLAGS - MFF_REG0,
-                                 MLF_LOCAL_ONLY, MLF_LOCAL_ONLY);
+                                 MLF_LOCAL_ONLY,
+                                 MLF_LOCAL_ONLY | MLF_KEEP_RA);
             ofctrl_add_flow(flow_table, OFTABLE_CHECK_LOOPBACK, 160,
                             binding->header_.uuid.parts[0], &match,
                             ofpacts_p, &binding->header_.uuid);
diff --git a/controller/pinctrl.c b/controller/pinctrl.c
index 8352e5c3c..d41539042 100644
--- a/controller/pinctrl.c
+++ b/controller/pinctrl.c
@@ -3684,6 +3684,7 @@ struct ipv6_ra_state {
     struct ipv6_ra_config *config;
     int64_t port_key;
     int64_t metadata;
+    bool preserved;
     bool delete_me;
 };
 
@@ -4014,6 +4015,9 @@ ipv6_ra_send(struct rconn *swconn, struct ipv6_ra_state 
*ra)
     put_load(dp_key, MFF_LOG_DATAPATH, 0, 64, &ofpacts);
     put_load(port_key, MFF_LOG_INPORT, 0, 32, &ofpacts);
     put_load(1, MFF_LOG_FLAGS, MLF_LOCAL_ONLY_BIT, 1, &ofpacts);
+    if (ra->preserved) {
+        put_load(1, MFF_LOG_FLAGS, MLF_KEEP_RA_BIT, 1, &ofpacts);
+    }
     struct ofpact_resubmit *resubmit = ofpact_put_RESUBMIT(&ofpacts);
     resubmit->in_port = OFPP_CONTROLLER;
     resubmit->table_id = OFTABLE_LOG_INGRESS_PIPELINE;
@@ -4124,8 +4128,11 @@ prepare_ipv6_ras(const struct shash 
*local_active_ports_ras,
          * router port is connected to. The RA is injected
          * into that logical switch port.
          */
-        ra->port_key = peer->tunnel_key;
-        ra->metadata = peer->datapath->tunnel_key;
+        ra->port_key  = peer->tunnel_key;
+        ra->metadata  = peer->datapath->tunnel_key;
+        ra->preserved = (!strcmp(pb->type,"l2gateway") ||
+                        !strcmp(pb->type,"l3gateway") ||
+                        !strcmp(pb->type,"chassisredirect"));
         ra->delete_me = false;
 
         /* pinctrl_handler thread will send the IPv6 RAs. */
diff --git a/include/ovn/logical-fields.h b/include/ovn/logical-fields.h
index bcd3fd1f9..77029805c 100644
--- a/include/ovn/logical-fields.h
+++ b/include/ovn/logical-fields.h
@@ -87,6 +87,7 @@ enum mff_log_flags_bits {
     MLF_LOCALNET_BIT = 15,
     MLF_RX_FROM_TUNNEL_BIT = 16,
     MLF_ICMP_SNAT_BIT = 17,
+    MLF_KEEP_RA_BIT = 18,
 };
 
 /* MFF_LOG_FLAGS_REG flag assignments */
@@ -142,6 +143,8 @@ enum mff_log_flags {
     MLF_RX_FROM_TUNNEL = (1 << MLF_RX_FROM_TUNNEL_BIT),
 
     MLF_ICMP_SNAT = (1 << MLF_ICMP_SNAT_BIT),
+
+    MLF_KEEP_RA = (1 << MLF_KEEP_RA_BIT),
 };
 
 /* OVN logical fields
diff --git a/ovn-architecture.7.xml b/ovn-architecture.7.xml
index bfd8680ce..c6909445f 100644
--- a/ovn-architecture.7.xml
+++ b/ovn-architecture.7.xml
@@ -1546,7 +1546,9 @@
       <p>
         Table 41 matches and drops packets for which the logical input and
         output ports are the same and the MLF_ALLOW_LOOPBACK flag is not
-        set. It also drops MLF_LOCAL_ONLY packets directed to a localnet port.
+        set. It also drops MLF_LOCAL_ONLY packets directed to a localnet port,
+        provided they aren't RAs sent from a gateway or distributed router
+        which is checked via the presence of the bitflag MLF_KEEP_RA.
         It resubmits other packets to table 42.
       </p>
     </li>
diff --git a/tests/ovn.at b/tests/ovn.at
index e010a1acb..fabb5c333 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -17014,6 +17014,158 @@ OVN_CLEANUP([hv1],[hv2])
 AT_CLEANUP
 ])
 
+
+OVN_FOR_EACH_NORTHD([
+AT_SETUP([IPv6 periodic gateway RA enabled for localnet adjacent switch ports])
+ovn_start
+
+net_add n1
+sim_add hv1
+sim_add hv2
+as hv1
+check ovs-vsctl add-br br-phys
+check ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys
+ovn_attach n1 br-phys 192.168.0.2
+as hv2
+check ovs-vsctl add-br br-phys
+check ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys
+ovn_attach n1 br-phys 192.168.0.3
+
+check ovn-nbctl lr-add ro -- set Logical_Router ro options:chassis="hv1"
+check ovn-nbctl lrp-add ro ro-sw 00:00:00:00:00:01 aef0:0:0:0:0:0:0:1/64
+
+check ovn-nbctl ls-add sw
+check ovn-nbctl lsp-add sw ln
+check ovn-nbctl lsp-set-addresses ln unknown
+check ovn-nbctl lsp-set-type ln localnet
+check ovn-nbctl lsp-set-options ln network_name=phys
+
+check ovn-nbctl lsp-add sw sw-ro
+check ovn-nbctl lsp-set-type sw-ro router
+check ovn-nbctl lsp-set-options sw-ro router-port=ro-sw
+check ovn-nbctl lsp-set-addresses sw-ro 00:00:00:00:00:01
+check ovn-nbctl lsp-add sw sw-p1
+check ovn-nbctl lsp-set-addresses sw-p1 "00:00:00:00:00:02 aef0::200:ff:fe00:2"
+check ovn-nbctl lsp-add sw sw-p2
+check ovn-nbctl lsp-set-addresses sw-p2 "00:00:00:00:00:03 aef0::200:ff:fe00:3"
+
+AT_CHECK([ovn-sbctl get Port_Binding ro-sw type | tr -d '\n'],[0],[l3gateway])
+
+check ovn-nbctl set Logical_Router_Port ro-sw 
ipv6_ra_configs:send_periodic=true
+check ovn-nbctl set Logical_Router_Port ro-sw 
ipv6_ra_configs:address_mode=slaac
+check ovn-nbctl set Logical_Router_Port ro-sw ipv6_ra_configs:max_interval=1
+check ovn-nbctl set Logical_Router_Port ro-sw ipv6_ra_configs:min_interval=1
+
+for i in 1 2 ; do
+    as hv$i
+    check ovs-vsctl -- add-port br-int hv$i-vif1 -- \
+        set interface hv$i-vif1 external-ids:iface-id=sw-p$i \
+        options:tx_pcap=hv$i/vif1-tx.pcap \
+        options:rxq_pcap=hv$i/vif1-rx.pcap \
+        ofport-request=1
+done
+
+wait_for_ports_up
+
+construct_expected_ra() {
+    local src_mac=000000000001
+    local dst_mac=333300000001
+    local src_addr=fe80000000000000020000fffe000001
+    local dst_addr=ff020000000000000000000000000001
+
+    local mtu=$1
+    local ra_mo=$2
+    local rdnss=$3
+    local dnssl=$4
+    local route_info=$5
+    local ra_prefix_la=$6
+
+    local slla=0101${src_mac}
+    local mtu_opt=""
+    if test $mtu != 0; then
+        mtu_opt=05010000${mtu}
+    fi
+    shift 6
+
+    local prefix=""
+    while [[ $# -gt 0 ]] ; do
+        local size=$1
+        local net=$2
+        
prefix=${prefix}0304${size}${ra_prefix_la}ffffffffffffffff00000000${net}
+        shift 2
+    done
+
+    local rdnss_opt=""
+    if test $rdnss != 0; then
+        rdnss_opt=19030000ffffffff${rdnss}
+    fi
+    local dnssl_opt=""
+    if test $dnssl != 0; then
+        dnssl_opt=1f030000ffffffff${dnssl}
+    fi
+    local route_info_opt=""
+    if test $route_info != 0; then
+        route_info_opt=${route_info}
+    fi
+
+    local 
ra=ff${ra_mo}ffff0000000000000000${slla}${mtu_opt}${prefix}${rdnss_opt}${dnssl_opt}${route_info_opt}
+    local icmp=8600XXXX${ra}
+
+    local ip_len=$(expr ${#icmp} / 2)
+    ip_len=$(echo "$ip_len" | awk '{printf "%0.4x\n", $0}')
+
+    local ip=60000000${ip_len}3aff${src_addr}${dst_addr}${icmp}
+    local eth=${dst_mac}${src_mac}86dd${ip}
+    local packet=${eth}
+    echo $packet >> expected
+}
+
+ra_received() {
+    $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" $1 | sed '/^ffffffffffff/d' | 
wc -l
+}
+
+ra_test() {
+    interface=$1
+    shift 1
+    construct_expected_ra $@
+    intname="$interface"
+
+    for i in hv1 hv2 ; do
+        if echo "$interface" | grep -q -v "br"; then
+            intname="$i-$interface"
+        fi
+        echo $intname
+        as $i reset_pcap_file $intname $i/$interface
+
+        OVS_WAIT_WHILE([test 0 = $(ra_received $i/$interface-tx.pcap)])
+
+        $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" $i/$interface-tx.pcap > 
packets
+        sed -i '/^ffffffffffff/d' packets
+
+        cat expected | cut -c -112 > expout
+        AT_CHECK([head -1 packets | cut -c -112], [0], [expout])
+
+        # Skip ICMPv6 checksum.
+        cat expected | cut -c 117- > expout
+        AT_CHECK([head -1 packets | cut -c 117-], [0], [expout])
+
+        rm -f packets
+        as $i reset_pcap_file $intname $i/$interface
+    done
+
+    rm -f expected
+}
+
+# check that RAs are sent
+ra_test vif1 0 00 0 0 0 c0 40 aef00000000000000000000000000000
+
+# check that RAs are recived on br-phys
+ra_test br-phys 0 00 0 0 0 c0 40 aef00000000000000000000000000000
+
+OVN_CLEANUP([hv1],[hv2])
+AT_CLEANUP
+])
+
 OVN_FOR_EACH_NORTHD([
 AT_SETUP([ACL reject rule test])
 AT_KEYWORDS([acl-reject])
-- 
2.43.0

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to