Merge ~alfonsosanchezbeato/snappy-hwe-snaps/+git/network-manager:fix-duplicated-conns into ~snappy-hwe-team/snappy-hwe-snaps/+git/network-manager:network-manager/xenial/1.2.2

Proposed by Alfonso Sanchez-Beato
Status: Merged
Approved by: Konrad Zapałowicz
Approved revision: c13396f08566e69e785ae24b5f63bde0f534d4eb
Merged at revision: 37cdd7f22c17dcc5be259c89e5ef59222a4854a6
Proposed branch: ~alfonsosanchezbeato/snappy-hwe-snaps/+git/network-manager:fix-duplicated-conns
Merge into: ~snappy-hwe-team/snappy-hwe-snaps/+git/network-manager:network-manager/xenial/1.2.2
Diff against target: 239 lines (+103/-42)
4 files modified
src/NetworkManagerUtils.c (+80/-24)
src/nm-core-utils.c (+21/-0)
src/nm-core-utils.h (+1/-0)
src/platform/nm-linux-platform.c (+1/-18)
Reviewer Review Type Date Requested Status
Konrad Zapałowicz (community) code Approve
System Enablement Bot continuous-integration Approve
Review via email: mp+361687@code.launchpad.net

Commit message

Set of patches to prevent duplicated addresses when NM re-starts. Fixes LP: #1811347

Description of the change

Set of patches to prevent duplicated addresses when NM re-starts. Fixes LP: #1811347

To post a comment you must log in.
Revision history for this message
System Enablement Bot (system-enablement-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
System Enablement Bot (system-enablement-ci-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Konrad Zapałowicz (kzapalowicz) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c
2index 09ed25c..d0e2a5c 100644
3--- a/src/NetworkManagerUtils.c
4+++ b/src/NetworkManagerUtils.c
5@@ -341,18 +341,19 @@ static int
6 route_compare (NMIPRoute *route1, NMIPRoute *route2, gint64 default_metric)
7 {
8 gint64 r, metric1, metric2;
9+ int family;
10+ guint plen;
11+ NMIPAddr a1 = { 0 }, a2 = { 0 };
12
13- r = g_strcmp0 (nm_ip_route_get_dest (route1), nm_ip_route_get_dest (route2));
14- if (r)
15- return r;
16-
17- r = nm_ip_route_get_prefix (route1) - nm_ip_route_get_prefix (route2);
18+ family = nm_ip_route_get_family (route1);
19+ r = family - nm_ip_route_get_family (route2);
20 if (r)
21 return r > 0 ? 1 : -1;
22
23- r = g_strcmp0 (nm_ip_route_get_next_hop (route1), nm_ip_route_get_next_hop (route2));
24+ plen = nm_ip_route_get_prefix (route1);
25+ r = plen - nm_ip_route_get_prefix (route2);
26 if (r)
27- return r;
28+ return r > 0 ? 1 : -1;
29
30 metric1 = nm_ip_route_get_metric (route1) == -1 ? default_metric : nm_ip_route_get_metric (route1);
31 metric2 = nm_ip_route_get_metric (route2) == -1 ? default_metric : nm_ip_route_get_metric (route2);
32@@ -361,17 +362,36 @@ route_compare (NMIPRoute *route1, NMIPRoute *route2, gint64 default_metric)
33 if (r)
34 return r > 0 ? 1 : -1;
35
36- r = nm_ip_route_get_family (route1) - nm_ip_route_get_family (route2);
37+ r = g_strcmp0 (nm_ip_route_get_next_hop (route1), nm_ip_route_get_next_hop (route2));
38 if (r)
39- return r > 0 ? 1 : -1;
40+ return r;
41+
42+ /* NMIPRoute validates family and dest. inet_pton() is not expected to fail. */
43+ inet_pton (family, nm_ip_route_get_dest (route1), &a1);
44+ inet_pton (family, nm_ip_route_get_dest (route2), &a2);
45+ nm_utils_ipx_address_clear_host_address (family, &a1, &a1, plen);
46+ nm_utils_ipx_address_clear_host_address (family, &a2, &a2, plen);
47+ r = memcmp (&a1, &a2, sizeof (a1));
48+ if (r)
49+ return r;
50
51 return 0;
52 }
53
54 static int
55-route_ptr_compare (const void *a, const void *b)
56+route_ptr_compare (const void *a, const void *b, gpointer metric)
57 {
58- return route_compare (*(NMIPRoute **) a, *(NMIPRoute **) b, -1);
59+ return route_compare (*(NMIPRoute **) a, *(NMIPRoute **) b, *((gint64 *) metric));
60+}
61+
62+static gboolean
63+route_is_v6_multicast (NMIPRoute *route)
64+{
65+ if (nm_ip_route_get_prefix (route) == 8 &&
66+ g_strcmp0 (nm_ip_route_get_dest (route), "ff00::") == 0)
67+ return TRUE;
68+
69+ return FALSE;
70 }
71
72 static gboolean
73@@ -381,11 +401,14 @@ check_ip_routes (NMConnection *orig,
74 gint64 default_metric,
75 gboolean v4)
76 {
77- gs_free NMIPRoute **routes1 = NULL, **routes2 = NULL;
78+ gs_free NMIPRoute **routes1 = NULL;
79+ NMIPRoute **routes2;
80 NMSettingIPConfig *s_ip1, *s_ip2;
81+ gint64 m;
82 const char *s_name;
83 GHashTable *props;
84- guint i, num;
85+ guint i, i1, i2, num1, num2;
86+ const guint8 PLEN = v4 ? 32 : 128;
87
88 s_name = v4 ? NM_SETTING_IP4_CONFIG_SETTING_NAME :
89 NM_SETTING_IP6_CONFIG_SETTING_NAME;
90@@ -402,24 +425,57 @@ check_ip_routes (NMConnection *orig,
91 if (!s_ip1 || !s_ip2)
92 return FALSE;
93
94- num = nm_setting_ip_config_get_num_routes (s_ip1);
95- if (num != nm_setting_ip_config_get_num_routes (s_ip2))
96- return FALSE;
97+ num1 = nm_setting_ip_config_get_num_routes (s_ip1);
98+ num2 = nm_setting_ip_config_get_num_routes (s_ip2);
99
100- routes1 = g_new (NMIPRoute *, num);
101- routes2 = g_new (NMIPRoute *, num);
102+ routes1 = g_new (NMIPRoute *, (gsize) num1 + num2);
103+ routes2 = &routes1[num1];
104
105- for (i = 0; i < num; i++) {
106+ for (i = 0; i < num1; i++)
107 routes1[i] = nm_setting_ip_config_get_route (s_ip1, i);
108+ for (i = 0; i < num2; i++)
109 routes2[i] = nm_setting_ip_config_get_route (s_ip2, i);
110- }
111
112- qsort (routes1, num, sizeof (NMIPRoute *), route_ptr_compare);
113- qsort (routes2, num, sizeof (NMIPRoute *), route_ptr_compare);
114+ m = nm_setting_ip_config_get_route_metric (s_ip2);
115+ if (m != -1)
116+ default_metric = m;
117
118- for (i = 0; i < num; i++) {
119- if (route_compare (routes1[i], routes2[i], default_metric))
120+ g_qsort_with_data (routes1, num1, sizeof (NMIPRoute *), route_ptr_compare, &default_metric);
121+ g_qsort_with_data (routes2, num2, sizeof (NMIPRoute *), route_ptr_compare, &default_metric);
122+
123+ for (i1 = 0, i2 = 0; i2 < num2; i1++) {
124+ if (i1 >= num1)
125 return FALSE;
126+ if (route_compare (routes1[i1], routes2[i2], default_metric) == 0) {
127+ i2++;
128+ continue;
129+ }
130+
131+ /* if @orig (@routes1) contains /32 routes that are missing in @candidate,
132+ * we accept that.
133+ *
134+ * A /32 may have been added automatically, as a direct-route to the gateway.
135+ * The generated connection (@orig) would contain that route, so we shall ignore
136+ * it.
137+ *
138+ * Likeweise for /128 for IPv6. */
139+ if (nm_ip_route_get_prefix (routes1[i1]) == PLEN)
140+ continue;
141+ /* We also ignore IPv6 default multicast route, that sometimes happen to be there */
142+ if (!v4 && route_is_v6_multicast (routes1[i1]))
143+ continue;
144+
145+ return FALSE;
146+ }
147+
148+ /* check that @orig has no left-over (except host routes that we ignore). */
149+ for (; i1 < num1; i1++) {
150+ if (nm_ip_route_get_prefix (routes1[i1]) == PLEN)
151+ continue;
152+ if (!v4 && route_is_v6_multicast (routes1[i1]))
153+ continue;
154+
155+ return FALSE;
156 }
157
158 remove_from_hash (settings, props, s_name, NM_SETTING_IP_CONFIG_ROUTES);
159diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c
160index aea80da..9701e48 100644
161--- a/src/nm-core-utils.c
162+++ b/src/nm-core-utils.c
163@@ -200,6 +200,27 @@ nm_ethernet_address_is_valid (gconstpointer addr, gssize len)
164 return TRUE;
165 }
166
167+gconstpointer
168+nm_utils_ipx_address_clear_host_address (int family, gpointer dst, gconstpointer src, guint8 plen)
169+{
170+ g_return_val_if_fail (src, NULL);
171+ g_return_val_if_fail (dst, NULL);
172+
173+ switch (family) {
174+ case AF_INET:
175+ g_return_val_if_fail (plen <= 32, NULL);
176+ *((guint32 *) dst) = nm_utils_ip4_address_clear_host_address (*((guint32 *) src), plen);
177+ break;
178+ case AF_INET6:
179+ g_return_val_if_fail (plen <= 128, NULL);
180+ nm_utils_ip6_address_clear_host_address (dst, src, plen);
181+ break;
182+ default:
183+ g_return_val_if_reached (NULL);
184+ }
185+ return dst;
186+}
187+
188 /* nm_utils_ip4_address_clear_host_address:
189 * @addr: source ip6 address
190 * @plen: prefix length of network
191diff --git a/src/nm-core-utils.h b/src/nm-core-utils.h
192index a55fb66..180b9df 100644
193--- a/src/nm-core-utils.h
194+++ b/src/nm-core-utils.h
195@@ -93,6 +93,7 @@ GETTER (void) \
196
197 gboolean nm_ethernet_address_is_valid (gconstpointer addr, gssize len);
198
199+gconstpointer nm_utils_ipx_address_clear_host_address (int family, gpointer dst, gconstpointer src, guint8 plen);
200 in_addr_t nm_utils_ip4_address_clear_host_address (in_addr_t addr, guint8 plen);
201 const struct in6_addr *nm_utils_ip6_address_clear_host_address (struct in6_addr *dst, const struct in6_addr *src, guint8 plen);
202 gboolean nm_utils_ip6_address_same_prefix (const struct in6_addr *addr_a, const struct in6_addr *addr_b, guint8 plen);
203diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
204index bbc3659..eade769 100644
205--- a/src/platform/nm-linux-platform.c
206+++ b/src/platform/nm-linux-platform.c
207@@ -303,23 +303,6 @@ _support_user_ipv6ll_detect (struct nlattr **tb)
208 * Various utilities
209 ******************************************************************/
210
211-static void
212-clear_host_address (int family, const void *network, guint8 plen, void *dst)
213-{
214- g_return_if_fail (network);
215-
216- switch (family) {
217- case AF_INET:
218- *((in_addr_t *) dst) = nm_utils_ip4_address_clear_host_address (*((in_addr_t *) network), plen);
219- break;
220- case AF_INET6:
221- nm_utils_ip6_address_clear_host_address ((struct in6_addr *) dst, (const struct in6_addr *) network, plen);
222- break;
223- default:
224- g_assert_not_reached ();
225- }
226-}
227-
228 static int
229 _vlan_qos_mapping_cmp_from (gconstpointer a, gconstpointer b, gpointer user_data)
230 {
231@@ -2273,7 +2256,7 @@ _nl_msg_new_route (int nlmsg_type,
232
233 addr_len = family == AF_INET ? sizeof (in_addr_t) : sizeof (struct in6_addr);
234
235- clear_host_address (family, network, plen, &network_clean);
236+ nm_utils_ipx_address_clear_host_address (family, &network_clean, network, plen);
237 NLA_PUT (msg, RTA_DST, addr_len, &network_clean);
238
239 NLA_PUT_U32 (msg, RTA_PRIORITY, metric);

Subscribers

People subscribed via source and target branches