rubybvc 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/controller/controller.rb +445 -0
- data/lib/controller/netconf_node.rb +55 -0
- data/lib/controller/node.rb +41 -0
- data/lib/controller/openflow_node.rb +33 -0
- data/lib/netconfdev/vrouter/dataplane_firewall.rb +53 -0
- data/lib/netconfdev/vrouter/firewall.rb +44 -0
- data/lib/netconfdev/vrouter/rule.rb +53 -0
- data/lib/netconfdev/vrouter/rules.rb +53 -0
- data/lib/netconfdev/vrouter/vrouter5600.rb +242 -0
- data/lib/openflowdev/action_output.rb +71 -0
- data/lib/openflowdev/actions/action.rb +39 -0
- data/lib/openflowdev/actions/actions.rb +63 -0
- data/lib/openflowdev/actions/copy_ttl_inwards_action.rb +39 -0
- data/lib/openflowdev/actions/copy_ttl_outwards_action.rb +39 -0
- data/lib/openflowdev/actions/dec_mpls_ttl_action.rb +39 -0
- data/lib/openflowdev/actions/dec_nw_ttl_action.rb +39 -0
- data/lib/openflowdev/actions/drop_action.rb +37 -0
- data/lib/openflowdev/actions/flood_action.rb +39 -0
- data/lib/openflowdev/actions/flood_all_action.rb +39 -0
- data/lib/openflowdev/actions/group_action.rb +44 -0
- data/lib/openflowdev/actions/hw_path_action.rb +39 -0
- data/lib/openflowdev/actions/loopback_action.rb +39 -0
- data/lib/openflowdev/actions/output_action.rb +43 -0
- data/lib/openflowdev/actions/pop_mpls_header_action.rb +41 -0
- data/lib/openflowdev/actions/pop_pbb_header_action.rb +39 -0
- data/lib/openflowdev/actions/pop_vlan_header_action.rb +39 -0
- data/lib/openflowdev/actions/push_mpls_header_action.rb +41 -0
- data/lib/openflowdev/actions/push_pbb_header_action.rb +40 -0
- data/lib/openflowdev/actions/push_vlan_header_action.rb +46 -0
- data/lib/openflowdev/actions/set_dl_dst_action.rb +41 -0
- data/lib/openflowdev/actions/set_dl_src_action.rb +41 -0
- data/lib/openflowdev/actions/set_field_action.rb +43 -0
- data/lib/openflowdev/actions/set_mpls_ttl_action.rb +41 -0
- data/lib/openflowdev/actions/set_nw_dst_action.rb +41 -0
- data/lib/openflowdev/actions/set_nw_src_action.rb +41 -0
- data/lib/openflowdev/actions/set_nw_ttl_action.rb +41 -0
- data/lib/openflowdev/actions/set_queue_action.rb +44 -0
- data/lib/openflowdev/actions/set_tp_dst_action.rb +41 -0
- data/lib/openflowdev/actions/set_tp_src_action.rb +41 -0
- data/lib/openflowdev/actions/set_vlan_cfi_action.rb +41 -0
- data/lib/openflowdev/actions/set_vlan_id_action.rb +41 -0
- data/lib/openflowdev/actions/set_vlan_pcp_action.rb +41 -0
- data/lib/openflowdev/actions/strip_vlan_action.rb +35 -0
- data/lib/openflowdev/actions/sw_path_action.rb +39 -0
- data/lib/openflowdev/flow_entry.rb +91 -0
- data/lib/openflowdev/instruction.rb +53 -0
- data/lib/openflowdev/match.rb +121 -0
- data/lib/openflowdev/of_switch.rb +374 -0
- data/lib/rubybvc.rb +52 -0
- data/lib/utils/hash_with_compact.rb +46 -0
- data/lib/utils/netconf_response.rb +67 -0
- data/lib/utils/netconf_response_status.rb +41 -0
- data/lib/utils/rest_agent.rb +103 -0
- data/lib/utils/utilities.rb +51 -0
- metadata +111 -0
@@ -0,0 +1,53 @@
|
|
1
|
+
# Copyright (c) 2015, BROCADE COMMUNICATIONS SYSTEMS, INC
|
2
|
+
#
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Redistribution and use in source and binary forms, with or without modification,
|
6
|
+
# are permitted provided that the following conditions are met:
|
7
|
+
#
|
8
|
+
# 1. Redistributions of source code must retain the above copyright notice, this
|
9
|
+
# list of conditions and the following disclaimer.
|
10
|
+
#
|
11
|
+
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
12
|
+
# this list of conditions and the following disclaimer in the documentation
|
13
|
+
# and/or other materials provided with the distribution.
|
14
|
+
#
|
15
|
+
# 3. Neither the name of the copyright holder nor the names of its contributors
|
16
|
+
# may be used to endorse or promote products derived from this software without
|
17
|
+
# specific prior written permission.
|
18
|
+
#
|
19
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
20
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
21
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
22
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
23
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
24
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
25
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
26
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
27
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
28
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
29
|
+
# THE POSSIBILITY OF SUCH DAMAGE.
|
30
|
+
|
31
|
+
class Instruction
|
32
|
+
attr_accessor :order
|
33
|
+
attr_reader :actions
|
34
|
+
|
35
|
+
def initialize(instruction_order: nil)
|
36
|
+
raise ArgumentError, "Instruction Order (instruction_order) required" unless instruction_order
|
37
|
+
@order = instruction_order
|
38
|
+
@actions = []
|
39
|
+
end
|
40
|
+
|
41
|
+
def add_apply_action(action)
|
42
|
+
raise ArgumentError, "Action must be a subclass of 'Action'" unless action.is_a?(Action)
|
43
|
+
@actions << action
|
44
|
+
end
|
45
|
+
|
46
|
+
def to_hash
|
47
|
+
actions_hash = []
|
48
|
+
@actions.each do |action|
|
49
|
+
actions_hash << action.to_hash
|
50
|
+
end
|
51
|
+
{:order => @order, 'apply-actions' => {:action => actions_hash}}
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
# Copyright (c) 2015, BROCADE COMMUNICATIONS SYSTEMS, INC
|
2
|
+
#
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Redistribution and use in source and binary forms, with or without modification,
|
6
|
+
# are permitted provided that the following conditions are met:
|
7
|
+
#
|
8
|
+
# 1. Redistributions of source code must retain the above copyright notice, this
|
9
|
+
# list of conditions and the following disclaimer.
|
10
|
+
#
|
11
|
+
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
12
|
+
# this list of conditions and the following disclaimer in the documentation
|
13
|
+
# and/or other materials provided with the distribution.
|
14
|
+
#
|
15
|
+
# 3. Neither the name of the copyright holder nor the names of its contributors
|
16
|
+
# may be used to endorse or promote products derived from this software without
|
17
|
+
# specific prior written permission.
|
18
|
+
#
|
19
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
20
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
21
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
22
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
23
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
24
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
25
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
26
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
27
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
28
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
29
|
+
# THE POSSIBILITY OF SUCH DAMAGE.
|
30
|
+
|
31
|
+
class Match
|
32
|
+
require 'utils/hash_with_compact'
|
33
|
+
attr_reader :eth_type, :ipv4_dst, :ipv4_src, :ipv6_src, :ipv6_dst,
|
34
|
+
:ipv6_flabel, :ipv6_ext_hdr, :ethernet_dst, :ethernet_src, :in_phy_port,
|
35
|
+
:in_port, :ip_proto, :ip_dscp, :ip_ecn, :tcp_src_port, :tcp_dst_port,
|
36
|
+
:udp_src_port, :udp_dst_port, :icmpv4_type, :icmpv4_code, :icmpv6_type,
|
37
|
+
:icmpv6_code, :arp_op_code, :arp_src_ipv4, :arp_tgt_ipv4, :arp_src_hw_addr,
|
38
|
+
:arp_tgt_hw_addr, :vlan_id, :vlan_pcp, :sctp_dst, :sctp_src, :mpls_label,
|
39
|
+
:mpls_tc, :mpls_bos, :tunnel_id, :metadata, :metadata_mask
|
40
|
+
|
41
|
+
def initialize(eth_type: nil, ipv4_destination: nil, ipv4_source: nil,
|
42
|
+
ipv6_source: nil, ipv6_destination: nil, ipv6_flabel: nil,
|
43
|
+
ipv6_ext_header: nil, ethernet_destination: nil, ethernet_source: nil,
|
44
|
+
in_port: nil, in_physical_port: nil, ip_protocol_num: nil, ip_dscp: nil,
|
45
|
+
ip_ecn: nil, tcp_source_port: nil, tcp_destination_port: nil,
|
46
|
+
udp_source_port: nil, udp_destination_port: nil, icmpv4_type: nil,
|
47
|
+
icmpv4_code: nil, icmpv6_type: nil, icmpv6_code: nil,
|
48
|
+
arp_op_code: nil, arp_source_ipv4: nil, arp_target_ipv4: nil,
|
49
|
+
arp_source_hardware_address: nil, arp_target_hardware_address: nil,
|
50
|
+
vlan_id: nil, vlan_pcp: nil, sctp_destination: nil, sctp_source: nil,
|
51
|
+
mpls_label: nil, mpls_tc: nil, mpls_bos: nil, tunnel_id: nil,
|
52
|
+
metadata: nil, metadata_mask: nil)
|
53
|
+
@eth_type = eth_type
|
54
|
+
@ipv4_dst = ipv4_destination
|
55
|
+
@ipv4_src = ipv4_source
|
56
|
+
@ipv6_dst = ipv6_destination
|
57
|
+
@ipv6_src = ipv6_source
|
58
|
+
@ipv6_flabel = ipv6_flabel
|
59
|
+
@ipv6_ext_hdr = ipv6_ext_header
|
60
|
+
@ethernet_dst = ethernet_destination
|
61
|
+
@ethernet_src = ethernet_source
|
62
|
+
@in_port = in_port
|
63
|
+
@in_phy_port = in_physical_port
|
64
|
+
@ip_proto = ip_protocol_num
|
65
|
+
@ip_dscp = ip_dscp
|
66
|
+
@ip_ecn = ip_ecn
|
67
|
+
@tcp_src_port = tcp_source_port
|
68
|
+
@tcp_dst_port = tcp_destination_port
|
69
|
+
@udp_dst_port = udp_destination_port
|
70
|
+
@udp_src_port = udp_source_port
|
71
|
+
@icmpv4_type = icmpv4_type
|
72
|
+
@icmpv4_code = icmpv4_code
|
73
|
+
@icmpv6_type = icmpv6_type
|
74
|
+
@icmpv6_code = icmpv6_code
|
75
|
+
@arp_op_code = arp_op_code
|
76
|
+
@arp_src_ipv4 = arp_source_ipv4
|
77
|
+
@arp_tgt_ipv4 = arp_target_ipv4
|
78
|
+
@arp_src_hw_addr = arp_source_hardware_address
|
79
|
+
@arp_tgt_hw_addr = arp_target_hardware_address
|
80
|
+
@vlan_id = vlan_id
|
81
|
+
@vlan_pcp = vlan_pcp
|
82
|
+
@sctp_dst = sctp_destination
|
83
|
+
@sctp_src = sctp_source
|
84
|
+
@mpls_label = mpls_label
|
85
|
+
@mpls_tc = mpls_tc
|
86
|
+
@mpls_bos = mpls_bos
|
87
|
+
@tunnel_id = tunnel_id
|
88
|
+
@metdata = metadata
|
89
|
+
@metadata_mask = metadata_mask
|
90
|
+
end
|
91
|
+
|
92
|
+
def to_hash
|
93
|
+
hash = {'ethernet-match' => {'ethernet-type' => {:type => @eth_type},
|
94
|
+
'ethernet-destination' => {:address => @ethernet_dst},
|
95
|
+
'ethernet-source' => {:address => @ethernet_src}},
|
96
|
+
'ipv4-destination' => @ipv4_dst, 'ipv4-source' => @ipv4_src,
|
97
|
+
'ipv6-destination' => @ipv6_dst, 'ipv6-source' => @ipv6_src,
|
98
|
+
'ipv6-label' => {'ipv6-flabel' => @ipv6_flabel},
|
99
|
+
'ipv6-ext-header' => {'ipv6-exthdr' => @ipv6_ext_hdr},
|
100
|
+
'in-port' => @in_port, 'in_phy_port' => @in_phy_port,
|
101
|
+
'ip-match' => {'ip-dscp' => @ip_dscp, 'ip-ecn' => @ip_ecn,
|
102
|
+
'ip-protocol' => @ip_proto}, 'tcp-destination-port' => @tcp_dst_port,
|
103
|
+
'tcp-source-port' => @tcp_src_port, 'udp-source-port' => @udp_src_port,
|
104
|
+
'udp-destination-port' => @udp_dst_port, 'icmpv4-match' =>
|
105
|
+
{'icmpv4-code' => @icmpv4_code, 'icmpv4-type' => @icmpv4_type},
|
106
|
+
'icmpv6-match' => {'icmpv6-code' => @icmpv6_code, 'icmpv6-type' => @icmpv6_type},
|
107
|
+
'arp-op' => @arp_op_code, 'arp-source-transport-address' => @arp_src_ipv4,
|
108
|
+
'arp-source-hardware-address' => {:address => @arp_src_hw_addr},
|
109
|
+
'arp-target-hardware-address' => {:address => @arp_tgt_hw_addr},
|
110
|
+
'arp-target-transport-address' => @arp_tgt_ipv4,
|
111
|
+
'vlan-match' => {'vlan-id' => {'vlan-id' => @vlan_id,
|
112
|
+
'vlan-id-present' => !@vlan_id.nil?}, 'vlan-pcp' => @vlan_pcp},
|
113
|
+
'sctp-source-port' => @sctp_src, 'sctp-destination-port' => @sctp_dst,
|
114
|
+
'protocol-match-fields' => {'mpls-label' => @mpls_label,
|
115
|
+
'mpls-tc' => @mpls_tc, 'mpls-bos' => @mpls_bos},
|
116
|
+
:tunnel => {'tunnel-id' => @tunnel_id},
|
117
|
+
:metadata => {:metadata => @metadata, 'metadata-mask' => @metadata_mask}}
|
118
|
+
hash.delete("vlan-match") if !@vlan_id
|
119
|
+
hash
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,374 @@
|
|
1
|
+
# Copyright (c) 2015, BROCADE COMMUNICATIONS SYSTEMS, INC
|
2
|
+
#
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Redistribution and use in source and binary forms, with or without modification,
|
6
|
+
# are permitted provided that the following conditions are met:
|
7
|
+
#
|
8
|
+
# 1. Redistributions of source code must retain the above copyright notice, this
|
9
|
+
# list of conditions and the following disclaimer.
|
10
|
+
#
|
11
|
+
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
12
|
+
# this list of conditions and the following disclaimer in the documentation
|
13
|
+
# and/or other materials provided with the distribution.
|
14
|
+
#
|
15
|
+
# 3. Neither the name of the copyright holder nor the names of its contributors
|
16
|
+
# may be used to endorse or promote products derived from this software without
|
17
|
+
# specific prior written permission.
|
18
|
+
#
|
19
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
20
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
21
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
22
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
23
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
24
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
25
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
26
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
27
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
28
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
29
|
+
# THE POSSIBILITY OF SUCH DAMAGE.
|
30
|
+
|
31
|
+
require 'controller/openflow_node'
|
32
|
+
class OFSwitch < OpenflowNode
|
33
|
+
require 'json'
|
34
|
+
require 'controller/controller'
|
35
|
+
require 'openflowdev/flow_entry'
|
36
|
+
require 'openflowdev/action_output'
|
37
|
+
|
38
|
+
attr_reader :name
|
39
|
+
|
40
|
+
def initialize(controller: nil, name: nil, dpid: nil)
|
41
|
+
super(controller: controller, name: name)
|
42
|
+
@dpid = dpid
|
43
|
+
end
|
44
|
+
|
45
|
+
def get_switch_info
|
46
|
+
get_uri = @controller.get_node_operational_uri(self)
|
47
|
+
response = @controller.rest_agent.get_request(get_uri)
|
48
|
+
check_response_for_success(response) do |body|
|
49
|
+
general_info = {}
|
50
|
+
if body.has_key?('node') && body['node'].is_a?(Array)
|
51
|
+
properties = body['node'][0]
|
52
|
+
if properties.has_key?('flow-node-inventory:manufacturer')
|
53
|
+
general_info['manufacturer'] = properties['flow-node-inventory:manufacturer']
|
54
|
+
end
|
55
|
+
if properties.has_key?('flow-node-inventory:serial-number')
|
56
|
+
general_info['serial-number'] = properties['flow-node-inventory:serial-number']
|
57
|
+
end
|
58
|
+
if properties.has_key?('flow-node-inventory:software')
|
59
|
+
general_info['software'] = properties['flow-node-inventory:software']
|
60
|
+
end
|
61
|
+
if properties.has_key?('flow-node-inventory:hardware')
|
62
|
+
general_info['hardware'] = properties['flow-node-inventory:hardware']
|
63
|
+
end
|
64
|
+
if properties.has_key?('flow-node-inventory:description')
|
65
|
+
general_info['description'] = properties['flow-node-inventory:description']
|
66
|
+
end
|
67
|
+
NetconfResponse.new(NetconfResponseStatus::OK, general_info)
|
68
|
+
else
|
69
|
+
NetconfResponse.new(NetconfResponseStatus::DATA_NOT_FOUND)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def get_features_info
|
75
|
+
get_uri = @controller.get_node_operational_uri(self)
|
76
|
+
response = @controller.rest_agent.get_request(get_uri)
|
77
|
+
check_response_for_success(response) do |body|
|
78
|
+
if body.has_key?('node') && body['node'].is_a?(Array) &&
|
79
|
+
body['node'][0].has_key?('flow-node-inventory:switch-features')
|
80
|
+
properties = body['node'][0]['flow-node-inventory:switch-features']
|
81
|
+
feature_info = {'max_tables' => properties['max_tables'],
|
82
|
+
'max_buffers' => properties['max_buffers']}
|
83
|
+
capabilities = []
|
84
|
+
properties['capabilities'].each do |capability|
|
85
|
+
capabilities << capability.gsub('flow-node-inventory:flow-feature-capability-', '')
|
86
|
+
end
|
87
|
+
feature_info['capabilities'] = capabilities
|
88
|
+
NetconfResponse.new(NetconfResponseStatus::OK, feature_info)
|
89
|
+
else
|
90
|
+
NetconfResponse.new(NetconfResponseStatus::DATA_NOT_FOUND)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def get_ports_list
|
96
|
+
get_uri = @controller.get_node_operational_uri(self)
|
97
|
+
response = @controller.rest_agent.get_request(get_uri)
|
98
|
+
check_response_for_success(response) do |body|
|
99
|
+
if body.has_key?('node') && body['node'].is_a?(Array) &&
|
100
|
+
body['node'][0].has_key?('node-connector')
|
101
|
+
ports = []
|
102
|
+
body['node'][0]['node-connector'].each do |port|
|
103
|
+
ports << port['flow-node-inventory:port-number']
|
104
|
+
end
|
105
|
+
NetconfResponse.new(NetconfResponseStatus::OK, ports)
|
106
|
+
else
|
107
|
+
NetconfResponse.new(NetconfResponseStatus::DATA_NOT_FOUND)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def get_ports_brief_info
|
113
|
+
get_uri = @controller.get_node_operational_uri(self)
|
114
|
+
response = @controller.rest_agent.get_request(get_uri)
|
115
|
+
check_response_for_success(response) do |body|
|
116
|
+
if body.has_key?('node') && body['node'].is_a?(Array) &&
|
117
|
+
body['node'][0].has_key?('node-connector')
|
118
|
+
ports_info = []
|
119
|
+
body['node'][0]['node-connector'].each do |port|
|
120
|
+
port_info = {'id' => port['id'],
|
121
|
+
'number' => port['flow-node-inventory:port-number'],
|
122
|
+
'name' => port['flow-node-inventory:name'],
|
123
|
+
'mac-address' => port['flow-node-inventory:hardware-address'],
|
124
|
+
'current-feature' => port['flow-node-inventory:current-feature'].upcase}
|
125
|
+
ports_info << port_info
|
126
|
+
end
|
127
|
+
NetconfResponse.new(NetconfResponseStatus::OK, ports_info)
|
128
|
+
else
|
129
|
+
NetconfResponse.new(NetconfResponseStatus::DATA_NOT_FOUND)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def get_port_detail_info(port)
|
135
|
+
get_uri = "#{@controller.get_node_operational_uri(self)}/node-connector/"\
|
136
|
+
"#{self.name}:#{port}"
|
137
|
+
response = @controller.rest_agent.get_request(get_uri)
|
138
|
+
check_response_for_success(response) do |body|
|
139
|
+
if body.has_key?('node-connector') &&
|
140
|
+
body['node-connector'].is_a?(Array) && body['node-connector'][0]
|
141
|
+
NetconfResponse.new(NetconfResponseStatus::OK, body['node-connector'][0])
|
142
|
+
else
|
143
|
+
NetconfResponse.new(NetconfResponseStatus::DATA_NOT_FOUND)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def add_modify_flow(flow)
|
149
|
+
put_uri = "#{@controller.get_node_config_uri(self)}/table/#{flow.table_id}/"\
|
150
|
+
"flow/#{flow.id}"
|
151
|
+
response = @controller.rest_agent.put_request(put_uri, flow.to_hash,
|
152
|
+
headers: {'Content-Type' => 'application/yang.data+json'})
|
153
|
+
if response.code.to_i == 200
|
154
|
+
NetconfResponse.new(NetconfResponseStatus::OK)
|
155
|
+
else
|
156
|
+
handle_error_response(response)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def get_configured_flow(table_id: nil, flow_id: nil)
|
161
|
+
raise ArgumentError, "Table ID (table_id) required" unless table_id
|
162
|
+
raise ArgumentError, "Flow ID (flow_id) required" unless flow_id
|
163
|
+
get_uri = "#{@controller.get_node_config_uri(self)}/table/#{table_id}/"\
|
164
|
+
"flow/#{flow_id}"
|
165
|
+
response = @controller.rest_agent.get_request(get_uri)
|
166
|
+
check_response_for_success(response) do |body|
|
167
|
+
NetconfResponse.new(NetconfResponseStatus::OK, body)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def delete_flow(table_id: nil, flow_id: nil)
|
172
|
+
raise ArgumentError, "Table ID (table_id) required" unless table_id
|
173
|
+
raise ArgumentError, "Flow ID (flow_id) required" unless flow_id
|
174
|
+
delete_uri = "#{@controller.get_node_config_uri(self)}/table/#{table_id}/"\
|
175
|
+
"flow/#{flow_id}"
|
176
|
+
response = @controller.rest_agent.delete_request(delete_uri)
|
177
|
+
if response.code.to_i == 200
|
178
|
+
NetconfResponse.new(NetconfResponseStatus::OK)
|
179
|
+
else
|
180
|
+
handle_error_response(response)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def get_operational_flows(table_id: nil)
|
185
|
+
raise ArgumentError, "Table ID (table_id) required" unless table_id
|
186
|
+
get_flows(table_id: table_id)
|
187
|
+
end
|
188
|
+
|
189
|
+
def get_configured_flows(table_id: nil)
|
190
|
+
raise ArgumentError, "Table ID (table_id) required" unless table_id
|
191
|
+
get_flows(table_id: table_id, is_operational: false)
|
192
|
+
end
|
193
|
+
|
194
|
+
def get_operational_flows_ovs_syntax(table_id: nil, sort: false)
|
195
|
+
raise ArgumentError, "Table ID (table_id) required" unless table_id
|
196
|
+
response = get_operational_flows(table_id: table_id)
|
197
|
+
if response.status == NetconfResponseStatus::OK
|
198
|
+
flows = []
|
199
|
+
response.body.sort! { |x,y| x['priority'] <=> y['priority']} if sort
|
200
|
+
response.body.each do |flow|
|
201
|
+
flows << odl_to_ovs_flow_syntax(flow)
|
202
|
+
end
|
203
|
+
NetconfResponse.new(NetconfResponseStatus::OK, flows)
|
204
|
+
else
|
205
|
+
response
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
def get_configured_flows_ovs_syntax(table_id: nil, sort: false)
|
210
|
+
raise ArgumentError, "Table ID (table_id) required" unless table_id
|
211
|
+
response = get_configured_flows(table_id: table_id)
|
212
|
+
if response.status == NetconfResponseStatus::OK
|
213
|
+
flows = []
|
214
|
+
response.body.sort! { |x,y| x['priority'] <=> y['priority']} if sort
|
215
|
+
response.body.each do |flow|
|
216
|
+
flows << odl_to_ovs_flow_syntax(flow)
|
217
|
+
end
|
218
|
+
NetconfResponse.new(NetconfResponseStatus::OK, flows)
|
219
|
+
else
|
220
|
+
response
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
private
|
225
|
+
|
226
|
+
def get_flows(table_id: nil, is_operational: true)
|
227
|
+
if is_operational
|
228
|
+
get_uri = "#{@controller.get_node_operational_uri(self)}/"\
|
229
|
+
"flow-node-inventory:table/#{table_id}"
|
230
|
+
else
|
231
|
+
get_uri = "#{@controller.get_node_config_uri(self)}/"\
|
232
|
+
"flow-node-inventory:table/#{table_id}"
|
233
|
+
end
|
234
|
+
|
235
|
+
response = @controller.rest_agent.get_request(get_uri)
|
236
|
+
check_response_for_success(response) do |body|
|
237
|
+
if body.has_key?('flow-node-inventory:table') &&
|
238
|
+
body['flow-node-inventory:table'].is_a?(Array) &&
|
239
|
+
body['flow-node-inventory:table'][0].has_key?('flow') &&
|
240
|
+
body['flow-node-inventory:table'][0]['flow'].is_a?(Array)
|
241
|
+
NetconfResponse.new(NetconfResponseStatus::OK,
|
242
|
+
body['flow-node-inventory:table'][0]['flow'])
|
243
|
+
else
|
244
|
+
NetconfResponse.new(NetconfResponseStatus::DATA_NOT_FOUND)
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
def odl_to_ovs_flow_syntax(odl_flow)
|
250
|
+
ovs_flow = {}
|
251
|
+
if odl_flow.has_key?('cookie')
|
252
|
+
ovs_flow['cookie'] = "0x#{odl_flow['cookie'].to_s(16)}"
|
253
|
+
end
|
254
|
+
|
255
|
+
if odl_flow.has_key?('opendaylight-flow-statistics:flow-statistics')
|
256
|
+
stats = odl_flow['opendaylight-flow-statistics:flow-statistics']
|
257
|
+
if stats.has_key?('duration')
|
258
|
+
nanoseconds = stats['duration']['nanosecond'] ||= 0
|
259
|
+
seconds = stats['duration']['second'] ||= 0
|
260
|
+
duration = ((seconds * 1000000000 + nanoseconds).to_f / 1000000000.to_f)
|
261
|
+
ovs_flow['duration'] = "#{duration}s"
|
262
|
+
end
|
263
|
+
|
264
|
+
if stats.has_key?('byte-count')
|
265
|
+
ovs_flow['n_bytes'] = stats['byte-count']
|
266
|
+
end
|
267
|
+
|
268
|
+
if stats.has_key?('packet-count')
|
269
|
+
ovs_flow['n_packets'] = stats['packet-count']
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
if odl_flow.has_key?("table_id")
|
274
|
+
ovs_flow['table'] = odl_flow['table_id']
|
275
|
+
end
|
276
|
+
|
277
|
+
if odl_flow.has_key?('idle-timeout')
|
278
|
+
ovs_flow['idle_timeout'] = odl_flow['idle-timeout'] if odl_flow['idle-timeout'] != 0
|
279
|
+
end
|
280
|
+
|
281
|
+
if odl_flow.has_key?('hard-timeout')
|
282
|
+
ovs_flow['hard_timeout'] = odl_flow['hard-timeout'] if odl_flow['hard-timeout'] != 0
|
283
|
+
end
|
284
|
+
|
285
|
+
if odl_flow.has_key?('priority')
|
286
|
+
ovs_flow['priority'] = odl_flow['priority']
|
287
|
+
end
|
288
|
+
|
289
|
+
if odl_flow.has_key?('match')
|
290
|
+
match = odl_flow['match']
|
291
|
+
if match.has_key?('in-port')
|
292
|
+
ovs_flow['in_port'] = match['in-port'].partition("#{@name}:")[2]
|
293
|
+
end
|
294
|
+
|
295
|
+
if match.has_key?('vlan-match')
|
296
|
+
vlan_match = match['vlan-match']
|
297
|
+
if vlan_match.has_key?('vlan-id') &&
|
298
|
+
vlan_match['vlan-id'].has_key?('vlan-id')
|
299
|
+
ovs_flow['dl_vlan'] = vlan_match['vlan-id']['vlan-id']
|
300
|
+
end
|
301
|
+
|
302
|
+
if vlan_match.has_key?('vlan-pcp')
|
303
|
+
ovs_flow['dl_vlan_pcp'] = vlan_match['vlan-pcp']
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
if match.has_key?('ethernet-match')
|
308
|
+
eth_match = match['ethernet-match']
|
309
|
+
if eth_match.has_key?('ethernet-type') &&
|
310
|
+
eth_match['ethernet-type'].has_key?('type')
|
311
|
+
ovs_flow['dl_type'] = "0x#{eth_match['ethernet-type']['type'].to_s(16)}"
|
312
|
+
end
|
313
|
+
|
314
|
+
if eth_match.has_key?('ethernet-source') &&
|
315
|
+
eth_match['ethernet-source'].has_key?('address')
|
316
|
+
ovs_flow['dl_src'] = eth_match['ethernet-source']['address']
|
317
|
+
end
|
318
|
+
|
319
|
+
if eth_match.has_key?('ethernet-destination') &&
|
320
|
+
eth_match['ethernet-destination'].has_key?('address')
|
321
|
+
ovs_flow['dl_dst'] = eth_match['ethernet-destination']['address']
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
if match.has_key?('ip-match')
|
326
|
+
ip_match = match['ip-match']
|
327
|
+
if ip_match.has_key?('ip-protocol')
|
328
|
+
ovs_flow['nw_proto'] = ip_match['ip-protocol']
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
if match.has_key?('tcp-source-port')
|
333
|
+
ovs_flow['tp_src'] = match['tcp-source-port']
|
334
|
+
end
|
335
|
+
|
336
|
+
if match.has_key?('ipv4-source')
|
337
|
+
ovs_flow['nw_src'] = match['ipv4-source']
|
338
|
+
end
|
339
|
+
|
340
|
+
if match.has_key?('ipv4-destination')
|
341
|
+
ovs_flow['nw_dst'] = match['ipv4-destination']
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
if odl_flow.has_key?('instructions') &&
|
346
|
+
odl_flow['instructions'].has_key?('instruction')
|
347
|
+
odl_flow['instructions']['instruction'].each do |instruction|
|
348
|
+
if instruction.has_key?('apply-actions') &&
|
349
|
+
instruction['apply-actions'].has_key?('action')
|
350
|
+
actions_list = []
|
351
|
+
instruction['apply-actions']['action'].each do |action|
|
352
|
+
if action.has_key?('output-action')
|
353
|
+
ao = ActionOutput.new
|
354
|
+
ao.update_from_object(action)
|
355
|
+
actions_list << ao
|
356
|
+
end
|
357
|
+
end
|
358
|
+
actions_list.sort! { |x, y| x.order <=> y.order}
|
359
|
+
actions = []
|
360
|
+
actions_list.each do |action|
|
361
|
+
actions << action.to_s
|
362
|
+
end
|
363
|
+
ovs_flow['actions'] = actions.join(',')
|
364
|
+
end
|
365
|
+
end
|
366
|
+
else
|
367
|
+
# ODL flows do not seem to contain the instructions info for flows that
|
368
|
+
# were set with 'drop'
|
369
|
+
ovs_flow['actions'] = 'drop'
|
370
|
+
end
|
371
|
+
|
372
|
+
ovs_flow
|
373
|
+
end
|
374
|
+
end
|
data/lib/rubybvc.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# Copyright (c) 2015, BROCADE COMMUNICATIONS SYSTEMS, INC
|
2
|
+
#
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Redistribution and use in source and binary forms, with or without modification,
|
6
|
+
# are permitted provided that the following conditions are met:
|
7
|
+
#
|
8
|
+
# 1. Redistributions of source code must retain the above copyright notice, this
|
9
|
+
# list of conditions and the following disclaimer.
|
10
|
+
#
|
11
|
+
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
12
|
+
# this list of conditions and the following disclaimer in the documentation
|
13
|
+
# and/or other materials provided with the distribution.
|
14
|
+
#
|
15
|
+
# 3. Neither the name of the copyright holder nor the names of its contributors
|
16
|
+
# may be used to endorse or promote products derived from this software without
|
17
|
+
# specific prior written permission.
|
18
|
+
#
|
19
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
20
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
21
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
22
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
23
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
24
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
25
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
26
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
27
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
28
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
29
|
+
# THE POSSIBILITY OF SUCH DAMAGE.
|
30
|
+
|
31
|
+
require 'controller/controller'
|
32
|
+
require 'controller/node'
|
33
|
+
require 'controller/netconf_node'
|
34
|
+
require 'controller/openflow_node'
|
35
|
+
|
36
|
+
require 'netconfdev/vrouter/dataplane_firewall'
|
37
|
+
require 'netconfdev/vrouter/firewall'
|
38
|
+
require 'netconfdev/vrouter/rule'
|
39
|
+
require 'netconfdev/vrouter/rules'
|
40
|
+
require 'netconfdev/vrouter/vrouter5600'
|
41
|
+
|
42
|
+
require 'openflowdev/actions/actions'
|
43
|
+
require 'openflowdev/action_output'
|
44
|
+
require 'openflowdev/flow_entry'
|
45
|
+
require 'openflowdev/instruction'
|
46
|
+
require 'openflowdev/match'
|
47
|
+
require 'openflowdev/of_switch'
|
48
|
+
|
49
|
+
require 'utils/hash_with_compact'
|
50
|
+
require 'utils/netconf_response'
|
51
|
+
require 'utils/netconf_response_status'
|
52
|
+
require 'utils/rest_agent'
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# Copyright (c) 2015, BROCADE COMMUNICATIONS SYSTEMS, INC
|
2
|
+
#
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Redistribution and use in source and binary forms, with or without modification,
|
6
|
+
# are permitted provided that the following conditions are met:
|
7
|
+
#
|
8
|
+
# 1. Redistributions of source code must retain the above copyright notice, this
|
9
|
+
# list of conditions and the following disclaimer.
|
10
|
+
#
|
11
|
+
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
12
|
+
# this list of conditions and the following disclaimer in the documentation
|
13
|
+
# and/or other materials provided with the distribution.
|
14
|
+
#
|
15
|
+
# 3. Neither the name of the copyright holder nor the names of its contributors
|
16
|
+
# may be used to endorse or promote products derived from this software without
|
17
|
+
# specific prior written permission.
|
18
|
+
#
|
19
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
20
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
21
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
22
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
23
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
24
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
25
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
26
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
27
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
28
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
29
|
+
# THE POSSIBILITY OF SUCH DAMAGE.
|
30
|
+
|
31
|
+
# borrowing from rails implementation
|
32
|
+
# https://github.com/rails/rails/blob/c0357d789b4323da64f1f9f82fa720ec9bac17cf/activesupport/lib/active_support/core_ext/hash/compact.rb#L8
|
33
|
+
class Hash
|
34
|
+
def compact
|
35
|
+
self.select { |_, value| value.is_a?(Hash) ? !value.compact_and_check_if_empty : !value.nil? }
|
36
|
+
end
|
37
|
+
|
38
|
+
def compact!
|
39
|
+
self.reject! {|_, value| value.is_a?(Hash) ? value.compact_and_check_if_empty : value.nil? }
|
40
|
+
end
|
41
|
+
|
42
|
+
def compact_and_check_if_empty
|
43
|
+
self.compact!
|
44
|
+
self.empty?
|
45
|
+
end
|
46
|
+
end
|