/* * Appends its action(set_nw_src) to the list of actions. * * @return [ActionSetNwSrc] self */ static VALUE action_set_nw_src_append( VALUE self, VALUE action_ptr ) { openflow_actions *actions; Data_Get_Struct( action_ptr, openflow_actions, actions ); append_action_set_nw_src( actions, nw_addr_to_i( action_get_nw_src( self ) ) ); 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; }
static uint32_t ip_addr_to_i( VALUE ip_addr ) { return nw_addr_to_i( ip_addr ); }
static void append_action( openflow_actions *actions, VALUE action ) { if ( rb_funcall( action, rb_intern( "is_a?" ), 1, rb_path2class( "Trema::Enqueue" ) ) == Qtrue ) { uint32_t queue_id = ( uint32_t ) NUM2UINT( rb_funcall( action, rb_intern( "queue_id" ), 0 ) ); uint16_t port_number = ( uint16_t ) NUM2UINT( rb_funcall( action, rb_intern( "port_number" ), 0 ) ); append_action_enqueue( actions, port_number, queue_id ); } else if ( rb_funcall( action, rb_intern( "is_a?" ), 1, rb_path2class( "Trema::SendOutPort" ) ) == Qtrue ) { uint16_t port_number = ( uint16_t ) NUM2UINT( rb_funcall( action, rb_intern( "port_number" ), 0 ) ); uint16_t max_len = ( uint16_t ) NUM2UINT( rb_funcall( action, rb_intern( "max_len" ), 0 ) ); append_action_output( actions, port_number, max_len ); } else if ( rb_funcall( action, rb_intern( "is_a?" ), 1, rb_path2class( "Trema::SetEthDstAddr" ) ) == Qtrue ) { uint8_t dl_dst[ OFP_ETH_ALEN ]; uint8_t *ptr = ( uint8_t * ) dl_addr_to_a( rb_funcall( action, rb_intern( "mac_address" ), 0 ), dl_dst ); append_action_set_dl_dst( actions, ptr ); } else if ( rb_funcall( action, rb_intern( "is_a?" ), 1, rb_path2class( "Trema::SetEthSrcAddr" ) ) == Qtrue ) { uint8_t dl_src[ OFP_ETH_ALEN ]; uint8_t *ptr = ( uint8_t * ) dl_addr_to_a( rb_funcall( action, rb_intern( "mac_address" ), 0 ), dl_src ); append_action_set_dl_src( actions, ptr ); } else if ( rb_funcall( action, rb_intern( "is_a?" ), 1, rb_path2class( "Trema::SetIpDstAddr" ) ) == Qtrue ) { append_action_set_nw_dst( actions, nw_addr_to_i( rb_funcall( action, rb_intern( "ip_address" ), 0 ) ) ); } else if ( rb_funcall( action, rb_intern( "is_a?" ), 1, rb_path2class( "Trema::SetIpSrcAddr" ) ) == Qtrue ) { append_action_set_nw_src( actions, nw_addr_to_i( rb_funcall( action, rb_intern( "ip_address" ), 0 ) ) ); } else if ( rb_funcall( action, rb_intern( "is_a?" ), 1, rb_path2class( "Trema::SetIpTos" ) ) == Qtrue ) { append_action_set_nw_tos( actions, ( uint8_t ) NUM2UINT( rb_funcall( action, rb_intern( "type_of_service" ), 0 ) ) ); } else if ( rb_funcall( action, rb_intern( "is_a?" ), 1, rb_path2class( "Trema::SetTransportDstPort" ) ) == Qtrue ) { append_action_set_tp_dst( actions, ( uint16_t ) NUM2UINT( rb_funcall( action, rb_intern( "port_number" ), 0 ) ) ); } else if ( rb_funcall( action, rb_intern( "is_a?" ), 1, rb_path2class( "Trema::SetTransportSrcPort" ) ) == Qtrue ) { append_action_set_tp_src( actions, ( uint16_t ) NUM2UINT( rb_funcall( action, rb_intern( "port_number" ), 0 ) ) ); } else if ( rb_funcall( action, rb_intern( "is_a?" ), 1, rb_path2class( "Trema::SetVlanPriority" ) ) == Qtrue ) { append_action_set_vlan_pcp( actions, ( uint8_t ) NUM2UINT( rb_funcall( action, rb_intern( "vlan_priority" ), 0 ) ) ); } else if ( rb_funcall( action, rb_intern( "is_a?" ), 1, rb_path2class( "Trema::SetVlanVid" ) ) == Qtrue ) { append_action_set_vlan_vid( actions, ( uint16_t ) NUM2UINT( rb_funcall( action, rb_intern( "vlan_id" ), 0 ) ) ); } else if ( rb_funcall( action, rb_intern( "is_a?" ), 1, rb_path2class( "Trema::StripVlanHeader" ) ) == Qtrue ) { append_action_strip_vlan( actions ); } else if ( rb_funcall( action, rb_intern( "is_a?" ), 1, rb_path2class( "Trema::VendorAction" ) ) == Qtrue ) { VALUE vendor_id = rb_funcall( action, rb_intern( "vendor_id" ), 0 ); VALUE rbody = rb_funcall( action, rb_intern( "body" ), 0 ); if ( rbody != Qnil ) { Check_Type( rbody, T_ARRAY ); uint16_t length = ( uint16_t ) RARRAY_LEN( rbody ); buffer *body = alloc_buffer_with_length( length ); void *p = append_back_buffer( body, length ); for ( int i = 0; i < length; i++ ) { ( ( uint8_t * ) p )[ i ] = ( uint8_t ) FIX2INT( RARRAY_PTR( rbody )[ i ] ); } append_action_vendor( actions, ( uint32_t ) NUM2UINT( vendor_id ), body ); free_buffer( body ); } else { append_action_vendor( actions, ( uint32_t ) NUM2UINT( vendor_id ), NULL ); } } else { rb_raise( rb_eTypeError, "actions argument must be an Array of Action objects" ); } }