iface_mgr.h 14.9 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.

#ifndef IFACE_MGR_H
#define IFACE_MGR_H

#include <list>
19
#include <boost/shared_ptr.hpp>
20
#include <boost/scoped_array.hpp>
21
#include <boost/noncopyable.hpp>
22
23
24
#include <asiolink/io_address.h>
#include <dhcp/pkt4.h>
#include <dhcp/pkt6.h>
25
26
27

namespace isc {

28
29
30
31
32
33
34
35
36
37
namespace dhcp {
/// @brief handles network interfaces, transmission and reception
///
/// IfaceMgr is an interface manager class that detects available network
/// interfaces, configured addresses, link-local addresses, and provides
/// API for using sockets.
///
class IfaceMgr : public boost::noncopyable {
public:
    /// type that defines list of addresses
38
    typedef std::vector<isc::asiolink::IOAddress> AddressCollection;
39
40
41
42

    /// maximum MAC address length (Infiniband uses 20 bytes)
    static const unsigned int MAX_MAC_LEN = 20;

43
44
45
46
47
48
    /// Holds information about socket.
    struct SocketInfo {
        uint16_t sockfd_; /// socket descriptor
        isc::asiolink::IOAddress addr_; /// bound address
        uint16_t port_;   /// socket port
        uint16_t family_; /// IPv4 or IPv6
Tomek Mrugalski's avatar
Tomek Mrugalski committed
49
50
51
52
53
54

        /// @brief SocketInfo constructor.
        ///
        /// @param sockfd socket descriptor
        /// @param addr an address the socket is bound to
        /// @param port a port the socket is bound to
55
56
57
58
59
60
61
62
        SocketInfo(uint16_t sockfd, const isc::asiolink::IOAddress& addr,
                   uint16_t port)
        :sockfd_(sockfd), addr_(addr), port_(port), family_(addr.getFamily()) { }
    };

    /// type that holds a list of socket informations
    typedef std::list<SocketInfo> SocketCollection;

63
    /// @brief represents a single network interface
64
    ///
65
66
67
    /// Iface structure represents network interface with all useful
    /// information, like name, interface index, MAC address and
    /// list of assigned addresses
Tomek Mrugalski's avatar
Tomek Mrugalski committed
68
69
    class Iface {
    public:
70
71
72
73
74
75
        /// @brief Iface constructor.
        ///
        /// Creates Iface object that represents network interface.
        ///
        /// @param name name of the interface
        /// @param ifindex interface index (unique integer identifier)
76
77
        Iface(const std::string& name, int ifindex);

78
79
80
        /// @brief Returns full interface name as "ifname/ifindex" string.
        ///
        /// @return string with interface name
81
82
        std::string getFullName() const;

83
84
85
        /// @brief Returns link-layer address a plain text.
        ///
        /// @return MAC address as a plain text (string)
86
        std::string getPlainMac() const;
87

88
89
90
        /// @brief Returns interface index.
        ///
        /// @return interface index
91
92
        uint16_t getIndex() const { return ifindex_; }

93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
        /// @brief Returns interface name.
        ///
        /// @return interface name
        std::string getName() const { return name_; };

        /// @brief Returns all interfaces available on an interface.
        ///
        /// Care should be taken to not use this collection after Iface object
        /// ceases to exist. That is easy in most cases as Iface objects are
        /// created by IfaceMgr that is a singleton an is expected to be
        /// available at all time. We may revisit this if we ever decide to
        /// implement dynamic interface detection, but such fancy feature would
        /// mostly be useful for clients with wifi/vpn/virtual interfaces.
        ///
        /// @return collection of addresses
108
109
        const AddressCollection& getAddresses() const { return addrs_; }

110
111
112
113
114
115
        /// @brief Adds an address to an interface.
        ///
        /// This only adds an address to collection, it does not physically
        /// configure address on actual network interface.
        ///
        /// @param addr address to be added
116
117
118
119
        void addAddress(const isc::asiolink::IOAddress& addr) {
            addrs_.push_back(addr);
        }

120
121
122
123
124
125
126
127
128
        /// @brief Deletes an address from an interface.
        ///
        /// This only deletes address from collection, it does not physically
        /// remove address configuration from actual network interface.
        ///
        /// @param addr address to be removed.
        ///
        /// @return true if removal was successful (address was in collection),
        ///         false otherwise
129
130
        bool delAddress(const isc::asiolink::IOAddress& addr);

131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
        /// @brief Adds socket descriptor to an interface.
        ///
        /// @param socket SocketInfo structure that describes socket.
        void addSocket(const SocketInfo& sock)
            { sockets_.push_back(sock); }

        /// @brief Closes socket.
        ///
        /// Closes socket and removes corresponding SocketInfo structure
        /// from an interface.
        ///
        /// @param socket descriptor to be closed/removed.
        /// @return true if there was such socket, false otherwise
        bool delSocket(uint16_t sockfd);

        /// socket used to sending data
        /// TODO: this should be protected
        SocketCollection sockets_;

150
    protected:
151
152
153
154
155
        /// network interface name
        std::string name_;

        /// interface index (a value that uniquely indentifies an interface)
        int ifindex_;
156
157

        /// list of assigned addresses
158
        AddressCollection addrs_;
159
160
161
162
163
164

        /// link-layer address
        uint8_t mac_[MAX_MAC_LEN];

        /// length of link-layer address (usually 6)
        int mac_len_;
165
    };
166

167
168
169
170
171
    // TODO performance improvement: we may change this into
    //      2 maps (ifindex-indexed and name-indexed) and
    //      also hide it (make it public make tests easier for now)

    /// type that holds a list of interfaces
172
    typedef std::list<Iface> IfaceCollection;
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199

    /// IfaceMgr is a singleton class. This method returns reference
    /// to its sole instance.
    ///
    /// @return the only existing instance of interface manager
    static IfaceMgr& instance();

    /// @brief Returns interface with specified interface index
    ///
    /// @param ifindex index of searched interface
    ///
    /// @return interface with requested index (or NULL if no such
    ///         interface is present)
    ///
    Iface*
    getIface(int ifindex);

    /// @brief Returns interface with specified interface name
    ///
    /// @param ifname name of searched interface
    ///
    /// @return interface with requested name (or NULL if no such
    ///         interface is present)
    ///
    Iface*
    getIface(const std::string& ifname);

200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
    /// @brief Return most suitable socket for transmitting specified IPv6 packet.
    ///
    /// This method takes Pkt6 (see overloaded implementation that takes
    /// Pkt4) and chooses appropriate socket to send it. This method
    /// may throw BadValue if specified packet does not have outbound
    /// interface specified, no such interface exists, or specified
    /// interface does not have any appropriate sockets open.
    ///
    /// @param pkt a packet to be transmitted
    ///
    /// @return a socket descriptor
    uint16_t getSocket(const isc::dhcp::Pkt6& pkt);

    /// @brief Return most suitable socket for transmitting specified IPv6 packet.
    ///
    /// This method takes Pkt4 (see overloaded implementation that takes
    /// Pkt6) and chooses appropriate socket to send it. This method
    /// may throw BadValue if specified packet does not have outbound
    /// interface specified, no such interface exists, or specified
    /// interface does not have any appropriate sockets open.
    ///
    /// @param pkt a packet to be transmitted
    ///
    /// @return a socket descriptor
    uint16_t getSocket(const isc::dhcp::Pkt4& pkt);

226
227
228
229
230
231
    /// debugging method that prints out all available interfaces
    ///
    /// @param out specifies stream to print list of interfaces to
    void
    printIfaces(std::ostream& out = std::cout);

Tomek Mrugalski's avatar
Tomek Mrugalski committed
232
    /// @brief Sends an IPv6 packet.
233
    ///
Tomek Mrugalski's avatar
Tomek Mrugalski committed
234
    /// Sends an IPv6 packet. All parameters for actual transmission are specified in
235
236
    /// Pkt6 structure itself. That includes destination address, src/dst port
    /// and interface over which data will be sent.
237
238
239
240
    ///
    /// @param pkt packet to be sent
    ///
    /// @return true if sending was successful
Tomek Mrugalski's avatar
Tomek Mrugalski committed
241
    bool send(boost::shared_ptr<Pkt6>& pkt);
242

Tomek Mrugalski's avatar
Tomek Mrugalski committed
243
244
245
246
247
248
249
250
251
252
    /// @brief Sends an IPv4 packet.
    ///
    /// Sends an IPv4 packet. All parameters for actual transmission are specified
    /// in Pkt4 structure itself. That includes destination address, src/dst
    /// port and interface over which data will be sent.
    ///
    /// @param pkt a packet to be sent
    ///
    /// @return true if sending was successful
    bool send(boost::shared_ptr<Pkt4>& pkt);
253

Tomek Mrugalski's avatar
Tomek Mrugalski committed
254
    /// @brief Tries to receive IPv6 packet over open IPv6 sockets.
255
    ///
Tomek Mrugalski's avatar
Tomek Mrugalski committed
256
    /// Attempts to receive a single IPv6 packet of any of the open IPv6 sockets.
257
258
259
    /// If reception is successful and all information about its sender
    /// are obtained, Pkt6 object is created and returned.
    ///
260
261
262
    /// TODO Start using select() and add timeout to be able
    /// to not wait infinitely, but rather do something useful
    /// (e.g. remove expired leases)
263
    ///
264
    /// @return Pkt6 object representing received packet (or NULL)
265
    boost::shared_ptr<Pkt6> receive6();
266

Tomek Mrugalski's avatar
Tomek Mrugalski committed
267
268
269
270
271
272
273
274
275
276
277
    /// @brief Tries to receive IPv4 packet over open IPv4 sockets.
    ///
    /// Attempts to receive a single IPv4 packet of any of the open IPv4 sockets.
    /// If reception is successful and all information about its sender
    /// are obtained, Pkt4 object is created and returned.
    ///
    /// TODO Start using select() and add timeout to be able
    /// to not wait infinitely, but rather do something useful
    /// (e.g. remove expired leases)
    ///
    /// @return Pkt4 object representing received packet (or NULL)
278
279
    boost::shared_ptr<Pkt4> receive4();

280
281
282
283
284
285
286
287
288
    /// Opens UDP/IP socket and binds it to address, interface and port.
    ///
    /// Specific type of socket (UDP/IPv4 or UDP/IPv6) depends on passed addr
    /// family.
    ///
    /// @param ifname name of the interface
    /// @param addr address to be bound.
    /// @param port UDP port.
    ///
Tomek Mrugalski's avatar
Tomek Mrugalski committed
289
290
291
    /// Method will throw if socket creation, socket binding or multicast
    /// join fails.
    ///
292
    /// @return socket descriptor, if socket creation, binding and multicast
Tomek Mrugalski's avatar
Tomek Mrugalski committed
293
    /// group join were all successful.
294
295
296
    uint16_t openSocket(const std::string& ifname,
                        const isc::asiolink::IOAddress& addr, int port);

Tomek Mrugalski's avatar
Tomek Mrugalski committed
297
298
299
300
301
302
    /// Opens IPv6 sockets on detected interfaces.
    ///
    /// Will throw exception if socket creation fails.
    ///
    /// @param port specifies port number (usually DHCP6_SERVER_PORT)
    void openSockets(uint16_t port);
303

304
305
306
307
308

    /// @brief Closes all open sockets.
    /// Is used in destructor, but also from Dhcpv4_srv and Dhcpv6_srv classes.
    void closeSockets();

309
310
311
312
313
314
    // don't use private, we need derived classes in tests
protected:

    /// @brief Protected constructor.
    ///
    /// Protected constructor. This is a singleton class. We don't want
Tomek Mrugalski's avatar
Tomek Mrugalski committed
315
    /// anyone to create instances of IfaceMgr. Use instance() method instead.
316
317
318
319
    IfaceMgr();

    ~IfaceMgr();

Tomek Mrugalski's avatar
Tomek Mrugalski committed
320
321
322
323
324
325
326
327
328
329
330
    /// @brief Opens IPv4 socket.
    ///
    /// Please do not use this method directly. Use openSocket instead.
    ///
    /// This method may throw exception if socket creation fails.
    ///
    /// @param iface reference to interface structure.
    /// @param addr an address the created socket should be bound to
    /// @param port a port that created socket should be bound to
    ///
    /// @return socket descriptor
331
    uint16_t openSocket4(Iface& iface, const isc::asiolink::IOAddress& addr, int port);
332

Tomek Mrugalski's avatar
Tomek Mrugalski committed
333
334
335
336
337
338
339
340
341
342
343
    /// @brief Opens IPv6 socket.
    ///
    /// Please do not use this method directly. Use openSocket instead.
    ///
    /// This method may throw exception if socket creation fails.
    ///
    /// @param iface reference to interface structure.
    /// @param addr an address the created socket should be bound to
    /// @param port a port that created socket should be bound to
    ///
    /// @return socket descriptor
344
    uint16_t openSocket6(Iface& iface, const isc::asiolink::IOAddress& addr, int port);
345

Tomek Mrugalski's avatar
Tomek Mrugalski committed
346
347
348
    /// @brief Adds an interface to list of known interfaces.
    ///
    /// @param iface reference to Iface object.
349
350
351
352
    void addInterface(const Iface& iface) {
        ifaces_.push_back(iface);
    }

353
354
355
356
357
358
359
360
361
362
363
364
    /// @brief Detects network interfaces.
    ///
    /// This method will eventually detect available interfaces. For now
    /// it offers stub implementation. First interface name and link-local
    /// IPv6 address is read from intefaces.txt file.
    void
    detectIfaces();

    // TODO: having 2 maps (ifindex->iface and ifname->iface would)
    //      probably be better for performance reasons

    /// List of available interfaces
365
    IfaceCollection ifaces_;
366
367
368
369
370
371
372

    /// a pointer to a sole instance of this class (a singleton)
    static IfaceMgr * instance_;

    // TODO: Also keep this interface on Iface once interface detection
    // is implemented. We may need it e.g. to close all sockets on
    // specific interface
373
374
375
    //int recvsock_; // TODO: should be fd_set eventually, but we have only
    //int sendsock_; // 2 sockets for now. Will do for until next release

376
377
378
379
    // we can't use the same socket, as receiving socket
    // is bound to multicast address. And we all know what happens
    // to people who try to use multicast as source address.

380
    /// length of the control_buf_ array
381
382
    int control_buf_len_;

383
384
385
    /// control-buffer, used in transmission and reception
    boost::scoped_array<char> control_buf_;

386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
private:

    /// creates a single instance of this class (a singleton implementation)
    static void
    instanceCreate();

    /// @brief Joins IPv6 multicast group on a socket.
    ///
    /// Socket must be created and bound to an address. Note that this
    /// address is different than the multicast address. For example DHCPv6
    /// server should bind its socket to link-local address (fe80::1234...)
    /// and later join ff02::1:2 multicast group.
    ///
    /// @param sock socket fd (socket must be bound)
    /// @param ifname interface name (for link-scoped multicast groups)
    /// @param mcast multicast address to join (e.g. "ff02::1:2")
    ///
    /// @return true if multicast join was successful
    ///
    bool
    joinMcast(int sock, const std::string& ifname,
              const std::string& mcast);
408

409
410
411
};

}; // namespace isc::dhcp
412
}; // namespace isc
413
414

#endif