+/* Takes 'packet', which has been converted with do_convert_to_packet_in(), and
+ * finalizes its content for sending on 'ofconn', and passes it to 'ofconn''s
+ * packet scheduler for sending.
+ *
+ * 'max_len' specifies the maximum number of bytes of the packet to send on
+ * 'ofconn' (INT_MAX specifies no limit).
+ *
+ * If 'clone' is true, the caller retains ownership of 'packet'. Otherwise,
+ * ownership is transferred to this function. */
+static void
+schedule_packet_in(struct ofconn *ofconn, struct ofpbuf *packet, int max_len,
+ bool clone)
+{
+ struct ofproto *ofproto = ofconn->ofproto;
+ struct ofp_packet_in *opi = packet->data;
+ uint16_t in_port = ofp_port_to_odp_port(ntohs(opi->in_port));
+ int send_len, trim_size;
+ uint32_t buffer_id;
+
+ /* Get buffer. */
+ if (opi->reason == OFPR_ACTION) {
+ buffer_id = UINT32_MAX;
+ } else if (ofproto->fail_open && fail_open_is_active(ofproto->fail_open)) {
+ buffer_id = pktbuf_get_null();
+ } else if (!ofconn->pktbuf) {
+ buffer_id = UINT32_MAX;
+ } else {
+ struct ofpbuf payload;
+ payload.data = opi->data;
+ payload.size = packet->size - offsetof(struct ofp_packet_in, data);
+ buffer_id = pktbuf_save(ofconn->pktbuf, &payload, in_port);
+ }
+
+ /* Figure out how much of the packet to send. */
+ send_len = ntohs(opi->total_len);
+ if (buffer_id != UINT32_MAX) {
+ send_len = MIN(send_len, ofconn->miss_send_len);
+ }
+ send_len = MIN(send_len, max_len);
+
+ /* Adjust packet length and clone if necessary. */
+ trim_size = offsetof(struct ofp_packet_in, data) + send_len;
+ if (clone) {
+ packet = ofpbuf_clone_data(packet->data, trim_size);
+ opi = packet->data;
+ } else {
+ packet->size = trim_size;
+ }