Skip to content

Commit

Permalink
netfilter: nf_flow_table: detach routing information from flow descri…
Browse files Browse the repository at this point in the history
…ption

This patch adds the infrastructure to support for flow entry types.
The initial type is NF_FLOW_OFFLOAD_ROUTE that stores the routing
information into the flow entry to define a fastpath for the classic
forwarding path.

Signed-off-by: Pablo Neira Ayuso <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
ummakynes authored and davem330 committed Nov 13, 2019
1 parent 62248df commit f1363e0
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 27 deletions.
14 changes: 11 additions & 3 deletions include/net/netfilter/nf_flow_table.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,16 @@ struct flow_offload_tuple_rhash {
#define FLOW_OFFLOAD_DYING 0x4
#define FLOW_OFFLOAD_TEARDOWN 0x8

enum flow_offload_type {
NF_FLOW_OFFLOAD_UNSPEC = 0,
NF_FLOW_OFFLOAD_ROUTE,
};

struct flow_offload {
struct flow_offload_tuple_rhash tuplehash[FLOW_OFFLOAD_DIR_MAX];
struct nf_conn *ct;
u32 flags;
u16 flags;
u16 type;
u32 timeout;
struct rcu_head rcu_head;
};
Expand All @@ -86,10 +92,12 @@ struct nf_flow_route {
} tuple[FLOW_OFFLOAD_DIR_MAX];
};

struct flow_offload *flow_offload_alloc(struct nf_conn *ct,
struct nf_flow_route *route);
struct flow_offload *flow_offload_alloc(struct nf_conn *ct);
void flow_offload_free(struct flow_offload *flow);

int flow_offload_route_init(struct flow_offload *flow,
const struct nf_flow_route *route);

int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow);
struct flow_offload_tuple_rhash *flow_offload_lookup(struct nf_flowtable *flow_table,
struct flow_offload_tuple *tuple);
Expand Down
88 changes: 65 additions & 23 deletions net/netfilter/nf_flow_table_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,40 +19,31 @@ static LIST_HEAD(flowtables);

static void
flow_offload_fill_dir(struct flow_offload *flow, struct nf_conn *ct,
struct nf_flow_route *route,
enum flow_offload_tuple_dir dir)
{
struct flow_offload_tuple *ft = &flow->tuplehash[dir].tuple;
struct nf_conntrack_tuple *ctt = &ct->tuplehash[dir].tuple;
struct dst_entry *other_dst = route->tuple[!dir].dst;
struct dst_entry *dst = route->tuple[dir].dst;

ft->dir = dir;

switch (ctt->src.l3num) {
case NFPROTO_IPV4:
ft->src_v4 = ctt->src.u3.in;
ft->dst_v4 = ctt->dst.u3.in;
ft->mtu = ip_dst_mtu_maybe_forward(dst, true);
break;
case NFPROTO_IPV6:
ft->src_v6 = ctt->src.u3.in6;
ft->dst_v6 = ctt->dst.u3.in6;
ft->mtu = ip6_dst_mtu_forward(dst);
break;
}

ft->l3proto = ctt->src.l3num;
ft->l4proto = ctt->dst.protonum;
ft->src_port = ctt->src.u.tcp.port;
ft->dst_port = ctt->dst.u.tcp.port;

ft->iifidx = other_dst->dev->ifindex;
ft->dst_cache = dst;
}

struct flow_offload *
flow_offload_alloc(struct nf_conn *ct, struct nf_flow_route *route)
struct flow_offload *flow_offload_alloc(struct nf_conn *ct)
{
struct flow_offload *flow;

Expand All @@ -64,16 +55,10 @@ flow_offload_alloc(struct nf_conn *ct, struct nf_flow_route *route)
if (!flow)
goto err_ct_refcnt;

if (!dst_hold_safe(route->tuple[FLOW_OFFLOAD_DIR_ORIGINAL].dst))
goto err_dst_cache_original;

if (!dst_hold_safe(route->tuple[FLOW_OFFLOAD_DIR_REPLY].dst))
goto err_dst_cache_reply;

flow->ct = ct;

flow_offload_fill_dir(flow, ct, route, FLOW_OFFLOAD_DIR_ORIGINAL);
flow_offload_fill_dir(flow, ct, route, FLOW_OFFLOAD_DIR_REPLY);
flow_offload_fill_dir(flow, ct, FLOW_OFFLOAD_DIR_ORIGINAL);
flow_offload_fill_dir(flow, ct, FLOW_OFFLOAD_DIR_REPLY);

if (ct->status & IPS_SRC_NAT)
flow->flags |= FLOW_OFFLOAD_SNAT;
Expand All @@ -82,17 +67,63 @@ flow_offload_alloc(struct nf_conn *ct, struct nf_flow_route *route)

return flow;

err_dst_cache_reply:
dst_release(route->tuple[FLOW_OFFLOAD_DIR_ORIGINAL].dst);
err_dst_cache_original:
kfree(flow);
err_ct_refcnt:
nf_ct_put(ct);

return NULL;
}
EXPORT_SYMBOL_GPL(flow_offload_alloc);

static int flow_offload_fill_route(struct flow_offload *flow,
const struct nf_flow_route *route,
enum flow_offload_tuple_dir dir)
{
struct flow_offload_tuple *flow_tuple = &flow->tuplehash[dir].tuple;
struct dst_entry *other_dst = route->tuple[!dir].dst;
struct dst_entry *dst = route->tuple[dir].dst;

if (!dst_hold_safe(route->tuple[dir].dst))
return -1;

switch (flow_tuple->l3proto) {
case NFPROTO_IPV4:
flow_tuple->mtu = ip_dst_mtu_maybe_forward(dst, true);
break;
case NFPROTO_IPV6:
flow_tuple->mtu = ip6_dst_mtu_forward(dst);
break;
}

flow_tuple->iifidx = other_dst->dev->ifindex;
flow_tuple->dst_cache = dst;

return 0;
}

int flow_offload_route_init(struct flow_offload *flow,
const struct nf_flow_route *route)
{
int err;

err = flow_offload_fill_route(flow, route, FLOW_OFFLOAD_DIR_ORIGINAL);
if (err < 0)
return err;

err = flow_offload_fill_route(flow, route, FLOW_OFFLOAD_DIR_REPLY);
if (err < 0)
goto err_route_reply;

flow->type = NF_FLOW_OFFLOAD_ROUTE;

return 0;

err_route_reply:
dst_release(route->tuple[FLOW_OFFLOAD_DIR_ORIGINAL].dst);

return err;
}
EXPORT_SYMBOL_GPL(flow_offload_route_init);

static void flow_offload_fixup_tcp(struct ip_ct_tcp *tcp)
{
tcp->state = TCP_CONNTRACK_ESTABLISHED;
Expand Down Expand Up @@ -141,10 +172,21 @@ static void flow_offload_fixup_ct(struct nf_conn *ct)
flow_offload_fixup_ct_timeout(ct);
}

void flow_offload_free(struct flow_offload *flow)
static void flow_offload_route_release(struct flow_offload *flow)
{
dst_release(flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.dst_cache);
dst_release(flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dst_cache);
}

void flow_offload_free(struct flow_offload *flow)
{
switch (flow->type) {
case NF_FLOW_OFFLOAD_ROUTE:
flow_offload_route_release(flow);
break;
default:
break;
}
if (flow->flags & FLOW_OFFLOAD_DYING)
nf_ct_delete(flow->ct, 0, 0);
nf_ct_put(flow->ct);
Expand Down
5 changes: 4 additions & 1 deletion net/netfilter/nft_flow_offload.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,13 @@ static void nft_flow_offload_eval(const struct nft_expr *expr,
if (nft_flow_route(pkt, ct, &route, dir) < 0)
goto err_flow_route;

flow = flow_offload_alloc(ct, &route);
flow = flow_offload_alloc(ct);
if (!flow)
goto err_flow_alloc;

if (flow_offload_route_init(flow, &route) < 0)
goto err_flow_add;

if (tcph) {
ct->proto.tcp.seen[0].flags |= IP_CT_TCP_FLAG_BE_LIBERAL;
ct->proto.tcp.seen[1].flags |= IP_CT_TCP_FLAG_BE_LIBERAL;
Expand Down

0 comments on commit f1363e0

Please sign in to comment.