From 1936cc1c68546e84b9a5cb817490681f3fcc1cd7 Mon Sep 17 00:00:00 2001 From: Justin Pettit Date: Mon, 2 Nov 2009 17:28:28 -0800 Subject: [PATCH] Implement flow cookies in user datapath. --- include/openflow/nicira-ext.h | 3 ++- lib/ofp-print.c | 17 ++++++++++------- udatapath/datapath.c | 4 ++++ udatapath/switch-flow.h | 1 + utilities/dpctl.c | 33 ++++++++++++++++++++++----------- 5 files changed, 39 insertions(+), 19 deletions(-) diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h index 8fdd004..727864a 100644 --- a/include/openflow/nicira-ext.h +++ b/include/openflow/nicira-ext.h @@ -171,6 +171,7 @@ OFP_ASSERT(sizeof(struct nx_flow_end_config) == 20); struct nx_flow_end { struct nicira_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 NXFER_*. */ @@ -189,6 +190,6 @@ struct nx_flow_end { uint64_t packet_count; uint64_t byte_count; }; -OFP_ASSERT(sizeof(struct nx_flow_end) == 104); +OFP_ASSERT(sizeof(struct nx_flow_end) == 112); #endif /* openflow/nicira-ext.h */ diff --git a/lib/ofp-print.c b/lib/ofp-print.c index 3ba0716..9cda46d 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -749,8 +749,9 @@ 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 flg:%#x ", - ntohs(ofm->idle_timeout), ntohs(ofm->hard_timeout), + ds_put_format(string, "cookie:%"PRIu64" idle:%d hard:%d pri:%d buf:%#x flg:%#x ", + 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)); ofp_print_actions(string, ofm->actions, @@ -783,12 +784,13 @@ ofp_print_flow_removed(struct ds *string, const void *oh, size_t len UNUSED, break; } ds_put_format(string, - " pri%"PRIu16" secs%"PRIu32" nsecs%"PRIu32" idle%"PRIu16"", + " cookie%"PRIu64" pri%"PRIu16" secs%"PRIu32" nsecs%"PRIu32"" + " idle%"PRIu16" pkts%"PRIu64" bytes%"PRIu64"\n", + ntohll(ofe->cookie), ofe->match.wildcards ? ntohs(ofe->priority) : (uint16_t)-1, ntohl(ofe->duration_sec), ntohl(ofe->duration_nsec), - ntohs(ofe->idle_timeout)); - ds_put_format(string, - " pkts%"PRIu64" bytes%"PRIu64"\n", ntohll(ofe->packet_count), + ntohs(ofe->idle_timeout), + ntohll(ofe->packet_count), ntohll(ofe->byte_count)); } @@ -991,7 +993,8 @@ ofp_flow_stats_reply(struct ds *string, const void *body_, size_t len, break; } - ds_put_format(string, " duration_sec=%"PRIu32"s, ", + ds_put_format(string, " cookie=%"PRIu64", ", ntohll(fs->cookie)); + ds_put_format(string, "duration_sec=%"PRIu32"s, ", ntohl(fs->duration_sec)); ds_put_format(string, "duration_nsec=%"PRIu32"s, ", ntohl(fs->duration_nsec)); diff --git a/udatapath/datapath.c b/udatapath/datapath.c index 6c41de3..88763f2 100644 --- a/udatapath/datapath.c +++ b/udatapath/datapath.c @@ -762,6 +762,7 @@ dp_send_flow_end(struct datapath *dp, struct sw_flow *flow, flow_fill_match(&ofr->match, &flow->key.flow, flow->key.wildcards); + ofr->cookie = htonll(flow->cookie); ofr->priority = htons(flow->priority); ofr->reason = reason; @@ -815,6 +816,7 @@ fill_flow_stats(struct ofpbuf *buffer, struct sw_flow *flow, ofs->match.tp_dst = flow->key.flow.tp_dst; ofs->duration_sec = htonl(sec); ofs->duration_nsec = htonl((tdiff - (sec * 1000)) * 1000000); + ofs->cookie = htonll(flow->cookie); ofs->priority = htons(flow->priority); ofs->idle_timeout = htons(flow->idle_timeout); ofs->hard_timeout = htons(flow->hard_timeout); @@ -1036,6 +1038,7 @@ add_flow(struct datapath *dp, const struct sender *sender, } /* Fill out flow. */ + flow->cookie = ntohll(ofm->cookie); flow->idle_timeout = ntohs(ofm->idle_timeout); flow->hard_timeout = ntohs(ofm->hard_timeout); flow->send_flow_rem = (ntohs(ofm->flags) & OFPFF_SEND_FLOW_REM) ? 1 : 0; @@ -1110,6 +1113,7 @@ mod_flow(struct datapath *dp, const struct sender *sender, strict, ofm->actions, actions_len, (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0)) { /* Fill out flow. */ + flow->cookie = ntohll(ofm->cookie); flow->idle_timeout = ntohs(ofm->idle_timeout); flow->hard_timeout = ntohs(ofm->hard_timeout); flow->send_flow_rem = (ntohs(ofm->flags) & OFPFF_SEND_FLOW_REM) ? 1 : 0; diff --git a/udatapath/switch-flow.h b/udatapath/switch-flow.h index 049b6e9..6821b4d 100644 --- a/udatapath/switch-flow.h +++ b/udatapath/switch-flow.h @@ -57,6 +57,7 @@ struct sw_flow_actions { struct sw_flow { struct sw_flow_key key; + uint64_t cookie; /* Opaque controller-issued identifier. */ uint16_t priority; /* Only used on entries with wildcards. */ uint16_t idle_timeout; /* Idle time before discarding (seconds). */ uint16_t hard_timeout; /* Hard expiration time (seconds) */ diff --git a/utilities/dpctl.c b/utilities/dpctl.c index cd344f5..55a0b35 100644 --- a/utilities/dpctl.c +++ b/utilities/dpctl.c @@ -938,7 +938,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; @@ -959,6 +960,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, "actions"); if (!act_str) { @@ -1007,6 +1011,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")) { @@ -1042,7 +1048,7 @@ do_dump_flows(const struct settings *s UNUSED, 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); @@ -1058,7 +1064,7 @@ do_dump_aggregate(const struct settings *s UNUSED, 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); @@ -1074,6 +1080,7 @@ do_add_flow(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) struct ofpbuf *buffer; struct ofp_flow_mod *ofm; uint16_t priority, idle_timeout, hard_timeout; + uint64_t cookie; uint8_t table_id; struct ofp_match match; @@ -1081,10 +1088,12 @@ do_add_flow(const struct settings *s UNUSED, int argc 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, - &table_id, NULL, &priority, &idle_timeout, &hard_timeout); + &table_id, 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 = table_id == EMERG_TABLE_ID ? 0 : htons(idle_timeout); ofm->hard_timeout = table_id == EMERG_TABLE_ID ? 0 : htons(hard_timeout); ofm->buffer_id = htonl(UINT32_MAX); @@ -1092,7 +1101,6 @@ do_add_flow(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) ofm->flags = htons(OFPFF_SEND_FLOW_REM); if (table_id == EMERG_TABLE_ID) ofm->flags |= htons(OFPFF_EMERG); - ofm->reserved = htonl(0); open_vconn(argv[1], &vconn); send_openflow_buffer(vconn, buffer); @@ -1116,6 +1124,7 @@ do_add_flows(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) struct ofpbuf *buffer; struct ofp_flow_mod *ofm; uint16_t priority, idle_timeout, hard_timeout; + uint64_t cookie; uint8_t table_id; struct ofp_match match; @@ -1137,10 +1146,12 @@ do_add_flows(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) * call. */ ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer); str_to_flow(line, &match, buffer, - &table_id, NULL, &priority, &idle_timeout, &hard_timeout); + &table_id, 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 = table_id == EMERG_TABLE_ID ? 0 : htons(idle_timeout); ofm->hard_timeout = table_id == EMERG_TABLE_ID ? 0 : htons(hard_timeout); ofm->buffer_id = htonl(UINT32_MAX); @@ -1148,7 +1159,6 @@ do_add_flows(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) ofm->flags = htons(OFPFF_SEND_FLOW_REM); if (table_id == EMERG_TABLE_ID) ofm->flags |= htons(OFPFF_EMERG); - ofm->reserved = htonl(0); send_openflow_buffer(vconn, buffer); } @@ -1160,6 +1170,7 @@ static void do_mod_flows(const struct settings *s, int argc UNUSED, char *argv[]) { uint16_t priority, idle_timeout, hard_timeout; + uint64_t cookie; uint8_t table_id; struct vconn *vconn; struct ofpbuf *buffer; @@ -1168,19 +1179,20 @@ do_mod_flows(const struct settings *s, int argc UNUSED, char *argv[]) /* Parse and send. */ ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer); str_to_flow(argv[2], &ofm->match, buffer, - &table_id, NULL, &priority, &idle_timeout, &hard_timeout); + &table_id, NULL, &priority, &idle_timeout, &hard_timeout, + &cookie); if (s->strict) { ofm->command = htons(OFPFC_MODIFY_STRICT); } else { ofm->command = htons(OFPFC_MODIFY); } + ofm->cookie = htonll(cookie); ofm->idle_timeout = table_id == EMERG_TABLE_ID ? 0 : htons(idle_timeout); ofm->hard_timeout = table_id == EMERG_TABLE_ID ? 0 : htons(hard_timeout); ofm->buffer_id = htonl(UINT32_MAX); if (table_id == EMERG_TABLE_ID) ofm->flags = htons(OFPFF_EMERG); ofm->priority = htons(priority); - ofm->reserved = htonl(0); open_vconn(argv[1], &vconn); send_openflow_buffer(vconn, buffer); @@ -1199,7 +1211,7 @@ static void do_del_flows(const struct settings *s, 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, - &table_id, &out_port, &priority, NULL, NULL); + &table_id, &out_port, &priority, NULL, NULL, NULL); if (s->strict) { ofm->command = htons(OFPFC_DELETE_STRICT); } else { @@ -1212,7 +1224,6 @@ static void do_del_flows(const struct settings *s, int argc, char *argv[]) ofm->flags = htons(OFPFF_EMERG); ofm->out_port = htons(out_port); ofm->priority = htons(priority); - ofm->reserved = htonl(0); open_vconn(argv[1], &vconn); send_openflow_buffer(vconn, buffer);