[ovs-dev] [PATCH ovn branch-20.06 2/7] ovn-northd: Store ETH address of router inport in xreg0.
Dumitru Ceara
dceara at redhat.com
Mon Aug 10 10:53:40 UTC 2020
This helps simplifying logical flows that need to use the port's
configured ETH address:
- ARP responders for owned IPs
- NS responders for owned IPs
Acked-by: Han Zhou <hzhou at ovn.org>
Signed-off-by: Dumitru Ceara <dceara at redhat.com>
(cherry-picked from master commit fa079165e49cb6694717bfc67456167076e19b66)
---
northd/ovn-northd.8.xml | 22 ++++---
northd/ovn-northd.c | 153 +++++++++++++++++++++++++----------------------
tests/ovn-northd.at | 140 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 235 insertions(+), 80 deletions(-)
diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
index 081536a..16f586d 100644
--- a/northd/ovn-northd.8.xml
+++ b/northd/ovn-northd.8.xml
@@ -1459,7 +1459,9 @@ output;
For each enabled router port <var>P</var> with Ethernet address
<var>E</var>, a priority-50 flow that matches <code>inport ==
<var>P</var> && (eth.mcast || eth.dst ==
- <var>E</var></code>), with action <code>next;</code>.
+ <var>E</var></code>), stores the router port ethernet address
+ and advances to next table, with action
+ <code>xreg0[0..47]=E; next;</code>.
</p>
<p>
@@ -1479,7 +1481,7 @@ output;
a priority-50 flow that matches <code>inport == <var>GW</var>
&& eth.dst == <var>E</var></code>, where <var>GW</var>
is the logical router gateway port, with action
- <code>next;</code>.
+ <code>xreg0[0..47]=E; next;</code>.
</p>
<p>
@@ -1742,10 +1744,10 @@ next;
<pre>
eth.dst = eth.src;
-eth.src = <var>E</var>;
+eth.src = xreg0[0..47];
arp.op = 2; /* ARP reply. */
arp.tha = arp.sha;
-arp.sha = <var>E</var>;
+arp.sha = xreg0[0..47];
arp.tpa = arp.spa;
arp.spa = <var>A</var>;
outport = <var>P</var>;
@@ -1794,10 +1796,10 @@ output;
<pre>
nd_na_router {
- eth.src = <var>E</var>;
+ eth.src = xreg0[0..47];
ip6.src = <var>A</var>;
nd.target = <var>A</var>;
- nd.tll = <var>E</var>;
+ nd.tll = xreg0[0..47];
outport = inport;
flags.loopback = 1;
output;
@@ -1834,10 +1836,10 @@ nd_na_router {
<pre>
eth.dst = eth.src;
-eth.src = <var>E</var>;
+eth.src = xreg0[0..47];
arp.op = 2; /* ARP reply. */
arp.tha = arp.sha;
-arp.sha = <var>E</var>;
+arp.sha = xreg0[0..47];
arp.tpa = arp.spa;
arp.spa = <var>A</var>;
outport = <var>P</var>;
@@ -1866,8 +1868,8 @@ output;
<pre>
eth.dst = eth.src;
nd_na {
- eth.src = <var>E</var>;
- nd.tll = <var>E</var>;
+ eth.src = xreg0[0..47];
+ nd.tll = xreg0[0..47];
ip6.src = <var>A</var>;
nd.target = <var>A</var>;
outport = <var>P</var>;
diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
index a1448dd..6a28864 100644
--- a/northd/ovn-northd.c
+++ b/northd/ovn-northd.c
@@ -222,6 +222,11 @@ enum ovn_stage {
#define REGBIT_LOOKUP_NEIGHBOR_RESULT "reg9[2]"
#define REGBIT_SKIP_LOOKUP_NEIGHBOR "reg9[3]"
+/* Register to store the eth address associated to a router port for packets
+ * received in S_ROUTER_IN_ADMISSION.
+ */
+#define REG_INPORT_ETH_ADDR "xreg0[0..47]"
+
/* Register for ECMP bucket selection. */
#define REG_ECMP_GROUP_ID "reg8[0..15]"
#define REG_ECMP_MEMBER_ID "reg8[16..31]"
@@ -245,36 +250,42 @@ enum ovn_stage {
* +---------+-------------------------------------+
*
* Logical Router pipeline:
- * +-----+--------------------------+---+---------------+
- * | R0 | REGBIT_ND_RA_OPTS_RESULT | | |
- * | | (= IN_ND_RA_OPTIONS) | | |
- * | | NEXT_HOP_IPV4 | X | |
- * | | (>= IP_INPUT) | X | |
- * +-----+--------------------------+ R | |
- * | R1 | SRC_IPV4 for ARP-REQ | E | NEXT_HOP_IPV6 |
- * | | (>= IP_INPUT) | G | (>= IP_INPUT) |
- * +-----+--------------------------+ 0 | |
- * | R2 | UNUSED | | |
- * +-----+--------------------------+ | |
- * | R3 | UNUSED | | |
- * +-----+--------------------------+---+---------------+
- * | R4 | UNUSED | | |
- * +-----+--------------------------+ X | |
- * | R5 | UNUSED | X |SRC_IPV6 for NS|
- * +-----+--------------------------+ R | (>= IP_INPUT) |
- * | R6 | UNUSED | E | |
- * +-----+--------------------------+ G | |
- * | R7 | UNUSED | 1 | |
- * +-----+--------------------------+---+---------------+
- * | R8 | ECMP_GROUP_ID |
- * | | ECMP_MEMBER_ID |
- * +-----+--------------------------+
- * | | REGBIT_{ |
- * | | EGRESS_LOOPBACK/ |
- * | R9 | PKT_LARGER/ |
- * | | LOOKUP_NEIGHBOR_RESULT/|
- * | | SKIP_LOOKUP_NEIGHBOR} |
- * +-----+--------------------------+
+ * +-----+--------------------------+---+-----------------+---+---------------+
+ * | R0 | REGBIT_ND_RA_OPTS_RESULT | | | | |
+ * | | (= IN_ND_RA_OPTIONS) | X | | | |
+ * | | NEXT_HOP_IPV4 | R | | | |
+ * | | (>= IP_INPUT) | E | INPORT_ETH_ADDR | X | |
+ * +-----+--------------------------+ G | (< IP_INPUT) | X | |
+ * | R1 | SRC_IPV4 for ARP-REQ | 0 | | R | |
+ * | | (>= IP_INPUT) | | | E | NEXT_HOP_IPV6 |
+ * +-----+--------------------------+---+-----------------+ G | (>= IP_INPUT) |
+ * | R2 | UNUSED | X | | 0 | |
+ * | | | R | | | |
+ * +-----+--------------------------+ E | UNUSED | | |
+ * | R3 | UNUSED | G | | | |
+ * | | | 1 | | | |
+ * +-----+--------------------------+---+-----------------+---+---------------+
+ * | R4 | UNUSED | X | | | |
+ * | | | R | | | |
+ * +-----+--------------------------+ E | UNUSED | X | |
+ * | R5 | UNUSED | G | | X | |
+ * | | | 2 | | R |SRC_IPV6 for NS|
+ * +-----+--------------------------+---+-----------------+ E | (>= IP_INPUT) |
+ * | R6 | UNUSED | X | | G | |
+ * | | | R | | 1 | |
+ * +-----+--------------------------+ E | UNUSED | | |
+ * | R7 | UNUSED | G | | | |
+ * | | | 3 | | | |
+ * +-----+--------------------------+---+-----------------+---+---------------+
+ * | R8 | ECMP_GROUP_ID | | |
+ * | | ECMP_MEMBER_ID | X | |
+ * +-----+--------------------------+ R | |
+ * | | REGBIT_{ | E | |
+ * | | EGRESS_LOOPBACK/ | G | UNUSED |
+ * | R9 | PKT_LARGER/ | 4 | |
+ * | | LOOKUP_NEIGHBOR_RESULT/| | |
+ * | | SKIP_LOOKUP_NEIGHBOR} | | |
+ * +-----+--------------------------+---+-----------------+
*
*/
@@ -8005,10 +8016,19 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
continue;
}
+ /* Store the ethernet address of the port receiving the packet.
+ * This will save us from having to match on inport further down in
+ * the pipeline.
+ */
+ ds_clear(&actions);
+ ds_put_format(&actions, REG_INPORT_ETH_ADDR " = %s; next;",
+ op->lrp_networks.ea_s);
+
ds_clear(&match);
ds_put_format(&match, "eth.mcast && inport == %s", op->json_key);
ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_ADMISSION, 50,
- ds_cstr(&match), "next;", &op->nbrp->header_);
+ ds_cstr(&match), ds_cstr(&actions),
+ &op->nbrp->header_);
ds_clear(&match);
ds_put_format(&match, "eth.dst == %s && inport == %s",
@@ -8021,7 +8041,8 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
op->od->l3redirect_port->json_key);
}
ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_ADMISSION, 50,
- ds_cstr(&match), "next;", &op->nbrp->header_);
+ ds_cstr(&match), ds_cstr(&actions),
+ &op->nbrp->header_);
}
/* Logical router ingress table 1: LOOKUP_NEIGHBOR and
@@ -8288,17 +8309,15 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
ds_clear(&actions);
ds_put_format(&actions,
"eth.dst = eth.src; "
- "eth.src = %s; "
+ "eth.src = " REG_INPORT_ETH_ADDR "; "
"arp.op = 2; /* ARP reply */ "
"arp.tha = arp.sha; "
- "arp.sha = %s; "
+ "arp.sha = " REG_INPORT_ETH_ADDR "; "
"arp.tpa = arp.spa; "
"arp.spa = %s; "
"outport = %s; "
"flags.loopback = 1; "
"output;",
- op->lrp_networks.ea_s,
- op->lrp_networks.ea_s,
op->lrp_networks.ipv4_addrs[i].addr_s,
op->json_key);
ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90,
@@ -8325,17 +8344,15 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
ds_clear(&actions);
ds_put_format(&actions,
"eth.dst = eth.src; "
- "eth.src = %s; "
+ "eth.src = " REG_INPORT_ETH_ADDR "; "
"arp.op = 2; /* ARP reply */ "
"arp.tha = arp.sha; "
- "arp.sha = %s; "
+ "arp.sha = " REG_INPORT_ETH_ADDR "; "
"arp.tpa = arp.spa; "
"arp.spa = %s; "
"outport = %s; "
"flags.loopback = 1; "
"output;",
- op->lrp_networks.ea_s,
- op->lrp_networks.ea_s,
ip_address,
op->json_key);
@@ -8356,18 +8373,16 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
ds_clear(&actions);
ds_put_format(&actions,
"nd_na { "
- "eth.src = %s; "
+ "eth.src = " REG_INPORT_ETH_ADDR "; "
"ip6.src = %s; "
"nd.target = %s; "
- "nd.tll = %s; "
+ "nd.tll = " REG_INPORT_ETH_ADDR "; "
"outport = inport; "
"flags.loopback = 1; "
"output; "
"};",
- op->lrp_networks.ea_s,
ip_address,
- ip_address,
- op->lrp_networks.ea_s);
+ ip_address);
ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90,
ds_cstr(&match), ds_cstr(&actions));
@@ -8490,18 +8505,14 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
nat->logical_port);
} else {
if (is_v6) {
- ds_put_format(&actions,
- "eth.src = %s; "
- "nd.tll = %s; ",
- op->lrp_networks.ea_s,
- op->lrp_networks.ea_s);
+ ds_put_cstr(&actions,
+ "eth.src = " REG_INPORT_ETH_ADDR "; "
+ "nd.tll = " REG_INPORT_ETH_ADDR "; ");
} else {
- ds_put_format(&actions,
- "eth.src = %s; "
- "arp.sha = %s; ",
- op->lrp_networks.ea_s,
- op->lrp_networks.ea_s);
+ ds_put_cstr(&actions,
+ "eth.src = "REG_INPORT_ETH_ADDR "; "
+ "arp.sha = " REG_INPORT_ETH_ADDR "; ");
}
/* Traffic with eth.src = l3dgw_port->lrp_networks.ea_s
* should only be sent from the "redirect-chassis", so that
@@ -8515,17 +8526,13 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
}
} else {
if (is_v6) {
- ds_put_format(&actions,
- "eth.src = %s; "
- "nd.tll = %s; ",
- op->lrp_networks.ea_s,
- op->lrp_networks.ea_s);
+ ds_put_cstr(&actions,
+ "eth.src = " REG_INPORT_ETH_ADDR "; "
+ "nd.tll = " REG_INPORT_ETH_ADDR "; ");
} else {
ds_put_format(&actions,
- "eth.src = %s; "
- "arp.sha = %s; ",
- op->lrp_networks.ea_s,
- op->lrp_networks.ea_s);
+ "eth.src = " REG_INPORT_ETH_ADDR "; "
+ "arp.sha = " REG_INPORT_ETH_ADDR "; ");
}
}
if (is_v6) {
@@ -8743,18 +8750,16 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
ds_clear(&actions);
ds_put_format(&actions,
"nd_na_router { "
- "eth.src = %s; "
+ "eth.src = " REG_INPORT_ETH_ADDR "; "
"ip6.src = %s; "
"nd.target = %s; "
- "nd.tll = %s; "
+ "nd.tll = " REG_INPORT_ETH_ADDR "; "
"outport = inport; "
"flags.loopback = 1; "
"output; "
"};",
- op->lrp_networks.ea_s,
- op->lrp_networks.ipv6_addrs[i].addr_s,
op->lrp_networks.ipv6_addrs[i].addr_s,
- op->lrp_networks.ea_s);
+ op->lrp_networks.ipv6_addrs[i].addr_s);
ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90,
ds_cstr(&match), ds_cstr(&actions),
&op->nbrp->header_);
@@ -9256,6 +9261,14 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
* on the l3dgw_port instance where nat->logical_port is
* resident. */
if (distributed) {
+ /* Store the ethernet address of the port receiving the packet.
+ * This will save us from having to match on inport further
+ * down in the pipeline.
+ */
+ ds_clear(&actions);
+ ds_put_format(&actions, REG_INPORT_ETH_ADDR " = %s; next;",
+ od->l3dgw_port->lrp_networks.ea_s);
+
ds_clear(&match);
ds_put_format(&match,
"eth.dst == "ETH_ADDR_FMT" && inport == %s"
@@ -9264,7 +9277,7 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
od->l3dgw_port->json_key,
nat->logical_port);
ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ADMISSION, 50,
- ds_cstr(&match), "next;",
+ ds_cstr(&match), ds_cstr(&actions),
&nat->header_);
}
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
index 87eb42e..a03dbf4 100644
--- a/tests/ovn-northd.at
+++ b/tests/ovn-northd.at
@@ -1624,3 +1624,143 @@ AT_CHECK([ovn-sbctl lflow-list | grep "ls_out_pre_lb.*priority=100" | grep reg0
])
AT_CLEANUP
+
+AT_SETUP([ovn -- check router ARP/NS responder])
+ovn_start
+
+ovn-sbctl chassis-add ch geneve 127.0.0.1
+
+ovn-nbctl lr-add lr
+ovn-nbctl lrp-add lr lrp-public 00:00:00:00:01:00 43.43.43.1/24
+ovn-nbctl lrp-add lr lrp 00:00:00:00:00:01 42.42.42.1/24
+
+ovn-nbctl ls-add ls
+ovn-nbctl lsp-add ls ls-rp
+ovn-nbctl lsp-set-type ls-rp router
+ovn-nbctl lsp-set-addresses ls-rp router
+ovn-nbctl lsp-set-options ls-rp router-port=lrp
+ovn-nbctl lsp-add ls ls-vm
+
+ovn-nbctl set logical_router lr options:chassis=ch
+ovn-nbctl lr-nat-add lr dnat_and_snat 43.43.43.2 42.42.42.2
+ovn-nbctl lr-nat-add lr dnat 43.43.43.3 42.42.42.3
+ovn-nbctl lr-nat-add lr dnat_and_snat 43.43.43.4 42.42.42.4 ls-vm 00:00:00:00:00:02
+
+ovn-nbctl --wait=sb sync
+
+# Ingress router port ETH address is stored in lr_in_admission.
+AT_CHECK([ovn-sbctl lflow-list | grep -E "lr_in_admission.*xreg0\[[0..47\]]" | sort], [0], [dnl
+ table=0 (lr_in_admission ), priority=50 , dnl
+match=(eth.dst == 00:00:00:00:00:01 && inport == "lrp"), dnl
+action=(xreg0[[0..47]] = 00:00:00:00:00:01; next;)
+ table=0 (lr_in_admission ), priority=50 , dnl
+match=(eth.dst == 00:00:00:00:01:00 && inport == "lrp-public"), dnl
+action=(xreg0[[0..47]] = 00:00:00:00:01:00; next;)
+ table=0 (lr_in_admission ), priority=50 , dnl
+match=(eth.mcast && inport == "lrp"), dnl
+action=(xreg0[[0..47]] = 00:00:00:00:00:01; next;)
+ table=0 (lr_in_admission ), priority=50 , dnl
+match=(eth.mcast && inport == "lrp-public"), dnl
+action=(xreg0[[0..47]] = 00:00:00:00:01:00; next;)
+])
+
+# Ingress router port ETH address is used for ARP reply/NA in lr_in_ip_input.
+AT_CHECK([ovn-sbctl lflow-list | grep -E "lr_in_ip_input.*priority=90" | grep "arp\|nd" | sort], [0], [dnl
+ table=3 (lr_in_ip_input ), priority=90 , dnl
+match=(inport == "lrp" && arp.spa == 42.42.42.0/24 && arp.tpa == 42.42.42.1 && arp.op == 1), dnl
+action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa; arp.spa = 42.42.42.1; outport = "lrp"; flags.loopback = 1; output;)
+ table=3 (lr_in_ip_input ), priority=90 , dnl
+match=(inport == "lrp" && arp.tpa == 43.43.43.2 && arp.op == 1), dnl
+action=(eth.dst = eth.src; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; eth.src = xreg0[[0..47]]; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa; arp.spa = 43.43.43.2; outport = "lrp"; flags.loopback = 1; output;)
+ table=3 (lr_in_ip_input ), priority=90 , dnl
+match=(inport == "lrp" && arp.tpa == 43.43.43.3 && arp.op == 1), dnl
+action=(eth.dst = eth.src; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; eth.src = xreg0[[0..47]]; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa; arp.spa = 43.43.43.3; outport = "lrp"; flags.loopback = 1; output;)
+ table=3 (lr_in_ip_input ), priority=90 , dnl
+match=(inport == "lrp" && arp.tpa == 43.43.43.4 && arp.op == 1), dnl
+action=(eth.dst = eth.src; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; eth.src = xreg0[[0..47]]; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa; arp.spa = 43.43.43.4; outport = "lrp"; flags.loopback = 1; output;)
+ table=3 (lr_in_ip_input ), priority=90 , dnl
+match=(inport == "lrp" && nd_ns && ip6.dst == {fe80::200:ff:fe00:1, ff02::1:ff00:1} && nd.target == fe80::200:ff:fe00:1), dnl
+action=(nd_na_router { eth.src = xreg0[[0..47]]; ip6.src = fe80::200:ff:fe00:1; nd.target = fe80::200:ff:fe00:1; nd.tll = xreg0[[0..47]]; outport = inport; flags.loopback = 1; output; };)
+ table=3 (lr_in_ip_input ), priority=90 , dnl
+match=(inport == "lrp-public" && arp.spa == 43.43.43.0/24 && arp.tpa == 43.43.43.1 && arp.op == 1), dnl
+action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa; arp.spa = 43.43.43.1; outport = "lrp-public"; flags.loopback = 1; output;)
+ table=3 (lr_in_ip_input ), priority=90 , dnl
+match=(inport == "lrp-public" && arp.tpa == 43.43.43.2 && arp.op == 1), dnl
+action=(eth.dst = eth.src; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; eth.src = xreg0[[0..47]]; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa; arp.spa = 43.43.43.2; outport = "lrp-public"; flags.loopback = 1; output;)
+ table=3 (lr_in_ip_input ), priority=90 , dnl
+match=(inport == "lrp-public" && arp.tpa == 43.43.43.3 && arp.op == 1), dnl
+action=(eth.dst = eth.src; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; eth.src = xreg0[[0..47]]; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa; arp.spa = 43.43.43.3; outport = "lrp-public"; flags.loopback = 1; output;)
+ table=3 (lr_in_ip_input ), priority=90 , dnl
+match=(inport == "lrp-public" && arp.tpa == 43.43.43.4 && arp.op == 1), dnl
+action=(eth.dst = eth.src; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; eth.src = xreg0[[0..47]]; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa; arp.spa = 43.43.43.4; outport = "lrp-public"; flags.loopback = 1; output;)
+ table=3 (lr_in_ip_input ), priority=90 , dnl
+match=(inport == "lrp-public" && nd_ns && ip6.dst == {fe80::200:ff:fe00:100, ff02::1:ff00:100} && nd.target == fe80::200:ff:fe00:100), dnl
+action=(nd_na_router { eth.src = xreg0[[0..47]]; ip6.src = fe80::200:ff:fe00:100; nd.target = fe80::200:ff:fe00:100; nd.tll = xreg0[[0..47]]; outport = inport; flags.loopback = 1; output; };)
+])
+
+# xreg0[0..47] isn't used anywhere else.
+AT_CHECK([ovn-sbctl lflow-list | grep "xreg0\[[0..47\]]" | grep -vE 'lr_in_admission|lr_in_ip_input'], [1], [])
+
+# Test chassis redirect port.
+ovn-nbctl remove logical_router lr options chassis
+ovn-nbctl lrp-set-gateway-chassis lrp-public ch
+ovn-nbctl --wait=sb sync
+
+# Ingress router port ETH address is stored in lr_in_admission.
+AT_CHECK([ovn-sbctl lflow-list | grep -E "lr_in_admission.*xreg0\[[0..47\]]" | sort], [0], [dnl
+ table=0 (lr_in_admission ), priority=50 , dnl
+match=(eth.dst == 00:00:00:00:00:01 && inport == "lrp"), dnl
+action=(xreg0[[0..47]] = 00:00:00:00:00:01; next;)
+ table=0 (lr_in_admission ), priority=50 , dnl
+match=(eth.dst == 00:00:00:00:00:02 && inport == "lrp-public" && is_chassis_resident("ls-vm")), dnl
+action=(xreg0[[0..47]] = 00:00:00:00:01:00; next;)
+ table=0 (lr_in_admission ), priority=50 , dnl
+match=(eth.dst == 00:00:00:00:01:00 && inport == "lrp-public" && is_chassis_resident("cr-lrp-public")), dnl
+action=(xreg0[[0..47]] = 00:00:00:00:01:00; next;)
+ table=0 (lr_in_admission ), priority=50 , dnl
+match=(eth.mcast && inport == "lrp"), dnl
+action=(xreg0[[0..47]] = 00:00:00:00:00:01; next;)
+ table=0 (lr_in_admission ), priority=50 , dnl
+match=(eth.mcast && inport == "lrp-public"), dnl
+action=(xreg0[[0..47]] = 00:00:00:00:01:00; next;)
+])
+
+# Ingress router port is used for ARP reply/NA in lr_in_ip_input.
+# xxreg0[0..47] is used unless external_mac is set.
+AT_CHECK([ovn-sbctl lflow-list | grep -E "lr_in_ip_input.*priority=90" | grep "arp\|nd" | sort], [0], [dnl
+ table=3 (lr_in_ip_input ), priority=90 , dnl
+match=(inport == "lrp" && arp.spa == 42.42.42.0/24 && arp.tpa == 42.42.42.1 && arp.op == 1), dnl
+action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa; arp.spa = 42.42.42.1; outport = "lrp"; flags.loopback = 1; output;)
+ table=3 (lr_in_ip_input ), priority=90 , dnl
+match=(inport == "lrp" && arp.tpa == 43.43.43.2 && arp.op == 1), dnl
+action=(eth.dst = eth.src; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; eth.src = xreg0[[0..47]]; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa; arp.spa = 43.43.43.2; outport = "lrp"; flags.loopback = 1; output;)
+ table=3 (lr_in_ip_input ), priority=90 , dnl
+match=(inport == "lrp" && arp.tpa == 43.43.43.3 && arp.op == 1), dnl
+action=(eth.dst = eth.src; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; eth.src = xreg0[[0..47]]; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa; arp.spa = 43.43.43.3; outport = "lrp"; flags.loopback = 1; output;)
+ table=3 (lr_in_ip_input ), priority=90 , dnl
+match=(inport == "lrp" && arp.tpa == 43.43.43.4 && arp.op == 1), dnl
+action=(eth.dst = eth.src; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; eth.src = xreg0[[0..47]]; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa; arp.spa = 43.43.43.4; outport = "lrp"; flags.loopback = 1; output;)
+ table=3 (lr_in_ip_input ), priority=90 , dnl
+match=(inport == "lrp" && nd_ns && ip6.dst == {fe80::200:ff:fe00:1, ff02::1:ff00:1} && nd.target == fe80::200:ff:fe00:1), dnl
+action=(nd_na_router { eth.src = xreg0[[0..47]]; ip6.src = fe80::200:ff:fe00:1; nd.target = fe80::200:ff:fe00:1; nd.tll = xreg0[[0..47]]; outport = inport; flags.loopback = 1; output; };)
+ table=3 (lr_in_ip_input ), priority=90 , dnl
+match=(inport == "lrp-public" && arp.spa == 43.43.43.0/24 && arp.tpa == 43.43.43.1 && arp.op == 1), dnl
+action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa; arp.spa = 43.43.43.1; outport = "lrp-public"; flags.loopback = 1; output;)
+ table=3 (lr_in_ip_input ), priority=90 , dnl
+match=(inport == "lrp-public" && arp.tpa == 43.43.43.2 && arp.op == 1 && is_chassis_resident("cr-lrp-public")), dnl
+action=(eth.dst = eth.src; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; eth.src = xreg0[[0..47]]; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa; arp.spa = 43.43.43.2; outport = "lrp-public"; flags.loopback = 1; output;)
+ table=3 (lr_in_ip_input ), priority=90 , dnl
+match=(inport == "lrp-public" && arp.tpa == 43.43.43.3 && arp.op == 1 && is_chassis_resident("cr-lrp-public")), dnl
+action=(eth.dst = eth.src; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; eth.src = xreg0[[0..47]]; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa; arp.spa = 43.43.43.3; outport = "lrp-public"; flags.loopback = 1; output;)
+ table=3 (lr_in_ip_input ), priority=90 , dnl
+match=(inport == "lrp-public" && arp.tpa == 43.43.43.4 && arp.op == 1 && is_chassis_resident("ls-vm")), dnl
+action=(eth.dst = eth.src; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; eth.src = 00:00:00:00:00:02; arp.sha = 00:00:00:00:00:02; arp.tpa = arp.spa; arp.spa = 43.43.43.4; outport = "lrp-public"; flags.loopback = 1; output;)
+ table=3 (lr_in_ip_input ), priority=90 , dnl
+match=(inport == "lrp-public" && nd_ns && ip6.dst == {fe80::200:ff:fe00:100, ff02::1:ff00:100} && nd.target == fe80::200:ff:fe00:100 && is_chassis_resident("cr-lrp-public")), dnl
+action=(nd_na_router { eth.src = xreg0[[0..47]]; ip6.src = fe80::200:ff:fe00:100; nd.target = fe80::200:ff:fe00:100; nd.tll = xreg0[[0..47]]; outport = inport; flags.loopback = 1; output; };)
+])
+
+# xreg0[0..47] isn't used anywhere else.
+AT_CHECK([ovn-sbctl lflow-list | grep "xreg0\[[0..47\]]" | grep -vE 'lr_in_admission|lr_in_ip_input'], [1], [])
+
+AT_CLEANUP
More information about the dev
mailing list