X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=datapath%2Fvport-vxlan.c;h=c05f5d447e089e5668aa8c070d70b76bbbff5a9f;hb=8f79bb4d3999d993424e9578342b4130d10a556c;hp=3401dfd22592bb6704da5a62f890ba5ba43f0f3a;hpb=13beaf6242986435200e545ce636446b12df8022;p=cascardo%2Fovs.git diff --git a/datapath/vport-vxlan.c b/datapath/vport-vxlan.c index 3401dfd22..c05f5d447 100644 --- a/datapath/vport-vxlan.c +++ b/datapath/vport-vxlan.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Nicira, Inc. + * Copyright (c) 2015 Nicira, Inc. * Copyright (c) 2013 Cisco Systems, Inc. * * This program is free software; you can redistribute it and/or @@ -17,188 +17,177 @@ * 02110-1301, USA */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include - -#include -#include -#include -#include -#include - -#include -#include +#include +#include +#include +#include #include #include -#include #include -#include -#include -#include -#include -#include #include #include "datapath.h" #include "vport.h" +#include "vport-netdev.h" -/** - * struct vxlan_port - Keeps track of open UDP ports - * @vs: vxlan_sock created for the port. - * @name: vport name. - */ -struct vxlan_port { - struct vxlan_sock *vs; - char name[IFNAMSIZ]; -}; +static struct vport_ops ovs_vxlan_netdev_vport_ops; -static inline struct vxlan_port *vxlan_vport(const struct vport *vport) +static int vxlan_get_options(const struct vport *vport, struct sk_buff *skb) { - return vport_priv(vport); -} + struct vxlan_dev *vxlan = netdev_priv(vport->dev); + __be16 dst_port = vxlan->cfg.dst_port; -/* Called with rcu_read_lock and BH disabled. */ -static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb, __be32 vx_vni) -{ - struct ovs_key_ipv4_tunnel tun_key; - struct vport *vport = vs->data; - struct iphdr *iph; - __be64 key; + if (nla_put_u16(skb, OVS_TUNNEL_ATTR_DST_PORT, ntohs(dst_port))) + return -EMSGSIZE; - /* Save outer tunnel values */ - iph = ip_hdr(skb); - key = cpu_to_be64(ntohl(vx_vni) >> 8); - ovs_flow_tun_key_init(&tun_key, iph, key, TUNNEL_KEY); + if (vxlan->flags & VXLAN_F_GBP) { + struct nlattr *exts; - ovs_vport_receive(vport, skb, &tun_key); -} + exts = nla_nest_start(skb, OVS_TUNNEL_ATTR_EXTENSION); + if (!exts) + return -EMSGSIZE; -static int vxlan_get_options(const struct vport *vport, struct sk_buff *skb) -{ - struct vxlan_port *vxlan_port = vxlan_vport(vport); - __be16 dst_port = inet_sport(vxlan_port->vs->sock->sk); + if (vxlan->flags & VXLAN_F_GBP && + nla_put_flag(skb, OVS_VXLAN_EXT_GBP)) + return -EMSGSIZE; + + nla_nest_end(skb, exts); + } - if (nla_put_u16(skb, OVS_TUNNEL_ATTR_DST_PORT, ntohs(dst_port))) - return -EMSGSIZE; return 0; } -static void vxlan_tnl_destroy(struct vport *vport) +static const struct nla_policy exts_policy[OVS_VXLAN_EXT_MAX + 1] = { + [OVS_VXLAN_EXT_GBP] = { .type = NLA_FLAG, }, +}; + +static int vxlan_configure_exts(struct vport *vport, struct nlattr *attr, + struct vxlan_config *conf) { - struct vxlan_port *vxlan_port = vxlan_vport(vport); + struct nlattr *exts[OVS_VXLAN_EXT_MAX + 1]; + int err; + + if (nla_len(attr) < sizeof(struct nlattr)) + return -EINVAL; + + err = nla_parse_nested(exts, OVS_VXLAN_EXT_MAX, attr, exts_policy); + if (err < 0) + return err; - vxlan_sock_release(vxlan_port->vs); + if (exts[OVS_VXLAN_EXT_GBP]) + conf->flags |= VXLAN_F_GBP; - ovs_vport_deferred_free(vport); + return 0; } static struct vport *vxlan_tnl_create(const struct vport_parms *parms) { struct net *net = ovs_dp_get_net(parms->dp); struct nlattr *options = parms->options; - struct vxlan_port *vxlan_port; - struct vxlan_sock *vs; + struct net_device *dev; struct vport *vport; struct nlattr *a; - u16 dst_port; int err; + struct vxlan_config conf = { + .no_share = true, + .flags = VXLAN_F_COLLECT_METADATA, + /* Don't restrict the packets that can be sent by MTU */ + .mtu = IP_MAX_MTU, + }; if (!options) { err = -EINVAL; goto error; } + a = nla_find_nested(options, OVS_TUNNEL_ATTR_DST_PORT); if (a && nla_len(a) == sizeof(u16)) { - dst_port = nla_get_u16(a); + conf.dst_port = htons(nla_get_u16(a)); } else { /* Require destination port from userspace. */ err = -EINVAL; goto error; } - vport = ovs_vport_alloc(sizeof(struct vxlan_port), - &ovs_vxlan_vport_ops, parms); + vport = ovs_vport_alloc(0, &ovs_vxlan_netdev_vport_ops, parms); if (IS_ERR(vport)) return vport; - vxlan_port = vxlan_vport(vport); - strncpy(vxlan_port->name, parms->name, IFNAMSIZ); + a = nla_find_nested(options, OVS_TUNNEL_ATTR_EXTENSION); + if (a) { + err = vxlan_configure_exts(vport, a, &conf); + if (err) { + ovs_vport_free(vport); + goto error; + } + } - vs = vxlan_sock_add(net, htons(dst_port), vxlan_rcv, vport, true); - if (IS_ERR(vs)) { + rtnl_lock(); + dev = vxlan_dev_create(net, parms->name, NET_NAME_USER, &conf); + if (IS_ERR(dev)) { + rtnl_unlock(); ovs_vport_free(vport); - return (void *)vs; + return ERR_CAST(dev); } - vxlan_port->vs = vs; + dev_change_flags(dev, dev->flags | IFF_UP); + rtnl_unlock(); return vport; - error: return ERR_PTR(err); } -static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb) +static struct vport *vxlan_create(const struct vport_parms *parms) { - struct vxlan_port *vxlan_port = vxlan_vport(vport); - __be16 dst_port = inet_sport(vxlan_port->vs->sock->sk); - struct rtable *rt; + struct vport *vport; + + vport = vxlan_tnl_create(parms); + if (IS_ERR(vport)) + return vport; + + return ovs_netdev_link(vport, parms->name); +} + +static int vxlan_get_egress_tun_info(struct vport *vport, struct sk_buff *skb, + struct dp_upcall_info *upcall) +{ + struct vxlan_dev *vxlan = netdev_priv(vport->dev); + struct net *net = ovs_dp_get_net(vport->dp); + __be16 dst_port = vxlan_dev_dst_port(vxlan); __be16 src_port; - __be32 saddr; - __be16 df; int port_min; int port_max; - int err; - if (unlikely(!OVS_CB(skb)->tun_key)) { - err = -EINVAL; - goto error; - } - - /* Route lookup */ - saddr = OVS_CB(skb)->tun_key->ipv4_src; - rt = find_route(ovs_dp_get_net(vport->dp), - &saddr, - OVS_CB(skb)->tun_key->ipv4_dst, - IPPROTO_UDP, - OVS_CB(skb)->tun_key->ipv4_tos, - skb->mark); - if (IS_ERR(rt)) { - err = PTR_ERR(rt); - goto error; - } - - df = OVS_CB(skb)->tun_key->tun_flags & TUNNEL_DONT_FRAGMENT ? - htons(IP_DF) : 0; + inet_get_local_port_range(net, &port_min, &port_max); + src_port = udp_flow_src_port(net, skb, 0, 0, true); - skb->local_df = 1; + return ovs_tunnel_get_egress_info(upcall, net, + skb, IPPROTO_UDP, + src_port, dst_port); +} - inet_get_local_port_range(&port_min, &port_max); - src_port = vxlan_src_port(port_min, port_max, skb); +static struct vport_ops ovs_vxlan_netdev_vport_ops = { + .type = OVS_VPORT_TYPE_VXLAN, + .create = vxlan_create, + .destroy = ovs_netdev_tunnel_destroy, + .get_options = vxlan_get_options, + .send = vxlan_xmit, + .get_egress_tun_info = vxlan_get_egress_tun_info, +}; - err = vxlan_xmit_skb(vxlan_port->vs, rt, skb, - saddr, OVS_CB(skb)->tun_key->ipv4_dst, - OVS_CB(skb)->tun_key->ipv4_tos, - OVS_CB(skb)->tun_key->ipv4_ttl, df, - src_port, dst_port, - htonl(be64_to_cpu(OVS_CB(skb)->tun_key->tun_id) << 8)); - if (err < 0) - ip_rt_put(rt); -error: - return err; +static int __init ovs_vxlan_tnl_init(void) +{ + return ovs_vport_ops_register(&ovs_vxlan_netdev_vport_ops); } -static const char *vxlan_get_name(const struct vport *vport) +static void __exit ovs_vxlan_tnl_exit(void) { - struct vxlan_port *vxlan_port = vxlan_vport(vport); - return vxlan_port->name; + ovs_vport_ops_unregister(&ovs_vxlan_netdev_vport_ops); } -const struct vport_ops ovs_vxlan_vport_ops = { - .type = OVS_VPORT_TYPE_VXLAN, - .create = vxlan_tnl_create, - .destroy = vxlan_tnl_destroy, - .get_name = vxlan_get_name, - .get_options = vxlan_get_options, - .send = vxlan_tnl_send, -}; +module_init(ovs_vxlan_tnl_init); +module_exit(ovs_vxlan_tnl_exit); + +MODULE_DESCRIPTION("OVS: VXLAN switching port"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("vport-type-4");