Skip to content

Commit

Permalink
Generate tuntap constants
Browse files Browse the repository at this point in the history
  • Loading branch information
thomascellerier committed Dec 13, 2024
1 parent 5ac51b9 commit 4783a85
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 60 deletions.
6 changes: 3 additions & 3 deletions src/aiortnetlink/link.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ class ARPHRDType(IntEnum):
NONE: Final = 65534
LOOPBACK: Final = 772

@property
def constant_name(self) -> str:
return f"ARPHRD_{self.name}"
@property
def constant_name(self) -> str:
return f"ARPHRD_{self.name}"


class IFLAType(IntEnum):
Expand Down
96 changes: 50 additions & 46 deletions src/aiortnetlink/tuntap.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,50 +2,54 @@
import os
import struct
import typing
from enum import IntEnum
from typing import Final, Literal

__all__ = ["create_tuntap", "delete_tuntap"]


_IOC_NRBITS: Final = 8
_IOC_TYPEBITS: Final = 8
_IOC_SIZEBITS: Final = 14
_IOC_DIRBITS: Final = 2
class TunIoctl(IntEnum):
SETNOCSUM: Final = 0x400454C8
SETDEBUG: Final = 0x400454C9
SETIFF: Final = 0x400454CA
SETPERSIST: Final = 0x400454CB
SETOWNER: Final = 0x400454CC
SETLINK: Final = 0x400454CD
SETGROUP: Final = 0x400454CE
GETFEATURES: Final = -0x7FFBAB31
SETOFFLOAD: Final = 0x400454D0
SETTXFILTER: Final = 0x400454D1
GETIFF: Final = -0x7FFBAB2E
GETSNDBUF: Final = -0x7FFBAB2D
SETSNDBUF: Final = 0x400454D4
ATTACHFILTER: Final = 0x401054D5
DETACHFILTER: Final = 0x401054D6
GETVNETHDRSZ: Final = -0x7FFBAB29
SETVNETHDRSZ: Final = 0x400454D8
SETVNETBE: Final = 0x400454DE
GETVNETBE: Final = -0x7FFBAB21
SETSTEERINGEBPF: Final = -0x7FFBAB20
SETFILTEREBPF: Final = -0x7FFBAB1F
SETCARRIER: Final = 0x400454E2
GETDEVNETNS: Final = 0x54E3

@property
def constant_name(self) -> str:
return f"TUN{self.name}"


class TunIffFlag(IntEnum):
TUN: Final = 1 << 0
TAP: Final = 1 << 1
NO_PI: Final = 1 << 12
ONE_QUEUE: Final = 1 << 13
VNET_HDR: Final = 1 << 14
TUN_EXCL: Final = 1 << 15

@property
def constant_name(self) -> str:
return f"IFF_{self.name}"

_IOC_NRSHIFT: Final = 0
_IOC_TYPESHIFT: Final = _IOC_NRSHIFT + _IOC_NRBITS
_IOC_SIZESHIFT: Final = _IOC_TYPESHIFT + _IOC_TYPEBITS
_IOC_DIRSHIFT: Final = _IOC_SIZESHIFT + _IOC_SIZEBITS

IOC_WRITE: Final = 1
IOC_READ: Final = 2


def _ioc(dir_: int, type_: int, nr: int, size: int) -> int:
return (
(dir_ << _IOC_DIRSHIFT)
| (type_ << _IOC_TYPESHIFT)
| (nr << _IOC_NRSHIFT)
| (size << _IOC_SIZESHIFT)
)


def _iow(type_: int, nr: int, size: int) -> int:
return _ioc(IOC_WRITE, type_, nr, size)


def _ior(type_: int, nr: int, size: int) -> int:
return _ioc(IOC_READ, type_, nr, size)


TUNSETIFF: Final = _iow(ord("T"), 202, struct.calcsize("i"))
TUNSETPERSIST: Final = _iow(ord("T"), 203, struct.calcsize("i"))
TUNSETOWNER: Final = _iow(ord("T"), 204, struct.calcsize("i"))
TUNSETGROUP: Final = _iow(ord("T"), 206, struct.calcsize("i"))
TUNGETIFF: Final = _ior(ord("T"), 210, struct.calcsize("I"))

IFF_TUN: Final = 0x0001
IFF_TAP: Final = 0x0002

IFNAMSIZ: Final = 16

Expand All @@ -61,9 +65,9 @@ def _ifreq_setiff(name: str, mode: Literal["tun", "tap"]) -> bytes:
flags = 0
match mode:
case "tun":
flags |= IFF_TUN
flags |= TunIffFlag.TUN
case "tap":
flags |= IFF_TAP
flags |= TunIffFlag.TAP
case unreachable:
typing.assert_never(unreachable)
return _IFReq.pack(name.encode("ascii"), flags)
Expand All @@ -79,12 +83,12 @@ def create_tuntap(
) -> None:
with open(dev_tun_path, "rb") as f:
fd = f.fileno()
fcntl.ioctl(fd, TUNSETIFF, _ifreq_setiff(name, mode))
fcntl.ioctl(fd, TunIoctl.SETIFF, _ifreq_setiff(name, mode))
if uid is not None:
fcntl.ioctl(fd, TUNSETOWNER, uid)
fcntl.ioctl(fd, TunIoctl.SETOWNER, uid)
if gid is not None:
fcntl.ioctl(fd, TUNSETGROUP, gid)
fcntl.ioctl(fd, TUNSETPERSIST, 1)
fcntl.ioctl(fd, TunIoctl.SETGROUP, gid)
fcntl.ioctl(fd, TunIoctl.SETPERSIST, 1)


def delete_tuntap(
Expand All @@ -95,5 +99,5 @@ def delete_tuntap(
) -> None:
with open(dev_tun_path, "rb") as f:
fd = f.fileno()
fcntl.ioctl(fd, TUNSETIFF, _ifreq_setiff(name, mode))
fcntl.ioctl(fd, TUNSETPERSIST, 0)
fcntl.ioctl(fd, TunIoctl.SETIFF, _ifreq_setiff(name, mode))
fcntl.ioctl(fd, TunIoctl.SETPERSIST, 0)
35 changes: 35 additions & 0 deletions tools/gen_constants.c

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

95 changes: 84 additions & 11 deletions tools/gen_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,41 @@
"CTRL_ATTR_MCAST_GROUPS",
]

tun_ioctls = [
"TUNSETNOCSUM",
"TUNSETDEBUG",
"TUNSETIFF",
"TUNSETPERSIST",
"TUNSETOWNER",
"TUNSETLINK",
"TUNSETGROUP",
"TUNGETFEATURES",
"TUNSETOFFLOAD",
"TUNSETTXFILTER",
"TUNGETIFF",
"TUNGETSNDBUF",
"TUNSETSNDBUF",
"TUNATTACHFILTER",
"TUNDETACHFILTER",
"TUNGETVNETHDRSZ",
"TUNSETVNETHDRSZ",
"TUNSETVNETBE",
"TUNGETVNETBE",
"TUNSETSTEERINGEBPF",
"TUNSETFILTEREBPF",
"TUNSETCARRIER",
"TUNGETDEVNETNS",
]

tun_iff_flags = [
"IFF_TUN",
"IFF_TAP",
"IFF_NO_PI",
"IFF_ONE_QUEUE",
"IFF_VNET_HDR",
"IFF_TUN_EXCL",
]


@dataclass
class TypeSpec:
Expand All @@ -219,13 +254,34 @@ class TypeSpec:
constants: list[str]
is_macro: bool = False
flag: bool = False
hex: bool = False
includes: list[str] = field(default_factory=list)
printf_specifier: typing.Literal["%d", "%ld"] = "%d"


constants = [
TypeSpec("NLFamily", "NETLINK_", netlink_families, is_macro=True, includes=["<linux/netlink.h>"]),
TypeSpec("NLMsgType", "NLMSG_", netlink_msg_types, is_macro=True, includes=["<linux/netlink.h>"]),
TypeSpec("NLFlag", "NLM_F_", netlink_flags, is_macro=True, flag=True, includes=["<linux/netlink.h>"]),
TypeSpec(
"NLFamily",
"NETLINK_",
netlink_families,
is_macro=True,
includes=["<linux/netlink.h>"],
),
TypeSpec(
"NLMsgType",
"NLMSG_",
netlink_msg_types,
is_macro=True,
includes=["<linux/netlink.h>"],
),
TypeSpec(
"NLFlag",
"NLM_F_",
netlink_flags,
is_macro=True,
flag=True,
includes=["<linux/netlink.h>"],
),
TypeSpec("RTNType", "RTN_", route_types, includes=["<linux/rtnetlink.h>"]),
TypeSpec("ARPHRDType", "ARPHRD_", arphrd_types, includes=["<linux/if_arp.h>"]),
TypeSpec("IFLAType", "IFLA_", ifla_types, includes=["<linux/if.h>"]),
Expand All @@ -241,6 +297,22 @@ class TypeSpec:
),
TypeSpec("CtrlCmd", "CTRL_CMD_", ctrl_cmds, includes=["<linux/genetlink.h>"]),
TypeSpec("CtrlAttr", "CTRL_ATTR_", ctrl_attrs, includes=["<linux/genetlink.h>"]),
TypeSpec(
"TunIoctl",
"TUN",
tun_ioctls,
hex=True,
printf_specifier="%d",
includes=["<sys/ioctl.h>", "<linux/if_tun.h>"],
),
TypeSpec(
"TunIffFlag",
"IFF_",
tun_iff_flags,
flag=True,
printf_specifier="%d",
includes=["<linux/if_tun.h>"],
),
]


Expand All @@ -258,11 +330,7 @@ def generate_program(name: str = "gen_constants") -> Path:
includes = {
"<stdio.h>",
}
includes |= {
include
for ts in constants
for include in ts.includes
}
includes |= {include for ts in constants for include in ts.includes}
for include in sorted(includes):
f.write(f"#include {include}\n")
# TODO: Should each typespec define it's includes?
Expand All @@ -276,7 +344,7 @@ def generate_program(name: str = "gen_constants") -> Path:
if type_spec.is_macro:
f.write(f"#ifdef {constant}\n")
f.write(
f' printf("{type_spec.name} {constant} %d\\n", {constant});\n'
f' printf("{type_spec.name} {constant} {type_spec.printf_specifier}\\n", {constant});\n'
)
if type_spec.is_macro:
f.write("#endif\n")
Expand Down Expand Up @@ -342,20 +410,25 @@ def print_result(
else:
# Not a bit shift, could be a combination of other flags.
value_str = hex(constant_value)
elif type_spec.hex:
value_str = hex(constant_value)
else:
value_str = str(constant_value)
print(
f" {constant_name.removeprefix(type_spec.prefix)}: Final = {value_str}",
file=f,
)
print(
textwrap.dedent(
f"""\
textwrap.indent(
textwrap.dedent(
f"""\
@property
def constant_name(self) -> str:
return f"{type_spec.prefix}{{self.name}}"
"""
),
prefix=" " * 4,
),
file=f,
)
Expand Down

0 comments on commit 4783a85

Please sign in to comment.