cloudFPGA (cF) API  1.0
The documentation of the source code of cloudFPGA (cF)
SimEthFrame.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_ETH_FRAME_
31 #define _SIM_ETH_FRAME_
32 
33 #include "nts_utils.hpp"
34 #include "SimIp4Packet.hpp"
35 #include "SimArpPacket.hpp"
36 #include "SimNtsUtils.hpp"
37 
38 
39 
55 class SimEthFrame {
56 
57  private:
58  int len; // The length of the frame in bytes
59  std::deque<AxisEth> frmQ; // A double-ended queue to store ETHernet chunks.
60  const char *myName;
61 
62  // Set the length of this ETH frame (in bytes)
63  void setLen(int frmLen) {
64  this->len = frmLen;
65  }
66  // Get the length of this ETH frame (in bytes)
67  int getLen() {
68  return this->len;
69  }
70  // Clear the content of the ETH frame queue
71  void clear() {
72  this->frmQ.clear();
73  this->len = 0;
74  }
75  // Return the front chunk element of the ETH frame queue but does not remove it from the queue
76  AxisEth front() {
77  return this->frmQ.front();
78  }
79  // Remove the first chunk element of the ETH frame queue
80  void pop_front() {
81  this->frmQ.pop_front();
82  }
83  // Add an element at the end of the ETH frame queue
84  void push_back(AxisEth ethChunk) {
85  this->frmQ.push_back(ethChunk);
86  }
87 
88  public:
89 
90  // Default Constructor: Constructs a frame of 'frmLen' bytes.
91  SimEthFrame(int frmLen) {
92  this->myName = "SimEthFrame";
93  setLen(0);
94  if (frmLen > 0 && frmLen <= MTU) {
95  int noBytes = frmLen;
96  while(noBytes > 8) {
97  pushChunk(AxisEth(0x0000000000000000, 0xFF, 0));
98  noBytes -= 8;
99  }
100  pushChunk(AxisEth(0x0000000000000000, lenToLE_tKeep(noBytes), TLAST));
101  }
102  }
104  this->myName = "SimEthFrame";
105  setLen(0);
106  }
107 
108  // Add a chunk of bytes at the end of the double-ended queue
109  void pushChunk(AxisEth ethChunk) {
110  if (this->size() > 0) {
111  // Always clear 'TLAST' bit of previous chunck
112  this->frmQ[this->size()-1].setLE_TLast(0);
113  }
114  this->push_back(ethChunk);
115  this->setLen(this->getLen() + ethChunk.getLen());
116  }
117 
118  // Return the chunk of bytes at the front of the queue and remove that chunk from the queue
120  AxisEth headingChunk = this->front();
121  this->pop_front();
122  setLen(getLen() - headingChunk.getLen());
123  return headingChunk;
124  }
125 
126  // Return the length of the ETH frame (in bytes)
127  int length() { return this->len; }
128 
129  // Return the number of chunks in the ETH frame (in axis-words)
130  int size() { return this->frmQ.size(); }
131 
132  // Set the MAC Destination Address field
133  void setMacDestinAddress(EthAddr addr) { frmQ[0].setEthDstAddr(addr); }
134  // Get the MAC Destination Address field
135  EthAddr getMacDestinAddress() { return frmQ[0].getEthDstAddr(); }
136  LE_EthAddr getLE_MacDestinAddress() { return frmQ[0].getLE_EthDstAddr(); }
137  // Set the MAC Source Address field
138  void setMacSourceAddress(EthAddr addr) { frmQ[0].setEthSrcAddrHi(addr);
139  frmQ[1].setEthSrcAddrLo(addr); }
140  // Get the MAC Source Address field
141  EthAddr getMacSourceAddress() { EthAddr macHi = ((EthAddr)(frmQ[0].getEthSrcAddrHi()) << 32);
142  EthAddr macLo = ((EthAddr)(frmQ[1].getEthSrcAddrLo()) << 0);
143  return (macHi | macLo); }
144  // Set the EtherType/Length field
145  void setTypeLength(EthTypeLen typLen) { frmQ[1].setEthTypeLen(typLen); }
146  // Get the EtherType/Length field
147  EthTypeLen getTypeLength() { return frmQ[1].getEthTypelen(); }
148 
149  // Return the size of the ETH data payload (in bytes)
151  int ethTypLen = this->getTypeLength();
152  if (ethTypLen < 0x0600) { // .i.e 1536
153  return ethTypLen;
154  }
155  else {
156  // Retrieve the payload length from the deque
157  return (this->length());
158  }
159  }
160 
161  // Return the ETH data payload as a SimIp4Packet
163  SimIp4Packet ipPacket;
164  LE_tData newTData = 0;
165  LE_tKeep newTKeep = 0;
166  LE_tLast newTLast = 0;
167  int chunkOutCnt = 0;
168  int chunkInpCnt = 1; // Skip 1st chunk which contains MAC_SA [1:0] | MAC_DA[5:0]
169  bool alternate = true;
170  bool endOfFrm = false;
171  int ethFrmSize = this->size();
172  while (chunkInpCnt < ethFrmSize) {
173  if (endOfFrm) {
174  break;
175  }
176  else if (alternate) {
177  newTData = 0;
178  newTKeep = 0;
179  newTLast = 0;
180  if (this->frmQ[chunkInpCnt].getLE_TKeep() & 0x40) {
181  newTData.range( 7, 0) = this->frmQ[chunkInpCnt].getLE_TData().range(55, 48);
182  newTKeep = newTKeep | (0x01);
183  }
184  if (this->frmQ[chunkInpCnt].getLE_TKeep() & 0x80) {
185  newTData.range(15, 8) = this->frmQ[chunkInpCnt].getLE_TData().range(63, 56);
186  newTKeep = newTKeep | (0x02);
187  }
188  if (this->frmQ[chunkInpCnt].getLE_TLast()) {
189  newTLast = TLAST;
190  endOfFrm = true;
191  ipPacket.pushChunk(AxisIp4(newTData, newTKeep, newTLast));
192  }
193  alternate = !alternate;
194  chunkInpCnt++;
195  }
196  else {
197  if (this->frmQ[chunkInpCnt].getLE_TKeep() & 0x01) {
198  newTData.range(23, 16) = this->frmQ[chunkInpCnt].getLE_TData().range( 7, 0);
199  newTKeep = newTKeep | (0x04);
200  }
201  if (this->frmQ[chunkInpCnt].getLE_TKeep() & 0x02) {
202  newTData.range(31, 24) = this->frmQ[chunkInpCnt].getLE_TData().range(15, 8);
203  newTKeep = newTKeep | (0x08);
204  }
205  if (this->frmQ[chunkInpCnt].getLE_TKeep() & 0x04) {
206  newTData.range(39, 32) = this->frmQ[chunkInpCnt].getLE_TData().range(23, 16);
207  newTKeep = newTKeep | (0x10);
208  }
209  if (this->frmQ[chunkInpCnt].getLE_TKeep() & 0x08) {
210  newTData.range(47, 40) = this->frmQ[chunkInpCnt].getLE_TData().range(31, 24);
211  newTKeep = newTKeep | (0x20);
212  }
213  if (this->frmQ[chunkInpCnt].getLE_TKeep() & 0x10) {
214  newTData.range(55, 48) = this->frmQ[chunkInpCnt].getLE_TData().range(39, 32);
215  newTKeep = newTKeep | (0x40);
216  }
217  if (this->frmQ[chunkInpCnt].getLE_TKeep() & 0x20) {
218  newTData.range(63, 56) = this->frmQ[chunkInpCnt].getLE_TData().range(47, 40);
219  newTKeep = newTKeep | (0x80);
220  }
221  if (this->frmQ[chunkInpCnt].getLE_TLast() && (not (this->frmQ[chunkInpCnt].getLE_TKeep() & 0xC0))) {
222  newTLast = TLAST;
223  endOfFrm = true;
224  }
225  alternate = !alternate;
226  chunkOutCnt++;
227  ipPacket.pushChunk(AxisIp4(newTData, newTKeep, newTLast));
228  }
229  }
230  return ipPacket;
231  }
232 
233  // Return the ETH data payload as an ArpPacket
235  SimArpPacket arpPacket;
236  LE_tData newTData = 0;
237  LE_tKeep newTKeep = 0;
238  LE_tLast newTLast = 0;
239  int chunkOutCnt = 0;
240  int chunkInpCnt = 1; // Skip 1st chunk with MAC_SA [1:0] and MAC_DA[5:0]
241  bool alternate = true;
242  bool endOfFrm = false;
243  int ethFrmSize = this->size();
244  while (chunkInpCnt < ethFrmSize) {
245  if (endOfFrm) {
246  break;
247  }
248  else if (alternate) {
249  newTData = 0;
250  newTKeep = 0;
251  newTLast = 0;
252  if (this->frmQ[chunkInpCnt].getLE_TKeep() & 0x40) {
253  newTData.range( 7, 0) = this->frmQ[chunkInpCnt].getLE_TData().range(55, 48);
254  newTKeep = newTKeep | (0x01);
255  }
256  if (this->frmQ[chunkInpCnt].getLE_TKeep() & 0x80) {
257  newTData.range(15, 8) = this->frmQ[chunkInpCnt].getLE_TData().range(63, 56);
258  newTKeep = newTKeep | (0x02);
259  }
260  if (this->frmQ[chunkInpCnt].getLE_TLast()) {
261  newTLast = TLAST;
262  endOfFrm = true;
263  arpPacket.pushChunk(AxisArp(newTData, newTKeep, newTLast));
264  }
265  alternate = !alternate;
266  chunkInpCnt++;
267  }
268  else {
269  if (this->frmQ[chunkInpCnt].getLE_TKeep() & 0x01) {
270  newTData.range(23, 16) = this->frmQ[chunkInpCnt].getLE_TData().range( 7, 0);
271  newTKeep = newTKeep | (0x04);
272  }
273  if (this->frmQ[chunkInpCnt].getLE_TKeep() & 0x02) {
274  newTData.range(31, 24) = this->frmQ[chunkInpCnt].getLE_TData().range(15, 8);
275  newTKeep = newTKeep | (0x08);
276  }
277  if (this->frmQ[chunkInpCnt].getLE_TKeep() & 0x04) {
278  newTData.range(39, 32) = this->frmQ[chunkInpCnt].getLE_TData().range(23, 16);
279  newTKeep = newTKeep | (0x10);
280  }
281  if (this->frmQ[chunkInpCnt].getLE_TKeep() & 0x08) {
282  newTData.range(47, 40) = this->frmQ[chunkInpCnt].getLE_TData().range(31, 24);
283  newTKeep = newTKeep | (0x20);
284  }
285  if (this->frmQ[chunkInpCnt].getLE_TKeep() & 0x10) {
286  newTData.range(55, 48) = this->frmQ[chunkInpCnt].getLE_TData().range(39, 32);
287  newTKeep = newTKeep | (0x40);
288  }
289  if (this->frmQ[chunkInpCnt].getLE_TKeep() & 0x20) {
290  newTData.range(63, 56) = this->frmQ[chunkInpCnt].getLE_TData().range(47, 40);
291  newTKeep = newTKeep | (0x80);
292  }
293  if (this->frmQ[chunkInpCnt].getLE_TLast() && (not (this->frmQ[chunkInpCnt].getLE_TKeep() & 0xC0))) {
294  newTLast = TLAST;
295  endOfFrm = true;
296  }
297  alternate = !alternate;
298  chunkOutCnt++;
299  arpPacket.pushChunk(AxisArp(newTData, newTKeep, newTLast));
300  }
301  }
302  return arpPacket;
303  }
304 
305 
314  bool addPayload(SimArpPacket arpPkt) {
315  bool alternate = true;
316  bool endOfPkt = false;
317  AxisArp arpChunk(0,0,0);
318  LE_tData newTData = 0;
319  LE_tKeep newTKeep = 0;
320  LE_tLast newTLast = 0;
321  int arpChunkCnt = 0;
322  int ethChunkCnt = 1; // Start from 1st chunk which contains ETHER_TYP and MAC_SA [5:2]
323 
324  if (this->getLen() != 14) {
325  printError(this->myName, "Frame is expected to be of length 14 bytes (was found to be %d bytes).\n", this->getLen());
326  return false;
327  }
328  // Read and pop the very first chunk from the packet
329  arpChunk = arpPkt.pullChunk();
330 
331  while (!endOfPkt) {
332  if (alternate) {
333  if (arpChunk.getLE_TKeep() & 0x01) {
334  this->frmQ[ethChunkCnt].setLE_TData(arpChunk.getLE_TData().range( 7, 0), 55, 48);
335  this->frmQ[ethChunkCnt].setLE_TKeep(this->frmQ[ethChunkCnt].getLE_TKeep() | (0x40));
336  this->setLen(this->getLen() + 1);
337  }
338  if (arpChunk.getLE_TKeep() & 0x02) {
339  this->frmQ[ethChunkCnt].setLE_TData(arpChunk.getLE_TData().range(15, 8), 63, 56);
340  this->frmQ[ethChunkCnt].setLE_TKeep(this->frmQ[ethChunkCnt].getLE_TKeep() | (0x80));
341  this->setLen(this->getLen() + 1);
342  }
343  if ((arpChunk.getLE_TLast()) && (arpChunk.getLE_TKeep() <= 0x03)) {
344  this->frmQ[ethChunkCnt].setLE_TLast(TLAST);
345  endOfPkt = true;
346  }
347  else {
348  this->frmQ[ethChunkCnt].setLE_TLast(0);
349  }
350  alternate = !alternate;
351  }
352  else {
353  // Build a new chunk and add it to the queue
354  AxisEth newEthChunk(0, 0, 0);
355  if (arpChunk.getLE_TKeep() & 0x04) {
356  newEthChunk.setLE_TData(arpChunk.getLE_TData().range(23, 16), 7, 0);
357  newEthChunk.setLE_TKeep(newEthChunk.getLE_TKeep() | (0x01));
358  }
359  if (arpChunk.getLE_TKeep() & 0x08) {
360  newEthChunk.setLE_TData(arpChunk.getLE_TData().range(31, 24), 15, 8);
361  newEthChunk.setLE_TKeep(newEthChunk.getLE_TKeep() | (0x02));
362  }
363  if (arpChunk.getLE_TKeep() & 0x10) {
364  newEthChunk.setLE_TData(arpChunk.getLE_TData().range(39, 32), 23,16);
365  newEthChunk.setLE_TKeep(newEthChunk.getLE_TKeep() | (0x04));
366  }
367  if (arpChunk.getLE_TKeep() & 0x20) {
368  newEthChunk.setLE_TData(arpChunk.getLE_TData().range(47, 40), 31,24);
369  newEthChunk.setLE_TKeep(newEthChunk.getLE_TKeep() | (0x08));
370  }
371  if (arpChunk.getLE_TKeep() & 0x40) {
372  newEthChunk.setLE_TData(arpChunk.getLE_TData().range(55, 48), 39,32);
373  newEthChunk.setLE_TKeep(newEthChunk.getLE_TKeep() | (0x10));
374  }
375  if (arpChunk.getLE_TKeep() & 0x80) {
376  newEthChunk.setLE_TData(arpChunk.getLE_TData().range(63, 56), 47,40);
377  newEthChunk.setLE_TKeep(newEthChunk.getLE_TKeep() | (0x20));
378  }
379  // Done with the incoming IP Chunk
380  arpChunkCnt++;
381  if (arpChunk.getLE_TLast()) {
382  newEthChunk.setLE_TLast(TLAST);
383  endOfPkt = true;
384  this->pushChunk(newEthChunk);
385  }
386  else {
387  newEthChunk.setLE_TLast(0);
388  this->pushChunk(newEthChunk);
389  ethChunkCnt++;
390  // Read and pop a new chunk from the packet
391  arpChunk = arpPkt.pullChunk();
392  }
393  alternate = !alternate;
394  }
395  } // End-of while(!endOfPkt)
396  return true;
397  }
398 
399 
408  bool addPayload(SimIp4Packet ipPkt) {
409  bool alternate = true;
410  bool endOfPkt = false;
411  AxisIp4 ip4Chunk(0, 0, 0);
412  int ip4ChunkCnt = 0;
413  int ethChunkCnt = 1; // Start from 1st chunk which contains ETHER_TYP and MAC_SA [5:2]
414 
415  if (this->getLen() != 14) {
416  printError(this->myName, "Frame is expected to be of length 14 bytes (was found to be %d bytes).\n", this->getLen());
417  return false;
418  }
419  // Read and pop the very first chunk from the packet
420  ip4Chunk = ipPkt.pullChunk();
421  while (!endOfPkt) {
422  if (alternate) {
423  if (ip4Chunk.getLE_TKeep() & 0x01) {
424  this->frmQ[ethChunkCnt].setLE_TData(ip4Chunk.getLE_TData( 7, 0), 55, 48);
425  this->frmQ[ethChunkCnt].setLE_TKeep(this->frmQ[ethChunkCnt].getLE_TKeep() | (0x40));
426  this->setLen(this->getLen() + 1);
427  }
428  if (ip4Chunk.getLE_TKeep() & 0x02) {
429  this->frmQ[ethChunkCnt].setLE_TData(ip4Chunk.getLE_TData(15, 8), 63, 56);
430  this->frmQ[ethChunkCnt].setLE_TKeep(this->frmQ[ethChunkCnt].getLE_TKeep() | (0x80));
431  this->setLen(this->getLen() + 1);
432  }
433  if ((ip4Chunk.getLE_TLast()) && (ip4Chunk.getLE_TKeep() <= 0x03)) {
434  this->frmQ[ethChunkCnt].setLE_TLast(TLAST);
435  endOfPkt = true;
436  }
437  else {
438  this->frmQ[ethChunkCnt].setLE_TLast(0);
439  }
440  alternate = !alternate;
441  }
442  else {
443  // Build a new chunk and add it to the queue
444  AxisEth newEthChunk(0,0,0);
445  if (ip4Chunk.getLE_TKeep() & 0x04) {
446  newEthChunk.setLE_TData(ip4Chunk.getLE_TData(23, 16), 7, 0);
447  newEthChunk.setLE_TKeep(newEthChunk.getLE_TKeep() | (0x01));
448  }
449  if (ip4Chunk.getLE_TKeep() & 0x08) {
450  newEthChunk.setLE_TData(ip4Chunk.getLE_TData(31, 24), 15, 8);
451  newEthChunk.setLE_TKeep(newEthChunk.getLE_TKeep() | (0x02));
452  }
453  if (ip4Chunk.getLE_TKeep() & 0x10) {
454  newEthChunk.setLE_TData(ip4Chunk.getLE_TData(39, 32), 23,16);
455  newEthChunk.setLE_TKeep(newEthChunk.getLE_TKeep() | (0x04));
456  }
457  if (ip4Chunk.getLE_TKeep() & 0x20) {
458  newEthChunk.setLE_TData(ip4Chunk.getLE_TData(47, 40), 31,24);
459  newEthChunk.setLE_TKeep(newEthChunk.getLE_TKeep() | (0x08));
460  }
461  if (ip4Chunk.getLE_TKeep() & 0x40) {
462  newEthChunk.setLE_TData(ip4Chunk.getLE_TData(55, 48), 39,32);
463  newEthChunk.setLE_TKeep(newEthChunk.getLE_TKeep() | (0x10));
464  }
465  if (ip4Chunk.getLE_TKeep() & 0x80) {
466  newEthChunk.setLE_TData(ip4Chunk.getLE_TData(63, 56), 47,40);
467  newEthChunk.setLE_TKeep(newEthChunk.getLE_TKeep() | (0x20));
468  }
469  // Done with the incoming IP word
470  ip4ChunkCnt++;
471  if (ip4Chunk.getLE_TLast()) {
472  newEthChunk.setLE_TLast(TLAST);
473  this->pushChunk(newEthChunk);
474  endOfPkt = true;
475  }
476  else {
477  newEthChunk.setLE_TLast(0);
478  this->pushChunk(newEthChunk);
479  ethChunkCnt++;
480  // Read and pop a new chunk from the packet
481  ip4Chunk = ipPkt.pullChunk();
482  }
483  alternate = !alternate;
484  }
485  } // End-of while(!endOfPkt)
486  return true;
487  }
488 
489 
495  bool writeToDatFile(ofstream &outFileStream) {
496  for (int i=0; i < this->size(); i++) {
497  AxisEth axisEth = this->frmQ[i];
498  if (not writeAxisRawToFile(axisEth, outFileStream)) {
499  return false;
500  }
501  }
502  return true;
503  }
504 
505 }; // End of: SimEthFrame
506 
507 #endif
508 
: A simulation class to build and handle ARP packets.
: A simulation class to build and handle IPv4 packets.
: 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
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
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 ARP Packet for simulation.
void pushChunk(AxisArp arpChunk)
AxisArp pullChunk()
Class ETHERNET Frame.
Definition: SimEthFrame.hpp:55
SimEthFrame(int frmLen)
Definition: SimEthFrame.hpp:91
LE_EthAddr getLE_MacDestinAddress()
void pushChunk(AxisEth ethChunk)
int sizeOfPayload()
SimIp4Packet getIpPacket()
bool writeToDatFile(ofstream &outFileStream)
Dump this Ethernet frame as raw AxisEth chunks into a file.
void setMacDestinAddress(EthAddr addr)
EthAddr getMacDestinAddress()
bool addPayload(SimArpPacket arpPkt)
Add data payload to this frame from an ARP packet.
void setTypeLength(EthTypeLen typLen)
bool addPayload(SimIp4Packet ipPkt)
Add data payload to this frame from an IP4 packet.
void setMacSourceAddress(EthAddr addr)
AxisEth pullChunk()
SimArpPacket getArpPacket()
EthAddr getMacSourceAddress()
EthTypeLen getTypeLength()
Class IPv4 Packet for simulation.
void pushChunk(AxisIp4 ip4Chunk)
AxisIp4 pullChunk()
bool writeAxisRawToFile(AxisRaw &axisRaw, ofstream &outFileStream)
Dump an Axis raw data chunk to a file.
ap_uint< 48 > EthAddr
Definition: AxisEth.hpp:120
#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< 64/8 > LE_tKeep
Definition: AxisRaw.hpp:124
ap_uint< 1 > LE_tLast
Definition: AxisRaw.hpp:125
ap_uint< 48 > LE_EthAddr
Definition: AxisEth.hpp:108
ap_uint< 16 > EthTypeLen
Definition: AxisEth.hpp:121
#define TLAST
Definition: AxisRaw.hpp:116
: Utilities and helpers for the Network-Transport-Stack (NTS) components.
#define MTU
Definition: udp.hpp:71