Line data Source code
1 : /* $OpenBSD: switchofp.c,v 1.71 2018/08/21 16:40:23 akoshibe Exp $ */
2 :
3 : /*
4 : * Copyright (c) 2016 Kazuya GODA <goda@openbsd.org>
5 : * Copyright (c) 2015, 2016 YASUOKA Masahiko <yasuoka@openbsd.org>
6 : * Copyright (c) 2015, 2016 Reyk Floeter <reyk@openbsd.org>
7 : *
8 : * Permission to use, copy, modify, and distribute this software for any
9 : * purpose with or without fee is hereby granted, provided that the above
10 : * copyright notice and this permission notice appear in all copies.
11 : *
12 : * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 : * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 : * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 : * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 : * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 : * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 : * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 : */
20 :
21 : #include "bpfilter.h"
22 :
23 : #include <sys/param.h>
24 : #include <sys/systm.h>
25 : #include <sys/errno.h>
26 : #include <sys/mbuf.h>
27 : #include <sys/socket.h>
28 : #include <sys/sockio.h>
29 : #include <sys/selinfo.h>
30 : #include <sys/stdint.h>
31 : #include <sys/time.h>
32 : #include <sys/pool.h>
33 : #include <sys/syslog.h>
34 :
35 : #include <net/if.h>
36 : #include <netinet/in.h>
37 : #include <netinet/ip.h>
38 : #include <netinet/ip6.h>
39 : #include <netinet/udp.h>
40 : #include <netinet/tcp.h>
41 : #include <netinet/ip_icmp.h>
42 : #include <netinet/icmp6.h>
43 : #include <netinet6/nd6.h>
44 : #include <netinet/if_ether.h>
45 : #include <net/if_bridge.h>
46 : #include <net/if_switch.h>
47 : #include <net/if_vlan_var.h>
48 : #include <net/ofp.h>
49 :
50 : #if NBPFILTER > 0
51 : #include <net/bpf.h>
52 : #endif
53 :
54 : /*
55 : * Per-frame debugging can be done at any time using the BPF
56 : * hook of DLT_OPENFLOW (eg. tcpdump -y openflow -i switch0)
57 : */
58 : #ifdef DEBUG
59 : #define DPRINTF(__sc, ...) \
60 : do { \
61 : struct switch_softc *_sc = __sc; \
62 : log(LOG_DEBUG, "%s: ", _sc->sc_if.if_xname); \
63 : addlog(__VA_ARGS__); \
64 : } while(/*CONSTCOND*/0)
65 : #else
66 : #define DPRINTF(__sc, ...) do {} while(0)
67 : #endif
68 :
69 : struct swofp_flow_entry {
70 : uint64_t swfe_cookie;
71 : uint16_t swfe_priority;
72 : uint8_t swfe_table_id;
73 : struct ofp_match *swfe_match;
74 : LIST_ENTRY(swofp_flow_entry) swfe_next;
75 : uint64_t swfe_packet_cnt;
76 : uint64_t swfe_byte_cnt;
77 : struct ofp_instruction_goto_table *swfe_goto_table;
78 : struct ofp_instruction_write_metadata *swfe_write_metadata;
79 : struct ofp_instruction_actions *swfe_write_actions;
80 : struct ofp_instruction_actions *swfe_apply_actions;
81 : struct ofp_instruction_actions *swfe_clear_actions;
82 : struct ofp_instruction_meter *swfe_meter;
83 : struct ofp_instruction_experimenter *swfe_experimenter;
84 : struct timespec swfe_installed_time;
85 : struct timespec swfe_idle_time;
86 : uint16_t swfe_idle_timeout;
87 : uint16_t swfe_hard_timeout;
88 : uint16_t swfe_flags;
89 : int swfe_tablemiss;
90 : };
91 :
92 : struct swofp_flow_table {
93 : uint32_t swft_table_id;
94 : TAILQ_ENTRY(swofp_flow_table) swft_table_next;
95 : uint64_t swft_lookup_count;
96 : uint64_t swft_matched_count;
97 : LIST_HEAD(, swofp_flow_entry) swft_flow_list;
98 : uint32_t swft_flow_num;
99 : };
100 :
101 : struct swofp_group_entry {
102 : uint32_t swge_group_id;
103 : LIST_ENTRY(swofp_group_entry) swge_next;
104 : uint64_t swge_packet_count;
105 : uint64_t swge_byte_count;
106 : uint32_t swge_ref_count;
107 : uint8_t swge_type;
108 : uint32_t swge_buckets_len;
109 : struct ofp_bucket *swge_buckets;
110 : struct ofp_bucket_counter *swge_bucket_counter; /* XXX */
111 : struct timespec swge_installed_time;
112 : };
113 :
114 : struct swofp_action_set {
115 : uint16_t swas_type;
116 : struct ofp_action_header *swas_action;
117 : };
118 :
119 : /* Same as total number of OFP_ACTION_ */
120 : #define SWOFP_ACTION_SET_MAX 18
121 : struct swofp_pipeline_desc {
122 : uint32_t swpld_table_id;
123 : uint64_t swpld_cookie;
124 : uint64_t swpld_metadata;
125 : struct switch_flow_classify *swpld_swfcl;
126 : struct switch_flow_classify swpld_pre_swfcl;
127 : struct switch_fwdp_queue swpld_fwdp_q;
128 : struct swofp_action_set swpld_action_set[SWOFP_ACTION_SET_MAX];
129 : struct ofp_action_header *swpld_set_fields[OFP_XM_T_MAX];
130 : int swpld_tablemiss;
131 : };
132 :
133 : struct swofp_ofs {
134 : /* There are parameters by OpenFlow */
135 : uint32_t swofs_xidnxt;
136 : uint64_t swofs_datapath_id;
137 : struct ofp_switch_config swofs_switch_config;
138 : struct timeout swofs_flow_timeout;
139 : uint32_t swofs_flow_max_entry;
140 : TAILQ_HEAD(, swofp_flow_table) swofs_table_list;
141 : uint32_t swofs_group_max_table;
142 : int swofs_group_table_num;
143 : LIST_HEAD(, swofp_group_entry) swofs_group_table;
144 : int (*swofp_cp_init)(struct switch_softc *);
145 : };
146 :
147 : struct swofp_mpmsg {
148 : struct mbuf *swmp_hdr;
149 : struct mbuf_list swmp_body;
150 : };
151 : #define SWOFP_MPMSG_MAX 0xffef
152 :
153 : typedef int (*ofp_msg_handler)(struct switch_softc *, struct mbuf *);
154 :
155 : void swofp_forward_ofs(struct switch_softc *, struct switch_flow_classify *,
156 : struct mbuf *);
157 :
158 : int swofp_input(struct switch_softc *, struct mbuf *);
159 : int swofp_output(struct switch_softc *, struct mbuf *);
160 : void swofp_timer(void *);
161 :
162 : struct ofp_oxm_class
163 : *swofp_lookup_oxm_handler(struct ofp_ox_match *);
164 : ofp_msg_handler
165 : swofp_lookup_msg_handler(uint8_t);
166 : ofp_msg_handler
167 : swofp_lookup_mpmsg_handler(uint16_t);
168 : struct ofp_action_handler
169 : *swofp_lookup_action_handler(uint16_t);
170 : ofp_msg_handler
171 : *swofp_flow_mod_lookup_handler(uint8_t);
172 : struct swofp_pipeline_desc
173 : *swofp_pipeline_desc_create(struct switch_flow_classify *);
174 : void swofp_pipeline_desc_destroy(struct swofp_pipeline_desc *);
175 : int swofp_flow_match_by_swfcl(struct ofp_match *,
176 : struct switch_flow_classify *);
177 : struct swofp_flow_entry
178 : *swofp_flow_lookup(struct swofp_flow_table *,
179 : struct switch_flow_classify *);
180 :
181 : /*
182 : * Flow table
183 : */
184 : struct swofp_flow_table
185 : *swofp_flow_table_lookup(struct switch_softc *, uint16_t);
186 : struct swofp_flow_table
187 : *swofp_flow_table_add(struct switch_softc *, uint16_t);
188 : int swofp_flow_table_delete(struct switch_softc *, uint16_t);
189 : void swofp_flow_table_delete_all(struct switch_softc *);
190 : void swofp_flow_delete_on_table_by_group(struct switch_softc *,
191 : struct swofp_flow_table *, uint32_t);
192 : void swofp_flow_delete_on_table(struct switch_softc *,
193 : struct swofp_flow_table *, struct ofp_match *, uint16_t,
194 : uint64_t, uint64_t cookie_mask, uint32_t,
195 : uint32_t, int);
196 :
197 : /*
198 : * Group table
199 : */
200 : struct swofp_group_entry
201 : *swofp_group_entry_lookup(struct switch_softc *, uint32_t);
202 : int swofp_group_entry_add(struct switch_softc *,
203 : struct swofp_group_entry *);
204 : int swofp_group_entry_delete(struct switch_softc *,
205 : struct swofp_group_entry *);
206 : int swofp_group_entry_delete_all(struct switch_softc *);
207 : int swofp_validate_buckets(struct switch_softc *, struct mbuf *, uint8_t,
208 : uint16_t *, uint16_t *);
209 :
210 : /*
211 : * Flow entry
212 : */
213 : int swofp_flow_entry_put_instructions(struct switch_softc *,
214 : struct mbuf *, struct swofp_flow_entry *, uint16_t *, uint16_t *);
215 : void swofp_flow_entry_table_free(struct ofp_instruction **);
216 : void swofp_flow_entry_instruction_free(struct swofp_flow_entry *);
217 : void swofp_flow_entry_free(struct swofp_flow_entry **);
218 : void swofp_flow_entry_add(struct switch_softc *, struct swofp_flow_table *,
219 : struct swofp_flow_entry *);
220 : void swofp_flow_entry_delete(struct switch_softc *,
221 : struct swofp_flow_table *, struct swofp_flow_entry *, uint8_t);
222 : int swofp_flow_mod_cmd_common_modify(struct switch_softc *,
223 : struct mbuf *, int );
224 : int swofp_flow_cmp_non_strict(struct swofp_flow_entry *,
225 : struct ofp_match *);
226 : int swofp_flow_cmp_strict(struct swofp_flow_entry *, struct ofp_match *,
227 : uint32_t);
228 : int swofp_flow_cmp_common(struct swofp_flow_entry *,
229 : struct ofp_match *, int);
230 : struct swofp_flow_entry
231 : *swofp_flow_search_by_table(struct swofp_flow_table *,
232 : struct ofp_match *, uint16_t);
233 : int swofp_flow_has_group(struct ofp_instruction_actions *, uint32_t);
234 : int swofp_flow_filter_out_port(struct ofp_instruction_actions *,
235 : uint32_t);
236 : int swofp_flow_filter(struct swofp_flow_entry *, uint64_t, uint64_t,
237 : uint32_t, uint32_t);
238 : void swofp_flow_timeout(struct switch_softc *);
239 : int swofp_validate_oxm(struct ofp_ox_match *, uint16_t *);
240 : int swofp_validate_flow_match(struct ofp_match *, uint16_t *);
241 : int swofp_validate_flow_instruction(struct switch_softc *,
242 : struct ofp_instruction *, size_t, uint16_t *, uint16_t *);
243 : int swofp_validate_action(struct switch_softc *sc,
244 : struct ofp_action_header *, size_t, uint16_t *);
245 :
246 : /*
247 : * OpenFlow protocol compare oxm
248 : */
249 : int swofp_ox_cmp_data(struct ofp_ox_match *,
250 : struct ofp_ox_match *, int);
251 : int swofp_ox_cmp_ipv6_addr(struct ofp_ox_match *,
252 : struct ofp_ox_match *, int);
253 : int swofp_ox_cmp_ipv4_addr(struct ofp_ox_match *,
254 : struct ofp_ox_match *, int);
255 : int swofp_ox_cmp_vlan_vid(struct ofp_ox_match *,
256 : struct ofp_ox_match *, int);
257 : int swofp_ox_cmp_ether_addr(struct ofp_ox_match *,
258 : struct ofp_ox_match *, int);
259 : /*
260 : * OpenFlow protocol match field handlers
261 : */
262 : int swofp_ox_match_ether_addr(struct switch_flow_classify *,
263 : struct ofp_ox_match *);
264 : int swofp_ox_match_vlan_vid(struct switch_flow_classify *,
265 : struct ofp_ox_match *);
266 : int swofp_ox_match_ipv6_addr(struct switch_flow_classify *,
267 : struct ofp_ox_match *);
268 : int swofp_ox_match_ipv4_addr(struct switch_flow_classify *,
269 : struct ofp_ox_match *);
270 : int swofp_ox_match_uint8(struct switch_flow_classify *,
271 : struct ofp_ox_match *);
272 : int swofp_ox_match_uint16(struct switch_flow_classify *,
273 : struct ofp_ox_match *);
274 : int swofp_ox_match_uint32(struct switch_flow_classify *,
275 : struct ofp_ox_match *);
276 : int swofp_ox_match_uint64(struct switch_flow_classify *,
277 : struct ofp_ox_match *);
278 :
279 : void swofp_ox_match_put_start(struct ofp_match *);
280 : int swofp_ox_match_put_end(struct ofp_match *);
281 : int swofp_ox_match_put_uint32(struct ofp_match *, uint8_t, uint32_t);
282 : int swofp_ox_match_put_uint64(struct ofp_match *, uint8_t, uint64_t);
283 : int swofp_nx_match_put(struct ofp_match *, uint8_t, int, caddr_t);
284 :
285 : /*
286 : * OpenFlow protocol push/pop tag action handlers
287 : */
288 : struct mbuf
289 : *swofp_action_push_vlan(struct switch_softc *, struct mbuf *,
290 : struct swofp_pipeline_desc *, struct ofp_action_header *);
291 : struct mbuf
292 : *swofp_action_pop_vlan(struct switch_softc *, struct mbuf *,
293 : struct swofp_pipeline_desc *, struct ofp_action_header *);
294 : struct mbuf
295 : *swofp_expand_8021q_tag(struct mbuf *);
296 :
297 : /*
298 : * OpenFlow protocol set field action handlers
299 : */
300 : struct mbuf
301 : *swofp_apply_set_field_udp(struct mbuf *, int,
302 : struct switch_flow_classify *, struct switch_flow_classify *);
303 : struct mbuf
304 : *swofp_apply_set_field_tcp(struct mbuf *, int,
305 : struct switch_flow_classify *, struct switch_flow_classify *);
306 : struct mbuf
307 : *swofp_apply_set_field_nd6(struct mbuf *, int,
308 : struct switch_flow_classify *, struct switch_flow_classify *);
309 : struct mbuf
310 : *swofp_apply_set_field_icmpv6(struct mbuf *m, int,
311 : struct switch_flow_classify *, struct switch_flow_classify *);
312 : struct mbuf
313 : *swofp_apply_set_field_icmpv4(struct mbuf *, int,
314 : struct switch_flow_classify *, struct switch_flow_classify *);
315 : struct mbuf
316 : *swofp_apply_set_field_ipv6(struct mbuf *, int,
317 : struct switch_flow_classify *, struct switch_flow_classify *);
318 : struct mbuf
319 : *swofp_apply_set_field_ipv4(struct mbuf *, int,
320 : struct switch_flow_classify *, struct switch_flow_classify *);
321 : struct mbuf
322 : *swofp_apply_set_field_arp(struct mbuf *, int,
323 : struct switch_flow_classify *, struct switch_flow_classify *);
324 : struct mbuf
325 : *swofp_apply_set_field_ether(struct mbuf *, int,
326 : struct switch_flow_classify *, struct switch_flow_classify *);
327 : struct mbuf
328 : *swofp_apply_set_field_tunnel(struct mbuf *, int,
329 : struct switch_flow_classify *, struct switch_flow_classify *);
330 : struct mbuf
331 : *swofp_apply_set_field(struct mbuf *, struct swofp_pipeline_desc *);
332 : int swofp_ox_set_vlan_vid(struct switch_flow_classify *,
333 : struct ofp_ox_match *);
334 : int swofp_ox_set_uint8(struct switch_flow_classify *,
335 : struct ofp_ox_match *);
336 : int swofp_ox_set_uint16(struct switch_flow_classify *,
337 : struct ofp_ox_match *);
338 : int swofp_ox_set_uint32(struct switch_flow_classify *,
339 : struct ofp_ox_match *);
340 : int swofp_ox_set_uint64(struct switch_flow_classify *,
341 : struct ofp_ox_match *);
342 : int swofp_ox_set_ether_addr(struct switch_flow_classify *,
343 : struct ofp_ox_match *);
344 : int swofp_ox_set_ipv4_addr(struct switch_flow_classify *,
345 : struct ofp_ox_match *);
346 : int swofp_ox_set_ipv6_addr(struct switch_flow_classify *,
347 : struct ofp_ox_match *);
348 :
349 : /*
350 : * OpenFlow protocol execute action handlers
351 : */
352 : int swofp_action_output_controller(struct switch_softc *, struct mbuf *,
353 : struct swofp_pipeline_desc *, uint16_t, uint8_t);
354 : struct mbuf
355 : *swofp_action_output(struct switch_softc *, struct mbuf *,
356 : struct swofp_pipeline_desc *, struct ofp_action_header *);
357 : struct mbuf
358 : *swofp_action_group_all(struct switch_softc *, struct mbuf *,
359 : struct swofp_pipeline_desc *, struct swofp_group_entry *);
360 : struct mbuf
361 : *swofp_action_group(struct switch_softc *, struct mbuf *,
362 : struct swofp_pipeline_desc *, struct ofp_action_header *);
363 : struct mbuf
364 : *swofp_action_set_field(struct switch_softc *, struct mbuf *,
365 : struct swofp_pipeline_desc *, struct ofp_action_header *);
366 : struct mbuf
367 : *swofp_execute_action(struct switch_softc *, struct mbuf *,
368 : struct swofp_pipeline_desc *, struct ofp_action_header *);
369 : struct mbuf
370 : *swofp_execute_action_set_field(struct switch_softc *, struct mbuf *,
371 : struct swofp_pipeline_desc *, struct ofp_action_header *);
372 : struct mbuf
373 : *swofp_execute_action_set(struct switch_softc *, struct mbuf *,
374 : struct swofp_pipeline_desc *);
375 : struct mbuf
376 : *swofp_apply_actions(struct switch_softc *, struct mbuf *,
377 : struct swofp_pipeline_desc *, struct ofp_instruction_actions *);
378 : struct swofp_action_set
379 : *swofp_lookup_action_set(struct swofp_pipeline_desc *, uint16_t);
380 : void swofp_write_actions_set_field(struct swofp_action_set *,
381 : struct ofp_action_header *);
382 : int swofp_write_actions(struct ofp_instruction_actions *,
383 : struct swofp_pipeline_desc *);
384 : void swofp_clear_actions_set_field(struct swofp_action_set *,
385 : struct ofp_action_header *);
386 : int swofp_clear_actions(struct ofp_instruction_actions *,
387 : struct swofp_pipeline_desc *);
388 : void swofp_write_metadata(struct ofp_instruction_write_metadata *,
389 : struct swofp_pipeline_desc *);
390 :
391 : /*
392 : * OpenFlow protocol message handlers
393 : */
394 : void swofp_send_hello(struct switch_softc *);
395 : int swofp_recv_hello(struct switch_softc *, struct mbuf *);
396 : int swofp_send_echo(struct switch_softc *, struct mbuf *);
397 : int swofp_recv_echo(struct switch_softc *, struct mbuf *);
398 : void swofp_send_error(struct switch_softc *, struct mbuf *,
399 : uint16_t, uint16_t);
400 : int swofp_recv_features_req(struct switch_softc *, struct mbuf *);
401 : int swofp_recv_config_req(struct switch_softc *, struct mbuf *);
402 : int swofp_recv_set_config(struct switch_softc *, struct mbuf *);
403 : int swofp_send_flow_removed(struct switch_softc *,
404 : struct swofp_flow_entry *, uint8_t);
405 : int swofp_recv_packet_out(struct switch_softc *, struct mbuf *);
406 : int swofp_flow_mod_cmd_add(struct switch_softc *, struct mbuf *);
407 : int swofp_flow_mod_cmd_common_modify(struct switch_softc *,
408 : struct mbuf *, int);
409 : int swofp_flow_mod_cmd_modify(struct switch_softc *, struct mbuf *);
410 : int swofp_flow_mod_cmd_modify_strict(struct switch_softc *, struct mbuf *);
411 : int swofp_flow_mod_cmd_common_delete(struct switch_softc *,
412 : struct mbuf *, int);
413 : int swofp_flow_mod_cmd_delete(struct switch_softc *, struct mbuf *);
414 : int swofp_flow_mod_cmd_delete_strict(struct switch_softc *, struct mbuf *);
415 : int swofp_flow_mod(struct switch_softc *, struct mbuf *);
416 : int swofp_group_mod_add(struct switch_softc *, struct mbuf *);
417 : int swofp_group_mod_modify(struct switch_softc *, struct mbuf *);
418 : int swofp_group_mod_delete(struct switch_softc *, struct mbuf *);
419 : int swofp_group_mod(struct switch_softc *, struct mbuf *);
420 : int swofp_multipart_req(struct switch_softc *, struct mbuf *);
421 : int swofp_barrier_req(struct switch_softc *, struct mbuf *);
422 : void swofp_barrier_reply(struct switch_softc *, struct mbuf *);
423 :
424 : /*
425 : * OpenFlow protocol multipart message handlers
426 : */
427 : int swofp_mpmsg_reply_create(struct ofp_multipart *, struct swofp_mpmsg *);
428 : int swofp_mpmsg_put(struct swofp_mpmsg *, caddr_t, size_t);
429 : int swofp_mpmsg_m_put(struct swofp_mpmsg *, struct mbuf *);
430 : void swofp_mpmsg_destroy(struct swofp_mpmsg *);
431 : int swofp_multipart_reply(struct switch_softc *, struct swofp_mpmsg *);
432 :
433 : int swofp_put_flow(struct mbuf *, struct swofp_flow_table *,
434 : struct swofp_flow_entry *);
435 : int swofp_put_flows_from_table(struct swofp_mpmsg *,
436 : struct swofp_flow_table *, struct ofp_flow_stats_request *);
437 : void swofp_aggregate_stat_from_table(struct ofp_aggregate_stats *,
438 : struct swofp_flow_table *, struct ofp_aggregate_stats_request *);
439 : int swofp_table_features_put_oxm(struct mbuf *, int *, uint16_t);
440 : int swofp_table_features_put_actions(struct mbuf *, int *, uint16_t);
441 : int swofp_table_features_put_instruction(struct mbuf *, int *, uint16_t);
442 :
443 : int swofp_mp_recv_desc(struct switch_softc *, struct mbuf *);
444 : int swofp_mp_recv_flow(struct switch_softc *, struct mbuf *);
445 : int swofp_mp_recv_aggregate_flow_stat(struct switch_softc *, struct mbuf *);
446 : int swofp_mp_recv_table_stats(struct switch_softc *, struct mbuf *);
447 : int swofp_mp_recv_table_features(struct switch_softc *, struct mbuf *);
448 : int swofp_mp_recv_port_stats(struct switch_softc *, struct mbuf *);
449 : int swofp_mp_recv_port_desc(struct switch_softc *, struct mbuf *);
450 : int swofp_mp_recv_group_desc(struct switch_softc *, struct mbuf *);
451 :
452 : #define OFP_ALIGNMENT 8
453 : /*
454 : * OXM (OpenFlow Extensible Match) structures appear in ofp_match structure
455 : * and ofp_instruction_{apply|write}_action structure.
456 : */
457 : #define OFP_OXM_FOREACH(hdr, len, curr) \
458 : for ((curr) = (struct ofp_ox_match *)((caddr_t)(hdr) + sizeof(*hdr)); \
459 : (caddr_t)(curr) < ((caddr_t)(hdr) + (len)); \
460 : (curr) = (struct ofp_ox_match *)((caddr_t)(curr) + \
461 : (curr)->oxm_length + sizeof(*curr)))
462 :
463 : #define OFP_OXM_TERMINATED(hdr, len, curr) \
464 : (((caddr_t)(hdr) + (len)) <= (caddr_t)(curr))
465 :
466 :
467 : #define OFP_ACTION_FOREACH(head, len, curr) \
468 : /* struct ofp_action_header head, curr */ \
469 : for ((curr) = (head); (caddr_t)curr < ((caddr_t)head + (len)); \
470 : (curr) = (struct ofp_action_header *)((caddr_t)curr + \
471 : ntohs((curr)->ah_len)))
472 :
473 : /*
474 : * Get instruction offset in ofp_flow_mod
475 : */
476 : #define OFP_FLOW_MOD_MSG_INSTRUCTION_OFFSET(ofm) \
477 : (offsetof(struct ofp_flow_mod, fm_match) + \
478 : OFP_ALIGN(ntohs((ofm)->fm_match.om_length)))
479 :
480 : /*
481 : * Instructions "FOREACH" in ofp_flow_mod. You can get header using
482 : * OFP_FLOW_MOD_MSG_INSTRUCTION_PTR macro
483 : */
484 : #define OFP_FLOW_MOD_INSTRUCTON_FOREACH(hadr, end, curr) \
485 : for ((curr) = (head); (caddr_t)curr < ((caddr_t)head + (end)); \
486 : (curr) = (struct ofp_instruction *)((caddr_t)(curr) + (curr)->i_len))
487 :
488 :
489 : #define OFP_I_ACTIONS_FOREACH(head, curr) \
490 : /* struct ofp_match head, struct ofp_ox_match curr */ \
491 : for ((curr) = (struct ofp_action_header *)((caddr_t)head + sizeof(*head)); \
492 : (caddr_t)curr < ((caddr_t)head + ntohs((head)->ia_len)); \
493 : (curr) = (struct ofp_action_header *)((caddr_t)curr + \
494 : ntohs((curr)->ah_len)))
495 :
496 : #define OFP_BUCKETS_FOREACH(head, end, curr) \
497 : for ((curr) = (head); (caddr_t)curr < ((caddr_t)head + (end)); \
498 : (curr) = (struct ofp_bucket *)((caddr_t)(curr) + ntohs((curr)->b_len)))
499 :
500 :
501 : /*
502 : * OpenFlow protocol message handlers
503 : */
504 : struct ofp_msg_class {
505 : uint8_t msg_type;
506 : ofp_msg_handler msg_handler;
507 : };
508 : struct ofp_msg_class ofp_msg_table[] = {
509 : { OFP_T_HELLO, swofp_recv_hello },
510 : { OFP_T_ERROR, NULL /* unsupported */ },
511 : { OFP_T_ECHO_REQUEST, swofp_recv_echo },
512 : { OFP_T_ECHO_REPLY, NULL /* from switch */ },
513 : { OFP_T_EXPERIMENTER, NULL /* unsupported */ },
514 : { OFP_T_FEATURES_REQUEST, swofp_recv_features_req },
515 : { OFP_T_FEATURES_REPLY, NULL /* from switch */ },
516 : { OFP_T_GET_CONFIG_REQUEST, swofp_recv_config_req },
517 : { OFP_T_GET_CONFIG_REPLY, NULL /* from switch */ },
518 : { OFP_T_SET_CONFIG, swofp_recv_set_config },
519 : { OFP_T_PACKET_IN, NULL /* from switch */ },
520 : { OFP_T_FLOW_REMOVED, NULL /* from switch */ },
521 : { OFP_T_PORT_STATUS, NULL /* from switch */ },
522 : { OFP_T_PACKET_OUT, swofp_recv_packet_out },
523 : { OFP_T_FLOW_MOD, swofp_flow_mod },
524 : { OFP_T_GROUP_MOD, swofp_group_mod },
525 : { OFP_T_PORT_MOD, NULL /* unsupported */ },
526 : { OFP_T_TABLE_MOD, NULL /* unsupported */ },
527 : { OFP_T_MULTIPART_REQUEST, swofp_multipart_req },
528 : { OFP_T_MULTIPART_REPLY, NULL /* from switch */ },
529 : { OFP_T_BARRIER_REQUEST, swofp_barrier_req },
530 : { OFP_T_BARRIER_REPLY, NULL /* from switch */ },
531 : { OFP_T_QUEUE_GET_CONFIG_REQUEST, NULL /* unsupported */ },
532 : { OFP_T_QUEUE_GET_CONFIG_REPLY, NULL /* from switch */ },
533 : { OFP_T_ROLE_REQUEST, NULL /* unsupported */ },
534 : { OFP_T_ROLE_REPLY, NULL /* from switch */ },
535 : { OFP_T_GET_ASYNC_REQUEST, NULL /* unsupported */ },
536 : { OFP_T_GET_ASYNC_REPLY, NULL /* from switch */ },
537 : { OFP_T_SET_ASYNC, NULL /* unsupported */ },
538 : { OFP_T_METER_MOD, NULL /* unsupported */ }
539 : };
540 :
541 :
542 : /*
543 : * OpenFlow protocol modification flow message command handlers
544 : */
545 : struct ofp_flow_mod_class {
546 : uint8_t ofm_cmd_type;
547 : ofp_msg_handler ofm_cmd_handler;
548 : };
549 : struct ofp_flow_mod_class ofp_flow_mod_table[] = {
550 : { OFP_FLOWCMD_ADD, swofp_flow_mod_cmd_add },
551 : { OFP_FLOWCMD_MODIFY, swofp_flow_mod_cmd_modify },
552 : { OFP_FLOWCMD_MODIFY_STRICT, swofp_flow_mod_cmd_modify_strict },
553 : { OFP_FLOWCMD_DELETE, swofp_flow_mod_cmd_delete },
554 : { OFP_FLOWCMD_DELETE_STRICT, swofp_flow_mod_cmd_delete_strict },
555 : };
556 :
557 : /*
558 : * OpenFlow protocol multipart handlers
559 : */
560 : struct ofp_mpmsg_class {
561 : uint8_t msgsg_type;
562 : ofp_msg_handler mpmsg_handler;
563 : };
564 : struct ofp_mpmsg_class ofp_mpmsg_table[] = {
565 : { OFP_MP_T_DESC, swofp_mp_recv_desc },
566 : { OFP_MP_T_FLOW, swofp_mp_recv_flow },
567 : { OFP_MP_T_AGGREGATE, swofp_mp_recv_aggregate_flow_stat },
568 : { OFP_MP_T_TABLE, swofp_mp_recv_table_stats },
569 : { OFP_MP_T_PORT_STATS, swofp_mp_recv_port_stats },
570 : { OFP_MP_T_QUEUE, NULL },
571 : { OFP_MP_T_GROUP, NULL },
572 : { OFP_MP_T_GROUP_DESC, swofp_mp_recv_group_desc },
573 : { OFP_MP_T_GROUP_FEATURES, NULL },
574 : { OFP_MP_T_METER, NULL },
575 : { OFP_MP_T_METER_CONFIG, NULL },
576 : { OFP_MP_T_METER_FEATURES, NULL },
577 : { OFP_MP_T_TABLE_FEATURES, swofp_mp_recv_table_features },
578 : { OFP_MP_T_PORT_DESC, swofp_mp_recv_port_desc }
579 : };
580 :
581 : /*
582 : * OpenFlow OXM match handlers
583 : */
584 : #define SWOFP_MATCH_MASK 0x1
585 : #define SWOFP_MATCH_WILDCARD 0x2
586 :
587 : struct ofp_oxm_class {
588 : uint8_t oxm_field;
589 : uint8_t oxm_len; /* This length defined by speficication */
590 : uint8_t oxm_flags;
591 : int (*oxm_match)(struct switch_flow_classify *,
592 : struct ofp_ox_match *);
593 : int (*oxm_set)(struct switch_flow_classify *,
594 : struct ofp_ox_match *);
595 : int (*oxm_cmp)(struct ofp_ox_match *,
596 : struct ofp_ox_match *, int);
597 : };
598 :
599 : /*
600 : * Handlers for basic class for OpenFlow
601 : */
602 : struct ofp_oxm_class ofp_oxm_handlers[] = {
603 : {
604 : OFP_XM_T_IN_PORT,
605 : sizeof(uint32_t),
606 : 0,
607 : swofp_ox_match_uint32, NULL,
608 : swofp_ox_cmp_data
609 : },
610 : {
611 : OFP_XM_T_IN_PHY_PORT,
612 : sizeof(uint32_t),
613 : 0,
614 : NULL, NULL,
615 : NULL
616 : },
617 : {
618 : OFP_XM_T_META,
619 : sizeof(uint64_t),
620 : SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD,
621 : swofp_ox_match_uint64, NULL,
622 : NULL
623 : },
624 : {
625 : OFP_XM_T_ETH_DST,
626 : ETHER_ADDR_LEN,
627 : SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD,
628 : swofp_ox_match_ether_addr, swofp_ox_set_ether_addr,
629 : swofp_ox_cmp_ether_addr
630 : },
631 : {
632 : OFP_XM_T_ETH_SRC,
633 : ETHER_ADDR_LEN,
634 : SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD,
635 : swofp_ox_match_ether_addr, swofp_ox_set_ether_addr,
636 : swofp_ox_cmp_ether_addr
637 : },
638 : {
639 : OFP_XM_T_ETH_TYPE,
640 : sizeof(uint16_t),
641 : SWOFP_MATCH_WILDCARD,
642 : swofp_ox_match_uint16, swofp_ox_set_uint16,
643 : swofp_ox_cmp_data
644 : },
645 : {
646 : OFP_XM_T_VLAN_VID,
647 : sizeof(uint16_t),
648 : SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD,
649 : swofp_ox_match_vlan_vid, swofp_ox_set_vlan_vid,
650 : swofp_ox_cmp_vlan_vid
651 : },
652 : {
653 : OFP_XM_T_VLAN_PCP,
654 : sizeof(uint8_t),
655 : SWOFP_MATCH_WILDCARD,
656 : swofp_ox_match_uint8, swofp_ox_set_uint16,
657 : swofp_ox_cmp_data
658 : },
659 : {
660 : OFP_XM_T_IP_DSCP,
661 : sizeof(uint8_t),
662 : SWOFP_MATCH_WILDCARD,
663 : swofp_ox_match_uint8, swofp_ox_set_uint8,
664 : swofp_ox_cmp_data
665 : },
666 : {
667 : OFP_XM_T_IP_ECN,
668 : sizeof(uint8_t),
669 : SWOFP_MATCH_WILDCARD,
670 : swofp_ox_match_uint8, swofp_ox_set_uint8,
671 : swofp_ox_cmp_data
672 : },
673 : {
674 : OFP_XM_T_IP_PROTO,
675 : sizeof(uint8_t),
676 : SWOFP_MATCH_WILDCARD,
677 : swofp_ox_match_uint8, swofp_ox_set_uint8,
678 : swofp_ox_cmp_data
679 : },
680 : {
681 : OFP_XM_T_IPV4_SRC,
682 : sizeof(uint32_t),
683 : SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD,
684 : swofp_ox_match_ipv4_addr, swofp_ox_set_ipv4_addr,
685 : swofp_ox_cmp_ipv4_addr
686 : },
687 : {
688 : OFP_XM_T_IPV4_DST,
689 : sizeof(uint32_t),
690 : SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD,
691 : swofp_ox_match_ipv4_addr, swofp_ox_set_ipv4_addr,
692 : swofp_ox_cmp_ipv4_addr
693 : },
694 : {
695 : OFP_XM_T_TCP_SRC,
696 : sizeof(uint16_t),
697 : SWOFP_MATCH_WILDCARD,
698 : swofp_ox_match_uint16, swofp_ox_set_uint16,
699 : swofp_ox_cmp_data
700 : },
701 : {
702 : OFP_XM_T_TCP_DST,
703 : sizeof(uint16_t),
704 : SWOFP_MATCH_WILDCARD,
705 : swofp_ox_match_uint16, swofp_ox_set_uint16,
706 : swofp_ox_cmp_data
707 : },
708 : {
709 : OFP_XM_T_UDP_SRC,
710 : sizeof(uint16_t),
711 : SWOFP_MATCH_WILDCARD,
712 : swofp_ox_match_uint16, swofp_ox_set_uint16,
713 : swofp_ox_cmp_data
714 : },
715 : {
716 : OFP_XM_T_UDP_DST,
717 : sizeof(uint16_t),
718 : SWOFP_MATCH_WILDCARD,
719 : swofp_ox_match_uint16, swofp_ox_set_uint16,
720 : swofp_ox_cmp_data
721 : },
722 : {
723 : OFP_XM_T_SCTP_SRC,
724 : sizeof(uint16_t),
725 : SWOFP_MATCH_WILDCARD,
726 : swofp_ox_match_uint16, swofp_ox_set_uint16,
727 : swofp_ox_cmp_data
728 : },
729 : {
730 : OFP_XM_T_SCTP_DST,
731 : sizeof(uint16_t),
732 : SWOFP_MATCH_WILDCARD,
733 : swofp_ox_match_uint16, swofp_ox_set_uint16,
734 : swofp_ox_cmp_data
735 : },
736 : {
737 : OFP_XM_T_ICMPV4_TYPE,
738 : sizeof(uint8_t),
739 : SWOFP_MATCH_WILDCARD,
740 : swofp_ox_match_uint8, swofp_ox_set_uint8,
741 : swofp_ox_cmp_data
742 : },
743 : {
744 : OFP_XM_T_ICMPV4_CODE,
745 : sizeof(uint8_t),
746 : SWOFP_MATCH_WILDCARD,
747 : swofp_ox_match_uint8, swofp_ox_set_uint8,
748 : swofp_ox_cmp_data
749 : },
750 : {
751 : OFP_XM_T_ARP_OP,
752 : sizeof(uint16_t),
753 : SWOFP_MATCH_WILDCARD,
754 : swofp_ox_match_uint16, swofp_ox_set_uint16,
755 : swofp_ox_cmp_data
756 : },
757 : {
758 : OFP_XM_T_ARP_SPA,
759 : sizeof(uint32_t),
760 : SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD,
761 : swofp_ox_match_ipv4_addr, swofp_ox_set_ipv4_addr,
762 : swofp_ox_cmp_ipv4_addr
763 : },
764 : {
765 : OFP_XM_T_ARP_TPA,
766 : sizeof(uint32_t),
767 : SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD,
768 : swofp_ox_match_ipv4_addr, swofp_ox_set_ipv4_addr,
769 : swofp_ox_cmp_ipv4_addr
770 : },
771 : {
772 : OFP_XM_T_ARP_SHA,
773 : ETHER_ADDR_LEN,
774 : SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD,
775 : swofp_ox_match_ether_addr, swofp_ox_set_ether_addr,
776 : swofp_ox_cmp_ether_addr
777 : },
778 : {
779 : OFP_XM_T_ARP_THA,
780 : ETHER_ADDR_LEN,
781 : SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD,
782 : swofp_ox_match_ether_addr, swofp_ox_set_ether_addr,
783 : swofp_ox_cmp_ether_addr
784 : },
785 : #ifdef INET6
786 : {
787 : OFP_XM_T_IPV6_SRC,
788 : sizeof(struct in6_addr),
789 : SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD,
790 : swofp_ox_match_ipv6_addr, swofp_ox_set_ipv6_addr,
791 : swofp_ox_cmp_ipv6_addr
792 : },
793 : {
794 : OFP_XM_T_IPV6_DST,
795 : sizeof(struct in6_addr),
796 : SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD,
797 : swofp_ox_match_ipv6_addr, swofp_ox_set_ipv6_addr,
798 : swofp_ox_cmp_ipv6_addr
799 : },
800 : {
801 : OFP_XM_T_IPV6_FLABEL,
802 : sizeof(uint32_t),
803 : SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD,
804 : swofp_ox_match_uint32, swofp_ox_set_uint32,
805 : swofp_ox_cmp_data
806 : },
807 : {
808 : OFP_XM_T_ICMPV6_TYPE,
809 : sizeof(uint8_t),
810 : SWOFP_MATCH_WILDCARD,
811 : swofp_ox_match_uint8, swofp_ox_set_uint8,
812 : swofp_ox_cmp_data
813 : },
814 : {
815 : OFP_XM_T_ICMPV6_CODE,
816 : sizeof(uint8_t),
817 : SWOFP_MATCH_WILDCARD,
818 : swofp_ox_match_uint8, swofp_ox_set_uint8,
819 : swofp_ox_cmp_data
820 : },
821 : {
822 : OFP_XM_T_IPV6_ND_TARGET,
823 : sizeof(struct in6_addr),
824 : SWOFP_MATCH_WILDCARD,
825 : swofp_ox_match_ipv6_addr, swofp_ox_set_ipv6_addr,
826 : swofp_ox_cmp_ipv6_addr
827 : },
828 : {
829 : OFP_XM_T_IPV6_ND_SLL,
830 : ETHER_ADDR_LEN,
831 : SWOFP_MATCH_WILDCARD,
832 : swofp_ox_match_ether_addr, swofp_ox_set_ether_addr,
833 : swofp_ox_cmp_ether_addr
834 : },
835 : {
836 : OFP_XM_T_IPV6_ND_TLL,
837 : ETHER_ADDR_LEN,
838 : SWOFP_MATCH_WILDCARD,
839 : swofp_ox_match_ether_addr, swofp_ox_set_ether_addr,
840 : swofp_ox_cmp_ether_addr
841 : },
842 : #endif /* INET6 */
843 : {
844 : OFP_XM_T_MPLS_LABEL,
845 : sizeof(uint32_t),
846 : SWOFP_MATCH_WILDCARD,
847 : NULL, NULL,
848 : NULL
849 : },
850 : {
851 : OFP_XM_T_MPLS_TC,
852 : sizeof(uint8_t),
853 : SWOFP_MATCH_WILDCARD,
854 : NULL, NULL,
855 : NULL
856 : },
857 : {
858 : OFP_XM_T_MPLS_BOS,
859 : sizeof(uint8_t),
860 : SWOFP_MATCH_WILDCARD,
861 : NULL, NULL,
862 : NULL
863 : },
864 : {
865 : OFP_XM_T_PBB_ISID,
866 : 3,
867 : SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD,
868 : NULL, NULL,
869 : NULL
870 : },
871 : {
872 : OFP_XM_T_TUNNEL_ID,
873 : sizeof(uint64_t),
874 : SWOFP_MATCH_WILDCARD,
875 : swofp_ox_match_uint64, swofp_ox_set_uint64,
876 : swofp_ox_cmp_data
877 : },
878 : {
879 : OFP_XM_T_IPV6_EXTHDR,
880 : sizeof(uint16_t),
881 : SWOFP_MATCH_WILDCARD,
882 : NULL, NULL,
883 : NULL
884 : },
885 : };
886 :
887 : /*
888 : * Handlers for backward compatibility with NXM
889 : */
890 : struct ofp_oxm_class ofp_oxm_nxm_handlers[] = {
891 : {
892 : OFP_XM_NXMT_TUNNEL_ID,
893 : sizeof(uint64_t),
894 : SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD,
895 : swofp_ox_match_uint64, swofp_ox_set_uint64,
896 : swofp_ox_cmp_data
897 : },
898 : {
899 : OFP_XM_NXMT_TUNNEL_IPV4_SRC,
900 : sizeof(uint32_t),
901 : SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD,
902 : swofp_ox_match_ipv4_addr, swofp_ox_set_ipv4_addr,
903 : swofp_ox_cmp_ipv4_addr
904 : },
905 : {
906 : OFP_XM_NXMT_TUNNEL_IPV4_DST,
907 : sizeof(uint32_t),
908 : SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD,
909 : swofp_ox_match_ipv4_addr, swofp_ox_set_ipv4_addr,
910 : swofp_ox_cmp_ipv4_addr
911 : },
912 : #ifdef INET6
913 : {
914 : OFP_XM_NXMT_TUNNEL_IPV6_SRC,
915 : sizeof(struct in6_addr),
916 : SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD,
917 : swofp_ox_match_ipv6_addr, swofp_ox_set_ipv6_addr,
918 : swofp_ox_cmp_ipv6_addr
919 : },
920 : {
921 : OFP_XM_NXMT_TUNNEL_IPV6_DST,
922 : sizeof(struct in6_addr),
923 : SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD,
924 : swofp_ox_match_ipv6_addr, swofp_ox_set_ipv6_addr,
925 : swofp_ox_cmp_ipv6_addr
926 : },
927 : #endif /* INET6 */
928 : };
929 :
930 : /*
931 : * OpenFlow action handlers
932 : */
933 : struct ofp_action_handler {
934 : uint16_t action_type;
935 : struct mbuf * (*action)(struct switch_softc *, struct mbuf *,
936 : struct swofp_pipeline_desc *, struct ofp_action_header *);
937 : };
938 : struct ofp_action_handler ofp_action_handlers[] = {
939 : /*
940 : * Following order complies with action set order in
941 : * OpenFlow Switch Specification (ver. 1.3.5)
942 : */
943 : {
944 : OFP_ACTION_COPY_TTL_IN,
945 : NULL
946 : },
947 : {
948 : OFP_ACTION_POP_MPLS,
949 : NULL
950 : },
951 : {
952 : OFP_ACTION_POP_PBB,
953 : NULL
954 : },
955 : {
956 : OFP_ACTION_POP_VLAN,
957 : swofp_action_pop_vlan
958 : },
959 : {
960 : OFP_ACTION_PUSH_MPLS,
961 : NULL
962 : },
963 : {
964 : OFP_ACTION_PUSH_PBB,
965 : NULL
966 : },
967 : {
968 : OFP_ACTION_PUSH_VLAN,
969 : swofp_action_push_vlan
970 : },
971 : {
972 : OFP_ACTION_COPY_TTL_OUT,
973 : NULL
974 : },
975 : {
976 : OFP_ACTION_DEC_NW_TTL,
977 : NULL
978 : },
979 : {
980 : OFP_ACTION_DEC_MPLS_TTL,
981 : NULL
982 : },
983 : {
984 : OFP_ACTION_SET_MPLS_TTL,
985 : NULL
986 : },
987 : {
988 : OFP_ACTION_SET_NW_TTL,
989 : NULL
990 : },
991 : {
992 : OFP_ACTION_SET_FIELD,
993 : swofp_action_set_field
994 : },
995 : {
996 : OFP_ACTION_SET_QUEUE,
997 : NULL
998 : },
999 : {
1000 : OFP_ACTION_GROUP,
1001 : swofp_action_group
1002 : },
1003 : {
1004 : OFP_ACTION_OUTPUT,
1005 : swofp_action_output
1006 : },
1007 : {
1008 : OFP_ACTION_EXPERIMENTER,
1009 : NULL
1010 : }, /* XXX Where is best position? */
1011 : };
1012 :
1013 : extern struct pool swfcl_pool;
1014 : struct pool swpld_pool;
1015 :
1016 : void
1017 0 : swofp_attach(void)
1018 : {
1019 0 : pool_init(&swpld_pool, sizeof(struct swofp_pipeline_desc), 0, 0, 0,
1020 : "swpld", NULL);
1021 0 : }
1022 :
1023 :
1024 : int
1025 0 : swofp_create(struct switch_softc *sc)
1026 : {
1027 : struct swofp_ofs *swofs;
1028 : int error;
1029 :
1030 0 : swofs = malloc(sizeof(*swofs), M_DEVBUF, M_NOWAIT|M_ZERO);
1031 0 : if (swofs == NULL)
1032 0 : return (ENOMEM);
1033 :
1034 0 : sc->sc_ofs = swofs;
1035 :
1036 0 : TAILQ_INIT(&swofs->swofs_table_list);
1037 :
1038 : /*
1039 : * A table with id 0 must exist
1040 : */
1041 0 : if ((swofp_flow_table_add(sc, 0)) == NULL) {
1042 : error = ENOBUFS;
1043 0 : free(swofs, M_DEVBUF, sizeof(*swofs));
1044 0 : return (error);
1045 : }
1046 :
1047 0 : swofs->swofs_xidnxt = 1;
1048 0 : arc4random_buf(&swofs->swofs_datapath_id,
1049 : sizeof(swofs->swofs_datapath_id));
1050 :
1051 0 : timeout_set(&swofs->swofs_flow_timeout, swofp_timer, sc);
1052 0 : timeout_add_sec(&swofs->swofs_flow_timeout, 10);
1053 :
1054 : /* TODO: Configured from ifconfig */
1055 0 : swofs->swofs_group_max_table = 1000;
1056 0 : swofs->swofs_flow_max_entry = 10000;
1057 :
1058 0 : sc->sc_capabilities |= SWITCH_CAP_OFP;
1059 0 : sc->switch_process_forward = swofp_forward_ofs;
1060 :
1061 : #if NBPFILTER > 0
1062 0 : bpfattach(&sc->sc_ofbpf, &sc->sc_if, DLT_OPENFLOW,
1063 : sizeof(struct ofp_header));
1064 : #endif
1065 :
1066 0 : return (0);
1067 0 : }
1068 :
1069 : void
1070 0 : swofp_destroy(struct switch_softc *sc)
1071 : {
1072 0 : struct swofp_ofs *swofs = sc->sc_ofs;
1073 :
1074 0 : if ((sc->sc_capabilities & SWITCH_CAP_OFP) == 0 || swofs == NULL)
1075 0 : return;
1076 :
1077 0 : timeout_del(&swofs->swofs_flow_timeout);
1078 :
1079 0 : sc->sc_capabilities &= ~SWITCH_CAP_OFP;
1080 0 : sc->switch_process_forward = NULL;
1081 :
1082 0 : swofp_group_entry_delete_all(sc);
1083 :
1084 0 : free(swofs, M_DEVBUF, sizeof(*swofs));
1085 0 : }
1086 :
1087 : int
1088 0 : swofp_init(struct switch_softc *sc)
1089 : {
1090 0 : sc->sc_swdev->swdev_input = swofp_input;
1091 0 : swofp_send_hello(sc);
1092 0 : return (0);
1093 : }
1094 :
1095 : uint32_t
1096 0 : swofp_assign_portno(struct switch_softc *sc, uint32_t req)
1097 : {
1098 : struct switch_port *swpo;
1099 : uint32_t candidate;
1100 :
1101 0 : TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next) {
1102 0 : if (swpo->swpo_port_no == req)
1103 : break;
1104 : }
1105 0 : if (swpo == NULL)
1106 0 : return (req);
1107 :
1108 : /* XXX
1109 : * OS's ifindex is "short", so it expect that floowing is unique
1110 : */
1111 0 : candidate = (req << 16) | req;
1112 0 : while (1) {
1113 0 : TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next) {
1114 0 : if (swpo->swpo_port_no == candidate)
1115 : break;
1116 : }
1117 0 : if (swpo == NULL)
1118 0 : return (candidate);
1119 :
1120 0 : if (candidate < OFP_PORT_MAX)
1121 0 : candidate++;
1122 : else
1123 : candidate = 0;
1124 : }
1125 0 : }
1126 :
1127 : int
1128 0 : swofp_ioctl(struct ifnet *ifp, unsigned long cmd, caddr_t data)
1129 : {
1130 0 : struct switch_softc *sc = ifp->if_softc;
1131 0 : struct swofp_ofs *swofs = sc->sc_ofs;
1132 0 : struct ifbrparam *bparam = (struct ifbrparam *)data;
1133 0 : struct ifbreq *breq = (struct ifbreq *)data;
1134 : struct switch_port *swpo;
1135 : struct ifnet *ifs;
1136 : int error = 0;
1137 :
1138 0 : switch (cmd) {
1139 : case SIOCSWGDPID:
1140 0 : memcpy(&bparam->ifbrp_datapath, &swofs->swofs_datapath_id,
1141 : sizeof(uint64_t));
1142 0 : break;
1143 : case SIOCSWSDPID:
1144 0 : if ((error = suser(curproc)) != 0)
1145 : break;
1146 0 : memcpy(&swofs->swofs_datapath_id, &bparam->ifbrp_datapath,
1147 : sizeof(uint64_t));
1148 0 : break;
1149 : case SIOCSWGMAXFLOW:
1150 0 : bparam->ifbrp_maxflow = swofs->swofs_flow_max_entry;
1151 0 : break;
1152 : case SIOCSWGMAXGROUP:
1153 0 : bparam->ifbrp_maxgroup = swofs->swofs_group_max_table;
1154 0 : break;
1155 : case SIOCSWSPORTNO:
1156 0 : if ((error = suser(curproc)) != 0)
1157 : break;
1158 :
1159 0 : if (breq->ifbr_portno >= OFP_PORT_MAX)
1160 0 : return (EINVAL);
1161 :
1162 0 : if ((ifs = ifunit(breq->ifbr_ifsname)) == NULL)
1163 0 : return (ENOENT);
1164 :
1165 0 : if (ifs->if_switchport == NULL)
1166 0 : return (ENOENT);
1167 :
1168 0 : TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next) {
1169 0 : if (swpo->swpo_port_no == breq->ifbr_portno)
1170 0 : return (EEXIST);
1171 : }
1172 :
1173 0 : swpo = (struct switch_port *)ifs->if_switchport;
1174 0 : swpo->swpo_port_no = breq->ifbr_portno;
1175 :
1176 0 : break;
1177 : default:
1178 : error = ENOTTY;
1179 0 : break;
1180 : }
1181 :
1182 0 : return (error);
1183 0 : }
1184 :
1185 : /* TODO: Optimization */
1186 : struct ofp_oxm_class *
1187 0 : swofp_lookup_oxm_handler(struct ofp_ox_match *oxm)
1188 : {
1189 : struct ofp_oxm_class *handlers;
1190 : uint8_t oxm_field;
1191 : int i, len;
1192 :
1193 0 : switch (ntohs(oxm->oxm_class)) {
1194 : case OFP_OXM_C_OPENFLOW_BASIC:
1195 : handlers = ofp_oxm_handlers;
1196 : len = nitems(ofp_oxm_handlers);
1197 0 : break;
1198 : case OFP_OXM_C_NXM_1:
1199 : handlers = ofp_oxm_nxm_handlers;
1200 : len = nitems(ofp_oxm_nxm_handlers);
1201 0 : break;
1202 : default:
1203 0 : return (NULL);
1204 : }
1205 :
1206 0 : oxm_field = OFP_OXM_GET_FIELD(oxm);
1207 :
1208 0 : for (i = 0; i < len ; i++) {
1209 0 : if (handlers[i].oxm_field == oxm_field)
1210 0 : return (&handlers[i]);
1211 : }
1212 :
1213 0 : return (NULL);
1214 0 : }
1215 :
1216 : ofp_msg_handler
1217 0 : swofp_lookup_msg_handler(uint8_t type)
1218 : {
1219 0 : if (type >= OFP_T_TYPE_MAX)
1220 0 : return (NULL);
1221 : else
1222 0 : return (ofp_msg_table[type].msg_handler);
1223 0 : }
1224 :
1225 : ofp_msg_handler
1226 0 : swofp_lookup_mpmsg_handler(uint16_t type)
1227 : {
1228 0 : if (type >= nitems(ofp_mpmsg_table))
1229 0 : return (NULL);
1230 : else
1231 0 : return (ofp_mpmsg_table[type].mpmsg_handler);
1232 0 : }
1233 :
1234 : struct ofp_action_handler *
1235 0 : swofp_lookup_action_handler(uint16_t type)
1236 : {
1237 : int i;
1238 :
1239 0 : for (i = 0; i < nitems(ofp_action_handlers); i++) {
1240 0 : if (ofp_action_handlers[i].action_type == type)
1241 0 : return &(ofp_action_handlers[i]);
1242 : }
1243 :
1244 0 : return (NULL);
1245 0 : }
1246 :
1247 : struct swofp_pipeline_desc *
1248 0 : swofp_pipeline_desc_create(struct switch_flow_classify *swfcl)
1249 : {
1250 : struct swofp_pipeline_desc *swpld = NULL;
1251 : struct swofp_action_set *swas = NULL;
1252 : int i;
1253 :
1254 0 : swpld = pool_get(&swpld_pool, PR_NOWAIT|PR_ZERO);
1255 0 : if (swpld == NULL)
1256 0 : return (NULL);
1257 :
1258 : /*
1259 : * ofp_action_handlers is sorted by applying action-set order,
1260 : * so it can be used for initializer for action-set.
1261 : */
1262 0 : swas = swpld->swpld_action_set;
1263 0 : for (i = 0; i < nitems(ofp_action_handlers); i++) {
1264 0 : swas[i].swas_type = ofp_action_handlers[i].action_type;
1265 0 : if (swas[i].swas_type == OFP_ACTION_SET_FIELD)
1266 0 : swas[i].swas_action = (struct ofp_action_header *)
1267 0 : swpld->swpld_set_fields;
1268 : else
1269 0 : swas[i].swas_action = NULL;
1270 : }
1271 :
1272 0 : swpld->swpld_swfcl = swfcl;
1273 :
1274 0 : return (swpld);
1275 0 : }
1276 :
1277 : void
1278 0 : swofp_pipeline_desc_destroy(struct swofp_pipeline_desc *swpld)
1279 : {
1280 0 : switch_swfcl_free(&swpld->swpld_pre_swfcl);
1281 0 : pool_put(&swpld_pool, swpld);
1282 0 : }
1283 :
1284 : struct swofp_flow_table *
1285 0 : swofp_flow_table_lookup(struct switch_softc *sc, uint16_t table_id)
1286 : {
1287 0 : struct swofp_ofs *ofs = sc->sc_ofs;
1288 : struct swofp_flow_table *swft;
1289 :
1290 0 : TAILQ_FOREACH(swft, &ofs->swofs_table_list, swft_table_next) {
1291 0 : if (swft->swft_table_id == table_id)
1292 0 : return (swft);
1293 : }
1294 :
1295 0 : return (NULL);
1296 0 : }
1297 :
1298 : struct swofp_flow_table *
1299 0 : swofp_flow_table_add(struct switch_softc *sc, uint16_t table_id)
1300 : {
1301 0 : struct swofp_ofs *ofs = sc->sc_ofs;
1302 : struct swofp_flow_table *swft, *new;
1303 :
1304 0 : if ((swft = swofp_flow_table_lookup(sc, table_id)) != NULL)
1305 0 : return (swft);
1306 :
1307 0 : if ((new = malloc(sizeof(*new), M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL)
1308 0 : return (NULL);
1309 :
1310 0 : new->swft_table_id = table_id;
1311 0 : TAILQ_FOREACH(swft, &ofs->swofs_table_list, swft_table_next) {
1312 0 : if (table_id < swft->swft_table_id)
1313 : break;
1314 : }
1315 :
1316 0 : if (swft)
1317 0 : TAILQ_INSERT_BEFORE(swft, new, swft_table_next);
1318 : else
1319 0 : TAILQ_INSERT_TAIL(&ofs->swofs_table_list, new, swft_table_next);
1320 :
1321 : DPRINTF(sc, "add openflow flow table (id:%d)\n", table_id);
1322 :
1323 0 : return (new);
1324 0 : }
1325 :
1326 : int
1327 0 : swofp_flow_table_delete(struct switch_softc *sc, uint16_t table_id)
1328 : {
1329 0 : struct swofp_ofs *ofs = sc->sc_ofs;
1330 : struct swofp_flow_table *swft;
1331 : struct swofp_flow_entry *swfe, *tswfe;
1332 :
1333 0 : if ((swft = swofp_flow_table_lookup(sc, table_id)) == NULL)
1334 0 : return ENOENT;
1335 :
1336 0 : LIST_FOREACH_SAFE(swfe, &swft->swft_flow_list, swfe_next, tswfe) {
1337 : /*
1338 : * Flows are deleted force becouse of deleting table,
1339 : * s it's not necessary to send flow remove message.
1340 : */
1341 0 : swfe->swfe_flags &= ~(OFP_FLOWFLAG_SEND_FLOW_REMOVED);
1342 0 : swofp_flow_entry_delete(sc, swft, swfe,
1343 : OFP_FLOWREM_REASON_DELETE);
1344 : }
1345 :
1346 0 : TAILQ_REMOVE(&ofs->swofs_table_list, swft, swft_table_next);
1347 0 : free(swft, M_DEVBUF, sizeof(*swft));
1348 :
1349 : DPRINTF(sc, "delete flow table (id:%d)\n", table_id);
1350 :
1351 0 : return 0;
1352 0 : }
1353 :
1354 : void
1355 0 : swofp_flow_table_delete_all(struct switch_softc *sc)
1356 : {
1357 0 : struct swofp_ofs *ofs = sc->sc_ofs;
1358 : struct swofp_flow_table *swft, *tswft;
1359 : int error;
1360 :
1361 0 : TAILQ_FOREACH_SAFE(swft, &ofs->swofs_table_list,
1362 : swft_table_next, tswft) {
1363 0 : if ((error = swofp_flow_table_delete(sc,swft->swft_table_id)))
1364 0 : log(LOG_ERR, "can't delete table id:%d (error:%d)\n",
1365 0 : swft->swft_table_id, error);
1366 : }
1367 0 : }
1368 :
1369 : struct swofp_group_entry *
1370 0 : swofp_group_entry_lookup(struct switch_softc *sc, uint32_t group_id)
1371 : {
1372 0 : struct swofp_ofs *ofs = sc->sc_ofs;
1373 : struct swofp_group_entry *swge;
1374 :
1375 0 : LIST_FOREACH(swge, &ofs->swofs_group_table, swge_next) {
1376 0 : if (swge->swge_group_id == group_id)
1377 0 : return swge;
1378 : }
1379 :
1380 0 : return (NULL);
1381 0 : }
1382 :
1383 : int
1384 0 : swofp_group_entry_add(struct switch_softc *sc, struct swofp_group_entry *swge)
1385 : {
1386 0 : struct swofp_ofs *ofs = sc->sc_ofs;
1387 :
1388 0 : LIST_INSERT_HEAD(&ofs->swofs_group_table, swge, swge_next);
1389 0 : ofs->swofs_group_table_num++;
1390 :
1391 : DPRINTF(sc, "add group %d in group table (total %d)\n",
1392 : swge->swge_group_id, ofs->swofs_group_table_num);
1393 :
1394 0 : return (0);
1395 : }
1396 :
1397 : int
1398 0 : swofp_group_entry_delete(struct switch_softc *sc,
1399 : struct swofp_group_entry *swge)
1400 : {
1401 0 : struct swofp_ofs *ofs = sc->sc_ofs;
1402 : struct swofp_flow_table *swft;
1403 :
1404 : DPRINTF(sc, "delete group %d in group table (total %d)\n",
1405 : swge->swge_group_id, ofs->swofs_group_table_num);
1406 :
1407 0 : LIST_REMOVE(swge, swge_next);
1408 0 : ofs->swofs_group_table_num--;
1409 :
1410 0 : TAILQ_FOREACH(swft, &ofs->swofs_table_list, swft_table_next) {
1411 0 : swofp_flow_delete_on_table_by_group(sc, swft,
1412 0 : swge->swge_group_id);
1413 : }
1414 :
1415 0 : free(swge->swge_buckets, M_DEVBUF, swge->swge_buckets_len);
1416 0 : free(swge, M_DEVBUF, sizeof(*swge));
1417 :
1418 0 : return (0);
1419 : }
1420 :
1421 : int
1422 0 : swofp_group_entry_delete_all(struct switch_softc *sc)
1423 : {
1424 0 : struct swofp_ofs *ofs = sc->sc_ofs;
1425 : struct swofp_group_entry *swge, *tswge;
1426 :
1427 0 : LIST_FOREACH_SAFE(swge, &ofs->swofs_group_table, swge_next, tswge) {
1428 0 : swofp_group_entry_delete(sc, swge);
1429 : }
1430 :
1431 0 : return (0);
1432 : }
1433 :
1434 : int
1435 0 : swofp_validate_buckets(struct switch_softc *sc, struct mbuf *m, uint8_t type,
1436 : uint16_t *etype, uint16_t *error)
1437 : {
1438 : struct ofp_group_mod *ogm;
1439 : struct ofp_bucket *bucket;
1440 : struct ofp_action_header *ah;
1441 : uint16_t weight, remaining;
1442 : int start, len, off, num;
1443 : size_t blen;
1444 :
1445 0 : *etype = OFP_ERRTYPE_GROUP_MOD_FAILED;
1446 :
1447 0 : ogm = mtod(m, struct ofp_group_mod *);
1448 : start = offsetof(struct ofp_group_mod, gm_buckets);
1449 0 : remaining = len = ntohs(ogm->gm_oh.oh_length) - start;
1450 :
1451 : /* Invalid packet size. */
1452 0 : if (len < 0) {
1453 0 : *error = OFP_ERRGROUPMOD_INVALID_GROUP;
1454 0 : return (-1);
1455 : }
1456 :
1457 : /* Indirect group type must always have one bucket. */
1458 0 : if (len < sizeof(*bucket) && type == OFP_GROUP_T_INDIRECT) {
1459 0 : *error = OFP_ERRGROUPMOD_INVALID_GROUP;
1460 0 : return (-1);
1461 : }
1462 :
1463 0 : for (off = start, num = 0; off < start + len; off += blen, num++) {
1464 0 : bucket = (struct ofp_bucket *)(mtod(m, caddr_t) + off);
1465 :
1466 0 : blen = ntohs(bucket->b_len);
1467 0 : if (blen < sizeof(*bucket)) {
1468 0 : *error = OFP_ERRGROUPMOD_BAD_BUCKET;
1469 0 : return (-1);
1470 : }
1471 :
1472 : /* Validate that the bucket is smaller than the payload. */
1473 0 : if (blen > remaining) {
1474 0 : *etype = OFP_ERRTYPE_BAD_REQUEST;
1475 0 : *error = OFP_ERRREQ_BAD_LEN;
1476 0 : return (-1);
1477 : }
1478 0 : remaining -= blen;
1479 :
1480 : /*
1481 : * Validate weight
1482 : */
1483 0 : switch (type) {
1484 : case OFP_GROUP_T_ALL:
1485 : case OFP_GROUP_T_INDIRECT:
1486 : case OFP_GROUP_T_FAST_FAILOVER:
1487 0 : if (ntohs(bucket->b_weight) != 0) {
1488 0 : *error = OFP_ERRGROUPMOD_BAD_BUCKET;
1489 0 : return (-1);
1490 : }
1491 : break;
1492 : case OFP_GROUP_T_SELECT:
1493 0 : if (num > 1 && weight != ntohs(bucket->b_weight)) {
1494 0 : *error = OFP_ERRGROUPMOD_WEIGHT_UNSUPP;
1495 0 : return (-1);
1496 : }
1497 : break;
1498 : }
1499 :
1500 : /*
1501 : * INDIRECT type has only one bucket
1502 : */
1503 0 : if (type == OFP_GROUP_T_INDIRECT && num > 1) {
1504 0 : *error = OFP_ERRGROUPMOD_BAD_BUCKET;
1505 0 : return (-1);
1506 : }
1507 :
1508 0 : weight = ntohs(bucket->b_weight);
1509 :
1510 : /* Skip if there are no actions to validate. */
1511 0 : if (blen == sizeof(*bucket))
1512 : continue;
1513 :
1514 0 : ah = (struct ofp_action_header *)
1515 0 : (mtod(m, caddr_t) + off + sizeof(*bucket));
1516 0 : if (swofp_validate_action(sc, ah, blen - sizeof(*bucket),
1517 : error)) {
1518 0 : *etype = OFP_ERRTYPE_BAD_ACTION;
1519 0 : return (-1);
1520 : }
1521 : }
1522 :
1523 0 : return (0);
1524 0 : }
1525 :
1526 : void
1527 0 : swofp_flow_entry_table_free(struct ofp_instruction **table)
1528 : {
1529 0 : if (*table) {
1530 0 : free(*table, M_DEVBUF, ntohs((*table)->i_len));
1531 0 : *table = NULL;
1532 0 : }
1533 0 : }
1534 :
1535 : void
1536 0 : swofp_flow_entry_instruction_free(struct swofp_flow_entry *swfe)
1537 : {
1538 0 : swofp_flow_entry_table_free((struct ofp_instruction **)
1539 0 : &swfe->swfe_goto_table);
1540 0 : swofp_flow_entry_table_free((struct ofp_instruction **)
1541 0 : &swfe->swfe_write_metadata);
1542 0 : swofp_flow_entry_table_free((struct ofp_instruction **)
1543 0 : &swfe->swfe_apply_actions);
1544 0 : swofp_flow_entry_table_free((struct ofp_instruction **)
1545 0 : &swfe->swfe_write_actions);
1546 0 : swofp_flow_entry_table_free((struct ofp_instruction **)
1547 0 : &swfe->swfe_clear_actions);
1548 0 : swofp_flow_entry_table_free((struct ofp_instruction **)
1549 0 : &swfe->swfe_experimenter);
1550 0 : swofp_flow_entry_table_free((struct ofp_instruction **)
1551 0 : &swfe->swfe_meter);
1552 0 : }
1553 :
1554 : void
1555 0 : swofp_flow_entry_free(struct swofp_flow_entry **swfe)
1556 : {
1557 0 : if ((*swfe)->swfe_match)
1558 0 : free((*swfe)->swfe_match, M_DEVBUF,
1559 0 : ntohs((*swfe)->swfe_match->om_length));
1560 :
1561 0 : swofp_flow_entry_instruction_free(*swfe);
1562 :
1563 0 : free((*swfe), M_DEVBUF, sizeof(**swfe));
1564 0 : }
1565 :
1566 : void
1567 0 : swofp_flow_entry_add(struct switch_softc *sc, struct swofp_flow_table *swft,
1568 : struct swofp_flow_entry *swfe)
1569 : {
1570 0 : swfe->swfe_table_id = swft->swft_table_id;
1571 0 : LIST_INSERT_HEAD(&swft->swft_flow_list, swfe, swfe_next);
1572 0 : swft->swft_flow_num++;
1573 :
1574 : DPRINTF(sc, "add flow in table %d (total %d)\n",
1575 : swft->swft_table_id, swft->swft_flow_num);
1576 0 : }
1577 :
1578 : void
1579 0 : swofp_flow_entry_delete(struct switch_softc *sc, struct swofp_flow_table *swft,
1580 : struct swofp_flow_entry *swfe, uint8_t reason)
1581 : {
1582 0 : if (swfe->swfe_flags & OFP_FLOWFLAG_SEND_FLOW_REMOVED)
1583 0 : swofp_send_flow_removed(sc, swfe, reason);
1584 :
1585 0 : LIST_REMOVE(swfe, swfe_next);
1586 0 : swofp_flow_entry_free(&swfe);
1587 0 : swft->swft_flow_num--;
1588 :
1589 : DPRINTF(sc, "delete flow from table %d (total %d)\n",
1590 : swft->swft_table_id, swft->swft_flow_num);
1591 0 : }
1592 :
1593 : void
1594 0 : swofp_flow_timeout(struct switch_softc *sc)
1595 : {
1596 0 : struct swofp_ofs *ofs = sc->sc_ofs;
1597 : struct swofp_flow_table *swft;
1598 : struct swofp_flow_entry *swfe, *tswfe;
1599 0 : struct timespec now, duration, idle;
1600 :
1601 0 : nanouptime(&now);
1602 :
1603 0 : TAILQ_FOREACH(swft, &ofs->swofs_table_list, swft_table_next) {
1604 0 : LIST_FOREACH_SAFE(swfe, &swft->swft_flow_list,
1605 : swfe_next, tswfe) {
1606 0 : if (swfe->swfe_idle_timeout) {
1607 0 : timespecsub(&now, &swfe->swfe_idle_time, &idle);
1608 0 : if (swfe->swfe_idle_timeout < idle.tv_sec) {
1609 : DPRINTF(sc, "flow expired "
1610 : "by idle timeout\n");
1611 0 : swofp_flow_entry_delete(sc, swft, swfe,
1612 : OFP_FLOWREM_REASON_IDLE_TIMEOUT);
1613 0 : continue;
1614 : }
1615 : }
1616 0 : if (swfe->swfe_hard_timeout) {
1617 0 : timespecsub(&now, &swfe->swfe_installed_time,
1618 : &duration);
1619 0 : if (swfe->swfe_hard_timeout < duration.tv_sec) {
1620 : DPRINTF(sc, "flow expired "
1621 : "by hard timeout\n");
1622 0 : swofp_flow_entry_delete(sc, swft, swfe,
1623 : OFP_FLOWREM_REASON_HARD_TIMEOUT);
1624 0 : }
1625 : }
1626 : }
1627 : }
1628 0 : }
1629 :
1630 : void
1631 0 : swofp_timer(void *v)
1632 : {
1633 0 : struct switch_softc *sc = (struct switch_softc *)v;
1634 0 : struct swofp_ofs *swofs = sc->sc_ofs;
1635 :
1636 0 : swofp_flow_timeout(sc);
1637 0 : timeout_add_sec(&swofs->swofs_flow_timeout, 10);
1638 0 : }
1639 :
1640 : int
1641 0 : swofp_ox_cmp_data(struct ofp_ox_match *target,
1642 : struct ofp_ox_match *key, int strict)
1643 : {
1644 0 : uint64_t tmth, tmask, kmth, kmask;
1645 0 : uint64_t dummy_mask = UINT64_MAX;
1646 : int len;
1647 :
1648 0 : if (OFP_OXM_GET_FIELD(target) != OFP_OXM_GET_FIELD(key))
1649 0 : return (1);
1650 :
1651 0 : switch (OFP_OXM_GET_FIELD(target)) {
1652 : case OFP_XM_T_VLAN_PCP:
1653 : case OFP_XM_T_IP_DSCP:
1654 : case OFP_XM_T_IP_ECN:
1655 : case OFP_XM_T_IP_PROTO:
1656 : case OFP_XM_T_ICMPV4_CODE:
1657 : case OFP_XM_T_ICMPV4_TYPE:
1658 : case OFP_XM_T_ICMPV6_CODE:
1659 : case OFP_XM_T_ICMPV6_TYPE:
1660 : len = sizeof(uint8_t);
1661 0 : break;
1662 : case OFP_XM_T_ETH_TYPE:
1663 : case OFP_XM_T_TCP_SRC:
1664 : case OFP_XM_T_TCP_DST:
1665 : case OFP_XM_T_UDP_SRC:
1666 : case OFP_XM_T_UDP_DST:
1667 : case OFP_XM_T_ARP_OP:
1668 : len = sizeof(uint16_t);
1669 0 : break;
1670 : case OFP_XM_T_IN_PORT:
1671 : case OFP_XM_T_IPV6_FLABEL:
1672 : len = sizeof(uint32_t);
1673 0 : break;
1674 : case OFP_XM_T_TUNNEL_ID: /* alias OFP_XM_NXMT_TUNNEL_ID */
1675 : len = sizeof(uint64_t);
1676 0 : break;
1677 : default:
1678 0 : return (1);
1679 : }
1680 :
1681 0 : tmth = tmask = kmth = kmask = 0;
1682 :
1683 0 : memcpy(&tmth, ((caddr_t)target + sizeof(*target)), len);
1684 0 : if (OFP_OXM_GET_HASMASK(target))
1685 0 : memcpy(&tmask, ((caddr_t)target + sizeof(*target) + len), len);
1686 : else
1687 0 : memcpy(&tmask, &dummy_mask, len);
1688 :
1689 0 : memcpy(&kmth, ((caddr_t)key + sizeof(*key)), len);
1690 0 : if (OFP_OXM_GET_HASMASK(key))
1691 0 : memcpy(&kmask, ((caddr_t)key + sizeof(*key) + len), len);
1692 : else
1693 0 : memcpy(&kmask, &dummy_mask, len);
1694 :
1695 0 : if (strict) {
1696 0 : if (tmask != kmask)
1697 0 : return (1);
1698 : } else {
1699 0 : if ((tmask & kmask) != kmask)
1700 0 : return (1);
1701 : }
1702 :
1703 0 : return !((tmth & tmask) == (kmth & kmask));
1704 0 : }
1705 :
1706 : #ifdef INET6
1707 : int
1708 0 : swofp_ox_cmp_ipv6_addr(struct ofp_ox_match *target,
1709 : struct ofp_ox_match *key, int strict)
1710 : {
1711 0 : struct in6_addr tmth, tmask, kmth, kmask;
1712 0 : struct in6_addr mask = in6mask128;
1713 :
1714 0 : if (OFP_OXM_GET_FIELD(target) != OFP_OXM_GET_FIELD(key))
1715 0 : return (1);
1716 :
1717 0 : switch (OFP_OXM_GET_FIELD(target)) {
1718 : case OFP_XM_NXMT_TUNNEL_IPV6_SRC:
1719 : case OFP_XM_NXMT_TUNNEL_IPV6_DST:
1720 : case OFP_XM_T_IPV6_SRC:
1721 : case OFP_XM_T_IPV6_DST:
1722 : case OFP_XM_T_IPV6_ND_TARGET:
1723 : break;
1724 : default:
1725 0 : return (1);
1726 : }
1727 :
1728 0 : memcpy(&kmth, ((caddr_t)key + sizeof(*key)), sizeof(kmth));
1729 0 : if (OFP_OXM_GET_HASMASK(key))
1730 0 : memcpy(&kmask, ((caddr_t)key + sizeof(*key) + sizeof(kmask)),
1731 : sizeof(kmask));
1732 : else
1733 0 : kmask = mask;
1734 :
1735 0 : memcpy(&tmth, ((caddr_t)target + sizeof(*target)), sizeof(tmth));
1736 0 : if (OFP_OXM_GET_HASMASK(target))
1737 0 : memcpy(&tmask, ((caddr_t)target + sizeof(*target) +
1738 : sizeof(tmask)), sizeof(tmask));
1739 : else
1740 0 : tmask = mask;
1741 :
1742 0 : if (strict) {
1743 0 : if (memcmp(&tmask, &kmask, sizeof(tmask)) != 0)
1744 0 : return (1);
1745 :
1746 0 : tmth.s6_addr32[0] &= tmask.s6_addr32[0];
1747 0 : tmth.s6_addr32[1] &= tmask.s6_addr32[1];
1748 0 : tmth.s6_addr32[2] &= tmask.s6_addr32[2];
1749 0 : tmth.s6_addr32[3] &= tmask.s6_addr32[3];
1750 :
1751 0 : kmth.s6_addr32[0] &= kmask.s6_addr32[0];
1752 0 : kmth.s6_addr32[1] &= kmask.s6_addr32[1];
1753 0 : kmth.s6_addr32[2] &= kmask.s6_addr32[2];
1754 0 : kmth.s6_addr32[3] &= kmask.s6_addr32[3];
1755 :
1756 0 : } else {
1757 0 : tmask.s6_addr32[0] &= kmask.s6_addr32[0];
1758 0 : tmask.s6_addr32[1] &= kmask.s6_addr32[1];
1759 0 : tmask.s6_addr32[2] &= kmask.s6_addr32[2];
1760 0 : tmask.s6_addr32[3] &= kmask.s6_addr32[3];
1761 :
1762 0 : if (memcmp(&tmask, &kmask, sizeof(tmask)) != 0)
1763 0 : return (1);
1764 :
1765 0 : tmth.s6_addr32[0] &= kmask.s6_addr32[0];
1766 0 : tmth.s6_addr32[1] &= kmask.s6_addr32[1];
1767 0 : tmth.s6_addr32[2] &= kmask.s6_addr32[2];
1768 0 : tmth.s6_addr32[3] &= kmask.s6_addr32[3];
1769 :
1770 0 : kmth.s6_addr32[0] &= kmask.s6_addr32[0];
1771 0 : kmth.s6_addr32[1] &= kmask.s6_addr32[1];
1772 0 : kmth.s6_addr32[2] &= kmask.s6_addr32[2];
1773 0 : kmth.s6_addr32[3] &= kmask.s6_addr32[3];
1774 :
1775 : }
1776 :
1777 0 : return memcmp(&tmth, &kmth, sizeof(tmth));
1778 0 : }
1779 : #endif /* INET6 */
1780 :
1781 : int
1782 0 : swofp_ox_cmp_ipv4_addr(struct ofp_ox_match *target,
1783 : struct ofp_ox_match *key, int strict)
1784 : {
1785 : uint32_t tmth, tmask, kmth, kmask;
1786 :
1787 0 : if (OFP_OXM_GET_FIELD(target) != OFP_OXM_GET_FIELD(key))
1788 0 : return (1);
1789 :
1790 0 : switch (OFP_OXM_GET_FIELD(target)) {
1791 : case OFP_XM_NXMT_TUNNEL_IPV4_SRC:
1792 : case OFP_XM_NXMT_TUNNEL_IPV4_DST:
1793 : case OFP_XM_T_IPV4_SRC:
1794 : case OFP_XM_T_IPV4_DST:
1795 : case OFP_XM_T_ARP_SPA:
1796 : case OFP_XM_T_ARP_TPA:
1797 : break;
1798 : default:
1799 0 : return (1);
1800 : }
1801 :
1802 0 : memcpy(&tmth, ((caddr_t)target + sizeof(*target)), sizeof(uint32_t));
1803 0 : if (OFP_OXM_GET_HASMASK(target))
1804 0 : memcpy(&tmask, ((caddr_t)target + sizeof(*target) +
1805 : sizeof(uint32_t)), sizeof(uint32_t));
1806 : else
1807 : tmask = UINT32_MAX;
1808 :
1809 0 : memcpy(&kmth, ((caddr_t)key + sizeof(*key)), sizeof(uint32_t));
1810 0 : if (OFP_OXM_GET_HASMASK(key))
1811 0 : memcpy(&kmask, ((caddr_t)key + sizeof(*key) +
1812 : sizeof(uint32_t)), sizeof(uint32_t));
1813 : else
1814 : kmask = UINT32_MAX;
1815 :
1816 0 : if (strict) {
1817 0 : if (tmask != kmask)
1818 0 : return (1);
1819 : } else {
1820 0 : if ((tmask & kmask) != kmask)
1821 0 : return (1);
1822 : }
1823 :
1824 0 : return !((tmth & kmask) == (kmth & kmask));
1825 0 : }
1826 :
1827 : int
1828 0 : swofp_ox_cmp_vlan_vid(struct ofp_ox_match *target,
1829 : struct ofp_ox_match *key, int strict)
1830 : {
1831 : uint16_t tmth, tmask, kmth, kmask;
1832 :
1833 0 : if (OFP_OXM_GET_FIELD(target) != OFP_OXM_GET_FIELD(key) ||
1834 0 : OFP_OXM_GET_FIELD(target) != OFP_XM_T_VLAN_VID)
1835 0 : return (1);
1836 :
1837 0 : memcpy(&tmth, ((caddr_t)target + sizeof(*target)), sizeof(uint16_t));
1838 0 : if (OFP_OXM_GET_HASMASK(target))
1839 0 : memcpy(&tmask, ((caddr_t)target + sizeof(*target)
1840 : + sizeof(uint16_t)), sizeof(uint16_t));
1841 : else
1842 : tmask = UINT16_MAX;
1843 :
1844 0 : memcpy(&kmth, ((caddr_t)key + sizeof(*key)), sizeof(uint16_t));
1845 0 : if (OFP_OXM_GET_HASMASK(key))
1846 0 : memcpy(&kmask, ((caddr_t)key + sizeof(*key) +
1847 : sizeof(uint16_t)), sizeof(uint16_t));
1848 : else
1849 : kmask = UINT16_MAX;
1850 :
1851 0 : tmth &= htons(EVL_VLID_MASK);
1852 0 : tmask &= htons(EVL_VLID_MASK);
1853 0 : kmth &= htons(EVL_VLID_MASK);
1854 0 : kmask &= htons(EVL_VLID_MASK);
1855 :
1856 0 : if (strict) {
1857 0 : if (tmask != kmask)
1858 0 : return (1);
1859 : } else {
1860 0 : if ((tmask & kmask) != kmask)
1861 0 : return (1);
1862 : }
1863 :
1864 0 : return !((tmth & kmask) == (kmth & kmask));
1865 0 : }
1866 :
1867 : int
1868 0 : swofp_ox_cmp_ether_addr(struct ofp_ox_match *target,
1869 : struct ofp_ox_match *key, int strict)
1870 : {
1871 : uint64_t tmth, tmask, kmth, kmask;
1872 : uint64_t eth_mask = 0x0000FFFFFFFFFFFFULL;
1873 :
1874 :
1875 0 : if (OFP_OXM_GET_FIELD(target) != OFP_OXM_GET_FIELD(key))
1876 0 : return (1);
1877 :
1878 0 : switch (OFP_OXM_GET_FIELD(target)) {
1879 : case OFP_XM_T_ETH_SRC:
1880 : case OFP_XM_T_ETH_DST:
1881 : case OFP_XM_T_ARP_SHA:
1882 : case OFP_XM_T_ARP_THA:
1883 : case OFP_XM_T_IPV6_ND_SLL:
1884 : case OFP_XM_T_IPV6_ND_TLL:
1885 : break;
1886 : default:
1887 0 : return (1);
1888 : }
1889 :
1890 0 : memcpy(&tmth, ((caddr_t)target + sizeof(*target)), ETHER_ADDR_LEN);
1891 0 : if (OFP_OXM_GET_HASMASK(target))
1892 0 : memcpy(&tmask, ((caddr_t)target + sizeof(*target) +
1893 : ETHER_ADDR_LEN), ETHER_ADDR_LEN);
1894 : else
1895 : tmask = UINT64_MAX;
1896 :
1897 0 : memcpy(&kmth, ((caddr_t)key + sizeof(*key)), ETHER_ADDR_LEN);
1898 0 : if (OFP_OXM_GET_HASMASK(key))
1899 0 : memcpy(&kmask, ((caddr_t)key + sizeof(*key) +
1900 : ETHER_ADDR_LEN), ETHER_ADDR_LEN);
1901 : else
1902 : kmask = UINT64_MAX;
1903 :
1904 0 : tmask &= eth_mask;
1905 0 : tmth &= eth_mask;
1906 0 : kmask &= eth_mask;
1907 0 : kmth &= eth_mask;
1908 :
1909 0 : if (strict) {
1910 0 : if (tmask != kmask)
1911 0 : return (1);
1912 : } else {
1913 0 : if ((tmask & kmask) != kmask)
1914 0 : return (1);
1915 : }
1916 :
1917 0 : return !((tmth & kmask) == (kmth & kmask));
1918 0 : }
1919 :
1920 : int
1921 0 : swofp_validate_oxm(struct ofp_ox_match *oxm, uint16_t *err)
1922 : {
1923 : struct ofp_oxm_class *handler;
1924 : int hasmask;
1925 : int neededlen;
1926 :
1927 0 : handler = swofp_lookup_oxm_handler(oxm);
1928 0 : if (handler == NULL || handler->oxm_match == NULL) {
1929 0 : *err = OFP_ERRMATCH_BAD_FIELD;
1930 0 : return (-1);
1931 : }
1932 :
1933 0 : hasmask = OFP_OXM_GET_HASMASK(oxm);
1934 :
1935 0 : neededlen = (hasmask) ?
1936 0 : (handler->oxm_len * 2) : (handler->oxm_len);
1937 0 : if (oxm->oxm_length != neededlen) {
1938 0 : *err = OFP_ERRMATCH_BAD_LEN;
1939 0 : return (-1);
1940 : }
1941 :
1942 0 : return (0);
1943 0 : }
1944 :
1945 : int
1946 0 : swofp_validate_flow_match(struct ofp_match *om, uint16_t *err)
1947 : {
1948 : struct ofp_ox_match *oxm;
1949 :
1950 : /*
1951 : * TODO this function is missing checks for:
1952 : * - OFP_ERRMATCH_BAD_TAG;
1953 : * - OFP_ERRMATCH_BAD_VALUE;
1954 : * - OFP_ERRMATCH_BAD_MASK;
1955 : * - OFP_ERRMATCH_BAD_PREREQ;
1956 : * - OFP_ERRMATCH_DUP_FIELD;
1957 : */
1958 0 : OFP_OXM_FOREACH(om, ntohs(om->om_length), oxm) {
1959 0 : if (swofp_validate_oxm(oxm, err))
1960 0 : return (*err);
1961 : }
1962 :
1963 0 : return (0);
1964 0 : }
1965 :
1966 : int
1967 0 : swofp_validate_flow_instruction(struct switch_softc *sc,
1968 : struct ofp_instruction *oi, size_t total, uint16_t *etype,
1969 : uint16_t *err)
1970 : {
1971 : struct ofp_action_header *oah;
1972 : struct ofp_instruction_actions *oia;
1973 : int ilen;
1974 :
1975 0 : *etype = OFP_ERRTYPE_BAD_INSTRUCTION;
1976 :
1977 0 : ilen = ntohs(oi->i_len);
1978 : /* Check for bigger than packet or smaller than header. */
1979 0 : if (ilen > total || ilen < sizeof(*oi)) {
1980 0 : *err = OFP_ERRINST_BAD_LEN;
1981 0 : return (-1);
1982 : }
1983 :
1984 0 : switch (ntohs(oi->i_type)) {
1985 : case OFP_INSTRUCTION_T_GOTO_TABLE:
1986 0 : if (ilen != sizeof(struct ofp_instruction_goto_table)) {
1987 0 : *err = OFP_ERRINST_BAD_LEN;
1988 0 : return (-1);
1989 : }
1990 : break;
1991 : case OFP_INSTRUCTION_T_WRITE_META:
1992 0 : if (ilen != sizeof(struct ofp_instruction_write_metadata)) {
1993 0 : *err = OFP_ERRINST_BAD_LEN;
1994 0 : return (-1);
1995 : }
1996 : break;
1997 : case OFP_INSTRUCTION_T_METER:
1998 0 : if (ilen != sizeof(struct ofp_instruction_meter)) {
1999 0 : *err = OFP_ERRINST_BAD_LEN;
2000 0 : return (-1);
2001 : }
2002 : break;
2003 :
2004 : case OFP_INSTRUCTION_T_WRITE_ACTIONS:
2005 : case OFP_INSTRUCTION_T_CLEAR_ACTIONS:
2006 : case OFP_INSTRUCTION_T_APPLY_ACTIONS:
2007 0 : if (ilen < sizeof(*oia)) {
2008 0 : *err = OFP_ERRINST_BAD_LEN;
2009 0 : return (-1);
2010 : }
2011 :
2012 0 : oia = (struct ofp_instruction_actions *)oi;
2013 :
2014 : /* Validate actions before iterating over them. */
2015 0 : oah = (struct ofp_action_header *)
2016 0 : ((uint8_t *)oia + sizeof(*oia));
2017 0 : if (swofp_validate_action(sc, oah, ilen - sizeof(*oia),
2018 : err)) {
2019 0 : *etype = OFP_ERRTYPE_BAD_ACTION;
2020 0 : return (-1);
2021 : }
2022 : break;
2023 :
2024 : case OFP_INSTRUCTION_T_EXPERIMENTER:
2025 : /* FALLTHROUGH */
2026 : default:
2027 0 : *err = OFP_ERRINST_UNKNOWN_INST;
2028 0 : return (-1);
2029 : }
2030 :
2031 0 : return (0);
2032 0 : }
2033 :
2034 : int
2035 0 : swofp_validate_action(struct switch_softc *sc, struct ofp_action_header *ah,
2036 : size_t ahtotal, uint16_t *err)
2037 : {
2038 : struct ofp_action_handler *oah;
2039 : struct ofp_ox_match *oxm;
2040 : struct ofp_action_push *ap;
2041 : struct ofp_action_group *ag;
2042 : struct ofp_action_output *ao;
2043 : struct switch_port *swpo;
2044 : uint8_t *dptr;
2045 : int ahtype, ahlen, oxmlen;
2046 :
2047 : /* No actions. */
2048 0 : if (ahtotal == 0)
2049 0 : return (0);
2050 :
2051 : /* Check if we have at least the first header. */
2052 0 : if (ahtotal < sizeof(*ah)) {
2053 0 : *err = OFP_ERRACTION_LEN;
2054 0 : return (-1);
2055 : }
2056 :
2057 : parse_next_action:
2058 0 : ahtype = ntohs(ah->ah_type);
2059 0 : ahlen = ntohs(ah->ah_len);
2060 0 : if (ahlen < sizeof(*ah) || ahlen > ahtotal) {
2061 0 : *err = OFP_ERRACTION_LEN;
2062 0 : return (-1);
2063 : }
2064 :
2065 0 : switch (ahtype) {
2066 : case OFP_ACTION_OUTPUT:
2067 0 : if (ahlen != sizeof(struct ofp_action_output)) {
2068 0 : *err = OFP_ERRACTION_LEN;
2069 0 : return (-1);
2070 : }
2071 :
2072 0 : ao = (struct ofp_action_output *)ah;
2073 0 : switch (ntohl(ao->ao_port)) {
2074 : case OFP_PORT_ANY:
2075 0 : *err = OFP_ERRACTION_OUT_PORT;
2076 0 : return (-1);
2077 :
2078 : case OFP_PORT_ALL:
2079 : case OFP_PORT_NORMAL:
2080 : /* TODO implement port ALL and NORMAL. */
2081 0 : *err = OFP_ERRACTION_OUT_PORT;
2082 0 : return (-1);
2083 :
2084 : case OFP_PORT_CONTROLLER:
2085 : case OFP_PORT_FLOWTABLE:
2086 : case OFP_PORT_FLOOD:
2087 : case OFP_PORT_INPUT:
2088 : case OFP_PORT_LOCAL:
2089 : break;
2090 :
2091 : default:
2092 0 : TAILQ_FOREACH(swpo, &sc->sc_swpo_list,
2093 : swpo_list_next) {
2094 0 : if (swpo->swpo_port_no ==
2095 0 : ntohl(ao->ao_port))
2096 : break;
2097 : }
2098 0 : if (swpo == NULL) {
2099 0 : *err = OFP_ERRACTION_OUT_PORT;
2100 0 : return (-1);
2101 : }
2102 : break;
2103 : }
2104 : break;
2105 : case OFP_ACTION_GROUP:
2106 0 : if (ahlen != sizeof(struct ofp_action_group)) {
2107 0 : *err = OFP_ERRACTION_LEN;
2108 0 : return (-1);
2109 : }
2110 :
2111 0 : ag = (struct ofp_action_group *)ah;
2112 0 : if (swofp_group_entry_lookup(sc,
2113 0 : ntohl(ag->ag_group_id)) == NULL) {
2114 0 : *err = OFP_ERRACTION_BAD_OUT_GROUP;
2115 0 : return (-1);
2116 : }
2117 : break;
2118 : case OFP_ACTION_SET_QUEUE:
2119 0 : if (ahlen != sizeof(struct ofp_action_set_queue)) {
2120 0 : *err = OFP_ERRACTION_LEN;
2121 0 : return (-1);
2122 : }
2123 : break;
2124 : case OFP_ACTION_SET_MPLS_TTL:
2125 0 : if (ahlen != sizeof(struct ofp_action_mpls_ttl)) {
2126 0 : *err = OFP_ERRACTION_LEN;
2127 0 : return (-1);
2128 : }
2129 : break;
2130 : case OFP_ACTION_SET_NW_TTL:
2131 0 : if (ahlen != sizeof(struct ofp_action_nw_ttl)) {
2132 0 : *err = OFP_ERRACTION_LEN;
2133 0 : return (-1);
2134 : }
2135 : break;
2136 : case OFP_ACTION_COPY_TTL_OUT:
2137 : case OFP_ACTION_COPY_TTL_IN:
2138 : case OFP_ACTION_DEC_MPLS_TTL:
2139 : case OFP_ACTION_POP_VLAN:
2140 0 : if (ahlen != sizeof(struct ofp_action_header)) {
2141 0 : *err = OFP_ERRACTION_LEN;
2142 0 : return (-1);
2143 : }
2144 : break;
2145 : case OFP_ACTION_PUSH_VLAN:
2146 : case OFP_ACTION_PUSH_MPLS:
2147 : case OFP_ACTION_PUSH_PBB:
2148 0 : if (ahlen != sizeof(struct ofp_action_push)) {
2149 0 : *err = OFP_ERRACTION_LEN;
2150 0 : return (-1);
2151 : }
2152 :
2153 0 : ap = (struct ofp_action_push *)ah;
2154 0 : switch (ntohs(ap->ap_type)) {
2155 : case OFP_ACTION_PUSH_VLAN:
2156 0 : if (ntohs(ap->ap_ethertype) != ETHERTYPE_VLAN &&
2157 0 : ntohs(ap->ap_ethertype) != ETHERTYPE_QINQ) {
2158 0 : *err = OFP_ERRACTION_ARGUMENT;
2159 0 : return (-1);
2160 : }
2161 : break;
2162 :
2163 : case OFP_ACTION_PUSH_MPLS:
2164 : case OFP_ACTION_PUSH_PBB:
2165 : /* Not implemented yet. */
2166 : default:
2167 0 : *err = OFP_ERRACTION_TYPE;
2168 0 : return (-1);
2169 : }
2170 : break;
2171 : case OFP_ACTION_POP_MPLS:
2172 0 : if (ahlen != sizeof(struct ofp_action_pop_mpls)) {
2173 0 : *err = OFP_ERRACTION_LEN;
2174 0 : return (-1);
2175 : }
2176 : break;
2177 : case OFP_ACTION_SET_FIELD:
2178 0 : if (ahlen < sizeof(struct ofp_action_set_field)) {
2179 0 : *err = OFP_ERRACTION_LEN;
2180 0 : return (-1);
2181 : }
2182 :
2183 0 : oxmlen = ahlen - (sizeof(struct ofp_action_set_field) -
2184 : offsetof(struct ofp_action_set_field, asf_field));
2185 0 : if (oxmlen < sizeof(*oxm)) {
2186 0 : *err = OFP_ERRACTION_LEN;
2187 0 : return (-1);
2188 : }
2189 :
2190 0 : dptr = (uint8_t *)ah;
2191 0 : dptr += sizeof(struct ofp_action_set_field) -
2192 : offsetof(struct ofp_action_set_field, asf_field);
2193 0 : while (oxmlen > 0) {
2194 0 : oxm = (struct ofp_ox_match *)dptr;
2195 0 : if (swofp_validate_oxm(oxm, err)) {
2196 0 : if (*err == OFP_ERRMATCH_BAD_LEN)
2197 0 : *err = OFP_ERRACTION_SET_LEN;
2198 : else
2199 0 : *err = OFP_ERRACTION_SET_TYPE;
2200 :
2201 0 : return (-1);
2202 : }
2203 :
2204 0 : dptr += sizeof(*oxm) + oxm->oxm_length;
2205 0 : oxmlen -= sizeof(*oxm) + oxm->oxm_length;
2206 : }
2207 : break;
2208 :
2209 : default:
2210 : /* Unknown/unsupported action. */
2211 0 : *err = OFP_ERRACTION_TYPE;
2212 0 : return (-1);
2213 : }
2214 :
2215 0 : oah = swofp_lookup_action_handler(ahtype);
2216 : /* Unknown/unsupported action. */
2217 0 : if (oah == NULL) {
2218 0 : *err = OFP_ERRACTION_TYPE;
2219 0 : return (-1);
2220 : }
2221 :
2222 0 : ahtotal -= min(ahlen, ahtotal);
2223 0 : if (ahtotal) {
2224 0 : ah = (struct ofp_action_header *)((uint8_t *)ah + ahlen);
2225 0 : goto parse_next_action;
2226 : }
2227 :
2228 0 : return (0);
2229 0 : }
2230 :
2231 : int
2232 0 : swofp_flow_filter_out_port(struct ofp_instruction_actions *oia,
2233 : uint32_t out_port)
2234 : {
2235 : struct ofp_action_header *oah;
2236 : struct ofp_action_output *oao;
2237 :
2238 0 : if (oia == NULL)
2239 0 : return (0);
2240 :
2241 0 : OFP_I_ACTIONS_FOREACH((struct ofp_instruction_actions *)oia, oah) {
2242 0 : if (ntohs(oah->ah_type) == OFP_ACTION_OUTPUT) {
2243 0 : oao = (struct ofp_action_output *)oah;
2244 0 : if (ntohl(oao->ao_port) == out_port)
2245 0 : return (1);
2246 : }
2247 : }
2248 :
2249 0 : return (0);
2250 0 : }
2251 :
2252 : int
2253 0 : swofp_flow_filter(struct swofp_flow_entry *swfe, uint64_t cookie,
2254 : uint64_t cookie_mask, uint32_t out_port, uint32_t out_group)
2255 : {
2256 :
2257 0 : if (cookie_mask != 0 &&
2258 0 : ((swfe->swfe_cookie & cookie_mask) != (cookie & cookie_mask)))
2259 0 : return (0);
2260 :
2261 0 : if ((out_port == OFP_PORT_ANY) && (out_group == OFP_GROUP_ID_ALL))
2262 0 : return (1);
2263 :
2264 0 : if ((out_port != OFP_PORT_ANY) &&
2265 0 : !(swofp_flow_filter_out_port(swfe->swfe_write_actions, out_port) ||
2266 0 : swofp_flow_filter_out_port(swfe->swfe_apply_actions, out_port)))
2267 0 : return (0);
2268 :
2269 : if (out_port != OFP_GROUP_ID_ALL) {
2270 : /* XXX ignore group */
2271 : }
2272 :
2273 0 : return (1);
2274 0 : }
2275 :
2276 : int
2277 0 : swofp_flow_cmp_common(struct swofp_flow_entry *swfe, struct ofp_match *key,
2278 : int strict)
2279 : {
2280 0 : struct ofp_match *target = swfe->swfe_match;
2281 : struct ofp_oxm_class *khandler;
2282 : struct ofp_ox_match *toxm, *koxm;
2283 : void *kmask;
2284 : int len;
2285 : /* maximam payload size is size of struct in6_addr */
2286 0 : uint8_t dummy_unmask[sizeof(struct in6_addr)];
2287 :
2288 0 : memset(dummy_unmask, 0, sizeof(dummy_unmask));
2289 :
2290 0 : OFP_OXM_FOREACH(key, ntohs(key->om_length), koxm) {
2291 0 : khandler = swofp_lookup_oxm_handler(koxm);
2292 0 : if (khandler == NULL || khandler->oxm_match == NULL)
2293 0 : return (0);
2294 :
2295 0 : len = khandler->oxm_len;
2296 :
2297 : /*
2298 : * OpenFlow Switch Specification 1.3.5 says:
2299 : * - An all-zero-bits oxm_mask is equivalent to omitting
2300 : * the OXM TLV entirely
2301 : */
2302 0 : if (strict && OFP_OXM_GET_HASMASK(koxm)) {
2303 0 : kmask = (void *)((caddr_t)koxm + sizeof(*koxm) + len);
2304 0 : if (memcmp(kmask, dummy_unmask, len) == 0)
2305 : continue;
2306 : }
2307 :
2308 0 : OFP_OXM_FOREACH(target, ntohs(target->om_length), toxm) {
2309 0 : if (khandler->oxm_cmp(toxm, koxm, strict) == 0)
2310 : break;
2311 : }
2312 0 : if (OFP_OXM_TERMINATED(target, ntohs(target->om_length), toxm))
2313 0 : return (0);
2314 : }
2315 :
2316 0 : return (1);
2317 0 : }
2318 :
2319 : int
2320 0 : swofp_flow_cmp_non_strict(struct swofp_flow_entry *swfe, struct ofp_match *key)
2321 : {
2322 : /* Every oxm matching is wildcard */
2323 0 : if (key == NULL)
2324 0 : return (1);
2325 :
2326 0 : return swofp_flow_cmp_common(swfe, key, 0);
2327 0 : }
2328 :
2329 : int
2330 0 : swofp_flow_cmp_strict(struct swofp_flow_entry *swfe, struct ofp_match *key,
2331 : uint32_t priority)
2332 : {
2333 0 : struct ofp_match *target = swfe->swfe_match;
2334 : struct ofp_ox_match *toxm, *koxm;
2335 : int key_matches, target_matches;
2336 :
2337 : /*
2338 : * Both target and key values are put on network byte order,
2339 : * so it's ok that those are compared without changing byte order
2340 : */
2341 0 : if (swfe->swfe_priority != priority)
2342 0 : return (0);
2343 :
2344 : key_matches = target_matches = 0;
2345 0 : OFP_OXM_FOREACH(key, ntohs(key->om_length), koxm)
2346 0 : key_matches++;
2347 :
2348 0 : OFP_OXM_FOREACH(target, ntohs(target->om_length), toxm)
2349 0 : target_matches++;
2350 :
2351 0 : if (key_matches != target_matches)
2352 0 : return (0);
2353 :
2354 0 : return swofp_flow_cmp_common(swfe, key, 1);
2355 0 : }
2356 :
2357 : struct swofp_flow_entry *
2358 0 : swofp_flow_search_by_table(struct swofp_flow_table *swft, struct ofp_match *key,
2359 : uint16_t priority)
2360 : {
2361 : struct swofp_flow_entry *swfe;
2362 :
2363 0 : LIST_FOREACH(swfe, &swft->swft_flow_list, swfe_next) {
2364 0 : if (swofp_flow_cmp_strict(swfe, key, priority))
2365 0 : return (swfe);
2366 : }
2367 :
2368 0 : return (NULL);
2369 0 : }
2370 :
2371 : int
2372 0 : swofp_flow_has_group(struct ofp_instruction_actions *oia, uint32_t group_id)
2373 : {
2374 : struct ofp_action_header *oah;
2375 : struct ofp_action_group *oag;
2376 :
2377 0 : if (oia == NULL)
2378 0 : return (0);
2379 :
2380 0 : OFP_I_ACTIONS_FOREACH((struct ofp_instruction_actions *)oia, oah) {
2381 0 : if (ntohs(oah->ah_type) == OFP_ACTION_GROUP) {
2382 0 : oag = (struct ofp_action_group *)oah;
2383 0 : if (ntohl(oag->ag_group_id) == group_id)
2384 0 : return (1);
2385 : }
2386 : }
2387 :
2388 0 : return (0);
2389 0 : }
2390 :
2391 : void
2392 0 : swofp_flow_delete_on_table_by_group(struct switch_softc *sc,
2393 : struct swofp_flow_table *swft, uint32_t group_id)
2394 : {
2395 : struct swofp_flow_entry *swfe, *tswfe;
2396 :
2397 0 : LIST_FOREACH_SAFE(swfe, &swft->swft_flow_list, swfe_next, tswfe) {
2398 0 : if (swofp_flow_has_group(swfe->swfe_apply_actions, group_id) ||
2399 0 : swofp_flow_has_group(swfe->swfe_write_actions, group_id)) {
2400 0 : swofp_flow_entry_delete(sc, swft, swfe,
2401 : OFP_FLOWREM_REASON_GROUP_DELETE);
2402 0 : }
2403 : }
2404 0 : }
2405 :
2406 : void
2407 0 : swofp_flow_delete_on_table(struct switch_softc *sc,
2408 : struct swofp_flow_table *swft, struct ofp_match *key, uint16_t priority,
2409 : uint64_t cookie, uint64_t cookie_mask, uint32_t out_port,
2410 : uint32_t out_group, int strict)
2411 : {
2412 : struct swofp_flow_entry *swfe, *tswfe;
2413 :
2414 0 : LIST_FOREACH_SAFE(swfe, &swft->swft_flow_list, swfe_next, tswfe) {
2415 0 : if (strict && !swofp_flow_cmp_strict(swfe, key, priority))
2416 : continue;
2417 0 : else if (!swofp_flow_cmp_non_strict(swfe, key))
2418 : continue;
2419 :
2420 0 : if (!swofp_flow_filter(swfe, cookie, cookie_mask,
2421 : out_port, out_group))
2422 : continue;
2423 :
2424 0 : swofp_flow_entry_delete(sc, swft, swfe,
2425 : OFP_FLOWREM_REASON_DELETE);
2426 0 : }
2427 0 : }
2428 :
2429 : void
2430 0 : swofp_ox_match_put_start(struct ofp_match *om)
2431 : {
2432 0 : om->om_type = htons(OFP_MATCH_OXM);
2433 0 : om->om_length = htons(sizeof(*om));
2434 0 : }
2435 :
2436 : /*
2437 : * Return ofp_match length include "PADDING" byte
2438 : */
2439 : int
2440 0 : swofp_ox_match_put_end(struct ofp_match *om)
2441 : {
2442 0 : int tsize = ntohs(om->om_length);
2443 : int padding;
2444 :
2445 0 : padding = OFP_ALIGN(tsize) - tsize;
2446 0 : if (padding)
2447 0 : memset((caddr_t)om + tsize, 0, padding);
2448 :
2449 0 : return tsize + padding;
2450 : }
2451 :
2452 : int
2453 0 : swofp_ox_match_put_uint32(struct ofp_match *om, uint8_t type, uint32_t val)
2454 : {
2455 0 : int off = ntohs(om->om_length);
2456 : struct ofp_ox_match *oxm;
2457 :
2458 0 : val = htonl(val);
2459 0 : oxm = (struct ofp_ox_match *)((caddr_t)om + off);
2460 0 : oxm->oxm_class = htons(OFP_OXM_C_OPENFLOW_BASIC);
2461 0 : OFP_OXM_SET_FIELD(oxm, type);
2462 0 : oxm->oxm_length = sizeof(uint32_t);
2463 0 : memcpy(oxm->oxm_value, &val, sizeof(val));
2464 0 : om->om_length = htons(ntohs(om->om_length) +
2465 : sizeof(*oxm) + sizeof(uint32_t));
2466 :
2467 0 : return ntohs(om->om_length);
2468 : }
2469 :
2470 : int
2471 0 : swofp_ox_match_put_uint64(struct ofp_match *om, uint8_t type, uint64_t val)
2472 : {
2473 : struct ofp_ox_match *oxm;
2474 0 : int off = ntohs(om->om_length);
2475 :
2476 0 : val = htobe64(val);
2477 0 : oxm = (struct ofp_ox_match *)((caddr_t)om + off);
2478 0 : oxm->oxm_class = htons(OFP_OXM_C_OPENFLOW_BASIC);
2479 0 : OFP_OXM_SET_FIELD(oxm, type);
2480 0 : oxm->oxm_length = sizeof(uint64_t);
2481 0 : memcpy(oxm->oxm_value, &val, sizeof(val));
2482 0 : om->om_length = htons(ntohs(om->om_length) +
2483 : sizeof(*oxm) + sizeof(uint64_t));
2484 :
2485 0 : return ntohs(om->om_length);
2486 : }
2487 :
2488 : int
2489 0 : swofp_nx_match_put(struct ofp_match *om, uint8_t type, int len,
2490 : caddr_t val)
2491 : {
2492 : struct ofp_ox_match *oxm;
2493 0 : int off = ntohs(om->om_length);
2494 :
2495 0 : oxm = (struct ofp_ox_match *)((caddr_t)om + off);
2496 0 : oxm->oxm_class = htons(OFP_OXM_C_NXM_1);
2497 0 : OFP_OXM_SET_FIELD(oxm, type);
2498 0 : oxm->oxm_length = len;
2499 0 : memcpy((void *)oxm->oxm_value, val, len);
2500 :
2501 0 : om->om_length = htons(ntohs(om->om_length) + sizeof(*oxm) + len);
2502 :
2503 0 : return ntohs(om->om_length);
2504 : }
2505 :
2506 : int
2507 0 : swofp_ox_set_vlan_vid(struct switch_flow_classify *swfcl,
2508 : struct ofp_ox_match *oxm)
2509 : {
2510 : uint16_t val;
2511 :
2512 0 : val = *(uint16_t *)oxm->oxm_value;
2513 0 : swfcl->swfcl_vlan->vlan_vid = (val & htons(EVL_VLID_MASK));
2514 :
2515 0 : return (0);
2516 : }
2517 :
2518 : int
2519 0 : swofp_ox_set_uint8(struct switch_flow_classify *swfcl,
2520 : struct ofp_ox_match *oxm)
2521 : {
2522 : uint8_t val;
2523 :
2524 0 : val = *(uint8_t *)oxm->oxm_value;
2525 :
2526 0 : switch (OFP_OXM_GET_FIELD(oxm)) {
2527 : case OFP_XM_T_IP_DSCP:
2528 0 : if (swfcl->swfcl_ipv4)
2529 0 : swfcl->swfcl_ipv4->ipv4_tos = ((val << 2) |
2530 0 : (swfcl->swfcl_ipv4->ipv4_tos & IPTOS_ECN_MASK));
2531 : else
2532 0 : swfcl->swfcl_ipv6->ipv6_tclass = ((val << 2) |
2533 0 : (swfcl->swfcl_ipv6->ipv6_tclass & IPTOS_ECN_MASK));
2534 : break;
2535 : case OFP_XM_T_IP_ECN:
2536 0 : if (swfcl->swfcl_ipv4)
2537 0 : swfcl->swfcl_ipv4->ipv4_tos = ((val & IPTOS_ECN_MASK) |
2538 0 : (swfcl->swfcl_ipv4->ipv4_tos & ~IPTOS_ECN_MASK));
2539 : else
2540 0 : swfcl->swfcl_ipv6->ipv6_tclass = (
2541 0 : (val & IPTOS_ECN_MASK) |
2542 0 : (swfcl->swfcl_ipv6->ipv6_tclass & ~IPTOS_ECN_MASK));
2543 : break;
2544 : case OFP_XM_T_IP_PROTO:
2545 0 : if (swfcl->swfcl_ipv4)
2546 0 : swfcl->swfcl_ipv4->ipv4_proto = val;
2547 : else
2548 0 : swfcl->swfcl_ipv6->ipv6_nxt = val;
2549 : break;
2550 : case OFP_XM_T_ICMPV4_TYPE:
2551 0 : swfcl->swfcl_icmpv4->icmpv4_type = val;
2552 0 : break;
2553 : case OFP_XM_T_ICMPV4_CODE:
2554 0 : swfcl->swfcl_icmpv4->icmpv4_code = val;
2555 0 : break;
2556 : case OFP_XM_T_ICMPV6_TYPE:
2557 0 : swfcl->swfcl_icmpv6->icmpv6_type = val;
2558 0 : break;
2559 : case OFP_XM_T_ICMPV6_CODE:
2560 0 : swfcl->swfcl_icmpv6->icmpv6_code = val;
2561 0 : break;
2562 : }
2563 :
2564 0 : return (0);
2565 : }
2566 :
2567 : int
2568 0 : swofp_ox_set_uint16(struct switch_flow_classify *swfcl,
2569 : struct ofp_ox_match *oxm)
2570 : {
2571 : uint16_t val;
2572 :
2573 0 : val = *(uint16_t *)oxm->oxm_value;
2574 :
2575 0 : switch (OFP_OXM_GET_FIELD(oxm)) {
2576 : case OFP_XM_T_ETH_TYPE:
2577 0 : swfcl->swfcl_ether->eth_type = val;
2578 0 : break;
2579 : case OFP_XM_T_VLAN_PCP:
2580 0 : swfcl->swfcl_vlan->vlan_pcp = val;
2581 0 : break;
2582 : case OFP_XM_T_TCP_SRC:
2583 0 : swfcl->swfcl_tcp->tcp_src = val;
2584 0 : break;
2585 : case OFP_XM_T_TCP_DST:
2586 0 : swfcl->swfcl_tcp->tcp_dst = val;
2587 0 : break;
2588 : case OFP_XM_T_UDP_SRC:
2589 0 : swfcl->swfcl_udp->udp_src = val;
2590 0 : break;
2591 : case OFP_XM_T_UDP_DST:
2592 0 : swfcl->swfcl_udp->udp_dst = val;
2593 0 : break;
2594 : case OFP_XM_T_ARP_OP:
2595 0 : swfcl->swfcl_arp->_arp_op = val;
2596 0 : }
2597 :
2598 0 : return (0);
2599 : }
2600 :
2601 : int
2602 0 : swofp_ox_set_uint32(struct switch_flow_classify *swfcl,
2603 : struct ofp_ox_match *oxm)
2604 : {
2605 : uint32_t val;
2606 :
2607 0 : val = *(uint32_t *)oxm->oxm_value;
2608 :
2609 0 : switch (OFP_OXM_GET_FIELD(oxm)) {
2610 : case OFP_XM_T_IPV6_FLABEL:
2611 0 : swfcl->swfcl_ipv6->ipv6_flow_label = val;
2612 0 : break;
2613 : }
2614 :
2615 0 : return (0);
2616 : }
2617 :
2618 : int
2619 0 : swofp_ox_set_uint64(struct switch_flow_classify *swfcl,
2620 : struct ofp_ox_match *oxm)
2621 : {
2622 : uint64_t val;
2623 :
2624 0 : val = *(uint64_t *)oxm->oxm_value;
2625 :
2626 0 : switch (OFP_OXM_GET_FIELD(oxm)) {
2627 : case OFP_XM_T_TUNNEL_ID: /* alias OFP_XM_NXMT_TUNNEL_ID */
2628 0 : swfcl->swfcl_tunnel->tun_key = val;
2629 0 : break;
2630 : }
2631 :
2632 0 : return (0);
2633 : }
2634 :
2635 : int
2636 0 : swofp_ox_set_ipv6_addr(struct switch_flow_classify *swfcl,
2637 : struct ofp_ox_match *oxm)
2638 : {
2639 0 : struct in6_addr val;
2640 :
2641 0 : memcpy(&val, oxm->oxm_value, sizeof(val));
2642 :
2643 0 : switch (OFP_OXM_GET_FIELD(oxm)) {
2644 : case OFP_XM_NXMT_TUNNEL_IPV6_SRC:
2645 0 : swfcl->swfcl_tunnel->tun_ipv6_src = val;
2646 0 : break;
2647 : case OFP_XM_NXMT_TUNNEL_IPV6_DST:
2648 0 : swfcl->swfcl_tunnel->tun_ipv6_dst = val;
2649 0 : break;
2650 : case OFP_XM_T_IPV6_SRC:
2651 0 : swfcl->swfcl_ipv6->ipv6_src = val;
2652 0 : break;
2653 : case OFP_XM_T_IPV6_DST:
2654 0 : swfcl->swfcl_ipv6->ipv6_dst = val;
2655 0 : break;
2656 : case OFP_XM_T_IPV6_ND_TARGET:
2657 0 : swfcl->swfcl_nd6->nd6_target = val;
2658 0 : break;
2659 : }
2660 :
2661 0 : return (0);
2662 0 : }
2663 :
2664 : int
2665 0 : swofp_ox_set_ipv4_addr(struct switch_flow_classify *swfcl,
2666 : struct ofp_ox_match *oxm)
2667 : {
2668 : uint32_t val;
2669 :
2670 0 : val = *(uint32_t *)oxm->oxm_value;
2671 :
2672 0 : switch (OFP_OXM_GET_FIELD(oxm)) {
2673 : case OFP_XM_NXMT_TUNNEL_IPV4_SRC:
2674 0 : swfcl->swfcl_tunnel->tun_ipv4_src = *(struct in_addr *)&val;
2675 0 : break;
2676 : case OFP_XM_NXMT_TUNNEL_IPV4_DST:
2677 0 : swfcl->swfcl_tunnel->tun_ipv4_dst = *(struct in_addr *)&val;
2678 0 : break;
2679 : case OFP_XM_T_IPV4_SRC:
2680 0 : swfcl->swfcl_ipv4->ipv4_src = val;
2681 0 : break;
2682 : case OFP_XM_T_IPV4_DST:
2683 0 : swfcl->swfcl_ipv4->ipv4_dst = val;
2684 0 : break;
2685 : case OFP_XM_T_ARP_SPA:
2686 0 : swfcl->swfcl_arp->arp_sip = val;
2687 0 : break;
2688 : case OFP_XM_T_ARP_TPA:
2689 0 : swfcl->swfcl_arp->arp_tip = val;
2690 0 : break;
2691 : }
2692 :
2693 0 : return (0);
2694 : }
2695 :
2696 : int
2697 0 : swofp_ox_set_ether_addr(struct switch_flow_classify *swfcl,
2698 : struct ofp_ox_match *oxm)
2699 : {
2700 : caddr_t eth_addr;
2701 :
2702 0 : eth_addr = oxm->oxm_value;
2703 :
2704 0 : switch (OFP_OXM_GET_FIELD(oxm)) {
2705 : case OFP_XM_T_ETH_SRC:
2706 0 : memcpy(swfcl->swfcl_ether->eth_src, eth_addr, ETHER_ADDR_LEN);
2707 0 : break;
2708 : case OFP_XM_T_ETH_DST:
2709 0 : memcpy(swfcl->swfcl_ether->eth_dst, eth_addr, ETHER_ADDR_LEN);
2710 0 : break;
2711 : case OFP_XM_T_ARP_SHA:
2712 0 : memcpy(swfcl->swfcl_arp->arp_sha, eth_addr, ETHER_ADDR_LEN);
2713 0 : break;
2714 : case OFP_XM_T_ARP_THA:
2715 0 : memcpy(swfcl->swfcl_arp->arp_tha, eth_addr, ETHER_ADDR_LEN);
2716 0 : break;
2717 : case OFP_XM_T_IPV6_ND_TLL:
2718 : case OFP_XM_T_IPV6_ND_SLL:
2719 0 : memcpy(swfcl->swfcl_nd6->nd6_lladdr, eth_addr, ETHER_ADDR_LEN);
2720 0 : break;
2721 : }
2722 :
2723 0 : return (0);
2724 : }
2725 :
2726 : #ifdef INET6
2727 : int
2728 0 : swofp_ox_match_ipv6_addr(struct switch_flow_classify *swfcl,
2729 : struct ofp_ox_match *oxm)
2730 : {
2731 0 : struct in6_addr in, mth, mask = in6mask128;
2732 :
2733 0 : switch (OFP_OXM_GET_FIELD(oxm)) {
2734 : case OFP_XM_NXMT_TUNNEL_IPV6_SRC:
2735 : case OFP_XM_NXMT_TUNNEL_IPV6_DST:
2736 0 : if (swfcl->swfcl_tunnel == NULL)
2737 0 : return (1);
2738 : break;
2739 : case OFP_XM_T_IPV6_SRC:
2740 : case OFP_XM_T_IPV6_DST:
2741 0 : if (swfcl->swfcl_ipv6 == NULL)
2742 0 : return (1);
2743 : break;
2744 : case OFP_XM_T_IPV6_ND_TARGET:
2745 0 : if (swfcl->swfcl_nd6 == NULL)
2746 0 : return (1);
2747 : break;
2748 : default:
2749 0 : return (1);
2750 : }
2751 :
2752 0 : switch (OFP_OXM_GET_FIELD(oxm)) {
2753 : case OFP_XM_NXMT_TUNNEL_IPV6_SRC:
2754 0 : in = swfcl->swfcl_tunnel->tun_ipv6_src;
2755 0 : break;
2756 : case OFP_XM_NXMT_TUNNEL_IPV6_DST:
2757 0 : in = swfcl->swfcl_tunnel->tun_ipv6_dst;
2758 0 : break;
2759 : case OFP_XM_T_IPV6_SRC:
2760 0 : in = swfcl->swfcl_ipv6->ipv6_src;
2761 0 : break;
2762 : case OFP_XM_T_IPV6_DST:
2763 0 : in = swfcl->swfcl_ipv6->ipv6_dst;
2764 0 : break;
2765 : case OFP_XM_T_IPV6_ND_TARGET:
2766 0 : in = swfcl->swfcl_nd6->nd6_target;
2767 0 : break;
2768 : }
2769 :
2770 0 : memcpy(&mth, oxm->oxm_value, sizeof(mth));
2771 :
2772 0 : if (OFP_OXM_GET_HASMASK(oxm)) {
2773 0 : memcpy(&mask, oxm->oxm_value + sizeof(mth),
2774 : sizeof(mask));
2775 :
2776 0 : in.s6_addr32[0] &= mask.s6_addr32[0];
2777 0 : in.s6_addr32[1] &= mask.s6_addr32[1];
2778 0 : in.s6_addr32[2] &= mask.s6_addr32[2];
2779 0 : in.s6_addr32[3] &= mask.s6_addr32[3];
2780 :
2781 0 : mth.s6_addr32[0] &= mask.s6_addr32[0];
2782 0 : mth.s6_addr32[1] &= mask.s6_addr32[1];
2783 0 : mth.s6_addr32[2] &= mask.s6_addr32[2];
2784 0 : mth.s6_addr32[3] &= mask.s6_addr32[3];
2785 0 : }
2786 :
2787 0 : return memcmp(&in, &mth, sizeof(in));
2788 0 : }
2789 : #endif /* INET6 */
2790 :
2791 : int
2792 0 : swofp_ox_match_ipv4_addr(struct switch_flow_classify *swfcl,
2793 : struct ofp_ox_match *oxm)
2794 : {
2795 : uint32_t in, mth, mask;
2796 :
2797 0 : switch (OFP_OXM_GET_FIELD(oxm)) {
2798 : case OFP_XM_NXMT_TUNNEL_IPV4_SRC:
2799 : case OFP_XM_NXMT_TUNNEL_IPV4_DST:
2800 0 : if (swfcl->swfcl_tunnel == NULL)
2801 0 : return (1);
2802 : break;
2803 : case OFP_XM_T_IPV4_SRC:
2804 : case OFP_XM_T_IPV4_DST:
2805 0 : if (swfcl->swfcl_ipv4 == NULL)
2806 0 : return (1);
2807 : break;
2808 : case OFP_XM_T_ARP_SPA:
2809 : case OFP_XM_T_ARP_TPA:
2810 0 : if (swfcl->swfcl_arp == NULL)
2811 0 : return (1);
2812 : break;
2813 : default:
2814 0 : return (1);
2815 : }
2816 :
2817 0 : switch (OFP_OXM_GET_FIELD(oxm)) {
2818 : case OFP_XM_NXMT_TUNNEL_IPV4_SRC:
2819 0 : in = swfcl->swfcl_tunnel->tun_ipv4_src.s_addr;
2820 0 : break;
2821 : case OFP_XM_NXMT_TUNNEL_IPV4_DST:
2822 0 : in = swfcl->swfcl_tunnel->tun_ipv4_dst.s_addr;
2823 0 : break;
2824 : case OFP_XM_T_IPV4_SRC:
2825 0 : in = swfcl->swfcl_ipv4->ipv4_src;
2826 0 : break;
2827 : case OFP_XM_T_IPV4_DST:
2828 0 : in = swfcl->swfcl_ipv4->ipv4_dst;
2829 0 : break;
2830 : case OFP_XM_T_ARP_SPA:
2831 0 : in = swfcl->swfcl_arp->arp_sip;
2832 0 : break;
2833 : case OFP_XM_T_ARP_TPA:
2834 0 : in = swfcl->swfcl_arp->arp_tip;
2835 0 : break;
2836 : }
2837 :
2838 0 : memcpy(&mth, oxm->oxm_value, sizeof(uint32_t));
2839 :
2840 0 : if (OFP_OXM_GET_HASMASK(oxm))
2841 0 : memcpy(&mask, oxm->oxm_value + sizeof(uint32_t),
2842 : sizeof(uint32_t));
2843 : else
2844 : mask = UINT32_MAX;
2845 :
2846 0 : return !((in & mask) == (mth & mask));
2847 0 : }
2848 :
2849 : int
2850 0 : swofp_ox_match_vlan_vid(struct switch_flow_classify *swfcl,
2851 : struct ofp_ox_match *oxm)
2852 : {
2853 : uint16_t in, mth, mask = 0;
2854 :
2855 0 : if (swfcl->swfcl_vlan == NULL)
2856 0 : return (1);
2857 :
2858 0 : in = swfcl->swfcl_vlan->vlan_vid;
2859 0 : memcpy(&mth, oxm->oxm_value, sizeof(uint16_t));
2860 :
2861 0 : if (OFP_OXM_GET_HASMASK(oxm))
2862 0 : memcpy(&mask, oxm->oxm_value + sizeof(uint16_t),
2863 : sizeof(uint16_t));
2864 : else
2865 : mask = UINT16_MAX;
2866 :
2867 : /*
2868 : * OpenFlow Switch Specification ver 1.3.5 says if oxm value
2869 : * is OFP_XM_VID_NONE, matches only packets without a VLAN tag
2870 : */
2871 0 : if (mth == htons(OFP_XM_VID_NONE))
2872 0 : return (1);
2873 :
2874 : /*
2875 : * OpenFlow Switch Specification ver 1.3.5 says if oxm value and mask
2876 : * is OFP_XM_VID_PRESENT, matches only packets with a VLAN tag
2877 : * regardless of its value.
2878 : */
2879 0 : if (ntohs(mth) == OFP_XM_VID_PRESENT &&
2880 0 : ntohs(mask) == OFP_XM_VID_PRESENT)
2881 0 : return (0);
2882 :
2883 0 : in &= htons(EVL_VLID_MASK);
2884 0 : mth &= htons(EVL_VLID_MASK);
2885 :
2886 0 : return !((in & mask) == (mth & mask));
2887 0 : }
2888 :
2889 : int
2890 0 : swofp_ox_match_uint8(struct switch_flow_classify *swfcl,
2891 : struct ofp_ox_match *oxm)
2892 : {
2893 : uint8_t in, mth;
2894 :
2895 0 : switch (OFP_OXM_GET_FIELD(oxm)) {
2896 : case OFP_XM_T_VLAN_PCP:
2897 0 : if (swfcl->swfcl_vlan == NULL)
2898 0 : return (1);
2899 : break;
2900 : case OFP_XM_T_IP_DSCP:
2901 : case OFP_XM_T_IP_ECN:
2902 : case OFP_XM_T_IP_PROTO:
2903 0 : if ((swfcl->swfcl_ipv4 == NULL &&
2904 0 : swfcl->swfcl_ipv6 == NULL))
2905 0 : return (1);
2906 : break;
2907 : case OFP_XM_T_ICMPV4_CODE:
2908 : case OFP_XM_T_ICMPV4_TYPE:
2909 0 : if (swfcl->swfcl_icmpv4 == NULL)
2910 0 : return (1);
2911 : break;
2912 : case OFP_XM_T_ICMPV6_CODE:
2913 : case OFP_XM_T_ICMPV6_TYPE:
2914 0 : if (swfcl->swfcl_icmpv6 == NULL)
2915 0 : return (1);
2916 : break;
2917 : default:
2918 0 : return (1);
2919 : }
2920 :
2921 0 : switch (OFP_OXM_GET_FIELD(oxm)) {
2922 : case OFP_XM_T_VLAN_PCP:
2923 0 : in = swfcl->swfcl_vlan->vlan_pcp;
2924 0 : break;
2925 : case OFP_XM_T_IP_DSCP:
2926 0 : if (swfcl->swfcl_ipv4)
2927 0 : in = swfcl->swfcl_ipv4->ipv4_tos >> 2;
2928 : else
2929 0 : in = swfcl->swfcl_ipv6->ipv6_tclass >> 2;
2930 : break;
2931 : case OFP_XM_T_IP_ECN:
2932 0 : if (swfcl->swfcl_ipv4)
2933 0 : in = (swfcl->swfcl_ipv4->ipv4_tos) & IPTOS_ECN_MASK;
2934 : else
2935 0 : in = (swfcl->swfcl_ipv6->ipv6_tclass) & IPTOS_ECN_MASK;
2936 : break;
2937 : case OFP_XM_T_IP_PROTO:
2938 0 : if (swfcl->swfcl_ipv4)
2939 0 : in = swfcl->swfcl_ipv4->ipv4_proto;
2940 : else
2941 0 : in = swfcl->swfcl_ipv6->ipv6_nxt;
2942 : break;
2943 : case OFP_XM_T_ICMPV4_CODE:
2944 0 : in = swfcl->swfcl_icmpv4->icmpv4_code;
2945 0 : break;
2946 : case OFP_XM_T_ICMPV4_TYPE:
2947 0 : in = swfcl->swfcl_icmpv4->icmpv4_type;
2948 0 : break;
2949 : case OFP_XM_T_ICMPV6_CODE:
2950 0 : in = swfcl->swfcl_icmpv6->icmpv6_code;
2951 0 : break;
2952 : case OFP_XM_T_ICMPV6_TYPE:
2953 0 : in = swfcl->swfcl_icmpv6->icmpv6_type;
2954 0 : break;
2955 : }
2956 :
2957 0 : memcpy(&mth, oxm->oxm_value, sizeof(uint8_t));
2958 :
2959 0 : return !(in == mth);
2960 :
2961 0 : }
2962 :
2963 : int
2964 0 : swofp_ox_match_uint16(struct switch_flow_classify *swfcl,
2965 : struct ofp_ox_match *oxm)
2966 : {
2967 : uint16_t in, mth;
2968 :
2969 0 : switch (OFP_OXM_GET_FIELD(oxm)) {
2970 : case OFP_XM_T_ETH_TYPE:
2971 0 : if (swfcl->swfcl_ether == NULL)
2972 0 : return (1);
2973 : break;
2974 : case OFP_XM_T_TCP_SRC:
2975 : case OFP_XM_T_TCP_DST:
2976 0 : if (swfcl->swfcl_tcp == NULL)
2977 0 : return (1);
2978 : break;
2979 : case OFP_XM_T_UDP_SRC:
2980 : case OFP_XM_T_UDP_DST:
2981 0 : if (swfcl->swfcl_udp == NULL)
2982 0 : return (1);
2983 : break;
2984 : case OFP_XM_T_ARP_OP:
2985 0 : if (swfcl->swfcl_arp == NULL)
2986 0 : return (1);
2987 : break;
2988 : default:
2989 0 : return (1);
2990 : }
2991 :
2992 0 : switch (OFP_OXM_GET_FIELD(oxm)) {
2993 : case OFP_XM_T_ETH_TYPE:
2994 0 : in = swfcl->swfcl_ether->eth_type;
2995 0 : break;
2996 : case OFP_XM_T_TCP_SRC:
2997 0 : in = swfcl->swfcl_tcp->tcp_src;
2998 0 : break;
2999 : case OFP_XM_T_TCP_DST:
3000 0 : in = swfcl->swfcl_tcp->tcp_dst;
3001 0 : break;
3002 : case OFP_XM_T_UDP_SRC:
3003 0 : in = swfcl->swfcl_udp->udp_src;
3004 0 : break;
3005 : case OFP_XM_T_UDP_DST:
3006 0 : in = swfcl->swfcl_udp->udp_dst;
3007 0 : break;
3008 : case OFP_XM_T_ARP_OP:
3009 0 : in = swfcl->swfcl_arp->_arp_op;
3010 0 : break;
3011 : }
3012 :
3013 0 : memcpy(&mth, oxm->oxm_value, sizeof(uint16_t));
3014 :
3015 0 : return !(in == mth);
3016 0 : }
3017 :
3018 : int
3019 0 : swofp_ox_match_uint32(struct switch_flow_classify *swfcl,
3020 : struct ofp_ox_match *oxm)
3021 : {
3022 : uint32_t in, mth, mask, nomask = UINT32_MAX;
3023 :
3024 0 : switch (OFP_OXM_GET_FIELD(oxm)) {
3025 : case OFP_XM_T_IN_PORT:
3026 : /* in_port field is always exist in swfcl */
3027 : break;
3028 : case OFP_XM_T_IPV6_FLABEL:
3029 0 : if (swfcl->swfcl_ipv6 == NULL)
3030 0 : return (1);
3031 : break;
3032 : default:
3033 0 : return (1);
3034 : }
3035 :
3036 0 : switch (OFP_OXM_GET_FIELD(oxm)) {
3037 : case OFP_XM_T_IN_PORT:
3038 : /*
3039 : * in_port isn't network byte order becouse
3040 : * it's pipeline match field.
3041 : */
3042 0 : in = htonl(swfcl->swfcl_in_port);
3043 0 : break;
3044 : case OFP_XM_T_IPV6_FLABEL:
3045 0 : in = swfcl->swfcl_ipv6->ipv6_flow_label;
3046 : nomask &= IPV6_FLOWLABEL_MASK;
3047 0 : break;
3048 : }
3049 :
3050 0 : memcpy(&mth, oxm->oxm_value, sizeof(uint32_t));
3051 :
3052 0 : if (OFP_OXM_GET_HASMASK(oxm))
3053 0 : memcpy(&mask, oxm->oxm_value + sizeof(uint32_t),
3054 : sizeof(uint32_t));
3055 : else
3056 : mask = nomask;
3057 :
3058 0 : return !((in & mask) == (mth & mask));
3059 0 : }
3060 :
3061 : int
3062 0 : swofp_ox_match_uint64(struct switch_flow_classify *swfcl,
3063 : struct ofp_ox_match *oxm)
3064 : {
3065 : uint64_t in, mth, mask;
3066 :
3067 0 : switch (OFP_OXM_GET_FIELD(oxm)) {
3068 : case OFP_XM_T_META:
3069 : break;
3070 : case OFP_XM_T_TUNNEL_ID:
3071 0 : if (swfcl->swfcl_tunnel == NULL)
3072 0 : return (1);
3073 : break;
3074 : default:
3075 0 : return (1);
3076 : }
3077 :
3078 0 : switch (OFP_OXM_GET_FIELD(oxm)) {
3079 : case OFP_XM_T_META:
3080 0 : in = swfcl->swfcl_metadata;
3081 0 : break;
3082 : case OFP_XM_T_TUNNEL_ID:
3083 0 : in = swfcl->swfcl_tunnel->tun_key;
3084 0 : break;
3085 : }
3086 :
3087 0 : memcpy(&mth, oxm->oxm_value, sizeof(uint64_t));
3088 :
3089 0 : if (OFP_OXM_GET_HASMASK(oxm))
3090 0 : memcpy(&mask, oxm->oxm_value + sizeof(uint64_t),
3091 : sizeof(uint64_t));
3092 : else
3093 : mask = UINT64_MAX;
3094 :
3095 0 : return !((in & mask) == (mth & mask));
3096 0 : }
3097 :
3098 : int
3099 0 : swofp_ox_match_ether_addr(struct switch_flow_classify *swfcl,
3100 : struct ofp_ox_match *oxm)
3101 : {
3102 : uint64_t eth_mask = 0x0000FFFFFFFFFFFFULL;
3103 : uint64_t in, mth, mask;
3104 :
3105 0 : switch (OFP_OXM_GET_FIELD(oxm)) {
3106 : case OFP_XM_T_ETH_SRC:
3107 : case OFP_XM_T_ETH_DST:
3108 0 : if (swfcl->swfcl_ether == NULL)
3109 0 : return (1);
3110 : break;
3111 : case OFP_XM_T_ARP_SHA:
3112 : case OFP_XM_T_ARP_THA:
3113 0 : if (swfcl->swfcl_arp == NULL)
3114 0 : return (1);
3115 : break;
3116 : case OFP_XM_T_IPV6_ND_SLL:
3117 : case OFP_XM_T_IPV6_ND_TLL:
3118 0 : if (swfcl->swfcl_nd6 == NULL)
3119 0 : return (1);
3120 : break;
3121 : default:
3122 0 : return (1);
3123 : }
3124 :
3125 0 : switch (OFP_OXM_GET_FIELD(oxm)) {
3126 : case OFP_XM_T_ETH_SRC:
3127 0 : in = *(uint64_t *)(swfcl->swfcl_ether->eth_src);
3128 0 : break;
3129 : case OFP_XM_T_ETH_DST:
3130 0 : in = *(uint64_t *)(swfcl->swfcl_ether->eth_dst);
3131 0 : break;
3132 : case OFP_XM_T_ARP_SHA:
3133 0 : in = *(uint64_t *)(swfcl->swfcl_arp->arp_sha);
3134 0 : break;
3135 : case OFP_XM_T_ARP_THA:
3136 0 : in = *(uint64_t *)(swfcl->swfcl_arp->arp_tha);
3137 0 : break;
3138 : case OFP_XM_T_IPV6_ND_SLL:
3139 : case OFP_XM_T_IPV6_ND_TLL:
3140 0 : in = *(uint64_t *)(swfcl->swfcl_nd6->nd6_lladdr);
3141 0 : break;
3142 : }
3143 :
3144 0 : memcpy(&mth, oxm->oxm_value, ETHER_ADDR_LEN);
3145 0 : if (OFP_OXM_GET_HASMASK(oxm))
3146 0 : memcpy(&mask, oxm->oxm_value + ETHER_ADDR_LEN,
3147 : ETHER_ADDR_LEN);
3148 : else
3149 : mask = UINT64_MAX;
3150 :
3151 0 : return !((in & mask & eth_mask) == (mth & mask & eth_mask));
3152 0 : }
3153 :
3154 : int
3155 0 : swofp_flow_match_by_swfcl(struct ofp_match *om,
3156 : struct switch_flow_classify *swfcl)
3157 : {
3158 : struct ofp_oxm_class *oxm_handler;
3159 : struct ofp_ox_match *oxm;
3160 :
3161 0 : OFP_OXM_FOREACH(om, ntohs(om->om_length), oxm) {
3162 0 : oxm_handler = swofp_lookup_oxm_handler(oxm);
3163 0 : if ((oxm_handler == NULL) ||
3164 0 : (oxm_handler->oxm_match == NULL))
3165 : continue;
3166 :
3167 0 : if (oxm_handler->oxm_match(swfcl, oxm))
3168 0 : return (1);
3169 : }
3170 :
3171 0 : return (0);
3172 0 : }
3173 :
3174 : /* TODO: Optimization */
3175 : struct swofp_flow_entry *
3176 0 : swofp_flow_lookup(struct swofp_flow_table *swft,
3177 : struct switch_flow_classify *swfcl)
3178 : {
3179 : struct swofp_flow_entry *swfe, *interim = NULL;
3180 :
3181 0 : LIST_FOREACH(swfe, &swft->swft_flow_list, swfe_next) {
3182 0 : if (swofp_flow_match_by_swfcl(swfe->swfe_match, swfcl) != 0)
3183 : continue;
3184 :
3185 0 : if (interim == NULL ||
3186 0 : (interim->swfe_priority < swfe->swfe_priority))
3187 0 : interim = swfe;
3188 : }
3189 :
3190 0 : swft->swft_lookup_count++;
3191 0 : if (interim)
3192 0 : swft->swft_matched_count++;
3193 :
3194 0 : return interim;
3195 : }
3196 :
3197 : /*
3198 : * OpenFlow protocol push/pop VLAN
3199 : */
3200 :
3201 : /* Expand 802.1Q VLAN header from M_VLANTAG mtag if it is exist. */
3202 : struct mbuf *
3203 0 : swofp_expand_8021q_tag(struct mbuf *m)
3204 : {
3205 0 : if ((m->m_flags & M_VLANTAG) == 0)
3206 0 : return (m);
3207 :
3208 : /* H/W tagging supports only 802.1Q */
3209 0 : return (vlan_inject(m, ETHERTYPE_VLAN,
3210 0 : EVL_VLANOFTAG(m->m_pkthdr.ether_vtag) |
3211 0 : EVL_PRIOFTAG(m->m_pkthdr.ether_vtag)));
3212 0 : }
3213 :
3214 : struct mbuf *
3215 0 : swofp_action_pop_vlan(struct switch_softc *sc, struct mbuf *m,
3216 : struct swofp_pipeline_desc *swpld, struct ofp_action_header *oah)
3217 : {
3218 0 : struct switch_flow_classify *swfcl = swpld->swpld_swfcl;
3219 : struct ether_vlan_header *evl;
3220 0 : struct ether_header eh;
3221 :
3222 : /* no vlan tag existing */
3223 0 : if (swfcl->swfcl_vlan == NULL) {
3224 0 : m_freem(m);
3225 0 : return (NULL);
3226 : }
3227 :
3228 0 : if ((m->m_flags & M_VLANTAG)) {
3229 0 : m->m_flags &= ~M_VLANTAG;
3230 0 : return (m);
3231 : }
3232 :
3233 0 : if (m->m_len < sizeof(*evl) &&
3234 0 : (m = m_pullup(m, sizeof(*evl))) == NULL)
3235 0 : return (NULL);
3236 0 : evl = mtod(m, struct ether_vlan_header *);
3237 :
3238 0 : if ((ntohs(evl->evl_encap_proto) != ETHERTYPE_VLAN) &&
3239 0 : (ntohs(evl->evl_encap_proto) != ETHERTYPE_QINQ)) {
3240 0 : m_freem(m);
3241 0 : return (NULL);
3242 : }
3243 :
3244 0 : m_copydata(m, 0, ETHER_HDR_LEN, (caddr_t)&eh);
3245 0 : eh.ether_type = evl->evl_proto;
3246 :
3247 0 : m_adj(m, sizeof(*evl));
3248 0 : M_PREPEND(m, sizeof(eh), M_DONTWAIT);
3249 0 : if (m == NULL)
3250 0 : return (NULL);
3251 0 : m_copyback(m, 0, sizeof(eh), &eh, M_NOWAIT);
3252 :
3253 : /*
3254 : * Update classify for vlan
3255 : */
3256 0 : if (m->m_len < sizeof(*evl) &&
3257 0 : (m = m_pullup(m, sizeof(*evl))) == NULL)
3258 0 : return (NULL);
3259 0 : evl = mtod(m, struct ether_vlan_header *);
3260 :
3261 0 : if (ntohs(evl->evl_encap_proto) == ETHERTYPE_VLAN) {
3262 0 : swfcl->swfcl_vlan->vlan_tpid = htons(ETHERTYPE_VLAN);
3263 0 : swfcl->swfcl_vlan->vlan_vid =
3264 0 : (evl->evl_tag & htons(EVL_VLID_MASK));
3265 0 : swfcl->swfcl_vlan->vlan_pcp =
3266 0 : EVL_PRIOFTAG(ntohs(evl->evl_tag));
3267 0 : } else {
3268 0 : pool_put(&swfcl_pool, swfcl->swfcl_vlan);
3269 0 : swfcl->swfcl_vlan = NULL;
3270 : }
3271 :
3272 0 : return (m);
3273 0 : }
3274 :
3275 : struct mbuf *
3276 0 : swofp_action_push_vlan(struct switch_softc *sc, struct mbuf *m,
3277 : struct swofp_pipeline_desc *swpld, struct ofp_action_header *oah)
3278 : {
3279 0 : struct switch_flow_classify *swfcl = swpld->swpld_swfcl;
3280 : struct ofp_action_push *oap;
3281 : struct ether_header *eh;
3282 0 : struct ether_vlan_header evh;
3283 :
3284 : /*
3285 : * Expands 802.1Q VLAN header from M_VLANTAG because switch(4) doesn't
3286 : * use H/W tagging on port currently.
3287 : */
3288 0 : m = swofp_expand_8021q_tag(m);
3289 0 : if (m == NULL)
3290 0 : return (NULL);
3291 :
3292 0 : oap = (struct ofp_action_push *)oah;
3293 :
3294 0 : if ((m->m_len < sizeof(*eh)) &&
3295 0 : ((m = m_pullup(m, sizeof(*eh))) == NULL)) {
3296 0 : return (NULL);
3297 : }
3298 0 : eh = mtod(m, struct ether_header *);
3299 :
3300 0 : switch (ntohs(oap->ap_ethertype)) {
3301 : case ETHERTYPE_VLAN:
3302 0 : if ((ntohs(eh->ether_type) == ETHERTYPE_VLAN) ||
3303 0 : (ntohs(eh->ether_type) == ETHERTYPE_QINQ)) {
3304 0 : m_freem(m);
3305 0 : return (NULL);
3306 : }
3307 : break;
3308 : case ETHERTYPE_QINQ:
3309 0 : if (ntohs(eh->ether_type) != ETHERTYPE_VLAN) {
3310 0 : m_freem(m);
3311 0 : return (NULL);
3312 : }
3313 : break;
3314 : default:
3315 0 : m_freem(m);
3316 0 : return (NULL);
3317 : }
3318 :
3319 0 : if (swfcl->swfcl_vlan == NULL) {
3320 0 : swfcl->swfcl_vlan = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
3321 0 : if (swfcl->swfcl_vlan == NULL) {
3322 0 : m_freem(m);
3323 0 : return (NULL);
3324 : }
3325 : /* puts default vlan */
3326 0 : swfcl->swfcl_vlan->vlan_vid = htons(1);
3327 0 : }
3328 :
3329 0 : m_copydata(m, 0, ETHER_HDR_LEN, (caddr_t)&evh);
3330 0 : evh.evl_proto = evh.evl_encap_proto;
3331 0 : evh.evl_encap_proto = oap->ap_ethertype;
3332 0 : evh.evl_tag = (swfcl->swfcl_vlan->vlan_vid |
3333 0 : htons(swfcl->swfcl_vlan->vlan_pcp << EVL_PRIO_BITS));
3334 :
3335 0 : m_adj(m, ETHER_HDR_LEN);
3336 0 : M_PREPEND(m, sizeof(evh), M_DONTWAIT);
3337 0 : if (m == NULL)
3338 0 : return (NULL);
3339 :
3340 0 : m_copyback(m, 0, sizeof(evh), &evh, M_NOWAIT);
3341 :
3342 : /*
3343 : * Update VLAN classification
3344 : */
3345 0 : swfcl->swfcl_vlan->vlan_tpid = oap->ap_ethertype;
3346 0 : swfcl->swfcl_vlan->vlan_vid = evh.evl_tag & htons(EVL_VLID_MASK);
3347 0 : swfcl->swfcl_vlan->vlan_pcp = EVL_PRIOFTAG(ntohs(evh.evl_tag));
3348 :
3349 0 : return (m);
3350 0 : }
3351 :
3352 :
3353 : /*
3354 : * OpenFlow protocol packet in
3355 : */
3356 : int
3357 0 : swofp_action_output_controller(struct switch_softc *sc, struct mbuf *m0,
3358 : struct swofp_pipeline_desc *swpld , uint16_t frame_max_len, uint8_t reason)
3359 : {
3360 0 : struct swofp_ofs *swofs = sc->sc_ofs;
3361 0 : struct switch_flow_classify *swfcl = swpld->swpld_swfcl;
3362 : struct ofp_packet_in *pin;
3363 : struct ofp_match *om;
3364 : struct ofp_ox_match *oxm;
3365 : struct mbuf *m;
3366 : caddr_t tail;
3367 : int match_len;
3368 :
3369 0 : if (reason != OFP_PKTIN_REASON_ACTION)
3370 0 : frame_max_len = swofs->swofs_switch_config.cfg_miss_send_len;
3371 : /*
3372 : * ofp_match in packet_in has only OFP_XM_T_INPORT, OFP_MX_T_META,
3373 : * OFP_XM_NXMT_TUNNEL_IPV{4|6}_{SRC|DST} and OFP_MX_T_TUNNEL_ID that
3374 : * if exist, so ofp_match length is determined here.
3375 : */
3376 : match_len = (
3377 : sizeof(*om) + /* struct ofp_match */
3378 : (sizeof(*oxm) + sizeof(uint32_t)) + /* OFP_MX_T_IMPORT */
3379 : (sizeof(*oxm) + sizeof(uint64_t)) /* OFP_MX_T_META */
3380 : );
3381 :
3382 0 : if (swfcl->swfcl_tunnel) {
3383 : /* OFP_MX_T_TUNNEL_ID */
3384 : match_len += (sizeof(*oxm) + sizeof(uint64_t));
3385 :
3386 : /* OFP_XM_NXMT_TUNNEL_IPV{4|6}_{SRC|DST} */
3387 0 : if (swfcl->swfcl_tunnel->tun_af == AF_INET)
3388 0 : match_len += (sizeof(*oxm) + sizeof(uint32_t)) * 2;
3389 0 : else if (swfcl->swfcl_tunnel->tun_af == AF_INET6)
3390 0 : match_len += (sizeof(*oxm) +
3391 : sizeof(struct in6_addr)) * 2;
3392 : }
3393 :
3394 0 : MGETHDR(m, M_DONTWAIT, MT_DATA);
3395 0 : if (m == NULL) {
3396 0 : m_freem(m0);
3397 0 : return (ENOBUFS);
3398 : }
3399 0 : if ((sizeof(*pin) + match_len) >= MHLEN) {
3400 0 : MCLGET(m, M_DONTWAIT);
3401 0 : if ((m->m_flags & M_EXT) == 0) {
3402 0 : m_freem(m);
3403 0 : m_freem(m0);
3404 0 : return (ENOBUFS);
3405 : }
3406 : }
3407 :
3408 0 : pin = mtod(m, struct ofp_packet_in *);
3409 0 : memset(pin, 0, sizeof(*pin));
3410 :
3411 0 : pin->pin_oh.oh_version = OFP_V_1_3;
3412 0 : pin->pin_oh.oh_type = OFP_T_PACKET_IN;
3413 0 : pin->pin_oh.oh_xid = htonl(swofs->swofs_xidnxt++);
3414 :
3415 0 : pin->pin_buffer_id = htonl(OFP_PKTOUT_NO_BUFFER);
3416 0 : pin->pin_table_id = swpld->swpld_table_id;
3417 0 : pin->pin_cookie = swpld->swpld_cookie;
3418 0 : pin->pin_reason = reason;
3419 :
3420 0 : if (frame_max_len) {
3421 : /*
3422 : * The switch should only truncate packets if it implements
3423 : * buffering or the controller might end up sending PACKET_OUT
3424 : * responses with truncated packets that will eventually end
3425 : * up on the network.
3426 : */
3427 0 : if (frame_max_len < m0->m_pkthdr.len) {
3428 0 : m_freem(m);
3429 0 : m_freem(m0);
3430 0 : return (EMSGSIZE);
3431 : }
3432 0 : pin->pin_total_len = htons(m0->m_pkthdr.len);
3433 0 : }
3434 :
3435 : /*
3436 : * It's ensured continuous memory space between ofp_mach space
3437 : */
3438 0 : om = &pin->pin_match;
3439 0 : swofp_ox_match_put_start(om);
3440 0 : swofp_ox_match_put_uint32(om, OFP_XM_T_IN_PORT, swfcl->swfcl_in_port);
3441 0 : swofp_ox_match_put_uint64(om, OFP_XM_T_META, swpld->swpld_metadata);
3442 0 : if (swfcl->swfcl_tunnel) {
3443 0 : swofp_ox_match_put_uint64(om, OFP_XM_T_TUNNEL_ID,
3444 0 : be64toh(swfcl->swfcl_tunnel->tun_key));
3445 :
3446 0 : if (swfcl->swfcl_tunnel->tun_af == AF_INET) {
3447 0 : swofp_nx_match_put(om, OFP_XM_NXMT_TUNNEL_IPV4_SRC,
3448 : sizeof(uint32_t),
3449 0 : (caddr_t)&swfcl->swfcl_tunnel->tun_ipv4_src);
3450 0 : swofp_nx_match_put(om, OFP_XM_NXMT_TUNNEL_IPV4_DST,
3451 : sizeof(uint32_t),
3452 0 : (caddr_t)&swfcl->swfcl_tunnel->tun_ipv4_dst);
3453 0 : } else if (swfcl->swfcl_tunnel->tun_af == AF_INET6) {
3454 0 : swofp_nx_match_put(om, OFP_XM_NXMT_TUNNEL_IPV6_SRC,
3455 : sizeof(struct in6_addr),
3456 0 : (caddr_t)&swfcl->swfcl_tunnel->tun_ipv6_src);
3457 0 : swofp_nx_match_put(om, OFP_XM_NXMT_TUNNEL_IPV6_DST,
3458 : sizeof(struct in6_addr),
3459 0 : (caddr_t)&swfcl->swfcl_tunnel->tun_ipv6_dst);
3460 0 : }
3461 : }
3462 0 : match_len = swofp_ox_match_put_end(om); /* match_len include padding */
3463 :
3464 : /*
3465 : * Adjust alignment for Ethernet header
3466 : */
3467 0 : tail = (caddr_t)pin +
3468 0 : offsetof(struct ofp_packet_in, pin_match) + match_len;
3469 0 : memset(tail, 0, ETHER_ALIGN);
3470 :
3471 0 : m->m_len = m->m_pkthdr.len =
3472 0 : offsetof(struct ofp_packet_in, pin_match) + match_len + ETHER_ALIGN;
3473 :
3474 0 : pin->pin_oh.oh_length =
3475 0 : htons(m->m_pkthdr.len + ntohs(pin->pin_total_len));
3476 :
3477 0 : if (frame_max_len) {
3478 : /* m_cat() doesn't update the m_pkthdr.len */
3479 0 : m_cat(m, m0);
3480 0 : m->m_pkthdr.len += ntohs(pin->pin_total_len);
3481 0 : }
3482 :
3483 0 : (void)swofp_output(sc, m);
3484 :
3485 0 : return (0);
3486 0 : }
3487 :
3488 : struct mbuf *
3489 0 : swofp_action_output(struct switch_softc *sc, struct mbuf *m,
3490 : struct swofp_pipeline_desc *swpld, struct ofp_action_header *oah)
3491 : {
3492 : struct ofp_action_output *oao;
3493 : struct switch_port *swpo;
3494 : struct mbuf *mc;
3495 :
3496 0 : m->m_pkthdr.csum_flags = 0;
3497 :
3498 0 : if ((m = swofp_apply_set_field(m, swpld)) == NULL)
3499 0 : return (NULL);
3500 :
3501 0 : oao = (struct ofp_action_output *)oah;
3502 :
3503 0 : switch (ntohl(oao->ao_port)) {
3504 : case OFP_PORT_CONTROLLER:
3505 : case OFP_PORT_FLOWTABLE:
3506 0 : if ((mc = m_dup_pkt(m, ETHER_ALIGN, M_NOWAIT)) == NULL) {
3507 0 : m_freem(m);
3508 0 : return (NULL);
3509 : }
3510 : }
3511 :
3512 0 : switch (ntohl(oao->ao_port)) {
3513 : case OFP_PORT_CONTROLLER:
3514 0 : swofp_action_output_controller(sc, mc, swpld,
3515 0 : ntohs(oao->ao_max_len), swpld->swpld_tablemiss ?
3516 : OFP_PKTIN_REASON_NO_MATCH : OFP_PKTIN_REASON_ACTION);
3517 0 : break;
3518 : case OFP_PORT_FLOWTABLE:
3519 0 : swofp_forward_ofs(sc, swpld->swpld_swfcl, mc);
3520 0 : break;
3521 : case OFP_PORT_FLOOD:
3522 0 : TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next) {
3523 0 : if (swpo->swpo_port_no !=
3524 0 : swpld->swpld_swfcl->swfcl_in_port)
3525 0 : TAILQ_INSERT_HEAD(&swpld->swpld_fwdp_q, swpo,
3526 : swpo_fwdp_next);
3527 : }
3528 : break;
3529 : case OFP_PORT_INPUT:
3530 0 : TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next) {
3531 0 : if (swpo->swpo_port_no ==
3532 0 : swpld->swpld_swfcl->swfcl_in_port) {
3533 0 : TAILQ_INSERT_HEAD(&swpld->swpld_fwdp_q, swpo,
3534 : swpo_fwdp_next);
3535 0 : break;
3536 : }
3537 : }
3538 : break;
3539 : case OFP_PORT_NORMAL:
3540 : case OFP_PORT_ALL:
3541 : case OFP_PORT_ANY:
3542 : /* no support yet */
3543 : break;
3544 : case OFP_PORT_LOCAL:
3545 0 : TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next) {
3546 0 : if (swpo->swpo_flags & IFBIF_LOCAL) {
3547 0 : TAILQ_INSERT_HEAD(&swpld->swpld_fwdp_q, swpo,
3548 : swpo_fwdp_next);
3549 0 : break;
3550 : }
3551 : }
3552 : break;
3553 : default:
3554 0 : TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next) {
3555 0 : if (swpo->swpo_port_no == ntohl(oao->ao_port))
3556 0 : TAILQ_INSERT_HEAD(&swpld->swpld_fwdp_q, swpo,
3557 : swpo_fwdp_next);
3558 : }
3559 : break;
3560 : }
3561 :
3562 0 : if (!TAILQ_EMPTY(&swpld->swpld_fwdp_q)) {
3563 0 : if ((mc = m_dup_pkt(m, ETHER_ALIGN, M_NOWAIT)) == NULL) {
3564 0 : m_freem(m);
3565 0 : return (NULL);
3566 : }
3567 0 : switch_port_egress(sc, &swpld->swpld_fwdp_q, mc);
3568 0 : TAILQ_INIT(&swpld->swpld_fwdp_q);
3569 0 : }
3570 :
3571 0 : return (m);
3572 0 : }
3573 :
3574 :
3575 : struct mbuf *
3576 0 : swofp_action_group_all(struct switch_softc *sc, struct mbuf *m,
3577 : struct swofp_pipeline_desc *swpld, struct swofp_group_entry *swge)
3578 : {
3579 : struct ofp_bucket *bucket;
3580 : struct ofp_action_header *ah;
3581 : int actions_len;
3582 : struct swofp_pipeline_desc *clean_swpld = NULL;
3583 0 : struct switch_flow_classify swfcl;
3584 : struct mbuf *n;
3585 :
3586 : /* Don't do anything if we don't have buckets. */
3587 0 : if (swge->swge_buckets == NULL)
3588 0 : return (m);
3589 :
3590 0 : OFP_BUCKETS_FOREACH(swge->swge_buckets,
3591 : swge->swge_buckets_len, bucket) {
3592 0 : if (switch_swfcl_dup(swpld->swpld_swfcl, &swfcl) != 0)
3593 : goto failed;
3594 :
3595 0 : clean_swpld = swofp_pipeline_desc_create(&swfcl);
3596 0 : if (clean_swpld == NULL)
3597 : goto failed;
3598 :
3599 0 : if ((n = m_dup_pkt(m, ETHER_ALIGN, M_NOWAIT)) == NULL)
3600 : goto failed;
3601 :
3602 0 : actions_len = (ntohs(bucket->b_len) -
3603 : (offsetof(struct ofp_bucket, b_actions)));
3604 :
3605 0 : OFP_ACTION_FOREACH(bucket->b_actions, actions_len, ah) {
3606 0 : n = swofp_execute_action(sc, n, clean_swpld, ah);
3607 0 : if (n == NULL)
3608 : goto failed;
3609 : }
3610 :
3611 0 : m_freem(n);
3612 0 : swofp_pipeline_desc_destroy(clean_swpld);
3613 : clean_swpld = NULL;
3614 0 : switch_swfcl_free(&swfcl);
3615 : }
3616 :
3617 0 : return (m);
3618 :
3619 : failed:
3620 0 : m_freem(m);
3621 0 : if (clean_swpld)
3622 0 : swofp_pipeline_desc_destroy(clean_swpld);
3623 0 : return (NULL);
3624 0 : }
3625 :
3626 : struct mbuf *
3627 0 : swofp_action_group(struct switch_softc *sc, struct mbuf *m,
3628 : struct swofp_pipeline_desc *swpld, struct ofp_action_header *oah)
3629 : {
3630 : struct ofp_action_group *oag;
3631 : struct swofp_group_entry *swge;
3632 :
3633 0 : oag = (struct ofp_action_group *)oah;
3634 :
3635 0 : swge = swofp_group_entry_lookup(sc, ntohl(oag->ag_group_id));
3636 0 : if (swge == NULL) {
3637 0 : m_freem(m);
3638 0 : return (NULL);
3639 : }
3640 :
3641 0 : swge->swge_packet_count++;
3642 0 : swge->swge_byte_count += m->m_pkthdr.len;
3643 :
3644 0 : switch (swge->swge_type) {
3645 : case OFP_GROUP_T_ALL:
3646 0 : return swofp_action_group_all(sc, m, swpld, swge);
3647 : case OFP_GROUP_T_INDIRECT:
3648 : case OFP_GROUP_T_FAST_FAILOVER:
3649 : case OFP_GROUP_T_SELECT:
3650 0 : m_freem(m);
3651 0 : return (NULL);
3652 : }
3653 :
3654 0 : return (m);
3655 0 : }
3656 :
3657 : struct mbuf *
3658 0 : swofp_apply_set_field_udp(struct mbuf *m, int off,
3659 : struct switch_flow_classify *pre_swfcl, struct switch_flow_classify *swfcl)
3660 : {
3661 : struct udphdr *uh;
3662 :
3663 0 : if (m->m_len < (off + sizeof(*uh)) &&
3664 0 : (m = m_pullup(m, off + sizeof(*uh))) == NULL)
3665 0 : return NULL;
3666 :
3667 0 : uh = (struct udphdr *)((m)->m_data + off);
3668 :
3669 0 : if (pre_swfcl->swfcl_udp) {
3670 0 : uh->uh_sport = pre_swfcl->swfcl_udp->udp_src;
3671 0 : uh->uh_dport = pre_swfcl->swfcl_udp->udp_dst;
3672 0 : memcpy(swfcl->swfcl_udp, pre_swfcl->swfcl_udp,
3673 : sizeof(*swfcl->swfcl_udp));
3674 0 : }
3675 :
3676 0 : return (m);
3677 0 : }
3678 :
3679 : struct mbuf *
3680 0 : swofp_apply_set_field_tcp(struct mbuf *m, int off,
3681 : struct switch_flow_classify *pre_swfcl, struct switch_flow_classify *swfcl)
3682 : {
3683 : struct tcphdr *th;
3684 :
3685 0 : if (m->m_len < (off + sizeof(*th)) &&
3686 0 : (m = m_pullup(m, off + sizeof(*th))) == NULL)
3687 0 : return NULL;
3688 :
3689 0 : th = (struct tcphdr *)((m)->m_data + off);
3690 :
3691 0 : if (pre_swfcl->swfcl_tcp) {
3692 0 : th->th_sport = pre_swfcl->swfcl_tcp->tcp_src;
3693 0 : th->th_dport = pre_swfcl->swfcl_tcp->tcp_dst;
3694 :
3695 0 : memcpy(swfcl->swfcl_tcp, pre_swfcl->swfcl_tcp,
3696 : sizeof(*swfcl->swfcl_tcp));
3697 0 : }
3698 :
3699 0 : return (m);
3700 0 : }
3701 :
3702 : #ifdef INET6
3703 : struct mbuf *
3704 0 : swofp_apply_set_field_nd6(struct mbuf *m, int off,
3705 : struct switch_flow_classify *pre_swfcl, struct switch_flow_classify *swfcl)
3706 : {
3707 : struct icmp6_hdr *icmp6;
3708 : struct nd_neighbor_advert *nd_na;
3709 : struct nd_neighbor_solicit *nd_ns;
3710 0 : union nd_opts ndopts;
3711 0 : int icmp6len = m->m_pkthdr.len - off;
3712 : int lladdrlen;
3713 : uint8_t *lladdr;
3714 :
3715 0 : if (pre_swfcl->swfcl_nd6 == NULL)
3716 0 : return (m);
3717 :
3718 0 : IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, sizeof(*icmp6));
3719 0 : if (icmp6 == NULL)
3720 : goto failed;
3721 :
3722 0 : switch (icmp6->icmp6_type) {
3723 : case ND_NEIGHBOR_ADVERT:
3724 0 : if (icmp6len < sizeof(struct nd_neighbor_advert))
3725 : goto failed;
3726 : break;
3727 : case ND_NEIGHBOR_SOLICIT:
3728 0 : if (icmp6len < sizeof(struct nd_neighbor_solicit))
3729 : goto failed;
3730 : break;
3731 : }
3732 :
3733 0 : switch (icmp6->icmp6_type) {
3734 : case ND_NEIGHBOR_ADVERT:
3735 0 : IP6_EXTHDR_GET(nd_na, struct nd_neighbor_advert *, m,
3736 : off, icmp6len);
3737 0 : if (nd_na == NULL)
3738 : goto failed;
3739 :
3740 0 : nd_na->nd_na_target = pre_swfcl->swfcl_nd6->nd6_target;
3741 0 : icmp6len -= sizeof(*nd_na);
3742 0 : nd6_option_init(nd_na + 1, icmp6len, &ndopts);
3743 0 : if (nd6_options(&ndopts) < 0)
3744 : goto failed;
3745 :
3746 0 : if (!ndopts.nd_opts_tgt_lladdr)
3747 : goto failed;
3748 :
3749 0 : lladdr = (char *)(ndopts.nd_opts_tgt_lladdr + 1);
3750 0 : lladdrlen = (ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3) - 2;
3751 :
3752 : /* switch(4) only supports Ethernet interfaces */
3753 0 : if (lladdrlen != ETHER_ADDR_LEN)
3754 : goto failed;
3755 :
3756 0 : memcpy(lladdr, pre_swfcl->swfcl_nd6->nd6_lladdr,
3757 : ETHER_ADDR_LEN);
3758 0 : break;
3759 : case ND_NEIGHBOR_SOLICIT:
3760 0 : IP6_EXTHDR_GET(nd_ns, struct nd_neighbor_solicit *, m,
3761 : off, icmp6len);
3762 0 : if (nd_ns == NULL)
3763 : goto failed;
3764 :
3765 0 : nd_ns->nd_ns_target = pre_swfcl->swfcl_nd6->nd6_target;
3766 0 : icmp6len -= sizeof(*nd_ns);
3767 :
3768 0 : nd6_option_init(nd_ns + 1, icmp6len, &ndopts);
3769 0 : if (nd6_options(&ndopts) < 0)
3770 : goto failed;
3771 :
3772 0 : if (!ndopts.nd_opts_src_lladdr)
3773 : goto failed;
3774 :
3775 0 : lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1);
3776 0 : lladdrlen = (ndopts.nd_opts_src_lladdr->nd_opt_len << 3) - 2;
3777 :
3778 : /* switch(4) only supports Ethernet interfaces */
3779 0 : if (lladdrlen != ETHER_ADDR_LEN)
3780 : goto failed;
3781 0 : memcpy(lladdr, pre_swfcl->swfcl_nd6->nd6_lladdr,
3782 : ETHER_ADDR_LEN);
3783 0 : break;
3784 : }
3785 :
3786 0 : memcpy(swfcl->swfcl_nd6, pre_swfcl->swfcl_nd6,
3787 : sizeof(*swfcl->swfcl_nd6));
3788 :
3789 0 : return (m);
3790 :
3791 : failed:
3792 0 : m_freem(m);
3793 0 : return (NULL);
3794 0 : }
3795 :
3796 : struct mbuf *
3797 0 : swofp_apply_set_field_icmpv6(struct mbuf *m, int off,
3798 : struct switch_flow_classify *pre_swfcl, struct switch_flow_classify *swfcl)
3799 : {
3800 : struct icmp6_hdr *icmp6;
3801 :
3802 0 : IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, sizeof(*icmp6));
3803 0 : if (icmp6 == NULL)
3804 0 : return (NULL); /* m was already freed */
3805 :
3806 0 : if (pre_swfcl->swfcl_icmpv6) {
3807 0 : icmp6->icmp6_type = pre_swfcl->swfcl_icmpv6->icmpv6_type;
3808 0 : icmp6->icmp6_code = pre_swfcl->swfcl_icmpv6->icmpv6_code;
3809 :
3810 0 : memcpy(swfcl->swfcl_icmpv6, pre_swfcl->swfcl_icmpv6,
3811 : sizeof(*swfcl->swfcl_icmpv6));
3812 0 : }
3813 :
3814 0 : m->m_pkthdr.csum_flags |= M_ICMP_CSUM_OUT;
3815 :
3816 0 : switch (icmp6->icmp6_type) {
3817 : case ND_NEIGHBOR_ADVERT:
3818 : case ND_NEIGHBOR_SOLICIT:
3819 0 : return swofp_apply_set_field_nd6(m, off, pre_swfcl, swfcl);
3820 : }
3821 :
3822 0 : return (m);
3823 0 : }
3824 : #endif /* INET6 */
3825 :
3826 : struct mbuf *
3827 0 : swofp_apply_set_field_icmpv4(struct mbuf *m, int off,
3828 : struct switch_flow_classify *pre_swfcl, struct switch_flow_classify *swfcl)
3829 : {
3830 : struct icmp *icmp;
3831 :
3832 0 : if (m->m_len < (off + ICMP_MINLEN) &&
3833 0 : (m = m_pullup(m, (off + ICMP_MINLEN))) == NULL)
3834 0 : return NULL;
3835 :
3836 0 : icmp = (struct icmp *)((m)->m_data + off);
3837 :
3838 0 : if (pre_swfcl->swfcl_icmpv4) {
3839 0 : icmp->icmp_type = pre_swfcl->swfcl_icmpv4->icmpv4_type;
3840 0 : icmp->icmp_code = pre_swfcl->swfcl_icmpv4->icmpv4_code;
3841 :
3842 0 : memcpy(swfcl->swfcl_icmpv4, pre_swfcl->swfcl_icmpv4,
3843 : sizeof(*swfcl->swfcl_icmpv4));
3844 0 : }
3845 :
3846 0 : m->m_pkthdr.csum_flags |= M_ICMP_CSUM_OUT;
3847 :
3848 0 : return (m);
3849 0 : }
3850 :
3851 : #ifdef INET6
3852 : struct mbuf *
3853 0 : swofp_apply_set_field_ipv6(struct mbuf *m, int off,
3854 : struct switch_flow_classify *pre_swfcl, struct switch_flow_classify *swfcl)
3855 : {
3856 : struct ip6_hdr *ip6;
3857 : int hlen;
3858 : /* max size is 802.1ad header size */
3859 0 : u_char eh_bk[sizeof(struct ether_vlan_header) + EVL_ENCAPLEN];
3860 :
3861 0 : if (m->m_len < (off + sizeof(*ip6)) &&
3862 0 : (m = m_pullup(m, off + sizeof(*ip6))) == NULL)
3863 0 : return (NULL);
3864 :
3865 0 : ip6 = (struct ip6_hdr *)(mtod(m, caddr_t) + off);
3866 :
3867 0 : if (pre_swfcl->swfcl_ipv6) {
3868 : /* set version, class and flow label at once */
3869 0 : ip6->ip6_flow = (IPV6_VERSION |
3870 0 : (pre_swfcl->swfcl_ipv6->ipv6_flow_label &
3871 0 : IPV6_FLOWLABEL_MASK) |
3872 0 : htonl(pre_swfcl->swfcl_ipv6->ipv6_tclass << 20));
3873 0 : ip6->ip6_hlim = pre_swfcl->swfcl_ipv6->ipv6_hlimit;
3874 0 : ip6->ip6_nxt = pre_swfcl->swfcl_ipv6->ipv6_nxt;
3875 :
3876 0 : ip6->ip6_src = pre_swfcl->swfcl_ipv6->ipv6_src;
3877 0 : ip6->ip6_dst = pre_swfcl->swfcl_ipv6->ipv6_dst;
3878 :
3879 0 : memcpy(pre_swfcl->swfcl_ipv6, swfcl->swfcl_ipv6,
3880 : sizeof(*pre_swfcl->swfcl_ipv6));
3881 0 : }
3882 :
3883 : hlen = sizeof(*ip6);
3884 :
3885 0 : switch (swfcl->swfcl_ipv6->ipv6_nxt) {
3886 : case IPPROTO_UDP:
3887 0 : m = swofp_apply_set_field_udp(m, (off + hlen),
3888 : pre_swfcl, swfcl);
3889 0 : if (m == NULL)
3890 0 : return (NULL);
3891 0 : m->m_pkthdr.csum_flags |= M_UDP_CSUM_OUT;
3892 0 : break;
3893 : case IPPROTO_TCP:
3894 0 : m = swofp_apply_set_field_tcp(m, (off + hlen),
3895 : pre_swfcl, swfcl);
3896 0 : if (m == NULL)
3897 0 : return (NULL);
3898 0 : m->m_pkthdr.csum_flags |= M_TCP_CSUM_OUT;
3899 0 : break;
3900 : case IPPROTO_ICMPV6:
3901 0 : m = swofp_apply_set_field_icmpv6(m, (off + hlen),
3902 : pre_swfcl, swfcl);
3903 0 : if (m == NULL)
3904 0 : return (NULL);
3905 : break;
3906 : }
3907 :
3908 : /*
3909 : * Recalculate checksums:
3910 : * It doesn't use H/W offload because doesn't know to send a frame
3911 : * from which interface.
3912 : */
3913 0 : m_copydata(m, 0, off, eh_bk);
3914 0 : m_adj(m, off);
3915 :
3916 0 : if (m->m_len < hlen && ((m = m_pullup(m, hlen)) == NULL))
3917 0 : return (NULL);
3918 :
3919 0 : in6_proto_cksum_out(m, NULL);
3920 :
3921 0 : M_PREPEND(m, off, M_DONTWAIT);
3922 0 : if (m == NULL)
3923 0 : return (NULL);
3924 :
3925 0 : m_copyback(m, 0, off, eh_bk, M_DONTWAIT);
3926 :
3927 0 : return (m);
3928 0 : }
3929 : #endif /* INET6 */
3930 :
3931 : struct mbuf *
3932 0 : swofp_apply_set_field_ipv4(struct mbuf *m, int off,
3933 : struct switch_flow_classify *pre_swfcl, struct switch_flow_classify *swfcl)
3934 : {
3935 : struct ip *ip;
3936 : int hlen;
3937 : /* max size is 802.1ad header size */
3938 0 : u_char eh_bk[sizeof(struct ether_vlan_header) + EVL_ENCAPLEN];
3939 :
3940 0 : if (m->m_len < (off + sizeof(*ip)) &&
3941 0 : (m = m_pullup(m, off + sizeof(*ip))) == NULL)
3942 0 : return (NULL);
3943 :
3944 0 : ip = (struct ip *)(mtod(m, caddr_t) + off);
3945 :
3946 0 : if (pre_swfcl->swfcl_ipv4) {
3947 0 : ip->ip_p = pre_swfcl->swfcl_ipv4->ipv4_proto;
3948 0 : ip->ip_tos = pre_swfcl->swfcl_ipv4->ipv4_tos;
3949 :
3950 0 : memcpy(&ip->ip_src.s_addr, &pre_swfcl->swfcl_ipv4->ipv4_src,
3951 : sizeof(uint32_t));
3952 0 : memcpy(&ip->ip_dst.s_addr, &pre_swfcl->swfcl_ipv4->ipv4_dst,
3953 : sizeof(uint32_t));
3954 :
3955 0 : memcpy(pre_swfcl->swfcl_ipv4, swfcl->swfcl_ipv4,
3956 : sizeof(*pre_swfcl->swfcl_ipv4));
3957 0 : }
3958 :
3959 0 : hlen = (ip->ip_hl << 2);
3960 :
3961 0 : switch (swfcl->swfcl_ipv4->ipv4_proto) {
3962 : case IPPROTO_UDP:
3963 0 : m = swofp_apply_set_field_udp(m, (off + hlen),
3964 : pre_swfcl, swfcl);
3965 0 : if (m == NULL)
3966 0 : return (NULL);
3967 0 : m->m_pkthdr.csum_flags |= M_UDP_CSUM_OUT;
3968 0 : break;
3969 : case IPPROTO_TCP:
3970 0 : m = swofp_apply_set_field_tcp(m, (off + hlen),
3971 : pre_swfcl, swfcl);
3972 0 : if (m == NULL)
3973 0 : return (NULL);
3974 0 : m->m_pkthdr.csum_flags |= M_TCP_CSUM_OUT;
3975 0 : break;
3976 : case IPPROTO_ICMP:
3977 0 : m = swofp_apply_set_field_icmpv4(m, (off + hlen),
3978 : pre_swfcl, swfcl);
3979 0 : if (m == NULL)
3980 0 : return (NULL);
3981 : break;
3982 : }
3983 :
3984 : /*
3985 : * Recalculate checksums:
3986 : * It doesn't use H/W offload because doesn't know to send a frame
3987 : * from which interface.
3988 : */
3989 0 : m_copydata(m, 0, off, eh_bk);
3990 0 : m_adj(m, off);
3991 :
3992 0 : if (m->m_len < hlen && ((m = m_pullup(m, hlen)) == NULL))
3993 0 : return (NULL);
3994 0 : ip = mtod(m, struct ip *);
3995 :
3996 0 : ip->ip_sum = 0;
3997 0 : in_proto_cksum_out(m, NULL);
3998 0 : ip->ip_sum = in_cksum(m, hlen);
3999 :
4000 0 : M_PREPEND(m, off, M_DONTWAIT);
4001 0 : if (m == NULL)
4002 0 : return (NULL);
4003 :
4004 0 : m_copyback(m, 0, off, eh_bk, M_DONTWAIT);
4005 :
4006 0 : return (m);
4007 0 : }
4008 :
4009 : struct mbuf *
4010 0 : swofp_apply_set_field_arp( struct mbuf *m, int off,
4011 : struct switch_flow_classify *pre_swfcl, struct switch_flow_classify *swfcl)
4012 : {
4013 : struct ether_arp *ea;
4014 :
4015 0 : if (m->m_len < (off + sizeof(*ea)) &&
4016 0 : (m = m_pullup(m, off + sizeof(*ea))) == NULL)
4017 0 : return (NULL);
4018 :
4019 0 : ea = (struct ether_arp *)((m)->m_data + off);
4020 :
4021 0 : if (pre_swfcl->swfcl_arp) {
4022 0 : ea->arp_op = pre_swfcl->swfcl_arp->_arp_op;
4023 :
4024 0 : memcpy(&ea->arp_sha, pre_swfcl->swfcl_arp->arp_sha,
4025 : ETHER_ADDR_LEN);
4026 0 : memcpy(&ea->arp_tha, pre_swfcl->swfcl_arp->arp_tha,
4027 : ETHER_ADDR_LEN);
4028 0 : memcpy(&ea->arp_spa, &pre_swfcl->swfcl_arp->arp_sip,
4029 : sizeof(uint32_t));
4030 0 : memcpy(&ea->arp_tpa, &pre_swfcl->swfcl_arp->arp_tip,
4031 : sizeof(uint32_t));
4032 0 : memcpy(swfcl->swfcl_arp, pre_swfcl->swfcl_arp,
4033 : sizeof(*swfcl->swfcl_arp));
4034 0 : }
4035 :
4036 0 : return (m);
4037 0 : }
4038 :
4039 : struct mbuf *
4040 0 : swofp_apply_set_field_ether(struct mbuf *m, int off,
4041 : struct switch_flow_classify *pre_swfcl, struct switch_flow_classify *swfcl)
4042 : {
4043 : struct ether_header *eh;
4044 : struct ether_vlan_header *evl = NULL;
4045 : uint16_t *ether_type;
4046 :
4047 0 : m = swofp_expand_8021q_tag(m);
4048 0 : if (m == NULL)
4049 0 : return (NULL);
4050 :
4051 : /*
4052 : * pullup to maximum size QinQ header
4053 : */
4054 0 : if ((m = m_pullup(m, (sizeof(*evl) + EVL_ENCAPLEN))) == NULL)
4055 0 : return (NULL);
4056 :
4057 0 : eh = mtod(m, struct ether_header *);
4058 :
4059 0 : switch (ntohs(eh->ether_type)) {
4060 : case ETHERTYPE_QINQ:
4061 : off = EVL_ENCAPLEN + sizeof(struct ether_vlan_header);
4062 0 : evl = mtod(m, struct ether_vlan_header *);
4063 0 : ether_type = (uint16_t *)(mtod(m, caddr_t) + EVL_ENCAPLEN +
4064 : offsetof(struct ether_vlan_header, evl_proto));
4065 0 : break;
4066 : case ETHERTYPE_VLAN:
4067 : off = sizeof(struct ether_vlan_header);
4068 0 : evl = mtod(m, struct ether_vlan_header *);
4069 0 : ether_type = &evl->evl_proto;
4070 0 : break;
4071 : default:
4072 : off = sizeof(struct ether_header);
4073 : ether_type = &eh->ether_type;
4074 0 : break;
4075 : }
4076 :
4077 0 : if (pre_swfcl->swfcl_vlan) {
4078 0 : switch (ntohs(eh->ether_type)) {
4079 : case ETHERTYPE_QINQ:
4080 : case ETHERTYPE_VLAN:
4081 0 : evl->evl_tag = (pre_swfcl->swfcl_vlan->vlan_vid |
4082 0 : htons(pre_swfcl->swfcl_vlan->vlan_pcp <<
4083 : EVL_PRIO_BITS));
4084 0 : break;
4085 : default:
4086 : break;
4087 : }
4088 :
4089 : /* Update the classifier if it exists. */
4090 0 : if (swfcl->swfcl_vlan)
4091 0 : memcpy(swfcl->swfcl_vlan, pre_swfcl->swfcl_vlan,
4092 : sizeof(*swfcl->swfcl_vlan));
4093 : }
4094 :
4095 0 : if (pre_swfcl->swfcl_ether) {
4096 0 : memcpy(eh->ether_shost, pre_swfcl->swfcl_ether->eth_src,
4097 : ETHER_ADDR_LEN);
4098 0 : memcpy(eh->ether_dhost, pre_swfcl->swfcl_ether->eth_dst,
4099 : ETHER_ADDR_LEN);
4100 0 : *ether_type = pre_swfcl->swfcl_ether->eth_type;
4101 0 : memcpy(swfcl->swfcl_ether, pre_swfcl->swfcl_ether,
4102 : sizeof(*swfcl->swfcl_ether));
4103 0 : }
4104 :
4105 0 : switch (ntohs(*ether_type)) {
4106 : case ETHERTYPE_ARP:
4107 0 : return swofp_apply_set_field_arp(m, off, pre_swfcl, swfcl);
4108 : case ETHERTYPE_IP:
4109 0 : return swofp_apply_set_field_ipv4(m, off, pre_swfcl, swfcl);
4110 : #ifdef INET6
4111 : case ETHERTYPE_IPV6:
4112 0 : return swofp_apply_set_field_ipv6(m, off, pre_swfcl, swfcl);
4113 : #endif /* INET6 */
4114 : case ETHERTYPE_MPLS:
4115 : /* unsupported yet */
4116 : break;
4117 : }
4118 :
4119 0 : return (m);
4120 0 : }
4121 :
4122 : struct mbuf *
4123 0 : swofp_apply_set_field_tunnel(struct mbuf *m, int off,
4124 : struct switch_flow_classify *pre_swfcl, struct switch_flow_classify *swfcl)
4125 : {
4126 : struct bridge_tunneltag *brtag;
4127 :
4128 0 : if (pre_swfcl->swfcl_tunnel) {
4129 0 : if ((brtag = bridge_tunneltag(m)) == NULL) {
4130 0 : m_freem(m);
4131 0 : return (NULL);
4132 : }
4133 :
4134 0 : brtag->brtag_id = be64toh(pre_swfcl->swfcl_tunnel->tun_key);
4135 :
4136 0 : if (pre_swfcl->swfcl_tunnel->tun_ipv4_dst.s_addr !=
4137 : INADDR_ANY) {
4138 0 : brtag->brtag_peer.sin.sin_family =
4139 0 : brtag->brtag_local.sin.sin_family = AF_INET;
4140 0 : brtag->brtag_local.sin.sin_addr =
4141 0 : pre_swfcl->swfcl_tunnel->tun_ipv4_src;
4142 0 : brtag->brtag_peer.sin.sin_addr =
4143 0 : pre_swfcl->swfcl_tunnel->tun_ipv4_dst;
4144 0 : } else if (!IN6_IS_ADDR_UNSPECIFIED(
4145 : &pre_swfcl->swfcl_tunnel->tun_ipv6_dst)) {
4146 0 : brtag->brtag_peer.sin6.sin6_family =
4147 0 : brtag->brtag_local.sin.sin_family = AF_INET6;
4148 0 : brtag->brtag_local.sin6.sin6_addr =
4149 0 : pre_swfcl->swfcl_tunnel->tun_ipv6_src;
4150 0 : brtag->brtag_peer.sin6.sin6_addr =
4151 0 : pre_swfcl->swfcl_tunnel->tun_ipv6_dst;
4152 : } else {
4153 0 : bridge_tunneluntag(m);
4154 0 : m_freem(m);
4155 0 : return (NULL);
4156 : }
4157 :
4158 : /*
4159 : * It can't be used by apply-action instruction.
4160 : */
4161 0 : if (swfcl->swfcl_tunnel) {
4162 0 : memcpy(swfcl->swfcl_tunnel, pre_swfcl->swfcl_tunnel,
4163 : sizeof(*pre_swfcl->swfcl_tunnel));
4164 0 : }
4165 : }
4166 :
4167 0 : return swofp_apply_set_field_ether(m, 0, pre_swfcl, swfcl);
4168 0 : }
4169 :
4170 : struct mbuf *
4171 0 : swofp_apply_set_field(struct mbuf *m, struct swofp_pipeline_desc *swpld)
4172 : {
4173 0 : return swofp_apply_set_field_tunnel(m, 0,
4174 0 : &swpld->swpld_pre_swfcl, swpld->swpld_swfcl);
4175 : }
4176 :
4177 : struct mbuf *
4178 0 : swofp_action_set_field(struct switch_softc *sc, struct mbuf *m,
4179 : struct swofp_pipeline_desc *swpld, struct ofp_action_header *oah)
4180 : {
4181 : struct ofp_oxm_class *oxm_handler;
4182 : struct ofp_action_set_field *oasf;
4183 : struct ofp_ox_match *oxm;
4184 : struct switch_flow_classify *swfcl, *pre_swfcl;
4185 :
4186 0 : oasf = (struct ofp_action_set_field *)oah;
4187 0 : oxm = (struct ofp_ox_match *)oasf->asf_field;
4188 :
4189 0 : oxm_handler = swofp_lookup_oxm_handler(oxm);
4190 0 : if ((oxm_handler == NULL) ||
4191 0 : (oxm_handler->oxm_set == NULL))
4192 : goto failed;
4193 :
4194 0 : swfcl = swpld->swpld_swfcl;
4195 0 : pre_swfcl = &swpld->swpld_pre_swfcl;
4196 :
4197 0 : if (oxm->oxm_class == htons(OFP_OXM_C_NXM_1)) {
4198 0 : switch (OFP_OXM_GET_FIELD(oxm)) {
4199 : case OFP_XM_NXMT_TUNNEL_ID: /* alias OFP_XM_T_TUNNEL_ID */
4200 : case OFP_XM_NXMT_TUNNEL_IPV4_SRC:
4201 : case OFP_XM_NXMT_TUNNEL_IPV4_DST:
4202 : case OFP_XM_NXMT_TUNNEL_IPV6_SRC:
4203 : case OFP_XM_NXMT_TUNNEL_IPV6_DST:
4204 0 : if (pre_swfcl->swfcl_tunnel)
4205 : break;
4206 0 : pre_swfcl->swfcl_tunnel = pool_get(&swfcl_pool,
4207 : PR_NOWAIT|PR_ZERO);
4208 0 : if (pre_swfcl->swfcl_tunnel == NULL)
4209 : goto failed;
4210 0 : if (swfcl->swfcl_tunnel)
4211 0 : memcpy(pre_swfcl->swfcl_tunnel,
4212 : swfcl->swfcl_tunnel,
4213 : sizeof(*swfcl->swfcl_tunnel));
4214 : break;
4215 : }
4216 : } else {
4217 0 : switch (OFP_OXM_GET_FIELD(oxm)) {
4218 : case OFP_XM_T_ETH_SRC:
4219 : case OFP_XM_T_ETH_DST:
4220 : case OFP_XM_T_ETH_TYPE:
4221 0 : if (pre_swfcl->swfcl_ether)
4222 : break;
4223 0 : pre_swfcl->swfcl_ether = pool_get(&swfcl_pool,
4224 : PR_NOWAIT|PR_ZERO);
4225 0 : if (pre_swfcl->swfcl_ether == NULL)
4226 : goto failed;
4227 0 : memcpy(pre_swfcl->swfcl_ether, swfcl->swfcl_ether,
4228 : sizeof(*swfcl->swfcl_ether));
4229 0 : break;
4230 : case OFP_XM_T_VLAN_VID:
4231 : case OFP_XM_T_VLAN_PCP:
4232 0 : if (pre_swfcl->swfcl_vlan)
4233 : break;
4234 0 : pre_swfcl->swfcl_vlan = pool_get(&swfcl_pool,
4235 : PR_NOWAIT|PR_ZERO);
4236 0 : if (pre_swfcl->swfcl_vlan == NULL)
4237 : goto failed;
4238 0 : if (swfcl->swfcl_vlan)
4239 0 : memcpy(pre_swfcl->swfcl_vlan, swfcl->swfcl_vlan,
4240 : sizeof(*swfcl->swfcl_vlan));
4241 : break;
4242 : case OFP_XM_T_ARP_SHA:
4243 : case OFP_XM_T_ARP_THA:
4244 : case OFP_XM_T_ARP_SPA:
4245 : case OFP_XM_T_ARP_TPA:
4246 : case OFP_XM_T_ARP_OP:
4247 0 : if (pre_swfcl->swfcl_arp)
4248 : break;
4249 0 : pre_swfcl->swfcl_arp = pool_get(&swfcl_pool,
4250 : PR_NOWAIT|PR_ZERO);
4251 0 : if (swfcl->swfcl_arp == NULL)
4252 : goto failed;
4253 0 : memcpy(pre_swfcl->swfcl_arp, swfcl->swfcl_arp,
4254 : sizeof(*swfcl->swfcl_arp));
4255 0 : break;
4256 : case OFP_XM_T_IP_DSCP:
4257 : case OFP_XM_T_IP_ECN:
4258 : case OFP_XM_T_IP_PROTO:
4259 0 : if (swfcl->swfcl_ipv4) {
4260 0 : if (pre_swfcl->swfcl_ipv4)
4261 : break;
4262 0 : pre_swfcl->swfcl_ipv4 = pool_get(&swfcl_pool,
4263 : PR_NOWAIT|PR_ZERO);
4264 0 : if (pre_swfcl->swfcl_ipv4 == NULL)
4265 : goto failed;
4266 0 : memcpy(pre_swfcl->swfcl_ipv4, swfcl->swfcl_ipv4,
4267 : sizeof(*swfcl->swfcl_ipv4));
4268 0 : } else if (swfcl->swfcl_ipv6) {
4269 0 : if (pre_swfcl->swfcl_ipv6)
4270 : break;
4271 0 : pre_swfcl->swfcl_ipv6 = pool_get(&swfcl_pool,
4272 : PR_NOWAIT|PR_ZERO);
4273 0 : if (pre_swfcl->swfcl_ipv6 == NULL)
4274 : goto failed;
4275 0 : memcpy(pre_swfcl->swfcl_ipv6, swfcl->swfcl_ipv6,
4276 : sizeof(*swfcl->swfcl_ipv6));
4277 0 : }
4278 : break;
4279 : case OFP_XM_T_IPV4_SRC:
4280 : case OFP_XM_T_IPV4_DST:
4281 0 : if (pre_swfcl->swfcl_ipv4)
4282 : break;
4283 0 : pre_swfcl->swfcl_ipv4 = pool_get(&swfcl_pool,
4284 : PR_NOWAIT|PR_ZERO);
4285 0 : if (pre_swfcl->swfcl_ipv4 == NULL)
4286 : goto failed;
4287 0 : memcpy(pre_swfcl->swfcl_ipv4, swfcl->swfcl_ipv4,
4288 : sizeof(*swfcl->swfcl_ipv4));
4289 0 : break;
4290 : case OFP_XM_T_IPV6_SRC:
4291 : case OFP_XM_T_IPV6_DST:
4292 : case OFP_XM_T_IPV6_FLABEL:
4293 0 : if (pre_swfcl->swfcl_ipv6)
4294 : break;
4295 0 : pre_swfcl->swfcl_ipv6 = pool_get(&swfcl_pool,
4296 : PR_NOWAIT|PR_ZERO);
4297 0 : if (pre_swfcl->swfcl_ipv6 == NULL)
4298 : goto failed;
4299 0 : memcpy(pre_swfcl->swfcl_ipv6, swfcl->swfcl_ipv6,
4300 : sizeof(*swfcl->swfcl_ipv6));
4301 0 : break;
4302 : case OFP_XM_T_UDP_SRC:
4303 : case OFP_XM_T_UDP_DST:
4304 0 : if (pre_swfcl->swfcl_udp)
4305 : break;
4306 0 : pre_swfcl->swfcl_udp = pool_get(&swfcl_pool,
4307 : PR_NOWAIT|PR_ZERO);
4308 0 : if (pre_swfcl->swfcl_udp == NULL)
4309 : goto failed;
4310 0 : memcpy(pre_swfcl->swfcl_udp, swfcl->swfcl_udp,
4311 : sizeof(*swfcl->swfcl_udp));
4312 0 : break;
4313 : case OFP_XM_T_TCP_SRC:
4314 : case OFP_XM_T_TCP_DST:
4315 0 : if (pre_swfcl->swfcl_tcp)
4316 : break;
4317 0 : pre_swfcl->swfcl_tcp = pool_get(&swfcl_pool,
4318 : PR_NOWAIT|PR_ZERO);
4319 0 : if (pre_swfcl->swfcl_tcp == NULL)
4320 : goto failed;
4321 0 : memcpy(pre_swfcl->swfcl_tcp, swfcl->swfcl_tcp,
4322 : sizeof(*swfcl->swfcl_tcp));
4323 0 : break;
4324 : case OFP_XM_T_ICMPV4_CODE:
4325 : case OFP_XM_T_ICMPV4_TYPE:
4326 0 : if (pre_swfcl->swfcl_icmpv4)
4327 : break;
4328 0 : pre_swfcl->swfcl_icmpv4 = pool_get(&swfcl_pool,
4329 : PR_NOWAIT|PR_ZERO);
4330 0 : if (pre_swfcl->swfcl_icmpv4 == NULL)
4331 : goto failed;
4332 0 : memcpy(pre_swfcl->swfcl_icmpv4, swfcl->swfcl_icmpv4,
4333 : sizeof(*swfcl->swfcl_icmpv4));
4334 0 : break;
4335 : case OFP_XM_T_ICMPV6_CODE:
4336 : case OFP_XM_T_ICMPV6_TYPE:
4337 0 : if (pre_swfcl->swfcl_icmpv6)
4338 : break;
4339 0 : pre_swfcl->swfcl_icmpv6 = pool_get(&swfcl_pool,
4340 : PR_NOWAIT|PR_ZERO);
4341 0 : if (pre_swfcl->swfcl_icmpv6 == NULL)
4342 : goto failed;
4343 0 : memcpy(pre_swfcl->swfcl_icmpv6, swfcl->swfcl_icmpv6,
4344 : sizeof(*swfcl->swfcl_icmpv6));
4345 0 : break;
4346 : case OFP_XM_T_IPV6_ND_SLL:
4347 : case OFP_XM_T_IPV6_ND_TLL:
4348 : case OFP_XM_T_IPV6_ND_TARGET:
4349 0 : if (pre_swfcl->swfcl_nd6)
4350 : break;
4351 0 : pre_swfcl->swfcl_nd6 = pool_get(&swfcl_pool,
4352 : PR_NOWAIT|PR_ZERO);
4353 0 : if (pre_swfcl->swfcl_nd6 == NULL)
4354 : goto failed;
4355 0 : memcpy(pre_swfcl->swfcl_nd6, swfcl->swfcl_nd6,
4356 : sizeof(*swfcl->swfcl_nd6));
4357 0 : break;
4358 : case OFP_XM_T_TUNNEL_ID: /* alias OFP_XM_T_TUNNEL_ID */
4359 0 : if (pre_swfcl->swfcl_tunnel)
4360 : break;
4361 0 : pre_swfcl->swfcl_tunnel = pool_get(&swfcl_pool,
4362 : PR_NOWAIT|PR_ZERO);
4363 0 : if (pre_swfcl->swfcl_tunnel == NULL)
4364 : goto failed;
4365 0 : if (swfcl->swfcl_tunnel)
4366 0 : memcpy(pre_swfcl->swfcl_tunnel,
4367 : swfcl->swfcl_tunnel,
4368 : sizeof(*swfcl->swfcl_tunnel));
4369 : break;
4370 : }
4371 : }
4372 :
4373 0 : if (oxm_handler->oxm_set(pre_swfcl, oxm))
4374 : goto failed;
4375 :
4376 0 : return (m);
4377 : failed:
4378 0 : m_freem(m);
4379 0 : return (NULL);
4380 0 : }
4381 :
4382 : struct mbuf *
4383 0 : swofp_execute_action(struct switch_softc *sc, struct mbuf *m,
4384 : struct swofp_pipeline_desc *swpld, struct ofp_action_header *oah)
4385 : {
4386 : struct ofp_action_handler *handler;
4387 :
4388 0 : handler = swofp_lookup_action_handler(ntohs(oah->ah_type));
4389 0 : if ((handler == NULL) || (handler->action == NULL)) {
4390 : DPRINTF(sc, "unknown action (type %d)\n",
4391 : ntohs(oah->ah_type));
4392 0 : m_freem(m);
4393 0 : return (NULL);
4394 : }
4395 :
4396 0 : m = handler->action(sc, m, swpld, oah);
4397 0 : if (m == NULL)
4398 0 : return (NULL);
4399 :
4400 0 : return (m);
4401 0 : }
4402 :
4403 : struct mbuf *
4404 0 : swofp_execute_action_set_field(struct switch_softc *sc, struct mbuf *m,
4405 : struct swofp_pipeline_desc *swpld, struct ofp_action_header *oah)
4406 : {
4407 : struct ofp_action_header **set_fields;
4408 : int i;
4409 :
4410 0 : set_fields = (struct ofp_action_header **)oah;
4411 :
4412 0 : for (i = 0; i < OFP_XM_T_MAX; i++) {
4413 0 : if (set_fields[i] == NULL)
4414 : continue;
4415 :
4416 0 : m = swofp_execute_action(sc, m, swpld, set_fields[i]);
4417 0 : if (m == NULL)
4418 0 : return (NULL);
4419 : }
4420 :
4421 0 : return (m);
4422 0 : }
4423 :
4424 :
4425 : struct mbuf *
4426 0 : swofp_execute_action_set(struct switch_softc *sc, struct mbuf *m,
4427 : struct swofp_pipeline_desc *swpld)
4428 : {
4429 : struct swofp_action_set *swas;
4430 : int i;
4431 :
4432 0 : TAILQ_INIT(&swpld->swpld_fwdp_q);
4433 0 : swas = swpld->swpld_action_set;
4434 0 : swpld->swpld_swfcl->swfcl_cookie = UINT64_MAX;
4435 :
4436 0 : for (i = 0 ; i < nitems(ofp_action_handlers); i++) {
4437 0 : if (swas[i].swas_action == NULL)
4438 : continue;
4439 :
4440 0 : if (swas[i].swas_type == OFP_ACTION_SET_FIELD)
4441 0 : m = swofp_execute_action_set_field(sc, m, swpld,
4442 : swas[i].swas_action);
4443 : else
4444 0 : m = swofp_execute_action(sc, m, swpld,
4445 : swas[i].swas_action);
4446 :
4447 0 : if (m == NULL)
4448 : break;
4449 : }
4450 :
4451 0 : m_freem(m);
4452 :
4453 0 : return (NULL);
4454 : }
4455 :
4456 : struct mbuf *
4457 0 : swofp_apply_actions(struct switch_softc *sc, struct mbuf *m,
4458 : struct swofp_pipeline_desc *swpld, struct ofp_instruction_actions *oia)
4459 : {
4460 : struct ofp_action_header *oah;
4461 :
4462 0 : TAILQ_INIT(&swpld->swpld_fwdp_q);
4463 :
4464 0 : OFP_I_ACTIONS_FOREACH(oia, oah) {
4465 0 : m = swofp_execute_action(sc, m, swpld, oah);
4466 0 : if (m == NULL)
4467 0 : return (NULL);
4468 : }
4469 :
4470 0 : return (m);
4471 0 : }
4472 :
4473 : struct swofp_action_set *
4474 0 : swofp_lookup_action_set(struct swofp_pipeline_desc *swpld, uint16_t type)
4475 : {
4476 : int i;
4477 :
4478 0 : for (i = 0; i < nitems(ofp_action_handlers); i ++) {
4479 0 : if (swpld->swpld_action_set[i].swas_type == type)
4480 0 : return (&swpld->swpld_action_set[i]);
4481 : }
4482 :
4483 0 : return (NULL);
4484 0 : }
4485 :
4486 : void
4487 0 : swofp_write_actions_set_field(struct swofp_action_set *swas,
4488 : struct ofp_action_header *oah)
4489 : {
4490 : struct ofp_action_header **set_fields;
4491 : struct ofp_action_set_field *oasf;
4492 : struct ofp_ox_match *oxm;
4493 :
4494 0 : set_fields = (struct ofp_action_header **)swas->swas_action;
4495 :
4496 0 : oasf = (struct ofp_action_set_field *)oah;
4497 0 : oxm = (struct ofp_ox_match *)oasf->asf_field;
4498 :
4499 0 : set_fields[OFP_OXM_GET_FIELD(oxm)] = oah;
4500 0 : }
4501 :
4502 : int
4503 0 : swofp_write_actions(struct ofp_instruction_actions *oia,
4504 : struct swofp_pipeline_desc *swpld)
4505 : {
4506 : struct swofp_action_set *swas;
4507 : struct ofp_action_header *oah;
4508 :
4509 0 : OFP_I_ACTIONS_FOREACH(oia, oah) {
4510 0 : swas = swofp_lookup_action_set(swpld, ntohs(oah->ah_type));
4511 0 : if (swas == NULL)
4512 0 : return (ENOENT);
4513 :
4514 0 : if (ntohs(oah->ah_type) == OFP_ACTION_SET_FIELD)
4515 0 : swofp_write_actions_set_field(swas, oah);
4516 : else
4517 0 : swas->swas_action = oah;
4518 : }
4519 :
4520 0 : return (0);
4521 0 : }
4522 :
4523 : void
4524 0 : swofp_clear_actions_set_field(struct swofp_action_set *swas,
4525 : struct ofp_action_header *oah)
4526 : {
4527 : struct ofp_action_header **set_fields;
4528 : struct ofp_action_set_field *oasf;
4529 : struct ofp_ox_match *oxm;
4530 :
4531 0 : set_fields = (struct ofp_action_header **)swas->swas_action;
4532 :
4533 0 : oasf = (struct ofp_action_set_field *)oah;
4534 0 : oxm = (struct ofp_ox_match *)oasf->asf_field;
4535 :
4536 0 : set_fields[OFP_OXM_GET_FIELD(oxm)] = NULL;
4537 0 : }
4538 :
4539 : int
4540 0 : swofp_clear_actions(struct ofp_instruction_actions *oia,
4541 : struct swofp_pipeline_desc *swpld)
4542 : {
4543 : struct swofp_action_set *swas;
4544 : struct ofp_action_header *oah;
4545 :
4546 0 : OFP_I_ACTIONS_FOREACH(oia, oah) {
4547 0 : swas = swofp_lookup_action_set(swpld, ntohs(oah->ah_type));
4548 0 : if (swas == NULL)
4549 0 : return (ENOENT);
4550 :
4551 0 : if (ntohs(oah->ah_type) == OFP_ACTION_SET_FIELD)
4552 0 : swofp_clear_actions_set_field(swas, oah);
4553 : else
4554 0 : swas->swas_action = NULL;
4555 : }
4556 :
4557 0 : return (0);
4558 0 : }
4559 :
4560 : void
4561 0 : swofp_write_metadata(struct ofp_instruction_write_metadata *iowm,
4562 : struct swofp_pipeline_desc *swpld)
4563 : {
4564 : uint64_t val, mask;
4565 :
4566 0 : val = iowm->iwm_metadata;
4567 0 : mask = iowm->iwm_metadata_mask;
4568 :
4569 0 : swpld->swpld_metadata = (val & mask);
4570 0 : }
4571 :
4572 : void
4573 0 : swofp_forward_ofs(struct switch_softc *sc, struct switch_flow_classify *swfcl,
4574 : struct mbuf *m)
4575 : {
4576 0 : struct swofp_ofs *ofs = sc->sc_ofs;
4577 : struct swofp_flow_entry *swfe;
4578 : struct swofp_flow_table *swft;
4579 : struct swofp_pipeline_desc *swpld;
4580 : int error;
4581 : uint8_t next_table_id = 0;
4582 :
4583 0 : swpld = swofp_pipeline_desc_create(swfcl);
4584 0 : if (swpld == NULL) {
4585 0 : m_freem(m);
4586 0 : return;
4587 : }
4588 :
4589 0 : TAILQ_FOREACH(swft, &ofs->swofs_table_list, swft_table_next) {
4590 0 : if (swft->swft_table_id != next_table_id)
4591 : continue;
4592 :
4593 : /* XXX
4594 : * The metadata is pipeline parameters but it uses same match
4595 : * framework for matching so it is copy to flow classify.
4596 : */
4597 0 : swpld->swpld_swfcl->swfcl_metadata = swpld->swpld_metadata;
4598 :
4599 0 : if ((swfe = swofp_flow_lookup(swft,
4600 0 : swpld->swpld_swfcl)) == NULL)
4601 : break;
4602 :
4603 : /* Set pipeline parameters */
4604 0 : swpld->swpld_cookie = swfe->swfe_cookie;
4605 0 : swpld->swpld_table_id = swft->swft_table_id;
4606 0 : swpld->swpld_tablemiss = swfe->swfe_tablemiss;
4607 :
4608 : /* Update statistics */
4609 0 : nanouptime(&swfe->swfe_idle_time);
4610 0 : swfe->swfe_packet_cnt++;
4611 0 : swfe->swfe_byte_cnt += m->m_pkthdr.len;
4612 :
4613 0 : if (swfe->swfe_meter) {
4614 : /* TODO: Here is meter instruction */
4615 : }
4616 :
4617 0 : if (swfe->swfe_apply_actions) {
4618 0 : m = swofp_apply_actions(sc, m, swpld,
4619 : swfe->swfe_apply_actions);
4620 0 : if (m == NULL)
4621 : goto out;
4622 : }
4623 :
4624 0 : if (swfe->swfe_clear_actions) {
4625 0 : error = swofp_clear_actions(
4626 : swfe->swfe_clear_actions, swpld);
4627 0 : if (error)
4628 : goto out;
4629 : }
4630 :
4631 0 : if (swfe->swfe_write_actions) {
4632 0 : error = swofp_write_actions(
4633 : swfe->swfe_write_actions, swpld);
4634 0 : if (error)
4635 : goto out;
4636 : }
4637 :
4638 0 : if (swfe->swfe_write_metadata)
4639 0 : swofp_write_metadata(swfe->swfe_write_metadata, swpld);
4640 :
4641 0 : if (swfe->swfe_goto_table)
4642 0 : next_table_id = swfe->swfe_goto_table->igt_table_id;
4643 : else
4644 : break;
4645 0 : }
4646 :
4647 0 : m = swofp_execute_action_set(sc, m, swpld);
4648 : out:
4649 0 : m_freem(m);
4650 0 : swofp_pipeline_desc_destroy(swpld);
4651 0 : }
4652 :
4653 : int
4654 0 : swofp_input(struct switch_softc *sc, struct mbuf *m)
4655 : {
4656 0 : struct swofp_ofs *swofs = sc->sc_ofs;
4657 : struct ofp_header *oh;
4658 : ofp_msg_handler handler;
4659 : uint16_t ohlen;
4660 :
4661 0 : if (m->m_len < sizeof(*oh) &&
4662 0 : (m = m_pullup(m, sizeof(*oh))) == NULL)
4663 0 : return (ENOBUFS);
4664 :
4665 0 : oh = mtod(m, struct ofp_header *);
4666 :
4667 0 : ohlen = ntohs(oh->oh_length);
4668 : /* Validate that we have a sane header. */
4669 0 : if (ohlen < sizeof(*oh)) {
4670 0 : swofp_send_error(sc, m, OFP_ERRTYPE_BAD_REQUEST,
4671 : OFP_ERRREQ_BAD_LEN);
4672 0 : return (0);
4673 : }
4674 :
4675 0 : if (m->m_len < ohlen && (m = m_pullup(m, ohlen)) == NULL)
4676 0 : return (ENOBUFS);
4677 :
4678 : #if NBPFILTER > 0
4679 0 : if (sc->sc_ofbpf)
4680 0 : switch_mtap(sc->sc_ofbpf, m, BPF_DIRECTION_IN,
4681 0 : swofs->swofs_datapath_id);
4682 : #endif
4683 :
4684 0 : handler = swofp_lookup_msg_handler(oh->oh_type);
4685 0 : if (handler)
4686 0 : (*handler)(sc, m);
4687 : else
4688 0 : swofp_send_error(sc, m, OFP_ERRTYPE_BAD_REQUEST,
4689 : OFP_ERRREQ_TYPE);
4690 :
4691 0 : return (0);
4692 0 : }
4693 :
4694 : int
4695 0 : swofp_output(struct switch_softc *sc, struct mbuf *m)
4696 : {
4697 0 : struct swofp_ofs *swofs = sc->sc_ofs;
4698 :
4699 0 : if (sc->sc_swdev == NULL) {
4700 0 : m_freem(m);
4701 0 : return (ENXIO);
4702 : }
4703 :
4704 : #if NBPFILTER > 0
4705 0 : if (sc->sc_ofbpf)
4706 0 : switch_mtap(sc->sc_ofbpf, m, BPF_DIRECTION_OUT,
4707 0 : swofs->swofs_datapath_id);
4708 : #endif
4709 :
4710 0 : if (sc->sc_swdev->swdev_output(sc, m) != 0)
4711 0 : return (ENOBUFS);
4712 :
4713 0 : return (0);
4714 0 : }
4715 :
4716 : /*
4717 : * OpenFlow protocol HELLO message handler
4718 : */
4719 : int
4720 0 : swofp_recv_hello(struct switch_softc *sc, struct mbuf *m)
4721 : {
4722 : struct ofp_header *oh;
4723 :
4724 0 : oh = mtod(m, struct ofp_header *);
4725 :
4726 0 : if (oh->oh_version != OFP_V_1_3)
4727 0 : swofp_send_error(sc, m,
4728 : OFP_ERRTYPE_HELLO_FAILED, OFP_ERRHELLO_INCOMPATIBLE);
4729 : else
4730 0 : m_freem(m);
4731 :
4732 0 : return (0);
4733 : }
4734 :
4735 : void
4736 0 : swofp_send_hello(struct switch_softc *sc)
4737 : {
4738 0 : struct swofp_ofs *swofs = sc->sc_ofs;
4739 : struct mbuf *m;
4740 : struct ofp_header *oh;
4741 :
4742 0 : MGETHDR(m, M_DONTWAIT, MT_DATA);
4743 0 : if (m == NULL)
4744 0 : return; /* XXX */
4745 :
4746 0 : oh = mtod(m, struct ofp_header *);
4747 :
4748 0 : oh->oh_version = OFP_V_1_3;
4749 0 : oh->oh_type = OFP_T_HELLO;
4750 0 : oh->oh_length = htons(sizeof(*oh));
4751 0 : oh->oh_xid = htonl(swofs->swofs_xidnxt++);
4752 0 : m->m_len = m->m_pkthdr.len = sizeof(*oh);
4753 :
4754 0 : (void)swofp_output(sc, m);
4755 0 : }
4756 :
4757 : /*
4758 : * OpenFlow protocol Error message
4759 : */
4760 : void
4761 0 : swofp_send_error(struct switch_softc *sc, struct mbuf *m,
4762 : uint16_t type, uint16_t code)
4763 : {
4764 : struct ofp_error *oe;
4765 : uint16_t len;
4766 0 : uint8_t data[OFP_ERRDATA_MAX];
4767 :
4768 : /* Reuse mbuf from request message */
4769 0 : oe = mtod(m, struct ofp_error *);
4770 :
4771 : /* Save data for the response and copy back later. */
4772 0 : len = min(ntohs(oe->err_oh.oh_length), OFP_ERRDATA_MAX);
4773 0 : m_copydata(m, 0, len, data);
4774 :
4775 0 : oe->err_oh.oh_version = OFP_V_1_3;
4776 0 : oe->err_oh.oh_type = OFP_T_ERROR;
4777 0 : oe->err_type = htons(type);
4778 0 : oe->err_code = htons(code);
4779 0 : oe->err_oh.oh_length = htons(len + sizeof(struct ofp_error));
4780 0 : m->m_len = m->m_pkthdr.len = sizeof(struct ofp_error);
4781 :
4782 0 : if (m_copyback(m, sizeof(struct ofp_error), len, data, M_DONTWAIT)) {
4783 0 : m_freem(m);
4784 0 : return;
4785 : }
4786 :
4787 0 : (void)swofp_output(sc, m);
4788 0 : }
4789 :
4790 :
4791 : /*
4792 : * OpenFlow protocol Echo message
4793 : */
4794 : int
4795 0 : swofp_recv_echo(struct switch_softc *sc, struct mbuf *m)
4796 : {
4797 0 : return swofp_send_echo(sc, m);
4798 : }
4799 :
4800 : int
4801 0 : swofp_send_echo(struct switch_softc *sc, struct mbuf *m)
4802 : {
4803 : struct ofp_header *oh;
4804 :
4805 0 : oh = mtod(m, struct ofp_header *);
4806 0 : oh->oh_type = OFP_T_ECHO_REPLY;
4807 :
4808 0 : return (swofp_output(sc, m));
4809 : }
4810 :
4811 :
4812 : /*
4813 : * Feature request handler
4814 : */
4815 : int
4816 0 : swofp_recv_features_req(struct switch_softc *sc, struct mbuf *m)
4817 : {
4818 :
4819 0 : struct swofp_ofs *swofs = sc->sc_ofs;
4820 : struct ofp_header *oh;
4821 0 : struct ofp_switch_features swf;
4822 :
4823 0 : oh = mtod(m, struct ofp_header *);
4824 :
4825 0 : memset(&swf, 0, sizeof(swf));
4826 0 : memcpy(&swf, oh, sizeof(*oh));
4827 0 : swf.swf_oh.oh_type = OFP_T_FEATURES_REPLY;
4828 0 : swf.swf_oh.oh_length = htons(sizeof(swf));
4829 :
4830 0 : swf.swf_datapath_id = htobe64(swofs->swofs_datapath_id);
4831 0 : swf.swf_nbuffers = htonl(0); /* no buffer now */
4832 0 : swf.swf_ntables = OFP_TABLE_ID_MAX;
4833 0 : swf.swf_aux_id = 0;
4834 0 : swf.swf_capabilities = htonl(OFP_SWCAP_FLOW_STATS |
4835 : OFP_SWCAP_TABLE_STATS | OFP_SWCAP_PORT_STATS |
4836 : OFP_SWCAP_GROUP_STATS);
4837 :
4838 0 : m_copyback(m, 0, sizeof(swf), (caddr_t)&swf, M_WAIT);
4839 :
4840 0 : return (swofp_output(sc, m));
4841 0 : }
4842 :
4843 : /*
4844 : * Get config handler
4845 : */
4846 : int
4847 0 : swofp_recv_config_req(struct switch_softc *sc, struct mbuf *m)
4848 : {
4849 0 : struct swofp_ofs *swofs = sc->sc_ofs;
4850 0 : struct ofp_switch_config osc;
4851 :
4852 0 : memcpy(&osc.cfg_oh, mtod(m, caddr_t), sizeof(struct ofp_header));
4853 0 : osc.cfg_oh.oh_type = OFP_T_GET_CONFIG_REPLY;
4854 0 : osc.cfg_oh.oh_length = htons(sizeof(osc));
4855 :
4856 0 : osc.cfg_flags = htons(swofs->swofs_switch_config.cfg_flags);
4857 0 : osc.cfg_miss_send_len =
4858 0 : htons(swofs->swofs_switch_config.cfg_miss_send_len);
4859 0 : if (m_copyback(m, 0, sizeof(osc), &osc, M_NOWAIT)) {
4860 0 : m_freem(m);
4861 0 : return (-1);
4862 : }
4863 :
4864 0 : return (swofp_output(sc, m));
4865 0 : }
4866 :
4867 : /*
4868 : * Set config handler
4869 : */
4870 : int
4871 0 : swofp_recv_set_config(struct switch_softc *sc, struct mbuf *m)
4872 : {
4873 0 : struct swofp_ofs *swofs = sc->sc_ofs;
4874 : struct ofp_switch_config *swc;
4875 :
4876 0 : swc = mtod(m, struct ofp_switch_config *);
4877 0 : if (ntohs(swc->cfg_oh.oh_length) < sizeof(*swc)) {
4878 0 : swofp_send_error(sc, m, OFP_ERRTYPE_BAD_REQUEST,
4879 : OFP_ERRREQ_BAD_LEN);
4880 0 : return (-1);
4881 : }
4882 :
4883 : /*
4884 : * Support only "normal" fragment handle
4885 : */
4886 0 : swofs->swofs_switch_config.cfg_flags = OFP_CONFIG_FRAG_NORMAL;
4887 0 : swofs->swofs_switch_config.cfg_miss_send_len =
4888 0 : ntohs(swc->cfg_miss_send_len);
4889 :
4890 0 : m_freem(m);
4891 :
4892 0 : return (0);
4893 0 : }
4894 :
4895 : /*
4896 : * OpenFlow protocol FLOW REMOVE message handlers
4897 : */
4898 : int
4899 0 : swofp_send_flow_removed(struct switch_softc *sc, struct swofp_flow_entry *swfe,
4900 : uint8_t reason)
4901 : {
4902 : struct ofp_flow_removed *ofr;
4903 0 : struct timespec now, duration;
4904 : struct mbuf *m;
4905 : int match_len;
4906 :
4907 0 : match_len = ntohs(swfe->swfe_match->om_length);
4908 :
4909 0 : MGETHDR(m, M_WAITOK, MT_DATA);
4910 0 : if (m == NULL)
4911 0 : return (ENOBUFS);
4912 0 : if ((sizeof(*ofr) + match_len) >= MHLEN) {
4913 0 : MCLGET(m, M_WAITOK);
4914 0 : if ((m->m_flags & M_EXT) == 0) {
4915 0 : m_freem(m);
4916 0 : return (ENOBUFS);
4917 : }
4918 : }
4919 :
4920 0 : ofr = mtod(m, struct ofp_flow_removed *);
4921 :
4922 0 : ofr->fr_oh.oh_version = OFP_V_1_3;
4923 0 : ofr->fr_oh.oh_type = OFP_T_FLOW_REMOVED;
4924 0 : ofr->fr_oh.oh_xid = htonl(sc->sc_ofs->swofs_xidnxt++);
4925 :
4926 0 : ofr->fr_cookie = htobe64(swfe->swfe_cookie);
4927 0 : ofr->fr_priority = htons(swfe->swfe_priority);
4928 0 : ofr->fr_reason = reason;
4929 0 : ofr->fr_table_id = swfe->swfe_table_id;
4930 :
4931 0 : nanouptime(&now);
4932 0 : timespecsub(&now, &swfe->swfe_installed_time, &duration);
4933 0 : ofr->fr_duration_sec = ntohl((int)duration.tv_sec);
4934 0 : ofr->fr_priority = htons(swfe->swfe_priority);
4935 0 : ofr->fr_idle_timeout = htons(swfe->swfe_idle_timeout);
4936 0 : ofr->fr_hard_timeout = htons(swfe->swfe_hard_timeout);
4937 0 : ofr->fr_byte_count = htobe64(swfe->swfe_byte_cnt);
4938 0 : ofr->fr_packet_count = htobe64(swfe->swfe_packet_cnt);
4939 :
4940 0 : memcpy(&ofr->fr_match, swfe->swfe_match, match_len);
4941 :
4942 : /* match_len inclusive ofp_match header length*/
4943 0 : ofr->fr_oh.oh_length =
4944 0 : htons(sizeof(*ofr) + match_len - sizeof(struct ofp_match));
4945 :
4946 0 : m->m_len = m->m_pkthdr.len =
4947 0 : sizeof(*ofr) + match_len - sizeof(struct ofp_match);
4948 :
4949 0 : return (swofp_output(sc, m));
4950 0 : }
4951 :
4952 : /*
4953 : * OpenFlow protocol FLOW MOD message handlers
4954 : */
4955 : int
4956 0 : swofp_flow_entry_put_instructions(struct switch_softc *sc, struct mbuf *m,
4957 : struct swofp_flow_entry *swfe, uint16_t *etype, uint16_t *error)
4958 : {
4959 : struct ofp_flow_mod *ofm;
4960 : struct ofp_instruction *oi;
4961 : caddr_t inst;
4962 : int start, len, off;
4963 :
4964 0 : *etype = OFP_ERRTYPE_BAD_INSTRUCTION;
4965 :
4966 0 : ofm = mtod(m, struct ofp_flow_mod *);
4967 :
4968 : /*
4969 : * Clear instructions from flow entry. It's necessary to only modify
4970 : * flow but it's no problem to clear on adding flow because the flow
4971 : * entry doesn't have any instructions. So it's always called.
4972 : */
4973 0 : swofp_flow_entry_instruction_free(swfe);
4974 :
4975 0 : start = OFP_FLOW_MOD_MSG_INSTRUCTION_OFFSET(ofm);
4976 0 : len = ntohs(ofm->fm_oh.oh_length) - start;
4977 0 : for (off = start; off < start + len; off += ntohs(oi->i_len)) {
4978 0 : oi = (struct ofp_instruction *)(mtod(m, caddr_t) + off);
4979 :
4980 0 : if (swofp_validate_flow_instruction(sc, oi,
4981 0 : len - (off - start), etype, error))
4982 0 : return (-1);
4983 :
4984 0 : if ((inst = malloc(ntohs(oi->i_len), M_DEVBUF,
4985 0 : M_DONTWAIT|M_ZERO)) == NULL) {
4986 0 : *error = OFP_ERRFLOWMOD_UNKNOWN;
4987 0 : return (-1);
4988 : }
4989 0 : memcpy(inst, oi, ntohs(oi->i_len));
4990 :
4991 0 : switch (ntohs(oi->i_type)) {
4992 : case OFP_INSTRUCTION_T_GOTO_TABLE:
4993 0 : if (swfe->swfe_goto_table)
4994 0 : free(swfe->swfe_goto_table, M_DEVBUF,
4995 0 : ntohs(swfe->swfe_goto_table->igt_len));
4996 :
4997 0 : swfe->swfe_goto_table =
4998 0 : (struct ofp_instruction_goto_table *)inst;
4999 0 : break;
5000 : case OFP_INSTRUCTION_T_WRITE_META:
5001 0 : if (swfe->swfe_write_metadata)
5002 0 : free(swfe->swfe_write_metadata, M_DEVBUF,
5003 0 : ntohs(swfe->swfe_write_metadata->iwm_len));
5004 :
5005 0 : swfe->swfe_write_metadata =
5006 0 : (struct ofp_instruction_write_metadata *)inst;
5007 0 : break;
5008 : case OFP_INSTRUCTION_T_WRITE_ACTIONS:
5009 0 : if (swfe->swfe_write_actions)
5010 0 : free(swfe->swfe_write_actions, M_DEVBUF,
5011 0 : ntohs(swfe->swfe_write_actions->ia_len));
5012 :
5013 0 : swfe->swfe_write_actions =
5014 0 : (struct ofp_instruction_actions *)inst;
5015 0 : break;
5016 : case OFP_INSTRUCTION_T_APPLY_ACTIONS:
5017 0 : if (swfe->swfe_apply_actions)
5018 0 : free(swfe->swfe_apply_actions, M_DEVBUF,
5019 0 : ntohs(swfe->swfe_apply_actions->ia_len));
5020 :
5021 0 : swfe->swfe_apply_actions =
5022 0 : (struct ofp_instruction_actions *)inst;
5023 0 : break;
5024 : case OFP_INSTRUCTION_T_CLEAR_ACTIONS:
5025 0 : if (swfe->swfe_clear_actions)
5026 0 : free(swfe->swfe_clear_actions, M_DEVBUF,
5027 0 : ntohs(swfe->swfe_clear_actions->ia_len));
5028 :
5029 0 : swfe->swfe_clear_actions =
5030 0 : (struct ofp_instruction_actions *)inst;
5031 0 : break;
5032 : case OFP_INSTRUCTION_T_METER:
5033 0 : if (swfe->swfe_meter)
5034 0 : free(swfe->swfe_meter, M_DEVBUF,
5035 0 : ntohs(swfe->swfe_meter->im_len));
5036 :
5037 0 : swfe->swfe_meter = (struct ofp_instruction_meter *)inst;
5038 0 : break;
5039 : case OFP_INSTRUCTION_T_EXPERIMENTER:
5040 0 : if (swfe->swfe_experimenter)
5041 0 : free(swfe->swfe_experimenter, M_DEVBUF,
5042 0 : ntohs(swfe->swfe_experimenter->ie_len));
5043 :
5044 0 : swfe->swfe_experimenter =
5045 0 : (struct ofp_instruction_experimenter *)inst;
5046 0 : break;
5047 : default:
5048 0 : free(inst, M_DEVBUF, ntohs(oi->i_len));
5049 0 : break;
5050 : }
5051 : }
5052 :
5053 0 : return (0);
5054 0 : }
5055 :
5056 : int
5057 0 : swofp_flow_mod_cmd_add(struct switch_softc *sc, struct mbuf *m)
5058 : {
5059 0 : struct swofp_ofs *ofs = sc->sc_ofs;
5060 : struct ofp_flow_mod *ofm;
5061 : struct ofp_match *om;
5062 0 : struct swofp_flow_entry *swfe, *old_swfe;
5063 : struct swofp_flow_table *swft;
5064 : int omlen;
5065 0 : uint16_t error, etype;
5066 :
5067 0 : etype = OFP_ERRTYPE_FLOW_MOD_FAILED;
5068 0 : ofm = mtod(m, struct ofp_flow_mod *);
5069 0 : om = &ofm->fm_match;
5070 :
5071 0 : if (OFP_TABLE_ID_MAX < ofm->fm_table_id) {
5072 0 : error = OFP_ERRFLOWMOD_TABLE_ID;
5073 0 : goto ofp_error;
5074 : }
5075 :
5076 0 : if (ofm->fm_cookie == UINT64_MAX) {
5077 : /* XXX What is best error code? */
5078 0 : error = OFP_ERRFLOWMOD_UNKNOWN;
5079 0 : goto ofp_error;
5080 : }
5081 :
5082 0 : omlen = ntohs(om->om_length);
5083 : /*
5084 : * 1) ofp_match header must have at least its own size,
5085 : * otherwise memcpy() will fail later;
5086 : * 2) OXM filters can't be bigger than the packet.
5087 : */
5088 0 : if (omlen < sizeof(*om) ||
5089 0 : omlen >= (m->m_len - sizeof(*ofm))) {
5090 0 : etype = OFP_ERRTYPE_BAD_MATCH;
5091 0 : error = OFP_ERRMATCH_BAD_LEN;
5092 0 : goto ofp_error;
5093 : }
5094 :
5095 0 : if ((swft = swofp_flow_table_add(sc, ofm->fm_table_id)) == NULL) {
5096 0 : error = OFP_ERRFLOWMOD_TABLE_ID;
5097 0 : goto ofp_error;
5098 : }
5099 :
5100 0 : if (swft->swft_flow_num >= ofs->swofs_flow_max_entry) {
5101 0 : error = OFP_ERRFLOWMOD_TABLE_FULL;
5102 0 : goto ofp_error;
5103 : }
5104 :
5105 : /* Validate that the OXM are in-place and correct. */
5106 0 : if (swofp_validate_flow_match(om, &error)) {
5107 0 : etype = OFP_ERRTYPE_BAD_MATCH;
5108 0 : goto ofp_error;
5109 : }
5110 :
5111 0 : if ((old_swfe = swofp_flow_search_by_table(swft, om,
5112 0 : ntohs(ofm->fm_priority)))) {
5113 0 : if (ntohs(ofm->fm_flags) & OFP_FLOWFLAG_CHECK_OVERLAP) {
5114 0 : error = OFP_ERRFLOWMOD_OVERLAP;
5115 0 : goto ofp_error;
5116 : }
5117 : }
5118 :
5119 0 : if ((swfe = malloc(sizeof(*swfe), M_DEVBUF,
5120 0 : M_DONTWAIT|M_ZERO)) == NULL) {
5121 0 : error = OFP_ERRFLOWMOD_UNKNOWN;
5122 0 : goto ofp_error;
5123 : }
5124 :
5125 0 : swfe->swfe_priority = ntohs(ofm->fm_priority);
5126 0 : swfe->swfe_cookie = be64toh(ofm->fm_cookie);
5127 0 : swfe->swfe_flags = ntohs(ofm->fm_flags);
5128 0 : swfe->swfe_idle_timeout = ntohs(ofm->fm_idle_timeout);
5129 0 : swfe->swfe_hard_timeout = ntohs(ofm->fm_hard_timeout);
5130 0 : nanouptime(&swfe->swfe_installed_time);
5131 0 : nanouptime(&swfe->swfe_idle_time);
5132 :
5133 0 : if ((swfe->swfe_match = malloc(omlen, M_DEVBUF,
5134 0 : M_DONTWAIT|M_ZERO)) == NULL) {
5135 0 : error = OFP_ERRFLOWMOD_UNKNOWN;
5136 0 : goto ofp_error_free_flow;
5137 : }
5138 0 : memcpy(swfe->swfe_match, om, omlen);
5139 :
5140 : /*
5141 : * If the ofp_match structure is empty and priority is zero, then
5142 : * this is a special flow type called table-miss which is the last
5143 : * flow to match.
5144 : */
5145 0 : if (omlen == sizeof(*om) && swfe->swfe_priority == 0)
5146 0 : swfe->swfe_tablemiss = 1;
5147 :
5148 0 : if (swofp_flow_entry_put_instructions(sc, m, swfe, &etype, &error))
5149 : goto ofp_error_free_flow;
5150 :
5151 0 : if (old_swfe) {
5152 0 : if (!(ntohs(ofm->fm_flags) & OFP_FLOWFLAG_RESET_COUNTS)) {
5153 0 : swfe->swfe_packet_cnt = old_swfe->swfe_packet_cnt;
5154 0 : swfe->swfe_byte_cnt = old_swfe->swfe_byte_cnt;
5155 0 : }
5156 : /*
5157 : * Doesn't need to send flow remove message because
5158 : * this deleted flow cause by internal reason
5159 : */
5160 0 : swfe->swfe_flags &= ~(OFP_FLOWFLAG_SEND_FLOW_REMOVED);
5161 0 : swofp_flow_entry_delete(sc, swft, old_swfe,
5162 : OFP_FLOWREM_REASON_DELETE);
5163 0 : }
5164 :
5165 0 : swofp_flow_entry_add(sc, swft, swfe);
5166 :
5167 0 : m_freem(m);
5168 0 : return (0);
5169 :
5170 : ofp_error_free_flow:
5171 0 : swofp_flow_entry_free(&swfe);
5172 : ofp_error:
5173 0 : swofp_send_error(sc, m, etype, error);
5174 0 : return (0);
5175 0 : }
5176 :
5177 : int
5178 0 : swofp_flow_mod_cmd_common_modify(struct switch_softc *sc, struct mbuf *m,
5179 : int strict)
5180 : {
5181 : struct ofp_flow_mod *ofm;
5182 : struct ofp_match *om;
5183 : struct swofp_flow_entry *swfe;
5184 : struct swofp_flow_table *swft;
5185 : int omlen;
5186 0 : uint16_t error, etype;
5187 :
5188 0 : etype = OFP_ERRTYPE_FLOW_MOD_FAILED;
5189 :
5190 0 : ofm = mtod(m, struct ofp_flow_mod *);
5191 0 : om = &ofm->fm_match;
5192 :
5193 0 : if (OFP_TABLE_ID_MAX < ofm->fm_table_id) {
5194 0 : error = OFP_ERRFLOWMOD_TABLE_ID;
5195 0 : goto ofp_error;
5196 : }
5197 :
5198 0 : if (ofm->fm_cookie == UINT64_MAX) {
5199 : /* XXX What is best error code? */
5200 0 : error = OFP_ERRFLOWMOD_UNKNOWN;
5201 0 : goto ofp_error;
5202 : }
5203 :
5204 0 : omlen = ntohs(om->om_length);
5205 : /*
5206 : * 1) ofp_match header must have at least its own size,
5207 : * otherwise memcpy() will fail later;
5208 : * 2) OXM filters can't be bigger than the packet.
5209 : */
5210 0 : if (omlen < sizeof(*om) ||
5211 0 : omlen >= (m->m_len - sizeof(*ofm))) {
5212 0 : etype = OFP_ERRTYPE_BAD_MATCH;
5213 0 : error = OFP_ERRMATCH_BAD_LEN;
5214 0 : goto ofp_error;
5215 : }
5216 :
5217 : /* Validate that the OXM are in-place and correct. */
5218 0 : if (swofp_validate_flow_match(om, &error)) {
5219 0 : etype = OFP_ERRTYPE_BAD_MATCH;
5220 0 : goto ofp_error;
5221 : }
5222 :
5223 0 : if ((swft = swofp_flow_table_lookup(sc, ofm->fm_table_id)) == NULL) {
5224 0 : error = OFP_ERRFLOWMOD_TABLE_ID;
5225 0 : goto ofp_error;
5226 : }
5227 :
5228 0 : LIST_FOREACH(swfe, &swft->swft_flow_list, swfe_next) {
5229 0 : if (strict && !swofp_flow_cmp_strict(swfe, om,
5230 0 : ntohs(ofm->fm_priority)))
5231 : continue;
5232 0 : else if (!swofp_flow_cmp_non_strict(swfe, om))
5233 : continue;
5234 :
5235 0 : if (!swofp_flow_filter(swfe, be64toh(ofm->fm_cookie),
5236 0 : be64toh(ofm->fm_cookie_mask), ntohl(ofm->fm_out_port),
5237 0 : ntohl(ofm->fm_out_group)))
5238 : continue;
5239 :
5240 0 : if (swofp_flow_entry_put_instructions(sc, m, swfe, &etype,
5241 : &error)) {
5242 : /*
5243 : * If error occurs in swofp_flow_entry_put_instructions,
5244 : * the flow entry might be half-way modified. So the
5245 : * flow entry is delete here.
5246 : */
5247 0 : swofp_flow_entry_delete(sc, swft, swfe,
5248 : OFP_FLOWREM_REASON_DELETE);
5249 0 : etype = OFP_ERRTYPE_BAD_INSTRUCTION;
5250 0 : goto ofp_error;
5251 : }
5252 :
5253 0 : if (ntohs(ofm->fm_flags) & OFP_FLOWFLAG_RESET_COUNTS) {
5254 0 : swfe->swfe_packet_cnt = 0;
5255 0 : swfe->swfe_byte_cnt = 0;
5256 0 : }
5257 : }
5258 :
5259 0 : m_freem(m);
5260 0 : return (0);
5261 :
5262 : ofp_error:
5263 0 : swofp_send_error(sc, m, etype, error);
5264 0 : return (0);
5265 0 : }
5266 :
5267 : int
5268 0 : swofp_flow_mod_cmd_modify(struct switch_softc *sc, struct mbuf *m)
5269 : {
5270 0 : return swofp_flow_mod_cmd_common_modify(sc, m, 0);
5271 : }
5272 :
5273 : int
5274 0 : swofp_flow_mod_cmd_modify_strict(struct switch_softc *sc, struct mbuf *m)
5275 : {
5276 0 : return swofp_flow_mod_cmd_common_modify(sc, m, 1);
5277 : }
5278 :
5279 :
5280 : int
5281 0 : swofp_flow_mod_cmd_common_delete(struct switch_softc *sc, struct mbuf *m,
5282 : int strict)
5283 : {
5284 0 : struct swofp_ofs *ofs = sc->sc_ofs;
5285 : struct ofp_flow_mod *ofm;
5286 : struct ofp_match *om;
5287 : struct swofp_flow_table *swft;
5288 : int omlen;
5289 0 : uint16_t error, etype = OFP_ERRTYPE_FLOW_MOD_FAILED;
5290 :
5291 0 : ofm = (struct ofp_flow_mod *)(mtod(m, caddr_t));
5292 0 : om = &ofm->fm_match;
5293 :
5294 0 : omlen = ntohs(om->om_length);
5295 : /*
5296 : * 1) ofp_match header must have at least its own size,
5297 : * otherwise memcpy() will fail later;
5298 : * 2) OXM filters can't be bigger than the packet.
5299 : */
5300 0 : if (omlen < sizeof(*om) ||
5301 0 : omlen >= (m->m_len - sizeof(*ofm))) {
5302 : etype = OFP_ERRTYPE_BAD_MATCH;
5303 0 : error = OFP_ERRMATCH_BAD_LEN;
5304 0 : goto ofp_error;
5305 : }
5306 :
5307 : /* Validate that the OXM are in-place and correct. */
5308 0 : if (swofp_validate_flow_match(om, &error)) {
5309 : etype = OFP_ERRTYPE_BAD_MATCH;
5310 0 : goto ofp_error;
5311 : }
5312 :
5313 0 : TAILQ_FOREACH(swft, &ofs->swofs_table_list, swft_table_next) {
5314 0 : if ((ofm->fm_table_id != OFP_TABLE_ID_ALL) &&
5315 0 : (ofm->fm_table_id != swft->swft_table_id))
5316 : continue;
5317 :
5318 0 : swofp_flow_delete_on_table(sc, swft, om,
5319 0 : ntohs(ofm->fm_priority),
5320 0 : be64toh(ofm->fm_cookie),
5321 0 : be64toh(ofm->fm_cookie_mask),
5322 0 : ntohl(ofm->fm_out_port),
5323 0 : ntohl(ofm->fm_out_group), strict);
5324 0 : }
5325 :
5326 0 : m_freem(m);
5327 0 : return (0);
5328 :
5329 : ofp_error:
5330 0 : swofp_send_error(sc, m, etype, error);
5331 0 : return (-1);
5332 0 : }
5333 :
5334 : int
5335 0 : swofp_flow_mod_cmd_delete(struct switch_softc *sc, struct mbuf *m)
5336 : {
5337 0 : return swofp_flow_mod_cmd_common_delete(sc, m, 0);
5338 : }
5339 :
5340 : int
5341 0 : swofp_flow_mod_cmd_delete_strict(struct switch_softc *sc, struct mbuf *m)
5342 : {
5343 0 : return swofp_flow_mod_cmd_common_delete(sc, m, 1);
5344 : }
5345 :
5346 : ofp_msg_handler *
5347 0 : swofp_flow_mod_lookup_handler(uint8_t cmd)
5348 : {
5349 0 : if (cmd >= nitems(ofp_flow_mod_table))
5350 0 : return (NULL);
5351 : else
5352 0 : return (&ofp_flow_mod_table[cmd].ofm_cmd_handler);
5353 0 : }
5354 :
5355 : int
5356 0 : swofp_flow_mod(struct switch_softc *sc, struct mbuf *m)
5357 : {
5358 : struct ofp_flow_mod *ofm;
5359 : ofp_msg_handler *handler;
5360 : uint16_t ohlen;
5361 :
5362 0 : ofm = mtod(m, struct ofp_flow_mod *);
5363 0 : ohlen = ntohs(ofm->fm_oh.oh_length);
5364 0 : if (ohlen < sizeof(*ofm) ||
5365 0 : ohlen < (sizeof(*ofm) + ntohs(ofm->fm_match.om_length))) {
5366 0 : swofp_send_error(sc, m, OFP_ERRTYPE_BAD_REQUEST,
5367 : OFP_ERRREQ_BAD_LEN);
5368 0 : return (-1);
5369 : }
5370 :
5371 0 : handler = swofp_flow_mod_lookup_handler(ofm->fm_command);
5372 0 : if (handler) {
5373 0 : (*handler)(sc, m);
5374 0 : } else {
5375 0 : swofp_send_error(sc, m, OFP_ERRTYPE_FLOW_MOD_FAILED,
5376 : OFP_ERRFLOWMOD_BAD_COMMAND);
5377 : }
5378 :
5379 0 : return (0);
5380 0 : }
5381 :
5382 : int
5383 0 : swofp_group_mod_add(struct switch_softc *sc, struct mbuf *m)
5384 : {
5385 0 : struct swofp_ofs *ofs = sc->sc_ofs;
5386 : struct ofp_group_mod *ogm;
5387 : struct swofp_group_entry *swge;
5388 0 : uint16_t error, etype;
5389 :
5390 0 : etype = OFP_ERRTYPE_GROUP_MOD_FAILED;
5391 0 : ogm = mtod(m, struct ofp_group_mod *);
5392 :
5393 0 : if (ofs->swofs_group_table_num >= ofs->swofs_group_max_table) {
5394 0 : error = OFP_ERRGROUPMOD_OUT_OF_GROUPS;
5395 0 : goto failed;
5396 : }
5397 :
5398 0 : if (ntohl(ogm->gm_group_id) > OFP_GROUP_ID_MAX) {
5399 0 : error = OFP_ERRGROUPMOD_INVALID_GROUP;
5400 0 : goto failed;
5401 : }
5402 :
5403 0 : if ((swge = swofp_group_entry_lookup(sc,
5404 : ntohl(ogm->gm_group_id)))) {
5405 0 : error = OFP_ERRGROUPMOD_GROUP_EXISTS;
5406 0 : goto failed;
5407 : }
5408 :
5409 0 : if (ogm->gm_type != OFP_GROUP_T_ALL) {
5410 : /* support ALL group only now*/
5411 0 : error = OFP_ERRGROUPMOD_BAD_TYPE;
5412 0 : goto failed;
5413 : }
5414 :
5415 0 : if (swofp_validate_buckets(sc, m, ogm->gm_type, &etype, &error))
5416 : goto failed;
5417 :
5418 0 : if ((swge = malloc(sizeof(*swge), M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) {
5419 0 : error = OFP_ERRGROUPMOD_UNKNOWN_GROUP;
5420 0 : goto failed;
5421 : }
5422 :
5423 0 : swge->swge_group_id = ntohl(ogm->gm_group_id);
5424 0 : swge->swge_type = ogm->gm_type;
5425 :
5426 0 : swge->swge_buckets_len = (ntohs(ogm->gm_oh.oh_length) -
5427 : offsetof(struct ofp_group_mod, gm_buckets));
5428 :
5429 0 : if (swge->swge_buckets_len > 0) {
5430 0 : if ((swge->swge_buckets = malloc(swge->swge_buckets_len,
5431 0 : M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) {
5432 0 : free(swge, M_DEVBUF, sizeof(*swge));
5433 0 : error = OFP_ERRGROUPMOD_UNKNOWN_GROUP;
5434 0 : goto failed;
5435 : }
5436 :
5437 0 : m_copydata(m, offsetof(struct ofp_group_mod, gm_buckets),
5438 0 : swge->swge_buckets_len, (caddr_t)swge->swge_buckets);
5439 0 : }
5440 :
5441 0 : swofp_group_entry_add(sc, swge);
5442 :
5443 0 : m_freem(m);
5444 0 : return (0);
5445 :
5446 : failed:
5447 0 : swofp_send_error(sc, m, etype, error);
5448 0 : return (0);
5449 0 : }
5450 :
5451 : int
5452 0 : swofp_group_mod_modify(struct switch_softc *sc, struct mbuf *m)
5453 : {
5454 : struct ofp_group_mod *ogm;
5455 : struct swofp_group_entry *swge;
5456 0 : uint16_t error, etype;
5457 : uint32_t obucketlen;
5458 :
5459 0 : etype = OFP_ERRTYPE_GROUP_MOD_FAILED;
5460 0 : ogm = mtod(m, struct ofp_group_mod *);
5461 :
5462 0 : if (ogm->gm_type != OFP_GROUP_T_ALL) {
5463 : /* support ALL group only now */
5464 0 : error = OFP_ERRGROUPMOD_BAD_TYPE;
5465 0 : goto failed;
5466 : }
5467 :
5468 0 : if ((swge = swofp_group_entry_lookup(sc,
5469 0 : ntohl(ogm->gm_group_id))) == NULL) {
5470 0 : error = OFP_ERRGROUPMOD_UNKNOWN_GROUP;
5471 0 : goto failed;
5472 : }
5473 :
5474 0 : if (swofp_validate_buckets(sc, m, ogm->gm_type, &etype, &error))
5475 : goto failed;
5476 :
5477 0 : swge->swge_type = ogm->gm_type;
5478 :
5479 0 : obucketlen = swge->swge_buckets_len;
5480 0 : swge->swge_buckets_len = (ntohs(ogm->gm_oh.oh_length) -
5481 : offsetof(struct ofp_group_mod, gm_buckets));
5482 :
5483 0 : if (obucketlen != swge->swge_buckets_len) {
5484 0 : free(swge->swge_buckets, M_DEVBUF, obucketlen);
5485 0 : swge->swge_buckets = NULL;
5486 :
5487 0 : if (swge->swge_buckets_len > 0 &&
5488 0 : (swge->swge_buckets = malloc(swge->swge_buckets_len,
5489 0 : M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) {
5490 0 : free(swge, M_DEVBUF, sizeof(*swge));
5491 0 : error = OFP_ERRGROUPMOD_UNKNOWN_GROUP;
5492 0 : goto failed;
5493 : }
5494 : }
5495 :
5496 0 : if (swge->swge_buckets != NULL)
5497 0 : m_copydata(m, offsetof(struct ofp_group_mod, gm_buckets),
5498 0 : swge->swge_buckets_len, (caddr_t)swge->swge_buckets);
5499 :
5500 0 : m_freem(m);
5501 0 : return (0);
5502 : failed:
5503 0 : swofp_send_error(sc, m, etype, error);
5504 0 : return (0);
5505 0 : }
5506 :
5507 : int
5508 0 : swofp_group_mod_delete(struct switch_softc *sc, struct mbuf *m)
5509 : {
5510 : struct ofp_group_mod *ogm;
5511 : struct swofp_group_entry *swge;
5512 : int group_id;
5513 :
5514 0 : ogm = mtod(m, struct ofp_group_mod *);
5515 0 : group_id = ntohl(ogm->gm_group_id);
5516 :
5517 0 : if (group_id == OFP_GROUP_ID_ALL)
5518 0 : swofp_group_entry_delete_all(sc);
5519 0 : else if ((swge = swofp_group_entry_lookup(sc, group_id)) != NULL)
5520 0 : swofp_group_entry_delete(sc, swge);
5521 : else {
5522 0 : swofp_send_error(sc, m, OFP_ERRTYPE_GROUP_MOD_FAILED,
5523 : OFP_ERRGROUPMOD_UNKNOWN_GROUP);
5524 0 : return (0);
5525 : }
5526 :
5527 0 : m_freem(m);
5528 0 : return (0);
5529 0 : }
5530 :
5531 : int
5532 0 : swofp_group_mod(struct switch_softc *sc, struct mbuf *m)
5533 : {
5534 : struct ofp_group_mod *ogm;
5535 : uint16_t cmd;
5536 :
5537 0 : ogm = mtod(m, struct ofp_group_mod *);
5538 0 : if (ntohs(ogm->gm_oh.oh_length) < sizeof(*ogm)) {
5539 0 : swofp_send_error(sc, m, OFP_ERRTYPE_BAD_REQUEST,
5540 : OFP_ERRREQ_BAD_LEN);
5541 0 : return (-1);
5542 : }
5543 :
5544 0 : cmd = ntohs(ogm->gm_command);
5545 :
5546 0 : switch (cmd) {
5547 : case OFP_GROUPCMD_ADD:
5548 0 : return swofp_group_mod_add(sc, m);
5549 : case OFP_GROUPCMD_MODIFY:
5550 0 : return swofp_group_mod_modify(sc, m);
5551 : case OFP_GROUPCMD_DELETE:
5552 0 : return swofp_group_mod_delete(sc, m);
5553 : default:
5554 0 : swofp_send_error(sc, m, OFP_ERRTYPE_GROUP_MOD_FAILED,
5555 : OFP_ERRGROUPMOD_BAD_COMMAND);
5556 : break;
5557 : }
5558 :
5559 0 : return (0);
5560 0 : }
5561 :
5562 :
5563 :
5564 : /*
5565 : * OpenFlow protocol PACKET OUT message handler
5566 : */
5567 : int
5568 0 : swofp_recv_packet_out(struct switch_softc *sc, struct mbuf *m)
5569 : {
5570 : struct ofp_packet_out *pout;
5571 : struct ofp_action_header *ah;
5572 : struct mbuf *mc = NULL, *mcn;
5573 : int al_start, al_len, off;
5574 0 : uint16_t ohlen, error;
5575 0 : struct switch_flow_classify swfcl = {};
5576 0 : struct swofp_pipeline_desc swpld = { .swpld_swfcl = &swfcl };
5577 :
5578 0 : pout = mtod(m, struct ofp_packet_out *);
5579 0 : ohlen = ntohs(pout->pout_oh.oh_length);
5580 0 : if (ohlen < sizeof(*pout) ||
5581 0 : ohlen < (sizeof(*pout) + ntohs(pout->pout_actions_len))) {
5582 0 : swofp_send_error(sc, m, OFP_ERRTYPE_BAD_REQUEST,
5583 : OFP_ERRREQ_BAD_LEN);
5584 0 : return (-1);
5585 : }
5586 :
5587 : al_len = ntohs(pout->pout_actions_len);
5588 : al_start = offsetof(struct ofp_packet_out, pout_actions);
5589 :
5590 : /* Validate actions before anything else. */
5591 0 : ah = (struct ofp_action_header *)
5592 0 : ((uint8_t *)pout + sizeof(*pout));
5593 0 : if (swofp_validate_action(sc, ah, al_len, &error)) {
5594 0 : swofp_send_error(sc, m, OFP_ERRTYPE_BAD_ACTION, error);
5595 0 : return (EINVAL);
5596 : }
5597 :
5598 0 : if (pout->pout_buffer_id == OFP_PKTOUT_NO_BUFFER) {
5599 : /*
5600 : * It's not necessary to deep copy at here because it's done
5601 : * in m_dup_pkt().
5602 : */
5603 0 : if ((mc = m_split(m, (al_start + al_len), M_NOWAIT)) == NULL) {
5604 0 : m_freem(m);
5605 0 : return (ENOBUFS);
5606 : }
5607 :
5608 0 : mcn = m_dup_pkt(mc, ETHER_ALIGN, M_NOWAIT);
5609 0 : m_freem(mc);
5610 0 : if (mcn == NULL) {
5611 0 : m_freem(m);
5612 0 : return (ENOBUFS);
5613 : }
5614 :
5615 : mc = mcn;
5616 : } else {
5617 : /* TODO We don't do buffering yet. */
5618 0 : swofp_send_error(sc, m, OFP_ERRTYPE_BAD_REQUEST,
5619 : OFP_ERRREQ_BUFFER_UNKNOWN);
5620 0 : return (0);
5621 : }
5622 :
5623 0 : mc = switch_flow_classifier(mc, pout->pout_in_port, &swfcl);
5624 0 : if (mc == NULL) {
5625 0 : m_freem(m);
5626 0 : return (0);
5627 : }
5628 :
5629 0 : TAILQ_INIT(&swpld.swpld_fwdp_q);
5630 0 : swfcl.swfcl_in_port = ntohl(pout->pout_in_port);
5631 0 : for (off = al_start; off < al_start + al_len;
5632 0 : off += ntohs(ah->ah_len)) {
5633 0 : ah = (struct ofp_action_header *)(mtod(m, caddr_t) + off);
5634 :
5635 0 : mc = swofp_execute_action(sc, mc, &swpld, ah);
5636 0 : if (mc == NULL)
5637 : break;
5638 : }
5639 :
5640 0 : if (mc)
5641 0 : switch_port_egress(sc, &swpld.swpld_fwdp_q, mc);
5642 :
5643 0 : m_freem(m);
5644 :
5645 0 : return (0);
5646 0 : }
5647 :
5648 : /*
5649 : * OpenFlow protocol MULTIPART message:
5650 : *
5651 : * Multipart messages are used to carry a large amount of data because a single
5652 : * OpenFlow message is limited to 64KB. If a message is over 64KB, it is
5653 : * splited some OpenFlow messages. OpenFlow Switch Specification says that
5654 : * "NO OBJECT CAN BE SPLIT ACROSS TWO MESSAGES". In other words, point of
5655 : * splittig is different per reply, so switch(4) builds multipart message using
5656 : * swofp_mpms_* functions which splits messsages not to object across
5657 : * two messages.
5658 : */
5659 : int
5660 0 : swofp_mpmsg_reply_create(struct ofp_multipart *req, struct swofp_mpmsg *swmp)
5661 : {
5662 : struct mbuf *hdr, *body;
5663 : struct ofp_multipart *omp;
5664 :
5665 0 : memset(swmp, 0, sizeof(*swmp));
5666 :
5667 0 : ml_init(&swmp->swmp_body);
5668 :
5669 0 : MGETHDR(hdr, M_DONTWAIT, MT_DATA);
5670 0 : if (hdr == NULL)
5671 : goto error;
5672 :
5673 0 : memset(mtod(hdr, caddr_t), 0, sizeof(*omp));
5674 0 : omp = mtod(hdr, struct ofp_multipart *);
5675 0 : omp->mp_oh.oh_version = req->mp_oh.oh_version;
5676 0 : omp->mp_oh.oh_xid = req->mp_oh.oh_xid;
5677 0 : omp->mp_oh.oh_type = OFP_T_MULTIPART_REPLY;
5678 0 : omp->mp_type = req->mp_type;
5679 0 : hdr->m_len = hdr->m_pkthdr.len = sizeof(*omp);
5680 0 : swmp->swmp_hdr = hdr;
5681 :
5682 0 : MGETHDR(body, M_DONTWAIT, MT_DATA);
5683 0 : if (body == NULL)
5684 : goto error;
5685 0 : MCLGET(body, M_DONTWAIT);
5686 0 : if ((body->m_flags & M_EXT) == 0) {
5687 0 : m_freem(body);
5688 0 : goto error;
5689 : }
5690 0 : body->m_len = body->m_pkthdr.len = 0;
5691 :
5692 0 : ml_enqueue(&swmp->swmp_body, body);
5693 :
5694 0 : return (0);
5695 :
5696 : error:
5697 0 : m_freem(hdr);
5698 0 : swmp->swmp_hdr = NULL;
5699 0 : return (ENOBUFS);
5700 0 : }
5701 :
5702 : /*
5703 : * Copy data from a buffer back into the indicated swmp's body buffer
5704 : */
5705 : int
5706 0 : swofp_mpmsg_put(struct swofp_mpmsg *swmp, caddr_t data, size_t len)
5707 : {
5708 : struct mbuf *m, *n;
5709 : int error;
5710 :
5711 0 : KASSERT(swmp->swmp_hdr != NULL);
5712 :
5713 0 : m = swmp->swmp_body.ml_tail;
5714 0 : if (m == NULL)
5715 0 : return (ENOBUFS);
5716 :
5717 0 : if (m->m_pkthdr.len + len > SWOFP_MPMSG_MAX) {
5718 0 : MGETHDR(n, M_DONTWAIT, MT_DATA);
5719 0 : if (n == NULL)
5720 0 : return (ENOBUFS);
5721 0 : MCLGET(n, M_DONTWAIT);
5722 0 : if ((n->m_flags & M_EXT) == 0) {
5723 0 : m_freem(n);
5724 0 : return (ENOBUFS);
5725 : }
5726 0 : n->m_len = n->m_pkthdr.len = 0;
5727 :
5728 0 : ml_enqueue(&swmp->swmp_body, n);
5729 :
5730 : m = n;
5731 0 : }
5732 :
5733 0 : if ((error = m_copyback(m, m->m_pkthdr.len, len, data, M_NOWAIT)))
5734 0 : return (error);
5735 :
5736 0 : return (0);
5737 0 : }
5738 :
5739 : /*
5740 : * Copy data from a mbuf back into the indicated swmp's body buffer
5741 : */
5742 : int
5743 0 : swofp_mpmsg_m_put(struct swofp_mpmsg *swmp, struct mbuf *msg)
5744 : {
5745 : struct mbuf *m, *n;
5746 : int len;
5747 :
5748 0 : KASSERT(swmp->swmp_hdr != NULL);
5749 :
5750 0 : m = swmp->swmp_body.ml_tail;
5751 0 : if (m == NULL)
5752 0 : return (ENOBUFS);
5753 :
5754 0 : if (m->m_pkthdr.len + msg->m_pkthdr.len > SWOFP_MPMSG_MAX) {
5755 0 : MGETHDR(n, M_DONTWAIT, MT_DATA);
5756 0 : if (n == NULL)
5757 0 : return (ENOBUFS);
5758 0 : MCLGET(n, M_DONTWAIT);
5759 0 : if ((n->m_flags & M_EXT) == 0) {
5760 0 : m_freem(n);
5761 0 : return (ENOBUFS);
5762 : }
5763 0 : n->m_len = n->m_pkthdr.len = 0;
5764 :
5765 0 : ml_enqueue(&swmp->swmp_body, n);
5766 :
5767 : m = n;
5768 0 : }
5769 :
5770 0 : len = m->m_pkthdr.len + msg->m_pkthdr.len;
5771 0 : m_cat(m, msg);
5772 0 : m->m_pkthdr.len = len;
5773 :
5774 0 : return (0);
5775 0 : }
5776 :
5777 : void
5778 0 : swofp_mpmsg_destroy(struct swofp_mpmsg *swmp)
5779 : {
5780 0 : m_freem(swmp->swmp_hdr);
5781 0 : ml_purge(&swmp->swmp_body);
5782 0 : }
5783 :
5784 : int
5785 0 : swofp_multipart_req(struct switch_softc *sc, struct mbuf *m)
5786 : {
5787 : struct ofp_multipart *omp;
5788 : ofp_msg_handler handler;
5789 :
5790 0 : omp = mtod(m, struct ofp_multipart *);
5791 0 : if (ntohs(omp->mp_oh.oh_length) < sizeof(*omp)) {
5792 0 : swofp_send_error(sc, m, OFP_ERRTYPE_BAD_REQUEST,
5793 : OFP_ERRREQ_BAD_LEN);
5794 0 : return (-1);
5795 : }
5796 :
5797 0 : if (omp->mp_flags & OFP_T_MULTIPART_REQUEST) {
5798 : /* multipart message re-assembly iss not supported yet */
5799 0 : m_freem(m);
5800 0 : return (ENOBUFS);
5801 : }
5802 :
5803 0 : handler = swofp_lookup_mpmsg_handler(ntohs(omp->mp_type));
5804 0 : if (handler)
5805 0 : (*handler)(sc, m);
5806 : else
5807 0 : swofp_send_error(sc, m, OFP_ERRTYPE_BAD_REQUEST,
5808 : OFP_ERRREQ_MULTIPART);
5809 :
5810 0 : return (0);
5811 0 : }
5812 :
5813 : int
5814 0 : swofp_multipart_reply(struct switch_softc *sc, struct swofp_mpmsg *swmp)
5815 : {
5816 : struct ofp_multipart *omp;
5817 : struct mbuf *hdr, *body;
5818 : int len, error = 0;
5819 :
5820 0 : KASSERT(swmp->swmp_hdr != NULL);
5821 :
5822 0 : omp = mtod(swmp->swmp_hdr, struct ofp_multipart *);
5823 :
5824 0 : while ((body = ml_dequeue(&swmp->swmp_body)) != NULL) {
5825 0 : omp->mp_oh.oh_length = htons(sizeof(*omp) + body->m_pkthdr.len);
5826 :
5827 0 : if (swmp->swmp_body.ml_tail != NULL) {
5828 0 : omp->mp_flags |= htons(OFP_MP_FLAG_REPLY_MORE);
5829 0 : if ((hdr = m_dup_pkt(swmp->swmp_hdr, 0,
5830 0 : M_WAITOK)) == NULL) {
5831 : error = ENOBUFS;
5832 : goto error;
5833 : }
5834 : } else {
5835 0 : omp->mp_flags &= ~htons(OFP_MP_FLAG_REPLY_MORE);
5836 0 : hdr = swmp->swmp_hdr;
5837 : }
5838 :
5839 0 : if (body->m_pkthdr.len) {
5840 0 : len = hdr->m_pkthdr.len + body->m_pkthdr.len;
5841 0 : m_cat(hdr, body);
5842 0 : hdr->m_pkthdr.len = len;
5843 0 : } else
5844 0 : m_freem(body);
5845 :
5846 0 : (void)swofp_output(sc, hdr);
5847 : }
5848 :
5849 0 : return (0);
5850 : error:
5851 0 : swofp_mpmsg_destroy(swmp);
5852 0 : return (error);
5853 0 : }
5854 :
5855 : int
5856 0 : swofp_put_flow(struct mbuf *m, struct swofp_flow_table *swft,
5857 : struct swofp_flow_entry *swfe)
5858 : {
5859 0 : struct ofp_flow_stats *pofs, ofs;
5860 0 : struct timespec now, duration;
5861 : const uint8_t pad_data[OFP_ALIGNMENT] = {};
5862 : struct mbuf *n;
5863 0 : int start, off, error, offp, pad = 0;
5864 : int omlen;
5865 :
5866 0 : memset(&ofs, 0, sizeof(ofs));
5867 :
5868 0 : ofs.fs_table_id = swft->swft_table_id;
5869 0 : nanouptime(&now);
5870 0 : timespecsub(&now, &swfe->swfe_installed_time, &duration);
5871 0 : ofs.fs_duration_sec = ntohl((int)duration.tv_sec);
5872 0 : ofs.fs_priority = htons(swfe->swfe_priority);
5873 0 : ofs.fs_idle_timeout = htons(swfe->swfe_idle_timeout);
5874 0 : ofs.fs_hard_timeout = htons(swfe->swfe_hard_timeout);
5875 0 : ofs.fs_cookie = htobe64(swfe->swfe_cookie);
5876 0 : ofs.fs_byte_count = htobe64(swfe->swfe_byte_cnt);
5877 0 : ofs.fs_packet_count = htobe64(swfe->swfe_packet_cnt);
5878 :
5879 : /*
5880 : * struct ofp_flow_statsu has some fields which is variable length ,
5881 : * so the length is determined by all fields puts.
5882 : */
5883 0 : start = off = m->m_pkthdr.len;
5884 :
5885 : /*
5886 : * Put ofp_flow_stat exclusive ofp_match because ofp_match is put
5887 : * with ofp_matches
5888 : */
5889 0 : if ((error = m_copyback(m, off, (sizeof(ofs) -
5890 : sizeof(struct ofp_match)), &ofs, M_NOWAIT)))
5891 : goto failed;
5892 0 : off += (sizeof(ofs) - sizeof(struct ofp_match));
5893 :
5894 : /*
5895 : * Put ofp_match include ofp_ox_matches and pad
5896 : */
5897 0 : omlen = ntohs(swfe->swfe_match->om_length);
5898 0 : pad = OFP_ALIGN(omlen) - omlen;
5899 0 : if ((error = m_copyback(m, off, omlen, swfe->swfe_match, M_NOWAIT)))
5900 : goto failed;
5901 0 : off += omlen;
5902 0 : if ((error = m_copyback(m, off, pad, pad_data, M_NOWAIT)))
5903 : goto failed;
5904 0 : off += pad;
5905 :
5906 : /*
5907 : * Put instructions
5908 : */
5909 0 : if (swfe->swfe_goto_table) {
5910 0 : if ((error = m_copyback(m, off,
5911 0 : ntohs(swfe->swfe_goto_table->igt_len),
5912 0 : swfe->swfe_goto_table, M_NOWAIT)))
5913 : goto failed;
5914 0 : off += ntohs(swfe->swfe_goto_table->igt_len);
5915 0 : }
5916 0 : if (swfe->swfe_write_metadata) {
5917 0 : if ((error = m_copyback(m, off,
5918 0 : ntohs(swfe->swfe_write_metadata->iwm_len),
5919 0 : swfe->swfe_write_metadata, M_NOWAIT)))
5920 : goto failed;
5921 0 : off += ntohs(swfe->swfe_write_metadata->iwm_len);
5922 0 : }
5923 0 : if (swfe->swfe_apply_actions) {
5924 0 : if ((error = m_copyback(m, off,
5925 0 : ntohs(swfe->swfe_apply_actions->ia_len),
5926 0 : swfe->swfe_apply_actions, M_NOWAIT)))
5927 : goto failed;
5928 0 : off += ntohs(swfe->swfe_apply_actions->ia_len);
5929 0 : }
5930 0 : if (swfe->swfe_write_actions) {
5931 0 : if ((error = m_copyback(m, off,
5932 0 : ntohs(swfe->swfe_write_actions->ia_len),
5933 0 : swfe->swfe_write_actions, M_NOWAIT)))
5934 : goto failed;
5935 0 : off += ntohs(swfe->swfe_write_actions->ia_len);
5936 0 : }
5937 0 : if (swfe->swfe_clear_actions) {
5938 0 : if ((error = m_copyback(m, off,
5939 0 : ntohs(swfe->swfe_clear_actions->ia_len),
5940 0 : swfe->swfe_clear_actions, M_NOWAIT)))
5941 : goto failed;
5942 0 : off += ntohs(swfe->swfe_clear_actions->ia_len);
5943 0 : }
5944 :
5945 : /*
5946 : * Set ofp_flow_stat length
5947 : */
5948 0 : if ((n = m_pulldown(m, start, sizeof(*pofs), &offp)) == NULL)
5949 0 : return (ENOBUFS);
5950 0 : pofs = (struct ofp_flow_stats *)(mtod(n, caddr_t) + offp);
5951 0 : pofs->fs_length = htons(off - start);
5952 :
5953 0 : return (0);
5954 :
5955 : failed:
5956 0 : m_freem(m);
5957 0 : return (error);
5958 0 : }
5959 :
5960 : int
5961 0 : swofp_mp_recv_desc(struct switch_softc *sc, struct mbuf *m)
5962 : {
5963 0 : struct ofp_desc od;
5964 0 : struct swofp_mpmsg swmp;
5965 : int error;
5966 :
5967 0 : if ((error = swofp_mpmsg_reply_create(
5968 0 : mtod(m, struct ofp_multipart *), &swmp)))
5969 : goto failed;
5970 :
5971 0 : memset(&od, 0, sizeof(od));
5972 :
5973 0 : strlcpy(od.d_mfr_desc, "openbsd.org", OFP_DESC_STR_LEN);
5974 0 : strlcpy(od.d_hw_desc, "openbsd", OFP_DESC_STR_LEN);
5975 0 : strlcpy(od.d_sw_desc, "openbsd", OFP_DESC_STR_LEN);
5976 0 : strlcpy(od.d_serial_num, "0", OFP_SERIAL_NUM_LEN);
5977 0 : strlcpy(od.d_dp_desc, sc->sc_if.if_xname, OFP_DESC_STR_LEN);
5978 :
5979 0 : if ((error = swofp_mpmsg_put(&swmp, (caddr_t)&od, sizeof(od))))
5980 : goto failed;
5981 :
5982 0 : m_freem(m);
5983 0 : return swofp_multipart_reply(sc, &swmp);
5984 :
5985 : failed:
5986 0 : m_freem(m);
5987 0 : swofp_mpmsg_destroy(&swmp);
5988 0 : return (error);
5989 0 : }
5990 :
5991 : int
5992 0 : swofp_put_flows_from_table(struct swofp_mpmsg *swmp,
5993 : struct swofp_flow_table *swft, struct ofp_flow_stats_request *ofsr)
5994 : {
5995 : struct swofp_flow_entry *swfe;
5996 : struct mbuf *m;
5997 : int error = 0;
5998 :
5999 0 : LIST_FOREACH(swfe, &swft->swft_flow_list, swfe_next) {
6000 0 : if (!swofp_flow_cmp_non_strict(swfe, &ofsr->fsr_match))
6001 : continue;
6002 :
6003 0 : if (!swofp_flow_filter(swfe, be64toh(ofsr->fsr_cookie),
6004 0 : be64toh(ofsr->fsr_cookie_mask), ntohl(ofsr->fsr_out_port),
6005 0 : ntohl(ofsr->fsr_out_group)))
6006 : continue;
6007 :
6008 0 : MGETHDR(m, M_DONTWAIT, MT_DATA);
6009 0 : if (m == NULL)
6010 0 : return (ENOBUFS);
6011 0 : m->m_len = m->m_pkthdr.len = 0;
6012 :
6013 0 : if ((error = swofp_put_flow(m, swft, swfe)))
6014 : break;
6015 :
6016 0 : if ((error = swofp_mpmsg_m_put(swmp, m))) {
6017 : /* swofp_mpmsg_m_put() doesn't free m on error */
6018 0 : m_freem(m);
6019 0 : break;
6020 : }
6021 : }
6022 :
6023 0 : return (error);
6024 0 : }
6025 :
6026 : int
6027 0 : swofp_mp_recv_flow(struct switch_softc *sc, struct mbuf *m)
6028 : {
6029 0 : struct swofp_ofs *ofs = sc->sc_ofs;
6030 : struct ofp_flow_stats_request *ofsr;
6031 : struct swofp_flow_table *swft;
6032 0 : struct swofp_mpmsg swmp;
6033 : int error;
6034 :
6035 0 : if ((error = swofp_mpmsg_reply_create(
6036 0 : mtod(m, struct ofp_multipart *), &swmp)))
6037 : goto failed;
6038 :
6039 0 : ofsr = (struct ofp_flow_stats_request *)
6040 0 : (mtod(m, caddr_t) + sizeof(struct ofp_multipart));
6041 :
6042 0 : TAILQ_FOREACH(swft, &ofs->swofs_table_list, swft_table_next) {
6043 0 : if ((ofsr->fsr_table_id != OFP_TABLE_ID_ALL) &&
6044 0 : (ofsr->fsr_table_id != swft->swft_table_id))
6045 : continue;
6046 :
6047 0 : if ((error = swofp_put_flows_from_table(&swmp, swft, ofsr)))
6048 : goto failed;
6049 : }
6050 :
6051 0 : m_freem(m);
6052 0 : return swofp_multipart_reply(sc, &swmp);
6053 :
6054 : failed:
6055 0 : m_freem(m);
6056 0 : swofp_mpmsg_destroy(&swmp);
6057 0 : return (error);
6058 0 : }
6059 :
6060 : void
6061 0 : swofp_aggregate_stat_from_table(struct ofp_aggregate_stats *aggstat,
6062 : struct swofp_flow_table *swft, struct ofp_aggregate_stats_request *oasr)
6063 : {
6064 : struct swofp_flow_entry *swfe;
6065 : uint64_t packet_cnt = 0, byte_cnt = 0;
6066 : uint32_t flow_cnt = 0;
6067 :
6068 0 : LIST_FOREACH(swfe, &swft->swft_flow_list, swfe_next) {
6069 0 : if (!swofp_flow_cmp_non_strict(swfe, &oasr->asr_match))
6070 : continue;
6071 :
6072 0 : if (!swofp_flow_filter(swfe, be64toh(oasr->asr_cookie),
6073 0 : be64toh(oasr->asr_cookie_mask), ntohl(oasr->asr_out_port),
6074 0 : ntohl(oasr->asr_out_group)))
6075 : continue;
6076 :
6077 0 : packet_cnt += swfe->swfe_packet_cnt;
6078 0 : byte_cnt += swfe->swfe_byte_cnt;
6079 0 : flow_cnt++;
6080 0 : }
6081 :
6082 0 : aggstat->as_packet_count = htobe64(packet_cnt);
6083 0 : aggstat->as_byte_count = htobe64(byte_cnt);
6084 0 : aggstat->as_flow_count = htonl(flow_cnt++);
6085 0 : }
6086 :
6087 : int
6088 0 : swofp_mp_recv_aggregate_flow_stat(struct switch_softc *sc, struct mbuf *m)
6089 : {
6090 0 : struct swofp_ofs *ofs = sc->sc_ofs;
6091 : struct ofp_aggregate_stats_request *oasr;
6092 : struct swofp_flow_table *swft;
6093 0 : struct swofp_mpmsg swmp;
6094 0 : struct ofp_aggregate_stats aggstat;
6095 : int error;
6096 :
6097 0 : if ((error = swofp_mpmsg_reply_create(
6098 0 : mtod(m, struct ofp_multipart *), &swmp)))
6099 : goto failed;
6100 :
6101 0 : memset(&aggstat, 0, sizeof(aggstat));
6102 :
6103 0 : oasr = (struct ofp_aggregate_stats_request *)
6104 0 : (mtod(m, caddr_t) + sizeof(struct ofp_multipart));
6105 :
6106 0 : TAILQ_FOREACH(swft, &ofs->swofs_table_list, swft_table_next) {
6107 0 : if ((oasr->asr_table_id != OFP_TABLE_ID_ALL) &&
6108 0 : (oasr->asr_table_id != swft->swft_table_id))
6109 : continue;
6110 0 : swofp_aggregate_stat_from_table(&aggstat, swft, oasr);
6111 0 : }
6112 :
6113 0 : if ((error = swofp_mpmsg_put(&swmp, (caddr_t)&aggstat,
6114 : sizeof(aggstat))))
6115 : goto failed;
6116 :
6117 0 : m_freem(m);
6118 0 : return swofp_multipart_reply(sc, &swmp);
6119 :
6120 : failed:
6121 0 : m_freem(m);
6122 0 : swofp_mpmsg_destroy(&swmp);
6123 0 : return (error);
6124 0 : }
6125 :
6126 : int
6127 0 : swofp_mp_recv_table_stats(struct switch_softc *sc, struct mbuf *m)
6128 : {
6129 0 : struct swofp_ofs *ofs = sc->sc_ofs;
6130 0 : struct ofp_table_stats tblstat;
6131 : struct swofp_flow_table *swft;
6132 0 : struct swofp_mpmsg swmp;
6133 : int error;
6134 :
6135 :
6136 0 : if ((error = swofp_mpmsg_reply_create(
6137 0 : mtod(m, struct ofp_multipart *), &swmp)))
6138 : goto failed;
6139 :
6140 0 : TAILQ_FOREACH(swft, &ofs->swofs_table_list, swft_table_next) {
6141 0 : memset(&tblstat, 0, sizeof(tblstat));
6142 :
6143 0 : tblstat.ts_table_id = swft->swft_table_id;
6144 0 : tblstat.ts_active_count = htonl((uint32_t)swft->swft_flow_num);
6145 0 : tblstat.ts_lookup_count = htobe64(swft->swft_lookup_count);
6146 0 : tblstat.ts_matched_count = htobe64(swft->swft_matched_count);
6147 :
6148 0 : if ((error = swofp_mpmsg_put(&swmp, (caddr_t)&tblstat,
6149 : sizeof(tblstat))))
6150 : goto failed;
6151 : }
6152 :
6153 0 : m_freem(m);
6154 0 : return swofp_multipart_reply(sc, &swmp);
6155 :
6156 : failed:
6157 0 : m_freem(m);
6158 0 : swofp_mpmsg_destroy(&swmp);
6159 0 : return (error);
6160 0 : }
6161 :
6162 : int
6163 0 : swofp_mp_recv_port_stats(struct switch_softc *sc, struct mbuf *m)
6164 : {
6165 : struct switch_port *swpo;
6166 0 : struct swofp_mpmsg swmp;
6167 : struct ifnet *ifs;
6168 0 : struct ofp_port_stats postat;
6169 : int error;
6170 0 : struct timespec now, duration;
6171 :
6172 0 : if ((error = swofp_mpmsg_reply_create(
6173 0 : mtod(m, struct ofp_multipart *), &swmp)))
6174 : goto failed;
6175 :
6176 0 : nanouptime(&now);
6177 :
6178 0 : TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next) {
6179 0 : memset(&postat, 0, sizeof(postat));
6180 0 : ifs = if_get(swpo->swpo_ifindex);
6181 0 : if (ifs == NULL)
6182 : continue;
6183 :
6184 0 : if (swpo->swpo_flags & IFBIF_LOCAL)
6185 0 : postat.pt_port_no = htonl(OFP_PORT_LOCAL);
6186 : else
6187 0 : postat.pt_port_no = htonl(swpo->swpo_port_no);
6188 0 : postat.pt_rx_packets = htobe64(ifs->if_ipackets);
6189 0 : postat.pt_tx_packets = htobe64(ifs->if_opackets);
6190 0 : postat.pt_rx_bytes = htobe64(ifs->if_obytes);
6191 0 : postat.pt_tx_bytes = htobe64(ifs->if_ibytes);
6192 0 : postat.pt_rx_dropped = htobe64(ifs->if_iqdrops);
6193 0 : postat.pt_tx_dropped = htobe64(ifs->if_oqdrops);
6194 0 : postat.pt_rx_errors = htobe64(ifs->if_ierrors);
6195 0 : postat.pt_tx_errors = htobe64(ifs->if_oerrors);
6196 0 : postat.pt_rx_frame_err = htobe64(0);
6197 0 : postat.pt_rx_over_err = htobe64(0);
6198 0 : postat.pt_rx_crc_err = htobe64(0);
6199 0 : postat.pt_collision = htobe64(ifs->if_collisions);
6200 0 : timespecsub(&now, &swpo->swpo_appended, &duration);
6201 0 : postat.pt_duration_sec = htonl((uint32_t)duration.tv_sec);
6202 0 : postat.pt_duration_nsec = htonl(duration.tv_nsec);
6203 :
6204 0 : if_put(ifs);
6205 :
6206 0 : if ((error = swofp_mpmsg_put(&swmp, (caddr_t)&postat,
6207 : sizeof(postat))))
6208 : goto failed;
6209 : }
6210 :
6211 0 : m_freem(m);
6212 0 : return swofp_multipart_reply(sc, &swmp);
6213 :
6214 : failed:
6215 0 : m_freem(m);
6216 0 : swofp_mpmsg_destroy(&swmp);
6217 0 : return (error);
6218 0 : }
6219 :
6220 : int
6221 0 : swofp_table_features_put_oxm(struct mbuf *m, int *off, uint16_t tp_type)
6222 : {
6223 0 : struct ofp_table_feature_property tp;
6224 0 : struct ofp_ox_match oxm;
6225 0 : uint32_t padding = 0;
6226 : int i, supported = 0;
6227 :
6228 0 : for (i = 0 ; i < nitems(ofp_oxm_handlers); i++) {
6229 0 : switch (tp_type) {
6230 : case OFP_TABLE_FEATPROP_MATCH:
6231 0 : if (ofp_oxm_handlers[i].oxm_match == NULL)
6232 : continue;
6233 : break;
6234 : case OFP_TABLE_FEATPROP_WILDCARDS:
6235 0 : if (ofp_oxm_handlers[i].oxm_match == NULL ||
6236 0 : !(ofp_oxm_handlers[i].oxm_flags &
6237 : SWOFP_MATCH_WILDCARD))
6238 : continue;
6239 : break;
6240 : case OFP_TABLE_FEATPROP_APPLY_SETFIELD:
6241 : case OFP_TABLE_FEATPROP_APPLY_SETFIELD_MISS:
6242 : case OFP_TABLE_FEATPROP_WRITE_SETFIELD:
6243 : case OFP_TABLE_FEATPROP_WRITE_SETFIELD_MISS:
6244 0 : if (ofp_oxm_handlers[i].oxm_set == NULL)
6245 : continue;
6246 : break;
6247 : }
6248 0 : supported++;
6249 0 : }
6250 :
6251 0 : tp.tp_type = htons(tp_type);
6252 0 : tp.tp_length = htons((sizeof(oxm) * supported) + sizeof(tp));
6253 :
6254 0 : if (m_copyback(m, *off, sizeof(tp), (caddr_t)&tp, M_NOWAIT))
6255 0 : return (OFP_ERRREQ_MULTIPART_OVERFLOW);
6256 0 : *off += sizeof(tp);
6257 :
6258 0 : for (i = 0 ; i < nitems(ofp_oxm_handlers); i++) {
6259 0 : switch (tp_type) {
6260 : case OFP_TABLE_FEATPROP_MATCH:
6261 0 : if (ofp_oxm_handlers[i].oxm_match == NULL)
6262 : continue;
6263 : break;
6264 : case OFP_TABLE_FEATPROP_WILDCARDS:
6265 0 : if (ofp_oxm_handlers[i].oxm_match == NULL ||
6266 0 : !(ofp_oxm_handlers[i].oxm_flags &
6267 : SWOFP_MATCH_WILDCARD))
6268 : continue;
6269 : break;
6270 : case OFP_TABLE_FEATPROP_APPLY_SETFIELD:
6271 : case OFP_TABLE_FEATPROP_APPLY_SETFIELD_MISS:
6272 : case OFP_TABLE_FEATPROP_WRITE_SETFIELD:
6273 : case OFP_TABLE_FEATPROP_WRITE_SETFIELD_MISS:
6274 0 : if (ofp_oxm_handlers[i].oxm_set == NULL)
6275 : continue;
6276 : break;
6277 : }
6278 :
6279 0 : memset(&oxm, 0, sizeof(oxm));
6280 0 : OFP_OXM_SET_FIELD(&oxm, ofp_oxm_handlers[i].oxm_field);
6281 0 : if ((tp_type == OFP_TABLE_FEATPROP_MATCH) &&
6282 0 : (ofp_oxm_handlers[i].oxm_flags & SWOFP_MATCH_MASK))
6283 0 : OFP_OXM_SET_HASMASK(&oxm);
6284 0 : oxm.oxm_class = htons(OFP_OXM_C_OPENFLOW_BASIC);
6285 0 : oxm.oxm_length = ofp_oxm_handlers[i].oxm_len;
6286 :
6287 0 : if (m_copyback(m, *off, sizeof(oxm), (caddr_t)&oxm, M_NOWAIT))
6288 0 : return (OFP_ERRREQ_MULTIPART_OVERFLOW);
6289 0 : *off += sizeof(oxm);
6290 0 : }
6291 :
6292 : /*
6293 : * It's always 4 byte for padding becouse struct ofp_ox_mach and
6294 : * struct ofp_table_feature_property are 4 byte.
6295 : */
6296 0 : if ((supported & 0x1) == 0) {
6297 0 : if (m_copyback(m, *off, sizeof(padding),
6298 : (caddr_t)&padding, M_NOWAIT))
6299 0 : return (OFP_ERRREQ_MULTIPART_OVERFLOW);
6300 0 : *off += sizeof(padding);
6301 0 : }
6302 :
6303 0 : return (0);
6304 0 : }
6305 :
6306 : int
6307 0 : swofp_table_features_put_actions(struct mbuf *m, int *off, uint16_t tp_type)
6308 : {
6309 0 : struct ofp_table_feature_property tp;
6310 0 : struct ofp_action_header action;
6311 : int i, supported = 0;
6312 : int actionlen, padsize;
6313 0 : uint8_t padding[8];
6314 :
6315 0 : for (i = 0 ; i < nitems(ofp_action_handlers); i++) {
6316 0 : if (ofp_action_handlers[i].action)
6317 0 : supported++;
6318 : }
6319 :
6320 : actionlen = sizeof(action) - sizeof(action.ah_pad);
6321 0 : tp.tp_type = htons(tp_type);
6322 0 : tp.tp_length = (actionlen * supported) + sizeof(tp);
6323 :
6324 0 : padsize = OFP_ALIGN(tp.tp_length) - tp.tp_length;
6325 0 : tp.tp_length = htons(tp.tp_length);
6326 :
6327 0 : if (m_copyback(m, *off, sizeof(tp), (caddr_t)&tp, M_NOWAIT))
6328 0 : return (OFP_ERRREQ_MULTIPART_OVERFLOW);
6329 0 : *off += sizeof(tp);
6330 :
6331 0 : for (i = 0 ; i < nitems(ofp_action_handlers); i++) {
6332 0 : if (ofp_action_handlers[i].action == NULL)
6333 : continue;
6334 :
6335 0 : memset(&action, 0, actionlen);
6336 0 : action.ah_type = ntohs(ofp_action_handlers[i].action_type);
6337 : /* XXX action length is different for experimenter type. */
6338 0 : action.ah_len = ntohs(actionlen);
6339 :
6340 0 : if (m_copyback(m, *off, actionlen,
6341 : (caddr_t)&action, M_NOWAIT))
6342 0 : return (OFP_ERRREQ_MULTIPART_OVERFLOW);
6343 0 : *off += actionlen;
6344 0 : }
6345 :
6346 0 : if (padsize) {
6347 0 : memset(padding, 0, padsize);
6348 0 : if (m_copyback(m, *off, padsize, &padding, M_NOWAIT))
6349 0 : return (OFP_ERRREQ_MULTIPART_OVERFLOW);
6350 :
6351 0 : *off += padsize;
6352 0 : }
6353 :
6354 0 : return (0);
6355 0 : }
6356 :
6357 : int
6358 0 : swofp_table_features_put_instruction(struct mbuf *m, int *off, uint16_t tp_type)
6359 : {
6360 0 : struct ofp_table_feature_property tp;
6361 0 : struct ofp_instruction instructions[] =
6362 : {
6363 : {
6364 : htons(OFP_INSTRUCTION_T_GOTO_TABLE),
6365 : htons(sizeof(struct ofp_instruction))
6366 : },
6367 : {
6368 : htons(OFP_INSTRUCTION_T_WRITE_META),
6369 : htons(sizeof(struct ofp_instruction))
6370 : },
6371 : {
6372 : htons(OFP_INSTRUCTION_T_WRITE_ACTIONS),
6373 : htons(sizeof(struct ofp_instruction))
6374 : },
6375 : {
6376 : htons(OFP_INSTRUCTION_T_APPLY_ACTIONS),
6377 : htons(sizeof(struct ofp_instruction))
6378 : },
6379 : {
6380 : htons(OFP_INSTRUCTION_T_CLEAR_ACTIONS),
6381 : htons(sizeof(struct ofp_instruction))
6382 : },
6383 : };
6384 :
6385 0 : tp.tp_type = htons(tp_type);
6386 0 : tp.tp_length = htons(sizeof(instructions) + sizeof(tp));
6387 :
6388 0 : if (m_copyback(m, *off, sizeof(tp), (caddr_t)&tp, M_NOWAIT))
6389 0 : return (OFP_ERRREQ_MULTIPART_OVERFLOW);
6390 0 : *off += sizeof(tp);
6391 :
6392 0 : if (m_copyback(m, *off, sizeof(instructions),
6393 0 : (caddr_t)instructions, M_NOWAIT))
6394 0 : return (OFP_ERRREQ_MULTIPART_OVERFLOW);
6395 0 : *off += sizeof(instructions);
6396 :
6397 0 : return (0);
6398 0 : }
6399 :
6400 : int
6401 0 : swofp_mp_recv_table_features(struct switch_softc *sc, struct mbuf *m)
6402 : {
6403 0 : struct swofp_ofs *ofs = sc->sc_ofs;
6404 : struct swofp_flow_table *swft;
6405 : struct ofp_table_features *tblf;
6406 : struct mbuf *n;
6407 0 : int off, error;
6408 0 : struct swofp_mpmsg swmp;
6409 :
6410 0 : if ((error = swofp_mpmsg_reply_create(
6411 0 : mtod(m, struct ofp_multipart *), &swmp)))
6412 : goto error;
6413 :
6414 0 : TAILQ_FOREACH(swft, &ofs->swofs_table_list, swft_table_next) {
6415 : /* using mbuf becouse table featrues struct is variable length*/
6416 0 : MGETHDR(n, M_DONTWAIT, MT_DATA);
6417 0 : if (n == NULL)
6418 : goto error;
6419 0 : MCLGET(n, M_DONTWAIT);
6420 0 : if ((n->m_flags & M_EXT) == 0) {
6421 0 : m_freem(n);
6422 0 : goto error;
6423 : }
6424 0 : n->m_len = n->m_pkthdr.len = sizeof(*tblf);
6425 :
6426 0 : tblf = mtod(n, struct ofp_table_features *);
6427 0 : memset(tblf, 0, sizeof(*tblf));
6428 0 : tblf->tf_tableid = swft->swft_table_id;
6429 0 : tblf->tf_metadata_match = UINT64_MAX;
6430 0 : tblf->tf_metadata_write = UINT64_MAX;
6431 0 : tblf->tf_config = 0;
6432 0 : tblf->tf_max_entries = htonl(ofs->swofs_flow_max_entry);
6433 :
6434 0 : off = sizeof(*tblf);
6435 0 : if ((error = swofp_table_features_put_instruction(n, &off,
6436 : OFP_TABLE_FEATPROP_INSTRUCTION)))
6437 : goto error;
6438 :
6439 0 : if ((error = swofp_table_features_put_instruction(n, &off,
6440 : OFP_TABLE_FEATPROP_INSTRUCTION_MISS)))
6441 : goto error;
6442 :
6443 0 : if ((error = swofp_table_features_put_actions(n, &off,
6444 : OFP_TABLE_FEATPROP_APPLY_ACTIONS)))
6445 : goto error;
6446 :
6447 0 : if ((error = swofp_table_features_put_actions(n, &off,
6448 : OFP_TABLE_FEATPROP_APPLY_ACTIONS_MISS)))
6449 : goto error;
6450 :
6451 0 : if ((error = swofp_table_features_put_actions(n, &off,
6452 : OFP_TABLE_FEATPROP_WRITE_ACTIONS)))
6453 : goto error;
6454 :
6455 0 : if ((error = swofp_table_features_put_actions(n, &off,
6456 : OFP_TABLE_FEATPROP_WRITE_ACTIONS_MISS)))
6457 : goto error;
6458 :
6459 0 : if ((error = swofp_table_features_put_oxm(n, &off,
6460 : OFP_TABLE_FEATPROP_MATCH)))
6461 : goto error;
6462 :
6463 0 : if ((error = swofp_table_features_put_oxm(n, &off,
6464 : OFP_TABLE_FEATPROP_WILDCARDS)))
6465 : goto error;
6466 :
6467 0 : if ((error = swofp_table_features_put_oxm(n, &off,
6468 : OFP_TABLE_FEATPROP_WRITE_SETFIELD)))
6469 : goto error;
6470 :
6471 0 : if ((error = swofp_table_features_put_oxm(n, &off,
6472 : OFP_TABLE_FEATPROP_WRITE_SETFIELD_MISS)))
6473 : goto error;
6474 :
6475 0 : if ((error = swofp_table_features_put_oxm(n, &off,
6476 : OFP_TABLE_FEATPROP_APPLY_SETFIELD)))
6477 : goto error;
6478 :
6479 0 : if ((error = swofp_table_features_put_oxm(n, &off,
6480 : OFP_TABLE_FEATPROP_APPLY_SETFIELD_MISS)))
6481 : goto error;
6482 :
6483 0 : tblf->tf_length = htons(n->m_pkthdr.len);
6484 :
6485 0 : if ((error = swofp_mpmsg_m_put(&swmp, n))) {
6486 0 : m_freem(n);
6487 0 : goto error;
6488 : }
6489 : }
6490 :
6491 0 : m_freem(m);
6492 0 : return swofp_multipart_reply(sc, &swmp);
6493 :
6494 : error:
6495 0 : m_freem(m);
6496 0 : swofp_mpmsg_destroy(&swmp);
6497 0 : return (error);
6498 0 : }
6499 :
6500 : int
6501 0 : swofp_mp_recv_port_desc(struct switch_softc *sc, struct mbuf *m)
6502 : {
6503 0 : struct ofp_switch_port swp;
6504 : struct switch_port *swpo;
6505 0 : struct swofp_mpmsg swmp;
6506 : struct ifnet *ifs;
6507 : int error;
6508 :
6509 0 : if ((error = swofp_mpmsg_reply_create(
6510 0 : mtod(m, struct ofp_multipart *), &swmp))) {
6511 0 : m_freem(m);
6512 0 : return (error);
6513 : }
6514 :
6515 0 : TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next) {
6516 0 : memset(&swp, 0, sizeof(swp));
6517 0 : ifs = if_get(swpo->swpo_ifindex);
6518 0 : if (ifs == NULL)
6519 : continue;
6520 :
6521 0 : if (swpo->swpo_flags & IFBIF_LOCAL)
6522 0 : swp.swp_number = htonl(OFP_PORT_LOCAL);
6523 : else
6524 0 : swp.swp_number = htonl(swpo->swpo_port_no);
6525 :
6526 0 : memcpy(swp.swp_macaddr,
6527 : ((struct arpcom *)ifs)->ac_enaddr, ETHER_ADDR_LEN);
6528 0 : strlcpy(swp.swp_name, ifs->if_xname,
6529 : sizeof(swp.swp_name));
6530 :
6531 0 : if (!ISSET(ifs->if_flags, IFF_UP))
6532 0 : swp.swp_config |= OFP_PORTCONFIG_PORT_DOWN;
6533 0 : if (!ISSET(swpo->swpo_flags, IFBIF_STP))
6534 0 : swp.swp_config |= OFP_PORTCONFIG_NO_STP;
6535 0 : swp.swp_config = htonl(swp.swp_config);
6536 :
6537 0 : if (!LINK_STATE_IS_UP(ifs->if_data.ifi_link_state))
6538 0 : swp.swp_state |= OFP_PORTSTATE_LINK_DOWN;
6539 :
6540 0 : if_put(ifs);
6541 :
6542 0 : swp.swp_state = htonl(swp.swp_state);
6543 : /* XXX how to get the if_media from ifp? ioctl? */
6544 0 : swp.swp_cur = htonl(swp.swp_cur);
6545 0 : swp.swp_advertised = htonl(swp.swp_advertised);
6546 0 : swp.swp_supported = htonl(swp.swp_supported);
6547 0 : swp.swp_peer = htonl(swp.swp_peer);
6548 :
6549 0 : if ((error = swofp_mpmsg_put(&swmp, (caddr_t)&swp,
6550 : sizeof(swp))))
6551 : goto error;
6552 : }
6553 :
6554 0 : m_freem(m);
6555 0 : return swofp_multipart_reply(sc, &swmp);
6556 :
6557 : error:
6558 0 : m_freem(m);
6559 0 : swofp_mpmsg_destroy(&swmp);
6560 0 : return (error);
6561 0 : }
6562 :
6563 : int
6564 0 : swofp_mp_recv_group_desc(struct switch_softc *sc, struct mbuf *m)
6565 : {
6566 0 : struct ofp_group_desc ogd;
6567 : struct swofp_group_entry *swge;
6568 0 : struct swofp_mpmsg swmp;
6569 : int error;
6570 :
6571 0 : if ((error = swofp_mpmsg_reply_create(
6572 0 : mtod(m, struct ofp_multipart *), &swmp)))
6573 : goto failed;
6574 :
6575 :
6576 0 : LIST_FOREACH(swge, &sc->sc_ofs->swofs_group_table, swge_next) {
6577 0 : memset(&ogd, 0, sizeof(ogd));
6578 :
6579 0 : ogd.gd_length = htons(offsetof(struct ofp_group_desc,
6580 : gd_buckets) + swge->swge_buckets_len);
6581 0 : ogd.gd_group_id = htonl(swge->swge_group_id);
6582 0 : ogd.gd_type = swge->swge_type;
6583 :
6584 : /*
6585 : * Copy back GROUP DESC without buckets
6586 : */
6587 0 : if ((error = swofp_mpmsg_put(&swmp, (caddr_t)&ogd,
6588 : sizeof(ogd))))
6589 : goto failed;
6590 :
6591 : /*
6592 : * Copy back buckets on GROUP DESC
6593 : */
6594 0 : if (swge->swge_buckets != NULL &&
6595 0 : (error = swofp_mpmsg_put(&swmp, (caddr_t)swge->swge_buckets,
6596 0 : swge->swge_buckets_len)))
6597 : goto failed;
6598 : }
6599 :
6600 0 : m_freem(m);
6601 0 : return swofp_multipart_reply(sc, &swmp);
6602 :
6603 : failed:
6604 0 : m_freem(m);
6605 0 : swofp_mpmsg_destroy(&swmp);
6606 0 : return (error);
6607 0 : }
6608 :
6609 : int
6610 0 : swofp_barrier_req(struct switch_softc *sc, struct mbuf *m)
6611 : {
6612 0 : swofp_barrier_reply(sc, m);
6613 0 : return 0;
6614 : }
6615 :
6616 : void
6617 0 : swofp_barrier_reply(struct switch_softc *sc, struct mbuf *m)
6618 : {
6619 : struct ofp_header *oh;
6620 :
6621 0 : oh = mtod(m, struct ofp_header *);
6622 0 : oh->oh_type = OFP_T_BARRIER_REPLY;
6623 :
6624 0 : (void)swofp_output(sc, m);
6625 0 : }
|