Linux Audio

Check our new training course

Embedded Linux training

Mar 10-20, 2025, special US time zones
Register
Loading...
v4.10.11
  1/*
  2 * Copyright (c) 2007-2014 Nicira, Inc.
  3 *
  4 * This program is free software; you can redistribute it and/or
  5 * modify it under the terms of version 2 of the GNU General Public
  6 * License as published by the Free Software Foundation.
  7 *
  8 * This program is distributed in the hope that it will be useful, but
  9 * WITHOUT ANY WARRANTY; without even the implied warranty of
 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 11 * General Public License for more details.
 12 *
 13 * You should have received a copy of the GNU General Public License
 14 * along with this program; if not, write to the Free Software
 15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 16 * 02110-1301, USA
 17 */
 18
 19#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 20
 21#include <linux/if.h>
 22#include <linux/skbuff.h>
 23#include <linux/ip.h>
 24#include <linux/if_tunnel.h>
 25#include <linux/if_vlan.h>
 26#include <linux/in.h>
 27#include <linux/in_route.h>
 28#include <linux/inetdevice.h>
 29#include <linux/jhash.h>
 30#include <linux/list.h>
 31#include <linux/kernel.h>
 32#include <linux/module.h>
 33#include <linux/workqueue.h>
 34#include <linux/rculist.h>
 35#include <net/route.h>
 36#include <net/xfrm.h>
 37
 38#include <net/icmp.h>
 39#include <net/ip.h>
 40#include <net/ip_tunnels.h>
 41#include <net/gre.h>
 42#include <net/net_namespace.h>
 43#include <net/netns/generic.h>
 44#include <net/protocol.h>
 45
 46#include "datapath.h"
 47#include "vport.h"
 48#include "vport-netdev.h"
 49
 50static struct vport_ops ovs_gre_vport_ops;
 
 
 
 
 
 
 
 
 51
 52static struct vport *gre_tnl_create(const struct vport_parms *parms)
 53{
 54	struct net *net = ovs_dp_get_net(parms->dp);
 55	struct net_device *dev;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 56	struct vport *vport;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 57	int err;
 58
 59	vport = ovs_vport_alloc(0, &ovs_gre_vport_ops, parms);
 60	if (IS_ERR(vport))
 61		return vport;
 
 62
 63	rtnl_lock();
 64	dev = gretap_fb_dev_create(net, parms->name, NET_NAME_USER);
 65	if (IS_ERR(dev)) {
 66		rtnl_unlock();
 67		ovs_vport_free(vport);
 68		return ERR_CAST(dev);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 69	}
 70
 71	err = dev_change_flags(dev, dev->flags | IFF_UP);
 72	if (err < 0) {
 73		rtnl_delete_link(dev);
 74		rtnl_unlock();
 75		ovs_vport_free(vport);
 76		return ERR_PTR(err);
 
 
 77	}
 78
 79	rtnl_unlock();
 80	return vport;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 81}
 82
 83static struct vport *gre_create(const struct vport_parms *parms)
 
 
 
 
 
 
 84{
 85	struct vport *vport;
 86
 87	vport = gre_tnl_create(parms);
 88	if (IS_ERR(vport))
 89		return vport;
 
 
 
 
 90
 91	return ovs_netdev_link(vport, parms->name);
 92}
 93
 94static struct vport_ops ovs_gre_vport_ops = {
 95	.type		= OVS_VPORT_TYPE_GRE,
 96	.create		= gre_create,
 97	.send		= dev_queue_xmit,
 98	.destroy	= ovs_netdev_tunnel_destroy,
 99};
100
101static int __init ovs_gre_tnl_init(void)
 
 
 
102{
103	return ovs_vport_ops_register(&ovs_gre_vport_ops);
104}
105
106static void __exit ovs_gre_tnl_exit(void)
107{
108	ovs_vport_ops_unregister(&ovs_gre_vport_ops);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109}
110
111module_init(ovs_gre_tnl_init);
112module_exit(ovs_gre_tnl_exit);
 
 
 
 
 
 
 
 
 
113
114MODULE_DESCRIPTION("OVS: GRE switching port");
115MODULE_LICENSE("GPL");
116MODULE_ALIAS("vport-type-3");
 
 
 
 
v3.15
  1/*
  2 * Copyright (c) 2007-2013 Nicira, Inc.
  3 *
  4 * This program is free software; you can redistribute it and/or
  5 * modify it under the terms of version 2 of the GNU General Public
  6 * License as published by the Free Software Foundation.
  7 *
  8 * This program is distributed in the hope that it will be useful, but
  9 * WITHOUT ANY WARRANTY; without even the implied warranty of
 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 11 * General Public License for more details.
 12 *
 13 * You should have received a copy of the GNU General Public License
 14 * along with this program; if not, write to the Free Software
 15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 16 * 02110-1301, USA
 17 */
 18
 19#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 20
 21#include <linux/if.h>
 22#include <linux/skbuff.h>
 23#include <linux/ip.h>
 24#include <linux/if_tunnel.h>
 25#include <linux/if_vlan.h>
 26#include <linux/in.h>
 27#include <linux/in_route.h>
 28#include <linux/inetdevice.h>
 29#include <linux/jhash.h>
 30#include <linux/list.h>
 31#include <linux/kernel.h>
 
 32#include <linux/workqueue.h>
 33#include <linux/rculist.h>
 34#include <net/route.h>
 35#include <net/xfrm.h>
 36
 37#include <net/icmp.h>
 38#include <net/ip.h>
 39#include <net/ip_tunnels.h>
 40#include <net/gre.h>
 41#include <net/net_namespace.h>
 42#include <net/netns/generic.h>
 43#include <net/protocol.h>
 44
 45#include "datapath.h"
 46#include "vport.h"
 
 47
 48/* Returns the least-significant 32 bits of a __be64. */
 49static __be32 be64_get_low32(__be64 x)
 50{
 51#ifdef __BIG_ENDIAN
 52	return (__force __be32)x;
 53#else
 54	return (__force __be32)((__force u64)x >> 32);
 55#endif
 56}
 57
 58static __be16 filter_tnl_flags(__be16 flags)
 59{
 60	return flags & (TUNNEL_CSUM | TUNNEL_KEY);
 61}
 62
 63static struct sk_buff *__build_header(struct sk_buff *skb,
 64				      int tunnel_hlen)
 65{
 66	const struct ovs_key_ipv4_tunnel *tun_key = OVS_CB(skb)->tun_key;
 67	struct tnl_ptk_info tpi;
 68
 69	skb = gre_handle_offloads(skb, !!(tun_key->tun_flags & TUNNEL_CSUM));
 70	if (IS_ERR(skb))
 71		return NULL;
 72
 73	tpi.flags = filter_tnl_flags(tun_key->tun_flags);
 74	tpi.proto = htons(ETH_P_TEB);
 75	tpi.key = be64_get_low32(tun_key->tun_id);
 76	tpi.seq = 0;
 77	gre_build_header(skb, &tpi, tunnel_hlen);
 78
 79	return skb;
 80}
 81
 82static __be64 key_to_tunnel_id(__be32 key, __be32 seq)
 83{
 84#ifdef __BIG_ENDIAN
 85	return (__force __be64)((__force u64)seq << 32 | (__force u32)key);
 86#else
 87	return (__force __be64)((__force u64)key << 32 | (__force u32)seq);
 88#endif
 89}
 90
 91/* Called with rcu_read_lock and BH disabled. */
 92static int gre_rcv(struct sk_buff *skb,
 93		   const struct tnl_ptk_info *tpi)
 94{
 95	struct ovs_key_ipv4_tunnel tun_key;
 96	struct ovs_net *ovs_net;
 97	struct vport *vport;
 98	__be64 key;
 99
100	ovs_net = net_generic(dev_net(skb->dev), ovs_net_id);
101	vport = rcu_dereference(ovs_net->vport_net.gre_vport);
102	if (unlikely(!vport))
103		return PACKET_REJECT;
104
105	key = key_to_tunnel_id(tpi->key, tpi->seq);
106	ovs_flow_tun_key_init(&tun_key, ip_hdr(skb), key,
107			      filter_tnl_flags(tpi->flags));
108
109	ovs_vport_receive(vport, skb, &tun_key);
110	return PACKET_RCVD;
111}
112
113static int gre_tnl_send(struct vport *vport, struct sk_buff *skb)
114{
115	struct net *net = ovs_dp_get_net(vport->dp);
116	struct flowi4 fl;
117	struct rtable *rt;
118	int min_headroom;
119	int tunnel_hlen;
120	__be16 df;
121	int err;
122
123	if (unlikely(!OVS_CB(skb)->tun_key)) {
124		err = -EINVAL;
125		goto error;
126	}
127
128	/* Route lookup */
129	memset(&fl, 0, sizeof(fl));
130	fl.daddr = OVS_CB(skb)->tun_key->ipv4_dst;
131	fl.saddr = OVS_CB(skb)->tun_key->ipv4_src;
132	fl.flowi4_tos = RT_TOS(OVS_CB(skb)->tun_key->ipv4_tos);
133	fl.flowi4_mark = skb->mark;
134	fl.flowi4_proto = IPPROTO_GRE;
135
136	rt = ip_route_output_key(net, &fl);
137	if (IS_ERR(rt))
138		return PTR_ERR(rt);
139
140	tunnel_hlen = ip_gre_calc_hlen(OVS_CB(skb)->tun_key->tun_flags);
141
142	min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len
143			+ tunnel_hlen + sizeof(struct iphdr)
144			+ (vlan_tx_tag_present(skb) ? VLAN_HLEN : 0);
145	if (skb_headroom(skb) < min_headroom || skb_header_cloned(skb)) {
146		int head_delta = SKB_DATA_ALIGN(min_headroom -
147						skb_headroom(skb) +
148						16);
149		err = pskb_expand_head(skb, max_t(int, head_delta, 0),
150					0, GFP_ATOMIC);
151		if (unlikely(err))
152			goto err_free_rt;
153	}
154
155	if (vlan_tx_tag_present(skb)) {
156		if (unlikely(!__vlan_put_tag(skb,
157					     skb->vlan_proto,
158					     vlan_tx_tag_get(skb)))) {
159			err = -ENOMEM;
160			goto err_free_rt;
161		}
162		skb->vlan_tci = 0;
163	}
164
165	/* Push Tunnel header. */
166	skb = __build_header(skb, tunnel_hlen);
167	if (unlikely(!skb)) {
168		err = 0;
169		goto err_free_rt;
170	}
171
172	df = OVS_CB(skb)->tun_key->tun_flags & TUNNEL_DONT_FRAGMENT ?
173		htons(IP_DF) : 0;
174
175	skb->local_df = 1;
176
177	return iptunnel_xmit(skb->sk, rt, skb, fl.saddr,
178			     OVS_CB(skb)->tun_key->ipv4_dst, IPPROTO_GRE,
179			     OVS_CB(skb)->tun_key->ipv4_tos,
180			     OVS_CB(skb)->tun_key->ipv4_ttl, df, false);
181err_free_rt:
182	ip_rt_put(rt);
183error:
184	return err;
185}
186
187static struct gre_cisco_protocol gre_protocol = {
188	.handler        = gre_rcv,
189	.priority       = 1,
190};
191
192static int gre_ports;
193static int gre_init(void)
194{
195	int err;
196
197	gre_ports++;
198	if (gre_ports > 1)
199		return 0;
200
201	err = gre_cisco_register(&gre_protocol);
202	if (err)
203		pr_warn("cannot register gre protocol handler\n");
204
205	return err;
206}
207
208static void gre_exit(void)
209{
210	gre_ports--;
211	if (gre_ports > 0)
212		return;
 
213
214	gre_cisco_unregister(&gre_protocol);
215}
216
217static const char *gre_get_name(const struct vport *vport)
218{
219	return vport_priv(vport);
220}
221
222static struct vport *gre_create(const struct vport_parms *parms)
223{
224	struct net *net = ovs_dp_get_net(parms->dp);
225	struct ovs_net *ovs_net;
226	struct vport *vport;
227	int err;
228
229	err = gre_init();
230	if (err)
231		return ERR_PTR(err);
232
233	ovs_net = net_generic(net, ovs_net_id);
234	if (ovsl_dereference(ovs_net->vport_net.gre_vport)) {
235		vport = ERR_PTR(-EEXIST);
236		goto error;
237	}
238
239	vport = ovs_vport_alloc(IFNAMSIZ, &ovs_gre_vport_ops, parms);
240	if (IS_ERR(vport))
241		goto error;
242
243	strncpy(vport_priv(vport), parms->name, IFNAMSIZ);
244	rcu_assign_pointer(ovs_net->vport_net.gre_vport, vport);
245	return vport;
246
247error:
248	gre_exit();
249	return vport;
250}
251
252static void gre_tnl_destroy(struct vport *vport)
253{
254	struct net *net = ovs_dp_get_net(vport->dp);
255	struct ovs_net *ovs_net;
256
257	ovs_net = net_generic(net, ovs_net_id);
258
259	rcu_assign_pointer(ovs_net->vport_net.gre_vport, NULL);
260	ovs_vport_deferred_free(vport);
261	gre_exit();
262}
263
264const struct vport_ops ovs_gre_vport_ops = {
265	.type		= OVS_VPORT_TYPE_GRE,
266	.create		= gre_create,
267	.destroy	= gre_tnl_destroy,
268	.get_name	= gre_get_name,
269	.send		= gre_tnl_send,
270};