static int lookup_brc_multicast_group(int *multicast_group) { struct nl_sock *sock; struct ofpbuf request, *reply; struct nlattr *attrs[ARRAY_SIZE(brc_multicast_policy)]; int retval; retval = nl_sock_create(NETLINK_GENERIC, &sock); if (retval) { return retval; } ofpbuf_init(&request, 0); nl_msg_put_genlmsghdr(&request, 0, brc_family, NLM_F_REQUEST, BRC_GENL_C_QUERY_MC, 1); retval = nl_sock_transact(sock, &request, &reply); ofpbuf_uninit(&request); if (retval) { nl_sock_destroy(sock); return retval; } if (!nl_policy_parse(reply, NLMSG_HDRLEN + GENL_HDRLEN, brc_multicast_policy, attrs, ARRAY_SIZE(brc_multicast_policy))) { nl_sock_destroy(sock); ofpbuf_delete(reply); return EPROTO; } *multicast_group = nl_attr_get_u32(attrs[BRC_GENL_A_MC_GROUP]); nl_sock_destroy(sock); ofpbuf_delete(reply); return 0; }
/* Drop a packet from the longest queue in 'rl'. */ static void drop_packet(struct rate_limiter *rl) { struct ofp_queue *longest; /* Queue currently selected as longest. */ int n_longest; /* # of queues of same length as 'longest'. */ struct ofp_queue *q; longest = &rl->queues[0]; n_longest = 1; for (q = &rl->queues[0]; q < &rl->queues[OFPP_MAX]; q++) { if (longest->n < q->n) { longest = q; n_longest = 1; } else if (longest->n == q->n) { n_longest++; /* Randomly select one of the longest queues, with a uniform * distribution (Knuth algorithm 3.4.2R). */ if (!random_range(n_longest)) { longest = q; } } } /* FIXME: do we want to pop the tail instead? */ ofpbuf_delete(queue_pop_head(longest)); rl->n_queued--; }
static void send_bpdu(struct ofpbuf *pkt, int port_no, void *b_) { struct bridge *b = b_; struct lan *lan; assert(port_no < b->n_ports); lan = b->ports[port_no]; if (lan) { const void *data = pkt->l3; size_t size = (char *) ofpbuf_tail(pkt) - (char *) data; int i; for (i = 0; i < lan->n_conns; i++) { struct lan_conn *conn = &lan->conns[i]; if (conn->bridge != b || conn->port_no != port_no) { struct bridge *dst = conn->bridge; struct bpdu *bpdu = &dst->rxq[dst->rxq_head++ % RXQ_SIZE]; assert(dst->rxq_head - dst->rxq_tail <= RXQ_SIZE); bpdu->data = xmemdup(data, size); bpdu->size = size; bpdu->port_no = conn->port_no; } } } ofpbuf_delete(pkt); }
/* Sends the given 'command' to datapath 'dp', related to the local datapath * numbered 'dp_idx'. If 'arg' is nonnull, adds it to the command as the * datapath or port name attribute depending on the requested operation. * Returns 0 if successful, otherwise a positive errno value. */ static int send_mgmt_command(struct dpif *dp, int dp_idx, int command, const char *arg) { struct ofpbuf request, *reply; int retval; ofpbuf_init(&request, 0); nl_msg_put_genlmsghdr(&request, dp->sock, 32, openflow_family, NLM_F_REQUEST | NLM_F_ACK, command, 1); if (dp_idx != -1) { nl_msg_put_u32(&request, DP_GENL_A_DP_IDX, dp_idx); } if (arg) { if ((command == DP_GENL_C_ADD_DP) || (command == DP_GENL_C_DEL_DP)) { nl_msg_put_string(&request, DP_GENL_A_DP_NAME, arg); } else { nl_msg_put_string(&request, DP_GENL_A_PORTNAME, arg); } } retval = nl_sock_transact(dp->sock, &request, &reply); ofpbuf_uninit(&request); ofpbuf_delete(reply); return retval; }
static int netdev_windows_system_construct(struct netdev *netdev_) { struct netdev_windows *netdev = netdev_windows_cast(netdev_); struct netdev_windows_netdev_info info; struct ofpbuf *buf; int ret; /* Query the attributes and runtime status of the netdev. */ ret = query_netdev(netdev_get_name(&netdev->up), &info, &buf); if (ret) { return ret; } ofpbuf_delete(buf); netdev->change_seq = 1; netdev->dev_type = info.ovs_type; netdev->port_no = info.port_no; netdev->mac = info.mac_address; netdev->cache_valid = VALID_ETHERADDR; netdev->ifindex = -EOPNOTSUPP; netdev->mtu = info.mtu; netdev->cache_valid |= VALID_MTU; netdev->ifi_flags = dp_to_netdev_ifi_flags(info.ifi_flags); netdev->cache_valid |= VALID_IFFLAG; VLOG_DBG("construct device %s, ovs_type: %u.", netdev_get_name(&netdev->up), info.ovs_type); return 0; }
int main(int argc OVS_UNUSED, char *argv[]) { struct ofp_match expected_match; FILE *flows, *pcap; int retval; int n = 0, errors = 0; set_program_name(argv[0]); flows = stdin; pcap = fdopen(3, "rb"); if (!pcap) { ovs_fatal(errno, "failed to open fd 3 for reading"); } retval = pcap_read_header(pcap); if (retval) { ovs_fatal(retval > 0 ? retval : 0, "reading pcap header failed"); } while (fread(&expected_match, sizeof expected_match, 1, flows)) { struct ofpbuf *packet; struct ofp_match extracted_match; struct cls_rule rule; struct flow flow; n++; retval = pcap_read(pcap, &packet); if (retval == EOF) { ovs_fatal(0, "unexpected end of file reading pcap file"); } else if (retval) { ovs_fatal(retval, "error reading pcap file"); } flow_extract(packet, 0, 1, &flow); cls_rule_init_exact(&flow, 0, &rule); ofputil_cls_rule_to_match(&rule, &extracted_match); if (memcmp(&expected_match, &extracted_match, sizeof expected_match)) { char *exp_s = ofp_match_to_string(&expected_match, 2); char *got_s = ofp_match_to_string(&extracted_match, 2); errors++; printf("mismatch on packet #%d (1-based).\n", n); printf("Packet:\n"); ofp_print_packet(stdout, packet->data, packet->size, packet->size); ovs_hex_dump(stdout, packet->data, packet->size, 0, true); printf("Expected flow:\n%s\n", exp_s); printf("Actually extracted flow:\n%s\n", got_s); printf("\n"); free(exp_s); free(got_s); } ofpbuf_delete(packet); } printf("checked %d packets, %d errors\n", n, errors); return errors != 0; }
/* Takes care of necessary 'sw' activity, except for receiving packets (which * the caller must do). */ void lswitch_run(struct lswitch *sw) { int i; rconn_run(sw->rconn); if (sw->state == S_CONNECTING) { if (rconn_get_version(sw->rconn) != -1) { lswitch_handshake(sw); sw->state = S_FEATURES_REPLY; } return; } for (i = 0; i < 50; i++) { struct ofpbuf *msg; msg = rconn_recv(sw->rconn); if (!msg) { break; } lswitch_process_packet(sw, msg); ofpbuf_delete(msg); } }
static void stream_clear_txbuf(struct stream_vconn *s) { ofpbuf_delete(s->txbuf); s->txbuf = NULL; s->tx_waiter = NULL; }
static void ssl_clear_txbuf(struct ssl_vconn *sslv) { ofpbuf_delete(sslv->txbuf); sslv->txbuf = NULL; sslv->tx_waiter = NULL; }
static int stream_send(struct vconn *vconn, struct ofpbuf *buffer) { struct stream_vconn *s = stream_vconn_cast(vconn); ssize_t retval; if (s->txbuf) { return EAGAIN; } retval = write(s->fd, buffer->data, buffer->size); if (retval == buffer->size) { ofpbuf_delete(buffer); return 0; } else if (retval >= 0 || errno == EAGAIN) { leak_checker_claim(buffer); s->txbuf = buffer; if (retval > 0) { ofpbuf_pull(buffer, retval); } s->tx_waiter = poll_fd_callback(s->fd, POLLOUT, stream_do_tx, vconn); return 0; } else { return errno; } }
/* Performs periodic maintenance on 'rpc', such as flushing output buffers. */ void jsonrpc_run(struct jsonrpc *rpc) { if (rpc->status) { return; } stream_run(rpc->stream); while (!list_is_empty(&rpc->output)) { struct ofpbuf *buf = ofpbuf_from_list(rpc->output.next); int retval; retval = stream_send(rpc->stream, buf->data, buf->size); if (retval >= 0) { rpc->backlog -= retval; ofpbuf_pull(buf, retval); if (!buf->size) { list_remove(&buf->list_node); rpc->output_count--; ofpbuf_delete(buf); } } else { if (retval != -EAGAIN) { VLOG_WARN_RL(&rl, "%s: send error: %s", rpc->name, ovs_strerror(-retval)); jsonrpc_error(rpc, -retval); } break; } } }
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); } } }
/* Removes each of the "struct ofpbuf"s on 'list' from the list and frees * them. */ void ofpbuf_list_delete(struct ovs_list *list) { struct ofpbuf *b; LIST_FOR_EACH_POP (b, list_node, list) { ofpbuf_delete(b); }
/* Removes each of the "struct ofpbuf"s on 'list' from the list and frees * them. */ void ofpbuf_list_delete(struct list *list) { struct ofpbuf *b, *next; LIST_FOR_EACH_SAFE (b, next, list_node, list) { list_remove(&b->list_node); ofpbuf_delete(b); }
static void stream_close(struct vconn *vconn) { struct stream_vconn *s = stream_vconn_cast(vconn); poll_cancel(s->tx_waiter); stream_clear_txbuf(s); ofpbuf_delete(s->rxbuf); close(s->fd); free(s); }
static void ssl_close(struct vconn *vconn) { struct ssl_vconn *sslv = ssl_vconn_cast(vconn); poll_cancel(sslv->tx_waiter); ssl_clear_txbuf(sslv); ofpbuf_delete(sslv->rxbuf); SSL_free(sslv->ssl); close(sslv->fd); free(sslv); }
/* Try connecting and sending a normal hello, which should succeed. */ static void test_send_plain_hello(int argc OVS_UNUSED, char *argv[]) { const char *type = argv[1]; struct ofpbuf *hello; hello = ofpraw_alloc_xid(OFPRAW_OFPT_HELLO, OFP13_VERSION, htonl(0x12345678), 0); test_send_hello(type, ofpbuf_data(hello), ofpbuf_size(hello), 0); ofpbuf_delete(hello); }
/* Try connecting and sending an echo request instead of a hello, which should * fail with EPROTO. */ static void test_send_echo_hello(int argc OVS_UNUSED, char *argv[]) { const char *type = argv[1]; struct ofpbuf *echo; echo = ofpraw_alloc_xid(OFPRAW_OFPT_ECHO_REQUEST, OFP13_VERSION, htonl(0x12345678), 0); test_send_hello(type, ofpbuf_data(echo), ofpbuf_size(echo), EPROTO); ofpbuf_delete(echo); }
/* Try connecting and sending an echo request instead of a hello, which should * fail with EPROTO. */ static void test_send_echo_hello(struct ovs_cmdl_context *ctx) { const char *type = ctx->argv[1]; struct ofpbuf *echo; echo = ofpraw_alloc_xid(OFPRAW_OFPT_ECHO_REQUEST, OFP13_VERSION, htonl(0x12345678), 0); test_send_hello(type, echo->data, echo->size, EPROTO); ofpbuf_delete(echo); }
/* Try connecting and sending a normal hello, which should succeed. */ static void test_send_plain_hello(struct ovs_cmdl_context *ctx) { const char *type = ctx->argv[1]; struct ofpbuf *hello; hello = ofpraw_alloc_xid(OFPRAW_OFPT_HELLO, OFP13_VERSION, htonl(0x12345678), 0); test_send_hello(type, hello->data, hello->size, 0); ofpbuf_delete(hello); }
/* Looks up the Netlink multicast group and datapath index of a datapath * by either the datapath index or name. If 'dp_idx' points to a value * of '-1', then 'dp_name' is used to lookup the datapath. If successful, * stores the multicast group in '*multicast_group' and the index in * '*dp_idx' and returns 0. Otherwise, returns a positive errno value. */ static int query_datapath(int *dp_idx, int *multicast_group, const char *dp_name) { struct nl_sock *sock; struct ofpbuf request, *reply; struct nlattr *attrs[ARRAY_SIZE(openflow_multicast_policy)]; int retval; retval = nl_sock_create(NETLINK_GENERIC, 0, 0, 0, &sock); if (retval) { return retval; } ofpbuf_init(&request, 0); nl_msg_put_genlmsghdr(&request, sock, 0, openflow_family, NLM_F_REQUEST, DP_GENL_C_QUERY_DP, 1); if (*dp_idx != -1) { nl_msg_put_u32(&request, DP_GENL_A_DP_IDX, *dp_idx); } if (dp_name) { nl_msg_put_string(&request, DP_GENL_A_DP_NAME, dp_name); } retval = nl_sock_transact(sock, &request, &reply); ofpbuf_uninit(&request); if (retval) { nl_sock_destroy(sock); return retval; } if (!nl_policy_parse(reply, NLMSG_HDRLEN + GENL_HDRLEN, openflow_multicast_policy, attrs, ARRAY_SIZE(openflow_multicast_policy))) { nl_sock_destroy(sock); ofpbuf_delete(reply); return EPROTO; } *dp_idx = nl_attr_get_u32(attrs[DP_GENL_A_DP_IDX]); *multicast_group = nl_attr_get_u32(attrs[DP_GENL_A_MC_GROUP]); nl_sock_destroy(sock); ofpbuf_delete(reply); return 0; }
/* 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; }
/* Try connecting and sending a hello packet that has a bad version, which * should fail with EPROTO. */ static void test_send_invalid_version_hello(int argc OVS_UNUSED, char *argv[]) { const char *type = argv[1]; struct ofpbuf *hello; hello = ofpraw_alloc_xid(OFPRAW_OFPT_HELLO, OFP13_VERSION, htonl(0x12345678), 0); ((struct ofp_header *) ofpbuf_data(hello))->version = 0; test_send_hello(type, ofpbuf_data(hello), ofpbuf_size(hello), EPROTO); ofpbuf_delete(hello); }
/* Try connecting and sending a hello packet that has a bad version, which * should fail with EPROTO. */ static void test_send_invalid_version_hello(struct ovs_cmdl_context *ctx) { const char *type = ctx->argv[1]; struct ofpbuf *hello; hello = ofpraw_alloc_xid(OFPRAW_OFPT_HELLO, OFP13_VERSION, htonl(0x12345678), 0); ((struct ofp_header *) hello->data)->version = 0; test_send_hello(type, hello->data, hello->size, EPROTO); ofpbuf_delete(hello); }
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) {
/* Try connecting and sending an extra-long hello, which should succeed (since * the specification says that implementations must accept and ignore extra * data). */ static void test_send_long_hello(int argc OVS_UNUSED, char *argv[]) { const char *type = argv[1]; struct ofpbuf *hello; enum { EXTRA_BYTES = 8 }; hello = ofpraw_alloc_xid(OFPRAW_OFPT_HELLO, OFP13_VERSION, htonl(0x12345678), EXTRA_BYTES); ofpbuf_put_zeros(hello, EXTRA_BYTES); ofpmsg_update_length(hello); test_send_hello(type, ofpbuf_data(hello), ofpbuf_size(hello), 0); ofpbuf_delete(hello); }
/* Try connecting and sending an extra-long hello, which should succeed (since * the specification says that implementations must accept and ignore extra * data). */ static void test_send_long_hello(struct ovs_cmdl_context *ctx) { const char *type = ctx->argv[1]; struct ofpbuf *hello; enum { EXTRA_BYTES = 8 }; hello = ofpraw_alloc_xid(OFPRAW_OFPT_HELLO, OFP13_VERSION, htonl(0x12345678), EXTRA_BYTES); ofpbuf_put_zeros(hello, EXTRA_BYTES); ofpmsg_update_length(hello); test_send_hello(type, hello->data, hello->size, 0); ofpbuf_delete(hello); }
void packet_destroy(struct packet *pkt) { /* If packet is saved in a buffer, do not destroy it, * if buffer is still valid */ if (pkt->buffer_id != NO_BUFFER) { if (dp_buffers_is_alive(pkt->dp->buffers, pkt->buffer_id)) { return; } else { dp_buffers_discard(pkt->dp->buffers, pkt->buffer_id, false); } } action_set_destroy(pkt->action_set); ofpbuf_delete(pkt->buffer); packet_handle_std_destroy(pkt->handle_std); free(pkt); }
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; }
struct ofpbuf * bundle_add(enum ofputil_protocol proto) { struct ofputil_bundle_add_msg msg; struct ofpbuf *fm; struct ofpbuf *add; memset(&msg, 0, sizeof(msg)); msg.bundle_id = 99999999; msg.flags = OFPBF_ATOMIC; fm = flow_mod(proto); clear_xid(fm); msg.msg = fm->data; add = ofputil_encode_bundle_add( ofputil_protocol_to_ofp_version(proto), &msg); ofpbuf_delete(fm); return add; }