Skip to content

Commit 824ff8c

Browse files
authored
Support listener events (#304)
* events: add listener created/closed support These events have been added to the upstream kernel a while ago, see commit f8c9dfbd875b ("mptcp: add pm listener events") in the kernel. To better explain why these events are useful, better to quote [1]: MPTCP for Linux, when not using the in-kernel PM, depends on the userspace PM to create extra listening sockets before announcing addresses and ports. Let's call these "PM listeners". With the existing MPTCP netlink events, a userspace PM can create PM listeners at startup time, or in response to an incoming connection. Creating sockets in response to connections is not optimal: ADD_ADDRs can't be sent until the sockets are created and listen()ed, and if all connections are closed then it may not be clear to the userspace PM daemon that PM listener sockets should be cleaned up. With the addition of MPTCP netlink events for listening socket close & create, PM listening sockets can be managed based on application activity. These new events are then now handled by mptcpd, and plugins can be notified via two new hooks: - listener_created(laddr, pm) - listener_closed(laddr, pm) Link: multipath-tcp/mptcp_net-next#313 [1] Signed-off-by: Matthieu Baerts (NGI0) <[email protected]> * plugins: sspi: add hooks for listener events Just to serve as an example, similar to what is done for other events like ADD_ADDR, RM_ADDR, and MP_PRIO. Signed-off-by: Matthieu Baerts (NGI0) <[email protected]> * tests: lib: support new listener events Just the structure to be able to test the new hooks. Signed-off-by: Matthieu Baerts (NGI0) <[email protected]> * tests: plugins: add listener event support Adding new hooks, checking the laddr value -- similar to what is done when a new connection is created -- and incrementing the linked counter, like the other hooks. Signed-off-by: Matthieu Baerts (NGI0) <[email protected]> * tests: validating new listener hooks Tests 1 and 2 are imitating the server side: a new listening socket is created. Not in the other ones, imitating the client side. Also validate the null plugin. Signed-off-by: Matthieu Baerts (NGI0) <[email protected]> --------- Signed-off-by: Matthieu Baerts (NGI0) <[email protected]>
1 parent 269f10a commit 824ff8c

File tree

14 files changed

+318
-4
lines changed

14 files changed

+318
-4
lines changed

include/mptcpd/plugin.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,26 @@ struct mptcpd_plugin_ops
263263
struct sockaddr const *raddr,
264264
bool backup,
265265
struct mptcpd_pm *pm);
266+
267+
/**
268+
* @brief New MPTCP listener socket has been created.
269+
*
270+
* @param[in] laddr Local address information.
271+
* @param[in] pm Opaque pointer to mptcpd path
272+
* manager object.
273+
*/
274+
void (*listener_created)(struct sockaddr const *laddr,
275+
struct mptcpd_pm *pm);
276+
277+
/**
278+
* @brief MPTCP listener socket has been closed.
279+
*
280+
* @param[in] laddr Local address information.
281+
* @param[in] pm Opaque pointer to mptcpd path
282+
* manager object.
283+
*/
284+
void (*listener_closed)(struct sockaddr const *laddr,
285+
struct mptcpd_pm *pm);
266286
///@}
267287

268288
// --------------------------------------------------------

include/mptcpd/private/plugin.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,28 @@ MPTCPD_API void mptcpd_plugin_subflow_priority(
167167
struct sockaddr const *raddr,
168168
bool backup,
169169
struct mptcpd_pm *pm);
170+
171+
/**
172+
* @brief Notify plugin of MPTCP listener creation.
173+
*
174+
* @param[in] laddr Local address information.
175+
* @param[in] pm Opaque pointer to mptcpd path manager object.
176+
*/
177+
MPTCPD_API void mptcpd_plugin_listener_created(
178+
char const *name,
179+
struct sockaddr const *laddr,
180+
struct mptcpd_pm *pm);
181+
182+
/**
183+
* @brief Notify plugin of MPTCP listener closure.
184+
*
185+
* @param[in] laddr Local address information.
186+
* @param[in] pm Opaque pointer to mptcpd path manager object.
187+
*/
188+
MPTCPD_API void mptcpd_plugin_listener_closed(
189+
char const *name,
190+
struct sockaddr const *laddr,
191+
struct mptcpd_pm *pm);
170192
///@}
171193

172194
/**

lib/plugin.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -679,6 +679,28 @@ void mptcpd_plugin_subflow_priority(mptcpd_token_t token,
679679

680680
}
681681

682+
void mptcpd_plugin_listener_created(char const *name,
683+
struct sockaddr const *laddr,
684+
struct mptcpd_pm *pm)
685+
{
686+
struct mptcpd_plugin_ops const *const ops = name_to_ops(name);
687+
688+
if (ops && ops->listener_created)
689+
ops->listener_created(laddr, pm);
690+
691+
}
692+
693+
void mptcpd_plugin_listener_closed(char const *name,
694+
struct sockaddr const *laddr,
695+
struct mptcpd_pm *pm)
696+
{
697+
struct mptcpd_plugin_ops const *const ops = name_to_ops(name);
698+
699+
if (ops && ops->listener_closed)
700+
ops->listener_closed(laddr, pm);
701+
702+
}
703+
682704
// ----------------------------------------------------------------
683705
// Network Monitoring Related Plugin Operation Callback Invocation
684706
// ----------------------------------------------------------------

plugins/path_managers/sspi.c

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -781,6 +781,29 @@ static void sspi_subflow_priority(mptcpd_token_t token,
781781
*/
782782
}
783783

784+
static void sspi_listener_created(struct sockaddr const *laddr,
785+
struct mptcpd_pm *pm)
786+
{
787+
(void) laddr;
788+
(void) pm;
789+
790+
/*
791+
The sspi plugin doesn't do anything with newly created listener
792+
sockets.
793+
*/
794+
}
795+
796+
static void sspi_listener_closed(struct sockaddr const *laddr,
797+
struct mptcpd_pm *pm)
798+
{
799+
(void) laddr;
800+
(void) pm;
801+
802+
/*
803+
The sspi plugin doesn't do anything with closed listener sockets.
804+
*/
805+
}
806+
784807
static struct mptcpd_plugin_ops const pm_ops = {
785808
.new_connection = sspi_new_connection,
786809
.connection_established = sspi_connection_established,
@@ -789,7 +812,9 @@ static struct mptcpd_plugin_ops const pm_ops = {
789812
.address_removed = sspi_address_removed,
790813
.new_subflow = sspi_new_subflow,
791814
.subflow_closed = sspi_subflow_closed,
792-
.subflow_priority = sspi_subflow_priority
815+
.subflow_priority = sspi_subflow_priority,
816+
.listener_created = sspi_listener_created,
817+
.listener_closed = sspi_listener_closed
793818
};
794819

795820
static int sspi_init(struct mptcpd_pm *pm)

src/path_manager.c

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,89 @@ static void handle_priority_changed(struct pm_event_attrs const *attrs,
539539
pm);
540540
}
541541

542+
#ifdef HAVE_UPSTREAM_KERNEL
543+
/**
544+
* @brief Retrieve listener event attributes.
545+
*
546+
* All listener events have the same payload attributes. Share
547+
* attribute validation and addr initialization in one location.
548+
*
549+
* @param[in] attrs Generic netlink MPTCP subflow event message.
550+
* @param[in,out] laddr MPTCP subflow local address and port.
551+
*
552+
* @return @c true on success, @c false otherwise.
553+
*/
554+
static bool handle_listener(struct pm_event_attrs const *attrs,
555+
struct sockaddr_storage *laddr)
556+
{
557+
assert(attrs != NULL);
558+
assert(laddr != NULL);
559+
560+
/*
561+
Payload:
562+
Address family
563+
Local address
564+
Local port
565+
*/
566+
if (!(attrs->laddr4 || attrs->laddr6)
567+
|| !attrs->local_port) {
568+
l_error("Required MPTCP_EVENT_LISTENER_*"
569+
"message attributes are missing.");
570+
571+
return false;
572+
}
573+
574+
if (!mptcpd_sockaddr_storage_init(attrs->laddr4,
575+
attrs->laddr6,
576+
*attrs->local_port,
577+
laddr)) {
578+
l_error("Unable to initialize address information");
579+
580+
return false;
581+
}
582+
583+
return true;
584+
}
585+
586+
static void handle_listener_created(struct pm_event_attrs const *attrs,
587+
struct mptcpd_pm *pm)
588+
{
589+
/*
590+
Payload:
591+
Address family
592+
Local address
593+
Local port
594+
*/
595+
struct sockaddr_storage laddr;
596+
597+
if (!handle_listener(attrs, &laddr))
598+
return;
599+
600+
static char const *const pm_name = NULL;
601+
602+
mptcpd_plugin_listener_created(pm_name, (struct sockaddr *) &laddr, pm);
603+
}
604+
605+
static void handle_listener_closed(struct pm_event_attrs const *attrs,
606+
struct mptcpd_pm *pm)
607+
{
608+
/*
609+
Payload:
610+
Address family
611+
Local address
612+
Local port
613+
*/
614+
struct sockaddr_storage laddr;
615+
616+
if (!handle_listener(attrs, &laddr))
617+
return;
618+
619+
static char const *const pm_name = NULL;
620+
621+
mptcpd_plugin_listener_closed(pm_name, (struct sockaddr *) &laddr, pm);
622+
}
623+
#endif // HAVE_UPSTREAM_KERNEL
624+
542625
static void handle_mptcp_event(struct l_genl_msg *msg, void *user_data)
543626
{
544627
int const cmd = l_genl_msg_get_command(msg);
@@ -583,6 +666,16 @@ static void handle_mptcp_event(struct l_genl_msg *msg, void *user_data)
583666
handle_priority_changed(&attrs, pm);
584667
break;
585668

669+
#ifdef HAVE_UPSTREAM_KERNEL
670+
case MPTCP_EVENT_LISTENER_CREATED:
671+
handle_listener_created(&attrs, pm);
672+
break;
673+
674+
case MPTCP_EVENT_LISTENER_CLOSED:
675+
handle_listener_closed(&attrs, pm);
676+
break;
677+
#endif // HAVE_UPSTREAM_KERNEL
678+
586679
default:
587680
l_error("Unhandled MPTCP event: %d", cmd);
588681
break;

tests/lib/call_count.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ void call_count_reset(struct plugin_call_count *p)
2222
p->new_subflow = 0;
2323
p->subflow_closed = 0;
2424
p->subflow_priority = 0;
25+
p->listener_created = 0;
26+
p->listener_closed = 0;
2527
p->new_interface = 0;
2628
p->update_interface = 0;
2729
p->delete_interface = 0;
@@ -39,6 +41,8 @@ bool call_count_all_positive(struct plugin_call_count const *p)
3941
&& p->new_subflow >= 0
4042
&& p->subflow_closed >= 0
4143
&& p->subflow_priority >= 0
44+
&& p->listener_created >= 0
45+
&& p->listener_closed >= 0
4246
&& p->new_interface >= 0
4347
&& p->update_interface >= 0
4448
&& p->delete_interface >= 0
@@ -71,6 +75,8 @@ bool call_count_is_equal(struct plugin_call_count const *lhs,
7175
&& lhs->new_subflow == rhs->new_subflow
7276
&& lhs->subflow_closed == rhs->subflow_closed
7377
&& lhs->subflow_priority == rhs->subflow_priority
78+
&& lhs->listener_created == rhs->listener_created
79+
&& lhs->listener_closed == rhs->listener_closed
7480
&& lhs->new_interface == rhs->new_interface
7581
&& lhs->update_interface == rhs->update_interface
7682
&& lhs->delete_interface == rhs->delete_interface

tests/lib/call_plugin.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,16 @@ void call_plugin_ops(struct plugin_call_count const *count,
7070
args->backup,
7171
args->pm);
7272

73+
for (int i = 0; i < count->listener_created; ++i)
74+
mptcpd_plugin_listener_created(args->name,
75+
args->laddr,
76+
args->pm);
77+
78+
for (int i = 0; i < count->listener_closed; ++i)
79+
mptcpd_plugin_listener_closed(args->name,
80+
args->laddr,
81+
args->pm);
82+
7383
for (int i = 0; i < count->connection_closed; ++i)
7484
mptcpd_plugin_connection_closed(args->token, args->pm);
7585

tests/lib/test-plugin.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ struct plugin_call_count
5050
int new_subflow;
5151
int subflow_closed;
5252
int subflow_priority;
53+
int listener_created;
54+
int listener_closed;
5355
int new_interface;
5456
int update_interface;
5557
int delete_interface;
@@ -97,7 +99,9 @@ static struct plugin_call_count const test_count_1 = {
9799
.address_removed = 0,
98100
.new_subflow = 0,
99101
.subflow_closed = 0,
100-
.subflow_priority = 0
102+
.subflow_priority = 0,
103+
.listener_created = 1,
104+
.listener_closed = 1
101105
};
102106

103107
static struct plugin_call_count const test_count_2 = {
@@ -109,6 +113,8 @@ static struct plugin_call_count const test_count_2 = {
109113
.new_subflow = 1,
110114
.subflow_closed = 1,
111115
.subflow_priority = 1,
116+
.listener_created = 1,
117+
.listener_closed = 1,
112118
.new_interface = 1,
113119
.update_interface = 2,
114120
.delete_interface = 1,
@@ -124,7 +130,9 @@ static struct plugin_call_count const test_count_4 = {
124130
.address_removed = 1,
125131
.new_subflow = 0,
126132
.subflow_closed = 0,
127-
.subflow_priority = 0
133+
.subflow_priority = 0,
134+
.listener_created = 0,
135+
.listener_closed = 0
128136
};
129137
///@}
130138

tests/plugins/noop/noop.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,20 @@ static void plugin_noop_subflow_priority(mptcpd_token_t token,
113113
(void) pm;
114114
}
115115

116+
static void plugin_noop_listener_created(struct sockaddr const *laddr,
117+
struct mptcpd_pm *pm)
118+
{
119+
(void) laddr;
120+
(void) pm;
121+
}
122+
123+
static void plugin_noop_listener_closed(struct sockaddr const *laddr,
124+
struct mptcpd_pm *pm)
125+
{
126+
(void) laddr;
127+
(void) pm;
128+
}
129+
116130
void plugin_noop_new_interface(struct mptcpd_interface const *i,
117131
struct mptcpd_pm *pm)
118132
{
@@ -161,6 +175,8 @@ static struct mptcpd_plugin_ops const pm_ops = {
161175
.new_subflow = plugin_noop_new_subflow,
162176
.subflow_closed = plugin_noop_subflow_closed,
163177
.subflow_priority = plugin_noop_subflow_priority,
178+
.listener_created = plugin_noop_listener_created,
179+
.listener_closed = plugin_noop_listener_closed,
164180
.new_interface = plugin_noop_new_interface,
165181
.update_interface = plugin_noop_update_interface,
166182
.delete_interface = plugin_noop_delete_interface,

tests/plugins/priority/one.c

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,28 @@ static void plugin_one_subflow_priority(mptcpd_token_t token,
158158
++call_count.subflow_priority;
159159
}
160160

161+
static void plugin_one_listener_created(struct sockaddr const *laddr,
162+
struct mptcpd_pm *pm)
163+
{
164+
(void) pm;
165+
166+
assert(laddr != NULL);
167+
assert(sockaddr_is_equal(laddr, local_addr));
168+
169+
++call_count.listener_created;
170+
}
171+
172+
static void plugin_one_listener_closed(struct sockaddr const *laddr,
173+
struct mptcpd_pm *pm)
174+
{
175+
(void) pm;
176+
177+
assert(laddr != NULL);
178+
assert(sockaddr_is_equal(laddr, local_addr));
179+
180+
++call_count.listener_closed;
181+
}
182+
161183
static struct mptcpd_plugin_ops const pm_ops = {
162184
.new_connection = plugin_one_new_connection,
163185
.connection_established = plugin_one_connection_established,
@@ -166,7 +188,9 @@ static struct mptcpd_plugin_ops const pm_ops = {
166188
.address_removed = plugin_one_address_removed,
167189
.new_subflow = plugin_one_new_subflow,
168190
.subflow_closed = plugin_one_subflow_closed,
169-
.subflow_priority = plugin_one_subflow_priority
191+
.subflow_priority = plugin_one_subflow_priority,
192+
.listener_created = plugin_one_listener_created,
193+
.listener_closed = plugin_one_listener_closed
170194
};
171195

172196
static int plugin_one_init(struct mptcpd_pm *pm)
@@ -204,6 +228,8 @@ static void plugin_one_exit(struct mptcpd_pm *pm)
204228
.new_subflow = test_count_1.new_subflow * 2,
205229
.subflow_closed = test_count_1.subflow_closed * 2,
206230
.subflow_priority = test_count_1.subflow_priority * 2,
231+
.listener_created = test_count_1.listener_created * 2,
232+
.listener_closed = test_count_1.listener_closed * 2,
207233
};
208234

209235
assert(call_count_is_sane(&call_count));

0 commit comments

Comments
 (0)