[ovs-dev] [PATCH ovn branch-20.06 3/7] ovn-northd: Refactor ARP/NS responder in router pipeline.
Dumitru Ceara
dceara at redhat.com
Mon Aug 10 10:53:51 UTC 2020
Add functions to build the ARP/NS responder flows for table
S_ROUTER_IN_IP_INPUT and use them in all places where responder
flows are created.
Acked-by: Han Zhou <hzhou at ovn.org>
Signed-off-by: Dumitru Ceara <dceara at redhat.com>
(cherry-picked from master commit d4ce368f1d3757fafafc7a7acd768e0c0ee3b30a)
---
northd/ovn-northd.8.xml | 8 +
northd/ovn-northd.c | 315 +++++++++++++++++++++--------------------------
tests/ovn-northd.at | 72 +++++------
3 files changed, 182 insertions(+), 213 deletions(-)
diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
index 16f586d..b4f45ab 100644
--- a/northd/ovn-northd.8.xml
+++ b/northd/ovn-northd.8.xml
@@ -1750,7 +1750,7 @@ arp.tha = arp.sha;
arp.sha = xreg0[0..47];
arp.tpa = arp.spa;
arp.spa = <var>A</var>;
-outport = <var>P</var>;
+outport = inport;
flags.loopback = 1;
output;
</pre>
@@ -1842,7 +1842,7 @@ arp.tha = arp.sha;
arp.sha = xreg0[0..47];
arp.tpa = arp.spa;
arp.spa = <var>A</var>;
-outport = <var>P</var>;
+outport = inport;
flags.loopback = 1;
output;
</pre>
@@ -1872,7 +1872,7 @@ nd_na {
nd.tll = xreg0[0..47];
ip6.src = <var>A</var>;
nd.target = <var>A</var>;
- outport = <var>P</var>;
+ outport = inport;
flags.loopback = 1;
output;
}
@@ -2542,7 +2542,7 @@ reg8[0..15] = 0;
xxreg0 = <var>G</var>;
xxreg1 = <var>A</var>;
eth.src = <var>E</var>;
-outport = <var>P</var>;
+outport = inport;
flags.loopback = 1;
next;
</pre>
diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
index 6a28864..88538e2 100644
--- a/northd/ovn-northd.c
+++ b/northd/ovn-northd.c
@@ -7973,6 +7973,106 @@ lrouter_nat_is_stateless(const struct nbrec_nat *nat)
return false;
}
+/* Builds the logical flow that replies to ARP requests for an 'ip_address'
+ * owned by the router. The flow is inserted in table S_ROUTER_IN_IP_INPUT
+ * with the given priority.
+ */
+static void
+build_lrouter_arp_flow(struct ovn_datapath *od, struct ovn_port *op,
+ const char *ip_address, const char *eth_addr,
+ struct ds *extra_match, uint16_t priority,
+ const struct ovsdb_idl_row *hint,
+ struct hmap *lflows)
+{
+ struct ds match = DS_EMPTY_INITIALIZER;
+ struct ds actions = DS_EMPTY_INITIALIZER;
+
+ if (op) {
+ ds_put_format(&match, "inport == %s && ", op->json_key);
+ }
+
+ ds_put_format(&match, "arp.op == 1 && arp.tpa == %s", ip_address);
+
+ if (extra_match && ds_last(extra_match) != EOF) {
+ ds_put_format(&match, " && %s", ds_cstr(extra_match));
+ }
+ ds_put_format(&actions,
+ "eth.dst = eth.src; "
+ "eth.src = %s; "
+ "arp.op = 2; /* ARP reply */ "
+ "arp.tha = arp.sha; "
+ "arp.sha = %s; "
+ "arp.tpa = arp.spa; "
+ "arp.spa = %s; "
+ "outport = inport; "
+ "flags.loopback = 1; "
+ "output;",
+ eth_addr,
+ eth_addr,
+ ip_address);
+
+ ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_IP_INPUT, priority,
+ ds_cstr(&match), ds_cstr(&actions), hint);
+
+ ds_destroy(&match);
+ ds_destroy(&actions);
+}
+
+/* Builds the logical flow that replies to NS requests for an 'ip_address'
+ * owned by the router. The flow is inserted in table S_ROUTER_IN_IP_INPUT
+ * with the given priority. If 'sn_ip_address' is non-NULL, requests are
+ * restricted only to packets with IP destination 'ip_address' or
+ * 'sn_ip_address'.
+ */
+static void
+build_lrouter_nd_flow(struct ovn_datapath *od, struct ovn_port *op,
+ const char *action, const char *ip_address,
+ const char *sn_ip_address, const char *eth_addr,
+ struct ds *extra_match, uint16_t priority,
+ const struct ovsdb_idl_row *hint,
+ struct hmap *lflows)
+{
+ struct ds match = DS_EMPTY_INITIALIZER;
+ struct ds actions = DS_EMPTY_INITIALIZER;
+
+ if (op) {
+ ds_put_format(&match, "inport == %s && ", op->json_key);
+ }
+
+ if (sn_ip_address) {
+ ds_put_format(&match, "ip6.dst == {%s, %s} && ",
+ ip_address, sn_ip_address);
+ }
+
+ ds_put_format(&match, "nd_ns && nd.target == %s", ip_address);
+
+ if (extra_match && ds_last(extra_match) != EOF) {
+ ds_put_format(&match, " && %s", ds_cstr(extra_match));
+ }
+
+ ds_put_format(&actions,
+ "%s { "
+ "eth.src = %s; "
+ "ip6.src = %s; "
+ "nd.target = %s; "
+ "nd.tll = %s; "
+ "outport = inport; "
+ "flags.loopback = 1; "
+ "output; "
+ "};",
+ action,
+ eth_addr,
+ ip_address,
+ ip_address,
+ eth_addr);
+
+ ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_IP_INPUT, priority,
+ ds_cstr(&match), ds_cstr(&actions), hint);
+
+ ds_destroy(&match);
+ ds_destroy(&actions);
+}
+
static void
build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
struct hmap *lflows, struct shash *meter_groups,
@@ -8268,13 +8368,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
* IP address. */
for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) {
ds_clear(&match);
- ds_put_format(&match,
- "inport == %s && arp.spa == %s/%u && arp.tpa == %s"
- " && arp.op == 1",
- op->json_key,
+ ds_put_format(&match, "arp.spa == %s/%u",
op->lrp_networks.ipv4_addrs[i].network_s,
- op->lrp_networks.ipv4_addrs[i].plen,
- op->lrp_networks.ipv4_addrs[i].addr_s);
+ op->lrp_networks.ipv4_addrs[i].plen);
if (op->od->l3dgw_port && op->od->l3redirect_port && op->peer
&& op->peer->od->n_localnet_ports) {
@@ -8306,23 +8402,10 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
}
}
- ds_clear(&actions);
- ds_put_format(&actions,
- "eth.dst = eth.src; "
- "eth.src = " REG_INPORT_ETH_ADDR "; "
- "arp.op = 2; /* ARP reply */ "
- "arp.tha = arp.sha; "
- "arp.sha = " REG_INPORT_ETH_ADDR "; "
- "arp.tpa = arp.spa; "
- "arp.spa = %s; "
- "outport = %s; "
- "flags.loopback = 1; "
- "output;",
- 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,
- ds_cstr(&match), ds_cstr(&actions),
- &op->nbrp->header_);
+ build_lrouter_arp_flow(op->od, op,
+ op->lrp_networks.ipv4_addrs[i].addr_s,
+ REG_INPORT_ETH_ADDR, &match, 90,
+ &op->nbrp->header_, lflows);
}
/* A set to hold all load-balancer vips that need ARP responses. */
@@ -8333,59 +8416,26 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
const char *ip_address;
SSET_FOR_EACH (ip_address, &all_ips_v4) {
ds_clear(&match);
- ds_put_format(&match,
- "inport == %s && arp.tpa == %s && arp.op == 1",
- op->json_key, ip_address);
-
if (op == op->od->l3dgw_port) {
- ds_put_format(&match, " && is_chassis_resident(%s)",
+ ds_put_format(&match, "is_chassis_resident(%s)",
op->od->l3redirect_port->json_key);
}
- ds_clear(&actions);
- ds_put_format(&actions,
- "eth.dst = eth.src; "
- "eth.src = " REG_INPORT_ETH_ADDR "; "
- "arp.op = 2; /* ARP reply */ "
- "arp.tha = arp.sha; "
- "arp.sha = " REG_INPORT_ETH_ADDR "; "
- "arp.tpa = arp.spa; "
- "arp.spa = %s; "
- "outport = %s; "
- "flags.loopback = 1; "
- "output;",
- ip_address,
- op->json_key);
- ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90,
- ds_cstr(&match), ds_cstr(&actions));
+ build_lrouter_arp_flow(op->od, op,
+ ip_address, REG_INPORT_ETH_ADDR,
+ &match, 90, NULL, lflows);
}
SSET_FOR_EACH (ip_address, &all_ips_v6) {
ds_clear(&match);
- ds_put_format(&match,
- "inport == %s && nd_ns && nd.target == %s",
- op->json_key, ip_address);
-
if (op == op->od->l3dgw_port) {
- ds_put_format(&match, " && is_chassis_resident(%s)",
+ ds_put_format(&match, "is_chassis_resident(%s)",
op->od->l3redirect_port->json_key);
}
- ds_clear(&actions);
- ds_put_format(&actions,
- "nd_na { "
- "eth.src = " REG_INPORT_ETH_ADDR "; "
- "ip6.src = %s; "
- "nd.target = %s; "
- "nd.tll = " REG_INPORT_ETH_ADDR "; "
- "outport = inport; "
- "flags.loopback = 1; "
- "output; "
- "};",
- ip_address,
- ip_address);
- ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90,
- ds_cstr(&match), ds_cstr(&actions));
+ build_lrouter_nd_flow(op->od, op, "nd_na",
+ ip_address, NULL, REG_INPORT_ETH_ADDR,
+ &match, 90, NULL, lflows);
}
sset_destroy(&all_ips_v4);
@@ -8441,123 +8491,60 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
continue;
}
+ /* Mac address to use when replying to ARP/NS. */
+ const char *mac_s = REG_INPORT_ETH_ADDR;
+
/* ARP / ND handling for external IP addresses.
*
* DNAT IP addresses are external IP addresses that need ARP
* handling. */
- char addr_s[INET6_ADDRSTRLEN + 1];
ds_clear(&match);
- ds_clear(&actions);
- if (is_v6) {
- /* For ND solicitations, we need to listen for both the
- * unicast IPv6 address and its all-nodes multicast address,
- * but always respond with the unicast IPv6 address. */
- char sn_addr_s[INET6_ADDRSTRLEN + 1];
- struct in6_addr sn_addr;
- in6_addr_solicited_node(&sn_addr, &ipv6);
- ipv6_string_mapped(sn_addr_s, &sn_addr);
- ipv6_string_mapped(addr_s, &ipv6);
-
- ds_put_format(&match, "inport == %s && "
- "nd_ns && ip6.dst == {%s, %s} && nd.target == %s",
- op->json_key, addr_s, sn_addr_s, addr_s);
- ds_put_format(&actions,
- "eth.dst = eth.src; "
- "nd_na { ");
- } else {
- ds_put_format(&match,
- "inport == %s "
- "&& arp.tpa == "IP_FMT" && arp.op == 1",
- op->json_key, IP_ARGS(ip));
-
- ds_put_format(&actions,
- "eth.dst = eth.src; "
- "arp.op = 2; /* ARP reply */ "
- "arp.tha = arp.sha; ");
- }
if (op->od->l3dgw_port && op == op->od->l3dgw_port) {
struct eth_addr mac;
if (nat->external_mac &&
eth_addr_from_string(nat->external_mac, &mac)
&& nat->logical_port) {
/* distributed NAT case, use nat->external_mac */
- if (is_v6) {
- ds_put_format(&actions,
- "eth.src = "ETH_ADDR_FMT"; "
- "nd.tll = "ETH_ADDR_FMT"; ",
- ETH_ADDR_ARGS(mac),
- ETH_ADDR_ARGS(mac));
-
- } else {
- ds_put_format(&actions,
- "eth.src = "ETH_ADDR_FMT"; "
- "arp.sha = "ETH_ADDR_FMT"; ",
- ETH_ADDR_ARGS(mac),
- ETH_ADDR_ARGS(mac));
- }
+ mac_s = nat->external_mac;
/* Traffic with eth.src = nat->external_mac should only be
* sent from the chassis where nat->logical_port is
* resident, so that upstream MAC learning points to the
* correct chassis. Also need to avoid generation of
* multiple ARP responses from different chassis. */
- ds_put_format(&match, " && is_chassis_resident(\"%s\")",
+ ds_put_format(&match, "is_chassis_resident(\"%s\")",
nat->logical_port);
} else {
- if (is_v6) {
- ds_put_cstr(&actions,
- "eth.src = " REG_INPORT_ETH_ADDR "; "
- "nd.tll = " REG_INPORT_ETH_ADDR "; ");
-
- } else {
- ds_put_cstr(&actions,
- "eth.src = "REG_INPORT_ETH_ADDR "; "
- "arp.sha = " REG_INPORT_ETH_ADDR "; ");
- }
+ mac_s = REG_INPORT_ETH_ADDR;
/* Traffic with eth.src = l3dgw_port->lrp_networks.ea_s
* should only be sent from the "redirect-chassis", so that
* upstream MAC learning points to the "redirect-chassis".
* Also need to avoid generation of multiple ARP responses
* from different chassis. */
if (op->od->l3redirect_port) {
- ds_put_format(&match, " && is_chassis_resident(%s)",
+ ds_put_format(&match, "is_chassis_resident(%s)",
op->od->l3redirect_port->json_key);
}
}
- } else {
- if (is_v6) {
- ds_put_cstr(&actions,
- "eth.src = " REG_INPORT_ETH_ADDR "; "
- "nd.tll = " REG_INPORT_ETH_ADDR "; ");
- } else {
- ds_put_format(&actions,
- "eth.src = " REG_INPORT_ETH_ADDR "; "
- "arp.sha = " REG_INPORT_ETH_ADDR "; ");
- }
}
if (is_v6) {
- ds_put_format(&actions,
- "ip6.src = %s; "
- "nd.target = %s; "
- "outport = %s; "
- "flags.loopback = 1; "
- "output; "
- "};",
- addr_s, addr_s, op->json_key);
+ /* For ND solicitations, we need to listen for both the
+ * unicast IPv6 address and its all-nodes multicast address,
+ * but always respond with the unicast IPv6 address. */
+ char sn_addr_s[INET6_ADDRSTRLEN + 1];
+ struct in6_addr sn_addr;
+ in6_addr_solicited_node(&sn_addr, &ipv6);
+ ipv6_string_mapped(sn_addr_s, &sn_addr);
+
+ build_lrouter_nd_flow(op->od, op, "nd_na",
+ nat->external_ip, sn_addr_s,
+ mac_s, &match, 90,
+ &nat->header_, lflows);
} else {
- ds_put_format(&actions,
- "arp.tpa = arp.spa; "
- "arp.spa = "IP_FMT"; "
- "outport = %s; "
- "flags.loopback = 1; "
- "output;",
- IP_ARGS(ip),
- op->json_key);
+ build_lrouter_arp_flow(op->od, op,
+ nat->external_ip, mac_s, &match, 90,
+ &nat->header_, lflows);
}
-
- ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90,
- ds_cstr(&match), ds_cstr(&actions),
- &nat->header_);
}
if (!smap_get(&op->od->nbr->options, "chassis")
@@ -8729,13 +8716,6 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
* router's own IP address. */
for (int i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) {
ds_clear(&match);
- ds_put_format(&match,
- "inport == %s && nd_ns && ip6.dst == {%s, %s} "
- "&& nd.target == %s",
- op->json_key,
- op->lrp_networks.ipv6_addrs[i].addr_s,
- op->lrp_networks.ipv6_addrs[i].sn_addr_s,
- op->lrp_networks.ipv6_addrs[i].addr_s);
if (op->od->l3dgw_port && op == op->od->l3dgw_port
&& op->od->l3redirect_port) {
/* Traffic with eth.src = l3dgw_port->lrp_networks.ea_s
@@ -8743,26 +8723,15 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
* upstream MAC learning points to the "redirect-chassis".
* Also need to avoid generation of multiple ND replies
* from different chassis. */
- ds_put_format(&match, " && is_chassis_resident(%s)",
+ ds_put_format(&match, "is_chassis_resident(%s)",
op->od->l3redirect_port->json_key);
}
- ds_clear(&actions);
- ds_put_format(&actions,
- "nd_na_router { "
- "eth.src = " REG_INPORT_ETH_ADDR "; "
- "ip6.src = %s; "
- "nd.target = %s; "
- "nd.tll = " REG_INPORT_ETH_ADDR "; "
- "outport = inport; "
- "flags.loopback = 1; "
- "output; "
- "};",
- op->lrp_networks.ipv6_addrs[i].addr_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_);
+ build_lrouter_nd_flow(op->od, op, "nd_na_router",
+ op->lrp_networks.ipv6_addrs[i].addr_s,
+ op->lrp_networks.ipv6_addrs[i].sn_addr_s,
+ REG_INPORT_ETH_ADDR, &match, 90,
+ &op->nbrp->header_, lflows);
}
/* UDP/TCP port unreachable */
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
index a03dbf4..a8a2b37 100644
--- a/tests/ovn-northd.at
+++ b/tests/ovn-northd.at
@@ -1667,34 +1667,34 @@ 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;)
+match=(inport == "lrp" && arp.op == 1 && arp.tpa == 42.42.42.1 && arp.spa == 42.42.42.0/24), 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 = inport; 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;)
+match=(inport == "lrp" && arp.op == 1 && arp.tpa == 43.43.43.2), 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.2; outport = inport; 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;)
+match=(inport == "lrp" && arp.op == 1 && arp.tpa == 43.43.43.3), 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.3; outport = inport; 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;)
+match=(inport == "lrp" && arp.op == 1 && arp.tpa == 43.43.43.4), 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.4; outport = inport; 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
+match=(inport == "lrp" && ip6.dst == {fe80::200:ff:fe00:1, ff02::1:ff00:1} && nd_ns && 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;)
+match=(inport == "lrp-public" && arp.op == 1 && arp.tpa == 43.43.43.1 && arp.spa == 43.43.43.0/24), 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 = inport; 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;)
+match=(inport == "lrp-public" && arp.op == 1 && arp.tpa == 43.43.43.2), 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.2; outport = inport; 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;)
+match=(inport == "lrp-public" && arp.op == 1 && arp.tpa == 43.43.43.3), 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.3; outport = inport; 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;)
+match=(inport == "lrp-public" && arp.op == 1 && arp.tpa == 43.43.43.4), 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.4; outport = inport; 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
+match=(inport == "lrp-public" && ip6.dst == {fe80::200:ff:fe00:100, ff02::1:ff00:100} && nd_ns && 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; };)
])
@@ -1729,34 +1729,34 @@ action=(xreg0[[0..47]] = 00:00:00:00:01:00; next;)
# 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;)
+match=(inport == "lrp" && arp.op == 1 && arp.tpa == 42.42.42.1 && arp.spa == 42.42.42.0/24), 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 = inport; 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;)
+match=(inport == "lrp" && arp.op == 1 && arp.tpa == 43.43.43.2), 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.2; outport = inport; 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;)
+match=(inport == "lrp" && arp.op == 1 && arp.tpa == 43.43.43.3), 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.3; outport = inport; 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;)
+match=(inport == "lrp" && arp.op == 1 && arp.tpa == 43.43.43.4), 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.4; outport = inport; 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
+match=(inport == "lrp" && ip6.dst == {fe80::200:ff:fe00:1, ff02::1:ff00:1} && nd_ns && 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;)
+match=(inport == "lrp-public" && arp.op == 1 && arp.tpa == 43.43.43.1 && arp.spa == 43.43.43.0/24), 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 = inport; 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;)
+match=(inport == "lrp-public" && arp.op == 1 && arp.tpa == 43.43.43.2 && is_chassis_resident("cr-lrp-public")), 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.2; outport = inport; 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;)
+match=(inport == "lrp-public" && arp.op == 1 && arp.tpa == 43.43.43.3 && is_chassis_resident("cr-lrp-public")), 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.3; outport = inport; 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;)
+match=(inport == "lrp-public" && arp.op == 1 && arp.tpa == 43.43.43.4 && is_chassis_resident("ls-vm")), dnl
+action=(eth.dst = eth.src; eth.src = 00:00:00:00:00:02; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; arp.sha = 00:00:00:00:00:02; arp.tpa = arp.spa; arp.spa = 43.43.43.4; outport = inport; 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
+match=(inport == "lrp-public" && ip6.dst == {fe80::200:ff:fe00:100, ff02::1:ff00:100} && nd_ns && 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; };)
])
More information about the dev
mailing list