cloudFPGA (cF) API  1.0
The documentation of the source code of cloudFPGA (cF)
SimUdpDatagram.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2016 -- 2021 IBM Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 
30 #ifndef _SIM_UDP_DATAGRAM_
31 #define _SIM_UDP_DATAGRAM_
32 
33 #include "nts_utils.hpp"
34 #include "SimNtsUtils.hpp"
35 #include "AxisUdp.hpp"
36 
37 
38 
48 
49  private:
50  int len; // In bytes
51  std::deque<AxisUdp> dgmQ; // A double-ended queue to store UDP chunks.
52  const char *myName;
53 
54  // Set the length of this UDP datagram (in bytes)
55  void setLen(int dgmLen) {
56  this->len = dgmLen;
57  }
58  // Get the length of this UDP datagram (in bytes)
59  int getLen() {
60  return this->len;
61  }
62  // Clear the content of the UDP datagram queue
63  void clear() {
64  this->dgmQ.clear();
65  this->len = 0;
66  }
67  // Return the front chunk element of the UDP datagram queue but do not remove it from the queue
68  AxisUdp front() {
69  return this->dgmQ.front();
70  }
71  // Remove the first chunk element of the UDP datagram queue
72  void pop_front() {
73  this->dgmQ.pop_front();
74  }
75  // Add an element at the end of the UDP datagram queue
76  void push_back(AxisUdp udpChunk) {
77  this->dgmQ.push_back(udpChunk);
78  }
79 
80  public:
81 
82  // Default Constructor: Constructs a datagram of 'dgmLen' bytes.
83  SimUdpDatagram(int dgmLen) {
84  this->myName = "SimUdpDatagram";
85  setLen(0);
86  if (dgmLen > 0 && dgmLen <= MTU) {
87  int noBytes = dgmLen;
88  while(noBytes > 8) {
89  pushChunk(AxisUdp(0x0000000000000000, 0xFF, 0));
90  noBytes -= 8;
91  }
92  pushChunk(AxisUdp(0x0000000000000000, lenToLE_tKeep(noBytes), TLAST));
93  }
94  }
96  this->myName = "SimUdpDatagram";
97  this->len = 0;
98  }
99 
100  // Add a chunk of bytes at the end of the double-ended queue
101  void pushChunk(AxisUdp udpChunk) {
102  if (this->size() > 0) {
103  // Always clear 'TLAST' bit of previous chunck
104  this->dgmQ[this->size()-1].setLE_TLast(0);
105  }
106  this->push_back(udpChunk);
107  this->setLen(this->getLen() + udpChunk.getLen());
108  }
109 
110  // Return the chunk at the front of the queue and remove that chunk from the queue
112  AxisUdp headingChunk = this->front();
113  this->pop_front();
114  setLen(getLen() - headingChunk.getLen());
115  return headingChunk;
116  }
117 
118  // Return the length of the UDP datagram (in bytes)
119  int length() {
120  return this->len;
121  }
122 
123  // Return the number of chunks in the UDP datagram
124  int size() {
125  return this->dgmQ.size();
126  }
127 
128 
132  void clone(SimUdpDatagram &udpDgm) {
133  AxisUdp newAxisUdp;
134  for (int i=0; i<udpDgm.dgmQ.size(); i++) {
135  newAxisUdp = udpDgm.dgmQ[i];
136  this->dgmQ.push_back(newAxisUdp);
137  }
138  this->setLen(udpDgm.getLen());
139  }
140 
141 
145  void cloneHeader(SimUdpDatagram &udpDgm) {
146  int cloneBytes = UDP_HEADER_LEN; // in bytes
147  int inpChunkCnt = 0;
148  while(cloneBytes > 0) {
149  if (cloneBytes > 8) {
150  this->pushChunk(udpDgm.dgmQ[inpChunkCnt]);
151  }
152  else {
153  AxisUdp lastHdrChunk(udpDgm.dgmQ[inpChunkCnt].getLE_TData(),
154  lenToLE_tKeep(cloneBytes), TLAST);
155  this->pushChunk(lastHdrChunk);
156  }
157  cloneBytes -= 8;
158  inpChunkCnt++;
159  }
160  }
161 
162 
167  SimUdpDatagram headerAsDatagram;
168  AxisUdp headerChunk = this->front();
169  this->pop_front();
170  setLen(getLen() - headerChunk.getLen());
171  headerAsDatagram.pushChunk(headerChunk);
172  return headerAsDatagram;
173  }
174 
175  // Set-Get the UDP Source Port field
176  void setUdpSourcePort(int port) { dgmQ[0].setUdpSrcPort(port); }
177  int getUdpSourcePort() { return dgmQ[0].getUdpSrcPort(); }
178  // Set-Get the UDP Destination Port field
179  void setUdpDestinationPort(int port) { dgmQ[0].setUdpDstPort(port); }
180  int getUdpDestinationPort() { return dgmQ[0].getUdpDstPort(); }
181  // Set-Get the UDP Length field
182  void setUdpLength(UdpLen len) { dgmQ[0].setUdpLen(len); }
183  UdpLen getUdpLength() { return dgmQ[0].getUdpLen(); }
184  // Set-Get the UDP Checksum field
185  void setUdpChecksum(UdpCsum csum) { dgmQ[0].setUdpCsum(csum); }
186  UdpCsum getUdpChecksum() { return dgmQ[0].getUdpCsum(); }
187 
188  // Append data payload to an UDP header
189  void addUdpPayload(string pldStr) {
190  if (this->getLen() != UDP_HEADER_LEN) {
191  printFatal(this->myName, "Empty datagram is expected to be of length %d bytes (was found to be %d bytes).\n",
192  UDP_HEADER_LEN, this->getLen());
193  }
194  int hdrLen = this->getLen(); // in bytes
195  int pldLen = pldStr.size();
196  int q = (hdrLen / 8);
197  int b = (hdrLen % 8);
198  int i = 0;
199  // At this point we are aligned on an 8-byte data chunk since all
200  // UDP packets have an 8-byte header.
201  while (i < pldLen) {
202  unsigned long leQword = 0x0000000000000000; // in LE order
203  unsigned char leKeep = 0x00;
204  bool leLast = false;
205  while (b < 8) {
206  unsigned char datByte = pldStr[i];
207  leQword = leQword | (datByte << b*8);
208  leKeep = leKeep | (1 << b);
209  i++;
210  b++;
211  if (i == pldLen) {
212  leLast = true;
213  break;
214  }
215  }
216  b = 0;
217  pushChunk(AxisUdp(leQword, leKeep, leLast));
218  }
219  } // End-of: addUdpPayload
220 
221 
241  ap_uint<32> csum = 0;
242  csum += byteSwap16(ipSa(31, 16)); // Set IP_SA in LE
243  csum += byteSwap16(ipSa(15, 0));
244  csum += byteSwap16(ipDa(31, 16)); // Set IP_DA in LE
245  csum += byteSwap16(ipDa(15, 0));
246  csum += byteSwap16(ap_uint<16>(IP4_PROT_UDP));
247  csum += byteSwap16(this->getUdpLength());
248  for (int i=0; i<this->size(); ++i) {
249  LE_tData tempInput = 0;
250  if (dgmQ[i].getLE_TKeep() & 0x01)
251  tempInput.range( 7, 0) = (dgmQ[i].getLE_TData()).range( 7, 0);
252  if (dgmQ[i].getLE_TKeep() & 0x02)
253  tempInput.range(15, 8) = (dgmQ[i].getLE_TData()).range(15, 8);
254  if (dgmQ[i].getLE_TKeep() & 0x04)
255  tempInput.range(23,16) = (dgmQ[i].getLE_TData()).range(23,16);
256  if (dgmQ[i].getLE_TKeep() & 0x08)
257  tempInput.range(31,24) = (dgmQ[i].getLE_TData()).range(31,24);
258  if (dgmQ[i].getLE_TKeep() & 0x10)
259  tempInput.range(39,32) = (dgmQ[i].getLE_TData()).range(39,32);
260  if (dgmQ[i].getLE_TKeep() & 0x20)
261  tempInput.range(47,40) = (dgmQ[i].getLE_TData()).range(47,40);
262  if (dgmQ[i].getLE_TKeep() & 0x40)
263  tempInput.range(55,48) = (dgmQ[i].getLE_TData()).range(55,48);
264  if (dgmQ[i].getLE_TKeep() & 0x80)
265  tempInput.range(63,56) = (dgmQ[i].getLE_TData()).range(63,56);
266  csum = ((((csum +
267  tempInput.range(63, 48)) + tempInput.range(47, 32)) +
268  tempInput.range(31, 16)) + tempInput.range(15, 0));
269  }
270  while (csum >> 16) {
271  csum = (csum & 0xFFFF) + (csum >> 16);
272  }
273  // Reverse the bits of the result
274  UdpCsum udpCsum = csum.range(15, 0);
275  udpCsum = ~udpCsum;
276  return byteSwap16(udpCsum);
277  }
278 
279 
290  this->setUdpChecksum(0x0000);
291  UdpCsum newUdpCsum = calculateUdpChecksum(ipSa, ipDa);
292  // Overwrite the former UDP checksum
293  this->setUdpChecksum(newUdpCsum);
294  return (newUdpCsum);
295  }
296 
297 
305  bool isWellFormed(const char *callerName, Ip4Addr ipSa, Ip4Addr ipDa) {
306  bool rc = true;
307  // Assess the length field vs datagram length
308  if (this->getUdpLength() != this->getLen()) {
309  printWarn(callerName, "Malformed UDP datagram: 'Length' field does not match the length of the datagram.\n");
310  printWarn(callerName, "\tFound 'Length' field=0x%4.4X, Was expecting 0x%4.4X)\n",
311  (this->getUdpLength()).to_uint(), this->getLen());
312  rc = false;
313  }
314  // Assess the checksum is valid (or 0x0000)
315  UdpCsum udpHCsum = this->getUdpChecksum();
316  UdpCsum calcCsum = this->reCalculateUdpChecksum(ipSa, ipDa);
317  if ((udpHCsum != 0) and (udpHCsum != calcCsum)) {
318  // UDP datagram comes with an invalid checksum
319  printWarn(callerName, "Malformed UDP datagram: 'Checksum' field does not match the checksum of the pseudo-packet.\n");
320  printWarn(callerName, "\tFound 'Checksum' field=0x%4.4X, Was expecting 0x%4.4X)\n",
321  udpHCsum.to_uint(), calcCsum.to_ushort());
322  rc = false;
323  }
324  return rc;
325  }
326 
327 
333  bool writeAxisUdpToFile(AxisUdp *axisUdp, ofstream &outFileStream) {
334  if (!outFileStream.is_open()) {
335  printError(myName, "File is not opened.\n");
336  return false;
337  }
338  AxisRaw axisRaw(axisUdp->getLE_TData(), axisUdp->getLE_TKeep(), axisUdp->getLE_TLast());
339  bool rc = writeAxisRawToFile(axisRaw, outFileStream);
340  return(rc);
341  }
342 
343 
348  bool writeToDatFile(ofstream &outFileStream) {
349  for (int i=0; i < this->size(); i++) {
350  AxisUdp axisUdp = this->dgmQ[i];
351  if (not this->writeAxisUdpToFile(&axisUdp, outFileStream)) {
352  return false;
353  }
354  }
355  return true;
356  }
357 
358 
363  bool writePayloadToDatFile(ofstream &outFileStream) {
364  for (int i=1; i < this->size(); i++) {
365  AxisUdp axisChunk = this->dgmQ[i];
366  if (not this->writeAxisUdpToFile(&axisChunk, outFileStream)) {
367  return false;
368  }
369  }
370  return true;
371  }
372 
373 }; // End-of: SimUdpDatagram
374 
375 #endif
376 
: A class to access UDP header fields within data chunks transmitted over an AXI4-Stream interface.
: Utilities for the simulation of the Network-Transport-Stack (NTS) components.
LE_tKeep getLE_TKeep(int leHi=64/8-1, int leLo=0) const
Definition: AxisRaw.hpp:264
LE_tData getLE_TData(int leHi=64 -1, int leLo=0) const
Definition: AxisRaw.hpp:260
int getLen() const
Definition: AxisRaw.hpp:411
LE_tLast getLE_TLast() const
Definition: AxisRaw.hpp:268
Class UDP Datagram.
SimUdpDatagram(int dgmLen)
void setUdpChecksum(UdpCsum csum)
void pushChunk(AxisUdp udpChunk)
SimUdpDatagram pullHeader()
Pull the header of this datagram.
void clone(SimUdpDatagram &udpDgm)
Clone a UDP datagram.
UdpCsum calculateUdpChecksum(Ip4Addr ipSa, Ip4Addr ipDa)
Calculate the UDP checksum of the datagram.
void setUdpLength(UdpLen len)
bool writeAxisUdpToFile(AxisUdp *axisUdp, ofstream &outFileStream)
Dump an AxisUdp chunk to a file.
bool isWellFormed(const char *callerName, Ip4Addr ipSa, Ip4Addr ipDa)
Checks if the datagram header fields are properly set.
void cloneHeader(SimUdpDatagram &udpDgm)
Clone the header of a UDP datagram.
bool writeToDatFile(ofstream &outFileStream)
Dump this UDP datagram as raw AxisUdp chunks into a file.
void addUdpPayload(string pldStr)
UdpCsum reCalculateUdpChecksum(Ip4Addr ipSa, Ip4Addr ipDa)
Recalculate the UDP checksum of a datagram.
void setUdpDestinationPort(int port)
UdpCsum getUdpChecksum()
void setUdpSourcePort(int port)
bool writePayloadToDatFile(ofstream &outFileStream)
Dump the payload of this datagram as AxisUdp chunks into a file.
ap_uint< 16 > UdpLen
Definition: nal.hpp:250
bool writeAxisRawToFile(AxisRaw &axisRaw, ofstream &outFileStream)
Dump an Axis raw data chunk to a file.
#define printError(callerName, format,...)
A macro to print an error message.
Definition: nts_utils.hpp:195
LE_tKeep lenToLE_tKeep(ap_uint< 4 > noValidBytes)
A function to set a number of '1' in an 8-bit field. It is used here to set the number of valid bytes...
Definition: nts_utils.cpp:307
ap_uint< 64 > LE_tData
Definition: AxisRaw.hpp:122
#define IP4_PROT_UDP
Definition: nts_types.hpp:185
ap_uint< 32 > Ip4Addr
Definition: AxisIp4.hpp:169
#define UDP_HEADER_LEN
Definition: AxisUdp.hpp:81
#define printWarn(callerName, format,...)
A macro to print a warning message.
Definition: nts_utils.hpp:182
ap_uint< 16 > UdpCsum
Definition: AxisUdp.hpp:101
#define printFatal(callerName, format,...)
A macro to print a fatal error message and exit.
Definition: nts_utils.hpp:208
#define TLAST
Definition: AxisRaw.hpp:116
: Utilities and helpers for the Network-Transport-Stack (NTS) components.
ap_uint< 16 > byteSwap16(ap_uint< 16 > inputVector)
Definition: udp.cpp:82
#define MTU
Definition: udp.hpp:71