Allow MAC binding lookup and cache-use actions to carry an optional
scope key. Temporarily enter the shared namespace, then restore packet
metadata before continuing. Preserve private fallback and static
override
lookup stages.

Document the new syntax and test parsing and OpenFlow encoding.

Assisted-by: OpenAI Codex
Signed-off-by: Tim Rozet <[email protected]>
---
 controller/lflow.c    |   4 ++
 controller/lflow.h    |   4 ++
 include/ovn/actions.h |  19 +++++++-
 lib/actions.c         | 107 ++++++++++++++++++++++++++++++++++++++++--
 lib/ovn-util.c        |   4 +-
 ovn-sb.xml            |  80 +++++++++++++++++++++++++------
 tests/ovn-macros.at   |   4 ++
 tests/ovn.at          |  28 ++++++++++-
 tests/test-ovn.c      |   4 ++
 9 files changed, 231 insertions(+), 23 deletions(-)

diff --git a/controller/lflow.c b/controller/lflow.c
index a71d4e0d7..74848365f 100644
--- a/controller/lflow.c
+++ b/controller/lflow.c
@@ -932,6 +932,10 @@ add_matches_to_flow_table(const struct sbrec_logical_flow 
*lflow,
         .output_ptable = output_ptable,
         .mac_bind_ptable = OFTABLE_MAC_BINDING,
         .mac_lookup_ptable = OFTABLE_MAC_LOOKUP,
+        .shared_mac_bind_ptable = OFTABLE_SHARED_MAC_BINDING,
+        .shared_mac_lookup_ptable = OFTABLE_SHARED_MAC_LOOKUP,
+        .mac_bind_override_ptable = OFTABLE_MAC_BINDING_OVERRIDE,
+        .mac_lookup_override_ptable = OFTABLE_MAC_LOOKUP_OVERRIDE,
         .lb_hairpin_ptable = OFTABLE_CHK_LB_HAIRPIN,
         .lb_hairpin_reply_ptable = OFTABLE_CHK_LB_HAIRPIN_REPLY,
         .ct_snat_vip_ptable = OFTABLE_CT_SNAT_HAIRPIN,
diff --git a/controller/lflow.h b/controller/lflow.h
index ca84f3753..c20dedec7 100644
--- a/controller/lflow.h
+++ b/controller/lflow.h
@@ -104,6 +104,10 @@ struct uuid;
 #define OFTABLE_LEARN_REMOTE_FDB          110
 #define OFTABLE_EVPN_ARP_LOOKUP           111
 #define OFTABLE_NF_ORIG_INPORT_LEARN      112
+#define OFTABLE_SHARED_MAC_BINDING        113
+#define OFTABLE_SHARED_MAC_LOOKUP         114
+#define OFTABLE_MAC_BINDING_OVERRIDE      115
+#define OFTABLE_MAC_LOOKUP_OVERRIDE       116
 
 /* 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 7def8917e..77d973e93 100644
--- a/include/ovn/actions.h
+++ b/include/ovn/actions.h
@@ -128,7 +128,7 @@ struct collector_set_ids;
     OVNACT(COMMIT_LB_AFF,     ovnact_commit_lb_aff)   \
     OVNACT(CHK_LB_AFF,        ovnact_result)          \
     OVNACT(SAMPLE,            ovnact_sample)          \
-    OVNACT(MAC_CACHE_USE,     ovnact_null)            \
+    OVNACT(MAC_CACHE_USE,     ovnact_mac_cache_use)   \
     OVNACT(CT_ORIG_NW_DST,    ovnact_result)          \
     OVNACT(CT_ORIG_IP6_DST,   ovnact_result)          \
     OVNACT(CT_ORIG_TP_DST,    ovnact_result)          \
@@ -369,6 +369,7 @@ struct ovnact_get_mac_bind {
     struct ovnact ovnact;
     struct expr_field port;     /* Logical port name. */
     struct expr_field ip;       /* 32-bit or 128-bit IP address. */
+    uint32_t scope;             /* Optional MAC binding scope key. */
 };
 
 /* OVNACT_PUT_ARP, ONVACT_PUT_ND. */
@@ -386,6 +387,7 @@ struct ovnact_lookup_mac_bind {
     struct expr_field port;     /* Logical port name. */
     struct expr_field ip;       /* 32-bit or 128-bit IP address. */
     struct expr_field mac;      /* 48-bit Ethernet address. */
+    uint32_t scope;             /* Optional MAC binding scope key. */
 };
 
 /* OVNACT_LOOKUP_ARP_IP, OVNACT_LOOKUP_ND_IP. */
@@ -394,6 +396,13 @@ struct ovnact_lookup_mac_bind_ip {
     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. */
+    uint32_t scope;             /* Optional MAC binding scope key. */
+};
+
+/* OVNACT_MAC_CACHE_USE. */
+struct ovnact_mac_cache_use {
+    struct ovnact ovnact;
+    uint32_t scope;             /* Optional MAC binding scope key. */
 };
 
 struct ovnact_gen_option {
@@ -970,6 +979,14 @@ struct ovnact_encode_params {
                                    resubmit. */
     uint8_t mac_lookup_ptable;  /* OpenFlow table for
                                    'lookup_arp'/'lookup_nd' to resubmit. */
+    uint8_t shared_mac_bind_ptable; /* OpenFlow table for shared dynamic
+                                       MAC bindings. */
+    uint8_t shared_mac_lookup_ptable; /* OpenFlow table for shared dynamic
+                                         MAC binding lookups. */
+    uint8_t mac_bind_override_ptable; /* OpenFlow table for high-priority
+                                         binding overrides. */
+    uint8_t mac_lookup_override_ptable; /* OpenFlow table for high-priority
+                                           lookup overrides. */
     uint8_t lb_hairpin_ptable;  /* OpenFlow table for
                                  * 'chk_lb_hairpin' to resubmit. */
     uint8_t lb_hairpin_reply_ptable;  /* OpenFlow table for
diff --git a/lib/actions.c b/lib/actions.c
index 0e95e2d70..fd7ad6511 100644
--- a/lib/actions.c
+++ b/lib/actions.c
@@ -2219,6 +2219,26 @@ ovnact_nest_free(struct ovnact_nest *on)
     free(on->nested);
 }
 
+static void
+parse_mac_binding_scope(struct action_context *ctx, uint32_t *scope)
+{
+    *scope = 0;
+    if (!lexer_match(ctx->lexer, LEX_T_COMMA)) {
+        return;
+    }
+
+    int value;
+    if (!lexer_force_int(ctx->lexer, &value)) {
+        return;
+    }
+    if (value < 1 || value > 0xffffff) {
+        lexer_error(ctx->lexer,
+                    "MAC binding scope must be in the range 1 to 16777215");
+        return;
+    }
+    *scope = value;
+}
+
 static void
 parse_get_mac_bind(struct action_context *ctx, int width,
                    struct ovnact_get_mac_bind *get_mac)
@@ -2227,6 +2247,7 @@ parse_get_mac_bind(struct action_context *ctx, int width,
     action_parse_field(ctx, 0, false, &get_mac->port);
     lexer_force_match(ctx->lexer, LEX_T_COMMA);
     action_parse_field(ctx, width, false, &get_mac->ip);
+    parse_mac_binding_scope(ctx, &get_mac->scope);
     lexer_force_match(ctx->lexer, LEX_T_RPAREN);
 }
 
@@ -2238,6 +2259,9 @@ format_get_mac_bind(const struct ovnact_get_mac_bind 
*get_mac,
     expr_field_format(&get_mac->port, s);
     ds_put_cstr(s, ", ");
     expr_field_format(&get_mac->ip, s);
+    if (get_mac->scope) {
+        ds_put_format(s, ", %"PRIu32, get_mac->scope);
+    }
     ds_put_cstr(s, ");");
 }
 
@@ -2253,6 +2277,19 @@ format_GET_ND(const struct ovnact_get_mac_bind *get_mac, 
struct ds *s)
     format_get_mac_bind(get_mac, "get_nd", s);
 }
 
+static void
+encode_mac_binding_scope(uint32_t scope, enum mf_field_id port_field,
+                         uint8_t table, struct ofpbuf *ofpacts)
+{
+    init_stack(ofpact_put_STACK_PUSH(ofpacts), MFF_LOG_DATAPATH);
+    init_stack(ofpact_put_STACK_PUSH(ofpacts), port_field);
+    put_load(scope, MFF_LOG_DATAPATH, 0, 64, ofpacts);
+    put_load(0, port_field, 0, 32, ofpacts);
+    emit_resubmit(ofpacts, table);
+    init_stack(ofpact_put_STACK_POP(ofpacts), port_field);
+    init_stack(ofpact_put_STACK_POP(ofpacts), MFF_LOG_DATAPATH);
+}
+
 static void
 encode_get_mac(const struct ovnact_get_mac_bind *get_mac,
                enum mf_field_id ip_field,
@@ -2267,6 +2304,11 @@ encode_get_mac(const struct ovnact_get_mac_bind *get_mac,
 
     put_load(0, MFF_ETH_DST, 0, 48, ofpacts);
     emit_resubmit(ofpacts, ep->mac_bind_ptable);
+    if (get_mac->scope) {
+        encode_mac_binding_scope(get_mac->scope, MFF_LOG_OUTPORT,
+                                 ep->shared_mac_bind_ptable, ofpacts);
+        emit_resubmit(ofpacts, ep->mac_bind_override_ptable);
+    }
 
     encode_restore_args(args, ARRAY_SIZE(args), ofpacts);
 }
@@ -2378,6 +2420,9 @@ static void format_lookup_mac_bind(
     expr_field_format(&lookup_mac->ip, s);
     ds_put_cstr(s, ", ");
     expr_field_format(&lookup_mac->mac, s);
+    if (lookup_mac->scope) {
+        ds_put_format(s, ", %"PRIu32, lookup_mac->scope);
+    }
     ds_put_cstr(s, ");");
 }
 
@@ -2414,6 +2459,11 @@ encode_lookup_mac_bind(const struct 
ovnact_lookup_mac_bind *lookup_mac,
 
     put_load(0, MFF_LOG_FLAGS, MLF_LOOKUP_MAC_BIT, 1, ofpacts);
     emit_resubmit(ofpacts, ep->mac_lookup_ptable);
+    if (lookup_mac->scope) {
+        encode_mac_binding_scope(lookup_mac->scope, MFF_LOG_INPORT,
+                                 ep->shared_mac_lookup_ptable, ofpacts);
+        emit_resubmit(ofpacts, ep->mac_lookup_override_ptable);
+    }
 
     struct ofpact_reg_move *orm = ofpact_put_REG_MOVE(ofpacts);
     orm->dst = dst;
@@ -2462,6 +2512,7 @@ parse_lookup_mac_bind(struct action_context *ctx,
     action_parse_field(ctx, width, false, &lookup_mac->ip);
     lexer_force_match(ctx->lexer, LEX_T_COMMA);
     action_parse_field(ctx, 48, false, &lookup_mac->mac);
+    parse_mac_binding_scope(ctx, &lookup_mac->scope);
     lexer_force_match(ctx->lexer, LEX_T_RPAREN);
     lookup_mac->dst = *dst;
 }
@@ -2483,6 +2534,9 @@ static void format_lookup_mac_bind_ip(
     expr_field_format(&lookup_mac->port, s);
     ds_put_cstr(s, ", ");
     expr_field_format(&lookup_mac->ip, s);
+    if (lookup_mac->scope) {
+        ds_put_format(s, ", %"PRIu32, lookup_mac->scope);
+    }
     ds_put_cstr(s, ");");
 }
 
@@ -2519,6 +2573,11 @@ encode_lookup_mac_bind_ip(const struct 
ovnact_lookup_mac_bind_ip *lookup_mac,
 
     put_load(0, MFF_LOG_FLAGS, MLF_LOOKUP_MAC_BIT, 1, ofpacts);
     emit_resubmit(ofpacts, ep->mac_bind_ptable);
+    if (lookup_mac->scope) {
+        encode_mac_binding_scope(lookup_mac->scope, MFF_LOG_OUTPORT,
+                                 ep->shared_mac_bind_ptable, ofpacts);
+        emit_resubmit(ofpacts, ep->mac_bind_override_ptable);
+    }
 
     struct ofpact_reg_move *orm = ofpact_put_REG_MOVE(ofpacts);
     orm->dst = dst;
@@ -2566,6 +2625,7 @@ parse_lookup_mac_bind_ip(struct action_context *ctx,
     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);
+    parse_mac_binding_scope(ctx, &lookup_mac->scope);
     lexer_force_match(ctx->lexer, LEX_T_RPAREN);
     lookup_mac->dst = *dst;
 }
@@ -5483,17 +5543,54 @@ encode_CHK_LB_AFF(const struct ovnact_result *res,
 }
 
 static void
-format_MAC_CACHE_USE(const struct ovnact_null *null OVS_UNUSED, struct ds *s)
+parse_MAC_CACHE_USE(struct action_context *ctx,
+                    struct ovnact_mac_cache_use *mac_cache_use)
 {
-    ds_put_cstr(s, "mac_cache_use;");
+    mac_cache_use->scope = 0;
+    if (!lexer_match(ctx->lexer, LEX_T_LPAREN)) {
+        return;
+    }
+
+    int value;
+    if (lexer_force_int(ctx->lexer, &value)) {
+        if (value < 1 || value > 0xffffff) {
+            lexer_error(ctx->lexer, "MAC binding scope must be in the "
+                        "range 1 to 16777215");
+        } else {
+            mac_cache_use->scope = value;
+        }
+    }
+    lexer_force_match(ctx->lexer, LEX_T_RPAREN);
 }
 
 static void
-encode_MAC_CACHE_USE(const struct ovnact_null *null OVS_UNUSED,
+format_MAC_CACHE_USE(const struct ovnact_mac_cache_use *mac_cache_use,
+                     struct ds *s)
+{
+    if (mac_cache_use->scope) {
+        ds_put_format(s, "mac_cache_use(%"PRIu32");", mac_cache_use->scope);
+    } else {
+        ds_put_cstr(s, "mac_cache_use;");
+    }
+}
+
+static void
+encode_MAC_CACHE_USE(const struct ovnact_mac_cache_use *mac_cache_use,
                      const struct ovnact_encode_params *ep,
                      struct ofpbuf *ofpacts)
 {
-    emit_resubmit(ofpacts, ep->mac_cache_use_table);
+    if (mac_cache_use->scope) {
+        encode_mac_binding_scope(mac_cache_use->scope, MFF_LOG_INPORT,
+                                 ep->mac_cache_use_table, ofpacts);
+    } else {
+        emit_resubmit(ofpacts, ep->mac_cache_use_table);
+    }
+}
+
+static void
+ovnact_mac_cache_use_free(
+    struct ovnact_mac_cache_use *mac_cache_use OVS_UNUSED)
+{
 }
 
 static bool
@@ -5999,7 +6096,7 @@ parse_action(struct action_context *ctx)
     } else if (lexer_match_id(ctx->lexer, "sample")) {
         parse_sample(ctx);
     } else if (lexer_match_id(ctx->lexer, "mac_cache_use")) {
-        ovnact_put_MAC_CACHE_USE(ctx->ovnacts);
+        parse_MAC_CACHE_USE(ctx, ovnact_put_MAC_CACHE_USE(ctx->ovnacts));
     } else if (lexer_match_id(ctx->lexer, "flood_remote")) {
         ovnact_put_FLOOD_REMOTE(ctx->ovnacts);
     } else if (lexer_match_id(ctx->lexer, "mirror")) {
diff --git a/lib/ovn-util.c b/lib/ovn-util.c
index eb1fa8a06..d10ad1c7b 100644
--- a/lib/ovn-util.c
+++ b/lib/ovn-util.c
@@ -1007,8 +1007,8 @@ 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 "3980195012 11262"
-#define OVN_INTERNAL_MINOR_VER 16
+#define OVN_NORTHD_PIPELINE_CSUM "1820732613 11262"
+#define OVN_INTERNAL_MINOR_VER 17
 
 /* Returns the OVN version. The caller must free the returned value. */
 char *
diff --git a/ovn-sb.xml b/ovn-sb.xml
index a05c043f6..f9e24dc8c 100644
--- a/ovn-sb.xml
+++ b/ovn-sb.xml
@@ -1634,12 +1634,15 @@
           <p><b>Prerequisite:</b> <code>ip4</code></p>
         </dd>
 
-        <dt><code>get_arp(<var>P</var>, <var>A</var>);</code></dt>
+        <dt>
+          <code>get_arp(<var>P</var>, <var>A</var>[, <var>S</var>]);</code>
+        </dt>
 
         <dd>
           <p>
             <b>Parameters</b>: logical port string field <var>P</var>, 32-bit
-            IP address field <var>A</var>.
+            IP address field <var>A</var>, optional MAC binding scope key
+            <var>S</var>.
           </p>
 
           <p>
@@ -1649,6 +1652,13 @@
             <code>00:00:00:00:00:00</code> in <code>eth.dst</code>.
           </p>
 
+          <p>
+            If <var>S</var> is specified, the shared dynamic binding in scope
+            <var>S</var> takes precedence over a private dynamic or
+            low-priority binding on <var>P</var>.  A high-priority binding
+            on <var>P</var> still takes precedence over the shared binding.
+          </p>
+
           <p><b>Example:</b> <code>get_arp(outport, ip4.dst);</code></p>
         </dd>
 
@@ -1673,14 +1683,15 @@
         </dd>
 
         <dt>
-          <code><var>R</var> = lookup_arp(<var>P</var>, <var>A</var>, 
<var>M</var>);</code>
+          <code><var>R</var> = lookup_arp(<var>P</var>, <var>A</var>,
+          <var>M</var>[, <var>S</var>]);</code>
         </dt>
 
         <dd>
           <p>
             <b>Parameters</b>: logical port string field <var>P</var>, 32-bit
             IP address field <var>A</var>, 48-bit MAC address field
-            <var>M</var>.
+            <var>M</var>, optional MAC binding scope key <var>S</var>.
           </p>
 
           <p>
@@ -1693,6 +1704,12 @@
             the 1-bit subfield <var>R</var>, else 0.
           </p>
 
+          <p>
+            If <var>S</var> is specified, lookup uses the same private
+            fallback, shared dynamic, and high-priority precedence as
+            <code>get_arp</code>.
+          </p>
+
           <p>
             <b>Example:</b>
             <code>
@@ -1702,13 +1719,15 @@
         </dd>
 
         <dt>
-          <code><var>R</var> = lookup_arp_ip(<var>P</var>, 
<var>A</var>);</code>
+          <code><var>R</var> = lookup_arp_ip(<var>P</var>, <var>A</var>[,
+          <var>S</var>]);</code>
         </dt>
 
         <dd>
           <p>
             <b>Parameters</b>: logical port string field <var>P</var>, 32-bit
-            IP address field <var>A</var>.
+            IP address field <var>A</var>, optional MAC binding scope key
+            <var>S</var>.
           </p>
 
           <p>
@@ -1721,6 +1740,12 @@
             <var>R</var>, else 0.
           </p>
 
+          <p>
+            If <var>S</var> is specified, lookup uses the same private
+            fallback, shared dynamic, and high-priority precedence as
+            <code>get_arp</code>.
+          </p>
+
           <p>
             <b>Example:</b>
             <code>
@@ -2036,12 +2061,15 @@
           </p>
         </dd>
 
-        <dt><code>get_nd(<var>P</var>, <var>A</var>);</code></dt>
+        <dt>
+          <code>get_nd(<var>P</var>, <var>A</var>[, <var>S</var>]);</code>
+        </dt>
 
         <dd>
           <p>
             <b>Parameters</b>: logical port string field <var>P</var>, 128-bit
-            IPv6 address field <var>A</var>.
+            IPv6 address field <var>A</var>, optional MAC binding scope key
+            <var>S</var>.
           </p>
 
           <p>
@@ -2051,6 +2079,13 @@
             <code>00:00:00:00:00:00</code> in <code>eth.dst</code>.
           </p>
 
+          <p>
+            If <var>S</var> is specified, the shared dynamic binding in scope
+            <var>S</var> takes precedence over a private dynamic or
+            low-priority binding on <var>P</var>.  A high-priority binding
+            on <var>P</var> still takes precedence over the shared binding.
+          </p>
+
           <p><b>Example:</b> <code>get_nd(outport, ip6.dst);</code></p>
         </dd>
 
@@ -2074,14 +2109,15 @@
           <p><b>Example:</b> <code>put_nd(inport, nd.target, 
nd.tll);</code></p>
         </dd>
 
-        <dt><code><var>R</var> = lookup_nd(<var>P</var>, <var>A</var>, 
<var>M</var>);</code>
+        <dt><code><var>R</var> = lookup_nd(<var>P</var>, <var>A</var>,
+          <var>M</var>[, <var>S</var>]);</code>
         </dt>
 
         <dd>
           <p>
             <b>Parameters</b>: logical port string field <var>P</var>, 128-bit
             IP address field <var>A</var>, 48-bit MAC address field
-            <var>M</var>.
+            <var>M</var>, optional MAC binding scope key <var>S</var>.
           </p>
 
           <p>
@@ -2094,6 +2130,12 @@
             the 1-bit subfield <var>R</var>, else 0.
           </p>
 
+          <p>
+            If <var>S</var> is specified, lookup uses the same private
+            fallback, shared dynamic, and high-priority precedence as
+            <code>get_nd</code>.
+          </p>
+
           <p>
             <b>Example:</b>
             <code>
@@ -2102,13 +2144,15 @@
           </p>
         </dd>
 
-        <dt><code><var>R</var> = lookup_nd_ip(<var>P</var>, 
<var>A</var>);</code>
+        <dt><code><var>R</var> = lookup_nd_ip(<var>P</var>, <var>A</var>[,
+          <var>S</var>]);</code>
         </dt>
 
         <dd>
           <p>
             <b>Parameters</b>: logical port string field <var>P</var>, 128-bit
-            IP address field <var>A</var>.
+            IP address field <var>A</var>, optional MAC binding scope key
+            <var>S</var>.
           </p>
 
           <p>
@@ -2121,6 +2165,12 @@
             <var>R</var>, else 0.
           </p>
 
+          <p>
+            If <var>S</var> is specified, lookup uses the same private
+            fallback, shared dynamic, and high-priority precedence as
+            <code>get_nd</code>.
+          </p>
+
           <p>
             <b>Example:</b>
             <code>
@@ -3012,11 +3062,13 @@ tcp.flags = RST;
           </dl>
         </dd>
 
-        <dt><code>mac_cache_use;</code></dt>
+        <dt><code>mac_cache_use[(<var>S</var>)];</code></dt>
         <dd>
           <p>
             This action resubmits to corresponding table which updates the
-            use statistics of MAC cache.
+            use statistics of MAC cache.  When the optional MAC binding scope
+            key <var>S</var> is specified, it updates use statistics for the
+            shared binding instead of a private per-port binding.
           </p>
         </dd>
 
diff --git a/tests/ovn-macros.at b/tests/ovn-macros.at
index e0f70bcde..01e64da2a 100644
--- a/tests/ovn-macros.at
+++ b/tests/ovn-macros.at
@@ -1696,6 +1696,10 @@ m4_define([OFTABLE_CHK_IN_PORT_SEC_ND], [98])
 m4_define([OFTABLE_CHK_OUT_PORT_SEC], [99])
 m4_define([OFTABLE_CHK_LB_AFFINITY], [100])
 m4_define([OFTABLE_MAC_CACHE_USE], [101])
+m4_define([OFTABLE_SHARED_MAC_BINDING], [113])
+m4_define([OFTABLE_SHARED_MAC_LOOKUP], [114])
+m4_define([OFTABLE_MAC_BINDING_OVERRIDE], [115])
+m4_define([OFTABLE_MAC_LOOKUP_OVERRIDE], [116])
 m4_define([OFTABLE_CT_ZONE_LOOKUP], [102])
 m4_define([OFTABLE_CT_ORIG_NW_DST_LOAD], [103])
 m4_define([OFTABLE_CT_ORIG_IP6_DST_LOAD], [104])
diff --git a/tests/ovn.at b/tests/ovn.at
index 49674266f..c080eeb20 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -1420,6 +1420,9 @@ get_arp(outport, ip4.dst);
     has prereqs eth.type == 0x800
 get_arp(inport, reg0);
     encodes as 
push:NXM_NX_REG15[[]],push:NXM_NX_REG0[[]],push:NXM_NX_XXREG0[[96..127]],push:NXM_NX_REG14[[]],pop:NXM_NX_REG15[[]],pop:NXM_NX_REG0[[]],set_field:00:00:00:00:00:00->eth_dst,resubmit(,OFTABLE_MAC_BINDING),pop:NXM_NX_REG0[[]],pop:NXM_NX_REG15[[]]
+get_arp(outport, ip4.dst, 42);
+    encodes as 
push:NXM_NX_REG0[[]],push:NXM_OF_IP_DST[[]],pop:NXM_NX_REG0[[]],set_field:00:00:00:00:00:00->eth_dst,resubmit(,OFTABLE_MAC_BINDING),push:OXM_OF_METADATA[[]],push:NXM_NX_REG15[[]],set_field:0x2a->metadata,set_field:0->reg15,resubmit(,OFTABLE_SHARED_MAC_BINDING),pop:NXM_NX_REG15[[]],pop:OXM_OF_METADATA[[]],resubmit(,OFTABLE_MAC_BINDING_OVERRIDE),pop:NXM_NX_REG0[[]]
+    has prereqs eth.type == 0x800
 
 get_arp;
     Syntax error at `;' expecting `('.
@@ -1437,6 +1440,10 @@ get_arp(inport, outport);
     Cannot use string field outport where numeric field is required.
 get_arp(reg0, ip4.dst);
     Cannot use numeric field reg0 where string field is required.
+get_arp(outport, ip4.dst, 0);
+    MAC binding scope must be in the range 1 to 16777215
+get_arp(outport, ip4.dst, 16777216);
+    MAC binding scope must be in the range 1 to 16777215
 
 # put_arp
 put_arp(inport, arp.spa, arp.sha);
@@ -1450,6 +1457,9 @@ reg0[[0]] = lookup_arp(inport, ip4.dst, eth.src);
 reg1[[1]] = lookup_arp(inport, arp.spa, arp.sha);
     encodes as 
push:NXM_NX_REG0[[]],push:NXM_OF_ETH_SRC[[]],push:NXM_NX_ARP_SHA[[]],push:NXM_OF_ARP_SPA[[]],pop:NXM_NX_REG0[[]],pop:NXM_OF_ETH_SRC[[]],set_field:0/0x40->reg10,resubmit(,OFTABLE_MAC_LOOKUP),move:NXM_NX_REG10[[6]]->NXM_NX_XXREG0[[65]],pop:NXM_OF_ETH_SRC[[]],pop:NXM_NX_REG0[[]]
     has prereqs eth.type == 0x806 && eth.type == 0x806
+reg0[[0]] = lookup_arp(inport, ip4.dst, eth.src, 42);
+    encodes as 
push:NXM_NX_REG0[[]],push:NXM_OF_IP_DST[[]],pop:NXM_NX_REG0[[]],set_field:0/0x40->reg10,resubmit(,OFTABLE_MAC_LOOKUP),push:OXM_OF_METADATA[[]],push:NXM_NX_REG14[[]],set_field:0x2a->metadata,set_field:0->reg14,resubmit(,OFTABLE_SHARED_MAC_LOOKUP),pop:NXM_NX_REG14[[]],pop:OXM_OF_METADATA[[]],resubmit(,OFTABLE_MAC_LOOKUP_OVERRIDE),move:NXM_NX_REG10[[6]]->NXM_NX_XXREG0[[96]],pop:NXM_NX_REG0[[]]
+    has prereqs eth.type == 0x800
 
 lookup_arp;
     Syntax error at `lookup_arp' expecting action.
@@ -1477,6 +1487,9 @@ reg0[[0]] = lookup_arp_ip(inport, ip4.dst);
 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(,OFTABLE_MAC_BINDING),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
+reg0[[0]] = lookup_arp_ip(inport, ip4.dst, 42);
+    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(,OFTABLE_MAC_BINDING),push:OXM_OF_METADATA[[]],push:NXM_NX_REG15[[]],set_field:0x2a->metadata,set_field:0->reg15,resubmit(,OFTABLE_SHARED_MAC_BINDING),pop:NXM_NX_REG15[[]],pop:OXM_OF_METADATA[[]],resubmit(,OFTABLE_MAC_BINDING_OVERRIDE),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
 
 lookup_arp_ip;
     Syntax error at `lookup_arp_ip' expecting action.
@@ -1491,7 +1504,7 @@ reg0[[0]] = lookup_arp_ip(inport ip4.dst);
 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 `)'.
+    Syntax error at `eth.src' expecting small integer.
 reg0[[0]] = lookup_arp_ip(inport, eth.dst);
     Cannot use 48-bit field eth.dst[[0..47]] where 32-bit field is required.
 
@@ -1600,6 +1613,9 @@ get_nd(outport, ip6.dst);
     has prereqs eth.type == 0x86dd
 get_nd(inport, xxreg0);
     encodes as 
push:NXM_NX_REG15[[]],push:NXM_NX_XXREG1[[]],push:NXM_NX_XXREG0[[]],push:NXM_NX_REG14[[]],pop:NXM_NX_REG15[[]],pop:NXM_NX_XXREG1[[]],set_field:00:00:00:00:00:00->eth_dst,resubmit(,OFTABLE_MAC_BINDING),pop:NXM_NX_XXREG1[[]],pop:NXM_NX_REG15[[]]
+get_nd(outport, ip6.dst, 42);
+    encodes as 
push:NXM_NX_XXREG1[[]],push:NXM_NX_IPV6_DST[[]],pop:NXM_NX_XXREG1[[]],set_field:00:00:00:00:00:00->eth_dst,resubmit(,OFTABLE_MAC_BINDING),push:OXM_OF_METADATA[[]],push:NXM_NX_REG15[[]],set_field:0x2a->metadata,set_field:0->reg15,resubmit(,OFTABLE_SHARED_MAC_BINDING),pop:NXM_NX_REG15[[]],pop:OXM_OF_METADATA[[]],resubmit(,OFTABLE_MAC_BINDING_OVERRIDE),pop:NXM_NX_XXREG1[[]]
+    has prereqs eth.type == 0x86dd
 get_nd;
     Syntax error at `;' expecting `('.
 get_nd();
@@ -1662,6 +1678,9 @@ reg2[[0]] = lookup_nd(inport, ip6.dst, eth.src);
 reg3[[0]] = lookup_nd(inport, nd.target, nd.tll);
     encodes as 
push:NXM_NX_XXREG0[[]],push:NXM_OF_ETH_SRC[[]],push:NXM_NX_ND_TLL[[]],push:NXM_NX_ND_TARGET[[]],pop:NXM_NX_XXREG0[[]],pop:NXM_OF_ETH_SRC[[]],set_field:0/0x40->reg10,resubmit(,OFTABLE_MAC_LOOKUP),move:NXM_NX_REG10[[6]]->NXM_NX_XXREG0[[0]],pop:NXM_OF_ETH_SRC[[]],pop:NXM_NX_XXREG0[[]]
     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) && 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)
+reg0[[0]] = lookup_nd(inport, ip6.dst, eth.src, 42);
+    encodes as 
push:NXM_NX_XXREG0[[]],push:NXM_NX_IPV6_DST[[]],pop:NXM_NX_XXREG0[[]],set_field:0/0x40->reg10,resubmit(,OFTABLE_MAC_LOOKUP),push:OXM_OF_METADATA[[]],push:NXM_NX_REG14[[]],set_field:0x2a->metadata,set_field:0->reg14,resubmit(,OFTABLE_SHARED_MAC_LOOKUP),pop:NXM_NX_REG14[[]],pop:OXM_OF_METADATA[[]],resubmit(,OFTABLE_MAC_LOOKUP_OVERRIDE),move:NXM_NX_REG10[[6]]->NXM_NX_XXREG0[[96]],pop:NXM_NX_XXREG0[[]]
+    has prereqs eth.type == 0x86dd
 
 lookup_nd;
     Syntax error at `lookup_nd' expecting action.
@@ -1691,6 +1710,9 @@ reg2[[0]] = lookup_nd_ip(inport, ip6.dst);
 reg3[[0]] = lookup_nd_ip(inport, nd.target);
     encodes as 
push:NXM_NX_REG15[[]],push:NXM_NX_XXREG1[[]],push:NXM_NX_ND_TARGET[[]],push:NXM_NX_REG14[[]],pop:NXM_NX_REG15[[]],pop:NXM_NX_XXREG1[[]],push:NXM_OF_ETH_DST[[]],set_field:0/0x40->reg10,resubmit(,OFTABLE_MAC_BINDING),move:NXM_NX_REG10[[6]]->NXM_NX_XXREG0[[0]],pop:NXM_OF_ETH_DST[[]],pop:NXM_NX_XXREG1[[]],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)
+reg0[[0]] = lookup_nd_ip(inport, ip6.dst, 42);
+    encodes as 
push:NXM_NX_REG15[[]],push:NXM_NX_XXREG1[[]],push:NXM_NX_IPV6_DST[[]],push:NXM_NX_REG14[[]],pop:NXM_NX_REG15[[]],pop:NXM_NX_XXREG1[[]],push:NXM_OF_ETH_DST[[]],set_field:0/0x40->reg10,resubmit(,OFTABLE_MAC_BINDING),push:OXM_OF_METADATA[[]],push:NXM_NX_REG15[[]],set_field:0x2a->metadata,set_field:0->reg15,resubmit(,OFTABLE_SHARED_MAC_BINDING),pop:NXM_NX_REG15[[]],pop:OXM_OF_METADATA[[]],resubmit(,OFTABLE_MAC_BINDING_OVERRIDE),move:NXM_NX_REG10[[6]]->NXM_NX_XXREG0[[96]],pop:NXM_OF_ETH_DST[[]],pop:NXM_NX_XXREG1[[]],pop:NXM_NX_REG15[[]]
+    has prereqs eth.type == 0x86dd
 
 lookup_nd_ip;
     Syntax error at `lookup_nd_ip' expecting action.
@@ -2283,6 +2305,10 @@ sample(probability=10, obs_point=ct_label);
 # mac_cache_use
 mac_cache_use;
     encodes as resubmit(,OFTABLE_MAC_CACHE_USE)
+mac_cache_use(42);
+    encodes as 
push:OXM_OF_METADATA[[]],push:NXM_NX_REG14[[]],set_field:0x2a->metadata,set_field:0->reg14,resubmit(,OFTABLE_MAC_CACHE_USE),pop:NXM_NX_REG14[[]],pop:OXM_OF_METADATA[[]]
+mac_cache_use();
+    Syntax error at `)' expecting small integer.
 
 # ct_nw_dst()
 reg1 = ct_nw_dst();
diff --git a/tests/test-ovn.c b/tests/test-ovn.c
index 51471750b..2203e34ce 100644
--- a/tests/test-ovn.c
+++ b/tests/test-ovn.c
@@ -1374,6 +1374,10 @@ test_parse_actions(struct ovs_cmdl_context *ctx 
OVS_UNUSED)
                 .output_ptable = OFTABLE_SAVE_INPORT,
                 .mac_bind_ptable = OFTABLE_MAC_BINDING,
                 .mac_lookup_ptable = OFTABLE_MAC_LOOKUP,
+                .shared_mac_bind_ptable = OFTABLE_SHARED_MAC_BINDING,
+                .shared_mac_lookup_ptable = OFTABLE_SHARED_MAC_LOOKUP,
+                .mac_bind_override_ptable = OFTABLE_MAC_BINDING_OVERRIDE,
+                .mac_lookup_override_ptable = OFTABLE_MAC_LOOKUP_OVERRIDE,
                 .lb_hairpin_ptable = OFTABLE_CHK_LB_HAIRPIN,
                 .lb_hairpin_reply_ptable = OFTABLE_CHK_LB_HAIRPIN_REPLY,
                 .ct_snat_vip_ptable = OFTABLE_CT_SNAT_HAIRPIN,
-- 
2.56.0

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to