From a4a1e108afb3e75717e204da49a975681d964e8c Mon Sep 17 00:00:00 2001 From: Kiran Kumar Kella <45939429+kirankella@users.noreply.github.com> Date: Thu, 7 Nov 2019 03:26:54 +0530 Subject: [PATCH] Changes in swss-common submodule to support NAT feature. (#304) * Changes to support NAT feature. * Add new tables in CONFIG_DB, APP_DB, COUNTERS_DB * Netlink class for abstracting netfilter application socket Signed-off-by: kiran.kella@broadcom.com --- common/Makefile.am | 1 + common/ipaddress.h | 5 ++ common/nfnetlink.cpp | 164 +++++++++++++++++++++++++++++++++++++++++++ common/nfnetlink.h | 39 ++++++++++ common/schema.h | 20 ++++++ configure.ac | 2 +- 6 files changed, 230 insertions(+), 1 deletion(-) create mode 100644 common/nfnetlink.cpp create mode 100644 common/nfnetlink.h diff --git a/common/Makefile.am b/common/Makefile.am index 575ef7a04..733365f44 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -45,6 +45,7 @@ libswsscommon_la_SOURCES = \ macaddress.cpp \ netdispatcher.cpp \ netlink.cpp \ + nfnetlink.cpp \ notificationconsumer.cpp \ notificationproducer.cpp \ linkcache.cpp \ diff --git a/common/ipaddress.h b/common/ipaddress.h index bf890e435..920f335b0 100644 --- a/common/ipaddress.h +++ b/common/ipaddress.h @@ -72,6 +72,11 @@ class IpAddress ); } + inline bool operator!=(const IpAddress &o) const + { + return (! (*this == o) ); + } + std::string to_string() const; enum AddrScope { diff --git a/common/nfnetlink.cpp b/common/nfnetlink.cpp new file mode 100644 index 000000000..0a8f5aaf3 --- /dev/null +++ b/common/nfnetlink.cpp @@ -0,0 +1,164 @@ +#include +#include +#include +#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); + } +} + +bool NfNetlink::setSockBufSize(uint32_t sockBufSize) +{ + if (nl_socket_set_buffer_size(m_socket, sockBufSize, 0) < 0) + { + return false; + } + return true; +} + +void NfNetlink::registerRecvCallbacks() +{ +#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_THROW("Unable to register to netfilter group %d: %s", nfnlGroup, + nl_geterror(err)); + } +} + +void NfNetlink::dumpRequest(int getCommand) +{ + int err = nfnl_ct_dump_request(m_socket); + if (err < 0) + { + SWSS_LOG_THROW("Unable to request netfilter conntrack dump: %s", + nl_geterror(err)); + } +} + +bool 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"); + return false; + } + return true; +} + +bool 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"); + return false; + } + return true; +} + +int NfNetlink::getFd() +{ + return nl_socket_get_fd(m_socket); +} + +uint64_t 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); + } + return 0; +} + +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 diff --git a/common/nfnetlink.h b/common/nfnetlink.h new file mode 100644 index 000000000..5e3c8fc11 --- /dev/null +++ b/common/nfnetlink.h @@ -0,0 +1,39 @@ +#ifndef __NFNETLINK__ +#define __NFNETLINK__ + +#include "ipaddress.h" +#include +#include + +namespace swss { + +class NfNetlink : public Selectable { +public: + NfNetlink(int pri = 0); + ~NfNetlink() override; + + void registerRecvCallbacks(); + bool setSockBufSize(uint32_t sockBufSize); + void registerGroup(int nfnlGroup); + void dumpRequest(int getCommand); + + int getFd() override; + uint64_t readData() override; + + bool updateConnTrackEntry(struct nfnl_ct *ct); + bool deleteConnTrackEntry(struct nfnl_ct *ct); + +private: +#ifdef NETFILTER_UNIT_TEST + static int onNetlinkRcv(struct nl_msg *msg, void *arg); +#endif + static int onNetlinkMsg(struct nl_msg *msg, void *arg); + + FILE *nfPktsLogFile; + nl_sock *m_socket; +}; + +} + +#endif /* __NFNETLINK__ */ + diff --git a/common/schema.h b/common/schema.h index 7b2c92a40..53a8b0d60 100644 --- a/common/schema.h +++ b/common/schema.h @@ -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" @@ -84,6 +91,12 @@ namespace swss { #define COUNTERS_DEBUG_NAME_PORT_STAT_MAP "COUNTERS_DEBUG_NAME_PORT_STAT_MAP" #define COUNTERS_DEBUG_NAME_SWITCH_STAT_MAP "COUNTERS_DEBUG_NAME_SWITCH_STAT_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" @@ -202,6 +215,12 @@ namespace swss { #define CFG_DEBUG_COUNTER_TABLE_NAME "DEBUG_COUNTER" #define CFG_DEBUG_COUNTER_DROP_REASON_TABLE_NAME "DEBUG_COUNTER_DROP_REASON" +#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" @@ -221,6 +240,7 @@ namespace swss { #define STATE_VXLAN_TABLE_NAME "VXLAN_TABLE" #define STATE_BGP_TABLE_NAME "BGP_STATE_TABLE" #define STATE_DEBUG_COUNTER_CAPABILITIES_NAME "DEBUG_COUNTER_CAPABILITIES" +#define STATE_NAT_RESTORE_TABLE_NAME "NAT_RESTORE_TABLE" /***** MISC *****/ diff --git a/configure.ac b/configure.ac index fe252abae..d99202352 100644 --- a/configure.ac +++ b/configure.ac @@ -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"