Skip to content

Commit

Permalink
[vslib]Add MACsec Filters (sonic-net#713)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Pterosaur authored Nov 20, 2020
1 parent eb642cf commit 2abd374
Show file tree
Hide file tree
Showing 9 changed files with 363 additions and 0 deletions.
20 changes: 20 additions & 0 deletions vslib/inc/MACsecEgressFilter.h
Original file line number Diff line number Diff line change
@@ -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;
};
}
39 changes: 39 additions & 0 deletions vslib/inc/MACsecFilter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#pragma once

#include "TrafficFilter.h"

#include <string>

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;
};
}
21 changes: 21 additions & 0 deletions vslib/inc/MACsecIngressFilter.h
Original file line number Diff line number Diff line change
@@ -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;
};
}
32 changes: 32 additions & 0 deletions vslib/inc/TrafficFilter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#pragma once

#include "swss/sal.h"

#include <sys/types.h>

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;
};
}
35 changes: 35 additions & 0 deletions vslib/inc/TrafficFilterPipes.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#pragma once

#include "TrafficFilter.h"

#include <memory>
#include <map>
#include <mutex>

namespace saivs
{
class TrafficFilterPipes
{
public:
TrafficFilterPipes() = default;

virtual ~TrafficFilterPipes() = default;

bool installFilter(
_In_ int priority,
_In_ std::shared_ptr<TrafficFilter> filter);

bool uninstallFilter(
_In_ std::shared_ptr<TrafficFilter> filter);

TrafficFilter::FilterStatus execute(
_Inout_ void *buffer,
_Inout_ size_t &length);

private:
typedef std::map<int, std::shared_ptr<TrafficFilter> > FilterPriorityQueue;

std::mutex m_mutex;
FilterPriorityQueue m_filters;
};
}
49 changes: 49 additions & 0 deletions vslib/src/MACsecEgressFilter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#include "MACsecEgressFilter.h"

#include <swss/logger.h>

#include <unistd.h>
#include <string.h>

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;
}
64 changes: 64 additions & 0 deletions vslib/src/MACsecFilter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#include "MACsecFilter.h"

#include "swss/logger.h"
#include "swss/select.h"

#include <sys/socket.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <arpa/inet.h>
#include <net/if.h>

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<const ethhdr *>(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;
}
30 changes: 30 additions & 0 deletions vslib/src/MACsecIngressFilter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#include "MACsecIngressFilter.h"

#include "swss/logger.h"

#include <unistd.h>
#include <string.h>

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;
}
73 changes: 73 additions & 0 deletions vslib/src/TrafficFilterPipes.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#include "TrafficFilterPipes.h"

#include "swss/logger.h"

using namespace saivs;

bool TrafficFilterPipes::installFilter(
_In_ int priority,
_In_ std::shared_ptr<TrafficFilter> filter)
{
SWSS_LOG_ENTER();

std::unique_lock<std::mutex> guard(m_mutex);

return m_filters.emplace(priority, filter).second;
}

bool TrafficFilterPipes::uninstallFilter(
_In_ std::shared_ptr<TrafficFilter> filter)
{
SWSS_LOG_ENTER();

std::unique_lock<std::mutex> 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<std::mutex> 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;
}

0 comments on commit 2abd374

Please sign in to comment.