Skip to content

Commit

Permalink
[vrf orchagent]: Add Request parser class and VRF orchagent based on …
Browse files Browse the repository at this point in the history
…it (sonic-net#424)

* First commit

* Compiles

* Use KeyOpFieldsValuesTuple instead of SyncMap

* Add tests and fixed bugs

* Put gtest library path

* Add Clean

* Throw errors in case of errors

* Rename methods to lowerCase. Use better names

* Fixed issues with untested last commit

* Use set instead of vector for attribute names

* Implemented vrf orch

* Fix an issue. configuration description must be outside of the class where it using, otherwise it would uninitialized

* Add initial version of test_vrf

* Support 'empty' attribute which is used as fake attribute for empty hash

* Add comprehensive tests for vrf orchagent

* Fix typo. Add extra comments.

* Add SET-update functionality

* Remove outdated macros. Use more appropriate function in the test

* Extract Orch2 class which support addOperation and delOperation

* Fix two FIXME from tests

* Check parser constructors in the test

* Move Orch2 to orch.h

* Fix compilation of cfgmgr
  • Loading branch information
pavel-shirshov authored Jan 17, 2018
1 parent 88636f9 commit 6634744
Show file tree
Hide file tree
Showing 14 changed files with 1,717 additions and 10 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ debian/tmp/
aclocal.m4
config.h
config.h.in
config.h.in~
config.log
config.status
configure
Expand Down Expand Up @@ -52,5 +53,5 @@ orchagent/orchagent
orchagent/routeresync
swssconfig/swssconfig
swssconfig/swssplayer

tests/tests

6 changes: 3 additions & 3 deletions cfgmgr/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ else
DBGFLAGS = -g
endif

vlanmgrd_SOURCES = vlanmgrd.cpp vlanmgr.cpp $(top_srcdir)/orchagent/orch.cpp shellcmd.h
vlanmgrd_SOURCES = vlanmgrd.cpp vlanmgr.cpp $(top_srcdir)/orchagent/orch.cpp $(top_srcdir)/orchagent/request_parser.cpp shellcmd.h
vlanmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI)
vlanmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI)
vlanmgrd_LDADD = -lswsscommon

intfmgrd_SOURCES = intfmgrd.cpp intfmgr.cpp $(top_srcdir)/orchagent/orch.cpp shellcmd.h
intfmgrd_SOURCES = intfmgrd.cpp intfmgr.cpp $(top_srcdir)/orchagent/orch.cpp $(top_srcdir)/orchagent/request_parser.cpp shellcmd.h
intfmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI)
intfmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI)
intfmgrd_LDADD = -lswsscommon
intfmgrd_LDADD = -lswsscommon
10 changes: 7 additions & 3 deletions orchagent/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,11 @@ orchagent_SOURCES = \
fdborch.cpp \
aclorch.cpp \
saihelper.cpp \
switchorch.cpp \
switchorch.cpp \
pfcwdorch.cpp \
pfcactionhandler.cpp \
request_parser.cpp \
vrforch.cpp \
acltable.h \
aclorch.h \
bufferorch.h \
Expand All @@ -56,9 +58,11 @@ orchagent_SOURCES = \
qosorch.h \
routeorch.h \
saihelper.h \
switchorch.h \
switchorch.h \
swssnet.h \
tunneldecaporch.h
tunneldecaporch.h \
request_parser.h \
vrforch.h

orchagent_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI)
orchagent_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI)
Expand Down
56 changes: 56 additions & 0 deletions orchagent/orch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -374,3 +374,59 @@ void Orch::addExecutor(string executorName, Executor* executor)
std::forward_as_tuple(executorName),
std::forward_as_tuple(executor));
}

void Orch2::doTask(Consumer &consumer)
{
SWSS_LOG_ENTER();

auto it = consumer.m_toSync.begin();
while (it != consumer.m_toSync.end())
{
bool erase_from_queue = true;
try
{
request_.parse(it->second);

auto op = request_.getOperation();
if (op == SET_COMMAND)
{
erase_from_queue = addOperation(request_);
}
else if (op == DEL_COMMAND)
{
erase_from_queue = delOperation(request_);
}
else
{
SWSS_LOG_ERROR("Wrong operation. Check RequestParser: %s", op.c_str());
}
}
catch (const std::invalid_argument& e)
{
SWSS_LOG_ERROR("Parse error: %s", e.what());
}
catch (const std::logic_error& e)
{
SWSS_LOG_ERROR("Logic error: %s", e.what());
}
catch (const std::exception& e)
{
SWSS_LOG_ERROR("Exception was catched in the request parser: %s", e.what());
}
catch (...)
{
SWSS_LOG_ERROR("Unknown exception was catched in the request parser");
}
request_.clear();

if (erase_from_queue)
{
it = consumer.m_toSync.erase(it);
}
else
{
++it;
}
}
}

23 changes: 23 additions & 0 deletions orchagent/orch.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#ifndef SWSS_ORCH_H
#define SWSS_ORCH_H

#include <unordered_map>
#include <unordered_set>
#include <map>
#include <memory>

Expand All @@ -15,6 +17,7 @@ extern "C" {
#include "consumerstatetable.h"
#include "notificationconsumer.h"
#include "selectabletimer.h"
#include "macaddress.h"

using namespace std;
using namespace swss;
Expand Down Expand Up @@ -163,4 +166,24 @@ class Orch
void addConsumer(DBConnector *db, string tableName);
};

#include "request_parser.h"

class Orch2 : public Orch
{
public:
Orch2(DBConnector *db, const std::string& tableName, Request& request)
: Orch(db, tableName), request_(request)
{
}

protected:
virtual void doTask(Consumer& consumer);

virtual bool addOperation(const Request& request)=0;
virtual bool delOperation(const Request& request)=0;

private:
Request& request_;
};

#endif /* SWSS_ORCH_H */
3 changes: 2 additions & 1 deletion orchagent/orchdaemon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,14 +91,15 @@ bool OrchDaemon::init()
TableConnector appDbMirrorSession(m_applDb, APP_MIRROR_SESSION_TABLE_NAME);
TableConnector confDbMirrorSession(m_configDb, CFG_MIRROR_SESSION_TABLE_NAME);
MirrorOrch *mirror_orch = new MirrorOrch(appDbMirrorSession, confDbMirrorSession, gPortsOrch, route_orch, neigh_orch, gFdbOrch);
VRFOrch *vrf_orch = new VRFOrch(m_configDb, CFG_VRF_TABLE_NAME);

vector<string> acl_tables = {
CFG_ACL_TABLE_NAME,
CFG_ACL_RULE_TABLE_NAME
};
gAclOrch = new AclOrch(m_configDb, acl_tables, gPortsOrch, mirror_orch, neigh_orch, route_orch);

m_orchList = { switch_orch, gPortsOrch, intfs_orch, neigh_orch, route_orch, copp_orch, tunnel_decap_orch, qos_orch, buffer_orch, mirror_orch, gAclOrch, gFdbOrch};
m_orchList = { switch_orch, gPortsOrch, intfs_orch, neigh_orch, route_orch, copp_orch, tunnel_decap_orch, qos_orch, buffer_orch, mirror_orch, gAclOrch, gFdbOrch, vrf_orch };
m_select = new Select();

vector<string> pfc_wd_tables = {
Expand Down
1 change: 1 addition & 0 deletions orchagent/orchdaemon.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "aclorch.h"
#include "pfcwdorch.h"
#include "switchorch.h"
#include "vrforch.h"

using namespace swss;

Expand Down
201 changes: 201 additions & 0 deletions orchagent/request_parser.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
#include <net/ethernet.h>
#include <cassert>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <exception>

#include "sai.h"
#include "macaddress.h"
#include "orch.h"
#include "request_parser.h"


void Request::parse(const KeyOpFieldsValuesTuple& request)
{
if (is_parsed_)
{
throw std::logic_error("The parser already has a parsed request");
}

parseOperation(request);
parseKey(request);
parseAttrs(request);

is_parsed_ = true;
}

void Request::clear()
{
operation_.clear();
full_key_.clear();
attr_names_.clear();
key_item_strings_.clear();
key_item_mac_addresses_.clear();
attr_item_strings_.clear();
attr_item_bools_.clear();
attr_item_mac_addresses_.clear();
attr_item_packet_actions_.clear();

is_parsed_ = false;
}

void Request::parseOperation(const KeyOpFieldsValuesTuple& request)
{
operation_ = kfvOp(request);
if (operation_ != SET_COMMAND && operation_ != DEL_COMMAND)
{
throw std::invalid_argument(std::string("Wrong operation: ") + operation_);
}
}

void Request::parseKey(const KeyOpFieldsValuesTuple& request)
{
full_key_ = kfvKey(request);

// split the key by separator
std::vector<std::string> key_items;
size_t f_position = 0;
size_t e_position = full_key_.find(key_separator_);
while (e_position != std::string::npos)
{
key_items.push_back(full_key_.substr(f_position, e_position - f_position));
f_position = e_position + 1;
e_position = full_key_.find(key_separator_, f_position);
}
key_items.push_back(full_key_.substr(f_position, full_key_.length()));

if (key_items.size() != number_of_key_items_)
{
throw std::invalid_argument(std::string("Wrong number of key items. Expected ")
+ std::to_string(number_of_key_items_)
+ std::string(" item(s). Key: '")
+ full_key_
+ std::string("'"));
}

// check types of the key items
for (int i = 0; i < static_cast<int>(number_of_key_items_); i++)
{
switch(request_description_.key_item_types[i])
{
case REQ_T_STRING:
key_item_strings_[i] = key_items[i];
break;
case REQ_T_MAC_ADDRESS:
key_item_mac_addresses_[i] = parseMacAddress(key_items[i]);
break;
default:
throw std::logic_error(std::string("Not implemented key type parser. Key '")
+ full_key_
+ std::string("'. Key item:")
+ key_items[i]);
}
}
}

void Request::parseAttrs(const KeyOpFieldsValuesTuple& request)
{
const auto not_found = std::end(request_description_.attr_item_types);

for (auto i = kfvFieldsValues(request).begin();
i != kfvFieldsValues(request).end(); i++)
{
if (fvField(*i) == "empty")
{
// if name of the attribute is 'empty', just skip it.
// it's used when we don't have any attributes, but we have to provide one for redis
continue;
}
const auto item = request_description_.attr_item_types.find(fvField(*i));
if (item == not_found)
{
throw std::invalid_argument(std::string("Unknown attribute name: ") + fvField(*i));
}
attr_names_.insert(fvField(*i));
switch(item->second)
{
case REQ_T_STRING:
attr_item_strings_[fvField(*i)] = fvValue(*i);
break;
case REQ_T_BOOL:
attr_item_bools_[fvField(*i)] = parseBool(fvValue(*i));
break;
case REQ_T_MAC_ADDRESS:
attr_item_mac_addresses_[fvField(*i)] = parseMacAddress(fvValue(*i));
break;
case REQ_T_PACKET_ACTION:
attr_item_packet_actions_[fvField(*i)] = parsePacketAction(fvValue(*i));
break;
default:
throw std::logic_error(std::string("Not implemented attribute type parser for attribute:") + fvField(*i));
}
}

if (operation_ == DEL_COMMAND && attr_names_.size() > 0)
{
throw std::invalid_argument("Delete operation request contains attributes");
}

if (operation_ == SET_COMMAND)
{
for (const auto& attr: request_description_.mandatory_attr_items)
{
if (attr_names_.find(attr) == std::end(attr_names_))
{
throw std::invalid_argument(std::string("Mandatory attribute '") + attr + std::string("' not found"));
}
}
}
}

bool Request::parseBool(const std::string& str)
{
if (str == "true")
{
return true;
}

if (str == "false")
{
return false;
}

throw std::invalid_argument(std::string("Can't parse boolean value '") + str + std::string("'"));
}

MacAddress Request::parseMacAddress(const std::string& str)
{
uint8_t mac[ETHER_ADDR_LEN];

if (!MacAddress::parseMacString(str, mac))
{
throw std::invalid_argument(std::string("Invalid mac address: ") + str);
}

return MacAddress(mac);
}

sai_packet_action_t Request::parsePacketAction(const std::string& str)
{
std::unordered_map<std::string, sai_packet_action_t> m = {
{"drop", SAI_PACKET_ACTION_DROP},
{"forward", SAI_PACKET_ACTION_FORWARD},
{"copy", SAI_PACKET_ACTION_COPY},
{"copy_cancel", SAI_PACKET_ACTION_COPY_CANCEL},
{"trap", SAI_PACKET_ACTION_TRAP},
{"log", SAI_PACKET_ACTION_LOG},
{"deny", SAI_PACKET_ACTION_DENY},
{"transit", SAI_PACKET_ACTION_TRANSIT},
};

const auto found = m.find(str);
if (found == std::end(m))
{
throw std::invalid_argument(std::string("Wrong packet action attribute value '") + str + std::string("'"));
}

return found->second;
}
Loading

0 comments on commit 6634744

Please sign in to comment.