MMapSocketProtocol.cc
Go to the documentation of this file.
1 //
2 // Copyright (c) 2020 Fraunhofer Institute for Applied Information Technology (FIT)
3 // Network Research Group (NET)
4 // Schloss Birlinghoven, 53754 Sankt Augustin, GERMANY
5 // Contact: support@wiback.org
6 //
7 // This file is part of the SENF code tree.
8 // It is licensed under the 3-clause BSD License (aka New BSD License).
9 // See LICENSE.txt in the top level directory for details or visit
10 // https://opensource.org/licenses/BSD-3-Clause
11 //
12 
13 
17 #include "MMapSocketProtocol.hh"
18 //#include "MMapSocketProtocol.ih"
19 
20 // Custom includes
21 #include <linux/if_packet.h>
22 #include <linux/net_tstamp.h>
23 #include <sys/mman.h>
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 
27 //#include "MMapSocketProtocol.mpp"
28 #define prefix_
29 //-/////////////////////////////////////////////////////////////////////////////////////////////////
30 
31 #ifndef PACKET_TX_HAS_OFF
32 #define PACKET_TX_HAS_OFF 19
33 #endif
34 #ifndef PACKET_QDISC_BYPASS
35 #define PACKET_QDISC_BYPASS 20
36 #endif
37 
39 {
40  close_mmap();
42 }
43 
45  const
46 {
49 }
50 
51 prefix_ void senf::MMapSocketProtocol::init_mmap(unsigned frameSize, unsigned rxqlen,
52  unsigned txqlen, unsigned reserve, bool qDiscBypass)
53  const
54 {
55  ::memset(&qi_, 0, sizeof(qi_));
56  qi_.frameSize = frameSize;
57 
58  int v = TPACKET_V2;
59  ::socklen_t l = sizeof(int);
60  if (getsockopt(fd(), SOL_PACKET, PACKET_HDRLEN, (char *)&v, &l) != 0)
61  SENF_THROW_SYSTEM_EXCEPTION("::getsockopt(SOL_PACKET, PACKET_HDRLEN)");
62  qi_.hdrlen = TPACKET_ALIGN(v);
63 
64  v = TPACKET_V2;
65  if (setsockopt(fd(), SOL_PACKET, PACKET_VERSION, (char *)&v, sizeof(v)) != 0 )
66  SENF_THROW_SYSTEM_EXCEPTION("::setsockopt(SOL_PACKET, PACKET_VERSION)");
67 
68  unsigned size (0);
69 
70  struct ::tpacket_req req;
71  ::memset(&req, 0, sizeof(req));
72 
73  if (txqlen > 0) {
74  v = 1;
75  if (setsockopt(fd(), SOL_PACKET, PACKET_LOSS, (char *)&v, sizeof(v)) != 0)
76  SENF_THROW_SYSTEM_EXCEPTION("::setsockopt(SOL_PACKET, PACKET_LOSS");
77  }
78 
79  if (rxqlen > 0) {
80  qi_.reserveSize = 0;
81  if (reserve > 0
82  && setsockopt(fd(), SOL_PACKET, PACKET_RESERVE, (char *)&reserve, sizeof(reserve)) == 0)
83  qi_.reserveSize = reserve;
84  req.tp_frame_nr = rxqlen;
85  req.tp_frame_size = frameSize;
86  req.tp_block_size = req.tp_frame_nr * req.tp_frame_size;
87  req.tp_block_nr = 1;
88  if (setsockopt(fd(), SOL_PACKET, PACKET_RX_RING,
89  reinterpret_cast<char *>(&req), sizeof(req)) != 0 )
90  SENF_THROW_SYSTEM_EXCEPTION("::setsockopt(SOL_PACKET, PACKET_RX_RING");
91  size += req.tp_block_size;
92  }
93 
94  if (txqlen > 0) {
95  req.tp_frame_nr = txqlen;
96  req.tp_frame_size = frameSize;
97  req.tp_block_size = req.tp_frame_nr * req.tp_frame_size;
98  req.tp_block_nr = 1;
99  if (setsockopt(fd(), SOL_PACKET, PACKET_TX_RING,
100  reinterpret_cast<char *>(&req), sizeof(req)) != 0 )
101  SENF_THROW_SYSTEM_EXCEPTION("::setsockopt(SOL_PACKET, PACKET_TX_RING");
102 #ifdef SENF_ENABLE_TPACKET_OFFSET
103  v = 1;
104  if (setsockopt(fd(), SOL_PACKET, PACKET_TX_HAS_OFF, (char *)&v, sizeof(v)) != 0)
105  SENF_THROW_SYSTEM_EXCEPTION("::setsockopt(SOL_PACKET, PACKET_TX_HAS_OFF");
106 #endif
107  size += req.tp_block_size;
108  }
109 
110  unsigned char * map (static_cast<unsigned char *>(
111  ::mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd(), 0)));
112  if (map == MAP_FAILED)
113  SENF_THROW_SYSTEM_EXCEPTION("::mmap()");
114 
115  qi_.map = map;
116  qi_.init(rxqlen, txqlen);
117 
118  // supposedly this should speed up TX. And it does (<5% increase), when our non-blocking patch is applied.
119  // Otherwise it seems to rather costs us 10%
120  if (qDiscBypass) {
121  v = 1;
122  setsockopt(fd(), SOL_PACKET, PACKET_QDISC_BYPASS, (char*)&v, sizeof(v));
123  }
124 
126 }
127 
129  const
130 {
131  if (! qi_.map)
132  return;
133  if (::munmap(qi_.map, (qi_.rx.end - qi_.rx.begin) + (qi_.tx.end - qi_.tx.begin)) < 0)
134  SENF_THROW_SYSTEM_EXCEPTION("::munmap");
135  ::memset(&qi_, 0, sizeof(qi_));
136 }
137 
139  const
140 {
141  if (! qi_.map)
142  return;
143  ::munmap(qi_.map, (qi_.rx.end - qi_.rx.begin) + (qi_.tx.end - qi_.tx.begin));
144  ::memset(&qi_, 0, sizeof(qi_));
145 }
146 
147 prefix_ senf::detail::QueueInfo::TxStats senf::MMapSocketProtocol::txStats()
148  const
149 {
150  detail::QueueInfo::TxStats txStats (qi_.txStats);
151  ::memset(&qi_.txStats, 0, sizeof(qi_.txStats));
152  return txStats;
153 }
154 
155 prefix_ senf::detail::QueueInfo::RxStats senf::MMapSocketProtocol::rxStats()
156  const
157 {
158  detail::QueueInfo::RxStats rxStats (qi_.rxStats);
159  ::memset(&qi_.rxStats, 0, sizeof(qi_.rxStats));
160  return rxStats;
161 }
162 
164  const
165 {
166  // Since dequeue() will skip outgoing packets it's impossible to return a correct
167  // value here without race conditions. Thus we always return the frame size
168  return static_cast<detail::QueueInfo *>(senf::FileHandleAccess::extraPtr(fh()))->frameSize;
169 }
170 
172  const
173 {
174  bool rtn (qi_.interfaceDead());
175  ::memset(&qi_.txStats, 0, sizeof(qi_.txStats));
176  ::memset(&qi_.rxStats, 0, sizeof(qi_.rxStats));
177  return rtn;
178 }
179 
181 {
182  if (setsockopt(fd(), SOL_PACKET, PACKET_TIMESTAMP, (char*)&sofFlags, sizeof(sofFlags)) != 0)
183  SENF_THROW_SYSTEM_EXCEPTION("::setsockopt(SOL_PACKET, PACKET_TIMESTAMP");
184 }
185 
186 
187 //-/////////////////////////////////////////////////////////////////////////////////////////////////
188 #undef prefix_
189 //#include "MMapSocketProtocol.mpp"
190 
191 
192 // Local Variables:
193 // mode: c++
194 // fill-column: 100
195 // comment-column: 40
196 // c-file-style: "senf"
197 // indent-tabs-mode: nil
198 // ispell-local-dictionary: "american"
199 // compile-command: "scons -u test"
200 // End:
#define SENF_THROW_SYSTEM_EXCEPTION(desc)
#define PACKET_TX_HAS_OFF
detail::QueueInfo::TxStats txStats() const
int fd() const
Get file descriptor.
#define PACKET_QDISC_BYPASS
void close()
Close socket.
void timestamping(int sofFlags)
FileHandle fh() const
Get a FileHandle for this instance.
void terminate() const
Forcibly close socket.
MMapSocketProtocol public header.
#define prefix_
virtual void close()
Close socket.
unsigned available() const
Return (maximum) number of bytes available for reading without < blocking.
void init_mmap(unsigned frameSize, unsigned rxqlen, unsigned txqlen, unsigned reserve=0, bool qDiscBypass=false) const
virtual void terminate() const
Forcibly close socket.
static void * extraPtr(FileHandle const &fh)
detail::QueueInfo::RxStats rxStats() const