blob: 144729598f5e40afc3ab2450f3f13e2c8cfec031 [file] [log] [blame]
Paul Stewartf748a362012-03-07 12:01:20 -08001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Paul Stewarta3c56f92011-05-26 07:08:52 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <errno.h>
6#include <time.h>
7#include <unistd.h>
8#include <string.h>
Darin Petkove0a312e2011-07-20 13:45:28 -07009#include <sys/ioctl.h>
Paul Stewarta3c56f92011-05-26 07:08:52 -070010#include <sys/socket.h>
11#include <arpa/inet.h>
12#include <netinet/ether.h>
13#include <net/if.h>
14#include <net/if_arp.h>
15#include <linux/netlink.h>
16#include <linux/rtnetlink.h>
17#include <fcntl.h>
Paul Stewarta3c56f92011-05-26 07:08:52 -070018
Eric Shienbrood3e20a232012-02-16 11:35:56 -050019#include <base/bind.h>
Paul Stewarta3c56f92011-05-26 07:08:52 -070020#include <base/logging.h>
Paul Stewarta3c56f92011-05-26 07:08:52 -070021
Paul Stewart26b327e2011-10-19 11:38:09 -070022#include "shill/event_dispatcher.h"
Paul Stewarta3c56f92011-05-26 07:08:52 -070023#include "shill/io_handler.h"
Paul Stewart1d18e8c2011-07-15 11:00:31 -070024#include "shill/ip_address.h"
Paul Stewartc39f1132011-06-22 12:02:28 -070025#include "shill/ipconfig.h"
Paul Stewarta3c56f92011-05-26 07:08:52 -070026#include "shill/rtnl_handler.h"
27#include "shill/rtnl_listener.h"
Paul Stewart75e89d22011-08-01 10:00:02 -070028#include "shill/rtnl_message.h"
Ben Chanfad4a0b2012-04-18 15:49:59 -070029#include "shill/scope_logger.h"
Darin Petkov633ac6f2011-07-08 13:56:13 -070030#include "shill/sockets.h"
Paul Stewarta3c56f92011-05-26 07:08:52 -070031
Eric Shienbrood3e20a232012-02-16 11:35:56 -050032using base::Bind;
33using base::Unretained;
Paul Stewarta3c56f92011-05-26 07:08:52 -070034using std::string;
35
36namespace shill {
37
Eric Shienbrood3e20a232012-02-16 11:35:56 -050038// TODO(ers): not using LAZY_INSTANCE_INITIALIZER
39// because of http://crbug.com/114828
40static base::LazyInstance<RTNLHandler> g_rtnl_handler = {0, {{0}}};
Paul Stewart0d2ada32011-08-09 17:01:57 -070041
Paul Stewarta3c56f92011-05-26 07:08:52 -070042RTNLHandler::RTNLHandler()
Darin Petkov633ac6f2011-07-08 13:56:13 -070043 : sockets_(NULL),
Paul Stewarta3c56f92011-05-26 07:08:52 -070044 in_request_(false),
Paul Stewarta3c56f92011-05-26 07:08:52 -070045 rtnl_socket_(-1),
46 request_flags_(0),
mukesh agrawalf60e4062011-05-27 13:13:41 -070047 request_sequence_(0),
Paul Stewart9a908082011-08-31 12:18:48 -070048 last_dump_sequence_(0),
Eric Shienbrood3e20a232012-02-16 11:35:56 -050049 rtnl_callback_(Bind(&RTNLHandler::ParseRTNL, Unretained(this))) {
Ben Chanfad4a0b2012-04-18 15:49:59 -070050 SLOG(RTNL, 2) << "RTNLHandler created";
Paul Stewarta3c56f92011-05-26 07:08:52 -070051}
52
53RTNLHandler::~RTNLHandler() {
Ben Chanfad4a0b2012-04-18 15:49:59 -070054 SLOG(RTNL, 2) << "RTNLHandler removed";
Paul Stewarta3c56f92011-05-26 07:08:52 -070055 Stop();
56}
57
58RTNLHandler* RTNLHandler::GetInstance() {
Paul Stewart0d2ada32011-08-09 17:01:57 -070059 return g_rtnl_handler.Pointer();
Paul Stewarta3c56f92011-05-26 07:08:52 -070060}
61
Darin Petkov633ac6f2011-07-08 13:56:13 -070062void RTNLHandler::Start(EventDispatcher *dispatcher, Sockets *sockets) {
Paul Stewarta3c56f92011-05-26 07:08:52 -070063 struct sockaddr_nl addr;
64
Darin Petkov633ac6f2011-07-08 13:56:13 -070065 if (sockets_) {
Paul Stewarta3c56f92011-05-26 07:08:52 -070066 return;
Darin Petkov633ac6f2011-07-08 13:56:13 -070067 }
Paul Stewarta3c56f92011-05-26 07:08:52 -070068
Darin Petkov633ac6f2011-07-08 13:56:13 -070069 rtnl_socket_ = sockets->Socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
Paul Stewarta3c56f92011-05-26 07:08:52 -070070 if (rtnl_socket_ < 0) {
71 LOG(ERROR) << "Failed to open rtnl socket";
72 return;
73 }
74
75 memset(&addr, 0, sizeof(addr));
76 addr.nl_family = AF_NETLINK;
Paul Stewart9a908082011-08-31 12:18:48 -070077 addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE |
78 RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE;
Paul Stewarta3c56f92011-05-26 07:08:52 -070079
Darin Petkov633ac6f2011-07-08 13:56:13 -070080 if (sockets->Bind(rtnl_socket_,
81 reinterpret_cast<struct sockaddr *>(&addr),
82 sizeof(addr)) < 0) {
83 sockets->Close(rtnl_socket_);
Paul Stewarta3c56f92011-05-26 07:08:52 -070084 rtnl_socket_ = -1;
85 LOG(ERROR) << "RTNL socket bind failed";
86 return;
87 }
88
89 rtnl_handler_.reset(dispatcher->CreateInputHandler(rtnl_socket_,
Eric Shienbrood3e20a232012-02-16 11:35:56 -050090 rtnl_callback_));
Darin Petkov633ac6f2011-07-08 13:56:13 -070091 sockets_ = sockets;
Paul Stewarta3c56f92011-05-26 07:08:52 -070092
Paul Stewart9a908082011-08-31 12:18:48 -070093 NextRequest(last_dump_sequence_);
Ben Chanfad4a0b2012-04-18 15:49:59 -070094 SLOG(RTNL, 2) << "RTNLHandler started";
Paul Stewarta3c56f92011-05-26 07:08:52 -070095}
96
97void RTNLHandler::Stop() {
Darin Petkov633ac6f2011-07-08 13:56:13 -070098 if (!sockets_)
Paul Stewarta3c56f92011-05-26 07:08:52 -070099 return;
100
Paul Stewart7355ce12011-09-02 10:47:01 -0700101 rtnl_handler_.reset();
Darin Petkov633ac6f2011-07-08 13:56:13 -0700102 sockets_->Close(rtnl_socket_);
Paul Stewarta3c56f92011-05-26 07:08:52 -0700103 in_request_ = false;
Darin Petkov633ac6f2011-07-08 13:56:13 -0700104 sockets_ = NULL;
Paul Stewart65c40f52011-08-08 07:27:46 -0700105 request_flags_ = 0;
Ben Chanfad4a0b2012-04-18 15:49:59 -0700106 SLOG(RTNL, 2) << "RTNLHandler stopped";
Paul Stewarta3c56f92011-05-26 07:08:52 -0700107}
108
109void RTNLHandler::AddListener(RTNLListener *to_add) {
110 std::vector<RTNLListener *>::iterator it;
111 for (it = listeners_.begin(); it != listeners_.end(); ++it) {
112 if (to_add == *it)
113 return;
114 }
115 listeners_.push_back(to_add);
Ben Chanfad4a0b2012-04-18 15:49:59 -0700116 SLOG(RTNL, 2) << "RTNLHandler added listener";
Paul Stewarta3c56f92011-05-26 07:08:52 -0700117}
118
119void RTNLHandler::RemoveListener(RTNLListener *to_remove) {
120 std::vector<RTNLListener *>::iterator it;
121 for (it = listeners_.begin(); it != listeners_.end(); ++it) {
122 if (to_remove == *it) {
123 listeners_.erase(it);
124 return;
125 }
126 }
Ben Chanfad4a0b2012-04-18 15:49:59 -0700127 SLOG(RTNL, 2) << "RTNLHandler removed listener";
Paul Stewarta3c56f92011-05-26 07:08:52 -0700128}
129
130void RTNLHandler::SetInterfaceFlags(int interface_index, unsigned int flags,
Darin Petkov0828f5f2011-08-11 10:18:52 -0700131 unsigned int change) {
Paul Stewart536820d2012-03-19 16:05:59 -0700132 if (!sockets_) {
133 LOG(ERROR) << __func__ << " called while not started. "
134 "Assuming we are in unit tests.";
135 return;
136 }
137
Paul Stewarta3c56f92011-05-26 07:08:52 -0700138 struct rtnl_request {
139 struct nlmsghdr hdr;
140 struct ifinfomsg msg;
141 } req;
142
143 request_sequence_++;
144 memset(&req, 0, sizeof(req));
145
146 req.hdr.nlmsg_len = sizeof(req);
147 req.hdr.nlmsg_flags = NLM_F_REQUEST;
148 req.hdr.nlmsg_pid = 0;
149 req.hdr.nlmsg_seq = request_sequence_;
150 req.hdr.nlmsg_type = RTM_NEWLINK;
151 req.msg.ifi_index = interface_index;
152 req.msg.ifi_flags = flags;
153 req.msg.ifi_change = change;
154
Darin Petkov633ac6f2011-07-08 13:56:13 -0700155 if (sockets_->Send(rtnl_socket_, &req, sizeof(req), 0) < 0) {
Paul Stewarta3c56f92011-05-26 07:08:52 -0700156 LOG(ERROR) << "RTNL sendto failed: " << strerror(errno);
157 }
158}
159
160void RTNLHandler::RequestDump(int request_flags) {
161 request_flags_ |= request_flags;
162
Ben Chanfad4a0b2012-04-18 15:49:59 -0700163 SLOG(RTNL, 2) << "RTNLHandler got request to dump "
mukesh agrawal47009f82011-08-25 14:07:35 -0700164 << std::showbase << std::hex
165 << request_flags
166 << std::dec << std::noshowbase;
Paul Stewarta3c56f92011-05-26 07:08:52 -0700167
Darin Petkov633ac6f2011-07-08 13:56:13 -0700168 if (!in_request_ && sockets_)
Paul Stewart9a908082011-08-31 12:18:48 -0700169 NextRequest(last_dump_sequence_);
Paul Stewarta3c56f92011-05-26 07:08:52 -0700170}
171
Chris Masone2aa97072011-08-09 17:35:08 -0700172void RTNLHandler::DispatchEvent(int type, const RTNLMessage &msg) {
Paul Stewarta3c56f92011-05-26 07:08:52 -0700173 std::vector<RTNLListener *>::iterator it;
174 for (it = listeners_.begin(); it != listeners_.end(); ++it) {
Chris Masone2aa97072011-08-09 17:35:08 -0700175 (*it)->NotifyEvent(type, msg);
Paul Stewarta3c56f92011-05-26 07:08:52 -0700176 }
177}
178
Paul Stewartf748a362012-03-07 12:01:20 -0800179void RTNLHandler::NextRequest(uint32 seq) {
Paul Stewarta3c56f92011-05-26 07:08:52 -0700180 int flag = 0;
Paul Stewart9a908082011-08-31 12:18:48 -0700181 RTNLMessage::Type type;
Paul Stewarta3c56f92011-05-26 07:08:52 -0700182
Ben Chanfad4a0b2012-04-18 15:49:59 -0700183 SLOG(RTNL, 2) << "RTNLHandler nextrequest " << seq << " "
184 << last_dump_sequence_
185 << std::showbase << std::hex
186 << " " << request_flags_
187 << std::dec << std::noshowbase;
Paul Stewarta3c56f92011-05-26 07:08:52 -0700188
Paul Stewart9a908082011-08-31 12:18:48 -0700189 if (seq != last_dump_sequence_)
Paul Stewarta3c56f92011-05-26 07:08:52 -0700190 return;
191
Paul Stewarta3c56f92011-05-26 07:08:52 -0700192 if ((request_flags_ & kRequestLink) != 0) {
Paul Stewart9a908082011-08-31 12:18:48 -0700193 type = RTNLMessage::kTypeLink;
Paul Stewarta3c56f92011-05-26 07:08:52 -0700194 flag = kRequestLink;
195 } else if ((request_flags_ & kRequestAddr) != 0) {
Paul Stewart9a908082011-08-31 12:18:48 -0700196 type = RTNLMessage::kTypeAddress;
Paul Stewarta3c56f92011-05-26 07:08:52 -0700197 flag = kRequestAddr;
198 } else if ((request_flags_ & kRequestRoute) != 0) {
Paul Stewart9a908082011-08-31 12:18:48 -0700199 type = RTNLMessage::kTypeRoute;
Paul Stewarta3c56f92011-05-26 07:08:52 -0700200 flag = kRequestRoute;
201 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700202 SLOG(RTNL, 2) << "Done with requests";
Paul Stewarta3c56f92011-05-26 07:08:52 -0700203 in_request_ = false;
204 return;
205 }
206
Paul Stewart9a908082011-08-31 12:18:48 -0700207 RTNLMessage msg(
208 type,
209 RTNLMessage::kModeGet,
210 0,
211 0,
212 0,
213 0,
Paul Stewart7355ce12011-09-02 10:47:01 -0700214 IPAddress::kFamilyUnknown);
Paul Stewart9a908082011-08-31 12:18:48 -0700215 CHECK(SendMessage(&msg));
Paul Stewarta3c56f92011-05-26 07:08:52 -0700216
Paul Stewart9a908082011-08-31 12:18:48 -0700217 last_dump_sequence_ = msg.seq();
Paul Stewarta3c56f92011-05-26 07:08:52 -0700218 request_flags_ &= ~flag;
219 in_request_ = true;
220}
221
222void RTNLHandler::ParseRTNL(InputData *data) {
223 unsigned char *buf = data->buf;
224 unsigned char *end = buf + data->len;
225
226 while (buf < end) {
227 struct nlmsghdr *hdr = reinterpret_cast<struct nlmsghdr *>(buf);
mukesh agrawalf60e4062011-05-27 13:13:41 -0700228 if (!NLMSG_OK(hdr, static_cast<unsigned int>(end - buf)))
Paul Stewarta3c56f92011-05-26 07:08:52 -0700229 break;
230
Ben Chanfad4a0b2012-04-18 15:49:59 -0700231 SLOG(RTNL, 3) << __func__ << ": received payload (" << end - buf << ")";
Paul Stewart7355ce12011-09-02 10:47:01 -0700232
Chris Masone2aa97072011-08-09 17:35:08 -0700233 RTNLMessage msg;
234 if (!msg.Decode(ByteString(reinterpret_cast<unsigned char *>(hdr),
235 hdr->nlmsg_len))) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700236 SLOG(RTNL, 3) << __func__ << ": rtnl packet type "
237 << hdr->nlmsg_type << " length " << hdr->nlmsg_len;
Chris Masone2aa97072011-08-09 17:35:08 -0700238 switch (hdr->nlmsg_type) {
239 case NLMSG_NOOP:
240 case NLMSG_OVERRUN:
241 break;
242 case NLMSG_DONE:
243 NextRequest(hdr->nlmsg_seq);
244 break;
245 case NLMSG_ERROR:
246 {
247 struct nlmsgerr *err =
248 reinterpret_cast<nlmsgerr *>(NLMSG_DATA(hdr));
249 LOG(ERROR) << "error " << -err->error << " ("
250 << strerror(-err->error) << ")";
251 break;
252 }
253 default:
254 NOTIMPLEMENTED() << "Unknown NL message type.";
255 }
256 } else {
257 switch (msg.type()) {
Paul Stewart9a908082011-08-31 12:18:48 -0700258 case RTNLMessage::kTypeLink:
Chris Masone2aa97072011-08-09 17:35:08 -0700259 DispatchEvent(kRequestLink, msg);
260 break;
Paul Stewart9a908082011-08-31 12:18:48 -0700261 case RTNLMessage::kTypeAddress:
Chris Masone2aa97072011-08-09 17:35:08 -0700262 DispatchEvent(kRequestAddr, msg);
263 break;
Paul Stewart9a908082011-08-31 12:18:48 -0700264 case RTNLMessage::kTypeRoute:
Chris Masone2aa97072011-08-09 17:35:08 -0700265 DispatchEvent(kRequestRoute, msg);
266 break;
267 default:
268 NOTIMPLEMENTED() << "Unknown RTNL message type.";
269 }
270 }
Paul Stewarta3c56f92011-05-26 07:08:52 -0700271 buf += hdr->nlmsg_len;
272 }
273}
274
Paul Stewart9a908082011-08-31 12:18:48 -0700275bool RTNLHandler::AddressRequest(int interface_index,
276 RTNLMessage::Mode mode,
277 int flags,
278 const IPAddress &local,
Paul Stewart48100b02012-03-19 07:53:52 -0700279 const IPAddress &gateway,
280 const IPAddress &peer) {
Paul Stewart9a908082011-08-31 12:18:48 -0700281 CHECK(local.family() == gateway.family());
Paul Stewart48100b02012-03-19 07:53:52 -0700282 CHECK(local.family() == peer.family());
Paul Stewartc39f1132011-06-22 12:02:28 -0700283
Paul Stewart9a908082011-08-31 12:18:48 -0700284 RTNLMessage msg(
285 RTNLMessage::kTypeAddress,
286 mode,
287 NLM_F_REQUEST | flags,
288 0,
289 0,
290 interface_index,
291 local.family());
Paul Stewartc39f1132011-06-22 12:02:28 -0700292
Paul Stewart9a908082011-08-31 12:18:48 -0700293 msg.set_address_status(RTNLMessage::AddressStatus(
294 local.prefix(),
295 0,
296 0));
Paul Stewartc39f1132011-06-22 12:02:28 -0700297
Paul Stewart9a908082011-08-31 12:18:48 -0700298 msg.SetAttribute(IFA_LOCAL, local.address());
299 if (!gateway.IsDefault()) {
300 msg.SetAttribute(IFA_BROADCAST, gateway.address());
Paul Stewartc39f1132011-06-22 12:02:28 -0700301 }
Paul Stewart48100b02012-03-19 07:53:52 -0700302 if (!peer.IsDefault()) {
303 msg.SetAttribute(IFA_ADDRESS, peer.address());
304 }
Paul Stewartc39f1132011-06-22 12:02:28 -0700305
Paul Stewart9a908082011-08-31 12:18:48 -0700306 return SendMessage(&msg);
Paul Stewartc39f1132011-06-22 12:02:28 -0700307}
308
309bool RTNLHandler::AddInterfaceAddress(int interface_index,
Paul Stewart9a908082011-08-31 12:18:48 -0700310 const IPAddress &local,
Paul Stewart48100b02012-03-19 07:53:52 -0700311 const IPAddress &broadcast,
312 const IPAddress &peer) {
Paul Stewart9a908082011-08-31 12:18:48 -0700313 return AddressRequest(interface_index,
314 RTNLMessage::kModeAdd,
315 NLM_F_CREATE | NLM_F_EXCL,
316 local,
Paul Stewart48100b02012-03-19 07:53:52 -0700317 broadcast,
318 peer);
Paul Stewartc39f1132011-06-22 12:02:28 -0700319}
320
321bool RTNLHandler::RemoveInterfaceAddress(int interface_index,
Paul Stewart9a908082011-08-31 12:18:48 -0700322 const IPAddress &local) {
323 return AddressRequest(interface_index,
324 RTNLMessage::kModeDelete,
325 0,
326 local,
Paul Stewart48100b02012-03-19 07:53:52 -0700327 IPAddress(local.family()),
Paul Stewart9a908082011-08-31 12:18:48 -0700328 IPAddress(local.family()));
Paul Stewartc39f1132011-06-22 12:02:28 -0700329}
330
Paul Stewartcba0f7f2012-02-29 16:33:05 -0800331bool RTNLHandler::RemoveInterface(int interface_index) {
332 RTNLMessage msg(
333 RTNLMessage::kTypeLink,
334 RTNLMessage::kModeDelete,
335 NLM_F_REQUEST,
336 0,
337 0,
338 interface_index,
339 IPAddress::kFamilyUnknown);
340 return SendMessage(&msg);
341}
342
Darin Petkove0a312e2011-07-20 13:45:28 -0700343int RTNLHandler::GetInterfaceIndex(const string &interface_name) {
344 if (interface_name.empty()) {
345 LOG(ERROR) << "Empty interface name -- unable to obtain index.";
346 return -1;
347 }
348 struct ifreq ifr;
349 if (interface_name.size() >= sizeof(ifr.ifr_name)) {
350 LOG(ERROR) << "Interface name too long: " << interface_name.size() << " >= "
351 << sizeof(ifr.ifr_name);
352 return -1;
353 }
354 int socket = sockets_->Socket(PF_INET, SOCK_DGRAM, 0);
355 if (socket < 0) {
356 PLOG(ERROR) << "Unable to open INET socket";
357 return -1;
358 }
359 ScopedSocketCloser socket_closer(sockets_, socket);
360 memset(&ifr, 0, sizeof(ifr));
361 strncpy(ifr.ifr_name, interface_name.c_str(), sizeof(ifr.ifr_name));
362 if (sockets_->Ioctl(socket, SIOCGIFINDEX, &ifr) < 0) {
363 PLOG(ERROR) << "SIOCGIFINDEX error for " << interface_name;
364 return -1;
365 }
366 return ifr.ifr_ifindex;
367}
368
Paul Stewart75e89d22011-08-01 10:00:02 -0700369bool RTNLHandler::SendMessage(RTNLMessage *message) {
370 message->set_seq(request_sequence_++);
371 ByteString msgdata = message->Encode();
372
373 if (msgdata.GetLength() == 0) {
374 return false;
375 }
376
377 if (sockets_->Send(rtnl_socket_,
Paul Stewart9a908082011-08-31 12:18:48 -0700378 msgdata.GetConstData(),
Paul Stewart75e89d22011-08-01 10:00:02 -0700379 msgdata.GetLength(),
380 0) < 0) {
381 PLOG(ERROR) << "RTNL send failed: " << strerror(errno);
382 return false;
383 }
384
385 return true;
386}
387
Paul Stewarta3c56f92011-05-26 07:08:52 -0700388} // namespace shill