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