Statistics
| Branch: | Tag: | Revision:

one / share / hooks / OpenNebulaVLAN.rb @ 8681584e

History | View | Annotate | Download (6.03 KB)

1
#!/usr/bin/env ruby
2

    
3
# -------------------------------------------------------------------------- #
4
# Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.org)             #
5
#                                                                            #
6
# Licensed under the Apache License, Version 2.0 (the "License"); you may    #
7
# not use this file except in compliance with the License. You may obtain    #
8
# a copy of the License at                                                   #
9
#                                                                            #
10
# http://www.apache.org/licenses/LICENSE-2.0                                 #
11
#                                                                            #
12
# Unless required by applicable law or agreed to in writing, software        #
13
# distributed under the License is distributed on an "AS IS" BASIS,          #
14
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   #
15
# See the License for the specific language governing permissions and        #
16
# limitations under the License.                                             #
17
#--------------------------------------------------------------------------- #
18

    
19
require 'rexml/document'
20

    
21
CONF = {
22
    :start_vlan => 2
23
}
24

    
25
COMMANDS = {
26
  :ebtables => "sudo /sbin/ebtables",
27
  :brctl    => "/usr/sbin/brctl",
28
  :virsh    => "virsh -c qemu:///system",
29
  :xm       => "sudo /usr/sbin/xm",
30
  :ovs_vsctl => "sudo /usr/local/bin/ovs-vsctl",
31
  :lsmod    => "/bin/lsmod"
32
}
33

    
34
class Nics < Array
35
    # finds nics that match 'args'
36
    # 'args' can be a Hash, or an array
37
    #  args example:
38
    #       {:mac => "02:00:C0:A8:01:01", :bridge => "br0"}
39
    #       :mac,  "02:00:C0:A8:01:01"
40
    def get(*args)
41
        if args.length == 2
42
            dict = Hash.new
43
            dict[args[0]] = args[1]
44
        elsif args.length == 1
45
            dict = args[0]
46
        else
47
            return nil
48
        end
49

    
50
        matching = Array.new
51
        self.each do |e|
52
            e_filter = Hash.new
53
            dict.each_key{|k| e_filter[k] = e[k]}
54
            if e_filter == dict
55
                matching << e
56
            end
57
        end
58

    
59
        if matching.empty?
60
            nil
61
        else
62
            matching
63
        end
64
    end
65
end
66

    
67
class Nic < Hash
68
    def initialize(hypervisor)
69
        @hypervisor = hypervisor
70
    end
71

    
72
    def get_tap(vm)
73
        case vm.hypervisor
74
        when "kvm"
75
            get_tap_kvm(vm)
76
        when "xen"
77
            get_tap_xen(vm)
78
        end
79
    end
80

    
81
    def get_tap_kvm(vm)
82
        dumpxml = vm.vm_info[:dumpxml]
83
        dumpxml_root = REXML::Document.new(dumpxml).root
84

    
85
        xpath = "devices/interface[@type='bridge']/"
86
        xpath << "mac[@address='#{self[:mac]}']/../target"
87
        tap = dumpxml_root.elements[xpath]
88

    
89
        if tap
90
            self[:tap] = tap.attributes['dev']
91
        end
92
        self
93
    end
94

    
95
    #TODO:
96
    #def get_tap_xen(nic)
97
    #end
98
end
99

    
100

    
101
class OpenNebulaVLAN
102
    attr_reader :vm_info, :hypervisor, :nics
103

    
104
    def initialize(vm_tpl, hypervisor=nil)
105
        @vm_root = REXML::Document.new(vm_tpl).root
106
        @vm_info = Hash.new
107

    
108
        if !hypervisor
109
            hypervisor = detect_hypervisor
110
        end
111
        @hypervisor = hypervisor
112

    
113
        @deploy_id = @vm_root.elements['DEPLOY_ID'].text
114

    
115
        case hypervisor
116
        when "kvm"
117
            @vm_info[:dumpxml] = `#{COMMANDS[:virsh]} dumpxml #{@deploy_id}`
118
        when "xen"
119
            @vm_info[:domid]    =`#{CONF[:xm]} domid #{VM_NAME}`.strip
120
            @vm_info[:networks] =`#{CONF[:xm]} network-list #{vm_id}`
121
        end
122

    
123
        @nics = get_nics
124
        @filtered_nics = @nics
125
    end
126

    
127
    def filter(*filter)
128
        @filtered_nics = @nics.get(*filter)
129
        self
130
    end
131

    
132
    def unfilter
133
        @filtered_nics = @nics
134
        self
135
    end
136

    
137
    def process(&block)
138
        if @filtered_nics
139
            @filtered_nics.each do |n|
140
                yield(n)
141
            end
142
        end
143
    end
144

    
145
    def detect_hypervisor
146
        uname_a = `uname -a`
147
        lsmod   = `#{COMMANDS[:lsmod]}`
148

    
149
        if uname_a.match(/xen/i)
150
            "xen"
151
        elsif lsmod.match(/kvm/)
152
            "kvm"
153
        end
154
    end
155

    
156
    def get_nics
157
        nics = Nics.new
158
        @vm_root.elements.each("TEMPLATE/NIC") do |nic_element|
159
            nic = Nic.new(@hypervisor)
160
            nic_element.elements.each('*') do |nic_attribute|
161
                key = nic_attribute.xpath.split('/')[-1].downcase.to_sym
162
                nic[key] = nic_attribute.text
163
            end
164
            nic.get_tap(self)
165
            nics << nic
166
        end
167
        nics
168
    end
169

    
170
    def get_interfaces
171
        bridges    = Hash.new
172
        brctl_exit =`#{COMMANDS[:brctl]} show`
173
        cur_bridge = ""
174

    
175
        brctl_exit.split("\n")[1..-1].each do |l|
176
            l = l.split
177

    
178
            if l.length > 1
179
                cur_bridge = l[0]
180

    
181
                bridges[cur_bridge] = Array.new
182
                bridges[cur_bridge] << l[3]
183
            else
184
                bridges[cur_bridge] << l[0]
185
            end
186
        end
187

    
188
        bridges
189
    end
190
end
191

    
192
class OpenvSwitchVLAN < OpenNebulaVLAN
193
    def initialize(vm, hypervisor = nil)
194
        super(vm,hypervisor)
195
    end
196

    
197
    def activate
198
        process do |nic|
199
            cmd =   "#{COMMANDS[:ovs_vsctl]} set Port #{nic[:tap]} "
200
            cmd <<  "tap=#{nic[:network_id].to_i + CONF[:start_vlan]}"
201

    
202
            #TODO: execute command
203
            puts cmd
204
            #system(cmd)
205
        end
206
    end
207
end
208

    
209
class EbtablesVLAN < OpenNebulaVLAN
210
    def initialize(vm, hypervisor = nil)
211
        super(vm,hypervisor)
212
    end
213

    
214
    def ebtables(rule)
215
        system("#{CONF[:ebtables]} -A #{rule}")
216
    end
217

    
218
    def activate
219
        process do |nic|
220
            tap = nic[:tap]
221
            iface_mac = nic[:mac]
222
         
223
            mac     = iface_mac.split(':')
224
            mac[-1] = '00'
225

    
226
            net_mac = mac.join(':')
227
         
228
            in_rule="FORWARD -s ! #{net_mac}/ff:ff:ff:ff:ff:00 -o #{tap} -j DROP"
229
            out_rule="FORWARD -s ! #{iface_mac} -i #{tap} -j DROP"
230
         
231
            ebtables(in_rule)
232
            ebtables(out_rule)
233
        end
234
    end
235
end