History

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.

Roopa Prabhu committed 11 years ago

Commit 499a2421 parent a0d9a866 files · +340 −0Browse files

Unified · Split

6 files
  1. include/linux/lwtunnel.h +6 −0
  2. include/net/lwtunnel.h +132 −0
  3. include/uapi/linux/lwtunnel.h +15 −0
  4. net/Kconfig +7 −0
  5. net/core/Makefile +1 −0
  6. net/core/lwtunnel.c +179 −0
include/linux/lwtunnel.h+6−0
@@ -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+132−0
@@ -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
16struct lwtunnel_state {
17 __u16 type;
18 __u16 flags;
19 atomic_t refcnt;
20 int len;
21 __u8 data[0];
22};
23
24struct 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
34extern const struct lwtunnel_encap_ops __rcu *
35 lwtun_encaps[LWTUNNEL_ENCAP_MAX+1];
36
37#ifdef CONFIG_LWTUNNEL
38static inline void lwtunnel_state_get(struct lwtunnel_state *lws)
39{
40 atomic_inc(&lws->refcnt);
41}
42
43static 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
52static 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
60int lwtunnel_encap_add_ops(const struct lwtunnel_encap_ops *op,
61 unsigned int num);
62int lwtunnel_encap_del_ops(const struct lwtunnel_encap_ops *op,
63 unsigned int num);
64int lwtunnel_build_state(struct net_device *dev, u16 encap_type,
65 struct nlattr *encap,
66 struct lwtunnel_state **lws);
67int lwtunnel_fill_encap(struct sk_buff *skb,
68 struct lwtunnel_state *lwtstate);
69int lwtunnel_get_encap_size(struct lwtunnel_state *lwtstate);
70struct lwtunnel_state *lwtunnel_state_alloc(int hdr_len);
71int lwtunnel_cmp_encap(struct lwtunnel_state *a, struct lwtunnel_state *b);
72
73#else
74
75static inline void lwtunnel_state_get(struct lwtunnel_state *lws)
76{
77}
78
79static inline void lwtunnel_state_put(struct lwtunnel_state *lws)
80{
81}
82
83static inline bool lwtunnel_output_redirect(struct lwtunnel_state *lwtstate)
84{
85 return false;
86}
87
88static inline int lwtunnel_encap_add_ops(const struct lwtunnel_encap_ops *op,
89 unsigned int num)
90{
91 return -EOPNOTSUPP;
92
93}
94
95static inline int lwtunnel_encap_del_ops(const struct lwtunnel_encap_ops *op,
96 unsigned int num)
97{
98 return -EOPNOTSUPP;
99}
100
101static 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
108static inline int lwtunnel_fill_encap(struct sk_buff *skb,
109 struct lwtunnel_state *lwtstate)
110{
111 return 0;
112}
113
114static inline int lwtunnel_get_encap_size(struct lwtunnel_state *lwtstate)
115{
116 return 0;
117}
118
119static inline struct lwtunnel_state *lwtunnel_state_alloc(int hdr_len)
120{
121 return NULL;
122}
123
124static 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+15−0
@@ -0,0 +1,15 @@
1#ifndef _UAPI_LWTUNNEL_H_
2#define _UAPI_LWTUNNEL_H_
3
4#include <linux/types.h>
5
6enum 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+7−0
@@ -374,6 +374,13 @@ source "net/caif/Kconfig" · 373 unmodified lines
374source "net/ceph/Kconfig"374source "net/ceph/Kconfig"
375source "net/nfc/Kconfig"375source "net/nfc/Kconfig"
376 376
377config 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.
377 384
378endif # if NET385endif # if NET
379 386
net/core/Makefile+1−0
@@ -23,3 +23,4 @@ obj-$(CONFIG_NETWORK_PHY_TIMESTAMPING) += timestamping.o · 22 unmodified lines
23obj-$(CONFIG_NET_PTP_CLASSIFY) += ptp_classifier.o23obj-$(CONFIG_NET_PTP_CLASSIFY) += ptp_classifier.o
24obj-$(CONFIG_CGROUP_NET_PRIO) += netprio_cgroup.o24obj-$(CONFIG_CGROUP_NET_PRIO) += netprio_cgroup.o
25obj-$(CONFIG_CGROUP_NET_CLASSID) += netclassid_cgroup.o25obj-$(CONFIG_CGROUP_NET_CLASSID) += netclassid_cgroup.o
26obj-$(CONFIG_LWTUNNEL) += lwtunnel.o
net/core/lwtunnel.c+179−0
@@ -0,0 +1,179 @@
1/*
2 * lwtunnel Infrastructure for light weight tunnels like mpls
3 *
4 * Authors: Roopa Prabhu, <roopa@cumulusnetworks.com>
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
29struct 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}
37EXPORT_SYMBOL(lwtunnel_state_alloc);
38
39const struct lwtunnel_encap_ops __rcu *
40 lwtun_encaps[LWTUNNEL_ENCAP_MAX + 1] __read_mostly;
41
42int 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}
52EXPORT_SYMBOL(lwtunnel_encap_add_ops);
53
54int 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}
71EXPORT_SYMBOL(lwtunnel_encap_del_ops);
72
73int 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}
92EXPORT_SYMBOL(lwtunnel_build_state);
93
94int 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
124nla_put_failure:
125 nla_nest_cancel(skb, nest);
126
127 return (ret == -EOPNOTSUPP ? 0 : ret);
128}
129EXPORT_SYMBOL(lwtunnel_fill_encap);
130
131int 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}
151EXPORT_SYMBOL(lwtunnel_get_encap_size);
152
153int 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}
179EXPORT_SYMBOL(lwtunnel_cmp_encap);