Kea 2.7.1
perf_socket.cc
Go to the documentation of this file.
1// Copyright (C) 2012-2024 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
12#include <perfdhcp/stats_mgr.h>
13
14#include <dhcp/iface_mgr.h>
15#include <asiolink/io_address.h>
16
17using namespace isc::dhcp;
18using namespace isc::asiolink;
19
20namespace isc {
21namespace perfdhcp {
22
27
28
29int
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.
78 sock = IfaceMgr::instance().openSocketFromRemoteAddress(remoteaddr,
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 =
108 IfaceMgr::instance().getIface(options.getLocalName());
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
129 IfacePtr iface = IfaceMgr::instance().getIface(ifindex_);
130 if (iface) {
131 iface->delSocket(sockfd_);
132 }
133}
134
135void
137 for (auto const& iface : IfaceMgr::instance().getIfaces()) {
138 for (auto const& 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
150PerfSocket::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) {
157 std::cout << "Incorrect DHCP packet received"
158 << e.what() << std::endl;
159 }
160 }
161 return (pkt);
162}
163
165PerfSocket::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) {
172 std::cout << "Incorrect DHCP packet received"
173 << e.what() << std::endl;
174 }
175 }
176 return (pkt);
177}
178
179bool
181 return IfaceMgr::instance().send(pkt);
182}
183
184bool
186 return IfaceMgr::instance().send(pkt);
187}
188
193
194}
195}
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
A generic exception that is thrown if a function is called in a prohibited way.
A generic exception that is thrown if a parameter given to a method or function is considered invalid...
A generic exception that is thrown when an unexpected error condition occurs.
static IfaceMgr & instance()
IfaceMgr is a singleton class.
Definition iface_mgr.cc:54
unsigned int ifindex_
Interface index.
Definition perf_socket.h:29
virtual ~PerfSocket()
Destructor of the socket wrapper class.
PerfSocket(CommandOptions &options)
Constructor of socket wrapper class.
virtual dhcp::Pkt6Ptr receive6(uint32_t timeout_sec, uint32_t timeout_usec) override
Receive DHCPv6 packet from interface.
virtual dhcp::IfacePtr getIface() override
Get interface from IfaceMgr.
virtual bool send(const dhcp::Pkt4Ptr &pkt) override
Send DHCPv4 packet through interface.
int openSocket(CommandOptions &options) const
Open socket to communicate with DHCP server.
void initSocketData()
Initialize socket data.
virtual dhcp::Pkt4Ptr receive4(uint32_t timeout_sec, uint32_t timeout_usec) override
Receive DHCPv4 packet from interface.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
boost::shared_ptr< Pkt4 > Pkt4Ptr
A pointer to Pkt4 object.
Definition pkt4.h:555
boost::shared_ptr< Iface > IfacePtr
Type definition for the pointer to an Iface object.
Definition iface_mgr.h:487
boost::shared_ptr< Pkt6 > Pkt6Ptr
A pointer to Pkt6 packet.
Definition pkt6.h:31
Defines the logger used by the top-level component of kea-lfc.
int sockfd_
IPv4 or IPv6.
Definition socket_info.h:26
isc::asiolink::IOAddress addr_
Definition socket_info.h:21