Toggle navigation
Toggle navigation
This project
Loading...
Sign in
홍길동
/
onos
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Snippets
Network
Create a new issue
Builds
Commits
Issue Boards
Authored by
tom
2014-08-29 11:38:49 -0700
Browse Files
Options
Browse Files
Download
Plain Diff
Commit
8f458bcb294ce442a0d1e3bf06fbdeeedcab2271
8f458bcb
2 parents
144de693
588f727f
Merge branch 'master' of
ssh://gerrit.onlab.us:29418/onos-next
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
1633 additions
and
81 deletions
of/api/src/main/java/org/onlab/onos/of/controller/OpenFlowSwitch.java
of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/AbstractOpenFlowSwitch.java
of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/Controller.java
of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/OFChannelHandler.java
of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/OpenFlowControllerImpl.java
of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/RoleManager.java
of/ctl/src/main/java/org/onlab/onos/of/drivers/DriverManager.java
of/ctl/src/main/java/org/onlab/onos/of/drivers/OFSwitchImplCPqD13.java
of/ctl/src/main/java/org/onlab/onos/of/drivers/OFSwitchImplOVS10.java
of/ctl/src/main/java/org/onlab/onos/of/drivers/OFSwitchImplOVS13.java
of/api/src/main/java/org/onlab/onos/of/controller/OpenFlowSwitch.java
View file @
8f458bc
...
...
@@ -13,7 +13,7 @@ public interface OpenFlowSwitch {
*
* @param msg the message to write
*/
public
void
write
(
OFMessage
msg
);
public
void
sendMsg
(
OFMessage
msg
);
/**
* Handle a message from the switch.
...
...
of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/AbstractOpenFlowSwitch.java
View file @
8f458bc
...
...
@@ -18,7 +18,9 @@
package
org
.
onlab
.
onos
.
of
.
controller
.
impl
.
internal
;
import
java.io.IOException
;
import
java.util.Collections
;
import
java.util.List
;
import
java.util.concurrent.atomic.AtomicInteger
;
import
org.jboss.netty.channel.Channel
;
import
org.onlab.onos.of.controller.Dpid
;
...
...
@@ -27,12 +29,14 @@ import org.onlab.onos.of.controller.RoleState;
import
org.onlab.onos.of.controller.impl.internal.OpenFlowControllerImpl.OpenFlowSwitchAgent
;
import
org.onlab.onos.of.controller.impl.internal.RoleManager.RoleRecvStatus
;
import
org.onlab.onos.of.controller.impl.internal.RoleManager.RoleReplyInfo
;
import
org.projectfloodlight.openflow.protocol.OFDescStatsReply
;
import
org.projectfloodlight.openflow.protocol.OFErrorMsg
;
import
org.projectfloodlight.openflow.protocol.OFExperimenter
;
import
org.projectfloodlight.openflow.protocol.OFFactories
;
import
org.projectfloodlight.openflow.protocol.OFFactory
;
import
org.projectfloodlight.openflow.protocol.OFFeaturesReply
;
import
org.projectfloodlight.openflow.protocol.OFMessage
;
import
org.projectfloodlight.openflow.protocol.OFPortDesc
;
import
org.projectfloodlight.openflow.protocol.OFPortDescStatsReply
;
import
org.projectfloodlight.openflow.protocol.OFRoleReply
;
import
org.projectfloodlight.openflow.protocol.OFVersion
;
...
...
@@ -45,10 +49,13 @@ public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitch {
private
static
Logger
log
=
LoggerFactory
.
getLogger
(
AbstractOpenFlowSwitch
.
class
);
private
Channel
channel
;
protected
Channel
channel
;
protected
boolean
startDriverHandshakeCalled
=
false
;
private
boolean
connected
;
private
Dpid
dpid
;
private
OpenFlowSwitchAgent
agent
;
private
AtomicInteger
xidCounter
=
new
AtomicInteger
(
0
);
private
OFVersion
ofVersion
;
...
...
@@ -58,8 +65,12 @@ public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitch {
private
final
RoleManager
roleMan
=
new
RoleManager
(
this
);
protected
AbstractOpenFlowSwitch
(
long
dpid
)
{
this
.
dpid
=
new
Dpid
(
dpid
);
protected
RoleState
role
;
protected
OFFeaturesReply
features
;
protected
AbstractOpenFlowSwitch
(
Dpid
dp
)
{
this
.
dpid
=
dp
;
}
//************************
...
...
@@ -80,14 +91,16 @@ public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitch {
*
* @param m the message to be written
*/
public
abstract
void
write
(
OFMessage
m
);
public
abstract
void
sendMsg
(
OFMessage
m
);
/**
* Writes to the OFMessage list to the output stream.
*
* @param msgs the messages to be written
*/
public
abstract
void
write
(
List
<
OFMessage
>
msgs
);
public
void
write
(
List
<
OFMessage
>
msgs
)
{
this
.
channel
.
write
(
msgs
);
}
/**
...
...
@@ -151,7 +164,9 @@ public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitch {
this
.
tableFull
=
full
;
}
public
abstract
void
setFeaturesReply
(
OFFeaturesReply
featuresReply
);
public
void
setFeaturesReply
(
OFFeaturesReply
featuresReply
)
{
this
.
features
=
featuresReply
;
}
/**
* Let peoeple know if you support Nicira style role requests.
...
...
@@ -172,7 +187,9 @@ public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitch {
this
.
agent
.
processMessage
(
m
);
}
public
abstract
RoleState
getRole
();
public
RoleState
getRole
()
{
return
role
;
};
final
boolean
addConnectedSwitch
()
{
return
this
.
agent
.
addConnectedSwitch
(
this
.
getId
(),
this
);
...
...
@@ -214,7 +231,9 @@ public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitch {
public
void
setRole
(
RoleState
role
)
{
try
{
this
.
roleMan
.
sendRoleRequest
(
role
,
RoleRecvStatus
.
MATCHED_SET_ROLE
);
if
(
this
.
roleMan
.
sendRoleRequest
(
role
,
RoleRecvStatus
.
MATCHED_SET_ROLE
))
{
this
.
role
=
role
;
}
}
catch
(
IOException
e
)
{
log
.
error
(
"Unable to write to switch {}."
,
this
.
dpid
);
}
...
...
@@ -236,23 +255,23 @@ public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitch {
}
void
handleNiciraRole
(
OFMessage
m
)
throws
SwitchStateException
{
RoleState
r
ole
=
this
.
roleMan
.
extractNiciraRoleReply
((
OFExperimenter
)
m
);
if
(
role
==
null
)
{
// The message wasn't really a Nicira role reply. We just
// dispatch it to the OFMessage listeners in this case.
this
.
handleMessage
(
m
);
}
RoleRecvStatus
rrs
=
this
.
roleMan
.
deliverRoleReply
(
new
RoleReplyInfo
(
role
,
null
,
m
.
getXid
()));
if
(
rrs
==
RoleRecvStatus
.
MATCHED_SET_ROLE
)
{
if
(
role
==
RoleState
.
MASTER
)
{
this
.
transitionToMasterSwitch
();
}
else
if
(
role
==
RoleState
.
EQUAL
||
role
==
RoleState
.
SLAVE
)
{
this
.
transitionToEqualSwitch
();
}
}
RoleState
r
=
this
.
roleMan
.
extractNiciraRoleReply
((
OFExperimenter
)
m
);
if
(
r
==
null
)
{
// The message wasn't really a Nicira role reply. We just
// dispatch it to the OFMessage listeners in this case.
this
.
handleMessage
(
m
);
}
RoleRecvStatus
rrs
=
this
.
roleMan
.
deliverRoleReply
(
new
RoleReplyInfo
(
r
,
null
,
m
.
getXid
()));
if
(
rrs
==
RoleRecvStatus
.
MATCHED_SET_ROLE
)
{
if
(
r
==
RoleState
.
MASTER
)
{
this
.
transitionToMasterSwitch
();
}
else
if
(
r
==
RoleState
.
EQUAL
||
r
==
RoleState
.
SLAVE
)
{
this
.
transitionToEqualSwitch
();
}
}
}
boolean
handleRoleError
(
OFErrorMsg
error
)
{
...
...
@@ -274,6 +293,16 @@ public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitch {
this
.
agent
=
ag
;
}
public
void
setSwitchDescription
(
OFDescStatsReply
desc
)
{
// TODO Auto-generated method stub
}
protected
int
getNextTransactionId
()
{
return
this
.
xidCounter
.
getAndIncrement
();
}
protected
List
<
OFPortDesc
>
getPorts
()
{
return
Collections
.
unmodifiableList
(
ports
.
getEntries
());
}
}
...
...
of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/Controller.java
View file @
8f458bc
...
...
@@ -29,9 +29,11 @@ import org.jboss.netty.channel.ChannelPipelineFactory;
import
org.jboss.netty.channel.group.ChannelGroup
;
import
org.jboss.netty.channel.group.DefaultChannelGroup
;
import
org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory
;
import
org.onlab.onos.of.controller.Dpid
;
import
org.onlab.onos.of.controller.impl.annotations.LogMessageDoc
;
import
org.onlab.onos.of.controller.impl.annotations.LogMessageDocs
;
import
org.onlab.onos.of.controller.impl.internal.OpenFlowControllerImpl.OpenFlowSwitchAgent
;
import
org.onlab.onos.of.drivers.DriverManager
;
import
org.projectfloodlight.openflow.protocol.OFDescStatsReply
;
import
org.projectfloodlight.openflow.protocol.OFFactories
;
import
org.projectfloodlight.openflow.protocol.OFFactory
;
...
...
@@ -83,11 +85,6 @@ public class Controller {
// Getters/Setters
// ***************
public
synchronized
void
setIOFSwitchManager
(
IOFSwitchManager
swManager
)
{
this
.
switchManager
=
swManager
;
}
public
OFFactory
getOFMessageFactory10
()
{
return
FACTORY10
;
}
...
...
@@ -201,18 +198,6 @@ public class Controller {
}
/**
* Startup all of the controller's components.
*/
@LogMessageDoc
(
message
=
"Waiting for storage source"
,
explanation
=
"The system database is not yet ready"
,
recommendation
=
"If this message persists, this indicates "
+
"that the system database has failed to start. "
+
LogMessageDoc
.
CHECK_CONTROLLER
)
public
synchronized
void
startupComponents
()
{
//TODO do something maybe
}
// **************
// Utility methods
// **************
...
...
@@ -236,9 +221,10 @@ public class Controller {
* @param desc
* @return switch instance
*/
protected
AbstractOpenFlowSwitch
getOFSwitchInstance
(
OFDescStatsReply
desc
,
OFVersion
ofv
)
{
AbstractOpenFlowSwitch
sw
=
switchManager
.
getSwitchImpl
(
desc
.
getMfrDesc
(),
desc
.
getHwDesc
(),
desc
.
getSwDesc
(),
ofv
);
protected
AbstractOpenFlowSwitch
getOFSwitchInstance
(
long
dpid
,
OFDescStatsReply
desc
,
OFVersion
ofv
)
{
AbstractOpenFlowSwitch
sw
=
DriverManager
.
getOFSwitchImpl
(
new
Dpid
(
dpid
),
desc
,
ofv
);
sw
.
setAgent
(
agent
);
return
sw
;
}
...
...
@@ -247,7 +233,6 @@ public class Controller {
log
.
info
(
"Initialising OpenFlow Lib and IO"
);
this
.
agent
=
ag
;
this
.
init
(
new
HashMap
<
String
,
String
>());
this
.
startupComponents
();
this
.
run
();
}
...
...
of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/OFChannelHandler.java
View file @
8f458bc
...
...
@@ -65,7 +65,6 @@ import org.slf4j.LoggerFactory;
*/
class
OFChannelHandler
extends
IdleStateAwareChannelHandler
{
private
static
final
Logger
log
=
LoggerFactory
.
getLogger
(
OFChannelHandler
.
class
);
private
static
final
long
DEFAULT_ROLE_TIMEOUT_MS
=
2
*
1000
;
// 10 sec
private
final
Controller
controller
;
private
AbstractOpenFlowSwitch
sw
;
private
long
thisdpid
;
// channelHandler cached value of connected switch id
...
...
@@ -230,12 +229,6 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
h
.
thisdpid
=
m
.
getDatapathId
().
getLong
();
log
.
info
(
"Received features reply for switch at {} with dpid {}"
,
h
.
getSwitchInfoString
(),
h
.
thisdpid
);
//update the controller about this connected switch
boolean
success
=
h
.
sw
.
addConnectedSwitch
();
if
(!
success
)
{
disconnectDuplicate
(
h
);
return
;
}
h
.
featuresReply
=
m
;
//temp store
if
(
h
.
ofVersion
==
OFVersion
.
OF_10
)
{
...
...
@@ -419,7 +412,12 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
h
.
channel
.
getRemoteAddress
());
OFDescStatsReply
drep
=
(
OFDescStatsReply
)
m
;
// Here is where we differentiate between different kinds of switches
h
.
sw
=
h
.
controller
.
getOFSwitchInstance
(
drep
,
h
.
ofVersion
);
h
.
sw
=
h
.
controller
.
getOFSwitchInstance
(
h
.
thisdpid
,
drep
,
h
.
ofVersion
);
boolean
success
=
h
.
sw
.
addConnectedSwitch
();
if
(!
success
)
{
disconnectDuplicate
(
h
);
return
;
}
// set switch information
h
.
sw
.
setOFVersion
(
h
.
ofVersion
);
h
.
sw
.
setFeaturesReply
(
h
.
featuresReply
);
...
...
@@ -433,7 +431,9 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
//Put switch in EQUAL mode until we hear back from the global registry
log
.
debug
(
"Setting new switch {} to EQUAL and sending Role request"
,
h
.
sw
.
getStringId
());
h
.
setSwitchRole
(
RoleState
.
EQUAL
);
h
.
sw
.
addActivatedEqualSwitch
();
//h.setSwitchRole(RoleState.EQUAL);
h
.
setSwitchRole
(
RoleState
.
MASTER
);
h
.
sw
.
startDriverHandshake
();
h
.
setState
(
WAIT_SWITCH_DRIVER_SUB_HANDSHAKE
);
...
...
of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/OpenFlowControllerImpl.java
View file @
8f458bc
...
...
@@ -24,12 +24,19 @@ import org.slf4j.LoggerFactory;
@Service
public
class
OpenFlowControllerImpl
implements
OpenFlowController
{
protected
ConcurrentHashMap
<
Long
,
OpenFlowSwitch
>
connectedSwitches
;
protected
ConcurrentHashMap
<
Long
,
OpenFlowSwitch
>
activeMasterSwitches
;
protected
ConcurrentHashMap
<
Long
,
OpenFlowSwitch
>
activeEqualSwitches
;
private
static
final
Logger
log
=
LoggerFactory
.
getLogger
(
OpenFlowControllerImpl
.
class
);
protected
ConcurrentHashMap
<
Long
,
OpenFlowSwitch
>
connectedSwitches
=
new
ConcurrentHashMap
<
Long
,
OpenFlowSwitch
>();
protected
ConcurrentHashMap
<
Long
,
OpenFlowSwitch
>
activeMasterSwitches
=
new
ConcurrentHashMap
<
Long
,
OpenFlowSwitch
>();
protected
ConcurrentHashMap
<
Long
,
OpenFlowSwitch
>
activeEqualSwitches
=
new
ConcurrentHashMap
<
Long
,
OpenFlowSwitch
>();
protected
OpenFlowSwitchAgent
agent
=
new
OpenFlowSwitchAgent
();
protected
ArrayList
<
OpenFlowSwitchListener
>
ofEventListener
;
protected
ArrayList
<
OpenFlowSwitchListener
>
ofEventListener
=
new
ArrayList
<
OpenFlowSwitchListener
>();
private
final
Controller
ctrl
=
new
Controller
();
...
...
@@ -98,29 +105,17 @@ public class OpenFlowControllerImpl implements OpenFlowController {
@Override
public
void
write
(
Dpid
dpid
,
OFMessage
msg
)
{
this
.
getSwitch
(
dpid
).
write
(
msg
);
this
.
getSwitch
(
dpid
).
sendMsg
(
msg
);
}
@Override
public
void
processPacket
(
OFMessage
msg
)
{
log
.
info
(
"Got message {}"
,
msg
);
}
@Override
public
void
setRole
(
Dpid
dpid
,
RoleState
role
)
{
switch
(
role
)
{
case
MASTER:
agent
.
transitionToMasterSwitch
(
dpid
.
value
());
break
;
case
EQUAL:
agent
.
transitionToEqualSwitch
(
dpid
.
value
());
break
;
case
SLAVE:
//agent.transitionToSlaveSwitch(dpid.value());
break
;
default
:
//WTF role is this?
}
((
AbstractOpenFlowSwitch
)
getSwitch
(
dpid
)).
setRole
(
role
);
}
public
class
OpenFlowSwitchAgent
{
...
...
@@ -189,6 +184,7 @@ public class OpenFlowControllerImpl implements OpenFlowController {
return
false
;
}
activeEqualSwitches
.
put
(
dpid
,
sw
);
log
.
info
(
"Added Activated EQUAL Switch {}"
,
dpid
);
return
true
;
}
finally
{
switchLock
.
unlock
();
...
...
@@ -203,6 +199,9 @@ public class OpenFlowControllerImpl implements OpenFlowController {
protected
void
transitionToMasterSwitch
(
long
dpid
)
{
switchLock
.
lock
();
try
{
if
(
activeMasterSwitches
.
containsKey
(
dpid
))
{
return
;
}
OpenFlowSwitch
sw
=
activeEqualSwitches
.
remove
(
dpid
);
if
(
sw
==
null
)
{
log
.
error
(
"Transition to master called on sw {}, but switch "
...
...
@@ -224,6 +223,9 @@ public class OpenFlowControllerImpl implements OpenFlowController {
protected
void
transitionToEqualSwitch
(
long
dpid
)
{
switchLock
.
lock
();
try
{
if
(
activeEqualSwitches
.
containsKey
(
dpid
))
{
return
;
}
OpenFlowSwitch
sw
=
activeMasterSwitches
.
remove
(
dpid
);
if
(
sw
==
null
)
{
log
.
error
(
"Transition to equal called on sw {}, but switch "
...
...
of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/RoleManager.java
View file @
8f458bc
...
...
@@ -2,7 +2,6 @@ package org.onlab.onos.of.controller.impl.internal;
import
java.io.IOException
;
import
java.util.Collections
;
import
java.util.concurrent.atomic.AtomicInteger
;
import
org.onlab.onos.of.controller.RoleState
;
import
org.projectfloodlight.openflow.protocol.OFControllerRole
;
...
...
@@ -50,7 +49,6 @@ class RoleManager {
// the expectation set by the caller for the returned role
private
RoleRecvStatus
expectation
;
private
AtomicInteger
xidCounter
;
private
AbstractOpenFlowSwitch
sw
;
...
...
@@ -58,7 +56,6 @@ class RoleManager {
this
.
requestPending
=
false
;
this
.
pendingXid
=
-
1
;
this
.
pendingRole
=
null
;
this
.
xidCounter
=
new
AtomicInteger
(
0
);
this
.
expectation
=
RoleRecvStatus
.
MATCHED_CURRENT_ROLE
;
this
.
sw
=
sw
;
}
...
...
@@ -85,7 +82,7 @@ class RoleManager {
roleToSend
=
OFNiciraControllerRole
.
ROLE_SLAVE
;
log
.
warn
(
"Sending Nx Role.SLAVE to switch {}."
,
sw
);
}
int
xid
=
xidCounter
.
getAndIncrement
();
int
xid
=
sw
.
getNextTransactionId
();
OFExperimenter
roleRequest
=
OFFactories
.
getFactory
(
OFVersion
.
OF_10
)
.
buildNiciraControllerRoleRequest
()
.
setXid
(
xid
)
...
...
@@ -113,7 +110,7 @@ class RoleManager {
+
" Should only be used for queries."
,
sw
);
}
int
xid
=
xidCounter
.
getAndIncrement
();
int
xid
=
sw
.
getNextTransactionId
();
OFRoleRequest
rrm
=
OFFactories
.
getFactory
(
OFVersion
.
OF_13
)
.
buildRoleRequest
()
.
setRole
(
roleToSend
)
...
...
@@ -121,7 +118,7 @@ class RoleManager {
//FIXME fix below when we actually use generation ids
.
setGenerationId
(
U64
.
ZERO
)
.
build
();
sw
.
write
(
rrm
);
sw
.
sendMsg
(
rrm
);
return
xid
;
}
...
...
of/ctl/src/main/java/org/onlab/onos/of/drivers/DriverManager.java
0 → 100644
View file @
8f458bc
package
org
.
onlab
.
onos
.
of
.
drivers
;
import
org.onlab.onos.of.controller.Dpid
;
import
org.onlab.onos.of.controller.RoleState
;
import
org.onlab.onos.of.controller.impl.internal.AbstractOpenFlowSwitch
;
import
org.projectfloodlight.openflow.protocol.OFDescStatsReply
;
import
org.projectfloodlight.openflow.protocol.OFFeaturesReply
;
import
org.projectfloodlight.openflow.protocol.OFMessage
;
import
org.projectfloodlight.openflow.protocol.OFVersion
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
/**
* A simple implementation of a driver manager that differentiates between
* connected switches using the OF Description Statistics Reply message.
*/
public
final
class
DriverManager
{
private
static
final
Logger
log
=
LoggerFactory
.
getLogger
(
DriverManager
.
class
);
// Whether to use an OF 1.3 configured TTP, or to use an OF 1.0-style
// single table with packet-ins.
private
static
boolean
cpqdUsePipeline13
=
false
;
/**
* Return an IOFSwitch object based on switch's manufacturer description
* from OFDescStatsReply.
*
* @param desc DescriptionStatistics reply from the switch
* @return A IOFSwitch instance if the driver found an implementation for
* the given description. Otherwise it returns OFSwitchImplBase
*/
public
static
AbstractOpenFlowSwitch
getOFSwitchImpl
(
Dpid
dpid
,
OFDescStatsReply
desc
,
OFVersion
ofv
)
{
String
vendor
=
desc
.
getMfrDesc
();
String
hw
=
desc
.
getHwDesc
();
if
(
vendor
.
startsWith
(
"Stanford University, Ericsson Research and CPqD Research"
)
&&
hw
.
startsWith
(
"OpenFlow 1.3 Reference Userspace Switch"
))
{
return
new
OFSwitchImplCPqD13
(
dpid
,
desc
,
cpqdUsePipeline13
);
}
if
(
vendor
.
startsWith
(
"Nicira"
)
&&
hw
.
startsWith
(
"Open vSwitch"
))
{
if
(
ofv
==
OFVersion
.
OF_10
)
{
return
new
OFSwitchImplOVS10
(
dpid
,
desc
);
}
else
if
(
ofv
==
OFVersion
.
OF_13
)
{
return
new
OFSwitchImplOVS13
(
dpid
,
desc
);
}
}
log
.
warn
(
"DriverManager could not identify switch desc: {}. "
+
"Assigning OFSwitchImplBase"
,
desc
);
AbstractOpenFlowSwitch
base
=
new
AbstractOpenFlowSwitch
(
dpid
)
{
@Override
public
void
sendMsg
(
OFMessage
m
)
{
channel
.
write
(
m
);
}
@Override
public
Boolean
supportNxRole
()
{
return
false
;
}
@Override
public
void
startDriverHandshake
()
{}
@Override
public
void
setFeaturesReply
(
OFFeaturesReply
featuresReply
)
{
this
.
features
=
featuresReply
;
}
@Override
public
void
processDriverHandshakeMessage
(
OFMessage
m
)
{}
@Override
public
boolean
isDriverHandshakeComplete
()
{
return
true
;
}
@Override
public
RoleState
getRole
()
{
return
role
;
}
};
base
.
setSwitchDescription
(
desc
);
return
base
;
}
/**
* Private constructor to avoid instantiation.
*/
private
DriverManager
()
{
}
/**
* Sets the configuration parameter which determines how the CPqD switch
* is set up. If usePipeline13 is true, a 1.3 pipeline will be set up on
* the switch. Otherwise, the switch will be set up in a 1.0 style with
* a single table where missed packets are sent to the controller.
*
* @param usePipeline13 whether to use a 1.3 pipeline or not
*/
public
static
void
setConfigForCpqd
(
boolean
usePipeline13
)
{
cpqdUsePipeline13
=
usePipeline13
;
}
}
of/ctl/src/main/java/org/onlab/onos/of/drivers/OFSwitchImplCPqD13.java
0 → 100644
View file @
8f458bc
package
org
.
onlab
.
onos
.
of
.
drivers
;
import
java.io.IOException
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.List
;
import
java.util.concurrent.ConcurrentHashMap
;
import
java.util.concurrent.atomic.AtomicBoolean
;
import
org.onlab.onos.of.controller.Dpid
;
import
org.onlab.onos.of.controller.RoleState
;
import
org.onlab.onos.of.controller.impl.internal.AbstractOpenFlowSwitch
;
import
org.onlab.onos.of.controller.impl.internal.SwitchDriverSubHandshakeAlreadyStarted
;
import
org.onlab.onos.of.controller.impl.internal.SwitchDriverSubHandshakeCompleted
;
import
org.onlab.onos.of.controller.impl.internal.SwitchDriverSubHandshakeNotStarted
;
import
org.projectfloodlight.openflow.protocol.OFAsyncGetReply
;
import
org.projectfloodlight.openflow.protocol.OFBarrierRequest
;
import
org.projectfloodlight.openflow.protocol.OFBucket
;
import
org.projectfloodlight.openflow.protocol.OFDescStatsReply
;
import
org.projectfloodlight.openflow.protocol.OFErrorMsg
;
import
org.projectfloodlight.openflow.protocol.OFFactory
;
import
org.projectfloodlight.openflow.protocol.OFGroupDescStatsReply
;
import
org.projectfloodlight.openflow.protocol.OFGroupFeaturesStatsReply
;
import
org.projectfloodlight.openflow.protocol.OFGroupType
;
import
org.projectfloodlight.openflow.protocol.OFMatchV3
;
import
org.projectfloodlight.openflow.protocol.OFMessage
;
import
org.projectfloodlight.openflow.protocol.OFOxmList
;
import
org.projectfloodlight.openflow.protocol.OFPortDesc
;
import
org.projectfloodlight.openflow.protocol.OFStatsReply
;
import
org.projectfloodlight.openflow.protocol.action.OFAction
;
import
org.projectfloodlight.openflow.protocol.instruction.OFInstruction
;
import
org.projectfloodlight.openflow.protocol.oxm.OFOxmEthDst
;
import
org.projectfloodlight.openflow.protocol.oxm.OFOxmEthSrc
;
import
org.projectfloodlight.openflow.protocol.oxm.OFOxmEthType
;
import
org.projectfloodlight.openflow.protocol.oxm.OFOxmInPort
;
import
org.projectfloodlight.openflow.protocol.oxm.OFOxmIpv4DstMasked
;
import
org.projectfloodlight.openflow.protocol.oxm.OFOxmMetadataMasked
;
import
org.projectfloodlight.openflow.protocol.oxm.OFOxmMplsLabel
;
import
org.projectfloodlight.openflow.protocol.oxm.OFOxmVlanVid
;
import
org.projectfloodlight.openflow.types.EthType
;
import
org.projectfloodlight.openflow.types.IPv4Address
;
import
org.projectfloodlight.openflow.types.MacAddress
;
import
org.projectfloodlight.openflow.types.OFBufferId
;
import
org.projectfloodlight.openflow.types.OFGroup
;
import
org.projectfloodlight.openflow.types.OFMetadata
;
import
org.projectfloodlight.openflow.types.OFPort
;
import
org.projectfloodlight.openflow.types.OFVlanVidMatch
;
import
org.projectfloodlight.openflow.types.TableId
;
import
org.projectfloodlight.openflow.types.U32
;
import
org.projectfloodlight.openflow.types.U64
;
import
org.projectfloodlight.openflow.util.HexString
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
/**
* OFDescriptionStatistics Vendor (Manufacturer Desc.): Stanford University,
* Ericsson Research and CPqD Research. Make (Hardware Desc.) : OpenFlow 1.3
* Reference Userspace Switch Model (Datapath Desc.) : None Software : Serial :
* None
*/
public
class
OFSwitchImplCPqD13
extends
AbstractOpenFlowSwitch
{
private
static
Logger
log
=
LoggerFactory
.
getLogger
(
OFSwitchImplCPqD13
.
class
);
private
static
final
int
VLAN_ID_OFFSET
=
16
;
private
AtomicBoolean
driverHandshakeComplete
;
private
OFFactory
factory
;
private
static
final
int
OFPCML_NO_BUFFER
=
0xffff
;
// Configuration of asynch messages to controller. We need different
// asynch messages depending on role-equal or role-master.
// We don't want to get anything if we are slave.
private
static
final
long
SET_FLOW_REMOVED_MASK_MASTER
=
0xf
;
private
static
final
long
SET_PACKET_IN_MASK_MASTER
=
0x7
;
private
static
final
long
SET_PORT_STATUS_MASK_MASTER
=
0x7
;
private
static
final
long
SET_FLOW_REMOVED_MASK_EQUAL
=
0x0
;
private
static
final
long
SET_PACKET_IN_MASK_EQUAL
=
0x0
;
private
static
final
long
SET_PORT_STATUS_MASK_EQUAL
=
0x7
;
private
static
final
long
SET_ALL_SLAVE
=
0x0
;
private
static
final
long
TEST_FLOW_REMOVED_MASK
=
0xf
;
private
static
final
long
TEST_PACKET_IN_MASK
=
0x7
;
private
static
final
long
TEST_PORT_STATUS_MASK
=
0x7
;
private
long
barrierXidToWaitFor
=
-
1
;
private
static
final
int
TABLE_VLAN
=
0
;
private
static
final
int
TABLE_TMAC
=
1
;
private
static
final
int
TABLE_IPV4_UNICAST
=
2
;
private
static
final
int
TABLE_MPLS
=
3
;
private
static
final
int
TABLE_META
=
4
;
private
static
final
int
TABLE_ACL
=
5
;
private
static
final
short
MAX_PRIORITY
=
(
short
)
0xffff
;
private
static
final
short
SLASH_24_PRIORITY
=
(
short
)
0xfff0
;
private
static
final
short
MIN_PRIORITY
=
0x0
;
private
static
final
U64
METADATA_MASK
=
U64
.
of
(
Long
.
MAX_VALUE
<<
1
|
0x1
);
ConcurrentHashMap
<
Integer
,
OFGroup
>
l2groups
;
private
final
boolean
usePipeline13
;
public
OFSwitchImplCPqD13
(
Dpid
dpid
,
OFDescStatsReply
desc
,
boolean
usePipeline13
)
{
super
(
dpid
);
driverHandshakeComplete
=
new
AtomicBoolean
(
false
);
l2groups
=
new
ConcurrentHashMap
<
Integer
,
OFGroup
>();
setSwitchDescription
(
desc
);
this
.
usePipeline13
=
usePipeline13
;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public
String
toString
()
{
return
"OFSwitchImplCPqD13 ["
+
((
channel
!=
null
)
?
channel
.
getRemoteAddress
()
:
"?"
)
+
" DPID["
+
((
this
.
getStringId
()
!=
null
)
?
this
.
getStringId
()
:
"?"
)
+
"]]"
;
}
@Override
public
void
startDriverHandshake
()
{
log
.
debug
(
"Starting driver handshake for sw {}"
,
getStringId
());
if
(
startDriverHandshakeCalled
)
{
throw
new
SwitchDriverSubHandshakeAlreadyStarted
();
}
startDriverHandshakeCalled
=
true
;
factory
=
this
.
factory
();
if
(!
usePipeline13
)
{
// Send packet-in to controller if a packet misses the first table
populateTableMissEntry
(
0
,
true
,
false
,
false
,
0
);
}
//else {
// configureSwitch();
//}
sendBarrier
(
true
);
}
@Override
public
boolean
isDriverHandshakeComplete
()
{
if
(!
startDriverHandshakeCalled
)
{
throw
new
SwitchDriverSubHandshakeNotStarted
();
}
return
driverHandshakeComplete
.
get
();
}
@Override
public
void
processDriverHandshakeMessage
(
OFMessage
m
)
{
if
(!
startDriverHandshakeCalled
)
{
throw
new
SwitchDriverSubHandshakeNotStarted
();
}
if
(
driverHandshakeComplete
.
get
())
{
throw
new
SwitchDriverSubHandshakeCompleted
(
m
);
}
if
(!
startDriverHandshakeCalled
)
{
throw
new
SwitchDriverSubHandshakeNotStarted
();
}
if
(
driverHandshakeComplete
.
get
())
{
throw
new
SwitchDriverSubHandshakeCompleted
(
m
);
}
switch
(
m
.
getType
())
{
case
BARRIER_REPLY:
if
(
m
.
getXid
()
==
barrierXidToWaitFor
)
{
driverHandshakeComplete
.
set
(
true
);
}
break
;
case
ERROR:
log
.
error
(
"Switch {} Error {}"
,
getStringId
(),
(
OFErrorMsg
)
m
);
break
;
case
FEATURES_REPLY:
break
;
case
FLOW_REMOVED:
break
;
case
GET_ASYNC_REPLY:
OFAsyncGetReply
asrep
=
(
OFAsyncGetReply
)
m
;
decodeAsyncGetReply
(
asrep
);
break
;
case
PACKET_IN:
break
;
case
PORT_STATUS:
break
;
case
QUEUE_GET_CONFIG_REPLY:
break
;
case
ROLE_REPLY:
break
;
case
STATS_REPLY:
processStatsReply
((
OFStatsReply
)
m
);
break
;
default
:
log
.
debug
(
"Received message {} during switch-driver subhandshake "
+
"from switch {} ... Ignoring message"
,
m
,
getStringId
());
}
}
private
void
configureSwitch
()
throws
IOException
{
// setAsyncConfig();
// getTableFeatures();
sendGroupFeaturesRequest
();
setL2Groups
();
sendBarrier
(
false
);
setL3Groups
();
setL25Groups
();
sendGroupDescRequest
();
populateTableVlan
();
populateTableTMac
();
populateIpTable
();
populateMplsTable
();
populateTableMissEntry
(
TABLE_ACL
,
false
,
false
,
false
,
-
1
);
sendBarrier
(
true
);
}
private
void
setAsyncConfig
()
throws
IOException
{
List
<
OFMessage
>
msglist
=
new
ArrayList
<
OFMessage
>(
3
);
OFMessage
setAC
=
null
;
if
(
role
==
RoleState
.
MASTER
)
{
setAC
=
factory
.
buildAsyncSet
()
.
setFlowRemovedMaskEqualMaster
(
SET_FLOW_REMOVED_MASK_MASTER
)
.
setPacketInMaskEqualMaster
(
SET_PACKET_IN_MASK_MASTER
)
.
setPortStatusMaskEqualMaster
(
SET_PORT_STATUS_MASK_MASTER
)
.
setFlowRemovedMaskSlave
(
SET_ALL_SLAVE
)
.
setPacketInMaskSlave
(
SET_ALL_SLAVE
)
.
setPortStatusMaskSlave
(
SET_ALL_SLAVE
)
.
setXid
(
getNextTransactionId
())
.
build
();
}
else
if
(
role
==
RoleState
.
EQUAL
)
{
setAC
=
factory
.
buildAsyncSet
()
.
setFlowRemovedMaskEqualMaster
(
SET_FLOW_REMOVED_MASK_EQUAL
)
.
setPacketInMaskEqualMaster
(
SET_PACKET_IN_MASK_EQUAL
)
.
setPortStatusMaskEqualMaster
(
SET_PORT_STATUS_MASK_EQUAL
)
.
setFlowRemovedMaskSlave
(
SET_ALL_SLAVE
)
.
setPacketInMaskSlave
(
SET_ALL_SLAVE
)
.
setPortStatusMaskSlave
(
SET_ALL_SLAVE
)
.
setXid
(
getNextTransactionId
())
.
build
();
}
msglist
.
add
(
setAC
);
OFMessage
br
=
factory
.
buildBarrierRequest
()
.
setXid
(
getNextTransactionId
())
.
build
();
msglist
.
add
(
br
);
OFMessage
getAC
=
factory
.
buildAsyncGetRequest
()
.
setXid
(
getNextTransactionId
())
.
build
();
msglist
.
add
(
getAC
);
write
(
msglist
);
}
private
void
decodeAsyncGetReply
(
OFAsyncGetReply
rep
)
{
long
frm
=
rep
.
getFlowRemovedMaskEqualMaster
();
//long frs = rep.getFlowRemovedMaskSlave();
long
pim
=
rep
.
getPacketInMaskEqualMaster
();
//long pis = rep.getPacketInMaskSlave();
long
psm
=
rep
.
getPortStatusMaskEqualMaster
();
//long pss = rep.getPortStatusMaskSlave();
if
(
role
==
RoleState
.
MASTER
||
role
==
RoleState
.
EQUAL
)
{
// should separate
log
.
info
(
"FRM:{}"
,
HexString
.
toHexString
((
frm
&
TEST_FLOW_REMOVED_MASK
)));
log
.
info
(
"PIM:{}"
,
HexString
.
toHexString
((
pim
&
TEST_PACKET_IN_MASK
)));
log
.
info
(
"PSM:{}"
,
HexString
.
toHexString
((
psm
&
TEST_PORT_STATUS_MASK
)));
}
}
private
void
getTableFeatures
()
throws
IOException
{
OFMessage
gtf
=
factory
.
buildTableFeaturesStatsRequest
()
.
setXid
(
getNextTransactionId
())
.
build
();
sendMsg
(
gtf
);
}
private
void
sendGroupFeaturesRequest
()
throws
IOException
{
OFMessage
gfr
=
factory
.
buildGroupFeaturesStatsRequest
()
.
setXid
(
getNextTransactionId
())
.
build
();
sendMsg
(
gfr
);
}
private
void
sendGroupDescRequest
()
throws
IOException
{
OFMessage
gdr
=
factory
.
buildGroupDescStatsRequest
()
.
setXid
(
getNextTransactionId
())
.
build
();
sendMsg
(
gdr
);
}
/*Create L2 interface groups for all physical ports
Naming convention followed is the same as OF-DPA spec
eg. port 1 with allowed vlan 10, is enveloped in group with id,
0x0 00a 0001, where the uppermost 4 bits identify an L2 interface,
the next 12 bits identify the vlan-id, and the lowermost 16 bits
identify the port number.*/
private
void
setL2Groups
()
throws
IOException
{
List
<
OFMessage
>
msglist
=
new
ArrayList
<
OFMessage
>();
for
(
OFPortDesc
p
:
getPorts
())
{
int
pnum
=
p
.
getPortNo
().
getPortNumber
();
int
portVlan
=
getVlanConfig
(
pnum
);
if
(
U32
.
of
(
pnum
).
compareTo
(
U32
.
of
(
OFPort
.
MAX
.
getPortNumber
()))
<
1
)
{
OFGroup
gl2
=
OFGroup
.
of
(
pnum
|
(
portVlan
<<
VLAN_ID_OFFSET
));
OFAction
out
=
factory
.
actions
().
buildOutput
()
.
setPort
(
p
.
getPortNo
()).
build
();
OFAction
popVlan
=
factory
.
actions
().
popVlan
();
List
<
OFAction
>
actions
=
new
ArrayList
<
OFAction
>();
actions
.
add
(
popVlan
);
actions
.
add
(
out
);
OFBucket
bucket
=
factory
.
buildBucket
()
.
setActions
(
actions
).
build
();
List
<
OFBucket
>
buckets
=
Collections
.
singletonList
(
bucket
);
OFMessage
gmAdd
=
factory
.
buildGroupAdd
()
.
setGroup
(
gl2
)
.
setBuckets
(
buckets
)
.
setGroupType
(
OFGroupType
.
INDIRECT
)
.
setXid
(
getNextTransactionId
())
.
build
();
msglist
.
add
(
gmAdd
);
l2groups
.
put
(
pnum
,
gl2
);
}
}
log
.
debug
(
"Creating {} L2 groups in sw {}"
,
msglist
.
size
(),
getStringId
());
write
(
msglist
);
}
private
int
getVlanConfig
(
int
portnum
)
{
int
portVlan
=
10
*
portnum
;
if
((
getId
()
==
0x1
&&
portnum
==
6
)
||
(
getId
()
==
0x2
)
||
(
getId
()
==
0x3
&&
portnum
==
2
))
{
portVlan
=
192
;
// 0xc0
}
return
portVlan
;
}
private
MacAddress
getRouterMacAddr
()
{
if
(
getId
()
==
0x3
)
{
return
MacAddress
.
of
(
"00:00:07:07:07:80"
);
// router mac
}
if
(
getId
()
==
0x1
)
{
return
MacAddress
.
of
(
"00:00:01:01:01:80"
);
}
// switch 0x2
return
MacAddress
.
of
(
"00:00:02:02:02:80"
);
}
// only for ports connected to other routers
private
OFAction
getDestAction
(
int
portnum
)
{
OFAction
setDA
=
null
;
MacAddress
dAddr
=
null
;
if
(
getId
()
==
0x1
&&
portnum
==
6
)
{
// connected to switch 2
dAddr
=
MacAddress
.
of
(
"00:00:02:02:02:80"
);
}
if
(
getId
()
==
0x2
)
{
if
(
portnum
==
1
)
{
// connected to sw 1
dAddr
=
MacAddress
.
of
(
"00:00:01:01:01:80"
);
}
else
if
(
portnum
==
2
)
{
// connected to sw 3
dAddr
=
MacAddress
.
of
(
"00:00:07:07:07:80"
);
}
}
if
(
getId
()
==
0x3
)
{
if
(
portnum
==
2
)
{
// connected to switch 2
dAddr
=
MacAddress
.
of
(
"00:00:02:02:02:80"
);
}
}
if
(
dAddr
!=
null
)
{
OFOxmEthDst
dstAddr
=
factory
.
oxms
().
ethDst
(
dAddr
);
setDA
=
factory
.
actions
().
buildSetField
()
.
setField
(
dstAddr
).
build
();
}
return
setDA
;
}
/*
* L3 groups are created for all router ports and they all point to corresponding
* L2 groups. Only the ports that connect to other routers will have the
* DA set.
*/
private
void
setL3Groups
()
throws
IOException
{
List
<
OFMessage
>
msglist
=
new
ArrayList
<
OFMessage
>();
for
(
OFGroup
gl2
:
l2groups
.
values
())
{
int
gnum
=
gl2
.
getGroupNumber
();
int
portnum
=
gnum
&
0x0000ffff
;
int
vlanid
=
((
gnum
&
0x0fff0000
)
>>
VLAN_ID_OFFSET
);
MacAddress
sAddr
=
getRouterMacAddr
();
OFGroup
gl3
=
OFGroup
.
of
(
0x20000000
|
portnum
);
OFAction
group
=
factory
.
actions
().
buildGroup
()
.
setGroup
(
gl2
).
build
();
OFOxmEthSrc
srcAddr
=
factory
.
oxms
().
ethSrc
(
sAddr
);
OFAction
setSA
=
factory
.
actions
().
buildSetField
()
.
setField
(
srcAddr
).
build
();
OFOxmVlanVid
vid
=
factory
.
oxms
().
vlanVid
(
OFVlanVidMatch
.
ofVlan
(
vlanid
));
OFAction
setVlan
=
factory
.
actions
().
buildSetField
()
.
setField
(
vid
).
build
();
OFAction
decTtl
=
factory
.
actions
().
decNwTtl
();
List
<
OFAction
>
actions
=
new
ArrayList
<
OFAction
>();
actions
.
add
(
decTtl
);
// decrement the IP TTL/do-checksum/check TTL
// and MTU
actions
.
add
(
setVlan
);
// set the vlan-id of the exit-port (and
// l2group)
actions
.
add
(
setSA
);
// set this routers mac address
// make L3Unicast group setDA for known (configured) ports
// that connect to other routers
OFAction
setDA
=
getDestAction
(
portnum
);
if
(
setDA
!=
null
)
{
actions
.
add
(
setDA
);
}
actions
.
add
(
group
);
OFBucket
bucket
=
factory
.
buildBucket
()
.
setActions
(
actions
).
build
();
List
<
OFBucket
>
buckets
=
Collections
.
singletonList
(
bucket
);
OFMessage
gmAdd
=
factory
.
buildGroupAdd
()
.
setGroup
(
gl3
)
.
setBuckets
(
buckets
)
.
setGroupType
(
OFGroupType
.
INDIRECT
)
.
setXid
(
getNextTransactionId
())
.
build
();
msglist
.
add
(
gmAdd
);
}
write
(
msglist
);
log
.
debug
(
"Creating {} L3 groups in sw {}"
,
msglist
.
size
(),
getStringId
());
}
/*
* L2.5 or mpls-unicast groups are only created for those router ports
* connected to other router ports. They differ from the corresponding
* L3-unicast group only by the fact that they decrement the MPLS TTL
* instead of the IP ttl
*/
private
void
setL25Groups
()
throws
IOException
{
List
<
OFMessage
>
msglist
=
new
ArrayList
<
OFMessage
>();
for
(
OFGroup
gl2
:
l2groups
.
values
())
{
int
gnum
=
gl2
.
getGroupNumber
();
int
portnum
=
gnum
&
0x0000ffff
;
int
vlanid
=
((
gnum
&
0x0fff0000
)
>>
VLAN_ID_OFFSET
);
MacAddress
sAddr
=
getRouterMacAddr
();
OFAction
setDA
=
getDestAction
(
portnum
);
// setDA will only be non-null for ports connected to routers
if
(
setDA
!=
null
)
{
OFGroup
gl3
=
OFGroup
.
of
(
0xa0000000
|
portnum
);
// different id
// for mpls
// group
OFAction
group
=
factory
.
actions
().
buildGroup
()
.
setGroup
(
gl2
).
build
();
OFOxmEthSrc
srcAddr
=
factory
.
oxms
().
ethSrc
(
sAddr
);
OFAction
setSA
=
factory
.
actions
().
buildSetField
()
.
setField
(
srcAddr
).
build
();
OFOxmVlanVid
vid
=
factory
.
oxms
().
vlanVid
(
OFVlanVidMatch
.
ofVlan
(
vlanid
));
OFAction
setVlan
=
factory
.
actions
().
buildSetField
()
.
setField
(
vid
).
build
();
OFAction
decMplsTtl
=
factory
.
actions
().
decMplsTtl
();
List
<
OFAction
>
actions
=
new
ArrayList
<
OFAction
>();
actions
.
add
(
decMplsTtl
);
// decrement the MPLS
// TTL/do-checksum/check TTL and MTU
actions
.
add
(
setVlan
);
// set the vlan-id of the exit-port (and
// l2group)
actions
.
add
(
setSA
);
// set this routers mac address
actions
.
add
(
setDA
);
actions
.
add
(
group
);
OFBucket
bucket
=
factory
.
buildBucket
()
.
setActions
(
actions
).
build
();
List
<
OFBucket
>
buckets
=
Collections
.
singletonList
(
bucket
);
OFMessage
gmAdd
=
factory
.
buildGroupAdd
()
.
setGroup
(
gl3
)
.
setBuckets
(
buckets
)
.
setGroupType
(
OFGroupType
.
INDIRECT
)
.
setXid
(
getNextTransactionId
())
.
build
();
msglist
.
add
(
gmAdd
);
}
}
write
(
msglist
);
log
.
debug
(
"Creating {} MPLS groups in sw {}"
,
msglist
.
size
(),
getStringId
());
}
/* Using ECMP groups
*
* OFGroup group47 = OFGroup.of(47);
OFAction outgroup1 = factory.actions()
.buildGroup()
.setGroup(group61)
.build();
OFBucket buc47_1 = factory.buildBucket()
.setWeight(1)
.setActions(Collections.singletonList(outgroup1))
.build();
OFAction outgroup2 = factory.actions()
.buildGroup()
.setGroup(group62)
.build();
OFBucket buc47_2 = factory.buildBucket()
.setWeight(1)
.setActions(Collections.singletonList(outgroup2))
.build();
List<OFBucket> buckets47 = new ArrayList<OFBucket>();
buckets47.add(buc47_1);
buckets47.add(buc47_2);
OFMessage gmS12 = factory.buildGroupAdd()
.setGroup(group47)
.setBuckets(buckets47)
.setGroupType(OFGroupType.SELECT)
.setXid(getNextTransactionId())
.build();
write(gmS12, null); */
private
void
processStatsReply
(
OFStatsReply
sr
)
{
switch
(
sr
.
getStatsType
())
{
case
AGGREGATE:
break
;
case
DESC:
break
;
case
EXPERIMENTER:
break
;
case
FLOW:
break
;
case
GROUP_DESC:
processGroupDesc
((
OFGroupDescStatsReply
)
sr
);
break
;
case
GROUP_FEATURES:
processGroupFeatures
((
OFGroupFeaturesStatsReply
)
sr
);
break
;
case
METER_CONFIG:
break
;
case
METER_FEATURES:
break
;
case
PORT_DESC:
break
;
case
TABLE_FEATURES:
break
;
default
:
break
;
}
}
private
void
processGroupFeatures
(
OFGroupFeaturesStatsReply
gfsr
)
{
log
.
info
(
"Sw: {} Group Features {}"
,
getStringId
(),
gfsr
);
}
private
void
processGroupDesc
(
OFGroupDescStatsReply
gdsr
)
{
log
.
info
(
"Sw: {} Group Desc {}"
,
getStringId
(),
gdsr
);
}
private
void
populateTableVlan
()
throws
IOException
{
// for all incoming ports assign configured port-vlans
// currently assign portnum*10 -> vlanid to access ports
// and vlan 192 to router to router ports
List
<
OFMessage
>
msglist
=
new
ArrayList
<
OFMessage
>();
for
(
OFPortDesc
p
:
getPorts
())
{
int
pnum
=
p
.
getPortNo
().
getPortNumber
();
if
(
U32
.
of
(
pnum
).
compareTo
(
U32
.
of
(
OFPort
.
MAX
.
getPortNumber
()))
<
1
)
{
int
vlanid
=
getVlanConfig
(
pnum
);
OFOxmInPort
oxp
=
factory
.
oxms
().
inPort
(
p
.
getPortNo
());
OFOxmVlanVid
oxv
=
factory
.
oxms
()
.
vlanVid
(
OFVlanVidMatch
.
UNTAGGED
);
OFOxmList
oxmList
=
OFOxmList
.
of
(
oxp
,
oxv
);
OFMatchV3
match
=
factory
.
buildMatchV3
()
.
setOxmList
(
oxmList
).
build
();
OFOxmVlanVid
vidToSet
=
factory
.
oxms
()
.
vlanVid
(
OFVlanVidMatch
.
ofVlan
(
vlanid
));
OFAction
pushVlan
=
factory
.
actions
().
pushVlan
(
EthType
.
VLAN_FRAME
);
OFAction
setVlan
=
factory
.
actions
().
setField
(
vidToSet
);
List
<
OFAction
>
actionlist
=
new
ArrayList
<
OFAction
>();
actionlist
.
add
(
pushVlan
);
actionlist
.
add
(
setVlan
);
OFInstruction
appAction
=
factory
.
instructions
().
buildApplyActions
()
.
setActions
(
actionlist
).
build
();
OFInstruction
gotoTbl
=
factory
.
instructions
().
buildGotoTable
()
.
setTableId
(
TableId
.
of
(
TABLE_TMAC
)).
build
();
List
<
OFInstruction
>
instructions
=
new
ArrayList
<
OFInstruction
>();
instructions
.
add
(
appAction
);
instructions
.
add
(
gotoTbl
);
OFMessage
flowEntry
=
factory
.
buildFlowAdd
()
.
setTableId
(
TableId
.
of
(
TABLE_VLAN
))
.
setMatch
(
match
)
.
setInstructions
(
instructions
)
.
setPriority
(
1000
)
// does not matter - all rules
// exclusive
.
setBufferId
(
OFBufferId
.
NO_BUFFER
)
.
setIdleTimeout
(
0
)
.
setHardTimeout
(
0
)
.
setXid
(
getNextTransactionId
())
.
build
();
msglist
.
add
(
flowEntry
);
}
}
// table-vlan has no table-miss entry, and so packets that miss are
// essentially dropped
write
(
msglist
);
log
.
debug
(
"Adding {} vlan-rules in sw {}"
,
msglist
.
size
(),
getStringId
());
}
private
void
populateTableTMac
()
throws
IOException
{
// match for ip packets
OFOxmEthType
oxe
=
factory
.
oxms
().
ethType
(
EthType
.
IPv4
);
OFOxmList
oxmListIp
=
OFOxmList
.
of
(
oxe
);
OFMatchV3
matchIp
=
factory
.
buildMatchV3
()
.
setOxmList
(
oxmListIp
).
build
();
OFInstruction
gotoTblIp
=
factory
.
instructions
().
buildGotoTable
()
.
setTableId
(
TableId
.
of
(
TABLE_IPV4_UNICAST
)).
build
();
List
<
OFInstruction
>
instructionsIp
=
Collections
.
singletonList
(
gotoTblIp
);
OFMessage
ipEntry
=
factory
.
buildFlowAdd
()
.
setTableId
(
TableId
.
of
(
TABLE_TMAC
))
.
setMatch
(
matchIp
)
.
setInstructions
(
instructionsIp
)
.
setPriority
(
1000
)
// strict priority required lower than
// multicastMac
.
setBufferId
(
OFBufferId
.
NO_BUFFER
)
.
setIdleTimeout
(
0
)
.
setHardTimeout
(
0
)
.
setXid
(
getNextTransactionId
())
.
build
();
// match for mpls packets
OFOxmEthType
oxmpls
=
factory
.
oxms
().
ethType
(
EthType
.
MPLS_UNICAST
);
OFOxmList
oxmListMpls
=
OFOxmList
.
of
(
oxmpls
);
OFMatchV3
matchMpls
=
factory
.
buildMatchV3
()
.
setOxmList
(
oxmListMpls
).
build
();
OFInstruction
gotoTblMpls
=
factory
.
instructions
().
buildGotoTable
()
.
setTableId
(
TableId
.
of
(
TABLE_MPLS
)).
build
();
List
<
OFInstruction
>
instructionsMpls
=
Collections
.
singletonList
(
gotoTblMpls
);
OFMessage
mplsEntry
=
factory
.
buildFlowAdd
()
.
setTableId
(
TableId
.
of
(
TABLE_TMAC
))
.
setMatch
(
matchMpls
)
.
setInstructions
(
instructionsMpls
)
.
setPriority
(
1001
)
// strict priority required lower than
// multicastMac
.
setBufferId
(
OFBufferId
.
NO_BUFFER
)
.
setIdleTimeout
(
0
)
.
setHardTimeout
(
0
)
.
setXid
(
getNextTransactionId
())
.
build
();
// match for everything else to send to controller. Essentially
// the table miss flow entry
populateTableMissEntry
(
TABLE_TMAC
,
true
,
false
,
false
,
-
1
);
log
.
debug
(
"Adding termination-mac-rules in sw {}"
,
getStringId
());
List
<
OFMessage
>
msglist
=
new
ArrayList
<
OFMessage
>(
2
);
msglist
.
add
(
ipEntry
);
msglist
.
add
(
mplsEntry
);
write
(
msglist
);
}
private
List
<
String
>
getMyIps
()
{
// send to controller
List
<
String
>
myIps
=
new
ArrayList
<
String
>();
if
(
getId
()
==
0x1
)
{
myIps
.
add
(
"10.0.2.128"
);
myIps
.
add
(
"10.0.3.128"
);
myIps
.
add
(
"10.0.1.128"
);
myIps
.
add
(
"192.168.0.1"
);
}
if
(
getId
()
==
0x2
)
{
myIps
.
add
(
"192.168.0.2"
);
}
if
(
getId
()
==
0x3
)
{
myIps
.
add
(
"192.168.0.3"
);
myIps
.
add
(
"7.7.7.128"
);
}
return
myIps
;
}
private
List
<
String
>
getMySubnetIps
()
{
// send to controller
List
<
String
>
subnetIps
=
new
ArrayList
<
String
>();
if
(
getId
()
==
0x1
)
{
subnetIps
.
add
(
"10.0.2.0"
);
subnetIps
.
add
(
"10.0.3.0"
);
subnetIps
.
add
(
"10.0.1.0"
);
}
// TODO needed?
//if (getId() == 0x2) {
//}
if
(
getId
()
==
0x3
)
{
subnetIps
.
add
(
"7.7.7.0"
);
}
return
subnetIps
;
}
private
static
class
RouteEntry
{
String
prefix
;
String
mask
;
int
nextHopPort
;
String
dstMac
;
int
label
;
public
RouteEntry
(
String
prefix
,
String
mask
,
int
nextHopPort
,
int
label
)
{
this
.
prefix
=
prefix
;
this
.
mask
=
mask
;
this
.
nextHopPort
=
nextHopPort
;
this
.
label
=
label
;
}
public
RouteEntry
(
String
prefix
,
int
nextHopPort
,
String
dstMac
)
{
this
.
prefix
=
prefix
;
this
.
nextHopPort
=
nextHopPort
;
this
.
dstMac
=
dstMac
;
}
}
// send out of mpls-group where the next-hop mac-da is already set
private
List
<
RouteEntry
>
getRouterNextHopIps
()
{
List
<
RouteEntry
>
routerNextHopIps
=
new
ArrayList
<
RouteEntry
>();
if
(
getId
()
==
0x1
)
{
routerNextHopIps
.
add
(
new
RouteEntry
(
"192.168.0.2"
,
"255.255.255.255"
,
6
,
102
));
routerNextHopIps
.
add
(
new
RouteEntry
(
"192.168.0.3"
,
"255.255.255.255"
,
6
,
103
));
routerNextHopIps
.
add
(
new
RouteEntry
(
"7.7.7.0"
,
"255.255.255.0"
,
6
,
103
));
}
//if (getId() == 0x2) {
/* These are required for normal IP routing without labels.
routerNextHopIps.add(new RouteEntry("192.168.0.1","255.255.255.255",1));
routerNextHopIps.add(new RouteEntry("192.168.0.3","255.255.255.255",2));
routerNextHopIps.add(new RouteEntry("10.0.1.0","255.255.255.0",1));
routerNextHopIps.add(new RouteEntry("10.0.2.0","255.255.255.0",1));
routerNextHopIps.add(new RouteEntry("10.0.3.0","255.255.255.0",1));
routerNextHopIps.add(new RouteEntry("7.7.7.0","255.255.255.0",2));*/
//}
if
(
getId
()
==
0x3
)
{
routerNextHopIps
.
add
(
new
RouteEntry
(
"192.168.0.2"
,
"255.255.255.255"
,
2
,
102
));
routerNextHopIps
.
add
(
new
RouteEntry
(
"192.168.0.1"
,
"255.255.255.255"
,
2
,
101
));
routerNextHopIps
.
add
(
new
RouteEntry
(
"10.0.1.0"
,
"255.255.255.0"
,
2
,
101
));
routerNextHopIps
.
add
(
new
RouteEntry
(
"10.0.2.0"
,
"255.255.255.0"
,
2
,
101
));
routerNextHopIps
.
add
(
new
RouteEntry
(
"10.0.3.0"
,
"255.255.255.0"
,
2
,
101
));
}
return
routerNextHopIps
;
}
// known host mac-addr, setDA/send out of l3group
private
List
<
RouteEntry
>
getHostNextHopIps
()
{
List
<
RouteEntry
>
hostNextHopIps
=
new
ArrayList
<
RouteEntry
>();
if
(
getId
()
==
0x1
)
{
hostNextHopIps
.
add
(
new
RouteEntry
(
"10.0.2.1"
,
4
,
"00:00:00:00:02:01"
));
hostNextHopIps
.
add
(
new
RouteEntry
(
"10.0.3.1"
,
5
,
"00:00:00:00:03:01"
));
}
// TODO needed?
//if (getId() == 0x2) {
//}
if
(
getId
()
==
0x3
)
{
hostNextHopIps
.
add
(
new
RouteEntry
(
"7.7.7.7"
,
1
,
"00:00:07:07:07:07"
));
}
return
hostNextHopIps
;
}
private
void
populateIpTable
()
throws
IOException
{
populateMyIps
();
populateMySubnets
();
populateRoutes
();
populateHostRoutes
();
// match for everything else to send to ACL table. Essentially
// the table miss flow entry
populateTableMissEntry
(
TABLE_IPV4_UNICAST
,
false
,
true
,
true
,
TABLE_ACL
);
}
private
void
populateMyIps
()
throws
IOException
{
List
<
OFMessage
>
msglist
=
new
ArrayList
<
OFMessage
>();
// first all my ip's as exact-matches
// write-action instruction to send to controller
List
<
String
>
myIps
=
getMyIps
();
for
(
int
i
=
0
;
i
<
myIps
.
size
();
i
++)
{
OFOxmEthType
ethTypeIp
=
factory
.
oxms
()
.
ethType
(
EthType
.
IPv4
);
OFOxmIpv4DstMasked
ipPrefix
=
factory
.
oxms
()
.
ipv4DstMasked
(
IPv4Address
.
of
(
myIps
.
get
(
i
)),
IPv4Address
.
NO_MASK
);
OFOxmList
oxmListSlash32
=
OFOxmList
.
of
(
ethTypeIp
,
ipPrefix
);
OFMatchV3
match
=
factory
.
buildMatchV3
()
.
setOxmList
(
oxmListSlash32
).
build
();
OFAction
outc
=
factory
.
actions
().
buildOutput
()
.
setPort
(
OFPort
.
CONTROLLER
).
setMaxLen
(
OFPCML_NO_BUFFER
)
.
build
();
OFInstruction
writeInstr
=
factory
.
instructions
().
buildWriteActions
()
.
setActions
(
Collections
.
singletonList
(
outc
)).
build
();
OFInstruction
gotoInstr
=
factory
.
instructions
().
buildGotoTable
()
.
setTableId
(
TableId
.
of
(
TABLE_ACL
)).
build
();
List
<
OFInstruction
>
instructions
=
new
ArrayList
<
OFInstruction
>();
instructions
.
add
(
writeInstr
);
instructions
.
add
(
gotoInstr
);
OFMessage
myIpEntry
=
factory
.
buildFlowAdd
()
.
setTableId
(
TableId
.
of
(
TABLE_IPV4_UNICAST
))
.
setMatch
(
match
)
.
setInstructions
(
instructions
)
.
setPriority
(
MAX_PRIORITY
)
// highest priority for exact
// match
.
setBufferId
(
OFBufferId
.
NO_BUFFER
)
.
setIdleTimeout
(
0
)
.
setHardTimeout
(
0
)
.
setXid
(
getNextTransactionId
())
.
build
();
msglist
.
add
(
myIpEntry
);
}
write
(
msglist
);
log
.
debug
(
"Adding {} my-ip-rules in sw {}"
,
msglist
.
size
(),
getStringId
());
}
private
void
populateMySubnets
()
throws
IOException
{
List
<
OFMessage
>
msglist
=
new
ArrayList
<
OFMessage
>();
// next prefix-based subnet-IP's configured on my interfaces
// need to ARP for exact-IP, so write-action instruction to send to
// controller
// this has different mask and priority than earlier case
List
<
String
>
subnetIps
=
getMySubnetIps
();
for
(
int
i
=
0
;
i
<
subnetIps
.
size
();
i
++)
{
OFOxmEthType
ethTypeIp
=
factory
.
oxms
()
.
ethType
(
EthType
.
IPv4
);
OFOxmIpv4DstMasked
ipPrefix
=
factory
.
oxms
().
ipv4DstMasked
(
IPv4Address
.
of
(
subnetIps
.
get
(
i
)),
IPv4Address
.
of
(
0xffffff00
));
// '/24' mask
OFOxmList
oxmListSlash24
=
OFOxmList
.
of
(
ethTypeIp
,
ipPrefix
);
OFMatchV3
match
=
factory
.
buildMatchV3
()
.
setOxmList
(
oxmListSlash24
).
build
();
OFAction
outc
=
factory
.
actions
().
buildOutput
()
.
setPort
(
OFPort
.
CONTROLLER
).
setMaxLen
(
OFPCML_NO_BUFFER
)
.
build
();
OFInstruction
writeInstr
=
factory
.
instructions
().
buildWriteActions
()
.
setActions
(
Collections
.
singletonList
(
outc
)).
build
();
OFInstruction
gotoInstr
=
factory
.
instructions
().
buildGotoTable
()
.
setTableId
(
TableId
.
of
(
TABLE_ACL
)).
build
();
List
<
OFInstruction
>
instructions
=
new
ArrayList
<
OFInstruction
>();
instructions
.
add
(
writeInstr
);
instructions
.
add
(
gotoInstr
);
OFMessage
myIpEntry
=
factory
.
buildFlowAdd
()
.
setTableId
(
TableId
.
of
(
TABLE_IPV4_UNICAST
))
.
setMatch
(
match
)
.
setInstructions
(
instructions
)
.
setPriority
(
SLASH_24_PRIORITY
)
.
setBufferId
(
OFBufferId
.
NO_BUFFER
)
.
setIdleTimeout
(
0
)
.
setHardTimeout
(
0
)
.
setXid
(
getNextTransactionId
())
.
build
();
msglist
.
add
(
myIpEntry
);
}
write
(
msglist
);
log
.
debug
(
"Adding {} subnet-ip-rules in sw {}"
,
msglist
.
size
(),
getStringId
());
msglist
.
clear
();
}
private
void
populateRoutes
()
throws
IOException
{
List
<
OFMessage
>
msglist
=
new
ArrayList
<
OFMessage
>();
// addresses where I know the next-hop's mac-address because it is a
// router port - so I have an L3 interface to it (and an MPLS interface)
List
<
RouteEntry
>
routerNextHopIps
=
getRouterNextHopIps
();
for
(
int
i
=
0
;
i
<
routerNextHopIps
.
size
();
i
++)
{
OFOxmEthType
ethTypeIp
=
factory
.
oxms
()
.
ethType
(
EthType
.
IPv4
);
OFOxmIpv4DstMasked
ipPrefix
=
factory
.
oxms
()
.
ipv4DstMasked
(
IPv4Address
.
of
(
routerNextHopIps
.
get
(
i
).
prefix
),
IPv4Address
.
of
(
routerNextHopIps
.
get
(
i
).
mask
)
);
OFOxmList
oxmListSlash32
=
OFOxmList
.
of
(
ethTypeIp
,
ipPrefix
);
OFMatchV3
match
=
factory
.
buildMatchV3
()
.
setOxmList
(
oxmListSlash32
).
build
();
OFAction
outg
=
factory
.
actions
().
buildGroup
()
.
setGroup
(
OFGroup
.
of
(
0xa0000000
|
// mpls group id
routerNextHopIps
.
get
(
i
).
nextHopPort
))
.
build
();
// lots of actions before forwarding to mpls group, and
// unfortunately
// they need to be apply-actions
OFAction
pushlabel
=
factory
.
actions
().
pushMpls
(
EthType
.
MPLS_UNICAST
);
OFOxmMplsLabel
l
=
factory
.
oxms
()
.
mplsLabel
(
U32
.
of
(
routerNextHopIps
.
get
(
i
).
label
));
OFAction
setlabelid
=
factory
.
actions
().
buildSetField
()
.
setField
(
l
).
build
();
OFAction
copyTtlOut
=
factory
.
actions
().
copyTtlOut
();
// OFAction setBos =
// factory.actions().buildSetField().setField(bos).build();
/*
writeActions.add(pushlabel); // need to be apply actions so can be
writeActions.add(copyTtlOut); // matched in pseudo-table
//writeActions.add(setlabelid); // bad support in cpqd
//writeActions.add(setBos); no support in loxigen
*/
List
<
OFAction
>
applyActions
=
new
ArrayList
<
OFAction
>();
applyActions
.
add
(
pushlabel
);
applyActions
.
add
(
copyTtlOut
);
OFInstruction
applyInstr
=
factory
.
instructions
().
buildApplyActions
()
.
setActions
(
applyActions
).
build
();
List
<
OFAction
>
writeActions
=
new
ArrayList
<
OFAction
>();
writeActions
.
add
(
outg
);
// group will decr mpls-ttl, set mac-sa/da,
// vlan
OFInstruction
writeInstr
=
factory
.
instructions
().
buildWriteActions
()
.
setActions
(
writeActions
).
build
();
// necessary to match in pseudo-table to overcome cpqd 1.3 flaw
OFInstruction
writeMeta
=
factory
.
instructions
().
buildWriteMetadata
()
.
setMetadata
(
U64
.
of
(
routerNextHopIps
.
get
(
i
).
label
))
.
setMetadataMask
(
METADATA_MASK
).
build
();
/*OFInstruction gotoInstr = factory.instructions().buildGotoTable()
.setTableId(TableId.of(TABLE_ACL)).build();*/
OFInstruction
gotoInstr
=
factory
.
instructions
().
buildGotoTable
()
.
setTableId
(
TableId
.
of
(
TABLE_META
)).
build
();
List
<
OFInstruction
>
instructions
=
new
ArrayList
<
OFInstruction
>();
instructions
.
add
(
applyInstr
);
// instructions.add(writeInstr);// cannot write here - causes switch
// to crash
instructions
.
add
(
writeMeta
);
instructions
.
add
(
gotoInstr
);
int
priority
=
-
1
;
if
(
routerNextHopIps
.
get
(
i
).
mask
.
equals
(
"255.255.255.255"
))
{
priority
=
MAX_PRIORITY
;
}
else
{
priority
=
SLASH_24_PRIORITY
;
}
OFMessage
myIpEntry
=
factory
.
buildFlowAdd
()
.
setTableId
(
TableId
.
of
(
TABLE_IPV4_UNICAST
))
.
setMatch
(
match
)
.
setInstructions
(
instructions
)
.
setPriority
(
priority
)
.
setBufferId
(
OFBufferId
.
NO_BUFFER
)
.
setIdleTimeout
(
0
)
.
setHardTimeout
(
0
)
.
setXid
(
getNextTransactionId
())
.
build
();
msglist
.
add
(
myIpEntry
);
// need to also handle psuedo-table entries to match-metadata and
// set mpls
// label-id
OFOxmEthType
ethTypeMpls
=
factory
.
oxms
()
.
ethType
(
EthType
.
MPLS_UNICAST
);
OFOxmMetadataMasked
meta
=
factory
.
oxms
()
.
metadataMasked
(
OFMetadata
.
ofRaw
(
routerNextHopIps
.
get
(
i
).
label
),
OFMetadata
.
NO_MASK
);
OFOxmList
oxmListMeta
=
OFOxmList
.
of
(
ethTypeMpls
,
meta
);
OFMatchV3
matchMeta
=
factory
.
buildMatchV3
()
.
setOxmList
(
oxmListMeta
).
build
();
List
<
OFAction
>
writeActions2
=
new
ArrayList
<
OFAction
>();
writeActions2
.
add
(
setlabelid
);
OFAction
outg2
=
factory
.
actions
().
buildGroup
()
.
setGroup
(
OFGroup
.
of
(
routerNextHopIps
.
get
(
i
).
nextHopPort
|
(
192
<<
VLAN_ID_OFFSET
)))
.
build
();
writeActions2
.
add
(
outg2
);
OFInstruction
writeInstr2
=
factory
.
instructions
().
buildWriteActions
()
.
setActions
(
writeActions2
).
build
();
OFInstruction
gotoInstr2
=
factory
.
instructions
().
buildGotoTable
()
.
setTableId
(
TableId
.
of
(
TABLE_ACL
)).
build
();
List
<
OFInstruction
>
instructions2
=
new
ArrayList
<
OFInstruction
>();
// unfortunately have to apply this action too
OFInstruction
applyInstr2
=
factory
.
instructions
().
buildApplyActions
()
.
setActions
(
writeActions2
).
build
();
instructions2
.
add
(
applyInstr2
);
// instructions2.add(writeInstr2);
// instructions2.add(gotoInstr2);
/*OFMatchV3 match3 = factory.buildMatchV3()
.setOxmList(OFOxmList.of(meta)).build();
OFInstruction clearInstruction = factory.instructions().clearActions();
List<OFInstruction> instructions3 = new ArrayList<OFInstruction>();
OFAction outc = factory.actions().buildOutput()
.setPort(OFPort.CONTROLLER).setMaxLen(OFPCML_NO_BUFFER)
.build();
OFInstruction writec = factory.instructions()
.writeActions(Collections.singletonList(outc));
instructions3.add(clearInstruction);
instructions3.add(writec);
instructions3.add(gotoInstr2); */
OFMessage
myMetaEntry
=
factory
.
buildFlowAdd
()
.
setTableId
(
TableId
.
of
(
TABLE_META
))
.
setMatch
(
matchMeta
)
.
setInstructions
(
instructions2
)
.
setPriority
(
MAX_PRIORITY
)
.
setBufferId
(
OFBufferId
.
NO_BUFFER
)
.
setIdleTimeout
(
0
)
.
setHardTimeout
(
0
)
.
setXid
(
getNextTransactionId
())
.
build
();
msglist
.
add
(
myMetaEntry
);
}
write
(
msglist
);
log
.
debug
(
"Adding {} next-hop-router-rules in sw {}"
,
msglist
.
size
(),
getStringId
());
// add a table-miss entry to table 4 for debugging - leave it out
// unclear packet state - causes switch to crash
// populateTableMissEntry(TABLE_META, false, true,
// true, TABLE_ACL);
}
private
void
populateHostRoutes
()
throws
IOException
{
List
<
OFMessage
>
msglist
=
new
ArrayList
<
OFMessage
>();
// addresses where I know the next hop's mac-address and I can set the
// destination mac in the match-instruction.write-action
// either I sent out arp-request or I got an arp-request from this host
List
<
RouteEntry
>
hostNextHopIps
=
getHostNextHopIps
();
for
(
int
i
=
0
;
i
<
hostNextHopIps
.
size
();
i
++)
{
OFOxmEthType
ethTypeIp
=
factory
.
oxms
()
.
ethType
(
EthType
.
IPv4
);
OFOxmIpv4DstMasked
ipPrefix
=
factory
.
oxms
()
.
ipv4DstMasked
(
IPv4Address
.
of
(
hostNextHopIps
.
get
(
i
).
prefix
),
IPv4Address
.
NO_MASK
);
// host addr should be /32
OFOxmList
oxmListSlash32
=
OFOxmList
.
of
(
ethTypeIp
,
ipPrefix
);
OFMatchV3
match
=
factory
.
buildMatchV3
()
.
setOxmList
(
oxmListSlash32
).
build
();
OFAction
setDmac
=
null
,
outg
=
null
;
OFOxmEthDst
dmac
=
factory
.
oxms
()
.
ethDst
(
MacAddress
.
of
(
hostNextHopIps
.
get
(
i
).
dstMac
));
setDmac
=
factory
.
actions
().
buildSetField
()
.
setField
(
dmac
).
build
();
outg
=
factory
.
actions
().
buildGroup
()
.
setGroup
(
OFGroup
.
of
(
0x20000000
|
hostNextHopIps
.
get
(
i
).
nextHopPort
))
// l3group
// id
.
build
();
List
<
OFAction
>
writeActions
=
new
ArrayList
<
OFAction
>();
writeActions
.
add
(
setDmac
);
writeActions
.
add
(
outg
);
OFInstruction
writeInstr
=
factory
.
instructions
().
buildWriteActions
()
.
setActions
(
writeActions
).
build
();
OFInstruction
gotoInstr
=
factory
.
instructions
().
buildGotoTable
()
.
setTableId
(
TableId
.
of
(
TABLE_ACL
)).
build
();
List
<
OFInstruction
>
instructions
=
new
ArrayList
<
OFInstruction
>();
instructions
.
add
(
writeInstr
);
instructions
.
add
(
gotoInstr
);
OFMessage
myIpEntry
=
factory
.
buildFlowAdd
()
.
setTableId
(
TableId
.
of
(
TABLE_IPV4_UNICAST
))
.
setMatch
(
match
)
.
setInstructions
(
instructions
)
.
setPriority
(
MAX_PRIORITY
)
// highest priority for exact
// match
.
setBufferId
(
OFBufferId
.
NO_BUFFER
)
.
setIdleTimeout
(
0
)
.
setHardTimeout
(
0
)
.
setXid
(
getNextTransactionId
())
.
build
();
msglist
.
add
(
myIpEntry
);
}
write
(
msglist
);
log
.
debug
(
"Adding {} next-hop-host-rules in sw {}"
,
msglist
.
size
(),
getStringId
());
}
private
static
class
MplsEntry
{
int
labelid
;
int
portnum
;
public
MplsEntry
(
int
labelid
,
int
portnum
)
{
this
.
labelid
=
labelid
;
this
.
portnum
=
portnum
;
}
}
private
List
<
MplsEntry
>
getMplsEntries
()
{
List
<
MplsEntry
>
myLabels
=
new
ArrayList
<
MplsEntry
>();
if
(
getId
()
==
0x1
)
{
myLabels
.
add
(
new
MplsEntry
(
101
,
OFPort
.
CONTROLLER
.
getPortNumber
()));
myLabels
.
add
(
new
MplsEntry
(
103
,
6
));
}
if
(
getId
()
==
0x2
)
{
myLabels
.
add
(
new
MplsEntry
(
103
,
2
));
myLabels
.
add
(
new
MplsEntry
(
102
,
OFPort
.
CONTROLLER
.
getPortNumber
()));
myLabels
.
add
(
new
MplsEntry
(
101
,
1
));
}
if
(
getId
()
==
0x3
)
{
myLabels
.
add
(
new
MplsEntry
(
103
,
OFPort
.
CONTROLLER
.
getPortNumber
()));
myLabels
.
add
(
new
MplsEntry
(
101
,
2
));
}
return
myLabels
;
}
private
void
populateMplsTable
()
throws
IOException
{
List
<
OFMessage
>
msglist
=
new
ArrayList
<
OFMessage
>();
List
<
MplsEntry
>
lfibEntries
=
getMplsEntries
();
for
(
int
i
=
0
;
i
<
lfibEntries
.
size
();
i
++)
{
OFOxmEthType
ethTypeMpls
=
factory
.
oxms
()
.
ethType
(
EthType
.
MPLS_UNICAST
);
OFOxmMplsLabel
labelid
=
factory
.
oxms
()
.
mplsLabel
(
U32
.
of
(
lfibEntries
.
get
(
i
).
labelid
));
OFOxmList
oxmList
=
OFOxmList
.
of
(
ethTypeMpls
,
labelid
);
OFMatchV3
matchlabel
=
factory
.
buildMatchV3
()
.
setOxmList
(
oxmList
).
build
();
OFAction
poplabel
=
factory
.
actions
().
popMpls
(
EthType
.
IPv4
);
OFAction
sendTo
=
null
;
if
(
lfibEntries
.
get
(
i
).
portnum
==
OFPort
.
CONTROLLER
.
getPortNumber
())
{
sendTo
=
factory
.
actions
().
output
(
OFPort
.
CONTROLLER
,
OFPCML_NO_BUFFER
);
}
else
{
sendTo
=
factory
.
actions
().
group
(
OFGroup
.
of
(
0xa0000000
|
lfibEntries
.
get
(
i
).
portnum
));
}
List
<
OFAction
>
writeActions
=
new
ArrayList
<
OFAction
>();
writeActions
.
add
(
poplabel
);
writeActions
.
add
(
sendTo
);
OFInstruction
writeInstr
=
factory
.
instructions
().
buildWriteActions
()
.
setActions
(
writeActions
).
build
();
OFInstruction
gotoInstr
=
factory
.
instructions
().
buildGotoTable
()
.
setTableId
(
TableId
.
of
(
TABLE_ACL
)).
build
();
List
<
OFInstruction
>
instructions
=
new
ArrayList
<
OFInstruction
>();
instructions
.
add
(
writeInstr
);
instructions
.
add
(
gotoInstr
);
OFMessage
myMplsEntry
=
factory
.
buildFlowAdd
()
.
setTableId
(
TableId
.
of
(
TABLE_MPLS
))
.
setMatch
(
matchlabel
)
.
setInstructions
(
instructions
)
.
setPriority
(
MAX_PRIORITY
)
// exact match and exclusive
.
setBufferId
(
OFBufferId
.
NO_BUFFER
)
.
setIdleTimeout
(
0
)
.
setHardTimeout
(
0
)
.
setXid
(
getNextTransactionId
())
.
build
();
msglist
.
add
(
myMplsEntry
);
}
write
(
msglist
);
log
.
debug
(
"Adding {} mpls-forwarding-rules in sw {}"
,
msglist
.
size
(),
getStringId
());
// match for everything else to send to ACL table. Essentially
// the table miss flow entry
populateTableMissEntry
(
TABLE_MPLS
,
false
,
true
,
true
,
TABLE_ACL
);
}
/**
* By default if none of the booleans in the call are set, then the
* table-miss entry is added with no instructions, which means that pipeline
* execution will stop, and the action set associated with the packet will
* be executed.
*
* @param tableToAdd
* @param toControllerNow as an APPLY_ACTION instruction
* @param toControllerWrite as a WRITE_ACITION instruction
* @param toTable as a GOTO_TABLE instruction
* @param tableToSend
* @throws IOException
*/
@SuppressWarnings
(
"unchecked"
)
private
void
populateTableMissEntry
(
int
tableToAdd
,
boolean
toControllerNow
,
boolean
toControllerWrite
,
boolean
toTable
,
int
tableToSend
)
{
OFOxmList
oxmList
=
OFOxmList
.
EMPTY
;
OFMatchV3
match
=
factory
.
buildMatchV3
()
.
setOxmList
(
oxmList
)
.
build
();
OFAction
outc
=
factory
.
actions
()
.
buildOutput
()
.
setPort
(
OFPort
.
CONTROLLER
)
.
setMaxLen
(
OFPCML_NO_BUFFER
)
.
build
();
List
<
OFInstruction
>
instructions
=
new
ArrayList
<
OFInstruction
>();
if
(
toControllerNow
)
{
// table-miss instruction to send to controller immediately
OFInstruction
instr
=
factory
.
instructions
()
.
buildApplyActions
()
.
setActions
(
Collections
.
singletonList
(
outc
))
.
build
();
instructions
.
add
(
instr
);
}
if
(
toControllerWrite
)
{
// table-miss instruction to write-action to send to controller
// this will be executed whenever the action-set gets executed
OFInstruction
instr
=
factory
.
instructions
()
.
buildWriteActions
()
.
setActions
(
Collections
.
singletonList
(
outc
))
.
build
();
instructions
.
add
(
instr
);
}
if
(
toTable
)
{
// table-miss instruction to goto-table x
OFInstruction
instr
=
factory
.
instructions
()
.
gotoTable
(
TableId
.
of
(
tableToSend
));
instructions
.
add
(
instr
);
}
if
(!
toControllerNow
&&
!
toControllerWrite
&&
!
toTable
)
{
// table-miss has no instruction - at which point action-set will be
// executed - if there is an action to output/group in the action
// set
// the packet will be sent there, otherwise it will be dropped.
instructions
=
(
List
<
OFInstruction
>)
Collections
.
EMPTY_LIST
;
}
OFMessage
tableMissEntry
=
factory
.
buildFlowAdd
()
.
setTableId
(
TableId
.
of
(
tableToAdd
))
.
setMatch
(
match
)
// match everything
.
setInstructions
(
instructions
)
.
setPriority
(
MIN_PRIORITY
)
.
setBufferId
(
OFBufferId
.
NO_BUFFER
)
.
setIdleTimeout
(
0
)
.
setHardTimeout
(
0
)
.
setXid
(
getNextTransactionId
())
.
build
();
sendMsg
(
tableMissEntry
);
}
private
void
sendBarrier
(
boolean
finalBarrier
)
{
int
xid
=
getNextTransactionId
();
if
(
finalBarrier
)
{
barrierXidToWaitFor
=
xid
;
}
OFBarrierRequest
br
=
factory
.
buildBarrierRequest
()
.
setXid
(
xid
)
.
build
();
sendMsg
(
br
);
}
@Override
public
void
sendMsg
(
OFMessage
m
)
{
channel
.
write
(
m
);
}
@Override
public
void
write
(
List
<
OFMessage
>
msgs
)
{
for
(
OFMessage
m
:
msgs
)
{
channel
.
write
(
m
);
}
}
@Override
public
Boolean
supportNxRole
()
{
return
false
;
}
}
of/ctl/src/main/java/org/onlab/onos/of/drivers/OFSwitchImplOVS10.java
0 → 100644
View file @
8f458bc
package
org
.
onlab
.
onos
.
of
.
drivers
;
import
org.onlab.onos.of.controller.Dpid
;
import
org.onlab.onos.of.controller.impl.internal.AbstractOpenFlowSwitch
;
import
org.projectfloodlight.openflow.protocol.OFDescStatsReply
;
import
org.projectfloodlight.openflow.protocol.OFMessage
;
/**
* OFDescriptionStatistics Vendor (Manufacturer Desc.): Nicira, Inc. Make
* (Hardware Desc.) : Open vSwitch Model (Datapath Desc.) : None Software :
* 1.11.90 (or whatever version + build) Serial : None
*/
public
class
OFSwitchImplOVS10
extends
AbstractOpenFlowSwitch
{
public
OFSwitchImplOVS10
(
Dpid
dpid
,
OFDescStatsReply
desc
)
{
super
(
dpid
);
setSwitchDescription
(
desc
);
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public
String
toString
()
{
return
"OFSwitchImplOVS10 ["
+
((
channel
!=
null
)
?
channel
.
getRemoteAddress
()
:
"?"
)
+
" DPID["
+
((
getStringId
()
!=
null
)
?
getStringId
()
:
"?"
)
+
"]]"
;
}
@Override
public
void
sendMsg
(
OFMessage
m
)
{
channel
.
write
(
m
);
}
@Override
public
Boolean
supportNxRole
()
{
return
true
;
}
@Override
public
void
startDriverHandshake
()
{}
@Override
public
boolean
isDriverHandshakeComplete
()
{
return
true
;
}
@Override
public
void
processDriverHandshakeMessage
(
OFMessage
m
)
{}
}
of/ctl/src/main/java/org/onlab/onos/of/drivers/OFSwitchImplOVS13.java
0 → 100644
View file @
8f458bc
package
org
.
onlab
.
onos
.
of
.
drivers
;
import
java.util.concurrent.atomic.AtomicBoolean
;
import
org.onlab.onos.of.controller.Dpid
;
import
org.onlab.onos.of.controller.impl.internal.AbstractOpenFlowSwitch
;
import
org.onlab.onos.of.controller.impl.internal.SwitchDriverSubHandshakeAlreadyStarted
;
import
org.onlab.onos.of.controller.impl.internal.SwitchDriverSubHandshakeCompleted
;
import
org.onlab.onos.of.controller.impl.internal.SwitchDriverSubHandshakeNotStarted
;
import
org.projectfloodlight.openflow.protocol.OFBarrierRequest
;
import
org.projectfloodlight.openflow.protocol.OFDescStatsReply
;
import
org.projectfloodlight.openflow.protocol.OFErrorMsg
;
import
org.projectfloodlight.openflow.protocol.OFFactory
;
import
org.projectfloodlight.openflow.protocol.OFMessage
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
/**
* OFDescriptionStatistics Vendor (Manufacturer Desc.): Nicira, Inc. Make
* (Hardware Desc.) : Open vSwitch Model (Datapath Desc.) : None Software :
* 2.1.0 (or whatever version + build) Serial : None
*/
public
class
OFSwitchImplOVS13
extends
AbstractOpenFlowSwitch
{
private
static
Logger
log
=
LoggerFactory
.
getLogger
(
OFSwitchImplOVS13
.
class
);
private
AtomicBoolean
driverHandshakeComplete
;
private
OFFactory
factory
;
private
long
barrierXidToWaitFor
=
-
1
;
public
OFSwitchImplOVS13
(
Dpid
dpid
,
OFDescStatsReply
desc
)
{
super
(
dpid
);
driverHandshakeComplete
=
new
AtomicBoolean
(
false
);
setSwitchDescription
(
desc
);
}
@Override
public
String
toString
()
{
return
"OFSwitchImplOVS13 ["
+
((
channel
!=
null
)
?
channel
.
getRemoteAddress
()
:
"?"
)
+
" DPID["
+
((
getStringId
()
!=
null
)
?
getStringId
()
:
"?"
)
+
"]]"
;
}
@Override
public
void
startDriverHandshake
()
{
log
.
debug
(
"Starting driver handshake for sw {}"
,
getStringId
());
if
(
startDriverHandshakeCalled
)
{
throw
new
SwitchDriverSubHandshakeAlreadyStarted
();
}
startDriverHandshakeCalled
=
true
;
factory
=
factory
();
configureSwitch
();
}
@Override
public
boolean
isDriverHandshakeComplete
()
{
if
(!
startDriverHandshakeCalled
)
{
throw
new
SwitchDriverSubHandshakeNotStarted
();
}
return
driverHandshakeComplete
.
get
();
}
@Override
public
void
processDriverHandshakeMessage
(
OFMessage
m
)
{
if
(!
startDriverHandshakeCalled
)
{
throw
new
SwitchDriverSubHandshakeNotStarted
();
}
if
(
driverHandshakeComplete
.
get
())
{
throw
new
SwitchDriverSubHandshakeCompleted
(
m
);
}
switch
(
m
.
getType
())
{
case
BARRIER_REPLY:
if
(
m
.
getXid
()
==
barrierXidToWaitFor
)
{
driverHandshakeComplete
.
set
(
true
);
}
break
;
case
ERROR:
log
.
error
(
"Switch {} Error {}"
,
getStringId
(),
(
OFErrorMsg
)
m
);
break
;
case
FEATURES_REPLY:
break
;
case
FLOW_REMOVED:
break
;
case
GET_ASYNC_REPLY:
// OFAsyncGetReply asrep = (OFAsyncGetReply)m;
// decodeAsyncGetReply(asrep);
break
;
case
PACKET_IN:
break
;
case
PORT_STATUS:
break
;
case
QUEUE_GET_CONFIG_REPLY:
break
;
case
ROLE_REPLY:
break
;
case
STATS_REPLY:
// processStatsReply((OFStatsReply) m);
break
;
default
:
log
.
debug
(
"Received message {} during switch-driver subhandshake "
+
"from switch {} ... Ignoring message"
,
m
,
getStringId
());
}
}
private
void
configureSwitch
()
{
sendBarrier
(
true
);
}
private
void
sendBarrier
(
boolean
finalBarrier
)
{
int
xid
=
getNextTransactionId
();
if
(
finalBarrier
)
{
barrierXidToWaitFor
=
xid
;
}
OFBarrierRequest
br
=
factory
.
buildBarrierRequest
()
.
setXid
(
xid
)
.
build
();
sendMsg
(
br
);
}
@Override
public
void
sendMsg
(
OFMessage
m
)
{
channel
.
write
(
m
);
}
@Override
public
Boolean
supportNxRole
()
{
return
false
;
}
}
Please
register
or
login
to post a comment