On Tue, May 7, 2013 at 11:13 AM, Jarno Rajahalme <[email protected]> wrote: > This reduces repeated code and makes it easier to add new UDP tunneling > protocols. > This approach is different from what tunnel upstream patches does. Since there is no lisp support in kernel, this patch will make ovs out of tree tunneling diverge significantly from upstream ovs tunneling. Basically we want to factor out common between upstream vxlan and ovs vxlan and keep similar code in out of tree kernel with old kernel compatibility code. In future do same with upstream lisp.
I will send out upstream patches soon. > Signed-off-by: Jarno Rajahalme <[email protected]> > --- > datapath/tunnel.c | 126 ++++++++++++++++++++++++++++++++++++ > datapath/tunnel.h | 48 ++++++++++++++ > datapath/vport-lisp.c | 167 > ++++-------------------------------------------- > datapath/vport-vxlan.c | 166 ++++------------------------------------------- > 4 files changed, 201 insertions(+), 306 deletions(-) > > diff --git a/datapath/tunnel.c b/datapath/tunnel.c > index 8c93e18..bef1f7d 100644 > --- a/datapath/tunnel.c > +++ b/datapath/tunnel.c > @@ -319,3 +319,129 @@ err_free_rt: > error: > return err; > } > + > +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) > +/* > + * Generic UDP tunnel handling > + */ > +static int ovs_tnl_udp_init_socket(struct tnl_udp_vport *udp_vport, > + struct net *net, > + int (*udp_rcv)(struct sock *, > + struct sk_buff *)) > +{ > + int err; > + struct sockaddr_in sin; > + > + err = sock_create_kern(AF_INET, SOCK_DGRAM, 0, > + &udp_vport->udp_rcv_socket); > + if (err) > + goto error; > + > + /* Release net ref. */ > + sk_change_net(udp_vport->udp_rcv_socket->sk, net); > + > + sin.sin_family = AF_INET; > + sin.sin_addr.s_addr = htonl(INADDR_ANY); > + sin.sin_port = udp_vport->dst_port; > + > + err = kernel_bind(udp_vport->udp_rcv_socket, (struct sockaddr *)&sin, > + sizeof(struct sockaddr_in)); > + if (err) > + goto error_sock; > + > + /* Arbitrary value > + * Irrelevant as long as it's not 0 since we set the handler. */ > + udp_sk(udp_vport->udp_rcv_socket->sk)->encap_type = 1; > + udp_sk(udp_vport->udp_rcv_socket->sk)->encap_rcv = udp_rcv; > + > + udp_encap_enable(); > + > + return 0; > + > +error_sock: > + sk_release_kernel(udp_vport->udp_rcv_socket->sk); > +error: > + pr_warn("Cannot register UDP protocol handler : %d\n", err); > + return err; > +} > + > +void ovs_tnl_udp_destroy(struct vport *vport) > +{ > + struct tnl_udp_vport *udp_vport = tnl_udp_vport(vport); > + > + list_del_rcu(&udp_vport->list); > + /* Release socket */ > + sk_release_kernel(udp_vport->udp_rcv_socket->sk); > + > + ovs_vport_deferred_free(vport); > +} > + > +struct vport * ovs_tnl_udp_create(const struct vport_parms *parms, > + const struct vport_ops *ops, > + struct list_head *ports, > + int (*udp_rcv)(struct sock *, > + struct sk_buff *)) > +{ > + struct net *net = ovs_dp_get_net(parms->dp); > + struct vport *vport; > + struct tnl_udp_vport *udp_vport; > + struct nlattr *a; > + int err; > + u16 dst_port; > + > + if (!parms->options) { > + err = -EINVAL; > + goto error; > + } > + > + a = nla_find_nested(parms->options, OVS_TUNNEL_ATTR_DST_PORT); > + if (a && nla_len(a) == sizeof(u16)) { > + dst_port = nla_get_u16(a); > + } else { > + /* Require destination port from userspace. */ > + err = -EINVAL; > + goto error; > + } > + > + /* Verify if we already have a socket created for this port. */ > + if (ovs_tnl_udp_find_port(net, htons(dst_port), ports)) { > + err = -EEXIST; > + goto error; > + } > + > + vport = ovs_vport_alloc(sizeof(struct tnl_udp_vport), ops, parms); > + if (IS_ERR(vport)) > + return vport; > + > + udp_vport = tnl_udp_vport(vport); > + udp_vport->dst_port = htons(dst_port); > + strncpy(udp_vport->name, parms->name, IFNAMSIZ); > + > + err = ovs_tnl_udp_init_socket(udp_vport, net, udp_rcv); > + if (err) > + goto error_free; > + > + list_add_tail_rcu(&udp_vport->list, ports); > + return vport; > + > +error_free: > + ovs_vport_free(vport); > +error: > + return ERR_PTR(err); > +} > + > +int ovs_tnl_udp_get_options(const struct vport *vport, struct sk_buff *skb) > +{ > + const struct tnl_udp_vport *udp_vport = tnl_udp_vport(vport); > + > + if (nla_put_u16(skb, OVS_TUNNEL_ATTR_DST_PORT, > + ntohs(udp_vport->dst_port))) > + return -EMSGSIZE; > + return 0; > +} > + > +const char *ovs_tnl_udp_get_name(const struct vport *vport) > +{ > + return tnl_udp_vport(vport)->name; > +} > +#endif > diff --git a/datapath/tunnel.h b/datapath/tunnel.h > index 89c4e16..3384684 100644 > --- a/datapath/tunnel.h > +++ b/datapath/tunnel.h > @@ -52,4 +52,52 @@ static inline void tnl_tun_key_init(struct > ovs_key_ipv4_tunnel *tun_key, > sizeof(*tun_key) - OVS_TUNNEL_KEY_SIZE); > } > > +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) > + > +/** > + * struct tnl_udp_vport - Private part of struct vport to keep track of open > + * UDP ports > + * @dst_port: UDP port no. > + * @list: list element for protocol specific port list. > + * @udp_rcv_socket: The socket created for this UDP port number. > + * @name: vport name. > + */ > +struct tnl_udp_vport { > + __be16 dst_port; > + struct list_head list; > + struct socket *udp_rcv_socket; > + char name[IFNAMSIZ]; > +}; > + > +static inline struct tnl_udp_vport *tnl_udp_vport(const struct vport *vport) > +{ > + return vport_priv(vport); > +} > + > +static inline struct tnl_udp_vport *ovs_tnl_udp_find_port(struct net *net, > + __be16 port, > + struct list_head > *head) > +{ > + struct tnl_udp_vport *udp_vport; > + > + list_for_each_entry_rcu(udp_vport, head, list) { > + if (udp_vport->dst_port == port && > + net_eq(sock_net(udp_vport->udp_rcv_socket->sk), net)) > + return udp_vport; > + } > + > + return NULL; > +} > + > +void ovs_tnl_udp_destroy(struct vport *); > +struct vport *ovs_tnl_udp_create(const struct vport_parms *, > + const struct vport_ops *, > + struct list_head *ports, > + int (*udp_rcv)(struct sock*, > + struct sk_buff *)); > +int ovs_tnl_udp_get_options(const struct vport *, struct sk_buff *); > + > +const char *ovs_tnl_udp_get_name(const struct vport *); > +#endif > + > #endif /* tunnel.h */ > diff --git a/datapath/vport-lisp.c b/datapath/vport-lisp.c > index ca2b441..dbfc4c5 100644 > --- a/datapath/vport-lisp.c > +++ b/datapath/vport-lisp.c > @@ -94,40 +94,8 @@ struct lisphdr { > > #define LISP_HLEN (sizeof(struct udphdr) + sizeof(struct lisphdr)) > > -/** > - * struct lisp_port - Keeps track of open UDP ports > - * @dst_port: lisp UDP port no. > - * @list: list element in @lisp_ports. > - * @lisp_rcv_socket: The socket created for this port number. > - * @name: vport name. > - */ > -struct lisp_port { > - __be16 dst_port; > - struct list_head list; > - struct socket *lisp_rcv_socket; > - char name[IFNAMSIZ]; > -}; > - > static LIST_HEAD(lisp_ports); > > -static inline struct lisp_port *lisp_vport(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) { > - if (lisp_port->dst_port == port && > - net_eq(sock_net(lisp_port->lisp_rcv_socket->sk), net)) > - return lisp_port; > - } > - > - return NULL; > -} > - > static inline struct lisphdr *lisp_hdr(const struct sk_buff *skb) > { > return (struct lisphdr *)(udp_hdr(skb) + 1); > @@ -164,12 +132,12 @@ static void lisp_build_header(const struct vport *vport, > struct sk_buff *skb, > int tunnel_hlen) > { > - struct lisp_port *lisp_port = lisp_vport(vport); > + struct tnl_udp_vport *udp_vport = tnl_udp_vport(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 = lisp_port->dst_port; > + udph->dest = udp_vport->dst_port; > udph->source = htons(ovs_tnl_get_src_port(skb)); > udph->check = 0; > udph->len = htons(skb->len - skb_transport_offset(skb)); > @@ -192,7 +160,7 @@ static void lisp_build_header(const struct vport *vport, > /* Called with rcu_read_lock and BH disabled. */ > static int lisp_rcv(struct sock *sk, struct sk_buff *skb) > { > - struct lisp_port *lisp_port; > + struct tnl_udp_vport *udp_vport; > struct lisphdr *lisph; > struct iphdr *iph, *inner_iph; > struct ovs_key_ipv4_tunnel tun_key; > @@ -200,8 +168,10 @@ static int lisp_rcv(struct sock *sk, struct sk_buff *skb) > struct ethhdr *ethh; > __be16 protocol; > > - lisp_port = lisp_find_port(dev_net(skb->dev), udp_hdr(skb)->dest); > - if (unlikely(!lisp_port)) > + udp_vport = ovs_tnl_udp_find_port(dev_net(skb->dev), > + udp_hdr(skb)->dest, > + &lisp_ports); > + if (unlikely(!udp_vport)) > goto error; > > if (unlikely(!pskb_may_pull(skb, LISP_HLEN))) > @@ -240,7 +210,7 @@ static int lisp_rcv(struct sock *sk, struct sk_buff *skb) > ethh->h_source[0] = 0x02; > ethh->h_proto = protocol; > > - ovs_tnl_rcv(vport_from_priv(lisp_port), skb, &tun_key); > + ovs_tnl_rcv(vport_from_priv(udp_vport), skb, &tun_key); > goto out; > > error: > @@ -249,114 +219,11 @@ out: > return 0; > } > > -/* Arbitrary value. Irrelevant as long as it's not 0 since we set the > handler. */ > -#define UDP_ENCAP_LISP 1 > -static int lisp_socket_init(struct lisp_port *lisp_port, struct net *net) > -{ > - struct sockaddr_in sin; > - int err; > - > - err = sock_create_kern(AF_INET, SOCK_DGRAM, 0, > - &lisp_port->lisp_rcv_socket); > - if (err) > - goto error; > - > - /* release net ref. */ > - sk_change_net(lisp_port->lisp_rcv_socket->sk, net); > - > - sin.sin_family = AF_INET; > - sin.sin_addr.s_addr = htonl(INADDR_ANY); > - sin.sin_port = lisp_port->dst_port; > - > - err = kernel_bind(lisp_port->lisp_rcv_socket, (struct sockaddr *)&sin, > - sizeof(struct sockaddr_in)); > - if (err) > - goto error_sock; > - > - udp_sk(lisp_port->lisp_rcv_socket->sk)->encap_type = UDP_ENCAP_LISP; > - udp_sk(lisp_port->lisp_rcv_socket->sk)->encap_rcv = lisp_rcv; > - > - udp_encap_enable(); > - > - return 0; > - > -error_sock: > - sk_release_kernel(lisp_port->lisp_rcv_socket->sk); > -error: > - pr_warn("cannot register lisp protocol handler: %d\n", err); > - return err; > -} > - > -static int lisp_get_options(const struct vport *vport, struct sk_buff *skb) > -{ > - struct lisp_port *lisp_port = lisp_vport(vport); > - > - if (nla_put_u16(skb, OVS_TUNNEL_ATTR_DST_PORT, > ntohs(lisp_port->dst_port))) > - return -EMSGSIZE; > - return 0; > -} > - > -static void lisp_tnl_destroy(struct vport *vport) > -{ > - struct lisp_port *lisp_port = lisp_vport(vport); > - > - list_del_rcu(&lisp_port->list); > - /* Release socket */ > - sk_release_kernel(lisp_port->lisp_rcv_socket->sk); > - > - ovs_vport_deferred_free(vport); > -} > > static struct vport *lisp_tnl_create(const struct vport_parms *parms) > { > - struct net *net = ovs_dp_get_net(parms->dp); > - struct nlattr *options = parms->options; > - struct lisp_port *lisp_port; > - struct vport *vport; > - struct nlattr *a; > - int err; > - u16 dst_port; > - > - 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); > - } else { > - /* Require destination port from userspace. */ > - err = -EINVAL; > - goto error; > - } > - > - /* Verify if we already have a socket created for this port */ > - if (lisp_find_port(net, htons(dst_port))) { > - err = -EEXIST; > - goto error; > - } > - > - vport = ovs_vport_alloc(sizeof(struct lisp_port), > - &ovs_lisp_vport_ops, parms); > - if (IS_ERR(vport)) > - return vport; > - > - lisp_port = lisp_vport(vport); > - lisp_port->dst_port = htons(dst_port); > - strncpy(lisp_port->name, parms->name, IFNAMSIZ); > - > - err = lisp_socket_init(lisp_port, net); > - if (err) > - goto error_free; > - > - list_add_tail_rcu(&lisp_port->list, &lisp_ports); > - return vport; > - > -error_free: > - ovs_vport_free(vport); > -error: > - return ERR_PTR(err); > + return ovs_tnl_udp_create(parms, &ovs_lisp_vport_ops, &lisp_ports, > + lisp_rcv); > } > > static int lisp_tnl_send(struct vport *vport, struct sk_buff *skb) > @@ -374,25 +241,19 @@ static int lisp_tnl_send(struct vport *vport, struct > sk_buff *skb) > /* Pop off "inner" Ethernet header */ > skb_pull(skb, network_offset); > tnl_len = ovs_tnl_send(vport, skb, IPPROTO_UDP, > - LISP_HLEN, lisp_build_header); > + LISP_HLEN, lisp_build_header); > return tnl_len > 0 ? tnl_len + network_offset : tnl_len; > default: > return 0; > } > } > > -static const char *lisp_get_name(const struct vport *vport) > -{ > - struct lisp_port *lisp_port = lisp_vport(vport); > - return lisp_port->name; > -} > - > const struct vport_ops ovs_lisp_vport_ops = { > .type = OVS_VPORT_TYPE_LISP, > .create = lisp_tnl_create, > - .destroy = lisp_tnl_destroy, > - .get_name = lisp_get_name, > - .get_options = lisp_get_options, > + .destroy = ovs_tnl_udp_destroy, > + .get_name = ovs_tnl_udp_get_name, > + .get_options = ovs_tnl_udp_get_options, > .send = lisp_tnl_send, > }; > #else > diff --git a/datapath/vport-vxlan.c b/datapath/vport-vxlan.c > index d140c3b..a7f7e1e 100644 > --- a/datapath/vport-vxlan.c > +++ b/datapath/vport-vxlan.c > @@ -50,41 +50,8 @@ struct vxlanhdr { > > #define VXLAN_HLEN (sizeof(struct udphdr) + sizeof(struct vxlanhdr)) > > -/** > - * struct vxlan_port - Keeps track of open UDP ports > - * @dst_port: vxlan UDP port no. > - * @list: list element in @vxlan_ports. > - * @vxlan_rcv_socket: The socket created for this port number. > - * @name: vport name. > - */ > -struct vxlan_port { > - __be16 dst_port; > - struct list_head list; > - struct socket *vxlan_rcv_socket; > - char name[IFNAMSIZ]; > -}; > - > static LIST_HEAD(vxlan_ports); > > -static inline struct vxlan_port *vxlan_vport(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) { > - > - if (vxlan_port->dst_port == port && > - net_eq(sock_net(vxlan_port->vxlan_rcv_socket->sk), > net)) > - return vxlan_port; > - } > - > - return NULL; > -} > - > static inline struct vxlanhdr *vxlan_hdr(const struct sk_buff *skb) > { > return (struct vxlanhdr *)(udp_hdr(skb) + 1); > @@ -94,12 +61,12 @@ static void vxlan_build_header(const struct vport *vport, > struct sk_buff *skb, > int tunnel_hlen) > { > - struct vxlan_port *vxlan_port = vxlan_vport(vport); > + struct tnl_udp_vport *udp_vport = tnl_udp_vport(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 = vxlan_port->dst_port; > + udph->dest = udp_vport->dst_port; > udph->source = htons(ovs_tnl_get_src_port(skb)); > udph->check = 0; > udph->len = htons(skb->len - skb_transport_offset(skb)); > @@ -111,14 +78,16 @@ static void vxlan_build_header(const struct vport *vport, > /* Called with rcu_read_lock and BH disabled. */ > static int vxlan_rcv(struct sock *sk, struct sk_buff *skb) > { > - struct vxlan_port *vxlan_vport; > + struct tnl_udp_vport *udp_vport; > struct vxlanhdr *vxh; > struct iphdr *iph; > struct ovs_key_ipv4_tunnel tun_key; > __be64 key; > > - vxlan_vport = vxlan_find_port(dev_net(skb->dev), udp_hdr(skb)->dest); > - if (unlikely(!vxlan_vport)) > + udp_vport = ovs_tnl_udp_find_port(dev_net(skb->dev), > + udp_hdr(skb)->dest, > + &vxlan_ports); > + if (unlikely(!udp_vport)) > goto error; > > if (unlikely(!pskb_may_pull(skb, VXLAN_HLEN + ETH_HLEN))) > @@ -138,7 +107,7 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb) > iph = ip_hdr(skb); > tnl_tun_key_init(&tun_key, iph, key, OVS_TNL_F_KEY); > > - ovs_tnl_rcv(vport_from_priv(vxlan_vport), skb, &tun_key); > + ovs_tnl_rcv(vport_from_priv(udp_vport), skb, &tun_key); > goto out; > > error: > @@ -147,113 +116,10 @@ out: > return 0; > } > > -/* Random value. Irrelevant as long as it's not 0 since we set the handler. > */ > -#define UDP_ENCAP_VXLAN 1 > -static int vxlan_socket_init(struct vxlan_port *vxlan_port, struct net *net) > -{ > - struct sockaddr_in sin; > - int err; > - > - err = sock_create_kern(AF_INET, SOCK_DGRAM, 0, > - &vxlan_port->vxlan_rcv_socket); > - if (err) > - goto error; > - > - /* release net ref. */ > - sk_change_net(vxlan_port->vxlan_rcv_socket->sk, net); > - > - sin.sin_family = AF_INET; > - sin.sin_addr.s_addr = htonl(INADDR_ANY); > - sin.sin_port = vxlan_port->dst_port; > - > - err = kernel_bind(vxlan_port->vxlan_rcv_socket, (struct sockaddr > *)&sin, > - sizeof(struct sockaddr_in)); > - if (err) > - goto error_sock; > - > - udp_sk(vxlan_port->vxlan_rcv_socket->sk)->encap_type = > UDP_ENCAP_VXLAN; > - udp_sk(vxlan_port->vxlan_rcv_socket->sk)->encap_rcv = vxlan_rcv; > - > - udp_encap_enable(); > - > - return 0; > - > -error_sock: > - sk_release_kernel(vxlan_port->vxlan_rcv_socket->sk); > -error: > - pr_warn("cannot register vxlan protocol handler\n"); > - return err; > -} > - > -static int vxlan_get_options(const struct vport *vport, struct sk_buff *skb) > -{ > - struct vxlan_port *vxlan_port = vxlan_vport(vport); > - > - if (nla_put_u16(skb, OVS_TUNNEL_ATTR_DST_PORT, > ntohs(vxlan_port->dst_port))) > - return -EMSGSIZE; > - return 0; > -} > - > -static void vxlan_tnl_destroy(struct vport *vport) > -{ > - struct vxlan_port *vxlan_port = vxlan_vport(vport); > - > - list_del_rcu(&vxlan_port->list); > - /* Release socket */ > - sk_release_kernel(vxlan_port->vxlan_rcv_socket->sk); > - > - ovs_vport_deferred_free(vport); > -} > - > 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 vport *vport; > - struct nlattr *a; > - int err; > - u16 dst_port; > - > - 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); > - } else { > - /* Require destination port from userspace. */ > - err = -EINVAL; > - goto error; > - } > - > - /* Verify if we already have a socket created for this port */ > - if (vxlan_find_port(net, htons(dst_port))) { > - err = -EEXIST; > - goto error; > - } > - > - vport = ovs_vport_alloc(sizeof(struct vxlan_port), > - &ovs_vxlan_vport_ops, parms); > - if (IS_ERR(vport)) > - return vport; > - > - vxlan_port = vxlan_vport(vport); > - vxlan_port->dst_port = htons(dst_port); > - strncpy(vxlan_port->name, parms->name, IFNAMSIZ); > - > - err = vxlan_socket_init(vxlan_port, net); > - if (err) > - goto error_free; > - > - list_add_tail_rcu(&vxlan_port->list, &vxlan_ports); > - return vport; > - > -error_free: > - ovs_vport_free(vport); > -error: > - return ERR_PTR(err); > + return ovs_tnl_udp_create(parms, &ovs_vxlan_vport_ops, &vxlan_ports, > + vxlan_rcv); > } > > static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb) > @@ -265,18 +131,12 @@ static int vxlan_tnl_send(struct vport *vport, struct > sk_buff *skb) > VXLAN_HLEN, vxlan_build_header); > } > > -static const char *vxlan_get_name(const struct vport *vport) > -{ > - struct vxlan_port *vxlan_port = vxlan_vport(vport); > - return vxlan_port->name; > -} > - > 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, > + .destroy = ovs_tnl_udp_destroy, > + .get_name = ovs_tnl_udp_get_name, > + .get_options = ovs_tnl_udp_get_options, > .send = vxlan_tnl_send, > }; > #else > -- > 1.7.10.4 > > _______________________________________________ > dev mailing list > [email protected] > http://openvswitch.org/mailman/listinfo/dev _______________________________________________ dev mailing list [email protected] http://openvswitch.org/mailman/listinfo/dev
