Package org.flowforwarding.warp.protocol.ofmessages

Source Code of org.flowforwarding.warp.protocol.ofmessages.OFMessageProvider12AvroProtocol$MatchEntry

/**
* © 2013 FlowForwarding.Org
* All Rights Reserved.  Use is subject to license terms.
*/
package org.flowforwarding.warp.protocol.ofmessages;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.avro.Schema;
import org.apache.avro.Schema.Field;
import org.apache.avro.generic.GenericArray;
import org.apache.avro.generic.GenericData;
import org.apache.avro.Protocol;
import org.flowforwarding.warp.protocol.ofmessages.OFMessageError.OFMessageErrorRef;
import org.flowforwarding.warp.protocol.ofmessages.OFMessageFlowMod.OFMessageFlowModRef;
import org.flowforwarding.warp.protocol.ofmessages.OFMessageGroupMod.OFMessageGroupModRef;
import org.flowforwarding.warp.protocol.ofmessages.OFMessageHello.OFMessageHelloRef;
import org.flowforwarding.warp.protocol.ofmessages.OFMessagePacketIn.OFMessagePacketInRef;
import org.flowforwarding.warp.protocol.ofmessages.OFMessageSwitchConfig.OFMessageSwitchConfigRef;
import org.flowforwarding.warp.protocol.ofp.avro.OFMessage.OFMessageBuilder;
import org.flowforwarding.warp.protocol.ofstructures.IOFStructureBuilder;
import org.flowforwarding.warp.protocol.ofstructures.OFStructureBuilder13;
import org.flowforwarding.warp.protocol.ofstructures.OFStructureInstruction;
import org.flowforwarding.warp.protocol.ofstructures.OFStructureInstruction.OFStructureInstructionRef;
import org.apache.avro.generic.GenericData.Fixed;
import org.apache.avro.generic.GenericDatumReader;
import org.apache.avro.generic.GenericDatumWriter;
import org.apache.avro.generic.GenericFixed;
import org.apache.avro.generic.GenericRecordBuilder;
import org.apache.avro.generic.GenericRecord;
import org.apache.avro.io.DatumReader;
import org.apache.avro.io.DatumWriter;
import org.apache.avro.io.Decoder;
import org.apache.avro.io.DecoderFactory;
import org.apache.avro.io.Encoder;
import org.apache.avro.io.EncoderFactory;
import org.apache.avro.specific.SpecificFixed;
import org.flowforwarding.warp.util.Tuple;
import org.flowforwarding.warp.util.U16;
import org.flowforwarding.warp.util.U8;

public class OFMessageProvider12AvroProtocol implements IOFMessageProvider {
  
   private final String schemaSrc = "of_protocol_12.avpr";
  
   private Schema ofpHeaderSchema = null;
  
   private Schema helloHeaderSchema = null;
   private Schema ofpHelloSchema = null;
  
   private Schema echoRequestHeaderSchema = null;
   private Schema ofpEchoRequestSchema = null;
  
   private Schema echoReplyHeaderSchema = null;
   private Schema ofpEchoReplySchema = null;
  
   private Schema ofpSwitchFeaturesRequestSchema = null;
   private Schema switchFeaturesRequestHeaderSchema = null;
  
   private Schema ofpSwitchFeaturesSchema = null;
   private Schema switchFeaturesHeaderSchema = null;
  
   private Schema switchConfigHeaderSchema = null;
   private Schema ofpSwitchConfigSchema = null;
   private Schema ofpSetSwitchConfigSchema;
   private Schema ofpSetSwitchConfigHeaderSchema;
  
   private Schema getConfigRequestHeaderSchema = null;
   private Schema ofpGetConfigRequestSchema = null;
   private Schema ofpGetConfigReplyHeaderSchema = null;
   private Schema ofpGetConfigReplySchema = null;
  
   private Schema ofpTypeSchema = null;
   private Schema ofpConfigFlagsSchema = null;  
   private Schema ofpFlowModCommandSchema = null;
   private Schema ofpFlowModFlagsSchema = null;
   private Schema flowModHeaderSchema = null;
   private Schema ofpFlowModSchema = null;
  
   private Schema packetInHeaderSchema = null;
   private Schema ofpPacketInSchema = null;
  
   private Schema errorMessageHeaderSchema = null;
   private Schema ofpErrorMessageSchema = null;
  
   private Schema uint_8Schema = null;
   private Schema uint_16Schema = null;
   private Schema uint_24Schema = null;
   private Schema uint_32Schema = null;
   private Schema uint_48Schema = null;
   private Schema uint_64Schema = null;
   private Schema uint_128Schema = null;
  
   /*
    * Delayed matches
    */
   // TODO Implement a wrapper around matches.add to handle PREREQs
   private GenericRecord delayedVlanPcp = null;
   private boolean isVlanVid = false;
  
   private GenericRecord delayedIpv4Src = null;
   private GenericRecord delayedIpv4Dst = null;
   private GenericRecord delayedIpv6Src = null;
   private GenericRecord delayedIpv6Dst = null;
   private GenericRecord delayedIpProto = null;
   private GenericRecord delayedTcpSrc = null;
   private GenericRecord delayedTcpDst = null;
   private GenericRecord delayedUdpSrc = null;
   private GenericRecord delayedUdpDst = null;

   private boolean isEtherType = false;
   private boolean isIpProto = false;
  
  
   private Protocol protocol = null;
   protected IOFStructureBuilder structureBuilder = null;
   OFMessageBuilder builder = null;
   IOFMessageBuilder builder12 = null;

   final class MatchEntry<K, V> implements Map.Entry<K, V> {
       private final K key;
       private V value;

       public MatchEntry(K key, V value) {
           this.key = key;
           this.value = value;
       }

       @Override
       public K getKey() {
           return key;
       }

       @Override
       public V getValue() {
           return value;
       }

       @Override
       public V setValue(V value) {
           V old = this.value;
           this.value = value;
           return old;
       }
   }
  
   public void init () {
      try {
         InputStream str = Thread.currentThread().getContextClassLoader().getResourceAsStream(schemaSrc);
        
         builder = new OFMessageBuilder(schemaSrc);

         protocol = Protocol.parse(str);
         builder12 = new OFMessageBuilder13();
         structureBuilder = new OFStructureBuilder13();

         } catch (IOException e) {
         // TODO Auto-generated catch block
           e.printStackTrace();
         }

      ofpHeaderSchema =  protocol.getType("of12.ofp_header");
     
      helloHeaderSchema = protocol.getType("of12.ofp_hello_header");
      ofpHelloSchema = protocol.getType("of12.ofp_hello");
     
      echoRequestHeaderSchema= protocol.getType("of12.echo_request_header");
      ofpEchoRequestSchema = protocol.getType("of12.ofp_echo_request");

      echoReplyHeaderSchema = protocol.getType("of12.echo_reply_header");
      ofpEchoReplySchema = protocol.getType("of12.ofp_echo_reply");

     
      ofpSwitchFeaturesRequestSchema =  protocol.getType("of12.ofp_switch_features_request");
      switchFeaturesRequestHeaderSchema =  protocol.getType("of12.ofp_switch_features_request_header");
      ofpSwitchFeaturesSchema =  protocol.getType("of12.ofp_switch_features");
      switchFeaturesHeaderSchema =  protocol.getType("of12.switch_features_header");

      switchConfigHeaderSchema = protocol.getType("of12.switch_config_header");
      ofpSwitchConfigSchema = protocol.getType("of12.ofp_switch_config");
      ofpSetSwitchConfigSchema = protocol.getType("of12.ofp_set_switch_config");
      ofpSetSwitchConfigHeaderSchema = protocol.getType("of12.ofp_set_switch_config_header");
     
      getConfigRequestHeaderSchema = protocol.getType("of12.get_config_request_header");
      ofpGetConfigRequestSchema = protocol.getType("of12.ofp_get_config_request");
      ofpGetConfigReplyHeaderSchema = protocol.getType("of12.ofp_get_config_reply_header");
     
      flowModHeaderSchema = protocol.getType("of12.flow_mod_header");
      ofpFlowModSchema = protocol.getType("of12.ofp_flow_mod");
     
      packetInHeaderSchema = protocol.getType("of12.packet_in_header");
      ofpPacketInSchema = protocol.getType("of12.ofp_packet_in");
     
      errorMessageHeaderSchema = protocol.getType("of12.error_msg_header");
      ofpErrorMessageSchema = protocol.getType("of12.ofp_error_msg");
     
      uint_8Schema = protocol.getType("of12.uint_8");
      uint_16Schema = protocol.getType("of12.uint_16");
      uint_16Schema = protocol.getType("of12.uint_24");
      uint_32Schema = protocol.getType("of12.uint_32");
      uint_48Schema = protocol.getType("of12.uint_48");
      uint_64Schema = protocol.getType("of12.uint_64");
      uint_128Schema = protocol.getType("of12.uint_128");

     
   }
  
   public OFMessageFlowModRef buildFlowModMsg () {
      return builder12.buildFlowMod();
   }
  
   public OFStructureInstructionRef buildInstructionApplyActions () {
      return structureBuilder.buildInstructionApplyActions();
   }
  
   public OFStructureInstructionRef buildInstructionWriteActions () {
      return structureBuilder.buildInstructionWriteActions();
   }
  
   public OFStructureInstructionRef buildInstructionGotoTable () {
      return structureBuilder.buildInstructionGotoTable();
   }
  
   public OFStructureInstructionRef buildInstructionClearActions () {
      return structureBuilder.buildInstructionClearActions();
   }
  
   public OFStructureInstructionRef buildInstructionMeter () {
      return structureBuilder.buildInstructionMeter();
   }
  
   public OFStructureInstructionRef buildInstructionWriteMetadata () {
      return structureBuilder.buildInstructionWriteMetadata();
   }
  
   private byte[] encodeMessage (Schema headerSchema, Schema bodySchema) {
     
      GenericRecord bodyRecord = new GenericData.Record(bodySchema);
      GenericRecordBuilder builder = new GenericRecordBuilder(headerSchema);

      GenericRecord headerRecord = builder.build();
      bodyRecord.put("header", headerRecord)
     
      ByteArrayOutputStream out = new ByteArrayOutputStream();
     
      DatumWriter<GenericRecord> writer = new GenericDatumWriter<GenericRecord>(bodySchema);
      Encoder encoder = EncoderFactory.get().binaryNonEncoder(out, null);
     
      try {
         writer.write(bodyRecord, encoder);
         encoder.flush();
      } catch (IOException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      }
     
      return out.toByteArray();
   }
  
   public ByteArrayOutputStream getHello(ByteArrayOutputStream out) {
     
      GenericRecord ofpHelloRecord = new GenericData.Record(ofpHelloSchema);
      GenericRecordBuilder builder = new GenericRecordBuilder(helloHeaderSchema);

      GenericRecord ofpHelloHeaderRecord = builder.build();
      ofpHelloRecord.put("header", ofpHelloHeaderRecord)
     
      DatumWriter<GenericRecord> writer = new GenericDatumWriter<GenericRecord>(ofpHelloSchema);
      Encoder encoder = EncoderFactory.get().binaryNonEncoder(out, null);
     
      try {
         writer.write(ofpHelloRecord, encoder);
         encoder.flush();
      } catch (IOException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      }

      return out;
    }
  
/*   public byte[] encodeHelloMessage() {
      return encodeMessage(helloHeaderSchema, ofpHelloSchema);
   }*/

   public byte[] encodeHelloMessage() {
      org.flowforwarding.warp.protocol.ofp.avro.OFMessage helloMsg = builder.type("ofp_hello").build();
      return helloMsg.binary();
   }
  
   public byte[] encodeEchoRequest() {
      return encodeMessage(echoRequestHeaderSchema, ofpEchoRequestSchema);
   }
  
   public byte[] encodeEchoReply() {
      return encodeMessage(echoReplyHeaderSchema, ofpEchoReplySchema);
   }
  
   public byte[] encodeSwitchFeaturesRequest () {
      return encodeMessage(switchFeaturesRequestHeaderSchema, ofpSwitchFeaturesRequestSchema);
   }
  
   public byte[] encodeSwitchFeaturesReply () {
      return encodeMessage(switchFeaturesHeaderSchema, ofpSwitchFeaturesSchema);
   }

   public ByteArrayOutputStream getSwitchFeaturesRequest(ByteArrayOutputStream out) {
     
      GenericRecord ofpSwitchFeaturesRequestRecord = new GenericData.Record(ofpSwitchFeaturesRequestSchema);
      GenericRecordBuilder builder = new GenericRecordBuilder(switchFeaturesRequestHeaderSchema);

      GenericRecord ofpSwitchFeaturesRequestHeaderRecord = builder.build();
      ofpSwitchFeaturesRequestRecord.put("header", ofpSwitchFeaturesRequestHeaderRecord)
     
      DatumWriter<GenericRecord> writer = new GenericDatumWriter<GenericRecord>(ofpSwitchFeaturesRequestSchema);
      Encoder encoder = EncoderFactory.get().binaryNonEncoder(out, null);
     
      try {
         writer.write(ofpSwitchFeaturesRequestRecord, encoder);
         encoder.flush();
      } catch (IOException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      }

      return out;
    }
  
   public ByteArrayOutputStream getSwitchFeaturesReply(ByteArrayOutputStream out) {
     
      GenericRecord ofpSwitchFeaturesReplyRecord = new GenericData.Record(ofpSwitchFeaturesSchema);
      GenericRecordBuilder builder = new GenericRecordBuilder(switchFeaturesHeaderSchema);
     
      GenericRecord ofpSwitchFeaturesReplyHeaderRecord = builder.build();
      ofpSwitchFeaturesReplyRecord.put("header", ofpSwitchFeaturesReplyHeaderRecord)
     
      DatumWriter<GenericRecord> writer = new GenericDatumWriter<GenericRecord>(ofpSwitchFeaturesSchema);
      Encoder encoder = EncoderFactory.get().binaryNonEncoder(out, null);
     
      try {
         writer.write(ofpSwitchFeaturesReplyRecord, encoder);
         encoder.flush();
      } catch (IOException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      }

      return out;
   }
  
   protected GenericRecord getSwitchFeaturesRecord (byte[] buffer) {
     
      try {
         GenericRecord featureReplyRecord = new GenericData.Record(ofpSwitchFeaturesSchema);
         GenericDatumReader<GenericRecord> reader = new GenericDatumReader<GenericRecord>(ofpSwitchFeaturesSchema);
         Decoder decoder = DecoderFactory.get().binaryDecoder(buffer, null);
        
         reader.read(featureReplyRecord, decoder);
        
         return featureReplyRecord;
    } catch (IOException e) {
       // TODO Auto-generated catch block
       e.printStackTrace();
      
       return null;
    }
   }
  
   protected GenericRecord getSwitchConfigRecord (byte[] buffer) {
      // TODO Improvs: make a protected getter to get general records.
      try {
         GenericRecord record = new GenericData.Record(ofpSwitchConfigSchema);
         GenericDatumReader<GenericRecord> reader = new GenericDatumReader<GenericRecord>(ofpSwitchConfigSchema);
         Decoder decoder = DecoderFactory.get().binaryDecoder(buffer, null);
        
         reader.read(record, decoder);
        
         return record;
    } catch (IOException e) {
       // TODO Auto-generated catch block
       e.printStackTrace();
      
       return null;
    }
   }
  
   protected GenericRecord getRecord (Schema schema, byte[] buffer) {
      // TODO Improvs: make a protected getter to get general records.
      try {
         GenericRecord record = new GenericData.Record(schema);
         GenericDatumReader<GenericRecord> reader = new GenericDatumReader<GenericRecord>(schema);
         Decoder decoder = DecoderFactory.get().binaryDecoder(buffer, null);
        
         reader.read(record, decoder);
        
         return record;
    } catch (IOException e) {
       // TODO Auto-generated catch block
       e.printStackTrace();
      
       return null;
    }
   }
  
   public Long getDPID(byte[] buffer) {
     
      GenericRecord featureReplyRecord = getSwitchFeaturesRecord (buffer);
     
      GenericData.Fixed dpid = (GenericData.Fixed) featureReplyRecord.get("datapath_id");
      return getLong(dpid);
   }
  
   public ByteArrayOutputStream getSetSwitchConfig(ByteArrayOutputStream out) {
     
      GenericRecord ofpSetSwitchConfigRecord = new GenericData.Record(ofpSetSwitchConfigSchema);
     
      GenericRecordBuilder builder = new GenericRecordBuilder(ofpSetSwitchConfigHeaderSchema);
      GenericRecord ofpSetSwitchConfigHeaderRecord = builder.build();
     
      ofpSetSwitchConfigRecord.put("header", ofpSetSwitchConfigHeaderRecord);
     
      byte[] fl = {0,0};
      GenericData.Fixed flags = new GenericData.Fixed(ofpSetSwitchConfigSchema, fl);
      ofpSetSwitchConfigRecord.put("flags", flags);
     
      byte[] msl = {(byte)255, (byte)255};
      GenericData.Fixed miss_send_len = new GenericData.Fixed(ofpSetSwitchConfigSchema, msl);
      ofpSetSwitchConfigRecord.put("miss_send_len", miss_send_len);
     
      DatumWriter<GenericRecord> writer = new GenericDatumWriter<GenericRecord>(ofpSetSwitchConfigSchema);
      Encoder encoder = EncoderFactory.get().binaryNonEncoder(out, null);
     
      try {
         writer.write(ofpSetSwitchConfigRecord, encoder);
         encoder.flush();
      } catch (IOException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      }
     
      return out;
   }
  
   public ByteArrayOutputStream getSwitchConfigRequest(ByteArrayOutputStream out) {
     
      GenericRecord ofpGetConfigRequestRecord = new GenericData.Record(ofpGetConfigRequestSchema);
      GenericRecordBuilder builder = new GenericRecordBuilder(getConfigRequestHeaderSchema);
     
      GenericRecord ofpGetConfigRequestHeaderRecord = builder.build();
      ofpGetConfigRequestRecord.put("header", ofpGetConfigRequestHeaderRecord)
     
      DatumWriter<GenericRecord> writer = new GenericDatumWriter<GenericRecord>(ofpGetConfigRequestSchema);
      Encoder encoder = EncoderFactory.get().binaryNonEncoder(out, null);
     
      try {
         writer.write(ofpGetConfigRequestRecord, encoder);
         encoder.flush();
      } catch (IOException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      }

      return out;
   }
  
   public byte[] encodeSwitchConfigRequest () {
     
      GenericRecord ofpGetConfigRequestRecord = new GenericData.Record(ofpGetConfigRequestSchema);
      GenericRecordBuilder builder = new GenericRecordBuilder(getConfigRequestHeaderSchema);
     
      GenericRecord ofpGetConfigRequestHeaderRecord = builder.build();
      ofpGetConfigRequestRecord.put("header", ofpGetConfigRequestHeaderRecord)
     
      ByteArrayOutputStream out = new ByteArrayOutputStream();
      DatumWriter<GenericRecord> writer = new GenericDatumWriter<GenericRecord>(ofpGetConfigRequestSchema);
      Encoder encoder = EncoderFactory.get().binaryNonEncoder(out, null);
     
      try {
         writer.write(ofpGetConfigRequestRecord, encoder);
         encoder.flush();
      } catch (IOException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      }
    
      return out.toByteArray();
   }

    public byte[] encodeGroupMod(OFMessageGroupModRef fmRef) {
        return new byte[0];
    }

    public byte[] encodeFlowMod (OFMessageFlowModRef fmRef) {
     
      GenericRecord ofpFlowModRecord = new GenericData.Record(ofpFlowModSchema);
     
      GenericRecordBuilder builder = null;

      builder = new GenericRecordBuilder (flowModHeaderSchema);
      GenericRecord flowModHeaderRecord = builder.build();
     
      Schema flowModBodySchema = protocol.getType("of12.flow_mod_body_add");
      builder = new GenericRecordBuilder(flowModBodySchema);
      GenericRecord flowModBodyRecord = builder.build();
     
      GenericRecord ofpMatchRecord = null;
      Schema ofpMatchSchema = null;
     
      List <GenericRecord> instructions = new ArrayList<>();
      List <GenericRecord> matches = new ArrayList<>();
     
   // TODO Improvs: I dislike this *.getMatches().getIterator();
//      Iterator<Tuple<String, String>> matchIter = fmRef.getMatches().getIterator();
      List<Tuple<String, String>> matchList = fmRef.getMatches().getMatches();
      for (Tuple<String, String> match : matchList) {
         //Tuple<String, String> match = matchIter.next();
         String name = match.getName();
        
         // TODO Improvs: Replace Switch with a structure... say, HashMap
         // TODO Improvs: How to control type compatibility between Shema types and incoming tlvs?
         switch (name) {
         case "ingress_port":
            matches.add(getMatch("of12.oxm_tlv_ingress_port", getUint32Fixed(Integer.parseInt(match.getValue()))));
            break;
        
         case "in_phy_port":
            matches.add(getMatch("of12.oxm_tlv_in_phy_port", getUint32Fixed(Integer.parseInt(match.getValue()))));
            break;

         case "metadata":
            matches.add(getMatch("of12.oxm_tlv_metadata", getUint64Fixed(Long.parseLong(match.getValue()))));
            break;

         case "eth_dst":
            matches.add(getMatch("of12.oxm_tlv_eth_dst", getUint48Fixed(get_mac_addr(match.getValue()))));
            break;
           
         case "eth_src":
            matches.add(getMatch("of12.oxm_tlv_eth_src", getUint48Fixed(get_mac_addr(match.getValue()))));
            break;

         case "eth_type":
            short ethType = U16.t(Integer.valueOf(match.getValue().replaceFirst("0x", ""), 16));
            matches.add(getMatch("of12.oxm_tlv_eth_type", getUint32Fixed(ethType)));
            break;           

         case "vlan_vid":
            short vid = U16.t(Integer.valueOf(match.getValue()));
            matches.add(getMatch("of12.oxm_tlv_vlan_vid", getUint32Fixed(vid)));
            break;           
        
         case "vlan_pcp":
            short pcp = U16.t(Integer.valueOf(match.getValue()));
            matches.add(getMatch("of12.oxm_tlv_vlan_vid", getUint32Fixed(pcp)));
            break;           

         case "ip_dscp":
            byte tmp = U8.t(Short.valueOf(match.getValue()));
            matches.add(getMatch("of12.oxm_tlv_ip_dscp", getUint8Fixed(tmp)));
            break;

         case "ip_ecn":
            tmp = U8.t(Short.valueOf(match.getValue()));
            matches.add(getMatch("of12.oxm_tlv_ip_ecn", getUint8Fixed(tmp)));
            break;

         case "ip_proto":
            tmp = U8.t(Short.valueOf(match.getValue()));
            matches.add(getMatch("of12.oxm_tlv_ip_proto", getUint8Fixed(tmp)));
            break;

         case "ipv4_src":
            matches.add(getMatch("of12.oxm_tlv_ipv4_src", getUint32Fixed(get_ipv4(match.getValue()))));
            break;

         case "ipv4_dst":
            matches.add(getMatch("of12.oxm_tlv_ipv4_dst", getUint32Fixed(get_ipv4(match.getValue()))));
            break;

         case "tcp_src":
            matches.add(getMatch("of12.oxm_tlv_tcp_src", getUint16Fixed(U16.t(Integer.valueOf(match.getValue())))));
            break;
           
         case "tcp_dst":
            matches.add(getMatch("of12.oxm_tlv_tcp_dst", getUint16Fixed(U16.t(Integer.valueOf(match.getValue())))));
            break;

         case "udp_src":
            matches.add(getMatch("of12.oxm_tlv_udp_src", getUint16Fixed(U16.t(Integer.valueOf(match.getValue())))));
            break;

         case "udp_dst":
            matches.add(getMatch("of12.oxm_tlv_udp_dst", getUint16Fixed(U16.t(Integer.valueOf(match.getValue())))));
            break;

         case "sctp_src":
            matches.add(getMatch("of12.oxm_tlv_sctp_src", getUint16Fixed(U16.t(Integer.valueOf(match.getValue())))));
            break;

         case "sctp_dst":
            matches.add(getMatch("of12.oxm_tlv_sctp_dst", getUint16Fixed(U16.t(Integer.valueOf(match.getValue())))));
            break;
           
         case "icmpv4_type":
            tmp = U8.t(Short.valueOf(match.getValue()));
            matches.add(getMatch("of12.oxm_tlv_icmpv4_type", getUint8Fixed(tmp)));
            break;

         case "icmpv4_code":
            tmp = U8.t(Short.valueOf(match.getValue()));
            matches.add(getMatch("of12.oxm_tlv_icmpv4_code", getUint8Fixed(tmp)));
            break;

         case "arp_op":
            matches.add(getMatch("of12.oxm_tlv_arp_op", getUint16Fixed(U16.t(Integer.parseInt(match.getValue())))));
            break;

         case "arp_spa":
            matches.add(getMatch("of12.oxm_tlv_arp_spa", getUint32Fixed(Integer.parseInt(match.getValue()))));
            break;

         case "arp_tpa":
            matches.add(getMatch("of12.oxm_tlv_arp_tpa", getUint32Fixed(Integer.parseInt(match.getValue()))));
            break;
           
         case "arp_sha":
            matches.add(getMatch("of12.oxm_tlv_arp_sha", getUint48Fixed(Long.parseLong(match.getValue()))));
            break;
           
         case "arp_tha":
            matches.add(getMatch("of12.oxm_tlv_arp_tha", getUint48Fixed(Long.parseLong(match.getValue()))));
            break;

         case "ipv6_src":
            matches.add(getMatch("of12.oxm_tlv_ipv6_src", getUint128Fixed(get_ipv6(match.getValue()))));
            break;

         case "ipv6_dst":
            matches.add(getMatch("of12.oxm_tlv_ipv6_dst", getUint128Fixed(get_ipv6(match.getValue()))));
            break;

         case "ipv6_flabel":
            matches.add(getMatch("of12.oxm_tlv_ipv6_flabel", getUint32Fixed(Integer.parseInt(match.getValue()))));
            break;

         case "icmpv6_type":
            tmp = U8.t(Short.valueOf(match.getValue()));
            matches.add(getMatch("of12.oxm_tlv_icmpv6_type", getUint8Fixed(tmp)));
            break;
        
         case "icmpv6_code":
            tmp = U8.t(Short.valueOf(match.getValue()));
            matches.add(getMatch("of12.oxm_tlv_icmpv6_code", getUint8Fixed(tmp)));
            break;

         case "ipv6_nd_target":
            matches.add(getMatch("of12.oxm_tlv_ipv6_nd_target", getUint128Fixed(get_ipv6(match.getValue()))));
            break;

         case "ipv6_nd_sll":
            matches.add(getMatch("of12.oxm_tlv_ipv6_nd_sll", getUint48Fixed(Long.parseLong(match.getValue()))));
            break;

         case "ipv6_nd_tll":
            matches.add(getMatch("of12.oxm_tlv_ipv6_nd_tll", getUint48Fixed(Long.parseLong(match.getValue()))));
            break;

         case "mpls_label":
            matches.add(getMatch("of12.oxm_tlv_mpls_label", getUint32Fixed(Integer.parseInt(match.getValue()))));
            break;

         case "mpls_tc":
            tmp = U8.t(Short.valueOf(match.getValue()));
            matches.add(getMatch("of12.oxm_tlv_mpls_tc", getUint8Fixed(tmp)));
            break;

         case "mpls_bos":
            tmp = U8.t(Short.valueOf(match.getValue()));
            matches.add(getMatch("of12.oxm_tlv_mpls_bos", getUint8Fixed(tmp)));
            break;

         case "pbb_isid":
            matches.add(getMatch("of12.oxm_tlv_pbb_isid", getUint32Fixed(Integer.parseInt(match.getValue()))));
            break;

         case "tunnel_id":
            matches.add(getMatch("of12.oxm_tlv_tunnel_id", getUint32Fixed(Integer.parseInt(match.getValue()))));
            break;

         case "ipv6_exthdr":
            matches.add(getMatch("of12.oxm_tlv_ipv6_exthdr", getUint32Fixed(Integer.parseInt(match.getValue()))));
            break;
           
         default:
            break;

         }
      }
     
      Schema oxmTlvSchema = protocol.getType("of12.oxm_tlv");
     
      Schema oxmTlvFieldsSchema = protocol.getType("of12.oxm_tlv_fields");
      GenericRecord oxmTlvFieldsRecord = new GenericData.Record(oxmTlvFieldsSchema);
      oxmTlvFieldsRecord.put("oxm_tlvs", new GenericData.Array<>(Schema.createArray(oxmTlvSchema), matches));

      /*
       * Build match header
       */
      Schema matchHeaderSchema = protocol.getType("of12.match_header");
      GenericRecordBuilder matchHeaderBuilder = new GenericRecordBuilder(matchHeaderSchema);
      GenericRecord matchHeaderRecord = matchHeaderBuilder.build();
     
      /*
       * Calculating oxm_tlvs length
       */
      ByteArrayOutputStream oxmOut = new ByteArrayOutputStream();
      DatumWriter<GenericRecord> oxmWriter = new GenericDatumWriter<GenericRecord>(oxmTlvFieldsSchema);
      Encoder oxmEncoder = EncoderFactory.get().binaryNonEncoder(oxmOut, null);
     
      int closingPadLength = 4;
     
      try {
         oxmWriter.write(oxmTlvFieldsRecord, oxmEncoder);
         oxmEncoder.flush();
        
         int matchLength = oxmOut.size() + 4;
         closingPadLength = (int) ((matchLength + 7)/8*8 - matchLength);
        
         Schema uint16Schema = protocol.getType("of12.uint_16");
        
         byte len[] = {(byte)(matchLength >> 8), (byte)(255 & matchLength)};
         GenericData.Fixed lenght = new GenericData.Fixed(uint16Schema, len);
        
         matchHeaderRecord.put("length", lenght);
      } catch (IOException e1) {
         // TODO Auto-generated catch block
         e1.printStackTrace();
      }     
     
      /*
       * Build closing pad
       */
      ByteBuffer clP = ByteBuffer.allocate(closingPadLength);
//      GenericData.Fixed closingPadRecord = new GenericData.Fixed(Schema.createFixed("", "", "of", closingPadLength), clP.toByteArray());
 
      /*
       * Assemble ofp_match structure
       */
      ofpMatchSchema = protocol.getType("of12.ofp_match");
      ofpMatchRecord = new GenericData.Record(ofpMatchSchema);
      ofpMatchRecord.put("header", matchHeaderRecord);
      ofpMatchRecord.put("fields", oxmTlvFieldsRecord);
      ofpMatchRecord.put("closing_pad", clP);
     
     
      // TODO Improvs: I dislike this *.getInstructions().getIterator();
      //Iterator<Tuple<String, OFStructureInstruction>> instrIter = fmRef.getInstructions().getIterator();
      List<Tuple<String, OFStructureInstructionRef>> instrList = fmRef.getInstructions().getInstructions();
      Schema instrHeaderSchema = null;
      Schema instrSchema = null;
      GenericRecord instrHeaderRecord = null;
      GenericRecord instrRecord = null;
      for (Tuple<String, OFStructureInstructionRef> tuple : instrList) {
         boolean isActions = false;
         //Tuple<String, OFStructureInstruction> tuple = instrIter.next();
         String name = tuple.getName();
         OFStructureInstructionRef instruction = tuple.getValue();
        
         // TODO Improvs: Replace Switch with a structure... say, HashMap
         // TODO Improvs: How to control type compatibility between Schema types and incoming tlvs?
         switch (name) {
         case "apply_actions":
            instrHeaderSchema = protocol.getType("of12.instruction_apply_actions_header");
            instrSchema = protocol.getType("of12.ofp_instruction_apply_actions");
            instrRecord = new GenericData.Record(instrSchema);
            isActions = true;
            break;
         case "write_actions":
            instrHeaderSchema = protocol.getType("of12.instruction_write_actions_header");
            instrSchema = protocol.getType("of12.ofp_instruction_write_actions");
            instrRecord = new GenericData.Record(instrSchema);
            isActions = true;           
            break;
         case "clear_actions":
            instrHeaderSchema = protocol.getType("of12.instruction_clear_actions_header");
            instrSchema = protocol.getType("of12.ofp_instruction_clear_actions");
            instrRecord = new GenericData.Record(instrSchema);
            isActions = true;           
            break;
         case "goto_table":
            instrHeaderSchema = protocol.getType("of12.instruction_goto_table_header");
            instrSchema = protocol.getType("of12.ofp_instruction_goto_table");
            instrRecord = new GenericData.Record(instrSchema);
            instrRecord.put("table_id", getUint8Fixed((byte)15));
            instrRecord.put("pad", getPad3(0));
            isActions = false;           
            break;
         case "write_metadata":
            instrHeaderSchema = protocol.getType("of12.instruction_write_metadata_header")
            instrSchema = protocol.getType("of12.ofp_instruction_write_metadata");
            instrRecord = new GenericData.Record(instrSchema);
            isActions = false;           
            break;
         case "meter":
            instrHeaderSchema = protocol.getType("of12.instruction_meter_header");
            instrSchema = protocol.getType("of12.ofp_instruction_meter");
            instrRecord = new GenericData.Record(instrSchema);
            isActions = false;           
            break;
         }
        
         GenericRecordBuilder instrHeaderBuilder = new GenericRecordBuilder(instrHeaderSchema);
         instrHeaderRecord = instrHeaderBuilder.build();
         instrRecord.put("header", instrHeaderRecord);
        

         if (isActions) {
            List<Tuple<String, String>> actionList = instruction.getActions().getActions();
//            Iterator<Tuple<String, String>> actionIter = instruction.getActions().getIterator();
            Schema ofpActionSchema = protocol.getType("of12.ofp_action");
            List<GenericRecord> actions = new LinkedList<GenericRecord>();
            GenericRecord actionSetRecord = null;

            for (Tuple<String, String> action : actionList) {
//               Tuple<String, String> action = actionIter.next();
               String actName = action.getName();

               GenericRecord ofpActionRecord = new GenericData.Record(ofpActionSchema);
              
               switch (actName) {
               case "output":
                  Schema ofpActionOutSchema = protocol.getType("of12.ofp_action_output");
                  GenericRecordBuilder actionBuilder = new GenericRecordBuilder(ofpActionOutSchema);
                  GenericRecord ofpActionOutRecord = actionBuilder.build();
                 
                  ofpActionOutRecord.put("port", getUint32Fixed(Integer.decode(action.getValue())));
                  ofpActionRecord.put("action", ofpActionOutRecord);

                  break;
              
               default:
                  break;

               }
               actions.add(ofpActionRecord);
            }
                       
            Schema actionSetSchema = protocol.getType("of12.action_set");
            actionSetRecord = new GenericData.Record(actionSetSchema);
            actionSetRecord.put("set", new GenericData.Array<> (Schema.createArray(ofpActionSchema), actions));
           
            //TODO Improvs: Double putting?
            instrRecord.put("header", instrHeaderRecord);
            instrRecord.put("actions", actionSetRecord);
           
            instrHeaderRecord.put("length", getUint16Fixed(calculateLength(instrSchema, instrRecord)));
            instrRecord.put("header", instrHeaderRecord);
         }

         Schema ofpInstructionSchema = protocol.getType("of12.ofp_instruction");
         GenericRecord ofpInstructionRecord = new GenericData.Record(ofpInstructionSchema);
         ofpInstructionRecord.put("instruction", instrRecord);
         instructions.add(ofpInstructionRecord);
      }
     
      Schema ofpInstructionSchema = protocol.getType("of12.ofp_instruction");
      Schema instructionSetSchema = protocol.getType("of12.instruction_set");
      GenericRecord instructionSetRecord = new GenericData.Record(instructionSetSchema);
      instructionSetRecord.put("set", new GenericData.Array<> (Schema.createArray(ofpInstructionSchema), instructions));
     
     
      ofpFlowModRecord.put("header", flowModHeaderRecord);
      ofpFlowModRecord.put("base", flowModBodyRecord);
      ofpFlowModRecord.put("match", ofpMatchRecord);
      ofpFlowModRecord.put("instructions", instructionSetRecord);
     
      flowModHeaderRecord.put("length", getUint16Fixed(calculateLength(ofpFlowModSchema, ofpFlowModRecord)));
      ofpFlowModRecord.put("header", flowModHeaderRecord);
     
      ByteArrayOutputStream fmOut = new ByteArrayOutputStream();
      DatumWriter<GenericRecord> writer = new GenericDatumWriter<GenericRecord>(ofpFlowModSchema);
      Encoder encoder = EncoderFactory.get().binaryNonEncoder(fmOut, null);
     
      try {
         writer.write(ofpFlowModRecord, encoder);
         encoder.flush();
      } catch (IOException e1) {
         // TODO Auto-generated catch block
         e1.printStackTrace();
      }      
     
      return fmOut.toByteArray();
   }
  
   public ByteArrayOutputStream getFlowMod (Map<String, Object> args, ByteArrayOutputStream out) {
     
      /*
       * Build FlowMod message
       */
      GenericRecord ofpFlowModRecord = new GenericData.Record(ofpFlowModSchema);
      boolean isDelete = false;
      reset();
     
      /*
       * Create FlowMod Body
       */
      Schema flowModBodySchema = null;
      if (args.containsKey("delete")) {
         flowModBodySchema = protocol.getType("of12.flow_mod_body_delete");
         isDelete = true;
      }
      else {
         flowModBodySchema = protocol.getType("of12.flow_mod_body_add");
         isDelete = false;
      }
     
      GenericRecordBuilder flowModBodyBuilder = new GenericRecordBuilder(flowModBodySchema);
      GenericRecord flowModBodyRecord = flowModBodyBuilder.build();
      GenericRecord actionSetRecord = null; // TODO Empty actions instead of null!
     
      List <GenericRecord> instructions = new ArrayList<>();
      List <GenericRecord> matches = new ArrayList<>();
     
      for (String key : args.keySet()) {
         if (args.get(key) == null)
            continue;
        
         /*
          * PRIORITY
          */
         if (key.equals("priority")) {
            short priority = U16.t(Integer.valueOf((String) args.get(key)));
            byte temp [] = {(byte)(priority >> 8), (byte)(priority) };
           
            GenericData.Fixed priorityFixed = new GenericData.Fixed(uint_16Schema, temp);
         
            flowModBodyRecord.put("priority", priorityFixed);
         /*
          * ACTIONS  
          */
         } else if ((key.equals("goto_table")) || (key.equals("write_metadata")) || (key.equals("meter"))) {
            continue;
           
         } else if ( (key.equals("apply_actions")) || (key.equals("write_actions")) || (key.equals("clear_actions"))) {
            actionSetRecord = parseActionString((String) args.get(key));
           
            /*
             * Build Write Actions Instruction for Test
             */
            Schema instrHeaderSchema = null;
            Schema instrSchema = null;
            GenericRecord instrHeaderRecord = null;
            GenericRecord instrRecord = null;
           
            if (key.equals("apply_actions")) {
               instrHeaderSchema = protocol.getType("of12.instruction_apply_actions_header");
               instrSchema = protocol.getType("of12.ofp_instruction_apply_actions");
               instrRecord = new GenericData.Record(instrSchema);
            else if (key.equals("write_actions")) {
               instrHeaderSchema = protocol.getType("of12.instruction_write_actions_header");
               instrSchema = protocol.getType("of12.ofp_instruction_write_actions");
               instrRecord = new GenericData.Record(instrSchema);
            } else if (key.equals("clear_actions")) {
               instrHeaderSchema = protocol.getType("of12.instruction_clear_actions_header");
               instrSchema = protocol.getType("of12.ofp_instruction_clear_actions");
               instrRecord = new GenericData.Record(instrSchema);
            }
           
            GenericRecordBuilder instrHeaderBuilder = new GenericRecordBuilder(instrHeaderSchema);
            instrHeaderRecord = instrHeaderBuilder.build();
            instrRecord.put("header", instrHeaderRecord);
            instrRecord.put("actions", actionSetRecord);
           
            instrHeaderRecord.put("length", getUint16Fixed(calculateLength(instrSchema, instrRecord)));
            instrRecord.put("header", instrHeaderRecord);
           
            /*
             * Create ofp_instruction_write_actions
             */

            Schema ofpInstrSchema = protocol.getType("of12.ofp_instruction");
            GenericRecord ofpInstrRecord = new GenericData.Record(ofpInstrSchema);

            ofpInstrRecord.put("instruction", instrRecord);
            instructions.add(ofpInstrRecord);
         /*
          * MATCH - INGRESS PORT
          */
         } else if (key.equals("in_port")) {
           
           
            /*Schema oxmTlvIngressPortSchema = protocol.getType("of12.oxm_tlv_ingress_port");
            GenericRecord oxmTlvIngressPortRecord = new GenericData.Record(oxmTlvIngressPortSchema);
        
            int inPort = Integer.valueOf((String) args.get(key));
            oxmTlvIngressPortRecord.put("tlv", getUint32Fixed(inPort));
           
            Schema oxmTlvSchema = protocol.getType("of12.oxm_tlv");
            GenericRecord oxmTlvRecord = new GenericData.Record(oxmTlvSchema);
            oxmTlvRecord.put("match", oxmTlvIngressPortRecord);*/
           
            matches.add(getMatch("of12.oxm_tlv_ingress_port", getUint32Fixed(Integer.valueOf((String) args.get(key)))));
           
            /*
             * MATCH - IN_PHY PORT
             */
         } else if (key.equals("in_phy_port")) {
            Schema oxmTlvInPhyPortSchema = protocol.getType("of12.oxm_tlv_in_phy_port");
            GenericRecord oxmTlvInPhyPortRecord = new GenericData.Record(oxmTlvInPhyPortSchema);
              
            int inPort = Integer.valueOf((String) args.get(key));

            oxmTlvInPhyPortRecord.put("tlv", getUint32Fixed(inPort));
              
            Schema oxmTlvSchema = protocol.getType("of12.oxm_tlv");
            GenericRecord oxmTlvRecord = new GenericData.Record(oxmTlvSchema);
            oxmTlvRecord.put("match", oxmTlvInPhyPortRecord);
              
            matches.add(oxmTlvRecord);
           
            /*
             * MATCH - METADATA
             */
         } else if (key.equals("metadata")) {
            Schema oxmTlvMetadataSchema = protocol.getType("of12.oxm_tlv_metadata");
            GenericRecord oxmTlvMetadataRecord = new GenericData.Record(oxmTlvMetadataSchema);
              
            long mdata = Integer.valueOf((String) args.get(key));
            oxmTlvMetadataRecord.put("tlv", getUint64Fixed(mdata));
              
            Schema oxmTlvSchema = protocol.getType("of12.oxm_tlv");
            GenericRecord oxmTlvRecord = new GenericData.Record(oxmTlvSchema);
            oxmTlvRecord.put("match", oxmTlvMetadataRecord);
              
            matches.add(oxmTlvRecord);
           
           /*
            * MATCH - ETH_SRC
            */
         } else if (key.equals("dl_src")) {

            Schema oxmTlvFieldSchema = protocol.getType("of12.oxm_tlv_eth_src");
            GenericRecord oxmTlvFieldRecord = new GenericData.Record(oxmTlvFieldSchema);
           
            oxmTlvFieldRecord.put("tlv", getUint48Fixed(get_mac_addr((String) args.get(key))));
            Schema oxmTlvSchema = protocol.getType("of12.oxm_tlv");
            GenericRecord oxmTlvRecord = new GenericData.Record(oxmTlvSchema);
            oxmTlvRecord.put("match", oxmTlvFieldRecord);
           
            matches.add(oxmTlvRecord);

          /*
           * MATCH - ETH_DST
           */
      } else if (key.equals("dl_dst")) {
     
         Schema oxmTlvFieldSchema = protocol.getType("of12.oxm_tlv_eth_dst");
         GenericRecord oxmTlvFieldRecord = new GenericData.Record(oxmTlvFieldSchema);

         oxmTlvFieldRecord.put("tlv", getUint48Fixed(get_mac_addr((String) args.get(key))));
         Schema oxmTlvSchema = protocol.getType("of12.oxm_tlv");
         GenericRecord oxmTlvRecord = new GenericData.Record(oxmTlvSchema);
         oxmTlvRecord.put("match", oxmTlvFieldRecord);
        
         matches.add(oxmTlvRecord);
         
         /*
          * MATCH - ETH_TYPE
          */
      } else if (key.equals("dl_type")) {
         Schema oxmTlvEthTypeSchema = protocol.getType("of12.oxm_tlv_eth_type");
         GenericRecord oxmTlvEthTypeRecord = new GenericData.Record(oxmTlvEthTypeSchema);

         short ethType = U16.t(Integer.valueOf(((String) args.get(key)).replaceFirst("0x", ""), 16));
        
         oxmTlvEthTypeRecord.put("tlv", getUint16Fixed(ethType));
           
         Schema oxmTlvSchema = protocol.getType("of12.oxm_tlv");
         GenericRecord oxmTlvRecord = new GenericData.Record(oxmTlvSchema);
         oxmTlvRecord.put("match", oxmTlvEthTypeRecord);
  
         matches.add(oxmTlvRecord);
           
         if (this.delayedIpv4Src != null)
            matches.add(this.delayedIpv4Src);
         if (this.delayedIpv4Dst != null)
               matches.add(this.delayedIpv4Dst);
         if (this.delayedIpv6Src != null)
               matches.add(this.delayedIpv6Src);
         if (this.delayedIpv6Dst != null)
               matches.add(this.delayedIpv6Dst);
         if (this.delayedIpProto != null)
               matches.add(this.delayedIpProto);

         this.isEtherType = true;

        /*
         * VLAN_VID
         */
        } else if (key.equals("vlan_vid")) {
          
           Schema oxmTlvVlanVidSchema = protocol.getType("of12.oxm_tlv_vlan_vid");
           GenericRecord oxmTlvVlanVidRecord = new GenericData.Record(oxmTlvVlanVidSchema);
          
           short vid = U16.t(Integer.valueOf((String) args.get(key)));
           oxmTlvVlanVidRecord.put("tlv", getUint16Fixed(vid));
          
           Schema oxmTlvSchema = protocol.getType("of12.oxm_tlv");
           GenericRecord oxmTlvRecord = new GenericData.Record(oxmTlvSchema);
           oxmTlvRecord.put("match", oxmTlvVlanVidRecord);
          
           matches.add(oxmTlvRecord);
          
           if (this.delayedVlanPcp != null)
              matches.add(this.delayedVlanPcp);
           else
              this.isVlanVid = true;
          
         /*
          * VLAN_PCP
          */
         } else if (key.equals("dl_vlan_pcp")) {
           
            Schema oxmTlvFieldSchema = protocol.getType("of12.oxm_tlv_vlan_pcp");
            GenericRecord oxmTlvFieldRecord = new GenericData.Record(oxmTlvFieldSchema);
           
            byte tmp = U8.t(Short.valueOf((String) args.get(key)));
            oxmTlvFieldRecord.put("tlv", getUint8Fixed(tmp));
           
            Schema oxmTlvSchema = protocol.getType("of12.oxm_tlv");
            GenericRecord oxmTlvRecord = new GenericData.Record(oxmTlvSchema);
            oxmTlvRecord.put("match", oxmTlvFieldRecord);
           
            if (this.isVlanVid == true)
               matches.add(oxmTlvRecord);
            else
               this.delayedVlanPcp = oxmTlvRecord;


            /*
             * MATCH - IPV6_SRC
             */
         } else if (key.equals("ipv6_src")) {

            Schema oxmTlvFieldSchema = protocol.getType("of12.oxm_tlv_ipv6_src");
            GenericRecord oxmTlvFieldRecord = new GenericData.Record(oxmTlvFieldSchema);
            
            oxmTlvFieldRecord.put("tlv", getUint128Fixed(get_ipv6((String) args.get(key))));
            Schema oxmTlvSchema = protocol.getType("of12.oxm_tlv");
            GenericRecord oxmTlvRecord = new GenericData.Record(oxmTlvSchema);
            oxmTlvRecord.put("match", oxmTlvFieldRecord);
            
            if (this.isEtherType)
               matches.add(oxmTlvRecord);
            else
               this.delayedIpv6Src = oxmTlvRecord;
           
            /*
             * MATCH - IPV6_SRC
             */
         } else if (key.equals("ipv6_dst")) {

            Schema oxmTlvFieldSchema = protocol.getType("of12.oxm_tlv_ipv6_dst");
            GenericRecord oxmTlvFieldRecord = new GenericData.Record(oxmTlvFieldSchema);
            
            oxmTlvFieldRecord.put("tlv", getUint128Fixed(get_ipv6((String) args.get(key))));
            Schema oxmTlvSchema = protocol.getType("of12.oxm_tlv");
            GenericRecord oxmTlvRecord = new GenericData.Record(oxmTlvSchema);
            oxmTlvRecord.put("match", oxmTlvFieldRecord);
            
            if (this.isEtherType)
               matches.add(oxmTlvRecord);
            else
               this.delayedIpv6Dst = oxmTlvRecord;
           

         /*
          * OXM_OF_IP_DSCP
          */
         } else if (key.equals("ip_dscp")) {
           
            Schema oxmTlvFieldSchema = protocol.getType("of12.oxm_tlv_ip_dscp");
            GenericRecord oxmTlvFieldRecord = new GenericData.Record(oxmTlvFieldSchema);
           
            byte tmp = U8.t(Short.valueOf((String) args.get(key)));
           
            oxmTlvFieldRecord.put("tlv", getUint8Fixed(tmp));
           
            Schema oxmTlvSchema = protocol.getType("of12.oxm_tlv");
            GenericRecord oxmTlvRecord = new GenericData.Record(oxmTlvSchema);
            oxmTlvRecord.put("match", oxmTlvFieldRecord);
           
            matches.add(oxmTlvRecord);

         /*
          * OXM_OF_IP_ECN
          */
         } else if (key.equals("ip_ecn")) {
           
            Schema oxmTlvFieldSchema = protocol.getType("of12.oxm_tlv_ip_ecn");
            GenericRecord oxmTlvFieldRecord = new GenericData.Record(oxmTlvFieldSchema);
           
            byte tmp = U8.t(Short.valueOf((String) args.get(key)));
            oxmTlvFieldRecord.put("tlv", getUint8Fixed(tmp));
           
            Schema oxmTlvSchema = protocol.getType("of12.oxm_tlv");
            GenericRecord oxmTlvRecord = new GenericData.Record(oxmTlvSchema);
            oxmTlvRecord.put("match", oxmTlvFieldRecord);
           
            matches.add(oxmTlvRecord);

         /*
          * OXM_OF_IP_PROTO
          */
         } else if (key.equals("nw_proto")) {
           
            Schema oxmTlvFieldSchema = protocol.getType("of12.oxm_tlv_ip_proto");
            GenericRecord oxmTlvFieldRecord = new GenericData.Record(oxmTlvFieldSchema);
           
            byte tmp = U8.t(Short.valueOf((String) args.get(key)));
            oxmTlvFieldRecord.put("tlv", getUint8Fixed(tmp));
           
            Schema oxmTlvSchema = protocol.getType("of12.oxm_tlv");
            GenericRecord oxmTlvRecord = new GenericData.Record(oxmTlvSchema);
            oxmTlvRecord.put("match", oxmTlvFieldRecord);
           
            if (this.isEtherType) {
               matches.add(oxmTlvRecord);
               this.isIpProto = true;
            }
            else {
               this.delayedIpProto = oxmTlvRecord;
            }
           
            if (this.delayedTcpSrc != null)
               matches.add(this.delayedTcpSrc);
            if (this.delayedTcpDst != null)
               matches.add(this.delayedTcpDst);
            if (this.delayedUdpSrc != null)
               matches.add(this.delayedUdpSrc);
            if (this.delayedUdpDst != null)
               matches.add(this.delayedUdpDst);
/*            if (this.delayedIpv6Src != null)
               matches.add(this.delayedIpv6Src);
            if (this.delayedIpv6Dst != null)
               matches.add(this.delayedIpv6Dst);
            if (this.delayedIpProto != null)
               matches.add(this.delayedIpProto);*/

            /*
             * MATCH - IPV4_SRC
             */
         } else if (key.equals("nw_src")) {
           
            Schema oxmTlvFieldSchema = protocol.getType("of12.oxm_tlv_ipv4_src");
            GenericRecord oxmTlvFieldRecord = new GenericData.Record(oxmTlvFieldSchema);
            
            oxmTlvFieldRecord.put("tlv", getUint32Fixed(get_ipv4((String) args.get(key))));

            Schema oxmTlvSchema = protocol.getType("of12.oxm_tlv");
            GenericRecord oxmTlvRecord = new GenericData.Record(oxmTlvSchema);
            oxmTlvRecord.put("match", oxmTlvFieldRecord);
           
            if (this.isEtherType)
               matches.add(oxmTlvRecord);
            else
               this.delayedIpv4Src = oxmTlvRecord;
           

            /*
             * MATCH - IPV4_DST
             */
         } else if (key.equals("nw_dst")) {
            
            Schema oxmTlvFieldSchema = protocol.getType("of12.oxm_tlv_ipv4_dst");
            GenericRecord oxmTlvFieldRecord = new GenericData.Record(oxmTlvFieldSchema);
            
            oxmTlvFieldRecord.put("tlv", getUint32Fixed(get_ipv4((String) args.get(key))));

            Schema oxmTlvSchema = protocol.getType("of12.oxm_tlv");
            GenericRecord oxmTlvRecord = new GenericData.Record(oxmTlvSchema);
            oxmTlvRecord.put("match", oxmTlvFieldRecord);

            if (this.isEtherType)
               matches.add(oxmTlvRecord);
            else
               this.delayedIpv4Dst = oxmTlvRecord;
           
            /*
             * MATCH - TCP_SRC
             */
         } else if (key.equals("tp_src")) {
            
            Schema oxmTlvFieldSchema = protocol.getType("of12.oxm_tlv_tcp_src");
            GenericRecord oxmTlvFieldRecord = new GenericData.Record(oxmTlvFieldSchema);
            
            oxmTlvFieldRecord.put("tlv", getUint16Fixed(U16.t(Integer.valueOf((String) args.get(key)))));

            Schema oxmTlvSchema = protocol.getType("of12.oxm_tlv");
            GenericRecord oxmTlvRecord = new GenericData.Record(oxmTlvSchema);
            oxmTlvRecord.put("match", oxmTlvFieldRecord);

            if (this.isIpProto)
               matches.add(oxmTlvRecord);
            else
               this.delayedTcpSrc = oxmTlvRecord;

            /*
             * MATCH - TCP_DST
             */
         } else if (key.equals("tp_dst")) {
            
            Schema oxmTlvFieldSchema = protocol.getType("of12.oxm_tlv_tcp_dst");
            GenericRecord oxmTlvFieldRecord = new GenericData.Record(oxmTlvFieldSchema);
            
            oxmTlvFieldRecord.put("tlv", getUint16Fixed(U16.t(Integer.valueOf((String) args.get(key)))));

            Schema oxmTlvSchema = protocol.getType("of12.oxm_tlv");
            GenericRecord oxmTlvRecord = new GenericData.Record(oxmTlvSchema);
            oxmTlvRecord.put("match", oxmTlvFieldRecord);

            if (this.isIpProto)
               matches.add(oxmTlvRecord);

            else
               this.delayedTcpDst = oxmTlvRecord;

            /*
             * MATCH - UDP_SRC
             */
         } else if (key.equals("udp_src")) {

            if (this.isIpProto)
               matches.add(getMatch("of12.oxm_tlv_udp_src", getUint16Fixed(U16.t(Integer.valueOf((String) args.get(key))))));
            else
               this.delayedUdpSrc = getMatch("of12.oxm_tlv_udp_src", getUint16Fixed(U16.t(Integer.valueOf((String) args.get(key)))));

            /*
             * MATCH - UDP_DST
             */
         } else if (key.equals("udp_dst")) {

            if (this.isIpProto)
               matches.add(getMatch("of12.oxm_tlv_udp_dst", getUint16Fixed(U16.t(Integer.valueOf((String) args.get(key))))));
            else
               this.delayedUdpDst = getMatch("of12.oxm_tlv_udp_dst", getUint16Fixed(U16.t(Integer.valueOf((String) args.get(key)))));
           
           
         }
      }

      Schema oxmTlvSchema = protocol.getType("of12.oxm_tlv");
      GenericArray<GenericRecord> oxmTlvsArray = new GenericData.Array<>(Schema.createArray(oxmTlvSchema), matches);
     
      Schema oxmTlvFieldsSchema = protocol.getType("of12.oxm_tlv_fields");
      GenericRecord oxmTlvFieldsRecord = new GenericData.Record(oxmTlvFieldsSchema);
      oxmTlvFieldsRecord.put("oxm_tlvs", oxmTlvsArray);

      /*
       * Build match header
       */
      Schema matchHeaderSchema = protocol.getType("of12.match_header");
      GenericRecordBuilder matchHeaderBuilder = new GenericRecordBuilder(matchHeaderSchema);
      GenericRecord matchHeaderRecord = matchHeaderBuilder.build();
     
      /*
       * Calculating oxm_tlvs length
       */
      ByteArrayOutputStream oxmOut = new ByteArrayOutputStream();
      DatumWriter<GenericRecord> oxmWriter = new GenericDatumWriter<GenericRecord>(oxmTlvFieldsSchema);
      Encoder oxmEncoder = EncoderFactory.get().binaryNonEncoder(oxmOut, null);
     
      int closingPadLength = 4;
     
      try {
         oxmWriter.write(oxmTlvFieldsRecord, oxmEncoder);
         oxmEncoder.flush();
        
         int matchLength = oxmOut.size() + 4;
         closingPadLength = (int) ((matchLength + 7)/8*8 - matchLength);
        
         Schema uint16Schema = protocol.getType("of12.uint_16");
        
         byte len[] = {(byte)(matchLength >> 8), (byte)(255 & matchLength)};
         GenericData.Fixed lenght = new GenericData.Fixed(uint16Schema, len);
        
         matchHeaderRecord.put("length", lenght);
      } catch (IOException e1) {
         // TODO Auto-generated catch block
         e1.printStackTrace();
      }     
     
      /*
       * Build closing pad
       */
      ByteBuffer clP = ByteBuffer.allocate(closingPadLength);
//      GenericData.Fixed closingPadRecord = new GenericData.Fixed(Schema.createFixed("", "", "of", closingPadLength), clP.toByteArray());
 
      /*
       * Assemble ofp_match structure
       */
      Schema ofpMatchSchema = protocol.getType("of12.ofp_match");
      GenericRecord ofpMatchRecord = new GenericData.Record(ofpMatchSchema);
      ofpMatchRecord.put("header", matchHeaderRecord);
      ofpMatchRecord.put("fields", oxmTlvFieldsRecord);
      ofpMatchRecord.put("closing_pad", clP);

     
/* I N S T R U C T I O N S */     
      /*
       * Build Instruction records
       * Build GoTo Instruction for Test
       */
      Schema ofpInstrSchema = protocol.getType("of12.ofp_instruction");
  /*    GenericRecord ofpInstrRecord = new GenericData.Record(ofpInstrSchema);
     
      Schema ofpInstrGoToSchema = protocol.getType("of12.ofp_instruction_goto_table");
      GenericRecordBuilder instrBuilder = new GenericRecordBuilder(ofpInstrGoToSchema);
      GenericRecord ofpInstrGoToRecord = instrBuilder.build();
      ofpInstrRecord.put("instruction", ofpInstrGoToRecord);
     
      instructions.add(ofpInstrRecord);
*/
      GenericArray<GenericRecord> instrArray = new GenericData.Array<>(Schema.createArray(ofpInstrSchema), instructions);
     
      /*
       * Create Instruction Set
       */
      Schema instrSetSchema = protocol.getType("of12.instruction_set");
      GenericRecord instrSetRecord = new GenericData.Record(instrSetSchema);
      instrSetRecord.put("set", instrArray);

/* F L O W  M O D  M E S S A G E */ 
      /*
       * Create FlowMod Header
       */
      GenericRecordBuilder flowModHeaderBuilder = new GenericRecordBuilder(flowModHeaderSchema);
      GenericRecord flowModHeaderRecord = flowModHeaderBuilder.build();
     
      /*
       * Assemble Flow_mod message
       */
      ofpFlowModRecord.put("header", flowModHeaderRecord);     
      ofpFlowModRecord.put("base", flowModBodyRecord);
      ofpFlowModRecord.put("match", ofpMatchRecord);
      /*if (! isDelete)*/
         ofpFlowModRecord.put("instructions", instrSetRecord);
     
      DatumWriter<GenericRecord> writer = new GenericDatumWriter<GenericRecord>(ofpFlowModSchema);
      Encoder encoder = EncoderFactory.get().binaryNonEncoder(out, null);
     
     
      try {
         writer.write(ofpFlowModRecord, encoder);
         encoder.flush();
        
         Schema uint16Schema = protocol.getType("of12.uint_16");
              
         byte len[] = {(byte)(out.size() >> 8), (byte)(255 & out.size())};
         GenericData.Fixed lenght = new GenericData.Fixed(uint16Schema, len);
        
         flowModHeaderRecord.put("length", lenght);
        
         ofpFlowModRecord.put("header", flowModHeaderRecord);
        
         out.reset();
         writer.write(ofpFlowModRecord, encoder);
         encoder.flush();
        
      } catch (IOException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      }
     
      return out;
   }  
  
   /*
    * Utilities
    */
  
   public GenericRecord parseActionString(String actionstr) {
     
      Schema ofpActionSchema = protocol.getType("of12.ofp_action");     
      List<GenericRecord> actions = new LinkedList<GenericRecord>();
     
      GenericRecord actionSetRecord = null;

      if (actionstr != null) {
          actionstr = actionstr.toLowerCase();
          for (String subaction : actionstr.split(",")) {
              String action = subaction.split("[=:]")[0].trim();
             
              GenericRecord ofpActionRecord = null;
             
              if (action.equals("output")) {
                 ofpActionRecord = decode_output(subaction.trim());
              } else if (action.equals("set_field_eth_dst")) {
                 ofpActionRecord = decode_set_field_eth_dst(subaction.trim());
              else if (action.equals("set_field_eth_src")) {
                 ofpActionRecord = decode_set_field_eth_src(subaction.trim());
              else if (action.equals("set_field_vlan_vid")) {
                 ofpActionRecord = decode_set_field_vlan_vid(subaction.trim());
              else if (action.equals("set_field_mpls_label")) {
                 ofpActionRecord = decode_set_field_mpls_label(subaction.trim());
              else if (action.equals("pop_vlan")) {
                 ofpActionRecord = decode_pop_vlan(subaction.trim());
              else if (action.equals("push_mpls")) {
                 ofpActionRecord = decode_push_mpls(subaction.trim());
              else if (action.equals("set_queue")) {
                 ofpActionRecord = decode_set_queue(subaction.trim());
              }
/*              else if (action.equals("enqueue")) {
                  subaction_struct = decode_enqueue(subaction);
              }
              else if (action.equals("strip-vlan")) {
                  subaction_struct = decode_strip_vlan(subaction);
              }
              else if (action.equals("set-vlan-id")) {
                  subaction_struct = decode_set_vlan_id(subaction);
              }
              else if (action.equals("set-vlan-priority")) {
                  subaction_struct = decode_set_vlan_priority(subaction);
              }
              else if (action.equals("set-src-mac")) {
                  subaction_struct = decode_set_src_mac(subaction);
              }
              else if (action.equals("set-dst-mac")) {
                  subaction_struct = decode_set_dst_mac(subaction);
              }
              else if (action.equals("set-tos-bits")) {
                  subaction_struct = decode_set_tos_bits(subaction);
              }
              else if (action.equals("set-src-ip")) {
                  subaction_struct = decode_set_src_ip(subaction);
              }
              else if (action.equals("set-dst-ip")) {
                  subaction_struct = decode_set_dst_ip(subaction);
              }
              else if (action.equals("set-src-port")) {
                  subaction_struct = decode_set_src_port(subaction);
              }
              else if (action.equals("set-dst-port")) {
                  subaction_struct = decode_set_dst_port(subaction);
              }
              else {
      //            log.error("  Unexpected action '{}', '{}'", action, subaction);
              }*/
              actions.add(ofpActionRecord);
          }
         

          GenericArray<GenericRecord> actionArray = new GenericData.Array<> (Schema.createArray(ofpActionSchema), actions);
          Schema actionSetSchema = protocol.getType("of12.action_set");
          actionSetRecord = new GenericData.Record(actionSetSchema);
          actionSetRecord.put("set", actionArray);
      }
     
      return actionSetRecord;
  }
  
   private GenericRecord decode_output(String subaction) {

      Matcher n;     
     
      Schema ofpActionSchema = protocol.getType("of12.ofp_action");
      GenericRecord ofpActionBaseRecord = new GenericData.Record(ofpActionSchema);
       
   
      Schema ofpActionOutSchema = protocol.getType("of12.ofp_action_output");
      GenericRecordBuilder actionBuilder = new GenericRecordBuilder(ofpActionOutSchema);
      GenericRecord ofpActionOutRecord = actionBuilder.build();
     
      n = Pattern.compile("output=(?:((?:0x)?\\d+)|(all)|(controller)|(local)|(ingress-port)|(normal)|(flood))").matcher(subaction);
      if (n.matches()) {

//          int port = OFPort.OFPP_NONE.getValue();
         int port = 0;
         if (n.group(1) != null) {
              try {
                  port = getInt(n.group(1));
              }
              catch (NumberFormatException e) {
                 // log.debug("  Invalid port in: '{}' (error ignored)", subaction);
                  return null;
              }
          }
/*          else if (n.group(2) != null)
              port = OFPort.OFPP_ALL.getValue();
          else if (n.group(3) != null)
              port = OFPort.OFPP_CONTROLLER.getValue();
          else if (n.group(4) != null)
              port = OFPort.OFPP_LOCAL.getValue();
          else if (n.group(5) != null)
              port = OFPort.OFPP_IN_PORT.getValue();
          else if (n.group(6) != null)
              port = OFPort.OFPP_NORMAL.getValue();
          else if (n.group(7) != null)
              port = OFPort.OFPP_FLOOD.getValue();*/
          ofpActionOutRecord.put("port", getUint32Fixed(port));
      }
      else {
      //    log.error("  Invalid action: '{}'", subaction);
          return null;
      }
     
      ofpActionBaseRecord.put("action", ofpActionOutRecord);
     
      return ofpActionBaseRecord;
  }
  
   private GenericRecord decode_set_queue (String subaction) {
     
      Matcher n;
     
      Schema ofpActionSchema = protocol.getType("of12.ofp_action");
      GenericRecord ofpActionRecord = new GenericData.Record(ofpActionSchema);
     
      Schema ofpActionSetQueueHeaderSchema = protocol.getType("of12.action_set_queue_header");

      GenericRecordBuilder headerBuilder = new GenericRecordBuilder(ofpActionSetQueueHeaderSchema);
      GenericRecord actionSetQueueHeaderRecord = headerBuilder.build();
     
      Schema ofpActionSetQueueSchema = protocol.getType("of12.ofp_action_set_queue");
      GenericRecord ofpActionSetQueueRecord = new GenericData.Record(ofpActionSetQueueSchema);
     
      n = Pattern.compile("set_queue=(?:((?:0x)?\\d+))").matcher(subaction);
     
      if (n.matches()) {

         int queue;
         if (n.group(1) != null) {
             try {
                 queue = getInt(n.group(1));
                 ofpActionSetQueueRecord.put("queue_id", getUint32Fixed(queue));
             }
             catch (NumberFormatException e) {
                 return null;
             }
         }
      } else {
         return null;
      }  
     
      ofpActionSetQueueRecord.put("header", actionSetQueueHeaderRecord);
      ofpActionRecord.put("action", ofpActionSetQueueRecord);

      return ofpActionRecord;

   }
     
   private GenericRecord decode_set_field_eth_dst(String subaction) {

      Matcher n;     
     
      Schema ofpActionSchema = protocol.getType("of12.ofp_action");
      GenericRecord ofpActionRecord = new GenericData.Record(ofpActionSchema);
      List <GenericRecord> matches = new ArrayList<>();
     
      Schema actionSetFieldHeaderSchema = protocol.getType("of12.action_set_field_header");
      GenericRecordBuilder headerBuilder = new GenericRecordBuilder(actionSetFieldHeaderSchema);
      GenericRecord actionSetFieldHeaderRecord = headerBuilder.build();
   
      Schema ofpActionSetFieldSchema = protocol.getType("of12.ofp_action_set_field");
      GenericRecord ofpActionSetFieldRecord = new GenericData.Record(ofpActionSetFieldSchema);

      n = Pattern.compile("set_field_eth_dst=(?:((?:0x)?\\d+))").matcher(subaction);
      if (n.matches()) {

          long eth = 0;
          if (n.group(1) != null) {
              try {
                  eth = getLong(n.group(1));
              }
              catch (NumberFormatException e) {
                 // log.debug("  Invalid port in: '{}' (error ignored)", subaction);
                  return null;
              }
          }
         
/*          Schema oxmTlvEthDstSchema = protocol.getType("of12.oxm_tlv_eth_dst");
          GenericRecord oxmTlvEthDstRecord = new GenericData.Record(oxmTlvEthDstSchema);
          int oxmTlvHeader = (OXMClass.OFPXMC_OPENFLOW_BASIC.getValue() << 16) |
                             (OXMField.OFPXMT_OFB_ETH_DST.getValue() << 9) |
                             (0 << 8) |
                             6;
         
            
          oxmTlvEthDstRecord.put("header", getUint32Fixed(oxmTlvHeader));
          oxmTlvEthDstRecord.put("tlv", getUint48Fixed(eth));
         
          Schema oxmTlvSchema = protocol.getType("of12.oxm_tlv");
          GenericRecord oxmTlvRecord = new GenericData.Record(oxmTlvSchema);
          oxmTlvRecord.put("match", oxmTlvEthDstRecord);
         
          matches.add(oxmTlvRecord);*/

          Schema oxmTlvSchema = protocol.getType("of12.oxm_tlv");
          matches.add(getMatch("of12.oxm_tlv_eth_dst", getUint48Fixed(eth)));
         
          GenericArray<GenericRecord> oxmTlvsArray = new GenericData.Array<>(Schema.createArray(oxmTlvSchema), matches);
         
          Schema oxmTlvFieldsSchema = protocol.getType("of12.oxm_tlv_fields");
          GenericRecord oxmTlvFieldsRecord = new GenericData.Record(oxmTlvFieldsSchema);
          oxmTlvFieldsRecord.put("oxm_tlvs", oxmTlvsArray);

         
          /*
           * Calculating oxm_tlvs length
           */
          ByteArrayOutputStream oxmOut = new ByteArrayOutputStream();
          DatumWriter<GenericRecord> oxmWriter = new GenericDatumWriter<GenericRecord>(oxmTlvFieldsSchema);
          Encoder oxmEncoder = EncoderFactory.get().binaryNonEncoder(oxmOut, null);
         
          int closingPadLength = 4;
         
          try {
             oxmWriter.write(oxmTlvFieldsRecord, oxmEncoder);
             oxmEncoder.flush();
            
             short matchLength = (short)oxmOut.size();
             closingPadLength = (int)(((matchLength + 4) + 7)/8*8 - (matchLength + 4));
             actionSetFieldHeaderRecord.put("length", getUint16Fixed(matchLength));

          } catch (IOException e1) {
             // TODO Auto-generated catch block
             e1.printStackTrace();
          }     
         
          /*
           * Build closing pad
           */
          ByteBuffer clP = ByteBuffer.allocate(closingPadLength);
    
          /*
           * Assemble action structure
           */
          ofpActionSetFieldRecord.put("header", actionSetFieldHeaderRecord);
          ofpActionSetFieldRecord.put("fields", oxmTlvFieldsRecord);
          ofpActionSetFieldRecord.put("closing_pad", clP);            /*
           * Calculate ofp_instruction_write_actions length
           */
         
          ByteArrayOutputStream actOut = new ByteArrayOutputStream();
          DatumWriter<GenericRecord> actWriter = new GenericDatumWriter<GenericRecord>(ofpActionSetFieldSchema);
          Encoder instrEncoder = EncoderFactory.get().binaryNonEncoder(actOut, null);
        
          try {
             actWriter.write(ofpActionSetFieldRecord, instrEncoder);
             instrEncoder.flush();
            
             Schema uint16Schema = protocol.getType("of12.uint_16");
            
             byte len[] = {(byte)(actOut.size() >> 8), (byte)(255 & actOut.size())};
             GenericData.Fixed lenght = new GenericData.Fixed(uint16Schema, len);
            
             actionSetFieldHeaderRecord.put("length", getUint16Fixed((short)actOut.size()));
             ofpActionSetFieldRecord.put("header", actionSetFieldHeaderRecord);
          } catch (IOException e1) {
             // TODO Auto-generated catch block
             e1.printStackTrace();
          }
      }
      else {
          return null;
      }
     
      ofpActionRecord.put("action", ofpActionSetFieldRecord);
     
      return ofpActionRecord;
  }
  
  private GenericRecord decode_set_field_eth_src(String subaction) {

      Matcher n;     
     
      Schema ofpActionSchema = protocol.getType("of12.ofp_action");
      GenericRecord ofpActionRecord = new GenericData.Record(ofpActionSchema);
      List <GenericRecord> matches = new ArrayList<>();
     
      Schema actionSetFieldHeaderSchema = protocol.getType("of12.action_set_field_header");
      GenericRecordBuilder headerBuilder = new GenericRecordBuilder(actionSetFieldHeaderSchema);
      GenericRecord actionSetFieldHeaderRecord = headerBuilder.build();
   
      Schema ofpActionSetFieldSchema = protocol.getType("of12.ofp_action_set_field");
      GenericRecord ofpActionSetFieldRecord = new GenericData.Record(ofpActionSetFieldSchema);

      //TODO implement format XX:XX:XX:XX:XX:XX using the precious get_mac_addr()
      n = Pattern.compile("set_field_eth_src=(?:((?:0x)?\\d+))").matcher(subaction);
      if (n.matches()) {

          long eth = 0;
          if (n.group(1) != null) {
              try {
                  eth = getLong(n.group(1));
              }
              catch (NumberFormatException e) {
                 // log.debug("  Invalid port in: '{}' (error ignored)", subaction);
                  return null;
              }
          }
         
/*          Schema oxmTlvEthSrcSchema = protocol.getType("of12.oxm_tlv_eth_src");
          GenericRecord oxmTlvEthSrcRecord = new GenericData.Record(oxmTlvEthSrcSchema);
         
          int oxmTlvHeader = (OXMClass.OFPXMC_OPENFLOW_BASIC.getValue() << 16) |
                             (OXMField.OFPXMT_OFB_ETH_SRC.getValue() << 9) |
                             (0 << 8) |
                             6;
         
          oxmTlvEthSrcRecord.put("header", getUint32Fixed(oxmTlvHeader));
          oxmTlvEthSrcRecord.put("tlv", getUint48Fixed(eth));
         
          Schema oxmTlvSchema = protocol.getType("of12.oxm_tlv");
          GenericRecord oxmTlvRecord = new GenericData.Record(oxmTlvSchema);
          oxmTlvRecord.put("match", oxmTlvEthSrcRecord);*/

          Schema oxmTlvSchema = protocol.getType("of12.oxm_tlv");         
          matches.add(getMatch("of12.oxm_tlv_eth_src", getUint48Fixed(eth)));
         
          GenericArray<GenericRecord> oxmTlvsArray = new GenericData.Array<>(Schema.createArray(oxmTlvSchema), matches);
         
          Schema oxmTlvFieldsSchema = protocol.getType("of12.oxm_tlv_fields");
          GenericRecord oxmTlvFieldsRecord = new GenericData.Record(oxmTlvFieldsSchema);
          oxmTlvFieldsRecord.put("oxm_tlvs", oxmTlvsArray);
         
          /*
           * Calculating oxm_tlvs length
           */
          ByteArrayOutputStream oxmOut = new ByteArrayOutputStream();
          DatumWriter<GenericRecord> oxmWriter = new GenericDatumWriter<GenericRecord>(oxmTlvFieldsSchema);
          Encoder oxmEncoder = EncoderFactory.get().binaryNonEncoder(oxmOut, null);
         
          int closingPadLength = 4;
         
          try {
             oxmWriter.write(oxmTlvFieldsRecord, oxmEncoder);
             oxmEncoder.flush();
            
             short matchLength = (short)oxmOut.size();
             closingPadLength = (int)(((matchLength + 4) + 7)/8*8 - (matchLength + 4));
             actionSetFieldHeaderRecord.put("length", getUint16Fixed(matchLength));

          } catch (IOException e1) {
             // TODO Auto-generated catch block
             e1.printStackTrace();
          }     
         
          /*
           * Build closing pad
           */
          ByteBuffer clP = ByteBuffer.allocate(closingPadLength);
    
          /*
           * Assemble action structure
           */
          ofpActionSetFieldRecord.put("header", actionSetFieldHeaderRecord);
          ofpActionSetFieldRecord.put("fields", oxmTlvFieldsRecord);
          ofpActionSetFieldRecord.put("closing_pad", clP);            /*
           * Calculate ofp_instruction_write_actions length
           */
         
          ByteArrayOutputStream actOut = new ByteArrayOutputStream();
          DatumWriter<GenericRecord> actWriter = new GenericDatumWriter<GenericRecord>(ofpActionSetFieldSchema);
          Encoder instrEncoder = EncoderFactory.get().binaryNonEncoder(actOut, null);
        
          try {
             actWriter.write(ofpActionSetFieldRecord, instrEncoder);
             instrEncoder.flush();
            
             Schema uint16Schema = protocol.getType("of12.uint_16");
            
             byte len[] = {(byte)(actOut.size() >> 8), (byte)(255 & actOut.size())};
             GenericData.Fixed lenght = new GenericData.Fixed(uint16Schema, len);
            
             actionSetFieldHeaderRecord.put("length", getUint16Fixed((short)actOut.size()));
             ofpActionSetFieldRecord.put("header", actionSetFieldHeaderRecord);
          } catch (IOException e1) {
             // TODO Auto-generated catch block
             e1.printStackTrace();
          }
      }
      else {
          return null;
      }
     
      ofpActionRecord.put("action", ofpActionSetFieldRecord);
     
      return ofpActionRecord;
  }
 
  private GenericRecord decode_push_mpls(String subaction) {
    
     Matcher n;
    
     Schema ofpActionSchema = protocol.getType("of12.ofp_action");
     GenericRecord ofpActionRecord = new GenericData.Record(ofpActionSchema);
    
     Schema actionPushMplsHeaderSchema = protocol.getType("of12.action_push_mpls_header");
     GenericRecordBuilder headerBuilder = new GenericRecordBuilder(actionPushMplsHeaderSchema);
     GenericRecord actionPushMplsHeaderRecord = headerBuilder.build();
    
     Schema ofpActionPushMplsSchema = protocol.getType("of12.ofp_action_push_mpls");
     GenericRecord ofpActionPushMplsRecord = new GenericData.Record(ofpActionPushMplsSchema);

     ofpActionPushMplsRecord.put("header", actionPushMplsHeaderRecord);
     ofpActionPushMplsRecord.put("pad", getPad2((short)0));

     n = Pattern.compile("push_mpls=(?:((?:0x)?\\d+))").matcher(subaction);
     if (n.matches()) {

         short ethertype = 0;
         if (n.group(1) != null) {
             try {
                ethertype = U16.t(Integer.valueOf(((String) n.group(1)).replaceFirst("0x", ""), 16));
                      //getShort(n.group(1));
             }
             catch (NumberFormatException e) {
                // log.debug("  Invalid port in: '{}' (error ignored)", subaction);
                 return null;
             }
         }
         ofpActionPushMplsRecord.put("ethertype", getUint16Fixed(ethertype));
     }

     ofpActionRecord.put("action", ofpActionPushMplsRecord);

     return ofpActionRecord;
  }
 
  private GenericRecord decode_pop_vlan(String subaction) {
    
     Matcher n;
    
     Schema ofpActionSchema = protocol.getType("of12.ofp_action");
     GenericRecord ofpActionRecord = new GenericData.Record(ofpActionSchema);
    
     Schema actionPopVlanHeaderSchema = protocol.getType("of12.action_pop_vlan_header");
     GenericRecordBuilder headerBuilder = new GenericRecordBuilder(actionPopVlanHeaderSchema);
     GenericRecord actionPopVlanHeaderRecord = headerBuilder.build();
    
     Schema ofpActionPopVlanSchema = protocol.getType("of12.ofp_action_pop_vlan");
     GenericRecord ofpActionPopVlanRecord = new GenericData.Record(ofpActionPopVlanSchema);
    
     ofpActionPopVlanRecord.put("header", actionPopVlanHeaderRecord);
     ofpActionPopVlanRecord.put("pad", getPad4(0));

     ofpActionRecord.put("action", ofpActionPopVlanRecord);

     return ofpActionRecord;
  }
 
  private GenericRecord decode_set_field_vlan_vid(String subaction) {

      Matcher n;     
     
      Schema ofpActionSchema = protocol.getType("of12.ofp_action");
      GenericRecord ofpActionRecord = new GenericData.Record(ofpActionSchema);
      List <GenericRecord> matches = new ArrayList<>();
     
      Schema actionSetFieldHeaderSchema = protocol.getType("of12.action_set_field_header");
      GenericRecordBuilder headerBuilder = new GenericRecordBuilder(actionSetFieldHeaderSchema);
      GenericRecord actionSetFieldHeaderRecord = headerBuilder.build();
   
      Schema ofpActionSetFieldSchema = protocol.getType("of12.ofp_action_set_field");
      GenericRecord ofpActionSetFieldRecord = new GenericData.Record(ofpActionSetFieldSchema);

      n = Pattern.compile("set_field_vlan_vid=(?:((?:0x)?\\d+))").matcher(subaction);
      if (n.matches()) {

          short vid = 0;
          if (n.group(1) != null) {
              try {
                  vid = getShort(n.group(1));
              }
              catch (NumberFormatException e) {
                 // log.debug("  Invalid port in: '{}' (error ignored)", subaction);
                  return null;
              }
          }
         
/*          Schema oxmTlvVlanVidSchema = protocol.getType("of12.oxm_tlv_vlan_vid");
          GenericRecord oxmTlvVlanVidRecord = new GenericData.Record(oxmTlvVlanVidSchema);
         
          int oxmTlvHeader = (OXMClass.OFPXMC_OPENFLOW_BASIC.getValue() << 16) |
                             (OXMField.OFPXMT_OFB_VLAN_VID.getValue() << 9) |
                             (0 << 8) |
                             2;
         
          oxmTlvVlanVidRecord.put("header", getUint32Fixed(oxmTlvHeader));
          oxmTlvVlanVidRecord.put("tlv", getUint16Fixed(vid));
         
          Schema oxmTlvSchema = protocol.getType("of12.oxm_tlv");
          GenericRecord oxmTlvRecord = new GenericData.Record(oxmTlvSchema);
          oxmTlvRecord.put("match", oxmTlvVlanVidRecord);*/
         
          Schema oxmTlvSchema = protocol.getType("of12.oxm_tlv");         
          matches.add(getMatch("of12.oxm_tlv_vlan_vid", getUint16Fixed(vid)));
         
          GenericArray<GenericRecord> oxmTlvsArray = new GenericData.Array<>(Schema.createArray(oxmTlvSchema), matches);
         
          Schema oxmTlvFieldsSchema = protocol.getType("of12.oxm_tlv_fields");
          GenericRecord oxmTlvFieldsRecord = new GenericData.Record(oxmTlvFieldsSchema);
          oxmTlvFieldsRecord.put("oxm_tlvs", oxmTlvsArray);
         
          /*
           * Calculating oxm_tlvs length
           */
          ByteArrayOutputStream oxmOut = new ByteArrayOutputStream();
          DatumWriter<GenericRecord> oxmWriter = new GenericDatumWriter<GenericRecord>(oxmTlvFieldsSchema);
          Encoder oxmEncoder = EncoderFactory.get().binaryNonEncoder(oxmOut, null);
         
          int closingPadLength = 4;
         
          try {
             oxmWriter.write(oxmTlvFieldsRecord, oxmEncoder);
             oxmEncoder.flush();
            
             short matchLength = (short)oxmOut.size();
             closingPadLength = (int)(((matchLength + 4) + 7)/8*8 - (matchLength + 4));
             actionSetFieldHeaderRecord.put("length", getUint16Fixed(matchLength));

          } catch (IOException e1) {
             // TODO Auto-generated catch block
             e1.printStackTrace();
          }     
         
          /*
           * Build closing pad
           */
          ByteBuffer clP = ByteBuffer.allocate(closingPadLength);
    
          /*
           * Assemble action structure
           */
          ofpActionSetFieldRecord.put("header", actionSetFieldHeaderRecord);
          ofpActionSetFieldRecord.put("fields", oxmTlvFieldsRecord);
          ofpActionSetFieldRecord.put("closing_pad", clP);            /*
           * Calculate ofp_instruction_write_actions length
           */
         
          ByteArrayOutputStream actOut = new ByteArrayOutputStream();
          DatumWriter<GenericRecord> actWriter = new GenericDatumWriter<GenericRecord>(ofpActionSetFieldSchema);
          Encoder instrEncoder = EncoderFactory.get().binaryNonEncoder(actOut, null);
        
          try {
             actWriter.write(ofpActionSetFieldRecord, instrEncoder);
             instrEncoder.flush();
            
             Schema uint16Schema = protocol.getType("of12.uint_16");
            
             byte len[] = {(byte)(actOut.size() >> 8), (byte)(255 & actOut.size())};
             GenericData.Fixed lenght = new GenericData.Fixed(uint16Schema, len);
            
             actionSetFieldHeaderRecord.put("length", getUint16Fixed((short)actOut.size()));
             ofpActionSetFieldRecord.put("header", actionSetFieldHeaderRecord);
          } catch (IOException e1) {
             // TODO Auto-generated catch block
             e1.printStackTrace();
          }
      }
      else {
          return null;
      }
     
      ofpActionRecord.put("action", ofpActionSetFieldRecord);
     
      return ofpActionRecord;
  }
 
  private GenericRecord decode_set_field_mpls_label(String subaction) {

     Matcher n;     
    
     Schema ofpActionSchema = protocol.getType("of12.ofp_action");
     GenericRecord ofpActionRecord = new GenericData.Record(ofpActionSchema);
     List <GenericRecord> matches = new ArrayList<>();
    
     Schema actionSetFieldHeaderSchema = protocol.getType("of12.action_set_field_header");
     GenericRecordBuilder headerBuilder = new GenericRecordBuilder(actionSetFieldHeaderSchema);
     GenericRecord actionSetFieldHeaderRecord = headerBuilder.build();
  
     Schema ofpActionSetFieldSchema = protocol.getType("of12.ofp_action_set_field");
     GenericRecord ofpActionSetFieldRecord = new GenericData.Record(ofpActionSetFieldSchema);

     n = Pattern.compile("set_field_mpls_label=(?:((?:0x)?\\d+))").matcher(subaction);
     if (n.matches()) {

         int label = 0;
         if (n.group(1) != null) {
             try {
                 label = getInt(n.group(1));
             }
             catch (NumberFormatException e) {
                // log.debug("  Invalid port in: '{}' (error ignored)", subaction);
                 return null;
             }
         }
        
/*         Schema oxmTlvMplsLabelSchema = protocol.getType("of12.oxm_tlv_mpls_label");
         GenericRecord oxmTlvMplsLabelRecord = new GenericData.Record(oxmTlvMplsLabelSchema);
        
         int oxmTlvHeader = (OXMClass.OFPXMC_OPENFLOW_BASIC.getValue() << 16) |
                            (OXMField.OFPXMT_OFB_MPLS_LABEL.getValue() << 9) |
                            (0 << 8) |
                            3;
        
         oxmTlvMplsLabelRecord.put("header", getUint32Fixed(oxmTlvHeader));
         oxmTlvMplsLabelRecord.put("tlv", getUint24Fixed(label));
        
         Schema oxmTlvSchema = protocol.getType("of12.oxm_tlv");
         GenericRecord oxmTlvRecord = new GenericData.Record(oxmTlvSchema);
         oxmTlvRecord.put("match", oxmTlvMplsLabelRecord);*/
        
         Schema oxmTlvSchema = protocol.getType("of12.oxm_tlv");        
         matches.add(getMatch("of12.oxm_tlv_mpls_label", getUint32Fixed(label)));
        
         GenericArray<GenericRecord> oxmTlvsArray = new GenericData.Array<>(Schema.createArray(oxmTlvSchema), matches);
        
         Schema oxmTlvFieldsSchema = protocol.getType("of12.oxm_tlv_fields");
         GenericRecord oxmTlvFieldsRecord = new GenericData.Record(oxmTlvFieldsSchema);
         oxmTlvFieldsRecord.put("oxm_tlvs", oxmTlvsArray);
        
         /*
          * Calculating oxm_tlvs length
          */
         ByteArrayOutputStream oxmOut = new ByteArrayOutputStream();
         DatumWriter<GenericRecord> oxmWriter = new GenericDatumWriter<GenericRecord>(oxmTlvFieldsSchema);
         Encoder oxmEncoder = EncoderFactory.get().binaryNonEncoder(oxmOut, null);
        
         int closingPadLength = 4;
        
         try {
            oxmWriter.write(oxmTlvFieldsRecord, oxmEncoder);
            oxmEncoder.flush();
           
            short matchLength = (short)oxmOut.size();
            closingPadLength = (int)(((matchLength + 4) + 7)/8*8 - (matchLength + 4));
            actionSetFieldHeaderRecord.put("length", getUint16Fixed(matchLength));

         } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
         }     
        
         /*
          * Build closing pad
          */
         ByteBuffer clP = ByteBuffer.allocate(closingPadLength);
   
         /*
          * Assemble action structure
          */
         ofpActionSetFieldRecord.put("header", actionSetFieldHeaderRecord);
         ofpActionSetFieldRecord.put("fields", oxmTlvFieldsRecord);
         ofpActionSetFieldRecord.put("closing_pad", clP);            /*
          * Calculate ofp_instruction_write_actions length
          */
        
         ByteArrayOutputStream actOut = new ByteArrayOutputStream();
         DatumWriter<GenericRecord> actWriter = new GenericDatumWriter<GenericRecord>(ofpActionSetFieldSchema);
         Encoder instrEncoder = EncoderFactory.get().binaryNonEncoder(actOut, null);
       
         try {
            actWriter.write(ofpActionSetFieldRecord, instrEncoder);
            instrEncoder.flush();
           
            Schema uint16Schema = protocol.getType("of12.uint_16");
           
            byte len[] = {(byte)(actOut.size() >> 8), (byte)(255 & actOut.size())};
            GenericData.Fixed lenght = new GenericData.Fixed(uint16Schema, len);
           
            actionSetFieldHeaderRecord.put("length", getUint16Fixed((short)actOut.size()));
            ofpActionSetFieldRecord.put("header", actionSetFieldHeaderRecord);
         } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
         }
     }
     else {
         return null;
     }
    
     ofpActionRecord.put("action", ofpActionSetFieldRecord);
    
     return ofpActionRecord;
}

   protected int getRecordLength (GenericRecord record, DatumWriter<GenericRecord> writer, Encoder encoder) {
     
      ByteArrayOutputStream temp = new ByteArrayOutputStream();
     
      try {
         writer.write(record, encoder);
         encoder.flush();
      } catch (IOException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      }
     
      return 0;
   }
  
  
   // Parse int as decimal, hex (start with 0x or #) or octal (starts with 0)
   private static long getLong(String str) {
       return (long)Long.decode(str);
   }
  
   // Parse int as decimal, hex (start with 0x or #) or octal (starts with 0)
   private static int getInt(String str) {
       return (int)Integer.decode(str);
   }
  
   private static Long getLong(byte[] buffer) {
      long result = 0;
      for (int i=0; i<8; i++)
         result = (result | buffer[i]) << 8;
     
      return new Long(result);
   }
  
   private static Long getLong(GenericData.Fixed in) {
      long result = 0;
      byte [] buffer = in.bytes();
     
      result |=  ((long)(buffer[7])  & 255);
      result |=  (((long)(buffer[6])  & 255) << 8);
      result |=  (((long)(buffer[5])  & 255) << 16);
      result |=  (((long)(buffer[4])  & 255) << 24);
      result |=  (((long)(buffer[3])  & 255) << 32);
      result |=  (((long)(buffer[2])  & 255) << 40);
      result |=  (((long)(buffer[1])  & 255) << 48);
      result |=  (((long)(buffer[0])  & 255) << 56);
      return new Long(result);
   }

   private static Byte getByte(GenericData.Fixed in) {
      return new Byte(in.bytes()[0]);
   }
  
   private static Short getShort(GenericData.Fixed in) {
      short result = 0;
      byte [] buffer = in.bytes();
     
      result |=  ((long)(buffer[1])  & 255);
      result |=  (((long)(buffer[0])  & 255) << 8);
     
      return new Short(result);
   }


 
   // Parse short as decimal, hex (start with 0x or #) or octal (starts with 0)
   private static short getShort(String str) {
       return (short)(int)Integer.decode(str);
   }
 
   // Parse byte as decimal, hex (start with 0x or #) or octal (starts with 0)
   private static byte getByte(String str) {
       return Integer.decode(str).byteValue();
   }

   private GenericData.Fixed getUint64Fixed (long in) {
      byte temp [] = {(byte)(in >> 56), (byte)(in >> 48), (byte)(in >> 40), (byte)(in >> 32), (byte)(in >> 24),(byte)(in >> 16), (byte)(in >> 8), (byte)(in) };
      GenericData.Fixed out = new GenericData.Fixed(uint_64Schema, temp);
     
      return out;
   }
  
   private GenericData.Fixed getUint48Fixed (long in) {
      byte temp [] = {(byte)(in >> 40), (byte)(in >> 32), (byte)(in >> 24),(byte)(in >> 16), (byte)(in >> 8), (byte)(in) };
      GenericData.Fixed out = new GenericData.Fixed(uint_48Schema, temp);
     
      return out;
   }
  
   private GenericData.Fixed getUint48Fixed (byte in []) {
      return new GenericData.Fixed(uint_48Schema, in);
   }
  
   private GenericData.Fixed getUint128Fixed (byte in []) {
      return new GenericData.Fixed(uint_128Schema, in);
   }
  
   private GenericData.Fixed getUint32Fixed (byte in []) {
      return new GenericData.Fixed(uint_32Schema, in);
   }
  
   private GenericData.Fixed getUint32Fixed (int in) {
      byte temp [] = {(byte)(in >> 24),(byte)(in >> 16), (byte)(in >> 8), (byte)(in) };
      GenericData.Fixed out = new GenericData.Fixed(uint_32Schema, temp);
     
      return out;
   }
  
   private GenericData.Fixed getUint8Fixed (byte in) {
      byte temp [] = {in};
      GenericData.Fixed out = new GenericData.Fixed(uint_8Schema, temp);
     
      return out;
   }
  
   private GenericData.Fixed getPad4 (int in) {
    // TODO Implement based on pad_4 schema 
      return getUint32Fixed(in);
   }
  
   private GenericData.Fixed getPad2 (short in) {
      // TODO Implement based on pad_2 schema   
      return getUint16Fixed(in);
   }
  
   private GenericData.Fixed getPad3 (int in) {
      // TODO Implement based on pad_2 schema   
      return getUint24Fixed(in);
   }
  
  
   private GenericData.Fixed getUint16Fixed (short in) {
      byte temp [] = {(byte)(in >> 8), (byte)(in) };
      GenericData.Fixed out = new GenericData.Fixed(uint_16Schema, temp);
     
      return out;
   }
  
   private GenericData.Fixed getUint24Fixed (int in) {
      byte temp [] = {(byte)(in >> 16), (byte)(in >> 8), (byte)(in) };
      GenericData.Fixed out = new GenericData.Fixed(uint_24Schema, temp);
     
      return out;
   }
  
   private int ipFromCIDR(String cidr, String which)
         throws IllegalArgumentException {
     String values[] = cidr.split("/");
     String[] ip_str = values[0].split("\\.");
     int ip = 0;
     ip += Integer.valueOf(ip_str[0]) << 24;
     ip += Integer.valueOf(ip_str[1]) << 16;
     ip += Integer.valueOf(ip_str[2]) << 8;
     ip += Integer.valueOf(ip_str[3]);
     int prefix = 32; // all bits are fixed, by default

     if (values.length >= 2)
         prefix = Integer.valueOf(values[1]);
     int mask = 32 - prefix;
    
     return ip;
   }
  
   private static byte[] get_mac_addr(String in) {
      byte[] macaddr = new byte[6];
     
      Matcher n = Pattern.compile("(?:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+))").matcher(in);
     
      if (n.matches()) {
         for (int i=0; i<6; i++) {
            if (n.group(i+1) != null) {
                try {
                    macaddr[i] = getByte("0x" + n.group(i+1));
                }
                catch (NumberFormatException e) {
           //         log.debug("  Invalid src-mac in: '{}' (error ignored)", subaction);
                    return null;
                }
            }
            else {
           //     log.debug("  Invalid src-mac in: '{}' (null, error ignored)", subaction);
                return null;
            }
        }
      } else
         return null;

      return macaddr;
  }
  
  private static byte[] get_ipv6(String in) {
      byte[] ipv6 = new byte[16];
     
      Matcher n = Pattern.compile("(?:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+))").matcher(in);
     
      if (n.matches()) {
         for (int i=0; i<8; i++) {
            if (n.group(i+1) != null) {
                try {
                   ipv6[2*i] = (byte) (getShort("0x" + n.group(i+1)) & 255);
                   ipv6[2*i+1] = (byte) (getShort("0x" + n.group(i+1)) >> 8);
                }
                catch (NumberFormatException e) {
                    return null;
                }
            }
            else {
                return null;
            }
        }
      } else
         return null;

      return ipv6;
  }
 
  private static byte[] get_ipv4(String in) {
     byte[] ipv4 = new byte[4];
    
     Matcher n = Pattern.compile("(?:(\\p{XDigit}+)\\.(\\p{XDigit}+)\\.(\\p{XDigit}+)\\.(\\p{XDigit}+))").matcher(in);
    
     if (n.matches()) {
        for (int i=0; i<4; i++) {
           if (n.group(i+1) != null) {
               try {
                  ipv4[i] = getByte(n.group(i+1));
               }
               catch (NumberFormatException e) {
                   return null;
               }
           }
           else {
               return null;
           }
       }
     } else
        return null;

     return ipv4;
  }
 
  private GenericRecord getMatch (String schemaName, GenericFixed tlv) {
    
     Schema oxmTlvFieldSchema = protocol.getType(schemaName);
     GenericRecord oxmTlvFieldRecord = new GenericData.Record(oxmTlvFieldSchema);

     oxmTlvFieldRecord.put("tlv", tlv);
    
     Schema oxmTlvSchema = protocol.getType("of12.oxm_tlv");
     GenericRecord oxmTlvRecord = new GenericData.Record(oxmTlvSchema);
     oxmTlvRecord.put("match", oxmTlvFieldRecord);
    
     return oxmTlvRecord;
    
  }
 
  private short calculateLength (Schema schema, GenericRecord record) {
    
     ByteArrayOutputStream buf = new ByteArrayOutputStream();
    
     DatumWriter<GenericRecord> instrWriter = new GenericDatumWriter<GenericRecord>(schema);
     Encoder encoder = EncoderFactory.get().binaryNonEncoder(buf, null);
   
     try {
        instrWriter.write(record, encoder);
        encoder.flush();
       
     } catch (IOException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
     }
    
     return (short)buf.size();
  }
 
  private void reset () {
     delayedIpv4Src = null;
     delayedIpv4Dst = null;
     delayedIpv6Src = null;
     delayedIpv6Dst = null;
     delayedIpProto = null;
     delayedTcpSrc = null;
     delayedTcpDst = null;
     delayedUdpSrc = null;
     delayedUdpDst = null;
     isEtherType = false;
     isIpProto = false;
     isVlanVid = false;
  }

/* (non-Javadoc)
* @see org.flowforwarding.warp.controller.protocol.OFMessageProvider#isHello(byte[])
*/
@Override
public boolean isHello(byte[] in) {
   return true;
}

/* (non-Javadoc)
* @see org.flowforwarding.warp.controller.protocol.OFMessageProvider#getVersion()
*/
@Override
public Short getVersion() {
   return 4;
}

/* (non-Javadoc)
* @see org.flowforwarding.warp.protocol.ofmessages.IOFMessageProvider#isConfig(byte[])
*/
@Override
public boolean isConfig(byte[] in) {
/*   GenericRecord header = getRecord(this.ofpHeaderSchema, in);
   Fixed msgType = (Fixed)header.get("type");
  
   // TODO Improv: get rid of this Type Cast: (OFItemEnumBuilder) builders

   AvroEnumBuilder builder = (AvroEnumBuilder) builders.get("ofp_type");
   AvroEnum enumItem = (AvroEnum) builder.build(msgType);
  
   if (enumItem.getName().equalsIgnoreCase("OFPT_GET_CONFIG_REPLY"))  // OFPT_GET_CONFIG_REPLY
      return true;
   else*/
      return false;
}

/* (non-Javadoc)
* @see org.flowforwarding.warp.protocol.ofmessages.IOFMessageProvider#parseSwitchConfig(byte[])
*/
@Override
public OFMessageSwitchConfigRef parseSwitchConfig(byte[] in) {
   GenericRecord record = getSwitchConfigRecord(in);
  
// TODO Improvs: We plan to get all flags from Avro protocol type... soon... so let it be now just numbers
   short flags = getShort((GenericData.Fixed)record.get("flags"));
   OFMessageSwitchConfigRef configH = builder12.buildSwitchConfig();
   if (flags == 0) {
      configH.setConfigFlagFragNormal();
   } else {
      if ((flags & 1) != 0) configH.setConfigFlagFragDrop();
      if ((flags & 2) != 0) configH.setConfigFlagFragReasm();
      if ((flags & 3) != 0) configH.setConfigFlagFragMask();
   }
  
   return configH;
}

@Override
public OFMessageErrorRef parseError(byte[] in) {
   GenericRecord record = getRecord(ofpErrorMessageSchema, in);
  
// TODO Improvs: We plan to get all flags from Avro protocol type... soon... so let it be now just numbers
   short type = getShort((GenericData.Fixed)record.get("type"));
   short code = getShort((GenericData.Fixed)record.get("code"));
   OFMessageErrorRef errorH = builder12.buildError();
  
   errorH.setCode(code);
   errorH.setType(type);
  
   return errorH;
}

/* (non-Javadoc)
* @see org.flowforwarding.warp.protocol.ofmessages.IOFMessageProvider#isPacketIn(byte[])
*/
@Override
public boolean isPacketIn(byte[] in) {
   GenericRecord header = getRecord(packetInHeaderSchema, in);

   // TODO Improvs: We plan to get all types from Avro protocol type... soon... so let it be now just 10
   Byte type = getByte((GenericData.Fixed)header.get("type"));
   if (type.byteValue() == 10 // OFPT_PACKET_IN
      return true;
   else
      return false;
}

/* (non-Javadoc)
* @see org.flowforwarding.warp.protocol.ofmessages.IOFMessageProvider#parsePacketIn(byte[])
*/
@Override
public OFMessagePacketInRef parsePacketIn(byte[] in) {
   return builder12.buildPacketIn();
}

/* (non-Javadoc)
* @see org.flowforwarding.warp.protocol.ofmessages.IOFMessageProvider#isError(byte[])
*/
@Override
public boolean isError(byte[] in) {
  
   /*GenericRecord header = getRecord(this.ofpHeaderSchema, in);
   Fixed msgType = (Fixed)header.get("type");
  
   // TODO Improv: get rid of this Type Cast: (OFItemEnumBuilder) builders
   AvroEnumBuilder builder = (AvroEnumBuilder) builders.get("ofp_type");
   AvroEnum enumItem = (AvroEnum) builder.build(msgType);
  
   if (enumItem.getName().equalsIgnoreCase("OFPT_ERROR"))
      return true;
   else*/
      return false;
}

   @Override
   public boolean isSwitchFeatures(byte[] in) {
      /*GenericRecord header = getRecord(this.ofpHeaderSchema, in);
      Fixed msgType = (Fixed)header.get("type");
     
      // TODO Improv: get rid of this Type Cast: (OFItemEnumBuilder) builders
      AvroEnumBuilder builder = (AvroEnumBuilder) builders.get("ofp_type");
      AvroEnum enumItem = (AvroEnum) builder.build(msgType);
     
      if (enumItem.getName().equalsIgnoreCase("OFPT_FEATURES_REPLY"))
         return true;
      else
         */return false;  
   }
  
   @Override
   public boolean isEchoRequest(byte[] in) {
     /* GenericRecord header = getRecord(this.ofpHeaderSchema, in);
      Fixed msgType = (Fixed)header.get("type");
     
      // TODO Improv: get rid of this Type Cast: (OFItemEnumBuilder) builders
      AvroEnumBuilder builder = (AvroEnumBuilder) builders.get("ofp_type");
      AvroEnum enumItem = (AvroEnum) builder.build(msgType);
     
      if (enumItem.getName().equalsIgnoreCase("OFPT_ECHO_REQUEST"))
         return true;
      else
         */return false;
   }
  
@Override
public boolean isMessage (Schema headerSchema, byte[] in) {
   GenericRecord header = getRecord(headerSchema, in);

   // TODO Improvs: We plan to get all types from Avro protocol type... soon... so let it be now just 1
   Byte type = getByte((GenericData.Fixed)header.get("type"));
   if (type.byteValue() == 1 // ERROR
      return true;
   else
      return false;
}

@Override
public List<OFMessageRef> parseMessages(byte[] in) {
   System.out.println("[OF-INFO]: parseMessages - Entering ");
   GenericRecord header = getRecord(ofpHeaderSchema, in);
  
   Byte type = getByte((GenericData.Fixed)header.get("type"));
   Short length = getShort((GenericData.Fixed)header.get("length"));
  
   System.out.println("[OF-INFO]: Message type - " + type);
  
   List<OFMessageRef> messageList = new ArrayList<OFMessageRef> ();
  
   // TODO Improvs: We plan to get all types from Avro protocol type... soon... so let it be now just numbers
   switch (type) {
   case 0:
      System.out.println("[OF-INFO]: HELLO message");
      messageList.add(parseHelloMessage(in));
      break;
   default:
      break;
   }
   return messageList;
}

@Override
public OFMessageHelloRef parseHelloMessage(byte[] in) {

   return OFMessageHelloRef.create();
}
}
TOP

Related Classes of org.flowforwarding.warp.protocol.ofmessages.OFMessageProvider12AvroProtocol$MatchEntry

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.