vde_autolink: Add missing null entry in getopt_long array.
[vde.git] / vde-2 / src / vde_vxlan / vxlan.c
blobf4cce40fcd821acc5eef51a23e3c61b497b2b404
1 /*
2 * VDE - vde_vxlan Network emulator for vde
3 * Copyright (C) 2014 Renzo Davoli, Alessandro Ghedini VirtualSquare
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
20 #include <stdlib.h>
21 #include <stddef.h>
22 #include <unistd.h>
23 #include <poll.h>
25 #include <netinet/in.h>
26 #include <sys/un.h>
28 #include "vxlan_hash.h"
29 #include "log.h"
30 #include "vxlan.h"
31 #include "plug.h"
33 #define ntoh24(p) (((p)[0] << 16) | ((p)[1] << 8) | ((p)[2]))
34 #define hton24(p, v) { \
35 p[0] = (((v) >> 16) & 0xFF); \
36 p[1] = (((v) >> 8) & 0xFF); \
37 p[2] = ((v) & 0xFF); \
40 int vxlan_id = -1;
41 in_addr_t vxlan_addr = INADDR_NONE;
42 int vxlan_port = 4879;
43 int vxlan_mttl = 1;
45 static int vxlan_fd = -1;
47 void vxlan_open(struct pollfd *pfd) {
48 int sock;
49 int loop = 0;
51 struct ip_mreq mc_req;
52 struct sockaddr_in addr_in;
54 if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
55 printlog(LOG_ERR, "socket(): %s", strerror(errno));
56 exit(1);
59 if ((setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL,
60 &vxlan_mttl, sizeof(vxlan_mttl))) < 0) {
61 printlog(LOG_ERR, "setsockopt(TTL): %s", strerror(errno));
62 exit(1);
65 if ((setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP,
66 &loop, sizeof(loop))) < 0) {
67 printlog(LOG_ERR, "setsockopt(LOOP): %s", strerror(errno));
68 exit(1);
71 memset(&addr_in, 0, sizeof(addr_in));
72 addr_in.sin_family = AF_INET;
73 addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
74 addr_in.sin_port = htons(vxlan_port);
76 if ((bind(sock, (struct sockaddr *) &addr_in, sizeof(addr_in))) < 0) {
77 printlog(LOG_ERR, "bind(): %s", strerror(errno));
78 exit(1);
81 /* send an IGMP join request */
82 mc_req.imr_multiaddr.s_addr = vxlan_addr;
83 mc_req.imr_interface.s_addr = htonl(INADDR_ANY);
85 if ((setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
86 &mc_req, sizeof(mc_req))) < 0) {
87 printlog(LOG_ERR, "setsockopt(ADD): %s", strerror(errno));
88 exit(1);
91 vxlan_fd = sock;
93 pfd[2].fd = sock;
94 pfd[2].events = POLLIN | POLLHUP;
97 void vxlan_process() {
98 struct vxlan_pkt pkt;
100 struct sockaddr_in src_addr;
101 socklen_t src_addr_len=sizeof(src_addr);
103 in_addr_t dest_addr;
105 size_t len = recvfrom(vxlan_fd, &pkt, sizeof(pkt), 0,
106 (struct sockaddr *) &src_addr, &src_addr_len);
108 if (len < 0)
109 printlog(LOG_ERR, "recvfrom(): %s", strerror(errno));
111 printlog(LOG_DEBUG, "VXLAN packet from %s",inet_ntoa(src_addr.sin_addr));
113 if (pkt.flags != (1<<3)) {
114 printlog(LOG_ERR, "Invalid flags");
115 return;
118 if (ntoh24(pkt.id) != vxlan_id) {
119 printlog(LOG_DEBUG, "Invalid VNI");
120 return;
123 find_in_hash_update(pkt.pkt.header.src, vxlan_id,
124 src_addr.sin_addr.s_addr, NULL);
126 if ((pkt.pkt.header.dest[0] == 0xff) &&
127 (pkt.pkt.header.dest[1] == 0xff) &&
128 (pkt.pkt.header.dest[2] == 0xff) &&
129 (pkt.pkt.header.dest[3] == 0xff) &&
130 (pkt.pkt.header.dest[4] == 0xff) &&
131 (pkt.pkt.header.dest[5] == 0xff)) {
132 printlog(LOG_DEBUG, "Broadcast send");
134 plug_send(&pkt.pkt, len-offsetof(struct vxlan_pkt,pkt));
135 return;
138 find_in_hash(pkt.pkt.header.dest, vxlan_id, &dest_addr);
140 switch (dest_addr) {
141 case 0:
142 printlog(LOG_DEBUG, "Not found");
143 case 1:
144 plug_send(&pkt.pkt,len-offsetof(struct vxlan_pkt,pkt));
145 printlog(LOG_DEBUG, "Send to VDE");
146 break;
148 default:
149 printlog(LOG_DEBUG, "Drop");
150 break;
154 void vxlan_send(in_addr_t addr_s, struct vxlan_pkt *pkt, size_t len) {
155 struct sockaddr_in addr;
157 addr.sin_family = AF_INET;
158 addr.sin_addr.s_addr = addr_s ? addr_s : vxlan_addr;
159 addr.sin_port = htons(vxlan_port);
161 memset(pkt, 0, offsetof(struct vxlan_pkt,pkt));
162 pkt->flags = (1 << 3);
164 hton24(pkt->id, vxlan_id);
166 if (sendto(vxlan_fd, pkt, len+offsetof(struct vxlan_pkt,pkt), 0,
167 (struct sockaddr *) &addr, sizeof(addr)) < 0)
168 printlog(LOG_ERR, "sendto(): %s", strerror(errno));
171 void vxlan_close() {
172 if (vxlan_fd == -1)
173 return;
175 struct ip_mreq mc_req;
177 mc_req.imr_multiaddr.s_addr = vxlan_addr;
178 mc_req.imr_interface.s_addr = htonl(INADDR_ANY);
180 if ((setsockopt(vxlan_fd, IPPROTO_IP, IP_DROP_MEMBERSHIP,
181 (void *) &mc_req, sizeof(mc_req))) < 0) {
182 printlog(LOG_ERR, "setsockopt(DROP): %s", strerror(errno));
183 exit(1);
186 close(vxlan_fd);