- Adapt MDS with this SNA implementation. --- src/base/Makefile.am | 6 +- src/base/sna.h | 138 +++++++++++++++++++++++++++++++ src/base/tests/sna_test.cc | 121 +++++++++++++++++++++++++++ src/mds/mds_tipc_fctrl_intf.cc | 2 +- src/mds/mds_tipc_fctrl_portid.cc | 19 ++--- src/mds/mds_tipc_fctrl_portid.h | 64 +------------- 6 files changed, 274 insertions(+), 76 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..4331e6119 --- /dev/null +++ b/src/base/sna.h @@ -0,0 +1,138 @@ +/* -*- OpenSAF -*- + * + * Copyright Ericsson AB 2020 - 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 <cassert> +#include <typeinfo> +#include <stdexcept> + +#define SNA16_MAX (1UL << 16) +#define SNA16_SPACE (SNA16_MAX/2) +#define SNA32_MAX (1ULL << 32) +#define SNA32_SPACE (SNA32_MAX/2) + +template <class T> +class SerialNumber { + public: + SerialNumber(): value_(0) {} + SerialNumber(const SerialNumber &t) { + value_ = t.value_; + } + explicit SerialNumber(const uint64_t &n) { + if ((n < 0) || (n > (max()-1))) + assert(0 && "Invalid initial value"); + value_ = n; + } + SerialNumber& operator=(const SerialNumber &t) { + // check for self-assignment + if (&t == this) + return *this; + value_ = t.value_; + return *this; + } + T v() const { + return value_; + } + SerialNumber& operator+=(const uint64_t& n) { + if ((n < 0) || (n > (space() - 1))) + throw std::out_of_range("Invalid addition value"); + value_ = (value_ + n) % max(); + return *this; + } + friend SerialNumber operator+(SerialNumber m, const uint64_t& n) { + m += n; + return m; + } + // prefix ++ + SerialNumber& operator++() { + *this += 1; + return *this; + } + // postfix ++ + SerialNumber operator++(int) { + SerialNumber tmp(*this); + operator++(); + return tmp; + } + bool operator==(const SerialNumber& rhs) { + return value_ == rhs.value_; + } + bool operator==(const uint32_t val) { + return value_ == val; + } + bool operator!=(const SerialNumber& rhs) { + return value_ != rhs.value_; + } + bool operator<(const SerialNumber& rhs) { + return (value_ < rhs.value_ && rhs.value_ - value_ < space()) || \ + (value_ > rhs.value_ && value_ - rhs.value_ > space()); + } + bool operator<=(const SerialNumber& rhs) { + return *this == rhs || *this < rhs; + } + bool operator>(const SerialNumber& rhs) { + return (value_ < rhs.value_ && rhs.value_ - value_ > space()) || \ + (value_ > rhs.value_ && value_ - rhs.value_ < space()); + } + bool operator>=(const SerialNumber& rhs) { + return *this == rhs || *this > rhs; + } + int64_t operator-(const SerialNumber& rhs) { + if (*this >= rhs) { + if (value_ >= rhs.value_) { + return value_ - rhs.value_; + } else { + return (value_ + max()) - rhs.value_; + } + } else { + if (value_ < rhs.value_) { + return value_ - rhs.value_; + } else { + return value_ - (rhs.value_ + max()); + } + } + } + private: + T value_; + uint64_t max() { + if (typeid(T) == typeid(uint64_t)) { + return SNA32_MAX; + } + if (typeid(T) == typeid(uint32_t)) { + return SNA16_MAX; + } + assert(0 && "Invalid data type"); + return 0; + } + uint64_t space() { + if (typeid(T) == typeid(uint64_t)) { + return SNA32_SPACE; + } + if (typeid(T) == typeid(uint32_t)) { + return SNA16_SPACE; + } + assert(0 && "Invalid data type"); + return 0; + } +}; + +using Seq16 = SerialNumber<uint32_t>; +using Seq32 = SerialNumber<uint64_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..6c9d3a1e7 --- /dev/null +++ b/src/base/tests/sna_test.cc @@ -0,0 +1,121 @@ +/* -*- 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" + +#ifndef DEBUG_SNA +#define printf(x, args...) // No printf +#endif + +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(Seq16)) + max_value = SNA16_MAX; + else if (typeid(T) == typeid(Seq32)) + max_value = SNA32_MAX; + 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) { + Seq16 x; + EXPECT_EQ(0, test_sna(x)); + Seq16 x1 = Seq16(1); + Seq16 x2 = Seq16(SNA16_MAX - 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) { + Seq32 x; + EXPECT_EQ(0, test_sna(x)); + Seq32 x1 = Seq32(1); + Seq32 x2 = Seq32(SNA32_MAX - 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 f3504b901..6ce00782e 100644 --- a/src/mds/mds_tipc_fctrl_intf.cc +++ b/src/mds/mds_tipc_fctrl_intf.cc @@ -106,7 +106,7 @@ void process_timer_event(const Event& evt) { static_cast<int>(evt.type_)); 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 57843b6de..41fce3df8 100644 --- a/src/mds/mds_tipc_fctrl_portid.cc +++ b/src/mds/mds_tipc_fctrl_portid.cc @@ -339,7 +339,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_ < Seq16(fseq) && rcvwnd_.rcv_ + 1 == Seq16(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 "]", @@ -370,7 +370,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 < Seq16(fseq)) { if (rcvwnd_.rcv_ == 0 && rcvwnd_.acked_ == 0) { // peer does not realize that this portid reset m_MDS_LOG_NOTIFY("FCTRL: [me] <-- [node:%x, ref:%u], " @@ -382,7 +382,7 @@ uint32_t TipcPortId::ReceiveData(uint32_t mseq, uint16_t mfrag, rcvwnd_.acked_.v(), rcvwnd_.rcv_.v(), rcvwnd_.nacked_space_); SendChunkAck(fseq, svc_id, 1); - rcvwnd_.rcv_ = fseq; + rcvwnd_.rcv_ = Seq16(fseq); rcvwnd_.acked_ = rcvwnd_.rcv_; } else { rc = NCSCC_RC_FAILURE; @@ -395,7 +395,7 @@ 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 (fseq == 1) { // sender realize me as portid reset @@ -408,7 +408,7 @@ uint32_t TipcPortId::ReceiveData(uint32_t mseq, uint16_t mfrag, rcvwnd_.acked_.v(), rcvwnd_.rcv_.v(), rcvwnd_.nacked_space_); SendChunkAck(fseq, svc_id, 1); - rcvwnd_.rcv_ = fseq; + rcvwnd_.rcv_ = Seq16(fseq); rcvwnd_.acked_ = rcvwnd_.rcv_; } else if (Seq16(fseq) <= rcvwnd_.rcv_) { rc = NCSCC_RC_FAILURE; @@ -471,13 +471,12 @@ void TipcPortId::ReceiveChunkAck(uint16_t fseq, uint16_t chksize) { sndwnd_.acked_.v(), sndwnd_.send_.v(), sndwnd_.nacked_space_, sndqueue_.Size()); - // fast forward the sndwnd_.acked_ sequence to fseq - sndwnd_.acked_ = 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(sndwnd_.acked_ + 1, Seq16(fseq)); + // fast forward the sndwnd_.acked_ sequence to fseq + sndwnd_.acked_ = Seq16(fseq); + assert(sndwnd_.nacked_space_ >= acked_bytes); sndwnd_.nacked_space_ -= acked_bytes; diff --git a/src/mds/mds_tipc_fctrl_portid.h b/src/mds/mds_tipc_fctrl_portid.h index ef74921e7..83564459b 100644 --- a/src/mds/mds_tipc_fctrl_portid.h +++ b/src/mds/mds_tipc_fctrl_portid.h @@ -24,73 +24,11 @@ #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); -- 2.17.1 _______________________________________________ Opensaf-devel mailing list Opensaf-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/opensaf-devel