mirror of
https://github.com/genodelabs/genode.git
synced 2025-02-08 04:10:27 +00:00
nic_router: support multiple DHCP option 6 entries
* The NIC router now considers, memorizes, and, if configured, reports multiple DHCP option 6 entries from DHCP replies that it received as DHCP client * A DHCP server at the NIC router can now be configured statically with multiple DNS server addresses to propagate * The 'dns_server_from' attribute of the DHCP server of the NIC router now supports the forwarding of multiple DNS server addresses * The automated run/nic_router_dhcp test tests all the above mentioned new functionality and reconfiguring it at runtime. The test was added to the autopilot. * All run scripts were adapted to fit the new NIC router configuration interface Fixes #3952
This commit is contained in:
parent
306466fc60
commit
bad8caee3f
@ -228,8 +228,11 @@ proc test_7_router_config { } {
|
|||||||
<domain name="t7_d1" interface="100.200.0.1/24">
|
<domain name="t7_d1" interface="100.200.0.1/24">
|
||||||
<dhcp-server ip_first="100.200.0.32"
|
<dhcp-server ip_first="100.200.0.32"
|
||||||
ip_last="100.200.0.64"
|
ip_last="100.200.0.64"
|
||||||
ip_lease_time_sec="3600"
|
ip_lease_time_sec="3600">
|
||||||
dns_server="8.8.8.8"/>
|
|
||||||
|
<dns-server ip="8.8.8.8"/>
|
||||||
|
|
||||||
|
</dhcp-server>
|
||||||
|
|
||||||
<tcp dst="10.0.0.0/16">
|
<tcp dst="10.0.0.0/16">
|
||||||
<permit port="2345" domain="t7_d2" />
|
<permit port="2345" domain="t7_d2" />
|
||||||
|
@ -159,8 +159,9 @@ proc test_7_router_config { } {
|
|||||||
<domain name="lan_2" interface="100.200.0.1/24">
|
<domain name="lan_2" interface="100.200.0.1/24">
|
||||||
<dhcp-server ip_first="100.200.0.32"
|
<dhcp-server ip_first="100.200.0.32"
|
||||||
ip_last="100.200.0.64"
|
ip_last="100.200.0.64"
|
||||||
ip_lease_time_sec="3600"
|
ip_lease_time_sec="3600">
|
||||||
dns_server="8.8.8.8"/>
|
<dns-server ip="8.8.8.8"/>
|
||||||
|
</dhcp-server>
|
||||||
|
|
||||||
<tcp dst="10.0.0.0/16">
|
<tcp dst="10.0.0.0/16">
|
||||||
<permit port="2345" domain="lan_3" />
|
<permit port="2345" domain="lan_3" />
|
||||||
|
282
repos/os/run/nic_router_dhcp.inc
Normal file
282
repos/os/run/nic_router_dhcp.inc
Normal file
@ -0,0 +1,282 @@
|
|||||||
|
#
|
||||||
|
# See os/src/test/nic_router_dhcp/README for a documentation.
|
||||||
|
#
|
||||||
|
|
||||||
|
create_boot_directory
|
||||||
|
|
||||||
|
import_from_depot [depot_user]/src/[base_src]
|
||||||
|
|
||||||
|
set build_components {
|
||||||
|
|
||||||
|
init
|
||||||
|
server/dynamic_rom
|
||||||
|
test/nic_router_dhcp/client
|
||||||
|
server/nic_router
|
||||||
|
}
|
||||||
|
|
||||||
|
lappend_if [nic_router_2_managed] build_components test/nic_router_dhcp/manager
|
||||||
|
lappend_if [nic_router_2_managed] build_components server/report_rom
|
||||||
|
|
||||||
|
build $build_components
|
||||||
|
|
||||||
|
append config {
|
||||||
|
|
||||||
|
<config>
|
||||||
|
|
||||||
|
<parent-provides>
|
||||||
|
<service name="ROM"/>
|
||||||
|
<service name="IRQ"/>
|
||||||
|
<service name="IO_MEM"/>
|
||||||
|
<service name="IO_PORT"/>
|
||||||
|
<service name="PD"/>
|
||||||
|
<service name="RM"/>
|
||||||
|
<service name="CPU"/>
|
||||||
|
<service name="LOG"/>
|
||||||
|
</parent-provides>
|
||||||
|
|
||||||
|
<default-route>
|
||||||
|
<any-service> <parent/> <any-child/> </any-service>
|
||||||
|
</default-route>
|
||||||
|
<default caps="200"/>
|
||||||
|
|
||||||
|
<start name="timer">
|
||||||
|
<resource name="RAM" quantum="1M"/>
|
||||||
|
<provides><service name="Timer"/></provides>
|
||||||
|
</start>
|
||||||
|
|
||||||
|
<start name="dynamic_rom">
|
||||||
|
<resource name="RAM" quantum="4M"/>
|
||||||
|
<provides><service name="ROM"/> </provides>
|
||||||
|
<config verbose="yes">
|
||||||
|
<rom name="nic_router_1.config">
|
||||||
|
<inline>
|
||||||
|
|
||||||
|
<config>
|
||||||
|
|
||||||
|
<policy label="nic_router_2 -> " domain="downlink"/>
|
||||||
|
|
||||||
|
<domain name="downlink" interface="10.2.3.1/24">
|
||||||
|
|
||||||
|
<dhcp-server ip_first="10.2.3.2"
|
||||||
|
ip_last="10.2.3.2">
|
||||||
|
|
||||||
|
<dns-server ip="1.2.3.4"/>
|
||||||
|
<dns-server ip="2.3.4.5"/>
|
||||||
|
<dns-server ip="3.4.5.6"/>
|
||||||
|
|
||||||
|
</dhcp-server>
|
||||||
|
|
||||||
|
</domain>
|
||||||
|
|
||||||
|
</config>
|
||||||
|
|
||||||
|
</inline>
|
||||||
|
<sleep milliseconds="3000"/>
|
||||||
|
<inline>
|
||||||
|
|
||||||
|
<config>
|
||||||
|
|
||||||
|
<policy label="nic_router_2 -> " domain="downlink"/>
|
||||||
|
|
||||||
|
<domain name="downlink" interface="10.2.3.1/24">
|
||||||
|
|
||||||
|
<dhcp-server ip_first="10.2.3.2"
|
||||||
|
ip_last="10.2.3.2">
|
||||||
|
|
||||||
|
<dns-server ip="4.5.6.7"/>
|
||||||
|
<dns-server ip="5.6.7.8"/>
|
||||||
|
|
||||||
|
</dhcp-server>
|
||||||
|
|
||||||
|
</domain>
|
||||||
|
|
||||||
|
</config>
|
||||||
|
|
||||||
|
</inline>
|
||||||
|
<sleep milliseconds="3000"/>
|
||||||
|
<inline>
|
||||||
|
|
||||||
|
<config>
|
||||||
|
|
||||||
|
<policy label="nic_router_2 -> " domain="downlink"/>
|
||||||
|
|
||||||
|
<domain name="downlink" interface="10.2.3.1/24">
|
||||||
|
|
||||||
|
<dhcp-server ip_first="10.2.3.2"
|
||||||
|
ip_last="10.2.3.2">
|
||||||
|
|
||||||
|
<dns-server ip="6.7.8.9"/>
|
||||||
|
|
||||||
|
</dhcp-server>
|
||||||
|
|
||||||
|
</domain>
|
||||||
|
|
||||||
|
</config>
|
||||||
|
|
||||||
|
</inline>
|
||||||
|
<sleep milliseconds="3000"/>
|
||||||
|
<inline>
|
||||||
|
|
||||||
|
<config>
|
||||||
|
|
||||||
|
<policy label="nic_router_2 -> " domain="downlink"/>
|
||||||
|
|
||||||
|
<domain name="downlink" interface="10.2.3.1/24">
|
||||||
|
|
||||||
|
<dhcp-server ip_first="10.2.3.2"
|
||||||
|
ip_last="10.2.3.2">
|
||||||
|
|
||||||
|
</dhcp-server>
|
||||||
|
|
||||||
|
</domain>
|
||||||
|
|
||||||
|
</config>
|
||||||
|
|
||||||
|
</inline>
|
||||||
|
<sleep milliseconds="3000"/>
|
||||||
|
|
||||||
|
</rom>
|
||||||
|
</config>
|
||||||
|
</start>
|
||||||
|
|
||||||
|
<start name="nic_router_1">
|
||||||
|
<binary name="nic_router"/>
|
||||||
|
<resource name="RAM" quantum="10M"/>
|
||||||
|
<provides><service name="Nic"/></provides>
|
||||||
|
<route>
|
||||||
|
<service name="ROM" label="config">
|
||||||
|
<child name="dynamic_rom" label="nic_router_1.config"/>
|
||||||
|
</service>
|
||||||
|
<any-service> <parent/> <any-child/> </any-service>
|
||||||
|
</route>
|
||||||
|
</start>
|
||||||
|
|
||||||
|
<start name="nic_router_2">
|
||||||
|
<binary name="nic_router"/>
|
||||||
|
<resource name="RAM" quantum="10M"/>
|
||||||
|
<provides><service name="Nic"/></provides>}
|
||||||
|
|
||||||
|
append_if [expr ![nic_router_2_managed]] config {
|
||||||
|
|
||||||
|
<config verbose_packets="no">
|
||||||
|
|
||||||
|
<policy label="test_client -> " domain="downlink"/>
|
||||||
|
<uplink domain="uplink"/>
|
||||||
|
|
||||||
|
<domain name="uplink"/>
|
||||||
|
<domain name="downlink" interface="10.0.3.1/24">
|
||||||
|
|
||||||
|
<dhcp-server ip_first="10.0.3.2"
|
||||||
|
ip_last="10.0.3.2"
|
||||||
|
dns_server_from="uplink"/>
|
||||||
|
|
||||||
|
</domain>
|
||||||
|
|
||||||
|
</config>}
|
||||||
|
|
||||||
|
append config {
|
||||||
|
|
||||||
|
<route>
|
||||||
|
<service name="Nic"> <child name="nic_router_1"/> </service>}
|
||||||
|
|
||||||
|
append_if [nic_router_2_managed] config {
|
||||||
|
|
||||||
|
<service name="ROM" label="config">
|
||||||
|
<child name="report_rom"/>
|
||||||
|
</service>}
|
||||||
|
|
||||||
|
append config {
|
||||||
|
|
||||||
|
<any-service> <parent/> <any-child/> </any-service>
|
||||||
|
</route>
|
||||||
|
</start>
|
||||||
|
|
||||||
|
<start name="test_client">
|
||||||
|
<binary name="test-nic_router_dhcp-client"/>
|
||||||
|
<resource name="RAM" quantum="10M"/>
|
||||||
|
<config verbose="no"/>
|
||||||
|
<route>
|
||||||
|
<service name="Nic"> <child name="nic_router_2"/> </service>
|
||||||
|
<any-service> <parent/> <any-child/> </any-service>
|
||||||
|
</route>
|
||||||
|
</start>}
|
||||||
|
|
||||||
|
append_if [nic_router_2_managed] config {
|
||||||
|
|
||||||
|
<start name="report_rom">
|
||||||
|
<resource name="RAM" quantum="1M"/>
|
||||||
|
<provides> <service name="Report"/> <service name="ROM"/> </provides>
|
||||||
|
<config verbose="no">
|
||||||
|
<policy label="test_manager -> router_state"
|
||||||
|
report="nic_router_2 -> state"/>
|
||||||
|
|
||||||
|
<policy label="nic_router_2 -> config"
|
||||||
|
report="test_manager -> router_config"/>
|
||||||
|
</config>
|
||||||
|
</start>
|
||||||
|
|
||||||
|
<start name="test_manager">
|
||||||
|
<binary name="test-nic_router_dhcp-manager"/>
|
||||||
|
<resource name="RAM" quantum="1M"/>
|
||||||
|
<route>
|
||||||
|
<service name="ROM" label="router_state">
|
||||||
|
<child name="report_rom"/>
|
||||||
|
</service>
|
||||||
|
<service name="Report"> <child name="report_rom"/> </service>
|
||||||
|
<any-service> <parent/> <any-child/> </any-service>
|
||||||
|
</route>
|
||||||
|
</start>}
|
||||||
|
|
||||||
|
append config {
|
||||||
|
|
||||||
|
</config>}
|
||||||
|
|
||||||
|
install_config $config
|
||||||
|
|
||||||
|
set boot_modules {
|
||||||
|
|
||||||
|
init
|
||||||
|
dynamic_rom
|
||||||
|
nic_router
|
||||||
|
test-nic_router_dhcp-client
|
||||||
|
}
|
||||||
|
|
||||||
|
lappend_if [nic_router_2_managed] boot_modules test-nic_router_dhcp-manager
|
||||||
|
lappend_if [nic_router_2_managed] boot_modules report_rom
|
||||||
|
|
||||||
|
build_boot_image $boot_modules
|
||||||
|
|
||||||
|
append qemu_args " -nographic "
|
||||||
|
append_qemu_nic_args
|
||||||
|
|
||||||
|
append done_string ".*DHCP request completed:.*\n"
|
||||||
|
append done_string ".* IP lease time: 3600 seconds.*\n"
|
||||||
|
append done_string ".* Interface: 10.0.3.2/24.*\n"
|
||||||
|
append done_string ".* Router: 10.0.3.1.*\n"
|
||||||
|
append done_string ".* DNS server #1: 1.2.3.4.*\n"
|
||||||
|
append done_string ".* DNS server #2: 2.3.4.5.*\n"
|
||||||
|
append done_string ".* DNS server #3: 3.4.5.6.*\n"
|
||||||
|
append done_string ".*DHCP request completed:.*\n"
|
||||||
|
append done_string ".* IP lease time: 3600 seconds.*\n"
|
||||||
|
append done_string ".* Interface: 10.0.3.2/24.*\n"
|
||||||
|
append done_string ".* Router: 10.0.3.1.*\n"
|
||||||
|
append done_string ".* DNS server #1: 4.5.6.7.*\n"
|
||||||
|
append done_string ".* DNS server #2: 5.6.7.8.*\n"
|
||||||
|
append done_string ".*DHCP request completed:.*\n"
|
||||||
|
append done_string ".* IP lease time: 3600 seconds.*\n"
|
||||||
|
append done_string ".* Interface: 10.0.3.2/24.*\n"
|
||||||
|
append done_string ".* Router: 10.0.3.1.*\n"
|
||||||
|
append done_string ".* DNS server #1: 6.7.8.9.*\n"
|
||||||
|
append done_string ".*DHCP request completed:.*\n"
|
||||||
|
append done_string ".* IP lease time: 3600 seconds.*\n"
|
||||||
|
append done_string ".* Interface: 10.0.3.2/24.*\n"
|
||||||
|
append done_string ".* Router: 10.0.3.1.*\n"
|
||||||
|
append done_string ".*DHCP request completed:.*\n"
|
||||||
|
append done_string ".* IP lease time: 3600 seconds.*\n"
|
||||||
|
append done_string ".* Interface: 10.0.3.2/24.*\n"
|
||||||
|
append done_string ".* Router: 10.0.3.1.*\n"
|
||||||
|
append done_string ".* DNS server #1: 1.2.3.4.*\n"
|
||||||
|
append done_string ".* DNS server #2: 2.3.4.5.*\n"
|
||||||
|
append done_string ".* DNS server #3: 3.4.5.6.*\n"
|
||||||
|
|
||||||
|
run_genode_until $done_string 30
|
6
repos/os/run/nic_router_dhcp_managed.run
Normal file
6
repos/os/run/nic_router_dhcp_managed.run
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#
|
||||||
|
# See os/src/test/nic_router_dhcp/README for a documentation.
|
||||||
|
#
|
||||||
|
|
||||||
|
proc nic_router_2_managed { } { return 1 }
|
||||||
|
source ${genode_dir}/repos/os/run/nic_router_dhcp.inc
|
6
repos/os/run/nic_router_dhcp_unmanaged.run
Normal file
6
repos/os/run/nic_router_dhcp_unmanaged.run
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#
|
||||||
|
# See os/src/test/nic_router_dhcp/README for a documentation.
|
||||||
|
#
|
||||||
|
|
||||||
|
proc nic_router_2_managed { } { return 0 }
|
||||||
|
source ${genode_dir}/repos/os/run/nic_router_dhcp.inc
|
@ -385,34 +385,61 @@ One can configure the NIC router to act as DHCP server at interfaces of a
|
|||||||
domain by adding the <dhcp> tag to the configuration of the domain like
|
domain by adding the <dhcp> tag to the configuration of the domain like
|
||||||
this:
|
this:
|
||||||
|
|
||||||
<domain name="vbox" interface="10.0.1.1/24">
|
! <domain name="vbox" interface="10.0.1.1/24">
|
||||||
<dhcp-server ip_first="10.0.1.80"
|
!
|
||||||
ip_last="10.0.1.100"
|
! <dhcp-server ip_first="10.0.1.80"
|
||||||
ip_lease_time_sec="3600"
|
! ip_last="10.0.1.100"
|
||||||
dns_server="10.0.0.2"
|
! ip_lease_time_sec="3600">
|
||||||
dns_server_from="uplink" />
|
!
|
||||||
...
|
! <dns-server ip="8.8.8.8" />
|
||||||
</domain>
|
! <dns-server ip="1.1.1.1" />
|
||||||
|
! ...
|
||||||
|
!
|
||||||
|
! </dhcp-server>
|
||||||
|
! ...
|
||||||
|
!
|
||||||
|
! </domain>
|
||||||
|
|
||||||
The attributes ip_first and ip_last define the available IPv4 address range
|
or like this:
|
||||||
while ip_lease_time_sec defines the lifetime of an IPv4 address assignment in
|
|
||||||
seconds. The IPv4 address range must be in the subnet defined by the interface
|
! <domain name="vbox" interface="10.0.1.1/24">
|
||||||
attribute of the domain tag and must not cover the IPv4 address in this
|
!
|
||||||
attribute. The dns_server attribute gives the IPv4 address of the DNS server
|
! <dhcp-server ip_first="10.0.1.80"
|
||||||
that might also be in another subnet. The dns_server_from attribute has effect
|
! ip_last="10.0.1.100"
|
||||||
only if the dns_server attribute is not set. If this is the case, the
|
! ip_lease_time_sec="3600"
|
||||||
dns_server_from attribute states the domain from whose IP config to take the
|
! dns_server_from="uplink" />
|
||||||
DNS server address. This is useful, for instance, if the stated domain
|
! ...
|
||||||
receives the address of a local DNS server via DHCP. Whenever the IP config
|
!
|
||||||
of the stated domain becomes invalid, the DHCP server switches to a mode where
|
! </domain>
|
||||||
it drops all requests unanswered until the IP config becomes valid again.
|
|
||||||
|
The mandatory attributes 'ip_first' and 'ip_last' define the available IPv4
|
||||||
|
address range while the optional attribute 'ip_lease_time_sec' defines the
|
||||||
|
lifetime of an IPv4 address assignment in seconds. The IPv4 address range must
|
||||||
|
be in the subnet defined by the 'interface' attribute of the <domain> tag and
|
||||||
|
must not cover the IPv4 address given by this attribute.
|
||||||
|
|
||||||
|
The <dns-server> sub-tags from the first example statically provide a list of
|
||||||
|
DNS server addresses that shall be propagated by the DHCP server through DHCP
|
||||||
|
option 6 entries to its clients. These addresses might be of any IP subnet. The
|
||||||
|
DHCP option 6 entries in the DHCP replies will have the same order as the
|
||||||
|
<dns-server> tags in the configuration.
|
||||||
|
|
||||||
|
The 'dns_server_from' attribute from the second example takes effect only when
|
||||||
|
the <dhcp-server> tag does not contain any <dns-server> sub-tags. The attribute
|
||||||
|
states the domain from whose IP config to take the list of propagated DNS
|
||||||
|
server addresses. Note that the order of DNS server adresses is not altered
|
||||||
|
thereby. This is useful in scenarios where these addresses must be obtained
|
||||||
|
dynamically through the DHCP client of another domain. An implication of the
|
||||||
|
'dns_server_from' attribute is that the link state of all interfaces at the
|
||||||
|
domain with the DHCP server becomes bound to the validity of the IP config of
|
||||||
|
the domain that is stated in the attribute.
|
||||||
|
|
||||||
The lifetime of an assignment that was yet only offered to the client can be
|
The lifetime of an assignment that was yet only offered to the client can be
|
||||||
configured for all domains in the <config> tag of the router:
|
configured for all domains in the <config> tag of the router:
|
||||||
|
|
||||||
! <config dhcp_offer_timeout_sec="6">
|
! <config dhcp_offer_timeout_sec="6">
|
||||||
|
|
||||||
The timeout ip_lease_time_sec is applied only when the offer is acknowledged
|
The timeout 'ip_lease_time_sec' is applied only when the offer is acknowledged
|
||||||
by the client in time.
|
by the client in time.
|
||||||
|
|
||||||
|
|
||||||
@ -454,7 +481,7 @@ Configuration example (shows default values of attributes):
|
|||||||
! quota="yes"
|
! quota="yes"
|
||||||
! config="yes"
|
! config="yes"
|
||||||
! config_triggers="no"
|
! config_triggers="no"
|
||||||
! interval_sec="5">
|
! interval_sec="5"/>
|
||||||
! </config>
|
! </config>
|
||||||
|
|
||||||
If the 'report' tag is not available, no reports are send.
|
If the 'report' tag is not available, no reports are send.
|
||||||
@ -560,19 +587,24 @@ two contrary edges at a max. The following diagrams demonstrate this:
|
|||||||
Examples
|
Examples
|
||||||
~~~~~~~~
|
~~~~~~~~
|
||||||
|
|
||||||
This section will list and explain some interesting configuration snippets. A
|
In-action examples of how to use the router are provided through the following
|
||||||
comprehensive example of how to use the router (except DHCP server
|
automated run scripts:
|
||||||
functionality) can be found in the test script 'libports/run/nic_router.run'.
|
|
||||||
For an example of how to use the DHCP server and the DHCP client functionality
|
|
||||||
see the 'os/run/ping_nic_router.run' script.
|
|
||||||
|
|
||||||
The environment for the examples shall be as
|
* libports/run/nic_router.run (basic functionality)
|
||||||
follows. There are two virtual subnets 192.168.1.0/24 and 192.168.2.0/24 that
|
* dde_linux/run/nic_router_uplinks.run (dynamically switching uplinks)
|
||||||
connect as Virtnet A and B to the router. The standard gateway of the virtual
|
* os/run/ping_nic_router.run (ICMP routing)
|
||||||
networks is the NIC router with IP 192.168.*.1 . The router's uplink leads to
|
* os/run/nic_router_dhcp_unmanaged.run (DHCP + link states without a manager)
|
||||||
the NIC driver that connects the machine with your home network 10.0.2.0/24.
|
* os/run/nic_router_dhcp_managed.run (DHCP + link states with a manager)
|
||||||
Your home network is connected to the internet through its standard gateway
|
* os/run/nic_router_flood.run (client misbehaving on protocol level)
|
||||||
10.0.2.1 .
|
* os/run/nic_router_stress.run (client misbehaving on session level)
|
||||||
|
|
||||||
|
The rest of this section will list and explain some smaller configuration
|
||||||
|
snippets. The environment for these examples shall be as follows. There are
|
||||||
|
two virtual subnets 192.168.1.0/24 and 192.168.2.0/24 that connect as Virtnet A
|
||||||
|
and B to the router. The standard gateway of the virtual networks is the NIC
|
||||||
|
router with IP 192.168.*.1 . The router's uplink leads to the NIC driver that
|
||||||
|
connects the machine with your home network 10.0.2.0/24. Your home network is
|
||||||
|
connected to the internet through its standard gateway 10.0.2.1 .
|
||||||
|
|
||||||
|
|
||||||
Connecting local networks
|
Connecting local networks
|
||||||
|
@ -109,10 +109,18 @@
|
|||||||
|
|
||||||
<xs:element name="dhcp-server">
|
<xs:element name="dhcp-server">
|
||||||
<xs:complexType>
|
<xs:complexType>
|
||||||
|
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||||
|
|
||||||
|
<xs:element name="dns-server">
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:attribute name="ip" type="Ipv4_address" />
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element><!-- dns-server -->
|
||||||
|
|
||||||
|
</xs:choice>
|
||||||
<xs:attribute name="ip_first" type="Ipv4_address" />
|
<xs:attribute name="ip_first" type="Ipv4_address" />
|
||||||
<xs:attribute name="ip_last" type="Ipv4_address" />
|
<xs:attribute name="ip_last" type="Ipv4_address" />
|
||||||
<xs:attribute name="ip_lease_time_sec" type="Seconds" />
|
<xs:attribute name="ip_lease_time_sec" type="Seconds" />
|
||||||
<xs:attribute name="dns_server" type="Ipv4_address" />
|
|
||||||
<xs:attribute name="dns_server_from" type="Domain_name" />
|
<xs:attribute name="dns_server_from" type="Domain_name" />
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
</xs:element><!-- dhcp-server -->
|
</xs:element><!-- dhcp-server -->
|
||||||
|
30
repos/os/src/server/nic_router/dhcp.h
Normal file
30
repos/os/src/server/nic_router/dhcp.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* \brief Genode DHCP protocol plus local utilities
|
||||||
|
* \author Martin Stein
|
||||||
|
* \date 2020-11-18
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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 _DHCP_H_
|
||||||
|
#define _DHCP_H_
|
||||||
|
|
||||||
|
/* Genode includes */
|
||||||
|
#include <net/dhcp.h>
|
||||||
|
|
||||||
|
namespace Net {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static Ipv4_address dhcp_ipv4_option(Dhcp_packet &dhcp)
|
||||||
|
{
|
||||||
|
try { return dhcp.option<T>().value(); }
|
||||||
|
catch (Dhcp_packet::Option_not_found) { return Ipv4_address { }; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _DHCP_H_ */
|
@ -142,20 +142,7 @@ void Dhcp_client::handle_dhcp_reply(Dhcp_packet &dhcp)
|
|||||||
}
|
}
|
||||||
_lease_time_sec = dhcp.option<Dhcp_packet::Ip_lease_time>().value();
|
_lease_time_sec = dhcp.option<Dhcp_packet::Ip_lease_time>().value();
|
||||||
_set_state(State::BOUND, _rerequest_timeout(1));
|
_set_state(State::BOUND, _rerequest_timeout(1));
|
||||||
|
_domain().ip_config_from_dhcp_ack(dhcp);
|
||||||
Ipv4_address dns_server;
|
|
||||||
Ipv4_address subnet_mask;
|
|
||||||
Ipv4_address router_ip;
|
|
||||||
|
|
||||||
try { dns_server = dhcp.option<Dhcp_packet::Dns_server_ipv4>().value(); }
|
|
||||||
catch (Dhcp_packet::Option_not_found) { }
|
|
||||||
try { subnet_mask = dhcp.option<Dhcp_packet::Subnet_mask>().value(); }
|
|
||||||
catch (Dhcp_packet::Option_not_found) { }
|
|
||||||
try { router_ip = dhcp.option<Dhcp_packet::Router_ipv4>().value(); }
|
|
||||||
catch (Net::Dhcp_packet::Option_not_found) { }
|
|
||||||
|
|
||||||
_domain().ip_config(dhcp.yiaddr(), subnet_mask, router_ip,
|
|
||||||
dns_server);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case State::RENEW:
|
case State::RENEW:
|
||||||
|
@ -21,12 +21,38 @@ using namespace Net;
|
|||||||
using namespace Genode;
|
using namespace Genode;
|
||||||
|
|
||||||
|
|
||||||
/*****************
|
/**********************
|
||||||
** Dhcp_server **
|
** Dhcp_server_base **
|
||||||
*****************/
|
**********************/
|
||||||
|
|
||||||
void Dhcp_server::_invalid(Domain &domain,
|
Dhcp_server_base::Dhcp_server_base(Xml_node const &node,
|
||||||
char const *reason)
|
Domain const &domain,
|
||||||
|
Allocator &alloc)
|
||||||
|
:
|
||||||
|
_alloc { alloc }
|
||||||
|
{
|
||||||
|
node.for_each_sub_node("dns-server", [&] (Xml_node const &sub_node) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
_dns_servers.insert_as_tail(*new (alloc)
|
||||||
|
Dns_server(sub_node.attribute_value("ip", Ipv4_address())));
|
||||||
|
|
||||||
|
} catch (Dns_server::Invalid) {
|
||||||
|
|
||||||
|
_invalid(domain, "invalid DNS server entry");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Dhcp_server_base::~Dhcp_server_base()
|
||||||
|
{
|
||||||
|
_dns_servers.destroy_each(_alloc);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Dhcp_server_base::_invalid(Domain const &domain,
|
||||||
|
char const *reason)
|
||||||
{
|
{
|
||||||
if (domain.config().verbose()) {
|
if (domain.config().verbose()) {
|
||||||
log("[", domain, "] invalid DHCP server (", reason, ")"); }
|
log("[", domain, "] invalid DHCP server (", reason, ")"); }
|
||||||
@ -35,13 +61,17 @@ void Dhcp_server::_invalid(Domain &domain,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************
|
||||||
|
** Dhcp_server **
|
||||||
|
*****************/
|
||||||
|
|
||||||
Dhcp_server::Dhcp_server(Xml_node const node,
|
Dhcp_server::Dhcp_server(Xml_node const node,
|
||||||
Domain &domain,
|
Domain &domain,
|
||||||
Allocator &alloc,
|
Allocator &alloc,
|
||||||
Ipv4_address_prefix const &interface,
|
Ipv4_address_prefix const &interface,
|
||||||
Domain_tree &domains)
|
Domain_tree &domains)
|
||||||
:
|
:
|
||||||
_dns_server(node.attribute_value("dns_server", Ipv4_address())),
|
Dhcp_server_base(node, domain, alloc),
|
||||||
_dns_server_from(_init_dns_server_from(node, domains)),
|
_dns_server_from(_init_dns_server_from(node, domains)),
|
||||||
_ip_lease_time (_init_ip_lease_time(node)),
|
_ip_lease_time (_init_ip_lease_time(node)),
|
||||||
_ip_first(node.attribute_value("ip_first", Ipv4_address())),
|
_ip_first(node.attribute_value("ip_first", Ipv4_address())),
|
||||||
@ -75,9 +105,9 @@ Microseconds Dhcp_server::_init_ip_lease_time(Xml_node const node)
|
|||||||
|
|
||||||
void Dhcp_server::print(Output &output) const
|
void Dhcp_server::print(Output &output) const
|
||||||
{
|
{
|
||||||
if (_dns_server.valid()) {
|
_dns_servers.for_each([&] (Dns_server const &dns_server) {
|
||||||
Genode::print(output, "DNS server ", _dns_server, ", ");
|
Genode::print(output, "DNS server ", dns_server.ip(), ", ");
|
||||||
}
|
});
|
||||||
try { Genode::print(output, "DNS server from ", _dns_server_from(), ", "); }
|
try { Genode::print(output, "DNS server from ", _dns_server_from(), ", "); }
|
||||||
catch (Pointer<Domain>::Invalid) { }
|
catch (Pointer<Domain>::Invalid) { }
|
||||||
|
|
||||||
@ -88,6 +118,18 @@ void Dhcp_server::print(Output &output) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Dhcp_server::dns_servers_equal_to_those_of(Dhcp_server const &dhcp_server) const
|
||||||
|
{
|
||||||
|
return _dns_servers.equal_to(dhcp_server._dns_servers);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Ipv4_config const &Dhcp_server::_resolve_dns_server_from() const
|
||||||
|
{
|
||||||
|
return _dns_server_from().ip_config();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Ipv4_address Dhcp_server::alloc_ip()
|
Ipv4_address Dhcp_server::alloc_ip()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
@ -117,7 +159,7 @@ void Dhcp_server::free_ip(Ipv4_address const &ip)
|
|||||||
Pointer<Domain> Dhcp_server::_init_dns_server_from(Genode::Xml_node const node,
|
Pointer<Domain> Dhcp_server::_init_dns_server_from(Genode::Xml_node const node,
|
||||||
Domain_tree &domains)
|
Domain_tree &domains)
|
||||||
{
|
{
|
||||||
if (_dns_server.valid()) {
|
if (!_dns_servers.empty()) {
|
||||||
return Pointer<Domain>();
|
return Pointer<Domain>();
|
||||||
}
|
}
|
||||||
Domain_name dns_server_from =
|
Domain_name dns_server_from =
|
||||||
@ -131,17 +173,9 @@ Pointer<Domain> Dhcp_server::_init_dns_server_from(Genode::Xml_node const node,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Ipv4_address const &Dhcp_server::dns_server() const
|
|
||||||
{
|
|
||||||
try { return _dns_server_from().ip_config().dns_server; }
|
|
||||||
catch (Pointer<Domain>::Invalid) { }
|
|
||||||
return _dns_server;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool Dhcp_server::ready() const
|
bool Dhcp_server::ready() const
|
||||||
{
|
{
|
||||||
if (_dns_server.valid()) {
|
if (!_dns_servers.empty()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
try { return _dns_server_from().ip_config().valid; }
|
try { return _dns_server_from().ip_config().valid; }
|
||||||
|
@ -15,10 +15,11 @@
|
|||||||
#define _DHCP_SERVER_H_
|
#define _DHCP_SERVER_H_
|
||||||
|
|
||||||
/* local includes */
|
/* local includes */
|
||||||
#include <ipv4_address_prefix.h>
|
|
||||||
#include <bit_allocator_dynamic.h>
|
#include <bit_allocator_dynamic.h>
|
||||||
#include <list.h>
|
#include <list.h>
|
||||||
#include <pointer.h>
|
#include <pointer.h>
|
||||||
|
#include <dns_server.h>
|
||||||
|
#include <ipv4_config.h>
|
||||||
|
|
||||||
/* Genode includes */
|
/* Genode includes */
|
||||||
#include <net/mac_address.h>
|
#include <net/mac_address.h>
|
||||||
@ -29,6 +30,7 @@
|
|||||||
namespace Net {
|
namespace Net {
|
||||||
|
|
||||||
class Configuration;
|
class Configuration;
|
||||||
|
class Dhcp_server_base;
|
||||||
class Dhcp_server;
|
class Dhcp_server;
|
||||||
class Dhcp_allocation;
|
class Dhcp_allocation;
|
||||||
class Dhcp_allocation_tree;
|
class Dhcp_allocation_tree;
|
||||||
@ -41,11 +43,31 @@ namespace Net {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class Net::Dhcp_server : private Genode::Noncopyable
|
class Net::Dhcp_server_base
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
Genode::Allocator &_alloc;
|
||||||
|
Net::List<Dns_server> _dns_servers { };
|
||||||
|
|
||||||
|
void _invalid(Domain const &domain,
|
||||||
|
char const *reason);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Dhcp_server_base(Genode::Xml_node const &node,
|
||||||
|
Domain const &domain,
|
||||||
|
Genode::Allocator &alloc);
|
||||||
|
|
||||||
|
~Dhcp_server_base();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Net::Dhcp_server : private Genode::Noncopyable,
|
||||||
|
private Net::Dhcp_server_base
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Ipv4_address const _dns_server;
|
|
||||||
Pointer<Domain> const _dns_server_from;
|
Pointer<Domain> const _dns_server_from;
|
||||||
Genode::Microseconds const _ip_lease_time;
|
Genode::Microseconds const _ip_lease_time;
|
||||||
Ipv4_address const _ip_first;
|
Ipv4_address const _ip_first;
|
||||||
@ -54,14 +76,13 @@ class Net::Dhcp_server : private Genode::Noncopyable
|
|||||||
Genode::uint32_t const _ip_count;
|
Genode::uint32_t const _ip_count;
|
||||||
Genode::Bit_allocator_dynamic _ip_alloc;
|
Genode::Bit_allocator_dynamic _ip_alloc;
|
||||||
|
|
||||||
void _invalid(Domain &domain,
|
|
||||||
char const *reason);
|
|
||||||
|
|
||||||
Genode::Microseconds _init_ip_lease_time(Genode::Xml_node const node);
|
Genode::Microseconds _init_ip_lease_time(Genode::Xml_node const node);
|
||||||
|
|
||||||
Pointer<Domain> _init_dns_server_from(Genode::Xml_node const node,
|
Pointer<Domain> _init_dns_server_from(Genode::Xml_node const node,
|
||||||
Domain_tree &domains);
|
Domain_tree &domains);
|
||||||
|
|
||||||
|
Ipv4_config const &_resolve_dns_server_from() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
enum { DEFAULT_IP_LEASE_TIME_SEC = 3600 };
|
enum { DEFAULT_IP_LEASE_TIME_SEC = 3600 };
|
||||||
@ -83,6 +104,27 @@ class Net::Dhcp_server : private Genode::Noncopyable
|
|||||||
|
|
||||||
bool ready() const;
|
bool ready() const;
|
||||||
|
|
||||||
|
template <typename FUNC>
|
||||||
|
void for_each_dns_server_ip(FUNC && functor) const
|
||||||
|
{
|
||||||
|
if (_dns_server_from.valid()) {
|
||||||
|
|
||||||
|
_resolve_dns_server_from().for_each_dns_server(
|
||||||
|
[&] (Dns_server const &dns_server) {
|
||||||
|
functor(dns_server.ip());
|
||||||
|
});
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
_dns_servers.for_each([&] (Dns_server const &dns_server) {
|
||||||
|
functor(dns_server.ip());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
dns_servers_equal_to_those_of(Dhcp_server const &dhcp_server) const;
|
||||||
|
|
||||||
|
|
||||||
/*********
|
/*********
|
||||||
** log **
|
** log **
|
||||||
@ -95,7 +137,6 @@ class Net::Dhcp_server : private Genode::Noncopyable
|
|||||||
** Accessors **
|
** Accessors **
|
||||||
***************/
|
***************/
|
||||||
|
|
||||||
Ipv4_address const &dns_server() const;
|
|
||||||
Domain &dns_server_from() { return _dns_server_from(); }
|
Domain &dns_server_from() { return _dns_server_from(); }
|
||||||
Genode::Microseconds ip_lease_time() const { return _ip_lease_time; }
|
Genode::Microseconds ip_lease_time() const { return _ip_lease_time; }
|
||||||
};
|
};
|
||||||
|
34
repos/os/src/server/nic_router/dns_server.cc
Normal file
34
repos/os/src/server/nic_router/dns_server.cc
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* \brief DNS server entry of a DHCP server or IPv4 config
|
||||||
|
* \author Martin Stein
|
||||||
|
* \date 2020-11-17
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* local includes */
|
||||||
|
#include <dns_server.h>
|
||||||
|
|
||||||
|
using namespace Net;
|
||||||
|
using namespace Genode;
|
||||||
|
|
||||||
|
|
||||||
|
Net::Dns_server::Dns_server(Ipv4_address const &ip)
|
||||||
|
:
|
||||||
|
_ip { ip }
|
||||||
|
{
|
||||||
|
if (!_ip.valid()) {
|
||||||
|
throw Invalid { };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Net::Dns_server::equal_to(Dns_server const &server) const
|
||||||
|
{
|
||||||
|
return _ip == server._ip;
|
||||||
|
}
|
50
repos/os/src/server/nic_router/dns_server.h
Normal file
50
repos/os/src/server/nic_router/dns_server.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* \brief DNS server entry of a DHCP server or IPv4 config
|
||||||
|
* \author Martin Stein
|
||||||
|
* \date 2020-11-17
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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 _DNS_SERVER_H_
|
||||||
|
#define _DNS_SERVER_H_
|
||||||
|
|
||||||
|
/* local includes */
|
||||||
|
#include <list.h>
|
||||||
|
|
||||||
|
/* Genode includes */
|
||||||
|
#include <net/ipv4.h>
|
||||||
|
|
||||||
|
namespace Net { class Dns_server; }
|
||||||
|
|
||||||
|
class Net::Dns_server : private Genode::Noncopyable,
|
||||||
|
public Net::List<Dns_server>::Element
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
Net::Ipv4_address const _ip;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
struct Invalid : Genode::Exception { };
|
||||||
|
|
||||||
|
Dns_server(Net::Ipv4_address const &ip);
|
||||||
|
|
||||||
|
bool equal_to(Dns_server const &server) const;
|
||||||
|
|
||||||
|
|
||||||
|
/***************
|
||||||
|
** Accessors **
|
||||||
|
***************/
|
||||||
|
|
||||||
|
Net::Ipv4_address const &ip() const { return _ip; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* _DHCP_SERVER_H_ */
|
@ -47,7 +47,7 @@ void Domain::_log_ip_config() const
|
|||||||
if (!ip_config.valid &&
|
if (!ip_config.valid &&
|
||||||
(ip_config.interface_valid ||
|
(ip_config.interface_valid ||
|
||||||
ip_config.gateway_valid ||
|
ip_config.gateway_valid ||
|
||||||
ip_config.dns_server_valid))
|
!ip_config.dns_servers.empty()))
|
||||||
{
|
{
|
||||||
log("[", *this, "] malformed ", _ip_config_dynamic ? "dynamic" :
|
log("[", *this, "] malformed ", _ip_config_dynamic ? "dynamic" :
|
||||||
"static", "IP config: ", ip_config);
|
"static", "IP config: ", ip_config);
|
||||||
@ -60,7 +60,7 @@ void Domain::_log_ip_config() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Domain::ip_config(Ipv4_config const &new_ip_config)
|
void Domain::_prepare_reconstructing_ip_config()
|
||||||
{
|
{
|
||||||
if (!_ip_config_dynamic) {
|
if (!_ip_config_dynamic) {
|
||||||
throw Ip_config_static(); }
|
throw Ip_config_static(); }
|
||||||
@ -69,7 +69,7 @@ void Domain::ip_config(Ipv4_config const &new_ip_config)
|
|||||||
if (ip_config().valid) {
|
if (ip_config().valid) {
|
||||||
|
|
||||||
/* mark IP config invalid */
|
/* mark IP config invalid */
|
||||||
_ip_config.construct();
|
_ip_config.construct(_alloc);
|
||||||
|
|
||||||
/* detach all dependent interfaces from old IP config */
|
/* detach all dependent interfaces from old IP config */
|
||||||
_interfaces.for_each([&] (Interface &interface) {
|
_interfaces.for_each([&] (Interface &interface) {
|
||||||
@ -86,8 +86,11 @@ void Domain::ip_config(Ipv4_config const &new_ip_config)
|
|||||||
waiter.src().cancel_arp_waiting(waiter);
|
waiter.src().cancel_arp_waiting(waiter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* overwrite old with new IP config */
|
}
|
||||||
_ip_config.construct(new_ip_config);
|
|
||||||
|
|
||||||
|
void Domain::_finish_reconstructing_ip_config()
|
||||||
|
{
|
||||||
_log_ip_config();
|
_log_ip_config();
|
||||||
|
|
||||||
/* attach all dependent interfaces to new IP config if it is valid */
|
/* attach all dependent interfaces to new IP config if it is valid */
|
||||||
@ -113,20 +116,15 @@ void Domain::ip_config(Ipv4_config const &new_ip_config)
|
|||||||
|
|
||||||
void Domain::discard_ip_config()
|
void Domain::discard_ip_config()
|
||||||
{
|
{
|
||||||
/* install invalid IP config */
|
_reconstruct_ip_config([&] (Reconstructible<Ipv4_config> &ip_config) {
|
||||||
Ipv4_config const new_ip_config;
|
ip_config.construct(_alloc); });
|
||||||
ip_config(new_ip_config);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Domain::ip_config(Ipv4_address ip,
|
void Domain::ip_config_from_dhcp_ack(Dhcp_packet &dhcp_ack)
|
||||||
Ipv4_address subnet_mask,
|
|
||||||
Ipv4_address gateway,
|
|
||||||
Ipv4_address dns_server)
|
|
||||||
{
|
{
|
||||||
Ipv4_config const new_ip_config(Ipv4_address_prefix(ip, subnet_mask),
|
_reconstruct_ip_config([&] (Reconstructible<Ipv4_config> &ip_config) {
|
||||||
gateway, dns_server);
|
ip_config.construct(dhcp_ack, _alloc); });
|
||||||
ip_config(new_ip_config);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -139,7 +137,8 @@ void Domain::try_reuse_ip_config(Domain const &domain)
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ip_config(domain.ip_config());
|
_reconstruct_ip_config([&] (Reconstructible<Ipv4_config> &ip_config) {
|
||||||
|
ip_config.construct(domain.ip_config(), _alloc); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -198,18 +197,20 @@ void Domain::print(Output &output) const
|
|||||||
|
|
||||||
Domain::Domain(Configuration &config, Xml_node const node, Allocator &alloc)
|
Domain::Domain(Configuration &config, Xml_node const node, Allocator &alloc)
|
||||||
:
|
:
|
||||||
Domain_base(node), Avl_string_base(_name.string()), _config(config),
|
Domain_base { node },
|
||||||
_node(node), _alloc(alloc),
|
Avl_string_base { Domain_base::_name.string() },
|
||||||
_ip_config(_node.attribute_value("interface", Ipv4_address_prefix()),
|
_config { config },
|
||||||
_node.attribute_value("gateway", Ipv4_address()),
|
_node { node },
|
||||||
Ipv4_address()),
|
_alloc { alloc },
|
||||||
_verbose_packets(_node.attribute_value("verbose_packets",
|
_ip_config { node, alloc },
|
||||||
_config.verbose_packets())),
|
_verbose_packets { node.attribute_value("verbose_packets",
|
||||||
_verbose_packet_drop(_node.attribute_value("verbose_packet_drop",
|
config.verbose_packets()) },
|
||||||
_config.verbose_packet_drop())),
|
_verbose_packet_drop { node.attribute_value("verbose_packet_drop",
|
||||||
_icmp_echo_server(_node.attribute_value("icmp_echo_server",
|
config.verbose_packet_drop()) },
|
||||||
_config.icmp_echo_server())),
|
_icmp_echo_server { node.attribute_value("icmp_echo_server",
|
||||||
_label(_node.attribute_value("label", String<160>()).string())
|
config.icmp_echo_server()) },
|
||||||
|
_label { node.attribute_value("label",
|
||||||
|
String<160>()).string() }
|
||||||
{
|
{
|
||||||
_log_ip_config();
|
_log_ip_config();
|
||||||
|
|
||||||
@ -375,7 +376,11 @@ void Domain::report(Xml_generator &xml)
|
|||||||
if (_config.report().config()) {
|
if (_config.report().config()) {
|
||||||
xml.attribute("ipv4", String<19>(ip_config().interface));
|
xml.attribute("ipv4", String<19>(ip_config().interface));
|
||||||
xml.attribute("gw", String<16>(ip_config().gateway));
|
xml.attribute("gw", String<16>(ip_config().gateway));
|
||||||
xml.attribute("dns", String<16>(ip_config().dns_server));
|
ip_config().for_each_dns_server([&] (Dns_server const &dns_server) {
|
||||||
|
xml.node("dns", [&] () {
|
||||||
|
xml.attribute("ip", String<16>(dns_server.ip()));
|
||||||
|
});
|
||||||
|
});
|
||||||
empty = false;
|
empty = false;
|
||||||
}
|
}
|
||||||
if (_config.report().stats()) {
|
if (_config.report().stats()) {
|
||||||
|
@ -142,6 +142,18 @@ class Net::Domain : public Domain_base,
|
|||||||
|
|
||||||
void _log_ip_config() const;
|
void _log_ip_config() const;
|
||||||
|
|
||||||
|
void _prepare_reconstructing_ip_config();
|
||||||
|
|
||||||
|
void _finish_reconstructing_ip_config();
|
||||||
|
|
||||||
|
template <typename FUNC>
|
||||||
|
void _reconstruct_ip_config(FUNC && functor)
|
||||||
|
{
|
||||||
|
_prepare_reconstructing_ip_config();
|
||||||
|
functor(_ip_config);
|
||||||
|
_finish_reconstructing_ip_config();
|
||||||
|
}
|
||||||
|
|
||||||
void __FIXME__dissolve_foreign_arp_waiters();
|
void __FIXME__dissolve_foreign_arp_waiters();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -162,12 +174,7 @@ class Net::Domain : public Domain_base,
|
|||||||
|
|
||||||
Ipv4_address const &next_hop(Ipv4_address const &ip) const;
|
Ipv4_address const &next_hop(Ipv4_address const &ip) const;
|
||||||
|
|
||||||
void ip_config(Ipv4_config const &ip_config);
|
void ip_config_from_dhcp_ack(Dhcp_packet &dhcp_ack);
|
||||||
|
|
||||||
void ip_config(Ipv4_address ip,
|
|
||||||
Ipv4_address subnet_mask,
|
|
||||||
Ipv4_address gateway,
|
|
||||||
Ipv4_address dns_server);
|
|
||||||
|
|
||||||
void discard_ip_config();
|
void discard_ip_config();
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@ using Genode::Exception;
|
|||||||
using Genode::Out_of_ram;
|
using Genode::Out_of_ram;
|
||||||
using Genode::Out_of_caps;
|
using Genode::Out_of_caps;
|
||||||
using Genode::Constructible;
|
using Genode::Constructible;
|
||||||
|
using Genode::Reconstructible;
|
||||||
using Genode::Signal_context_capability;
|
using Genode::Signal_context_capability;
|
||||||
using Genode::Signal_transmitter;
|
using Genode::Signal_transmitter;
|
||||||
|
|
||||||
@ -644,8 +645,9 @@ void Interface::_send_dhcp_reply(Dhcp_server const &dhcp_srv,
|
|||||||
dhcp_opts.append_option<Dhcp_packet::Ip_lease_time>(dhcp_srv.ip_lease_time().value / 1000 / 1000);
|
dhcp_opts.append_option<Dhcp_packet::Ip_lease_time>(dhcp_srv.ip_lease_time().value / 1000 / 1000);
|
||||||
dhcp_opts.append_option<Dhcp_packet::Subnet_mask>(local_intf.subnet_mask());
|
dhcp_opts.append_option<Dhcp_packet::Subnet_mask>(local_intf.subnet_mask());
|
||||||
dhcp_opts.append_option<Dhcp_packet::Router_ipv4>(local_intf.address);
|
dhcp_opts.append_option<Dhcp_packet::Router_ipv4>(local_intf.address);
|
||||||
if (dhcp_srv.dns_server().valid()) {
|
dhcp_srv.for_each_dns_server_ip([&] (Ipv4_address const &dns_server_ip) {
|
||||||
dhcp_opts.append_option<Dhcp_packet::Dns_server_ipv4>(dhcp_srv.dns_server()); }
|
dhcp_opts.append_option<Dhcp_packet::Dns_server_ipv4>(dns_server_ip);
|
||||||
|
});
|
||||||
dhcp_opts.append_option<Dhcp_packet::Broadcast_addr>(local_intf.broadcast_address());
|
dhcp_opts.append_option<Dhcp_packet::Broadcast_addr>(local_intf.broadcast_address());
|
||||||
dhcp_opts.append_option<Dhcp_packet::Options_end>();
|
dhcp_opts.append_option<Dhcp_packet::Options_end>();
|
||||||
|
|
||||||
@ -1865,7 +1867,7 @@ void Interface::_update_dhcp_allocations(Domain &old_domain,
|
|||||||
try {
|
try {
|
||||||
Dhcp_server &old_dhcp_srv = old_domain.dhcp_server();
|
Dhcp_server &old_dhcp_srv = old_domain.dhcp_server();
|
||||||
Dhcp_server &new_dhcp_srv = new_domain.dhcp_server();
|
Dhcp_server &new_dhcp_srv = new_domain.dhcp_server();
|
||||||
if (old_dhcp_srv.dns_server() != new_dhcp_srv.dns_server()) {
|
if (!old_dhcp_srv.dns_servers_equal_to_those_of(new_dhcp_srv)) {
|
||||||
throw Pointer<Dhcp_server>::Invalid();
|
throw Pointer<Dhcp_server>::Invalid();
|
||||||
}
|
}
|
||||||
if (old_dhcp_srv.ip_lease_time().value !=
|
if (old_dhcp_srv.ip_lease_time().value !=
|
||||||
|
@ -20,19 +20,79 @@
|
|||||||
using namespace Genode;
|
using namespace Genode;
|
||||||
using namespace Net;
|
using namespace Net;
|
||||||
|
|
||||||
Ipv4_config::Ipv4_config(Ipv4_address_prefix interface,
|
|
||||||
Ipv4_address gateway,
|
Ipv4_config::Ipv4_config(Allocator &alloc)
|
||||||
Ipv4_address dns_server)
|
|
||||||
:
|
:
|
||||||
interface(interface), gateway(gateway), dns_server(dns_server)
|
alloc { alloc },
|
||||||
|
interface { },
|
||||||
|
gateway { }
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
|
||||||
|
Ipv4_config::Ipv4_config(Xml_node const &domain_node,
|
||||||
|
Allocator &alloc)
|
||||||
|
:
|
||||||
|
alloc { alloc },
|
||||||
|
interface { domain_node.attribute_value("interface", Ipv4_address_prefix()) },
|
||||||
|
gateway { domain_node.attribute_value("gateway", Ipv4_address()) }
|
||||||
|
{ }
|
||||||
|
|
||||||
|
|
||||||
|
Ipv4_config::Ipv4_config(Ipv4_config const &ip_config,
|
||||||
|
Allocator &alloc)
|
||||||
|
:
|
||||||
|
alloc { alloc },
|
||||||
|
interface { ip_config.interface },
|
||||||
|
gateway { ip_config.gateway }
|
||||||
|
{
|
||||||
|
ip_config.dns_servers.for_each([&] (Dns_server const &dns_server) {
|
||||||
|
dns_servers.insert_as_tail(
|
||||||
|
*new (alloc) Dns_server(dns_server.ip()));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Ipv4_config::Ipv4_config(Dhcp_packet &dhcp_ack,
|
||||||
|
Allocator &alloc)
|
||||||
|
:
|
||||||
|
alloc { alloc },
|
||||||
|
interface { dhcp_ack.yiaddr(),
|
||||||
|
dhcp_ipv4_option<Dhcp_packet::Subnet_mask>(dhcp_ack) },
|
||||||
|
gateway { dhcp_ipv4_option<Dhcp_packet::Router_ipv4>(dhcp_ack) }
|
||||||
|
{
|
||||||
|
dhcp_ack.for_each_option([&] (Dhcp_packet::Option const &opt)
|
||||||
|
{
|
||||||
|
if (opt.code() != Dhcp_packet::Option::Code::DNS_SERVER) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
dns_servers.insert_as_tail(*new (alloc)
|
||||||
|
Dns_server(
|
||||||
|
reinterpret_cast<Dhcp_packet::Dns_server_ipv4 const *>(&opt)->value()));
|
||||||
|
}
|
||||||
|
catch (Dns_server::Invalid) { }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Ipv4_config::~Ipv4_config()
|
||||||
|
{
|
||||||
|
dns_servers.destroy_each(alloc);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Ipv4_config::print(Output &output) const
|
void Ipv4_config::print(Output &output) const
|
||||||
{
|
{
|
||||||
if (valid) {
|
if (valid) {
|
||||||
|
|
||||||
Genode::print(output, "interface ", interface, ", gateway ", gateway,
|
Genode::print(output, "interface ", interface, ", gateway ", gateway,
|
||||||
", DNS server ", dns_server, " P2P ", point_to_point); }
|
" P2P ", point_to_point);
|
||||||
else {
|
|
||||||
Genode::print(output, "none"); }
|
for_each_dns_server([&] (Dns_server const &dns_server) {
|
||||||
|
Genode::print(output, ", DNS server ", dns_server.ip()); });
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
Genode::print(output, "none");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,36 +16,56 @@
|
|||||||
|
|
||||||
/* local includes */
|
/* local includes */
|
||||||
#include <ipv4_address_prefix.h>
|
#include <ipv4_address_prefix.h>
|
||||||
|
#include <dhcp.h>
|
||||||
|
#include <dns_server.h>
|
||||||
|
|
||||||
|
/* Genode includes */
|
||||||
|
#include <util/xml_node.h>
|
||||||
|
|
||||||
namespace Net { class Ipv4_config; }
|
namespace Net { class Ipv4_config; }
|
||||||
|
|
||||||
struct Net::Ipv4_config
|
struct Net::Ipv4_config
|
||||||
{
|
{
|
||||||
Ipv4_address_prefix const interface { };
|
Genode::Allocator &alloc;
|
||||||
bool const interface_valid { interface.valid() };
|
Ipv4_address_prefix const interface;
|
||||||
Ipv4_address const gateway { };
|
bool const interface_valid { interface.valid() };
|
||||||
bool const gateway_valid { gateway.valid() };
|
Ipv4_address const gateway;
|
||||||
bool const point_to_point { gateway_valid &&
|
bool const gateway_valid { gateway.valid() };
|
||||||
interface_valid &&
|
bool const point_to_point { gateway_valid &&
|
||||||
interface.prefix == 32 };
|
interface_valid &&
|
||||||
Ipv4_address const dns_server { };
|
interface.prefix == 32 };
|
||||||
bool const dns_server_valid { dns_server.valid() };
|
Net::List<Dns_server> dns_servers { };
|
||||||
bool const valid { point_to_point ||
|
bool const valid { point_to_point ||
|
||||||
(interface_valid &&
|
(interface_valid &&
|
||||||
(!gateway_valid ||
|
(!gateway_valid ||
|
||||||
interface.prefix_matches(gateway))) };
|
interface.prefix_matches(gateway))) };
|
||||||
|
|
||||||
Ipv4_config(Ipv4_address_prefix interface,
|
Ipv4_config(Net::Dhcp_packet &dhcp_ack,
|
||||||
Ipv4_address gateway,
|
Genode::Allocator &alloc);
|
||||||
Ipv4_address dns_server);
|
|
||||||
|
|
||||||
Ipv4_config() { }
|
Ipv4_config(Genode::Xml_node const &domain_node,
|
||||||
|
Genode::Allocator &alloc);
|
||||||
|
|
||||||
|
Ipv4_config(Ipv4_config const &ip_config,
|
||||||
|
Genode::Allocator &alloc);
|
||||||
|
|
||||||
|
Ipv4_config(Genode::Allocator &alloc);
|
||||||
|
|
||||||
|
~Ipv4_config();
|
||||||
|
|
||||||
bool operator != (Ipv4_config const &other) const
|
bool operator != (Ipv4_config const &other) const
|
||||||
{
|
{
|
||||||
return interface != other.interface ||
|
return interface != other.interface ||
|
||||||
gateway != other.gateway ||
|
gateway != other.gateway ||
|
||||||
dns_server != other.dns_server;
|
!dns_servers.equal_to(other.dns_servers);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FUNC>
|
||||||
|
void for_each_dns_server(FUNC && functor) const
|
||||||
|
{
|
||||||
|
dns_servers.for_each([&] (Dns_server const &dns_server) {
|
||||||
|
functor(dns_server);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -37,6 +37,17 @@ struct Net::List : Genode::List<LT>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename FUNC>
|
||||||
|
void for_each(FUNC && functor) const
|
||||||
|
{
|
||||||
|
for (LT const *elem = Base::first(); elem; )
|
||||||
|
{
|
||||||
|
LT const *const next = elem->Base::Element::next();
|
||||||
|
functor(*elem);
|
||||||
|
elem = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void destroy_each(Genode::Deallocator &dealloc)
|
void destroy_each(Genode::Deallocator &dealloc)
|
||||||
{
|
{
|
||||||
while (LT *elem = Base::first()) {
|
while (LT *elem = Base::first()) {
|
||||||
@ -44,6 +55,48 @@ struct Net::List : Genode::List<LT>
|
|||||||
destroy(dealloc, elem);
|
destroy(dealloc, elem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool empty() const
|
||||||
|
{
|
||||||
|
return Base::first() == nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void insert_as_tail(LT const &le)
|
||||||
|
{
|
||||||
|
LT *elem { Base::first() };
|
||||||
|
if (elem) {
|
||||||
|
while (elem->Base::Element::next()) {
|
||||||
|
elem = elem->Base::Element::next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Base::insert(&le, elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool equal_to(List<LT> const &list) const
|
||||||
|
{
|
||||||
|
LT const *curr_elem_1 { Base::first() };
|
||||||
|
LT const *curr_elem_2 { list.Base::first() };
|
||||||
|
while (true) {
|
||||||
|
|
||||||
|
if (curr_elem_1 == nullptr) {
|
||||||
|
return curr_elem_2 == nullptr;
|
||||||
|
}
|
||||||
|
if (curr_elem_2 == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
LT const *const next_elem_1 {
|
||||||
|
curr_elem_1->List<LT>::Element::next() };
|
||||||
|
|
||||||
|
LT const *const next_elem_2 {
|
||||||
|
curr_elem_2->List<LT>::Element::next() };
|
||||||
|
|
||||||
|
if (!curr_elem_1->equal_to(*curr_elem_2)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
curr_elem_1 = next_elem_1;
|
||||||
|
curr_elem_2 = next_elem_2;
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _LIST_H_ */
|
#endif /* _LIST_H_ */
|
||||||
|
@ -7,7 +7,7 @@ SRC_CC += component.cc port_allocator.cc forward_rule.cc
|
|||||||
SRC_CC += nat_rule.cc main.cc ipv4_config.cc
|
SRC_CC += nat_rule.cc main.cc ipv4_config.cc
|
||||||
SRC_CC += uplink.cc interface.cc arp_cache.cc configuration.cc
|
SRC_CC += uplink.cc interface.cc arp_cache.cc configuration.cc
|
||||||
SRC_CC += domain.cc l3_protocol.cc direct_rule.cc link.cc
|
SRC_CC += domain.cc l3_protocol.cc direct_rule.cc link.cc
|
||||||
SRC_CC += transport_rule.cc permit_rule.cc
|
SRC_CC += transport_rule.cc permit_rule.cc dns_server.cc
|
||||||
SRC_CC += dhcp_client.cc dhcp_server.cc report.cc xml_node.cc
|
SRC_CC += dhcp_client.cc dhcp_server.cc report.cc xml_node.cc
|
||||||
|
|
||||||
INC_DIR += $(PRG_DIR)
|
INC_DIR += $(PRG_DIR)
|
||||||
|
153
repos/os/src/test/nic_router_dhcp/README
Normal file
153
repos/os/src/test/nic_router_dhcp/README
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
|
||||||
|
|
||||||
|
====================
|
||||||
|
NIC-router-DHCP test
|
||||||
|
====================
|
||||||
|
|
||||||
|
Martin Stein
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
The NIC-router-DHCP test is meant to test and demonstrate the functionalities
|
||||||
|
of the NIC router that correspond to the management of networks through DHCP.
|
||||||
|
This comprises the abilities of the router to basically act as DHCP client and
|
||||||
|
DHCP server, to recognize and propagate additional information through DHCP,
|
||||||
|
and to react to changes in DHCP environments.
|
||||||
|
|
||||||
|
|
||||||
|
Unmanaged test scenario
|
||||||
|
#######################
|
||||||
|
|
||||||
|
The test is integrated by the run scripts
|
||||||
|
'os/run/nic_router_dhcp_unmanaged.run' and 'os/run/nic_router_managed.run'.
|
||||||
|
The "unmanaged" variant creates the following setup:
|
||||||
|
|
||||||
|
|
||||||
|
+--------------------------------------+ Received
|
||||||
|
| Test Client | DHCP info
|
||||||
|
| (DHCP Client 2) |----------------> Serial Output
|
||||||
|
+--------------------------------------+
|
||||||
|
|
|
||||||
|
| NIC session
|
||||||
|
|
|
||||||
|
v
|
||||||
|
+---------------+-------------------+--+
|
||||||
|
| NIC Router 2 | Domain Downlink 2 | |
|
||||||
|
| | (DHCP Server 2) | |
|
||||||
|
| +-------------------+ |
|
||||||
|
| ^ |
|
||||||
|
| | Built-in |
|
||||||
|
| | DHCP info |
|
||||||
|
| | forwarding |
|
||||||
|
| | |
|
||||||
|
| | |
|
||||||
|
| +-------------------+ |
|
||||||
|
| | Domain Uplink | |
|
||||||
|
| | (DHCP Client 1) | |
|
||||||
|
+---------------+-------------------+--+
|
||||||
|
|
|
||||||
|
| NIC session
|
||||||
|
|
|
||||||
|
v
|
||||||
|
+---------------+-------------------+--+ Reconfigure
|
||||||
|
| NIC Router 1 | Domain Downlink 1 | | DHCP server +--------------+
|
||||||
|
| | (DHCP Server 1) | |<----------------| Dynamic ROM |
|
||||||
|
| +-------------------+ | +--------------+
|
||||||
|
| |
|
||||||
|
+--------------------------------------+
|
||||||
|
|
||||||
|
|
||||||
|
Throughout the test, the dynamic ROM changes the setup of DHCP Server 1
|
||||||
|
multiple times. This results also in changes of the additional information
|
||||||
|
propagated via DHCP. As a reaction to the changes, the link state of domain
|
||||||
|
Downlink 1 does a "down-up" sequence in order to advise all connected DHCP
|
||||||
|
clients to reset. DHCP Client 1 does so and receives the updated information
|
||||||
|
for its domain Uplink.
|
||||||
|
|
||||||
|
But the domain Uplink is also watched by Downlink 2 for additional DHCP
|
||||||
|
information through the router-internal forwarding mechanism (currently only
|
||||||
|
DNS server addresses, see attribute 'dns_server_from'). Therefore, the reset of
|
||||||
|
DHCP Client 1 also causes the link state of Downlink 2 to go "down" until DHCP
|
||||||
|
Client 1 finishes re-requesting DHCP. This causes DHCP Client 2 in the test
|
||||||
|
client (os/src/test/nic_router_dhcp/manager) to reset and re-request both the
|
||||||
|
basic DHCP info (originating from DHCP Server 2) and the updated additional
|
||||||
|
DHCP info (originating from DHCP Server 1) as soon as Downlink 2 is "up" again.
|
||||||
|
|
||||||
|
The test terminates successfully when the test client has printed a certain
|
||||||
|
sequence of successively received DHCP setups to the serial output. It fails,
|
||||||
|
at the other hand, when the expected output wasn't observed for a certain time.
|
||||||
|
|
||||||
|
|
||||||
|
Managed test scenario
|
||||||
|
#####################
|
||||||
|
|
||||||
|
The "managed" variant of test differs only in one detail from the "unmanaged"
|
||||||
|
variant: It doesn't use the router-internal mechanism for forwarding additional
|
||||||
|
DHCP information from the domain Uplink to domain Downlink 2. Instead, it
|
||||||
|
achieves the forwarding through an additional manager component
|
||||||
|
(os/src/test/nic_router_dhcp/manager):
|
||||||
|
|
||||||
|
|
||||||
|
+--------------------------------------+ Received
|
||||||
|
| Test Client | DHCP info
|
||||||
|
| (DHCP Client 2) |----------------> Serial Output
|
||||||
|
+--------------------------------------+
|
||||||
|
|
|
||||||
|
| NIC session
|
||||||
|
|
|
||||||
|
v Reconfigure
|
||||||
|
+---------------+-------------------+--+ DHCP server +--------------+
|
||||||
|
| NIC Router 2 | Domain Downlink 2 | | +---+ | Test Manager |
|
||||||
|
| | (DHCP Server 2) | |<-----| R |------| |
|
||||||
|
| +-------------------+ | | e | | |
|
||||||
|
| | | p | | |
|
||||||
|
| | | o | | |
|
||||||
|
| | | r | | |
|
||||||
|
| | | t | | |
|
||||||
|
| | | | | |
|
||||||
|
| | | R | | |
|
||||||
|
| +-------------------+ | | O | | |
|
||||||
|
| | Domain Uplink | |------| M |----->| |
|
||||||
|
| | (DHCP Client 1) | | +---+ | |
|
||||||
|
+---------------+-------------------+--+ Observe DHCP +--------------+
|
||||||
|
| client state
|
||||||
|
| NIC session
|
||||||
|
|
|
||||||
|
v
|
||||||
|
+---------------+-------------------+--+ Reconfigure
|
||||||
|
| NIC Router 1 | Domain Downlink 1 | | DHCP server +--------------+
|
||||||
|
| | (DHCP Server 1) | |<----------------| Dynamic ROM |
|
||||||
|
| +-------------------+ | +--------------+
|
||||||
|
| |
|
||||||
|
+--------------------------------------+
|
||||||
|
|
||||||
|
|
||||||
|
The manager initially writes out a router configuration using a Report session.
|
||||||
|
The configuration is received by NIC Router 2 through a ROM session. The
|
||||||
|
mediator between the managers Report and the routers ROM session is a Report
|
||||||
|
ROM server. The initial router configuration written by the manager is
|
||||||
|
basically the same as the static NIC-Router-2 configuration in the "unmanaged"
|
||||||
|
scenario with the small addition that it causes the router to report its state.
|
||||||
|
|
||||||
|
Now, each time that the DCHP info of domain Uplink changes, NIC Router 2
|
||||||
|
generates a new state report reflecting the updated DHCP info. The manager
|
||||||
|
receives the state update through its ROM session with the Report ROM server.
|
||||||
|
Now, the manager checks whether the additional DHCP info of domain Uplink
|
||||||
|
was affected by the update. If so, it generates a new router configuration
|
||||||
|
injecting the new additional DHCP info into DHCP Server 2.
|
||||||
|
|
||||||
|
Note that the test manager takes care not to create endless feedback-response
|
||||||
|
loops by re-configuring the router only when the interesting part of the router
|
||||||
|
state changes (the additional DHCP info of domain Uplink). The test manager
|
||||||
|
reduces re-configuration even further by doing it only when the DHCP info at
|
||||||
|
domain Uplink became valid. This means that it skips the short periods where
|
||||||
|
DHCP Client 1 is waiting for the re-request to finish and no DHCP info is
|
||||||
|
available. It's fine for DHCP Server 2 to stay with the outdated information
|
||||||
|
during this time as no basic DHCP information is affected and routing via
|
||||||
|
Uplink remains blocked until DHCP finished anyway.
|
||||||
|
|
||||||
|
The rest of the process remains the same as in the "unmanaged" variant. The
|
||||||
|
"managed" approach has the benefit that the forwarding of additional DHCP info
|
||||||
|
can be adapted to scenarios with special requirements. For instance, one might
|
||||||
|
want to filter information in order to restrict or protect the client behind
|
||||||
|
the router.
|
281
repos/os/src/test/nic_router_dhcp/client/dhcp_client.cc
Normal file
281
repos/os/src/test/nic_router_dhcp/client/dhcp_client.cc
Normal file
@ -0,0 +1,281 @@
|
|||||||
|
/*
|
||||||
|
* \brief DHCP client state model
|
||||||
|
* \author Martin Stein
|
||||||
|
* \date 2016-08-24
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* local includes */
|
||||||
|
#include <nic.h>
|
||||||
|
#include <dhcp_client.h>
|
||||||
|
#include <ipv4_config.h>
|
||||||
|
|
||||||
|
/* Genode includes */
|
||||||
|
#include <util/xml_node.h>
|
||||||
|
|
||||||
|
enum { PKT_SIZE = 1024 };
|
||||||
|
|
||||||
|
struct Send_buffer_too_small : Genode::Exception { };
|
||||||
|
struct Bad_send_dhcp_args : Genode::Exception { };
|
||||||
|
|
||||||
|
using namespace Genode;
|
||||||
|
using namespace Net;
|
||||||
|
using Message_type = Dhcp_packet::Message_type;
|
||||||
|
using Dhcp_options = Dhcp_packet::Options_aggregator<Size_guard>;
|
||||||
|
|
||||||
|
|
||||||
|
/***************
|
||||||
|
** Utilities **
|
||||||
|
***************/
|
||||||
|
|
||||||
|
void append_param_req_list(Dhcp_options &dhcp_opts)
|
||||||
|
{
|
||||||
|
dhcp_opts.append_param_req_list([&] (Dhcp_options::Parameter_request_list_data &data) {
|
||||||
|
data.append_param_req<Dhcp_packet::Message_type_option>();
|
||||||
|
data.append_param_req<Dhcp_packet::Server_ipv4>();
|
||||||
|
data.append_param_req<Dhcp_packet::Ip_lease_time>();
|
||||||
|
data.append_param_req<Dhcp_packet::Dns_server_ipv4>();
|
||||||
|
data.append_param_req<Dhcp_packet::Subnet_mask>();
|
||||||
|
data.append_param_req<Dhcp_packet::Router_ipv4>();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************
|
||||||
|
** Dhcp_client **
|
||||||
|
*****************/
|
||||||
|
|
||||||
|
Dhcp_client::Dhcp_client(Genode::Allocator &alloc,
|
||||||
|
Timer::Connection &timer,
|
||||||
|
Nic &nic,
|
||||||
|
Dhcp_client_handler &handler)
|
||||||
|
:
|
||||||
|
_alloc (alloc),
|
||||||
|
_timeout (timer, *this, &Dhcp_client::_handle_timeout),
|
||||||
|
_nic (nic),
|
||||||
|
_handler (handler)
|
||||||
|
{
|
||||||
|
_discover();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Dhcp_client::_discover()
|
||||||
|
{
|
||||||
|
_set_state(State::SELECT, _discover_timeout);
|
||||||
|
_send(Message_type::DISCOVER, Ipv4_address(), Ipv4_address(),
|
||||||
|
Ipv4_address());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Dhcp_client::_rerequest(State next_state)
|
||||||
|
{
|
||||||
|
_set_state(next_state, _rerequest_timeout(2));
|
||||||
|
Ipv4_address const client_ip = _handler.ip_config().interface.address;
|
||||||
|
_send(Message_type::REQUEST, client_ip, Ipv4_address(), client_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Dhcp_client::_set_state(State state, Microseconds timeout)
|
||||||
|
{
|
||||||
|
_state = state;
|
||||||
|
_timeout.schedule(timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Microseconds Dhcp_client::_rerequest_timeout(unsigned lease_time_div_log2)
|
||||||
|
{
|
||||||
|
/* FIXME limit the time because of shortcomings in timeout framework */
|
||||||
|
enum { MAX_TIMEOUT_SEC = 3600 };
|
||||||
|
uint64_t timeout_sec = _lease_time_sec >> lease_time_div_log2;
|
||||||
|
|
||||||
|
if (timeout_sec > MAX_TIMEOUT_SEC) {
|
||||||
|
timeout_sec = MAX_TIMEOUT_SEC;
|
||||||
|
warning("Had to prune the state timeout of DHCP client");
|
||||||
|
}
|
||||||
|
return Microseconds(timeout_sec * 1000 * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Dhcp_client::_handle_timeout(Duration)
|
||||||
|
{
|
||||||
|
switch (_state) {
|
||||||
|
case State::BOUND: _rerequest(State::RENEW); break;
|
||||||
|
case State::RENEW: _rerequest(State::REBIND); break;
|
||||||
|
default: _discover();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Dhcp_client::handle_eth(Ethernet_frame ð, Size_guard &size_guard)
|
||||||
|
{
|
||||||
|
if (eth.dst() != _nic.mac() &&
|
||||||
|
eth.dst() != Mac_address(0xff))
|
||||||
|
{
|
||||||
|
throw Drop_packet_inform("DHCP client expects Ethernet targeting the router");
|
||||||
|
}
|
||||||
|
Ipv4_packet &ip = eth.data<Ipv4_packet>(size_guard);
|
||||||
|
if (ip.protocol() != Ipv4_packet::Protocol::UDP) {
|
||||||
|
throw Drop_packet_inform("DHCP client expects UDP packet"); }
|
||||||
|
|
||||||
|
Udp_packet &udp = ip.data<Udp_packet>(size_guard);
|
||||||
|
if (!Dhcp_packet::is_dhcp(&udp)) {
|
||||||
|
throw Drop_packet_inform("DHCP client expects DHCP packet"); }
|
||||||
|
|
||||||
|
Dhcp_packet &dhcp = udp.data<Dhcp_packet>(size_guard);
|
||||||
|
if (dhcp.op() != Dhcp_packet::REPLY) {
|
||||||
|
throw Drop_packet_inform("DHCP client expects DHCP reply"); }
|
||||||
|
|
||||||
|
if (dhcp.client_mac() != _nic.mac()) {
|
||||||
|
throw Drop_packet_inform("DHCP client expects DHCP targeting the router"); }
|
||||||
|
|
||||||
|
try { _handle_dhcp_reply(dhcp); }
|
||||||
|
catch (Dhcp_packet::Option_not_found) {
|
||||||
|
throw Drop_packet_inform("DHCP client misses DHCP option"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Dhcp_client::_handle_dhcp_reply(Dhcp_packet &dhcp)
|
||||||
|
{
|
||||||
|
Message_type const msg_type =
|
||||||
|
dhcp.option<Dhcp_packet::Message_type_option>().value();
|
||||||
|
|
||||||
|
switch (_state) {
|
||||||
|
case State::SELECT:
|
||||||
|
|
||||||
|
if (msg_type != Message_type::OFFER) {
|
||||||
|
throw Drop_packet_inform("DHCP client expects an offer");
|
||||||
|
}
|
||||||
|
_set_state(State::REQUEST, _request_timeout);
|
||||||
|
_send(Message_type::REQUEST, Ipv4_address(),
|
||||||
|
dhcp.option<Dhcp_packet::Server_ipv4>().value(),
|
||||||
|
dhcp.yiaddr());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case State::REQUEST:
|
||||||
|
{
|
||||||
|
if (msg_type != Message_type::ACK) {
|
||||||
|
throw Drop_packet_inform("DHCP client expects an acknowledgement");
|
||||||
|
}
|
||||||
|
_lease_time_sec = dhcp.option<Dhcp_packet::Ip_lease_time>().value();
|
||||||
|
_set_state(State::BOUND, _rerequest_timeout(1));
|
||||||
|
|
||||||
|
log("DHCP request completed:");
|
||||||
|
log(" IP lease time: ", _lease_time_sec, " seconds");
|
||||||
|
log(" Interface: ", Ipv4_address_prefix(dhcp.yiaddr(), dhcp.option<Dhcp_packet::Subnet_mask>().value()));
|
||||||
|
log(" Router: ", dhcp.option<Dhcp_packet::Router_ipv4>().value());
|
||||||
|
|
||||||
|
Ipv4_address dns_server { };
|
||||||
|
unsigned idx { 1 };
|
||||||
|
dhcp.for_each_option([&] (Dhcp_packet::Option const &opt)
|
||||||
|
{
|
||||||
|
if (!dns_server.valid()) {
|
||||||
|
dns_server = reinterpret_cast<Dhcp_packet::Dns_server_ipv4 const *>(&opt)->value();
|
||||||
|
}
|
||||||
|
if (opt.code() != Dhcp_packet::Option::Code::DNS_SERVER) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
log(" DNS server #", idx++, ": ", reinterpret_cast<Dhcp_packet::Dns_server_ipv4 const *>(&opt)->value());
|
||||||
|
});
|
||||||
|
Ipv4_config ip_config(
|
||||||
|
Ipv4_address_prefix(
|
||||||
|
dhcp.yiaddr(),
|
||||||
|
dhcp.option<Dhcp_packet::Subnet_mask>().value()),
|
||||||
|
dhcp.option<Dhcp_packet::Router_ipv4>().value(),
|
||||||
|
dns_server);
|
||||||
|
|
||||||
|
_handler.ip_config(ip_config);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case State::RENEW:
|
||||||
|
case State::REBIND:
|
||||||
|
|
||||||
|
if (msg_type != Message_type::ACK) {
|
||||||
|
throw Drop_packet_inform("DHCP client expects an acknowledgement");
|
||||||
|
}
|
||||||
|
_set_state(State::BOUND, _rerequest_timeout(1));
|
||||||
|
_lease_time_sec = dhcp.option<Dhcp_packet::Ip_lease_time>().value();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: throw Drop_packet_inform("DHCP client doesn't expect a packet");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Dhcp_client::_send(Message_type msg_type,
|
||||||
|
Ipv4_address client_ip,
|
||||||
|
Ipv4_address server_ip,
|
||||||
|
Ipv4_address requested_ip)
|
||||||
|
{
|
||||||
|
_nic.send(PKT_SIZE, [&] (void *pkt_base, Size_guard &size_guard) {
|
||||||
|
|
||||||
|
/* create ETH header of the request */
|
||||||
|
Ethernet_frame ð = Ethernet_frame::construct_at(pkt_base, size_guard);
|
||||||
|
eth.dst(Mac_address(0xff));
|
||||||
|
eth.src(_nic.mac());
|
||||||
|
eth.type(Ethernet_frame::Type::IPV4);
|
||||||
|
|
||||||
|
/* create IP header of the request */
|
||||||
|
enum { IPV4_TIME_TO_LIVE = 64 };
|
||||||
|
size_t const ip_off = size_guard.head_size();
|
||||||
|
Ipv4_packet &ip = eth.construct_at_data<Ipv4_packet>(size_guard);
|
||||||
|
ip.header_length(sizeof(Ipv4_packet) / 4);
|
||||||
|
ip.version(4);
|
||||||
|
ip.time_to_live(IPV4_TIME_TO_LIVE);
|
||||||
|
ip.protocol(Ipv4_packet::Protocol::UDP);
|
||||||
|
ip.src(client_ip);
|
||||||
|
ip.dst(Ipv4_address(0xff));
|
||||||
|
|
||||||
|
/* create UDP header of the request */
|
||||||
|
size_t const udp_off = size_guard.head_size();
|
||||||
|
Udp_packet &udp = ip.construct_at_data<Udp_packet>(size_guard);
|
||||||
|
udp.src_port(Port(Dhcp_packet::BOOTPC));
|
||||||
|
udp.dst_port(Port(Dhcp_packet::BOOTPS));
|
||||||
|
|
||||||
|
/* create mandatory DHCP fields of the request */
|
||||||
|
size_t const dhcp_off = size_guard.head_size();
|
||||||
|
Dhcp_packet &dhcp = udp.construct_at_data<Dhcp_packet>(size_guard);
|
||||||
|
dhcp.op(Dhcp_packet::REQUEST);
|
||||||
|
dhcp.htype(Dhcp_packet::Htype::ETH);
|
||||||
|
dhcp.hlen(sizeof(Mac_address));
|
||||||
|
dhcp.ciaddr(client_ip);
|
||||||
|
dhcp.client_mac(_nic.mac());
|
||||||
|
dhcp.default_magic_cookie();
|
||||||
|
|
||||||
|
/* append DHCP option fields to the request */
|
||||||
|
Dhcp_options dhcp_opts(dhcp, size_guard);
|
||||||
|
dhcp_opts.append_option<Dhcp_packet::Message_type_option>(msg_type);
|
||||||
|
switch (msg_type) {
|
||||||
|
case Message_type::DISCOVER:
|
||||||
|
append_param_req_list(dhcp_opts);
|
||||||
|
dhcp_opts.append_option<Dhcp_packet::Client_id>(_nic.mac());
|
||||||
|
dhcp_opts.append_option<Dhcp_packet::Max_msg_size>(PKT_SIZE - dhcp_off);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Message_type::REQUEST:
|
||||||
|
append_param_req_list(dhcp_opts);
|
||||||
|
dhcp_opts.append_option<Dhcp_packet::Client_id>(_nic.mac());
|
||||||
|
dhcp_opts.append_option<Dhcp_packet::Max_msg_size>(PKT_SIZE - dhcp_off);
|
||||||
|
if (_state == State::REQUEST) {
|
||||||
|
dhcp_opts.append_option<Dhcp_packet::Requested_addr>(requested_ip);
|
||||||
|
dhcp_opts.append_option<Dhcp_packet::Server_ipv4>(server_ip);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw Bad_send_dhcp_args();
|
||||||
|
}
|
||||||
|
dhcp_opts.append_option<Dhcp_packet::Options_end>();
|
||||||
|
|
||||||
|
/* fill in header values that need the packet to be complete already */
|
||||||
|
udp.length(size_guard.head_size() - udp_off);
|
||||||
|
udp.update_checksum(ip.src(), ip.dst());
|
||||||
|
ip.total_length(size_guard.head_size() - ip_off);
|
||||||
|
ip.update_checksum();
|
||||||
|
});
|
||||||
|
}
|
105
repos/os/src/test/nic_router_dhcp/client/dhcp_client.h
Normal file
105
repos/os/src/test/nic_router_dhcp/client/dhcp_client.h
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* \brief DHCP client state model
|
||||||
|
* \author Martin Stein
|
||||||
|
* \date 2016-08-24
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 _DHCP_CLIENT_H_
|
||||||
|
#define _DHCP_CLIENT_H_
|
||||||
|
|
||||||
|
/* Genode includes */
|
||||||
|
#include <net/dhcp.h>
|
||||||
|
#include <timer_session/connection.h>
|
||||||
|
|
||||||
|
namespace Net {
|
||||||
|
|
||||||
|
/* external definition */
|
||||||
|
class Nic_peer;
|
||||||
|
class Ipv4_config;
|
||||||
|
class Ethernet_frame;
|
||||||
|
|
||||||
|
/* local definition */
|
||||||
|
class Dhcp_client;
|
||||||
|
class Dhcp_client_handler;
|
||||||
|
class Drop_packet_inform;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct Net::Drop_packet_inform : Genode::Exception
|
||||||
|
{
|
||||||
|
char const *msg;
|
||||||
|
|
||||||
|
Drop_packet_inform(char const *msg) : msg(msg) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Net::Dhcp_client_handler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual void ip_config(Ipv4_config const &ip_config) = 0;
|
||||||
|
|
||||||
|
virtual Ipv4_config const &ip_config() const = 0;
|
||||||
|
|
||||||
|
virtual ~Dhcp_client_handler() { }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Net::Dhcp_client
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
enum class State
|
||||||
|
{
|
||||||
|
INIT = 0, SELECT = 1, REQUEST = 2, BOUND = 3, RENEW = 4, REBIND = 5
|
||||||
|
};
|
||||||
|
|
||||||
|
enum { DISCOVER_TIMEOUT_SEC = 2 };
|
||||||
|
enum { REQUEST_TIMEOUT_SEC = 2 };
|
||||||
|
|
||||||
|
Genode::Allocator &_alloc;
|
||||||
|
State _state { State::INIT };
|
||||||
|
Timer::One_shot_timeout<Dhcp_client> _timeout;
|
||||||
|
unsigned long _lease_time_sec = 0;
|
||||||
|
Genode::Microseconds const _discover_timeout { (Genode::uint64_t)DISCOVER_TIMEOUT_SEC * 1000 * 1000 };
|
||||||
|
Genode::Microseconds const _request_timeout { (Genode::uint64_t)REQUEST_TIMEOUT_SEC * 1000 * 1000 };
|
||||||
|
Nic &_nic;
|
||||||
|
Dhcp_client_handler &_handler;
|
||||||
|
|
||||||
|
void _handle_dhcp_reply(Dhcp_packet &dhcp);
|
||||||
|
|
||||||
|
void _handle_timeout(Genode::Duration);
|
||||||
|
|
||||||
|
void _rerequest(State next_state);
|
||||||
|
|
||||||
|
Genode::Microseconds _rerequest_timeout(unsigned lease_time_div_log2);
|
||||||
|
|
||||||
|
void _set_state(State state, Genode::Microseconds timeout);
|
||||||
|
|
||||||
|
void _send(Dhcp_packet::Message_type msg_type,
|
||||||
|
Ipv4_address client_ip,
|
||||||
|
Ipv4_address server_ip,
|
||||||
|
Ipv4_address requested_ip);
|
||||||
|
|
||||||
|
void _discover();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Dhcp_client(Genode::Allocator &alloc,
|
||||||
|
Timer::Connection &timer,
|
||||||
|
Nic &nic,
|
||||||
|
Dhcp_client_handler &handler);
|
||||||
|
|
||||||
|
void handle_eth(Ethernet_frame ð,
|
||||||
|
Size_guard &size_guard);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* _DHCP_CLIENT_H_ */
|
103
repos/os/src/test/nic_router_dhcp/client/ipv4_address_prefix.cc
Normal file
103
repos/os/src/test/nic_router_dhcp/client/ipv4_address_prefix.cc
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* \brief Ipv4 address combined with a subnet prefix length
|
||||||
|
* \author Martin Stein
|
||||||
|
* \date 2017-10-12
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* local includes */
|
||||||
|
#include <ipv4_address_prefix.h>
|
||||||
|
|
||||||
|
using namespace Genode;
|
||||||
|
using namespace Net;
|
||||||
|
|
||||||
|
|
||||||
|
Ipv4_address Ipv4_address_prefix::subnet_mask() const
|
||||||
|
{
|
||||||
|
Ipv4_address result;
|
||||||
|
if (prefix >= 8) {
|
||||||
|
|
||||||
|
result.addr[0] = 0xff;
|
||||||
|
|
||||||
|
if (prefix >= 16) {
|
||||||
|
|
||||||
|
result.addr[1] = 0xff;
|
||||||
|
|
||||||
|
if (prefix >= 24) {
|
||||||
|
|
||||||
|
result.addr[2] = 0xff;
|
||||||
|
result.addr[3] = 0xff << (32 - prefix);
|
||||||
|
} else {
|
||||||
|
result.addr[2] = 0xff << (24 - prefix);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result.addr[1] = 0xff << (16 - prefix);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result.addr[0] = 0xff << (8 - prefix);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Ipv4_address_prefix::print(Genode::Output &output) const
|
||||||
|
{
|
||||||
|
Genode::print(output, address, "/", prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Ipv4_address_prefix::prefix_matches(Ipv4_address const &ip) const
|
||||||
|
{
|
||||||
|
uint8_t prefix_left = prefix;
|
||||||
|
uint8_t byte = 0;
|
||||||
|
for (; prefix_left >= 8; prefix_left -= 8, byte++) {
|
||||||
|
if (ip.addr[byte] != address.addr[byte]) {
|
||||||
|
return false; }
|
||||||
|
}
|
||||||
|
if (prefix_left == 0) {
|
||||||
|
return true; }
|
||||||
|
|
||||||
|
uint8_t const mask = ~(0xff >> prefix_left);
|
||||||
|
return !((ip.addr[byte] ^ address.addr[byte]) & mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Ipv4_address Ipv4_address_prefix::broadcast_address() const
|
||||||
|
{
|
||||||
|
Ipv4_address result = address;
|
||||||
|
Ipv4_address const mask = subnet_mask();
|
||||||
|
for (unsigned i = 0; i < 4; i++) {
|
||||||
|
result.addr[i] |= ~mask.addr[i];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Ipv4_address_prefix::Ipv4_address_prefix(Ipv4_address address,
|
||||||
|
Ipv4_address subnet_mask)
|
||||||
|
:
|
||||||
|
address(address), prefix(0)
|
||||||
|
{
|
||||||
|
Genode::uint8_t rest;
|
||||||
|
if (subnet_mask.addr[0] != 0xff) {
|
||||||
|
rest = subnet_mask.addr[0];
|
||||||
|
prefix = 0;
|
||||||
|
} else if (subnet_mask.addr[1] != 0xff) {
|
||||||
|
rest = subnet_mask.addr[1];
|
||||||
|
prefix = 8;
|
||||||
|
} else if (subnet_mask.addr[2] != 0xff) {
|
||||||
|
rest = subnet_mask.addr[2];
|
||||||
|
prefix = 16;
|
||||||
|
} else {
|
||||||
|
rest = subnet_mask.addr[3];
|
||||||
|
prefix = 24;
|
||||||
|
}
|
||||||
|
for (Genode::uint8_t mask = 1 << 7; rest & mask; mask >>= 1)
|
||||||
|
prefix++;
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* \brief Ipv4 address combined with a subnet prefix length
|
||||||
|
* \author Martin Stein
|
||||||
|
* \date 2017-10-12
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 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 _IPV4_ADDRESS_PREFIX_H_
|
||||||
|
#define _IPV4_ADDRESS_PREFIX_H_
|
||||||
|
|
||||||
|
/* Genode includes */
|
||||||
|
#include <net/ipv4.h>
|
||||||
|
|
||||||
|
namespace Net {
|
||||||
|
class Ipv4_address_prefix;
|
||||||
|
|
||||||
|
static inline Genode::size_t ascii_to(char const *, Net::Ipv4_address_prefix &);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct Net::Ipv4_address_prefix
|
||||||
|
{
|
||||||
|
Ipv4_address address { };
|
||||||
|
Genode::uint8_t prefix;
|
||||||
|
|
||||||
|
Ipv4_address_prefix(Ipv4_address address,
|
||||||
|
Ipv4_address subnet_mask);
|
||||||
|
|
||||||
|
Ipv4_address_prefix() : prefix(32) { }
|
||||||
|
|
||||||
|
bool valid() const { return address.valid() || prefix == 0; }
|
||||||
|
|
||||||
|
void print(Genode::Output &output) const;
|
||||||
|
|
||||||
|
bool prefix_matches(Ipv4_address const &ip) const;
|
||||||
|
|
||||||
|
Ipv4_address subnet_mask() const;
|
||||||
|
|
||||||
|
Ipv4_address broadcast_address() const;
|
||||||
|
|
||||||
|
bool operator != (Ipv4_address_prefix const &other) const
|
||||||
|
{
|
||||||
|
return prefix != other.prefix ||
|
||||||
|
address != other.address;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Genode::size_t Net::ascii_to(char const *s, Ipv4_address_prefix &result)
|
||||||
|
{
|
||||||
|
using namespace Genode;
|
||||||
|
|
||||||
|
/* read the leading IPv4 address, fail if there's no address */
|
||||||
|
Net::Ipv4_address_prefix buf;
|
||||||
|
size_t read_len = ascii_to(s, buf.address);
|
||||||
|
if (!read_len) {
|
||||||
|
return 0; }
|
||||||
|
|
||||||
|
/* check for the following slash */
|
||||||
|
s += read_len;
|
||||||
|
if (*s != '/') {
|
||||||
|
return 0; }
|
||||||
|
read_len++;
|
||||||
|
s++;
|
||||||
|
|
||||||
|
/* read the prefix, fail if there's no prefix */
|
||||||
|
size_t prefix_len = ascii_to_unsigned(s, buf.prefix, 10);
|
||||||
|
if (!prefix_len) {
|
||||||
|
return 0; }
|
||||||
|
|
||||||
|
/* fill result and return read length */
|
||||||
|
result = buf;
|
||||||
|
return read_len + prefix_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _IPV4_ADDRESS_PREFIX_H_ */
|
43
repos/os/src/test/nic_router_dhcp/client/ipv4_config.cc
Normal file
43
repos/os/src/test/nic_router_dhcp/client/ipv4_config.cc
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* \brief IPv4 peer configuration
|
||||||
|
* \author Martin Stein
|
||||||
|
* \date 2016-08-19
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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/log.h>
|
||||||
|
|
||||||
|
/* local includes */
|
||||||
|
#include <ipv4_config.h>
|
||||||
|
|
||||||
|
using namespace Genode;
|
||||||
|
using namespace Net;
|
||||||
|
|
||||||
|
Ipv4_config::Ipv4_config(Ipv4_address_prefix interface,
|
||||||
|
Ipv4_address gateway,
|
||||||
|
Ipv4_address dns_server)
|
||||||
|
:
|
||||||
|
interface(interface), gateway(gateway), dns_server(dns_server)
|
||||||
|
{
|
||||||
|
if (!valid && (interface_valid || gateway_valid)) {
|
||||||
|
error("Bad IP configuration");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Ipv4_config::print(Genode::Output &output) const
|
||||||
|
{
|
||||||
|
Genode::print(output, "interface ", interface);
|
||||||
|
if (gateway.valid()) {
|
||||||
|
Genode::print(output, ", gateway ", gateway); }
|
||||||
|
|
||||||
|
if (dns_server.valid()) {
|
||||||
|
Genode::print(output, ", DNS server ", dns_server); }
|
||||||
|
}
|
49
repos/os/src/test/nic_router_dhcp/client/ipv4_config.h
Normal file
49
repos/os/src/test/nic_router_dhcp/client/ipv4_config.h
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* \brief IPv4 peer configuration
|
||||||
|
* \author Martin Stein
|
||||||
|
* \date 2016-08-19
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 _IPV4_CONFIG_H_
|
||||||
|
#define _IPV4_CONFIG_H_
|
||||||
|
|
||||||
|
/* local includes */
|
||||||
|
#include <ipv4_address_prefix.h>
|
||||||
|
|
||||||
|
namespace Net { class Ipv4_config; }
|
||||||
|
|
||||||
|
struct Net::Ipv4_config
|
||||||
|
{
|
||||||
|
Ipv4_address_prefix const interface { };
|
||||||
|
bool const interface_valid { interface.valid() };
|
||||||
|
Ipv4_address const gateway { };
|
||||||
|
bool const gateway_valid { gateway.valid() };
|
||||||
|
Ipv4_address const dns_server { };
|
||||||
|
bool const valid { interface_valid &&
|
||||||
|
(!gateway_valid ||
|
||||||
|
interface.prefix_matches(gateway)) };
|
||||||
|
|
||||||
|
Ipv4_config(Ipv4_address_prefix interface,
|
||||||
|
Ipv4_address gateway,
|
||||||
|
Ipv4_address dns_server);
|
||||||
|
|
||||||
|
Ipv4_config() { }
|
||||||
|
|
||||||
|
bool operator != (Ipv4_config const &other) const
|
||||||
|
{
|
||||||
|
return interface != other.interface ||
|
||||||
|
gateway != other.gateway ||
|
||||||
|
dns_server != other.dns_server;
|
||||||
|
}
|
||||||
|
|
||||||
|
void print(Genode::Output &output) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* _IPV4_CONFIG_H_ */
|
119
repos/os/src/test/nic_router_dhcp/client/main.cc
Normal file
119
repos/os/src/test/nic_router_dhcp/client/main.cc
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
/*
|
||||||
|
* \brief Test the DHCP functionality of the NIC router
|
||||||
|
* \author Martin Stein
|
||||||
|
* \date 2020-11-23
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* local includes */
|
||||||
|
#include <nic.h>
|
||||||
|
#include <ipv4_config.h>
|
||||||
|
#include <dhcp_client.h>
|
||||||
|
|
||||||
|
/* Genode includes */
|
||||||
|
#include <net/ethernet.h>
|
||||||
|
#include <base/component.h>
|
||||||
|
#include <base/heap.h>
|
||||||
|
#include <base/attached_rom_dataspace.h>
|
||||||
|
#include <timer_session/connection.h>
|
||||||
|
|
||||||
|
using namespace Net;
|
||||||
|
using namespace Genode;
|
||||||
|
|
||||||
|
|
||||||
|
class Main : public Nic_handler,
|
||||||
|
public Dhcp_client_handler
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
Env &_env;
|
||||||
|
Attached_rom_dataspace _config_rom { _env, "config" };
|
||||||
|
Xml_node _config { _config_rom.xml() };
|
||||||
|
Timer::Connection _timer { _env };
|
||||||
|
Heap _heap { &_env.ram(), &_env.rm() };
|
||||||
|
bool const _verbose { _config.attribute_value("verbose", false) };
|
||||||
|
Net::Nic _nic { _env, _heap, *this, _verbose };
|
||||||
|
Constructible<Dhcp_client> _dhcp_client { };
|
||||||
|
bool _link_state { false };
|
||||||
|
Reconstructible<Ipv4_config> _ip_config { };
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
struct Invalid_arguments : Exception { };
|
||||||
|
|
||||||
|
Main(Env &env);
|
||||||
|
|
||||||
|
|
||||||
|
/*****************
|
||||||
|
** Nic_handler **
|
||||||
|
*****************/
|
||||||
|
|
||||||
|
void handle_eth(Ethernet_frame ð,
|
||||||
|
Size_guard &size_guard) override;
|
||||||
|
|
||||||
|
void handle_link_state(bool link_state) override
|
||||||
|
{
|
||||||
|
if (!_link_state && link_state) {
|
||||||
|
_dhcp_client.construct(_heap, _timer, _nic, *this);
|
||||||
|
}
|
||||||
|
if (_link_state && !link_state && ip_config().valid) {
|
||||||
|
ip_config(Ipv4_config { });
|
||||||
|
}
|
||||||
|
_link_state = link_state;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*************************
|
||||||
|
** Dhcp_client_handler **
|
||||||
|
*************************/
|
||||||
|
|
||||||
|
void ip_config(Ipv4_config const &ip_config) override;
|
||||||
|
|
||||||
|
Ipv4_config const &ip_config() const override { return *_ip_config; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void Main::ip_config(Ipv4_config const &ip_config)
|
||||||
|
{
|
||||||
|
if (_verbose) {
|
||||||
|
log("IP config: ", ip_config); }
|
||||||
|
|
||||||
|
_ip_config.construct(ip_config);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Main::Main(Env &env) : _env(env)
|
||||||
|
{
|
||||||
|
log("Initialized");
|
||||||
|
_nic.handle_link_state();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Main::handle_eth(Ethernet_frame ð,
|
||||||
|
Size_guard &size_guard)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
/* print receipt message */
|
||||||
|
if (_verbose) {
|
||||||
|
log("rcv ", eth); }
|
||||||
|
|
||||||
|
if (!ip_config().valid) {
|
||||||
|
_dhcp_client->handle_eth(eth, size_guard); }
|
||||||
|
else {
|
||||||
|
throw Drop_packet_inform("IP config still valid");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Drop_packet_inform exception) {
|
||||||
|
if (_verbose) {
|
||||||
|
log("drop packet: ", exception.msg); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Component::construct(Env &env) { static Main main(env); }
|
46
repos/os/src/test/nic_router_dhcp/client/nic.cc
Normal file
46
repos/os/src/test/nic_router_dhcp/client/nic.cc
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* \brief NIC connection wrapper for a more convenient interface
|
||||||
|
* \author Martin Stein
|
||||||
|
* \date 2018-04-16
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* local includes */
|
||||||
|
#include <nic.h>
|
||||||
|
|
||||||
|
using namespace Net;
|
||||||
|
using namespace Genode;
|
||||||
|
|
||||||
|
|
||||||
|
void Net::Nic::_ready_to_ack()
|
||||||
|
{
|
||||||
|
while (_source().ack_avail()) {
|
||||||
|
_source().release_packet(_source().get_acked_packet()); }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Net::Nic::_ready_to_submit()
|
||||||
|
{
|
||||||
|
while (_sink().packet_avail()) {
|
||||||
|
|
||||||
|
Packet_descriptor const pkt = _sink().get_packet();
|
||||||
|
if (!pkt.size()) {
|
||||||
|
continue; }
|
||||||
|
|
||||||
|
Size_guard size_guard(pkt.size());
|
||||||
|
_handler.handle_eth(Ethernet_frame::cast_from(_sink().packet_content(pkt), size_guard),
|
||||||
|
size_guard);
|
||||||
|
|
||||||
|
if (!_sink().ready_to_ack()) {
|
||||||
|
error("ack state FULL");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_sink().acknowledge_packet(pkt);
|
||||||
|
}
|
||||||
|
}
|
137
repos/os/src/test/nic_router_dhcp/client/nic.h
Normal file
137
repos/os/src/test/nic_router_dhcp/client/nic.h
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
/*
|
||||||
|
* \brief NIC connection wrapper for a more convenient interface
|
||||||
|
* \author Martin Stein
|
||||||
|
* \date 2018-04-16
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018 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_H_
|
||||||
|
#define _NIC_H_
|
||||||
|
|
||||||
|
/* Genode includes */
|
||||||
|
#include <nic_session/connection.h>
|
||||||
|
#include <nic/packet_allocator.h>
|
||||||
|
#include <net/ethernet.h>
|
||||||
|
|
||||||
|
namespace Genode {
|
||||||
|
|
||||||
|
class Env;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Net {
|
||||||
|
|
||||||
|
struct Nic_handler;
|
||||||
|
class Nic;
|
||||||
|
|
||||||
|
using Packet_descriptor = ::Nic::Packet_descriptor;
|
||||||
|
using Packet_stream_sink = ::Nic::Packet_stream_sink< ::Nic::Session::Policy>;
|
||||||
|
using Packet_stream_source = ::Nic::Packet_stream_source< ::Nic::Session::Policy>;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct Net::Nic_handler
|
||||||
|
{
|
||||||
|
virtual void handle_eth(Ethernet_frame ð,
|
||||||
|
Size_guard &size_guard) = 0;
|
||||||
|
|
||||||
|
virtual void handle_link_state(bool link_state) = 0;
|
||||||
|
|
||||||
|
virtual ~Nic_handler() { }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Net::Nic
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
using Signal_handler = Genode::Signal_handler<Nic>;
|
||||||
|
|
||||||
|
enum { PKT_SIZE = ::Nic::Packet_allocator::DEFAULT_PACKET_SIZE };
|
||||||
|
enum { BUF_SIZE = ::Nic::Session::QUEUE_SIZE * PKT_SIZE };
|
||||||
|
|
||||||
|
Genode::Env &_env;
|
||||||
|
Genode::Allocator &_alloc;
|
||||||
|
Nic_handler &_handler;
|
||||||
|
bool const &_verbose;
|
||||||
|
::Nic::Packet_allocator _pkt_alloc { &_alloc };
|
||||||
|
::Nic::Connection _nic { _env, &_pkt_alloc, BUF_SIZE, BUF_SIZE };
|
||||||
|
Signal_handler _sink_ack { _env.ep(), *this, &Nic::_ack_avail };
|
||||||
|
Signal_handler _sink_submit { _env.ep(), *this, &Nic::_ready_to_submit };
|
||||||
|
Signal_handler _source_ack { _env.ep(), *this, &Nic::_ready_to_ack };
|
||||||
|
Signal_handler _source_submit { _env.ep(), *this, &Nic::_packet_avail };
|
||||||
|
Signal_handler _link_state_handler { _env.ep(), *this, &Nic::handle_link_state };
|
||||||
|
Mac_address const _mac { _nic.mac_address() };
|
||||||
|
|
||||||
|
Net::Packet_stream_sink &_sink() { return *_nic.rx(); }
|
||||||
|
Net::Packet_stream_source &_source() { return *_nic.tx(); }
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************
|
||||||
|
** Packet-stream signal handlers **
|
||||||
|
***********************************/
|
||||||
|
|
||||||
|
void _ready_to_submit();
|
||||||
|
void _ack_avail() { }
|
||||||
|
void _ready_to_ack();
|
||||||
|
void _packet_avail() { }
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Nic(Genode::Env &env,
|
||||||
|
Genode::Allocator &alloc,
|
||||||
|
Nic_handler &handler,
|
||||||
|
bool const &verbose)
|
||||||
|
:
|
||||||
|
_env (env),
|
||||||
|
_alloc (alloc),
|
||||||
|
_handler (handler),
|
||||||
|
_verbose (verbose)
|
||||||
|
{
|
||||||
|
_nic.rx_channel()->sigh_ready_to_ack(_sink_ack);
|
||||||
|
_nic.rx_channel()->sigh_packet_avail(_sink_submit);
|
||||||
|
_nic.tx_channel()->sigh_ack_avail(_source_ack);
|
||||||
|
_nic.tx_channel()->sigh_ready_to_submit(_source_submit);
|
||||||
|
_nic.link_state_sigh(_link_state_handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_link_state()
|
||||||
|
{
|
||||||
|
_handler.handle_link_state(_nic.link_state());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FUNC>
|
||||||
|
void send(Genode::size_t pkt_size,
|
||||||
|
FUNC && write_to_pkt)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Packet_descriptor pkt = _source().alloc_packet(pkt_size);
|
||||||
|
void *pkt_base = _source().packet_content(pkt);
|
||||||
|
Size_guard size_guard(pkt_size);
|
||||||
|
write_to_pkt(pkt_base, size_guard);
|
||||||
|
_source().submit_packet(pkt);
|
||||||
|
if (_verbose) {
|
||||||
|
Size_guard size_guard(pkt_size);
|
||||||
|
try { Genode::log("snd ", Ethernet_frame::cast_from(pkt_base, size_guard)); }
|
||||||
|
catch (Size_guard::Exceeded) { Genode::log("snd ?"); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Net::Packet_stream_source::Packet_alloc_failed) {
|
||||||
|
Genode::warning("failed to allocate packet"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***************
|
||||||
|
** Accessors **
|
||||||
|
***************/
|
||||||
|
|
||||||
|
Mac_address const &mac() const { return _mac; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* _NIC_H_ */
|
8
repos/os/src/test/nic_router_dhcp/client/target.mk
Normal file
8
repos/os/src/test/nic_router_dhcp/client/target.mk
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
TARGET = test-nic_router_dhcp-client
|
||||||
|
|
||||||
|
LIBS += base net
|
||||||
|
|
||||||
|
SRC_CC += main.cc dhcp_client.cc ipv4_address_prefix.cc
|
||||||
|
SRC_CC += nic.cc ipv4_config.cc
|
||||||
|
|
||||||
|
INC_DIR += $(PRG_DIR)
|
34
repos/os/src/test/nic_router_dhcp/manager/dns_server.cc
Normal file
34
repos/os/src/test/nic_router_dhcp/manager/dns_server.cc
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* \brief DNS server entry of a DHCP server or IPv4 config
|
||||||
|
* \author Martin Stein
|
||||||
|
* \date 2020-11-17
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* local includes */
|
||||||
|
#include <dns_server.h>
|
||||||
|
|
||||||
|
using namespace Net;
|
||||||
|
using namespace Genode;
|
||||||
|
|
||||||
|
|
||||||
|
Local::Dns_server::Dns_server(Ipv4_address const &ip)
|
||||||
|
:
|
||||||
|
_ip { ip }
|
||||||
|
{
|
||||||
|
if (!_ip.valid()) {
|
||||||
|
throw Invalid { };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Local::Dns_server::equal_to(Dns_server const &server) const
|
||||||
|
{
|
||||||
|
return _ip == server._ip;
|
||||||
|
}
|
50
repos/os/src/test/nic_router_dhcp/manager/dns_server.h
Normal file
50
repos/os/src/test/nic_router_dhcp/manager/dns_server.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* \brief DNS server entry of a DHCP server or IPv4 config
|
||||||
|
* \author Martin Stein
|
||||||
|
* \date 2020-11-17
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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 _DNS_SERVER_H_
|
||||||
|
#define _DNS_SERVER_H_
|
||||||
|
|
||||||
|
/* local includes */
|
||||||
|
#include <list.h>
|
||||||
|
|
||||||
|
/* Genode includes */
|
||||||
|
#include <net/ipv4.h>
|
||||||
|
|
||||||
|
namespace Local { class Dns_server; }
|
||||||
|
|
||||||
|
class Local::Dns_server : private Genode::Noncopyable,
|
||||||
|
public Local::List<Dns_server>::Element
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
Net::Ipv4_address const _ip;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
struct Invalid : Genode::Exception { };
|
||||||
|
|
||||||
|
Dns_server(Net::Ipv4_address const &ip);
|
||||||
|
|
||||||
|
bool equal_to(Dns_server const &server) const;
|
||||||
|
|
||||||
|
|
||||||
|
/***************
|
||||||
|
** Accessors **
|
||||||
|
***************/
|
||||||
|
|
||||||
|
Net::Ipv4_address const &ip() const { return _ip; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* _DHCP_SERVER_H_ */
|
103
repos/os/src/test/nic_router_dhcp/manager/ipv4_address_prefix.cc
Normal file
103
repos/os/src/test/nic_router_dhcp/manager/ipv4_address_prefix.cc
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* \brief Ipv4 address combined with a subnet prefix length
|
||||||
|
* \author Martin Stein
|
||||||
|
* \date 2017-10-12
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* local includes */
|
||||||
|
#include <ipv4_address_prefix.h>
|
||||||
|
|
||||||
|
using namespace Genode;
|
||||||
|
using namespace Net;
|
||||||
|
|
||||||
|
|
||||||
|
Ipv4_address Ipv4_address_prefix::subnet_mask() const
|
||||||
|
{
|
||||||
|
Ipv4_address result;
|
||||||
|
if (prefix >= 8) {
|
||||||
|
|
||||||
|
result.addr[0] = 0xff;
|
||||||
|
|
||||||
|
if (prefix >= 16) {
|
||||||
|
|
||||||
|
result.addr[1] = 0xff;
|
||||||
|
|
||||||
|
if (prefix >= 24) {
|
||||||
|
|
||||||
|
result.addr[2] = 0xff;
|
||||||
|
result.addr[3] = 0xff << (32 - prefix);
|
||||||
|
} else {
|
||||||
|
result.addr[2] = 0xff << (24 - prefix);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result.addr[1] = 0xff << (16 - prefix);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result.addr[0] = 0xff << (8 - prefix);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Ipv4_address_prefix::print(Genode::Output &output) const
|
||||||
|
{
|
||||||
|
Genode::print(output, address, "/", prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Ipv4_address_prefix::prefix_matches(Ipv4_address const &ip) const
|
||||||
|
{
|
||||||
|
uint8_t prefix_left = prefix;
|
||||||
|
uint8_t byte = 0;
|
||||||
|
for (; prefix_left >= 8; prefix_left -= 8, byte++) {
|
||||||
|
if (ip.addr[byte] != address.addr[byte]) {
|
||||||
|
return false; }
|
||||||
|
}
|
||||||
|
if (prefix_left == 0) {
|
||||||
|
return true; }
|
||||||
|
|
||||||
|
uint8_t const mask = ~(0xff >> prefix_left);
|
||||||
|
return !((ip.addr[byte] ^ address.addr[byte]) & mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Ipv4_address Ipv4_address_prefix::broadcast_address() const
|
||||||
|
{
|
||||||
|
Ipv4_address result = address;
|
||||||
|
Ipv4_address const mask = subnet_mask();
|
||||||
|
for (unsigned i = 0; i < 4; i++) {
|
||||||
|
result.addr[i] |= ~mask.addr[i];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Ipv4_address_prefix::Ipv4_address_prefix(Ipv4_address address,
|
||||||
|
Ipv4_address subnet_mask)
|
||||||
|
:
|
||||||
|
address(address), prefix(0)
|
||||||
|
{
|
||||||
|
Genode::uint8_t rest;
|
||||||
|
if (subnet_mask.addr[0] != 0xff) {
|
||||||
|
rest = subnet_mask.addr[0];
|
||||||
|
prefix = 0;
|
||||||
|
} else if (subnet_mask.addr[1] != 0xff) {
|
||||||
|
rest = subnet_mask.addr[1];
|
||||||
|
prefix = 8;
|
||||||
|
} else if (subnet_mask.addr[2] != 0xff) {
|
||||||
|
rest = subnet_mask.addr[2];
|
||||||
|
prefix = 16;
|
||||||
|
} else {
|
||||||
|
rest = subnet_mask.addr[3];
|
||||||
|
prefix = 24;
|
||||||
|
}
|
||||||
|
for (Genode::uint8_t mask = 1 << 7; rest & mask; mask >>= 1)
|
||||||
|
prefix++;
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* \brief Ipv4 address combined with a subnet prefix length
|
||||||
|
* \author Martin Stein
|
||||||
|
* \date 2017-10-12
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 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 _IPV4_ADDRESS_PREFIX_H_
|
||||||
|
#define _IPV4_ADDRESS_PREFIX_H_
|
||||||
|
|
||||||
|
/* Genode includes */
|
||||||
|
#include <net/ipv4.h>
|
||||||
|
|
||||||
|
namespace Net {
|
||||||
|
class Ipv4_address_prefix;
|
||||||
|
|
||||||
|
static inline Genode::size_t ascii_to(char const *, Net::Ipv4_address_prefix &);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct Net::Ipv4_address_prefix
|
||||||
|
{
|
||||||
|
Ipv4_address address { };
|
||||||
|
Genode::uint8_t prefix;
|
||||||
|
|
||||||
|
Ipv4_address_prefix(Ipv4_address address,
|
||||||
|
Ipv4_address subnet_mask);
|
||||||
|
|
||||||
|
Ipv4_address_prefix() : prefix(32) { }
|
||||||
|
|
||||||
|
bool valid() const { return address.valid() || prefix == 0; }
|
||||||
|
|
||||||
|
void print(Genode::Output &output) const;
|
||||||
|
|
||||||
|
bool prefix_matches(Ipv4_address const &ip) const;
|
||||||
|
|
||||||
|
Ipv4_address subnet_mask() const;
|
||||||
|
|
||||||
|
Ipv4_address broadcast_address() const;
|
||||||
|
|
||||||
|
bool operator != (Ipv4_address_prefix const &other) const
|
||||||
|
{
|
||||||
|
return prefix != other.prefix ||
|
||||||
|
address != other.address;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Genode::size_t Net::ascii_to(char const *s, Ipv4_address_prefix &result)
|
||||||
|
{
|
||||||
|
using namespace Genode;
|
||||||
|
|
||||||
|
/* read the leading IPv4 address, fail if there's no address */
|
||||||
|
Net::Ipv4_address_prefix buf;
|
||||||
|
size_t read_len = ascii_to(s, buf.address);
|
||||||
|
if (!read_len) {
|
||||||
|
return 0; }
|
||||||
|
|
||||||
|
/* check for the following slash */
|
||||||
|
s += read_len;
|
||||||
|
if (*s != '/') {
|
||||||
|
return 0; }
|
||||||
|
read_len++;
|
||||||
|
s++;
|
||||||
|
|
||||||
|
/* read the prefix, fail if there's no prefix */
|
||||||
|
size_t prefix_len = ascii_to_unsigned(s, buf.prefix, 10);
|
||||||
|
if (!prefix_len) {
|
||||||
|
return 0; }
|
||||||
|
|
||||||
|
/* fill result and return read length */
|
||||||
|
result = buf;
|
||||||
|
return read_len + prefix_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _IPV4_ADDRESS_PREFIX_H_ */
|
102
repos/os/src/test/nic_router_dhcp/manager/list.h
Normal file
102
repos/os/src/test/nic_router_dhcp/manager/list.h
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
* \brief Genode list with additional functions needed by NIC router
|
||||||
|
* \author Martin Stein
|
||||||
|
* \date 2016-08-19
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 _LIST_H_
|
||||||
|
#define _LIST_H_
|
||||||
|
|
||||||
|
/* Genode includes */
|
||||||
|
#include <util/list.h>
|
||||||
|
#include <base/allocator.h>
|
||||||
|
|
||||||
|
namespace Local { template <typename> class List; }
|
||||||
|
|
||||||
|
|
||||||
|
template <typename LT>
|
||||||
|
struct Local::List : Genode::List<LT>
|
||||||
|
{
|
||||||
|
using Base = Genode::List<LT>;
|
||||||
|
|
||||||
|
template <typename FUNC>
|
||||||
|
void for_each(FUNC && functor)
|
||||||
|
{
|
||||||
|
for (LT *elem = Base::first(); elem; )
|
||||||
|
{
|
||||||
|
LT *const next = elem->Base::Element::next();
|
||||||
|
functor(*elem);
|
||||||
|
elem = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FUNC>
|
||||||
|
void for_each(FUNC && functor) const
|
||||||
|
{
|
||||||
|
for (LT const *elem = Base::first(); elem; )
|
||||||
|
{
|
||||||
|
LT const *const next = elem->Base::Element::next();
|
||||||
|
functor(*elem);
|
||||||
|
elem = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_each(Genode::Deallocator &dealloc)
|
||||||
|
{
|
||||||
|
while (LT *elem = Base::first()) {
|
||||||
|
Base::remove(elem);
|
||||||
|
destroy(dealloc, elem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty() const
|
||||||
|
{
|
||||||
|
return Base::first() == nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void insert_as_tail(LT const &le)
|
||||||
|
{
|
||||||
|
LT *elem { Base::first() };
|
||||||
|
if (elem) {
|
||||||
|
while (elem->Base::Element::next()) {
|
||||||
|
elem = elem->Base::Element::next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Base::insert(&le, elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool equal_to(List<LT> const &list) const
|
||||||
|
{
|
||||||
|
LT const *curr_elem_1 { Base::first() };
|
||||||
|
LT const *curr_elem_2 { list.Base::first() };
|
||||||
|
while (true) {
|
||||||
|
|
||||||
|
if (curr_elem_1 == nullptr) {
|
||||||
|
return curr_elem_2 == nullptr;
|
||||||
|
}
|
||||||
|
if (curr_elem_2 == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
LT const *const next_elem_1 {
|
||||||
|
curr_elem_1->List<LT>::Element::next() };
|
||||||
|
|
||||||
|
LT const *const next_elem_2 {
|
||||||
|
curr_elem_2->List<LT>::Element::next() };
|
||||||
|
|
||||||
|
if (!curr_elem_1->equal_to(*curr_elem_2)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
curr_elem_1 = next_elem_1;
|
||||||
|
curr_elem_2 = next_elem_2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* _LIST_H_ */
|
175
repos/os/src/test/nic_router_dhcp/manager/main.cc
Normal file
175
repos/os/src/test/nic_router_dhcp/manager/main.cc
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
/*
|
||||||
|
* \brief Server component for Network Address Translation on NIC sessions
|
||||||
|
* \author Martin Stein
|
||||||
|
* \date 2016-08-24
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 */
|
||||||
|
#include <base/component.h>
|
||||||
|
#include <base/attached_rom_dataspace.h>
|
||||||
|
#include <base/heap.h>
|
||||||
|
#include <util/list.h>
|
||||||
|
#include <os/reporter.h>
|
||||||
|
|
||||||
|
/* local includes */
|
||||||
|
#include <ipv4_address_prefix.h>
|
||||||
|
#include <dns_server.h>
|
||||||
|
|
||||||
|
using namespace Net;
|
||||||
|
using namespace Genode;
|
||||||
|
using Domain_name = String<160>;
|
||||||
|
|
||||||
|
namespace Local { class Main; }
|
||||||
|
|
||||||
|
|
||||||
|
class Local::Main
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
Env &_env;
|
||||||
|
Heap _heap { &_env.ram(), &_env.rm() };
|
||||||
|
Attached_rom_dataspace _router_state_rom { _env, "router_state" };
|
||||||
|
Signal_handler<Main> _router_state_handler { _env.ep(), *this, &Main::_handle_router_state };
|
||||||
|
Expanding_reporter _router_config_reporter { _env, "config", "router_config" };
|
||||||
|
bool _router_config_outdated { true };
|
||||||
|
Local::List<Dns_server> _dns_servers { };
|
||||||
|
|
||||||
|
void _handle_router_state();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Main(Env &env);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Local::Main::Main(Env &env) : _env(env)
|
||||||
|
{
|
||||||
|
log("Initialized");
|
||||||
|
_router_state_rom.sigh(_router_state_handler);
|
||||||
|
_handle_router_state();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Local::Main::_handle_router_state()
|
||||||
|
{
|
||||||
|
/* Request the moste recent content of the router state dataspace. */
|
||||||
|
log("Read state of nic_router_2");
|
||||||
|
_router_state_rom.update();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Search for the uplink domain tag in the updated router state,
|
||||||
|
* read the new list of DNS servers from and compare it to the old list to
|
||||||
|
* see whether we have to re-configure the router.
|
||||||
|
*/
|
||||||
|
bool domain_found { false };
|
||||||
|
_router_state_rom.xml().for_each_sub_node(
|
||||||
|
"domain",
|
||||||
|
[&] (Xml_node const &domain_node)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* If we already found the uplink domain, refrain from inspecting
|
||||||
|
* further domain tags.
|
||||||
|
*/
|
||||||
|
if (domain_found) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (domain_node.attribute_value("name", Domain_name()) == "uplink") {
|
||||||
|
|
||||||
|
domain_found = true;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Consider re-configuring the router only when the uplink has
|
||||||
|
* a valid IPv4 config. This prevents us from propagating each,
|
||||||
|
* normally short-living "No-DNS-Server"-state that merely comes
|
||||||
|
* from the fact that the uplink has to redo DHCP and invalidates
|
||||||
|
* its Ipv4 config for this time.
|
||||||
|
*/
|
||||||
|
if (!domain_node.attribute_value("ipv4", Ipv4_address_prefix { }).valid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read out all DNS servers from the new uplink state
|
||||||
|
* and memorize them in a function-local list.
|
||||||
|
*/
|
||||||
|
Local::List<Dns_server> dns_servers { };
|
||||||
|
domain_node.for_each_sub_node(
|
||||||
|
"dns",
|
||||||
|
[&] (Xml_node const &dns_node)
|
||||||
|
{
|
||||||
|
|
||||||
|
dns_servers.insert_as_tail(
|
||||||
|
*new (_heap) Dns_server(dns_node.attribute_value("ip", Ipv4_address { })));
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the new list of DNS servers differs our member list,
|
||||||
|
* update the member list, and remember to write out a new router
|
||||||
|
* configuration.
|
||||||
|
*/
|
||||||
|
if (!_dns_servers.equal_to(dns_servers)) {
|
||||||
|
|
||||||
|
_dns_servers.destroy_each(_heap);
|
||||||
|
dns_servers.for_each([&] (Dns_server const &dns_server) {
|
||||||
|
_dns_servers.insert_as_tail(
|
||||||
|
*new (_heap) Dns_server(dns_server.ip()));
|
||||||
|
});
|
||||||
|
_router_config_outdated = true;
|
||||||
|
}
|
||||||
|
dns_servers.destroy_each(_heap);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write out a new router configuration with the updated list of
|
||||||
|
* DNS servers if necessary.
|
||||||
|
*/
|
||||||
|
if (_router_config_outdated) {
|
||||||
|
|
||||||
|
log("Write config of nic_router_2");
|
||||||
|
_router_config_reporter.generate([&] (Xml_generator &xml) {
|
||||||
|
xml.node("report", [&] () {
|
||||||
|
xml.attribute("bytes", "no");
|
||||||
|
xml.attribute("stats", "no");
|
||||||
|
xml.attribute("quota", "no");
|
||||||
|
xml.attribute("config", "yes");
|
||||||
|
xml.attribute("config_triggers", "yes");
|
||||||
|
xml.attribute("interval_sec", "100");
|
||||||
|
});
|
||||||
|
xml.node("policy", [&] () {
|
||||||
|
xml.attribute("label", "test_client -> ");
|
||||||
|
xml.attribute("domain", "downlink");
|
||||||
|
});
|
||||||
|
xml.node("uplink", [&] () {
|
||||||
|
xml.attribute("domain", "uplink");
|
||||||
|
});
|
||||||
|
xml.node("domain", [&] () {
|
||||||
|
xml.attribute("name", "uplink");
|
||||||
|
});
|
||||||
|
xml.node("domain", [&] () {
|
||||||
|
xml.attribute("name", "downlink");
|
||||||
|
xml.attribute("interface", "10.0.3.1/24");
|
||||||
|
xml.node("dhcp-server", [&] () {
|
||||||
|
xml.attribute("ip_first", "10.0.3.2");
|
||||||
|
xml.attribute("ip_last", "10.0.3.2");
|
||||||
|
_dns_servers.for_each([&] (Dns_server const &dns_server) {
|
||||||
|
xml.node("dns-server", [&] () {
|
||||||
|
xml.attribute("ip", String<16>(dns_server.ip()));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
_router_config_outdated = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Component::construct(Env &env) { static Local::Main main(env); }
|
7
repos/os/src/test/nic_router_dhcp/manager/target.mk
Normal file
7
repos/os/src/test/nic_router_dhcp/manager/target.mk
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
TARGET = test-nic_router_dhcp-manager
|
||||||
|
|
||||||
|
LIBS += base
|
||||||
|
|
||||||
|
SRC_CC += main.cc ipv4_address_prefix.cc dns_server.cc
|
||||||
|
|
||||||
|
INC_DIR += $(PRG_DIR)
|
@ -41,6 +41,8 @@ nic_bridge
|
|||||||
nic_bridge_stress
|
nic_bridge_stress
|
||||||
nic_dump
|
nic_dump
|
||||||
nic_router
|
nic_router
|
||||||
|
nic_router_dhcp_managed
|
||||||
|
nic_router_dhcp_unmanaged
|
||||||
nic_router_flood
|
nic_router_flood
|
||||||
nic_router_stress
|
nic_router_stress
|
||||||
nic_router_uplinks
|
nic_router_uplinks
|
||||||
|
Loading…
x
Reference in New Issue
Block a user