From f1b1f05094388ac7b0338b37256f271b81714d36 Mon Sep 17 00:00:00 2001 From: Ze Gan Date: Sat, 21 Nov 2020 01:23:10 +0800 Subject: [PATCH] [vslib]Add MACsec Filters (#713) All filters will be installed in HostInterfaceInfo to filter the EAPOL and data traffic. The MACsecEgressFilter will forward EAPOL packets to eth device and forward data packets to MACsec device. The MACsecIngressFilter will forward EAPOL packets to Ethernet device and drop all data packets. Because the data packets will be forwarded to MACsec device by Linux kernel. The TrafficFilterPipes provides an interfaces to add more filters for future functions. --- vslib/inc/MACsecEgressFilter.h | 20 +++++++++ vslib/inc/MACsecFilter.h | 39 +++++++++++++++++ vslib/inc/MACsecIngressFilter.h | 21 +++++++++ vslib/inc/TrafficFilter.h | 32 ++++++++++++++ vslib/inc/TrafficFilterPipes.h | 35 +++++++++++++++ vslib/src/MACsecEgressFilter.cpp | 49 +++++++++++++++++++++ vslib/src/MACsecFilter.cpp | 64 +++++++++++++++++++++++++++ vslib/src/MACsecIngressFilter.cpp | 30 +++++++++++++ vslib/src/TrafficFilterPipes.cpp | 73 +++++++++++++++++++++++++++++++ 9 files changed, 363 insertions(+) create mode 100644 vslib/inc/MACsecEgressFilter.h create mode 100644 vslib/inc/MACsecFilter.h create mode 100644 vslib/inc/MACsecIngressFilter.h create mode 100644 vslib/inc/TrafficFilter.h create mode 100644 vslib/inc/TrafficFilterPipes.h create mode 100644 vslib/src/MACsecEgressFilter.cpp create mode 100644 vslib/src/MACsecFilter.cpp create mode 100644 vslib/src/MACsecIngressFilter.cpp create mode 100644 vslib/src/TrafficFilterPipes.cpp diff --git a/vslib/inc/MACsecEgressFilter.h b/vslib/inc/MACsecEgressFilter.h new file mode 100644 index 000000000..1f4aa14b4 --- /dev/null +++ b/vslib/inc/MACsecEgressFilter.h @@ -0,0 +1,20 @@ +#pragma once + +#include "MACsecFilter.h" + +namespace saivs +{ + class MACsecEgressFilter : public MACsecFilter + { + public: + MACsecEgressFilter( + _In_ const std::string &macsecInterfaceName); + + virtual ~MACsecEgressFilter() = default; + + protected: + virtual FilterStatus forward( + _In_ const void *buffer, + _In_ size_t length) override; + }; +} diff --git a/vslib/inc/MACsecFilter.h b/vslib/inc/MACsecFilter.h new file mode 100644 index 000000000..3cd06f5c6 --- /dev/null +++ b/vslib/inc/MACsecFilter.h @@ -0,0 +1,39 @@ +#pragma once + +#include "TrafficFilter.h" + +#include + +namespace saivs +{ + class MACsecFilter : + public TrafficFilter + { + public: + MACsecFilter( + _In_ const std::string &macsecInterfaceName); + + virtual ~MACsecFilter() = default; + + virtual FilterStatus execute( + _Inout_ void *buffer, + _Inout_ size_t &length) override; + + void enable_macsec_device( + _In_ bool enable); + + void set_macsec_fd( + _In_ int macsecfd); + + protected: + virtual FilterStatus forward( + _In_ const void *buffer, + _In_ size_t length) = 0; + + bool m_macsec_device_enable; + + int m_macsecfd; + + const std::string m_macsec_interface_name; + }; +} diff --git a/vslib/inc/MACsecIngressFilter.h b/vslib/inc/MACsecIngressFilter.h new file mode 100644 index 000000000..29ac15330 --- /dev/null +++ b/vslib/inc/MACsecIngressFilter.h @@ -0,0 +1,21 @@ +#pragma once + +#include "MACsecFilter.h" + +namespace saivs +{ + class MACsecIngressFilter : + public MACsecFilter + { + public: + MACsecIngressFilter( + _In_ const std::string &macsecInterfaceName); + + virtual ~MACsecIngressFilter() = default; + + protected: + virtual FilterStatus forward( + _In_ const void *buffer, + _In_ size_t length) override; + }; +} diff --git a/vslib/inc/TrafficFilter.h b/vslib/inc/TrafficFilter.h new file mode 100644 index 000000000..9456b3375 --- /dev/null +++ b/vslib/inc/TrafficFilter.h @@ -0,0 +1,32 @@ +#pragma once + +#include "swss/sal.h" + +#include + +namespace saivs +{ + enum FilterPriority + { + MACSEC_FILTER, + }; + + class TrafficFilter + { + public: + enum FilterStatus + { + CONTINUE, + TERMINATE, + ERROR, + }; + + TrafficFilter() = default; + + virtual ~TrafficFilter() = default; + + virtual FilterStatus execute( + _Inout_ void *buffer, + _Inout_ size_t &length) = 0; + }; +} diff --git a/vslib/inc/TrafficFilterPipes.h b/vslib/inc/TrafficFilterPipes.h new file mode 100644 index 000000000..d772cba2a --- /dev/null +++ b/vslib/inc/TrafficFilterPipes.h @@ -0,0 +1,35 @@ +#pragma once + +#include "TrafficFilter.h" + +#include +#include +#include + +namespace saivs +{ + class TrafficFilterPipes + { + public: + TrafficFilterPipes() = default; + + virtual ~TrafficFilterPipes() = default; + + bool installFilter( + _In_ int priority, + _In_ std::shared_ptr filter); + + bool uninstallFilter( + _In_ std::shared_ptr filter); + + TrafficFilter::FilterStatus execute( + _Inout_ void *buffer, + _Inout_ size_t &length); + + private: + typedef std::map > FilterPriorityQueue; + + std::mutex m_mutex; + FilterPriorityQueue m_filters; + }; +} diff --git a/vslib/src/MACsecEgressFilter.cpp b/vslib/src/MACsecEgressFilter.cpp new file mode 100644 index 000000000..bf9400b53 --- /dev/null +++ b/vslib/src/MACsecEgressFilter.cpp @@ -0,0 +1,49 @@ +#include "MACsecEgressFilter.h" + +#include + +#include +#include + +using namespace saivs; + +MACsecEgressFilter::MACsecEgressFilter( + _In_ const std::string &macsecInterfaceName): + MACsecFilter(macsecInterfaceName) +{ + SWSS_LOG_ENTER(); + + // empty intentionally +} + +TrafficFilter::FilterStatus MACsecEgressFilter::forward( + _In_ const void *buffer, + _In_ size_t length) +{ + SWSS_LOG_ENTER(); + + if (write(m_macsecfd, buffer, length) < 0) + { + if (errno != ENETDOWN && errno != EIO) + { + SWSS_LOG_ERROR( + "failed to write to macsec device %s fd %d, errno(%d): %s", + m_macsecInterfaceName.c_str(), + m_macsecfd, + errno, + strerror(errno)); + } + + if (errno == EBADF) + { + SWSS_LOG_ERROR( + "ending thread for macsec device %s fd %d", + m_macsecInterfaceName.c_str(), + m_macsecfd); + + return TrafficFilter::ERROR; + } + } + + return TrafficFilter::TERMINATE; +} diff --git a/vslib/src/MACsecFilter.cpp b/vslib/src/MACsecFilter.cpp new file mode 100644 index 000000000..b0329e675 --- /dev/null +++ b/vslib/src/MACsecFilter.cpp @@ -0,0 +1,64 @@ +#include "MACsecFilter.h" + +#include "swss/logger.h" +#include "swss/select.h" + +#include +#include +#include +#include +#include + +using namespace saivs; + +#define EAPOL_ETHER_TYPE (0x888e) + +MACsecFilter::MACsecFilter( + _In_ const std::string &macsecInterfaceName): + m_macsecDeviceEnable(false), + m_macsecfd(0), + m_macsecInterfaceName(macsecInterfaceName) +{ + SWSS_LOG_ENTER(); + + // empty intentionally +} + +void MACsecFilter::enable_macsec_device( + _In_ bool enable) +{ + SWSS_LOG_ENTER(); + + m_macsecDeviceEnable = enable; +} + +void MACsecFilter::set_macsec_fd( + _In_ int macsecfd) +{ + SWSS_LOG_ENTER(); + + m_macsecfd = macsecfd; +} + +TrafficFilter::FilterStatus MACsecFilter::execute( + _Inout_ void *buffer, + _Inout_ size_t &length) +{ + SWSS_LOG_ENTER(); + + auto mac_hdr = static_cast(buffer); + + if (ntohs(mac_hdr->h_proto) == EAPOL_ETHER_TYPE) + { + // EAPOL traffic will never be delivered to MACsec device + return TrafficFilter::CONTINUE; + } + + if (m_macsecDeviceEnable) + { + return forward(buffer, length); + } + + // Drop all non-EAPOL packets if macsec device haven't been enable. + return TrafficFilter::TERMINATE; +} diff --git a/vslib/src/MACsecIngressFilter.cpp b/vslib/src/MACsecIngressFilter.cpp new file mode 100644 index 000000000..78d83c302 --- /dev/null +++ b/vslib/src/MACsecIngressFilter.cpp @@ -0,0 +1,30 @@ +#include "MACsecIngressFilter.h" + +#include "swss/logger.h" + +#include +#include + +using namespace saivs; + +MACsecIngressFilter::MACsecIngressFilter( + _In_ const std::string &macsecInterfaceName) : + MACsecFilter(macsecInterfaceName) +{ + SWSS_LOG_ENTER(); + + // empty intentionally +} + +TrafficFilter::FilterStatus MACsecIngressFilter::forward( + _In_ const void *buffer, + _In_ size_t length) +{ + SWSS_LOG_ENTER(); + + // MACsec interface will automatically forward ingress MACsec traffic + // by Linux Kernel. + // So this filter just need to drop all ingress MACsec traffic directly + + return TrafficFilter::TERMINATE; +} diff --git a/vslib/src/TrafficFilterPipes.cpp b/vslib/src/TrafficFilterPipes.cpp new file mode 100644 index 000000000..cdb20642d --- /dev/null +++ b/vslib/src/TrafficFilterPipes.cpp @@ -0,0 +1,73 @@ +#include "TrafficFilterPipes.h" + +#include "swss/logger.h" + +using namespace saivs; + +bool TrafficFilterPipes::installFilter( + _In_ int priority, + _In_ std::shared_ptr filter) +{ + SWSS_LOG_ENTER(); + + std::unique_lock guard(m_mutex); + + return m_filters.emplace(priority, filter).second; +} + +bool TrafficFilterPipes::uninstallFilter( + _In_ std::shared_ptr filter) +{ + SWSS_LOG_ENTER(); + + std::unique_lock guard(m_mutex); + + for (auto itr = m_filters.begin(); + itr != m_filters.end(); + itr ++) + { + if (itr->second == filter) + { + m_filters.erase(itr); + + return true; + } + } + + return false; +} + +TrafficFilter::FilterStatus TrafficFilterPipes::execute( + _Inout_ void *buffer, + _Inout_ size_t &length) +{ + SWSS_LOG_ENTER(); + + std::unique_lock guard(m_mutex); + TrafficFilter::FilterStatus ret = TrafficFilter::CONTINUE; + + for (auto itr = m_filters.begin(); itr != m_filters.end();) + { + auto filter = itr->second; + + if (filter) + { + ret = filter->execute(buffer, length); + + if (ret == TrafficFilter::CONTINUE) + { + itr ++; + } + else + { + break; + } + } + else + { + itr = m_filters.erase(itr); + } + } + + return ret; +}