VLAN tagging on Mikrotik RouterOS 6

Mikrotik doesn’t have quite the same brand recognition as the bigger players in the SOHO networking space, so it’s a bit of a surprise that Mikrotik has some of the most feature-rich network appliances under $200. I’m not aware of anything else that acts a layer-3 switch, provides console access, and has the same granular control for the price.

However, the one and only downside of this is that they hide all of these features in the most counter-intuitive interface possible. There are no less than three unique sections to edit in order to successfully VLAN-tag an interface in the Mikrotik CLI, and it will silently fail if you omit one of them (!).

Ultimately, my goal is to trunk multiple VLANs between my existing Cloud Router switch in my basement to the five-port RB750Gr2 acting as a switch in my office, so I can move my NTP server (and subnet) upstairs next to the window with good GPS reception. In Mikrotik parlance a ‘trunk’ port is an aggregation port a la 802.3ad, so for clarity’s sake the instructions below are for creating dot1Q trunks.

Some notes:
– You should have an existing, working VLAN configuration on the switch.
– I’m using a RB750G configured as a simple switch on the other end, with no VLANs configured.
– CRS-125-24G connecting to RB750Gr2, Mikrotik RouterOS 6.40.1 on both devices

STEP 1: Take a backup!

[admin@MikroTik] /> /system backup save name=crs125-24G_20170817
Saving system configuration
Configuration backup saved

a. Download this backup from the web GUI, in the ‘Files’ section

STEP 2: Configure free interface ‘ether24’ on the Cloud Router switch

a. Using ‘ether24’ as the interface in this example, make a comment so you know what the hell it is in six months.

/interface ethernet comment ether24 comment="upstairs. vlan10 vlan100 vlan123"

b. Ensure ‘network-port’ (default) is set for the port

[admin@MikroTik] /interface ethernet switch port> set ether24 vlan-type=network-port

c. Add egress-vlan-tag tagged-ports entries for ether24

[admin@MikroTik] /> /interface ethernet switch egress-vlan-tag print
Flags: X - disabled, I - invalid, D - dynamic
 0       100 ether1-master
 1        10 ether1-master
 2       200 ether2
 3       299 ether2
 4       999 ether2
 5       123 ether1-master
 6 D    4095

[admin@MikroTik] /> /interface ethernet switch egress-vlan-tag set numbers=0 tagged-ports=ether1-master,ether24,switch1-cpu
[admin@MikroTik] /> /interface ethernet switch egress-vlan-tag set numbers=1 tagged-ports=ether1-master,ether24
[admin@MikroTik] /> /interface ethernet switch egress-vlan-tag set numbers=5 tagged-ports=ether1-master,ether24
[admin@MikroTik] /> /interface ethernet switch egress-vlan-tag print

Flags: X - disabled, I - invalid, D - dynamic
 0       100 ether1-master
 1        10 ether1-master
 2       200 ether2
 3       299 ether2
 4       999 ether2
 5       123 ether1-master
 6 D    4095

d. Edit the interface to vlan-id mapping. Output looks like this:

[admin@MikroTik] /interface ethernet switch vlan> print
Flags: X - disabled, I - invalid, D - dynamic
 0        10 ether1-master     no  yes   no    no             none

Use this command to edit the ‘#’ column in a nano-like editor, and add ‘ether24’ at the end. Ctrl+o to save and quit. Where ‘#’ column is ‘0’:

[admin@MikroTik] /interface ethernet switch vlan> edit 0 ports

Add ether24 to all vlan-ids required, using the above steps.

At this point the Cloud Router switch is ready to trunk via ether24! Now we have to set up the RB750G to accept and de-encapsulate the VLANs.

STEP 3: Configure the RB750G

This part is a bit tricky. I think it’s easiest to dump my working config so you can get an idea of what’s going on, and modify to suit your environment.

Note that I have my RB750G mgmt interface (switch1-cpu) tied to my management VLAN (vlan100), so it requires some magic to get working without a console connection. I set up two IP addresses and used a direct connection from a laptop to the RB750 to configure the second VLAN-enabled mgmt connection. Once you cut over the switch1-cpu port config to ‘secure’ VLAN type, you lose connectivity to the device if your configs are incorrect. Note to self: Get networking devices with a console connection.

Additionally, I stripped out all of the routing configs and reconfigured the ‘interface ethernet’ ports to all utilize ether1 as the master, renaming it from ‘ether1’ to ‘ether1-master’, and renaming ‘ether2-master’ to ‘ether2’.

Take backups often during configuration, as it is easy to lock yourself out without a console connection. If that happens, just restore default configs and restore the last good backup.

# aug/18/2017 23:36:18 by RouterOS 6.40.1
/interface ethernet
set [ find default-name=ether1 ] name=ether1-master
set [ find default-name=ether2 ] master-port=ether1-master
set [ find default-name=ether3 ] master-port=ether1-master
set [ find default-name=ether4 ] master-port=ether1-master
set [ find default-name=ether5 ] master-port=ether1-master
/interface vlan
add interface=ether1-master name=ether1-vlan10 vlan-id=10
add interface=ether1-master name=ether1-vlan100 vlan-id=100
add interface=ether1-master name=ether1-vlan123 vlan-id=123
/interface ethernet switch port
set 0 vlan-header=add-if-missing vlan-mode=secure
set 4 default-vlan-id=10 vlan-header=always-strip vlan-mode=secure
set 5 vlan-mode=secure
/ip hotspot profile
set [ find default=yes ] html-directory=flash/hotspot
/interface ethernet switch vlan
add independent-learning=yes ports=ether1-master,ether5 switch=switch1 vlan-id=10
add independent-learning=yes ports=ether1-master,switch1-cpu switch=switch1 vlan-id=100
add independent-learning=yes ports=ether1-master,ether4 switch=switch1 vlan-id=123
/ip address
add address= comment=vlan100_mgt interface=ether1-vlan100 network=
/ip dns
set servers=
/ip route
add distance=1 gateway=
/system clock
set time-zone-name=America/Detroit
/system ntp client
set enabled=yes primary-ntp=

STEP 4: Take final backups

/system backup save

Mikrotik VLAN
My initial VLAN trunk adventure from 2016
802.1q trunking on Mikrotik router/switch (StackExchange)
Cloud Router Switch CRS125-24G-1S
hEX v3 router

Shorewall DDNS script

Since running Shorewall on my APU2c4 running a EL distro, I found myself replicating all of the built-ins that were present in other all-in-one projects such as pfSense or openWRT. Here’s one of my quick scripts to replace some of that functionality. This checks and updates my domain’s DNS from my Shorewall router hourly.

It performs a check of the IP reported by my domain’s resolver against the IP of my default gateway, and updates using the DDNS URL if necessary.

– Not tested against IPv6 or complex routing scenarios!
– Place in /etc/cron.d/hourly or /etc/cron.d/daily
– The DDNS_QUERY var is highly dependent on your DDNS provider, adjust as necessary

# Simple Dynamic DNS Script
# - Use-case: UNIX-based server acting as front door router
# - Performs comparison between domain A versus default gw
# - Not tested with IPv6 or complex routing scenarios (dual WAN, etc.)


DNSIP=$(dig +short @${RESOLVER} ${DOMAIN}) # get IP address of domain from resolver
WANIP=$(ip route get 1 | awk '{print $NF;exit}') # get IP address of default gateway

DDNS_HOST='YOUR_HOST' # the host record (TLD, '@', etc)

DNSIP=$(dig +short @${RESOLVER} ${DOMAIN})
WANIP=$(ip route get 1 | awk '{print $NF;exit}')

#echo ${DNSIP}
#echo ${WANIP}

if [ "${DNSIP}" != "${WANIP}" ]; then
curl --silent "${DDNS_URL}/${DDNS_QUERY}" 2>&1 1>/dev/null

Flash BIOS of APU2c4

Updated for March 2017 BIOS

I recently purchased the latest version of the venerable PCEngines APU: the apu2c4.

The coreboot BIOS is still WIP, and the device I received had BIOS version 160307. I need PXE or iPXE support to kickstart CentOS 7.2, and luckily the latest BIOS version available (160311) supports iPXE.

Here is my rough guide to flash the APU2c4 BIOS, using Fedora 23 to make a flash drive.

sudo dnf install syslinux
# insert flash drive; find physical address
# assuming flash drive is /dev/sdb

sudo parted /dev/sdb mklabel msdos
sudo parted /dev/sdb mkpart primary fat16 2048s 2G
sudo mkfs.vfat /dev/sdb1
sudo dd if=/usr/share/syslinux/mbr.bin of=/dev/sdb
sudo syslinux --install /dev/sdb1
sudo parted /dev/sdb set 1 boot on
cd ~; mkdir temp
sudo mount /dev/sdb1 temp/
cd temp/
sudo wget http://pcengines.ch/file/apu2-tinycore6.4.tar.bz2
sudo wget https://www.pcengines.ch/file/apu2_v4.0.7.rom.zip
sudo tar --no-same-owner xvf apu2-tinycore6.4.tar.bz2
sudo unzip apu2_v4.0.7.rom.zip
sudo rm -vf apu2-tinycore6.4.tar.bz2 apu2_v4.0.7.rom.zip
cd ..
sudo umount ./temp

# unplug flash drive from computer
# plug flash drive in to apu
# attach usb keyboard to apu
# power on apu

# press f10
# boot from usb drive
# you may notice some errors about autostart.sh and FAT partition, safe to ignore

sdb      8:16   1  14.8G  0 disk 
`-sdb1   8:17   1   1.9G  0 part /media/usbhd-sdb1

cd /media/usbhd-sdb1
flashrom -p internal -w apu2_v4.0.7.rom

# reboot after completion
# power on, press f10, choose iPXE


# proceed with iPXE goodness

Some additional reading and references:

Infoblox DHCP Filters for Mixed UEFI/BIOS PXE Boot

After migrating all of our DHCP helpers to Infoblox in the past few weeks, one of the annoyances we had was having to override the bootfile name in the DHCP lease for new hosts that were being built. Since all new server hardware purchases have UEFI enabled by default, in order to PXE boot from your TFTP server, you have to pass it a different bootfile (bootx64.efi) than you would if you were using a traditional BIOS-based system. Some of our admins were either manually overriding the host record in Infoblox to use bootx64.efi as its bootfile (instead of pxelinux.0 if you’re using syslinux), or, even worse, putting the machine into legacy BIOS mode in order to kickstart the box. What I needed was a way for Infoblox to automatically present the needed boot file without any extra steps in the provisioning process.

Continue reading Infoblox DHCP Filters for Mixed UEFI/BIOS PXE Boot

OpenLDAP to Active Directory Proxy Configuration

One of the more glaring issues with the environment I’m currently supporting is that there’s no single sign on. Workstations and web tools (mostly Atlassian in nature – Stash, Jira, Confluence, et al) all authenticate against our Active Directory environment. However, all of our Linux and Solaris hosts authenticate against a separate OpenLDAP environment, so users have to maintain two different sets of credentials and passwords. This has all the extra baggage that comes from maintaining password policies, such as two different auth sources that you can get locked out from. I elected to take up the task to eliminate one of the environments, and given that our OpenLDAP database was significantly smaller than Active Directory, we decided to eliminate OpenLDAP from the environment.

I considered three approaches for achieving this. The quick and dirty method is to use SASL passthrough authentication, which is supported by OpenLDAP as detailed in this page. In short, you can take an existing user account in OpenLDAP and modify their userPassword attribute, replacing the existing hash with “{SASL}user@domain” which will point to a matching user in Active Directory. While this would satisfy the requirement of single sign-on, it still requires that you maintain an OpenLDAP backend database for all other data, such as homeDirectory, loginShell, uid, gid, and so on.

A second option is to not use an OpenLDAP server at all, and configure all your clients to natively talk to Active Directory. This isn’t terribly difficult as long as you’re using SSSD – see this excellent article on the subject. However, I’d have to gut a large amount of the environment to move to sssd, and it requires some software bloat – namely, Samba – in order to work. While this wasn’t necessarily a dealbreaker, I didn’t think it was the cleanest option.

The third method – and ultimately is the one we chose to pursue – is to continue leveraging an OpenLDAP backend, but proxy the requests to Active Directory. This has the benefit of utilizing a single source of authentication (AD, in our case) and allows us to continue using the native OpenLDAP client that all our hosts are currently utilizing without any additional configuration. Additionally, it would allow any applications that have weaker LDAP client support to continue to work. The OpenLDAP proxy can also remap fields on the fly, taking an OpenLDAP attribute and remap it to its AD equivalent – translating “uid” to “sAMAccountName”, for example. This allows for maximum flexibility without requiring any special configuration on the client side. The only real downside is that you add an additional layer of complexity to the flow of authentication, which means one extra spot you may have to troubleshoot in the event of auth issues. Still, it seemed this approach would be the best one for us.

Continue reading OpenLDAP to Active Directory Proxy Configuration

APU1C4 serial to usb console

During an upgrade from pfsense 2.1.5 (FreeBSD 8) to pfsense 2.2 (FreeBSD 10), my AMD APU router became unresponsive using tools such as ping and ssh. It required connecting via serial console. Here’s a quick overview.

Model number of the board: PCEnginges APU1C4 T40E
USB to male serial: TRENDnet USB to RS-232 DB9 Serial Converter
Null model cable: DB9 RS232 Serial Null Modem Cable F/F (SCNM9FF)
Build reference: Unpacking and Assembling PC Engines APU

I have an older Lenovo Thinkpad T400 acting as a server running CentOS 7 that provides lightweight services such as DHCP, DNS, and iPXE to my LAN. To gain access to the router’s console, I plugged in the serial converter above to the Thinkpad and attached it to the null-modem cable that was hooked up to the router.

I verified on the laptop that everything was detected via dmesg | tail -10 and ls -l /dev/ttyUSB?, which showed the following:

$ dmesg | tail -25
[4643071.873119] usb 6-2: new full-speed USB device number 2 using uhci_hcd
[4643072.019109] usb 6-2: New USB device found, idVendor=067b, idProduct=2303
[4643072.019119] usb 6-2: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[4643072.019126] usb 6-2: Product: USB-Serial Controller D
[4643072.019131] usb 6-2: Manufacturer: Prolific Technology Inc.
[4643072.128738] usbcore: registered new interface driver pl2303
[4643072.128766] usbserial: USB Serial support registered for pl2303
[4643072.128785] pl2303 6-2:1.0: pl2303 converter detected
[4643072.140519] usb 6-2: pl2303 converter now attached to ttyUSB0

$ ls -l /dev/ttyUSB?
crw-rw----. 1 root dialout 188, 0 Jan 24 17:59 /dev/ttyUSB0

To connect to the console, I used the following command:

screen /dev/ttyUSB0 115200

From there I was able to troubleshoot and debug as necessary on the pfsense shell.

cmd.exe replacement in Windows 7/8

As someone who bounces back and forth between Windows, Mac OS X, and Linux, one of the most consistently frustrating aspects of Windows is the lack of decent terminal emulation support. I’ve always been a fan of the simplicity of cygwin+mintty but it has always been lacking tab functionality along with a few other nice-to-haves – especially when compared with a more evolved terminal emulator in Gnome or OS X. A coworker recently pointed me in the direction of ‘cmder’, a conemu repackage that pre-configures a lot necessary settings to make the user experience more streamlined. cmder-mini is a portable version of the program – all settings and data are confined to the directory it is extracted to. My goal was to configure something lightweight and that rivals mintty, Console2, and ConsoleZ in terms of both usability and features.

Please note the main focus when I use terminal emulation on Windows is connecting from my windows host to a remote UNIX server, so Powershell and cmd.exe integration are not covered here (although they work out of the box). I also don’t care about most basic Linux binaries within Windows, besides the fact that they perform horribly due to the missing fork() functionality. I just need something that supports SSH and bind-utils natively.



  • Cygwin with openSSH and bind-utils, cmder-mini zip file

Install cygwin, extract cmder-mini to desired location, open ‘Cmder.bat’, right click on taskbar, ‘Settings’

Default shell of Cygwin bash:

  • Startup -> Tasks: Click ‘+’
  • Name: ‘cygwin-bash’
  • Task Parameters: ‘/dir “C:cygwin64home<user>”‘
  • File Path…: ‘C:cygwin64Cygwin.bat’
  • Startup: Specified Named Task: ‘{cygwin-bash}’

Ctrl+T to create a new tab, select ‘cygwin bash’ as shell, and away you go…




### Tab manipulation

* `Ctrl + t` : new tab dialog (maybe you want to open cmd as admin?)
* `Ctrl + w` : close tab
* `Ctrl + alt + number` : fast new tab: `1` – CMD, `2` – Powershell `*` – More to come
* `Alt + enter`: Fullscreen

### Shell

* `Shift + Up` : Traverse up in directory structure (lovely feature!)
* `End, Home, ctrl` : Traversing text with as usual on Windows
* `Ctrl + r` : History search
* `Shift + mouse` : Select and copy text from buffer


I’m sure there are tons of other options to configure to make this shinier, but this basic configuration should get anyone looking to connect to a remote host via SSH using tabs (!!!)¬†off to a good start.

Edit: So I discovered that it’s impossible to pin a shortcut to a batch file onto the Windows 7 taskbar. ¬†Here’s a workaround:

  • Right click on ‘Cmder.bat’ and select ‘Send To -> Desktop’
  • On Desktop, right click on ‘Cmder.bat – Shortcut’ and select ‘Properties’
  • Change target to ‘cmd.exe /C “C:pathtoCmder.bat”‘, select ‘OK’ (change name here too if desired)
  • Drag edited shortcut to Taskbar

Failed storage vmotion: when VMware’s log verbosity tells you Nothing At All

I recently was in the middle of migrating an entire cluster of VMs (190 in all) to a different datastore. 189 of them migrated just fine, but a single one gave me grief during the svmotion with the following error:

Relocate virtual machine
File /vmfs/volumes/f08ad362-ff1e8a5b/naughtyvm3161p/naughtyvm3161p-000001.vmdk was not found

This is especially curious, because when browsing the datastore, the vmdk certainly existed, albeit as naughtyvm3161p-000002.vmdk. Looking at all the config files (the vmx, the vmdk, et al) on the datastore with my favorite text editor, all of these reference the proper, existing 00002.vmdk file. The GUI, too, points to the proper file. So what on earth still thinks the VMDK was at its old name?

vpxa.log and hostd.log on the VM host were no help either – hostd.log just showed the error, and vpxa merely spat out a few thousand lines of it looking up the datastore with nothing meaningful about WHAT was referencing that file

2013-07-18T13:57:14.512Z [7B004B90 verbose 'Default' opID=AC56DD98-000446B3-3a-f0] [VpxaVmprovUtil] LocalPathToDatastoreUrl conversion: /vmfs/volumes/51e0170e-514c8539-b69a-68b599b15d64/naughtyvm3161p/naughtyvm3161p-000001.vmdk -> ds:///vmfs/volumes/51e0170e-514c8539-b69a-68b599b15d64/
2013-07-18T14:22:36.622Z [7AFA1B90 info 'DiskLib' opID=AC56DD98-00044873-1a-77] DISKLIB-DSCPTR: DescriptorDetermineType: failed to open '/vmfs/volumes/f08ad362-ff1e8a5b/naughtyvm3161p/naughtyvm3161p-000001.vmdk': Could not find the file (600000003)

Real helpful, as you can see. Peak snark was hit at around 9:57AM, when I realized I needed more coffee.

And then I noticed on a lark that this particular VM had a snapshot – based on the fact that it had a “delta” vmdk file. Why? No clue. None of these VMs should be using snapshots. After busting out the snapshot hatchet (the snatchet? the snapchet? idk) the storage vmotion was successful.

Goofy as hell, but that’s vmware for you.