# Open Flow related system parameters
# TCP port on which the controller is listening (default 6633)
# of.listenPort=6633
+# IP address of the controller (default: wild card)
+# of.address = 127.0.0.1
# The time (in milliseconds) the controller will wait for a response after sending a Barrier Request or a Statistic Request message (default 2000 msec)
# of.messageResponseTimer=2000
# The switch liveness timeout value (default 60500 msec)
exit 1
}
-if [ -v "TMP" ]; then
- pidfile="${TMP}/opendaylight.PID"
-else
+if [ -z ${TMP} ]; then
pidfile="/tmp/opendaylight.PID"
+else
+ pidfile="${TMP}/opendaylight.PID"
fi
debug=0
debugsuspend=0
package org.opendaylight.controller.protocol_plugin.openflow.core.internal;
import java.io.IOException;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
.getLogger(ControllerIO.class);
private static Short defaultOpenFlowPort = 6633;
private Short openFlowPort;
+ private InetAddress controllerIP;
+ private NetworkInterface netInt;
private SelectionKey serverSelectionKey;
private IController listener;
private ServerSocketChannel serverSocket;
openFlowPort);
}
}
+ String addressString = System.getProperty("of.address");
+ if (addressString != null) {
+ try {
+ controllerIP = InetAddress.getByName(addressString);
+ } catch (Exception e) {
+ controllerIP = null;
+ logger.warn("Invalid IP: {}, use wildcard *", addressString);
+ }
+ } else {
+ controllerIP = null;
+ }
}
public void start() throws IOException {
this.running = true;
- // obtain a selector
- this.selector = SelectorProvider.provider().openSelector();
- // create the listening socket
- this.serverSocket = ServerSocketChannel.open();
- this.serverSocket.configureBlocking(false);
- this.serverSocket.socket().bind(
- new java.net.InetSocketAddress(openFlowPort));
- this.serverSocket.socket().setReuseAddress(true);
- // register this socket for accepting incoming connections
- this.serverSelectionKey = this.serverSocket.register(selector,
- SelectionKey.OP_ACCEPT);
+ this.netInt = null;
controllerIOThread = new Thread(new Runnable() {
@Override
public void run() {
+ waitUntilInterfaceUp();
+ if (!startAcceptConnections()) {
+ return;
+ }
+ logger.info("Controller is now listening on {}:{}",
+ (controllerIP == null) ? "any" : controllerIP.getHostAddress(),
+ openFlowPort);
+ boolean netInterfaceUp = true;
while (running) {
try {
// wait for an incoming connection
- selector.select(0);
+ // check interface state every 5sec
+ selector.select(5000);
Iterator<SelectionKey> selectedKeys = selector
.selectedKeys().iterator();
+ netInterfaceUp = isNetInterfaceUp(netInterfaceUp);
while (selectedKeys.hasNext()) {
SelectionKey skey = selectedKeys.next();
selectedKeys.remove();
}
}, "ControllerI/O Thread");
controllerIOThread.start();
- logger.info("Controller is now listening on port {}", openFlowPort);
}
+ private boolean startAcceptConnections() {
+ if (running) {
+ try {
+ // obtain a selector
+ selector = SelectorProvider.provider().openSelector();
+ // create the listening socket
+ serverSocket = ServerSocketChannel.open();
+ serverSocket.configureBlocking(false);
+ serverSocket.socket().bind(
+ new java.net.InetSocketAddress(controllerIP,
+ openFlowPort));
+ serverSocket.socket().setReuseAddress(true);
+ // register this socket for accepting incoming
+ // connections
+ serverSelectionKey = serverSocket.register(selector,
+ SelectionKey.OP_ACCEPT);
+ } catch (IOException e) {
+ logger.error(
+ "Failed to listen on {}:{}, exit",
+ (controllerIP == null) ? "" : controllerIP
+ .getHostAddress(), openFlowPort);
+ return false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ private boolean isNetInterfaceUp(boolean currentlyUp) {
+ if (controllerIP == null) {
+ // for wildcard address, return since there is always an "up"
+ // interface (such as loopback)
+ return true;
+ }
+ boolean up;
+ try {
+ if (netInt == null) {
+ logger.warn("Can't find any operational interface for address {}",
+ controllerIP.getHostAddress());
+ return false;
+ }
+ up = netInt.isUp();
+ if (!up) {
+ // always generate log if the interface is down
+ logger.warn("Interface {} with address {} is DOWN!",
+ netInt.getDisplayName(),
+ controllerIP.getHostAddress());
+ } else {
+ if (!currentlyUp) {
+ // only generate log if the interface changes from down to up
+ logger.info("Interface {} with address {} is UP!",
+ netInt.getDisplayName(),
+ controllerIP.getHostAddress());
+ }
+ }
+ } catch (SocketException e) {
+ logger.warn("Interface {} with address {} is DOWN!",
+ netInt.getDisplayName(),
+ controllerIP.getHostAddress());
+ up = false;
+ }
+ return up;
+ }
+
+ private void waitUntilInterfaceUp() {
+ if (controllerIP == null) {
+ // for wildcard address, return since there is always an "up"
+ // interface (such as loopback)
+ return;
+ }
+ boolean isUp = false;
+ do {
+ try {
+ // get the network interface from the address
+ netInt = NetworkInterface.getByInetAddress(controllerIP);
+ isUp = isNetInterfaceUp(isUp);
+ if (!isUp) {
+ Thread.sleep(5000);
+ }
+ } catch (Exception e) {
+ }
+ } while ((!isUp) && (running));
+ }
public void shutDown() throws IOException {
this.running = false;
this.selector.wakeup();
</scm>
<modelVersion>4.0.0</modelVersion>
- <artifactId>model-flow</artifactId>
+ <artifactId>model-flow-base</artifactId>
<dependencies>
<dependency>
<artifactId>model-inventory</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools.model</groupId>
+ <artifactId>opendaylight-l2-types</artifactId>
+ <version>2013.08.27-SNAPSHOT</version>
+ </dependency>
</dependencies>
<packaging>bundle</packaging>
</project>
-module opendaylight-flow {
- namespace "urn:opendaylight:flow:service";
- prefix flow;
+module opendaylight-flow-base {
+ namespace "urn:opendaylight:flow:base";
+ prefix "flowbase";
import yang-ext {prefix ext;}
import ietf-inet-types {prefix inet;}
import ietf-yang-types {prefix yang;}
import opendaylight-inventory {prefix inv;}
+ import opendaylight-l2-types {prefix l2t;}
revision "2013-08-19" {
description "Initial revision of flow service";
}
- /** Base structure **/
- container flows {
- list flow {
- leaf node {
- type inv:node-id;
- }
- container match {
- // Match is empty
- leaf input-node-connector {
- type inv:node-connector-id; //
- }
- }
- list action {
- key id;
- leaf id {
- type string;
- }
- choice action {
-
- }
- }
- }
- }
-
- /** Matches **/
- augment "/flows/flow/match" {
- ext:augment-identifier "ethernet-match";
+ /** Match Groupings **/
+ grouping "ethernet-match-fields" {
container ethernet-source {
- description "Ethernet source address.";
+ //description "Ethernet source address.";
+ //presence "Match field is active and set";
leaf address {
+ mandatory true;
type yang:mac-address;
}
leaf mask {
}
container ethernet-destination {
description "Ethernet destination address.";
+ presence "Match field is active and set";
leaf address {
+ mandatory true;
type yang:mac-address;
}
}
container ethernet-type {
description "Ethernet frame type.";
+ presence "Match field is active and set";
+
leaf type {
- type uint16; // Needs to define that as general model
+ mandatory true;
+ type l2t:ether-type; // Needs to define that as general model
}
leaf mask {
type binary;
}
}
- augment "/flows/flow/match" {
- ext:augment-identifier "vlan-match";
-
+ grouping "vlan-match-fields" {
container vlan-id {
description "VLAN id.";
+ presence "Match field is active and set";
+
leaf vlan-id {
- type uint16; // TODO: Define proper vlan id type.
+ mandatory true;
+ type l2t:vlan-id;
}
leaf mask {
type binary;
}
leaf vlan-pcp {
description "VLAN priority.";
- type uint8; // TODO: Define PCP type
+ type l2t:vlan-pcp;
}
}
- augment "/flows/flow/match" {
- ext:augment-identifier "ip-match";
-
+ grouping "ip-match-fields" {
leaf ip-protocol {
description "IP protocol.";
type uint8; // TODO define IP protocol number
}
}
- augment "/flows/flow/match" {
- ext:augment-identifier "ipv4-match";
+ grouping "ipv4-match-fields" {
leaf ipv4-source {
description "IPv4 source address.";
type inet:ipv4-prefix;
}
}
- augment "/flows/flow/match" {
- ext:augment-identifier "ipv6-match";
+ grouping "ipv6-match-fields" {
leaf ipv6-source {
description "IPv6 source address.";
type inet:ipv6-prefix;
}
- augment "/flows/flow/match" {
- ext:augment-identifier "udp-match";
-
+ grouping "udp-match-fields" {
leaf udp-source-port {
description "UDP source port.";
type inet:port-number;
}
}
- augment "/flows/flow/match" {
- ext:augment-identifier "tcp-match";
+ grouping "tcp-match-fields" {
leaf tcp-source-port {
description "TCP source port.";
type inet:port-number;
}
}
- augment "/flows/flow/match" {
- ext:augment-identifier "sctp-match";
+ grouping "sctp-match-fields" {
leaf sctp-source-port {
description "SCTP source port.";
type inet:port-number;
}
}
- augment "/flows/flow/match" {
- ext:augment-identifier "icmpv4-match";
+ grouping "icmpv4-match-fields" {
leaf icmpv4-type {
description "ICMP type.";
type uint8; // Define ICMP Type
}
}
- augment "/flows/flow/match" {
- ext:augment-identifier "arp-match";
-
+ grouping "arp-match-fields" {
leaf arp-source-transport-address {
description "ARP source IPv4 address.";
type inet:ipv4-prefix;
}
container arp-source-hardware-address {
description "ARP source hardware address.";
+ presence "Match field is active and set";
leaf address {
+ mandatory true;
type yang:mac-address;
}
leaf mask {
}
container arp-target-hardware-address {
description "ARP target hardware address.";
+ presence "Match field is active and set";
leaf address {
+ mandatory true;
type yang:mac-address;
}
leaf mask {
}
}
- /** Actions **/
- augment "/flows/flow/action/action" {
- case output-action {
- leaf output-node-connector {
- type string;
+ grouping action {
+ choice action {
+ case output-action {
+ leaf output-node-connector {
+ type string;
+ }
}
- }
- case controller-action {
- leaf max-length {
- type uint16 {
- range "0..65294";
+ case controller-action {
+ leaf max-length {
+ type uint16 {
+ range "0..65294";
+ }
}
}
- }
- case set-queue-action {
- leaf queue {
- type string; // TODO: define queues
+ case set-queue-action {
+ leaf queue {
+ type string; // TODO: define queues
+ }
}
- }
- case pop-mpls-action {
- container pop-mpls {
- leaf ethernet-type {
- type uint16; // TODO: define ethertype type
+ case pop-mpls-action {
+ container pop-mpls {
+ leaf ethernet-type {
+ type uint16; // TODO: define ethertype type
+ }
}
}
- }
- case set-mpls-ttl-action {
- leaf mpls-ttl {
- type uint8;
+ case set-mpls-ttl-action {
+ leaf mpls-ttl {
+ type uint8;
+ }
}
- }
- case set-nw-ttl-action {
- leaf nw-ttl {
- type uint8;
+ case set-nw-ttl-action {
+ leaf nw-ttl {
+ type uint8;
+ }
}
- }
- case push-pbb-action {
+ case push-pbb-action {
- }
+ }
- case push-mpls-action {
+ case push-mpls-action {
- }
+ }
- case push-vlan-action {
+ case push-vlan-action {
+ }
}
}
+ grouping flow {
+ leaf node {
+ type inv:node-id;
+ }
+ container match {
+ container "ethernet-match" {
+ uses "ethernet-match-fields";
+ }
+ container "vlan-match" {
+ uses "vlan-match-fields";
+ }
+ container "ip-match" {
+ uses "ip-match-fields";
+ }
+ container "ipv4-match" {
+ uses "ipv4-match-fields";
+ }
+ container "ipv6-match" {
+ uses "ipv6-match-fields";
+ }
+ container "udp-match" {
+ uses "udp-match-fields";
+ }
+ container "tcp-match" {
+ uses "tcp-match-fields";
+ }
+ container "sctp-match" {
+ uses "sctp-match-fields";
+ }
+ container "icmpv4-match" {
+ uses "icmpv4-match-fields";
+ }
+ container "arp-match" {
+ uses "arp-match-fields";
+ }
+ }
+ list action {
+ key "order";
+ leaf order {
+ type int32;
+ }
+ uses action;
+ }
+ }
}
\ No newline at end of file
--- /dev/null
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <artifactId>model-parent</artifactId>
+ <groupId>org.opendaylight.controller.model</groupId>
+ <version>1.0-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>model-flow-service</artifactId>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>model-flow-base</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>model-inventory</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools.model</groupId>
+ <artifactId>opendaylight-l2-types</artifactId>
+ <version>2013.08.27-SNAPSHOT</version>
+ </dependency>
+ </dependencies>
+ <packaging>bundle</packaging>
+</project>
\ No newline at end of file
--- /dev/null
+module opendaylight-flow-config {
+ namespace "urn:opendaylight:flow:config";
+ prefix flow;
+
+ import yang-ext {prefix ext;}
+ import opendaylight-inventory {prefix inv;}
+ import opendaylight-flow-base {prefix flowbase;}
+
+ revision "2013-08-19" {
+ description "Initial revision of flow service";
+ }
+
+ /** Base configuration structure
+ container flows {
+ list flow {
+ uses flowbase:flow;
+ }
+ }
+
+ **/
+}
\ No newline at end of file
--- /dev/null
+module opendaylight-flow-service {
+ namespace "urn:opendaylight:flow:service";
+ prefix flow;
+
+ import yang-ext {prefix ext;}
+ import opendaylight-inventory {prefix inv;}
+ import opendaylight-flow-base {prefix flowbase;}
+
+ revision "2013-08-19" {
+ description "Initial revision of flow service";
+ }
+
+ /** Base configuration structure **/
+
+
+ grouping flow-update {
+ container original-flow {
+ uses flowbase:flow;
+ }
+ container updated-flow {
+ uses flowbase:flow;
+ }
+ }
+
+ rpc add-flow {
+ input {
+ uses flowbase:flow;
+ }
+ }
+
+ rpc remove-flow {
+ input {
+ uses flowbase:flow;
+ }
+ }
+
+ rpc update-flow {
+ input {
+ uses flow-update;
+ }
+ }
+
+ notification flow-added {
+ uses flowbase:flow;
+ }
+
+ notification flow-updated {
+ input {
+ uses flow-update;
+ }
+ }
+
+ notification flow-removed {
+ uses flowbase:flow;
+ }
+}
\ No newline at end of file
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
- <artifactId>model-flow</artifactId>
+ <artifactId>model-flow-service</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
import yang-ext {prefix ext;}
import ietf-inet-types {prefix inet;}
import ietf-yang-types {prefix yang;}
- import opendaylight-flow {prefix flow;}
+ import opendaylight-flow-base {prefix flow;}
import opendaylight-inventory {prefix inv;}
revision "2013-08-19" {
description "Initial revision of flow service";
}
+ /*
augment "/flow:flows/flow:flow" {
ext:augment-identifier "flow-statistics";
}
}
}
+ */
augment "/inv:nodes/inv:node/inv:node-connector" {
ext:augment-identifier "node-connector-statistics";
type node-id;
}
list node-connector {
- type node-connector-id;
+ key "id";
+ leaf id {
+ type node-connector-id;
+ }
}
}
}
<modules>
<module>model-inventory</module>
- <module>model-flow</module>
+ <module>model-flow-base</module>
+ <module>model-flow-service</module>
<module>model-flow-statistics</module>
<!-- <module>model-topology-bgp</module> -->
</modules>
*/
package org.opendaylight.controller.sample.toaster.provider.api;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev20091120.ToastType;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToastType;
public interface ToastConsumer {
import org.opendaylight.controller.sal.common.DataStoreIdentifier;
import org.opendaylight.controller.sal.common.GlobalDataStore;
import org.opendaylight.controller.sample.toaster.provider.api.ToastConsumer;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev20091120.MakeToastInputBuilder;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev20091120.ToastDone;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev20091120.ToastType;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev20091120.Toaster;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev20091120.ToasterData;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev20091120.ToasterService;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.MakeToastInputBuilder;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToastDone;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToastType;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.Toaster;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterData;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterService;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
import org.opendaylight.controller.sample.toaster.provider.ToasterProvider;
import org.opendaylight.controller.sample.toaster.provider.api.ToastConsumer;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev20091120.ToasterService;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev20091120.WhiteBread;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterService;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.WhiteBread;
import org.ops4j.pax.exam.Configuration;
import org.ops4j.pax.exam.CoreOptions;
import org.ops4j.pax.exam.Option;
import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
import org.opendaylight.controller.sal.common.util.Futures;
import org.opendaylight.controller.sal.common.util.Rpcs;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev20091120.DisplayString;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev20091120.MakeToastInput;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev20091120.ToastDone.ToastStatus;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev20091120.ToastDoneBuilder;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev20091120.Toaster;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev20091120.Toaster.ToasterStatus;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev20091120.ToasterBuilder;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev20091120.ToasterData;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev20091120.ToasterService;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.DisplayString;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.MakeToastInput;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToastDone.ToastStatus;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToastDoneBuilder;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.Toaster;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.Toaster.ToasterStatus;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterBuilder;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterData;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterService;
import org.opendaylight.yangtools.yang.common.RpcError;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.slf4j.Logger;
notificationProvider.notify(notifyBuilder.build());
log.info("Toast Done");
logToastInput(toastRequest);
+ currentTask = null;
return Rpcs.<Void> getRpcResult(true, null, Collections.<RpcError> emptySet());
}
}
import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev20091120.ToasterService;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterService;
import org.opendaylight.yangtools.yang.binding.RpcService;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
-module toaster {
+ module toaster {
yang-version 1;
identity toast-type {
description
- "Base for all bread types supported by the toaster.
+ "Base for all bread types supported by the toaster.
New bread types not listed here nay be added in the
future.";
}
}
typedef DisplayString {
- type string;
+ type string {
+ length "0 .. 255";
+ }
description
"YANG version of the SMIv2 DisplayString TEXTUAL-CONVENTION.";
reference