Skip to content

Commit c44e2dc

Browse files
committed
actions: Implement new actions lookup_arp_ip and lookup_nd_ip.
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. Acked-by: Numan Siddique <[email protected]> Signed-off-by: Han Zhou <[email protected]>
1 parent 0402bb8 commit c44e2dc

File tree

6 files changed

+281
-4
lines changed

6 files changed

+281
-4
lines changed

controller/lflow.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -782,13 +782,15 @@ consider_neighbor_flow(struct ovsdb_idl_index *sbrec_port_binding_by_name,
782782

783783
uint64_t stub[1024 / 8];
784784
struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(stub);
785+
uint8_t value = 1;
785786
put_load(mac.ea, sizeof mac.ea, MFF_ETH_DST, 0, 48, &ofpacts);
787+
put_load(&value, sizeof value, MFF_LOG_FLAGS, MLF_LOOKUP_MAC_BIT, 1,
788+
&ofpacts);
786789
ofctrl_add_flow(flow_table, OFTABLE_MAC_BINDING, 100,
787790
b->header_.uuid.parts[0], &get_arp_match,
788791
&ofpacts, &b->header_.uuid);
789792

790793
ofpbuf_clear(&ofpacts);
791-
uint8_t value = 1;
792794
put_load(&value, sizeof value, MFF_LOG_FLAGS, MLF_LOOKUP_MAC_BIT, 1,
793795
&ofpacts);
794796
match_set_dl_src(&lookup_arp_match, mac);

include/ovn/actions.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,11 @@ struct ovn_extend_table;
7575
OVNACT(GET_ARP, ovnact_get_mac_bind) \
7676
OVNACT(PUT_ARP, ovnact_put_mac_bind) \
7777
OVNACT(LOOKUP_ARP, ovnact_lookup_mac_bind) \
78+
OVNACT(LOOKUP_ARP_IP, ovnact_lookup_mac_bind_ip) \
7879
OVNACT(GET_ND, ovnact_get_mac_bind) \
7980
OVNACT(PUT_ND, ovnact_put_mac_bind) \
8081
OVNACT(LOOKUP_ND, ovnact_lookup_mac_bind) \
82+
OVNACT(LOOKUP_ND_IP, ovnact_lookup_mac_bind_ip) \
8183
OVNACT(PUT_DHCPV4_OPTS, ovnact_put_opts) \
8284
OVNACT(PUT_DHCPV6_OPTS, ovnact_put_opts) \
8385
OVNACT(SET_QUEUE, ovnact_set_queue) \
@@ -301,6 +303,14 @@ struct ovnact_lookup_mac_bind {
301303
struct expr_field mac; /* 48-bit Ethernet address. */
302304
};
303305

306+
/* OVNACT_LOOKUP_ARP_IP, OVNACT_LOOKUP_ND_IP. */
307+
struct ovnact_lookup_mac_bind_ip {
308+
struct ovnact ovnact;
309+
struct expr_field dst; /* 1-bit destination field. */
310+
struct expr_field port; /* Logical port name. */
311+
struct expr_field ip; /* 32-bit or 128-bit IP address. */
312+
};
313+
304314
struct ovnact_gen_option {
305315
const struct gen_opts_map *option;
306316
struct expr_constant_set value;

lib/actions.c

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1914,6 +1914,110 @@ ovnact_lookup_mac_bind_free(
19141914

19151915
}
19161916

1917+
1918+
static void format_lookup_mac_bind_ip(
1919+
const struct ovnact_lookup_mac_bind_ip *lookup_mac,
1920+
struct ds *s, const char *name)
1921+
{
1922+
expr_field_format(&lookup_mac->dst, s);
1923+
ds_put_format(s, " = %s(", name);
1924+
expr_field_format(&lookup_mac->port, s);
1925+
ds_put_cstr(s, ", ");
1926+
expr_field_format(&lookup_mac->ip, s);
1927+
ds_put_cstr(s, ");");
1928+
}
1929+
1930+
static void
1931+
format_LOOKUP_ARP_IP(const struct ovnact_lookup_mac_bind_ip *lookup_mac,
1932+
struct ds *s)
1933+
{
1934+
format_lookup_mac_bind_ip(lookup_mac, s, "lookup_arp_ip");
1935+
}
1936+
1937+
static void
1938+
format_LOOKUP_ND_IP(const struct ovnact_lookup_mac_bind_ip *lookup_mac,
1939+
struct ds *s)
1940+
{
1941+
format_lookup_mac_bind_ip(lookup_mac, s, "lookup_nd_ip");
1942+
}
1943+
1944+
static void
1945+
encode_lookup_mac_bind_ip(const struct ovnact_lookup_mac_bind_ip *lookup_mac,
1946+
enum mf_field_id ip_field,
1947+
const struct ovnact_encode_params *ep,
1948+
struct ofpbuf *ofpacts)
1949+
{
1950+
const struct arg args[] = {
1951+
{ expr_resolve_field(&lookup_mac->port), MFF_LOG_OUTPORT },
1952+
{ expr_resolve_field(&lookup_mac->ip), ip_field },
1953+
};
1954+
1955+
encode_setup_args(args, ARRAY_SIZE(args), ofpacts);
1956+
init_stack(ofpact_put_STACK_PUSH(ofpacts), MFF_ETH_DST);
1957+
1958+
struct mf_subfield dst = expr_resolve_field(&lookup_mac->dst);
1959+
ovs_assert(dst.field);
1960+
1961+
put_load(0, MFF_LOG_FLAGS, MLF_LOOKUP_MAC_BIT, 1, ofpacts);
1962+
emit_resubmit(ofpacts, ep->mac_bind_ptable);
1963+
1964+
struct ofpact_reg_move *orm = ofpact_put_REG_MOVE(ofpacts);
1965+
orm->dst = dst;
1966+
orm->src.field = mf_from_id(MFF_LOG_FLAGS);
1967+
orm->src.ofs = MLF_LOOKUP_MAC_BIT;
1968+
orm->src.n_bits = 1;
1969+
1970+
init_stack(ofpact_put_STACK_POP(ofpacts), MFF_ETH_DST);
1971+
encode_restore_args(args, ARRAY_SIZE(args), ofpacts);
1972+
}
1973+
1974+
static void
1975+
encode_LOOKUP_ARP_IP(const struct ovnact_lookup_mac_bind_ip *lookup_mac,
1976+
const struct ovnact_encode_params *ep,
1977+
struct ofpbuf *ofpacts)
1978+
{
1979+
encode_lookup_mac_bind_ip(lookup_mac, MFF_REG0, ep, ofpacts);
1980+
}
1981+
1982+
static void
1983+
encode_LOOKUP_ND_IP(const struct ovnact_lookup_mac_bind_ip *lookup_mac,
1984+
const struct ovnact_encode_params *ep,
1985+
struct ofpbuf *ofpacts)
1986+
{
1987+
encode_lookup_mac_bind_ip(lookup_mac, MFF_XXREG0, ep, ofpacts);
1988+
}
1989+
1990+
static void
1991+
parse_lookup_mac_bind_ip(struct action_context *ctx,
1992+
const struct expr_field *dst,
1993+
int width,
1994+
struct ovnact_lookup_mac_bind_ip *lookup_mac)
1995+
{
1996+
/* Validate that the destination is a 1-bit, modifiable field. */
1997+
char *error = expr_type_check(dst, 1, true, ctx->scope);
1998+
if (error) {
1999+
lexer_error(ctx->lexer, "%s", error);
2000+
free(error);
2001+
return;
2002+
}
2003+
2004+
lexer_get(ctx->lexer); /* Skip lookup_arp/lookup_nd. */
2005+
lexer_get(ctx->lexer); /* Skip '('. * */
2006+
2007+
action_parse_field(ctx, 0, false, &lookup_mac->port);
2008+
lexer_force_match(ctx->lexer, LEX_T_COMMA);
2009+
action_parse_field(ctx, width, false, &lookup_mac->ip);
2010+
lexer_force_match(ctx->lexer, LEX_T_RPAREN);
2011+
lookup_mac->dst = *dst;
2012+
}
2013+
2014+
static void
2015+
ovnact_lookup_mac_bind_ip_free(
2016+
struct ovnact_lookup_mac_bind_ip *lookup_mac OVS_UNUSED)
2017+
{
2018+
2019+
}
2020+
19172021

19182022
static void
19192023
parse_gen_opt(struct action_context *ctx, struct ovnact_gen_option *o,
@@ -3370,6 +3474,14 @@ parse_set_action(struct action_context *ctx)
33703474
&& lexer_lookahead(ctx->lexer) == LEX_T_LPAREN) {
33713475
parse_lookup_mac_bind(ctx, &lhs, 128,
33723476
ovnact_put_LOOKUP_ND(ctx->ovnacts));
3477+
} else if (!strcmp(ctx->lexer->token.s, "lookup_arp_ip")
3478+
&& lexer_lookahead(ctx->lexer) == LEX_T_LPAREN) {
3479+
parse_lookup_mac_bind_ip(ctx, &lhs, 32,
3480+
ovnact_put_LOOKUP_ARP_IP(ctx->ovnacts));
3481+
} else if (!strcmp(ctx->lexer->token.s, "lookup_nd_ip")
3482+
&& lexer_lookahead(ctx->lexer) == LEX_T_LPAREN) {
3483+
parse_lookup_mac_bind_ip(ctx, &lhs, 128,
3484+
ovnact_put_LOOKUP_ND_IP(ctx->ovnacts));
33733485
} else {
33743486
parse_assignment_action(ctx, false, &lhs);
33753487
}

ovn-sb.xml

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1448,6 +1448,34 @@
14481448
</p>
14491449
</dd>
14501450

1451+
<dt>
1452+
<code><var>R</var> = lookup_arp_ip(<var>P</var>, <var>A</var>);</code>
1453+
</dt>
1454+
1455+
<dd>
1456+
<p>
1457+
<b>Parameters</b>: logical port string field <var>P</var>, 32-bit
1458+
IP address field <var>A</var>.
1459+
</p>
1460+
1461+
<p>
1462+
<b>Result</b>: stored to a 1-bit subfield <var>R</var>.
1463+
</p>
1464+
1465+
<p>
1466+
Looks up <var>A</var> in <var>P</var>'s mac binding table. If an
1467+
entry is found, stores <code>1</code> in the 1-bit subfield
1468+
<var>R</var>, else 0.
1469+
</p>
1470+
1471+
<p>
1472+
<b>Example:</b>
1473+
<code>
1474+
reg0[0] = lookup_arp_ip(inport, arp.spa);
1475+
</code>
1476+
</p>
1477+
</dd>
1478+
14511479
<dt><code>nd_ns { <var>action</var>; </code>...<code> };</code></dt>
14521480
<dd>
14531481
<p>
@@ -1632,6 +1660,33 @@
16321660
</p>
16331661
</dd>
16341662

1663+
<dt><code><var>R</var> = lookup_nd_ip(<var>P</var>, <var>A</var>);</code>
1664+
</dt>
1665+
1666+
<dd>
1667+
<p>
1668+
<b>Parameters</b>: logical port string field <var>P</var>, 128-bit
1669+
IP address field <var>A</var>.
1670+
</p>
1671+
1672+
<p>
1673+
<b>Result</b>: stored to a 1-bit subfield <var>R</var>.
1674+
</p>
1675+
1676+
<p>
1677+
Looks up <var>A</var> in <var>P</var>'s mac binding table. If an
1678+
entry is found, stores <code>1</code> in the 1-bit subfield
1679+
<var>R</var>, else 0.
1680+
</p>
1681+
1682+
<p>
1683+
<b>Example:</b>
1684+
<code>
1685+
reg0[0] = lookup_nd_ip(inport, ip6.src);
1686+
</code>
1687+
</p>
1688+
</dd>
1689+
16351690
<dt>
16361691
<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>
16371692
</dt>

tests/ovn.at

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1249,6 +1249,31 @@ reg0[0] = lookup_arp(inport, eth.dst);
12491249
reg0[0] = lookup_arp(inport, ip4.src, ip4.dst);
12501250
Cannot use 32-bit field ip4.dst[0..31] where 48-bit field is required.
12511251

1252+
# lookup_arp_ip
1253+
reg0[0] = lookup_arp_ip(inport, ip4.dst);
1254+
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[]
1255+
has prereqs eth.type == 0x800
1256+
reg1[1] = lookup_arp_ip(inport, arp.spa);
1257+
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[]
1258+
has prereqs eth.type == 0x806
1259+
1260+
lookup_arp_ip;
1261+
Syntax error at `lookup_arp_ip' expecting action.
1262+
reg0[0] = lookup_arp_ip;
1263+
Syntax error at `lookup_arp_ip' expecting field name.
1264+
reg0[0] = lookup_arp_ip();
1265+
Syntax error at `)' expecting field name.
1266+
reg0[0] = lookup_arp_ip(inport);
1267+
Syntax error at `)' expecting `,'.
1268+
reg0[0] = lookup_arp_ip(inport ip4.dst);
1269+
Syntax error at `ip4.dst' expecting `,'.
1270+
reg0[0] = lookup_arp_ip(inport, ip4.dst;
1271+
Syntax error at `;' expecting `)'.
1272+
reg0[0] = lookup_arp_ip(inport, ip4.dst, eth.src;
1273+
Syntax error at `,' expecting `)'.
1274+
reg0[0] = lookup_arp_ip(inport, eth.dst);
1275+
Cannot use 48-bit field eth.dst[0..47] where 32-bit field is required.
1276+
12521277
# put_dhcp_opts
12531278
reg1[0] = put_dhcp_opts(offerip = 1.2.3.4, router = 10.0.0.1);
12541279
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)
@@ -1392,6 +1417,31 @@ reg0[0] = lookup_nd(inport, ip4.src, ip4.dst);
13921417
reg0[0] = lookup_nd(inport, ip6.src, ip6.dst);
13931418
Cannot use 128-bit field ip6.dst[0..127] where 48-bit field is required.
13941419

1420+
# lookup_nd_ip
1421+
reg2[0] = lookup_nd_ip(inport, ip6.dst);
1422+
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[]
1423+
has prereqs eth.type == 0x86dd
1424+
reg3[0] = lookup_nd_ip(inport, nd.target);
1425+
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[]
1426+
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)
1427+
1428+
lookup_nd_ip;
1429+
Syntax error at `lookup_nd_ip' expecting action.
1430+
reg0[0] = lookup_nd_ip;
1431+
Syntax error at `lookup_nd_ip' expecting field name.
1432+
reg0[0] = lookup_nd_ip();
1433+
Syntax error at `)' expecting field name.
1434+
reg0[0] = lookup_nd_ip(inport);
1435+
Syntax error at `)' expecting `,'.
1436+
reg0[0] = lookup_nd_ip(inport ip6.dst);
1437+
Syntax error at `ip6.dst' expecting `,'.
1438+
reg0[0] = lookup_nd_ip(inport, ip6.dst;
1439+
Syntax error at `;' expecting `)'.
1440+
reg0[0] = lookup_nd_ip(inport, eth.dst);
1441+
Cannot use 48-bit field eth.dst[0..47] where 128-bit field is required.
1442+
reg0[0] = lookup_nd_ip(inport, ip4.src);
1443+
Cannot use 32-bit field ip4.src[0..31] where 128-bit field is required.
1444+
13951445
# set_queue
13961446
set_queue(0);
13971447
encodes as set_queue:0

utilities/ovn-trace.c

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -582,13 +582,13 @@ ovntrace_mac_binding_find(const struct ovntrace_datapath *dp,
582582
static const struct ovntrace_mac_binding *
583583
ovntrace_mac_binding_find_mac_ip(const struct ovntrace_datapath *dp,
584584
uint16_t port_key, const struct in6_addr *ip,
585-
struct eth_addr mac)
585+
struct eth_addr *mac)
586586
{
587587
const struct ovntrace_mac_binding *bind;
588588
HMAP_FOR_EACH_WITH_HASH (bind, node, hash_mac_binding(port_key, ip),
589589
&dp->mac_bindings) {
590590
if (bind->port_key == port_key && ipv6_addr_equals(ip, &bind->ip)
591-
&& eth_addr_equals(bind->mac, mac)) {
591+
&& (!mac || eth_addr_equals(bind->mac, *mac))) {
592592
return bind;
593593
}
594594
}
@@ -1772,7 +1772,7 @@ execute_lookup_mac_bind(const struct ovnact_lookup_mac_bind *bind,
17721772
mf_read_subfield(&mac_sf, uflow, &mac_sv);
17731773

17741774
const struct ovntrace_mac_binding *binding
1775-
= ovntrace_mac_binding_find_mac_ip(dp, port_key, &ip, mac_sv.mac);
1775+
= ovntrace_mac_binding_find_mac_ip(dp, port_key, &ip, &mac_sv.mac);
17761776

17771777
struct mf_subfield dst = expr_resolve_field(&bind->dst);
17781778
uint8_t val = 0;
@@ -1790,6 +1790,44 @@ execute_lookup_mac_bind(const struct ovnact_lookup_mac_bind *bind,
17901790
mf_write_subfield_flow(&dst, &sv, uflow);
17911791
}
17921792

1793+
static void
1794+
execute_lookup_mac_bind_ip(const struct ovnact_lookup_mac_bind_ip *bind,
1795+
const struct ovntrace_datapath *dp,
1796+
struct flow *uflow,
1797+
struct ovs_list *super)
1798+
{
1799+
/* Get logical port number.*/
1800+
struct mf_subfield port_sf = expr_resolve_field(&bind->port);
1801+
ovs_assert(port_sf.n_bits == 32);
1802+
uint32_t port_key = mf_get_subfield(&port_sf, uflow);
1803+
1804+
/* Get IP address. */
1805+
struct mf_subfield ip_sf = expr_resolve_field(&bind->ip);
1806+
ovs_assert(ip_sf.n_bits == 32 || ip_sf.n_bits == 128);
1807+
union mf_subvalue ip_sv;
1808+
mf_read_subfield(&ip_sf, uflow, &ip_sv);
1809+
struct in6_addr ip = (ip_sf.n_bits == 32
1810+
? in6_addr_mapped_ipv4(ip_sv.ipv4)
1811+
: ip_sv.ipv6);
1812+
1813+
const struct ovntrace_mac_binding *binding
1814+
= ovntrace_mac_binding_find_mac_ip(dp, port_key, &ip, NULL);
1815+
1816+
struct mf_subfield dst = expr_resolve_field(&bind->dst);
1817+
uint8_t val = 0;
1818+
1819+
if (binding) {
1820+
val = 1;
1821+
ovntrace_node_append(super, OVNTRACE_NODE_ACTION,
1822+
"/* MAC binding found. */");
1823+
} else {
1824+
ovntrace_node_append(super, OVNTRACE_NODE_ACTION,
1825+
"/* lookup failed - No MAC binding. */");
1826+
}
1827+
union mf_subvalue sv = { .u8_val = val };
1828+
mf_write_subfield_flow(&dst, &sv, uflow);
1829+
}
1830+
17931831
static void
17941832
execute_put_opts(const struct ovnact_put_opts *po,
17951833
const char *name, struct flow *uflow,
@@ -2222,6 +2260,16 @@ trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len,
22222260
execute_lookup_mac_bind(ovnact_get_LOOKUP_ND(a), dp, uflow, super);
22232261
break;
22242262

2263+
case OVNACT_LOOKUP_ARP_IP:
2264+
execute_lookup_mac_bind_ip(ovnact_get_LOOKUP_ARP_IP(a), dp, uflow,
2265+
super);
2266+
break;
2267+
2268+
case OVNACT_LOOKUP_ND_IP:
2269+
execute_lookup_mac_bind_ip(ovnact_get_LOOKUP_ND_IP(a), dp, uflow,
2270+
super);
2271+
break;
2272+
22252273
case OVNACT_PUT_DHCPV4_OPTS:
22262274
execute_put_dhcp_opts(ovnact_get_PUT_DHCPV4_OPTS(a),
22272275
"put_dhcp_opts", uflow, super);

0 commit comments

Comments
 (0)