diff --git a/doc/admin-guide/files/records.yaml.en.rst b/doc/admin-guide/files/records.yaml.en.rst index 359bceaadd1..0c7becd2828 100644 --- a/doc/admin-guide/files/records.yaml.en.rst +++ b/doc/admin-guide/files/records.yaml.en.rst @@ -4837,6 +4837,14 @@ removed in the future without prior notice. UDP Configuration ===================== +.. ts:cv:: CONFIG proxy.config.udp.poll_timeout INT 100 + :units: milliseconds + + This is the timeout for listening UDP connections to ``epoll_wait()`` on + Linux platforms, and to ``kevent()`` on BSD type OSs. The default value is + 100. See :ts:cv:`proxy.config.net.poll_timeout` for general information on + poll_timeout. + .. ts:cv:: CONFIG proxy.config.udp.threads INT 0 Specifies the number of UDP threads to run. By default 0 threads are dedicated to UDP, diff --git a/iocore/net/UnixUDPNet.cc b/iocore/net/UnixUDPNet.cc index 26c95743926..429beae24de 100644 --- a/iocore/net/UnixUDPNet.cc +++ b/iocore/net/UnixUDPNet.cc @@ -144,6 +144,7 @@ UDPPacket::free() UDPNetProcessorInternal udpNetInternal; UDPNetProcessor &udpNet = udpNetInternal; +int g_udp_pollTimeout; int32_t g_udp_periodicCleanupSlots; int32_t g_udp_periodicFreeCancelledPkts; int32_t g_udp_numSendRetries; @@ -172,9 +173,10 @@ initialize_thread_for_udp_net(EThread *thread) PollCont *upc = get_UDPPollCont(thread); PollDescriptor *upd = upc->pollDescriptor; - // due to ET_UDP is really simple, it should sleep for a long time - // TODO: fixed size - upc->poll_timeout = 100; + + REC_ReadConfigInteger(g_udp_pollTimeout, "proxy.config.udp.poll_timeout"); + upc->poll_timeout = g_udp_pollTimeout; + // This variable controls how often we cleanup the cancelled packets. // If it is set to 0, then cleanup never occurs. REC_ReadConfigInt32(g_udp_periodicFreeCancelledPkts, "proxy.config.udp.free_cancelled_pkts_sec"); diff --git a/src/records/RecordsConfig.cc b/src/records/RecordsConfig.cc index 18ff2c58189..c01d2a9b765 100644 --- a/src/records/RecordsConfig.cc +++ b/src/records/RecordsConfig.cc @@ -254,6 +254,8 @@ static const RecordElement RecordsConfig[] = , {RECT_CONFIG, "proxy.config.udp.send_retries", RECD_INT, "0", RECU_NULL, RR_NULL, RECC_NULL, nullptr, RECA_NULL} , + {RECT_CONFIG, "proxy.config.udp.poll_timeout", RECD_INT, "100", RECU_RESTART_TS, RR_NULL, RECC_NULL, nullptr, RECA_NULL} + , {RECT_CONFIG, "proxy.config.udp.threads", RECD_INT, "0", RECU_RESTART_TS, RR_NULL, RECC_NULL, nullptr, RECA_NULL} , {RECT_CONFIG, "proxy.config.udp.enable_gso", RECD_INT, "1", RECU_NULL, RR_NULL, RECC_NULL, nullptr, RECA_NULL} diff --git a/tests/gold_tests/timeout/quic_poll_timeout.test.py b/tests/gold_tests/timeout/quic_poll_timeout.test.py new file mode 100644 index 00000000000..04ea8b7510c --- /dev/null +++ b/tests/gold_tests/timeout/quic_poll_timeout.test.py @@ -0,0 +1,83 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Optional + +Test.Summary = 'Checks ts.proxy.config.udp.poll_timeout' + +Test.SkipUnless( + Condition.HasATSFeature('TS_HAS_QUICHE') +) + + +class TestPollTimeout: + """Configure a test for poll_timeout.""" + + ts_counter: int = 0 + + def __init__(self, name: str, udp_poll_timeout_in: Optional[int] = None) -> None: + """Initialize the test. + + :param name: The name of the test. + :param udp_poll_timeout_in: Configuration value for proxy.config.udp.poll_timeout + """ + self.name = name + self.udp_poll_timeout_in = udp_poll_timeout_in + self.expected_udp_poll_timeout = 100 + if udp_poll_timeout_in is not None: + self.expected_udp_poll_timeout = udp_poll_timeout_in + + def _configure_traffic_server(self, tr: 'TestRun'): + """Configure Traffic Server. + + :param tr: The TestRun object to associate the ts process with. + """ + ts = tr.MakeATSProcess(f"ts-{TestPollTimeout.ts_counter}", enable_quic=True, enable_tls=True) + + TestPollTimeout.ts_counter += 1 + self._ts = ts + self._ts.Disk.records_config.update({ + 'proxy.config.diags.debug.enabled': 1, + 'proxy.config.diags.debug.tags': 'net|v_quic|quic|socket|inactivity_cop|v_iocore_net_poll', + }) + + if self.udp_poll_timeout_in is not None: + self._ts.Disk.records_config.update({ + 'proxy.config.udp.poll_timeout': self.udp_poll_timeout_in + }) + + def run(self): + """Run the test.""" + tr = Test.AddTestRun(self.name) + self._configure_traffic_server(tr) + + tr.Processes.Default.Command = "echo 'testing ts.proxy.config.udp.poll_timeout'" + tr.Processes.Default.StartBefore(self._ts) + + self._ts.Disk.traffic_out.Content += Testers.IncludesExpression( + f"ET_UDP.*timeout: {self.expected_udp_poll_timeout},", "Verify UDP poll timeout.") + +# Tests start. + + +test0 = TestPollTimeout( + "Test ts.proxy.config.udp.poll_timeout with default value.") +test0.run() + +test1 = TestPollTimeout( + "Test ts.proxy.config.udp.poll_timeout with value of 10.", + udp_poll_timeout_in=10) +test1.run()