How to create a vlan programmatically?
The situation was the following: I had to reinstall a server from scratch, remotely, using an IP-KVM. I was using a simple debian netinstall. When the network step came, I skiped as much as possible to type (you know, copy and paste issues) the networking configuration, which was involving vlan and brige. The install process finishes, the machine reboot and ... no network!
Disclaimer: Yes ifconfig could do the job. It's just that the bonding utilities were not installed, nor vlan's. Hence, I felt kind of stuck there, so I figured out a way to create VLAN by hand. I bet it's an ioctl thing. Hey debian is shiped with Perl, which can do ioctl! I might be saved after all! The actual issue was that my configuration was involving bond0, which could not be created. But iproute error message were so obvious, that it was not my first guess. Anyway, I found if fun enough to share; eventhough I managed to make it work using the proper interface name afterwards...
So the configuration is the following: a physical server having two network interfaces. Each of them is connected to a different switch. Both switch basically have the same configuration. The server (running debian) was configured to use failover bonding. On top of the bonded interfaces, are several vlans. In particular, one was used to access publicly reachable network. So, I had to bind vlan 73 to eth0.
This debian box runs on a 3.16 kernel. Let's go and see the source!
VLAN are handled in net/8021q/. I suppose we're looking for ioctl commands: there's an interesting function: static int vlan_ioctl_handler(struct net *net, void __user *arg) (l 487) which accepts a ADD_VLAN_CMD which uses takes a
To sumup, we need to craft a blob which contains a int (cmd) 24 char (device1) int (vlan id in union) short (vlan qos). And the, we need to route the ioctl command to the vlan module. Hence, the command to provide ioctl is
- create a socket;
- create the blob to fit in the struct vlan_ioctl_args format;
- invoke ioctl with that payload;
- profit!
And that's it! Also, this can be done with a one-liner:
<pre>perl -MIO::Socket -e "ioctl(IO::Socket::INET->new('Proto' => 'tcp'), 0x8983, pack('l Z24 L s', 0, "eth0", 73, 0));"</pre>
References:
- https://wiki.debian.org/Bonding
- http://lxr.free-electrons.com/source/include/uapi/linux/sockios.h#L110
- http://lxr.free-electrons.com/source/net/socket.c
- https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/net/8021q/vlan.c?h=v3.16
- https://fossies.org/dox/iproute2-4.8.0/if__vlan_8h_source.html
Add new comment