The tc gate action opens and closes a gate on a schedule, so only frames in the right time slot get through. This guide builds one ingress filter that opens for one slot, closes for the next, and repeats that cycle, plus a byte limit for the open slot. It uses the locally installed tc from iproute2 6.1.0.
Allow about fifteen minutes, plus time to choose a safe test interface and traffic match. You need iproute2, a network interface that can carry the filter, and elevated privileges for changes; the read-only checks do not normally need root.
Checkpoint: this guide changes ingress handling. A mistake can drop packets before they reach the host. Test on a disposable interface or during a maintenance window, and keep a console or an out-of-band route available.
Confirm the binary and package version before copying a schedule. This is an ordinary, read-only check:
$ command -v tc
/usr/sbin/tc
$ tc -V
tc utility, iproute2-6.1.0, libbpf 1.3.0
$ dpkg-query -W -f='${Package} ${Version}\n' iproute2
iproute2 6.1.0-1ubuntu6.4
The installed manpage calls this the gate action, but the action lives inside a tc filter. A filter selects frames first; the gate then decides whether a selected frame gets through in the current schedule slot.
Replace IFACE with the interface you intend to test. These commands only display state:
$ IFACE='eth0'
$ tc qdisc show dev "$IFACE"
$ tc filter show dev "$IFACE" ingress
Look for an existing ingress qdisc and filters. Do not assume an empty-looking result means the interface is unused: another tool or network manager may install configuration later.
If the interface has no ingress qdisc, the example below adds one. If one already exists, do not run the add command blindly; reuse the existing ingress qdisc and record the filter index you choose so you can remove exactly your own rule.
Run this as root, or through your normal privilege tool:
# tc qdisc add dev eth0 ingress
Verify the qdisc before adding a filter:
# tc qdisc show dev eth0
qdisc ingress ffff: dev eth0 parent ffff:fff1
The exact line can include more fields. What matters is the ingress qdisc and the ffff: handle used as the filter parent. If the add reports that the qdisc already exists, stop and inspect the current configuration instead of deleting it.
This example matches IPv4 frames from one source address. It opens the gate for 200,000,000 nanoseconds, allows up to 8,000,000 octets in that slot, then closes it for 100,000,000 nanoseconds:
# tc filter add dev eth0 parent ffff: protocol ip \
flower skip_hw src_ip 192.0.2.20 \
action gate index 2 clockid CLOCK_TAI \
base-time 200000000000ns \
sched-entry open 200000000ns -1 8000000 \
sched-entry close 100000000ns
skip_hw keeps this filter in software, the form the installed manpage uses when a software clock is supplied.CLOCK_TAI is the reference clock for the schedule. The two entries form a 300,000,000-nanosecond cycle, or 300 milliseconds.tc starts at the next base time plus a whole number of complete cycles. A base time of 0 is not a convenient way to mean "start immediately"; it is the documented default and the schedule aligns to a later cycle. Choose the base time deliberately when synchronisation matters.-1 is a wildcard internal priority. The final value in the open entry is the maximum octets permitted in that slot. The close entry has no useful priority or byte limit: every frame selected while the gate is closed is dropped.Checkpoint: list the filter and confirm the action contains both schedule entries:
# tc filter show dev eth0 parent ffff:
filter protocol ip pref 49152 flower ...
action order 1: gate index 2 ...
Preference numbers and formatting are assigned by tc, so they will not necessarily match this abbreviated output. If the filter is absent, inspect the error from the add command before trying again.
A schedule does not need an open entry at all. To match ICMP frames for a particular destination MAC and drop them for a 200-millisecond cycle, use a closed entry:
# tc filter add dev eth0 parent ffff: protocol ip \
flower skip_hw ip_proto icmp dst_mac 10:00:80:00:00:00 \
action gate index 12 clockid CLOCK_TAI \
sched-entry close 200000000ns
Warning: this is a traffic-disrupting rule. Do not use a broad match such as all IPv4 traffic on a production uplink while experimenting. Narrow the source or destination match, and verify with a known test frame before expanding it.
Removing a filter is destructive to the traffic policy, so identify it first with tc filter show. If you created the rules above and no other filter shares their preference, delete the matching filters by their displayed preference:
# tc filter del dev eth0 parent ffff: protocol ip pref FILTER_PREF
Replace FILTER_PREF with the numeric preference printed by your host; do not copy the abbreviated example value blindly. Verify that it is gone:
# tc filter show dev eth0 parent ffff:
If you added the ingress qdisc solely for this test and no longer need it, remove it only after its filters are gone:
# tc qdisc del dev eth0 ingress
# tc qdisc show dev eth0
Do not run that last command to "clean up" a qdisc owned by another network service: its removal can discard unrelated ingress filters, and the service may just recreate it.
RTNETLINK answers: File exists while adding the qdisc usually means an ingress qdisc is already present. Inspect it; do not delete it automatically.tc, or offload path does not support the requested gate action. Compare tc -V against the local tc-gate(8) page, rather than borrowing syntax from another release.tc -V identifies the iproute2 version you tested.