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
 
  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();
 
  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>
 
  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());
 
  514  Switch_factory(
Virtio_switch *virtio_switch, 
unsigned vq_max_num)
 
  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))
 
  585    int port_num = _virtio_switch->port_available(monitor);
 
  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();
 
  644    bool added = monitor ? _virtio_switch->add_monitor_port(port)
 
  645                         : _virtio_switch->add_port(port);
 
  653    info.printf(
"    Created port %s\n", name);
 
  657  long create_stats(L4::Ipc::Cap<void> &res)
 
  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>
 
  678  class Port_irq : 
public L4::Irqep_t<Derived>
 
  681    Port_irq(Virtio_switch *virtio_switch, Ixl_port *port)
 
  682    : _switch{virtio_switch}, _port{port} {}
 
  685    Virtio_switch *_switch;
 
  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;
 
  727  Ixl_hw_port(L4Re::Util::Object_registry *registry,
 
  728              Virtio_switch *virtio_switch, Ixl::Ixl_device *dev)
 
  730    _recv_irq(virtio_switch, this),
 
  731    _reschedule_tx_irq(virtio_switch, this)
 
  733    L4::Cap<L4::Irq> recv_irq_cap = 
L4Re::chkcap(dev->get_recv_irq(0), 
"Get receive IRQ");
 
  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.
 
l4_fpage_t fpage(unsigned rights=L4_CAP_FPAGE_RWS) const noexcept
Return flexpage for the capability.
 
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).
 
l4_msgtag_t unmask(l4_utcb_t *utcb=l4_utcb()) noexcept
Unmask this IRQ.
 
l4_msgtag_t dec_refcnt(l4_mword_t diff, l4_utcb_t *utcb=l4_utcb())
Decrement the in kernel reference counter for the object.
 
Exception for an abstract runtime error.
 
The virtual bus (Vbus) interface.
 
virtual L4::Cap< L4::Irq > device_notify_irq() const
 
void enable_notify()
Clear the 'no notify' flag for this queue.
 
void disable_notify()
Set the 'no notify' flag for this queue.
 
A Port on the Virtio Net Switch.
 
void drop_requests()
Drop all requests pending in the transmission queue.
 
L4virtio_port(unsigned vq_max, unsigned num_ds, char const *name, l4_uint8_t const *mac)
Create a Virtio net port object.
 
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.
 
void check_ports()
Check validity of ports.
 
bool handle_l4virtio_port_tx(L4virtio_port *port)
Handle TX queue of the given port.
 
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 ...
 
Unique_cap< T > make_unique_cap()
Allocate a capability slot and wrap it in an Unique_cap.
 
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< L4virtio::Device > obj_cap() const
 
Epiface implementation for Kobject-based interface implementations.
 
Base class for interface implementations.
 
Epiface implementation for interrupt handlers.
 
Common task related definitions.