1 /* 2 * Copyright (c) 2014 Nicira, Inc. 3 * Copyright (c) 2013 Cisco Systems, Inc. 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of version 2 of the GNU General Public 7 * License as published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it will be useful, but 10 * WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 17 * 02110-1301, USA 18 */ 19 20 #include <linux/kernel.h> 21 #include <linux/skbuff.h> 22 #include <linux/openvswitch.h> 23 #include <linux/module.h> 24 #include <net/udp.h> 25 #include <net/ip_tunnels.h> 26 #include <net/rtnetlink.h> 27 #include <net/vxlan.h> 28 29 #include "datapath.h" 30 #include "vport.h" 31 #include "vport-netdev.h" 32 33 static struct vport_ops ovs_vxlan_netdev_vport_ops; 34 35 static int vxlan_get_options(const struct vport *vport, struct sk_buff *skb) 36 { 37 struct vxlan_dev *vxlan = netdev_priv(vport->dev); 38 __be16 dst_port = vxlan->cfg.dst_port; 39 40 if (nla_put_u16(skb, OVS_TUNNEL_ATTR_DST_PORT, ntohs(dst_port))) 41 return -EMSGSIZE; 42 43 if (vxlan->cfg.flags & VXLAN_F_GBP) { 44 struct nlattr *exts; 45 46 exts = nla_nest_start_noflag(skb, OVS_TUNNEL_ATTR_EXTENSION); 47 if (!exts) 48 return -EMSGSIZE; 49 50 if (vxlan->cfg.flags & VXLAN_F_GBP && 51 nla_put_flag(skb, OVS_VXLAN_EXT_GBP)) 52 return -EMSGSIZE; 53 54 nla_nest_end(skb, exts); 55 } 56 57 return 0; 58 } 59 60 static const struct nla_policy exts_policy[OVS_VXLAN_EXT_MAX + 1] = { 61 [OVS_VXLAN_EXT_GBP] = { .type = NLA_FLAG, }, 62 }; 63 64 static int vxlan_configure_exts(struct vport *vport, struct nlattr *attr, 65 struct vxlan_config *conf) 66 { 67 struct nlattr *exts[OVS_VXLAN_EXT_MAX + 1]; 68 int err; 69 70 if (nla_len(attr) < sizeof(struct nlattr)) 71 return -EINVAL; 72 73 err = nla_parse_nested_deprecated(exts, OVS_VXLAN_EXT_MAX, attr, 74 exts_policy, NULL); 75 if (err < 0) 76 return err; 77 78 if (exts[OVS_VXLAN_EXT_GBP]) 79 conf->flags |= VXLAN_F_GBP; 80 81 return 0; 82 } 83 84 static struct vport *vxlan_tnl_create(const struct vport_parms *parms) 85 { 86 struct net *net = ovs_dp_get_net(parms->dp); 87 struct nlattr *options = parms->options; 88 struct net_device *dev; 89 struct vport *vport; 90 struct nlattr *a; 91 int err; 92 struct vxlan_config conf = { 93 .no_share = true, 94 .flags = VXLAN_F_COLLECT_METADATA | VXLAN_F_UDP_ZERO_CSUM6_RX, 95 /* Don't restrict the packets that can be sent by MTU */ 96 .mtu = IP_MAX_MTU, 97 }; 98 99 if (!options) { 100 err = -EINVAL; 101 goto error; 102 } 103 104 a = nla_find_nested(options, OVS_TUNNEL_ATTR_DST_PORT); 105 if (a && nla_len(a) == sizeof(u16)) { 106 conf.dst_port = htons(nla_get_u16(a)); 107 } else { 108 /* Require destination port from userspace. */ 109 err = -EINVAL; 110 goto error; 111 } 112 113 vport = ovs_vport_alloc(0, &ovs_vxlan_netdev_vport_ops, parms); 114 if (IS_ERR(vport)) 115 return vport; 116 117 a = nla_find_nested(options, OVS_TUNNEL_ATTR_EXTENSION); 118 if (a) { 119 err = vxlan_configure_exts(vport, a, &conf); 120 if (err) { 121 ovs_vport_free(vport); 122 goto error; 123 } 124 } 125 126 rtnl_lock(); 127 dev = vxlan_dev_create(net, parms->name, NET_NAME_USER, &conf); 128 if (IS_ERR(dev)) { 129 rtnl_unlock(); 130 ovs_vport_free(vport); 131 return ERR_CAST(dev); 132 } 133 134 err = dev_change_flags(dev, dev->flags | IFF_UP, NULL); 135 if (err < 0) { 136 rtnl_delete_link(dev); 137 rtnl_unlock(); 138 ovs_vport_free(vport); 139 goto error; 140 } 141 142 rtnl_unlock(); 143 return vport; 144 error: 145 return ERR_PTR(err); 146 } 147 148 static struct vport *vxlan_create(const struct vport_parms *parms) 149 { 150 struct vport *vport; 151 152 vport = vxlan_tnl_create(parms); 153 if (IS_ERR(vport)) 154 return vport; 155 156 return ovs_netdev_link(vport, parms->name); 157 } 158 159 static struct vport_ops ovs_vxlan_netdev_vport_ops = { 160 .type = OVS_VPORT_TYPE_VXLAN, 161 .create = vxlan_create, 162 .destroy = ovs_netdev_tunnel_destroy, 163 .get_options = vxlan_get_options, 164 .send = dev_queue_xmit, 165 }; 166 167 static int __init ovs_vxlan_tnl_init(void) 168 { 169 return ovs_vport_ops_register(&ovs_vxlan_netdev_vport_ops); 170 } 171 172 static void __exit ovs_vxlan_tnl_exit(void) 173 { 174 ovs_vport_ops_unregister(&ovs_vxlan_netdev_vport_ops); 175 } 176 177 module_init(ovs_vxlan_tnl_init); 178 module_exit(ovs_vxlan_tnl_exit); 179 180 MODULE_DESCRIPTION("OVS: VXLAN switching port"); 181 MODULE_LICENSE("GPL"); 182 MODULE_ALIAS("vport-type-4"); 183