Loading...
Searching...
No Matches
mac_table.h
/*
* Copyright (C) 2016-2017, 2020, 2022-2024 Kernkonzept GmbH.
* Author(s): Jean Wolter <jean.wolter@kernkonzept.com>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include "mac_addr.h"
#include "port.h"
#include <array>
#include <map>
#include <tuple>
#include <algorithm>
template<std::size_t Size = 1024U>
class Mac_table
{
public:
Mac_table()
: _mac_table(),
_entries(),
_rr_index(0U)
{}
Port_iface *lookup(Mac_addr dst, l4_uint16_t vlan_id) const
{
auto entry = _mac_table.find(std::tuple(dst, vlan_id));
return (entry != _mac_table.end()) ? entry->second->port : nullptr;
}
void learn(Mac_addr src, Port_iface *port, l4_uint16_t vlan_id)
{
Dbg info(Dbg::Port, Dbg::Info);
if (L4_UNLIKELY(info.is_active()))
{
// check whether we already know about src mac and vlan_id
auto *p = lookup(src, vlan_id);
if (!p || p != port)
{
info.printf("%s %-20s -> ", !p ? "learned " : "replaced",
port->get_name());
src.print(info);
info.cprintf("\n");
}
}
auto status = _mac_table.emplace(std::tuple(src, vlan_id),
&_entries[_rr_index]);
if (L4_UNLIKELY(status.second))
{
if (_entries[_rr_index].port)
{
// remove old entry
_mac_table.erase(std::tuple(_entries[_rr_index].addr,
_entries[_rr_index].vlan_id));
}
// Set/Replace port and mac address
_entries[_rr_index].port = port;
_entries[_rr_index].addr = src;
_entries[_rr_index].vlan_id = vlan_id;
_rr_index = (_rr_index + 1U) % Size;
}
else
{
// Update port to allow for movement of client between ports
status.first->second->port = port;
}
}
void flush(Port_iface *port)
{
typedef std::pair<std::tuple<const Mac_addr, l4_uint16_t>, Entry*> TableEntry;
auto iter = _mac_table.begin();
while ((iter = std::find_if(iter, _mac_table.end(),
[port](TableEntry const &p)
{ return p.second->port == port; }))
!= _mac_table.end())
{
iter->second->port = nullptr;
iter->second->addr = Mac_addr::Addr_unknown;
iter->second->vlan_id = 0;
iter = _mac_table.erase(iter);
}
assert(std::find_if(_mac_table.begin(), _mac_table.end(),
[port](TableEntry const &p)
{ return p.second->port == port; }) == _mac_table.end());
}
private:
struct Entry {
Port_iface *port;
Mac_addr addr;
l4_uint16_t vlan_id;
Entry()
: port(nullptr),
addr(Mac_addr::Addr_unknown),
vlan_id(0)
{}
};
std::map<std::tuple<Mac_addr, l4_uint16_t>, Entry*> _mac_table;
std::array<Entry, Size> _entries;
size_t _rr_index;
};
Mac_addr
A wrapper class around the value of a MAC address.
Definition mac_addr.h:20
Mac_table::lookup
Port_iface * lookup(Mac_addr dst, l4_uint16_t vlan_id) const
Find the destination port for a MAC address and VLAN id.
Definition mac_table.h:58
Mac_table::learn
void learn(Mac_addr src, Port_iface *port, l4_uint16_t vlan_id)
Learn a MAC address (add it to the MAC table).
Definition mac_table.h:78
Mac_table::flush
void flush(Port_iface *port)
Flush all associations with a given port.
Definition mac_table.h:129
l4_uint16_t
unsigned short int l4_uint16_t
Unsigned 16bit value.
Definition l4int.h:27
L4_UNLIKELY
#define L4_UNLIKELY(x)
Expression is unlikely to execute.
Definition compiler.h:284