> On 20 Jul 2026, at 7:05 PM, Dumitru Ceara <[email protected]> wrote:
>
> !-------------------------------------------------------------------|
> CAUTION: External Email
>
> |-------------------------------------------------------------------!
>
> On 7/14/26 10:21 AM, Naveen Yerramneni wrote:
>> A network function (NF) in inline mode redirects matched traffic through a
>> service VM. When such traffic is an unknown-unicast flood (the destination
>> MAC is not yet in the FDB and not yet learned by the underlay), the copy
>> that is redirected to the NF can, after NF processing, be re-flooded and
>> sent back out of the port it originally arrived on. On a VLAN backed
>> logical switch this loop-back copy egresses the localnet port again and
>> makes the physical TOR switch flap the source MAC between ports.
>>
>> Add two OVS-learn based logical actions that, together, allow northd to
>> detect and drop these loop-back copies:
>>
>> - "nf_learn_orig_src_port(ipv6 = true|false)" installs a learned flow in
>> a new OFTABLE_NF_ORIG_SRC_PORT_LEARN table. The learned flow is keyed
>> on the logical datapath and the IP source and destination addresses
>> and matches future packets whose logical output port equals the
>> logical input port of the packet that created it, i.e. packets that
>> are about to be sent back out of the port they entered on. Matching
>> packets get MLF_NF_LOOKUP_HIT set. The learned flow has a 30s idle
>> timeout.
>>
>> - "R = nf_lookup_orig_src_port()" resubmits to the learn table and stores
>> the result of the lookup (MLF_NF_LOOKUP_HIT) into the 1-bit field R.
>>
>> Signed-off-by: Naveen Yerramneni <[email protected]>
>> Acked-by: Aditya Mehakare <[email protected]>
>> CC: Sragdhara Datta Chaudhuri <[email protected]>
>> Assisted-by: Claude Opus 4.7, Cursor
>> ---
>
> Hi Naveen,
>
> Thanks for the patch!
Hi Dumitru,
Thanks for the review!
>
>> controller/lflow.h | 1 +
>> include/ovn/actions.h | 15 +++
>> include/ovn/logical-fields.h | 7 ++
>> lib/actions.c | 190 +++++++++++++++++++++++++++++++++++
>> lib/ovn-util.c | 2 +-
>> ovn-sb.xml | 57 +++++++++++
>> tests/ovn-macros.at | 1 +
>> tests/ovn.at | 19 ++++
>> utilities/ovn-trace.c | 15 +++
>> 9 files changed, 306 insertions(+), 1 deletion(-)
>>
>> diff --git a/controller/lflow.h b/controller/lflow.h
>> index c211fe195..82cf87f08 100644
>> --- a/controller/lflow.h
>> +++ b/controller/lflow.h
>> @@ -105,6 +105,7 @@ struct uuid;
>> #define OFTABLE_GET_REMOTE_FDB 111
>> #define OFTABLE_LEARN_REMOTE_FDB 112
>> #define OFTABLE_EVPN_ARP_LOOKUP 113
>> +#define OFTABLE_NF_ORIG_SRC_PORT_LEARN 114
>>
>> /* Verify that table regions do not overlap. */
>> BUILD_ASSERT_DECL(OFTABLE_LOG_INGRESS_PIPELINE + LOG_PIPELINE_INGRESS_LEN
>> diff --git a/include/ovn/actions.h b/include/ovn/actions.h
>> index 2b81f3f05..3b897cea6 100644
>> --- a/include/ovn/actions.h
>> +++ b/include/ovn/actions.h
>> @@ -140,6 +140,8 @@ struct collector_set_ids;
>> OVNACT(CT_STATE_SAVE, ovnact_result) \
>> OVNACT(MIRROR, ovnact_mirror) \
>> OVNACT(CHK_EVPN_ARP, ovnact_chk_evpn_arp) \
>> + OVNACT(NF_LEARN_ORIG_SRC_PORT, ovnact_nf_learn) \
>> + OVNACT(NF_LOOKUP_ORIG_SRC_PORT, ovnact_nf_lookup) \
>>
>> /* enum ovnact_type, with a member OVNACT_<ENUM> for each action. */
>> enum OVS_PACKED_ENUM ovnact_type {
>> @@ -513,6 +515,19 @@ struct ovnact_lookup_fdb {
>> struct expr_field dst; /* 1-bit destination field. */
>> };
>>
>> +/* OVNACT_NF_LEARN_ORIG_SRC_PORT. */
>> +struct ovnact_nf_learn {
>> + struct ovnact ovnact;
>> + bool ipv6; /* Learn IPv6 (true) or IPv4 (false) flow. */
>
> This comment is a bit superfluous.
>
>> + uint16_t idle_timeout; /* Idle timeout of the learned flow,
>> seconds. */
>
> I'd call this "idle_timeout_s" making it more clear that these are
> seconds. But see my comment below, maybe we should just remove it.
>
>> +};
>> +
>> +/* OVNACT_NF_LOOKUP_ORIG_SRC_PORT. */
>> +struct ovnact_nf_lookup {
>> + struct ovnact ovnact;
>> + struct expr_field dst; /* 1-bit destination field. */
>> +};
>> +
>> /* OVNACT_SAMPLE */
>> struct ovnact_sample {
>> struct ovnact ovnact;
>> diff --git a/include/ovn/logical-fields.h b/include/ovn/logical-fields.h
>> index 9694d105f..b2f1af64a 100644
>> --- a/include/ovn/logical-fields.h
>> +++ b/include/ovn/logical-fields.h
>> @@ -140,6 +140,7 @@ enum mff_log_flags_bits {
>> MLF_PKT_SAMPLED_BIT = 23,
>> MLF_RECIRC_BIT = 24,
>> MLF_EVPN_LOOKUP_BIT = 25,
>> + MLF_NF_LOOKUP_HIT_BIT = 26,
>> MLF_NETWORK_ID_START_BIT = 28,
>> MLF_NETWORK_ID_END_BIT = 31,
>> };
>> @@ -219,6 +220,12 @@ enum mff_log_flags {
>> /* Indicate that the lookup in the EVPN ARP table was successful. */
>> MLF_EVPN_LOOKUP = (1 << MLF_EVPN_LOOKUP_BIT),
>>
>> + /* Indicate that the network function post-redirect lookup matched, i.e.
>> + * the packet is being sent back out of the port it originally entered
>> the
>> + * logical switch on. Used to drop such "loop-back" copies and avoid
>> + * MAC flaps / L2 loops after network function redirection. */
>
> This comment talks about the northd implementation, that's not part of
> this patch and not really relevant here anyway. This bit actually
> identifies packets that are being looped-back to the original port
> post-nf-processing.
>
> Let's rename it to MLF_POST_NF_LOOP_BACK_BIT/MLF_POST_NF_LOOP_BACK. And
> update the comment to something like:
>
> "Indicate that a NF-processed packet is being sent out back the port it
> was originally received on".
>
>> + MLF_NF_LOOKUP_HIT = (1 << MLF_NF_LOOKUP_HIT_BIT),
>> +
>> /* Assign network ID to packet to choose correct network for snat when
>> * lb_force_snat_ip=router_ip. */
>> MLF_NETWORK_ID = (OVN_MAX_NETWORK_ID << MLF_NETWORK_ID_START_BIT),
>> diff --git a/lib/actions.c b/lib/actions.c
>> index 93d7aefd2..26294abca 100644
>> --- a/lib/actions.c
>> +++ b/lib/actions.c
>> @@ -4717,6 +4717,189 @@ ovnact_lookup_fdb_free(struct ovnact_lookup_fdb
>> *get_fdb OVS_UNUSED)
>> {
>> }
>>
>> +static void
>> +format_NF_LEARN_ORIG_SRC_PORT(const struct ovnact_nf_learn *nf_learn,
>> + struct ds *s)
>> +{
>> + ds_put_format(s, "nf_learn_orig_src_port(ipv6 = %s);",
>> + nf_learn->ipv6 ? "true" : "false");
>> +}
>> +
>> +/* Adds a NXAST_LEARN spec matching the value of field 'id' (as it is in the
>> + * packet that triggers the learn) on the same field of future packets. */
>> +static void
>> +nf_learn_put_match_field(struct ofpbuf *ofpacts, enum mf_field_id id)
>> +{
>> + struct ofpact_learn_spec *ol_spec =
>> + ofpbuf_put_zeros(ofpacts, sizeof *ol_spec);
>> + ol_spec->dst.field = mf_from_id(id);
>> + ol_spec->dst.ofs = 0;
>> + ol_spec->dst.n_bits = ol_spec->dst.field->n_bits;
>> + ol_spec->n_bits = ol_spec->dst.n_bits;
>> + ol_spec->dst_type = NX_LEARN_DST_MATCH;
>> + ol_spec->src_type = NX_LEARN_SRC_FIELD;
>> + ol_spec->src.field = mf_from_id(id);
>> +}
>> +
>> +static void
>> +encode_NF_LEARN_ORIG_SRC_PORT(const struct ovnact_nf_learn *nf_learn,
>> + const struct ovnact_encode_params *ep,
>> + struct ofpbuf *ofpacts)
>> +{
>> + size_t ol_offset = ofpacts->size;
>> + struct ofpact_learn *ol = ofpact_put_LEARN(ofpacts);
>> + struct match match = MATCH_CATCHALL_INITIALIZER;
>> + struct ofpact_learn_spec *ol_spec;
>> + unsigned int imm_bytes;
>> + uint8_t *src_imm;
>> +
>> + ol->flags = NX_LEARN_F_DELETE_LEARNED;
>> + ol->idle_timeout = nf_learn->idle_timeout; /* seconds. */
>> + ol->hard_timeout = OFP_FLOW_PERMANENT;
>> + ol->priority = OFP_DEFAULT_PRIORITY;
>> + ol->table_id = OFTABLE_NF_ORIG_SRC_PORT_LEARN;
>> + ol->cookie = htonll(ep->lflow_uuid.parts[0]);
>> +
>> + /* Match on the logical datapath. */
>> + nf_learn_put_match_field(ofpacts, MFF_METADATA);
>> +
>> + /* Match on the same ETH type as the packet that created the flow. */
>> + ol_spec = ofpbuf_put_zeros(ofpacts, sizeof *ol_spec);
>> + ol_spec->dst.field = mf_from_id(MFF_ETH_TYPE);
>> + ol_spec->dst.ofs = 0;
>> + ol_spec->dst.n_bits = ol_spec->dst.field->n_bits;
>> + ol_spec->n_bits = ol_spec->dst.n_bits;
>> + ol_spec->dst_type = NX_LEARN_DST_MATCH;
>> + ol_spec->src_type = NX_LEARN_SRC_IMMEDIATE;
>> + union mf_value imm_eth_type = {
>> + .be16 = nf_learn->ipv6 ? htons(ETH_TYPE_IPV6) : htons(ETH_TYPE_IP)
>> + };
>> + mf_write_subfield_value(&ol_spec->dst, &imm_eth_type, &match);
>> + /* Push value last, as this may reallocate 'ol_spec'. */
>> + imm_bytes = DIV_ROUND_UP(ol_spec->dst.n_bits, 8);
>> + src_imm = ofpbuf_put_zeros(ofpacts, OFPACT_ALIGN(imm_bytes));
>> + memcpy(src_imm, &imm_eth_type, imm_bytes);
>> +
>> + /* Match on the IP source and destination addresses. */
>> + nf_learn_put_match_field(ofpacts,
>> + nf_learn->ipv6 ? MFF_IPV6_SRC : MFF_IPV4_SRC);
>> + nf_learn_put_match_field(ofpacts,
>> + nf_learn->ipv6 ? MFF_IPV6_DST : MFF_IPV4_DST);
>> +
>> + /* Match future packets whose logical output port equals the logical
>> + * input port of the packet that created this flow. Such packets are
>> + * being sent back out of the port they originally arrived on. */
>
> As in the new flag's definition comment, this one is too verbose,
> talking about the northd use case.
>
> Let's not prescribe what the action will be used for. Maybe stop before
> "such packets...".
>
>> + ol_spec = ofpbuf_put_zeros(ofpacts, sizeof *ol_spec);
>> + ol_spec->dst.field = mf_from_id(MFF_LOG_OUTPORT);
>> + ol_spec->dst.ofs = 0;
>> + ol_spec->dst.n_bits = ol_spec->dst.field->n_bits;
>> + ol_spec->n_bits = ol_spec->dst.n_bits;
>> + ol_spec->dst_type = NX_LEARN_DST_MATCH;
>> + ol_spec->src_type = NX_LEARN_SRC_FIELD;
>> + ol_spec->src.field = mf_from_id(MFF_LOG_INPORT);
>> +
>> + /* Load the "lookup hit" flag into MFF_LOG_FLAGS of matching packets. */
>> + ol_spec = ofpbuf_put_zeros(ofpacts, sizeof *ol_spec);
>> + ol_spec->dst.field = mf_from_id(MFF_LOG_FLAGS);
>> + ol_spec->dst.ofs = MLF_NF_LOOKUP_HIT_BIT;
>> + ol_spec->dst.n_bits = 1;
>> + ol_spec->n_bits = ol_spec->dst.n_bits;
>> + ol_spec->dst_type = NX_LEARN_DST_LOAD;
>> + ol_spec->src_type = NX_LEARN_SRC_IMMEDIATE;
>> + union mf_value imm_hit = { .u8 = 1 };
>> + mf_write_subfield_value(&ol_spec->dst, &imm_hit, &match);
>> + /* Push value last, as this may reallocate 'ol_spec'. */
>> + imm_bytes = DIV_ROUND_UP(ol_spec->dst.n_bits, 8);
>> + src_imm = ofpbuf_put_zeros(ofpacts, OFPACT_ALIGN(imm_bytes));
>> + memcpy(src_imm, &imm_hit, imm_bytes);
>> +
>> + ol = ofpbuf_at_assert(ofpacts, ol_offset, sizeof *ol);
>> + ofpact_finish_LEARN(ofpacts, &ol);
>> +}
>> +
>> +static void
>> +parse_nf_learn_orig_src_port(struct action_context *ctx,
>> + struct ovnact_nf_learn *nf_learn)
>> +{
>> + nf_learn->idle_timeout = 30; /* seconds. */
>
> Will there ever be a need to make this configurable? I think not.. in
> that case we should just add a new macro definition and remove the
> "idle_timeout" field of the ovnact_nf_learn struct.
>
Currently there is no plan to make this configurable. If some
requirement comes in future, we can consider it. I will remove
this for now.
> Also, this will make the learned flows have idle_timeout 30s, always.
> So if there's no traffic matching the learned flow for 30s then the
> entry is removed.
>
> So if at that point a new packet is processed on a LSP and requires NF
> processing a new learn() action is hit for that packet and a new learned
> flow is created. Is there a race between the NF-processed version of
> the packet being sent back into OVS (OVN) and the learned flow being
> created?
>
> I assume there isn't any but I was curious if you tested that.
I have not tested this case but to my knowledge there should not be
any issue.
>
>> +
>> + lexer_force_match(ctx->lexer, LEX_T_LPAREN);
>> + if (!lexer_match_id(ctx->lexer, "ipv6")) {
>> + lexer_syntax_error(ctx->lexer, "invalid parameter");
>> + return;
>> + }
>> + if (!lexer_force_match(ctx->lexer, LEX_T_EQUALS)) {
>> + lexer_syntax_error(ctx->lexer, "invalid parameter");
>
> lexer_syntax_error not needed here, it's already covered by force_match.
>
>> + return;
>> + }
>> + if (lexer_match_id(ctx->lexer, "true")) {
>> + nf_learn->ipv6 = true;
>> + } else if (lexer_match_id(ctx->lexer, "false")) {
>> + nf_learn->ipv6 = false;
>> + } else {
>> + lexer_syntax_error(ctx->lexer, "expecting true or false");
>> + return;
>> + }
>> + lexer_force_match(ctx->lexer, LEX_T_RPAREN);
>> +}
>> +
>> +static void
>> +ovnact_nf_learn_free(struct ovnact_nf_learn *nf_learn OVS_UNUSED)
>> +{
>> +}
>> +
>> +static void
>> +format_NF_LOOKUP_ORIG_SRC_PORT(const struct ovnact_nf_lookup *nf_lookup,
>> + struct ds *s)
>> +{
>> + expr_field_format(&nf_lookup->dst, s);
>> + ds_put_cstr(s, " = nf_lookup_orig_src_port();");
>> +}
>> +
>> +static void
>> +encode_NF_LOOKUP_ORIG_SRC_PORT(
>> + const struct ovnact_nf_lookup *nf_lookup,
>> + const struct ovnact_encode_params *ep OVS_UNUSED,
>> + struct ofpbuf *ofpacts)
>> +{
>> + struct mf_subfield dst = expr_resolve_field(&nf_lookup->dst);
>> + ovs_assert(dst.field);
>> +
>> + put_load(0, MFF_LOG_FLAGS, MLF_NF_LOOKUP_HIT_BIT, 1, ofpacts);
>> + emit_resubmit(ofpacts, OFTABLE_NF_ORIG_SRC_PORT_LEARN);
>> +
>> + 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_NF_LOOKUP_HIT_BIT;
>> + orm->src.n_bits = 1;
>> +}
>> +
>> +static void
>> +parse_nf_lookup_orig_src_port(struct action_context *ctx,
>> + struct expr_field *dst,
>> + struct ovnact_nf_lookup *nf_lookup)
>> +{
>> + lexer_get(ctx->lexer); /* Skip nf_lookup_orig_src_port. */
>> + lexer_get(ctx->lexer); /* Skip '('. */
>
> This should be lexer_force_match(ctx->lexer, LEX_T_LPAREN).
>
>> +
>> + /* 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;
>> + }
>> + nf_lookup->dst = *dst;
>> +
>> + lexer_force_match(ctx->lexer, LEX_T_RPAREN);
>> +}
>> +
>> +static void
>> +ovnact_nf_lookup_free(struct ovnact_nf_lookup *nf_lookup OVS_UNUSED)
>> +{
>> +}
>> +
>> static void
>> parse_check_in_port_sec(struct action_context *ctx,
>> const struct expr_field *dst,
>> @@ -5976,6 +6159,10 @@ parse_set_action(struct action_context *ctx)
>> && lexer_lookahead(ctx->lexer) == LEX_T_LPAREN) {
>> parse_lookup_fdb(
>> ctx, &lhs, ovnact_put_LOOKUP_FDB(ctx->ovnacts));
>> + } else if (!strcmp(ctx->lexer->token.s, "nf_lookup_orig_src_port")
>> + && lexer_lookahead(ctx->lexer) == LEX_T_LPAREN) {
>> + parse_nf_lookup_orig_src_port(
>> + ctx, &lhs,
>> ovnact_put_NF_LOOKUP_ORIG_SRC_PORT(ctx->ovnacts));
>> } else if (!strcmp(ctx->lexer->token.s, "check_in_port_sec")
>> && lexer_lookahead(ctx->lexer) == LEX_T_LPAREN) {
>> parse_check_in_port_sec(
>> @@ -6147,6 +6334,9 @@ parse_action(struct action_context *ctx)
>> ovnact_put_FLOOD_REMOTE(ctx->ovnacts);
>> } else if (lexer_match_id(ctx->lexer, "mirror")) {
>> parse_MIRROR_action(ctx);
>> + } else if (lexer_match_id(ctx->lexer, "nf_learn_orig_src_port")) {
>> + parse_nf_learn_orig_src_port(
>> + ctx, ovnact_put_NF_LEARN_ORIG_SRC_PORT(ctx->ovnacts));
>> } else {
>> lexer_syntax_error(ctx->lexer, "expecting action");
>> }
>> diff --git a/lib/ovn-util.c b/lib/ovn-util.c
>> index 80346d5bb..4c0587efb 100644
>> --- a/lib/ovn-util.c
>> +++ b/lib/ovn-util.c
>> @@ -1007,7 +1007,7 @@ ip_address_and_port_from_lb_key(const char *key, char
>> **ip_address,
>> *
>> * NOTE: If OVN_NORTHD_PIPELINE_CSUM is updated make sure to double check
>> * whether an update of OVN_INTERNAL_MINOR_VER is required. */
>> -#define OVN_NORTHD_PIPELINE_CSUM "118971668 11318"
>> +#define OVN_NORTHD_PIPELINE_CSUM "2232216761 11430"
>> #define OVN_INTERNAL_MINOR_VER 15
>>
>> /* Returns the OVN version. The caller must free the returned value. */
>> diff --git a/ovn-sb.xml b/ovn-sb.xml
>> index b54c25c91..434c8e43e 100644
>> --- a/ovn-sb.xml
>> +++ b/ovn-sb.xml
>> @@ -1831,6 +1831,63 @@
>> </p>
>> </dd>
>>
>> + <dt>
>> + <code>nf_learn_orig_src_port(ipv6 = <var>B</var>);</code>
>> + </dt>
>> +
>> + <dd>
>> + <p>
>> + Records the logical input port that the current IP packet
>> + entered the logical switch on by learning a flow. The learned
>> + flow matches a later packet of the same flow (same logical
>> + datapath and IP source and destination addresses) when its
>> + logical output port equals that input port, that is, when the
>> + packet is about to be sent back out of the port it originally
>> + arrived on.
>> + </p>
>> +
>> + <p>
>> + <var>B</var> must be <code>true</code> to learn an IPv6 flow or
>> + <code>false</code> to learn an IPv4 flow. The learned flow has
>> a
>> + 30 second idle timeout. This action is used together with
>> + <code>nf_lookup_orig_src_port()</code> to drop the duplicate
>> + copies that a network function (NF) redirection can produce when
>> + the destination MAC address is still unknown, which would
>> + otherwise cause MAC address flaps or L2 loops.
>> + </p>
>> +
>> + <p>
>> + <b>Example:</b>
>> + <code>nf_learn_orig_src_port(ipv6 = false);</code>
>> + </p>
>> + </dd>
>> +
>> + <dt>
>> + <code><var>R</var> = nf_lookup_orig_src_port();</code>
>> + </dt>
>> +
>> + <dd>
>> + <p>
>> + <b>Result</b>: stored to a 1-bit subfield <var>R</var>.
>> + </p>
>> +
>> + <p>
>> + Looks up the flow learned by
>> + <code>nf_learn_orig_src_port()</code>. Stores <code>1</code> in
>> + <var>R</var> if the current packet matches a learned flow, that
>> is,
>> + if it is an IP packet that, after network function redirection,
>> is
>> + about to be sent back out of the logical input port it
>> originally
>> + arrived on. Otherwise stores <code>0</code>.
>> + </p>
>> +
>> + <p>
>> + <b>Example:</b>
>> + <code>
>> + reg0[0] = nf_lookup_orig_src_port();
>> + </code>
>> + </p>
>> + </dd>
>> +
>> <dt><code>nd_ns { <var>action</var>; </code>...<code> };</code></dt>
>> <dd>
>> <p>
>> diff --git a/tests/ovn-macros.at b/tests/ovn-macros.at
>> index 8879c2fa1..51b73083e 100644
>> --- a/tests/ovn-macros.at
>> +++ b/tests/ovn-macros.at
>> @@ -1650,5 +1650,6 @@ m4_define([OFTABLE_CT_ORIG_PROTO_LOAD], [110])
>> m4_define([OFTABLE_GET_REMOTE_FDB], [111])
>> m4_define([OFTABLE_LEARN_REMOTE_FDB], [112])
>> m4_define([OFTABLE_EVPN_ARP_LOOKUP], [113])
>> +m4_define([OFTABLE_NF_ORIG_SRC_PORT_LEARN], [114])
>>
>> m4_define([OFTABLE_SAVE_INPORT_HEX], [m4_eval(OFTABLE_SAVE_INPORT, 16)])
>> diff --git a/tests/ovn.at b/tests/ovn.at
>> index 7e4f78b8f..29ea90215 100644
>> --- a/tests/ovn.at
>> +++ b/tests/ovn.at
>> @@ -2129,6 +2129,25 @@ reg1[[1]] = lookup_fdb(outport, ip4.src);
>> reg1[[1]] = lookup_fdb(ip4.src, eth.src);
>> Cannot use numeric field ip4.src where string field is required.
>>
>> +# nf_learn_orig_src_port / nf_lookup_orig_src_port
>> +nf_learn_orig_src_port(ipv6 = false);
>> + encodes as
>> learn(table=OFTABLE_NF_ORIG_SRC_PORT_LEARN,idle_timeout=30,delete_learned,cookie=0xaaaaaaaa,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],NXM_OF_IP_DST[[]],NXM_NX_REG15[[]]=NXM_NX_REG14[[0..-1]],load:0x1->NXM_NX_REG10[[26]])
>> +
>> +nf_learn_orig_src_port(ipv6 = true);
>> + encodes as
>> learn(table=OFTABLE_NF_ORIG_SRC_PORT_LEARN,idle_timeout=30,delete_learned,cookie=0xaaaaaaaa,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],NXM_NX_IPV6_DST[[]],NXM_NX_REG15[[]]=NXM_NX_REG14[[0..-1]],load:0x1->NXM_NX_REG10[[26]])
>> +
>> +nf_learn_orig_src_port();
>> + Syntax error at `)' invalid parameter.
>> +
>> +nf_learn_orig_src_port(ipv6 = maybe);
>> + Syntax error at `maybe' expecting true or false.
>> +
>> +reg0[[0]] = nf_lookup_orig_src_port();
>> + encodes as
>> set_field:0/0x4000000->reg10,resubmit(,OFTABLE_NF_ORIG_SRC_PORT_LEARN),move:NXM_NX_REG10[[26]]->NXM_NX_XXREG0[[96]]
>> +
>> +reg0 = nf_lookup_orig_src_port();
>> + Cannot use 32-bit field reg0[[0..31]] where 1-bit field is required.
>> +
>> # check_in_port_sec
>> reg0[[0]] = check_in_port_sec();
>> encodes as
>> set_field:0/0x1000->reg10,resubmit(,OFTABLE_CHK_IN_PORT_SEC),move:NXM_NX_REG10[[12]]->NXM_NX_XXREG0[[96]]
>> diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c
>> index 0dcee89ac..a6feb30e0 100644
>> --- a/utilities/ovn-trace.c
>> +++ b/utilities/ovn-trace.c
>> @@ -3641,6 +3641,21 @@ trace_actions(const struct ovnact *ovnacts, size_t
>> ovnacts_len,
>> execute_chk_evpn_arp(ovnact_get_CHK_EVPN_ARP(a), dp, uflow,
>> super);
>> break;
>> + case OVNACT_NF_LEARN_ORIG_SRC_PORT:
>> + /* Nothing to do for tracing. */
>> + break;
>> + case OVNACT_NF_LOOKUP_ORIG_SRC_PORT: {
>> + /* Assume a lookup miss and clear the destination subfield. */
>> + const struct ovnact_nf_lookup *nf_lookup =
>> + ovnact_get_NF_LOOKUP_ORIG_SRC_PORT(a);
>> + struct mf_subfield dst = expr_resolve_field(&nf_lookup->dst);
>> + union mf_subvalue sv = { .u8_val = 0 };
>> + mf_write_subfield_flow(&dst, &sv, uflow);
>> + ovntrace_node_append(super, OVNTRACE_NODE_ACTION,
>> + "/* nf_lookup_orig_src_port miss "
>> + "(learn table not modelled). */");
>
> Let's add this into a function, execute_nf_lookup_....(), instead of
> inlining the code here.
>
> Also, "not modelled" is too fancy IMO, I'd just say "Assumed
> nf_lookup_orig_src_port miss.". Or something like that.
>
>> + break;
>> + }
>> }
>> }
>> ofpbuf_uninit(&stack);
>
I will address other comments in this patch.
Thanks,
Naveen
> Regards,
> Dumitru
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev