Skip to content

Commit 744676e

Browse files
teknoraverdavem330
authored andcommitted
openvswitch: add TTL decrement action
New action to decrement TTL instead of setting it to a fixed value. This action will decrement the TTL and, in case of expired TTL, drop it or execute an action passed via a nested attribute. The default TTL expired action is to drop the packet. Supports both IPv4 and IPv6 via the ttl and hop_limit fields, respectively. Tested with a corresponding change in the userspace: # ovs-dpctl dump-flows in_port(2),eth(),eth_type(0x0800), packets:0, bytes:0, used:never, actions:dec_ttl{ttl<=1 action:(drop)},1 in_port(1),eth(),eth_type(0x0800), packets:0, bytes:0, used:never, actions:dec_ttl{ttl<=1 action:(drop)},2 in_port(1),eth(),eth_type(0x0806), packets:0, bytes:0, used:never, actions:2 in_port(2),eth(),eth_type(0x0806), packets:0, bytes:0, used:never, actions:1 # ping -c1 192.168.0.2 -t 42 IP (tos 0x0, ttl 41, id 61647, offset 0, flags [DF], proto ICMP (1), length 84) 192.168.0.1 > 192.168.0.2: ICMP echo request, id 386, seq 1, length 64 # ping -c1 192.168.0.2 -t 120 IP (tos 0x0, ttl 119, id 62070, offset 0, flags [DF], proto ICMP (1), length 84) 192.168.0.1 > 192.168.0.2: ICMP echo request, id 388, seq 1, length 64 # ping -c1 192.168.0.2 -t 1 # Co-developed-by: Bindiya Kurle <[email protected]> Signed-off-by: Bindiya Kurle <[email protected]> Signed-off-by: Matteo Croce <[email protected]> Acked-by: Pravin B Shelar <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 7458bd5 commit 744676e

File tree

3 files changed

+144
-0
lines changed

3 files changed

+144
-0
lines changed

include/uapi/linux/openvswitch.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -958,6 +958,7 @@ enum ovs_action_attr {
958958
OVS_ACTION_ATTR_CLONE, /* Nested OVS_CLONE_ATTR_*. */
959959
OVS_ACTION_ATTR_CHECK_PKT_LEN, /* Nested OVS_CHECK_PKT_LEN_ATTR_*. */
960960
OVS_ACTION_ATTR_ADD_MPLS, /* struct ovs_action_add_mpls. */
961+
OVS_ACTION_ATTR_DEC_TTL, /* Nested OVS_DEC_TTL_ATTR_*. */
961962

962963
__OVS_ACTION_ATTR_MAX, /* Nothing past this will be accepted
963964
* from userspace. */
@@ -1050,4 +1051,10 @@ struct ovs_zone_limit {
10501051
__u32 count;
10511052
};
10521053

1054+
enum ovs_dec_ttl_attr {
1055+
OVS_DEC_TTL_ATTR_UNSPEC,
1056+
OVS_DEC_TTL_ATTR_ACTION, /* Nested struct nlattr */
1057+
__OVS_DEC_TTL_ATTR_MAX
1058+
};
1059+
10531060
#endif /* _LINUX_OPENVSWITCH_H */

net/openvswitch/actions.c

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -964,6 +964,25 @@ static int output_userspace(struct datapath *dp, struct sk_buff *skb,
964964
return ovs_dp_upcall(dp, skb, key, &upcall, cutlen);
965965
}
966966

967+
static int dec_ttl_exception_handler(struct datapath *dp, struct sk_buff *skb,
968+
struct sw_flow_key *key,
969+
const struct nlattr *attr, bool last)
970+
{
971+
/* The first action is always 'OVS_DEC_TTL_ATTR_ARG'. */
972+
struct nlattr *dec_ttl_arg = nla_data(attr);
973+
int rem = nla_len(attr);
974+
975+
if (nla_len(dec_ttl_arg)) {
976+
struct nlattr *actions = nla_next(dec_ttl_arg, &rem);
977+
978+
if (actions)
979+
return clone_execute(dp, skb, key, 0, actions, rem,
980+
last, false);
981+
}
982+
consume_skb(skb);
983+
return 0;
984+
}
985+
967986
/* When 'last' is true, sample() should always consume the 'skb'.
968987
* Otherwise, sample() should keep 'skb' intact regardless what
969988
* actions are executed within sample().
@@ -1180,6 +1199,45 @@ static int execute_check_pkt_len(struct datapath *dp, struct sk_buff *skb,
11801199
nla_len(actions), last, clone_flow_key);
11811200
}
11821201

1202+
static int execute_dec_ttl(struct sk_buff *skb, struct sw_flow_key *key)
1203+
{
1204+
int err;
1205+
1206+
if (skb->protocol == htons(ETH_P_IPV6)) {
1207+
struct ipv6hdr *nh;
1208+
1209+
err = skb_ensure_writable(skb, skb_network_offset(skb) +
1210+
sizeof(*nh));
1211+
if (unlikely(err))
1212+
return err;
1213+
1214+
nh = ipv6_hdr(skb);
1215+
1216+
if (nh->hop_limit <= 1)
1217+
return -EHOSTUNREACH;
1218+
1219+
key->ip.ttl = --nh->hop_limit;
1220+
} else {
1221+
struct iphdr *nh;
1222+
u8 old_ttl;
1223+
1224+
err = skb_ensure_writable(skb, skb_network_offset(skb) +
1225+
sizeof(*nh));
1226+
if (unlikely(err))
1227+
return err;
1228+
1229+
nh = ip_hdr(skb);
1230+
if (nh->ttl <= 1)
1231+
return -EHOSTUNREACH;
1232+
1233+
old_ttl = nh->ttl--;
1234+
csum_replace2(&nh->check, htons(old_ttl << 8),
1235+
htons(nh->ttl << 8));
1236+
key->ip.ttl = nh->ttl;
1237+
}
1238+
return 0;
1239+
}
1240+
11831241
/* Execute a list of actions against 'skb'. */
11841242
static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
11851243
struct sw_flow_key *key,
@@ -1365,6 +1423,15 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
13651423

13661424
break;
13671425
}
1426+
1427+
case OVS_ACTION_ATTR_DEC_TTL:
1428+
err = execute_dec_ttl(skb, key);
1429+
if (err == -EHOSTUNREACH) {
1430+
err = dec_ttl_exception_handler(dp, skb, key,
1431+
a, true);
1432+
return err;
1433+
}
1434+
break;
13681435
}
13691436

13701437
if (unlikely(err)) {

net/openvswitch/flow_netlink.c

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ static bool actions_may_change_flow(const struct nlattr *actions)
8080
case OVS_ACTION_ATTR_METER:
8181
case OVS_ACTION_ATTR_CHECK_PKT_LEN:
8282
case OVS_ACTION_ATTR_ADD_MPLS:
83+
case OVS_ACTION_ATTR_DEC_TTL:
8384
default:
8485
return true;
8586
}
@@ -2495,6 +2496,39 @@ static int validate_and_copy_sample(struct net *net, const struct nlattr *attr,
24952496
return 0;
24962497
}
24972498

2499+
static int validate_and_copy_dec_ttl(struct net *net,
2500+
const struct nlattr *attr,
2501+
const struct sw_flow_key *key,
2502+
struct sw_flow_actions **sfa,
2503+
__be16 eth_type, __be16 vlan_tci,
2504+
u32 mpls_label_count, bool log)
2505+
{
2506+
int start, err;
2507+
u32 nested = true;
2508+
2509+
if (!nla_len(attr))
2510+
return ovs_nla_add_action(sfa, OVS_ACTION_ATTR_DEC_TTL,
2511+
NULL, 0, log);
2512+
2513+
start = add_nested_action_start(sfa, OVS_ACTION_ATTR_DEC_TTL, log);
2514+
if (start < 0)
2515+
return start;
2516+
2517+
err = ovs_nla_add_action(sfa, OVS_DEC_TTL_ATTR_ACTION, &nested,
2518+
sizeof(nested), log);
2519+
2520+
if (err)
2521+
return err;
2522+
2523+
err = __ovs_nla_copy_actions(net, attr, key, sfa, eth_type,
2524+
vlan_tci, mpls_label_count, log);
2525+
if (err)
2526+
return err;
2527+
2528+
add_nested_action_end(*sfa, start);
2529+
return 0;
2530+
}
2531+
24982532
static int validate_and_copy_clone(struct net *net,
24992533
const struct nlattr *attr,
25002534
const struct sw_flow_key *key,
@@ -3007,6 +3041,7 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
30073041
[OVS_ACTION_ATTR_CLONE] = (u32)-1,
30083042
[OVS_ACTION_ATTR_CHECK_PKT_LEN] = (u32)-1,
30093043
[OVS_ACTION_ATTR_ADD_MPLS] = sizeof(struct ovs_action_add_mpls),
3044+
[OVS_ACTION_ATTR_DEC_TTL] = (u32)-1,
30103045
};
30113046
const struct ovs_action_push_vlan *vlan;
30123047
int type = nla_type(a);
@@ -3267,6 +3302,15 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
32673302
break;
32683303
}
32693304

3305+
case OVS_ACTION_ATTR_DEC_TTL:
3306+
err = validate_and_copy_dec_ttl(net, a, key, sfa,
3307+
eth_type, vlan_tci,
3308+
mpls_label_count, log);
3309+
if (err)
3310+
return err;
3311+
skip_copy = true;
3312+
break;
3313+
32703314
default:
32713315
OVS_NLERR(log, "Unknown Action type %d", type);
32723316
return -EINVAL;
@@ -3438,6 +3482,26 @@ static int check_pkt_len_action_to_attr(const struct nlattr *attr,
34383482
return err;
34393483
}
34403484

3485+
static int dec_ttl_action_to_attr(const struct nlattr *attr,
3486+
struct sk_buff *skb)
3487+
{
3488+
int err = 0, rem = nla_len(attr);
3489+
struct nlattr *start;
3490+
3491+
start = nla_nest_start_noflag(skb, OVS_ACTION_ATTR_DEC_TTL);
3492+
3493+
if (!start)
3494+
return -EMSGSIZE;
3495+
3496+
err = ovs_nla_put_actions(nla_data(attr), rem, skb);
3497+
if (err)
3498+
nla_nest_cancel(skb, start);
3499+
else
3500+
nla_nest_end(skb, start);
3501+
3502+
return err;
3503+
}
3504+
34413505
static int set_action_to_attr(const struct nlattr *a, struct sk_buff *skb)
34423506
{
34433507
const struct nlattr *ovs_key = nla_data(a);
@@ -3538,6 +3602,12 @@ int ovs_nla_put_actions(const struct nlattr *attr, int len, struct sk_buff *skb)
35383602
return err;
35393603
break;
35403604

3605+
case OVS_ACTION_ATTR_DEC_TTL:
3606+
err = dec_ttl_action_to_attr(a, skb);
3607+
if (err)
3608+
return err;
3609+
break;
3610+
35413611
default:
35423612
if (nla_put(skb, type, nla_len(a), nla_data(a)))
35433613
return -EMSGSIZE;

0 commit comments

Comments
 (0)