@@ -782,13 +782,15 @@ consider_neighbor_flow(struct ovsdb_idl_index *sbrec_port_binding_by_name,
uint64_t stub[1024 / 8];
struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(stub);
+ uint8_t value = 1;
put_load(mac.ea, sizeof mac.ea, MFF_ETH_DST, 0, 48, &ofpacts);
+ put_load(&value, sizeof value, MFF_LOG_FLAGS, MLF_LOOKUP_MAC_BIT, 1,
+ &ofpacts);
ofctrl_add_flow(flow_table, OFTABLE_MAC_BINDING, 100,
b->header_.uuid.parts[0], &get_arp_match,
&ofpacts, &b->header_.uuid);
ofpbuf_clear(&ofpacts);
- uint8_t value = 1;
put_load(&value, sizeof value, MFF_LOG_FLAGS, MLF_LOOKUP_MAC_BIT, 1,
&ofpacts);
match_set_dl_src(&lookup_arp_match, mac);
@@ -75,9 +75,11 @@ struct ovn_extend_table;
OVNACT(GET_ARP, ovnact_get_mac_bind) \
OVNACT(PUT_ARP, ovnact_put_mac_bind) \
OVNACT(LOOKUP_ARP, ovnact_lookup_mac_bind) \
+ OVNACT(LOOKUP_ARP_IP, ovnact_lookup_mac_bind_ip) \
OVNACT(GET_ND, ovnact_get_mac_bind) \
OVNACT(PUT_ND, ovnact_put_mac_bind) \
OVNACT(LOOKUP_ND, ovnact_lookup_mac_bind) \
+ OVNACT(LOOKUP_ND_IP, ovnact_lookup_mac_bind_ip) \
OVNACT(PUT_DHCPV4_OPTS, ovnact_put_opts) \
OVNACT(PUT_DHCPV6_OPTS, ovnact_put_opts) \
OVNACT(SET_QUEUE, ovnact_set_queue) \
@@ -301,6 +303,14 @@ struct ovnact_lookup_mac_bind {
struct expr_field mac; /* 48-bit Ethernet address. */
};
+/* OVNACT_LOOKUP_ARP_IP, OVNACT_LOOKUP_ND_IP. */
+struct ovnact_lookup_mac_bind_ip {
+ struct ovnact ovnact;
+ struct expr_field dst; /* 1-bit destination field. */
+ struct expr_field port; /* Logical port name. */
+ struct expr_field ip; /* 32-bit or 128-bit IP address. */
+};
+
struct ovnact_gen_option {
const struct gen_opts_map *option;
struct expr_constant_set value;
@@ -1902,6 +1902,110 @@ ovnact_lookup_mac_bind_free(
}
+
+static void format_lookup_mac_bind_ip(
+ const struct ovnact_lookup_mac_bind_ip *lookup_mac,
+ struct ds *s, const char *name)
+{
+ expr_field_format(&lookup_mac->dst, s);
+ ds_put_format(s, " = %s(", name);
+ expr_field_format(&lookup_mac->port, s);
+ ds_put_cstr(s, ", ");
+ expr_field_format(&lookup_mac->ip, s);
+ ds_put_cstr(s, ");");
+}
+
+static void
+format_LOOKUP_ARP_IP(const struct ovnact_lookup_mac_bind_ip *lookup_mac,
+ struct ds *s)
+{
+ format_lookup_mac_bind_ip(lookup_mac, s, "lookup_arp_ip");
+}
+
+static void
+format_LOOKUP_ND_IP(const struct ovnact_lookup_mac_bind_ip *lookup_mac,
+ struct ds *s)
+{
+ format_lookup_mac_bind_ip(lookup_mac, s, "lookup_nd_ip");
+}
+
+static void
+encode_lookup_mac_bind_ip(const struct ovnact_lookup_mac_bind_ip *lookup_mac,
+ enum mf_field_id ip_field,
+ const struct ovnact_encode_params *ep,
+ struct ofpbuf *ofpacts)
+{
+ const struct arg args[] = {
+ { expr_resolve_field(&lookup_mac->port), MFF_LOG_OUTPORT },
+ { expr_resolve_field(&lookup_mac->ip), ip_field },
+ };
+
+ encode_setup_args(args, ARRAY_SIZE(args), ofpacts);
+ init_stack(ofpact_put_STACK_PUSH(ofpacts), MFF_ETH_DST);
+
+ struct mf_subfield dst = expr_resolve_field(&lookup_mac->dst);
+ ovs_assert(dst.field);
+
+ put_load(0, MFF_LOG_FLAGS, MLF_LOOKUP_MAC_BIT, 1, ofpacts);
+ emit_resubmit(ofpacts, ep->mac_bind_ptable);
+
+ struct ofpact_reg_move *orm = ofpact_put_REG_MOVE(ofpacts);
+ orm->dst = dst;
+ orm->src.field = mf_from_id(MFF_LOG_FLAGS);
+ orm->src.ofs = MLF_LOOKUP_MAC_BIT;
+ orm->src.n_bits = 1;
+
+ init_stack(ofpact_put_STACK_POP(ofpacts), MFF_ETH_DST);
+ encode_restore_args(args, ARRAY_SIZE(args), ofpacts);
+}
+
+static void
+encode_LOOKUP_ARP_IP(const struct ovnact_lookup_mac_bind_ip *lookup_mac,
+ const struct ovnact_encode_params *ep,
+ struct ofpbuf *ofpacts)
+{
+ encode_lookup_mac_bind_ip(lookup_mac, MFF_REG0, ep, ofpacts);
+}
+
+static void
+encode_LOOKUP_ND_IP(const struct ovnact_lookup_mac_bind_ip *lookup_mac,
+ const struct ovnact_encode_params *ep,
+ struct ofpbuf *ofpacts)
+{
+ encode_lookup_mac_bind_ip(lookup_mac, MFF_XXREG0, ep, ofpacts);
+}
+
+static void
+parse_lookup_mac_bind_ip(struct action_context *ctx,
+ const struct expr_field *dst,
+ int width,
+ struct ovnact_lookup_mac_bind_ip *lookup_mac)
+{
+ /* Validate that the destination is a 1-bit, modifiable field. */
+ char *error = expr_type_check(dst, 1, true, ctx->scope);
+ if (error) {
+ lexer_error(ctx->lexer, "%s", error);
+ free(error);
+ return;
+ }
+
+ lexer_get(ctx->lexer); /* Skip lookup_arp/lookup_nd. */
+ lexer_get(ctx->lexer); /* Skip '('. * */
+
+ action_parse_field(ctx, 0, false, &lookup_mac->port);
+ lexer_force_match(ctx->lexer, LEX_T_COMMA);
+ action_parse_field(ctx, width, false, &lookup_mac->ip);
+ lexer_force_match(ctx->lexer, LEX_T_RPAREN);
+ lookup_mac->dst = *dst;
+}
+
+static void
+ovnact_lookup_mac_bind_ip_free(
+ struct ovnact_lookup_mac_bind_ip *lookup_mac OVS_UNUSED)
+{
+
+}
+
static void
parse_gen_opt(struct action_context *ctx, struct ovnact_gen_option *o,
@@ -3358,6 +3462,14 @@ parse_set_action(struct action_context *ctx)
&& lexer_lookahead(ctx->lexer) == LEX_T_LPAREN) {
parse_lookup_mac_bind(ctx, &lhs, 128,
ovnact_put_LOOKUP_ND(ctx->ovnacts));
+ } else if (!strcmp(ctx->lexer->token.s, "lookup_arp_ip")
+ && lexer_lookahead(ctx->lexer) == LEX_T_LPAREN) {
+ parse_lookup_mac_bind_ip(ctx, &lhs, 32,
+ ovnact_put_LOOKUP_ARP_IP(ctx->ovnacts));
+ } else if (!strcmp(ctx->lexer->token.s, "lookup_nd_ip")
+ && lexer_lookahead(ctx->lexer) == LEX_T_LPAREN) {
+ parse_lookup_mac_bind_ip(ctx, &lhs, 128,
+ ovnact_put_LOOKUP_ND_IP(ctx->ovnacts));
} else {
parse_assignment_action(ctx, false, &lhs);
}
@@ -1448,6 +1448,34 @@
</p>
</dd>
+ <dt>
+ <code><var>R</var> = lookup_arp_ip(<var>P</var>, <var>A</var>);</code>
+ </dt>
+
+ <dd>
+ <p>
+ <b>Parameters</b>: logical port string field <var>P</var>, 32-bit
+ IP address field <var>A</var>.
+ </p>
+
+ <p>
+ <b>Result</b>: stored to a 1-bit subfield <var>R</var>.
+ </p>
+
+ <p>
+ Looks up <var>A</var> in <var>P</var>'s mac binding table. If an
+ entry is found, stores <code>1</code> in the 1-bit subfield
+ <var>R</var>, else 0.
+ </p>
+
+ <p>
+ <b>Example:</b>
+ <code>
+ reg0[0] = lookup_arp_ip(inport, arp.spa);
+ </code>
+ </p>
+ </dd>
+
<dt><code>nd_ns { <var>action</var>; </code>...<code> };</code></dt>
<dd>
<p>
@@ -1632,6 +1660,33 @@
</p>
</dd>
+ <dt><code><var>R</var> = lookup_nd_ip(<var>P</var>, <var>A</var>);</code>
+ </dt>
+
+ <dd>
+ <p>
+ <b>Parameters</b>: logical port string field <var>P</var>, 128-bit
+ IP address field <var>A</var>.
+ </p>
+
+ <p>
+ <b>Result</b>: stored to a 1-bit subfield <var>R</var>.
+ </p>
+
+ <p>
+ Looks up <var>A</var> in <var>P</var>'s mac binding table. If an
+ entry is found, stores <code>1</code> in the 1-bit subfield
+ <var>R</var>, else 0.
+ </p>
+
+ <p>
+ <b>Example:</b>
+ <code>
+ reg0[0] = lookup_nd_ip(inport, ip6.src);
+ </code>
+ </p>
+ </dd>
+
<dt>
<code><var>R</var> = put_dhcp_opts(<var>D1</var> = <var>V1</var>, <var>D2</var> = <var>V2</var>, ..., <var>Dn</var> = <var>Vn</var>);</code>
</dt>
@@ -1246,6 +1246,31 @@ reg0[0] = lookup_arp(inport, eth.dst);
reg0[0] = lookup_arp(inport, ip4.src, ip4.dst);
Cannot use 32-bit field ip4.dst[0..31] where 48-bit field is required.
+# lookup_arp_ip
+reg0[0] = lookup_arp_ip(inport, ip4.dst);
+ encodes as push:NXM_NX_REG15[],push:NXM_NX_REG0[],push:NXM_OF_IP_DST[],push:NXM_NX_REG14[],pop:NXM_NX_REG15[],pop:NXM_NX_REG0[],push:NXM_OF_ETH_DST[],set_field:0/0x40->reg10,resubmit(,66),move:NXM_NX_REG10[6]->NXM_NX_XXREG0[96],pop:NXM_OF_ETH_DST[],pop:NXM_NX_REG0[],pop:NXM_NX_REG15[]
+ has prereqs eth.type == 0x800
+reg1[1] = lookup_arp_ip(inport, arp.spa);
+ encodes as push:NXM_NX_REG15[],push:NXM_NX_REG0[],push:NXM_OF_ARP_SPA[],push:NXM_NX_REG14[],pop:NXM_NX_REG15[],pop:NXM_NX_REG0[],push:NXM_OF_ETH_DST[],set_field:0/0x40->reg10,resubmit(,66),move:NXM_NX_REG10[6]->NXM_NX_XXREG0[65],pop:NXM_OF_ETH_DST[],pop:NXM_NX_REG0[],pop:NXM_NX_REG15[]
+ has prereqs eth.type == 0x806
+
+lookup_arp_ip;
+ Syntax error at `lookup_arp_ip' expecting action.
+reg0[0] = lookup_arp_ip;
+ Syntax error at `lookup_arp_ip' expecting field name.
+reg0[0] = lookup_arp_ip();
+ Syntax error at `)' expecting field name.
+reg0[0] = lookup_arp_ip(inport);
+ Syntax error at `)' expecting `,'.
+reg0[0] = lookup_arp_ip(inport ip4.dst);
+ Syntax error at `ip4.dst' expecting `,'.
+reg0[0] = lookup_arp_ip(inport, ip4.dst;
+ Syntax error at `;' expecting `)'.
+reg0[0] = lookup_arp_ip(inport, ip4.dst, eth.src;
+ Syntax error at `,' expecting `)'.
+reg0[0] = lookup_arp_ip(inport, eth.dst);
+ Cannot use 48-bit field eth.dst[0..47] where 32-bit field is required.
+
# put_dhcp_opts
reg1[0] = put_dhcp_opts(offerip = 1.2.3.4, router = 10.0.0.1);
encodes as controller(userdata=00.00.00.02.00.00.00.00.00.01.de.10.00.00.00.40.01.02.03.04.03.04.0a.00.00.01,pause)
@@ -1389,6 +1414,31 @@ reg0[0] = lookup_nd(inport, ip4.src, ip4.dst);
reg0[0] = lookup_nd(inport, ip6.src, ip6.dst);
Cannot use 128-bit field ip6.dst[0..127] where 48-bit field is required.
+# lookup_nd_ip
+reg2[0] = lookup_nd_ip(inport, ip6.dst);
+ encodes as push:NXM_NX_REG15[],push:NXM_NX_XXREG0[],push:NXM_NX_IPV6_DST[],push:NXM_NX_REG14[],pop:NXM_NX_REG15[],pop:NXM_NX_XXREG0[],push:NXM_OF_ETH_DST[],set_field:0/0x40->reg10,resubmit(,66),move:NXM_NX_REG10[6]->NXM_NX_XXREG0[32],pop:NXM_OF_ETH_DST[],pop:NXM_NX_XXREG0[],pop:NXM_NX_REG15[]
+ has prereqs eth.type == 0x86dd
+reg3[0] = lookup_nd_ip(inport, nd.target);
+ encodes as push:NXM_NX_REG15[],push:NXM_NX_XXREG0[],push:NXM_NX_ND_TARGET[],push:NXM_NX_REG14[],pop:NXM_NX_REG15[],pop:NXM_NX_XXREG0[],push:NXM_OF_ETH_DST[],set_field:0/0x40->reg10,resubmit(,66),move:NXM_NX_REG10[6]->NXM_NX_XXREG0[0],pop:NXM_OF_ETH_DST[],pop:NXM_NX_XXREG0[],pop:NXM_NX_REG15[]
+ has prereqs (icmp6.type == 0x87 || icmp6.type == 0x88) && eth.type == 0x86dd && ip.proto == 0x3a && (eth.type == 0x800 || eth.type == 0x86dd) && icmp6.code == 0 && eth.type == 0x86dd && ip.proto == 0x3a && (eth.type == 0x800 || eth.type == 0x86dd) && ip.ttl == 0xff && (eth.type == 0x800 || eth.type == 0x86dd)
+
+lookup_nd_ip;
+ Syntax error at `lookup_nd_ip' expecting action.
+reg0[0] = lookup_nd_ip;
+ Syntax error at `lookup_nd_ip' expecting field name.
+reg0[0] = lookup_nd_ip();
+ Syntax error at `)' expecting field name.
+reg0[0] = lookup_nd_ip(inport);
+ Syntax error at `)' expecting `,'.
+reg0[0] = lookup_nd_ip(inport ip6.dst);
+ Syntax error at `ip6.dst' expecting `,'.
+reg0[0] = lookup_nd_ip(inport, ip6.dst;
+ Syntax error at `;' expecting `)'.
+reg0[0] = lookup_nd_ip(inport, eth.dst);
+ Cannot use 48-bit field eth.dst[0..47] where 128-bit field is required.
+reg0[0] = lookup_nd_ip(inport, ip4.src);
+ Cannot use 32-bit field ip4.src[0..31] where 128-bit field is required.
+
# set_queue
set_queue(0);
encodes as set_queue:0
@@ -582,13 +582,13 @@ ovntrace_mac_binding_find(const struct ovntrace_datapath *dp,
static const struct ovntrace_mac_binding *
ovntrace_mac_binding_find_mac_ip(const struct ovntrace_datapath *dp,
uint16_t port_key, const struct in6_addr *ip,
- struct eth_addr mac)
+ struct eth_addr *mac)
{
const struct ovntrace_mac_binding *bind;
HMAP_FOR_EACH_WITH_HASH (bind, node, hash_mac_binding(port_key, ip),
&dp->mac_bindings) {
if (bind->port_key == port_key && ipv6_addr_equals(ip, &bind->ip)
- && eth_addr_equals(bind->mac, mac)) {
+ && (!mac || eth_addr_equals(bind->mac, *mac))) {
return bind;
}
}
@@ -1772,7 +1772,7 @@ execute_lookup_mac_bind(const struct ovnact_lookup_mac_bind *bind,
mf_read_subfield(&mac_sf, uflow, &mac_sv);
const struct ovntrace_mac_binding *binding
- = ovntrace_mac_binding_find_mac_ip(dp, port_key, &ip, mac_sv.mac);
+ = ovntrace_mac_binding_find_mac_ip(dp, port_key, &ip, &mac_sv.mac);
struct mf_subfield dst = expr_resolve_field(&bind->dst);
uint8_t val = 0;
@@ -1791,6 +1791,44 @@ execute_lookup_mac_bind(const struct ovnact_lookup_mac_bind *bind,
}
static void
+execute_lookup_mac_bind_ip(const struct ovnact_lookup_mac_bind_ip *bind,
+ const struct ovntrace_datapath *dp,
+ struct flow *uflow,
+ struct ovs_list *super)
+{
+ /* Get logical port number.*/
+ struct mf_subfield port_sf = expr_resolve_field(&bind->port);
+ ovs_assert(port_sf.n_bits == 32);
+ uint32_t port_key = mf_get_subfield(&port_sf, uflow);
+
+ /* Get IP address. */
+ struct mf_subfield ip_sf = expr_resolve_field(&bind->ip);
+ ovs_assert(ip_sf.n_bits == 32 || ip_sf.n_bits == 128);
+ union mf_subvalue ip_sv;
+ mf_read_subfield(&ip_sf, uflow, &ip_sv);
+ struct in6_addr ip = (ip_sf.n_bits == 32
+ ? in6_addr_mapped_ipv4(ip_sv.ipv4)
+ : ip_sv.ipv6);
+
+ const struct ovntrace_mac_binding *binding
+ = ovntrace_mac_binding_find_mac_ip(dp, port_key, &ip, NULL);
+
+ struct mf_subfield dst = expr_resolve_field(&bind->dst);
+ uint8_t val = 0;
+
+ if (binding) {
+ val = 1;
+ ovntrace_node_append(super, OVNTRACE_NODE_ACTION,
+ "/* MAC binding found. */");
+ } else {
+ ovntrace_node_append(super, OVNTRACE_NODE_ACTION,
+ "/* lookup failed - No MAC binding. */");
+ }
+ union mf_subvalue sv = { .u8_val = val };
+ mf_write_subfield_flow(&dst, &sv, uflow);
+}
+
+static void
execute_put_opts(const struct ovnact_put_opts *po,
const char *name, struct flow *uflow,
struct ovs_list *super)
@@ -2222,6 +2260,16 @@ trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len,
execute_lookup_mac_bind(ovnact_get_LOOKUP_ND(a), dp, uflow, super);
break;
+ case OVNACT_LOOKUP_ARP_IP:
+ execute_lookup_mac_bind_ip(ovnact_get_LOOKUP_ARP_IP(a), dp, uflow,
+ super);
+ break;
+
+ case OVNACT_LOOKUP_ND_IP:
+ execute_lookup_mac_bind_ip(ovnact_get_LOOKUP_ND_IP(a), dp, uflow,
+ super);
+ break;
+
case OVNACT_PUT_DHCPV4_OPTS:
execute_put_dhcp_opts(ovnact_get_PUT_DHCPV4_OPTS(a),
"put_dhcp_opts", uflow, super);
lookup_arp_ip and lookup_nd_ip are added to lookup if an entry exists in MAC bindings for a given IP address, for IPv4 and IPv6 respectively. Signed-off-by: Han Zhou <hzhou@ovn.org> --- controller/lflow.c | 4 +- include/ovn/actions.h | 10 +++++ lib/actions.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++ ovn-sb.xml | 55 +++++++++++++++++++++++++ tests/ovn.at | 50 ++++++++++++++++++++++ utilities/ovn-trace.c | 54 ++++++++++++++++++++++-- 6 files changed, 281 insertions(+), 4 deletions(-)