cloudFPGA (cF) API  1.0
The documentation of the source code of cloudFPGA (cF)
SimTcpSegment.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_TCP_SEGMENT_
31 #define _SIM_TCP_SEGMENT_
32 
33 #include <iostream>
34 #include <iomanip>
35 #include <deque>
36 #include <cstdlib>
37 
38 #include "nts_utils.hpp"
39 #include "SimNtsUtils.hpp"
40 #include "AxisTcp.hpp"
41 
42 using namespace std;
43 using namespace hls;
44 
45 
55 
56  private:
57  int len; // In bytes
58  std::deque<AxisTcp> segQ; // A double-ended queue to store TCP chunks.
59  const char *myName;
60 
61  // Set the length of this TCP segment (in bytes)
62  void setLen(int segLen) {
63  this->len = segLen;
64  }
65  // Get the length of this TCP segment (in bytes)
66  int getLen() {
67  return this->len;
68  }
69  // Clear the content of the TCP segment queue
70  void clear() {
71  this->segQ.clear();
72  this->len = 0;
73  }
74  // Return the back chunk element of the TCP segment queue but do not remove it from the queue
75  AxisTcp back() {
76  return this->segQ.front();
77  }
78  // Return the front chunk element of the TCP segment queue but do not remove it from the queue
79  AxisTcp front() {
80  return this->segQ.front();
81  }
82  // Remove the back chunk element of the TCP segment queue
83  void pop_back() {
84  this->segQ.pop_back();
85  }
86  // Remove the first chunk element of the TCP segment queue
87  void pop_front() {
88  this->segQ.pop_front();
89  }
90  // Add an element at the end of the TCP segment queue
91  void push_back(AxisTcp tcpChunk) {
92  this->segQ.push_back(tcpChunk);
93  }
94 
95  public:
96 
97  // Default Constructor: Constructs a segment of 'segLen' bytes.
98  SimTcpSegment(int segLen) {
99  this->myName = "SimTcpSegment";
100  setLen(0);
101  if (segLen > 0 && segLen <= MTU) { // [FIXME - Why MTU and not 64KB]
102  int noBytes = segLen;
103  while(noBytes > 8) {
104  pushChunk(AxisTcp(0x0000000000000000, 0xFF, 0));
105  noBytes -= 8;
106  }
107  pushChunk(AxisTcp(0x0000000000000000, lenToLE_tKeep(noBytes), TLAST));
108  }
109  }
111  this->myName = "SimTcpSegment";
112  this->len = 0;
113  }
114 
115  // Add a chunk of bytes at the end of the double-ended queue
116  void pushChunk(AxisTcp tcpChunk) {
117  if (this->size() > 0) {
118  // Always clear 'TLAST' bit of previous chunck
119  this->segQ[this->size()-1].setLE_TLast(0);
120  }
121  this->push_back(tcpChunk);
122  this->setLen(this->getLen() + tcpChunk.getLen());
123  }
124 
125  // Return the chunk at the front of the queue and remove that chunk from the queue
127  AxisTcp headingChunk = this->front();
128  this->pop_front();
129  setLen(getLen() - headingChunk.getLen());
130  return headingChunk;
131  }
132 
133  // Return the length of the TCP segment (in bytes)
134  int length() {
135  return this->len;
136  }
137 
138  // Return the number of chunks in the TCP segment (in axis-words)
139  int size() {
140  return this->segQ.size();
141  }
142 
143 
147  void clone(SimTcpSegment &tcpSeg) {
148  AxisTcp newAxisTcp;
149  for (int i=0; i<tcpSeg.segQ.size(); i++) {
150  newAxisTcp = tcpSeg.segQ[i];
151  this->segQ.push_back(newAxisTcp);
152  }
153  this->setLen(tcpSeg.getLen());
154  }
155 
156 
162  void cloneHeader(SimTcpSegment &tcpSeg) {
163  int cloneBytes = TCP_HEADER_LEN; // in bytes
164  int inpChunkCnt = 0;
165  while(cloneBytes > 0) {
166  if (cloneBytes > 8) {
167  this->pushChunk(tcpSeg.segQ[inpChunkCnt]);
168  }
169  else {
170  AxisTcp lastHdrChunk(tcpSeg.segQ[inpChunkCnt].getLE_TData(),
171  lenToLE_tKeep(cloneBytes), TLAST);
172  this->pushChunk(lastHdrChunk);
173  }
174  cloneBytes -= 8;
175  inpChunkCnt++;
176  }
177  }
178 
179  // Set the TCP Source Port field
180  void setTcpSourcePort(TcpPort port) { segQ[0].setTcpSrcPort(port); }
181  // Get the TCP Source Port field
182  TcpPort getTcpSourcePort() { return segQ[0].getTcpSrcPort(); }
183  LE_TcpPort getLE_TcpSourcePort() { return segQ[0].getLE_TcpSrcPort(); }
184  // Set the TCP Destination Port field
185  void setTcpDestinationPort(TcpPort port) { segQ[0].setTcpDstPort(port); }
186  // Get the TCP Destination Port field
187  TcpPort getTcpDestinationPort() { return segQ[0].getTcpDstPort(); }
188  LE_TcpPort getLE_TcpDestinationPort() { return segQ[0].getLE_TcpDstPort(); }
189  // Set the TCP Sequence Number field
190  void setTcpSequenceNumber(TcpSeqNum num) { segQ[0].setTcpSeqNum(num); }
191  // Get the TCP Sequence Number field
192  TcpSeqNum getTcpSequenceNumber() { return segQ[0].getTcpSeqNum(); }
193  // Set the TCP Acknowledgment Number
194  void setTcpAcknowledgeNumber(TcpAckNum num){ segQ[0].setTcpAckNum(num); }
195  // Get the TCP Acknowledgment Number
196  TcpAckNum getTcpAcknowledgeNumber() { return segQ[1].getTcpAckNum(); }
197  // Set the TCP Data Offset field
198  void setTcpDataOffset(int offset) { segQ[1].setTcpDataOff(offset); }
199  // Get the TCP Data Offset field
200  int getTcpDataOffset() { return segQ[1].getTcpDataOff(); }
201  // Set-Get the TCP Control Bits
202  void setTcpControlFin(TcpCtrlBit bit) { segQ[1].setTcpCtrlFin(bit); }
203  TcpCtrlBit getTcpControlFin() { return segQ[1].getTcpCtrlFin(); }
204  void setTcpControlSyn(TcpCtrlBit bit) { segQ[1].setTcpCtrlSyn(bit); }
205  TcpCtrlBit getTcpControlSyn() { return segQ[1].getTcpCtrlSyn(); }
206  void setTcpControlRst(TcpCtrlBit bit) { segQ[1].setTcpCtrlRst(bit); }
207  TcpCtrlBit getTcpControlRst() { return segQ[1].getTcpCtrlRst(); }
208  void setTcpControlPsh(TcpCtrlBit bit) { segQ[1].setTcpCtrlPsh(bit); }
209  TcpCtrlBit getTcpControlPsh() { return segQ[1].getTcpCtrlPsh(); }
210  void setTcpControlAck(TcpCtrlBit bit) { segQ[1].setTcpCtrlAck(bit); }
211  TcpCtrlBit getTcpControlAck() { return segQ[1].getTcpCtrlAck(); }
212  void setTcpControlUrg(TcpCtrlBit bit) { segQ[1].setTcpCtrlUrg(bit); }
213  TcpCtrlBit getTcpControlUrg() { return segQ[1].getTcpCtrlUrg(); }
214  // Set the TCP Window field
215  void setTcpWindow(TcpWindow win) { segQ[1].setTcpWindow(win); }
216  // Get the TCP Window field
217  TcpWindow getTcpWindow() { return segQ[1].getTcpWindow(); }
218  // Set the TCP Checksum field
219  void setTcpChecksum(TcpChecksum csum) { segQ[2].setTcpChecksum(csum); }
220  // Get the TCP Checksum field
221  TcpCsum getTcpChecksum() { return segQ[2].getTcpChecksum(); }
222  // Set the TCP Urgent Pointer field
223  void setTcpUrgentPointer(TcpUrgPtr ptr) { segQ[2].setTcpUrgPtr(ptr); }
224  // Get the TCP Urgent Pointer field
225  TcpUrgPtr getTcpUrgentPointer() { return segQ[2].getTcpUrgPtr(); }
226  // Set-Get the TCP Option fields
227  void setTcpOptionKind(TcpOptKind val) { segQ[2].setTcpOptKind(val); }
228  TcpOptKind getTcpOptionKind() { return segQ[2].getTcpOptKind(); }
229  void setTcpOptionMss(TcpOptMss val) { segQ[2].setTcpOptMss(val); }
230  TcpOptMss getTcpOptionMss() { return segQ[2].getTcpOptMss(); }
231 
232 
238  void addTcpPayload(string pldStr) {
239  if (this->getLen() != TCP_HEADER_LEN) {
240  printFatal(this->myName, "Empty segment is expected to be of length %d bytes (was found to be %d bytes).\n",
241  TCP_HEADER_LEN, this->getLen());
242  }
243  int hdrLen = this->getLen(); // in bytes
244  int pldLen = pldStr.size();
245  int q = (hdrLen / 8);
246  int b = (hdrLen % 8);
247  int i = 0;
248  AxisTcp currChunk(0, 0, 0);
249  // At this point we are not aligned on an 8-byte data chunk because the
250  // default TCP headet length is 20 bytes. Alignement only occurs when
251  // the number of TCP option bytes is a multiple of 4 bytes.
252  if (b != 0) {
253  currChunk = this->back();
254  this->pop_back();
255  }
256  while (i < pldLen) {
257  while (b != 8) {
258  unsigned char datByte = pldStr[i];
259  currChunk.setLE_TData(datByte, (b*8+7), (b*8+0));
260  currChunk.setLE_TKeep(1, b, b);
261  i++;
262  b++;
263  if (i == pldLen) {
264  currChunk.setLE_TLast(TLAST);
265  break;
266  }
267  }
268  pushChunk(currChunk);
269  // Prepare a new chunk
270  currChunk.setLE_TData(0);
271  currChunk.setLE_TKeep(0);
272  currChunk.setLE_TLast(0);
273  b = 0;
274  }
275  } // End-of: addTcpPayload
276 
277 
301  ap_uint<32> csum = 0;
302  csum += byteSwap16(ipSa(31, 16)); // Set IP_SA in LE
303  csum += byteSwap16(ipSa(15, 0));
304  csum += byteSwap16(ipDa(31, 16)); // Set IP_DA in LE
305  csum += byteSwap16(ipDa(15, 0));
306  csum += byteSwap16(ap_uint<16>(IP4_PROT_TCP));
307  csum += byteSwap16(tcpSegLen);
308  for (int i=0; i<this->size(); ++i) {
309  LE_tData tempInput = 0;
310  if (segQ[i].getLE_TKeep() & 0x01)
311  tempInput.range( 7, 0) = (segQ[i].getLE_TData()).range( 7, 0);
312  if (segQ[i].getLE_TKeep() & 0x02)
313  tempInput.range(15, 8) = (segQ[i].getLE_TData()).range(15, 8);
314  if (segQ[i].getLE_TKeep() & 0x04)
315  tempInput.range(23,16) = (segQ[i].getLE_TData()).range(23,16);
316  if (segQ[i].getLE_TKeep() & 0x08)
317  tempInput.range(31,24) = (segQ[i].getLE_TData()).range(31,24);
318  if (segQ[i].getLE_TKeep() & 0x10)
319  tempInput.range(39,32) = (segQ[i].getLE_TData()).range(39,32);
320  if (segQ[i].getLE_TKeep() & 0x20)
321  tempInput.range(47,40) = (segQ[i].getLE_TData()).range(47,40);
322  if (segQ[i].getLE_TKeep() & 0x40)
323  tempInput.range(55,48) = (segQ[i].getLE_TData()).range(55,48);
324  if (segQ[i].getLE_TKeep() & 0x80)
325  tempInput.range(63,56) = (segQ[i].getLE_TData()).range(63,56);
326  csum = ((((csum +
327  tempInput.range(63, 48)) + tempInput.range(47, 32)) +
328  tempInput.range(31, 16)) + tempInput.range(15, 0));
329  }
330  while (csum >> 16) {
331  csum = (csum & 0xFFFF) + (csum >> 16);
332  }
333  // Reverse the bits of the result
334  TcpCsum tcpCsum = csum.range(15, 0);
335  tcpCsum = ~tcpCsum;
336  return byteSwap16(tcpCsum);
337  }
338 
339 
350  this->setTcpChecksum(0x0000);
351  TcpCsum newTcpCsum = calculateTcpChecksum(ipSa, ipDa, segLen);
352  // Overwrite the former TCP checksum
353  this->setTcpChecksum(newTcpCsum);
354  return (newTcpCsum);
355  }
356 
357 
365  bool isWellFormed(const char *callerName, Ip4Addr ipSa, Ip4Addr ipDa) {
366  bool rc = true;
367  // Assess the checksum is valid (or 0xDEAD)
368  TcpCsum tcpCsum = this->getTcpChecksum();
369  TcpCsum calcCsum = this->reCalculateTcpChecksum(ipSa, ipDa, (Ip4DatLen)this->getLen());
370  if ((tcpCsum != 0xDEAD) and (tcpCsum != calcCsum)) {
371  // TCP segment comes with an invalid checksum
372  printWarn(callerName, "Malformed TCP segment: 'Checksum' field does not match the checksum of the pseudo-packet.\n");
373  printWarn(callerName, "\tFound 'Checksum' field=0x%4.4X, Was expecting 0x%4.4X)\n",
374  tcpCsum.to_uint(), calcCsum.to_ushort());
375  rc = false;
376  }
377  return rc;
378  }
379 
380 
383  void dump() {
384  string segStr;
385  for (int q=0; q < this->size(); q++) {
386  AxisTcp axisData = this->segQ[q];
387  for (int b=7; b >= 0; b--) {
388  if (axisData.getTKeep().bit(b)) {
389  int hi = ((b*8) + 7);
390  int lo = ((b*8) + 0);
391  ap_uint<8> octet = axisData.getTData().range(hi, lo);
392  segStr += myUint8ToStrHex(octet);
393  }
394  }
395  }
396  bool endOfSeg = false;
397  int i = 0;
398  int offset = 0;
399  char *ptr;
400  do {
401  string hexaStr;
402  string asciiStr;
403  for (int c=0; c < 16*2; c+=2) {
404  if (i < segStr.length()) {
405  hexaStr += segStr.substr(i, 2);
406  char ch = std::strtoul(segStr.substr(i, 2).c_str(), &ptr, 16);
407  if ((int)ch > 0x1F)
408  asciiStr += ch;
409  else
410  asciiStr += '.';
411 
412  }
413  else {
414  hexaStr += " ";
415  endOfSeg = true;
416  }
417  hexaStr += " ";
418  i += 2;
419  }
420  printf("%4.4X %s %s \n", offset, hexaStr.c_str(), asciiStr.c_str());
421  offset += 16;
422  } while (not endOfSeg);
423  }
424 
425 
431  bool writeAxisTcpToFile(AxisTcp &axisTcp, ofstream &outFileStream) {
432  if (!outFileStream.is_open()) {
433  printError(myName, "File is not opened.\n");
434  return false;
435  }
436  outFileStream << std::uppercase;
437  outFileStream << hex << noshowbase << setfill('0') << setw(16) << axisTcp.getLE_TData().to_uint64();
438  outFileStream << " ";
439  outFileStream << setw(1) << axisTcp.getLE_TLast().to_int();
440  outFileStream << " ";
441  outFileStream << hex << noshowbase << setfill('0') << setw(2) << axisTcp.getLE_TKeep().to_int() << "\n";
442  if (axisTcp.getLE_TLast()) {
443  outFileStream << "\n";
444  }
445  return(true);
446  }
447 
448 
453  bool writeToDatFile(ofstream &outFileStream) {
454  for (int i=0; i < this->size(); i++) {
455  AxisTcp axisTcp = this->segQ[i];
456  if (not this->writeAxisTcpToFile(axisTcp, outFileStream)) {
457  return false;
458  }
459  }
460  return true;
461  }
462 
463 
468  bool writePayloadToDatFile(ofstream &outFileStream) {
469  for (int i=1; i < this->size(); i++) {
470  AxisTcp axisWord = this->segQ[i];
471  if (not this->writeAxisTcpToFile(axisWord, outFileStream)) {
472  return false;
473  }
474  }
475  return true;
476  }
477 
478 }; // End-of: SimTcpSegment
479 
480 #endif
481 
: A class to access TCP header fields within data chunks transmitted over an AXI4-Stream interface.
: Utilities for the simulation of the Network-Transport-Stack (NTS) components.
tData getTData(int leHi=64 -1, int leLo=0) const
Definition: AxisRaw.hpp:191
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
void setLE_TLast(LE_tLast last)
Definition: AxisRaw.hpp:280
void setLE_TData(LE_tData data, int leHi=64 -1, int leLo=0)
Definition: AxisRaw.hpp:272
int getLen() const
Definition: AxisRaw.hpp:411
tKeep getTKeep(int leHi=64/8-1, int leLo=0) const
Definition: AxisRaw.hpp:207
void setLE_TKeep(LE_tKeep keep, int leHi=64/8-1, int leLo=0)
Definition: AxisRaw.hpp:276
LE_tLast getLE_TLast() const
Definition: AxisRaw.hpp:268
Class TCP Segment.
TcpCsum getTcpChecksum()
void setTcpControlAck(TcpCtrlBit bit)
void cloneHeader(SimTcpSegment &tcpSeg)
Clone the header of a TCP segment.
void setTcpDataOffset(int offset)
void setTcpOptionKind(TcpOptKind val)
void setTcpControlUrg(TcpCtrlBit bit)
TcpCtrlBit getTcpControlSyn()
void setTcpAcknowledgeNumber(TcpAckNum num)
void pushChunk(AxisTcp tcpChunk)
TcpCtrlBit getTcpControlAck()
TcpCtrlBit getTcpControlRst()
TcpCtrlBit getTcpControlFin()
TcpAckNum getTcpAcknowledgeNumber()
TcpCtrlBit getTcpControlUrg()
void setTcpControlSyn(TcpCtrlBit bit)
SimTcpSegment(int segLen)
void setTcpControlRst(TcpCtrlBit bit)
TcpCsum calculateTcpChecksum(Ip4Addr ipSa, Ip4Addr ipDa, Ip4DatLen tcpSegLen)
Calculate the TCP checksum of the segment.
void setTcpWindow(TcpWindow win)
void setTcpSourcePort(TcpPort port)
TcpOptKind getTcpOptionKind()
TcpUrgPtr getTcpUrgentPointer()
AxisTcp pullChunk()
bool writePayloadToDatFile(ofstream &outFileStream)
Dump the payload of this segment as AxisTcp chunks into a file.
void setTcpOptionMss(TcpOptMss val)
void clone(SimTcpSegment &tcpSeg)
Clone a TCP segment.
void setTcpUrgentPointer(TcpUrgPtr ptr)
TcpPort getTcpSourcePort()
bool writeToDatFile(ofstream &outFileStream)
Dump this TCP segment as raw AxisTcp chunks into a file.
void setTcpControlFin(TcpCtrlBit bit)
LE_TcpPort getLE_TcpDestinationPort()
TcpCtrlBit getTcpControlPsh()
void dump()
Dump this TCP segment as HEX and ASCII characters to screen.
TcpWindow getTcpWindow()
void setTcpChecksum(TcpChecksum csum)
void addTcpPayload(string pldStr)
Append data payload to a TCP header.
TcpPort getTcpDestinationPort()
bool isWellFormed(const char *callerName, Ip4Addr ipSa, Ip4Addr ipDa)
Checks if the segment header fields are properly set.
TcpSeqNum getTcpSequenceNumber()
bool writeAxisTcpToFile(AxisTcp &axisTcp, ofstream &outFileStream)
Dump an AxisTcp chunk to a file.
void setTcpDestinationPort(TcpPort port)
void setTcpSequenceNumber(TcpSeqNum num)
LE_TcpPort getLE_TcpSourcePort()
void setTcpControlPsh(TcpCtrlBit bit)
TcpCsum reCalculateTcpChecksum(Ip4Addr ipSa, Ip4Addr ipDa, Ip4DatLen segLen)
Recalculate the TCP checksum of this segment.
TcpOptMss getTcpOptionMss()
TcpSegLen tcpSegLen
Definition: tb_nal.cpp:833
string myUint8ToStrHex(ap_uint< 8 > inputNumber)
Converts an UINT8 into a string of 2 HEX characters.
ap_uint< 16 > LE_TcpPort
Definition: AxisTcp.hpp:88
ap_uint< 32 > TcpSeqNum
Definition: AxisTcp.hpp:106
ap_uint< 8 > TcpOptKind
Definition: AxisTcp.hpp:117
#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
ap_uint< 16 > TcpUrgPtr
Definition: AxisTcp.hpp:115
ap_uint< 16 > TcpCsum
Definition: AxisTcp.hpp:114
ap_uint< 16 > Ip4DatLen
Definition: AxisIp4.hpp:173
ap_uint< 1 > TcpCtrlBit
Definition: AxisTcp.hpp:111
ap_uint< 32 > Ip4Addr
Definition: AxisIp4.hpp:169
#define TCP_HEADER_LEN
Definition: AxisTcp.hpp:81
#define IP4_PROT_TCP
Definition: nts_types.hpp:184
ap_uint< 16 > TcpPort
Definition: AxisTcp.hpp:105
#define printWarn(callerName, format,...)
A macro to print a warning message.
Definition: nts_utils.hpp:182
ap_uint< 16 > TcpWindow
Definition: AxisTcp.hpp:112
ap_uint< 16 > TcpOptMss
Definition: AxisTcp.hpp:119
ap_uint< 32 > TcpAckNum
Definition: AxisTcp.hpp:107
#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
ap_uint< 16 > TcpChecksum
Definition: AxisTcp.hpp:113
void uppercase(ap_uint< 32 > *pi_rank, ap_uint< 32 > *pi_size, stream< NetworkWord > &siSHL_This_Data, stream< NetworkWord > &soTHIS_Shl_Data, stream< NetworkMetaStream > &siNrc_meta, stream< NetworkMetaStream > &soNrc_meta, ap_uint< 32 > *po_rx_ports)
Main process of the Uppercase Application directives.
Definition: uppercase.cpp:335
: Utilities and helpers for the Network-Transport-Stack (NTS) components.
ap_uint< 32 > size
ap_uint< 16 > byteSwap16(ap_uint< 16 > inputVector)
Definition: udp.cpp:82
#define MTU
Definition: udp.hpp:71