Revision: 571 http://sourceforge.net/p/vde/svn/571 Author: rd235 Date: 2014-02-07 11:48:49 +0000 (Fri, 07 Feb 2014) Log Message: ----------- new feature: vxlan and lxvde modules for libvdeplug
Modified Paths: -------------- branches/rd235/vde-2/src/lib/libvdeplug/Makefile.am branches/rd235/vde-2/src/lib/libvdeplug/libvdeplug.c branches/rd235/vde-2/src/lib/libvdeplug/libvdeplug_kvde.c branches/rd235/vde-2/src/lib/libvdeplug/libvdeplug_ptp.c branches/rd235/vde-2/src/lib/libvdeplug/libvdeplug_udp.c branches/rd235/vde-2/src/lib/libvdeplug/libvdeplug_vde.c Added Paths: ----------- branches/rd235/vde-2/src/lib/libvdeplug/libvdeplug_vxhash.c branches/rd235/vde-2/src/lib/libvdeplug/libvdeplug_vxhash.h branches/rd235/vde-2/src/lib/libvdeplug/libvdeplug_vxlan.c branches/rd235/vde-2/src/lib/libvdeplug/libvdeplug_vxvde.c Modified: branches/rd235/vde-2/src/lib/libvdeplug/Makefile.am =================================================================== --- branches/rd235/vde-2/src/lib/libvdeplug/Makefile.am 2014-01-30 10:52:17 UTC (rev 570) +++ branches/rd235/vde-2/src/lib/libvdeplug/Makefile.am 2014-02-07 11:48:49 UTC (rev 571) @@ -18,6 +18,9 @@ libvdeplug_vde.c \ libvdeplug_kvde.c \ libvdeplug_udp.c \ + libvdeplug_vxhash.c \ + libvdeplug_vxlan.c \ + libvdeplug_vxvde.c \ libvdestream.c libvdeplug_la_LIBADD = $(LIBADD) Modified: branches/rd235/vde-2/src/lib/libvdeplug/libvdeplug.c =================================================================== --- branches/rd235/vde-2/src/lib/libvdeplug/libvdeplug.c 2014-01-30 10:52:17 UTC (rev 570) +++ branches/rd235/vde-2/src/lib/libvdeplug/libvdeplug.c 2014-02-07 11:48:49 UTC (rev 571) @@ -40,6 +40,8 @@ extern struct vdeplug_module vdeplug_udp; extern struct vdeplug_module vdeplug_ptpf; extern struct vdeplug_module vdeplug_ptpm; +extern struct vdeplug_module vdeplug_vxlan; +extern struct vdeplug_module vdeplug_vxvde; //extern struct vdeplug_module vdeplug_gvde; static struct vdeplug_module *modules[]={ @@ -48,6 +50,8 @@ &vdeplug_udp, &vdeplug_ptpf, &vdeplug_ptpm, + &vdeplug_vxlan, + &vdeplug_vxvde, //&vdeplug_gvde, }; @@ -67,6 +71,7 @@ int pid = getpid(); callerpwd=getpwuid(getuid()); + //fprintf(stderr, "LIBVDEPLUG OPEN! %s\n",given_sockname); descrlen=snprintf(newdescr,MAXDESCR,"%s user=%s PID=%d", descr,(callerpwd != NULL)?callerpwd->pw_name:"??", Modified: branches/rd235/vde-2/src/lib/libvdeplug/libvdeplug_kvde.c =================================================================== --- branches/rd235/vde-2/src/lib/libvdeplug/libvdeplug_kvde.c 2014-01-30 10:52:17 UTC (rev 570) +++ branches/rd235/vde-2/src/lib/libvdeplug/libvdeplug_kvde.c 2014-02-07 11:48:49 UTC (rev 571) @@ -64,15 +64,11 @@ static char *vde_kvde_check(char *given_sockname) { static char tag[]="KVDE:"; - static char atag[]="KVDE{"; - int len; + static char atag[]="KVDE/"; if (strncmp(given_sockname,tag,strlen(tag)) == 0) return given_sockname+strlen(tag); - len=strlen(given_sockname); - if (strncmp(given_sockname,atag,strlen(atag)) == 0 && - given_sockname[len-1] == '}') { + if (strncmp(given_sockname,atag,strlen(atag)) == 0) { given_sockname[strlen(atag)-1]=':'; - given_sockname[len-1] = 0; return given_sockname+strlen(atag); } return NULL; Modified: branches/rd235/vde-2/src/lib/libvdeplug/libvdeplug_ptp.c =================================================================== --- branches/rd235/vde-2/src/lib/libvdeplug/libvdeplug_ptp.c 2014-01-30 10:52:17 UTC (rev 570) +++ branches/rd235/vde-2/src/lib/libvdeplug/libvdeplug_ptp.c 2014-02-07 11:48:49 UTC (rev 571) @@ -33,8 +33,6 @@ #include "libvdeplug_mod.h" #include "canonicalize.h" -#define USE_IPN - static char *vde_ptpf_check(char *given_sockname); static VDECONN *vde_ptpf_open(char *given_sockname, char *descr,int interface_version, struct vde_open_args *open_args); @@ -77,25 +75,20 @@ static char *vde_ptpf_check(char *given_sockname) { static char tag[]="PTPF:"; - static char atag[]="PTPF{"; + static char atag[]="PTPF/"; static char tag2[]="PTP:"; - static char atag2[]="PTP{"; - int len; - len=strlen(given_sockname); + static char atag2[]="PTP/"; + int len=strlen(given_sockname); if (strncmp(given_sockname,tag,strlen(tag)) == 0) return given_sockname+strlen(tag); - if (strncmp(given_sockname,atag,strlen(atag)) == 0 && - given_sockname[len-1] == '}') { + if (strncmp(given_sockname,atag,strlen(atag)) == 0) { given_sockname[strlen(atag)-1]=':'; - given_sockname[len-1] = 0; return given_sockname+strlen(atag); } if (strncmp(given_sockname,tag2,strlen(tag2)) == 0) return given_sockname+strlen(tag2); - if (strncmp(given_sockname,atag2,strlen(atag2)) == 0 && - given_sockname[len-1] == '}') { + if (strncmp(given_sockname,atag2,strlen(atag2)) == 0) { given_sockname[strlen(atag2)-1]=':'; - given_sockname[len-1] = 0; return given_sockname+strlen(atag2); } if (len > 2 && given_sockname[len-1] == ']' && @@ -109,15 +102,11 @@ static char *vde_ptpm_check(char *given_sockname) { static char tag[]="PTPM:"; - static char atag[]="PTPM{"; - int len; + static char atag[]="PTPM"; if (strncmp(given_sockname,tag,strlen(tag)) == 0) return given_sockname+strlen(tag); - len=strlen(given_sockname); - if (strncmp(given_sockname,atag,strlen(atag)) == 0 && - given_sockname[len-1] == '}') { + if (strncmp(given_sockname,atag,strlen(atag)) == 0) { given_sockname[strlen(atag)-1]=':'; - given_sockname[len-1] = 0; return given_sockname+strlen(atag); } return NULL; Modified: branches/rd235/vde-2/src/lib/libvdeplug/libvdeplug_udp.c =================================================================== --- branches/rd235/vde-2/src/lib/libvdeplug/libvdeplug_udp.c 2014-01-30 10:52:17 UTC (rev 570) +++ branches/rd235/vde-2/src/lib/libvdeplug/libvdeplug_udp.c 2014-02-07 11:48:49 UTC (rev 571) @@ -62,16 +62,12 @@ static char *vde_udp_check(char *given_sockname) { static char tag[]="UDP:"; - static char atag[]="UDP{"; - int len; + static char atag[]="UDP/"; char *split; if (strncmp(given_sockname,tag,strlen(tag)) == 0) return given_sockname+strlen(tag); - len=strlen(given_sockname); - if (strncmp(given_sockname,atag,strlen(atag)) == 0 && - given_sockname[len-1] == '}') { + if (strncmp(given_sockname,atag,strlen(atag)) == 0) { given_sockname[strlen(atag)-1]=':'; - given_sockname[len-1] = 0; return given_sockname+strlen(atag); } if((split = strstr(given_sockname,"->")) != NULL && rindex(split,':') != NULL) Modified: branches/rd235/vde-2/src/lib/libvdeplug/libvdeplug_vde.c =================================================================== --- branches/rd235/vde-2/src/lib/libvdeplug/libvdeplug_vde.c 2014-01-30 10:52:17 UTC (rev 570) +++ branches/rd235/vde-2/src/lib/libvdeplug/libvdeplug_vde.c 2014-02-07 11:48:49 UTC (rev 571) @@ -63,15 +63,11 @@ static char *vde_vde_check(char *given_sockname) { static char tag[]="VDE:"; - static char atag[]="VDE{"; - int len; + static char atag[]="VDE/"; if (strncmp(given_sockname,tag,strlen(tag)) == 0) return given_sockname+strlen(tag); - len=strlen(given_sockname); - if (strncmp(given_sockname,atag,strlen(atag)) == 0 && - given_sockname[len-1] == '}') { + if (strncmp(given_sockname,atag,strlen(atag)) == 0) { given_sockname[strlen(atag)-1]=':'; - given_sockname[len-1] = 0; return given_sockname+strlen(atag); } return NULL; Added: branches/rd235/vde-2/src/lib/libvdeplug/libvdeplug_vxhash.c =================================================================== --- branches/rd235/vde-2/src/lib/libvdeplug/libvdeplug_vxhash.c (rev 0) +++ branches/rd235/vde-2/src/lib/libvdeplug/libvdeplug_vxhash.c 2014-02-07 11:48:49 UTC (rev 571) @@ -0,0 +1,129 @@ +/* + * VDE - vde_vxlan Network emulator for vde + * Copyright (C) 2014 Renzo Davoli VirtualSquare + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <stdlib.h> +#include <stddef.h> +#include <unistd.h> + +#include <sys/socket.h> +#include <netinet/in.h> +#include <sys/un.h> +#include "libvdeplug_vxhash.h" + +struct hash_entry6 { + u_int64_t edst; + time_t last_seen; + struct sockaddr_in6 addr; +}; + +struct hash_entry4 { + u_int64_t edst; + time_t last_seen; + struct sockaddr_in addr; +}; + +struct hash_entry { + u_int64_t edst; + time_t last_seen; + struct sockaddr addr; +}; + +static int calc_hash(u_int64_t src, int hash_mask) +{ + src ^= src >> 33; + src *= 0xff51afd7ed558ccd; + src ^= src >> 33; + src *= 0xc4ceb9fe1a85ec53; + return src & hash_mask; +} + +#define extmac(MAC,VLAN) \ + ((*(u_int32_t *) &((MAC)[0])) + ((u_int64_t) ((*(u_int16_t *) &((MAC)[4]))+ ((u_int64_t) (VLAN) << 16)) << 32)) + +/* look in global hash table for given address, and return associated sockaddr */ +struct sockaddr *vx_find_in_hash(void *table, int sa_family, int hash_mask, + unsigned char *dst, int vlan, time_t too_old) +{ + u_int64_t edst; + int index; + struct hash_entry *entry; + + if (__builtin_expect(table == NULL, 0)) + return NULL; + if ((dst[0] & 1) == 1) /* broadcast */ + return NULL; + edst=extmac(dst,vlan); + index=calc_hash(edst, hash_mask); + switch (sa_family) { + case AF_INET: entry = (struct hash_entry *)((struct hash_entry4 *)table)+index; + break; + case AF_INET6: entry = (struct hash_entry *)((struct hash_entry6 *)table)+index; + break; + default: + return NULL; + } + if (entry->edst == edst && entry->last_seen >= too_old) + return &(entry->addr); + else + return NULL; +} + +void vx_find_in_hash_update(void *table, int hash_mask, + unsigned char *src, int vlan, struct sockaddr *addr, time_t now) +{ + u_int64_t esrc; + int index; + size_t addrlen; + struct hash_entry *entry; + if (__builtin_expect(table == NULL, 0)) + return; + if ((src[0] & 1) == 1) /* broadcast */ + return; + esrc=extmac(src,vlan); + index=calc_hash(esrc, hash_mask); + + switch (addr->sa_family) { + case AF_INET: entry = (struct hash_entry *)((struct hash_entry4 *)table)+index; + addrlen = sizeof(struct sockaddr_in); + break; + case AF_INET6: entry = (struct hash_entry *)((struct hash_entry6 *)table)+index; + addrlen = sizeof(struct sockaddr_in6); + break; + default: + return; + } + entry->edst=esrc; + memcpy(&(entry->addr),addr,addrlen); + entry->last_seen=now; +} + +/* hash_mask must be 2^n - 1 */ +void *vx_hash_init(int sa_family, int hash_mask) +{ + size_t elsize; + switch (sa_family) { + case AF_INET: elsize=sizeof(struct hash_entry4); break; + case AF_INET6: elsize=sizeof(struct hash_entry6); break; + default: + return NULL; + } + + return calloc(hash_mask+1, elsize); +} + Added: branches/rd235/vde-2/src/lib/libvdeplug/libvdeplug_vxhash.h =================================================================== --- branches/rd235/vde-2/src/lib/libvdeplug/libvdeplug_vxhash.h (rev 0) +++ branches/rd235/vde-2/src/lib/libvdeplug/libvdeplug_vxhash.h 2014-02-07 11:48:49 UTC (rev 571) @@ -0,0 +1,34 @@ +/* + * VDE - vde_vxlan Network emulator for vde + * Copyright (C) 2014 Renzo Davoli VirtualSquare + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef LIBVDEPLUG_VXHASH_H +#define LIBVDEPLUG_VXHASH_H + +/* look in global hash table for given address, and return associated sockaddr */ +struct sockaddr *vx_find_in_hash(void *table, int sa_family, int hash_mask, + unsigned char *dst, int vlan, time_t too_old); + +/* update the address associated to a MAC address*/ +void vx_find_in_hash_update(void *table, int hash_mask, + unsigned char *src, int vlan, struct sockaddr *addr, time_t now); + +/* init the hash table */ +/* hash_mask must be 2^n - 1 */ +void *vx_hash_init(int sa_family, int hash_mask); +#endif + Added: branches/rd235/vde-2/src/lib/libvdeplug/libvdeplug_vxlan.c =================================================================== --- branches/rd235/vde-2/src/lib/libvdeplug/libvdeplug_vxlan.c (rev 0) +++ branches/rd235/vde-2/src/lib/libvdeplug/libvdeplug_vxlan.c 2014-02-07 11:48:49 UTC (rev 571) @@ -0,0 +1,312 @@ +/* + * VDE - vde_vxlan Network emulator for vde + * Copyright (C) 2014 Renzo Davoli VirtualSquare + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <libvdeplug.h> +#include <errno.h> +#include <limits.h> +#include <stdint.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <time.h> +#include "libvdeplug_mod.h" +#include "libvdeplug_vxhash.h" + +#define STDPORTSTR "4879" +#define STDTTL 1 +#define STDVNI 1 +#define STDHASHSIZE 1023 +#define STDEXPIRETIME 128 + +#define ETH_ALEN 6 +#define ETH_HEADER_SIZE 14 +#define IS_BROADCAST(addr) ((addr[0] & 1) == 1) + +#define ntoh24(p) (((p)[0] << 16) | ((p)[1] << 8) | ((p)[2])) +#define hton24(p, v) { \ + p[0] = (((v) >> 16) & 0xFF); \ + p[1] = (((v) >> 8) & 0xFF); \ + p[2] = ((v) & 0xFF); \ +} + +struct eth_hdr { + unsigned char dest[ETH_ALEN]; + unsigned char src[ETH_ALEN]; + unsigned char proto[2]; +}; + +struct vxlan_hdr { + unsigned char flags; + unsigned char priv1[3]; + unsigned char id[3]; + unsigned char priv2[1]; +}; + +static char *vde_vxlan_check(char *given_sockname); +static VDECONN *vde_vxlan_open(char *given_sockname, char *descr,int interface_version, + struct vde_open_args *open_args); +static ssize_t vde_vxlan_recv(VDECONN *conn,void *buf,size_t len,int flags); +static ssize_t vde_vxlan_send(VDECONN *conn,const void *buf,size_t len,int flags); +static int vde_vxlan_datafd(VDECONN *conn); +static int vde_vxlan_ctlfd(VDECONN *conn); +static int vde_vxlan_close(VDECONN *conn); + +struct vde_vxlan_conn { + struct vdeplug_module *module; + void *table; + int hash_mask; // hash table size - 1. This must be 2^n-1 + int vni; + union { + struct sockaddr vx; + struct sockaddr_in v4; + struct sockaddr_in6 v6; + } multiaddr; + int multifd; + int expiretime; +}; + +struct vdeplug_module vdeplug_vxlan={ + .flags=ONLY_BY_CHECK, + .vde_check=vde_vxlan_check, + .vde_open_real=vde_vxlan_open, + .vde_recv=vde_vxlan_recv, + .vde_send=vde_vxlan_send, + .vde_datafd=vde_vxlan_datafd, + .vde_ctlfd=vde_vxlan_ctlfd, + .vde_close=vde_vxlan_close +}; + +static char *vde_vxlan_check(char *given_sockname) { + static char tag[]="VXLAN:"; + static char atag[]="VXLAN/"; + if (strncmp(given_sockname,tag,strlen(tag)) == 0) + return given_sockname+strlen(tag); + if (strncmp(given_sockname,atag,strlen(atag)) == 0) { + given_sockname[strlen(atag)-1]=':'; + return given_sockname+strlen(atag); + } + return NULL; +} + +static VDECONN *vde_vxlan_open(char *given_sockname, char *descr,int interface_version, + struct vde_open_args *open_args) +{ + struct vde_vxlan_conn *newconn; + struct addrinfo hints; + struct addrinfo *result,*rp; + int s; + char *portstr; + char *vnistr; + struct sockaddr *multiaddr=NULL; + int multifd=-1; + int ttl=STDTTL; + + /* TODO a more complete parsing of options: hash table size */ + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ + hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */ + hints.ai_protocol = 0; /* Any protocol */ + vnistr=strchr(given_sockname,'/'); + if (vnistr) { + *vnistr=0; + vnistr++; + portstr=strchr(vnistr,'/'); + if (portstr) { + *portstr=0; + portstr++; + } else + portstr=STDPORTSTR; + } else + portstr=STDPORTSTR; + s = getaddrinfo(given_sockname, portstr, &hints, &result); + if (s < 0) { + fprintf(stderr, "vxlan getaddrinfo: %s\n", gai_strerror(s)); + errno=ENOENT; + return NULL; + } + + /* TODO scan the list of results */ + for (rp = result; rp != NULL; rp = rp->ai_next) { + switch (rp->ai_family) { + case AF_INET6: + // currently unsupported + continue; + case AF_INET: { + struct sockaddr_in *addr=(struct sockaddr_in *)(rp->ai_addr); + struct ip_mreq mc_req; + multiaddr = (struct sockaddr *) addr; + struct sockaddr_in bindaddr; + int loop = 0; + + multifd=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (multifd < 0) + return NULL; + if ((setsockopt(multifd, IPPROTO_IP, IP_MULTICAST_TTL, + &ttl, sizeof(ttl))) < 0) { + close(multifd); + multifd=-1; + return NULL; + } + if ((setsockopt(multifd, IPPROTO_IP, IP_MULTICAST_LOOP, + &loop, sizeof(loop))) < 0) { + close(multifd); + multifd=-1; + return NULL; + } + memset(&bindaddr, 0, sizeof(bindaddr)); + bindaddr.sin_family = AF_INET; + bindaddr.sin_addr.s_addr = htonl(INADDR_ANY); + bindaddr.sin_port = addr->sin_port; + if ((bind(multifd, (struct sockaddr *) &bindaddr, + sizeof(bindaddr))) < 0) { + close(multifd); + multifd=-1; + continue; + } + mc_req.imr_multiaddr.s_addr = addr->sin_addr.s_addr; + mc_req.imr_interface.s_addr = htonl(INADDR_ANY); + if ((setsockopt(multifd, IPPROTO_IP, IP_ADD_MEMBERSHIP, + &mc_req, sizeof(mc_req))) < 0) { + close(multifd); + multifd=-1; + return NULL; + } + } + } + } + if (multifd < 0) + return NULL; + + if ((newconn=calloc(1,sizeof(struct vde_vxlan_conn)))==NULL) + { + errno=ENOMEM; + close(multifd); + return NULL; + } + + newconn->module=&vdeplug_vxlan; + newconn->hash_mask=STDHASHSIZE; + newconn->table=vx_hash_init(AF_INET, newconn->hash_mask); + newconn->vni=vnistr?atoi(vnistr):STDVNI; + newconn->expiretime=STDEXPIRETIME; + switch (multiaddr->sa_family) { + case AF_INET: + memcpy(&(newconn->multiaddr.v4), multiaddr, sizeof(struct sockaddr_in)); + break; + case AF_INET6: + memcpy(&(newconn->multiaddr.v6), multiaddr, sizeof(struct sockaddr_in6)); + break; + } + newconn->multifd=multifd; + return (VDECONN *) newconn; +} + +static ssize_t vde_vxlan_recv(VDECONN *conn,void *buf,size_t len,int flags) { + struct vde_vxlan_conn *vde_conn = (struct vde_vxlan_conn *)conn; + struct vxlan_hdr vhdr; + struct iovec iov[]={{&vhdr, sizeof(vhdr)},{buf, len}}; + struct msghdr msg; + struct sockaddr_in6 sender; + int retval; + msg.msg_name=&sender; + switch (vde_conn->multiaddr.vx.sa_family) { + case AF_INET: msg.msg_namelen = sizeof(struct sockaddr_in); + break; + case AF_INET6: msg.msg_namelen = sizeof(struct sockaddr_in6); + break; + default: + msg.msg_namelen = 0; + } + msg.msg_iov=iov; + msg.msg_iovlen=2; + msg.msg_control=NULL; + msg.msg_control=0; + msg.msg_flags=0; + if (__builtin_expect(((retval=recvmsg(vde_conn->multifd, &msg, 0) + -sizeof(struct vxlan_hdr))>ETH_HEADER_SIZE), 1)) { + struct eth_hdr *ehdr=(struct eth_hdr *) buf; + if (vhdr.flags != (1<<0) || ntoh24(vhdr.id) != vde_conn->vni) + vx_find_in_hash_update(vde_conn->table, vde_conn->hash_mask, + ehdr->src, 1, msg.msg_name, time(NULL)); + return retval; + } + return 0; +} + +static ssize_t vde_vxlan_send(VDECONN *conn,const void *buf, size_t len,int flags) { + struct vde_vxlan_conn *vde_conn = (struct vde_vxlan_conn *)conn; + struct vxlan_hdr vhdr; + struct iovec iov[]={{&vhdr, sizeof(vhdr)},{(char *)buf, len}}; + struct sockaddr *destaddr; + static struct msghdr msg; + int retval; + msg.msg_iov=iov; + msg.msg_iovlen=2; + struct eth_hdr *ehdr=(struct eth_hdr *) buf; + if (len < ETH_HEADER_SIZE) + return len; // discard packets shorter than an ethernet header + if (IS_BROADCAST(ehdr->dest) || + (destaddr=vx_find_in_hash(vde_conn->table, vde_conn->multiaddr.vx.sa_family, + vde_conn->hash_mask, ehdr->dest, 1, time(NULL)- vde_conn->expiretime)) == NULL) + /* MULTICAST */ + msg.msg_name = &(vde_conn->multiaddr.vx); + else + /* UNICAST */ + msg.msg_name = destaddr; + switch (vde_conn->multiaddr.vx.sa_family) { + case AF_INET: msg.msg_namelen = sizeof(struct sockaddr_in); + break; + case AF_INET6: msg.msg_namelen = sizeof(struct sockaddr_in6); + break; + default: + msg.msg_namelen = 0; + } + memset(&vhdr, 0, sizeof(vhdr)); + vhdr.flags = (1 << 3); + + hton24(vhdr.id, vde_conn->vni); + + if ((retval=sendmsg(vde_conn->multifd, &msg, 0)) < 0) + return -1; + retval -= sizeof(struct vxlan_hdr); + if (retval < 0) + retval = 0; + return retval; +} + +static int vde_vxlan_datafd(VDECONN *conn) { + struct vde_vxlan_conn *vde_conn = (struct vde_vxlan_conn *)conn; + return vde_conn->multifd; +} + +static int vde_vxlan_ctlfd(VDECONN *conn) { + return -1; +} + +static int vde_vxlan_close(VDECONN *conn) { + struct vde_vxlan_conn *vde_conn = (struct vde_vxlan_conn *)conn; + close(vde_conn->multifd); + free(vde_conn); + return 0; +} Added: branches/rd235/vde-2/src/lib/libvdeplug/libvdeplug_vxvde.c =================================================================== --- branches/rd235/vde-2/src/lib/libvdeplug/libvdeplug_vxvde.c (rev 0) +++ branches/rd235/vde-2/src/lib/libvdeplug/libvdeplug_vxvde.c 2014-02-07 11:48:49 UTC (rev 571) @@ -0,0 +1,430 @@ +/* + * VDE - vde_vxvde Network emulator for vde + * Copyright (C) 2014 Renzo Davoli VirtualSquare + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <libvdeplug.h> +#include <errno.h> +#include <limits.h> +#include <stdint.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <time.h> +#include <sys/epoll.h> +#include "libvdeplug_mod.h" +#include "libvdeplug_vxhash.h" + +#define STDPORTSTR "4879" +#define STDTTL 1 +#define STDVNI 1 +#define STDHASHSIZE 1023 +#define STDEXPIRETIME 128 + +#define ETH_ALEN 6 +#define ETH_HEADER_SIZE 14 +#define IS_BROADCAST(addr) ((addr[0] & 1) == 1) + +#define ntoh24(p) (((p)[0] << 16) | ((p)[1] << 8) | ((p)[2])) +#define hton24(p, v) { \ + p[0] = (((v) >> 16) & 0xFF); \ + p[1] = (((v) >> 8) & 0xFF); \ + p[2] = ((v) & 0xFF); \ +} + +struct eth_hdr { + unsigned char dest[ETH_ALEN]; + unsigned char src[ETH_ALEN]; + unsigned char proto[2]; +}; + +struct vxvde_hdr { + unsigned char flags; + unsigned char priv1[3]; + unsigned char id[3]; + unsigned char priv2[1]; +}; + +static char *vde_vxvde_check(char *given_sockname); +static VDECONN *vde_vxvde_open(char *given_sockname, char *descr,int interface_version, + struct vde_open_args *open_args); +static ssize_t vde_vxvde_recv(VDECONN *conn,void *buf,size_t len,int flags); +static ssize_t vde_vxvde_send(VDECONN *conn,const void *buf,size_t len,int flags); +static int vde_vxvde_datafd(VDECONN *conn); +static int vde_vxvde_ctlfd(VDECONN *conn); +static int vde_vxvde_close(VDECONN *conn); + +struct vde_vxvde_conn { + struct vdeplug_module *module; + void *table; + int hash_mask; // hash table size - 1. This must be 2^n-1 + int vni; + union { + struct sockaddr vx; + struct sockaddr_in v4; + struct sockaddr_in6 v6; + } multiaddr; + int multifd; + int unifd; + int pollfd; + in_port_t multiport; + in_port_t uniport; + int expiretime; +}; + +struct vdeplug_module vdeplug_vxvde={ + .flags=ONLY_BY_CHECK, + .vde_check=vde_vxvde_check, + .vde_open_real=vde_vxvde_open, + .vde_recv=vde_vxvde_recv, + .vde_send=vde_vxvde_send, + .vde_datafd=vde_vxvde_datafd, + .vde_ctlfd=vde_vxvde_ctlfd, + .vde_close=vde_vxvde_close +}; + +static char *vde_vxvde_check(char *given_sockname) { + static char tag[]="VXVDE:"; + static char atag[]="VXVDE/"; + if (strncmp(given_sockname,tag,strlen(tag)) == 0) + return given_sockname+strlen(tag); + if (strncmp(given_sockname,atag,strlen(atag)) == 0) { + given_sockname[strlen(atag)-1]=':'; + return given_sockname+strlen(atag); + } + return NULL; +} + +static VDECONN *vde_vxvde_open(char *given_sockname, char *descr,int interface_version, + struct vde_open_args *open_args) +{ + struct vde_vxvde_conn *newconn=NULL; + struct addrinfo hints; + struct addrinfo *result,*rp; + int s; + char *portstr; + char *vnistr; + struct sockaddr *multiaddr=NULL; + int multifd=-1; + int unifd=-1; + int pollfd=-1; + int ttl=STDTTL; + in_port_t uniport; + + /* TODO a more complete parsing of options: hash table size */ + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ + hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */ + hints.ai_protocol = 0; /* Any protocol */ + vnistr=strchr(given_sockname,'/'); + if (vnistr) { + *vnistr=0; + vnistr++; + portstr=strchr(vnistr,'/'); + if (portstr) { + *portstr=0; + portstr++; + } else + portstr=STDPORTSTR; + } else + portstr=STDPORTSTR; + s = getaddrinfo(given_sockname, portstr, &hints, &result); + if (s < 0) { + fprintf(stderr, "vxvde getaddrinfo: %s\n", gai_strerror(s)); + errno=ENOENT; + return NULL; + } + + /* TODO scan the list of results */ + for (rp = result; rp != NULL; rp = rp->ai_next) { + switch (rp->ai_family) { + case AF_INET6: + // currently unsupported + continue; + case AF_INET: { + struct sockaddr_in *addr=(struct sockaddr_in *)(rp->ai_addr); + struct ip_mreqn mc_req; + multiaddr = (struct sockaddr *) addr; + struct sockaddr_in bindaddr; + socklen_t bindaddrlen; + int one = 1; + + if ((multifd=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) + goto error; + if ((unifd=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) + goto error; + if ((setsockopt(multifd, IPPROTO_IP, IP_MULTICAST_TTL, + &ttl, sizeof(ttl))) < 0) + goto error; + int loop=0; + if ((setsockopt(multifd, IPPROTO_IP, IP_MULTICAST_LOOP, + &loop, sizeof(loop))) < 0) + goto error; + if ((setsockopt(multifd, IPPROTO_IP, IP_PKTINFO, + &one, sizeof(one))) < 0) + goto error; +#ifdef SO_REUSEPORT + if ((setsockopt(multifd, SOL_SOCKET, SO_REUSEPORT, + &one, sizeof(one))) < 0) + goto error; +#endif + memset(&bindaddr, 0, sizeof(bindaddr)); + memset(&bindaddr, 0, sizeof(bindaddr)); + bindaddr.sin_family = AF_INET; + bindaddr.sin_addr.s_addr = htonl(INADDR_ANY); + bindaddr.sin_port = addr->sin_port; + if ((bind(multifd, (struct sockaddr *) &bindaddr, + sizeof(bindaddr))) < 0) { + close(multifd); + close(unifd); + multifd=unifd=-1; + continue; + } + mc_req.imr_multiaddr.s_addr = addr->sin_addr.s_addr; + mc_req.imr_address.s_addr = htonl(INADDR_ANY); + mc_req.imr_ifindex = 0; + if ((setsockopt(multifd, IPPROTO_IP, IP_ADD_MEMBERSHIP, + &mc_req, sizeof(mc_req))) < 0) + goto error; + bindaddr.sin_port = 0; + if ((bind(unifd, (struct sockaddr *) &bindaddr, + sizeof(bindaddr))) < 0) { + close(multifd); + close(unifd); + multifd=unifd=-1; + continue; + } + bindaddrlen=sizeof(bindaddr); + if (getsockname(unifd, (struct sockaddr *) &bindaddr, + &bindaddrlen) < 0) + goto error; + uniport=bindaddr.sin_port; + //fprintf(stderr,"local port %d\n",ntohs(bindaddr.sin_port)); + /*static char buf[]="test"; + socklen_t addrs=sizeof(struct sockaddr_in); + sendto(unifd, buf, strlen(buf)+1, 0, (struct sockaddr *) addr, addrs);*/ + } + } + } + if (multifd < 0) + return NULL; + + if ((pollfd = epoll_create1(0)) < 0) + goto error; + else { + struct epoll_event ev; + ev.events = EPOLLIN; + ev.data.fd = multifd; + if (epoll_ctl(pollfd, EPOLL_CTL_ADD, multifd, &ev) < 0) + goto error; + ev.data.fd = unifd; + if (epoll_ctl(pollfd, EPOLL_CTL_ADD, unifd, &ev) < 0) + goto error; + } + + if ((newconn=calloc(1,sizeof(struct vde_vxvde_conn)))==NULL) { + errno=ENOMEM; + goto error; + } + + newconn->module=&vdeplug_vxvde; + newconn->hash_mask=STDHASHSIZE; + newconn->table=vx_hash_init(AF_INET, newconn->hash_mask); + newconn->vni=vnistr?atoi(vnistr):STDVNI; + newconn->expiretime=STDEXPIRETIME; + switch (multiaddr->sa_family) { + case AF_INET: + memcpy(&(newconn->multiaddr.v4), multiaddr, sizeof(struct sockaddr_in)); + newconn->multiport = newconn->multiaddr.v4.sin_port; + break; + case AF_INET6: + memcpy(&(newconn->multiaddr.v6), multiaddr, sizeof(struct sockaddr_in6)); + newconn->multiport = newconn->multiaddr.v6.sin6_port; + break; + } + newconn->multifd=multifd; + newconn->unifd=unifd; + newconn->uniport=uniport; + newconn->pollfd=pollfd; + return (VDECONN *) newconn; + +error: + if (multifd >= 0) close(multifd); + if (unifd >= 0) close(unifd); + if (pollfd >= 0) close(pollfd); + if (newconn != NULL) free(newconn); + return NULL; +} + +static ssize_t vde_vxvde_recv(VDECONN *conn,void *buf,size_t len,int flags) { + struct vde_vxvde_conn *vde_conn = (struct vde_vxvde_conn *)conn; + struct epoll_event events[1]; + int nfd = epoll_wait(vde_conn->pollfd, events, 1, 0); + if (nfd > 0) { + if (events[0].data.fd == vde_conn->unifd) { + int retval; + struct sockaddr_in sender; + socklen_t senderlen=sizeof(sender); + retval = recvfrom(vde_conn->unifd, buf, len, 0, + (struct sockaddr *) &sender, &senderlen); + //fprintf(stderr, "<- unicast packet len %d\n",retval); + if (__builtin_expect((retval > ETH_HEADER_SIZE), 1)) { + struct eth_hdr *ehdr=(struct eth_hdr *) buf; + vx_find_in_hash_update(vde_conn->table, vde_conn->hash_mask, + ehdr->src, 1, (struct sockaddr *) &sender, time(NULL)); + return retval; + } else + goto error; + } else /*if (events[0].data.fd == vde_conn->multifd)*/ { + struct vxvde_hdr vhdr; + struct iovec iov[]={{&vhdr, sizeof(vhdr)},{buf, len}}; + struct msghdr msg; + struct sockaddr_in sender; + + char cmsg[CMSG_SPACE(sizeof(struct in_pktinfo))+1024]; + int retval; + msg.msg_name=&sender; + switch (vde_conn->multiaddr.vx.sa_family) { + case AF_INET: msg.msg_namelen = sizeof(struct sockaddr_in); + break; + case AF_INET6: msg.msg_namelen = sizeof(struct sockaddr_in6); + break; + default: + msg.msg_namelen = 0; + } + msg.msg_iov=iov; + msg.msg_iovlen=2; + msg.msg_control=cmsg; + msg.msg_controllen=sizeof(cmsg); + msg.msg_flags=0; + retval=recvmsg(vde_conn->multifd, &msg, 0)-sizeof(struct vxvde_hdr); + //fprintf(stderr, "<- multicast packet len %d\n",retval); + if (__builtin_expect((retval > ETH_HEADER_SIZE), 1)) { + struct eth_hdr *ehdr=(struct eth_hdr *) buf; + if (sender.sin_port == vde_conn->uniport) { + struct cmsghdr *cmsgptr=CMSG_FIRSTHDR(&msg); + struct in_pktinfo *pki=(struct in_pktinfo*)(CMSG_DATA(cmsgptr)); + if (sender.sin_addr.s_addr == pki->ipi_spec_dst.s_addr) { + //fprintf(stderr,"self packet, rejected \n"); + goto error; + } + } + if (vhdr.flags != (1<<0) || ntoh24(vhdr.id) != vde_conn->vni) + vx_find_in_hash_update(vde_conn->table, vde_conn->hash_mask, + ehdr->src, 1, msg.msg_name, time(NULL)); + return retval; + } + /* + struct cmsghdr *cmsgptr=CMSG_FIRSTHDR(&msg); + struct in_pktinfo *pki=(struct in_pktinfo*)(CMSG_DATA(cmsgptr)); + fprintf(stderr,"%d %s ",msg.msg_controllen, inet_ntoa(pki->ipi_spec_dst)); + fprintf(stderr,"%s- ",inet_ntoa(pki->ipi_addr)); + fprintf(stderr,"%s port %d\n",inet_ntoa(sender.sin_addr),ntohs(sender.sin_port)); + */ + goto error; + } + } +error: + errno = EAGAIN; + *((unsigned char *)buf)=0; + return 1; +} + +static ssize_t vde_vxvde_vxsend(struct vde_vxvde_conn *vde_conn, + struct sockaddr *destaddr, const void *buf, size_t len,int flags) { + struct vxvde_hdr vhdr; + struct iovec iov[]={{&vhdr, sizeof(vhdr)},{(char *)buf, len}}; + static struct msghdr msg; + int retval; + msg.msg_iov=iov; + msg.msg_iovlen=2; + msg.msg_name = destaddr; + switch (destaddr->sa_family) { + case AF_INET: msg.msg_namelen = sizeof(struct sockaddr_in); + break; + case AF_INET6: msg.msg_namelen = sizeof(struct sockaddr_in6); + break; + default: + msg.msg_namelen = 0; + } + memset(&vhdr, 0, sizeof(vhdr)); + vhdr.flags = (1 << 3); + + hton24(vhdr.id, vde_conn->vni); + + if ((retval=sendmsg(vde_conn->unifd, &msg, 0)) < 0) + return -1; + retval -= sizeof(struct vxvde_hdr); + if (retval < 0) + retval = 0; + return retval; +} + +static ssize_t vde_vxvde_send(VDECONN *conn,const void *buf, size_t len,int flags) { + struct vde_vxvde_conn *vde_conn = (struct vde_vxvde_conn *)conn; + struct eth_hdr *ehdr=(struct eth_hdr *) buf; + struct sockaddr *destaddr; + if (len < ETH_HEADER_SIZE) + return len; // discard packets shorter than an ethernet header + if (__builtin_expect( + (IS_BROADCAST(ehdr->dest) || + (destaddr=vx_find_in_hash(vde_conn->table, vde_conn->multiaddr.vx.sa_family, + vde_conn->hash_mask, ehdr->dest, 1, time(NULL)- vde_conn->expiretime)) == NULL), + 0)) { + return vde_vxvde_vxsend(vde_conn, &(vde_conn->multiaddr.vx), buf, len, flags); + } else { + socklen_t destlen; + in_port_t destport; + switch (destaddr->sa_family) { + case AF_INET: destlen = sizeof(struct sockaddr_in); + destport = ((struct sockaddr_in *) destaddr)->sin_port; + break; + case AF_INET6: destlen = sizeof(struct sockaddr_in6); + destport = ((struct sockaddr_in6 *) destaddr)->sin6_port; + break; + default: + destlen = 0; + destport = 0; + } + if (__builtin_expect(destport != vde_conn->multiport, 1)) { + return sendto(vde_conn->unifd, buf, len, 0, destaddr, destlen); + } else { /* compatibility with vxlan! */ + return vde_vxvde_vxsend(vde_conn, destaddr, buf, len, flags); + } + } +} + +static int vde_vxvde_datafd(VDECONN *conn) { + struct vde_vxvde_conn *vde_conn = (struct vde_vxvde_conn *)conn; + return vde_conn->pollfd; +} + +static int vde_vxvde_ctlfd(VDECONN *conn) { + return -1; +} + +static int vde_vxvde_close(VDECONN *conn) { + struct vde_vxvde_conn *vde_conn = (struct vde_vxvde_conn *)conn; + close(vde_conn->multifd); + free(vde_conn); + return 0; +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. ------------------------------------------------------------------------------ Managing the Performance of Cloud-Based Applications Take advantage of what the Cloud has to offer - Avoid Common Pitfalls. Read the Whitepaper. http://pubads.g.doubleclick.net/gampad/clk?id=121051231&iu=/4140/ostg.clktrk _______________________________________________ vde-users mailing list vde-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/vde-users