- Adapt MDS with this SNA implementation.
---
src/base/Makefile.am | 6 +-
src/base/sna.h | 123 +++++++++++++++++++++++++++++++
src/base/tests/sna_test.cc | 117 +++++++++++++++++++++++++++++
src/mds/mds_tipc_fctrl_portid.cc | 39 +++++-----
src/mds/mds_tipc_fctrl_portid.h | 76 ++-----------------
5 files changed, 270 insertions(+), 91 deletions(-)
create mode 100644 src/base/sna.h
create mode 100644 src/base/tests/sna_test.cc
diff --git a/src/base/Makefile.am b/src/base/Makefile.am
index 025fb86a2..5082175cf 100644
--- a/src/base/Makefile.am
+++ b/src/base/Makefile.am
@@ -173,7 +173,8 @@ noinst_HEADERS += \
src/base/unix_client_socket.h \
src/base/unix_server_socket.h \
src/base/unix_socket.h \
- src/base/usrbuf.h
+ src/base/usrbuf.h \
+ src/base/sna.h
TESTS += bin/testleap bin/libbase_test bin/core_common_test
@@ -237,7 +238,8 @@ bin_libbase_test_SOURCES = \
src/base/tests/time_compare_test.cc \
src/base/tests/time_convert_test.cc \
src/base/tests/time_subtract_test.cc \
- src/base/tests/unix_socket_test.cc
+ src/base/tests/unix_socket_test.cc \
+ src/base/tests/sna_test.cc
bin_libbase_test_LDADD = \
$(GTEST_DIR)/lib/libgtest.la \
diff --git a/src/base/sna.h b/src/base/sna.h
new file mode 100644
index 000000000..bd138293f
--- /dev/null
+++ b/src/base/sna.h
@@ -0,0 +1,123 @@
+/* -*- OpenSAF -*-
+ *
+ * Copyright Ericsson AB 2019 - All Rights Reserved.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed
+ * under the GNU Lesser General Public License Version 2.1, February 1999.
+ * The complete license can be accessed from the following location:
+ * http://opensource.org/licenses/lgpl-license.php
+ * See the Copying file included with the OpenSAF distribution for full
+ * licensing terms.
+ *
+ * Reference: Serial Number Arithmetic from RFC1982
+ *
+ */
+
+#ifndef BASE_SNA_H_
+#define BASE_SNA_H_
+
+#include <typeinfo>
+#include <stdexcept>
+
+#define MAX_16BITS 65536 // 2^16
+#define MAX_32BITS 4294967296 // 2^32
+
+template <class T>
+class _sna {
+ private:
+ T i;
+ uint64_t max() {
+ if (typeid(T) == typeid(uint64_t)) {
+ return MAX_32BITS;
+ } else if (typeid(T) == typeid(uint32_t)) {
+ return MAX_16BITS;
+ } else {
+ printf("Type:%s\n", typeid(T).name());
+ throw std::out_of_range("Invalid type");
+ }
+ }
+
+ public:
+ _sna(): i(0) {}
+ _sna(const _sna &t) {
+ i = t.i;
+ }
+ explicit _sna(const uint64_t &n) {
+ if ((n < 0) || (n > (max()-1)))
+ throw std::out_of_range("SNA assign with invalid value");
+ i = n;
+ }
+ _sna& operator=(const _sna &t) {
+ // check for self-assignment
+ if (&t == this)
+ return *this;
+ i = t.i;
+ return *this;
+ }
+ T v() const {
+ return i;
+ }
+ _sna& operator+=(const uint64_t& n) {
+ if ((n < 0) || (n > (max()/2 - 1)))
+ throw std::out_of_range("SNA received invalid addition value");
+ i = (i + n) % max();
+ return *this;
+ }
+ friend _sna operator+(_sna m, const uint64_t& n) {
+ m += n;
+ return m;
+ }
+ // prefix ++
+ _sna& operator++() {
+ *this += 1;
+ return *this;
+ }
+ // postfix ++
+ _sna operator++(int) {
+ _sna tmp(*this);
+ operator++();
+ return tmp;
+ }
+ bool operator==(const _sna& rhs) {
+ return i == rhs.i;
+ }
+ bool operator!=(const _sna& rhs) {
+ return i != rhs.i;
+ }
+ bool operator<(const _sna& rhs) {
+ return (i < rhs.i && rhs.i - i < max()/2) || \
+ (i > rhs.i && i - rhs.i > max()/2);
+ }
+ bool operator>=(const _sna& rhs) {
+ return !(*this < rhs);
+ }
+ bool operator>(const _sna& rhs) {
+ return (i < rhs.i && rhs.i - i > max()/2) || \
+ (i > rhs.i && i - rhs.i < max()/2);
+ }
+ bool operator<=(const _sna& rhs) {
+ return !(*this > rhs);
+ }
+ int32_t operator-(const _sna& rhs) {
+ if (*this >= rhs) {
+ if (i >= rhs.v()) {
+ return i - rhs.v();
+ } else {
+ return (i + max()) - rhs.v();
+ }
+ } else {
+ if (i < rhs.v()) {
+ return i - rhs.v();
+ } else {
+ return i - (rhs.v() + max());
+ }
+ }
+ }
+};
+
+typedef _sna<uint32_t> sna16_t;
+typedef _sna<uint64_t> sna32_t;
+
+#endif // BASE_SNA_H_
diff --git a/src/base/tests/sna_test.cc b/src/base/tests/sna_test.cc
new file mode 100644
index 000000000..4b7eb83e3
--- /dev/null
+++ b/src/base/tests/sna_test.cc
@@ -0,0 +1,117 @@
+/* -*- OpenSAF -*-
+ *
+ * Copyright Ericsson AB 2019 - All Rights Reserved.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed
+ * under the GNU Lesser General Public License Version 2.1, February 1999.
+ * The complete license can be accessed from the following location:
+ * http://opensource.org/licenses/lgpl-license.php
+ * See the Copying file included with the OpenSAF distribution for full
+ * licensing terms.
+ *
+ * Reference: Serial Number Arithmetic from RFC1982
+ *
+ */
+
+#include "base/sna.h"
+#include "gtest/gtest.h"
+
+template <class T>
+int test_sna(T x) {
+ int rc = 1;
+ printf("\n============= START with x=%lu =============\n", (uint64_t)x.v());
+ T y = x;
+ printf("x=%lu, y=%lu: check x == y++ is TRUE\n",
+ (uint64_t)x.v(), (uint64_t)y.v());
+ if (x == y++) {
+ printf("now y=%lu, reset y = x\n", (uint64_t)y.v());
+ y = x;
+ printf("x=%lu, y=%lu: check x != ++y is TRUE\n",
+ (uint64_t)x.v(), (uint64_t)y.v());
+ if (x != ++y) {
+ printf("now y=%lu, reset y = x\n", (uint64_t)y.v());
+ y = x;
+ printf("x=%lu, y=%lu: check x < ++y is TRUE\n",
+ (uint64_t)x.v(), (uint64_t)y.v());
+ if (x < ++y) {
+ printf("x=%lu: check x + 1 > x and x + 1 >= x is TRUE\n",
+ (uint64_t)x.v());
+ if ((x + 1 > x) && (x + 1 >= x)) {
+ printf("x=%lu: check x < x + 1 and x <= x + 1 is TRUE\n",
+ (uint64_t)x.v());
+ y = x + 1;
+ printf("y = x+1 => y=%lu\n", (uint64_t)y.v());
+ y = y + 1;
+ printf("y = y+1 => y=%lu\n", (uint64_t)y.v());
+ if ((x < x + 1) && (x <= x + 1)) {
+ try {
+ printf("x=%lu: add invalid (-1)\n", (uint64_t)x.v());
+ x = x + (-1);
+ } catch (const std::out_of_range& oor) {
+ printf("Expected error: %s\n", oor.what());
+ try {
+ uint64_t max_value = 0;
+ if (typeid(T) == typeid(sna16_t))
+ max_value = MAX_16BITS;
+ else if (typeid(T) == typeid(sna32_t))
+ max_value = MAX_32BITS;
+ printf("x=%lu: add invalid (%lu)\n",
+ (uint64_t)x.v(), max_value);
+ x = x + max_value;
+ } catch (const std::out_of_range& oor) {
+ printf("Expected error: %s\n", oor.what());
+ rc = 0;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ printf("================ END with x=%lu ==============\n", (uint64_t)x.v());
+ return rc;
+}
+
+
+class SnaTest : public ::testing::Test {
+ protected:
+ SnaTest() {}
+ virtual ~SnaTest() {
+ // Cleanup work that doesn't throw exceptions here.
+ }
+ virtual void SetUp() {
+ // Code here will be called immediately after the constructor (right
+ // before each test)
+ }
+ virtual void TearDown() {}
+};
+
+TEST_F(SnaTest, unit16_sna) {
+ sna16_t x;
+ EXPECT_EQ(0, test_sna(x));
+ sna16_t x1 = sna16_t(1);
+ sna16_t x2 = sna16_t(MAX_16BITS - 1);
+ EXPECT_EQ(2, x1 - x2);
+ EXPECT_EQ(-2, x2 - x1);
+ EXPECT_EQ(0, test_sna(x1));
+ EXPECT_EQ(0, test_sna(x2));
+}
+
+TEST_F(SnaTest, unit32_sna) {
+ sna32_t x;
+ EXPECT_EQ(0, test_sna(x));
+ sna32_t x1 = sna32_t(1);
+ sna32_t x2 = sna32_t(MAX_32BITS - 1);
+ EXPECT_EQ(2, x1 - x2);
+ EXPECT_EQ(-2, x2 - x1);
+ EXPECT_EQ(0, test_sna(x1));
+ EXPECT_EQ(0, test_sna(x2));
+}
+
+
+int main(int argc, char **argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/src/mds/mds_tipc_fctrl_portid.cc b/src/mds/mds_tipc_fctrl_portid.cc
index 1ce792dd8..f5dbf803e 100644
--- a/src/mds/mds_tipc_fctrl_portid.cc
+++ b/src/mds/mds_tipc_fctrl_portid.cc
@@ -67,12 +67,12 @@ DataMessage* MessageQueue::Find(uint32_t mseq, uint16_t
mfrag) {
return nullptr;
}
-uint64_t MessageQueue::Erase(Seq16 fseq_from, Seq16 fseq_to) {
+uint64_t MessageQueue::Erase(uint16_t chksize, sna16_t fseq_to) {
uint64_t msg_len = 0;
for (auto it = queue_.begin(); it != queue_.end();) {
DataMessage *m = *it;
- if (fseq_from <= Seq16(m->header_.fseq_) &&
- Seq16(m->header_.fseq_) <= fseq_to) {
+ if (sna16_t(m->header_.fseq_) + chksize > fseq_to &&
+ sna16_t(m->header_.fseq_) <= fseq_to) {
msg_len += m->header_.msg_len_;
it = queue_.erase(it);
delete m;
@@ -93,10 +93,10 @@ DataMessage* MessageQueue::FirstUnsent() {
return nullptr;
}
-void MessageQueue::MarkUnsentFrom(Seq16 fseq) {
+void MessageQueue::MarkUnsentFrom(sna16_t fseq) {
for (const auto& it : queue_) {
DataMessage *m = it;
- if (Seq16(m->header_.fseq_) >= fseq) m->is_sent_ = false;
+ if (sna16_t(m->header_.fseq_) >= fseq) m->is_sent_ = false;
}
}
@@ -259,7 +259,7 @@ uint32_t TipcPortId::ReceiveData(uint32_t mseq, uint16_t
mfrag,
txprob_cnt_, (uint8_t)state_);
}
// update receiver sequence window
- if (rcvwnd_.acked_ < Seq16(fseq) && rcvwnd_.rcv_ + Seq16(1) == Seq16(fseq)) {
+ if (rcvwnd_.acked_ < sna16_t(fseq) && rcvwnd_.rcv_ + 1 == sna16_t(fseq)) {
m_MDS_LOG_DBG("FCTRL: [me] <-- [node:%x, ref:%u], "
"RcvData[mseq:%u, mfrag:%u, fseq:%u], "
"rcvwnd[acked:%u, rcv:%u, nacked:%" PRIu64 "]",
@@ -268,12 +268,12 @@ uint32_t TipcPortId::ReceiveData(uint32_t mseq, uint16_t
mfrag,
rcvwnd_.acked_.v(), rcvwnd_.rcv_.v(), rcvwnd_.nacked_space_);
++rcvwnd_.rcv_;
- if (rcvwnd_.rcv_ - rcvwnd_.acked_ >= chunk_size_) {
+ if (rcvwnd_.rcv_ >= rcvwnd_.acked_ + chunk_size_) {
// send ack for @chunk_size_ msgs starting from fseq
SendChunkAck(fseq, svc_id, chunk_size_);
rcvwnd_.acked_ = rcvwnd_.rcv_;
rc = NCSCC_RC_CONTINUE;
- } else if (fseq == 1 && rcvwnd_.acked_ == 0) {
+ } else if (fseq == 1 && rcvwnd_.acked_ == sna16_t(0)) {
// send ack right away for the very first data message
// to stop txprob timer at sender
SendChunkAck(fseq, svc_id, 1);
@@ -290,8 +290,8 @@ uint32_t TipcPortId::ReceiveData(uint32_t mseq, uint16_t
mfrag,
// It is not used for now, so ignore it.
// check for transmission error
- if (rcvwnd_.rcv_ + Seq16(1) < Seq16(fseq)) {
- if (rcvwnd_.rcv_ == 0 && rcvwnd_.acked_ == 0) {
+ if (rcvwnd_.rcv_ + 1 < sna16_t(fseq)) {
+ if (rcvwnd_.rcv_ == sna16_t(0) && rcvwnd_.acked_ == sna16_t(0)) {
// peer does not realize that this portid reset
m_MDS_LOG_ERR("FCTRL: [me] <-- [node:%x, ref:%u], "
"RcvData[mseq:%u, mfrag:%u, fseq:%u], "
@@ -301,7 +301,7 @@ uint32_t TipcPortId::ReceiveData(uint32_t mseq, uint16_t
mfrag,
mseq, mfrag, fseq,
rcvwnd_.acked_.v(), rcvwnd_.rcv_.v(), rcvwnd_.nacked_space_);
- rcvwnd_.rcv_ = fseq;
+ rcvwnd_.rcv_ = sna16_t(fseq);
} else {
rc = NCSCC_RC_FAILURE;
// msg loss
@@ -314,7 +314,7 @@ uint32_t TipcPortId::ReceiveData(uint32_t mseq, uint16_t
mfrag,
rcvwnd_.acked_.v(), rcvwnd_.rcv_.v(), rcvwnd_.nacked_space_);
}
}
- if (Seq16(fseq) <= rcvwnd_.acked_) {
+ if (sna16_t(fseq) <= rcvwnd_.acked_) {
rc = NCSCC_RC_FAILURE;
// unexpected retransmission
m_MDS_LOG_ERR("FCTRL: [me] <-- [node:%x, ref:%u], "
@@ -349,7 +349,7 @@ void TipcPortId::ReceiveChunkAck(uint16_t fseq, uint16_t
chksize) {
txprob_cnt_, (uint8_t)state_);
}
// update sender sequence window
- if (sndwnd_.acked_ < Seq16(fseq) && Seq16(fseq) < sndwnd_.send_) {
+ if (sndwnd_.acked_ < sna16_t(fseq) && sna16_t(fseq) < sndwnd_.send_) {
m_MDS_LOG_DBG("FCTRL: [me] <-- [node:%x, ref:%u], "
"RcvChkAck[fseq:%u, chunk:%u], "
"sndwnd[acked:%u, send:%u, nacked:%" PRIu64 "], "
@@ -360,12 +360,11 @@ void TipcPortId::ReceiveChunkAck(uint16_t fseq, uint16_t
chksize) {
sndqueue_.Size());
// fast forward the sndwnd_.acked_ sequence to fseq
- sndwnd_.acked_ = fseq;
+ sndwnd_.acked_ = sna16_t(fseq);
// remove a number @chksize messages out of sndqueue_ and decrease
// the nacked_space_ of sender
- uint64_t acked_bytes = sndqueue_.Erase(Seq16(fseq) - (chksize-1),
- Seq16(fseq));
+ uint64_t acked_bytes = sndqueue_.Erase(chksize, sna16_t(fseq));
sndwnd_.nacked_space_ -= acked_bytes;
// try to send a few pending msg
@@ -429,14 +428,14 @@ void TipcPortId::ReceiveNack(uint32_t mseq, uint16_t
mfrag,
"RcvNack, ignore[fseq:%u, state:%u]",
id_.node, id_.ref,
fseq, (uint8_t)state_);
- sndqueue_.MarkUnsentFrom(Seq16(fseq));
+ sndqueue_.MarkUnsentFrom(sna16_t(fseq));
return;
}
if (state_ != State::kRcvBuffOverflow) {
state_ = State::kRcvBuffOverflow;
m_MDS_LOG_NOTIFY("FCTRL: [node:%x, ref:%u] --> Overflow ",
id_.node, id_.ref);
- sndqueue_.MarkUnsentFrom(Seq16(fseq));
+ sndqueue_.MarkUnsentFrom(sna16_t(fseq));
}
DataMessage* msg = sndqueue_.Find(mseq, mfrag);
if (msg != nullptr) {
@@ -462,8 +461,8 @@ void TipcPortId::ReceiveNack(uint32_t mseq, uint16_t mfrag,
bool TipcPortId::ReceiveTmrTxProb(uint8_t max_txprob) {
bool restart_txprob = false;
if (state_ == State::kDisabled ||
- sndwnd_.acked_ > Seq16(1) ||
- rcvwnd_.rcv_ > Seq16(1)) return restart_txprob;
+ sndwnd_.acked_ > sna16_t(1) ||
+ rcvwnd_.rcv_ > sna16_t(1)) return restart_txprob;
if (state_ == State::kTxProb || state_ == State::kRcvBuffOverflow) {
txprob_cnt_++;
if (txprob_cnt_ >= max_txprob) {
diff --git a/src/mds/mds_tipc_fctrl_portid.h b/src/mds/mds_tipc_fctrl_portid.h
index cf2daaa31..8b22f1dee 100644
--- a/src/mds/mds_tipc_fctrl_portid.h
+++ b/src/mds/mds_tipc_fctrl_portid.h
@@ -24,82 +24,20 @@
#include <stdio.h>
#include <unistd.h>
#include <deque>
+#include "base/sna.h"
#include "mds/mds_tipc_fctrl_msg.h"
namespace mds {
-class Seq16 {
- public:
-#define SEQ16_MAX 65536
-#define SEQ16_SPACE 32768
- uint16_t value_;
- explicit Seq16(uint16_t v) {
- value_ = uint16_t((uint32_t)v % SEQ16_MAX);
- }
- uint16_t v() {
- return value_;
- }
- Seq16 operator + (const Seq16 add) const {
- return Seq16(((uint32_t)value_ + (uint32_t)add.value_) % SEQ16_MAX);
- }
-
- int16_t operator - (const Seq16 sub) const {
- if (value_ < sub.value_ && (sub.value_ - value_ < SEQ16_SPACE)) {
- return value_ - sub.value_;
- }
- if (value_ > sub.value_ && (value_ - sub.value_ > SEQ16_SPACE)) {
- return (int32_t)value_ + SEQ16_MAX - (int32_t)sub.value_;
- }
- if (value_ < sub.value_ && (sub.value_ - value_ > SEQ16_SPACE)) {
- return (int32_t)value_ + SEQ16_MAX - (int32_t)sub.value_;
- }
- if (value_ > sub.value_ && (value_ - sub.value_ < SEQ16_SPACE)) {
- return value_ - sub.value_;
- }
- return 0;
- }
- Seq16 operator - (const uint16_t sub) const {
- return Seq16(((uint32_t)value_ + 65536 - sub) % SEQ16_MAX);
- }
- void operator ++() {
- value_ = (value_ + 1) % SEQ16_MAX;
- }
- void operator = (const uint16_t v) {
- value_ = v % SEQ16_MAX;
- }
- bool operator == (const Seq16& seq) const {
- return value_ == seq.value_;
- }
- bool operator == (uint16_t val) const {
- return value_ == val;
- }
- bool operator <= (const Seq16& seq) {
- return *this == seq || *this < seq;
- }
- bool operator < (const Seq16& seq) {
- if (value_ < seq.value_ && (seq.value_ - value_ < SEQ16_SPACE)) return
true;
- if (value_ > seq.value_ && (value_ - seq.value_ > SEQ16_SPACE)) return
true;
- return false;
- }
- bool operator > (const Seq16& seq) {
- if (value_ < seq.value_ && (seq.value_ - value_ > SEQ16_SPACE)) return
true;
- if (value_ > seq.value_ && (value_ - seq.value_ < SEQ16_SPACE)) return
true;
- return false;
- }
- bool operator >= (const Seq16& seq) {
- return *this == seq || *this > seq;
- }
-};
-
class MessageQueue {
public:
void Queue(DataMessage* msg);
DataMessage* Find(uint32_t mseq, uint16_t mfrag);
- uint64_t Erase(Seq16 fseq_from, Seq16 fseq_to);
+ uint64_t Erase(uint16_t chksize, sna16_t fseq_to);
uint64_t Size() const { return queue_.size(); }
void Clear();
DataMessage* FirstUnsent();
- void MarkUnsentFrom(Seq16 fseq);
+ void MarkUnsentFrom(sna16_t fseq);
private:
std::deque<DataMessage*> queue_;
};
@@ -155,16 +93,16 @@ class TipcPortId {
struct sndwnd {
// sender sequence window
- Seq16 acked_{0}; // last sequence has been acked by receiver
- Seq16 send_{1}; // next sequence to be sent
+ sna16_t acked_{0}; // last sequence has been acked by receiver
+ sna16_t send_{1}; // next sequence to be sent
uint64_t nacked_space_{0}; // total bytes are sent but not acked
};
struct sndwnd sndwnd_;
struct rcvwnd {
// receiver sequence window
- Seq16 acked_{0}; // last sequence has been acked to sender
- Seq16 rcv_{0}; // last sequence has been received
+ sna16_t acked_{0}; // last sequence has been acked to sender
+ sna16_t rcv_{0}; // last sequence has been received
uint64_t nacked_space_{0}; // total bytes has not been acked
};
struct rcvwnd rcvwnd_;
--
2.17.1
_______________________________________________
Opensaf-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/opensaf-devel