Loading...
Searching...
No Matches
port.h
/*
* Copyright (C) 2016-2018, 2020, 2022-2024 Kernkonzept GmbH.
* Author(s): Jean Wolter <jean.wolter@kernkonzept.com>
* Alexander Warg <warg@os.inf.tu-dresden.de>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include "request.h"
#include "mac_addr.h"
#include "vlan.h"
#include "stats.h"
#include <cassert>
#include <set>
#include <vector>
class Port_iface
{
protected:
Virtio_net_switch::Port_statistics *_stats;
public:
Port_iface(char const *name)
{
strncpy(_name, name, sizeof(_name));
_name[sizeof(_name) - 1] = '\0';
#ifdef CONFIG_VNS_STATS
_stats = Switch_statistics::get_instance().allocate_port_statistics(name);
if (!_stats)
throw L4::Runtime_error(-L4_ENOMEM,
"Could not allocate port statistics.\n");
#endif
}
virtual ~Port_iface()
{
#ifdef CONFIG_VNS_STATS
_stats->in_use = false;
#endif
}
// delete copy and assignment
Port_iface(Port_iface const &) = delete;
Port_iface &operator = (Port_iface const &) = delete;
char const *get_name() const
{ return _name; }
l4_uint16_t get_vlan() const
{ return _vlan_id; }
inline bool is_trunk() const
{ return _vlan_id == VLAN_ID_TRUNK; }
inline bool is_native() const
{ return _vlan_id == VLAN_ID_NATIVE; }
inline bool is_access() const
{ return !is_trunk() && !is_native(); }
void set_vlan_access(l4_uint16_t id)
{
assert(vlan_valid_id(id));
_vlan_id = id;
_vlan_bloom_filter = 0;
_vlan_ids.clear();
}
void set_vlan_trunk(const std::vector<l4_uint16_t> &ids)
{
// bloom filter to quickly reject packets that do not belong to this port
l4_uint32_t filter = 0;
_vlan_ids.clear();
for (const auto id : ids)
{
assert(vlan_valid_id(id));
filter |= vlan_bloom_hash(id);
_vlan_ids.insert(id);
}
_vlan_id = VLAN_ID_TRUNK;
_vlan_bloom_filter = filter;
}
void set_vlan_trunk_all()
{
_vlan_all = true;
_vlan_id = VLAN_ID_TRUNK;
_vlan_bloom_filter = -1;
}
void set_monitor()
{
_vlan_id = VLAN_ID_TRUNK;
_vlan_bloom_filter = 0;
}
bool match_vlan(uint16_t id)
{
// Regular case native/access port
if (id == _vlan_id)
return true;
// This port participates in all VLANs
if (_vlan_all)
return true;
// Quick check: does port probably accept this VLAN?
if ((_vlan_bloom_filter & vlan_bloom_hash(id)) == 0)
return false;
return _vlan_ids.find(id) != _vlan_ids.end();
}
inline Mac_addr mac() const
{ return _mac; }
Virtio_vlan_mangle create_vlan_mangle(Port_iface *src_port) const
{
Virtio_vlan_mangle mangle;
if (is_trunk())
{
/*
* Add a VLAN tag only if the packet does not already have one (by
* coming from another trunk port) or if the packet does not belong to
* any VLAN (by coming from a native port). The latter case is only
* relevant if this is a monitor port. Otherwise traffic from native
* ports is never forwarded to trunk ports.
*/
if (!src_port->is_trunk() && !src_port->is_native())
mangle = Virtio_vlan_mangle::add(src_port->get_vlan());
}
else
/*
* Remove VLAN tag only if the packet actually has one (by coming from a
* trunk port).
*/
if (src_port->is_trunk())
mangle = Virtio_vlan_mangle::remove();
return mangle;
}
virtual void rx_notify_disable_and_remember() = 0;
virtual void rx_notify_emit_and_enable() = 0;
virtual bool is_gone() const = 0;
// std::optional<Net_request> get_tx_request() = 0;
enum class Result
{
Delivered, Exception, Dropped,
};
virtual Result handle_request(Port_iface *src_port,
Net_transfer &src,
l4_uint64_t *bytes_transferred) = 0;
void reschedule_pending_tx()
{ _pending_tx_reschedule->trigger(); }
protected:
/*
* VLAN related management information.
*
* A port may either be
* - a native port (_vlan_id == VLAN_ID_NATIVE), or
* - an access port (_vlan_id set accordingly), or
* - a trunk port (_vlan_id == VLAN_ID_TRUNK, _vlan_bloom_filter and
* _vlan_ids populated accordingly, or _vlan_all == true).
*/
l4_uint16_t _vlan_id = VLAN_ID_NATIVE; // VID for native/access port
l4_uint32_t _vlan_bloom_filter = 0; // Bloom filter for trunk ports
std::set<l4_uint16_t> _vlan_ids; // Authoritative list of trunk VLANs
bool _vlan_all; // This port participates in all VLANs (ignoring _vlan_ids)
inline l4_uint32_t vlan_bloom_hash(l4_uint16_t vid)
{ return 1UL << (vid & 31U); }
L4::Cap<L4::Irq> _pending_tx_reschedule;
Mac_addr _mac = Mac_addr(Mac_addr::Addr_unknown);
char _name[20];
public:
#ifdef CONFIG_VNS_STATS
inline void stat_inc_tx_num()
{ _stats->tx_num++; }
inline void stat_inc_tx_dropped()
{ _stats->tx_dropped++; }
inline void stat_inc_tx_bytes(l4_uint64_t bytes)
{ _stats->tx_bytes += bytes; }
inline void stat_inc_rx_num()
{ _stats->rx_num++; }
inline void stat_inc_rx_dropped()
{ _stats->rx_dropped++; }
inline void stat_inc_rx_bytes(l4_uint64_t bytes)
{ _stats->rx_bytes += bytes; }
#else
inline void stat_inc_tx_num()
{}
inline void stat_inc_tx_dropped()
{}
inline void stat_inc_tx_bytes(l4_uint64_t /*bytes*/)
{}
inline void stat_inc_rx_num()
{}
inline void stat_inc_rx_dropped()
{}
inline void stat_inc_rx_bytes(l4_uint64_t /*bytes*/)
{}
#endif
};
Virtio_vlan_mangle::remove
static constexpr Virtio_vlan_mangle remove()
Construct an object that removes the VLAN tag.
Definition vlan.h:75
Virtio_vlan_mangle::add
static constexpr Virtio_vlan_mangle add(l4_uint16_t tci)
Construct an object that adds a VLAN tag.
Definition vlan.h:64
l4_uint32_t
unsigned int l4_uint32_t
Unsigned 32bit value.
Definition l4int.h:29
l4_uint16_t
unsigned short int l4_uint16_t
Unsigned 16bit value.
Definition l4int.h:27
l4_uint64_t
unsigned long long l4_uint64_t
Unsigned 64bit value.
Definition l4int.h:31
L4_ENOMEM
@ L4_ENOMEM
No memory.
Definition err.h:39