pio 0.22.0 → 0.23.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/README.md +1 -0
- data/Rakefile +1 -1
- data/features/open_flow13/match.feature +215 -0
- data/features/open_flow13/oxm_arp_op_field.raw +0 -0
- data/features/open_flow13/oxm_arp_sha_field.raw +0 -0
- data/features/open_flow13/oxm_arp_spa_field.raw +0 -0
- data/features/open_flow13/oxm_arp_tha_field.raw +0 -0
- data/features/open_flow13/oxm_arp_tpa_field.raw +0 -0
- data/features/open_flow13/oxm_masked_arp_sha_field.raw +0 -0
- data/features/open_flow13/oxm_masked_arp_spa_field.raw +0 -0
- data/features/open_flow13/oxm_masked_arp_tha_field.raw +0 -0
- data/features/open_flow13/oxm_masked_arp_tpa_field.raw +0 -0
- data/features/open_flow13/oxm_masked_tunnel_id_field.raw +0 -0
- data/features/open_flow13/oxm_tunnel_id_field.raw +0 -0
- data/features/open_flow13/packet_out.feature +96 -0
- data/lib/pio/open_flow13.rb +1 -0
- data/lib/pio/open_flow13/actions.rb +42 -0
- data/lib/pio/open_flow13/apply.rb +1 -39
- data/lib/pio/open_flow13/buffer_id.rb +17 -0
- data/lib/pio/open_flow13/flow_mod.rb +1 -16
- data/lib/pio/open_flow13/match.rb +197 -4
- data/lib/pio/open_flow13/packet_out.rb +90 -0
- data/lib/pio/version.rb +1 -1
- data/spec/pio/open_flow13/match_spec.rb +290 -0
- metadata +29 -2
@@ -1,48 +1,10 @@
|
|
1
1
|
require 'bindata'
|
2
2
|
require 'forwardable'
|
3
|
+
require 'pio/open_flow13/actions'
|
3
4
|
|
4
5
|
module Pio
|
5
6
|
# An instruction to apply a list of actions to a packet in-order.
|
6
7
|
class Apply
|
7
|
-
# Actions not yet implemented.
|
8
|
-
class UnsupportedAction < BinData::Record
|
9
|
-
endian :big
|
10
|
-
|
11
|
-
uint16 :action_type
|
12
|
-
uint16 :action_length
|
13
|
-
end
|
14
|
-
|
15
|
-
# Actions list of actions-apply instruction.
|
16
|
-
class Actions < BinData::Primitive
|
17
|
-
mandatory_parameter :length
|
18
|
-
|
19
|
-
endian :big
|
20
|
-
|
21
|
-
string :binary, read_length: :length
|
22
|
-
|
23
|
-
def set(value)
|
24
|
-
self.binary = [value].flatten.map(&:to_binary).join
|
25
|
-
end
|
26
|
-
|
27
|
-
# rubocop:disable MethodLength
|
28
|
-
def get
|
29
|
-
actions = []
|
30
|
-
tmp = binary
|
31
|
-
while tmp.length > 0
|
32
|
-
action = case BinData::Uint16be.read(tmp)
|
33
|
-
when 0
|
34
|
-
SendOutPort.read(tmp)
|
35
|
-
else
|
36
|
-
UnsupportedAction.read(tmp)
|
37
|
-
end
|
38
|
-
tmp = tmp[action.action_length..-1]
|
39
|
-
actions << action
|
40
|
-
end
|
41
|
-
actions
|
42
|
-
end
|
43
|
-
# rubocop:enable MethodLength
|
44
|
-
end
|
45
|
-
|
46
8
|
# OpenFlow 1.3.4 OFPIT_APPLY_ACTIONS instruction format.
|
47
9
|
class Format < BinData::Record
|
48
10
|
endian :big
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Pio
|
2
|
+
# Buffered packet to apply to, or :no_buffer.
|
3
|
+
class BufferId < BinData::Primitive
|
4
|
+
NO_BUFFER = 0xffffffff
|
5
|
+
|
6
|
+
endian :big
|
7
|
+
uint32 :buffer_id, initial_value: NO_BUFFER
|
8
|
+
|
9
|
+
def get
|
10
|
+
(buffer_id == NO_BUFFER) ? :no_buffer : buffer_id
|
11
|
+
end
|
12
|
+
|
13
|
+
def set(value)
|
14
|
+
self.buffer_id = (value == :no_buffer ? NO_BUFFER : value)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'forwardable'
|
2
2
|
require 'pio/open_flow'
|
3
|
+
require 'pio/open_flow13/buffer_id'
|
3
4
|
require 'pio/open_flow13/match'
|
4
5
|
|
5
6
|
# Base module.
|
@@ -29,22 +30,6 @@ module Pio
|
|
29
30
|
end
|
30
31
|
end
|
31
32
|
|
32
|
-
# Buffered packet to apply to, or :no_buffer.
|
33
|
-
class BufferId < BinData::Primitive
|
34
|
-
NO_BUFFER = 0xffffffff
|
35
|
-
|
36
|
-
endian :big
|
37
|
-
uint32 :buffer_id, initial_value: NO_BUFFER
|
38
|
-
|
39
|
-
def get
|
40
|
-
(buffer_id == NO_BUFFER) ? :no_buffer : buffer_id
|
41
|
-
end
|
42
|
-
|
43
|
-
def set(value)
|
44
|
-
self.buffer_id = (value == :no_buffer ? NO_BUFFER : value)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
33
|
# For delete commands, require matching entries to include this as
|
49
34
|
# an output port.
|
50
35
|
class OutPort < BinData::Primitive
|
@@ -348,6 +348,125 @@ module Pio
|
|
348
348
|
end
|
349
349
|
end
|
350
350
|
|
351
|
+
# The value of OXM_OF_ARP_OP
|
352
|
+
class ArpOp < BinData::Record
|
353
|
+
OXM_FIELD = 21
|
354
|
+
|
355
|
+
endian :big
|
356
|
+
|
357
|
+
uint16 :arp_op
|
358
|
+
|
359
|
+
def length
|
360
|
+
2
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
# The value of OXM_OF_ARP_SPA
|
365
|
+
class ArpSenderProtocolAddress < BinData::Record
|
366
|
+
OXM_FIELD = 22
|
367
|
+
|
368
|
+
endian :big
|
369
|
+
|
370
|
+
ip_address :arp_sender_protocol_address
|
371
|
+
|
372
|
+
def length
|
373
|
+
4
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
# The value of masked OXM_OF_ARP_SPA
|
378
|
+
class MaskedArpSenderProtocolAddress < BinData::Record
|
379
|
+
OXM_FIELD = 22
|
380
|
+
|
381
|
+
endian :big
|
382
|
+
ip_address :arp_sender_protocol_address
|
383
|
+
ip_address :arp_sender_protocol_address_mask
|
384
|
+
|
385
|
+
def length
|
386
|
+
8
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
# The value of OXM_OF_ARP_TPA
|
391
|
+
class ArpTargetProtocolAddress < BinData::Record
|
392
|
+
OXM_FIELD = 23
|
393
|
+
|
394
|
+
endian :big
|
395
|
+
|
396
|
+
ip_address :arp_target_protocol_address
|
397
|
+
|
398
|
+
def length
|
399
|
+
4
|
400
|
+
end
|
401
|
+
end
|
402
|
+
|
403
|
+
# The value of masked OXM_OF_ARP_TPA
|
404
|
+
class MaskedArpTargetProtocolAddress < BinData::Record
|
405
|
+
OXM_FIELD = 23
|
406
|
+
|
407
|
+
endian :big
|
408
|
+
ip_address :arp_target_protocol_address
|
409
|
+
ip_address :arp_target_protocol_address_mask
|
410
|
+
|
411
|
+
def length
|
412
|
+
8
|
413
|
+
end
|
414
|
+
end
|
415
|
+
|
416
|
+
# The value of OXM_OF_ARP_SHA match field.
|
417
|
+
class ArpSenderHardwareAddress < BinData::Record
|
418
|
+
OXM_FIELD = 24
|
419
|
+
|
420
|
+
endian :big
|
421
|
+
|
422
|
+
mac_address :arp_sender_hardware_address
|
423
|
+
|
424
|
+
def length
|
425
|
+
6
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
429
|
+
# Masked OXM_OF_ARP_SHA match field.
|
430
|
+
class MaskedArpSenderHardwareAddress < BinData::Record
|
431
|
+
OXM_FIELD = 24
|
432
|
+
|
433
|
+
endian :big
|
434
|
+
|
435
|
+
mac_address :arp_sender_hardware_address
|
436
|
+
mac_address :arp_sender_hardware_address_mask
|
437
|
+
|
438
|
+
def length
|
439
|
+
12
|
440
|
+
end
|
441
|
+
end
|
442
|
+
|
443
|
+
# The value of OXM_OF_ARP_THA match field.
|
444
|
+
class ArpTargetHardwareAddress < BinData::Record
|
445
|
+
OXM_FIELD = 25
|
446
|
+
|
447
|
+
endian :big
|
448
|
+
|
449
|
+
mac_address :arp_target_hardware_address
|
450
|
+
|
451
|
+
def length
|
452
|
+
6
|
453
|
+
end
|
454
|
+
end
|
455
|
+
|
456
|
+
# Masked OXM_OF_ARP_THA match field.
|
457
|
+
class MaskedArpTargetHardwareAddress < BinData::Record
|
458
|
+
OXM_FIELD = 25
|
459
|
+
|
460
|
+
endian :big
|
461
|
+
|
462
|
+
mac_address :arp_target_hardware_address
|
463
|
+
mac_address :arp_target_hardware_address_mask
|
464
|
+
|
465
|
+
def length
|
466
|
+
12
|
467
|
+
end
|
468
|
+
end
|
469
|
+
|
351
470
|
# The value of OXM_OF_IPV6_SRC
|
352
471
|
class Ipv6SourceAddress < BinData::Record
|
353
472
|
OXM_FIELD = 26
|
@@ -402,9 +521,35 @@ module Pio
|
|
402
521
|
end
|
403
522
|
end
|
404
523
|
|
524
|
+
# The value of OXM_OF_TUNNEL_ID match field
|
525
|
+
class TunnelId < BinData::Record
|
526
|
+
OXM_FIELD = 38
|
527
|
+
|
528
|
+
endian :big
|
529
|
+
|
530
|
+
uint64 :tunnel_id
|
531
|
+
|
532
|
+
def length
|
533
|
+
8
|
534
|
+
end
|
535
|
+
end
|
536
|
+
|
537
|
+
# Masked OXM_OF_TUNNEL_ID match field
|
538
|
+
class MaskedTunnelId < BinData::Record
|
539
|
+
endian :big
|
540
|
+
|
541
|
+
uint64 :tunnel_id
|
542
|
+
uint64 :tunnel_id_mask
|
543
|
+
|
544
|
+
def length
|
545
|
+
16
|
546
|
+
end
|
547
|
+
end
|
548
|
+
|
405
549
|
# OXM format
|
406
550
|
class Oxm < BinData::Record
|
407
551
|
# OXM match field.
|
552
|
+
# rubocop:disable ClassLength
|
408
553
|
class MatchField < BinData::Record
|
409
554
|
endian :big
|
410
555
|
|
@@ -438,12 +583,23 @@ module Pio
|
|
438
583
|
udp_destination_port UdpDestinationPort
|
439
584
|
sctp_source_port SctpSourcePort
|
440
585
|
sctp_destination_port SctpDestinationPort
|
586
|
+
arp_op ArpOp
|
587
|
+
arp_sender_protocol_address ArpSenderProtocolAddress
|
588
|
+
masked_arp_sender_protocol_address MaskedArpSenderProtocolAddress
|
589
|
+
arp_target_protocol_address ArpTargetProtocolAddress
|
590
|
+
masked_arp_target_protocol_address MaskedArpTargetProtocolAddress
|
591
|
+
arp_sender_hardware_address ArpSenderHardwareAddress
|
592
|
+
masked_arp_sender_hardware_address MaskedArpSenderHardwareAddress
|
593
|
+
arp_target_hardware_address ArpTargetHardwareAddress
|
594
|
+
masked_arp_target_hardware_address MaskedArpTargetHardwareAddress
|
441
595
|
icmpv4_type Icmpv4Type
|
442
596
|
icmpv4_code Icmpv4Code
|
443
597
|
ipv6_source_address Ipv6SourceAddress
|
444
598
|
masked_ipv6_source_address MaskedIpv6SourceAddress
|
445
599
|
ipv6_destination_address Ipv6DestinationAddress
|
446
600
|
masked_ipv6_destination_address MaskedIpv6DestinationAddress
|
601
|
+
tunnel_id TunnelId
|
602
|
+
masked_tunnel_id MaskedTunnelId
|
447
603
|
end
|
448
604
|
|
449
605
|
def length
|
@@ -506,10 +662,42 @@ module Pio
|
|
506
662
|
Icmpv4Type
|
507
663
|
when Icmpv4Code::OXM_FIELD
|
508
664
|
Icmpv4Code
|
665
|
+
when ArpOp::OXM_FIELD
|
666
|
+
ArpOp
|
667
|
+
when ArpSenderProtocolAddress::OXM_FIELD
|
668
|
+
if masked?
|
669
|
+
MaskedArpSenderProtocolAddress
|
670
|
+
else
|
671
|
+
ArpSenderProtocolAddress
|
672
|
+
end
|
673
|
+
when ArpTargetProtocolAddress::OXM_FIELD
|
674
|
+
if masked?
|
675
|
+
MaskedArpTargetProtocolAddress
|
676
|
+
else
|
677
|
+
ArpTargetProtocolAddress
|
678
|
+
end
|
679
|
+
when ArpSenderHardwareAddress::OXM_FIELD
|
680
|
+
if masked?
|
681
|
+
MaskedArpSenderHardwareAddress
|
682
|
+
else
|
683
|
+
ArpSenderHardwareAddress
|
684
|
+
end
|
685
|
+
when ArpTargetHardwareAddress::OXM_FIELD
|
686
|
+
if masked?
|
687
|
+
MaskedArpTargetHardwareAddress
|
688
|
+
else
|
689
|
+
ArpTargetHardwareAddress
|
690
|
+
end
|
509
691
|
when Ipv6SourceAddress::OXM_FIELD
|
510
|
-
masked?
|
692
|
+
if masked?
|
693
|
+
MaskedIpv6SourceAddress
|
694
|
+
else
|
695
|
+
Ipv6SourceAddress
|
696
|
+
end
|
511
697
|
when Ipv6DestinationAddress::OXM_FIELD
|
512
698
|
masked? ? MaskedIpv6DestinationAddress : Ipv6DestinationAddress
|
699
|
+
when TunnelId::OXM_FIELD
|
700
|
+
masked? ? MaskedTunnelId : TunnelId
|
513
701
|
else
|
514
702
|
fail "Unknown OXM field value: #{oxm_field}"
|
515
703
|
end
|
@@ -519,6 +707,7 @@ module Pio
|
|
519
707
|
# rubocop:enable PerceivedComplexity
|
520
708
|
# rubocop:enable AbcSize
|
521
709
|
end
|
710
|
+
# rubocop:enable MethodLength
|
522
711
|
|
523
712
|
endian :big
|
524
713
|
|
@@ -571,8 +760,9 @@ module Pio
|
|
571
760
|
|
572
761
|
[:in_port, :ether_type, :ip_protocol, :vlan_vid, :vlan_pcp,
|
573
762
|
:ip_dscp, :ip_ecn, :tcp_source_port, :tcp_destination_port,
|
574
|
-
:udp_source_port, :udp_destination_port,
|
575
|
-
:
|
763
|
+
:udp_source_port, :udp_destination_port,
|
764
|
+
:sctp_source_port, :sctp_destination_port,
|
765
|
+
:icmpv4_type, :icmpv4_code, :arp_op].each do |each|
|
576
766
|
next unless user_attrs.key?(each)
|
577
767
|
klass = Match.const_get(each.to_s.split('_').map(&:capitalize).join)
|
578
768
|
@match_fields << { oxm_field: klass.const_get(:OXM_FIELD),
|
@@ -581,7 +771,10 @@ module Pio
|
|
581
771
|
|
582
772
|
[:metadata, :ether_destination_address, :ether_source_address,
|
583
773
|
:ipv4_source_address, :ipv4_destination_address,
|
584
|
-
:
|
774
|
+
:arp_sender_protocol_address, :arp_target_protocol_address,
|
775
|
+
:arp_sender_hardware_address, :arp_target_hardware_address,
|
776
|
+
:ipv6_source_address, :ipv6_destination_address,
|
777
|
+
:tunnel_id].each do |each|
|
585
778
|
next unless user_attrs.key?(each)
|
586
779
|
klass = Match.const_get(each.to_s.split('_').map(&:capitalize).join)
|
587
780
|
mask_key = "#{each}_mask".to_sym
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'bindata'
|
2
|
+
require 'pio/open_flow13/actions'
|
3
|
+
require 'pio/open_flow13/buffer_id'
|
4
|
+
|
5
|
+
# Base module.
|
6
|
+
module Pio
|
7
|
+
remove_const :PacketOut
|
8
|
+
|
9
|
+
# OpenFlow 1.3 PacketOut message parser and generator
|
10
|
+
class PacketOut
|
11
|
+
# Packet's input port or :controller
|
12
|
+
class InPort < BinData::Primitive
|
13
|
+
CONTROLLER = 0xfffffffd
|
14
|
+
|
15
|
+
endian :big
|
16
|
+
uint32 :in_port
|
17
|
+
|
18
|
+
def get
|
19
|
+
(in_port == CONTROLLER) ? :controller : in_port
|
20
|
+
end
|
21
|
+
|
22
|
+
def set(value)
|
23
|
+
self.in_port = (value == :controller ? NO_CONTROLLER : value)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# OpenFlow 1.3 PacketOut message body
|
28
|
+
class Body < BinData::Record
|
29
|
+
endian :big
|
30
|
+
|
31
|
+
buffer_id :buffer_id
|
32
|
+
in_port :in_port
|
33
|
+
uint16 :actions_length, initial_value: -> { actions.binary.length }
|
34
|
+
string :padding, length: 6
|
35
|
+
actions :actions, length: :actions_length
|
36
|
+
string :raw_data, read_length: -> { message_length - 24 - actions_length }
|
37
|
+
|
38
|
+
def length
|
39
|
+
10 + padding.length + actions_length + raw_data.length
|
40
|
+
end
|
41
|
+
|
42
|
+
def data
|
43
|
+
@data ||= Pio::Parser.read(raw_data)
|
44
|
+
end
|
45
|
+
|
46
|
+
def method_missing(method, *args)
|
47
|
+
data.__send__(method, *args).snapshot
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# OpenFlow 1.3 PacketOut message body
|
52
|
+
class Format < BinData::Record
|
53
|
+
extend Forwardable
|
54
|
+
|
55
|
+
endian :big
|
56
|
+
|
57
|
+
open_flow_header :open_flow_header,
|
58
|
+
ofp_version_value: 4, message_type_value: 13
|
59
|
+
body :body
|
60
|
+
|
61
|
+
def_delegators :open_flow_header, :ofp_version
|
62
|
+
def_delegators :open_flow_header, :message_type
|
63
|
+
def_delegators :open_flow_header, :message_length
|
64
|
+
def_delegators :open_flow_header, :transaction_id
|
65
|
+
def_delegator :open_flow_header, :transaction_id, :xid
|
66
|
+
|
67
|
+
def method_missing(method, *args, &block)
|
68
|
+
body.__send__ method, *args, &block
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.read(raw_data)
|
73
|
+
allocate.tap do |message|
|
74
|
+
message.instance_variable_set(:@format, Format.read(raw_data))
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def initialize(user_attrs = {})
|
79
|
+
header_attrs = OpenFlowHeader::Options.parse(user_attrs)
|
80
|
+
body_attrs = { actions: user_attrs[:actions],
|
81
|
+
raw_data: user_attrs[:raw_data] }
|
82
|
+
@format = Format.new(open_flow_header: header_attrs,
|
83
|
+
body: body_attrs)
|
84
|
+
end
|
85
|
+
|
86
|
+
def method_missing(method, *args, &block)
|
87
|
+
@format.__send__ method, *args, &block
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|