Skip to content

Commit 00b2f18

Browse files
hzhou8dceara
authored andcommitted
northd: Support /31 router ports (RFC 3021).
A /31 point-to-point link has no broadcast address; both addresses in the range are usable hosts. However, ovn-northd computed a traditional subnet broadcast for the router port and included it in the priority-100 lr_in_ip_input L3 admission control drop flow (ip4.src == {...}). On a /31, that "broadcast" address is the peer, so all traffic originating from the /31 peer was dropped. Skip the broadcast address in the admission control drop set for /31 networks so that /31 router ports work as expected. Fixes: 936b640 ("ovn: Implement basic logical L3 routing.") Assisted-by: Claude Opus 4.8, Cursor Signed-off-by: Han Zhou <hzhou@ovn.org> Signed-off-by: Dumitru Ceara <dceara@redhat.com> (cherry picked from commit 1e738aa)
1 parent 7038ae7 commit 00b2f18

4 files changed

Lines changed: 125 additions & 2 deletions

File tree

Documentation/ref/ovn-logical-flows.7.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2342,6 +2342,8 @@ contains the following flows to implement very basic IP host functionality.
23422342
``REGBIT_EGRESS_LOOPBACK``.
23432343

23442344
- ``ip4.src`` is the broadcast address of any IP network known to the router.
2345+
Point-to-point (``/31``, RFC 3021) networks have no broadcast address and
2346+
are excluded, so that traffic from a ``/31`` peer is not dropped.
23452347

23462348
- A priority-100 flow parses DHCPv6 replies from IPv6 prefix delegation routers
23472349
(``udp.src == 547 && udp.dst == 546``). The ``handle_dhcpv6_reply`` is used to

northd/northd.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13420,9 +13420,13 @@ op_put_v4_networks(struct ds *ds, const struct ovn_port *op, bool add_bcast)
1342013420
}
1342113421

1342213422
ds_put_cstr(ds, "{");
13423-
for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) {
13423+
for (size_t i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) {
1342413424
ds_put_format(ds, "%s, ", op->lrp_networks.ipv4_addrs[i].addr_s);
13425-
if (add_bcast) {
13425+
/* A /31 point-to-point link (RFC 3021) has no broadcast address:
13426+
* both addresses in the range are usable hosts. Including the
13427+
* computed "broadcast" here would drop legitimate traffic from the
13428+
* /31 peer, so skip it for /31 networks. */
13429+
if (add_bcast && op->lrp_networks.ipv4_addrs[i].plen != 31) {
1342613430
ds_put_format(ds, "%s, ", op->lrp_networks.ipv4_addrs[i].bcast_s);
1342713431
}
1342813432
}

tests/ovn-northd.at

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2403,6 +2403,33 @@ OVN_CLEANUP_NORTHD
24032403
AT_CLEANUP
24042404
])
24052405

2406+
OVN_FOR_EACH_NORTHD_NO_HV([
2407+
AT_SETUP([router LRP /31 L3 admission control])
2408+
ovn_start
2409+
2410+
# A /31 point-to-point link (RFC 3021) has no broadcast address; both
2411+
# addresses of the /31 are usable hosts. The L3 admission control flow must
2412+
# therefore not drop the computed "broadcast" address, otherwise traffic from
2413+
# the /31 peer is dropped.
2414+
check ovn-nbctl lr-add lr
2415+
check ovn-nbctl lrp-add lr lrp31 00:00:00:00:00:01 10.0.0.0/31
2416+
check ovn-nbctl lrp-add lr lrp24 00:00:00:00:00:03 10.0.2.1/24
2417+
2418+
check ovn-nbctl --wait=sb sync
2419+
ovn-sbctl dump-flows lr > lrflows
2420+
AT_CAPTURE_FILE([lrflows])
2421+
2422+
# The /31 peer (10.0.0.1) must not appear as a dropped broadcast source;
2423+
# only the wider /24 network keeps its broadcast address.
2424+
AT_CHECK([grep "lr_in_ip_input" lrflows | grep "priority=100" | grep "reg9" | ovn_strip_lflows], [0], [dnl
2425+
table=??(lr_in_ip_input ), priority=100 , match=(ip4.src == {10.0.0.0} && reg9[[0]] == 0), action=(drop;)
2426+
table=??(lr_in_ip_input ), priority=100 , match=(ip4.src == {10.0.2.1, 10.0.2.255} && reg9[[0]] == 0), action=(drop;)
2427+
])
2428+
2429+
OVN_CLEANUP_NORTHD
2430+
AT_CLEANUP
2431+
])
2432+
24062433
# This test case tests that when a logical switch has load balancers associated
24072434
# (with VIPs configured), the below logical flow is added by ovn-northd.
24082435
# table=ls_out_pre_lb, priority=100, match=(ip), action=(reg0[[0]] = 1; next;)

tests/ovn.at

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14291,6 +14291,96 @@ OVN_CLEANUP([hv1],[hv2])
1429114291
AT_CLEANUP
1429214292
])
1429314293

14294+
OVN_FOR_EACH_NORTHD([
14295+
AT_SETUP([/31 router port (RFC 3021)])
14296+
CHECK_SCAPY
14297+
ovn_start
14298+
14299+
# Logical network:
14300+
# 2 LS 'sw0' and 'sw1' connected via router R1.
14301+
# R1 connects to 'sw0' with a /31 point-to-point network (RFC 3021). The
14302+
# host 'sw0p1' uses 10.0.0.1, which is the address that OVN previously
14303+
# computed as the /31 "broadcast" and dropped in the L3 admission control.
14304+
# This test verifies that traffic sourced from the /31 peer is forwarded.
14305+
14306+
check ovn-nbctl lr-add R1
14307+
14308+
check ovn-nbctl ls-add sw0
14309+
check ovn-nbctl ls-add sw1
14310+
14311+
# Connect sw0 to R1 with a /31 network. The router owns 10.0.0.0/31.
14312+
check ovn-nbctl lrp-add R1 sw0 00:00:00:01:02:03 10.0.0.0/31
14313+
check ovn-nbctl lsp-add sw0 rp-sw0 -- set Logical_Switch_Port rp-sw0 \
14314+
type=router options:router-port=sw0 addresses=\"00:00:00:01:02:03\"
14315+
14316+
# Connect sw1 to R1.
14317+
check ovn-nbctl lrp-add R1 sw1 00:00:00:01:02:04 20.0.0.1/24
14318+
check ovn-nbctl lsp-add sw1 rp-sw1 -- set Logical_Switch_Port rp-sw1 \
14319+
type=router options:router-port=sw1 addresses=\"00:00:00:01:02:04\"
14320+
14321+
# Create logical port sw0p1 in sw0. Its IP (10.0.0.1) is the /31 peer of
14322+
# the router port and equals the address OVN treated as the broadcast.
14323+
check ovn-nbctl lsp-add sw0 sw0p1 \
14324+
-- lsp-set-addresses sw0p1 "f0:00:00:01:02:03 10.0.0.1"
14325+
14326+
# Create logical port sw1p1 in sw1.
14327+
check ovn-nbctl lsp-add sw1 sw1p1 \
14328+
-- lsp-set-addresses sw1p1 "f0:00:00:01:02:04 20.0.0.2"
14329+
14330+
# Create two hypervisors and OVS ports corresponding to logical ports.
14331+
net_add n1
14332+
14333+
sim_add hv1
14334+
as hv1
14335+
check ovs-vsctl add-br br-phys
14336+
ovn_attach n1 br-phys 192.168.0.1
14337+
check ovs-vsctl -- add-port br-int hv1-vif1 -- \
14338+
set interface hv1-vif1 external-ids:iface-id=sw0p1 \
14339+
options:tx_pcap=hv1/vif1-tx.pcap \
14340+
options:rxq_pcap=hv1/vif1-rx.pcap \
14341+
ofport-request=1
14342+
14343+
sim_add hv2
14344+
as hv2
14345+
check ovs-vsctl add-br br-phys
14346+
ovn_attach n1 br-phys 192.168.0.2
14347+
check ovs-vsctl -- add-port br-int hv2-vif1 -- \
14348+
set interface hv2-vif1 external-ids:iface-id=sw1p1 \
14349+
options:tx_pcap=hv2/vif1-tx.pcap \
14350+
options:rxq_pcap=hv2/vif1-rx.pcap \
14351+
ofport-request=1
14352+
14353+
# Pre-populate the hypervisors' ARP tables so that we don't lose any
14354+
# packets for ARP resolution (native tunneling doesn't queue packets
14355+
# for ARP resolution).
14356+
OVN_POPULATE_ARP
14357+
14358+
wait_for_ports_up
14359+
check ovn-nbctl --wait=hv sync
14360+
14361+
# Send an IP packet from sw0p1 (10.0.0.1, the /31 peer) to sw1p1 (20.0.0.2).
14362+
# Before the /31 fix this packet was dropped by the L3 admission control,
14363+
# which treated 10.0.0.1 as the broadcast address of the 10.0.0.0/31 network.
14364+
packet=$(fmt_pkt "Ether(dst='00:00:00:01:02:03', \
14365+
src='f0:00:00:01:02:03') / \
14366+
IP(src='10.0.0.1', dst='20.0.0.2', ttl=64) / \
14367+
UDP(sport=53, dport=4369)")
14368+
as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 $packet
14369+
14370+
# Packet to expect at 'sw1p1'.
14371+
packet=$(fmt_pkt "Ether(dst='f0:00:00:01:02:04', \
14372+
src='00:00:00:01:02:04') / \
14373+
IP(src='10.0.0.1', dst='20.0.0.2', ttl=63) / \
14374+
UDP(sport=53, dport=4369)")
14375+
echo $packet > expected
14376+
14377+
OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected])
14378+
14379+
OVN_CLEANUP([hv1],[hv2])
14380+
14381+
AT_CLEANUP
14382+
])
14383+
1429414384
OVN_FOR_EACH_NORTHD([
1429514385
AT_SETUP([2 HVs, 1 lport/HV, localport ports])
1429614386
ovn_start

0 commit comments

Comments
 (0)