X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fodp-util.c;h=901dac3b4c80cba5649ff5a58af604632fde2127;hb=refs%2Fheads%2Fhotfix;hp=8fa3359493b11523fb43a729e06bf45c2e727210;hpb=3a8cfc5087a5b917055a472da1d1efa4e32768dd;p=sliver-openvswitch.git diff --git a/lib/odp-util.c b/lib/odp-util.c index 8fa335949..901dac3b4 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, 2011, 2012 Nicira Networks. + * Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,8 +14,8 @@ * limitations under the License. */ -#include #include +#include #include "odp-util.h" #include #include @@ -30,9 +30,8 @@ #include "flow.h" #include "netlink.h" #include "ofpbuf.h" -#include "openvswitch/tunnel.h" #include "packets.h" -#include "shash.h" +#include "simap.h" #include "timeval.h" #include "util.h" #include "vlog.h" @@ -49,7 +48,7 @@ VLOG_DEFINE_THIS_MODULE(odp_util); * from another. */ static const char *delimiters = ", \t\r\n"; -static int parse_odp_key_attr(const char *, const struct shash *port_names, +static int parse_odp_key_attr(const char *, const struct simap *port_names, struct ofpbuf *); static void format_odp_key_attr(const struct nlattr *a, struct ds *ds); @@ -166,6 +165,52 @@ format_odp_sample_action(struct ds *ds, const struct nlattr *attr) ds_put_format(ds, "))"); } +static const char * +slow_path_reason_to_string(enum slow_path_reason bit) +{ + switch (bit) { + case SLOW_CFM: + return "cfm"; + case SLOW_LACP: + return "lacp"; + case SLOW_STP: + return "stp"; + case SLOW_IN_BAND: + return "in_band"; + case SLOW_CONTROLLER: + return "controller"; + case SLOW_MATCH: + return "match"; + default: + return NULL; + } +} + +static void +format_slow_path_reason(struct ds *ds, uint32_t slow) +{ + uint32_t bad = 0; + + while (slow) { + uint32_t bit = rightmost_1bit(slow); + const char *s; + + s = slow_path_reason_to_string(bit); + if (s) { + ds_put_format(ds, "%s,", s); + } else { + bad |= bit; + } + + slow &= ~bit; + } + + if (bad) { + ds_put_format(ds, "0x%"PRIx32",", bad); + } + ds_chomp(ds, ','); +} + static void format_odp_userspace_action(struct ds *ds, const struct nlattr *attr) { @@ -185,17 +230,31 @@ format_odp_userspace_action(struct ds *ds, const struct nlattr *attr) if (a[OVS_USERSPACE_ATTR_USERDATA]) { uint64_t userdata = nl_attr_get_u64(a[OVS_USERSPACE_ATTR_USERDATA]); - struct user_action_cookie cookie; + union user_action_cookie cookie; memcpy(&cookie, &userdata, sizeof cookie); - if (cookie.type == USER_ACTION_COOKIE_SFLOW) { - ds_put_format(ds, ",sFlow,n_output=%"PRIu8"," - "vid=%"PRIu16",pcp=%"PRIu8",ifindex=%"PRIu32, - cookie.n_output, vlan_tci_to_vid(cookie.vlan_tci), - vlan_tci_to_pcp(cookie.vlan_tci), cookie.data); - } else { + switch (cookie.type) { + case USER_ACTION_COOKIE_SFLOW: + ds_put_format(ds, ",sFlow(" + "vid=%"PRIu16",pcp=%"PRIu8",output=%"PRIu32")", + vlan_tci_to_vid(cookie.sflow.vlan_tci), + vlan_tci_to_pcp(cookie.sflow.vlan_tci), + cookie.sflow.output); + break; + + case USER_ACTION_COOKIE_SLOW_PATH: + ds_put_cstr(ds, ",slow_path("); + if (cookie.slow_path.reason) { + format_slow_path_reason(ds, cookie.slow_path.reason); + } + ds_put_char(ds, ')'); + break; + + case USER_ACTION_COOKIE_UNSPEC: + default: ds_put_format(ds, ",userdata=0x%"PRIx64, userdata); + break; } } @@ -295,7 +354,7 @@ format_odp_actions(struct ds *ds, const struct nlattr *actions, } static int -parse_odp_action(const char *s, const struct shash *port_names, +parse_odp_action(const char *s, const struct simap *port_names, struct ofpbuf *actions) { /* Many of the sscanf calls in this function use oversized destination @@ -320,31 +379,29 @@ parse_odp_action(const char *s, const struct shash *port_names, if (port_names) { int len = strcspn(s, delimiters); - struct shash_node *node; + struct simap_node *node; - node = shash_find_len(port_names, s, len); + node = simap_find_len(port_names, s, len); if (node) { - nl_msg_put_u32(actions, OVS_ACTION_ATTR_OUTPUT, - (uintptr_t) node->data); + nl_msg_put_u32(actions, OVS_ACTION_ATTR_OUTPUT, node->data); return len; } } { unsigned long long int pid; - unsigned long long int ifindex; + unsigned long long int output; char userdata_s[32]; - int n_output; int vid, pcp; int n = -1; if (sscanf(s, "userspace(pid=%lli)%n", &pid, &n) > 0 && n > 0) { odp_put_userspace_action(pid, NULL, actions); return n; - } else if (sscanf(s, "userspace(pid=%lli,sFlow,n_output=%i,vid=%i," - "pcp=%i,ifindex=%lli)%n", &pid, &n_output, - &vid, &pcp, &ifindex, &n) > 0 && n > 0) { - struct user_action_cookie cookie; + } else if (sscanf(s, "userspace(pid=%lli,sFlow(vid=%i," + "pcp=%i,output=%lli))%n", + &pid, &vid, &pcp, &output, &n) > 0 && n > 0) { + union user_action_cookie cookie; uint16_t tci; tci = vid | (pcp << VLAN_PCP_SHIFT); @@ -353,15 +410,50 @@ parse_odp_action(const char *s, const struct shash *port_names, } cookie.type = USER_ACTION_COOKIE_SFLOW; - cookie.n_output = n_output; - cookie.vlan_tci = htons(tci); - cookie.data = ifindex; + cookie.sflow.vlan_tci = htons(tci); + cookie.sflow.output = output; + odp_put_userspace_action(pid, &cookie, actions); + return n; + } else if (sscanf(s, "userspace(pid=%lli,slow_path(%n", &pid, &n) > 0 + && n > 0) { + union user_action_cookie cookie; + + cookie.type = USER_ACTION_COOKIE_SLOW_PATH; + cookie.slow_path.unused = 0; + cookie.slow_path.reason = 0; + + while (s[n] != ')') { + uint32_t bit; + + for (bit = 1; bit; bit <<= 1) { + const char *reason = slow_path_reason_to_string(bit); + size_t len = strlen(reason); + + if (reason + && !strncmp(s + n, reason, len) + && (s[n + len] == ',' || s[n + len] == ')')) + { + cookie.slow_path.reason |= bit; + n += len + (s[n + len] == ','); + break; + } + } + + if (!bit) { + return -EINVAL; + } + } + if (s[n + 1] != ')') { + return -EINVAL; + } + n += 2; + odp_put_userspace_action(pid, &cookie, actions); return n; } else if (sscanf(s, "userspace(pid=%lli,userdata=" "%31[x0123456789abcdefABCDEF])%n", &pid, userdata_s, &n) > 0 && n > 0) { - struct user_action_cookie cookie; + union user_action_cookie cookie; uint64_t userdata; userdata = strtoull(userdata_s, NULL, 0); @@ -440,7 +532,7 @@ parse_odp_action(const char *s, const struct shash *port_names, for (;;) { int retval; - s += strspn(s, delimiters); + n += strspn(s + n, delimiters); if (s[n] == ')') { break; } @@ -450,7 +542,6 @@ parse_odp_action(const char *s, const struct shash *port_names, return retval; } n += retval; - } nl_msg_end_nested(actions, actions_ofs); nl_msg_end_nested(actions, sample_ofs); @@ -468,7 +559,7 @@ parse_odp_action(const char *s, const struct shash *port_names, * Netlink attributes. On failure, no data is appended to 'actions'. Either * way, 'actions''s data might be reallocated. */ int -odp_actions_from_string(const char *s, const struct shash *port_names, +odp_actions_from_string(const char *s, const struct simap *port_names, struct ofpbuf *actions) { size_t old_size; @@ -785,7 +876,7 @@ ovs_frag_type_from_string(const char *s, enum ovs_frag_type *type) } static int -parse_odp_key_attr(const char *s, const struct shash *port_names, +parse_odp_key_attr(const char *s, const struct simap *port_names, struct ofpbuf *key) { /* Many of the sscanf calls in this function use oversized destination @@ -832,14 +923,14 @@ parse_odp_key_attr(const char *s, const struct shash *port_names, if (port_names && !strncmp(s, "in_port(", 8)) { const char *name; - const struct shash_node *node; + const struct simap_node *node; int name_len; name = s + 8; name_len = strcspn(s, ")"); - node = shash_find_len(port_names, name, name_len); + node = simap_find_len(port_names, name, name_len); if (node) { - nl_msg_put_u32(key, OVS_KEY_ATTR_IN_PORT, (uintptr_t) node->data); + nl_msg_put_u32(key, OVS_KEY_ATTR_IN_PORT, node->data); return 8 + name_len + 1; } } @@ -1116,15 +1207,15 @@ parse_odp_key_attr(const char *s, const struct shash *port_names, * data is appended to 'key'. Either way, 'key''s data might be * reallocated. * - * If 'port_names' is nonnull, it points to an shash that maps from a port name - * to a port number cast to void *. (Port names may be used instead of port - * numbers in in_port.) + * If 'port_names' is nonnull, it points to an simap that maps from a port name + * to a port number. (Port names may be used instead of port numbers in + * in_port.) * * On success, the attributes appended to 'key' are individually syntactically * valid, but they may not be valid as a sequence. 'key' might, for example, * have duplicated keys. odp_flow_key_to_flow() will detect those errors. */ int -odp_flow_key_from_string(const char *s, const struct shash *port_names, +odp_flow_key_from_string(const char *s, const struct simap *port_names, struct ofpbuf *key) { const size_t old_size = key->size; @@ -1155,7 +1246,10 @@ ovs_to_odp_frag(uint8_t nw_frag) : OVS_FRAG_TYPE_LATER); } -/* Appends a representation of 'flow' as OVS_KEY_ATTR_* attributes to 'buf'. */ +/* Appends a representation of 'flow' as OVS_KEY_ATTR_* attributes to 'buf'. + * + * 'buf' must have at least ODPUTIL_FLOW_KEY_BYTES bytes of space, or be + * capable of being expanded to allow for that much space. */ void odp_flow_key_from_flow(struct ofpbuf *buf, const struct flow *flow) { @@ -1170,7 +1264,7 @@ odp_flow_key_from_flow(struct ofpbuf *buf, const struct flow *flow) nl_msg_put_be64(buf, OVS_KEY_ATTR_TUN_ID, flow->tun_id); } - if (flow->in_port != OFPP_NONE) { + if (flow->in_port != OFPP_NONE && flow->in_port != OFPP_CONTROLLER) { nl_msg_put_u32(buf, OVS_KEY_ATTR_IN_PORT, ofp_port_to_odp_port(flow->in_port)); } @@ -1723,7 +1817,7 @@ odp_key_fitness_to_string(enum odp_key_fitness fitness) * the start of the cookie. (If 'cookie' is null, then the return value is not * meaningful.) */ size_t -odp_put_userspace_action(uint32_t pid, const struct user_action_cookie *cookie, +odp_put_userspace_action(uint32_t pid, const union user_action_cookie *cookie, struct ofpbuf *odp_actions) { size_t offset; @@ -1882,7 +1976,7 @@ static void commit_set_port_action(const struct flow *flow, struct flow *base, struct ofpbuf *odp_actions) { - if (!base->tp_src || !base->tp_dst) { + if (!base->tp_src && !base->tp_dst) { return; }