From: Justin Pettit Date: Wed, 13 Jan 2010 07:22:22 +0000 (-0800) Subject: ofproto: Add support for flow cookies (OpenFlow 1.0) X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=39997502e46f49f4f7eaa994d1883c76e0c23451;p=openvswitch ofproto: Add support for flow cookies (OpenFlow 1.0) In OpenFlow 1.0, flows have been extended to include an opaque identifier, referred to as a cookie. The cookie is specified by the controller when the flow is installed; the cookie will be returned as part of each flow stats and flow removed message. NOTE: OVS at this point is not wire-compatible with OpenFlow 1.0 until the final commit in this Openflow 1.0 set. --- diff --git a/include/openflow/openflow.h b/include/openflow/openflow.h index 4835b8a9..2847aedd 100644 --- a/include/openflow/openflow.h +++ b/include/openflow/openflow.h @@ -543,6 +543,7 @@ enum ofp_flow_mod_flags { struct ofp_flow_mod { struct ofp_header header; struct ofp_match match; /* Fields to match */ + uint64_t cookie; /* Opaque controller-issued identifier. */ /* Flow actions. */ uint16_t command; /* One of OFPFC_*. */ @@ -556,12 +557,11 @@ struct ofp_flow_mod { output port. A value of OFPP_NONE indicates no restriction. */ uint16_t flags; /* One of OFPFF_*. */ - uint32_t reserved; /* Reserved for future use. */ struct ofp_action_header actions[0]; /* The action length is inferred from the length field in the header. */ }; -OFP_ASSERT(sizeof(struct ofp_flow_mod) == 68); +OFP_ASSERT(sizeof(struct ofp_flow_mod) == 72); /* Why was this flow removed? */ enum ofp_flow_removed_reason { @@ -574,6 +574,7 @@ enum ofp_flow_removed_reason { struct ofp_flow_removed { struct ofp_header header; struct ofp_match match; /* Description of fields. */ + uint64_t cookie; /* Opaque controller-issued identifier. */ uint16_t priority; /* Priority level of flow entry. */ uint8_t reason; /* One of OFPRR_*. */ @@ -585,7 +586,7 @@ struct ofp_flow_removed { uint64_t packet_count; uint64_t byte_count; }; -OFP_ASSERT(sizeof(struct ofp_flow_removed) == 80); +OFP_ASSERT(sizeof(struct ofp_flow_removed) == 88); /* Values for 'type' in ofp_error_message. These values are immutable: they * will not change in future versions of the protocol (although new values may @@ -753,12 +754,13 @@ struct ofp_flow_stats { when this is not an exact-match entry. */ uint16_t idle_timeout; /* Number of seconds idle before expiration. */ uint16_t hard_timeout; /* Number of seconds before expiration. */ - uint16_t pad2; /* Pad to 64 bits. */ + uint8_t pad2[2]; /* Align to 64 bits. */ + uint64_t cookie; /* Opaque controller-issued identifier. */ uint64_t packet_count; /* Number of packets in flow. */ uint64_t byte_count; /* Number of bytes in flow. */ struct ofp_action_header actions[0]; /* Actions. */ }; -OFP_ASSERT(sizeof(struct ofp_flow_stats) == 72); +OFP_ASSERT(sizeof(struct ofp_flow_stats) == 80); /* Body for ofp_stats_request of type OFPST_AGGREGATE. */ struct ofp_aggregate_stats_request { diff --git a/lib/ofp-print.c b/lib/ofp-print.c index 19058b45..700f3c4f 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -735,7 +735,8 @@ ofp_print_flow_mod(struct ds *string, const void *oh, size_t len, default: ds_put_format(string, " cmd:%d ", ntohs(ofm->command)); } - ds_put_format(string, "idle:%d hard:%d pri:%d buf:%#x flags:%"PRIx16" ", + ds_put_format(string, "cookie:%"PRIx64" idle:%d hard:%d pri:%d " + "buf:%#x flags:%"PRIx16" ", ntohll(ofm->cookie), ntohs(ofm->idle_timeout), ntohs(ofm->hard_timeout), ofm->match.wildcards ? ntohs(ofm->priority) : (uint16_t)-1, ntohl(ofm->buffer_id), ntohs(ofm->flags)); @@ -769,8 +770,8 @@ ofp_print_flow_removed(struct ds *string, const void *oh, break; } ds_put_format(string, - " pri%"PRIu16" secs%"PRIu32" idle%"PRIu16" pkts%"PRIu64 - " bytes%"PRIu64"\n", + " cookie%"PRIx64" pri%"PRIu16" secs%"PRIu32" idle%"PRIu16 + " pkts%"PRIu64" bytes%"PRIu64"\n", ntohll(ofr->cookie), ofr->match.wildcards ? ntohs(ofr->priority) : (uint16_t)-1, ntohl(ofr->duration), ntohs(ofr->idle_timeout), ntohll(ofr->packet_count), ntohll(ofr->byte_count)); @@ -984,7 +985,8 @@ ofp_flow_stats_reply(struct ds *string, const void *body_, size_t len, break; } - ds_put_format(string, " duration=%"PRIu32"s, ", ntohl(fs->duration)); + ds_put_format(string, " cookie=%"PRIu64"s, ", ntohll(fs->cookie)); + ds_put_format(string, "duration=%"PRIu32"s, ", ntohl(fs->duration)); ds_put_format(string, "table_id=%"PRIu8", ", fs->table_id); ds_put_format(string, "priority=%"PRIu16", ", fs->match.wildcards ? ntohs(fs->priority) : (uint16_t)-1); diff --git a/lib/vconn.c b/lib/vconn.c index 19a19786..de407448 100644 --- a/lib/vconn.c +++ b/lib/vconn.c @@ -886,6 +886,7 @@ make_flow_mod(uint16_t command, const flow_t *flow, size_t actions_len) ofm->header.version = OFP_VERSION; ofm->header.type = OFPT_FLOW_MOD; ofm->header.length = htons(size); + ofm->cookie = 0; ofm->match.wildcards = htonl(0); ofm->match.in_port = htons(flow->in_port == ODPP_LOCAL ? OFPP_LOCAL : flow->in_port); diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 14a425db..18d3e029 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -83,6 +83,8 @@ static int xlate_actions(const union ofp_action *in, size_t n_in, struct rule { struct cls_rule cr; + uint64_t flow_cookie; /* Controller-issued identifier. + (Kept in network-byte order.) */ uint16_t idle_timeout; /* In seconds from time of last use. */ uint16_t hard_timeout; /* In seconds from time of creation. */ bool send_flow_removed; /* Send a flow removed message? */ @@ -144,7 +146,7 @@ rule_is_hidden(const struct rule *rule) static struct rule *rule_create(struct ofproto *, struct rule *super, const union ofp_action *, size_t n_actions, uint16_t idle_timeout, uint16_t hard_timeout, - bool send_flow_removed); + uint64_t flow_cookie, bool send_flow_removed); static void rule_free(struct rule *); static void rule_destroy(struct ofproto *, struct rule *); static struct rule *rule_from_cls_rule(const struct cls_rule *); @@ -992,7 +994,7 @@ ofproto_add_flow(struct ofproto *p, struct rule *rule; rule = rule_create(p, NULL, actions, n_actions, idle_timeout >= 0 ? idle_timeout : 5 /* XXX */, - 0, false); + 0, 0, false); cls_rule_from_flow(&rule->cr, flow, wildcards, priority); rule_insert(p, rule, NULL, 0); } @@ -1404,11 +1406,12 @@ static struct rule * rule_create(struct ofproto *ofproto, struct rule *super, const union ofp_action *actions, size_t n_actions, uint16_t idle_timeout, uint16_t hard_timeout, - bool send_flow_removed) + uint64_t flow_cookie, bool send_flow_removed) { struct rule *rule = xzalloc(sizeof *rule); rule->idle_timeout = idle_timeout; rule->hard_timeout = hard_timeout; + rule->flow_cookie = flow_cookie; rule->used = rule->created = time_msec(); rule->send_flow_removed = send_flow_removed; rule->super = super; @@ -1571,7 +1574,7 @@ rule_create_subrule(struct ofproto *ofproto, struct rule *rule, { struct rule *subrule = rule_create(ofproto, rule, NULL, 0, rule->idle_timeout, rule->hard_timeout, - false); + 0, false); COVERAGE_INC(ofproto_subrule_create); cls_rule_from_flow(&subrule->cr, flow, 0, (rule->cr.priority <= UINT16_MAX ? UINT16_MAX @@ -2565,10 +2568,11 @@ flow_stats_cb(struct cls_rule *rule_, void *cbdata_) ofs->pad = 0; flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards, &ofs->match); ofs->duration = htonl((time_msec() - rule->created) / 1000); + ofs->cookie = rule->flow_cookie; ofs->priority = htons(rule->cr.priority); ofs->idle_timeout = htons(rule->idle_timeout); ofs->hard_timeout = htons(rule->hard_timeout); - ofs->pad2 = 0; + memset(ofs->pad2, 0, sizeof ofs->pad2); ofs->packet_count = htonll(packet_count); ofs->byte_count = htonll(byte_count); memcpy(ofs->actions, rule->actions, act_len); @@ -2819,7 +2823,7 @@ add_flow(struct ofproto *p, struct ofconn *ofconn, rule = rule_create(p, NULL, (const union ofp_action *) ofm->actions, n_actions, ntohs(ofm->idle_timeout), - ntohs(ofm->hard_timeout), + ntohs(ofm->hard_timeout), ofm->cookie, ofm->flags & htons(OFPFF_SEND_FLOW_REM)); cls_rule_from_match(&rule->cr, &ofm->match, ntohs(ofm->priority)); @@ -2861,6 +2865,7 @@ modify_flow(struct ofproto *p, const struct ofp_flow_mod *ofm, free(rule->actions); rule->actions = xmemdup(ofm->actions, actions_len); rule->n_actions = n_actions; + rule->flow_cookie = ofm->cookie; if (rule->cr.wc.wildcards) { COVERAGE_INC(ofproto_mod_wc_flow); @@ -3260,6 +3265,7 @@ compose_flow_removed(const struct rule *rule, long long int now, uint8_t reason) ofr = make_openflow(sizeof *ofr, OFPT_FLOW_REMOVED, &buf); flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards, &ofr->match); + ofr->cookie = rule->flow_cookie; ofr->priority = htons(rule->cr.priority); ofr->reason = reason; ofr->duration = htonl((now - rule->created) / 1000); diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c index 9dd80b11..1a4700cd 100644 --- a/utilities/ovs-ofctl.c +++ b/utilities/ovs-ofctl.c @@ -48,6 +48,7 @@ #include "timeval.h" #include "util.h" #include "vconn.h" +#include "xtoxll.h" #include "vlog.h" #define THIS_MODULE VLM_ofctl @@ -686,7 +687,8 @@ parse_field(const char *name, const struct field **f_out) static void str_to_flow(char *string, struct ofp_match *match, struct ofpbuf *actions, uint8_t *table_idx, uint16_t *out_port, uint16_t *priority, - uint16_t *idle_timeout, uint16_t *hard_timeout) + uint16_t *idle_timeout, uint16_t *hard_timeout, + uint64_t *cookie) { char *save_ptr = NULL; char *name; @@ -707,6 +709,9 @@ str_to_flow(char *string, struct ofp_match *match, struct ofpbuf *actions, if (hard_timeout) { *hard_timeout = OFP_FLOW_PERMANENT; } + if (cookie) { + *cookie = 0; + } if (actions) { char *act_str = strstr(string, "action"); if (!act_str) { @@ -755,6 +760,8 @@ str_to_flow(char *string, struct ofp_match *match, struct ofpbuf *actions, *idle_timeout = atoi(value); } else if (hard_timeout && !strcmp(name, "hard_timeout")) { *hard_timeout = atoi(value); + } else if (cookie && !strcmp(name, "cookie")) { + *cookie = atoi(value); } else if (parse_field(name, &f)) { void *data = (char *) match + f->offset; if (!strcmp(value, "*") || !strcmp(value, "ANY")) { @@ -793,7 +800,7 @@ do_dump_flows(int argc, char *argv[]) req = alloc_stats_request(sizeof *req, OFPST_FLOW, &request); str_to_flow(argc > 2 ? argv[2] : "", &req->match, NULL, - &req->table_id, &out_port, NULL, NULL, NULL); + &req->table_id, &out_port, NULL, NULL, NULL, NULL); memset(&req->pad, 0, sizeof req->pad); req->out_port = htons(out_port); @@ -809,7 +816,7 @@ do_dump_aggregate(int argc, char *argv[]) req = alloc_stats_request(sizeof *req, OFPST_AGGREGATE, &request); str_to_flow(argc > 2 ? argv[2] : "", &req->match, NULL, - &req->table_id, &out_port, NULL, NULL, NULL); + &req->table_id, &out_port, NULL, NULL, NULL, NULL); memset(&req->pad, 0, sizeof req->pad); req->out_port = htons(out_port); @@ -823,21 +830,23 @@ do_add_flow(int argc OVS_UNUSED, char *argv[]) struct ofpbuf *buffer; struct ofp_flow_mod *ofm; uint16_t priority, idle_timeout, hard_timeout; + uint64_t cookie; struct ofp_match match; /* Parse and send. str_to_flow() will expand and reallocate the data in * 'buffer', so we can't keep pointers to across the str_to_flow() call. */ make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer); str_to_flow(argv[2], &match, buffer, - NULL, NULL, &priority, &idle_timeout, &hard_timeout); + NULL, NULL, &priority, &idle_timeout, &hard_timeout, + &cookie); ofm = buffer->data; ofm->match = match; ofm->command = htons(OFPFC_ADD); + ofm->cookie = htonll(cookie); ofm->idle_timeout = htons(idle_timeout); ofm->hard_timeout = htons(hard_timeout); ofm->buffer_id = htonl(UINT32_MAX); ofm->priority = htons(priority); - ofm->reserved = htonl(0); open_vconn(argv[1], &vconn); send_openflow_buffer(vconn, buffer); @@ -861,6 +870,7 @@ do_add_flows(int argc OVS_UNUSED, char *argv[]) struct ofpbuf *buffer; struct ofp_flow_mod *ofm; uint16_t priority, idle_timeout, hard_timeout; + uint64_t cookie; struct ofp_match match; char *comment; @@ -881,15 +891,16 @@ do_add_flows(int argc OVS_UNUSED, char *argv[]) * call. */ make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer); str_to_flow(line, &match, buffer, - NULL, NULL, &priority, &idle_timeout, &hard_timeout); + NULL, NULL, &priority, &idle_timeout, &hard_timeout, + &cookie); ofm = buffer->data; ofm->match = match; ofm->command = htons(OFPFC_ADD); + ofm->cookie = htonll(cookie); ofm->idle_timeout = htons(idle_timeout); ofm->hard_timeout = htons(hard_timeout); ofm->buffer_id = htonl(UINT32_MAX); ofm->priority = htons(priority); - ofm->reserved = htonl(0); send_openflow_buffer(vconn, buffer); } @@ -901,6 +912,7 @@ static void do_mod_flows(int argc OVS_UNUSED, char *argv[]) { uint16_t priority, idle_timeout, hard_timeout; + uint64_t cookie; struct vconn *vconn; struct ofpbuf *buffer; struct ofp_flow_mod *ofm; @@ -910,7 +922,8 @@ do_mod_flows(int argc OVS_UNUSED, char *argv[]) * 'buffer', so we can't keep pointers to across the str_to_flow() call. */ make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer); str_to_flow(argv[2], &match, buffer, - NULL, NULL, &priority, &idle_timeout, &hard_timeout); + NULL, NULL, &priority, &idle_timeout, &hard_timeout, + &cookie); ofm = buffer->data; ofm->match = match; if (strict) { @@ -920,9 +933,9 @@ do_mod_flows(int argc OVS_UNUSED, char *argv[]) } ofm->idle_timeout = htons(idle_timeout); ofm->hard_timeout = htons(hard_timeout); + ofm->cookie = htonll(cookie); ofm->buffer_id = htonl(UINT32_MAX); ofm->priority = htons(priority); - ofm->reserved = htonl(0); open_vconn(argv[1], &vconn); send_openflow_buffer(vconn, buffer); @@ -940,7 +953,7 @@ static void do_del_flows(int argc, char *argv[]) /* Parse and send. */ ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer); str_to_flow(argc > 2 ? argv[2] : "", &ofm->match, NULL, NULL, - &out_port, &priority, NULL, NULL); + &out_port, &priority, NULL, NULL, NULL); if (strict) { ofm->command = htons(OFPFC_DELETE_STRICT); } else { @@ -951,7 +964,6 @@ static void do_del_flows(int argc, char *argv[]) ofm->buffer_id = htonl(UINT32_MAX); ofm->out_port = htons(out_port); ofm->priority = htons(priority); - ofm->reserved = htonl(0); open_vconn(argv[1], &vconn); send_openflow_buffer(vconn, buffer);