主な 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); } }
まとめ
それぞれのコードを見て、何を思うかはあなた次第です。好きなのを選んでくださいね!