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