master
hxx 156 lines 4.1 KB
Raw
1 // Copyright (C) Microsoft Corporation. All rights reserved.
2 #pragma once
3 #include <sys/ioctl.h>
4 #include <arpa/inet.h>
5 #include <net/if.h>
6 #include <linux/netlink.h>
7 #include <linux/rtnetlink.h>
8 #include <unistd.h>
9 #include <string.h>
10 #include <atomic>
11
12 #include "NetlinkChannel.h"
13 #include "Syscall.h"
14
15 inline NetlinkChannel::NetlinkChannel(int socketType, int netlinkFamily, int groups)
16 {
17 m_socket.reset(Syscall(::socket, AF_NETLINK, socketType, netlinkFamily));
18
19 sockaddr_nl address = {};
20 address.nl_family = AF_NETLINK;
21 address.nl_groups = groups;
22
23 Syscall(bind, m_socket.get(), reinterpret_cast<sockaddr*>(&address), sizeof(address));
24 }
25
26 inline NetlinkChannel::NetlinkChannel(NetlinkChannel&& other)
27 {
28 *this = std::move(other);
29 }
30
31 inline const NetlinkChannel& NetlinkChannel::operator=(NetlinkChannel&& other)
32 {
33 m_socket = std::move(other.m_socket);
34
35 return *this;
36 }
37
38 inline NetlinkChannel::NetlinkChannel(Tag)
39 {
40 }
41
42 inline NetlinkChannel::~NetlinkChannel()
43 {
44 }
45
46 inline NetlinkChannel NetlinkChannel::FromFd(int fd)
47 {
48 assert(fd != -1);
49
50 NetlinkChannel channel(Tag{});
51 channel.m_socket.reset(fd);
52
53 return channel;
54 }
55
56 inline NetlinkTransaction NetlinkChannel::CreateTransactionImpl(std::vector<char>&& message, int type, int flags)
57 {
58 auto header = reinterpret_cast<nlmsghdr*>(message.data());
59 header->nlmsg_len = message.size();
60 header->nlmsg_type = type;
61 header->nlmsg_seq = ++seqNumber;
62 header->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
63
64 return {*this, std::move(message), header->nlmsg_seq};
65 }
66
67 inline void NetlinkChannel::SendMessage(const std::vector<char>& message)
68 {
69 Syscall(sendto, m_socket.get(), message.data(), message.size(), 0, nullptr, 0);
70 }
71
72 inline NetlinkTransaction NetlinkChannel::CreateTransaction(int type, int flags)
73 {
74 auto header = std::vector<char>(sizeof(nlmsghdr));
75 return CreateTransactionImpl(std::move(header), type, flags);
76 }
77
78 template <typename T>
79 NetlinkTransaction NetlinkChannel::CreateTransaction(const T& message, int type, int flags)
80 {
81 return CreateTransaction(&message, sizeof(T), type, flags);
82 }
83
84 inline NetlinkTransaction NetlinkChannel::CreateTransaction(const void* message, size_t messageSize, int type, int flags)
85 {
86 struct Request
87 {
88 nlmsghdr header;
89 char message;
90 } __attribute__((packed));
91
92 if (messageSize == 0)
93 {
94 return CreateTransaction(type, flags);
95 }
96
97 std::vector<char> buffer(offsetof(Request, message) + messageSize);
98 const auto request = reinterpret_cast<Request*>(buffer.data());
99 memcpy(&request->message, message, messageSize);
100 return CreateTransactionImpl(std::move(buffer), type, flags);
101 }
102
103 inline NetlinkResponse NetlinkChannel::ReceiveNetlinkResponse()
104 {
105 std::vector<char> buffer;
106
107 sockaddr_storage src = {};
108 iovec iov = {};
109
110 msghdr message = {};
111 message.msg_name = &src;
112 message.msg_namelen = sizeof(src);
113 message.msg_iov = &iov;
114 message.msg_iovlen = 1;
115
116 int size = Syscall(recvmsg, m_socket.get(), &message, MSG_PEEK | MSG_TRUNC);
117 buffer.resize(size);
118
119 size = Syscall(recvfrom, m_socket.get(), buffer.data(), buffer.size(), 0, nullptr, nullptr);
120 if (size != static_cast<int>(buffer.size()))
121 {
122 throw RuntimeErrorWithSourceLocation(std::format("Unexpected response size: {} != {}", size, buffer.size()));
123 }
124
125 return {std::move(buffer)};
126 }
127
128 inline int NetlinkChannel::GetInterfaceIndex(const std::string& name)
129 {
130 ifreq ifr = {};
131 strncpy(ifr.ifr_name, name.c_str(), sizeof(ifr.ifr_name) - 1);
132 Syscall(ioctl, m_socket.get(), SIOCGIFINDEX, &ifr);
133
134 return ifr.ifr_ifindex;
135 }
136
137 inline int NetlinkChannel::SetInterfaceFlags(const std::string& name, int flags)
138 {
139 ifreq ifr = {};
140 strncpy(ifr.ifr_name, name.c_str(), sizeof(ifr.ifr_name) - 1);
141 ifr.ifr_flags = flags;
142
143 Syscall(ioctl, m_socket.get(), SIOCSIFFLAGS, &ifr);
144
145 return ifr.ifr_flags;
146 }
147
148 inline int NetlinkChannel::GetInterfaceFlags(const std::string& name)
149 {
150 ifreq ifr = {};
151 strncpy(ifr.ifr_name, name.c_str(), sizeof(ifr.ifr_name) - 1);
152
153 Syscall(ioctl, m_socket.get(), SIOCGIFFLAGS, &ifr);
154
155 return ifr.ifr_flags;
156 }