summaryrefslogtreecommitdiff
path: root/src/lbdecision.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/lbdecision.cc')
-rw-r--r--src/lbdecision.cc318
1 files changed, 318 insertions, 0 deletions
diff --git a/src/lbdecision.cc b/src/lbdecision.cc
new file mode 100644
index 0000000..79e86cb
--- /dev/null
+++ b/src/lbdecision.cc
@@ -0,0 +1,318 @@
+/*
+ * Module: lbdecision.cc
+ *
+ * **** License ****
+ * Version: VPL 1.0
+ *
+ * The contents of this file are subject to the Vyatta Public License
+ * Version 1.0 ("License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.vyatta.com/vpl
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * This code was originally developed by Vyatta, Inc.
+ * Portions created by Vyatta are Copyright (C) 2007 Vyatta, Inc.
+ * All Rights Reserved.
+ *
+ * Author: Michael Larson
+ * Date: 2007
+ * Description:
+ *
+ * **** End License ****
+ *
+ */
+#include <syslog.h>
+#include <iostream>
+#include "lbdata.hh"
+#include "lbdecision.hh"
+
+using namespace std;
+
+/*
+iptables -t mangle -N ISP1
+iptables -t mangle -A ISP1 -j CONNMARK --set-mark 1
+iptables -t mangle -A ISP1 -j MARK --set-mark 1
+iptables -t mangle -A ISP1 -j ACCEPT
+
+iptables -t mangle -N ISP2
+iptables -t mangle -A ISP2 -j CONNMARK --set-mark 2
+iptables -t mangle -A ISP2 -j MARK --set-mark 2
+iptables -t mangle -A ISP2 -j ACCEPT
+
+
+#THIS APPEARS TO ROUGHLY WORK BELOW, AND CAN BE SET UP WITH SPECIFIC FILTERS.
+iptables -t mangle -A PREROUTING -i eth0 -m statistic --mode nth --every 2 --packet 0 -j ISP1
+iptables -t mangle -A PREROUTING -i eth0 -j ISP2
+
+#iptables -t mangle -A PREROUTING -i eth0 -m state --state NEW -m statistic --mode random --probability .01 -j MARK --set-mark 1
+#iptables -t mangle -A PREROUTING -i eth0 -j MARK --set-mark 2
+
+iptables -t raw -N NAT_CONNTRACK
+iptables -t raw -A NAT_CONNTRACK -j ACCEPT
+iptables -t raw -I PREROUTING 1 -j NAT_CONNTRACK
+iptables -t raw -I OUTPUT 1 -j NAT_CONNTRACK
+ip ro add table 10 default via 192.168.1.2 dev eth1
+ip ru add fwmark 1 table 10
+ip ro fl ca
+ip ro add table 20 default via 192.168.2.2 dev eth2
+ip ru add fwmark 2 table 20
+ip ro fl ca
+
+*/
+
+
+/**
+ *
+ *
+ **/
+LBDecision::LBDecision()
+{
+
+}
+
+/**
+ *
+ *
+ **/
+LBDecision::~LBDecision()
+{
+ shutdown();
+}
+
+/**
+ *
+ *
+ **/
+void
+LBDecision::init(LBData &lbdata)
+{
+ //here is where we set up iptables and policy routing for the interfaces
+ /*
+ iptables -t mangle -N ISP1
+ iptables -t mangle -A ISP1 -j CONNMARK --set-mark 1
+ iptables -t mangle -A ISP1 -j MARK --set-mark 1
+ iptables -t mangle -A ISP1 -j ACCEPT
+ */
+
+ char buf[20];
+ int ct = 1;
+
+ /*
+ do we need:
+iptables -t raw -N NAT_CONNTRACK
+iptables -t raw -A NAT_CONNTRACK -j ACCEPT
+iptables -t raw -I PREROUTING 1 -j NAT_CONNTRACK
+iptables -t raw -I OUTPUT 1 -j NAT_CONNTRACK
+
+if so then this stuff goes here!
+ */
+
+
+ //note: doesn't appear to clean up rule table, may need to individually erase each rule
+ // execute(string("ip rule flush"));
+
+ LBData::InterfaceHealthIter iter = lbdata._iface_health_coll.begin();
+ while (iter != lbdata._iface_health_coll.end()) {
+ string iface = iter->first;
+ sprintf(buf,"%d",ct);
+ execute(string("iptables -t mangle -N ISP_") + buf);
+ execute(string("iptables -t mangle -F ISP_") + buf);
+ execute(string("iptables -t mangle -A ISP_") + buf + " -j CONNMARK --set-mark " + buf);
+ execute(string("iptables -t mangle -A ISP_") + buf + " -j MARK --set-mark " + buf);
+
+ //NOTE, WILL NEED A WAY TO CLEAN UP THIS RULE ON RESTART...
+ execute(string("iptables -t mangle -A ISP_") + buf + " -j ACCEPT");
+
+ execute(string("ip route replace table ") + buf + " default dev " + iface);
+ execute(string("ip rule add fwmark ") + buf + " table " + buf);
+
+ _iface_mark_coll.insert(pair<string,int>(iface,ct));
+ ++ct;
+ ++iter;
+ }
+ execute("ip route flush cache");
+}
+
+
+/**
+ * only responsible for
+
+iptables -t mangle -A PREROUTING -i eth0 -m state --state NEW -m statistic --mode random --probability .01 -j MARK --set-mark 1
+iptables -t mangle -A PREROUTING -i eth0 -j MARK --set-mark 2
+
+ *
+ *
+ *
+ **/
+void
+LBDecision::run(LBData &lb_data)
+{
+#ifdef DEBUG
+ cout << "LBDecision::run(), starting decision" << endl;
+#endif
+
+ //first determine if we need to alter the rule set
+ if (!lb_data.state_changed()) {
+ return;
+ }
+
+#ifdef DEBUG
+ cout << "LBDecision::run(), state changed, applying new rule set" << endl;
+#endif
+
+ //then if we do, flush all
+ execute("iptables -t mangle -F PREROUTING");
+
+ //and compute the new set and apply
+ LBData::LBRuleIter iter = lb_data._lb_rule_coll.begin();
+ while (iter != lb_data._lb_rule_coll.end()) {
+ map<int,float> weights = get_new_weights(lb_data,iter->second);
+ map<int,float>::iterator w_iter = weights.begin();
+ map<int,float>::iterator w_end = weights.end();
+ if (w_iter == w_end) {
+ ++iter;
+ continue;
+ }
+ else {
+ --w_end;
+ }
+
+ //NEED TO HANDLE APPLICATION SPECIFIC DETAILS
+ string app_cmd = get_application_cmd(iter->second);
+
+ char fbuf[20],dbuf[20];
+ while (w_iter != w_end) {
+ sprintf(fbuf,"%f",w_iter->second);
+ sprintf(dbuf,"%d",w_iter->first);
+ execute(string("iptables -t mangle -A PREROUTING ") + app_cmd + " -m state --state NEW -m statistic --mode random --probability " + fbuf + " -j ISP_" + dbuf);
+ ++w_iter;
+ }
+ //last one is special case, the catch all rule
+ ++w_iter;
+ sprintf(dbuf,"%d",w_iter->first);
+ execute(string("iptables -t mangle -A PREROUTING ") + app_cmd + " -j ISP_" + dbuf);
+ ++iter;
+ }
+}
+
+/**
+ *
+ *
+ **/
+void
+LBDecision::shutdown()
+{
+ char buf[20];
+
+ //then if we do, flush all
+ execute("iptables -t mangle -F PREROUTING");
+
+ //remove the policy entries
+ InterfaceMarkIter iter = _iface_mark_coll.begin();
+ while (iter != _iface_mark_coll.end()) {
+ sprintf(buf,"%d",iter->second);
+ execute(string("ip rule del fwmark ") + buf);
+ ++iter;
+ }
+}
+
+/**
+ *
+ *
+ **/
+void
+LBDecision::execute(string cmd)
+{
+#ifdef DEBUG
+ cout << "LBDecision::execute(): applying command to system: " << cmd << endl;
+#endif
+
+ FILE *f = popen(cmd.c_str(), "w");
+ if (f) {
+ if (pclose(f) != 0) {
+ cerr << "LBDecision::execute(): error executing command: " << cmd << endl;
+ syslog(LOG_ERR, "Error executing system command: %s", cmd.c_str());
+ }
+ }
+ else {
+ cerr << "LBDecision::execute(): error executing command: " << cmd << endl;
+ syslog(LOG_ERR, "Error executing system command: %s", cmd.c_str());
+ }
+}
+
+map<int,float>
+LBDecision::get_new_weights(LBData &data, LBRule &rule)
+{
+ map<int,float> weights;
+ int group = 0;
+ int ct = 1;
+ LBRule::InterfaceDistIter iter = rule._iface_dist_coll.begin();
+ while (iter != rule._iface_dist_coll.end()) {
+#ifdef DEBUG
+ cout << "LBDecision::get_new_weights(): " << iter->first << " is active: " << (data.is_active(iter->first) ? "true" : "false") << endl;
+#endif
+ if (data.is_active(iter->first)) {
+ weights.insert(pair<int,float>(ct,iter->second));
+ group += iter->second;
+ }
+ ++ct;
+ ++iter;
+ }
+
+ //now weight the overall distribution
+ map<int,float>::iterator w_iter = weights.begin();
+ while (w_iter != weights.end()) {
+ float w = float(w_iter->second) / float(group);
+ group -= w_iter->second; //I THINK THIS NEEDS TO BE ADJUSTED TO THE OVERALL REMAINING VALUES. which is this...
+ w_iter->second = w;
+ ++w_iter;
+ }
+
+ return weights;
+}
+
+/**
+ *
+ *
+ **/
+string
+LBDecision::get_application_cmd(LBRule &rule)
+{
+ string filter;
+
+ if (rule._proto.empty() == false) {
+ filter += "--proto " + rule._proto + " ";
+ }
+
+ if (rule._proto == "icmp") {
+ filter += "--icmp-type any ";
+ }
+ else if (rule._proto == "udp" || rule._proto == "tcp") {
+ if (rule._s_addr.empty() == false) {
+ filter += "--source " + rule._s_addr + " ";
+ }
+ else if (rule._s_net.empty() == false) {
+ filter += "--source " + rule._s_net + " ";
+ }
+
+ if (rule._d_addr.empty() == false) {
+ filter += "--destination " + rule._d_addr + " ";
+ }
+ else if (rule._d_net.empty() == false) {
+ filter += "--destination " + rule._d_net + " ";
+ }
+
+ if (rule._s_port_name.empty() == false) {
+ filter += "--source-port " + rule._s_port_name + " ";
+ }
+ else if (rule._s_port_num.empty() == false) {
+ filter += "--source-port " + rule._s_port_num + " ";
+ }
+ }
+
+ return filter;
+}