summaryrefslogtreecommitdiffstats
path: root/docs
AgeCommit message (Collapse)AuthorFilesLines
2019-09-16Update git submodulesPanagiotis Karalis1-0/+0
* Update docs/submodules/dovetail from branch 'master' to 005d868d68dbb0e70b3f92a685ea269c4f646fd7 - Move the proj to python3 The aim of this patch is to upgrade python version of this project from python2 to python3. Signed-off-by: Panagiotis Karalis <panos.pkaralis@gmail.com> Change-Id: I3d3ef01176fda1b23a0542a24625be2f3368c40e
2019-09-16Update git submodulesPanagiotis Karalis1-0/+0
* Update docs/submodules/dovetail from branch 'master' to f0c44b1ae02ffbdb87da81dac7b6754c641d8c04 - Introduce XCI installer After the expression of the need to run the dovetail tool over the XCI installer, the investigation to that direction has been started. The aim of this patch is to introduce the relevant impact either on dovetail's code or on dovetail's documentation. JIRA: DOVETAIL-766 Change-Id: I6931506cb80baa4fa4288141ba86a858bc4215b0 Signed-off-by: Panagiotis Karalis <pkaralis@intracom-telecom.com>
2019-09-14Update git submodulesCédric Ollivier1-0/+0
* Update docs/submodules/releng from branch 'master' to 5e6970e3eea9c552eb82849fafd5952b7c26bb0a - Select 3.6 if iruya It conforms with "Select python 3.6 as default" [1]. [1] https://gerrit.opnfv.org/gerrit/c/functest/+/68471 Change-Id: Ibc4ae81597ce9ed3d12ab27c6eae796870f6a2d4 Signed-off-by: Cédric Ollivier <cedric.ollivier@orange.com>
2019-09-10Update git submodulesxudan1-0/+0
* Update docs/submodules/dovetail from branch 'master' to 369a1fb6e32496ef53e37717de31265f5d4d7074 - Use assertEqual instead of assertEquals DeprecationWarning: Please use assertEqual instead Change-Id: I84db84e85a8a43486109bb948258e57c8b86fdfb Signed-off-by: xudan <xudan16@huawei.com>
2019-09-04Update git submodulesGeorg Kunz1-0/+0
* Update docs/submodules/releng from branch 'master' to cc34c4492b58fd217451faacf54359f2b5ad6d06 - Removing NetReady from Jenkins config NetReady has been archived a while ago, but still some Jenkins config is left and the Anteater job is run. This removes all remaining config. Change-Id: I72b4eb091175db678feb4b4db314321f1543a814 Signed-off-by: Georg Kunz <georg.kunz@ericsson.com>
2019-09-02Update git submodulesFatih Degirmenci1-0/+0
* Update docs/submodules/releng from branch 'master' to 58954fc37a9db69b87f9efb1f0a0b352340d6b7e - xci: Ensure the flavor is captured in all cases Change-Id: I48ee615325002a2d3687d336b9a83a0e5637cee7 Signed-off-by: Fatih Degirmenci <fdegir@gmail.com>
2019-09-02Update git submodulesxudan1-0/+0
* Update docs/submodules/dovetail from branch 'master' to 6d33ad294d6bc56226c86604cded0b70a6952661 - Add portal_key_file into all test case yml files Change-Id: If111a8cc56c31ec3e22b090aca92ff56d41f7e01 Signed-off-by: xudan <xudan16@huawei.com>
2019-09-02Update git submodulesxudan1-0/+0
* Update docs/submodules/dovetail from branch 'master' to d15825b04fde0b40df1840ae2ec2fab2ac961471 - Add validation disabled/enabled to results.json Change-Id: I918f85c5ac89cf2745efa8513946a2b5ab8638b1 Signed-off-by: xudan <xudan16@huawei.com>
2019-08-31Update git submodulesFatih Degirmenci1-0/+0
* Update docs/submodules/releng from branch 'master' to 417d91d8d6de7b0887759b5a17a0bafa5aed7cbe - xci: Fix scenario determination logic Function override_xci_flavor exits with 0 early, preventing the rest of the script and especially override_scenario function to run. This makes it impossible to verify patches that contains installer-type or deploy-scenario in commit message since the generated scenario.properties file contains only XCI_FLAVOR in it, causing verify jobs to fail determining the installer type and the scenario. See the example. https://build.opnfv.org/ci/job/xci-verify-ubuntu-virtual-master/2937/console This change removes exit 0 from override_xci_flavor and moves the call to it to after override_scenario function. JIRA: XCI-21 Change-Id: Ic7f943ba5e1562177b59a8215cd8a6f2a58db093 Signed-off-by: Fatih Degirmenci <fdegir@gmail.com>
2019-08-31Update git submodulesCédric Ollivier1-0/+0
* Update docs/submodules/releng from branch 'master' to 3ecb0c33570d1b37a2034db84c499fcc3a95012b - Remove Functest (OS and K8s) features containers Change-Id: I0391b15adc9f5a8f36d340f6970fe731ff10bcc1 Signed-off-by: Cédric Ollivier <cedric.ollivier@orange.com>
2019-08-30Update git submodulesCédric Ollivier1-0/+0
* Update docs/submodules/releng from branch 'master' to 32532def42dfb1e365fe15bf17c4d4dd0cc97c9b - Run tempest_slow in Functest Iruya gates tempest_slow was backported to Iruya [1] [1] https://gerrit.opnfv.org/gerrit/c/functest/+/68409 Change-Id: I3305d8db5a3dcd19769aef726557866cb03396b4 Signed-off-by: Cédric Ollivier <cedric.ollivier@orange.com>
2019-08-29Update git submodulesCédric Ollivier1-0/+0
* Update docs/submodules/releng from branch 'master' to d77a45334371bcd8b0ddfa8b1062d5851a6670fc - Add tempest_slow in Functest gates It disables few ipv6 testcases due to possible SUT misconfigurations. It seems better than fully skipping ipv6 via tempest config [1] because it's already well covered in tempest_full. [1] https://docs.openstack.org/tempest/latest/sampleconf.html Change-Id: If1160dc68f5e53dffdfdd6722bdc557683243bde Signed-off-by: Cédric Ollivier <cedric.ollivier@orange.com>
2019-08-28Update git submodulesCédric Ollivier1-0/+0
* Update docs/submodules/releng from branch 'master' to c9321951ce4e0ec2f378ad0cb89c71199a0306b7 - Add Octavia in Functest gates It's now avaible in functest-smoke:latest Change-Id: Ib6d5313d63c92a5e760714001a1b8ca670fa261f Signed-off-by: Cédric Ollivier <cedric.ollivier@orange.com>
2019-08-23Update git submodulesxudan1-0/+0
* Update docs/submodules/dovetail from branch 'master' to 14a9a43bf675469486a6991976bef24f3540217b - Add run tests API Change-Id: I456d5d1459faa20d9dd8afd0c235a4bb6cbfbcce Signed-off-by: xudan <xudan16@huawei.com>
2019-08-23Update git submodulesxudan1-0/+0
* Update docs/submodules/dovetail from branch 'master' to a85d35f86170a2a2f2455fa157c12be823060522 - Update Dovetail for XCI and Functest Hunter All info are recorded in etherpad https://etherpad.opnfv.org/p/Dovetail_XCI_TCs Change-Id: Iec54ecca63ef9d83a2e6cceb4c8664a9d107eab4 Signed-off-by: xudan <xudan16@huawei.com>
2019-08-22Update git submodulesCédric Ollivier1-0/+0
* Update docs/submodules/releng from branch 'master' to 38212fb43515a4681e2a0e90eea8abd44947892b - Update alpine to 3.10 in Functest K8S gates Change-Id: I24a92a5252ce47bcb636df2d05624422c6cbe1eb Signed-off-by: Cédric Ollivier <cedric.ollivier@orange.com>
2019-08-22Update git submodulesCédric Ollivier1-0/+0
* Update docs/submodules/releng from branch 'master' to f426669dd26e7d24ce6a13bc0af38d43be758658 - Update Xtesting Gates It now selects lf-virtual1 as slave and Alpine 3.10. It has been generated via latest Xtesting Ansible role. Change-Id: I97c2179cc0f42e435e19b738f7d86114de592425 Signed-off-by: Cédric Ollivier <cedric.ollivier@orange.com>
2019-08-21Update git submodulesCédric Ollivier1-0/+0
* Update docs/submodules/releng from branch 'master' to 6f496588ed030772c6acf3256fc134515b8e5f05 - Protect tag in functest.yaml Else 3.10 becomes falsy 3.1. Change-Id: I84045769d062f184f2f7020b9613cf06abc4af3e Signed-off-by: Cédric Ollivier <cedric.ollivier@orange.com>
2019-08-14Update git submodulesJulien1-0/+0
* Update docs/submodules/releng from branch 'master' to c0f118801c94afe69fa66f686a473bdba18c29fd - Update Pharos PTL email Change-Id: I99ef81ea9e1de2113f28bcb4d401c786b66a1e9e Signed-off-by: Julien <zhang.jun3g@zte.com.cn>
2019-08-05Update git submodulesTim Rozet1-0/+0
* Update docs/submodules/releng from branch 'master' to 84cf308c1df4a10091fa1a14982543f122bc8679 - Temporarily disable apex daily Temporarily disabling daily jobs while running some manual testing on LFPOD1. Change-Id: I5553e4921e95c67954f93416cab651b9f81e911b Signed-off-by: Tim Rozet <trozet@redhat.com>
2019-07-31Update git submodulesFatih Degirmenci1-0/+0
* Update docs/submodules/releng from branch 'master' to 559f32dec5d0d693792a04fab14eeb51939b90ea - Merge "Configure voting for verify jobs" - Configure voting for verify jobs OSH integration to XCI is ongoing but OpenSUSE jobs vote -1, slowing down the integration work. Also, bumping OSA and Kubespray would be easier while we focus on single distro to make jobs green. Voting will gradually be enabled once the basics working. Change-Id: Ic34177741efca683b4c0c1c474fc4b9d826712ec Signed-off-by: Fatih Degirmenci <fdegir@gmail.com>
2019-07-30Update git submodulesFatih Degirmenci1-0/+0
* Update docs/submodules/releng from branch 'master' to de2e7d2c03750a80849dcdb5c47830dbe2c0c1d0 - Disable post-merge jobs Jobs will be kept disabled until we bump OSA and Kubesoray versions and stabilize the deployment and testing. Change-Id: Iad208bec23a311787acf97efd560f285ecf1ea1f Signed-off-by: Fatih Degirmenci <fdegir@gmail.com>
2019-07-27Update git submodulesCedric Ollivier1-0/+0
* Update docs/submodules/releng from branch 'master' to 0a2dfdffb822f822e041085a8e32fe4f87d55f87 - Merge "Update to python 3.7 and alpine 3.10" - Update to python 3.7 and alpine 3.10 Change-Id: Id800208e148190ee10e4cfcb2a48a2dff00c35a7 Signed-off-by: Cédric Ollivier <cedric.ollivier@orange.com>
2019-07-26Update git submodulesCédric Ollivier1-0/+0
* Update docs/submodules/releng from branch 'master' to 3aad5c124e77b44b513727281e471d7083eb190b - Select lf-virtual1 as defaut slave (ut) It allows verifying unit tests vs python3 and building docs (see latest OpenStack upper-constraints) Change-Id: Ie9566d4b1e0a288d5944c3111ec2dc0749be1975 Signed-off-by: Cédric Ollivier <cedric.ollivier@orange.com>
2019-07-22Update git submodulesTrevor Bramwell1-0/+0
* Update docs/submodules/releng from branch 'master' to 09c905482f1c4578a94c420057bc391718d508c2 - Merge "add views for remaining jenkins subprojects" - add views for remaining jenkins subprojects forgot beginning a yaml and a duplication definition add apex and sfc back in sectioned-views plugin not supported by jjb so removed custom views created in prod jenkins responded to cedric's request to remove moon and netready remove views for deprecated jobs Issue: RELENG-1831 Change-Id: I39ef0aabcf8ef4f3b3a378bb242ce0a7119acc85 Signed-off-by: Daniel Takamori <dtakamori@contractor.linuxfoundation.org>
2019-07-22Update git submodulesCédric Ollivier1-0/+0
* Update docs/submodules/releng from branch 'master' to 6a4f123e622a80d4a19f7428809fedb89893c1ed - Exclude behave tests from hunter and iruya For the time being, it's only part of master [1] [1] https://gerrit.opnfv.org/gerrit/#/c/68206/ Change-Id: I7c8baf4bd178668c99f15029eb425e63c3a3b5a2 Signed-off-by: Cédric Ollivier <cedric.ollivier@orange.com>
2019-07-21Update git submodulesCédric Ollivier1-0/+0
* Update docs/submodules/releng from branch 'master' to e5af792bda666731b875ffb8a79a1cf3aabb5727 - Stop blacklisting tempest tests in gates It reverts "Allow blacklisting tempest tests" [1] as all volume leaks were solved [2]. [1] https://gerrit.opnfv.org/gerrit/#/c/68020/ [2] https://bugs.launchpad.net/tempest/+bug/1829613 This reverts commit f90b8b66834b81b1022a05e14392857e77fccfca. Change-Id: Ic87de200482eb6c7aef878a1f23dcd43b79d1b10 Signed-off-by: Cédric Ollivier <cedric.ollivier@orange.com>
2019-07-20Update git submodulesCédric Ollivier1-0/+0
* Update docs/submodules/releng from branch 'master' to dfc0da009328f3aaffc887a603085a9c56767147 - Revert "Exclude latest rally_full and rally_jobs" This reverts commit f0b74187ee9e26a6b0be9976b1c5d35d9c96523b. Change-Id: I97466016e6cf296996558a45d4e4a5354d349e6f Signed-off-by: Cédric Ollivier <cedric.ollivier@orange.com>
2019-07-16Update git submodulesMark Beierl1-0/+0
* Update docs/submodules/releng from branch 'master' to e595f2da3fb955b3481a39367a26266cbd862f30 - Adds ARM Hunter Jobs Adds the missing docker build jobs for StorPerf on ARM. Change-Id: I5ed4a055b4f5f50309159c860ecdae93b1aa4b60 Signed-off-by: Mark Beierl <mbeierl@vmware.com>
2019-07-12Update git submodulesTrevor Bramwell1-0/+0
* Update docs/submodules/dovetail from branch 'master' to 7d4456beaf190bbd6bb935325cfe43a1df1c70f2 - Update OVP Support Email Address As the portals have moved from the opnfv.org domain to lfnetworking.org, the support address has changed as well from 'verified' to 'ovp-support'. Change-Id: I341093992e456ac90580b3b96206a402f98bf2d2 Signed-off-by: Trevor Bramwell <tbramwell@linuxfoundation.org>
2019-07-12Update git submodulesTrevor Bramwell1-0/+0
* Update docs/submodules/dovetail from branch 'master' to 7360cbb9d286d8fac22947ab918a7285fea9d570 - Update the Certification Workflow document These changes are at the request of Brandon Wick. Change-Id: Ieb4ea0164656e349451820071dc0c3d3f9bf67ac Signed-off-by: Trevor Bramwell <tbramwell@linuxfoundation.org>
2019-07-11Update git submodulesCédric Ollivier1-0/+0
* Update docs/submodules/releng from branch 'master' to 3de3c2d466fc6dc50b5f0f9ca2b4300eed4259b2 - Run the sixth sample in Xtesting gates Change-Id: I18033f737f93bd9c4680490f0a2ffbd7e2e5bffc Signed-off-by: Cédric Ollivier <cedric.ollivier@orange.com>
2019-07-10Update git submodulesCédric Ollivier1-0/+0
* Update docs/submodules/releng from branch 'master' to 1a632d79c86df67898619509dd822466f6122f47 - Run Functest K8s smoke test sequentially It also reorders xally_kubernetes and conformance. Change-Id: I5a9aab3f9f7cecd443b1246c8b8de7d148632a08 Signed-off-by: Cédric Ollivier <cedric.ollivier@orange.com>
2019-07-10Update git submodulesCédric Ollivier1-0/+0
* Update docs/submodules/releng from branch 'master' to 5141565bb09aedf33878648af08863b86e8dba27 - Remove functest-components containers They can be safely removed as gambia is no longer supported. Change-Id: I71b4201203b601e40b308e6a414b874f450f96dc Signed-off-by: Cédric Ollivier <cedric.ollivier@orange.com>
2019-07-10Update git submodulesMichael Polenchuk1-0/+0
* Update docs/submodules/releng from branch 'master' to adcb86b47d623600a06a0ec13615dd1d15ae9984 - [fuel] Bind functest's iruya container to master Change-Id: I9d1745718eec8f42c7a2792406bccf70f600f66b Signed-off-by: Michael Polenchuk <mpolenchuk@mirantis.com>
2019-07-10Update git submodulesCédric Ollivier1-0/+0
* Update docs/submodules/releng from branch 'master' to a62f077c802ff57a50f05a4d2b8389b7a300ef10 - Add xrally_kubernetes in Functest Kubernetes gates Change-Id: Ie34e8698a262be18f66f934955baa0ca9194d6a9 Signed-off-by: Cédric Ollivier <cedric.ollivier@orange.com>
2019-07-10Update git submodulesxudan1-0/+0
* Update docs/submodules/dovetail from branch 'master' to 1f36d6247578273197a4ba64b58b02b1ed837171 - Add Swagger UI for dovetail API Change-Id: If8f515b02f0372955739dd580967a3198930e98b Signed-off-by: xudan <xudan16@huawei.com>
2019-07-09Update git submodulesCédric Ollivier1-0/+0
* Update docs/submodules/releng from branch 'master' to 9040f15da60769caf40ad3364ca3a50bcbeedddf - Exclude functest-tempest from master gates Change-Id: I09bde2d35769c0045f72e3da56a085db6426e4b4 Signed-off-by: Cédric Ollivier <cedric.ollivier@orange.com>
2019-07-09Update git submodulesCedric Ollivier1-0/+0
* Update docs/submodules/releng from branch 'master' to 3cfccedf319071827990baae6156079974249afa - Merge "Exclude functest-tempest in master builds" - Exclude functest-tempest in master builds It's being removed and we do first merge that change to allow verifying the related patch in Functest [1] [1] https://gerrit.opnfv.org/gerrit/#/c/68167/ Change-Id: I2c069c65c771ef076556c2758ae003dba03c2f28 Signed-off-by: Cédric Ollivier <cedric.ollivier@orange.com>
2019-07-08Update git submodulesTrevor Bramwell1-0/+0
* Update docs/submodules/releng from branch 'master' to 49d61940222066a3e8f5d1491fc611558bb2788e - Merge "Barometer 8.1 release" - Barometer 8.1 release we skipped 8.0 Change-Id: I7eff94d1f4a90b9997c99f08b19d1064c98116c9 Signed-off-by: Matthias Runge <mrunge@redhat.com>
2019-07-08Update git submodulesTrevor Bramwell1-0/+0
* Update docs/submodules/releng from branch 'master' to 8fe135b39e5ccdb2f55fe5ff054597fda521a3f3 - Merge "Tagging Hunter 8.1 Release for IPv6" - Tagging Hunter 8.1 Release for IPv6 Change-Id: I9dee44495e21886917cb517bfee8c2c8cd9a1d32 Signed-off-by: BIN HU <bin.hu@att.com>
2019-07-06Update git submodulesCédric Ollivier1-0/+0
* Update docs/submodules/releng from branch 'master' to f0b74187ee9e26a6b0be9976b1c5d35d9c96523b - Exclude latest rally_full and rally_jobs Rally is sometimes failing when running vs python3. It will be excluded during the investigation to allow checking changes and containers. Change-Id: Ifbd02629e618b9a6969b321b4862fc76df3f3bc5 Signed-off-by: Cédric Ollivier <cedric.ollivier@orange.com>
2019-07-02Update git submodulesxudan1-0/+0
* Update docs/submodules/dovetail from branch 'master' to 1aafeb7eeef0a870d0c4cef95c929b66fd8ad991 - Update osinterop check list with Hunter scope Change-Id: If8ca533772ad85a3789f5f448adbeb16491c23b0 Signed-off-by: xudan <xudan16@huawei.com>
2019-07-02Update git submodulesxudan1-0/+0
* Update docs/submodules/dovetail from branch 'master' to 7cea09ab4718d9f307a32a261543c08de8244720 - Update trunk port list with Hunter and using blacklist 1. Using blacklist to avoid running some sub test cases 2. Update the sub test cases according to Functest Hunter scope Change-Id: I61d6d796dcdfe0fef41ba7578d0f8f2221414686 Signed-off-by: xudan <xudan16@huawei.com>
2019-07-02Update git submodulesxudan1-0/+0
* Update docs/submodules/dovetail from branch 'master' to 4f881e39e996e77d94c191d4e0d8209871709b82 - Use Functest blacklist to exclude the sub test cases of patrole 1. using blacklist to exclude some sub test cases 2. update the patrole scope according to Hunter using patrole 0.4.0 Change-Id: I32de419e482cf2f2d7289dba48155f3d09fdec91 Signed-off-by: xudan <xudan16@huawei.com>
2019-06-28Update git submodulesAlexandru Avadanii1-0/+0
* Update docs/submodules/releng from branch 'master' to 03547cdc309342c56133e4306de76b2e0df79734 - [fuel] Release opnfv-8.1.0 Change-Id: I3194ec7ce01d0572adcf64efe48cb84f772071cb Signed-off-by: Alexandru Avadanii <Alexandru.Avadanii@enea.com>
2019-06-28Update git submodulesCédric Ollivier1-0/+0
* Update docs/submodules/releng from branch 'master' to a1d9442b3c35042f292f118a4db1b898c6929a22 - Clean functest-kubernetes jjb It removes all debug data added by "Add debugs when calling gsutil" [1] and "Print debug infos in functest-kubernetes jjbs" [2] The issue came from former data dirs in http://artifacts.opnfv.org/ which changes logics [3]. All kubernetes latest results were removed to solve the issues. [1] https://gerrit.opnfv.org/gerrit/#/c/68145/ [2] https://gerrit.opnfv.org/gerrit/#/c/68113/ [3] https://cloud.google.com/storage/docs/gsutil/commands/cp Change-Id: I4be465b0b6f63bcd77e46440da715d4269d4e79f Signed-off-by: Cédric Ollivier <cedric.ollivier@orange.com>
2019-06-27Update git submodulesTrevor Bramwell1-0/+0
* Update docs/submodules/releng from branch 'master' to cc143b936c8337ee65c21e5fa78c1c56d2d833e1 - Merge "Add Docker jobs for Hunter" - Add Docker jobs for Hunter This removes jobs for all previous stable releases, and moves jobs from the gambia stream to hunter for the following projects: * barometer * bottlenecks * storperf Change-Id: Ica64b906f9a102c30878b541c89bee1624fbfd26 Signed-off-by: Trevor Bramwell <tbramwell@linuxfoundation.org>
2019-06-27Update git submodulesTrevor Bramwell1-0/+0
* Update docs/submodules/releng from branch 'master' to b54f720486510779253b3df54c24f535916f7037 - Merge "Create Stable Branch Jobs for container4nfv" - Create Stable Branch Jobs for container4nfv Change-Id: I2526a7cec3e1084868497ccf6cd41c8a7af9dbe0 Signed-off-by: jenkins-ci <jenkins-opnfv-ci@opnfv.org> Signed-off-by: Trevor Bramwell <tbramwell@linuxfoundation.org>
2019-06-27Update git submodulesCedric Ollivier1-0/+0
* Update docs/submodules/releng from branch 'master' to 52fe2bfcad5ce039fc8e512343d12a085a074e1f - Merge "Add debugs when calling gsutil" - Add debugs when calling gsutil Change-Id: I8e0618e344ade4eb692a15eab1eecfa0d479ba6f Signed-off-by: Cédric Ollivier <cedric.ollivier@orange.com>
id='n1564' href='#n1564'>1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996
/*
// Copyright (c) 2010-2017 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain 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.
*/

#include <unistd.h>
#include <string.h>

#include <rte_sched.h>
#include <rte_string_fns.h>
#include <rte_version.h>

#include "prox_malloc.h"
#include "version.h"
#include "defines.h"
#include "prox_args.h"
#include "prox_assert.h"
#include "prox_cfg.h"
#include "cfgfile.h"
#include "quit.h"
#include "log.h"
#include "parse_utils.h"
#include "prox_port_cfg.h"
#include "defaults.h"
#include "prox_lua.h"
#include "cqm.h"

#define MAX_RTE_ARGV 64
#define MAX_ARG_LEN  64

struct cfg_depr {
	const char *opt;
	const char *info;
};

/* Helper macro */
#define STR_EQ(s1, s2)	(!strcmp((s1), (s2)))

/* configuration files support */
static int get_rte_cfg(unsigned sindex, char *str, void *data);
static int get_global_cfg(unsigned sindex, char *str, void *data);
static int get_port_cfg(unsigned sindex, char *str, void *data);
static int get_defaults_cfg(unsigned sindex, char *str, void *data);
static int get_cache_set_cfg(unsigned sindex, char *str, void *data);
static int get_var_cfg(unsigned sindex, char *str, void *data);
static int get_lua_cfg(unsigned sindex, char *str, void *data);
static int get_core_cfg(unsigned sindex, char *str, void *data);

static const char *cfg_file = DEFAULT_CONFIG_FILE;
static struct rte_cfg    rte_cfg;
struct prox_cache_set_cfg  prox_cache_set_cfg[PROX_MAX_CACHE_SET];

static char format_err_str[1024];
static const char *err_str = "Unknown error";

static struct cfg_section eal_default_cfg = {
	.name   = "eal options",
	.parser = get_rte_cfg,
	.data   = &rte_cfg,
	.indexp[0]  = 0,
	.nbindex = 1,
	.error  = 0
};

static struct cfg_section port_cfg = {
	.name   = "port #",
	.parser = get_port_cfg,
	.data   = &prox_port_cfg,
	.indexp[0]  = 0,
	.nbindex = 1,
	.error  = 0
};

static struct cfg_section var_cfg = {
	.name   = "variables",
	.parser = get_var_cfg,
	.data   = 0,
	.indexp[0]  = 0,
	.nbindex = 1,
	.error  = 0
};

static struct cfg_section cache_set_cfg = {
	.name   = "cache set #",
	.parser = get_cache_set_cfg,
	.data   = &prox_cache_set_cfg,
	.indexp[0]  = 0,
	.nbindex = 1,
	.error  = 0
};

static struct cfg_section defaults_cfg = {
	.name   = "defaults",
	.parser = get_defaults_cfg,
	.data   = 0,
	.indexp[0]  = 0,
	.nbindex = 1,
	.error  = 0
};

static struct cfg_section settings_cfg = {
	.name   = "global",
	.parser = get_global_cfg,
	.data   = &prox_cfg,
	.indexp[0]  = 0,
	.nbindex = 1,
	.error  = 0
};

static struct cfg_section lua_cfg = {
	.name = "lua",
	.parser = get_lua_cfg,
	.raw_lines = 1,
	.indexp[0] = 0,
	.nbindex = 1,
	.error = 0,
};

static struct cfg_section core_cfg = {
	.name   = "core #",
	.parser = get_core_cfg,
	.data   = lcore_cfg_init,
	.indexp[0]  = 0,
	.nbindex = 1,
	.error  = 0
};

static void set_errf(const char *format, ...)
{
	va_list ap;
	va_start(ap, format);
	vsnprintf(format_err_str, sizeof(format_err_str), format, ap);
	va_end(ap);
	err_str = format_err_str;
}

/* [eal options] parser */
static int get_rte_cfg(__attribute__((unused))unsigned sindex, char *str, void *data)
{
	struct rte_cfg *pconfig = (struct rte_cfg *)data;

	if (str == NULL || pconfig == NULL) {
		return -1;
	}

	char *pkey = get_cfg_key(str);
	if (pkey == NULL) {
		set_errf("Missing key after option");
		return -1;
	}

	if (STR_EQ(str, "-m")) {
		return parse_int(&pconfig->memory, pkey);
	}
	if (STR_EQ(str, "-n")) {
		if (parse_int(&pconfig->force_nchannel, pkey)) {
			return -1;
		}
		if (pconfig->force_nchannel == 0) {
			set_errf("Invalid number of memory channels");
			return -1;
		}
		return 0;
	}
	if (STR_EQ(str, "-r")) {
		if (parse_int(&pconfig->force_nrank, pkey)) {
			return -1;
		}
		if (pconfig->force_nrank == 0 || pconfig->force_nrank > 16) {
			set_errf("Invalid number of memory ranks");
			return -1;
		}
		return 0;
	}
	/* debug options */
	if (STR_EQ(str, "no-pci")) {
		return parse_bool(&pconfig->no_pci, pkey);
	}
	if (STR_EQ(str, "no-hpet")) {
		return parse_bool(&pconfig->no_hpet, pkey);
	}
	if (STR_EQ(str, "no-shconf")) {
		return parse_bool(&pconfig->no_shconf, pkey);
	}
	if (STR_EQ(str, "no-huge")) {
		return parse_bool(&pconfig->no_hugetlbfs, pkey);
	}
	if (STR_EQ(str, "no-output")) {
		return parse_bool(&pconfig->no_output, pkey);
	}

	if (STR_EQ(str, "huge-dir")) {
		if (pconfig->hugedir) {
			free(pconfig->hugedir);
		}
		pconfig->hugedir = strdup(pkey);
		return 0;
	}

	if (STR_EQ(str, "eal")) {
		char eal[MAX_STR_LEN_PROC];
		if (pconfig->eal) {
			free(pconfig->eal);
			pconfig->eal = NULL;
		}
		if (parse_str(eal, pkey, sizeof(eal)))
			return -1;
		pkey = eal;
		strip_spaces(&pkey, 1);
		if (*pkey)
			pconfig->eal = strdup(pkey);
		return 0;
	}

	set_errf("Option '%s' is not known", str);
	return -1;
}

struct cfg_depr global_cfg_depr[] = {
	{"virtualization", "This is now set automatically if needed"},
	{"qinq_tag", "This option is deprecated"},
	{"wait on quit", "This is now set automatically if needed"},
	{"version", ""}
};

const char *get_cfg_dir(void)
{
	static char dir[PATH_MAX];
	size_t end = strlen(cfg_file) - 1;
	while (end > 0 && cfg_file[end] != '/')
		end--;

	strncpy(dir, cfg_file, end);
	return dir;
}

static int get_lua_cfg(__attribute__((unused)) unsigned sindex, __attribute__((unused)) char *str, __attribute__((unused)) void *data)
{
	int status;
	char cwd[1024];
	if (NULL == getcwd(cwd, sizeof(cwd))) {
		set_errf("Failed to get current directory while loading Lua file\n");
		return -1;
	}
	status = chdir(get_cfg_dir());
	if (status) {
		set_errf("Failed to change directory to '%s' while loading Lua file\n", get_cfg_dir());
		return -1;
	}

	struct lua_State *l = prox_lua();

	char str_cpy[1024];
	strncpy(str_cpy, str, sizeof(str_cpy));
	uint32_t len = strlen(str_cpy);
	str_cpy[len++] = '\n';
	str_cpy[len++] = 0;

	status = luaL_loadstring(l, str_cpy);
	if (status) {
		set_errf("Lua error: '%s'\n", lua_tostring(l, -1));
		status = chdir(cwd);
		return -1;
	}

	status = lua_pcall(l, 0, LUA_MULTRET, 0);
	if (status) {
		set_errf("Lua error: '%s'\n", lua_tostring(l, -1));
		status = chdir(cwd);
		return -1;
	}

	status = chdir(cwd);
	if (status) {
		set_errf("Failed to restore current directory to '%s' while loading Lua file\n", cwd);
		return -1;
	}

	return 0;
}

/* [global] parser */
static int get_global_cfg(__attribute__((unused))unsigned sindex, char *str, void *data)
{
	struct prox_cfg *pset = (struct prox_cfg *)data;

	if (str == NULL || pset == NULL) {
		return -1;
	}

	char *pkey = get_cfg_key(str);
	if (pkey == NULL) {
		set_errf("Missing key after option");
		return -1;
	}

	for (uint32_t i = 0; i < RTE_DIM(global_cfg_depr); ++i) {
		if (STR_EQ(str, global_cfg_depr[i].opt)) {
			set_errf("Option '%s' is deprecated%s%s",
				 global_cfg_depr[i].opt, strlen(global_cfg_depr[i].info)? ": ": "", global_cfg_depr[i].info);
			return -1;
		}
	}

	if (STR_EQ(str, "name")) {
		return parse_str(pset->name, pkey, sizeof(pset->name));
	}

	if (STR_EQ(str, "start time")) {
		return parse_int(&pset->start_time, pkey);
	}

	if (STR_EQ(str, "duration time")) {
		return parse_int(&pset->duration_time, pkey);
	}

	if (STR_EQ(str, "shuffle")) {
		return parse_flag(&pset->flags, DSF_SHUFFLE, pkey);
	}
	if (STR_EQ(str, "disable cmt")) {
		return parse_flag(&pset->flags, DSF_DISABLE_CMT, pkey);
	}
	if (STR_EQ(str, "mp rings")) {
		return parse_flag(&pset->flags, DSF_MP_RINGS, pkey);
	}
	if (STR_EQ(str, "enable bypass")) {
		return parse_flag(&pset->flags, DSF_ENABLE_BYPASS, pkey);
	}

	if (STR_EQ(str, "cpe table map")) {
		/* The config defined ports through 0, 1, 2 ... which
		   need to be associated with ports. This is done
		   through defining it using "cpe table map=" */
		return parse_port_name_list((uint32_t*)pset->cpe_table_ports, NULL, PROX_MAX_PORTS, pkey);
	}

	if (STR_EQ(str, "pre cmd")) {
		return system(pkey);
	}

	if (STR_EQ(str, "unique mempool per socket")) {
		return parse_flag(&pset->flags, UNIQUE_MEMPOOL_PER_SOCKET, pkey);
	}

	if (STR_EQ(str, "log buffer size")) {
		if (parse_kmg(&pset->logbuf_size, pkey)) {
			return -1;
		}
		plog_info("Logging to buffer with size = %d\n", pset->logbuf_size);
		return 0;
	}

	set_errf("Option '%s' is not known", str);
	return -1;
}

/* [variable] parser */
static int get_var_cfg(__attribute__((unused)) unsigned sindex, char *str, __attribute__((unused)) void *data)
{
	return add_var(str, get_cfg_key(str), 0);
}

/* [defaults] parser */
static int get_defaults_cfg(__attribute__((unused)) unsigned sindex, char *str, __attribute__((unused)) void *data)
{
	uint32_t val;
	char *pkey;

	pkey = get_cfg_key(str);
	if (pkey == NULL) {
		set_errf("Missing key after option");
		return -1;
	}

	if (STR_EQ(str, "mempool size")) {

		if (parse_kmg(&val, pkey)) {
			return -1;
		}

		for (uint8_t lcore_id = 0; lcore_id < RTE_MAX_LCORE; ++lcore_id) {
			struct lcore_cfg *cur_lcore_cfg_init = &lcore_cfg_init[lcore_id];
			cur_lcore_cfg_init->id = lcore_id;
			for (uint8_t task_id = 0; task_id < MAX_TASKS_PER_CORE; ++task_id) {
				struct task_args *targ = &cur_lcore_cfg_init->targs[task_id];
				targ->nb_mbuf = val;
				targ->id = task_id;
			}
		}
		return 0;
	}

	if (STR_EQ(str, "qinq tag")) {
		for (uint8_t lcore_id = 0; lcore_id < RTE_MAX_LCORE; ++lcore_id) {
			struct lcore_cfg *cur_lcore_cfg_init = &lcore_cfg_init[lcore_id];
			cur_lcore_cfg_init->id = lcore_id;
			for (uint8_t task_id = 0; task_id < MAX_TASKS_PER_CORE; ++task_id) {
				struct task_args *targ = &cur_lcore_cfg_init->targs[task_id];
				parse_int(&targ->qinq_tag, pkey);
			}
		}
		return 0;
	}
	if (STR_EQ(str, "memcache size")) {

		if (parse_kmg(&val, pkey)) {
			return -1;
		}

		for (uint8_t lcore_id = 0; lcore_id < RTE_MAX_LCORE; ++lcore_id) {
			struct lcore_cfg *cur_lcore_cfg_init = &lcore_cfg_init[lcore_id];
			cur_lcore_cfg_init->id = lcore_id;
			for (uint8_t task_id = 0; task_id < MAX_TASKS_PER_CORE; ++task_id) {
				struct task_args *targ = &cur_lcore_cfg_init->targs[task_id];
				targ->nb_cache_mbuf = val;
			}
		}
		return 0;
	}

	set_errf("Option '%s' is not known", str);
	return -1;
}

/* [cache set] parser */
static int get_cache_set_cfg(unsigned sindex, char *str, void *data)
{
	struct prox_cache_set_cfg *cfg = (struct prox_cache_set_cfg *)data;

	uint8_t cur_if = sindex & ~CFG_INDEXED;

	if (cur_if >= PROX_MAX_CACHE_SET) {
		set_errf("Cache set ID is too high (max allowed %d)", PROX_MAX_CACHE_SET - 1 );
		return -1;
	}

	cfg = &prox_cache_set_cfg[cur_if];

	if (str == NULL || data == NULL) {
		return -1;
	}

	char *pkey = get_cfg_key(str);

	if (pkey == NULL) {
		set_errf("Missing key after option");
		return -1;
	}

	if (STR_EQ(str, "mask")) {
                uint32_t val;
                int err = parse_int(&val, pkey);
                if (err) {
                        return -1;
                }
                cfg->mask = val;
                cfg->socket_id = -1;
		plog_info("\tCache set %d has mask %x\n", cur_if, cfg->mask);
                return 0;
	}
        return 0;
}

/* [port] parser */
static int get_port_cfg(unsigned sindex, char *str, void *data)
{
	struct prox_port_cfg *cfg = (struct prox_port_cfg *)data;

	uint8_t cur_if = sindex & ~CFG_INDEXED;

	if (cur_if >= PROX_MAX_PORTS) {
		set_errf("Port ID is too high (max allowed %d)", PROX_MAX_PORTS - 1 );
		return -1;
	}

	cfg = &prox_port_cfg[cur_if];

	if (str == NULL || data == NULL) {
		return -1;
	}

	char *pkey = get_cfg_key(str);

	if (pkey == NULL) {
		set_errf("Missing key after option");
		return -1;
	}

	if (STR_EQ(str, "mac")) {
		if (STR_EQ(pkey, "hardware")) {
			cfg->type = PROX_PORT_MAC_HW;
		}
		else if (STR_EQ(pkey, "random")) {
			cfg->type = PROX_PORT_MAC_RAND;
		}
		else {
			cfg->type = PROX_PORT_MAC_SET;
			if (parse_mac(&cfg->eth_addr, pkey)) {
				return -1;
			}
		}
	}
	else if (STR_EQ(str, "name")) {
		uint32_t val;
		strncpy(cfg->name, pkey, MAX_NAME_SIZE);
		PROX_ASSERT(cur_if < PROX_MAX_PORTS);
		return add_port_name(cur_if, pkey);
	}
	else if (STR_EQ(str, "rx desc")) {
		return parse_int(&cfg->n_rxd, pkey);
	}
	else if (STR_EQ(str, "tx desc")) {
		return parse_int(&cfg->n_txd, pkey);
	}
	else if (STR_EQ(str, "promiscuous")) {
		uint32_t val;
		if (parse_bool(&val, pkey)) {
			return -1;
		}
		cfg->promiscuous = val;
	}
	else if (STR_EQ(str, "lsc")) {
		cfg->lsc_set_explicitely = 1;
		uint32_t val;
		if (parse_bool(&val, pkey)) {
			return -1;
		}
		cfg->lsc_val = val;
	}
	else if (STR_EQ(str, "strip crc")) {
		uint32_t val;
		if (parse_bool(&val, pkey)) {
			return -1;
		}
		cfg->port_conf.rxmode.hw_strip_crc = val;
	}
	else if (STR_EQ(str, "rss")) {
		uint32_t val;
		if (parse_bool(&val, pkey)) {
			return -1;
		}
		if (val) {
			cfg->port_conf.rxmode.mq_mode = ETH_MQ_RX_RSS;
			cfg->port_conf.rx_adv_conf.rss_conf.rss_hf = ETH_RSS_IPV4;
		}
	}
	else if (STR_EQ(str, "rx_ring")) {
		parse_str(cfg->rx_ring, pkey, sizeof(cfg->rx_ring));
	}
	else if (STR_EQ(str, "tx_ring")) {
		parse_str(cfg->tx_ring, pkey, sizeof(cfg->tx_ring));
	}

	return 0;
}

static enum police_action str_to_color(const char *str)
{
	if (STR_EQ(str, "green"))
		return ACT_GREEN;
	if (STR_EQ(str, "yellow"))
		return ACT_YELLOW;
	if (STR_EQ(str, "red"))
		return ACT_RED;
	if (STR_EQ(str, "drop"))
		return ACT_DROP;
	return ACT_INVALID;
}

struct cfg_depr task_cfg_depr[] = {
	{"sig", ""},
};

struct cfg_depr core_cfg_depr[] = {
	{"do sig", ""},
	{"lat", ""},
	{"network side", ""},
};

/* [core] parser */
static int get_core_cfg(unsigned sindex, char *str, void *data)
{
	char *pkey;
	struct lcore_cfg *lconf = (struct lcore_cfg *)data;

	if (str == NULL || lconf == NULL || !(sindex & CFG_INDEXED)) {
		return -1;
	}

	pkey = get_cfg_key(str);
	if (pkey == NULL) {
		set_errf("Missing key after option");
		return -1;
	}

	uint32_t ncore = sindex & ~CFG_INDEXED;
	if (ncore >= RTE_MAX_LCORE) {
		set_errf("Core index too high (max allowed %d)", RTE_MAX_LCORE - 1);
		return -1;
	}

	lconf = &lconf[ncore];

	for (uint32_t i = 0; i < RTE_DIM(core_cfg_depr); ++i) {
		if (STR_EQ(str, core_cfg_depr[i].opt)) {
			set_errf("Option '%s' is deprecated%s%s",
				 core_cfg_depr[i].opt, strlen(core_cfg_depr[i].info)? ": ": "", core_cfg_depr[i].info);
			return -1;
		}
	}

	char buff[128];
	lcore_to_socket_core_ht(ncore, buff, sizeof(buff));
	set_self_var(buff);
	if (STR_EQ(str, "task")) {

		uint32_t val;
		if (parse_int(&val, pkey)) {
			return -1;
		}
		if (val >= MAX_TASKS_PER_CORE) {
			set_errf("Too many tasks for core (max allowed %d)", MAX_TASKS_PER_CORE - 1);
			return -1;
		}
		if (val != lconf->n_tasks_all) {
			set_errf("Task ID skipped or defined twice");
			return -1;
		}

		lconf->active_task = val;

		lconf->targs[lconf->active_task].task = lconf->active_task;

		if (lconf->n_tasks_all < lconf->active_task + 1) {
			lconf->n_tasks_all = lconf->active_task + 1;
		}
		return 0;
	}

	struct task_args *targ = &lconf->targs[lconf->active_task];
	if (STR_EQ(str, "tx ports from routing table")) {
		uint32_t vals[PROX_MAX_PORTS];
		uint32_t n_if;
		if (!(targ->task_init->flag_features & TASK_FEATURE_ROUTING)) {
			set_errf("tx port form route not supported mode %s",  targ->task_init->mode_str);
			return -1;
		}

		if (parse_port_name_list(vals, &n_if, PROX_MAX_PORTS, pkey)) {
			return -1;
		}

		for (uint8_t i = 0; i < n_if; ++i) {
			targ->tx_port_queue[i].port = vals[i];
			targ->nb_txports++;
		}
		targ->runtime_flags |= TASK_ROUTING;
		return 0;
	}
	if (STR_EQ(str, "tx ports from cpe table")) {
		uint32_t vals[PROX_MAX_PORTS];
		int n_remap = -1;
		uint32_t ret;
		uint32_t val;
		char* mapping_str = strstr(pkey, " remap=");

		if (mapping_str != NULL) {
			*mapping_str = 0;
			mapping_str += strlen(" remap=");
			n_remap = parse_remap(targ->mapping, mapping_str);
		}

		if (parse_port_name_list(vals, &ret, PROX_MAX_PORTS, pkey)) {
			return -1;
		}

		if (n_remap != -1 && ret != (uint32_t)n_remap) {
			set_errf("Expected %d remap elements but had %d", n_remap, ret);
			return -1;
		}

		for (uint8_t i = 0; i < ret; ++i) {
			targ->tx_port_queue[i].port = vals[i];

			/* default mapping this case is port0 -> port0 */
			if (n_remap == -1) {
				targ->mapping[vals[i]] = i;
			}
		}

		targ->nb_txports = ret;

		return 0;
	}
	if (STR_EQ(str, "tx cores from routing table")) {
		if (!(targ->task_init->flag_features & TASK_FEATURE_ROUTING)) {
			set_errf("tx port form route not supported mode %s",  targ->task_init->mode_str);
			return -1;
		}

		struct core_task_set *cts = &targ->core_task_set[0];

		if (parse_task_set(cts, pkey))
			return -1;

		if (cts->n_elems > MAX_WT_PER_LB) {
			set_errf("Maximum worker threads allowed is %u but have %u", MAX_WT_PER_LB, cts->n_elems);
			return -1;
		}

		targ->nb_worker_threads = cts->n_elems;
		targ->nb_txrings = cts->n_elems;

		if (targ->nb_txrings > MAX_RINGS_PER_TASK) {
			set_errf("Maximum allowed TX rings is %u but have %u", MAX_RINGS_PER_TASK, targ->nb_txrings);
			return -1;
		}

		targ->runtime_flags |= TASK_ROUTING;
		return 0;
	}
	if (STR_EQ(str, "tx cores from cpe table")) {
		struct core_task_set *core_task_set =  &targ->core_task_set[0];
		int ret, ret2;
		char *mapping_str;

		mapping_str = strstr(pkey, " remap=");
		if (mapping_str == NULL) {
			set_errf("There is no default mapping for tx cores from cpe table. Please specify it through remap=");
			return -1;
		}
		*mapping_str = 0;
		mapping_str += strlen(" remap=");
		ret = parse_remap(targ->mapping, mapping_str);
		if (ret <= 0) {
			return -1;
		}

		struct core_task_set *cts = &targ->core_task_set[0];

		if (parse_task_set(cts, pkey))
			return -1;
		if (cts->n_elems > MAX_RINGS_PER_TASK) {
			set_errf("Maximum cores to route to is %u\n", MAX_RINGS_PER_TASK);
			return -1;
		}

		targ->nb_txrings = cts->n_elems;

		if (ret != targ->nb_txrings) {
			set_errf("Expecting same number of remaps as cores\n", str);
			return -1;
		}
		return 0;
	}

	if (STR_EQ(str, "delay ms")) {
		if (targ->delay_us) {
			set_errf("delay ms and delay us are mutually exclusive\n", str);
			return -1;
		}
		uint32_t delay_ms;
		int rc = parse_int(&delay_ms, pkey);
		targ->delay_us = delay_ms * 1000;
		return rc;
	}
	if (STR_EQ(str, "delay us")) {
		if (targ->delay_us) {
			set_errf("delay ms and delay us are mutually exclusive\n", str);
			return -1;
		}
		return parse_int(&targ->delay_us, pkey);
	}
	if (STR_EQ(str, "random delay us")) {
		return parse_int(&targ->random_delay_us, pkey);
	}
	if (STR_EQ(str, "cpe table timeout ms")) {
		return parse_int(&targ->cpe_table_timeout_ms, pkey);
	}
	if (STR_EQ(str, "ctrl path polling frequency")) {
		int rc = parse_int(&targ->ctrl_freq, pkey);
		if (rc == 0) {
			if (targ->ctrl_freq == 0) {
				set_errf("ctrl frequency must be non null.");
				return -1;
			}
		}
		return rc;
	}

	if (STR_EQ(str, "handle arp")) {
		return parse_flag(&targ->runtime_flags, TASK_CTRL_HANDLE_ARP, pkey);
	}
	if (STR_EQ(str, "fast path handle arp")) {
		return parse_flag(&targ->runtime_flags, TASK_FP_HANDLE_ARP, pkey);
	}
	if (STR_EQ(str, "multiple arp")) {
		return parse_flag(&targ->flags, TASK_MULTIPLE_MAC, pkey);
	}

	/* Using tx port name, only a _single_ port can be assigned to a task. */
	if (STR_EQ(str, "tx port")) {
		if (targ->nb_txports > 0) {
			set_errf("Only one tx port can be defined per task. Use a LB task or routing instead.");
			return -1;
		}

		uint32_t n_if = 0;
		uint32_t ports[PROX_MAX_PORTS];

		if(parse_port_name_list(ports, &n_if, PROX_MAX_PORTS, pkey)) {
			return -1;
		}

		PROX_ASSERT(n_if-1 < PROX_MAX_PORTS);

                for (uint8_t i = 0; i < n_if; ++i) {
                        targ->tx_port_queue[i].port = ports[i];
                        targ->nb_txports++;
                }

		if (n_if > 1) {
			targ->nb_worker_threads = targ->nb_txports;
		}

		return 0;
	}
	if (STR_EQ(str, "rx ring")) {
		uint32_t val;
		int err = parse_bool(&val, pkey);
		if (!err && val && targ->rx_port_queue[0].port != OUT_DISCARD) {
			set_errf("Can't read both from internal ring and external port from the same task. Use multiple tasks instead.");
			return -1;
		}

		return parse_flag(&targ->flags, TASK_ARG_RX_RING, pkey);
	}
	if (STR_EQ(str, "private")) {
		return parse_bool(&targ->use_src, pkey);
	}
	if (STR_EQ(str, "use src ip")) {
		return parse_bool(&targ->use_src, pkey);
	}
	if (STR_EQ(str, "nat table")) {
		return parse_str(targ->nat_table, pkey, sizeof(targ->nat_table));
	}
	if (STR_EQ(str, "rules")) {
		return parse_str(targ->rules, pkey, sizeof(targ->rules));
	}
	if (STR_EQ(str, "route table")) {
		return parse_str(targ->route_table, pkey, sizeof(targ->route_table));
	}
	if (STR_EQ(str, "dscp")) {
		return parse_str(targ->dscp, pkey, sizeof(targ->dscp));
	}
	if (STR_EQ(str, "tun_bindings")) {
		return parse_str(targ->tun_bindings, pkey, sizeof(targ->tun_bindings));
	}
	if (STR_EQ(str, "cpe table")) {
		return parse_str(targ->cpe_table_name, pkey, sizeof(targ->cpe_table_name));
	}
	if (STR_EQ(str, "user table")) {
		return parse_str(targ->user_table, pkey, sizeof(targ->user_table));
	}
	if (STR_EQ(str, "streams")) {
		return parse_str(targ->streams, pkey, sizeof(targ->streams));
	}
	if (STR_EQ(str, "local lpm")) {
		return parse_flag(&targ->flags, TASK_ARG_LOCAL_LPM, pkey);
	}
	if (STR_EQ(str, "drop")) {
		return parse_flag(&targ->flags, TASK_ARG_DROP, pkey);
	}
	if (STR_EQ(str, "loop")) {
		parse_flag(&targ->loop, 1, pkey);
		return parse_flag(&targ->loop, 1, pkey);
	}
	if (STR_EQ(str, "qinq")) {
		return parse_flag(&targ->flags, TASK_ARG_QINQ_ACL, pkey);
	}
	if (STR_EQ(str, "bps")) {
		return parse_u64(&targ->rate_bps, pkey);
	}
	if (STR_EQ(str, "random")) {
		return parse_str(targ->rand_str[targ->n_rand_str++], pkey, sizeof(targ->rand_str[0]));
	}
	if (STR_EQ(str, "rand_offset")) {
		if (targ->n_rand_str == 0) {
			set_errf("No random defined previously (use random=...)");
			return -1;
		}

		return parse_int(&targ->rand_offset[targ->n_rand_str - 1], pkey);
	}
	if (STR_EQ(str, "keep src mac")) {
		return parse_flag(&targ->flags, DSF_KEEP_SRC_MAC, pkey);
	}
	if (STR_EQ(str, "pcap file")) {
		return parse_str(targ->pcap_file, pkey, sizeof(targ->pcap_file));
	}
	if (STR_EQ(str, "pkt inline")) {
		char pkey2[MAX_CFG_STRING_LEN];
		if (parse_str(pkey2, pkey, sizeof(pkey2)) != 0) {
			set_errf("Error while parsing pkt line, too long\n");
			return -1;
		}

		const size_t pkey_len = strlen(pkey2);
		targ->pkt_size = 0;

		for (size_t i = 0; i < pkey_len; ++i) {
			if (pkey2[i] == ' ')
				continue;

			if (i + 1 == pkey_len) {
				set_errf("Incomplete byte at character %z", i);
				return -1;
			}

			uint8_t byte = 0;

			if (pkey2[i] >= '0' && pkey2[i] <= '9') {
				byte = (pkey2[i] - '0') << 4;
			}
			else if (pkey2[i] >= 'a' && pkey2[i] <= 'f') {
				byte = (pkey2[i] - 'a' + 10) << 4;
			}
			else if (pkey2[i] >= 'A' && pkey2[i] <= 'F') {
				byte = (pkey2[i] - 'A' + 10) << 4;
			}
			else {
				set_errf("Invalid character in pkt inline at byte %d (%c)", i, pkey2[i]);
				return -1;
			}

			if (pkey2[i + 1] >= '0' && pkey2[i + 1] <= '9') {
				byte |= (pkey2[i + 1] - '0');
			}
			else if (pkey2[i + 1] >= 'a' && pkey2[i + 1] <= 'f') {
				byte |= (pkey2[i + 1] - 'a' + 10);
			}
			else if (pkey2[i + 1] >= 'A' && pkey2[i + 1] <= 'F') {
				byte |= (pkey2[i + 1] - 'A' + 10);
			}
			else {
				set_errf("Invalid character in pkt inline at byte %d (%c)", i, pkey2[i + 1]);
				return -1;
			}
			if (targ->pkt_size == sizeof(targ->pkt_inline)) {
				set_errf("Inline packet definition can't be longer than 1518");
			}

			targ->pkt_inline[targ->pkt_size++] = byte;
			i += 1;
		}

		return 0;
	}
	if (STR_EQ(str, "accuracy limit nsec")) {
		return parse_int(&targ->accuracy_limit_nsec, pkey);
	}
	if (STR_EQ(str, "latency bucket size")) {
		return parse_int(&targ->bucket_size, pkey);
	}
	if (STR_EQ(str, "latency buffer size")) {
		return parse_int(&targ->latency_buffer_size, pkey);
	}
	if (STR_EQ(str, "accuracy pos")) {
		return parse_int(&targ->accur_pos, pkey);
	}
	if (STR_EQ(str, "signature")) {
		return parse_int(&targ->sig, pkey);
	}
	if (STR_EQ(str, "signature pos")) {
		return parse_int(&targ->sig_pos, pkey);
	}
	if (STR_EQ(str, "lat pos")) {
		targ->lat_enabled = 1;
		return parse_int(&targ->lat_pos, pkey);
	}
	if (STR_EQ(str, "packet id pos")) {
		return parse_int(&targ->packet_id_pos, pkey);
	}
	if (STR_EQ(str, "probability")) {
		float probability;
		int rc = parse_float(&probability, pkey);
		if (probability == 0) {
			set_errf("Probability must be != 0\n");
			return -1;
		} else if (probability > 100.0) {
			set_errf("Probability must be < 100\n");
			return -1;
		}
		targ->probability = probability * 10000;
		return rc;
	}
	if (STR_EQ(str, "concur conn")) {
		return parse_int(&targ->n_concur_conn, pkey);
	}
	if (STR_EQ(str, "max setup rate")) {
		return parse_int(&targ->max_setup_rate, pkey);
	}
	if (STR_EQ(str, "pkt size")) {
		return parse_int(&targ->pkt_size, pkey);
	}
	if (STR_EQ(str, "min bulk size")) {
		return parse_int(&targ->min_bulk_size, pkey);
	}
	if (STR_EQ(str, "max bulk size")) {
		return parse_int(&targ->max_bulk_size, pkey);
	}
	if (STR_EQ(str, "rx port")) {
		if (targ->flags & TASK_ARG_RX_RING) {
			set_errf("Can't read both from internal ring and external port from the same task. Use multiple tasks instead.");
			return -1;
		}
		uint32_t vals[PROX_MAX_PORTS];
		uint32_t n_if;

                if (parse_port_name_list(vals, &n_if, PROX_MAX_PORTS, pkey)) {
                        return -1;
                }

                for (uint8_t i = 0; i < n_if; ++i) {
			PROX_ASSERT(vals[i] < PROX_MAX_PORTS);
                        targ->rx_port_queue[i].port = vals[i];
                        targ->nb_rxports++;
                }
		return 0;
	}

	if (STR_EQ(str, "mode")) {
		/* Check deprecated task modes */
		char mode[255];
		int ret = parse_str(mode, pkey, sizeof(mode));
		if (ret)
			return ret;

		for (uint32_t i = 0; i < RTE_DIM(task_cfg_depr); ++i) {
			if (STR_EQ(mode, task_cfg_depr[i].opt)) {
				set_errf("Task mode '%s' is deprecated%s%s",
					 task_cfg_depr[i].opt, strlen(task_cfg_depr[i].info)? ": ": "", task_cfg_depr[i].info);
				return -1;
			}
		}

		/* master is a special mode that is always needed (cannot be turned off) */
		if (STR_EQ(mode, "master")) {
			prox_cfg.master = ncore;
			targ->mode = MASTER;
			if (lconf->n_tasks_all > 1 || targ->task != 0) {
				set_errf("Master core can only have one task\n");
				return -1;
			}
			// Initialize number of tasks to 1 for master, even if no task specified
			lconf->n_tasks_all = 1;
			lconf->active_task = 0;
			lconf->targs[lconf->active_task].task = 0;
			struct task_init* task_init = to_task_init(mode, "");
			if (task_init) {
				targ->mode = task_init->mode;
			}
			targ->task_init = task_init;
			return 0;
		}

		struct task_init* task_init = to_task_init(mode, "");
		if (task_init) {
			targ->mode = task_init->mode;
		}
		else {
			set_errf("Task mode '%s' is invalid", mode);
			tasks_list();
			return -1;
		}
		targ->task_init = task_init;
		return 0;
	}
	if (STR_EQ(str, "users")) {
		return parse_int(&targ->n_flows, pkey);
	}

	if (STR_EQ(str, "mark")) {
		return parse_flag(&targ->runtime_flags, TASK_MARK, pkey);
	}

	if (STR_EQ(str, "mark green")) {
		return parse_int(&targ->marking[0], pkey);
	}

	if (STR_EQ(str, "mark yellow")) {
		return parse_int(&targ->marking[1], pkey);
	}

	if (STR_EQ(str, "mark red")) {
		return parse_int(&targ->marking[2], pkey);
	}

	if (STR_EQ(str, "tx cores")) {
		uint8_t dest_task = 0;
		/* if user did not specify, dest_port is left at default (first type) */
		uint8_t dest_proto = 0;
		uint8_t ctrl = CTRL_TYPE_DP;
		char *task_str = strstr(pkey, "proto=");
		if (task_str) {
			task_str += strlen("proto=");

			if (STR_EQ(task_str, "ipv4")) {
				dest_proto = IPV4;
			}
			else if (STR_EQ(task_str, "arp")) {
				dest_proto = ARP;
			}
			else if (STR_EQ(task_str, "ipv6")) {
				dest_proto = IPV6;
			}
			else {
				set_errf("proto needs to be either ipv4, arp or ipv6");
				return -1;
			}

		}

		task_str = strstr(pkey, "task=");

		if (task_str) {
			--task_str;
			*task_str = 0;
			task_str++;
			task_str += strlen("task=");
			char *task_str_end = strstr(task_str, " ");
			if (task_str_end) {
				*task_str_end = 0;
			}
			if (0 == strlen(task_str)) {
				set_errf("Invalid task= syntax");
				return -1;
			}

			switch (task_str[strlen(task_str) - 1]) {
			case 'p':
				ctrl = CTRL_TYPE_PKT;
				break;
			case 'm':
				ctrl = CTRL_TYPE_MSG;
				break;
			case '\n':
			case 0:
				break;
			default:
				if (task_str[strlen(task_str) -1] < '0' ||
				    task_str[strlen(task_str) -1] > '9') {
					set_errf("Unknown ring type %c.\n",
						 task_str[strlen(task_str) - 1]);
					return -1;
				}
			}

			dest_task = atoi(task_str);
			if (dest_task >= MAX_TASKS_PER_CORE) {
				set_errf("Destination task too high (max allowed %d)", MAX_TASKS_PER_CORE - 1);
				return -1;
			}
		}
		else {
			dest_task = 0;
		}

		struct core_task_set *cts = &targ->core_task_set[dest_proto];

		if (parse_task_set(cts, pkey))
			return -1;

		if (cts->n_elems > MAX_WT_PER_LB) {
			set_errf("Too many worker threads (max allowed %d)", MAX_WT_PER_LB - 1);
			return -1;
		}

		targ->nb_worker_threads = cts->n_elems;
		targ->nb_txrings += cts->n_elems;

		return 0;
	}
	if (STR_EQ(str, "tx crc")) {
		return parse_flag(&targ->runtime_flags, TASK_TX_CRC, pkey);
	}
	if (STR_EQ(str, "ring size")) {
		return parse_int(&targ->ring_size, pkey);
	}
	if (STR_EQ(str, "mempool size")) {
		return parse_kmg(&targ->nb_mbuf, pkey);
	}

	else if (STR_EQ(str, "mbuf size")) {
		targ->mbuf_size_set_explicitely = 1;
		return parse_int(&targ->mbuf_size, pkey);
	}
	if (STR_EQ(str, "memcache size")) {
		return parse_kmg(&targ->nb_cache_mbuf, pkey);
	}

	if (STR_EQ(str, "byte offset")) {
		return parse_int(&targ->byte_offset, pkey);
	}

	if (STR_EQ(str, "name")) {
		return parse_str(lconf->name, pkey, sizeof(lconf->name));
	}
	/* MPLS configuration */
	if (STR_EQ(str, "untag mpls")) {
		return parse_flag(&targ->runtime_flags, TASK_MPLS_TAGGING, pkey);
	}

	if (STR_EQ(str, "add mpls")) {
		return parse_flag(&targ->runtime_flags, TASK_MPLS_TAGGING, pkey);
	}

	if (STR_EQ(str, "ether type")) {
		return parse_int(&targ->etype, pkey);
	}

	if (STR_EQ(str, "cache set")) {
		return parse_int(&lconf->cache_set, pkey);
	}

	if (STR_EQ(str, "sub mode")) {
		const char* mode_str = targ->task_init->mode_str;
		const char *sub_mode_str = pkey;

		targ->task_init = to_task_init(mode_str, sub_mode_str);
		if (!targ->task_init) {
			if (strcmp(sub_mode_str, "l3") != 0) {
				set_errf("sub mode %s not supported for mode %s", sub_mode_str, mode_str);
				return -1;
			}
			targ->task_init = to_task_init(mode_str, "");
			if (!targ->task_init) {
				set_errf("sub mode %s not supported for mode %s", sub_mode_str, mode_str);
				return -1;
			}
		}
		if (strcmp(sub_mode_str, "l3") == 0) {
			prox_cfg.flags |= DSF_CTRL_PLANE_ENABLED;
			targ->task_init->flag_features |= TASK_FEATURE_L3;
			strcpy(targ->task_init->sub_mode_str, "l3");
		}
		return 0;
	}

	if (STR_EQ(str, "mempool name")) {
		return parse_str(targ->pool_name, pkey, sizeof(targ->pool_name));
	}
	if (STR_EQ(str, "dpi engine")) {
		return parse_str(targ->dpi_engine_path, pkey, sizeof(targ->dpi_engine_path));
	}
	if (STR_EQ(str, "dpi engine arg")) {
		return parse_str(targ->dpi_engine_args[targ->n_dpi_engine_args++], pkey,
				 sizeof(targ->dpi_engine_args[0]));
	}
	if (STR_EQ(str, "dst mac")) { /* destination MAC address to be used for packets */
		if (parse_mac(&targ->edaddr, pkey)) {
			if (STR_EQ(pkey, "no")) {
				targ->flags |= TASK_ARG_DO_NOT_SET_DST_MAC;
				return 0;
			}
			if (STR_EQ(pkey, "packet") == 0)
				return -1;
			else
				return 0;
		}
		targ->flags |= TASK_ARG_DST_MAC_SET;
		return 0;
	}
	if (STR_EQ(str, "src mac")) {
		if (parse_mac(&targ->esaddr, pkey)) {
			if (STR_EQ(pkey, "no")) {
				targ->flags |= TASK_ARG_DO_NOT_SET_SRC_MAC;
				return 0;
			}
			else if (STR_EQ(pkey, "packet"))
				return 0;
			else if (STR_EQ(pkey, "packet")) {
				targ->flags |= TASK_ARG_HW_SRC_MAC;
				return 0;
			} else {
				return -1;
			}
		}
		targ->flags |= TASK_ARG_SRC_MAC_SET;
		return 0;
	}
	if (STR_EQ(str, "gateway ipv4")) { /* Gateway IP address used when generating */
		return parse_ip(&targ->gateway_ipv4, pkey);
	}
	if (STR_EQ(str, "local ipv4")) { /* source IP address to be used for packets */
		return parse_ip(&targ->local_ipv4, pkey);
	}
	if (STR_EQ(str, "remote ipv4")) { /* source IP address to be used for packets */
		return parse_ip(&targ->remote_ipv4, pkey);
	}
        if (STR_EQ(str, "local ipv6")) { /* source IPv6 address to be used for packets */
                return parse_ip6(&targ->local_ipv6, pkey);
        }
	if (STR_EQ(str, "number of packets"))
		return parse_int(&targ->n_pkts, pkey);
	if (STR_EQ(str, "pipes")) {
		uint32_t val;
		int err = parse_int(&val, pkey);
		if (err)
			return -1;
		if (!val || !rte_is_power_of_2(val)) {
			set_errf("Number of pipes has to be power of 2 and not zero");
			return -1;
		}

		targ->qos_conf.port_params.n_pipes_per_subport = val;
		return 0;
	}
	if (STR_EQ(str, "queue size")) {
		uint32_t val;
		int err = parse_int(&val, pkey);
		if (err) {
			return -1;
		}

		targ->qos_conf.port_params.qsize[0] = val;
		targ->qos_conf.port_params.qsize[1] = val;
		targ->qos_conf.port_params.qsize[2] = val;
		targ->qos_conf.port_params.qsize[3] = val;
		return 0;
	}
	if (STR_EQ(str, "subport tb rate")) {
		return parse_int(&targ->qos_conf.subport_params[0].tb_rate, pkey);
	}
	if (STR_EQ(str, "subport tb size")) {
		return parse_int(&targ->qos_conf.subport_params[0].tb_size, pkey);
	}
	if (STR_EQ(str, "subport tc 0 rate")) {
		return parse_int(&targ->qos_conf.subport_params[0].tc_rate[0], pkey);
	}
	if (STR_EQ(str, "subport tc 1 rate")) {
		return parse_int(&targ->qos_conf.subport_params[0].tc_rate[1], pkey);
	}
	if (STR_EQ(str, "subport tc 2 rate")) {
		return parse_int(&targ->qos_conf.subport_params[0].tc_rate[2], pkey);
	}
	if (STR_EQ(str, "subport tc 3 rate")) {
		return parse_int(&targ->qos_conf.subport_params[0].tc_rate[3], pkey);
	}

	if (STR_EQ(str, "subport tc rate")) {
		uint32_t val;
		int err = parse_int(&val, pkey);
		if (err) {
			return -1;
		}

		targ->qos_conf.subport_params[0].tc_rate[0] = val;
		targ->qos_conf.subport_params[0].tc_rate[1] = val;
		targ->qos_conf.subport_params[0].tc_rate[2] = val;
		targ->qos_conf.subport_params[0].tc_rate[3] = val;

		return 0;
	}
	if (STR_EQ(str, "subport tc period")) {
		return parse_int(&targ->qos_conf.subport_params[0].tc_period, pkey);
	}
	if (STR_EQ(str, "pipe tb rate")) {
		return parse_int(&targ->qos_conf.pipe_params[0].tb_rate, pkey);
	}
	if (STR_EQ(str, "pipe tb size")) {
		return parse_int(&targ->qos_conf.pipe_params[0].tb_size, pkey);
	}
	if (STR_EQ(str, "pipe tc rate")) {
		uint32_t val;
		int err = parse_int(&val, pkey);
		if (err) {
			return -1;
		}

		targ->qos_conf.pipe_params[0].tc_rate[0] = val;
		targ->qos_conf.pipe_params[0].tc_rate[1] = val;
		targ->qos_conf.pipe_params[0].tc_rate[2] = val;
		targ->qos_conf.pipe_params[0].tc_rate[3] = val;
		return 0;
	}
	if (STR_EQ(str, "pipe tc 0 rate")) {
		return parse_int(&targ->qos_conf.pipe_params[0].tc_rate[0], pkey);
	}
	if (STR_EQ(str, "pipe tc 1 rate")) {
		return parse_int(&targ->qos_conf.pipe_params[0].tc_rate[1], pkey);
	}
	if (STR_EQ(str, "pipe tc 2 rate")) {
		return parse_int(&targ->qos_conf.pipe_params[0].tc_rate[2], pkey);
	}
	if (STR_EQ(str, "pipe tc 3 rate")) {
		return parse_int(&targ->qos_conf.pipe_params[0].tc_rate[3], pkey);
	}
	if (STR_EQ(str, "pipe tc period")) {
		return parse_int(&targ->qos_conf.pipe_params[0].tc_period, pkey);
	}
	if (STR_EQ(str, "police action")) {
		char *in = strstr(pkey, " io=");
		if (in == NULL) {
			set_errf("Need to specify io colors using io=in_color,out_color\n");
			return -1;
		}
		*in = 0;
		in += strlen(" io=");

		char *out = strstr(in, ",");
		if (out == NULL) {
			set_errf("Output color not specified\n");
		}
		*out = 0;
		out++;

		enum police_action in_color = str_to_color(in);
		enum police_action out_color = str_to_color(out);

		if (in_color == ACT_INVALID) {
			set_errf("Invalid input color %s. Expected green, yellow or red", in);
			return -1;
		}
		if (out_color == ACT_INVALID) {
			set_errf("Invalid output color %s. Expected green, yellow or red", out);
			return -1;
		}
		enum police_action action = str_to_color(pkey);
		if (action == ACT_INVALID) {
			set_errf("Error action %s. Expected green, yellow, red or drop", pkey);
			return -1;
		}
		targ->police_act[in_color][out_color] = action;

		return 0;
	}
	if (STR_EQ(str, "qinq tag")) {
		return parse_int(&targ->qinq_tag, pkey);
	}
	if (STR_EQ(str, "cir")) {
		return parse_int(&targ->cir, pkey);
	}
	if (STR_EQ(str, "cbs")) {
		return parse_int(&targ->cbs, pkey);
	}
	if (STR_EQ(str, "pir")) {
		return parse_int(&targ->pir, pkey);
	}
	if (STR_EQ(str, "pbs")) {
		return parse_int(&targ->pbs, pkey);
	}
	if (STR_EQ(str, "ebs")) {
		return parse_int(&targ->ebs, pkey);
	}
	uint32_t queue_id = 0;
	if (sscanf(str, "queue %d weight", &queue_id) == 1) {
		uint32_t val;
		int err = parse_int(&val, pkey);
		if (err) {
			return -1;
		}
		targ->qos_conf.pipe_params[0].wrr_weights[queue_id] = val;
		return 0;
	}
	if (STR_EQ(str, "classify")) {
		if (!(targ->task_init->flag_features & TASK_FEATURE_CLASSIFY)) {
			set_errf("Classify is not supported in '%s' mode", targ->task_init->mode_str);
			return -1;
		}

		return parse_flag(&targ->runtime_flags, TASK_CLASSIFY, pkey);
	}
	if (STR_EQ(str, "flow table size")) {
		return parse_int(&targ->flow_table_size, pkey);
	}
#ifdef GRE_TP
	if (STR_EQ(str, "tbf rate")) {
		return parse_int(&targ->tb_rate, pkey);
	}
	if (STR_EQ(str, "tbf size")) {
		return parse_int(&targ->tb_size, pkey);
	}
#endif
	if (STR_EQ(str, "max rules")) {
		return parse_int(&targ->n_max_rules, pkey);
	}

        if (STR_EQ(str, "tunnel hop limit")) {
                uint32_t val;
                int err = parse_int(&val, pkey);
                if (err) {
                        return -1;
                }
                targ->tunnel_hop_limit = val;
                return 0;
        }

        if (STR_EQ(str, "lookup port mask")) {
                uint32_t val;
                int err = parse_int(&val, pkey);
                if (err) {
                        return -1;
                }
                targ->lookup_port_mask = val;
                return 0;
        }

	set_errf("Option '%s' is not known", str);
	/* fail on unknown keys */
	return -1;
}

static int str_is_number(const char *in)
{
	int dot_once = 0;

	for (size_t i = 0; i < strlen(in); ++i) {
		if (!dot_once && in[i] == '.') {
			dot_once = 1;
			continue;
		}

		if (in[i] < '0' || in[i] > '9')
			return 0;
	}

	return 1;
}

/* command line parameters parsing procedure */
int prox_parse_args(int argc, char **argv)
{
	int i, opt, ret;
	char *tmp, *tmp2;
	char tmp3[64];

	/* Default settings */
	prox_cfg.flags |= DSF_AUTOSTART | DSF_WAIT_ON_QUIT;
	prox_cfg.ui = PROX_UI_CURSES;

	plog_info("\tCommand line:");
	for (i = 0; i < argc; ++i) {
		plog_info(" %s", argv[i]);
	}
	plog_info("\n");

	while ((opt = getopt(argc, argv, "f:dnzpo:tkuar:emsiw:l:v:q:")) != EOF) {
		switch (opt) {
		case 'f':
			/* path to config file */
			cfg_file = optarg;
			size_t offset = 0;
			for (size_t i = 0; i < strlen(cfg_file); ++i) {
				if (cfg_file[i] == '/') {
					offset = i + 1;
				}
			}

			strncpy(prox_cfg.name, cfg_file + offset, MAX_NAME_SIZE);
			break;
		case 'v':
			plog_set_lvl(atoi(optarg));
			break;
		case 'l':
			prox_cfg.log_name_pid = 0;
			strncpy(prox_cfg.log_name, optarg, MAX_NAME_SIZE);
			break;
		case 'p':
			prox_cfg.log_name_pid = 1;
			break;
		case 'k':
			prox_cfg.use_stats_logger = 1;
			break;
		case 'd':
			prox_cfg.flags |= DSF_DAEMON;
			prox_cfg.ui = PROX_UI_NONE;
			break;
                case 'z':
                        prox_cfg.flags |= DSF_USE_DUMMY_CPU_TOPO;
			prox_cfg.flags |= DSF_CHECK_INIT;
                        break;
		case 'n':
			prox_cfg.flags |= DSF_USE_DUMMY_DEVICES;
			break;
		case 'r':
			if (!str_is_number(optarg) || strlen(optarg) > 11)
				return -1;
			strncpy(prox_cfg.update_interval_str, optarg, sizeof(prox_cfg.update_interval_str));
			break;
		case 'o':
			if (prox_cfg.flags & DSF_DAEMON)
				break;

			if (!strcmp(optarg, "curses")) {
				prox_cfg.ui = PROX_UI_CURSES;
			}
			else if (!strcmp(optarg, "cli")) {
				prox_cfg.ui = PROX_UI_CLI;
			}
			else if (!strcmp(optarg, "none")) {
				prox_cfg.ui = PROX_UI_NONE;
			}
			else {
				plog_err("Invalid local UI '%s', local UI can be 'curses', 'cli' or 'none'.", optarg);
				return -1;
			}
			break;
		case 'q':
			if (luaL_loadstring(prox_lua(), optarg)) {
				set_errf("Lua error: '%s'\n", lua_tostring(prox_lua(), -1));
				return -1;
			}

			if (lua_pcall(prox_lua(), 0, LUA_MULTRET, 0)) {
				set_errf("Lua error: '%s'\n", lua_tostring(prox_lua(), -1));
				return -1;
			}

			break;
		case 'a':
			/* autostart all cores */
			prox_cfg.flags |= DSF_AUTOSTART;
			break;
		case 'e':
			/* don't autostart */
			prox_cfg.flags &= ~DSF_AUTOSTART;
			break;
		case 't':
			prox_cfg.flags |= DSF_LISTEN_TCP;
			break;
		case 'u':
			prox_cfg.flags |= DSF_LISTEN_UDS;
			break;
		case 'm':
			/* list supported task modes and exit */
			prox_cfg.flags |= DSF_LIST_TASK_MODES;
			break;
		case 's':
			/* check configuration file syntax and exit */
			prox_cfg.flags |= DSF_CHECK_SYNTAX;
			break;
		case 'i':
			/* check initialization sequence and exit */
			prox_cfg.flags |= DSF_CHECK_INIT;
			break;
		case 'w':
			tmp = optarg;
			tmp2 = 0;
			if (strlen(tmp) >= 3 &&
			    (tmp2 = strchr(tmp, '='))) {
				*tmp2 = 0;
				tmp3[0] = '$';
				strncpy(tmp3 + 1, tmp, 63);
				plog_info("\tAdding variable: %s = %s\n", tmp3, tmp2 + 1);
				ret = add_var(tmp3, tmp2 + 1, 1);
				if (ret == -2) {
					plog_err("\tFailed to add variable, too many variables defines\n");
					return -1;
				}
				else if(ret == -3) {
					plog_err("\tFailed to add variable, already defined\n");
					return -1;
				}
				break;
			}
			/* fall-through */
		default:
			plog_err("\tUnknown option\n");
			return -1;
		}
	}

	/* reset getopt lib for DPDK */
	optind = 0;

	return 0;
}

static int check_cfg(void)
{
	/* Sanity check */
#define RETURN_IF(cond, err)			\
	if (cond) {				\
		plog_err(err);			\
		return -1;			\
	};

	RETURN_IF(rte_cfg.force_nchannel == 0, "\tError: number of memory channels not specified in [eal options] section\n");
	RETURN_IF(prox_cfg.master >= RTE_MAX_LCORE, "\tError: No master core specified (one core needs to have mode=master)\n");

#undef RETURN_IF

	return 0;
}

static int calc_tot_rxrings(void)
{
	struct lcore_cfg *slconf, *dlconf;
	struct task_args *starg, *dtarg;
	uint32_t dlcore_id;
	uint8_t dtask_id;
	struct core_task ct;

	dlconf = NULL;
	while (core_targ_next_early(&dlconf, &dtarg, 1) == 0) {
		dtarg->tot_rxrings = 0;
	}

	slconf = NULL;
	while (core_targ_next_early(&slconf, &starg, 1) == 0) {
		for (uint8_t idx = 0; idx < MAX_PROTOCOLS; ++idx) {
			for (uint8_t ring_idx = 0; ring_idx < starg->core_task_set[idx].n_elems; ++ring_idx) {
				ct = starg->core_task_set[idx].core_task[ring_idx];
				if (!prox_core_active(ct.core, 0)) {
					set_errf("Core %u is disabled but Core %u task %u is sending to it\n",
						 ct.core, slconf->id, starg->id);
					return -1;
				}

				dlconf = &lcore_cfg_init[ct.core];

				if (ct.task >= dlconf->n_tasks_all) {
					set_errf("Core %u task %u not enabled\n", ct.core, ct.task);
					return -1;
				}

				dtarg = &dlconf->targs[ct.task];

				/* Control rings are not relevant at this point. */
				if (ct.type)
					continue;

				if (!(dtarg->flags & TASK_ARG_RX_RING)) {
					set_errf("Core %u task %u is not expecting to receive through a ring\n",
						 ct.core, ct.task);
					return -1;
				}

				dtarg->tot_rxrings++;
				if (dtarg->tot_rxrings > MAX_RINGS_PER_TASK) {
					set_errf("Core %u task %u is receiving from too many tasks",
						 ct.core, ct.task);
					return -1;
				}
			}
		}
	}

	return 0;
}

static void prox_set_core_mask(void)
{
	struct lcore_cfg *lconf;

	prox_core_clr();
	for (uint8_t lcore_id = 0; lcore_id < RTE_MAX_LCORE; ++lcore_id) {
		lconf = &lcore_cfg_init[lcore_id];
		if (lconf->n_tasks_all > 0 && lconf->targs[0].mode != MASTER) {
			prox_core_set_active(lcore_id);
		}
	}
}

static int is_using_no_drop(void)
{
	uint32_t lcore_id;
	struct lcore_cfg *lconf;
	struct task_args *targs;

	lcore_id = -1;
	while(prox_core_next(&lcore_id, 1) == 0) {
		lconf = &lcore_cfg_init[lcore_id];
		for (uint8_t task_id = 0; task_id < lconf->n_tasks_all; ++task_id) {
			targs = &lconf->targs[task_id];
			if (!(targs->flags & TASK_ARG_DROP))
				return 1;
		}
	}
	return 0;
}

int prox_read_config_file(void)
{
	set_global_defaults(&prox_cfg);
	set_task_defaults(&prox_cfg, lcore_cfg_init);
	set_port_defaults();
	plog_info("=== Parsing configuration file '%s' ===\n", cfg_file);
	struct cfg_file *pcfg = cfg_open(cfg_file);
	if (pcfg == NULL) {
		return -1;
	}

	struct cfg_section* config_sections[] = {
		&lua_cfg          ,
		&var_cfg          ,
		&eal_default_cfg  ,
		&cache_set_cfg    ,
		&port_cfg         ,
		&defaults_cfg     ,
		&settings_cfg     ,
		&core_cfg         ,
		NULL
	};

	for (struct cfg_section** section = config_sections; *section != NULL; ++section) {
		const char* name = (*section)->name;
		size_t len = strlen(name);
		plog_info("\t*** Reading [%s] section%s ***\n", name, name[len - 1] == '#'? "s": "");
		cfg_parse(pcfg, *section);

		if ((*section)->error) {
			plog_err("At line %u, section [%s], entry %u: '%s'\n\t%s\n"
				 , pcfg->err_line, pcfg->err_section, pcfg->err_entry + 1, pcfg->cur_line,
				 strlen(get_parse_err())? get_parse_err() : err_str);
			cfg_close(pcfg); /* cannot close before printing error, print uses internal buffer */
			return -1;
		}
	}

	cfg_close(pcfg);

	prox_set_core_mask();

	if (is_using_no_drop()) {
		prox_cfg.flags &= ~DSF_WAIT_ON_QUIT;
	}

	if (calc_tot_rxrings()) {
		plog_err("Error in configuration: %s\n", err_str);
		return -1;
	}

	return check_cfg();
}

static void failed_rte_eal_init(__attribute__((unused))const char *prog_name)
{
	plog_err("\tError in rte_eal_init()\n");
}

int prox_setup_rte(const char *prog_name)
{
	char *rte_argv[MAX_RTE_ARGV];
	char  rte_arg[MAX_RTE_ARGV][MAX_ARG_LEN];
	char tmp[PROX_CM_STR_LEN];
	/* create mask of used cores */
	plog_info("=== Setting up RTE EAL ===\n");

	if (prox_cfg.flags & DSF_USE_DUMMY_CPU_TOPO) {
		plog_info("Using dummy cpu topology\n");
		snprintf(tmp, sizeof(tmp), "0x1");
	} else {
		prox_core_to_hex(tmp, sizeof(tmp), 0);
		plog_info("\tWorker threads core mask is %s\n", tmp);
		prox_core_to_hex(tmp, sizeof(tmp), 1);
		plog_info("\tWith master core index %u, full core mask is %s\n", prox_cfg.master, tmp);
	}

	/* fake command line parameters for rte_eal_init() */
	int argc = 0;
	rte_argv[argc] = strdup(prog_name);
	sprintf(rte_arg[++argc], "-c%s", tmp);
	rte_argv[argc] = rte_arg[argc];
#if RTE_VERSION >= RTE_VERSION_NUM(1,8,0,0)
	if (prox_cfg.flags & DSF_USE_DUMMY_CPU_TOPO)
		sprintf(rte_arg[++argc], "--master-lcore=%u", 0);
	else
		sprintf(rte_arg[++argc], "--master-lcore=%u", prox_cfg.master);
	rte_argv[argc] = rte_arg[argc];
#else
	/* For old DPDK versions, the master core had to be the first
	   core. */
	uint32_t first_core = -1;

	if (prox_core_next(&first_core, 1) == -1) {
		plog_err("Can't core ID of first core in use\n");
		return -1;
	}
	if (first_core != prox_cfg.master) {
		plog_err("The master core needs to be the first core (master core = %u, first core = %u).\n", first_core, prox_cfg.master);
		return -1;
	}
#endif

	if (rte_cfg.memory) {
		sprintf(rte_arg[++argc], "-m%u", rte_cfg.memory);
		rte_argv[argc] = rte_arg[argc];
	}

	if (rte_cfg.force_nchannel) {
		sprintf(rte_arg[++argc], "-n%u", rte_cfg.force_nchannel);
		rte_argv[argc] = rte_arg[argc];
	}

	if (rte_cfg.force_nrank) {
		sprintf(rte_arg[++argc], "-r%u", rte_cfg.force_nrank);
		rte_argv[argc] = rte_arg[argc];
	}

	if (rte_cfg.no_hugetlbfs) {
		strcpy(rte_arg[++argc], "--no-huge");
		rte_argv[argc] = rte_arg[argc];
	}

	if (rte_cfg.no_pci) {
		strcpy(rte_arg[++argc], "--no-pci");
		rte_argv[argc] = rte_arg[argc];
	}

	if (rte_cfg.no_hpet) {
		strcpy(rte_arg[++argc], "--no-hpet");
		rte_argv[argc] = rte_arg[argc];
	}

	if (rte_cfg.no_shconf) {
		strcpy(rte_arg[++argc], "--no-shconf");
		rte_argv[argc] = rte_arg[argc];
	}

	if (rte_cfg.eal != NULL) {
		char *ptr = rte_cfg.eal;
		char *ptr2;
		while (ptr != NULL) {
			while (isspace(*ptr))
				ptr++;
			ptr2 = ptr;
			ptr = strchr(ptr, ' ');
			if (ptr) {
				*ptr++ = '\0';
			}
			strcpy(rte_arg[++argc], ptr2);
			rte_argv[argc] = rte_arg[argc];
		}
	}

	if (rte_cfg.hugedir != NULL) {
		strcpy(rte_arg[++argc], "--huge-dir");
		rte_argv[argc] = rte_arg[argc];
		rte_argv[++argc] = rte_cfg.hugedir;
	}

	if (rte_cfg.no_output) {
		rte_set_log_level(0);
	}
	/* init EAL */
	plog_info("\tEAL command line:");
	if (argc >= MAX_RTE_ARGV) {
		plog_err("too many arguments for EAL\n");
		return -1;
	}

	for (int h = 0; h <= argc; ++h) {
		plog_info(" %s", rte_argv[h]);
	}
	plog_info("\n");

	rte_set_application_usage_hook(failed_rte_eal_init);
	if (rte_eal_init(++argc, rte_argv) < 0) {
		plog_err("\tError in rte_eal_init()\n");
		return -1;
	}
	plog_info("\tEAL Initialized\n");

	if (prox_cfg.flags & DSF_USE_DUMMY_CPU_TOPO)
		return 0;

	/* check if all active cores are in enabled in DPDK */
	for (uint32_t lcore_id = 0; lcore_id < RTE_MAX_LCORE; ++lcore_id) {
		if (lcore_id == prox_cfg.master) {
			if (!rte_lcore_is_enabled(lcore_id))
				return -1;
		}
		else if (rte_lcore_is_enabled(lcore_id) != prox_core_active(lcore_id, 0)) {
			plog_err("\tFailed to enable lcore %u\n", lcore_id);
			return -1;
		}
		else if (lcore_cfg_init[lcore_id].n_tasks_all != 0 && !rte_lcore_is_enabled(lcore_id)) {
			plog_err("\tFailed to enable lcore %u\n", lcore_id);
			return -1;
		}
	}
	return 0;
}