X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=switch%2Fswitch-flow.c;h=8e3b7f7a866ecbe950bfb83ae0eb9814bf1db4f8;hb=40840f6a54b30ea018d62dc6f68a2f18e87e37d4;hp=732cea540d239b0682deab2a90f1211c317f1f0e;hpb=be25fa83e8f65d92b853bd20a3d1a594af352b92;p=sliver-openvswitch.git diff --git a/switch/switch-flow.c b/switch/switch-flow.c index 732cea540..8e3b7f7a8 100644 --- a/switch/switch-flow.c +++ b/switch/switch-flow.c @@ -37,51 +37,72 @@ #include #include #include -#include "buffer.h" -#include "openflow.h" +#include "ofpbuf.h" +#include "openflow/openflow.h" #include "packets.h" +#include "timeval.h" /* Internal function used to compare fields in flow. */ -static inline -int flow_fields_match(const struct flow *a, const struct flow *b, uint16_t w) +static inline int +flow_fields_match(const struct flow *a, const struct flow *b, uint16_t w, + uint32_t src_mask, uint32_t dst_mask) { return ((w & OFPFW_IN_PORT || a->in_port == b->in_port) && (w & OFPFW_DL_VLAN || a->dl_vlan == b->dl_vlan) - && (w & OFPFW_DL_SRC || !memcmp(a->dl_src, b->dl_src, ETH_ADDR_LEN)) - && (w & OFPFW_DL_DST || !memcmp(a->dl_dst, b->dl_dst, ETH_ADDR_LEN)) + && (w & OFPFW_DL_SRC || eth_addr_equals(a->dl_src, b->dl_src)) + && (w & OFPFW_DL_DST || eth_addr_equals(a->dl_dst, b->dl_dst)) && (w & OFPFW_DL_TYPE || a->dl_type == b->dl_type) - && (w & OFPFW_NW_SRC || a->nw_src == b->nw_src) - && (w & OFPFW_NW_DST || a->nw_dst == b->nw_dst) + && !((a->nw_src ^ b->nw_src) & src_mask) + && !((a->nw_dst ^ b->nw_dst) & dst_mask) && (w & OFPFW_NW_PROTO || a->nw_proto == b->nw_proto) && (w & OFPFW_TP_SRC || a->tp_src == b->tp_src) && (w & OFPFW_TP_DST || a->tp_dst == b->tp_dst)); } +static uint32_t make_nw_mask(int n_wild_bits) +{ + n_wild_bits &= (1u << OFPFW_NW_SRC_BITS) - 1; + return n_wild_bits < 32 ? htonl(~((1u << n_wild_bits) - 1)) : 0; +} + /* Returns nonzero if 'a' and 'b' match, that is, if their fields are equal - * modulo wildcards, zero otherwise. */ -inline -int flow_matches(const struct sw_flow_key *a, const struct sw_flow_key *b) + * modulo wildcards in 'b', zero otherwise. */ +inline int +flow_matches_1wild(const struct sw_flow_key *a, const struct sw_flow_key *b) { - return flow_fields_match(&a->flow, &b->flow, a->wildcards | b->wildcards); + return flow_fields_match(&a->flow, &b->flow, b->wildcards, + b->nw_src_mask, b->nw_dst_mask); +} + +/* Returns nonzero if 'a' and 'b' match, that is, if their fields are equal + * modulo wildcards in 'a' or 'b', zero otherwise. */ +inline int +flow_matches_2wild(const struct sw_flow_key *a, const struct sw_flow_key *b) +{ + return flow_fields_match(&a->flow, &b->flow, a->wildcards | b->wildcards, + a->nw_src_mask & b->nw_src_mask, + a->nw_dst_mask & b->nw_dst_mask); } /* Returns nonzero if 't' (the table entry's key) and 'd' (the key - * describing the deletion) match, that is, if their fields are + * describing the match) match, that is, if their fields are * equal modulo wildcards, zero otherwise. If 'strict' is nonzero, the * wildcards must match in both 't_key' and 'd_key'. Note that the * table's wildcards are ignored unless 'strict' is set. */ -inline -int flow_del_matches(const struct sw_flow_key *t, const struct sw_flow_key *d, int strict) +int +flow_matches_desc(const struct sw_flow_key *t, const struct sw_flow_key *d, + int strict) { - if (strict && t->wildcards != d->wildcards) + if (strict && d->wildcards != t->wildcards) { return 0; - - return flow_fields_match(&t->flow, &d->flow, d->wildcards); + } + return flow_matches_1wild(t, d); } -void flow_extract_match(struct sw_flow_key* to, const struct ofp_match* from) +void +flow_extract_match(struct sw_flow_key* to, const struct ofp_match* from) { - to->wildcards = ntohs(from->wildcards) & OFPFW_ALL; + to->wildcards = ntohl(from->wildcards) & OFPFW_ALL; to->flow.reserved = 0; to->flow.in_port = from->in_port; to->flow.dl_vlan = from->dl_vlan; @@ -93,7 +114,7 @@ void flow_extract_match(struct sw_flow_key* to, const struct ofp_match* from) to->flow.tp_src = to->flow.tp_dst = 0; #define OFPFW_TP (OFPFW_TP_SRC | OFPFW_TP_DST) -#define OFPFW_NW (OFPFW_NW_SRC | OFPFW_NW_DST | OFPFW_NW_PROTO) +#define OFPFW_NW (OFPFW_NW_SRC_MASK | OFPFW_NW_DST_MASK | OFPFW_NW_PROTO) if (to->wildcards & OFPFW_DL_TYPE) { /* Can't sensibly match on network or transport headers if the * data link type is unknown. */ @@ -123,11 +144,16 @@ void flow_extract_match(struct sw_flow_key* to, const struct ofp_match* from) * instead of falling into table-linear. */ to->wildcards &= ~(OFPFW_NW | OFPFW_TP); } + + /* We set these late because code above adjusts to->wildcards. */ + to->nw_src_mask = make_nw_mask(to->wildcards >> OFPFW_NW_SRC_SHIFT); + to->nw_dst_mask = make_nw_mask(to->wildcards >> OFPFW_NW_DST_SHIFT); } -void flow_fill_match(struct ofp_match* to, const struct sw_flow_key* from) +void +flow_fill_match(struct ofp_match* to, const struct sw_flow_key* from) { - to->wildcards = htons(from->wildcards); + to->wildcards = htonl(from->wildcards); to->in_port = from->flow.in_port; to->dl_vlan = from->flow.dl_vlan; memcpy(to->dl_src, from->flow.dl_src, ETH_ADDR_LEN); @@ -138,41 +164,68 @@ void flow_fill_match(struct ofp_match* to, const struct sw_flow_key* from) to->nw_proto = from->flow.nw_proto; to->tp_src = from->flow.tp_src; to->tp_dst = from->flow.tp_dst; - memset(to->pad, '\0', sizeof(to->pad)); + to->pad = 0; } -/* Allocates and returns a new flow with 'n_actions' action, using allocation - * flags 'flags'. Returns the new flow or a null pointer on failure. */ -struct sw_flow *flow_alloc(int n_actions) +/* Allocates and returns a new flow with room for 'actions_len' actions. + * Returns the new flow or a null pointer on failure. */ +struct sw_flow * +flow_alloc(size_t actions_len) { + struct sw_flow_actions *sfa; + size_t size = sizeof *sfa + actions_len; struct sw_flow *flow = malloc(sizeof *flow); if (!flow) return NULL; - flow->n_actions = n_actions; - flow->actions = malloc(n_actions * sizeof *flow->actions); - if (!flow->actions && n_actions > 0) { + sfa = malloc(size); + if (!sfa) { free(flow); return NULL; } + sfa->actions_len = actions_len; + flow->sf_acts = sfa; return flow; } /* Frees 'flow' immediately. */ -void flow_free(struct sw_flow *flow) +void +flow_free(struct sw_flow *flow) { if (!flow) { return; } - free(flow->actions); + free(flow->sf_acts); free(flow); } +/* Copies 'actions' into a newly allocated structure for use by 'flow' + * and frees the structure that defined the previous actions. */ +void flow_replace_acts(struct sw_flow *flow, + const struct ofp_action_header *actions, size_t actions_len) +{ + struct sw_flow_actions *sfa; + int size = sizeof *sfa + actions_len; + + sfa = malloc(size); + if (unlikely(!sfa)) + return; + + sfa->actions_len = actions_len; + memcpy(sfa->actions, actions, actions_len); + + free(flow->sf_acts); + flow->sf_acts = sfa; + + return; +} + /* Prints a representation of 'key' to the kernel log. */ -void print_flow(const struct sw_flow_key *key) +void +print_flow(const struct sw_flow_key *key) { const struct flow *f = &key->flow; - printf("wild%04x port%04x:vlan%04x mac%02x:%02x:%02x:%02x:%02x:%02x" + printf("wild%08x port%04x:vlan%04x mac%02x:%02x:%02x:%02x:%02x:%02x" "->%02x:%02x:%02x:%02x:%02x:%02x " "proto%04x ip%u.%u.%u.%u->%u.%u.%u.%u port%d->%d\n", key->wildcards, ntohs(f->in_port), ntohs(f->dl_vlan), @@ -192,20 +245,25 @@ void print_flow(const struct sw_flow_key *key) ntohs(f->tp_src), ntohs(f->tp_dst)); } -int flow_timeout(struct sw_flow *flow) +bool flow_timeout(struct sw_flow *flow) { - if (flow->max_idle == OFP_FLOW_PERMANENT) - return 0; - - /* FIXME */ - return time(0) > flow->timeout; + time_t now = time_now(); + if (flow->idle_timeout != OFP_FLOW_PERMANENT + && now > flow->used + flow->idle_timeout) { + flow->reason = OFPER_IDLE_TIMEOUT; + return true; + } else if (flow->hard_timeout != OFP_FLOW_PERMANENT + && now > flow->created + flow->hard_timeout) { + flow->reason = OFPER_HARD_TIMEOUT; + return true; + } else { + return false; + } } -void flow_used(struct sw_flow *flow, struct buffer *buffer) +void flow_used(struct sw_flow *flow, struct ofpbuf *buffer) { - if (flow->max_idle != OFP_FLOW_PERMANENT) - flow->timeout = time(0) + flow->max_idle; - + flow->used = time_now(); flow->packet_count++; flow->byte_count += buffer->size; }