Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Buffer.orch #27

Closed
wants to merge 12 commits into from
2 changes: 1 addition & 1 deletion orchagent/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ else
DBGFLAGS = -g
endif

orchagent_SOURCES = main.cpp orchdaemon.cpp orch.cpp routeorch.cpp neighorch.cpp intfsorch.cpp portsorch.cpp
orchagent_SOURCES = main.cpp orchdaemon.cpp orch.cpp routeorch.cpp neighorch.cpp intfsorch.cpp portsorch.cpp qosorch.cpp bufferorch.cpp

orchagent_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI)
orchagent_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI)
Expand Down
629 changes: 629 additions & 0 deletions orchagent/bufferorch.cpp

Large diffs are not rendered by default.

50 changes: 50 additions & 0 deletions orchagent/bufferorch.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#ifndef SWSS_BUFFORCH_H
#define SWSS_BUFFORCH_H

#include <map>
#include "orch.h"
#include "portsorch.h"

const std::string buffer_size_field_name = "size";
const std::string buffer_pool_type_field_name = "type";
const std::string buffer_pool_mode_field_name = "mode";
const std::string buffer_pool_field_name = "pool";
const std::string buffer_xon_field_name = "xon";
const std::string buffer_xoff_field_name = "xoff";
const std::string buffer_dynamic_th_field_name = "dynamic_th";
const std::string buffer_static_th_field_name = "static_th";
const std::string buffer_profile_field_name = "profile";
const std::string buffer_value_ingress = "ingress";
const std::string buffer_value_egress = "egress";
const std::string buffer_pool_mode_dynamic_value = "dynamic";
const std::string buffer_pool_mode_static_value = "static";
const std::string range_specifier = "-";
const std::string buffer_profile_list_field_name = "profile_list";
const std::string comma = ",";

class BufferOrch : public Orch
{
public:
BufferOrch(DBConnector *db, vector<string> &tableNames, PortsOrch *portsOrch);
static type_map m_buffer_type_maps;
private:
typedef task_process_status (BufferOrch::*buffer_table_handler)(Consumer& consumer);
typedef std::map<std::string, buffer_table_handler> buffer_table_handler_map;
typedef std::pair<string, buffer_table_handler> buffer_handler_pair;

virtual void doTask(Consumer& consumer);
void initTableHandlers();
task_process_status processBufferPool(Consumer &consumer);
task_process_status processBufferProfile(Consumer &consumer);
task_process_status processQueue(Consumer &consumer);
task_process_status processPriorityGroup(Consumer &consumer);
task_process_status processIngressBufferProfileList(Consumer &consumer);
task_process_status processEgressBufferProfileList(Consumer &consumer);
bool parseIndexRange(const string &input, sai_uint32_t &range_low, sai_uint32_t &range_high);
bool parseNameArray(const string &input, vector<string> &port_names);
private:
PortsOrch *m_portsOrch;
buffer_table_handler_map m_bufferHandlerMap;
};
#endif /* SWSS_BUFFORCH_H */

21 changes: 20 additions & 1 deletion orchagent/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ sai_neighbor_api_t* sai_neighbor_api;
sai_next_hop_api_t* sai_next_hop_api;
sai_next_hop_group_api_t* sai_next_hop_group_api;
sai_route_api_t* sai_route_api;
sai_queue_api_t* sai_queue_api;
sai_scheduler_api_t* sai_scheduler_api;
sai_scheduler_group_api_t* sai_scheduler_group_api;
sai_wred_api_t* sai_wred_api;
sai_qos_map_api_t* sai_qos_map_api;
sai_buffer_api_t* sai_buffer_api;


map<string, string> gProfileMap;
sai_object_id_t gVirtualRouterId;
Expand Down Expand Up @@ -83,7 +90,13 @@ void initSaiApi()
sai_api_query(SAI_API_NEXT_HOP, (void **)&sai_next_hop_api);
sai_api_query(SAI_API_NEXT_HOP_GROUP, (void **)&sai_next_hop_group_api);
sai_api_query(SAI_API_ROUTE, (void **)&sai_route_api);

sai_api_query(SAI_API_QUEUE, (void **)&sai_queue_api);
sai_api_query(SAI_API_SCHEDULER, (void **)&sai_scheduler_api);
sai_api_query(SAI_API_WRED, (void **)&sai_wred_api);
sai_api_query(SAI_API_QOS_MAPS, (void **)&sai_qos_map_api);
sai_api_query(SAI_API_BUFFERS, (void **)&sai_buffer_api);
sai_api_query(SAI_API_SCHEDULER_GROUP, (void **)&sai_scheduler_group_api);

sai_log_set(SAI_API_SWITCH, SAI_LOG_NOTICE);
sai_log_set(SAI_API_VIRTUAL_ROUTER, SAI_LOG_NOTICE);
sai_log_set(SAI_API_PORT, SAI_LOG_NOTICE);
Expand All @@ -94,6 +107,12 @@ void initSaiApi()
sai_log_set(SAI_API_NEXT_HOP, SAI_LOG_NOTICE);
sai_log_set(SAI_API_NEXT_HOP_GROUP, SAI_LOG_NOTICE);
sai_log_set(SAI_API_ROUTE, SAI_LOG_NOTICE);
sai_log_set(SAI_API_QUEUE, SAI_LOG_NOTICE);
sai_log_set(SAI_API_SCHEDULER, SAI_LOG_NOTICE);
sai_log_set(SAI_API_WRED, SAI_LOG_NOTICE);
sai_log_set(SAI_API_QOS_MAPS, SAI_LOG_NOTICE);
sai_log_set(SAI_API_BUFFERS, SAI_LOG_NOTICE);
sai_log_set(SAI_API_SCHEDULER_GROUP, SAI_LOG_NOTICE);
}

void initDiagShell()
Expand Down
178 changes: 172 additions & 6 deletions orchagent/orch.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#include "orch.h"
#include "logger.h"

#include <sstream>
#include <iostream>

using namespace swss;

Orch::Orch(DBConnector *db, string tableName) :
Expand All @@ -13,7 +16,7 @@ Orch::Orch(DBConnector *db, string tableName) :
Orch::Orch(DBConnector *db, vector<string> &tableNames) :
m_db(db)
{
for( auto it = tableNames.begin(); it != tableNames.end(); it++) {
for ( auto it = tableNames.begin(); it != tableNames.end(); it++) {
Consumer consumer(new ConsumerTable(m_db, *it));
m_consumerMap.insert(ConsumerMapPair(*it, consumer));
}
Expand All @@ -22,7 +25,7 @@ Orch::Orch(DBConnector *db, vector<string> &tableNames) :
Orch::~Orch()
{
delete(m_db);
for(auto it : m_consumerMap) {
for (auto it : m_consumerMap) {
delete it.second.m_consumer;
}
}
Expand All @@ -32,16 +35,16 @@ std::vector<Selectable*> Orch::getConsumers()
SWSS_LOG_ENTER();

std::vector<Selectable*> consumers;
for(auto it : m_consumerMap) {
for (auto it : m_consumerMap) {
consumers.push_back(it.second.m_consumer);
}
return consumers;
}

bool Orch::hasConsumer(ConsumerTable *consumer) const
{
for(auto it : m_consumerMap) {
if(it.second.m_consumer == consumer) {
for (auto it : m_consumerMap) {
if (it.second.m_consumer == consumer) {
return true;
}
}
Expand All @@ -51,7 +54,7 @@ bool Orch::hasConsumer(ConsumerTable *consumer) const
bool Orch::execute(string tableName)
{
auto consumer_it = m_consumerMap.find(tableName);
if(consumer_it == m_consumerMap.end()) {
if (consumer_it == m_consumerMap.end()) {
SWSS_LOG_ERROR("Unrecognized tableName:%s\n", tableName.c_str());
return false;
}
Expand Down Expand Up @@ -106,3 +109,166 @@ bool Orch::execute(string tableName)
doTask(consumer);
return true;
}
bool Orch::tokenizeString(string str, const string &separator, vector<string> &tokens)
{
SWSS_LOG_ENTER();
if (0 == separator.size())
{
SWSS_LOG_ERROR("Invalid separator passed in:%s\n", separator.c_str());
return false;
}
if (string::npos == str.find(separator))
{
SWSS_LOG_ERROR("Specified separator:%s not found in input:%s\n", separator.c_str(), str.c_str());
return false;
}
istringstream ss(str);
string tmp;
while (getline(ss, tmp, separator[0]))
{
SWSS_LOG_DEBUG("extracted token:%s", tmp.c_str());
tokens.push_back(tmp);
}
return true;
}

/*
- Validates reference is has proper format which is [table_name:object_name]
- validates table_name exists
- validates object with object_name exists
*/
bool Orch::parseReference(type_map &type_maps, string &ref_in, string &type_name, string &object_name)
{
SWSS_LOG_ENTER();
SWSS_LOG_DEBUG("input:%s", ref_in.c_str());
if (ref_in.size() < 3)
{
SWSS_LOG_ERROR("invalid reference received:%s\n", ref_in.c_str());
return false;
}
if ((ref_in[0] != ref_start) && (ref_in[ref_in.size()-1] != ref_end))
{
SWSS_LOG_ERROR("malformed reference:%s. Must be surrounded by [ ]\n", ref_in.c_str());
return false;
}
string ref_content = ref_in.substr(1, ref_in.size() - 2);
vector<string> tokens;
if (!tokenizeString(ref_content, delimiter, tokens))
{
return false;
}
if (tokens.size() != 2)
{
SWSS_LOG_ERROR("malformed reference:%s. Must contain 2 tokens\n", ref_content.c_str());
return false;
}
auto type_it = type_maps.find(tokens[0]);
if (type_it == type_maps.end())
{
SWSS_LOG_ERROR("not recognized type:%s\n", tokens[0].c_str());
return false;
}
auto obj_map = type_maps[tokens[0]];
auto obj_it = obj_map->find(tokens[1]);
if (obj_it == obj_map->end())
{
SWSS_LOG_ERROR("map:%s does not contain object with name:%s\n", tokens[0].c_str(), tokens[1].c_str());
return false;
}
type_name = tokens[0];
object_name = tokens[1];
SWSS_LOG_DEBUG("parsed: type_name:%s, object_name:%s", type_name.c_str(), object_name.c_str());
return true;
}

ref_resolve_status Orch::resolveFieldRefValue(
type_map &type_maps,
const string &field_name,
KeyOpFieldsValuesTuple &tuple,
sai_object_id_t &sai_object)
{
SWSS_LOG_ENTER();
size_t count = 0;
for (auto i = kfvFieldsValues(tuple).begin(); i != kfvFieldsValues(tuple).end(); i++)
{
if (fvField(*i) == field_name)
{
SWSS_LOG_DEBUG("field:%s, value:%s", fvField(*i).c_str(), fvValue(*i).c_str());
if (count > 1)
{
SWSS_LOG_ERROR("Singleton field with name:%s must have only 1 instance, actual count:%d\n", field_name.c_str(), count);
return ref_resolve_status::multiple_instances;
}
string ref_type_name, object_name;
if (!parseReference(type_maps, fvValue(*i), ref_type_name, object_name))
{
return ref_resolve_status::failure;
}
sai_object = (*(type_maps[ref_type_name]))[object_name];
count++;
}
}
if (0 == count)
{
SWSS_LOG_NOTICE("field with name:%s not found\n", field_name.c_str());
return ref_resolve_status::field_not_found;
}
return ref_resolve_status::success;
}

// example: [BUFFER_PROFILE_TABLE:e_port.profile0],[BUFFER_PROFILE_TABLE:e_port.profile1]
bool Orch::resolveFieldRefArray(
type_map &type_maps,
const string &field_name,
KeyOpFieldsValuesTuple &tuple,
vector<sai_object_id_t> &sai_object_arr)
{
SWSS_LOG_ENTER();
size_t count = 0;
sai_object_arr.clear();
for (auto i = kfvFieldsValues(tuple).begin(); i != kfvFieldsValues(tuple).end(); i++)
{
if (fvField(*i) == field_name)
{
if (count > 1)
{
SWSS_LOG_ERROR("Singleton field with name:%s must have only 1 instance, actual count:%d\n", field_name.c_str(), count);
return false;
}
string ref_type_name, object_name;
string list = fvValue(*i);
vector<string> list_items;
if (list.find(list_item_delimiter) != string::npos)
{
if (!tokenizeString(list, list_item_delimiter, list_items))
{
SWSS_LOG_ERROR("Failed to tokenize buffer profile list:%s\n", list.c_str());
return false;
}
}
else
{
list_items.push_back(list);
}
for (size_t ind = 0; ind < list_items.size(); ind++)
{
if (!parseReference(type_maps, list_items[ind], ref_type_name, object_name))
{
SWSS_LOG_ERROR("Failed to parse profile reference:%s\n", list_items[ind].c_str());
return false;
}
sai_object_id_t sai_obj = (*(type_maps[ref_type_name]))[object_name];
SWSS_LOG_DEBUG("Resolved to sai_object:0x%llx, type:%s, name:%s", sai_obj, ref_type_name.c_str(), object_name.c_str());
sai_object_arr.push_back(sai_obj);
}
count++;
}
}
if (0 == count)
{
SWSS_LOG_NOTICE("field with name:%s not found\n", field_name.c_str());
return ref_resolve_status::field_not_found;
}
return ref_resolve_status::success;
}

43 changes: 43 additions & 0 deletions orchagent/orch.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,19 @@ extern "C" {
using namespace std;
using namespace swss;

const char ref_start = '[';
const char ref_end = ']';
const std::string delimiter = ":";
const std::string list_item_delimiter = ",";

typedef std::map<string, sai_object_id_t> object_map;
typedef std::pair<string, sai_object_id_t> object_map_pair;

typedef std::map<string, object_map*> type_map;
typedef std::pair<string, object_map*> type_map_pair;



typedef map<string, KeyOpFieldsValuesTuple> SyncMap;
struct Consumer {
Consumer(ConsumerTable* consumer) :m_consumer(consumer) { }
Expand All @@ -25,19 +38,49 @@ struct Consumer {
typedef std::pair<string, Consumer> ConsumerMapPair;
typedef map<string, Consumer> ConsumerMap;

typedef enum
{
success,
field_not_found,
multiple_instances,
failure
} ref_resolve_status;

typedef enum
{
task_success,
task_invalid_entry,
task_failed,
task_need_retry
} task_process_status;

class Orch
{
public:
Orch(DBConnector *db, string tableName);
Orch(DBConnector *db, vector<string> &tableNames);
~Orch();

public:
std::vector<Selectable*> getConsumers();
bool hasConsumer(ConsumerTable* s)const;

bool execute(string tableName);

protected:
ref_resolve_status resolveFieldRefValue(
type_map &type_maps,
const string &field_name,
KeyOpFieldsValuesTuple &tuple,
sai_object_id_t &sai_object);
bool parseReference(type_map &type_maps, string &ref, string &table_name, string &object_name);
bool tokenizeString(string str, const string &separator, vector<string> &tokens);
bool resolveFieldRefArray(
type_map &type_maps,
const string &field_name,
KeyOpFieldsValuesTuple &tuple,
vector<sai_object_id_t> &sai_object_arr);

virtual void doTask(Consumer &consumer) = 0;
private:
DBConnector *m_db;
Expand Down
Loading