static void do_flooding( packet_in packet_in, uint32_t in_port ) { openflow_actions *actions = create_actions(); append_action_output( actions, OFPP_ALL, OFPCML_NO_BUFFER ); buffer *packet_out; if ( packet_in.buffer_id == OFP_NO_BUFFER ) { buffer *frame = duplicate_buffer( packet_in.data ); fill_ether_padding( frame ); packet_out = create_packet_out( get_transaction_id(), packet_in.buffer_id, in_port, actions, frame ); free_buffer( frame ); } else { packet_out = create_packet_out( get_transaction_id(), packet_in.buffer_id, in_port, actions, NULL ); } send_openflow_message( packet_in.datapath_id, packet_out ); free_buffer( packet_out ); delete_actions( actions ); }
static void do_flooding( packet_in packet_in ) { openflow_actions *actions = create_actions(); append_action_output( actions, OFPP_FLOOD, UINT16_MAX ); buffer *packet_out; if ( packet_in.buffer_id == UINT32_MAX ) { buffer *frame = duplicate_buffer( packet_in.data ); fill_ether_padding( frame ); packet_out = create_packet_out( get_transaction_id(), packet_in.buffer_id, packet_in.in_port, actions, frame ); free_buffer( frame ); } else { packet_out = create_packet_out( get_transaction_id(), packet_in.buffer_id, packet_in.in_port, actions, NULL ); } send_openflow_message( packet_in.datapath_id, packet_out ); free_buffer( packet_out ); delete_actions( actions ); }
bool send_lldp( probe_timer_entry *port ) { buffer *lldp; lldp = create_lldp_frame( port->mac, port->datapath_id, port->port_no ); openflow_actions *actions = create_actions(); if ( !append_action_output( actions, port->port_no, UINT16_MAX ) ) { free_buffer( lldp ); error( "Failed to sent LLDP frame(%#" PRIx64 ", %u)", port->datapath_id, port->port_no ); return false; } uint32_t transaction_id = get_transaction_id(); buffer *packetout = create_packet_out( transaction_id, UINT32_MAX, OFPP_NONE, actions, lldp ); if ( !send_openflow_message( port->datapath_id, packetout ) ) { free_buffer( lldp ); free_buffer( packetout ); delete_actions( actions ); die( "send_openflow_message" ); } free_buffer( lldp ); free_buffer( packetout ); delete_actions( actions ); debug( "Sent LLDP frame(%#" PRIx64 ", %u)", port->datapath_id, port->port_no ); return true; }
static void handle_packet_in( uint64_t datapath_id, packet_in message ) { if ( message.data == NULL ) { error( "data must not be NULL" ); return; } uint32_t in_port = get_in_port_from_oxm_matches( message.match ); if ( in_port == 0 ) { return; } openflow_actions *actions = create_actions(); append_action_output( actions, OFPP_ALL, OFPCML_NO_BUFFER ); openflow_instructions *insts = create_instructions(); append_instructions_apply_actions( insts, actions ); oxm_matches *match = create_oxm_matches(); set_match_from_packet( match, in_port, 0, message.data ); buffer *flow_mod = create_flow_mod( get_transaction_id(), get_cookie(), 0, 0, OFPFC_ADD, 60, 0, OFP_HIGH_PRIORITY, message.buffer_id, 0, 0, OFPFF_SEND_FLOW_REM, match, insts ); send_openflow_message( datapath_id, flow_mod ); free_buffer( flow_mod ); delete_oxm_matches( match ); delete_instructions( insts ); if ( message.buffer_id == OFP_NO_BUFFER ) { buffer *frame = duplicate_buffer( message.data ); fill_ether_padding( frame ); buffer *packet_out = create_packet_out( get_transaction_id(), message.buffer_id, in_port, actions, frame ); send_openflow_message( datapath_id, packet_out ); free_buffer( packet_out ); free_buffer( frame ); } delete_actions( actions ); }
static void send_packet( uint32_t destination_port, packet_in packet_in, uint32_t in_port ) { openflow_actions *actions = create_actions(); append_action_output( actions, destination_port, OFPCML_NO_BUFFER ); openflow_instructions *insts = create_instructions(); append_instructions_apply_actions( insts, actions ); oxm_matches *match = create_oxm_matches(); set_match_from_packet( match, in_port, NULL, packet_in.data ); buffer *flow_mod = create_flow_mod( get_transaction_id(), get_cookie(), 0, 0, OFPFC_ADD, 60, 0, OFP_HIGH_PRIORITY, packet_in.buffer_id, 0, 0, OFPFF_SEND_FLOW_REM, match, insts ); send_openflow_message( packet_in.datapath_id, flow_mod ); free_buffer( flow_mod ); delete_oxm_matches( match ); delete_instructions( insts ); if ( packet_in.buffer_id == OFP_NO_BUFFER ) { buffer *frame = duplicate_buffer( packet_in.data ); fill_ether_padding( frame ); buffer *packet_out = create_packet_out( get_transaction_id(), packet_in.buffer_id, in_port, actions, frame ); send_openflow_message( packet_in.datapath_id, packet_out ); free_buffer( packet_out ); free_buffer( frame ); } delete_actions( actions ); }
static void send_packet_out( packet_in packet_in, openflow_actions *actions ) { buffer *frame = duplicate_buffer( packet_in.data ); fill_ether_padding( frame ); buffer *packet_out = create_packet_out( get_transaction_id(), UINT32_MAX, packet_in.in_port, actions, frame ); free_buffer( frame ); send_openflow_message( packet_in.datapath_id, packet_out ); free_buffer( packet_out ); }
static void output_packet( buffer *packet, uint64_t dpid, uint16_t port_no ) { openflow_actions *actions = create_actions(); const uint16_t max_len = UINT16_MAX; append_action_output( actions, port_no, max_len ); const uint32_t transaction_id = get_transaction_id(); const uint32_t buffer_id = UINT32_MAX; const uint16_t in_port = OFPP_NONE; fill_ether_padding( packet ); buffer *packet_out = create_packet_out( transaction_id, buffer_id, in_port, actions, packet ); send_openflow_message( dpid, packet_out ); free_buffer( packet_out ); delete_actions( actions ); }
static void send_packet_out( uint64_t datapath_id, packet_in *message, uint16_t out_port ) { uint32_t buffer_id = message->buffer_id; uint16_t in_port = message->in_port; if ( datapath_id != message->datapath_id ) { buffer_id = UINT32_MAX; in_port = OFPP_NONE; } openflow_actions *actions = create_actions(); append_action_output( actions, out_port, UINT16_MAX ); const buffer *data = NULL; if ( buffer_id == UINT32_MAX ) { data = message->data; } buffer *packet_out = create_packet_out( get_transaction_id(), buffer_id, in_port, actions, data ); delete_actions( actions ); send_openflow_message( datapath_id, packet_out ); free_buffer( packet_out ); }
static void send_packet( uint16_t destination_port, packet_in packet_in ) { openflow_actions *actions = create_actions(); append_action_output( actions, destination_port, UINT16_MAX ); struct ofp_match match; set_match_from_packet( &match, packet_in.in_port, 0, packet_in.data ); buffer *flow_mod = create_flow_mod( get_transaction_id(), match, get_cookie(), OFPFC_ADD, 60, 0, UINT16_MAX, packet_in.buffer_id, OFPP_NONE, OFPFF_SEND_FLOW_REM, actions ); send_openflow_message( packet_in.datapath_id, flow_mod ); free_buffer( flow_mod ); if ( packet_in.buffer_id == UINT32_MAX ) { buffer *frame = duplicate_buffer( packet_in.data ); fill_ether_padding( frame ); buffer *packet_out = create_packet_out( get_transaction_id(), packet_in.buffer_id, packet_in.in_port, actions, frame ); send_openflow_message( packet_in.datapath_id, packet_out ); free_buffer( packet_out ); free_buffer( frame ); } delete_actions( actions ); }
static void send_packet_out_for_each_switch( switch_info *sw, buffer *packet, uint64_t dpid, uint16_t in_port ) { openflow_actions *actions = create_actions(); int number_of_actions = foreach_port( sw->ports, build_packet_out_actions, actions, dpid, in_port ); // check if no action is build if ( number_of_actions > 0 ) { const uint32_t transaction_id = get_transaction_id(); const uint32_t buffer_id = UINT32_MAX; const uint16_t in_port = OFPP_NONE; fill_ether_padding( packet ); buffer *packet_out = create_packet_out( transaction_id, buffer_id, in_port, actions, packet ); send_openflow_message( sw->dpid, packet_out ); free_buffer( packet_out ); } delete_actions( actions ); }
static void send_packet_out( uint64_t datapath_id, openflow_actions *actions, const buffer *original ) { const uint32_t transaction_id = get_transaction_id(); const uint32_t buffer_id = UINT32_MAX; const uint16_t in_port = OFPP_NONE; buffer *copy = NULL; const buffer *packet = original; if ( original->length + ETH_FCS_LENGTH < ETH_MINIMUM_LENGTH ) { copy = duplicate_buffer( original ); fill_ether_padding( copy ); packet = copy; } buffer *packet_out = create_packet_out( transaction_id, buffer_id, in_port, actions, packet ); send_openflow_message( datapath_id, packet_out ); free_buffer( packet_out ); if ( copy != NULL ) { free_buffer( copy ); } }
static void recv_packet_from_tun() { char data[ PKT_BUF_SIZE ]; ssize_t ret; ret = read( fd, data, PKT_BUF_SIZE ); if ( ret <= 0 ) { return; } debug( "%zd bytes packet received from tun interface (fd = %d).", ret, fd ); // FIXME: we need to parse the ipv4 packet. ipv4_header_t *ip_header = ( ipv4_header_t * ) data; host_entry *entry = lookup_host( ntohl( ip_header->daddr ) ); struct in_addr addr; addr.s_addr = ip_header->daddr; if ( entry == NULL ) { error( "Failed to resolve host location (ip = %s).", inet_ntoa( addr ) ); return; } // create an Ethernet frame and send a packet-out void *p; uint16_t *type; buffer *frame; buffer *pout; openflow_actions *actions; size_t frame_length = ETH_ADDRLEN * 2 + 2 + ( size_t ) ret; frame = alloc_buffer_with_length( frame_length ); p = append_back_buffer( frame, ETH_ADDRLEN ); memcpy( p, entry->mac, ETH_ADDRLEN ); p = append_back_buffer( frame, ETH_ADDRLEN ); memcpy( p, redirector_mac, ETH_ADDRLEN ); type = append_back_buffer( frame, 2 ); *type = htons( ETH_ETHTYPE_IPV4 ); p = append_back_buffer( frame, ( size_t ) ret ); memcpy( p, data, ( size_t ) ret ); debug( "Sending a packet-out to a switch (ip = %s, dpid = %#" PRIx64 ", port = %u).", inet_ntoa( addr ), entry->dpid, entry->port ); actions = create_actions(); append_action_output( actions, entry->port, UINT16_MAX ); pout = create_packet_out( get_transaction_id(), UINT32_MAX, OFPP_NONE, actions, frame ); send_openflow_message( entry->dpid, pout ); free_buffer( frame ); free_buffer( pout ); delete_actions( actions ); }
static VALUE send_packet_out( int argc, VALUE *argv, VALUE self ) { VALUE datapath_id = Qnil; VALUE options = Qnil; rb_scan_args( argc, argv, "11", &datapath_id, &options ); uint32_t buffer_id = OFP_NO_BUFFER; buffer *data = NULL; openflow_actions *actions = NULL; uint32_t in_port = OFPP_ANY; if ( !NIL_P( options ) ) { VALUE r_opt_action = HASH_REF( options, actions ); if ( !NIL_P( r_opt_action ) ) { actions = pack_basic_action( r_opt_action ); } VALUE r_opt_message = HASH_REF( options, packet_in ); VALUE r_opt_data = HASH_REF( options, data ); if ( !NIL_P( r_opt_message ) ) { if ( datapath_id == rb_iv_get( r_opt_message, "@datapath_id" ) ) { buffer_id = NUM2UINT( rb_iv_get( r_opt_message, "@buffer_id" ) ); VALUE match = rb_iv_get( r_opt_message, "@match" ); in_port = NUM2UINT( rb_iv_get( match, "@in_port" ) ); } VALUE r_data = rb_iv_get( r_opt_message, "@data" ); data = r_array_to_buffer( r_data ); } else if ( !NIL_P( r_opt_data ) ) { data = r_array_to_buffer( r_opt_data ); } buffer *packet_out; if ( buffer_id == OFP_NO_BUFFER && ( !NIL_P( r_opt_message ) || !NIL_P( r_opt_data ) )) { buffer *frame = duplicate_buffer( data ); fill_ether_padding( frame ); packet_out = create_packet_out( get_transaction_id(), buffer_id, in_port, actions, frame ); free_buffer( data ); free_buffer( frame ); } else { packet_out = create_packet_out( get_transaction_id(), buffer_id, in_port, actions, NULL ); } send_openflow_message( NUM2ULL( datapath_id ), packet_out ); free_buffer( packet_out ); delete_actions( actions ); } return self; }
/* * @overload send_packet_out(datapath_id, options={}) * Sends a packet_out message to have a packet processed by the datapath. * * @example * send_packet_out( * datapath_id, * :packet_in => message, * :actions => Trema::SendOutPort.new(port_no) * ) * * * @param [Number] datapath_id * the datapath to which a message is sent. * * @param [Hash] options * the options to create a message with. * * * @option options [PacketIn] :packet_in (nil) * The {PacketIn} object received by packet_in handler. If this * option is not nil, :buffer_id, :data, and :in_port option is * set automatically according to the value of :packet_in. * * @option options [Number] :in_port (OFPP_NONE) * The port from which the frame is to be sent. OFPP_NONE if * none. OFPP_TABLE to perform the actions defined in the flow * table. * * @option options [Number] :buffer_id (0xffffffff) * The buffer ID assigned by the datapath. If 0xffffffff, the * frame is not buffered, and the entire frame must be passed in * :data. * * @option options [String, nil] :data (nil) * The entire Ethernet frame. Should be of length 0 if buffer_id * is 0xffffffff, and should be of length >0 otherwise. * * @option options [Action, Array<Action>, nil] :actions (nil) * The sequence of actions specifying the actions to perform on * the frame. * * @option options [Boolean] :zero_padding (false) * If true, fill up to minimum ethernet frame size. */ static VALUE controller_send_packet_out( int argc, VALUE *argv, VALUE self ) { VALUE datapath_id = Qnil; VALUE options = Qnil; rb_scan_args( argc, argv, "11", &datapath_id, &options ); // Defaults. uint32_t buffer_id = UINT32_MAX; uint16_t in_port = OFPP_NONE; openflow_actions *actions = create_actions(); const buffer *data = NULL; buffer *allocated_data = NULL; VALUE opt_zero_padding = Qnil; if ( options != Qnil ) { VALUE opt_message = rb_hash_aref( options, ID2SYM( rb_intern( "packet_in" ) ) ); if ( opt_message != Qnil ) { packet_in *message; Data_Get_Struct( opt_message, packet_in, message ); if ( NUM2ULL( datapath_id ) == message->datapath_id ) { buffer_id = message->buffer_id; in_port = message->in_port; } data = ( buffer_id == UINT32_MAX ? message->data : NULL ); } VALUE opt_buffer_id = rb_hash_aref( options, ID2SYM( rb_intern( "buffer_id" ) ) ); if ( opt_buffer_id != Qnil ) { buffer_id = ( uint32_t ) NUM2ULONG( opt_buffer_id ); } VALUE opt_in_port = rb_hash_aref( options, ID2SYM( rb_intern( "in_port" ) ) ); if ( opt_in_port != Qnil ) { in_port = ( uint16_t ) NUM2UINT( opt_in_port ); } VALUE opt_action = rb_hash_aref( options, ID2SYM( rb_intern( "actions" ) ) ); if ( opt_action != Qnil ) { form_actions( opt_action, actions ); } VALUE opt_data = rb_hash_aref( options, ID2SYM( rb_intern( "data" ) ) ); if ( opt_data != Qnil ) { Check_Type( opt_data, T_STRING ); uint16_t length = ( uint16_t ) RSTRING_LEN( opt_data ); allocated_data = alloc_buffer_with_length( length ); memcpy( append_back_buffer( allocated_data, length ), RSTRING_PTR( opt_data ), length ); data = allocated_data; } opt_zero_padding = rb_hash_aref( options, ID2SYM( rb_intern( "zero_padding" ) ) ); if ( opt_zero_padding != Qnil ) { if ( TYPE( opt_zero_padding ) != T_TRUE && TYPE( opt_zero_padding ) != T_FALSE ) { rb_raise( rb_eTypeError, ":zero_padding must be true or false" ); } } } if ( data != NULL && data->length + ETH_FCS_LENGTH < ETH_MINIMUM_LENGTH && opt_zero_padding != Qnil && TYPE( opt_zero_padding ) == T_TRUE ) { if ( allocated_data == NULL ) { allocated_data = duplicate_buffer( data ); data = allocated_data; } fill_ether_padding( allocated_data ); } buffer *packet_out = create_packet_out( get_transaction_id(), buffer_id, in_port, actions, data ); send_openflow_message( NUM2ULL( datapath_id ), packet_out ); if ( allocated_data != NULL ) { free_buffer( allocated_data ); } free_buffer( packet_out ); delete_actions( actions ); return self; }