From patchwork Tue Oct 5 20:24:40 2021
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Vladislav Odintsov
If ECMP routes with symmetric reply are configured in the
-
+ If a packet arrived at this table from Logical Router Port P
+ which has
+ This table contains the following logical flows:
+
+ Priority-100 flow with match
+ A priority-0 logical flow with match
A packet that arrives at this table is an IP packet that should be
@@ -3316,10 +3344,10 @@ output;
IPv4 routing table. For each route to IPv4 network N with
netmask M, on router port P with IP address
- A and Ethernet
- address E, a logical flow with match OVN_Northbound
database for a gateway router, a priority-300
+ OVN_Northbound
database for a gateway router, a priority-400
flow is added for each router port on which symmetric replies are
configured. The matching logic for these ports essentially reverses the
configured logic of the ECMP route. So for instance, a route with a
@@ -3245,7 +3245,35 @@ output;
- Ingress Table 10: IP Routing
+ Ingress Table 10: IP Routing Pre
+
+ options:route_table
value set, a logical flow with
+ match inport == "P"
with priority 100 and action,
+ setting unique-generated per-datapath 32-bit value (non-zero) in OVS
+ register 7. This register is checked in next table.
+
+
+
+ inport == "LRP_NAME"
value
+ and action, which set route table identifier in reg7.
+ 1
has actions
+ next;
.
+ Ingress Table 11: IP Routing
ip4.dst ==
- N/M
, whose priority is the number of
- 1-bits in M, has the following actions:
+ A and Ethernet address E, a logical flow with
+ match ip4.dst == N/M
, whose
+ priority is 100 + the number of 1-bits in M, has the
+ following actions:
@@ -3382,6 +3410,13 @@ next;
If the address A is in the link-local scope, the
route will be limited to sending on the ingress port.
+ For routes with route_table
value set
+ reg7 == id
is prefixed in logical flow match portion.
+ Priority for routes with route_table
value set is
+ the number of 1-bits in M.
+
This table implements the second part of IP routing for ECMP routes @@ -3460,7 +3495,7 @@ outport = P; -
This table adds flows for the logical router policies configured on the logical router. Please see the @@ -3532,7 +3567,7 @@ next; -
This table handles the ECMP for the router policies configured with multiple nexthops. @@ -3576,7 +3611,7 @@ outport = P -
Any packet that reaches this table is an IP packet whose next-hop @@ -3767,7 +3802,7 @@ outport = P -
For distributed logical routers or gateway routers with gateway @@ -3797,7 +3832,7 @@ REGBIT_PKT_LARGER = check_pkt_larger(L); next; and advances to the next table.
-For distributed logical routers or gateway routers with gateway port @@ -3860,7 +3895,7 @@ icmp6 { and advances to the next table.
-For distributed logical routers where one or more of the logical router @@ -3907,7 +3942,7 @@ icmp6 { -
In the common case where the Ethernet destination has been resolved, this diff --git a/ovn-nb.ovsschema b/ovn-nb.ovsschema index 2ac8ef3ea..a0a171e19 100644 --- a/ovn-nb.ovsschema +++ b/ovn-nb.ovsschema @@ -1,7 +1,7 @@ { "name": "OVN_Northbound", - "version": "5.32.1", - "cksum": "2805328215 29734", + "version": "5.33.1", + "cksum": "3874993350 29785", "tables": { "NB_Global": { "columns": { @@ -387,6 +387,7 @@ "isRoot": false}, "Logical_Router_Static_Route": { "columns": { + "route_table": {"type": "string"}, "ip_prefix": {"type": "string"}, "policy": {"type": {"key": {"type": "string", "enum": ["set", ["src-ip", diff --git a/ovn-nb.xml b/ovn-nb.xml index d8266ed4d..b2917c363 100644 --- a/ovn-nb.xml +++ b/ovn-nb.xml @@ -2772,6 +2772,14 @@ prefix according to RFC3663
+ +route_table
value. Routes to directly connected networks
+ from same Logical Router and routes without route_table
+ option set have higher priority than routes with
+ route_table
option set.
+ + Any string to place route to separate routing table. If Logical Router + Port has configured value in other than empty string, OVN + performs route lookup for all packets entering Logical Router ingress + pipeline from this port in the following manner: +
+ +route_table
value set and routes to directly connected
+ networks.
+ route_table
value
+ as specified in LRP's options:route_table field.
+ ovn-ic
populates this key if the route is learned from the
global database. In this case the value
diff --git a/tests/ovn-ic.at b/tests/ovn-ic.at
index 32f4e9d02..3aab54362 100644
--- a/tests/ovn-ic.at
+++ b/tests/ovn-ic.at
@@ -281,6 +281,7 @@ done
AT_CHECK([ovn_as az1 ovn-nbctl lr-route-list lr1], [0], [dnl
IPv4 Routes
+Route Table global:
10.11.1.0/24 169.254.0.1 dst-ip
10.11.2.0/24 169.254.100.2 dst-ip (learned)
10.22.1.0/24 169.254.0.2 src-ip
@@ -299,6 +300,7 @@ ovn_as az1 ovn-nbctl set nb_global . options:ic-route-learn=false
OVS_WAIT_WHILE([ovn_as az1 ovn-nbctl lr-route-list lr1 | grep learned])
AT_CHECK([ovn_as az1 ovn-nbctl lr-route-list lr1], [0], [dnl
IPv4 Routes
+Route Table global:
10.11.1.0/24 169.254.0.1 dst-ip
10.22.1.0/24 169.254.0.2 src-ip
])
@@ -314,6 +316,7 @@ ovn_as az1 ovn-nbctl set nb_global . options:ic-route-adv=false
OVS_WAIT_WHILE([ovn_as az2 ovn-nbctl lr-route-list lr2 | grep learned])
AT_CHECK([ovn_as az2 ovn-nbctl lr-route-list lr2], [0], [dnl
IPv4 Routes
+Route Table global:
10.11.2.0/24 169.254.0.1 dst-ip
10.22.2.0/24 169.254.0.2 src-ip
])
@@ -332,6 +335,7 @@ done
# Default route should NOT get advertised or learned, by default.
AT_CHECK([ovn_as az2 ovn-nbctl lr-route-list lr2], [0], [dnl
IPv4 Routes
+Route Table global:
10.11.1.0/24 169.254.100.1 dst-ip (learned)
10.11.2.0/24 169.254.0.1 dst-ip
10.22.2.0/24 169.254.0.2 src-ip
diff --git a/tests/ovn-nbctl.at b/tests/ovn-nbctl.at
index 9b80ae410..ddb5536ce 100644
--- a/tests/ovn-nbctl.at
+++ b/tests/ovn-nbctl.at
@@ -1520,6 +1520,7 @@ AT_CHECK([ovn-nbctl --ecmp --policy=src-ip lr-route-add lr0 20.0.0.0/24 11.0.0.1
AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl
IPv4 Routes
+Route Table global:
10.0.0.0/24 11.0.0.1 dst-ip
10.0.1.0/24 11.0.1.1 dst-ip lp0
10.0.10.0/24 dst-ip lp0
@@ -1534,6 +1535,7 @@ AT_CHECK([ovn-nbctl lrp-add lr0 lp1 f0:00:00:00:00:02 11.0.0.254/24])
AT_CHECK([ovn-nbctl --may-exist lr-route-add lr0 10.0.0.111/24 11.0.0.1 lp1])
AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl
IPv4 Routes
+Route Table global:
10.0.0.0/24 11.0.0.1 dst-ip lp1
10.0.1.0/24 11.0.1.1 dst-ip lp0
10.0.10.0/24 dst-ip lp0
@@ -1564,6 +1566,7 @@ AT_CHECK([ovn-nbctl --policy=src-ip lr-route-del lr0 9.16.1.0/24])
AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl
IPv4 Routes
+Route Table global:
10.0.0.0/24 11.0.0.1 dst-ip lp1
10.0.10.0/24 dst-ip lp0
10.0.0.0/24 11.0.0.2 src-ip
@@ -1575,6 +1578,7 @@ AT_CHECK([ovn-nbctl --policy=dst-ip lr-route-del lr0 10.0.0.0/24])
AT_CHECK([ovn-nbctl --policy=src-ip lr-route-del lr0 10.0.0.0/24])
AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl
IPv4 Routes
+Route Table global:
10.0.10.0/24 dst-ip lp0
0.0.0.0/0 192.168.0.1 dst-ip
])
@@ -1585,6 +1589,7 @@ AT_CHECK([ovn-nbctl --policy=src-ip lr-route-add lr0 10.0.0.0/24 11.0.0.2])
AT_CHECK([ovn-nbctl lr-route-del lr0 10.0.0.0/24])
AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl
IPv4 Routes
+Route Table global:
10.0.10.0/24 dst-ip lp0
0.0.0.0/0 192.168.0.1 dst-ip
])
@@ -1601,6 +1606,7 @@ AT_CHECK([ovn-nbctl --ecmp lr-route-add lr0 10.0.0.0/24 11.0.0.3])
AT_CHECK([ovn-nbctl --ecmp lr-route-add lr0 10.0.0.0/24 11.0.0.4 lp0])
AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl
IPv4 Routes
+Route Table global:
10.0.0.0/24 11.0.0.1 dst-ip ecmp
10.0.0.0/24 11.0.0.2 dst-ip ecmp
10.0.0.0/24 11.0.0.3 dst-ip ecmp
@@ -1615,6 +1621,7 @@ dnl Delete ecmp routes
AT_CHECK([ovn-nbctl lr-route-del lr0 10.0.0.0/24 11.0.0.1])
AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl
IPv4 Routes
+Route Table global:
10.0.0.0/24 11.0.0.2 dst-ip ecmp
10.0.0.0/24 11.0.0.3 dst-ip ecmp
10.0.0.0/24 11.0.0.4 dst-ip lp0 ecmp
@@ -1622,12 +1629,14 @@ IPv4 Routes
AT_CHECK([ovn-nbctl lr-route-del lr0 10.0.0.0/24 11.0.0.2])
AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl
IPv4 Routes
+Route Table global:
10.0.0.0/24 11.0.0.3 dst-ip ecmp
10.0.0.0/24 11.0.0.4 dst-ip lp0 ecmp
])
AT_CHECK([ovn-nbctl lr-route-del lr0 10.0.0.0/24 11.0.0.4 lp0])
AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl
IPv4 Routes
+Route Table global:
10.0.0.0/24 11.0.0.3 dst-ip
])
AT_CHECK([ovn-nbctl lr-route-del lr0 10.0.0.0/24 11.0.0.3])
@@ -1641,6 +1650,7 @@ AT_CHECK([ovn-nbctl lr-route-add lr0 2001:0db8:1::/64 2001:0db8:0:f103::1])
AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl
IPv6 Routes
+Route Table global:
2001:db8::/64 2001:db8:0:f102::1 dst-ip lp0
2001:db8:1::/64 2001:db8:0:f103::1 dst-ip
::/0 2001:db8:0:f101::1 dst-ip
@@ -1650,6 +1660,7 @@ AT_CHECK([ovn-nbctl lr-route-del lr0 2001:0db8:0::/64])
AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl
IPv6 Routes
+Route Table global:
2001:db8:1::/64 2001:db8:0:f103::1 dst-ip
::/0 2001:db8:0:f101::1 dst-ip
])
@@ -1677,11 +1688,13 @@ AT_CHECK([ovn-nbctl --may-exist --ecmp-symmetric-reply lr-route-add lr0 2003:0db
AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl
IPv4 Routes
+Route Table global:
10.0.0.0/24 11.0.0.1 dst-ip
10.0.1.0/24 11.0.1.1 dst-ip lp0
0.0.0.0/0 192.168.0.1 dst-ip
IPv6 Routes
+Route Table global:
2001:db8::/64 2001:db8:0:f102::1 dst-ip lp0
2001:db8:1::/64 2001:db8:0:f103::1 dst-ip ecmp
2001:db8:1::/64 2001:db8:0:f103::2 dst-ip ecmp
@@ -1696,7 +1709,188 @@ AT_CHECK([ovn-nbctl lrp-add lr0 lr0-p0 00:00:01:01:02:03 192.168.10.1/24])
bfd_uuid=$(ovn-nbctl create bfd logical_port=lr0-p0 dst_ip=100.0.0.50 status=down min_tx=250 min_rx=250 detect_mult=10)
AT_CHECK([ovn-nbctl lr-route-add lr0 100.0.0.0/24 192.168.0.1])
route_uuid=$(fetch_column nb:logical_router_static_route _uuid ip_prefix="100.0.0.0/24")
-AT_CHECK([ovn-nbctl set logical_router_static_route $route_uuid bfd=$bfd_uuid])])
+AT_CHECK([ovn-nbctl set logical_router_static_route $route_uuid bfd=$bfd_uuid])
+
+check ovn-nbctl lr-route-del lr0
+AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl
+])
+
+dnl Check IPv4 routes in route table
+check ovn-nbctl --route-table=rtb-1 lr-route-add lr0 0.0.0.0/0 192.168.0.1
+check ovn-nbctl --route-table=rtb-1 lr-route-add lr0 10.0.1.1/24 11.0.1.1 lp0
+check ovn-nbctl --route-table=rtb-1 lr-route-add lr0 10.0.0.1/24 11.0.0.1
+AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl
+IPv4 Routes
+Route Table rtb-1:
+ 10.0.0.0/24 11.0.0.1 dst-ip
+ 10.0.1.0/24 11.0.1.1 dst-ip lp0
+ 0.0.0.0/0 192.168.0.1 dst-ip
+])
+
+check ovn-nbctl lr-route-del lr0
+AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl
+])
+
+dnl Check IPv6 routes in route table
+check ovn-nbctl --route-table=rtb-1 lr-route-add lr0 0:0:0:0:0:0:0:0/0 2001:0db8:0:f101::1
+check ovn-nbctl --route-table=rtb-1 lr-route-add lr0 2001:0db8:0::/64 2001:0db8:0:f102::1 lp0
+check ovn-nbctl --route-table=rtb-1 lr-route-add lr0 2001:0db8:1::/64 2001:0db8:0:f103::1
+
+AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl
+IPv6 Routes
+Route Table rtb-1:
+ 2001:db8::/64 2001:db8:0:f102::1 dst-ip lp0
+ 2001:db8:1::/64 2001:db8:0:f103::1 dst-ip
+ ::/0 2001:db8:0:f101::1 dst-ip
+])
+
+dnl Check IPv4 and IPv6 routes in route table
+check ovn-nbctl --route-table=rtb-1 lr-route-add lr0 0.0.0.0/0 192.168.0.1
+check ovn-nbctl --route-table=rtb-1 lr-route-add lr0 10.0.1.1/24 11.0.1.1 lp0
+check ovn-nbctl --route-table=rtb-1 lr-route-add lr0 10.0.0.1/24 11.0.0.1
+
+AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl
+IPv4 Routes
+Route Table rtb-1:
+ 10.0.0.0/24 11.0.0.1 dst-ip
+ 10.0.1.0/24 11.0.1.1 dst-ip lp0
+ 0.0.0.0/0 192.168.0.1 dst-ip
+
+IPv6 Routes
+Route Table rtb-1:
+ 2001:db8::/64 2001:db8:0:f102::1 dst-ip lp0
+ 2001:db8:1::/64 2001:db8:0:f103::1 dst-ip
+ ::/0 2001:db8:0:f101::1 dst-ip
+])
+
+# Add routes in another route table
+check ovn-nbctl --route-table=rtb-2 lr-route-add lr0 0.0.0.0/0 192.168.0.1
+check ovn-nbctl --route-table=rtb-2 lr-route-add lr0 10.0.1.1/24 11.0.1.1 lp0
+check ovn-nbctl --route-table=rtb-2 lr-route-add lr0 10.0.0.1/24 11.0.0.1
+check ovn-nbctl --route-table=rtb-2 lr-route-add lr0 0:0:0:0:0:0:0:0/0 2001:0db8:0:f101::1
+check ovn-nbctl --route-table=rtb-2 lr-route-add lr0 2001:0db8:0::/64 2001:0db8:0:f102::1 lp0
+check ovn-nbctl --route-table=rtb-2 lr-route-add lr0 2001:0db8:1::/64 2001:0db8:0:f103::1
+
+AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl
+IPv4 Routes
+Route Table rtb-1:
+ 10.0.0.0/24 11.0.0.1 dst-ip
+ 10.0.1.0/24 11.0.1.1 dst-ip lp0
+ 0.0.0.0/0 192.168.0.1 dst-ip
+
+Route Table rtb-2:
+ 10.0.0.0/24 11.0.0.1 dst-ip
+ 10.0.1.0/24 11.0.1.1 dst-ip lp0
+ 0.0.0.0/0 192.168.0.1 dst-ip
+
+IPv6 Routes
+Route Table rtb-1:
+ 2001:db8::/64 2001:db8:0:f102::1 dst-ip lp0
+ 2001:db8:1::/64 2001:db8:0:f103::1 dst-ip
+ ::/0 2001:db8:0:f101::1 dst-ip
+
+Route Table rtb-2:
+ 2001:db8::/64 2001:db8:0:f102::1 dst-ip lp0
+ 2001:db8:1::/64 2001:db8:0:f103::1 dst-ip
+ ::/0 2001:db8:0:f101::1 dst-ip
+])
+
+# Add routes to global route table
+check ovn-nbctl lr-route-add lr0 0.0.0.0/0 192.168.0.1
+check ovn-nbctl lr-route-add lr0 10.0.1.1/24 11.0.1.1 lp0
+check ovn-nbctl lr-route-add lr0 10.0.0.1/24 11.0.0.1
+check ovn-nbctl lr-route-add lr0 0:0:0:0:0:0:0:0/0 2001:0db8:0:f101::1
+check ovn-nbctl lr-route-add lr0 2001:0db8:0::/64 2001:0db8:0:f102::1 lp0
+check check ovn-nbctl lr-route-add lr0 2001:0db8:1::/64 2001:0db8:0:f103::1
+
+AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl
+IPv4 Routes
+Route Table global:
+ 10.0.0.0/24 11.0.0.1 dst-ip
+ 10.0.1.0/24 11.0.1.1 dst-ip lp0
+ 0.0.0.0/0 192.168.0.1 dst-ip
+
+Route Table rtb-1:
+ 10.0.0.0/24 11.0.0.1 dst-ip
+ 10.0.1.0/24 11.0.1.1 dst-ip lp0
+ 0.0.0.0/0 192.168.0.1 dst-ip
+
+Route Table rtb-2:
+ 10.0.0.0/24 11.0.0.1 dst-ip
+ 10.0.1.0/24 11.0.1.1 dst-ip lp0
+ 0.0.0.0/0 192.168.0.1 dst-ip
+
+IPv6 Routes
+Route Table global:
+ 2001:db8::/64 2001:db8:0:f102::1 dst-ip lp0
+ 2001:db8:1::/64 2001:db8:0:f103::1 dst-ip
+ ::/0 2001:db8:0:f101::1 dst-ip
+
+Route Table rtb-1:
+ 2001:db8::/64 2001:db8:0:f102::1 dst-ip lp0
+ 2001:db8:1::/64 2001:db8:0:f103::1 dst-ip
+ ::/0 2001:db8:0:f101::1 dst-ip
+
+Route Table rtb-2:
+ 2001:db8::/64 2001:db8:0:f102::1 dst-ip lp0
+ 2001:db8:1::/64 2001:db8:0:f103::1 dst-ip
+ ::/0 2001:db8:0:f101::1 dst-ip
+])
+
+# delete IPv4 route from rtb-1
+check ovn-nbctl --route-table=rtb-1 lr-route-del lr0 10.0.0.0/24
+AT_CHECK([ovn-nbctl --route-table=rtb-1 lr-route-list lr0], [0], [dnl
+IPv4 Routes
+Route Table rtb-1:
+ 10.0.1.0/24 11.0.1.1 dst-ip lp0
+ 0.0.0.0/0 192.168.0.1 dst-ip
+
+IPv6 Routes
+Route Table rtb-1:
+ 2001:db8::/64 2001:db8:0:f102::1 dst-ip lp0
+ 2001:db8:1::/64 2001:db8:0:f103::1 dst-ip
+ ::/0 2001:db8:0:f101::1 dst-ip
+])
+
+# delete IPv6 route from rtb-2
+check ovn-nbctl --route-table=rtb-2 lr-route-del lr0 2001:db8::/64
+AT_CHECK([ovn-nbctl --route-table=rtb-2 lr-route-list lr0], [0], [dnl
+IPv4 Routes
+Route Table rtb-2:
+ 10.0.0.0/24 11.0.0.1 dst-ip
+ 10.0.1.0/24 11.0.1.1 dst-ip lp0
+ 0.0.0.0/0 192.168.0.1 dst-ip
+
+IPv6 Routes
+Route Table rtb-2:
+ 2001:db8:1::/64 2001:db8:0:f103::1 dst-ip
+ ::/0 2001:db8:0:f101::1 dst-ip
+])
+
+check ovn-nbctl lr-route-del lr0
+
+# ECMP route in route table
+check ovn-nbctl --route-table=rtb1 lr-route-add lr0 0.0.0.0/0 192.168.0.1
+check ovn-nbctl --ecmp --route-table=rtb1 lr-route-add lr0 0.0.0.0/0 192.168.0.2
+
+# Negative route table case: same prefix
+AT_CHECK([ovn-nbctl --route-table=rtb1 lr-route-add lr0 0.0.0.0/0 192.168.0.1], [1], [], [dnl
+ovn-nbctl: duplicate prefix: 0.0.0.0/0 (policy: dst-ip). Use option --ecmp to allow this for ECMP routing.
+])
+
+# Negative route table case: same prefix & nexthop with ecmp
+AT_CHECK([ovn-nbctl --ecmp --route-table=rtb1 lr-route-add lr0 0.0.0.0/0 192.168.0.2], [1], [], [dnl
+ovn-nbctl: duplicate nexthop for the same ECMP route
+])
+
+# Add routes to global route table
+check ovn-nbctl lrp-add lr0 lrp0 00:00:00:00:00:01 1.1.1.1/24
+check ovn-nbctl lrp-set-options lrp0 route_table=rtb1
+AT_CHECK([ovn-nbctl get logical-router-port lrp0 options:route_table], [0], [dnl
+rtb1
+])
+check `ovn-nbctl show lr0 | grep lrp0 -A3 | grep route_table=rtb1`
+])
dnl ---------------------------------------------------------------------
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
index 3eebb55b6..e71e65bcc 100644
--- a/tests/ovn-northd.at
+++ b/tests/ovn-northd.at
@@ -5111,7 +5111,7 @@ check ovn-nbctl --wait=sb --ecmp-symmetric-reply lr-route-add lr0 1.0.0.1 192.16
ovn-sbctl dump-flows lr0 > lr0flows
AT_CHECK([grep -e "lr_in_ip_routing.*select" lr0flows | sed 's/table=../table=??/' | sort], [0], [dnl
- table=??(lr_in_ip_routing ), priority=65 , match=(ip4.dst == 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; reg8[[0..15]] = 1; reg8[[16..31]] = select(1, 2);)
+ table=??(lr_in_ip_routing ), priority=165 , match=(ip4.dst == 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; reg8[[0..15]] = 1; reg8[[16..31]] = select(1, 2);)
])
AT_CHECK([grep -e "lr_in_ip_routing_ecmp" lr0flows | sed 's/192\.168\.0\..0/192.168.0.??/' | sed 's/table=../table=??/' | sort], [0], [dnl
table=??(lr_in_ip_routing_ecmp), priority=100 , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = 192.168.0.??; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; next;)
@@ -5124,7 +5124,7 @@ check ovn-nbctl --wait=sb --ecmp-symmetric-reply lr-route-add lr0 1.0.0.1 192.16
ovn-sbctl dump-flows lr0 > lr0flows
AT_CHECK([grep -e "lr_in_ip_routing.*select" lr0flows | sed 's/table=../table=??/' | sort], [0], [dnl
- table=??(lr_in_ip_routing ), priority=65 , match=(ip4.dst == 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; reg8[[0..15]] = 1; reg8[[16..31]] = select(1, 2);)
+ table=??(lr_in_ip_routing ), priority=165 , match=(ip4.dst == 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; reg8[[0..15]] = 1; reg8[[16..31]] = select(1, 2);)
])
AT_CHECK([grep -e "lr_in_ip_routing_ecmp" lr0flows | sed 's/192\.168\.0\..0/192.168.0.??/' | sed 's/table=../table=??/' | sort], [0], [dnl
table=??(lr_in_ip_routing_ecmp), priority=100 , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = 192.168.0.??; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; next;)
@@ -5139,14 +5139,14 @@ check ovn-nbctl --wait=sb lr-route-add lr0 1.0.0.0/24 192.168.0.10
ovn-sbctl dump-flows lr0 > lr0flows
AT_CHECK([grep -e "lr_in_ip_routing.*192.168.0.10" lr0flows | sed 's/table=../table=??/' | sort], [0], [dnl
- table=??(lr_in_ip_routing ), priority=49 , match=(ip4.dst == 1.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.10; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;)
+ table=??(lr_in_ip_routing ), priority=149 , match=(ip4.dst == 1.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.10; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;)
])
check ovn-nbctl --wait=sb lr-route-add lr0 2.0.0.0/24 lr0-public
ovn-sbctl dump-flows lr0 > lr0flows
AT_CHECK([grep -e "lr_in_ip_routing.*2.0.0.0" lr0flows | sed 's/table=../table=??/' | sort], [0], [dnl
- table=??(lr_in_ip_routing ), priority=49 , match=(ip4.dst == 2.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;)
+ table=??(lr_in_ip_routing ), priority=149 , match=(ip4.dst == 2.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;)
])
AT_CLEANUP
@@ -5232,3 +5232,71 @@ AT_CHECK([grep lr_in_gw_redirect lrflows | grep cr-DR | sed 's/table=../table=??
AT_CLEANUP
])
+
+
+OVN_FOR_EACH_NORTHD([
+AT_SETUP([route tables -- flows])
+AT_KEYWORDS([route-tables-flows])
+ovn_start
+
+check ovn-nbctl lr-add lr0
+check ovn-nbctl lrp-add lr0 lrp0 00:00:00:00:00:01 192.168.0.1/24
+check ovn-nbctl lrp-add lr0 lrp1 00:00:00:00:01:01 192.168.1.1/24
+check ovn-nbctl lrp-add lr0 lrp2 00:00:00:00:02:01 192.168.2.1/24
+check ovn-nbctl lrp-set-options lrp1 route_table=rtb-1
+check ovn-nbctl lrp-set-options lrp2 route_table=rtb-2
+
+check ovn-nbctl lr-route-add lr0 0.0.0.0/0 192.168.0.10
+check ovn-nbctl --route-table=rtb-1 lr-route-add lr0 192.168.0.0/24 192.168.1.10
+check ovn-nbctl --route-table=rtb-2 lr-route-add lr0 0.0.0.0/0 192.168.0.10
+check ovn-nbctl --route-table=rtb-2 lr-route-add lr0 1.1.1.1/32 192.168.0.20
+check ovn-nbctl --route-table=rtb-2 lr-route-add lr0 2.2.2.2/32 192.168.0.30
+check ovn-nbctl --route-table=rtb-2 --ecmp lr-route-add lr0 2.2.2.2/32 192.168.0.31
+check ovn-nbctl --wait=sb sync
+
+ovn-sbctl dump-flows lr0 > lr0flows
+AT_CAPTURE_FILE([lr0flows])
+
+AT_CHECK([grep -e "lr_in_ip_routing_pre.*match=(1)" lr0flows | sed 's/table=../table=??/'], [0], [dnl
+ table=??(lr_in_ip_routing_pre), priority=0 , match=(1), action=(next;)
+])
+
+p1_reg=$(grep -oP "lr_in_ip_routing_pre.*lrp1.*action=\(reg7 = \K." lr0flows)
+p2_reg=$(grep -oP "lr_in_ip_routing_pre.*lrp2.*action=\(reg7 = \K." lr0flows)
+echo $p1_reg
+echo $p2_reg
+
+# exact register values are not predictable
+if [[ $p1_reg -eq 2 ] && [ $p2_reg -eq 1 ]]; then
+ echo "swap reg values in dump"
+ sed -i -r s'/^(.*lrp2.*action=\(reg7 = )(1)(.*)/\12\3/g' lr0flows # "reg7 = 1" -> "reg7 = 2"
+ sed -i -r s'/^(.*lrp1.*action=\(reg7 = )(2)(.*)/\11\3/g' lr0flows # "reg7 = 2" -> "reg7 = 1"
+ sed -i -r s'/^(.*match=\(reg7 == )(2)( &&.*lrp1.*)/\11\3/g' lr0flows # "reg7 == 2" -> "reg7 == 1"
+ sed -i -r s'/^(.*match=\(reg7 == )(1)( &&.*lrp0.*)/\12\3/g' lr0flows # "reg7 == 1" -> "reg7 == 2"
+fi
+
+check test "$p1_reg" != "$p2_reg" -a $((p1_reg * p2_reg)) -eq 2
+
+AT_CHECK([grep "lr_in_ip_routing_pre" lr0flows | sed 's/table=../table=??/' | sort], [0], [dnl
+ table=??(lr_in_ip_routing_pre), priority=0 , match=(1), action=(next;)
+ table=??(lr_in_ip_routing_pre), priority=100 , match=(inport == "lrp1"), action=(reg7 = 1; next;)
+ table=??(lr_in_ip_routing_pre), priority=100 , match=(inport == "lrp2"), action=(reg7 = 2; next;)
+])
+
+grep -e "(lr_in_ip_routing ).*outport" lr0flows
+
+AT_CHECK([grep -e "(lr_in_ip_routing ).*outport" lr0flows | sed 's/table=../table=??/' | sort], [0], [dnl
+ table=??(lr_in_ip_routing ), priority=1 , match=(reg7 == 2 && ip4.dst == 0.0.0.0/0), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.10; reg1 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; next;)
+ table=??(lr_in_ip_routing ), priority=101 , match=(ip4.dst == 0.0.0.0/0), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.10; reg1 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; next;)
+ table=??(lr_in_ip_routing ), priority=149 , match=(ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg1 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; next;)
+ table=??(lr_in_ip_routing ), priority=149 , match=(ip4.dst == 192.168.1.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg1 = 192.168.1.1; eth.src = 00:00:00:00:01:01; outport = "lrp1"; flags.loopback = 1; next;)
+ table=??(lr_in_ip_routing ), priority=149 , match=(ip4.dst == 192.168.2.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg1 = 192.168.2.1; eth.src = 00:00:00:00:02:01; outport = "lrp2"; flags.loopback = 1; next;)
+ table=??(lr_in_ip_routing ), priority=229 , match=(inport == "lrp0" && ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = fe80::200:ff:fe00:1; eth.src = 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; next;)
+ table=??(lr_in_ip_routing ), priority=229 , match=(inport == "lrp1" && ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = fe80::200:ff:fe00:101; eth.src = 00:00:00:00:01:01; outport = "lrp1"; flags.loopback = 1; next;)
+ table=??(lr_in_ip_routing ), priority=229 , match=(inport == "lrp2" && ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = fe80::200:ff:fe00:201; eth.src = 00:00:00:00:02:01; outport = "lrp2"; flags.loopback = 1; next;)
+ table=??(lr_in_ip_routing ), priority=49 , match=(reg7 == 1 && ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.1.10; reg1 = 192.168.1.1; eth.src = 00:00:00:00:01:01; outport = "lrp1"; flags.loopback = 1; next;)
+ table=??(lr_in_ip_routing ), priority=65 , match=(reg7 == 2 && ip4.dst == 1.1.1.1/32), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.20; reg1 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; next;)
+])
+
+AT_CLEANUP
+])
diff --git a/tests/ovn.at b/tests/ovn.at
index 49ece8735..60783a14b 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -18145,7 +18145,7 @@ eth_dst=00000000ff01
ip_src=$(ip_to_hex 10 0 0 10)
ip_dst=$(ip_to_hex 172 168 0 101)
send_icmp_packet 1 1 $eth_src $eth_dst $ip_src $ip_dst c4c9 0000000000000000000000
-AT_CHECK([as hv1 ovs-ofctl dump-flows br-int | awk '/table=25, n_packets=1, n_bytes=45/{print $7" "$8}'],[0],[dnl
+AT_CHECK([as hv1 ovs-ofctl dump-flows br-int | awk '/table=26, n_packets=1, n_bytes=45/{print $7" "$8}'],[0],[dnl
priority=80,ip,reg15=0x3,metadata=0x3,nw_src=10.0.0.10 actions=drop
])
@@ -22577,6 +22577,433 @@ OVN_CLEANUP([hv1])
AT_CLEANUP
])
+
+OVN_FOR_EACH_NORTHD([
+AT_SETUP([route tables -- global routes])
+ovn_start
+
+# Logical network:
+# ls1 (192.168.1.0/24) - lrp-lr1-ls1 - lr1 - lrp-lr1-ls2 - ls2 (192.168.2.0/24)
+#
+# ls1 has lsp11 (192.168.1.11) and ls2 has lsp21 (192.168.2.21) and lsp22
+# (192.168.2.22)
+#
+# lrp-lr1-ls1 set options:route_table=rtb-1
+#
+# Static routes on lr1:
+# 0.0.0.0/0 nexthop 192.168.2.21
+# 1.1.1.1/32 nexthop 192.168.2.22 route_table=rtb-1
+#
+# Test 1:
+# lsp11 send packet to 2.2.2.2
+#
+# Expected result:
+# lsp21 should receive traffic, lsp22 should not receive any traffic
+#
+# Test 2:
+# lsp11 send packet to 1.1.1.1
+#
+# Expected result:
+# lsp21 should receive traffic, lsp22 should not receive any traffic
+
+ovn-nbctl lr-add lr1
+
+for i in 1 2; do
+ ovn-nbctl ls-add ls${i}
+ ovn-nbctl lrp-add lr1 lrp-lr1-ls${i} 00:00:00:01:0${i}:01 192.168.${i}.1/24
+ ovn-nbctl lsp-add ls${i} lsp-ls${i}-lr1 -- lsp-set-type lsp-ls${i}-lr1 router \
+ -- lsp-set-options lsp-ls${i}-lr1 router-port=lrp-lr1-ls${i} \
+ -- lsp-set-addresses lsp-ls${i}-lr1 router
+done
+
+# install static routes
+ovn-nbctl lr-route-add lr1 0.0.0.0/0 192.168.2.21
+ovn-nbctl --route-table=rtb-1 lr-route-add lr1 1.1.1.1/32 192.168.2.22
+
+# set lrp-lr1-ls1 route table
+ovn-nbctl lrp-set-options lrp-lr1-ls1 route_table=rtb-1
+
+# Create logical ports
+ovn-nbctl lsp-add ls1 lsp11 -- \
+ lsp-set-addresses lsp11 "f0:00:00:00:01:11 192.168.1.11"
+ovn-nbctl lsp-add ls2 lsp21 -- \
+ lsp-set-addresses lsp21 "f0:00:00:00:02:21 192.168.2.21"
+ovn-nbctl lsp-add ls2 lsp22 -- \
+ lsp-set-addresses lsp22 "f0:00:00:00:02:22 192.168.2.22"
+
+net_add n1
+sim_add hv1
+as hv1
+ovs-vsctl add-br br-phys
+ovn_attach n1 br-phys 192.168.0.1
+ovs-vsctl -- add-port br-int hv1-vif1 -- \
+ set interface hv1-vif1 external-ids:iface-id=lsp11 \
+ options:tx_pcap=hv1/vif1-tx.pcap \
+ options:rxq_pcap=hv1/vif1-rx.pcap \
+ ofport-request=1
+
+ovs-vsctl -- add-port br-int hv1-vif2 -- \
+ set interface hv1-vif2 external-ids:iface-id=lsp21 \
+ options:tx_pcap=hv1/vif2-tx.pcap \
+ options:rxq_pcap=hv1/vif2-rx.pcap \
+ ofport-request=2
+
+ovs-vsctl -- add-port br-int hv1-vif3 -- \
+ set interface hv1-vif3 external-ids:iface-id=lsp22 \
+ options:tx_pcap=hv1/vif3-tx.pcap \
+ options:rxq_pcap=hv1/vif3-rx.pcap \
+ ofport-request=3
+
+# wait for earlier changes to take effect
+check ovn-nbctl --wait=hv sync
+wait_for_ports_up
+
+for i in 1 2; do
+ packet="inport==\"lsp11\" && eth.src==f0:00:00:00:01:11 && eth.dst==00:00:00:01:01:01 &&
+ ip4 && ip.ttl==64 && ip4.src==192.168.1.11 && ip4.dst==$i.$i.$i.$i && icmp"
+ AT_CHECK([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"])
+
+ # Assume all packets go to lsp21.
+ exp_packet="eth.src==00:00:00:01:02:01 && eth.dst==f0:00:00:00:02:21 &&
+ ip4 && ip.ttl==63 && ip4.src==192.168.1.11 && ip4.dst==$i.$i.$i.$i && icmp"
+ echo $exp_packet | ovstest test-ovn expr-to-packets >> expected_lsp21
+done
+> expected_lsp22
+
+# lsp21 should recieve 2 packets and lsp22 should recieve no packets
+OVS_WAIT_UNTIL([
+ rcv_n1=`$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > lsp21.packets && cat lsp21.packets | wc -l`
+ rcv_n2=`$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif3-tx.pcap > lsp22.packets && cat lsp22.packets | wc -l`
+ echo $rcv_n1 $rcv_n2
+ test $rcv_n1 -eq 2 -a $rcv_n2 -eq 0])
+
+for i in 1 2; do
+ sort expected_lsp2$i > expout
+ AT_CHECK([cat lsp2${i}.packets | sort], [0], [expout])
+done
+
+OVN_CLEANUP([hv1])
+AT_CLEANUP
+])
+
+
+OVN_FOR_EACH_NORTHD([
+AT_SETUP([route tables -- directly connected routes])
+ovn_start
+
+# Logical network:
+# ls1 (192.168.1.0/24) - lrp-lr1-ls1 - lr1 - lrp-lr1-ls2 - ls2 (192.168.2.0/24)
+#
+# ls1 has lsp11 (192.168.1.11) and ls2 has lsp21 (192.168.2.21)
+#
+# lrp-lr1-ls1 set options:route_table=rtb-1
+#
+# Static routes on lr1:
+# 192.168.2.0/25 nexthop 192.168.1.11 route_table=rtb-1
+#
+# Test 1:
+# lsp11 send packet to 192.168.2.21
+#
+# Expected result:
+# lsp21 should receive traffic, lsp11 should not receive any traffic
+
+ovn-nbctl lr-add lr1
+
+for i in 1 2; do
+ ovn-nbctl ls-add ls${i}
+ ovn-nbctl lrp-add lr1 lrp-lr1-ls${i} 00:00:00:01:0${i}:01 192.168.${i}.1/24
+ ovn-nbctl lsp-add ls${i} lsp-ls${i}-lr1 -- lsp-set-type lsp-ls${i}-lr1 router \
+ -- lsp-set-options lsp-ls${i}-lr1 router-port=lrp-lr1-ls${i} \
+ -- lsp-set-addresses lsp-ls${i}-lr1 router
+done
+
+# install static route, which overrides directly-connected routes
+ovn-nbctl --route-table=rtb-1 lr-route-add lr1 192.168.2.0/25 192.168.1.11
+
+# set lrp-lr1-ls1 route table
+ovn-nbctl lrp-set-options lrp-lr1-ls1 route_table=rtb-1
+
+# Create logical ports
+ovn-nbctl lsp-add ls1 lsp11 -- \
+ lsp-set-addresses lsp11 "f0:00:00:00:01:11 192.168.1.11"
+ovn-nbctl lsp-add ls2 lsp21 -- \
+ lsp-set-addresses lsp21 "f0:00:00:00:02:21 192.168.2.21"
+
+net_add n1
+sim_add hv1
+as hv1
+ovs-vsctl add-br br-phys
+ovn_attach n1 br-phys 192.168.0.1
+ovs-vsctl -- add-port br-int hv1-vif1 -- \
+ set interface hv1-vif1 external-ids:iface-id=lsp11 \
+ options:tx_pcap=hv1/vif1-tx.pcap \
+ options:rxq_pcap=hv1/vif1-rx.pcap \
+ ofport-request=1
+
+ovs-vsctl -- add-port br-int hv1-vif2 -- \
+ set interface hv1-vif2 external-ids:iface-id=lsp21 \
+ options:tx_pcap=hv1/vif2-tx.pcap \
+ options:rxq_pcap=hv1/vif2-rx.pcap \
+ ofport-request=2
+
+# wait for earlier changes to take effect
+check ovn-nbctl --wait=hv sync
+wait_for_ports_up
+
+packet="inport==\"lsp11\" && eth.src==f0:00:00:00:01:11 && eth.dst==00:00:00:01:01:01 &&
+ ip4 && ip.ttl==64 && ip4.src==192.168.1.11 && ip4.dst==192.168.2.21 && icmp"
+AT_CHECK([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"])
+
+# Assume all packets go to lsp21.
+exp_packet="eth.src==00:00:00:01:02:01 && eth.dst==f0:00:00:00:02:21 &&
+ ip4 && ip.ttl==63 && ip4.src==192.168.1.11 && ip4.dst==192.168.2.21 && icmp"
+echo $exp_packet | ovstest test-ovn expr-to-packets >> expected_lsp21
+> expected_lsp11
+
+# lsp21 should recieve 1 icmp packet and lsp11 should recieve no packets
+OVS_WAIT_UNTIL([
+ rcv_n11=`$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif1-tx.pcap > lsp11.packets && cat lsp11.packets | wc -l`
+ rcv_n21=`$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > lsp21.packets && cat lsp21.packets | wc -l`
+ echo $rcv_n11 $rcv_n21
+ test $rcv_n11 -eq 0 -a $rcv_n21 -eq 1])
+
+for i in 11 21; do
+ sort expected_lsp$i > expout
+ AT_CHECK([cat lsp${i}.packets | sort], [0], [expout])
+done
+
+OVN_CLEANUP([hv1])
+AT_CLEANUP
+])
+
+
+OVN_FOR_EACH_NORTHD([
+AT_SETUP([route tables -- overlapping subnets])
+ovn_start
+
+# Logical network:
+#
+# ls1 (192.168.1.0/24) - lrp-lr1-ls1 -\ /- lrp-lr1-ls2 - ls2 (192.168.2.0/24)
+# lr1
+# ls3 (192.168.3.0/24) - lrp-lr1-ls3 -/ \- lrp-lr1-ls4 - ls4 (192.168.4.0/24)
+#
+# ls1 has lsp11 (192.168.1.11)
+# ls2 has lsp21 (192.168.2.21)
+# ls3 has lsp31 (192.168.3.31)
+# ls4 has lsp41 (192.168.4.41)
+#
+# lrp-lr1-ls1 set options:route_table=rtb-1
+# lrp-lr1-ls2 set options:route_table=rtb-2
+#
+# Static routes on lr1:
+# 10.0.0.0/24 nexthop 192.168.3.31 route_table=rtb-1
+# 10.0.0.0/24 nexthop 192.168.4.41 route_table=rtb-2
+#
+# Test 1:
+# lsp11 send packet to 10.0.0.1
+#
+# Expected result:
+# lsp31 should receive traffic, lsp41 should not receive any traffic
+#
+# Test 2:
+# lsp21 send packet to 10.0.0.1
+#
+# Expected result:
+# lsp41 should receive traffic, lsp31 should not receive any traffic
+
+ovn-nbctl lr-add lr1
+
+# Create logical topology
+for i in $(seq 1 4); do
+ ovn-nbctl ls-add ls${i}
+ ovn-nbctl lrp-add lr1 lrp-lr1-ls${i} 00:00:00:01:0${i}:01 192.168.${i}.1/24
+ ovn-nbctl lsp-add ls${i} lsp-ls${i}-lr1 -- lsp-set-type lsp-ls${i}-lr1 router \
+ -- lsp-set-options lsp-ls${i}-lr1 router-port=lrp-lr1-ls${i} \
+ -- lsp-set-addresses lsp-ls${i}-lr1 router
+ ovn-nbctl lsp-add ls$i lsp${i}1 -- \
+ lsp-set-addresses lsp${i}1 "f0:00:00:00:0${i}:1${i} 192.168.${i}.${i}1"
+done
+
+# install static routes
+ovn-nbctl --route-table=rtb-1 lr-route-add lr1 10.0.0.0/24 192.168.3.31
+ovn-nbctl --route-table=rtb-2 lr-route-add lr1 10.0.0.0/24 192.168.4.41
+
+# set lrp-lr1-ls{1,2} route tables
+ovn-nbctl lrp-set-options lrp-lr1-ls1 route_table=rtb-1
+ovn-nbctl lrp-set-options lrp-lr1-ls2 route_table=rtb-2
+
+net_add n1
+sim_add hv1
+as hv1
+ovs-vsctl add-br br-phys
+ovn_attach n1 br-phys 192.168.0.1
+
+for i in $(seq 1 4); do
+ ovs-vsctl -- add-port br-int hv1-vif${i} -- \
+ set interface hv1-vif${i} external-ids:iface-id=lsp${i}1 \
+ options:tx_pcap=hv1/vif${i}-tx.pcap \
+ options:rxq_pcap=hv1/vif${i}-rx.pcap \
+ ofport-request=${i}
+done
+
+# wait for earlier changes to take effect
+check ovn-nbctl --wait=hv sync
+wait_for_ports_up
+
+# lsp31 should recieve packet coming from lsp11
+# lsp41 should recieve packet coming from lsp21
+for i in $(seq 1 2); do
+ di=$(( i + 2)) # dst index
+ ri=$(( 5 - i)) # reverse index
+ packet="inport==\"lsp${i}1\" && eth.src==f0:00:00:00:0${i}:1${i} &&
+ eth.dst==00:00:00:01:0${i}:01 && ip4 && ip.ttl==64 &&
+ ip4.src==192.168.${i}.${i}1 && ip4.dst==10.0.0.1 && icmp"
+ AT_CHECK([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"])
+
+ # Assume all packets go to lsp${di}1.
+ exp_packet="eth.src==00:00:00:01:0${di}:01 && eth.dst==f0:00:00:00:0${di}:1${di} &&
+ ip4 && ip.ttl==63 && ip4.src==192.168.${i}.${i}1 && ip4.dst==10.0.0.1 && icmp"
+ echo $exp_packet | ovstest test-ovn expr-to-packets >> expected_lsp${di}1
+ > expected_lsp${ri}1
+
+ OVS_WAIT_UNTIL([
+ rcv_n1=`$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif${di}-tx.pcap > lsp${di}1.packets && cat lsp${di}1.packets | wc -l`
+ rcv_n2=`$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif${ri}-tx.pcap > lsp${ri}1.packets && cat lsp${ri}1.packets | wc -l`
+ echo $rcv_n1 $rcv_n2
+ test $rcv_n1 -eq 1 -a $rcv_n2 -eq 0])
+
+ for j in "${di}1" "${ri}1"; do
+ sort expected_lsp${j} > expout
+ AT_CHECK([cat lsp${j}.packets | sort], [0], [expout])
+ done
+
+ # cleanup tx pcap files
+ for j in "${di}1" "${ri}1"; do
+ ovs-vsctl -- remove interface hv1-vif${di} options tx_pcap
+ > hv1/vif${di}-tx.pcap
+ ovs-vsctl -- set interface hv1-vif${di} external-ids:iface-id=lsp${di}1 \
+ options:tx_pcap=hv1/vif${di}-tx.pcap
+ done
+done
+
+OVN_CLEANUP([hv1])
+AT_CLEANUP
+])
+
+
+OVN_FOR_EACH_NORTHD([
+AT_SETUP([route tables IPv6 -- overlapping subnets])
+ovn_start
+
+# Logical network:
+#
+# ls1 (2001:db8:1::/64) - lrp-lr1-ls1 -\ /- lrp-lr1-ls2 - ls2 (2001:db8:2::/64)
+# lr1
+# ls3 (2001:db8:3::/64) - lrp-lr1-ls3 -/ \- lrp-lr1-ls4 - ls4 (2001:db8:4::/64)
+#
+# ls1 has lsp11 (2001:db8:1::11)
+# ls2 has lsp21 (2001:db8:2::21)
+# ls3 has lsp31 (2001:db8:3::31)
+# ls4 has lsp41 (2001:db8:4::41)
+#
+# lrp-lr1-ls1 set options:route_table=rtb-1
+# lrp-lr1-ls2 set options:route_table=rtb-2
+#
+# Static routes on lr1:
+# 2001:db8:2000::/64 nexthop 2001:db8:3::31 route_table=rtb-1
+# 2001:db8:2000::/64 nexthop 2001:db8:3::41 route_table=rtb-2
+#
+# Test 1:
+# lsp11 send packet to 2001:db8:2000::1
+#
+# Expected result:
+# lsp31 should receive traffic, lsp41 should not receive any traffic
+#
+# Test 2:
+# lsp21 send packet to 2001:db8:2000::1
+#
+# Expected result:
+# lsp41 should receive traffic, lsp31 should not receive any traffic
+
+ovn-nbctl lr-add lr1
+
+# Create logical topology
+for i in $(seq 1 4); do
+ ovn-nbctl ls-add ls${i}
+ ovn-nbctl lrp-add lr1 lrp-lr1-ls${i} 00:00:00:01:0${i}:01 2001:db8:${i}::1/64
+ ovn-nbctl lsp-add ls${i} lsp-ls${i}-lr1 -- lsp-set-type lsp-ls${i}-lr1 router \
+ -- lsp-set-options lsp-ls${i}-lr1 router-port=lrp-lr1-ls${i} \
+ -- lsp-set-addresses lsp-ls${i}-lr1 router
+ ovn-nbctl lsp-add ls$i lsp${i}1 -- \
+ lsp-set-addresses lsp${i}1 "f0:00:00:00:0${i}:1${i} 2001:db8:${i}::${i}1"
+done
+
+# install static routes
+ovn-nbctl --route-table=rtb-1 lr-route-add lr1 2001:db8:2000::/64 2001:db8:3::31
+ovn-nbctl --route-table=rtb-2 lr-route-add lr1 2001:db8:2000::/64 2001:db8:4::41
+
+# set lrp-lr1-ls{1,2} route tables
+ovn-nbctl lrp-set-options lrp-lr1-ls1 route_table=rtb-1
+ovn-nbctl lrp-set-options lrp-lr1-ls2 route_table=rtb-2
+
+net_add n1
+sim_add hv1
+as hv1
+ovs-vsctl add-br br-phys
+ovn_attach n1 br-phys 192.168.0.1
+
+for i in $(seq 1 4); do
+ ovs-vsctl -- add-port br-int hv1-vif${i} -- \
+ set interface hv1-vif${i} external-ids:iface-id=lsp${i}1 \
+ options:tx_pcap=hv1/vif${i}-tx.pcap \
+ options:rxq_pcap=hv1/vif${i}-rx.pcap \
+ ofport-request=${i}
+done
+
+# wait for earlier changes to take effect
+AT_CHECK([ovn-nbctl --timeout=3 --wait=hv sync], [0], [ignore])
+
+# lsp31 should recieve packet coming from lsp11
+# lsp41 should recieve packet coming from lsp21
+for i in $(seq 1 2); do
+ di=$(( i + 2)) # dst index
+ ri=$(( 5 - i)) # reverse index
+ packet="inport==\"lsp${i}1\" && eth.src==f0:00:00:00:0${i}:1${i} &&
+ eth.dst==00:00:00:01:0${i}:01 && ip6 && ip.ttl==64 &&
+ ip6.src==2001:db8:${i}::${i}1 && ip6.dst==2001:db8:2000::1 && icmp6"
+ AT_CHECK([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"])
+
+ # Assume all packets go to lsp${di}1.
+ exp_packet="eth.src==00:00:00:01:0${di}:01 && eth.dst==f0:00:00:00:0${di}:1${di} && ip6 &&
+ ip.ttl==63 && ip6.src==2001:db8:${i}::${i}1 && ip6.dst==2001:db8:2000::1 && icmp6"
+ echo $exp_packet | ovstest test-ovn expr-to-packets >> expected_lsp${di}1
+ > expected_lsp${ri}1
+
+ OVS_WAIT_UNTIL([
+ rcv_n1=`$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif${di}-tx.pcap > lsp${di}1.packets && cat lsp${di}1.packets | wc -l`
+ rcv_n2=`$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif${ri}-tx.pcap > lsp${ri}1.packets && cat lsp${ri}1.packets | wc -l`
+ echo $rcv_n1 $rcv_n2
+ test $rcv_n1 -eq 1 -a $rcv_n2 -eq 0])
+
+ for j in "${di}1" "${ri}1"; do
+ sort expected_lsp${j} > expout
+ AT_CHECK([cat lsp${j}.packets | sort], [0], [expout])
+ done
+
+ # cleanup tx pcap files
+ for j in "${di}1" "${ri}1"; do
+ ovs-vsctl -- remove interface hv1-vif${di} options tx_pcap
+ > hv1/vif${di}-tx.pcap
+ ovs-vsctl -- set interface hv1-vif${di} external-ids:iface-id=lsp${di}1 \
+ options:tx_pcap=hv1/vif${di}-tx.pcap
+ done
+done
+
+OVN_CLEANUP([hv1])
+AT_CLEANUP
+])
+
+
OVN_FOR_EACH_NORTHD([
AT_SETUP([forwarding group: 3 HVs, 1 LR, 2 LS])
AT_KEYWORDS([forwarding-group])
@@ -23332,7 +23759,7 @@ ovn-sbctl dump-flows > sbflows
AT_CAPTURE_FILE([sbflows])
AT_CAPTURE_FILE([offlows])
OVS_WAIT_UNTIL([
- as hv1 ovs-ofctl dump-flows br-int table=20 > offlows
+ as hv1 ovs-ofctl dump-flows br-int table=21 > offlows
test $(grep -c "load:0x64->NXM_NX_PKT_MARK" offlows) = 1 && \
test $(grep -c "load:0x3->NXM_NX_PKT_MARK" offlows) = 1 && \
test $(grep -c "load:0x4->NXM_NX_PKT_MARK" offlows) = 1 && \
@@ -23425,12 +23852,12 @@ send_ipv4_pkt hv1 hv1-vif1 505400000003 00000000ff01 \
$(ip_to_hex 10 0 0 3) $(ip_to_hex 172 168 0 120)
OVS_WAIT_UNTIL([
- test 1 -eq $(as hv1 ovs-ofctl dump-flows br-int table=20 | \
+ test 1 -eq $(as hv1 ovs-ofctl dump-flows br-int table=21 | \
grep "load:0x2->NXM_NX_PKT_MARK" -c)
])
AT_CHECK([
- test 0 -eq $(as hv1 ovs-ofctl dump-flows br-int table=20 | \
+ test 0 -eq $(as hv1 ovs-ofctl dump-flows br-int table=21 | \
grep "load:0x64->NXM_NX_PKT_MARK" -c)
])
@@ -24133,7 +24560,7 @@ AT_CHECK([
grep "priority=100" | \
grep -c "ct(commit,zone=NXM_NX_REG11\\[[0..15\\]],.*exec(move:NXM_OF_ETH_SRC\\[[\\]]->NXM_NX_CT_LABEL\\[[32..79\\]],load:0x[[0-9]]->NXM_NX_CT_LABEL\\[[80..95\\]]))"
- grep table=22 hv${hv}flows | \
+ grep table=23 hv${hv}flows | \
grep "priority=200" | \
grep -c "actions=move:NXM_NX_CT_LABEL\\[[32..79\\]]->NXM_OF_ETH_DST\\[[\\]]"
done; :], [0], [dnl
@@ -24258,7 +24685,7 @@ AT_CHECK([
grep "priority=100" | \
grep -c "ct(commit,zone=NXM_NX_REG11\\[[0..15\\]],.*exec(move:NXM_OF_ETH_SRC\\[[\\]]->NXM_NX_CT_LABEL\\[[32..79\\]],load:0x[[0-9]]->NXM_NX_CT_LABEL\\[[80..95\\]]))"
- grep table=22 hv${hv}flows | \
+ grep table=23 hv${hv}flows | \
grep "priority=200" | \
grep -c "actions=move:NXM_NX_CT_LABEL\\[[32..79\\]]->NXM_OF_ETH_DST\\[[\\]]"
done; :], [0], [dnl
@@ -24880,7 +25307,7 @@ AT_CHECK([as hv1 ovs-ofctl dump-flows br-int | grep "actions=controller" | grep
])
# The packet should've been dropped in the lr_in_arp_resolve stage.
-AT_CHECK([as hv1 ovs-ofctl dump-flows br-int | grep -E "table=22, n_packets=1,.* priority=1,ip,metadata=0x${sw_key},nw_dst=10.0.1.1 actions=drop" -c], [0], [dnl
+AT_CHECK([as hv1 ovs-ofctl dump-flows br-int | grep -E "table=23, n_packets=1,.* priority=1,ip,metadata=0x${sw_key},nw_dst=10.0.1.1 actions=drop" -c], [0], [dnl
1
])
diff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c
index e34bb65f7..0ff10618b 100644
--- a/utilities/ovn-nbctl.c
+++ b/utilities/ovn-nbctl.c
@@ -329,6 +329,8 @@ Logical router port commands:\n\
add logical port PORT on ROUTER\n\
lrp-set-gateway-chassis PORT CHASSIS [PRIORITY]\n\
set gateway chassis for port PORT\n\
+ lrp-set-options PORT KEY=VALUE [KEY=VALUE]...\n\
+ set router port options\n\
lrp-del-gateway-chassis PORT CHASSIS\n\
delete gateway chassis from port PORT\n\
lrp-get-gateway-chassis PORT\n\
@@ -351,11 +353,17 @@ Logical router port commands:\n\
('overlay' or 'bridged')\n\
\n\
Route commands:\n\
- [--policy=POLICY] [--ecmp] [--ecmp-symmetric-reply] lr-route-add ROUTER \n\
- PREFIX NEXTHOP [PORT]\n\
+ [--policy=POLICY]\n\
+ [--ecmp]\n\
+ [--ecmp-symmetric-reply]\n\
+ [--route-table=ROUTE_TABLE]\n\
+ lr-route-add ROUTER PREFIX NEXTHOP [PORT]\n\
add a route to ROUTER\n\
- [--policy=POLICY] lr-route-del ROUTER [PREFIX [NEXTHOP [PORT]]]\n\
+ [--policy=POLICY]\n\
+ [--route-table=ROUTE_TABLE]\n\
+ lr-route-del ROUTER [PREFIX [NEXTHOP [PORT]]]\n\
remove routes from ROUTER\n\
+ [--route-table=ROUTE_TABLE]\n\
lr-route-list ROUTER print routes for ROUTER\n\
\n\
Policy commands:\n\
@@ -743,6 +751,11 @@ print_lr(const struct nbrec_logical_router *lr, struct ds *s)
ds_put_cstr(s, "]\n");
}
+ const char *route_table = smap_get(&lrp->options, "route_table");
+ if (route_table) {
+ ds_put_format(s, " route-table: %s\n", route_table);
+ }
+
if (lrp->n_gateway_chassis) {
const struct nbrec_gateway_chassis **gcs;
@@ -862,6 +875,7 @@ nbctl_pre_show(struct ctl_context *ctx)
ovsdb_idl_add_column(ctx->idl, &nbrec_logical_router_port_col_name);
ovsdb_idl_add_column(ctx->idl, &nbrec_logical_router_port_col_mac);
ovsdb_idl_add_column(ctx->idl, &nbrec_logical_router_port_col_networks);
+ ovsdb_idl_add_column(ctx->idl, &nbrec_logical_router_port_col_options);
ovsdb_idl_add_column(ctx->idl, &nbrec_logical_router_port_col_gateway_chassis);
ovsdb_idl_add_column(ctx->idl, &nbrec_gateway_chassis_col_chassis_name);
@@ -4000,11 +4014,19 @@ nbctl_lr_policy_list(struct ctl_context *ctx)
static struct nbrec_logical_router_static_route *
nbctl_lr_get_route(const struct nbrec_logical_router *lr, char *prefix,
- char *next_hop, bool is_src_route, bool ecmp)
+ char *next_hop, bool is_src_route, bool ecmp,
+ char *route_table)
{
for (int i = 0; i < lr->n_static_routes; i++) {
struct nbrec_logical_router_static_route *route = lr->static_routes[i];
+ /* Strict compare for route_table.
+ * If route_table was not specified,
+ * lookup for routes with empty route_table value. */
+ if (strcmp(route->route_table, route_table ? route_table : "")) {
+ continue;
+ }
+
/* Compare route policy. */
char *nb_policy = route->policy;
bool nb_is_src_route = false;
@@ -4060,6 +4082,8 @@ nbctl_pre_lr_route_add(struct ctl_context *ctx)
&nbrec_logical_router_static_route_col_bfd);
ovsdb_idl_add_column(ctx->idl,
&nbrec_logical_router_static_route_col_options);
+ ovsdb_idl_add_column(ctx->idl,
+ &nbrec_logical_router_static_route_col_route_table);
}
static char * OVS_WARN_UNUSED_RESULT
@@ -4090,6 +4114,7 @@ nbctl_lr_route_add(struct ctl_context *ctx)
}
}
+ char *route_table = shash_find_data(&ctx->options, "--route-table");
bool v6_prefix = false;
prefix = normalize_ipv4_prefix_str(ctx->argv[2]);
if (!prefix) {
@@ -4166,7 +4191,8 @@ nbctl_lr_route_add(struct ctl_context *ctx)
bool ecmp = shash_find(&ctx->options, "--ecmp") != NULL ||
ecmp_symmetric_reply;
struct nbrec_logical_router_static_route *route =
- nbctl_lr_get_route(lr, prefix, next_hop, is_src_route, ecmp);
+ nbctl_lr_get_route(lr, prefix, next_hop, is_src_route, ecmp,
+ route_table);
/* Validations for nexthop = "discard" */
if (is_discard_route) {
@@ -4230,7 +4256,8 @@ nbctl_lr_route_add(struct ctl_context *ctx)
}
struct nbrec_logical_router_static_route *discard_route =
- nbctl_lr_get_route(lr, prefix, "discard", is_src_route, true);
+ nbctl_lr_get_route(lr, prefix, "discard", is_src_route, true,
+ route_table);
if (discard_route) {
ctl_error(ctx, "discard nexthop for the same ECMP route exists.");
goto cleanup;
@@ -4246,6 +4273,9 @@ nbctl_lr_route_add(struct ctl_context *ctx)
if (policy) {
nbrec_logical_router_static_route_set_policy(route, policy);
}
+ if (route_table) {
+ nbrec_logical_router_static_route_set_route_table(route, route_table);
+ }
if (ecmp_symmetric_reply) {
const struct smap options = SMAP_CONST1(&options,
@@ -4289,6 +4319,8 @@ nbctl_pre_lr_route_del(struct ctl_context *ctx)
&nbrec_logical_router_static_route_col_nexthop);
ovsdb_idl_add_column(ctx->idl,
&nbrec_logical_router_static_route_col_output_port);
+ ovsdb_idl_add_column(ctx->idl,
+ &nbrec_logical_router_static_route_col_route_table);
}
@@ -4302,6 +4334,7 @@ nbctl_lr_route_del(struct ctl_context *ctx)
return;
}
+ const char *route_table = shash_find_data(&ctx->options, "--route-table");
const char *policy = shash_find_data(&ctx->options, "--policy");
bool is_src_route = false;
if (policy) {
@@ -4392,6 +4425,14 @@ nbctl_lr_route_del(struct ctl_context *ctx)
}
}
+ /* Strict compare for route_table.
+ * If route_table was not specified,
+ * lookup for routes with empty route_table value. */
+ if (strcmp(lr->static_routes[i]->route_table,
+ route_table ? route_table : "")) {
+ continue;
+ }
+
/* Compare output_port, if specified. */
if (output_port) {
char *rt_output_port = lr->static_routes[i]->output_port;
@@ -5115,6 +5156,41 @@ nbctl_pre_lrp_del_gateway_chassis(struct ctl_context *ctx)
ovsdb_idl_add_column(ctx->idl, &nbrec_gateway_chassis_col_chassis_name);
}
+static void
+nbctl_pre_lrp_options(struct ctl_context *ctx)
+{
+ ovsdb_idl_add_column(ctx->idl, &nbrec_logical_router_port_col_name);
+ ovsdb_idl_add_column(ctx->idl, &nbrec_logical_router_port_col_options);
+}
+
+static void
+nbctl_lrp_set_options(struct ctl_context *ctx)
+{
+ const char *id = ctx->argv[1];
+ const struct nbrec_logical_router_port *lrp = NULL;
+ size_t i;
+ struct smap options = SMAP_INITIALIZER(&options);
+
+ char *error = lrp_by_name_or_uuid(ctx, id, true, &lrp);
+ if (error) {
+ ctx->error = error;
+ return;
+ }
+ for (i = 2; i < ctx->argc; i++) {
+ char *key, *value;
+ value = xstrdup(ctx->argv[i]);
+ key = strsep(&value, "=");
+ if (value) {
+ smap_add(&options, key, value);
+ }
+ free(key);
+ }
+
+ nbrec_logical_router_port_set_options(lrp, &options);
+
+ smap_destroy(&options);
+}
+
/* Removes logical router port 'lrp->gateway_chassis[idx]'. */
static void
remove_gc(const struct nbrec_logical_router_port *lrp, size_t idx)
@@ -5891,6 +5967,7 @@ route_cmp_details(const struct nbrec_logical_router_static_route *r1,
}
return r1->output_port ? 1 : -1;
}
+
struct ipv4_route {
int priority;
ovs_be32 addr;
@@ -5900,6 +5977,11 @@ struct ipv4_route {
static int
__ipv4_route_cmp(const struct ipv4_route *r1, const struct ipv4_route *r2)
{
+ int rtb_cmp = strcmp(r1->route->route_table,
+ r2->route->route_table);
+ if (rtb_cmp) {
+ return rtb_cmp;
+ }
if (r1->priority != r2->priority) {
return r1->priority > r2->priority ? -1 : 1;
}
@@ -5931,6 +6013,11 @@ struct ipv6_route {
static int
__ipv6_route_cmp(const struct ipv6_route *r1, const struct ipv6_route *r2)
{
+ int rtb_cmp = strcmp(r1->route->route_table,
+ r2->route->route_table);
+ if (rtb_cmp) {
+ return rtb_cmp;
+ }
if (r1->priority != r2->priority) {
return r1->priority > r2->priority ? -1 : 1;
}
@@ -6018,6 +6105,8 @@ nbctl_pre_lr_route_list(struct ctl_context *ctx)
&nbrec_logical_router_static_route_col_options);
ovsdb_idl_add_column(ctx->idl,
&nbrec_logical_router_static_route_col_bfd);
+ ovsdb_idl_add_column(ctx->idl,
+ &nbrec_logical_router_static_route_col_route_table);
}
static void
@@ -6035,12 +6124,17 @@ nbctl_lr_route_list(struct ctl_context *ctx)
return;
}
+ char *route_table = shash_find_data(&ctx->options, "--route-table");
+
ipv4_routes = xmalloc(sizeof *ipv4_routes * lr->n_static_routes);
ipv6_routes = xmalloc(sizeof *ipv6_routes * lr->n_static_routes);
for (int i = 0; i < lr->n_static_routes; i++) {
const struct nbrec_logical_router_static_route *route
= lr->static_routes[i];
+ if (route_table && strcmp(route->route_table, route_table)) {
+ continue;
+ }
unsigned int plen;
ovs_be32 ipv4;
const char *policy = route->policy ? route->policy : "dst-ip";
@@ -6081,6 +6175,7 @@ nbctl_lr_route_list(struct ctl_context *ctx)
if (n_ipv4_routes) {
ds_put_cstr(&ctx->output, "IPv4 Routes\n");
}
+ const struct nbrec_logical_router_static_route *route;
for (int i = 0; i < n_ipv4_routes; i++) {
bool ecmp = false;
if (i < n_ipv4_routes - 1 &&
@@ -6091,6 +6186,15 @@ nbctl_lr_route_list(struct ctl_context *ctx)
&ipv4_routes[i - 1])) {
ecmp = true;
}
+
+ route = ipv4_routes[i].route;
+ if (!i || (i > 0 && strcmp(route->route_table,
+ ipv4_routes[i - 1].route->route_table))) {
+ ds_put_format(&ctx->output, "%sRoute Table %s:\n", i ? "\n" : "",
+ strlen(route->route_table) ? route->route_table
+ : "global");
+ }
+
print_route(ipv4_routes[i].route, &ctx->output, ecmp);
}
@@ -6108,6 +6212,15 @@ nbctl_lr_route_list(struct ctl_context *ctx)
&ipv6_routes[i - 1])) {
ecmp = true;
}
+
+ route = ipv6_routes[i].route;
+ if (!i || (i > 0 && strcmp(route->route_table,
+ ipv6_routes[i - 1].route->route_table))) {
+ ds_put_format(&ctx->output, "%sRoute Table %s:\n", i ? "\n" : "",
+ strlen(route->route_table) ? route->route_table
+ : "global");
+ }
+
print_route(ipv6_routes[i].route, &ctx->output, ecmp);
}
@@ -6926,6 +7039,8 @@ static const struct ctl_command_syntax nbctl_commands[] = {
"PORT CHASSIS [PRIORITY]",
nbctl_pre_lrp_set_gateway_chassis, nbctl_lrp_set_gateway_chassis,
NULL, "--may-exist", RW },
+ { "lrp-set-options", 1, INT_MAX, "PORT KEY=VALUE [KEY=VALUE]...",
+ nbctl_pre_lrp_options, nbctl_lrp_set_options, NULL, "", RW },
{ "lrp-del-gateway-chassis", 2, 2, "PORT CHASSIS",
nbctl_pre_lrp_del_gateway_chassis, nbctl_lrp_del_gateway_chassis,
NULL, "", RW },
@@ -6949,12 +7064,13 @@ static const struct ctl_command_syntax nbctl_commands[] = {
/* logical router route commands. */
{ "lr-route-add", 3, 4, "ROUTER PREFIX NEXTHOP [PORT]",
nbctl_pre_lr_route_add, nbctl_lr_route_add, NULL,
- "--may-exist,--ecmp,--ecmp-symmetric-reply,--policy=,--bfd?", RW },
+ "--may-exist,--ecmp,--ecmp-symmetric-reply,--policy=,--route-table=,--bfd?",
+ RW },
{ "lr-route-del", 1, 4, "ROUTER [PREFIX [NEXTHOP [PORT]]]",
nbctl_pre_lr_route_del, nbctl_lr_route_del, NULL,
- "--if-exists,--policy=", RW },
+ "--if-exists,--policy=,--route-table=", RW },
{ "lr-route-list", 1, 1, "ROUTER", nbctl_pre_lr_route_list,
- nbctl_lr_route_list, NULL, "", RO },
+ nbctl_lr_route_list, NULL, "--route-table=", RO },
/* Policy commands */
{ "lr-policy-add", 4, INT_MAX,