X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fodp-util.c;h=96a9523019a672f825780108de651219d85ee9f8;hb=ea7655d9f9d38a3af7250de8ba0b89115b5f4a5e;hp=9b0876c45982af700bce46b4607cfece67bbb51c;hpb=29c7a2b26ed005902b2179d7fe242eb711184b88;p=sliver-openvswitch.git diff --git a/lib/odp-util.c b/lib/odp-util.c index 9b0876c45..96a952301 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -92,9 +92,10 @@ ovs_key_attr_to_string(enum ovs_key_attr attr) switch (attr) { case OVS_KEY_ATTR_UNSPEC: return "unspec"; case OVS_KEY_ATTR_ENCAP: return "encap"; - case OVS_KEY_ATTR_PRIORITY: return "priority"; + case OVS_KEY_ATTR_PRIORITY: return "skb_priority"; + case OVS_KEY_ATTR_SKB_MARK: return "skb_mark"; case OVS_KEY_ATTR_TUN_ID: return "tun_id"; - case OVS_KEY_ATTR_IPV4_TUNNEL: return "ipv4_tunnel"; + case OVS_KEY_ATTR_TUNNEL: return "tunnel"; case OVS_KEY_ATTR_IN_PORT: return "in_port"; case OVS_KEY_ATTR_ETHERNET: return "eth"; case OVS_KEY_ATTR_VLAN: return "vlan"; @@ -189,38 +190,6 @@ slow_path_reason_to_string(uint32_t data) } } -static void -format_flags(struct ds *ds, const char *(*bit_to_string)(uint32_t), - uint32_t flags) -{ - uint32_t bad = 0; - - ds_put_format(ds, "("); - if (!flags) { - goto out; - } - while (flags) { - uint32_t bit = rightmost_1bit(flags); - const char *s; - - s = bit_to_string(bit); - if (s) { - ds_put_format(ds, "%s,", s); - } else { - bad |= bit; - } - - flags &= ~bit; - } - - if (bad) { - ds_put_format(ds, "0x%"PRIx32",", bad); - } - ds_chomp(ds, ','); -out: - ds_put_format(ds, ")"); -} - static int parse_flags(const char *s, const char *(*bit_to_string)(uint32_t), uint32_t *res) @@ -304,8 +273,10 @@ format_odp_userspace_action(struct ds *ds, const struct nlattr *attr) break; case USER_ACTION_COOKIE_SLOW_PATH: - ds_put_cstr(ds, ",slow_path"); - format_flags(ds, slow_path_reason_to_string, cookie.slow_path.reason); + ds_put_cstr(ds, ",slow_path("); + format_flags(ds, slow_path_reason_to_string, + cookie.slow_path.reason, ','); + ds_put_format(ds, ")"); break; case USER_ACTION_COOKIE_UNSPEC: @@ -644,8 +615,9 @@ odp_flow_key_attr_len(uint16_t type) switch ((enum ovs_key_attr) type) { case OVS_KEY_ATTR_ENCAP: return -2; case OVS_KEY_ATTR_PRIORITY: return 4; + case OVS_KEY_ATTR_SKB_MARK: return 4; case OVS_KEY_ATTR_TUN_ID: return 8; - case OVS_KEY_ATTR_IPV4_TUNNEL: return sizeof(struct ovs_key_ipv4_tunnel); + case OVS_KEY_ATTR_TUNNEL: return -2; case OVS_KEY_ATTR_IN_PORT: return 4; case OVS_KEY_ATTR_ETHERNET: return sizeof(struct ovs_key_ethernet); case OVS_KEY_ATTR_VLAN: return sizeof(ovs_be16); @@ -700,19 +672,109 @@ ovs_frag_type_to_string(enum ovs_frag_type type) } } -static const char * -tun_flag_to_string(uint32_t flags) +static int +tunnel_key_attr_len(int type) { - switch (flags) { - case OVS_TNL_F_DONT_FRAGMENT: - return "df"; - case OVS_TNL_F_CSUM: - return "csum"; - case OVS_TNL_F_KEY: - return "key"; - default: - return NULL; + switch (type) { + case OVS_TUNNEL_KEY_ATTR_ID: return 8; + case OVS_TUNNEL_KEY_ATTR_IPV4_SRC: return 4; + case OVS_TUNNEL_KEY_ATTR_IPV4_DST: return 4; + case OVS_TUNNEL_KEY_ATTR_TOS: return 1; + case OVS_TUNNEL_KEY_ATTR_TTL: return 1; + case OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT: return 0; + case OVS_TUNNEL_KEY_ATTR_CSUM: return 0; + case __OVS_TUNNEL_KEY_ATTR_MAX: + return -1; + } + return -1; +} + +static enum odp_key_fitness +tun_key_from_attr(const struct nlattr *attr, struct flow_tnl *tun) +{ + unsigned int left; + const struct nlattr *a; + bool ttl = false; + bool unknown = false; + + NL_NESTED_FOR_EACH(a, left, attr) { + uint16_t type = nl_attr_type(a); + size_t len = nl_attr_get_size(a); + int expected_len = tunnel_key_attr_len(type); + + if (len != expected_len && expected_len >= 0) { + return ODP_FIT_ERROR; + } + + switch (type) { + case OVS_TUNNEL_KEY_ATTR_ID: + tun->tun_id = nl_attr_get_be64(a); + tun->flags |= FLOW_TNL_F_KEY; + break; + case OVS_TUNNEL_KEY_ATTR_IPV4_SRC: + tun->ip_src = nl_attr_get_be32(a); + break; + case OVS_TUNNEL_KEY_ATTR_IPV4_DST: + tun->ip_dst = nl_attr_get_be32(a); + break; + case OVS_TUNNEL_KEY_ATTR_TOS: + tun->ip_tos = nl_attr_get_u8(a); + break; + case OVS_TUNNEL_KEY_ATTR_TTL: + tun->ip_ttl = nl_attr_get_u8(a); + ttl = true; + break; + case OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT: + tun->flags |= FLOW_TNL_F_DONT_FRAGMENT; + break; + case OVS_TUNNEL_KEY_ATTR_CSUM: + tun->flags |= FLOW_TNL_F_CSUM; + break; + default: + /* Allow this to show up as unexpected, if there are unknown + * tunnel attribute, eventually resulting in ODP_FIT_TOO_MUCH. */ + unknown = true; + break; + } + } + + if (!ttl) { + return ODP_FIT_ERROR; + } + if (unknown) { + return ODP_FIT_TOO_MUCH; } + return ODP_FIT_PERFECT; +} + +static void +tun_key_to_attr(struct ofpbuf *a, const struct flow_tnl *tun_key) +{ + size_t tun_key_ofs; + + tun_key_ofs = nl_msg_start_nested(a, OVS_KEY_ATTR_TUNNEL); + + if (tun_key->flags & FLOW_TNL_F_KEY) { + nl_msg_put_be64(a, OVS_TUNNEL_KEY_ATTR_ID, tun_key->tun_id); + } + if (tun_key->ip_src) { + nl_msg_put_be32(a, OVS_TUNNEL_KEY_ATTR_IPV4_SRC, tun_key->ip_src); + } + if (tun_key->ip_dst) { + nl_msg_put_be32(a, OVS_TUNNEL_KEY_ATTR_IPV4_DST, tun_key->ip_dst); + } + if (tun_key->ip_tos) { + nl_msg_put_u8(a, OVS_TUNNEL_KEY_ATTR_TOS, tun_key->ip_tos); + } + nl_msg_put_u8(a, OVS_TUNNEL_KEY_ATTR_TTL, tun_key->ip_ttl); + if (tun_key->flags & FLOW_TNL_F_DONT_FRAGMENT) { + nl_msg_put_flag(a, OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT); + } + if (tun_key->flags & FLOW_TNL_F_CSUM) { + nl_msg_put_flag(a, OVS_TUNNEL_KEY_ATTR_CSUM); + } + + nl_msg_end_nested(a, tun_key_ofs); } static void @@ -727,7 +789,7 @@ format_odp_key_attr(const struct nlattr *a, struct ds *ds) const struct ovs_key_icmpv6 *icmpv6_key; const struct ovs_key_arp *arp_key; const struct ovs_key_nd *nd_key; - const struct ovs_key_ipv4_tunnel *ipv4_tun_key; + struct flow_tnl tun_key; enum ovs_key_attr attr = nl_attr_type(a); int expected_len; @@ -751,24 +813,33 @@ format_odp_key_attr(const struct nlattr *a, struct ds *ds) break; case OVS_KEY_ATTR_PRIORITY: - ds_put_format(ds, "(%"PRIu32")", nl_attr_get_u32(a)); + ds_put_format(ds, "(%#"PRIx32")", nl_attr_get_u32(a)); + break; + + case OVS_KEY_ATTR_SKB_MARK: + ds_put_format(ds, "(%#"PRIx32")", nl_attr_get_u32(a)); break; case OVS_KEY_ATTR_TUN_ID: ds_put_format(ds, "(%#"PRIx64")", ntohll(nl_attr_get_be64(a))); break; - case OVS_KEY_ATTR_IPV4_TUNNEL: - ipv4_tun_key = nl_attr_get(a); - ds_put_format(ds, "(tun_id=0x%"PRIx64",src="IP_FMT",dst="IP_FMT"," - "tos=0x%"PRIx8",ttl=%"PRIu8",flags", - ntohll(ipv4_tun_key->tun_id), - IP_ARGS(&ipv4_tun_key->ipv4_src), - IP_ARGS(&ipv4_tun_key->ipv4_dst), - ipv4_tun_key->ipv4_tos, ipv4_tun_key->ipv4_ttl); - - format_flags(ds, tun_flag_to_string, ipv4_tun_key->tun_flags); - ds_put_format(ds, ")"); + case OVS_KEY_ATTR_TUNNEL: + memset(&tun_key, 0, sizeof tun_key); + if (tun_key_from_attr(a, &tun_key) == ODP_FIT_ERROR) { + ds_put_format(ds, "(error)"); + } else { + ds_put_format(ds, "(tun_id=0x%"PRIx64",src="IP_FMT",dst="IP_FMT"," + "tos=0x%"PRIx8",ttl=%"PRIu8",flags(", + ntohll(tun_key.tun_id), + IP_ARGS(tun_key.ip_src), + IP_ARGS(tun_key.ip_dst), + tun_key.ip_tos, tun_key.ip_ttl); + + format_flags(ds, flow_tun_flag_to_string, + (uint32_t) tun_key.flags, ','); + ds_put_format(ds, "))"); + } break; case OVS_KEY_ATTR_IN_PORT: @@ -797,8 +868,8 @@ format_odp_key_attr(const struct nlattr *a, struct ds *ds) ipv4_key = nl_attr_get(a); ds_put_format(ds, "(src="IP_FMT",dst="IP_FMT",proto=%"PRIu8 ",tos=%#"PRIx8",ttl=%"PRIu8",frag=%s)", - IP_ARGS(&ipv4_key->ipv4_src), - IP_ARGS(&ipv4_key->ipv4_dst), + IP_ARGS(ipv4_key->ipv4_src), + IP_ARGS(ipv4_key->ipv4_dst), ipv4_key->ipv4_proto, ipv4_key->ipv4_tos, ipv4_key->ipv4_ttl, ovs_frag_type_to_string(ipv4_key->ipv4_frag)); @@ -849,7 +920,7 @@ format_odp_key_attr(const struct nlattr *a, struct ds *ds) arp_key = nl_attr_get(a); ds_put_format(ds, "(sip="IP_FMT",tip="IP_FMT",op=%"PRIu16"," "sha="ETH_ADDR_FMT",tha="ETH_ADDR_FMT")", - IP_ARGS(&arp_key->arp_sip), IP_ARGS(&arp_key->arp_tip), + IP_ARGS(arp_key->arp_sip), IP_ARGS(arp_key->arp_tip), ntohs(arp_key->arp_op), ETH_ADDR_ARGS(arp_key->arp_sha), ETH_ADDR_ARGS(arp_key->arp_tha)); break; @@ -966,12 +1037,22 @@ parse_odp_key_attr(const char *s, const struct simap *port_names, unsigned long long int priority; int n = -1; - if (sscanf(s, "priority(%lli)%n", &priority, &n) > 0 && n > 0) { + if (sscanf(s, "skb_priority(%llx)%n", &priority, &n) > 0 && n > 0) { nl_msg_put_u32(key, OVS_KEY_ATTR_PRIORITY, priority); return n; } } + { + unsigned long long int mark; + int n = -1; + + if (sscanf(s, "skb_mark(%llx)%n", &mark, &n) > 0 && n > 0) { + nl_msg_put_u32(key, OVS_KEY_ATTR_SKB_MARK, mark); + return n; + } + } + { char tun_id_s[32]; int n = -1; @@ -987,22 +1068,24 @@ parse_odp_key_attr(const char *s, const struct simap *port_names, { char tun_id_s[32]; int tos, ttl; - struct ovs_key_ipv4_tunnel tun_key; + struct flow_tnl tun_key; int n = -1; - if (sscanf(s, "ipv4_tunnel(tun_id=%31[x0123456789abcdefABCDEF]," + if (sscanf(s, "tunnel(tun_id=%31[x0123456789abcdefABCDEF]," "src="IP_SCAN_FMT",dst="IP_SCAN_FMT ",tos=%i,ttl=%i,flags%n", tun_id_s, - IP_SCAN_ARGS(&tun_key.ipv4_src), - IP_SCAN_ARGS(&tun_key.ipv4_dst), &tos, &ttl, + IP_SCAN_ARGS(&tun_key.ip_src), + IP_SCAN_ARGS(&tun_key.ip_dst), &tos, &ttl, &n) > 0 && n > 0) { int res; + uint32_t flags; tun_key.tun_id = htonll(strtoull(tun_id_s, NULL, 0)); - tun_key.ipv4_tos = tos; - tun_key.ipv4_ttl = ttl; + tun_key.ip_tos = tos; + tun_key.ip_ttl = ttl; + res = parse_flags(&s[n], flow_tun_flag_to_string, &flags); + tun_key.flags = (uint16_t) flags; - res = parse_flags(&s[n], tun_flag_to_string, &tun_key.tun_flags); if (res < 0) { return res; } @@ -1011,10 +1094,7 @@ parse_odp_key_attr(const char *s, const struct simap *port_names, return -EINVAL; } n++; - - memset(&tun_key.pad, 0, sizeof tun_key.pad); - nl_msg_put_unspec(key, OVS_KEY_ATTR_IPV4_TUNNEL, &tun_key, - sizeof tun_key); + tun_key_to_attr(key, &tun_key); return n; } } @@ -1373,10 +1453,16 @@ odp_flow_key_from_flow(struct ofpbuf *buf, const struct flow *flow, nl_msg_put_u32(buf, OVS_KEY_ATTR_PRIORITY, flow->skb_priority); } - if (flow->tunnel.tun_id != htonll(0)) { + if (flow->tunnel.ip_dst) { + tun_key_to_attr(buf, &flow->tunnel); + } else if (flow->tunnel.tun_id != htonll(0)) { nl_msg_put_be64(buf, OVS_KEY_ATTR_TUN_ID, flow->tunnel.tun_id); } + if (flow->skb_mark) { + nl_msg_put_u32(buf, OVS_KEY_ATTR_SKB_MARK, flow->skb_mark); + } + if (odp_in_port != OVSP_NONE) { nl_msg_put_u32(buf, OVS_KEY_ATTR_IN_PORT, odp_in_port); } @@ -1869,11 +1955,27 @@ odp_flow_key_to_flow(const struct nlattr *key, size_t key_len, expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_PRIORITY; } + if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_SKB_MARK)) { + flow->skb_mark = nl_attr_get_u32(attrs[OVS_KEY_ATTR_SKB_MARK]); + expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_SKB_MARK; + } + if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_TUN_ID)) { flow->tunnel.tun_id = nl_attr_get_be64(attrs[OVS_KEY_ATTR_TUN_ID]); expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_TUN_ID; } + if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_TUNNEL)) { + enum odp_key_fitness res; + + res = tun_key_from_attr(attrs[OVS_KEY_ATTR_TUNNEL], &flow->tunnel); + if (res == ODP_FIT_ERROR) { + return ODP_FIT_ERROR; + } else if (res == ODP_FIT_PERFECT) { + expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_TUNNEL; + } + } + if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_IN_PORT)) { flow->in_port = nl_attr_get_u32(attrs[OVS_KEY_ATTR_IN_PORT]); expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_IN_PORT; @@ -1956,16 +2058,25 @@ commit_set_action(struct ofpbuf *odp_actions, enum ovs_key_attr key_type, } static void -commit_set_tun_id_action(const struct flow *flow, struct flow *base, +commit_set_tunnel_action(const struct flow *flow, struct flow *base, struct ofpbuf *odp_actions) { - if (base->tunnel.tun_id == flow->tunnel.tun_id) { + if (!memcmp(&base->tunnel, &flow->tunnel, sizeof base->tunnel)) { return; } - base->tunnel.tun_id = flow->tunnel.tun_id; + memcpy(&base->tunnel, &flow->tunnel, sizeof base->tunnel); + + /* A valid IPV4_TUNNEL must have non-zero ip_dst. */ + if (flow->tunnel.ip_dst) { + size_t offset; - commit_set_action(odp_actions, OVS_KEY_ATTR_TUN_ID, - &base->tunnel.tun_id, sizeof(base->tunnel.tun_id)); + offset = nl_msg_start_nested(odp_actions, OVS_ACTION_ATTR_SET); + tun_key_to_attr(odp_actions, &base->tunnel); + nl_msg_end_nested(odp_actions, offset); + } else { + commit_set_action(odp_actions, OVS_KEY_ATTR_TUN_ID, + &base->tunnel.tun_id, sizeof base->tunnel.tun_id); + } } static void @@ -2129,6 +2240,18 @@ commit_set_priority_action(const struct flow *flow, struct flow *base, &base->skb_priority, sizeof(base->skb_priority)); } +static void +commit_set_skb_mark_action(const struct flow *flow, struct flow *base, + struct ofpbuf *odp_actions) +{ + if (base->skb_mark == flow->skb_mark) { + return; + } + base->skb_mark = flow->skb_mark; + + commit_set_action(odp_actions, OVS_KEY_ATTR_SKB_MARK, + &base->skb_mark, sizeof(base->skb_mark)); +} /* If any of the flow key data that ODP actions can modify are different in * 'base' and 'flow', appends ODP actions to 'odp_actions' that change the flow * key from 'base' into 'flow', and then changes 'base' the same way. */ @@ -2136,10 +2259,11 @@ void commit_odp_actions(const struct flow *flow, struct flow *base, struct ofpbuf *odp_actions) { - commit_set_tun_id_action(flow, base, odp_actions); + commit_set_tunnel_action(flow, base, odp_actions); commit_set_ether_addr_action(flow, base, odp_actions); commit_vlan_action(flow, base, odp_actions); commit_set_nw_action(flow, base, odp_actions); commit_set_port_action(flow, base, odp_actions); commit_set_priority_action(flow, base, odp_actions); + commit_set_skb_mark_action(flow, base, odp_actions); }