From: Roy Marples Date: Mon, 8 Sep 2008 11:30:31 +0000 (+0000) Subject: On Linux, fix replacing the kernel added subnet route correctly for metrics. X-Git-Tag: v5.0.0~275 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cf7a295fa370022c78bf971667e61f69450104a4;p=thirdparty%2Fdhcpcd.git On Linux, fix replacing the kernel added subnet route correctly for metrics. --- diff --git a/configure.c b/configure.c index 07502eff..a4c206b7 100644 --- a/configure.c +++ b/configure.c @@ -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) diff --git a/if-linux.c b/if-linux.c index bece58cc..1353d7e6 100644 --- a/if-linux.c +++ b/if-linux.c @@ -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 0629302a..87d0d4c8 100644 --- 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 *);