Order mechanism_drivers list

The list of networking mechanism driver entrypoints should be ordered
to ensure sriovnicswitch is listed first, followed by opendaylight.

Change-Id: I05fdfceef13d3051d2bac5bfd624b52b2606778d
Closes-Bug: PROD-20883
diff --git a/README.rst b/README.rst
index e659bde..5712e7d 100644
--- a/README.rst
+++ b/README.rst
@@ -747,6 +747,10 @@
               driver: openvswitch
             sriov:
               driver: sriovnicswitch
+              # Driver w/ highest number will be placed ahead in the list (default is 0).
+              # It's recommended for SR-IOV driver to set an order >0 to get it
+              # before (for example) the opendaylight one.
+              order: 9
 
     neutron:
       compute:
@@ -911,6 +915,7 @@
         mechanism:
           ovs:
             driver: opendaylight_v2
+            order: 1
 
 Network/Gateway node:
 
diff --git a/neutron/files/pike/ml2_conf.ini b/neutron/files/pike/ml2_conf.ini
index 377ecd7..45c07f0 100644
--- a/neutron/files/pike/ml2_conf.ini
+++ b/neutron/files/pike/ml2_conf.ini
@@ -131,14 +131,17 @@
 # the neutron.ml2.mechanism_drivers namespace. (list value)
 #mechanism_drivers =
 {%- set mechanism_drivers = [] %}
+{%- set default_order = 0 %}
 {%- for mechanism_name, mechanism in server.get('backend', {}).get('mechanism', []).items() %}
-{%- do mechanism_drivers.append(mechanism.get('driver')) if 'driver' in mechanism %}
+{%-   if 'driver' in mechanism %}
+{%-     do mechanism.update({'order': default_order}) if 'order' not in mechanism %}
+{%-     do mechanism_drivers.append(mechanism) %}
+{%-   endif %}
 {%- endfor %}
-{%- set opendaylight_enabled = true if 'opendaylight' in mechanism_drivers|join else false %}
-{%- if "vxlan" in server.backend.tenant_network_types and not opendaylight_enabled %}
-{%- do mechanism_drivers.append('l2population') %}
+{%- if "vxlan" in server.backend.tenant_network_types and not server.backend.opendaylight|default(False) %}
+{%-   do mechanism_drivers.append({'driver': 'l2population', 'order': default_order}) %}
 {%- endif %}
-mechanism_drivers = {{ ','.join(mechanism_drivers) }}
+mechanism_drivers = {{ mechanism_drivers|sort(True, attribute='order')|join(',', attribute='driver') }}
 
 # An ordered list of extension driver entrypoints to be loaded from the
 # neutron.ml2.extension_drivers namespace. For example: extension_drivers =
@@ -321,7 +324,7 @@
 ovn_l3_scheduler = leastloaded
 {%- endif %}
 
-{%- if opendaylight_enabled %}
+{%- if server.backend.opendaylight|default(False) %}
 [ml2_odl]
 # HTTP URL of OpenDaylight REST interface. (string value)
 url = {{ server.backend.protocol|default('http') }}://{{ server.backend.host }}:{{ server.backend.rest_api_port }}/controller/nb/v2/neutron
diff --git a/neutron/files/queens/ml2_conf.ini b/neutron/files/queens/ml2_conf.ini
index fe465ba..13eae76 100644
--- a/neutron/files/queens/ml2_conf.ini
+++ b/neutron/files/queens/ml2_conf.ini
@@ -37,14 +37,17 @@
 # the neutron.ml2.mechanism_drivers namespace. (list value)
 #mechanism_drivers =
 {%- set mechanism_drivers = [] %}
+{%- set default_order = 0 %}
 {%- for mechanism_name, mechanism in server.get('backend', {}).get('mechanism', []).items() %}
-{%- do mechanism_drivers.append(mechanism.get('driver')) if 'driver' in mechanism %}
+{%-   if 'driver' in mechanism %}
+{%-     do mechanism.update({'order': default_order}) if 'order' not in mechanism %}
+{%-     do mechanism_drivers.append(mechanism) %}
+{%-   endif %}
 {%- endfor %}
-{%- set opendaylight_enabled = true if 'opendaylight' in mechanism_drivers|join else false %}
-{%- if "vxlan" in server.backend.tenant_network_types and not opendaylight_enabled %}
-{%- do mechanism_drivers.append('l2population') %}
+{%- if "vxlan" in server.backend.tenant_network_types and not server.backend.opendaylight|default(False) %}
+{%-   do mechanism_drivers.append({'driver': 'l2population', 'order': default_order}) %}
 {%- endif %}
-mechanism_drivers = {{ ','.join(mechanism_drivers) }}
+mechanism_drivers = {{ mechanism_drivers|sort(True, attribute='order')|join(',', attribute='driver') }}
 
 # An ordered list of extension driver entrypoints to be loaded from the
 # neutron.ml2.extension_drivers namespace. For example: extension_drivers =
@@ -230,7 +233,7 @@
 enable_distributed_floating_ip = {{ server.dvr|default('false') }}
 {%- endif %}
 
-{%- if opendaylight_enabled %}
+{%- if server.backend.opendaylight|default(False) %}
 [ml2_odl]
 # HTTP URL of OpenDaylight REST interface. (string value)
 url = {{ server.backend.protocol|default('http') }}://{{ server.backend.host }}:{{ server.backend.rest_api_port }}/controller/nb/v2/neutron
diff --git a/tests/pillar/control_opendaylight.sls b/tests/pillar/control_opendaylight.sls
index 174790e..9064406 100644
--- a/tests/pillar/control_opendaylight.sls
+++ b/tests/pillar/control_opendaylight.sls
@@ -59,6 +59,7 @@
       mechanism:
         ovs:
           driver: opendaylight
+          order: 77
 linux:
   system:
     enabled: true