Agora  1.2.0
Agora project
eth_common.h
Go to the documentation of this file.
1 // Copyright 2018, Carnegie Mellon University
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
20 #ifndef ETH_COMMON_H_
21 #define ETH_COMMON_H_
22 
23 #include <arpa/inet.h>
24 #include <ifaddrs.h>
25 #include <linux/if_packet.h>
26 #include <net/if.h>
27 #include <sys/ioctl.h>
28 #include <sys/socket.h>
29 #include <sys/types.h>
30 #include <unistd.h>
31 
32 #include <cassert>
33 #include <sstream>
34 #include <string>
35 
36 #include "utils.h"
37 
38 static constexpr uint16_t kIPEtherType = 0x800;
39 static constexpr uint16_t kIPHdrProtocol = 0x11;
40 
41 static inline std::string mac_to_string(const uint8_t* mac) {
42  std::ostringstream ret;
43  for (size_t i = 0; i < 6; i++) {
44  ret << std::hex << static_cast<uint32_t>(mac[i]);
45  if (i != 5) ret << ":";
46  }
47  return ret.str();
48 }
49 
51 static inline uint32_t ipv4_from_str(const char* ip) {
52  uint32_t addr;
53  int ret = inet_pton(AF_INET, ip, &addr);
54  RtAssert(ret == 1, "inet_pton() failed for " + std::string(ip));
55  return addr;
56 }
57 
59 static inline std::string ipv4_to_string(uint32_t ipv4_addr) {
60  char str[INET_ADDRSTRLEN];
61  const char* ret = inet_ntop(AF_INET, &ipv4_addr, str, sizeof(str));
62  RtAssert(ret == str, "inet_ntop failed");
63  str[INET_ADDRSTRLEN - 1] = 0; // Null-terminate
64  return str;
65 }
66 
71  uint8_t mac[6];
72  uint32_t ipv4_addr;
73  uint16_t udp_port;
74 
75  std::string to_string() {
76  std::ostringstream ret;
77  ret << "[MAC " << mac_to_string(mac) << ", IP " << ipv4_to_string(ipv4_addr)
78  << ", UDP port " << std::to_string(udp_port) << "]";
79 
80  return std::string(ret.str());
81  }
82  // This must be smaller than Transport::kMaxRoutingInfoSize, but a static
83  // assert here causes a circular dependency.
84 };
85 
86 struct eth_hdr_t {
87  uint8_t dst_mac[6];
88  uint8_t src_mac[6];
89  uint16_t eth_type;
90 
91  std::string to_string() const {
92  std::ostringstream ret;
93  ret << "[ETH: dst " << mac_to_string(dst_mac) << ", src "
94  << mac_to_string(src_mac) << ", eth_type "
95  << std::to_string(ntohs(eth_type)) << "]";
96  return ret.str();
97  }
98 } __attribute__((packed));
99 
100 struct ipv4_hdr_t {
101  uint8_t ihl : 4;
102  uint8_t version : 4;
103  uint8_t ecn : 2;
104  uint8_t dscp : 6;
105  uint16_t tot_len;
106  uint16_t id;
107  uint16_t frag_off;
108  uint8_t ttl;
109  uint8_t protocol;
110  uint16_t check;
111  uint32_t src_ip;
112  uint32_t dst_ip;
113 
114  std::string to_string() const {
115  std::ostringstream ret;
116  ret << "[IPv4: ihl " << std::to_string(ihl) << ", version "
117  << std::to_string(version) << ", ecn " << std::to_string(ecn)
118  << ", tot_len " << std::to_string(ntohs(tot_len)) << ", id "
119  << std::to_string(ntohs(id)) << ", frag_off "
120  << std::to_string(ntohs(frag_off)) << ", ttl " << std::to_string(ttl)
121  << ", protocol " << std::to_string(protocol) << ", check "
122  << std::to_string(check) << ", src IP " << ipv4_to_string(src_ip)
123  << ", dst IP " << ipv4_to_string(dst_ip) << "]";
124  return ret.str();
125  }
126 } __attribute__((packed));
127 
128 struct udp_hdr_t {
129  uint16_t src_port;
130  uint16_t dst_port;
131  uint16_t len;
132  uint16_t check;
133 
134  std::string to_string() const {
135  std::ostringstream ret;
136  ret << "[UDP: src_port " << std::to_string(ntohs(src_port)) << ", dst_port "
137  << std::to_string(ntohs(dst_port)) << ", len "
138  << std::to_string(ntohs(len)) << ", check " << std::to_string(check)
139  << "]";
140  return ret.str();
141  }
142 } __attribute__((packed));
143 
144 static constexpr size_t kInetHdrsTotSize =
145  sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t) + sizeof(udp_hdr_t);
146 static_assert(kInetHdrsTotSize == 42);
147 
150 static inline std::string frame_header_to_string(const uint8_t* buf) {
151  auto* eth_hdr = reinterpret_cast<const eth_hdr_t*>(buf);
152  auto* ipv4_hdr = reinterpret_cast<const ipv4_hdr_t*>(&eth_hdr[1]);
153  auto* udp_hdr = reinterpret_cast<const udp_hdr_t*>(&ipv4_hdr[1]);
154 
155  return eth_hdr->to_string() + ", " + ipv4_hdr->to_string() + ", " +
156  udp_hdr->to_string();
157 }
158 
160 static void inline gen_eth_header(eth_hdr_t* eth_header, const uint8_t* src_mac,
161  const uint8_t* dst_mac) {
162  std::memcpy(eth_header->src_mac, src_mac, 6);
163  std::memcpy(eth_header->dst_mac, dst_mac, 6);
164  eth_header->eth_type = htons(kIPEtherType);
165 }
166 
169 static inline void gen_ipv4_header(ipv4_hdr_t* ipv4_hdr, uint32_t src_ip,
170  uint32_t dst_ip, uint16_t data_size) {
171  ipv4_hdr->version = 4;
172  ipv4_hdr->ihl = 5;
173  ipv4_hdr->ecn = 1; // ECT => ECN-capable transport
174  ipv4_hdr->dscp = 0;
175  ipv4_hdr->tot_len = htons(sizeof(ipv4_hdr_t) + sizeof(udp_hdr_t) + data_size);
176  ipv4_hdr->id = htons(0);
177  ipv4_hdr->frag_off = htons(0);
178  ipv4_hdr->ttl = 128;
179  ipv4_hdr->protocol = kIPHdrProtocol;
180  ipv4_hdr->src_ip = htonl(src_ip);
181  ipv4_hdr->dst_ip = htonl(dst_ip);
182  ipv4_hdr->check = 0;
183 }
184 
187 static inline void gen_udp_header(udp_hdr_t* udp_hdr, uint16_t src_port,
188  uint16_t dst_port, uint16_t data_size) {
189  udp_hdr->src_port = htons(src_port);
190  udp_hdr->dst_port = htons(dst_port);
191  udp_hdr->len = htons(sizeof(udp_hdr_t) + data_size);
192  udp_hdr->check = 0;
193 }
194 
196 static inline uint32_t get_interface_ipv4_addr(const std::string& interface) {
197  struct ifaddrs *ifaddr, *ifa;
198  RtAssert(getifaddrs(&ifaddr) == 0);
199  uint32_t ipv4_addr = 0;
200 
201  for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
202  if (strcmp(ifa->ifa_name, interface.c_str()) != 0) continue;
203 
204  // We might get the same interface multiple times with different sa_family
205  if (ifa->ifa_addr == nullptr || ifa->ifa_addr->sa_family != AF_INET) {
206  continue;
207  }
208 
209  auto sin_addr = reinterpret_cast<sockaddr_in*>(ifa->ifa_addr);
210  ipv4_addr = ntohl(*reinterpret_cast<uint32_t*>(&sin_addr->sin_addr));
211  }
212 
213  RtAssert(ipv4_addr != 0,
214  std::string("Failed to find interface ") + interface);
215 
216  freeifaddrs(ifaddr);
217  return ipv4_addr;
218 }
219 
221 static inline void fill_interface_mac(const std::string& interface,
222  uint8_t* mac) {
223  struct ifreq ifr;
224  ifr.ifr_addr.sa_family = AF_INET;
225  strncpy(ifr.ifr_name, interface.c_str(), IFNAMSIZ - 1);
226 
227  int fd = socket(AF_INET, SOCK_DGRAM, 0);
228  assert(fd >= 0);
229 
230  int ret = ioctl(fd, SIOCGIFHWADDR, &ifr);
231  RtAssert(ret == 0, "MAC address IOCTL failed");
232  close(fd);
233 
234  for (size_t i = 0; i < 6; i++) {
235  mac[i] = static_cast<uint8_t>(ifr.ifr_hwaddr.sa_data[i]);
236  }
237 }
238 
239 #endif // ETH_COMMON_H_
eth_routing_info_t::to_string
std::string to_string()
Definition: eth_common.h:75
ipv4_hdr_t::version
uint8_t version
Definition: eth_common.h:102
eth_hdr_t::eth_type
uint16_t eth_type
Definition: eth_common.h:89
ipv4_hdr_t::protocol
uint8_t protocol
Definition: eth_common.h:109
eth_routing_info_t::ipv4_addr
uint32_t ipv4_addr
Definition: eth_common.h:72
ipv4_hdr_t::dscp
uint8_t dscp
Definition: eth_common.h:104
ipv4_to_string
static std::string ipv4_to_string(uint32_t ipv4_addr)
Convert a network-byte-order IPv4 address to a human-readable IP string.
Definition: eth_common.h:59
src_mac
uint8_t src_mac[6]
Definition: eth_common.h:61
kIPHdrProtocol
static constexpr uint16_t kIPHdrProtocol
Definition: eth_common.h:39
src_port
uint16_t src_port
Definition: eth_common.h:60
ipv4_hdr_t::tot_len
uint16_t tot_len
Definition: eth_common.h:105
udp_hdr_t::len
uint16_t len
Definition: eth_common.h:131
eth_routing_info_t::udp_port
uint16_t udp_port
Definition: eth_common.h:73
eth_hdr_t
Definition: eth_common.h:86
src_ip
uint32_t src_ip
Definition: eth_common.h:70
dst_port
uint16_t dst_port
Definition: eth_common.h:61
eth_routing_info_t::mac
uint8_t mac[6]
Definition: eth_common.h:71
gen_ipv4_header
static void gen_ipv4_header(ipv4_hdr_t *ipv4_hdr, uint32_t src_ip, uint32_t dst_ip, uint16_t data_size)
Definition: eth_common.h:169
ipv4_hdr_t::to_string
std::string to_string() const
Definition: eth_common.h:114
ipv4_from_str
static uint32_t ipv4_from_str(const char *ip)
Get the network-byte-order IPv4 address from a human-readable IP string.
Definition: eth_common.h:51
frame_header_to_string
static std::string frame_header_to_string(const uint8_t *buf)
Definition: eth_common.h:150
matplotlibcpp::close
void close()
Definition: matplotlibcpp.h:2567
ipv4_hdr_t::ttl
uint8_t ttl
Definition: eth_common.h:108
ipv4_hdr_t::dst_ip
uint32_t dst_ip
Definition: eth_common.h:112
i
for i
Definition: generate_data.m:107
ipv4_hdr_t::id
uint16_t id
Definition: eth_common.h:106
dst_mac
uint8_t dst_mac[6]
Definition: eth_common.h:60
udp_hdr_t::to_string
std::string to_string() const
Definition: eth_common.h:134
eth_hdr_t::src_mac
uint8_t src_mac[6]
Definition: eth_common.h:88
__attribute__
struct eth_hdr_t __attribute__((packed))
ipv4_hdr_t::frag_off
uint16_t frag_off
Definition: eth_common.h:107
udp_hdr_t::check
uint16_t check
Definition: eth_common.h:132
ipv4_hdr_t::ecn
uint8_t ecn
Definition: eth_common.h:103
udp_hdr_t
Definition: eth_common.h:128
kInetHdrsTotSize
static constexpr size_t kInetHdrsTotSize
Definition: eth_common.h:144
fill_interface_mac
static void fill_interface_mac(const std::string &interface, uint8_t *mac)
Fill the MAC address of kernel-visible interface.
Definition: eth_common.h:221
eth_hdr_t::to_string
std::string to_string() const
Definition: eth_common.h:91
data_size
data_size
Definition: inspect_agora_results.m:16
ipv4_hdr_t::check
uint16_t check
Definition: eth_common.h:110
ipv4_hdr_t::ihl
uint8_t ihl
Definition: eth_common.h:101
udp_hdr_t::src_port
uint16_t src_port
Definition: eth_common.h:129
RtAssert
static void RtAssert(bool condition, const char *throw_str)
Definition: utils.h:104
get_interface_ipv4_addr
static uint32_t get_interface_ipv4_addr(const std::string &interface)
Return the IPv4 address of a kernel-visible interface in host-byte order.
Definition: eth_common.h:196
to_string
std::string to_string() const
Definition: eth_common.h:64
ipv4_hdr_t::src_ip
uint32_t src_ip
Definition: eth_common.h:111
kIPEtherType
static constexpr uint16_t kIPEtherType
Definition: eth_common.h:38
utils.h
Utility functions for file and text processing.
udp_hdr_t::dst_port
uint16_t dst_port
Definition: eth_common.h:130
gen_eth_header
static void gen_eth_header(eth_hdr_t *eth_header, const uint8_t *src_mac, const uint8_t *dst_mac)
Fill in Ethernet header eth_header using the source and destination MAC.
Definition: eth_common.h:160
ipv4_hdr_t
Definition: eth_common.h:100
dst_ip
uint32_t dst_ip
Definition: eth_common.h:71
gen_udp_header
static void gen_udp_header(udp_hdr_t *udp_hdr, uint16_t src_port, uint16_t dst_port, uint16_t data_size)
Definition: eth_common.h:187
eth_routing_info_t
Definition: eth_common.h:70
mac_to_string
static std::string mac_to_string(const uint8_t *mac)
Definition: eth_common.h:41
eth_hdr_t::dst_mac
uint8_t dst_mac[6]
Definition: eth_common.h:87