e1660b09d568d7c3738ce30841c2747c8e6d87ad
[sliver-openvswitch.git] / planetlab / pltap-ovs / pltap-ovs.c
1 #include <sys/un.h>
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <fcntl.h>
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <string.h>
8 #include <unistd.h>
9 #include <sys/socket.h>
10 #include <errno.h>
11 #include <linux/if.h>
12 #include <linux/if_tun.h>
13
14 #include "tunalloc.h"
15
16 #define OVS_SOCK "/var/run/pl-ovs.control"
17
18 void send_fd(int p, int fd, char* vif_name);
19
20 char *appname;
21
22 #define ERROR(msg)                                                              \
23         do {                                                                    \
24                 fprintf(stderr, "%s: %s: %s", appname, msg, strerror(errno));   \
25                 exit(1);                                                        \
26         } while (0)
27
28
29 static
30 int send_vif_fd(int sock_fd, int vif_fd, char *vif_name)
31 {
32         int retval;
33         struct msghdr msg;
34         struct cmsghdr *p_cmsg;
35         struct iovec vec;
36         size_t cmsgbuf[CMSG_SPACE(sizeof(vif_fd)) / sizeof(size_t)];
37         int *p_fds;
38
39
40         msg.msg_control = cmsgbuf;
41         msg.msg_controllen = sizeof(cmsgbuf);
42         p_cmsg = CMSG_FIRSTHDR(&msg);
43         p_cmsg->cmsg_level = SOL_SOCKET;
44         p_cmsg->cmsg_type = SCM_RIGHTS;
45         p_cmsg->cmsg_len = CMSG_LEN(sizeof(vif_fd));
46         p_fds = (int *) CMSG_DATA(p_cmsg);
47         *p_fds = vif_fd;
48         msg.msg_controllen = p_cmsg->cmsg_len;
49         msg.msg_name = NULL;
50         msg.msg_namelen = 0;
51         msg.msg_iov = &vec;
52         msg.msg_iovlen = 1;
53         msg.msg_flags = 0;
54
55         /* Send the interface name as the iov */
56         vec.iov_base = vif_name;
57         vec.iov_len = strlen(vif_name)+1;
58
59         while ((retval = sendmsg(sock_fd, &msg, 0)) == -1 && errno == EINTR);
60         if (retval == -1) {
61                 ERROR("sending file descriptor");
62         }
63         return 0;
64 }
65
66 void send_fd(int p, int fd, char* vif_name)
67 {
68         int control_fd;
69         int accept_fd;
70         struct sockaddr_un addr, accept_addr;
71         socklen_t addr_len = sizeof(accept_addr);
72
73         control_fd = socket(AF_UNIX, SOCK_STREAM, 0);
74         if (control_fd == -1 && errno != ENOENT) {
75                 ERROR("Could not create UNIX socket");
76         }
77
78         memset(&addr, 0, sizeof(struct sockaddr_un));
79         /* Clear structure */
80         addr.sun_family = AF_UNIX;
81         strncpy(addr.sun_path, OVS_SOCK,
82                         sizeof(addr.sun_path) - 1);
83
84         if (unlink(OVS_SOCK) == -1 && errno != ENOENT) {
85                 ERROR("Could not unlink " OVS_SOCK " control socket");
86         }
87
88         if (bind(control_fd, (struct sockaddr *) &addr,
89                                 sizeof(struct sockaddr_un)) == -1) {
90                 ERROR("Could not bind to " OVS_SOCK " control socket");
91         }
92
93         if (listen(control_fd, 5) == -1) {
94                 ERROR("listen on " OVS_SOCK " failed");
95         }
96         if (write(p, "1", 1) != 1) {
97                 ERROR("writing on the synch pipe");
98         }
99         if ((accept_fd = accept(control_fd, (struct sockaddr*) &accept_addr,
100                                                 &addr_len)) == -1) {
101                 ERROR("accept on " OVS_SOCK " failed");
102         }
103         send_vif_fd(accept_fd, fd, vif_name);
104 }
105
106 int main(int argc, char* argv[])
107 {
108         char if_name[IFNAMSIZ];
109         int p[2]; // synchronization pipe
110         char dummy;
111         int tun_fd;
112
113         (void) argc; // unused
114
115         if (pipe(p) < 0) {
116                 ERROR("pipe");
117         }
118
119         tun_fd = tun_alloc(IFF_TAP, if_name);
120
121         appname = argv[0];
122
123         switch(fork()) {
124         case -1:
125                 ERROR("fork");
126                 exit(1);
127         case 0:
128                 close(1);
129                 open("/dev/null", O_WRONLY);
130                 close(p[0]);
131                 send_fd(p[1], tun_fd, if_name);
132                 exit(0);
133         default:
134                 close(p[1]);
135                 if (read(p[0], &dummy, 1) != 1) {
136                         ERROR("reading from the synch pipe");
137                 }
138                 printf("%s\n", if_name);
139         }
140         return 0;
141 }