OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
dhcp_proto.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3  */
4 
5 #include <boost/filesystem.hpp>
6 #include "base/timer.h"
7 #include "cmn/agent_cmn.h"
8 #include "init/agent_param.h"
9 #include "oper/vn.h"
10 #include "services/dhcp_proto.h"
11 #include "services/dhcp_lease_db.h"
12 #include "services/services_types.h"
13 #include "services/services_init.h"
14 #include "pkt/pkt_init.h"
15 
16 using namespace boost::asio;
17 using boost::asio::ip::udp;
18 
19 DhcpProto::DhcpProto(Agent *agent, boost::asio::io_context &io,
20  bool run_with_vrouter) :
21  Proto(agent, "Agent::Services", PktHandler::DHCP, io),
22  run_with_vrouter_(run_with_vrouter), ip_fabric_interface_(NULL),
23  ip_fabric_interface_index_(-1), pkt_interface_index_(-1),
24  dhcp_server_socket_(io), dhcp_server_read_buf_(NULL),
25  gateway_delete_seqno_(0) {
26  // limit the number of entries in the workqueue
28  work_queue_.SetBounded(true);
29 
31  if (dhcp_relay_mode_) {
32  boost::system::error_code ec;
33  dhcp_server_socket_.open(udp::v4(), ec);
34  assert(!ec);
35  dhcp_server_socket_.bind(udp::endpoint(udp::v4(), DHCP_SERVER_PORT), ec);
36  if (ec) {
37  DHCP_TRACE(Error, "Error creating DHCP socket : " << ec);
38  }
39 
40  // For DHCP requests coming from VMs in default VRF, when the IP received
41  // from Nova is 0, DHCP module acts DHCP relay and relays the request onto
42  // the fabric VRF. Vrouter sends responses for these to vhost0 interface.
43  // We listen on DHCP server port to receive these responses (check option 82
44  // header to decide that it is a response for a relayed request) and send
45  // the response to the VM.
46  AsyncRead();
47  }
48 
49  iid_ = agent->interface_table()->Register(
50  boost::bind(&DhcpProto::ItfNotify, this, _2));
51  vnid_ = agent->vn_table()->Register(
52  boost::bind(&DhcpProto::VnNotify, this, _2));
53 
55  TimerManager::CreateTimer(io, "DhcpLeaseFileCleanupTimer",
56  TaskScheduler::GetInstance()->GetTaskId("Agent::Services"),
58 }
59 
61 }
62 
64  if (dhcp_relay_mode_) {
65  boost::system::error_code ec;
66  dhcp_server_socket_.shutdown(udp::socket::shutdown_both, ec);
67  if (ec) {
68  DHCP_TRACE(Error, "Error shutting down DHCP socket : " << ec);
69  }
70  dhcp_server_socket_.close (ec);
71  if (ec) {
72  DHCP_TRACE(Error, "Error closing DHCP socket : " << ec);
73  }
74  }
80 }
81 
84  dhcp_server_socket_.async_receive_from(
85  boost::asio::buffer(dhcp_server_read_buf_, kDhcpMaxPacketSize),
87  boost::bind(&DhcpProto::ReadHandler, this,
88  boost::asio::placeholders::error,
89  boost::asio::placeholders::bytes_transferred));
90 }
91 
92 void DhcpProto::ReadHandler(const boost::system::error_code &error,
93  std::size_t len) {
94  if (!error) {
96  } else {
97  DHCP_TRACE(Error, "Error reading packet <" + error.message() + ">");
98  if (error == boost::system::errc::operation_canceled) {
99  return;
100  }
101  delete [] dhcp_server_read_buf_;
102  dhcp_server_read_buf_ = NULL;
103  }
104 
105  AsyncRead();
106 }
107 
108 void DhcpProto::SendDhcpIpc(uint8_t *dhcp, std::size_t len) {
109  DhcpVhostMsg *ipc = new DhcpVhostMsg(dhcp, len);
111 }
112 
113 ProtoHandler *DhcpProto::AllocProtoHandler(boost::shared_ptr<PktInfo> info,
114  boost::asio::io_context &io) {
115  return new DhcpHandler(agent(), info, io);
116 }
117 
119  Interface *itf = static_cast<Interface *>(entry);
120  if (entry->IsDeleted()) {
121  if (itf->type() == Interface::PHYSICAL &&
122  itf->name() == agent_->fabric_interface_name()) {
125  } else if (itf->type() == Interface::PACKET) {
127  } else if (itf->type() == Interface::VM_INTERFACE) {
128  VmInterface *vmi = static_cast<VmInterface *>(itf);
129  if (gw_vmi_list_.erase(vmi)) {
130  DHCP_TRACE(Trace, "Gateway interface deleted: " << itf->name());
132  }
133  DeleteLeaseDb(vmi);
134  }
135  } else {
136  if (itf->type() == Interface::PHYSICAL &&
137  itf->name() == agent_->fabric_interface_name()) {
140  if (run_with_vrouter_) {
142  } else {
144  }
145  } else if (itf->type() == Interface::PACKET) {
146  set_pkt_interface_index(itf->id());
147  } else if (itf->type() == Interface::VM_INTERFACE) {
148  VmInterface *vmi = static_cast<VmInterface *>(itf);
149  if (vmi->vmi_type() == VmInterface::GATEWAY) {
150  DHCP_TRACE(Trace, "Gateway interface added: " << itf->name());
151  gw_vmi_list_.insert(vmi);
152  CreateLeaseDb(vmi);
153  }
154  }
155  }
156 }
157 
159  const Ip4Address &subnet = vmi->subnet();
160  if (vmi->vn() == NULL || subnet.to_ulong() == 0) {
161  DeleteLeaseDb(vmi);
162  DHCP_TRACE(Trace, "DHCP Lease DB not created - config not present : " <<
163  vmi->subnet().to_string());
164  return;
165  }
166 
167  const IpAddress address(subnet);
168  const VnIpam *vn_ipam = vmi->vn()->GetIpam(address);
169  if (!vn_ipam) {
170  DeleteLeaseDb(vmi);
171  DHCP_TRACE(Trace, "DHCP Lease DB not created for subnet " <<
172  vmi->subnet().to_string() << " - IPAM not available");
173  return;
174  }
175 
176  std::string res;
177  std::vector<Ip4Address> reserve_list;
178  if (vmi->primary_ip_addr().to_ulong()) {
179  reserve_list.push_back(vmi->primary_ip_addr());
180  res = vmi->primary_ip_addr().to_string() + ", ";
181  }
182  reserve_list.push_back(vn_ipam->default_gw.to_v4());
183  reserve_list.push_back(vn_ipam->dns_server.to_v4());
184  res += vn_ipam->default_gw.to_v4().to_string() + ", ";
185  res += vn_ipam->dns_server.to_v4().to_string();
186  LeaseManagerMap::iterator it = lease_manager_.find(vmi);
187  if (it == lease_manager_.end()) {
188  DHCP_TRACE(Trace, "Created new DHCP Lease DB : " <<
189  vmi->name() << " " << vmi->subnet().to_string() << "/" <<
190  vmi->subnet_plen() << "; Reserved : " << res);
191  DhcpLeaseDb *lease_db = new DhcpLeaseDb(vmi->subnet(),
192  vmi->subnet_plen(),
193  reserve_list,
194  GetLeaseFileName(vmi),
195  io_);
196  lease_manager_.insert(LeaseManagerPair(vmi, lease_db));
197  } else {
198  DHCP_TRACE(Trace, "Updated DHCP Lease DB : " <<
199  vmi->subnet().to_string() << "/" <<
200  vmi->subnet_plen() << "; Reserved : " << res);
201  it->second->Update(vmi->subnet(), vmi->subnet_plen(),
202  reserve_list);
203  }
204 }
205 
207  LeaseManagerMap::iterator it = lease_manager_.find(vmi);
208  if (it != lease_manager_.end()) {
209  delete it->second;
210  lease_manager_.erase(it);
211  DHCP_TRACE(Trace, "Deleted DHCP Lease DB : " << vmi->name());
212  }
213 }
214 
216  VnEntry *vn = static_cast<VnEntry *>(entry);
217  for (std::set<VmInterface *>::iterator it = gw_vmi_list_.begin();
218  it != gw_vmi_list_.end(); ++it) {
219  VmInterface *vmi = *it;
220  if (vmi->vn() != vn)
221  continue;
222  CreateLeaseDb(*it);
223  }
224 }
225 
227  LeaseManagerMap::iterator it = lease_manager_.find(intrface);
228  if (it != lease_manager_.end())
229  return it->second;
230 
231  return NULL;
232 }
233 
234 std::string DhcpProto::GetLeaseFileName(const VmInterface *vmi) {
235  if (!run_with_vrouter_)
236  return "./dhcp." + UuidToString(vmi->GetUuid()) + ".leases";
237 
238  boost::filesystem::path dir(agent()->params()->agent_base_dir() + "/dhcp");
239  boost::system::error_code ec;
240  if (!boost::filesystem::exists(dir, ec)) {
241  boost::filesystem::create_directory(dir, ec);
242  // boost::filesystem::permissions(dir, boost::filesystem::remove_perms |
243  // boost::filesystem::others_all, ec);
244  if (ec) {
245  DHCP_TRACE(Error, "Cannot create DHCP Lease directory : " << dir);
246  }
247  }
248 
249  return dir.string() + "/dhcp." + UuidToString(vmi->GetUuid()) + ".leases";
250 }
251 
257  this, gateway_delete_seqno_));
258 }
259 
260 bool DhcpProto::LeaseFileCleanupExpiry(uint32_t seqno) {
261  if (seqno == gateway_delete_seqno_ && !gw_vmi_list_.empty()) {
262  // get valid file list
263  std::set<std::string> filelist;
264  for (std::set<VmInterface *>::const_iterator it = gw_vmi_list_.begin();
265  it != gw_vmi_list_.end(); ++it) {
266  filelist.insert(GetLeaseFileName(*it));
267  }
268 
269  // delete unused files
270  boost::system::error_code ec;
271  boost::filesystem::path dir(agent()->params()->agent_base_dir() +
272  "/dhcp");
273  if (boost::filesystem::exists(dir, ec) &&
274  boost::filesystem::is_directory(dir, ec)) {
275  for (boost::filesystem::directory_iterator it(dir);
276  it != boost::filesystem::directory_iterator(); ++it) {
277  std::string filename = it->path().string();
278  if (boost::filesystem::is_regular_file(it->status()) &&
279  filelist.find(filename) == filelist.end()) {
280  DHCP_TRACE(Trace, "Removing DHCP Lease file : " << filename);
281  remove(filename.c_str()); // doesnt invalidate iterator
282  }
283  }
284  }
285  }
286 
287  return false;
288 }
void SetBounded(bool bounded)
Definition: queue_task.h:200
void DeleteLeaseDb(VmInterface *vmi)
Definition: dhcp_proto.cc:206
#define DHCP_SERVER_PORT
Definition: pkt_handler.h:29
void StartLeaseFileCleanupTimer()
Definition: dhcp_proto.cc:252
ProtoHandler * AllocProtoHandler(boost::shared_ptr< PktInfo > info, boost::asio::io_context &io)
Definition: dhcp_proto.cc:113
Type type() const
Definition: interface.h:112
void SendMessage(PktModuleName mod, InterTaskMsg *msg)
void set_ip_fabric_interface_index(uint32_t ind)
Definition: dhcp_proto.h:84
uint8_t * dhcp_server_read_buf_
Definition: dhcp_proto.h:145
const boost::uuids::uuid & GetUuid() const
Definition: interface.h:113
const uint32_t id() const
Definition: interface.h:123
void Shutdown()
Definition: dhcp_proto.cc:63
const VnIpam * GetIpam(const IpAddress &ip) const
Definition: vn.cc:651
Definition: vn.h:28
boost::asio::io_context & io_
#define DHCP_TRACE(obj, arg)
Definition: dhcp_proto.h:11
bool IsDeleted() const
Definition: db_entry.h:49
DhcpLeaseDb * GetLeaseDb(Interface *intrface)
Definition: dhcp_proto.cc:226
boost::asio::ip::address IpAddress
Definition: address.h:13
const Ip4Address & subnet() const
uint32_t gateway_delete_seqno_
Definition: dhcp_proto.h:149
void AsyncRead()
Definition: dhcp_proto.cc:82
InterfaceTable * interface_table() const
Definition: agent.h:465
VnTable * vn_table() const
Definition: agent.h:495
LeaseManagerMap lease_manager_
Definition: dhcp_proto.h:148
const MacAddress & mac() const
Definition: interface.h:131
static std::string UuidToString(const boost::uuids::uuid &id)
Definition: string_util.h:138
void set_ip_fabric_interface_mac(const MacAddress &mac)
Definition: dhcp_proto.h:96
void Unregister(ListenerId listener)
Definition: db_table.cc:186
void ReadHandler(const boost::system::error_code &error, std::size_t len)
Definition: dhcp_proto.cc:92
ListenerId Register(ChangeCallback callback, const std::string &name="unspecified")
Definition: db_table.cc:181
DBTableBase::ListenerId iid_
Definition: dhcp_proto.h:139
Timer * lease_file_cleanup_timer_
Definition: dhcp_proto.h:150
bool LeaseFileCleanupExpiry(uint32_t seqno)
Definition: dhcp_proto.cc:260
IpAddress default_gw
Definition: vn.h:31
void SetSize(size_t size)
Definition: queue_task.h:196
Definition: agent.h:358
static TaskScheduler * GetInstance()
Definition: task.cc:547
void CreateLeaseDb(VmInterface *vmi)
Definition: dhcp_proto.cc:158
const std::string & fabric_interface_name() const
Definition: agent.h:1129
Definition: trace.h:220
void ItfNotify(DBEntryBase *entry)
Definition: dhcp_proto.cc:118
PktHandler * pkt_handler() const
Definition: pkt_init.h:31
void VnNotify(DBEntryBase *entry)
Definition: dhcp_proto.cc:215
const VnEntry * vn() const
DhcpProto(Agent *agent, boost::asio::io_context &io, bool run_with_vrouter)
Definition: dhcp_proto.cc:19
AgentParam * params() const
Definition: agent.h:1218
static const uint32_t kDhcpLeaseFileDeleteTimeout
Definition: dhcp_proto.h:26
static Timer * CreateTimer(boost::asio::io_context &service, const std::string &name, int task_id=Timer::GetTimerTaskId(), int task_instance=Timer::GetTimerInstanceId(), bool delete_on_completion=false)
Definition: timer.cc:201
IpAddress dns_server
Definition: vn.h:33
boost::asio::ip::address_v4 Ip4Address
Definition: address.h:14
bool Cancel()
Definition: timer.cc:150
Definition: vn.h:151
void SendDhcpIpc(uint8_t *dhcp, std::size_t len)
Definition: dhcp_proto.cc:108
const Ip4Address & primary_ip_addr() const
uint32_t services_queue_limit()
Definition: agent_param.h:417
std::pair< Interface *, DhcpLeaseDb * > LeaseManagerPair
Definition: dhcp_proto.h:33
VmInterface::VmiType vmi_type() const
DBTableBase::ListenerId vnid_
Definition: dhcp_proto.h:140
bool Start(int time, Handler handler, ErrorHandler error_handler=NULL)
Definition: timer.cc:108
const uint8_t subnet_plen() const
std::string GetLeaseFileName(const VmInterface *vmi)
Definition: dhcp_proto.cc:234
const std::string & name() const
Definition: interface.h:114
void set_pkt_interface_index(uint32_t ind)
Definition: dhcp_proto.h:90
bool dhcp_relay_mode() const
Definition: agent_param.h:266
virtual ~DhcpProto()
Definition: dhcp_proto.cc:60
PktModule * pkt() const
Definition: agent.cc:965
static const uint32_t kDhcpMaxPacketSize
Definition: dhcp_proto.h:25
bool dhcp_relay_mode_
Definition: dhcp_proto.h:134
boost::asio::ip::udp::endpoint remote_endpoint_
Definition: dhcp_proto.h:144
bool run_with_vrouter_
Definition: dhcp_proto.h:133
void set_ip_fabric_interface(Interface *itf)
Definition: dhcp_proto.h:80
std::set< VmInterface * > gw_vmi_list_
Definition: dhcp_proto.h:147
boost::asio::ip::udp::socket dhcp_server_socket_
Definition: dhcp_proto.h:143
static bool DeleteTimer(Timer *Timer)
Definition: timer.cc:222