1use bytes::Bytes;
4
5use crate::instruction::{Instruction, InstructionList};
6use crate::message::{Message, MessageType};
7use crate::{ActionList, Match, Version};
8
9#[derive(Debug, Clone)]
11pub struct FlowStats {
12 pub table_id: u8,
14 pub priority: u16,
16 pub cookie: u64,
18 pub match_fields: Match,
20 pub actions: ActionList,
22 pub idle_timeout: u16,
24 pub hard_timeout: u16,
26 pub packet_count: u64,
28 pub byte_count: u64,
30}
31
32#[derive(Debug, Clone, Copy, PartialEq, Eq)]
34#[repr(u8)]
35pub enum FlowCommand {
36 Add = 0,
38 Modify = 1,
40 ModifyStrict = 2,
42 Delete = 3,
44 DeleteStrict = 4,
46}
47
48#[derive(Debug, Clone, Copy, Default)]
50pub struct FlowFlags {
51 pub send_flow_rem: bool,
53 pub check_overlap: bool,
55 pub reset_counts: bool,
57 pub no_pkt_counts: bool,
59 pub no_byte_counts: bool,
61}
62
63pub mod flow_flags {
65 pub const SEND_FLOW_REM: u16 = 1 << 0;
67 pub const CHECK_OVERLAP: u16 = 1 << 1;
69 pub const RESET_COUNTS: u16 = 1 << 2;
71 pub const NO_PKT_COUNTS: u16 = 1 << 3;
73 pub const NO_BYT_COUNTS: u16 = 1 << 4;
75}
76
77impl FlowFlags {
78 pub fn to_wire(self) -> u16 {
80 let mut flags = 0u16;
81 if self.send_flow_rem {
82 flags |= flow_flags::SEND_FLOW_REM;
83 }
84 if self.check_overlap {
85 flags |= flow_flags::CHECK_OVERLAP;
86 }
87 if self.reset_counts {
88 flags |= flow_flags::RESET_COUNTS;
89 }
90 if self.no_pkt_counts {
91 flags |= flow_flags::NO_PKT_COUNTS;
92 }
93 if self.no_byte_counts {
94 flags |= flow_flags::NO_BYT_COUNTS;
95 }
96 flags
97 }
98}
99
100pub const OFPP_ANY: u32 = 0xffff_ffff;
102pub const OFPG_ANY: u32 = 0xffff_ffff;
104pub const OFP_NO_BUFFER: u32 = 0xffff_ffff;
106
107#[derive(Debug, Clone)]
109pub struct Flow {
110 pub command: FlowCommand,
112 pub table_id: u8,
114 pub priority: u16,
116 pub cookie: u64,
118 pub cookie_mask: u64,
120 pub match_fields: Match,
122 pub actions: ActionList,
124 pub instructions: InstructionList,
126 pub idle_timeout: u16,
128 pub hard_timeout: u16,
130 pub flags: FlowFlags,
132 pub out_port: Option<u32>,
134 pub out_group: Option<u32>,
136 pub buffer_id: Option<u32>,
138}
139
140impl Flow {
141 pub fn add() -> Self {
143 Self {
144 command: FlowCommand::Add,
145 table_id: 0,
146 priority: 0,
147 cookie: 0,
148 cookie_mask: 0,
149 match_fields: Match::new(),
150 actions: ActionList::new(),
151 instructions: InstructionList::new(),
152 idle_timeout: 0,
153 hard_timeout: 0,
154 flags: FlowFlags::default(),
155 out_port: None,
156 out_group: None,
157 buffer_id: None,
158 }
159 }
160
161 pub fn delete() -> Self {
163 Self {
164 command: FlowCommand::Delete,
165 table_id: 0xff, priority: 0,
167 cookie: 0,
168 cookie_mask: 0,
169 match_fields: Match::new(),
170 actions: ActionList::new(),
171 instructions: InstructionList::new(),
172 idle_timeout: 0,
173 hard_timeout: 0,
174 flags: FlowFlags::default(),
175 out_port: None,
176 out_group: None,
177 buffer_id: None,
178 }
179 }
180
181 pub fn table(mut self, id: u8) -> Self {
183 self.table_id = id;
184 self
185 }
186
187 pub fn priority(mut self, priority: u16) -> Self {
189 self.priority = priority;
190 self
191 }
192
193 pub fn cookie(mut self, cookie: u64) -> Self {
195 self.cookie = cookie;
196 self
197 }
198
199 pub fn match_fields(mut self, m: Match) -> Self {
201 self.match_fields = m;
202 self
203 }
204
205 pub fn actions(mut self, actions: ActionList) -> Self {
207 self.actions = actions;
208 self
209 }
210
211 pub fn instructions(mut self, instructions: InstructionList) -> Self {
213 self.instructions = instructions;
214 self
215 }
216
217 pub fn idle_timeout(mut self, timeout: u16) -> Self {
219 self.idle_timeout = timeout;
220 self
221 }
222
223 pub fn hard_timeout(mut self, timeout: u16) -> Self {
225 self.hard_timeout = timeout;
226 self
227 }
228
229 fn encode_fixed(&self) -> [u8; 40] {
253 let mut buf = [0u8; 40];
254
255 buf[0..8].copy_from_slice(&self.cookie.to_be_bytes());
257
258 buf[8..16].copy_from_slice(&self.cookie_mask.to_be_bytes());
260
261 buf[16] = self.table_id;
263
264 buf[17] = self.command as u8;
266
267 buf[18..20].copy_from_slice(&self.idle_timeout.to_be_bytes());
269
270 buf[20..22].copy_from_slice(&self.hard_timeout.to_be_bytes());
272
273 buf[22..24].copy_from_slice(&self.priority.to_be_bytes());
275
276 let buffer_id = self.buffer_id.unwrap_or(OFP_NO_BUFFER);
278 buf[24..28].copy_from_slice(&buffer_id.to_be_bytes());
279
280 let out_port = self.out_port.unwrap_or(OFPP_ANY);
282 buf[28..32].copy_from_slice(&out_port.to_be_bytes());
283
284 let out_group = self.out_group.unwrap_or(OFPG_ANY);
286 buf[32..36].copy_from_slice(&out_group.to_be_bytes());
287
288 buf[36..38].copy_from_slice(&self.flags.to_wire().to_be_bytes());
290
291 buf
294 }
295
296 pub fn encode(&self) -> Vec<u8> {
300 let fixed = self.encode_fixed();
301 let match_bytes = self.match_fields.encode();
302
303 let instruction_bytes = if self.instructions.is_empty() && !self.actions.is_empty() {
305 let inst = Instruction::ApplyActions(self.actions.clone());
307 inst.encode()
308 } else {
309 self.instructions.encode()
310 };
311
312 let mut buf = Vec::with_capacity(40 + match_bytes.len() + instruction_bytes.len());
313 buf.extend_from_slice(&fixed);
314 buf.extend(match_bytes);
315 buf.extend(instruction_bytes);
316 buf
317 }
318
319 pub fn to_message(&self, version: Version, xid: u32) -> Message {
325 let body = self.encode();
326 Message::new(version, MessageType::FlowMod, xid, Bytes::from(body))
327 }
328}
329
330#[cfg(test)]
335mod tests {
336 use super::*;
337 use crate::action::OutputPort;
338
339 #[test]
340 fn flow_flags_to_wire_empty() {
341 let flags = FlowFlags::default();
342 assert_eq!(flags.to_wire(), 0);
343 }
344
345 #[test]
346 fn flow_flags_to_wire_all() {
347 let flags = FlowFlags {
348 send_flow_rem: true,
349 check_overlap: true,
350 reset_counts: true,
351 no_pkt_counts: true,
352 no_byte_counts: true,
353 };
354 assert_eq!(flags.to_wire(), 0b11111);
355 }
356
357 #[test]
358 fn flow_flags_to_wire_send_flow_rem() {
359 let flags = FlowFlags {
360 send_flow_rem: true,
361 ..Default::default()
362 };
363 assert_eq!(flags.to_wire(), flow_flags::SEND_FLOW_REM);
364 }
365
366 #[test]
367 fn flow_command_wire_values() {
368 assert_eq!(FlowCommand::Add as u8, 0);
369 assert_eq!(FlowCommand::Modify as u8, 1);
370 assert_eq!(FlowCommand::ModifyStrict as u8, 2);
371 assert_eq!(FlowCommand::Delete as u8, 3);
372 assert_eq!(FlowCommand::DeleteStrict as u8, 4);
373 }
374
375 #[test]
376 fn encode_fixed_fields_add() {
377 let flow = Flow::add()
378 .table(1)
379 .priority(100)
380 .cookie(0x1234_5678_9abc_def0)
381 .idle_timeout(60)
382 .hard_timeout(120);
383
384 let fixed = flow.encode_fixed();
385 assert_eq!(fixed.len(), 40);
386
387 assert_eq!(
389 &fixed[0..8],
390 &[0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0]
391 );
392
393 assert_eq!(&fixed[8..16], &[0, 0, 0, 0, 0, 0, 0, 0]);
395
396 assert_eq!(fixed[16], 1);
398
399 assert_eq!(fixed[17], 0);
401
402 assert_eq!(&fixed[18..20], &[0x00, 0x3c]);
404
405 assert_eq!(&fixed[20..22], &[0x00, 0x78]);
407
408 assert_eq!(&fixed[22..24], &[0x00, 0x64]);
410
411 assert_eq!(&fixed[24..28], &[0xff, 0xff, 0xff, 0xff]);
413
414 assert_eq!(&fixed[28..32], &[0xff, 0xff, 0xff, 0xff]);
416
417 assert_eq!(&fixed[32..36], &[0xff, 0xff, 0xff, 0xff]);
419
420 assert_eq!(&fixed[36..38], &[0x00, 0x00]);
422
423 assert_eq!(&fixed[38..40], &[0x00, 0x00]);
425 }
426
427 #[test]
428 fn encode_fixed_fields_delete() {
429 let flow = Flow::delete().table(0xff);
430
431 let fixed = flow.encode_fixed();
432
433 assert_eq!(fixed[16], 0xff);
435
436 assert_eq!(fixed[17], 3);
438 }
439
440 #[test]
441 fn encode_flow_with_match() {
442 let flow = Flow::add()
443 .table(0)
444 .priority(100)
445 .match_fields(Match::new().in_port(1));
446
447 let bytes = flow.encode();
448
449 assert!(bytes.len() >= 56);
451
452 assert_eq!(bytes[16], 0); assert_eq!(bytes[17], 0); }
456
457 #[test]
458 fn encode_flow_with_actions() {
459 let flow = Flow::add()
460 .table(0)
461 .priority(100)
462 .match_fields(Match::new().in_port(1))
463 .actions(ActionList::new().output(OutputPort::Port(2)));
464
465 let bytes = flow.encode();
466
467 assert_eq!(bytes.len(), 80);
469
470 assert_eq!(&bytes[56..58], &[0x00, 0x04]);
474 }
475
476 #[test]
477 fn encode_flow_with_instructions() {
478 let flow = Flow::add()
479 .table(0)
480 .priority(100)
481 .match_fields(Match::new().in_port(1))
482 .instructions(InstructionList::new().goto_table(5));
483
484 let bytes = flow.encode();
485
486 assert_eq!(bytes.len(), 64);
488
489 assert_eq!(&bytes[56..58], &[0x00, 0x01]); assert_eq!(bytes[60], 5); }
493
494 #[test]
495 fn to_message_creates_valid_header() {
496 let flow = Flow::add()
497 .table(0)
498 .priority(100)
499 .match_fields(Match::new().in_port(1));
500
501 let msg = flow.to_message(Version::Of13, 0x1234);
502
503 assert_eq!(msg.header.version, Version::Of13);
505 assert_eq!(msg.header.msg_type, MessageType::FlowMod);
506 assert_eq!(msg.header.xid, 0x1234);
507
508 let expected_len = 8 + flow.encode().len();
510 assert_eq!(msg.header.length as usize, expected_len);
511 }
512
513 #[test]
514 fn to_message_encodes_correctly() {
515 let flow = Flow::add()
516 .table(0)
517 .priority(100)
518 .match_fields(Match::new().in_port(1))
519 .actions(ActionList::new().output(OutputPort::Port(2)));
520
521 let msg = flow.to_message(Version::Of13, 42);
522 let encoded = msg.encode();
523
524 assert_eq!(encoded[0], 0x04); assert_eq!(encoded[1], 14); assert_eq!(encoded[6], 0); assert_eq!(encoded[7], 42); assert_eq!(encoded[24], 0); }
534
535 #[test]
536 fn flow_builder_chain() {
537 let flow = Flow::add()
538 .table(5)
539 .priority(1000)
540 .cookie(0xdead_beef)
541 .idle_timeout(300)
542 .hard_timeout(600)
543 .match_fields(Match::new().eth_type(0x0800).ipv4_dst("10.0.0.0".parse().unwrap(), 24))
544 .actions(ActionList::new().output(OutputPort::Port(1)));
545
546 assert_eq!(flow.table_id, 5);
547 assert_eq!(flow.priority, 1000);
548 assert_eq!(flow.cookie, 0xdead_beef);
549 assert_eq!(flow.idle_timeout, 300);
550 assert_eq!(flow.hard_timeout, 600);
551 }
552}