Skip to content

Commit

Permalink
Release 1.3
Browse files Browse the repository at this point in the history
  • Loading branch information
David Fialho committed Oct 2, 2017
2 parents 1b1f1d2 + 8d437a2 commit f9da2c8
Show file tree
Hide file tree
Showing 13 changed files with 301 additions and 16 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,5 @@ gradle-app.setting
.idea/
out/


### Specific to application
src/main/resources/version.properties
12 changes: 10 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
group 'ssbgp'
version '1.2'
version properties.get('application.version')

buildscript {
ext.kotlin_version = '1.1.50'
ext.kotlin_version = '1.1.51'
ext.dokka_version = '0.9.15'
ext.junit_version = '1.0.0-M4'
ext.junit5_version = '5.0.0-M4'
Expand Down Expand Up @@ -77,6 +77,14 @@ task enabledMockingFinalClasses << {
}

jar {

task updateProjectVersion {
def versionFile = new File("$projectDir/src/main/resources/version.properties")
versionFile.parentFile.mkdirs()
versionFile.createNewFile()
versionFile.write("application.version=${version}")
}

manifest {
attributes 'Main-Class': 'main.MainKt'
}
Expand Down
1 change: 1 addition & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
application.version=1.3
2 changes: 1 addition & 1 deletion settings.gradle
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
rootProject.name = 'simulator'
rootProject.name = 'ssbgp-simulator'

15 changes: 15 additions & 0 deletions src/main/kotlin/bgp/BGP.kt
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ abstract class BaseBGP(val mrai: Time, routingTable: RoutingTable<BGPRoute>): Pr
*/
protected var wasSelectedRouteUpdated: Boolean = false

/**
* Stores the last route that was exported to neighbors.
* This is used to ensure that a selected and exported is not exported again when the MRAI expires.
*/
private var lastExportedRoute = BGPRoute.invalid()

/**
* Adds a new in-neighbor for the protocol to export selected routes to.
*
Expand Down Expand Up @@ -160,9 +166,17 @@ abstract class BaseBGP(val mrai: Time, routingTable: RoutingTable<BGPRoute>): Pr

val selectedRoute = routingTable.getSelectedRoute()

if (selectedRoute == lastExportedRoute) {
// No need to export any route since the currently selected route corresponds to the
// last exported route
// This test prevents routes from being exported multiple times before and after the MRAI expires
return
}

// Export the route currently selected
node.send(selectedRoute)
BGPNotifier.notifyExport(ExportNotification(node, selectedRoute))
lastExportedRoute = selectedRoute

if (restartMRAITimer && mrai > 0) {
// Restart the MRAI timer
Expand All @@ -181,6 +195,7 @@ abstract class BaseBGP(val mrai: Time, routingTable: RoutingTable<BGPRoute>): Pr
wasSelectedRouteUpdated = false
mraiTimer.cancel()
mraiTimer = Timer.disabled()
lastExportedRoute = BGPRoute.invalid()
}

/**
Expand Down
28 changes: 28 additions & 0 deletions src/main/kotlin/bgp/BGPRoute.kt
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,34 @@ sealed class BGPRoute : Route {
override fun toString(): String {
return "BGPRoute(localPref=$localPref, asPath=$asPath)"
}

/**
* Two BGP routes are considered equal if and only if they have the same exact local preference value and the
* same AS path
*/
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false

other as BGPRoute

if (localPref != other.localPref) return false

// trick to avoid having to compare each node of the AS-paths most times
if (asPath.size != other.asPath.size) return false

if (asPath != other.asPath) return false

return true
}

override fun hashCode(): Int {
var result = localPref
result = 31 * result + asPath.hashCode()
return result
}


}

/**
Expand Down
75 changes: 75 additions & 0 deletions src/main/kotlin/io/NodeDataReporter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package io

import bgp.BGPRoute
import simulation.NodeDataSet
import java.io.File
import java.io.IOException

/**
* Created on 02-10-2017.
*
* @author David Fialho
*
* IMPORTANT: This Reporter only works for BGP routes!!
*/
class NodeDataReporter(private val outputFile: File): Reporter<NodeDataSet> {

/**
* Flag to indicate if the headers were already printed.
* Helps to ensure the headers are printed only once despite the report() method being called multiple times.
*/
private var wereHeadersPrinted = false

/**
* Stores the simulation number, Incremented each time the report() method is called.
*/
private var simulation = 1

/**
* Reports a data set.
*/
@Throws(IOException::class)
override fun report(data: NodeDataSet) {

CSVPrinter(outputFile).use {

if (!wereHeadersPrinted) {
it.printRecord(
"Simulation",
"Node",
"Local Preference",
"Next-hop",
"Path Length",
"Termination Time"
)

wereHeadersPrinted = true
}

for ((nodeID, selectedRoute) in data.selectedRoutes) {

selectedRoute as BGPRoute

it.printRecord(
simulation,
nodeID,
selectedRoute.localPref,
selectedRoute.asPath.nextHop()?.id,
selectedRoute.asPath.size,
data.terminationTimes[nodeID]
)
}

simulation++
}
}

/**
* Resets the reporter to its initial state.
*/
override fun reset() {
wereHeadersPrinted = false
simulation = 1
}

}
98 changes: 98 additions & 0 deletions src/main/kotlin/simulation/NodeDataCollector.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package simulation

import bgp.notifications.BGPNotifier
import bgp.notifications.ExportListener
import bgp.notifications.ExportNotification
import core.simulator.notifications.*
import io.NodeDataReporter
import java.io.File
import java.io.IOException

/**
* Created on 01-10-2017.
*
* @author David Fialho
*
* The node data collector collects data relative to each individual node in the topology.
*/
class NodeDataCollector(private val reporter: NodeDataReporter) :
DataCollector, StartListener, EndListener, ExportListener {

/**
* Creates a Basic Reporter that will output results to the specified output file.
*/
constructor(outputFile: File) : this(NodeDataReporter(outputFile))

private val data = NodeDataSet()

/**
* Adds the collector as a listener for notifications the collector needs to listen to collect data.
*/
override fun register() {
BasicNotifier.addStartListener(this)
BasicNotifier.addEndListener(this)
BGPNotifier.addExportListener(this)
}

/**
* Removes the collector from all notifiers
*/
override fun unregister() {
BasicNotifier.removeStartListener(this)
BasicNotifier.removeEndListener(this)
BGPNotifier.removeExportListener(this)
}

/**
* Processes the data after all raw data has been collected. It should be called after an execution.
*/
override fun processData() {
// nothing to do here
}

/**
* Reports the currently collected data.
*
* @throws IOException If an I/O error occurs
*/
@Throws(IOException::class)
override fun report() {
reporter.report(data)
}

/**
* Clears all collected data.
*/
override fun clear() {
data.clear()
}

/**
* Invoked to notify the listener of a new start notification.
*/
override fun notify(notification: StartNotification) {
// Ensure that all nodes start with a termination time of 0. This also ensures
// that all nodes are included in the terminationTimes map Why is this necessary?
// It may occur the some nodes never export a route. If that is the case, then
// these nodes would not be included in the terminationTimes map.
for (node in notification.topology.nodes)
data.terminationTimes[node.id] = 0
}

/**
* Invoked to notify the listener of a new export notification.
*/
override fun notify(notification: ExportNotification) {
// Update termination time of the node that exported a new route
data.terminationTimes[notification.node.id] = notification.time
}

/**
* Invoked to notify the listener of a new end notification.
*/
override fun notify(notification: EndNotification) {
for (node in notification.topology.nodes)
data.selectedRoutes[node.id] = node.protocol.selectedRoute
}

}
29 changes: 29 additions & 0 deletions src/main/kotlin/simulation/NodeDataSet.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package simulation

import core.routing.NodeID
import core.routing.Route
import core.simulator.Time

/**
* Created on 02-10-2017.
*
* @author David Fialho
*/
class NodeDataSet : DataSet {

/**
* Data stored for each node.
*/
data class NodeData(var selectedRoute: Route, var terminationTime: Time = 0)

val terminationTimes: MutableMap<NodeID, Time> = HashMap()
val selectedRoutes: MutableMap<NodeID, Route> = HashMap()

/**
* Clears all data from the data set.
*/
override fun clear() {
terminationTimes.clear()
selectedRoutes.clear()
}
}
1 change: 1 addition & 0 deletions src/main/kotlin/simulation/RepetitionRunner.kt
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class RepetitionRunner<R: Route>(

// Cleanup for next execution
topology.reset()
destination.reset()
Engine.messageDelayGenerator.generateNewSeed()
}

Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/ui/cli/CLIApplication.kt
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ object CLIApplication: Application {
exitProcess(1)

} catch (e: Exception){
console.error("Program was interrupted due to unexpected error.")
console.error("Program was interrupted due to unexpected error: ${e.javaClass.simpleName}")
console.error("Cause: ${e.message ?: "No information available."}")
exitProcess(1)
}
Expand Down
Loading

0 comments on commit f9da2c8

Please sign in to comment.