Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Macsec profile deploy on peer VM's and DUT for macsec topo pipeline. #16048

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
20 changes: 20 additions & 0 deletions ansible/config_sonic_basedon_testbed.yml
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,26 @@
port_index_map: "{{ port_index_map | default({}) }}"
become: true
Copy link
Contributor

@liamkearney-msft liamkearney-msft Jan 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this needs to be gated on something like when: "('t2' not in topo)", or moved lower, otherwise deploy-mg will fail here on t2 since the profile/templates are not on the dut


- name: Copy macsec profile json to dut
copy: src=../tests/common/macsec/profile.json
dest=/tmp/profile.json
become: true
when: "('t2' in topo) and (enable_macsec is defined)"

- name: Copy golden_config_db_t2 template to DUT
copy: src=templates/golden_config_db_t2.j2
dest=/tmp/golden_config_db_t2.j2
become: true
when: "('t2' in topo) and (enable_macsec is defined)"

- name: Generate golden_config_db.json for t2
generate_golden_config_db:
topo_name: "{{ topo }}"
macsec_profile: "{{ macsec_profile }}"
num_asics: "{{ num_asics }}"
become: true
when: "('t2' in topo) and (enable_macsec is defined)"

- name: Use minigraph case
block:
- name: execute cli "config load_minigraph --override_config -y" to apply new minigraph
Expand Down
38 changes: 35 additions & 3 deletions ansible/library/generate_golden_config_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@


import copy
import jinja2
import json

from ansible.module_utils.basic import AnsibleModule
Expand All @@ -25,15 +26,22 @@
TEMP_DHCP_SERVER_CONFIG_PATH = "/tmp/dhcp_server.json"
TEMP_SMARTSWITCH_CONFIG_PATH = "/tmp/smartswitch.json"
DUMMY_QUOTA = "dummy_single_quota"
MACSEC_PROFILE_PATH = '/tmp/profile.json'
GOLDEN_CONFIG_TEMPLATE = 'golden_config_db_t2.j2'
GOLDEN_CONFIG_TEMPLATE_PATH = '/tmp/golden_config_db_t2.j2'


class GenerateGoldenConfigDBModule(object):
def __init__(self):
self.module = AnsibleModule(argument_spec=dict(topo_name=dict(required=True, type='str'),
port_index_map=dict(require=False, type='dict', default=None)),
port_index_map=dict(require=False, type='dict', default=None),
macsec_profile=dict(require=False, type='str', default=None),
num_asics=dict(require=False, type='int', default=1)),
supports_check_mode=True)
self.topo_name = self.module.params['topo_name']
self.port_index_map = self.module.params['port_index_map']
self.macsec_profile = self.module.params['macsec_profile']
self.num_asics = self.module.params['num_asics']

def generate_mgfx_golden_config_db(self):
rc, out, err = self.module.run_command("sonic-cfggen -H -m -j /etc/sonic/init_cfg.json --print-data")
Expand Down Expand Up @@ -115,18 +123,42 @@ def generate_smartswitch_golden_config_db(self):
gold_config_db.update(smartswitch_config_obj)
return json.dumps(gold_config_db, indent=4)

def generate_t2_golden_config_db(self):
with open(MACSEC_PROFILE_PATH) as f:
macsec_profiles = json.load(f)
for k, v in list(macsec_profiles.items()):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you avoid iterating by just grabbing the key directly? eg:
profile = macsec_profiles.get(self.macsec_profile) if profile: profile['macsec_profile'] = self.macsec_profile

Also, should we explicitly error out/fail here if there is not a matching profile in the json?

if k == self.macsec_profile:
profile = v
# Update the macsec profile name in the profile context
profile['macsec_profile'] = k
break

# Update the profile context with the asic count
profile['asic_cnt'] = self.num_asics

# Render the template using the profile
j2_env = jinja2.Environment(loader=jinja2.FileSystemLoader('/tmp'))
j2_template = j2_env.get_template(GOLDEN_CONFIG_TEMPLATE)
rendered_json = j2_template.render(profile)

return rendered_json

def generate(self):
if self.topo_name == "mx" or "m0" in self.topo_name:
config = self.generate_mgfx_golden_config_db()
self.module.run_command("sudo rm -f {}".format(TEMP_DHCP_SERVER_CONFIG_PATH))
elif self.topo_name == "t1-28-lag":
config = self.generate_smartswitch_golden_config_db()
self.module.run_command("sudo rm -f {}".format(TEMP_SMARTSWITCH_CONFIG_PATH))
elif "t2" in self.topo_name:
config = self.generate_t2_golden_config_db()
self.module.run_command("sudo rm -f {}".format(MACSEC_PROFILE_PATH))
self.module.run_command("sudo rm -f {}".format(GOLDEN_CONFIG_TEMPLATE_PATH))
else:
config = "{}"

with open(GOLDEN_CONFIG_DB_PATH, "w") as temp_file:
temp_file.write(config)
self.module.run_command("sudo rm -f {}".format(TEMP_DHCP_SERVER_CONFIG_PATH))
self.module.run_command("sudo rm -f {}".format(TEMP_SMARTSWITCH_CONFIG_PATH))
self.module.exit_json(change=True, msg="Success to generate golden_config_db.json")


Expand Down
28 changes: 28 additions & 0 deletions ansible/library/get_macsec_profile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-

import json
from ansible.module_utils.basic import AnsibleModule


def get_macsec_profile(module, macsec_profile):
with open('/tmp/profile.json') as f:
macsec_profiles = json.load(f)
for k, v in list(macsec_profiles.items()):
if k == macsec_profile:
profile = v
# Update the macsec profile name in the profile context
profile['macsec_profile'] = k
break
return profile


def main():
module = AnsibleModule(argument_spec=dict(macsec_profile=dict(required=True, type='str')))

macsec_profile = module.params['macsec_profile']
module.exit_json(profile=get_macsec_profile(module, macsec_profile), changed=False)


if __name__ == "__main__":
main()
21 changes: 21 additions & 0 deletions ansible/roles/eos/tasks/ceos_config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,27 @@
state: directory
delegate_to: "{{ VM_host[0] }}"

- name: Copy macsec profile json to dut
copy: src=../../../../tests/common/macsec/profile.json
dest=/tmp/profile.json
become: true
when: "'t2' == base_topo and enable_macsec is defined"
delegate_to: "{{ VM_host[0] }}"

- name: Get the macsec profile data from profile_name
get_macsec_profile:
macsec_profile: "{{ macsec_profile }}"
register: profile_raw
become: true
when: "'t2' == base_topo and enable_macsec is defined"
delegate_to: "{{ VM_host[0] }}"

- name: Flatten profile data into a flat structure
set_fact:
profile: "{{ profile_raw.profile }}"
when: "'t2' == base_topo and enable_macsec is defined"
delegate_to: "{{ VM_host[0] }}"

- name: update startup-config
become: yes
template: src="{{ base_topo }}-{{ props.swrole }}.j2"
Expand Down
13 changes: 13 additions & 0 deletions ansible/roles/eos/templates/t2-core.j2
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,15 @@ interface Management {{ mgmt_if_index }}
ip address {{ mgmt_ip }}/{{ mgmt_prefixlen }}
no shutdown
!
{% if enable_macsec is defined %}
judyjoseph marked this conversation as resolved.
Show resolved Hide resolved
mac security
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need to add similar change when using SONiC vm as neighbor ?

profile {{ profile.macsec_profile }}
cipher aes256-gcm-xpn
key {{ profile.primary_ckn }} 7 {{ profile.primary_cak }}
traffic unprotected drop
sci
{% endif %}
!
{% set ns = namespace(po_mbr_cnt=0) %}
{% for name, iface in host['interfaces'].items() %}
{% if name.startswith('Ethernet') %}
Expand All @@ -75,6 +84,10 @@ interface {{ name }}
{% if name.startswith('Port-Channel') %}
{% set min_links = (ns.po_mbr_cnt * 0.75) | round(0, 'ceil') | int %}
port-channel min-links {{ min_links }}
{% else %}
{% if enable_macsec is defined %}
mac security profile {{ profile.macsec_profile }}
{% endif %}
{% endif %}
{% if iface['lacp'] is defined %}
channel-group {{ iface['lacp'] }} mode active
Expand Down
30 changes: 30 additions & 0 deletions ansible/templates/golden_config_db_t2.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
{%- set asic_cnt = asic_cnt|int -%}
{% if asic_cnt > 1 %}
"localhost": {
"MACSEC_PROFILE": {}
},
{% for ns in range(asic_cnt) %}
"asic{{ns}}": {
"MACSEC_PROFILE": {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we check for macsec_profile is defined here ?

"{{macsec_profile}}": {
"priority": "{{priority}}",
"cipher_suite": "{{cipher_suite}}",
"primary_cak": "{{primary_cak}}",
"primary_ckn": "{{primary_ckn}}",
"policy": "{{policy}}",
"send_sci": "{{send_sci}}"
}
}
{% if ns == asic_cnt-1 %}
}
{% else %}
},
{% endif %}
{%- endfor -%}
{% else %}
{
"MACSEC_PROFILE": {}
},
{%- endif -%}
}
Loading