Skip to content

Commit 499a242

Browse files
roopa-prabhudavem330
authored andcommitted
lwtunnel: infrastructure for handling light weight tunnels like mpls
Provides infrastructure to parse/dump/store encap information for light weight tunnels like mpls. Encap information for such tunnels is associated with fib routes. This infrastructure is based on previous suggestions from Eric Biederman to follow the xfrm infrastructure. Signed-off-by: Roopa Prabhu <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent a0d9a86 commit 499a242

File tree

6 files changed

+340
-0
lines changed

6 files changed

+340
-0
lines changed

include/linux/lwtunnel.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#ifndef _LINUX_LWTUNNEL_H_
2+
#define _LINUX_LWTUNNEL_H_
3+
4+
#include <uapi/linux/lwtunnel.h>
5+
6+
#endif /* _LINUX_LWTUNNEL_H_ */

include/net/lwtunnel.h

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
#ifndef __NET_LWTUNNEL_H
2+
#define __NET_LWTUNNEL_H 1
3+
4+
#include <linux/lwtunnel.h>
5+
#include <linux/netdevice.h>
6+
#include <linux/skbuff.h>
7+
#include <linux/types.h>
8+
#include <net/route.h>
9+
10+
#define LWTUNNEL_HASH_BITS 7
11+
#define LWTUNNEL_HASH_SIZE (1 << LWTUNNEL_HASH_BITS)
12+
13+
/* lw tunnel state flags */
14+
#define LWTUNNEL_STATE_OUTPUT_REDIRECT 0x1
15+
16+
struct lwtunnel_state {
17+
__u16 type;
18+
__u16 flags;
19+
atomic_t refcnt;
20+
int len;
21+
__u8 data[0];
22+
};
23+
24+
struct lwtunnel_encap_ops {
25+
int (*build_state)(struct net_device *dev, struct nlattr *encap,
26+
struct lwtunnel_state **ts);
27+
int (*output)(struct sock *sk, struct sk_buff *skb);
28+
int (*fill_encap)(struct sk_buff *skb,
29+
struct lwtunnel_state *lwtstate);
30+
int (*get_encap_size)(struct lwtunnel_state *lwtstate);
31+
int (*cmp_encap)(struct lwtunnel_state *a, struct lwtunnel_state *b);
32+
};
33+
34+
extern const struct lwtunnel_encap_ops __rcu *
35+
lwtun_encaps[LWTUNNEL_ENCAP_MAX+1];
36+
37+
#ifdef CONFIG_LWTUNNEL
38+
static inline void lwtunnel_state_get(struct lwtunnel_state *lws)
39+
{
40+
atomic_inc(&lws->refcnt);
41+
}
42+
43+
static inline void lwtunnel_state_put(struct lwtunnel_state *lws)
44+
{
45+
if (!lws)
46+
return;
47+
48+
if (atomic_dec_and_test(&lws->refcnt))
49+
kfree(lws);
50+
}
51+
52+
static inline bool lwtunnel_output_redirect(struct lwtunnel_state *lwtstate)
53+
{
54+
if (lwtstate && (lwtstate->flags & LWTUNNEL_STATE_OUTPUT_REDIRECT))
55+
return true;
56+
57+
return false;
58+
}
59+
60+
int lwtunnel_encap_add_ops(const struct lwtunnel_encap_ops *op,
61+
unsigned int num);
62+
int lwtunnel_encap_del_ops(const struct lwtunnel_encap_ops *op,
63+
unsigned int num);
64+
int lwtunnel_build_state(struct net_device *dev, u16 encap_type,
65+
struct nlattr *encap,
66+
struct lwtunnel_state **lws);
67+
int lwtunnel_fill_encap(struct sk_buff *skb,
68+
struct lwtunnel_state *lwtstate);
69+
int lwtunnel_get_encap_size(struct lwtunnel_state *lwtstate);
70+
struct lwtunnel_state *lwtunnel_state_alloc(int hdr_len);
71+
int lwtunnel_cmp_encap(struct lwtunnel_state *a, struct lwtunnel_state *b);
72+
73+
#else
74+
75+
static inline void lwtunnel_state_get(struct lwtunnel_state *lws)
76+
{
77+
}
78+
79+
static inline void lwtunnel_state_put(struct lwtunnel_state *lws)
80+
{
81+
}
82+
83+
static inline bool lwtunnel_output_redirect(struct lwtunnel_state *lwtstate)
84+
{
85+
return false;
86+
}
87+
88+
static inline int lwtunnel_encap_add_ops(const struct lwtunnel_encap_ops *op,
89+
unsigned int num)
90+
{
91+
return -EOPNOTSUPP;
92+
93+
}
94+
95+
static inline int lwtunnel_encap_del_ops(const struct lwtunnel_encap_ops *op,
96+
unsigned int num)
97+
{
98+
return -EOPNOTSUPP;
99+
}
100+
101+
static inline int lwtunnel_build_state(struct net_device *dev, u16 encap_type,
102+
struct nlattr *encap,
103+
struct lwtunnel_state **lws)
104+
{
105+
return -EOPNOTSUPP;
106+
}
107+
108+
static inline int lwtunnel_fill_encap(struct sk_buff *skb,
109+
struct lwtunnel_state *lwtstate)
110+
{
111+
return 0;
112+
}
113+
114+
static inline int lwtunnel_get_encap_size(struct lwtunnel_state *lwtstate)
115+
{
116+
return 0;
117+
}
118+
119+
static inline struct lwtunnel_state *lwtunnel_state_alloc(int hdr_len)
120+
{
121+
return NULL;
122+
}
123+
124+
static inline int lwtunnel_cmp_encap(struct lwtunnel_state *a,
125+
struct lwtunnel_state *b)
126+
{
127+
return 0;
128+
}
129+
130+
#endif
131+
132+
#endif /* __NET_LWTUNNEL_H */

include/uapi/linux/lwtunnel.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#ifndef _UAPI_LWTUNNEL_H_
2+
#define _UAPI_LWTUNNEL_H_
3+
4+
#include <linux/types.h>
5+
6+
enum lwtunnel_encap_types {
7+
LWTUNNEL_ENCAP_NONE,
8+
LWTUNNEL_ENCAP_MPLS,
9+
__LWTUNNEL_ENCAP_MAX,
10+
};
11+
12+
#define LWTUNNEL_ENCAP_MAX (__LWTUNNEL_ENCAP_MAX - 1)
13+
14+
15+
#endif /* _UAPI_LWTUNNEL_H_ */

net/Kconfig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,13 @@ source "net/caif/Kconfig"
374374
source "net/ceph/Kconfig"
375375
source "net/nfc/Kconfig"
376376

377+
config LWTUNNEL
378+
bool "Network light weight tunnels"
379+
---help---
380+
This feature provides an infrastructure to support light weight
381+
tunnels like mpls. There is no netdevice associated with a light
382+
weight tunnel endpoint. Tunnel encapsulation parameters are stored
383+
with light weight tunnel state associated with fib routes.
377384

378385
endif # if NET
379386

net/core/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,4 @@ obj-$(CONFIG_NETWORK_PHY_TIMESTAMPING) += timestamping.o
2323
obj-$(CONFIG_NET_PTP_CLASSIFY) += ptp_classifier.o
2424
obj-$(CONFIG_CGROUP_NET_PRIO) += netprio_cgroup.o
2525
obj-$(CONFIG_CGROUP_NET_CLASSID) += netclassid_cgroup.o
26+
obj-$(CONFIG_LWTUNNEL) += lwtunnel.o

net/core/lwtunnel.c

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
/*
2+
* lwtunnel Infrastructure for light weight tunnels like mpls
3+
*
4+
* Authors: Roopa Prabhu, <[email protected]>
5+
*
6+
* This program is free software; you can redistribute it and/or
7+
* modify it under the terms of the GNU General Public License
8+
* as published by the Free Software Foundation; either version
9+
* 2 of the License, or (at your option) any later version.
10+
*
11+
*/
12+
13+
#include <linux/capability.h>
14+
#include <linux/module.h>
15+
#include <linux/types.h>
16+
#include <linux/kernel.h>
17+
#include <linux/slab.h>
18+
#include <linux/uaccess.h>
19+
#include <linux/skbuff.h>
20+
#include <linux/netdevice.h>
21+
#include <linux/lwtunnel.h>
22+
#include <linux/in.h>
23+
#include <linux/init.h>
24+
#include <linux/err.h>
25+
26+
#include <net/lwtunnel.h>
27+
#include <net/rtnetlink.h>
28+
29+
struct lwtunnel_state *lwtunnel_state_alloc(int encap_len)
30+
{
31+
struct lwtunnel_state *lws;
32+
33+
lws = kzalloc(sizeof(*lws) + encap_len, GFP_ATOMIC);
34+
35+
return lws;
36+
}
37+
EXPORT_SYMBOL(lwtunnel_state_alloc);
38+
39+
const struct lwtunnel_encap_ops __rcu *
40+
lwtun_encaps[LWTUNNEL_ENCAP_MAX + 1] __read_mostly;
41+
42+
int lwtunnel_encap_add_ops(const struct lwtunnel_encap_ops *ops,
43+
unsigned int num)
44+
{
45+
if (num > LWTUNNEL_ENCAP_MAX)
46+
return -ERANGE;
47+
48+
return !cmpxchg((const struct lwtunnel_encap_ops **)
49+
&lwtun_encaps[num],
50+
NULL, ops) ? 0 : -1;
51+
}
52+
EXPORT_SYMBOL(lwtunnel_encap_add_ops);
53+
54+
int lwtunnel_encap_del_ops(const struct lwtunnel_encap_ops *ops,
55+
unsigned int encap_type)
56+
{
57+
int ret;
58+
59+
if (encap_type == LWTUNNEL_ENCAP_NONE ||
60+
encap_type > LWTUNNEL_ENCAP_MAX)
61+
return -ERANGE;
62+
63+
ret = (cmpxchg((const struct lwtunnel_encap_ops **)
64+
&lwtun_encaps[encap_type],
65+
ops, NULL) == ops) ? 0 : -1;
66+
67+
synchronize_net();
68+
69+
return ret;
70+
}
71+
EXPORT_SYMBOL(lwtunnel_encap_del_ops);
72+
73+
int lwtunnel_build_state(struct net_device *dev, u16 encap_type,
74+
struct nlattr *encap, struct lwtunnel_state **lws)
75+
{
76+
const struct lwtunnel_encap_ops *ops;
77+
int ret = -EINVAL;
78+
79+
if (encap_type == LWTUNNEL_ENCAP_NONE ||
80+
encap_type > LWTUNNEL_ENCAP_MAX)
81+
return ret;
82+
83+
ret = -EOPNOTSUPP;
84+
rcu_read_lock();
85+
ops = rcu_dereference(lwtun_encaps[encap_type]);
86+
if (likely(ops && ops->build_state))
87+
ret = ops->build_state(dev, encap, lws);
88+
rcu_read_unlock();
89+
90+
return ret;
91+
}
92+
EXPORT_SYMBOL(lwtunnel_build_state);
93+
94+
int lwtunnel_fill_encap(struct sk_buff *skb, struct lwtunnel_state *lwtstate)
95+
{
96+
const struct lwtunnel_encap_ops *ops;
97+
struct nlattr *nest;
98+
int ret = -EINVAL;
99+
100+
if (!lwtstate)
101+
return 0;
102+
103+
if (lwtstate->type == LWTUNNEL_ENCAP_NONE ||
104+
lwtstate->type > LWTUNNEL_ENCAP_MAX)
105+
return 0;
106+
107+
ret = -EOPNOTSUPP;
108+
nest = nla_nest_start(skb, RTA_ENCAP);
109+
rcu_read_lock();
110+
ops = rcu_dereference(lwtun_encaps[lwtstate->type]);
111+
if (likely(ops && ops->fill_encap))
112+
ret = ops->fill_encap(skb, lwtstate);
113+
rcu_read_unlock();
114+
115+
if (ret)
116+
goto nla_put_failure;
117+
nla_nest_end(skb, nest);
118+
ret = nla_put_u16(skb, RTA_ENCAP_TYPE, lwtstate->type);
119+
if (ret)
120+
goto nla_put_failure;
121+
122+
return 0;
123+
124+
nla_put_failure:
125+
nla_nest_cancel(skb, nest);
126+
127+
return (ret == -EOPNOTSUPP ? 0 : ret);
128+
}
129+
EXPORT_SYMBOL(lwtunnel_fill_encap);
130+
131+
int lwtunnel_get_encap_size(struct lwtunnel_state *lwtstate)
132+
{
133+
const struct lwtunnel_encap_ops *ops;
134+
int ret = 0;
135+
136+
if (!lwtstate)
137+
return 0;
138+
139+
if (lwtstate->type == LWTUNNEL_ENCAP_NONE ||
140+
lwtstate->type > LWTUNNEL_ENCAP_MAX)
141+
return 0;
142+
143+
rcu_read_lock();
144+
ops = rcu_dereference(lwtun_encaps[lwtstate->type]);
145+
if (likely(ops && ops->get_encap_size))
146+
ret = nla_total_size(ops->get_encap_size(lwtstate));
147+
rcu_read_unlock();
148+
149+
return ret;
150+
}
151+
EXPORT_SYMBOL(lwtunnel_get_encap_size);
152+
153+
int lwtunnel_cmp_encap(struct lwtunnel_state *a, struct lwtunnel_state *b)
154+
{
155+
const struct lwtunnel_encap_ops *ops;
156+
int ret = 0;
157+
158+
if (!a && !b)
159+
return 0;
160+
161+
if (!a || !b)
162+
return 1;
163+
164+
if (a->type != b->type)
165+
return 1;
166+
167+
if (a->type == LWTUNNEL_ENCAP_NONE ||
168+
a->type > LWTUNNEL_ENCAP_MAX)
169+
return 0;
170+
171+
rcu_read_lock();
172+
ops = rcu_dereference(lwtun_encaps[a->type]);
173+
if (likely(ops && ops->cmp_encap))
174+
ret = ops->cmp_encap(a, b);
175+
rcu_read_unlock();
176+
177+
return ret;
178+
}
179+
EXPORT_SYMBOL(lwtunnel_cmp_encap);

0 commit comments

Comments
 (0)