All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.sdnwiselab.sdnwise.controller.Controller Maven / Gradle / Ivy

/* 
 * Copyright (C) 2015 SDN-WISE
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */
package com.github.sdnwiselab.sdnwise.controller;

import com.github.sdnwiselab.sdnwise.adapter.Adapter;
import com.github.sdnwiselab.sdnwise.flowtable.FlowTableEntry;
import com.github.sdnwiselab.sdnwise.packet.NetworkPacket;
import com.github.sdnwiselab.sdnwise.packet.ReportPacket;
import com.github.sdnwiselab.sdnwise.util.NodeAddress;
import java.util.ArrayList;
import java.util.Arrays;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Observable;
import java.util.Observer;
import java.util.Scanner;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.jodah.expiringmap.ExpiringMap;

/**
 * This class holds a representation of the sensor network and resolves all the
 * requests coming from the network itself. This abstract class has two main
 * methods. manageRoutingRequest and graphUpdate. The first is called when a
 * request is coming from the network while the latter is called when something
 * in the tolopogy of the network changes.
 * 

* There are two main implementation of this class: ControllerDijkstra and * Controller Static. *

* This class also offers methods to send messages and configure the nodes in * the network. * * @author Sebastiano Milardo * @version 0.1 */ public abstract class Controller implements Observer, Runnable { final static byte SDN_WISE_DATA = 0; final static byte SDN_WISE_BEACON = 1; final static byte SDN_WISE_REPORT = 2; final static byte SDN_WISE_RESPONSE = 4; final static byte SDN_WISE_OPEN_PATH = 5; final static byte SDN_WISE_CONFIG = 6; final static int SDN_WISE_CNF_READ = 0; final static int SDN_WISE_CNF_WRITE = 128; final static int SDN_WISE_CNF_ID_ADDR = 0; final static int SDN_WISE_CNF_ID_NET_ID = 1; final static int SDN_WISE_CNF_ID_CNT_BEACON_MAX = 2; final static int SDN_WISE_CNF_ID_CNT_REPORT_MAX = 3; final static int SDN_WISE_CNF_ID_CNT_UPDTABLE_MAX = 4; final static int SDN_WISE_CNF_ID_CNT_SLEEP_MAX = 5; final static int SDN_WISE_CNF_ID_TTL_MAX = 6; final static int SDN_WISE_CNF_ID_RSSI_MIN = 7; final static int SDN_WISE_CNF_ADD_ACCEPTED = 8; final static int SDN_WISE_CNF_REMOVE_ACCEPTED = 9; final static int SDN_WISE_CNF_LIST_ACCEPTED = 10; final static int SDN_WISE_CNF_ADD_RULE = 11; final static int SDN_WISE_CNF_REMOVE_RULE = 12; final static int SDN_WISE_CNF_REMOVE_RULE_INDEX = 13; final static int SDN_WISE_CNF_LIST_RULE = 14; final static int SDN_WISE_CNF_RESET = 15; final static int SDN_WISE_RLS_MAX = 16; final static int RESPONSE_TIMEOUT = 250; final Adapter lower; final Scanner scanner; final NetworkGraph networkGraph; final HashMap> results; private boolean isStopped; private final ArrayBlockingQueue bQ; private final Map cache = ExpiringMap.builder() .expiration(5, TimeUnit.SECONDS) .build(); private ControllerId id; public abstract void manageRoutingRequest(NetworkPacket data); public abstract void graphUpdate(); public abstract void setupNetwork(); Controller(ControllerId id, Adapter lower, NetworkGraph networkGraph) { this.id = id; this.lower = lower; bQ = new ArrayBlockingQueue<>(1000); this.networkGraph = networkGraph; results = new HashMap<>(); scanner = new Scanner(System.in, "UTF-8"); isStopped = false; } public final ControllerId getId(){ return id; } public final void setId(ControllerId id){ this.id = id; } private void managePacket(NetworkPacket data) { switch (data.getType()) { case SDN_WISE_REPORT: networkGraph.updateMap(new ReportPacket(data.toByteArray())); break; case SDN_WISE_DATA: case SDN_WISE_BEACON: case SDN_WISE_RESPONSE: case SDN_WISE_OPEN_PATH: break; case SDN_WISE_CONFIG: if (data.getPayload()[0] == SDN_WISE_CNF_LIST_RULE) { cache.put(data.getNetId() + " " + data.getSrc() + " " + data.getPayload()[0] + " " + data.getPayload()[2], data); } else { cache.put(data.getNetId() + " " + data.getSrc() + " " + data.getPayload()[0], data); } break; default: manageRoutingRequest(data); break; } } /** * This methods manages updates coming from the lower adapter or the network * representation. When a message is received from the lower adapter it is * inserted in a ArrayBlockingQueue and then the method managePacket it is * called on it. While for updates coming from the network representation * the method graphUpdate is invoked. * * @param o * @param arg */ @Override public final void update(Observable o, Object arg) { if (o.equals(lower)) { try { bQ.put(new NetworkPacket((byte[]) arg)); } catch (InterruptedException ex) { Logger.getLogger(ControllerDijkstra.class.getName()).log( Level.SEVERE, null, ex); } } else if (o.equals(networkGraph)) { graphUpdate(); } } /** * Starts the working thread that manages incoming requests and it listens * to messages coming from the standard input. */ @Override public final void run() { if (lower.open()) { Thread th = new Thread(new Worker(bQ)); th.start(); lower.addObserver(this); networkGraph.addObserver(this); register(); setupNetwork(); while (!isStopped) { if (scanner.nextLine().equals("exit -l Controller")) { isStopped = true; } } lower.close(); } } public Adapter getLower() { return lower; } /** * This method sends a SDN_WISE_OPEN_PATH messages to a generic node. This * kind of message holds a list of nodes that will create a path inside the * network. * * @param netId network id of the destination node * @param destination network address of the destination node * @param path the list of all the NodeAddresses in the path */ public final void sendPath(int netId, NodeAddress destination, List path) { byte[] message = new byte[(path.size() * 2)]; int i = 0; for (NodeAddress addr : path) { message[i] = addr.getHigh(); i++; message[i] = addr.getLow(); i++; } sendMessage(netId, destination, (byte) 5, message); } /** * This method sends a generic message to a node. The message is represented * by an array of bytes. * * * @param netId network id of the destination node * @param destination network address of the destination node * @param type the type of message that will be sent * @param message the content of the message to be sent */ public final void sendMessage(int netId, NodeAddress destination, byte type, byte[] message) { byte[] response = new byte[10 + message.length]; response[0] = (byte) response.length; response[1] = (byte) netId; response[2] = 0; response[3] = 0; response[4] = destination.getHigh(); response[5] = destination.getLow(); response[6] = type; response[7] = 20; response[8] = 0; response[9] = 0; System.arraycopy(message, 0, response, 10, message.length); lower.send(response); } public final void sendMessage(NetworkPacket packet){ lower.send(packet.toByteArray()); } /** * This method sets the address of a node. The new address value is passed * using two bytes. * * * @param netId network id of the destination node * @param destination network address of the destination node * @param high high byte of the new address * @param low low byte of the new address */ public final void setNodeAddress(int netId, NodeAddress destination, int high, int low) { byte[] message = new byte[3]; message[0] = (byte) (SDN_WISE_CNF_WRITE + SDN_WISE_CNF_ID_ADDR); message[1] = (byte) (high & 0xFF); message[2] = (byte) (low & 0xFF); sendMessage(netId, destination, SDN_WISE_CONFIG, message); } /** * This method reads the address of a node. * * @param netId network id of the destination node * @param destination network address of the destination node * @return returns the NodeAddress of a node, null if it does exists. */ public final NodeAddress getNodeAddress(int netId, NodeAddress destination) { byte[] message = new byte[3]; message[0] = (byte) (SDN_WISE_CNF_READ + SDN_WISE_CNF_ID_ADDR); message[1] = (byte) (0); message[2] = (byte) (0); sendMessage(netId, destination, SDN_WISE_CONFIG, message); try { Thread.sleep(RESPONSE_TIMEOUT); } catch (InterruptedException ex) { Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex); } if (cache.containsKey(netId + " " + destination.toString() + " " + message[0])) { NetworkPacket data = cache.remove(netId + " " + destination.toString() + " " + message[0]); return new NodeAddress(data.getPayload()[1] & 0xFF, data.getPayload()[2] & 0xFF); } else { return null; } } /** * This method sets the Network ID of a node. The new value is passed using * a byte. * * @param netId network id of the destination node * @param destination network address of the destination node * @param newNetId value of the new net ID */ public final void resetNode(int netId, NodeAddress destination) { byte[] message = new byte[3]; message[0] = (byte) (SDN_WISE_CNF_WRITE + SDN_WISE_CNF_RESET); message[1] = 0; message[2] = 0; sendMessage(netId, destination, SDN_WISE_CONFIG, message); } /** * This method sets the Network ID of a node. The new value is passed using * a byte. * * @param netId network id of the destination node * @param destination network address of the destination node * @param newNetId value of the new net ID */ public final void setNodeNetId(int netId, NodeAddress destination, int newNetId) { byte[] message = new byte[3]; message[0] = (byte) (SDN_WISE_CNF_WRITE + SDN_WISE_CNF_ID_NET_ID); message[1] = 0; message[2] = (byte) (newNetId & 0xFF); sendMessage(netId, destination, SDN_WISE_CONFIG, message); } /** * This method reads the Network ID of a node. * * @param netId network id of the destination node * @param destination network address of the destination node * @return returns the nedId, -1 if not found */ public final int getNodeNetId(int netId, NodeAddress destination) { byte[] message = new byte[3]; message[0] = (byte) (SDN_WISE_CNF_READ + SDN_WISE_CNF_ID_NET_ID); message[1] = 0; message[2] = 0; sendMessage(netId, destination, SDN_WISE_CONFIG, message); try { Thread.sleep(RESPONSE_TIMEOUT); } catch (InterruptedException ex) { Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex); } if (cache.containsKey(netId + " " + destination.toString() + " " + message[0])) { NetworkPacket data = cache.remove(netId + " " + destination.toString() + " " + message[0]); return data.getPayload()[2] & 0xFF; } else { return -1; } } /** * This method sets the beacon period of a node. The new value is passed * using a short. * * @param netId network id of the destination node * @param destination network address of the destination node * @param period beacon period in seconds (TODO check) */ public final void setNodeBeaconPeriod(int netId, NodeAddress destination, short period) { byte[] message = new byte[3]; message[0] = (byte) (SDN_WISE_CNF_WRITE + SDN_WISE_CNF_ID_CNT_BEACON_MAX); message[1] = (byte) (period >> 8); message[2] = (byte) (period & 0xFF); sendMessage(netId, destination, SDN_WISE_CONFIG, message); } /** * This method reads the beacon period of a node. * * @param netId network id of the destination node * @param destination network address of the destination node * @return returns the beacon period, -1 if not found */ public final int getNodeBeaconPeriod(int netId, NodeAddress destination) { byte[] message = new byte[3]; message[0] = (byte) (SDN_WISE_CNF_READ + SDN_WISE_CNF_ID_CNT_BEACON_MAX); message[1] = 0; message[2] = 0; sendMessage(netId, destination, SDN_WISE_CONFIG, message); try { Thread.sleep(RESPONSE_TIMEOUT); } catch (InterruptedException ex) { Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex); } if (cache.containsKey(netId + " " + destination.toString() + " " + message[0])) { NetworkPacket data = cache.remove(netId + " " + destination.toString() + " " + message[0]); return (((data.getPayload()[1] & 0xFF) << 8) + (data.getPayload()[2] & 0xFF)); } else { return -1; } } /** * This method sets the report period of a node. The new value is passed * using a short. * * @param netId network id of the destination node * @param destination network address of the destination node * @param period report period in seconds (TODO check) */ public final void setNodeReportPeriod(int netId, NodeAddress destination, short period) { byte[] message = new byte[3]; message[0] = (byte) (SDN_WISE_CNF_WRITE + SDN_WISE_CNF_ID_CNT_REPORT_MAX); message[1] = (byte) (period >> 8); message[2] = (byte) (period & 0xFF); sendMessage(netId, destination, SDN_WISE_CONFIG, message); } /** * This method reads the report period of a node. * * @param netId network id of the destination node * @param destination network address of the destination node * @return returns the report period, -1 if not found */ public final int getNodeReportPeriod(int netId, NodeAddress destination) { byte[] message = new byte[3]; message[0] = (byte) (SDN_WISE_CNF_READ + SDN_WISE_CNF_ID_CNT_REPORT_MAX); message[1] = (byte) 0; message[2] = (byte) 0; sendMessage(netId, destination, SDN_WISE_CONFIG, message); try { Thread.sleep(RESPONSE_TIMEOUT); } catch (InterruptedException ex) { Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex); } if (cache.containsKey(netId + " " + destination.toString() + " " + message[0])) { NetworkPacket data = cache.remove(netId + " " + destination.toString() + " " + message[0]); return (((data.getPayload()[1] & 0xFF) << 8) + (data.getPayload()[2] & 0xFF)); } else { return -1; } } /** * This method sets the update table period of a node. The new value is * passed using a short. * * @param netId network id of the destination node * @param destination network address of the destination node * @param period update table period in seconds (TODO check) */ public final void setNodeUpdateTablePeriod(int netId, NodeAddress destination, short period) { byte[] message = new byte[3]; message[0] = (byte) (SDN_WISE_CNF_WRITE + SDN_WISE_CNF_ID_CNT_UPDTABLE_MAX); message[1] = (byte) (period >> 8); message[2] = (byte) (period & 0xFF); sendMessage(netId, destination, SDN_WISE_CONFIG, message); } /** * This method reads the Update table period of a node. * * @param netId network id of the destination node * @param destination network address of the destination node * @return returns the updateTablePeriod, -1 if not found */ public final int getNodeUpdateTablePeriod(int netId, NodeAddress destination) { byte[] message = new byte[3]; message[0] = (byte) (SDN_WISE_CNF_READ + SDN_WISE_CNF_ID_CNT_UPDTABLE_MAX); message[1] = (byte) 0; message[2] = (byte) 0; sendMessage(netId, destination, SDN_WISE_CONFIG, message); try { Thread.sleep(RESPONSE_TIMEOUT); } catch (InterruptedException ex) { Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex); } if (cache.containsKey(netId + " " + destination.toString() + " " + message[0])) { NetworkPacket data = cache.remove(netId + " " + destination.toString() + " " + message[0]); return (((data.getPayload()[1] & 0xFF) << 8) + (data.getPayload()[2] & 0xFF)); } else { return -1; } } /** * This method sets the maximum time to live for each message sent by a * node. The new value is passed using a byte. * * @param netId network id of the destination node * @param destination network address of the destination node * @param newTtl time to live in number of hops */ public final void setNodeTtlMax(int netId, NodeAddress destination, byte newTtl) { byte[] message = new byte[3]; message[0] = (byte) (SDN_WISE_CNF_WRITE + SDN_WISE_CNF_ID_TTL_MAX); message[1] = (byte) 0; message[2] = (byte) (newTtl & 0xFF); sendMessage(netId, destination, SDN_WISE_CONFIG, message); } /** * This method reads the maximum time to live for each message sent by a * node. * * @param netId network id of the destination node * @param destination network address of the destination node * @return returns the maximum time to live, -1 if not found */ public final int getNodeTtlMax(int netId, NodeAddress destination) { byte[] message = new byte[3]; message[0] = (byte) (SDN_WISE_CNF_READ + SDN_WISE_CNF_ID_TTL_MAX); message[1] = (byte) 0; message[2] = (byte) 0; sendMessage(netId, destination, SDN_WISE_CONFIG, message); try { Thread.sleep(RESPONSE_TIMEOUT); } catch (InterruptedException ex) { Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex); } if (cache.containsKey(netId + " " + destination.toString() + " " + message[0])) { NetworkPacket data = cache.remove(netId + " " + destination.toString() + " " + message[0]); return (data.getPayload()[2] & 0xFF); } else { return -1; } } /** * This method sets the minimum RSSI in order to consider a node as a * neighbour. * * @param netId network id of the destination node * @param destination network address of the destination node * @param newRssi new threshold rssi value */ public final void setNodeRssiMin(int netId, NodeAddress destination, byte newRssi) { byte[] message = new byte[3]; message[0] = (byte) (SDN_WISE_CNF_WRITE + SDN_WISE_CNF_ID_RSSI_MIN); message[1] = (byte) 0; message[2] = (byte) (newRssi & 0xFF); sendMessage(netId, destination, SDN_WISE_CONFIG, message); } /** * This method reads the minimum RSSI in order to consider a node as a * neighbour. * * @param netId network id of the destination node * @param destination network address of the destination node * @return returns the minimum RSSI, -1 if not found */ public final int getNodeRssiMin(int netId, NodeAddress destination) { byte[] message = new byte[3]; message[0] = (byte) (SDN_WISE_CNF_READ + SDN_WISE_CNF_ID_RSSI_MIN); message[1] = (byte) 0; message[2] = (byte) 0; sendMessage(netId, destination, SDN_WISE_CONFIG, message); try { Thread.sleep(RESPONSE_TIMEOUT); } catch (InterruptedException ex) { Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex); } if (cache.containsKey(netId + " " + destination.toString() + " " + message[0])) { NetworkPacket data = cache.remove(netId + " " + destination.toString() + " " + message[0]); return (data.getPayload()[2] & 0xFF); } else { return -1; // TODO make an exception out of this -1 } } /** * This method adds a new address in the list of addresses accepted by the * node. * * @param netId network id of the destination node * @param destination network address of the destination node * @param high high byte of the address * @param low low byte of the address */ public final void addAcceptedAddress(int netId, NodeAddress destination, int high, int low) { byte[] message = new byte[3]; message[0] = (byte) (SDN_WISE_CNF_WRITE + SDN_WISE_CNF_ADD_ACCEPTED); message[1] = (byte) (high); message[2] = (byte) (low); sendMessage(netId, destination, SDN_WISE_CONFIG, message); } /** * This method removes an address in the list of addresses accepted by the * node. * * @param netId network id of the destination node * @param destination network address of the destination node * @param high high byte of the address * @param low low byte of the address */ public final void removeAcceptedAddress(int netId, NodeAddress destination, int high, int low) { byte[] message = new byte[3]; message[0] = (byte) (SDN_WISE_CNF_WRITE + SDN_WISE_CNF_REMOVE_ACCEPTED); message[1] = (byte) (high); message[2] = (byte) (low); sendMessage(netId, destination, SDN_WISE_CONFIG, message); } /** * This method returns the list of addresses accepted by the node. * * @param netId network id of the destination node * @param destination network address of the destination node * @return returns the list of accepted Addresses */ public final List getAcceptedAddressesList(int netId, NodeAddress destination) { byte[] message = new byte[3]; message[0] = (byte) (SDN_WISE_CNF_READ + SDN_WISE_CNF_LIST_ACCEPTED); message[1] = 0; message[2] = 0; sendMessage(netId, destination, SDN_WISE_CONFIG, message); try { Thread.sleep(RESPONSE_TIMEOUT); } catch (InterruptedException ex) { Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex); } if (cache.containsKey(netId + " " + destination.toString() + " " + message[0])) { NetworkPacket data = cache.remove(netId + " " + destination.toString() + " " + message[0]); LinkedList list = new LinkedList<>(); for (int i = 1; i < data.getPayload().length; i += 2) { if (data.getPayload()[i] != -1 && data.getPayload()[i + 1] != -1) { list.add(new NodeAddress( data.getPayload()[i] & 0xFF, data.getPayload()[i + 1] & 0xFF)); } } return list; } else { return null; } } /** * This method installs a rule in the node * * @param netId network id of the destination node * @param destination network address of the destination node * @param rule the rule to be installed */ public final void addRule(int netId, NodeAddress destination, FlowTableEntry rule) { } /** * This method removes a rule in the node * * @param netId network id of the destination node * @param destination network address of the destination node * @param index index of the erased row */ public final void removeRule(int netId, NodeAddress destination, int index) { byte[] message = new byte[3]; message[0] = (byte) (SDN_WISE_CNF_WRITE + SDN_WISE_CNF_REMOVE_RULE_INDEX); message[1] = (byte) 0; message[2] = (byte) index; sendMessage(netId, destination, SDN_WISE_CONFIG, message); } /** * This method removes a rule in the node * * @param netId network id of the destination node * @param destination network address of the destination node * @param rule the rule to be removed */ public final void removeRule(int netId, NodeAddress destination, FlowTableEntry rule) { byte[] bRule = rule.toByteArray(); byte[] message = new byte[1 + bRule.length]; message[0] = (byte) (SDN_WISE_CNF_WRITE + SDN_WISE_CNF_REMOVE_RULE); System.arraycopy(bRule, 0, message, 1, bRule.length); sendMessage(netId, destination, SDN_WISE_CONFIG, message); } /** * This method gets the WISE flow table of a node * * @param netId network id of the destination node * @param destination network address of the destination node * @return returns the list of the entries in the WISE Flow Table */ public final List getRules(int netId, NodeAddress destination) { List list = new ArrayList<>(SDN_WISE_RLS_MAX); for (int i = 0; i < SDN_WISE_RLS_MAX; i++) { list.add(i, getRuleAtPos(netId, destination, i)); } return list; } /** * This method gets the WISE flow table entry of a node at position n * * @param netId network id of the destination node * @param destination network address of the destination node * @param n position of the entry in the table * @return returns the list of the entries in the WISE Flow Table */ public final FlowTableEntry getRuleAtPos(int netId, NodeAddress destination, int n) { byte[] message = new byte[3]; message[0] = (byte) (SDN_WISE_CNF_LIST_RULE); message[1] = 0; message[2] = (byte) (n); sendMessage(netId, destination, SDN_WISE_CONFIG, message); try { Thread.sleep(RESPONSE_TIMEOUT); } catch (InterruptedException ex) { Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex); } if (cache.containsKey(netId + " " + destination.toString() + " " + message[0] + " " + message[2])) { NetworkPacket data = cache.remove(netId + " " + destination.toString() + " " + message[0] + " " + message[2]); FlowTableEntry entry = new FlowTableEntry( Arrays.copyOfRange( data.getPayload(), 3, data.getPayload().length)); return entry; } else { return null; } } /** * This method is used to register the Controller with the FlowVisor. */ //TODO we need to implement same sort of security check/auth private void register() { } /** * This method gets the NetworkGraph of the controller * * @return returns a NetworkGraph object */ public NetworkGraph getNetworkGraph() { return networkGraph; } private class Worker implements Runnable { private final ArrayBlockingQueue bQ; boolean isStopped = false; public Worker(ArrayBlockingQueue bQ) { this.bQ = bQ; } @Override public void run() { while (!isStopped) { try { managePacket(bQ.take()); } catch (InterruptedException ex) { isStopped = true; } } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy