From: Numan Siddique <[email protected]> This patch adds these OVN actions to learn port-to-mac bindings on the logical ports whose port security is disabled and are configured to accept unknown destination packets.
put_fdb(inport, mac) will add an entry in the Southbound 'FDB' table. get_fdb(mac) will get the port key on which the mac is learnt. lookup_fdb(inport, mac) will check if the port-to-mac entry is already present or not. This is added to limit using the action - put_fdb() only if required. An upcoming patch in the series will add the necessary logical flows which makes use of these actions. Signed-off-by: Numan Siddique <[email protected]> --- controller/lflow.c | 2 + controller/lflow.h | 2 + include/ovn/actions.h | 29 ++++++ include/ovn/logical-fields.h | 4 + lib/actions.c | 176 +++++++++++++++++++++++++++++++++++ ovn-sb.xml | 62 ++++++++++++ tests/ovn.at | 58 ++++++++++++ tests/test-ovn.c | 2 + utilities/ovn-trace.c | 138 ++++++++++++++++++++++++++- 9 files changed, 472 insertions(+), 1 deletion(-) diff --git a/controller/lflow.c b/controller/lflow.c index 946c1e04b7..baf6932d51 100644 --- a/controller/lflow.c +++ b/controller/lflow.c @@ -701,6 +701,8 @@ add_matches_to_flow_table(const struct sbrec_logical_flow *lflow, .lb_hairpin_ptable = OFTABLE_CHK_LB_HAIRPIN, .lb_hairpin_reply_ptable = OFTABLE_CHK_LB_HAIRPIN_REPLY, .ct_snat_vip_ptable = OFTABLE_CT_SNAT_FOR_VIP, + .fdb_ptable = OFTABLE_GET_FDB, + .fdb_lookup_ptable = OFTABLE_LOOKUP_FDB, }; ovnacts_encode(ovnacts->data, ovnacts->size, &ep, &ofpacts); diff --git a/controller/lflow.h b/controller/lflow.h index ba79cc374f..d790d518d8 100644 --- a/controller/lflow.h +++ b/controller/lflow.h @@ -71,6 +71,8 @@ struct uuid; #define OFTABLE_CHK_LB_HAIRPIN 68 #define OFTABLE_CHK_LB_HAIRPIN_REPLY 69 #define OFTABLE_CT_SNAT_FOR_VIP 70 +#define OFTABLE_GET_FDB 71 +#define OFTABLE_LOOKUP_FDB 72 /* The number of tables for the ingress and egress pipelines. */ #define LOG_PIPELINE_LEN 24 diff --git a/include/ovn/actions.h b/include/ovn/actions.h index a2d28c6a3f..0402131777 100644 --- a/include/ovn/actions.h +++ b/include/ovn/actions.h @@ -107,6 +107,9 @@ struct ovn_extend_table; OVNACT(CT_SNAT_TO_VIP, ovnact_null) \ OVNACT(BFD_MSG, ovnact_null) \ OVNACT(SCTP_ABORT, ovnact_nest) \ + OVNACT(PUT_FDB, ovnact_put_fdb) \ + OVNACT(GET_FDB, ovnact_get_fdb) \ + OVNACT(LOOKUP_FDB, ovnact_lookup_fdb) \ /* enum ovnact_type, with a member OVNACT_<ENUM> for each action. */ enum OVS_PACKED_ENUM ovnact_type { @@ -415,6 +418,28 @@ struct ovnact_fwd_group { uint8_t ltable; /* Logical table ID of next table. */ }; +/* OVNACT_PUT_FDB. */ +struct ovnact_put_fdb { + struct ovnact ovnact; + struct expr_field port; /* Logical port name. */ + struct expr_field mac; /* 48-bit Ethernet address. */ +}; + +/* OVNACT_GET_FDB. */ +struct ovnact_get_fdb { + struct ovnact ovnact; + struct expr_field mac; /* 48-bit Ethernet address. */ + struct expr_field dst; /* 32-bit destination field. */ +}; + +/* OVNACT_LOOKUP_FDB. */ +struct ovnact_lookup_fdb { + struct ovnact ovnact; + struct expr_field mac; /* 48-bit Ethernet address. */ + struct expr_field port; /* Logical port name. */ + struct expr_field dst; /* 1-bit destination field. */ +}; + /* Internal use by the helpers below. */ void ovnact_init(struct ovnact *, enum ovnact_type, size_t len); void *ovnact_put(struct ofpbuf *, enum ovnact_type, size_t len); @@ -766,6 +791,10 @@ struct ovnact_encode_params { * 'chk_lb_hairpin_reply' to resubmit. */ uint8_t ct_snat_vip_ptable; /* OpenFlow table for * 'ct_snat_to_vip' to resubmit. */ + uint8_t fdb_ptable; /* OpenFlow table for + * 'get_fdb' to resubmit. */ + uint8_t fdb_lookup_ptable; /* OpenFlow table for + * 'lookup_fdb' to resubmit. */ }; void ovnacts_encode(const struct ovnact[], size_t ovnacts_len, diff --git a/include/ovn/logical-fields.h b/include/ovn/logical-fields.h index aee4748562..9d8d07fab2 100644 --- a/include/ovn/logical-fields.h +++ b/include/ovn/logical-fields.h @@ -59,6 +59,7 @@ enum mff_log_flags_bits { MLF_NESTED_CONTAINER_BIT = 5, MLF_LOOKUP_MAC_BIT = 6, MLF_LOOKUP_LB_HAIRPIN_BIT = 7, + MLF_LOOKUP_FDB_BIT = 8, }; /* MFF_LOG_FLAGS_REG flag assignments */ @@ -92,6 +93,9 @@ enum mff_log_flags { MLF_LOOKUP_MAC = (1 << MLF_LOOKUP_MAC_BIT), MLF_LOOKUP_LB_HAIRPIN = (1 << MLF_LOOKUP_LB_HAIRPIN_BIT), + + /* Indicate that the lookup in the fdb table was successful. */ + MLF_LOOKUP_FDB = (1 << MLF_LOOKUP_FDB_BIT), }; /* OVN logical fields diff --git a/lib/actions.c b/lib/actions.c index 56b8fab629..b3433f49ea 100644 --- a/lib/actions.c +++ b/lib/actions.c @@ -3743,6 +3743,172 @@ encode_CT_SNAT_TO_VIP(const struct ovnact_null *null OVS_UNUSED, emit_resubmit(ofpacts, ep->ct_snat_vip_ptable); } +static void +format_PUT_FDB(const struct ovnact_put_fdb *put_fdb, struct ds *s) +{ + ds_put_cstr(s, "put_fdb("); + expr_field_format(&put_fdb->port, s); + ds_put_cstr(s, ", "); + expr_field_format(&put_fdb->mac, s); + ds_put_cstr(s, ");"); +} + +static void +encode_PUT_FDB(const struct ovnact_put_fdb *put_fdb, + const struct ovnact_encode_params *ep OVS_UNUSED, + struct ofpbuf *ofpacts) +{ + const struct arg args[] = { + { expr_resolve_field(&put_fdb->port), MFF_LOG_INPORT }, + { expr_resolve_field(&put_fdb->mac), MFF_ETH_SRC } + }; + encode_setup_args(args, ARRAY_SIZE(args), ofpacts); + encode_controller_op(ACTION_OPCODE_PUT_FDB, ofpacts); + encode_restore_args(args, ARRAY_SIZE(args), ofpacts); +} + +static void +parse_put_fdb(struct action_context *ctx, struct ovnact_put_fdb *put_fdb) +{ + lexer_force_match(ctx->lexer, LEX_T_LPAREN); + action_parse_field(ctx, 0, false, &put_fdb->port); + lexer_force_match(ctx->lexer, LEX_T_COMMA); + action_parse_field(ctx, 48, false, &put_fdb->mac); + lexer_force_match(ctx->lexer, LEX_T_RPAREN); +} + +static void +ovnact_put_fdb_free(struct ovnact_put_fdb *put_fdb OVS_UNUSED) +{ +} + +static void +format_GET_FDB(const struct ovnact_get_fdb *get_fdb, struct ds *s) +{ + expr_field_format(&get_fdb->dst, s); + ds_put_cstr(s, " = get_fdb("); + expr_field_format(&get_fdb->mac, s); + ds_put_cstr(s, ");"); +} + +static void +encode_GET_FDB(const struct ovnact_get_fdb *get_fdb, + const struct ovnact_encode_params *ep, + struct ofpbuf *ofpacts) +{ + struct mf_subfield dst = expr_resolve_field(&get_fdb->dst); + ovs_assert(dst.field); + + const struct arg args[] = { + { expr_resolve_field(&get_fdb->mac), MFF_ETH_DST }, + }; + encode_setup_args(args, ARRAY_SIZE(args), ofpacts); + put_load(0, MFF_LOG_OUTPORT, 0, 32, ofpacts); + emit_resubmit(ofpacts, ep->fdb_ptable); + encode_restore_args(args, ARRAY_SIZE(args), ofpacts); + + if (dst.field->id != MFF_LOG_OUTPORT) { + struct ofpact_reg_move *orm = ofpact_put_REG_MOVE(ofpacts); + orm->dst = dst; + orm->src.field = mf_from_id(MFF_LOG_OUTPORT); + orm->src.ofs = 0; + orm->src.n_bits = 32; + } +} + +static void +parse_get_fdb(struct action_context *ctx, + struct expr_field *dst, + struct ovnact_get_fdb *get_fdb) +{ + lexer_get(ctx->lexer); /* Skip get_bfd. */ + lexer_get(ctx->lexer); /* Skip '('. */ + + /* Validate that the destination is a 32-bit, modifiable field if it + is not a string field (i.e 'inport' or 'outport'). */ + if (dst->n_bits) { + char *error = expr_type_check(dst, 32, true, ctx->scope); + if (error) { + lexer_error(ctx->lexer, "%s", error); + free(error); + return; + } + } + get_fdb->dst = *dst; + + action_parse_field(ctx, 48, false, &get_fdb->mac); + lexer_force_match(ctx->lexer, LEX_T_RPAREN); +} + +static void +ovnact_get_fdb_free(struct ovnact_get_fdb *get_fdb OVS_UNUSED) +{ +} + +static void +format_LOOKUP_FDB(const struct ovnact_lookup_fdb *lookup_fdb, struct ds *s) +{ + expr_field_format(&lookup_fdb->dst, s); + ds_put_cstr(s, " = lookup_fdb("); + expr_field_format(&lookup_fdb->port, s); + ds_put_cstr(s, ", "); + expr_field_format(&lookup_fdb->mac, s); + ds_put_cstr(s, ");"); +} + +static void +encode_LOOKUP_FDB(const struct ovnact_lookup_fdb *lookup_fdb, + const struct ovnact_encode_params *ep, + struct ofpbuf *ofpacts) +{ + const struct arg args[] = { + { expr_resolve_field(&lookup_fdb->port), MFF_LOG_INPORT }, + { expr_resolve_field(&lookup_fdb->mac), MFF_ETH_SRC }, + }; + encode_setup_args(args, ARRAY_SIZE(args), ofpacts); + + struct mf_subfield dst = expr_resolve_field(&lookup_fdb->dst); + ovs_assert(dst.field); + + put_load(0, MFF_LOG_FLAGS, MLF_LOOKUP_FDB_BIT, 1, ofpacts); + emit_resubmit(ofpacts, ep->fdb_lookup_ptable); + encode_restore_args(args, ARRAY_SIZE(args), ofpacts); + + 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_FDB_BIT; + orm->src.n_bits = 1; +} + +static void +parse_lookup_fdb(struct action_context *ctx, + struct expr_field *dst, + struct ovnact_lookup_fdb *lookup_fdb) +{ + lexer_get(ctx->lexer); /* Skip lookup_bfd. */ + lexer_get(ctx->lexer); /* Skip '('. */ + + /* 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; + } + lookup_fdb->dst = *dst; + + action_parse_field(ctx, 0, false, &lookup_fdb->port); + lexer_force_match(ctx->lexer, LEX_T_COMMA); + action_parse_field(ctx, 48, false, &lookup_fdb->mac); + lexer_force_match(ctx->lexer, LEX_T_RPAREN); +} + +static void +ovnact_lookup_fdb_free(struct ovnact_lookup_fdb *get_fdb OVS_UNUSED) +{ +} + /* Parses an assignment or exchange or put_dhcp_opts action. */ static void parse_set_action(struct action_context *ctx) @@ -3803,6 +3969,14 @@ parse_set_action(struct action_context *ctx) && lexer_lookahead(ctx->lexer) == LEX_T_LPAREN) { parse_chk_lb_hairpin_reply( ctx, &lhs, ovnact_put_CHK_LB_HAIRPIN_REPLY(ctx->ovnacts)); + } else if (!strcmp(ctx->lexer->token.s, "get_fdb") + && lexer_lookahead(ctx->lexer) == LEX_T_LPAREN) { + parse_get_fdb( + ctx, &lhs, ovnact_put_GET_FDB(ctx->ovnacts)); + } else if (!strcmp(ctx->lexer->token.s, "lookup_fdb") + && lexer_lookahead(ctx->lexer) == LEX_T_LPAREN) { + parse_lookup_fdb( + ctx, &lhs, ovnact_put_LOOKUP_FDB(ctx->ovnacts)); } else { parse_assignment_action(ctx, false, &lhs); } @@ -3895,6 +4069,8 @@ parse_action(struct action_context *ctx) parse_REJECT(ctx); } else if (lexer_match_id(ctx->lexer, "ct_snat_to_vip")) { ovnact_put_CT_SNAT_TO_VIP(ctx->ovnacts); + } else if (lexer_match_id(ctx->lexer, "put_fdb")) { + parse_put_fdb(ctx, ovnact_put_PUT_FDB(ctx->ovnacts)); } else { lexer_syntax_error(ctx->lexer, "expecting action"); } diff --git a/ovn-sb.xml b/ovn-sb.xml index b8912b33c8..35000ed681 100644 --- a/ovn-sb.xml +++ b/ovn-sb.xml @@ -1526,6 +1526,68 @@ </p> </dd> + <dt><code><var>P</var> = get_fdb(<var>A</var>);</code></dt> + + <dd> + <p> + <b>Parameters</b>:48-bit MAC address field <var>A</var>. + </p> + + <p> + Looks up <var>A</var> in fdb table. If an entry is found, stores + the logical port key to the out parameter <code>P</code>. + </p> + + <p><b>Example:</b> <code>outport = get_fdb(eth.src);</code></p> + </dd> + + <dt> + <code>put_fdb(<var>P</var>, <var>A</var>);</code> + </dt> + + <dd> + <p> + <b>Parameters</b>: logical port string field <var>P</var>, 48-bit + MAC address field <var>A</var>. + </p> + + <p> + Adds or updates the entry for Ethernet address <var>A</var> in + fdb table, setting its logical port key to <var>P</var>. + </p> + + <p><b>Example:</b> <code>put_fdb(inport, arp.spa);</code></p> + </dd> + + <dt> + <code><var>R</var> = lookup_fdb(<var>P</var>, <var>A</var>);</code> + </dt> + + <dd> + <p> + <b>Parameters</b>: 48-bit MAC address field <var>M</var>, + logical port string field <var>P</var>. + </p> + + <p> + <b>Result</b>: stored to a 1-bit subfield <var>R</var>. + </p> + + <p> + Looks up <var>A</var> in fdb table. If an entry is found + and the the logical port key is <var>P</var>, <code>P</code>, + stores <code>1</code> in the 1-bit subfield + <var>R</var>, else 0. + </p> + + <p> + <b>Example:</b> + <code> + reg0[0] = lookup_fdb(inport, eth.src); + </code> + </p> + </dd> + <dt><code>nd_ns { <var>action</var>; </code>...<code> };</code></dt> <dd> <p> diff --git a/tests/ovn.at b/tests/ovn.at index 80c9fe138a..8dbd3bf932 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -1822,6 +1822,64 @@ ct_snat_to_vip(foo); handle_bfd_msg(); encodes as controller(userdata=00.00.00.17.00.00.00.00) +# put_fdb +put_fdb(inport, arp.sha); + encodes as push:NXM_OF_ETH_SRC[],push:NXM_NX_ARP_SHA[],pop:NXM_OF_ETH_SRC[],controller(userdata=00.00.00.19.00.00.00.00),pop:NXM_OF_ETH_SRC[] + has prereqs eth.type == 0x806 + +put_fdb(inport, eth.src); + encodes as controller(userdata=00.00.00.19.00.00.00.00) + +put_fdb(inport, ip4.src); + Cannot use 32-bit field ip4.src[0..31] where 48-bit field is required. + +# get_fdb +outport = get_fdb(eth.dst); + encodes as set_field:0->reg15,resubmit(,71) + +outport = get_fdb(eth.src); + encodes as push:NXM_OF_ETH_DST[],push:NXM_OF_ETH_SRC[],pop:NXM_OF_ETH_DST[],set_field:0->reg15,resubmit(,71),pop:NXM_OF_ETH_DST[] + +inport = get_fdb(arp.sha); + encodes as push:NXM_OF_ETH_DST[],push:NXM_NX_ARP_SHA[],pop:NXM_OF_ETH_DST[],set_field:0->reg15,resubmit(,71),pop:NXM_OF_ETH_DST[],move:NXM_NX_REG15[]->NXM_NX_REG14[] + has prereqs eth.type == 0x806 + +reg0 = get_fdb(arp.tha); + encodes as push:NXM_OF_ETH_DST[],push:NXM_NX_ARP_THA[],pop:NXM_OF_ETH_DST[],set_field:0->reg15,resubmit(,71),pop:NXM_OF_ETH_DST[],move:NXM_NX_REG15[]->NXM_NX_XXREG0[96..127] + has prereqs eth.type == 0x806 + +reg0[1..3] = get_fdb(eth.src); + Cannot use 3-bit field reg0[1..3] where 32-bit field is required. + +reg15 = get_fdb(eth.dst); + Syntax error at `reg15' expecting field name. + +outport = get_fdb(ip4.dst); + Cannot use 32-bit field ip4.dst[0..31] where 48-bit field is required. + +# lookup_fdb +reg0[0] = lookup_fdb(inport, eth.src); + encodes as set_field:0/0x100->reg10,resubmit(,72),move:NXM_NX_REG10[8]->NXM_NX_XXREG0[96] + +reg1[4] = lookup_fdb(outport, eth.dst); + encodes as push:NXM_NX_REG14[],push:NXM_OF_ETH_SRC[],push:NXM_OF_ETH_DST[],push:NXM_NX_REG15[],pop:NXM_NX_REG14[],pop:NXM_OF_ETH_SRC[],set_field:0/0x100->reg10,resubmit(,72),pop:NXM_OF_ETH_SRC[],pop:NXM_NX_REG14[],move:NXM_NX_REG10[8]->NXM_NX_XXREG0[68] + +reg0[0] = lookup_fdb(outport, arp.sha); + encodes as push:NXM_NX_REG14[],push:NXM_OF_ETH_SRC[],push:NXM_NX_ARP_SHA[],push:NXM_NX_REG15[],pop:NXM_NX_REG14[],pop:NXM_OF_ETH_SRC[],set_field:0/0x100->reg10,resubmit(,72),pop:NXM_OF_ETH_SRC[],pop:NXM_NX_REG14[],move:NXM_NX_REG10[8]->NXM_NX_XXREG0[96] + has prereqs eth.type == 0x806 + +reg0 = lookup_fdb(outport, arp.sha); + Cannot use 32-bit field reg0[0..31] where 1-bit field is required. + +outport = lookup_fdb(outport, arp.sha); + Cannot use string field outport where numeric field is required. + +reg1[1] = lookup_fdb(outport, ip4.src); + Cannot use 32-bit field ip4.src[0..31] where 48-bit field is required. + +reg1[1] = lookup_fdb(ip4.src, eth.src); + Cannot use numeric field ip4.src where string field is required. + # Miscellaneous negative tests. ; Syntax error at `;'. diff --git a/tests/test-ovn.c b/tests/test-ovn.c index 9bd13a037f..202a96c5dd 100644 --- a/tests/test-ovn.c +++ b/tests/test-ovn.c @@ -1348,6 +1348,8 @@ test_parse_actions(struct ovs_cmdl_context *ctx OVS_UNUSED) .lb_hairpin_ptable = OFTABLE_CHK_LB_HAIRPIN, .lb_hairpin_reply_ptable = OFTABLE_CHK_LB_HAIRPIN_REPLY, .ct_snat_vip_ptable = OFTABLE_CT_SNAT_FOR_VIP, + .fdb_ptable = OFTABLE_GET_FDB, + .fdb_lookup_ptable = OFTABLE_LOOKUP_FDB, }; struct ofpbuf ofpacts; ofpbuf_init(&ofpacts, 0); diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c index c0a0edc0a3..fead759b49 100644 --- a/utilities/ovn-trace.c +++ b/utilities/ovn-trace.c @@ -405,6 +405,7 @@ struct ovntrace_datapath { size_t n_flows, allocated_flows; struct hmap mac_bindings; /* Contains "struct ovntrace_mac_binding"s. */ + struct hmap fdbs; /* Contains "struct ovntrace_fdb"s. */ bool has_local_l3gateway; }; @@ -453,12 +454,24 @@ struct ovntrace_mac_binding { struct eth_addr mac; }; +struct ovntrace_fdb { + struct hmap_node node; + uint16_t port_key; + struct eth_addr mac; +}; + static inline uint32_t hash_mac_binding(uint16_t port_key, const struct in6_addr *ip) { return hash_bytes(ip, sizeof *ip, port_key); } +static inline uint32_t +hash_fdb(const struct eth_addr *mac) +{ + return hash_bytes(mac, sizeof *mac, 0); +} + /* Every ovntrace_datapath, by southbound Datapath_Binding record UUID. */ static struct hmap datapaths; @@ -518,6 +531,18 @@ ovntrace_datapath_find_by_name(const char *name) return match; } +static struct ovntrace_datapath * +ovntrace_datapath_find_by_key(uint32_t tunnel_key) +{ + struct ovntrace_datapath *dp; + HMAP_FOR_EACH (dp, sb_uuid_node, &datapaths) { + if (dp->tunnel_key == tunnel_key) { + return dp; + } + } + return NULL; +} + static const struct ovntrace_port * ovntrace_port_find_by_key(const struct ovntrace_datapath *dp, uint16_t tunnel_key) @@ -598,6 +623,20 @@ ovntrace_mac_binding_find_mac_ip(const struct ovntrace_datapath *dp, return NULL; } +static const struct ovntrace_fdb * +ovntrace_fdb_find(const struct ovntrace_datapath *dp, + const struct eth_addr *mac) +{ + const struct ovntrace_fdb *fdb; + HMAP_FOR_EACH_WITH_HASH (fdb, node, hash_fdb(mac), + &dp->fdbs) { + if (eth_addr_equals(fdb->mac, *mac)) { + return fdb; + } + } + return NULL; +} + /* If 's' ends with a UUID, returns a copy of it with the UUID truncated to * just the first 6 characters; otherwise, returns a copy of 's'. */ static char * @@ -638,7 +677,7 @@ read_datapaths(void) ovs_list_init(&dp->mcgroups); hmap_init(&dp->mac_bindings); - + hmap_init(&dp->fdbs); hmap_insert(&datapaths, &dp->sb_uuid_node, uuid_hash(&dp->sb_uuid)); } } @@ -1053,6 +1092,30 @@ read_mac_bindings(void) } } +static void +read_fdbs(void) +{ + const struct sbrec_fdb *fdb; + SBREC_FDB_FOR_EACH (fdb, ovnsb_idl) { + struct eth_addr mac; + if (!eth_addr_from_string(fdb->mac, &mac)) { + VLOG_WARN("%s: bad Ethernet address", fdb->mac); + continue; + } + + struct ovntrace_datapath *dp = + ovntrace_datapath_find_by_key(fdb->dp_key); + if (!dp) { + continue; + } + + struct ovntrace_fdb *fdb_t = xmalloc(sizeof *fdb_t); + fdb_t->mac = mac; + fdb_t->port_key = fdb->port_key; + hmap_insert(&dp->fdbs, &fdb_t->node, hash_fdb(&mac)); + } +} + static void read_db(void) { @@ -1064,6 +1127,7 @@ read_db(void) read_gen_opts(); read_flows(); read_mac_bindings(); + read_fdbs(); } static const struct ovntrace_port * @@ -2029,6 +2093,66 @@ execute_lookup_mac_bind_ip(const struct ovnact_lookup_mac_bind_ip *bind, mf_write_subfield_flow(&dst, &sv, uflow); } +static void +execute_lookup_fdb(const struct ovnact_lookup_fdb *lookup_fdb, + const struct ovntrace_datapath *dp, + struct flow *uflow, + struct ovs_list *super) +{ + /* Get logical port number.*/ + struct mf_subfield port_sf = expr_resolve_field(&lookup_fdb->port); + ovs_assert(port_sf.n_bits == 32); + uint32_t port_key = mf_get_subfield(&port_sf, uflow); + + /* Get MAC. */ + struct mf_subfield mac_sf = expr_resolve_field(&lookup_fdb->mac); + ovs_assert(mac_sf.n_bits == 48); + union mf_subvalue mac_sv; + mf_read_subfield(&mac_sf, uflow, &mac_sv); + + const struct ovntrace_fdb *fdb_t + = ovntrace_fdb_find(dp, &mac_sv.mac); + + struct mf_subfield dst = expr_resolve_field(&lookup_fdb->dst); + uint8_t val = 0; + + if (fdb_t && fdb_t->port_key == port_key) { + val = 1; + ovntrace_node_append(super, OVNTRACE_NODE_ACTION, + "/* MAC lookup for "ETH_ADDR_FMT" found in " + "FDB. */", ETH_ADDR_ARGS(uflow->dl_dst)); + } else { + ovntrace_node_append(super, OVNTRACE_NODE_ACTION, + "/* lookup mac failed in mac learning table. */"); + } + union mf_subvalue sv = { .u8_val = val }; + mf_write_subfield_flow(&dst, &sv, uflow); +} + +static void +execute_get_fdb(const struct ovnact_get_fdb *get_fdb, + const struct ovntrace_datapath *dp, + struct flow *uflow) +{ + /* Get MAC. */ + struct mf_subfield mac_sf = expr_resolve_field(&get_fdb->mac); + ovs_assert(mac_sf.n_bits == 48); + union mf_subvalue mac_sv; + mf_read_subfield(&mac_sf, uflow, &mac_sv); + + const struct ovntrace_fdb *fdb_t + = ovntrace_fdb_find(dp, &mac_sv.mac); + + struct mf_subfield dst = expr_resolve_field(&get_fdb->dst); + uint32_t val = 0; + if (fdb_t) { + val = fdb_t->port_key; + } + + union mf_subvalue sv = { .be32_int = htonl(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, @@ -2638,6 +2762,18 @@ trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len, break; case OVNACT_BFD_MSG: break; + + case OVNACT_PUT_FDB: + /* Nothing to do for tracing. */ + break; + + case OVNACT_GET_FDB: + execute_get_fdb(ovnact_get_GET_FDB(a), dp, uflow); + break; + + case OVNACT_LOOKUP_FDB: + execute_lookup_fdb(ovnact_get_LOOKUP_FDB(a), dp, uflow, super); + break; } } ds_destroy(&s); -- 2.29.2 _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
