mirror of
https://github.com/mfontanini/libtins
synced 2026-01-22 18:25:57 +01:00
Add VXLAN support (#501)
This patch adds a new PDU class to support VXLAN. Several VXLAN-related tests have also been added. Signed-off-by: James Raphael Tiovalen <jamestiotio@gmail.com>
This commit is contained in:
@@ -180,6 +180,7 @@ public:
|
||||
PKTAP,
|
||||
MPLS,
|
||||
DOT11_CONTROL_TA,
|
||||
VXLAN,
|
||||
UNKNOWN = 999,
|
||||
USER_DEFINED_PDU = 1000
|
||||
};
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
#include <tins/pdu_allocator.h>
|
||||
#include <tins/ipsec.h>
|
||||
#include <tins/ip_reassembler.h>
|
||||
|
||||
#include <tins/pdu_iterator.h>
|
||||
#include <tins/vxlan.h>
|
||||
|
||||
#endif // TINS_TINS_H
|
||||
|
||||
98
include/tins/vxlan.h
Normal file
98
include/tins/vxlan.h
Normal file
@@ -0,0 +1,98 @@
|
||||
#ifndef TINS_VXLAN_H
|
||||
#define TINS_VXLAN_H
|
||||
|
||||
#include <tins/pdu.h>
|
||||
#include <tins/small_uint.h>
|
||||
|
||||
namespace Tins {
|
||||
|
||||
/**
|
||||
* \class VXLAN
|
||||
* \brief Represents a VXLAN PDU.
|
||||
*
|
||||
* This class represents a VXLAN PDU.
|
||||
*
|
||||
* \sa RawPDU
|
||||
*/
|
||||
class TINS_API VXLAN : public PDU {
|
||||
public:
|
||||
/**
|
||||
* \brief This PDU's flag.
|
||||
*/
|
||||
static const PDU::PDUType pdu_flag = PDU::VXLAN;
|
||||
|
||||
/**
|
||||
* \brief Constructs a VXLAN PDU.
|
||||
*
|
||||
* \param vni VXLAN Network Identifier.
|
||||
*/
|
||||
VXLAN(const small_uint<24> vni = 0);
|
||||
|
||||
/**
|
||||
* \brief Constructs a VXLAN object from a buffer and adds
|
||||
* the Ethernet II PDU.
|
||||
*
|
||||
* \param buffer The buffer from which this PDU will be constructed.
|
||||
* \param total_sz The total size of the buffer.
|
||||
*/
|
||||
VXLAN(const uint8_t* buffer, uint32_t total_sz);
|
||||
|
||||
/**
|
||||
* \brief Getter for the flags.
|
||||
*/
|
||||
uint8_t get_flags() const { return Endian::be_to_host(header_.flags) >> 24; }
|
||||
|
||||
/**
|
||||
* \brief Getter for the VNI.
|
||||
*/
|
||||
small_uint<24> get_vni() const { return Endian::be_to_host(header_.vni) >> 8; }
|
||||
|
||||
/**
|
||||
* \brief Setter for the flags.
|
||||
* \param new_flags The new flags.
|
||||
*/
|
||||
void set_flags(uint8_t new_flags) { header_.flags = Endian::host_to_be(new_flags << 24); }
|
||||
|
||||
/**
|
||||
* \brief Setter for the VNI.
|
||||
* \param new_vni The new VNI.
|
||||
*/
|
||||
void set_vni(small_uint<24> new_vni) { header_.vni = Endian::host_to_be(new_vni << 8); }
|
||||
|
||||
/**
|
||||
* \brief Returns the VXLAN frame's header length.
|
||||
*
|
||||
* This method overrides PDU::header_size. This size includes the
|
||||
* payload and options size.
|
||||
*
|
||||
* \return An uint32_t with the header's size.
|
||||
* \sa PDU::header_size
|
||||
*/
|
||||
uint32_t header_size() const { return sizeof(header_); }
|
||||
|
||||
/**
|
||||
* \brief Getter for the PDU's type.
|
||||
* \sa PDU::pdu_type
|
||||
*/
|
||||
PDUType pdu_type() const { return pdu_flag; }
|
||||
|
||||
/**
|
||||
* \sa PDU::clone
|
||||
*/
|
||||
VXLAN *clone() const { return new VXLAN(*this); }
|
||||
|
||||
private:
|
||||
TINS_BEGIN_PACK
|
||||
struct vxlan_header {
|
||||
uint32_t flags;
|
||||
uint32_t vni;
|
||||
} TINS_END_PACK;
|
||||
|
||||
void write_serialization(uint8_t* buffer, uint32_t total_sz);
|
||||
|
||||
vxlan_header header_;
|
||||
};
|
||||
|
||||
} // Tins
|
||||
|
||||
#endif // TINS_VXLAN_H
|
||||
@@ -73,6 +73,7 @@ set(SOURCES
|
||||
utils/routing_utils.cpp
|
||||
utils/resolve_utils.cpp
|
||||
utils/pdu_utils.cpp
|
||||
vxlan.cpp
|
||||
)
|
||||
|
||||
set(HEADERS
|
||||
|
||||
36
src/vxlan.cpp
Normal file
36
src/vxlan.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
#include <tins/internals.h>
|
||||
#include <tins/memory_helpers.h>
|
||||
#include <tins/small_uint.h>
|
||||
#include <tins/vxlan.h>
|
||||
|
||||
using Tins::Memory::InputMemoryStream;
|
||||
using Tins::Memory::OutputMemoryStream;
|
||||
|
||||
namespace Tins {
|
||||
|
||||
VXLAN::VXLAN(const small_uint<24> vni) {
|
||||
set_flags(8);
|
||||
set_vni(vni);
|
||||
}
|
||||
|
||||
VXLAN::VXLAN(const uint8_t* buffer, uint32_t total_sz) {
|
||||
InputMemoryStream stream(buffer, total_sz);
|
||||
stream.read(header_);
|
||||
// If there is any size left
|
||||
if (stream) {
|
||||
inner_pdu(
|
||||
Internals::pdu_from_flag(
|
||||
PDU::ETHERNET_II,
|
||||
stream.pointer(),
|
||||
stream.size()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void VXLAN::write_serialization(uint8_t* buffer, uint32_t total_sz) {
|
||||
OutputMemoryStream stream(buffer, total_sz);
|
||||
stream.write(header_);
|
||||
}
|
||||
|
||||
} // Tins
|
||||
@@ -70,6 +70,7 @@ CREATE_TEST(tcp)
|
||||
CREATE_TEST(tcp_ip)
|
||||
CREATE_TEST(udp)
|
||||
CREATE_TEST(utils)
|
||||
CREATE_TEST(vxlan)
|
||||
|
||||
IF(LIBTINS_ENABLE_PCAP)
|
||||
CREATE_TEST(offline_packet_filter)
|
||||
|
||||
90
tests/src/vxlan_test.cpp
Normal file
90
tests/src/vxlan_test.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <string>
|
||||
#include <tins/ethernetII.h>
|
||||
#include <tins/ip.h>
|
||||
#include <tins/tcp.h>
|
||||
#include <tins/udp.h>
|
||||
#include <tins/pdu.h>
|
||||
#include <tins/small_uint.h>
|
||||
#include <tins/vxlan.h>
|
||||
|
||||
#define PACKET_SIZE 68ul
|
||||
|
||||
using namespace std;
|
||||
using namespace Tins;
|
||||
|
||||
class VXLANTest : public testing::Test {
|
||||
public:
|
||||
static const uint8_t expected_packet[PACKET_SIZE];
|
||||
static const uint8_t flags;
|
||||
static const uint16_t dport, sport, p_type;
|
||||
static const small_uint<24> vni;
|
||||
static const IP::address_type dst_ip, src_ip;
|
||||
static const EthernetII::address_type dst_addr, src_addr;
|
||||
};
|
||||
|
||||
const uint8_t VXLANTest::expected_packet[PACKET_SIZE] = {
|
||||
0x08, 0x00, 0x00, 0x00,
|
||||
0xff, 0xff, 0xff, 0x00,
|
||||
0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
|
||||
0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
const uint8_t VXLANTest::flags = 8;
|
||||
const uint16_t VXLANTest::dport = 19627;
|
||||
const uint16_t VXLANTest::sport = 4789;
|
||||
const uint16_t VXLANTest::p_type = 0xd0ab;
|
||||
const small_uint<24> VXLANTest::vni = 0xffffff;
|
||||
const IP::address_type VXLANTest::dst_ip = IP::address_type{"2.2.2.2"};
|
||||
const IP::address_type VXLANTest::src_ip = IP::address_type{"1.1.1.1"};
|
||||
const EthernetII::address_type VXLANTest::dst_addr = EthernetII::address_type{"aa:bb:cc:dd:ee:ff"};
|
||||
const EthernetII::address_type VXLANTest::src_addr = EthernetII::address_type{"8a:8b:8c:8d:8e:8f"};
|
||||
|
||||
TEST_F(VXLANTest, Flags) {
|
||||
auto const vxlan = VXLAN{};
|
||||
EXPECT_EQ(vxlan.get_flags(), flags);
|
||||
}
|
||||
|
||||
TEST_F(VXLANTest, VNI) {
|
||||
auto const vxlan = VXLAN{vni};
|
||||
EXPECT_EQ(vxlan.get_vni(), vni);
|
||||
}
|
||||
|
||||
TEST_F(VXLANTest, Find) {
|
||||
auto const pdu = VXLAN{} / EthernetII{dst_addr, src_addr};
|
||||
auto const eth = pdu.find_pdu<EthernetII>();
|
||||
ASSERT_TRUE(eth != nullptr);
|
||||
EXPECT_EQ(eth->dst_addr(), dst_addr);
|
||||
EXPECT_EQ(eth->src_addr(), src_addr);
|
||||
}
|
||||
|
||||
TEST_F(VXLANTest, Serialize) {
|
||||
auto eth = EthernetII{dst_addr, src_addr};
|
||||
eth.payload_type(p_type);
|
||||
auto vxlan = VXLAN{vni};
|
||||
vxlan.inner_pdu(eth);
|
||||
auto serialized = vxlan.serialize();
|
||||
ASSERT_EQ(serialized.size(), PACKET_SIZE);
|
||||
EXPECT_TRUE(std::equal(serialized.begin(), serialized.end(), expected_packet));
|
||||
}
|
||||
|
||||
TEST_F(VXLANTest, ConstructorFromBuffer) {
|
||||
auto vxlan = VXLAN{expected_packet, PACKET_SIZE};
|
||||
EXPECT_EQ(vxlan.get_vni(), vni);
|
||||
EXPECT_EQ(vxlan.get_flags(), flags);
|
||||
auto const eth = vxlan.find_pdu<EthernetII>();
|
||||
ASSERT_TRUE(eth != nullptr);
|
||||
EXPECT_EQ(eth->dst_addr(), dst_addr);
|
||||
EXPECT_EQ(eth->src_addr(), src_addr);
|
||||
}
|
||||
|
||||
TEST_F(VXLANTest, OuterUDP) {
|
||||
auto pkt = IP{dst_ip, src_ip} / UDP{dport, sport} / VXLAN{expected_packet, PACKET_SIZE};
|
||||
auto const vxlan = pkt.find_pdu<VXLAN>();
|
||||
ASSERT_TRUE(vxlan != nullptr);
|
||||
EXPECT_EQ(vxlan->get_flags(), flags);
|
||||
EXPECT_EQ(vxlan->get_vni(), vni);
|
||||
}
|
||||
Reference in New Issue
Block a user