Skip to content

Commit

Permalink
Changes to support NAT feature.
Browse files Browse the repository at this point in the history
 * Add new tables in CONFIG_DB, APP_DB, COUNTERS_DB
 * Netlink class for abstracting netfilter application socket

Signed-off-by: kiran.kella@broadcom.com
  • Loading branch information
kirankella committed Sep 16, 2019
1 parent e455891 commit 16ef26f
Show file tree
Hide file tree
Showing 6 changed files with 274 additions and 1 deletion.
1 change: 1 addition & 0 deletions common/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ libswsscommon_la_SOURCES = \
macaddress.cpp \
netdispatcher.cpp \
netlink.cpp \
nfnetlink.cpp \
notificationconsumer.cpp \
notificationproducer.cpp \
linkcache.cpp \
Expand Down
5 changes: 5 additions & 0 deletions common/ipaddress.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ class IpAddress
);
}

inline bool operator!=(const IpAddress &o) const
{
return (! (*this == o) );
}

std::string to_string() const;

enum AddrScope {
Expand Down
208 changes: 208 additions & 0 deletions common/nfnetlink.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
#include <string.h>
#include <errno.h>
#include <system_error>
#include "common/logger.h"
#include "common/netmsg.h"
#include "common/netdispatcher.h"
#include "common/netlink.h"
#include "common/nfnetlink.h"

using namespace swss;
using namespace std;

NfNetlink::NfNetlink(int pri) :
Selectable(pri)
{
m_socket = nl_socket_alloc();
if (!m_socket)
{
SWSS_LOG_ERROR("Unable to allocated nfnetlink socket");
throw system_error(make_error_code(errc::address_not_available),
"Unable to allocate nfnetlink socket");
}

nl_socket_disable_seq_check(m_socket);
nl_socket_disable_auto_ack(m_socket);

int err = nfnl_connect(m_socket);
if (err < 0)
{
SWSS_LOG_ERROR("Unable to connect nfnetlink socket: %s", nl_geterror(err));
nl_socket_free(m_socket);
m_socket = NULL;
throw system_error(make_error_code(errc::address_not_available),
"Unable to connect nfnetlink socket");
}

nl_socket_set_nonblocking(m_socket);

/* Set socket buffer size to 10 MB */
nl_socket_set_buffer_size(m_socket, 10485760, 0);

#ifdef NETFILTER_UNIT_TEST
/* For netlink packet tracing purposes */
nfPktsLogFile = fopen("/var/log/nf_netlink_pkts.log", "w");
if (nfPktsLogFile == NULL)
{
SWSS_LOG_ERROR("Unable to open netfilter netlink packets log file: %s", strerror(errno));
}
#endif
}

NfNetlink::~NfNetlink()
{
if (m_socket != NULL)
{
nl_close(m_socket);
nl_socket_free(m_socket);
}
}

void NfNetlink::registerRecvCallbacks(void)
{
#ifdef NETFILTER_UNIT_TEST
nl_socket_modify_cb(m_socket, NL_CB_MSG_IN, NL_CB_CUSTOM, onNetlinkRcv, this);
#endif

nl_socket_modify_cb(m_socket, NL_CB_VALID, NL_CB_CUSTOM, onNetlinkMsg, this);
}

void NfNetlink::registerGroup(int nfnlGroup)
{
int err = nl_socket_add_membership(m_socket, nfnlGroup);
if (err < 0)
{
SWSS_LOG_ERROR("Unable to register to netfilter group %d: %s", nfnlGroup,
nl_geterror(err));
throw system_error(make_error_code(errc::address_not_available),
"Unable to register to netfilter group");
}
}
void NfNetlink::dumpRequest(int getCommand)
{
int err = nfnl_ct_dump_request(m_socket);
if (err < 0)
{
SWSS_LOG_ERROR("Unable to request netfilter conntrack dump: %s",
nl_geterror(err));
throw system_error(make_error_code(errc::address_not_available),
"Unable to request netfilter conntrack dump");
}
}

void NfNetlink::updateConnTrackEntry(struct nfnl_ct *ct)
{
if (nfnl_ct_add(m_socket, ct, NLM_F_REPLACE) < 0)
{
SWSS_LOG_ERROR("Failed to update conntrack object in the kernel");
}
}

void NfNetlink::deleteConnTrackEntry(struct nfnl_ct *ct)
{
if (nfnl_ct_del(m_socket, ct, 0) < 0)
{
SWSS_LOG_ERROR("Failed to delete conntrack object in the kernel");
}
}

struct nfnl_ct *NfNetlink::getCtObject(const IpAddress &sourceIpAddr)
{
struct nfnl_ct *ct = nfnl_ct_alloc();
struct nl_addr *orig_src_ip;

if (! ct)
{
SWSS_LOG_ERROR("Unable to allocate memory for conntrack object");
return NULL;
}

nfnl_ct_set_family(ct, AF_INET);
if (nl_addr_parse(sourceIpAddr.to_string().c_str(), AF_INET, &orig_src_ip) == 0)
{
nfnl_ct_set_src(ct, 0, orig_src_ip);
}
else
{
SWSS_LOG_ERROR("Failed to parse orig src ip into conntrack object");
nfnl_ct_put(ct);
return NULL;
}

return ct;
}

struct nfnl_ct *NfNetlink::getCtObject(uint8_t protoType, const IpAddress &sourceIpAddr, uint16_t srcPort)
{
struct nfnl_ct *ct = nfnl_ct_alloc();
struct nl_addr *orig_src_ip;

if (! ct)
{
SWSS_LOG_ERROR("Unable to allocate memory for conntrack object");
return NULL;
}

nfnl_ct_set_family(ct, AF_INET);
nfnl_ct_set_proto(ct, protoType);

if (nl_addr_parse(sourceIpAddr.to_string().c_str(), AF_INET, &orig_src_ip) == 0)
{
nfnl_ct_set_src(ct, 0, orig_src_ip);
}
else
{
SWSS_LOG_ERROR("Failed to parse orig src ip into conntrack object");
nfnl_ct_put(ct);
return NULL;
}
nfnl_ct_set_src_port(ct, 0, srcPort);

return ct;
}

int NfNetlink::getFd()
{
return nl_socket_get_fd(m_socket);
}

void NfNetlink::readData()
{
int err;

do
{
err = nl_recvmsgs_default(m_socket);
}
while(err == -NLE_INTR); // Retry if the process was interrupted by a signal

if (err < 0)
{
if (err == -NLE_NOMEM)
SWSS_LOG_ERROR("netlink reports out of memory on reading a netfilter netlink socket. High possiblity of a lost message");
else if (err == -NLE_AGAIN)
SWSS_LOG_DEBUG("netlink reports NLE_AGAIN on reading a netfilter netlink socket");
else
SWSS_LOG_ERROR("netlink reports an error=%d on reading a netfilter netlink socket", err);
}
}

int NfNetlink::onNetlinkMsg(struct nl_msg *msg, void *arg)
{
NetDispatcher::getInstance().onNetlinkMessage(msg);
return NL_OK;
}

#ifdef NETFILTER_UNIT_TEST
int NfNetlink::onNetlinkRcv(struct nl_msg *msg, void *arg)
{
NfNetlink *nfnlink = (NfNetlink *)arg;

if ((nfnlink == NULL) || (nfnlink->nfPktsLogFile == NULL))
return NL_OK;

nl_msg_dump(msg, nfnlink->nfPktsLogFile);

return NL_OK;
}
#endif
39 changes: 39 additions & 0 deletions common/nfnetlink.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#ifndef __NFNETLINK__
#define __NFNETLINK__

#include "ipaddress.h"
#include <netlink/netfilter/ct.h>
#include <netlink/netfilter/nfnl.h>

namespace swss {

class NfNetlink : public Selectable {
public:
NfNetlink(int pri = 0);
~NfNetlink() override;

void registerRecvCallbacks(void);
void registerGroup(int nfnlGroup);
void dumpRequest(int getCommand);

int getFd() override;
void readData() override;

void updateConnTrackEntry(struct nfnl_ct *ct);
void deleteConnTrackEntry(struct nfnl_ct *ct);

private:
struct nfnl_ct *getCtObject(const IpAddress &sourceIpAddr);
struct nfnl_ct *getCtObject(uint8_t protoType, const IpAddress &sourceIpAddr, uint16_t srcPort);

static int onNetlinkRcv(struct nl_msg *msg, void *arg);
static int onNetlinkMsg(struct nl_msg *msg, void *arg);

FILE *nfPktsLogFile;
nl_sock *m_socket;
};

}

#endif /* __NFNETLINK__ */

20 changes: 20 additions & 0 deletions common/schema.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ namespace swss {
#define APP_SFLOW_SESSION_TABLE_NAME "SFLOW_SESSION_TABLE"
#define APP_SFLOW_SAMPLE_RATE_TABLE_NAME "SFLOW_SAMPLE_RATE_TABLE"

#define APP_NAT_TABLE_NAME "NAT_TABLE"
#define APP_NAPT_TABLE_NAME "NAPT_TABLE"
#define APP_NAT_TWICE_TABLE_NAME "NAT_TWICE_TABLE"
#define APP_NAPT_TWICE_TABLE_NAME "NAPT_TWICE_TABLE"
#define APP_NAT_GLOBAL_TABLE_NAME "NAT_GLOBAL_TABLE"
#define APP_NAPT_POOL_IP_TABLE_NAME "NAPT_POOL_IP_TABLE"

/***** TO BE REMOVED *****/

#define APP_TC_TO_QUEUE_MAP_TABLE_NAME "TC_TO_QUEUE_MAP_TABLE"
Expand Down Expand Up @@ -80,6 +87,12 @@ namespace swss {
#define COUNTERS_CRM_TABLE "CRM"
#define COUNTERS_BUFFER_POOL_NAME_MAP "COUNTERS_BUFFER_POOL_NAME_MAP"

#define COUNTERS_NAT_TABLE "COUNTERS_NAT"
#define COUNTERS_NAPT_TABLE "COUNTERS_NAPT"
#define COUNTERS_TWICE_NAT_TABLE "COUNTERS_TWICE_NAT"
#define COUNTERS_TWICE_NAPT_TABLE "COUNTERS_TWICE_NAPT"
#define COUNTERS_GLOBAL_NAT_TABLE "COUNTERS_GLOBAL_NAT"

#define PERIODIC_WATERMARKS_TABLE "PERIODIC_WATERMARKS"
#define PERSISTENT_WATERMARKS_TABLE "PERSISTENT_WATERMARKS"
#define USER_WATERMARKS_TABLE "USER_WATERMARKS"
Expand Down Expand Up @@ -192,6 +205,12 @@ namespace swss {
#define CFG_SFLOW_TABLE_NAME "SFLOW"
#define CFG_SFLOW_SESSION_TABLE_NAME "SFLOW_SESSION"

#define CFG_STATIC_NAT_TABLE_NAME "STATIC_NAT"
#define CFG_STATIC_NAPT_TABLE_NAME "STATIC_NAPT"
#define CFG_NAT_POOL_TABLE_NAME "NAT_POOL"
#define CFG_NAT_BINDINGS_TABLE_NAME "NAT_BINDINGS"
#define CFG_NAT_GLOBAL_TABLE_NAME "NAT_GLOBAL"

/***** STATE DATABASE *****/

#define STATE_SWITCH_CAPABILITY_TABLE_NAME "SWITCH_CAPABILITY_TABLE"
Expand All @@ -209,6 +228,7 @@ namespace swss {
#define STATE_MIRROR_SESSION_TABLE_NAME "MIRROR_SESSION_TABLE"
#define STATE_VXLAN_TABLE_NAME "VXLAN_TABLE"
#define STATE_BGP_TABLE_NAME "BGP_STATE_TABLE"
#define STATE_NAT_RESTORE_TABLE_NAME "NAT_RESTORE_TABLE"

/***** MISC *****/

Expand Down
2 changes: 1 addition & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ AC_HEADER_STDC
AM_PATH_PYTHON

AC_CHECK_LIB([hiredis], [redisConnect])
PKG_CHECK_MODULES([LIBNL], [libnl-3.0 libnl-genl-3.0 libnl-route-3.0])
PKG_CHECK_MODULES([LIBNL], [libnl-3.0 libnl-genl-3.0 libnl-route-3.0 libnl-nf-3.0])
CFLAGS="$CFLAGS $LIBNL_CFLAGS"
LIBS="$LIBS $LIBNL_LIBS"

Expand Down

0 comments on commit 16ef26f

Please sign in to comment.