diff options
author | Thomas Haller <thaller@redhat.com> | 2020-10-28 12:10:40 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2020-10-28 12:10:40 +0100 |
commit | 817ea086eeaa4b739a46624cd037999d4ec920cc (patch) | |
tree | 17f96029a86f981ca5430ff86a6acd0fc684d0f3 | |
parent | 1cda792206ae4ea72fd3ecd891f665933565adc7 (diff) | |
parent | 33041e04afe195e40d49a748df1ed56e6f0d523d (diff) | |
download | NetworkManager-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.h | 22 | ||||
-rw-r--r-- | src/NetworkManagerUtils.c | 200 | ||||
-rw-r--r-- | src/NetworkManagerUtils.h | 27 | ||||
-rw-r--r-- | src/devices/nm-device.c | 98 | ||||
-rw-r--r-- | src/nm-act-request.c | 120 | ||||
-rw-r--r-- | src/nm-act-request.h | 10 | ||||
-rw-r--r-- | src/nm-l3-config-data.c | 2 | ||||
-rw-r--r-- | src/nm-l3-ipv4ll.c | 197 | ||||
-rw-r--r-- | src/nm-l3-ipv4ll.h | 23 | ||||
-rw-r--r-- | src/nm-l3cfg.c | 46 | ||||
-rw-r--r-- | src/nm-l3cfg.h | 9 | ||||
-rw-r--r-- | src/platform/nm-platform.h | 4 |
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, ¬ify_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, ¬ify_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; } |