This is generally better handled by letting the os network stack do its job, and at most run namespacing for isolation for the clients. Its total overkill to have the application understand stuff below layer 3 when the stack itself is designed to handle all of this trivially already.

Like you could add support for vxlan, qinq etc, or just configure the virtual interfaces on the box properly in about 4 lines of netconf and just tap the virtual interface and avoid all this extra work duplicating the effort.