diff mbox series

[ovs-dev,ovn] Fix ACL reject action for UDP packets.

Message ID 20200428110609.3680194-1-numans@ovn.org
State Superseded
Headers show
Series [ovs-dev,ovn] Fix ACL reject action for UDP packets. | expand

Commit Message

Numan Siddique April 28, 2020, 11:06 a.m. UTC
From: Numan Siddique <numans@ovn.org>

The icmp packet generated by ovn-controller for reject ACL action
for non TCP packets is not getting delivered to the sender of
the original packet. This is because the icmp packets are skipped
from out_pre_lb/out_pre_acl logical switch egress pipeline and this
results in these icmp packets getting dropped in the ACL stage because
of invalid ct flags. This patch fixes this issue by removing those logical
flows. The IP checksum generated by ovn-controller is invalid. This patch
fixes this issue as well.

Signed-off-by: Numan Siddique <numans@ovn.org>
---
 controller/pinctrl.c | 102 ++++++++++++++++++++++++++++---------------
 northd/ovn-northd.c  |  22 +++++-----
 tests/ovn.at         |  46 +++++++++----------
 tests/system-ovn.at  |  95 ++++++++++++++++++++++++++++++++--------
 4 files changed, 177 insertions(+), 88 deletions(-)

Comments

Lorenzo Bianconi May 5, 2020, 1:03 p.m. UTC | #1
>
> From: Numan Siddique <numans@ovn.org>
>
> The icmp packet generated by ovn-controller for reject ACL action
> for non TCP packets is not getting delivered to the sender of
> the original packet. This is because the icmp packets are skipped
> from out_pre_lb/out_pre_acl logical switch egress pipeline and this
> results in these icmp packets getting dropped in the ACL stage because
> of invalid ct flags. This patch fixes this issue by removing those logical
> flows. The IP checksum generated by ovn-controller is invalid. This patch
> fixes this issue as well.
>
> Signed-off-by: Numan Siddique <numans@ovn.org>

Tested-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>

> ---
>  controller/pinctrl.c | 102 ++++++++++++++++++++++++++++---------------
>  northd/ovn-northd.c  |  22 +++++-----
>  tests/ovn.at         |  46 +++++++++----------
>  tests/system-ovn.at  |  95 ++++++++++++++++++++++++++++++++--------
>  4 files changed, 177 insertions(+), 88 deletions(-)
>
> diff --git a/controller/pinctrl.c b/controller/pinctrl.c
> index 3230bb386..63796d88c 100644
> --- a/controller/pinctrl.c
> +++ b/controller/pinctrl.c
> @@ -1453,7 +1453,7 @@ static void
>  pinctrl_handle_icmp(struct rconn *swconn, const struct flow *ip_flow,
>                      struct dp_packet *pkt_in,
>                      const struct match *md, struct ofpbuf *userdata,
> -                    bool include_orig_ip_datagram)
> +                    bool set_icmp_code)
>  {
>      /* This action only works for IP packets, and the switch should only send
>       * us IP packets this way, but check here just to be sure. */
> @@ -1500,46 +1500,51 @@ pinctrl_handle_icmp(struct rconn *swconn, const struct flow *ip_flow,
>          packet_set_ipv4(&packet, ip_flow->nw_src, ip_flow->nw_dst,
>                          ip_flow->nw_tos, 255);
>
> +        uint8_t icmp_code =  1;
> +        if (set_icmp_code && in_ip->ip_proto == IPPROTO_UDP) {
> +            icmp_code = 3;
> +        }
> +
>          struct icmp_header *ih = dp_packet_put_zeros(&packet, sizeof *ih);
>          dp_packet_set_l4(&packet, ih);
> -        packet_set_icmp(&packet, ICMP4_DST_UNREACH, 1);
> -
> -        if (include_orig_ip_datagram) {
> -            /* RFC 1122: 3.2.2 MUST send at least the IP header and 8 bytes
> -             * of header. MAY send more.
> -             * RFC says return as much as we can without exceeding 576
> -             * bytes.
> -             * So, lets return as much as we can. */
> -
> -            /* Calculate available room to include the original IP + data. */
> -            nh = dp_packet_l3(&packet);
> -            uint16_t room = 576 - (sizeof *eh + ntohs(nh->ip_tot_len));
> -            if (in_ip_len > room) {
> -                in_ip_len = room;
> -            }
> -            dp_packet_put(&packet, in_ip, in_ip_len);
> -
> -            /* dp_packet_put may reallocate the buffer. Get the l3 and l4
> -             * header pointers again. */
> -            nh = dp_packet_l3(&packet);
> -            ih = dp_packet_l4(&packet);
> -            uint16_t ip_total_len = ntohs(nh->ip_tot_len) + in_ip_len;
> -            nh->ip_tot_len = htons(ip_total_len);
> -            ih->icmp_csum = 0;
> -            ih->icmp_csum = csum(ih, sizeof *ih + in_ip_len);
> -            nh->ip_csum = 0;
> -            nh->ip_csum = csum(nh, sizeof *nh);
> -        }
> +        packet_set_icmp(&packet, ICMP4_DST_UNREACH, icmp_code);
> +
> +        /* RFC 1122: 3.2.2     MUST send at least the IP header and 8 bytes
> +         * of header. MAY send more.
> +         * RFC says return as much as we can without exceeding 576
> +         * bytes.
> +         * So, lets return as much as we can. */
> +
> +        /* Calculate available room to include the original IP + data. */
> +        nh = dp_packet_l3(&packet);
> +        uint16_t room = 576 - (sizeof *eh + ntohs(nh->ip_tot_len));
> +        if (in_ip_len > room) {
> +            in_ip_len = room;
> +        }
> +        dp_packet_put(&packet, in_ip, in_ip_len);
> +
> +        /* dp_packet_put may reallocate the buffer. Get the l3 and l4
> +            * header pointers again. */
> +        nh = dp_packet_l3(&packet);
> +        ih = dp_packet_l4(&packet);
> +        uint16_t ip_total_len = ntohs(nh->ip_tot_len) + in_ip_len;
> +        nh->ip_tot_len = htons(ip_total_len);
> +        ih->icmp_csum = 0;
> +        ih->icmp_csum = csum(ih, sizeof *ih + in_ip_len);
> +        nh->ip_csum = 0;
> +        nh->ip_csum = csum(nh, sizeof *nh);
> +
>      } else {
>          struct ip6_hdr *nh = dp_packet_put_zeros(&packet, sizeof *nh);
>          struct icmp6_data_header *ih;
>          uint32_t icmpv6_csum;
> +        struct ip6_hdr *in_ip = dp_packet_l3(pkt_in);
>
>          eh->eth_type = htons(ETH_TYPE_IPV6);
>          dp_packet_set_l3(&packet, nh);
>          nh->ip6_vfc = 0x60;
>          nh->ip6_nxt = IPPROTO_ICMPV6;
> -        nh->ip6_plen = htons(sizeof(*nh) + ICMP6_DATA_HEADER_LEN);
> +        nh->ip6_plen = htons(ICMP6_DATA_HEADER_LEN);
>          packet_set_ipv6(&packet, &ip_flow->ipv6_src, &ip_flow->ipv6_dst,
>                          ip_flow->nw_tos, ip_flow->ipv6_label, 255);
>
> @@ -1547,15 +1552,42 @@ pinctrl_handle_icmp(struct rconn *swconn, const struct flow *ip_flow,
>          dp_packet_set_l4(&packet, ih);
>          ih->icmp6_base.icmp6_type = ICMP6_DST_UNREACH;
>          ih->icmp6_base.icmp6_code = 1;
> +
> +        if (set_icmp_code && in_ip->ip6_nxt == IPPROTO_UDP) {
> +            ih->icmp6_base.icmp6_code = ICMP6_DST_UNREACH_NOPORT;
> +        }
>          ih->icmp6_base.icmp6_cksum = 0;
>
> -        uint8_t *data = dp_packet_put_zeros(&packet, sizeof *nh);
> -        memcpy(data, dp_packet_l3(pkt_in), sizeof(*nh));
> +        nh = dp_packet_l3(&packet);
> +
> +        /* RFC 4443: 3.1.
> +         *
> +         * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
> +         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> +         * |     Type      |     Code      |          Checksum             |
> +         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> +         * |                             Unused                            |
> +         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> +         * |                    As much of invoking packet                 |
> +         * +                as possible without the ICMPv6 packet          +
> +         * |                exceeding the minimum IPv6 MTU [IPv6]          |
> +         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> +         */
> +
> +        uint16_t room = 1280 - (sizeof *eh + sizeof *nh +
> +                                ICMP6_DATA_HEADER_LEN);
> +        uint16_t in_ip_len = (uint16_t) sizeof *in_ip + ntohs(in_ip->ip6_plen);
> +        if (in_ip_len > room) {
> +            in_ip_len = room;
> +        }
> +
> +        dp_packet_put(&packet, in_ip, in_ip_len);
> +        nh->ip6_plen = htons(ICMP6_DATA_HEADER_LEN + in_ip_len);
>
>          icmpv6_csum = packet_csum_pseudoheader6(dp_packet_l3(&packet));
>          ih->icmp6_base.icmp6_cksum = csum_finish(
>              csum_continue(icmpv6_csum, ih,
> -                          sizeof(*nh) + ICMP6_DATA_HEADER_LEN));
> +                          in_ip_len + ICMP6_DATA_HEADER_LEN));
>      }
>
>      if (ip_flow->vlans[0].tci & htons(VLAN_CFI)) {
> @@ -2646,12 +2678,12 @@ process_packet_in(struct rconn *swconn, const struct ofp_header *msg)
>
>      case ACTION_OPCODE_ICMP:
>          pinctrl_handle_icmp(swconn, &headers, &packet, &pin.flow_metadata,
> -                            &userdata, false);
> +                            &userdata, true);
>          break;
>
>      case ACTION_OPCODE_ICMP4_ERROR:
>          pinctrl_handle_icmp(swconn, &headers, &packet, &pin.flow_metadata,
> -                            &userdata, true);
> +                            &userdata, false);
>          break;
>
>      case ACTION_OPCODE_TCP_RESET:
> diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
> index 63753ac61..eb459c8c4 100644
> --- a/northd/ovn-northd.c
> +++ b/northd/ovn-northd.c
> @@ -4724,12 +4724,10 @@ build_pre_acls(struct ovn_datapath *od, struct hmap *lflows)
>           * Not to do conntrack on ND and ICMP destination
>           * unreachable packets. */
>          ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 110,
> -                      "nd || nd_rs || nd_ra || icmp4.type == 3 || "
> -                      "icmp6.type == 1 || "
> +                      "nd || nd_rs || nd_ra || "
>                        "(udp && udp.src == 546 && udp.dst == 547)", "next;");
>          ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 110,
> -                      "nd || nd_rs || nd_ra || icmp4.type == 3 || "
> -                      "icmp6.type == 1 || "
> +                      "nd || nd_rs || nd_ra || "
>                        "(udp && udp.src == 546 && udp.dst == 547)", "next;");
>
>          /* Ingress and Egress Pre-ACL Table (Priority 100).
> @@ -4841,12 +4839,10 @@ build_pre_lb(struct ovn_datapath *od, struct hmap *lflows,
>  {
>      /* Do not send ND packets to conntrack */
>      ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, 110,
> -                  "nd || nd_rs || nd_ra || icmp4.type == 3 ||"
> -                  "icmp6.type == 1",
> +                  "nd || nd_rs || nd_ra",
>                    "next;");
>      ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, 110,
> -                  "nd || nd_rs || nd_ra || icmp4.type == 3 ||"
> -                  "icmp6.type == 1",
> +                  "nd || nd_rs || nd_ra",
>                    "next;");
>
>      /* Do not send service monitor packets to conntrack. */
> @@ -5025,9 +5021,10 @@ build_reject_acl_rules(struct ovn_datapath *od, struct hmap *lflows,
>          ds_put_format(&actions, "%s ", extra_actions->string);
>      }
>      ds_put_format(&actions, "reg0 = 0; "
> -                  "eth.dst <-> eth.src; ip4.dst <-> ip4.src; "
> -                  "icmp4 { outport <-> inport; %s };",
> -                  ingress ? "output;" : "next(pipeline=ingress,table=0);");
> +                  "icmp4 { eth.dst <-> eth.src; ip4.dst <-> ip4.src; "
> +                  "outport <-> inport; %s };",
> +                  ingress ? "next(pipeline=egress,table=5);"
> +                          : "next(pipeline=ingress,table=19);");
>      ovn_lflow_add_with_hint(lflows, od, stage,
>                              acl->priority + OVN_ACL_PRI_OFFSET,
>                              ds_cstr(&match), ds_cstr(&actions), stage_hint);
> @@ -5044,7 +5041,8 @@ build_reject_acl_rules(struct ovn_datapath *od, struct hmap *lflows,
>      ds_put_format(&actions, "reg0 = 0; icmp6 { "
>                    "eth.dst <-> eth.src; ip6.dst <-> ip6.src; "
>                    "outport <-> inport; %s };",
> -                  ingress ? "output;" : "next(pipeline=ingress,table=0);");
> +                  ingress ? "next(pipeline=egress,table=5);"
> +                          : "next(pipeline=ingress,table=19);");
>      ovn_lflow_add_with_hint(lflows, od, stage,
>                              acl->priority + OVN_ACL_PRI_OFFSET,
>                              ds_cstr(&match), ds_cstr(&actions), stage_hint);
> diff --git a/tests/ovn.at b/tests/ovn.at
> index e6febd4c2..6467bdc42 100644
> --- a/tests/ovn.at
> +++ b/tests/ovn.at
> @@ -11813,13 +11813,13 @@ test_ip_packet() {
>
>      local ip_ttl=ff
>      local packet=${eth_dst}${eth_src}08004500001400004000${ip_ttl}01${ip_chksum}${ipv4_src}${ipv4_dst}
> -
> +    local orig_pkt_in_reply=4500001400004000${ip_ttl}01${ip_chksum}${ipv4_src}${ipv4_dst}
>      local reply_icmp_ttl=ff
>      local icmp_type_code_response=0301
>      local icmp_data=00000000
>      local reply_icmp_payload=${icmp_type_code_response}${exp_icmp_chksum}${icmp_data}
> -    local reply=${eth_src}${eth_dst}08004500001c00004000${reply_icmp_ttl}01${exp_ip_chksum}${ipv4_dst}${ipv4_src}${reply_icmp_payload}
> -    echo $reply >> vif$inport.expected
> +    local reply=${eth_src}${eth_dst}08004500003000004000${reply_icmp_ttl}01${exp_ip_chksum}${ipv4_dst}${ipv4_src}${reply_icmp_payload}
> +    echo $reply$orig_pkt_in_reply >> vif$inport.expected
>
>      as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet
>  }
> @@ -11836,7 +11836,7 @@ test_ipv6_packet() {
>      local ip6_hdr=6000000000083aff${ipv6_src}${ipv6_dst}
>      local packet=${eth_dst}${eth_src}86dd${ip6_hdr}0000000000000000
>
> -    local reply=${eth_src}${eth_dst}86dd6000000000303aff${ipv6_dst}${ipv6_src}0101${exp_icmp_chksum}00000000${ip6_hdr}
> +    local reply=${eth_src}${eth_dst}86dd6000000000383aff${ipv6_dst}${ipv6_src}0101${exp_icmp_chksum}00000000${ip6_hdr}0000000000000000
>      echo $reply >> vif$inport.expected
>
>      as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet
> @@ -11914,11 +11914,11 @@ ovn-nbctl --log acl-add sw0 from-lport 1000 "inport == \"sw0-p21\"" reject
>  # Allow some time for ovn-northd and ovn-controller to catch up.
>  ovn-nbctl --timeout=3 --wait=hv sync
>
> -test_ip_packet 11 1 000000000011 000000000021 $(ip_to_hex 192 168 1 11) $(ip_to_hex 192 168 1 21) 0000 7d8d fcfe
> -test_ip_packet 21 2 000000000021 000000000011 $(ip_to_hex 192 168 1 21) $(ip_to_hex 192 168 1 11) 0000 7d8d fcfe
> -test_ip_packet 31 3 000000000031 000000000012 $(ip_to_hex 192 168 1 31) $(ip_to_hex 192 168 1 12) 0000 7d82 fcfe
> +test_ip_packet 11 1 000000000011 000000000021 $(ip_to_hex 192 168 1 11) $(ip_to_hex 192 168 1 21) 0000 f85b f576
> +test_ip_packet 21 2 000000000021 000000000011 $(ip_to_hex 192 168 1 21) $(ip_to_hex 192 168 1 11) 0000 f85b f576
> +test_ip_packet 31 3 000000000031 000000000012 $(ip_to_hex 192 168 1 31) $(ip_to_hex 192 168 1 12) 0000 f850 f56b
>
> -test_ipv6_packet 11 1 000000000011 000000000021 fe80000000000000020001fffe000001 fe80000000000000020001fffe000002 6183
> +test_ipv6_packet 11 1 000000000011 000000000021 fe80000000000000020001fffe000001 fe80000000000000020001fffe000002 617b
>
>  test_tcp_syn_packet 11 1 000000000011 000000000021 $(ip_to_hex 192 168 1 11) $(ip_to_hex 192 168 1 21) 0000 8b40 3039 0000 b85f 70e4
>  test_tcp_syn_packet 21 2 000000000021 000000000011 $(ip_to_hex 192 168 1 21) $(ip_to_hex 192 168 1 11) 0000 8b40 3039 0000 b85f 70e4
> @@ -12871,13 +12871,13 @@ test_ip_packet() {
>
>      local ip_ttl=01
>      local packet=${eth_dst}${eth_src}08004500001400004000${ip_ttl}01${ip_chksum}${ipv4_src}${ipv4_dst}
> -
> +    local orig_pkt_in_reply=4500001400004000${ip_ttl}01${ip_chksum}${ipv4_src}${ipv4_dst}
>      local reply_icmp_ttl=fe
>      local icmp_type_code_response=0b00
>      local icmp_data=00000000
>      local reply_icmp_payload=${icmp_type_code_response}${exp_icmp_chksum}${icmp_data}
> -    local reply=${eth_src}${eth_dst}08004500001c00004000${reply_icmp_ttl}01${exp_ip_chksum}${ip_router}${ipv4_src}${reply_icmp_payload}
> -    echo $reply >> vif$inport.expected
> +    local reply=${eth_src}${eth_dst}08004500003000004000${reply_icmp_ttl}01${exp_ip_chksum}${ip_router}${ipv4_src}${reply_icmp_payload}
> +    echo $reply$orig_pkt_in_reply >> vif$inport.expected
>
>      as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet
>  }
> @@ -12895,7 +12895,7 @@ test_ip6_packet() {
>      local ip6_hdr=6000000000151101${ipv6_src}${ipv6_dst}
>      local packet=${eth_dst}${eth_src}86dd${ip6_hdr}dbb8303900155bac6b646f65206676676e6d66720a
>
> -    local reply=${eth_src}${eth_dst}86dd6000000000303afe${ipv6_router}${ipv6_src}0300${exp_icmp_chksum}00000000${ip6_hdr}
> +    local reply=${eth_src}${eth_dst}86dd6000000000453afe${ipv6_router}${ipv6_src}0300${exp_icmp_chksum}00000000${ip6_hdr}dbb8303900155bac6b646f65206676676e6d66720a
>      echo $reply >> vif$inport.expected
>
>      as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet
> @@ -12937,8 +12937,8 @@ OVN_POPULATE_ARP
>  # allow some time for ovn-northd and ovn-controller to catch up.
>  ovn-nbctl --wait=hv sync
>
> -test_ip_packet 1 1 000000000001 00000000ff01 $(ip_to_hex 192 168 1 1) $(ip_to_hex 192 168 2 1) $(ip_to_hex 192 168 1 254) 0000 7dae f4ff
> -test_ip6_packet 1 1 000000000001 00000000ff01 20010db8000100000000000000000011 20010db8000200000000000000000011 20010db8000100000000000000000001 d461
> +test_ip_packet 1 1 000000000001 00000000ff01 $(ip_to_hex 192 168 1 1) $(ip_to_hex 192 168 2 1) $(ip_to_hex 192 168 1 254) 0000 f87c ea96
> +test_ip6_packet 1 1 000000000001 00000000ff01 20010db8000100000000000000000011 20010db8000200000000000000000011 20010db8000100000000000000000001 1c22
>  OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [vif1.expected])
>
>  OVN_CLEANUP([hv1], [hv2])
> @@ -12967,12 +12967,12 @@ test_ip_packet() {
>
>      local ip_ttl=ff
>      local packet=${eth_dst}${eth_src}08004500001400004000${ip_ttl}${l4_proto}${ip_chksum}${ipv4_src}${ip_router}
> -
> +    local orig_pkt_in_reply=4500001400004000${ip_ttl}${l4_proto}${ip_chksum}${ipv4_src}${ip_router}
>      local reply_icmp_ttl=fe
>      local icmp_data=00000000
>      local reply_icmp_payload=${exp_icmp_code}${exp_icmp_chksum}${icmp_data}
> -    local reply=${eth_src}${eth_dst}08004500001c00004000${reply_icmp_ttl}01${exp_ip_chksum}${ip_router}${ipv4_src}${reply_icmp_payload}
> -    echo $reply >> vif$inport.expected
> +    local reply=${eth_src}${eth_dst}08004500003000004000${reply_icmp_ttl}01${exp_ip_chksum}${ip_router}${ipv4_src}${reply_icmp_payload}
> +    echo $reply$orig_pkt_in_reply >> vif$inport.expected
>
>      as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet
>  }
> @@ -13038,7 +13038,9 @@ test_ip6_packet() {
>      local ip6_hdr=60000000${ipv6_len}${ipv6_proto}ff${ipv6_src}${ipv6_dst}
>      local packet=${eth_dst}${eth_src}86dd${ip6_hdr}${data}
>
> -    local reply=${eth_src}${eth_dst}86dd6000000000303afe${ipv6_dst}${ipv6_src}${exp_icmp_code}${exp_icmp_chksum}00000000${ip6_hdr}
> +    local reply_ip_len=`expr 48 + ${#data} / 2`
> +    reply_ip_len=$(printf "%x" $reply_ip_len)
> +    local reply=${eth_src}${eth_dst}86dd6000000000${reply_ip_len}3afe${ipv6_dst}${ipv6_src}${exp_icmp_code}${exp_icmp_chksum}00000000${ip6_hdr}${data}
>      echo $reply >> vif$inport.expected
>
>      as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet
> @@ -13080,13 +13082,13 @@ OVN_POPULATE_ARP
>  # allow some time for ovn-northd and ovn-controller to catch up.
>  ovn-nbctl --wait=hv sync
>
> -test_ip_packet 1 1 000000000001 00000000ff01 $(ip_to_hex 192 168 1 1) $(ip_to_hex 192 168 1 254) 11 0000 7dae fcfc 0303
> -test_ip_packet 1 1 000000000001 00000000ff01 $(ip_to_hex 192 168 1 1) $(ip_to_hex 192 168 1 254) 84 0000 7dae fcfd 0302
> -test_ip6_packet 1 1 000000000001 00000000ff01 20010db8000100000000000000000011 20010db8000100000000000000000001 11 0015 dbb8303900155bac6b646f65206676676e6d66720a 0104 d570
> +test_ip_packet 1 1 000000000001 00000000ff01 $(ip_to_hex 192 168 1 1) $(ip_to_hex 192 168 1 254) 11 0000 f87c f485 0303
> +test_ip_packet 1 1 000000000001 00000000ff01 $(ip_to_hex 192 168 1 1) $(ip_to_hex 192 168 1 254) 84 0000 f87c f413 0302
> +test_ip6_packet 1 1 000000000001 00000000ff01 20010db8000100000000000000000011 20010db8000100000000000000000001 11 0015 dbb8303900155bac6b646f65206676676e6d66720a 0104 1d31
>  OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [vif1.expected])
>
>  test_tcp_syn_packet 2 2 000000000002 00000000ff02 $(ip_to_hex 192 168 2 1) $(ip_to_hex 192 168 2 254) 0000 8b40 3039 0000 b680 6e05
> -test_ip6_packet 2 2 000000000002 00000000ff02 20010db8000200000000000000000011 20010db8000200000000000000000001 84 0004 01020304 0103 627e
> +test_ip6_packet 2 2 000000000002 00000000ff02 20010db8000200000000000000000011 20010db8000200000000000000000001 84 0004 01020304 0103 5e74
>  test_tcp6_packet 2 2 000000000002 00000000ff02 20010db8000200000000000000000011 20010db8000200000000000000000001 8b40 3039 0000 98cd
>  OVN_CHECK_PACKETS([hv2/vif2-tx.pcap], [vif2.expected])
>
> diff --git a/tests/system-ovn.at b/tests/system-ovn.at
> index fa3b83cb1..117f1e835 100644
> --- a/tests/system-ovn.at
> +++ b/tests/system-ovn.at
> @@ -3697,7 +3697,7 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
>  AT_CLEANUP
>
>
> -AT_SETUP([ovn -- ACL reject - TCP reset])
> +AT_SETUP([ovn -- ACL reject])
>  AT_SKIP_IF([test $HAVE_NC = no])
>  AT_KEYWORDS([lb])
>
> @@ -3736,13 +3736,14 @@ ovn-nbctl acl-add pg0_drop from-lport 1001 "inport == @pg0_drop && ip" drop
>  ovn-nbctl acl-add pg0_drop to-lport 1001 "outport == @pg0_drop && ip" drop
>
>  ovn-nbctl pg-add pg0 sw0-p1-rej sw0-p2-rej
> -ovn-nbctl acl-add pg0 from-lport 1002 "inport == @pg0 && ip4" allow-related
> +ovn-nbctl acl-add pg0 from-lport 1002 "inport == @pg0 && ip" allow-related
>  ovn-nbctl --log acl-add pg0 from-lport 1004 "inport == @pg0 && ip && tcp && tcp.dst == 80" reject
> +ovn-nbctl --log acl-add pg0 from-lport 1004 "inport == @pg0 && ip && udp && udp.dst == 90" reject
>
> -ovn-nbctl acl-add pg0 to-lport 1002 "outport == @pg0 && ip4 && ip4.src == 0.0.0.0/0 && icmp4" allow-related
>  ovn-nbctl acl-add pg0 to-lport 1002 "outport == @pg0 && ip4 && ip4.src == 0.0.0.0/0 && tcp && tcp.dst == 82" allow-related
>  ovn-nbctl acl-add pg0 to-lport 1002 "outport == @pg0 && ip4 && ip4.src == 0.0.0.0/0 && udp && udp.dst == 82" allow-related
>  ovn-nbctl --log acl-add pg0 to-lport 1004 "inport == @pg0 && ip && tcp && tcp.dst == 84" reject
> +ovn-nbctl --log acl-add pg0 to-lport 1004 "inport == @pg0 && ip && udp && udp.dst == 94" reject
>
>  OVN_POPULATE_ARP
>  ovn-nbctl --wait=hv sync
> @@ -3758,33 +3759,38 @@ ADD_VETH(sw0-p2-rej, sw0-p2-rej, br-int, "10.0.0.4/24", "50:54:00:00:00:04", \
>  NS_CHECK_EXEC([sw0-p1-rej], [ip a a aef0::3/64 dev sw0-p1-rej], [0])
>  NS_CHECK_EXEC([sw0-p2-rej], [ip a a aef0::4/64 dev sw0-p2-rej], [0])
>
> -# Capture packets in sw0-p1-rej.
> -NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -n -c 2 -i sw0-p1-rej tcp port 80 > sw0-p1-rej-ip4.pcap &], [0])
>  sleep 1
>
> -NS_CHECK_EXEC([sw0-p1-rej], [nc 10.0.0.4 80], [1], [],
> -[dnl
> -Ncat: Connection refused.
> -])
> +# Capture packets in sw0-p1-rej.
> +NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -n -c 4 -i sw0-p1-rej tcp > sw0-p1-rej-ip4.pcap &], [0])
> +
> +sleep 1
>
>  OVS_WAIT_UNTIL([
> -    total=`cat sw0-p1-rej-ip4.pcap |  wc -l`
> -    echo "total = $total"
> -    test "${total}" = "2"
> +    ip netns exec sw0-p1-rej nc  10.0.0.4 80 2> r
> +    res=$(cat r)
> +    test "$res" = "Ncat: Connection refused."
>  ])
>
>  # Now send traffic to port 84
> -NS_CHECK_EXEC([sw0-p1-rej], [nc 10.0.0.4 84], [1], [],
> -[dnl
> -Ncat: Connection refused.
> +OVS_WAIT_UNTIL([
> +    ip netns exec sw0-p1-rej nc  10.0.0.4 84 2> r
> +    res=$(cat r)
> +    test "$res" = "Ncat: Connection refused."
>  ])
>
> -AT_CHECK([
> +OVS_WAIT_UNTIL([
>      n_pkt=$(ovs-ofctl dump-flows br-int table=44 | grep -v n_packets=0 | \
>  grep controller | grep tp_dst=84 -c)
>      test $n_pkt -eq 1
>  ])
>
> +OVS_WAIT_UNTIL([
> +    total=`cat sw0-p1-rej-ip4.pcap |  wc -l`
> +    echo "total = $total"
> +    test "${total}" = "4"
> +])
> +
>  # Without this sleep, test case fails intermittently.
>  sleep 3
>
> @@ -3792,17 +3798,68 @@ NS_CHECK_EXEC([sw0-p2-rej], [tcpdump -n -c 2 -i sw0-p2-rej tcp port 80 > sw0-p2-
>
>  sleep 1
>
> -NS_CHECK_EXEC([sw0-p2-rej], [nc -6 aef0::3 80], [1], [],
> -[dnl
> -Ncat: Connection refused.
> +OVS_WAIT_UNTIL([
> +    ip netns exec sw0-p2-rej nc -6 aef0::3 80 2> r
> +    res=$(cat r)
> +    test "$res" = "Ncat: Connection refused."
>  ])
>
> +
>  OVS_WAIT_UNTIL([
>      total=`cat sw0-p2-rej-ip6.pcap |  wc -l`
>      echo "total = $total"
>      test "${total}" = "2"
>  ])
>
> +# Now test for IPv4 UDP.
> +NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -n -c 1 -i sw0-p1-rej udp port 90 > sw0-p1-rej-udp.pcap &], [0])
> +NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -n -c 1 -i sw0-p1-rej icmp > sw0-p1-rej-icmp.pcap &], [0])
> +
> +echo "foo" > foo
> +OVS_WAIT_UNTIL([
> +    ip netns exec sw0-p1-rej nc -u 10.0.0.4 90 < foo
> +    c=$(cat sw0-p1-rej-icmp.pcap | grep \
> +"10.0.0.4 > 10.0.0.3: ICMP 10.0.0.4 udp port dnsix unreachable" | uniq | wc -l)
> +    test $c -eq 1
> +])
> +
> +rm -f *.pcap
> +
> +NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -n -c 1 -i sw0-p1-rej udp port 94 > sw0-p1-rej-udp.pcap &], [0])
> +NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -n -c 1 -i sw0-p1-rej icmp > sw0-p1-rej-icmp.pcap &], [0])
> +
> +OVS_WAIT_UNTIL([
> +    ip netns exec sw0-p1-rej nc -u 10.0.0.4 94 < foo
> +    c=$(cat sw0-p1-rej-icmp.pcap | grep \
> +"10.0.0.4 > 10.0.0.3: ICMP 10.0.0.4 udp port objcall unreachable" | uniq | wc -l)
> +    test $c -eq 1
> +])
> +
> +# Now test for IPv6 UDP.
> +NS_CHECK_EXEC([sw0-p2-rej], [tcpdump -n -c 1 -i sw0-p2-rej udp port 90 > sw0-p2-rej-ip6-udp.pcap &], [0])
> +NS_CHECK_EXEC([sw0-p2-rej], [tcpdump -n -c 1 -i sw0-p2-rej icmp6 > sw0-p2-rej-icmp6.pcap &], [0])
> +
> +OVS_WAIT_UNTIL([
> +    ip netns exec sw0-p2-rej nc -u -6 aef0::3 90 < foo
> +    c=$(cat sw0-p2-rej-icmp6.pcap | grep \
> +"IP6 aef0::3 > aef0::4: ICMP6, destination unreachable, unreachable port, \
> +aef0::3 udp port dnsix" | uniq | wc -l)
> +    test $c -eq 1
> +])
> +
> +rm -f *.pcap
> +
> +NS_CHECK_EXEC([sw0-p2-rej], [tcpdump -n -c 1 -i sw0-p2-rej udp port 94 > sw0-p2-rej-ip6-udp.pcap &], [0])
> +NS_CHECK_EXEC([sw0-p2-rej], [tcpdump -n -c 1 -i sw0-p2-rej icmp6 > sw0-p2-rej-icmp6.pcap &], [0])
> +
> +OVS_WAIT_UNTIL([
> +    ip netns exec sw0-p2-rej nc -u -6 aef0::3 94 < foo
> +    c=$(cat sw0-p2-rej-icmp6.pcap | grep \
> +"IP6 aef0::3 > aef0::4: ICMP6, destination unreachable, unreachable port, \
> +aef0::3 udp port objcall" | uniq | wc -l)
> +    test $c -eq 1
> +])
> +
>  OVS_APP_EXIT_AND_WAIT([ovn-controller])
>
>  as ovn-sb
> --
> 2.25.1
>
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
Numan Siddique May 6, 2020, 7:45 a.m. UTC | #2
On Tue, May 5, 2020 at 6:34 PM Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
wrote:

> >
> > From: Numan Siddique <numans@ovn.org>
> >
> > The icmp packet generated by ovn-controller for reject ACL action
> > for non TCP packets is not getting delivered to the sender of
> > the original packet. This is because the icmp packets are skipped
> > from out_pre_lb/out_pre_acl logical switch egress pipeline and this
> > results in these icmp packets getting dropped in the ACL stage because
> > of invalid ct flags. This patch fixes this issue by removing those
> logical
> > flows. The IP checksum generated by ovn-controller is invalid. This patch
> > fixes this issue as well.
> >
> > Signed-off-by: Numan Siddique <numans@ovn.org>
>
> Tested-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
>

Thanks Lorenzo. I applied this patch to master and branch-20.03.

Numan


>
> > ---
> >  controller/pinctrl.c | 102 ++++++++++++++++++++++++++++---------------
> >  northd/ovn-northd.c  |  22 +++++-----
> >  tests/ovn.at         |  46 +++++++++----------
> >  tests/system-ovn.at  |  95 ++++++++++++++++++++++++++++++++--------
> >  4 files changed, 177 insertions(+), 88 deletions(-)
> >
> > diff --git a/controller/pinctrl.c b/controller/pinctrl.c
> > index 3230bb386..63796d88c 100644
> > --- a/controller/pinctrl.c
> > +++ b/controller/pinctrl.c
> > @@ -1453,7 +1453,7 @@ static void
> >  pinctrl_handle_icmp(struct rconn *swconn, const struct flow *ip_flow,
> >                      struct dp_packet *pkt_in,
> >                      const struct match *md, struct ofpbuf *userdata,
> > -                    bool include_orig_ip_datagram)
> > +                    bool set_icmp_code)
> >  {
> >      /* This action only works for IP packets, and the switch should
> only send
> >       * us IP packets this way, but check here just to be sure. */
> > @@ -1500,46 +1500,51 @@ pinctrl_handle_icmp(struct rconn *swconn, const
> struct flow *ip_flow,
> >          packet_set_ipv4(&packet, ip_flow->nw_src, ip_flow->nw_dst,
> >                          ip_flow->nw_tos, 255);
> >
> > +        uint8_t icmp_code =  1;
> > +        if (set_icmp_code && in_ip->ip_proto == IPPROTO_UDP) {
> > +            icmp_code = 3;
> > +        }
> > +
> >          struct icmp_header *ih = dp_packet_put_zeros(&packet, sizeof
> *ih);
> >          dp_packet_set_l4(&packet, ih);
> > -        packet_set_icmp(&packet, ICMP4_DST_UNREACH, 1);
> > -
> > -        if (include_orig_ip_datagram) {
> > -            /* RFC 1122: 3.2.2 MUST send at least the IP header and 8
> bytes
> > -             * of header. MAY send more.
> > -             * RFC says return as much as we can without exceeding 576
> > -             * bytes.
> > -             * So, lets return as much as we can. */
> > -
> > -            /* Calculate available room to include the original IP +
> data. */
> > -            nh = dp_packet_l3(&packet);
> > -            uint16_t room = 576 - (sizeof *eh + ntohs(nh->ip_tot_len));
> > -            if (in_ip_len > room) {
> > -                in_ip_len = room;
> > -            }
> > -            dp_packet_put(&packet, in_ip, in_ip_len);
> > -
> > -            /* dp_packet_put may reallocate the buffer. Get the l3 and
> l4
> > -             * header pointers again. */
> > -            nh = dp_packet_l3(&packet);
> > -            ih = dp_packet_l4(&packet);
> > -            uint16_t ip_total_len = ntohs(nh->ip_tot_len) + in_ip_len;
> > -            nh->ip_tot_len = htons(ip_total_len);
> > -            ih->icmp_csum = 0;
> > -            ih->icmp_csum = csum(ih, sizeof *ih + in_ip_len);
> > -            nh->ip_csum = 0;
> > -            nh->ip_csum = csum(nh, sizeof *nh);
> > -        }
> > +        packet_set_icmp(&packet, ICMP4_DST_UNREACH, icmp_code);
> > +
> > +        /* RFC 1122: 3.2.2     MUST send at least the IP header and 8
> bytes
> > +         * of header. MAY send more.
> > +         * RFC says return as much as we can without exceeding 576
> > +         * bytes.
> > +         * So, lets return as much as we can. */
> > +
> > +        /* Calculate available room to include the original IP + data.
> */
> > +        nh = dp_packet_l3(&packet);
> > +        uint16_t room = 576 - (sizeof *eh + ntohs(nh->ip_tot_len));
> > +        if (in_ip_len > room) {
> > +            in_ip_len = room;
> > +        }
> > +        dp_packet_put(&packet, in_ip, in_ip_len);
> > +
> > +        /* dp_packet_put may reallocate the buffer. Get the l3 and l4
> > +            * header pointers again. */
> > +        nh = dp_packet_l3(&packet);
> > +        ih = dp_packet_l4(&packet);
> > +        uint16_t ip_total_len = ntohs(nh->ip_tot_len) + in_ip_len;
> > +        nh->ip_tot_len = htons(ip_total_len);
> > +        ih->icmp_csum = 0;
> > +        ih->icmp_csum = csum(ih, sizeof *ih + in_ip_len);
> > +        nh->ip_csum = 0;
> > +        nh->ip_csum = csum(nh, sizeof *nh);
> > +
> >      } else {
> >          struct ip6_hdr *nh = dp_packet_put_zeros(&packet, sizeof *nh);
> >          struct icmp6_data_header *ih;
> >          uint32_t icmpv6_csum;
> > +        struct ip6_hdr *in_ip = dp_packet_l3(pkt_in);
> >
> >          eh->eth_type = htons(ETH_TYPE_IPV6);
> >          dp_packet_set_l3(&packet, nh);
> >          nh->ip6_vfc = 0x60;
> >          nh->ip6_nxt = IPPROTO_ICMPV6;
> > -        nh->ip6_plen = htons(sizeof(*nh) + ICMP6_DATA_HEADER_LEN);
> > +        nh->ip6_plen = htons(ICMP6_DATA_HEADER_LEN);
> >          packet_set_ipv6(&packet, &ip_flow->ipv6_src, &ip_flow->ipv6_dst,
> >                          ip_flow->nw_tos, ip_flow->ipv6_label, 255);
> >
> > @@ -1547,15 +1552,42 @@ pinctrl_handle_icmp(struct rconn *swconn, const
> struct flow *ip_flow,
> >          dp_packet_set_l4(&packet, ih);
> >          ih->icmp6_base.icmp6_type = ICMP6_DST_UNREACH;
> >          ih->icmp6_base.icmp6_code = 1;
> > +
> > +        if (set_icmp_code && in_ip->ip6_nxt == IPPROTO_UDP) {
> > +            ih->icmp6_base.icmp6_code = ICMP6_DST_UNREACH_NOPORT;
> > +        }
> >          ih->icmp6_base.icmp6_cksum = 0;
> >
> > -        uint8_t *data = dp_packet_put_zeros(&packet, sizeof *nh);
> > -        memcpy(data, dp_packet_l3(pkt_in), sizeof(*nh));
> > +        nh = dp_packet_l3(&packet);
> > +
> > +        /* RFC 4443: 3.1.
> > +         *
> > +         * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
> 0 1
> > +         *
> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> > +         * |     Type      |     Code      |          Checksum
>    |
> > +         *
> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> > +         * |                             Unused
>     |
> > +         *
> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> > +         * |                    As much of invoking packet
>    |
> > +         * +                as possible without the ICMPv6 packet
>     +
> > +         * |                exceeding the minimum IPv6 MTU [IPv6]
>     |
> > +         *
> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> > +         */
> > +
> > +        uint16_t room = 1280 - (sizeof *eh + sizeof *nh +
> > +                                ICMP6_DATA_HEADER_LEN);
> > +        uint16_t in_ip_len = (uint16_t) sizeof *in_ip +
> ntohs(in_ip->ip6_plen);
> > +        if (in_ip_len > room) {
> > +            in_ip_len = room;
> > +        }
> > +
> > +        dp_packet_put(&packet, in_ip, in_ip_len);
> > +        nh->ip6_plen = htons(ICMP6_DATA_HEADER_LEN + in_ip_len);
> >
> >          icmpv6_csum = packet_csum_pseudoheader6(dp_packet_l3(&packet));
> >          ih->icmp6_base.icmp6_cksum = csum_finish(
> >              csum_continue(icmpv6_csum, ih,
> > -                          sizeof(*nh) + ICMP6_DATA_HEADER_LEN));
> > +                          in_ip_len + ICMP6_DATA_HEADER_LEN));
> >      }
> >
> >      if (ip_flow->vlans[0].tci & htons(VLAN_CFI)) {
> > @@ -2646,12 +2678,12 @@ process_packet_in(struct rconn *swconn, const
> struct ofp_header *msg)
> >
> >      case ACTION_OPCODE_ICMP:
> >          pinctrl_handle_icmp(swconn, &headers, &packet,
> &pin.flow_metadata,
> > -                            &userdata, false);
> > +                            &userdata, true);
> >          break;
> >
> >      case ACTION_OPCODE_ICMP4_ERROR:
> >          pinctrl_handle_icmp(swconn, &headers, &packet,
> &pin.flow_metadata,
> > -                            &userdata, true);
> > +                            &userdata, false);
> >          break;
> >
> >      case ACTION_OPCODE_TCP_RESET:
> > diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
> > index 63753ac61..eb459c8c4 100644
> > --- a/northd/ovn-northd.c
> > +++ b/northd/ovn-northd.c
> > @@ -4724,12 +4724,10 @@ build_pre_acls(struct ovn_datapath *od, struct
> hmap *lflows)
> >           * Not to do conntrack on ND and ICMP destination
> >           * unreachable packets. */
> >          ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 110,
> > -                      "nd || nd_rs || nd_ra || icmp4.type == 3 || "
> > -                      "icmp6.type == 1 || "
> > +                      "nd || nd_rs || nd_ra || "
> >                        "(udp && udp.src == 546 && udp.dst == 547)",
> "next;");
> >          ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 110,
> > -                      "nd || nd_rs || nd_ra || icmp4.type == 3 || "
> > -                      "icmp6.type == 1 || "
> > +                      "nd || nd_rs || nd_ra || "
> >                        "(udp && udp.src == 546 && udp.dst == 547)",
> "next;");
> >
> >          /* Ingress and Egress Pre-ACL Table (Priority 100).
> > @@ -4841,12 +4839,10 @@ build_pre_lb(struct ovn_datapath *od, struct
> hmap *lflows,
> >  {
> >      /* Do not send ND packets to conntrack */
> >      ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, 110,
> > -                  "nd || nd_rs || nd_ra || icmp4.type == 3 ||"
> > -                  "icmp6.type == 1",
> > +                  "nd || nd_rs || nd_ra",
> >                    "next;");
> >      ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, 110,
> > -                  "nd || nd_rs || nd_ra || icmp4.type == 3 ||"
> > -                  "icmp6.type == 1",
> > +                  "nd || nd_rs || nd_ra",
> >                    "next;");
> >
> >      /* Do not send service monitor packets to conntrack. */
> > @@ -5025,9 +5021,10 @@ build_reject_acl_rules(struct ovn_datapath *od,
> struct hmap *lflows,
> >          ds_put_format(&actions, "%s ", extra_actions->string);
> >      }
> >      ds_put_format(&actions, "reg0 = 0; "
> > -                  "eth.dst <-> eth.src; ip4.dst <-> ip4.src; "
> > -                  "icmp4 { outport <-> inport; %s };",
> > -                  ingress ? "output;" :
> "next(pipeline=ingress,table=0);");
> > +                  "icmp4 { eth.dst <-> eth.src; ip4.dst <-> ip4.src; "
> > +                  "outport <-> inport; %s };",
> > +                  ingress ? "next(pipeline=egress,table=5);"
> > +                          : "next(pipeline=ingress,table=19);");
> >      ovn_lflow_add_with_hint(lflows, od, stage,
> >                              acl->priority + OVN_ACL_PRI_OFFSET,
> >                              ds_cstr(&match), ds_cstr(&actions),
> stage_hint);
> > @@ -5044,7 +5041,8 @@ build_reject_acl_rules(struct ovn_datapath *od,
> struct hmap *lflows,
> >      ds_put_format(&actions, "reg0 = 0; icmp6 { "
> >                    "eth.dst <-> eth.src; ip6.dst <-> ip6.src; "
> >                    "outport <-> inport; %s };",
> > -                  ingress ? "output;" :
> "next(pipeline=ingress,table=0);");
> > +                  ingress ? "next(pipeline=egress,table=5);"
> > +                          : "next(pipeline=ingress,table=19);");
> >      ovn_lflow_add_with_hint(lflows, od, stage,
> >                              acl->priority + OVN_ACL_PRI_OFFSET,
> >                              ds_cstr(&match), ds_cstr(&actions),
> stage_hint);
> > diff --git a/tests/ovn.at b/tests/ovn.at
> > index e6febd4c2..6467bdc42 100644
> > --- a/tests/ovn.at
> > +++ b/tests/ovn.at
> > @@ -11813,13 +11813,13 @@ test_ip_packet() {
> >
> >      local ip_ttl=ff
> >      local
> packet=${eth_dst}${eth_src}08004500001400004000${ip_ttl}01${ip_chksum}${ipv4_src}${ipv4_dst}
> > -
> > +    local
> orig_pkt_in_reply=4500001400004000${ip_ttl}01${ip_chksum}${ipv4_src}${ipv4_dst}
> >      local reply_icmp_ttl=ff
> >      local icmp_type_code_response=0301
> >      local icmp_data=00000000
> >      local
> reply_icmp_payload=${icmp_type_code_response}${exp_icmp_chksum}${icmp_data}
> > -    local
> reply=${eth_src}${eth_dst}08004500001c00004000${reply_icmp_ttl}01${exp_ip_chksum}${ipv4_dst}${ipv4_src}${reply_icmp_payload}
> > -    echo $reply >> vif$inport.expected
> > +    local
> reply=${eth_src}${eth_dst}08004500003000004000${reply_icmp_ttl}01${exp_ip_chksum}${ipv4_dst}${ipv4_src}${reply_icmp_payload}
> > +    echo $reply$orig_pkt_in_reply >> vif$inport.expected
> >
> >      as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet
> >  }
> > @@ -11836,7 +11836,7 @@ test_ipv6_packet() {
> >      local ip6_hdr=6000000000083aff${ipv6_src}${ipv6_dst}
> >      local packet=${eth_dst}${eth_src}86dd${ip6_hdr}0000000000000000
> >
> > -    local
> reply=${eth_src}${eth_dst}86dd6000000000303aff${ipv6_dst}${ipv6_src}0101${exp_icmp_chksum}00000000${ip6_hdr}
> > +    local
> reply=${eth_src}${eth_dst}86dd6000000000383aff${ipv6_dst}${ipv6_src}0101${exp_icmp_chksum}00000000${ip6_hdr}0000000000000000
> >      echo $reply >> vif$inport.expected
> >
> >      as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet
> > @@ -11914,11 +11914,11 @@ ovn-nbctl --log acl-add sw0 from-lport 1000
> "inport == \"sw0-p21\"" reject
> >  # Allow some time for ovn-northd and ovn-controller to catch up.
> >  ovn-nbctl --timeout=3 --wait=hv sync
> >
> > -test_ip_packet 11 1 000000000011 000000000021 $(ip_to_hex 192 168 1 11)
> $(ip_to_hex 192 168 1 21) 0000 7d8d fcfe
> > -test_ip_packet 21 2 000000000021 000000000011 $(ip_to_hex 192 168 1 21)
> $(ip_to_hex 192 168 1 11) 0000 7d8d fcfe
> > -test_ip_packet 31 3 000000000031 000000000012 $(ip_to_hex 192 168 1 31)
> $(ip_to_hex 192 168 1 12) 0000 7d82 fcfe
> > +test_ip_packet 11 1 000000000011 000000000021 $(ip_to_hex 192 168 1 11)
> $(ip_to_hex 192 168 1 21) 0000 f85b f576
> > +test_ip_packet 21 2 000000000021 000000000011 $(ip_to_hex 192 168 1 21)
> $(ip_to_hex 192 168 1 11) 0000 f85b f576
> > +test_ip_packet 31 3 000000000031 000000000012 $(ip_to_hex 192 168 1 31)
> $(ip_to_hex 192 168 1 12) 0000 f850 f56b
> >
> > -test_ipv6_packet 11 1 000000000011 000000000021
> fe80000000000000020001fffe000001 fe80000000000000020001fffe000002 6183
> > +test_ipv6_packet 11 1 000000000011 000000000021
> fe80000000000000020001fffe000001 fe80000000000000020001fffe000002 617b
> >
> >  test_tcp_syn_packet 11 1 000000000011 000000000021 $(ip_to_hex 192 168
> 1 11) $(ip_to_hex 192 168 1 21) 0000 8b40 3039 0000 b85f 70e4
> >  test_tcp_syn_packet 21 2 000000000021 000000000011 $(ip_to_hex 192 168
> 1 21) $(ip_to_hex 192 168 1 11) 0000 8b40 3039 0000 b85f 70e4
> > @@ -12871,13 +12871,13 @@ test_ip_packet() {
> >
> >      local ip_ttl=01
> >      local
> packet=${eth_dst}${eth_src}08004500001400004000${ip_ttl}01${ip_chksum}${ipv4_src}${ipv4_dst}
> > -
> > +    local
> orig_pkt_in_reply=4500001400004000${ip_ttl}01${ip_chksum}${ipv4_src}${ipv4_dst}
> >      local reply_icmp_ttl=fe
> >      local icmp_type_code_response=0b00
> >      local icmp_data=00000000
> >      local
> reply_icmp_payload=${icmp_type_code_response}${exp_icmp_chksum}${icmp_data}
> > -    local
> reply=${eth_src}${eth_dst}08004500001c00004000${reply_icmp_ttl}01${exp_ip_chksum}${ip_router}${ipv4_src}${reply_icmp_payload}
> > -    echo $reply >> vif$inport.expected
> > +    local
> reply=${eth_src}${eth_dst}08004500003000004000${reply_icmp_ttl}01${exp_ip_chksum}${ip_router}${ipv4_src}${reply_icmp_payload}
> > +    echo $reply$orig_pkt_in_reply >> vif$inport.expected
> >
> >      as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet
> >  }
> > @@ -12895,7 +12895,7 @@ test_ip6_packet() {
> >      local ip6_hdr=6000000000151101${ipv6_src}${ipv6_dst}
> >      local
> packet=${eth_dst}${eth_src}86dd${ip6_hdr}dbb8303900155bac6b646f65206676676e6d66720a
> >
> > -    local
> reply=${eth_src}${eth_dst}86dd6000000000303afe${ipv6_router}${ipv6_src}0300${exp_icmp_chksum}00000000${ip6_hdr}
> > +    local
> reply=${eth_src}${eth_dst}86dd6000000000453afe${ipv6_router}${ipv6_src}0300${exp_icmp_chksum}00000000${ip6_hdr}dbb8303900155bac6b646f65206676676e6d66720a
> >      echo $reply >> vif$inport.expected
> >
> >      as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet
> > @@ -12937,8 +12937,8 @@ OVN_POPULATE_ARP
> >  # allow some time for ovn-northd and ovn-controller to catch up.
> >  ovn-nbctl --wait=hv sync
> >
> > -test_ip_packet 1 1 000000000001 00000000ff01 $(ip_to_hex 192 168 1 1)
> $(ip_to_hex 192 168 2 1) $(ip_to_hex 192 168 1 254) 0000 7dae f4ff
> > -test_ip6_packet 1 1 000000000001 00000000ff01
> 20010db8000100000000000000000011 20010db8000200000000000000000011
> 20010db8000100000000000000000001 d461
> > +test_ip_packet 1 1 000000000001 00000000ff01 $(ip_to_hex 192 168 1 1)
> $(ip_to_hex 192 168 2 1) $(ip_to_hex 192 168 1 254) 0000 f87c ea96
> > +test_ip6_packet 1 1 000000000001 00000000ff01
> 20010db8000100000000000000000011 20010db8000200000000000000000011
> 20010db8000100000000000000000001 1c22
> >  OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [vif1.expected])
> >
> >  OVN_CLEANUP([hv1], [hv2])
> > @@ -12967,12 +12967,12 @@ test_ip_packet() {
> >
> >      local ip_ttl=ff
> >      local
> packet=${eth_dst}${eth_src}08004500001400004000${ip_ttl}${l4_proto}${ip_chksum}${ipv4_src}${ip_router}
> > -
> > +    local
> orig_pkt_in_reply=4500001400004000${ip_ttl}${l4_proto}${ip_chksum}${ipv4_src}${ip_router}
> >      local reply_icmp_ttl=fe
> >      local icmp_data=00000000
> >      local
> reply_icmp_payload=${exp_icmp_code}${exp_icmp_chksum}${icmp_data}
> > -    local
> reply=${eth_src}${eth_dst}08004500001c00004000${reply_icmp_ttl}01${exp_ip_chksum}${ip_router}${ipv4_src}${reply_icmp_payload}
> > -    echo $reply >> vif$inport.expected
> > +    local
> reply=${eth_src}${eth_dst}08004500003000004000${reply_icmp_ttl}01${exp_ip_chksum}${ip_router}${ipv4_src}${reply_icmp_payload}
> > +    echo $reply$orig_pkt_in_reply >> vif$inport.expected
> >
> >      as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet
> >  }
> > @@ -13038,7 +13038,9 @@ test_ip6_packet() {
> >      local
> ip6_hdr=60000000${ipv6_len}${ipv6_proto}ff${ipv6_src}${ipv6_dst}
> >      local packet=${eth_dst}${eth_src}86dd${ip6_hdr}${data}
> >
> > -    local
> reply=${eth_src}${eth_dst}86dd6000000000303afe${ipv6_dst}${ipv6_src}${exp_icmp_code}${exp_icmp_chksum}00000000${ip6_hdr}
> > +    local reply_ip_len=`expr 48 + ${#data} / 2`
> > +    reply_ip_len=$(printf "%x" $reply_ip_len)
> > +    local
> reply=${eth_src}${eth_dst}86dd6000000000${reply_ip_len}3afe${ipv6_dst}${ipv6_src}${exp_icmp_code}${exp_icmp_chksum}00000000${ip6_hdr}${data}
> >      echo $reply >> vif$inport.expected
> >
> >      as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet
> > @@ -13080,13 +13082,13 @@ OVN_POPULATE_ARP
> >  # allow some time for ovn-northd and ovn-controller to catch up.
> >  ovn-nbctl --wait=hv sync
> >
> > -test_ip_packet 1 1 000000000001 00000000ff01 $(ip_to_hex 192 168 1 1)
> $(ip_to_hex 192 168 1 254) 11 0000 7dae fcfc 0303
> > -test_ip_packet 1 1 000000000001 00000000ff01 $(ip_to_hex 192 168 1 1)
> $(ip_to_hex 192 168 1 254) 84 0000 7dae fcfd 0302
> > -test_ip6_packet 1 1 000000000001 00000000ff01
> 20010db8000100000000000000000011 20010db8000100000000000000000001 11 0015
> dbb8303900155bac6b646f65206676676e6d66720a 0104 d570
> > +test_ip_packet 1 1 000000000001 00000000ff01 $(ip_to_hex 192 168 1 1)
> $(ip_to_hex 192 168 1 254) 11 0000 f87c f485 0303
> > +test_ip_packet 1 1 000000000001 00000000ff01 $(ip_to_hex 192 168 1 1)
> $(ip_to_hex 192 168 1 254) 84 0000 f87c f413 0302
> > +test_ip6_packet 1 1 000000000001 00000000ff01
> 20010db8000100000000000000000011 20010db8000100000000000000000001 11 0015
> dbb8303900155bac6b646f65206676676e6d66720a 0104 1d31
> >  OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [vif1.expected])
> >
> >  test_tcp_syn_packet 2 2 000000000002 00000000ff02 $(ip_to_hex 192 168 2
> 1) $(ip_to_hex 192 168 2 254) 0000 8b40 3039 0000 b680 6e05
> > -test_ip6_packet 2 2 000000000002 00000000ff02
> 20010db8000200000000000000000011 20010db8000200000000000000000001 84 0004
> 01020304 0103 627e
> > +test_ip6_packet 2 2 000000000002 00000000ff02
> 20010db8000200000000000000000011 20010db8000200000000000000000001 84 0004
> 01020304 0103 5e74
> >  test_tcp6_packet 2 2 000000000002 00000000ff02
> 20010db8000200000000000000000011 20010db8000200000000000000000001 8b40 3039
> 0000 98cd
> >  OVN_CHECK_PACKETS([hv2/vif2-tx.pcap], [vif2.expected])
> >
> > diff --git a/tests/system-ovn.at b/tests/system-ovn.at
> > index fa3b83cb1..117f1e835 100644
> > --- a/tests/system-ovn.at
> > +++ b/tests/system-ovn.at
> > @@ -3697,7 +3697,7 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port
> patch-.*/d
> >  AT_CLEANUP
> >
> >
> > -AT_SETUP([ovn -- ACL reject - TCP reset])
> > +AT_SETUP([ovn -- ACL reject])
> >  AT_SKIP_IF([test $HAVE_NC = no])
> >  AT_KEYWORDS([lb])
> >
> > @@ -3736,13 +3736,14 @@ ovn-nbctl acl-add pg0_drop from-lport 1001
> "inport == @pg0_drop && ip" drop
> >  ovn-nbctl acl-add pg0_drop to-lport 1001 "outport == @pg0_drop && ip"
> drop
> >
> >  ovn-nbctl pg-add pg0 sw0-p1-rej sw0-p2-rej
> > -ovn-nbctl acl-add pg0 from-lport 1002 "inport == @pg0 && ip4"
> allow-related
> > +ovn-nbctl acl-add pg0 from-lport 1002 "inport == @pg0 && ip"
> allow-related
> >  ovn-nbctl --log acl-add pg0 from-lport 1004 "inport == @pg0 && ip &&
> tcp && tcp.dst == 80" reject
> > +ovn-nbctl --log acl-add pg0 from-lport 1004 "inport == @pg0 && ip &&
> udp && udp.dst == 90" reject
> >
> > -ovn-nbctl acl-add pg0 to-lport 1002 "outport == @pg0 && ip4 && ip4.src
> == 0.0.0.0/0 && icmp4" allow-related
> >  ovn-nbctl acl-add pg0 to-lport 1002 "outport == @pg0 && ip4 && ip4.src
> == 0.0.0.0/0 && tcp && tcp.dst == 82" allow-related
> >  ovn-nbctl acl-add pg0 to-lport 1002 "outport == @pg0 && ip4 && ip4.src
> == 0.0.0.0/0 && udp && udp.dst == 82" allow-related
> >  ovn-nbctl --log acl-add pg0 to-lport 1004 "inport == @pg0 && ip && tcp
> && tcp.dst == 84" reject
> > +ovn-nbctl --log acl-add pg0 to-lport 1004 "inport == @pg0 && ip && udp
> && udp.dst == 94" reject
> >
> >  OVN_POPULATE_ARP
> >  ovn-nbctl --wait=hv sync
> > @@ -3758,33 +3759,38 @@ ADD_VETH(sw0-p2-rej, sw0-p2-rej, br-int, "
> 10.0.0.4/24", "50:54:00:00:00:04", \
> >  NS_CHECK_EXEC([sw0-p1-rej], [ip a a aef0::3/64 dev sw0-p1-rej], [0])
> >  NS_CHECK_EXEC([sw0-p2-rej], [ip a a aef0::4/64 dev sw0-p2-rej], [0])
> >
> > -# Capture packets in sw0-p1-rej.
> > -NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -n -c 2 -i sw0-p1-rej tcp port 80
> > sw0-p1-rej-ip4.pcap &], [0])
> >  sleep 1
> >
> > -NS_CHECK_EXEC([sw0-p1-rej], [nc 10.0.0.4 80], [1], [],
> > -[dnl
> > -Ncat: Connection refused.
> > -])
> > +# Capture packets in sw0-p1-rej.
> > +NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -n -c 4 -i sw0-p1-rej tcp >
> sw0-p1-rej-ip4.pcap &], [0])
> > +
> > +sleep 1
> >
> >  OVS_WAIT_UNTIL([
> > -    total=`cat sw0-p1-rej-ip4.pcap |  wc -l`
> > -    echo "total = $total"
> > -    test "${total}" = "2"
> > +    ip netns exec sw0-p1-rej nc  10.0.0.4 80 2> r
> > +    res=$(cat r)
> > +    test "$res" = "Ncat: Connection refused."
> >  ])
> >
> >  # Now send traffic to port 84
> > -NS_CHECK_EXEC([sw0-p1-rej], [nc 10.0.0.4 84], [1], [],
> > -[dnl
> > -Ncat: Connection refused.
> > +OVS_WAIT_UNTIL([
> > +    ip netns exec sw0-p1-rej nc  10.0.0.4 84 2> r
> > +    res=$(cat r)
> > +    test "$res" = "Ncat: Connection refused."
> >  ])
> >
> > -AT_CHECK([
> > +OVS_WAIT_UNTIL([
> >      n_pkt=$(ovs-ofctl dump-flows br-int table=44 | grep -v n_packets=0
> | \
> >  grep controller | grep tp_dst=84 -c)
> >      test $n_pkt -eq 1
> >  ])
> >
> > +OVS_WAIT_UNTIL([
> > +    total=`cat sw0-p1-rej-ip4.pcap |  wc -l`
> > +    echo "total = $total"
> > +    test "${total}" = "4"
> > +])
> > +
> >  # Without this sleep, test case fails intermittently.
> >  sleep 3
> >
> > @@ -3792,17 +3798,68 @@ NS_CHECK_EXEC([sw0-p2-rej], [tcpdump -n -c 2 -i
> sw0-p2-rej tcp port 80 > sw0-p2-
> >
> >  sleep 1
> >
> > -NS_CHECK_EXEC([sw0-p2-rej], [nc -6 aef0::3 80], [1], [],
> > -[dnl
> > -Ncat: Connection refused.
> > +OVS_WAIT_UNTIL([
> > +    ip netns exec sw0-p2-rej nc -6 aef0::3 80 2> r
> > +    res=$(cat r)
> > +    test "$res" = "Ncat: Connection refused."
> >  ])
> >
> > +
> >  OVS_WAIT_UNTIL([
> >      total=`cat sw0-p2-rej-ip6.pcap |  wc -l`
> >      echo "total = $total"
> >      test "${total}" = "2"
> >  ])
> >
> > +# Now test for IPv4 UDP.
> > +NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -n -c 1 -i sw0-p1-rej udp port 90
> > sw0-p1-rej-udp.pcap &], [0])
> > +NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -n -c 1 -i sw0-p1-rej icmp >
> sw0-p1-rej-icmp.pcap &], [0])
> > +
> > +echo "foo" > foo
> > +OVS_WAIT_UNTIL([
> > +    ip netns exec sw0-p1-rej nc -u 10.0.0.4 90 < foo
> > +    c=$(cat sw0-p1-rej-icmp.pcap | grep \
> > +"10.0.0.4 > 10.0.0.3: ICMP 10.0.0.4 udp port dnsix unreachable" | uniq
> | wc -l)
> > +    test $c -eq 1
> > +])
> > +
> > +rm -f *.pcap
> > +
> > +NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -n -c 1 -i sw0-p1-rej udp port 94
> > sw0-p1-rej-udp.pcap &], [0])
> > +NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -n -c 1 -i sw0-p1-rej icmp >
> sw0-p1-rej-icmp.pcap &], [0])
> > +
> > +OVS_WAIT_UNTIL([
> > +    ip netns exec sw0-p1-rej nc -u 10.0.0.4 94 < foo
> > +    c=$(cat sw0-p1-rej-icmp.pcap | grep \
> > +"10.0.0.4 > 10.0.0.3: ICMP 10.0.0.4 udp port objcall unreachable" |
> uniq | wc -l)
> > +    test $c -eq 1
> > +])
> > +
> > +# Now test for IPv6 UDP.
> > +NS_CHECK_EXEC([sw0-p2-rej], [tcpdump -n -c 1 -i sw0-p2-rej udp port 90
> > sw0-p2-rej-ip6-udp.pcap &], [0])
> > +NS_CHECK_EXEC([sw0-p2-rej], [tcpdump -n -c 1 -i sw0-p2-rej icmp6 >
> sw0-p2-rej-icmp6.pcap &], [0])
> > +
> > +OVS_WAIT_UNTIL([
> > +    ip netns exec sw0-p2-rej nc -u -6 aef0::3 90 < foo
> > +    c=$(cat sw0-p2-rej-icmp6.pcap | grep \
> > +"IP6 aef0::3 > aef0::4: ICMP6, destination unreachable, unreachable
> port, \
> > +aef0::3 udp port dnsix" | uniq | wc -l)
> > +    test $c -eq 1
> > +])
> > +
> > +rm -f *.pcap
> > +
> > +NS_CHECK_EXEC([sw0-p2-rej], [tcpdump -n -c 1 -i sw0-p2-rej udp port 94
> > sw0-p2-rej-ip6-udp.pcap &], [0])
> > +NS_CHECK_EXEC([sw0-p2-rej], [tcpdump -n -c 1 -i sw0-p2-rej icmp6 >
> sw0-p2-rej-icmp6.pcap &], [0])
> > +
> > +OVS_WAIT_UNTIL([
> > +    ip netns exec sw0-p2-rej nc -u -6 aef0::3 94 < foo
> > +    c=$(cat sw0-p2-rej-icmp6.pcap | grep \
> > +"IP6 aef0::3 > aef0::4: ICMP6, destination unreachable, unreachable
> port, \
> > +aef0::3 udp port objcall" | uniq | wc -l)
> > +    test $c -eq 1
> > +])
> > +
> >  OVS_APP_EXIT_AND_WAIT([ovn-controller])
> >
> >  as ovn-sb
> > --
> > 2.25.1
> >
> > _______________________________________________
> > dev mailing list
> > dev@openvswitch.org
> > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
> >
>
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
>
diff mbox series

Patch

diff --git a/controller/pinctrl.c b/controller/pinctrl.c
index 3230bb386..63796d88c 100644
--- a/controller/pinctrl.c
+++ b/controller/pinctrl.c
@@ -1453,7 +1453,7 @@  static void
 pinctrl_handle_icmp(struct rconn *swconn, const struct flow *ip_flow,
                     struct dp_packet *pkt_in,
                     const struct match *md, struct ofpbuf *userdata,
-                    bool include_orig_ip_datagram)
+                    bool set_icmp_code)
 {
     /* This action only works for IP packets, and the switch should only send
      * us IP packets this way, but check here just to be sure. */
@@ -1500,46 +1500,51 @@  pinctrl_handle_icmp(struct rconn *swconn, const struct flow *ip_flow,
         packet_set_ipv4(&packet, ip_flow->nw_src, ip_flow->nw_dst,
                         ip_flow->nw_tos, 255);
 
+        uint8_t icmp_code =  1;
+        if (set_icmp_code && in_ip->ip_proto == IPPROTO_UDP) {
+            icmp_code = 3;
+        }
+
         struct icmp_header *ih = dp_packet_put_zeros(&packet, sizeof *ih);
         dp_packet_set_l4(&packet, ih);
-        packet_set_icmp(&packet, ICMP4_DST_UNREACH, 1);
-
-        if (include_orig_ip_datagram) {
-            /* RFC 1122: 3.2.2	MUST send at least the IP header and 8 bytes
-             * of header. MAY send more.
-             * RFC says return as much as we can without exceeding 576
-             * bytes.
-             * So, lets return as much as we can. */
-
-            /* Calculate available room to include the original IP + data. */
-            nh = dp_packet_l3(&packet);
-            uint16_t room = 576 - (sizeof *eh + ntohs(nh->ip_tot_len));
-            if (in_ip_len > room) {
-                in_ip_len = room;
-            }
-            dp_packet_put(&packet, in_ip, in_ip_len);
-
-            /* dp_packet_put may reallocate the buffer. Get the l3 and l4
-             * header pointers again. */
-            nh = dp_packet_l3(&packet);
-            ih = dp_packet_l4(&packet);
-            uint16_t ip_total_len = ntohs(nh->ip_tot_len) + in_ip_len;
-            nh->ip_tot_len = htons(ip_total_len);
-            ih->icmp_csum = 0;
-            ih->icmp_csum = csum(ih, sizeof *ih + in_ip_len);
-            nh->ip_csum = 0;
-            nh->ip_csum = csum(nh, sizeof *nh);
-        }
+        packet_set_icmp(&packet, ICMP4_DST_UNREACH, icmp_code);
+
+        /* RFC 1122: 3.2.2	MUST send at least the IP header and 8 bytes
+         * of header. MAY send more.
+         * RFC says return as much as we can without exceeding 576
+         * bytes.
+         * So, lets return as much as we can. */
+
+        /* Calculate available room to include the original IP + data. */
+        nh = dp_packet_l3(&packet);
+        uint16_t room = 576 - (sizeof *eh + ntohs(nh->ip_tot_len));
+        if (in_ip_len > room) {
+            in_ip_len = room;
+        }
+        dp_packet_put(&packet, in_ip, in_ip_len);
+
+        /* dp_packet_put may reallocate the buffer. Get the l3 and l4
+            * header pointers again. */
+        nh = dp_packet_l3(&packet);
+        ih = dp_packet_l4(&packet);
+        uint16_t ip_total_len = ntohs(nh->ip_tot_len) + in_ip_len;
+        nh->ip_tot_len = htons(ip_total_len);
+        ih->icmp_csum = 0;
+        ih->icmp_csum = csum(ih, sizeof *ih + in_ip_len);
+        nh->ip_csum = 0;
+        nh->ip_csum = csum(nh, sizeof *nh);
+
     } else {
         struct ip6_hdr *nh = dp_packet_put_zeros(&packet, sizeof *nh);
         struct icmp6_data_header *ih;
         uint32_t icmpv6_csum;
+        struct ip6_hdr *in_ip = dp_packet_l3(pkt_in);
 
         eh->eth_type = htons(ETH_TYPE_IPV6);
         dp_packet_set_l3(&packet, nh);
         nh->ip6_vfc = 0x60;
         nh->ip6_nxt = IPPROTO_ICMPV6;
-        nh->ip6_plen = htons(sizeof(*nh) + ICMP6_DATA_HEADER_LEN);
+        nh->ip6_plen = htons(ICMP6_DATA_HEADER_LEN);
         packet_set_ipv6(&packet, &ip_flow->ipv6_src, &ip_flow->ipv6_dst,
                         ip_flow->nw_tos, ip_flow->ipv6_label, 255);
 
@@ -1547,15 +1552,42 @@  pinctrl_handle_icmp(struct rconn *swconn, const struct flow *ip_flow,
         dp_packet_set_l4(&packet, ih);
         ih->icmp6_base.icmp6_type = ICMP6_DST_UNREACH;
         ih->icmp6_base.icmp6_code = 1;
+
+        if (set_icmp_code && in_ip->ip6_nxt == IPPROTO_UDP) {
+            ih->icmp6_base.icmp6_code = ICMP6_DST_UNREACH_NOPORT;
+        }
         ih->icmp6_base.icmp6_cksum = 0;
 
-        uint8_t *data = dp_packet_put_zeros(&packet, sizeof *nh);
-        memcpy(data, dp_packet_l3(pkt_in), sizeof(*nh));
+        nh = dp_packet_l3(&packet);
+
+        /* RFC 4443: 3.1.
+         *
+         * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         * |     Type      |     Code      |          Checksum             |
+         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         * |                             Unused                            |
+         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         * |                    As much of invoking packet                 |
+         * +                as possible without the ICMPv6 packet          +
+         * |                exceeding the minimum IPv6 MTU [IPv6]          |
+         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         */
+
+        uint16_t room = 1280 - (sizeof *eh + sizeof *nh +
+                                ICMP6_DATA_HEADER_LEN);
+        uint16_t in_ip_len = (uint16_t) sizeof *in_ip + ntohs(in_ip->ip6_plen);
+        if (in_ip_len > room) {
+            in_ip_len = room;
+        }
+
+        dp_packet_put(&packet, in_ip, in_ip_len);
+        nh->ip6_plen = htons(ICMP6_DATA_HEADER_LEN + in_ip_len);
 
         icmpv6_csum = packet_csum_pseudoheader6(dp_packet_l3(&packet));
         ih->icmp6_base.icmp6_cksum = csum_finish(
             csum_continue(icmpv6_csum, ih,
-                          sizeof(*nh) + ICMP6_DATA_HEADER_LEN));
+                          in_ip_len + ICMP6_DATA_HEADER_LEN));
     }
 
     if (ip_flow->vlans[0].tci & htons(VLAN_CFI)) {
@@ -2646,12 +2678,12 @@  process_packet_in(struct rconn *swconn, const struct ofp_header *msg)
 
     case ACTION_OPCODE_ICMP:
         pinctrl_handle_icmp(swconn, &headers, &packet, &pin.flow_metadata,
-                            &userdata, false);
+                            &userdata, true);
         break;
 
     case ACTION_OPCODE_ICMP4_ERROR:
         pinctrl_handle_icmp(swconn, &headers, &packet, &pin.flow_metadata,
-                            &userdata, true);
+                            &userdata, false);
         break;
 
     case ACTION_OPCODE_TCP_RESET:
diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
index 63753ac61..eb459c8c4 100644
--- a/northd/ovn-northd.c
+++ b/northd/ovn-northd.c
@@ -4724,12 +4724,10 @@  build_pre_acls(struct ovn_datapath *od, struct hmap *lflows)
          * Not to do conntrack on ND and ICMP destination
          * unreachable packets. */
         ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 110,
-                      "nd || nd_rs || nd_ra || icmp4.type == 3 || "
-                      "icmp6.type == 1 || "
+                      "nd || nd_rs || nd_ra || "
                       "(udp && udp.src == 546 && udp.dst == 547)", "next;");
         ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 110,
-                      "nd || nd_rs || nd_ra || icmp4.type == 3 || "
-                      "icmp6.type == 1 || "
+                      "nd || nd_rs || nd_ra || "
                       "(udp && udp.src == 546 && udp.dst == 547)", "next;");
 
         /* Ingress and Egress Pre-ACL Table (Priority 100).
@@ -4841,12 +4839,10 @@  build_pre_lb(struct ovn_datapath *od, struct hmap *lflows,
 {
     /* Do not send ND packets to conntrack */
     ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, 110,
-                  "nd || nd_rs || nd_ra || icmp4.type == 3 ||"
-                  "icmp6.type == 1",
+                  "nd || nd_rs || nd_ra",
                   "next;");
     ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, 110,
-                  "nd || nd_rs || nd_ra || icmp4.type == 3 ||"
-                  "icmp6.type == 1",
+                  "nd || nd_rs || nd_ra",
                   "next;");
 
     /* Do not send service monitor packets to conntrack. */
@@ -5025,9 +5021,10 @@  build_reject_acl_rules(struct ovn_datapath *od, struct hmap *lflows,
         ds_put_format(&actions, "%s ", extra_actions->string);
     }
     ds_put_format(&actions, "reg0 = 0; "
-                  "eth.dst <-> eth.src; ip4.dst <-> ip4.src; "
-                  "icmp4 { outport <-> inport; %s };",
-                  ingress ? "output;" : "next(pipeline=ingress,table=0);");
+                  "icmp4 { eth.dst <-> eth.src; ip4.dst <-> ip4.src; "
+                  "outport <-> inport; %s };",
+                  ingress ? "next(pipeline=egress,table=5);"
+                          : "next(pipeline=ingress,table=19);");
     ovn_lflow_add_with_hint(lflows, od, stage,
                             acl->priority + OVN_ACL_PRI_OFFSET,
                             ds_cstr(&match), ds_cstr(&actions), stage_hint);
@@ -5044,7 +5041,8 @@  build_reject_acl_rules(struct ovn_datapath *od, struct hmap *lflows,
     ds_put_format(&actions, "reg0 = 0; icmp6 { "
                   "eth.dst <-> eth.src; ip6.dst <-> ip6.src; "
                   "outport <-> inport; %s };",
-                  ingress ? "output;" : "next(pipeline=ingress,table=0);");
+                  ingress ? "next(pipeline=egress,table=5);"
+                          : "next(pipeline=ingress,table=19);");
     ovn_lflow_add_with_hint(lflows, od, stage,
                             acl->priority + OVN_ACL_PRI_OFFSET,
                             ds_cstr(&match), ds_cstr(&actions), stage_hint);
diff --git a/tests/ovn.at b/tests/ovn.at
index e6febd4c2..6467bdc42 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -11813,13 +11813,13 @@  test_ip_packet() {
 
     local ip_ttl=ff
     local packet=${eth_dst}${eth_src}08004500001400004000${ip_ttl}01${ip_chksum}${ipv4_src}${ipv4_dst}
-
+    local orig_pkt_in_reply=4500001400004000${ip_ttl}01${ip_chksum}${ipv4_src}${ipv4_dst}
     local reply_icmp_ttl=ff
     local icmp_type_code_response=0301
     local icmp_data=00000000
     local reply_icmp_payload=${icmp_type_code_response}${exp_icmp_chksum}${icmp_data}
-    local reply=${eth_src}${eth_dst}08004500001c00004000${reply_icmp_ttl}01${exp_ip_chksum}${ipv4_dst}${ipv4_src}${reply_icmp_payload}
-    echo $reply >> vif$inport.expected
+    local reply=${eth_src}${eth_dst}08004500003000004000${reply_icmp_ttl}01${exp_ip_chksum}${ipv4_dst}${ipv4_src}${reply_icmp_payload}
+    echo $reply$orig_pkt_in_reply >> vif$inport.expected
 
     as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet
 }
@@ -11836,7 +11836,7 @@  test_ipv6_packet() {
     local ip6_hdr=6000000000083aff${ipv6_src}${ipv6_dst}
     local packet=${eth_dst}${eth_src}86dd${ip6_hdr}0000000000000000
 
-    local reply=${eth_src}${eth_dst}86dd6000000000303aff${ipv6_dst}${ipv6_src}0101${exp_icmp_chksum}00000000${ip6_hdr}
+    local reply=${eth_src}${eth_dst}86dd6000000000383aff${ipv6_dst}${ipv6_src}0101${exp_icmp_chksum}00000000${ip6_hdr}0000000000000000
     echo $reply >> vif$inport.expected
 
     as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet
@@ -11914,11 +11914,11 @@  ovn-nbctl --log acl-add sw0 from-lport 1000 "inport == \"sw0-p21\"" reject
 # Allow some time for ovn-northd and ovn-controller to catch up.
 ovn-nbctl --timeout=3 --wait=hv sync
 
-test_ip_packet 11 1 000000000011 000000000021 $(ip_to_hex 192 168 1 11) $(ip_to_hex 192 168 1 21) 0000 7d8d fcfe
-test_ip_packet 21 2 000000000021 000000000011 $(ip_to_hex 192 168 1 21) $(ip_to_hex 192 168 1 11) 0000 7d8d fcfe
-test_ip_packet 31 3 000000000031 000000000012 $(ip_to_hex 192 168 1 31) $(ip_to_hex 192 168 1 12) 0000 7d82 fcfe
+test_ip_packet 11 1 000000000011 000000000021 $(ip_to_hex 192 168 1 11) $(ip_to_hex 192 168 1 21) 0000 f85b f576
+test_ip_packet 21 2 000000000021 000000000011 $(ip_to_hex 192 168 1 21) $(ip_to_hex 192 168 1 11) 0000 f85b f576
+test_ip_packet 31 3 000000000031 000000000012 $(ip_to_hex 192 168 1 31) $(ip_to_hex 192 168 1 12) 0000 f850 f56b
 
-test_ipv6_packet 11 1 000000000011 000000000021 fe80000000000000020001fffe000001 fe80000000000000020001fffe000002 6183
+test_ipv6_packet 11 1 000000000011 000000000021 fe80000000000000020001fffe000001 fe80000000000000020001fffe000002 617b
 
 test_tcp_syn_packet 11 1 000000000011 000000000021 $(ip_to_hex 192 168 1 11) $(ip_to_hex 192 168 1 21) 0000 8b40 3039 0000 b85f 70e4
 test_tcp_syn_packet 21 2 000000000021 000000000011 $(ip_to_hex 192 168 1 21) $(ip_to_hex 192 168 1 11) 0000 8b40 3039 0000 b85f 70e4
@@ -12871,13 +12871,13 @@  test_ip_packet() {
 
     local ip_ttl=01
     local packet=${eth_dst}${eth_src}08004500001400004000${ip_ttl}01${ip_chksum}${ipv4_src}${ipv4_dst}
-
+    local orig_pkt_in_reply=4500001400004000${ip_ttl}01${ip_chksum}${ipv4_src}${ipv4_dst}
     local reply_icmp_ttl=fe
     local icmp_type_code_response=0b00
     local icmp_data=00000000
     local reply_icmp_payload=${icmp_type_code_response}${exp_icmp_chksum}${icmp_data}
-    local reply=${eth_src}${eth_dst}08004500001c00004000${reply_icmp_ttl}01${exp_ip_chksum}${ip_router}${ipv4_src}${reply_icmp_payload}
-    echo $reply >> vif$inport.expected
+    local reply=${eth_src}${eth_dst}08004500003000004000${reply_icmp_ttl}01${exp_ip_chksum}${ip_router}${ipv4_src}${reply_icmp_payload}
+    echo $reply$orig_pkt_in_reply >> vif$inport.expected
 
     as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet
 }
@@ -12895,7 +12895,7 @@  test_ip6_packet() {
     local ip6_hdr=6000000000151101${ipv6_src}${ipv6_dst}
     local packet=${eth_dst}${eth_src}86dd${ip6_hdr}dbb8303900155bac6b646f65206676676e6d66720a
 
-    local reply=${eth_src}${eth_dst}86dd6000000000303afe${ipv6_router}${ipv6_src}0300${exp_icmp_chksum}00000000${ip6_hdr}
+    local reply=${eth_src}${eth_dst}86dd6000000000453afe${ipv6_router}${ipv6_src}0300${exp_icmp_chksum}00000000${ip6_hdr}dbb8303900155bac6b646f65206676676e6d66720a
     echo $reply >> vif$inport.expected
 
     as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet
@@ -12937,8 +12937,8 @@  OVN_POPULATE_ARP
 # allow some time for ovn-northd and ovn-controller to catch up.
 ovn-nbctl --wait=hv sync
 
-test_ip_packet 1 1 000000000001 00000000ff01 $(ip_to_hex 192 168 1 1) $(ip_to_hex 192 168 2 1) $(ip_to_hex 192 168 1 254) 0000 7dae f4ff
-test_ip6_packet 1 1 000000000001 00000000ff01 20010db8000100000000000000000011 20010db8000200000000000000000011 20010db8000100000000000000000001 d461
+test_ip_packet 1 1 000000000001 00000000ff01 $(ip_to_hex 192 168 1 1) $(ip_to_hex 192 168 2 1) $(ip_to_hex 192 168 1 254) 0000 f87c ea96
+test_ip6_packet 1 1 000000000001 00000000ff01 20010db8000100000000000000000011 20010db8000200000000000000000011 20010db8000100000000000000000001 1c22
 OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [vif1.expected])
 
 OVN_CLEANUP([hv1], [hv2])
@@ -12967,12 +12967,12 @@  test_ip_packet() {
 
     local ip_ttl=ff
     local packet=${eth_dst}${eth_src}08004500001400004000${ip_ttl}${l4_proto}${ip_chksum}${ipv4_src}${ip_router}
-
+    local orig_pkt_in_reply=4500001400004000${ip_ttl}${l4_proto}${ip_chksum}${ipv4_src}${ip_router}
     local reply_icmp_ttl=fe
     local icmp_data=00000000
     local reply_icmp_payload=${exp_icmp_code}${exp_icmp_chksum}${icmp_data}
-    local reply=${eth_src}${eth_dst}08004500001c00004000${reply_icmp_ttl}01${exp_ip_chksum}${ip_router}${ipv4_src}${reply_icmp_payload}
-    echo $reply >> vif$inport.expected
+    local reply=${eth_src}${eth_dst}08004500003000004000${reply_icmp_ttl}01${exp_ip_chksum}${ip_router}${ipv4_src}${reply_icmp_payload}
+    echo $reply$orig_pkt_in_reply >> vif$inport.expected
 
     as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet
 }
@@ -13038,7 +13038,9 @@  test_ip6_packet() {
     local ip6_hdr=60000000${ipv6_len}${ipv6_proto}ff${ipv6_src}${ipv6_dst}
     local packet=${eth_dst}${eth_src}86dd${ip6_hdr}${data}
 
-    local reply=${eth_src}${eth_dst}86dd6000000000303afe${ipv6_dst}${ipv6_src}${exp_icmp_code}${exp_icmp_chksum}00000000${ip6_hdr}
+    local reply_ip_len=`expr 48 + ${#data} / 2`
+    reply_ip_len=$(printf "%x" $reply_ip_len)
+    local reply=${eth_src}${eth_dst}86dd6000000000${reply_ip_len}3afe${ipv6_dst}${ipv6_src}${exp_icmp_code}${exp_icmp_chksum}00000000${ip6_hdr}${data}
     echo $reply >> vif$inport.expected
 
     as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet
@@ -13080,13 +13082,13 @@  OVN_POPULATE_ARP
 # allow some time for ovn-northd and ovn-controller to catch up.
 ovn-nbctl --wait=hv sync
 
-test_ip_packet 1 1 000000000001 00000000ff01 $(ip_to_hex 192 168 1 1) $(ip_to_hex 192 168 1 254) 11 0000 7dae fcfc 0303
-test_ip_packet 1 1 000000000001 00000000ff01 $(ip_to_hex 192 168 1 1) $(ip_to_hex 192 168 1 254) 84 0000 7dae fcfd 0302
-test_ip6_packet 1 1 000000000001 00000000ff01 20010db8000100000000000000000011 20010db8000100000000000000000001 11 0015 dbb8303900155bac6b646f65206676676e6d66720a 0104 d570
+test_ip_packet 1 1 000000000001 00000000ff01 $(ip_to_hex 192 168 1 1) $(ip_to_hex 192 168 1 254) 11 0000 f87c f485 0303
+test_ip_packet 1 1 000000000001 00000000ff01 $(ip_to_hex 192 168 1 1) $(ip_to_hex 192 168 1 254) 84 0000 f87c f413 0302
+test_ip6_packet 1 1 000000000001 00000000ff01 20010db8000100000000000000000011 20010db8000100000000000000000001 11 0015 dbb8303900155bac6b646f65206676676e6d66720a 0104 1d31
 OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [vif1.expected])
 
 test_tcp_syn_packet 2 2 000000000002 00000000ff02 $(ip_to_hex 192 168 2 1) $(ip_to_hex 192 168 2 254) 0000 8b40 3039 0000 b680 6e05
-test_ip6_packet 2 2 000000000002 00000000ff02 20010db8000200000000000000000011 20010db8000200000000000000000001 84 0004 01020304 0103 627e
+test_ip6_packet 2 2 000000000002 00000000ff02 20010db8000200000000000000000011 20010db8000200000000000000000001 84 0004 01020304 0103 5e74
 test_tcp6_packet 2 2 000000000002 00000000ff02 20010db8000200000000000000000011 20010db8000200000000000000000001 8b40 3039 0000 98cd
 OVN_CHECK_PACKETS([hv2/vif2-tx.pcap], [vif2.expected])
 
diff --git a/tests/system-ovn.at b/tests/system-ovn.at
index fa3b83cb1..117f1e835 100644
--- a/tests/system-ovn.at
+++ b/tests/system-ovn.at
@@ -3697,7 +3697,7 @@  OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
 AT_CLEANUP
 
 
-AT_SETUP([ovn -- ACL reject - TCP reset])
+AT_SETUP([ovn -- ACL reject])
 AT_SKIP_IF([test $HAVE_NC = no])
 AT_KEYWORDS([lb])
 
@@ -3736,13 +3736,14 @@  ovn-nbctl acl-add pg0_drop from-lport 1001 "inport == @pg0_drop && ip" drop
 ovn-nbctl acl-add pg0_drop to-lport 1001 "outport == @pg0_drop && ip" drop
 
 ovn-nbctl pg-add pg0 sw0-p1-rej sw0-p2-rej
-ovn-nbctl acl-add pg0 from-lport 1002 "inport == @pg0 && ip4" allow-related
+ovn-nbctl acl-add pg0 from-lport 1002 "inport == @pg0 && ip" allow-related
 ovn-nbctl --log acl-add pg0 from-lport 1004 "inport == @pg0 && ip && tcp && tcp.dst == 80" reject
+ovn-nbctl --log acl-add pg0 from-lport 1004 "inport == @pg0 && ip && udp && udp.dst == 90" reject
 
-ovn-nbctl acl-add pg0 to-lport 1002 "outport == @pg0 && ip4 && ip4.src == 0.0.0.0/0 && icmp4" allow-related
 ovn-nbctl acl-add pg0 to-lport 1002 "outport == @pg0 && ip4 && ip4.src == 0.0.0.0/0 && tcp && tcp.dst == 82" allow-related
 ovn-nbctl acl-add pg0 to-lport 1002 "outport == @pg0 && ip4 && ip4.src == 0.0.0.0/0 && udp && udp.dst == 82" allow-related
 ovn-nbctl --log acl-add pg0 to-lport 1004 "inport == @pg0 && ip && tcp && tcp.dst == 84" reject
+ovn-nbctl --log acl-add pg0 to-lport 1004 "inport == @pg0 && ip && udp && udp.dst == 94" reject
 
 OVN_POPULATE_ARP
 ovn-nbctl --wait=hv sync
@@ -3758,33 +3759,38 @@  ADD_VETH(sw0-p2-rej, sw0-p2-rej, br-int, "10.0.0.4/24", "50:54:00:00:00:04", \
 NS_CHECK_EXEC([sw0-p1-rej], [ip a a aef0::3/64 dev sw0-p1-rej], [0])
 NS_CHECK_EXEC([sw0-p2-rej], [ip a a aef0::4/64 dev sw0-p2-rej], [0])
 
-# Capture packets in sw0-p1-rej.
-NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -n -c 2 -i sw0-p1-rej tcp port 80 > sw0-p1-rej-ip4.pcap &], [0])
 sleep 1
 
-NS_CHECK_EXEC([sw0-p1-rej], [nc 10.0.0.4 80], [1], [],
-[dnl
-Ncat: Connection refused.
-])
+# Capture packets in sw0-p1-rej.
+NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -n -c 4 -i sw0-p1-rej tcp > sw0-p1-rej-ip4.pcap &], [0])
+
+sleep 1
 
 OVS_WAIT_UNTIL([
-    total=`cat sw0-p1-rej-ip4.pcap |  wc -l`
-    echo "total = $total"
-    test "${total}" = "2"
+    ip netns exec sw0-p1-rej nc  10.0.0.4 80 2> r
+    res=$(cat r)
+    test "$res" = "Ncat: Connection refused."
 ])
 
 # Now send traffic to port 84
-NS_CHECK_EXEC([sw0-p1-rej], [nc 10.0.0.4 84], [1], [],
-[dnl
-Ncat: Connection refused.
+OVS_WAIT_UNTIL([
+    ip netns exec sw0-p1-rej nc  10.0.0.4 84 2> r
+    res=$(cat r)
+    test "$res" = "Ncat: Connection refused."
 ])
 
-AT_CHECK([
+OVS_WAIT_UNTIL([
     n_pkt=$(ovs-ofctl dump-flows br-int table=44 | grep -v n_packets=0 | \
 grep controller | grep tp_dst=84 -c)
     test $n_pkt -eq 1
 ])
 
+OVS_WAIT_UNTIL([
+    total=`cat sw0-p1-rej-ip4.pcap |  wc -l`
+    echo "total = $total"
+    test "${total}" = "4"
+])
+
 # Without this sleep, test case fails intermittently.
 sleep 3
 
@@ -3792,17 +3798,68 @@  NS_CHECK_EXEC([sw0-p2-rej], [tcpdump -n -c 2 -i sw0-p2-rej tcp port 80 > sw0-p2-
 
 sleep 1
 
-NS_CHECK_EXEC([sw0-p2-rej], [nc -6 aef0::3 80], [1], [],
-[dnl
-Ncat: Connection refused.
+OVS_WAIT_UNTIL([
+    ip netns exec sw0-p2-rej nc -6 aef0::3 80 2> r
+    res=$(cat r)
+    test "$res" = "Ncat: Connection refused."
 ])
 
+
 OVS_WAIT_UNTIL([
     total=`cat sw0-p2-rej-ip6.pcap |  wc -l`
     echo "total = $total"
     test "${total}" = "2"
 ])
 
+# Now test for IPv4 UDP.
+NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -n -c 1 -i sw0-p1-rej udp port 90 > sw0-p1-rej-udp.pcap &], [0])
+NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -n -c 1 -i sw0-p1-rej icmp > sw0-p1-rej-icmp.pcap &], [0])
+
+echo "foo" > foo
+OVS_WAIT_UNTIL([
+    ip netns exec sw0-p1-rej nc -u 10.0.0.4 90 < foo
+    c=$(cat sw0-p1-rej-icmp.pcap | grep \
+"10.0.0.4 > 10.0.0.3: ICMP 10.0.0.4 udp port dnsix unreachable" | uniq | wc -l)
+    test $c -eq 1
+])
+
+rm -f *.pcap
+
+NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -n -c 1 -i sw0-p1-rej udp port 94 > sw0-p1-rej-udp.pcap &], [0])
+NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -n -c 1 -i sw0-p1-rej icmp > sw0-p1-rej-icmp.pcap &], [0])
+
+OVS_WAIT_UNTIL([
+    ip netns exec sw0-p1-rej nc -u 10.0.0.4 94 < foo
+    c=$(cat sw0-p1-rej-icmp.pcap | grep \
+"10.0.0.4 > 10.0.0.3: ICMP 10.0.0.4 udp port objcall unreachable" | uniq | wc -l)
+    test $c -eq 1
+])
+
+# Now test for IPv6 UDP.
+NS_CHECK_EXEC([sw0-p2-rej], [tcpdump -n -c 1 -i sw0-p2-rej udp port 90 > sw0-p2-rej-ip6-udp.pcap &], [0])
+NS_CHECK_EXEC([sw0-p2-rej], [tcpdump -n -c 1 -i sw0-p2-rej icmp6 > sw0-p2-rej-icmp6.pcap &], [0])
+
+OVS_WAIT_UNTIL([
+    ip netns exec sw0-p2-rej nc -u -6 aef0::3 90 < foo
+    c=$(cat sw0-p2-rej-icmp6.pcap | grep \
+"IP6 aef0::3 > aef0::4: ICMP6, destination unreachable, unreachable port, \
+aef0::3 udp port dnsix" | uniq | wc -l)
+    test $c -eq 1
+])
+
+rm -f *.pcap
+
+NS_CHECK_EXEC([sw0-p2-rej], [tcpdump -n -c 1 -i sw0-p2-rej udp port 94 > sw0-p2-rej-ip6-udp.pcap &], [0])
+NS_CHECK_EXEC([sw0-p2-rej], [tcpdump -n -c 1 -i sw0-p2-rej icmp6 > sw0-p2-rej-icmp6.pcap &], [0])
+
+OVS_WAIT_UNTIL([
+    ip netns exec sw0-p2-rej nc -u -6 aef0::3 94 < foo
+    c=$(cat sw0-p2-rej-icmp6.pcap | grep \
+"IP6 aef0::3 > aef0::4: ICMP6, destination unreachable, unreachable port, \
+aef0::3 udp port objcall" | uniq | wc -l)
+    test $c -eq 1
+])
+
 OVS_APP_EXIT_AND_WAIT([ovn-controller])
 
 as ovn-sb