X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=datapath%2Fvport-vxlan.c;h=9f8874adf59872ff939893ecdbac554401d84560;hb=85c9de194b9f432f7b8a66bda980cbab52a55b72;hp=388d9fb97046a8761f19af172bb5a61a95f1fa47;hpb=0d0673857b5b2a50f6aef62e0f042795d9893690;p=sliver-openvswitch.git diff --git a/datapath/vport-vxlan.c b/datapath/vport-vxlan.c index 388d9fb97..9f8874adf 100644 --- a/datapath/vport-vxlan.c +++ b/datapath/vport-vxlan.c @@ -24,8 +24,8 @@ #include #include -#include #include +#include #include #include @@ -50,8 +50,7 @@ struct vxlanhdr { #define VXLAN_HLEN (sizeof(struct udphdr) + sizeof(struct vxlanhdr)) -static inline int vxlan_hdr_len(const struct tnl_mutable_config *mutable, - const struct ovs_key_ipv4_tunnel *tun_key) +static inline int vxlan_hdr_len(const struct ovs_key_ipv4_tunnel *tun_key) { return VXLAN_HLEN; } @@ -59,25 +58,26 @@ static inline int vxlan_hdr_len(const struct tnl_mutable_config *mutable, /** * struct vxlan_port - Keeps track of open UDP ports * @list: list element. - * @port: The UDP port number in network byte order. + * @vport: vport for the tunnel. * @socket: The socket created for this port number. - * @count: How many ports are using this socket/port. */ struct vxlan_port { struct list_head list; - __be16 port; + struct vport *vport; struct socket *vxlan_rcv_socket; - int count; + struct rcu_head rcu; }; static LIST_HEAD(vxlan_ports); -static struct vxlan_port *vxlan_port_exists(struct net *net, __be16 port) +static struct vxlan_port *vxlan_find_port(struct net *net, __be16 port) { struct vxlan_port *vxlan_port; - list_for_each_entry(vxlan_port, &vxlan_ports, list) { - if (vxlan_port->port == port && + list_for_each_entry_rcu(vxlan_port, &vxlan_ports, list) { + struct tnl_vport *tnl_vport = tnl_vport_priv(vxlan_port->vport); + + if (tnl_vport->dst_port == port && net_eq(sock_net(vxlan_port->vxlan_rcv_socket->sk), net)) return vxlan_port; } @@ -90,27 +90,22 @@ static inline struct vxlanhdr *vxlan_hdr(const struct sk_buff *skb) return (struct vxlanhdr *)(udp_hdr(skb) + 1); } -static struct sk_buff *vxlan_build_header(const struct vport *vport, - const struct tnl_mutable_config *mutable, - struct dst_entry *dst, - struct sk_buff *skb, - int tunnel_hlen) +static void vxlan_build_header(const struct vport *vport, + struct sk_buff *skb, + int tunnel_hlen) { + struct tnl_vport *tnl_vport = tnl_vport_priv(vport); struct udphdr *udph = udp_hdr(skb); struct vxlanhdr *vxh = (struct vxlanhdr *)(udph + 1); const struct ovs_key_ipv4_tunnel *tun_key = OVS_CB(skb)->tun_key; - __be64 out_key; - u32 flags; - tnl_get_param(mutable, tun_key, &flags, &out_key); - - udph->dest = mutable->dst_port; + udph->dest = tnl_vport->dst_port; udph->source = htons(ovs_tnl_get_src_port(skb)); udph->check = 0; udph->len = htons(skb->len - skb_transport_offset(skb)); vxh->vx_flags = htonl(VXLAN_FLAGS); - vxh->vx_vni = htonl(be64_to_cpu(out_key) << 8); + vxh->vx_vni = htonl(be64_to_cpu(tun_key->tun_id) << 8); /* * Allow our local IP stack to fragment the outer packet even if the @@ -119,21 +114,21 @@ static struct sk_buff *vxlan_build_header(const struct vport *vport, * packet originally had DF set. */ skb->local_df = 1; - __ip_select_ident(ip_hdr(skb), dst, 0); - - return skb; + __ip_select_ident(ip_hdr(skb), skb_dst(skb), 0); } /* Called with rcu_read_lock and BH disabled. */ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb) { - struct vport *vport; + struct vxlan_port *vxlan_vport; struct vxlanhdr *vxh; - const struct tnl_mutable_config *mutable; struct iphdr *iph; struct ovs_key_ipv4_tunnel tun_key; __be64 key; - u32 tunnel_flags = 0; + + vxlan_vport = vxlan_find_port(dev_net(skb->dev), udp_hdr(skb)->dest); + if (unlikely(!vxlan_vport)) + goto error; if (unlikely(!pskb_may_pull(skb, VXLAN_HLEN + ETH_HLEN))) goto error; @@ -148,22 +143,12 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb) key = cpu_to_be64(ntohl(vxh->vx_vni) >> 8); - iph = ip_hdr(skb); - vport = ovs_tnl_find_port(dev_net(skb->dev), iph->daddr, iph->saddr, - key, TNL_T_PROTO_VXLAN, &mutable); - if (unlikely(!vport)) - goto error; - - if (mutable->flags & TNL_F_IN_KEY_MATCH || !mutable->key.daddr) - tunnel_flags = OVS_TNL_F_KEY; - else - key = 0; - /* Save outer tunnel values */ - tnl_tun_key_init(&tun_key, iph, key, tunnel_flags); + iph = ip_hdr(skb); + tnl_tun_key_init(&tun_key, iph, key, OVS_TNL_F_KEY); OVS_CB(skb)->tun_key = &tun_key; - ovs_tnl_rcv(vport, skb); + ovs_tnl_rcv(vxlan_vport->vport, skb); goto out; error: @@ -178,6 +163,7 @@ static int vxlan_socket_init(struct vxlan_port *vxlan_port, struct net *net) { int err; struct sockaddr_in sin; + struct tnl_vport *tnl_vport = tnl_vport_priv(vxlan_port->vport); err = sock_create_kern(AF_INET, SOCK_DGRAM, 0, &vxlan_port->vxlan_rcv_socket); @@ -189,7 +175,7 @@ static int vxlan_socket_init(struct vxlan_port *vxlan_port, struct net *net) sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(INADDR_ANY); - sin.sin_port = vxlan_port->port; + sin.sin_port = tnl_vport->dst_port; err = kernel_bind(vxlan_port->vxlan_rcv_socket, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)); @@ -210,26 +196,33 @@ error: return err; } +static void free_port_rcu(struct rcu_head *rcu) +{ + struct vxlan_port *vxlan_port = container_of(rcu, + struct vxlan_port, rcu); + + kfree(vxlan_port); +} + static void vxlan_tunnel_release(struct vxlan_port *vxlan_port) { - vxlan_port->count--; + if (!vxlan_port) + return; - if (vxlan_port->count == 0) { - /* Release old socket */ - sk_release_kernel(vxlan_port->vxlan_rcv_socket->sk); - list_del(&vxlan_port->list); - kfree(vxlan_port); - } + list_del_rcu(&vxlan_port->list); + /* Release socket */ + sk_release_kernel(vxlan_port->vxlan_rcv_socket->sk); + call_rcu(&vxlan_port->rcu, free_port_rcu); } -static int vxlan_tunnel_setup(struct net *net, struct nlattr *options, - struct vxlan_port **vxport) + +static int vxlan_tunnel_setup(struct net *net, struct vport *vport, + struct nlattr *options) { + struct vxlan_port *vxlan_port; + struct tnl_vport *tnl_vport = tnl_vport_priv(vport); struct nlattr *a; int err; u16 dst_port; - struct vxlan_port *vxlan_port = NULL; - - *vxport = NULL; if (!options) { err = -EINVAL; @@ -246,11 +239,9 @@ static int vxlan_tunnel_setup(struct net *net, struct nlattr *options, } /* Verify if we already have a socket created for this port */ - vxlan_port = vxlan_port_exists(net, htons(dst_port)); + vxlan_port = vxlan_find_port(net, htons(dst_port)); if (vxlan_port) { - vxlan_port->count++; - err = 0; - *vxport = vxlan_port; + err = -EEXIST; goto out; } @@ -261,55 +252,33 @@ static int vxlan_tunnel_setup(struct net *net, struct nlattr *options, goto out; } - vxlan_port->port = htons(dst_port); - vxlan_port->count = 1; - list_add_tail(&vxlan_port->list, &vxlan_ports); + tnl_vport->dst_port = htons(dst_port); + vxlan_port->vport = vport; + list_add_tail_rcu(&vxlan_port->list, &vxlan_ports); err = vxlan_socket_init(vxlan_port, net); if (err) goto error; - *vxport = vxlan_port; - goto out; + return 0; error: - list_del(&vxlan_port->list); + list_del_rcu(&vxlan_port->list); kfree(vxlan_port); out: return err; } -static int vxlan_set_options(struct vport *vport, struct nlattr *options) +static int vxlan_get_options(const struct vport *vport, struct sk_buff *skb) { - int err; - struct net *net = ovs_dp_get_net(vport->dp); - struct tnl_vport *tnl_vport = tnl_vport_priv(vport); - struct tnl_mutable_config *config; - struct vxlan_port *old_port = NULL; - struct vxlan_port *vxlan_port = NULL; - - config = rtnl_dereference(tnl_vport->mutable); - - old_port = vxlan_port_exists(net, config->dst_port); + const struct tnl_vport *tnl_vport = tnl_vport_priv(vport); - err = vxlan_tunnel_setup(net, options, &vxlan_port); - if (err) - goto out; - - err = ovs_tnl_set_options(vport, options); - - if (err) - vxlan_tunnel_release(vxlan_port); - else { - /* Release old socket */ - vxlan_tunnel_release(old_port); - } -out: - return err; + if (nla_put_u16(skb, OVS_TUNNEL_ATTR_DST_PORT, ntohs(tnl_vport->dst_port))) + return -EMSGSIZE; + return 0; } static const struct tnl_ops ovs_vxlan_tnl_ops = { - .tunnel_type = TNL_T_PROTO_VXLAN, .ipproto = IPPROTO_UDP, .hdr_len = vxlan_hdr_len, .build_header = vxlan_build_header, @@ -319,15 +288,11 @@ static void vxlan_tnl_destroy(struct vport *vport) { struct vxlan_port *vxlan_port; struct tnl_vport *tnl_vport = tnl_vport_priv(vport); - struct tnl_mutable_config *config; - config = rtnl_dereference(tnl_vport->mutable); - - vxlan_port = vxlan_port_exists(ovs_dp_get_net(vport->dp), - config->dst_port); + vxlan_port = vxlan_find_port(ovs_dp_get_net(vport->dp), + tnl_vport->dst_port); vxlan_tunnel_release(vxlan_port); - ovs_tnl_destroy(vport); } @@ -335,17 +300,17 @@ static struct vport *vxlan_tnl_create(const struct vport_parms *parms) { int err; struct vport *vport; - struct vxlan_port *vxlan_port = NULL; - - err = vxlan_tunnel_setup(ovs_dp_get_net(parms->dp), parms->options, - &vxlan_port); - if (err) - return ERR_PTR(err); vport = ovs_tnl_create(parms, &ovs_vxlan_vport_ops, &ovs_vxlan_tnl_ops); - if (IS_ERR(vport)) - vxlan_tunnel_release(vxlan_port); + return vport; + + err = vxlan_tunnel_setup(ovs_dp_get_net(parms->dp), vport, + parms->options); + if (err) { + ovs_tnl_destroy(vport); + return ERR_PTR(err); + } return vport; } @@ -356,8 +321,7 @@ const struct vport_ops ovs_vxlan_vport_ops = { .create = vxlan_tnl_create, .destroy = vxlan_tnl_destroy, .get_name = ovs_tnl_get_name, - .get_options = ovs_tnl_get_options, - .set_options = vxlan_set_options, + .get_options = vxlan_get_options, .send = ovs_tnl_send, }; #else