From ce02c2d101f4f169693504a61969b34d171d5032 Mon Sep 17 00:00:00 2001 From: Ramanjaneya Date: Sat, 5 Dec 2015 16:02:00 +0530 Subject: [PATCH] Implement Firewall conversions This patch implements API's for * Saving firewall rules in common classifier model. * Retrieving firewall rule from the common classfier db. Change-Id: I64ff4ce875fd909d57375d1c601dc61e86c79f40 Co-Authored-By: Mohankumar --- neutron_classifier/common/constants.py | 4 ++ neutron_classifier/db/api.py | 75 +++++++++++++++++++-- neutron_classifier/tests/test_db_api.py | 86 +++++++++++++++++++------ 3 files changed, 141 insertions(+), 24 deletions(-) diff --git a/neutron_classifier/common/constants.py b/neutron_classifier/common/constants.py index ac50f05..6e536a0 100644 --- a/neutron_classifier/common/constants.py +++ b/neutron_classifier/common/constants.py @@ -1,4 +1,5 @@ # Copyright (c) 2015 Mirantis, Inc. +# Copyright (c) 2015 Huawei Technologies India Pvt Ltd. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain @@ -24,5 +25,8 @@ DIRECTIONS = ['INGRESS', 'EGRESS', 'BIDIRECTIONAL'] ETHERTYPE_IPV4 = 0x0800 ETHERTYPE_IPV6 = 0x86DD +IP_VERSION_4 = 4 +IP_VERSION_6 = 6 + SECURITYGROUP_ETHERTYPE_IPV4 = 'IPv4' SECURITYGROUP_ETHERTYPE_IPV6 = 'IPv6' diff --git a/neutron_classifier/db/api.py b/neutron_classifier/db/api.py index 2afd866..6467b62 100644 --- a/neutron_classifier/db/api.py +++ b/neutron_classifier/db/api.py @@ -1,4 +1,5 @@ # Copyright (c) 2015 Mirantis, Inc. +# Copyright (c) 2015 Huawei Technologies India Pvt Ltd. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain @@ -88,10 +89,6 @@ def convert_security_group_rule_to_classifier(context, sgr, group): create_classifier_chain(group, classifiers) -def convert_firewall_rule_to_classifier(context, firewall_rule): - pass - - def convert_classifier_group_to_security_group(context, classifier_group_id): sg_dict = {} cg = get_classifier_group(context, classifier_group_id) @@ -121,5 +118,71 @@ def convert_classifier_group_to_security_group(context, classifier_group_id): return sg_dict -def convert_classifier_to_firewall_policy(context, chain_id): - pass +def convert_firewall_policy_to_classifier(context, firewall): + cgroup = models.ClassifierGroup() + cgroup.service = 'neutron-fwaas' + for rule in firewall['firewall_rules']: + convert_firewall_rule_to_classifier(context, rule, cgroup) + context.session.add(cgroup) + context.session.commit() + return cgroup + + +def convert_firewall_rule_to_classifier(context, fw_rule, group): + # ip_version + cl1 = models.EthernetClassifier() + cl1.ethertype = fw_rule['ip_version'] + + # protocol + if cl1.ethertype == constants.IP_VERSION_6: + cl2 = models.Ipv6Classifier() + cl2.next_header = fw_rule['protocol'] + else: + cl2 = models.Ipv4Classifier() + cl2.protocol = fw_rule['protocol'] + + # Source and destination ip + cl3 = models.IpClassifier() + cl3.source_ip_prefix = fw_rule['source_ip_address'] + cl3.destination_ip_prefix = fw_rule['destination_ip_address'] + + # Ports + cl4 = models.TransportClassifier( + source_port_range_min=fw_rule['source_port_range_min'], + source_port_range_max=fw_rule['source_port_range_max'], + destination_port_range_min=fw_rule['destination_port_range_min'], + destination_port_range_max=fw_rule['destination_port_range_max']) + + classifiers = [cl1, cl2, cl3, cl4] + create_classifier_chain(group, classifiers) + + +def convert_classifier_to_firewall(context, classifier_group_id): + fw_rule = {} + cg = get_classifier_group(context, classifier_group_id) + for classifier in [link.classifier for link in cg.classifier_chain]: + classifier_type = type(classifier) + if classifier_type is models.EthernetClassifier: + fw_rule['ip_version'] = classifier.ethertype + continue + if classifier_type is models.Ipv4Classifier: + fw_rule['protocol'] = classifier.protocol + continue + if classifier_type is models.Ipv6Classifier: + fw_rule['protocol'] = classifier.next_header + continue + if classifier_type is models.TransportClassifier: + fw_rule['source_port_range_min'] = classifier.source_port_range_min + fw_rule['source_port_range_max'] = classifier.source_port_range_max + fw_rule['destination_port_range_min'] = \ + classifier.destination_port_range_min + fw_rule['destination_port_range_max'] = \ + classifier.destination_port_range_max + continue + if classifier_type is models.IpClassifier: + fw_rule['source_ip_address'] = classifier.source_ip_prefix + fw_rule['destination_ip_address'] = \ + classifier.destination_ip_prefix + continue + + return fw_rule diff --git a/neutron_classifier/tests/test_db_api.py b/neutron_classifier/tests/test_db_api.py index 80aa22f..1ca0c06 100644 --- a/neutron_classifier/tests/test_db_api.py +++ b/neutron_classifier/tests/test_db_api.py @@ -1,4 +1,5 @@ # Copyright (c) 2015 Mirantis, Inc. +# Copyright (c) 2015 Huawei Technologies India Pvt Ltd. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain @@ -33,6 +34,34 @@ FAKE_SG_V6 = {'name': 'fake security group', 'tenant_id': uuidutils.generate_uuid(), 'description': 'this is fake', 'security_group_rules': [FAKE_SG_RULE_V6]} +FAKE_FW_RULE_V4 = {'ip_version': 4, 'protocol': 'udp', + 'source_port_range_min': 1, 'source_port_range_max': 80, + 'destination_port_range_min': 1, + 'destination_port_range_max': 80, + 'source_ip_address': '20.1.1.1/24', + 'destination_ip_address': '30.1.1.1/24', + 'position': 1, 'action': 'ALLOW', 'enabled': True, + 'tenant_id': 'fake_tenant', } + +FAKE_FW_RULE_V6 = {'ip_version': 6, 'protocol': 'udp', + 'source_port_range_min': 1, 'source_port_range_max': 80, + 'destination_port_range_min': 1, + 'destination_port_range_max': 80, + 'source_ip_address': 'fddf:cb3b:bc4::/48', + 'destination_ip_address': 'fddf:cb3b:b33f::/48', + 'position': 1, 'action': 'ALLOW', 'enabled': True, + 'tenant_id': 'fake_tenant', } + +FAKE_FW_V4 = {'name': 'fake firewall policy', + 'tenant_id': uuidutils.generate_uuid(), + 'description': 'this is fake', + 'firewall_rules': [FAKE_FW_RULE_V4]} + +FAKE_FW_V6 = {'name': 'fake firewall policy', + 'tenant_id': uuidutils.generate_uuid(), + 'description': 'this is fake', + 'firewall_rules': [FAKE_FW_RULE_V6]} + class ClassifierTestContext(object): "Classifier Database Context." @@ -87,22 +116,6 @@ class DbApiTestCase(base.BaseTestCase): def test_convert_security_group_rule_v6_to_classifier(self): self._test_convert_security_group_rule_to_classifier(FAKE_SG_RULE_V6) - def test_convert_firewall_rule_to_classifier(self): - firewall_rule = {'protocol': 'foo', - 'ip_version': 6, - 'source_ip_address': 'fddf:cb3b:bc4::/48', - 'destination_ip_address': 'fddf:cb3b:b33f::/48', - 'source_port': 80, - 'destination_port': 80, - 'position': 1, - 'action': 'ALLOW', - 'enabled': True - } - api.convert_firewall_rule_to_classifier(self.context, firewall_rule) - - def test_convert_firewall_policy_to_classifier_chain(self): - pass - def test_convert_security_group_to_classifier_chain(self): result = api.convert_security_group_to_classifier(self.context, FAKE_SG_V6) @@ -116,5 +129,42 @@ class DbApiTestCase(base.BaseTestCase): result['tenant_id'] = FAKE_SG_RULE_V6['tenant_id'] self.assertEqual(FAKE_SG_RULE_V6, result) - def test_convert_classifier_chain_to_firewall_policy(self): - pass + # Firewall testcases + def _test_convert_firewall_rule_to_classifier(self, fw_rule): + cg = self._create_classifier_group('neutron-fwaas') + api.convert_firewall_rule_to_classifier(self.context, fw_rule, cg) + + # Save to the database + self.context.session.add(cg) + self.context.session.commit() + + # Refresh the classifier group from the DB + cg = api.get_classifier_group(self.context, cg.id) + self.assertGreater(len(cg.classifier_chain), 0) + + def test_convert_firewall_rule_v4_to_classifier(self): + self._test_convert_firewall_rule_to_classifier(FAKE_FW_RULE_V4) + + def test_convert_firewall_rule_v6_to_classifier(self): + self._test_convert_firewall_rule_to_classifier(FAKE_FW_RULE_V6) + + def test_convert_firewall_policy_v4_to_classifier_chain(self): + result = api.convert_firewall_policy_to_classifier(self.context, + FAKE_FW_V4) + self.assertIsNotNone(result) + + def test_convert_firewall_policy_v6_to_classifier_chain(self): + result = api.convert_firewall_policy_to_classifier(self.context, + FAKE_FW_V6) + self.assertIsNotNone(result) + + def test_convert_classifier_chain_to_firewall(self): + classifier_id = api.convert_firewall_policy_to_classifier( + self.context, FAKE_FW_V6).id + result = api.convert_classifier_to_firewall(self.context, + classifier_id) + result['tenant_id'] = FAKE_FW_RULE_V6['tenant_id'] + result['position'] = FAKE_FW_RULE_V6['position'] + result['action'] = FAKE_FW_RULE_V6['action'] + result['enabled'] = FAKE_FW_RULE_V6['enabled'] + self.assertEqual(FAKE_FW_RULE_V6, result)