diff mbox series

[ovs-dev] Suppress periodic RAs for switches attached to localnet

Message ID 20210806221957.3460911-1-ihrachys@redhat.com
State Changes Requested
Headers show
Series [ovs-dev] Suppress periodic RAs for switches attached to localnet | expand

Checks

Context Check Description
ovsrobot/apply-robot success apply and check: success
ovsrobot/github-robot-Build_and_Test success github build: passed
ovsrobot/github-robot-ovn-kubernetes fail github build: failed

Commit Message

Ihar Hrachyshka Aug. 6, 2021, 10:19 p.m. UTC
When a router port is attached to a localnet switch, sending periodic
RAs through localnet port will confuse upstream router by leaking
conflicting router advertisements into datacenter network.

Signed-off-by: Ihar Hrachyshka <ihrachys@redhat.com>
---
 northd/ovn-northd.c |   5 +-
 tests/ovn.at        | 156 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 160 insertions(+), 1 deletion(-)

Comments

Ihar Hrachyshka Aug. 7, 2021, 12:56 a.m. UTC | #1
I'd need some help with ddlog implementation for this patch. The
change in C is primitive but somehow I couldn't figure out how to
replicate it in ddlog. My limited knowledge of the language shows.

If someone has an idea how to replicate, please let me know.

Ihar

On Fri, Aug 6, 2021 at 6:20 PM Ihar Hrachyshka <ihrachys@redhat.com> wrote:
>
> When a router port is attached to a localnet switch, sending periodic
> RAs through localnet port will confuse upstream router by leaking
> conflicting router advertisements into datacenter network.
>
> Signed-off-by: Ihar Hrachyshka <ihrachys@redhat.com>
> ---
>  northd/ovn-northd.c |   5 +-
>  tests/ovn.at        | 156 ++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 160 insertions(+), 1 deletion(-)
>
> diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
> index a0eaa1247..6cd686d12 100644
> --- a/northd/ovn-northd.c
> +++ b/northd/ovn-northd.c
> @@ -10207,7 +10207,10 @@ build_ND_RA_flows_for_lrouter_port(
>
>      if (smap_get_bool(&op->nbrp->ipv6_ra_configs, "send_periodic",
>                        false)) {
> -        copy_ra_to_sb(op, address_mode);
> +        /* Don't leak RAs into datacenter networks. */
> +        if (!op->peer->od->n_localnet_ports) {
> +            copy_ra_to_sb(op, address_mode);
> +        }
>      }
>
>      ds_clear(match);
> diff --git a/tests/ovn.at b/tests/ovn.at
> index 7ae136ad9..22c5ed07c 100644
> --- a/tests/ovn.at
> +++ b/tests/ovn.at
> @@ -13674,6 +13674,162 @@ OVN_CLEANUP([hv1],[hv2])
>  AT_CLEANUP
>  ])
>
> +OVN_FOR_EACH_NORTHD([
> +AT_SETUP([IPv6 periodic RA disabled 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
> +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"
> +
> +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=4
> +check ovn-nbctl set Logical_Router_Port ro-sw ipv6_ra_configs:min_interval=3
> +
> +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
> +
> +OVS_WAIT_UNTIL([test x`ovn-nbctl lsp-get-up sw-p1` = xup])
> +OVS_WAIT_UNTIL([test x`ovn-nbctl lsp-get-up sw-p2` = xup])
> +
> +reset_pcap_file() {
> +    local iface=$1
> +    local pcap_file=$2
> +    ovs-vsctl -- set Interface $iface options:tx_pcap=dummy-tx.pcap \
> +options:rxq_pcap=dummy-rx.pcap
> +    rm -f ${pcap_file}*.pcap
> +    ovs-vsctl -- set Interface $iface options:tx_pcap=${pcap_file}-tx.pcap \
> +options:rxq_pcap=${pcap_file}-rx.pcap
> +
> +}
> +
> +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_test() {
> +    if [[ $1 = 1 ]]; then
> +        shift; construct_expected_ra $@
> +    else
> +        shift; > expected
> +    fi
> +
> +    for i in hv1 hv2 ; do
> +        as $i reset_pcap_file $i-vif1 $i/vif1
> +
> +        OVS_WAIT_WHILE([test 24 = $(wc -c $i/vif1-tx.pcap | cut -d " " -f1)])
> +
> +        $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" $i/vif1-tx.pcap > packets
> +        sed -i '/^ffffffffffff/d' packets
> +
> +        cat expected | cut -c -112 > expout
> +        AT_CHECK([cat packets | cut -c -112], [0], [expout])
> +
> +        # Skip ICMPv6 checksum.
> +        cat expected | cut -c 117- > expout
> +        AT_CHECK([cat packets | cut -c 117-], [0], [expout])
> +
> +        rm -f packets
> +        as $i reset_pcap_file $i-vif1 $i/vif1
> +    done
> +
> +    rm -f expected
> +}
> +
> +# first check that localnet port blocks RAs
> +ra_test 0 0 00 0 0 0 c0 40 aef00000000000000000000000000000
> +
> +# now remove localnet port and check periodic RAs
> +check ovn-nbctl lsp-del ln
> +check ovn-nbctl --wait=hv sync
> +ra_test 1 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.31.1
>
Frode Nordahl Aug. 13, 2021, 2:33 p.m. UTC | #2
On Sat, Aug 7, 2021 at 12:20 AM Ihar Hrachyshka <ihrachys@redhat.com> wrote:
>
> When a router port is attached to a localnet switch, sending periodic
> RAs through localnet port will confuse upstream router by leaking
> conflicting router advertisements into datacenter network.

Do I understand you correctly that you want to suppress RA's on an
entire LS if it has one localnet port? If so, I'm a bit concerned
about this approach as it is a perfectly valid configuration to attach
an instance directly to a LS with a localnet port.

In such a scenario the instance would no longer receive periodic RAs.
While the instance would still be able to solicit its IPv6 prefix,
router and DNS servers on startup, it would not receive any
information should the router address, prefix or DNS server
information change somewhere down the line.

Could we filter this in some other way that does not affect the entire
switch? Or could it be managing and suppressing the RAs is the
responsibility of the physical DC switch/router administrator?
Numan Siddique Aug. 17, 2021, 6:19 p.m. UTC | #3
On Fri, Aug 13, 2021 at 10:33 AM Frode Nordahl
<frode.nordahl@canonical.com> wrote:
>
> On Sat, Aug 7, 2021 at 12:20 AM Ihar Hrachyshka <ihrachys@redhat.com> wrote:
> >
> > When a router port is attached to a localnet switch, sending periodic
> > RAs through localnet port will confuse upstream router by leaking
> > conflicting router advertisements into datacenter network.
>
> Do I understand you correctly that you want to suppress RA's on an
> entire LS if it has one localnet port? If so, I'm a bit concerned
> about this approach as it is a perfectly valid configuration to attach
> an instance directly to a LS with a localnet port.
>
> In such a scenario the instance would no longer receive periodic RAs.
> While the instance would still be able to solicit its IPv6 prefix,
> router and DNS servers on startup, it would not receive any
> information should the router address, prefix or DNS server
> information change somewhere down the line.
>
> Could we filter this in some other way that does not affect the entire
> switch? Or could it be managing and suppressing the RAs is the
> responsibility of the physical DC switch/router administrator?


Agree with Frode.  VIFs associated with logical switches with localnet port
should be served periodic RAs if configured.

I think the right fix would be to make sure that ovn-controller doesn't inject
the periodic RAs to the patch ports connecting to the provider bridges.

If I recall, ovn-controller would inject the periodic RAs only to the local VIFs
which need the periodic RAs.  So ideally it should not leak out of the br-int.

Thanks
Numan


>
> --
> Frode Nordahl
>
> > Signed-off-by: Ihar Hrachyshka <ihrachys@redhat.com>
> > ---
> >  northd/ovn-northd.c |   5 +-
> >  tests/ovn.at        | 156 ++++++++++++++++++++++++++++++++++++++++++++
> >  2 files changed, 160 insertions(+), 1 deletion(-)
> >
> > diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
> > index a0eaa1247..6cd686d12 100644
> > --- a/northd/ovn-northd.c
> > +++ b/northd/ovn-northd.c
> > @@ -10207,7 +10207,10 @@ build_ND_RA_flows_for_lrouter_port(
> >
> >      if (smap_get_bool(&op->nbrp->ipv6_ra_configs, "send_periodic",
> >                        false)) {
> > -        copy_ra_to_sb(op, address_mode);
> > +        /* Don't leak RAs into datacenter networks. */
> > +        if (!op->peer->od->n_localnet_ports) {
> > +            copy_ra_to_sb(op, address_mode);
> > +        }
> >      }
> >
> >      ds_clear(match);
> > diff --git a/tests/ovn.at b/tests/ovn.at
> > index 7ae136ad9..22c5ed07c 100644
> > --- a/tests/ovn.at
> > +++ b/tests/ovn.at
> > @@ -13674,6 +13674,162 @@ OVN_CLEANUP([hv1],[hv2])
> >  AT_CLEANUP
> >  ])
> >
> > +OVN_FOR_EACH_NORTHD([
> > +AT_SETUP([IPv6 periodic RA disabled 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
> > +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"
> > +
> > +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=4
> > +check ovn-nbctl set Logical_Router_Port ro-sw ipv6_ra_configs:min_interval=3
> > +
> > +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
> > +
> > +OVS_WAIT_UNTIL([test x`ovn-nbctl lsp-get-up sw-p1` = xup])
> > +OVS_WAIT_UNTIL([test x`ovn-nbctl lsp-get-up sw-p2` = xup])
> > +
> > +reset_pcap_file() {
> > +    local iface=$1
> > +    local pcap_file=$2
> > +    ovs-vsctl -- set Interface $iface options:tx_pcap=dummy-tx.pcap \
> > +options:rxq_pcap=dummy-rx.pcap
> > +    rm -f ${pcap_file}*.pcap
> > +    ovs-vsctl -- set Interface $iface options:tx_pcap=${pcap_file}-tx.pcap \
> > +options:rxq_pcap=${pcap_file}-rx.pcap
> > +
> > +}
> > +
> > +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_test() {
> > +    if [[ $1 = 1 ]]; then
> > +        shift; construct_expected_ra $@
> > +    else
> > +        shift; > expected
> > +    fi
> > +
> > +    for i in hv1 hv2 ; do
> > +        as $i reset_pcap_file $i-vif1 $i/vif1
> > +
> > +        OVS_WAIT_WHILE([test 24 = $(wc -c $i/vif1-tx.pcap | cut -d " " -f1)])
> > +
> > +        $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" $i/vif1-tx.pcap > packets
> > +        sed -i '/^ffffffffffff/d' packets
> > +
> > +        cat expected | cut -c -112 > expout
> > +        AT_CHECK([cat packets | cut -c -112], [0], [expout])
> > +
> > +        # Skip ICMPv6 checksum.
> > +        cat expected | cut -c 117- > expout
> > +        AT_CHECK([cat packets | cut -c 117-], [0], [expout])
> > +
> > +        rm -f packets
> > +        as $i reset_pcap_file $i-vif1 $i/vif1
> > +    done
> > +
> > +    rm -f expected
> > +}
> > +
> > +# first check that localnet port blocks RAs
> > +ra_test 0 0 00 0 0 0 c0 40 aef00000000000000000000000000000
> > +
> > +# now remove localnet port and check periodic RAs
> > +check ovn-nbctl lsp-del ln
> > +check ovn-nbctl --wait=hv sync
> > +ra_test 1 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.31.1
> >
> > _______________________________________________
> > dev mailing list
> > dev@openvswitch.org
> > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
Ihar Hrachyshka Aug. 24, 2021, 11:23 p.m. UTC | #4
On Tue, Aug 17, 2021 at 2:20 PM Numan Siddique <numans@ovn.org> wrote:
>
> On Fri, Aug 13, 2021 at 10:33 AM Frode Nordahl
> <frode.nordahl@canonical.com> wrote:
> >
> > On Sat, Aug 7, 2021 at 12:20 AM Ihar Hrachyshka <ihrachys@redhat.com> wrote:
> > >
> > > When a router port is attached to a localnet switch, sending periodic
> > > RAs through localnet port will confuse upstream router by leaking
> > > conflicting router advertisements into datacenter network.
> >
> > Do I understand you correctly that you want to suppress RA's on an
> > entire LS if it has one localnet port? If so, I'm a bit concerned
> > about this approach as it is a perfectly valid configuration to attach
> > an instance directly to a LS with a localnet port.
> >
> > In such a scenario the instance would no longer receive periodic RAs.
> > While the instance would still be able to solicit its IPv6 prefix,
> > router and DNS servers on startup, it would not receive any
> > information should the router address, prefix or DNS server
> > information change somewhere down the line.
> >
> > Could we filter this in some other way that does not affect the entire
> > switch? Or could it be managing and suppressing the RAs is the
> > responsibility of the physical DC switch/router administrator?
>
>
> Agree with Frode.  VIFs associated with logical switches with localnet port
> should be served periodic RAs if configured.
>
> I think the right fix would be to make sure that ovn-controller doesn't inject
> the periodic RAs to the patch ports connecting to the provider bridges.
>
> If I recall, ovn-controller would inject the periodic RAs only to the local VIFs
> which need the periodic RAs.  So ideally it should not leak out of the br-int.
>

You are right we shouldn't suppress other RAs. I am sending a new
patch in a sec.

To the point of the mechanism to suppress RAs on localnets, AFAIU the
packet is injected into LS peer port that is plugged into router. From
the controller() action perspective, we don't know where RA will
propagate.

There are two options here:
a) block specifically RAs using corresponding drop rule (dst=ff02:1,
icmp6, code=134...)
b) block all LOCAL_ONLY marked traffic on leaving through localnet port

The latter will also block prefix delegation and BFD messages, which I
believe we should block any way.

I will send (b) in a second but let me know if a more fine grained (a)
option is preferable (perhaps we should have both?)

Cheers,
Ihar


> Thanks
> Numan
>
>
> >
> > --
> > Frode Nordahl
> >
> > > Signed-off-by: Ihar Hrachyshka <ihrachys@redhat.com>
> > > ---
> > >  northd/ovn-northd.c |   5 +-
> > >  tests/ovn.at        | 156 ++++++++++++++++++++++++++++++++++++++++++++
> > >  2 files changed, 160 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
> > > index a0eaa1247..6cd686d12 100644
> > > --- a/northd/ovn-northd.c
> > > +++ b/northd/ovn-northd.c
> > > @@ -10207,7 +10207,10 @@ build_ND_RA_flows_for_lrouter_port(
> > >
> > >      if (smap_get_bool(&op->nbrp->ipv6_ra_configs, "send_periodic",
> > >                        false)) {
> > > -        copy_ra_to_sb(op, address_mode);
> > > +        /* Don't leak RAs into datacenter networks. */
> > > +        if (!op->peer->od->n_localnet_ports) {
> > > +            copy_ra_to_sb(op, address_mode);
> > > +        }
> > >      }
> > >
> > >      ds_clear(match);
> > > diff --git a/tests/ovn.at b/tests/ovn.at
> > > index 7ae136ad9..22c5ed07c 100644
> > > --- a/tests/ovn.at
> > > +++ b/tests/ovn.at
> > > @@ -13674,6 +13674,162 @@ OVN_CLEANUP([hv1],[hv2])
> > >  AT_CLEANUP
> > >  ])
> > >
> > > +OVN_FOR_EACH_NORTHD([
> > > +AT_SETUP([IPv6 periodic RA disabled 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
> > > +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"
> > > +
> > > +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=4
> > > +check ovn-nbctl set Logical_Router_Port ro-sw ipv6_ra_configs:min_interval=3
> > > +
> > > +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
> > > +
> > > +OVS_WAIT_UNTIL([test x`ovn-nbctl lsp-get-up sw-p1` = xup])
> > > +OVS_WAIT_UNTIL([test x`ovn-nbctl lsp-get-up sw-p2` = xup])
> > > +
> > > +reset_pcap_file() {
> > > +    local iface=$1
> > > +    local pcap_file=$2
> > > +    ovs-vsctl -- set Interface $iface options:tx_pcap=dummy-tx.pcap \
> > > +options:rxq_pcap=dummy-rx.pcap
> > > +    rm -f ${pcap_file}*.pcap
> > > +    ovs-vsctl -- set Interface $iface options:tx_pcap=${pcap_file}-tx.pcap \
> > > +options:rxq_pcap=${pcap_file}-rx.pcap
> > > +
> > > +}
> > > +
> > > +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_test() {
> > > +    if [[ $1 = 1 ]]; then
> > > +        shift; construct_expected_ra $@
> > > +    else
> > > +        shift; > expected
> > > +    fi
> > > +
> > > +    for i in hv1 hv2 ; do
> > > +        as $i reset_pcap_file $i-vif1 $i/vif1
> > > +
> > > +        OVS_WAIT_WHILE([test 24 = $(wc -c $i/vif1-tx.pcap | cut -d " " -f1)])
> > > +
> > > +        $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" $i/vif1-tx.pcap > packets
> > > +        sed -i '/^ffffffffffff/d' packets
> > > +
> > > +        cat expected | cut -c -112 > expout
> > > +        AT_CHECK([cat packets | cut -c -112], [0], [expout])
> > > +
> > > +        # Skip ICMPv6 checksum.
> > > +        cat expected | cut -c 117- > expout
> > > +        AT_CHECK([cat packets | cut -c 117-], [0], [expout])
> > > +
> > > +        rm -f packets
> > > +        as $i reset_pcap_file $i-vif1 $i/vif1
> > > +    done
> > > +
> > > +    rm -f expected
> > > +}
> > > +
> > > +# first check that localnet port blocks RAs
> > > +ra_test 0 0 00 0 0 0 c0 40 aef00000000000000000000000000000
> > > +
> > > +# now remove localnet port and check periodic RAs
> > > +check ovn-nbctl lsp-del ln
> > > +check ovn-nbctl --wait=hv sync
> > > +ra_test 1 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.31.1
> > >
> > > _______________________________________________
> > > dev mailing list
> > > dev@openvswitch.org
> > > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
> > _______________________________________________
> > dev mailing list
> > dev@openvswitch.org
> > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
> >
>
diff mbox series

Patch

diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
index a0eaa1247..6cd686d12 100644
--- a/northd/ovn-northd.c
+++ b/northd/ovn-northd.c
@@ -10207,7 +10207,10 @@  build_ND_RA_flows_for_lrouter_port(
 
     if (smap_get_bool(&op->nbrp->ipv6_ra_configs, "send_periodic",
                       false)) {
-        copy_ra_to_sb(op, address_mode);
+        /* Don't leak RAs into datacenter networks. */
+        if (!op->peer->od->n_localnet_ports) {
+            copy_ra_to_sb(op, address_mode);
+        }
     }
 
     ds_clear(match);
diff --git a/tests/ovn.at b/tests/ovn.at
index 7ae136ad9..22c5ed07c 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -13674,6 +13674,162 @@  OVN_CLEANUP([hv1],[hv2])
 AT_CLEANUP
 ])
 
+OVN_FOR_EACH_NORTHD([
+AT_SETUP([IPv6 periodic RA disabled 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
+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"
+
+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=4
+check ovn-nbctl set Logical_Router_Port ro-sw ipv6_ra_configs:min_interval=3
+
+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
+
+OVS_WAIT_UNTIL([test x`ovn-nbctl lsp-get-up sw-p1` = xup])
+OVS_WAIT_UNTIL([test x`ovn-nbctl lsp-get-up sw-p2` = xup])
+
+reset_pcap_file() {
+    local iface=$1
+    local pcap_file=$2
+    ovs-vsctl -- set Interface $iface options:tx_pcap=dummy-tx.pcap \
+options:rxq_pcap=dummy-rx.pcap
+    rm -f ${pcap_file}*.pcap
+    ovs-vsctl -- set Interface $iface options:tx_pcap=${pcap_file}-tx.pcap \
+options:rxq_pcap=${pcap_file}-rx.pcap
+
+}
+
+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_test() {
+    if [[ $1 = 1 ]]; then
+        shift; construct_expected_ra $@
+    else
+        shift; > expected
+    fi
+
+    for i in hv1 hv2 ; do
+        as $i reset_pcap_file $i-vif1 $i/vif1
+
+        OVS_WAIT_WHILE([test 24 = $(wc -c $i/vif1-tx.pcap | cut -d " " -f1)])
+
+        $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" $i/vif1-tx.pcap > packets
+        sed -i '/^ffffffffffff/d' packets
+
+        cat expected | cut -c -112 > expout
+        AT_CHECK([cat packets | cut -c -112], [0], [expout])
+
+        # Skip ICMPv6 checksum.
+        cat expected | cut -c 117- > expout
+        AT_CHECK([cat packets | cut -c 117-], [0], [expout])
+
+        rm -f packets
+        as $i reset_pcap_file $i-vif1 $i/vif1
+    done
+
+    rm -f expected
+}
+
+# first check that localnet port blocks RAs
+ra_test 0 0 00 0 0 0 c0 40 aef00000000000000000000000000000
+
+# now remove localnet port and check periodic RAs
+check ovn-nbctl lsp-del ln
+check ovn-nbctl --wait=hv sync
+ra_test 1 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])