You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by GitBox <gi...@apache.org> on 2022/04/29 11:19:32 UTC

[GitHub] [cloudstack] shwstppr opened a new pull request, #6338: test: add, refactor ipv6 network, vpc tests

shwstppr opened a new pull request, #6338:
URL: https://github.com/apache/cloudstack/pull/6338

   ### Description
   TBA
   
   ### Types of changes
   
   - [ ] Breaking change (fix or feature that would cause existing functionality to change)
   - [ ] New feature (non-breaking change which adds functionality)
   - [ ] Bug fix (non-breaking change which fixes an issue)
   - [ ] Enhancement (improves an existing feature and functionality)
   - [x] Cleanup (Code refactoring and cleanup, that may add test cases)
   
   ### Feature/Enhancement Scale or Bug Severity
   
   #### Feature/Enhancement Scale
   
   - [ ] Major
   - [ ] Minor
   
   #### Bug Severity
   
   - [ ] BLOCKER
   - [ ] Critical
   - [ ] Major
   - [ ] Minor
   - [ ] Trivial
   
   
   ### Screenshots (if appropriate):
   
   
   ### How Has This Been Tested?
   <!-- Please describe in detail how you tested your changes. -->
   <!-- Include details of your testing environment, and the tests you ran to -->
   <!-- see how your change affects other areas of the code, etc. -->
   
   
   <!-- Please read the [CONTRIBUTING](https://github.com/apache/cloudstack/blob/main/CONTRIBUTING.md) document -->
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1129661579

   Packaging result: :heavy_multiplication_x: el7 :heavy_check_mark: el8 :heavy_multiplication_x: debian :heavy_check_mark: suse15. SL-JID 3424


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] sonarcloud[bot] commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
sonarcloud[bot] commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1158751108

   Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=apache_cloudstack&pullRequest=6338)
   
   [![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG)  
   [![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY)  
   [![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT)  
   [![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL)
   
   [![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=coverage&view=list) No Coverage information  
   [![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=new_duplicated_lines_density&view=list)
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1180538896

   @rohityadavcloud a Jenkins job has been kicked to build packages. It will be bundled with  KVM, XenServer and VMware SystemVM templates. I'll keep you posted as I make progress.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] rohityadavcloud commented on a diff in pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
rohityadavcloud commented on code in PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#discussion_r918633628


##########
test/integration/smoke/test_vpc_ipv6.py:
##########
@@ -0,0 +1,901 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file

Review Comment:
   Thanks @shwstppr 



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1162686259

   @shwstppr a Jenkins job has been kicked to build packages. I'll keep you posted as I make progress.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1160321658

   @acs-robot a Jenkins job has been kicked to build UI QA env. I'll keep you posted as I make progress.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] acs-robot commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
acs-robot commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1118183375

   Found UI changes, kicking a new UI QA build
   @blueorangutan ui


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] rohityadavcloud commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
rohityadavcloud commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1133803322

   @blueorangutan package 


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1129930016

   Packaging result: :heavy_check_mark: el7 :heavy_multiplication_x: el8 :heavy_check_mark: debian :heavy_check_mark: suse15. SL-JID 3436


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1153264496

   <b>Trillian test result (tid-4321)</b>
   Environment: kvm-centos7 (x2), Advanced Networking with Mgmt server 7
   Total time taken: 39364 seconds
   Marvin logs: https://github.com/blueorangutan/acs-prs/releases/download/trillian/pr6338-t4321-kvm-centos7.zip
   Smoke tests completed. 98 look OK, 1 have errors
   Only failed tests results shown below:
   
   
   Test | Result | Time (s) | Test File
   --- | --- | --- | ---
   test_03_create_redundant_VPC_1tier_2VMs_2IPs_2PF_ACL_reboot_routers | `Failure` | 456.33 | test_vpc_redundant.py
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] sonarcloud[bot] commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
sonarcloud[bot] commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1122031659

   SonarCloud Quality Gate failed.&nbsp; &nbsp; [![Quality Gate failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/failed-16px.png 'Quality Gate failed')](https://sonarcloud.io/dashboard?id=apache_cloudstack&pullRequest=6338)
   
   [![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG)  
   [![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY)  
   [![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT)  
   [![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL) [3 Code Smells](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL)
   
   [![66.7%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/60-16px.png '66.7%')](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=new_coverage&view=list) [66.7% Coverage](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=new_coverage&view=list)  
   [![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=new_duplicated_lines_density&view=list)
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] sonarcloud[bot] commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
sonarcloud[bot] commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1122026384

   SonarCloud Quality Gate failed.&nbsp; &nbsp; [![Quality Gate failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/failed-16px.png 'Quality Gate failed')](https://sonarcloud.io/dashboard?id=apache_cloudstack&pullRequest=6338)
   
   [![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG)  
   [![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY)  
   [![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT)  
   [![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL) [1 Code Smell](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL)
   
   [![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/0-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=new_coverage&view=list) [0.0% Coverage](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=new_coverage&view=list)  
   [![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=new_duplicated_lines_density&view=list)
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] sonarcloud[bot] commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
sonarcloud[bot] commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1122130035

   SonarCloud Quality Gate failed.&nbsp; &nbsp; [![Quality Gate failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/failed-16px.png 'Quality Gate failed')](https://sonarcloud.io/dashboard?id=apache_cloudstack&pullRequest=6338)
   
   [![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG)  
   [![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY)  
   [![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT)  
   [![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL)
   
   [![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/0-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=new_coverage&view=list) [0.0% Coverage](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=new_coverage&view=list)  
   [![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=new_duplicated_lines_density&view=list)
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1122130386

   Packaging result: :heavy_check_mark: el7 :heavy_check_mark: el8 :heavy_check_mark: debian :heavy_check_mark: suse15. SL-JID 3378


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1118298778

   @weizhouapache a Trillian-Jenkins test job (centos7 mgmt + kvm-centos7) has been kicked to run smoke tests


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] weizhouapache commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
weizhouapache commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1118298108

   @blueorangutan test


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1158713370

   UI build: :heavy_check_mark:
   Live QA URL: http://qa.cloudstack.cloud:8080/client/pr/6338 (SL-JID-1759)


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] DaanHoogland commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
DaanHoogland commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1134309493

   I think it makes sense to only leave miniml tests in the smoke dir, @shwstppr . The rest we´d only want to run on subject specific PRs and releases.
   €0.02


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1152109179

   @shwstppr a Jenkins job has been kicked to build packages. It will be bundled with  KVM, XenServer and VMware SystemVM templates. I'll keep you posted as I make progress.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1152117879

   UI build: :heavy_check_mark:
   Live QA URL: http://qa.cloudstack.cloud:8080/client/pr/6338 (SL-JID-1710)


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1152121331

   UI build: :heavy_check_mark:
   Live QA URL: http://qa.cloudstack.cloud:8080/client/pr/6338 (SL-JID-1711)


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1152159384

   Packaging result: :heavy_check_mark: el7 :heavy_check_mark: el8 :heavy_check_mark: debian :heavy_check_mark: suse15. SL-JID 3559


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] sonarcloud[bot] commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
sonarcloud[bot] commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1121076741

   SonarCloud Quality Gate failed.&nbsp; &nbsp; [![Quality Gate failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/failed-16px.png 'Quality Gate failed')](https://sonarcloud.io/dashboard?id=apache_cloudstack&pullRequest=6338)
   
   [![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG)  
   [![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY)  
   [![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT)  
   [![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL)
   
   [![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/0-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=new_coverage&view=list) [0.0% Coverage](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=new_coverage&view=list)  
   [![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=new_duplicated_lines_density&view=list)
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] weizhouapache closed pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
weizhouapache closed pull request #6338: test: add, refactor ipv6 network, vpc tests
URL: https://github.com/apache/cloudstack/pull/6338


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1118257157

   Packaging result: :heavy_check_mark: el7 :heavy_check_mark: el8 :heavy_check_mark: debian :heavy_check_mark: suse15. SL-JID 3354


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] rohityadavcloud commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
rohityadavcloud commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1181287649

   @blueorangutan package


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1162753312

   Packaging result: :heavy_multiplication_x: el7 :heavy_check_mark: el8 :heavy_check_mark: debian :heavy_multiplication_x: suse15. SL-JID 3623


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1113190411

   @acs-robot a Jenkins job has been kicked to build UI QA env. I'll keep you posted as I make progress.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] rohityadavcloud commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
rohityadavcloud commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1180537992

   @blueorangutan package


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1181320661

   Packaging result: :heavy_check_mark: el7 :heavy_multiplication_x: el8 :heavy_check_mark: debian :heavy_check_mark: suse15. SL-JID 3749


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1178659417

   Packaging result: :heavy_check_mark: el7 :heavy_check_mark: el8 :heavy_check_mark: debian :heavy_check_mark: suse15. SL-JID 3730


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] shwstppr commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
shwstppr commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1122089681

   @blueorangutan package


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1153095407

   @shwstppr a Trillian-Jenkins test job (centos7 mgmt + kvm-centos7) has been kicked to run smoke tests


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] acs-robot commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
acs-robot commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1158701399

   Found UI changes, kicking a new UI QA build
   @blueorangutan ui


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1118234156

   @weizhouapache a Jenkins job has been kicked to build packages. It will be bundled with  KVM, XenServer and VMware SystemVM templates. I'll keep you posted as I make progress.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] shwstppr commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
shwstppr commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1134302875

   @blueorangutan test


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1165169135

   <b>Trillian test result (tid-4366)</b>
   Environment: kvm-centos7 (x2), Advanced Networking with Mgmt server 7
   Total time taken: 34148 seconds
   Marvin logs: https://github.com/blueorangutan/acs-prs/releases/download/trillian/pr6338-t4366-kvm-centos7.zip
   Smoke tests completed. 96 look OK, 4 have errors
   Only failed tests results shown below:
   
   
   Test | Result | Time (s) | Test File
   --- | --- | --- | ---
   test_DeployVmAntiAffinityGroup | `Error` | 35.41 | test_affinity_groups.py
   test_DeployVmAntiAffinityGroup_in_project | `Error` | 74.40 | test_affinity_groups_projects.py
   test_01_invalid_upgrade_kubernetes_cluster | `Failure` | 52.77 | test_kubernetes_clusters.py
   test_02_upgrade_kubernetes_cluster | `Failure` | 0.06 | test_kubernetes_clusters.py
   test_03_deploy_and_scale_kubernetes_cluster | `Failure` | 0.05 | test_kubernetes_clusters.py
   test_04_autoscale_kubernetes_cluster | `Failure` | 0.03 | test_kubernetes_clusters.py
   test_05_basic_lifecycle_kubernetes_cluster | `Failure` | 0.04 | test_kubernetes_clusters.py
   test_06_delete_kubernetes_cluster | `Failure` | 0.05 | test_kubernetes_clusters.py
   test_07_deploy_kubernetes_ha_cluster | `Failure` | 0.07 | test_kubernetes_clusters.py
   test_08_upgrade_kubernetes_ha_cluster | `Failure` | 0.04 | test_kubernetes_clusters.py
   test_09_delete_kubernetes_ha_cluster | `Failure` | 0.03 | test_kubernetes_clusters.py
   ContextSuite context=TestKubernetesCluster>:teardown | `Error` | 54.94 | test_kubernetes_clusters.py
   test_hostha_enable_ha_when_host_in_maintenance | `Error` | 307.32 | test_hostha_kvm.py
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1162767044

   Packaging result: :heavy_multiplication_x: el7 :heavy_multiplication_x: el8 :heavy_multiplication_x: debian :heavy_multiplication_x: suse15. SL-JID 5


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1114552502

   @shwstppr a Jenkins job has been kicked to build packages. It will be bundled with  KVM, XenServer and VMware SystemVM templates. I'll keep you posted as I make progress.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1118185934

   UI build: :heavy_check_mark:
   Live QA URL: http://qa.cloudstack.cloud:8080/client/pr/6338 (SL-JID-1525)


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1120785769

   @acs-robot a Jenkins job has been kicked to build UI QA env. I'll keep you posted as I make progress.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] shwstppr commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
shwstppr commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1122259995

   @blueorangutan test


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1122996681

   <b>Trillian test result (tid-4157)</b>
   Environment: kvm-centos7 (x2), Advanced Networking with Mgmt server 7
   Total time taken: 40816 seconds
   Marvin logs: https://github.com/blueorangutan/acs-prs/releases/download/trillian/pr6338-t4157-kvm-centos7.zip
   Smoke tests completed. 98 look OK, 0 have errors
   Only failed tests results shown below:
   
   
   Test | Result | Time (s) | Test File
   --- | --- | --- | ---
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1152108324

   @acs-robot a Jenkins job has been kicked to build UI QA env. I'll keep you posted as I make progress.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] shwstppr commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
shwstppr commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1164721073

   
   @blueorangutan test


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] rohityadavcloud commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
rohityadavcloud commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1180623198

   @blueorangutan test matrix


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] shwstppr commented on a diff in pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
shwstppr commented on code in PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#discussion_r918530759


##########
test/integration/smoke/test_vpc_ipv6.py:
##########
@@ -0,0 +1,901 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file

Review Comment:
   @rohityadavcloud There are four test files added,
   `smoke/test_network_ipv6.py` - contains 1 test-case
   `smoke/test_vpc_ipv6.py` - contains 1 test-case
   `component/test_network_ipv6.py` - contains 4 test-cases for upgrade network, redundant VR, etc
   `component/test_vpc_ipv6.py` - contains 4 test-cases for upgrade VPC, redundant VR, etc
   
   Each component test file may take over 30mins to execute 



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] rohityadavcloud commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
rohityadavcloud commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1161503967

   cc @shwstppr pl check that the base branch changed to 4.17 causes some extra changes/commits (rebase/merge 4.17 branch on your PR branch). I think since you're adding tests, the 4.17 branch can benefit from this which has the ipv6 feature.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1161611748

   Packaging result: :heavy_multiplication_x: el7 :heavy_check_mark: el8 :heavy_multiplication_x: debian :heavy_multiplication_x: suse15. SL-JID 3611


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1161671592

   @shwstppr a Jenkins job has been kicked to build packages. It will be bundled with  KVM, XenServer and VMware SystemVM templates. I'll keep you posted as I make progress.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] acs-robot commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
acs-robot commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1160320721

   Found UI changes, kicking a new UI QA build
   @blueorangutan ui


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1113194630

   UI build: :heavy_check_mark:
   Live QA URL: http://qa.cloudstack.cloud:8080/client/pr/6338 (SL-JID-1498)


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1120144686

   @acs-robot a Jenkins job has been kicked to build UI QA env. I'll keep you posted as I make progress.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1120145421

   UI build: :heavy_check_mark:
   Live QA URL: http://qa.cloudstack.cloud:8080/client/pr/6338 (SL-JID-1529)


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1122262980

   @shwstppr a Trillian-Jenkins test job (centos7 mgmt + kvm-centos7) has been kicked to run smoke tests


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1122090495

   @shwstppr a Jenkins job has been kicked to build packages. It will be bundled with  KVM, XenServer and VMware SystemVM templates. I'll keep you posted as I make progress.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] sonarcloud[bot] commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
sonarcloud[bot] commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1129791578

   SonarCloud Quality Gate failed.&nbsp; &nbsp; [![Quality Gate failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/failed-16px.png 'Quality Gate failed')](https://sonarcloud.io/dashboard?id=apache_cloudstack&pullRequest=6338)
   
   [![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG)  
   [![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY)  
   [![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT)  
   [![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL)
   
   [![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/0-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=new_coverage&view=list) [0.0% Coverage](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=new_coverage&view=list)  
   [![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=new_duplicated_lines_density&view=list)
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] DaanHoogland commented on a diff in pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
DaanHoogland commented on code in PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#discussion_r916673320


##########
test/integration/smoke/test_vpc_ipv6.py:
##########
@@ -0,0 +1,901 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT test for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        try:
+            super(TestIpv6Vpc, cls).tearDownClass()
+        finally:
+            if cls.test_ipv6_guestprefix != None:
+                cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+                cmd.id = cls.test_ipv6_guestprefix.id
+                cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        finally:
+            super(TestIpv6Vpc, self).tearDown()
+        return
+
+    def getRandomIpv6Cidr(self):
+        prefix_length = choice(PREFIX_OPTIONS)
+        random_suffix = getrandbits(40) << (128-prefix_length)
+        base_address = ULA_BASE.network_address + random_suffix
+        return str(IPv6Network((base_address, prefix_length)))
+
+    def createTinyServiceOffering(self):
+        self.service_offering = ServiceOffering.create(
+            self.apiclient,
+            self.services["service_offerings"]["big"],
+        )
+        self.cleanup.append(self.service_offering)
+
+    def createVpcOfferingInternal(self, is_redundant, is_ipv6):
+        off_service = self.services["vpc_offering"]
+        if is_redundant:
+            off_service["serviceCapabilityList"] = {
+                "SourceNat": {
+                    "RedundantRouter": 'true'
+                },
+            }
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        vpc_offering = VpcOffering.create(
+            self.apiclient,
+            off_service
+        )
+        self.cleanup.append(vpc_offering)
+        vpc_offering.update(self.apiclient, state='Enabled')
+        return vpc_offering
+
+    def createIpv4VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, False)
+
+    def createIpv6VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, True)
+
+    def createIpv6VpcOfferingForUpdate(self, is_redundant=False):
+        self.vpc_offering_update = self.createVpcOfferingInternal(is_redundant, True)
+
+    def createNetworkTierOfferingInternal(self, is_ipv6, remove_lb=True):
+        off_service = self.services["nw_offering_isolated_vpc"]
+        if not remove_lb: # Remove Lb service
+            if "serviceProviderList" in off_service and "Lb" in off_service["serviceProviderList"].keys():
+                providers = off_service["serviceProviderList"]
+                providers.pop("Lb")
+                off_service["serviceProviderList"] = providers
+            if "supportedservices" in off_service and "Lb" in off_service["supportedservices"]:
+                supportedServices = off_service["supportedservices"].split(",")
+                supportedServices.remove("Lb")
+                off_service["supportedservices"] = ",".join(supportedServices)
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        network_offering = NetworkOffering.create(
+            self.apiclient,
+            off_service,
+            conservemode=False
+        )
+        network_offering.update(self.apiclient, state='Enabled')
+        self.cleanup.append(network_offering)

Review Comment:
   if `update()` throws an exception ...
   ```suggestion
           self.cleanup.append(network_offering)
           network_offering.update(self.apiclient, state='Enabled')
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1178848274

   UI build: :heavy_check_mark:
   Live QA URL: http://qa.cloudstack.cloud:8080/client/pr/6338 (SL-JID-1924)


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1181287803

   @rohityadavcloud a Jenkins job has been kicked to build packages. It will be bundled with  KVM, XenServer and VMware SystemVM templates. I'll keep you posted as I make progress.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] rohityadavcloud commented on a diff in pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
rohityadavcloud commented on code in PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#discussion_r918527534


##########
test/integration/smoke/test_vpc_ipv6.py:
##########
@@ -0,0 +1,901 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file

Review Comment:
   @shwstppr does it make sense to move the test_network_ipv6 to smoke/ ? How much time do they take? (asking as the test_vpc_ipv6 is in smoke but the other one is in component/ ) 



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] shwstppr commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
shwstppr commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1152108827

   Refactored tests. Now only basic test for IPv6 isolated nw and VPC is there in /smoke. /component has all the added Marvin tests.
   
   @blueorangutan package


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1134305750

   @shwstppr a Trillian-Jenkins test job (centos7 mgmt + kvm-centos7) has been kicked to run smoke tests


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] shwstppr commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
shwstppr commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1161553593

   @blueorangutan package


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] shwstppr commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
shwstppr commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1162685982

   @blueorangutan package


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1161712754

   Packaging result: :heavy_multiplication_x: el7 :heavy_check_mark: el8 :heavy_multiplication_x: debian :heavy_multiplication_x: suse15. SL-JID 3614


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1120790956

   UI build: :heavy_check_mark:
   Live QA URL: http://qa.cloudstack.cloud:8080/client/pr/6338 (SL-JID-1533)


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] sonarcloud[bot] commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
sonarcloud[bot] commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1129908132

   SonarCloud Quality Gate failed.&nbsp; &nbsp; [![Quality Gate failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/failed-16px.png 'Quality Gate failed')](https://sonarcloud.io/dashboard?id=apache_cloudstack&pullRequest=6338)
   
   [![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG)  
   [![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY)  
   [![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT)  
   [![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL)
   
   [![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/0-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=new_coverage&view=list) [0.0% Coverage](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=new_coverage&view=list)  
   [![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=new_duplicated_lines_density&view=list)
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] shwstppr commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
shwstppr commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1165217008

   @blueorangutan test


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] sonarcloud[bot] commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
sonarcloud[bot] commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1152164005

   Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=apache_cloudstack&pullRequest=6338)
   
   [![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG)  
   [![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY)  
   [![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT)  
   [![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL)
   
   [![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=coverage&view=list) No Coverage information  
   [![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=new_duplicated_lines_density&view=list)
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] shwstppr commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
shwstppr commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1152954675

   @blueorangutan test


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] acs-robot commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
acs-robot commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1152109605

   Found UI changes, kicking a new UI QA build
   @blueorangutan ui


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] DaanHoogland commented on a diff in pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
DaanHoogland commented on code in PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#discussion_r896555594


##########
test/integration/component/test_network_ipv6.py:
##########
@@ -0,0 +1,937 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT tests for IPv6 Network"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix,
+                                  listIpv6FirewallRules,
+                                  createIpv6FirewallRule,
+                                  deleteIpv6FirewallRule)
+from marvin.lib.utils import (cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               list_hosts,
+                               get_test_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+FIREWALL_TABLE = "ip6_firewall"
+FIREWALL_CHAINS = {
+    "Ingress": "fw_chain_ingress",
+    "Egress": "fw_chain_egress"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+SLEEP_BEFORE_VR_CHANGES = 45
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+class TestIpv6Network(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Network, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Network')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Network, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)

Review Comment:
   if the parent throws an exception, the next part of the cleanup will not be executed. Is that intentional?
   or should it be like,
   ```suggestion
           try:
               super(TestIpv6Network, cls).tearDownClass()
           finally:
               if cls.test_ipv6_guestprefix != None:
                   cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
                   cmd.id = cls.test_ipv6_guestprefix.id
                   cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
   ```



##########
test/integration/component/test_network_ipv6.py:
##########
@@ -0,0 +1,937 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT tests for IPv6 Network"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix,
+                                  listIpv6FirewallRules,
+                                  createIpv6FirewallRule,
+                                  deleteIpv6FirewallRule)
+from marvin.lib.utils import (cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               list_hosts,
+                               get_test_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+FIREWALL_TABLE = "ip6_firewall"
+FIREWALL_CHAINS = {
+    "Ingress": "fw_chain_ingress",
+    "Egress": "fw_chain_egress"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+SLEEP_BEFORE_VR_CHANGES = 45
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+class TestIpv6Network(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Network, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Network')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Network, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)
+            #Clean up, terminate the created templates
+            cleanup_resources(self.apiclient, reversed(self.cleanup))
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return

Review Comment:
   in this case it might be
   ```suggestion
           try:
               if self.thread and self.thread.is_alive():
                   self.thread.join(5*60)
               #Clean up, terminate the created templates
           except Exception as e:
               raise Exception("Warning: Exception during cleanup : %s" % e)
           finally:
               super(TestIpv6Network, self).tearDown()
           return
   ```
   this structural part of this sugestion *is* a question, but it seems that any resources created during the test would not get cleaned if the `thread.join` leads to an exception.
   the call to super is really very convenient, and if you use vms very much needed.



##########
test/integration/component/test_vpc_ipv6.py:
##########
@@ -0,0 +1,1036 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT tests for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Vpc, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)
+            #Clean up, terminate the created templates
+            # cleanup_resources(self.apiclient, reversed(self.cleanup))
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    def getRandomIpv6Cidr(self):
+        prefix_length = choice(PREFIX_OPTIONS)
+        random_suffix = getrandbits(40) << (128-prefix_length)
+        base_address = ULA_BASE.network_address + random_suffix
+        return str(IPv6Network((base_address, prefix_length)))
+
+    def createTinyServiceOffering(self):
+        self.service_offering = ServiceOffering.create(
+            self.apiclient,
+            self.services["service_offerings"]["big"],
+        )
+        self.cleanup.append(self.service_offering)
+
+    def createVpcOfferingInternal(self, is_redundant, is_ipv6):
+        off_service = self.services["vpc_offering"]
+        if is_redundant:
+            off_service["serviceCapabilityList"] = {
+                "SourceNat": {
+                    "RedundantRouter": 'true'
+                },
+            }
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        vpc_offering = VpcOffering.create(
+            self.apiclient,
+            off_service
+        )

Review Comment:
   ```suggestion
           vpc_offering = VpcOffering.create(
               self.apiclient,
               off_service
           )
           self.cleanup.append(vpc_offering)
   ```



##########
test/integration/component/test_vpc_ipv6.py:
##########
@@ -0,0 +1,1036 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT tests for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Vpc, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)
+            #Clean up, terminate the created templates
+            # cleanup_resources(self.apiclient, reversed(self.cleanup))

Review Comment:
   ```suggestion
               super(TestIpv6Vpc, self).tearDown()
   ```
   I see no reason why this would be a comment.



##########
test/integration/component/test_vpc_ipv6.py:
##########
@@ -0,0 +1,1036 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT tests for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Vpc, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)
+            #Clean up, terminate the created templates
+            # cleanup_resources(self.apiclient, reversed(self.cleanup))
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    def getRandomIpv6Cidr(self):
+        prefix_length = choice(PREFIX_OPTIONS)
+        random_suffix = getrandbits(40) << (128-prefix_length)
+        base_address = ULA_BASE.network_address + random_suffix
+        return str(IPv6Network((base_address, prefix_length)))
+
+    def createTinyServiceOffering(self):
+        self.service_offering = ServiceOffering.create(
+            self.apiclient,
+            self.services["service_offerings"]["big"],
+        )
+        self.cleanup.append(self.service_offering)
+
+    def createVpcOfferingInternal(self, is_redundant, is_ipv6):
+        off_service = self.services["vpc_offering"]
+        if is_redundant:
+            off_service["serviceCapabilityList"] = {
+                "SourceNat": {
+                    "RedundantRouter": 'true'
+                },
+            }
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        vpc_offering = VpcOffering.create(
+            self.apiclient,
+            off_service
+        )
+        vpc_offering.update(self.apiclient, state='Enabled')
+        return vpc_offering
+
+    def createIpv4VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, False)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOfferingForUpdate(self, is_redundant=False):
+        self.vpc_offering_update = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering_update)
+
+    def createNetworkTierOfferingInternal(self, is_ipv6, remove_lb=True):
+        off_service = self.services["nw_offering_isolated_vpc"]
+        if not remove_lb: # Remove Lb service
+            if "serviceProviderList" in off_service and "Lb" in off_service["serviceProviderList"].keys():
+                providers = off_service["serviceProviderList"]
+                providers.pop("Lb")
+                off_service["serviceProviderList"] = providers
+            if "supportedservices" in off_service and "Lb" in off_service["supportedservices"]:
+                supportedServices = off_service["supportedservices"].split(",")
+                supportedServices.remove("Lb")
+                off_service["supportedservices"] = ",".join(supportedServices)
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        network_offering = NetworkOffering.create(
+            self.apiclient,
+            off_service,
+            conservemode=False
+        )
+        network_offering.update(self.apiclient, state='Enabled')
+        return network_offering
+
+    def createIpv4NetworkTierOffering(self):
+        self.network_offering = self.createNetworkTierOfferingInternal(False)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOffering(self, remove_lb=True):
+        self.network_offering = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOfferingForUpdate(self):
+        self.network_offering_update = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering_update)
+
+    def deployAllowAllVpcInternal(self, cidr):
+        service = self.services["vpc"]
+        service["cidr"] = cidr
+        vpc = VPC.create(
+            self.apiclient,
+            self.services["vpc"],
+            vpcofferingid=self.vpc_offering.id,
+            zoneid=self.zone.id,
+            account=self.account.name,
+            domainid=self.account.domainid
+        )
+        acl = NetworkACLList.create(
+            self.apiclient,
+            services={},
+            name="allowall",
+            description="allowall",
+            vpcid=vpc.id
+        )
+        rule ={
+            "protocol": "all",
+            "traffictype": "ingress",
+        }
+        NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=acl.id
+        )
+        rule["traffictype"] = "egress"
+        NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=acl.id
+        )
+        self.vpcAllowAllAclDetailsMap[vpc.id] = acl.id
+        return vpc
+
+    def deployVpc(self):
+        self.vpc = self.deployAllowAllVpcInternal(VPC_DATA["cidr"])
+        self.cleanup.append(self.vpc)
+
+    def deployNetworkTierInternal(self, network_offering_id, vpc_id, tier_gateway, tier_netmask, acl_id=None, tier_name=None):
+        if not acl_id and vpc_id in self.vpcAllowAllAclDetailsMap:
+            acl_id = self.vpcAllowAllAclDetailsMap[vpc_id]
+        service = self.services["ntwk"]
+        if tier_name:
+            service["name"] = tier_name
+            service["displaytext"] = "vpc-%s" % tier_name
+        network = Network.create(
+            self.apiclient,
+            service,
+            self.account.name,
+            self.account.domainid,
+            networkofferingid=network_offering_id,
+            vpcid=vpc_id,
+            zoneid=self.zone.id,
+            gateway=tier_gateway,
+            netmask=tier_netmask,
+            aclid=acl_id
+        )
+        return network
+
+    def deployNetworkTier(self):
+        self.network = self.deployNetworkTierInternal(
+            self.network_offering.id,
+            self.vpc.id,
+            VPC_DATA["tier1_gateway"],
+            VPC_DATA["tier_netmask"]
+        )
+        self.cleanup.append(self.network)
+
+    def deployNetworkTierVmInternal(self, network):
+        if self.template == FAILED:
+            assert False, "get_test_template() failed to return template"
+        self.services["virtual_machine"]["zoneid"] = self.zone.id
+        virtual_machine = VirtualMachine.create(
+            self.apiclient,
+            self.services["virtual_machine"],
+            templateid=self.template.id,
+            accountid=self.account.name,
+            domainid=self.account.domainid,
+            networkids=network,
+            serviceofferingid=self.service_offering.id
+        )

Review Comment:
   ```suggestion
           virtual_machine = VirtualMachine.create(
               self.apiclient,
               self.services["virtual_machine"],
               templateid=self.template.id,
               accountid=self.account.name,
               domainid=self.account.domainid,
               networkids=network,
               serviceofferingid=self.service_offering.id
           )
           self.cleanup.append(virtual_machine)
   ```



##########
test/integration/component/test_vpc_ipv6.py:
##########
@@ -0,0 +1,1036 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT tests for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Vpc, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)

Review Comment:
   same as above
   ```suggestion
           try:
               super(TestIpv6Vpc, cls).tearDownClass()
           finally:
               if cls.test_ipv6_guestprefix != None:
                   cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
                   cmd.id = cls.test_ipv6_guestprefix.id
                   cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
   ```
   ?!?!?



##########
test/integration/component/test_vpc_ipv6.py:
##########
@@ -0,0 +1,1036 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT tests for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Vpc, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)
+            #Clean up, terminate the created templates
+            # cleanup_resources(self.apiclient, reversed(self.cleanup))
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    def getRandomIpv6Cidr(self):
+        prefix_length = choice(PREFIX_OPTIONS)
+        random_suffix = getrandbits(40) << (128-prefix_length)
+        base_address = ULA_BASE.network_address + random_suffix
+        return str(IPv6Network((base_address, prefix_length)))
+
+    def createTinyServiceOffering(self):
+        self.service_offering = ServiceOffering.create(
+            self.apiclient,
+            self.services["service_offerings"]["big"],
+        )
+        self.cleanup.append(self.service_offering)
+
+    def createVpcOfferingInternal(self, is_redundant, is_ipv6):
+        off_service = self.services["vpc_offering"]
+        if is_redundant:
+            off_service["serviceCapabilityList"] = {
+                "SourceNat": {
+                    "RedundantRouter": 'true'
+                },
+            }
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        vpc_offering = VpcOffering.create(
+            self.apiclient,
+            off_service
+        )
+        vpc_offering.update(self.apiclient, state='Enabled')
+        return vpc_offering
+
+    def createIpv4VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, False)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOfferingForUpdate(self, is_redundant=False):
+        self.vpc_offering_update = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering_update)
+
+    def createNetworkTierOfferingInternal(self, is_ipv6, remove_lb=True):
+        off_service = self.services["nw_offering_isolated_vpc"]
+        if not remove_lb: # Remove Lb service
+            if "serviceProviderList" in off_service and "Lb" in off_service["serviceProviderList"].keys():
+                providers = off_service["serviceProviderList"]
+                providers.pop("Lb")
+                off_service["serviceProviderList"] = providers
+            if "supportedservices" in off_service and "Lb" in off_service["supportedservices"]:
+                supportedServices = off_service["supportedservices"].split(",")
+                supportedServices.remove("Lb")
+                off_service["supportedservices"] = ",".join(supportedServices)
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        network_offering = NetworkOffering.create(
+            self.apiclient,
+            off_service,
+            conservemode=False
+        )
+        network_offering.update(self.apiclient, state='Enabled')
+        return network_offering
+
+    def createIpv4NetworkTierOffering(self):
+        self.network_offering = self.createNetworkTierOfferingInternal(False)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOffering(self, remove_lb=True):
+        self.network_offering = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOfferingForUpdate(self):
+        self.network_offering_update = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering_update)
+
+    def deployAllowAllVpcInternal(self, cidr):
+        service = self.services["vpc"]
+        service["cidr"] = cidr
+        vpc = VPC.create(
+            self.apiclient,
+            self.services["vpc"],
+            vpcofferingid=self.vpc_offering.id,
+            zoneid=self.zone.id,
+            account=self.account.name,
+            domainid=self.account.domainid
+        )

Review Comment:
   ```suggestion
           vpc = VPC.create(
               self.apiclient,
               self.services["vpc"],
               vpcofferingid=self.vpc_offering.id,
               zoneid=self.zone.id,
               account=self.account.name,
               domainid=self.account.domainid
           )
           self.cleanup.append(vpc)
   ```



##########
test/integration/smoke/test_ipv6_infra.py:
##########
@@ -0,0 +1,488 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT tests for IPv6 infra operations"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (cleanup_resources)
+from marvin.lib.base import (Configurations,
+                             NetworkOffering,
+                             VpcOffering,
+                             PublicIpRange)
+from marvin.lib.common import (get_zone)
+from marvin.cloudstackException import CloudstackAPIException
+
+from nose.plugins.attrib import attr
+import logging
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+
+class TestCreateIpv6NetworkVpcOffering(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestCreateIpv6NetworkVpcOffering, cls).getClsTestClient()
+        cls.apiclient = testClient.getApiClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.initial_ipv6_offering_enabled = Configurations.list(
+            cls.apiclient,
+            name=ipv6_offering_config_name)[0].value
+        cls._cleanup = []
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestCreateIpv6NetworkVpcOffering, cls).tearDownClass()
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            #Clean up, terminate the created templates
+            cleanup_resources(self.apiclient, self.cleanup)
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return

Review Comment:
   ```suggestion
           try:
   
           except Exception as e:
               raise Exception("Warning: Exception during cleanup : %s" % e)
           finally:
               super(TestCreateIpv6NetworkVpcOffering, self).tearDown()
           return
   ```



##########
server/src/test/java/com/cloud/network/Ipv6ServiceImplTest.java:
##########
@@ -0,0 +1,781 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.network;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.UUID;
+
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.MBeanRegistrationException;
+import javax.management.MalformedObjectNameException;
+import javax.management.NotCompliantMBeanException;
+
+import org.apache.cloudstack.api.command.user.ipv6.CreateIpv6FirewallRuleCmd;
+import org.apache.cloudstack.api.command.user.ipv6.UpdateIpv6FirewallRuleCmd;
+import org.apache.cloudstack.api.response.Ipv6RouteResponse;
+import org.apache.cloudstack.api.response.VpcResponse;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
+import org.apache.commons.collections.CollectionUtils;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mockito.stubbing.Answer;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+import com.cloud.api.ApiDBUtils;
+import com.cloud.dc.DataCenter;
+import com.cloud.dc.DataCenterGuestIpv6PrefixVO;
+import com.cloud.dc.DataCenterVO;
+import com.cloud.dc.Vlan;
+import com.cloud.dc.VlanVO;
+import com.cloud.dc.dao.DataCenterGuestIpv6PrefixDao;
+import com.cloud.dc.dao.VlanDao;
+import com.cloud.event.ActionEventUtils;
+import com.cloud.event.UsageEventUtils;
+import com.cloud.exception.InsufficientAddressCapacityException;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.NetworkRuleConflictException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.network.dao.FirewallRulesDao;
+import com.cloud.network.dao.IPAddressDao;
+import com.cloud.network.dao.IPAddressVO;
+import com.cloud.network.dao.Ipv6GuestPrefixSubnetNetworkMapDao;
+import com.cloud.network.dao.NetworkDetailsDao;
+import com.cloud.network.dao.NetworkVO;
+import com.cloud.network.firewall.FirewallService;
+import com.cloud.network.guru.PublicNetworkGuru;
+import com.cloud.network.rules.FirewallManager;
+import com.cloud.network.rules.FirewallRule;
+import com.cloud.network.rules.FirewallRuleVO;
+import com.cloud.network.vpc.Vpc;
+import com.cloud.offerings.dao.NetworkOfferingDao;
+import com.cloud.user.Account;
+import com.cloud.user.AccountManager;
+import com.cloud.user.AccountVO;
+import com.cloud.user.User;
+import com.cloud.user.UserVO;
+import com.cloud.utils.Pair;
+import com.cloud.utils.db.DB;
+import com.cloud.utils.db.TransactionLegacy;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.vm.DomainRouterVO;
+import com.cloud.vm.Nic;
+import com.cloud.vm.NicProfile;
+import com.cloud.vm.NicVO;
+import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.dao.DomainRouterDao;
+import com.cloud.vm.dao.NicDao;
+import com.googlecode.ipv6.IPv6Network;
+import com.googlecode.ipv6.IPv6NetworkMask;
+
+@PowerMockIgnore("javax.management.*")
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({ApiDBUtils.class, ActionEventUtils.class, UsageEventUtils.class})
+public class Ipv6ServiceImplTest {
+
+    @Mock
+    NetworkOfferingDao networkOfferingDao;
+    @Mock
+    VlanDao vlanDao;
+    @Mock
+    DataCenterGuestIpv6PrefixDao dataCenterGuestIpv6PrefixDao;
+    @Mock
+    Ipv6GuestPrefixSubnetNetworkMapDao ipv6GuestPrefixSubnetNetworkMapDao;
+    @Mock
+    FirewallRulesDao firewallDao;
+    @Mock
+    FirewallService firewallService;
+    @Mock
+    NetworkDetailsDao networkDetailsDao;
+    @Mock
+    NicDao nicDao;
+    @Mock
+    DomainRouterDao domainRouterDao;
+    @Mock
+    AccountManager accountManager;
+    @Mock
+    NetworkModel networkModel = Mockito.mock(NetworkModelImpl.class);
+    @Mock
+    IPAddressDao ipAddressDao;
+    @Mock
+    NetworkOrchestrationService networkOrchestrationService;
+
+    FirewallManager firewallManager = Mockito.mock(FirewallManager.class);
+
+    @InjectMocks
+    private Ipv6ServiceImpl ipv6Service = new Ipv6ServiceImpl();
+
+    List<Ipv6GuestPrefixSubnetNetworkMapVO> updatedPrefixSubnetMap;
+
+    List<Ipv6GuestPrefixSubnetNetworkMapVO> persistedPrefixSubnetMap;
+
+    final String publicReserver = PublicNetworkGuru.class.getSimpleName();
+    final String vlan = "vlan";
+    final Long networkId = 101L;
+    final Long nicId = 100L;
+    final String ipv6Prefix = "fd17:6:8a43:e2a4::/62"; // Will have 4 /64 subnets
+    final String cidr = "fd17:5:8a43:e2a5::/64";
+    final String gateway = "fd17:5:8a43:e2a5::1";
+    final String macAddress = "1e:00:4c:00:00:03";
+    final String ipv6Address = "fd17:5:8a43:e2a5:1c00:4cff:fe00:3"; // Resulting  IPv6 address using SLAAC
+    public static final long ACCOUNT_ID = 1;
+
+    private AccountVO account;
+    private UserVO user;
+
+    @Before
+    public void setup() {
+        updatedPrefixSubnetMap = new ArrayList<>();
+        persistedPrefixSubnetMap = new ArrayList<>();
+        MockitoAnnotations.initMocks(this);
+        ipv6Service.firewallManager = firewallManager;
+        Mockito.when(ipv6GuestPrefixSubnetNetworkMapDao.update(Mockito.anyLong(), Mockito.any(Ipv6GuestPrefixSubnetNetworkMapVO.class))).thenAnswer((Answer<Boolean>) invocation -> {
+            Ipv6GuestPrefixSubnetNetworkMapVO map = (Ipv6GuestPrefixSubnetNetworkMapVO)invocation.getArguments()[1];
+            updatedPrefixSubnetMap.add(map);
+            return true;
+        });
+        Mockito.when(ipv6GuestPrefixSubnetNetworkMapDao.persist(Mockito.any(Ipv6GuestPrefixSubnetNetworkMapVO.class))).thenAnswer((Answer<Ipv6GuestPrefixSubnetNetworkMapVO>) invocation -> {
+            Ipv6GuestPrefixSubnetNetworkMapVO map = (Ipv6GuestPrefixSubnetNetworkMapVO)invocation.getArguments()[0];
+            persistedPrefixSubnetMap.add(map);
+            return map;
+        });
+        PowerMockito.mockStatic(ApiDBUtils.class);
+        Mockito.when(ApiDBUtils.findZoneById(Mockito.anyLong())).thenReturn(Mockito.mock(DataCenterVO.class));
+    }
+
+    private DataCenterGuestIpv6PrefixVO prepareMocksForIpv6Subnet() {
+        final long prefixId = 1L;
+        DataCenterGuestIpv6PrefixVO prefix = Mockito.mock(DataCenterGuestIpv6PrefixVO.class);
+        Mockito.when(prefix.getId()).thenReturn(prefixId);
+        Mockito.when(prefix.getPrefix()).thenReturn(ipv6Prefix);
+        List<Ipv6GuestPrefixSubnetNetworkMapVO> subnets = new ArrayList<>();
+        Ipv6GuestPrefixSubnetNetworkMapVO subnetMap = new Ipv6GuestPrefixSubnetNetworkMapVO(prefixId, "subnet", 1L, Ipv6GuestPrefixSubnetNetworkMap.State.Allocated);
+        subnets.add(subnetMap);
+        subnetMap = new Ipv6GuestPrefixSubnetNetworkMapVO(1L, "subnet", 2L, Ipv6GuestPrefixSubnetNetworkMap.State.Allocated);
+        subnets.add(subnetMap);
+        Mockito.when(ipv6GuestPrefixSubnetNetworkMapDao.listUsedByPrefix(prefixId)).thenReturn(subnets);
+        return prefix;
+    }
+
+    @Test
+    public void testGetUsedTotalIpv6SubnetForPrefix() {
+        DataCenterGuestIpv6PrefixVO prefix = prepareMocksForIpv6Subnet();
+        Pair<Integer, Integer> results = ipv6Service.getUsedTotalIpv6SubnetForPrefix(prefix);
+        Assert.assertEquals(2, results.first().intValue());
+        Assert.assertEquals(4, results.second().intValue());
+    }
+
+    @Test
+    public void testNoPrefixesGetUsedTotalIpv6SubnetForZone() {
+        final long zoneId = 1L;
+        final List<DataCenterGuestIpv6PrefixVO> prefixes = new ArrayList<>();
+        Mockito.when(dataCenterGuestIpv6PrefixDao.listByDataCenterId(zoneId)).thenReturn(prefixes);
+        Pair<Integer, Integer> results = ipv6Service.getUsedTotalIpv6SubnetForZone(zoneId);
+        Assert.assertEquals(0, results.first().intValue());
+        Assert.assertEquals(0, results.second().intValue());
+    }
+
+    @Test
+    public void testGetUsedTotalIpv6SubnetForZone() {
+        final long zoneId = 1L;
+        final List<DataCenterGuestIpv6PrefixVO> prefixes = new ArrayList<>();
+        DataCenterGuestIpv6PrefixVO prefix = prepareMocksForIpv6Subnet();
+        prefixes.add(prefix);
+        prefixes.add(prefix);
+        Mockito.when(dataCenterGuestIpv6PrefixDao.listByDataCenterId(zoneId)).thenReturn(prefixes);
+        Pair<Integer, Integer> results = ipv6Service.getUsedTotalIpv6SubnetForZone(zoneId);
+        Assert.assertEquals(4, results.first().intValue());
+        Assert.assertEquals(8, results.second().intValue());
+    }
+
+    @Test(expected = ResourceAllocationException.class)
+    @DB

Review Comment:
   Unit tests using DB are a bit worrying. Do these tests reallly need this annotation?
   and if so; Are these tests really needed/not covered by the integration tests?



##########
test/integration/smoke/test_ipv6_infra.py:
##########
@@ -0,0 +1,488 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT tests for IPv6 infra operations"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (cleanup_resources)
+from marvin.lib.base import (Configurations,
+                             NetworkOffering,
+                             VpcOffering,
+                             PublicIpRange)
+from marvin.lib.common import (get_zone)
+from marvin.cloudstackException import CloudstackAPIException
+
+from nose.plugins.attrib import attr
+import logging
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+
+class TestCreateIpv6NetworkVpcOffering(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestCreateIpv6NetworkVpcOffering, cls).getClsTestClient()
+        cls.apiclient = testClient.getApiClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.initial_ipv6_offering_enabled = Configurations.list(
+            cls.apiclient,
+            name=ipv6_offering_config_name)[0].value
+        cls._cleanup = []
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestCreateIpv6NetworkVpcOffering, cls).tearDownClass()
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            #Clean up, terminate the created templates
+            cleanup_resources(self.apiclient, self.cleanup)
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    @attr(
+        tags=[
+            "advanced",
+            "basic",
+            "eip",
+            "sg",
+            "advancedns",
+            "smoke"],
+        required_hardware="false")
+    def test_01_create_ipv6_network_offering(self):
+        """Test to create network offering
+
+        # Validate the following:
+        # 1. createNetworkOffering should return valid info for new offering
+        # 2. The Cloud Database contains the valid information
+        """
+        Configurations.update(self.apiclient,
+            ipv6_offering_config_name,
+            "true")
+        ipv6_service = self.services["network_offering"]
+        ipv6_service["internetprotocol"] = "dualstack"
+        network_offering = NetworkOffering.create(
+            self.apiclient,
+            ipv6_service
+        )
+        self.cleanup.append(network_offering)
+
+        self.debug("Created Network offering with ID: %s" % network_offering.id)
+
+        list_network_off_response = NetworkOffering.list(self.apiclient,
+            id=network_offering.id)
+        self.assertEqual(
+            isinstance(list_network_off_response, list),
+            True,
+            "Check list response returns a valid list"
+        )
+        self.assertNotEqual(
+            len(list_network_off_response),
+            0,
+            "Check Network offering is created"
+        )
+        network_off_response = list_network_off_response[0]
+
+        self.assertEqual(
+            network_off_response.id,
+            network_offering.id,
+            "Check server id in listNetworkOfferings"
+        )
+        self.assertEqual(
+            network_off_response.internetprotocol.lower(),
+            ipv6_service["internetprotocol"].lower(),
+            "Check internetprotocol in listNetworkOfferings"
+        )
+        return
+
+    @attr(
+        tags=[
+            "advanced",
+            "basic",
+            "eip",
+            "sg",
+            "advancedns",
+            "smoke"],
+        required_hardware="false")
+    def test_02_create_ipv6_network_offering_fail(self):
+        """Test to create network offering
+
+        # Validate the following:
+        # 1. createNetworkOffering should fail
+        """
+        Configurations.update(self.apiclient,
+            ipv6_offering_config_name,
+            "false")
+        ipv6_service = self.services["network_offering"]
+        ipv6_service["internetprotocol"] = "dualstack"
+        try:
+            network_offering = NetworkOffering.create(
+                self.apiclient,
+                ipv6_service
+            )
+            self.cleanup.append(network_offering)
+            self.fail("Network offering created despite global setting - %s set to false" % ipv6_offering_config_name)
+        except CloudstackAPIException as e:
+            self.debug("Network offering creation failed as expected %s " % e)
+        return
+
+    @attr(
+        tags=[
+            "advanced",
+            "basic",
+            "eip",
+            "sg",
+            "advancedns",
+            "smoke"],
+        required_hardware="false")
+    def test_03_create_ipv6_vpc_offering(self):
+        """Test to create network offering
+
+        # Validate the following:
+        # 1. createVpcOffering should return valid info for new offering
+        # 2. The Cloud Database contains the valid information
+        """
+        Configurations.update(self.apiclient,
+            ipv6_offering_config_name,
+            "true")
+        ipv6_service = self.services["vpc_offering"]
+        ipv6_service["internetprotocol"] = "dualstack"
+        vpc_offering = VpcOffering.create(
+            self.apiclient,
+            ipv6_service
+        )
+        self.cleanup.append(vpc_offering)
+
+        self.debug("Created VPC offering with ID: %s" % vpc_offering.id)
+
+        list_vpc_off_response = VpcOffering.list(self.apiclient,
+            id=vpc_offering.id)
+        self.assertEqual(
+            isinstance(list_vpc_off_response, list),
+            True,
+            "Check list response returns a valid list"
+        )
+        self.assertNotEqual(
+            len(list_vpc_off_response),
+            0,
+            "Check VPC offering is created"
+        )
+        vpc_off_response = list_vpc_off_response[0]
+        self.assertEqual(
+            vpc_off_response.id,
+            vpc_offering.id,
+            "Check server id in listVpcOfferings"
+        )
+        self.assertEqual(
+            vpc_off_response.internetprotocol.lower(),
+            ipv6_service["internetprotocol"].lower(),
+            "Check internetprotocol in listVpcOfferings"
+        )
+        return
+
+    @attr(
+        tags=[
+            "advanced",
+            "basic",
+            "eip",
+            "sg",
+            "advancedns",
+            "smoke"],
+        required_hardware="false")
+    def test_04_create_ipv6_vpc_offering_fail(self):
+        """Test to create VPC offering failure
+
+        # Validate the following:
+        # 1. createVpcOffering should fail
+        """
+        Configurations.update(self.apiclient,
+            ipv6_offering_config_name,
+            "false")
+        ipv6_service = self.services["vpc_offering"]
+        ipv6_service["internetprotocol"] = "dualstack"
+        try:
+            vpc_offering = VpcOffering.create(
+                self.apiclient,
+                ipv6_service
+            )
+            self.cleanup.append(vpc_offering)
+            self.fail("VPC offering created despite global setting - %s set to false" % ipv6_offering_config_name)
+        except CloudstackAPIException as e:
+            self.debug("VPC offering creation failed as expected %s " % e)
+        return
+
+class TestIpv6PublicIpRange(cloudstackTestCase):
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            #Clean up, terminate the created templates
+            cleanup_resources(self.apiclient, self.cleanup)
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6PublicIpRange, cls).getClsTestClient()
+        cls.apiclient = testClient.getApiClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls._cleanup = []
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        super(TestIpv6PublicIpRange, cls).tearDownClass()
+
+    @attr(
+        tags=[
+            "advanced",
+            "basic",
+            "eip",
+            "sg",
+            "advancedns",
+            "smoke"],
+        required_hardware="false")
+    def test_01_create_ipv6_public_ip_range(self):
+        """Test to add IPv6 public IP range
+
+        # Validate the following:
+        # 1. createVlanIpRange should return valid info for new public range
+        # 2. The Cloud Database contains the valid information
+        """
+        ipv6_publiciprange_service = self.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = self.zone.id
+        ipv6_publiciprange = PublicIpRange.create(
+            self.apiclient,
+            ipv6_publiciprange_service
+        )
+        self.cleanup.append(ipv6_publiciprange)
+
+        self.debug("Created IPv6 public IP range with ID: %s" % ipv6_publiciprange.vlan.id)
+        ipv6_publiciprange = ipv6_publiciprange.vlan
+
+        public_ip_ranges = PublicIpRange.list(
+                    self.apiclient,
+                    id=ipv6_publiciprange.id
+                )
+        self.assertEqual(
+            isinstance(public_ip_ranges, list),
+            True,
+            "Check list response returns a valid list"
+        )
+        self.assertNotEqual(
+            len(public_ip_ranges),
+            0,
+            "Check public IP range is created"
+        )
+        public_ip_range = public_ip_ranges[0]
+
+        self.assertEqual(
+            public_ip_range.id,
+            ipv6_publiciprange.id,
+            "Check server id"
+        )
+        self.assertEqual(
+            public_ip_range.ip6cidr,
+            ipv6_publiciprange_service["ip6cidr"],
+            "Check ip6cidr for IPv6 public IP range"
+        )
+        return
+
+    @attr(
+        tags=[
+            "advanced",
+            "basic",
+            "eip",
+            "sg",
+            "advancedns",
+            "smoke"],
+        required_hardware="false")
+    def test_02_create_ipv6_public_ip_range_fail(self):
+        """Test to add IPv6 public IP range failure
+
+        # Validate the following:
+        # 1. createVlanIpRange should return valid info for new public range
+        # 2. The Cloud Database contains the valid information
+        """
+        ipv6_publiciprange_service = self.services["publicip6range"]
+        cidr = ipv6_publiciprange_service["ip6cidr"]
+        x = cidr.split("/")
+        x[1] = "72"
+        cidr = "/".join(x)
+        ipv6_publiciprange_service["ip6cidr"] = cidr
+        ipv6_publiciprange_service["zoneid"] = self.zone.id
+        try:
+            ipv6_publiciprange = PublicIpRange.create(
+                self.apiclient,
+                ipv6_publiciprange_service
+            )
+        except Exception as e:
+            self.debug("IPv6 public range creation failed as expected %s " % e)
+            ipv6_publiciprange = None
+        if ipv6_publiciprange != None:
+            self.debug("Created IPv6 public range with ID: %s. Deleting it before failure" % ipv6_publiciprange.id)
+            self.cleanup.append(ipv6_publiciprange)

Review Comment:
   ```suggestion
               self.cleanup.append(ipv6_publiciprange)
               self.debug("Created IPv6 public range with ID: %s. Deleting it before failure" % ipv6_publiciprange.id)
   ```
   a bit pompeus, but on io errors we still want to clean up as much as possible.



##########
test/integration/smoke/test_vpc_ipv6.py:
##########
@@ -0,0 +1,911 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT test for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Vpc, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)
+            #Clean up, terminate the created templates
+            # cleanup_resources(self.apiclient, reversed(self.cleanup))
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return

Review Comment:
   ```suggestion
       def tearDown(self):
           try:
               if self.thread and self.thread.is_alive():
                   self.thread.join(5*60)
           except Exception as e:
               raise Exception("Warning: Exception during cleanup : %s" % e)
           finally:
               super(TestIpv6Vpc, self).tearDown()
           return
   ```



##########
test/integration/component/test_vpc_ipv6.py:
##########
@@ -0,0 +1,1036 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT tests for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Vpc, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)
+            #Clean up, terminate the created templates
+            # cleanup_resources(self.apiclient, reversed(self.cleanup))
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    def getRandomIpv6Cidr(self):
+        prefix_length = choice(PREFIX_OPTIONS)
+        random_suffix = getrandbits(40) << (128-prefix_length)
+        base_address = ULA_BASE.network_address + random_suffix
+        return str(IPv6Network((base_address, prefix_length)))
+
+    def createTinyServiceOffering(self):
+        self.service_offering = ServiceOffering.create(
+            self.apiclient,
+            self.services["service_offerings"]["big"],
+        )
+        self.cleanup.append(self.service_offering)
+
+    def createVpcOfferingInternal(self, is_redundant, is_ipv6):
+        off_service = self.services["vpc_offering"]
+        if is_redundant:
+            off_service["serviceCapabilityList"] = {
+                "SourceNat": {
+                    "RedundantRouter": 'true'
+                },
+            }
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        vpc_offering = VpcOffering.create(
+            self.apiclient,
+            off_service
+        )
+        vpc_offering.update(self.apiclient, state='Enabled')
+        return vpc_offering
+
+    def createIpv4VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, False)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOfferingForUpdate(self, is_redundant=False):
+        self.vpc_offering_update = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering_update)
+
+    def createNetworkTierOfferingInternal(self, is_ipv6, remove_lb=True):
+        off_service = self.services["nw_offering_isolated_vpc"]
+        if not remove_lb: # Remove Lb service
+            if "serviceProviderList" in off_service and "Lb" in off_service["serviceProviderList"].keys():
+                providers = off_service["serviceProviderList"]
+                providers.pop("Lb")
+                off_service["serviceProviderList"] = providers
+            if "supportedservices" in off_service and "Lb" in off_service["supportedservices"]:
+                supportedServices = off_service["supportedservices"].split(",")
+                supportedServices.remove("Lb")
+                off_service["supportedservices"] = ",".join(supportedServices)
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        network_offering = NetworkOffering.create(
+            self.apiclient,
+            off_service,
+            conservemode=False
+        )
+        network_offering.update(self.apiclient, state='Enabled')
+        return network_offering
+
+    def createIpv4NetworkTierOffering(self):
+        self.network_offering = self.createNetworkTierOfferingInternal(False)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOffering(self, remove_lb=True):
+        self.network_offering = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering)

Review Comment:
   ```suggestion
   ```



##########
test/integration/component/test_vpc_ipv6.py:
##########
@@ -0,0 +1,1036 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT tests for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Vpc, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)
+            #Clean up, terminate the created templates
+            # cleanup_resources(self.apiclient, reversed(self.cleanup))
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    def getRandomIpv6Cidr(self):
+        prefix_length = choice(PREFIX_OPTIONS)
+        random_suffix = getrandbits(40) << (128-prefix_length)
+        base_address = ULA_BASE.network_address + random_suffix
+        return str(IPv6Network((base_address, prefix_length)))
+
+    def createTinyServiceOffering(self):
+        self.service_offering = ServiceOffering.create(
+            self.apiclient,
+            self.services["service_offerings"]["big"],
+        )
+        self.cleanup.append(self.service_offering)
+
+    def createVpcOfferingInternal(self, is_redundant, is_ipv6):
+        off_service = self.services["vpc_offering"]
+        if is_redundant:
+            off_service["serviceCapabilityList"] = {
+                "SourceNat": {
+                    "RedundantRouter": 'true'
+                },
+            }
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        vpc_offering = VpcOffering.create(
+            self.apiclient,
+            off_service
+        )
+        vpc_offering.update(self.apiclient, state='Enabled')
+        return vpc_offering
+
+    def createIpv4VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, False)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOfferingForUpdate(self, is_redundant=False):
+        self.vpc_offering_update = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering_update)
+
+    def createNetworkTierOfferingInternal(self, is_ipv6, remove_lb=True):
+        off_service = self.services["nw_offering_isolated_vpc"]
+        if not remove_lb: # Remove Lb service
+            if "serviceProviderList" in off_service and "Lb" in off_service["serviceProviderList"].keys():
+                providers = off_service["serviceProviderList"]
+                providers.pop("Lb")
+                off_service["serviceProviderList"] = providers
+            if "supportedservices" in off_service and "Lb" in off_service["supportedservices"]:
+                supportedServices = off_service["supportedservices"].split(",")
+                supportedServices.remove("Lb")
+                off_service["supportedservices"] = ",".join(supportedServices)
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        network_offering = NetworkOffering.create(
+            self.apiclient,
+            off_service,
+            conservemode=False
+        )
+        network_offering.update(self.apiclient, state='Enabled')

Review Comment:
   ```suggestion
           network_offering = NetworkOffering.create(
               self.apiclient,
               off_service,
               conservemode=False
           )
           self.cleanup.append(network_offering)
           network_offering.update(self.apiclient, state='Enabled')
   ```



##########
test/integration/component/test_vpc_ipv6.py:
##########
@@ -0,0 +1,1036 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT tests for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Vpc, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)
+            #Clean up, terminate the created templates
+            # cleanup_resources(self.apiclient, reversed(self.cleanup))
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)

Review Comment:
   ```suggestion
           try:
               if self.thread and self.thread.is_alive():
                   self.thread.join(5*60)
               #Clean up, terminate the created templates
               # cleanup_resources(self.apiclient, reversed(self.cleanup))
   
           except Exception as e:
               raise Exception("Warning: Exception during cleanup : %s" % e)
           finally:
               super(TestIpv6Vpc, self).tearDown()
   ```



##########
test/integration/component/test_vpc_ipv6.py:
##########
@@ -0,0 +1,1036 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT tests for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Vpc, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)
+            #Clean up, terminate the created templates
+            # cleanup_resources(self.apiclient, reversed(self.cleanup))
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    def getRandomIpv6Cidr(self):
+        prefix_length = choice(PREFIX_OPTIONS)
+        random_suffix = getrandbits(40) << (128-prefix_length)
+        base_address = ULA_BASE.network_address + random_suffix
+        return str(IPv6Network((base_address, prefix_length)))
+
+    def createTinyServiceOffering(self):
+        self.service_offering = ServiceOffering.create(
+            self.apiclient,
+            self.services["service_offerings"]["big"],
+        )
+        self.cleanup.append(self.service_offering)
+
+    def createVpcOfferingInternal(self, is_redundant, is_ipv6):
+        off_service = self.services["vpc_offering"]
+        if is_redundant:
+            off_service["serviceCapabilityList"] = {
+                "SourceNat": {
+                    "RedundantRouter": 'true'
+                },
+            }
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        vpc_offering = VpcOffering.create(
+            self.apiclient,
+            off_service
+        )
+        vpc_offering.update(self.apiclient, state='Enabled')
+        return vpc_offering
+
+    def createIpv4VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, False)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOfferingForUpdate(self, is_redundant=False):
+        self.vpc_offering_update = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering_update)
+
+    def createNetworkTierOfferingInternal(self, is_ipv6, remove_lb=True):
+        off_service = self.services["nw_offering_isolated_vpc"]
+        if not remove_lb: # Remove Lb service
+            if "serviceProviderList" in off_service and "Lb" in off_service["serviceProviderList"].keys():
+                providers = off_service["serviceProviderList"]
+                providers.pop("Lb")
+                off_service["serviceProviderList"] = providers
+            if "supportedservices" in off_service and "Lb" in off_service["supportedservices"]:
+                supportedServices = off_service["supportedservices"].split(",")
+                supportedServices.remove("Lb")
+                off_service["supportedservices"] = ",".join(supportedServices)
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        network_offering = NetworkOffering.create(
+            self.apiclient,
+            off_service,
+            conservemode=False
+        )
+        network_offering.update(self.apiclient, state='Enabled')
+        return network_offering
+
+    def createIpv4NetworkTierOffering(self):
+        self.network_offering = self.createNetworkTierOfferingInternal(False)
+        self.cleanup.append(self.network_offering)

Review Comment:
   ```suggestion
   ```



##########
test/integration/smoke/test_vpc_ipv6.py:
##########
@@ -0,0 +1,911 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT test for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Vpc, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)
+            #Clean up, terminate the created templates
+            # cleanup_resources(self.apiclient, reversed(self.cleanup))
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    def getRandomIpv6Cidr(self):
+        prefix_length = choice(PREFIX_OPTIONS)
+        random_suffix = getrandbits(40) << (128-prefix_length)
+        base_address = ULA_BASE.network_address + random_suffix
+        return str(IPv6Network((base_address, prefix_length)))
+
+    def createTinyServiceOffering(self):
+        self.service_offering = ServiceOffering.create(
+            self.apiclient,
+            self.services["service_offerings"]["big"],
+        )
+        self.cleanup.append(self.service_offering)
+
+    def createVpcOfferingInternal(self, is_redundant, is_ipv6):
+        off_service = self.services["vpc_offering"]
+        if is_redundant:
+            off_service["serviceCapabilityList"] = {
+                "SourceNat": {
+                    "RedundantRouter": 'true'
+                },
+            }
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        vpc_offering = VpcOffering.create(
+            self.apiclient,
+            off_service
+        )

Review Comment:
   ```suggestion
           vpc_offering = VpcOffering.create(
               self.apiclient,
               off_service
           )
           self.cleanup.append(vpc_offering)
   ```



##########
test/integration/component/test_vpc_ipv6.py:
##########
@@ -0,0 +1,1036 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT tests for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Vpc, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)
+            #Clean up, terminate the created templates
+            # cleanup_resources(self.apiclient, reversed(self.cleanup))
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    def getRandomIpv6Cidr(self):
+        prefix_length = choice(PREFIX_OPTIONS)
+        random_suffix = getrandbits(40) << (128-prefix_length)
+        base_address = ULA_BASE.network_address + random_suffix
+        return str(IPv6Network((base_address, prefix_length)))
+
+    def createTinyServiceOffering(self):
+        self.service_offering = ServiceOffering.create(
+            self.apiclient,
+            self.services["service_offerings"]["big"],
+        )
+        self.cleanup.append(self.service_offering)
+
+    def createVpcOfferingInternal(self, is_redundant, is_ipv6):
+        off_service = self.services["vpc_offering"]
+        if is_redundant:
+            off_service["serviceCapabilityList"] = {
+                "SourceNat": {
+                    "RedundantRouter": 'true'
+                },
+            }
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        vpc_offering = VpcOffering.create(
+            self.apiclient,
+            off_service
+        )
+        vpc_offering.update(self.apiclient, state='Enabled')
+        return vpc_offering
+
+    def createIpv4VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, False)
+        self.cleanup.append(self.vpc_offering)

Review Comment:
   this appending to the cleanup list should really be inside the `createVpcOfferingInternal()`, directly after the create.
   in this way an exception in the `update()` would leave garbage.
   ```suggestion
   ```



##########
test/integration/smoke/test_vpc_ipv6.py:
##########
@@ -0,0 +1,911 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT test for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Vpc, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)
+            #Clean up, terminate the created templates
+            # cleanup_resources(self.apiclient, reversed(self.cleanup))
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    def getRandomIpv6Cidr(self):
+        prefix_length = choice(PREFIX_OPTIONS)
+        random_suffix = getrandbits(40) << (128-prefix_length)
+        base_address = ULA_BASE.network_address + random_suffix
+        return str(IPv6Network((base_address, prefix_length)))
+
+    def createTinyServiceOffering(self):
+        self.service_offering = ServiceOffering.create(
+            self.apiclient,
+            self.services["service_offerings"]["big"],
+        )
+        self.cleanup.append(self.service_offering)
+
+    def createVpcOfferingInternal(self, is_redundant, is_ipv6):
+        off_service = self.services["vpc_offering"]
+        if is_redundant:
+            off_service["serviceCapabilityList"] = {
+                "SourceNat": {
+                    "RedundantRouter": 'true'
+                },
+            }
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        vpc_offering = VpcOffering.create(
+            self.apiclient,
+            off_service
+        )
+        vpc_offering.update(self.apiclient, state='Enabled')
+        return vpc_offering
+
+    def createIpv4VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, False)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOfferingForUpdate(self, is_redundant=False):
+        self.vpc_offering_update = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering_update)
+
+    def createNetworkTierOfferingInternal(self, is_ipv6, remove_lb=True):
+        off_service = self.services["nw_offering_isolated_vpc"]
+        if not remove_lb: # Remove Lb service
+            if "serviceProviderList" in off_service and "Lb" in off_service["serviceProviderList"].keys():
+                providers = off_service["serviceProviderList"]
+                providers.pop("Lb")
+                off_service["serviceProviderList"] = providers
+            if "supportedservices" in off_service and "Lb" in off_service["supportedservices"]:
+                supportedServices = off_service["supportedservices"].split(",")
+                supportedServices.remove("Lb")
+                off_service["supportedservices"] = ",".join(supportedServices)
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        network_offering = NetworkOffering.create(
+            self.apiclient,
+            off_service,
+            conservemode=False
+        )
+        network_offering.update(self.apiclient, state='Enabled')
+        return network_offering
+
+    def createIpv4NetworkTierOffering(self):
+        self.network_offering = self.createNetworkTierOfferingInternal(False)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOffering(self, remove_lb=True):
+        self.network_offering = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering)

Review Comment:
   ```suggestion
   ```



##########
test/integration/component/test_vpc_ipv6.py:
##########
@@ -0,0 +1,1036 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT tests for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Vpc, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)
+            #Clean up, terminate the created templates
+            # cleanup_resources(self.apiclient, reversed(self.cleanup))
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    def getRandomIpv6Cidr(self):
+        prefix_length = choice(PREFIX_OPTIONS)
+        random_suffix = getrandbits(40) << (128-prefix_length)
+        base_address = ULA_BASE.network_address + random_suffix
+        return str(IPv6Network((base_address, prefix_length)))
+
+    def createTinyServiceOffering(self):
+        self.service_offering = ServiceOffering.create(
+            self.apiclient,
+            self.services["service_offerings"]["big"],
+        )
+        self.cleanup.append(self.service_offering)
+
+    def createVpcOfferingInternal(self, is_redundant, is_ipv6):
+        off_service = self.services["vpc_offering"]
+        if is_redundant:
+            off_service["serviceCapabilityList"] = {
+                "SourceNat": {
+                    "RedundantRouter": 'true'
+                },
+            }
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        vpc_offering = VpcOffering.create(
+            self.apiclient,
+            off_service
+        )
+        vpc_offering.update(self.apiclient, state='Enabled')
+        return vpc_offering
+
+    def createIpv4VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, False)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOfferingForUpdate(self, is_redundant=False):
+        self.vpc_offering_update = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering_update)
+
+    def createNetworkTierOfferingInternal(self, is_ipv6, remove_lb=True):
+        off_service = self.services["nw_offering_isolated_vpc"]
+        if not remove_lb: # Remove Lb service
+            if "serviceProviderList" in off_service and "Lb" in off_service["serviceProviderList"].keys():
+                providers = off_service["serviceProviderList"]
+                providers.pop("Lb")
+                off_service["serviceProviderList"] = providers
+            if "supportedservices" in off_service and "Lb" in off_service["supportedservices"]:
+                supportedServices = off_service["supportedservices"].split(",")
+                supportedServices.remove("Lb")
+                off_service["supportedservices"] = ",".join(supportedServices)
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        network_offering = NetworkOffering.create(
+            self.apiclient,
+            off_service,
+            conservemode=False
+        )
+        network_offering.update(self.apiclient, state='Enabled')
+        return network_offering
+
+    def createIpv4NetworkTierOffering(self):
+        self.network_offering = self.createNetworkTierOfferingInternal(False)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOffering(self, remove_lb=True):
+        self.network_offering = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOfferingForUpdate(self):
+        self.network_offering_update = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering_update)

Review Comment:
   ```suggestion
   ```



##########
test/integration/smoke/test_vpc_ipv6.py:
##########
@@ -0,0 +1,911 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT test for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Vpc, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)
+            #Clean up, terminate the created templates
+            # cleanup_resources(self.apiclient, reversed(self.cleanup))
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    def getRandomIpv6Cidr(self):
+        prefix_length = choice(PREFIX_OPTIONS)
+        random_suffix = getrandbits(40) << (128-prefix_length)
+        base_address = ULA_BASE.network_address + random_suffix
+        return str(IPv6Network((base_address, prefix_length)))
+
+    def createTinyServiceOffering(self):
+        self.service_offering = ServiceOffering.create(
+            self.apiclient,
+            self.services["service_offerings"]["big"],
+        )
+        self.cleanup.append(self.service_offering)
+
+    def createVpcOfferingInternal(self, is_redundant, is_ipv6):
+        off_service = self.services["vpc_offering"]
+        if is_redundant:
+            off_service["serviceCapabilityList"] = {
+                "SourceNat": {
+                    "RedundantRouter": 'true'
+                },
+            }
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        vpc_offering = VpcOffering.create(
+            self.apiclient,
+            off_service
+        )
+        vpc_offering.update(self.apiclient, state='Enabled')
+        return vpc_offering
+
+    def createIpv4VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, False)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOfferingForUpdate(self, is_redundant=False):
+        self.vpc_offering_update = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering_update)
+
+    def createNetworkTierOfferingInternal(self, is_ipv6, remove_lb=True):
+        off_service = self.services["nw_offering_isolated_vpc"]
+        if not remove_lb: # Remove Lb service
+            if "serviceProviderList" in off_service and "Lb" in off_service["serviceProviderList"].keys():
+                providers = off_service["serviceProviderList"]
+                providers.pop("Lb")
+                off_service["serviceProviderList"] = providers
+            if "supportedservices" in off_service and "Lb" in off_service["supportedservices"]:
+                supportedServices = off_service["supportedservices"].split(",")
+                supportedServices.remove("Lb")
+                off_service["supportedservices"] = ",".join(supportedServices)
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        network_offering = NetworkOffering.create(
+            self.apiclient,
+            off_service,
+            conservemode=False
+        )
+        network_offering.update(self.apiclient, state='Enabled')
+        return network_offering
+
+    def createIpv4NetworkTierOffering(self):
+        self.network_offering = self.createNetworkTierOfferingInternal(False)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOffering(self, remove_lb=True):
+        self.network_offering = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOfferingForUpdate(self):
+        self.network_offering_update = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering_update)
+
+    def deployAllowAllVpcInternal(self, cidr):
+        service = self.services["vpc"]
+        service["cidr"] = cidr
+        vpc = VPC.create(
+            self.apiclient,
+            self.services["vpc"],
+            vpcofferingid=self.vpc_offering.id,
+            zoneid=self.zone.id,
+            account=self.account.name,
+            domainid=self.account.domainid
+        )
+        acl = NetworkACLList.create(
+            self.apiclient,
+            services={},
+            name="allowall",
+            description="allowall",
+            vpcid=vpc.id
+        )
+        rule ={
+            "protocol": "all",
+            "traffictype": "ingress",
+        }
+        NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=acl.id
+        )
+        rule["traffictype"] = "egress"
+        NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=acl.id
+        )
+        self.vpcAllowAllAclDetailsMap[vpc.id] = acl.id
+        return vpc
+
+    def deployVpc(self):
+        self.vpc = self.deployAllowAllVpcInternal(VPC_DATA["cidr"])
+        self.cleanup.append(self.vpc)
+
+    def deployNetworkTierInternal(self, network_offering_id, vpc_id, tier_gateway, tier_netmask, acl_id=None, tier_name=None):
+        if not acl_id and vpc_id in self.vpcAllowAllAclDetailsMap:
+            acl_id = self.vpcAllowAllAclDetailsMap[vpc_id]
+        service = self.services["ntwk"]
+        if tier_name:
+            service["name"] = tier_name
+            service["displaytext"] = "vpc-%s" % tier_name
+        network = Network.create(
+            self.apiclient,
+            service,
+            self.account.name,
+            self.account.domainid,
+            networkofferingid=network_offering_id,
+            vpcid=vpc_id,
+            zoneid=self.zone.id,
+            gateway=tier_gateway,
+            netmask=tier_netmask,
+            aclid=acl_id
+        )
+        return network
+
+    def deployNetworkTier(self):
+        self.network = self.deployNetworkTierInternal(
+            self.network_offering.id,
+            self.vpc.id,
+            VPC_DATA["tier1_gateway"],
+            VPC_DATA["tier_netmask"]
+        )
+        self.cleanup.append(self.network)

Review Comment:
   ```suggestion
   ```



##########
test/integration/component/test_vpc_ipv6.py:
##########
@@ -0,0 +1,1036 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT tests for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Vpc, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)
+            #Clean up, terminate the created templates
+            # cleanup_resources(self.apiclient, reversed(self.cleanup))
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    def getRandomIpv6Cidr(self):
+        prefix_length = choice(PREFIX_OPTIONS)
+        random_suffix = getrandbits(40) << (128-prefix_length)
+        base_address = ULA_BASE.network_address + random_suffix
+        return str(IPv6Network((base_address, prefix_length)))
+
+    def createTinyServiceOffering(self):
+        self.service_offering = ServiceOffering.create(
+            self.apiclient,
+            self.services["service_offerings"]["big"],
+        )
+        self.cleanup.append(self.service_offering)
+
+    def createVpcOfferingInternal(self, is_redundant, is_ipv6):
+        off_service = self.services["vpc_offering"]
+        if is_redundant:
+            off_service["serviceCapabilityList"] = {
+                "SourceNat": {
+                    "RedundantRouter": 'true'
+                },
+            }
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        vpc_offering = VpcOffering.create(
+            self.apiclient,
+            off_service
+        )
+        vpc_offering.update(self.apiclient, state='Enabled')
+        return vpc_offering
+
+    def createIpv4VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, False)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOfferingForUpdate(self, is_redundant=False):
+        self.vpc_offering_update = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering_update)
+
+    def createNetworkTierOfferingInternal(self, is_ipv6, remove_lb=True):
+        off_service = self.services["nw_offering_isolated_vpc"]
+        if not remove_lb: # Remove Lb service
+            if "serviceProviderList" in off_service and "Lb" in off_service["serviceProviderList"].keys():
+                providers = off_service["serviceProviderList"]
+                providers.pop("Lb")
+                off_service["serviceProviderList"] = providers
+            if "supportedservices" in off_service and "Lb" in off_service["supportedservices"]:
+                supportedServices = off_service["supportedservices"].split(",")
+                supportedServices.remove("Lb")
+                off_service["supportedservices"] = ",".join(supportedServices)
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        network_offering = NetworkOffering.create(
+            self.apiclient,
+            off_service,
+            conservemode=False
+        )
+        network_offering.update(self.apiclient, state='Enabled')
+        return network_offering
+
+    def createIpv4NetworkTierOffering(self):
+        self.network_offering = self.createNetworkTierOfferingInternal(False)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOffering(self, remove_lb=True):
+        self.network_offering = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOfferingForUpdate(self):
+        self.network_offering_update = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering_update)
+
+    def deployAllowAllVpcInternal(self, cidr):
+        service = self.services["vpc"]
+        service["cidr"] = cidr
+        vpc = VPC.create(
+            self.apiclient,
+            self.services["vpc"],
+            vpcofferingid=self.vpc_offering.id,
+            zoneid=self.zone.id,
+            account=self.account.name,
+            domainid=self.account.domainid
+        )
+        acl = NetworkACLList.create(
+            self.apiclient,
+            services={},
+            name="allowall",
+            description="allowall",
+            vpcid=vpc.id
+        )
+        rule ={
+            "protocol": "all",
+            "traffictype": "ingress",
+        }
+        NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=acl.id
+        )
+        rule["traffictype"] = "egress"
+        NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=acl.id
+        )
+        self.vpcAllowAllAclDetailsMap[vpc.id] = acl.id
+        return vpc
+
+    def deployVpc(self):
+        self.vpc = self.deployAllowAllVpcInternal(VPC_DATA["cidr"])
+        self.cleanup.append(self.vpc)

Review Comment:
   ```suggestion
   ```



##########
test/integration/component/test_vpc_ipv6.py:
##########
@@ -0,0 +1,1036 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT tests for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Vpc, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)
+            #Clean up, terminate the created templates
+            # cleanup_resources(self.apiclient, reversed(self.cleanup))
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    def getRandomIpv6Cidr(self):
+        prefix_length = choice(PREFIX_OPTIONS)
+        random_suffix = getrandbits(40) << (128-prefix_length)
+        base_address = ULA_BASE.network_address + random_suffix
+        return str(IPv6Network((base_address, prefix_length)))
+
+    def createTinyServiceOffering(self):
+        self.service_offering = ServiceOffering.create(
+            self.apiclient,
+            self.services["service_offerings"]["big"],
+        )
+        self.cleanup.append(self.service_offering)
+
+    def createVpcOfferingInternal(self, is_redundant, is_ipv6):
+        off_service = self.services["vpc_offering"]
+        if is_redundant:
+            off_service["serviceCapabilityList"] = {
+                "SourceNat": {
+                    "RedundantRouter": 'true'
+                },
+            }
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        vpc_offering = VpcOffering.create(
+            self.apiclient,
+            off_service
+        )
+        vpc_offering.update(self.apiclient, state='Enabled')
+        return vpc_offering
+
+    def createIpv4VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, False)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering)

Review Comment:
   same here; this appending to the cleanup list should be inside the createVpcOfferingInternal()
   ```suggestion
   ```



##########
test/integration/component/test_vpc_ipv6.py:
##########
@@ -0,0 +1,1036 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT tests for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Vpc, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)
+            #Clean up, terminate the created templates
+            # cleanup_resources(self.apiclient, reversed(self.cleanup))
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    def getRandomIpv6Cidr(self):
+        prefix_length = choice(PREFIX_OPTIONS)
+        random_suffix = getrandbits(40) << (128-prefix_length)
+        base_address = ULA_BASE.network_address + random_suffix
+        return str(IPv6Network((base_address, prefix_length)))
+
+    def createTinyServiceOffering(self):
+        self.service_offering = ServiceOffering.create(
+            self.apiclient,
+            self.services["service_offerings"]["big"],
+        )
+        self.cleanup.append(self.service_offering)
+
+    def createVpcOfferingInternal(self, is_redundant, is_ipv6):
+        off_service = self.services["vpc_offering"]
+        if is_redundant:
+            off_service["serviceCapabilityList"] = {
+                "SourceNat": {
+                    "RedundantRouter": 'true'
+                },
+            }
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        vpc_offering = VpcOffering.create(
+            self.apiclient,
+            off_service
+        )
+        vpc_offering.update(self.apiclient, state='Enabled')
+        return vpc_offering
+
+    def createIpv4VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, False)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOfferingForUpdate(self, is_redundant=False):
+        self.vpc_offering_update = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering_update)
+
+    def createNetworkTierOfferingInternal(self, is_ipv6, remove_lb=True):
+        off_service = self.services["nw_offering_isolated_vpc"]
+        if not remove_lb: # Remove Lb service
+            if "serviceProviderList" in off_service and "Lb" in off_service["serviceProviderList"].keys():
+                providers = off_service["serviceProviderList"]
+                providers.pop("Lb")
+                off_service["serviceProviderList"] = providers
+            if "supportedservices" in off_service and "Lb" in off_service["supportedservices"]:
+                supportedServices = off_service["supportedservices"].split(",")
+                supportedServices.remove("Lb")
+                off_service["supportedservices"] = ",".join(supportedServices)
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        network_offering = NetworkOffering.create(
+            self.apiclient,
+            off_service,
+            conservemode=False
+        )
+        network_offering.update(self.apiclient, state='Enabled')
+        return network_offering
+
+    def createIpv4NetworkTierOffering(self):
+        self.network_offering = self.createNetworkTierOfferingInternal(False)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOffering(self, remove_lb=True):
+        self.network_offering = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOfferingForUpdate(self):
+        self.network_offering_update = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering_update)
+
+    def deployAllowAllVpcInternal(self, cidr):
+        service = self.services["vpc"]
+        service["cidr"] = cidr
+        vpc = VPC.create(
+            self.apiclient,
+            self.services["vpc"],
+            vpcofferingid=self.vpc_offering.id,
+            zoneid=self.zone.id,
+            account=self.account.name,
+            domainid=self.account.domainid
+        )
+        acl = NetworkACLList.create(
+            self.apiclient,
+            services={},
+            name="allowall",
+            description="allowall",
+            vpcid=vpc.id
+        )
+        rule ={
+            "protocol": "all",
+            "traffictype": "ingress",
+        }
+        NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=acl.id
+        )
+        rule["traffictype"] = "egress"
+        NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=acl.id
+        )
+        self.vpcAllowAllAclDetailsMap[vpc.id] = acl.id
+        return vpc
+
+    def deployVpc(self):
+        self.vpc = self.deployAllowAllVpcInternal(VPC_DATA["cidr"])
+        self.cleanup.append(self.vpc)
+
+    def deployNetworkTierInternal(self, network_offering_id, vpc_id, tier_gateway, tier_netmask, acl_id=None, tier_name=None):
+        if not acl_id and vpc_id in self.vpcAllowAllAclDetailsMap:
+            acl_id = self.vpcAllowAllAclDetailsMap[vpc_id]
+        service = self.services["ntwk"]
+        if tier_name:
+            service["name"] = tier_name
+            service["displaytext"] = "vpc-%s" % tier_name
+        network = Network.create(
+            self.apiclient,
+            service,
+            self.account.name,
+            self.account.domainid,
+            networkofferingid=network_offering_id,
+            vpcid=vpc_id,
+            zoneid=self.zone.id,
+            gateway=tier_gateway,
+            netmask=tier_netmask,
+            aclid=acl_id
+        )
+        return network
+
+    def deployNetworkTier(self):
+        self.network = self.deployNetworkTierInternal(
+            self.network_offering.id,
+            self.vpc.id,
+            VPC_DATA["tier1_gateway"],
+            VPC_DATA["tier_netmask"]
+        )
+        self.cleanup.append(self.network)
+
+    def deployNetworkTierVmInternal(self, network):
+        if self.template == FAILED:
+            assert False, "get_test_template() failed to return template"
+        self.services["virtual_machine"]["zoneid"] = self.zone.id
+        virtual_machine = VirtualMachine.create(
+            self.apiclient,
+            self.services["virtual_machine"],
+            templateid=self.template.id,
+            accountid=self.account.name,
+            domainid=self.account.domainid,
+            networkids=network,
+            serviceofferingid=self.service_offering.id
+        )
+        return virtual_machine
+
+    def deployNetworkTierVm(self):
+        self.virtual_machine = self.deployNetworkTierVmInternal(self.network.id)
+        self.cleanup.append(self.virtual_machine)

Review Comment:
   ```suggestion
   ```



##########
test/integration/smoke/test_vpc_ipv6.py:
##########
@@ -0,0 +1,911 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT test for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Vpc, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)
+            #Clean up, terminate the created templates
+            # cleanup_resources(self.apiclient, reversed(self.cleanup))
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    def getRandomIpv6Cidr(self):
+        prefix_length = choice(PREFIX_OPTIONS)
+        random_suffix = getrandbits(40) << (128-prefix_length)
+        base_address = ULA_BASE.network_address + random_suffix
+        return str(IPv6Network((base_address, prefix_length)))
+
+    def createTinyServiceOffering(self):
+        self.service_offering = ServiceOffering.create(
+            self.apiclient,
+            self.services["service_offerings"]["big"],
+        )
+        self.cleanup.append(self.service_offering)
+
+    def createVpcOfferingInternal(self, is_redundant, is_ipv6):
+        off_service = self.services["vpc_offering"]
+        if is_redundant:
+            off_service["serviceCapabilityList"] = {
+                "SourceNat": {
+                    "RedundantRouter": 'true'
+                },
+            }
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        vpc_offering = VpcOffering.create(
+            self.apiclient,
+            off_service
+        )
+        vpc_offering.update(self.apiclient, state='Enabled')
+        return vpc_offering
+
+    def createIpv4VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, False)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering)

Review Comment:
   ```suggestion
   ```



##########
test/integration/component/test_vpc_ipv6.py:
##########
@@ -0,0 +1,1036 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT tests for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Vpc, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)
+            #Clean up, terminate the created templates
+            # cleanup_resources(self.apiclient, reversed(self.cleanup))
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    def getRandomIpv6Cidr(self):
+        prefix_length = choice(PREFIX_OPTIONS)
+        random_suffix = getrandbits(40) << (128-prefix_length)
+        base_address = ULA_BASE.network_address + random_suffix
+        return str(IPv6Network((base_address, prefix_length)))
+
+    def createTinyServiceOffering(self):
+        self.service_offering = ServiceOffering.create(
+            self.apiclient,
+            self.services["service_offerings"]["big"],
+        )
+        self.cleanup.append(self.service_offering)
+
+    def createVpcOfferingInternal(self, is_redundant, is_ipv6):
+        off_service = self.services["vpc_offering"]
+        if is_redundant:
+            off_service["serviceCapabilityList"] = {
+                "SourceNat": {
+                    "RedundantRouter": 'true'
+                },
+            }
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        vpc_offering = VpcOffering.create(
+            self.apiclient,
+            off_service
+        )
+        vpc_offering.update(self.apiclient, state='Enabled')
+        return vpc_offering
+
+    def createIpv4VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, False)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOfferingForUpdate(self, is_redundant=False):
+        self.vpc_offering_update = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering_update)
+
+    def createNetworkTierOfferingInternal(self, is_ipv6, remove_lb=True):
+        off_service = self.services["nw_offering_isolated_vpc"]
+        if not remove_lb: # Remove Lb service
+            if "serviceProviderList" in off_service and "Lb" in off_service["serviceProviderList"].keys():
+                providers = off_service["serviceProviderList"]
+                providers.pop("Lb")
+                off_service["serviceProviderList"] = providers
+            if "supportedservices" in off_service and "Lb" in off_service["supportedservices"]:
+                supportedServices = off_service["supportedservices"].split(",")
+                supportedServices.remove("Lb")
+                off_service["supportedservices"] = ",".join(supportedServices)
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        network_offering = NetworkOffering.create(
+            self.apiclient,
+            off_service,
+            conservemode=False
+        )
+        network_offering.update(self.apiclient, state='Enabled')
+        return network_offering
+
+    def createIpv4NetworkTierOffering(self):
+        self.network_offering = self.createNetworkTierOfferingInternal(False)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOffering(self, remove_lb=True):
+        self.network_offering = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOfferingForUpdate(self):
+        self.network_offering_update = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering_update)
+
+    def deployAllowAllVpcInternal(self, cidr):
+        service = self.services["vpc"]
+        service["cidr"] = cidr
+        vpc = VPC.create(
+            self.apiclient,
+            self.services["vpc"],
+            vpcofferingid=self.vpc_offering.id,
+            zoneid=self.zone.id,
+            account=self.account.name,
+            domainid=self.account.domainid
+        )
+        acl = NetworkACLList.create(
+            self.apiclient,
+            services={},
+            name="allowall",
+            description="allowall",
+            vpcid=vpc.id
+        )
+        rule ={
+            "protocol": "all",
+            "traffictype": "ingress",
+        }
+        NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=acl.id
+        )
+        rule["traffictype"] = "egress"
+        NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=acl.id
+        )
+        self.vpcAllowAllAclDetailsMap[vpc.id] = acl.id
+        return vpc
+
+    def deployVpc(self):
+        self.vpc = self.deployAllowAllVpcInternal(VPC_DATA["cidr"])
+        self.cleanup.append(self.vpc)
+
+    def deployNetworkTierInternal(self, network_offering_id, vpc_id, tier_gateway, tier_netmask, acl_id=None, tier_name=None):
+        if not acl_id and vpc_id in self.vpcAllowAllAclDetailsMap:
+            acl_id = self.vpcAllowAllAclDetailsMap[vpc_id]
+        service = self.services["ntwk"]
+        if tier_name:
+            service["name"] = tier_name
+            service["displaytext"] = "vpc-%s" % tier_name
+        network = Network.create(
+            self.apiclient,
+            service,
+            self.account.name,
+            self.account.domainid,
+            networkofferingid=network_offering_id,
+            vpcid=vpc_id,
+            zoneid=self.zone.id,
+            gateway=tier_gateway,
+            netmask=tier_netmask,
+            aclid=acl_id
+        )

Review Comment:
   ```suggestion
           network = Network.create(
               self.apiclient,
               service,
               self.account.name,
               self.account.domainid,
               networkofferingid=network_offering_id,
               vpcid=vpc_id,
               zoneid=self.zone.id,
               gateway=tier_gateway,
               netmask=tier_netmask,
               aclid=acl_id
           )
           self.cleanup.append(network)
   ```



##########
test/integration/smoke/test_vpc_ipv6.py:
##########
@@ -0,0 +1,911 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT test for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Vpc, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)
+            #Clean up, terminate the created templates
+            # cleanup_resources(self.apiclient, reversed(self.cleanup))
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    def getRandomIpv6Cidr(self):
+        prefix_length = choice(PREFIX_OPTIONS)
+        random_suffix = getrandbits(40) << (128-prefix_length)
+        base_address = ULA_BASE.network_address + random_suffix
+        return str(IPv6Network((base_address, prefix_length)))
+
+    def createTinyServiceOffering(self):
+        self.service_offering = ServiceOffering.create(
+            self.apiclient,
+            self.services["service_offerings"]["big"],
+        )
+        self.cleanup.append(self.service_offering)
+
+    def createVpcOfferingInternal(self, is_redundant, is_ipv6):
+        off_service = self.services["vpc_offering"]
+        if is_redundant:
+            off_service["serviceCapabilityList"] = {
+                "SourceNat": {
+                    "RedundantRouter": 'true'
+                },
+            }
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        vpc_offering = VpcOffering.create(
+            self.apiclient,
+            off_service
+        )
+        vpc_offering.update(self.apiclient, state='Enabled')
+        return vpc_offering
+
+    def createIpv4VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, False)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOfferingForUpdate(self, is_redundant=False):
+        self.vpc_offering_update = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering_update)
+
+    def createNetworkTierOfferingInternal(self, is_ipv6, remove_lb=True):
+        off_service = self.services["nw_offering_isolated_vpc"]
+        if not remove_lb: # Remove Lb service
+            if "serviceProviderList" in off_service and "Lb" in off_service["serviceProviderList"].keys():
+                providers = off_service["serviceProviderList"]
+                providers.pop("Lb")
+                off_service["serviceProviderList"] = providers
+            if "supportedservices" in off_service and "Lb" in off_service["supportedservices"]:
+                supportedServices = off_service["supportedservices"].split(",")
+                supportedServices.remove("Lb")
+                off_service["supportedservices"] = ",".join(supportedServices)
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        network_offering = NetworkOffering.create(
+            self.apiclient,
+            off_service,
+            conservemode=False
+        )
+        network_offering.update(self.apiclient, state='Enabled')
+        return network_offering
+
+    def createIpv4NetworkTierOffering(self):
+        self.network_offering = self.createNetworkTierOfferingInternal(False)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOffering(self, remove_lb=True):
+        self.network_offering = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOfferingForUpdate(self):
+        self.network_offering_update = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering_update)
+
+    def deployAllowAllVpcInternal(self, cidr):
+        service = self.services["vpc"]
+        service["cidr"] = cidr
+        vpc = VPC.create(
+            self.apiclient,
+            self.services["vpc"],
+            vpcofferingid=self.vpc_offering.id,
+            zoneid=self.zone.id,
+            account=self.account.name,
+            domainid=self.account.domainid
+        )
+        acl = NetworkACLList.create(
+            self.apiclient,
+            services={},
+            name="allowall",
+            description="allowall",
+            vpcid=vpc.id
+        )
+        rule ={
+            "protocol": "all",
+            "traffictype": "ingress",
+        }
+        NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=acl.id
+        )
+        rule["traffictype"] = "egress"
+        NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=acl.id
+        )
+        self.vpcAllowAllAclDetailsMap[vpc.id] = acl.id
+        return vpc
+
+    def deployVpc(self):
+        self.vpc = self.deployAllowAllVpcInternal(VPC_DATA["cidr"])
+        self.cleanup.append(self.vpc)
+
+    def deployNetworkTierInternal(self, network_offering_id, vpc_id, tier_gateway, tier_netmask, acl_id=None, tier_name=None):
+        if not acl_id and vpc_id in self.vpcAllowAllAclDetailsMap:
+            acl_id = self.vpcAllowAllAclDetailsMap[vpc_id]
+        service = self.services["ntwk"]
+        if tier_name:
+            service["name"] = tier_name
+            service["displaytext"] = "vpc-%s" % tier_name
+        network = Network.create(
+            self.apiclient,
+            service,
+            self.account.name,
+            self.account.domainid,
+            networkofferingid=network_offering_id,
+            vpcid=vpc_id,
+            zoneid=self.zone.id,
+            gateway=tier_gateway,
+            netmask=tier_netmask,
+            aclid=acl_id
+        )
+        return network
+
+    def deployNetworkTier(self):
+        self.network = self.deployNetworkTierInternal(
+            self.network_offering.id,
+            self.vpc.id,
+            VPC_DATA["tier1_gateway"],
+            VPC_DATA["tier_netmask"]
+        )
+        self.cleanup.append(self.network)
+
+    def deployNetworkTierVmInternal(self, network):
+        if self.template == FAILED:
+            assert False, "get_test_template() failed to return template"
+        self.services["virtual_machine"]["zoneid"] = self.zone.id
+        virtual_machine = VirtualMachine.create(
+            self.apiclient,
+            self.services["virtual_machine"],
+            templateid=self.template.id,
+            accountid=self.account.name,
+            domainid=self.account.domainid,
+            networkids=network,
+            serviceofferingid=self.service_offering.id
+        )

Review Comment:
   ```suggestion
           virtual_machine = VirtualMachine.create(
               self.apiclient,
               self.services["virtual_machine"],
               templateid=self.template.id,
               accountid=self.account.name,
               domainid=self.account.domainid,
               networkids=network,
               serviceofferingid=self.service_offering.id
           )
           self.cleanup.append(virtual_machine)
   ```



##########
test/integration/component/test_vpc_ipv6.py:
##########
@@ -0,0 +1,1036 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT tests for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Vpc, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)
+            #Clean up, terminate the created templates
+            # cleanup_resources(self.apiclient, reversed(self.cleanup))
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    def getRandomIpv6Cidr(self):
+        prefix_length = choice(PREFIX_OPTIONS)
+        random_suffix = getrandbits(40) << (128-prefix_length)
+        base_address = ULA_BASE.network_address + random_suffix
+        return str(IPv6Network((base_address, prefix_length)))
+
+    def createTinyServiceOffering(self):
+        self.service_offering = ServiceOffering.create(
+            self.apiclient,
+            self.services["service_offerings"]["big"],
+        )
+        self.cleanup.append(self.service_offering)
+
+    def createVpcOfferingInternal(self, is_redundant, is_ipv6):
+        off_service = self.services["vpc_offering"]
+        if is_redundant:
+            off_service["serviceCapabilityList"] = {
+                "SourceNat": {
+                    "RedundantRouter": 'true'
+                },
+            }
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        vpc_offering = VpcOffering.create(
+            self.apiclient,
+            off_service
+        )
+        vpc_offering.update(self.apiclient, state='Enabled')
+        return vpc_offering
+
+    def createIpv4VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, False)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOfferingForUpdate(self, is_redundant=False):
+        self.vpc_offering_update = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering_update)
+
+    def createNetworkTierOfferingInternal(self, is_ipv6, remove_lb=True):
+        off_service = self.services["nw_offering_isolated_vpc"]
+        if not remove_lb: # Remove Lb service
+            if "serviceProviderList" in off_service and "Lb" in off_service["serviceProviderList"].keys():
+                providers = off_service["serviceProviderList"]
+                providers.pop("Lb")
+                off_service["serviceProviderList"] = providers
+            if "supportedservices" in off_service and "Lb" in off_service["supportedservices"]:
+                supportedServices = off_service["supportedservices"].split(",")
+                supportedServices.remove("Lb")
+                off_service["supportedservices"] = ",".join(supportedServices)
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        network_offering = NetworkOffering.create(
+            self.apiclient,
+            off_service,
+            conservemode=False
+        )
+        network_offering.update(self.apiclient, state='Enabled')
+        return network_offering
+
+    def createIpv4NetworkTierOffering(self):
+        self.network_offering = self.createNetworkTierOfferingInternal(False)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOffering(self, remove_lb=True):
+        self.network_offering = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOfferingForUpdate(self):
+        self.network_offering_update = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering_update)
+
+    def deployAllowAllVpcInternal(self, cidr):
+        service = self.services["vpc"]
+        service["cidr"] = cidr
+        vpc = VPC.create(
+            self.apiclient,
+            self.services["vpc"],
+            vpcofferingid=self.vpc_offering.id,
+            zoneid=self.zone.id,
+            account=self.account.name,
+            domainid=self.account.domainid
+        )
+        acl = NetworkACLList.create(
+            self.apiclient,
+            services={},
+            name="allowall",
+            description="allowall",
+            vpcid=vpc.id
+        )
+        rule ={
+            "protocol": "all",
+            "traffictype": "ingress",
+        }
+        NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=acl.id
+        )
+        rule["traffictype"] = "egress"
+        NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=acl.id
+        )
+        self.vpcAllowAllAclDetailsMap[vpc.id] = acl.id
+        return vpc
+
+    def deployVpc(self):
+        self.vpc = self.deployAllowAllVpcInternal(VPC_DATA["cidr"])
+        self.cleanup.append(self.vpc)
+
+    def deployNetworkTierInternal(self, network_offering_id, vpc_id, tier_gateway, tier_netmask, acl_id=None, tier_name=None):
+        if not acl_id and vpc_id in self.vpcAllowAllAclDetailsMap:
+            acl_id = self.vpcAllowAllAclDetailsMap[vpc_id]
+        service = self.services["ntwk"]
+        if tier_name:
+            service["name"] = tier_name
+            service["displaytext"] = "vpc-%s" % tier_name
+        network = Network.create(
+            self.apiclient,
+            service,
+            self.account.name,
+            self.account.domainid,
+            networkofferingid=network_offering_id,
+            vpcid=vpc_id,
+            zoneid=self.zone.id,
+            gateway=tier_gateway,
+            netmask=tier_netmask,
+            aclid=acl_id
+        )
+        return network
+
+    def deployNetworkTier(self):
+        self.network = self.deployNetworkTierInternal(
+            self.network_offering.id,
+            self.vpc.id,
+            VPC_DATA["tier1_gateway"],
+            VPC_DATA["tier_netmask"]
+        )
+        self.cleanup.append(self.network)
+
+    def deployNetworkTierVmInternal(self, network):
+        if self.template == FAILED:
+            assert False, "get_test_template() failed to return template"
+        self.services["virtual_machine"]["zoneid"] = self.zone.id
+        virtual_machine = VirtualMachine.create(
+            self.apiclient,
+            self.services["virtual_machine"],
+            templateid=self.template.id,
+            accountid=self.account.name,
+            domainid=self.account.domainid,
+            networkids=network,
+            serviceofferingid=self.service_offering.id
+        )
+        return virtual_machine
+
+    def deployNetworkTierVm(self):
+        self.virtual_machine = self.deployNetworkTierVmInternal(self.network.id)
+        self.cleanup.append(self.virtual_machine)
+
+    def checkIpv6Vpc(self):
+        self.debug("Listing VPC: %s" % (self.vpc.name))
+        ipv6_vpc = VPC.list(self.apiclient,listall="true",id=self.vpc.id)
+        self.assertTrue(
+            isinstance(ipv6_vpc, list),
+            "Check listVpcs response returns a valid list"
+        )
+        self.assertEqual(
+            len(ipv6_vpc),
+            1,
+            "Network not found"
+        )
+        ipv6_vpc = ipv6_vpc[0]
+        self.assertNotEqual(ipv6_vpc.ip6routes,
+                    None,
+                    "IPv6 routes for network is empty")
+
+    def checkIpv6NetworkTierBasic(self):
+        self.debug("Listing network: %s" % (self.network.name))
+        ipv6_network = Network.list(self.apiclient,listall="true",id=self.network.id)
+        self.assertTrue(
+            isinstance(ipv6_network, list),
+            "Check listNetworks response returns a valid list"
+        )
+        self.assertEqual(
+            len(ipv6_network),
+            1,
+            "Network not found"
+        )
+        ipv6_network = ipv6_network[0]
+        self.assertNotEqual(ipv6_network,
+                    None,
+                    "User is not able to retrieve network details %s" % self.network.id)
+        self.assertNotEqual(ipv6_network.ip6cidr,
+                    None,
+                    "IPv6 CIDR for network is empty")
+        self.assertNotEqual(ipv6_network.ip6gateway,
+                    None,
+                    "IPv6 gateway for network is empty")
+        self.assertNotEqual(ipv6_network.ip6routes,
+                    None,
+                    "IPv6 routes for network is empty")
+
+    def checkIpv6VpcRoutersBasic(self):
+        self.debug("Listing routers for VPC: %s" % self.vpc.name)
+        self.routers = Router.list(
+            self.apiclient,
+            vpcid=self.vpc.id,
+            listall=True
+        )
+        self.assertTrue(
+            isinstance(self.routers, list),
+            "Check listRouters response returns a valid list"
+        )
+        self.assertTrue(
+            len(self.routers) > 0,
+            "Router for the network isn't found"
+        )
+        for router in self.routers:
+            self.assertFalse(
+                router.isredundantrouter == True and router.redundantstate == "FAULT",
+                "Router for the network is in FAULT state"
+            )
+            nics = router.nic
+            for nic in nics:
+                if (nic.traffictype == 'Guest' and router.isredundantrouter == False) or nic.traffictype == 'Public':
+                    self.assertNotEqual(nic.ip6address,
+                                None,
+                                "IPv6 address for router %s NIC is empty" % nic.traffictype)
+                    self.assertNotEqual(nic.ip6cidr,
+                                None,
+                                "IPv6 CIDR for router %s NIC is empty" % nic.traffictype)
+                    self.assertNotEqual(nic.ip6gateway,
+                                None,
+                                "IPv6 gateway for router %s NIC is empty" % nic.traffictype)
+
+
+    def getRouterProcessStatus(self, router, cmd):
+        if router.id not in self.routerDetailsMap or self.routerDetailsMap[router.id] is None:
+            connect_ip = self.apiclient.connection.mgtSvr
+            connect_user = self.apiclient.connection.user
+            connect_passwd = self.apiclient.connection.passwd
+            hypervisor = self.hypervisor
+            if self.hypervisor.lower() not in ('vmware', 'hyperv'):
+                hosts = Host.list(
+                    self.apiclient,
+                    zoneid=router.zoneid,
+                    type='Routing',
+                    state='Up',
+                    id=router.hostid
+                )
+                self.assertEqual(
+                    isinstance(hosts, list),
+                    True,
+                    "Check list host returns a valid list"
+                )
+                host = hosts[0]
+                connect_ip = host.ipaddress
+                hypervisor = None
+                try:
+                    connect_user, connect_passwd= get_host_credentials(
+                        self.config, host.ipaddress)
+                except KeyError:
+                    self.skipTest(
+                        "Marvin configuration has no host credentials to\
+                                check router services")
+            details = {}
+            details['connect_ip'] = connect_ip
+            details['connect_user'] = connect_user
+            details['connect_passwd'] = connect_passwd
+            details['hypervisor'] = hypervisor
+            self.routerDetailsMap[router.id] = details
+        result = get_process_status(
+            self.routerDetailsMap[router.id]['connect_ip'],
+            22,
+            self.routerDetailsMap[router.id]['connect_user'],
+            self.routerDetailsMap[router.id]['connect_passwd'],
+            router.linklocalip,
+            cmd,
+            hypervisor=self.routerDetailsMap[router.id]['hypervisor']
+        )
+        self.assertTrue(type(result) == list and len(result) > 0,
+            "%s on router %s returned invalid result" % (cmd, router.id))
+        result = '\n'.join(result)
+        return result
+
+    def getVpcRouter(self, vpc, red_state="PRIMARY"):
+        routers = Router.list(
+            self.apiclient,
+            vpcid=vpc.id,
+            listall=True
+        )
+        self.assertTrue(
+            isinstance(routers, list) and len(routers) > 0,
+            "No routers found for VPC %s" % vpc.id
+        )
+        if len(routers) == 1:
+            return routers[0]
+        for router in routers:
+            if router.redundantstate == red_state:
+                return router
+
+    def getNetworkGateway(self, network):
+        ipv6_network = Network.list(self.apiclient,listall="true",id=network.id)
+        self.assertTrue(
+            isinstance(ipv6_network, list),
+            "Check listNetworks response returns a valid list"
+        )
+        self.assertEqual(
+            len(ipv6_network),
+            1,
+            "Network not found"
+        )
+        ipv6_network = ipv6_network[0]
+        self.assertNotEqual(ipv6_network.ip6gateway,
+                    None,
+                    "IPv6 gateway for network is empty")
+        return ipv6_network.ip6gateway
+
+    def getNetworkRoutes(self, network):
+        ipv6_network = Network.list(self.apiclient,listall="true",id=network.id)
+        self.assertTrue(
+            isinstance(ipv6_network, list),
+            "Check listNetworks response returns a valid list"
+        )
+        self.assertEqual(
+            len(ipv6_network),
+            1,
+            "Network not found"
+        )
+        ipv6_network = ipv6_network[0]
+        self.assertNotEqual(ipv6_network.ip6routes,
+                    None,
+                    "IPv6 routes for network is empty")
+        return ipv6_network.ip6routes
+
+    def isNetworkEgressDefaultPolicyAllow(self, network):
+        ipv6_network = Network.list(self.apiclient,listall="true",id=network.id)
+        if len(ipv6_network) == 1:
+            ipv6_network = ipv6_network[0]
+            return ipv6_network.egressdefaultpolicy
+        return False
+
+    def checkRouterNicState(self, router, dev, state):
+        st = "state %s" % state
+        cmd = "ip link show %s | grep '%s'" % (dev, st)
+        res = self.getRouterProcessStatus(router, cmd)
+        self.assertTrue(type(res) == str and len(res) > 0 and st in res,
+            "%s failed on router %s" % (cmd, router.id))
+
+    def checkIpv6VpcPrimaryRouter(self, router, network_ip6gateway):
+        self.checkRouterNicState(router, VPC_ROUTER_GUEST_NIC, "UP")
+        guest_gateway_check_cmd = "ip -6 address show %s | grep 'inet6 %s'" % (VPC_ROUTER_GUEST_NIC, network_ip6gateway)
+        res = self.getRouterProcessStatus(router, guest_gateway_check_cmd)
+        self.assertTrue(type(res) == str and len(res) > 0 and network_ip6gateway in res,
+            "%s failed on router %s" % (guest_gateway_check_cmd, router.id))
+        self.assertFalse("dadfailed" in res,
+            "dadfailed for IPv6 guest gateway on router %s" % router.id)
+        self.checkRouterNicState(router, VPC_ROUTER_PUBLIC_NIC, "UP")
+        public_ipv6 = None
+        public_ipv6_gateway = None
+        nics = router.nic
+        for nic in nics:
+            if nic.traffictype == 'Public':
+                public_ipv6 = nic.ip6address
+                public_ipv6_gateway = nic.ip6gateway
+                break
+        self.assertNotEqual(public_ipv6,
+            None,
+            "IPv6 address for router Public NIC is empty")
+        public_ip_check_cmd = "ip -6 address show %s | grep 'inet6 %s'" % (VPC_ROUTER_PUBLIC_NIC, public_ipv6)
+        res = self.getRouterProcessStatus(router, public_ip_check_cmd)
+        self.assertTrue(type(res) == str and len(res) > 0 and public_ipv6 in res,
+            "%s failed on router %s" % (public_ip_check_cmd, router.id))
+        self.assertFalse("dadfailed" in res,
+            "dadfailed for public IPv6 on router %s" % router.id)
+        self.assertNotEqual(public_ipv6_gateway,
+            None,
+            "IPv6 gateway for router Public NIC is empty")
+        default_route_check_cmd = "ip -6 route | grep 'default via %s'" % (public_ipv6_gateway)
+        res = self.getRouterProcessStatus(router, default_route_check_cmd)
+        self.assertTrue(type(res) == str and len(res) > 0 and public_ipv6_gateway in res,
+            "%s failed on router %s" % (default_route_check_cmd, router.id))
+
+    def checkIpv6VpcBackupRouter(self, router, network_ip6gateway):
+        self.checkRouterNicState(router, VPC_ROUTER_GUEST_NIC, "UP")
+        guest_gateway_check_cmd = "ip -6 address show %s | grep 'inet6 %s'" % ("eth0", network_ip6gateway)
+        res = self.getRouterProcessStatus(router, guest_gateway_check_cmd)
+        self.assertFalse(type(res) == str and len(res) > 0 and network_ip6gateway in res,
+            "%s failed on router %s" % (guest_gateway_check_cmd, router.id))
+        self.checkRouterNicState(router, VPC_ROUTER_PUBLIC_NIC, "DOWN")
+
+    def checkIpv6VpcRoutersInternal(self):
+        network_ip6gateway = self.getNetworkGateway(self.network)
+        for router in self.routers:
+            if router.state != "Running":
+                continue
+            if router.isredundantrouter == True and router.redundantstate == 'BACKUP':
+                self.checkIpv6VpcBackupRouter(router, network_ip6gateway)
+                continue
+            self.checkIpv6VpcPrimaryRouter(router, network_ip6gateway)
+
+
+    def checkIpv6NetworkTierVm(self):
+        self.debug("Listing NICS for VM %s in network tier: %s" % (self.virtual_machine.name, self.network.name))
+        nics = NIC.list(
+            self.apiclient,
+            virtualmachineid=self.virtual_machine.id,
+            networkid=self.network.id
+        )
+        self.assertEqual(
+            len(nics),
+            1,
+            "VM NIC for the network tier isn't found"
+        )
+        nic = nics[0]
+        self.assertNotEqual(nic.ip6address,
+                    None,
+                    "IPv6 address for VM %s NIC is empty" % nic.traffictype)
+        self.virtual_machine_ipv6_address = nic.ip6address
+        self.assertNotEqual(nic.ip6cidr,
+                    None,
+                    "IPv6 CIDR for VM %s NIC is empty" % nic.traffictype)
+        self.assertNotEqual(nic.ip6gateway,
+                    None,
+                    "IPv6 gateway for VM %s NIC is empty" % nic.traffictype)
+
+    def restartVpcWithCleanup(self):
+        self.vpc.restart(self.apiclient, cleanup=True)
+        time.sleep(SLEEP_BEFORE_VR_CHANGES)
+
+    def updateNetworkTierWithOffering(self):
+        self.network.update(self.apiclient, networkofferingid=self.network_offering_update.id)
+        time.sleep(SLEEP_BEFORE_VR_CHANGES)
+
+    def deployRoutingTestResources(self):
+        self.routing_test_vpc = self.deployAllowAllVpcInternal(ROUTE_TEST_VPC_DATA["cidr"])
+        self.cleanup.append(self.routing_test_vpc)
+        self.routing_test_network_offering = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.routing_test_network_offering)

Review Comment:
   ```suggestion
   ```



##########
test/integration/component/test_vpc_ipv6.py:
##########
@@ -0,0 +1,1036 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT tests for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Vpc, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)
+            #Clean up, terminate the created templates
+            # cleanup_resources(self.apiclient, reversed(self.cleanup))
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    def getRandomIpv6Cidr(self):
+        prefix_length = choice(PREFIX_OPTIONS)
+        random_suffix = getrandbits(40) << (128-prefix_length)
+        base_address = ULA_BASE.network_address + random_suffix
+        return str(IPv6Network((base_address, prefix_length)))
+
+    def createTinyServiceOffering(self):
+        self.service_offering = ServiceOffering.create(
+            self.apiclient,
+            self.services["service_offerings"]["big"],
+        )
+        self.cleanup.append(self.service_offering)
+
+    def createVpcOfferingInternal(self, is_redundant, is_ipv6):
+        off_service = self.services["vpc_offering"]
+        if is_redundant:
+            off_service["serviceCapabilityList"] = {
+                "SourceNat": {
+                    "RedundantRouter": 'true'
+                },
+            }
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        vpc_offering = VpcOffering.create(
+            self.apiclient,
+            off_service
+        )
+        vpc_offering.update(self.apiclient, state='Enabled')
+        return vpc_offering
+
+    def createIpv4VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, False)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOfferingForUpdate(self, is_redundant=False):
+        self.vpc_offering_update = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering_update)
+
+    def createNetworkTierOfferingInternal(self, is_ipv6, remove_lb=True):
+        off_service = self.services["nw_offering_isolated_vpc"]
+        if not remove_lb: # Remove Lb service
+            if "serviceProviderList" in off_service and "Lb" in off_service["serviceProviderList"].keys():
+                providers = off_service["serviceProviderList"]
+                providers.pop("Lb")
+                off_service["serviceProviderList"] = providers
+            if "supportedservices" in off_service and "Lb" in off_service["supportedservices"]:
+                supportedServices = off_service["supportedservices"].split(",")
+                supportedServices.remove("Lb")
+                off_service["supportedservices"] = ",".join(supportedServices)
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        network_offering = NetworkOffering.create(
+            self.apiclient,
+            off_service,
+            conservemode=False
+        )
+        network_offering.update(self.apiclient, state='Enabled')
+        return network_offering
+
+    def createIpv4NetworkTierOffering(self):
+        self.network_offering = self.createNetworkTierOfferingInternal(False)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOffering(self, remove_lb=True):
+        self.network_offering = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOfferingForUpdate(self):
+        self.network_offering_update = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering_update)
+
+    def deployAllowAllVpcInternal(self, cidr):
+        service = self.services["vpc"]
+        service["cidr"] = cidr
+        vpc = VPC.create(
+            self.apiclient,
+            self.services["vpc"],
+            vpcofferingid=self.vpc_offering.id,
+            zoneid=self.zone.id,
+            account=self.account.name,
+            domainid=self.account.domainid
+        )
+        acl = NetworkACLList.create(
+            self.apiclient,
+            services={},
+            name="allowall",
+            description="allowall",
+            vpcid=vpc.id
+        )
+        rule ={
+            "protocol": "all",
+            "traffictype": "ingress",
+        }
+        NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=acl.id
+        )
+        rule["traffictype"] = "egress"
+        NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=acl.id
+        )
+        self.vpcAllowAllAclDetailsMap[vpc.id] = acl.id
+        return vpc
+
+    def deployVpc(self):
+        self.vpc = self.deployAllowAllVpcInternal(VPC_DATA["cidr"])
+        self.cleanup.append(self.vpc)
+
+    def deployNetworkTierInternal(self, network_offering_id, vpc_id, tier_gateway, tier_netmask, acl_id=None, tier_name=None):
+        if not acl_id and vpc_id in self.vpcAllowAllAclDetailsMap:
+            acl_id = self.vpcAllowAllAclDetailsMap[vpc_id]
+        service = self.services["ntwk"]
+        if tier_name:
+            service["name"] = tier_name
+            service["displaytext"] = "vpc-%s" % tier_name
+        network = Network.create(
+            self.apiclient,
+            service,
+            self.account.name,
+            self.account.domainid,
+            networkofferingid=network_offering_id,
+            vpcid=vpc_id,
+            zoneid=self.zone.id,
+            gateway=tier_gateway,
+            netmask=tier_netmask,
+            aclid=acl_id
+        )
+        return network
+
+    def deployNetworkTier(self):
+        self.network = self.deployNetworkTierInternal(
+            self.network_offering.id,
+            self.vpc.id,
+            VPC_DATA["tier1_gateway"],
+            VPC_DATA["tier_netmask"]
+        )
+        self.cleanup.append(self.network)
+
+    def deployNetworkTierVmInternal(self, network):
+        if self.template == FAILED:
+            assert False, "get_test_template() failed to return template"
+        self.services["virtual_machine"]["zoneid"] = self.zone.id
+        virtual_machine = VirtualMachine.create(
+            self.apiclient,
+            self.services["virtual_machine"],
+            templateid=self.template.id,
+            accountid=self.account.name,
+            domainid=self.account.domainid,
+            networkids=network,
+            serviceofferingid=self.service_offering.id
+        )
+        return virtual_machine
+
+    def deployNetworkTierVm(self):
+        self.virtual_machine = self.deployNetworkTierVmInternal(self.network.id)
+        self.cleanup.append(self.virtual_machine)
+
+    def checkIpv6Vpc(self):
+        self.debug("Listing VPC: %s" % (self.vpc.name))
+        ipv6_vpc = VPC.list(self.apiclient,listall="true",id=self.vpc.id)
+        self.assertTrue(
+            isinstance(ipv6_vpc, list),
+            "Check listVpcs response returns a valid list"
+        )
+        self.assertEqual(
+            len(ipv6_vpc),
+            1,
+            "Network not found"
+        )
+        ipv6_vpc = ipv6_vpc[0]
+        self.assertNotEqual(ipv6_vpc.ip6routes,
+                    None,
+                    "IPv6 routes for network is empty")
+
+    def checkIpv6NetworkTierBasic(self):
+        self.debug("Listing network: %s" % (self.network.name))
+        ipv6_network = Network.list(self.apiclient,listall="true",id=self.network.id)
+        self.assertTrue(
+            isinstance(ipv6_network, list),
+            "Check listNetworks response returns a valid list"
+        )
+        self.assertEqual(
+            len(ipv6_network),
+            1,
+            "Network not found"
+        )
+        ipv6_network = ipv6_network[0]
+        self.assertNotEqual(ipv6_network,
+                    None,
+                    "User is not able to retrieve network details %s" % self.network.id)
+        self.assertNotEqual(ipv6_network.ip6cidr,
+                    None,
+                    "IPv6 CIDR for network is empty")
+        self.assertNotEqual(ipv6_network.ip6gateway,
+                    None,
+                    "IPv6 gateway for network is empty")
+        self.assertNotEqual(ipv6_network.ip6routes,
+                    None,
+                    "IPv6 routes for network is empty")
+
+    def checkIpv6VpcRoutersBasic(self):
+        self.debug("Listing routers for VPC: %s" % self.vpc.name)
+        self.routers = Router.list(
+            self.apiclient,
+            vpcid=self.vpc.id,
+            listall=True
+        )
+        self.assertTrue(
+            isinstance(self.routers, list),
+            "Check listRouters response returns a valid list"
+        )
+        self.assertTrue(
+            len(self.routers) > 0,
+            "Router for the network isn't found"
+        )
+        for router in self.routers:
+            self.assertFalse(
+                router.isredundantrouter == True and router.redundantstate == "FAULT",
+                "Router for the network is in FAULT state"
+            )
+            nics = router.nic
+            for nic in nics:
+                if (nic.traffictype == 'Guest' and router.isredundantrouter == False) or nic.traffictype == 'Public':
+                    self.assertNotEqual(nic.ip6address,
+                                None,
+                                "IPv6 address for router %s NIC is empty" % nic.traffictype)
+                    self.assertNotEqual(nic.ip6cidr,
+                                None,
+                                "IPv6 CIDR for router %s NIC is empty" % nic.traffictype)
+                    self.assertNotEqual(nic.ip6gateway,
+                                None,
+                                "IPv6 gateway for router %s NIC is empty" % nic.traffictype)
+
+
+    def getRouterProcessStatus(self, router, cmd):
+        if router.id not in self.routerDetailsMap or self.routerDetailsMap[router.id] is None:
+            connect_ip = self.apiclient.connection.mgtSvr
+            connect_user = self.apiclient.connection.user
+            connect_passwd = self.apiclient.connection.passwd
+            hypervisor = self.hypervisor
+            if self.hypervisor.lower() not in ('vmware', 'hyperv'):
+                hosts = Host.list(
+                    self.apiclient,
+                    zoneid=router.zoneid,
+                    type='Routing',
+                    state='Up',
+                    id=router.hostid
+                )
+                self.assertEqual(
+                    isinstance(hosts, list),
+                    True,
+                    "Check list host returns a valid list"
+                )
+                host = hosts[0]
+                connect_ip = host.ipaddress
+                hypervisor = None
+                try:
+                    connect_user, connect_passwd= get_host_credentials(
+                        self.config, host.ipaddress)
+                except KeyError:
+                    self.skipTest(
+                        "Marvin configuration has no host credentials to\
+                                check router services")
+            details = {}
+            details['connect_ip'] = connect_ip
+            details['connect_user'] = connect_user
+            details['connect_passwd'] = connect_passwd
+            details['hypervisor'] = hypervisor
+            self.routerDetailsMap[router.id] = details
+        result = get_process_status(
+            self.routerDetailsMap[router.id]['connect_ip'],
+            22,
+            self.routerDetailsMap[router.id]['connect_user'],
+            self.routerDetailsMap[router.id]['connect_passwd'],
+            router.linklocalip,
+            cmd,
+            hypervisor=self.routerDetailsMap[router.id]['hypervisor']
+        )
+        self.assertTrue(type(result) == list and len(result) > 0,
+            "%s on router %s returned invalid result" % (cmd, router.id))
+        result = '\n'.join(result)
+        return result
+
+    def getVpcRouter(self, vpc, red_state="PRIMARY"):
+        routers = Router.list(
+            self.apiclient,
+            vpcid=vpc.id,
+            listall=True
+        )
+        self.assertTrue(
+            isinstance(routers, list) and len(routers) > 0,
+            "No routers found for VPC %s" % vpc.id
+        )
+        if len(routers) == 1:
+            return routers[0]
+        for router in routers:
+            if router.redundantstate == red_state:
+                return router
+
+    def getNetworkGateway(self, network):
+        ipv6_network = Network.list(self.apiclient,listall="true",id=network.id)
+        self.assertTrue(
+            isinstance(ipv6_network, list),
+            "Check listNetworks response returns a valid list"
+        )
+        self.assertEqual(
+            len(ipv6_network),
+            1,
+            "Network not found"
+        )
+        ipv6_network = ipv6_network[0]
+        self.assertNotEqual(ipv6_network.ip6gateway,
+                    None,
+                    "IPv6 gateway for network is empty")
+        return ipv6_network.ip6gateway
+
+    def getNetworkRoutes(self, network):
+        ipv6_network = Network.list(self.apiclient,listall="true",id=network.id)
+        self.assertTrue(
+            isinstance(ipv6_network, list),
+            "Check listNetworks response returns a valid list"
+        )
+        self.assertEqual(
+            len(ipv6_network),
+            1,
+            "Network not found"
+        )
+        ipv6_network = ipv6_network[0]
+        self.assertNotEqual(ipv6_network.ip6routes,
+                    None,
+                    "IPv6 routes for network is empty")
+        return ipv6_network.ip6routes
+
+    def isNetworkEgressDefaultPolicyAllow(self, network):
+        ipv6_network = Network.list(self.apiclient,listall="true",id=network.id)
+        if len(ipv6_network) == 1:
+            ipv6_network = ipv6_network[0]
+            return ipv6_network.egressdefaultpolicy
+        return False
+
+    def checkRouterNicState(self, router, dev, state):
+        st = "state %s" % state
+        cmd = "ip link show %s | grep '%s'" % (dev, st)
+        res = self.getRouterProcessStatus(router, cmd)
+        self.assertTrue(type(res) == str and len(res) > 0 and st in res,
+            "%s failed on router %s" % (cmd, router.id))
+
+    def checkIpv6VpcPrimaryRouter(self, router, network_ip6gateway):
+        self.checkRouterNicState(router, VPC_ROUTER_GUEST_NIC, "UP")
+        guest_gateway_check_cmd = "ip -6 address show %s | grep 'inet6 %s'" % (VPC_ROUTER_GUEST_NIC, network_ip6gateway)
+        res = self.getRouterProcessStatus(router, guest_gateway_check_cmd)
+        self.assertTrue(type(res) == str and len(res) > 0 and network_ip6gateway in res,
+            "%s failed on router %s" % (guest_gateway_check_cmd, router.id))
+        self.assertFalse("dadfailed" in res,
+            "dadfailed for IPv6 guest gateway on router %s" % router.id)
+        self.checkRouterNicState(router, VPC_ROUTER_PUBLIC_NIC, "UP")
+        public_ipv6 = None
+        public_ipv6_gateway = None
+        nics = router.nic
+        for nic in nics:
+            if nic.traffictype == 'Public':
+                public_ipv6 = nic.ip6address
+                public_ipv6_gateway = nic.ip6gateway
+                break
+        self.assertNotEqual(public_ipv6,
+            None,
+            "IPv6 address for router Public NIC is empty")
+        public_ip_check_cmd = "ip -6 address show %s | grep 'inet6 %s'" % (VPC_ROUTER_PUBLIC_NIC, public_ipv6)
+        res = self.getRouterProcessStatus(router, public_ip_check_cmd)
+        self.assertTrue(type(res) == str and len(res) > 0 and public_ipv6 in res,
+            "%s failed on router %s" % (public_ip_check_cmd, router.id))
+        self.assertFalse("dadfailed" in res,
+            "dadfailed for public IPv6 on router %s" % router.id)
+        self.assertNotEqual(public_ipv6_gateway,
+            None,
+            "IPv6 gateway for router Public NIC is empty")
+        default_route_check_cmd = "ip -6 route | grep 'default via %s'" % (public_ipv6_gateway)
+        res = self.getRouterProcessStatus(router, default_route_check_cmd)
+        self.assertTrue(type(res) == str and len(res) > 0 and public_ipv6_gateway in res,
+            "%s failed on router %s" % (default_route_check_cmd, router.id))
+
+    def checkIpv6VpcBackupRouter(self, router, network_ip6gateway):
+        self.checkRouterNicState(router, VPC_ROUTER_GUEST_NIC, "UP")
+        guest_gateway_check_cmd = "ip -6 address show %s | grep 'inet6 %s'" % ("eth0", network_ip6gateway)
+        res = self.getRouterProcessStatus(router, guest_gateway_check_cmd)
+        self.assertFalse(type(res) == str and len(res) > 0 and network_ip6gateway in res,
+            "%s failed on router %s" % (guest_gateway_check_cmd, router.id))
+        self.checkRouterNicState(router, VPC_ROUTER_PUBLIC_NIC, "DOWN")
+
+    def checkIpv6VpcRoutersInternal(self):
+        network_ip6gateway = self.getNetworkGateway(self.network)
+        for router in self.routers:
+            if router.state != "Running":
+                continue
+            if router.isredundantrouter == True and router.redundantstate == 'BACKUP':
+                self.checkIpv6VpcBackupRouter(router, network_ip6gateway)
+                continue
+            self.checkIpv6VpcPrimaryRouter(router, network_ip6gateway)
+
+
+    def checkIpv6NetworkTierVm(self):
+        self.debug("Listing NICS for VM %s in network tier: %s" % (self.virtual_machine.name, self.network.name))
+        nics = NIC.list(
+            self.apiclient,
+            virtualmachineid=self.virtual_machine.id,
+            networkid=self.network.id
+        )
+        self.assertEqual(
+            len(nics),
+            1,
+            "VM NIC for the network tier isn't found"
+        )
+        nic = nics[0]
+        self.assertNotEqual(nic.ip6address,
+                    None,
+                    "IPv6 address for VM %s NIC is empty" % nic.traffictype)
+        self.virtual_machine_ipv6_address = nic.ip6address
+        self.assertNotEqual(nic.ip6cidr,
+                    None,
+                    "IPv6 CIDR for VM %s NIC is empty" % nic.traffictype)
+        self.assertNotEqual(nic.ip6gateway,
+                    None,
+                    "IPv6 gateway for VM %s NIC is empty" % nic.traffictype)
+
+    def restartVpcWithCleanup(self):
+        self.vpc.restart(self.apiclient, cleanup=True)
+        time.sleep(SLEEP_BEFORE_VR_CHANGES)
+
+    def updateNetworkTierWithOffering(self):
+        self.network.update(self.apiclient, networkofferingid=self.network_offering_update.id)
+        time.sleep(SLEEP_BEFORE_VR_CHANGES)
+
+    def deployRoutingTestResources(self):
+        self.routing_test_vpc = self.deployAllowAllVpcInternal(ROUTE_TEST_VPC_DATA["cidr"])
+        self.cleanup.append(self.routing_test_vpc)

Review Comment:
   ```suggestion
   ```



##########
test/integration/smoke/test_ipv6_infra.py:
##########
@@ -0,0 +1,488 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT tests for IPv6 infra operations"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (cleanup_resources)
+from marvin.lib.base import (Configurations,
+                             NetworkOffering,
+                             VpcOffering,
+                             PublicIpRange)
+from marvin.lib.common import (get_zone)
+from marvin.cloudstackException import CloudstackAPIException
+
+from nose.plugins.attrib import attr
+import logging
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+
+class TestCreateIpv6NetworkVpcOffering(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestCreateIpv6NetworkVpcOffering, cls).getClsTestClient()
+        cls.apiclient = testClient.getApiClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.initial_ipv6_offering_enabled = Configurations.list(
+            cls.apiclient,
+            name=ipv6_offering_config_name)[0].value
+        cls._cleanup = []
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestCreateIpv6NetworkVpcOffering, cls).tearDownClass()

Review Comment:
   ```suggestion
           try:
               if cls.initial_ipv6_offering_enabled != None:
                   Configurations.update(cls.apiclient,
                       ipv6_offering_config_name,
                       cls.initial_ipv6_offering_enabled)
           finally:
               super(TestCreateIpv6NetworkVpcOffering, cls).tearDownClass()
   ```
   , unless of course we are sure no exceptions can be thrown in the `Configurations.update(..)`, but I think it involves network, so pretty sure it can.



##########
test/integration/component/test_vpc_ipv6.py:
##########
@@ -0,0 +1,1036 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT tests for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Vpc, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)
+            #Clean up, terminate the created templates
+            # cleanup_resources(self.apiclient, reversed(self.cleanup))
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    def getRandomIpv6Cidr(self):
+        prefix_length = choice(PREFIX_OPTIONS)
+        random_suffix = getrandbits(40) << (128-prefix_length)
+        base_address = ULA_BASE.network_address + random_suffix
+        return str(IPv6Network((base_address, prefix_length)))
+
+    def createTinyServiceOffering(self):
+        self.service_offering = ServiceOffering.create(
+            self.apiclient,
+            self.services["service_offerings"]["big"],
+        )
+        self.cleanup.append(self.service_offering)
+
+    def createVpcOfferingInternal(self, is_redundant, is_ipv6):
+        off_service = self.services["vpc_offering"]
+        if is_redundant:
+            off_service["serviceCapabilityList"] = {
+                "SourceNat": {
+                    "RedundantRouter": 'true'
+                },
+            }
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        vpc_offering = VpcOffering.create(
+            self.apiclient,
+            off_service
+        )
+        vpc_offering.update(self.apiclient, state='Enabled')
+        return vpc_offering
+
+    def createIpv4VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, False)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOfferingForUpdate(self, is_redundant=False):
+        self.vpc_offering_update = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering_update)
+
+    def createNetworkTierOfferingInternal(self, is_ipv6, remove_lb=True):
+        off_service = self.services["nw_offering_isolated_vpc"]
+        if not remove_lb: # Remove Lb service
+            if "serviceProviderList" in off_service and "Lb" in off_service["serviceProviderList"].keys():
+                providers = off_service["serviceProviderList"]
+                providers.pop("Lb")
+                off_service["serviceProviderList"] = providers
+            if "supportedservices" in off_service and "Lb" in off_service["supportedservices"]:
+                supportedServices = off_service["supportedservices"].split(",")
+                supportedServices.remove("Lb")
+                off_service["supportedservices"] = ",".join(supportedServices)
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        network_offering = NetworkOffering.create(
+            self.apiclient,
+            off_service,
+            conservemode=False
+        )
+        network_offering.update(self.apiclient, state='Enabled')
+        return network_offering
+
+    def createIpv4NetworkTierOffering(self):
+        self.network_offering = self.createNetworkTierOfferingInternal(False)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOffering(self, remove_lb=True):
+        self.network_offering = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOfferingForUpdate(self):
+        self.network_offering_update = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering_update)
+
+    def deployAllowAllVpcInternal(self, cidr):
+        service = self.services["vpc"]
+        service["cidr"] = cidr
+        vpc = VPC.create(
+            self.apiclient,
+            self.services["vpc"],
+            vpcofferingid=self.vpc_offering.id,
+            zoneid=self.zone.id,
+            account=self.account.name,
+            domainid=self.account.domainid
+        )
+        acl = NetworkACLList.create(
+            self.apiclient,
+            services={},
+            name="allowall",
+            description="allowall",
+            vpcid=vpc.id
+        )
+        rule ={
+            "protocol": "all",
+            "traffictype": "ingress",
+        }
+        NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=acl.id
+        )
+        rule["traffictype"] = "egress"
+        NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=acl.id
+        )
+        self.vpcAllowAllAclDetailsMap[vpc.id] = acl.id
+        return vpc
+
+    def deployVpc(self):
+        self.vpc = self.deployAllowAllVpcInternal(VPC_DATA["cidr"])
+        self.cleanup.append(self.vpc)
+
+    def deployNetworkTierInternal(self, network_offering_id, vpc_id, tier_gateway, tier_netmask, acl_id=None, tier_name=None):
+        if not acl_id and vpc_id in self.vpcAllowAllAclDetailsMap:
+            acl_id = self.vpcAllowAllAclDetailsMap[vpc_id]
+        service = self.services["ntwk"]
+        if tier_name:
+            service["name"] = tier_name
+            service["displaytext"] = "vpc-%s" % tier_name
+        network = Network.create(
+            self.apiclient,
+            service,
+            self.account.name,
+            self.account.domainid,
+            networkofferingid=network_offering_id,
+            vpcid=vpc_id,
+            zoneid=self.zone.id,
+            gateway=tier_gateway,
+            netmask=tier_netmask,
+            aclid=acl_id
+        )
+        return network
+
+    def deployNetworkTier(self):
+        self.network = self.deployNetworkTierInternal(
+            self.network_offering.id,
+            self.vpc.id,
+            VPC_DATA["tier1_gateway"],
+            VPC_DATA["tier_netmask"]
+        )
+        self.cleanup.append(self.network)

Review Comment:
   ```suggestion
   ```



##########
test/integration/component/test_vpc_ipv6.py:
##########
@@ -0,0 +1,1036 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT tests for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Vpc, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)
+            #Clean up, terminate the created templates
+            # cleanup_resources(self.apiclient, reversed(self.cleanup))
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    def getRandomIpv6Cidr(self):
+        prefix_length = choice(PREFIX_OPTIONS)
+        random_suffix = getrandbits(40) << (128-prefix_length)
+        base_address = ULA_BASE.network_address + random_suffix
+        return str(IPv6Network((base_address, prefix_length)))
+
+    def createTinyServiceOffering(self):
+        self.service_offering = ServiceOffering.create(
+            self.apiclient,
+            self.services["service_offerings"]["big"],
+        )
+        self.cleanup.append(self.service_offering)
+
+    def createVpcOfferingInternal(self, is_redundant, is_ipv6):
+        off_service = self.services["vpc_offering"]
+        if is_redundant:
+            off_service["serviceCapabilityList"] = {
+                "SourceNat": {
+                    "RedundantRouter": 'true'
+                },
+            }
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        vpc_offering = VpcOffering.create(
+            self.apiclient,
+            off_service
+        )
+        vpc_offering.update(self.apiclient, state='Enabled')
+        return vpc_offering
+
+    def createIpv4VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, False)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOfferingForUpdate(self, is_redundant=False):
+        self.vpc_offering_update = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering_update)

Review Comment:
   same here; this appending to the cleanup list should be inside the `createVpcOfferingInternal()`
   ```suggestion
   ```



##########
test/integration/smoke/test_ipv6_infra.py:
##########
@@ -0,0 +1,488 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT tests for IPv6 infra operations"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (cleanup_resources)
+from marvin.lib.base import (Configurations,
+                             NetworkOffering,
+                             VpcOffering,
+                             PublicIpRange)
+from marvin.lib.common import (get_zone)
+from marvin.cloudstackException import CloudstackAPIException
+
+from nose.plugins.attrib import attr
+import logging
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+
+class TestCreateIpv6NetworkVpcOffering(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestCreateIpv6NetworkVpcOffering, cls).getClsTestClient()
+        cls.apiclient = testClient.getApiClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.initial_ipv6_offering_enabled = Configurations.list(
+            cls.apiclient,
+            name=ipv6_offering_config_name)[0].value
+        cls._cleanup = []
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestCreateIpv6NetworkVpcOffering, cls).tearDownClass()
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            #Clean up, terminate the created templates
+            cleanup_resources(self.apiclient, self.cleanup)
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    @attr(
+        tags=[
+            "advanced",
+            "basic",
+            "eip",
+            "sg",
+            "advancedns",
+            "smoke"],
+        required_hardware="false")
+    def test_01_create_ipv6_network_offering(self):
+        """Test to create network offering
+
+        # Validate the following:
+        # 1. createNetworkOffering should return valid info for new offering
+        # 2. The Cloud Database contains the valid information
+        """
+        Configurations.update(self.apiclient,
+            ipv6_offering_config_name,
+            "true")
+        ipv6_service = self.services["network_offering"]
+        ipv6_service["internetprotocol"] = "dualstack"
+        network_offering = NetworkOffering.create(
+            self.apiclient,
+            ipv6_service
+        )
+        self.cleanup.append(network_offering)
+
+        self.debug("Created Network offering with ID: %s" % network_offering.id)
+
+        list_network_off_response = NetworkOffering.list(self.apiclient,
+            id=network_offering.id)
+        self.assertEqual(
+            isinstance(list_network_off_response, list),
+            True,
+            "Check list response returns a valid list"
+        )
+        self.assertNotEqual(
+            len(list_network_off_response),
+            0,
+            "Check Network offering is created"
+        )
+        network_off_response = list_network_off_response[0]
+
+        self.assertEqual(
+            network_off_response.id,
+            network_offering.id,
+            "Check server id in listNetworkOfferings"
+        )
+        self.assertEqual(
+            network_off_response.internetprotocol.lower(),
+            ipv6_service["internetprotocol"].lower(),
+            "Check internetprotocol in listNetworkOfferings"
+        )
+        return
+
+    @attr(
+        tags=[
+            "advanced",
+            "basic",
+            "eip",
+            "sg",
+            "advancedns",
+            "smoke"],
+        required_hardware="false")
+    def test_02_create_ipv6_network_offering_fail(self):
+        """Test to create network offering
+
+        # Validate the following:
+        # 1. createNetworkOffering should fail
+        """
+        Configurations.update(self.apiclient,
+            ipv6_offering_config_name,
+            "false")
+        ipv6_service = self.services["network_offering"]
+        ipv6_service["internetprotocol"] = "dualstack"
+        try:
+            network_offering = NetworkOffering.create(
+                self.apiclient,
+                ipv6_service
+            )
+            self.cleanup.append(network_offering)
+            self.fail("Network offering created despite global setting - %s set to false" % ipv6_offering_config_name)
+        except CloudstackAPIException as e:
+            self.debug("Network offering creation failed as expected %s " % e)
+        return
+
+    @attr(
+        tags=[
+            "advanced",
+            "basic",
+            "eip",
+            "sg",
+            "advancedns",
+            "smoke"],
+        required_hardware="false")
+    def test_03_create_ipv6_vpc_offering(self):
+        """Test to create network offering
+
+        # Validate the following:
+        # 1. createVpcOffering should return valid info for new offering
+        # 2. The Cloud Database contains the valid information
+        """
+        Configurations.update(self.apiclient,
+            ipv6_offering_config_name,
+            "true")
+        ipv6_service = self.services["vpc_offering"]
+        ipv6_service["internetprotocol"] = "dualstack"
+        vpc_offering = VpcOffering.create(
+            self.apiclient,
+            ipv6_service
+        )
+        self.cleanup.append(vpc_offering)
+
+        self.debug("Created VPC offering with ID: %s" % vpc_offering.id)
+
+        list_vpc_off_response = VpcOffering.list(self.apiclient,
+            id=vpc_offering.id)
+        self.assertEqual(
+            isinstance(list_vpc_off_response, list),
+            True,
+            "Check list response returns a valid list"
+        )
+        self.assertNotEqual(
+            len(list_vpc_off_response),
+            0,
+            "Check VPC offering is created"
+        )
+        vpc_off_response = list_vpc_off_response[0]
+        self.assertEqual(
+            vpc_off_response.id,
+            vpc_offering.id,
+            "Check server id in listVpcOfferings"
+        )
+        self.assertEqual(
+            vpc_off_response.internetprotocol.lower(),
+            ipv6_service["internetprotocol"].lower(),
+            "Check internetprotocol in listVpcOfferings"
+        )
+        return
+
+    @attr(
+        tags=[
+            "advanced",
+            "basic",
+            "eip",
+            "sg",
+            "advancedns",
+            "smoke"],
+        required_hardware="false")
+    def test_04_create_ipv6_vpc_offering_fail(self):
+        """Test to create VPC offering failure
+
+        # Validate the following:
+        # 1. createVpcOffering should fail
+        """
+        Configurations.update(self.apiclient,
+            ipv6_offering_config_name,
+            "false")
+        ipv6_service = self.services["vpc_offering"]
+        ipv6_service["internetprotocol"] = "dualstack"
+        try:
+            vpc_offering = VpcOffering.create(
+                self.apiclient,
+                ipv6_service
+            )
+            self.cleanup.append(vpc_offering)
+            self.fail("VPC offering created despite global setting - %s set to false" % ipv6_offering_config_name)
+        except CloudstackAPIException as e:
+            self.debug("VPC offering creation failed as expected %s " % e)
+        return
+
+class TestIpv6PublicIpRange(cloudstackTestCase):
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            #Clean up, terminate the created templates
+            cleanup_resources(self.apiclient, self.cleanup)
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return

Review Comment:
   ```suggestion
       def tearDown(self):
           super(TestIpv6PublicIpRange, self).tearDown()
   ```



##########
test/integration/component/test_vpc_ipv6.py:
##########
@@ -0,0 +1,1036 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT tests for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Vpc, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)
+            #Clean up, terminate the created templates
+            # cleanup_resources(self.apiclient, reversed(self.cleanup))
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    def getRandomIpv6Cidr(self):
+        prefix_length = choice(PREFIX_OPTIONS)
+        random_suffix = getrandbits(40) << (128-prefix_length)
+        base_address = ULA_BASE.network_address + random_suffix
+        return str(IPv6Network((base_address, prefix_length)))
+
+    def createTinyServiceOffering(self):
+        self.service_offering = ServiceOffering.create(
+            self.apiclient,
+            self.services["service_offerings"]["big"],
+        )
+        self.cleanup.append(self.service_offering)
+
+    def createVpcOfferingInternal(self, is_redundant, is_ipv6):
+        off_service = self.services["vpc_offering"]
+        if is_redundant:
+            off_service["serviceCapabilityList"] = {
+                "SourceNat": {
+                    "RedundantRouter": 'true'
+                },
+            }
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        vpc_offering = VpcOffering.create(
+            self.apiclient,
+            off_service
+        )
+        vpc_offering.update(self.apiclient, state='Enabled')
+        return vpc_offering
+
+    def createIpv4VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, False)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOfferingForUpdate(self, is_redundant=False):
+        self.vpc_offering_update = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering_update)
+
+    def createNetworkTierOfferingInternal(self, is_ipv6, remove_lb=True):
+        off_service = self.services["nw_offering_isolated_vpc"]
+        if not remove_lb: # Remove Lb service
+            if "serviceProviderList" in off_service and "Lb" in off_service["serviceProviderList"].keys():
+                providers = off_service["serviceProviderList"]
+                providers.pop("Lb")
+                off_service["serviceProviderList"] = providers
+            if "supportedservices" in off_service and "Lb" in off_service["supportedservices"]:
+                supportedServices = off_service["supportedservices"].split(",")
+                supportedServices.remove("Lb")
+                off_service["supportedservices"] = ",".join(supportedServices)
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        network_offering = NetworkOffering.create(
+            self.apiclient,
+            off_service,
+            conservemode=False
+        )
+        network_offering.update(self.apiclient, state='Enabled')
+        return network_offering
+
+    def createIpv4NetworkTierOffering(self):
+        self.network_offering = self.createNetworkTierOfferingInternal(False)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOffering(self, remove_lb=True):
+        self.network_offering = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOfferingForUpdate(self):
+        self.network_offering_update = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering_update)
+
+    def deployAllowAllVpcInternal(self, cidr):
+        service = self.services["vpc"]
+        service["cidr"] = cidr
+        vpc = VPC.create(
+            self.apiclient,
+            self.services["vpc"],
+            vpcofferingid=self.vpc_offering.id,
+            zoneid=self.zone.id,
+            account=self.account.name,
+            domainid=self.account.domainid
+        )
+        acl = NetworkACLList.create(
+            self.apiclient,
+            services={},
+            name="allowall",
+            description="allowall",
+            vpcid=vpc.id
+        )
+        rule ={
+            "protocol": "all",
+            "traffictype": "ingress",
+        }
+        NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=acl.id
+        )
+        rule["traffictype"] = "egress"
+        NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=acl.id
+        )
+        self.vpcAllowAllAclDetailsMap[vpc.id] = acl.id
+        return vpc
+
+    def deployVpc(self):
+        self.vpc = self.deployAllowAllVpcInternal(VPC_DATA["cidr"])
+        self.cleanup.append(self.vpc)
+
+    def deployNetworkTierInternal(self, network_offering_id, vpc_id, tier_gateway, tier_netmask, acl_id=None, tier_name=None):
+        if not acl_id and vpc_id in self.vpcAllowAllAclDetailsMap:
+            acl_id = self.vpcAllowAllAclDetailsMap[vpc_id]
+        service = self.services["ntwk"]
+        if tier_name:
+            service["name"] = tier_name
+            service["displaytext"] = "vpc-%s" % tier_name
+        network = Network.create(
+            self.apiclient,
+            service,
+            self.account.name,
+            self.account.domainid,
+            networkofferingid=network_offering_id,
+            vpcid=vpc_id,
+            zoneid=self.zone.id,
+            gateway=tier_gateway,
+            netmask=tier_netmask,
+            aclid=acl_id
+        )
+        return network
+
+    def deployNetworkTier(self):
+        self.network = self.deployNetworkTierInternal(
+            self.network_offering.id,
+            self.vpc.id,
+            VPC_DATA["tier1_gateway"],
+            VPC_DATA["tier_netmask"]
+        )
+        self.cleanup.append(self.network)
+
+    def deployNetworkTierVmInternal(self, network):
+        if self.template == FAILED:
+            assert False, "get_test_template() failed to return template"
+        self.services["virtual_machine"]["zoneid"] = self.zone.id
+        virtual_machine = VirtualMachine.create(
+            self.apiclient,
+            self.services["virtual_machine"],
+            templateid=self.template.id,
+            accountid=self.account.name,
+            domainid=self.account.domainid,
+            networkids=network,
+            serviceofferingid=self.service_offering.id
+        )
+        return virtual_machine
+
+    def deployNetworkTierVm(self):
+        self.virtual_machine = self.deployNetworkTierVmInternal(self.network.id)
+        self.cleanup.append(self.virtual_machine)
+
+    def checkIpv6Vpc(self):
+        self.debug("Listing VPC: %s" % (self.vpc.name))
+        ipv6_vpc = VPC.list(self.apiclient,listall="true",id=self.vpc.id)
+        self.assertTrue(
+            isinstance(ipv6_vpc, list),
+            "Check listVpcs response returns a valid list"
+        )
+        self.assertEqual(
+            len(ipv6_vpc),
+            1,
+            "Network not found"
+        )
+        ipv6_vpc = ipv6_vpc[0]
+        self.assertNotEqual(ipv6_vpc.ip6routes,
+                    None,
+                    "IPv6 routes for network is empty")
+
+    def checkIpv6NetworkTierBasic(self):
+        self.debug("Listing network: %s" % (self.network.name))
+        ipv6_network = Network.list(self.apiclient,listall="true",id=self.network.id)
+        self.assertTrue(
+            isinstance(ipv6_network, list),
+            "Check listNetworks response returns a valid list"
+        )
+        self.assertEqual(
+            len(ipv6_network),
+            1,
+            "Network not found"
+        )
+        ipv6_network = ipv6_network[0]
+        self.assertNotEqual(ipv6_network,
+                    None,
+                    "User is not able to retrieve network details %s" % self.network.id)
+        self.assertNotEqual(ipv6_network.ip6cidr,
+                    None,
+                    "IPv6 CIDR for network is empty")
+        self.assertNotEqual(ipv6_network.ip6gateway,
+                    None,
+                    "IPv6 gateway for network is empty")
+        self.assertNotEqual(ipv6_network.ip6routes,
+                    None,
+                    "IPv6 routes for network is empty")
+
+    def checkIpv6VpcRoutersBasic(self):
+        self.debug("Listing routers for VPC: %s" % self.vpc.name)
+        self.routers = Router.list(
+            self.apiclient,
+            vpcid=self.vpc.id,
+            listall=True
+        )
+        self.assertTrue(
+            isinstance(self.routers, list),
+            "Check listRouters response returns a valid list"
+        )
+        self.assertTrue(
+            len(self.routers) > 0,
+            "Router for the network isn't found"
+        )
+        for router in self.routers:
+            self.assertFalse(
+                router.isredundantrouter == True and router.redundantstate == "FAULT",
+                "Router for the network is in FAULT state"
+            )
+            nics = router.nic
+            for nic in nics:
+                if (nic.traffictype == 'Guest' and router.isredundantrouter == False) or nic.traffictype == 'Public':
+                    self.assertNotEqual(nic.ip6address,
+                                None,
+                                "IPv6 address for router %s NIC is empty" % nic.traffictype)
+                    self.assertNotEqual(nic.ip6cidr,
+                                None,
+                                "IPv6 CIDR for router %s NIC is empty" % nic.traffictype)
+                    self.assertNotEqual(nic.ip6gateway,
+                                None,
+                                "IPv6 gateway for router %s NIC is empty" % nic.traffictype)
+
+
+    def getRouterProcessStatus(self, router, cmd):
+        if router.id not in self.routerDetailsMap or self.routerDetailsMap[router.id] is None:
+            connect_ip = self.apiclient.connection.mgtSvr
+            connect_user = self.apiclient.connection.user
+            connect_passwd = self.apiclient.connection.passwd
+            hypervisor = self.hypervisor
+            if self.hypervisor.lower() not in ('vmware', 'hyperv'):
+                hosts = Host.list(
+                    self.apiclient,
+                    zoneid=router.zoneid,
+                    type='Routing',
+                    state='Up',
+                    id=router.hostid
+                )
+                self.assertEqual(
+                    isinstance(hosts, list),
+                    True,
+                    "Check list host returns a valid list"
+                )
+                host = hosts[0]
+                connect_ip = host.ipaddress
+                hypervisor = None
+                try:
+                    connect_user, connect_passwd= get_host_credentials(
+                        self.config, host.ipaddress)
+                except KeyError:
+                    self.skipTest(
+                        "Marvin configuration has no host credentials to\
+                                check router services")
+            details = {}
+            details['connect_ip'] = connect_ip
+            details['connect_user'] = connect_user
+            details['connect_passwd'] = connect_passwd
+            details['hypervisor'] = hypervisor
+            self.routerDetailsMap[router.id] = details
+        result = get_process_status(
+            self.routerDetailsMap[router.id]['connect_ip'],
+            22,
+            self.routerDetailsMap[router.id]['connect_user'],
+            self.routerDetailsMap[router.id]['connect_passwd'],
+            router.linklocalip,
+            cmd,
+            hypervisor=self.routerDetailsMap[router.id]['hypervisor']
+        )
+        self.assertTrue(type(result) == list and len(result) > 0,
+            "%s on router %s returned invalid result" % (cmd, router.id))
+        result = '\n'.join(result)
+        return result
+
+    def getVpcRouter(self, vpc, red_state="PRIMARY"):
+        routers = Router.list(
+            self.apiclient,
+            vpcid=vpc.id,
+            listall=True
+        )
+        self.assertTrue(
+            isinstance(routers, list) and len(routers) > 0,
+            "No routers found for VPC %s" % vpc.id
+        )
+        if len(routers) == 1:
+            return routers[0]
+        for router in routers:
+            if router.redundantstate == red_state:
+                return router
+
+    def getNetworkGateway(self, network):
+        ipv6_network = Network.list(self.apiclient,listall="true",id=network.id)
+        self.assertTrue(
+            isinstance(ipv6_network, list),
+            "Check listNetworks response returns a valid list"
+        )
+        self.assertEqual(
+            len(ipv6_network),
+            1,
+            "Network not found"
+        )
+        ipv6_network = ipv6_network[0]
+        self.assertNotEqual(ipv6_network.ip6gateway,
+                    None,
+                    "IPv6 gateway for network is empty")
+        return ipv6_network.ip6gateway
+
+    def getNetworkRoutes(self, network):
+        ipv6_network = Network.list(self.apiclient,listall="true",id=network.id)
+        self.assertTrue(
+            isinstance(ipv6_network, list),
+            "Check listNetworks response returns a valid list"
+        )
+        self.assertEqual(
+            len(ipv6_network),
+            1,
+            "Network not found"
+        )
+        ipv6_network = ipv6_network[0]
+        self.assertNotEqual(ipv6_network.ip6routes,
+                    None,
+                    "IPv6 routes for network is empty")
+        return ipv6_network.ip6routes
+
+    def isNetworkEgressDefaultPolicyAllow(self, network):
+        ipv6_network = Network.list(self.apiclient,listall="true",id=network.id)
+        if len(ipv6_network) == 1:
+            ipv6_network = ipv6_network[0]
+            return ipv6_network.egressdefaultpolicy
+        return False
+
+    def checkRouterNicState(self, router, dev, state):
+        st = "state %s" % state
+        cmd = "ip link show %s | grep '%s'" % (dev, st)
+        res = self.getRouterProcessStatus(router, cmd)
+        self.assertTrue(type(res) == str and len(res) > 0 and st in res,
+            "%s failed on router %s" % (cmd, router.id))
+
+    def checkIpv6VpcPrimaryRouter(self, router, network_ip6gateway):
+        self.checkRouterNicState(router, VPC_ROUTER_GUEST_NIC, "UP")
+        guest_gateway_check_cmd = "ip -6 address show %s | grep 'inet6 %s'" % (VPC_ROUTER_GUEST_NIC, network_ip6gateway)
+        res = self.getRouterProcessStatus(router, guest_gateway_check_cmd)
+        self.assertTrue(type(res) == str and len(res) > 0 and network_ip6gateway in res,
+            "%s failed on router %s" % (guest_gateway_check_cmd, router.id))
+        self.assertFalse("dadfailed" in res,
+            "dadfailed for IPv6 guest gateway on router %s" % router.id)
+        self.checkRouterNicState(router, VPC_ROUTER_PUBLIC_NIC, "UP")
+        public_ipv6 = None
+        public_ipv6_gateway = None
+        nics = router.nic
+        for nic in nics:
+            if nic.traffictype == 'Public':
+                public_ipv6 = nic.ip6address
+                public_ipv6_gateway = nic.ip6gateway
+                break
+        self.assertNotEqual(public_ipv6,
+            None,
+            "IPv6 address for router Public NIC is empty")
+        public_ip_check_cmd = "ip -6 address show %s | grep 'inet6 %s'" % (VPC_ROUTER_PUBLIC_NIC, public_ipv6)
+        res = self.getRouterProcessStatus(router, public_ip_check_cmd)
+        self.assertTrue(type(res) == str and len(res) > 0 and public_ipv6 in res,
+            "%s failed on router %s" % (public_ip_check_cmd, router.id))
+        self.assertFalse("dadfailed" in res,
+            "dadfailed for public IPv6 on router %s" % router.id)
+        self.assertNotEqual(public_ipv6_gateway,
+            None,
+            "IPv6 gateway for router Public NIC is empty")
+        default_route_check_cmd = "ip -6 route | grep 'default via %s'" % (public_ipv6_gateway)
+        res = self.getRouterProcessStatus(router, default_route_check_cmd)
+        self.assertTrue(type(res) == str and len(res) > 0 and public_ipv6_gateway in res,
+            "%s failed on router %s" % (default_route_check_cmd, router.id))
+
+    def checkIpv6VpcBackupRouter(self, router, network_ip6gateway):
+        self.checkRouterNicState(router, VPC_ROUTER_GUEST_NIC, "UP")
+        guest_gateway_check_cmd = "ip -6 address show %s | grep 'inet6 %s'" % ("eth0", network_ip6gateway)
+        res = self.getRouterProcessStatus(router, guest_gateway_check_cmd)
+        self.assertFalse(type(res) == str and len(res) > 0 and network_ip6gateway in res,
+            "%s failed on router %s" % (guest_gateway_check_cmd, router.id))
+        self.checkRouterNicState(router, VPC_ROUTER_PUBLIC_NIC, "DOWN")
+
+    def checkIpv6VpcRoutersInternal(self):
+        network_ip6gateway = self.getNetworkGateway(self.network)
+        for router in self.routers:
+            if router.state != "Running":
+                continue
+            if router.isredundantrouter == True and router.redundantstate == 'BACKUP':
+                self.checkIpv6VpcBackupRouter(router, network_ip6gateway)
+                continue
+            self.checkIpv6VpcPrimaryRouter(router, network_ip6gateway)
+
+
+    def checkIpv6NetworkTierVm(self):
+        self.debug("Listing NICS for VM %s in network tier: %s" % (self.virtual_machine.name, self.network.name))
+        nics = NIC.list(
+            self.apiclient,
+            virtualmachineid=self.virtual_machine.id,
+            networkid=self.network.id
+        )
+        self.assertEqual(
+            len(nics),
+            1,
+            "VM NIC for the network tier isn't found"
+        )
+        nic = nics[0]
+        self.assertNotEqual(nic.ip6address,
+                    None,
+                    "IPv6 address for VM %s NIC is empty" % nic.traffictype)
+        self.virtual_machine_ipv6_address = nic.ip6address
+        self.assertNotEqual(nic.ip6cidr,
+                    None,
+                    "IPv6 CIDR for VM %s NIC is empty" % nic.traffictype)
+        self.assertNotEqual(nic.ip6gateway,
+                    None,
+                    "IPv6 gateway for VM %s NIC is empty" % nic.traffictype)
+
+    def restartVpcWithCleanup(self):
+        self.vpc.restart(self.apiclient, cleanup=True)
+        time.sleep(SLEEP_BEFORE_VR_CHANGES)
+
+    def updateNetworkTierWithOffering(self):
+        self.network.update(self.apiclient, networkofferingid=self.network_offering_update.id)
+        time.sleep(SLEEP_BEFORE_VR_CHANGES)
+
+    def deployRoutingTestResources(self):
+        self.routing_test_vpc = self.deployAllowAllVpcInternal(ROUTE_TEST_VPC_DATA["cidr"])
+        self.cleanup.append(self.routing_test_vpc)
+        self.routing_test_network_offering = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.routing_test_network_offering)
+        self.routing_test_network = self.deployNetworkTierInternal(
+            self.routing_test_network_offering.id,
+            self.routing_test_vpc.id,
+            ROUTE_TEST_VPC_DATA["tier1_gateway"],
+            ROUTE_TEST_VPC_DATA["tier_netmask"]
+        )
+        self.cleanup.append(self.routing_test_network)

Review Comment:
   ```suggestion
   ```



##########
test/integration/component/test_vpc_ipv6.py:
##########
@@ -0,0 +1,1036 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT tests for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Vpc, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)
+            #Clean up, terminate the created templates
+            # cleanup_resources(self.apiclient, reversed(self.cleanup))
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    def getRandomIpv6Cidr(self):
+        prefix_length = choice(PREFIX_OPTIONS)
+        random_suffix = getrandbits(40) << (128-prefix_length)
+        base_address = ULA_BASE.network_address + random_suffix
+        return str(IPv6Network((base_address, prefix_length)))
+
+    def createTinyServiceOffering(self):
+        self.service_offering = ServiceOffering.create(
+            self.apiclient,
+            self.services["service_offerings"]["big"],
+        )
+        self.cleanup.append(self.service_offering)
+
+    def createVpcOfferingInternal(self, is_redundant, is_ipv6):
+        off_service = self.services["vpc_offering"]
+        if is_redundant:
+            off_service["serviceCapabilityList"] = {
+                "SourceNat": {
+                    "RedundantRouter": 'true'
+                },
+            }
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        vpc_offering = VpcOffering.create(
+            self.apiclient,
+            off_service
+        )
+        vpc_offering.update(self.apiclient, state='Enabled')
+        return vpc_offering
+
+    def createIpv4VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, False)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOfferingForUpdate(self, is_redundant=False):
+        self.vpc_offering_update = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering_update)
+
+    def createNetworkTierOfferingInternal(self, is_ipv6, remove_lb=True):
+        off_service = self.services["nw_offering_isolated_vpc"]
+        if not remove_lb: # Remove Lb service
+            if "serviceProviderList" in off_service and "Lb" in off_service["serviceProviderList"].keys():
+                providers = off_service["serviceProviderList"]
+                providers.pop("Lb")
+                off_service["serviceProviderList"] = providers
+            if "supportedservices" in off_service and "Lb" in off_service["supportedservices"]:
+                supportedServices = off_service["supportedservices"].split(",")
+                supportedServices.remove("Lb")
+                off_service["supportedservices"] = ",".join(supportedServices)
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        network_offering = NetworkOffering.create(
+            self.apiclient,
+            off_service,
+            conservemode=False
+        )
+        network_offering.update(self.apiclient, state='Enabled')
+        return network_offering
+
+    def createIpv4NetworkTierOffering(self):
+        self.network_offering = self.createNetworkTierOfferingInternal(False)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOffering(self, remove_lb=True):
+        self.network_offering = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOfferingForUpdate(self):
+        self.network_offering_update = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering_update)
+
+    def deployAllowAllVpcInternal(self, cidr):
+        service = self.services["vpc"]
+        service["cidr"] = cidr
+        vpc = VPC.create(
+            self.apiclient,
+            self.services["vpc"],
+            vpcofferingid=self.vpc_offering.id,
+            zoneid=self.zone.id,
+            account=self.account.name,
+            domainid=self.account.domainid
+        )
+        acl = NetworkACLList.create(
+            self.apiclient,
+            services={},
+            name="allowall",
+            description="allowall",
+            vpcid=vpc.id
+        )
+        rule ={
+            "protocol": "all",
+            "traffictype": "ingress",
+        }
+        NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=acl.id
+        )
+        rule["traffictype"] = "egress"
+        NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=acl.id
+        )
+        self.vpcAllowAllAclDetailsMap[vpc.id] = acl.id
+        return vpc
+
+    def deployVpc(self):
+        self.vpc = self.deployAllowAllVpcInternal(VPC_DATA["cidr"])
+        self.cleanup.append(self.vpc)
+
+    def deployNetworkTierInternal(self, network_offering_id, vpc_id, tier_gateway, tier_netmask, acl_id=None, tier_name=None):
+        if not acl_id and vpc_id in self.vpcAllowAllAclDetailsMap:
+            acl_id = self.vpcAllowAllAclDetailsMap[vpc_id]
+        service = self.services["ntwk"]
+        if tier_name:
+            service["name"] = tier_name
+            service["displaytext"] = "vpc-%s" % tier_name
+        network = Network.create(
+            self.apiclient,
+            service,
+            self.account.name,
+            self.account.domainid,
+            networkofferingid=network_offering_id,
+            vpcid=vpc_id,
+            zoneid=self.zone.id,
+            gateway=tier_gateway,
+            netmask=tier_netmask,
+            aclid=acl_id
+        )
+        return network
+
+    def deployNetworkTier(self):
+        self.network = self.deployNetworkTierInternal(
+            self.network_offering.id,
+            self.vpc.id,
+            VPC_DATA["tier1_gateway"],
+            VPC_DATA["tier_netmask"]
+        )
+        self.cleanup.append(self.network)
+
+    def deployNetworkTierVmInternal(self, network):
+        if self.template == FAILED:
+            assert False, "get_test_template() failed to return template"
+        self.services["virtual_machine"]["zoneid"] = self.zone.id
+        virtual_machine = VirtualMachine.create(
+            self.apiclient,
+            self.services["virtual_machine"],
+            templateid=self.template.id,
+            accountid=self.account.name,
+            domainid=self.account.domainid,
+            networkids=network,
+            serviceofferingid=self.service_offering.id
+        )
+        return virtual_machine
+
+    def deployNetworkTierVm(self):
+        self.virtual_machine = self.deployNetworkTierVmInternal(self.network.id)
+        self.cleanup.append(self.virtual_machine)
+
+    def checkIpv6Vpc(self):
+        self.debug("Listing VPC: %s" % (self.vpc.name))
+        ipv6_vpc = VPC.list(self.apiclient,listall="true",id=self.vpc.id)
+        self.assertTrue(
+            isinstance(ipv6_vpc, list),
+            "Check listVpcs response returns a valid list"
+        )
+        self.assertEqual(
+            len(ipv6_vpc),
+            1,
+            "Network not found"
+        )
+        ipv6_vpc = ipv6_vpc[0]
+        self.assertNotEqual(ipv6_vpc.ip6routes,
+                    None,
+                    "IPv6 routes for network is empty")
+
+    def checkIpv6NetworkTierBasic(self):
+        self.debug("Listing network: %s" % (self.network.name))
+        ipv6_network = Network.list(self.apiclient,listall="true",id=self.network.id)
+        self.assertTrue(
+            isinstance(ipv6_network, list),
+            "Check listNetworks response returns a valid list"
+        )
+        self.assertEqual(
+            len(ipv6_network),
+            1,
+            "Network not found"
+        )
+        ipv6_network = ipv6_network[0]
+        self.assertNotEqual(ipv6_network,
+                    None,
+                    "User is not able to retrieve network details %s" % self.network.id)
+        self.assertNotEqual(ipv6_network.ip6cidr,
+                    None,
+                    "IPv6 CIDR for network is empty")
+        self.assertNotEqual(ipv6_network.ip6gateway,
+                    None,
+                    "IPv6 gateway for network is empty")
+        self.assertNotEqual(ipv6_network.ip6routes,
+                    None,
+                    "IPv6 routes for network is empty")
+
+    def checkIpv6VpcRoutersBasic(self):
+        self.debug("Listing routers for VPC: %s" % self.vpc.name)
+        self.routers = Router.list(
+            self.apiclient,
+            vpcid=self.vpc.id,
+            listall=True
+        )
+        self.assertTrue(
+            isinstance(self.routers, list),
+            "Check listRouters response returns a valid list"
+        )
+        self.assertTrue(
+            len(self.routers) > 0,
+            "Router for the network isn't found"
+        )
+        for router in self.routers:
+            self.assertFalse(
+                router.isredundantrouter == True and router.redundantstate == "FAULT",
+                "Router for the network is in FAULT state"
+            )
+            nics = router.nic
+            for nic in nics:
+                if (nic.traffictype == 'Guest' and router.isredundantrouter == False) or nic.traffictype == 'Public':
+                    self.assertNotEqual(nic.ip6address,
+                                None,
+                                "IPv6 address for router %s NIC is empty" % nic.traffictype)
+                    self.assertNotEqual(nic.ip6cidr,
+                                None,
+                                "IPv6 CIDR for router %s NIC is empty" % nic.traffictype)
+                    self.assertNotEqual(nic.ip6gateway,
+                                None,
+                                "IPv6 gateway for router %s NIC is empty" % nic.traffictype)
+
+
+    def getRouterProcessStatus(self, router, cmd):
+        if router.id not in self.routerDetailsMap or self.routerDetailsMap[router.id] is None:
+            connect_ip = self.apiclient.connection.mgtSvr
+            connect_user = self.apiclient.connection.user
+            connect_passwd = self.apiclient.connection.passwd
+            hypervisor = self.hypervisor
+            if self.hypervisor.lower() not in ('vmware', 'hyperv'):
+                hosts = Host.list(
+                    self.apiclient,
+                    zoneid=router.zoneid,
+                    type='Routing',
+                    state='Up',
+                    id=router.hostid
+                )
+                self.assertEqual(
+                    isinstance(hosts, list),
+                    True,
+                    "Check list host returns a valid list"
+                )
+                host = hosts[0]
+                connect_ip = host.ipaddress
+                hypervisor = None
+                try:
+                    connect_user, connect_passwd= get_host_credentials(
+                        self.config, host.ipaddress)
+                except KeyError:
+                    self.skipTest(
+                        "Marvin configuration has no host credentials to\
+                                check router services")
+            details = {}
+            details['connect_ip'] = connect_ip
+            details['connect_user'] = connect_user
+            details['connect_passwd'] = connect_passwd
+            details['hypervisor'] = hypervisor
+            self.routerDetailsMap[router.id] = details
+        result = get_process_status(
+            self.routerDetailsMap[router.id]['connect_ip'],
+            22,
+            self.routerDetailsMap[router.id]['connect_user'],
+            self.routerDetailsMap[router.id]['connect_passwd'],
+            router.linklocalip,
+            cmd,
+            hypervisor=self.routerDetailsMap[router.id]['hypervisor']
+        )
+        self.assertTrue(type(result) == list and len(result) > 0,
+            "%s on router %s returned invalid result" % (cmd, router.id))
+        result = '\n'.join(result)
+        return result
+
+    def getVpcRouter(self, vpc, red_state="PRIMARY"):
+        routers = Router.list(
+            self.apiclient,
+            vpcid=vpc.id,
+            listall=True
+        )
+        self.assertTrue(
+            isinstance(routers, list) and len(routers) > 0,
+            "No routers found for VPC %s" % vpc.id
+        )
+        if len(routers) == 1:
+            return routers[0]
+        for router in routers:
+            if router.redundantstate == red_state:
+                return router
+
+    def getNetworkGateway(self, network):
+        ipv6_network = Network.list(self.apiclient,listall="true",id=network.id)
+        self.assertTrue(
+            isinstance(ipv6_network, list),
+            "Check listNetworks response returns a valid list"
+        )
+        self.assertEqual(
+            len(ipv6_network),
+            1,
+            "Network not found"
+        )
+        ipv6_network = ipv6_network[0]
+        self.assertNotEqual(ipv6_network.ip6gateway,
+                    None,
+                    "IPv6 gateway for network is empty")
+        return ipv6_network.ip6gateway
+
+    def getNetworkRoutes(self, network):
+        ipv6_network = Network.list(self.apiclient,listall="true",id=network.id)
+        self.assertTrue(
+            isinstance(ipv6_network, list),
+            "Check listNetworks response returns a valid list"
+        )
+        self.assertEqual(
+            len(ipv6_network),
+            1,
+            "Network not found"
+        )
+        ipv6_network = ipv6_network[0]
+        self.assertNotEqual(ipv6_network.ip6routes,
+                    None,
+                    "IPv6 routes for network is empty")
+        return ipv6_network.ip6routes
+
+    def isNetworkEgressDefaultPolicyAllow(self, network):
+        ipv6_network = Network.list(self.apiclient,listall="true",id=network.id)
+        if len(ipv6_network) == 1:
+            ipv6_network = ipv6_network[0]
+            return ipv6_network.egressdefaultpolicy
+        return False
+
+    def checkRouterNicState(self, router, dev, state):
+        st = "state %s" % state
+        cmd = "ip link show %s | grep '%s'" % (dev, st)
+        res = self.getRouterProcessStatus(router, cmd)
+        self.assertTrue(type(res) == str and len(res) > 0 and st in res,
+            "%s failed on router %s" % (cmd, router.id))
+
+    def checkIpv6VpcPrimaryRouter(self, router, network_ip6gateway):
+        self.checkRouterNicState(router, VPC_ROUTER_GUEST_NIC, "UP")
+        guest_gateway_check_cmd = "ip -6 address show %s | grep 'inet6 %s'" % (VPC_ROUTER_GUEST_NIC, network_ip6gateway)
+        res = self.getRouterProcessStatus(router, guest_gateway_check_cmd)
+        self.assertTrue(type(res) == str and len(res) > 0 and network_ip6gateway in res,
+            "%s failed on router %s" % (guest_gateway_check_cmd, router.id))
+        self.assertFalse("dadfailed" in res,
+            "dadfailed for IPv6 guest gateway on router %s" % router.id)
+        self.checkRouterNicState(router, VPC_ROUTER_PUBLIC_NIC, "UP")
+        public_ipv6 = None
+        public_ipv6_gateway = None
+        nics = router.nic
+        for nic in nics:
+            if nic.traffictype == 'Public':
+                public_ipv6 = nic.ip6address
+                public_ipv6_gateway = nic.ip6gateway
+                break
+        self.assertNotEqual(public_ipv6,
+            None,
+            "IPv6 address for router Public NIC is empty")
+        public_ip_check_cmd = "ip -6 address show %s | grep 'inet6 %s'" % (VPC_ROUTER_PUBLIC_NIC, public_ipv6)
+        res = self.getRouterProcessStatus(router, public_ip_check_cmd)
+        self.assertTrue(type(res) == str and len(res) > 0 and public_ipv6 in res,
+            "%s failed on router %s" % (public_ip_check_cmd, router.id))
+        self.assertFalse("dadfailed" in res,
+            "dadfailed for public IPv6 on router %s" % router.id)
+        self.assertNotEqual(public_ipv6_gateway,
+            None,
+            "IPv6 gateway for router Public NIC is empty")
+        default_route_check_cmd = "ip -6 route | grep 'default via %s'" % (public_ipv6_gateway)
+        res = self.getRouterProcessStatus(router, default_route_check_cmd)
+        self.assertTrue(type(res) == str and len(res) > 0 and public_ipv6_gateway in res,
+            "%s failed on router %s" % (default_route_check_cmd, router.id))
+
+    def checkIpv6VpcBackupRouter(self, router, network_ip6gateway):
+        self.checkRouterNicState(router, VPC_ROUTER_GUEST_NIC, "UP")
+        guest_gateway_check_cmd = "ip -6 address show %s | grep 'inet6 %s'" % ("eth0", network_ip6gateway)
+        res = self.getRouterProcessStatus(router, guest_gateway_check_cmd)
+        self.assertFalse(type(res) == str and len(res) > 0 and network_ip6gateway in res,
+            "%s failed on router %s" % (guest_gateway_check_cmd, router.id))
+        self.checkRouterNicState(router, VPC_ROUTER_PUBLIC_NIC, "DOWN")
+
+    def checkIpv6VpcRoutersInternal(self):
+        network_ip6gateway = self.getNetworkGateway(self.network)
+        for router in self.routers:
+            if router.state != "Running":
+                continue
+            if router.isredundantrouter == True and router.redundantstate == 'BACKUP':
+                self.checkIpv6VpcBackupRouter(router, network_ip6gateway)
+                continue
+            self.checkIpv6VpcPrimaryRouter(router, network_ip6gateway)
+
+
+    def checkIpv6NetworkTierVm(self):
+        self.debug("Listing NICS for VM %s in network tier: %s" % (self.virtual_machine.name, self.network.name))
+        nics = NIC.list(
+            self.apiclient,
+            virtualmachineid=self.virtual_machine.id,
+            networkid=self.network.id
+        )
+        self.assertEqual(
+            len(nics),
+            1,
+            "VM NIC for the network tier isn't found"
+        )
+        nic = nics[0]
+        self.assertNotEqual(nic.ip6address,
+                    None,
+                    "IPv6 address for VM %s NIC is empty" % nic.traffictype)
+        self.virtual_machine_ipv6_address = nic.ip6address
+        self.assertNotEqual(nic.ip6cidr,
+                    None,
+                    "IPv6 CIDR for VM %s NIC is empty" % nic.traffictype)
+        self.assertNotEqual(nic.ip6gateway,
+                    None,
+                    "IPv6 gateway for VM %s NIC is empty" % nic.traffictype)
+
+    def restartVpcWithCleanup(self):
+        self.vpc.restart(self.apiclient, cleanup=True)
+        time.sleep(SLEEP_BEFORE_VR_CHANGES)
+
+    def updateNetworkTierWithOffering(self):
+        self.network.update(self.apiclient, networkofferingid=self.network_offering_update.id)
+        time.sleep(SLEEP_BEFORE_VR_CHANGES)
+
+    def deployRoutingTestResources(self):
+        self.routing_test_vpc = self.deployAllowAllVpcInternal(ROUTE_TEST_VPC_DATA["cidr"])
+        self.cleanup.append(self.routing_test_vpc)
+        self.routing_test_network_offering = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.routing_test_network_offering)
+        self.routing_test_network = self.deployNetworkTierInternal(
+            self.routing_test_network_offering.id,
+            self.routing_test_vpc.id,
+            ROUTE_TEST_VPC_DATA["tier1_gateway"],
+            ROUTE_TEST_VPC_DATA["tier_netmask"]
+        )
+        self.cleanup.append(self.routing_test_network)
+        self.services["virtual_machine"]["zoneid"] = self.zone.id
+        self.routing_test_vm = VirtualMachine.create(
+            self.apiclient,
+            self.services["virtual_machine"],
+            templateid=self.template.id,
+            accountid=self.account.name,
+            domainid=self.account.domainid,
+            networkids=[self.routing_test_network.id],
+            serviceofferingid=self.service_offering.id,
+            mode="advanced",
+            vpcid=self.routing_test_vpc.id
+        )
+        self.cleanup.append(self.routing_test_vm)
+
+    def prepareRoutingTestResourcesInBackground(self):
+        self.thread = threading.Thread(target=self.deployRoutingTestResources, args=())
+        self.thread.daemon = True
+        self.thread.start()
+
+    def checkVpcRouting(self):
+        if not self.thread:
+            self.deployRoutingTestResources()
+        else:
+            self.thread.join(5*60)
+        self.assertFalse(not self.routing_test_vpc or not self.routing_test_network or not self.routing_test_vm,
+            "Routing resources failure")
+
+        test_vpc_router = self.getVpcRouter(self.routing_test_vpc)
+        routes = self.getNetworkRoutes(self.network)
+        self.logger.debug("Adding vpc routes in routing_test_vpc %s" % routes)
+        for route in routes:
+            add_route_cmd = "ip -6 route add %s via %s" % (route.subnet, route.gateway)
+            self.getRouterProcessStatus(test_vpc_router, add_route_cmd)
+
+        vpc_router = self.getVpcRouter(self.vpc)
+        routes = self.getNetworkRoutes(self.routing_test_network)
+        self.logger.debug("Adding routing_test_vpc routes in vpc %s" % routes)
+        for route in routes:
+            add_route_cmd = "ip -6 route add %s via %s" % (route.subnet, route.gateway)
+            self.getRouterProcessStatus(vpc_router, add_route_cmd)
+
+        ping_cmd = "ping6 -c 4 %s" % self.virtual_machine_ipv6_address
+        count = 0
+        while count < PING_RETRIES:
+            count = count + 1
+            res = self.getRouterProcessStatus(test_vpc_router, ping_cmd)
+            if " 0% packet loss" in res:
+                break
+            time.sleep(PING_SLEEP)
+        self.assertTrue(" 0% packet loss" in res,
+            "Ping from router %s of VPC %s to VM %s of VPC %s is unsuccessful" % (test_vpc_router.id, self.routing_test_vpc.id, self.virtual_machine.id, self.vpc.id))
+
+        ssh = self.routing_test_vm.get_ssh_client(retries=5)
+        count = 0
+        while count < PING_RETRIES:
+            count = count + 1
+            res = ssh.execute(ping_cmd)
+            if type(res) == list and len(res) > 0 and " 0% packet loss" in '\n'.join(res):
+                break
+            time.sleep(PING_SLEEP)
+        self.assertTrue(type(res) == list and len(res) > 0,
+            "%s on VM %s returned invalid result" % (ping_cmd, self.routing_test_vm.id))
+        self.logger.debug(res)
+        res = '\n'.join(res)
+        self.assertTrue(" 0% packet loss" in res,
+            "Ping from VM %s of VPC %s to VM %s of VPC %s is unsuccessful" % (self.routing_test_vm.id, self.routing_test_vpc.id, self.virtual_machine.id, self.vpc.id))
+
+    def createNetworkAclRule(self, rule, aclid):
+        return NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=aclid
+        )
+
+    def verifyAclRulesInRouter(self, nic, rules, router):
+        for rule in rules:
+            acl_chain = nic + ACL_CHAINS_SUFFIX[rule["traffictype"]]
+            routerCmd = "nft list chain ip6 %s %s" % (ACL_TABLE, acl_chain)
+            res = self.getRouterProcessStatus(router, routerCmd)
+            self.assertTrue(rule["parsedrule"] in res,
+                "Listing firewall rule with nft list chain failure for rule: %s" % rule["parsedrule"])
+
+    def checkIpv6AclRule(self):
+        router = self.getVpcRouter(self.vpc)
+
+        tier1_acl = NetworkACLList.create(
+            self.apiclient,
+            services={},
+            name="tier1_acl",
+            description="tier1_acl",
+            vpcid=self.vpc.id
+        )
+        rules = []
+        # Ingress - ip6 saddr SOURCE_CIDR tcp dport { START_PORT-END_PORT } accept
+        rule = {}
+        rule["traffictype"] = "Ingress"
+        rule["cidrlist"] = self.getRandomIpv6Cidr()
+        rule["protocol"] = "tcp"
+        rule["startport"] = randint(3000, 5000)
+        rule["endport"] = rule["startport"] + randint(1, 8)
+        parsedrule = "ip6 saddr %s %s dport { %d-%d } accept" % (rule["cidrlist"], rule["protocol"], rule["startport"], rule["endport"])
+        rules.append({"traffictype": rule["traffictype"], "parsedrule": parsedrule})
+        self.createNetworkAclRule(rule, tier1_acl.id)
+        # Egress - ip6 daddr DEST_CIDR icmpv6 type TYPE code CODE accept
+        rule = {}
+        rule["traffictype"] = "Egress"
+        rule["cidrlist"] = self.getRandomIpv6Cidr()
+        rule["protocol"] = "icmp"
+        rule["icmptype"] = choice(list(ICMPV6_TYPE.keys()))
+        rule["icmpcode"] = choice(list(ICMPV6_CODE_TYPE.keys()))
+        parsedrule = "ip6 daddr %s %sv6 type %s %sv6 code %s accept" % (rule["cidrlist"], rule["protocol"], ICMPV6_TYPE[rule["icmptype"]], rule["protocol"], ICMPV6_CODE_TYPE[rule["icmpcode"]])
+        rules.append({"traffictype": rule["traffictype"], "parsedrule": parsedrule})
+        self.createNetworkAclRule(rule, tier1_acl.id)
+
+        self.network.replaceACLList(self.apiclient, tier1_acl.id)
+
+        self.verifyAclRulesInRouter("eth2", rules, router)
+
+
+        tier2_acl = NetworkACLList.create(
+            self.apiclient,
+            services={},
+            name="tier2_acl",
+            description="tier2_acl",
+            vpcid=self.vpc.id
+        )
+        rules = []
+        # Ingress - ip6 saddr ::/0 udp dport { 0-65355 } ACTION
+        rule = {}
+        rule["traffictype"] = "Ingress"
+        rule["cidrlist"] = CIDR_IPV6_ANY
+        rule["protocol"] = "udp"
+        parsedrule = "ip6 saddr %s %s dport %s accept" % (rule["cidrlist"], rule["protocol"], TCP_UDP_PORT_ANY)
+        rules.append({"traffictype": rule["traffictype"], "parsedrule": parsedrule})
+        self.createNetworkAclRule(rule, tier2_acl.id)
+        # Egress - ip6 daddr DEST_CIDR icmpv6 type TYPE code CODE accept
+        rule = {}
+        rule["traffictype"] = "Egress"
+        rule["protocol"] = "all"
+        parsedrule = "ip6 daddr %s accept" % (CIDR_IPV6_ANY)
+        rules.append({"traffictype": rule["traffictype"], "parsedrule": parsedrule})
+        self.createNetworkAclRule(rule, tier2_acl.id)
+
+        self.network_offering_tier2 = self.createNetworkTierOfferingInternal(True, False)
+        self.cleanup.append(self.network_offering_tier2)
+        self.tier2_network = self.deployNetworkTierInternal(
+            self.network_offering_tier2.id,
+            self.vpc.id,
+            VPC_DATA["tier2_gateway"],
+            VPC_DATA["tier_netmask"],
+            tier2_acl.id,
+            "tier2"
+        )
+        self.cleanup.append(self.tier2_network)

Review Comment:
   ```suggestion
   ```



##########
test/integration/component/test_vpc_ipv6.py:
##########
@@ -0,0 +1,1036 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT tests for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Vpc, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)
+            #Clean up, terminate the created templates
+            # cleanup_resources(self.apiclient, reversed(self.cleanup))
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    def getRandomIpv6Cidr(self):
+        prefix_length = choice(PREFIX_OPTIONS)
+        random_suffix = getrandbits(40) << (128-prefix_length)
+        base_address = ULA_BASE.network_address + random_suffix
+        return str(IPv6Network((base_address, prefix_length)))
+
+    def createTinyServiceOffering(self):
+        self.service_offering = ServiceOffering.create(
+            self.apiclient,
+            self.services["service_offerings"]["big"],
+        )
+        self.cleanup.append(self.service_offering)
+
+    def createVpcOfferingInternal(self, is_redundant, is_ipv6):
+        off_service = self.services["vpc_offering"]
+        if is_redundant:
+            off_service["serviceCapabilityList"] = {
+                "SourceNat": {
+                    "RedundantRouter": 'true'
+                },
+            }
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        vpc_offering = VpcOffering.create(
+            self.apiclient,
+            off_service
+        )
+        vpc_offering.update(self.apiclient, state='Enabled')
+        return vpc_offering
+
+    def createIpv4VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, False)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOfferingForUpdate(self, is_redundant=False):
+        self.vpc_offering_update = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering_update)
+
+    def createNetworkTierOfferingInternal(self, is_ipv6, remove_lb=True):
+        off_service = self.services["nw_offering_isolated_vpc"]
+        if not remove_lb: # Remove Lb service
+            if "serviceProviderList" in off_service and "Lb" in off_service["serviceProviderList"].keys():
+                providers = off_service["serviceProviderList"]
+                providers.pop("Lb")
+                off_service["serviceProviderList"] = providers
+            if "supportedservices" in off_service and "Lb" in off_service["supportedservices"]:
+                supportedServices = off_service["supportedservices"].split(",")
+                supportedServices.remove("Lb")
+                off_service["supportedservices"] = ",".join(supportedServices)
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        network_offering = NetworkOffering.create(
+            self.apiclient,
+            off_service,
+            conservemode=False
+        )
+        network_offering.update(self.apiclient, state='Enabled')
+        return network_offering
+
+    def createIpv4NetworkTierOffering(self):
+        self.network_offering = self.createNetworkTierOfferingInternal(False)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOffering(self, remove_lb=True):
+        self.network_offering = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOfferingForUpdate(self):
+        self.network_offering_update = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering_update)
+
+    def deployAllowAllVpcInternal(self, cidr):
+        service = self.services["vpc"]
+        service["cidr"] = cidr
+        vpc = VPC.create(
+            self.apiclient,
+            self.services["vpc"],
+            vpcofferingid=self.vpc_offering.id,
+            zoneid=self.zone.id,
+            account=self.account.name,
+            domainid=self.account.domainid
+        )
+        acl = NetworkACLList.create(
+            self.apiclient,
+            services={},
+            name="allowall",
+            description="allowall",
+            vpcid=vpc.id
+        )
+        rule ={
+            "protocol": "all",
+            "traffictype": "ingress",
+        }
+        NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=acl.id
+        )
+        rule["traffictype"] = "egress"
+        NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=acl.id
+        )
+        self.vpcAllowAllAclDetailsMap[vpc.id] = acl.id
+        return vpc
+
+    def deployVpc(self):
+        self.vpc = self.deployAllowAllVpcInternal(VPC_DATA["cidr"])
+        self.cleanup.append(self.vpc)
+
+    def deployNetworkTierInternal(self, network_offering_id, vpc_id, tier_gateway, tier_netmask, acl_id=None, tier_name=None):
+        if not acl_id and vpc_id in self.vpcAllowAllAclDetailsMap:
+            acl_id = self.vpcAllowAllAclDetailsMap[vpc_id]
+        service = self.services["ntwk"]
+        if tier_name:
+            service["name"] = tier_name
+            service["displaytext"] = "vpc-%s" % tier_name
+        network = Network.create(
+            self.apiclient,
+            service,
+            self.account.name,
+            self.account.domainid,
+            networkofferingid=network_offering_id,
+            vpcid=vpc_id,
+            zoneid=self.zone.id,
+            gateway=tier_gateway,
+            netmask=tier_netmask,
+            aclid=acl_id
+        )
+        return network
+
+    def deployNetworkTier(self):
+        self.network = self.deployNetworkTierInternal(
+            self.network_offering.id,
+            self.vpc.id,
+            VPC_DATA["tier1_gateway"],
+            VPC_DATA["tier_netmask"]
+        )
+        self.cleanup.append(self.network)
+
+    def deployNetworkTierVmInternal(self, network):
+        if self.template == FAILED:
+            assert False, "get_test_template() failed to return template"
+        self.services["virtual_machine"]["zoneid"] = self.zone.id
+        virtual_machine = VirtualMachine.create(
+            self.apiclient,
+            self.services["virtual_machine"],
+            templateid=self.template.id,
+            accountid=self.account.name,
+            domainid=self.account.domainid,
+            networkids=network,
+            serviceofferingid=self.service_offering.id
+        )
+        return virtual_machine
+
+    def deployNetworkTierVm(self):
+        self.virtual_machine = self.deployNetworkTierVmInternal(self.network.id)
+        self.cleanup.append(self.virtual_machine)
+
+    def checkIpv6Vpc(self):
+        self.debug("Listing VPC: %s" % (self.vpc.name))
+        ipv6_vpc = VPC.list(self.apiclient,listall="true",id=self.vpc.id)
+        self.assertTrue(
+            isinstance(ipv6_vpc, list),
+            "Check listVpcs response returns a valid list"
+        )
+        self.assertEqual(
+            len(ipv6_vpc),
+            1,
+            "Network not found"
+        )
+        ipv6_vpc = ipv6_vpc[0]
+        self.assertNotEqual(ipv6_vpc.ip6routes,
+                    None,
+                    "IPv6 routes for network is empty")
+
+    def checkIpv6NetworkTierBasic(self):
+        self.debug("Listing network: %s" % (self.network.name))
+        ipv6_network = Network.list(self.apiclient,listall="true",id=self.network.id)
+        self.assertTrue(
+            isinstance(ipv6_network, list),
+            "Check listNetworks response returns a valid list"
+        )
+        self.assertEqual(
+            len(ipv6_network),
+            1,
+            "Network not found"
+        )
+        ipv6_network = ipv6_network[0]
+        self.assertNotEqual(ipv6_network,
+                    None,
+                    "User is not able to retrieve network details %s" % self.network.id)
+        self.assertNotEqual(ipv6_network.ip6cidr,
+                    None,
+                    "IPv6 CIDR for network is empty")
+        self.assertNotEqual(ipv6_network.ip6gateway,
+                    None,
+                    "IPv6 gateway for network is empty")
+        self.assertNotEqual(ipv6_network.ip6routes,
+                    None,
+                    "IPv6 routes for network is empty")
+
+    def checkIpv6VpcRoutersBasic(self):
+        self.debug("Listing routers for VPC: %s" % self.vpc.name)
+        self.routers = Router.list(
+            self.apiclient,
+            vpcid=self.vpc.id,
+            listall=True
+        )
+        self.assertTrue(
+            isinstance(self.routers, list),
+            "Check listRouters response returns a valid list"
+        )
+        self.assertTrue(
+            len(self.routers) > 0,
+            "Router for the network isn't found"
+        )
+        for router in self.routers:
+            self.assertFalse(
+                router.isredundantrouter == True and router.redundantstate == "FAULT",
+                "Router for the network is in FAULT state"
+            )
+            nics = router.nic
+            for nic in nics:
+                if (nic.traffictype == 'Guest' and router.isredundantrouter == False) or nic.traffictype == 'Public':
+                    self.assertNotEqual(nic.ip6address,
+                                None,
+                                "IPv6 address for router %s NIC is empty" % nic.traffictype)
+                    self.assertNotEqual(nic.ip6cidr,
+                                None,
+                                "IPv6 CIDR for router %s NIC is empty" % nic.traffictype)
+                    self.assertNotEqual(nic.ip6gateway,
+                                None,
+                                "IPv6 gateway for router %s NIC is empty" % nic.traffictype)
+
+
+    def getRouterProcessStatus(self, router, cmd):
+        if router.id not in self.routerDetailsMap or self.routerDetailsMap[router.id] is None:
+            connect_ip = self.apiclient.connection.mgtSvr
+            connect_user = self.apiclient.connection.user
+            connect_passwd = self.apiclient.connection.passwd
+            hypervisor = self.hypervisor
+            if self.hypervisor.lower() not in ('vmware', 'hyperv'):
+                hosts = Host.list(
+                    self.apiclient,
+                    zoneid=router.zoneid,
+                    type='Routing',
+                    state='Up',
+                    id=router.hostid
+                )
+                self.assertEqual(
+                    isinstance(hosts, list),
+                    True,
+                    "Check list host returns a valid list"
+                )
+                host = hosts[0]
+                connect_ip = host.ipaddress
+                hypervisor = None
+                try:
+                    connect_user, connect_passwd= get_host_credentials(
+                        self.config, host.ipaddress)
+                except KeyError:
+                    self.skipTest(
+                        "Marvin configuration has no host credentials to\
+                                check router services")
+            details = {}
+            details['connect_ip'] = connect_ip
+            details['connect_user'] = connect_user
+            details['connect_passwd'] = connect_passwd
+            details['hypervisor'] = hypervisor
+            self.routerDetailsMap[router.id] = details
+        result = get_process_status(
+            self.routerDetailsMap[router.id]['connect_ip'],
+            22,
+            self.routerDetailsMap[router.id]['connect_user'],
+            self.routerDetailsMap[router.id]['connect_passwd'],
+            router.linklocalip,
+            cmd,
+            hypervisor=self.routerDetailsMap[router.id]['hypervisor']
+        )
+        self.assertTrue(type(result) == list and len(result) > 0,
+            "%s on router %s returned invalid result" % (cmd, router.id))
+        result = '\n'.join(result)
+        return result
+
+    def getVpcRouter(self, vpc, red_state="PRIMARY"):
+        routers = Router.list(
+            self.apiclient,
+            vpcid=vpc.id,
+            listall=True
+        )
+        self.assertTrue(
+            isinstance(routers, list) and len(routers) > 0,
+            "No routers found for VPC %s" % vpc.id
+        )
+        if len(routers) == 1:
+            return routers[0]
+        for router in routers:
+            if router.redundantstate == red_state:
+                return router
+
+    def getNetworkGateway(self, network):
+        ipv6_network = Network.list(self.apiclient,listall="true",id=network.id)
+        self.assertTrue(
+            isinstance(ipv6_network, list),
+            "Check listNetworks response returns a valid list"
+        )
+        self.assertEqual(
+            len(ipv6_network),
+            1,
+            "Network not found"
+        )
+        ipv6_network = ipv6_network[0]
+        self.assertNotEqual(ipv6_network.ip6gateway,
+                    None,
+                    "IPv6 gateway for network is empty")
+        return ipv6_network.ip6gateway
+
+    def getNetworkRoutes(self, network):
+        ipv6_network = Network.list(self.apiclient,listall="true",id=network.id)
+        self.assertTrue(
+            isinstance(ipv6_network, list),
+            "Check listNetworks response returns a valid list"
+        )
+        self.assertEqual(
+            len(ipv6_network),
+            1,
+            "Network not found"
+        )
+        ipv6_network = ipv6_network[0]
+        self.assertNotEqual(ipv6_network.ip6routes,
+                    None,
+                    "IPv6 routes for network is empty")
+        return ipv6_network.ip6routes
+
+    def isNetworkEgressDefaultPolicyAllow(self, network):
+        ipv6_network = Network.list(self.apiclient,listall="true",id=network.id)
+        if len(ipv6_network) == 1:
+            ipv6_network = ipv6_network[0]
+            return ipv6_network.egressdefaultpolicy
+        return False
+
+    def checkRouterNicState(self, router, dev, state):
+        st = "state %s" % state
+        cmd = "ip link show %s | grep '%s'" % (dev, st)
+        res = self.getRouterProcessStatus(router, cmd)
+        self.assertTrue(type(res) == str and len(res) > 0 and st in res,
+            "%s failed on router %s" % (cmd, router.id))
+
+    def checkIpv6VpcPrimaryRouter(self, router, network_ip6gateway):
+        self.checkRouterNicState(router, VPC_ROUTER_GUEST_NIC, "UP")
+        guest_gateway_check_cmd = "ip -6 address show %s | grep 'inet6 %s'" % (VPC_ROUTER_GUEST_NIC, network_ip6gateway)
+        res = self.getRouterProcessStatus(router, guest_gateway_check_cmd)
+        self.assertTrue(type(res) == str and len(res) > 0 and network_ip6gateway in res,
+            "%s failed on router %s" % (guest_gateway_check_cmd, router.id))
+        self.assertFalse("dadfailed" in res,
+            "dadfailed for IPv6 guest gateway on router %s" % router.id)
+        self.checkRouterNicState(router, VPC_ROUTER_PUBLIC_NIC, "UP")
+        public_ipv6 = None
+        public_ipv6_gateway = None
+        nics = router.nic
+        for nic in nics:
+            if nic.traffictype == 'Public':
+                public_ipv6 = nic.ip6address
+                public_ipv6_gateway = nic.ip6gateway
+                break
+        self.assertNotEqual(public_ipv6,
+            None,
+            "IPv6 address for router Public NIC is empty")
+        public_ip_check_cmd = "ip -6 address show %s | grep 'inet6 %s'" % (VPC_ROUTER_PUBLIC_NIC, public_ipv6)
+        res = self.getRouterProcessStatus(router, public_ip_check_cmd)
+        self.assertTrue(type(res) == str and len(res) > 0 and public_ipv6 in res,
+            "%s failed on router %s" % (public_ip_check_cmd, router.id))
+        self.assertFalse("dadfailed" in res,
+            "dadfailed for public IPv6 on router %s" % router.id)
+        self.assertNotEqual(public_ipv6_gateway,
+            None,
+            "IPv6 gateway for router Public NIC is empty")
+        default_route_check_cmd = "ip -6 route | grep 'default via %s'" % (public_ipv6_gateway)
+        res = self.getRouterProcessStatus(router, default_route_check_cmd)
+        self.assertTrue(type(res) == str and len(res) > 0 and public_ipv6_gateway in res,
+            "%s failed on router %s" % (default_route_check_cmd, router.id))
+
+    def checkIpv6VpcBackupRouter(self, router, network_ip6gateway):
+        self.checkRouterNicState(router, VPC_ROUTER_GUEST_NIC, "UP")
+        guest_gateway_check_cmd = "ip -6 address show %s | grep 'inet6 %s'" % ("eth0", network_ip6gateway)
+        res = self.getRouterProcessStatus(router, guest_gateway_check_cmd)
+        self.assertFalse(type(res) == str and len(res) > 0 and network_ip6gateway in res,
+            "%s failed on router %s" % (guest_gateway_check_cmd, router.id))
+        self.checkRouterNicState(router, VPC_ROUTER_PUBLIC_NIC, "DOWN")
+
+    def checkIpv6VpcRoutersInternal(self):
+        network_ip6gateway = self.getNetworkGateway(self.network)
+        for router in self.routers:
+            if router.state != "Running":
+                continue
+            if router.isredundantrouter == True and router.redundantstate == 'BACKUP':
+                self.checkIpv6VpcBackupRouter(router, network_ip6gateway)
+                continue
+            self.checkIpv6VpcPrimaryRouter(router, network_ip6gateway)
+
+
+    def checkIpv6NetworkTierVm(self):
+        self.debug("Listing NICS for VM %s in network tier: %s" % (self.virtual_machine.name, self.network.name))
+        nics = NIC.list(
+            self.apiclient,
+            virtualmachineid=self.virtual_machine.id,
+            networkid=self.network.id
+        )
+        self.assertEqual(
+            len(nics),
+            1,
+            "VM NIC for the network tier isn't found"
+        )
+        nic = nics[0]
+        self.assertNotEqual(nic.ip6address,
+                    None,
+                    "IPv6 address for VM %s NIC is empty" % nic.traffictype)
+        self.virtual_machine_ipv6_address = nic.ip6address
+        self.assertNotEqual(nic.ip6cidr,
+                    None,
+                    "IPv6 CIDR for VM %s NIC is empty" % nic.traffictype)
+        self.assertNotEqual(nic.ip6gateway,
+                    None,
+                    "IPv6 gateway for VM %s NIC is empty" % nic.traffictype)
+
+    def restartVpcWithCleanup(self):
+        self.vpc.restart(self.apiclient, cleanup=True)
+        time.sleep(SLEEP_BEFORE_VR_CHANGES)
+
+    def updateNetworkTierWithOffering(self):
+        self.network.update(self.apiclient, networkofferingid=self.network_offering_update.id)
+        time.sleep(SLEEP_BEFORE_VR_CHANGES)
+
+    def deployRoutingTestResources(self):
+        self.routing_test_vpc = self.deployAllowAllVpcInternal(ROUTE_TEST_VPC_DATA["cidr"])
+        self.cleanup.append(self.routing_test_vpc)
+        self.routing_test_network_offering = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.routing_test_network_offering)
+        self.routing_test_network = self.deployNetworkTierInternal(
+            self.routing_test_network_offering.id,
+            self.routing_test_vpc.id,
+            ROUTE_TEST_VPC_DATA["tier1_gateway"],
+            ROUTE_TEST_VPC_DATA["tier_netmask"]
+        )
+        self.cleanup.append(self.routing_test_network)
+        self.services["virtual_machine"]["zoneid"] = self.zone.id
+        self.routing_test_vm = VirtualMachine.create(
+            self.apiclient,
+            self.services["virtual_machine"],
+            templateid=self.template.id,
+            accountid=self.account.name,
+            domainid=self.account.domainid,
+            networkids=[self.routing_test_network.id],
+            serviceofferingid=self.service_offering.id,
+            mode="advanced",
+            vpcid=self.routing_test_vpc.id
+        )
+        self.cleanup.append(self.routing_test_vm)

Review Comment:
   why isn´t this one a call to one of the `**Internal()` methods?



##########
test/integration/component/test_vpc_ipv6.py:
##########
@@ -0,0 +1,1036 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT tests for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Vpc, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)
+            #Clean up, terminate the created templates
+            # cleanup_resources(self.apiclient, reversed(self.cleanup))
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    def getRandomIpv6Cidr(self):
+        prefix_length = choice(PREFIX_OPTIONS)
+        random_suffix = getrandbits(40) << (128-prefix_length)
+        base_address = ULA_BASE.network_address + random_suffix
+        return str(IPv6Network((base_address, prefix_length)))
+
+    def createTinyServiceOffering(self):
+        self.service_offering = ServiceOffering.create(
+            self.apiclient,
+            self.services["service_offerings"]["big"],
+        )
+        self.cleanup.append(self.service_offering)
+
+    def createVpcOfferingInternal(self, is_redundant, is_ipv6):
+        off_service = self.services["vpc_offering"]
+        if is_redundant:
+            off_service["serviceCapabilityList"] = {
+                "SourceNat": {
+                    "RedundantRouter": 'true'
+                },
+            }
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        vpc_offering = VpcOffering.create(
+            self.apiclient,
+            off_service
+        )
+        vpc_offering.update(self.apiclient, state='Enabled')
+        return vpc_offering
+
+    def createIpv4VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, False)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOfferingForUpdate(self, is_redundant=False):
+        self.vpc_offering_update = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering_update)
+
+    def createNetworkTierOfferingInternal(self, is_ipv6, remove_lb=True):
+        off_service = self.services["nw_offering_isolated_vpc"]
+        if not remove_lb: # Remove Lb service
+            if "serviceProviderList" in off_service and "Lb" in off_service["serviceProviderList"].keys():
+                providers = off_service["serviceProviderList"]
+                providers.pop("Lb")
+                off_service["serviceProviderList"] = providers
+            if "supportedservices" in off_service and "Lb" in off_service["supportedservices"]:
+                supportedServices = off_service["supportedservices"].split(",")
+                supportedServices.remove("Lb")
+                off_service["supportedservices"] = ",".join(supportedServices)
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        network_offering = NetworkOffering.create(
+            self.apiclient,
+            off_service,
+            conservemode=False
+        )
+        network_offering.update(self.apiclient, state='Enabled')
+        return network_offering
+
+    def createIpv4NetworkTierOffering(self):
+        self.network_offering = self.createNetworkTierOfferingInternal(False)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOffering(self, remove_lb=True):
+        self.network_offering = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOfferingForUpdate(self):
+        self.network_offering_update = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering_update)
+
+    def deployAllowAllVpcInternal(self, cidr):
+        service = self.services["vpc"]
+        service["cidr"] = cidr
+        vpc = VPC.create(
+            self.apiclient,
+            self.services["vpc"],
+            vpcofferingid=self.vpc_offering.id,
+            zoneid=self.zone.id,
+            account=self.account.name,
+            domainid=self.account.domainid
+        )
+        acl = NetworkACLList.create(
+            self.apiclient,
+            services={},
+            name="allowall",
+            description="allowall",
+            vpcid=vpc.id
+        )
+        rule ={
+            "protocol": "all",
+            "traffictype": "ingress",
+        }
+        NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=acl.id
+        )
+        rule["traffictype"] = "egress"
+        NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=acl.id
+        )
+        self.vpcAllowAllAclDetailsMap[vpc.id] = acl.id
+        return vpc
+
+    def deployVpc(self):
+        self.vpc = self.deployAllowAllVpcInternal(VPC_DATA["cidr"])
+        self.cleanup.append(self.vpc)
+
+    def deployNetworkTierInternal(self, network_offering_id, vpc_id, tier_gateway, tier_netmask, acl_id=None, tier_name=None):
+        if not acl_id and vpc_id in self.vpcAllowAllAclDetailsMap:
+            acl_id = self.vpcAllowAllAclDetailsMap[vpc_id]
+        service = self.services["ntwk"]
+        if tier_name:
+            service["name"] = tier_name
+            service["displaytext"] = "vpc-%s" % tier_name
+        network = Network.create(
+            self.apiclient,
+            service,
+            self.account.name,
+            self.account.domainid,
+            networkofferingid=network_offering_id,
+            vpcid=vpc_id,
+            zoneid=self.zone.id,
+            gateway=tier_gateway,
+            netmask=tier_netmask,
+            aclid=acl_id
+        )
+        return network
+
+    def deployNetworkTier(self):
+        self.network = self.deployNetworkTierInternal(
+            self.network_offering.id,
+            self.vpc.id,
+            VPC_DATA["tier1_gateway"],
+            VPC_DATA["tier_netmask"]
+        )
+        self.cleanup.append(self.network)
+
+    def deployNetworkTierVmInternal(self, network):
+        if self.template == FAILED:
+            assert False, "get_test_template() failed to return template"
+        self.services["virtual_machine"]["zoneid"] = self.zone.id
+        virtual_machine = VirtualMachine.create(
+            self.apiclient,
+            self.services["virtual_machine"],
+            templateid=self.template.id,
+            accountid=self.account.name,
+            domainid=self.account.domainid,
+            networkids=network,
+            serviceofferingid=self.service_offering.id
+        )
+        return virtual_machine
+
+    def deployNetworkTierVm(self):
+        self.virtual_machine = self.deployNetworkTierVmInternal(self.network.id)
+        self.cleanup.append(self.virtual_machine)
+
+    def checkIpv6Vpc(self):
+        self.debug("Listing VPC: %s" % (self.vpc.name))
+        ipv6_vpc = VPC.list(self.apiclient,listall="true",id=self.vpc.id)
+        self.assertTrue(
+            isinstance(ipv6_vpc, list),
+            "Check listVpcs response returns a valid list"
+        )
+        self.assertEqual(
+            len(ipv6_vpc),
+            1,
+            "Network not found"
+        )
+        ipv6_vpc = ipv6_vpc[0]
+        self.assertNotEqual(ipv6_vpc.ip6routes,
+                    None,
+                    "IPv6 routes for network is empty")
+
+    def checkIpv6NetworkTierBasic(self):
+        self.debug("Listing network: %s" % (self.network.name))
+        ipv6_network = Network.list(self.apiclient,listall="true",id=self.network.id)
+        self.assertTrue(
+            isinstance(ipv6_network, list),
+            "Check listNetworks response returns a valid list"
+        )
+        self.assertEqual(
+            len(ipv6_network),
+            1,
+            "Network not found"
+        )
+        ipv6_network = ipv6_network[0]
+        self.assertNotEqual(ipv6_network,
+                    None,
+                    "User is not able to retrieve network details %s" % self.network.id)
+        self.assertNotEqual(ipv6_network.ip6cidr,
+                    None,
+                    "IPv6 CIDR for network is empty")
+        self.assertNotEqual(ipv6_network.ip6gateway,
+                    None,
+                    "IPv6 gateway for network is empty")
+        self.assertNotEqual(ipv6_network.ip6routes,
+                    None,
+                    "IPv6 routes for network is empty")
+
+    def checkIpv6VpcRoutersBasic(self):
+        self.debug("Listing routers for VPC: %s" % self.vpc.name)
+        self.routers = Router.list(
+            self.apiclient,
+            vpcid=self.vpc.id,
+            listall=True
+        )
+        self.assertTrue(
+            isinstance(self.routers, list),
+            "Check listRouters response returns a valid list"
+        )
+        self.assertTrue(
+            len(self.routers) > 0,
+            "Router for the network isn't found"
+        )
+        for router in self.routers:
+            self.assertFalse(
+                router.isredundantrouter == True and router.redundantstate == "FAULT",
+                "Router for the network is in FAULT state"
+            )
+            nics = router.nic
+            for nic in nics:
+                if (nic.traffictype == 'Guest' and router.isredundantrouter == False) or nic.traffictype == 'Public':
+                    self.assertNotEqual(nic.ip6address,
+                                None,
+                                "IPv6 address for router %s NIC is empty" % nic.traffictype)
+                    self.assertNotEqual(nic.ip6cidr,
+                                None,
+                                "IPv6 CIDR for router %s NIC is empty" % nic.traffictype)
+                    self.assertNotEqual(nic.ip6gateway,
+                                None,
+                                "IPv6 gateway for router %s NIC is empty" % nic.traffictype)
+
+
+    def getRouterProcessStatus(self, router, cmd):
+        if router.id not in self.routerDetailsMap or self.routerDetailsMap[router.id] is None:
+            connect_ip = self.apiclient.connection.mgtSvr
+            connect_user = self.apiclient.connection.user
+            connect_passwd = self.apiclient.connection.passwd
+            hypervisor = self.hypervisor
+            if self.hypervisor.lower() not in ('vmware', 'hyperv'):
+                hosts = Host.list(
+                    self.apiclient,
+                    zoneid=router.zoneid,
+                    type='Routing',
+                    state='Up',
+                    id=router.hostid
+                )
+                self.assertEqual(
+                    isinstance(hosts, list),
+                    True,
+                    "Check list host returns a valid list"
+                )
+                host = hosts[0]
+                connect_ip = host.ipaddress
+                hypervisor = None
+                try:
+                    connect_user, connect_passwd= get_host_credentials(
+                        self.config, host.ipaddress)
+                except KeyError:
+                    self.skipTest(
+                        "Marvin configuration has no host credentials to\
+                                check router services")
+            details = {}
+            details['connect_ip'] = connect_ip
+            details['connect_user'] = connect_user
+            details['connect_passwd'] = connect_passwd
+            details['hypervisor'] = hypervisor
+            self.routerDetailsMap[router.id] = details
+        result = get_process_status(
+            self.routerDetailsMap[router.id]['connect_ip'],
+            22,
+            self.routerDetailsMap[router.id]['connect_user'],
+            self.routerDetailsMap[router.id]['connect_passwd'],
+            router.linklocalip,
+            cmd,
+            hypervisor=self.routerDetailsMap[router.id]['hypervisor']
+        )
+        self.assertTrue(type(result) == list and len(result) > 0,
+            "%s on router %s returned invalid result" % (cmd, router.id))
+        result = '\n'.join(result)
+        return result
+
+    def getVpcRouter(self, vpc, red_state="PRIMARY"):
+        routers = Router.list(
+            self.apiclient,
+            vpcid=vpc.id,
+            listall=True
+        )
+        self.assertTrue(
+            isinstance(routers, list) and len(routers) > 0,
+            "No routers found for VPC %s" % vpc.id
+        )
+        if len(routers) == 1:
+            return routers[0]
+        for router in routers:
+            if router.redundantstate == red_state:
+                return router
+
+    def getNetworkGateway(self, network):
+        ipv6_network = Network.list(self.apiclient,listall="true",id=network.id)
+        self.assertTrue(
+            isinstance(ipv6_network, list),
+            "Check listNetworks response returns a valid list"
+        )
+        self.assertEqual(
+            len(ipv6_network),
+            1,
+            "Network not found"
+        )
+        ipv6_network = ipv6_network[0]
+        self.assertNotEqual(ipv6_network.ip6gateway,
+                    None,
+                    "IPv6 gateway for network is empty")
+        return ipv6_network.ip6gateway
+
+    def getNetworkRoutes(self, network):
+        ipv6_network = Network.list(self.apiclient,listall="true",id=network.id)
+        self.assertTrue(
+            isinstance(ipv6_network, list),
+            "Check listNetworks response returns a valid list"
+        )
+        self.assertEqual(
+            len(ipv6_network),
+            1,
+            "Network not found"
+        )
+        ipv6_network = ipv6_network[0]
+        self.assertNotEqual(ipv6_network.ip6routes,
+                    None,
+                    "IPv6 routes for network is empty")
+        return ipv6_network.ip6routes
+
+    def isNetworkEgressDefaultPolicyAllow(self, network):
+        ipv6_network = Network.list(self.apiclient,listall="true",id=network.id)
+        if len(ipv6_network) == 1:
+            ipv6_network = ipv6_network[0]
+            return ipv6_network.egressdefaultpolicy
+        return False
+
+    def checkRouterNicState(self, router, dev, state):
+        st = "state %s" % state
+        cmd = "ip link show %s | grep '%s'" % (dev, st)
+        res = self.getRouterProcessStatus(router, cmd)
+        self.assertTrue(type(res) == str and len(res) > 0 and st in res,
+            "%s failed on router %s" % (cmd, router.id))
+
+    def checkIpv6VpcPrimaryRouter(self, router, network_ip6gateway):
+        self.checkRouterNicState(router, VPC_ROUTER_GUEST_NIC, "UP")
+        guest_gateway_check_cmd = "ip -6 address show %s | grep 'inet6 %s'" % (VPC_ROUTER_GUEST_NIC, network_ip6gateway)
+        res = self.getRouterProcessStatus(router, guest_gateway_check_cmd)
+        self.assertTrue(type(res) == str and len(res) > 0 and network_ip6gateway in res,
+            "%s failed on router %s" % (guest_gateway_check_cmd, router.id))
+        self.assertFalse("dadfailed" in res,
+            "dadfailed for IPv6 guest gateway on router %s" % router.id)
+        self.checkRouterNicState(router, VPC_ROUTER_PUBLIC_NIC, "UP")
+        public_ipv6 = None
+        public_ipv6_gateway = None
+        nics = router.nic
+        for nic in nics:
+            if nic.traffictype == 'Public':
+                public_ipv6 = nic.ip6address
+                public_ipv6_gateway = nic.ip6gateway
+                break
+        self.assertNotEqual(public_ipv6,
+            None,
+            "IPv6 address for router Public NIC is empty")
+        public_ip_check_cmd = "ip -6 address show %s | grep 'inet6 %s'" % (VPC_ROUTER_PUBLIC_NIC, public_ipv6)
+        res = self.getRouterProcessStatus(router, public_ip_check_cmd)
+        self.assertTrue(type(res) == str and len(res) > 0 and public_ipv6 in res,
+            "%s failed on router %s" % (public_ip_check_cmd, router.id))
+        self.assertFalse("dadfailed" in res,
+            "dadfailed for public IPv6 on router %s" % router.id)
+        self.assertNotEqual(public_ipv6_gateway,
+            None,
+            "IPv6 gateway for router Public NIC is empty")
+        default_route_check_cmd = "ip -6 route | grep 'default via %s'" % (public_ipv6_gateway)
+        res = self.getRouterProcessStatus(router, default_route_check_cmd)
+        self.assertTrue(type(res) == str and len(res) > 0 and public_ipv6_gateway in res,
+            "%s failed on router %s" % (default_route_check_cmd, router.id))
+
+    def checkIpv6VpcBackupRouter(self, router, network_ip6gateway):
+        self.checkRouterNicState(router, VPC_ROUTER_GUEST_NIC, "UP")
+        guest_gateway_check_cmd = "ip -6 address show %s | grep 'inet6 %s'" % ("eth0", network_ip6gateway)
+        res = self.getRouterProcessStatus(router, guest_gateway_check_cmd)
+        self.assertFalse(type(res) == str and len(res) > 0 and network_ip6gateway in res,
+            "%s failed on router %s" % (guest_gateway_check_cmd, router.id))
+        self.checkRouterNicState(router, VPC_ROUTER_PUBLIC_NIC, "DOWN")
+
+    def checkIpv6VpcRoutersInternal(self):
+        network_ip6gateway = self.getNetworkGateway(self.network)
+        for router in self.routers:
+            if router.state != "Running":
+                continue
+            if router.isredundantrouter == True and router.redundantstate == 'BACKUP':
+                self.checkIpv6VpcBackupRouter(router, network_ip6gateway)
+                continue
+            self.checkIpv6VpcPrimaryRouter(router, network_ip6gateway)
+
+
+    def checkIpv6NetworkTierVm(self):
+        self.debug("Listing NICS for VM %s in network tier: %s" % (self.virtual_machine.name, self.network.name))
+        nics = NIC.list(
+            self.apiclient,
+            virtualmachineid=self.virtual_machine.id,
+            networkid=self.network.id
+        )
+        self.assertEqual(
+            len(nics),
+            1,
+            "VM NIC for the network tier isn't found"
+        )
+        nic = nics[0]
+        self.assertNotEqual(nic.ip6address,
+                    None,
+                    "IPv6 address for VM %s NIC is empty" % nic.traffictype)
+        self.virtual_machine_ipv6_address = nic.ip6address
+        self.assertNotEqual(nic.ip6cidr,
+                    None,
+                    "IPv6 CIDR for VM %s NIC is empty" % nic.traffictype)
+        self.assertNotEqual(nic.ip6gateway,
+                    None,
+                    "IPv6 gateway for VM %s NIC is empty" % nic.traffictype)
+
+    def restartVpcWithCleanup(self):
+        self.vpc.restart(self.apiclient, cleanup=True)
+        time.sleep(SLEEP_BEFORE_VR_CHANGES)
+
+    def updateNetworkTierWithOffering(self):
+        self.network.update(self.apiclient, networkofferingid=self.network_offering_update.id)
+        time.sleep(SLEEP_BEFORE_VR_CHANGES)
+
+    def deployRoutingTestResources(self):
+        self.routing_test_vpc = self.deployAllowAllVpcInternal(ROUTE_TEST_VPC_DATA["cidr"])
+        self.cleanup.append(self.routing_test_vpc)
+        self.routing_test_network_offering = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.routing_test_network_offering)
+        self.routing_test_network = self.deployNetworkTierInternal(
+            self.routing_test_network_offering.id,
+            self.routing_test_vpc.id,
+            ROUTE_TEST_VPC_DATA["tier1_gateway"],
+            ROUTE_TEST_VPC_DATA["tier_netmask"]
+        )
+        self.cleanup.append(self.routing_test_network)
+        self.services["virtual_machine"]["zoneid"] = self.zone.id
+        self.routing_test_vm = VirtualMachine.create(
+            self.apiclient,
+            self.services["virtual_machine"],
+            templateid=self.template.id,
+            accountid=self.account.name,
+            domainid=self.account.domainid,
+            networkids=[self.routing_test_network.id],
+            serviceofferingid=self.service_offering.id,
+            mode="advanced",
+            vpcid=self.routing_test_vpc.id
+        )
+        self.cleanup.append(self.routing_test_vm)
+
+    def prepareRoutingTestResourcesInBackground(self):
+        self.thread = threading.Thread(target=self.deployRoutingTestResources, args=())
+        self.thread.daemon = True
+        self.thread.start()
+
+    def checkVpcRouting(self):
+        if not self.thread:
+            self.deployRoutingTestResources()
+        else:
+            self.thread.join(5*60)
+        self.assertFalse(not self.routing_test_vpc or not self.routing_test_network or not self.routing_test_vm,
+            "Routing resources failure")
+
+        test_vpc_router = self.getVpcRouter(self.routing_test_vpc)
+        routes = self.getNetworkRoutes(self.network)
+        self.logger.debug("Adding vpc routes in routing_test_vpc %s" % routes)
+        for route in routes:
+            add_route_cmd = "ip -6 route add %s via %s" % (route.subnet, route.gateway)
+            self.getRouterProcessStatus(test_vpc_router, add_route_cmd)
+
+        vpc_router = self.getVpcRouter(self.vpc)
+        routes = self.getNetworkRoutes(self.routing_test_network)
+        self.logger.debug("Adding routing_test_vpc routes in vpc %s" % routes)
+        for route in routes:
+            add_route_cmd = "ip -6 route add %s via %s" % (route.subnet, route.gateway)
+            self.getRouterProcessStatus(vpc_router, add_route_cmd)
+
+        ping_cmd = "ping6 -c 4 %s" % self.virtual_machine_ipv6_address
+        count = 0
+        while count < PING_RETRIES:
+            count = count + 1
+            res = self.getRouterProcessStatus(test_vpc_router, ping_cmd)
+            if " 0% packet loss" in res:
+                break
+            time.sleep(PING_SLEEP)
+        self.assertTrue(" 0% packet loss" in res,
+            "Ping from router %s of VPC %s to VM %s of VPC %s is unsuccessful" % (test_vpc_router.id, self.routing_test_vpc.id, self.virtual_machine.id, self.vpc.id))
+
+        ssh = self.routing_test_vm.get_ssh_client(retries=5)
+        count = 0
+        while count < PING_RETRIES:
+            count = count + 1
+            res = ssh.execute(ping_cmd)
+            if type(res) == list and len(res) > 0 and " 0% packet loss" in '\n'.join(res):
+                break
+            time.sleep(PING_SLEEP)
+        self.assertTrue(type(res) == list and len(res) > 0,
+            "%s on VM %s returned invalid result" % (ping_cmd, self.routing_test_vm.id))
+        self.logger.debug(res)
+        res = '\n'.join(res)
+        self.assertTrue(" 0% packet loss" in res,
+            "Ping from VM %s of VPC %s to VM %s of VPC %s is unsuccessful" % (self.routing_test_vm.id, self.routing_test_vpc.id, self.virtual_machine.id, self.vpc.id))
+
+    def createNetworkAclRule(self, rule, aclid):
+        return NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=aclid
+        )
+
+    def verifyAclRulesInRouter(self, nic, rules, router):
+        for rule in rules:
+            acl_chain = nic + ACL_CHAINS_SUFFIX[rule["traffictype"]]
+            routerCmd = "nft list chain ip6 %s %s" % (ACL_TABLE, acl_chain)
+            res = self.getRouterProcessStatus(router, routerCmd)
+            self.assertTrue(rule["parsedrule"] in res,
+                "Listing firewall rule with nft list chain failure for rule: %s" % rule["parsedrule"])
+
+    def checkIpv6AclRule(self):
+        router = self.getVpcRouter(self.vpc)
+
+        tier1_acl = NetworkACLList.create(
+            self.apiclient,
+            services={},
+            name="tier1_acl",
+            description="tier1_acl",
+            vpcid=self.vpc.id
+        )
+        rules = []
+        # Ingress - ip6 saddr SOURCE_CIDR tcp dport { START_PORT-END_PORT } accept
+        rule = {}
+        rule["traffictype"] = "Ingress"
+        rule["cidrlist"] = self.getRandomIpv6Cidr()
+        rule["protocol"] = "tcp"
+        rule["startport"] = randint(3000, 5000)
+        rule["endport"] = rule["startport"] + randint(1, 8)
+        parsedrule = "ip6 saddr %s %s dport { %d-%d } accept" % (rule["cidrlist"], rule["protocol"], rule["startport"], rule["endport"])
+        rules.append({"traffictype": rule["traffictype"], "parsedrule": parsedrule})
+        self.createNetworkAclRule(rule, tier1_acl.id)
+        # Egress - ip6 daddr DEST_CIDR icmpv6 type TYPE code CODE accept
+        rule = {}
+        rule["traffictype"] = "Egress"
+        rule["cidrlist"] = self.getRandomIpv6Cidr()
+        rule["protocol"] = "icmp"
+        rule["icmptype"] = choice(list(ICMPV6_TYPE.keys()))
+        rule["icmpcode"] = choice(list(ICMPV6_CODE_TYPE.keys()))
+        parsedrule = "ip6 daddr %s %sv6 type %s %sv6 code %s accept" % (rule["cidrlist"], rule["protocol"], ICMPV6_TYPE[rule["icmptype"]], rule["protocol"], ICMPV6_CODE_TYPE[rule["icmpcode"]])
+        rules.append({"traffictype": rule["traffictype"], "parsedrule": parsedrule})
+        self.createNetworkAclRule(rule, tier1_acl.id)
+
+        self.network.replaceACLList(self.apiclient, tier1_acl.id)
+
+        self.verifyAclRulesInRouter("eth2", rules, router)
+
+
+        tier2_acl = NetworkACLList.create(
+            self.apiclient,
+            services={},
+            name="tier2_acl",
+            description="tier2_acl",
+            vpcid=self.vpc.id
+        )
+        rules = []
+        # Ingress - ip6 saddr ::/0 udp dport { 0-65355 } ACTION
+        rule = {}
+        rule["traffictype"] = "Ingress"
+        rule["cidrlist"] = CIDR_IPV6_ANY
+        rule["protocol"] = "udp"
+        parsedrule = "ip6 saddr %s %s dport %s accept" % (rule["cidrlist"], rule["protocol"], TCP_UDP_PORT_ANY)
+        rules.append({"traffictype": rule["traffictype"], "parsedrule": parsedrule})
+        self.createNetworkAclRule(rule, tier2_acl.id)
+        # Egress - ip6 daddr DEST_CIDR icmpv6 type TYPE code CODE accept
+        rule = {}
+        rule["traffictype"] = "Egress"
+        rule["protocol"] = "all"
+        parsedrule = "ip6 daddr %s accept" % (CIDR_IPV6_ANY)
+        rules.append({"traffictype": rule["traffictype"], "parsedrule": parsedrule})
+        self.createNetworkAclRule(rule, tier2_acl.id)
+
+        self.network_offering_tier2 = self.createNetworkTierOfferingInternal(True, False)
+        self.cleanup.append(self.network_offering_tier2)

Review Comment:
   ```suggestion
   ```



##########
test/integration/smoke/test_ipv6_infra.py:
##########
@@ -0,0 +1,488 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT tests for IPv6 infra operations"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (cleanup_resources)
+from marvin.lib.base import (Configurations,
+                             NetworkOffering,
+                             VpcOffering,
+                             PublicIpRange)
+from marvin.lib.common import (get_zone)
+from marvin.cloudstackException import CloudstackAPIException
+
+from nose.plugins.attrib import attr
+import logging
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+
+class TestCreateIpv6NetworkVpcOffering(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestCreateIpv6NetworkVpcOffering, cls).getClsTestClient()
+        cls.apiclient = testClient.getApiClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.initial_ipv6_offering_enabled = Configurations.list(
+            cls.apiclient,
+            name=ipv6_offering_config_name)[0].value
+        cls._cleanup = []
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestCreateIpv6NetworkVpcOffering, cls).tearDownClass()
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            #Clean up, terminate the created templates
+            cleanup_resources(self.apiclient, self.cleanup)
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    @attr(
+        tags=[
+            "advanced",
+            "basic",
+            "eip",
+            "sg",
+            "advancedns",
+            "smoke"],
+        required_hardware="false")
+    def test_01_create_ipv6_network_offering(self):
+        """Test to create network offering
+
+        # Validate the following:
+        # 1. createNetworkOffering should return valid info for new offering
+        # 2. The Cloud Database contains the valid information
+        """
+        Configurations.update(self.apiclient,
+            ipv6_offering_config_name,
+            "true")
+        ipv6_service = self.services["network_offering"]
+        ipv6_service["internetprotocol"] = "dualstack"
+        network_offering = NetworkOffering.create(
+            self.apiclient,
+            ipv6_service
+        )
+        self.cleanup.append(network_offering)
+
+        self.debug("Created Network offering with ID: %s" % network_offering.id)
+
+        list_network_off_response = NetworkOffering.list(self.apiclient,
+            id=network_offering.id)
+        self.assertEqual(
+            isinstance(list_network_off_response, list),
+            True,
+            "Check list response returns a valid list"
+        )
+        self.assertNotEqual(
+            len(list_network_off_response),
+            0,
+            "Check Network offering is created"
+        )
+        network_off_response = list_network_off_response[0]
+
+        self.assertEqual(
+            network_off_response.id,
+            network_offering.id,
+            "Check server id in listNetworkOfferings"
+        )
+        self.assertEqual(
+            network_off_response.internetprotocol.lower(),
+            ipv6_service["internetprotocol"].lower(),
+            "Check internetprotocol in listNetworkOfferings"
+        )
+        return
+
+    @attr(
+        tags=[
+            "advanced",
+            "basic",
+            "eip",
+            "sg",
+            "advancedns",
+            "smoke"],
+        required_hardware="false")
+    def test_02_create_ipv6_network_offering_fail(self):
+        """Test to create network offering
+
+        # Validate the following:
+        # 1. createNetworkOffering should fail
+        """
+        Configurations.update(self.apiclient,
+            ipv6_offering_config_name,
+            "false")
+        ipv6_service = self.services["network_offering"]
+        ipv6_service["internetprotocol"] = "dualstack"
+        try:
+            network_offering = NetworkOffering.create(
+                self.apiclient,
+                ipv6_service
+            )
+            self.cleanup.append(network_offering)
+            self.fail("Network offering created despite global setting - %s set to false" % ipv6_offering_config_name)
+        except CloudstackAPIException as e:
+            self.debug("Network offering creation failed as expected %s " % e)
+        return
+
+    @attr(
+        tags=[
+            "advanced",
+            "basic",
+            "eip",
+            "sg",
+            "advancedns",
+            "smoke"],
+        required_hardware="false")
+    def test_03_create_ipv6_vpc_offering(self):
+        """Test to create network offering
+
+        # Validate the following:
+        # 1. createVpcOffering should return valid info for new offering
+        # 2. The Cloud Database contains the valid information
+        """
+        Configurations.update(self.apiclient,
+            ipv6_offering_config_name,
+            "true")
+        ipv6_service = self.services["vpc_offering"]
+        ipv6_service["internetprotocol"] = "dualstack"
+        vpc_offering = VpcOffering.create(
+            self.apiclient,
+            ipv6_service
+        )
+        self.cleanup.append(vpc_offering)
+
+        self.debug("Created VPC offering with ID: %s" % vpc_offering.id)
+
+        list_vpc_off_response = VpcOffering.list(self.apiclient,
+            id=vpc_offering.id)
+        self.assertEqual(
+            isinstance(list_vpc_off_response, list),
+            True,
+            "Check list response returns a valid list"
+        )
+        self.assertNotEqual(
+            len(list_vpc_off_response),
+            0,
+            "Check VPC offering is created"
+        )
+        vpc_off_response = list_vpc_off_response[0]
+        self.assertEqual(
+            vpc_off_response.id,
+            vpc_offering.id,
+            "Check server id in listVpcOfferings"
+        )
+        self.assertEqual(
+            vpc_off_response.internetprotocol.lower(),
+            ipv6_service["internetprotocol"].lower(),
+            "Check internetprotocol in listVpcOfferings"
+        )
+        return
+
+    @attr(
+        tags=[
+            "advanced",
+            "basic",
+            "eip",
+            "sg",
+            "advancedns",
+            "smoke"],
+        required_hardware="false")
+    def test_04_create_ipv6_vpc_offering_fail(self):
+        """Test to create VPC offering failure
+
+        # Validate the following:
+        # 1. createVpcOffering should fail
+        """
+        Configurations.update(self.apiclient,
+            ipv6_offering_config_name,
+            "false")
+        ipv6_service = self.services["vpc_offering"]
+        ipv6_service["internetprotocol"] = "dualstack"
+        try:
+            vpc_offering = VpcOffering.create(
+                self.apiclient,
+                ipv6_service
+            )
+            self.cleanup.append(vpc_offering)
+            self.fail("VPC offering created despite global setting - %s set to false" % ipv6_offering_config_name)
+        except CloudstackAPIException as e:
+            self.debug("VPC offering creation failed as expected %s " % e)
+        return
+
+class TestIpv6PublicIpRange(cloudstackTestCase):
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            #Clean up, terminate the created templates
+            cleanup_resources(self.apiclient, self.cleanup)
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6PublicIpRange, cls).getClsTestClient()
+        cls.apiclient = testClient.getApiClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls._cleanup = []
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        super(TestIpv6PublicIpRange, cls).tearDownClass()
+
+    @attr(
+        tags=[
+            "advanced",
+            "basic",
+            "eip",
+            "sg",
+            "advancedns",
+            "smoke"],
+        required_hardware="false")
+    def test_01_create_ipv6_public_ip_range(self):
+        """Test to add IPv6 public IP range
+
+        # Validate the following:
+        # 1. createVlanIpRange should return valid info for new public range
+        # 2. The Cloud Database contains the valid information
+        """
+        ipv6_publiciprange_service = self.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = self.zone.id
+        ipv6_publiciprange = PublicIpRange.create(
+            self.apiclient,
+            ipv6_publiciprange_service
+        )
+        self.cleanup.append(ipv6_publiciprange)
+
+        self.debug("Created IPv6 public IP range with ID: %s" % ipv6_publiciprange.vlan.id)
+        ipv6_publiciprange = ipv6_publiciprange.vlan
+
+        public_ip_ranges = PublicIpRange.list(
+                    self.apiclient,
+                    id=ipv6_publiciprange.id
+                )
+        self.assertEqual(
+            isinstance(public_ip_ranges, list),
+            True,
+            "Check list response returns a valid list"
+        )
+        self.assertNotEqual(
+            len(public_ip_ranges),
+            0,
+            "Check public IP range is created"
+        )
+        public_ip_range = public_ip_ranges[0]
+
+        self.assertEqual(
+            public_ip_range.id,
+            ipv6_publiciprange.id,
+            "Check server id"
+        )
+        self.assertEqual(
+            public_ip_range.ip6cidr,
+            ipv6_publiciprange_service["ip6cidr"],
+            "Check ip6cidr for IPv6 public IP range"
+        )
+        return
+
+    @attr(
+        tags=[
+            "advanced",
+            "basic",
+            "eip",
+            "sg",
+            "advancedns",
+            "smoke"],
+        required_hardware="false")
+    def test_02_create_ipv6_public_ip_range_fail(self):
+        """Test to add IPv6 public IP range failure
+
+        # Validate the following:
+        # 1. createVlanIpRange should return valid info for new public range
+        # 2. The Cloud Database contains the valid information
+        """
+        ipv6_publiciprange_service = self.services["publicip6range"]
+        cidr = ipv6_publiciprange_service["ip6cidr"]
+        x = cidr.split("/")
+        x[1] = "72"
+        cidr = "/".join(x)
+        ipv6_publiciprange_service["ip6cidr"] = cidr
+        ipv6_publiciprange_service["zoneid"] = self.zone.id
+        try:
+            ipv6_publiciprange = PublicIpRange.create(
+                self.apiclient,
+                ipv6_publiciprange_service
+            )
+        except Exception as e:
+            self.debug("IPv6 public range creation failed as expected %s " % e)
+            ipv6_publiciprange = None
+        if ipv6_publiciprange != None:
+            self.debug("Created IPv6 public range with ID: %s. Deleting it before failure" % ipv6_publiciprange.id)
+            self.cleanup.append(ipv6_publiciprange)
+            self.fail("IPv6 guest prefix created despite CIDR size greater than 64")
+        return
+
+class TestIpv6GuestPrefix(cloudstackTestCase):
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            #Clean up, terminate the created templates
+            cleanup_resources(self.apiclient, self.cleanup)
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return

Review Comment:
   ```suggestion
       def tearDown(self):
           super(TestIpv6GuestPrefix, self).tearDown()
           return
   ```



##########
test/integration/smoke/test_network_ipv6.py:
##########
@@ -665,14 +209,16 @@ def setUp(self):
         self.services = self.testClient.getParsedTestDataConfig()
         self.apiclient = self.testClient.getApiClient()
         self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
         self.cleanup = []
         return
 
     def tearDown(self):
         try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)

Review Comment:
   with this extra code we run the test of the cleanup not being reached. Please see the construct I sugested in other tests to apply it here as well.



##########
test/integration/component/test_vpc_ipv6.py:
##########
@@ -0,0 +1,1036 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT tests for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Vpc, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)
+            #Clean up, terminate the created templates
+            # cleanup_resources(self.apiclient, reversed(self.cleanup))
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    def getRandomIpv6Cidr(self):
+        prefix_length = choice(PREFIX_OPTIONS)
+        random_suffix = getrandbits(40) << (128-prefix_length)
+        base_address = ULA_BASE.network_address + random_suffix
+        return str(IPv6Network((base_address, prefix_length)))
+
+    def createTinyServiceOffering(self):
+        self.service_offering = ServiceOffering.create(
+            self.apiclient,
+            self.services["service_offerings"]["big"],
+        )
+        self.cleanup.append(self.service_offering)
+
+    def createVpcOfferingInternal(self, is_redundant, is_ipv6):
+        off_service = self.services["vpc_offering"]
+        if is_redundant:
+            off_service["serviceCapabilityList"] = {
+                "SourceNat": {
+                    "RedundantRouter": 'true'
+                },
+            }
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        vpc_offering = VpcOffering.create(
+            self.apiclient,
+            off_service
+        )
+        vpc_offering.update(self.apiclient, state='Enabled')
+        return vpc_offering
+
+    def createIpv4VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, False)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOfferingForUpdate(self, is_redundant=False):
+        self.vpc_offering_update = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering_update)
+
+    def createNetworkTierOfferingInternal(self, is_ipv6, remove_lb=True):
+        off_service = self.services["nw_offering_isolated_vpc"]
+        if not remove_lb: # Remove Lb service
+            if "serviceProviderList" in off_service and "Lb" in off_service["serviceProviderList"].keys():
+                providers = off_service["serviceProviderList"]
+                providers.pop("Lb")
+                off_service["serviceProviderList"] = providers
+            if "supportedservices" in off_service and "Lb" in off_service["supportedservices"]:
+                supportedServices = off_service["supportedservices"].split(",")
+                supportedServices.remove("Lb")
+                off_service["supportedservices"] = ",".join(supportedServices)
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        network_offering = NetworkOffering.create(
+            self.apiclient,
+            off_service,
+            conservemode=False
+        )
+        network_offering.update(self.apiclient, state='Enabled')
+        return network_offering
+
+    def createIpv4NetworkTierOffering(self):
+        self.network_offering = self.createNetworkTierOfferingInternal(False)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOffering(self, remove_lb=True):
+        self.network_offering = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOfferingForUpdate(self):
+        self.network_offering_update = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering_update)
+
+    def deployAllowAllVpcInternal(self, cidr):
+        service = self.services["vpc"]
+        service["cidr"] = cidr
+        vpc = VPC.create(
+            self.apiclient,
+            self.services["vpc"],
+            vpcofferingid=self.vpc_offering.id,
+            zoneid=self.zone.id,
+            account=self.account.name,
+            domainid=self.account.domainid
+        )
+        acl = NetworkACLList.create(
+            self.apiclient,
+            services={},
+            name="allowall",
+            description="allowall",
+            vpcid=vpc.id
+        )
+        rule ={
+            "protocol": "all",
+            "traffictype": "ingress",
+        }
+        NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=acl.id
+        )
+        rule["traffictype"] = "egress"
+        NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=acl.id
+        )
+        self.vpcAllowAllAclDetailsMap[vpc.id] = acl.id
+        return vpc
+
+    def deployVpc(self):
+        self.vpc = self.deployAllowAllVpcInternal(VPC_DATA["cidr"])
+        self.cleanup.append(self.vpc)
+
+    def deployNetworkTierInternal(self, network_offering_id, vpc_id, tier_gateway, tier_netmask, acl_id=None, tier_name=None):
+        if not acl_id and vpc_id in self.vpcAllowAllAclDetailsMap:
+            acl_id = self.vpcAllowAllAclDetailsMap[vpc_id]
+        service = self.services["ntwk"]
+        if tier_name:
+            service["name"] = tier_name
+            service["displaytext"] = "vpc-%s" % tier_name
+        network = Network.create(
+            self.apiclient,
+            service,
+            self.account.name,
+            self.account.domainid,
+            networkofferingid=network_offering_id,
+            vpcid=vpc_id,
+            zoneid=self.zone.id,
+            gateway=tier_gateway,
+            netmask=tier_netmask,
+            aclid=acl_id
+        )
+        return network
+
+    def deployNetworkTier(self):
+        self.network = self.deployNetworkTierInternal(
+            self.network_offering.id,
+            self.vpc.id,
+            VPC_DATA["tier1_gateway"],
+            VPC_DATA["tier_netmask"]
+        )
+        self.cleanup.append(self.network)
+
+    def deployNetworkTierVmInternal(self, network):
+        if self.template == FAILED:
+            assert False, "get_test_template() failed to return template"
+        self.services["virtual_machine"]["zoneid"] = self.zone.id
+        virtual_machine = VirtualMachine.create(
+            self.apiclient,
+            self.services["virtual_machine"],
+            templateid=self.template.id,
+            accountid=self.account.name,
+            domainid=self.account.domainid,
+            networkids=network,
+            serviceofferingid=self.service_offering.id
+        )
+        return virtual_machine
+
+    def deployNetworkTierVm(self):
+        self.virtual_machine = self.deployNetworkTierVmInternal(self.network.id)
+        self.cleanup.append(self.virtual_machine)
+
+    def checkIpv6Vpc(self):
+        self.debug("Listing VPC: %s" % (self.vpc.name))
+        ipv6_vpc = VPC.list(self.apiclient,listall="true",id=self.vpc.id)
+        self.assertTrue(
+            isinstance(ipv6_vpc, list),
+            "Check listVpcs response returns a valid list"
+        )
+        self.assertEqual(
+            len(ipv6_vpc),
+            1,
+            "Network not found"
+        )
+        ipv6_vpc = ipv6_vpc[0]
+        self.assertNotEqual(ipv6_vpc.ip6routes,
+                    None,
+                    "IPv6 routes for network is empty")
+
+    def checkIpv6NetworkTierBasic(self):
+        self.debug("Listing network: %s" % (self.network.name))
+        ipv6_network = Network.list(self.apiclient,listall="true",id=self.network.id)
+        self.assertTrue(
+            isinstance(ipv6_network, list),
+            "Check listNetworks response returns a valid list"
+        )
+        self.assertEqual(
+            len(ipv6_network),
+            1,
+            "Network not found"
+        )
+        ipv6_network = ipv6_network[0]
+        self.assertNotEqual(ipv6_network,
+                    None,
+                    "User is not able to retrieve network details %s" % self.network.id)
+        self.assertNotEqual(ipv6_network.ip6cidr,
+                    None,
+                    "IPv6 CIDR for network is empty")
+        self.assertNotEqual(ipv6_network.ip6gateway,
+                    None,
+                    "IPv6 gateway for network is empty")
+        self.assertNotEqual(ipv6_network.ip6routes,
+                    None,
+                    "IPv6 routes for network is empty")
+
+    def checkIpv6VpcRoutersBasic(self):
+        self.debug("Listing routers for VPC: %s" % self.vpc.name)
+        self.routers = Router.list(
+            self.apiclient,
+            vpcid=self.vpc.id,
+            listall=True
+        )
+        self.assertTrue(
+            isinstance(self.routers, list),
+            "Check listRouters response returns a valid list"
+        )
+        self.assertTrue(
+            len(self.routers) > 0,
+            "Router for the network isn't found"
+        )
+        for router in self.routers:
+            self.assertFalse(
+                router.isredundantrouter == True and router.redundantstate == "FAULT",
+                "Router for the network is in FAULT state"
+            )
+            nics = router.nic
+            for nic in nics:
+                if (nic.traffictype == 'Guest' and router.isredundantrouter == False) or nic.traffictype == 'Public':
+                    self.assertNotEqual(nic.ip6address,
+                                None,
+                                "IPv6 address for router %s NIC is empty" % nic.traffictype)
+                    self.assertNotEqual(nic.ip6cidr,
+                                None,
+                                "IPv6 CIDR for router %s NIC is empty" % nic.traffictype)
+                    self.assertNotEqual(nic.ip6gateway,
+                                None,
+                                "IPv6 gateway for router %s NIC is empty" % nic.traffictype)
+
+
+    def getRouterProcessStatus(self, router, cmd):
+        if router.id not in self.routerDetailsMap or self.routerDetailsMap[router.id] is None:
+            connect_ip = self.apiclient.connection.mgtSvr
+            connect_user = self.apiclient.connection.user
+            connect_passwd = self.apiclient.connection.passwd
+            hypervisor = self.hypervisor
+            if self.hypervisor.lower() not in ('vmware', 'hyperv'):
+                hosts = Host.list(
+                    self.apiclient,
+                    zoneid=router.zoneid,
+                    type='Routing',
+                    state='Up',
+                    id=router.hostid
+                )
+                self.assertEqual(
+                    isinstance(hosts, list),
+                    True,
+                    "Check list host returns a valid list"
+                )
+                host = hosts[0]
+                connect_ip = host.ipaddress
+                hypervisor = None
+                try:
+                    connect_user, connect_passwd= get_host_credentials(
+                        self.config, host.ipaddress)
+                except KeyError:
+                    self.skipTest(
+                        "Marvin configuration has no host credentials to\
+                                check router services")
+            details = {}
+            details['connect_ip'] = connect_ip
+            details['connect_user'] = connect_user
+            details['connect_passwd'] = connect_passwd
+            details['hypervisor'] = hypervisor
+            self.routerDetailsMap[router.id] = details
+        result = get_process_status(
+            self.routerDetailsMap[router.id]['connect_ip'],
+            22,
+            self.routerDetailsMap[router.id]['connect_user'],
+            self.routerDetailsMap[router.id]['connect_passwd'],
+            router.linklocalip,
+            cmd,
+            hypervisor=self.routerDetailsMap[router.id]['hypervisor']
+        )
+        self.assertTrue(type(result) == list and len(result) > 0,
+            "%s on router %s returned invalid result" % (cmd, router.id))
+        result = '\n'.join(result)
+        return result
+
+    def getVpcRouter(self, vpc, red_state="PRIMARY"):
+        routers = Router.list(
+            self.apiclient,
+            vpcid=vpc.id,
+            listall=True
+        )
+        self.assertTrue(
+            isinstance(routers, list) and len(routers) > 0,
+            "No routers found for VPC %s" % vpc.id
+        )
+        if len(routers) == 1:
+            return routers[0]
+        for router in routers:
+            if router.redundantstate == red_state:
+                return router
+
+    def getNetworkGateway(self, network):
+        ipv6_network = Network.list(self.apiclient,listall="true",id=network.id)
+        self.assertTrue(
+            isinstance(ipv6_network, list),
+            "Check listNetworks response returns a valid list"
+        )
+        self.assertEqual(
+            len(ipv6_network),
+            1,
+            "Network not found"
+        )
+        ipv6_network = ipv6_network[0]
+        self.assertNotEqual(ipv6_network.ip6gateway,
+                    None,
+                    "IPv6 gateway for network is empty")
+        return ipv6_network.ip6gateway
+
+    def getNetworkRoutes(self, network):
+        ipv6_network = Network.list(self.apiclient,listall="true",id=network.id)
+        self.assertTrue(
+            isinstance(ipv6_network, list),
+            "Check listNetworks response returns a valid list"
+        )
+        self.assertEqual(
+            len(ipv6_network),
+            1,
+            "Network not found"
+        )
+        ipv6_network = ipv6_network[0]
+        self.assertNotEqual(ipv6_network.ip6routes,
+                    None,
+                    "IPv6 routes for network is empty")
+        return ipv6_network.ip6routes
+
+    def isNetworkEgressDefaultPolicyAllow(self, network):
+        ipv6_network = Network.list(self.apiclient,listall="true",id=network.id)
+        if len(ipv6_network) == 1:
+            ipv6_network = ipv6_network[0]
+            return ipv6_network.egressdefaultpolicy
+        return False
+
+    def checkRouterNicState(self, router, dev, state):
+        st = "state %s" % state
+        cmd = "ip link show %s | grep '%s'" % (dev, st)
+        res = self.getRouterProcessStatus(router, cmd)
+        self.assertTrue(type(res) == str and len(res) > 0 and st in res,
+            "%s failed on router %s" % (cmd, router.id))
+
+    def checkIpv6VpcPrimaryRouter(self, router, network_ip6gateway):
+        self.checkRouterNicState(router, VPC_ROUTER_GUEST_NIC, "UP")
+        guest_gateway_check_cmd = "ip -6 address show %s | grep 'inet6 %s'" % (VPC_ROUTER_GUEST_NIC, network_ip6gateway)
+        res = self.getRouterProcessStatus(router, guest_gateway_check_cmd)
+        self.assertTrue(type(res) == str and len(res) > 0 and network_ip6gateway in res,
+            "%s failed on router %s" % (guest_gateway_check_cmd, router.id))
+        self.assertFalse("dadfailed" in res,
+            "dadfailed for IPv6 guest gateway on router %s" % router.id)
+        self.checkRouterNicState(router, VPC_ROUTER_PUBLIC_NIC, "UP")
+        public_ipv6 = None
+        public_ipv6_gateway = None
+        nics = router.nic
+        for nic in nics:
+            if nic.traffictype == 'Public':
+                public_ipv6 = nic.ip6address
+                public_ipv6_gateway = nic.ip6gateway
+                break
+        self.assertNotEqual(public_ipv6,
+            None,
+            "IPv6 address for router Public NIC is empty")
+        public_ip_check_cmd = "ip -6 address show %s | grep 'inet6 %s'" % (VPC_ROUTER_PUBLIC_NIC, public_ipv6)
+        res = self.getRouterProcessStatus(router, public_ip_check_cmd)
+        self.assertTrue(type(res) == str and len(res) > 0 and public_ipv6 in res,
+            "%s failed on router %s" % (public_ip_check_cmd, router.id))
+        self.assertFalse("dadfailed" in res,
+            "dadfailed for public IPv6 on router %s" % router.id)
+        self.assertNotEqual(public_ipv6_gateway,
+            None,
+            "IPv6 gateway for router Public NIC is empty")
+        default_route_check_cmd = "ip -6 route | grep 'default via %s'" % (public_ipv6_gateway)
+        res = self.getRouterProcessStatus(router, default_route_check_cmd)
+        self.assertTrue(type(res) == str and len(res) > 0 and public_ipv6_gateway in res,
+            "%s failed on router %s" % (default_route_check_cmd, router.id))
+
+    def checkIpv6VpcBackupRouter(self, router, network_ip6gateway):
+        self.checkRouterNicState(router, VPC_ROUTER_GUEST_NIC, "UP")
+        guest_gateway_check_cmd = "ip -6 address show %s | grep 'inet6 %s'" % ("eth0", network_ip6gateway)
+        res = self.getRouterProcessStatus(router, guest_gateway_check_cmd)
+        self.assertFalse(type(res) == str and len(res) > 0 and network_ip6gateway in res,
+            "%s failed on router %s" % (guest_gateway_check_cmd, router.id))
+        self.checkRouterNicState(router, VPC_ROUTER_PUBLIC_NIC, "DOWN")
+
+    def checkIpv6VpcRoutersInternal(self):
+        network_ip6gateway = self.getNetworkGateway(self.network)
+        for router in self.routers:
+            if router.state != "Running":
+                continue
+            if router.isredundantrouter == True and router.redundantstate == 'BACKUP':
+                self.checkIpv6VpcBackupRouter(router, network_ip6gateway)
+                continue
+            self.checkIpv6VpcPrimaryRouter(router, network_ip6gateway)
+
+
+    def checkIpv6NetworkTierVm(self):
+        self.debug("Listing NICS for VM %s in network tier: %s" % (self.virtual_machine.name, self.network.name))
+        nics = NIC.list(
+            self.apiclient,
+            virtualmachineid=self.virtual_machine.id,
+            networkid=self.network.id
+        )
+        self.assertEqual(
+            len(nics),
+            1,
+            "VM NIC for the network tier isn't found"
+        )
+        nic = nics[0]
+        self.assertNotEqual(nic.ip6address,
+                    None,
+                    "IPv6 address for VM %s NIC is empty" % nic.traffictype)
+        self.virtual_machine_ipv6_address = nic.ip6address
+        self.assertNotEqual(nic.ip6cidr,
+                    None,
+                    "IPv6 CIDR for VM %s NIC is empty" % nic.traffictype)
+        self.assertNotEqual(nic.ip6gateway,
+                    None,
+                    "IPv6 gateway for VM %s NIC is empty" % nic.traffictype)
+
+    def restartVpcWithCleanup(self):
+        self.vpc.restart(self.apiclient, cleanup=True)
+        time.sleep(SLEEP_BEFORE_VR_CHANGES)
+
+    def updateNetworkTierWithOffering(self):
+        self.network.update(self.apiclient, networkofferingid=self.network_offering_update.id)
+        time.sleep(SLEEP_BEFORE_VR_CHANGES)
+
+    def deployRoutingTestResources(self):
+        self.routing_test_vpc = self.deployAllowAllVpcInternal(ROUTE_TEST_VPC_DATA["cidr"])
+        self.cleanup.append(self.routing_test_vpc)
+        self.routing_test_network_offering = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.routing_test_network_offering)
+        self.routing_test_network = self.deployNetworkTierInternal(
+            self.routing_test_network_offering.id,
+            self.routing_test_vpc.id,
+            ROUTE_TEST_VPC_DATA["tier1_gateway"],
+            ROUTE_TEST_VPC_DATA["tier_netmask"]
+        )
+        self.cleanup.append(self.routing_test_network)
+        self.services["virtual_machine"]["zoneid"] = self.zone.id
+        self.routing_test_vm = VirtualMachine.create(
+            self.apiclient,
+            self.services["virtual_machine"],
+            templateid=self.template.id,
+            accountid=self.account.name,
+            domainid=self.account.domainid,
+            networkids=[self.routing_test_network.id],
+            serviceofferingid=self.service_offering.id,
+            mode="advanced",
+            vpcid=self.routing_test_vpc.id
+        )
+        self.cleanup.append(self.routing_test_vm)
+
+    def prepareRoutingTestResourcesInBackground(self):
+        self.thread = threading.Thread(target=self.deployRoutingTestResources, args=())
+        self.thread.daemon = True
+        self.thread.start()
+
+    def checkVpcRouting(self):
+        if not self.thread:
+            self.deployRoutingTestResources()
+        else:
+            self.thread.join(5*60)
+        self.assertFalse(not self.routing_test_vpc or not self.routing_test_network or not self.routing_test_vm,
+            "Routing resources failure")
+
+        test_vpc_router = self.getVpcRouter(self.routing_test_vpc)
+        routes = self.getNetworkRoutes(self.network)
+        self.logger.debug("Adding vpc routes in routing_test_vpc %s" % routes)
+        for route in routes:
+            add_route_cmd = "ip -6 route add %s via %s" % (route.subnet, route.gateway)
+            self.getRouterProcessStatus(test_vpc_router, add_route_cmd)
+
+        vpc_router = self.getVpcRouter(self.vpc)
+        routes = self.getNetworkRoutes(self.routing_test_network)
+        self.logger.debug("Adding routing_test_vpc routes in vpc %s" % routes)
+        for route in routes:
+            add_route_cmd = "ip -6 route add %s via %s" % (route.subnet, route.gateway)
+            self.getRouterProcessStatus(vpc_router, add_route_cmd)
+
+        ping_cmd = "ping6 -c 4 %s" % self.virtual_machine_ipv6_address
+        count = 0
+        while count < PING_RETRIES:
+            count = count + 1
+            res = self.getRouterProcessStatus(test_vpc_router, ping_cmd)
+            if " 0% packet loss" in res:
+                break
+            time.sleep(PING_SLEEP)
+        self.assertTrue(" 0% packet loss" in res,
+            "Ping from router %s of VPC %s to VM %s of VPC %s is unsuccessful" % (test_vpc_router.id, self.routing_test_vpc.id, self.virtual_machine.id, self.vpc.id))
+
+        ssh = self.routing_test_vm.get_ssh_client(retries=5)
+        count = 0
+        while count < PING_RETRIES:
+            count = count + 1
+            res = ssh.execute(ping_cmd)
+            if type(res) == list and len(res) > 0 and " 0% packet loss" in '\n'.join(res):
+                break
+            time.sleep(PING_SLEEP)
+        self.assertTrue(type(res) == list and len(res) > 0,
+            "%s on VM %s returned invalid result" % (ping_cmd, self.routing_test_vm.id))
+        self.logger.debug(res)
+        res = '\n'.join(res)
+        self.assertTrue(" 0% packet loss" in res,
+            "Ping from VM %s of VPC %s to VM %s of VPC %s is unsuccessful" % (self.routing_test_vm.id, self.routing_test_vpc.id, self.virtual_machine.id, self.vpc.id))
+
+    def createNetworkAclRule(self, rule, aclid):
+        return NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=aclid
+        )
+
+    def verifyAclRulesInRouter(self, nic, rules, router):
+        for rule in rules:
+            acl_chain = nic + ACL_CHAINS_SUFFIX[rule["traffictype"]]
+            routerCmd = "nft list chain ip6 %s %s" % (ACL_TABLE, acl_chain)
+            res = self.getRouterProcessStatus(router, routerCmd)
+            self.assertTrue(rule["parsedrule"] in res,
+                "Listing firewall rule with nft list chain failure for rule: %s" % rule["parsedrule"])
+
+    def checkIpv6AclRule(self):
+        router = self.getVpcRouter(self.vpc)
+
+        tier1_acl = NetworkACLList.create(
+            self.apiclient,
+            services={},
+            name="tier1_acl",
+            description="tier1_acl",
+            vpcid=self.vpc.id
+        )
+        rules = []
+        # Ingress - ip6 saddr SOURCE_CIDR tcp dport { START_PORT-END_PORT } accept
+        rule = {}
+        rule["traffictype"] = "Ingress"
+        rule["cidrlist"] = self.getRandomIpv6Cidr()
+        rule["protocol"] = "tcp"
+        rule["startport"] = randint(3000, 5000)
+        rule["endport"] = rule["startport"] + randint(1, 8)
+        parsedrule = "ip6 saddr %s %s dport { %d-%d } accept" % (rule["cidrlist"], rule["protocol"], rule["startport"], rule["endport"])
+        rules.append({"traffictype": rule["traffictype"], "parsedrule": parsedrule})
+        self.createNetworkAclRule(rule, tier1_acl.id)
+        # Egress - ip6 daddr DEST_CIDR icmpv6 type TYPE code CODE accept
+        rule = {}
+        rule["traffictype"] = "Egress"
+        rule["cidrlist"] = self.getRandomIpv6Cidr()
+        rule["protocol"] = "icmp"
+        rule["icmptype"] = choice(list(ICMPV6_TYPE.keys()))
+        rule["icmpcode"] = choice(list(ICMPV6_CODE_TYPE.keys()))
+        parsedrule = "ip6 daddr %s %sv6 type %s %sv6 code %s accept" % (rule["cidrlist"], rule["protocol"], ICMPV6_TYPE[rule["icmptype"]], rule["protocol"], ICMPV6_CODE_TYPE[rule["icmpcode"]])
+        rules.append({"traffictype": rule["traffictype"], "parsedrule": parsedrule})
+        self.createNetworkAclRule(rule, tier1_acl.id)
+
+        self.network.replaceACLList(self.apiclient, tier1_acl.id)
+
+        self.verifyAclRulesInRouter("eth2", rules, router)
+
+
+        tier2_acl = NetworkACLList.create(
+            self.apiclient,
+            services={},
+            name="tier2_acl",
+            description="tier2_acl",
+            vpcid=self.vpc.id
+        )
+        rules = []
+        # Ingress - ip6 saddr ::/0 udp dport { 0-65355 } ACTION
+        rule = {}
+        rule["traffictype"] = "Ingress"
+        rule["cidrlist"] = CIDR_IPV6_ANY
+        rule["protocol"] = "udp"
+        parsedrule = "ip6 saddr %s %s dport %s accept" % (rule["cidrlist"], rule["protocol"], TCP_UDP_PORT_ANY)
+        rules.append({"traffictype": rule["traffictype"], "parsedrule": parsedrule})
+        self.createNetworkAclRule(rule, tier2_acl.id)
+        # Egress - ip6 daddr DEST_CIDR icmpv6 type TYPE code CODE accept
+        rule = {}
+        rule["traffictype"] = "Egress"
+        rule["protocol"] = "all"
+        parsedrule = "ip6 daddr %s accept" % (CIDR_IPV6_ANY)
+        rules.append({"traffictype": rule["traffictype"], "parsedrule": parsedrule})
+        self.createNetworkAclRule(rule, tier2_acl.id)
+
+        self.network_offering_tier2 = self.createNetworkTierOfferingInternal(True, False)
+        self.cleanup.append(self.network_offering_tier2)
+        self.tier2_network = self.deployNetworkTierInternal(
+            self.network_offering_tier2.id,
+            self.vpc.id,
+            VPC_DATA["tier2_gateway"],
+            VPC_DATA["tier_netmask"],
+            tier2_acl.id,
+            "tier2"
+        )
+        self.cleanup.append(self.tier2_network)
+        self.tier2_vm = self.deployNetworkTierVmInternal(self.tier2_network.id)
+        self.cleanup.append(self.tier2_vm)

Review Comment:
   ```suggestion
   ```



##########
test/integration/smoke/test_vpc_ipv6.py:
##########
@@ -0,0 +1,911 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT test for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Vpc, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)
+            #Clean up, terminate the created templates
+            # cleanup_resources(self.apiclient, reversed(self.cleanup))
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    def getRandomIpv6Cidr(self):
+        prefix_length = choice(PREFIX_OPTIONS)
+        random_suffix = getrandbits(40) << (128-prefix_length)
+        base_address = ULA_BASE.network_address + random_suffix
+        return str(IPv6Network((base_address, prefix_length)))
+
+    def createTinyServiceOffering(self):
+        self.service_offering = ServiceOffering.create(
+            self.apiclient,
+            self.services["service_offerings"]["big"],
+        )
+        self.cleanup.append(self.service_offering)
+
+    def createVpcOfferingInternal(self, is_redundant, is_ipv6):
+        off_service = self.services["vpc_offering"]
+        if is_redundant:
+            off_service["serviceCapabilityList"] = {
+                "SourceNat": {
+                    "RedundantRouter": 'true'
+                },
+            }
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        vpc_offering = VpcOffering.create(
+            self.apiclient,
+            off_service
+        )
+        vpc_offering.update(self.apiclient, state='Enabled')
+        return vpc_offering
+
+    def createIpv4VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, False)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOfferingForUpdate(self, is_redundant=False):
+        self.vpc_offering_update = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering_update)
+
+    def createNetworkTierOfferingInternal(self, is_ipv6, remove_lb=True):
+        off_service = self.services["nw_offering_isolated_vpc"]
+        if not remove_lb: # Remove Lb service
+            if "serviceProviderList" in off_service and "Lb" in off_service["serviceProviderList"].keys():
+                providers = off_service["serviceProviderList"]
+                providers.pop("Lb")
+                off_service["serviceProviderList"] = providers
+            if "supportedservices" in off_service and "Lb" in off_service["supportedservices"]:
+                supportedServices = off_service["supportedservices"].split(",")
+                supportedServices.remove("Lb")
+                off_service["supportedservices"] = ",".join(supportedServices)
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        network_offering = NetworkOffering.create(
+            self.apiclient,
+            off_service,
+            conservemode=False
+        )
+        network_offering.update(self.apiclient, state='Enabled')
+        return network_offering
+
+    def createIpv4NetworkTierOffering(self):
+        self.network_offering = self.createNetworkTierOfferingInternal(False)
+        self.cleanup.append(self.network_offering)

Review Comment:
   ```suggestion
   ```



##########
test/integration/smoke/test_vpc_ipv6.py:
##########
@@ -0,0 +1,911 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT test for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Vpc, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)
+            #Clean up, terminate the created templates
+            # cleanup_resources(self.apiclient, reversed(self.cleanup))
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    def getRandomIpv6Cidr(self):
+        prefix_length = choice(PREFIX_OPTIONS)
+        random_suffix = getrandbits(40) << (128-prefix_length)
+        base_address = ULA_BASE.network_address + random_suffix
+        return str(IPv6Network((base_address, prefix_length)))
+
+    def createTinyServiceOffering(self):
+        self.service_offering = ServiceOffering.create(
+            self.apiclient,
+            self.services["service_offerings"]["big"],
+        )
+        self.cleanup.append(self.service_offering)
+
+    def createVpcOfferingInternal(self, is_redundant, is_ipv6):
+        off_service = self.services["vpc_offering"]
+        if is_redundant:
+            off_service["serviceCapabilityList"] = {
+                "SourceNat": {
+                    "RedundantRouter": 'true'
+                },
+            }
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        vpc_offering = VpcOffering.create(
+            self.apiclient,
+            off_service
+        )
+        vpc_offering.update(self.apiclient, state='Enabled')
+        return vpc_offering
+
+    def createIpv4VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, False)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOfferingForUpdate(self, is_redundant=False):
+        self.vpc_offering_update = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering_update)

Review Comment:
   ```suggestion
   ```



##########
test/integration/smoke/test_vpc_ipv6.py:
##########
@@ -0,0 +1,911 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT test for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Vpc, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)
+            #Clean up, terminate the created templates
+            # cleanup_resources(self.apiclient, reversed(self.cleanup))
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    def getRandomIpv6Cidr(self):
+        prefix_length = choice(PREFIX_OPTIONS)
+        random_suffix = getrandbits(40) << (128-prefix_length)
+        base_address = ULA_BASE.network_address + random_suffix
+        return str(IPv6Network((base_address, prefix_length)))
+
+    def createTinyServiceOffering(self):
+        self.service_offering = ServiceOffering.create(
+            self.apiclient,
+            self.services["service_offerings"]["big"],
+        )
+        self.cleanup.append(self.service_offering)
+
+    def createVpcOfferingInternal(self, is_redundant, is_ipv6):
+        off_service = self.services["vpc_offering"]
+        if is_redundant:
+            off_service["serviceCapabilityList"] = {
+                "SourceNat": {
+                    "RedundantRouter": 'true'
+                },
+            }
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        vpc_offering = VpcOffering.create(
+            self.apiclient,
+            off_service
+        )
+        vpc_offering.update(self.apiclient, state='Enabled')
+        return vpc_offering
+
+    def createIpv4VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, False)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOfferingForUpdate(self, is_redundant=False):
+        self.vpc_offering_update = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering_update)
+
+    def createNetworkTierOfferingInternal(self, is_ipv6, remove_lb=True):
+        off_service = self.services["nw_offering_isolated_vpc"]
+        if not remove_lb: # Remove Lb service
+            if "serviceProviderList" in off_service and "Lb" in off_service["serviceProviderList"].keys():
+                providers = off_service["serviceProviderList"]
+                providers.pop("Lb")
+                off_service["serviceProviderList"] = providers
+            if "supportedservices" in off_service and "Lb" in off_service["supportedservices"]:
+                supportedServices = off_service["supportedservices"].split(",")
+                supportedServices.remove("Lb")
+                off_service["supportedservices"] = ",".join(supportedServices)
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        network_offering = NetworkOffering.create(
+            self.apiclient,
+            off_service,
+            conservemode=False
+        )

Review Comment:
   ```suggestion
           network_offering = NetworkOffering.create(
               self.apiclient,
               off_service,
               conservemode=False
           )
           self.cleanup.append(network_offering)
   ```



##########
test/integration/smoke/test_vpc_ipv6.py:
##########
@@ -0,0 +1,911 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT test for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Vpc, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)
+            #Clean up, terminate the created templates
+            # cleanup_resources(self.apiclient, reversed(self.cleanup))
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    def getRandomIpv6Cidr(self):
+        prefix_length = choice(PREFIX_OPTIONS)
+        random_suffix = getrandbits(40) << (128-prefix_length)
+        base_address = ULA_BASE.network_address + random_suffix
+        return str(IPv6Network((base_address, prefix_length)))
+
+    def createTinyServiceOffering(self):
+        self.service_offering = ServiceOffering.create(
+            self.apiclient,
+            self.services["service_offerings"]["big"],
+        )
+        self.cleanup.append(self.service_offering)
+
+    def createVpcOfferingInternal(self, is_redundant, is_ipv6):
+        off_service = self.services["vpc_offering"]
+        if is_redundant:
+            off_service["serviceCapabilityList"] = {
+                "SourceNat": {
+                    "RedundantRouter": 'true'
+                },
+            }
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        vpc_offering = VpcOffering.create(
+            self.apiclient,
+            off_service
+        )
+        vpc_offering.update(self.apiclient, state='Enabled')
+        return vpc_offering
+
+    def createIpv4VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, False)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOfferingForUpdate(self, is_redundant=False):
+        self.vpc_offering_update = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering_update)
+
+    def createNetworkTierOfferingInternal(self, is_ipv6, remove_lb=True):
+        off_service = self.services["nw_offering_isolated_vpc"]
+        if not remove_lb: # Remove Lb service
+            if "serviceProviderList" in off_service and "Lb" in off_service["serviceProviderList"].keys():
+                providers = off_service["serviceProviderList"]
+                providers.pop("Lb")
+                off_service["serviceProviderList"] = providers
+            if "supportedservices" in off_service and "Lb" in off_service["supportedservices"]:
+                supportedServices = off_service["supportedservices"].split(",")
+                supportedServices.remove("Lb")
+                off_service["supportedservices"] = ",".join(supportedServices)
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        network_offering = NetworkOffering.create(
+            self.apiclient,
+            off_service,
+            conservemode=False
+        )
+        network_offering.update(self.apiclient, state='Enabled')
+        return network_offering
+
+    def createIpv4NetworkTierOffering(self):
+        self.network_offering = self.createNetworkTierOfferingInternal(False)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOffering(self, remove_lb=True):
+        self.network_offering = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOfferingForUpdate(self):
+        self.network_offering_update = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering_update)

Review Comment:
   ```suggestion
   ```



##########
test/integration/smoke/test_vpc_ipv6.py:
##########
@@ -0,0 +1,911 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT test for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Vpc, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)
+            #Clean up, terminate the created templates
+            # cleanup_resources(self.apiclient, reversed(self.cleanup))
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    def getRandomIpv6Cidr(self):
+        prefix_length = choice(PREFIX_OPTIONS)
+        random_suffix = getrandbits(40) << (128-prefix_length)
+        base_address = ULA_BASE.network_address + random_suffix
+        return str(IPv6Network((base_address, prefix_length)))
+
+    def createTinyServiceOffering(self):
+        self.service_offering = ServiceOffering.create(
+            self.apiclient,
+            self.services["service_offerings"]["big"],
+        )
+        self.cleanup.append(self.service_offering)
+
+    def createVpcOfferingInternal(self, is_redundant, is_ipv6):
+        off_service = self.services["vpc_offering"]
+        if is_redundant:
+            off_service["serviceCapabilityList"] = {
+                "SourceNat": {
+                    "RedundantRouter": 'true'
+                },
+            }
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        vpc_offering = VpcOffering.create(
+            self.apiclient,
+            off_service
+        )
+        vpc_offering.update(self.apiclient, state='Enabled')
+        return vpc_offering
+
+    def createIpv4VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, False)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOfferingForUpdate(self, is_redundant=False):
+        self.vpc_offering_update = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering_update)
+
+    def createNetworkTierOfferingInternal(self, is_ipv6, remove_lb=True):
+        off_service = self.services["nw_offering_isolated_vpc"]
+        if not remove_lb: # Remove Lb service
+            if "serviceProviderList" in off_service and "Lb" in off_service["serviceProviderList"].keys():
+                providers = off_service["serviceProviderList"]
+                providers.pop("Lb")
+                off_service["serviceProviderList"] = providers
+            if "supportedservices" in off_service and "Lb" in off_service["supportedservices"]:
+                supportedServices = off_service["supportedservices"].split(",")
+                supportedServices.remove("Lb")
+                off_service["supportedservices"] = ",".join(supportedServices)
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        network_offering = NetworkOffering.create(
+            self.apiclient,
+            off_service,
+            conservemode=False
+        )
+        network_offering.update(self.apiclient, state='Enabled')
+        return network_offering
+
+    def createIpv4NetworkTierOffering(self):
+        self.network_offering = self.createNetworkTierOfferingInternal(False)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOffering(self, remove_lb=True):
+        self.network_offering = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOfferingForUpdate(self):
+        self.network_offering_update = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering_update)
+
+    def deployAllowAllVpcInternal(self, cidr):
+        service = self.services["vpc"]
+        service["cidr"] = cidr
+        vpc = VPC.create(
+            self.apiclient,
+            self.services["vpc"],
+            vpcofferingid=self.vpc_offering.id,
+            zoneid=self.zone.id,
+            account=self.account.name,
+            domainid=self.account.domainid
+        )
+        acl = NetworkACLList.create(
+            self.apiclient,
+            services={},
+            name="allowall",
+            description="allowall",
+            vpcid=vpc.id
+        )
+        rule ={
+            "protocol": "all",
+            "traffictype": "ingress",
+        }
+        NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=acl.id
+        )
+        rule["traffictype"] = "egress"
+        NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=acl.id
+        )
+        self.vpcAllowAllAclDetailsMap[vpc.id] = acl.id
+        return vpc
+
+    def deployVpc(self):
+        self.vpc = self.deployAllowAllVpcInternal(VPC_DATA["cidr"])
+        self.cleanup.append(self.vpc)

Review Comment:
   ```suggestion
   ```



##########
test/integration/smoke/test_vpc_ipv6.py:
##########
@@ -0,0 +1,911 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT test for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Vpc, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)
+            #Clean up, terminate the created templates
+            # cleanup_resources(self.apiclient, reversed(self.cleanup))
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    def getRandomIpv6Cidr(self):
+        prefix_length = choice(PREFIX_OPTIONS)
+        random_suffix = getrandbits(40) << (128-prefix_length)
+        base_address = ULA_BASE.network_address + random_suffix
+        return str(IPv6Network((base_address, prefix_length)))
+
+    def createTinyServiceOffering(self):
+        self.service_offering = ServiceOffering.create(
+            self.apiclient,
+            self.services["service_offerings"]["big"],
+        )
+        self.cleanup.append(self.service_offering)
+
+    def createVpcOfferingInternal(self, is_redundant, is_ipv6):
+        off_service = self.services["vpc_offering"]
+        if is_redundant:
+            off_service["serviceCapabilityList"] = {
+                "SourceNat": {
+                    "RedundantRouter": 'true'
+                },
+            }
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        vpc_offering = VpcOffering.create(
+            self.apiclient,
+            off_service
+        )
+        vpc_offering.update(self.apiclient, state='Enabled')
+        return vpc_offering
+
+    def createIpv4VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, False)
+        self.cleanup.append(self.vpc_offering)

Review Comment:
   ```suggestion
   ```



##########
test/integration/smoke/test_vpc_ipv6.py:
##########
@@ -0,0 +1,911 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT test for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Vpc, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)
+            #Clean up, terminate the created templates
+            # cleanup_resources(self.apiclient, reversed(self.cleanup))
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    def getRandomIpv6Cidr(self):
+        prefix_length = choice(PREFIX_OPTIONS)
+        random_suffix = getrandbits(40) << (128-prefix_length)
+        base_address = ULA_BASE.network_address + random_suffix
+        return str(IPv6Network((base_address, prefix_length)))
+
+    def createTinyServiceOffering(self):
+        self.service_offering = ServiceOffering.create(
+            self.apiclient,
+            self.services["service_offerings"]["big"],
+        )
+        self.cleanup.append(self.service_offering)
+
+    def createVpcOfferingInternal(self, is_redundant, is_ipv6):
+        off_service = self.services["vpc_offering"]
+        if is_redundant:
+            off_service["serviceCapabilityList"] = {
+                "SourceNat": {
+                    "RedundantRouter": 'true'
+                },
+            }
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        vpc_offering = VpcOffering.create(
+            self.apiclient,
+            off_service
+        )
+        vpc_offering.update(self.apiclient, state='Enabled')
+        return vpc_offering
+
+    def createIpv4VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, False)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOfferingForUpdate(self, is_redundant=False):
+        self.vpc_offering_update = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering_update)
+
+    def createNetworkTierOfferingInternal(self, is_ipv6, remove_lb=True):
+        off_service = self.services["nw_offering_isolated_vpc"]
+        if not remove_lb: # Remove Lb service
+            if "serviceProviderList" in off_service and "Lb" in off_service["serviceProviderList"].keys():
+                providers = off_service["serviceProviderList"]
+                providers.pop("Lb")
+                off_service["serviceProviderList"] = providers
+            if "supportedservices" in off_service and "Lb" in off_service["supportedservices"]:
+                supportedServices = off_service["supportedservices"].split(",")
+                supportedServices.remove("Lb")
+                off_service["supportedservices"] = ",".join(supportedServices)
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        network_offering = NetworkOffering.create(
+            self.apiclient,
+            off_service,
+            conservemode=False
+        )
+        network_offering.update(self.apiclient, state='Enabled')
+        return network_offering
+
+    def createIpv4NetworkTierOffering(self):
+        self.network_offering = self.createNetworkTierOfferingInternal(False)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOffering(self, remove_lb=True):
+        self.network_offering = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOfferingForUpdate(self):
+        self.network_offering_update = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering_update)
+
+    def deployAllowAllVpcInternal(self, cidr):
+        service = self.services["vpc"]
+        service["cidr"] = cidr
+        vpc = VPC.create(
+            self.apiclient,
+            self.services["vpc"],
+            vpcofferingid=self.vpc_offering.id,
+            zoneid=self.zone.id,
+            account=self.account.name,
+            domainid=self.account.domainid
+        )

Review Comment:
   ```suggestion
           vpc = VPC.create(
               self.apiclient,
               self.services["vpc"],
               vpcofferingid=self.vpc_offering.id,
               zoneid=self.zone.id,
               account=self.account.name,
               domainid=self.account.domainid
           )
           self.cleanup.append(vpc)
   ```



##########
test/integration/smoke/test_vpc_ipv6.py:
##########
@@ -0,0 +1,911 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT test for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Vpc, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)

Review Comment:
   ```suggestion
       def tearDownClass(cls):
           try:
               if cls.initial_ipv6_offering_enabled != None:
                   Configurations.update(cls.apiclient,
                        ipv6_offering_config_name,
                        cls.initial_ipv6_offering_enabled)
           finally:
               super(TestIpv6Vpc, cls).tearDownClass()
           if cls.test_ipv6_guestprefix != None:
               cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
               cmd.id = cls.test_ipv6_guestprefix.id
               cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
   ```
   
   should GuestNetworkIpv6Prefix be added as class in base.py?



##########
test/integration/smoke/test_vpc_ipv6.py:
##########
@@ -0,0 +1,911 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT test for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Vpc, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)
+            #Clean up, terminate the created templates
+            # cleanup_resources(self.apiclient, reversed(self.cleanup))
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    def getRandomIpv6Cidr(self):
+        prefix_length = choice(PREFIX_OPTIONS)
+        random_suffix = getrandbits(40) << (128-prefix_length)
+        base_address = ULA_BASE.network_address + random_suffix
+        return str(IPv6Network((base_address, prefix_length)))
+
+    def createTinyServiceOffering(self):
+        self.service_offering = ServiceOffering.create(
+            self.apiclient,
+            self.services["service_offerings"]["big"],
+        )
+        self.cleanup.append(self.service_offering)
+
+    def createVpcOfferingInternal(self, is_redundant, is_ipv6):
+        off_service = self.services["vpc_offering"]
+        if is_redundant:
+            off_service["serviceCapabilityList"] = {
+                "SourceNat": {
+                    "RedundantRouter": 'true'
+                },
+            }
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        vpc_offering = VpcOffering.create(
+            self.apiclient,
+            off_service
+        )
+        vpc_offering.update(self.apiclient, state='Enabled')
+        return vpc_offering
+
+    def createIpv4VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, False)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOfferingForUpdate(self, is_redundant=False):
+        self.vpc_offering_update = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering_update)
+
+    def createNetworkTierOfferingInternal(self, is_ipv6, remove_lb=True):
+        off_service = self.services["nw_offering_isolated_vpc"]
+        if not remove_lb: # Remove Lb service
+            if "serviceProviderList" in off_service and "Lb" in off_service["serviceProviderList"].keys():
+                providers = off_service["serviceProviderList"]
+                providers.pop("Lb")
+                off_service["serviceProviderList"] = providers
+            if "supportedservices" in off_service and "Lb" in off_service["supportedservices"]:
+                supportedServices = off_service["supportedservices"].split(",")
+                supportedServices.remove("Lb")
+                off_service["supportedservices"] = ",".join(supportedServices)
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        network_offering = NetworkOffering.create(
+            self.apiclient,
+            off_service,
+            conservemode=False
+        )
+        network_offering.update(self.apiclient, state='Enabled')
+        return network_offering
+
+    def createIpv4NetworkTierOffering(self):
+        self.network_offering = self.createNetworkTierOfferingInternal(False)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOffering(self, remove_lb=True):
+        self.network_offering = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOfferingForUpdate(self):
+        self.network_offering_update = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering_update)
+
+    def deployAllowAllVpcInternal(self, cidr):
+        service = self.services["vpc"]
+        service["cidr"] = cidr
+        vpc = VPC.create(
+            self.apiclient,
+            self.services["vpc"],
+            vpcofferingid=self.vpc_offering.id,
+            zoneid=self.zone.id,
+            account=self.account.name,
+            domainid=self.account.domainid
+        )
+        acl = NetworkACLList.create(
+            self.apiclient,
+            services={},
+            name="allowall",
+            description="allowall",
+            vpcid=vpc.id
+        )
+        rule ={
+            "protocol": "all",
+            "traffictype": "ingress",
+        }
+        NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=acl.id
+        )
+        rule["traffictype"] = "egress"
+        NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=acl.id
+        )
+        self.vpcAllowAllAclDetailsMap[vpc.id] = acl.id
+        return vpc
+
+    def deployVpc(self):
+        self.vpc = self.deployAllowAllVpcInternal(VPC_DATA["cidr"])
+        self.cleanup.append(self.vpc)
+
+    def deployNetworkTierInternal(self, network_offering_id, vpc_id, tier_gateway, tier_netmask, acl_id=None, tier_name=None):
+        if not acl_id and vpc_id in self.vpcAllowAllAclDetailsMap:
+            acl_id = self.vpcAllowAllAclDetailsMap[vpc_id]
+        service = self.services["ntwk"]
+        if tier_name:
+            service["name"] = tier_name
+            service["displaytext"] = "vpc-%s" % tier_name
+        network = Network.create(
+            self.apiclient,
+            service,
+            self.account.name,
+            self.account.domainid,
+            networkofferingid=network_offering_id,
+            vpcid=vpc_id,
+            zoneid=self.zone.id,
+            gateway=tier_gateway,
+            netmask=tier_netmask,
+            aclid=acl_id
+        )

Review Comment:
   ```suggestion
           network = Network.create(
               self.apiclient,
               service,
               self.account.name,
               self.account.domainid,
               networkofferingid=network_offering_id,
               vpcid=vpc_id,
               zoneid=self.zone.id,
               gateway=tier_gateway,
               netmask=tier_netmask,
               aclid=acl_id
           )
           self.cleanup.append(network)
   ```



##########
test/integration/smoke/test_vpc_ipv6.py:
##########
@@ -0,0 +1,911 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT test for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Vpc, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)
+            #Clean up, terminate the created templates
+            # cleanup_resources(self.apiclient, reversed(self.cleanup))
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    def getRandomIpv6Cidr(self):
+        prefix_length = choice(PREFIX_OPTIONS)
+        random_suffix = getrandbits(40) << (128-prefix_length)
+        base_address = ULA_BASE.network_address + random_suffix
+        return str(IPv6Network((base_address, prefix_length)))
+
+    def createTinyServiceOffering(self):
+        self.service_offering = ServiceOffering.create(
+            self.apiclient,
+            self.services["service_offerings"]["big"],
+        )
+        self.cleanup.append(self.service_offering)
+
+    def createVpcOfferingInternal(self, is_redundant, is_ipv6):
+        off_service = self.services["vpc_offering"]
+        if is_redundant:
+            off_service["serviceCapabilityList"] = {
+                "SourceNat": {
+                    "RedundantRouter": 'true'
+                },
+            }
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        vpc_offering = VpcOffering.create(
+            self.apiclient,
+            off_service
+        )
+        vpc_offering.update(self.apiclient, state='Enabled')
+        return vpc_offering
+
+    def createIpv4VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, False)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOfferingForUpdate(self, is_redundant=False):
+        self.vpc_offering_update = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering_update)
+
+    def createNetworkTierOfferingInternal(self, is_ipv6, remove_lb=True):
+        off_service = self.services["nw_offering_isolated_vpc"]
+        if not remove_lb: # Remove Lb service
+            if "serviceProviderList" in off_service and "Lb" in off_service["serviceProviderList"].keys():
+                providers = off_service["serviceProviderList"]
+                providers.pop("Lb")
+                off_service["serviceProviderList"] = providers
+            if "supportedservices" in off_service and "Lb" in off_service["supportedservices"]:
+                supportedServices = off_service["supportedservices"].split(",")
+                supportedServices.remove("Lb")
+                off_service["supportedservices"] = ",".join(supportedServices)
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        network_offering = NetworkOffering.create(
+            self.apiclient,
+            off_service,
+            conservemode=False
+        )
+        network_offering.update(self.apiclient, state='Enabled')
+        return network_offering
+
+    def createIpv4NetworkTierOffering(self):
+        self.network_offering = self.createNetworkTierOfferingInternal(False)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOffering(self, remove_lb=True):
+        self.network_offering = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOfferingForUpdate(self):
+        self.network_offering_update = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering_update)
+
+    def deployAllowAllVpcInternal(self, cidr):
+        service = self.services["vpc"]
+        service["cidr"] = cidr
+        vpc = VPC.create(
+            self.apiclient,
+            self.services["vpc"],
+            vpcofferingid=self.vpc_offering.id,
+            zoneid=self.zone.id,
+            account=self.account.name,
+            domainid=self.account.domainid
+        )
+        acl = NetworkACLList.create(
+            self.apiclient,
+            services={},
+            name="allowall",
+            description="allowall",
+            vpcid=vpc.id
+        )
+        rule ={
+            "protocol": "all",
+            "traffictype": "ingress",
+        }
+        NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=acl.id
+        )
+        rule["traffictype"] = "egress"
+        NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=acl.id
+        )
+        self.vpcAllowAllAclDetailsMap[vpc.id] = acl.id
+        return vpc
+
+    def deployVpc(self):
+        self.vpc = self.deployAllowAllVpcInternal(VPC_DATA["cidr"])
+        self.cleanup.append(self.vpc)
+
+    def deployNetworkTierInternal(self, network_offering_id, vpc_id, tier_gateway, tier_netmask, acl_id=None, tier_name=None):
+        if not acl_id and vpc_id in self.vpcAllowAllAclDetailsMap:
+            acl_id = self.vpcAllowAllAclDetailsMap[vpc_id]
+        service = self.services["ntwk"]
+        if tier_name:
+            service["name"] = tier_name
+            service["displaytext"] = "vpc-%s" % tier_name
+        network = Network.create(
+            self.apiclient,
+            service,
+            self.account.name,
+            self.account.domainid,
+            networkofferingid=network_offering_id,
+            vpcid=vpc_id,
+            zoneid=self.zone.id,
+            gateway=tier_gateway,
+            netmask=tier_netmask,
+            aclid=acl_id
+        )
+        return network
+
+    def deployNetworkTier(self):
+        self.network = self.deployNetworkTierInternal(
+            self.network_offering.id,
+            self.vpc.id,
+            VPC_DATA["tier1_gateway"],
+            VPC_DATA["tier_netmask"]
+        )
+        self.cleanup.append(self.network)
+
+    def deployNetworkTierVmInternal(self, network):
+        if self.template == FAILED:
+            assert False, "get_test_template() failed to return template"
+        self.services["virtual_machine"]["zoneid"] = self.zone.id
+        virtual_machine = VirtualMachine.create(
+            self.apiclient,
+            self.services["virtual_machine"],
+            templateid=self.template.id,
+            accountid=self.account.name,
+            domainid=self.account.domainid,
+            networkids=network,
+            serviceofferingid=self.service_offering.id
+        )
+        return virtual_machine
+
+    def deployNetworkTierVm(self):
+        self.virtual_machine = self.deployNetworkTierVmInternal(self.network.id)
+        self.cleanup.append(self.virtual_machine)
+
+    def checkIpv6Vpc(self):
+        self.debug("Listing VPC: %s" % (self.vpc.name))
+        ipv6_vpc = VPC.list(self.apiclient,listall="true",id=self.vpc.id)
+        self.assertTrue(
+            isinstance(ipv6_vpc, list),
+            "Check listVpcs response returns a valid list"
+        )
+        self.assertEqual(
+            len(ipv6_vpc),
+            1,
+            "Network not found"
+        )
+        ipv6_vpc = ipv6_vpc[0]
+        self.assertNotEqual(ipv6_vpc.ip6routes,
+                    None,
+                    "IPv6 routes for network is empty")
+
+    def checkIpv6NetworkTierBasic(self):
+        self.debug("Listing network: %s" % (self.network.name))
+        ipv6_network = Network.list(self.apiclient,listall="true",id=self.network.id)
+        self.assertTrue(
+            isinstance(ipv6_network, list),
+            "Check listNetworks response returns a valid list"
+        )
+        self.assertEqual(
+            len(ipv6_network),
+            1,
+            "Network not found"
+        )
+        ipv6_network = ipv6_network[0]
+        self.assertNotEqual(ipv6_network,
+                    None,
+                    "User is not able to retrieve network details %s" % self.network.id)
+        self.assertNotEqual(ipv6_network.ip6cidr,
+                    None,
+                    "IPv6 CIDR for network is empty")
+        self.assertNotEqual(ipv6_network.ip6gateway,
+                    None,
+                    "IPv6 gateway for network is empty")
+        self.assertNotEqual(ipv6_network.ip6routes,
+                    None,
+                    "IPv6 routes for network is empty")
+
+    def checkIpv6VpcRoutersBasic(self):
+        self.debug("Listing routers for VPC: %s" % self.vpc.name)
+        self.routers = Router.list(
+            self.apiclient,
+            vpcid=self.vpc.id,
+            listall=True
+        )
+        self.assertTrue(
+            isinstance(self.routers, list),
+            "Check listRouters response returns a valid list"
+        )
+        self.assertTrue(
+            len(self.routers) > 0,
+            "Router for the network isn't found"
+        )
+        for router in self.routers:
+            self.assertFalse(
+                router.isredundantrouter == True and router.redundantstate == "FAULT",
+                "Router for the network is in FAULT state"
+            )
+            nics = router.nic
+            for nic in nics:
+                if (nic.traffictype == 'Guest' and router.isredundantrouter == False) or nic.traffictype == 'Public':
+                    self.assertNotEqual(nic.ip6address,
+                                None,
+                                "IPv6 address for router %s NIC is empty" % nic.traffictype)
+                    self.assertNotEqual(nic.ip6cidr,
+                                None,
+                                "IPv6 CIDR for router %s NIC is empty" % nic.traffictype)
+                    self.assertNotEqual(nic.ip6gateway,
+                                None,
+                                "IPv6 gateway for router %s NIC is empty" % nic.traffictype)
+
+
+    def getRouterProcessStatus(self, router, cmd):
+        if router.id not in self.routerDetailsMap or self.routerDetailsMap[router.id] is None:
+            connect_ip = self.apiclient.connection.mgtSvr
+            connect_user = self.apiclient.connection.user
+            connect_passwd = self.apiclient.connection.passwd
+            hypervisor = self.hypervisor
+            if self.hypervisor.lower() not in ('vmware', 'hyperv'):
+                hosts = Host.list(
+                    self.apiclient,
+                    zoneid=router.zoneid,
+                    type='Routing',
+                    state='Up',
+                    id=router.hostid
+                )
+                self.assertEqual(
+                    isinstance(hosts, list),
+                    True,
+                    "Check list host returns a valid list"
+                )
+                host = hosts[0]
+                connect_ip = host.ipaddress
+                hypervisor = None
+                try:
+                    connect_user, connect_passwd= get_host_credentials(
+                        self.config, host.ipaddress)
+                except KeyError:
+                    self.skipTest(
+                        "Marvin configuration has no host credentials to\
+                                check router services")
+            details = {}
+            details['connect_ip'] = connect_ip
+            details['connect_user'] = connect_user
+            details['connect_passwd'] = connect_passwd
+            details['hypervisor'] = hypervisor
+            self.routerDetailsMap[router.id] = details
+        result = get_process_status(
+            self.routerDetailsMap[router.id]['connect_ip'],
+            22,
+            self.routerDetailsMap[router.id]['connect_user'],
+            self.routerDetailsMap[router.id]['connect_passwd'],
+            router.linklocalip,
+            cmd,
+            hypervisor=self.routerDetailsMap[router.id]['hypervisor']
+        )
+        self.assertTrue(type(result) == list and len(result) > 0,
+            "%s on router %s returned invalid result" % (cmd, router.id))
+        result = '\n'.join(result)
+        return result
+
+    def getVpcRouter(self, vpc, red_state="PRIMARY"):
+        routers = Router.list(
+            self.apiclient,
+            vpcid=vpc.id,
+            listall=True
+        )
+        self.assertTrue(
+            isinstance(routers, list) and len(routers) > 0,
+            "No routers found for VPC %s" % vpc.id
+        )
+        if len(routers) == 1:
+            return routers[0]
+        for router in routers:
+            if router.redundantstate == red_state:
+                return router
+
+    def getNetworkGateway(self, network):
+        ipv6_network = Network.list(self.apiclient,listall="true",id=network.id)
+        self.assertTrue(
+            isinstance(ipv6_network, list),
+            "Check listNetworks response returns a valid list"
+        )
+        self.assertEqual(
+            len(ipv6_network),
+            1,
+            "Network not found"
+        )
+        ipv6_network = ipv6_network[0]
+        self.assertNotEqual(ipv6_network.ip6gateway,
+                    None,
+                    "IPv6 gateway for network is empty")
+        return ipv6_network.ip6gateway
+
+    def getNetworkRoutes(self, network):
+        ipv6_network = Network.list(self.apiclient,listall="true",id=network.id)
+        self.assertTrue(
+            isinstance(ipv6_network, list),
+            "Check listNetworks response returns a valid list"
+        )
+        self.assertEqual(
+            len(ipv6_network),
+            1,
+            "Network not found"
+        )
+        ipv6_network = ipv6_network[0]
+        self.assertNotEqual(ipv6_network.ip6routes,
+                    None,
+                    "IPv6 routes for network is empty")
+        return ipv6_network.ip6routes
+
+    def isNetworkEgressDefaultPolicyAllow(self, network):
+        ipv6_network = Network.list(self.apiclient,listall="true",id=network.id)
+        if len(ipv6_network) == 1:
+            ipv6_network = ipv6_network[0]
+            return ipv6_network.egressdefaultpolicy
+        return False
+
+    def checkRouterNicState(self, router, dev, state):
+        st = "state %s" % state
+        cmd = "ip link show %s | grep '%s'" % (dev, st)
+        res = self.getRouterProcessStatus(router, cmd)
+        self.assertTrue(type(res) == str and len(res) > 0 and st in res,
+            "%s failed on router %s" % (cmd, router.id))
+
+    def checkIpv6VpcPrimaryRouter(self, router, network_ip6gateway):
+        self.checkRouterNicState(router, VPC_ROUTER_GUEST_NIC, "UP")
+        guest_gateway_check_cmd = "ip -6 address show %s | grep 'inet6 %s'" % (VPC_ROUTER_GUEST_NIC, network_ip6gateway)
+        res = self.getRouterProcessStatus(router, guest_gateway_check_cmd)
+        self.assertTrue(type(res) == str and len(res) > 0 and network_ip6gateway in res,
+            "%s failed on router %s" % (guest_gateway_check_cmd, router.id))
+        self.assertFalse("dadfailed" in res,
+            "dadfailed for IPv6 guest gateway on router %s" % router.id)
+        self.checkRouterNicState(router, VPC_ROUTER_PUBLIC_NIC, "UP")
+        public_ipv6 = None
+        public_ipv6_gateway = None
+        nics = router.nic
+        for nic in nics:
+            if nic.traffictype == 'Public':
+                public_ipv6 = nic.ip6address
+                public_ipv6_gateway = nic.ip6gateway
+                break
+        self.assertNotEqual(public_ipv6,
+            None,
+            "IPv6 address for router Public NIC is empty")
+        public_ip_check_cmd = "ip -6 address show %s | grep 'inet6 %s'" % (VPC_ROUTER_PUBLIC_NIC, public_ipv6)
+        res = self.getRouterProcessStatus(router, public_ip_check_cmd)
+        self.assertTrue(type(res) == str and len(res) > 0 and public_ipv6 in res,
+            "%s failed on router %s" % (public_ip_check_cmd, router.id))
+        self.assertFalse("dadfailed" in res,
+            "dadfailed for public IPv6 on router %s" % router.id)
+        self.assertNotEqual(public_ipv6_gateway,
+            None,
+            "IPv6 gateway for router Public NIC is empty")
+        default_route_check_cmd = "ip -6 route | grep 'default via %s'" % (public_ipv6_gateway)
+        res = self.getRouterProcessStatus(router, default_route_check_cmd)
+        self.assertTrue(type(res) == str and len(res) > 0 and public_ipv6_gateway in res,
+            "%s failed on router %s" % (default_route_check_cmd, router.id))
+
+    def checkIpv6VpcBackupRouter(self, router, network_ip6gateway):
+        self.checkRouterNicState(router, VPC_ROUTER_GUEST_NIC, "UP")
+        guest_gateway_check_cmd = "ip -6 address show %s | grep 'inet6 %s'" % ("eth0", network_ip6gateway)
+        res = self.getRouterProcessStatus(router, guest_gateway_check_cmd)
+        self.assertFalse(type(res) == str and len(res) > 0 and network_ip6gateway in res,
+            "%s failed on router %s" % (guest_gateway_check_cmd, router.id))
+        self.checkRouterNicState(router, VPC_ROUTER_PUBLIC_NIC, "DOWN")
+
+    def checkIpv6VpcRoutersInternal(self):
+        network_ip6gateway = self.getNetworkGateway(self.network)
+        for router in self.routers:
+            if router.state != "Running":
+                continue
+            if router.isredundantrouter == True and router.redundantstate == 'BACKUP':
+                self.checkIpv6VpcBackupRouter(router, network_ip6gateway)
+                continue
+            self.checkIpv6VpcPrimaryRouter(router, network_ip6gateway)
+
+
+    def checkIpv6NetworkTierVm(self):
+        self.debug("Listing NICS for VM %s in network tier: %s" % (self.virtual_machine.name, self.network.name))
+        nics = NIC.list(
+            self.apiclient,
+            virtualmachineid=self.virtual_machine.id,
+            networkid=self.network.id
+        )
+        self.assertEqual(
+            len(nics),
+            1,
+            "VM NIC for the network tier isn't found"
+        )
+        nic = nics[0]
+        self.assertNotEqual(nic.ip6address,
+                    None,
+                    "IPv6 address for VM %s NIC is empty" % nic.traffictype)
+        self.virtual_machine_ipv6_address = nic.ip6address
+        self.assertNotEqual(nic.ip6cidr,
+                    None,
+                    "IPv6 CIDR for VM %s NIC is empty" % nic.traffictype)
+        self.assertNotEqual(nic.ip6gateway,
+                    None,
+                    "IPv6 gateway for VM %s NIC is empty" % nic.traffictype)
+
+    def restartVpcWithCleanup(self):
+        self.vpc.restart(self.apiclient, cleanup=True)
+        time.sleep(SLEEP_BEFORE_VR_CHANGES)
+
+    def updateNetworkTierWithOffering(self):
+        self.network.update(self.apiclient, networkofferingid=self.network_offering_update.id)
+        time.sleep(SLEEP_BEFORE_VR_CHANGES)
+
+    def deployRoutingTestResources(self):
+        self.routing_test_vpc = self.deployAllowAllVpcInternal(ROUTE_TEST_VPC_DATA["cidr"])
+        self.cleanup.append(self.routing_test_vpc)
+        self.routing_test_network_offering = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.routing_test_network_offering)
+        self.routing_test_network = self.deployNetworkTierInternal(
+            self.routing_test_network_offering.id,
+            self.routing_test_vpc.id,
+            ROUTE_TEST_VPC_DATA["tier1_gateway"],
+            ROUTE_TEST_VPC_DATA["tier_netmask"]
+        )
+        self.cleanup.append(self.routing_test_network)

Review Comment:
   ```suggestion
           self.routing_test_vpc = self.deployAllowAllVpcInternal(ROUTE_TEST_VPC_DATA["cidr"])
           self.routing_test_network_offering = self.createNetworkTierOfferingInternal(True)
           self.routing_test_network = self.deployNetworkTierInternal(
               self.routing_test_network_offering.id,
               self.routing_test_vpc.id,
               ROUTE_TEST_VPC_DATA["tier1_gateway"],
               ROUTE_TEST_VPC_DATA["tier_netmask"]
           )
   ```



##########
test/integration/smoke/test_vpc_ipv6.py:
##########
@@ -0,0 +1,911 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT test for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Vpc, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)
+            #Clean up, terminate the created templates
+            # cleanup_resources(self.apiclient, reversed(self.cleanup))
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    def getRandomIpv6Cidr(self):
+        prefix_length = choice(PREFIX_OPTIONS)
+        random_suffix = getrandbits(40) << (128-prefix_length)
+        base_address = ULA_BASE.network_address + random_suffix
+        return str(IPv6Network((base_address, prefix_length)))
+
+    def createTinyServiceOffering(self):
+        self.service_offering = ServiceOffering.create(
+            self.apiclient,
+            self.services["service_offerings"]["big"],
+        )
+        self.cleanup.append(self.service_offering)
+
+    def createVpcOfferingInternal(self, is_redundant, is_ipv6):
+        off_service = self.services["vpc_offering"]
+        if is_redundant:
+            off_service["serviceCapabilityList"] = {
+                "SourceNat": {
+                    "RedundantRouter": 'true'
+                },
+            }
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        vpc_offering = VpcOffering.create(
+            self.apiclient,
+            off_service
+        )
+        vpc_offering.update(self.apiclient, state='Enabled')
+        return vpc_offering
+
+    def createIpv4VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, False)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOfferingForUpdate(self, is_redundant=False):
+        self.vpc_offering_update = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering_update)
+
+    def createNetworkTierOfferingInternal(self, is_ipv6, remove_lb=True):
+        off_service = self.services["nw_offering_isolated_vpc"]
+        if not remove_lb: # Remove Lb service
+            if "serviceProviderList" in off_service and "Lb" in off_service["serviceProviderList"].keys():
+                providers = off_service["serviceProviderList"]
+                providers.pop("Lb")
+                off_service["serviceProviderList"] = providers
+            if "supportedservices" in off_service and "Lb" in off_service["supportedservices"]:
+                supportedServices = off_service["supportedservices"].split(",")
+                supportedServices.remove("Lb")
+                off_service["supportedservices"] = ",".join(supportedServices)
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        network_offering = NetworkOffering.create(
+            self.apiclient,
+            off_service,
+            conservemode=False
+        )
+        network_offering.update(self.apiclient, state='Enabled')
+        return network_offering
+
+    def createIpv4NetworkTierOffering(self):
+        self.network_offering = self.createNetworkTierOfferingInternal(False)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOffering(self, remove_lb=True):
+        self.network_offering = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOfferingForUpdate(self):
+        self.network_offering_update = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering_update)
+
+    def deployAllowAllVpcInternal(self, cidr):
+        service = self.services["vpc"]
+        service["cidr"] = cidr
+        vpc = VPC.create(
+            self.apiclient,
+            self.services["vpc"],
+            vpcofferingid=self.vpc_offering.id,
+            zoneid=self.zone.id,
+            account=self.account.name,
+            domainid=self.account.domainid
+        )
+        acl = NetworkACLList.create(
+            self.apiclient,
+            services={},
+            name="allowall",
+            description="allowall",
+            vpcid=vpc.id
+        )
+        rule ={
+            "protocol": "all",
+            "traffictype": "ingress",
+        }
+        NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=acl.id
+        )
+        rule["traffictype"] = "egress"
+        NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=acl.id
+        )
+        self.vpcAllowAllAclDetailsMap[vpc.id] = acl.id
+        return vpc
+
+    def deployVpc(self):
+        self.vpc = self.deployAllowAllVpcInternal(VPC_DATA["cidr"])
+        self.cleanup.append(self.vpc)
+
+    def deployNetworkTierInternal(self, network_offering_id, vpc_id, tier_gateway, tier_netmask, acl_id=None, tier_name=None):
+        if not acl_id and vpc_id in self.vpcAllowAllAclDetailsMap:
+            acl_id = self.vpcAllowAllAclDetailsMap[vpc_id]
+        service = self.services["ntwk"]
+        if tier_name:
+            service["name"] = tier_name
+            service["displaytext"] = "vpc-%s" % tier_name
+        network = Network.create(
+            self.apiclient,
+            service,
+            self.account.name,
+            self.account.domainid,
+            networkofferingid=network_offering_id,
+            vpcid=vpc_id,
+            zoneid=self.zone.id,
+            gateway=tier_gateway,
+            netmask=tier_netmask,
+            aclid=acl_id
+        )
+        return network
+
+    def deployNetworkTier(self):
+        self.network = self.deployNetworkTierInternal(
+            self.network_offering.id,
+            self.vpc.id,
+            VPC_DATA["tier1_gateway"],
+            VPC_DATA["tier_netmask"]
+        )
+        self.cleanup.append(self.network)
+
+    def deployNetworkTierVmInternal(self, network):
+        if self.template == FAILED:
+            assert False, "get_test_template() failed to return template"
+        self.services["virtual_machine"]["zoneid"] = self.zone.id
+        virtual_machine = VirtualMachine.create(
+            self.apiclient,
+            self.services["virtual_machine"],
+            templateid=self.template.id,
+            accountid=self.account.name,
+            domainid=self.account.domainid,
+            networkids=network,
+            serviceofferingid=self.service_offering.id
+        )
+        return virtual_machine
+
+    def deployNetworkTierVm(self):
+        self.virtual_machine = self.deployNetworkTierVmInternal(self.network.id)
+        self.cleanup.append(self.virtual_machine)

Review Comment:
   ```suggestion
   ```



##########
test/integration/smoke/test_vpc_ipv6.py:
##########
@@ -0,0 +1,911 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" BVT test for IPv6 VPC"""
+
+#Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (isAlmostEqual,
+                              cleanup_resources,
+                              random_gen,
+                              get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             NIC,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template,
+                               get_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits, choice, randint
+import time
+import logging
+import threading
+
+ipv6_offering_config_name = "ipv6.offering.enabled"
+ULA_BASE = IPv6Network("fd00::/8")
+PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
+ACL_TABLE = "ip6_acl"
+ACL_CHAINS_SUFFIX = {
+    "Ingress": "_ingress_policy",
+    "Egress": "_egress_policy"
+}
+CIDR_IPV6_ANY = "::/0"
+ICMPV6_TYPE = {
+    1: "destination-unreachable",
+    2: "packet-too-big",
+    3: "time-exceeded",
+    4: "parameter-problem",
+    128: "echo-request",
+    129: "echo-reply",
+    130: "mld-listener-query",
+    131: "mld-listener-report",
+    132: "mld-listener-done",
+    133: "nd-router-solicit",
+    134: "nd-router-advert",
+    135: "nd-neighbor-solicit",
+    136: "nd-neighbor-advert",
+    137: "nd-redirect",
+    138: "router-renumbering",
+    141: "ind-neighbor-solicit",
+    142: "ind-neighbor-advert",
+    143: "mld2-listener-report"
+}
+ICMPV6_CODE_TYPE = {
+    0: "no-route",
+    1: "admin-prohibited",
+    3: "addr-unreachable",
+    4: "port-unreachable",
+    5: "policy-fail",
+    6: "reject-route"
+}
+ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
+TCP_UDP_PORT_ANY = "{ 0-65535 }"
+VPC_ROUTER_PUBLIC_NIC = "eth1"
+VPC_ROUTER_GUEST_NIC = "eth2"
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+ROUTE_TEST_VPC_DATA = {
+    "cidr": "10.2.0.0/22",
+    "tier1_gateway": "10.2.1.1",
+    "tier_netmask": "255.255.255.0"
+}
+SLEEP_BEFORE_VR_CHANGES = 90
+PING_RETRIES = 5
+PING_SLEEP = 20
+
+
+class TestIpv6Vpc(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestIpv6Vpc, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        cls.routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestIpv6Vpc')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=ipv6_offering_config_name)[0].value
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                "true")
+            cls.domain = get_domain(cls.apiclient)
+            cls.account = Account.create(
+                cls.apiclient,
+                cls.services["account"],
+                admin=True,
+                domainid=cls.domain.id
+            )
+            cls._cleanup.append(cls.account)
+            cls.hypervisor = testClient.getHypervisorInfo()
+            cls.template = get_test_template(
+               cls.apiclient,
+               cls.zone.id,
+               cls.hypervisor)
+        else:
+            cls.debug("IPv6 is not supported, skipping tests!")
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                ipv6_offering_config_name,
+                cls.initial_ipv6_offering_enabled)
+        super(TestIpv6Vpc, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.thread = None
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            if self.thread and self.thread.is_alive():
+                self.thread.join(5*60)
+            #Clean up, terminate the created templates
+            # cleanup_resources(self.apiclient, reversed(self.cleanup))
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    def getRandomIpv6Cidr(self):
+        prefix_length = choice(PREFIX_OPTIONS)
+        random_suffix = getrandbits(40) << (128-prefix_length)
+        base_address = ULA_BASE.network_address + random_suffix
+        return str(IPv6Network((base_address, prefix_length)))
+
+    def createTinyServiceOffering(self):
+        self.service_offering = ServiceOffering.create(
+            self.apiclient,
+            self.services["service_offerings"]["big"],
+        )
+        self.cleanup.append(self.service_offering)
+
+    def createVpcOfferingInternal(self, is_redundant, is_ipv6):
+        off_service = self.services["vpc_offering"]
+        if is_redundant:
+            off_service["serviceCapabilityList"] = {
+                "SourceNat": {
+                    "RedundantRouter": 'true'
+                },
+            }
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        vpc_offering = VpcOffering.create(
+            self.apiclient,
+            off_service
+        )
+        vpc_offering.update(self.apiclient, state='Enabled')
+        return vpc_offering
+
+    def createIpv4VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, False)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering)
+
+    def createIpv6VpcOfferingForUpdate(self, is_redundant=False):
+        self.vpc_offering_update = self.createVpcOfferingInternal(is_redundant, True)
+        self.cleanup.append(self.vpc_offering_update)
+
+    def createNetworkTierOfferingInternal(self, is_ipv6, remove_lb=True):
+        off_service = self.services["nw_offering_isolated_vpc"]
+        if not remove_lb: # Remove Lb service
+            if "serviceProviderList" in off_service and "Lb" in off_service["serviceProviderList"].keys():
+                providers = off_service["serviceProviderList"]
+                providers.pop("Lb")
+                off_service["serviceProviderList"] = providers
+            if "supportedservices" in off_service and "Lb" in off_service["supportedservices"]:
+                supportedServices = off_service["supportedservices"].split(",")
+                supportedServices.remove("Lb")
+                off_service["supportedservices"] = ",".join(supportedServices)
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        network_offering = NetworkOffering.create(
+            self.apiclient,
+            off_service,
+            conservemode=False
+        )
+        network_offering.update(self.apiclient, state='Enabled')
+        return network_offering
+
+    def createIpv4NetworkTierOffering(self):
+        self.network_offering = self.createNetworkTierOfferingInternal(False)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOffering(self, remove_lb=True):
+        self.network_offering = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering)
+
+    def createIpv6NetworkTierOfferingForUpdate(self):
+        self.network_offering_update = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.network_offering_update)
+
+    def deployAllowAllVpcInternal(self, cidr):
+        service = self.services["vpc"]
+        service["cidr"] = cidr
+        vpc = VPC.create(
+            self.apiclient,
+            self.services["vpc"],
+            vpcofferingid=self.vpc_offering.id,
+            zoneid=self.zone.id,
+            account=self.account.name,
+            domainid=self.account.domainid
+        )
+        acl = NetworkACLList.create(
+            self.apiclient,
+            services={},
+            name="allowall",
+            description="allowall",
+            vpcid=vpc.id
+        )
+        rule ={
+            "protocol": "all",
+            "traffictype": "ingress",
+        }
+        NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=acl.id
+        )
+        rule["traffictype"] = "egress"
+        NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=acl.id
+        )
+        self.vpcAllowAllAclDetailsMap[vpc.id] = acl.id
+        return vpc
+
+    def deployVpc(self):
+        self.vpc = self.deployAllowAllVpcInternal(VPC_DATA["cidr"])
+        self.cleanup.append(self.vpc)
+
+    def deployNetworkTierInternal(self, network_offering_id, vpc_id, tier_gateway, tier_netmask, acl_id=None, tier_name=None):
+        if not acl_id and vpc_id in self.vpcAllowAllAclDetailsMap:
+            acl_id = self.vpcAllowAllAclDetailsMap[vpc_id]
+        service = self.services["ntwk"]
+        if tier_name:
+            service["name"] = tier_name
+            service["displaytext"] = "vpc-%s" % tier_name
+        network = Network.create(
+            self.apiclient,
+            service,
+            self.account.name,
+            self.account.domainid,
+            networkofferingid=network_offering_id,
+            vpcid=vpc_id,
+            zoneid=self.zone.id,
+            gateway=tier_gateway,
+            netmask=tier_netmask,
+            aclid=acl_id
+        )
+        return network
+
+    def deployNetworkTier(self):
+        self.network = self.deployNetworkTierInternal(
+            self.network_offering.id,
+            self.vpc.id,
+            VPC_DATA["tier1_gateway"],
+            VPC_DATA["tier_netmask"]
+        )
+        self.cleanup.append(self.network)
+
+    def deployNetworkTierVmInternal(self, network):
+        if self.template == FAILED:
+            assert False, "get_test_template() failed to return template"
+        self.services["virtual_machine"]["zoneid"] = self.zone.id
+        virtual_machine = VirtualMachine.create(
+            self.apiclient,
+            self.services["virtual_machine"],
+            templateid=self.template.id,
+            accountid=self.account.name,
+            domainid=self.account.domainid,
+            networkids=network,
+            serviceofferingid=self.service_offering.id
+        )
+        return virtual_machine
+
+    def deployNetworkTierVm(self):
+        self.virtual_machine = self.deployNetworkTierVmInternal(self.network.id)
+        self.cleanup.append(self.virtual_machine)
+
+    def checkIpv6Vpc(self):
+        self.debug("Listing VPC: %s" % (self.vpc.name))
+        ipv6_vpc = VPC.list(self.apiclient,listall="true",id=self.vpc.id)
+        self.assertTrue(
+            isinstance(ipv6_vpc, list),
+            "Check listVpcs response returns a valid list"
+        )
+        self.assertEqual(
+            len(ipv6_vpc),
+            1,
+            "Network not found"
+        )
+        ipv6_vpc = ipv6_vpc[0]
+        self.assertNotEqual(ipv6_vpc.ip6routes,
+                    None,
+                    "IPv6 routes for network is empty")
+
+    def checkIpv6NetworkTierBasic(self):
+        self.debug("Listing network: %s" % (self.network.name))
+        ipv6_network = Network.list(self.apiclient,listall="true",id=self.network.id)
+        self.assertTrue(
+            isinstance(ipv6_network, list),
+            "Check listNetworks response returns a valid list"
+        )
+        self.assertEqual(
+            len(ipv6_network),
+            1,
+            "Network not found"
+        )
+        ipv6_network = ipv6_network[0]
+        self.assertNotEqual(ipv6_network,
+                    None,
+                    "User is not able to retrieve network details %s" % self.network.id)
+        self.assertNotEqual(ipv6_network.ip6cidr,
+                    None,
+                    "IPv6 CIDR for network is empty")
+        self.assertNotEqual(ipv6_network.ip6gateway,
+                    None,
+                    "IPv6 gateway for network is empty")
+        self.assertNotEqual(ipv6_network.ip6routes,
+                    None,
+                    "IPv6 routes for network is empty")
+
+    def checkIpv6VpcRoutersBasic(self):
+        self.debug("Listing routers for VPC: %s" % self.vpc.name)
+        self.routers = Router.list(
+            self.apiclient,
+            vpcid=self.vpc.id,
+            listall=True
+        )
+        self.assertTrue(
+            isinstance(self.routers, list),
+            "Check listRouters response returns a valid list"
+        )
+        self.assertTrue(
+            len(self.routers) > 0,
+            "Router for the network isn't found"
+        )
+        for router in self.routers:
+            self.assertFalse(
+                router.isredundantrouter == True and router.redundantstate == "FAULT",
+                "Router for the network is in FAULT state"
+            )
+            nics = router.nic
+            for nic in nics:
+                if (nic.traffictype == 'Guest' and router.isredundantrouter == False) or nic.traffictype == 'Public':
+                    self.assertNotEqual(nic.ip6address,
+                                None,
+                                "IPv6 address for router %s NIC is empty" % nic.traffictype)
+                    self.assertNotEqual(nic.ip6cidr,
+                                None,
+                                "IPv6 CIDR for router %s NIC is empty" % nic.traffictype)
+                    self.assertNotEqual(nic.ip6gateway,
+                                None,
+                                "IPv6 gateway for router %s NIC is empty" % nic.traffictype)
+
+
+    def getRouterProcessStatus(self, router, cmd):
+        if router.id not in self.routerDetailsMap or self.routerDetailsMap[router.id] is None:
+            connect_ip = self.apiclient.connection.mgtSvr
+            connect_user = self.apiclient.connection.user
+            connect_passwd = self.apiclient.connection.passwd
+            hypervisor = self.hypervisor
+            if self.hypervisor.lower() not in ('vmware', 'hyperv'):
+                hosts = Host.list(
+                    self.apiclient,
+                    zoneid=router.zoneid,
+                    type='Routing',
+                    state='Up',
+                    id=router.hostid
+                )
+                self.assertEqual(
+                    isinstance(hosts, list),
+                    True,
+                    "Check list host returns a valid list"
+                )
+                host = hosts[0]
+                connect_ip = host.ipaddress
+                hypervisor = None
+                try:
+                    connect_user, connect_passwd= get_host_credentials(
+                        self.config, host.ipaddress)
+                except KeyError:
+                    self.skipTest(
+                        "Marvin configuration has no host credentials to\
+                                check router services")
+            details = {}
+            details['connect_ip'] = connect_ip
+            details['connect_user'] = connect_user
+            details['connect_passwd'] = connect_passwd
+            details['hypervisor'] = hypervisor
+            self.routerDetailsMap[router.id] = details
+        result = get_process_status(
+            self.routerDetailsMap[router.id]['connect_ip'],
+            22,
+            self.routerDetailsMap[router.id]['connect_user'],
+            self.routerDetailsMap[router.id]['connect_passwd'],
+            router.linklocalip,
+            cmd,
+            hypervisor=self.routerDetailsMap[router.id]['hypervisor']
+        )
+        self.assertTrue(type(result) == list and len(result) > 0,
+            "%s on router %s returned invalid result" % (cmd, router.id))
+        result = '\n'.join(result)
+        return result
+
+    def getVpcRouter(self, vpc, red_state="PRIMARY"):
+        routers = Router.list(
+            self.apiclient,
+            vpcid=vpc.id,
+            listall=True
+        )
+        self.assertTrue(
+            isinstance(routers, list) and len(routers) > 0,
+            "No routers found for VPC %s" % vpc.id
+        )
+        if len(routers) == 1:
+            return routers[0]
+        for router in routers:
+            if router.redundantstate == red_state:
+                return router
+
+    def getNetworkGateway(self, network):
+        ipv6_network = Network.list(self.apiclient,listall="true",id=network.id)
+        self.assertTrue(
+            isinstance(ipv6_network, list),
+            "Check listNetworks response returns a valid list"
+        )
+        self.assertEqual(
+            len(ipv6_network),
+            1,
+            "Network not found"
+        )
+        ipv6_network = ipv6_network[0]
+        self.assertNotEqual(ipv6_network.ip6gateway,
+                    None,
+                    "IPv6 gateway for network is empty")
+        return ipv6_network.ip6gateway
+
+    def getNetworkRoutes(self, network):
+        ipv6_network = Network.list(self.apiclient,listall="true",id=network.id)
+        self.assertTrue(
+            isinstance(ipv6_network, list),
+            "Check listNetworks response returns a valid list"
+        )
+        self.assertEqual(
+            len(ipv6_network),
+            1,
+            "Network not found"
+        )
+        ipv6_network = ipv6_network[0]
+        self.assertNotEqual(ipv6_network.ip6routes,
+                    None,
+                    "IPv6 routes for network is empty")
+        return ipv6_network.ip6routes
+
+    def isNetworkEgressDefaultPolicyAllow(self, network):
+        ipv6_network = Network.list(self.apiclient,listall="true",id=network.id)
+        if len(ipv6_network) == 1:
+            ipv6_network = ipv6_network[0]
+            return ipv6_network.egressdefaultpolicy
+        return False
+
+    def checkRouterNicState(self, router, dev, state):
+        st = "state %s" % state
+        cmd = "ip link show %s | grep '%s'" % (dev, st)
+        res = self.getRouterProcessStatus(router, cmd)
+        self.assertTrue(type(res) == str and len(res) > 0 and st in res,
+            "%s failed on router %s" % (cmd, router.id))
+
+    def checkIpv6VpcPrimaryRouter(self, router, network_ip6gateway):
+        self.checkRouterNicState(router, VPC_ROUTER_GUEST_NIC, "UP")
+        guest_gateway_check_cmd = "ip -6 address show %s | grep 'inet6 %s'" % (VPC_ROUTER_GUEST_NIC, network_ip6gateway)
+        res = self.getRouterProcessStatus(router, guest_gateway_check_cmd)
+        self.assertTrue(type(res) == str and len(res) > 0 and network_ip6gateway in res,
+            "%s failed on router %s" % (guest_gateway_check_cmd, router.id))
+        self.assertFalse("dadfailed" in res,
+            "dadfailed for IPv6 guest gateway on router %s" % router.id)
+        self.checkRouterNicState(router, VPC_ROUTER_PUBLIC_NIC, "UP")
+        public_ipv6 = None
+        public_ipv6_gateway = None
+        nics = router.nic
+        for nic in nics:
+            if nic.traffictype == 'Public':
+                public_ipv6 = nic.ip6address
+                public_ipv6_gateway = nic.ip6gateway
+                break
+        self.assertNotEqual(public_ipv6,
+            None,
+            "IPv6 address for router Public NIC is empty")
+        public_ip_check_cmd = "ip -6 address show %s | grep 'inet6 %s'" % (VPC_ROUTER_PUBLIC_NIC, public_ipv6)
+        res = self.getRouterProcessStatus(router, public_ip_check_cmd)
+        self.assertTrue(type(res) == str and len(res) > 0 and public_ipv6 in res,
+            "%s failed on router %s" % (public_ip_check_cmd, router.id))
+        self.assertFalse("dadfailed" in res,
+            "dadfailed for public IPv6 on router %s" % router.id)
+        self.assertNotEqual(public_ipv6_gateway,
+            None,
+            "IPv6 gateway for router Public NIC is empty")
+        default_route_check_cmd = "ip -6 route | grep 'default via %s'" % (public_ipv6_gateway)
+        res = self.getRouterProcessStatus(router, default_route_check_cmd)
+        self.assertTrue(type(res) == str and len(res) > 0 and public_ipv6_gateway in res,
+            "%s failed on router %s" % (default_route_check_cmd, router.id))
+
+    def checkIpv6VpcBackupRouter(self, router, network_ip6gateway):
+        self.checkRouterNicState(router, VPC_ROUTER_GUEST_NIC, "UP")
+        guest_gateway_check_cmd = "ip -6 address show %s | grep 'inet6 %s'" % ("eth0", network_ip6gateway)
+        res = self.getRouterProcessStatus(router, guest_gateway_check_cmd)
+        self.assertFalse(type(res) == str and len(res) > 0 and network_ip6gateway in res,
+            "%s failed on router %s" % (guest_gateway_check_cmd, router.id))
+        self.checkRouterNicState(router, VPC_ROUTER_PUBLIC_NIC, "DOWN")
+
+    def checkIpv6VpcRoutersInternal(self):
+        network_ip6gateway = self.getNetworkGateway(self.network)
+        for router in self.routers:
+            if router.state != "Running":
+                continue
+            if router.isredundantrouter == True and router.redundantstate == 'BACKUP':
+                self.checkIpv6VpcBackupRouter(router, network_ip6gateway)
+                continue
+            self.checkIpv6VpcPrimaryRouter(router, network_ip6gateway)
+
+
+    def checkIpv6NetworkTierVm(self):
+        self.debug("Listing NICS for VM %s in network tier: %s" % (self.virtual_machine.name, self.network.name))
+        nics = NIC.list(
+            self.apiclient,
+            virtualmachineid=self.virtual_machine.id,
+            networkid=self.network.id
+        )
+        self.assertEqual(
+            len(nics),
+            1,
+            "VM NIC for the network tier isn't found"
+        )
+        nic = nics[0]
+        self.assertNotEqual(nic.ip6address,
+                    None,
+                    "IPv6 address for VM %s NIC is empty" % nic.traffictype)
+        self.virtual_machine_ipv6_address = nic.ip6address
+        self.assertNotEqual(nic.ip6cidr,
+                    None,
+                    "IPv6 CIDR for VM %s NIC is empty" % nic.traffictype)
+        self.assertNotEqual(nic.ip6gateway,
+                    None,
+                    "IPv6 gateway for VM %s NIC is empty" % nic.traffictype)
+
+    def restartVpcWithCleanup(self):
+        self.vpc.restart(self.apiclient, cleanup=True)
+        time.sleep(SLEEP_BEFORE_VR_CHANGES)
+
+    def updateNetworkTierWithOffering(self):
+        self.network.update(self.apiclient, networkofferingid=self.network_offering_update.id)
+        time.sleep(SLEEP_BEFORE_VR_CHANGES)
+
+    def deployRoutingTestResources(self):
+        self.routing_test_vpc = self.deployAllowAllVpcInternal(ROUTE_TEST_VPC_DATA["cidr"])
+        self.cleanup.append(self.routing_test_vpc)
+        self.routing_test_network_offering = self.createNetworkTierOfferingInternal(True)
+        self.cleanup.append(self.routing_test_network_offering)
+        self.routing_test_network = self.deployNetworkTierInternal(
+            self.routing_test_network_offering.id,
+            self.routing_test_vpc.id,
+            ROUTE_TEST_VPC_DATA["tier1_gateway"],
+            ROUTE_TEST_VPC_DATA["tier_netmask"]
+        )
+        self.cleanup.append(self.routing_test_network)
+        self.services["virtual_machine"]["zoneid"] = self.zone.id
+        self.routing_test_vm = VirtualMachine.create(
+            self.apiclient,
+            self.services["virtual_machine"],
+            templateid=self.template.id,
+            accountid=self.account.name,
+            domainid=self.account.domainid,
+            networkids=[self.routing_test_network.id],
+            serviceofferingid=self.service_offering.id,
+            mode="advanced",
+            vpcid=self.routing_test_vpc.id
+        )
+        self.cleanup.append(self.routing_test_vm)
+
+    def prepareRoutingTestResourcesInBackground(self):
+        self.thread = threading.Thread(target=self.deployRoutingTestResources, args=())
+        self.thread.daemon = True
+        self.thread.start()
+
+    def checkVpcRouting(self):
+        if not self.thread:
+            self.deployRoutingTestResources()
+        else:
+            self.thread.join(5*60)
+        self.assertFalse(not self.routing_test_vpc or not self.routing_test_network or not self.routing_test_vm,
+            "Routing resources failure")
+
+        test_vpc_router = self.getVpcRouter(self.routing_test_vpc)
+        routes = self.getNetworkRoutes(self.network)
+        self.logger.debug("Adding vpc routes in routing_test_vpc %s" % routes)
+        for route in routes:
+            add_route_cmd = "ip -6 route add %s via %s" % (route.subnet, route.gateway)
+            self.getRouterProcessStatus(test_vpc_router, add_route_cmd)
+
+        vpc_router = self.getVpcRouter(self.vpc)
+        routes = self.getNetworkRoutes(self.routing_test_network)
+        self.logger.debug("Adding routing_test_vpc routes in vpc %s" % routes)
+        for route in routes:
+            add_route_cmd = "ip -6 route add %s via %s" % (route.subnet, route.gateway)
+            self.getRouterProcessStatus(vpc_router, add_route_cmd)
+
+        ping_cmd = "ping6 -c 4 %s" % self.virtual_machine_ipv6_address
+        count = 0
+        while count < PING_RETRIES:
+            count = count + 1
+            res = self.getRouterProcessStatus(test_vpc_router, ping_cmd)
+            if " 0% packet loss" in res:
+                break
+            time.sleep(PING_SLEEP)
+        self.assertTrue(" 0% packet loss" in res,
+            "Ping from router %s of VPC %s to VM %s of VPC %s is unsuccessful" % (test_vpc_router.id, self.routing_test_vpc.id, self.virtual_machine.id, self.vpc.id))
+
+        ssh = self.routing_test_vm.get_ssh_client(retries=5)
+        count = 0
+        while count < PING_RETRIES:
+            count = count + 1
+            res = ssh.execute(ping_cmd)
+            if type(res) == list and len(res) > 0 and " 0% packet loss" in '\n'.join(res):
+                break
+            time.sleep(PING_SLEEP)
+        self.assertTrue(type(res) == list and len(res) > 0,
+            "%s on VM %s returned invalid result" % (ping_cmd, self.routing_test_vm.id))
+        self.logger.debug(res)
+        res = '\n'.join(res)
+        self.assertTrue(" 0% packet loss" in res,
+            "Ping from VM %s of VPC %s to VM %s of VPC %s is unsuccessful" % (self.routing_test_vm.id, self.routing_test_vpc.id, self.virtual_machine.id, self.vpc.id))
+
+    def createNetworkAclRule(self, rule, aclid):
+        return NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=aclid
+        )
+
+    def verifyAclRulesInRouter(self, nic, rules, router):
+        for rule in rules:
+            acl_chain = nic + ACL_CHAINS_SUFFIX[rule["traffictype"]]
+            routerCmd = "nft list chain ip6 %s %s" % (ACL_TABLE, acl_chain)
+            res = self.getRouterProcessStatus(router, routerCmd)
+            self.assertTrue(rule["parsedrule"] in res,
+                "Listing firewall rule with nft list chain failure for rule: %s" % rule["parsedrule"])
+
+    def checkIpv6AclRule(self):
+        router = self.getVpcRouter(self.vpc)
+
+        tier1_acl = NetworkACLList.create(
+            self.apiclient,
+            services={},
+            name="tier1_acl",
+            description="tier1_acl",
+            vpcid=self.vpc.id
+        )
+        rules = []
+        # Ingress - ip6 saddr SOURCE_CIDR tcp dport { START_PORT-END_PORT } accept
+        rule = {}
+        rule["traffictype"] = "Ingress"
+        rule["cidrlist"] = self.getRandomIpv6Cidr()
+        rule["protocol"] = "tcp"
+        rule["startport"] = randint(3000, 5000)
+        rule["endport"] = rule["startport"] + randint(1, 8)
+        parsedrule = "ip6 saddr %s %s dport { %d-%d } accept" % (rule["cidrlist"], rule["protocol"], rule["startport"], rule["endport"])
+        rules.append({"traffictype": rule["traffictype"], "parsedrule": parsedrule})
+        self.createNetworkAclRule(rule, tier1_acl.id)
+        # Egress - ip6 daddr DEST_CIDR icmpv6 type TYPE code CODE accept
+        rule = {}
+        rule["traffictype"] = "Egress"
+        rule["cidrlist"] = self.getRandomIpv6Cidr()
+        rule["protocol"] = "icmp"
+        rule["icmptype"] = choice(list(ICMPV6_TYPE.keys()))
+        rule["icmpcode"] = choice(list(ICMPV6_CODE_TYPE.keys()))
+        parsedrule = "ip6 daddr %s %sv6 type %s %sv6 code %s accept" % (rule["cidrlist"], rule["protocol"], ICMPV6_TYPE[rule["icmptype"]], rule["protocol"], ICMPV6_CODE_TYPE[rule["icmpcode"]])
+        rules.append({"traffictype": rule["traffictype"], "parsedrule": parsedrule})
+        self.createNetworkAclRule(rule, tier1_acl.id)
+
+        self.network.replaceACLList(self.apiclient, tier1_acl.id)
+
+        self.verifyAclRulesInRouter("eth2", rules, router)
+
+
+        tier2_acl = NetworkACLList.create(
+            self.apiclient,
+            services={},
+            name="tier2_acl",
+            description="tier2_acl",
+            vpcid=self.vpc.id
+        )
+        rules = []
+        # Ingress - ip6 saddr ::/0 udp dport { 0-65355 } ACTION
+        rule = {}
+        rule["traffictype"] = "Ingress"
+        rule["cidrlist"] = CIDR_IPV6_ANY
+        rule["protocol"] = "udp"
+        parsedrule = "ip6 saddr %s %s dport %s accept" % (rule["cidrlist"], rule["protocol"], TCP_UDP_PORT_ANY)
+        rules.append({"traffictype": rule["traffictype"], "parsedrule": parsedrule})
+        self.createNetworkAclRule(rule, tier2_acl.id)
+        # Egress - ip6 daddr DEST_CIDR icmpv6 type TYPE code CODE accept
+        rule = {}
+        rule["traffictype"] = "Egress"
+        rule["protocol"] = "all"
+        parsedrule = "ip6 daddr %s accept" % (CIDR_IPV6_ANY)
+        rules.append({"traffictype": rule["traffictype"], "parsedrule": parsedrule})
+        self.createNetworkAclRule(rule, tier2_acl.id)
+
+        self.network_offering_tier2 = self.createNetworkTierOfferingInternal(True, False)
+        self.cleanup.append(self.network_offering_tier2)
+        self.tier2_network = self.deployNetworkTierInternal(
+            self.network_offering_tier2.id,
+            self.vpc.id,
+            VPC_DATA["tier2_gateway"],
+            VPC_DATA["tier_netmask"],
+            tier2_acl.id,
+            "tier2"
+        )
+        self.cleanup.append(self.tier2_network)
+        self.tier2_vm = self.deployNetworkTierVmInternal(self.tier2_network.id)
+        self.cleanup.append(self.tier2_vm)

Review Comment:
   ```suggestion
           self.network_offering_tier2 = self.createNetworkTierOfferingInternal(True, False)
           self.tier2_network = self.deployNetworkTierInternal(
               self.network_offering_tier2.id,
               self.vpc.id,
               VPC_DATA["tier2_gateway"],
               VPC_DATA["tier_netmask"],
               tier2_acl.id,
               "tier2"
           )
           self.tier2_vm = self.deployNetworkTierVmInternal(self.tier2_network.id)
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] acs-robot commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
acs-robot commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1113189986

   Found UI changes, kicking a new UI QA build
   @blueorangutan ui


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] shwstppr commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
shwstppr commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1178617248

   @blueorangutan package


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1180624042

   @rohityadavcloud a Trillian-Jenkins matrix job (centos7 mgmt + xs71, centos7 mgmt + vmware65, centos7 mgmt + kvmcentos7) has been kicked to run smoke tests


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] rohityadavcloud commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
rohityadavcloud commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1181411179

   LGTM, tests have passed, I think xenserver would be more or less same as Travis/build, and tests on kvm, vmware has passed. This only adds tests to the branch.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1118996028

   <b>Trillian test result (tid-4125)</b>
   Environment: kvm-centos7 (x2), Advanced Networking with Mgmt server 7
   Total time taken: 40035 seconds
   Marvin logs: https://github.com/blueorangutan/acs-prs/releases/download/trillian/pr6338-t4125-kvm-centos7.zip
   Smoke tests completed. 97 look OK, 0 have errors
   Only failed tests results shown below:
   
   
   Test | Result | Time (s) | Test File
   --- | --- | --- | ---
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] shwstppr commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
shwstppr commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1129622403

   @blueorangutan package


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] weizhouapache commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
weizhouapache commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1129726043

   
   @blueorangutan package
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] sonarcloud[bot] commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
sonarcloud[bot] commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1178889764

   Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=apache_cloudstack&pullRequest=6338)
   
   [![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG)  
   [![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY)  
   [![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT)  
   [![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL)
   
   [![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=coverage&view=list) No Coverage information  
   [![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=new_duplicated_lines_density&view=list)
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] shwstppr commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
shwstppr commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1114552017

   @blueorangutan package


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1118183753

   @acs-robot a Jenkins job has been kicked to build UI QA env. I'll keep you posted as I make progress.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] sonarcloud[bot] commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
sonarcloud[bot] commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1118215702

   Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=apache_cloudstack&pullRequest=6338)
   
   [![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG)  
   [![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY)  
   [![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT)  
   [![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL)
   
   [![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=coverage&view=list) No Coverage information  
   [![No Duplication information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/NoDuplicationInfo-16px.png 'No Duplication information')](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=duplicated_lines_density&view=list) No Duplication information
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] sonarcloud[bot] commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
sonarcloud[bot] commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1152164195

   Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=apache_cloudstack&pullRequest=6338)
   
   [![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG)  
   [![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY)  
   [![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT)  
   [![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL)
   
   [![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=coverage&view=list) No Coverage information  
   [![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=new_duplicated_lines_density&view=list)
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1158701746

   @acs-robot a Jenkins job has been kicked to build UI QA env. I'll keep you posted as I make progress.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] shwstppr commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
shwstppr commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1161671092

   @blueorangutan package


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] sonarcloud[bot] commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
sonarcloud[bot] commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1160384359

   Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=apache_cloudstack&pullRequest=6338)
   
   [![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG)  
   [![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY)  
   [![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT)  
   [![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL)
   
   [![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=coverage&view=list) No Coverage information  
   [![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=new_duplicated_lines_density&view=list)
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1161554735

   @shwstppr a Jenkins job has been kicked to build packages. It will be bundled with  KVM, XenServer and VMware SystemVM templates. I'll keep you posted as I make progress.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1162686264

   @shwstppr a Jenkins job has been kicked to build packages. It will be bundled with  KVM, XenServer and VMware SystemVM templates. I'll keep you posted as I make progress.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1160338516

   UI build: :heavy_check_mark:
   Live QA URL: http://qa.cloudstack.cloud:8080/client/pr/6338 (SL-JID-1777)


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] sonarcloud[bot] commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
sonarcloud[bot] commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1161601468

   Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=apache_cloudstack&pullRequest=6338)
   
   [![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG)  
   [![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY)  
   [![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT)  
   [![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL)
   
   [![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=coverage&view=list) No Coverage information  
   [![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=new_duplicated_lines_density&view=list)
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1135043223

   <b>Trillian test result (tid-4230)</b>
   Environment: kvm-centos7 (x2), Advanced Networking with Mgmt server 7
   Total time taken: 39903 seconds
   Marvin logs: https://github.com/blueorangutan/acs-prs/releases/download/trillian/pr6338-t4230-kvm-centos7.zip
   Smoke tests completed. 99 look OK, 0 have errors
   Only failed tests results shown below:
   
   
   Test | Result | Time (s) | Test File
   --- | --- | --- | ---
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1129866700

   @shwstppr a Jenkins job has been kicked to build packages. It will be bundled with  KVM, XenServer and VMware SystemVM templates. I'll keep you posted as I make progress.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] shwstppr commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
shwstppr commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1129866296

   @blueorangutan package


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] sonarcloud[bot] commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
sonarcloud[bot] commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1129662481

   SonarCloud Quality Gate failed.&nbsp; &nbsp; [![Quality Gate failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/failed-16px.png 'Quality Gate failed')](https://sonarcloud.io/dashboard?id=apache_cloudstack&pullRequest=6338)
   
   [![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG)  
   [![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY)  
   [![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT)  
   [![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL)
   
   [![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/0-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=new_coverage&view=list) [0.0% Coverage](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=new_coverage&view=list)  
   [![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=new_duplicated_lines_density&view=list)
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1129624359

   @shwstppr a Jenkins job has been kicked to build packages. It will be bundled with  KVM, XenServer and VMware SystemVM templates. I'll keep you posted as I make progress.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1152110099

   @acs-robot a Jenkins job has been kicked to build UI QA env. I'll keep you posted as I make progress.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1152954783

   @shwstppr a Trillian-Jenkins test job (centos7 mgmt + kvm-centos7) has been kicked to run smoke tests


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1178617543

   @shwstppr a Jenkins job has been kicked to build packages. It will be bundled with  KVM, XenServer and VMware SystemVM templates. I'll keep you posted as I make progress.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] rohityadavcloud merged pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
rohityadavcloud merged PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1180604271

   Packaging result: :heavy_check_mark: el7 :heavy_check_mark: el8 :heavy_check_mark: debian :heavy_multiplication_x: suse15. SL-JID 3745


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1181304808

   <b>Trillian test result (tid-4484)</b>
   Environment: vmware-65u2 (x2), Advanced Networking with Mgmt server 7
   Total time taken: 42333 seconds
   Marvin logs: https://github.com/blueorangutan/acs-prs/releases/download/trillian/pr6338-t4484-vmware-65u2.zip
   Smoke tests completed. 100 look OK, 0 have errors
   Only failed tests results shown below:
   
   
   Test | Result | Time (s) | Test File
   --- | --- | --- | ---
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1164721342

   @shwstppr a Trillian-Jenkins test job (centos7 mgmt + kvm-centos7) has been kicked to run smoke tests


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1165217269

   @shwstppr a Trillian-Jenkins test job (centos7 mgmt + kvm-centos7) has been kicked to run smoke tests


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1162947281

   Packaging result: :heavy_check_mark: el7 :heavy_check_mark: el8 :heavy_check_mark: debian :heavy_multiplication_x: suse15. SL-JID 3627


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] sonarcloud[bot] commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
sonarcloud[bot] commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1120873825

   Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=apache_cloudstack&pullRequest=6338)
   
   [![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=BUG)  
   [![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=VULNERABILITY)  
   [![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=apache_cloudstack&pullRequest=6338&resolved=false&types=SECURITY_HOTSPOT)  
   [![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL) [6 Code Smells](https://sonarcloud.io/project/issues?id=apache_cloudstack&pullRequest=6338&resolved=false&types=CODE_SMELL)
   
   [![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=coverage&view=list) No Coverage information  
   [![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=apache_cloudstack&pullRequest=6338&metric=new_duplicated_lines_density&view=list)
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] acs-robot commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
acs-robot commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1120144653

   Found UI changes, kicking a new UI QA build
   @blueorangutan ui


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] acs-robot commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
acs-robot commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1120784981

   Found UI changes, kicking a new UI QA build
   @blueorangutan ui


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] shwstppr commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
shwstppr commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1113191752

   @rohityadavcloud acs-robot calling UI build when there are no UI changes in PR ^^


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1114583031

   Packaging result: :heavy_check_mark: el7 :heavy_check_mark: el8 :heavy_check_mark: debian :heavy_check_mark: suse15. SL-JID 3335


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1134299206

   @shwstppr unsupported parameters provided. Supported mgmt server os are: `suse15, centos7, centos6, alma8, ubuntu18, ubuntu20, rocky8`. Supported hypervisors are: `kvm-centos6, kvm-centos7, kvm-rocky8, kvm-alma8, kvm-ubuntu18, kvm-ubuntu20, kvm-suse15, vmware-55u3, vmware-60u2, vmware-65u2, vmware-67u3, vmware-70u1, vmware-70u2, vmware-70u3, xenserver-65sp1, xenserver-71, xenserver-74, xcpng74, xcpng76, xcpng80, xcpng81, xcpng82`


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] shwstppr commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
shwstppr commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1134297655

   @blueorangutan test
   
   @rohityadavcloud @weizhouapache @DaanHoogland added smoke tests may add ~1.25hrs to smoke test run. Does it make sense to move some of the test cases to a test file in component  dir?


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] weizhouapache commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
weizhouapache commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1134315868

   > I think it makes sense to only leave miniml tests in the smoke dir, @shwstppr . The rest we´d only want to run on subject specific PRs and releases. €0.02
   
   agree with @DaanHoogland 
   we should run the component tests at least once a month (we need to fix all component tests before run, or move failed component tests to a separated folder)


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1133806517

   Packaging result: :heavy_check_mark: el7 :heavy_check_mark: el8 :heavy_check_mark: debian :heavy_check_mark: suse15. SL-JID 3464


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] weizhouapache commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
weizhouapache commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1118233517

   @blueorangutan package


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] weizhouapache closed pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
weizhouapache closed pull request #6338: test: add, refactor ipv6 network, vpc tests
URL: https://github.com/apache/cloudstack/pull/6338


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1133803352

   @rohityadavcloud a Jenkins job has been kicked to build packages. It will be bundled with  SystemVM template(s). I'll keep you posted as I make progress.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1165729774

   <b>Trillian test result (tid-4367)</b>
   Environment: kvm-centos7 (x2), Advanced Networking with Mgmt server 7
   Total time taken: 37007 seconds
   Marvin logs: https://github.com/blueorangutan/acs-prs/releases/download/trillian/pr6338-t4367-kvm-centos7.zip
   Smoke tests completed. 100 look OK, 0 have errors
   Only failed tests results shown below:
   
   
   Test | Result | Time (s) | Test File
   --- | --- | --- | ---
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1178843320

   @acs-robot a Jenkins job has been kicked to build UI QA env. I'll keep you posted as I make progress.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] acs-robot commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
acs-robot commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1178842877

   Found UI changes, kicking a new UI QA build
   @blueorangutan ui


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1180625375

   <b>Trillian Build Failed (tid-4482)<b/>


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1181318816

   <b>Trillian test result (tid-4483)</b>
   Environment: kvm-centos7 (x2), Advanced Networking with Mgmt server 7
   Total time taken: 43762 seconds
   Marvin logs: https://github.com/blueorangutan/acs-prs/releases/download/trillian/pr6338-t4483-kvm-centos7.zip
   Smoke tests completed. 100 look OK, 0 have errors
   Only failed tests results shown below:
   
   
   Test | Result | Time (s) | Test File
   --- | --- | --- | ---
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] acs-robot commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
acs-robot commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1152107407

   Found UI changes, kicking a new UI QA build
   @blueorangutan ui


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] blueorangutan commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
blueorangutan commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1153060794

   <b>Trillian test result (tid-4320)</b>
   Environment: kvm-centos7 (x2), Advanced Networking with Mgmt server 7
   Total time taken: 40729 seconds
   Marvin logs: https://github.com/blueorangutan/acs-prs/releases/download/trillian/pr6338-t4320-kvm-centos7.zip
   Smoke tests completed. 94 look OK, 1 have errors
   Only failed tests results shown below:
   
   
   Test | Result | Time (s) | Test File
   --- | --- | --- | ---
   test_01_create_redundant_VPC_2tiers_4VMs_4IPs_4PF_ACL | `Failure` | 276.40 | test_vpc_redundant.py
   test_01_create_redundant_VPC_2tiers_4VMs_4IPs_4PF_ACL | `Error` | 276.41 | test_vpc_redundant.py
   test_02_redundant_VPC_default_routes | `Error` | 2.98 | test_vpc_redundant.py
   test_03_create_redundant_VPC_1tier_2VMs_2IPs_2PF_ACL_reboot_routers | `Error` | 3.00 | test_vpc_redundant.py
   test_04_rvpc_network_garbage_collector_nics | `Error` | 3.00 | test_vpc_redundant.py
   test_05_rvpc_multi_tiers | `Error` | 3.00 | test_vpc_redundant.py
   ContextSuite context=TestVPCRedundancy>:teardown | `Error` | 6.02 | test_vpc_redundant.py
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [cloudstack] shwstppr commented on pull request #6338: test: add, refactor ipv6 network, vpc tests

Posted by GitBox <gi...@apache.org>.
shwstppr commented on PR #6338:
URL: https://github.com/apache/cloudstack/pull/6338#issuecomment-1153095376

   @blueorangutan test


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org