- /* IPv4 */
- if (!ovs_scan_len(s, &n, "ipv4(src="IP_SCAN_FMT",dst="IP_SCAN_FMT",proto=%"SCNi8
- ",tos=%"SCNi8",ttl=%"SCNi8",frag=0x%"SCNx16"),",
- IP_SCAN_ARGS(&sip),
- IP_SCAN_ARGS(&dip),
- &ip->ip_proto, &ip->ip_tos,
- &ip->ip_ttl, &ip->ip_frag_off)) {
- return -EINVAL;
+ if (eth->eth_type == htons(ETH_TYPE_IP)) {
+ /* IPv4 */
+ uint16_t ip_frag_off;
+ if (!ovs_scan_len(s, &n, "ipv4(src="IP_SCAN_FMT",dst="IP_SCAN_FMT",proto=%"SCNi8
+ ",tos=%"SCNi8",ttl=%"SCNi8",frag=0x%"SCNx16"),",
+ IP_SCAN_ARGS(&sip),
+ IP_SCAN_ARGS(&dip),
+ &ip->ip_proto, &ip->ip_tos,
+ &ip->ip_ttl, &ip_frag_off)) {
+ return -EINVAL;
+ }
+ put_16aligned_be32(&ip->ip_src, sip);
+ put_16aligned_be32(&ip->ip_dst, dip);
+ ip->ip_frag_off = htons(ip_frag_off);
+ ip_len = sizeof *ip;
+ } else {
+ char sip6_s[IPV6_SCAN_LEN + 1];
+ char dip6_s[IPV6_SCAN_LEN + 1];
+ struct in6_addr sip6, dip6;
+ uint8_t tclass;
+ uint32_t label;
+ if (!ovs_scan_len(s, &n, "ipv6(src="IPV6_SCAN_FMT",dst="IPV6_SCAN_FMT
+ ",label=%i,proto=%"SCNi8",tclass=0x%"SCNx8
+ ",hlimit=%"SCNi8"),",
+ sip6_s, dip6_s, &label, &ip6->ip6_nxt,
+ &tclass, &ip6->ip6_hlim)
+ || (label & ~IPV6_LABEL_MASK) != 0
+ || inet_pton(AF_INET6, sip6_s, &sip6) != 1
+ || inet_pton(AF_INET6, dip6_s, &dip6) != 1) {
+ return -EINVAL;
+ }
+ put_16aligned_be32(&ip6->ip6_flow, htonl(6 << 28) |
+ htonl(tclass << 20) | htonl(label));
+ memcpy(&ip6->ip6_src, &sip6, sizeof(ip6->ip6_src));
+ memcpy(&ip6->ip6_dst, &dip6, sizeof(ip6->ip6_dst));
+ ip_len = sizeof *ip6;