1 |
|
|
/* $OpenBSD: ofp_common.c,v 1.10 2016/12/22 15:31:43 rzalamena Exp $ */ |
2 |
|
|
|
3 |
|
|
/* |
4 |
|
|
* Copyright (c) 2013-2016 Reyk Floeter <reyk@openbsd.org> |
5 |
|
|
* Copyright (c) 2016 Rafael Zalamena <rzalamena@openbsd.org> |
6 |
|
|
* |
7 |
|
|
* Permission to use, copy, modify, and distribute this software for any |
8 |
|
|
* purpose with or without fee is hereby granted, provided that the above |
9 |
|
|
* copyright notice and this permission notice appear in all copies. |
10 |
|
|
* |
11 |
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
12 |
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
13 |
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
14 |
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
15 |
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
16 |
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
17 |
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
18 |
|
|
*/ |
19 |
|
|
|
20 |
|
|
#include <sys/types.h> |
21 |
|
|
#include <sys/queue.h> |
22 |
|
|
#include <sys/socket.h> |
23 |
|
|
|
24 |
|
|
#include <net/if.h> |
25 |
|
|
#include <net/if_arp.h> |
26 |
|
|
#include <net/ofp.h> |
27 |
|
|
|
28 |
|
|
#include <netinet/in.h> |
29 |
|
|
#include <netinet/if_ether.h> |
30 |
|
|
#include <netinet/tcp.h> |
31 |
|
|
#include <netmpls/mpls.h> |
32 |
|
|
|
33 |
|
|
#include <endian.h> |
34 |
|
|
#include <stdio.h> |
35 |
|
|
#include <stdlib.h> |
36 |
|
|
#include <stddef.h> |
37 |
|
|
#include <unistd.h> |
38 |
|
|
#include <string.h> |
39 |
|
|
#include <fcntl.h> |
40 |
|
|
#include <imsg.h> |
41 |
|
|
#include <event.h> |
42 |
|
|
|
43 |
|
|
#include "switchd.h" |
44 |
|
|
#include "ofp_map.h" |
45 |
|
|
|
46 |
|
|
int ofp_setversion(struct switch_connection *, int); |
47 |
|
|
|
48 |
|
|
int |
49 |
|
|
ofp_validate_header(struct switchd *sc, |
50 |
|
|
struct sockaddr_storage *src, struct sockaddr_storage *dst, |
51 |
|
|
struct ofp_header *oh, uint8_t version) |
52 |
|
|
{ |
53 |
|
|
struct constmap *tmap; |
54 |
|
|
|
55 |
|
|
/* For debug, don't verify the header if the version is unset */ |
56 |
|
|
if (version != OFP_V_0 && |
57 |
|
|
(oh->oh_version != version || |
58 |
|
|
oh->oh_type >= OFP_T_TYPE_MAX)) |
59 |
|
|
return (-1); |
60 |
|
|
|
61 |
|
|
switch (version) { |
62 |
|
|
case OFP_V_1_0: |
63 |
|
|
case OFP_V_1_1: |
64 |
|
|
tmap = ofp10_t_map; |
65 |
|
|
break; |
66 |
|
|
case OFP_V_1_3: |
67 |
|
|
default: |
68 |
|
|
tmap = ofp_t_map; |
69 |
|
|
break; |
70 |
|
|
} |
71 |
|
|
|
72 |
|
|
log_debug("%s > %s: version %s type %s length %u xid %u", |
73 |
|
|
print_host(src, NULL, 0), |
74 |
|
|
print_host(dst, NULL, 0), |
75 |
|
|
print_map(oh->oh_version, ofp_v_map), |
76 |
|
|
print_map(oh->oh_type, tmap), |
77 |
|
|
ntohs(oh->oh_length), ntohl(oh->oh_xid)); |
78 |
|
|
|
79 |
|
|
return (0); |
80 |
|
|
} |
81 |
|
|
|
82 |
|
|
int |
83 |
|
|
ofp_validate(struct switchd *sc, |
84 |
|
|
struct sockaddr_storage *src, struct sockaddr_storage *dst, |
85 |
|
|
struct ofp_header *oh, struct ibuf *ibuf, uint8_t version) |
86 |
|
|
{ |
87 |
|
|
switch (version) { |
88 |
|
|
case OFP_V_1_0: |
89 |
|
|
return (ofp10_validate(sc, src, dst, oh, ibuf)); |
90 |
|
|
case OFP_V_1_3: |
91 |
|
|
return (ofp13_validate(sc, src, dst, oh, ibuf)); |
92 |
|
|
default: |
93 |
|
|
return (-1); |
94 |
|
|
} |
95 |
|
|
|
96 |
|
|
/* NOTREACHED */ |
97 |
|
|
} |
98 |
|
|
|
99 |
|
|
int |
100 |
|
|
ofp_output(struct switch_connection *con, struct ofp_header *oh, |
101 |
|
|
struct ibuf *obuf) |
102 |
|
|
{ |
103 |
|
|
struct ibuf *buf; |
104 |
|
|
|
105 |
|
|
if ((buf = ibuf_static()) == NULL) |
106 |
|
|
return (-1); |
107 |
|
|
if ((oh != NULL) && |
108 |
|
|
(ibuf_add(buf, oh, sizeof(*oh)) == -1)) { |
109 |
|
|
ibuf_release(buf); |
110 |
|
|
return (-1); |
111 |
|
|
} |
112 |
|
|
if ((obuf != NULL) && |
113 |
|
|
(ibuf_cat(buf, obuf) == -1)) { |
114 |
|
|
ibuf_release(buf); |
115 |
|
|
return (-1); |
116 |
|
|
} |
117 |
|
|
|
118 |
|
|
ofrelay_write(con, buf); |
119 |
|
|
|
120 |
|
|
return (0); |
121 |
|
|
} |
122 |
|
|
|
123 |
|
|
int |
124 |
|
|
ofp_send_hello(struct switchd *sc, struct switch_connection *con, int version) |
125 |
|
|
{ |
126 |
|
|
struct ofp_hello_element_header *he; |
127 |
|
|
struct ofp_header *oh; |
128 |
|
|
struct ibuf *ibuf; |
129 |
|
|
size_t hstart, hend; |
130 |
|
|
uint32_t *bmp; |
131 |
|
|
int rv = -1; |
132 |
|
|
|
133 |
|
|
if ((ibuf = ibuf_static()) == NULL || |
134 |
|
|
(oh = ibuf_advance(ibuf, sizeof(*oh))) == NULL || |
135 |
|
|
(he = ibuf_advance(ibuf, sizeof(*he))) == NULL) |
136 |
|
|
goto done; |
137 |
|
|
|
138 |
|
|
/* Write down all versions we support. */ |
139 |
|
|
hstart = ibuf->wpos; |
140 |
|
|
if ((bmp = ibuf_advance(ibuf, sizeof(*bmp))) == NULL) |
141 |
|
|
goto done; |
142 |
|
|
|
143 |
|
|
*bmp = htonl((1 << OFP_V_1_0) | (1 << OFP_V_1_3)); |
144 |
|
|
hend = ibuf->wpos; |
145 |
|
|
|
146 |
|
|
/* Fill the headers. */ |
147 |
|
|
oh->oh_version = version; |
148 |
|
|
oh->oh_type = OFP_T_HELLO; |
149 |
|
|
oh->oh_length = htons(ibuf_length(ibuf)); |
150 |
|
|
oh->oh_xid = htonl(con->con_xidnxt++); |
151 |
|
|
he->he_type = htons(OFP_HELLO_T_VERSION_BITMAP); |
152 |
|
|
he->he_length = htons(sizeof(*he) + (hend - hstart)); |
153 |
|
|
|
154 |
|
|
if (ofp_validate(sc, &con->con_local, &con->con_peer, oh, ibuf, |
155 |
|
|
version) != 0) |
156 |
|
|
goto done; |
157 |
|
|
|
158 |
|
|
rv = ofp_output(con, NULL, ibuf); |
159 |
|
|
|
160 |
|
|
done: |
161 |
|
|
ibuf_free(ibuf); |
162 |
|
|
return (rv); |
163 |
|
|
} |
164 |
|
|
|
165 |
|
|
int |
166 |
|
|
ofp_validate_hello(struct switchd *sc, |
167 |
|
|
struct sockaddr_storage *src, struct sockaddr_storage *dst, |
168 |
|
|
struct ofp_header *oh, struct ibuf *ibuf) |
169 |
|
|
{ |
170 |
|
|
struct ofp_hello_element_header *he; |
171 |
|
|
uint32_t *bmp; |
172 |
|
|
off_t poff; |
173 |
|
|
int helen, i, ver; |
174 |
|
|
|
175 |
|
|
/* No extra element headers. */ |
176 |
|
|
if (ntohs(oh->oh_length) == sizeof(*oh)) |
177 |
|
|
return (0); |
178 |
|
|
|
179 |
|
|
/* Test for supported element headers. */ |
180 |
|
|
if ((he = ibuf_seek(ibuf, sizeof(*oh), sizeof(*he))) == NULL) |
181 |
|
|
return (-1); |
182 |
|
|
if (he->he_type != htons(OFP_HELLO_T_VERSION_BITMAP)) |
183 |
|
|
return (-1); |
184 |
|
|
|
185 |
|
|
log_debug("\tversion bitmap:"); |
186 |
|
|
|
187 |
|
|
/* Validate header sizes. */ |
188 |
|
|
helen = ntohs(he->he_length); |
189 |
|
|
if (helen < (int)sizeof(*he)) |
190 |
|
|
return (-1); |
191 |
|
|
else if (helen == sizeof(*he)) |
192 |
|
|
return (0); |
193 |
|
|
|
194 |
|
|
helen -= sizeof(*he); |
195 |
|
|
/* Invalid bitmap size. */ |
196 |
|
|
if ((helen % sizeof(*bmp)) != 0) |
197 |
|
|
return (-1); |
198 |
|
|
|
199 |
|
|
ver = 0; |
200 |
|
|
poff = sizeof(*oh) + sizeof(*he); |
201 |
|
|
while (helen > 0) { |
202 |
|
|
if ((bmp = ibuf_seek(ibuf, poff, sizeof(*bmp))) == NULL) |
203 |
|
|
return (-1); |
204 |
|
|
|
205 |
|
|
for (i = 0; i < 32; i++, ver++) { |
206 |
|
|
if ((ntohl(*bmp) & (1 << i)) == 0) |
207 |
|
|
continue; |
208 |
|
|
|
209 |
|
|
log_debug("\t\tversion %s", |
210 |
|
|
print_map(ver, ofp_v_map)); |
211 |
|
|
} |
212 |
|
|
|
213 |
|
|
helen -= sizeof(*bmp); |
214 |
|
|
poff += sizeof(*bmp); |
215 |
|
|
} |
216 |
|
|
|
217 |
|
|
return (0); |
218 |
|
|
} |
219 |
|
|
|
220 |
|
|
int |
221 |
|
|
ofp_setversion(struct switch_connection *con, int version) |
222 |
|
|
{ |
223 |
|
|
switch (version) { |
224 |
|
|
case OFP_V_1_0: |
225 |
|
|
case OFP_V_1_3: |
226 |
|
|
con->con_version = version; |
227 |
|
|
return (0); |
228 |
|
|
|
229 |
|
|
default: |
230 |
|
|
return (-1); |
231 |
|
|
} |
232 |
|
|
} |
233 |
|
|
|
234 |
|
|
int |
235 |
|
|
ofp_recv_hello(struct switchd *sc, struct switch_connection *con, |
236 |
|
|
struct ofp_header *oh, struct ibuf *ibuf) |
237 |
|
|
{ |
238 |
|
|
struct ofp_hello_element_header *he; |
239 |
|
|
uint32_t *bmp; |
240 |
|
|
off_t poff; |
241 |
|
|
int helen, i, ver; |
242 |
|
|
|
243 |
|
|
/* No extra element headers, just use the header version. */ |
244 |
|
|
if (ntohs(oh->oh_length) == sizeof(*oh)) |
245 |
|
|
return (ofp_setversion(con, oh->oh_version)); |
246 |
|
|
|
247 |
|
|
/* Read the element header. */ |
248 |
|
|
if ((he = ibuf_seek(ibuf, sizeof(*oh), sizeof(*he))) == NULL) |
249 |
|
|
return (-1); |
250 |
|
|
|
251 |
|
|
/* We don't support anything else than the version bitmap. */ |
252 |
|
|
if (he->he_type != htons(OFP_HELLO_T_VERSION_BITMAP)) |
253 |
|
|
return (-1); |
254 |
|
|
|
255 |
|
|
/* Validate header sizes. */ |
256 |
|
|
helen = ntohs(he->he_length); |
257 |
|
|
if (helen < (int)sizeof(*he)) |
258 |
|
|
return (-1); |
259 |
|
|
else if (helen == sizeof(*he)) |
260 |
|
|
return (ofp_setversion(con, oh->oh_version)); |
261 |
|
|
|
262 |
|
|
helen -= sizeof(*he); |
263 |
|
|
/* Invalid bitmap size. */ |
264 |
|
|
if ((helen % sizeof(*bmp)) != 0) |
265 |
|
|
return (-1); |
266 |
|
|
|
267 |
|
|
ver = 0; |
268 |
|
|
poff = sizeof(*oh) + sizeof(*he); |
269 |
|
|
|
270 |
|
|
/* Loop through the bitmaps and choose the higher version. */ |
271 |
|
|
while (helen > 0) { |
272 |
|
|
if ((bmp = ibuf_seek(ibuf, poff, sizeof(*bmp))) == NULL) |
273 |
|
|
return (-1); |
274 |
|
|
|
275 |
|
|
for (i = 0; i < 32; i++, ver++) { |
276 |
|
|
if ((ntohl(*bmp) & (1 << i)) == 0) |
277 |
|
|
continue; |
278 |
|
|
|
279 |
|
|
ofp_setversion(con, ver); |
280 |
|
|
} |
281 |
|
|
|
282 |
|
|
helen -= sizeof(*bmp); |
283 |
|
|
poff += sizeof(*bmp); |
284 |
|
|
} |
285 |
|
|
|
286 |
|
|
/* Check if we have set any version, otherwise fallback. */ |
287 |
|
|
if (con->con_version == OFP_V_0) |
288 |
|
|
return (ofp_setversion(con, oh->oh_version)); |
289 |
|
|
|
290 |
|
|
return (0); |
291 |
|
|
} |
292 |
|
|
|
293 |
|
|
int |
294 |
|
|
ofp_send_featuresrequest(struct switchd *sc, struct switch_connection *con) |
295 |
|
|
{ |
296 |
|
|
struct ofp_header *oh; |
297 |
|
|
struct ibuf *ibuf; |
298 |
|
|
int rv = -1; |
299 |
|
|
|
300 |
|
|
if ((ibuf = ibuf_static()) == NULL || |
301 |
|
|
(oh = ibuf_advance(ibuf, sizeof(*oh))) == NULL) |
302 |
|
|
return (-1); |
303 |
|
|
|
304 |
|
|
oh->oh_version = con->con_version; |
305 |
|
|
oh->oh_type = OFP_T_FEATURES_REQUEST; |
306 |
|
|
oh->oh_length = htons(ibuf_length(ibuf)); |
307 |
|
|
oh->oh_xid = htonl(con->con_xidnxt++); |
308 |
|
|
if (ofp_validate(sc, &con->con_local, &con->con_peer, oh, ibuf, |
309 |
|
|
con->con_version) != 0) |
310 |
|
|
goto done; |
311 |
|
|
|
312 |
|
|
rv = ofp_output(con, NULL, ibuf); |
313 |
|
|
|
314 |
|
|
done: |
315 |
|
|
ibuf_free(ibuf); |
316 |
|
|
return (rv); |
317 |
|
|
} |
318 |
|
|
|
319 |
|
|
/* Appends an action with just the generic header. */ |
320 |
|
|
int |
321 |
|
|
action_new(struct ibuf *ibuf, uint16_t type) |
322 |
|
|
{ |
323 |
|
|
struct ofp_action_header *ah; |
324 |
|
|
|
325 |
|
|
if ((ah = ibuf_advance(ibuf, sizeof(*ah))) == NULL) |
326 |
|
|
return (-1); |
327 |
|
|
|
328 |
|
|
ah->ah_type = htons(type); |
329 |
|
|
ah->ah_len = htons(sizeof(*ah)); |
330 |
|
|
return (0); |
331 |
|
|
} |
332 |
|
|
|
333 |
|
|
int |
334 |
|
|
action_group(struct ibuf *ibuf, uint32_t group) |
335 |
|
|
{ |
336 |
|
|
struct ofp_action_group *ag; |
337 |
|
|
|
338 |
|
|
if ((ag = ibuf_advance(ibuf, sizeof(*ag))) == NULL) |
339 |
|
|
return (-1); |
340 |
|
|
|
341 |
|
|
ag->ag_type = htons(OFP_ACTION_GROUP); |
342 |
|
|
ag->ag_len = sizeof(*ag); |
343 |
|
|
ag->ag_group_id = htonl(group); |
344 |
|
|
return (0); |
345 |
|
|
} |
346 |
|
|
|
347 |
|
|
int |
348 |
|
|
action_output(struct ibuf *ibuf, uint32_t port, uint16_t maxlen) |
349 |
|
|
{ |
350 |
|
|
struct ofp_action_output *ao; |
351 |
|
|
|
352 |
|
|
if ((ao = ibuf_advance(ibuf, sizeof(*ao))) == NULL) |
353 |
|
|
return (-1); |
354 |
|
|
|
355 |
|
|
ao->ao_type = htons(OFP_ACTION_OUTPUT); |
356 |
|
|
ao->ao_len = htons(sizeof(*ao)); |
357 |
|
|
ao->ao_port = htonl(port); |
358 |
|
|
ao->ao_max_len = htons(maxlen); |
359 |
|
|
return (0); |
360 |
|
|
} |
361 |
|
|
|
362 |
|
|
/* |
363 |
|
|
* This action pushes VLAN/MPLS/PBB tags into the outermost part of the |
364 |
|
|
* packet. When the type is X ethertype must be Y: |
365 |
|
|
* - OFP_ACTION_PUSH_VLAN: ETHERTYPE_VLAN or ETHERTYPE_QINQ. |
366 |
|
|
* - OFP_ACTION_PUSH_MPLS: ETHERTYPE_MPLS or ETHERTYPE_MPLSCAST. |
367 |
|
|
* - OFP_ACTION_PUSH_PBB: ETHERTYPE_??? (0x88E7). |
368 |
|
|
*/ |
369 |
|
|
int |
370 |
|
|
action_push(struct ibuf *ibuf, uint16_t type, uint16_t ethertype) |
371 |
|
|
{ |
372 |
|
|
struct ofp_action_push *ap; |
373 |
|
|
|
374 |
|
|
if ((ap = ibuf_advance(ibuf, sizeof(*ap))) == NULL) |
375 |
|
|
return (-1); |
376 |
|
|
|
377 |
|
|
ap->ap_type = htons(type); |
378 |
|
|
ap->ap_len = htons(sizeof(*ap)); |
379 |
|
|
ap->ap_ethertype = htons(ethertype); |
380 |
|
|
return (0); |
381 |
|
|
} |
382 |
|
|
|
383 |
|
|
/* |
384 |
|
|
* This action only pops the outermost VLAN tag and only one at a time, |
385 |
|
|
* you can only pop multiple VLANs with an action list that is only |
386 |
|
|
* availiable for OFP_INSTRUCTION_T_APPLY_ACTIONS. |
387 |
|
|
*/ |
388 |
|
|
int |
389 |
|
|
action_pop_vlan(struct ibuf *ibuf) |
390 |
|
|
{ |
391 |
|
|
return (action_new(ibuf, OFP_ACTION_POP_VLAN)); |
392 |
|
|
} |
393 |
|
|
|
394 |
|
|
/* |
395 |
|
|
* Use this with caution since this will pop MPLS shim regardless of the |
396 |
|
|
* BoS bit state. |
397 |
|
|
*/ |
398 |
|
|
int |
399 |
|
|
action_pop_mpls(struct ibuf *ibuf, uint16_t ethertype) |
400 |
|
|
{ |
401 |
|
|
struct ofp_action_pop_mpls *apm; |
402 |
|
|
|
403 |
|
|
if ((apm = ibuf_advance(ibuf, sizeof(*apm))) == NULL) |
404 |
|
|
return (-1); |
405 |
|
|
|
406 |
|
|
apm->apm_type = htons(OFP_ACTION_POP_MPLS); |
407 |
|
|
apm->apm_len = htons(sizeof(*apm)); |
408 |
|
|
apm->apm_ethertype = htons(ethertype); |
409 |
|
|
return (0); |
410 |
|
|
} |
411 |
|
|
|
412 |
|
|
int |
413 |
|
|
action_copyttlout(struct ibuf *ibuf) |
414 |
|
|
{ |
415 |
|
|
return (action_new(ibuf, OFP_ACTION_COPY_TTL_OUT)); |
416 |
|
|
} |
417 |
|
|
|
418 |
|
|
int |
419 |
|
|
action_copyttlin(struct ibuf *ibuf) |
420 |
|
|
{ |
421 |
|
|
return (action_new(ibuf, OFP_ACTION_COPY_TTL_IN)); |
422 |
|
|
} |
423 |
|
|
|
424 |
|
|
int |
425 |
|
|
action_decnwttl(struct ibuf *ibuf) |
426 |
|
|
{ |
427 |
|
|
return (action_new(ibuf, OFP_ACTION_DEC_NW_TTL)); |
428 |
|
|
} |
429 |
|
|
|
430 |
|
|
/* |
431 |
|
|
* This function should be used with the oxm_*() family. |
432 |
|
|
* |
433 |
|
|
* After filling the action_setfield() with oxms you have to set the |
434 |
|
|
* asf_len with htons(size_of_oxms). |
435 |
|
|
*/ |
436 |
|
|
struct ofp_action_set_field * |
437 |
|
|
action_setfield(struct ibuf *ibuf) |
438 |
|
|
{ |
439 |
|
|
struct ofp_action_set_field *asf; |
440 |
|
|
|
441 |
|
|
if ((asf = ibuf_advance(ibuf, sizeof(*asf))) == NULL) |
442 |
|
|
return (NULL); |
443 |
|
|
|
444 |
|
|
asf->asf_type = htons(OFP_ACTION_SET_FIELD); |
445 |
|
|
return (asf); |
446 |
|
|
} |
447 |
|
|
|
448 |
|
|
struct ofp_ox_match * |
449 |
|
|
oxm_get(struct ibuf *ibuf, uint16_t field, int hasmask, uint8_t len) |
450 |
|
|
{ |
451 |
|
|
struct ofp_ox_match *oxm; |
452 |
|
|
size_t oxmlen; |
453 |
|
|
|
454 |
|
|
/* |
455 |
|
|
* When the mask is used we must always reserve double the space, |
456 |
|
|
* because the mask field is the same size of the value. |
457 |
|
|
*/ |
458 |
|
|
if (hasmask) |
459 |
|
|
len = len * 2; |
460 |
|
|
|
461 |
|
|
oxmlen = sizeof(*oxm) + len; |
462 |
|
|
if ((oxm = ibuf_advance(ibuf, oxmlen)) == NULL) |
463 |
|
|
return (NULL); |
464 |
|
|
|
465 |
|
|
oxm->oxm_class = htons(OFP_OXM_C_OPENFLOW_BASIC); |
466 |
|
|
oxm->oxm_length = len; |
467 |
|
|
OFP_OXM_SET_FIELD(oxm, field); |
468 |
|
|
if (hasmask) |
469 |
|
|
OFP_OXM_SET_HASMASK(oxm); |
470 |
|
|
|
471 |
|
|
return (oxm); |
472 |
|
|
} |
473 |
|
|
|
474 |
|
|
/* |
475 |
|
|
* OpenFlow port where the packet where received. |
476 |
|
|
* May be a physical port, a logical port or the reserved port OFPP_LOCAL. |
477 |
|
|
*/ |
478 |
|
|
int |
479 |
|
|
oxm_inport(struct ibuf *ibuf, uint32_t in_port) |
480 |
|
|
{ |
481 |
|
|
struct ofp_ox_match *oxm; |
482 |
|
|
|
483 |
|
|
if ((oxm = oxm_get(ibuf, OFP_XM_T_IN_PORT, 0, |
484 |
|
|
sizeof(in_port))) == NULL) |
485 |
|
|
return (-1); |
486 |
|
|
|
487 |
|
|
in_port = htonl(in_port); |
488 |
|
|
memcpy(oxm->oxm_value, &in_port, sizeof(in_port)); |
489 |
|
|
return (0); |
490 |
|
|
} |
491 |
|
|
|
492 |
|
|
/* |
493 |
|
|
* Physical port on which the packet was received. |
494 |
|
|
* Requires: oxm_inport. |
495 |
|
|
*/ |
496 |
|
|
int |
497 |
|
|
oxm_inphyport(struct ibuf *ibuf, uint32_t in_phy_port) |
498 |
|
|
{ |
499 |
|
|
struct ofp_ox_match *oxm; |
500 |
|
|
|
501 |
|
|
if ((oxm = oxm_get(ibuf, OFP_XM_T_IN_PHY_PORT, 0, |
502 |
|
|
sizeof(in_phy_port))) == NULL) |
503 |
|
|
return (-1); |
504 |
|
|
|
505 |
|
|
in_phy_port = htonl(in_phy_port); |
506 |
|
|
memcpy(oxm->oxm_value, &in_phy_port, sizeof(in_phy_port)); |
507 |
|
|
return (0); |
508 |
|
|
} |
509 |
|
|
|
510 |
|
|
/* Table metadata. */ |
511 |
|
|
int |
512 |
|
|
oxm_metadata(struct ibuf *ibuf, int hasmask, uint64_t metadata, uint64_t mask) |
513 |
|
|
{ |
514 |
|
|
struct ofp_ox_match *oxm; |
515 |
|
|
|
516 |
|
|
if ((oxm = oxm_get(ibuf, OFP_XM_T_META, hasmask, |
517 |
|
|
sizeof(metadata))) == NULL) |
518 |
|
|
return (-1); |
519 |
|
|
|
520 |
|
|
metadata = htobe64(metadata); |
521 |
|
|
memcpy(oxm->oxm_value, &metadata, sizeof(metadata)); |
522 |
|
|
if (hasmask) { |
523 |
|
|
mask = htobe64(mask); |
524 |
|
|
memcpy(oxm->oxm_value + sizeof(metadata), &mask, sizeof(mask)); |
525 |
|
|
} |
526 |
|
|
|
527 |
|
|
return (0); |
528 |
|
|
} |
529 |
|
|
|
530 |
|
|
int |
531 |
|
|
oxm_etheraddr(struct ibuf *ibuf, int issrc, uint8_t *addr, uint8_t *mask) |
532 |
|
|
{ |
533 |
|
|
struct ofp_ox_match *oxm; |
534 |
|
|
int type; |
535 |
|
|
int hasmask = (mask != NULL); |
536 |
|
|
|
537 |
|
|
type = issrc ? OFP_XM_T_ETH_SRC : OFP_XM_T_ETH_DST; |
538 |
|
|
if ((oxm = oxm_get(ibuf, type, hasmask, ETHER_ADDR_LEN)) == NULL) |
539 |
|
|
return (-1); |
540 |
|
|
|
541 |
|
|
memcpy(oxm->oxm_value, addr, ETHER_ADDR_LEN); |
542 |
|
|
if (hasmask) |
543 |
|
|
memcpy(oxm->oxm_value + ETHER_ADDR_LEN, mask, ETHER_ADDR_LEN); |
544 |
|
|
|
545 |
|
|
return (0); |
546 |
|
|
} |
547 |
|
|
|
548 |
|
|
int |
549 |
|
|
oxm_ethertype(struct ibuf *ibuf, uint16_t type) |
550 |
|
|
{ |
551 |
|
|
struct ofp_ox_match *oxm; |
552 |
|
|
|
553 |
|
|
if ((oxm = oxm_get(ibuf, OFP_XM_T_ETH_TYPE, 0, sizeof(type))) == NULL) |
554 |
|
|
return (-1); |
555 |
|
|
|
556 |
|
|
type = htons(type); |
557 |
|
|
memcpy(oxm->oxm_value, &type, sizeof(type)); |
558 |
|
|
return (0); |
559 |
|
|
} |
560 |
|
|
|
561 |
|
|
int |
562 |
|
|
oxm_vlanvid(struct ibuf *ibuf, int hasmask, uint16_t vid, uint16_t mask) |
563 |
|
|
{ |
564 |
|
|
struct ofp_ox_match *oxm; |
565 |
|
|
|
566 |
|
|
if ((oxm = oxm_get(ibuf, OFP_XM_T_VLAN_VID, hasmask, |
567 |
|
|
sizeof(vid))) == NULL) |
568 |
|
|
return (-1); |
569 |
|
|
|
570 |
|
|
/* VID uses only the 13 least significant bits. */ |
571 |
|
|
vid &= 0x1fff; |
572 |
|
|
vid = htons(vid); |
573 |
|
|
memcpy(oxm->oxm_value, &vid, sizeof(vid)); |
574 |
|
|
if (hasmask) { |
575 |
|
|
mask &= 0x1fff; |
576 |
|
|
mask = htons(mask); |
577 |
|
|
memcpy(oxm->oxm_value + sizeof(vid), &mask, sizeof(mask)); |
578 |
|
|
} |
579 |
|
|
|
580 |
|
|
return (0); |
581 |
|
|
} |
582 |
|
|
|
583 |
|
|
/* |
584 |
|
|
* 802.1Q Prio from the outermost tag. |
585 |
|
|
* |
586 |
|
|
* Requires: oxm_vlanvid. |
587 |
|
|
*/ |
588 |
|
|
int |
589 |
|
|
oxm_vlanpcp(struct ibuf *ibuf, uint8_t pcp) |
590 |
|
|
{ |
591 |
|
|
struct ofp_ox_match *oxm; |
592 |
|
|
|
593 |
|
|
if ((oxm = oxm_get(ibuf, OFP_XM_T_VLAN_PCP, 0, sizeof(pcp))) == NULL) |
594 |
|
|
return (-1); |
595 |
|
|
|
596 |
|
|
/* PCP only uses the lower 3 bits. */ |
597 |
|
|
pcp &= 0x07; |
598 |
|
|
memcpy(oxm->oxm_value, &pcp, sizeof(pcp)); |
599 |
|
|
return (0); |
600 |
|
|
} |
601 |
|
|
|
602 |
|
|
/* |
603 |
|
|
* The Diff Serv Code Point (DSCP) bits avaliable in IPv4 ToS field or |
604 |
|
|
* IPv6 Traffic Class field. |
605 |
|
|
* |
606 |
|
|
* Requires: oxm_ethertype(ETHERTYPE_IP) or oxm_ethertype(ETHERTYPE_IPV6). |
607 |
|
|
*/ |
608 |
|
|
int |
609 |
|
|
oxm_ipdscp(struct ibuf *ibuf, uint8_t dscp) |
610 |
|
|
{ |
611 |
|
|
struct ofp_ox_match *oxm; |
612 |
|
|
|
613 |
|
|
if ((oxm = oxm_get(ibuf, OFP_XM_T_IP_DSCP, 0, sizeof(dscp))) == NULL) |
614 |
|
|
return (-1); |
615 |
|
|
|
616 |
|
|
/* Only the 6 lower bits have meaning. */ |
617 |
|
|
dscp &= 0x3F; |
618 |
|
|
memcpy(oxm->oxm_value, &dscp, sizeof(dscp)); |
619 |
|
|
return (0); |
620 |
|
|
} |
621 |
|
|
|
622 |
|
|
/* |
623 |
|
|
* The ECN (Explicit Congestion Notification) bits of IP headers. |
624 |
|
|
* |
625 |
|
|
* Requires: oxm_ethertype(ETHERTYPE_IP) or oxm_ethertype(ETHERTYPE_IPV6). |
626 |
|
|
*/ |
627 |
|
|
int |
628 |
|
|
oxm_ipecn(struct ibuf *ibuf, uint8_t ecn) |
629 |
|
|
{ |
630 |
|
|
struct ofp_ox_match *oxm; |
631 |
|
|
|
632 |
|
|
if ((oxm = oxm_get(ibuf, OFP_XM_T_IP_ECN, 0, sizeof(ecn))) == NULL) |
633 |
|
|
return (-1); |
634 |
|
|
|
635 |
|
|
/* Only the 2 most significant bits have meaning. */ |
636 |
|
|
ecn &= 0x03; |
637 |
|
|
memcpy(oxm->oxm_value, &ecn, sizeof(ecn)); |
638 |
|
|
return (0); |
639 |
|
|
} |
640 |
|
|
|
641 |
|
|
/* |
642 |
|
|
* The IP protocol byte. |
643 |
|
|
* |
644 |
|
|
* Requires: oxm_ethertype(ETHERTYPE_IP) or oxm_ethertype(ETHERTYPE_IPV6). |
645 |
|
|
*/ |
646 |
|
|
int |
647 |
|
|
oxm_ipproto(struct ibuf *ibuf, uint8_t proto) |
648 |
|
|
{ |
649 |
|
|
struct ofp_ox_match *oxm; |
650 |
|
|
|
651 |
|
|
if ((oxm = oxm_get(ibuf, OFP_XM_T_IP_PROTO, 0, sizeof(proto))) == NULL) |
652 |
|
|
return (-1); |
653 |
|
|
|
654 |
|
|
memcpy(oxm->oxm_value, &proto, sizeof(proto)); |
655 |
|
|
return (0); |
656 |
|
|
} |
657 |
|
|
|
658 |
|
|
/* |
659 |
|
|
* The IPv4 address source/destination. |
660 |
|
|
* |
661 |
|
|
* Requires: oxm_ethertype(ETHERTYPE_IP). |
662 |
|
|
*/ |
663 |
|
|
int |
664 |
|
|
oxm_ipaddr(struct ibuf *ibuf, int issrc, int hasmask, uint32_t addr, |
665 |
|
|
uint32_t mask) |
666 |
|
|
{ |
667 |
|
|
struct ofp_ox_match *oxm; |
668 |
|
|
int type; |
669 |
|
|
|
670 |
|
|
type = issrc ? OFP_XM_T_IPV4_SRC : OFP_XM_T_IPV4_DST; |
671 |
|
|
if ((oxm = oxm_get(ibuf, type, hasmask, sizeof(addr))) == NULL) |
672 |
|
|
return (-1); |
673 |
|
|
|
674 |
|
|
addr = htonl(addr); |
675 |
|
|
memcpy(oxm->oxm_value, &addr, sizeof(addr)); |
676 |
|
|
if (hasmask) { |
677 |
|
|
mask = htonl(mask); |
678 |
|
|
memcpy(oxm->oxm_value + sizeof(addr), &mask, sizeof(mask)); |
679 |
|
|
} |
680 |
|
|
|
681 |
|
|
return (0); |
682 |
|
|
} |
683 |
|
|
|
684 |
|
|
/* |
685 |
|
|
* The TCP source/destination port. |
686 |
|
|
* |
687 |
|
|
* Requirements: oxm_ethertype(ETHERTYPE_IP) or oxm_ethertype(ETHERTYPE_IPV6) |
688 |
|
|
* and oxm_ipproto(IPPROTO_TCP). |
689 |
|
|
*/ |
690 |
|
|
int |
691 |
|
|
oxm_tcpport(struct ibuf *ibuf, int issrc, uint16_t port) |
692 |
|
|
{ |
693 |
|
|
struct ofp_ox_match *oxm; |
694 |
|
|
int type; |
695 |
|
|
|
696 |
|
|
type = issrc ? OFP_XM_T_TCP_SRC : OFP_XM_T_TCP_DST; |
697 |
|
|
if ((oxm = oxm_get(ibuf, type, 0, sizeof(port))) == NULL) |
698 |
|
|
return (-1); |
699 |
|
|
|
700 |
|
|
port = htons(port); |
701 |
|
|
memcpy(oxm->oxm_value, &port, sizeof(port)); |
702 |
|
|
return (0); |
703 |
|
|
} |
704 |
|
|
|
705 |
|
|
/* |
706 |
|
|
* The UDP source/destination port. |
707 |
|
|
* |
708 |
|
|
* Requirements: oxm_ethertype(ETHERTYPE_IP) or oxm_ethertype(ETHERTYPE_IPV6) |
709 |
|
|
* and oxm_ipproto(IPPROTO_UDP). |
710 |
|
|
*/ |
711 |
|
|
int |
712 |
|
|
oxm_udpport(struct ibuf *ibuf, int issrc, uint16_t port) |
713 |
|
|
{ |
714 |
|
|
struct ofp_ox_match *oxm; |
715 |
|
|
int type; |
716 |
|
|
|
717 |
|
|
type = issrc ? OFP_XM_T_UDP_SRC : OFP_XM_T_UDP_DST; |
718 |
|
|
if ((oxm = oxm_get(ibuf, type, 0, sizeof(port))) == NULL) |
719 |
|
|
return (-1); |
720 |
|
|
|
721 |
|
|
port = htons(port); |
722 |
|
|
memcpy(oxm->oxm_value, &port, sizeof(port)); |
723 |
|
|
return (0); |
724 |
|
|
} |
725 |
|
|
|
726 |
|
|
/* |
727 |
|
|
* The SCTP source/destination port. |
728 |
|
|
* |
729 |
|
|
* Requirements: oxm_ethertype(ETHERTYPE_IP) or oxm_ethertype(ETHERTYPE_IPV6) |
730 |
|
|
* and oxm_ipproto(IPPROTO_??? -- 132). |
731 |
|
|
*/ |
732 |
|
|
int |
733 |
|
|
oxm_sctpport(struct ibuf *ibuf, int issrc, uint16_t port) |
734 |
|
|
{ |
735 |
|
|
struct ofp_ox_match *oxm; |
736 |
|
|
int type; |
737 |
|
|
|
738 |
|
|
type = issrc ? OFP_XM_T_SCTP_SRC : OFP_XM_T_SCTP_DST; |
739 |
|
|
if ((oxm = oxm_get(ibuf, type, 0, sizeof(port))) == NULL) |
740 |
|
|
return (-1); |
741 |
|
|
|
742 |
|
|
port = htons(port); |
743 |
|
|
memcpy(oxm->oxm_value, &port, sizeof(port)); |
744 |
|
|
return (0); |
745 |
|
|
} |
746 |
|
|
|
747 |
|
|
/* |
748 |
|
|
* The ICMPv4 type in the ICMP header. |
749 |
|
|
* |
750 |
|
|
* Requires: oxm_ethertype(ETHERTYPE_IP) and oxm_ipproto(IPPROTO_ICMP). |
751 |
|
|
*/ |
752 |
|
|
int |
753 |
|
|
oxm_icmpv4type(struct ibuf *ibuf, uint8_t type) |
754 |
|
|
{ |
755 |
|
|
struct ofp_ox_match *oxm; |
756 |
|
|
|
757 |
|
|
if ((oxm = oxm_get(ibuf, OFP_XM_T_ICMPV4_TYPE, 0, |
758 |
|
|
sizeof(type))) == NULL) |
759 |
|
|
return (-1); |
760 |
|
|
|
761 |
|
|
memcpy(oxm->oxm_value, &type, sizeof(type)); |
762 |
|
|
return (0); |
763 |
|
|
} |
764 |
|
|
|
765 |
|
|
/* |
766 |
|
|
* The ICMPv4 code in the ICMP header. |
767 |
|
|
* |
768 |
|
|
* Requires: oxm_ethertype(ETHERTYPE_IP) and oxm_ipproto(IPPROTO_ICMP). |
769 |
|
|
*/ |
770 |
|
|
int |
771 |
|
|
oxm_icmpv4code(struct ibuf *ibuf, uint8_t code) |
772 |
|
|
{ |
773 |
|
|
struct ofp_ox_match *oxm; |
774 |
|
|
|
775 |
|
|
if ((oxm = oxm_get(ibuf, OFP_XM_T_ICMPV4_CODE, 0, |
776 |
|
|
sizeof(code))) == NULL) |
777 |
|
|
return (-1); |
778 |
|
|
|
779 |
|
|
memcpy(oxm->oxm_value, &code, sizeof(code)); |
780 |
|
|
return (0); |
781 |
|
|
} |
782 |
|
|
|
783 |
|
|
/* |
784 |
|
|
* ARP opcode. |
785 |
|
|
* |
786 |
|
|
* Requires: oxm_ethertype(ETHERTYPE_ARP). |
787 |
|
|
*/ |
788 |
|
|
int |
789 |
|
|
oxm_arpop(struct ibuf *ibuf, uint16_t op) |
790 |
|
|
{ |
791 |
|
|
struct ofp_ox_match *oxm; |
792 |
|
|
|
793 |
|
|
if ((oxm = oxm_get(ibuf, OFP_XM_T_ARP_OP, 0, sizeof(op))) == NULL) |
794 |
|
|
return (-1); |
795 |
|
|
|
796 |
|
|
op = htons(op); |
797 |
|
|
memcpy(oxm->oxm_value, &op, sizeof(op)); |
798 |
|
|
return (0); |
799 |
|
|
} |
800 |
|
|
|
801 |
|
|
/* |
802 |
|
|
* ARP source/target protocol address. |
803 |
|
|
* |
804 |
|
|
* Requires: oxm_ethertype(ETHERTYPE_ARP). |
805 |
|
|
*/ |
806 |
|
|
int |
807 |
|
|
oxm_arpaddr(struct ibuf *ibuf, int issrc, int hasmask, uint32_t addr, |
808 |
|
|
uint32_t mask) |
809 |
|
|
{ |
810 |
|
|
struct ofp_ox_match *oxm; |
811 |
|
|
int type; |
812 |
|
|
|
813 |
|
|
type = issrc ? OFP_XM_T_ARP_SPA : OFP_XM_T_ARP_TPA; |
814 |
|
|
if ((oxm = oxm_get(ibuf, type, hasmask, sizeof(addr))) == NULL) |
815 |
|
|
return (-1); |
816 |
|
|
|
817 |
|
|
addr = htonl(addr); |
818 |
|
|
memcpy(oxm->oxm_value, &addr, sizeof(addr)); |
819 |
|
|
if (hasmask) { |
820 |
|
|
mask = htonl(mask); |
821 |
|
|
memcpy(oxm->oxm_value + sizeof(addr), &mask, sizeof(mask)); |
822 |
|
|
} |
823 |
|
|
|
824 |
|
|
return (0); |
825 |
|
|
} |
826 |
|
|
|
827 |
|
|
/* |
828 |
|
|
* ARP source/target hardware address. |
829 |
|
|
* |
830 |
|
|
* Requires: oxm_ethertype(ETHERTYPE_ARP). |
831 |
|
|
*/ |
832 |
|
|
int |
833 |
|
|
oxm_arphaddr(struct ibuf *ibuf, int issrc, uint8_t *addr, uint8_t *mask) |
834 |
|
|
{ |
835 |
|
|
struct ofp_ox_match *oxm; |
836 |
|
|
int type; |
837 |
|
|
int hasmask = (mask != NULL); |
838 |
|
|
|
839 |
|
|
type = issrc ? OFP_XM_T_ARP_SHA : OFP_XM_T_ARP_THA; |
840 |
|
|
if ((oxm = oxm_get(ibuf, type, hasmask, ETHER_ADDR_LEN)) == NULL) |
841 |
|
|
return (-1); |
842 |
|
|
|
843 |
|
|
memcpy(oxm->oxm_value, addr, ETHER_ADDR_LEN); |
844 |
|
|
if (hasmask) |
845 |
|
|
memcpy(oxm->oxm_value + ETHER_ADDR_LEN, mask, ETHER_ADDR_LEN); |
846 |
|
|
|
847 |
|
|
return (0); |
848 |
|
|
} |
849 |
|
|
|
850 |
|
|
/* |
851 |
|
|
* The source or destination of the IPv6 address. |
852 |
|
|
* |
853 |
|
|
* Requirements: oxm_ethertype(ETHERTYPE_IPV6). |
854 |
|
|
*/ |
855 |
|
|
int |
856 |
|
|
oxm_ipv6addr(struct ibuf *ibuf, int issrc, struct in6_addr *addr, |
857 |
|
|
struct in6_addr *mask) |
858 |
|
|
{ |
859 |
|
|
struct ofp_ox_match *oxm; |
860 |
|
|
int type; |
861 |
|
|
int hasmask = (mask != NULL); |
862 |
|
|
|
863 |
|
|
type = issrc ? OFP_XM_T_IPV6_SRC : OFP_XM_T_IPV6_DST; |
864 |
|
|
if ((oxm = oxm_get(ibuf, type, hasmask, sizeof(*addr))) == NULL) |
865 |
|
|
return (-1); |
866 |
|
|
|
867 |
|
|
memcpy(oxm->oxm_value, addr, sizeof(*addr)); |
868 |
|
|
if (hasmask) |
869 |
|
|
memcpy(oxm->oxm_value + sizeof(*addr), mask, sizeof(*mask)); |
870 |
|
|
|
871 |
|
|
return (0); |
872 |
|
|
} |
873 |
|
|
|
874 |
|
|
/* |
875 |
|
|
* The IPv6 flow label field. |
876 |
|
|
* |
877 |
|
|
* Requirements: oxm_ethertype(ETHERTYPE_IPV6). |
878 |
|
|
*/ |
879 |
|
|
int |
880 |
|
|
oxm_ipv6flowlabel(struct ibuf *ibuf, int hasmask, uint32_t flowlabel, |
881 |
|
|
uint32_t mask) |
882 |
|
|
{ |
883 |
|
|
struct ofp_ox_match *oxm; |
884 |
|
|
|
885 |
|
|
if ((oxm = oxm_get(ibuf, OFP_XM_T_IPV6_FLABEL, hasmask, |
886 |
|
|
sizeof(flowlabel))) == NULL) |
887 |
|
|
return (-1); |
888 |
|
|
|
889 |
|
|
/* |
890 |
|
|
* 12 most significants bits forced to 0 and only the 20 lowers |
891 |
|
|
* bits have meaning. |
892 |
|
|
*/ |
893 |
|
|
flowlabel &= 0x000FFFFFU; |
894 |
|
|
flowlabel = htonl(flowlabel); |
895 |
|
|
memcpy(oxm->oxm_value, &flowlabel, sizeof(flowlabel)); |
896 |
|
|
if (hasmask) { |
897 |
|
|
mask &= 0x000FFFFFU; |
898 |
|
|
mask = htonl(mask); |
899 |
|
|
memcpy(oxm->oxm_value + sizeof(flowlabel), &mask, sizeof(mask)); |
900 |
|
|
} |
901 |
|
|
|
902 |
|
|
return (0); |
903 |
|
|
} |
904 |
|
|
|
905 |
|
|
/* |
906 |
|
|
* The ICMPv6 type in ICMP header. |
907 |
|
|
* |
908 |
|
|
* Requirements: oxm_ethertype(ETHERTYPE_IPV6) and oxm_ipproto(IPPROTO_ICMPV6). |
909 |
|
|
*/ |
910 |
|
|
int |
911 |
|
|
oxm_icmpv6type(struct ibuf *ibuf, uint8_t type) |
912 |
|
|
{ |
913 |
|
|
struct ofp_ox_match *oxm; |
914 |
|
|
|
915 |
|
|
if ((oxm = oxm_get(ibuf, OFP_XM_T_ICMPV6_TYPE, 0, |
916 |
|
|
sizeof(type))) == NULL) |
917 |
|
|
return (-1); |
918 |
|
|
|
919 |
|
|
memcpy(oxm->oxm_value, &type, sizeof(type)); |
920 |
|
|
return (0); |
921 |
|
|
} |
922 |
|
|
|
923 |
|
|
/* |
924 |
|
|
* The ICMPv6 code in ICMP header. |
925 |
|
|
* |
926 |
|
|
* Requirements: oxm_ethertype(ETHERTYPE_IPV6) and oxm_ipproto(IPPROTO_ICMPV6). |
927 |
|
|
*/ |
928 |
|
|
int |
929 |
|
|
oxm_icmpv6code(struct ibuf *ibuf, uint8_t code) |
930 |
|
|
{ |
931 |
|
|
struct ofp_ox_match *oxm; |
932 |
|
|
|
933 |
|
|
if ((oxm = oxm_get(ibuf, OFP_XM_T_ICMPV6_CODE, 0, |
934 |
|
|
sizeof(code))) == NULL) |
935 |
|
|
return (-1); |
936 |
|
|
|
937 |
|
|
memcpy(oxm->oxm_value, &code, sizeof(code)); |
938 |
|
|
return (0); |
939 |
|
|
} |
940 |
|
|
|
941 |
|
|
/* |
942 |
|
|
* The target address in neighbour discovery message. |
943 |
|
|
* |
944 |
|
|
* Requirements: oxm_ethertype(ETHERTYPE_IPV6), oxm_ipproto(IPPROTO_ICMPV6) |
945 |
|
|
* and oxm_icmpv6type(ND_NEIGHBOR_SOLICIT) or |
946 |
|
|
* oxm_icmpv6type(ND_NEIGHBOR_ADVERT). |
947 |
|
|
*/ |
948 |
|
|
int |
949 |
|
|
oxm_ipv6ndtarget(struct ibuf *ibuf, struct in6_addr *addr) |
950 |
|
|
{ |
951 |
|
|
struct ofp_ox_match *oxm; |
952 |
|
|
|
953 |
|
|
if ((oxm = oxm_get(ibuf, OFP_XM_T_IPV6_ND_TARGET, 0, |
954 |
|
|
sizeof(*addr))) == NULL) |
955 |
|
|
return (-1); |
956 |
|
|
|
957 |
|
|
memcpy(oxm->oxm_value, addr, sizeof(*addr)); |
958 |
|
|
return (0); |
959 |
|
|
} |
960 |
|
|
|
961 |
|
|
/* |
962 |
|
|
* The source link-layer address in an IPv6 Neighbour discovery. |
963 |
|
|
* |
964 |
|
|
* Requirements: oxm_ethertype(ETHERTYPE_IPV6), oxm_ipproto(IPPROTO_ICMPV6) |
965 |
|
|
* and oxm_icmpv6type(ND_NEIGHBOR_SOLICIT). |
966 |
|
|
*/ |
967 |
|
|
int |
968 |
|
|
oxm_ipv6ndlinkaddr(struct ibuf *ibuf, int issrc, uint8_t *addr) |
969 |
|
|
{ |
970 |
|
|
struct ofp_ox_match *oxm; |
971 |
|
|
int type; |
972 |
|
|
|
973 |
|
|
type = issrc ? OFP_XM_T_IPV6_ND_SLL : OFP_XM_T_IPV6_ND_TLL; |
974 |
|
|
if ((oxm = oxm_get(ibuf, type, 0, ETHER_ADDR_LEN)) == NULL) |
975 |
|
|
return (-1); |
976 |
|
|
|
977 |
|
|
memcpy(oxm->oxm_value, addr, ETHER_ADDR_LEN); |
978 |
|
|
return (0); |
979 |
|
|
} |
980 |
|
|
|
981 |
|
|
/* |
982 |
|
|
* The label in the MPLS shim. |
983 |
|
|
* |
984 |
|
|
* Requirements: oxm_ethertype(ETHERTYPE_MPLS) or |
985 |
|
|
* oxm_ethertype(ETHERTYPE_MPLS_MCAST). |
986 |
|
|
*/ |
987 |
|
|
int |
988 |
|
|
oxm_mplslabel(struct ibuf *ibuf, uint32_t label) |
989 |
|
|
{ |
990 |
|
|
struct ofp_ox_match *oxm; |
991 |
|
|
|
992 |
|
|
if ((oxm = oxm_get(ibuf, OFP_XM_T_MPLS_LABEL, 0, |
993 |
|
|
sizeof(label))) == NULL) |
994 |
|
|
return (-1); |
995 |
|
|
|
996 |
|
|
label &= MPLS_LABEL_MASK; |
997 |
|
|
label = htonl(label); |
998 |
|
|
memcpy(oxm->oxm_value, &label, sizeof(label)); |
999 |
|
|
return (0); |
1000 |
|
|
} |
1001 |
|
|
|
1002 |
|
|
/* |
1003 |
|
|
* The TC in the first MPLS shim. |
1004 |
|
|
* |
1005 |
|
|
* Requirements: oxm_ethertype(ETHERTYPE_MPLS) or |
1006 |
|
|
* oxm_ethertype(ETHERTYPE_MPLS_MCAST). |
1007 |
|
|
*/ |
1008 |
|
|
int |
1009 |
|
|
oxm_mplstc(struct ibuf *ibuf, uint8_t tc) |
1010 |
|
|
{ |
1011 |
|
|
struct ofp_ox_match *oxm; |
1012 |
|
|
|
1013 |
|
|
if ((oxm = oxm_get(ibuf, OFP_XM_T_MPLS_TC, 0, sizeof(tc))) == NULL) |
1014 |
|
|
return (-1); |
1015 |
|
|
|
1016 |
|
|
tc &= 0x07; |
1017 |
|
|
memcpy(oxm->oxm_value, &tc, sizeof(tc)); |
1018 |
|
|
return (0); |
1019 |
|
|
} |
1020 |
|
|
|
1021 |
|
|
/* |
1022 |
|
|
* The BoS bit in the first MPLS shim. |
1023 |
|
|
* |
1024 |
|
|
* Requirements: oxm_ethertype(ETHERTYPE_MPLS) or |
1025 |
|
|
* oxm_ethertype(ETHERTYPE_MPLS_MCAST). |
1026 |
|
|
*/ |
1027 |
|
|
int |
1028 |
|
|
oxm_mplsbos(struct ibuf *ibuf, uint8_t bos) |
1029 |
|
|
{ |
1030 |
|
|
struct ofp_ox_match *oxm; |
1031 |
|
|
|
1032 |
|
|
if ((oxm = oxm_get(ibuf, OFP_XM_T_MPLS_BOS, 0, sizeof(bos))) == NULL) |
1033 |
|
|
return (-1); |
1034 |
|
|
|
1035 |
|
|
bos &= 0x01; |
1036 |
|
|
memcpy(oxm->oxm_value, &bos, sizeof(bos)); |
1037 |
|
|
return (0); |
1038 |
|
|
} |
1039 |
|
|
|
1040 |
|
|
/* |
1041 |
|
|
* Comment shamelessly taken from OpenFlow 1.3.5 specification. |
1042 |
|
|
* |
1043 |
|
|
* Metadata associated with a logical port. |
1044 |
|
|
* |
1045 |
|
|
* If the logical port performs encapsulation and decapsulation, this |
1046 |
|
|
* is the demultiplexing field from the encapsulation header. |
1047 |
|
|
* For example, for a packet received via GRE tunnel including a (32-bit) key, |
1048 |
|
|
* the key is stored in the low 32-bits and the high bits are zeroed. |
1049 |
|
|
* For a MPLS logical port, the low 20 bits represent the MPLS Label. |
1050 |
|
|
* For a VxLAN logical port, the low 24 bits represent the VNI. |
1051 |
|
|
* If the packet is not received through a logical port, the value is 0. |
1052 |
|
|
*/ |
1053 |
|
|
int |
1054 |
|
|
oxm_tunnelid(struct ibuf *ibuf, int hasmask, uint64_t id, uint64_t mask) |
1055 |
|
|
{ |
1056 |
|
|
struct ofp_ox_match *oxm; |
1057 |
|
|
|
1058 |
|
|
if ((oxm = oxm_get(ibuf, OFP_XM_T_TUNNEL_ID, hasmask, |
1059 |
|
|
sizeof(id))) == NULL) |
1060 |
|
|
return (-1); |
1061 |
|
|
|
1062 |
|
|
id = htobe64(id); |
1063 |
|
|
memcpy(oxm->oxm_value, &id, sizeof(id)); |
1064 |
|
|
if (hasmask) { |
1065 |
|
|
mask = htobe64(mask); |
1066 |
|
|
memcpy(oxm->oxm_value + sizeof(id), &mask, sizeof(mask)); |
1067 |
|
|
} |
1068 |
|
|
return (0); |
1069 |
|
|
} |
1070 |
|
|
|
1071 |
|
|
/* |
1072 |
|
|
* The IPv6 extension header. |
1073 |
|
|
* |
1074 |
|
|
* Tip: use the OFP_XM_IPV6_EXTHDR_* macros. |
1075 |
|
|
* |
1076 |
|
|
* Requirements: oxm_ethertype(ETHERTYPE_IPV6). |
1077 |
|
|
*/ |
1078 |
|
|
int |
1079 |
|
|
oxm_ipv6exthdr(struct ibuf *ibuf, int hasmask, uint16_t exthdr, uint16_t mask) |
1080 |
|
|
{ |
1081 |
|
|
struct ofp_ox_match *oxm; |
1082 |
|
|
|
1083 |
|
|
if ((oxm = oxm_get(ibuf, OFP_XM_T_IPV6_EXTHDR, hasmask, |
1084 |
|
|
sizeof(exthdr))) == NULL) |
1085 |
|
|
return (-1); |
1086 |
|
|
|
1087 |
|
|
/* Only the lower 9 bits have meaning. */ |
1088 |
|
|
exthdr &= 0x01FF; |
1089 |
|
|
exthdr = htons(exthdr); |
1090 |
|
|
memcpy(oxm->oxm_value, &exthdr, sizeof(exthdr)); |
1091 |
|
|
if (hasmask) { |
1092 |
|
|
mask &= 0x01FF; |
1093 |
|
|
mask = htons(mask); |
1094 |
|
|
memcpy(oxm->oxm_value + sizeof(exthdr), &mask, sizeof(mask)); |
1095 |
|
|
} |
1096 |
|
|
return (0); |
1097 |
|
|
} |
1098 |
|
|
|
1099 |
|
|
/* |
1100 |
|
|
* Appends a new instruction with hlen size. |
1101 |
|
|
* |
1102 |
|
|
* Remember to set the instruction length (i->i_len) if it has more data, |
1103 |
|
|
* like ofp_instruction_actions, ofp_instruction_goto_table etc... |
1104 |
|
|
*/ |
1105 |
|
|
struct ofp_instruction * |
1106 |
|
|
ofp_instruction(struct ibuf *ibuf, uint16_t type, uint16_t hlen) |
1107 |
|
|
{ |
1108 |
|
|
struct ofp_instruction *oi; |
1109 |
|
|
|
1110 |
|
|
if ((oi = ibuf_advance(ibuf, hlen)) == NULL) |
1111 |
|
|
return (NULL); |
1112 |
|
|
|
1113 |
|
|
oi->i_type = htons(type); |
1114 |
|
|
oi->i_len = htons(hlen); |
1115 |
|
|
return (oi); |
1116 |
|
|
} |
1117 |
|
|
|
1118 |
|
|
struct multipart_message * |
1119 |
|
|
ofp_multipart_lookup(struct switch_connection *con, uint32_t xid) |
1120 |
|
|
{ |
1121 |
|
|
struct multipart_message *mm; |
1122 |
|
|
|
1123 |
|
|
SLIST_FOREACH(mm, &con->con_mmlist, mm_entry) { |
1124 |
|
|
if (mm->mm_xid != xid) |
1125 |
|
|
continue; |
1126 |
|
|
|
1127 |
|
|
return (mm); |
1128 |
|
|
} |
1129 |
|
|
|
1130 |
|
|
return (NULL); |
1131 |
|
|
} |
1132 |
|
|
|
1133 |
|
|
int |
1134 |
|
|
ofp_multipart_add(struct switch_connection *con, uint32_t xid, uint8_t type) |
1135 |
|
|
{ |
1136 |
|
|
struct multipart_message *mm; |
1137 |
|
|
|
1138 |
|
|
if ((mm = ofp_multipart_lookup(con, xid)) != NULL) { |
1139 |
|
|
/* |
1140 |
|
|
* A multipart reply has the same xid and type, otherwise |
1141 |
|
|
* something went wrong. |
1142 |
|
|
*/ |
1143 |
|
|
if (mm->mm_type != type) |
1144 |
|
|
return (-1); |
1145 |
|
|
|
1146 |
|
|
return (0); |
1147 |
|
|
} |
1148 |
|
|
|
1149 |
|
|
if ((mm = calloc(1, sizeof(*mm))) == NULL) |
1150 |
|
|
return (-1); |
1151 |
|
|
|
1152 |
|
|
mm->mm_xid = xid; |
1153 |
|
|
mm->mm_type = type; |
1154 |
|
|
SLIST_INSERT_HEAD(&con->con_mmlist, mm, mm_entry); |
1155 |
|
|
return (0); |
1156 |
|
|
} |
1157 |
|
|
|
1158 |
|
|
void |
1159 |
|
|
ofp_multipart_del(struct switch_connection *con, uint32_t xid) |
1160 |
|
|
{ |
1161 |
|
|
struct multipart_message *mm; |
1162 |
|
|
|
1163 |
|
|
SLIST_FOREACH(mm, &con->con_mmlist, mm_entry) |
1164 |
|
|
if (mm->mm_xid == xid) |
1165 |
|
|
break; |
1166 |
|
|
|
1167 |
|
|
if (mm == NULL) |
1168 |
|
|
return; |
1169 |
|
|
|
1170 |
|
|
ofp_multipart_free(con, mm); |
1171 |
|
|
} |
1172 |
|
|
|
1173 |
|
|
void |
1174 |
|
|
ofp_multipart_free(struct switch_connection *con, |
1175 |
|
|
struct multipart_message *mm) |
1176 |
|
|
{ |
1177 |
|
|
SLIST_REMOVE(&con->con_mmlist, mm, multipart_message, mm_entry); |
1178 |
|
|
free(mm); |
1179 |
|
|
} |
1180 |
|
|
|
1181 |
|
|
void |
1182 |
|
|
ofp_multipart_clear(struct switch_connection *con) |
1183 |
|
|
{ |
1184 |
|
|
struct multipart_message *mm; |
1185 |
|
|
|
1186 |
|
|
while (!SLIST_EMPTY(&con->con_mmlist)) { |
1187 |
|
|
mm = SLIST_FIRST(&con->con_mmlist); |
1188 |
|
|
ofp_multipart_free(con, mm); |
1189 |
|
|
} |
1190 |
|
|
} |
1191 |
|
|
|
1192 |
|
|
struct switch_table * |
1193 |
|
|
switch_tablelookup(struct switch_connection *con, int table) |
1194 |
|
|
{ |
1195 |
|
|
struct switch_table *st; |
1196 |
|
|
|
1197 |
|
|
TAILQ_FOREACH(st, &con->con_stlist, st_entry) { |
1198 |
|
|
if (st->st_table == table) |
1199 |
|
|
return (st); |
1200 |
|
|
} |
1201 |
|
|
|
1202 |
|
|
return (NULL); |
1203 |
|
|
} |
1204 |
|
|
|
1205 |
|
|
struct switch_table * |
1206 |
|
|
switch_newtable(struct switch_connection *con, int table) |
1207 |
|
|
{ |
1208 |
|
|
struct switch_table *st; |
1209 |
|
|
|
1210 |
|
|
if ((st = calloc(1, sizeof(*st))) == NULL) |
1211 |
|
|
return (NULL); |
1212 |
|
|
|
1213 |
|
|
st->st_table = table; |
1214 |
|
|
TAILQ_INSERT_TAIL(&con->con_stlist, st, st_entry); |
1215 |
|
|
|
1216 |
|
|
return (st); |
1217 |
|
|
} |
1218 |
|
|
|
1219 |
|
|
void |
1220 |
|
|
switch_deltable(struct switch_connection *con, struct switch_table *st) |
1221 |
|
|
{ |
1222 |
|
|
TAILQ_REMOVE(&con->con_stlist, st, st_entry); |
1223 |
|
|
free(st); |
1224 |
|
|
} |
1225 |
|
|
|
1226 |
|
|
void |
1227 |
|
|
switch_freetables(struct switch_connection *con) |
1228 |
|
|
{ |
1229 |
|
|
struct switch_table *st; |
1230 |
|
|
|
1231 |
|
|
while (!TAILQ_EMPTY(&con->con_stlist)) { |
1232 |
|
|
st = TAILQ_FIRST(&con->con_stlist); |
1233 |
|
|
switch_deltable(con, st); |
1234 |
|
|
} |
1235 |
|
|
} |
1236 |
|
|
|
1237 |
|
|
int |
1238 |
|
|
oflowmod_state(struct oflowmod_ctx *ctx, unsigned int old, unsigned int new) |
1239 |
|
|
{ |
1240 |
|
|
if (ctx->ctx_state != old) |
1241 |
|
|
return (-1); |
1242 |
|
|
ctx->ctx_state = new; |
1243 |
|
|
return (0); |
1244 |
|
|
} |
1245 |
|
|
|
1246 |
|
|
int |
1247 |
|
|
oflowmod_err(struct oflowmod_ctx *ctx, const char *func, int line) |
1248 |
|
|
{ |
1249 |
|
|
log_debug("%s: function %s line %d state %d", |
1250 |
|
|
__func__, func, line, ctx->ctx_state); |
1251 |
|
|
|
1252 |
|
|
if (ctx->ctx_state >= OFMCTX_ERR) |
1253 |
|
|
return (-1); |
1254 |
|
|
if (ctx->ctx_flags & OFMCTX_IBUF) |
1255 |
|
|
ibuf_release(ctx->ctx_ibuf); |
1256 |
|
|
ctx->ctx_state = OFMCTX_ERR; |
1257 |
|
|
return (-1); |
1258 |
|
|
} |
1259 |
|
|
|
1260 |
|
|
struct ibuf * |
1261 |
|
|
oflowmod_open(struct oflowmod_ctx *ctx, struct switch_connection *con, |
1262 |
|
|
struct ibuf *ibuf, uint8_t version) |
1263 |
|
|
{ |
1264 |
|
|
struct ofp_flow_mod *fm; |
1265 |
|
|
struct switch_connection conb; |
1266 |
|
|
|
1267 |
|
|
switch (version) { |
1268 |
|
|
case OFP_V_0: |
1269 |
|
|
case OFP_V_1_3: |
1270 |
|
|
version = OFP_V_1_3; |
1271 |
|
|
break; |
1272 |
|
|
default: |
1273 |
|
|
log_warnx("%s: unsupported version 0x%02x", __func__, version); |
1274 |
|
|
return (NULL); |
1275 |
|
|
} |
1276 |
|
|
|
1277 |
|
|
memset(ctx, 0, sizeof(*ctx)); |
1278 |
|
|
|
1279 |
|
|
if (oflowmod_state(ctx, OFMCTX_INIT, OFMCTX_OPEN) == -1) |
1280 |
|
|
goto err; |
1281 |
|
|
|
1282 |
|
|
if (ibuf == NULL) { |
1283 |
|
|
ctx->ctx_flags |= OFMCTX_IBUF; |
1284 |
|
|
if ((ibuf = ibuf_static()) == NULL) |
1285 |
|
|
goto err; |
1286 |
|
|
} |
1287 |
|
|
|
1288 |
|
|
ctx->ctx_ibuf = ibuf; |
1289 |
|
|
ctx->ctx_start = ibuf->wpos; |
1290 |
|
|
|
1291 |
|
|
/* |
1292 |
|
|
* The connection is not strictly required and might not be |
1293 |
|
|
* available in other places; just default to an xid 0. |
1294 |
|
|
*/ |
1295 |
|
|
if (con == NULL) { |
1296 |
|
|
con = &conb; |
1297 |
|
|
memset(con, 0, sizeof(*con)); |
1298 |
|
|
} |
1299 |
|
|
|
1300 |
|
|
/* uses defaults, can be changed by accessing fm later */ |
1301 |
|
|
if ((fm = ofp13_flowmod(con, ibuf, |
1302 |
|
|
OFP_FLOWCMD_ADD, 0, 0, 0, 0)) == NULL) |
1303 |
|
|
goto err; |
1304 |
|
|
|
1305 |
|
|
ctx->ctx_fm = fm; |
1306 |
|
|
|
1307 |
|
|
return (ctx->ctx_ibuf); |
1308 |
|
|
|
1309 |
|
|
err: |
1310 |
|
|
(void)oflowmod_err(ctx, __func__, __LINE__); |
1311 |
|
|
return (NULL); |
1312 |
|
|
} |
1313 |
|
|
|
1314 |
|
|
int |
1315 |
|
|
oflowmod_mopen(struct oflowmod_ctx *ctx) |
1316 |
|
|
{ |
1317 |
|
|
if (oflowmod_state(ctx, OFMCTX_OPEN, OFMCTX_MOPEN) == -1) |
1318 |
|
|
return (oflowmod_err(ctx, __func__, __LINE__)); |
1319 |
|
|
|
1320 |
|
|
ctx->ctx_ostart = ctx->ctx_start + |
1321 |
|
|
offsetof(struct ofp_flow_mod, fm_match); |
1322 |
|
|
|
1323 |
|
|
return (0); |
1324 |
|
|
} |
1325 |
|
|
|
1326 |
|
|
int |
1327 |
|
|
oflowmod_mclose(struct oflowmod_ctx *ctx) |
1328 |
|
|
{ |
1329 |
|
|
struct ibuf *ibuf = ctx->ctx_ibuf; |
1330 |
|
|
struct ofp_flow_mod *fm = ctx->ctx_fm; |
1331 |
|
|
size_t omlen, padding; |
1332 |
|
|
|
1333 |
|
|
if (oflowmod_state(ctx, OFMCTX_MOPEN, OFMCTX_MCLOSE) == -1) |
1334 |
|
|
return (oflowmod_err(ctx, __func__, __LINE__)); |
1335 |
|
|
|
1336 |
|
|
ctx->ctx_oend = ibuf->wpos; |
1337 |
|
|
omlen = ctx->ctx_oend - ctx->ctx_ostart; |
1338 |
|
|
|
1339 |
|
|
/* Update match length */ |
1340 |
|
|
fm->fm_match.om_length = htons(omlen); |
1341 |
|
|
|
1342 |
|
|
padding = OFP_ALIGN(omlen) - omlen; |
1343 |
|
|
if (padding) { |
1344 |
|
|
ctx->ctx_oend += padding; |
1345 |
|
|
if (ibuf_advance(ibuf, padding) == NULL) |
1346 |
|
|
return (oflowmod_err(ctx, __func__, __LINE__)); |
1347 |
|
|
} |
1348 |
|
|
|
1349 |
|
|
return (0); |
1350 |
|
|
} |
1351 |
|
|
|
1352 |
|
|
int |
1353 |
|
|
oflowmod_iopen(struct oflowmod_ctx *ctx) |
1354 |
|
|
{ |
1355 |
|
|
struct ibuf *ibuf = ctx->ctx_ibuf; |
1356 |
|
|
|
1357 |
|
|
if (ctx->ctx_state < OFMCTX_MOPEN && |
1358 |
|
|
(oflowmod_mopen(ctx) == -1)) |
1359 |
|
|
return (oflowmod_err(ctx, __func__, __LINE__)); |
1360 |
|
|
if (ctx->ctx_state < OFMCTX_MCLOSE && |
1361 |
|
|
(oflowmod_mclose(ctx) == -1)) |
1362 |
|
|
return (oflowmod_err(ctx, __func__, __LINE__)); |
1363 |
|
|
|
1364 |
|
|
if (oflowmod_state(ctx, OFMCTX_MCLOSE, OFMCTX_IOPEN) == -1) |
1365 |
|
|
return (oflowmod_err(ctx, __func__, __LINE__)); |
1366 |
|
|
|
1367 |
|
|
ctx->ctx_istart = ibuf->wpos; |
1368 |
|
|
|
1369 |
|
|
return (0); |
1370 |
|
|
} |
1371 |
|
|
|
1372 |
|
|
int |
1373 |
|
|
oflowmod_instruction(struct oflowmod_ctx *ctx, unsigned int type) |
1374 |
|
|
{ |
1375 |
|
|
struct ibuf *ibuf = ctx->ctx_ibuf; |
1376 |
|
|
struct ofp_instruction *oi; |
1377 |
|
|
size_t len; |
1378 |
|
|
|
1379 |
|
|
if (ctx->ctx_state < OFMCTX_IOPEN && |
1380 |
|
|
(oflowmod_iopen(ctx) == -1)) |
1381 |
|
|
return (oflowmod_err(ctx, __func__, __LINE__)); |
1382 |
|
|
|
1383 |
|
|
if (oflowmod_state(ctx, OFMCTX_IOPEN, OFMCTX_IOPEN) == -1) |
1384 |
|
|
return (oflowmod_err(ctx, __func__, __LINE__)); |
1385 |
|
|
|
1386 |
|
|
if (ctx->ctx_oi != NULL && oflowmod_instructionclose(ctx) == -1) |
1387 |
|
|
return (oflowmod_err(ctx, __func__, __LINE__)); |
1388 |
|
|
|
1389 |
|
|
ctx->ctx_oioff = ibuf->wpos; |
1390 |
|
|
|
1391 |
|
|
switch (type) { |
1392 |
|
|
case OFP_INSTRUCTION_T_GOTO_TABLE: |
1393 |
|
|
len = sizeof(struct ofp_instruction_goto_table); |
1394 |
|
|
break; |
1395 |
|
|
case OFP_INSTRUCTION_T_WRITE_META: |
1396 |
|
|
len = sizeof(struct ofp_instruction_write_metadata); |
1397 |
|
|
break; |
1398 |
|
|
case OFP_INSTRUCTION_T_WRITE_ACTIONS: |
1399 |
|
|
case OFP_INSTRUCTION_T_APPLY_ACTIONS: |
1400 |
|
|
case OFP_INSTRUCTION_T_CLEAR_ACTIONS: |
1401 |
|
|
len = sizeof(struct ofp_instruction_actions); |
1402 |
|
|
break; |
1403 |
|
|
case OFP_INSTRUCTION_T_METER: |
1404 |
|
|
len = sizeof(struct ofp_instruction_meter); |
1405 |
|
|
break; |
1406 |
|
|
case OFP_INSTRUCTION_T_EXPERIMENTER: |
1407 |
|
|
len = sizeof(struct ofp_instruction_experimenter); |
1408 |
|
|
break; |
1409 |
|
|
default: |
1410 |
|
|
return (oflowmod_err(ctx, __func__, __LINE__)); |
1411 |
|
|
} |
1412 |
|
|
|
1413 |
|
|
if ((oi = ofp_instruction(ibuf, type, len)) == NULL) |
1414 |
|
|
return (oflowmod_err(ctx, __func__, __LINE__)); |
1415 |
|
|
|
1416 |
|
|
ctx->ctx_oi = oi; |
1417 |
|
|
|
1418 |
|
|
return (0); |
1419 |
|
|
} |
1420 |
|
|
|
1421 |
|
|
int |
1422 |
|
|
oflowmod_instructionclose(struct oflowmod_ctx *ctx) |
1423 |
|
|
{ |
1424 |
|
|
struct ibuf *ibuf = ctx->ctx_ibuf; |
1425 |
|
|
struct ofp_instruction *oi = ctx->ctx_oi; |
1426 |
|
|
size_t oilen; |
1427 |
|
|
|
1428 |
|
|
if (ctx->ctx_state < OFMCTX_IOPEN || oi == NULL) |
1429 |
|
|
return (oflowmod_err(ctx, __func__, __LINE__)); |
1430 |
|
|
|
1431 |
|
|
oilen = ibuf->wpos - ctx->ctx_oioff; |
1432 |
|
|
|
1433 |
|
|
if (oilen > UINT16_MAX) |
1434 |
|
|
return (oflowmod_err(ctx, __func__, __LINE__)); |
1435 |
|
|
|
1436 |
|
|
oi->i_len = htons(oilen); |
1437 |
|
|
ctx->ctx_oi = NULL; |
1438 |
|
|
|
1439 |
|
|
return (0); |
1440 |
|
|
} |
1441 |
|
|
|
1442 |
|
|
int |
1443 |
|
|
oflowmod_iclose(struct oflowmod_ctx *ctx) |
1444 |
|
|
{ |
1445 |
|
|
struct ibuf *ibuf = ctx->ctx_ibuf; |
1446 |
|
|
|
1447 |
|
|
if (oflowmod_state(ctx, OFMCTX_IOPEN, OFMCTX_ICLOSE) == -1) |
1448 |
|
|
return (oflowmod_err(ctx, __func__, __LINE__)); |
1449 |
|
|
|
1450 |
|
|
if (ctx->ctx_oi != NULL && oflowmod_instructionclose(ctx) == -1) |
1451 |
|
|
return (-1); |
1452 |
|
|
|
1453 |
|
|
ctx->ctx_iend = ibuf->wpos; |
1454 |
|
|
|
1455 |
|
|
return (0); |
1456 |
|
|
} |
1457 |
|
|
|
1458 |
|
|
int |
1459 |
|
|
oflowmod_close(struct oflowmod_ctx *ctx) |
1460 |
|
|
{ |
1461 |
|
|
struct ofp_flow_mod *fm = ctx->ctx_fm; |
1462 |
|
|
struct ibuf *ibuf = ctx->ctx_ibuf; |
1463 |
|
|
size_t len; |
1464 |
|
|
|
1465 |
|
|
/* No matches, calculate default */ |
1466 |
|
|
if (ctx->ctx_state < OFMCTX_MOPEN && |
1467 |
|
|
(oflowmod_mopen(ctx) == -1 || |
1468 |
|
|
oflowmod_mclose(ctx) == -1)) |
1469 |
|
|
goto err; |
1470 |
|
|
|
1471 |
|
|
/* No instructions, calculate default */ |
1472 |
|
|
if (ctx->ctx_state < OFMCTX_IOPEN && |
1473 |
|
|
(oflowmod_iopen(ctx) == -1 || |
1474 |
|
|
oflowmod_iclose(ctx) == -1)) |
1475 |
|
|
goto err; |
1476 |
|
|
|
1477 |
|
|
if (oflowmod_state(ctx, OFMCTX_ICLOSE, OFMCTX_CLOSE) == -1) |
1478 |
|
|
goto err; |
1479 |
|
|
|
1480 |
|
|
/* Update length */ |
1481 |
|
|
len = ibuf->wpos - ctx->ctx_start; |
1482 |
|
|
fm->fm_oh.oh_length = htons(len); |
1483 |
|
|
|
1484 |
|
|
return (0); |
1485 |
|
|
|
1486 |
|
|
err: |
1487 |
|
|
return (oflowmod_err(ctx, __func__, __LINE__)); |
1488 |
|
|
|
1489 |
|
|
} |