ofpmsg-js
Version:
OpenFlow message javascript library
860 lines (754 loc) • 22 kB
JavaScript
(function() {
'use strict';
var _ = require('underscore');
var uint = require('uint-js');
var util = require('../util');
var dt = require('../data');
var msg = require('../message');
var mat = require('./match');
var act = require('./action');
var stats = require('./stats');
var ports = require('./ports');
var VERSION = uint.mk(1, 1);
exports.VERSION = VERSION;
exports.MATCH = mat;
exports.STATS = stats;
exports.ACTION = act;
exports.PORTS = ports;
var CAPABILITIES = {
0x1: 'FLOW_STATS',
0x2: 'TABLE_STATS',
0x4: 'PORT_STATS',
0x8: 'STP',
0x10: 'RESERVED',
0X20: 'IP_REASM',
0X40: 'QUEUE_STATS',
0X80: 'ARP_MATCH_IP'
};
var ACTIONS = {
0x1: 'OUTPUT',
0x2: 'SET_VLAN_VID',
0x4: 'SET_VLAN_PCP',
0x8: 'STRIP_VLAN',
0x10: 'SET_DL_SRC',
0x20: 'SET_DL_DST',
0x40: 'SET_NW_SRC',
0x80: 'SET_NW_DST',
0x100: 'SET_NW_TOS',
0x200: 'SET_TP_SRC',
0x400: 'SET_TP_DST',
0X800: 'ENQUEUE'
};
function Hello(data) {
this.VERSION = VERSION;
this.Type = uint.mk(1, Hello.Type);
dt.Data.call(this, data);
}
util.makePayload(Hello, 0, dt.Data);
Hello.prototype.bytes = function(){
return uint.mk( 2, dt.Data.prototype.bytes.call(this) );
};
exports.Hello = function(data) {
return msg.Message({ payload: new Hello(data) });
};
function Error(type, code, data) {
this.VERSION = VERSION;
this.Type = uint.mk(1, Error.Type);
this.type = type || null;
this.code = code || null;
dt.Data.call(this, data);
}
util.makePayload(Error, 1, dt.Data);
exports.Error = function(args) {
var data = null;
var type = null;
var code = null;
if(args) {
type = args.type || null;
code = args.code || null;
data = args.data || null;
}
return msg.Message({ payload: new Error(type, code, data) });
};
Error.prototype.bytes = function() {
return uint.mk(2, 4 + dt.Data.prototype.bytes.call(this));
};
Error.prototype.toJSON = function(){
return {
type: this.type.toString(),
code: this.code.toString()
};
};
Error.prototype.toView = function(view) {
if(view.available() < this.bytes()) {
throw util.Available('Error');
}
view.writeUInt16(this.type);
view.writeUInt16(this.code);
dt.Data.prototype.toView.call(this, view);
};
Error.prototype.fromView = function(view) {
if(view.available() < this.bytes()) {
throw util.Available('Error');
}
this.type = view.readUInt16();
this.code = view.readUInt16();
dt.Data.prototype.fromView.call(this, view);
};
function EchoReq(data) {
this.VERSION = VERSION;
this.Type = uint.mk(1, EchoReq.Type);
dt.Data.call(this, data);
}
util.makePayload(EchoReq, 2, dt.Data);
EchoReq.prototype.bytes = function() {
return uint.mk(2, dt.Data.prototype.bytes.call(this));
};
exports.EchoReq = function(data) {
return msg.Message({ payload: new EchoReq(data) });
};
function EchoRes(data) {
this.VERSION = VERSION;
this.Type = uint.mk(1, EchoRes.Type);
dt.Data.call(this, data);
}
util.makePayload(EchoRes, 3, dt.Data);
EchoRes.prototype.bytes = function() {
return uint.mk(2, dt.Data.prototype.bytes.call(this));
};
exports.EchoRes = function(data) {
return msg.Message({ payload: new EchoRes(data) });
};
function Vendor(id, data) {
this.VERSION = VERSION;
this.Type = uint.mk(1, Vendor.Type);
dt.Data.call(this, data);
this.id = id || null;
}
util.makePayload(Vendor, 4, dt.Data);
exports.Vendor = function(args) {
var id = null;
var data = null;
if(args) {
id = args.id || null;
data = args.data || null;
}
return msg.Message({ payload: new Vendor(id, data) });
};
Vendor.prototype.bytes = function() {
return uint.mk(2, 4 + dt.Data.prototype.bytes.call(this));
};
Vendor.prototype.toJSON = function() {
return this;
};
Vendor.prototype.toView = function(view) {
if(view.available() < this.bytes()) {
throw util.Available('Vendor');
}
view.writeUInt32(this.id);
dt.Data.prototype.toView.call(this, view);
};
Vendor.prototype.fromView = function(view) {
if(view.available() < this.bytes()) {
throw util.Available('Vendor');
}
this.id = view.readUInt32();
dt.Data.prototype.fromView.call(this, view);
};
function FeatureReq(){
this.VERSION = VERSION;
this.Type = uint.mk(1, FeatureReq.Type);
}
util.makePayload(FeatureReq, 5, dt.Data);
FeatureReq.prototype.bytes = function(){
return uint.mk(2, 0);
};
exports.FeatureReq = function(args){
return msg.Message({ payload: new FeatureReq(args) });
};
FeatureReq.prototype.toJSON = function() {
return this;
};
function FeatureRes(datapathId, nBuffers, nTbls, featureCaps, featureActs, ports){
this.VERSION = VERSION;
this.TYPE = uint.mk(1, FeatureRes.Type);
this.datapathId = datapathId || null;
this.nBuffers = nBuffers || null;
this.nTbls = nTbls || null;
this.featureCaps = featureCaps || null;
this.featureActs = featureActs || null;
this.ports = ports || [] ;
}
util.makePayload(FeatureRes, 6);
FeatureRes.prototype.bytes = function(){
return uint.mk(2, 24 + (this.ports.length * 48));
};
FeatureRes.prototype.fromView = function(view){
if(view.available() < this.bytes()){
throw util.Available('FeatureRes');
}
this.datapathId = view.readUInt64();
this.nBuffers = view.readUInt32();
this.nTbls = view.readUInt8();
util.pad(view, 3);
this.featureCaps = view.readUInt32();
this.featureActs = view.readUInt32();
this.ports = [];
_((view.available() / 48)).times(function(i){
var p = new Port();
p.fromView(view);
this.ports.push(p);
}, this);
};
FeatureRes.prototype.toView = function(view){
if(view.available() < this.bytes()){
throw util.Available('FeatureRes');
}
view.writeUInt64(this.datapathId);
view.writeUInt32(this.nBuffers);
view.writeUInt8(this.nTbls);
util.pad(view, 3);
view.writeUInt32(this.featureCaps);
view.writeUInt32(this.featureActs);
//TODO: port to view
if(view.available() && ((view.available() % 48) === 0)){
_(this.ports).forEach(function(p){
p.toView(view);
}, this);
}
};
FeatureRes.prototype.toString = function(){
return 'Datapath ID: ' + this.datapathId.toString(16) + '\n' +
'Buffers: ' + this.nBuffers.toString() + '\n' +
'Tables: ' + this.nTbls.toString() + '\n' +
'Capabilities ' + util.bmToString(this.featureCaps.value(), CAPABILITIES) + '\n' +
'Actions: ' + util.bmToString(this.featureActs.value(), ACTIONS);
};
exports.FeatureRes = function(args){
return msg.Message({ payload: new FeatureRes(args) });
};
function GetConfigReq(){
this.VERSION = VERSION;
this.Type = uint.mk(1, GetConfigReq.Type);
}
util.makePayload(GetConfigReq, 7);
GetConfigReq.prototype.bytes = function(){
return uint.mk(2, 0);
};
GetConfigReq.prototype.fromView = function(view){
return this;
};
GetConfigReq.prototype.toView = function(view){
return this;
};
GetConfigReq.prototype.toJSON = toJSON;
exports.GetConfigReq = function(){
return msg.Message({ payload: new GetConfigReq() });
};
function GetConfigRes(args){
this.VERSION = VERSION;
this.Type = uint.mk(1, GetConfigRes.Type);
this.flags = null;
this.miss_send_len = null;
if(args){
this.flags = args.flags || null;
this.miss_send_len = args.miss_send_len || null;
}
}
util.makePayload(GetConfigRes, 8);
GetConfigRes.prototype.bytes = function(){
return uint.mk(2, 4);
};
GetConfigRes.prototype.fromView = function(view){
this.flags = view.readUInt16();
this.miss_send_len = view.readUInt16();
return this;
};
GetConfigRes.prototype.toView = function(view){
if(view.available() < this.bytes().value()){
throw util.Available('GetConfigRes');
}
view.writeUInt16(this.flags);
view.writeUInt16(this.miss_send_len);
return this;
};
exports.GetConfigRes = function(args){
return msg.Message({ payload: new GetConfigRes(args) });
};
function SetConfig(args){
this.VERSION = VERSION;
this.Type = uint.mk(1, SetConfig.Type);
this.flags = null;
this.miss_send_len = null;
if(args){
this.flags = args.flags || null;
this.miss_send_len = args.miss_send_len || null;
}
}
util.makePayload(SetConfig, 9);
SetConfig.prototype.bytes = function(){
return uint.mk(2, 4);
};
SetConfig.prototype.fromView = function(view){
this.flags = view.readUInt16();
this.miss_send_len = view.readUInt16();
return this;
};
SetConfig.prototype.toView = function(view){
if(view.available() < this.bytes().value()){
throw util.Available('SetConfig');
}
view.writeUInt16(this.flags);
view.writeUInt16(this.miss_send_len);
return this;
};
exports.SetConfig = function(args){
return msg.Message({ payload: new SetConfig(args) });
};
function PacketIn(bufferId, totalLen, inPort, reason, data){
this.VERSION = VERSION;
this.TYPE = uint.mk(1, PacketIn.Type);
dt.Data.call(this, data);
this.bufferId = bufferId || null;
this.totalLen = totalLen || null;
this.inPort = inPort || null;
this.reason = reason || null;
}
util.makePayload(PacketIn, 10);
var PacketInReason = {
0x0: 'TableMiss',
0x1: 'Action'
};
exports.PacketInReason = PacketInReason;
PacketIn.prototype.fromView = function(view){
if(view.available() < this.bytes()){
throw util.Available('PacketIn');
}
this.bufferId = view.readUInt32();
this.totalLen = view.readUInt16();
this.inPort = view.readUInt16();
this.reason = view.readUInt8();
util.pad(view, 1);
dt.Data.prototype.fromView.call(this, view);
};
PacketIn.prototype.toView = function(view){
if(view.available() < this.bytes()){
throw util.Available('PacketIn');
}
view.writeUInt32(this.bufferId);
view.writeUInt16(this.totalLen);
view.writeUInt16(this.inPort);
view.writeUInt8(this.reason);
util.pad(view, 1);
dt.Data.prototype.toView.call(this, view);
};
PacketIn.prototype.bytes = function(){
return 10 + dt.Data.prototype.bytes.call(this);
};
exports.PacketIn = function(args){
var bufferId = null;
var totalLen = null;
var inPort = null;
var reason = null;
var data = null;
if(args){
bufferId = args.bufferId || null;
totalLen = args.totalLen || null;
inPort = args.inPort || null;
reason = args.reason || null;
data = args.data || null;
}
return msg.Message({ payload: new PacketIn(bufferId, totalLen, inPort, reason, data) });
};
function FlowRemoved(match, cookie, priority, reason, duration_sec, duration_nsec,
idle_timeout, packet_count, byte_count){
this.VERSION = VERSION;
this.TYPE = uint.mk(1, FlowRemoved.Type);
this.match = match || new mat.Match();
this.cookie = cookie || null;
this.priority = priority || null;
this.reason = reason || null;
this.duration_sec = duration_sec || null;
this.duration_nsec = duration_nsec || null;
this.idle_timeout = idle_timeout || null;
this.packet_count = packet_count || null;
this.byte_count = byte_count || null;
}
util.makePayload(FlowRemoved, 11);
var FlowRemovedReason = {
0x0: 'IdleTimeout',
0x1: 'HardTimeout',
0x2: 'Delete'
};
FlowRemoved.prototype.fromView = function(view){
if(view.available() < this.bytes()){
throw util.Available('FlowRemoved');
}
this.match.fromView(view);
this.cookie = view.readUInt64();
this.priority = view.readUInt16();
this.reason = view.readUInt8();
util.pad(view, 1);
this.duration_sec = view.readUInt32();
this.duration_nsec = view.readUInt32();
this.idle_timeout = view.readUInt16();
util.pad(view, 2);
this.packet_count = view.readUInt64();
this.byte_count = view.readUInt64();
};
FlowRemoved.prototype.toView = function(view){
if(view.available() < this.bytes()){
throw util.Available('FlowRemoved');
}
this.match.toView(view);
view.writeUInt64(this.cookie);
view.writeUInt16(this.priority);
view.writeUInt8(this.reason);
util.pad(view, 1);
view.writeUInt32(this.duration_sec);
view.writeUInt32(this.duration_nsec);
view.writeUInt16(this.idle_timeout);
util.pad(view, 2);
view.writeUInt64(this.packet_count);
view.writeUInt64(this.byte_count);
};
FlowRemoved.prototype.bytes = function(){
return uint.mk(2, 80);
};
exports.FlowRemoved = function(args){
var match = null;
var cookie = null;
var priority = null;
var reason = null;
var duration_sec = null;
var duration_nsec = null;
var idle_timeout = null;
var packet_count = null;
var byte_count = null;
if(args){
match = args.match || new mat.Match();
cookie = args.cookie || null;
priority = args.priority || null;
reason = args.reason || null;
duration_sec = args.duration_sec || null;
duration_nsec = args.duraction_nsec || null;
idle_timeout = args.idle_timeout || null;
packet_count = args.packet_count || null;
byte_count = args.byte_count || null;
}
return msg.Message({ payload: new FlowRemoved(match, cookie, priority, reason,
duration_sec, duration_nsec, idle_timeout, packet_count, byte_count) });
};
function PacketOut(buffer_id, in_port, actions_len, actions, data) {
this.VERSION = VERSION;
this.TYPE = uint.mk(1, PacketOut.Type);
this.buffer_id = buffer_id || null;
this.in_port = in_port || null;
this.actions = actions || [];
var actlen = uint.mk(2, 0);
_(this.actions).forEach(function(a){
actlen = actlen.plus(a.length);
});
this.actions_len = actions_len || actlen;
dt.Data.call(this, data);
}
util.makePayload(PacketOut, 13);
PacketOut.prototype.fromView = function(view){
if(view.available() < this.bytes()){
throw util.Available('PacketOut');
}
this.buffer_id = view.readUInt32();
this.in_port = view.readUInt16();
this.actions_len = view.readUInt16();
this.actions = [];
while(this.actions_len.value() && (view.available() >= this.actions_len.value())){
this.actions.push(act.fromView(view));
}
dt.Data.prototype.fromView.call(this, view);
};
PacketOut.prototype.toView = function(view){
if(view.available() < this.bytes()){
throw util.Available('FlowRemoved');
}
view.writeUInt32(this.buffer_id);
view.writeUInt16(this.in_port);
view.writeUInt16(this.actions_len);
_(this.actions).forEach(function(a){
a.toView(view);
}, this);
dt.Data.prototype.toView.call(this, view);
};
PacketOut.prototype.bytes = function(){
return uint.mk(2, 8 + this.actions_len.value() + dt.Data.prototype.bytes.call(this));
};
exports.PacketOut = function(args){
var buffer_id = null;
var in_port = null;
var actions_len = null;
var actions = [];
var data = null;
if(args){
buffer_id = args.buffer_id || uint.mk(4, 0xffffffff);
in_port = args.in_port || uint.mk(2, 0);
actions_len = args.actions_len || null;
actions = actions || [];
data = data || null;
}
return msg.Message({ payload: new PacketOut(buffer_id, in_port, actions_len, actions, data) });
};
function Port(){
this.portId = null;
this.hwAddr = null;
this.name = null;
this.config = null;
this.state = null;
this.curr = null;
this.advertised = null;
this.supported = null;
this.peer = null;
}
Port.prototype.bytes = function(){
return uint.mk(2, 48);
};
Port.prototype.fromView = function(view){
if(view.available() < this.bytes()){
throw util.Available('Port');
}
this.portId = view.readUInt16();
this.hwAddr = view.readBytes(6);
this.name = view.readBytes(16);
this.config = view.readUInt32();
this.state = view.readUInt32();
this.curr = view.readUInt32();
this.advertised = view.readUInt32();
this.supported = view.readUInt32();
this.peer = view.readUInt32();
};
Port.prototype.toView = function(view){
if(view.available() < this.bytes()){
throw util.Available('Port');
}
view.writeUInt16(this.portId);
view.writeBytes(this.hwAddr);
view.writeBytes(this.name);
view.writeUInt32(this.config);
view.writeUInt32(this.state);
view.writeUInt32(this.curr);
view.writeUInt32(this.advertised);
view.writeUInt32(this.supported);
view.writeUInt32(this.peer);
};
function PortStatus(reason, port){
this.VERSION = VERSION;
this.TYPE = uint.mk(1, PortStatus.Type);
this.reason = reason || null;
this.port = port || null;
}
util.makePayload(PortStatus, 12);
PortStatus.prototype.bytes = function(){
return uint.mk(2, 56);
};
PortStatus.prototype.fromView = function(view){
if(view.available() < this.bytes()){
throw util.Available('PortStatus');
}
this.reason = view.readUInt8();
util.pad(view, 7);
this.port = new Port();
this.port.fromView(view);
};
PortStatus.prototype.toView = function(view){
if(view.available() < this.bytes()){
throw util.Available('PortStatus');
}
view.writeUInt8(this.reason);
util.pad(view, 7);
this.port.toView(view);
};
exports.PortStatus = function(args){
var reason = null;
var port = null;
if(args){
reason = args.reason || null;
port = args.port || null;
}
return msg.Message({ payload: new PortStatus(reason, reason) });
};
function Match() {
this.wildcards = null;
this.in_port = 0;
this.dl_src = null;
this.dl_dst = null;
this.dl_vlan = null;
this.dl_pcp = null;
this.dl_type = null;
this.nw_tos = null;
this.nw_proto = null;
this.nw_src = null;
this.nw_dst = null;
this.tp_src = null;
this.tp_dst = null;
}
Match.prototype.bytes = function() {
return 40;
};
Match.prototype.fromView = function(view) {
if(view.available() < this.bytes()) {
throw util.Available();
}
this.wildcard = view.readUInt32();
};
Match.prototype.toView = function(view) {
if(view.available() < this.bytes()) {
throw util.Available();
}
};
function FlowMod(args) {
this.VERSION = VERSION;
this.Type = uint.mk(1, FlowMod.Type);
this.match = new mat.Match();
this.cookie = uint.mk(8, 0);
this.command = uint.mk(2, 0);
this.idle_timeout = uint.mk(2, 0);
this.hard_timeout = uint.mk(2, 0);
this.priority = uint.mk(2, 0);
this.buffer_id = uint.mk(4, 0);
this.out_port = uint.mk(2, 0);
this.flags = uint.mk(2, 0);
this.actions = [];
if(args) {
if(args.match) { this.match = args.match; }
if(args.cookie) { this.cookie = args.cookie; }
if(args.command) { this.command = args.command; }
if(args.idle_timeout) { this.idle_timeout = args.idle_timeout; }
if(args.hard_timeout) { this.hard_timeout = args.hard_timeout; }
if(args.priority) { this.priority = args.priority; }
if(args.buffer_id) { this.buffer_id = args.buffer_id; }
if(args.out_port) { this.out_port = args.out_port; }
if(args.flags) { this.flags = args.flags; }
if(args.actions) { this.actions = args.actions; }
}
}
util.makePayload(FlowMod, 14);
exports.FlowMod = function(args) {
return msg.Message({ payload: new FlowMod(args) });
};
FlowMod.prototype.bytes = function() {
return uint.mk(2, this.match.bytes() +
24 +
_(this.actions).reduce(function(bytes, action) {
return bytes + action.bytes();
}, 0) );
};
FlowMod.prototype.toView = function(view) {
if(view.available() < this.bytes()){
throw util.Available('FlowMod');
}
this.match.toView(view);
view.writeUInt64(this.cookie);
view.writeUInt16(this.command);
view.writeUInt16(this.idle_timeout);
view.writeUInt16(this.hard_timeout);
view.writeUInt16(this.priority);
view.writeUInt32(this.buffer_id);
view.writeUInt16(this.out_port);
view.writeUInt16(this.flags);
_(this.actions).forEach(function(a){
a.toView(view);
}, this);
};
FlowMod.prototype.fromView = function(view) {
if(view.available() < this.bytes()){
throw util.Available('FlowMod');
}
this.match.fromView(view);
this.cookie = view.readUInt64();
this.command = view.readUInt16();
this.idle_timeout = view.readUInt16();
this.hard_timeout = view.readUInt16();
this.priority = view.readUInt16();
this.buffer_id = view.readUInt32();
this.out_port = view.readUInt16();
this.flags = view.readUInt16();
this.actions = [];
while(view.available() >= 4){
this.actions.push(act.fromView(view));
}
};
util.makePayload(stats.StatsReq, 16);
exports.StatsReq = function(args){
return msg.Message({ payload: new stats.StatsReq(args) });
};
util.makePayload(stats.StatsRes, 17);
exports.StatsRes = function(args){
return msg.Message({ payload: new stats.StatsRes(args) });
};
function BarrierReq(data) {
this.VERSION = VERSION;
this.Type = BarrierRes.Type;
dt.Data.call(this, data);
}
util.makePayload(BarrierReq, 18, dt.Data);
exports.BarrierReq = function(args) {
var data = null;
if(args) {
data = args.data || null;
}
return new BarrierReq(data);
};
function BarrierRes(data) {
this.VERSION = VERSION;
this.Type = uint.mk(1, BarrierRes.Type);
dt.Data.call(this, data);
}
util.makePayload(BarrierRes, 19, dt.Data);
exports.BarrierRes = function(args) {
var data = null;
if(args) {
data = args.data || null;
}
return msg.Message({ payload: new BarrierRes(data) });
};
var Type = util.makeIndex([
Hello,
Error,
EchoReq,
EchoRes,
Vendor,
FeatureReq,
FeatureRes,
GetConfigReq,
GetConfigRes,
SetConfig,
PacketIn,
FlowRemoved,
PortStatus,
PacketOut,
FlowMod,
stats.StatsReq,
stats.StatsRes,
BarrierReq,
BarrierRes
]);
exports.Type = Type;
exports.Payload = function() {
return util.Variant(Type);
};
exports.fromView = function(view) {
return msg.fromView(view, VERSION);
};
var toJSON = function(){
return this;
};
Hello.prototype.toJSON = toJSON;
EchoReq.prototype.toJSON = toJSON;
EchoRes.prototype.toJSON = toJSON;
GetConfigReq.prototype.toJSON = toJSON;
GetConfigRes.prototype.toJSON = toJSON;
SetConfig.prototype.toJSON = toJSON;
PacketIn.prototype.toJSON = toJSON;
FlowRemoved.prototype.toJSON = toJSON;
PortStatus.prototype.toJSON = toJSON;
PacketOut.prototype.toJSON = toJSON;
FlowMod.prototype.toJSON = toJSON;
})();