nic_router: replace term "uplink" with "NIC client"

BREAKS CONFIG COMPATIBILITY:
This commit changes the configuration interface of the NIC router in a way that
may break systems that use the component without proper adjustment!

HOW TO ADJUST:
At each occurrence of the '<uplink ...>' tag in a NIC router configuration
replace the tag name 'uplink' with 'nic-client'. The rest of the tag stays the
same.

The term "uplink" for network interfaces in the router that have a NIC session
client as back end was introduced in a time when Uplink sessions didn't yet
exist. Now, they do and, although both an uplink and an Uplink session
normally describe a network session between router and network device driver,
they are based on two different service types (NIC and Uplink). This can easily
cause confusion when integrating the router (the <uplink> is not related to
Uplink sessions) or trying to understand its functioning (an 'Uplink' object
has nothing to do with the Uplink service).

Therefore, this commit introduces the more specific term "NIC client" for an
interface that is based on a NIC session requested by the router. This doesn't
imply any semantic changes at the NIC router. However, the commit also brings a
broader update of the router's README and removes the term "downlink" that was
used only in documentation to refer to interfaces backed by a NIC session
provided by the router. The term was only associated with this meaning because
it is the natural counterpart to an uplink. This isn't appropriate anymore as
the terms for interface types have moved to a more technical level.

The commit adjusts all scenarios in the basic Genode repositories properly.

Fixes #4238
This commit is contained in:
Martin Stein 2021-07-27 13:52:21 +02:00 committed by Christian Helmuth
parent fce525f122
commit f8953de7ac
21 changed files with 617 additions and 563 deletions

View File

@ -196,7 +196,7 @@ proc test_7_config { } {
<config> <config>
<policy label_prefix="t7_d1" domain="downlink" /> <policy label_prefix="t7_d1" domain="downlink" />
<uplink domain="uplink" /> <nic-client domain="uplink" />
<domain name="uplink"> <domain name="uplink">
<nat domain="downlink" tcp-ports="6" /> <nat domain="downlink" tcp-ports="6" />
@ -312,7 +312,7 @@ append config {
link_state_triggers="yes" link_state_triggers="yes"
interval_sec="60" /> interval_sec="60" />
<uplink domain="uplink"/> <nic-client domain="uplink"/>
<domain name="uplink" <domain name="uplink"
interface="10.0.2.55/24" interface="10.0.2.55/24"

View File

@ -231,7 +231,7 @@ append config {
<report/> <report/>
<uplink domain="uplink"/> <nic-client domain="uplink"/>
<domain name="uplink" <domain name="uplink"
interface="10.0.2.55/24" interface="10.0.2.55/24"
@ -269,7 +269,7 @@ append config {
tcp_idle_timeout_sec="30" tcp_idle_timeout_sec="30"
tcp_max_segm_lifetime_sec="15"> tcp_max_segm_lifetime_sec="15">
<uplink domain="uplink"/> <nic-client domain="uplink"/>
<domain name="uplink" <domain name="uplink"
interface="10.0.2.55/24" interface="10.0.2.55/24"
@ -311,7 +311,7 @@ append config {
<report interval_sec="2" bytes="yes" config="no" /> <report interval_sec="2" bytes="yes" config="no" />
<uplink domain="uplink"/> <nic-client domain="uplink"/>
<domain name="uplink" <domain name="uplink"
interface="10.0.2.55/24" interface="10.0.2.55/24"
@ -345,7 +345,7 @@ append config {
<report interval_sec="2" bytes="yes" config="no" /> <report interval_sec="2" bytes="yes" config="no" />
<uplink domain="uplink"/> <nic-client domain="uplink"/>
<domain name="uplink" <domain name="uplink"
interface="10.0.2.55/24" interface="10.0.2.55/24"

View File

@ -5,7 +5,7 @@
<config verbose_domain_state="yes"> <config verbose_domain_state="yes">
<default-policy domain="default" /> <default-policy domain="default" />
<uplink domain="uplink" /> <nic-client domain="uplink" />
<domain name="uplink"> <domain name="uplink">
<nat domain="default" <nat domain="default"
tcp-ports="1000" tcp-ports="1000"

View File

@ -131,7 +131,7 @@ append config {
<policy label_prefix="ping_1" domain="ping_1"/> <policy label_prefix="ping_1" domain="ping_1"/>
<policy label_prefix="ping_2" domain="ping_2"/> <policy label_prefix="ping_2" domain="ping_2"/>
<uplink domain="uplink"/> <nic-client domain="uplink"/>
<domain name="uplink"> <domain name="uplink">
<nat domain="ping_1" icmp-ids="100"/> <nat domain="ping_1" icmp-ids="100"/>
@ -166,7 +166,7 @@ append config {
<config> <config>
<policy label_prefix="ping_2" domain="ping_2"/> <policy label_prefix="ping_2" domain="ping_2"/>
<uplink domain="uplink"/> <nic-client domain="uplink"/>
<domain name="uplink" interface="10.0.4.2/24" gateway="10.0.4.1"> <domain name="uplink" interface="10.0.4.2/24" gateway="10.0.4.1">
<nat domain="ping_2" icmp-ids="100" udp-ports="100"/> <nat domain="ping_2" icmp-ids="100" udp-ports="100"/>

View File

@ -186,7 +186,7 @@ append_if [expr ![nic_router_2_managed]] config {
<config verbose_packets="no"> <config verbose_packets="no">
<policy label="test_client -> " domain="downlink"/> <policy label="test_client -> " domain="downlink"/>
<uplink domain="uplink"/> <nic-client domain="uplink"/>
<domain name="uplink"/> <domain name="uplink"/>
<domain name="downlink" interface="10.0.3.1/24"> <domain name="downlink" interface="10.0.3.1/24">

View File

@ -113,7 +113,7 @@ append config {
icmp_idle_timeout_sec="10"> icmp_idle_timeout_sec="10">
<policy label_prefix="ping_2" domain="ping_2"/> <policy label_prefix="ping_2" domain="ping_2"/>
<uplink domain="uplink"/> <nic-client domain="uplink"/>
<domain name="uplink"> <domain name="uplink">
<nat domain="ping_2" icmp-ids="100" udp-ports="100"/> <nat domain="ping_2" icmp-ids="100" udp-ports="100"/>

View File

@ -1,68 +1,118 @@
The 'nic_router' component can be used to achieve a controlled mediation The 'nic_router' component can be used to achieve a controlled mediation
between multiple NIC sessions on network or transport level. NIC sessions are between multiple NIC and Uplink sessions on network or transport level.
assigned to domains. The rules configured by the user then mediate between Sessions are assigned to router domains. The rules configured by the user then
these domains. This is a brief overview of the features thereby provided: mediate between these domains. This is a brief overview of the features thereby
provided:
* Acting as hub between NIC session with the same domain, * Acting as hub among NIC and Uplink sessions of the same domain,
* routing of UDP and TCP according to destination IP address and port, * routing of IPv4-based UDP and TCP according to destination IP address & port,
* routing of ICMP and IPv4 according to destination IP address, * routing of ICMPv4 and IPv4 according to destination IP address,
* port forwarding for UDP and TCP, * port forwarding for IPv4-based UDP and TCP,
* NAPT for UDP, TCP and ICMP "Echo", * NAPT for IPv4-based UDP, TCP and ICMPv4 echo,
* forwarding of ICMP "Destination Unreachable" according to the UDP, TCP or * forwarding of ICMPv4 "Destination Unreachable" according to the UDP, TCP or
ICMP "Echo" connection it refers to, ICMPv4 echo connection it refers to,
* acting as ICMP echo server per domain * acting as ICMPv4 echo server per domain
* acting as DHCP server or client per domain, * acting as DHCPv4 server or client per domain,
* provide per-domain network statistics via a report session, * provide per-domain network statistics via a report session,
* print out header information for each packet received or sent, * print out header information for each packet received or sent,
* and be fully re-configurable at runtime. * and be fully re-configurable at runtime.
Basics Functional description
~~~~~~ ======================
The NIC router can act as server of multiple NIC session clients (downlinks)
and at the same time as client of multiple NIC session servers (uplinks).
Besides the decision which side initiates the NIC session and provides MAC
address respectively link state, uplinks and downlinks are equal to the NIC
router.
The routing algorithm is ultimately controlled through the configuration. NIC Interfaces and domains
sessions are assigned to domains. Each domain represents one subnet and a ~~~~~~~~~~~~~~~~~~~~~~
corresponding routing configuration. The assignment of downlink NIC sessions
to domains is controlled through the policy tag that is also known from other
Genode components:
! <policy label_prefix="vlan_" domain="vlan" /> The NIC router acts as server for both Genode's NIC and Uplink service. For
both services it can manage an arbitrary number of clients at a time.
Furthermore, the NIC router can itself request multiple NIC sessions and act as
client at them. Among these types of network sessions at the router, there are
some minor differences regarding the roles when initializing the session,
determining a MAC address or communicating the link state. However, each
network session at the router, regardless of its type, is an "interface" (like
a network interface in Linux-based systems) and in all regards except the
mentioned subtleties treated the same as other interfaces.
The behavior of the router regarding interfaces is ultimately controlled
through the router's configuration. An interface that uses a NIC session that
is requested by the router (subsequently called NIC client) can be created
using the '<nic-client>' tag with an optional attribute for the session label:
! <nic-client ... />
! <nic-client label="wifi" ... />
! <nic-client label="wired" ... />
An interface that uses a NIC or Uplink session provided by the NIC router
(subsequently called NIC server respectively Uplink server) is created whenever
a client requests a session of one of the two service types at the router
(given the session arguments are valid).
New interfaces, although having a network session established, remain dead ends
towards the router (all packets are dropped by the router) as long as they are
not assigned a router domain. A domain is a set of router rules that is applied
as a whole to all interfaces assigned to that domain. Domains can be created by
using the '<domain>' tag with a unique name:
! <domain name="default" ...>...<domain/>
! <domain name="servers" ...>...<domain/>
! <domain name="home_net" ...>...<domain/>
! <domain name="travel_net" ...>...<domain/>
The assignment of NIC clients to domains is controlled through the 'domain'
attribute in the '<nic-client>' tag:
! <nic-client domain="home_net" />
! <nic-client label="mobile_drv" domain="travel_net" />
! <nic-client label="nic_bridge" domain="home_net" />
The assignment of NIC and Uplink servers is controlled through the tags
'<policy>' and '<default-policy>' that are known from other Genode components:
! <default-policy domain="default" />
! <policy label_prefix="vbox_" domain="servers" />
! <policy label_suffix="_server" domain="servers" /> ! <policy label_suffix="_server" domain="servers" />
! <policy label="nic_bridge_1" domain="wired_bridge" /> ! <policy label="nic_drv -> " domain="home_net" />
! <policy label="nic_bridge_2" domain="wired_bridge" /> ! <policy label="wifi_drv -> " domain="public" />
The domain name can be freely choosen but must be unique. Each of these tags applies to all NIC and Uplink servers whose session label
The uplink tag instructs the NIC router to create an uplink NIC session that matches. A domain can be assigned any number of interfaces and interfaces of
is assigned to the give domain: different types.
! <uplink domain="wired_bridge" /> Besides defining the router rules for assigned interfaces, domains have a
! <uplink label="wired" domain="wired_bridge" /> second purpose. All interfaces assigned the same domain are assumed to be in
! <uplink label="wifi" domain="wifi_uplink" /> the same IPv4 subnet. So, from the router's perspective, each domain is a
distinct IPv4 subnet. At each domain the router is represented through an
IPv4 identity local to the corresponding IPv4 subnet.
The label is the session label that is used when requesting the uplink NIC Besides being an IPv4 peer at each domain. The router is also a hub at each
session. The label attribute is optional. It is perfectly fine to have a domain: If a network packet must be sent at a domain, it is always sent at all
domain with uplinks and downlinks assigned to at the same time. For each interfaces assigned that domain. If a network packet from a domain addresses a
domain there must be a domain tag: host in the same IPv4 subnet and it's not the routers IPv4 peer in that domain,
the packet is again sent at all interfaces assigned that domain
! <domain name="uplink" interface="10.0.2.55/24" /> A good analogy would be that interfaces assigned a single domain are like
! <domain name="http_servers" interface="192.168.1.18/24" /> network cables that are all plugged into the same hub device. There's an
! <domain name="imap_servers" interface="192.168.2.17/24" /> additional cable going away from the hub device that directly leads to the
routers IPv4 peer in the subnet.
The 'interface' attribute defines two things at once. First, it tells the A domain enters an IPv4 subnet by receing an IPv4 configuration for the routers
router which subnet can be found behind this domain, and second, which IP IPv4 peer in that subnet. This configuration can be obtained statically or
identity the router shall use in case it has to communicate as itself with dynamically using DHCP. A static configuration is applied if an 'interface'
the subnet. If the 'interface' attribute is not set in a 'domain' tag, the attribute is found in the '<domain>' tag:
router acts as DHCP client (Section [Configuring DHCP client functionality]).
! <domain name="servers" interface="10.0.2.55/24" />
The attribute defines the IPv4 address of the routers peer and the address
prefix length of the corresponding subnet. If the attribute is missing the
domain automatically sends DHCP requests at all assigned interfaces in order
to obtain a dynamic IPv4 configuration (Section [Configuring DHCP client
functionality]).
Additionaly, the optional 'gateway' attribute can be set for a domain: Additionaly, the optional 'gateway' attribute can be set for a domain:
! <domain name="uplink" interface="10.0.2.55/24" gateway="10.0.2.1" /> ! <domain name="home_lan" interface="10.0.2.55/24" gateway="10.0.2.1" />
It defines the standard gateway of the subnet behind this domain. If a packet It defines the standard gateway of the subnet behind this domain. If a packet
shall be routed to this domain and its final IP destination does not match shall be routed to this domain and its final IP destination does not match
@ -155,9 +205,9 @@ These are examples for IP rules:
! <ip dst="10.0.2.0/24" domain="intranet" /> ! <ip dst="10.0.2.0/24" domain="intranet" />
! <ip dst="192.168.1.18/32" domain="my_server" /> ! <ip dst="192.168.1.18/32" domain="my_server" />
! <ip dst="0.0.0.0/0" domain="uplink" /> ! <ip dst="0.0.0.0/0" domain="default" />
IP rules only apply to IPv4 packets from the session of the surrounding IP rules only apply to IPv4 packets from interfaces of the surrounding
domain. The 'dst' attribute is compared with the IP destination of the packet. domain. The 'dst' attribute is compared with the IP destination of the packet.
The rule with the longest prefix match is taken. The packet is then routed to The rule with the longest prefix match is taken. The packet is then routed to
the domain given in the rule. the domain given in the rule.
@ -179,9 +229,9 @@ These are examples for ICMP rules:
! <icmp dst="10.0.2.0/24" domain="intranet" /> ! <icmp dst="10.0.2.0/24" domain="intranet" />
! <icmp dst="192.168.1.18/32" domain="my_server" /> ! <icmp dst="192.168.1.18/32" domain="my_server" />
! <icmp dst="0.0.0.0/0" domain="uplink" /> ! <icmp dst="0.0.0.0/0" domain="default" />
ICMP rules only apply to ICMP "Echo" packets from sessions of the surrounding ICMP rules only apply to ICMP "Echo" packets from interfaces of the surrounding
domain. The 'dst' attribute is compared with the IP destination of the packet. domain. The 'dst' attribute is compared with the IP destination of the packet.
The rule with the longest prefix match is taken. The packet is then routed to The rule with the longest prefix match is taken. The packet is then routed to
the domain given in the rule. the domain given in the rule.
@ -212,12 +262,12 @@ rules to get effective:
! <permit port="80" domain="http_servers" /> ! <permit port="80" domain="http_servers" />
! </tcp> ! </tcp>
! <udp dst="10.0.2.0/24"> ! <udp dst="10.0.2.0/24">
! <permit-any domain="uplink" /> ! <permit-any domain="default" />
! </udp> ! </udp>
TCP rules only apply to TCP packets and UDP rules only to UDP packets from the TCP rules only apply to TCP packets and UDP rules only to UDP packets from
session of the surrounding domain. The 'dst' attribute is compared with the IP interfaces of the surrounding domain. The 'dst' attribute is compared with the
destination of the packet. The rule with the longest prefix match is taken. IP destination of the packet. The rule with the longest prefix match is taken.
If the rule contains a 'permit-any' subrule or a 'permit' subrule whose 'port' If the rule contains a 'permit-any' subrule or a 'permit' subrule whose 'port'
attribute matches the destination port of the packet, the packet is routed to attribute matches the destination port of the packet, the packet is routed to
the domain given in the subrule. the domain given in the subrule.
@ -242,7 +292,7 @@ These are examples for port-forwarding rules:
! <tcp-forward port="80" domain="http_servers" to="192.168.1.18" to_port="1234" /> ! <tcp-forward port="80" domain="http_servers" to="192.168.1.18" to_port="1234" />
! <udp-forward port="69" domain="tftp_servers" to="192.168.2.23" /> ! <udp-forward port="69" domain="tftp_servers" to="192.168.2.23" />
Port-forwarding rules only apply to packets that come from the session of the Port-forwarding rules only apply to packets that come from interfaces of the
surrounding domain and are addressed to the router's IP identity at this domain surrounding domain and are addressed to the router's IP identity at this domain
(Section [Basics]). Amongst those, 'tcp-forward' rules only apply to the TCP (Section [Basics]). Amongst those, 'tcp-forward' rules only apply to the TCP
packets and 'udp-forward' rules only to the UDP packets. The 'port' attribute packets and 'udp-forward' rules only to the UDP packets. The 'port' attribute
@ -273,7 +323,7 @@ Each time a packet gets routed by using a TCP, UDP, ICMP or port-forwarding
rule, the router creates a link state. From then on, all packets that belong rule, the router creates a link state. From then on, all packets that belong
to the exchange this first packet initiated and come from one of the two to the exchange this first packet initiated and come from one of the two
involved domains are routed by the link state and not by a rule. The costs for involved domains are routed by the link state and not by a rule. The costs for
the link state are paid by the session that sent the first packet. the link state are paid by the interface that sent the first packet.
If a link state exists for a packet, it is unambiguously correlated either If a link state exists for a packet, it is unambiguously correlated either
through source IP and port plus destination IP and port or, for ICMP, through through source IP and port plus destination IP and port or, for ICMP, through
@ -281,7 +331,7 @@ source and destination IP plus ICMP query ID. This is also the case if the
transfer includes NAT no matter of what kind or for which side. transfer includes NAT no matter of what kind or for which side.
It is desirable to discard a link state as soon as it is not needed anymore. It is desirable to discard a link state as soon as it is not needed anymore.
The more precise this is done, the more efficient can NIC sessions use their The more precise this is done, the more efficient can interfaces use their
resources (ports, RAM), and the less is the risk for DoS attacks. Therefore, resources (ports, RAM), and the less is the risk for DoS attacks. Therefore,
the NIC router keeps track of the idle time of a link. Idle time means the the NIC router keeps track of the idle time of a link. Idle time means the
time passed since the last packet was routed using that link regardless of time passed since the last packet was routed using that link regardless of
@ -326,23 +376,23 @@ Configuring NAT
In contrast to routing rules that affect packets coming from their domain, In contrast to routing rules that affect packets coming from their domain,
NAT rules affect packets that go to their domain: NAT rules affect packets that go to their domain:
! <domain name="uplink" interface="10.0.2.55/24"> ! <domain name="home_lan" interface="10.0.2.55/24">
! <nat domain="http_client" tcp-ports="6" /> ! <nat domain="http_client" tcp-ports="6" />
! </domain> ! </domain>
This would tell the router to apply NAT for the HTTP client when it speaks to This would tell the router to apply NAT for the HTTP client when it speaks to
the uplink. This means, it affects all packets from the HTTP client that get the home LAN. This means, it affects all packets from the HTTP client that get
routed to the uplink by using a UDP, TCP, or port-forwarding rule respectively routed to the home LAN by using a UDP, TCP, or port-forwarding rule
a corresponding link state. If this is the case, the packet's source IP respectively a corresponding link state. If this is the case, the packet's
address is changed to "10.0.2.55" and the source port is replaced by a free source IP address is changed to "10.0.2.55" and the source port is replaced by
source port of the router. When saying "free source port" this actually means a free source port of the router. When saying "free source port" this actually
a port that the router currently doesn't use at the destination domain. So, means a port that the router currently doesn't use at the destination domain.
at each domain, the router has two complete port spaces for source NAT So, at each domain, the router has two complete port spaces for source NAT
available. One for UDP and one for TCP. Each port space contains the IANA available. One for UDP and one for TCP. Each port space contains the IANA
dynamic port range 49152 to 65535. dynamic port range 49152 to 65535.
As you can see, the NAT rule also has a 'tcp-ports' attribute. It restricts As you can see, the NAT rule also has a 'tcp-ports' attribute. It restricts how
how many TCP source ports of the uplink the HTTP client may use at a time. The many TCP source ports of the home LAN the HTTP client may use at a time. The
same goes also for UDP: same goes also for UDP:
! <nat domain="tftp_client" udp-ports="13" /> ! <nat domain="tftp_client" udp-ports="13" />
@ -407,7 +457,7 @@ or like this:
! <dhcp-server ip_first="10.0.1.80" ! <dhcp-server ip_first="10.0.1.80"
! ip_last="10.0.1.100" ! ip_last="10.0.1.100"
! ip_lease_time_sec="3600" ! ip_lease_time_sec="3600"
! dns_server_from="uplink" /> ! dns_server_from="home_lan" />
! ... ! ...
! !
! </domain> ! </domain>
@ -560,7 +610,7 @@ described below:
A boolean value that controls whether the attributes 'rx_bytes' and 'tx_bytes' A boolean value that controls whether the attributes 'rx_bytes' and 'tx_bytes'
of the <domain> tag in the state report are generated. These attributes of the <domain> tag in the state report are generated. These attributes
provide the number of bytes that were sent respectively recieved at all provide the number of bytes that were sent respectively recieved at all
sessions/interfaces of that domain beginning with the creation of the domain. interfaces of that domain beginning with the creation of the domain.
'stats' 'stats'
@ -581,26 +631,26 @@ itself terminated the connection).
The <destroyed> subtag can occur in <*-links> subtags in both the <interface> The <destroyed> subtag can occur in <*-links> subtags in both the <interface>
and the <domain> tag. It shows the number of links of the protocol type that and the <domain> tag. It shows the number of links of the protocol type that
once existed but were already destroyed. In case of the <interface> tag, the once existed but were already destroyed. In case of the <interface> tag, the
corresponding session/interface still exists at that domain. Once the corresponding interface still exists at that domain. Once the interface gets
session/interface gets destroyed or disconnected from the domain, the number is destroyed or disconnected from the domain, the number is transferred to the
transferred to the <destroyed> subtag in the <*-links> subtag in the <domain> <destroyed> subtag in the <*-links> subtag in the <domain> tag. I.e. the
tag. I.e. the <destroyed> subtags in <*-links> subtags in the <domain> tag <destroyed> subtags in <*-links> subtags in the <domain> tag provide the number
provide the number of destroyed links that can't be correlated anymore to any of destroyed links that can't be correlated anymore to any interface of the
session/interface of the domain. domain.
The same applies for the <refused_*> subtags of <*-links> tags. They show the The same applies for the <refused_*> subtags of <*-links> tags. They show the
number of links that couldn't be established through the router because of the number of links that couldn't be established through the router because of the
lack of a certain quota. Thereby, <refused_for_ram> refers to a lack of RAM lack of a certain quota. Thereby, <refused_for_ram> refers to a lack of RAM
quota at the source session/interface of the link. The <refused_for_ports>, at quota at the source interface of the link. The <refused_for_ports>, at the
the other hand, refers to a lack of UDP/TCP-NAT-ports respectively other hand, refers to a lack of UDP/TCP-NAT-ports respectively ICMP-NAT-IDs at
ICMP-NAT-IDs at the target domain (see section [Configuring NAT]). the target domain (see section [Configuring NAT]).
The subtags <arp-waiters>, and <dhcp-allocations> list the number of still The subtags <arp-waiters>, and <dhcp-allocations> list the number of still
active (<active> subtag) and already destroyed (<destroyed> subtag) objects active (<active> subtag) and already destroyed (<destroyed> subtag) objects for
for pending ARP requests respectively DHCP-address allocations at a pending ARP requests respectively DHCP-address allocations at an interface when
session/interface when in an <interface> tag. When in a <domain> tag, they in an <interface> tag. When in a <domain> tag, they only list the number of
only list the number of already destroyed objects of these types that can't already destroyed objects of these types that can't be correlated anymore to
be correlated anymore to any session/interface of the domain. any interface of the domain.
'quota' 'quota'
@ -609,18 +659,18 @@ A boolean value that controls whether the subtags <ram> and <cap> of the
tag are generated. tag are generated.
The former two show the capability quota respectively RAM quota of the router The former two show the capability quota respectively RAM quota of the router
that isn't accounted to any of the sessions/interfaces connected to the router that isn't accounted to any of the interfaces connected to the router (i.e.,
(i.e., the routers "own" quota). The 'quota' attribute denotes the total amount the routers "own" quota). The 'quota' attribute denotes the total amount of
of quota available to the router, the 'used' attribute the part of the total quota available to the router, the 'used' attribute the part of the total
amount of quota that is currently spent or in use, and the 'shared' attribute amount of quota that is currently spent or in use, and the 'shared' attribute
the part of the spent quota that, although it was spent for session/interface- the part of the spent quota that, although it was spent for interface-specific
specific things, can't be accounted to one session/interface technical reasons. things, can't be accounted to one interface for technical reasons.
The subtags <ram-quota> and <cap-quota> in the <interface> tag, however, show The subtags <ram-quota> and <cap-quota> in the <interface> tag, however, show
the capability quota respectively RAM quota accounted to that the capability quota respectively RAM quota accounted to that interface. The
session/interface. The 'limit' and 'used' attributes are equal to the 'quota' 'limit' and 'used' attributes are equal to the 'quota' and 'used' attributes of
and 'used' attributes of the <ram> and <cap> subtags of the <state> tag. The the <ram> and <cap> subtags of the <state> tag. The 'avail' attribute contains
'avail' attribute contains simply the 'limit' value minus the 'used' value. simply the 'limit' value minus the 'used' value.
'config' 'config'
@ -645,17 +695,16 @@ changes. I.e., whenever the IP configuration of any domain has changed.
A boolean value that controls whether the attribute 'link_state' of the A boolean value that controls whether the attribute 'link_state' of the
<interface> tag is generated. The 'link_state' attribute shows the current real <interface> tag is generated. The 'link_state' attribute shows the current real
link state of the session/interface. Note, that in case of a NIC session, this link state of the interface. Note, that in case of a NIC server, this is not
is not necessarily the same value as the one that the session client sees. For necessarily the same value as the one that the session client sees. For more
more information about that, refer to [Behavior regarding the NIC-session link information on that, refer to [Behavior regarding the NIC-session link state].
state].
'link_state_triggers' 'link_state_triggers'
A boolean value that controls whether to enforce sending a report each time the A boolean value that controls whether to enforce sending a report each time the
state that is controlled through the 'link_state' attribute of the <report> tag state that is controlled through the 'link_state' attribute of the <report> tag
changes. I.e., whenever the real link state of any session/interface at the changes. I.e., whenever the real link state of any interface at the router has
router has changed. changed.
'interval_sec' 'interval_sec'
@ -690,8 +739,8 @@ affects all domains without a <domain> local value.
! <config verbose_domain_state="no"> ! <config verbose_domain_state="no">
Whether to log most important changes in the state of a domain (number of NIC Whether to log most important changes in the state of a domain (number of
sessions connected, current IPv4 config). interfaces assigned, current IPv4 config).
Other configuration attributes Other configuration attributes
@ -701,16 +750,16 @@ Other configuration attributes
Maximum number of packets handled per signal Maximum number of packets handled per signal
-------------------------------------------- --------------------------------------------
If possible, the NIC router normally handles multiple packets from a NIC If possible, the NIC router normally handles multiple packets from an interface
session per signal. However, if one NIC session has a high packet rate and a per signal. However, if one interface has a high packet rate and a big buffer,
big buffer, this can lead to starvation of the other NIC sessions. Thus, the this can lead to starvation of the other interfaces. Thus, the maximum number
maximum number of packets handled per signal is limited by default. This limit of packets handled per signal is limited by default. This limit can be
can be configured as follows (default value shown): configured as follows (default value shown):
! <config max_packets_per_signal="32"> ! <config max_packets_per_signal="32">
When set to zero, the limit is deactivated, meaning that the router always When set to zero, the limit is deactivated, meaning that the router always
handles all available packets of a NIC session. handles all available packets of an interface.
Disable requesting address resolutions via ARP Disable requesting address resolutions via ARP
@ -736,14 +785,14 @@ interfaces with the 'NOARP' flag set.
Behavior regarding the NIC-session link state Behavior regarding the NIC-session link state
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
At downlinks, the NIC router applies a feedback-driven state machine for the At NIC servers, the NIC router applies a feedback-driven state machine for the
link state in order to ensure that clients recognize state transitions. This link state in order to ensure that clients recognize state transitions. This
means that the NIC router guarantees that a new link state remains fixed until means that the NIC router guarantees that a new link state remains fixed until
the client has read it using the corresponding RPC at the NIC-session the client has read it using the corresponding RPC at the NIC-session
interface. If, in the meantime, further "up" and "down" edges occur, they are interface. If, in the meantime, further "up" and "down" edges occur, they are
memorized and executed as soon as the former state has been read by the memorized and executed as soon as the former state has been read by the client.
client. Such postponed link state edges are merged in a way that they result in Such postponed link state edges are merged in a way that they result in two
two contrary edges at a max. The following diagrams demonstrate this: contrary edges at a max. The following diagrams demonstrate this:
! client reads: 0 1 0 1 0 1 ! client reads: 0 1 0 1 0 1
@ -774,13 +823,17 @@ two contrary edges at a max. The following diagrams demonstrate this:
Examples Examples
~~~~~~~~ ========
Scripted scenarios
~~~~~~~~~~~~~~~~~~
In-action examples of how to use the router are provided through the following In-action examples of how to use the router are provided through the following
automated run scripts: automated run scripts:
* libports/run/nic_router.run (basic functionality) * libports/run/nic_router.run (basic functionality)
* dde_linux/run/nic_router_uplinks.run (dynamically switching uplinks) * dde_linux/run/nic_router_uplinks.run (dynamically switching between wifi and wired driver)
* os/run/ping_nic_router.run (ICMP routing) * os/run/ping_nic_router.run (ICMP routing)
* os/run/nic_router_disable_arp.run ('use_arp' configuration flag) * os/run/nic_router_disable_arp.run ('use_arp' configuration flag)
* os/run/nic_router_dhcp_unmanaged.run (DHCP + link states without a manager) * os/run/nic_router_dhcp_unmanaged.run (DHCP + link states without a manager)
@ -789,12 +842,12 @@ automated run scripts:
* os/run/nic_router_stress.run (client misbehaving on session level) * os/run/nic_router_stress.run (client misbehaving on session level)
The rest of this section will list and explain some smaller configuration The rest of this section will list and explain some smaller configuration
snippets. The environment for these examples shall be as follows. There are snippets. The environment for these examples shall be as follows. There are two
two virtual subnets 192.168.1.0/24 and 192.168.2.0/24 that connect as Virtnet A virtual subnets 192.168.1.0/24 and 192.168.2.0/24 that connect as Virtnet A and
and B to the router. The standard gateway of the virtual networks is the NIC B to the router. The standard gateway of the virtual networks is the NIC router
router with IP 192.168.*.1 . The router's uplink leads to the NIC driver that with IP 192.168.*.1 . The NIC driver connects the machine with your home
connects the machine with your home network 10.0.2.0/24. Your home network is network 10.0.2.0/24 and has an Uplink session to the NIC router. Your home
connected to the internet through its standard gateway 10.0.2.1 . network is connected to the internet through its standard gateway 10.0.2.1 .
Connecting local networks Connecting local networks
@ -807,33 +860,33 @@ following configuration:
! <policy label_prefix="virtnet_a" domain="virtnet_a" /> ! <policy label_prefix="virtnet_a" domain="virtnet_a" />
! <policy label_prefix="virtnet_b" domain="virtnet_b" /> ! <policy label_prefix="virtnet_b" domain="virtnet_b" />
! <uplink domain="uplink" /> ! <policy label_prefic="nic_drv" domain="home_lan" />
! !
! <domain name="uplink" interface="10.0.2.55/24" gateway="10.0.2.1/24"> ! <domain name="home_lan" interface="10.0.2.55/24" gateway="10.0.2.1/24">
! <ip dst="192.168.1.0/24" domain="virtnet_a"/> ! <ip dst="192.168.1.0/24" domain="virtnet_a"/>
! <ip dst="192.168.2.0/24" domain="virtnet_b"/> ! <ip dst="192.168.2.0/24" domain="virtnet_b"/>
! </domain> ! </domain>
! !
! <domain name="virtnet_a" interface="192.168.1.1/24"> ! <domain name="virtnet_a" interface="192.168.1.1/24">
! <ip dst="192.168.2.0/24" domain="virtnet_b"/> ! <ip dst="192.168.2.0/24" domain="virtnet_b"/>
! <ip dst="0.0.0.0/0" domain="uplink"/> ! <ip dst="0.0.0.0/0" domain="home_lan"/>
! </domain> ! </domain>
! !
! <domain name="virtnet_b" interface="192.168.2.1/24"> ! <domain name="virtnet_b" interface="192.168.2.1/24">
! <ip dst="192.168.1.0/24" domain="virtnet_a"/> ! <ip dst="192.168.1.0/24" domain="virtnet_a"/>
! <ip dst="0.0.0.0/0" domain="uplink"/> ! <ip dst="0.0.0.0/0" domain="home_lan"/>
! </domain> ! </domain>
IP packets from Virtnet A and uplink that target an IP address 192.168.2.* are IP packets from Virtnet A and the home LAN that target an IP address
routed to Virtnet B. IP packets from Virtnet B and uplink that target an IP 192.168.2.* are routed to Virtnet B. IP packets from Virtnet B and the home LAN
address 192.168.1.* are routed to Virtnet A. Packets that are addressed to that target an IP address 192.168.1.* are routed to Virtnet A. Packets that are
hosts in the same local network should never reach the router as they can be addressed to hosts in the same local network should never reach the router as
transmitted directly. If there's a packet from one of the virtual networks they can be transmitted directly. If there's a packet from one of the virtual
that doesn't target 192.168.1.* or 192.168.2.*, the IP 0.0.0.0/0 rules route networks that doesn't target 192.168.1.* or 192.168.2.*, the IP 0.0.0.0/0 rules
them to the uplink. If these packets target an IP 10.0.2.*, the router sends route them to the home LAN. If these packets target an IP 10.0.2.*, the router
them directly to the host in your home network. Otherwise, the router sends sends them directly to the host in your home network. Otherwise, the router
them to your gateway 10.0.2.1 . Note that none of the packets is modified on sends them to your gateway 10.0.2.1 . Note that none of the packets is modified
layer 2 or higher, so, no NAT is done by the router to hide the virtual on layer 2 or higher, so, no NAT is done by the router to hide the virtual
networks. networks.
@ -847,48 +900,49 @@ internet. The router would have the following configuration:
! <policy label_prefix="virtnet_a" domain="virtnet_a" /> ! <policy label_prefix="virtnet_a" domain="virtnet_a" />
! <policy label_prefix="virtnet_b" domain="virtnet_b" /> ! <policy label_prefix="virtnet_b" domain="virtnet_b" />
! <uplink domain="uplink" /> ! <policy label_prefic="nic_drv" domain="home_lan" />
! !
! <domain name="uplink" interface="10.0.2.55/24" gateway="10.0.2.1/24"> ! <domain name="home_lan" interface="10.0.2.55/24" gateway="10.0.2.1/24">
! <nat domain="virtnet_a" tcp_ports="1000" udp_ports="1000"> ! <nat domain="virtnet_a" tcp_ports="1000" udp_ports="1000">
! </domain> ! </domain>
! !
! <domain name="virtnet_a" interface="192.168.1.1/24"> ! <domain name="virtnet_a" interface="192.168.1.1/24">
! <tcp dst="10.0.2.0/24"><permit-any domain="uplink" /></tcp> ! <tcp dst="10.0.2.0/24"><permit-any domain="home_lan" /></tcp>
! <udp dst="10.0.2.0/24"><permit-any domain="uplink" /></udp> ! <udp dst="10.0.2.0/24"><permit-any domain="home_lan" /></udp>
! <tcp dst="0.0.0.0/0"> ! <tcp dst="0.0.0.0/0">
! <permit port="443" domain="uplink" /> ! <permit port="443" domain="home_lan" />
! <permit port="993" domain="uplink" /> ! <permit port="993" domain="home_lan" />
! </tcp> ! </tcp>
! </domain> ! </domain>
From the packets that come from Virtnet A, those that target an IP 10.0.2.* From the packets that come from Virtnet A, those that target an IP 10.0.2.* are
are routed to the uplink without inspecting the port. At the uplink, the routed to the home LAN without inspecting the port. At the home LAN, the router
router notices that it shall apply NAT for Virtnet A. It replaces the source notices that it shall apply NAT for Virtnet A. It replaces the source IP with
IP with 10.0.2.55 and allocates one of its uplink source ports for the 10.0.2.55 and allocates a free source port of the home LAN for the exchange. On
exchange. On replies to Virtnet-A packets from the home network, the router replies to Virtnet-A packets from the home network, the router translates IP
translates IP and port back using the corresponding link state. For packets and port back using the corresponding link state. For packets from Virtnet A
from Virtnet A that target other IPs, only the 0.0.0.0/0 rule applies and only that target other IPs, only the 0.0.0.0/0 rule applies and only if the packet
if the packet targets TCP port 443 or 993. Both ports route the packet to the targets TCP port 443 or 993. Both ports route the packet to the home LAN where,
uplink where, again, NAT is applied and the packets are sent to the gateway again, NAT is applied and the packets are sent to the gateway 10.0.2.1 .
10.0.2.1 .
Servers in a private network Servers in a private network
---------------------------- ----------------------------
In this example, we assume that there are three servers in Virtnet A. An HTTP In this example, we assume that the NIC router has to request a NIC session at
server at port 80 with IP 192.168.1.2, a GOPHER server at port 70 with IP a NIC bridge instance in order to reach the NIC driver (the driver serves the
192.168.1.3, and a TFTP server at port 69 with IP 192.168.1.4 . Now you want NIC bridge) and gain access to the home LAN. Furthermore, there are three
the servers (and only them) to be reachable to the home network via the servers in Virtnet A. An HTTP server at port 80 with IP 192.168.1.2, a GOPHER
router's IP and to the internet via your gateway. The router would have the server at port 70 with IP 192.168.1.3, and a TFTP server at port 69 with IP
following configuration: 192.168.1.4 . Now, you want the servers (and only them) to be reachable to the
home network via the router's IP and to the internet via your gateway. The
router would have the following configuration:
! <policy label_prefix="virtnet_a" domain="virtnet_a" /> ! <policy label_prefix="virtnet_a" domain="virtnet_a" />
! <policy label_prefix="virtnet_b" domain="virtnet_b" /> ! <policy label_prefix="virtnet_b" domain="virtnet_b" />
! <uplink domain="uplink" /> ! <nic-client domain="home_lan" />
! !
! <domain name="uplink" interface="10.0.2.55/24" gateway="10.0.2.1"> ! <domain name="home_lan" interface="10.0.2.55/24" gateway="10.0.2.1">
! <tcp-forward port="80" domain="virtnet_a" to="192.168.1.2" /> ! <tcp-forward port="80" domain="virtnet_a" to="192.168.1.2" />
! <tcp-forward port="70" domain="virtnet_a" to="192.168.1.3" /> ! <tcp-forward port="70" domain="virtnet_a" to="192.168.1.3" />
! <udp-forward port="69" domain="virtnet_a" to="192.168.1.4" to_port="2048"/> ! <udp-forward port="69" domain="virtnet_a" to="192.168.1.4" to_port="2048"/>
@ -897,7 +951,7 @@ following configuration:
! <domain name="virtnet_a" interface="192.168.1.1/24" /> ! <domain name="virtnet_a" interface="192.168.1.1/24" />
! <domain name="virtnet_b" interface="192.168.1.1/24" /> ! <domain name="virtnet_b" interface="192.168.1.1/24" />
Amongst the packets that come from the uplink, only those that are addressed Amongst the packets that come from the home LAN, only those that are addressed
to 10.0.2.55 and TCP port 80, TCP port 70, or UDP port 69 are forwarded. to 10.0.2.55 and TCP port 80, TCP port 70, or UDP port 69 are forwarded.
All these packets are forwarded to Virtnet A. But beforehand, their IP All these packets are forwarded to Virtnet A. But beforehand, their IP
destination is adapted. TCP-port-80 packets are redirected to 192.168.1.2, destination is adapted. TCP-port-80 packets are redirected to 192.168.1.2,
@ -905,7 +959,7 @@ TCP-port-70 packets to 192.168.1.3, and UDP-port-69 packets to
192.168.1.4:2048. 192.168.1.4:2048.
Amongst the packets that come from Virtnet A, only those that match a link Amongst the packets that come from Virtnet A, only those that match a link
state at the uplink are forwarded, because the Virtnet-A domain contains no state at the home LAN are forwarded, because the Virtnet-A domain contains no
rules. Thus, Virtnet A can only talk to the uplink in the context of rules. Thus, Virtnet A can only talk to the home LAN in the context of
TCP-connections or UDP pseudo-connections that were opened by clients behind TCP-connections or UDP pseudo-connections that were opened by clients behind
the uplink. The servers IP addresses never leave Virtnet A. the home LAN. The servers IP addresses never leave Virtnet A.

View File

@ -84,12 +84,12 @@
</xs:complexType> </xs:complexType>
</xs:element><!-- policy --> </xs:element><!-- policy -->
<xs:element name="uplink"> <xs:element name="nic-client">
<xs:complexType> <xs:complexType>
<xs:attribute name="label" type="Session_label" /> <xs:attribute name="label" type="Session_label" />
<xs:attribute name="domain" type="Domain_name" /> <xs:attribute name="domain" type="Domain_name" />
</xs:complexType> </xs:complexType>
</xs:element><!-- uplink --> </xs:element><!-- nic-client -->
<xs:element name="domain"> <xs:element name="domain">
<xs:complexType> <xs:complexType>

View File

@ -48,14 +48,14 @@ Configuration::Configuration(Xml_node const node,
{ } { }
void Configuration::_invalid_uplink(Uplink &uplink, void Configuration::_invalid_nic_client(Nic_client &nic_client,
char const *reason) char const *reason)
{ {
if (_verbose) { if (_verbose) {
log("[", uplink.domain(), "] invalid uplink: ", uplink, " (", reason, ")"); } log("[", nic_client.domain(), "] invalid NIC client: ", nic_client, " (", reason, ")"); }
_uplinks.remove(uplink); _nic_clients.remove(nic_client);
destroy(_alloc, &uplink); destroy(_alloc, &nic_client);
} }
@ -160,26 +160,26 @@ Configuration::Configuration(Env &env,
} }
catch (Genode::Xml_node::Nonexistent_sub_node) { } catch (Genode::Xml_node::Nonexistent_sub_node) { }
/* initialize uplinks */ /* initialize NIC clients */
_node.for_each_sub_node("uplink", [&] (Xml_node const node) { _node.for_each_sub_node("nic-client", [&] (Xml_node const node) {
try { try {
Uplink &uplink = *new (_alloc) Nic_client &nic_client = *new (_alloc)
Uplink { node, alloc, old_config._uplinks, env, timer, Nic_client { node, alloc, old_config._nic_clients, env, timer,
interfaces, *this }; interfaces, *this };
try { _uplinks.insert(uplink); } try { _nic_clients.insert(nic_client); }
catch (Uplink_tree::Name_not_unique exception) { catch (Nic_client_tree::Name_not_unique exception) {
_invalid_uplink(uplink, "label not unique"); _invalid_nic_client(nic_client, "label not unique");
_invalid_uplink(exception.object, "label not unique"); _invalid_nic_client(exception.object, "label not unique");
} }
} }
catch (Uplink::Invalid) { } catch (Nic_client::Invalid) { }
}); });
/* /*
* Destroy old uplinks to ensure that uplink interfaces that were not * Destroy old NIC clients to ensure that NIC client interfaces that were not
* re-used are not re-attached to the new domains. * re-used are not re-attached to the new domains.
*/ */
old_config._uplinks.destroy_each(_alloc); old_config._nic_clients.destroy_each(_alloc);
} }
@ -203,8 +203,8 @@ void Configuration::start_reporting()
Configuration::~Configuration() Configuration::~Configuration()
{ {
/* destroy uplinks */ /* destroy NIC clients */
_uplinks.destroy_each(_alloc); _nic_clients.destroy_each(_alloc);
/* destroy reporter */ /* destroy reporter */
try { destroy(_alloc, &_reporter()); } try { destroy(_alloc, &_reporter()); }

View File

@ -17,7 +17,7 @@
/* local includes */ /* local includes */
#include <domain.h> #include <domain.h>
#include <report.h> #include <report.h>
#include <uplink.h> #include <nic_client.h>
/* Genode includes */ /* Genode includes */
#include <base/duration.h> #include <base/duration.h>
@ -50,10 +50,10 @@ class Net::Configuration
Pointer<Report> _report { }; Pointer<Report> _report { };
Pointer<Genode::Reporter> _reporter { }; Pointer<Genode::Reporter> _reporter { };
Domain_tree _domains { }; Domain_tree _domains { };
Uplink_tree _uplinks { }; Nic_client_tree _nic_clients { };
Genode::Xml_node const _node; Genode::Xml_node const _node;
void _invalid_uplink(Uplink &uplink, void _invalid_nic_client(Nic_client &nic_client,
char const *reason); char const *reason);
void _invalid_domain(Domain &domain, void _invalid_domain(Domain &domain,

View File

@ -20,7 +20,6 @@
/* local includes */ /* local includes */
#include <nic_session_root.h> #include <nic_session_root.h>
#include <uplink_session_root.h> #include <uplink_session_root.h>
#include <uplink.h>
#include <configuration.h> #include <configuration.h>
using namespace Net; using namespace Net;

View File

@ -0,0 +1,180 @@
/*
* \brief Interface back-end using a NIC session requested by the NIC router
* \author Martin Stein
* \date 2016-08-23
*/
/*
* Copyright (C) 2016-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* Genode includes */
#include <base/env.h>
/* local includes */
#include <nic_client.h>
#include <configuration.h>
using namespace Net;
using namespace Genode;
/*********************
** Nic_client_base **
*********************/
Net::Nic_client_base::Nic_client_base(Xml_node const &node)
:
_label { node.attribute_value("label", Session_label::String()) },
_domain { node.attribute_value("domain", Domain_name()) }
{ }
/****************
** Nic_client **
****************/
void Nic_client::_invalid(char const *reason) const
{
if (_config.verbose()) {
log("[", domain(), "] invalid NIC client: ", *this, " (", reason, ")"); }
throw Invalid();
}
Net::Nic_client::Nic_client(Xml_node const &node,
Allocator &alloc,
Nic_client_tree &old_nic_clients,
Env &env,
Timer::Connection &timer,
Interface_list &interfaces,
Configuration &config)
:
Nic_client_base { node },
Avl_string_base { label().string() },
_alloc { alloc },
_config { config }
{
/* if an interface with this label already exists, reuse it */
try {
Nic_client &old_nic_client = old_nic_clients.find_by_name(label());
Nic_client_interface &interface = old_nic_client._interface();
old_nic_client._interface = Pointer<Nic_client_interface>();
interface.domain_name(domain());
_interface = interface;
}
/* if not, create a new one */
catch (Nic_client_tree::No_match) {
if (config.verbose()) {
log("[", domain(), "] create NIC client: ", *this); }
try {
_interface = *new (_alloc)
Nic_client_interface { env, timer, alloc, interfaces, config,
domain(), label() };
}
catch (Insufficient_ram_quota) { _invalid("NIC session RAM quota"); }
catch (Insufficient_cap_quota) { _invalid("NIC session CAP quota"); }
catch (Service_denied) { _invalid("NIC session denied"); }
}
}
Net::Nic_client::~Nic_client()
{
/* if the interface was yet not reused by another NIC client, destroy it */
try {
Nic_client_interface &interface = _interface();
if (_config.verbose()) {
log("[", domain(), "] destroy NIC client: ", *this); }
destroy(_alloc, &interface);
}
catch (Pointer<Nic_client_interface>::Invalid) { }
}
void Net::Nic_client::print(Output &output) const
{
if (label() == Session_label()) {
Genode::print(output, "?"); }
else {
Genode::print(output, label()); }
}
/*******************************
** Nic_client_interface_base **
*******************************/
Net::Nic_client_interface_base::
Nic_client_interface_base(Domain_name const &domain_name,
Session_label const &label,
bool const &session_link_state)
:
_domain_name { domain_name },
_label { label },
_session_link_state { session_link_state }
{ }
void Net::Nic_client_interface_base::interface_unready()
{
_interface_ready = false;
};
void Net::Nic_client_interface_base::interface_ready()
{
_interface_ready = true;
};
bool Net::Nic_client_interface_base::interface_link_state() const
{
return _interface_ready && _session_link_state;
}
/**************************
** Nic_client_interface **
**************************/
Net::Nic_client_interface::Nic_client_interface(Env &env,
Timer::Connection &timer,
Genode::Allocator &alloc,
Interface_list &interfaces,
Configuration &config,
Domain_name const &domain_name,
Session_label const &label)
:
Nic_client_interface_base { domain_name, label, _session_link_state },
Nic::Packet_allocator { &alloc },
Nic::Connection { env, this, BUF_SIZE, BUF_SIZE, label.string() },
_session_link_state_handler { env.ep(), *this,
&Nic_client_interface::_handle_session_link_state },
_interface { env.ep(), timer, mac_address(), alloc,
Mac_address(), config, interfaces, *rx(), *tx(),
*this }
{
/* install packet stream signal handlers */
rx_channel()->sigh_ready_to_ack (_interface.sink_ack());
rx_channel()->sigh_packet_avail (_interface.sink_submit());
tx_channel()->sigh_ack_avail (_interface.source_ack());
tx_channel()->sigh_ready_to_submit(_interface.source_submit());
/* initialize link state handling */
Nic::Connection::link_state_sigh(_session_link_state_handler);
_session_link_state = Nic::Connection::link_state();
}
void Net::Nic_client_interface::_handle_session_link_state()
{
_session_link_state = Nic::Connection::link_state();
_interface.handle_interface_link_state();
}

View File

@ -0,0 +1,178 @@
/*
* \brief Interface back-end using a NIC session requested by the NIC router
* \author Martin Stein
* \date 2016-08-23
*/
/*
* Copyright (C) 2016-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _NIC_CLIENT_H_
#define _NIC_CLIENT_H_
/* Genode includes */
#include <nic_session/connection.h>
#include <nic/packet_allocator.h>
/* local includes */
#include <avl_string_tree.h>
#include <interface.h>
#include <ipv4_address_prefix.h>
namespace Net {
using Domain_name = Genode::String<160>;
class Nic_client_base;
class Nic_client;
class Nic_client_tree;
class Nic_client_interface_base;
class Nic_client_interface;
}
class Net::Nic_client_tree
:
public Avl_string_tree<Nic_client, Genode::Session_label>
{ };
class Net::Nic_client_base
{
private:
Genode::Session_label const _label;
Domain_name const _domain;
public:
Nic_client_base(Genode::Xml_node const &node);
virtual ~Nic_client_base() { }
/**************
** Acessors **
**************/
Genode::Session_label const &label() const { return _label; }
Domain_name const &domain() const { return _domain; }
};
class Net::Nic_client : public Nic_client_base,
private Genode::Avl_string_base
{
friend class Avl_string_tree<Nic_client, Genode::Session_label>;
friend class Genode::List<Nic_client>;
private:
Genode::Allocator &_alloc;
Configuration const &_config;
Pointer<Nic_client_interface> _interface { };
void _invalid(char const *reason) const;
public:
struct Invalid : Genode::Exception { };
Nic_client(Genode::Xml_node const &node,
Genode::Allocator &alloc,
Nic_client_tree &old_nic_clients,
Genode::Env &env,
Timer::Connection &timer,
Interface_list &interfaces,
Configuration &config);
~Nic_client();
/*********
** log **
*********/
void print(Genode::Output &output) const;
};
class Net::Nic_client_interface_base : public Interface_policy
{
private:
Const_reference<Domain_name> _domain_name;
Genode::Session_label const _label;
bool const &_session_link_state;
bool _interface_ready { false };
/***************************
** Net::Interface_policy **
***************************/
Domain_name determine_domain_name() const override { return _domain_name(); };
void handle_config(Configuration const &) override { }
Genode::Session_label const &label() const override { return _label; }
void interface_unready() override;
void interface_ready() override;
bool interface_link_state() const override;
public:
Nic_client_interface_base(Domain_name const &domain_name,
Genode::Session_label const &label,
bool const &session_link_state);
virtual ~Nic_client_interface_base() { }
/***************
** Accessors **
***************/
void domain_name(Domain_name const &v) { _domain_name = v; }
};
class Net::Nic_client_interface : public Nic_client_interface_base,
public Nic::Packet_allocator,
public Nic::Connection
{
private:
enum {
PKT_SIZE = Nic::Packet_allocator::DEFAULT_PACKET_SIZE,
BUF_SIZE = Nic::Session::QUEUE_SIZE * PKT_SIZE,
};
bool _session_link_state { false };
Genode::Signal_handler<Nic_client_interface> _session_link_state_handler;
Net::Interface _interface;
Ipv4_address_prefix _read_interface();
void _handle_session_link_state();
public:
Nic_client_interface(Genode::Env &env,
Timer::Connection &timer,
Genode::Allocator &alloc,
Interface_list &interfaces,
Configuration &config,
Domain_name const &domain_name,
Genode::Session_label const &label);
/***************
** Accessors **
***************/
Mac_address const &router_mac() const { return _interface.router_mac(); }
};
#endif /* _NIC_CLIENT_H_ */

View File

@ -1,5 +1,5 @@
/* /*
* \brief NIC session server role of the NIC router * \brief Interface back-end using NIC sessions provided by the NIC router
* \author Martin Stein * \author Martin Stein
* \date 2016-08-23 * \date 2016-08-23
*/ */

View File

@ -1,5 +1,5 @@
/* /*
* \brief NIC session server role of the NIC router * \brief Interface back-end using NIC sessions provided by the NIC router
* \author Martin Stein * \author Martin Stein
* \date 2016-08-23 * \date 2016-08-23
*/ */

View File

@ -12,7 +12,7 @@ SRC_CC += \
nat_rule.cc \ nat_rule.cc \
main.cc \ main.cc \
ipv4_config.cc \ ipv4_config.cc \
uplink.cc \ nic_client.cc \
interface.cc \ interface.cc \
arp_cache.cc \ arp_cache.cc \
configuration.cc \ configuration.cc \

View File

@ -1,179 +0,0 @@
/*
* \brief Uplink interface in form of a NIC session component
* \author Martin Stein
* \date 2016-08-23
*/
/*
* Copyright (C) 2016-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* Genode includes */
#include <base/env.h>
/* local includes */
#include <uplink.h>
#include <configuration.h>
using namespace Net;
using namespace Genode;
/*****************
** Uplink_base **
*****************/
Net::Uplink_base::Uplink_base(Xml_node const &node)
:
_label { node.attribute_value("label", Session_label::String()) },
_domain { node.attribute_value("domain", Domain_name()) }
{ }
/************
** Uplink **
************/
void Uplink::_invalid(char const *reason) const
{
if (_config.verbose()) {
log("[", domain(), "] invalid uplink: ", *this, " (", reason, ")"); }
throw Invalid();
}
Net::Uplink::Uplink(Xml_node const &node,
Allocator &alloc,
Uplink_tree &old_uplinks,
Env &env,
Timer::Connection &timer,
Interface_list &interfaces,
Configuration &config)
:
Uplink_base { node },
Avl_string_base { label().string() },
_alloc { alloc },
_config { config }
{
/* if an interface with this label already exists, reuse it */
try {
Uplink &old_uplink = old_uplinks.find_by_name(label());
Uplink_interface &interface = old_uplink._interface();
old_uplink._interface = Pointer<Uplink_interface>();
interface.domain_name(domain());
_interface = interface;
}
/* if not, create a new one */
catch (Uplink_tree::No_match) {
if (config.verbose()) {
log("[", domain(), "] request uplink NIC session: ", *this); }
try {
_interface = *new (_alloc)
Uplink_interface { env, timer, alloc, interfaces, config,
domain(), label() };
}
catch (Insufficient_ram_quota) { _invalid("NIC session RAM quota"); }
catch (Insufficient_cap_quota) { _invalid("NIC session CAP quota"); }
catch (Service_denied) { _invalid("NIC session denied"); }
}
}
Net::Uplink::~Uplink()
{
/* if the interface was yet not reused by another uplink, destroy it */
try {
Uplink_interface &interface = _interface();
if (_config.verbose()) {
log("[", domain(), "] close uplink NIC session: ", *this); }
destroy(_alloc, &interface);
}
catch (Pointer<Uplink_interface>::Invalid) { }
}
void Net::Uplink::print(Output &output) const
{
if (label() == Session_label()) {
Genode::print(output, "?"); }
else {
Genode::print(output, label()); }
}
/***************************
** Uplink_interface_base **
***************************/
Net::Uplink_interface_base::Uplink_interface_base(Domain_name const &domain_name,
Session_label const &label,
bool const &session_link_state)
:
_domain_name { domain_name },
_label { label },
_session_link_state { session_link_state }
{ }
void Net::Uplink_interface_base::interface_unready()
{
_interface_ready = false;
};
void Net::Uplink_interface_base::interface_ready()
{
_interface_ready = true;
};
bool Net::Uplink_interface_base::interface_link_state() const
{
return _interface_ready && _session_link_state;
}
/**********************
** Uplink_interface **
**********************/
Net::Uplink_interface::Uplink_interface(Env &env,
Timer::Connection &timer,
Genode::Allocator &alloc,
Interface_list &interfaces,
Configuration &config,
Domain_name const &domain_name,
Session_label const &label)
:
Uplink_interface_base { domain_name, label, _session_link_state },
Nic::Packet_allocator { &alloc },
Nic::Connection { env, this, BUF_SIZE, BUF_SIZE, label.string() },
_session_link_state_handler { env.ep(), *this,
&Uplink_interface::_handle_session_link_state },
_interface { env.ep(), timer, mac_address(), alloc,
Mac_address(), config, interfaces, *rx(), *tx(),
*this }
{
/* install packet stream signal handlers */
rx_channel()->sigh_ready_to_ack (_interface.sink_ack());
rx_channel()->sigh_packet_avail (_interface.sink_submit());
tx_channel()->sigh_ack_avail (_interface.source_ack());
tx_channel()->sigh_ready_to_submit(_interface.source_submit());
/* initialize link state handling */
Nic::Connection::link_state_sigh(_session_link_state_handler);
_session_link_state = Nic::Connection::link_state();
}
void Net::Uplink_interface::_handle_session_link_state()
{
_session_link_state = Nic::Connection::link_state();
_interface.handle_interface_link_state();
}

View File

@ -1,178 +0,0 @@
/*
* \brief Uplink interface in form of a NIC session component
* \author Martin Stein
* \date 2016-08-23
*/
/*
* Copyright (C) 2016-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _UPLINK_H_
#define _UPLINK_H_
/* Genode includes */
#include <nic_session/connection.h>
#include <nic/packet_allocator.h>
/* local includes */
#include <avl_string_tree.h>
#include <interface.h>
#include <ipv4_address_prefix.h>
namespace Net {
using Domain_name = Genode::String<160>;
class Uplink_base;
class Uplink;
class Uplink_tree;
class Uplink_interface_base;
class Uplink_interface;
}
class Net::Uplink_tree
:
public Avl_string_tree<Uplink, Genode::Session_label>
{ };
class Net::Uplink_base
{
private:
Genode::Session_label const _label;
Domain_name const _domain;
public:
Uplink_base(Genode::Xml_node const &node);
virtual ~Uplink_base() { }
/**************
** Acessors **
**************/
Genode::Session_label const &label() const { return _label; }
Domain_name const &domain() const { return _domain; }
};
struct Net::Uplink : public Uplink_base,
private Genode::Avl_string_base
{
friend class Avl_string_tree<Uplink, Genode::Session_label>;
friend class Genode::List<Uplink>;
private:
Genode::Allocator &_alloc;
Configuration const &_config;
Pointer<Uplink_interface> _interface { };
void _invalid(char const *reason) const;
public:
struct Invalid : Genode::Exception { };
Uplink(Genode::Xml_node const &node,
Genode::Allocator &alloc,
Uplink_tree &old_uplinks,
Genode::Env &env,
Timer::Connection &timer,
Interface_list &interfaces,
Configuration &config);
~Uplink();
/*********
** log **
*********/
void print(Genode::Output &output) const;
};
class Net::Uplink_interface_base : public Interface_policy
{
private:
Const_reference<Domain_name> _domain_name;
Genode::Session_label const _label;
bool const &_session_link_state;
bool _interface_ready { false };
/***************************
** Net::Interface_policy **
***************************/
Domain_name determine_domain_name() const override { return _domain_name(); };
void handle_config(Configuration const &) override { }
Genode::Session_label const &label() const override { return _label; }
void interface_unready() override;
void interface_ready() override;
bool interface_link_state() const override;
public:
Uplink_interface_base(Domain_name const &domain_name,
Genode::Session_label const &label,
bool const &session_link_state);
virtual ~Uplink_interface_base() { }
/***************
** Accessors **
***************/
void domain_name(Domain_name const &v) { _domain_name = v; }
};
class Net::Uplink_interface : public Uplink_interface_base,
public Nic::Packet_allocator,
public Nic::Connection
{
private:
enum {
PKT_SIZE = Nic::Packet_allocator::DEFAULT_PACKET_SIZE,
BUF_SIZE = Nic::Session::QUEUE_SIZE * PKT_SIZE,
};
bool _session_link_state { false };
Genode::Signal_handler<Uplink_interface> _session_link_state_handler;
Net::Interface _interface;
Ipv4_address_prefix _read_interface();
void _handle_session_link_state();
public:
Uplink_interface(Genode::Env &env,
Timer::Connection &timer,
Genode::Allocator &alloc,
Interface_list &interfaces,
Configuration &config,
Domain_name const &domain_name,
Genode::Session_label const &label);
/***************
** Accessors **
***************/
Mac_address const &router_mac() const { return _interface.router_mac(); }
};
#endif /* _UPLINK_H_ */

View File

@ -1,5 +1,5 @@
/* /*
* \brief Downlink interface in form of an Uplink session component * \brief Interface back-end using Uplink sessions provided by the NIC router
* \author Martin Stein * \author Martin Stein
* \date 2016-08-23 * \date 2016-08-23
*/ */

View File

@ -1,5 +1,5 @@
/* /*
* \brief Downlink interface in form of an Uplink session component * \brief Interface back-end using Uplink sessions provided by the NIC router
* \author Martin Stein * \author Martin Stein
* \date 2016-08-23 * \date 2016-08-23
*/ */

View File

@ -147,7 +147,7 @@ void Local::Main::_handle_router_state()
xml.attribute("label", "test_client -> "); xml.attribute("label", "test_client -> ");
xml.attribute("domain", "downlink"); xml.attribute("domain", "downlink");
}); });
xml.node("uplink", [&] () { xml.node("nic-client", [&] () {
xml.attribute("domain", "uplink"); xml.attribute("domain", "uplink");
}); });
xml.node("domain", [&] () { xml.node("domain", [&] () {