{"id":34983108,"url":"https://github.com/msune/uif","last_synced_at":"2026-04-17T10:02:54.881Z","repository":{"id":329157853,"uuid":"1118381278","full_name":"msune/uif","owner":"msune","description":"Creating 'untagged' subinterfaces in Linux","archived":false,"fork":false,"pushed_at":"2025-12-19T22:03:00.000Z","size":15,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-12-21T05:47:36.492Z","etag":null,"topics":["interface","linux","networking","vlan"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/msune.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE-GPL-2.0","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-17T17:05:05.000Z","updated_at":"2025-12-19T22:02:53.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/msune/uif","commit_stats":null,"previous_names":["msune/uif"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/msune/uif","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/msune%2Fuif","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/msune%2Fuif/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/msune%2Fuif/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/msune%2Fuif/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/msune","download_url":"https://codeload.github.com/msune/uif/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/msune%2Fuif/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28067208,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-12-26T02:00:06.189Z","response_time":55,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["interface","linux","networking","vlan"],"created_at":"2025-12-27T01:09:04.652Z","updated_at":"2025-12-27T01:09:08.464Z","avatar_url":"https://github.com/msune.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# `uif`: untagged subinterfaces in Linux\n\n`uif` is as small tool to create(emulate) untagged network subinterfaces\n`\u003ciface\u003e.ut` in Linux, so interfaces that only receive and send untagged\n(no VLAN) traffic. It leverages the power of :bee: [eBPF](https://ebpf.io/).\n\n## Quick start\n\nClone the repo and build:\n\n```\n$ make\n```\n\nTo create an 'untagged' subinterface over `veth0`:\n\n```\n$ sudo output/uif create veth0\n```\n\nThe subinterface can then be managed using standard Linux tools\n(e.g. `ip`), as any other network device.\n\n## Why?\n\nIn short:\n\n * To be able to **only do MAC learning on untagged traffic** on a Linux bridge\n   (with `vlan_filtering=0` [^1]) as opposed to what happens when you attach\n   the main interface.\n * To make it **compatible with TC/TCX BPF programs**.\n * To allow programs capturing or processing traffic (e.g. `tcpdump` or\n   `wireshark`) to handle untagged traffic only transparently, that is without\n   pcap filters, etc.\n * To have them modeled as a subinterface, with its own `ifindex` etc, similar\n   to how some switches and routers do it.\n\n### More details\n\nIn Linux, it's not possible to create a subinterface that sends and receives\nonly untagged traffic from a network device card (physical or virtual). A main\ninterface (e.g. `eth0`) sees all traffic, both untagged and tagged. VLAN\nsubinterfaces, on the other hand, see only traffic tagged with particular\nVLAN of that subinterface [^2].\n\nThis is generally not an issue at Layer 3, since assigning an IP address to an\ninterface implicitely applies to untagged traffic (no VLAN), but it is for\nLayer 2.\n\nWhen an interface is attached to a bridge with `vlan_filtering=0` (default),\nMAC learning happens using solely the destination MAC address of the received\npacket, regardless of the packet's VLAN tag or absence of (unqualified\nlearning). So attaching `eth0` to a bridge will learn from untagged traffic and\nfrom any other VLAN tagged traffic that `eth0` doesn't have an (outer) VLAN\nsubinterface for.\n\nThe lack of an \"untagged subinterface\" also prevents attaching (TC/TCX) eBPF\nprograms to a subinterface that would only process untagged frames.\n\n## How does it work?\n\n`uif` creates a VLAN 0 interface over the target interface with the name\n`\u003ciface\u003e.ut`, and it attaches two small eBPF TCX programs on ingress and egress\non `\u003ciface\u003e`.\n\nThese programs push a VLAN 0 tag on ingress and pop the VLAN0 tag on egress\nrespectively, to make sure untagged traffic is muxed/demuxed to `\u003ciface\u003e.ut`\ncorrectly.\n\nBecause of the place where TCX eBPF hooks execute, the result is that programs\nsuch as `tcpdump` and `wireshark` work as expected, transparently, seeing all\nuntagged and tagged traffic in `\u003ciface\u003e`, and only untagged traffic in\n`\u003ciface\u003e.ut`.\n\n### Compatibility with VLAN0 priority tagging\n\nAs VLAN 0 is (ab)used as a means to mux/demux to/from the main interface,\n[VLAN 0 priority tagging](https://www.cisco.com/c/en/us/td/docs/switches/connectedgrid/cg-switch-sw-master/software/configuration/guide/vlan0/b_vlan_0.html)\nis not supported.\n\n### Compatibility with other BPF programs\n\n`uif` attaches eBPF programs on ingress and egress of the primary interface\nusing [TCX](https://docs.ebpf.io/linux/program-type/BPF_PROG_TYPE_SCHED_CLS/).\nThese programs always return `TC_ACT_UNSPEC`, so it's safe to attach other\nprograms _after_ it on TCX, or in TC (they will always run after).\n\n[^1]: and in absence of L2 ACLs.\n[^2]: or when stacking VLAN interfaces (e.g. 2 interfaces to do 802.1ad), all\n      stacked VLANs.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmsune%2Fuif","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmsune%2Fuif","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmsune%2Fuif/lists"}