Initial commit
[ta/infra-ansible.git] / roles / baremetal_interface_config / templates / os_net_config.j2
1 {#
2 This file is written with conditional check and for loop based indentation.
3 It improved code readability. The output json is not pretty. Run cat <output.json> | python -m json.tool
4 for pretty printing the same.
5 #}
6
7 {%- set CLOUD_TENANT = 'cloud_tenant' %}
8 {%- set VXLAN_HDR_LEN = 50 %}
9
10 {#- initialize some variables -#}
11 {%- set host_networking = hostvars[ansible_hostname]['networking'] %}
12 {%- if 'mtu' in host_networking %}
13     {%- set default_mtu = host_networking['mtu'] %}
14 {%- else %}
15     {%- set default_mtu = 1500 %}
16 {%- endif %}
17 {%- set sriov_mtu = 9000 %}
18 {%- set max_mtu = 9000 %}
19 {%- set host_network_profiles_list = hosts[ansible_hostname]['network_profiles'] %}
20 {%- set host_network_profile_value = hostvars[ansible_hostname]['network_profiles'][host_network_profiles_list[0]] %}
21 {%- set host_interface_net_mapping = host_network_profile_value['interface_net_mapping'] %}
22 {%- if 'bonding_interfaces' in host_network_profile_value %}
23     {%- set host_bonding_interfaces = host_network_profile_value['bonding_interfaces'] %}
24 {%- else %}
25     {%- set host_bonding_interfaces = {} %}
26 {%- endif %}
27 {%- set single_nic_setup = False %}
28 {%- if 'provider_network_interfaces' in host_network_profile_value %}
29     {%- set host_provider_network_interfaces = host_network_profile_value['provider_network_interfaces'] %}
30     {%- set dpdk_in_use = ((host_provider_network_interfaces.itervalues()|first).type == 'ovs-dpdk') %}
31
32     {%- if host_interface_net_mapping|length == 1 and host_provider_network_interfaces|length == 1 %}
33         {%- if host_interface_net_mapping.keys()[0] == host_provider_network_interfaces.keys()[0] %}
34             {%- set single_nic_setup = True %}
35             {%- if CLOUD_TENANT in host_networking.keys() %}
36                 {%- set mtu = default_mtu %}
37                 {%- if 'mtu' in host_networking[CLOUD_TENANT] %}
38                     {%- set mtu = host_networking[CLOUD_TENANT]['mtu'] %}
39                 {%- endif %}
40                 {%- set mtu = mtu + VXLAN_HDR_LEN %}
41                 {%- if mtu > max_mtu %}
42                     {%- set max_mtu = mtu %}
43                 {%- endif %}
44             {%- endif %}
45         {%-endif %}
46     {%-endif %}
47
48     {#- make a list of ixgbe devices, needed in ovs-dpdk configuration -#}
49     {%- set ixgbedevs = [] %}
50     {%- for key in hostvars[ansible_hostname].keys() %}
51         {%- if key.startswith('ansible_') %}
52             {%- set value = hostvars[ansible_hostname][key] %}
53             {%- if value is iterable and 'device' in value and 'module' in value and value['module'] == 'ixgbe' %}
54                 {%- if ixgbedevs.append(value['device']) %}{%- endif %}
55             {%- endif %}
56         {%- endif %}
57     {%- endfor %}
58 {%- else %}
59     {%- set host_provider_network_interfaces = {} %}
60     {%- set dpdk_in_use = False %}
61 {%- endif %}
62 {%- set external_ceph_cidr = None %}
63 {%- if config_phase != 'setup' and 'external_ceph' in storage['backends'] %}
64     {%- set ext_ceph = storage['backends']['external_ceph'] %}
65     {%- if 'enabled' in ext_ceph and 'cidr' in ext_ceph and ext_ceph['enabled'] %}
66         {%- set external_ceph_cidr = ext_ceph['cidr'] %}
67     {%- endif %}
68 {%- endif %}
69
70 {% macro generate_linux_bonding_options(options) -%}
71     {%- set mode_mapping = {'active-backup' : 'active-backup', 'lacp' : '802.3ad'} -%}
72     {%- set default_options = {
73                                 'active-backup' : 'miimon=100',
74                                 'lacp' : 'lacp_rate=fast miimon=100'
75                               } -%}
76     {%- for i in options.split() -%}
77         {%- set key, value = i.split('=') -%}
78         {%- if key == 'mode' -%}
79             {%- if default_options[value] -%}
80                 {{ 'mode=' ~ mode_mapping[value] ~ ' ' ~ default_options[value] }}
81             {%- else -%}
82                 {{ 'mode=' ~ mode_mapping[value] }}
83             {%- endif -%}
84         {%- endif -%}
85     {%- endfor -%}
86 {%- endmacro %}
87
88 {% macro generate_ovs_bonding_options(options) -%}
89     {%- set mode_mapping = {'active-backup' : 'active-backup', 'lacp' : 'balance-slb', 'lacp-layer34' : 'balance-tcp'} -%}
90     {%- set default_options = {
91                                 'active-backup' : '',
92                                 'lacp' : 'lacp=active other_config:lacp-time=fast other_config:bond-detect-mode=carrier',
93                                 'lacp-layer34' : 'lacp=active other_config:lacp-time=fast other_config:bond-detect-mode=carrier'
94                               } -%}
95     {%- for i in options.split() -%}
96         {%- set key, value = i.split('=') -%}
97         {%- if key == 'mode' -%}
98             {%- if default_options[value] -%}
99                 {{ 'bond_mode=' ~ mode_mapping[value] ~ ' ' ~ default_options[value] }}
100             {%- else -%}
101                 {{ 'bond_mode=' ~ mode_mapping[value] }}
102             {%- endif -%}
103         {%- endif -%}
104     {%- endfor -%}
105 {%- endmacro %}
106
107 {% macro add_static_routes(routes) -%}
108     [
109     {%- for route in routes %}
110         {
111             "ip_netmask": "{{ route.to }}", "next_hop": "{{ route.via }}"
112         } {% if not loop.last %},{% endif %}
113     {%- endfor %}
114     ]
115 {%- endmacro %}
116
117 {#- create network configuration input for the os-net-config -#}
118 {
119 "network_config": [
120 {%- set loopvar = {'first_entry': True} %}
121 {%- set configured_phys_ifaces = [] %}
122
123 {#- single nic ifra networks are configured with the ovs provider networks -#}
124 {%- if not single_nic_setup %}
125
126 {#-
127 If all infra ifaces on some phys iface are vlan ifaces it is configured here.
128 Otherwise it gets configured normally on infra iface configuration in the next loop.
129 -#}
130 {%- for iface,infras in host_interface_net_mapping.iteritems() %}
131     {%- set ifacevars = {'create': True, 'mtu': 0} %}
132     {%- for infra,value in host_networking.iteritems() %}
133         {%- if infra in infras %}
134             {%- if value['interface'] == iface %}
135                 {%- if ifacevars.update({'create': False}) %}{%- endif %}
136             {%- else %}
137                 {%- if 'mtu' in value %}
138                     {%- set mtu = value['mtu'] %}
139                 {%- else %}
140                     {%- set mtu = default_mtu %}
141                 {%- endif %}
142                 {%- if infra == CLOUD_TENANT %}
143                     {%- set mtu = mtu + VXLAN_HDR_LEN %}
144                 {%- endif %}
145                 {%- if mtu > ifacevars.mtu %}
146                     {%- if ifacevars.update({'mtu': mtu}) %}{%- endif %}
147                 {%- endif %}
148             {%- endif %}
149         {%- endif %}
150     {%- endfor %}
151     {%- if ifacevars.create %}
152         {%- if not loopvar.first_entry %},{%- endif %}
153         {%- if loopvar.update({'first_entry': False}) %}{%- endif %}
154         {
155             "name": "{{iface}}",
156             {%- if 'bond' in iface %}
157                 {%- for key,slaves in host_bonding_interfaces.iteritems() if key == iface %}
158                     "type": "linux_bond",
159                     {% if ifacevars.mtu > 0 %}"mtu": {{ifacevars['mtu']}},{% endif %}
160                     {%- if 'linux_bonding_options' in  host_network_profile_value %}
161                         "bonding_options": "{{ generate_linux_bonding_options(host_network_profile_value['linux_bonding_options']) }}",
162                     {%- endif %}
163                     "members": [ {% for slave in slaves %}
164                         {%- if configured_phys_ifaces.append(slave) %}{%- endif %}
165                         {
166                         "name": "{{slave}}",
167                         "type": "interface",
168                         {% if ifacevars.mtu > 0 %}"mtu": {{ifacevars['mtu']}},{% endif %}
169                         "use_dhcp": false
170                         }
171                         {% if not loop.last %},{% endif %}
172                     {%- endfor %}
173                     ],
174                 {%- endfor %}
175             {%- else %}
176                 {%- if configured_phys_ifaces.append(iface) %}{%- endif %}
177                 "type": "interface",
178             {%- endif %}
179             {% if ifacevars.mtu > 0 %}"mtu": {{ifacevars['mtu']}},{% endif %}
180             "use_dhcp": false
181         }
182     {%- endif %}
183 {%- endfor %}
184
185 {#- configure all infra ifaces (except cloud_tenant if ovs-dpdk in use) -#}
186 {%- for key,value in host_networking.iteritems() %}
187     {%- if value is iterable and 'interface' in value %}
188         {%- if key != CLOUD_TENANT or not dpdk_in_use %}{#- no dpdk or no cloud tenant -#}
189         {%- if 'mtu' in value %}{% set mtu = value['mtu'] %}{% else %}{% set mtu = default_mtu %}{% endif %}
190         {%- if key == CLOUD_TENANT %}{% set mtu = mtu + VXLAN_HDR_LEN %}{% endif %}
191         {%- if not loopvar.first_entry %},{%- endif %}
192         {%- if loopvar.update({'first_entry': False}) %}{%- endif %}
193         {
194         {%- if 'bond' in value['interface'] %}
195             {%- for bond_key,bond_value in host_bonding_interfaces.iteritems() if bond_key == value['interface'] %}
196                 "name": "{{bond_key}}",
197                 "type": "linux_bond",
198                 "members": [ {% for member in bond_value %}
199                     {
200                     "name": "{{ member }}",
201                     "type": "interface",
202                     "mtu": {{mtu}},
203                     "use_dhcp": false
204                     }
205                     {% if not loop.last %},{% endif %}
206                 {%- endfor %}
207                 ],
208                 {%- if 'linux_bonding_options' in  host_network_profile_value %}
209                     "bonding_options": "{{ generate_linux_bonding_options(host_network_profile_value['linux_bonding_options']) }}",
210                 {%- endif %}
211             {%- endfor %}
212         {%- elif 'vlan' in value %}
213             "type": "vlan",
214             "vlan_id": {{ value['vlan'] }},
215             {%- for net_key,net_value in host_interface_net_mapping.iteritems() %}
216                 {%- if key in net_value %}
217                     "device": "{{net_key}}",
218                 {%- endif %}
219             {%- endfor %}
220         {%- else %}
221             {%- if configured_phys_ifaces.append(value['interface']) %}{%- endif %}
222             "name": "{{value['interface']}}",
223             "type": "interface",
224         {%- endif %}
225             "addresses": [ { "ip_netmask": "{{ value['ip'] }}/{{value['mask']}}" } ],
226             "mtu": {{mtu}},
227             {%- if (key == "infra_external" or key == "infra_access")
228                     and 'dns' in host_networking
229                     and (ansible_hostname not in groups.get('caas_nodes', [])) %}
230                 "dns_servers": [{% for server in host_networking['dns'] %}"{{ server }}"{% if not loop.last %},{% endif %}{% endfor %}],
231             {%- endif %}
232             {%- set routes = [] %}
233             {%- if 'routes' in value %}
234                 {%- set routes = value['routes'] %}
235             {%- endif %}
236             {%- if key == 'infra_external' and 'gateway' in value %}
237                 {%- if '.' in value['gateway'] %}
238                     {% set defaultroute = '0.0.0.0/0'%}
239                 {%- else %}
240                     {% set defaultroute = '::/0'%}
241                 {%- endif %}
242                 {%- set gw = {"to": defaultroute, "via": value['gateway']} %}
243                 {%- if routes.append(gw) %}{%- endif %}
244             {%- endif %}
245             {%- if key == 'infra_access' and 'gateway' in value %}
246                 {%- if 'dns' in host_networking %}
247                     {%- if '.' in value['gateway'] %}
248                         {% set mask = '/32' %}
249                     {%- else %}
250                         {% set mask = '/128' %}
251                     {%- endif %}
252                     {%- for server in host_networking['dns'] %}
253                         {%- set dnsroute = server ~ mask %}
254                         {%- set gw = {"to": dnsroute, "via": value['gateway']} %}
255                         {%- if routes.append(gw) %}{%- endif %}
256                     {%- endfor %}
257                 {%- endif %}
258                 {%- if external_ceph_cidr is not none %}
259                     {%- set gw = {"to": external_ceph_cidr, "via": value['gateway']} %}
260                     {%- if routes.append(gw) %}{%- endif %}
261                 {%- endif %}
262             {%- endif %}
263             {%- if routes %}
264                 "routes": {{ add_static_routes(routes) }},
265             {%- endif %}
266             "use_dhcp": false
267         }
268         {%- endif %}{#- no dpdk or no cloud tenant -#}
269     {%- endif %}
270 {%- endfor %}
271
272 {%- endif %}{#- if not single_nic_setup -#}
273
274 {%- if config_phase != 'setup' or single_nic_setup %}
275
276 {#- configure provider network interfaces -#}
277 {%- for key,value in host_provider_network_interfaces|dictsort(true) %}
278     {%- set keyloop = loop %}
279     {%- if 'ovs' in value['type'] %}
280         {%- if not loopvar.first_entry %},{%- endif %}
281         {%- if loopvar.update({'first_entry': False}) %}{%- endif %}
282         {%- if value['type'] == 'ovs-dpdk' %}
283             {%- for bond_key,bond_value in host_bonding_interfaces.iteritems() if bond_key == key %}
284                 {%- for member in bond_value %}
285                     {%- if member not in ixgbedevs %}
286                         {%- if configured_phys_ifaces.append(member) %}{%- endif %}
287                         {
288                             "name": "{{member}}",
289                             "type": "interface",
290                             "mtu": {{max_mtu}},
291                             "use_dhcp": false
292                         },
293                     {%- endif %}
294                 {%- endfor %}
295             {%- endfor %}
296             {%- if 'bond' not in key and key not in ixgbedevs %}
297                 {%- if configured_phys_ifaces.append(key) %}{%- endif %}
298                 {
299                     "name": "{{key}}",
300                     "type": "interface",
301                     "mtu": {{max_mtu}},
302                     "use_dhcp": false
303                 },
304             {%- endif %}
305         {%- endif %}
306         {
307         "name": "br-pro{{keyloop.index0}}",
308         {%- if value['type'] == 'ovs-dpdk' %}
309             "type": "ovs_user_bridge",
310         {%- else %}
311             "type": "ovs_bridge",
312         {%- endif %}
313         "members": [
314             {
315             "mtu": {{max_mtu}},
316             {%- if 'bond' in key %}
317                 {%- for bond_key,bond_value in host_bonding_interfaces.iteritems() if bond_key == key %}
318                     {%- if 'ovs_bonding_options' in  host_network_profile_value %}
319                         "ovs_options": "{{ generate_ovs_bonding_options(host_network_profile_value['ovs_bonding_options']) }}",
320                     {%- endif %}
321                     "name": "{{key}}",
322                     {%- if value['type'] == 'ovs-dpdk' %}
323                         "type": "ovs_dpdk_bond",
324                         {%- if 'dpdk_max_rx_queues' in value %}
325                             "rx_queue": {{ value['dpdk_max_rx_queues'] }},
326                         {%- endif %}
327                         "members": [ {%- for member in bond_value %}
328                             {%- if configured_phys_ifaces.append(member) %}{%- endif %}
329                             {
330                             "name": "dpdk-{{member}}",
331                             "type": "ovs_dpdk_port",
332                             "mtu": {{max_mtu}},
333                             "members": [ { "name": "{{member}}", "type": "interface", "mtu": {{max_mtu}}, "use_dhcp": false } ],
334                             "use_dhcp": false
335                             }
336                             {% if not loop.last %},{% endif %}
337                         {%- endfor %}
338                         ],
339                     {%- else %}
340                         "type": "ovs_bond",
341                         "members": [ {% for member in bond_value %}
342                             {%- if configured_phys_ifaces.append(member) %}{%- endif %}
343                             {
344                             "name": "{{ member }}",
345                             "type": "interface",
346                             "mtu": {{max_mtu}},
347                             "use_dhcp": false
348                             }
349                             {% if not loop.last %},{% endif %}
350                         {%- endfor %}
351                         ],
352                     {%- endif %}
353                 {%- endfor %}
354             {%- else %}
355                 {%- if configured_phys_ifaces.append(key) %}{%- endif %}
356                 {%- if value['type'] == 'ovs-dpdk' %}
357                     "name": "dpdk-{{key}}",
358                     "type": "ovs_dpdk_port",
359                     "mtu": {{max_mtu}},
360                     {%- if 'dpdk_max_rx_queues' in value %}
361                         "rx_queue": {{ value['dpdk_max_rx_queues'] }},
362                     {%- endif %}
363                     "members": [ { "name": "{{key}}", "type": "interface", "mtu": {{max_mtu}}, "use_dhcp": false } ],
364                 {%- else %}
365                     "name": "{{key}}",
366                     "type": "interface",
367                 {%- endif %}
368             {%- endif %}
369             "use_dhcp": false
370             }
371             {%- for net in value['provider_networks'] %}
372                 ,
373                 {
374                 "name": "pro{{keyloop.index0}}-pro{{keyloop.index0}}.{{loop.index0}}",
375                 "bridge_name": "br-pro{{keyloop.index0}}",
376                 "type": "ovs_patch_port",
377                 "peer": "pro{{keyloop.index0}}.{{loop.index0}}-pro{{keyloop.index0}}"
378                 }
379             {%- endfor %}
380             {%- if single_nic_setup %}
381                 {#- configure all infra ifaces -#}
382                 {%- for key,value in host_networking.iteritems() %}
383                     {%- if value is iterable and 'interface' in value %}
384                         {%- if 'mtu' in value %}{% set mtu = value['mtu'] %}{% else %}{% set mtu = default_mtu %}{% endif %}
385                         {%- if key == CLOUD_TENANT %}{% set mtu = mtu + VXLAN_HDR_LEN %}{% endif %}
386                         ,
387                         {
388                         "type": "vlan",
389                         "vlan_id": {{ value['vlan'] }},
390                         "addresses": [ { "ip_netmask": "{{ value['ip'] }}/{{value['mask']}}" } ],
391                         "mtu": {{mtu}},
392                         {%- if (key == "infra_external" or key == "infra_access")
393                             and 'dns' in host_networking
394                             and (ansible_hostname not in groups.get('caas_nodes', [])) %}
395                             "dns_servers": [{% for server in host_networking['dns'] %}"{{ server }}"{% if not loop.last %},{% endif %}{% endfor %}],
396                         {%- endif %}
397                         {%- set routes = [] %}
398                         {%- if 'routes' in value %}
399                             {%- set routes = value['routes'] %}
400                         {%- endif %}
401                         {%- if key == 'infra_external' and 'gateway' in value %}
402                             {%- if '.' in value['gateway'] %}
403                                 {% set defaultroute = '0.0.0.0/0'%}
404                             {%- else %}
405                                 {% set defaultroute = '::/0'%}
406                             {%- endif %}
407                             {%- set gw = {"to": defaultroute, "via": value['gateway']} %}
408                             {%- if routes.append(gw) %}{%- endif %}
409                         {%- endif %}
410                         {%- if key == 'infra_access' and 'gateway' in value %}
411                             {%- if 'dns' in host_networking %}
412                                 {%- if '.' in value['gateway'] %}
413                                     {% set mask = '/32' %}
414                                 {%- else %}
415                                     {% set mask = '/128' %}
416                                 {%- endif %}
417                                 {%- for server in host_networking['dns'] %}
418                                     {%- set dnsroute = server ~ mask %}
419                                     {%- set gw = {"to": dnsroute, "via": value['gateway']} %}
420                                     {%- if routes.append(gw) %}{%- endif %}
421                                 {%- endfor %}
422                             {%- endif %}
423                             {%- if external_ceph_cidr is not none %}
424                                 {%- set gw = {"to": external_ceph_cidr, "via": value['gateway']} %}
425                                 {%- if routes.append(gw) %}{%- endif %}
426                             {%- endif %}
427                         {%- endif %}
428                         {%- if routes %}
429                             "routes": {{ add_static_routes(routes) }},
430                         {%- endif %}
431                         "use_dhcp": false
432                         }
433                     {%- endif %}
434                 {%- endfor %}
435             {%- endif %}{#- if single_nic_setup -#}
436         ]
437         }
438         {%- for net in value['provider_networks'] %}
439             ,
440             {
441             "name": "br-pro{{keyloop.index0}}.{{loop.index0}}",
442             {%- if value['type'] == 'ovs-dpdk' %}
443                 "type": "ovs_user_bridge",
444             {%- else %}
445                 "type": "ovs_bridge",
446             {%- endif %}
447             "ovs_fail_mode": "secure",
448             "members": [
449                 {
450                 "name": "pro{{keyloop.index0}}.{{loop.index0}}-pro{{keyloop.index0}}",
451                 "bridge_name": "br-pro{{keyloop.index0}}.{{loop.index0}}",
452                 "type": "ovs_patch_port",
453                 "peer": "pro{{keyloop.index0}}-pro{{keyloop.index0}}.{{loop.index0}}"
454                 }
455             ]
456             }
457         {%- endfor %}
458     {%- endif %}
459 {%- endfor %}
460
461 {#- configure vxlan bridge for dpdk cloud tenant -#}
462 {%- if CLOUD_TENANT in host_networking.keys() and dpdk_in_use %}
463     {%- set net = host_networking[CLOUD_TENANT] %}
464     {%- if not loopvar.first_entry %},{%- endif %}
465     {%- if loopvar.update({'first_entry': False}) %}{%- endif %}
466     {
467         "type": "ovs_user_bridge",
468         "name": "br-vxlan",
469         "addresses": [ { "ip_netmask": "{{ net['ip'] }}/{{net['mask']}}" } ],
470         {%- if 'routes' in net %}
471             "routes": {{ add_static_routes(net['routes']) }},
472         {%- endif %}
473         "members": [{
474             "type": "vlan",
475             "vlan_id": {{ net['vlan'] }},
476             {%- for net_key,net_value in host_interface_net_mapping.iteritems() %}
477                 {%- if CLOUD_TENANT in net_value %}
478                     "device": "{{net_key}}",
479                 {%- endif %}
480             {%- endfor %}
481             {%- if 'mtu' in net %}{% set mtu = net['mtu'] %}{% else %}{% set mtu = default_mtu %}{% endif %}
482             {% set mtu = mtu + VXLAN_HDR_LEN %}
483             "mtu": {{mtu}},
484             "use_dhcp": false
485         }],
486         "ovs_extra": [ "br-set-external-id br-vxlan bridge-id br-vxlan" ]
487     }
488 {%- endif %}
489 {%- endif %}{#- if config_phase != 'setup' or single_nic_setup -#}
490
491 {#- configure sr-iov ifaces -#}
492 {%- if config_phase != 'setup' %}
493 {%- if 'sriov_provider_networks' in host_network_profile_value %}
494     {%- for net,net_info in host_network_profile_value['sriov_provider_networks'].iteritems() %}
495         {%- for iface in net_info['interfaces'] %}
496             {%- if iface not in configured_phys_ifaces %}
497                 {%- if not loopvar.first_entry %},{%- endif %}
498                 {%- if loopvar.update({'first_entry': False}) %}{%- endif %}
499                 {
500                 "name": "{{iface}}",
501                 "type": "interface",
502                 "mtu": {{sriov_mtu}},
503                 "use_dhcp": false
504                 }
505             {%- endif %}
506         {%- endfor %}
507     {%- endfor %}
508 {%- endif %}
509 {%- endif %}{#- if config_phase != 'setup' -#}
510 ]
511 }