Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net sched actions: Complete the JUMPX opcode

per discussion at netconf/netdev:
When we have an action that is capable of branching (example a policer),
we can achieve a continuation of the action graph by programming a
"continue" where we find an exact replica of the same filter rule with a lower
priority and the remainder of the action graph. When you have 100s of thousands
of filters which require such a feature it gets very inefficient to do two
lookups.

This patch completes a leftover feature of action codes. Its time has come.

Example below where a user labels packets with a different skbmark on ingress
of a port depending on whether they have/not exceeded the configured rate.
This mark is then used to make further decisions on some egress port.

#rate control, very low so we can easily see the effect
sudo $TC actions add action police rate 1kbit burst 90k \
conform-exceed pipe/jump 2 index 10
# skbedit index 11 will be used if the user conforms
sudo $TC actions add action skbedit mark 11 ok index 11
# skbedit index 12 will be used if the user does not conform
sudo $TC actions add action skbedit mark 12 ok index 12

#lets bind the user ..
sudo $TC filter add dev $ETH parent ffff: protocol ip prio 8 u32 \
match ip dst 127.0.0.8/32 flowid 1:10 \
action police index 10 \
action skbedit index 11 \
action skbedit index 12

#run a ping -f and see what happens..
#
jhs@foobar:~$ sudo $TC -s filter ls dev $ETH parent ffff: protocol ip
filter pref 8 u32
filter pref 8 u32 fh 800: ht divisor 1
filter pref 8 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:10 (rule hit 2800 success 1005)
match 7f000008/ffffffff at 16 (success 1005 )
action order 1: police 0xa rate 1Kbit burst 23440b mtu 2Kb action pipe/jump 2 overhead 0b
ref 2 bind 1 installed 207 sec used 122 sec
Action statistics:
Sent 84420 bytes 1005 pkt (dropped 0, overlimits 721 requeues 0)
backlog 0b 0p requeues 0

action order 2: skbedit mark 11 pass
index 11 ref 2 bind 1 installed 204 sec used 122 sec
Action statistics:
Sent 60564 bytes 721 pkt (dropped 0, overlimits 0 requeues 0)
backlog 0b 0p requeues 0

action order 3: skbedit mark 12 pass
index 12 ref 2 bind 1 installed 201 sec used 122 sec
Action statistics:
Sent 23856 bytes 284 pkt (dropped 0, overlimits 0 requeues 0)
backlog 0b 0p requeues 0

Not bad, about 28% non-conforming packets..

Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Jamal Hadi Salim and committed by
David S. Miller
e0ee84de 45a6f3bc

+25
+25
net/sched/act_api.c
··· 428 428 return res; 429 429 } 430 430 431 + /*TCA_ACT_MAX_PRIO is 32, there count upto 32 */ 432 + #define TCA_ACT_MAX_PRIO_MASK 0x1FF 431 433 int tcf_action_exec(struct sk_buff *skb, struct tc_action **actions, 432 434 int nr_actions, struct tcf_result *res) 433 435 { 434 436 int ret = -1, i; 437 + u32 jmp_prgcnt = 0; 438 + u32 jmp_ttl = TCA_ACT_MAX_PRIO; /*matches actions per filter */ 435 439 436 440 if (skb_skip_tc_classify(skb)) 437 441 return TC_ACT_OK; 438 442 443 + restart_act_graph: 439 444 for (i = 0; i < nr_actions; i++) { 440 445 const struct tc_action *a = actions[i]; 441 446 447 + if (jmp_prgcnt > 0) { 448 + jmp_prgcnt -= 1; 449 + continue; 450 + } 442 451 repeat: 443 452 ret = a->ops->act(skb, a, res); 444 453 if (ret == TC_ACT_REPEAT) 445 454 goto repeat; /* we need a ttl - JHS */ 455 + 456 + if (ret & TC_ACT_JUMP) { 457 + jmp_prgcnt = ret & TCA_ACT_MAX_PRIO_MASK; 458 + if (!jmp_prgcnt || (jmp_prgcnt > nr_actions)) { 459 + /* faulty opcode, stop pipeline */ 460 + return TC_ACT_OK; 461 + } else { 462 + jmp_ttl -= 1; 463 + if (jmp_ttl > 0) 464 + goto restart_act_graph; 465 + else /* faulty graph, stop pipeline */ 466 + return TC_ACT_OK; 467 + } 468 + } 469 + 446 470 if (ret != TC_ACT_PIPE) 447 471 break; 448 472 } 473 + 449 474 return ret; 450 475 } 451 476 EXPORT_SYMBOL(tcf_action_exec);