summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2020-10-28 12:10:40 +0100
committerThomas Haller <thaller@redhat.com>2020-10-28 12:10:40 +0100
commit817ea086eeaa4b739a46624cd037999d4ec920cc (patch)
tree17f96029a86f981ca5430ff86a6acd0fc684d0f3
parent1cda792206ae4ea72fd3ecd891f665933565adc7 (diff)
parent33041e04afe195e40d49a748df1ed56e6f0d523d (diff)
downloadNetworkManager-817ea086eeaa4b739a46624cd037999d4ec920cc.tar.gz
l3cfg: merge branch 'th/l3cfg-14'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/660
-rw-r--r--shared/nm-std-aux/nm-std-aux.h22
-rw-r--r--src/NetworkManagerUtils.c200
-rw-r--r--src/NetworkManagerUtils.h27
-rw-r--r--src/devices/nm-device.c98
-rw-r--r--src/nm-act-request.c120
-rw-r--r--src/nm-act-request.h10
-rw-r--r--src/nm-l3-config-data.c2
-rw-r--r--src/nm-l3-ipv4ll.c197
-rw-r--r--src/nm-l3-ipv4ll.h23
-rw-r--r--src/nm-l3cfg.c46
-rw-r--r--src/nm-l3cfg.h9
-rw-r--r--src/platform/nm-platform.h4
12 files changed, 497 insertions, 261 deletions
diff --git a/shared/nm-std-aux/nm-std-aux.h b/shared/nm-std-aux/nm-std-aux.h
index 44d0dd273b..7b06472631 100644
--- a/shared/nm-std-aux/nm-std-aux.h
+++ b/shared/nm-std-aux/nm-std-aux.h
@@ -190,11 +190,11 @@ typedef uint64_t _nm_bitwise nm_be64_t;
/*****************************************************************************/
static inline uint32_t
-nm_add_u32_clamped(uint32_t a, uint32_t b)
+nm_add_clamped_u32(uint32_t a, uint32_t b)
{
uint32_t c;
- /* returns the sum of a+b, or UINT32_MAX if the result would overflow. */
+ /* returns a+b, or UINT32_MAX if the result would overflow. */
c = a + b;
if (c < a)
@@ -202,6 +202,24 @@ nm_add_u32_clamped(uint32_t a, uint32_t b)
return c;
}
+static inline unsigned
+nm_mult_clamped_u(unsigned a, unsigned b)
+{
+ unsigned c;
+
+ /* returns a*b, or UINT_MAX if the result would overflow. */
+
+ if (b == 0)
+ return 0;
+
+ c = a * b;
+
+ if (c / b != a)
+ return (unsigned) -1;
+
+ return c;
+}
+
/* glib's MIN()/MAX() macros don't have function-like behavior, in that they evaluate
* the argument possibly twice.
*
diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c
index 4739e9dd15..3d1b3a4489 100644
--- a/src/NetworkManagerUtils.c
+++ b/src/NetworkManagerUtils.c
@@ -1636,3 +1636,203 @@ nm_utils_ip_routes_to_dbus(int addr_family,
NM_SET_OUT(out_route_data, g_variant_builder_end(&builder_data));
NM_SET_OUT(out_routes, g_variant_builder_end(&builder_legacy));
}
+
+/*****************************************************************************/
+
+typedef struct {
+ char *table;
+ char *rule;
+} ShareRule;
+
+struct _NMUtilsShareRules {
+ GArray *rules;
+};
+
+static void
+_share_rule_clear(gpointer data)
+{
+ ShareRule *rule = data;
+
+ g_free(rule->table);
+ g_free(rule->rule);
+}
+
+NMUtilsShareRules *
+nm_utils_share_rules_new(void)
+{
+ NMUtilsShareRules *self;
+
+ self = g_slice_new(NMUtilsShareRules);
+ *self = (NMUtilsShareRules){
+ .rules = g_array_sized_new(FALSE, FALSE, sizeof(ShareRule), 10),
+ };
+
+ g_array_set_clear_func(self->rules, _share_rule_clear);
+ return self;
+}
+
+void
+nm_utils_share_rules_free(NMUtilsShareRules *self)
+{
+ if (!self)
+ return;
+
+ g_array_unref(self->rules);
+ nm_g_slice_free(self);
+}
+
+void
+nm_utils_share_rules_add_rule_take(NMUtilsShareRules *self, const char *table, char *rule_take)
+{
+ ShareRule *rule;
+
+ g_return_if_fail(self);
+ g_return_if_fail(table);
+ g_return_if_fail(rule_take);
+
+ rule = nm_g_array_append_new(self->rules, ShareRule);
+ *rule = (ShareRule){
+ .table = g_strdup(table),
+ .rule = g_steal_pointer(&rule_take),
+ };
+}
+
+void
+nm_utils_share_rules_apply(NMUtilsShareRules *self, gboolean shared)
+{
+ guint i;
+
+ g_return_if_fail(self);
+
+ if (self->rules->len == 0)
+ return;
+
+ /* depending on whether we share or unshare, we add/remote the rules
+ * in opposite order. */
+ if (shared)
+ i = self->rules->len - 1;
+ else
+ i = 0;
+
+ for (;;) {
+ gs_free_error GError *error = NULL;
+ ShareRule * rule;
+ gs_free const char ** argv = NULL;
+ gs_free char * cmd = NULL;
+ int status;
+
+ rule = &g_array_index(self->rules, ShareRule, i);
+
+ cmd = g_strdup_printf("%s --table %s %s %s",
+ IPTABLES_PATH,
+ rule->table,
+ shared ? "--insert" : "--delete",
+ rule->rule);
+ argv = nm_utils_strsplit_set(cmd, " ");
+
+ nm_log_info(LOGD_SHARING, "Executing: %s", cmd);
+ if (!g_spawn_sync("/",
+ (char **) argv,
+ (char **) NM_PTRARRAY_EMPTY(const char *),
+ G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &status,
+ &error)) {
+ nm_log_warn(LOGD_SHARING, "Error executing command: %s", error->message);
+ goto next;
+ }
+ if (WEXITSTATUS(status)) {
+ nm_log_warn(LOGD_SHARING, "** Command returned exit status %d.", WEXITSTATUS(status));
+ }
+
+next:
+ if (shared) {
+ if (i == 0)
+ break;
+ i--;
+ } else {
+ i++;
+ if (i >= self->rules->len)
+ break;
+ }
+ }
+}
+
+void
+nm_utils_share_rules_add_all_rules(NMUtilsShareRules *self,
+ const char * ip_iface,
+ in_addr_t addr,
+ guint plen)
+{
+ in_addr_t netmask;
+ in_addr_t network;
+ char str_mask[NM_UTILS_INET_ADDRSTRLEN];
+ char str_addr[NM_UTILS_INET_ADDRSTRLEN];
+
+ nm_assert(self);
+
+ netmask = _nm_utils_ip4_prefix_to_netmask(plen);
+ _nm_utils_inet4_ntop(netmask, str_mask);
+
+ network = addr & netmask;
+ _nm_utils_inet4_ntop(network, str_addr);
+
+ nm_utils_share_rules_add_rule_v(
+ self,
+ "nat",
+ "POSTROUTING --source %s/%s ! --destination %s/%s --jump MASQUERADE",
+ str_addr,
+ str_mask,
+ str_addr,
+ str_mask);
+ nm_utils_share_rules_add_rule_v(
+ self,
+ "filter",
+ "FORWARD --destination %s/%s --out-interface %s --match state --state "
+ "ESTABLISHED,RELATED --jump ACCEPT",
+ str_addr,
+ str_mask,
+ ip_iface);
+ nm_utils_share_rules_add_rule_v(self,
+ "filter",
+ "FORWARD --source %s/%s --in-interface %s --jump ACCEPT",
+ str_addr,
+ str_mask,
+ ip_iface);
+ nm_utils_share_rules_add_rule_v(self,
+ "filter",
+ "FORWARD --in-interface %s --out-interface %s --jump ACCEPT",
+ ip_iface,
+ ip_iface);
+ nm_utils_share_rules_add_rule_v(self,
+ "filter",
+ "FORWARD --out-interface %s --jump REJECT",
+ ip_iface);
+ nm_utils_share_rules_add_rule_v(self,
+ "filter",
+ "FORWARD --in-interface %s --jump REJECT",
+ ip_iface);
+ nm_utils_share_rules_add_rule_v(
+ self,
+ "filter",
+ "INPUT --in-interface %s --protocol udp --destination-port 67 --jump ACCEPT",
+ ip_iface);
+ nm_utils_share_rules_add_rule_v(
+ self,
+ "filter",
+ "INPUT --in-interface %s --protocol tcp --destination-port 67 --jump ACCEPT",
+ ip_iface);
+ nm_utils_share_rules_add_rule_v(
+ self,
+ "filter",
+ "INPUT --in-interface %s --protocol udp --destination-port 53 --jump ACCEPT",
+ ip_iface);
+ nm_utils_share_rules_add_rule_v(
+ self,
+ "filter",
+ "INPUT --in-interface %s --protocol tcp --destination-port 53 --jump ACCEPT",
+ ip_iface);
+}
diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h
index e961c785a1..5373f9cea8 100644
--- a/src/NetworkManagerUtils.h
+++ b/src/NetworkManagerUtils.h
@@ -224,4 +224,31 @@ NM_AUTO_DEFINE_FCN(NMDhcpLease *, _nm_auto_unref_dhcplease, nm_dhcp_lease_unref)
/*****************************************************************************/
+typedef struct _NMUtilsShareRules NMUtilsShareRules;
+
+NMUtilsShareRules *nm_utils_share_rules_new(void);
+
+void nm_utils_share_rules_free(NMUtilsShareRules *self);
+
+void
+nm_utils_share_rules_add_rule_take(NMUtilsShareRules *self, const char *table, char *rule_take);
+
+static inline void
+nm_utils_share_rules_add_rule(NMUtilsShareRules *self, const char *table, const char *rule)
+{
+ nm_utils_share_rules_add_rule_take(self, table, g_strdup(rule));
+}
+
+#define nm_utils_share_rules_add_rule_v(self, table, ...) \
+ nm_utils_share_rules_add_rule_take((self), (table), g_strdup_printf(__VA_ARGS__))
+
+void nm_utils_share_rules_add_all_rules(NMUtilsShareRules *self,
+ const char * ip_iface,
+ in_addr_t addr,
+ guint plen);
+
+void nm_utils_share_rules_apply(NMUtilsShareRules *self, gboolean shared);
+
+/*****************************************************************************/
+
#endif /* __NETWORKMANAGER_UTILS_H__ */
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 06693b4f70..a30e42df41 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -11536,17 +11536,16 @@ activate_stage4_ip_config_timeout_6(NMDevice *self)
static gboolean
share_init(NMDevice *self, GError **error)
{
- char * modules[] = {"ip_tables",
- "iptable_nat",
- "nf_nat_ftp",
- "nf_nat_irc",
- "nf_nat_sip",
- "nf_nat_tftp",
- "nf_nat_pptp",
- "nf_nat_h323",
- NULL};
- char **iter;
- int errsv;
+ const char *const modules[] = {"ip_tables",
+ "iptable_nat",
+ "nf_nat_ftp",
+ "nf_nat_irc",
+ "nf_nat_sip",
+ "nf_nat_tftp",
+ "nf_nat_pptp",
+ "nf_nat_h323"};
+ guint i;
+ int errsv;
if (nm_platform_sysctl_get_int32(nm_device_get_platform(self),
NMP_SYSCTL_PATHID_ABSOLUTE("/proc/sys/net/ipv4/ip_forward"),
@@ -11584,35 +11583,24 @@ share_init(NMDevice *self, GError **error)
nm_strerror_native(errsv));
}
- for (iter = modules; *iter; iter++)
- nm_utils_modprobe(NULL, FALSE, *iter, NULL);
+ for (i = 0; i < G_N_ELEMENTS(modules); i++)
+ nm_utils_modprobe(NULL, FALSE, modules[i], NULL);
return TRUE;
}
-#define add_share_rule(req, table, ...) \
- G_STMT_START \
- { \
- char *_cmd = g_strdup_printf(__VA_ARGS__); \
- nm_act_request_add_share_rule(req, table, _cmd); \
- g_free(_cmd); \
- } \
- G_STMT_END
-
static gboolean
start_sharing(NMDevice *self, NMIP4Config *config, GError **error)
{
NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self);
NMActRequest * req;
- char str_addr[INET_ADDRSTRLEN];
- char str_mask[INET_ADDRSTRLEN];
- guint32 netmask, network;
const NMPlatformIP4Address *ip4_addr = NULL;
const char * ip_iface;
GError * local = NULL;
NMConnection * conn;
NMSettingConnection * s_con;
gboolean announce_android_metered;
+ NMUtilsShareRules * share_rules;
g_return_val_if_fail(config, FALSE);
@@ -11637,57 +11625,13 @@ start_sharing(NMDevice *self, NMIP4Config *config, GError **error)
req = nm_device_get_act_request(self);
g_return_val_if_fail(req, FALSE);
- netmask = _nm_utils_ip4_prefix_to_netmask(ip4_addr->plen);
- _nm_utils_inet4_ntop(netmask, str_mask);
-
- network = ip4_addr->address & netmask;
- _nm_utils_inet4_ntop(network, str_addr);
-
- add_share_rule(req,
- "nat",
- "POSTROUTING --source %s/%s ! --destination %s/%s --jump MASQUERADE",
- str_addr,
- str_mask,
- str_addr,
- str_mask);
- add_share_rule(req,
- "filter",
- "FORWARD --destination %s/%s --out-interface %s --match state --state "
- "ESTABLISHED,RELATED --jump ACCEPT",
- str_addr,
- str_mask,
- ip_iface);
- add_share_rule(req,
- "filter",
- "FORWARD --source %s/%s --in-interface %s --jump ACCEPT",
- str_addr,
- str_mask,
- ip_iface);
- add_share_rule(req,
- "filter",
- "FORWARD --in-interface %s --out-interface %s --jump ACCEPT",
- ip_iface,
- ip_iface);
- add_share_rule(req, "filter", "FORWARD --out-interface %s --jump REJECT", ip_iface);
- add_share_rule(req, "filter", "FORWARD --in-interface %s --jump REJECT", ip_iface);
- add_share_rule(req,
- "filter",
- "INPUT --in-interface %s --protocol udp --destination-port 67 --jump ACCEPT",
- ip_iface);
- add_share_rule(req,
- "filter",
- "INPUT --in-interface %s --protocol tcp --destination-port 67 --jump ACCEPT",
- ip_iface);
- add_share_rule(req,
- "filter",
- "INPUT --in-interface %s --protocol udp --destination-port 53 --jump ACCEPT",
- ip_iface);
- add_share_rule(req,
- "filter",
- "INPUT --in-interface %s --protocol tcp --destination-port 53 --jump ACCEPT",
- ip_iface);
-
- nm_act_request_set_shared(req, TRUE);
+ share_rules = nm_utils_share_rules_new();
+
+ nm_utils_share_rules_add_all_rules(share_rules, ip_iface, ip4_addr->address, ip4_addr->plen);
+
+ nm_utils_share_rules_apply(share_rules, TRUE);
+
+ nm_act_request_set_shared(req, share_rules);
conn = nm_act_request_get_applied_connection(req);
s_con = nm_connection_get_setting_connection(conn);
@@ -11722,7 +11666,7 @@ start_sharing(NMDevice *self, NMIP4Config *config, GError **error)
"could not start dnsmasq due to %s",
local->message);
g_error_free(local);
- nm_act_request_set_shared(req, FALSE);
+ nm_act_request_set_shared(req, NULL);
return FALSE;
}
diff --git a/src/nm-act-request.c b/src/nm-act-request.c
index 67936ca08e..b1c675a678 100644
--- a/src/nm-act-request.c
+++ b/src/nm-act-request.c
@@ -22,14 +22,8 @@
#include "nm-libnm-core-intern/nm-auth-subject.h"
typedef struct {
- char *table;
- char *rule;
-} ShareRule;
-
-typedef struct {
- CList call_ids_lst_head;
- gboolean shared;
- GSList * share_rules;
+ CList call_ids_lst_head;
+ NMUtilsShareRules *share_rules;
} NMActRequestPrivate;
struct _NMActRequest {
@@ -254,109 +248,32 @@ nm_act_request_clear_secrets(NMActRequest *self)
/*****************************************************************************/
-static void
-clear_share_rules(NMActRequest *req)
-{
- NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE(req);
- GSList * iter;
-
- for (iter = priv->share_rules; iter; iter = g_slist_next(iter)) {
- ShareRule *rule = (ShareRule *) iter->data;
-
- g_free(rule->table);
- g_free(rule->rule);
- g_free(rule);
- }
-
- g_slist_free(priv->share_rules);
- priv->share_rules = NULL;
-}
-
-void
-nm_act_request_set_shared(NMActRequest *req, gboolean shared)
-{
- NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE(req);
- GSList * list, *iter;
-
- g_return_if_fail(NM_IS_ACT_REQUEST(req));
-
- NM_ACT_REQUEST_GET_PRIVATE(req)->shared = shared;
-
- /* Tear the rules down in reverse order when sharing is stopped */
- list = g_slist_copy(priv->share_rules);
- if (!shared)
- list = g_slist_reverse(list);
-
- /* Send the rules to iptables */
- for (iter = list; iter; iter = g_slist_next(iter)) {
- ShareRule * rule = (ShareRule *) iter->data;
- char * envp[1] = {NULL};
- gs_strfreev char **argv = NULL;
- gs_free char * cmd = NULL;
-
- cmd = g_strdup_printf("%s --table %s %s %s",
- IPTABLES_PATH,
- rule->table,
- shared ? "--insert" : "--delete",
- rule->rule);
- if (!cmd)
- continue;
-
- argv = g_strsplit(cmd, " ", 0);
- if (argv && argv[0]) {
- int status;
- GError *error = NULL;
-
- nm_log_info(LOGD_SHARING, "Executing: %s", cmd);
- if (!g_spawn_sync("/",
- argv,
- envp,
- G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- &status,
- &error)) {
- nm_log_warn(LOGD_SHARING, "Error executing command: %s", error->message);
- g_clear_error(&error);
- } else if (WEXITSTATUS(status)) {
- nm_log_warn(LOGD_SHARING,
- "** Command returned exit status %d.",
- WEXITSTATUS(status));
- }
- }
- }
-
- g_slist_free(list);
-
- /* Clear the share rule list when sharing is stopped */
- if (!shared)
- clear_share_rules(req);
-}
-
-gboolean
+NMUtilsShareRules *
nm_act_request_get_shared(NMActRequest *req)
{
g_return_val_if_fail(NM_IS_ACT_REQUEST(req), FALSE);
- return NM_ACT_REQUEST_GET_PRIVATE(req)->shared;
+ return NM_ACT_REQUEST_GET_PRIVATE(req)->share_rules;
}
void
-nm_act_request_add_share_rule(NMActRequest *req, const char *table, const char *table_rule)
+nm_act_request_set_shared(NMActRequest *req, NMUtilsShareRules *rules)
{
NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE(req);
- ShareRule * rule;
g_return_if_fail(NM_IS_ACT_REQUEST(req));
- g_return_if_fail(table != NULL);
- g_return_if_fail(table_rule != NULL);
- rule = g_malloc0(sizeof(ShareRule));
- rule->table = g_strdup(table);
- rule->rule = g_strdup(table_rule);
- priv->share_rules = g_slist_prepend(priv->share_rules, rule);
+ if (priv->share_rules == rules)
+ return;
+
+ if (priv->share_rules) {
+ nm_utils_share_rules_apply(priv->share_rules, FALSE);
+ priv->share_rules = NULL;
+ }
+ if (rules) {
+ priv->share_rules = rules;
+ nm_utils_share_rules_apply(priv->share_rules, TRUE);
+ }
}
/*****************************************************************************/
@@ -589,10 +506,9 @@ dispose(GObject *object)
c_list_for_each_entry_safe (call_id, call_id_safe, &priv->call_ids_lst_head, call_ids_lst)
_do_cancel_secrets(self, call_id, TRUE);
- /* Clear any share rules */
if (priv->share_rules) {
- nm_act_request_set_shared(NM_ACT_REQUEST(object), FALSE);
- clear_share_rules(NM_ACT_REQUEST(object));
+ nm_utils_share_rules_apply(priv->share_rules, FALSE);
+ nm_clear_pointer(&priv->share_rules, nm_utils_share_rules_free);
}
G_OBJECT_CLASS(nm_act_request_parent_class)->dispose(object);
diff --git a/src/nm-act-request.h b/src/nm-act-request.h
index 65c8abf51b..e962ee7225 100644
--- a/src/nm-act-request.h
+++ b/src/nm-act-request.h
@@ -36,11 +36,15 @@ NMSettingsConnection *nm_act_request_get_settings_connection(NMActRequest *req);
NMConnection *nm_act_request_get_applied_connection(NMActRequest *req);
-gboolean nm_act_request_get_shared(NMActRequest *req);
+/*****************************************************************************/
-void nm_act_request_set_shared(NMActRequest *req, gboolean shared);
+struct _NMUtilsShareRules;
-void nm_act_request_add_share_rule(NMActRequest *req, const char *table, const char *rule);
+struct _NMUtilsShareRules *nm_act_request_get_shared(NMActRequest *req);
+
+void nm_act_request_set_shared(NMActRequest *req, struct _NMUtilsShareRules *rules);
+
+/*****************************************************************************/
/* Secrets handling */
diff --git a/src/nm-l3-config-data.c b/src/nm-l3-config-data.c
index 9b1e017b14..3f6db67c61 100644
--- a/src/nm-l3-config-data.c
+++ b/src/nm-l3-config-data.c
@@ -2600,7 +2600,7 @@ nm_l3_config_data_merge(NML3ConfigData * self,
if (r_src->metric_any) {
_ensure_r();
r.rx.metric_any = FALSE;
- r.rx.metric = nm_add_u32_clamped(r.rx.metric, default_route_metric_x[IS_IPv4]);
+ r.rx.metric = nm_add_clamped_u32(r.rx.metric, default_route_metric_x[IS_IPv4]);
}
if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT(r_src)) {
diff --git a/src/nm-l3-ipv4ll.c b/src/nm-l3-ipv4ll.c
index c5dd7ec88c..fe76b96955 100644
--- a/src/nm-l3-ipv4ll.c
+++ b/src/nm-l3-ipv4ll.c
@@ -11,8 +11,16 @@
#define ADDR_IPV4LL_PREFIX_LEN 16
+#define TIMED_OUT_TIME_FACTOR 5u
+
/*****************************************************************************/
+typedef enum {
+ TIMED_OUT_STATE_IS_NOT_TIMED_OUT,
+ TIMED_OUT_STATE_IS_TIMED_OUT,
+ TIMED_OUT_STATE_HAVE_TIMER_RUNNING,
+} TimedOutState;
+
struct _NML3IPv4LLRegistration {
NML3IPv4LL *self;
CList reg_lst;
@@ -29,24 +37,26 @@ struct _NML3IPv4LL {
CList reg_lst_head;
NML3CfgCommitTypeHandle *l3cfg_commit_handle;
GSource * state_change_on_idle_source;
+ GSource * timed_out_source;
const NML3ConfigData * l3cd;
const NMPObject * plobj;
struct {
nm_le64_t value;
nm_le64_t generation;
} seed;
+ gint64 timed_out_expiry_msec;
gulong l3cfg_signal_notify_id;
- gint64 last_good_at_msec : 1;
NML3IPv4LLState state;
NMEtherAddr seed_mac;
NMEtherAddr mac;
bool seed_set : 1;
- bool seed_reset_generation : 1;
bool mac_set : 1;
- bool link_seen_not_ready : 1;
bool notify_on_idle : 1;
bool reg_changed : 1;
bool l3cd_timeout_msec_changed : 1;
+
+ /* not yet used. */
+ bool seed_reset_generation : 1;
};
G_STATIC_ASSERT(G_STRUCT_OFFSET(NML3IPv4LL, ref_count) == sizeof(gpointer));
@@ -77,6 +87,8 @@ static void _ipv4ll_state_change_on_idle(NML3IPv4LL *self);
static void _ipv4ll_state_change(NML3IPv4LL *self, gboolean is_on_idle_handler);
+static void _ipv4ll_set_timed_out_update(NML3IPv4LL *self, TimedOutState new_state);
+
/*****************************************************************************/
NM_UTILS_ENUM2STR_DEFINE(nm_l3_ipv4ll_state_to_string,
@@ -140,6 +152,22 @@ nm_l3_ipv4ll_get_state(NML3IPv4LL *self)
return self->state;
}
+static gboolean
+_ipv4ll_is_timed_out(NML3IPv4LL *self)
+{
+ _ASSERT(self);
+
+ return self->timed_out_expiry_msec != 0 && !self->timed_out_source;
+}
+
+gboolean
+nm_l3_ipv4ll_is_timed_out(NML3IPv4LL *self)
+{
+ nm_assert(NM_IS_L3_IPV4LL(self));
+
+ return _ipv4ll_is_timed_out(self);
+}
+
in_addr_t
nm_l3_ipv4ll_get_addr(NML3IPv4LL *self)
{
@@ -156,6 +184,20 @@ nm_l3_ipv4ll_get_l3cd(NML3IPv4LL *self)
return self->l3cd;
}
+static void
+_ipv4ll_emit_signal_notify(NML3IPv4LL *self)
+{
+ NML3ConfigNotifyData notify_data;
+
+ self->notify_on_idle = FALSE;
+
+ notify_data.notify_type = NM_L3_CONFIG_NOTIFY_TYPE_IPV4LL_EVENT;
+ notify_data.ipv4ll_event = (typeof(notify_data.ipv4ll_event)){
+ .ipv4ll = self,
+ };
+ _nm_l3cfg_emit_signal_notify(self->l3cfg, &notify_data);
+}
+
/*****************************************************************************/
static NML3IPv4LLRegistration *
@@ -272,23 +314,6 @@ _acd_info_is_good(const NML3AcdAddrInfo *acd_info)
return FALSE;
}
-static gboolean
-_plobj_link_is_ready(const NMPObject *plobj)
-{
- const NMPlatformLink *pllink;
-
- if (!plobj)
- return FALSE;
-
- pllink = NMP_OBJECT_CAST_LINK(plobj);
- if (!NM_FLAGS_HAS(pllink->n_ifi_flags, IFF_UP))
- return FALSE;
- if (pllink->l_address.len != ETH_ALEN)
- return FALSE;
-
- return TRUE;
-}
-
/*****************************************************************************/
static NMPlatformIP4Address *
@@ -694,6 +719,67 @@ _ipv4ll_platform_find_addr(NML3IPv4LL *self, const NML3AcdAddrInfo **out_acd_inf
/*****************************************************************************/
static gboolean
+_ipv4ll_set_timed_out_timeout_cb(gpointer user_data)
+{
+ NML3IPv4LL *self = user_data;
+
+ _ipv4ll_set_timed_out_update(self, TIMED_OUT_STATE_IS_TIMED_OUT);
+ if (self->notify_on_idle)
+ _ipv4ll_emit_signal_notify(self);
+ return G_SOURCE_REMOVE;
+}
+
+static void
+_ipv4ll_set_timed_out_update(NML3IPv4LL *self, TimedOutState new_state)
+{
+ gboolean before;
+
+ before = _ipv4ll_is_timed_out(self);
+
+ switch (new_state) {
+ case TIMED_OUT_STATE_IS_TIMED_OUT:
+ if (self->timed_out_expiry_msec == 0) {
+ nm_assert(!self->timed_out_source);
+ self->timed_out_expiry_msec = 1;
+ }
+ nm_clear_g_source_inst(&self->timed_out_source);
+ break;
+ case TIMED_OUT_STATE_IS_NOT_TIMED_OUT:
+ self->timed_out_expiry_msec = 0;
+ nm_clear_g_source_inst(&self->timed_out_source);
+ break;
+ case TIMED_OUT_STATE_HAVE_TIMER_RUNNING:
+ {
+ gint64 now_msec = nm_utils_get_monotonic_timestamp_msec();
+ guint timeout_msec;
+ gint64 expiry_msec;
+
+ nm_assert(self->reg_timeout_msec > 0u);
+
+ timeout_msec = nm_mult_clamped_u(TIMED_OUT_TIME_FACTOR, self->reg_timeout_msec);
+ expiry_msec = now_msec + timeout_msec;
+
+ if (self->timed_out_expiry_msec == 0 || self->timed_out_expiry_msec < expiry_msec) {
+ self->timed_out_expiry_msec = expiry_msec;
+ nm_clear_g_source_inst(&self->timed_out_source);
+ self->timed_out_source = nm_g_timeout_source_new(timeout_msec,
+ G_PRIORITY_DEFAULT,
+ _ipv4ll_set_timed_out_timeout_cb,
+ self,
+ NULL);
+ g_source_attach(self->timed_out_source, NULL);
+ }
+ break;
+ }
+ }
+
+ if (before != _ipv4ll_is_timed_out(self)) {
+ self->notify_on_idle = TRUE;
+ _LOGT("state: set timed-out-is-bad=%d", (!before));
+ }
+}
+
+static gboolean
_ipv4ll_set_state(NML3IPv4LL *self, NML3IPv4LLState state)
{
char sbuf_addr[NM_UTILS_INET_ADDRSTRLEN];
@@ -731,6 +817,8 @@ _ipv4ll_state_change(NML3IPv4LL *self, gboolean is_on_idle_handler)
if (self->reg_changed) {
guint timeout_msec = self->reg_timeout_msec;
+ self->reg_changed = FALSE;
+
if (c_list_is_empty(&self->reg_lst_head))
timeout_msec = 0;
else {
@@ -749,12 +837,14 @@ _ipv4ll_state_change(NML3IPv4LL *self, gboolean is_on_idle_handler)
}
if (self->reg_timeout_msec == 0) {
+ _ipv4ll_set_timed_out_update(self, TIMED_OUT_STATE_IS_NOT_TIMED_OUT);
if (_ipv4ll_set_state(self, NM_L3_IPV4LL_STATE_DISABLED))
_l3cd_config_remove(self);
goto out_notify;
}
if (!self->mac_set) {
+ _ipv4ll_set_timed_out_update(self, TIMED_OUT_STATE_HAVE_TIMER_RUNNING);
if (_ipv4ll_set_state(self, NM_L3_IPV4LL_STATE_WAIT_FOR_LINK))
_l3cd_config_remove(self);
else
@@ -773,7 +863,12 @@ _ipv4ll_state_change(NML3IPv4LL *self, gboolean is_on_idle_handler)
if (pladdr) {
/* we have an externally configured address. Check whether we can use it. */
- goto out_set_external_pladdr;
+ self->addr = pladdr->address;
+ self->notify_on_idle = TRUE;
+ _ipv4ll_set_state(self, NM_L3_IPV4LL_STATE_EXTERNAL);
+ _l3cd_config_add(self);
+ _ipv4ll_set_timed_out_update(self, TIMED_OUT_STATE_IS_NOT_TIMED_OUT);
+ goto out_notify;
}
}
@@ -782,29 +877,24 @@ _ipv4ll_state_change(NML3IPv4LL *self, gboolean is_on_idle_handler)
_ipv4ll_addrgen(self, generate_new_addr);
acd_info = _ipv4ll_l3cfg_get_acd_addr_info(self, self->addr);
if (_acd_info_is_good(acd_info))
- goto out_is_good;
+ break;
generate_new_addr = TRUE;
}
-out_set_external_pladdr:
- self->addr = pladdr->address;
- _ipv4ll_set_state(self, NM_L3_IPV4LL_STATE_EXTERNAL);
- _l3cd_config_add(self);
- self->notify_on_idle = TRUE;
- goto out_notify;
-
-out_is_good:
nm_assert(_acd_info_is_good(acd_info));
switch (acd_info ? acd_info->state : NM_L3_ACD_ADDR_STATE_INIT) {
case NM_L3_ACD_ADDR_STATE_INIT:
case NM_L3_ACD_ADDR_STATE_PROBING:
new_state = NM_L3_IPV4LL_STATE_PROBING;
+ _ipv4ll_set_timed_out_update(self, TIMED_OUT_STATE_HAVE_TIMER_RUNNING);
goto out_is_good_1;
case NM_L3_ACD_ADDR_STATE_READY:
new_state = NM_L3_IPV4LL_STATE_READY;
+ _ipv4ll_set_timed_out_update(self, TIMED_OUT_STATE_HAVE_TIMER_RUNNING);
goto out_is_good_1;
case NM_L3_ACD_ADDR_STATE_DEFENDING:
new_state = NM_L3_IPV4LL_STATE_DEFENDING;
+ _ipv4ll_set_timed_out_update(self, TIMED_OUT_STATE_IS_NOT_TIMED_OUT);
goto out_is_good_1;
case NM_L3_ACD_ADDR_STATE_EXTERNAL_REMOVED:
case NM_L3_ACD_ADDR_STATE_USED:
@@ -823,17 +913,9 @@ out_is_good_1:
out_notify:
if (self->notify_on_idle) {
- if (is_on_idle_handler) {
- NML3ConfigNotifyData notify_data;
-
- self->notify_on_idle = FALSE;
-
- notify_data.notify_type = NM_L3_CONFIG_NOTIFY_TYPE_IPV4LL_EVENT;
- notify_data.ipv4ll_event = (typeof(notify_data.ipv4ll_event)){
- .ipv4ll = self,
- };
- _nm_l3cfg_emit_signal_notify(self->l3cfg, &notify_data);
- } else
+ if (is_on_idle_handler)
+ _ipv4ll_emit_signal_notify(self);
+ else
_ipv4ll_state_change_on_idle(self);
}
}
@@ -861,36 +943,9 @@ _ipv4ll_state_change_on_idle(NML3IPv4LL *self)
/*****************************************************************************/
-void
-nm_l3_ipv4ll_restart(NML3IPv4LL *self)
-{
- nm_assert(NM_IS_L3_IPV4LL(self));
-
- self->seed_reset_generation = TRUE;
- _ipv4ll_state_change(self, FALSE);
-}
-
-/*****************************************************************************/
-
static void
_l3cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NML3IPv4LL *self)
{
- if (notify_data->notify_type == NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE) {
- const NMPObject *obj = notify_data->platform_change.obj;
-
- /* we only process the link changes on the idle handler. That means, we may miss
- * events. If we saw the link down for a moment, remember it. Note that netlink
- * anyway can loose signals, so we might still miss to see the link down. This
- * is as good as we get it. */
- if (NMP_OBJECT_GET_TYPE(obj) == NMP_OBJECT_TYPE_LINK) {
- if (notify_data->platform_change.change_type == NM_PLATFORM_SIGNAL_REMOVED)
- self->link_seen_not_ready = TRUE;
- else if (!_plobj_link_is_ready(obj))
- self->link_seen_not_ready = TRUE;
- }
- return;
- }
-
if (notify_data->notify_type == NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE) {
/* NMl3Cfg only reloads the platform link during the idle handler. Pick it up now. */
_ipv4ll_update_link(self, nm_l3cfg_get_plobj(l3cfg, FALSE));
@@ -938,8 +993,6 @@ nm_l3_ipv4ll_new(NML3Cfg *l3cfg)
.notify_on_idle = TRUE,
.l3cfg_signal_notify_id =
g_signal_connect(l3cfg, NM_L3CFG_SIGNAL_NOTIFY, G_CALLBACK(_l3cfg_notify_cb), self),
- .last_good_at_msec = 0,
- .link_seen_not_ready = FALSE,
.seed_set = FALSE,
.seed_reset_generation = FALSE,
};
@@ -975,6 +1028,9 @@ nm_l3_ipv4ll_unref(NML3IPv4LL *self)
if (--self->ref_count > 0)
return;
+ if (nm_l3cfg_get_ipv4ll(self->l3cfg) == self)
+ _nm_l3cfg_unregister_ipv4ll(self->l3cfg);
+
_LOGT("finalize");
nm_assert(c_list_is_empty(&self->reg_lst_head));
@@ -992,6 +1048,7 @@ nm_l3_ipv4ll_unref(NML3IPv4LL *self)
nm_assert(!self->l3cfg_commit_handle);
nm_clear_g_source_inst(&self->state_change_on_idle_source);
+ nm_clear_g_source_inst(&self->timed_out_source);
nm_clear_g_signal_handler(self->l3cfg, &self->l3cfg_signal_notify_id);
diff --git a/src/nm-l3-ipv4ll.h b/src/nm-l3-ipv4ll.h
index 1d45b0c51a..4509f95c4f 100644
--- a/src/nm-l3-ipv4ll.h
+++ b/src/nm-l3-ipv4ll.h
@@ -19,6 +19,23 @@ typedef enum _nm_packed {
const char *nm_l3_ipv4ll_state_to_string(NML3IPv4LLState val, char *buf, gsize len);
+static inline gboolean
+nm_l3_ipv4ll_state_is_good(NML3IPv4LLState state)
+{
+ switch (state) {
+ case NM_L3_IPV4LL_STATE_UNKNOWN:
+ case NM_L3_IPV4LL_STATE_DISABLED:
+ case NM_L3_IPV4LL_STATE_WAIT_FOR_LINK:
+ case NM_L3_IPV4LL_STATE_PROBING:
+ return FALSE;
+ case NM_L3_IPV4LL_STATE_EXTERNAL:
+ case NM_L3_IPV4LL_STATE_READY:
+ case NM_L3_IPV4LL_STATE_DEFENDING:
+ return TRUE;
+ }
+ return nm_assert_unreachable_val(FALSE);
+}
+
/*****************************************************************************/
typedef struct _NML3IPv4LL NML3IPv4LL;
@@ -92,12 +109,10 @@ nm_l3_ipv4ll_register_get_instance(NML3IPv4LLRegistration *reg)
NML3IPv4LLState nm_l3_ipv4ll_get_state(NML3IPv4LL *self);
+gboolean nm_l3_ipv4ll_is_timed_out(NML3IPv4LL *self);
+
in_addr_t nm_l3_ipv4ll_get_addr(NML3IPv4LL *self);
const NML3ConfigData *nm_l3_ipv4ll_get_l3cd(NML3IPv4LL *self);
-/*****************************************************************************/
-
-void nm_l3_ipv4ll_restart(NML3IPv4LL *self);
-
#endif /* __NM_L3_IPV4LL_H__ */
diff --git a/src/nm-l3cfg.c b/src/nm-l3cfg.c
index c6ad7f100d..b45084bb7b 100644
--- a/src/nm-l3cfg.c
+++ b/src/nm-l3cfg.c
@@ -16,6 +16,8 @@
/*****************************************************************************/
+G_STATIC_ASSERT(NM_ACD_TIMEOUT_RFC5227_MSEC == N_ACD_TIMEOUT_RFC5227);
+
#define ACD_SUPPORTED_ETH_ALEN ETH_ALEN
#define ACD_ENSURE_RATELIMIT_MSEC ((guint32) 4000u)
#define ACD_WAIT_PROBING_EXTRA_TIME_MSEC ((guint32)(1000u + ACD_ENSURE_RATELIMIT_MSEC))
@@ -145,6 +147,8 @@ typedef struct _NML3CfgPrivate {
GArray *property_emit_list;
GArray *l3_config_datas;
+ NML3IPv4LL *ipv4ll;
+
const NML3ConfigData *combined_l3cd_merged;
const NML3ConfigData *combined_l3cd_commited;
@@ -3606,6 +3610,47 @@ nm_l3cfg_has_commited_ip6_addresses_pending_dad(NML3Cfg *self)
/*****************************************************************************/
+NML3IPv4LL *
+nm_l3cfg_get_ipv4ll(NML3Cfg *self)
+{
+ g_return_val_if_fail(NM_IS_L3CFG(self), NULL);
+
+ return self->priv.p->ipv4ll;
+}
+
+NML3IPv4LL *
+nm_l3cfg_access_ipv4ll(NML3Cfg *self)
+{
+ g_return_val_if_fail(NM_IS_L3CFG(self), NULL);
+
+ if (self->priv.p->ipv4ll)
+ return nm_l3_ipv4ll_ref(self->priv.p->ipv4ll);
+
+ /* We return the reference. But the NML3IPv4LL instance
+ * will call _nm_l3cfg_unregister_ipv4ll() when it gets
+ * destroyed.
+ *
+ * We don't have weak references, but NML3Cfg and NML3IPv4LL
+ * cooperate to handle this reference. */
+ self->priv.p->ipv4ll = nm_l3_ipv4ll_new(self);
+ return self->priv.p->ipv4ll;
+}
+
+void
+_nm_l3cfg_unregister_ipv4ll(NML3Cfg *self)
+{
+ nm_assert(NM_IS_L3CFG(self));
+
+ /* we don't own the refernce to "self->priv.p->ipv4ll", but
+ * when that instance gets destroyed, we get called back to
+ * forget about it. Basically, it's like a weak pointer. */
+
+ nm_assert(self->priv.p->ipv4ll);
+ self->priv.p->ipv4ll = NULL;
+}
+
+/*****************************************************************************/
+
static void
set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
{
@@ -3673,6 +3718,7 @@ finalize(GObject *object)
NML3Cfg *self = NM_L3CFG(object);
nm_assert(!self->priv.p->l3_config_datas);
+ nm_assert(!self->priv.p->ipv4ll);
nm_assert(c_list_is_empty(&self->priv.p->commit_type_lst_head));
diff --git a/src/nm-l3cfg.h b/src/nm-l3cfg.h
index d6aa1172a8..e83bdc9163 100644
--- a/src/nm-l3cfg.h
+++ b/src/nm-l3cfg.h
@@ -7,6 +7,7 @@
#include "nm-l3-config-data.h"
#define NM_L3CFG_CONFIG_PRIORITY_IPV4LL 0
+#define NM_ACD_TIMEOUT_RFC5227_MSEC 9000u
#define NM_TYPE_L3CFG (nm_l3cfg_get_type())
#define NM_L3CFG(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_L3CFG, NML3Cfg))
@@ -344,4 +345,12 @@ gboolean nm_l3cfg_has_commited_ip6_addresses_pending_dad(NML3Cfg *self);
/*****************************************************************************/
+struct _NML3IPv4LL *nm_l3cfg_get_ipv4ll(NML3Cfg *self);
+
+struct _NML3IPv4LL *nm_l3cfg_access_ipv4ll(NML3Cfg *self);
+
+void _nm_l3cfg_unregister_ipv4ll(NML3Cfg *self);
+
+/*****************************************************************************/
+
#endif /* __NM_L3CFG_H__ */
diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h
index df637fe03e..53bb7777c2 100644
--- a/src/platform/nm-platform.h
+++ b/src/platform/nm-platform.h
@@ -2086,7 +2086,7 @@ nm_platform_ip4_route_get_effective_metric(const NMPlatformIP4Route *r)
{
nm_assert(r);
- return r->metric_any ? nm_add_u32_clamped(NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP4, r->metric)
+ return r->metric_any ? nm_add_clamped_u32(NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP4, r->metric)
: r->metric;
}
@@ -2095,7 +2095,7 @@ nm_platform_ip6_route_get_effective_metric(const NMPlatformIP6Route *r)
{
nm_assert(r);
- return r->metric_any ? nm_add_u32_clamped(NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6, r->metric)
+ return r->metric_any ? nm_add_clamped_u32(NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6, r->metric)
: r->metric;
}