about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--debian/changelog2
-rw-r--r--debian/patches/13-dont-replace-kernel-default-route-for-IPv6.patch120
-rw-r--r--debian/patches/series1
3 files changed, 123 insertions, 0 deletions
diff --git a/debian/changelog b/debian/changelog
index 9cc8ecaf..2b0f099a 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -7,6 +7,8 @@ network-manager (0.9.4.0-4) UNRELEASED; urgency=low
   * debian/network-manager.maintscript: Use new versioning scheme as
     recommended by dpkg-maintscript-helper which better handles local
     modifications and (bin)NMUs.
+  * debian/patches/13-dont-replace-kernel-default-route-for-IPv6.patch: Don't
+    fight with the kernel over the default IPv6 route. (Closes: #670818)
 
  -- Michael Biebl <biebl@debian.org>  Tue, 15 May 2012 01:46:40 +0200
 
diff --git a/debian/patches/13-dont-replace-kernel-default-route-for-IPv6.patch b/debian/patches/13-dont-replace-kernel-default-route-for-IPv6.patch
new file mode 100644
index 00000000..552976c2
--- /dev/null
+++ b/debian/patches/13-dont-replace-kernel-default-route-for-IPv6.patch
@@ -0,0 +1,120 @@
+commit 77de91e5a8b1c1993ae65c54b37e0411e78e6fe6
+Author: Dan Winship <danw@gnome.org>
+Date:   Thu Apr 19 14:27:12 2012 -0400
+
+    core: don't fight with the kernel over the default IPv6 route
+    
+    The kernel wants there to be a default route over every RA-ed IPv6
+    interface, and it gets confused and annoyed if we remove that default
+    route and replace it with our own (causing it to effectively drop all
+    further RAs on the floor, which is particularly bad if some of the
+    information in the earlier RA had an expiration time).
+    
+    So, rather than replacing the kernel's default route(s), just add an
+    additional one of our own, with a lower (ie, higher priority) metric.
+    
+    https://bugzilla.redhat.com/show_bug.cgi?id=785772
+
+diff --git a/src/nm-system.c b/src/nm-system.c
+index 91153ec..4cebb13 100644
+--- a/src/nm-system.c
++++ b/src/nm-system.c
+@@ -1023,7 +1023,7 @@ add_ip6_route_to_gateway (int ifindex, const struct in6_addr *gw)
+ }
+ 
+ static int
+-replace_default_ip6_route (int ifindex, const struct in6_addr *gw)
++add_default_ip6_route (int ifindex, const struct in6_addr *gw)
+ {
+ 	struct rtnl_route *route = NULL;
+ 	struct nl_sock *nlh;
+@@ -1037,22 +1037,36 @@ replace_default_ip6_route (int ifindex, const struct in6_addr *gw)
+ 	route = nm_netlink_route_new (ifindex, AF_INET6, 0,
+ 	                              NMNL_PROP_SCOPE, RT_SCOPE_UNIVERSE,
+ 	                              NMNL_PROP_TABLE, RT_TABLE_MAIN,
++	                              NMNL_PROP_PRIO, 1,
+ 	                              NULL);
+ 	g_return_val_if_fail (route != NULL, -ENOMEM);
+ 
+ 	/* Add the new default route */
+-	err = nm_netlink_route6_add (route, &in6addr_any, 0, gw, NLM_F_REPLACE);
+-	if (err == -NLE_EXIST) {
+-		/* FIXME: even though we use NLM_F_REPLACE the kernel won't replace
+-		 * the route if it's the same.  Suppress the pointless error.
+-		 */
++	err = nm_netlink_route6_add (route, &in6addr_any, 0, gw, NLM_F_CREATE);
++	if (err == -NLE_EXIST)
+ 		err = 0;
+-	}
+ 
+ 	rtnl_route_put (route);
+ 	return err;
+ }
+ 
++static struct rtnl_route *
++find_static_default_routes (struct rtnl_route *route,
++                            struct nl_addr *dst,
++                            const char *iface,
++                            gpointer user_data)
++{
++	GList **def_routes = user_data;
++
++	if (   nl_addr_get_prefixlen (dst) == 0
++	    && rtnl_route_get_protocol (route) == RTPROT_STATIC) {
++		rtnl_route_get (route);
++		*def_routes = g_list_prepend (*def_routes, route);
++	}
++
++	return NULL;
++}
++
+ /*
+  * nm_system_replace_default_ip6_route
+  *
+@@ -1062,12 +1076,35 @@ replace_default_ip6_route (int ifindex, const struct in6_addr *gw)
+ gboolean
+ nm_system_replace_default_ip6_route (int ifindex, const struct in6_addr *gw)
+ {
+-	struct rtnl_route *gw_route = NULL;
++	GList *def_routes, *iter;
++	struct rtnl_route *route, *gw_route = NULL;
+ 	gboolean success = FALSE;
+ 	char *iface;
+ 	int err;
+ 
+-	err = replace_default_ip6_route (ifindex, gw);
++	/* We can't just use NLM_F_REPLACE here like in the IPv4 case, because
++	 * the kernel doesn't like it if we replace the default routes it
++	 * creates. (See rh#785772.) So we delete any non-kernel default routes,
++	 * and then add a new default route of our own with a lower metric than
++	 * the kernel ones.
++	 */
++	def_routes = NULL;
++	nm_netlink_foreach_route (ifindex, AF_INET6, RT_SCOPE_UNIVERSE, TRUE,
++	                          find_static_default_routes, &def_routes);
++	for (iter = def_routes; iter; iter = iter->next) {
++		route = iter->data;
++		if (!nm_netlink_route_delete (route)) {
++			iface = nm_netlink_index_to_iface (ifindex);
++			nm_log_err (LOGD_DEVICE | LOGD_IP6,
++			            "(%s): failed to delete existing IPv6 default route",
++			            iface);
++			g_free (iface);
++		}
++		rtnl_route_put (route);
++	}
++	g_list_free (def_routes);
++
++	err = add_default_ip6_route (ifindex, gw);
+ 	if (err == 0)
+ 		return TRUE;
+ 
+@@ -1091,7 +1128,7 @@ nm_system_replace_default_ip6_route (int ifindex, const struct in6_addr *gw)
+ 		goto out;
+ 
+ 	/* Try adding the original route again */
+-	err = replace_default_ip6_route (ifindex, gw);
++	err = add_default_ip6_route (ifindex, gw);
+ 	if (err != 0) {
+ 		nm_netlink_route_delete (gw_route);
+ 		nm_log_err (LOGD_DEVICE | LOGD_IP6,
diff --git a/debian/patches/series b/debian/patches/series
index d9c8f38d..0db45e84 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -4,3 +4,4 @@
 10-format-security.patch
 11-initialize-nm-remote-settings.patch
 12-initialize-gerror.patch
+13-dont-replace-kernel-default-route-for-IPv6.patch