130eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko/*
230eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko * f_flower.c		Flower Classifier
330eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko *
430eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko *		This program is free software; you can distribute it and/or
530eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko *		modify it under the terms of the GNU General Public License
630eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko *		as published by the Free Software Foundation; either version
730eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko *		2 of the License, or (at your option) any later version.
830eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko *
930eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko * Authors:     Jiri Pirko <jiri@resnulli.us>
1030eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko */
1130eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
1230eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko#include <stdio.h>
1330eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko#include <stdlib.h>
1430eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko#include <unistd.h>
1530eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko#include <syslog.h>
1630eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko#include <string.h>
1730eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko#include <net/if.h>
18f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman#include <linux/if_arp.h>
1930eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko#include <linux/if_ether.h>
2030eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko#include <linux/ip.h>
21745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion#include <linux/tc_act/tc_vlan.h>
2230eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
2330eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko#include "utils.h"
2430eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko#include "tc_util.h"
2530eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko#include "rt_names.h"
2630eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
2708f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakeyenum flower_matching_flags {
2808f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey	FLOWER_IP_FLAGS,
2908f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey};
3008f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey
316910d65661a3718ef4b944251a0dec170027f3d5Simon Hormanenum flower_endpoint {
326910d65661a3718ef4b944251a0dec170027f3d5Simon Horman	FLOWER_ENDPOINT_SRC,
336910d65661a3718ef4b944251a0dec170027f3d5Simon Horman	FLOWER_ENDPOINT_DST
346910d65661a3718ef4b944251a0dec170027f3d5Simon Horman};
356910d65661a3718ef4b944251a0dec170027f3d5Simon Horman
36eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Hormanenum flower_icmp_field {
37eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman	FLOWER_ICMP_FIELD_TYPE,
38eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman	FLOWER_ICMP_FIELD_CODE
39eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman};
40eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman
4130eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirkostatic void explain(void)
4230eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko{
43512caeb2737f1657d941945cc770a95882e1c1bbStephen Hemminger	fprintf(stderr,
44512caeb2737f1657d941945cc770a95882e1c1bbStephen Hemminger		"Usage: ... flower [ MATCH-LIST ]\n"
45512caeb2737f1657d941945cc770a95882e1c1bbStephen Hemminger		"                  [ skip_sw | skip_hw ]\n"
46512caeb2737f1657d941945cc770a95882e1c1bbStephen Hemminger		"                  [ action ACTION-SPEC ] [ classid CLASSID ]\n"
47512caeb2737f1657d941945cc770a95882e1c1bbStephen Hemminger		"\n"
48512caeb2737f1657d941945cc770a95882e1c1bbStephen Hemminger		"Where: MATCH-LIST := [ MATCH-LIST ] MATCH\n"
49512caeb2737f1657d941945cc770a95882e1c1bbStephen Hemminger		"       MATCH      := { indev DEV-NAME |\n"
50512caeb2737f1657d941945cc770a95882e1c1bbStephen Hemminger		"                       vlan_id VID |\n"
51512caeb2737f1657d941945cc770a95882e1c1bbStephen Hemminger		"                       vlan_prio PRIORITY |\n"
52512caeb2737f1657d941945cc770a95882e1c1bbStephen Hemminger		"                       vlan_ethtype [ ipv4 | ipv6 | ETH-TYPE ] |\n"
53c2078f8dc48c572a5016c79c3a2a878b6e39e8eeSimon Horman		"                       dst_mac MASKED-LLADDR |\n"
54c2078f8dc48c572a5016c79c3a2a878b6e39e8eeSimon Horman		"                       src_mac MASKED-LLADDR |\n"
55eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman		"                       ip_proto [tcp | udp | sctp | icmp | icmpv6 | IP-PROTO ] |\n"
566ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz		"                       ip_tos MASKED-IP_TOS |\n"
576ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz		"                       ip_ttl MASKED-IP_TTL |\n"
58b2a1f740aa4d37b0a15a1a8ea866a29d5fab4591Simon Horman		"                       dst_ip PREFIX |\n"
59b2a1f740aa4d37b0a15a1a8ea866a29d5fab4591Simon Horman		"                       src_ip PREFIX |\n"
60512caeb2737f1657d941945cc770a95882e1c1bbStephen Hemminger		"                       dst_port PORT-NUMBER |\n"
61bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai		"                       src_port PORT-NUMBER |\n"
620c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko		"                       tcp_flags MASKED-TCP_FLAGS |\n"
636374961a00d4b862bdf87c0f22af86d3ff7d0d67Simon Horman		"                       type MASKED-ICMP-TYPE |\n"
646374961a00d4b862bdf87c0f22af86d3ff7d0d67Simon Horman		"                       code MASKED-ICMP-CODE |\n"
65c7ec052bb8682a9889d1e71e2cb2ec780c9d5e26Simon Horman		"                       arp_tip IPV4-PREFIX |\n"
66c7ec052bb8682a9889d1e71e2cb2ec780c9d5e26Simon Horman		"                       arp_sip IPV4-PREFIX |\n"
67f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman		"                       arp_op [ request | reply | OP ] |\n"
68f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman		"                       arp_tha MASKED-LLADDR |\n"
69f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman		"                       arp_sha MASKED-LLADDR |\n"
7010da552800d761fff60eabc067f599c4e403403aStephen Hemminger		"                       enc_dst_ip [ IPV4-ADDR | IPV6-ADDR ] |\n"
7110da552800d761fff60eabc067f599c4e403403aStephen Hemminger		"                       enc_src_ip [ IPV4-ADDR | IPV6-ADDR ] |\n"
72bf73c650ac93ae673291c584fe592ea70686e37eHadar Hen Zion		"                       enc_key_id [ KEY-ID ] |\n"
7308f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey		"                       ip_flags IP-FLAGS | \n"
74a5ae170ed87c6a096451c7a7b94950e7befd8878Simon Horman		"                       enc_dst_port [ port_number ] }\n"
75512caeb2737f1657d941945cc770a95882e1c1bbStephen Hemminger		"       FILTERID := X:Y:Z\n"
76c2078f8dc48c572a5016c79c3a2a878b6e39e8eeSimon Horman		"       MASKED_LLADDR := { LLADDR | LLADDR/MASK | LLADDR/BITS }\n"
77512caeb2737f1657d941945cc770a95882e1c1bbStephen Hemminger		"       ACTION-SPEC := ... look at individual actions\n"
78512caeb2737f1657d941945cc770a95882e1c1bbStephen Hemminger		"\n"
79328374dcfea968d9aa709475d4e3fc04b1d073bbStephen Hemminger		"NOTE: CLASSID, IP-PROTO are parsed as hexadecimal input.\n"
80512caeb2737f1657d941945cc770a95882e1c1bbStephen Hemminger		"NOTE: There can be only used one mask per one prio. If user needs\n"
81512caeb2737f1657d941945cc770a95882e1c1bbStephen Hemminger		"      to specify different mask, he has to use different prio.\n");
8230eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko}
8330eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
8430eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirkostatic int flower_parse_eth_addr(char *str, int addr_type, int mask_type,
8530eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko				 struct nlmsghdr *n)
8630eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko{
87c2078f8dc48c572a5016c79c3a2a878b6e39e8eeSimon Horman	int ret, err = -1;
88c2078f8dc48c572a5016c79c3a2a878b6e39e8eeSimon Horman	char addr[ETH_ALEN], *slash;
89c2078f8dc48c572a5016c79c3a2a878b6e39e8eeSimon Horman
90c2078f8dc48c572a5016c79c3a2a878b6e39e8eeSimon Horman	slash = strchr(str, '/');
91c2078f8dc48c572a5016c79c3a2a878b6e39e8eeSimon Horman	if (slash)
92c2078f8dc48c572a5016c79c3a2a878b6e39e8eeSimon Horman		*slash = '\0';
9330eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
9430eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	ret = ll_addr_a2n(addr, sizeof(addr), str);
9530eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	if (ret < 0)
96c2078f8dc48c572a5016c79c3a2a878b6e39e8eeSimon Horman		goto err;
9730eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	addattr_l(n, MAX_MSG, addr_type, addr, sizeof(addr));
98c2078f8dc48c572a5016c79c3a2a878b6e39e8eeSimon Horman
99c2078f8dc48c572a5016c79c3a2a878b6e39e8eeSimon Horman	if (slash) {
100c2078f8dc48c572a5016c79c3a2a878b6e39e8eeSimon Horman		unsigned bits;
101c2078f8dc48c572a5016c79c3a2a878b6e39e8eeSimon Horman
102c2078f8dc48c572a5016c79c3a2a878b6e39e8eeSimon Horman		if (!get_unsigned(&bits, slash + 1, 10)) {
103c2078f8dc48c572a5016c79c3a2a878b6e39e8eeSimon Horman			uint64_t mask;
104c2078f8dc48c572a5016c79c3a2a878b6e39e8eeSimon Horman
105c2078f8dc48c572a5016c79c3a2a878b6e39e8eeSimon Horman			/* Extra 16 bit shift to push mac address into
106c2078f8dc48c572a5016c79c3a2a878b6e39e8eeSimon Horman			 * high bits of uint64_t
107c2078f8dc48c572a5016c79c3a2a878b6e39e8eeSimon Horman			 */
108c2078f8dc48c572a5016c79c3a2a878b6e39e8eeSimon Horman			mask = htonll(0xffffffffffffULL << (16 + 48 - bits));
109c2078f8dc48c572a5016c79c3a2a878b6e39e8eeSimon Horman			memcpy(addr, &mask, ETH_ALEN);
110c2078f8dc48c572a5016c79c3a2a878b6e39e8eeSimon Horman		} else {
111c2078f8dc48c572a5016c79c3a2a878b6e39e8eeSimon Horman			ret = ll_addr_a2n(addr, sizeof(addr), slash + 1);
112c2078f8dc48c572a5016c79c3a2a878b6e39e8eeSimon Horman			if (ret < 0)
113c2078f8dc48c572a5016c79c3a2a878b6e39e8eeSimon Horman				goto err;
114c2078f8dc48c572a5016c79c3a2a878b6e39e8eeSimon Horman		}
115c2078f8dc48c572a5016c79c3a2a878b6e39e8eeSimon Horman	} else {
116c2078f8dc48c572a5016c79c3a2a878b6e39e8eeSimon Horman		memset(addr, 0xff, ETH_ALEN);
117c2078f8dc48c572a5016c79c3a2a878b6e39e8eeSimon Horman	}
11830eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	addattr_l(n, MAX_MSG, mask_type, addr, sizeof(addr));
119c2078f8dc48c572a5016c79c3a2a878b6e39e8eeSimon Horman
120c2078f8dc48c572a5016c79c3a2a878b6e39e8eeSimon Horman	err = 0;
121c2078f8dc48c572a5016c79c3a2a878b6e39e8eeSimon Hormanerr:
122c2078f8dc48c572a5016c79c3a2a878b6e39e8eeSimon Horman	if (slash)
123c2078f8dc48c572a5016c79c3a2a878b6e39e8eeSimon Horman		*slash = '/';
124c2078f8dc48c572a5016c79c3a2a878b6e39e8eeSimon Horman	return err;
12530eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko}
12630eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
127745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zionstatic int flower_parse_vlan_eth_type(char *str, __be16 eth_type, int type,
128512caeb2737f1657d941945cc770a95882e1c1bbStephen Hemminger				      __be16 *p_vlan_eth_type,
129512caeb2737f1657d941945cc770a95882e1c1bbStephen Hemminger				      struct nlmsghdr *n)
130745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion{
131745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion	__be16 vlan_eth_type;
132745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion
133745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion	if (eth_type != htons(ETH_P_8021Q)) {
134512caeb2737f1657d941945cc770a95882e1c1bbStephen Hemminger		fprintf(stderr,
135512caeb2737f1657d941945cc770a95882e1c1bbStephen Hemminger			"Can't set \"vlan_ethtype\" if ethertype isn't 802.1Q\n");
136745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion		return -1;
137745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion	}
138745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion
139745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion	if (ll_proto_a2n(&vlan_eth_type, str))
140745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion		invarg("invalid vlan_ethtype", str);
141745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion	addattr16(n, MAX_MSG, type, vlan_eth_type);
142745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion	*p_vlan_eth_type = vlan_eth_type;
143745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion	return 0;
144745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion}
145745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion
14608f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakeystruct flag_to_string {
14708f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey	int flag;
14808f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey	enum flower_matching_flags type;
14908f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey	char *string;
15008f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey};
15122a8f019891ca73295298384612008ff538e48faPaul Blakey
15208f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakeystatic struct flag_to_string flags_str[] = {
15308f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey	{ TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT, FLOWER_IP_FLAGS, "frag" },
15408f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey};
15522a8f019891ca73295298384612008ff538e48faPaul Blakey
15608f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakeystatic int flower_parse_matching_flags(char *str,
15708f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey				       enum flower_matching_flags type,
15808f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey				       __u32 *mtf, __u32 *mtf_mask)
15908f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey{
16008f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey	char *token;
16108f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey	bool no;
16208f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey	bool found;
16308f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey	int i;
16422a8f019891ca73295298384612008ff538e48faPaul Blakey
16508f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey	token = strtok(str, "/");
16608f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey
16708f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey	while (token) {
16808f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey		if (!strncmp(token, "no", 2)) {
16908f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey			no = true;
17008f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey			token += 2;
17108f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey		} else
17208f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey			no = false;
17308f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey
17408f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey		found = false;
17508f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey		for (i = 0; i < ARRAY_SIZE(flags_str); i++) {
17608f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey			if (type != flags_str[i].type)
17708f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey				continue;
17808f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey
17908f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey			if (!strcmp(token, flags_str[i].string)) {
18008f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey				if (no)
18108f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey					*mtf &= ~flags_str[i].flag;
18208f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey				else
18308f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey					*mtf |= flags_str[i].flag;
18408f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey
18508f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey				*mtf_mask |= flags_str[i].flag;
18608f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey				found = true;
18708f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey				break;
18808f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey			}
18908f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey		}
19008f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey		if (!found)
19122a8f019891ca73295298384612008ff538e48faPaul Blakey			return -1;
19208f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey
19308f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey		token = strtok(NULL, "/");
19422a8f019891ca73295298384612008ff538e48faPaul Blakey	}
19522a8f019891ca73295298384612008ff538e48faPaul Blakey
19622a8f019891ca73295298384612008ff538e48faPaul Blakey	return 0;
19722a8f019891ca73295298384612008ff538e48faPaul Blakey}
19822a8f019891ca73295298384612008ff538e48faPaul Blakey
19930eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirkostatic int flower_parse_ip_proto(char *str, __be16 eth_type, int type,
20030eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko				 __u8 *p_ip_proto, struct nlmsghdr *n)
20130eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko{
20230eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	int ret;
20330eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	__u8 ip_proto;
20430eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
205eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman	if (eth_type != htons(ETH_P_IP) && eth_type != htons(ETH_P_IPV6))
206eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman		goto err;
207eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman
20830eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	if (matches(str, "tcp") == 0) {
20930eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		ip_proto = IPPROTO_TCP;
21030eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	} else if (matches(str, "udp") == 0) {
21130eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		ip_proto = IPPROTO_UDP;
212a1fb0d484237b41f92ee17634880be80a0dcf51aSimon Horman	} else if (matches(str, "sctp") == 0) {
213a1fb0d484237b41f92ee17634880be80a0dcf51aSimon Horman		ip_proto = IPPROTO_SCTP;
214eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman	} else if (matches(str, "icmp") == 0) {
215eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman		if (eth_type != htons(ETH_P_IP))
216eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman			goto err;
217eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman		ip_proto = IPPROTO_ICMP;
218eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman	} else if (matches(str, "icmpv6") == 0) {
219eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman		if (eth_type != htons(ETH_P_IPV6))
220eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman			goto err;
221eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman		ip_proto = IPPROTO_ICMPV6;
22230eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	} else {
22330eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		ret = get_u8(&ip_proto, str, 16);
22430eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		if (ret)
22530eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			return -1;
22630eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	}
22730eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	addattr8(n, MAX_MSG, type, ip_proto);
22830eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	*p_ip_proto = ip_proto;
22930eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	return 0;
230eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman
231eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Hormanerr:
232eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman	fprintf(stderr, "Illegal \"eth_type\" for ip proto\n");
233eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman	return -1;
23430eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko}
23530eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
236f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Hormanstatic int __flower_parse_ip_addr(char *str, int family,
237f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman				  int addr4_type, int mask4_type,
238f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman				  int addr6_type, int mask6_type,
239f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman				  struct nlmsghdr *n)
24030eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko{
24130eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	int ret;
24230eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	inet_prefix addr;
24330eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	int bits;
24430eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	int i;
24530eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
24630eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	ret = get_prefix(&addr, str, family);
24730eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	if (ret)
24830eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		return -1;
24930eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
250bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai	if (family && (addr.family != family)) {
251bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai		fprintf(stderr, "Illegal \"eth_type\" for ip address\n");
25230eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		return -1;
253bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai	}
25430eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
25530eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	addattr_l(n, MAX_MSG, addr.family == AF_INET ? addr4_type : addr6_type,
25630eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		  addr.data, addr.bytelen);
25730eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
25830eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	memset(addr.data, 0xff, addr.bytelen);
25930eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	bits = addr.bitlen;
26030eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	for (i = 0; i < addr.bytelen / 4; i++) {
26130eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		if (!bits) {
26230eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			addr.data[i] = 0;
26330eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		} else if (bits / 32 >= 1) {
26430eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			bits -= 32;
26530eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		} else {
26630eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			addr.data[i] <<= 32 - bits;
26730eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			addr.data[i] = htonl(addr.data[i]);
26830eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			bits = 0;
26930eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		}
27030eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	}
27130eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
27230eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	addattr_l(n, MAX_MSG, addr.family == AF_INET ? mask4_type : mask6_type,
27330eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		  addr.data, addr.bytelen);
27430eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
27530eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	return 0;
27630eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko}
27730eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
278f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Hormanstatic int flower_parse_ip_addr(char *str, __be16 eth_type,
279f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman				int addr4_type, int mask4_type,
280f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman				int addr6_type, int mask6_type,
281f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman				struct nlmsghdr *n)
282f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman{
283f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman	int family;
284f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman
285f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman	if (eth_type == htons(ETH_P_IP)) {
286f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman		family = AF_INET;
287f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman	} else if (eth_type == htons(ETH_P_IPV6)) {
288f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman		family = AF_INET6;
289f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman	} else if (!eth_type) {
290f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman		family = AF_UNSPEC;
291f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman	} else {
292f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman		return -1;
293f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman	}
294f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman
295164a9ff401e58ff9c0b90088a3aa96216e1d6e8aRoi Dayan	return __flower_parse_ip_addr(str, family, addr4_type, mask4_type,
296164a9ff401e58ff9c0b90088a3aa96216e1d6e8aRoi Dayan				      addr6_type, mask6_type, n);
297f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman}
298f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman
299f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Hormanstatic bool flower_eth_type_arp(__be16 eth_type)
300f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman{
301f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman	return eth_type == htons(ETH_P_ARP) || eth_type == htons(ETH_P_RARP);
302f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman}
303f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman
304f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Hormanstatic int flower_parse_arp_ip_addr(char *str, __be16 eth_type,
305f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman				    int addr_type, int mask_type,
306f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman				    struct nlmsghdr *n)
307f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman{
308f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman	if (!flower_eth_type_arp(eth_type))
309f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman		return -1;
310f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman
311f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman	return __flower_parse_ip_addr(str, AF_INET, addr_type, mask_type,
312f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman				      TCA_FLOWER_UNSPEC, TCA_FLOWER_UNSPEC, n);
313f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman}
314f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman
315180136e540ca16826c0069644222878ea8236f93Simon Hormanstatic int flower_parse_u8(char *str, int value_type, int mask_type,
316180136e540ca16826c0069644222878ea8236f93Simon Horman			   int (*value_from_name)(const char *str,
317180136e540ca16826c0069644222878ea8236f93Simon Horman						 __u8 *value),
318180136e540ca16826c0069644222878ea8236f93Simon Horman			   bool (*value_validate)(__u8 value),
319180136e540ca16826c0069644222878ea8236f93Simon Horman			   struct nlmsghdr *n)
320f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman{
321f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman	char *slash;
322f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman	int ret, err = -1;
323180136e540ca16826c0069644222878ea8236f93Simon Horman	__u8 value, mask;
324f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman
325f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman	slash = strchr(str, '/');
326f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman	if (slash)
327f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman		*slash = '\0';
328f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman
329180136e540ca16826c0069644222878ea8236f93Simon Horman	ret = value_from_name ? value_from_name(str, &value) : -1;
330180136e540ca16826c0069644222878ea8236f93Simon Horman	if (ret < 0) {
331f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman		ret = get_u8(&value, str, 10);
332f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman		if (ret)
333f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman			goto err;
334f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman	}
335f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman
336180136e540ca16826c0069644222878ea8236f93Simon Horman	if (value_validate && !value_validate(value))
337180136e540ca16826c0069644222878ea8236f93Simon Horman		goto err;
338180136e540ca16826c0069644222878ea8236f93Simon Horman
339f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman	if (slash) {
340f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman		ret = get_u8(&mask, slash + 1, 10);
341f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman		if (ret)
342f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman			goto err;
343f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman	}
344f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman	else {
345f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman		mask = UINT8_MAX;
346f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman	}
347f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman
348180136e540ca16826c0069644222878ea8236f93Simon Horman	addattr8(n, MAX_MSG, value_type, value);
349f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman	addattr8(n, MAX_MSG, mask_type, mask);
350f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman
351f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman	err = 0;
352f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Hormanerr:
353f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman	if (slash)
354f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman		*slash = '/';
355f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman	return err;
356f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman}
357f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman
3589d36e54f36b8360766519bba79028aeb9ec3a762Simon Hormanstatic const char *flower_print_arp_op_to_name(__u8 op)
3599d36e54f36b8360766519bba79028aeb9ec3a762Simon Horman{
3609d36e54f36b8360766519bba79028aeb9ec3a762Simon Horman	switch (op) {
3619d36e54f36b8360766519bba79028aeb9ec3a762Simon Horman	case ARPOP_REQUEST:
3629d36e54f36b8360766519bba79028aeb9ec3a762Simon Horman		return "request";
3639d36e54f36b8360766519bba79028aeb9ec3a762Simon Horman	case ARPOP_REPLY:
3649d36e54f36b8360766519bba79028aeb9ec3a762Simon Horman		return "reply";
3659d36e54f36b8360766519bba79028aeb9ec3a762Simon Horman	default:
3669d36e54f36b8360766519bba79028aeb9ec3a762Simon Horman		return NULL;
3679d36e54f36b8360766519bba79028aeb9ec3a762Simon Horman	}
3689d36e54f36b8360766519bba79028aeb9ec3a762Simon Horman}
3699d36e54f36b8360766519bba79028aeb9ec3a762Simon Horman
370180136e540ca16826c0069644222878ea8236f93Simon Hormanstatic int flower_arp_op_from_name(const char *name, __u8 *op)
371180136e540ca16826c0069644222878ea8236f93Simon Horman{
372180136e540ca16826c0069644222878ea8236f93Simon Horman	if (!strcmp(name, "request"))
373180136e540ca16826c0069644222878ea8236f93Simon Horman		*op = ARPOP_REQUEST;
374180136e540ca16826c0069644222878ea8236f93Simon Horman	else if (!strcmp(name, "reply"))
375180136e540ca16826c0069644222878ea8236f93Simon Horman		*op = ARPOP_REPLY;
376180136e540ca16826c0069644222878ea8236f93Simon Horman	else
377180136e540ca16826c0069644222878ea8236f93Simon Horman		return -1;
378180136e540ca16826c0069644222878ea8236f93Simon Horman
379180136e540ca16826c0069644222878ea8236f93Simon Horman	return 0;
380180136e540ca16826c0069644222878ea8236f93Simon Horman}
381180136e540ca16826c0069644222878ea8236f93Simon Horman
382180136e540ca16826c0069644222878ea8236f93Simon Hormanstatic bool flow_arp_op_validate(__u8 op)
383180136e540ca16826c0069644222878ea8236f93Simon Horman{
384180136e540ca16826c0069644222878ea8236f93Simon Horman	return !op || op == ARPOP_REQUEST || op == ARPOP_REPLY;
385180136e540ca16826c0069644222878ea8236f93Simon Horman}
386180136e540ca16826c0069644222878ea8236f93Simon Horman
387180136e540ca16826c0069644222878ea8236f93Simon Hormanstatic int flower_parse_arp_op(char *str, __be16 eth_type,
388180136e540ca16826c0069644222878ea8236f93Simon Horman			       int op_type, int mask_type,
389180136e540ca16826c0069644222878ea8236f93Simon Horman			       struct nlmsghdr *n)
390180136e540ca16826c0069644222878ea8236f93Simon Horman{
391180136e540ca16826c0069644222878ea8236f93Simon Horman	if (!flower_eth_type_arp(eth_type))
392180136e540ca16826c0069644222878ea8236f93Simon Horman		return -1;
393180136e540ca16826c0069644222878ea8236f93Simon Horman
394180136e540ca16826c0069644222878ea8236f93Simon Horman	return flower_parse_u8(str, op_type, mask_type, flower_arp_op_from_name,
395180136e540ca16826c0069644222878ea8236f93Simon Horman			       flow_arp_op_validate, n);
396180136e540ca16826c0069644222878ea8236f93Simon Horman}
397180136e540ca16826c0069644222878ea8236f93Simon Horman
398eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Hormanstatic int flower_icmp_attr_type(__be16 eth_type, __u8 ip_proto,
399eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman				 enum flower_icmp_field field)
400eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman{
401eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman	if (eth_type == htons(ETH_P_IP) && ip_proto == IPPROTO_ICMP)
402eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman		return field == FLOWER_ICMP_FIELD_CODE ?
403eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman			TCA_FLOWER_KEY_ICMPV4_CODE :
404eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman			TCA_FLOWER_KEY_ICMPV4_TYPE;
405eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman	else if (eth_type == htons(ETH_P_IPV6) && ip_proto == IPPROTO_ICMPV6)
406eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman		return field == FLOWER_ICMP_FIELD_CODE ?
407eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman			TCA_FLOWER_KEY_ICMPV6_CODE :
408eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman			TCA_FLOWER_KEY_ICMPV6_TYPE;
409eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman
410eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman	return -1;
411eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman}
412eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman
4136374961a00d4b862bdf87c0f22af86d3ff7d0d67Simon Hormanstatic int flower_icmp_attr_mask_type(__be16 eth_type, __u8 ip_proto,
4146374961a00d4b862bdf87c0f22af86d3ff7d0d67Simon Horman				      enum flower_icmp_field field)
4156374961a00d4b862bdf87c0f22af86d3ff7d0d67Simon Horman{
4166374961a00d4b862bdf87c0f22af86d3ff7d0d67Simon Horman	if (eth_type == htons(ETH_P_IP) && ip_proto == IPPROTO_ICMP)
4176374961a00d4b862bdf87c0f22af86d3ff7d0d67Simon Horman		return field == FLOWER_ICMP_FIELD_CODE ?
4186374961a00d4b862bdf87c0f22af86d3ff7d0d67Simon Horman			TCA_FLOWER_KEY_ICMPV4_CODE_MASK :
4196374961a00d4b862bdf87c0f22af86d3ff7d0d67Simon Horman			TCA_FLOWER_KEY_ICMPV4_TYPE_MASK;
4206374961a00d4b862bdf87c0f22af86d3ff7d0d67Simon Horman	else if (eth_type == htons(ETH_P_IPV6) && ip_proto == IPPROTO_ICMPV6)
4216374961a00d4b862bdf87c0f22af86d3ff7d0d67Simon Horman		return field == FLOWER_ICMP_FIELD_CODE ?
4226374961a00d4b862bdf87c0f22af86d3ff7d0d67Simon Horman			TCA_FLOWER_KEY_ICMPV6_CODE_MASK :
4236374961a00d4b862bdf87c0f22af86d3ff7d0d67Simon Horman			TCA_FLOWER_KEY_ICMPV6_TYPE_MASK;
4246374961a00d4b862bdf87c0f22af86d3ff7d0d67Simon Horman
4256374961a00d4b862bdf87c0f22af86d3ff7d0d67Simon Horman	return -1;
4266374961a00d4b862bdf87c0f22af86d3ff7d0d67Simon Horman}
4276374961a00d4b862bdf87c0f22af86d3ff7d0d67Simon Horman
428eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Hormanstatic int flower_parse_icmp(char *str, __u16 eth_type, __u8 ip_proto,
429eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman			     enum flower_icmp_field field, struct nlmsghdr *n)
430eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman{
4316374961a00d4b862bdf87c0f22af86d3ff7d0d67Simon Horman	int value_type, mask_type;
432eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman
4336374961a00d4b862bdf87c0f22af86d3ff7d0d67Simon Horman	value_type = flower_icmp_attr_type(eth_type, ip_proto, field);
4346374961a00d4b862bdf87c0f22af86d3ff7d0d67Simon Horman	mask_type = flower_icmp_attr_mask_type(eth_type, ip_proto, field);
4356374961a00d4b862bdf87c0f22af86d3ff7d0d67Simon Horman	if (value_type < 0 || mask_type < 0)
436eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman		return -1;
437eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman
4386374961a00d4b862bdf87c0f22af86d3ff7d0d67Simon Horman	return flower_parse_u8(str, value_type, mask_type, NULL, NULL, n);
439eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman}
440eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman
4416910d65661a3718ef4b944251a0dec170027f3d5Simon Hormanstatic int flower_port_attr_type(__u8 ip_proto, enum flower_endpoint endpoint)
44230eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko{
4436bd5b80cdcfbeb30b79c3ff07ce844f9e4f2c600Simon Horman	if (ip_proto == IPPROTO_TCP)
4446910d65661a3718ef4b944251a0dec170027f3d5Simon Horman		return endpoint == FLOWER_ENDPOINT_SRC ?
4456910d65661a3718ef4b944251a0dec170027f3d5Simon Horman			TCA_FLOWER_KEY_TCP_SRC :
446a1fb0d484237b41f92ee17634880be80a0dcf51aSimon Horman			TCA_FLOWER_KEY_TCP_DST;
4476bd5b80cdcfbeb30b79c3ff07ce844f9e4f2c600Simon Horman	else if (ip_proto == IPPROTO_UDP)
4486910d65661a3718ef4b944251a0dec170027f3d5Simon Horman		return endpoint == FLOWER_ENDPOINT_SRC ?
4496910d65661a3718ef4b944251a0dec170027f3d5Simon Horman			TCA_FLOWER_KEY_UDP_SRC :
450a1fb0d484237b41f92ee17634880be80a0dcf51aSimon Horman			TCA_FLOWER_KEY_UDP_DST;
4516bd5b80cdcfbeb30b79c3ff07ce844f9e4f2c600Simon Horman	else if (ip_proto == IPPROTO_SCTP)
4526910d65661a3718ef4b944251a0dec170027f3d5Simon Horman		return endpoint == FLOWER_ENDPOINT_SRC ?
4536910d65661a3718ef4b944251a0dec170027f3d5Simon Horman			TCA_FLOWER_KEY_SCTP_SRC :
454a1fb0d484237b41f92ee17634880be80a0dcf51aSimon Horman			TCA_FLOWER_KEY_SCTP_DST;
4556bd5b80cdcfbeb30b79c3ff07ce844f9e4f2c600Simon Horman	else
45630eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		return -1;
457a1fb0d484237b41f92ee17634880be80a0dcf51aSimon Horman}
458a1fb0d484237b41f92ee17634880be80a0dcf51aSimon Horman
4596910d65661a3718ef4b944251a0dec170027f3d5Simon Hormanstatic int flower_parse_port(char *str, __u8 ip_proto,
4606910d65661a3718ef4b944251a0dec170027f3d5Simon Horman			     enum flower_endpoint endpoint,
461a1fb0d484237b41f92ee17634880be80a0dcf51aSimon Horman			     struct nlmsghdr *n)
462a1fb0d484237b41f92ee17634880be80a0dcf51aSimon Horman{
463a1fb0d484237b41f92ee17634880be80a0dcf51aSimon Horman	int ret;
464a1fb0d484237b41f92ee17634880be80a0dcf51aSimon Horman	int type;
465a1fb0d484237b41f92ee17634880be80a0dcf51aSimon Horman	__be16 port;
466a1fb0d484237b41f92ee17634880be80a0dcf51aSimon Horman
4676910d65661a3718ef4b944251a0dec170027f3d5Simon Horman	type = flower_port_attr_type(ip_proto, endpoint);
468a1fb0d484237b41f92ee17634880be80a0dcf51aSimon Horman	if (type < 0)
469a1fb0d484237b41f92ee17634880be80a0dcf51aSimon Horman		return -1;
47030eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
4719f7401fa4967178a071c53498f6bdc460c7cc4eaSabrina Dubroca	ret = get_be16(&port, str, 10);
47230eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	if (ret)
47330eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		return -1;
47430eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
4759f7401fa4967178a071c53498f6bdc460c7cc4eaSabrina Dubroca	addattr16(n, MAX_MSG, type, port);
47630eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
47730eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	return 0;
47830eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko}
47930eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
4800c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko#define TCP_FLAGS_MAX_MASK 0xfff
4810c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko
4820c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirkostatic int flower_parse_tcp_flags(char *str, int flags_type, int mask_type,
4830c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko				  struct nlmsghdr *n)
4840c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko{
4850c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko	char *slash;
4860c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko	int ret, err = -1;
4870c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko	__u16 flags;
4880c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko
4890c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko	slash = strchr(str, '/');
4900c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko	if (slash)
4910c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko		*slash = '\0';
4920c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko
4930c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko	ret = get_u16(&flags, str, 16);
4940c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko	if (ret < 0 || flags & ~TCP_FLAGS_MAX_MASK)
4950c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko		goto err;
4960c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko
4970c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko	addattr16(n, MAX_MSG, flags_type, htons(flags));
4980c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko
4990c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko	if (slash) {
5000c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko		ret = get_u16(&flags, slash + 1, 16);
5010c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko		if (ret < 0 || flags & ~TCP_FLAGS_MAX_MASK)
5020c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko			goto err;
5030c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko	} else {
5040c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko		flags = TCP_FLAGS_MAX_MASK;
5050c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko	}
5060c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko	addattr16(n, MAX_MSG, mask_type, htons(flags));
5070c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko
5080c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko	err = 0;
5090c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirkoerr:
5100c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko	if (slash)
5110c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko		*slash = '/';
5120c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko	return err;
5130c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko}
5140c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko
5156ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitzstatic int flower_parse_ip_tos_ttl(char *str, int key_type, int mask_type,
5166ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz				   struct nlmsghdr *n)
5176ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz{
5186ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz	char *slash;
5196ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz	int ret, err = -1;
5206ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz	__u8 tos_ttl;
5216ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz
5226ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz	slash = strchr(str, '/');
5236ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz	if (slash)
5246ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz		*slash = '\0';
5256ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz
5266ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz	ret = get_u8(&tos_ttl, str, 10);
5276ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz	if (ret < 0)
5286ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz		ret = get_u8(&tos_ttl, str, 16);
5296ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz	if (ret < 0)
5306ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz		goto err;
5316ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz
5326ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz	addattr8(n, MAX_MSG, key_type, tos_ttl);
5336ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz
5346ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz	if (slash) {
5356ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz		ret = get_u8(&tos_ttl, slash + 1, 16);
5366ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz		if (ret < 0)
5376ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz			goto err;
5386ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz	} else {
5396ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz		tos_ttl = 0xff;
5406ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz	}
5416ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz	addattr8(n, MAX_MSG, mask_type, tos_ttl);
5426ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz
5436ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz	err = 0;
5446ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitzerr:
5456ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz	if (slash)
5466ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz		*slash = '/';
5476ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz	return err;
5486ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz}
5496ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz
550bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadaistatic int flower_parse_key_id(const char *str, int type, struct nlmsghdr *n)
551bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai{
552bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai	int ret;
553bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai	__be32 key_id;
554bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai
555bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai	ret = get_be32(&key_id, str, 10);
556bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai	if (!ret)
557bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai		addattr32(n, MAX_MSG, type, key_id);
558bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai
559bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai	return ret;
560bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai}
561bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai
56241aa17ff4668ce97ec27e5f4cdc20db7169b549bHadar Hen Zionstatic int flower_parse_enc_port(char *str, int type, struct nlmsghdr *n)
56341aa17ff4668ce97ec27e5f4cdc20db7169b549bHadar Hen Zion{
56441aa17ff4668ce97ec27e5f4cdc20db7169b549bHadar Hen Zion	int ret;
56541aa17ff4668ce97ec27e5f4cdc20db7169b549bHadar Hen Zion	__be16 port;
56641aa17ff4668ce97ec27e5f4cdc20db7169b549bHadar Hen Zion
56741aa17ff4668ce97ec27e5f4cdc20db7169b549bHadar Hen Zion	ret = get_be16(&port, str, 10);
56841aa17ff4668ce97ec27e5f4cdc20db7169b549bHadar Hen Zion	if (ret)
56941aa17ff4668ce97ec27e5f4cdc20db7169b549bHadar Hen Zion		return -1;
57041aa17ff4668ce97ec27e5f4cdc20db7169b549bHadar Hen Zion
57141aa17ff4668ce97ec27e5f4cdc20db7169b549bHadar Hen Zion	addattr16(n, MAX_MSG, type, port);
57241aa17ff4668ce97ec27e5f4cdc20db7169b549bHadar Hen Zion
57341aa17ff4668ce97ec27e5f4cdc20db7169b549bHadar Hen Zion	return 0;
57441aa17ff4668ce97ec27e5f4cdc20db7169b549bHadar Hen Zion}
57541aa17ff4668ce97ec27e5f4cdc20db7169b549bHadar Hen Zion
57630eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirkostatic int flower_parse_opt(struct filter_util *qu, char *handle,
57730eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			    int argc, char **argv, struct nlmsghdr *n)
57830eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko{
57930eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	int ret;
58030eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	struct tcmsg *t = NLMSG_DATA(n);
58130eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	struct rtattr *tail;
582488b41d020fb06428b90289f70a41210718f52b7Jamal Hadi Salim	__be16 eth_type = TC_H_MIN(t->tcm_info);
583745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion	__be16 vlan_ethtype = 0;
58430eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	__u8 ip_proto = 0xff;
585cfcabf18d84a2f4908cb5b4489f67c2cd3f70426Amir Vadai	__u32 flags = 0;
58608f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey	__u32 mtf = 0;
58708f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey	__u32 mtf_mask = 0;
58830eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
58930eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	if (handle) {
59030eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		ret = get_u32(&t->tcm_handle, handle, 0);
59130eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		if (ret) {
59230eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			fprintf(stderr, "Illegal \"handle\"\n");
59330eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			return -1;
59430eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		}
59530eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	}
59630eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
59730eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	tail = (struct rtattr *) (((void *) n) + NLMSG_ALIGN(n->nlmsg_len));
59830eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	addattr_l(n, MAX_MSG, TCA_OPTIONS, NULL, 0);
59930eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
600488b41d020fb06428b90289f70a41210718f52b7Jamal Hadi Salim	if (argc == 0) {
601488b41d020fb06428b90289f70a41210718f52b7Jamal Hadi Salim		/*at minimal we will match all ethertype packets */
602488b41d020fb06428b90289f70a41210718f52b7Jamal Hadi Salim		goto parse_done;
603488b41d020fb06428b90289f70a41210718f52b7Jamal Hadi Salim	}
604488b41d020fb06428b90289f70a41210718f52b7Jamal Hadi Salim
60530eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	while (argc > 0) {
60630eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		if (matches(*argv, "classid") == 0 ||
60730eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		    matches(*argv, "flowid") == 0) {
60832a121cba257954963fbdd56a1c4567c2efc779aStephen Hemminger			unsigned int handle;
60930eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
61030eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			NEXT_ARG();
61130eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			ret = get_tc_classid(&handle, *argv);
61230eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			if (ret) {
61330eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko				fprintf(stderr, "Illegal \"classid\"\n");
61430eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko				return -1;
61530eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			}
61630eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			addattr_l(n, MAX_MSG, TCA_FLOWER_CLASSID, &handle, 4);
61708f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey		} else if (matches(*argv, "ip_flags") == 0) {
61822a8f019891ca73295298384612008ff538e48faPaul Blakey			NEXT_ARG();
61922a8f019891ca73295298384612008ff538e48faPaul Blakey			ret = flower_parse_matching_flags(*argv,
62008f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey							  FLOWER_IP_FLAGS,
62108f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey							  &mtf,
62208f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey							  &mtf_mask);
62322a8f019891ca73295298384612008ff538e48faPaul Blakey			if (ret < 0) {
62408f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey				fprintf(stderr, "Illegal \"ip_flags\"\n");
62522a8f019891ca73295298384612008ff538e48faPaul Blakey				return -1;
62622a8f019891ca73295298384612008ff538e48faPaul Blakey			}
627cfcabf18d84a2f4908cb5b4489f67c2cd3f70426Amir Vadai		} else if (matches(*argv, "skip_hw") == 0) {
628cfcabf18d84a2f4908cb5b4489f67c2cd3f70426Amir Vadai			flags |= TCA_CLS_FLAGS_SKIP_HW;
629cfcabf18d84a2f4908cb5b4489f67c2cd3f70426Amir Vadai		} else if (matches(*argv, "skip_sw") == 0) {
630cfcabf18d84a2f4908cb5b4489f67c2cd3f70426Amir Vadai			flags |= TCA_CLS_FLAGS_SKIP_SW;
63130eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		} else if (matches(*argv, "indev") == 0) {
63230eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			NEXT_ARG();
633625df645b703dc858d54784c35beff64464afae2Phil Sutter			if (check_ifname(*argv))
634625df645b703dc858d54784c35beff64464afae2Phil Sutter				invarg("\"indev\" not a valid ifname", *argv);
635ee474849c85116ec36e387882447f737ac3fdefbPhil Sutter			addattrstrz(n, MAX_MSG, TCA_FLOWER_INDEV, *argv);
636745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion		} else if (matches(*argv, "vlan_id") == 0) {
637745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion			__u16 vid;
638745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion
639745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion			NEXT_ARG();
640745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion			if (eth_type != htons(ETH_P_8021Q)) {
641512caeb2737f1657d941945cc770a95882e1c1bbStephen Hemminger				fprintf(stderr,
642512caeb2737f1657d941945cc770a95882e1c1bbStephen Hemminger					"Can't set \"vlan_id\" if ethertype isn't 802.1Q\n");
643745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion				return -1;
644745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion			}
645745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion			ret = get_u16(&vid, *argv, 10);
646745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion			if (ret < 0 || vid & ~0xfff) {
647745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion				fprintf(stderr, "Illegal \"vlan_id\"\n");
648745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion				return -1;
649745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion			}
650745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion			addattr16(n, MAX_MSG, TCA_FLOWER_KEY_VLAN_ID, vid);
651745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion		} else if (matches(*argv, "vlan_prio") == 0) {
652745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion			__u8 vlan_prio;
653745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion
654745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion			NEXT_ARG();
655745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion			if (eth_type != htons(ETH_P_8021Q)) {
656512caeb2737f1657d941945cc770a95882e1c1bbStephen Hemminger				fprintf(stderr,
657512caeb2737f1657d941945cc770a95882e1c1bbStephen Hemminger					"Can't set \"vlan_prio\" if ethertype isn't 802.1Q\n");
658745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion				return -1;
659745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion			}
660745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion			ret = get_u8(&vlan_prio, *argv, 10);
661745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion			if (ret < 0 || vlan_prio & ~0x7) {
662745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion				fprintf(stderr, "Illegal \"vlan_prio\"\n");
663745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion				return -1;
664745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion			}
665512caeb2737f1657d941945cc770a95882e1c1bbStephen Hemminger			addattr8(n, MAX_MSG,
666512caeb2737f1657d941945cc770a95882e1c1bbStephen Hemminger				 TCA_FLOWER_KEY_VLAN_PRIO, vlan_prio);
667745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion		} else if (matches(*argv, "vlan_ethtype") == 0) {
668745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion			NEXT_ARG();
669745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion			ret = flower_parse_vlan_eth_type(*argv, eth_type,
670512caeb2737f1657d941945cc770a95882e1c1bbStephen Hemminger						 TCA_FLOWER_KEY_VLAN_ETH_TYPE,
671512caeb2737f1657d941945cc770a95882e1c1bbStephen Hemminger						 &vlan_ethtype, n);
672745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion			if (ret < 0)
673745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion				return -1;
67430eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		} else if (matches(*argv, "dst_mac") == 0) {
67530eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			NEXT_ARG();
67630eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			ret = flower_parse_eth_addr(*argv,
67730eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko						    TCA_FLOWER_KEY_ETH_DST,
67830eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko						    TCA_FLOWER_KEY_ETH_DST_MASK,
67930eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko						    n);
68030eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			if (ret < 0) {
68130eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko				fprintf(stderr, "Illegal \"dst_mac\"\n");
68230eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko				return -1;
68330eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			}
68430eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		} else if (matches(*argv, "src_mac") == 0) {
68530eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			NEXT_ARG();
68630eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			ret = flower_parse_eth_addr(*argv,
68730eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko						    TCA_FLOWER_KEY_ETH_SRC,
68830eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko						    TCA_FLOWER_KEY_ETH_SRC_MASK,
68930eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko						    n);
69030eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			if (ret < 0) {
69130eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko				fprintf(stderr, "Illegal \"src_mac\"\n");
69230eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko				return -1;
69330eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			}
69430eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		} else if (matches(*argv, "ip_proto") == 0) {
69530eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			NEXT_ARG();
696745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion			ret = flower_parse_ip_proto(*argv, vlan_ethtype ?
697745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion						    vlan_ethtype : eth_type,
69830eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko						    TCA_FLOWER_KEY_IP_PROTO,
69930eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko						    &ip_proto, n);
70030eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			if (ret < 0) {
70130eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko				fprintf(stderr, "Illegal \"ip_proto\"\n");
70230eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko				return -1;
70330eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			}
7046ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz		} else if (matches(*argv, "ip_tos") == 0) {
7056ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz			NEXT_ARG();
7066ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz			ret = flower_parse_ip_tos_ttl(*argv,
7076ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz						      TCA_FLOWER_KEY_IP_TOS,
7086ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz						      TCA_FLOWER_KEY_IP_TOS_MASK,
7096ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz						      n);
7106ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz			if (ret < 0) {
7116ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz				fprintf(stderr, "Illegal \"ip_tos\"\n");
7126ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz				return -1;
7136ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz			}
7146ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz		} else if (matches(*argv, "ip_ttl") == 0) {
7156ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz			NEXT_ARG();
7166ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz			ret = flower_parse_ip_tos_ttl(*argv,
7176ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz						      TCA_FLOWER_KEY_IP_TTL,
7186ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz						      TCA_FLOWER_KEY_IP_TTL_MASK,
7196ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz						      n);
7206ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz			if (ret < 0) {
7216ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz				fprintf(stderr, "Illegal \"ip_ttl\"\n");
7226ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz				return -1;
7236ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz			}
72430eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		} else if (matches(*argv, "dst_ip") == 0) {
72530eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			NEXT_ARG();
726745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion			ret = flower_parse_ip_addr(*argv, vlan_ethtype ?
727745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion						   vlan_ethtype : eth_type,
72830eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko						   TCA_FLOWER_KEY_IPV4_DST,
72930eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko						   TCA_FLOWER_KEY_IPV4_DST_MASK,
73030eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko						   TCA_FLOWER_KEY_IPV6_DST,
73130eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko						   TCA_FLOWER_KEY_IPV6_DST_MASK,
73230eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko						   n);
73330eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			if (ret < 0) {
73430eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko				fprintf(stderr, "Illegal \"dst_ip\"\n");
73530eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko				return -1;
73630eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			}
73730eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		} else if (matches(*argv, "src_ip") == 0) {
73830eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			NEXT_ARG();
739745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion			ret = flower_parse_ip_addr(*argv, vlan_ethtype ?
740745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion						   vlan_ethtype : eth_type,
74130eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko						   TCA_FLOWER_KEY_IPV4_SRC,
74230eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko						   TCA_FLOWER_KEY_IPV4_SRC_MASK,
74330eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko						   TCA_FLOWER_KEY_IPV6_SRC,
74430eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko						   TCA_FLOWER_KEY_IPV6_SRC_MASK,
74530eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko						   n);
74630eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			if (ret < 0) {
74730eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko				fprintf(stderr, "Illegal \"src_ip\"\n");
74830eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko				return -1;
74930eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			}
75030eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		} else if (matches(*argv, "dst_port") == 0) {
75130eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			NEXT_ARG();
7526910d65661a3718ef4b944251a0dec170027f3d5Simon Horman			ret = flower_parse_port(*argv, ip_proto,
7536910d65661a3718ef4b944251a0dec170027f3d5Simon Horman						FLOWER_ENDPOINT_DST, n);
75430eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			if (ret < 0) {
75530eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko				fprintf(stderr, "Illegal \"dst_port\"\n");
75630eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko				return -1;
75730eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			}
75830eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		} else if (matches(*argv, "src_port") == 0) {
75930eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			NEXT_ARG();
7606910d65661a3718ef4b944251a0dec170027f3d5Simon Horman			ret = flower_parse_port(*argv, ip_proto,
7616910d65661a3718ef4b944251a0dec170027f3d5Simon Horman						FLOWER_ENDPOINT_SRC, n);
76230eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			if (ret < 0) {
76330eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko				fprintf(stderr, "Illegal \"src_port\"\n");
76430eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko				return -1;
76530eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			}
7660c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko		} else if (matches(*argv, "tcp_flags") == 0) {
7670c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko			NEXT_ARG();
7680c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko			ret = flower_parse_tcp_flags(*argv,
7690c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko						     TCA_FLOWER_KEY_TCP_FLAGS,
7700c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko						     TCA_FLOWER_KEY_TCP_FLAGS_MASK,
7710c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko						     n);
7720c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko			if (ret < 0) {
7730c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko				fprintf(stderr, "Illegal \"tcp_flags\"\n");
7740c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko				return -1;
7750c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko			}
776eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman		} else if (matches(*argv, "type") == 0) {
777eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman			NEXT_ARG();
778eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman			ret = flower_parse_icmp(*argv, eth_type, ip_proto,
779eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman						FLOWER_ICMP_FIELD_TYPE, n);
780eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman			if (ret < 0) {
781eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman				fprintf(stderr, "Illegal \"icmp type\"\n");
782eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman				return -1;
783eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman			}
784eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman		} else if (matches(*argv, "code") == 0) {
785eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman			NEXT_ARG();
786eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman			ret = flower_parse_icmp(*argv, eth_type, ip_proto,
787eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman						FLOWER_ICMP_FIELD_CODE, n);
788eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman			if (ret < 0) {
789eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman				fprintf(stderr, "Illegal \"icmp code\"\n");
790eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman				return -1;
791eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman			}
792f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman		} else if (matches(*argv, "arp_tip") == 0) {
793f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman			NEXT_ARG();
794f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman			ret = flower_parse_arp_ip_addr(*argv, vlan_ethtype ?
795f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman						       vlan_ethtype : eth_type,
796f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman						       TCA_FLOWER_KEY_ARP_TIP,
797f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman						       TCA_FLOWER_KEY_ARP_TIP_MASK,
798f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman						       n);
799f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman			if (ret < 0) {
800f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman				fprintf(stderr, "Illegal \"arp_tip\"\n");
801f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman				return -1;
802f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman			}
803f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman		} else if (matches(*argv, "arp_sip") == 0) {
804f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman			NEXT_ARG();
805f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman			ret = flower_parse_arp_ip_addr(*argv, vlan_ethtype ?
806f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman						       vlan_ethtype : eth_type,
807f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman						       TCA_FLOWER_KEY_ARP_SIP,
808f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman						       TCA_FLOWER_KEY_ARP_SIP_MASK,
809f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman						       n);
810f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman			if (ret < 0) {
811f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman				fprintf(stderr, "Illegal \"arp_sip\"\n");
812f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman				return -1;
813f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman			}
814f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman		} else if (matches(*argv, "arp_op") == 0) {
815f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman			NEXT_ARG();
816f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman			ret = flower_parse_arp_op(*argv, vlan_ethtype ?
817f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman						  vlan_ethtype : eth_type,
818f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman						  TCA_FLOWER_KEY_ARP_OP,
819f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman						  TCA_FLOWER_KEY_ARP_OP_MASK,
820f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman						  n);
821f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman			if (ret < 0) {
822f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman				fprintf(stderr, "Illegal \"arp_op\"\n");
823f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman				return -1;
824f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman			}
825f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman		} else if (matches(*argv, "arp_tha") == 0) {
826f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman			NEXT_ARG();
827f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman			ret = flower_parse_eth_addr(*argv,
828f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman						    TCA_FLOWER_KEY_ARP_THA,
829f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman						    TCA_FLOWER_KEY_ARP_THA_MASK,
830f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman						    n);
831f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman			if (ret < 0) {
832f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman				fprintf(stderr, "Illegal \"arp_tha\"\n");
833f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman				return -1;
834f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman			}
835f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman		} else if (matches(*argv, "arp_sha") == 0) {
836f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman			NEXT_ARG();
837f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman			ret = flower_parse_eth_addr(*argv,
838f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman						    TCA_FLOWER_KEY_ARP_SHA,
839f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman						    TCA_FLOWER_KEY_ARP_SHA_MASK,
840f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman						    n);
841f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman			if (ret < 0) {
842f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman				fprintf(stderr, "Illegal \"arp_sha\"\n");
843f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman				return -1;
844f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman			}
845bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai		} else if (matches(*argv, "enc_dst_ip") == 0) {
846bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai			NEXT_ARG();
847bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai			ret = flower_parse_ip_addr(*argv, 0,
848bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai						   TCA_FLOWER_KEY_ENC_IPV4_DST,
849bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai						   TCA_FLOWER_KEY_ENC_IPV4_DST_MASK,
850bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai						   TCA_FLOWER_KEY_ENC_IPV6_DST,
851bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai						   TCA_FLOWER_KEY_ENC_IPV6_DST_MASK,
852bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai						   n);
853bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai			if (ret < 0) {
854bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai				fprintf(stderr, "Illegal \"enc_dst_ip\"\n");
855bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai				return -1;
856bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai			}
857bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai		} else if (matches(*argv, "enc_src_ip") == 0) {
858bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai			NEXT_ARG();
859bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai			ret = flower_parse_ip_addr(*argv, 0,
860bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai						   TCA_FLOWER_KEY_ENC_IPV4_SRC,
861bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai						   TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK,
862bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai						   TCA_FLOWER_KEY_ENC_IPV6_SRC,
863bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai						   TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK,
864bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai						   n);
865bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai			if (ret < 0) {
866bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai				fprintf(stderr, "Illegal \"enc_src_ip\"\n");
867bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai				return -1;
868bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai			}
869bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai		} else if (matches(*argv, "enc_key_id") == 0) {
870bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai			NEXT_ARG();
871bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai			ret = flower_parse_key_id(*argv,
872bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai						  TCA_FLOWER_KEY_ENC_KEY_ID, n);
873bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai			if (ret < 0) {
874bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai				fprintf(stderr, "Illegal \"enc_key_id\"\n");
875bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai				return -1;
876bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai			}
87741aa17ff4668ce97ec27e5f4cdc20db7169b549bHadar Hen Zion		} else if (matches(*argv, "enc_dst_port") == 0) {
87841aa17ff4668ce97ec27e5f4cdc20db7169b549bHadar Hen Zion			NEXT_ARG();
87941aa17ff4668ce97ec27e5f4cdc20db7169b549bHadar Hen Zion			ret = flower_parse_enc_port(*argv,
88041aa17ff4668ce97ec27e5f4cdc20db7169b549bHadar Hen Zion						    TCA_FLOWER_KEY_ENC_UDP_DST_PORT, n);
88141aa17ff4668ce97ec27e5f4cdc20db7169b549bHadar Hen Zion			if (ret < 0) {
88241aa17ff4668ce97ec27e5f4cdc20db7169b549bHadar Hen Zion				fprintf(stderr, "Illegal \"enc_dst_port\"\n");
88341aa17ff4668ce97ec27e5f4cdc20db7169b549bHadar Hen Zion				return -1;
88441aa17ff4668ce97ec27e5f4cdc20db7169b549bHadar Hen Zion			}
88530eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		} else if (matches(*argv, "action") == 0) {
88630eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			NEXT_ARG();
88730eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			ret = parse_action(&argc, &argv, TCA_FLOWER_ACT, n);
88830eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			if (ret) {
88930eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko				fprintf(stderr, "Illegal \"action\"\n");
89030eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko				return -1;
89130eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			}
89230eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			continue;
89330eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		} else if (strcmp(*argv, "help") == 0) {
89430eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			explain();
89530eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			return -1;
89630eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		} else {
89730eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			fprintf(stderr, "What is \"%s\"?\n", *argv);
89830eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			explain();
89930eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			return -1;
90030eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		}
90130eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		argc--; argv++;
90230eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	}
90330eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
904488b41d020fb06428b90289f70a41210718f52b7Jamal Hadi Salimparse_done:
905c85609b25faff034d450b0106fac7932d6acf124Roi Dayan	ret = addattr32(n, MAX_MSG, TCA_FLOWER_FLAGS, flags);
906c85609b25faff034d450b0106fac7932d6acf124Roi Dayan	if (ret)
907c85609b25faff034d450b0106fac7932d6acf124Roi Dayan		return ret;
908cfcabf18d84a2f4908cb5b4489f67c2cd3f70426Amir Vadai
90908f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey	if (mtf_mask) {
91008f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey		ret = addattr32(n, MAX_MSG, TCA_FLOWER_KEY_FLAGS, htonl(mtf));
91108f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey		if (ret)
91208f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey			return ret;
91308f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey
91408f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey		ret = addattr32(n, MAX_MSG, TCA_FLOWER_KEY_FLAGS_MASK, htonl(mtf_mask));
91508f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey		if (ret)
91608f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey			return ret;
91708f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey	}
91808f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey
9194f7d406f5dc89229d8aec8b723015c06db343e17Benjamin LaHaise	if (eth_type != htons(ETH_P_ALL)) {
9204f7d406f5dc89229d8aec8b723015c06db343e17Benjamin LaHaise		ret = addattr16(n, MAX_MSG, TCA_FLOWER_KEY_ETH_TYPE, eth_type);
9214f7d406f5dc89229d8aec8b723015c06db343e17Benjamin LaHaise		if (ret)
9224f7d406f5dc89229d8aec8b723015c06db343e17Benjamin LaHaise			return ret;
9234f7d406f5dc89229d8aec8b723015c06db343e17Benjamin LaHaise	}
924488b41d020fb06428b90289f70a41210718f52b7Jamal Hadi Salim
92532a121cba257954963fbdd56a1c4567c2efc779aStephen Hemminger	tail->rta_len = (((void *)n)+n->nlmsg_len) - (void *)tail;
92630eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
92730eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	return 0;
92830eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko}
92930eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
93030eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirkostatic int __mask_bits(char *addr, size_t len)
93130eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko{
93230eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	int bits = 0;
93330eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	bool hole = false;
93430eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	int i;
93530eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	int j;
93630eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
93730eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	for (i = 0; i < len; i++, addr++) {
93830eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		for (j = 7; j >= 0; j--) {
93930eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			if (((*addr) >> j) & 0x1) {
94030eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko				if (hole)
94130eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko					return -1;
94230eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko				bits++;
94330eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			} else if (bits) {
94430eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko				hole = true;
94530eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			} else{
94630eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko				return -1;
94730eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			}
94830eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		}
94930eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	}
95030eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	return bits;
95130eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko}
95230eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
95330eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirkostatic void flower_print_eth_addr(FILE *f, char *name,
95430eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko				  struct rtattr *addr_attr,
95530eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko				  struct rtattr *mask_attr)
95630eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko{
95730eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	SPRINT_BUF(b1);
95830eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	int bits;
95930eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
96030eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	if (!addr_attr || RTA_PAYLOAD(addr_attr) != ETH_ALEN)
96130eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		return;
96230eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	fprintf(f, "\n  %s %s", name, ll_addr_n2a(RTA_DATA(addr_attr), ETH_ALEN,
96330eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko						  0, b1, sizeof(b1)));
96430eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	if (!mask_attr || RTA_PAYLOAD(mask_attr) != ETH_ALEN)
96530eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		return;
96630eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	bits = __mask_bits(RTA_DATA(mask_attr), ETH_ALEN);
96730eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	if (bits < 0)
96830eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		fprintf(f, "/%s", ll_addr_n2a(RTA_DATA(mask_attr), ETH_ALEN,
96930eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko					      0, b1, sizeof(b1)));
97030eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	else if (bits < ETH_ALEN * 8)
97130eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		fprintf(f, "/%d", bits);
97230eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko}
97330eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
97430eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirkostatic void flower_print_eth_type(FILE *f, __be16 *p_eth_type,
97530eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko				  struct rtattr *eth_type_attr)
97630eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko{
97730eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	__be16 eth_type;
97830eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
97930eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	if (!eth_type_attr)
98030eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		return;
98130eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
98230eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	eth_type = rta_getattr_u16(eth_type_attr);
98330eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	fprintf(f, "\n  eth_type ");
98430eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	if (eth_type == htons(ETH_P_IP))
98530eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		fprintf(f, "ipv4");
98630eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	else if (eth_type == htons(ETH_P_IPV6))
98730eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		fprintf(f, "ipv6");
988f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman	else if (eth_type == htons(ETH_P_ARP))
989f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman		fprintf(f, "arp");
990f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman	else if (eth_type == htons(ETH_P_RARP))
991f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman		fprintf(f, "rarp");
99230eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	else
99330eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		fprintf(f, "%04x", ntohs(eth_type));
99430eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	*p_eth_type = eth_type;
99530eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko}
99630eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
99730eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirkostatic void flower_print_ip_proto(FILE *f, __u8 *p_ip_proto,
99830eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko				  struct rtattr *ip_proto_attr)
99930eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko{
100030eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	__u8 ip_proto;
100130eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
100230eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	if (!ip_proto_attr)
100330eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		return;
100430eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
100530eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	ip_proto = rta_getattr_u8(ip_proto_attr);
100630eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	fprintf(f, "\n  ip_proto ");
100730eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	if (ip_proto == IPPROTO_TCP)
100830eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		fprintf(f, "tcp");
100930eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	else if (ip_proto == IPPROTO_UDP)
101030eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		fprintf(f, "udp");
1011a1fb0d484237b41f92ee17634880be80a0dcf51aSimon Horman	else if (ip_proto == IPPROTO_SCTP)
1012a1fb0d484237b41f92ee17634880be80a0dcf51aSimon Horman		fprintf(f, "sctp");
1013eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman	else if (ip_proto == IPPROTO_ICMP)
1014eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman		fprintf(f, "icmp");
1015eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman	else if (ip_proto == IPPROTO_ICMPV6)
1016eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman		fprintf(f, "icmpv6");
101730eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	else
101830eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		fprintf(f, "%02x", ip_proto);
101930eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	*p_ip_proto = ip_proto;
102030eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko}
102130eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
10226ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitzstatic void flower_print_ip_attr(FILE *f, char *name,
10236ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz				 struct rtattr *key_attr,
10246ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz				 struct rtattr *mask_attr)
10256ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz{
10266ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz	if (!key_attr)
10276ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz		return;
10286ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz
10296ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz	fprintf(f, "\n  %s %x", name, rta_getattr_u8(key_attr));
10306ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz	if (!mask_attr)
10316ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz		return;
10326ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz	fprintf(f, "/%x", rta_getattr_u8(mask_attr));
10336ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz}
10346ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz
103522a8f019891ca73295298384612008ff538e48faPaul Blakeystatic void flower_print_matching_flags(FILE *f, char *name,
103608f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey					enum flower_matching_flags type,
103722a8f019891ca73295298384612008ff538e48faPaul Blakey					struct rtattr *attr,
103822a8f019891ca73295298384612008ff538e48faPaul Blakey					struct rtattr *mask_attr)
103922a8f019891ca73295298384612008ff538e48faPaul Blakey{
104008f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey	int i;
104108f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey	int count = 0;
104208f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey	__u32 mtf;
104308f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey	__u32 mtf_mask;
104408f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey
104522a8f019891ca73295298384612008ff538e48faPaul Blakey	if (!mask_attr || RTA_PAYLOAD(mask_attr) != 4)
104622a8f019891ca73295298384612008ff538e48faPaul Blakey		return;
104722a8f019891ca73295298384612008ff538e48faPaul Blakey
104808f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey	mtf = ntohl(rta_getattr_u32(attr));
104908f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey	mtf_mask = ntohl(rta_getattr_u32(mask_attr));
105008f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey
105108f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey	for (i = 0; i < ARRAY_SIZE(flags_str); i++) {
105208f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey		if (type != flags_str[i].type)
105308f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey			continue;
105408f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey		if (mtf_mask & flags_str[i].flag) {
105508f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey			if (++count == 1)
105608f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey				fprintf(f, "\n  %s ", name);
105708f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey			else
105808f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey				fprintf(f, "/");
105908f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey
106008f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey			if (mtf & flags_str[i].flag)
106108f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey				fprintf(f, "%s", flags_str[i].string);
106208f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey			else
106308f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey				fprintf(f, "no%s", flags_str[i].string);
106408f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey		}
106508f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey	}
106622a8f019891ca73295298384612008ff538e48faPaul Blakey}
106722a8f019891ca73295298384612008ff538e48faPaul Blakey
106830eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirkostatic void flower_print_ip_addr(FILE *f, char *name, __be16 eth_type,
106930eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko				 struct rtattr *addr4_attr,
107030eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko				 struct rtattr *mask4_attr,
107130eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko				 struct rtattr *addr6_attr,
107230eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko				 struct rtattr *mask6_attr)
107330eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko{
107430eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	struct rtattr *addr_attr;
107530eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	struct rtattr *mask_attr;
107630eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	int family;
107730eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	size_t len;
107830eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	int bits;
107930eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
108030eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	if (eth_type == htons(ETH_P_IP)) {
108130eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		family = AF_INET;
108230eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		addr_attr = addr4_attr;
108330eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		mask_attr = mask4_attr;
108430eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		len = 4;
108530eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	} else if (eth_type == htons(ETH_P_IPV6)) {
108630eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		family = AF_INET6;
108730eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		addr_attr = addr6_attr;
108830eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		mask_attr = mask6_attr;
108930eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		len = 16;
109030eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	} else {
109130eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		return;
109230eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	}
109330eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	if (!addr_attr || RTA_PAYLOAD(addr_attr) != len)
109430eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		return;
10957faf1588a755edb9c9cabbe1d3211265e9826d28Phil Sutter	fprintf(f, "\n  %s %s", name, rt_addr_n2a_rta(family, addr_attr));
109630eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	if (!mask_attr || RTA_PAYLOAD(mask_attr) != len)
109730eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		return;
109830eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	bits = __mask_bits(RTA_DATA(mask_attr), len);
109930eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	if (bits < 0)
11007faf1588a755edb9c9cabbe1d3211265e9826d28Phil Sutter		fprintf(f, "/%s", rt_addr_n2a_rta(family, mask_attr));
110130eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	else if (bits < len * 8)
110230eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		fprintf(f, "/%d", bits);
110330eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko}
1104f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Hormanstatic void flower_print_ip4_addr(FILE *f, char *name,
1105f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman				  struct rtattr *addr_attr,
1106f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman				  struct rtattr *mask_attr)
1107f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman{
1108f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman	return flower_print_ip_addr(f, name, htons(ETH_P_IP),
1109f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman				    addr_attr, mask_attr, 0, 0);
1110f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman}
111130eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
1112a1fb0d484237b41f92ee17634880be80a0dcf51aSimon Hormanstatic void flower_print_port(FILE *f, char *name, struct rtattr *attr)
111330eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko{
11146bd5b80cdcfbeb30b79c3ff07ce844f9e4f2c600Simon Horman	if (attr)
11156bd5b80cdcfbeb30b79c3ff07ce844f9e4f2c600Simon Horman		fprintf(f, "\n  %s %d", name, rta_getattr_be16(attr));
111630eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko}
111730eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
11180c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirkostatic void flower_print_tcp_flags(FILE *f, char *name,
11190c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko				  struct rtattr *flags_attr,
11200c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko				  struct rtattr *mask_attr)
11210c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko{
11220c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko	if (!flags_attr)
11230c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko		return;
11240c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko	fprintf(f, "\n  %s %x", name, rta_getattr_be16(flags_attr));
11250c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko	if (!mask_attr)
11260c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko		return;
11270c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko	fprintf(f, "/%x", rta_getattr_be16(mask_attr));
11280c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko}
11290c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko
11300c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko
1131bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadaistatic void flower_print_key_id(FILE *f, const char *name,
1132bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai				struct rtattr *attr)
1133bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai{
1134bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai	if (attr)
1135bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai		fprintf(f, "\n  %s %d", name, rta_getattr_be32(attr));
1136bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai}
1137bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai
11389d36e54f36b8360766519bba79028aeb9ec3a762Simon Hormanstatic void flower_print_masked_u8(FILE *f, const char *name,
11399d36e54f36b8360766519bba79028aeb9ec3a762Simon Horman				   struct rtattr *attr,
11409d36e54f36b8360766519bba79028aeb9ec3a762Simon Horman				   struct rtattr *mask_attr,
11419d36e54f36b8360766519bba79028aeb9ec3a762Simon Horman				   const char *(*value_to_str)(__u8 value))
1142f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman{
11439d36e54f36b8360766519bba79028aeb9ec3a762Simon Horman	const char *value_str = NULL;
11449d36e54f36b8360766519bba79028aeb9ec3a762Simon Horman	__u8 value, mask;
1145f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman
11469d36e54f36b8360766519bba79028aeb9ec3a762Simon Horman	if (!attr)
1147f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman		return;
1148f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman
11499d36e54f36b8360766519bba79028aeb9ec3a762Simon Horman	value = rta_getattr_u8(attr);
1150f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman	mask = mask_attr ? rta_getattr_u8(mask_attr) : UINT8_MAX;
11519d36e54f36b8360766519bba79028aeb9ec3a762Simon Horman	if (mask == UINT8_MAX && value_to_str)
11529d36e54f36b8360766519bba79028aeb9ec3a762Simon Horman		value_str = value_to_str(value);
1153f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman
1154f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman	fprintf(f, "\n  %s ", name);
1155f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman
11569d36e54f36b8360766519bba79028aeb9ec3a762Simon Horman	if (value_str)
11579d36e54f36b8360766519bba79028aeb9ec3a762Simon Horman		fputs(value_str, f);
1158f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman	else
11599d36e54f36b8360766519bba79028aeb9ec3a762Simon Horman		fprintf(f, "%d", value);
1160f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman
1161f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman	if (mask != UINT8_MAX)
1162f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman		fprintf(f, "/%d", mask);
1163f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman}
1164f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman
11659d36e54f36b8360766519bba79028aeb9ec3a762Simon Hormanstatic void flower_print_arp_op(FILE *f, const char *name,
11669d36e54f36b8360766519bba79028aeb9ec3a762Simon Horman				struct rtattr *op_attr,
11679d36e54f36b8360766519bba79028aeb9ec3a762Simon Horman				struct rtattr *mask_attr)
11689d36e54f36b8360766519bba79028aeb9ec3a762Simon Horman{
11699d36e54f36b8360766519bba79028aeb9ec3a762Simon Horman	flower_print_masked_u8(f, name, op_attr, mask_attr,
11709d36e54f36b8360766519bba79028aeb9ec3a762Simon Horman			       flower_print_arp_op_to_name);
11719d36e54f36b8360766519bba79028aeb9ec3a762Simon Horman}
11729d36e54f36b8360766519bba79028aeb9ec3a762Simon Horman
117330eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirkostatic int flower_print_opt(struct filter_util *qu, FILE *f,
117430eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			    struct rtattr *opt, __u32 handle)
117530eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko{
117630eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	struct rtattr *tb[TCA_FLOWER_MAX + 1];
11776374961a00d4b862bdf87c0f22af86d3ff7d0d67Simon Horman	int nl_type, nl_mask_type;
117830eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	__be16 eth_type = 0;
117930eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	__u8 ip_proto = 0xff;
118030eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
118130eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	if (!opt)
118230eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		return 0;
118330eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
118430eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	parse_rtattr_nested(tb, TCA_FLOWER_MAX, opt);
118530eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
118630eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	if (handle)
118730eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		fprintf(f, "handle 0x%x ", handle);
118830eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
118930eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	if (tb[TCA_FLOWER_CLASSID]) {
119030eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		SPRINT_BUF(b1);
119130eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		fprintf(f, "classid %s ",
1192488b41d020fb06428b90289f70a41210718f52b7Jamal Hadi Salim			sprint_tc_classid(rta_getattr_u32(tb[TCA_FLOWER_CLASSID]),
1193488b41d020fb06428b90289f70a41210718f52b7Jamal Hadi Salim					  b1));
119430eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	}
119530eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
119630eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	if (tb[TCA_FLOWER_INDEV]) {
119730eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		struct rtattr *attr = tb[TCA_FLOWER_INDEV];
119830eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
119930eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko		fprintf(f, "\n  indev %s", rta_getattr_str(attr));
120030eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	}
120130eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
1202745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion	if (tb[TCA_FLOWER_KEY_VLAN_ID]) {
1203745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion		struct rtattr *attr = tb[TCA_FLOWER_KEY_VLAN_ID];
1204745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion
1205745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion		fprintf(f, "\n  vlan_id %d", rta_getattr_u16(attr));
1206745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion	}
1207745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion
1208745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion	if (tb[TCA_FLOWER_KEY_VLAN_PRIO]) {
1209745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion		struct rtattr *attr = tb[TCA_FLOWER_KEY_VLAN_PRIO];
1210745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion
1211745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion		fprintf(f, "\n  vlan_prio %d", rta_getattr_u8(attr));
1212745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion	}
1213745d91726006fcaa9006f491f9a596c4025cecf7Hadar Hen Zion
121430eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	flower_print_eth_addr(f, "dst_mac", tb[TCA_FLOWER_KEY_ETH_DST],
121530eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			      tb[TCA_FLOWER_KEY_ETH_DST_MASK]);
121630eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	flower_print_eth_addr(f, "src_mac", tb[TCA_FLOWER_KEY_ETH_SRC],
121730eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			      tb[TCA_FLOWER_KEY_ETH_SRC_MASK]);
121830eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
121930eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	flower_print_eth_type(f, &eth_type, tb[TCA_FLOWER_KEY_ETH_TYPE]);
122030eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	flower_print_ip_proto(f, &ip_proto, tb[TCA_FLOWER_KEY_IP_PROTO]);
122130eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
12226ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz	flower_print_ip_attr(f, "ip_tos", tb[TCA_FLOWER_KEY_IP_TOS],
12236ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz			    tb[TCA_FLOWER_KEY_IP_TOS_MASK]);
12246ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz	flower_print_ip_attr(f, "ip_ttl", tb[TCA_FLOWER_KEY_IP_TTL],
12256ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz			    tb[TCA_FLOWER_KEY_IP_TTL_MASK]);
12266ea2c2b1cff676be2d01029a01cbd84d0675213cOr Gerlitz
122730eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	flower_print_ip_addr(f, "dst_ip", eth_type,
122830eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			     tb[TCA_FLOWER_KEY_IPV4_DST],
122930eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			     tb[TCA_FLOWER_KEY_IPV4_DST_MASK],
123030eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			     tb[TCA_FLOWER_KEY_IPV6_DST],
123130eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			     tb[TCA_FLOWER_KEY_IPV6_DST_MASK]);
123230eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
123330eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	flower_print_ip_addr(f, "src_ip", eth_type,
123430eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			     tb[TCA_FLOWER_KEY_IPV4_SRC],
123530eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			     tb[TCA_FLOWER_KEY_IPV4_SRC_MASK],
123630eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			     tb[TCA_FLOWER_KEY_IPV6_SRC],
123730eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko			     tb[TCA_FLOWER_KEY_IPV6_SRC_MASK]);
123830eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
1239b2141de1ad98517ffecc1feb99800cd36a26fd22Roi Dayan	nl_type = flower_port_attr_type(ip_proto, FLOWER_ENDPOINT_DST);
12406bd5b80cdcfbeb30b79c3ff07ce844f9e4f2c600Simon Horman	if (nl_type >= 0)
12416bd5b80cdcfbeb30b79c3ff07ce844f9e4f2c600Simon Horman		flower_print_port(f, "dst_port", tb[nl_type]);
1242b2141de1ad98517ffecc1feb99800cd36a26fd22Roi Dayan	nl_type = flower_port_attr_type(ip_proto, FLOWER_ENDPOINT_SRC);
12436bd5b80cdcfbeb30b79c3ff07ce844f9e4f2c600Simon Horman	if (nl_type >= 0)
12446bd5b80cdcfbeb30b79c3ff07ce844f9e4f2c600Simon Horman		flower_print_port(f, "src_port", tb[nl_type]);
124530eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
12460c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko	flower_print_tcp_flags(f, "tcp_flags", tb[TCA_FLOWER_KEY_TCP_FLAGS],
12470c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko			       tb[TCA_FLOWER_KEY_TCP_FLAGS_MASK]);
12480c30d14d0a2fc2fb6b7fef62bea05f2e5c3eb26aJiri Pirko
124981f6e5a7279eaab826ba8b291b98fb2e89df0572Simon Horman	nl_type = flower_icmp_attr_type(eth_type, ip_proto,
125081f6e5a7279eaab826ba8b291b98fb2e89df0572Simon Horman					FLOWER_ICMP_FIELD_TYPE);
12516374961a00d4b862bdf87c0f22af86d3ff7d0d67Simon Horman	nl_mask_type = flower_icmp_attr_mask_type(eth_type, ip_proto,
12526374961a00d4b862bdf87c0f22af86d3ff7d0d67Simon Horman						  FLOWER_ICMP_FIELD_TYPE);
12536374961a00d4b862bdf87c0f22af86d3ff7d0d67Simon Horman	if (nl_type >= 0 && nl_mask_type >= 0)
12546374961a00d4b862bdf87c0f22af86d3ff7d0d67Simon Horman		flower_print_masked_u8(f, "icmp_type", tb[nl_type],
12556374961a00d4b862bdf87c0f22af86d3ff7d0d67Simon Horman				       tb[nl_mask_type], NULL);
12566374961a00d4b862bdf87c0f22af86d3ff7d0d67Simon Horman
125781f6e5a7279eaab826ba8b291b98fb2e89df0572Simon Horman	nl_type = flower_icmp_attr_type(eth_type, ip_proto,
125881f6e5a7279eaab826ba8b291b98fb2e89df0572Simon Horman					FLOWER_ICMP_FIELD_CODE);
12596374961a00d4b862bdf87c0f22af86d3ff7d0d67Simon Horman	nl_mask_type = flower_icmp_attr_mask_type(eth_type, ip_proto,
12606374961a00d4b862bdf87c0f22af86d3ff7d0d67Simon Horman						  FLOWER_ICMP_FIELD_CODE);
12616374961a00d4b862bdf87c0f22af86d3ff7d0d67Simon Horman	if (nl_type >= 0 && nl_mask_type >= 0)
12626374961a00d4b862bdf87c0f22af86d3ff7d0d67Simon Horman		flower_print_masked_u8(f, "icmp_code", tb[nl_type],
12636374961a00d4b862bdf87c0f22af86d3ff7d0d67Simon Horman				       tb[nl_mask_type], NULL);
1264eb3b5696f16334b4513ad42882ca6bc35b78144dSimon Horman
1265f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman	flower_print_ip4_addr(f, "arp_sip", tb[TCA_FLOWER_KEY_ARP_SIP],
1266f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman			     tb[TCA_FLOWER_KEY_ARP_SIP_MASK]);
1267f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman	flower_print_ip4_addr(f, "arp_tip", tb[TCA_FLOWER_KEY_ARP_TIP],
1268f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman			     tb[TCA_FLOWER_KEY_ARP_TIP_MASK]);
1269f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman	flower_print_arp_op(f, "arp_op", tb[TCA_FLOWER_KEY_ARP_OP],
1270f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman			    tb[TCA_FLOWER_KEY_ARP_OP_MASK]);
1271f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman	flower_print_eth_addr(f, "arp_sha", tb[TCA_FLOWER_KEY_ARP_SHA],
1272f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman			      tb[TCA_FLOWER_KEY_ARP_SHA_MASK]);
1273f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman	flower_print_eth_addr(f, "arp_tha", tb[TCA_FLOWER_KEY_ARP_THA],
1274f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman			      tb[TCA_FLOWER_KEY_ARP_THA_MASK]);
1275f888f4e20534ae44ec4c5a2cfc5209b105645a04Simon Horman
1276bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai	flower_print_ip_addr(f, "enc_dst_ip",
1277bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai			     tb[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK] ?
1278bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai			     htons(ETH_P_IP) : htons(ETH_P_IPV6),
1279bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai			     tb[TCA_FLOWER_KEY_ENC_IPV4_DST],
1280bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai			     tb[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK],
1281bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai			     tb[TCA_FLOWER_KEY_ENC_IPV6_DST],
1282bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai			     tb[TCA_FLOWER_KEY_ENC_IPV6_DST_MASK]);
1283bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai
1284bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai	flower_print_ip_addr(f, "enc_src_ip",
1285bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai			     tb[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK] ?
1286bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai			     htons(ETH_P_IP) : htons(ETH_P_IPV6),
1287bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai			     tb[TCA_FLOWER_KEY_ENC_IPV4_SRC],
1288bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai			     tb[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK],
1289bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai			     tb[TCA_FLOWER_KEY_ENC_IPV6_SRC],
1290bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai			     tb[TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK]);
1291bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai
1292bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai	flower_print_key_id(f, "enc_key_id",
1293bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai			    tb[TCA_FLOWER_KEY_ENC_KEY_ID]);
1294bb9b63b18e85f17e618469ecb139e78ca5a4a4fcAmir Vadai
129541aa17ff4668ce97ec27e5f4cdc20db7169b549bHadar Hen Zion	flower_print_port(f, "enc_dst_port",
129641aa17ff4668ce97ec27e5f4cdc20db7169b549bHadar Hen Zion			  tb[TCA_FLOWER_KEY_ENC_UDP_DST_PORT]);
129741aa17ff4668ce97ec27e5f4cdc20db7169b549bHadar Hen Zion
129808f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey	flower_print_matching_flags(f, "ip_flags",
129908f66c80c094eaa5d71abc0395fd114ff919af7aPaul Blakey				    FLOWER_IP_FLAGS,
130022a8f019891ca73295298384612008ff538e48faPaul Blakey				    tb[TCA_FLOWER_KEY_FLAGS],
130122a8f019891ca73295298384612008ff538e48faPaul Blakey				    tb[TCA_FLOWER_KEY_FLAGS_MASK]);
130222a8f019891ca73295298384612008ff538e48faPaul Blakey
1303512caeb2737f1657d941945cc770a95882e1c1bbStephen Hemminger	if (tb[TCA_FLOWER_FLAGS]) {
1304cfcabf18d84a2f4908cb5b4489f67c2cd3f70426Amir Vadai		__u32 flags = rta_getattr_u32(tb[TCA_FLOWER_FLAGS]);
1305cfcabf18d84a2f4908cb5b4489f67c2cd3f70426Amir Vadai
1306cfcabf18d84a2f4908cb5b4489f67c2cd3f70426Amir Vadai		if (flags & TCA_CLS_FLAGS_SKIP_HW)
1307cfcabf18d84a2f4908cb5b4489f67c2cd3f70426Amir Vadai			fprintf(f, "\n  skip_hw");
1308cfcabf18d84a2f4908cb5b4489f67c2cd3f70426Amir Vadai		if (flags & TCA_CLS_FLAGS_SKIP_SW)
1309cfcabf18d84a2f4908cb5b4489f67c2cd3f70426Amir Vadai			fprintf(f, "\n  skip_sw");
1310e57285b81a098ed705d683ce94f9abd1cc53438aOr Gerlitz
1311e57285b81a098ed705d683ce94f9abd1cc53438aOr Gerlitz		if (flags & TCA_CLS_FLAGS_IN_HW)
1312e57285b81a098ed705d683ce94f9abd1cc53438aOr Gerlitz			fprintf(f, "\n  in_hw");
1313e57285b81a098ed705d683ce94f9abd1cc53438aOr Gerlitz		else if (flags & TCA_CLS_FLAGS_NOT_IN_HW)
1314e57285b81a098ed705d683ce94f9abd1cc53438aOr Gerlitz			fprintf(f, "\n  not_in_hw");
1315cfcabf18d84a2f4908cb5b4489f67c2cd3f70426Amir Vadai	}
1316cfcabf18d84a2f4908cb5b4489f67c2cd3f70426Amir Vadai
1317512caeb2737f1657d941945cc770a95882e1c1bbStephen Hemminger	if (tb[TCA_FLOWER_ACT])
13189e71352581954065ea4a6c0766f55fcb04ca0499Jamal Hadi Salim		tc_print_action(f, tb[TCA_FLOWER_ACT], 0);
131930eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
132030eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	return 0;
132130eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko}
132230eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko
132330eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirkostruct filter_util flower_filter_util = {
132430eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	.id = "flower",
132530eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	.parse_fopt = flower_parse_opt,
132630eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko	.print_fopt = flower_print_opt,
132730eb304ecd1dd7e452847fabea779de0dbe3f1a5Jiri Pirko};
1328