1
0
Fork 0
mirror of https://github.com/warmcat/libwebsockets.git synced 2025-03-09 00:00:04 +01:00

netlink: migrate to context

For SMP case, it was desirable to have a netlink listener per pt so they
could deal with pt-level changes in the pt's local service thread.  But
Linux restricts the process to just one netlink listener.

We worked around it by only listening on pt[0], this aligns us a bit more
with the reality and moves to a single routing table in the context.
There's still more to do for SMP case locking.
This commit is contained in:
Andy Green 2021-03-07 09:44:29 +00:00
parent 8dbe8507a3
commit f9c3d432a8
10 changed files with 89 additions and 62 deletions

View file

@ -311,7 +311,7 @@ solo:
lwsi_set_state(wsi, LRS_WAITING_DNS);
lwsl_info("%s: %s: lookup %s:%u\n", __func__, wsi->lc.gutag, ads, port);
(void)port;
wsi->conn_port = (uint16_t)port;
#if defined(LWS_WITH_DETAILED_LATENCY)
wsi->detlat.earliest_write_req_pre_write = lws_now_usecs();

View file

@ -129,7 +129,7 @@ lws_client_connect_3_connect(struct lws *wsi, const char *ads,
#endif
struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
const struct sockaddr *psa = NULL;
uint16_t port = wsi->c_port;
uint16_t port = wsi->conn_port;
const char *cce, *iface;
lws_dns_sort_t *curr;
ssize_t plen = 0;

View file

@ -106,6 +106,7 @@ lws_client_connect_4_established(struct lws *wsi, struct lws *wsi_piggyback,
lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE,
(int)wsi->a.context->timeout_secs);
wsi->conn_port = wsi->c_port;
lwsi_set_state(wsi, LRS_WAITING_PROXY_REPLY);
return wsi;

View file

@ -562,7 +562,7 @@ lws_sort_dns_dump(struct lws *wsi)
(void)n; /* nologs */
if (!lws_dll2_get_head(&wsi->dns_sorted_list))
lwsl_info("%s: empty\n", __func__);
lwsl_notice("%s: empty\n", __func__);
lws_start_foreach_dll(struct lws_dll2 *, d,
lws_dll2_get_head(&wsi->dns_sorted_list)) {
@ -572,7 +572,7 @@ lws_sort_dns_dump(struct lws *wsi)
lws_sa46_write_numeric_address(&s->dest, dest, sizeof(dest));
lws_sa46_write_numeric_address(&s->gateway, gw, sizeof(gw));
lwsl_info("%s: %d: (%d)%s, gw (%d)%s, idi: %d, "
lwsl_notice("%s: %d: (%d)%s, gw (%d)%s, idi: %d, "
"lbl: %d, prec: %d\n",
__func__, n++, s->dest.sa4.sin_family, dest,
s->gateway.sa4.sin_family, gw,
@ -648,12 +648,13 @@ lws_sort_dns(struct lws *wsi, const struct addrinfo *result)
* we don't have a way to use it if we listed it
*/
if (pt->routing_table.count) {
if (pt->context->routing_table.count) {
estr = _lws_route_est_outgoing(pt, &ds->dest);
if (!estr) {
lws_free(ds);
lwsl_info("%s: no route out\n", __func__);
lwsl_notice("%s: %s has no route out\n",
__func__, afip);
/*
* There's no outbound route for this, it's
* unusable, so don't add it to the list
@ -716,7 +717,7 @@ lws_sort_dns(struct lws *wsi, const struct addrinfo *result)
*/
lws_start_foreach_dll(struct lws_dll2 *, d,
lws_dll2_get_head(&pt->routing_table)) {
lws_dll2_get_head(&pt->context->routing_table)) {
lws_route_t *r = lws_container_of(d, lws_route_t, list);
/* gateway routes are skipped here */
@ -731,7 +732,7 @@ lws_sort_dns(struct lws *wsi, const struct addrinfo *result)
/* bestsrc is the best source route, or NULL if none */
if (!bestsrc && pt->routing_table.count) {
if (!bestsrc && pt->context->routing_table.count) {
/* drop it, no usable source route */
lws_free(ds);
goto next;

View file

@ -881,7 +881,18 @@ lws_sa46_write_numeric_address(lws_sockaddr46 *sa46, char *buf, size_t len)
return lws_write_numeric_address(
(uint8_t *)&sa46->sa4.sin_addr, 4, buf, len);
lws_snprintf(buf, len, "(bad AF %d)", (int)sa46->sa4.sin_family);
#if defined(LWS_WITH_UNIX_SOCK)
if (sa46->sa4.sin_family == AF_UNIX)
return lws_snprintf(buf, len, "(unix skt)");
#endif
if (!sa46->sa4.sin_family)
return lws_snprintf(buf, len, "(unset)");
if (sa46->sa4.sin_family == AF_INET6)
lws_snprintf(buf, len, "(ipv6 unsupp)");
lws_snprintf(buf, len, "(AF%d unsupp)", (int)sa46->sa4.sin_family);
return -1;
}

View file

@ -298,7 +298,7 @@ __insert_wsi_socket_into_fds(struct lws_context *context, struct lws *wsi)
assert(wsi);
#if defined(LWS_WITH_NETLINK)
assert(wsi->event_pipe || wsi->a.vhost || wsi == pt->netlink);
assert(wsi->event_pipe || wsi->a.vhost || wsi == pt->context->netlink);
#else
assert(wsi->event_pipe || wsi->a.vhost);
#endif

View file

@ -402,11 +402,6 @@ struct lws_context_per_thread {
lws_sockfd_type dummy_pipe_fds[2];
struct lws *pipe_wsi;
#if defined(LWS_WITH_NETLINK)
lws_dll2_owner_t routing_table;
struct lws *netlink;
#endif
/* --- role based members --- */
#if defined(LWS_ROLE_WS) && !defined(LWS_WITHOUT_EXTENSIONS)
@ -450,10 +445,6 @@ struct lws_context_per_thread {
unsigned char tid;
#if defined(LWS_WITH_NETLINK)
lws_route_uidx_t route_uidx;
#endif
unsigned char inside_service:1;
unsigned char inside_lws_service:1;
unsigned char event_loop_foreign:1;
@ -889,7 +880,7 @@ struct lws {
unsigned int sock_send_blocking:1;
#endif
uint16_t ocport, c_port;
uint16_t ocport, c_port, conn_port;
uint16_t retry;
#if defined(LWS_WITH_CLIENT)
uint16_t keep_warm_secs;
@ -1411,7 +1402,7 @@ void
_lws_routing_entry_dump(lws_route_t *rou);
void
_lws_routing_table_dump(struct lws_context_per_thread *pt);
_lws_routing_table_dump(struct lws_context *cx);
#define LRR_IGNORE_PRI (1 << 0)
#define LRR_MATCH_SRC (1 << 1)
@ -1426,7 +1417,7 @@ void
_lws_route_table_ifdown(struct lws_context_per_thread *pt, int idx);
lws_route_uidx_t
_lws_route_get_uidx(struct lws_context_per_thread *pt);
_lws_route_get_uidx(struct lws_context *cx);
int
_lws_route_pt_close_route_users(struct lws_context_per_thread *pt,

View file

@ -31,28 +31,43 @@
#include <private-lib-core.h>
#if defined(_DEBUG)
void
_lws_routing_entry_dump(lws_route_t *rou)
{
char sa[48], da[48], gw[48];
char sa[48], fin[192], *end = &fin[sizeof(fin)];
int n = 0;
lws_sa46_write_numeric_address(&rou->src, sa, sizeof(sa));
lws_sa46_write_numeric_address(&rou->dest, da, sizeof(da));
lws_sa46_write_numeric_address(&rou->gateway, gw, sizeof(gw));
if (rou->dest.sa4.sin_family) {
lws_sa46_write_numeric_address(&rou->dest, sa, sizeof(sa));
n += lws_snprintf(fin, lws_ptr_diff_size_t(end, fin),
"dst: %s/%d, ", sa, rou->dest_len);
}
lwsl_info(" dst: (%d)%s/%d, src: (%d)%s/%d, gw: (%d)%s, ifidx: %d, pri: %d, proto: %d\n",
rou->dest.sa4.sin_family, da, rou->dest_len,
rou->src.sa4.sin_family, sa, rou->src_len,
rou->gateway.sa4.sin_family, gw,
rou->if_idx, rou->priority, rou->proto);
if (rou->src.sa4.sin_family) {
lws_sa46_write_numeric_address(&rou->src, sa, sizeof(sa));
n += lws_snprintf(fin, lws_ptr_diff_size_t(end, fin),
"src: %s/%d, ", sa, rou->src_len);
}
if (rou->gateway.sa4.sin_family) {
lws_sa46_write_numeric_address(&rou->gateway, sa, sizeof(sa));
n += lws_snprintf(fin, lws_ptr_diff_size_t(end, fin),
"gw: %s, ", sa);
}
lwsl_info(" %s ifidx: %d, pri: %d, proto: %d\n", fin,
rou->if_idx, rou->priority, rou->proto);
}
void
_lws_routing_table_dump(struct lws_context_per_thread *pt)
_lws_routing_table_dump(struct lws_context *cx)
{
lwsl_info("%s\n", __func__);
lws_start_foreach_dll(struct lws_dll2 *, d,
lws_dll2_get_head(&pt->routing_table)) {
lws_dll2_get_head(&cx->routing_table)) {
lws_route_t *rou = lws_container_of(d, lws_route_t, list);
_lws_routing_entry_dump(rou);
@ -80,10 +95,10 @@ _lws_routing_table_dump(struct lws_context_per_thread *pt)
*/
lws_route_uidx_t
_lws_route_get_uidx(struct lws_context_per_thread *pt)
_lws_route_get_uidx(struct lws_context *cx)
{
if (!pt->route_uidx)
pt->route_uidx++;
if (!cx->route_uidx)
cx->route_uidx++;
while (1) {
char again = 0;
@ -91,20 +106,20 @@ _lws_route_get_uidx(struct lws_context_per_thread *pt)
/* Anybody in the table already uses the pt's next uidx? */
lws_start_foreach_dll(struct lws_dll2 *, d,
lws_dll2_get_head(&pt->routing_table)) {
lws_dll2_get_head(&cx->routing_table)) {
lws_route_t *rou = lws_container_of(d, lws_route_t, list);
if (rou->uidx == pt->route_uidx) {
if (rou->uidx == cx->route_uidx) {
/* if so, bump and restart the check */
pt->route_uidx++;
if (!pt->route_uidx)
pt->route_uidx++;
cx->route_uidx++;
if (!cx->route_uidx)
cx->route_uidx++;
again = 1;
}
} lws_end_foreach_dll(d);
if (!again)
return pt->route_uidx++;
return cx->route_uidx++;
}
}
@ -112,7 +127,7 @@ int
_lws_route_remove(struct lws_context_per_thread *pt, lws_route_t *robj, int flags)
{
lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
lws_dll2_get_head(&pt->routing_table)) {
lws_dll2_get_head(&pt->context->routing_table)) {
lws_route_t *rou = lws_container_of(d, lws_route_t, list);
if ((!(flags & LRR_MATCH_SRC) || !lws_sa46_compare_ads(&robj->src, &rou->src)) &&
@ -139,7 +154,7 @@ void
_lws_route_table_empty(struct lws_context_per_thread *pt)
{
lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
lws_dll2_get_head(&pt->routing_table)) {
lws_dll2_get_head(&pt->context->routing_table)) {
lws_route_t *rou = lws_container_of(d, lws_route_t, list);
lws_dll2_remove(&rou->list);
lws_free(rou);
@ -151,7 +166,7 @@ void
_lws_route_table_ifdown(struct lws_context_per_thread *pt, int idx)
{
lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
lws_dll2_get_head(&pt->routing_table)) {
lws_dll2_get_head(&pt->context->routing_table)) {
lws_route_t *rou = lws_container_of(d, lws_route_t, list);
if (rou->if_idx == idx) {
@ -183,7 +198,7 @@ _lws_route_est_outgoing(struct lws_context_per_thread *pt,
*/
lws_start_foreach_dll(struct lws_dll2 *, d,
lws_dll2_get_head(&pt->routing_table)) {
lws_dll2_get_head(&pt->context->routing_table)) {
lws_route_t *rou = lws_container_of(d, lws_route_t, list);
// _lws_routing_entry_dump(rou);
@ -242,7 +257,7 @@ _lws_route_find_source(struct lws_context_per_thread *pt,
const lws_sockaddr46 *src)
{
lws_start_foreach_dll(struct lws_dll2 *, d,
lws_dll2_get_head(&pt->routing_table)) {
lws_dll2_get_head(&pt->context->routing_table)) {
lws_route_t *rou = lws_container_of(d, lws_route_t, list);
// _lws_routing_entry_dump(rou);
@ -318,7 +333,7 @@ _lws_route_pt_close_unroutable(struct lws_context_per_thread *pt)
lwsl_debug("%s\n", __func__);
#if defined(_DEBUG)
_lws_routing_table_dump(pt);
_lws_routing_table_dump(pt->context);
#endif
for (n = 0; n < pt->fds_count; n++) {

View file

@ -405,6 +405,9 @@ struct lws_context {
#if defined(LWS_WITH_NETLINK)
lws_sorted_usec_list_t sul_nl_coldplug;
/* process can only have one netlink socket, have to do it in ctx */
lws_dll2_owner_t routing_table;
struct lws *netlink;
#endif
#if defined(LWS_PLAT_FREERTOS) || defined(WIN32)
@ -625,6 +628,10 @@ struct lws_context {
uint16_t smd_queue_depth;
#endif
#if defined(LWS_WITH_NETLINK)
lws_route_uidx_t route_uidx;
#endif
unsigned int deprecated:1;
unsigned int inside_context_destroy:1;
unsigned int being_destroyed:1;

View file

@ -41,7 +41,7 @@
#define RTA_ALIGNTO 4U
//#define lwsl_netlink lwsl_notice
#define lwsl_netlink lwsl_debug
#define lwsl_netlink lwsl_info
static void
lws_netlink_coldplug_done_cb(lws_sorted_usec_list_t *sul)
@ -58,6 +58,7 @@ static int
rops_handle_POLLIN_netlink(struct lws_context_per_thread *pt, struct lws *wsi,
struct lws_pollfd *pollfd)
{
struct lws_context *cx = pt->context;
uint8_t s[4096]
#if defined(_DEBUG)
, route_change = 0
@ -77,16 +78,16 @@ rops_handle_POLLIN_netlink(struct lws_context_per_thread *pt, struct lws *wsi,
if (!(pollfd->revents & LWS_POLLIN))
return LWS_HPI_RET_HANDLED;
if (!pt->context->nl_initial_done && pt == &pt->context->pt[0]) {
if (!cx->nl_initial_done && pt == &cx->pt[0]) {
/*
* While netlink info still coming, keep moving the timer for
* calling it "done" to +100ms until after it stops coming
*/
lws_context_lock(pt->context, __func__);
lws_sul_schedule(pt->context, 0, &pt->context->sul_nl_coldplug,
lws_context_lock(cx, __func__);
lws_sul_schedule(cx, 0, &cx->sul_nl_coldplug,
lws_netlink_coldplug_done_cb,
100 * LWS_US_PER_MS);
lws_context_unlock(pt->context);
lws_context_unlock(cx);
}
memset(&msg, 0, sizeof(msg));
@ -388,8 +389,8 @@ ana:
* cannot race
*/
rou->uidx = _lws_route_get_uidx(pt);
lws_dll2_add_tail(&rou->list, &pt->routing_table);
rou->uidx = _lws_route_get_uidx(cx);
lws_dll2_add_tail(&rou->list, &cx->routing_table);
_lws_route_pt_close_unroutable(pt);
@ -405,7 +406,7 @@ inform:
* Participants interested can refer to the pt
* routing table
*/
(void)lws_smd_msg_printf(pt->context, LWSSMDCL_NETWORK,
(void)lws_smd_msg_printf(cx, LWSSMDCL_NETWORK,
"{\"rt\":\"%s\"}\n",
(h->nlmsg_type == RTM_DELROUTE) ?
"del" : "add");
@ -426,16 +427,16 @@ inform:
* If a route with a gw was added or deleted, retrigger captive
* portal detection if we have that
*/
(void)lws_smd_msg_printf(pt->context, LWSSMDCL_NETWORK,
(void)lws_smd_msg_printf(cx, LWSSMDCL_NETWORK,
"{\"trigger\": \"cpdcheck\", "
"\"src\":\"gw-change\"}");
#endif
#if defined(_DEBUG)
if (route_change) {
lws_pt_lock(pt, __func__);
_lws_routing_table_dump(pt);
lws_pt_unlock(pt);
lws_context_lock(cx, __func__);
_lws_routing_table_dump(cx);
lws_context_unlock(cx);
}
#endif
@ -470,7 +471,7 @@ rops_pt_init_destroy_netlink(struct lws_context *context,
return 0;
}
if (pt->netlink)
if (context->netlink)
return 0;
if (pt > &context->pt[0])
@ -515,7 +516,7 @@ rops_pt_init_destroy_netlink(struct lws_context *context,
goto bail2;
}
pt->netlink = wsi;
context->netlink = wsi;
if (lws_wsi_inject_to_loop(pt, wsi))
goto bail2;