After flow based tunneling, kernel tunneling is greatly simplified. There is no need to have extra tunning layer between vport and perticular protocol. Following patch removes tunneling struct which make code easy to read.
Signed-off-by: Pravin B Shelar <pshe...@nicira.com> --- datapath/tunnel.c | 62 +++------------------ datapath/tunnel.h | 39 ++------------ datapath/vport-gre.c | 78 +++++++++++++++++++-------- datapath/vport-lisp.c | 141 ++++++++++++++++++++---------------------------- datapath/vport-vxlan.c | 109 ++++++++++++++++--------------------- datapath/vport.c | 15 +++++ datapath/vport.h | 3 + 7 files changed, 193 insertions(+), 254 deletions(-) diff --git a/datapath/tunnel.c b/datapath/tunnel.c index 057aaed..bf8f386 100644 --- a/datapath/tunnel.c +++ b/datapath/tunnel.c @@ -218,13 +218,15 @@ u16 ovs_tnl_get_src_port(struct sk_buff *skb) return (((u64) hash * range) >> 32) + low; } -int ovs_tnl_send(struct vport *vport, struct sk_buff *skb) +int ovs_tnl_send(struct vport *vport, struct sk_buff *skb, + u8 ipproto, int tunnel_hlen, + void (*build_header)(const struct vport *, + struct sk_buff *, + int tunnel_hlen)) { - struct tnl_vport *tnl_vport = tnl_vport_priv(vport); struct rtable *rt; __be32 saddr; int sent_len = 0; - int tunnel_hlen; if (unlikely(!OVS_CB(skb)->tun_key)) goto error_free; @@ -234,14 +236,14 @@ int ovs_tnl_send(struct vport *vport, struct sk_buff *skb) rt = find_route(ovs_dp_get_net(vport->dp), &saddr, OVS_CB(skb)->tun_key->ipv4_dst, - tnl_vport->tnl_ops->ipproto, + ipproto, OVS_CB(skb)->tun_key->ipv4_tos, skb_get_mark(skb)); if (IS_ERR(rt)) goto error_free; /* Offloading */ - tunnel_hlen = tnl_vport->tnl_ops->hdr_len(OVS_CB(skb)->tun_key); + tunnel_hlen = tunnel_hlen; tunnel_hlen += sizeof(struct iphdr); skb = handle_offloads(skb, rt, tunnel_hlen); @@ -278,13 +280,13 @@ int ovs_tnl_send(struct vport *vport, struct sk_buff *skb) skb_dst_set(skb, &rt_dst(rt)); /* Push Tunnel header. */ - tnl_vport->tnl_ops->build_header(vport, skb, tunnel_hlen); + build_header(vport, skb, tunnel_hlen); /* Push IP header. */ iph = ip_hdr(skb); iph->version = 4; iph->ihl = sizeof(struct iphdr) >> 2; - iph->protocol = tnl_vport->tnl_ops->ipproto; + iph->protocol = ipproto; iph->daddr = OVS_CB(skb)->tun_key->ipv4_dst; iph->saddr = saddr; iph->tos = OVS_CB(skb)->tun_key->ipv4_tos; @@ -325,49 +327,3 @@ error_free: ovs_vport_record_error(vport, VPORT_E_TX_ERROR); return sent_len; } - -struct vport *ovs_tnl_create(const struct vport_parms *parms, - const struct vport_ops *vport_ops, - const struct tnl_ops *tnl_ops) -{ - struct vport *vport; - struct tnl_vport *tnl_vport; - int err; - - vport = ovs_vport_alloc(sizeof(struct tnl_vport), vport_ops, parms); - if (IS_ERR(vport)) { - err = PTR_ERR(vport); - goto error; - } - - tnl_vport = tnl_vport_priv(vport); - - strcpy(tnl_vport->name, parms->name); - tnl_vport->tnl_ops = tnl_ops; - - return vport; - -error: - return ERR_PTR(err); -} - -static void free_port_rcu(struct rcu_head *rcu) -{ - struct tnl_vport *tnl_vport = container_of(rcu, - struct tnl_vport, rcu); - - ovs_vport_free(vport_from_priv(tnl_vport)); -} - -void ovs_tnl_destroy(struct vport *vport) -{ - struct tnl_vport *tnl_vport = tnl_vport_priv(vport); - - call_rcu(&tnl_vport->rcu, free_port_rcu); -} - -const char *ovs_tnl_get_name(const struct vport *vport) -{ - const struct tnl_vport *tnl_vport = tnl_vport_priv(vport); - return tnl_vport->name; -} diff --git a/datapath/tunnel.h b/datapath/tunnel.h index e853146..75a84d1 100644 --- a/datapath/tunnel.h +++ b/datapath/tunnel.h @@ -26,45 +26,16 @@ #include "flow.h" #include "vport.h" -struct tnl_ops { - u8 ipproto; /* The IP protocol for the tunnel. */ - /* - * Returns the length of the tunnel header that will be added in - * build_header() (i.e. excludes the IP header). - */ - int (*hdr_len)(const struct ovs_key_ipv4_tunnel *); - /* - * Builds header for given SKB. Space will have already been - * allocated at the start of the packet equal - * to sizeof(struct iphdr) + value returned by hdr_len(). - */ - void (*build_header)(const struct vport *, struct sk_buff *, - int tunnel_hlen); -}; +int ovs_tnl_send(struct vport *vport, struct sk_buff *skb, + u8 ipproto, int tunnel_hlen, + void (*build_header)(const struct vport *, + struct sk_buff *, + int tunnel_hlen)); -struct tnl_vport { - struct rcu_head rcu; - - __be16 dst_port; - char name[IFNAMSIZ]; - const struct tnl_ops *tnl_ops; -}; - -struct vport *ovs_tnl_create(const struct vport_parms *, const struct vport_ops *, - const struct tnl_ops *); -void ovs_tnl_destroy(struct vport *); - -const char *ovs_tnl_get_name(const struct vport *vport); -int ovs_tnl_send(struct vport *vport, struct sk_buff *skb); void ovs_tnl_rcv(struct vport *vport, struct sk_buff *skb); u16 ovs_tnl_get_src_port(struct sk_buff *skb); -static inline struct tnl_vport *tnl_vport_priv(const struct vport *vport) -{ - return vport_priv(vport); -} - static inline void tnl_tun_key_init(struct ovs_key_ipv4_tunnel *tun_key, const struct iphdr *iph, __be64 tun_id, u32 tun_flags) { diff --git a/datapath/vport-gre.c b/datapath/vport-gre.c index a29d2e8..dc33d4c 100644 --- a/datapath/vport-gre.c +++ b/datapath/vport-gre.c @@ -317,13 +317,6 @@ static void gre_exit(void) inet_del_protocol(&gre_protocol_handlers, IPPROTO_GRE); } -/* GRE vport. */ -static const struct tnl_ops gre_tnl_ops = { - .ipproto = IPPROTO_GRE, - .hdr_len = gre_hdr_len, - .build_header = gre_build_header, -}; - static struct vport *gre_create(const struct vport_parms *parms) { struct net *net = ovs_dp_get_net(parms->dp); @@ -334,8 +327,11 @@ static struct vport *gre_create(const struct vport_parms *parms) if (ovsl_dereference(ovs_net->vport_net.gre_vport)) return ERR_PTR(-EEXIST); - vport = ovs_tnl_create(parms, &ovs_gre_vport_ops, &gre_tnl_ops); + vport = ovs_vport_alloc(0, &ovs_gre_vport_ops, parms); + if (IS_ERR(vport)) + return vport; + strncpy(ovs_net->vport_net.gre_name, parms->name, IFNAMSIZ); rcu_assign_pointer(ovs_net->vport_net.gre_vport, vport); return vport; } @@ -348,7 +344,28 @@ static void gre_tnl_destroy(struct vport *vport) ovs_net = net_generic(net, ovs_net_id); rcu_assign_pointer(ovs_net->vport_net.gre_vport, NULL); - ovs_tnl_destroy(vport); + ovs_vport_deferred_destroy(vport); +} + +static const char *gre_tnl_get_name(const struct vport *vport) +{ + struct net *net = ovs_dp_get_net(vport->dp); + struct ovs_net *ovs_net; + + ovs_net = net_generic(net, ovs_net_id); + + return ovs_net->vport_net.gre_name; +} + +static int gre_tnl_send(struct vport *vport, struct sk_buff *skb) +{ + int hlen; + + if (unlikely(!OVS_CB(skb)->tun_key)) + return 0; + + hlen = gre_hdr_len(OVS_CB(skb)->tun_key); + return ovs_tnl_send(vport, skb, IPPROTO_GRE, hlen, gre_build_header); } const struct vport_ops ovs_gre_vport_ops = { @@ -358,17 +375,11 @@ const struct vport_ops ovs_gre_vport_ops = { .exit = gre_exit, .create = gre_create, .destroy = gre_tnl_destroy, - .get_name = ovs_tnl_get_name, - .send = ovs_tnl_send, + .get_name = gre_tnl_get_name, + .send = gre_tnl_send, }; /* GRE64 vport. */ -static const struct tnl_ops gre64_tnl_ops = { - .ipproto = IPPROTO_GRE, - .hdr_len = gre64_hdr_len, - .build_header = gre64_build_header, -}; - static struct vport *gre64_create(const struct vport_parms *parms) { struct net *net = ovs_dp_get_net(parms->dp); @@ -379,13 +390,15 @@ static struct vport *gre64_create(const struct vport_parms *parms) if (ovsl_dereference(ovs_net->vport_net.gre64_vport)) return ERR_PTR(-EEXIST); - vport = ovs_tnl_create(parms, &ovs_gre64_vport_ops, &gre64_tnl_ops); + vport = ovs_vport_alloc(0, &ovs_gre64_vport_ops, parms); + if (IS_ERR(vport)) + return vport; + strncpy(ovs_net->vport_net.gre64_name, parms->name, IFNAMSIZ); rcu_assign_pointer(ovs_net->vport_net.gre64_vport, vport); return vport; } - static void gre64_tnl_destroy(struct vport *vport) { struct net *net = ovs_dp_get_net(vport->dp); @@ -394,7 +407,28 @@ static void gre64_tnl_destroy(struct vport *vport) ovs_net = net_generic(net, ovs_net_id); rcu_assign_pointer(ovs_net->vport_net.gre64_vport, NULL); - ovs_tnl_destroy(vport); + ovs_vport_deferred_destroy(vport); +} + +static int gre64_tnl_send(struct vport *vport, struct sk_buff *skb) +{ + int hlen; + + if (unlikely(!OVS_CB(skb)->tun_key)) + return 0; + + hlen = gre64_hdr_len(OVS_CB(skb)->tun_key); + return ovs_tnl_send(vport, skb, IPPROTO_GRE, hlen, gre64_build_header); +} + +static const char *gre64_tnl_get_name(const struct vport *vport) +{ + struct net *net = ovs_dp_get_net(vport->dp); + struct ovs_net *ovs_net; + + ovs_net = net_generic(net, ovs_net_id); + + return ovs_net->vport_net.gre64_name; } const struct vport_ops ovs_gre64_vport_ops = { @@ -404,6 +438,6 @@ const struct vport_ops ovs_gre64_vport_ops = { .exit = gre_exit, .create = gre64_create, .destroy = gre64_tnl_destroy, - .get_name = ovs_tnl_get_name, - .send = ovs_tnl_send, + .get_name = gre64_tnl_get_name, + .send = gre64_tnl_send, }; diff --git a/datapath/vport-lisp.c b/datapath/vport-lisp.c index 1fff5ae..c4685fb 100644 --- a/datapath/vport-lisp.c +++ b/datapath/vport-lisp.c @@ -94,11 +94,6 @@ struct lisphdr { #define LISP_HLEN (sizeof(struct udphdr) + sizeof(struct lisphdr)) -static inline int lisp_hdr_len(const struct ovs_key_ipv4_tunnel *tun_key) -{ - return LISP_HLEN; -} - /** * struct lisp_port - Keeps track of open UDP ports * @list: list element. @@ -106,22 +101,27 @@ static inline int lisp_hdr_len(const struct ovs_key_ipv4_tunnel *tun_key) * @socket: The socket created for this port number. */ struct lisp_port { + __be16 dst_port; struct list_head list; struct vport *vport; struct socket *lisp_rcv_socket; + char name[IFNAMSIZ]; struct rcu_head rcu; }; static LIST_HEAD(lisp_ports); +static inline struct lisp_port *lisp_vport_priv(const struct vport *vport) +{ + return vport_priv(vport); +} + static struct lisp_port *lisp_find_port(struct net *net, __be16 port) { struct lisp_port *lisp_port; list_for_each_entry_rcu(lisp_port, &lisp_ports, list) { - struct tnl_vport *tnl_vport = tnl_vport_priv(lisp_port->vport); - - if (tnl_vport->dst_port == port && + if (lisp_port->dst_port == port && net_eq(sock_net(lisp_port->lisp_rcv_socket->sk), net)) return lisp_port; } @@ -134,25 +134,6 @@ static inline struct lisphdr *lisp_hdr(const struct sk_buff *skb) return (struct lisphdr *)(udp_hdr(skb) + 1); } -static int lisp_tnl_send(struct vport *vport, struct sk_buff *skb) -{ - int tnl_len; - int network_offset = skb_network_offset(skb); - - /* We only encapsulate IPv4 and IPv6 packets */ - switch (skb->protocol) { - case htons(ETH_P_IP): - case htons(ETH_P_IPV6): - /* Pop off "inner" Ethernet header */ - skb_pull(skb, network_offset); - tnl_len = ovs_tnl_send(vport, skb); - return tnl_len > 0 ? tnl_len + network_offset : tnl_len; - default: - kfree_skb(skb); - return 0; - } -} - /* Convert 64 bit tunnel ID to 24 bit Instance ID. */ static void tunnel_id_to_instance_id(__be64 tun_id, __u8 *iid) { @@ -184,12 +165,12 @@ static void lisp_build_header(const struct vport *vport, struct sk_buff *skb, int tunnel_hlen) { - struct tnl_vport *tnl_vport = tnl_vport_priv(vport); + struct lisp_port *lisp_port = lisp_vport_priv(vport); struct udphdr *udph = udp_hdr(skb); struct lisphdr *lisph = (struct lisphdr *)(udph + 1); const struct ovs_key_ipv4_tunnel *tun_key = OVS_CB(skb)->tun_key; - udph->dest = tnl_vport->dst_port; + udph->dest = lisp_port->dst_port; udph->source = htons(ovs_tnl_get_src_port(skb)); udph->check = 0; udph->len = htons(skb->len - skb_transport_offset(skb)); @@ -274,9 +255,8 @@ out: #define UDP_ENCAP_LISP 1 static int lisp_socket_init(struct lisp_port *lisp_port, struct net *net) { - int err; struct sockaddr_in sin; - struct tnl_vport *tnl_vport = tnl_vport_priv(lisp_port->vport); + int err; err = sock_create_kern(AF_INET, SOCK_DGRAM, 0, &lisp_port->lisp_rcv_socket); @@ -288,7 +268,7 @@ static int lisp_socket_init(struct lisp_port *lisp_port, struct net *net) sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(INADDR_ANY); - sin.sin_port = tnl_vport->dst_port; + sin.sin_port = lisp_port->dst_port; err = kernel_bind(lisp_port->lisp_rcv_socket, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)); @@ -309,30 +289,11 @@ error: return err; } - -static void free_port_rcu(struct rcu_head *rcu) -{ - struct lisp_port *lisp_port = container_of(rcu, - struct lisp_port, rcu); - - kfree(lisp_port); -} - -static void lisp_tunnel_release(struct lisp_port *lisp_port) -{ - if (!lisp_port) - return; - list_del_rcu(&lisp_port->list); - /* Release socket */ - sk_release_kernel(lisp_port->lisp_rcv_socket->sk); - call_rcu(&lisp_port->rcu, free_port_rcu); -} - static int lisp_tunnel_setup(struct net *net, struct vport *vport, - struct nlattr *options) + const struct vport_parms *parms) { - struct tnl_vport *tnl_vport = tnl_vport_priv(vport); - struct lisp_port *lisp_port; + struct nlattr *options = parms->options; + struct lisp_port *lisp_port = lisp_vport_priv(vport); struct nlattr *a; int err; u16 dst_port; @@ -352,20 +313,13 @@ static int lisp_tunnel_setup(struct net *net, struct vport *vport, } /* Verify if we already have a socket created for this port */ - lisp_port = lisp_find_port(net, htons(dst_port)); - if (lisp_port) { + if (lisp_find_port(net, htons(dst_port))) { err = -EEXIST; goto out; } - /* Add a new socket for this port */ - lisp_port = kzalloc(sizeof(struct lisp_port), GFP_KERNEL); - if (!lisp_port) { - err = -ENOMEM; - goto out; - } - - tnl_vport->dst_port = htons(dst_port); + strncpy(lisp_port->name, parms->name, IFNAMSIZ); + lisp_port->dst_port = htons(dst_port); lisp_port->vport = vport; list_add_tail_rcu(&lisp_port->list, &lisp_ports); @@ -377,36 +331,32 @@ static int lisp_tunnel_setup(struct net *net, struct vport *vport, error: list_del_rcu(&lisp_port->list); - kfree(lisp_port); out: return err; } static int lisp_get_options(const struct vport *vport, struct sk_buff *skb) { - const struct tnl_vport *tnl_vport = tnl_vport_priv(vport); + struct lisp_port *lisp_port = lisp_vport_priv(vport); - if (nla_put_u16(skb, OVS_TUNNEL_ATTR_DST_PORT, ntohs(tnl_vport->dst_port))) + if (nla_put_u16(skb, OVS_TUNNEL_ATTR_DST_PORT, ntohs(lisp_port->dst_port))) return -EMSGSIZE; return 0; } -static const struct tnl_ops ovs_lisp_tnl_ops = { - .ipproto = IPPROTO_UDP, - .hdr_len = lisp_hdr_len, - .build_header = lisp_build_header, -}; +static void lisp_tunnel_release(struct lisp_port *lisp_port) +{ + list_del_rcu(&lisp_port->list); + /* Release socket */ + sk_release_kernel(lisp_port->lisp_rcv_socket->sk); +} static void lisp_tnl_destroy(struct vport *vport) { - struct lisp_port *lisp_port; - struct tnl_vport *tnl_vport = tnl_vport_priv(vport); - - lisp_port = lisp_find_port(ovs_dp_get_net(vport->dp), - tnl_vport->dst_port); + struct lisp_port *lisp_port = lisp_vport_priv(vport); lisp_tunnel_release(lisp_port); - ovs_tnl_destroy(vport); + ovs_vport_deferred_destroy(vport); } static struct vport *lisp_tnl_create(const struct vport_parms *parms) @@ -414,26 +364,53 @@ static struct vport *lisp_tnl_create(const struct vport_parms *parms) struct vport *vport; int err; - vport = ovs_tnl_create(parms, &ovs_lisp_vport_ops, &ovs_lisp_tnl_ops); + vport = ovs_vport_alloc(sizeof(struct lisp_port), + &ovs_lisp_vport_ops, parms); if (IS_ERR(vport)) return vport; err = lisp_tunnel_setup(ovs_dp_get_net(parms->dp), vport, - parms->options); + parms); if (err) { - ovs_tnl_destroy(vport); + ovs_vport_deferred_destroy(vport); return ERR_PTR(err); } return vport; } +static const char *lisp_tnl_get_name(const struct vport *vport) +{ + struct lisp_port *lisp_port = lisp_vport_priv(vport); + return lisp_port->name; +} + +static int lisp_tnl_send(struct vport *vport, struct sk_buff *skb) +{ + int tnl_len; + int network_offset = skb_network_offset(skb); + + /* We only encapsulate IPv4 and IPv6 packets */ + switch (skb->protocol) { + case htons(ETH_P_IP): + case htons(ETH_P_IPV6): + /* Pop off "inner" Ethernet header */ + skb_pull(skb, network_offset); + tnl_len = ovs_tnl_send(vport, skb, IPPROTO_UDP, + LISP_HLEN, lisp_build_header); + return tnl_len > 0 ? tnl_len + network_offset : tnl_len; + default: + kfree_skb(skb); + return 0; + } +} + const struct vport_ops ovs_lisp_vport_ops = { .type = OVS_VPORT_TYPE_LISP, .flags = VPORT_F_TUN_ID, .create = lisp_tnl_create, .destroy = lisp_tnl_destroy, - .get_name = ovs_tnl_get_name, + .get_name = lisp_tnl_get_name, .get_options = lisp_get_options, .send = lisp_tnl_send, }; diff --git a/datapath/vport-vxlan.c b/datapath/vport-vxlan.c index 1850fc2..c480693 100644 --- a/datapath/vport-vxlan.c +++ b/datapath/vport-vxlan.c @@ -50,11 +50,6 @@ struct vxlanhdr { #define VXLAN_HLEN (sizeof(struct udphdr) + sizeof(struct vxlanhdr)) -static inline int vxlan_hdr_len(const struct ovs_key_ipv4_tunnel *tun_key) -{ - return VXLAN_HLEN; -} - /** * struct vxlan_port - Keeps track of open UDP ports * @list: list element. @@ -62,22 +57,28 @@ static inline int vxlan_hdr_len(const struct ovs_key_ipv4_tunnel *tun_key) * @socket: The socket created for this port number. */ struct vxlan_port { + __be16 dst_port; struct list_head list; struct vport *vport; struct socket *vxlan_rcv_socket; + char name[IFNAMSIZ]; struct rcu_head rcu; }; static LIST_HEAD(vxlan_ports); +static inline struct vxlan_port *vxlan_vport_priv(const struct vport *vport) +{ + return vport_priv(vport); +} + static struct vxlan_port *vxlan_find_port(struct net *net, __be16 port) { struct vxlan_port *vxlan_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 && + if (vxlan_port->dst_port == port && net_eq(sock_net(vxlan_port->vxlan_rcv_socket->sk), net)) return vxlan_port; } @@ -94,12 +95,12 @@ 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 vxlan_port *vxlan_port = vxlan_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; - udph->dest = tnl_vport->dst_port; + udph->dest = vxlan_port->dst_port; udph->source = htons(ovs_tnl_get_src_port(skb)); udph->check = 0; udph->len = htons(skb->len - skb_transport_offset(skb)); @@ -152,9 +153,8 @@ out: #define UDP_ENCAP_VXLAN 1 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); + int err; err = sock_create_kern(AF_INET, SOCK_DGRAM, 0, &vxlan_port->vxlan_rcv_socket); @@ -166,7 +166,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 = tnl_vport->dst_port; + sin.sin_port = vxlan_port->dst_port; err = kernel_bind(vxlan_port->vxlan_rcv_socket, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)); @@ -187,30 +187,11 @@ 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) -{ - if (!vxlan_port) - return; - - 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 vport *vport, - struct nlattr *options) + const struct vport_parms *parms) { - struct vxlan_port *vxlan_port; - struct tnl_vport *tnl_vport = tnl_vport_priv(vport); + struct nlattr *options = parms->options; + struct vxlan_port *vxlan_port = vxlan_vport_priv(vport); struct nlattr *a; int err; u16 dst_port; @@ -230,20 +211,13 @@ static int vxlan_tunnel_setup(struct net *net, struct vport *vport, } /* Verify if we already have a socket created for this port */ - vxlan_port = vxlan_find_port(net, htons(dst_port)); - if (vxlan_port) { + if (vxlan_find_port(net, htons(dst_port))) { err = -EEXIST; goto out; } - /* Add a new socket for this port */ - vxlan_port = kzalloc(sizeof(struct vxlan_port), GFP_KERNEL); - if (!vxlan_port) { - err = -ENOMEM; - goto out; - } - - tnl_vport->dst_port = htons(dst_port); + strncpy(vxlan_port->name, parms->name, IFNAMSIZ); + vxlan_port->dst_port = htons(dst_port); vxlan_port->vport = vport; list_add_tail_rcu(&vxlan_port->list, &vxlan_ports); @@ -255,36 +229,32 @@ static int vxlan_tunnel_setup(struct net *net, struct vport *vport, error: list_del_rcu(&vxlan_port->list); - kfree(vxlan_port); out: return err; } static int vxlan_get_options(const struct vport *vport, struct sk_buff *skb) { - const struct tnl_vport *tnl_vport = tnl_vport_priv(vport); + struct vxlan_port *vxlan_port = vxlan_vport_priv(vport); - if (nla_put_u16(skb, OVS_TUNNEL_ATTR_DST_PORT, ntohs(tnl_vport->dst_port))) + if (nla_put_u16(skb, OVS_TUNNEL_ATTR_DST_PORT, ntohs(vxlan_port->dst_port))) return -EMSGSIZE; return 0; } -static const struct tnl_ops ovs_vxlan_tnl_ops = { - .ipproto = IPPROTO_UDP, - .hdr_len = vxlan_hdr_len, - .build_header = vxlan_build_header, -}; +static void vxlan_tunnel_release(struct vxlan_port *vxlan_port) +{ + list_del_rcu(&vxlan_port->list); + /* Release socket */ + sk_release_kernel(vxlan_port->vxlan_rcv_socket->sk); +} static void vxlan_tnl_destroy(struct vport *vport) { - struct vxlan_port *vxlan_port; - struct tnl_vport *tnl_vport = tnl_vport_priv(vport); - - vxlan_port = vxlan_find_port(ovs_dp_get_net(vport->dp), - tnl_vport->dst_port); + struct vxlan_port *vxlan_port = vxlan_vport_priv(vport); vxlan_tunnel_release(vxlan_port); - ovs_tnl_destroy(vport); + ovs_vport_deferred_destroy(vport); } static struct vport *vxlan_tnl_create(const struct vport_parms *parms) @@ -292,28 +262,41 @@ static struct vport *vxlan_tnl_create(const struct vport_parms *parms) int err; struct vport *vport; - vport = ovs_tnl_create(parms, &ovs_vxlan_vport_ops, &ovs_vxlan_tnl_ops); + vport = ovs_vport_alloc(sizeof(struct vxlan_port), + &ovs_vxlan_vport_ops, parms); if (IS_ERR(vport)) return vport; err = vxlan_tunnel_setup(ovs_dp_get_net(parms->dp), vport, - parms->options); + parms); if (err) { - ovs_tnl_destroy(vport); + ovs_vport_deferred_destroy(vport); return ERR_PTR(err); } return vport; } +static const char *vxlan_tnl_get_name(const struct vport *vport) +{ + struct vxlan_port *vxlan_port = vxlan_vport_priv(vport); + return vxlan_port->name; +} + +static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb) +{ + return ovs_tnl_send(vport, skb, IPPROTO_UDP, + VXLAN_HLEN, vxlan_build_header); +} + const struct vport_ops ovs_vxlan_vport_ops = { .type = OVS_VPORT_TYPE_VXLAN, .flags = VPORT_F_TUN_ID, .create = vxlan_tnl_create, .destroy = vxlan_tnl_destroy, - .get_name = ovs_tnl_get_name, + .get_name = vxlan_tnl_get_name, .get_options = vxlan_get_options, - .send = ovs_tnl_send, + .send = vxlan_tnl_send, }; #else #warning VXLAN tunneling will not be available on kernels before 2.6.26 diff --git a/datapath/vport.c b/datapath/vport.c index 8a05209..4ac3de4 100644 --- a/datapath/vport.c +++ b/datapath/vport.c @@ -483,3 +483,18 @@ void ovs_vport_record_error(struct vport *vport, enum vport_err_type err_type) spin_unlock(&vport->stats_lock); } + +static void free_vport_rcu(struct rcu_head *rcu) +{ + struct vport *vport = container_of(rcu, struct vport, rcu); + + ovs_vport_free(vport); +} + +void ovs_vport_deferred_destroy(struct vport *vport) +{ + if (!vport) + return; + + call_rcu(&vport->rcu, free_vport_rcu); +} diff --git a/datapath/vport.h b/datapath/vport.h index 70d64b1..19cdd6b 100644 --- a/datapath/vport.h +++ b/datapath/vport.h @@ -33,6 +33,8 @@ struct vport_parms; struct vport_net { struct vport __rcu *gre_vport; struct vport __rcu *gre64_vport; + char gre_name[IFNAMSIZ]; + char gre64_name[IFNAMSIZ]; }; int ovs_vport_init(void); @@ -50,6 +52,7 @@ int ovs_vport_set_options(struct vport *, struct nlattr *options); int ovs_vport_get_options(const struct vport *, struct sk_buff *); int ovs_vport_send(struct vport *, struct sk_buff *); +void ovs_vport_deferred_destroy(struct vport *vport); /* The following definitions are for implementers of vport devices: */ -- 1.7.1 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev