Skip to content

Commit 5c27d8d

Browse files
committed
netfilter: nf_flow_table_offload: add IPv6 support
Add nf_flow_rule_route_ipv6() and use it from the IPv6 and the inet flowtable type definitions. Rename the nf_flow_rule_route() function to nf_flow_rule_route_ipv4(). Adjust maximum number of actions, which now becomes 16 to leave sufficient room for the IPv6 address mangling for NAT. Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent 4a766d4 commit 5c27d8d

File tree

5 files changed

+127
-11
lines changed

5 files changed

+127
-11
lines changed

include/net/netfilter/nf_flow_table.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -163,9 +163,12 @@ void nf_flow_table_offload_flush(struct nf_flowtable *flowtable);
163163
int nf_flow_table_offload_setup(struct nf_flowtable *flowtable,
164164
struct net_device *dev,
165165
enum flow_block_command cmd);
166-
int nf_flow_rule_route(struct net *net, const struct flow_offload *flow,
167-
enum flow_offload_tuple_dir dir,
168-
struct nf_flow_rule *flow_rule);
166+
int nf_flow_rule_route_ipv4(struct net *net, const struct flow_offload *flow,
167+
enum flow_offload_tuple_dir dir,
168+
struct nf_flow_rule *flow_rule);
169+
int nf_flow_rule_route_ipv6(struct net *net, const struct flow_offload *flow,
170+
enum flow_offload_tuple_dir dir,
171+
struct nf_flow_rule *flow_rule);
169172

170173
int nf_flow_table_offload_init(void);
171174
void nf_flow_table_offload_exit(void);

net/ipv4/netfilter/nf_flow_table_ipv4.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ static struct nf_flowtable_type flowtable_ipv4 = {
1010
.family = NFPROTO_IPV4,
1111
.init = nf_flow_table_init,
1212
.setup = nf_flow_table_offload_setup,
13-
.action = nf_flow_rule_route,
13+
.action = nf_flow_rule_route_ipv4,
1414
.free = nf_flow_table_free,
1515
.hook = nf_flow_offload_ip_hook,
1616
.owner = THIS_MODULE,

net/ipv6/netfilter/nf_flow_table_ipv6.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ static struct nf_flowtable_type flowtable_ipv6 = {
1111
.family = NFPROTO_IPV6,
1212
.init = nf_flow_table_init,
1313
.setup = nf_flow_table_offload_setup,
14-
.action = nf_flow_rule_route,
14+
.action = nf_flow_rule_route_ipv6,
1515
.free = nf_flow_table_free,
1616
.hook = nf_flow_offload_ipv6_hook,
1717
.owner = THIS_MODULE,

net/netfilter/nf_flow_table_inet.c

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,34 @@ nf_flow_offload_inet_hook(void *priv, struct sk_buff *skb,
2121
return NF_ACCEPT;
2222
}
2323

24+
static int nf_flow_rule_route_inet(struct net *net,
25+
const struct flow_offload *flow,
26+
enum flow_offload_tuple_dir dir,
27+
struct nf_flow_rule *flow_rule)
28+
{
29+
const struct flow_offload_tuple *flow_tuple = &flow->tuplehash[dir].tuple;
30+
int err;
31+
32+
switch (flow_tuple->l3proto) {
33+
case NFPROTO_IPV4:
34+
err = nf_flow_rule_route_ipv4(net, flow, dir, flow_rule);
35+
break;
36+
case NFPROTO_IPV6:
37+
err = nf_flow_rule_route_ipv6(net, flow, dir, flow_rule);
38+
break;
39+
default:
40+
err = -1;
41+
break;
42+
}
43+
44+
return err;
45+
}
46+
2447
static struct nf_flowtable_type flowtable_inet = {
2548
.family = NFPROTO_INET,
2649
.init = nf_flow_table_init,
2750
.setup = nf_flow_table_offload_setup,
28-
.action = nf_flow_rule_route,
51+
.action = nf_flow_rule_route_inet,
2952
.free = nf_flow_table_free,
3053
.hook = nf_flow_offload_inet_hook,
3154
.owner = THIS_MODULE,

net/netfilter/nf_flow_table_offload.c

Lines changed: 95 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,71 @@ static void flow_offload_ipv4_dnat(struct net *net,
236236
(u8 *)&addr, (u8 *)&mask);
237237
}
238238

239+
static void flow_offload_ipv6_mangle(struct nf_flow_rule *flow_rule,
240+
unsigned int offset,
241+
u8 *addr, u8 *mask)
242+
{
243+
struct flow_action_entry *entry;
244+
int i;
245+
246+
for (i = 0; i < sizeof(struct in6_addr) / sizeof(u32); i += sizeof(u32)) {
247+
entry = flow_action_entry_next(flow_rule);
248+
flow_offload_mangle(entry, FLOW_ACT_MANGLE_HDR_TYPE_IP6,
249+
offset + i,
250+
&addr[i], mask);
251+
}
252+
}
253+
254+
static void flow_offload_ipv6_snat(struct net *net,
255+
const struct flow_offload *flow,
256+
enum flow_offload_tuple_dir dir,
257+
struct nf_flow_rule *flow_rule)
258+
{
259+
u32 mask = ~htonl(0xffffffff);
260+
const u8 *addr;
261+
u32 offset;
262+
263+
switch (dir) {
264+
case FLOW_OFFLOAD_DIR_ORIGINAL:
265+
addr = flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dst_v6.s6_addr;
266+
offset = offsetof(struct ipv6hdr, saddr);
267+
break;
268+
case FLOW_OFFLOAD_DIR_REPLY:
269+
addr = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.src_v6.s6_addr;
270+
offset = offsetof(struct ipv6hdr, daddr);
271+
break;
272+
default:
273+
return;
274+
}
275+
276+
flow_offload_ipv6_mangle(flow_rule, offset, (u8 *)addr, (u8 *)&mask);
277+
}
278+
279+
static void flow_offload_ipv6_dnat(struct net *net,
280+
const struct flow_offload *flow,
281+
enum flow_offload_tuple_dir dir,
282+
struct nf_flow_rule *flow_rule)
283+
{
284+
u32 mask = ~htonl(0xffffffff);
285+
const u8 *addr;
286+
u32 offset;
287+
288+
switch (dir) {
289+
case FLOW_OFFLOAD_DIR_ORIGINAL:
290+
addr = flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.src_v6.s6_addr;
291+
offset = offsetof(struct ipv6hdr, daddr);
292+
break;
293+
case FLOW_OFFLOAD_DIR_REPLY:
294+
addr = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.dst_v6.s6_addr;
295+
offset = offsetof(struct ipv6hdr, saddr);
296+
break;
297+
default:
298+
return;
299+
}
300+
301+
flow_offload_ipv6_mangle(flow_rule, offset, (u8 *)addr, (u8 *)&mask);
302+
}
303+
239304
static int flow_offload_l4proto(const struct flow_offload *flow)
240305
{
241306
u8 protonum = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.l4proto;
@@ -342,9 +407,9 @@ static void flow_offload_redirect(const struct flow_offload *flow,
342407
dev_hold(rt->dst.dev);
343408
}
344409

345-
int nf_flow_rule_route(struct net *net, const struct flow_offload *flow,
346-
enum flow_offload_tuple_dir dir,
347-
struct nf_flow_rule *flow_rule)
410+
int nf_flow_rule_route_ipv4(struct net *net, const struct flow_offload *flow,
411+
enum flow_offload_tuple_dir dir,
412+
struct nf_flow_rule *flow_rule)
348413
{
349414
if (flow_offload_eth_src(net, flow, dir, flow_rule) < 0 ||
350415
flow_offload_eth_dst(net, flow, dir, flow_rule) < 0)
@@ -366,7 +431,32 @@ int nf_flow_rule_route(struct net *net, const struct flow_offload *flow,
366431

367432
return 0;
368433
}
369-
EXPORT_SYMBOL_GPL(nf_flow_rule_route);
434+
EXPORT_SYMBOL_GPL(nf_flow_rule_route_ipv4);
435+
436+
int nf_flow_rule_route_ipv6(struct net *net, const struct flow_offload *flow,
437+
enum flow_offload_tuple_dir dir,
438+
struct nf_flow_rule *flow_rule)
439+
{
440+
if (flow_offload_eth_src(net, flow, dir, flow_rule) < 0 ||
441+
flow_offload_eth_dst(net, flow, dir, flow_rule) < 0)
442+
return -1;
443+
444+
if (flow->flags & FLOW_OFFLOAD_SNAT) {
445+
flow_offload_ipv6_snat(net, flow, dir, flow_rule);
446+
flow_offload_port_snat(net, flow, dir, flow_rule);
447+
}
448+
if (flow->flags & FLOW_OFFLOAD_DNAT) {
449+
flow_offload_ipv6_dnat(net, flow, dir, flow_rule);
450+
flow_offload_port_dnat(net, flow, dir, flow_rule);
451+
}
452+
453+
flow_offload_redirect(flow, dir, flow_rule);
454+
455+
return 0;
456+
}
457+
EXPORT_SYMBOL_GPL(nf_flow_rule_route_ipv6);
458+
459+
#define NF_FLOW_RULE_ACTION_MAX 16
370460

371461
static struct nf_flow_rule *
372462
nf_flow_offload_rule_alloc(struct net *net,
@@ -383,7 +473,7 @@ nf_flow_offload_rule_alloc(struct net *net,
383473
if (!flow_rule)
384474
goto err_flow;
385475

386-
flow_rule->rule = flow_rule_alloc(10);
476+
flow_rule->rule = flow_rule_alloc(NF_FLOW_RULE_ACTION_MAX);
387477
if (!flow_rule->rule)
388478
goto err_flow_rule;
389479

0 commit comments

Comments
 (0)