ebb439
From 6fc44a540fdb1bc9ac0d0cc1ef5786efadbee13c Mon Sep 17 00:00:00 2001
ebb439
From: Numan Siddique <numans@ovn.org>
ebb439
Date: Tue, 29 Sep 2020 15:25:43 +0530
ebb439
Subject: [PATCH 3/5] actions: Add a new OVN action - reject {}.
ebb439
ebb439
This action is similar to tcp_reset and icmp4/icmp6 action. If the matching
ebb439
packet is an IPv4 of IPv6 TCP packet, it sends out TCP RST packet else it
ebb439
sends out ICMPv4 or ICMPv6 Destination unreachable packet.
ebb439
ebb439
While transforming the original packet to the reject packet, this action
ebb439
implicitly swaps the eth source with eth destination and IP source with
ebb439
IP destination.
ebb439
ebb439
A future patch will make use of this action for reject ACL.
ebb439
ebb439
Acked-by: Mark Michelson <mmichels@redhat.com>
ebb439
Acked-by: Dumitru Ceara <dceara@redhat.com>
ebb439
Signed-off-by: Numan Siddique <numans@ovn.org>
ebb439
ebb439
(cherry-picked from upstream master commit 64f8c9e9ff1ce26d06831995514cf66319f16b34)
ebb439
ebb439
Change-Id: Iacabf30344f21daf51d53989b4774fbdbafe00be
ebb439
---
ebb439
 controller/pinctrl.c  | 64 +++++++++++++++++++++++--------
ebb439
 include/ovn/actions.h |  9 ++++-
ebb439
 lib/actions.c         | 22 +++++++++++
ebb439
 ovn-sb.xml            | 16 ++++++++
ebb439
 tests/ovn.at          |  8 ++++
ebb439
 utilities/ovn-trace.c | 88 ++++++++++++++++++++++++++++++++-----------
ebb439
 6 files changed, 168 insertions(+), 39 deletions(-)
ebb439
ebb439
diff --git a/controller/pinctrl.c b/controller/pinctrl.c
ebb439
index 7099687eb..d85ba504d 100644
ebb439
--- a/controller/pinctrl.c
ebb439
+++ b/controller/pinctrl.c
ebb439
@@ -1542,7 +1542,7 @@ static void
ebb439
 pinctrl_handle_icmp(struct rconn *swconn, const struct flow *ip_flow,
ebb439
                     struct dp_packet *pkt_in,
ebb439
                     const struct match *md, struct ofpbuf *userdata,
ebb439
-                    bool set_icmp_code)
ebb439
+                    bool set_icmp_code, bool loopback)
ebb439
 {
ebb439
     /* This action only works for IP packets, and the switch should only send
ebb439
      * us IP packets this way, but check here just to be sure. */
ebb439
@@ -1563,8 +1563,8 @@ pinctrl_handle_icmp(struct rconn *swconn, const struct flow *ip_flow,
ebb439
     packet.packet_type = htonl(PT_ETH);
ebb439
 
ebb439
     struct eth_header *eh = dp_packet_put_zeros(&packet, sizeof *eh);
ebb439
-    eh->eth_dst = ip_flow->dl_dst;
ebb439
-    eh->eth_src = ip_flow->dl_src;
ebb439
+    eh->eth_dst = loopback ? ip_flow->dl_src : ip_flow->dl_dst;
ebb439
+    eh->eth_src = loopback ? ip_flow->dl_dst : ip_flow->dl_src;
ebb439
 
ebb439
     if (get_dl_type(ip_flow) == htons(ETH_TYPE_IP)) {
ebb439
         struct ip_header *in_ip = dp_packet_l3(pkt_in);
ebb439
@@ -1586,8 +1586,9 @@ pinctrl_handle_icmp(struct rconn *swconn, const struct flow *ip_flow,
ebb439
                                sizeof(struct icmp_header));
ebb439
         nh->ip_proto = IPPROTO_ICMP;
ebb439
         nh->ip_frag_off = htons(IP_DF);
ebb439
-        packet_set_ipv4(&packet, ip_flow->nw_src, ip_flow->nw_dst,
ebb439
-                        ip_flow->nw_tos, 255);
ebb439
+        ovs_be32 nw_src = loopback ? ip_flow->nw_dst : ip_flow->nw_src;
ebb439
+        ovs_be32 nw_dst = loopback ? ip_flow->nw_src : ip_flow->nw_dst;
ebb439
+        packet_set_ipv4(&packet, nw_src, nw_dst, ip_flow->nw_tos, 255);
ebb439
 
ebb439
         uint8_t icmp_code =  1;
ebb439
         if (set_icmp_code && in_ip->ip_proto == IPPROTO_UDP) {
ebb439
@@ -1634,8 +1635,12 @@ pinctrl_handle_icmp(struct rconn *swconn, const struct flow *ip_flow,
ebb439
         nh->ip6_vfc = 0x60;
ebb439
         nh->ip6_nxt = IPPROTO_ICMPV6;
ebb439
         nh->ip6_plen = htons(ICMP6_DATA_HEADER_LEN);
ebb439
-        packet_set_ipv6(&packet, &ip_flow->ipv6_src, &ip_flow->ipv6_dst,
ebb439
-                        ip_flow->nw_tos, ip_flow->ipv6_label, 255);
ebb439
+        const struct in6_addr *ip6_src =
ebb439
+            loopback ? &ip_flow->ipv6_dst : &ip_flow->ipv6_src;
ebb439
+        const struct in6_addr *ip6_dst =
ebb439
+            loopback ? &ip_flow->ipv6_src : &ip_flow->ipv6_dst;
ebb439
+        packet_set_ipv6(&packet, ip6_src, ip6_dst, ip_flow->nw_tos,
ebb439
+                        ip_flow->ipv6_label, 255);
ebb439
 
ebb439
         ih = dp_packet_put_zeros(&packet, sizeof *ih);
ebb439
         dp_packet_set_l4(&packet, ih);
ebb439
@@ -1692,7 +1697,8 @@ pinctrl_handle_icmp(struct rconn *swconn, const struct flow *ip_flow,
ebb439
 static void
ebb439
 pinctrl_handle_tcp_reset(struct rconn *swconn, const struct flow *ip_flow,
ebb439
                          struct dp_packet *pkt_in,
ebb439
-                         const struct match *md, struct ofpbuf *userdata)
ebb439
+                         const struct match *md, struct ofpbuf *userdata,
ebb439
+                         bool loopback)
ebb439
 {
ebb439
     /* This action only works for TCP segments, and the switch should only send
ebb439
      * us TCP segments this way, but check here just to be sure. */
ebb439
@@ -1707,14 +1713,23 @@ pinctrl_handle_tcp_reset(struct rconn *swconn, const struct flow *ip_flow,
ebb439
 
ebb439
     dp_packet_use_stub(&packet, packet_stub, sizeof packet_stub);
ebb439
     packet.packet_type = htonl(PT_ETH);
ebb439
+
ebb439
+    struct eth_addr eth_src = loopback ? ip_flow->dl_dst : ip_flow->dl_src;
ebb439
+    struct eth_addr eth_dst = loopback ? ip_flow->dl_src : ip_flow->dl_dst;
ebb439
+
ebb439
     if (get_dl_type(ip_flow) == htons(ETH_TYPE_IPV6)) {
ebb439
-        pinctrl_compose_ipv6(&packet, ip_flow->dl_src, ip_flow->dl_dst,
ebb439
-                             (struct in6_addr *)&ip_flow->ipv6_src,
ebb439
-                             (struct in6_addr *)&ip_flow->ipv6_dst,
ebb439
+        const struct in6_addr *ip6_src =
ebb439
+            loopback ? &ip_flow->ipv6_dst : &ip_flow->ipv6_src;
ebb439
+        const struct in6_addr *ip6_dst =
ebb439
+            loopback ? &ip_flow->ipv6_src : &ip_flow->ipv6_dst;
ebb439
+        pinctrl_compose_ipv6(&packet, eth_src, eth_dst,
ebb439
+                             (struct in6_addr *) ip6_src,
ebb439
+                             (struct in6_addr *) ip6_dst,
ebb439
                              IPPROTO_TCP, 63, TCP_HEADER_LEN);
ebb439
     } else {
ebb439
-        pinctrl_compose_ipv4(&packet, ip_flow->dl_src, ip_flow->dl_dst,
ebb439
-                             ip_flow->nw_src, ip_flow->nw_dst,
ebb439
+        ovs_be32 nw_src = loopback ? ip_flow->nw_dst : ip_flow->nw_src;
ebb439
+        ovs_be32 nw_dst = loopback ? ip_flow->nw_src : ip_flow->nw_dst;
ebb439
+        pinctrl_compose_ipv4(&packet, eth_src, eth_dst, nw_src, nw_dst,
ebb439
                              IPPROTO_TCP, 63, TCP_HEADER_LEN);
ebb439
     }
ebb439
 
ebb439
@@ -1745,6 +1760,18 @@ pinctrl_handle_tcp_reset(struct rconn *swconn, const struct flow *ip_flow,
ebb439
     dp_packet_uninit(&packet);
ebb439
 }
ebb439
 
ebb439
+static void
ebb439
+pinctrl_handle_reject(struct rconn *swconn, const struct flow *ip_flow,
ebb439
+                      struct dp_packet *pkt_in,
ebb439
+                      const struct match *md, struct ofpbuf *userdata)
ebb439
+{
ebb439
+    if (ip_flow->nw_proto == IPPROTO_TCP) {
ebb439
+        pinctrl_handle_tcp_reset(swconn, ip_flow, pkt_in, md, userdata, true);
ebb439
+    } else {
ebb439
+        pinctrl_handle_icmp(swconn, ip_flow, pkt_in, md, userdata, true, true);
ebb439
+    }
ebb439
+}
ebb439
+
ebb439
 static bool
ebb439
 is_dhcp_flags_broadcast(ovs_be16 flags)
ebb439
 {
ebb439
@@ -2848,18 +2875,23 @@ process_packet_in(struct rconn *swconn, const struct ofp_header *msg)
ebb439
 
ebb439
     case ACTION_OPCODE_ICMP:
ebb439
         pinctrl_handle_icmp(swconn, &headers, &packet, &pin.flow_metadata,
ebb439
-                            &userdata, true);
ebb439
+                            &userdata, true, false);
ebb439
         break;
ebb439
 
ebb439
     case ACTION_OPCODE_ICMP4_ERROR:
ebb439
     case ACTION_OPCODE_ICMP6_ERROR:
ebb439
         pinctrl_handle_icmp(swconn, &headers, &packet, &pin.flow_metadata,
ebb439
-                            &userdata, false);
ebb439
+                            &userdata, false, false);
ebb439
         break;
ebb439
 
ebb439
     case ACTION_OPCODE_TCP_RESET:
ebb439
         pinctrl_handle_tcp_reset(swconn, &headers, &packet, &pin.flow_metadata,
ebb439
-                                 &userdata);
ebb439
+                                 &userdata, false);
ebb439
+        break;
ebb439
+
ebb439
+    case ACTION_OPCODE_REJECT:
ebb439
+        pinctrl_handle_reject(swconn, &headers, &packet, &pin.flow_metadata,
ebb439
+                              &userdata);
ebb439
         break;
ebb439
 
ebb439
     case ACTION_OPCODE_PUT_ICMP4_FRAG_MTU:
ebb439
diff --git a/include/ovn/actions.h b/include/ovn/actions.h
ebb439
index 636cb4bc1..b4e5acabb 100644
ebb439
--- a/include/ovn/actions.h
ebb439
+++ b/include/ovn/actions.h
ebb439
@@ -95,7 +95,8 @@ struct ovn_extend_table;
ebb439
     OVNACT(HANDLE_SVC_CHECK,  ovnact_handle_svc_check) \
ebb439
     OVNACT(FWD_GROUP,         ovnact_fwd_group)       \
ebb439
     OVNACT(DHCP6_REPLY,       ovnact_null)            \
ebb439
-    OVNACT(ICMP6_ERROR,       ovnact_nest)
ebb439
+    OVNACT(ICMP6_ERROR,       ovnact_nest)            \
ebb439
+    OVNACT(REJECT,            ovnact_nest)            \
ebb439
 
ebb439
 /* enum ovnact_type, with a member OVNACT_<ENUM> for each action. */
ebb439
 enum OVS_PACKED_ENUM ovnact_type {
ebb439
@@ -605,6 +606,12 @@ enum action_opcode {
ebb439
     /* MTU value (to put in the icmp6 header field - frag_mtu) follow the
ebb439
      * action header. */
ebb439
     ACTION_OPCODE_PUT_ICMP6_FRAG_MTU,
ebb439
+
ebb439
+    /* "reject { ...actions... }".
ebb439
+     *
ebb439
+     * The actions, in OpenFlow 1.3 format, follow the action_header.
ebb439
+     */
ebb439
+    ACTION_OPCODE_REJECT,
ebb439
 };
ebb439
 
ebb439
 /* Header. */
ebb439
diff --git a/lib/actions.c b/lib/actions.c
ebb439
index 5fe0a3897..1e1bdeff2 100644
ebb439
--- a/lib/actions.c
ebb439
+++ b/lib/actions.c
ebb439
@@ -1386,6 +1386,12 @@ parse_CLONE(struct action_context *ctx)
ebb439
     parse_nested_action(ctx, OVNACT_CLONE, NULL, WR_DEFAULT);
ebb439
 }
ebb439
 
ebb439
+static void
ebb439
+parse_REJECT(struct action_context *ctx)
ebb439
+{
ebb439
+    parse_nested_action(ctx, OVNACT_REJECT, NULL, ctx->scope);
ebb439
+}
ebb439
+
ebb439
 static void
ebb439
 format_nested_action(const struct ovnact_nest *on, const char *name,
ebb439
                      struct ds *s)
ebb439
@@ -1479,6 +1485,12 @@ format_TRIGGER_EVENT(const struct ovnact_controller_event *event,
ebb439
     ds_put_cstr(s, ");");
ebb439
 }
ebb439
 
ebb439
+static void
ebb439
+format_REJECT(const struct ovnact_nest *nest, struct ds *s)
ebb439
+{
ebb439
+    format_nested_action(nest, "reject", s);
ebb439
+}
ebb439
+
ebb439
 static void
ebb439
 encode_nested_actions(const struct ovnact_nest *on,
ebb439
                       const struct ovnact_encode_params *ep,
ebb439
@@ -1560,6 +1572,14 @@ encode_TCP_RESET(const struct ovnact_nest *on,
ebb439
     encode_nested_actions(on, ep, ACTION_OPCODE_TCP_RESET, ofpacts);
ebb439
 }
ebb439
 
ebb439
+static void
ebb439
+encode_REJECT(const struct ovnact_nest *on,
ebb439
+              const struct ovnact_encode_params *ep,
ebb439
+              struct ofpbuf *ofpacts)
ebb439
+{
ebb439
+    encode_nested_actions(on, ep, ACTION_OPCODE_REJECT, ofpacts);
ebb439
+}
ebb439
+
ebb439
 static void
ebb439
 encode_ND_NA(const struct ovnact_nest *on,
ebb439
              const struct ovnact_encode_params *ep,
ebb439
@@ -3567,6 +3587,8 @@ parse_action(struct action_context *ctx)
ebb439
         parse_fwd_group_action(ctx);
ebb439
     } else if (lexer_match_id(ctx->lexer, "handle_dhcpv6_reply")) {
ebb439
         ovnact_put_DHCP6_REPLY(ctx->ovnacts);
ebb439
+    } else if (lexer_match_id(ctx->lexer, "reject")) {
ebb439
+        parse_REJECT(ctx);
ebb439
     } else {
ebb439
         lexer_syntax_error(ctx->lexer, "expecting action");
ebb439
     }
ebb439
diff --git a/ovn-sb.xml b/ovn-sb.xml
ebb439
index 59888a155..182ff0a8a 100644
ebb439
--- a/ovn-sb.xml
ebb439
+++ b/ovn-sb.xml
ebb439
@@ -2191,6 +2191,22 @@ tcp.flags = RST;
ebb439
           

Prerequisite: tcp

ebb439
         
ebb439
 
ebb439
+        
reject { action; ... };
ebb439
+        
ebb439
+          

ebb439
+            If the original packet is IPv4 or IPv6 TCP packet, it replaces it
ebb439
+            with IPv4 or IPv6 TCP RST packet and executes the inner actions.
ebb439
+            Otherwise it replaces it with an ICMPv4 or ICMPv6 packet and
ebb439
+            executes the inner actions.
ebb439
+          

ebb439
+
ebb439
+          

ebb439
+            The inner actions should not attempt to swap eth source with eth
ebb439
+            destination and IP source with IP destination as this action
ebb439
+            implicitly does that.
ebb439
+          

ebb439
+        
ebb439
+
ebb439
         
trigger_event;
ebb439
         
ebb439
           

ebb439
diff --git a/tests/ovn.at b/tests/ovn.at
ebb439
index 53f5d4d96..337ab4e7d 100644
ebb439
--- a/tests/ovn.at
ebb439
+++ b/tests/ovn.at
ebb439
@@ -1593,6 +1593,14 @@ tcp_reset { };
ebb439
     encodes as controller(userdata=00.00.00.0b.00.00.00.00)
ebb439
     has prereqs tcp
ebb439
 
ebb439
+# reject
ebb439
+reject { eth.dst = ff:ff:ff:ff:ff:ff; output; }; output;
ebb439
+    encodes as controller(userdata=00.00.00.16.00.00.00.00.00.19.00.10.80.00.06.06.ff.ff.ff.ff.ff.ff.00.00.ff.ff.00.10.00.00.23.20.00.0e.ff.f8.40.00.00.00),resubmit(,64)
ebb439
+
ebb439
+reject { };
ebb439
+    formats as reject { drop; };
ebb439
+    encodes as controller(userdata=00.00.00.16.00.00.00.00)
ebb439
+
ebb439
 # trigger_event
ebb439
 trigger_event(event = "empty_lb_backends", vip = "10.0.0.1:80", protocol = "tcp", load_balancer = "12345678-abcd-9876-fedc-11119f8e7d6c");
ebb439
     encodes as controller(userdata=00.00.00.0f.00.00.00.00.00.00.00.00.00.01.00.0b.31.30.2e.30.2e.30.2e.31.3a.38.30.00.02.00.03.74.63.70.00.03.00.24.31.32.33.34.35.36.37.38.2d.61.62.63.64.2d.39.38.37.36.2d.66.65.64.63.2d.31.31.31.31.39.66.38.65.37.64.36.63)
ebb439
diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c
ebb439
index 0920ae159..ad33f8e36 100644
ebb439
--- a/utilities/ovn-trace.c
ebb439
+++ b/utilities/ovn-trace.c
ebb439
@@ -1638,16 +1638,23 @@ execute_nd_ns(const struct ovnact_nest *on, const struct ovntrace_datapath *dp,
ebb439
 static void
ebb439
 execute_icmp4(const struct ovnact_nest *on,
ebb439
               const struct ovntrace_datapath *dp,
ebb439
-              const struct flow *uflow, uint8_t table_id,
ebb439
+              const struct flow *uflow, uint8_t table_id, bool loopback,
ebb439
               enum ovnact_pipeline pipeline, struct ovs_list *super)
ebb439
 {
ebb439
     struct flow icmp4_flow = *uflow;
ebb439
 
ebb439
     /* Update fields for ICMP. */
ebb439
-    icmp4_flow.dl_dst = uflow->dl_dst;
ebb439
-    icmp4_flow.dl_src = uflow->dl_src;
ebb439
-    icmp4_flow.nw_dst = uflow->nw_dst;
ebb439
-    icmp4_flow.nw_src = uflow->nw_src;
ebb439
+    if (loopback) {
ebb439
+        icmp4_flow.dl_dst = uflow->dl_src;
ebb439
+        icmp4_flow.dl_src = uflow->dl_dst;
ebb439
+        icmp4_flow.nw_dst = uflow->nw_src;
ebb439
+        icmp4_flow.nw_src = uflow->nw_dst;
ebb439
+    } else {
ebb439
+        icmp4_flow.dl_dst = uflow->dl_dst;
ebb439
+        icmp4_flow.dl_src = uflow->dl_src;
ebb439
+        icmp4_flow.nw_dst = uflow->nw_dst;
ebb439
+        icmp4_flow.nw_src = uflow->nw_src;
ebb439
+    }
ebb439
     icmp4_flow.nw_proto = IPPROTO_ICMP;
ebb439
     icmp4_flow.nw_ttl = 255;
ebb439
     icmp4_flow.tp_src = htons(ICMP4_DST_UNREACH); /* icmp type */
ebb439
@@ -1663,16 +1670,23 @@ execute_icmp4(const struct ovnact_nest *on,
ebb439
 static void
ebb439
 execute_icmp6(const struct ovnact_nest *on,
ebb439
               const struct ovntrace_datapath *dp,
ebb439
-              const struct flow *uflow, uint8_t table_id,
ebb439
+              const struct flow *uflow, uint8_t table_id, bool loopback,
ebb439
               enum ovnact_pipeline pipeline, struct ovs_list *super)
ebb439
 {
ebb439
     struct flow icmp6_flow = *uflow;
ebb439
 
ebb439
     /* Update fields for ICMPv6. */
ebb439
-    icmp6_flow.dl_dst = uflow->dl_dst;
ebb439
-    icmp6_flow.dl_src = uflow->dl_src;
ebb439
-    icmp6_flow.ipv6_dst = uflow->ipv6_dst;
ebb439
-    icmp6_flow.ipv6_src = uflow->ipv6_src;
ebb439
+    if (loopback) {
ebb439
+        icmp6_flow.dl_dst = uflow->dl_src;
ebb439
+        icmp6_flow.dl_src = uflow->dl_dst;
ebb439
+        icmp6_flow.ipv6_dst = uflow->ipv6_src;
ebb439
+        icmp6_flow.ipv6_src = uflow->ipv6_dst;
ebb439
+    } else {
ebb439
+        icmp6_flow.dl_dst = uflow->dl_dst;
ebb439
+        icmp6_flow.dl_src = uflow->dl_src;
ebb439
+        icmp6_flow.ipv6_dst = uflow->ipv6_dst;
ebb439
+        icmp6_flow.ipv6_src = uflow->ipv6_src;
ebb439
+    }
ebb439
     icmp6_flow.nw_proto = IPPROTO_ICMPV6;
ebb439
     icmp6_flow.nw_ttl = 255;
ebb439
     icmp6_flow.tp_src = htons(ICMP6_DST_UNREACH); /* icmp type */
ebb439
@@ -1689,15 +1703,23 @@ static void
ebb439
 execute_tcp_reset(const struct ovnact_nest *on,
ebb439
                   const struct ovntrace_datapath *dp,
ebb439
                   const struct flow *uflow, uint8_t table_id,
ebb439
-                  enum ovnact_pipeline pipeline, struct ovs_list *super)
ebb439
+                  bool loopback, enum ovnact_pipeline pipeline,
ebb439
+                  struct ovs_list *super)
ebb439
 {
ebb439
     struct flow tcp_flow = *uflow;
ebb439
 
ebb439
     /* Update fields for TCP segment. */
ebb439
-    tcp_flow.dl_dst = uflow->dl_dst;
ebb439
-    tcp_flow.dl_src = uflow->dl_src;
ebb439
-    tcp_flow.nw_dst = uflow->nw_dst;
ebb439
-    tcp_flow.nw_src = uflow->nw_src;
ebb439
+    if (loopback) {
ebb439
+        tcp_flow.dl_dst = uflow->dl_src;
ebb439
+        tcp_flow.dl_src = uflow->dl_dst;
ebb439
+        tcp_flow.nw_dst = uflow->nw_src;
ebb439
+        tcp_flow.nw_src = uflow->nw_dst;
ebb439
+    } else {
ebb439
+        tcp_flow.dl_dst = uflow->dl_dst;
ebb439
+        tcp_flow.dl_src = uflow->dl_src;
ebb439
+        tcp_flow.nw_dst = uflow->nw_dst;
ebb439
+        tcp_flow.nw_src = uflow->nw_src;
ebb439
+    }
ebb439
     tcp_flow.nw_proto = IPPROTO_TCP;
ebb439
     tcp_flow.nw_ttl = 255;
ebb439
     tcp_flow.tp_src = uflow->tp_src;
ebb439
@@ -1711,6 +1733,23 @@ execute_tcp_reset(const struct ovnact_nest *on,
ebb439
                   table_id, pipeline, &node->subs);
ebb439
 }
ebb439
 
ebb439
+static void
ebb439
+execute_reject(const struct ovnact_nest *on,
ebb439
+               const struct ovntrace_datapath *dp,
ebb439
+               const struct flow *uflow, uint8_t table_id,
ebb439
+               enum ovnact_pipeline pipeline, struct ovs_list *super)
ebb439
+{
ebb439
+    if (uflow->nw_proto == IPPROTO_TCP) {
ebb439
+        execute_tcp_reset(on, dp, uflow, table_id, true, pipeline, super);
ebb439
+    } else {
ebb439
+        if (get_dl_type(uflow) == htons(ETH_TYPE_IP)) {
ebb439
+            execute_icmp4(on, dp, uflow, table_id, true, pipeline, super);
ebb439
+        } else {
ebb439
+            execute_icmp6(on, dp, uflow, table_id, true, pipeline, super);
ebb439
+        }
ebb439
+    }
ebb439
+}
ebb439
+
ebb439
 static void
ebb439
 execute_get_mac_bind(const struct ovnact_get_mac_bind *bind,
ebb439
                      const struct ovntrace_datapath *dp,
ebb439
@@ -2315,23 +2354,23 @@ trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len,
ebb439
             break;
ebb439
 
ebb439
         case OVNACT_ICMP4:
ebb439
-            execute_icmp4(ovnact_get_ICMP4(a), dp, uflow, table_id, pipeline,
ebb439
-                          super);
ebb439
+            execute_icmp4(ovnact_get_ICMP4(a), dp, uflow, table_id, false,
ebb439
+                          pipeline, super);
ebb439
             break;
ebb439
 
ebb439
         case OVNACT_ICMP4_ERROR:
ebb439
             execute_icmp4(ovnact_get_ICMP4_ERROR(a), dp, uflow, table_id,
ebb439
-                          pipeline, super);
ebb439
+                          false, pipeline, super);
ebb439
             break;
ebb439
 
ebb439
         case OVNACT_ICMP6:
ebb439
-            execute_icmp6(ovnact_get_ICMP6(a), dp, uflow, table_id, pipeline,
ebb439
-                          super);
ebb439
+            execute_icmp6(ovnact_get_ICMP6(a), dp, uflow, table_id, false,
ebb439
+                          pipeline, super);
ebb439
             break;
ebb439
 
ebb439
         case OVNACT_ICMP6_ERROR:
ebb439
             execute_icmp6(ovnact_get_ICMP6_ERROR(a), dp, uflow, table_id,
ebb439
-                          pipeline, super);
ebb439
+                          false, pipeline, super);
ebb439
             break;
ebb439
 
ebb439
         case OVNACT_IGMP:
ebb439
@@ -2340,13 +2379,18 @@ trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len,
ebb439
 
ebb439
         case OVNACT_TCP_RESET:
ebb439
             execute_tcp_reset(ovnact_get_TCP_RESET(a), dp, uflow, table_id,
ebb439
-                              pipeline, super);
ebb439
+                              false, pipeline, super);
ebb439
             break;
ebb439
 
ebb439
         case OVNACT_OVNFIELD_LOAD:
ebb439
             execute_ovnfield_load(ovnact_get_OVNFIELD_LOAD(a), super);
ebb439
             break;
ebb439
 
ebb439
+        case OVNACT_REJECT:
ebb439
+            execute_reject(ovnact_get_REJECT(a), dp, uflow, table_id,
ebb439
+                           pipeline, super);
ebb439
+            break;
ebb439
+
ebb439
         case OVNACT_TRIGGER_EVENT:
ebb439
             break;
ebb439
 
ebb439
-- 
ebb439
2.26.2
ebb439