Closed CMCDragonkai closed 4 years ago
I'm coming up to this:
derivingEnum :: String -> Map String Integer -> String
derivingEnum name vals =
"instance Enum " ++ name ++ " where\n" ++ toEnums ++ fromEnums
where
values = sortBy (compare `on` snd) $ toList vals
toEnums = concatMap
(\(k, v) -> " toEnum " ++ show v ++ " = " ++ k ++ "\n") $
nubBy ((==) `on` snd) values
fromEnums = concatMap
(\(k, v) -> " fromEnum " ++ k ++ " = " ++ show v ++ "\n") $
values
Need to plug it into the mkEnums
, so we get proper enum derivation as well.
It works:
data AddressFamily = AF_UNSPEC
| AF_FILE
| AF_LOCAL
| AF_UNIX
| AF_INET
| AF_AX25
| AF_IPX
| AF_APPLETALK
| AF_NETROM
| AF_BRIDGE
| AF_ATMPVC
| AF_X25
| AF_INET6
| AF_ROSE
| AF_DECnet
| AF_NETBEUI
| AF_SECURITY
| AF_KEY
| AF_NETLINK
| AF_ROUTE
| AF_PACKET
| AF_ASH
| AF_ECONET
| AF_ATMSVC
| AF_RDS
| AF_SNA
| AF_IRDA
| AF_PPPOX
| AF_WANPIPE
| AF_LLC
| AF_IB
| AF_MPLS
| AF_CAN
| AF_TIPC
| AF_BLUETOOTH
| AF_IUCV
| AF_RXRPC
| AF_ISDN
| AF_PHONET
| AF_IEEE802154
| AF_CAIF
| AF_ALG
| AF_NFC
| AF_VSOCK
| AF_KCM
| AF_QIPCRTR
| AF_SMC
| AF_MAX
deriving (Eq, Show)
instance Enum AddressFamily where
toEnum 0 = AF_UNSPEC
toEnum 1 = AF_FILE
toEnum 2 = AF_INET
toEnum 3 = AF_AX25
toEnum 4 = AF_IPX
toEnum 5 = AF_APPLETALK
toEnum 6 = AF_NETROM
toEnum 7 = AF_BRIDGE
toEnum 8 = AF_ATMPVC
toEnum 9 = AF_X25
toEnum 10 = AF_INET6
toEnum 11 = AF_ROSE
toEnum 12 = AF_DECnet
toEnum 13 = AF_NETBEUI
toEnum 14 = AF_SECURITY
toEnum 15 = AF_KEY
toEnum 16 = AF_NETLINK
toEnum 17 = AF_PACKET
toEnum 18 = AF_ASH
toEnum 19 = AF_ECONET
toEnum 20 = AF_ATMSVC
toEnum 21 = AF_RDS
toEnum 22 = AF_SNA
toEnum 23 = AF_IRDA
toEnum 24 = AF_PPPOX
toEnum 25 = AF_WANPIPE
toEnum 26 = AF_LLC
toEnum 27 = AF_IB
toEnum 28 = AF_MPLS
toEnum 29 = AF_CAN
toEnum 30 = AF_TIPC
toEnum 31 = AF_BLUETOOTH
toEnum 32 = AF_IUCV
toEnum 33 = AF_RXRPC
toEnum 34 = AF_ISDN
toEnum 35 = AF_PHONET
toEnum 36 = AF_IEEE802154
toEnum 37 = AF_CAIF
toEnum 38 = AF_ALG
toEnum 39 = AF_NFC
toEnum 40 = AF_VSOCK
toEnum 41 = AF_KCM
toEnum 42 = AF_QIPCRTR
toEnum 43 = AF_SMC
toEnum 44 = AF_MAX
fromEnum AF_UNSPEC = 0
fromEnum AF_FILE = 1
fromEnum AF_LOCAL = 1
fromEnum AF_UNIX = 1
fromEnum AF_INET = 2
fromEnum AF_AX25 = 3
fromEnum AF_IPX = 4
fromEnum AF_APPLETALK = 5
fromEnum AF_NETROM = 6
fromEnum AF_BRIDGE = 7
fromEnum AF_ATMPVC = 8
fromEnum AF_X25 = 9
fromEnum AF_INET6 = 10
fromEnum AF_ROSE = 11
fromEnum AF_DECnet = 12
fromEnum AF_NETBEUI = 13
fromEnum AF_SECURITY = 14
fromEnum AF_KEY = 15
fromEnum AF_NETLINK = 16
fromEnum AF_ROUTE = 16
fromEnum AF_PACKET = 17
fromEnum AF_ASH = 18
fromEnum AF_ECONET = 19
fromEnum AF_ATMSVC = 20
fromEnum AF_RDS = 21
fromEnum AF_SNA = 22
fromEnum AF_IRDA = 23
fromEnum AF_PPPOX = 24
fromEnum AF_WANPIPE = 25
fromEnum AF_LLC = 26
fromEnum AF_IB = 27
fromEnum AF_MPLS = 28
fromEnum AF_CAN = 29
fromEnum AF_TIPC = 30
fromEnum AF_BLUETOOTH = 31
fromEnum AF_IUCV = 32
fromEnum AF_RXRPC = 33
fromEnum AF_ISDN = 34
fromEnum AF_PHONET = 35
fromEnum AF_IEEE802154 = 36
fromEnum AF_CAIF = 37
fromEnum AF_ALG = 38
fromEnum AF_NFC = 39
fromEnum AF_VSOCK = 40
fromEnum AF_KCM = 41
fromEnum AF_QIPCRTR = 42
fromEnum AF_SMC = 43
fromEnum AF_MAX = 44
Again we can see that we are defaulting to the first name appearing to be the "primary name". So that's AF_FILE
instead of what glibc says it is, which is AF_LOCAL
.
Both flags and enums are now standardised to ADTs with Enum typeclasses.
Figuring out the best names for the all the ADTs is still a bit of a challenge as the C names aren't really modularised.
One thing is that I've separated out the RTM_
from the NLMSG_
. This means the way in which the family types is worked out needs to be done differently.
@ramwan
The other thing is that there are currently 3 generation scripts:
Generate.hs
GenerateGenl.hs
- generates CTRL_CMD_...
and CTRL_
constantsggGenerateNL80211.hs
- generates NL80211...
constantsI'm not sure what to use those 2 other ones for. So for now I'm removing them. Unless you have something to add @ramwan?
So we will only have 1 constants file to deal with for now.
I'm not quite comfortable with how the toEnum
s only work on a single constructor from the AddressFamily type. Even though in your example AF_UNIX and AF_LOCAL have the same value, it may be confusing to future users who read documentation specifying AF_LOCAL and cannot find it in the constants list.
We will need to use generic netlink (the generategenl.hs?) for wireguard and maybe any other kernel modules we load in.
Rather than using toEnum
, we might have to use another function that pattern matches on the constructors. It'll be some real big functions.
This problem existed in the original netlink code. Its just fundamentally ambiguous.
On 10 May 2019 13:46:16 GMT+10:00, ramwan notifications@github.com wrote:
I'm not quite comfortable with how the
toEnum
s only work on a single constructor from the AddressFamily type. Even though in your example AF_UNIX and AF_LOCAL have the same value, it may be confusing to future users who read documentation specifying AF_LOCAL and cannot find it in the constants list.We will need to use generic netlink (the generategenl.hs?) for wireguard and maybe any other kernel modules we load in.-- You are receiving this because you authored the thread. Reply to this email directly or view it on GitHub: https://github.com/MatrixAI/netlink-hs/issues/1#issuecomment-491145304
-- Sent from my Android device with K-9 Mail. Please excuse my brevity.
are we able to restructure it and fix this issue or is that too much work
Well the problem is that conversion from number to "name" is fundamentally ambiguous so we have to choose one. So here we are just choosing the first one.
On 10 May 2019 16:38:09 GMT+10:00, ramwan notifications@github.com wrote:
are we able to restructure it and fix this issue or is that too much work
-- You are receiving this because you authored the thread. Reply to this email directly or view it on GitHub: https://github.com/MatrixAI/netlink-hs/issues/1#issuecomment-491174724
-- Sent from my Android device with K-9 Mail. Please excuse my brevity.
I counted that there are 21 official netlink families. And apparently a total limit of 32 families. So that's why everything else uses NETLINK_GENERIC
.
These are the families that may be relevant to us:
NETLINK_ROUTE
NETLINK_INET_DIAG
NETLINK_NFLOG
NETLINK_NETFILTER
NETLINK_GENERIC
- https://wiki.linuxfoundation.org/networking/generic_netlink_howtoWhat do you think @ramwan?
The gen netlink architecture is:
+---------------------+ +---------------------+
| (3) application "A" | | (3) application "B" |
+------+--------------+ +--------------+------+
| |
\ /
\ /
| |
+-------+--------------------------------+-------+
| : : | user-space
=====+ : (5) kernel socket API : +================
| : : | kernel-space
+--------+-------------------------------+-------+
| |
+-----+-------------------------------+----+
| (1) Netlink subsystem |
+---------------------+--------------------+
|
+---------------------+--------------------+
| (2) Generic Netlink bus |
+--+--------------------------+-------+----+
| | |
+-------+---------+ | |
| (4) controller | / \
+-----------------+ / \
| |
+------------------+--+ +--+------------------+
| (3) kernel user "X" | | (3) kernel user "Y" |
+---------------------+ +---------------------+
Generic Netlink communications are essentially a series of different communication channels which are multiplexed on a single Netlink family. Communication channels are uniquely identified by channel numbers which are dynamically allocated by the Generic Netlink controller. The controller is a special Generic Netlink user which listens on a fixed communication channel, number 0x10, which is always present. Kernel or userspace users which provide services over the Generic Netlink bus establish new communication channels by registering their services with the Generic Netlink controller. Users who want to use a service query the controller to see if the service exists and to determine the correct channel number.
The control constants are the main default constants for gen netlink. Then each service within gennetlink has their own set of constants. As we can see in the upstream repo, that's NL80211. But we're not really interested in those.
I've added genetlink.h
and added 4 extra constant ADTs for the genetlink control service.
Constants are now generated into ADTs. The only thing left is to add in all relevant family constants into the single generation script.
Currently netlink-hs generate constants as actual numbers. I want to change to using ADTs so I can pattern match on them.
However this means we need to derive the Enum typeclass for the ADTs. This would be simple except the numbers don't exactly match the constant names.
For example, these 3 have the same value:
And in fact,
AF_LOCAL
should be shown, as that's the primary name, and all the other names are synonyms forAF_LOCAL
.So ideally we would have:
But of course from the generation code, we don't know which one is meant to be the primary name. So we just have to take the first one as is.
This also is true for flags, which also can be defined out of order.
All of this can come from
#define
constants in C, or from actual enums.