xref: /openbmc/linux/net/openvswitch/vport-geneve.c (revision 7ae9fb1b7ecbb5d85d07857943f677fd1a559b18)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2f5796684SJesse Gross /*
3f5796684SJesse Gross  * Copyright (c) 2014 Nicira, Inc.
4f5796684SJesse Gross  */
5f5796684SJesse Gross 
6f5796684SJesse Gross #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
7f5796684SJesse Gross 
8f5796684SJesse Gross #include <linux/in.h>
9f5796684SJesse Gross #include <linux/ip.h>
10f5796684SJesse Gross #include <linux/net.h>
11f5796684SJesse Gross #include <linux/rculist.h>
12f5796684SJesse Gross #include <linux/udp.h>
13f5796684SJesse Gross #include <linux/if_vlan.h>
1462b9c8d0SThomas Graf #include <linux/module.h>
15f5796684SJesse Gross 
16f5796684SJesse Gross #include <net/geneve.h>
17f5796684SJesse Gross #include <net/icmp.h>
18f5796684SJesse Gross #include <net/ip.h>
19f5796684SJesse Gross #include <net/route.h>
20f5796684SJesse Gross #include <net/udp.h>
21f5796684SJesse Gross #include <net/xfrm.h>
22f5796684SJesse Gross 
23f5796684SJesse Gross #include "datapath.h"
24f5796684SJesse Gross #include "vport.h"
256b001e68SPravin B Shelar #include "vport-netdev.h"
26f5796684SJesse Gross 
2762b9c8d0SThomas Graf static struct vport_ops ovs_geneve_vport_ops;
28f5796684SJesse Gross /**
29f5796684SJesse Gross  * struct geneve_port - Keeps track of open UDP ports
306b001e68SPravin B Shelar  * @dst_port: destination port.
31f5796684SJesse Gross  */
32f5796684SJesse Gross struct geneve_port {
332f7066adSJean Sacren 	u16 dst_port;
34f5796684SJesse Gross };
35f5796684SJesse Gross 
geneve_vport(const struct vport * vport)36f5796684SJesse Gross static inline struct geneve_port *geneve_vport(const struct vport *vport)
37f5796684SJesse Gross {
38f5796684SJesse Gross 	return vport_priv(vport);
39f5796684SJesse Gross }
40f5796684SJesse Gross 
geneve_get_options(const struct vport * vport,struct sk_buff * skb)41f5796684SJesse Gross static int geneve_get_options(const struct vport *vport,
42f5796684SJesse Gross 			      struct sk_buff *skb)
43f5796684SJesse Gross {
44f5796684SJesse Gross 	struct geneve_port *geneve_port = geneve_vport(vport);
45f5796684SJesse Gross 
462f7066adSJean Sacren 	if (nla_put_u16(skb, OVS_TUNNEL_ATTR_DST_PORT, geneve_port->dst_port))
47f5796684SJesse Gross 		return -EMSGSIZE;
48f5796684SJesse Gross 	return 0;
49f5796684SJesse Gross }
50f5796684SJesse Gross 
geneve_tnl_create(const struct vport_parms * parms)51f5796684SJesse Gross static struct vport *geneve_tnl_create(const struct vport_parms *parms)
52f5796684SJesse Gross {
53f5796684SJesse Gross 	struct net *net = ovs_dp_get_net(parms->dp);
54f5796684SJesse Gross 	struct nlattr *options = parms->options;
55f5796684SJesse Gross 	struct geneve_port *geneve_port;
566b001e68SPravin B Shelar 	struct net_device *dev;
57f5796684SJesse Gross 	struct vport *vport;
58f5796684SJesse Gross 	struct nlattr *a;
59f5796684SJesse Gross 	u16 dst_port;
606b001e68SPravin B Shelar 	int err;
61f5796684SJesse Gross 
62f5796684SJesse Gross 	if (!options) {
63f5796684SJesse Gross 		err = -EINVAL;
64f5796684SJesse Gross 		goto error;
65f5796684SJesse Gross 	}
66f5796684SJesse Gross 
67f5796684SJesse Gross 	a = nla_find_nested(options, OVS_TUNNEL_ATTR_DST_PORT);
68f5796684SJesse Gross 	if (a && nla_len(a) == sizeof(u16)) {
69f5796684SJesse Gross 		dst_port = nla_get_u16(a);
70f5796684SJesse Gross 	} else {
71f5796684SJesse Gross 		/* Require destination port from userspace. */
72f5796684SJesse Gross 		err = -EINVAL;
73f5796684SJesse Gross 		goto error;
74f5796684SJesse Gross 	}
75f5796684SJesse Gross 
76f5796684SJesse Gross 	vport = ovs_vport_alloc(sizeof(struct geneve_port),
77f5796684SJesse Gross 				&ovs_geneve_vport_ops, parms);
78f5796684SJesse Gross 	if (IS_ERR(vport))
79f5796684SJesse Gross 		return vport;
80f5796684SJesse Gross 
81f5796684SJesse Gross 	geneve_port = geneve_vport(vport);
822f7066adSJean Sacren 	geneve_port->dst_port = dst_port;
83f5796684SJesse Gross 
846b001e68SPravin B Shelar 	rtnl_lock();
856b001e68SPravin B Shelar 	dev = geneve_dev_create_fb(net, parms->name, NET_NAME_USER, dst_port);
866b001e68SPravin B Shelar 	if (IS_ERR(dev)) {
876b001e68SPravin B Shelar 		rtnl_unlock();
88f5796684SJesse Gross 		ovs_vport_free(vport);
896b001e68SPravin B Shelar 		return ERR_CAST(dev);
90f5796684SJesse Gross 	}
91f5796684SJesse Gross 
92567c5e13SPetr Machata 	err = dev_change_flags(dev, dev->flags | IFF_UP, NULL);
934b5b9ba5SMartynas Pumputis 	if (err < 0) {
94*f3a63cceSHangbin Liu 		rtnl_delete_link(dev, 0, NULL);
954b5b9ba5SMartynas Pumputis 		rtnl_unlock();
964b5b9ba5SMartynas Pumputis 		ovs_vport_free(vport);
974b5b9ba5SMartynas Pumputis 		goto error;
984b5b9ba5SMartynas Pumputis 	}
994b5b9ba5SMartynas Pumputis 
1006b001e68SPravin B Shelar 	rtnl_unlock();
101f5796684SJesse Gross 	return vport;
102f5796684SJesse Gross error:
103f5796684SJesse Gross 	return ERR_PTR(err);
104f5796684SJesse Gross }
105f5796684SJesse Gross 
geneve_create(const struct vport_parms * parms)1066b001e68SPravin B Shelar static struct vport *geneve_create(const struct vport_parms *parms)
107f5796684SJesse Gross {
1086b001e68SPravin B Shelar 	struct vport *vport;
109f5796684SJesse Gross 
1106b001e68SPravin B Shelar 	vport = geneve_tnl_create(parms);
1116b001e68SPravin B Shelar 	if (IS_ERR(vport))
1126b001e68SPravin B Shelar 		return vport;
113f5796684SJesse Gross 
1146b001e68SPravin B Shelar 	return ovs_netdev_link(vport, parms->name);
1158f0aad6fSWenyu Zhang }
1168f0aad6fSWenyu Zhang 
11762b9c8d0SThomas Graf static struct vport_ops ovs_geneve_vport_ops = {
118f5796684SJesse Gross 	.type		= OVS_VPORT_TYPE_GENEVE,
1196b001e68SPravin B Shelar 	.create		= geneve_create,
1206b001e68SPravin B Shelar 	.destroy	= ovs_netdev_tunnel_destroy,
121f5796684SJesse Gross 	.get_options	= geneve_get_options,
122aec15924SPravin B Shelar 	.send		= dev_queue_xmit,
123f5796684SJesse Gross };
12462b9c8d0SThomas Graf 
ovs_geneve_tnl_init(void)12562b9c8d0SThomas Graf static int __init ovs_geneve_tnl_init(void)
12662b9c8d0SThomas Graf {
12762b9c8d0SThomas Graf 	return ovs_vport_ops_register(&ovs_geneve_vport_ops);
12862b9c8d0SThomas Graf }
12962b9c8d0SThomas Graf 
ovs_geneve_tnl_exit(void)13062b9c8d0SThomas Graf static void __exit ovs_geneve_tnl_exit(void)
13162b9c8d0SThomas Graf {
13262b9c8d0SThomas Graf 	ovs_vport_ops_unregister(&ovs_geneve_vport_ops);
13362b9c8d0SThomas Graf }
13462b9c8d0SThomas Graf 
13562b9c8d0SThomas Graf module_init(ovs_geneve_tnl_init);
13662b9c8d0SThomas Graf module_exit(ovs_geneve_tnl_exit);
13762b9c8d0SThomas Graf 
138fc4fa6e1SMasanari Iida MODULE_DESCRIPTION("OVS: Geneve switching port");
13962b9c8d0SThomas Graf MODULE_LICENSE("GPL");
14062b9c8d0SThomas Graf MODULE_ALIAS("vport-type-5");
141