Kea  2.1.7-git
perf_socket.cc
Go to the documentation of this file.
1 // Copyright (C) 2012-2020 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 
7 
8 #include <config.h>
9 
10 #include <perfdhcp/perf_socket.h>
12 #include <perfdhcp/stats_mgr.h>
13 
14 #include <dhcp/iface_mgr.h>
15 #include <asiolink/io_address.h>
16 
17 using namespace isc::dhcp;
18 using namespace isc::asiolink;
19 
20 namespace isc {
21 namespace perfdhcp {
22 
23 PerfSocket::PerfSocket(CommandOptions& options) {
24  sockfd_ = openSocket(options);
25  initSocketData();
26 }
27 
28 
29 int
30 PerfSocket::openSocket(CommandOptions& options) const {
31  std::string localname = options.getLocalName();
32  std::string servername = options.getServerName();
33  uint16_t port = options.getLocalPort();
34  int sock = 0;
35 
36  uint8_t family = (options.getIpVersion() == 6) ? AF_INET6 : AF_INET;
37  IOAddress remoteaddr(servername);
38 
39  // Check for mismatch between IP option and server address
40  if (family != remoteaddr.getFamily()) {
42  "Values for IP version: " <<
43  static_cast<unsigned int>(options.getIpVersion()) <<
44  " and server address: " << servername << " are mismatched.");
45  }
46 
47  if (port == 0) {
48  if (family == AF_INET6) {
49  // need server port (547) because the server is acting as a relay agent
50  port = DHCP6_CLIENT_PORT;
51  // if acting as a relay agent change port.
52  if (options.isUseRelayedV6()) {
53  port = DHCP6_SERVER_PORT;
54  }
55  } else if (options.getIpVersion() == 4) {
56  port = 67;
57  }
58  }
59 
60  // Local name is specified along with '-l' option.
61  // It may point to interface name or local address.
62  if (!localname.empty()) {
63  // CommandOptions should be already aware whether local name
64  // is interface name or address because it uses IfaceMgr to
65  // scan interfaces and get's their names.
66  if (options.isInterface()) {
67  sock = IfaceMgr::instance().openSocketFromIface(localname,
68  port,
69  family);
70  } else {
71  IOAddress localaddr(localname);
72  sock = IfaceMgr::instance().openSocketFromAddress(localaddr,
73  port);
74  }
75  } else if (!servername.empty()) {
76  // If only server name is given we will need to try to resolve
77  // the local address to bind socket to based on remote address.
79  port);
80  }
81  if (sock <= 0) {
82  isc_throw(BadValue, "unable to open socket to communicate with "
83  "DHCP server");
84  }
85 
86  // IfaceMgr does not set broadcast option on the socket. We rely
87  // on CommandOptions object to find out if socket has to have
88  // broadcast enabled.
89  if ((options.getIpVersion() == 4) && options.isBroadcast()) {
90  int broadcast_enable = 1;
91  int ret = setsockopt(sock, SOL_SOCKET, SO_BROADCAST,
92  &broadcast_enable, sizeof(broadcast_enable));
93  if (ret < 0) {
95  "unable to set broadcast option on the socket");
96  }
97  } else if (options.getIpVersion() == 6) {
98  // If remote address is multicast we need to enable it on
99  // the socket that has been created.
100  if (remoteaddr.isV6Multicast()) {
101  int hops = 1;
102  int ret = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
103  &hops, sizeof(hops));
104  // If user specified interface name with '-l' the
105  // IPV6_MULTICAST_IF has to be set.
106  if ((ret >= 0) && options.isInterface()) {
107  IfacePtr iface =
109  if (iface == NULL) {
110  isc_throw(Unexpected, "unknown interface "
111  << options.getLocalName());
112  }
113  int idx = iface->getIndex();
114  ret = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF,
115  &idx, sizeof(idx));
116  }
117  if (ret < 0) {
119  "unable to enable multicast on socket " << sock
120  << ". errno = " << errno);
121  }
122  }
123  }
124 
125  return (sock);
126 }
127 
128 PerfSocket::~PerfSocket() {
129  IfacePtr iface = IfaceMgr::instance().getIface(ifindex_);
130  if (iface) {
131  iface->delSocket(sockfd_);
132  }
133 }
134 
135 void
136 PerfSocket::initSocketData() {
137  for (IfacePtr iface : IfaceMgr::instance().getIfaces()) {
138  for (SocketInfo s : iface->getSockets()) {
139  if (s.sockfd_ == sockfd_) {
140  ifindex_ = iface->getIndex();
141  addr_ = s.addr_;
142  return;
143  }
144  }
145  }
146  isc_throw(BadValue, "interface for specified socket descriptor not found");
147 }
148 
149 Pkt4Ptr
150 PerfSocket::receive4(uint32_t timeout_sec, uint32_t timeout_usec) {
151  Pkt4Ptr pkt = IfaceMgr::instance().receive4(timeout_sec, timeout_usec);
152  if (pkt) {
153  try {
154  pkt->unpack();
155  } catch (const std::exception &e) {
156  ExchangeStats::malformed_pkts_++;
157  std::cout << "Incorrect DHCP packet received"
158  << e.what() << std::endl;
159  }
160  }
161  return (pkt);
162 }
163 
164 Pkt6Ptr
165 PerfSocket::receive6(uint32_t timeout_sec, uint32_t timeout_usec) {
166  Pkt6Ptr pkt = IfaceMgr::instance().receive6(timeout_sec, timeout_usec);
167  if (pkt) {
168  try {
169  pkt->unpack();
170  } catch (const std::exception &e) {
171  ExchangeStats::malformed_pkts_++;
172  std::cout << "Incorrect DHCP packet received"
173  << e.what() << std::endl;
174  }
175  }
176  return (pkt);
177 }
178 
179 bool
180 PerfSocket::send(const Pkt4Ptr& pkt) {
181  return IfaceMgr::instance().send(pkt);
182 }
183 
184 bool
185 PerfSocket::send(const Pkt6Ptr& pkt) {
186  return IfaceMgr::instance().send(pkt);
187 }
188 
189 IfacePtr
190 PerfSocket::getIface() {
191  return (IfaceMgr::instance().getIface(ifindex_));
192 }
193 
194 }
195 }
IfacePtr getIface(int ifindex)
Returns interface specified interface index.
Definition: iface_mgr.cc:894
int openSocketFromRemoteAddress(const isc::asiolink::IOAddress &remote_addr, const uint16_t port)
Opens UDP/IP socket to be used to connect to remote address.
Definition: iface_mgr.cc:1033
std::string getLocalName() const
Returns local address or interface name.
bool isUseRelayedV6() const
Check if generated DHCPv6 messages should appear as relayed.
A generic exception that is thrown if a parameter given to a method or function is considered invalid...
boost::shared_ptr< Iface > IfacePtr
Type definition for the pointer to an Iface object.
Definition: iface_mgr.h:463
uint8_t getIpVersion() const
Returns IP version.
int openSocketFromAddress(const isc::asiolink::IOAddress &addr, const uint16_t port)
Opens UDP/IP socket and binds to address specified.
Definition: iface_mgr.cc:1010
bool send(const Pkt6Ptr &pkt)
Sends an IPv6 packet.
Definition: iface_mgr.cc:1118
bool isBroadcast() const
Checks if broadcast address is to be used.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
boost::shared_ptr< Pkt6 > Pkt6Ptr
A pointer to Pkt6 packet.
Definition: pkt6.h:28
Pkt4Ptr receive4(uint32_t timeout_sec, uint32_t timeout_usec=0)
Receive IPv4 packets or data from external sockets.
Definition: iface_mgr.cc:1143
bool isInterface() const
Checks if interface name was used.
A generic exception that is thrown when an unexpected error condition occurs.
boost::shared_ptr< Pkt4 > Pkt4Ptr
A pointer to Pkt4 object.
Definition: pkt4.h:544
std::string getServerName() const
Returns server name.
int getLocalPort() const
Returns local port number.
Defines the logger used by the top-level component of kea-lfc.
A generic exception that is thrown if a function is called in a prohibited way.
static IfaceMgr & instance()
IfaceMgr is a singleton class.
Definition: iface_mgr.cc:53
int openSocketFromIface(const std::string &ifname, const uint16_t port, const uint8_t family)
Opens UDP/IP socket and binds it to interface specified.
Definition: iface_mgr.cc:969
Pkt6Ptr receive6(uint32_t timeout_sec, uint32_t timeout_usec=0)
Receive IPv4 packets or data from external sockets.
Definition: iface_mgr.cc:1398
Holds information about socket.
Definition: socket_info.h:19