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>
29#include <l4/virtio-net-switch/stats.h>
57using Ds_vector = std::vector<L4::Cap<L4Re::Dataspace>>;
58static std::shared_ptr<Ds_vector> trusted_dataspaces;
61parse_int_param(
L4::Ipc::Varg const ¶m,
char const *prefix,
int *out)
65 if (param.
length() < headlen)
68 char const *pstr = param.
value<
char const *>();
70 if (strncmp(pstr, prefix, headlen) != 0)
73 std::string tail(pstr + headlen, param.
length() - headlen);
75 if (!parse_int_optstring(tail.c_str(), out))
77 Err(Err::Normal).printf(
"Bad parameter '%s'. Invalid number specified.\n",
88 static bool initialized =
false;
96 for (
int i = 0; i < 6; i++)
125 {
return _device_notify_irq; }
128 Port(
unsigned vq_max,
unsigned num_ds,
char const *name,
148 { server.registry()->unregister_obj(
this); }
154 class Switch_port :
public Port
182 : _switch{virtio_switch}, _port{port} {}
186 Kick_irq _reschedule_tx_irq;
190 Virtio_switch *virtio_switch,
unsigned vq_max,
unsigned num_ds,
192 : Port(vq_max, num_ds, name, mac),
193 _kick_irq(virtio_switch,
this),
194 _reschedule_tx_irq(virtio_switch,
this)
196 register_end_points(registry, &_kick_irq);
198 _pending_tx_reschedule =
200 "Register TX reschedule IRQ.");
201 _pending_tx_reschedule->unmask();
204 virtual ~Switch_port()
208 ->unmap(_kick_irq.obj_cap().fpage(),
210 server.registry()->unregister_obj(&_kick_irq);
213 ->unmap(_pending_tx_reschedule.fpage(),
215 server.registry()->unregister_obj(&_reschedule_tx_irq);
222 class Monitor_port :
public Port
245 _port->
tx_q()->disable_notify();
246 _port->
rx_q()->disable_notify();
250 _port->
tx_q()->enable_notify();
251 _port->
rx_q()->enable_notify();
266 unsigned vq_max,
unsigned num_ds,
char const *name,
268 : Port(vq_max, num_ds, name, mac), _kick_irq(
this)
269 { register_end_points(registry, &_kick_irq); }
271 virtual ~Monitor_port()
275 ->unmap(_kick_irq.obj_cap().fpage(),
277 server.registry()->unregister_obj(&_kick_irq);
285 :
public cxx::D_list_item,
286 public L4::Epiface_t<Stats_reader, Virtio_net_switch::Statistics_if>
294 l4_size_t size = Switch_statistics::get_instance().size();
295 _ds = L4Re::Util::make_unique_cap<L4Re::Dataspace>();
297 "Could not allocate shared mem ds.");
303 memset(
reinterpret_cast<void*
>(_addr), 0, _ds->size());
309 server.registry()->unregister_obj(
this);
312 long op_get_buffer(Virtio_net_switch::Statistics_if::Rights,
322 long op_sync(Virtio_net_switch::Statistics_if::Rights)
324 memcpy(
reinterpret_cast<void *
>(_addr),
325 reinterpret_cast<void *
>(Switch_statistics::get_instance().stats()),
326 Switch_statistics::get_instance().size());
334 class Stats_reader_list
336 cxx::D_list<Stats_reader> _readers;
341 auto it = _readers.begin();
342 while (it != _readers.end())
345 if (!reader->is_valid())
347 it = _readers.erase(it);
355 void push_back(cxx::unique_ptr<Stats_reader> reader)
357 _readers.push_back(reader.release());
364 struct Del_cap_irq :
public L4::Irqep_t<Del_cap_irq>
369 _switch->check_ports();
370 _stats_readers->check_readers();
373 Del_cap_irq(
Virtio_switch *virtio_switch, Stats_reader_list *stats_readers)
374 : _switch{virtio_switch},
375 _stats_readers{stats_readers}
380 Stats_reader_list *_stats_readers;
386 unsigned _vq_max_num;
387 Stats_reader_list _stats_readers;
388 Del_cap_irq _del_cap_irq;
406 char *name,
size_t size,
408 std::vector<l4_uint16_t> &vlan_trunk,
409 bool *vlan_trunk_all,
412 assert(opt.
is_of<
char const *>());
413 unsigned len = opt.
length();
414 const char *opt_str = opt.
data();
415 Err err(Err::Normal);
420 if (!strncmp(
"type=", opt_str, 5))
422 if (!strncmp(
"type=monitor", opt_str, len))
427 else if (!strncmp(
"type=none", opt_str, len))
430 err.printf(
"Unknown type '%.*s'\n", opt.
length() - 5, opt.
data() + 5);
433 else if (!strncmp(
"name=", opt_str, 5))
435 snprintf(name, size,
"%.*s", opt.
length() - 5, opt.
data() + 5);
438 else if (!strncmp(
"vlan=", opt_str, 5))
440 cxx::String str(opt_str + 5, strnlen(opt_str + 5, len - 5));
448 if (next && next == str.
len() && vlan_valid_id(vid))
452 err.printf(
"Invalid VLAN access port id '%.*s'\n",
464 *vlan_trunk_all =
true;
469 if (!vlan_valid_id(vid))
471 vlan_trunk.push_back(vid);
472 if (next < str.
len() && str[next] !=
',')
477 if (vlan_trunk.empty() || !str.
empty())
479 err.printf(
"Invalid VLAN trunk port spec '%.*s'\n",
486 err.printf(
"Invalid VLAN specification..\n");
492 else if (!strncmp(
"mac=", opt_str, 4))
494 size_t const OPT_LEN = 4 + 6*2 + 5 ;
496 if (len > OPT_LEN && opt_str[OPT_LEN] ==
'\0' &&
497 sscanf(opt_str+4,
"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &mac[0],
498 &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]) == 6)
504 err.printf(
"Invalid mac address '%.*s'\n", len - 4, opt_str + 4);
509 err.printf(
"Unknown option '%.*s'\n", opt.
length(), opt.
data());
515 : _virtio_switch{virtio_switch}, _vq_max_num{vq_max_num},
516 _del_cap_irq{virtio_switch, &_stats_readers}
518 auto c =
L4Re::chkcap(server.registry()->register_irq_obj(&_del_cap_irq));
534 return create_port(res, va);
536 return create_stats(res);
538 Dbg(Dbg::Core, Dbg::Warn).printf(
"op_create: Invalid object type\n");
545 Dbg warn(Dbg::Port, Dbg::Warn,
"Port");
546 Dbg info(Dbg::Port, Dbg::Info,
"Port");
548 info.printf(
"Incoming port request\n");
550 bool monitor =
false;
554 std::vector<l4_uint16_t> vlan_trunk;
555 bool vlan_trunk_all =
false;
558 bool mac_set =
false;
563 if (!opt.
is_of<
char const *>())
565 warn.printf(
"Unexpected type for argument %d\n", arg_n);
569 if (parse_int_param(opt,
"ds-max=", &num_ds))
571 if (num_ds <= 0 || num_ds > 80)
573 Err(Err::Normal).printf(
"warning: client requested invalid number"
574 " of data spaces: 0 < %d <= 80\n", num_ds);
578 else if (!handle_opt_arg(opt, monitor, name,
sizeof(name), vlan_access,
579 vlan_trunk, &vlan_trunk_all, mac, mac_set))
588 warn.printf(
"No port available\n");
592 if (vlan_access && (!vlan_trunk.empty() || vlan_trunk_all))
594 warn.printf(
"VLAN port cannot be access and trunk simultaneously.\n");
599 snprintf(name,
sizeof(name),
"%s[%d]", monitor ?
"monitor" :
"",
602 info.printf(
" Creating port %s%s\n", name,
603 monitor ?
" as monitor port" :
"");
607 if (!mac_set && Options::get_options()->assign_mac())
608 assign_random_mac(mac);
610 l4_uint8_t *mac_ptr = (mac_set || Options::get_options()->assign_mac())
617 port =
new Monitor_port(server.registry(), _vq_max_num, num_ds, name,
622 warn.printf(
"vlan=access=<id> ignored on monitor ports!\n");
623 if (!vlan_trunk.empty())
624 warn.printf(
"vlan=trunk=... ignored on monitor ports!\n");
628 port =
new Switch_port(server.registry(), _virtio_switch, _vq_max_num,
629 num_ds, name, mac_ptr);
632 port->set_vlan_access(vlan_access);
633 else if (vlan_trunk_all)
634 port->set_vlan_trunk_all();
635 else if (!vlan_trunk.empty())
636 port->set_vlan_trunk(vlan_trunk);
639 port->add_trusted_dataspaces(trusted_dataspaces);
640 if (!trusted_dataspaces->empty())
641 port->enable_trusted_ds_validation();
653 info.printf(
" Created port %s\n", name);
661 auto reader = cxx::make_unique<Stats_reader>();
662 L4Re::chkcap(server.registry()->register_obj(reader.get()));
663 reader->obj_cap()->dec_refcnt(1);
666 _stats_readers.push_back(cxx::move(reader));
675class Ixl_hw_port :
public Ixl_port
677 template<
typename Derived>
682 : _switch{virtio_switch}, _port{port} {}
689 class Receive_irq :
public Port_irq<Receive_irq>
692 using Port_irq::Port_irq;
702 if (!_port->dev()->check_recv_irq(0))
705 if (_switch->handle_ixl_port_tx(_port))
706 _port->dev()->ack_recv_irq(0);
710 class Reschedule_tx_irq :
public Port_irq<Reschedule_tx_irq>
713 using Port_irq::Port_irq;
717 if (_switch->handle_ixl_port_tx(_port))
719 _port->dev()->ack_recv_irq(0);
723 Receive_irq _recv_irq;
724 Reschedule_tx_irq _reschedule_tx_irq;
730 _recv_irq(virtio_switch, this),
731 _reschedule_tx_irq(virtio_switch, this)
735 "Register receive IRQ.");
736 recv_irq_cap->unmask();
738 _pending_tx_reschedule =
740 "Register TX reschedule IRQ.");
741 _pending_tx_reschedule->unmask();
744 ~Ixl_hw_port()
override
746 server.registry()->unregister_obj(&_recv_irq);
753 struct Ixl::Dev_cfg cfg;
755 cfg.irq_timeout_ms = -1;
759 Ixl::Ixl_device *dev = Ixl::Ixl_device::ixl_init(vbus, 0, cfg);
764 Ixl_hw_port *hw_port =
new Ixl_hw_port(server.registry(), virtio_switch, dev);
765 if (!virtio_switch->
add_port(hw_port))
767 Err().printf(
"error adding ixl port\n");
773int main(
int argc,
char *argv[])
775 trusted_dataspaces = std::make_shared<Ds_vector>();
776 auto *opts = Options::parse_options(argc, argv, trusted_dataspaces);
779 Err().printf(
"Error during command line parsing.\n");
784 if (Dbg(Dbg::Core, Dbg::Warn).is_active())
785 printf(
"Hello from l4virtio switch\n");
789#ifdef CONFIG_VNS_STATS
790 Switch_statistics::get_instance().initialize(opts->get_max_ports());
796 discover_ixl_devices(vbus, virtio_switch);
800 opts->get_virtq_max_num());
802 L4::Cap<void> cap = server.registry()->register_obj(factory,
"svr");
805 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.
l4_kernel_info_t const * l4re_kip(void) L4_NOTHROW
Get Kernel Info Page.
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_cpu_time_t l4_kip_clock(l4_kernel_info_t const *kip) L4_NOTHROW
Return clock value from the KIP.
@ 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.