TIMPacket.hh
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 
14 #ifndef HH_WiBACK_DataPlane_Packets_TIMPacket_
15 #define HH_WiBACK_DataPlane_Packets_TIMPacket_ 1
16 
17 // Custom includes
18 #include <senf/Packets/Packets.hh>
20 #include <senf/Utils/Statistics.hh>
22 
24 namespace wiback {
25 
27  {
28 # include SENF_FIXED_PARSER()
29 
30  SENF_PARSER_BITFIELD( syn, 1, bool );
31  SENF_PARSER_BITFIELD( oddSize, 1, bool );
32  SENF_PARSER_BITFIELD( timestamp, 14, unsigned );
33  SENF_PARSER_BITFIELD( sequenceNumber, 24, unsigned );
34  SENF_PARSER_BITFIELD( linkLocalSeqNo, 24, unsigned );
35 
37  };
38 
40  : public senf::PacketTypeBase,
41  public senf::PacketTypeMixin<TIMPacketType>
42  {
43  static constexpr std::uint32_t TSBits = 14;
44  static constexpr std::uint32_t SeqNoBits = 24;
45 
49 
50  using mixin::initSize;
51  using mixin::init;
52 
53  static factory_t nextPacketType(packet p);
54  static optional_range nextPacketRange(packet const & p);
56  static void dump(packet p, std::ostream & os);
57  static void finalize(packet p);
58  // computes the difference between our timestamps and seqNos
59  static std::int32_t timeStampDiff(std::uint32_t tstamp2, std::uint32_t tstamp1);
60  static std::int32_t seqNoDiff(std::uint32_t current, std::uint32_t last);
61  };
62 
64 
65  //
66  // TIM SeqNo Stats Analyzer
67  //
68  struct TIMSeqNoStats {
69  std::uint32_t processed;
70  std::uint32_t good;
71  std::uint32_t goodBytes;
72  std::uint32_t duplicate;
73  std::uint32_t late;
74  std::uint32_t lost;
75  std::uint32_t resyncs;
76  std::uint32_t last_;
77 
79  reset();
80  };
81 
82  void clear() {
83  processed = good = goodBytes = duplicate = late = lost = 0;
84  };
85 
86  void reset() {
87  clear();
88  resyncs = 0;
89  last_ = 0xFFFFFFFF;
90  };
91 
92  bool process(std::uint32_t seqNo, std::uint32_t payloadSize) {
93  processed++;
94  if (SENF_UNLIKELY(last_ == 0xFFFFFFFF)) {
95  good = 1;
96  goodBytes = payloadSize;
97  last_ = seqNo;
98  return true;
99  }
100 
101  int diff (TIMPacketType::seqNoDiff(seqNo, last_));
102 
103  if (SENF_LIKELY(diff == 1)) {
104  // no loss
105  good++;
106  goodBytes += payloadSize;
107  last_ = seqNo;
108  return true;
109  }
110  else if (diff == 0) {
111  // duplicate
112  duplicate++;
113  }
114  else if (diff < 0) {
115  // late frame(s) => reordering
116  late++;
117  if (diff <= -128) {
118  // resync to next expected SeqNo
119  resyncs++;
120  last_ = seqNo;
121  return true;
122  }
123  } else {
124  // frame loss
125  lost += diff-1;
126  last_ = seqNo;
127  return true;
128  }
129  return false;
130  }
131 
132  bool processSeqNo(TIMPacket const & tim) {
133  return process(tim->sequenceNumber(), tim.size() - TIMPacketType::parser::fixed_bytes);
134  }
135 
136  bool processLLSeqNo(TIMPacket const & tim) {
137  return process(tim->linkLocalSeqNo(), tim.size() - TIMPacketType::parser::fixed_bytes);
138  }
139 
140  void dump(std::ostream & os, senf::ClockService::clock_type const & period = senf::ClockService::clock_type(0)) {
141  os << "processed " << processed << ", good " << good << ", goodBytes " << goodBytes;
142  if (period) {
143  os << ", good/s " << ((std::uint64_t(good) * 1000) / senf::ClockService::in_milliseconds(period));
144  os << ", goodBytes/s " << ((std::uint64_t(goodBytes) * 1000) / senf::ClockService::in_milliseconds(period));
145  }
146  os << ", duplicate " << duplicate << ", late " << late << ", lost " << lost;
147  os << ", resyncs " << resyncs;
148  }
149  };
150 
154  // no unsigned here!
155  std::int32_t lastPD_;
156 
158  reset();
159  };
160 
161  void clear() {
162  delay.clear();
163  pdv.clear();
164  };
165 
166  void reset() {
167  clear();
168  lastPD_ = 0x7FFFFFFF;
169  };
170 
171  void process(TIMPacket const & tim) {
172 
173  std::int32_t diff (TIMPacketType::timeStampDiff(tim.annotation<senf::emu::annotations::Timestamp>().as_milli_seconds((TIMPacketParser::timestamp_t::max_value + 1)), tim->timestamp()));
174 
175  // first packet seen => establish the typical delay
176  if (SENF_UNLIKELY(lastPD_ == 0x7FFFFFFF)) {
177  lastPD_ = diff;
178  }
179 
180  pdv.accumulate(unsigned(abs(diff - lastPD_)));
181  lastPD_ = diff;
182 
183  if (tim->syn()) { // we need to also check if our clock is synced
184  if (SENF_UNLIKELY(diff < 0))
185  diff = (TIMPacketParser::timestamp_t::max_value + 1); // error
186  delay.accumulate(unsigned(diff));
187  }
188  }
189  };
190 
191 }
192 
194 
196 #include "TIMPacket.cci"
197 //#include "TIMPacket.ct"
198 //#include "TIMPacket.cti"
199 #endif
config::time_type clock_type
senf::UIntFieldParser<?,?+14 > timestamp() const
static std::int32_t timeStampDiff(std::uint32_t tstamp2, std::uint32_t tstamp1)
#define SENF_PARSER_BITFIELD(name, bits, type)
static SENF_CLOCKSERVICE_CONSTEXPR int64_type in_milliseconds(clock_type const &v)
senf::FlagParser<?> syn() const
PacketInterpreterBase::optional_range optional_range
SENF_PACKET_PREVENT_TEMPLATE_INSTANTIATION(senf::TIMPacket)
senf::UIntFieldParser<?,?+24 > linkLocalSeqNo() const
std::uint32_t duplicate
Definition: TIMPacket.hh:72
#define SENF_LIKELY(x)
std::uint32_t last_
Definition: TIMPacket.hh:76
senf::PacketTypeMixin< TIMPacketType > mixin
Definition: TIMPacket.hh:46
Annotations public header.
std::uint32_t late
Definition: TIMPacket.hh:73
void process()
#define SENF_PARSER_FINALIZE(name)
void dump(std::ostream &os, DirectoryNode &dir=root())
bool processLLSeqNo(TIMPacket const &tim)
Definition: TIMPacket.hh:136
Incoming packet timestamp.
Definition: Annotations.hh:86
senf::StatisticAccumulator< std::uint32_t > pdv
Definition: TIMPacket.hh:153
std::uint32_t resyncs
Definition: TIMPacket.hh:75
senf::StatisticAccumulator< std::uint32_t > delay
Definition: TIMPacket.hh:152
Annotation & annotation()
static std::int32_t seqNoDiff(std::uint32_t current, std::uint32_t last)
void process(TIMPacket const &tim)
Definition: TIMPacket.hh:171
senf::FlagParser<?> oddSize() const
std::uint32_t as_milli_seconds(std::uint32_t modulo=0xffffffff) const
bool process(std::uint32_t seqNo, std::uint32_t payloadSize)
Definition: TIMPacket.hh:92
std::uint32_t processed
Definition: TIMPacket.hh:69
senf::ConcretePacket< TIMPacketType > TIMPacket
Definition: TIMPacket.hh:63
std::uint32_t lost
Definition: TIMPacket.hh:74
bool processSeqNo(TIMPacket const &tim)
Definition: TIMPacket.hh:132
std::uint32_t good
Definition: TIMPacket.hh:70
size_type size() const
senf::UIntFieldParser<?,?+24 > sequenceNumber() const
std::uint32_t goodBytes
Definition: TIMPacket.hh:71
PacketInterpreterBase::factory_t factory_t
senf::ConcretePacket< TIMPacketType > packet
Definition: TIMPacket.hh:47
::phoenix::function< detail::clear > const clear
void dump(std::ostream &os, senf::ClockService::clock_type const &period=senf::ClockService::clock_type(0))
Definition: TIMPacket.hh:140
#define SENF_UNLIKELY(x)
TIMPacketParser parser
Definition: TIMPacket.hh:48