blob: eb7a634d4b995cde7ea4d418d074257c0cc0a2a7 [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"
Darin Petkov633ac6f2011-07-08 13:56:13 -070029#include "shill/sockets.h"
Paul Stewarta3c56f92011-05-26 07:08:52 -070030
Eric Shienbrood3e20a232012-02-16 11:35:56 -050031using base::Bind;
32using base::Unretained;
Paul Stewarta3c56f92011-05-26 07:08:52 -070033using std::string;
34
35namespace shill {
36
Eric Shienbrood3e20a232012-02-16 11:35:56 -050037// TODO(ers): not using LAZY_INSTANCE_INITIALIZER
38// because of http://crbug.com/114828
39static base::LazyInstance<RTNLHandler> g_rtnl_handler = {0, {{0}}};
Paul Stewart0d2ada32011-08-09 17:01:57 -070040
Paul Stewarta3c56f92011-05-26 07:08:52 -070041RTNLHandler::RTNLHandler()
Darin Petkov633ac6f2011-07-08 13:56:13 -070042 : sockets_(NULL),
Paul Stewarta3c56f92011-05-26 07:08:52 -070043 in_request_(false),
Paul Stewarta3c56f92011-05-26 07:08:52 -070044 rtnl_socket_(-1),
45 request_flags_(0),
mukesh agrawalf60e4062011-05-27 13:13:41 -070046 request_sequence_(0),
Paul Stewart9a908082011-08-31 12:18:48 -070047 last_dump_sequence_(0),
Eric Shienbrood3e20a232012-02-16 11:35:56 -050048 rtnl_callback_(Bind(&RTNLHandler::ParseRTNL, Unretained(this))) {
Paul Stewarta3c56f92011-05-26 07:08:52 -070049 VLOG(2) << "RTNLHandler created";
50}
51
52RTNLHandler::~RTNLHandler() {
53 VLOG(2) << "RTNLHandler removed";
54 Stop();
55}
56
57RTNLHandler* RTNLHandler::GetInstance() {
Paul Stewart0d2ada32011-08-09 17:01:57 -070058 return g_rtnl_handler.Pointer();
Paul Stewarta3c56f92011-05-26 07:08:52 -070059}
60
Darin Petkov633ac6f2011-07-08 13:56:13 -070061void RTNLHandler::Start(EventDispatcher *dispatcher, Sockets *sockets) {
Paul Stewarta3c56f92011-05-26 07:08:52 -070062 struct sockaddr_nl addr;
63
Darin Petkov633ac6f2011-07-08 13:56:13 -070064 if (sockets_) {
Paul Stewarta3c56f92011-05-26 07:08:52 -070065 return;
Darin Petkov633ac6f2011-07-08 13:56:13 -070066 }
Paul Stewarta3c56f92011-05-26 07:08:52 -070067
Darin Petkov633ac6f2011-07-08 13:56:13 -070068 rtnl_socket_ = sockets->Socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
Paul Stewarta3c56f92011-05-26 07:08:52 -070069 if (rtnl_socket_ < 0) {
70 LOG(ERROR) << "Failed to open rtnl socket";
71 return;
72 }
73
74 memset(&addr, 0, sizeof(addr));
75 addr.nl_family = AF_NETLINK;
Paul Stewart9a908082011-08-31 12:18:48 -070076 addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE |
77 RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE;
Paul Stewarta3c56f92011-05-26 07:08:52 -070078
Darin Petkov633ac6f2011-07-08 13:56:13 -070079 if (sockets->Bind(rtnl_socket_,
80 reinterpret_cast<struct sockaddr *>(&addr),
81 sizeof(addr)) < 0) {
82 sockets->Close(rtnl_socket_);
Paul Stewarta3c56f92011-05-26 07:08:52 -070083 rtnl_socket_ = -1;
84 LOG(ERROR) << "RTNL socket bind failed";
85 return;
86 }
87
88 rtnl_handler_.reset(dispatcher->CreateInputHandler(rtnl_socket_,
Eric Shienbrood3e20a232012-02-16 11:35:56 -050089 rtnl_callback_));
Darin Petkov633ac6f2011-07-08 13:56:13 -070090 sockets_ = sockets;
Paul Stewarta3c56f92011-05-26 07:08:52 -070091
Paul Stewart9a908082011-08-31 12:18:48 -070092 NextRequest(last_dump_sequence_);
Paul Stewarta3c56f92011-05-26 07:08:52 -070093 VLOG(2) << "RTNLHandler started";
94}
95
96void RTNLHandler::Stop() {
Darin Petkov633ac6f2011-07-08 13:56:13 -070097 if (!sockets_)
Paul Stewarta3c56f92011-05-26 07:08:52 -070098 return;
99
Paul Stewart7355ce12011-09-02 10:47:01 -0700100 rtnl_handler_.reset();
Darin Petkov633ac6f2011-07-08 13:56:13 -0700101 sockets_->Close(rtnl_socket_);
Paul Stewarta3c56f92011-05-26 07:08:52 -0700102 in_request_ = false;
Darin Petkov633ac6f2011-07-08 13:56:13 -0700103 sockets_ = NULL;
Paul Stewart65c40f52011-08-08 07:27:46 -0700104 request_flags_ = 0;
Paul Stewarta3c56f92011-05-26 07:08:52 -0700105 VLOG(2) << "RTNLHandler stopped";
106}
107
108void RTNLHandler::AddListener(RTNLListener *to_add) {
109 std::vector<RTNLListener *>::iterator it;
110 for (it = listeners_.begin(); it != listeners_.end(); ++it) {
111 if (to_add == *it)
112 return;
113 }
114 listeners_.push_back(to_add);
115 VLOG(2) << "RTNLHandler added listener";
116}
117
118void RTNLHandler::RemoveListener(RTNLListener *to_remove) {
119 std::vector<RTNLListener *>::iterator it;
120 for (it = listeners_.begin(); it != listeners_.end(); ++it) {
121 if (to_remove == *it) {
122 listeners_.erase(it);
123 return;
124 }
125 }
126 VLOG(2) << "RTNLHandler removed listener";
127}
128
129void RTNLHandler::SetInterfaceFlags(int interface_index, unsigned int flags,
Darin Petkov0828f5f2011-08-11 10:18:52 -0700130 unsigned int change) {
Paul Stewart536820d2012-03-19 16:05:59 -0700131 if (!sockets_) {
132 LOG(ERROR) << __func__ << " called while not started. "
133 "Assuming we are in unit tests.";
134 return;
135 }
136
Paul Stewarta3c56f92011-05-26 07:08:52 -0700137 struct rtnl_request {
138 struct nlmsghdr hdr;
139 struct ifinfomsg msg;
140 } req;
141
142 request_sequence_++;
143 memset(&req, 0, sizeof(req));
144
145 req.hdr.nlmsg_len = sizeof(req);
146 req.hdr.nlmsg_flags = NLM_F_REQUEST;
147 req.hdr.nlmsg_pid = 0;
148 req.hdr.nlmsg_seq = request_sequence_;
149 req.hdr.nlmsg_type = RTM_NEWLINK;
150 req.msg.ifi_index = interface_index;
151 req.msg.ifi_flags = flags;
152 req.msg.ifi_change = change;
153
Darin Petkov633ac6f2011-07-08 13:56:13 -0700154 if (sockets_->Send(rtnl_socket_, &req, sizeof(req), 0) < 0) {
Paul Stewarta3c56f92011-05-26 07:08:52 -0700155 LOG(ERROR) << "RTNL sendto failed: " << strerror(errno);
156 }
157}
158
159void RTNLHandler::RequestDump(int request_flags) {
160 request_flags_ |= request_flags;
161
mukesh agrawal47009f82011-08-25 14:07:35 -0700162 VLOG(2) << "RTNLHandler got request to dump "
163 << std::showbase << std::hex
164 << request_flags
165 << std::dec << std::noshowbase;
Paul Stewarta3c56f92011-05-26 07:08:52 -0700166
Darin Petkov633ac6f2011-07-08 13:56:13 -0700167 if (!in_request_ && sockets_)
Paul Stewart9a908082011-08-31 12:18:48 -0700168 NextRequest(last_dump_sequence_);
Paul Stewarta3c56f92011-05-26 07:08:52 -0700169}
170
Chris Masone2aa97072011-08-09 17:35:08 -0700171void RTNLHandler::DispatchEvent(int type, const RTNLMessage &msg) {
Paul Stewarta3c56f92011-05-26 07:08:52 -0700172 std::vector<RTNLListener *>::iterator it;
173 for (it = listeners_.begin(); it != listeners_.end(); ++it) {
Chris Masone2aa97072011-08-09 17:35:08 -0700174 (*it)->NotifyEvent(type, msg);
Paul Stewarta3c56f92011-05-26 07:08:52 -0700175 }
176}
177
Paul Stewartf748a362012-03-07 12:01:20 -0800178void RTNLHandler::NextRequest(uint32 seq) {
Paul Stewarta3c56f92011-05-26 07:08:52 -0700179 int flag = 0;
Paul Stewart9a908082011-08-31 12:18:48 -0700180 RTNLMessage::Type type;
Paul Stewarta3c56f92011-05-26 07:08:52 -0700181
Paul Stewart9a908082011-08-31 12:18:48 -0700182 VLOG(2) << "RTNLHandler nextrequest " << seq << " " << last_dump_sequence_
mukesh agrawal47009f82011-08-25 14:07:35 -0700183 << std::showbase << std::hex
184 << " " << request_flags_
185 << std::dec << std::noshowbase;
Paul Stewarta3c56f92011-05-26 07:08:52 -0700186
Paul Stewart9a908082011-08-31 12:18:48 -0700187 if (seq != last_dump_sequence_)
Paul Stewarta3c56f92011-05-26 07:08:52 -0700188 return;
189
Paul Stewarta3c56f92011-05-26 07:08:52 -0700190 if ((request_flags_ & kRequestLink) != 0) {
Paul Stewart9a908082011-08-31 12:18:48 -0700191 type = RTNLMessage::kTypeLink;
Paul Stewarta3c56f92011-05-26 07:08:52 -0700192 flag = kRequestLink;
193 } else if ((request_flags_ & kRequestAddr) != 0) {
Paul Stewart9a908082011-08-31 12:18:48 -0700194 type = RTNLMessage::kTypeAddress;
Paul Stewarta3c56f92011-05-26 07:08:52 -0700195 flag = kRequestAddr;
196 } else if ((request_flags_ & kRequestRoute) != 0) {
Paul Stewart9a908082011-08-31 12:18:48 -0700197 type = RTNLMessage::kTypeRoute;
Paul Stewarta3c56f92011-05-26 07:08:52 -0700198 flag = kRequestRoute;
199 } else {
Paul Stewart9a908082011-08-31 12:18:48 -0700200 VLOG(2) << "Done with requests";
Paul Stewarta3c56f92011-05-26 07:08:52 -0700201 in_request_ = false;
202 return;
203 }
204
Paul Stewart9a908082011-08-31 12:18:48 -0700205 RTNLMessage msg(
206 type,
207 RTNLMessage::kModeGet,
208 0,
209 0,
210 0,
211 0,
Paul Stewart7355ce12011-09-02 10:47:01 -0700212 IPAddress::kFamilyUnknown);
Paul Stewart9a908082011-08-31 12:18:48 -0700213 CHECK(SendMessage(&msg));
Paul Stewarta3c56f92011-05-26 07:08:52 -0700214
Paul Stewart9a908082011-08-31 12:18:48 -0700215 last_dump_sequence_ = msg.seq();
Paul Stewarta3c56f92011-05-26 07:08:52 -0700216 request_flags_ &= ~flag;
217 in_request_ = true;
218}
219
220void RTNLHandler::ParseRTNL(InputData *data) {
221 unsigned char *buf = data->buf;
222 unsigned char *end = buf + data->len;
223
224 while (buf < end) {
225 struct nlmsghdr *hdr = reinterpret_cast<struct nlmsghdr *>(buf);
mukesh agrawalf60e4062011-05-27 13:13:41 -0700226 if (!NLMSG_OK(hdr, static_cast<unsigned int>(end - buf)))
Paul Stewarta3c56f92011-05-26 07:08:52 -0700227 break;
228
Paul Stewart7355ce12011-09-02 10:47:01 -0700229 VLOG(3) << __func__ << ": received payload (" << end - buf << ")";
230
Chris Masone2aa97072011-08-09 17:35:08 -0700231 RTNLMessage msg;
232 if (!msg.Decode(ByteString(reinterpret_cast<unsigned char *>(hdr),
233 hdr->nlmsg_len))) {
Paul Stewart7355ce12011-09-02 10:47:01 -0700234 VLOG(3) << __func__ << ": rtnl packet type "
235 << hdr->nlmsg_type << " length " << hdr->nlmsg_len;
Chris Masone2aa97072011-08-09 17:35:08 -0700236 switch (hdr->nlmsg_type) {
237 case NLMSG_NOOP:
238 case NLMSG_OVERRUN:
239 break;
240 case NLMSG_DONE:
241 NextRequest(hdr->nlmsg_seq);
242 break;
243 case NLMSG_ERROR:
244 {
245 struct nlmsgerr *err =
246 reinterpret_cast<nlmsgerr *>(NLMSG_DATA(hdr));
247 LOG(ERROR) << "error " << -err->error << " ("
248 << strerror(-err->error) << ")";
249 break;
250 }
251 default:
252 NOTIMPLEMENTED() << "Unknown NL message type.";
253 }
254 } else {
255 switch (msg.type()) {
Paul Stewart9a908082011-08-31 12:18:48 -0700256 case RTNLMessage::kTypeLink:
Chris Masone2aa97072011-08-09 17:35:08 -0700257 DispatchEvent(kRequestLink, msg);
258 break;
Paul Stewart9a908082011-08-31 12:18:48 -0700259 case RTNLMessage::kTypeAddress:
Chris Masone2aa97072011-08-09 17:35:08 -0700260 DispatchEvent(kRequestAddr, msg);
261 break;
Paul Stewart9a908082011-08-31 12:18:48 -0700262 case RTNLMessage::kTypeRoute:
Chris Masone2aa97072011-08-09 17:35:08 -0700263 DispatchEvent(kRequestRoute, msg);
264 break;
265 default:
266 NOTIMPLEMENTED() << "Unknown RTNL message type.";
267 }
268 }
Paul Stewarta3c56f92011-05-26 07:08:52 -0700269 buf += hdr->nlmsg_len;
270 }
271}
272
Paul Stewart9a908082011-08-31 12:18:48 -0700273bool RTNLHandler::AddressRequest(int interface_index,
274 RTNLMessage::Mode mode,
275 int flags,
276 const IPAddress &local,
Paul Stewart48100b02012-03-19 07:53:52 -0700277 const IPAddress &gateway,
278 const IPAddress &peer) {
Paul Stewart9a908082011-08-31 12:18:48 -0700279 CHECK(local.family() == gateway.family());
Paul Stewart48100b02012-03-19 07:53:52 -0700280 CHECK(local.family() == peer.family());
Paul Stewartc39f1132011-06-22 12:02:28 -0700281
Paul Stewart9a908082011-08-31 12:18:48 -0700282 RTNLMessage msg(
283 RTNLMessage::kTypeAddress,
284 mode,
285 NLM_F_REQUEST | flags,
286 0,
287 0,
288 interface_index,
289 local.family());
Paul Stewartc39f1132011-06-22 12:02:28 -0700290
Paul Stewart9a908082011-08-31 12:18:48 -0700291 msg.set_address_status(RTNLMessage::AddressStatus(
292 local.prefix(),
293 0,
294 0));
Paul Stewartc39f1132011-06-22 12:02:28 -0700295
Paul Stewart9a908082011-08-31 12:18:48 -0700296 msg.SetAttribute(IFA_LOCAL, local.address());
297 if (!gateway.IsDefault()) {
298 msg.SetAttribute(IFA_BROADCAST, gateway.address());
Paul Stewartc39f1132011-06-22 12:02:28 -0700299 }
Paul Stewart48100b02012-03-19 07:53:52 -0700300 if (!peer.IsDefault()) {
301 msg.SetAttribute(IFA_ADDRESS, peer.address());
302 }
Paul Stewartc39f1132011-06-22 12:02:28 -0700303
Paul Stewart9a908082011-08-31 12:18:48 -0700304 return SendMessage(&msg);
Paul Stewartc39f1132011-06-22 12:02:28 -0700305}
306
307bool RTNLHandler::AddInterfaceAddress(int interface_index,
Paul Stewart9a908082011-08-31 12:18:48 -0700308 const IPAddress &local,
Paul Stewart48100b02012-03-19 07:53:52 -0700309 const IPAddress &broadcast,
310 const IPAddress &peer) {
Paul Stewart9a908082011-08-31 12:18:48 -0700311 return AddressRequest(interface_index,
312 RTNLMessage::kModeAdd,
313 NLM_F_CREATE | NLM_F_EXCL,
314 local,
Paul Stewart48100b02012-03-19 07:53:52 -0700315 broadcast,
316 peer);
Paul Stewartc39f1132011-06-22 12:02:28 -0700317}
318
319bool RTNLHandler::RemoveInterfaceAddress(int interface_index,
Paul Stewart9a908082011-08-31 12:18:48 -0700320 const IPAddress &local) {
321 return AddressRequest(interface_index,
322 RTNLMessage::kModeDelete,
323 0,
324 local,
Paul Stewart48100b02012-03-19 07:53:52 -0700325 IPAddress(local.family()),
Paul Stewart9a908082011-08-31 12:18:48 -0700326 IPAddress(local.family()));
Paul Stewartc39f1132011-06-22 12:02:28 -0700327}
328
Paul Stewartcba0f7f2012-02-29 16:33:05 -0800329bool RTNLHandler::RemoveInterface(int interface_index) {
330 RTNLMessage msg(
331 RTNLMessage::kTypeLink,
332 RTNLMessage::kModeDelete,
333 NLM_F_REQUEST,
334 0,
335 0,
336 interface_index,
337 IPAddress::kFamilyUnknown);
338 return SendMessage(&msg);
339}
340
Darin Petkove0a312e2011-07-20 13:45:28 -0700341int RTNLHandler::GetInterfaceIndex(const string &interface_name) {
342 if (interface_name.empty()) {
343 LOG(ERROR) << "Empty interface name -- unable to obtain index.";
344 return -1;
345 }
346 struct ifreq ifr;
347 if (interface_name.size() >= sizeof(ifr.ifr_name)) {
348 LOG(ERROR) << "Interface name too long: " << interface_name.size() << " >= "
349 << sizeof(ifr.ifr_name);
350 return -1;
351 }
352 int socket = sockets_->Socket(PF_INET, SOCK_DGRAM, 0);
353 if (socket < 0) {
354 PLOG(ERROR) << "Unable to open INET socket";
355 return -1;
356 }
357 ScopedSocketCloser socket_closer(sockets_, socket);
358 memset(&ifr, 0, sizeof(ifr));
359 strncpy(ifr.ifr_name, interface_name.c_str(), sizeof(ifr.ifr_name));
360 if (sockets_->Ioctl(socket, SIOCGIFINDEX, &ifr) < 0) {
361 PLOG(ERROR) << "SIOCGIFINDEX error for " << interface_name;
362 return -1;
363 }
364 return ifr.ifr_ifindex;
365}
366
Paul Stewart75e89d22011-08-01 10:00:02 -0700367bool RTNLHandler::SendMessage(RTNLMessage *message) {
368 message->set_seq(request_sequence_++);
369 ByteString msgdata = message->Encode();
370
371 if (msgdata.GetLength() == 0) {
372 return false;
373 }
374
375 if (sockets_->Send(rtnl_socket_,
Paul Stewart9a908082011-08-31 12:18:48 -0700376 msgdata.GetConstData(),
Paul Stewart75e89d22011-08-01 10:00:02 -0700377 msgdata.GetLength(),
378 0) < 0) {
379 PLOG(ERROR) << "RTNL send failed: " << strerror(errno);
380 return false;
381 }
382
383 return true;
384}
385
Paul Stewarta3c56f92011-05-26 07:08:52 -0700386} // namespace shill