/* * A {PortMod} instance a request object to perform operations on a physical port. * * @overload initialize(options={}) * @example * PortMod.new( * :port_no => 1, * :hw_addr => "11:22:33:44:55:66", * :config => 1, * :mask => 1, * :advertise => 0 * ) * * @param [Hash] options * the options to create a message with. * * @param [Number] :port_no * an index into datapath's ports list. * * @param [String,Number,Trema::Mac] :hw_addr * the hardware address of a port. * Unique for each port. Obtained from +OFPT_FEATURES_REPLY+ message. * Can be supplied as a string, number or as a Mac object. * * @param [Number] :config * a bitmap that can be set to configure a port. * * @param [Number] :mask * set the bits of the +config+ flag to change. * * @param [Number] :advertise * bitmap of +ofp_port_features+ set to zero to prevent * any changes. Or can be copied from +OFPT_FEATURES_REPLY+ message. * * @return [PortMod] * an object that encapsulates the +OFPT_PORT_MOD+ OpenFlow message. */ static VALUE port_mod_init( int argc, VALUE *argv, VALUE self ) { VALUE options; if ( rb_scan_args( argc, argv, "01", &options ) == 1 ) { Check_Type( options, T_HASH ); buffer *port_mod; Data_Get_Struct( self, buffer, port_mod ); VALUE mac; VALUE hw_addr; uint8_t *ptr; uint8_t haddr[ OFP_ETH_ALEN ]; if ( ( hw_addr = rb_hash_aref( options, ID2SYM( rb_intern( "hw_addr" ) ) ) ) != Qnil ) { mac = hw_addr; if ( rb_obj_is_kind_of( hw_addr, rb_cString ) == Qtrue || rb_obj_is_kind_of( hw_addr, rb_cInteger ) == Qtrue ) { mac = rb_funcall( rb_eval_string( "Trema::Mac" ), rb_intern( "new" ), 1, hw_addr ); } else if ( rb_obj_is_instance_of( hw_addr, rb_eval_string( "Trema::Mac" ) ) == Qfalse ) { rb_raise( rb_eArgError, "hw_addr must be a string or an integer or Mac object" ); } ptr = ( uint8_t* ) dl_addr_short( mac, haddr ); rb_iv_set( self, "@hw_addr", mac ); } VALUE port_no; if ( ( port_no = rb_hash_aref( options, ID2SYM( rb_intern( "port_no" ) ) ) ) != Qnil ) { if ( rb_funcall( port_no, rb_intern( "unsigned_16bit?" ), 0 ) == Qfalse ) { rb_raise( rb_eArgError, "Port number must be an unsigned 16-bit integer" ); } rb_iv_set( self, "@port_no", port_no ); } VALUE config; if ( ( config = rb_hash_aref( options, ID2SYM( rb_intern( "config" ) ) ) ) != Qnil ){ rb_iv_set( self, "@config", config ); } VALUE mask; if ( ( mask = rb_hash_aref( options, ID2SYM( rb_intern( "mask" ) ) ) ) != Qnil ){ rb_iv_set( self, "@mask", mask ); } VALUE advertise; if ( ( advertise = rb_hash_aref( options, ID2SYM( rb_intern( "advertise" ) ) ) ) != Qnil ){ rb_iv_set( self, "@advertise", advertise ); } uint32_t xid = get_transaction_id(); rb_iv_set( self, "@transaction_id", UINT2NUM( xid ) ); ( ( struct ofp_header * ) ( port_mod->data ) )->xid = htonl( xid ); ( ( struct ofp_port_mod * ) ( port_mod->data ) )->port_no = htons( ( uint16_t ) NUM2UINT( port_no ) ); memcpy( ( ( struct ofp_port_mod * ) ( port_mod->data ) )->hw_addr, ptr, OFP_ETH_ALEN ); ( ( struct ofp_port_mod * ) ( port_mod->data ) )->config = htonl( ( uint32_t ) NUM2UINT( config ) ); ( ( struct ofp_port_mod * ) ( port_mod->data ) )->mask = htonl( ( uint32_t ) NUM2UINT( mask ) ); ( ( struct ofp_port_mod * ) ( port_mod->data ) )->advertise = htonl( ( uint32_t ) NUM2UINT( advertise ) ); } else { rb_raise( rb_eArgError, "Port no, hw_addr, config, mask, advertise are mandatory options" ); } return self; }
/* * Appends its action(set_dl_src) to the list of actions. * * @return [ActionSetDlSrc] self */ static VALUE action_set_dl_src_append( VALUE self, VALUE action_ptr ) { openflow_actions *actions; Data_Get_Struct( action_ptr, openflow_actions, actions ); uint8_t dl_src[ OFP_ETH_ALEN ]; uint8_t *ptr; ptr = ( uint8_t* ) dl_addr_short( action_get_dl_src( self ), dl_src ); append_action_set_dl_src( actions, ptr ); return self; }
/* * Creates a {Match} instance which describe fields such as MAC addresses, IP * addresses, TCP/UDP ports of a flow to match against. An exact match * flow would match on all fields whereas don't care bits are wildcarded and * ignored. * * @overload initialize(options={}) * * @example * Match.new( * :in_port => port_no, * :dl_src => "xx:xx:xx;xx:xx:xx", * :dl_dst => "xx:xx:xx:xx:xx:xx", * :dl_type => ethertype, * :dl_vlan => vlan, * :dl_vlan_pcp => priority, * :nw_tos => tos, * :nw_proto => proto, * :nw_src => ip_address/netmask, * :nw_dst => ip_address/netmask, * :tp_src => port, * :tp_dst => port, * ) * * @param [Hash] options the options hash. * * @option options [Symbol] :inport * the physical port number to match. * * @option options [Symbol] :dl_src * the source ethernet address to match specified either as 6 pairs of * hexadecimal digits delimited by colon or as a hexadecimal number. * (eg. "00:11:22:33:44:55" or 0x001122334455). * * @option options [Symbol] :dl_dst * the destination ethernet address to match specified either as a 6 pairs of * hexadecimal digits delimited by colon or as a hexadecimal number. * (eg. "00:11:22:33:44:55" or 0x001122334455). * * @option options [Symbol] :dl_type * the Ethernet protocol type to match. Can be specified either as a decimal * or hexadecimal number. (eg 0x0800 to match IP packets, 0x08006 to match * ARP packets, 0x88cc for LLDP packets). * * @option options [Symbol] :dl_vlan * the IEEE 802.1q virtual VLAN tag to match specified as a 12-bit number * 0 to 4095 inclusive. * * @option options [Symbol] :dl_vlan_pcp * the IEEE 802.1q Priority Code Point (PCP) to match specified as a value of * 0 to 7 inclusive. A higher value indicates a higher priority frame. * * @option options [Symbol] :nw_tos * the IP ToS/DSCP field to match specified as a decimal number between 0 and * 255 inclusive. * * @option options [Symbol] :nw_proto * Depending on the dl_type the IP protocol type to match. (eg if dl_type * equals 0x0800 UDP packets can be match by setting nw_proto to 17.) * to match TCP packets). When dl_type = 0x0806 is set to arp it matches the * lower 8 bits of the ARP opcode. * * @option options [Symbol] :nw_src * the IPv4 source address to match if dl_type is set to 0x0800. * * @option options [Symbol] :nw_dst * the IPv4 destination address to match if dl_type is set to 0x0800. * * @option options [Symbol] :tp_src * the source TCP/UDP port number to match specified as a decimal number * between 0 and 65535 inclusive. The value dl_type and nw_proto must be set * to specify TCP or UDP. * * @option options [Symbol] :tp_dst * the destination TCP/UDP port number to match specified as a decimal number * between 0 and 65535 inclusive. * * @return [Match] self * an object that encapsulates and wraps the +struct ofp_match+ */ static VALUE match_init( int argc, VALUE *argv, VALUE self ) { struct ofp_match *match; VALUE options; // Always clear the memory as the unused memory locations are // exposed to both the user and the OpenFlow controller. Data_Get_Struct( self, struct ofp_match, match ); memset( match, 0, sizeof ( *match ) ); // Default matches all packets. match->wildcards = ( OFPFW_ALL & ~( OFPFW_NW_SRC_MASK | OFPFW_NW_DST_MASK ) ) | OFPFW_NW_SRC_ALL | OFPFW_NW_DST_ALL; if ( rb_scan_args( argc, argv, "01", &options ) >= 1 ) { if ( options != Qnil ) { VALUE in_port = rb_hash_aref( options, ID2SYM( rb_intern( "in_port" ) ) ); if ( in_port != Qnil ) { match->in_port = ( uint16_t ) NUM2UINT( in_port ); match->wildcards &= ( uint32_t ) ~OFPFW_IN_PORT; } VALUE dl_src = rb_hash_aref( options, ID2SYM( rb_intern( "dl_src" ) ) ); if ( dl_src != Qnil ) { VALUE dl_addr = rb_funcall( rb_eval_string( "Trema::Mac" ), rb_intern( "new" ), 1, dl_src ); dl_addr_short( dl_addr, match->dl_src ); match->wildcards &= ( uint32_t ) ~OFPFW_DL_SRC; } VALUE dl_dst = rb_hash_aref( options, ID2SYM( rb_intern( "dl_dst" ) ) ); if ( dl_dst != Qnil ) { VALUE dl_addr = rb_funcall( rb_eval_string( "Trema::Mac" ), rb_intern( "new" ), 1, dl_dst ); dl_addr_short( dl_addr, match->dl_dst ); match->wildcards &= ( uint32_t ) ~OFPFW_DL_DST; } VALUE dl_type = rb_hash_aref( options, ID2SYM( rb_intern( "dl_type" ) ) ); if ( dl_type != Qnil ) { match->dl_type = ( uint16_t ) NUM2UINT( dl_type ); match->wildcards &= ( uint32_t ) ~OFPFW_DL_TYPE; } VALUE dl_vlan = rb_hash_aref( options, ID2SYM( rb_intern( "dl_vlan" ) ) ); if ( dl_vlan != Qnil ) { match->dl_vlan = ( uint16_t ) NUM2UINT( dl_vlan ); match->wildcards &= ( uint32_t ) ~OFPFW_DL_VLAN; } VALUE dl_vlan_pcp = rb_hash_aref( options, ID2SYM( rb_intern( "dl_vlan_pcp" ) ) ); if ( dl_vlan_pcp != Qnil ) { match->dl_vlan_pcp = ( uint8_t ) NUM2UINT( dl_vlan_pcp ); match->wildcards &= ( uint32_t ) ~OFPFW_DL_VLAN_PCP; } VALUE nw_tos = rb_hash_aref( options, ID2SYM( rb_intern( "nw_tos" ) ) ); if ( nw_tos != Qnil ) { match->nw_tos = ( uint8_t ) NUM2UINT( nw_tos ); match->wildcards &= ( uint32_t ) ~OFPFW_NW_TOS; } VALUE nw_proto = rb_hash_aref( options, ID2SYM( rb_intern( "nw_proto" ) ) ); if ( nw_proto != Qnil ) { match->nw_proto = ( uint8_t ) NUM2UINT( nw_proto ); match->wildcards &= ( uint32_t ) ~OFPFW_NW_PROTO; } VALUE nw_src = rb_hash_aref( options, ID2SYM( rb_intern( "nw_src" ) ) ); if ( nw_src != Qnil ) { VALUE nw_addr = rb_funcall( rb_eval_string( "Trema::IP" ), rb_intern( "new" ), 1, nw_src ); match->nw_src = nw_addr_to_i( nw_addr ); match->wildcards &= ( uint32_t ) ~OFPFW_NW_SRC_MASK; } VALUE nw_dst = rb_hash_aref( options, ID2SYM( rb_intern( "nw_dst" ) ) ); if ( nw_dst != Qnil ) { VALUE nw_addr = rb_funcall( rb_eval_string( "Trema::IP" ), rb_intern( "new" ), 1, nw_dst ); match->nw_dst = nw_addr_to_i( nw_addr ); match->wildcards &= ( uint32_t ) ~OFPFW_NW_DST_MASK; } VALUE tp_src = rb_hash_aref( options, ID2SYM( rb_intern( "tp_src" ) ) ); if ( tp_src != Qnil ) { match->tp_src = ( uint16_t ) NUM2UINT( tp_src ); match->wildcards &= ( uint32_t ) ~OFPFW_TP_SRC; } VALUE tp_dst = rb_hash_aref( options, ID2SYM( rb_intern( "tp_dst" ) ) ); if ( tp_dst != Qnil ) { match->tp_dst = ( uint16_t ) NUM2UINT( tp_dst ); match->wildcards &= ( uint32_t ) ~OFPFW_TP_DST; } } } return self; }