]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
On Linux, fix replacing the kernel added subnet route correctly for metrics.
authorRoy Marples <roy@marples.name>
Mon, 8 Sep 2008 11:30:31 +0000 (11:30 +0000)
committerRoy Marples <roy@marples.name>
Mon, 8 Sep 2008 11:30:31 +0000 (11:30 +0000)
configure.c
if-linux.c
net.h

index 07502eff33175573f34ec283fffd94ceaee81c6b..a4c206b784e77aff0674019ec4a2a53ce0213308 100644 (file)
@@ -301,6 +301,7 @@ static int
 delete_address(struct interface *iface)
 {
        int retval;
+
        syslog(LOG_DEBUG, "%s: deleting IP address %s/%d",
               iface->name,
               inet_ntoa(iface->addr),
@@ -323,7 +324,6 @@ configure(struct interface *iface, const char *reason)
 #ifdef __linux__
        struct in_addr dest;
        struct in_addr gate;
-       struct rt *rt = NULL;
 #endif
 
        /* Grab our IP config */
@@ -336,6 +336,10 @@ configure(struct interface *iface, const char *reason)
                        net.s_addr = get_netmask(addr.s_addr);
                if (get_option_addr(&brd.s_addr, dhcp, DHO_BROADCAST) == -1)
                        brd.s_addr = addr.s_addr | ~net.s_addr;
+#ifdef __linux__
+               dest.s_addr = addr.s_addr & net.s_addr;
+               gate.s_addr = 0;
+#endif
        } else {
                /* Only reset things if we had set them before */
                if (iface->addr.s_addr != 0) {
@@ -367,31 +371,20 @@ configure(struct interface *iface, const char *reason)
 
 #ifdef __linux__
        /* On linux, we need to change the subnet route to have our metric. */
-       if (iface->addr.s_addr != iface->state->lease.addr.s_addr &&
-           iface->metric > 0 &&
-           net.s_addr != INADDR_BROADCAST)
+       if (iface->metric > 0 && 
+           (net.s_addr != iface->net.s_addr ||
+            dest.s_addr != (iface->addr.s_addr & iface->net.s_addr)))
        {
-               dest.s_addr = addr.s_addr & net.s_addr;
-               gate.s_addr = 0;
-               add_route(iface, &dest, &net, &gate, iface->metric);
+               iface->addr.s_addr = addr.s_addr;
+               iface->net.s_addr = net.s_addr;
+               change_route(iface, &dest, &net, &gate, iface->metric);
                del_route(iface, &dest, &net, &gate, 0);
-               rt = xmalloc(sizeof(*rt));
-               rt->dest.s_addr = dest.s_addr;
-               rt->net.s_addr = net.s_addr;
-               rt->gate.s_addr = gate.s_addr;
        }
 #endif
 
-       configure_routes(iface, dhcp);
        iface->addr.s_addr = addr.s_addr;
        iface->net.s_addr = net.s_addr;
-
-#ifdef __linux__
-       if (rt) {
-               rt->next = iface->routes;
-               iface->routes = rt;
-       }
-#endif
+       configure_routes(iface, dhcp);
 
        if (!iface->state->lease.frominfo)
                if (write_lease(iface, dhcp) == -1)
index bece58cc073e6c6d00071e02d7332fcc16bea383..1353d7e6857aed81994396300e3dacd11be80363 100644 (file)
@@ -351,7 +351,7 @@ if_route(const struct interface *iface,
        nlm->hdr.nlmsg_type = RTM_NEWROUTE;
        if (action == 0)
                nlm->hdr.nlmsg_flags = NLM_F_REPLACE;
-       else if (action > 0)
+       else if (action  == 1)
                nlm->hdr.nlmsg_flags = NLM_F_CREATE | NLM_F_EXCL;
        else
                nlm->hdr.nlmsg_type = RTM_DELROUTE;
@@ -359,11 +359,12 @@ if_route(const struct interface *iface,
        nlm->rt.rtm_family = AF_INET;
        nlm->rt.rtm_table = RT_TABLE_MAIN;
 
-       if (action < 0)
+       if (action == -1 || action == -2)
                nlm->rt.rtm_scope = RT_SCOPE_NOWHERE;
        else {
                nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
-               nlm->rt.rtm_protocol = RTPROT_BOOT;
+               /* We only change route metrics for kernel routes */
+               nlm->rt.rtm_protocol = action ? RTPROT_BOOT : RTPROT_KERNEL;
                if (gateway->s_addr == INADDR_ANY)
                        nlm->rt.rtm_scope = RT_SCOPE_LINK;
                else
@@ -374,6 +375,10 @@ if_route(const struct interface *iface,
        nlm->rt.rtm_dst_len = inet_ntocidr(*netmask);
        add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_DST,
                   &destination->s_addr, sizeof(destination->s_addr));
+       if (action != 1) {
+               add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_PREFSRC,
+                          &iface->addr.s_addr, sizeof(iface->addr.s_addr));
+       }
        add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_GATEWAY,
                   &gateway->s_addr, sizeof(gateway->s_addr));
 
diff --git a/net.h b/net.h
index 0629302a4b482b5ab30ef85f3d0c76dde1ba0ec7..87d0d4c8bb0c243515ec67ede497971353a8761c 100644 (file)
--- a/net.h
+++ b/net.h
@@ -132,6 +132,8 @@ int if_route(const struct interface *, const struct in_addr *,
        if_route(iface, dest, mask, gate, metric, 0)
 #define del_route(iface, dest, mask, gate, metric) \
        if_route(iface, dest, mask, gate, metric, -1)
+#define del_src_route(iface, dest, mask, gate, metric) \
+       if_route(iface, dest, mask, gate, metric, -2)
 void free_routes(struct rt *);
 
 int open_udp_socket(struct interface *);