| 1 |
tetromino |
1.1 |
From 77de91e5a8b1c1993ae65c54b37e0411e78e6fe6 Mon Sep 17 00:00:00 2001
|
| 2 |
|
|
From: Dan Winship <danw@gnome.org>
|
| 3 |
|
|
Date: Thu, 19 Apr 2012 14:27:12 -0400
|
| 4 |
|
|
Subject: [PATCH] core: don't fight with the kernel over the default IPv6
|
| 5 |
|
|
route
|
| 6 |
|
|
|
| 7 |
|
|
The kernel wants there to be a default route over every RA-ed IPv6
|
| 8 |
|
|
interface, and it gets confused and annoyed if we remove that default
|
| 9 |
|
|
route and replace it with our own (causing it to effectively drop all
|
| 10 |
|
|
further RAs on the floor, which is particularly bad if some of the
|
| 11 |
|
|
information in the earlier RA had an expiration time).
|
| 12 |
|
|
|
| 13 |
|
|
So, rather than replacing the kernel's default route(s), just add an
|
| 14 |
|
|
additional one of our own, with a lower (ie, higher priority) metric.
|
| 15 |
|
|
|
| 16 |
|
|
https://bugzilla.redhat.com/show_bug.cgi?id=785772
|
| 17 |
|
|
---
|
| 18 |
|
|
src/nm-system.c | 57 +++++++++++++++++++++++++++++++++++++++++++++---------
|
| 19 |
|
|
1 files changed, 47 insertions(+), 10 deletions(-)
|
| 20 |
|
|
|
| 21 |
|
|
diff --git a/src/nm-system.c b/src/nm-system.c
|
| 22 |
|
|
index 91153ec..4cebb13 100644
|
| 23 |
|
|
--- a/src/nm-system.c
|
| 24 |
|
|
+++ b/src/nm-system.c
|
| 25 |
|
|
@@ -1023,7 +1023,7 @@ add_ip6_route_to_gateway (int ifindex, const struct in6_addr *gw)
|
| 26 |
|
|
}
|
| 27 |
|
|
|
| 28 |
|
|
static int
|
| 29 |
|
|
-replace_default_ip6_route (int ifindex, const struct in6_addr *gw)
|
| 30 |
|
|
+add_default_ip6_route (int ifindex, const struct in6_addr *gw)
|
| 31 |
|
|
{
|
| 32 |
|
|
struct rtnl_route *route = NULL;
|
| 33 |
|
|
struct nl_sock *nlh;
|
| 34 |
|
|
@@ -1037,22 +1037,36 @@ replace_default_ip6_route (int ifindex, const struct in6_addr *gw)
|
| 35 |
|
|
route = nm_netlink_route_new (ifindex, AF_INET6, 0,
|
| 36 |
|
|
NMNL_PROP_SCOPE, RT_SCOPE_UNIVERSE,
|
| 37 |
|
|
NMNL_PROP_TABLE, RT_TABLE_MAIN,
|
| 38 |
|
|
+ NMNL_PROP_PRIO, 1,
|
| 39 |
|
|
NULL);
|
| 40 |
|
|
g_return_val_if_fail (route != NULL, -ENOMEM);
|
| 41 |
|
|
|
| 42 |
|
|
/* Add the new default route */
|
| 43 |
|
|
- err = nm_netlink_route6_add (route, &in6addr_any, 0, gw, NLM_F_REPLACE);
|
| 44 |
|
|
- if (err == -NLE_EXIST) {
|
| 45 |
|
|
- /* FIXME: even though we use NLM_F_REPLACE the kernel won't replace
|
| 46 |
|
|
- * the route if it's the same. Suppress the pointless error.
|
| 47 |
|
|
- */
|
| 48 |
|
|
+ err = nm_netlink_route6_add (route, &in6addr_any, 0, gw, NLM_F_CREATE);
|
| 49 |
|
|
+ if (err == -NLE_EXIST)
|
| 50 |
|
|
err = 0;
|
| 51 |
|
|
- }
|
| 52 |
|
|
|
| 53 |
|
|
rtnl_route_put (route);
|
| 54 |
|
|
return err;
|
| 55 |
|
|
}
|
| 56 |
|
|
|
| 57 |
|
|
+static struct rtnl_route *
|
| 58 |
|
|
+find_static_default_routes (struct rtnl_route *route,
|
| 59 |
|
|
+ struct nl_addr *dst,
|
| 60 |
|
|
+ const char *iface,
|
| 61 |
|
|
+ gpointer user_data)
|
| 62 |
|
|
+{
|
| 63 |
|
|
+ GList **def_routes = user_data;
|
| 64 |
|
|
+
|
| 65 |
|
|
+ if ( nl_addr_get_prefixlen (dst) == 0
|
| 66 |
|
|
+ && rtnl_route_get_protocol (route) == RTPROT_STATIC) {
|
| 67 |
|
|
+ rtnl_route_get (route);
|
| 68 |
|
|
+ *def_routes = g_list_prepend (*def_routes, route);
|
| 69 |
|
|
+ }
|
| 70 |
|
|
+
|
| 71 |
|
|
+ return NULL;
|
| 72 |
|
|
+}
|
| 73 |
|
|
+
|
| 74 |
|
|
/*
|
| 75 |
|
|
* nm_system_replace_default_ip6_route
|
| 76 |
|
|
*
|
| 77 |
|
|
@@ -1062,12 +1076,35 @@ replace_default_ip6_route (int ifindex, const struct in6_addr *gw)
|
| 78 |
|
|
gboolean
|
| 79 |
|
|
nm_system_replace_default_ip6_route (int ifindex, const struct in6_addr *gw)
|
| 80 |
|
|
{
|
| 81 |
|
|
- struct rtnl_route *gw_route = NULL;
|
| 82 |
|
|
+ GList *def_routes, *iter;
|
| 83 |
|
|
+ struct rtnl_route *route, *gw_route = NULL;
|
| 84 |
|
|
gboolean success = FALSE;
|
| 85 |
|
|
char *iface;
|
| 86 |
|
|
int err;
|
| 87 |
|
|
|
| 88 |
|
|
- err = replace_default_ip6_route (ifindex, gw);
|
| 89 |
|
|
+ /* We can't just use NLM_F_REPLACE here like in the IPv4 case, because
|
| 90 |
|
|
+ * the kernel doesn't like it if we replace the default routes it
|
| 91 |
|
|
+ * creates. (See rh#785772.) So we delete any non-kernel default routes,
|
| 92 |
|
|
+ * and then add a new default route of our own with a lower metric than
|
| 93 |
|
|
+ * the kernel ones.
|
| 94 |
|
|
+ */
|
| 95 |
|
|
+ def_routes = NULL;
|
| 96 |
|
|
+ nm_netlink_foreach_route (ifindex, AF_INET6, RT_SCOPE_UNIVERSE, TRUE,
|
| 97 |
|
|
+ find_static_default_routes, &def_routes);
|
| 98 |
|
|
+ for (iter = def_routes; iter; iter = iter->next) {
|
| 99 |
|
|
+ route = iter->data;
|
| 100 |
|
|
+ if (!nm_netlink_route_delete (route)) {
|
| 101 |
|
|
+ iface = nm_netlink_index_to_iface (ifindex);
|
| 102 |
|
|
+ nm_log_err (LOGD_DEVICE | LOGD_IP6,
|
| 103 |
|
|
+ "(%s): failed to delete existing IPv6 default route",
|
| 104 |
|
|
+ iface);
|
| 105 |
|
|
+ g_free (iface);
|
| 106 |
|
|
+ }
|
| 107 |
|
|
+ rtnl_route_put (route);
|
| 108 |
|
|
+ }
|
| 109 |
|
|
+ g_list_free (def_routes);
|
| 110 |
|
|
+
|
| 111 |
|
|
+ err = add_default_ip6_route (ifindex, gw);
|
| 112 |
|
|
if (err == 0)
|
| 113 |
|
|
return TRUE;
|
| 114 |
|
|
|
| 115 |
|
|
@@ -1091,7 +1128,7 @@ nm_system_replace_default_ip6_route (int ifindex, const struct in6_addr *gw)
|
| 116 |
|
|
goto out;
|
| 117 |
|
|
|
| 118 |
|
|
/* Try adding the original route again */
|
| 119 |
|
|
- err = replace_default_ip6_route (ifindex, gw);
|
| 120 |
|
|
+ err = add_default_ip6_route (ifindex, gw);
|
| 121 |
|
|
if (err != 0) {
|
| 122 |
|
|
nm_netlink_route_delete (gw_route);
|
| 123 |
|
|
nm_log_err (LOGD_DEVICE | LOGD_IP6,
|
| 124 |
|
|
--
|
| 125 |
|
|
1.7.8.6
|
| 126 |
|
|
|