ndn: Add NFD and NLSR class abstractions

refs: #2528

Change-Id: I3241af0e85f4eec4eb640aca274ff9ca4f812656
diff --git a/ndn/__init__.py b/ndn/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ndn/__init__.py
diff --git a/ndn/ndn_host.py b/ndn/ndn_host.py
new file mode 100644
index 0000000..427aced
--- /dev/null
+++ b/ndn/ndn_host.py
@@ -0,0 +1,84 @@
+from mininet.node import CPULimitedHost, Host, Node
+from ndn.nfd import Nfd
+
+class NdnHostCommon():
+    "Common methods of NdnHost and CpuLimitedNdnHost"
+
+    def configNdn(self):
+        self.buildPeerIp()
+
+    def buildPeerIp(self):
+        for iface in self.intfList():
+            link = iface.link
+            if link:
+                node1, node2 = link.intf1.node, link.intf2.node
+                if node1 == self:
+                    self.peerList[node2.name] = link.intf2.node.IP(link.intf2)
+                else:
+                    self.peerList[node1.name] = link.intf1.node.IP(link.intf1)
+
+    inited = False
+
+    @classmethod
+    def init(cls):
+        "Initialization for NDNHost class"
+        cls.inited = True
+
+class NdnHost(Host, NdnHostCommon):
+    "NDNHost is a Host that always runs NFD"
+
+    def __init__(self, name, **kwargs):
+
+        Host.__init__(self, name, **kwargs)
+        if not NdnHost.inited:
+            NdnHostCommon.init()
+
+        self.nfd = Nfd(self)
+        self.nfd.start()
+
+        self.peerList = {}
+
+    def config(self, fib=None, app=None, cache=None, **params):
+
+        r = Node.config(self, **params)
+
+        self.setParam(r, 'app', fib=fib)   # why is this not app=app, to be investigated
+        self.setParam(r, 'fib', app=app)   # and this fib=fib
+        self.setParam(r, 'cache', cache=cache)
+
+        return r
+
+    def terminate(self):
+        "Stop node."
+        self.nfd.stop()
+        Host.terminate(self)
+
+class CpuLimitedNdnHost(CPULimitedHost, NdnHostCommon):
+    '''CPULimitedNDNHost is a Host that always runs NFD and extends CPULimitedHost.
+       It should be used when one wants to limit the resources of NDN routers and hosts '''
+
+    def __init__(self, name, sched='cfs', **kwargs):
+
+        CPULimitedHost.__init__(self, name, sched, **kwargs)
+        if not NdnHost.inited:
+            NdnHostCommon.init()
+
+        self.nfd = Nfd(self)
+        self.nfd.start()
+
+        self.peerList = {}
+
+    def config(self, fib=None, app=None, cpu=None, cores=None, cache=None, **params):
+
+        r = CPULimitedHost.config(self,cpu,cores, **params)
+
+        self.setParam(r, 'app', fib=fib)   #????? shoud it be app=app
+        self.setParam(r, 'fib', app=app)
+        self.setParam(r, 'cache', cache=cache)
+
+        return r
+
+    def terminate(self):
+        "Stop node."
+        self.nfd.stop()
+        Host.terminate(self)
diff --git a/ndn/nfd.py b/ndn/nfd.py
new file mode 100644
index 0000000..8ee9423
--- /dev/null
+++ b/ndn/nfd.py
@@ -0,0 +1,58 @@
+#!/usr/bin/env python
+
+import time
+from os.path import expanduser
+
+class Nfd:
+    def __init__(self, node):
+        self.node = node
+        self.isRunning = False
+
+        # Create home directory for a node
+        node.cmd("cd /tmp && mkdir %s" % node.name)
+        node.cmd("cd %s" % node.name)
+
+        self.homeFolder = "/tmp/%s" % node.name
+        self.confFile = "%s/%s.conf" % (self.homeFolder, node.name)
+        self.logFile = "%s/%s.log" % (self.homeFolder, node.name)
+        self.sockFile = "/var/run/%s.sock" % node.name
+        self.ndnFolder = "%s/.ndn" % self.homeFolder
+        self.clientConf = "%s/client.conf" % self.ndnFolder
+
+        # Copy file that checks FIB
+        node.cmd("sudo cp ~/mn-ndn/ndn_utils/checkFIB %s/checkFIB" % self.homeFolder)
+
+        # Copy nfd.conf file from mn-ndn/ndn_utils to the node's home
+        node.cmd("sudo cp ~/mn-ndn/ndn_utils/nfd.conf %s" % self.confFile)
+
+        # Open the conf file and change socket file name
+        node.cmd("sudo sed -i 's|nfd.sock|%s.sock|g' %s" % (node.name, self.confFile))
+
+        # Make NDN folder
+        node.cmd("sudo mkdir %s" % self.ndnFolder)
+
+        # Copy the client.conf file and change the unix socket
+        node.cmd("sudo cp ~/mn-ndn/ndn_utils/client.conf.sample %s" % self.clientConf)
+        node.cmd("sudo sed -i 's|nfd.sock|%s.sock|g' %s" % (node.name, self.clientConf))
+
+        # Change home folder
+        node.cmd("export HOME=%s" % self.homeFolder)
+
+    def start(self):
+        if self.isRunning is False:
+            self.node.cmd("sudo nfd --config %s 2>> %s &" % (self.confFile, self.logFile))
+            self.processId = self.node.cmd("echo $!")[:-1]
+
+            time.sleep(2)
+
+            self.isRunning = True
+
+    def stop(self):
+        if self.isRunning is True:
+            self.node.cmd("sudo kill %s" % self.processId)
+
+        self.isRunning = False
+
+    def setStrategy(self, name, strategy):
+        node.cmd("nfdc set-strategy %s ndn:/localhost/nfd/strategy/%s" % (name, strategy))
+        time.sleep(0.5)
diff --git a/ndn/nlsr.py b/ndn/nlsr.py
new file mode 100644
index 0000000..de9ec86
--- /dev/null
+++ b/ndn/nlsr.py
@@ -0,0 +1,154 @@
+#!/usr/bin/env python
+
+class Nlsr:
+    def __init__(self, node):
+        self.node = node
+        self.routerName = "/%sC1.Router/cs/%s" % ('%', node.name)
+        self.confFile = "/tmp/%s/nlsr.conf" % node.name
+
+        # Make directory for log file
+        self.logDir = "/tmp/%s/log" % node.name
+        node.cmd("mkdir %s" % self.logDir)
+
+        # Configure basic router information in nlsr.conf based on host name
+        node.cmd("sudo sed -i 's|router .*|router %s|g' %s" % (self.routerName, self.confFile))
+        node.cmd("sudo sed -i 's|log-dir .*|log-dir %s|g' %s" % (self.logDir, self.confFile))
+        node.cmd("sudo sed -i 's|seq-dir .*|seq-dir %s|g' %s" % (self.logDir, self.confFile))
+        node.cmd("sudo sed -i 's|prefix .*netlab|prefix /ndn/edu/%s|g' %s" % (node.name, self.confFile))
+
+    def start(self):
+        self.node.cmd("nlsr -d")
+
+
+class NlsrConfigGenerator:
+
+    ROUTING_LINK_STATE = "ls"
+    ROUTING_HYPERBOLIC = "hr"
+
+    def __init__(self, node, home):
+        node.cmd("sudo cp %s/mn-ndn/ndn_utils/nlsr.conf nlsr.conf" % home)
+        self.node = node
+
+        parameters = node.nlsrParameters
+
+        self.nFaces = parameters.get("max-faces-per-prefix", 3)
+        self.hyperbolicState = parameters.get("hyperbolic-state", "off")
+        self.hyperRadius = parameters.get("radius", 0.0)
+        self.hyperAngle = parameters.get("angle", 0.0)
+
+    def createConfigFile(self):
+
+        filePath = "/tmp/%s/nlsr.conf" % self.node.name
+
+        configFile = open(filePath, 'r')
+        oldContent = configFile.read()
+        configFile.close()
+
+        newContent = oldContent.replace("$GENERAL_SECTION", self.__getGeneralSection())
+        newContent = newContent.replace("$NEIGHBORS_SECTION", self.__getNeighborsSection())
+        newContent = newContent.replace("$HYPERBOLIC_SECTION", self.__getHyperbolicSection())
+        newContent = newContent.replace("$FIB_SECTION", self.__getFibSection())
+        newContent = newContent.replace("$ADVERTISING_SECTION", self.__getAdvertisingSection())
+
+        configFile = open(filePath, 'w')
+        configFile.write(newContent)
+        configFile.close()
+
+    def __getConfig(self):
+
+        config =  self.__getGeneralSection()
+        config += self.__getNeighborsSection()
+        config += self.__getHyperbolicSection()
+        config += self.__getFibSection()
+        config += self.__getAdvertisingSection()
+        config += self.__getSecuritySection()
+
+        return config
+
+    def __getGeneralSection(self):
+
+        general =  "general\n"
+        general += "{\n"
+        general += "  network /ndn/\n"
+        general += "  site /edu\n"
+        general += "  router /%C1.Router/cs/" + self.node.name + "\n"
+        general += "  log-level DEBUG\n"
+        general += "  log-dir /tmp/" + self.node.name + "/log\n"
+        general += "  seq-dir /tmp/" + self.node.name + "/log\n"
+        general += "}\n"
+
+        return general
+
+    def __getNeighborsSection(self):
+
+        neighbors =  "neighbors\n"
+        neighbors += "{\n"
+
+        for intf in self.node.intfList():
+            link = intf.link
+            if link:
+                node1, node2 = link.intf1.node, link.intf2.node
+
+                if node1 == self.node:
+                    other = node2
+                    ip = other.IP(str(link.intf2))
+                else:
+                    other = node1
+                    ip = other.IP(str(link.intf1))
+
+                linkCost = intf.params.get("delay", "0ms").replace("ms", "")
+
+                neighbors += "neighbor\n"
+                neighbors += "{\n"
+                neighbors += "  name /ndn/edu/%C1.Router/cs/" + other.name + "\n"
+                neighbors += "  face-uri udp://" + str(ip) + "\n"
+                neighbors += "  link-cost " + linkCost + "\n"
+                neighbors += "}\n"
+
+        neighbors += "}\n"
+
+        return neighbors
+
+    def __getHyperbolicSection(self):
+
+        hyper =  "hyperbolic\n"
+        hyper += "{\n"
+        hyper += "state %s\n" % self.hyperbolicState
+        hyper += "radius " + str(self.hyperRadius) + "\n"
+        hyper += "angle " + str(self.hyperAngle) + "\n"
+        hyper += "}\n"
+
+        return hyper
+
+    def __getFibSection(self):
+
+        fib =  "fib\n"
+        fib += "{\n"
+        fib += "  max-faces-per-prefix " + str(self.nFaces) + "\n"
+        fib += "}\n"
+
+        return fib
+
+    def __getAdvertisingSection(self):
+
+        advertising =  "advertising\n"
+        advertising += "{\n"
+        advertising += "  prefix /ndn/edu/" + self.node.name + "\n"
+        advertising += "}\n"
+
+        return advertising
+
+    def __getSecuritySection(self):
+
+        security =  "security\n"
+        security += "{\n"
+        security += "  validator\n"
+        security += "  {\n"
+        security += "    trust-anchor\n"
+        security += "    {\n"
+        security += "      type any\n"
+        security += "    }\n"
+        security += "  }\n"
+        security += "}\n"
+
+        return security