summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian Haley <bhaley@redhat.com>2017-03-24 17:41:17 -0400
committerIhar Hrachyshka <ihrachys@redhat.com>2017-06-14 16:11:50 +0000
commit8275f13dd73e836be0b9055b107aa75488552df9 (patch)
tree4e7ec2e4636c6169f3ec9c157c185ca51c0fe616
parent633b452e28b7a95ced1917257ca0e200cbffa4ba (diff)
Verify metering label exists before applying rule
If the metering-agent receives a label rule before it has added the label, it will fail to update the iptables rules as there are no existing chains. When the action is "create", check if there is an existing label, and create one and the corresponding iptables chains, before trying to add the rule. Closes-Bug: #1617248 Change-Id: Ia0ec1361188cca53023667d249c2b1e10bc22089 (cherry picked from commit 29652e0aff760bf445fd7ffef8eeede61a6710e3)
Notes
Notes (review): Code-Review+2: Brian Haley <haleyb.dev@gmail.com> Code-Review+2: Kevin Benton <kevin@benton.pub> Workflow+1: Kevin Benton <kevin@benton.pub> Verified+2: Jenkins Submitted-by: Jenkins Submitted-at: Thu, 15 Jun 2017 03:27:03 +0000 Reviewed-on: https://review.openstack.org/474270 Project: openstack/neutron Branch: refs/heads/stable/ocata
-rw-r--r--neutron/services/metering/drivers/iptables/iptables_driver.py31
-rw-r--r--neutron/tests/unit/services/metering/drivers/test_iptables.py44
2 files changed, 67 insertions, 8 deletions
diff --git a/neutron/services/metering/drivers/iptables/iptables_driver.py b/neutron/services/metering/drivers/iptables/iptables_driver.py
index 860fc73..dee7bc2 100644
--- a/neutron/services/metering/drivers/iptables/iptables_driver.py
+++ b/neutron/services/metering/drivers/iptables/iptables_driver.py
@@ -233,24 +233,22 @@ class IptablesMeteringDriver(abstract_driver.MeteringAbstractDriver):
233 233
234 label_chain = iptables_manager.get_chain_name( 234 label_chain = iptables_manager.get_chain_name(
235 WRAP_NAME + LABEL + label_id, wrap=False) 235 WRAP_NAME + LABEL + label_id, wrap=False)
236 im.ipv4['filter'].add_chain(label_chain, wrap=False)
237 236
238 rules_chain = iptables_manager.get_chain_name( 237 rules_chain = iptables_manager.get_chain_name(
239 WRAP_NAME + RULE + label_id, wrap=False) 238 WRAP_NAME + RULE + label_id, wrap=False)
240 im.ipv4['filter'].add_chain(rules_chain, wrap=False)
241 im.ipv4['filter'].add_rule(
242 TOP_CHAIN, '-j ' + rules_chain, wrap=False)
243 239
244 im.ipv4['filter'].add_rule( 240 exists = rm.metering_labels.get(label_id)
245 label_chain, '', wrap=False) 241 if not exists:
242 self._create_metering_label_chain(rm,
243 label_chain,
244 rules_chain)
245 rm.metering_labels[label_id] = label
246 246
247 rules = label.get('rules') 247 rules = label.get('rules')
248 if rules: 248 if rules:
249 self._process_metering_label_rules( 249 self._process_metering_label_rules(
250 rules, label_chain, rules_chain, ext_dev, im) 250 rules, label_chain, rules_chain, ext_dev, im)
251 251
252 rm.metering_labels[label_id] = label
253
254 def _process_associate_metering_label(self, router): 252 def _process_associate_metering_label(self, router):
255 self._update_router(router) 253 self._update_router(router)
256 rm = self.routers.get(router['id']) 254 rm = self.routers.get(router['id'])
@@ -319,9 +317,18 @@ class IptablesMeteringDriver(abstract_driver.MeteringAbstractDriver):
319 def _remove_metering_label_rule(self, router): 317 def _remove_metering_label_rule(self, router):
320 self._process_metering_rule_action(router, 'delete') 318 self._process_metering_rule_action(router, 'delete')
321 319
320 def _create_metering_label_chain(self, rm, label_chain, rules_chain):
321 rm.iptables_manager.ipv4['filter'].add_chain(label_chain, wrap=False)
322 rm.iptables_manager.ipv4['filter'].add_chain(rules_chain, wrap=False)
323 rm.iptables_manager.ipv4['filter'].add_rule(
324 TOP_CHAIN, '-j ' + rules_chain, wrap=False)
325 rm.iptables_manager.ipv4['filter'].add_rule(
326 label_chain, '', wrap=False)
327
322 def _process_metering_rule_action_based_on_ns( 328 def _process_metering_rule_action_based_on_ns(
323 self, router, action, ext_dev, im): 329 self, router, action, ext_dev, im):
324 '''Process metering rule actions based specific namespaces.''' 330 '''Process metering rule actions based specific namespaces.'''
331 rm = self.routers.get(router['id'])
325 with IptablesManagerTransaction(im): 332 with IptablesManagerTransaction(im):
326 labels = router.get(constants.METERING_LABEL_KEY, []) 333 labels = router.get(constants.METERING_LABEL_KEY, [])
327 for label in labels: 334 for label in labels:
@@ -331,6 +338,14 @@ class IptablesMeteringDriver(abstract_driver.MeteringAbstractDriver):
331 338
332 rules_chain = iptables_manager.get_chain_name( 339 rules_chain = iptables_manager.get_chain_name(
333 WRAP_NAME + RULE + label_id, wrap=False) 340 WRAP_NAME + RULE + label_id, wrap=False)
341
342 exists = rm.metering_labels.get(label_id)
343 if action == 'create' and not exists:
344 self._create_metering_label_chain(rm,
345 label_chain,
346 rules_chain)
347 rm.metering_labels[label_id] = label
348
334 rule = label.get('rule') 349 rule = label.get('rule')
335 if rule: 350 if rule:
336 if action == 'create': 351 if action == 'create':
diff --git a/neutron/tests/unit/services/metering/drivers/test_iptables.py b/neutron/tests/unit/services/metering/drivers/test_iptables.py
index 3044a92..3ea0eb4 100644
--- a/neutron/tests/unit/services/metering/drivers/test_iptables.py
+++ b/neutron/tests/unit/services/metering/drivers/test_iptables.py
@@ -104,6 +104,22 @@ TEST_ROUTERS_WITH_ONE_RULE = [
104 'tenant_id': '6c5f5d2a1fa2441e88e35422926f48e8'}, 104 'tenant_id': '6c5f5d2a1fa2441e88e35422926f48e8'},
105] 105]
106 106
107TEST_ROUTERS_WITH_NEW_LABEL = [
108 {'_metering_labels': [
109 {'id': 'e27fe2df-376e-4ac7-ae13-92f050a21f84',
110 'rule': {
111 'direction': 'ingress',
112 'excluded': False,
113 'id': '7f1a261f-2489-4ed1-870c-a62754501379',
114 'metering_label_id': 'e27fe2df-376e-4ac7-ae13-92f050a21f84',
115 'remote_ip_prefix': '50.0.0.0/24'}}],
116 'admin_state_up': True,
117 'gw_port_id': '6d411f48-ecc7-45e0-9ece-3b5bdb54fcee',
118 'id': '473ec392-1711-44e3-b008-3251ccfc5099',
119 'name': 'router1',
120 'status': 'ACTIVE',
121 'tenant_id': '6c5f5d2a1fa2441e88e35422926f48e8'}]
122
107 123
108class IptablesDriverTestCase(base.BaseTestCase): 124class IptablesDriverTestCase(base.BaseTestCase):
109 def setUp(self): 125 def setUp(self):
@@ -440,7 +456,35 @@ class IptablesDriverTestCase(base.BaseTestCase):
440 '-d 40.0.0.0/24 -o qg-7d411f48-ec' 456 '-d 40.0.0.0/24 -o qg-7d411f48-ec'
441 ' -j neutron-meter-l-eeef45da-c60', 457 ' -j neutron-meter-l-eeef45da-c60',
442 wrap=False, top=False), 458 wrap=False, top=False),
459 ]
460 self.v4filter_inst.assert_has_calls(calls)
461
462 def test_add_metering_label_rule_without_label(self):
463 new_routers_rules = TEST_ROUTERS_WITH_NEW_LABEL
464 # clear all the metering labels
465 for r in TEST_ROUTERS:
466 rm = iptables_driver.RouterWithMetering(self.metering.conf, r)
467 rm.metering_labels = {}
443 468
469 self.metering.update_routers(None, TEST_ROUTERS)
470 self.metering.add_metering_label_rule(None, new_routers_rules)
471 calls = [
472 mock.call.add_chain('neutron-meter-l-e27fe2df-376',
473 wrap=False),
474 mock.call.add_chain('neutron-meter-r-e27fe2df-376',
475 wrap=False),
476 mock.call.add_rule('neutron-meter-FORWARD',
477 '-j neutron-meter-r-e27fe2df-376',
478 wrap=False),
479 mock.call.add_rule('neutron-meter-l-e27fe2df-376',
480 '',
481 wrap=False),
482 mock.call.add_rule('neutron-meter-r-e27fe2df-376',
483 '-s 50.0.0.0/24 '
484 '-i qg-6d411f48-ec '
485 '-j neutron-meter-l-e27fe2df-376',
486 top=False,
487 wrap=False)
444 ] 488 ]
445 self.v4filter_inst.assert_has_calls(calls) 489 self.v4filter_inst.assert_has_calls(calls)
446 490