L4Re Operating System Framework
Interface and Usage Documentation
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
mac_table.h
1/*
2 * Copyright (C) 2016-2017, 2020, 2022-2024 Kernkonzept GmbH.
3 * Author(s): Jean Wolter <jean.wolter@kernkonzept.com>
4 *
5 * License: see LICENSE.spdx (in this directory or the directories above)
6 */
7#pragma once
8
9#include "mac_addr.h"
10#include "port.h"
11
12#include <array>
13#include <map>
14#include <tuple>
15#include <algorithm>
39template<std::size_t Size = 1024U>
41{
42public:
43 Mac_table()
44 : _mac_table(),
45 _entries(),
46 _rr_index(0U)
47 {}
48
58 Port_iface *lookup(Mac_addr dst, l4_uint16_t vlan_id) const
59 {
60 auto entry = _mac_table.find(std::tuple(dst, vlan_id));
61 return (entry != _mac_table.end()) ? entry->second->port : nullptr;
62 }
63
78 void learn(Mac_addr src, Port_iface *port, l4_uint16_t vlan_id)
79 {
80 Dbg info(Dbg::Port, Dbg::Info);
81
82 if (L4_UNLIKELY(info.is_active()))
83 {
84 // check whether we already know about src mac and vlan_id
85 auto *p = lookup(src, vlan_id);
86 if (!p || p != port)
87 {
88 info.printf("%s %-20s -> ", !p ? "learned " : "replaced",
89 port->get_name());
90 src.print(info);
91 info.cprintf("\n");
92 }
93 }
94
95 auto status = _mac_table.emplace(std::tuple(src, vlan_id),
96 &_entries[_rr_index]);
97 if (L4_UNLIKELY(status.second))
98 {
99 if (_entries[_rr_index].port)
100 {
101 // remove old entry
102 _mac_table.erase(std::tuple(_entries[_rr_index].addr,
103 _entries[_rr_index].vlan_id));
104 }
105 // Set/Replace port and mac address
106 _entries[_rr_index].port = port;
107 _entries[_rr_index].addr = src;
108 _entries[_rr_index].vlan_id = vlan_id;
109 _rr_index = (_rr_index + 1U) % Size;
110 }
111 else
112 {
113 // Update port to allow for movement of client between ports
114 status.first->second->port = port;
115 }
116 }
117
129 void flush(Port_iface *port)
130 {
131 typedef std::pair<std::tuple<const Mac_addr, l4_uint16_t>, Entry*> TableEntry;
132
133 auto iter = _mac_table.begin();
134 while ((iter = std::find_if(iter, _mac_table.end(),
135 [port](TableEntry const &p)
136 { return p.second->port == port; }))
137 != _mac_table.end())
138 {
139 iter->second->port = nullptr;
140 iter->second->addr = Mac_addr::Addr_unknown;
141 iter->second->vlan_id = 0;
142 iter = _mac_table.erase(iter);
143 }
144
145 assert(std::find_if(_mac_table.begin(), _mac_table.end(),
146 [port](TableEntry const &p)
147 { return p.second->port == port; }) == _mac_table.end());
148 }
149
150private:
157 struct Entry {
158 Port_iface *port;
159 Mac_addr addr;
160 l4_uint16_t vlan_id;
161
162 Entry()
163 : port(nullptr),
164 addr(Mac_addr::Addr_unknown),
165 vlan_id(0)
166 {}
167 };
168
169 std::map<std::tuple<Mac_addr, l4_uint16_t>, Entry*> _mac_table;
170 std::array<Entry, Size> _entries;
171 size_t _rr_index;
172};
A wrapper class around the value of a MAC address.
Definition mac_addr.h:20
Mac_table manages a 1:n association between ports and MAC addresses.
Definition mac_table.h:41
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
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
void flush(Port_iface *port)
Flush all associations with a given port.
Definition mac_table.h:129
unsigned short int l4_uint16_t
Unsigned 16bit value.
Definition l4int.h:27
#define L4_UNLIKELY(x)
Expression is unlikely to execute.
Definition compiler.h:275