SatCat5
eth_sw_vlan.cc
1 // Copyright 2024-2025 The Aerospace Corporation.
3 // This file is a part of SatCat5, licensed under CERN-OHL-W v2 or later.
5 
6 #include <satcat5/eth_sw_log.h>
7 #include <satcat5/eth_sw_vlan.h>
8 #include <satcat5/utils.h>
9 
25 
26 void SwitchVlanEgress::egress(PluginPacket& pkt) {
27  // Note the original VTAG value for later comparison.
28  auto vref = pkt.hdr.vtag;
29 
30  // Set VTAG fields based on incoming tag plus port defaults.
31  // Note: All tags have DEI and PCP fields, but VID is optional.
32  auto port_cfg = m_port->vlan_config();
33  u32 dst_pol = port_cfg.policy();
34  u16 dst_vid = pkt.hdr.vtag.vid() ? pkt.hdr.vtag.vid() : port_cfg.vtag().vid();
35  u16 dst_dei = pkt.hdr.vtag.any() ? pkt.hdr.vtag.dei() : port_cfg.vtag().dei();
36  u16 dst_pcp = pkt.hdr.vtag.any() ? pkt.hdr.vtag.pcp() : port_cfg.vtag().pcp();
37 
38  // Does the destination port require a tag? Format accordingly.
39  // See definition of each mode in "switch_cfg.h".
40  // Modified header will be written by eth::SwitchPort::data_rcvd(...).
41  if (dst_pol == satcat5::eth::VTAG_PRIORITY) {
42  // VTAG_PRIORITY emits tagged frames DEI and PCP only.
43  pkt.hdr.vtag.set(0, dst_dei, dst_pcp);
44  } else if (dst_pol == satcat5::eth::VTAG_MANDATORY) {
45  // VTAG_MANDATORY emits tagged frames with all fields.
46  pkt.hdr.vtag.set(dst_vid, dst_dei, dst_pcp);
47  } else {
48  // Other modes never emit tagged frames.
49  pkt.hdr.vtag.set(0, 0, 0);
50  }
51 
52  // Set the header-change flag?
53  if (pkt.hdr.vtag.value != vref.value) pkt.adjust();
54 }
55 
56 SwitchVlanInner::SwitchVlanInner(SwitchCore* sw, VlanPolicy* vptr, unsigned vmax, bool lockdown)
57  : PluginCore(sw)
58  , m_policy(vptr)
59  , m_vmax(vmax)
60 {
61  timer_every(1);
62  vlan_reset(lockdown);
63 }
64 
66  // Decode packet tags and source-port configuration.
67  u16 pkt_vid = pkt.hdr.vtag.vid();
68  u16 pkt_dei = pkt.hdr.vtag.dei();
69  u16 pkt_pcp = pkt.hdr.vtag.pcp();
70  u32 src_pol = pkt.port_vcfg().policy();
71 
72  // Is this packet following the source-port's tag policy?
73  // (See rule definitions in "switch_cfg.h")
74  bool tag_ok = (src_pol == VTAG_ADMIT_ALL)
75  || (src_pol == VTAG_RESTRICT && !pkt_vid)
76  || (src_pol == VTAG_PRIORITY && !pkt_vid)
77  || (src_pol == VTAG_MANDATORY && pkt_vid);
78 
79  // Use specified VLAN identifier or revert to default?
80  u16 dst_vid = pkt_vid ? pkt_vid : pkt.port_vcfg().vtag().vid();
81  if (dst_vid == 0 || dst_vid > m_vmax) tag_ok = false;
82 
83  // Set the priority level for this packet.
84  pkt.pkt->m_priority = pkt_pcp ? pkt_pcp : pkt.port_vcfg().vtag().pcp();
85 
86  // Did the packet come from a valid source port?
87  SATCAT5_PMASK_TYPE vmask = tag_ok ? m_policy[dst_vid-1].pmask : 0;
88  if ((vmask & pkt.src_mask()) == 0) tag_ok = false;
89 
90  // Drop this packet based on any of the above rules?
91  if (!tag_ok) {
93  return;
94  }
95 
96  // Decode and apply rate-control rules.
97  VlanPolicy& policy = m_policy[dst_vid-1];
98  u32 vpol = (policy.vrate.tok_policy & 0xFF000000u);
99  u32 scale = (policy.vrate.tok_policy & VRATE_SCALE_256X) ? 256 : 1;
100  u32 cost = satcat5::util::div_ceil(u32(pkt.length()), scale);
101 
102  if (cost > policy.tcount) {
103  // Apply rules to drop this packet or reduce its priority.
104  if ((vpol == VPOL_DEMOTE) || (vpol == VPOL_AUTO)) {
105  pkt.pkt->m_priority = 0;
106  }
107  if ((vpol == VPOL_STRICT) || (vpol == VPOL_AUTO && pkt_dei)) {
109  }
110  } else if (vpol != VPOL_UNLIMITED) {
111  // Pay the required number of tokens.
112  policy.tcount -= cost;
113  }
114 
115  // OK to forward this packet to any port(s) in this VLAN.
116  // (MAC-lookup and other plugins will decide which.)
117  pkt.dst_mask &= policy.pmask;
118 }
119 
120 void SwitchVlanInner::vlan_reset(bool lockdown) {
121  constexpr VlanPolicy VPOL_LOCK = {VRATE_8KBPS, VLAN_CONNECT_NONE, 0};
122  constexpr VlanPolicy VPOL_OPEN = {VRATE_UNLIMITED, VLAN_CONNECT_ALL, 0};
123 
124  // Reset each port with default policy and VID = 1.
125  unsigned pcount = m_switch->port_count();
126  u32 tags = lockdown ? VTAG_RESTRICT : VTAG_ADMIT_ALL;
127  for (unsigned port = 0 ; port < pcount ; ++port) {
128  satcat5::eth::VtagPolicy cfg(port, tags, satcat5::eth::VTAG_DEFAULT);
129  m_switch->get_port(port)->vlan_config(cfg);
130  }
131 
132  // Reset rate and connectivity for each VID.
133  VlanPolicy vpol = lockdown ? VPOL_LOCK : VPOL_OPEN;
134  for (unsigned vidx = 0 ; vidx < m_vmax ; ++vidx) {
135  m_policy[vidx] = vpol;
136  }
137 }
138 
140  if (vid == 0 || vid > m_vmax) return 0;
141  return m_policy[vid-1].pmask;
142 }
143 
145  if (vid == 0 || vid > m_vmax) return;
146  m_policy[vid-1].pmask = mask;
147 }
148 
150  auto port = m_switch->get_port(pidx);
151  return port ? port->vlan_config() : satcat5::eth::VCFG_DEFAULT;
152 }
153 
155  auto port = m_switch->get_port(cfg.port());
156  if (port) port->vlan_config(cfg);
157 }
158 
159 void SwitchVlanInner::vlan_join(u16 vid, unsigned port) {
160  if (vid == 0 || vid > m_vmax) return;
161  satcat5::util::set_mask(m_policy[vid-1].pmask, idx2mask(port));
162 }
163 
164 void SwitchVlanInner::vlan_leave(u16 vid, unsigned port) {
165  if (vid == 0 || vid > m_vmax) return;
166  satcat5::util::clr_mask(m_policy[vid-1].pmask, idx2mask(port));
167 }
168 
170  if (vid == 0 || vid > m_vmax) return;
171  m_policy[vid-1].vrate = cfg;
172  m_policy[vid-1].tcount = cfg.tok_max;
173 }
174 
176  // Increment the token-bucket counter for each VID.
177  for (unsigned a = 0 ; a < m_vmax ; ++a) {
178  m_policy[a].tcount = saturate_add(
179  m_policy[a].tcount,
180  m_policy[a].vrate.tok_rate,
181  m_policy[a].vrate.tok_max);
182  }
183 }
Ethernet switch plugin API.
Definition: eth_plugin.h:166
satcat5::eth::SwitchCore *const m_switch
Pointer to the associated SwitchCore object.
Definition: eth_plugin.h:183
satcat5::eth::SwitchPort *const m_port
Pointer to the associated SwitchPort object.
Definition: eth_plugin.h:224
A shared-memory Ethernet switch based on the MultiBuffer class.
Definition: eth_switch.h:93
satcat5::eth::SwitchPort * get_port(unsigned idx)
Fetch a SwitchPort object by port-index.
Definition: eth_switch.h:101
u32 port_count() const
Get the number of attached ports.
Definition: eth_switch.h:110
satcat5::eth::VtagPolicy vlan_config() const
Return this port's VLAN configuration.
Definition: eth_switch.h:304
Port plugin for egress formatting of Virtual-LAN tags.
Definition: eth_sw_vlan.h:25
Switch plugin for Virtual-LAN connectivity and rate-limiting rules.
Definition: eth_sw_vlan.h:44
void timer_event() override
Child class MUST override this method.
Definition: eth_sw_vlan.cc:175
void vlan_reset(bool lockdown=false)
Revert to default VLAN settings for all ports and VIDs.
Definition: eth_sw_vlan.cc:120
VtagPolicy vlan_get_port(unsigned port) const
Query a port's tag policy and other VLAN settings.
Definition: eth_sw_vlan.cc:149
SATCAT5_PMASK_TYPE vlan_get_mask(u16 vid)
Get allowed-connectivity port-mask for designated VID.
Definition: eth_sw_vlan.cc:139
void vlan_leave(u16 vid, unsigned port)
Port should leave VLAN, updating vlan_get_mask.
Definition: eth_sw_vlan.cc:164
void vlan_set_port(const VtagPolicy &cfg)
Set a port's tag policy and other VLAN settings.
Definition: eth_sw_vlan.cc:154
void vlan_join(u16 vid, unsigned port)
Port should join VLAN, updating vlan_get_mask.
Definition: eth_sw_vlan.cc:159
void vlan_set_rate(u16 vid, const satcat5::eth::VlanRate &cfg)
Set rate-limiting options for the designated VID.
Definition: eth_sw_vlan.cc:169
void vlan_set_mask(u16 vid, SATCAT5_PMASK_TYPE mask)
Limit the specified VID to the designated port(s).
Definition: eth_sw_vlan.cc:144
void query(PluginPacket &pkt) override
Packet-received callback.
Definition: eth_sw_vlan.cc:65
Diagnostic logging system for the Ethernet switch.
IEEE802.1Q Virtual-LAN plugin for the software-defined Ethernet switch.
#define SATCAT5_PMASK_TYPE
Set the integer type used to identify source and destination ports.
Definition: eth_switch.h:41
constexpr SATCAT5_PMASK_TYPE idx2mask(unsigned idx)
Macro converting port-index to a bit-mask.
Definition: eth_switch.h:53
An Ethernet frame header.
Definition: eth_header.h:167
satcat5::eth::VlanTag vtag
Ethernet header fields.
Definition: eth_header.h:173
Ephemeral data structure provided to plugin callbacks.
Definition: eth_plugin.h:48
satcat5::io::MultiPacket * pkt
Complete packet contents.
Definition: eth_plugin.h:51
void drop(u8 reason)
Drop this frame, indicating why.
Definition: eth_plugin.h:118
unsigned length() const
Accessors and shortcuts for packet metadata.
Definition: eth_plugin.h:137
SATCAT5_PMASK_TYPE dst_mask
Destination mask for which port(s) receive this packet.
Definition: eth_plugin.h:75
SATCAT5_PMASK_TYPE src_mask() const
Accessors and shortcuts for packet metadata.
Definition: eth_plugin.h:139
satcat5::eth::VtagPolicy port_vcfg() const
Accessors and shortcuts for packet metadata.
Definition: eth_plugin.h:143
satcat5::eth::Header hdr
Copy of Ethernet header fields.
Definition: eth_plugin.h:55
void adjust()
Notify parent that header contents have changed.
Definition: eth_plugin.h:105
A single 24-byte packet-log message.
Definition: eth_sw_log.h:74
static constexpr u8 DROP_VLAN
Virtual-LAN policy.
Definition: eth_sw_log.h:83
static constexpr u8 DROP_VRATE
Virtual-LAN rate limits.
Definition: eth_sw_log.h:84
Data structure for configuring VLAN rate-limiter parameters.
Definition: switch_cfg.h:107
u32 tok_max
Maximum accumulated tokens.
Definition: switch_cfg.h:110
u32 tok_policy
Policy and scaling.
Definition: switch_cfg.h:108
u16 pcp() const
Accessors for each individual field.
Definition: eth_header.h:137
u16 value
The 16-bit value holds VID, DEI, and PCP fields.
Definition: eth_header.h:126
bool any() const
Accessors for each individual field.
Definition: eth_header.h:134
u16 vid() const
Accessors for each individual field.
Definition: eth_header.h:135
void set(u16 vid, u16 dei, u16 pcp)
Accessors for each individual field.
Definition: eth_header.h:138
u16 dei() const
Accessors for each individual field.
Definition: eth_header.h:136
Data structure for configuring VLAN tagging policy of each port.
Definition: switch_cfg.h:68
u32 policy() const
Accessors for each individual field.
Definition: switch_cfg.h:75
unsigned port() const
Accessors for each individual field.
Definition: switch_cfg.h:77
satcat5::eth::VlanTag vtag() const
Accessors for each individual field.
Definition: switch_cfg.h:79
u16 m_priority
Packet priority.
Definition: multi_buffer.h:104
constexpr satcat5::eth::VtagPolicy VCFG_DEFAULT(0, VTAG_ADMIT_ALL, VTAG_DEFAULT)
Default VLAN tagging policy.
constexpr u32 VTAG_RESTRICT
Define VLAN policy modes for a given switch port.
Definition: switch_cfg.h:36
constexpr u32 VTAG_ADMIT_ALL
Define VLAN policy modes for a given switch port.
Definition: switch_cfg.h:35
constexpr u32 VPOL_UNLIMITED
Define VLAN rate-limiter modes for each VID.
Definition: switch_cfg.h:49
constexpr u32 VLAN_CONNECT_ALL
Common port-connection masks.
Definition: switch_cfg.h:63
constexpr u32 VLAN_CONNECT_NONE
Common port-connection masks.
Definition: switch_cfg.h:64
constexpr u32 VPOL_STRICT
Define VLAN rate-limiter modes for each VID.
Definition: switch_cfg.h:51
constexpr satcat5::eth::VlanRate VRATE_UNLIMITED(VPOL_UNLIMITED, 0, 0)
Define some commonly-used rate-limiter configurations.
constexpr satcat5::eth::VlanRate VRATE_8KBPS(VPOL_STRICT, 8000ull, 4096)
Define some commonly-used rate-limiter configurations.
constexpr u32 VTAG_MANDATORY
Define VLAN policy modes for a given switch port.
Definition: switch_cfg.h:38
constexpr u32 VPOL_AUTO
Define VLAN rate-limiter modes for each VID.
Definition: switch_cfg.h:52
constexpr u32 VTAG_PRIORITY
Define VLAN policy modes for a given switch port.
Definition: switch_cfg.h:37
constexpr u32 VPOL_DEMOTE
Define VLAN rate-limiter modes for each VID.
Definition: switch_cfg.h:50
Miscellaneous mathematical utility functions.
constexpr T saturate_add(T a, T b, T c=T(-1))
Unsigned add with saturation: min(A + B, C).
Definition: utils.h:250