size_t ofl_structs_match_pack(struct ofl_match_header *src, struct ofp_match *dst, uint8_t* oxm_fields, enum byte_order order, struct ofl_exp *exp) { switch (src->type) { case (OFPMT_OXM): { struct ofl_match *m = (struct ofl_match *)src; struct ofpbuf *b = ofpbuf_new(0); int oxm_len; dst->type = htons(m->header.type); oxm_fields = (uint8_t*) &dst->oxm_fields; dst->length = htons(sizeof(struct ofp_match)); if (src->length){ if (order == HOST_ORDER) oxm_len = oxm_put_match(b, m); else oxm_len = oxm_put_packet_match(b,m); memcpy(oxm_fields, (uint8_t*) ofpbuf_pull(b,oxm_len), oxm_len); dst->length = htons(oxm_len + ((sizeof(struct ofp_match )-4))); ofpbuf_delete(b); return ntohs(dst->length); } else return 0; } default: { if (exp == NULL || exp->match == NULL || exp->match->pack == NULL) { OFL_LOG_WARN(LOG_MODULE, "Trying to pack experimenter match, but no callback was given."); return -1; } return exp->match->pack(src, dst); } } }
/* Creates and returns a new ofpbuf with an initial capacity of 'size + * headroom' bytes, reserving the first 'headroom' bytes as headroom. */ struct ofpbuf * ofpbuf_new_with_headroom(size_t size, size_t headroom) { struct ofpbuf *b = ofpbuf_new(size + headroom); ofpbuf_reserve(b, headroom); return b; }
/* Allocates and stores in '*bufferp' a new ofpbuf with a size of * 'openflow_len', starting with an OpenFlow header with the given 'type' and * transaction id 'xid'. Allocated bytes beyond the header, if any, are * zeroed. * * The caller is responsible for freeing '*bufferp' when it is no longer * needed. * * The OpenFlow header length is initially set to 'openflow_len'; if the * message is later extended, the length should be updated with * update_openflow_length() before sending. * * Returns the header. */ void * make_openflow_xid(size_t openflow_len, uint8_t type, uint32_t xid, struct ofpbuf **bufferp) { *bufferp = ofpbuf_new(openflow_len); return put_openflow_xid(openflow_len, type, xid, *bufferp); }
struct ofpbuf * ofpbuf_clone_data(const void *data, size_t size) { struct ofpbuf *b = ofpbuf_new(size); ofpbuf_put(b, data, size); return b; }
static int stream_recv(struct vconn *vconn, struct ofpbuf **bufferp) { struct stream_vconn *s = stream_vconn_cast(vconn); struct ofpbuf *rx; size_t want_bytes; ssize_t retval; if (s->rxbuf == NULL) { s->rxbuf = ofpbuf_new(1564); } rx = s->rxbuf; again: if (sizeof(struct ofp_header) > rx->size) { want_bytes = sizeof(struct ofp_header) - rx->size; } else { struct ofp_header *oh = rx->data; size_t length = ntohs(oh->length); if (length < sizeof(struct ofp_header)) { VLOG_ERR_RL(LOG_MODULE, &rl, "received too-short ofp_header (%zu bytes)", length); return EPROTO; } want_bytes = length - rx->size; if (!want_bytes) { *bufferp = rx; s->rxbuf = NULL; return 0; } } ofpbuf_prealloc_tailroom(rx, want_bytes); retval = read(s->fd, ofpbuf_tail(rx), want_bytes); if (retval > 0) { rx->size += retval; if (retval == want_bytes) { if (rx->size > sizeof(struct ofp_header)) { *bufferp = rx; s->rxbuf = NULL; return 0; } else { goto again; } } return EAGAIN; } else if (retval == 0) { if (rx->size) { VLOG_ERR_RL(LOG_MODULE, &rl, "connection dropped mid-packet"); return EPROTO; } else { return EOF; } } else { return errno; } }
static ofl_err ofl_structs_oxm_match_unpack(struct ofp_match* src, uint8_t* buf, size_t *len, struct ofl_match **dst){ int error = 0; struct ofpbuf *b = ofpbuf_new(0); struct ofl_match *m = (struct ofl_match *) malloc(sizeof(struct ofl_match)); m->header.type = ntohs(src->type); *len -= ROUND_UP(ntohs(src->length),8); if(ntohs(src->length) > sizeof(struct ofp_match)){ ofpbuf_put(b, buf, ntohs(src->length) - (sizeof(struct ofp_match) -4)); error = oxm_pull_match(b, m, ntohs(src->length) - (sizeof(struct ofp_match) -4)); m->header.length = ntohs(src->length) - 4; } else m->header.length = 0; ofpbuf_delete(b); *dst = m; return error; }
/* Converts hex digits in 'hex' to an Ethernet packet in '*packetp'. The * caller must free '*packetp'. On success, returns NULL. On failure, returns * an error message and stores NULL in '*packetp'. */ const char * eth_from_hex(const char *hex, struct ofpbuf **packetp) { struct ofpbuf *packet; packet = *packetp = ofpbuf_new(strlen(hex) / 2); if (ofpbuf_put_hex(packet, hex, NULL)[0] != '\0') { ofpbuf_delete(packet); *packetp = NULL; return "Trailing garbage in packet data"; } if (packet->size < ETH_HEADER_LEN) { ofpbuf_delete(packet); *packetp = NULL; return "Packet data too short for Ethernet"; } return NULL; }
/* Sends 'request' to the kernel via 'sock' and waits for a response. If * successful, returns 0. On failure, returns a positive errno value. * * If 'replyp' is nonnull, then on success '*replyp' is set to the kernel's * reply, which the caller is responsible for freeing with ofpbuf_delete(), and * on failure '*replyp' is set to NULL. If 'replyp' is null, then the kernel's * reply, if any, is discarded. * * Before the message is sent, nlmsg_len in 'request' will be finalized to * match msg->size, nlmsg_pid will be set to 'sock''s pid, and nlmsg_seq will * be initialized, NLM_F_ACK will be set in nlmsg_flags. * * The caller is responsible for destroying 'request'. * * Bare Netlink is an unreliable transport protocol. This function layers * reliable delivery and reply semantics on top of bare Netlink. * * In Netlink, sending a request to the kernel is reliable enough, because the * kernel will tell us if the message cannot be queued (and we will in that * case put it on the transmit queue and wait until it can be delivered). * * Receiving the reply is the real problem: if the socket buffer is full when * the kernel tries to send the reply, the reply will be dropped. However, the * kernel sets a flag that a reply has been dropped. The next call to recv * then returns ENOBUFS. We can then re-send the request. * * Caveats: * * 1. Netlink depends on sequence numbers to match up requests and * replies. The sender of a request supplies a sequence number, and * the reply echos back that sequence number. * * This is fine, but (1) some kernel netlink implementations are * broken, in that they fail to echo sequence numbers and (2) this * function will drop packets with non-matching sequence numbers, so * that only a single request can be usefully transacted at a time. * * 2. Resending the request causes it to be re-executed, so the request * needs to be idempotent. */ int nl_sock_transact(struct nl_sock *sock, const struct ofpbuf *request, struct ofpbuf **replyp) { struct nl_transaction *transactionp; struct nl_transaction transaction; transaction.request = CONST_CAST(struct ofpbuf *, request); transaction.reply = replyp ? ofpbuf_new(1024) : NULL; transactionp = &transaction; nl_sock_transact_multiple(sock, &transactionp, 1); if (replyp) { if (transaction.error) { ofpbuf_delete(transaction.reply); *replyp = NULL; } else { *replyp = transaction.reply; } } return transaction.error; }
size_t ofl_structs_match_pack(struct ofl_match_header *src, struct ofp_match *dst, uint8_t* oxm_fields, struct ofl_exp *exp) { switch (src->type) { case (OFPMT_OXM): { struct ofl_match *m = (struct ofl_match *)src; struct ofpbuf *b = ofpbuf_new(0); int oxm_len; dst->type = htons(m->header.type); oxm_fields = (uint8_t*) &dst->oxm_fields; dst->length = htons(sizeof(struct ofp_match) - 4); if (src->length){ oxm_len = oxm_put_match(b, m); memcpy(oxm_fields, (uint8_t*) ofpbuf_pull(b,oxm_len), oxm_len); dst->length = htons(oxm_len + ((sizeof(struct ofp_match )-4))); ofpbuf_delete(b); return ntohs(dst->length); } else return 0; } //*********************************** // Modified by Bence Ladoczki //case (OFPMT_STANDARD): { //struct ofl_match_standard *m = (struct ofl_match_standard *)src; // //dst->type = htons( m->header.type); //dst->length = htons( OFPMT_STANDARD_LENGTH); //dst->in_port = htonl( m->in_port); //dst->wildcards = htonl( m->wildcards); //memcpy(&(dst->dl_src), &(m->dl_src), OFP_ETH_ALEN); //memcpy(&(dst->dl_src_mask), &(m->dl_src_mask), OFP_ETH_ALEN); //memcpy(&(dst->dl_dst), &(m->dl_dst), OFP_ETH_ALEN); //memcpy(&(dst->dl_dst_mask), &(m->dl_dst_mask), OFP_ETH_ALEN); //dst->dl_vlan = htons( m->dl_vlan); //dst->dl_vlan_pcp = m->dl_vlan_pcp; //memset(dst->pad1, 0x00, 1); //dst->dl_type = htons( m->dl_type); //dst->nw_tos = m->nw_tos; //dst->nw_proto = m->nw_proto; //dst->nw_src = m->nw_src; //dst->nw_src_mask = m->nw_src_mask; //dst->nw_dst = m ->nw_dst; //dst->nw_dst_mask = m->nw_dst_mask; //dst->tp_src = htons( m->tp_src); //dst->tp_dst = htons( m->tp_dst); //dst->mpls_label = htonl( m->mpls_label); //dst->mpls_tc = m->mpls_tc; //memset(dst->pad2, 0x00, 3); //dst->metadata = hton64(m->metadata); //dst->metadata_mask = hton64(m->metadata_mask); // //return sizeof(struct ofp_match); //} //*********************************** default: { if (exp == NULL || exp->match == NULL || exp->match->pack == NULL) { OFL_LOG_WARN(LOG_MODULE, "Setting leak logging file size limit to %"PRIdMAX" bytes", src->type); OFL_LOG_WARN(LOG_MODULE, "Trying to pack experimenter match, but no callback was given."); return -1; } return exp->match->pack(src, dst); } } }
/* Allocates and stores in '*bufferp' a new ofpbuf with a size of * 'openflow_len', starting with an OpenFlow header with the given 'type' and * an arbitrary transaction id. Allocated bytes beyond the header, if any, are * zeroed. * * The caller is responsible for freeing '*bufferp' when it is no longer * needed. * * The OpenFlow header length is initially set to 'openflow_len'; if the * message is later extended, the length should be updated with * update_openflow_length() before sending. * * Returns the header. */ void * make_openflow(size_t openflow_len, uint8_t type, struct ofpbuf **bufferp) { *bufferp = ofpbuf_new(openflow_len); return put_openflow_xid(openflow_len, type, alloc_xid(), *bufferp); }
void update_instruction_length(struct ofpbuf *buffer, size_t oia_offset) { struct ofp_header *oh = ofpbuf_at_assert(buffer, 0, sizeof *oh); struct ofp_instruction *ih = ofpbuf_at_assert(buffer, oia_offset, sizeof *ih); ih->len = htons(buffer->size - oia_offset); } struct ofpbuf * make_flow_mod(uint8_t command, uint8_t table_id, const struct flow *flow UNUSED, size_t actions_len) { struct ofp_flow_mod *ofm; size_t size = sizeof *ofm + actions_len; struct ofpbuf *out = ofpbuf_new(size); ofm = ofpbuf_put_zeros(out, sizeof *ofm); ofm->header.version = OFP_VERSION; ofm->header.type = OFPT_FLOW_MOD; ofm->header.length = htons(size); ofm->cookie = 0; /*TODO fill match ofm->match.in_port = flow->in_port; memcpy(ofm->match.dl_src, flow->dl_src, sizeof ofm->match.dl_src); memcpy(ofm->match.dl_dst, flow->dl_dst, sizeof ofm->match.dl_dst); ofm->match.dl_vlan = flow->dl_vlan; ofm->match.dl_vlan_pcp = flow->dl_vlan_pcp; ofm->match.dl_type = flow->dl_type; ofm->match.nw_src = flow->nw_src; ofm->match.nw_dst = flow->nw_dst; ofm->match.nw_proto = flow->nw_proto;
static int ssl_recv(struct vconn *vconn, struct ofpbuf **bufferp) { struct ssl_vconn *sslv = ssl_vconn_cast(vconn); struct ofpbuf *rx; size_t want_bytes; int old_state; ssize_t ret; if (sslv->rxbuf == NULL) { sslv->rxbuf = ofpbuf_new(1564); } rx = sslv->rxbuf; again: if (sizeof(struct ofp_header) > rx->size) { want_bytes = sizeof(struct ofp_header) - rx->size; } else { struct ofp_header *oh = rx->data; size_t length = ntohs(oh->length); if (length < sizeof(struct ofp_header)) { VLOG_ERR_RL(&rl, "received too-short ofp_header (%zu bytes)", length); return EPROTO; } want_bytes = length - rx->size; if (!want_bytes) { *bufferp = rx; sslv->rxbuf = NULL; return 0; } } ofpbuf_prealloc_tailroom(rx, want_bytes); /* Behavior of zero-byte SSL_read is poorly defined. */ assert(want_bytes > 0); old_state = SSL_get_state(sslv->ssl); ret = SSL_read(sslv->ssl, ofpbuf_tail(rx), want_bytes); if (old_state != SSL_get_state(sslv->ssl)) { sslv->tx_want = SSL_NOTHING; if (sslv->tx_waiter) { poll_cancel(sslv->tx_waiter); ssl_tx_poll_callback(sslv->fd, POLLIN, vconn); } } sslv->rx_want = SSL_NOTHING; if (ret > 0) { rx->size += ret; if (ret == want_bytes) { if (rx->size > sizeof(struct ofp_header)) { *bufferp = rx; sslv->rxbuf = NULL; return 0; } else { goto again; } } return EAGAIN; } else { int error = SSL_get_error(sslv->ssl, ret); if (error == SSL_ERROR_ZERO_RETURN) { /* Connection closed (EOF). */ if (rx->size) { VLOG_WARN_RL(&rl, "SSL_read: unexpected connection close"); return EPROTO; } else { return EOF; } } else { return interpret_ssl_error("SSL_read", ret, error, &sslv->rx_want); } } }