Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
9 changes: 8 additions & 1 deletion cfgmgr/Makefile.am
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
INCLUDES = -I $(top_srcdir) -I $(top_srcdir)/orchagent -I $(top_srcdir)/warmrestart
CFLAGS_SAI = -I /usr/include/sai
LIBNL_CFLAGS = -I/usr/include/libnl3
LIBNL_LIBS = -lnl-genl-3 -lnl-route-3 -lnl-3

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 +40,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) $(LIBNL_CFLAGS)
nbrmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(LIBNL_CPPFLAGS)
nbrmgrd_LDADD = -lswsscommon $(LIBNL_LIBS)
210 changes: 210 additions & 0 deletions cfgmgr/nbrmgr.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
#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;

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

static bool send_message(struct nl_msg *msg)
{
struct nl_sock *sk = nl_socket_alloc();
if (!sk)
{
SWSS_LOG_ERROR("Netlink socket alloc failed");
return false;
}

nl_connect(sk, NETLINK_ROUTE);
bool rc = true;

if (nl_send_auto(sk, msg) < 0)
{
SWSS_LOG_ERROR("Netlink send message failed");
rc = false;
}

nlmsg_free(msg);
nl_socket_free(sk);

return rc;
}

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::setNeighbor(const string& alias, const IpAddress& ip, const MacAddress& mac)
{
SWSS_LOG_ENTER();

struct nl_msg *msg = nlmsg_alloc();
if (!msg)
{
SWSS_LOG_ERROR("Netlink message alloc failed for '%s'", ip.to_string().c_str());
return false;
}

auto flags = (NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_REPLACE);

nlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, RTM_NEWNEIGH, 0, flags);

struct ndmsg *nd_msg = static_cast<struct ndmsg *>
(nlmsg_reserve(msg, sizeof(struct ndmsg), NLMSG_ALIGNTO));
memset(nd_msg, 0, sizeof(struct ndmsg));

nd_msg->ndm_ifindex = if_nametoindex(alias.c_str());

auto addr_len = ip.isV4()? sizeof(struct in_addr) : sizeof(struct in6_addr);

struct rtattr *rta = static_cast<struct rtattr *>
(nlmsg_reserve(msg, sizeof(struct rtattr) + addr_len, NLMSG_ALIGNTO));

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;

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 = static_cast<struct rtattr *>
(nlmsg_reserve(msg, sizeof(struct rtattr) + mac_len, NLMSG_ALIGNTO));

rta->rta_type = NDA_LLADDR;
rta->rta_len = static_cast<short>(RTA_LENGTH(mac_len));
memcpy(RTA_DATA(rta), mac_addr, mac_len);
}

return send_message(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;
}
}

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);
}
}
34 changes: 34 additions & 0 deletions cfgmgr/nbrmgr.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#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, const IpAddress& ip, const MacAddress& mac);

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;
}
5 changes: 5 additions & 0 deletions doc/swss-schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,11 @@ Status: ready
vni = uint24 ; vni id, defined for tunnel map
vlan = "Vlan"vlan_id ; name of the existing vlan interface

### NEIGH_TABLE
; Stores the neighbors. Defines static configuration of neighbor entries. If mac address is not specified, implementation shall resolve the mac-address for the neighbor IP.
key = NEIGH|PORT_TABLE.name / VLAN_INTF_TABLE.name / LAG_INTF_TABLE.name|prefix
neigh = 12HEXDIG ; mac address of the neighbor (optional)
family = "IPv4" / "IPv6" ; address family

## State DB schema

Expand Down