]> git.proxmox.com Git - mirror_iproute2.git/blob - tc/em_u32.c
tc: Add support for ETS Qdisc
[mirror_iproute2.git] / tc / em_u32.c
1 /*
2 * em_u32.c U32 Ematch
3 *
4 * This program is free software; you can distribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * Authors: Thomas Graf <tgraf@suug.ch>
10 */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <unistd.h>
15 #include <fcntl.h>
16 #include <sys/socket.h>
17 #include <netinet/in.h>
18 #include <arpa/inet.h>
19 #include <string.h>
20 #include <errno.h>
21
22 #include "m_ematch.h"
23
24 extern struct ematch_util u32_ematch_util;
25
26 static void u32_print_usage(FILE *fd)
27 {
28 fprintf(fd,
29 "Usage: u32(ALIGN VALUE MASK at [ nexthdr+ ] OFFSET)\n" \
30 "where: ALIGN := { u8 | u16 | u32 }\n" \
31 "\n" \
32 "Example: u32(u16 0x1122 0xffff at nexthdr+4)\n");
33 }
34
35 static int u32_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr,
36 struct bstr *args)
37 {
38 struct bstr *a;
39 int align, nh_len;
40 unsigned long key, mask, offmask = 0, offset;
41 struct tc_u32_key u_key = {};
42
43 #define PARSE_ERR(CARG, FMT, ARGS...) \
44 em_parse_error(EINVAL, args, CARG, &u32_ematch_util, FMT, ##ARGS)
45
46 if (args == NULL)
47 return PARSE_ERR(args, "u32: missing arguments");
48
49 if (!bstrcmp(args, "u8"))
50 align = 1;
51 else if (!bstrcmp(args, "u16"))
52 align = 2;
53 else if (!bstrcmp(args, "u32"))
54 align = 4;
55 else
56 return PARSE_ERR(args, "u32: invalid alignment");
57
58 a = bstr_next(args);
59 if (a == NULL)
60 return PARSE_ERR(a, "u32: missing key");
61
62 key = bstrtoul(a);
63 if (key == ULONG_MAX)
64 return PARSE_ERR(a, "u32: invalid key, must be numeric");
65
66 a = bstr_next(a);
67 if (a == NULL)
68 return PARSE_ERR(a, "u32: missing mask");
69
70 mask = bstrtoul(a);
71 if (mask == ULONG_MAX)
72 return PARSE_ERR(a, "u32: invalid mask, must be numeric");
73
74 a = bstr_next(a);
75 if (a == NULL || bstrcmp(a, "at") != 0)
76 return PARSE_ERR(a, "u32: missing \"at\"");
77
78 a = bstr_next(a);
79 if (a == NULL)
80 return PARSE_ERR(a, "u32: missing offset");
81
82 nh_len = strlen("nexthdr+");
83 if (a->len > nh_len && !memcmp(a->data, "nexthdr+", nh_len)) {
84 char buf[a->len - nh_len + 1];
85
86 offmask = -1;
87 memcpy(buf, a->data + nh_len, a->len - nh_len);
88 offset = strtoul(buf, NULL, 0);
89 } else if (!bstrcmp(a, "nexthdr+")) {
90 a = bstr_next(a);
91 if (a == NULL)
92 return PARSE_ERR(a, "u32: missing offset");
93 offset = bstrtoul(a);
94 } else
95 offset = bstrtoul(a);
96
97 if (offset == ULONG_MAX)
98 return PARSE_ERR(a, "u32: invalid offset");
99
100 if (a->next)
101 return PARSE_ERR(a->next, "u32: unexpected trailer");
102
103 switch (align) {
104 case 1:
105 if (key > 0xFF)
106 return PARSE_ERR(a, "Illegal key (>0xFF)");
107 if (mask > 0xFF)
108 return PARSE_ERR(a, "Illegal mask (>0xFF)");
109
110 key <<= 24 - ((offset & 3) * 8);
111 mask <<= 24 - ((offset & 3) * 8);
112 offset &= ~3;
113 break;
114
115 case 2:
116 if (key > 0xFFFF)
117 return PARSE_ERR(a, "Illegal key (>0xFFFF)");
118 if (mask > 0xFFFF)
119 return PARSE_ERR(a, "Illegal mask (>0xFFFF)");
120
121 if ((offset & 3) == 0) {
122 key <<= 16;
123 mask <<= 16;
124 }
125 offset &= ~3;
126 break;
127 }
128
129 key = htonl(key);
130 mask = htonl(mask);
131
132 if (offset % 4)
133 return PARSE_ERR(a, "u32: invalid offset alignment, " \
134 "must be aligned to 4.");
135
136 key &= mask;
137
138 u_key.mask = mask;
139 u_key.val = key;
140 u_key.off = offset;
141 u_key.offmask = offmask;
142
143 addraw_l(n, MAX_MSG, hdr, sizeof(*hdr));
144 addraw_l(n, MAX_MSG, &u_key, sizeof(u_key));
145
146 #undef PARSE_ERR
147 return 0;
148 }
149
150 static int u32_print_eopt(FILE *fd, struct tcf_ematch_hdr *hdr, void *data,
151 int data_len)
152 {
153 struct tc_u32_key *u_key = data;
154
155 if (data_len < sizeof(*u_key)) {
156 fprintf(stderr, "U32 header size mismatch\n");
157 return -1;
158 }
159
160 fprintf(fd, "%08x/%08x at %s%d",
161 (unsigned int) ntohl(u_key->val),
162 (unsigned int) ntohl(u_key->mask),
163 u_key->offmask ? "nexthdr+" : "",
164 u_key->off);
165
166 return 0;
167 }
168
169 struct ematch_util u32_ematch_util = {
170 .kind = "u32",
171 .kind_num = TCF_EM_U32,
172 .parse_eopt = u32_parse_eopt,
173 .print_eopt = u32_print_eopt,
174 .print_usage = u32_print_usage
175 };