nic_router: clean-up session creation with class

Introduces a new class that does the clean-up if some exception is
thrown while creating the session. This reduces redundancy and overall
lines of code.

Ref #4966
This commit is contained in:
Martin Stein 2023-07-18 13:04:43 +02:00 committed by Christian Helmuth
parent 7aa301361d
commit 4c4962b306
3 changed files with 147 additions and 137 deletions

View File

@ -16,6 +16,7 @@
/* local includes */
#include <nic_session_root.h>
#include <session_creation.h>
#include <configuration.h>
using namespace Net;
@ -304,79 +305,39 @@ Net::Nic_session_root::Nic_session_root(Env &env,
Nic_session_component *Net::Nic_session_root::_create_session(char const *args)
{
Session_creation<Nic_session_component> session_creation { };
try {
/* create session environment temporarily on the stack */
Session_env session_env_stack { _env, _shared_quota,
Ram_quota { Arg_string::find_arg(args, "ram_quota").ulong_value(0) },
Cap_quota { Arg_string::find_arg(args, "cap_quota").ulong_value(0) } };
/* alloc/attach RAM block and move session env to base of the block */
Ram_dataspace_capability ram_ds {
session_env_stack.alloc(sizeof(Session_env) +
sizeof(Nic_session_component), CACHED) };
try {
void * const ram_ptr { session_env_stack.attach(ram_ds) };
Session_env &session_env {
*construct_at<Session_env>(ram_ptr, session_env_stack) };
/* create new session object behind session env in the RAM block */
try {
return session_creation.execute(
_env, _shared_quota, args,
[&] (Session_env &session_env, void *session_at, Ram_dataspace_capability ram_ds)
{
Session_label const label { label_from_args(args) };
Mac_address const mac { _mac_alloc.alloc() };
Mac_address const mac { _mac_alloc.alloc() };
try {
return construct_at<Nic_session_component>(
(void*)((addr_t)ram_ptr + sizeof(Session_env)),
session_env,
session_at, session_env,
Arg_string::find_arg(args, "tx_buf_size").ulong_value(0),
Arg_string::find_arg(args, "rx_buf_size").ulong_value(0),
_timer, mac, _router_mac, label, _interfaces,
_config(), ram_ds);
}
catch (Out_of_ram) {
catch (...) {
_mac_alloc.free(mac);
Session_env session_env_stack { session_env };
session_env_stack.detach(ram_ptr);
session_env_stack.free(ram_ds);
_invalid_downlink("NIC session RAM quota");
throw Insufficient_ram_quota();
throw;
}
catch (Out_of_caps) {
_mac_alloc.free(mac);
Session_env session_env_stack { session_env };
session_env_stack.detach(ram_ptr);
session_env_stack.free(ram_ds);
_invalid_downlink("NIC session CAP quota");
throw Insufficient_cap_quota();
}
}
catch (Mac_allocator::Alloc_failed) {
Session_env session_env_stack { session_env };
session_env_stack.detach(ram_ptr);
session_env_stack.free(ram_ds);
_invalid_downlink("failed to allocate MAC address");
throw Service_denied();
}
}
catch (Region_map::Invalid_dataspace) {
session_env_stack.free(ram_ds);
_invalid_downlink("Failed to attach RAM");
throw Service_denied();
}
catch (Region_map::Region_conflict) {
session_env_stack.free(ram_ds);
_invalid_downlink("Failed to attach RAM");
throw Service_denied();
}
catch (Out_of_ram) {
session_env_stack.free(ram_ds);
_invalid_downlink("NIC session RAM quota");
throw Insufficient_ram_quota();
}
catch (Out_of_caps) {
session_env_stack.free(ram_ds);
_invalid_downlink("NIC session CAP quota");
throw Insufficient_cap_quota();
}
});
}
catch (Mac_allocator::Alloc_failed) {
_invalid_downlink("failed to allocate MAC address");
throw Service_denied();
}
catch (Region_map::Invalid_dataspace) {
_invalid_downlink("Failed to attach RAM");
throw Service_denied();
}
catch (Region_map::Region_conflict) {
_invalid_downlink("Failed to attach RAM");
throw Service_denied();
}
catch (Out_of_ram) {
_invalid_downlink("NIC session RAM quota");

View File

@ -0,0 +1,93 @@
/*
* \brief The generic parts of the process of creating a session component
* \author Martin Stein
* \date 2023-07-18
*/
/*
* Copyright (C) 2023 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 _SESSION_CREATION_H_
#define _SESSION_CREATION_H_
/* nic_router includes */
#include <session_env.h>
namespace Net {
using namespace Genode;
template <typename SESSION_COMPONENT>
class Session_creation;
}
template <typename SESSION_COMPONENT>
class Net::Session_creation
{
private:
Constructible<Session_env> _tmp_session_env { };
Constructible<Ram_dataspace_capability> _ram_ds { };
void *_ram_ptr { nullptr };
Session_env *_session_env_ptr { nullptr };
public:
template <typename CREATE_SESSION_FN>
SESSION_COMPONENT *execute(Env &env,
Quota &shared_quota,
char const *session_args,
CREATE_SESSION_FN && create_session_fn)
{
/*
* Note that this cannot be done in the constructor of this class
* because it is required that the destructor of this class is called
* on any exception that is thrown by the below code.
*/
/* create session env as temporary member of this object */
_tmp_session_env.construct(env, shared_quota,
Ram_quota { Arg_string::find_arg(session_args, "ram_quota").ulong_value(0) },
Cap_quota { Arg_string::find_arg(session_args, "cap_quota").ulong_value(0) });
/* alloc/attach ram ds and move session env to the base of it */
_ram_ds.construct(_tmp_session_env->alloc(sizeof(Session_env) + sizeof(SESSION_COMPONENT), CACHED));
_ram_ptr = _tmp_session_env->attach(*_ram_ds);
_session_env_ptr = construct_at<Session_env>(_ram_ptr, *_tmp_session_env);
/* create session right behind the session env inside the ram ds */
SESSION_COMPONENT *session { create_session_fn(*_session_env_ptr, (void*)((addr_t)_ram_ptr + sizeof(Session_env)), *_ram_ds) };
/* ensure that the ram ds is not dissolved on destruction of this object */
_tmp_session_env.destruct();
_session_env_ptr = nullptr;
return session;
}
~Session_creation()
{
if (_session_env_ptr) {
Session_env tmp_session_env { *_session_env_ptr };
if (_ram_ds.constructed())
tmp_session_env.free(*_ram_ds);
if (_ram_ptr)
tmp_session_env.detach(_ram_ptr);
} else if (_tmp_session_env.constructed()) {
if (_ram_ds.constructed())
_tmp_session_env->free(*_ram_ds);
if (_ram_ptr)
_tmp_session_env->detach(_ram_ptr);
}
}
};
#endif /* _SESSION_CREATION_H_ */

View File

@ -17,6 +17,7 @@
/* local includes */
#include <uplink_session_root.h>
#include <configuration.h>
#include <session_creation.h>
using namespace Net;
using namespace Genode;
@ -136,88 +137,43 @@ Net::Uplink_session_root::Uplink_session_root(Env &env,
Uplink_session_component *
Net::Uplink_session_root::_create_session(char const *args)
{
Session_creation<Uplink_session_component> session_creation { };
try {
/* create session environment temporarily on the stack */
Session_env session_env_stack { _env, _shared_quota,
Ram_quota { Arg_string::find_arg(args, "ram_quota").ulong_value(0) },
Cap_quota { Arg_string::find_arg(args, "cap_quota").ulong_value(0) } };
return session_creation.execute(
_env, _shared_quota, args,
[&] (Session_env &session_env, void *session_at, Ram_dataspace_capability ram_ds)
{
Session_label const label { label_from_args(args) };
/* alloc/attach RAM block and move session env to base of the block */
Ram_dataspace_capability ram_ds {
session_env_stack.alloc(sizeof(Session_env) +
sizeof(Uplink_session_component), CACHED) };
try {
void * const ram_ptr { session_env_stack.attach(ram_ds) };
Session_env &session_env {
*construct_at<Session_env>(ram_ptr, session_env_stack) };
enum { MAC_STR_LENGTH = 19 };
char mac_str [MAC_STR_LENGTH];
Arg mac_arg { Arg_string::find_arg(args, "mac_address") };
Session_label const label { label_from_args(args) };
enum { MAC_STR_LENGTH = 19 };
char mac_str [MAC_STR_LENGTH];
Arg mac_arg { Arg_string::find_arg(args, "mac_address") };
if (!mac_arg.valid()) {
Session_env session_env_stack { session_env };
session_env_stack.detach(ram_ptr);
session_env_stack.free(ram_ds);
_invalid_downlink("failed to find 'mac_address' arg");
throw Service_denied();
}
mac_arg.string(mac_str, MAC_STR_LENGTH, "");
Mac_address mac { };
ascii_to(mac_str, mac);
if (mac == Mac_address { }) {
Session_env session_env_stack { session_env };
session_env_stack.detach(ram_ptr);
session_env_stack.free(ram_ds);
_invalid_downlink("malformed 'mac_address' arg");
throw Service_denied();
}
/* create new session object behind session env in the RAM block */
try {
if (!mac_arg.valid()) {
_invalid_downlink("failed to find 'mac_address' arg");
throw Service_denied();
}
mac_arg.string(mac_str, MAC_STR_LENGTH, "");
Mac_address mac { };
ascii_to(mac_str, mac);
if (mac == Mac_address { }) {
_invalid_downlink("malformed 'mac_address' arg");
throw Service_denied();
}
return construct_at<Uplink_session_component>(
(void*)((addr_t)ram_ptr + sizeof(Session_env)),
session_env,
session_at, session_env,
Arg_string::find_arg(args, "tx_buf_size").ulong_value(0),
Arg_string::find_arg(args, "rx_buf_size").ulong_value(0),
_timer, mac, label, _interfaces, _config(), ram_ds);
}
catch (Out_of_ram) {
Session_env session_env_stack { session_env };
session_env_stack.detach(ram_ptr);
session_env_stack.free(ram_ds);
_invalid_downlink("Uplink session RAM quota");
throw Insufficient_ram_quota();
}
catch (Out_of_caps) {
Session_env session_env_stack { session_env };
session_env_stack.detach(ram_ptr);
session_env_stack.free(ram_ds);
_invalid_downlink("Uplink session CAP quota");
throw Insufficient_cap_quota();
}
}
catch (Region_map::Invalid_dataspace) {
session_env_stack.free(ram_ds);
_invalid_downlink("Failed to attach RAM");
throw Service_denied();
}
catch (Region_map::Region_conflict) {
session_env_stack.free(ram_ds);
_invalid_downlink("Failed to attach RAM");
throw Service_denied();
}
catch (Out_of_ram) {
session_env_stack.free(ram_ds);
_invalid_downlink("Uplink session RAM quota");
throw Insufficient_ram_quota();
}
catch (Out_of_caps) {
session_env_stack.free(ram_ds);
_invalid_downlink("Uplink session CAP quota");
throw Insufficient_cap_quota();
}
});
}
catch (Region_map::Invalid_dataspace) {
_invalid_downlink("Failed to attach RAM");
throw Service_denied();
}
catch (Region_map::Region_conflict) {
_invalid_downlink("Failed to attach RAM");
throw Service_denied();
}
catch (Out_of_ram) {
_invalid_downlink("Uplink session RAM quota");