X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=controller%2Fcontroller.c;h=9355c02bbbaac89165f5a5aebf5c16b4a8812168;hb=60a87c9b0032346568485ad40fd72ea1f72b8674;hp=f4a53f5d95847c6a81a12cf8a1b18e686d2bb68c;hpb=a9111b60153ba0a726a1711f2b7969d2691fbb0f;p=sliver-openvswitch.git diff --git a/controller/controller.c b/controller/controller.c index f4a53f5d9..9355c02bb 100644 --- a/controller/controller.c +++ b/controller/controller.c @@ -1,22 +1,34 @@ -/* Copyright (C) 2007 Board of Trustees, Leland Stanford Jr. University. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. */ #include @@ -36,10 +48,11 @@ #include "flow.h" #include "hash.h" #include "list.h" -#include "mac.h" #include "ofp-print.h" #include "openflow.h" +#include "packets.h" #include "poll-loop.h" +#include "queue.h" #include "time.h" #include "util.h" #include "vconn-ssl.h" @@ -58,10 +71,9 @@ struct switch_ { struct vconn *vconn; uint64_t datapath_id; - time_t last_control_hello; + time_t last_features_request; - int n_txq; - struct buffer *txq, *tx_tail; + struct queue txq; }; /* -H, --hub: Use dumb hub instead of learning switch? */ @@ -79,7 +91,7 @@ static void close_switch(struct switch_ *); static void queue_tx(struct switch_ *, struct buffer *); -static void send_control_hello(struct switch_ *); +static void send_features_request(struct switch_ *); static int do_switch_recv(struct switch_ *this); static int do_switch_send(struct switch_ *this); @@ -150,6 +162,7 @@ main(int argc, char *argv[]) if (retval) { break; } + printf("accept!\n"); switches[n_switches++] = new_switch("tcp", new_vconn); } } else { @@ -185,7 +198,7 @@ main(int argc, char *argv[]) } } else { vconn_recv_wait(this->vconn); - if (this->n_txq) { + if (this->txq.n) { vconn_send_wait(this->vconn); } } @@ -214,19 +227,13 @@ static int do_switch_send(struct switch_ *this) { int retval = 0; - if (this->n_txq) { - struct buffer *next = this->txq->next; - - retval = vconn_send(this->vconn, this->txq); + if (this->txq.n) { + struct buffer *next = this->txq.head->next; + retval = vconn_send(this->vconn, this->txq.head); if (retval) { return retval; } - - this->txq = next; - if (this->txq == NULL) { - this->tx_tail = NULL; - } - this->n_txq--; + queue_advance_head(&this->txq, next); return 0; } return EAGAIN; @@ -254,12 +261,10 @@ new_switch(const char *name, struct vconn *vconn) memset(this, 0, sizeof *this); this->name = xstrdup(name); this->vconn = vconn; - this->n_txq = 0; - this->txq = NULL; - this->tx_tail = NULL; - this->last_control_hello = 0; + queue_init(&this->txq); + this->last_features_request = 0; if (!vconn_is_passive(vconn)) { - send_control_hello(this); + send_features_request(this); } return this; } @@ -268,93 +273,60 @@ static void close_switch(struct switch_ *this) { if (this) { - struct buffer *cur, *next; - + printf("dropped!\n"); free(this->name); vconn_close(this->vconn); - for (cur = this->txq; cur != NULL; cur = next) { - next = cur->next; - buffer_delete(cur); - } + queue_destroy(&this->txq); free(this); } } static void -send_control_hello(struct switch_ *this) +send_features_request(struct switch_ *this) { time_t now = time(0); - if (now >= this->last_control_hello + 1) { + if (now >= this->last_features_request + 1) { struct buffer *b; - struct ofp_control_hello *och; + struct ofp_header *ofr; + struct ofp_switch_config *osc; + /* Send OFPT_SET_CONFIG. */ b = buffer_new(0); - och = buffer_put_uninit(b, sizeof *och); - memset(och, 0, sizeof *och); - och->header.version = OFP_VERSION; - och->header.length = htons(sizeof *och); - - och->version = htonl(OFP_VERSION); - och->flags = htons(OFP_CHELLO_SEND_FLOW_EXP); - och->miss_send_len = htons(OFP_DEFAULT_MISS_SEND_LEN); + osc = buffer_put_uninit(b, sizeof *osc); + memset(osc, 0, sizeof *osc); + osc->header.type = OFPT_SET_CONFIG; + osc->header.version = OFP_VERSION; + osc->header.length = htons(sizeof *osc); + osc->flags = htons(OFPC_SEND_FLOW_EXP); + osc->miss_send_len = htons(OFP_DEFAULT_MISS_SEND_LEN); queue_tx(this, b); - this->last_control_hello = now; - } -} + /* Send OFPT_FEATURES_REQUEST. */ + b = buffer_new(0); + ofr = buffer_put_uninit(b, sizeof *ofr); + memset(ofr, 0, sizeof *ofr); + ofr->type = OFPT_FEATURES_REQUEST; + ofr->version = OFP_VERSION; + ofr->length = htons(sizeof *ofr); + queue_tx(this, b); -static void -check_txq(struct switch_ *this UNUSED) -{ -#if 0 - struct buffer *iter; - size_t n; - - assert(this->n_txq == 0 - ? this->txq == NULL && this->tx_tail == NULL - : this->txq != NULL && this->tx_tail != NULL); - - n = 0; - for (iter = this->txq; iter != NULL; iter = iter->next) { - n++; - assert((iter->next != NULL) == (iter != this->tx_tail)); + this->last_features_request = now; } - assert(n == this->n_txq); -#endif } static void queue_tx(struct switch_ *this, struct buffer *b) { - check_txq(this); - - b->next = NULL; - if (this->n_txq++) { - this->tx_tail->next = b; - } else { - this->txq = b; - } - this->tx_tail = b; - - check_txq(this); + queue_push_tail(&this->txq, b); } static void process_packet(struct switch_ *sw, struct buffer *msg) { static const size_t min_size[UINT8_MAX + 1] = { - [0 ... UINT8_MAX] = SIZE_MAX, - [OFPT_CONTROL_HELLO] = sizeof (struct ofp_control_hello), - [OFPT_DATA_HELLO] = sizeof (struct ofp_data_hello), + [0 ... UINT8_MAX] = sizeof (struct ofp_header), + [OFPT_FEATURES_REPLY] = sizeof (struct ofp_switch_features), [OFPT_PACKET_IN] = offsetof (struct ofp_packet_in, data), - [OFPT_PACKET_OUT] = sizeof (struct ofp_packet_out), - [OFPT_FLOW_MOD] = sizeof (struct ofp_flow_mod), - [OFPT_FLOW_EXPIRED] = sizeof (struct ofp_flow_expired), - [OFPT_TABLE] = sizeof (struct ofp_table), - [OFPT_PORT_MOD] = sizeof (struct ofp_port_mod), - [OFPT_PORT_STATUS] = sizeof (struct ofp_port_status), - [OFPT_FLOW_STAT_REQUEST] = sizeof (struct ofp_flow_stat_request), - [OFPT_FLOW_STAT_REPLY] = sizeof (struct ofp_flow_stat_reply), }; struct ofp_header *oh; @@ -365,28 +337,26 @@ process_packet(struct switch_ *sw, struct buffer *msg) return; } - if (oh->type == OFPT_DATA_HELLO) { - struct ofp_data_hello *odh = msg->data; - sw->datapath_id = odh->datapath_id; + if (oh->type == OFPT_FEATURES_REPLY) { + struct ofp_switch_features *osf = msg->data; + sw->datapath_id = osf->datapath_id; } else if (sw->datapath_id == 0) { - send_control_hello(sw); - return; - } - - if (oh->type == OFPT_PACKET_IN) { - if (sw->n_txq >= MAX_TXQ) { + send_features_request(sw); + } else if (oh->type == OFPT_PACKET_IN) { + struct ofp_packet_in *opi = msg->data; + if (sw->txq.n >= MAX_TXQ) { + /* FIXME: ratelimit. */ VLOG_WARN("%s: tx queue overflow", sw->name); } else if (noflow) { - process_noflow(sw, msg->data); + process_noflow(sw, opi); } else if (hub) { - process_hub(sw, msg->data); + process_hub(sw, opi); } else { - process_switch(sw, msg->data); + process_switch(sw, opi); } - return; + } else { + ofp_print(stdout, msg->data, msg->size, 2); } - - ofp_print(stdout, msg->data, msg->size, 2); } static void @@ -492,7 +462,7 @@ process_switch(struct switch_ *sw, struct ofp_packet_in *opi) flow_extract(&pkt, ntohs(opi->in_port), &flow); /* Learn the source. */ - if (!mac_is_multicast(flow.dl_src)) { + if (!eth_addr_is_multicast(flow.dl_src)) { struct mac_source *src; struct list *bucket; bool found; @@ -501,7 +471,7 @@ process_switch(struct switch_ *sw, struct ofp_packet_in *opi) found = false; LIST_FOR_EACH (src, struct mac_source, hash_list, bucket) { if (src->datapath_id == sw->datapath_id - && mac_equals(src->mac, flow.dl_src)) { + && eth_addr_equals(src->mac, flow.dl_src)) { found = true; break; } @@ -536,24 +506,26 @@ process_switch(struct switch_ *sw, struct ofp_packet_in *opi) if (ntohs(flow.in_port) != src->port) { src->port = ntohs(flow.in_port); - VLOG_DBG("learned that "MAC_FMT" is on datapath %"PRIx64" port %d", - MAC_ARGS(src->mac), ntohll(src->datapath_id), + VLOG_DBG("learned that "ETH_ADDR_FMT" is on datapath %" + PRIx64" port %d", + ETH_ADDR_ARGS(src->mac), ntohll(src->datapath_id), src->port); } } else { - VLOG_DBG("multicast packet source "MAC_FMT, MAC_ARGS(flow.dl_src)); + VLOG_DBG("multicast packet source "ETH_ADDR_FMT, + ETH_ADDR_ARGS(flow.dl_src)); } /* Figure out the destination. */ out_port = OFPP_FLOOD; - if (!mac_is_multicast(flow.dl_dst)) { + if (!eth_addr_is_multicast(flow.dl_dst)) { struct mac_source *dst; struct list *bucket; bucket = mac_table_bucket(sw->datapath_id, flow.dl_dst); LIST_FOR_EACH (dst, struct mac_source, hash_list, bucket) { if (dst->datapath_id == sw->datapath_id - && mac_equals(dst->mac, flow.dl_dst)) { + && eth_addr_equals(dst->mac, flow.dl_dst)) { out_port = dst->port; break; }