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/string>
21#include <terminate_handler-l4>
54using Ds_vector = std::vector<L4::Cap<L4Re::Dataspace>>;
55static std::shared_ptr<Ds_vector> trusted_dataspaces;
58parse_int_param(
L4::Ipc::Varg const ¶m,
char const *prefix,
int *out)
62 if (param.
length() < headlen)
65 char const *pstr = param.
value<
char const *>();
67 if (strncmp(pstr, prefix, headlen) != 0)
70 std::string tail(pstr + headlen, param.
length() - headlen);
72 if (!parse_int_optstring(tail.c_str(), out))
74 Err(Err::Normal).printf(
"Bad paramter '%s'. Invalid number specified.\n",
104 {
return _device_notify_irq; }
107 Port(
unsigned vq_max,
unsigned num_ds,
char const *name,
127 { server.registry()->unregister_obj(
this); }
133 class Switch_port :
public Port
161 : _switch{virtio_switch}, _port{port} {}
168 Virtio_switch *virtio_switch,
unsigned vq_max,
unsigned num_ds,
170 : Port(vq_max, num_ds, name,
mac),
171 _kick_irq(virtio_switch,
this)
172 { register_end_points(registry, &_kick_irq); }
174 virtual ~Switch_port()
178 ->unmap(_kick_irq.obj_cap().fpage(),
180 server.registry()->unregister_obj(&_kick_irq);
187 class Monitor_port :
public Port
210 _port->
tx_q()->disable_notify();
211 _port->
rx_q()->disable_notify();
215 _port->
tx_q()->enable_notify();
216 _port->
rx_q()->enable_notify();
231 unsigned vq_max,
unsigned num_ds,
char const *name,
233 : Port(vq_max, num_ds, name,
mac), _kick_irq(
this)
234 { register_end_points(registry, &_kick_irq); }
236 virtual ~Monitor_port()
240 ->unmap(_kick_irq.obj_cap().fpage(),
242 server.registry()->unregister_obj(&_kick_irq);
249 struct Del_cap_irq :
public L4::Irqep_t<Del_cap_irq>
253 { _switch->check_ports(); }
255 Del_cap_irq(
Virtio_switch *virtio_switch) : _switch{virtio_switch} {}
264 unsigned _vq_max_num;
265 Del_cap_irq _del_cap_irq;
280 char *name,
size_t size,
282 std::vector<l4_uint16_t> &vlan_trunk,
285 assert(opt.
is_of<
char const *>());
286 unsigned len = opt.
length();
287 const char *opt_str = opt.
data();
288 Err err(Err::Normal);
293 if (!strncmp(
"type=", opt_str, 5))
295 if (!strncmp(
"type=monitor", opt_str, len))
300 else if (!strncmp(
"type=none", opt_str, len))
303 err.printf(
"Unknown type '%.*s'\n", opt.
length() - 5, opt.
data() + 5);
306 else if (!strncmp(
"name=", opt_str, 5))
308 snprintf(name, size,
"%.*s", opt.
length() - 5, opt.
data() + 5);
311 else if (!strncmp(
"vlan=", opt_str, 5))
313 cxx::String str(opt_str + 5, strnlen(opt_str + 5, len - 5));
321 if (next && next == str.
len() && vlan_valid_id(vid))
325 err.printf(
"Invalid VLAN access port id '%.*s'\n",
337 if (!vlan_valid_id(vid))
339 vlan_trunk.push_back(vid);
340 if (next < str.
len() && str[next] !=
',')
347 err.printf(
"Invalid VLAN trunk port spec '%.*s'\n",
354 err.printf(
"Invalid VLAN specification..\n");
360 else if (!strncmp(
"mac=", opt_str, 4))
362 size_t const OPT_LEN = 4 + 6*2 + 5 ;
364 if (len > OPT_LEN && opt_str[OPT_LEN] ==
'\0' &&
365 sscanf(opt_str+4,
"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &mac[0],
366 &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]) == 6)
372 err.printf(
"Invalid mac address '%.*s'\n", len - 4, opt_str + 4);
377 err.printf(
"Unknown option '%.*s'\n", opt.
length(), opt.
data());
383 : _virtio_switch{virtio_switch}, _vq_max_num{vq_max_num},
384 _del_cap_irq{virtio_switch}
386 auto c =
L4Re::chkcap(server.registry()->register_irq_obj(&_del_cap_irq));
399 Dbg warn(Dbg::Port, Dbg::Warn,
"Port");
400 Dbg info(Dbg::Port, Dbg::Info,
"Port");
402 info.printf(
"Incoming port request\n");
407 warn.printf(
"Invalid object type\n");
411 bool monitor =
false;
415 std::vector<l4_uint16_t> vlan_trunk;
422 l4_uint8_t mac[6] = { 0x02, 0x08, 0x0f, 0x2a, 0x00, 0x00 };
423 bool mac_set =
false;
428 if (!opt.
is_of<
char const *>())
430 warn.printf(
"Unexpected type for argument %d\n", arg_n);
434 if (parse_int_param(opt,
"ds-max=", &num_ds))
436 if (num_ds <= 0 || num_ds > 80)
438 Err(Err::Normal).printf(
"warning: client requested invalid number"
439 " of data spaces: 0 < %d <= 80\n", num_ds);
443 else if (!handle_opt_arg(opt, monitor, name,
sizeof(name), vlan_access,
444 vlan_trunk, mac, mac_set))
453 warn.printf(
"No port available\n");
457 if (vlan_access && !vlan_trunk.empty())
459 warn.printf(
"Port cannot be access and trunk VLAN port simultaneously.\n");
466 unsigned len = strlen(name);
467 snprintf(name + len,
sizeof(name) - len,
"[%d]", port_num);
470 snprintf(name,
sizeof(name),
"%s[%d]", monitor ?
"monitor" :
"",
473 info.printf(
" Creating port %s%s\n", name,
474 monitor ?
" as monitor port" :
"");
492 l4_uint8_t *mac_ptr = (mac_set || Options::get_options()->assign_mac())
499 port =
new Monitor_port(server.registry(), _vq_max_num, num_ds, name,
504 warn.printf(
"vlan=access=<id> ignored on monitor ports!\n");
505 if (!vlan_trunk.empty())
506 warn.printf(
"vlan=trunk=... ignored on monitor ports!\n");
510 port =
new Switch_port(server.registry(), _virtio_switch, _vq_max_num,
511 num_ds, name, mac_ptr);
514 port->set_vlan_access(vlan_access);
515 else if (!vlan_trunk.empty())
516 port->set_vlan_trunk(vlan_trunk);
519 port->add_trusted_dataspaces(trusted_dataspaces);
520 if (!trusted_dataspaces->empty())
521 port->enable_trusted_ds_validation();
533 info.printf(
" Created port %s\n", name);
539int main(
int argc,
char *argv[])
541 trusted_dataspaces = std::make_shared<Ds_vector>();
542 auto *opts = Options::parse_options(argc, argv, trusted_dataspaces);
545 Err().printf(
"Error during command line parsing.\n");
550 if (Dbg(Dbg::Core, Dbg::Warn).is_active())
551 printf(
"Hello from l4virtio switch\n");
555 opts->get_virtq_max_num());
556 L4::Cap<void> cap = server.registry()->register_obj(factory,
"svr");
559 Err().printf(
"error registering switch\n");
static Env const * env() noexcept
Returns the initial environment for the current task.
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 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.
A Port on the Virtio Net Switch.
bool tx_work_pending() const
Check whether there is any work pending on the transmission queue.
Mac_addr mac() const
Get MAC address.
void drop_requests()
Drop all requests pending in the transmission queue.
The Virtio switch contains all ports and processes network requests.
bool add_monitor_port(Virtio_port *port)
Add a monitor port to the switch.
bool add_port(Virtio_port *port)
Add a port to the switch.
void handle_port_irq(Virtio_port *port)
Handle an incoming irq on a given port.
int port_available(bool monitor)
Is there still a free port on this switch available?
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 char l4_uint8_t
Unsigned 8bit value.
unsigned short int l4_uint16_t
Unsigned 16bit value.
@ L4_EINVAL
Invalid argument.
@ L4_CAP_FPAGE_RWSD
Full rights 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 ...
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< 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.