Skip to content

Commit

Permalink
ovn-northd: Store ETH address of router inport in xreg0.
Browse files Browse the repository at this point in the history
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@ovn.org>
Signed-off-by: Dumitru Ceara <dceara@redhat.com>
Signed-off-by: Numan Siddique <numans@ovn.org>

(cherry-picked from master commit fa07916)
  • Loading branch information
dceara authored and numansiddique committed Aug 10, 2020
1 parent d6733e5 commit 763b588
Show file tree
Hide file tree
Showing 3 changed files with 235 additions and 80 deletions.
22 changes: 12 additions & 10 deletions northd/ovn-northd.8.xml
Expand Up @@ -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> &amp;&amp; (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>
Expand All @@ -1479,7 +1481,7 @@ output;
a priority-50 flow that matches <code>inport == <var>GW</var>
&amp;&amp; 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>
Expand Down Expand Up @@ -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>;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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>;
Expand Down Expand Up @@ -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>;
Expand Down
153 changes: 83 additions & 70 deletions northd/ovn-northd.c
Expand Up @@ -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]"
Expand All @@ -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} | | |
* +-----+--------------------------+---+-----------------+
*
*/

Expand Down Expand Up @@ -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",
Expand All @@ -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
Expand Down Expand Up @@ -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,
Expand All @@ -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);

Expand All @@ -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));
Expand Down Expand Up @@ -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
Expand All @@ -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) {
Expand Down Expand Up @@ -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_);
Expand Down Expand Up @@ -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"
Expand All @@ -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_);
}

Expand Down

0 comments on commit 763b588

Please sign in to comment.