static bool rate_limit_local_packet_cb(struct relay *r, void *rl_) { struct rate_limiter *rl = rl_; const struct settings *s = rl->s; struct ofp_packet_in *opi; opi = get_ofp_packet_in(r); if (!opi) { return false; } if (opi->reason == OFPR_ACTION) { /* Don't rate-limit 'ofp-packet_in's generated by flows that the * controller set up. XXX we should really just rate-limit them * *separately* so that no one can flood the controller this way. */ return false; } if (!rl->n_queued && get_token(rl)) { /* In the common case where we are not constrained by the rate limit, * let the packet take the normal path. */ rl->n_normal++; return false; } else { /* Otherwise queue it up for the periodic callback to drain out. */ struct ofpbuf *msg = r->halves[HALF_LOCAL].rxbuf; int port = ntohs(opi->in_port) % OFPP_MAX; if (rl->n_queued >= s->burst_limit) { drop_packet(rl); } queue_push_tail(&rl->queues[port], ofpbuf_clone(msg)); rl->n_queued++; rl->n_limited++; return true; } }
struct packet * packet_clone(struct packet *pkt) { struct packet *clone; clone = xmalloc(sizeof(struct packet)); clone->dp = pkt->dp; clone->buffer = ofpbuf_clone(pkt->buffer); clone->in_port = pkt->in_port; clone->action_set = action_set_clone(pkt->action_set); clone->packet_out = pkt->packet_out; clone->out_group = OFPG_ANY; clone->out_port = OFPP_ANY; clone->out_port_max_len = 0; clone->out_queue = 0; clone->buffer_id = NO_BUFFER; // the original is saved in buffer, // but this buffer is a copy of that, // and might be altered later clone->table_id = pkt->table_id; clone->handle_std = packet_handle_std_clone(clone, pkt->handle_std); return clone; }
int get_packet_list(struct ofpbuf *out_packets[], struct ofpbuf * packet, uint32_t flow_id, uint32_t in_port){ struct tcp_buf * tcp_buf; uint8_t tcp_flags; struct tcp_header *tcp; uint32_t seq; int i, out_packets_count; uint32_t seq_work; struct ofpbuf * buf_pkt; int removed_items; // Getting the buffer for the flow, or creating a new one if // not existing tcp_buf = get_tcp_buf(flow_id); tcp = ofpbuf_l4(packet); tcp_flags = TCP_FLAGS(tcp->tcp_ctl); seq = get_tcp_seq(packet); out_packets_count = 0; if (tcp_flags & TCP_SYN){ tcp_buf->expected_seqnum = seq+1; VLOG_INFO("[SYN packet] sequence: %" PRIu32 " expected: %" PRIu32 " in_port: %"PRIu32 " size: %d", seq, tcp_buf->expected_seqnum, in_port, tcp_buf->inserted_items); out_packets[out_packets_count] = packet; out_packets_count++; } else if(tcp_buf->fin_state){ delete_tcp_buf(tcp_buf); out_packets[out_packets_count] = packet; out_packets_count++; } // Retransmission or packets which come without a SYN or after a FIN // Just send out else if(tcp_buf->expected_seqnum == -1){ out_packets[out_packets_count] = packet; out_packets_count++; } // Sending out and checking if the the gap in the reordering buffer has been filled else if(seq <= tcp_buf->expected_seqnum){ VLOG_INFO("[sending in order packet] seq: %"PRIu32 " expected: %" PRIu32 " in_port: %"PRIu32 " size: %d", seq, tcp_buf->expected_seqnum, in_port, tcp_buf->inserted_items); out_packets[out_packets_count] = packet; out_packets_count++; tcp_buf->consecutive_buffering_events = 0; // Increasing sequence only if it matches if(seq == tcp_buf->expected_seqnum){ tcp_buf->expected_seqnum = get_next_seqnum(tcp_buf, tcp_buf->expected_seqnum, packet, false); } // Check if there are packets waiting to be sent removed_items = 0; for(i=tcp_buf->inserted_items-1;i>= 0;i--){ seq_work = get_tcp_seq(tcp_buf->buffer[i]); if(seq_work <= tcp_buf->expected_seqnum){ VLOG_INFO("[sending out from buffer] sequence: %" PRIu32 " expected: %" PRIu32 " size: %d", seq_work, tcp_buf->expected_seqnum, tcp_buf->inserted_items - removed_items); removed_items++; out_packets[out_packets_count] = tcp_buf->buffer[i]; out_packets_count++; if(seq_work == tcp_buf->expected_seqnum){ tcp_buf->expected_seqnum = get_next_seqnum(tcp_buf, tcp_buf->expected_seqnum, tcp_buf->buffer[i], false); } } } tcp_buf->inserted_items = tcp_buf->inserted_items - removed_items; } // Buffer not full yet, buffering the packet else if(tcp_buf->inserted_items<TCP_BUF_SIZE && tcp_buf->consecutive_buffering_events < CONSECUTIVE_BUFFERING_TREESHOLD){ VLOG_INFO("[buffering] sequence: %"PRIu32 " expected: %" PRIu32 " in_port: %"PRIu32 " size: %d", seq, tcp_buf->expected_seqnum, in_port, tcp_buf->inserted_items); buf_pkt = ofpbuf_clone(packet); insert_descending_order(tcp_buf, buf_pkt); } // Buffer full or loss event detecte else{ VLOG_WARN("!! -- Empty Buffer Event -- !!"); if(tcp_buf->consecutive_buffering_events >= CONSECUTIVE_BUFFERING_TREESHOLD) syslog(LOG_INFO, "!! -- Because of an apparent loss -- !!"); seq_work = get_tcp_seq(tcp_buf->buffer[tcp_buf->inserted_items-1]); // If incoming packet has the smallest sequence if(seq<seq_work){ VLOG_INFO("[resetting buffer] sequence: %" PRIu32, seq); out_packets[out_packets_count] = packet; out_packets_count++; } // If a packet in the buffer has the smallest sequence else{ VLOG_INFO("[resetting] sequence: %" PRIu32, get_tcp_seq(tcp_buf->buffer[tcp_buf->inserted_items-1])); out_packets[out_packets_count] = tcp_buf->buffer[tcp_buf->inserted_items-1]; out_packets_count++; tcp_buf->inserted_items--; buf_pkt = ofpbuf_clone(packet); insert_descending_order(tcp_buf, buf_pkt); } // Completely empty the buffer for(i=tcp_buf->inserted_items-1;i>= 0;i--){ seq_work = get_tcp_seq(tcp_buf->buffer[i]); VLOG_INFO("resetting %" PRIu32, seq_work); get_next_seqnum(tcp_buf, seq_work, tcp_buf->buffer[i], false); out_packets[out_packets_count] = tcp_buf->buffer[i]; out_packets_count++; // Adjusting seqnum if(i==0){ tcp_buf->expected_seqnum = get_next_seqnum(tcp_buf, seq_work, tcp_buf->buffer[i], false); } } tcp_buf->inserted_items=0; if(tcp_buf->consecutive_buffering_events >= CONSECUTIVE_BUFFERING_TREESHOLD){ tcp_buf->expected_seqnum = get_next_seqnum(tcp_buf, tcp_buf->expected_seqnum, packet, true); } } return out_packets_count; }