1 .TH "Generic packet editor action in tc" 8 "12 Jan 2015" "iproute2" "Linux"
4 pedit - generic packet editor action
8 .BR tc " ... " "action pedit [ex] munge " {
9 .IR RAW_OP " | " LAYERED_OP " | " EXTENDED_LAYERED_OP " } [ " CONTROL " ]"
14 .RB "{ " u8 " | " u16 " | " u32 " } ["
15 .IR AT_SPEC " ] " CMD_SPEC
19 .BI at " AT " offmask " MASK " shift " SHIFT"
22 .IR LAYERED_OP " := { "
25 .BI ip " BEYOND_IPHDR_FIELD"
29 .IR EXTENDED_LAYERED_OP " := { "
30 .BI eth " ETHHDR_FIELD"
34 .BI ip " EX_IPHDR_FIELD"
36 .BI ip6 " IP6HDR_FIELD"
38 .BI tcp " TCPHDR_FIELD"
40 .BI udp " UDPHDR_FIELD"
44 .IR ETHHDR_FIELD " := { "
45 .BR src " | " dst " | " type " }"
48 .IR IPHDR_FIELD " := { "
49 .BR src " | " dst " | " tos " | " dsfield " | " ihl " | " protocol " |"
50 .BR precedence " | " nofrag " | " firstfrag " | " ce " | " df " }"
53 .IR BEYOND_IPHDR_FIELD " := { "
54 .BR dport " | " sport " | " icmp_type " | " icmp_code " }"
57 .IR EX_IPHDR_FIELD " := { "
62 .IR IP6HDR_FIELD " := { "
63 .BR src " | " dst " | " traffic_class " | " flow_lbl " | " payload_len " | "
64 .BR nexthdr " | " hoplimit " }"
67 .IR TCPHDR_FIELD " := { "
68 .BR sport " | " dport " | " flags " }"
71 .IR UDPHDR_FIELD " := { "
72 .BR sport " | " dport " }"
76 .BR clear " | " invert " | " set
80 .BR preserve " } [ " retain
85 .BR reclassify " | " pipe " | " drop " | " shot " | " continue " | " pass " | " goto " " chain " " CHAIN_INDEX " }"
89 action can be used to change arbitrary packet data. The location of data to
90 change can either be specified by giving an offset and size as in
92 or for header values by naming the header and field to edit the size is then
93 chosen automatically based on the header field size. Currently this is supported
94 only for IPv4 headers.
99 .I EXTENDED_LAYERED_OP
102 are allowed only in this mode.
104 .BI offset " OFFSET " "\fR{ \fBu32 \fR| \fBu16 \fR| \fBu8 \fR}"
105 Specify the offset at which to change data.
107 is a signed integer, it's base is automatically chosen (e.g. hex if prefixed by
109 or octal if prefixed by
111 The second argument specifies the length of data to change, that is four bytes
118 .BI at " AT " offmask " MASK " shift " SHIFT"
119 This is an optional part of
121 which allows to have a variable
123 depending on packet data at offset
125 which is binary ANDed with
132 .BI eth " ETHHDR_FIELD"
133 Change an ETH header field. The supported keywords for
141 Source or destination MAC address in the standard format: XX:XX:XX:XX:XX:XX
144 Ether-type in numeric value
147 .BI ip " IPHDR_FIELD"
148 Change an IPv4 header field. The supported keywords for
156 Source or destination IP address, a four-byte value.
163 Type Of Service field, an eight-bit value.
166 Change the IP Header Length field, a four-bit value.
169 Next-layer Protocol field, an eight-bit value.
180 Change IP header flags. Note that the value to pass to the
182 command is not just a bit value, but the full byte including the flags field.
183 Though only the relevant bits of that value are respected, the rest ignored.
186 .BI ip " BEYOND_IPHDR_FIELD"
187 Supported only for non-extended layered op. It is passed to the kernel as
188 offsets relative to the beginning of the IP header and assumes the IP header is
189 of minimum size (20 bytes). The supported keywords for
190 .I BEYOND_IPHDR_FIELD
197 Destination or source port numbers, a 16-bit value. Indeed, IPv4 headers don't
198 contain this information. Instead, this will set an offset which suits at least
199 TCP and UDP if the IP header is of minimum size (20 bytes). If not, this will do
205 Again, this allows to change data past the actual IP header itself. It assumes
206 an ICMP header is present immediately following the (minimal sized) IP header.
207 If it is not or the latter is bigger than the minimum of 20 bytes, this will do
208 unexpected things. These fields are eight-bit values.
211 .BI ip " EX_IPHDR_FIELD"
214 is used. The supported keywords for
222 .BI ip6 " IP6HDR_FIELD"
223 The supported keywords for
243 .BI tcp " TCPHDR_FIELD"
244 The supported keywords for
252 Source or destination TCP port number, a 16-bit value.
257 .BI udp " UDPHDR_FIELD"
258 The supported keywords for
266 Source or destination TCP port number, a 16-bit value.
270 Clear the addressed data (i.e., set it to zero).
273 Swap every bit in the addressed data.
276 Set the addressed data to a specific value. The size of
278 is defined by either one of the
279 .BR u32 ", " u16 " or " u8
282 or the size of the addressed header field in
286 Add the addressed data by a specific value. The size of
288 is defined by the size of the addressed header field in
289 .IR EXTENDED_LAYERED_OP .
290 This operation is supported only for extended layered op.
293 Keep the addressed data as is.
296 This optional extra part of
298 allows to exclude bits from being changed. Supported only for 32 bits fields
302 The following keywords allow to control how the tree of qdisc, classes,
303 filters and actions is further traversed after this action.
307 Restart with the first filter in the current list.
310 Continue with the next action attached to the same filter.
318 Continue classification with the next filter in line.
321 Finish classification process and return to calling qdisc for further packet
322 processing. This is the default.
325 Being able to edit packet data, one could do all kinds of things, such as e.g.
326 implementing port redirection. Certainly not the most useful application, but
327 as an example it should do:
329 First, qdiscs need to be set up to attach filters to. For the receive path, a simple
331 qdisc will do, for transmit path a classful qdisc
333 in this case) is necessary:
337 tc qdisc replace dev eth0 root handle 1: htb
338 tc qdisc add dev eth0 ingress handle ffff:
342 Finally, a filter with
344 action can be added for each direction. In this case,
346 is used matching on the port number to redirect from, while
348 then does the actual rewriting:
352 tc filter add dev eth0 parent 1: u32 \\
353 match ip dport 23 0xffff \\
354 action pedit pedit munge ip dport set 22
355 tc filter add dev eth0 parent ffff: u32 \\
356 match ip sport 22 0xffff \\
357 action pedit pedit munge ip sport set 23
358 tc filter add dev eth0 parent ffff: u32 \\
359 match ip sport 22 0xffff \\
360 action pedit ex munge ip dst set 192.168.1.199
361 tc filter add dev eth0 parent ffff: u32 \\
362 match ip sport 22 0xffff \\
363 action pedit ex munge ip6 dst set fe80::dacb:8aff:fec7:320e
364 tc filter add dev eth0 parent ffff: u32 \\
365 match ip sport 22 0xffff \\
366 action pedit ex munge eth dst set 11:22:33:44:55:66
367 tc filter add dev eth0 parent ffff: u32 \\
368 match ip dport 23 0xffff \\
369 action pedit ex munge tcp dport set 22
373 To rewrite just part of a field, use the
375 directive. E.g. to overwrite the DSCP part of a dsfield with $DSCP, without
380 tc filter add dev eth0 ingress flower ... \\
381 action pedit ex munge ip dsfield set $((DSCP << 2)) retain 0xfc
385 And vice versa, to set ECN to e.g. 1 without impacting DSCP:
389 tc filter add dev eth0 ingress flower ... \\
390 action pedit ex munge ip dsfield set 1 retain 0x3