[ovs-dev] [PATCH ovn v4] ovn-controller: Avoid infinite replying for TCP/ICMP connection reset messages

Numan Siddique numans at ovn.org
Tue Nov 30 15:32:39 UTC 2021


On Tue, Nov 30, 2021 at 4:23 AM Mohammad Heib <mheib at redhat.com> wrote:
>
> When the ovn controller receives an ip packet that targets a lport that has ACL
> rule to reject ip packets, the controller will reply with TCP_RST or icmp4/6 unreachable packet
> to notify the sender that the destination is not available.
>
> In turn, the receiver host will receive the notification packet and handle it as a normal IP packet
> and if the receiver host is part of the same logical-switch/port-group or has IP reject ACL rule
> it will send TCP_RST or icmp4/6 unreachable packet replying to the TCP_RST or icmp4/6 unreachable
> packet we received and here we will enter to an infinity loop of replying about replying which
> will consume high CPU.
>
> To avoid such scenarios this patch proposes to drop/ignore TCP_RST or icmp4/6 unreachable packets
> that received on lport that has  IP reject ACL rules.
>
> Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=1934011
> Fixes: 64f8c9e9f ("actions: Add a new OVN action - reject {}.")
> Signed-off-by: Mohammad Heib <mheib at redhat.com>

Thanks.  I applied this patch to the main branch and I'm running some
tests to backport to other branches.

Numan

> ---
>  controller/pinctrl.c |  29 +++++++++++
>  tests/ovn.at         | 113 +++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 142 insertions(+)
>
> diff --git a/controller/pinctrl.c b/controller/pinctrl.c
> index ae5320e09..0d443c150 100644
> --- a/controller/pinctrl.c
> +++ b/controller/pinctrl.c
> @@ -1933,11 +1933,40 @@ pinctrl_handle_sctp_abort(struct rconn *swconn, const struct flow *ip_flow,
>      dp_packet_uninit(&packet);
>  }
>
> +static bool
> +pinctrl_handle_reject_ignore_pkt(const struct flow *ip_flow,
> +                                 struct dp_packet *pkt_in)
> +{
> +    if (ip_flow->nw_proto == IPPROTO_TCP) {
> +        struct tcp_header *th = dp_packet_l4(pkt_in);
> +        if (!th || (TCP_FLAGS(th->tcp_ctl) & TCP_RST)) {
> +            return true;
> +        }
> +    } else {
> +        if (is_icmpv4(ip_flow, NULL)) {
> +            struct icmp_header *ih = dp_packet_l4(pkt_in);
> +            if (!ih || (ih->icmp_type == ICMP4_DST_UNREACH)) {
> +                return true;
> +            }
> +        } else if (is_icmpv6(ip_flow, NULL)) {
> +            struct icmp6_data_header *ih = dp_packet_l4(pkt_in);
> +            if (!ih || (ih->icmp6_base.icmp6_type == ICMP6_DST_UNREACH)) {
> +                return true;
> +            }
> +        }
> +    }
> +    return false;
> +}
> +
>  static void
>  pinctrl_handle_reject(struct rconn *swconn, const struct flow *ip_flow,
>                        struct dp_packet *pkt_in,
>                        const struct match *md, struct ofpbuf *userdata)
>  {
> +    if (pinctrl_handle_reject_ignore_pkt(ip_flow, pkt_in)) {
> +        return;
> +    }
> +
>      if (ip_flow->nw_proto == IPPROTO_TCP) {
>          pinctrl_handle_tcp_reset(swconn, ip_flow, pkt_in, md, userdata, true);
>      } else if (ip_flow->nw_proto == IPPROTO_SCTP) {
> diff --git a/tests/ovn.at b/tests/ovn.at
> index 7a7ae0da6..a4ed03041 100644
> --- a/tests/ovn.at
> +++ b/tests/ovn.at
> @@ -14223,6 +14223,119 @@ OVN_CLEANUP([hv1], [hv2], [hv3])
>  AT_CLEANUP
>  ])
>
> +OVN_FOR_EACH_NORTHD([
> +AT_SETUP([ACL Reject ping pong])
> +AT_KEYWORDS([ACL Reject ping pong])
> +ovn_start
> +
> +send_icmp6_packet() {
> +    local inport=$1 hv=$2 eth_src=$3 eth_dst=$4 ipv6_src=$5 ipv6_dst=$6
> +
> +    local ip6_hdr=6000000000083aff${ipv6_src}${ipv6_dst}
> +    local packet=${eth_dst}${eth_src}86dd${ip6_hdr}8000dcb662f00001
> +
> +    as hv$hv ovs-appctl netdev-dummy/receive hv${hv}-vif$inport $packet
> +}
> +
> +send_icmp_packet() {
> +    local inport=$1 hv=$2 eth_src=$3 eth_dst=$4 ipv4_src=$5 ipv4_dst=$6 ip_chksum=$7 data=$8
> +    shift 8
> +
> +    local ip_ttl=ff
> +    local ip_len=001c
> +    local packet=${eth_dst}${eth_src}08004500${ip_len}00004000${ip_ttl}01${ip_chksum}${ipv4_src}${ipv4_dst}${data}
> +    as hv$hv ovs-appctl netdev-dummy/receive hv${hv}-vif$inport $packet
> +}
> +
> +net_add n1
> +
> +sim_add hv1
> +as hv1
> +ovs-vsctl add-br br-phys
> +ovn_attach n1 br-phys 192.168.0.1
> +ovs-vsctl -- add-port br-int hv1-vif1 -- \
> +    set interface hv1-vif1 external-ids:iface-id=sw0-p1 \
> +    options:tx_pcap=hv1/vif1-tx.pcap \
> +    options:rxq_pcap=hv1/vif1-rx.pcap \
> +    ofport-request=1
> +
> +sim_add hv2
> +as hv2
> +ovs-vsctl add-br br-phys
> +ovn_attach n1 br-phys 192.168.0.2
> +ovs-vsctl -- add-port br-int hv2-vif1 -- \
> +    set interface hv2-vif1 external-ids:iface-id=sw0-p2 \
> +    options:tx_pcap=hv2/vif1-tx.pcap \
> +    options:rxq_pcap=hv2/vif1-rx.pcap \
> +    ofport-request=1
> +
> +ovn-nbctl ls-add sw0
> +
> +check ovn-nbctl lsp-add sw0 sw0-p1
> +check ovn-nbctl lsp-set-addresses sw0-p1 "50:54:00:00:00:03 10.0.0.3 1000::3"
> +check ovn-nbctl lsp-set-port-security sw0-p1 "50:54:00:00:00:03 10.0.0.3 1000::3"
> +
> +check ovn-nbctl lsp-add sw0 sw0-p2
> +check ovn-nbctl lsp-set-addresses sw0-p2 "50:54:00:00:00:04 10.0.0.4 1000::4"
> +check ovn-nbctl lsp-set-port-security sw0-p2 "50:54:00:00:00:04 10.0.0.4 1000::4"
> +
> +check ovn-nbctl acl-add sw0 to-lport 1002 ip reject
> +
> +OVN_POPULATE_ARP
> +
> +wait_for_ports_up
> +ovn-nbctl --wait=hv sync
> +
> +ovn-sbctl dump-flows sw0 > sw0-flows
> +AT_CAPTURE_FILE([sw0-flows])
> +
> +AT_CHECK([grep -E 'ls_(in|out)_acl' sw0-flows |grep reject| sed 's/table=../table=??/' | sort], [0], [dnl
> +  table=??(ls_out_acl         ), priority=2002 , match=(ip), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=22); };)
> +])
> +
> +
> +eth_src=505400000003
> +eth_dst=505400000004
> +ip_src=$(ip_to_hex 10 0 0 3)
> +ip_dst=$(ip_to_hex 10 0 0 4)
> +ipv6_src=10000000000000000000000000000003
> +ipv6_dst=10000000000000000000000000000004
> +
> +send_icmp_packet 1 1 $eth_src $eth_dst $ip_src $ip_dst c4c9 0000000000000000000000
> +send_icmp6_packet 1 1 $eth_src $eth_dst $ipv6_src $ipv6_dst
> +sleep 2
> +
> +# Get total number of ipv4 packets that received on ovs
> +
> +# sender side
> +flow=$(as hv1 ovs-ofctl dump-flows br-int table=44 | grep priority=2002|grep ip,metadata=0x1)
> +n_pkts="$(echo $flow|awk -F',' '{ print $4 }'|awk -F'=' '{ print $2 }')"
> +check test $n_pkts -eq 1
> +
> +# receiver side
> +flow=$(as hv2 ovs-ofctl dump-flows br-int table=44 | grep priority=2002|grep ip,metadata=0x1)
> +n_pkts="$(echo $flow|awk -F',' '{ print $4 }'|awk -F'=' '{ print $2 }')"
> +check test $n_pkts -eq 1
> +
> +# Get total number of ipv6 packets that received on ovs
> +
> +# sender side
> +flow=$(as hv1 ovs-ofctl dump-flows br-int table=44 | grep priority=2002|grep ipv6,metadata=0x1)
> +n_pkts="$(echo $flow|awk -F',' '{ print $4 }'|awk -F'=' '{ print $2 }')"
> +check test $n_pkts -eq 1
> +
> +
> +# receiver side
> +flow=$(as hv2 ovs-ofctl dump-flows br-int table=44 | grep priority=2002|grep ipv6,metadata=0x1)
> +n_pkts="$(echo $flow|awk -F',' '{ print $4 }'|awk -F'=' '{ print $2 }')"
> +check test $n_pkts -eq 1
> +
> +
> +OVN_CLEANUP([hv1], [hv2])
> +AT_CLEANUP
> +])
> +
> +
>  OVN_FOR_EACH_NORTHD([
>  AT_SETUP([Port Groups])
>  AT_KEYWORDS([ovnpg])
> --
> 2.26.3
>
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>


More information about the dev mailing list