+ case OVS_KEY_ATTR_TUNNEL:
+ memset(&tun_key, 0, sizeof tun_key);
+ if (odp_tun_key_from_attr(a, &tun_key) == ODP_FIT_ERROR) {
+ ds_put_format(ds, "error");
+ } else if (!is_exact) {
+ struct flow_tnl tun_mask;
+
+ memset(&tun_mask, 0, sizeof tun_mask);
+ odp_tun_key_from_attr(ma, &tun_mask);
+ ds_put_format(ds, "tun_id=%#"PRIx64"/%#"PRIx64
+ ",src="IP_FMT"/"IP_FMT",dst="IP_FMT"/"IP_FMT
+ ",tos=%#"PRIx8"/%#"PRIx8",ttl=%"PRIu8"/%#"PRIx8
+ ",flags(",
+ ntohll(tun_key.tun_id), ntohll(tun_mask.tun_id),
+ IP_ARGS(tun_key.ip_src), IP_ARGS(tun_mask.ip_src),
+ IP_ARGS(tun_key.ip_dst), IP_ARGS(tun_mask.ip_dst),
+ tun_key.ip_tos, tun_mask.ip_tos,
+ tun_key.ip_ttl, tun_mask.ip_ttl);
+
+ format_flags(ds, flow_tun_flag_to_string, tun_key.flags, ',');
+
+ /* XXX This code is correct, but enabling it would break the unit
+ test. Disable it for now until the input parser is fixed.
+
+ ds_put_char(ds, '/');
+ format_flags(ds, flow_tun_flag_to_string, tun_mask.flags, ',');
+ */
+ ds_put_char(ds, ')');
+ } 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, tun_key.flags, ',');
+ ds_put_char(ds, ')');
+ }
+ break;
+
+ case OVS_KEY_ATTR_IN_PORT:
+ if (portno_names && verbose && is_exact) {
+ char *name = odp_portno_names_get(portno_names,
+ u32_to_odp(nl_attr_get_u32(a)));
+ if (name) {
+ ds_put_format(ds, "%s", name);
+ } else {
+ ds_put_format(ds, "%"PRIu32, nl_attr_get_u32(a));
+ }
+ } else {
+ ds_put_format(ds, "%"PRIu32, nl_attr_get_u32(a));
+ if (!is_exact) {
+ ds_put_format(ds, "/%#"PRIx32, nl_attr_get_u32(ma));
+ }
+ }
+ break;
+
+ case OVS_KEY_ATTR_ETHERNET:
+ if (!is_exact) {
+ const struct ovs_key_ethernet *eth_mask = nl_attr_get(ma);
+ const struct ovs_key_ethernet *eth_key = nl_attr_get(a);
+
+ ds_put_format(ds, "src="ETH_ADDR_FMT"/"ETH_ADDR_FMT
+ ",dst="ETH_ADDR_FMT"/"ETH_ADDR_FMT,
+ ETH_ADDR_ARGS(eth_key->eth_src),
+ ETH_ADDR_ARGS(eth_mask->eth_src),
+ ETH_ADDR_ARGS(eth_key->eth_dst),
+ ETH_ADDR_ARGS(eth_mask->eth_dst));
+ } else {
+ const struct ovs_key_ethernet *eth_key = nl_attr_get(a);
+
+ ds_put_format(ds, "src="ETH_ADDR_FMT",dst="ETH_ADDR_FMT,
+ ETH_ADDR_ARGS(eth_key->eth_src),
+ ETH_ADDR_ARGS(eth_key->eth_dst));
+ }
+ break;
+
+ case OVS_KEY_ATTR_VLAN:
+ {
+ ovs_be16 vlan_tci = nl_attr_get_be16(a);
+ if (!is_exact) {
+ ovs_be16 mask = nl_attr_get_be16(ma);
+ ds_put_format(ds, "vid=%"PRIu16"/0x%"PRIx16",pcp=%d/0x%x,cfi=%d/%d",
+ vlan_tci_to_vid(vlan_tci),
+ vlan_tci_to_vid(mask),
+ vlan_tci_to_pcp(vlan_tci),
+ vlan_tci_to_pcp(mask),
+ vlan_tci_to_cfi(vlan_tci),
+ vlan_tci_to_cfi(mask));
+ } else {
+ format_vlan_tci(ds, vlan_tci);
+ }
+ }
+ break;
+
+ case OVS_KEY_ATTR_MPLS: {
+ const struct ovs_key_mpls *mpls_key = nl_attr_get(a);
+ const struct ovs_key_mpls *mpls_mask = NULL;
+ if (!is_exact) {
+ mpls_mask = nl_attr_get(ma);
+ }
+ format_mpls(ds, mpls_key, mpls_mask);
+ break;
+ }
+
+ case OVS_KEY_ATTR_ETHERTYPE:
+ ds_put_format(ds, "0x%04"PRIx16, ntohs(nl_attr_get_be16(a)));
+ if (!is_exact) {
+ ds_put_format(ds, "/0x%04"PRIx16, ntohs(nl_attr_get_be16(ma)));
+ }
+ break;
+
+ case OVS_KEY_ATTR_IPV4:
+ if (!is_exact) {
+ const struct ovs_key_ipv4 *ipv4_key = nl_attr_get(a);
+ const struct ovs_key_ipv4 *ipv4_mask = nl_attr_get(ma);
+
+ ds_put_format(ds, "src="IP_FMT"/"IP_FMT",dst="IP_FMT"/"IP_FMT
+ ",proto=%"PRIu8"/%#"PRIx8",tos=%#"PRIx8"/%#"PRIx8
+ ",ttl=%"PRIu8"/%#"PRIx8",frag=%s/%#"PRIx8,
+ IP_ARGS(ipv4_key->ipv4_src),
+ IP_ARGS(ipv4_mask->ipv4_src),
+ IP_ARGS(ipv4_key->ipv4_dst),
+ IP_ARGS(ipv4_mask->ipv4_dst),
+ ipv4_key->ipv4_proto, ipv4_mask->ipv4_proto,
+ ipv4_key->ipv4_tos, ipv4_mask->ipv4_tos,
+ ipv4_key->ipv4_ttl, ipv4_mask->ipv4_ttl,
+ ovs_frag_type_to_string(ipv4_key->ipv4_frag),
+ ipv4_mask->ipv4_frag);
+ } else {
+ const struct ovs_key_ipv4 *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),
+ ipv4_key->ipv4_proto, ipv4_key->ipv4_tos,
+ ipv4_key->ipv4_ttl,
+ ovs_frag_type_to_string(ipv4_key->ipv4_frag));
+ }
+ break;
+
+ case OVS_KEY_ATTR_IPV6:
+ if (!is_exact) {
+ const struct ovs_key_ipv6 *ipv6_key, *ipv6_mask;
+ char src_str[INET6_ADDRSTRLEN];
+ char dst_str[INET6_ADDRSTRLEN];
+ char src_mask[INET6_ADDRSTRLEN];
+ char dst_mask[INET6_ADDRSTRLEN];
+
+ ipv6_key = nl_attr_get(a);
+ inet_ntop(AF_INET6, ipv6_key->ipv6_src, src_str, sizeof src_str);
+ inet_ntop(AF_INET6, ipv6_key->ipv6_dst, dst_str, sizeof dst_str);
+
+ ipv6_mask = nl_attr_get(ma);
+ inet_ntop(AF_INET6, ipv6_mask->ipv6_src, src_mask, sizeof src_mask);
+ inet_ntop(AF_INET6, ipv6_mask->ipv6_dst, dst_mask, sizeof dst_mask);
+
+ ds_put_format(ds, "src=%s/%s,dst=%s/%s,label=%#"PRIx32"/%#"PRIx32
+ ",proto=%"PRIu8"/%#"PRIx8",tclass=%#"PRIx8"/%#"PRIx8
+ ",hlimit=%"PRIu8"/%#"PRIx8",frag=%s/%#"PRIx8,
+ src_str, src_mask, dst_str, dst_mask,
+ ntohl(ipv6_key->ipv6_label),
+ ntohl(ipv6_mask->ipv6_label),
+ ipv6_key->ipv6_proto, ipv6_mask->ipv6_proto,
+ ipv6_key->ipv6_tclass, ipv6_mask->ipv6_tclass,
+ ipv6_key->ipv6_hlimit, ipv6_mask->ipv6_hlimit,
+ ovs_frag_type_to_string(ipv6_key->ipv6_frag),
+ ipv6_mask->ipv6_frag);
+ } else {
+ const struct ovs_key_ipv6 *ipv6_key;
+ char src_str[INET6_ADDRSTRLEN];
+ char dst_str[INET6_ADDRSTRLEN];
+
+ ipv6_key = nl_attr_get(a);
+ inet_ntop(AF_INET6, ipv6_key->ipv6_src, src_str, sizeof src_str);
+ inet_ntop(AF_INET6, ipv6_key->ipv6_dst, dst_str, sizeof dst_str);
+
+ ds_put_format(ds, "src=%s,dst=%s,label=%#"PRIx32",proto=%"PRIu8
+ ",tclass=%#"PRIx8",hlimit=%"PRIu8",frag=%s",
+ src_str, dst_str, ntohl(ipv6_key->ipv6_label),
+ ipv6_key->ipv6_proto, ipv6_key->ipv6_tclass,
+ ipv6_key->ipv6_hlimit,
+ ovs_frag_type_to_string(ipv6_key->ipv6_frag));
+ }
+ break;
+
+ case OVS_KEY_ATTR_TCP:
+ if (!is_exact) {
+ const struct ovs_key_tcp *tcp_mask = nl_attr_get(ma);
+ const struct ovs_key_tcp *tcp_key = nl_attr_get(a);
+
+ ds_put_format(ds, "src=%"PRIu16"/%#"PRIx16
+ ",dst=%"PRIu16"/%#"PRIx16,
+ ntohs(tcp_key->tcp_src), ntohs(tcp_mask->tcp_src),
+ ntohs(tcp_key->tcp_dst), ntohs(tcp_mask->tcp_dst));
+ } else {
+ const struct ovs_key_tcp *tcp_key = nl_attr_get(a);
+
+ ds_put_format(ds, "src=%"PRIu16",dst=%"PRIu16,
+ ntohs(tcp_key->tcp_src), ntohs(tcp_key->tcp_dst));
+ }
+ break;
+
+ case OVS_KEY_ATTR_TCP_FLAGS:
+ ds_put_format(ds, "0x%03"PRIx16, ntohs(nl_attr_get_be16(a)));
+ if (!is_exact) {
+ ds_put_format(ds, "/0x%03"PRIx16, ntohs(nl_attr_get_be16(ma)));
+ }
+ break;
+
+ case OVS_KEY_ATTR_UDP:
+ if (!is_exact) {
+ const struct ovs_key_udp *udp_mask = nl_attr_get(ma);
+ const struct ovs_key_udp *udp_key = nl_attr_get(a);
+
+ ds_put_format(ds, "src=%"PRIu16"/%#"PRIx16
+ ",dst=%"PRIu16"/%#"PRIx16,
+ ntohs(udp_key->udp_src), ntohs(udp_mask->udp_src),
+ ntohs(udp_key->udp_dst), ntohs(udp_mask->udp_dst));
+ } else {
+ const struct ovs_key_udp *udp_key = nl_attr_get(a);
+
+ ds_put_format(ds, "src=%"PRIu16",dst=%"PRIu16,
+ ntohs(udp_key->udp_src), ntohs(udp_key->udp_dst));
+ }
+ break;
+
+ case OVS_KEY_ATTR_SCTP:
+ if (ma) {
+ const struct ovs_key_sctp *sctp_mask = nl_attr_get(ma);
+ const struct ovs_key_sctp *sctp_key = nl_attr_get(a);
+
+ ds_put_format(ds, "src=%"PRIu16"/%#"PRIx16
+ ",dst=%"PRIu16"/%#"PRIx16,
+ ntohs(sctp_key->sctp_src), ntohs(sctp_mask->sctp_src),
+ ntohs(sctp_key->sctp_dst), ntohs(sctp_mask->sctp_dst));
+ } else {
+ const struct ovs_key_sctp *sctp_key = nl_attr_get(a);
+
+ ds_put_format(ds, "(src=%"PRIu16",dst=%"PRIu16")",
+ ntohs(sctp_key->sctp_src), ntohs(sctp_key->sctp_dst));
+ }
+ break;
+
+ case OVS_KEY_ATTR_ICMP:
+ if (!is_exact) {
+ const struct ovs_key_icmp *icmp_mask = nl_attr_get(ma);
+ const struct ovs_key_icmp *icmp_key = nl_attr_get(a);
+
+ ds_put_format(ds, "type=%"PRIu8"/%#"PRIx8",code=%"PRIu8"/%#"PRIx8,
+ icmp_key->icmp_type, icmp_mask->icmp_type,
+ icmp_key->icmp_code, icmp_mask->icmp_code);
+ } else {
+ const struct ovs_key_icmp *icmp_key = nl_attr_get(a);
+
+ ds_put_format(ds, "type=%"PRIu8",code=%"PRIu8,
+ icmp_key->icmp_type, icmp_key->icmp_code);
+ }