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

Add fallback and fast_rate attributes to LAG interfaces module #458

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
minor_changes:
- sonic_lag_interfaces - Add fallback and fast_rate attributes to LAG interfaces module (https://github.com/ansible-collections/dellemc.enterprise_sonic/pull/458).
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#
# -*- coding: utf-8 -*-
# Copyright 2020 Dell Inc. or its subsidiaries. All Rights Reserved
# Copyright 2024 Dell Inc. or its subsidiaries. All Rights Reserved
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

Expand Down Expand Up @@ -67,7 +67,9 @@ def __init__(self, **kwargs):
"df_preference": {"type": "int"},
},
"type": "dict"
}
},
"fallback": {"type": "bool"},
"fast_rate": {"type": "bool"}
},
"type": "list"
},
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#
# -*- coding: utf-8 -*-
# Copyright 2020 Dell Inc. or its subsidiaries. All Rights Reserved
# Copyright 2024 Dell Inc. or its subsidiaries. All Rights Reserved
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""
Expand All @@ -25,8 +25,6 @@
)
from ansible.module_utils.connection import ConnectionError

GET = "get"


class Lag_interfacesFacts(object):
""" The sonic lag_interfaces fact class
Expand All @@ -48,41 +46,74 @@ def __init__(self, module, subspec='config', options='options'):

def get_all_portchannels(self):
"""Get all the interfaces available in chassis"""
request = [{"path": "data/sonic-portchannel:sonic-portchannel", "method": GET}]
data = []
request = {'path': 'data/sonic-portchannel:sonic-portchannel', 'method': 'get'}
try:
response = edit_config(self._module, to_request(self._module, request))
if response[0][1]:
data = response[0][1].get('sonic-portchannel:sonic-portchannel', [])
except ConnectionError as exc:
self._module.fail_json(msg=str(exc), code=exc.code)
if response[0][1]:
data = response[0][1]['sonic-portchannel:sonic-portchannel']
else:
data = []

return data

def get_po_and_po_members(self, data):
if data is not None:
if "PORTCHANNEL_MEMBER" in data:
portchannel_members_list = data["PORTCHANNEL_MEMBER"]["PORTCHANNEL_MEMBER_LIST"]
else:
portchannel_members_list = []
if "PORTCHANNEL" in data:
portchannel_list = data["PORTCHANNEL"]["PORTCHANNEL_LIST"]
else:
portchannel_list = []
if portchannel_list:
for i in portchannel_list:
if not any(d["name"] == i["name"] for d in portchannel_members_list):
portchannel_members_list.append({'ifname': None, 'name': i['name']})
all_portchannels_list = []
merged_portchannels = []

if data:
return portchannel_members_list
else:
return []
if 'PORTCHANNEL' in data:
portchannel_list = data['PORTCHANNEL']['PORTCHANNEL_LIST']
all_portchannels_list.extend(portchannel_list)
if 'PORTCHANNEL_MEMBER' in data:
portchannel_members_list = data['PORTCHANNEL_MEMBER']['PORTCHANNEL_MEMBER_LIST']
all_portchannels_list.extend(portchannel_members_list)

if all_portchannels_list:
mode_dict = {True: 'static', False: 'lacp'}
for portchannel in all_portchannels_list:
name = portchannel.get('name')
fallback = portchannel.get('fallback')
fast_rate = portchannel.get('fast_rate')
member = portchannel.get('ifname')
mode = portchannel.get('static')

# Find if portchannel already exists and update
matched = next((portchannel for portchannel in merged_portchannels if portchannel['name'] == name), None)
if matched:
if fallback is not None:
matched['fallback'] = fallback
if fast_rate is not None:
matched['fast_rate'] = fast_rate
if member:
if 'members' in matched and matched['members'].get('interfaces'):
matched['members']['interfaces'].append({'member': member})
else:
matched['members'] = {'interfaces': [{'member': member}]}
if mode is not None:
matched['mode'] = mode_dict[mode]
# Create new portchannel if it doesn't already exist
else:
new_portchannel = {}
if name:
new_portchannel['name'] = name
if fallback is not None:
new_portchannel['fallback'] = fallback
if fast_rate is not None:
new_portchannel['fast_rate'] = fast_rate
if member:
new_portchannel['members'] = {'interfaces': [{'member': member}]}
if mode is not None:
new_portchannel['mode'] = mode_dict[mode]
if new_portchannel:
merged_portchannels.append(new_portchannel)

return merged_portchannels

def get_ethernet_segments(self, data):
es_list = []
if data:
if "EVPN_ETHERNET_SEGMENT" in data:
if 'EVPN_ETHERNET_SEGMENT' in data:
es_list = data["EVPN_ETHERNET_SEGMENT"]["EVPN_ETHERNET_SEGMENT_LIST"]
return es_list

Expand All @@ -97,42 +128,35 @@ def populate_facts(self, connection, ansible_facts, data=None):
objs = []
if not data:
data = self.get_all_portchannels()
objs = self.get_po_and_po_members(data)

es_data = self.get_ethernet_segments(data)
for es in es_data:
po_name = es['ifname']
esi_t = es['esi_type']
esi = es['esi']
if 'df_pref' in es:
df_pref = es['df_pref']
else:
df_pref = None

po_data = self.get_po_and_po_members(data)
for conf in po_data:
if conf:
obj = self.render_config(self.generated_spec, conf)
obj = self.transform_config(obj)
if obj:
self.merge_portchannels(objs, obj)

es_data = self.get_ethernet_segments(data)
for es in es_data:
po_name = es['ifname']
esi_t = es['esi_type']
esi = es['esi']
if 'df_pref' in es:
df_pref = es['df_pref']
else:
df_pref = None

if esi_t == 'TYPE_1_LACP_BASED':
esi_type = 'auto_lacp'
elif esi_t == 'TYPE_3_MAC_BASED':
esi_type = 'auto_system_mac'
elif esi_t == 'TYPE_0_OPERATOR_CONFIGURED':
esi_type = 'ethernet_segment_id'
if esi_t == 'TYPE_1_LACP_BASED':
esi_type = 'auto_lacp'
elif esi_t == 'TYPE_3_MAC_BASED':
esi_type = 'auto_system_mac'
elif esi_t == 'TYPE_0_OPERATOR_CONFIGURED':
esi_type = 'ethernet_segment_id'

if df_pref:
es_dict = {'esi_type': esi_type, 'esi': esi, 'df_preference': df_pref}
else:
es_dict = {'esi_type': esi_type, 'esi': esi}
if df_pref:
es_dict = {'esi_type': esi_type, 'esi': esi, 'df_preference': df_pref}
else:
es_dict = {'esi_type': esi_type, 'esi': esi}

have_po_conf = next((po_conf for po_conf in objs if po_conf['name'] == po_name), {})
if have_po_conf:
have_po_conf['ethernet_segment'] = es_dict
else:
self._module.fail_json(msg='{0} does not exist for ethernet segment'.format(po_name))
have_po_conf = next((po_conf for po_conf in objs if po_conf['name'] == po_name), {})
if have_po_conf:
have_po_conf['ethernet_segment'] = es_dict
else:
self._module.fail_json(msg='{0} does not exist for ethernet segment'.format(po_name))

facts = {}
if objs:
Expand All @@ -143,34 +167,3 @@ def populate_facts(self, connection, ansible_facts, data=None):
ansible_facts['ansible_network_resources'].update(facts)

return ansible_facts

def render_config(self, spec, conf):
return conf

def transform_config(self, conf):
trans_cfg = dict()
trans_cfg['name'] = conf['name']
trans_cfg['members'] = dict()
if conf['ifname']:
interfaces = list()
interface = {'member': conf['ifname']}
interfaces.append(interface)
trans_cfg['members'] = {'interfaces': interfaces}
return trans_cfg

def merge_portchannels(self, configs, conf):
if len(configs) == 0:
configs.append(conf)
else:
new_interface = None
if conf.get('members') and conf['members'].get('interfaces'):
new_interface = conf['members']['interfaces'][0]
else:
configs.append(conf)
if new_interface:
matched = next((cfg for cfg in configs if cfg['name'] == conf['name']), None)
if matched and matched.get('members'):
ext_interfaces = matched.get('members').get('interfaces', [])
ext_interfaces.append(new_interface)
else:
configs.append(conf)
42 changes: 36 additions & 6 deletions plugins/modules/sonic_lag_interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,16 @@
- The preference for Designated Forwarder election method.
The range of df_preference value is from 1 to 65535.
type: int
fallback:
description:
- Enable/disable LACP fallback.
version_added: 3.1.0
type: bool
fast_rate:
description:
- When set to true LACP packets will be sent every second; otherwise, the LACP packets will be sent every 30 seconds.
version_added: 3.1.0
type: bool
state:
description:
- The state that the configuration should be left in.
Expand Down Expand Up @@ -139,6 +149,9 @@
esi_type: auto_lacp
df_preference: 2222
- name: PortChannel12
fallback: true
fast_rate: true
mode: lacp
members:
interfaces:
- member: Eth1/15
Expand All @@ -165,7 +178,9 @@
# evpn ethernet-segment auto-lacp
# df-preference 2222
# !
# interface PortChannel12
# interface PortChannel12 mode active
# fast_rate
# fallback
# no shutdown
#
#
Expand All @@ -186,7 +201,9 @@
# speed 100000
# no shutdown
# !
# interface PortChannel10
# interface PortChannel10 mode active
# fast_rate
# fallback
# no shutdown
# !
# evpn ethernet-segment auto-lacp
Expand All @@ -203,6 +220,8 @@
esi_type: auto_system_mac
df_preference: 6666
- name: PortChannel10
fallback: false
fast_rate: false
members:
interfaces:
- member: Eth1/7
Expand Down Expand Up @@ -231,7 +250,7 @@
# speed 100000
# no shutdown
#
# interface PortChannel10
# interface PortChannel10 mode active
# no shutdown
# !
# evpn ethernet-segment auto-system-mac
Expand Down Expand Up @@ -270,6 +289,9 @@
dellemc.enterprise_sonic.sonic_lag_interfaces:
config:
- name: PortChannel20
fallback: true
fast_rate: true
mode: lacp
members:
interfaces:
- member: Eth1/6
Expand All @@ -292,7 +314,9 @@
# speed 100000
# no shutdown
#
# interface PortChannel20
# interface PortChannel20 mode active
# fast_rate
# fallback
# no shutdown
# !
# evpn ethernet-segment auto-lacp
Expand All @@ -302,7 +326,9 @@
#
# Before state:
# -------------
# interface PortChannel 10
# interface PortChannel 10 mode active
# fast_rate
# fallback
# no shutdown
# !
# evpn ethernet-segment auto-lacp
Expand Down Expand Up @@ -350,7 +376,9 @@
# speed 100000
# no shutdown
# !
# interface PortChannel10
# interface PortChannel10 mode active
# fast_rate
# fallback
# no shutdown
# !
# evpn ethernet-segment auto-lacp
Expand All @@ -360,6 +388,8 @@
sonic_lag_interfaces:
config:
- name: PortChannel10
fallback: true
fast_rate: true
members:
interfaces:
- member: Eth1/10
Expand Down
Loading
Loading