summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorpauljensen@chromium.org <pauljensen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-01-23 18:12:20 +0000
committerpauljensen@chromium.org <pauljensen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-01-23 18:12:20 +0000
commitfb5dead7e644df782b1e63e97fa532940d1cc7bb (patch)
tree333192f875355251820a0ca074b24a31768d786d /net
parent4d89a9279940415b80c79f51beb3394f7e991560 (diff)
downloadchromium_src-fb5dead7e644df782b1e63e97fa532940d1cc7bb.zip
chromium_src-fb5dead7e644df782b1e63e97fa532940d1cc7bb.tar.gz
chromium_src-fb5dead7e644df782b1e63e97fa532940d1cc7bb.tar.bz2
Work around linux kernel bug by interpreting IPv6 "Preferred Lifetimes" of 0 as implying the address is deprecated. This avoids spurious network changed signals on linux by ignoring more duplicate messages by canonicalizing them before matching them.
BUG=268042 TEST=net_unittests --gtest_filter=AddressTrackerLinuxTest.DeprecatedLifetime Review URL: https://codereview.chromium.org/109213004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@246641 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r--net/base/address_tracker_linux.cc34
-rw-r--r--net/base/address_tracker_linux.h2
-rw-r--r--net/base/address_tracker_linux_unittest.cc75
3 files changed, 95 insertions, 16 deletions
diff --git a/net/base/address_tracker_linux.cc b/net/base/address_tracker_linux.cc
index f863ccd..37911de 100644
--- a/net/base/address_tracker_linux.cc
+++ b/net/base/address_tracker_linux.cc
@@ -18,7 +18,12 @@ namespace internal {
namespace {
// Retrieves address from NETLINK address message.
-bool GetAddress(const struct nlmsghdr* header, IPAddressNumber* out) {
+// Sets |really_deprecated| for IPv6 addresses with preferred lifetimes of 0.
+bool GetAddress(const struct nlmsghdr* header,
+ IPAddressNumber* out,
+ bool* really_deprecated) {
+ if (really_deprecated)
+ *really_deprecated = false;
const struct ifaddrmsg* msg =
reinterpret_cast<struct ifaddrmsg*>(NLMSG_DATA(header));
size_t address_length = 0;
@@ -53,6 +58,12 @@ bool GetAddress(const struct nlmsghdr* header, IPAddressNumber* out) {
DCHECK_GE(RTA_PAYLOAD(attr), address_length);
local = reinterpret_cast<unsigned char*>(RTA_DATA(attr));
break;
+ case IFA_CACHEINFO: {
+ const struct ifa_cacheinfo *cache_info =
+ reinterpret_cast<const struct ifa_cacheinfo*>(RTA_DATA(attr));
+ if (really_deprecated)
+ *really_deprecated = (cache_info->ifa_prefered == 0);
+ } break;
default:
break;
}
@@ -225,13 +236,12 @@ void AddressTrackerLinux::ReadMessages(bool* address_changed,
}
}
-void AddressTrackerLinux::HandleMessage(const char* buffer,
+void AddressTrackerLinux::HandleMessage(char* buffer,
size_t length,
bool* address_changed,
bool* link_changed) {
DCHECK(buffer);
- for (const struct nlmsghdr* header =
- reinterpret_cast<const struct nlmsghdr*>(buffer);
+ for (struct nlmsghdr* header = reinterpret_cast<struct nlmsghdr*>(buffer);
NLMSG_OK(header, length);
header = NLMSG_NEXT(header, length)) {
switch (header->nlmsg_type) {
@@ -244,10 +254,20 @@ void AddressTrackerLinux::HandleMessage(const char* buffer,
} return;
case RTM_NEWADDR: {
IPAddressNumber address;
- if (GetAddress(header, &address)) {
+ bool really_deprecated;
+ if (GetAddress(header, &address, &really_deprecated)) {
base::AutoLock lock(address_map_lock_);
- const struct ifaddrmsg* msg =
+ struct ifaddrmsg* msg =
reinterpret_cast<struct ifaddrmsg*>(NLMSG_DATA(header));
+ // Routers may frequently (every few seconds) output the IPv6 ULA
+ // prefix which can cause the linux kernel to frequently output two
+ // back-to-back messages, one without the deprecated flag and one with
+ // the deprecated flag but both with preferred lifetimes of 0. Avoid
+ // interpretting this as an actual change by canonicalizing the two
+ // messages by setting the deprecated flag based on the preferred
+ // lifetime also. http://crbug.com/268042
+ if (really_deprecated)
+ msg->ifa_flags |= IFA_F_DEPRECATED;
// Only indicate change if the address is new or ifaddrmsg info has
// changed.
AddressMap::iterator it = address_map_.find(address);
@@ -262,7 +282,7 @@ void AddressTrackerLinux::HandleMessage(const char* buffer,
} break;
case RTM_DELADDR: {
IPAddressNumber address;
- if (GetAddress(header, &address)) {
+ if (GetAddress(header, &address, NULL)) {
base::AutoLock lock(address_map_lock_);
if (address_map_.erase(address))
*address_changed = true;
diff --git a/net/base/address_tracker_linux.h b/net/base/address_tracker_linux.h
index e5ab692..0d56ee5 100644
--- a/net/base/address_tracker_linux.h
+++ b/net/base/address_tracker_linux.h
@@ -60,7 +60,7 @@ class NET_EXPORT_PRIVATE AddressTrackerLinux :
// Sets |*address_changed| to true if |address_map_| changed, sets
// |*link_changed| to true if |online_links_| changed while reading the
// message from |buffer|.
- void HandleMessage(const char* buffer,
+ void HandleMessage(char* buffer,
size_t length,
bool* address_changed,
bool* link_changed);
diff --git a/net/base/address_tracker_linux_unittest.cc b/net/base/address_tracker_linux_unittest.cc
index 4708380..19ad3dd 100644
--- a/net/base/address_tracker_linux_unittest.cc
+++ b/net/base/address_tracker_linux_unittest.cc
@@ -23,18 +23,20 @@ class AddressTrackerLinuxTest : public testing::Test {
AddressTrackerLinuxTest() : tracker_(base::Bind(&Noop), base::Bind(&Noop)) {}
bool HandleAddressMessage(const Buffer& buf) {
+ Buffer writable_buf = buf;
bool address_changed = false;
bool link_changed = false;
- tracker_.HandleMessage(&buf[0], buf.size(),
+ tracker_.HandleMessage(&writable_buf[0], buf.size(),
&address_changed, &link_changed);
EXPECT_FALSE(link_changed);
return address_changed;
}
bool HandleLinkMessage(const Buffer& buf) {
+ Buffer writable_buf = buf;
bool address_changed = false;
bool link_changed = false;
- tracker_.HandleMessage(&buf[0], buf.size(),
+ tracker_.HandleMessage(&writable_buf[0], buf.size(),
&address_changed, &link_changed);
EXPECT_FALSE(address_changed);
return link_changed;
@@ -103,12 +105,15 @@ class NetlinkMessage {
Buffer buffer_;
};
-void MakeAddrMessage(uint16 type,
- uint8 flags,
- uint8 family,
- const IPAddressNumber& address,
- const IPAddressNumber& local,
- Buffer* output) {
+#define INFINITY_LIFE_TIME 0xFFFFFFFF
+
+void MakeAddrMessageWithCacheInfo(uint16 type,
+ uint8 flags,
+ uint8 family,
+ const IPAddressNumber& address,
+ const IPAddressNumber& local,
+ uint32 preferred_lifetime,
+ Buffer* output) {
NetlinkMessage nlmsg(type);
struct ifaddrmsg msg = {};
msg.ifa_family = family;
@@ -118,9 +123,23 @@ void MakeAddrMessage(uint16 type,
nlmsg.AddAttribute(IFA_ADDRESS, &address[0], address.size());
if (local.size())
nlmsg.AddAttribute(IFA_LOCAL, &local[0], local.size());
+ struct ifa_cacheinfo cache_info = {};
+ cache_info.ifa_prefered = preferred_lifetime;
+ cache_info.ifa_valid = INFINITY_LIFE_TIME;
+ nlmsg.AddAttribute(IFA_CACHEINFO, &cache_info, sizeof(cache_info));
nlmsg.AppendTo(output);
}
+void MakeAddrMessage(uint16 type,
+ uint8 flags,
+ uint8 family,
+ const IPAddressNumber& address,
+ const IPAddressNumber& local,
+ Buffer* output) {
+ MakeAddrMessageWithCacheInfo(type, flags, family, address, local,
+ INFINITY_LIFE_TIME, output);
+}
+
void MakeLinkMessage(uint16 type, uint32 flags, uint32 index, Buffer* output) {
NetlinkMessage nlmsg(type);
struct ifinfomsg msg = {};
@@ -258,6 +277,46 @@ TEST_F(AddressTrackerLinuxTest, DeleteAddress) {
EXPECT_EQ(0u, map.size());
}
+TEST_F(AddressTrackerLinuxTest, DeprecatedLifetime) {
+ const IPAddressNumber kEmpty;
+ const IPAddressNumber kAddr3(kAddress3, kAddress3 + arraysize(kAddress3));
+
+ Buffer buffer;
+ MakeAddrMessage(RTM_NEWADDR, 0, AF_INET6, kEmpty, kAddr3, &buffer);
+ EXPECT_TRUE(HandleAddressMessage(buffer));
+ AddressTrackerLinux::AddressMap map = GetAddressMap();
+ EXPECT_EQ(1u, map.size());
+ EXPECT_EQ(1u, map.count(kAddr3));
+ EXPECT_EQ(0, map[kAddr3].ifa_flags);
+
+ // Verify 0 preferred lifetime implies deprecated.
+ buffer.clear();
+ MakeAddrMessageWithCacheInfo(RTM_NEWADDR, 0, AF_INET6, kEmpty, kAddr3, 0,
+ &buffer);
+ EXPECT_TRUE(HandleAddressMessage(buffer));
+ map = GetAddressMap();
+ EXPECT_EQ(1u, map.size());
+ EXPECT_EQ(IFA_F_DEPRECATED, map[kAddr3].ifa_flags);
+
+ // Verify properly flagged message doesn't imply change.
+ buffer.clear();
+ MakeAddrMessageWithCacheInfo(RTM_NEWADDR, IFA_F_DEPRECATED, AF_INET6, kEmpty,
+ kAddr3, 0, &buffer);
+ EXPECT_FALSE(HandleAddressMessage(buffer));
+ map = GetAddressMap();
+ EXPECT_EQ(1u, map.size());
+ EXPECT_EQ(IFA_F_DEPRECATED, map[kAddr3].ifa_flags);
+
+ // Verify implied deprecated doesn't imply change.
+ buffer.clear();
+ MakeAddrMessageWithCacheInfo(RTM_NEWADDR, 0, AF_INET6, kEmpty, kAddr3, 0,
+ &buffer);
+ EXPECT_FALSE(HandleAddressMessage(buffer));
+ map = GetAddressMap();
+ EXPECT_EQ(1u, map.size());
+ EXPECT_EQ(IFA_F_DEPRECATED, map[kAddr3].ifa_flags);
+}
+
TEST_F(AddressTrackerLinuxTest, IgnoredMessage) {
const IPAddressNumber kEmpty;
const IPAddressNumber kAddr0(kAddress0, kAddress0 + arraysize(kAddress0));