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

Support ConfigDB neighbor configuration, introduce nbrmgr daemon #693

Merged
merged 6 commits into from
Nov 28, 2018
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ cfgmgr/intfmgrd
cfgmgr/vlanmgrd
cfgmgr/buffermanager
cfgmgr/vrfmgrd
cfgmgr/nbrmgrd
neighsyncd/neighsyncd
portsyncd/portsyncd
orchagent/orchagent
Expand Down
7 changes: 6 additions & 1 deletion cfgmgr/Makefile.am
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
INCLUDES = -I $(top_srcdir) -I $(top_srcdir)/orchagent -I $(top_srcdir)/warmrestart
CFLAGS_SAI = -I /usr/include/sai

bin_PROGRAMS = vlanmgrd teammgrd portmgrd intfmgrd buffermgrd vrfmgrd
bin_PROGRAMS = vlanmgrd teammgrd portmgrd intfmgrd buffermgrd vrfmgrd nbrmgrd

if DEBUG
DBGFLAGS = -ggdb -DDEBUG
Expand Down Expand Up @@ -38,3 +38,8 @@ vrfmgrd_SOURCES = vrfmgrd.cpp vrfmgr.cpp $(top_srcdir)/orchagent/orch.cpp $(top_
vrfmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI)
vrfmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI)
vrfmgrd_LDADD = -lswsscommon

nbrmgrd_SOURCES = nbrmgrd.cpp nbrmgr.cpp $(top_srcdir)/orchagent/orch.cpp $(top_srcdir)/orchagent/request_parser.cpp shellcmd.h
nbrmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI)
nbrmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI)
nbrmgrd_LDADD = -lswsscommon
236 changes: 236 additions & 0 deletions cfgmgr/nbrmgr.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
#include <arpa/inet.h>
#include <netinet/in.h>
#include <net/if.h>
#include <unistd.h>

#include "logger.h"
#include "tokenize.h"
#include "ipprefix.h"
#include "macaddress.h"
#include "nbrmgr.h"
#include "exec.h"
#include "shellcmd.h"

using namespace swss;

const int IP4_ADDR_LEN = 4;
const int IP6_ADDR_LEN = 16;
prsunny marked this conversation as resolved.
Show resolved Hide resolved
const int NL_MSG_BUF_SZ = 512;

#define VLAN_PREFIX "Vlan"
#define LAG_PREFIX "PortChannel"

NbrMgr::NbrMgr(DBConnector *cfgDb, DBConnector *appDb, DBConnector *stateDb, const vector<string> &tableNames) :
Orch(cfgDb, tableNames),
m_statePortTable(stateDb, STATE_PORT_TABLE_NAME),
m_stateLagTable(stateDb, STATE_LAG_TABLE_NAME),
m_stateVlanTable(stateDb, STATE_VLAN_TABLE_NAME),
m_stateIntfTable(stateDb, STATE_INTERFACE_TABLE_NAME)
{

}

bool NbrMgr::isIntfStateOk(const string &alias)
{
vector<FieldValueTuple> temp;

if (!alias.compare(0, strlen(VLAN_PREFIX), VLAN_PREFIX))
{
if (m_stateVlanTable.get(alias, temp))
{
SWSS_LOG_DEBUG("Vlan %s is ready", alias.c_str());
return true;
}
}
else if (!alias.compare(0, strlen(LAG_PREFIX), LAG_PREFIX))
{
if (m_stateLagTable.get(alias, temp))
{
SWSS_LOG_DEBUG("Lag %s is ready", alias.c_str());
return true;
}
}
else if (m_statePortTable.get(alias, temp))
{
SWSS_LOG_DEBUG("Port %s is ready", alias.c_str());
return true;
}

return false;
}

bool NbrMgr::sendMsg(struct nlmsghdr *msg)
{
SWSS_LOG_ENTER();

int sk = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (sk < 0)
{
SWSS_LOG_ERROR("Socket create error");
return false;
}

struct sockaddr_nl nl_addr ;
memset(&nl_addr, 0, sizeof(nl_addr));

nl_addr.nl_family = AF_NETLINK;

struct iovec iov[1] =
{
{
.iov_base = msg,
.iov_len = msg->nlmsg_len
}
};

struct msghdr msg_hdr =
{
.msg_name = &nl_addr,
.msg_namelen = sizeof(nl_addr),
.msg_iov = iov,
.msg_iovlen = 1,
.msg_control = NULL,
.msg_controllen = 0,
.msg_flags =0
};

if (sendmsg(sk, &msg_hdr, 0) != (msg->nlmsg_len))
{
SWSS_LOG_ERROR("Error sending message to kernel");
close(sk);
return false;
}

close(sk);

SWSS_LOG_INFO("Neighbor add msg sent to kernel");
return true;
}

bool NbrMgr::setNeighbor(const string& alias, IpAddress& ip, MacAddress& mac)
prsunny marked this conversation as resolved.
Show resolved Hide resolved
{
SWSS_LOG_ENTER();

char m_buf[NL_MSG_BUF_SZ];
memset(m_buf, 0, sizeof(struct nlmsghdr));

auto alloc_fn = [&] (struct nlmsghdr *msg, uint32_t len) {
auto *tail = (void *) (((char*)msg) + NLMSG_ALIGN(msg->nlmsg_len));;
msg->nlmsg_len = NLMSG_ALIGN(msg->nlmsg_len) + RTA_ALIGN(len);
return tail;
};

struct nlmsghdr *nl_msg = (struct nlmsghdr *) alloc_fn((struct nlmsghdr *)m_buf, sizeof(struct nlmsghdr));
struct ndmsg *nd_msg = (struct ndmsg *) alloc_fn(nl_msg, sizeof(struct ndmsg));

memset(nd_msg, 0, sizeof(struct ndmsg));

nd_msg->ndm_ifindex = if_nametoindex(alias.c_str());
prsunny marked this conversation as resolved.
Show resolved Hide resolved

int addr_len = ip.isV4()?IP4_ADDR_LEN : IP6_ADDR_LEN;

struct rtattr *rta = (struct rtattr *) alloc_fn(nl_msg, uint32_t(RTA_LENGTH(addr_len)));

rta->rta_type = NDA_DST;
rta->rta_len = static_cast<short>(RTA_LENGTH(addr_len));

nd_msg->ndm_type = RTN_UNICAST;
auto ip_addr = ip.getIp();

if (ip.isV4())
{
nd_msg->ndm_family = AF_INET;
memcpy(RTA_DATA(rta), &ip_addr.ip_addr.ipv4_addr, addr_len);
}
else
{
nd_msg->ndm_family = AF_INET6;
memcpy(RTA_DATA(rta), &ip_addr.ip_addr.ipv6_addr, addr_len);
}

if (!mac)
{
/*
* If mac is not provided, expected to resolve the MAC
*/
nd_msg->ndm_state = NUD_DELAY;
nd_msg->ndm_flags = NTF_USE;
prsunny marked this conversation as resolved.
Show resolved Hide resolved

SWSS_LOG_INFO("Resolve request for '%s'", ip.to_string().c_str());
}
else
{
SWSS_LOG_INFO("Set mac address '%s'", mac.to_string().c_str());

nd_msg->ndm_state = NUD_PERMANENT;

auto mac_len = ETHER_ADDR_LEN;
auto mac_addr = mac.getMac();
struct rtattr *rta = (struct rtattr *) alloc_fn(nl_msg, uint32_t(RTA_LENGTH(mac_len)));
rta->rta_type = NDA_LLADDR;
rta->rta_len = static_cast<short>(RTA_LENGTH(mac_len));
memcpy(RTA_DATA(rta), mac_addr, mac_len);
}

nl_msg->nlmsg_flags = (NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_REPLACE);
nl_msg->nlmsg_type = RTM_NEWNEIGH;

return sendMsg(nl_msg);
}

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

auto it = consumer.m_toSync.begin();
while (it != consumer.m_toSync.end())
{
KeyOpFieldsValuesTuple t = it->second;
vector<string> keys = tokenize(kfvKey(t), config_db_key_delimiter);
const vector<FieldValueTuple>& data = kfvFieldsValues(t);

string alias(keys[0]);
IpAddress ip(keys[1]);
string op = kfvOp(t);
MacAddress mac;

for (auto idx : data)
{
const auto &field = fvField(idx);
const auto &value = fvValue(idx);
if (field == "neigh")
{
mac = value;
prsunny marked this conversation as resolved.
Show resolved Hide resolved
}
}

if (op == SET_COMMAND)
{
if (!isIntfStateOk(alias))
{
SWSS_LOG_DEBUG("Interface is not yet ready, skipping '%s'", kfvKey(t).c_str());
it++;
continue;
}

if (!setNeighbor(alias, ip, mac))
{
SWSS_LOG_ERROR("Neigh entry add failed for '%s'", kfvKey(t).c_str());
}
else
{
SWSS_LOG_NOTICE("Neigh entry added for '%s'", kfvKey(t).c_str());
}
}
else if (op == DEL_COMMAND)
{
SWSS_LOG_NOTICE("Not yet implemented, key '%s'", kfvKey(t).c_str());
}
else
{
SWSS_LOG_ERROR("Unknown operation: '%s'", op.c_str());
}

it = consumer.m_toSync.erase(it);
}
}
35 changes: 35 additions & 0 deletions cfgmgr/nbrmgr.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#ifndef __NBRMGR__
#define __NBRMGR__

#include <string>
#include <map>
#include <set>

#include "dbconnector.h"
#include "producerstatetable.h"
#include "orch.h"
#include "netmsg.h"

using namespace std;

namespace swss {

class NbrMgr : public Orch
{
public:
NbrMgr(DBConnector *cfgDb, DBConnector *appDb, DBConnector *stateDb, const vector<string> &tableNames);
using Orch::doTask;

private:
bool isIntfStateOk(const string &alias);
bool setNeighbor(const string& alias, IpAddress& ip, MacAddress& mac);
bool sendMsg(struct nlmsghdr *msg);

void doTask(Consumer &consumer);

Table m_statePortTable, m_stateLagTable, m_stateVlanTable, m_stateIntfTable;
};

}

#endif // __NBRMGR__
88 changes: 88 additions & 0 deletions cfgmgr/nbrmgrd.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#include <unistd.h>
#include <vector>
#include <mutex>
#include <fstream>
#include <iostream>

#include "select.h"
#include "exec.h"
#include "schema.h"
#include "nbrmgr.h"

using namespace std;
using namespace swss;

/* select() function timeout retry time, in millisecond */
#define SELECT_TIMEOUT 1000

/*
* Following global variables are defined here for the purpose of
* using existing Orch class which is to be refactored soon to
* eliminate the direct exposure of the global variables.
*
* Once Orch class refactoring is done, these global variables
* should be removed from here.
*/
int gBatchSize = 0;
bool gSwssRecord = false;
bool gLogRotate = false;
ofstream gRecordOfs;
string gRecordFile;
/* Global database mutex */
mutex gDbMutex;

int main(int argc, char **argv)
{
Logger::linkToDbNative("nbrmgrd");
SWSS_LOG_ENTER();

SWSS_LOG_NOTICE("--- Starting nbrmgrd ---");

try
{
vector<string> cfg_nbr_tables = {
CFG_NEIGH_TABLE_NAME,
};

DBConnector cfgDb(CONFIG_DB, DBConnector::DEFAULT_UNIXSOCKET, 0);
DBConnector appDb(APPL_DB, DBConnector::DEFAULT_UNIXSOCKET, 0);
DBConnector stateDb(STATE_DB, DBConnector::DEFAULT_UNIXSOCKET, 0);

NbrMgr nbrmgr(&cfgDb, &appDb, &stateDb, cfg_nbr_tables);

std::vector<Orch *> cfgOrchList = {&nbrmgr};

swss::Select s;
for (Orch *o : cfgOrchList)
{
s.addSelectables(o->getSelectables());
}

SWSS_LOG_NOTICE("starting main loop");
while (true)
{
Selectable *sel;
int ret;

ret = s.select(&sel, SELECT_TIMEOUT);
if (ret == Select::ERROR)
{
SWSS_LOG_NOTICE("Error: %s!", strerror(errno));
continue;
}
if (ret == Select::TIMEOUT)
{
nbrmgr.doTask();
continue;
}

auto *c = (Executor *)sel;
c->execute();
}
}
catch(const std::exception &e)
{
SWSS_LOG_ERROR("Runtime error: %s", e.what());
}
return -1;
}
Loading