Skip to content

Commit

Permalink
ovn-controller: Avoid infinite replying for TCP/ICMP connection reset…
Browse files Browse the repository at this point in the history
… messages

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: 64f8c9e ("actions: Add a new OVN action - reject {}.")
Signed-off-by: Mohammad Heib <mheib@redhat.com>
Signed-off-by: Numan Siddique <numans@ovn.org>
  • Loading branch information
mohammadheib authored and numansiddique committed Nov 30, 2021
1 parent 58ed501 commit bcd9a8f
Show file tree
Hide file tree
Showing 2 changed files with 142 additions and 0 deletions.
29 changes: 29 additions & 0 deletions controller/pinctrl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
113 changes: 113 additions & 0 deletions tests/ovn.at
Original file line number Diff line number Diff line change
Expand Up @@ -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])
Expand Down

0 comments on commit bcd9a8f

Please sign in to comment.