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; +}