2 * Lightweight Autonomic Network Architecture
4 * General purpose vlink layer userspace tool for binding low-level
5 * transport layers to LANA, i.e. Ethernet, ATM, Bluetooth, Serial
6 * Link, Inifiband and so on.
8 * strlcpy taken from the Linux kernel.
9 * Copyright 1991, 1992 Linus Torvalds <torvalds@linux-foundation.org>
11 * Copyright 2011 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,
12 * Swiss federal institute of technology (ETH Zurich)
22 #include <sys/socket.h>
23 #include <sys/types.h>
24 #include <linux/netlink.h>
30 # define likely(x) __builtin_expect(!!(x), 1)
33 # define unlikely(x) __builtin_expect(!!(x), 0)
36 # define bug() __builtin_trap()
39 #define PROGNAME "vlink"
40 #define VERSNAME "0.9"
42 size_t strlcpy(char *dest
, const char *src
, size_t size
)
44 size_t ret
= strlen(src
);
47 size_t len
= (ret
>= size
) ? size
- 1 : ret
;
48 memcpy(dest
, src
, len
);
55 static inline void die(void)
60 static inline void panic(char *msg
, ...)
64 vfprintf(stderr
, msg
, vl
);
70 static inline void whine(char *msg
, ...)
74 vfprintf(stderr
, msg
, vl
);
78 static void *xzmalloc(size_t size
)
82 if (unlikely(size
== 0))
83 panic("xzmalloc: zero size\n");
86 if (unlikely(ptr
== NULL
))
87 panic("xzmalloc: out of memory (allocating %lu bytes)\n",
94 static void xfree(void *ptr
)
96 if (unlikely(ptr
== NULL
))
97 panic("xfree: NULL pointer given as argument\n");
101 void check_for_root_maybe_die(void)
103 if (geteuid() != 0 || geteuid() != getuid())
104 panic("Uhhuh, not root?! \n");
107 static void usage(void)
109 printf("\n%s %s\n", PROGNAME
, VERSNAME
);
110 printf("Usage: %s <linktype> <cmd> [<args> ...]\n", PROGNAME
);
111 printf("Linktypes:\n");
112 printf(" ethernet\n");
113 printf("Commands:\n");
114 printf(" add <name> <rootdev> <port>\n");
115 printf(" rm <name>\n");
116 printf(" hook <rootdev>\n");
117 printf(" unhook <rootdev>\n");
119 printf("Please report bugs to <dborkma@tik.ee.ethz.ch>\n");
120 printf("Copyright (C) 2011 Daniel Borkmann\n");
121 printf("License: GNU GPL version 2\n");
122 printf("This is free software: you are free to change and redistribute it.\n");
123 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
128 static void version(void)
130 printf("\n%s %s\n", PROGNAME
, VERSNAME
);
131 printf("Please report bugs to <dborkma@tik.ee.ethz.ch>\n");
132 printf("Copyright (C) 2011 Daniel Borkmann\n");
133 printf("License: GNU GPL version 2\n");
134 printf("This is free software: you are free to change and redistribute it.\n");
135 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
140 void do_ethernet(int argc
, char **argv
)
144 struct sockaddr_nl src_addr
, dest_addr
;
145 struct nlmsghdr
*nlh
;
148 struct vlinknlmsg
*vmsg
;
150 if (unlikely(argc
== 0))
152 if (!strncmp("add", argv
[0], strlen("add")) && argc
== 4)
153 cmd
= VLINKNLCMD_ADD_DEVICE
;
154 else if (!strncmp("rm", argv
[0], strlen("rm")) && argc
== 2)
155 cmd
= VLINKNLCMD_RM_DEVICE
;
156 else if (!strncmp("hook", argv
[0], strlen("hook")) && argc
== 2)
157 cmd
= VLINKNLCMD_START_HOOK_DEVICE
;
158 else if (!strncmp("unhook", argv
[0], strlen("unhook")) && argc
== 2)
159 cmd
= VLINKNLCMD_STOP_HOOK_DEVICE
;
163 sock
= socket(PF_NETLINK
, SOCK_RAW
, NETLINK_VLINK
);
164 if (unlikely(sock
< 0))
165 panic("Cannot get NETLINK_VLINK socket from kernel! "
166 "Modules not loaded?!\n");
168 memset(&src_addr
, 0, sizeof(src_addr
));
169 src_addr
.nl_family
= AF_NETLINK
;
171 src_addr
.nl_pid
= getpid();
172 src_addr
.nl_groups
= 0;
174 ret
= bind(sock
, (struct sockaddr
*) &src_addr
, sizeof(src_addr
));
176 panic("Cannot bind socket!\n");
178 memset(&dest_addr
, 0, sizeof(dest_addr
));
179 dest_addr
.nl_family
= AF_NETLINK
;
180 dest_addr
.nl_pad
= 0;
181 dest_addr
.nl_pid
= 0;
182 dest_addr
.nl_groups
= 0;
184 nlh
= xzmalloc(NLMSG_SPACE(sizeof(*vmsg
)));
185 nlh
->nlmsg_len
= NLMSG_SPACE(sizeof(*vmsg
));
186 nlh
->nlmsg_pid
= getpid();
187 nlh
->nlmsg_type
= VLINKNLGRP_ETHERNET
;
188 nlh
->nlmsg_flags
= NLM_F_REQUEST
;
190 vmsg
= (struct vlinknlmsg
*) NLMSG_DATA(nlh
);
192 if (cmd
== VLINKNLCMD_ADD_DEVICE
)
193 vmsg
->port
= (uint16_t) (0xFFFF & atoi(argv
[3]));
195 strlcpy((char *) vmsg
->virt_name
, argv
[1], sizeof(vmsg
->virt_name
));
196 if (cmd
== VLINKNLCMD_ADD_DEVICE
)
197 strlcpy((char *) vmsg
->real_name
, argv
[2],
198 sizeof(vmsg
->real_name
));
199 else if (cmd
== VLINKNLCMD_START_HOOK_DEVICE
||
200 cmd
== VLINKNLCMD_STOP_HOOK_DEVICE
)
201 strlcpy((char *) vmsg
->real_name
, argv
[1],
202 sizeof(vmsg
->real_name
));
205 iov
.iov_len
= nlh
->nlmsg_len
;
207 memset(&msg
, 0, sizeof(msg
));
208 msg
.msg_name
= &dest_addr
;
209 msg
.msg_namelen
= sizeof(dest_addr
);
213 ret
= sendmsg(sock
, &msg
, 0);
214 if (unlikely(ret
< 0))
215 panic("Cannot send NETLINK message to the kernel!\n");
221 int main(int argc
, char **argv
)
223 check_for_root_maybe_die();
228 if (!strncmp("help", argv
[0], strlen("help")))
230 else if (!strncmp("version", argv
[0], strlen("version")))
232 else if (!strncmp("ethernet", argv
[0], strlen("ethernet")))
233 do_ethernet(--argc
, ++argv
);