- Adapt MDS with this SNA implementation. --- src/base/Makefile.am | 6 +- src/base/sna.h | 126 +++++++++++++++++++++++++++++++ src/base/tests/sna_test.cc | 117 ++++++++++++++++++++++++++++ src/mds/mds_tipc_fctrl_intf.cc | 3 +- src/mds/mds_tipc_fctrl_portid.cc | 45 ++++++----- src/mds/mds_tipc_fctrl_portid.h | 79 +++---------------- 6 files changed, 280 insertions(+), 96 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..b231fb134 --- /dev/null +++ b/src/base/sna.h @@ -0,0 +1,126 @@ +/* -*- 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 uint32_t val) { + return i == val; + } + 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); + } + int64_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_intf.cc b/src/mds/mds_tipc_fctrl_intf.cc index fe3dbd597..dbf9d8e4a 100644 --- a/src/mds/mds_tipc_fctrl_intf.cc +++ b/src/mds/mds_tipc_fctrl_intf.cc @@ -104,7 +104,8 @@ void process_timer_event(const Event& evt) { bool txprob_restart = false; for (auto i : portid_map) { TipcPortId* portid = i.second; - + if (!portid) + continue; if (evt.type_ == Event::Type::kEvtTmrTxProb) { if (portid->ReceiveTmrTxProb(kTxProbMaxRetries) == true) { txprob_restart = true; diff --git a/src/mds/mds_tipc_fctrl_portid.cc b/src/mds/mds_tipc_fctrl_portid.cc index 3704baddb..9fc9a50a5 100644 --- a/src/mds/mds_tipc_fctrl_portid.cc +++ b/src/mds/mds_tipc_fctrl_portid.cc @@ -57,22 +57,22 @@ void MessageQueue::Queue(DataMessage* msg) { queue_.push_back(msg); } -DataMessage* MessageQueue::Find(Seq16 fseq) { +DataMessage* MessageQueue::Find(sna16_t fseq) { for (const auto& it : queue_) { DataMessage *m = it; - if (Seq16(m->header_.fseq_) == fseq) { + if (sna16_t(m->header_.fseq_) == fseq) { return m; } } 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; } } @@ -315,7 +315,7 @@ uint32_t TipcPortId::ReceiveData(uint32_t mseq, uint16_t mfrag, } // 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 "]", @@ -346,7 +346,7 @@ 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_ + 1 < sna16_t(fseq)) { if (rcvwnd_.rcv_ == 0 && rcvwnd_.acked_ == 0) { // peer does not realize that this portid reset m_MDS_LOG_ERR("FCTRL: [me] <-- [node:%x, ref:%u], " @@ -357,7 +357,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 @@ -369,9 +369,9 @@ uint32_t TipcPortId::ReceiveData(uint32_t mseq, uint16_t mfrag, mseq, mfrag, fseq, rcvwnd_.acked_.v(), rcvwnd_.rcv_.v(), rcvwnd_.nacked_space_); // send nack - SendNack((rcvwnd_.rcv_ + Seq16(1)).v(), svc_id); + SendNack((rcvwnd_.rcv_ + 1).v(), svc_id); } - } else if (Seq16(fseq) <= rcvwnd_.rcv_) { + } else if (sna16_t(fseq) <= rcvwnd_.rcv_) { rc = NCSCC_RC_FAILURE; // unexpected retransmission m_MDS_LOG_ERR("FCTRL: [me] <-- [node:%x, ref:%u], " @@ -406,7 +406,7 @@ void TipcPortId::ReceiveChunkAck(uint16_t fseq, uint16_t chksize) { txprob_cnt_, (uint8_t)state_); } // update sender sequence window - if (sndwnd_.acked_ < Seq16(fseq)) { + if (sndwnd_.acked_ < sna16_t(fseq)) { // The fseq_ should always be less then sndwnd_.send_, hence // mds should check the sender being capable of sending more // message only if D = sndwnd_.send_ - sndwnd_.acked_ < 2^15 - 1 = 32767 @@ -416,7 +416,7 @@ void TipcPortId::ReceiveChunkAck(uint16_t fseq, uint16_t chksize) { // For now mds logs a warning and let the transmission continue // (mds could be changed to return try again if it is not a backward // compatibility problem to a specific client). - if (Seq16(fseq) >= sndwnd_.send_) { + if (sna16_t(fseq) >= sndwnd_.send_) { m_MDS_LOG_ERR("FCTRL: [me] <-- [node:%x, ref:%u], " "RcvChkAck[fseq:%u, chunk:%u], " "sndwnd[acked:%u, send:%u, nacked:%" PRIu64 "], " @@ -438,12 +438,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 @@ -503,8 +502,8 @@ void TipcPortId::ReceiveNack(uint32_t mseq, uint16_t mfrag, return; } if (state_ == State::kRcvBuffOverflow) { - sndqueue_.MarkUnsentFrom(Seq16(fseq)); - if (Seq16(fseq) - sndwnd_.acked_ > 1) { + sndqueue_.MarkUnsentFrom(sna16_t(fseq)); + if (sna16_t(fseq) - sndwnd_.acked_ > 1) { m_MDS_LOG_ERR("FCTRL: [me] <-- [node:%x, ref:%u], " "RcvNack[fseq:%u], " "sndwnd[acked:%u, send:%u, nacked:%" PRIu64 "], " @@ -520,9 +519,9 @@ void TipcPortId::ReceiveNack(uint32_t mseq, uint16_t mfrag, 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(Seq16(fseq)); + DataMessage* msg = sndqueue_.Find(sna16_t(fseq)); if (msg != nullptr) { // Resend the msg found if (Send(msg->msg_data_, msg->header_.msg_len_) == NCSCC_RC_SUCCESS) { @@ -546,8 +545,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 24fb195d2..7f48327f2 100644 --- a/src/mds/mds_tipc_fctrl_portid.h +++ b/src/mds/mds_tipc_fctrl_portid.h @@ -24,82 +24,21 @@ #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(Seq16 fseq); - uint64_t Erase(Seq16 fseq_from, Seq16 fseq_to); + + DataMessage* Find(sna16_t fseq); + 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_; }; @@ -159,16 +98,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 Opensaf-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/opensaf-devel