主な OpenFlow フレームワーク 4 種類でリピータハブを実装してみました。さあ結果はどうなるか!? フレームワークごとの違いをお楽しみください。
比較のルール
公平な比較のために、コメントなど処理に関係無いものは省きました。ログ出力やエラー処理なども思い切って省いてあります。どのコードも自然さを損わずに最短になるようにがんばっていますが、Trema 以外は普段使っていないので、ひょっとしたらコードが間違っている可能性もあります。もし、間違いを発見した場合はご指摘ください。
それではどうぞ!
Trema
Trema はご存知のとおり Ruby です。
class RepeaterHub < Controller
def packet_in datapath_id, message
send_flow_mod_add(
datapath_id,
:match => ExactMatch.from( message ),
:actions => ActionOutput.new( OFPP_FLOOD )
)
send_packet_out(
datapath_id,
:packet_in => message,
:actions => ActionOutput.new( OFPP_FLOOD )
)
end
end
POX
POX は Python です。 このサンプルを参考にしました。
from pox.core import core
import pox.openflow.libopenflow_01 as of
class RepeaterHub (object):
def __init__ (self, connection):
self.connection = connection
connection.addListeners(self)
def send_packet (self, buffer_id, raw_data, out_port, in_port):
msg = of.ofp_packet_out()
msg.in_port = in_port
if buffer_id != -1 and buffer_id is not None:
msg.buffer_id = buffer_id
else:
if raw_data is None:
return
msg.data = raw_data
action = of.ofp_action_output(port = out_port)
msg.actions.append(action)
self.connection.send(msg)
def act_like_hub (self, packet, packet_in):
self.send_packet(packet_in.buffer_id, packet_in.data,
of.OFPP_FLOOD, packet_in.in_port)
def _handle_PacketIn (self, event):
packet = event.parsed
if not packet.parsed:
return
packet_in = event.ofp
self.act_like_hub(packet, packet_in)
def launch ():
def start_switch (event):
RepeaterHub(event.connection)
core.openflow.addListenerByName("ConnectionUp", start_switch)
NOX
NOX は C++ です。このサンプルを参考にしました。
#include <boost/bind.hpp>
#include <boost/shared_array.hpp>
#include "assert.hh"
#include "component.hh"
#include "flow.hh"
#include "packet-in.hh"
#include "vlog.hh"
#include "netinet++/ethernet.hh"
namespace {
using namespace vigil;
using namespace vigil::container;
Vlog_module lg("hub");
class Hub
: public Component
{
public:
Hub(const Context* c,
const json_object*)
: Component(c) { }
void configure(const Configuration*) {
}
Disposition handler(const Event& e)
{
const Packet_in_event& pi = assert_cast<const Packet_in_event&>(e);
uint32_t buffer_id = pi.buffer_id;
Flow flow(pi.in_port, *(pi.get_buffer()));
if (flow.dl_type == ethernet::LLDP){
return CONTINUE;
}
ofp_flow_mod* ofm;
size_t size = sizeof *ofm + sizeof(ofp_action_output);
boost::shared_array<char> raw_of(new char[size]);
ofm = (ofp_flow_mod*) raw_of.get();
ofm->header.version = OFP_VERSION;
ofm->header.type = OFPT_FLOW_MOD;
ofm->header.length = htons(size);
ofm->match.wildcards = htonl(0);
ofm->match.in_port = htons(flow.in_port);
ofm->match.dl_vlan = flow.dl_vlan;
ofm->match.dl_vlan_pcp = flow.dl_vlan_pcp;
memcpy(ofm->match.dl_src, flow.dl_src.octet, sizeof ofm->match.dl_src);
memcpy(ofm->match.dl_dst, flow.dl_dst.octet, sizeof ofm->match.dl_dst);
ofm->match.dl_type = flow.dl_type;
ofm->match.nw_src = flow.nw_src;
ofm->match.nw_dst = flow.nw_dst;
ofm->match.nw_proto = flow.nw_proto;
ofm->match.tp_src = flow.tp_src;
ofm->match.tp_dst = flow.tp_dst;
ofm->cookie = htonl(0);
ofm->command = htons(OFPFC_ADD);
ofm->buffer_id = htonl(buffer_id);
ofm->idle_timeout = htons(5);
ofm->hard_timeout = htons(5);
ofm->priority = htons(OFP_DEFAULT_PRIORITY);
ofm->flags = htons(0);
ofp_action_output& action = *((ofp_action_output*)ofm->actions);
memset(&action, 0, sizeof(ofp_action_output));
action.type = htons(OFPAT_OUTPUT);
action.len = htons(sizeof(ofp_action_output));
action.port = htons(OFPP_FLOOD);
action.max_len = htons(0);
send_openflow_command(pi.datapath_id, &ofm->header, true);
free(ofm);
if (buffer_id == UINT32_MAX) {
size_t data_len = pi.get_buffer()->size();
size_t total_len = pi.total_len;
if (total_len == data_len) {
send_openflow_packet(pi.datapath_id, *pi.get_buffer(),
OFPP_FLOOD, pi.in_port, true);
}
}
return CONTINUE;
}
void install()
{
register_handler<Packet_in_event>(boost::bind(&Hub::handler, this, _1));
}
};
REGISTER_COMPONENT(container::Simple_component_factory<Hub>, Hub);
}
Floodlight
Floodlight は Java です。このサンプルを参考にしました。
package net.floodlightcontroller.hub;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import net.floodlightcontroller.core.FloodlightContext;
import net.floodlightcontroller.core.IFloodlightProviderService;
import net.floodlightcontroller.core.IOFMessageListener;
import net.floodlightcontroller.core.IOFSwitch;
import net.floodlightcontroller.core.module.FloodlightModuleContext;
import net.floodlightcontroller.core.module.FloodlightModuleException;
import net.floodlightcontroller.core.module.IFloodlightModule;
import net.floodlightcontroller.core.module.IFloodlightService;
import org.openflow.protocol.OFMessage;
import org.openflow.protocol.OFPacketIn;
import org.openflow.protocol.OFPacketOut;
import org.openflow.protocol.OFPort;
import org.openflow.protocol.OFType;
import org.openflow.protocol.action.OFAction;
import org.openflow.protocol.action.OFActionOutput;
import org.openflow.util.U16;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Hub implements IFloodlightModule, IOFMessageListener {
protected static Logger log = LoggerFactory.getLogger(Hub.class);
protected IFloodlightProviderService floodlightProvider;
public void setFloodlightProvider(IFloodlightProviderService floodlightProvider) {
this.floodlightProvider = floodlightProvider;
}
@Override
public String getName() {
return Hub.class.getPackage().getName();
}
public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
OFPacketIn pi = (OFPacketIn) msg;
OFPacketOut po = (OFPacketOut) floodlightProvider.getOFMessageFactory()
.getMessage(OFType.PACKET_OUT);
po.setBufferId(pi.getBufferId())
.setInPort(pi.getInPort());
OFActionOutput action = new OFActionOutput()
.setPort((short) OFPort.OFPP_FLOOD.getValue());
po.setActions(Collections.singletonList((OFAction)action));
po.setActionsLength((short) OFActionOutput.MINIMUM_LENGTH);
if (pi.getBufferId() == 0xffffffff) {
byte[] packetData = pi.getPacketData();
po.setLength(U16.t(OFPacketOut.MINIMUM_LENGTH
+ po.getActionsLength() + packetData.length));
po.setPacketData(packetData);
} else {
po.setLength(U16.t(OFPacketOut.MINIMUM_LENGTH
+ po.getActionsLength()));
}
try {
sw.write(po, cntx);
} catch (IOException e) {
log.error("Failure writing PacketOut", e);
}
return Command.CONTINUE;
}
@Override
public boolean isCallbackOrderingPrereq(OFType type, String name) {
return false;
}
@Override
public boolean isCallbackOrderingPostreq(OFType type, String name) {
return false;
}
@Override
public Collection<Class<? extends IFloodlightService>> getModuleServices() {
return null;
}
@Override
public Map<Class<? extends IFloodlightService>, IFloodlightService>
getServiceImpls() {
return null;
}
@Override
public Collection<Class<? extends IFloodlightService>>
getModuleDependencies() {
Collection<Class<? extends IFloodlightService>> l =
new ArrayList<Class<? extends IFloodlightService>>();
l.add(IFloodlightProviderService.class);
return l;
}
@Override
public void init(FloodlightModuleContext context)
throws FloodlightModuleException {
floodlightProvider =
context.getServiceImpl(IFloodlightProviderService.class);
}
@Override
public void startUp(FloodlightModuleContext context) {
floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
}
}
まとめ
それぞれのコードを見て、何を思うかはあなた次第です。好きなのを選んでくださいね!
