162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2007-2014 Nicira, Inc.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/if.h>
962306a36Sopenharmony_ci#include <linux/skbuff.h>
1062306a36Sopenharmony_ci#include <linux/ip.h>
1162306a36Sopenharmony_ci#include <linux/if_tunnel.h>
1262306a36Sopenharmony_ci#include <linux/if_vlan.h>
1362306a36Sopenharmony_ci#include <linux/in.h>
1462306a36Sopenharmony_ci#include <linux/in_route.h>
1562306a36Sopenharmony_ci#include <linux/inetdevice.h>
1662306a36Sopenharmony_ci#include <linux/jhash.h>
1762306a36Sopenharmony_ci#include <linux/list.h>
1862306a36Sopenharmony_ci#include <linux/kernel.h>
1962306a36Sopenharmony_ci#include <linux/module.h>
2062306a36Sopenharmony_ci#include <linux/workqueue.h>
2162306a36Sopenharmony_ci#include <linux/rculist.h>
2262306a36Sopenharmony_ci#include <net/route.h>
2362306a36Sopenharmony_ci#include <net/xfrm.h>
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#include <net/icmp.h>
2662306a36Sopenharmony_ci#include <net/ip.h>
2762306a36Sopenharmony_ci#include <net/ip_tunnels.h>
2862306a36Sopenharmony_ci#include <net/gre.h>
2962306a36Sopenharmony_ci#include <net/net_namespace.h>
3062306a36Sopenharmony_ci#include <net/netns/generic.h>
3162306a36Sopenharmony_ci#include <net/protocol.h>
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#include "datapath.h"
3462306a36Sopenharmony_ci#include "vport.h"
3562306a36Sopenharmony_ci#include "vport-netdev.h"
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic struct vport_ops ovs_gre_vport_ops;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistatic struct vport *gre_tnl_create(const struct vport_parms *parms)
4062306a36Sopenharmony_ci{
4162306a36Sopenharmony_ci	struct net *net = ovs_dp_get_net(parms->dp);
4262306a36Sopenharmony_ci	struct net_device *dev;
4362306a36Sopenharmony_ci	struct vport *vport;
4462306a36Sopenharmony_ci	int err;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	vport = ovs_vport_alloc(0, &ovs_gre_vport_ops, parms);
4762306a36Sopenharmony_ci	if (IS_ERR(vport))
4862306a36Sopenharmony_ci		return vport;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	rtnl_lock();
5162306a36Sopenharmony_ci	dev = gretap_fb_dev_create(net, parms->name, NET_NAME_USER);
5262306a36Sopenharmony_ci	if (IS_ERR(dev)) {
5362306a36Sopenharmony_ci		rtnl_unlock();
5462306a36Sopenharmony_ci		ovs_vport_free(vport);
5562306a36Sopenharmony_ci		return ERR_CAST(dev);
5662306a36Sopenharmony_ci	}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	err = dev_change_flags(dev, dev->flags | IFF_UP, NULL);
5962306a36Sopenharmony_ci	if (err < 0) {
6062306a36Sopenharmony_ci		rtnl_delete_link(dev, 0, NULL);
6162306a36Sopenharmony_ci		rtnl_unlock();
6262306a36Sopenharmony_ci		ovs_vport_free(vport);
6362306a36Sopenharmony_ci		return ERR_PTR(err);
6462306a36Sopenharmony_ci	}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	rtnl_unlock();
6762306a36Sopenharmony_ci	return vport;
6862306a36Sopenharmony_ci}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic struct vport *gre_create(const struct vport_parms *parms)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	struct vport *vport;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	vport = gre_tnl_create(parms);
7562306a36Sopenharmony_ci	if (IS_ERR(vport))
7662306a36Sopenharmony_ci		return vport;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	return ovs_netdev_link(vport, parms->name);
7962306a36Sopenharmony_ci}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistatic struct vport_ops ovs_gre_vport_ops = {
8262306a36Sopenharmony_ci	.type		= OVS_VPORT_TYPE_GRE,
8362306a36Sopenharmony_ci	.create		= gre_create,
8462306a36Sopenharmony_ci	.send		= dev_queue_xmit,
8562306a36Sopenharmony_ci	.destroy	= ovs_netdev_tunnel_destroy,
8662306a36Sopenharmony_ci};
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic int __init ovs_gre_tnl_init(void)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	return ovs_vport_ops_register(&ovs_gre_vport_ops);
9162306a36Sopenharmony_ci}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistatic void __exit ovs_gre_tnl_exit(void)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	ovs_vport_ops_unregister(&ovs_gre_vport_ops);
9662306a36Sopenharmony_ci}
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_cimodule_init(ovs_gre_tnl_init);
9962306a36Sopenharmony_cimodule_exit(ovs_gre_tnl_exit);
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ciMODULE_DESCRIPTION("OVS: GRE switching port");
10262306a36Sopenharmony_ciMODULE_LICENSE("GPL");
10362306a36Sopenharmony_ciMODULE_ALIAS("vport-type-3");
104