~ubuntu-branches/ubuntu/quantal/nova/quantal-proposed

« back to all changes in this revision

Viewing changes to nova/network/linux_net.py

  • Committer: Package Import Robot
  • Author(s): Chuck Short
  • Date: 2012-08-16 14:04:11 UTC
  • mto: This revision was merged to the branch mainline in revision 84.
  • Revision ID: package-import@ubuntu.com-20120816140411-0mr4n241wmk30t9l
Tags: upstream-2012.2~f3
ImportĀ upstreamĀ versionĀ 2012.2~f3

Show diffs side-by-side

added added

removed removed

Lines of Context:
125
125
            chain = '%s-%s' % (binary_name, self.chain)
126
126
        else:
127
127
            chain = self.chain
128
 
        return '-A %s %s' % (chain, self.rule)
 
128
        # new rules should have a zero [packet: byte] count
 
129
        return '[0:0] -A %s %s' % (chain, self.rule)
129
130
 
130
131
 
131
132
class IptablesTable(object):
133
134
 
134
135
    def __init__(self):
135
136
        self.rules = []
 
137
        self.remove_rules = []
136
138
        self.chains = set()
137
139
        self.unwrapped_chains = set()
 
140
        self.remove_chains = set()
138
141
 
139
142
    def add_chain(self, name, wrap=True):
140
143
        """Adds a named chain to the table.
172
175
                     name)
173
176
            return
174
177
 
 
178
        # non-wrapped chains and rules need to be dealt with specially,
 
179
        # so we keep a list of them to be iterated over in apply()
 
180
        if not wrap:
 
181
            self.remove_chains.add(name)
175
182
        chain_set.remove(name)
 
183
        if not wrap:
 
184
            self.remove_rules += filter(lambda r: r.chain == name, self.rules)
176
185
        self.rules = filter(lambda r: r.chain != name, self.rules)
177
186
 
178
187
        if wrap:
180
189
        else:
181
190
            jump_snippet = '-j %s' % (name,)
182
191
 
 
192
        if not wrap:
 
193
            self.remove_rules += filter(lambda r: jump_snippet in r.rule,
 
194
                                        self.rules)
183
195
        self.rules = filter(lambda r: jump_snippet not in r.rule, self.rules)
184
196
 
185
197
    def add_rule(self, chain, rule, wrap=True, top=False):
216
228
        """
217
229
        try:
218
230
            self.rules.remove(IptablesRule(chain, rule, wrap, top))
 
231
            if not wrap:
 
232
                self.remove_rules.append(IptablesRule(chain, rule, wrap, top))
219
233
        except ValueError:
220
234
            LOG.warn(_('Tried to remove rule that was not there:'
221
235
                       ' %(chain)r %(rule)r %(wrap)r %(top)r'),
263
277
                     'nat': IptablesTable()}
264
278
        self.ipv6 = {'filter': IptablesTable()}
265
279
 
 
280
        self.iptables_apply_deferred = False
 
281
 
266
282
        # Add a nova-filter-top chain. It's intended to be shared
267
283
        # among the various nova components. It sits at the very top
268
284
        # of FORWARD and OUTPUT.
312
328
        self.ipv4['nat'].add_chain('float-snat')
313
329
        self.ipv4['nat'].add_rule('snat', '-j $float-snat')
314
330
 
 
331
    def defer_apply_on(self):
 
332
        self.iptables_apply_deferred = True
 
333
 
 
334
    def defer_apply_off(self):
 
335
        self.iptables_apply_deferred = False
 
336
        self._apply()
 
337
 
 
338
    def apply(self):
 
339
        if self.iptables_apply_deferred:
 
340
            return
 
341
 
 
342
        self._apply()
 
343
 
315
344
    @utils.synchronized('iptables', external=True)
316
 
    def apply(self):
 
345
    def _apply(self):
317
346
        """Apply the current in-memory set of iptables rules.
318
347
 
319
348
        This will blow away any rules left over from previous runs of the
327
356
 
328
357
        for cmd, tables in s:
329
358
            for table in tables:
330
 
                current_table, _err = self.execute('%s-save' % (cmd,),
 
359
                current_table, _err = self.execute('%s-save' % (cmd,), '-c',
331
360
                                                   '-t', '%s' % (table,),
332
361
                                                   run_as_root=True,
333
362
                                                   attempts=5)
334
363
                current_lines = current_table.split('\n')
335
364
                new_filter = self._modify_rules(current_lines,
336
365
                                                tables[table])
337
 
                self.execute('%s-restore' % (cmd,), run_as_root=True,
 
366
                self.execute('%s-restore' % (cmd,), '-c', run_as_root=True,
338
367
                             process_input='\n'.join(new_filter),
339
368
                             attempts=5)
340
369
        LOG.debug(_("IPTablesManager.apply completed with success"))
342
371
    def _modify_rules(self, current_lines, table, binary=None):
343
372
        unwrapped_chains = table.unwrapped_chains
344
373
        chains = table.chains
 
374
        remove_chains = table.remove_chains
345
375
        rules = table.rules
 
376
        remove_rules = table.remove_rules
346
377
 
347
378
        # Remove any trace of our rules
348
379
        new_filter = filter(lambda line: binary_name not in line,
359
390
                    break
360
391
 
361
392
        our_rules = []
 
393
        bot_rules = []
362
394
        for rule in rules:
363
395
            rule_str = str(rule)
364
396
            if rule.top:
365
397
                # rule.top == True means we want this rule to be at the top.
366
398
                # Further down, we weed out duplicates from the bottom of the
367
399
                # list, so here we remove the dupes ahead of time.
368
 
                new_filter = filter(lambda s: s.strip() != rule_str.strip(),
369
 
                                    new_filter)
370
 
            our_rules += [rule_str]
 
400
 
 
401
                # We don't want to remove an entry if it has non-zero
 
402
                # [packet:byte] counts and replace it with [0:0], so let's
 
403
                # go look for a duplicate, and over-ride our table rule if
 
404
                # found.
 
405
 
 
406
                # ignore [packet:byte] counts at beginning of line
 
407
                if rule_str.startswith('['):
 
408
                    rule_str = rule_str.split(']', 1)[1]
 
409
                dup_filter = filter(lambda s: rule_str.strip() in s.strip(),
 
410
                                    new_filter)
 
411
 
 
412
                new_filter = filter(lambda s:
 
413
                                    rule_str.strip() not in s.strip(),
 
414
                                    new_filter)
 
415
                # if no duplicates, use original rule
 
416
                if dup_filter:
 
417
                    # grab the last entry, if there is one
 
418
                    dup = dup_filter[-1]
 
419
                    rule_str = str(dup)
 
420
                else:
 
421
                    rule_str = str(rule)
 
422
                rule_str.strip()
 
423
 
 
424
                our_rules += [rule_str]
 
425
            else:
 
426
                bot_rules += [rule_str]
 
427
 
 
428
        our_rules += bot_rules
371
429
 
372
430
        new_filter[rules_index:rules_index] = our_rules
373
431
 
380
438
        seen_lines = set()
381
439
 
382
440
        def _weed_out_duplicates(line):
 
441
            # ignore [packet:byte] counts at beginning of lines
 
442
            if line.startswith('['):
 
443
                line = line.split(']', 1)[1]
383
444
            line = line.strip()
384
445
            if line in seen_lines:
385
446
                return False
387
448
                seen_lines.add(line)
388
449
                return True
389
450
 
 
451
        def _weed_out_removes(line):
 
452
            # We need to find exact matches here
 
453
            if line.startswith(':'):
 
454
                # it's a chain, for example, ":nova-billing - [0:0]"
 
455
                # strip off everything except the chain name
 
456
                line = line.split(':')[1]
 
457
                line = line.split('- [')[0]
 
458
                line = line.strip()
 
459
                for chain in remove_chains:
 
460
                    if chain == line:
 
461
                        remove_chains.remove(chain)
 
462
                        return False
 
463
            elif line.startswith('['):
 
464
                # it's a rule
 
465
                # ignore [packet:byte] counts at beginning of lines
 
466
                line = line.split(']', 1)[1]
 
467
                line = line.strip()
 
468
                for rule in remove_rules:
 
469
                    # ignore [packet:byte] counts at beginning of rules
 
470
                    rule_str = str(rule)
 
471
                    rule_str = rule_str.split(' ', 1)[1]
 
472
                    rule_str = rule_str.strip()
 
473
                    if rule_str == line:
 
474
                        remove_rules.remove(rule)
 
475
                        return False
 
476
 
 
477
            # Leave it alone
 
478
            return True
 
479
 
390
480
        # We filter duplicates, letting the *last* occurrence take
391
 
        # precedence.
 
481
        # precendence.  We also filter out anything in the "remove"
 
482
        # lists.
392
483
        new_filter.reverse()
393
484
        new_filter = filter(_weed_out_duplicates, new_filter)
 
485
        new_filter = filter(_weed_out_removes, new_filter)
394
486
        new_filter.reverse()
 
487
 
 
488
        # flush lists, just in case we didn't find something
 
489
        remove_chains.clear()
 
490
        for rule in remove_rules:
 
491
            remove_rules.remove(rule)
 
492
 
395
493
        return new_filter
396
494
 
397
495
 
628
726
                                               host=host)
629
727
 
630
728
    if data:
631
 
        #set of instance ids
632
 
        instance_set = set([datum['instance_id'] for datum in data])
 
729
        instance_set = set([datum['instance_uuid'] for datum in data])
633
730
        default_gw_vif = {}
634
 
        for instance_id in instance_set:
635
 
            vifs = db.virtual_interface_get_by_instance(context, instance_id)
 
731
        for instance_uuid in instance_set:
 
732
            vifs = db.virtual_interface_get_by_instance(context,
 
733
                                                        instance_uuid)
636
734
            if vifs:
637
735
                #offer a default gateway to the first virtual interface
638
 
                default_gw_vif[instance_id] = vifs[0]['id']
 
736
                default_gw_vif[instance_uuid] = vifs[0]['id']
639
737
 
640
738
        for datum in data:
641
 
            if instance_id in default_gw_vif:
 
739
            if instance_uuid in default_gw_vif:
642
740
                # we don't want default gateway for this fixed ip
643
 
                if default_gw_vif[instance_id] != datum['vif_id']:
 
741
                if default_gw_vif[instance_uuid] != datum['vif_id']:
644
742
                    hosts.append(_host_dhcp_opts(datum))
645
743
    return '\n'.join(hosts)
646
744
 
724
822
           '--pid-file=%s' % _dhcp_file(dev, 'pid'),
725
823
           '--listen-address=%s' % network_ref['dhcp_server'],
726
824
           '--except-interface=lo',
727
 
           '--dhcp-range=%s,static,%ss' % (network_ref['dhcp_start'],
728
 
                                           FLAGS.dhcp_lease_time),
 
825
           '--dhcp-range=set:\'%s\',%s,static,%ss' %
 
826
                         (network_ref['label'],
 
827
                          network_ref['dhcp_start'],
 
828
                          FLAGS.dhcp_lease_time),
729
829
           '--dhcp-lease-max=%s' % len(netaddr.IPNetwork(network_ref['cidr'])),
730
830
           '--dhcp-hostsfile=%s' % _dhcp_file(dev, 'conf'),
731
831
           '--dhcp-script=%s' % FLAGS.dhcpbridge,
987
1087
            LOG.debug(_('Starting VLAN inteface %s'), interface)
988
1088
            _execute('ip', 'link', 'add', 'link', bridge_interface,
989
1089
                     'name', interface, 'type', 'vlan',
990
 
                     'id', vlan_num, run_as_root=True)
 
1090
                     'id', vlan_num, run_as_root=True,
 
1091
                     check_exit_code=[0, 2, 254])
991
1092
            # (danwent) the bridge will inherit this address, so we want to
992
1093
            # make sure it is the value set from the NetworkManager
993
1094
            if mac_address:
994
1095
                _execute('ip', 'link', 'set', interface, 'address',
995
 
                         mac_address, run_as_root=True)
996
 
            _execute('ip', 'link', 'set', interface, 'up', run_as_root=True)
 
1096
                         mac_address, run_as_root=True,
 
1097
                         check_exit_code=[0, 2, 254])
 
1098
            _execute('ip', 'link', 'set', interface, 'up', run_as_root=True,
 
1099
                     check_exit_code=[0, 2, 254])
997
1100
            if FLAGS.network_device_mtu:
998
1101
                _execute('ip', 'link', 'set', interface, 'mtu',
999
 
                         FLAGS.network_device_mtu, run_as_root=True)
 
1102
                         FLAGS.network_device_mtu, run_as_root=True,
 
1103
                         check_exit_code=[0, 2, 254])
1000
1104
        return interface
1001
1105
 
1002
1106
    @classmethod
1165
1269
            utils.execute('brctl', 'setfd', bridge, str(0), run_as_root=True)
1166
1270
            utils.execute('brctl', 'stp', bridge, 'off', run_as_root=True)
1167
1271
            utils.execute('ip', 'link', 'set', bridge, 'address', mac_address,
1168
 
                          run_as_root=True)
1169
 
            utils.execute('ip', 'link', 'set', bridge, 'up', run_as_root=True)
 
1272
                          run_as_root=True, check_exit_code=[0, 2, 254])
 
1273
            utils.execute('ip', 'link', 'set', bridge, 'up', run_as_root=True,
 
1274
                          check_exit_code=[0, 2, 254])
1170
1275
            LOG.debug(_("Done starting bridge %s"), bridge)
1171
1276
 
1172
1277
            full_ip = '%s/%s' % (network['dhcp_server'],
1173
1278
                                 network['cidr'].rpartition('/')[2])
1174
1279
            utils.execute('ip', 'address', 'add', full_ip, 'dev', bridge,
1175
 
                          run_as_root=True)
 
1280
                          run_as_root=True, check_exit_code=[0, 2, 254])
1176
1281
 
1177
1282
        return dev
1178
1283
 
1183
1288
            return None
1184
1289
        else:
1185
1290
            try:
1186
 
                utils.execute('ip', 'link', 'delete', dev, run_as_root=True)
 
1291
                utils.execute('ip', 'link', 'delete', dev, run_as_root=True,
 
1292
                              check_exit_code=[0, 2, 254])
1187
1293
            except exception.ProcessExecutionError:
1188
1294
                LOG.error(_("Failed unplugging gateway interface '%s'"), dev)
1189
1295
                raise
1196
1302
            try:
1197
1303
                # First, try with 'ip'
1198
1304
                utils.execute('ip', 'tuntap', 'add', dev, 'mode', 'tap',
1199
 
                              run_as_root=True)
 
1305
                              run_as_root=True, check_exit_code=[0, 2, 254])
1200
1306
            except exception.ProcessExecutionError:
1201
1307
                # Second option: tunctl
1202
1308
                utils.execute('tunctl', '-b', '-t', dev, run_as_root=True)
1203
1309
            if mac_address:
1204
1310
                utils.execute('ip', 'link', 'set', dev, 'address', mac_address,
1205
 
                              run_as_root=True)
1206
 
            utils.execute('ip', 'link', 'set', dev, 'up', run_as_root=True)
 
1311
                              run_as_root=True, check_exit_code=[0, 2, 254])
 
1312
            utils.execute('ip', 'link', 'set', dev, 'up', run_as_root=True,
 
1313
                          check_exit_code=[0, 2, 254])
1207
1314
 
1208
1315
    def get_dev(self, network):
1209
1316
        dev = self.GATEWAY_INTERFACE_PREFIX + str(network['uuid'][0:11])