8#include <l4/re/util/meta>
9#include <l4/re/util/object_registry>
10#include <l4/re/util/br_manager>
15#include <l4/sys/cxx/ipc_epiface>
16#include <l4/sys/cxx/ipc_varg>
17#include <l4/cxx/dlist>
18#include <l4/cxx/string>
22#include <terminate_handler-l4>
28#include <l4/virtio-net-switch/stats.h>
56using Ds_vector = std::vector<L4::Cap<L4Re::Dataspace>>;
57static std::shared_ptr<Ds_vector> trusted_dataspaces;
60parse_int_param(
L4::Ipc::Varg const ¶m,
char const *prefix,
int *out)
64 if (param.
length() < headlen)
67 char const *pstr = param.
value<
char const *>();
69 if (strncmp(pstr, prefix, headlen) != 0)
72 std::string tail(pstr + headlen, param.
length() - headlen);
74 if (!parse_int_optstring(tail.c_str(), out))
76 Err(Err::Normal).printf(
"Bad parameter '%s'. Invalid number specified.\n",
106 {
return _device_notify_irq; }
109 Port(
unsigned vq_max,
unsigned num_ds,
char const *name,
129 { server.registry()->unregister_obj(
this); }
135 class Switch_port :
public Port
163 : _switch{virtio_switch}, _port{port} {}
167 Kick_irq _reschedule_tx_irq;
171 Virtio_switch *virtio_switch,
unsigned vq_max,
unsigned num_ds,
173 : Port(vq_max, num_ds, name, mac),
174 _kick_irq(virtio_switch,
this),
175 _reschedule_tx_irq(virtio_switch,
this)
177 register_end_points(registry, &_kick_irq);
179 _pending_tx_reschedule =
181 "Register TX reschedule IRQ.");
182 _pending_tx_reschedule->unmask();
185 virtual ~Switch_port()
189 ->unmap(_kick_irq.obj_cap().fpage(),
191 server.registry()->unregister_obj(&_kick_irq);
198 class Monitor_port :
public Port
221 _port->
tx_q()->disable_notify();
222 _port->
rx_q()->disable_notify();
226 _port->
tx_q()->enable_notify();
227 _port->
rx_q()->enable_notify();
242 unsigned vq_max,
unsigned num_ds,
char const *name,
244 : Port(vq_max, num_ds, name, mac), _kick_irq(
this)
245 { register_end_points(registry, &_kick_irq); }
247 virtual ~Monitor_port()
251 ->unmap(_kick_irq.obj_cap().fpage(),
253 server.registry()->unregister_obj(&_kick_irq);
261 :
public cxx::D_list_item,
262 public L4::Epiface_t<Stats_reader, Virtio_net_switch::Statistics_if>
270 l4_size_t size = Switch_statistics::get_instance().size();
271 _ds = L4Re::Util::make_unique_cap<L4Re::Dataspace>();
273 "Could not allocate shared mem ds.");
279 memset(
reinterpret_cast<void*
>(_addr), 0, _ds->size());
285 server.registry()->unregister_obj(
this);
288 long op_get_buffer(Virtio_net_switch::Statistics_if::Rights,
298 long op_sync(Virtio_net_switch::Statistics_if::Rights)
300 memcpy(
reinterpret_cast<void *
>(_addr),
301 reinterpret_cast<void *
>(Switch_statistics::get_instance().stats()),
302 Switch_statistics::get_instance().size());
310 class Stats_reader_list
312 cxx::D_list<Stats_reader> _readers;
317 auto it = _readers.begin();
318 while (it != _readers.end())
321 if (!reader->is_valid())
323 it = _readers.erase(it);
331 void push_back(cxx::unique_ptr<Stats_reader> reader)
333 _readers.push_back(reader.release());
340 struct Del_cap_irq :
public L4::Irqep_t<Del_cap_irq>
345 _switch->check_ports();
346 _stats_readers->check_readers();
349 Del_cap_irq(
Virtio_switch *virtio_switch, Stats_reader_list *stats_readers)
350 : _switch{virtio_switch},
351 _stats_readers{stats_readers}
356 Stats_reader_list *_stats_readers;
362 unsigned _vq_max_num;
363 Stats_reader_list _stats_readers;
364 Del_cap_irq _del_cap_irq;
382 char *name,
size_t size,
384 std::vector<l4_uint16_t> &vlan_trunk,
385 bool *vlan_trunk_all,
388 assert(opt.
is_of<
char const *>());
389 unsigned len = opt.
length();
390 const char *opt_str = opt.
data();
391 Err err(Err::Normal);
396 if (!strncmp(
"type=", opt_str, 5))
398 if (!strncmp(
"type=monitor", opt_str, len))
403 else if (!strncmp(
"type=none", opt_str, len))
406 err.printf(
"Unknown type '%.*s'\n", opt.
length() - 5, opt.
data() + 5);
409 else if (!strncmp(
"name=", opt_str, 5))
411 snprintf(name, size,
"%.*s", opt.
length() - 5, opt.
data() + 5);
414 else if (!strncmp(
"vlan=", opt_str, 5))
416 cxx::String str(opt_str + 5, strnlen(opt_str + 5, len - 5));
424 if (next && next == str.
len() && vlan_valid_id(vid))
428 err.printf(
"Invalid VLAN access port id '%.*s'\n",
440 *vlan_trunk_all =
true;
445 if (!vlan_valid_id(vid))
447 vlan_trunk.push_back(vid);
448 if (next < str.
len() && str[next] !=
',')
453 if (vlan_trunk.empty() || !str.
empty())
455 err.printf(
"Invalid VLAN trunk port spec '%.*s'\n",
462 err.printf(
"Invalid VLAN specification..\n");
468 else if (!strncmp(
"mac=", opt_str, 4))
470 size_t const OPT_LEN = 4 + 6*2 + 5 ;
472 if (len > OPT_LEN && opt_str[OPT_LEN] ==
'\0' &&
473 sscanf(opt_str+4,
"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &mac[0],
474 &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]) == 6)
480 err.printf(
"Invalid mac address '%.*s'\n", len - 4, opt_str + 4);
485 err.printf(
"Unknown option '%.*s'\n", opt.
length(), opt.
data());
491 : _virtio_switch{virtio_switch}, _vq_max_num{vq_max_num},
492 _del_cap_irq{virtio_switch, &_stats_readers}
494 auto c =
L4Re::chkcap(server.registry()->register_irq_obj(&_del_cap_irq));
510 return create_port(res, va);
512 return create_stats(res);
514 Dbg(Dbg::Core, Dbg::Warn).printf(
"op_create: Invalid object type\n");
521 Dbg warn(Dbg::Port, Dbg::Warn,
"Port");
522 Dbg info(Dbg::Port, Dbg::Info,
"Port");
524 info.printf(
"Incoming port request\n");
526 bool monitor =
false;
530 std::vector<l4_uint16_t> vlan_trunk;
531 bool vlan_trunk_all =
false;
538 l4_uint8_t mac[6] = { 0x02, 0x08, 0x0f, 0x2a, 0x00, 0x00 };
539 bool mac_set =
false;
544 if (!opt.
is_of<
char const *>())
546 warn.printf(
"Unexpected type for argument %d\n", arg_n);
550 if (parse_int_param(opt,
"ds-max=", &num_ds))
552 if (num_ds <= 0 || num_ds > 80)
554 Err(Err::Normal).printf(
"warning: client requested invalid number"
555 " of data spaces: 0 < %d <= 80\n", num_ds);
559 else if (!handle_opt_arg(opt, monitor, name,
sizeof(name), vlan_access,
560 vlan_trunk, &vlan_trunk_all, mac, mac_set))
569 warn.printf(
"No port available\n");
573 if (vlan_access && (!vlan_trunk.empty() || vlan_trunk_all))
575 warn.printf(
"VLAN port cannot be access and trunk simultaneously.\n");
580 snprintf(name,
sizeof(name),
"%s[%d]", monitor ?
"monitor" :
"",
583 info.printf(
" Creating port %s%s\n", name,
584 monitor ?
" as monitor port" :
"");
602 l4_uint8_t *mac_ptr = (mac_set || Options::get_options()->assign_mac())
609 port =
new Monitor_port(server.registry(), _vq_max_num, num_ds, name,
614 warn.printf(
"vlan=access=<id> ignored on monitor ports!\n");
615 if (!vlan_trunk.empty())
616 warn.printf(
"vlan=trunk=... ignored on monitor ports!\n");
620 port =
new Switch_port(server.registry(), _virtio_switch, _vq_max_num,
621 num_ds, name, mac_ptr);
624 port->set_vlan_access(vlan_access);
625 else if (vlan_trunk_all)
626 port->set_vlan_trunk_all();
627 else if (!vlan_trunk.empty())
628 port->set_vlan_trunk(vlan_trunk);
631 port->add_trusted_dataspaces(trusted_dataspaces);
632 if (!trusted_dataspaces->empty())
633 port->enable_trusted_ds_validation();
645 info.printf(
" Created port %s\n", name);
653 auto reader = cxx::make_unique<Stats_reader>();
654 L4Re::chkcap(server.registry()->register_obj(reader.get()));
655 reader->obj_cap()->dec_refcnt(1);
658 _stats_readers.push_back(cxx::move(reader));
667class Ixl_hw_port :
public Ixl_port
669 template<
typename Derived>
674 : _switch{virtio_switch}, _port{port} {}
681 class Receive_irq :
public Port_irq<Receive_irq>
684 using Port_irq::Port_irq;
694 if (!_port->dev()->check_recv_irq(0))
697 if (_switch->handle_ixl_port_tx(_port))
698 _port->dev()->ack_recv_irq(0);
702 class Reschedule_tx_irq :
public Port_irq<Reschedule_tx_irq>
705 using Port_irq::Port_irq;
709 if (_switch->handle_ixl_port_tx(_port))
711 _port->dev()->ack_recv_irq(0);
715 Receive_irq _recv_irq;
716 Reschedule_tx_irq _reschedule_tx_irq;
722 _recv_irq(virtio_switch, this),
723 _reschedule_tx_irq(virtio_switch, this)
727 "Register receive IRQ.");
728 recv_irq_cap->unmask();
730 _pending_tx_reschedule =
732 "Register TX reschedule IRQ.");
733 _pending_tx_reschedule->unmask();
736 ~Ixl_hw_port()
override
738 server.registry()->unregister_obj(&_recv_irq);
745 struct Ixl::Dev_cfg cfg;
747 cfg.irq_timeout_ms = -1;
751 Ixl::Ixl_device *dev = Ixl::Ixl_device::ixl_init(vbus, 0, cfg);
756 Ixl_hw_port *hw_port =
new Ixl_hw_port(server.registry(), virtio_switch, dev);
757 if (!virtio_switch->
add_port(hw_port))
759 Err().printf(
"error adding ixl port\n");
765int main(
int argc,
char *argv[])
767 trusted_dataspaces = std::make_shared<Ds_vector>();
768 auto *opts = Options::parse_options(argc, argv, trusted_dataspaces);
771 Err().printf(
"Error during command line parsing.\n");
776 if (Dbg(Dbg::Core, Dbg::Warn).is_active())
777 printf(
"Hello from l4virtio switch\n");
784 discover_ixl_devices(vbus, virtio_switch);
788 opts->get_virtq_max_num());
790#ifdef CONFIG_VNS_STATS
791 Switch_statistics::get_instance().initialize(opts->get_max_ports());
794 L4::Cap<void> cap = server.registry()->register_obj(factory,
"svr");
797 Err().printf(
"error registering switch\n");
static Env const * env() noexcept
Returns the initial environment for the current task.
L4::Cap< Rm > rm() const noexcept
Object-capability to the region map.
L4::Cap< T > get_cap(char const *name, unsigned l) const noexcept
Get the capability selector for the object named name.
A registry that manages server objects and their attached IPC gates for a single server loop for a sp...
L4::Cap< L4::Irq > register_irq_obj(L4::Epiface *o) override
Register a handler for an interrupt.
L4::Cap< void > register_obj(L4::Epiface *o, char const *service) override
Register a new server object to a pre-allocated receive endpoint.
A server loop object which has a Object_registry included.
bool is_valid() const noexcept
Test whether the capability is a valid capability index (i.e., not L4_INVALID_CAP).
C++ interface for capabilities.
Capability type for RPC interfaces (see L4::Cap<T>).
List of variable-sized RPC parameters as received by the server.
Variably sized RPC argument.
Va_type< V >::Ret_value value() const
unsigned length() const
Get the size of the RPC argument.
void data(char const *d)
Set Varg to indirect data value (usually in UTCB)
Exception for an abstract runtime error.
The virtual bus (Vbus) interface.
A Port on the Virtio Net Switch.
void drop_requests()
Drop all requests pending in the transmission queue.
bool tx_work_pending() const
Check whether there is any work pending on the transmission queue.
The IPC interface for creating ports.
long op_create(L4::Factory::Rights, L4::Ipc::Cap< void > &res, l4_umword_t type, L4::Ipc::Varg_list_ref va)
Handle factory protocol.
Virtqueue * rx_q()
Getter for the receive queue.
Virtqueue * tx_q()
Getter for the transmission queue.
The Virtio switch contains all ports and processes network requests.
bool add_monitor_port(Port_iface *port)
Add a monitor port to the switch.
bool handle_l4virtio_port_tx(L4virtio_port *port)
Handle TX queue of the given port.
int port_available(bool monitor)
Is there still a free port on this switch available?
bool add_port(Port_iface *port)
Add a port to the switch.
Allocation free string class with explicit length field.
bool empty() const
Check if the string has length zero.
String substr(unsigned long idx, unsigned long len=~0UL) const
Substring of length len starting at idx.
char const * Index
Character index type.
int from_dec(INT *v) const
Convert decimal string to integer.
Index starts_with(cxx::String const &c) const
Check if c is a prefix of string.
Common factory related definitions.
unsigned int l4_size_t
Unsigned size type.
unsigned long l4_umword_t
Unsigned machine word.
unsigned long l4_addr_t
Address type.
unsigned char l4_uint8_t
Unsigned 8bit value.
unsigned short int l4_uint16_t
Unsigned 16bit value.
@ L4_EINVAL
Invalid argument.
@ L4_CAP_FPAGE_RO
Read right for capability flexpages.
@ L4_CAP_FPAGE_R
Read right for capability flexpages.
@ L4_CAP_FPAGE_RWSD
Full rights for capability flexpages.
@ L4_CAP_FPAGE_D
Delete right for capability flexpages.
@ L4_FP_DELETE_OBJ
Flag that indicates that an unmap operation on object capabilities shall try to delete the correspond...
@ L4_FP_ALL_SPACES
Flag to tell the unmap operation to revoke permissions from all child mappings including the mapping ...
L4::Detail::Unique_cap_impl< T, Smart_cap_auto< L4_FP_ALL_SPACES > > Unique_cap
Unique capability that implements automatic free and unmap of the capability selector.
long chksys(long err, char const *extra="", long ret=0)
Generate C++ exception on error.
T chkcap(T &&cap, char const *extra="", long err=-L4_ENOMEM)
Check for valid capability or raise C++ exception.
Cap< T > make_cap(L4::Cap< T > cap, unsigned rights) noexcept
Make an L4::Ipc::Cap<T> for the given capability and rights.
Cap< T > make_cap_rw(L4::Cap< T > cap) noexcept
Make an L4::Ipc::Cap<T> for the given capability with L4_CAP_FPAGE_RW rights.
@ RW
Readable and writable region.
@ Search_addr
Search for a suitable address range.
Cap< RPC_IFACE > obj_cap() const
Get the (typed) capability to this object.
Epiface implementation for Kobject-based interface implementations.
Base class for interface implementations.
Epiface implementation for interrupt handlers.
Common task related definitions.