summaryrefslogtreecommitdiffstats
path: root/watchlink/netlink_linkstatus.cc
diff options
context:
space:
mode:
Diffstat (limited to 'watchlink/netlink_linkstatus.cc')
-rw-r--r--watchlink/netlink_linkstatus.cc318
1 files changed, 318 insertions, 0 deletions
diff --git a/watchlink/netlink_linkstatus.cc b/watchlink/netlink_linkstatus.cc
new file mode 100644
index 00000000..9dd26fbd
--- /dev/null
+++ b/watchlink/netlink_linkstatus.cc
@@ -0,0 +1,318 @@
+/*
+ * Module: netlink_linkstatus.cc
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+#include <stdio.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <iostream>
+#include <string>
+#include <syslog.h>
+#include <errno.h>
+
+#include "rl_str_proc.hh"
+#include "netlink_send.hh"
+#include "netlink_event.hh"
+#include "netlink_utils.hh"
+#include "netlink_linkstatus.hh"
+
+
+using namespace std;
+
+/**
+ *
+ *
+ **/
+NetlinkLinkStatus::NetlinkLinkStatus(int send_sock, const string &link_dir, bool debug) :
+ _nl_send(debug),
+ _send_sock(send_sock),
+ _link_dir(link_dir),
+ _debug(debug)
+{
+ if (_send_sock < 0) {
+ syslog(LOG_ERR,"NetlinkListStatus::NetlinkLinkStatus(), send sock is bad value");
+ cerr << "NetlinkListStatus::NetlinkLinkStatus(), send sock is bad value" << endl;
+ }
+
+ if (_link_dir.empty()) {
+ syslog(LOG_ERR,"NetlinkListStatus::NetlinkLinkStatus(), no link status directory specified");
+ cerr << "NetlinkListStatus::NetlinkLinkStatus(), no link status directory specified" << endl;
+ }
+}
+
+/**
+ *
+ *
+ **/
+NetlinkLinkStatus::~NetlinkLinkStatus()
+{
+}
+
+/**
+ *
+ *
+ **/
+void
+NetlinkLinkStatus::process(const NetlinkEvent &event)
+{
+ bool state_event = false;
+
+ IfaceStateIter iter = _iface_state_coll.find(event.get_index());
+ if (iter == _iface_state_coll.end()) {
+ if (event.get_type() == RTM_NEWLINK || event.get_type() == RTM_DELLINK) {
+ //start maintaining state information here.
+ _iface_state_coll.insert(pair<int,bool>(event.get_index(),event.get_running()));
+
+ //let's clean up directory here!
+ char buf[40];
+ sprintf(buf,"%d",event.get_index());
+ string file = _link_dir + "/" + buf;
+ unlink(file.c_str());
+ }
+ return;
+ }
+
+ bool running_old = iter->second;
+ bool running_new = event.get_running();
+
+ //capture link status on link messages only
+ if (event.get_type() == RTM_NEWLINK ||
+ event.get_type() == RTM_DELLINK) {
+ // _iface_state_coll.insert(pair<int,bool>(event.get_index(),event.get_running()));
+ _iface_state_coll[event.get_index()] = event.get_running();
+ if (running_old != running_new) {
+ state_event = true;
+ }
+ }
+
+ //is this a transition from up->down, or down->up?
+ if (state_event) {
+ if (running_new) {
+ process_going_up(event);
+ }
+ else {
+ process_going_down(event);
+ }
+ }
+ else {
+ if (running_old) {
+ process_up(event);
+ }
+ else {
+ process_down(event);
+ }
+ }
+}
+
+/**
+ *
+ * file is in the format of IFINDEX,IP,MASK
+ *
+ **/
+int
+NetlinkLinkStatus::process_up(const NetlinkEvent &event)
+{
+ if (_debug) {
+ cout << "NetlinkLinkStatus::process_up(): " << event.get_iface() << endl;
+ }
+ //can't think of anything that needs to go here yet.
+ return 0;
+}
+
+/**
+ *
+ *
+ **/
+int
+NetlinkLinkStatus::process_going_up(const NetlinkEvent &event)
+{
+ if (_debug) {
+ cout << "NetlinkLinkStatus::process_going_up(): " << event.get_iface() << endl;
+ }
+ syslog(LOG_INFO,"Interface is now active: %s",event.get_iface().c_str());
+
+ //check for link status file, otherwise return
+ char buf[40];
+ sprintf(buf,"%d",event.get_index());
+ string file = _link_dir + "/" + buf;
+ FILE *fp = fopen(file.c_str(), "r");
+ if (fp == NULL) {
+ syslog(LOG_INFO,"NetlinkLinkStatus::process_going_up(), failed to open state file: %s",
+ strerror(errno));
+ // cerr << "NetlinkLinkStatus::process_going_up(), failed to open state file" << endl;
+ return -1; //means we are still up, ignore...
+ }
+
+ if (flock(fileno(fp), LOCK_SH)) {
+ syslog(LOG_INFO, "NetlinkLinkStatus::process_going_up() failed to acquire lock: %s",
+ strerror(errno));
+ fclose(fp);
+ return -1;
+ }
+
+ char str[1025];
+ while (fgets(str, 1024, fp)) {
+ string line(str);
+
+ StrProc tokens(line, ",");
+ if (tokens.size() != 4) {
+ syslog(LOG_INFO,"NetlinkLinkStatus::process_up(), failure to parse link status file, exiting(): %s, size: %d", line.c_str(), tokens.size());
+ // cerr << "NetlinkLinkStatus::process_up(), failure to parse link status file, exiting(): " << line << ", size: " << tokens.size() << endl;
+ fclose(fp);
+ return -1;
+ }
+
+ int ifindex = strtoul(tokens.get(0).c_str(),NULL,10);
+ uint32_t local_addr = strtoul(tokens.get(1).c_str(),NULL,10);
+ uint32_t addr = strtoul(tokens.get(2).c_str(),NULL,10);
+ int mask_len = strtoul(tokens.get(3).c_str(),NULL,10);
+
+
+ bool err = _nl_send.send_set(_send_sock, ifindex, local_addr, addr, mask_len, RTM_NEWADDR);
+ if (err) {
+ syslog(LOG_INFO,"NetlinkLinkStatus::process_up(), failure in setting interface back to up");
+ }
+ /*
+ bool err = _nl_send.send_set_route(_send_sock, ifindex, local_addr, local_addr, 32, RTM_NEWROUTE, RT_TABLE_LOCAL, RTN_LOCAL, RT_SCOPE_HOST);
+ if (err) {
+ syslog(LOG_INFO,"NetlinkLinkStatus::process_up(), failure in setting interface back to up");
+ }
+ //COMPUTE FIRST ADDRESS
+ uint32_t first_addr = ipv4_first_addr(local_addr, mask_len);
+ err = _nl_send.send_set_route(_send_sock, ifindex, local_addr, first_addr, 32, RTM_NEWROUTE, RT_TABLE_LOCAL, RTN_BROADCAST, RT_SCOPE_LINK);
+ if (err) {
+ syslog(LOG_INFO,"NetlinkLinkStatus::process_up(), failure in setting interface back to up");
+ }
+ //COMPUTE LAST ADDRESS
+ uint32_t last_addr = ipv4_broadcast_addr(local_addr, mask_len);
+ err = _nl_send.send_set_route(_send_sock, ifindex, local_addr, last_addr, 32, RTM_NEWROUTE, RT_TABLE_LOCAL, RTN_BROADCAST, RT_SCOPE_LINK);
+ if (err) {
+ syslog(LOG_INFO,"NetlinkLinkStatus::process_up(), failure in setting interface back to up");
+ }
+
+ //reinsert addresses to interface
+ err = _nl_send.send_set_route(_send_sock, ifindex, local_addr, first_addr, mask_len, RTM_NEWROUTE, RT_TABLE_MAIN, RTN_UNICAST, RT_SCOPE_LINK);
+ if (err) {
+ syslog(LOG_INFO,"NetlinkLinkStatus::process_up(), failure in setting interface back to up");
+ }
+ */
+ }
+
+ fclose(fp);
+
+ //remove file
+ unlink(file.c_str());
+
+ return 0;
+}
+
+/**
+ * send an ip flush command and capture all the rtm_deladdr messages to the file...
+ *
+ **/
+int
+NetlinkLinkStatus::process_down(const NetlinkEvent &event)
+{
+ if (_debug) {
+ cout << "NetlinkLinkStatus::process_down(): " << event.get_iface() << endl;
+ }
+
+ if (event.get_type() != RTM_NEWADDR) {
+ return 0;
+ }
+
+ if (event.get_index() < 0 || event.get_local_addr().get() == 0 || event.get_mask_len() < 1) {
+ return 0;
+ }
+
+ if (_debug) {
+ cout << "netlinkLinkStatus::process_down(), processing valid request" << endl;
+ }
+
+ //append to file...
+ char buf[40];
+ sprintf(buf,"%d",event.get_index());
+ string file = _link_dir + "/" + buf;
+ FILE *fp = fopen(file.c_str(), "a");
+ if (fp == NULL) {
+ syslog(LOG_INFO,"NetlinkLinkStatus::process_down(), failed to open state file");
+ // cerr << "NetlinkLinkStatus::process_down(), failed to open state file" << endl;
+ return -1;
+ }
+
+ if (flock(fileno(fp), LOCK_EX)) {
+ syslog(LOG_INFO, "NetlinkLinkStatus::process_down() failed to acquire lock: %s",
+ strerror(errno));
+ fclose(fp);
+ return -1;
+ }
+
+ int ifindex = event.get_index();
+ uint32_t local_addr = event.get_local_addr().get();
+ int mask_len = event.get_mask_len();
+
+ //create file on system
+ //CRAJ--NEED TO HAVE THIS BE FROM A COLLECTION??? DEPENDS ON FORMAT OF NETLINK MSG
+ sprintf(buf,"%d",ifindex);
+ string line = string(buf) + ",";
+ sprintf(buf,"%d",local_addr);
+ line += string(buf) + ",";
+ sprintf(buf,"%d",event.get_addr().get());
+ line += string(buf) + ",";
+ sprintf(buf,"%d",mask_len);
+ line += string(buf) + "\n";
+
+ fputs(line.c_str(),fp);
+
+ bool err = _nl_send.send_set(_send_sock, ifindex, event.get_local_addr().get(), event.get_addr().get(), mask_len, RTM_DELADDR);
+ if (err) {
+ syslog(LOG_INFO,"NetlinkLinkStatus::process_down(), failure in setting interface down");
+ }
+
+ /*
+ uint32_t first_addr = ipv4_first_addr(local_addr, mask_len);
+ //reinsert addresses to interface
+ bool err = _nl_send.send_set_route(_send_sock, ifindex, local_addr, first_addr, mask_len, RTM_DELROUTE, RT_TABLE_MAIN, -1,-1);
+ if (err) {
+ syslog(LOG_INFO,"NetlinkLinkStatus::process_down(), failure in setting interface down");
+ }
+
+ uint32_t last_addr = ipv4_broadcast_addr(local_addr, mask_len);
+ err = _nl_send.send_set_route(_send_sock, ifindex, local_addr, last_addr, 32, RTM_DELROUTE, RT_TABLE_LOCAL, -1,-1);
+ if (err) {
+ syslog(LOG_INFO,"NetlinkLinkStatus::process_down(), failure in setting interface down");
+ }
+
+ err = _nl_send.send_set_route(_send_sock, ifindex, first_addr, first_addr, 32, RTM_DELROUTE, RT_TABLE_LOCAL, -1,-1);
+ if (err) {
+ syslog(LOG_INFO,"NetlinkLinkStatus::process_down(), failure in setting interface down");
+ }
+
+ err = _nl_send.send_set_route(_send_sock, ifindex, local_addr, local_addr, 32, RTM_DELROUTE, RT_TABLE_LOCAL, -1,-1);
+ if (err) {
+ syslog(LOG_INFO,"NetlinkLinkStatus::process_down(), failure in setting interface down");
+ }
+ */
+ fclose(fp);
+
+ return 0;
+}
+
+int
+NetlinkLinkStatus::process_going_down(const NetlinkEvent &event)
+{
+ if (_debug) {
+ cout << "NetlinkLinkStatus::process_going_down(): " << event.get_iface() << "(" << event.get_index() << ")" << endl;
+ }
+ syslog(LOG_INFO,"Interface is now inactive: %s",event.get_iface().c_str());
+
+ //pull interface addresses
+ if (_nl_send.send_get(_send_sock, RTM_GETADDR, event.get_index())) {
+ return -1;
+ }
+ return 0;
+}