static void remote_rconn_run(struct datapath *dp, struct remote *r, uint8_t conn_id) { struct rconn *rconn; ofl_err error; size_t i; if (conn_id == MAIN_CONNECTION) rconn = r->rconn; else if (conn_id == PTIN_CONNECTION) rconn = r->rconn_aux; rconn_run(rconn); /* Do some remote processing, but cap it at a reasonable amount so that * other processing doesn't starve. */ for (i = 0; i < 50; i++) { if (!r->cb_dump) { struct ofpbuf *buffer; buffer = rconn_recv(rconn); if (buffer == NULL) { break; } else { struct ofl_msg_header *msg; struct sender sender = {.remote = r, .conn_id = conn_id}; error = ofl_msg_unpack(buffer->data, buffer->size, &msg, &(sender.xid), dp->exp); if (!error) { error = handle_control_msg(dp, msg, &sender); if (error) { ofl_msg_free(msg, dp->exp); } } if (error) { struct ofl_msg_error err = {{.type = OFPT_ERROR}, .type = ofl_error_type(error), .code = ofl_error_code(error), .data_length = buffer->size, .data = buffer->data}; dp_send_message(dp, (struct ofl_msg_header *)&err, &sender); } ofpbuf_delete(buffer); } } else { if (r->n_txq < TXQ_LIMIT) {
/* Handles barrier request messages. */ static ofl_err handle_control_barrier_request(struct datapath *dp, struct ofl_msg_header *msg, const struct sender *sender) { /* Note: the implementation is single-threaded, so a barrier request can simply be replied. */ struct ofl_msg_header reply = {.type = OFPT_BARRIER_REPLY}; dp_send_message(dp, (struct ofl_msg_header *)&reply, sender); ofl_msg_free(msg, dp->exp); return 0; }
int main(int argc, char **argv) { uint8_t *buf ,*buf0; size_t buf_len = 0; ofl_err err; struct ofl_msg_header *msg = NULL; uint32_t xid; FILE *msg_file; struct ofp_header *oh; if (argc < 2) { fprintf(stderr, "Expecting msg file.\n"); return 1; } time_init(); vlog_init(); vlog_set_verbosity(NULL); msg_file = fopen(argv[1], "r"); if (msg_file == NULL) { fprintf(stderr, "Cannot open msg file.\n"); return 1; } buf_len = read_all(msg_file, &buf); buf0 = buf; while (buf_len > 0) { oh = (struct ofp_header *)buf; err = ofl_msg_unpack(buf, ntohs(oh->length), &msg, &xid, NULL); if (err == 0) { //printf("Success!\n"); ofl_msg_print(stdout, msg, NULL); printf("\n\n"); ofl_msg_free(msg, NULL); } else { free(buf); printf("Failed :-( error type: %d code %d\n", ofl_error_type(err), ofl_error_code(err)); return 1; } buf_len -= ntohs(oh->length); buf += ntohs(oh->length); } free(buf0); return 0; }
ofl_err pipeline_handle_table_mod(struct pipeline *pl, struct ofl_msg_table_mod *msg, const struct sender *sender) { if(sender->remote->role == OFPCR_ROLE_SLAVE) return ofl_error(OFPET_BAD_REQUEST, OFPBRC_IS_SLAVE); if (msg->table_id == 0xff) { size_t i; for (i=0; i<PIPELINE_TABLES; i++) { pl->tables[i]->features->config = msg->config; } } else { pl->tables[msg->table_id]->features->config = msg->config; } ofl_msg_free((struct ofl_msg_header *)msg, pl->dp->exp); return 0; }
/* Sends OpenFlow messages received from other threads via the appropriate functions. * Primarily used by DP to send messages to the controllers. */ static bool process_msg(void *ctrl_loop_, struct list_node *msg_) { struct ctrl_loop *ctrl_loop = (struct ctrl_loop *)ctrl_loop_; struct ctrl_msg *msg = (struct ctrl_msg *)msg_; if (msg->conn_id == CTRL_CONN_ALL) { size_t i; for (i=1; i<ctrl_loop->conns_num; i++) { ctrl_conn_send_msg(ctrl_loop->conns[i], msg->xid, msg->msg); } } else { if (ctrl_loop->conns[msg->conn_id] != NULL) { ctrl_conn_send_msg(ctrl_loop->conns[msg->conn_id], msg->xid, msg->msg); } else { logger_log(ctrl_loop->logger, LOG_WARN, "Request for message on non-existing connection."); } } ofl_msg_free(msg->msg, OFL_NO_EXP, NULL/*errbuf*/); free(msg); return true; }
/* Commit operation. */ static ofl_err bundle_commit(struct datapath *dp, struct bundle_table *table, uint32_t bundle_id, uint16_t flags, const struct sender *sender) { struct bundle_table_entry *entry; struct bundle_message *bundle_msg; struct ofl_msg_header *msg; uint32_t xid; ofl_err error; ofl_err last_error = ofl_error(OFPET_BUNDLE_FAILED, OFPBFC_BAD_ID); /* Find and process commit operation for bundle ID */ entry = bundle_table_entry_find(table, bundle_id); if (entry != NULL) { /* Ensure flags are consistent with flags specified previously */ if (entry->flags != flags) { last_error = ofl_error(OFPET_BUNDLE_FAILED, OFPBFC_BAD_FLAGS); } else { /* Save state in case failure occurs */ last_error = 0; dp_save_state(dp); /* Commit all messages in bundle, stopping at first error */ LIST_FOR_EACH (bundle_msg, struct bundle_message, node, &entry->bundle_message_list) { VLOG_DBG_RL(LOG_MODULE, &rl, "Commit of message with type %u and length %u\n", bundle_msg->message->type, ntohs(bundle_msg->message->length)); error = ofl_msg_unpack((uint8_t *)bundle_msg->message, ntohs(bundle_msg->message->length), &msg, &xid, dp->exp); if (!error) { /* This prototype only properly supports bundling of * messages that do not generate replies (other than * error replies). TODO: keep replies in a holding * area and only release them to the controller when * the commit succeeds. */ error = handle_control_msg(dp, msg, sender); if (error) { ofl_msg_free(msg, dp->exp); } } if (error) { last_error = error; break; } } /* Restore state if failures occurred */ if (last_error) { dp_restore_state(dp); } else { /* TODO free memory used to save state without restoring * (not required currently as variables used to save/restore * state are re-used) */ } /* We need to generate the error ourselves. The spec say that * the error need to refer to the offending message in the budle. * If we just return the error code, the error message would refer * to the commit message. */ if (last_error) { struct sender orig_sender = {.remote = sender->remote, .conn_id = sender->conn_id, .xid = xid}; struct ofl_msg_error orig_err = {{.type = OFPT_ERROR}, .type = ofl_error_type(last_error), .code = ofl_error_code(last_error), .data_length = ntohs(bundle_msg->message->length), .data = (uint8_t *)bundle_msg->message}; dp_send_message(dp, (struct ofl_msg_header *)&orig_err, &orig_sender); /* Trigger second error message. */ last_error = ofl_error(OFPET_BUNDLE_FAILED, OFPBFC_MSG_FAILED); } } /* Whether or not commit succeeded: free entry for bundle ID */ bundle_table_entry_destroy(entry); } return last_error; }