using namespace isc::asiolink;
using namespace isc::dhcp;
+typedef vector<struct nlmsghdr*> NetlinkMessages;
+
/// This is a structure that defines context for netlink connection.
struct rtnl_handle
{
- int fd;
+ int fd; // netlink file descriptor
struct sockaddr_nl local;
struct sockaddr_nl peer;
- __u32 seq;
- __u32 dump;
+ __u32 seq;
+ __u32 dump;
};
-struct nlmsg_list
-{
- struct nlmsg_list *next;
- struct nlmsghdr h;
-};
-
-const int sndbuf = 32768;
-const int rcvbuf = 32768;
+const size_t sndbuf = 32768;
+const size_t rcvbuf = 32768;
namespace isc {
+namespace dhcp {
/// @brief Opens netlink socket and initializes handle structure.
///
}
}
-/// @brief Appends nlmsg to a list
+/// @brief Appends nlmsg to a storage.
///
-/// @param n a message to be added
-/// @param link_info a list
-void rtnl_store_reply(struct nlmsghdr *n, struct nlmsg_list** link_info)
+/// @param storage a vector that holds netlink messages
+/// @param msg a netlink message to be added
+void rtnl_store_reply(NetlinkMessages& storage, const struct nlmsghdr *msg)
{
- struct nlmsg_list *h;
- struct nlmsg_list **lp;
-
- h = (nlmsg_list*)malloc(n->nlmsg_len+sizeof(void*));
- if (h == NULL) {
- isc_throw(Unexpected, "Failed to allocate " << n->nlmsg_len+sizeof(void*)
+ // we need to make a copy of this message. As those messages are variable size
+ // it is easier to use malloc + C-style case than do new char[X] and then
+ // reinterpret_cast<> to struct nlmsghdr.
+ struct nlmsghdr* copy = (struct nlmsghdr*)malloc(msg->nlmsg_len);
+ memcpy(copy, msg, msg->nlmsg_len);
+ if (copy == NULL) {
+ isc_throw(Unexpected, "Failed to allocate " << msg->nlmsg_len
<< " bytes.");
}
- memcpy(&h->h, n, n->nlmsg_len);
- h->next = NULL;
-
- for (lp = link_info; *lp; lp = &(*lp)->next) /* NOTHING */;
- *lp = h;
+ // push_back copies only pointer content, not the pointed object
+ storage.push_back(copy);
}
void parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
}
}
-void ipaddrs_get(IfaceMgr::Iface& iface, struct nlmsg_list *addr_info) {
+void ipaddrs_get(IfaceMgr::Iface& iface, NetlinkMessages& addr_info) {
uint8_t addr[16];
struct rtattr * rta_tb[IFA_MAX+1];
- for ( ;addr_info ; addr_info = addr_info->next) {
- struct nlmsghdr *n = &addr_info->h;
- struct ifaddrmsg *ifa = (ifaddrmsg*)NLMSG_DATA(n);
+ for (NetlinkMessages::const_iterator msg = addr_info.begin();
+ msg != addr_info.end(); ++msg) {
+ struct ifaddrmsg *ifa = (ifaddrmsg*)NLMSG_DATA(*msg);
// these are not the addresses you are looking for
if ( ifa->ifa_index != iface.getIndex()) {
if ( ifa->ifa_family == AF_INET6 ) {
memset(rta_tb, 0, sizeof(rta_tb));
- parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa), n->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
+ parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa), (*msg)->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
if (!rta_tb[IFA_LOCAL])
rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS];
if (!rta_tb[IFA_ADDRESS])
if ( ifa->ifa_family == AF_INET ) {
memset(rta_tb, 0, sizeof(rta_tb));
- parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa), n->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
+ parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa), (*msg)->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
if (!rta_tb[IFA_LOCAL])
rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS];
if (!rta_tb[IFA_ADDRESS])
}
}
-
-void rtnl_process_reply(struct rtnl_handle &rth, struct nlmsg_list *&info) {
+void rtnl_process_reply(const struct rtnl_handle& rth, NetlinkMessages& info) {
struct sockaddr_nl nladdr;
struct iovec iov;
char buf[rcvbuf];
iov.iov_base = buf;
- while (1) {
+ while (true) {
int status;
- struct nlmsghdr *h;
+ struct nlmsghdr* header;
iov.iov_len = sizeof(buf);
status = recvmsg(rth.fd, &msg, 0);
isc_throw(Unexpected, "EOF while reading netlink socket.");
}
- h = (struct nlmsghdr*)buf;
- while (NLMSG_OK(h, status)) {
+ header = (struct nlmsghdr*)buf;
+ while (NLMSG_OK(header, status)) {
// why we received this anyway?
if (nladdr.nl_pid != 0 ||
- h->nlmsg_pid != rth.local.nl_pid ||
- h->nlmsg_seq != rth.dump) {
- h = NLMSG_NEXT(h, status);
+ header->nlmsg_pid != rth.local.nl_pid ||
+ header->nlmsg_seq != rth.dump) {
+ header = NLMSG_NEXT(header, status);
continue;
}
- if (h->nlmsg_type == NLMSG_DONE) {
+ if (header->nlmsg_type == NLMSG_DONE) {
// end of message
return;
}
- if (h->nlmsg_type == NLMSG_ERROR) {
- struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
- if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
+ if (header->nlmsg_type == NLMSG_ERROR) {
+ struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(header);
+ if (header->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
// we are really out of luck here. We can't even say what is
// wrong as error message is truncated. D'oh.
isc_throw(Unexpected, "Netlink reply read failed.");
}
// store the data
- rtnl_store_reply(h, &info);
+ rtnl_store_reply(info, header);
- h = NLMSG_NEXT(h, status);
+ header = NLMSG_NEXT(header, status);
}
if (msg.msg_flags & MSG_TRUNC) {
isc_throw(Unexpected, "Message received over netlink truncated.");
/// @brief releases nlmsg list
///
-/// @param head first element of the list to be released
-void release_list(struct nlmsg_list *head) {
- struct nlmsg_list *tmp;
- while (head) {
- tmp = head->next;
- free(head);
- head = tmp;
+/// @param messages first element of the list to be released
+void release_list(NetlinkMessages& messages) {
+ // let's free our copies of stored messages
+ for (NetlinkMessages::iterator msg = messages.begin(); msg != messages.end(); ++msg) {
+ free(*msg);
}
+ messages.clear();
}
void IfaceMgr::detectIfaces() {
cout << "Linux: detecting interfaces." << endl;
- struct nlmsg_list* link_info = NULL; // link info list
- struct nlmsg_list* addr_info = NULL; // address info list
- struct nlmsg_list* l = NULL;
+ NetlinkMessages link_info; // link info
+ NetlinkMessages addr_info; // address info
struct rtnl_handle rth;
// required to display information about interface
rtnl_process_reply(rth, addr_info);
// Now build list with interface names
- for (l=link_info; l; l = l->next) {
- ifi = (ifinfomsg*)NLMSG_DATA(&l->h);
- len = (&l->h)->nlmsg_len;
+ for (NetlinkMessages::iterator msg = link_info.begin(); msg != link_info.end(); ++msg) {
+ // for (l=link_info; l; l = l->next) {
+ ifi = (ifinfomsg*)NLMSG_DATA(*msg);
+ len = (*msg)->nlmsg_len;
len -= NLMSG_LENGTH(sizeof(*ifi));
parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
flag_broadcast_ = flags & IFF_BROADCAST;
}
-}
+} // end of isc::dhcp namespace
+
+} // end of isc namespace
#endif // if defined(LINUX)