diff --git a/changelogs/fragments/479-proxy-arp-nd-proxy-feature-support.yaml b/changelogs/fragments/479-proxy-arp-nd-proxy-feature-support.yaml new file mode 100644 index 000000000..ed7b247ae --- /dev/null +++ b/changelogs/fragments/479-proxy-arp-nd-proxy-feature-support.yaml @@ -0,0 +1,2 @@ +minor_changes: + - sonic_l3_interfaces - Added support for Proxy-ARP/ND-Proxy feature (https://github.com/ansible-collections/dellemc.enterprise_sonic/pull/479). diff --git a/plugins/module_utils/network/sonic/argspec/l3_interfaces/l3_interfaces.py b/plugins/module_utils/network/sonic/argspec/l3_interfaces/l3_interfaces.py index 4c89e8104..4cdd617b4 100644 --- a/plugins/module_utils/network/sonic/argspec/l3_interfaces/l3_interfaces.py +++ b/plugins/module_utils/network/sonic/argspec/l3_interfaces/l3_interfaces.py @@ -53,6 +53,12 @@ def __init__(self, **kwargs): 'type': 'list' }, 'anycast_addresses': {'elements': 'str', 'type': 'list'}, + 'proxy_arp': { + 'options': { + 'mode': {'choices': ['DISABLE', 'REMOTE_ONLY', 'ALL'], 'type': 'str'}, + }, + 'type': 'dict' + }, }, 'type': 'dict' }, @@ -68,7 +74,14 @@ def __init__(self, **kwargs): }, 'autoconf': {'type': 'bool'}, 'dad': {'choices': ['ENABLE', 'DISABLE', 'DISABLE_IPV6_ON_FAILURE'], 'type': 'str'}, - 'enabled': {'type': 'bool'} + 'enabled': {'type': 'bool'}, + 'nd_proxy': { + 'options': { + 'mode': {'choices': ['DISABLE', 'REMOTE_ONLY', 'ALL'], 'type': 'str'}, + 'nd_proxy_rules': {'elements': 'str', 'type': 'list'} + }, + 'type': 'dict' + }, }, 'type': 'dict' }, diff --git a/plugins/module_utils/network/sonic/config/l3_interfaces/l3_interfaces.py b/plugins/module_utils/network/sonic/config/l3_interfaces/l3_interfaces.py index 70d7b2277..830d43aa8 100644 --- a/plugins/module_utils/network/sonic/config/l3_interfaces/l3_interfaces.py +++ b/plugins/module_utils/network/sonic/config/l3_interfaces/l3_interfaces.py @@ -39,6 +39,11 @@ from ansible.module_utils.connection import ConnectionError +try: + from urllib.parse import urlencode +except Exception: + from urllib import urlencode + TEST_KEYS = [ {"addresses": {"address": "", "secondary": ""}} ] @@ -192,14 +197,21 @@ def _state_replaced(self, want, have): diff_del = get_diff(get_replace_interfaces_list, new_want, TEST_KEYS) diff_add = get_diff(new_want, get_replace_interfaces_list, TEST_KEYS) + delete_l3_proxy_requests = self.delete_existing_proxy_values( + get_replace_interfaces_list, new_want) + if diff_del: delete_l3_interfaces_requests = self.get_delete_all_requests(diff_del) - ret_requests.extend(delete_l3_interfaces_requests) + unique_del_requests = [{'path': item.get('path'), 'method': item.get( + 'method')} for item in delete_l3_proxy_requests + delete_l3_interfaces_requests] + ret_requests.extend(unique_del_requests) commands.extend(update_states(diff_del, "deleted")) l3_interfaces_to_create_requests = self.get_create_l3_interfaces_requests(new_want) ret_requests.extend(l3_interfaces_to_create_requests) commands.extend(update_states(new_want, "replaced")) elif diff_add: + ret_requests.extend(delete_l3_proxy_requests) + commands.extend(update_states(diff_add, "deleted")) l3_interfaces_to_create_requests = self.get_create_l3_interfaces_requests(diff_add) ret_requests.extend(l3_interfaces_to_create_requests) commands.extend(update_states(diff_add, "replaced")) @@ -270,6 +282,100 @@ def _state_deleted(self, want, have): commands = update_states(commands, "deleted") return commands, requests + def delete_existing_proxy_values(self, existing_list, new_have): + requests = [] + + ipv4_proxy_arp_url = 'data/openconfig-interfaces:interfaces/interface={intf_name}/{sub_intf_name}/openconfig-if-ip:ipv4/proxy-arp' + ipv6_nd_proxy_url = 'data/openconfig-interfaces:interfaces/interface={intf_name}/{sub_intf_name}/openconfig-if-ip:ipv6/nd-proxy' + + for new_item in new_have: + l3_interface_name = new_item.get('name') + sub_intf = self.get_sub_interface_name(l3_interface_name) + existing_item = next((item for item in existing_list if item.get('name') == l3_interface_name), None) + + if existing_item and new_item.get( + 'ipv4') and existing_item.get('ipv4'): + + new_list_ipv4_addr = [] + existing_list_ipv4_addr = [] + existing_proxy_mode = None + new_proxy_mode = None + + if 'addresses' in existing_item['ipv4'] and existing_item['ipv4']['addresses']: + existing_ipv4_addresses = existing_item['ipv4']['addresses'] + existing_list_ipv4_addr = [ + item['address'] for item in existing_ipv4_addresses if 'address' in item] + + if 'addresses' in new_item['ipv4'] and new_item['ipv4']['addresses']: + new_ipv4_addresses = new_item['ipv4']['addresses'] + new_list_ipv4_addr = [ + item['address'] for item in new_ipv4_addresses if 'address' in item] + + if 'proxy_arp' in existing_item['ipv4'] and existing_item['ipv4']['proxy_arp'] is not None: + if 'mode' in existing_item['ipv4']['proxy_arp'] and existing_item['ipv4']['proxy_arp']['mode'] is not None: + existing_proxy_mode = existing_item['ipv4']['proxy_arp']['mode'] + + if 'proxy_arp' in new_item['ipv4'] and new_item['ipv4']['proxy_arp'] is not None: + if 'mode' in new_item['ipv4']['proxy_arp'] and new_item['ipv4']['proxy_arp']['mode'] is not None: + new_proxy_mode = new_item['ipv4']['proxy_arp']['mode'] + + if existing_proxy_mode is not None: + if sorted(existing_list_ipv4_addr) != sorted( + new_list_ipv4_addr) or existing_proxy_mode != new_proxy_mode: + ipv4_proxy_delete_request = {"path": ipv4_proxy_arp_url.format(intf_name=l3_interface_name, sub_intf_name=sub_intf), + "method": DELETE} + requests.append(ipv4_proxy_delete_request) + + if existing_item and new_item.get( + 'ipv6') and existing_item.get('ipv6'): + + existing_nd_proxy_mode = None + existing_nd_proxy_rules = [] + new_nd_proxy_mode = None + new_nd_proxy_rules = [] + existing_list_ipv6_addr = [] + new_list_ipv6_addr = [] + delete_url = False + + if 'addresses' in existing_item['ipv6'] and existing_item['ipv6']['addresses']: + existing_ipv6_addresses = existing_item['ipv6']['addresses'] + existing_list_ipv6_addr = [ + item['address'] for item in existing_ipv6_addresses if 'address' in item] + + if 'addresses' in new_item['ipv6'] and new_item['ipv6']['addresses']: + new_ipv6_addresses = new_item['ipv6']['addresses'] + new_list_ipv6_addr = [ + item['address'] for item in new_ipv6_addresses if 'address' in item] + + if 'nd_proxy' in existing_item['ipv6'] and existing_item['ipv6']['nd_proxy'] is not None: + if 'mode' in existing_item['ipv6']['nd_proxy'] and existing_item['ipv6']['nd_proxy']['mode'] is not None: + existing_nd_proxy_mode = existing_item['ipv6']['nd_proxy']['mode'] + if 'nd_proxy_rules' in existing_item['ipv6']['nd_proxy'] and existing_item[ + 'ipv6']['nd_proxy']['nd_proxy_rules'] is not None: + existing_nd_proxy_rules = existing_item['ipv6']['nd_proxy']['nd_proxy_rules'] + + if 'nd_proxy' in new_item['ipv6'] and new_item['ipv6']['nd_proxy'] is not None: + if 'mode' in new_item['ipv6']['nd_proxy'] and new_item['ipv6']['nd_proxy']['mode'] is not None: + new_nd_proxy_mode = new_item['ipv6']['nd_proxy']['mode'] + if 'nd_proxy_rules' in new_item['ipv6']['nd_proxy'] and new_item[ + 'ipv6']['nd_proxy']['nd_proxy_rules'] is not None: + new_nd_proxy_rules = new_item['ipv6']['nd_proxy']['nd_proxy_rules'] + + if existing_nd_proxy_mode is not None or new_nd_proxy_mode is not None: + delete_url = True + elif not existing_list_ipv6_addr and not new_list_ipv6_addr: + if sorted(existing_list_ipv6_addr) != sorted(new_list_ipv6_addr): + delete_url = True + elif not existing_nd_proxy_rules and not new_nd_proxy_rules: + if sorted(existing_nd_proxy_rules) != sorted(new_nd_proxy_rules): + delete_url = True + + if delete_url is True: + ipv6_proxy_delete_request = {"path": ipv6_nd_proxy_url.format(intf_name=l3_interface_name, sub_intf_name=sub_intf), "method": DELETE} + requests.append(ipv6_proxy_delete_request) + + return requests + def remove_default_entries(self, config): new_config = list() state = self._module.params['state'] @@ -278,6 +384,7 @@ def remove_default_entries(self, config): if obj.get('ipv4', None) and \ (obj['ipv4'].get('addresses', None) or obj['ipv4'].get('anycast_addresses', None) or + obj['ipv4'].get('proxy_arp', None) or state == 'deleted'): new_obj['ipv4'] = obj['ipv4'] if obj.get('ipv6', None) and \ @@ -285,8 +392,8 @@ def remove_default_entries(self, config): obj['ipv6'].get('dad', None) or obj['ipv6'].get('autoconf', None) is not None or obj['ipv6'].get('enabled', None) is not None or + obj['ipv6'].get('nd_proxy', None) or state == 'deleted'): - new_obj['ipv6'] = obj['ipv6'].copy() # The following options have defult values in the device IPv6 @@ -362,20 +469,29 @@ def get_interface_object_for_overridden(self, have): if obj.get('ipv4', None): ipv4_addresses = obj['ipv4'].get('addresses', None) anycast_addresses = obj['ipv4'].get('anycast_addresses', None) + ipv4_proxy_arp = obj['ipv4'].get('proxy_arp', None) else: ipv4_addresses = None anycast_addresses = None + ipv4_proxy_arp = None if obj.get('ipv6', None): ipv6_addresses = obj['ipv6'].get('addresses', None) ipv6_enable = obj['ipv6'].get('enabled', None) ipv6_autoconf = obj['ipv6'].get('autoconf', None) ipv6_dad = obj['ipv6'].get('dad', None) + ipv6_nd_proxy = obj['ipv6'].get('nd_proxy', None) else: ipv6_addresses = None ipv6_enable = None ipv6_autoconf = None ipv6_dad = None + ipv6_nd_proxy = None + + if ipv4_addresses is not None and ipv4_proxy_arp is not None \ + or ipv6_addresses is not None and ipv6_nd_proxy is not None: + objects.append(obj.copy()) + continue if ipv4_addresses is not None or ipv6_addresses is not None: objects.append(obj.copy()) @@ -384,6 +500,7 @@ def get_interface_object_for_overridden(self, have): if ipv6_enable or anycast_addresses is not None: objects.append(obj.copy()) continue + return objects def get_address(self, ip_str, have_obj): @@ -405,6 +522,9 @@ def get_delete_l3_interfaces_requests(self, want, have): ipv6_enabled_url = 'data/openconfig-interfaces:interfaces/interface={intf_name}/{sub_intf_name}/openconfig-if-ip:ipv6/config/enabled' ipv6_autoconf_url = 'data/openconfig-interfaces:interfaces/interface={intf_name}/{sub_intf_name}/openconfig-if-ip:ipv6/config/ipv6_autoconfig' ipv6_dad_url = 'data/openconfig-interfaces:interfaces/interface={intf_name}/{sub_intf_name}/openconfig-if-ip:ipv6/config/ipv6_dad' + ipv4_proxy_arp_url = 'data/openconfig-interfaces:interfaces/interface={intf_name}/{sub_intf_name}/openconfig-if-ip:ipv4/proxy-arp/config/mode' + ipv6_nd_proxy_url = 'data/openconfig-interfaces:interfaces/interface={intf_name}/{sub_intf_name}/openconfig-if-ip:ipv6/nd-proxy/config/mode' + ipv6_nd_proxy_rules_url = 'data/openconfig-interfaces:interfaces/interface={intf_name}/{sub_intf_name}/openconfig-if-ip:ipv6/nd-proxy/config/{rules}' if not want: return requests @@ -421,21 +541,34 @@ def get_delete_l3_interfaces_requests(self, want, have): have_ipv6_enabled = None have_ipv6_autoconf = None have_ipv6_dad = None + have_ipv4_proxy_arp_mode = None + have_ipv6_nd_proxy_mode = None + have_ipv6_nd_proxy_rules = list() if have_obj.get('ipv4'): if 'addresses' in have_obj['ipv4']: have_ipv4_addrs = have_obj['ipv4']['addresses'] if 'anycast_addresses' in have_obj['ipv4']: have_ipv4_anycast_addrs = have_obj['ipv4']['anycast_addresses'] + if 'proxy_arp' in have_obj['ipv4'] and have_obj['ipv4']['proxy_arp'] is not None: + if 'mode' in have_obj['ipv4']['proxy_arp'] and have_obj['ipv4']['proxy_arp']['mode'] is not None: + have_ipv4_proxy_arp_mode = have_obj['ipv4']['proxy_arp']['mode'] have_ipv6_addrs = self.get_address('ipv6', [have_obj]) if have_obj.get('ipv6') and 'enabled' in have_obj['ipv6']: have_ipv6_enabled = have_obj['ipv6']['enabled'] if have_obj.get('ipv6') and 'autoconf' in have_obj['ipv6']: have_ipv6_autoconf = have_obj['ipv6']['autoconf'] - if (have_obj.get('ipv6') and 'dad' in have_obj['ipv6'] and - have_obj['ipv6']['dad'] is not None and have_obj['ipv6']['dad'] != "DISABLE"): + if (have_obj.get('ipv6') and 'dad' in have_obj['ipv6'] and have_obj['ipv6'] + ['dad'] is not None and have_obj['ipv6']['dad'] != "DISABLE"): have_ipv6_dad = have_obj['ipv6']['dad'] + if have_obj.get( + 'ipv6') and 'nd_proxy' in have_obj['ipv6'] and have_obj['ipv6']['nd_proxy'] is not None: + if 'mode' in have_obj['ipv6']['nd_proxy'] and have_obj['ipv6']['nd_proxy']['mode'] is not None: + have_ipv6_nd_proxy_mode = have_obj['ipv6']['nd_proxy']['mode'] + if 'nd_proxy_rules' in have_obj['ipv6']['nd_proxy'] and have_obj[ + 'ipv6']['nd_proxy']['nd_proxy_rules'] is not None: + have_ipv6_nd_proxy_rules = have_obj['ipv6']['nd_proxy']['nd_proxy_rules'] ipv4 = l3.get('ipv4', None) ipv6 = l3.get('ipv6', None) @@ -449,13 +582,16 @@ def get_delete_l3_interfaces_requests(self, want, have): is_del_ipv4 = True is_del_ipv6 = True else: - if ipv4 and not ipv4.get('addresses') and not ipv4.get('anycast_addresses'): + if ipv4 and not ipv4.get('addresses') and not ipv4.get('anycast_addresses') and ipv4.get('proxy_arp') is None: is_del_ipv4 = True - if (ipv6 and not ipv6.get('addresses') and ipv6.get('enabled') is None and - ipv6.get('autoconf') is None and ipv6.get('dad') is None): + if ipv6 and not ipv6.get('addresses') and ipv6.get('enabled') is None and ipv6.get('autoconf') is None \ + and ipv6.get('dad') is None and ipv6.get('nd_proxy') is None: is_del_ipv6 = True if is_del_ipv4: + if have_ipv4_proxy_arp_mode: + ipv4_proxy_delete_request = {"path": ipv4_proxy_arp_url.format(intf_name=name, sub_intf_name=sub_intf), "method": DELETE} + requests.append(ipv4_proxy_delete_request) if have_ipv4_addrs and len(have_ipv4_addrs) != 0: ipv4_addrs_delete_request = {"path": ipv4_addrs_url_all.format(intf_name=name, sub_intf_name=sub_intf), "method": DELETE} requests.append(ipv4_addrs_delete_request) @@ -468,14 +604,24 @@ def get_delete_l3_interfaces_requests(self, want, have): else: ipv4_addrs = [] ipv4_anycast_addrs = [] + ipv4_proxy_arp_mode = None if l3.get('ipv4'): if l3['ipv4'].get('addresses'): ipv4_addrs = l3['ipv4']['addresses'] if l3['ipv4'].get('anycast_addresses'): ipv4_anycast_addrs = l3['ipv4']['anycast_addresses'] + if l3['ipv4'].get('proxy_arp'): + if 'mode' in l3['ipv4']['proxy_arp'] and l3['ipv4']['proxy_arp']['mode'] is not None: + ipv4_proxy_arp_mode = l3['ipv4']['proxy_arp']['mode'] # Store the primary ip at end of the list. So primary ip will be deleted after the secondary ips ipv4_del_reqs = [] + + if have_ipv4_proxy_arp_mode and ipv4_proxy_arp_mode: + ipv4_proxy_delete_request = {"path": ipv4_proxy_arp_url.format( + intf_name=name, sub_intf_name=sub_intf), "method": DELETE} + requests.append(ipv4_proxy_delete_request) + if ipv4_addrs: for ip in ipv4_addrs: if have_ipv4_addrs: @@ -499,6 +645,18 @@ def get_delete_l3_interfaces_requests(self, want, have): requests.append(anycast_delete_request) if is_del_ipv6: + + if have_ipv6_nd_proxy_rules: + for rule in have_ipv6_nd_proxy_rules: + encoded_nd_proxy_rules = urlencode({'nd-proxy-rules': rule}) + request = {"path": ipv6_nd_proxy_rules_url.format(intf_name=name, sub_intf_name=sub_intf, rules=encoded_nd_proxy_rules), + "method": DELETE} + requests.append(request) + + if have_ipv6_nd_proxy_mode: + ipv6_nd_proxy_delete_request = {"path": ipv6_nd_proxy_url.format(intf_name=name, sub_intf_name=sub_intf), "method": DELETE} + requests.append(ipv6_nd_proxy_delete_request) + if have_ipv6_addrs and len(have_ipv6_addrs) != 0: ipv6_addrs_delete_request = {"path": ipv6_addrs_url_all.format(intf_name=name, sub_intf_name=sub_intf), "method": DELETE} requests.append(ipv6_addrs_delete_request) @@ -519,6 +677,8 @@ def get_delete_l3_interfaces_requests(self, want, have): ipv6_enabled = None ipv6_autoconf = None ipv6_dad = None + ipv6_nd_proxy_rules = list() + ipv6_nd_proxy_mode = None if l3.get('ipv6'): if l3['ipv6'].get('addresses'): ipv6_addrs = l3['ipv6']['addresses'] @@ -528,6 +688,25 @@ def get_delete_l3_interfaces_requests(self, want, have): ipv6_autoconf = l3['ipv6']['autoconf'] if 'dad' in l3['ipv6']: ipv6_dad = l3['ipv6']['dad'] + if 'nd_proxy' in l3['ipv6'] and l3['ipv6']['nd_proxy'] is not None: + if 'mode' in l3['ipv6']['nd_proxy'] and l3['ipv6']['nd_proxy']['mode'] is not None: + ipv6_nd_proxy_mode = l3['ipv6']['nd_proxy']['mode'] + if 'nd_proxy_rules' in l3['ipv6']['nd_proxy'] and l3['ipv6']['nd_proxy']['nd_proxy_rules'] is not None: + ipv6_nd_proxy_rules = l3['ipv6']['nd_proxy']['nd_proxy_rules'] + + if ipv6_nd_proxy_rules: + for rule in ipv6_nd_proxy_rules: + if have_ipv6_nd_proxy_rules and rule in have_ipv6_nd_proxy_rules: + encoded_nd_proxy_rules = urlencode( + {'nd-proxy-rules': rule}) + request = { + "path": ipv6_nd_proxy_rules_url.format(intf_name=name, sub_intf_name=sub_intf, rules=encoded_nd_proxy_rules), + "method": DELETE} + requests.append(request) + + if have_ipv6_nd_proxy_mode and ipv6_nd_proxy_mode is not None: + request = {"path": ipv6_nd_proxy_url.format(intf_name=name, sub_intf_name=sub_intf), "method": DELETE} + requests.append(request) if ipv6_addrs: for ip in ipv6_addrs: @@ -564,11 +743,16 @@ def get_delete_all_requests(self, configs): ipv6_enabled_url = 'data/openconfig-interfaces:interfaces/interface={intf_name}/{sub_intf_name}/openconfig-if-ip:ipv6/config/enabled' ipv6_autoconf_url = 'data/openconfig-interfaces:interfaces/interface={intf_name}/{sub_intf_name}/openconfig-if-ip:ipv6/config/ipv6_autoconfig' ipv6_dad_url = 'data/openconfig-interfaces:interfaces/interface={intf_name}/{sub_intf_name}/openconfig-if-ip:ipv6/config/ipv6_dad' + ipv4_proxy_arp_url = 'data/openconfig-interfaces:interfaces/interface={intf_name}/{sub_intf_name}/openconfig-if-ip:ipv4/proxy-arp/config/mode' + ipv6_nd_proxy_url = 'data/openconfig-interfaces:interfaces/interface={intf_name}/{sub_intf_name}/openconfig-if-ip:ipv6/nd-proxy/config/mode' + ipv6_nd_proxy_rules_url = ('data/openconfig-interfaces:interfaces/interface={intf_name}/{sub_intf_name}/' + 'openconfig-if-ip:ipv6/nd-proxy/config/nd-proxy-rules') for l3 in configs: name = l3.get('name') ipv4_addrs = [] ipv4_anycast = [] + ipv4_proxy_arp_mode = None if name == "Management0": continue if l3.get('ipv4'): @@ -576,11 +760,16 @@ def get_delete_all_requests(self, configs): ipv4_addrs = l3['ipv4']['addresses'] if l3['ipv4'].get('anycast_addresses', None): ipv4_anycast = l3['ipv4']['anycast_addresses'] + if l3['ipv4'].get('proxy_arp'): + if 'mode' in l3['ipv4']['proxy_arp'] and l3['ipv4']['proxy_arp']['mode'] is not None: + ipv4_proxy_arp_mode = l3['ipv4']['proxy_arp']['mode'] ipv6_addrs = [] ipv6_enabled = None ipv6_autoconf = None ipv6_dad = None + ipv6_nd_proxy_mode = None + ipv6_nd_proxy_rules = [] if l3.get('ipv6'): if l3['ipv6'].get('addresses'): ipv6_addrs = l3['ipv6']['addresses'] @@ -590,9 +779,17 @@ def get_delete_all_requests(self, configs): ipv6_autoconf = l3['ipv6']['autoconf'] if 'dad' in l3['ipv6']: ipv6_dad = l3['ipv6']['dad'] + if 'nd_proxy' in l3['ipv6'] and l3['ipv6']['nd_proxy'] is not None: + if 'mode' in l3['ipv6']['nd_proxy'] and l3['ipv6']['nd_proxy']['mode'] is not None: + ipv6_nd_proxy_mode = l3['ipv6']['nd_proxy']['mode'] + if 'nd_proxy_rules' in l3['ipv6']['nd_proxy'] and l3['ipv6']['nd_proxy']['nd_proxy_rules'] is not None: + ipv6_nd_proxy_rules = l3['ipv6']['nd_proxy']['nd_proxy_rules'] sub_intf = self.get_sub_interface_name(name) + if ipv4_proxy_arp_mode: + ipv4_proxy_arp_delete_request = {"path": ipv4_proxy_arp_url.format(intf_name=name, sub_intf_name=sub_intf), "method": DELETE} + requests.append(ipv4_proxy_arp_delete_request) if ipv4_addrs: ipv4_addrs_delete_request = {"path": ipv4_addrs_url_all.format(intf_name=name, sub_intf_name=sub_intf), "method": DELETE} requests.append(ipv4_addrs_delete_request) @@ -601,6 +798,12 @@ def get_delete_all_requests(self, configs): ip = ip.replace('/', '%2f') anycast_delete_request = {"path": ipv4_anycast_url.format(intf_name=name, sub_intf_name=sub_intf, anycast_ip=ip), "method": DELETE} requests.append(anycast_delete_request) + if ipv6_nd_proxy_rules: + ipv6_nd_proxy_rules_delete_request = {"path": ipv6_nd_proxy_rules_url.format(intf_name=name, sub_intf_name=sub_intf), "method": DELETE} + requests.append(ipv6_nd_proxy_rules_delete_request) + if ipv6_nd_proxy_mode: + ipv6_nd_proxy_delete_request = {"path": ipv6_nd_proxy_url.format(intf_name=name, sub_intf_name=sub_intf), "method": DELETE} + requests.append(ipv6_nd_proxy_delete_request) if ipv6_addrs: ipv6_addrs_delete_request = {"path": ipv6_addrs_url_all.format(intf_name=name, sub_intf_name=sub_intf), "method": DELETE} requests.append(ipv6_addrs_delete_request) @@ -613,6 +816,7 @@ def get_delete_all_requests(self, configs): if ipv6_dad: ipv6_dad_delete_request = {"path": ipv6_dad_url.format(intf_name=name, sub_intf_name=sub_intf), "method": DELETE} requests.append(ipv6_dad_delete_request) + return requests def get_create_l3_interfaces_requests(self, configs): @@ -628,6 +832,10 @@ def get_create_l3_interfaces_requests(self, configs): ipv6_autoconf_url = 'data/openconfig-interfaces:interfaces/interface={intf_name}/{sub_intf_name}/openconfig-if-ip:ipv6/config' ipv6_eui64_url = 'data/openconfig-interfaces:interfaces/interface={intf_name}/{sub_intf_name}/openconfig-if-ip:ipv6/addresses' ipv6_dad_url = 'data/openconfig-interfaces:interfaces/interface={intf_name}/{sub_intf_name}/openconfig-if-ip:ipv6/config' + ipv4_proxy_arp_url = 'data/openconfig-interfaces:interfaces/interface={intf_name}/{sub_intf_name}/openconfig-if-ip:ipv4/proxy-arp/config/mode' + ipv6_nd_proxy_url = 'data/openconfig-interfaces:interfaces/interface={intf_name}/{sub_intf_name}/openconfig-if-ip:ipv6/nd-proxy/config/mode' + ipv6_nd_proxy_rules_url = ('data/openconfig-interfaces:interfaces/interface={intf_name}/{sub_intf_name}/' + 'openconfig-if-ip:ipv6/nd-proxy/config/nd-proxy-rules') for l3 in configs: l3_interface_name = l3.get('name') @@ -638,16 +846,22 @@ def get_create_l3_interfaces_requests(self, configs): ipv4_addrs = [] ipv4_anycast = [] + ipv4_proxy_arp_mode = None if l3.get('ipv4'): if l3['ipv4'].get('addresses'): ipv4_addrs = l3['ipv4']['addresses'] if l3['ipv4'].get('anycast_addresses'): ipv4_anycast = l3['ipv4']['anycast_addresses'] + if l3['ipv4'].get('proxy_arp'): + if 'mode' in l3['ipv4']['proxy_arp'] and l3['ipv4']['proxy_arp']['mode'] is not None: + ipv4_proxy_arp_mode = l3['ipv4']['proxy_arp']['mode'] ipv6_addrs = [] ipv6_enabled = None ipv6_autoconf = None ipv6_dad = None + ipv6_nd_proxy_mode = None + ipv6_nd_proxy_rules = [] if l3.get('ipv6'): if l3['ipv6'].get('addresses'): ipv6_addrs = l3['ipv6']['addresses'] @@ -657,6 +871,11 @@ def get_create_l3_interfaces_requests(self, configs): ipv6_autoconf = l3['ipv6']['autoconf'] if l3['ipv6'].get('dad'): ipv6_dad = l3['ipv6']['dad'] + if 'nd_proxy' in l3['ipv6'] and l3['ipv6']['nd_proxy'] is not None: + if 'mode' in l3['ipv6']['nd_proxy'] and l3['ipv6']['nd_proxy']['mode'] is not None: + ipv6_nd_proxy_mode = l3['ipv6']['nd_proxy']['mode'] + if 'nd_proxy_rules' in l3['ipv6']['nd_proxy'] and l3['ipv6']['nd_proxy']['nd_proxy_rules'] is not None: + ipv6_nd_proxy_rules = l3['ipv6']['nd_proxy']['nd_proxy_rules'] if ipv4_addrs: ipv4_addrs_pri_payload = [] @@ -684,6 +903,11 @@ def get_create_l3_interfaces_requests(self, configs): anycast_url = ipv4_anycast_url.format(intf_name=l3_interface_name, sub_intf_name=sub_intf) requests.append({'path': anycast_url, 'method': PATCH, 'data': anycast_payload}) + if ipv4_proxy_arp_mode: + proxy_arp_payload = self.build_update_ipv4_proxy_arp(ipv4_proxy_arp_mode) + proxy_arp_url = ipv4_proxy_arp_url.format(intf_name=l3_interface_name, sub_intf_name=sub_intf) + requests.append({'path': proxy_arp_url, 'method': PATCH, 'data': proxy_arp_payload}) + if ipv6_addrs: ipv6_addrs_payload = [] ipv6_addrs_eui64_payload = [] @@ -713,6 +937,17 @@ def get_create_l3_interfaces_requests(self, configs): ipv6_dad_req = {"path": ipv6_dad_url.format(intf_name=l3_interface_name, sub_intf_name=sub_intf), "method": PATCH, "data": payload} requests.append(ipv6_dad_req) + if ipv6_nd_proxy_mode is not None: + payload = self.build_update_ipv6_nd_proxy(ipv6_nd_proxy_mode) + ipv6_nd_proxy_req = {"path": ipv6_nd_proxy_url.format(intf_name=l3_interface_name, sub_intf_name=sub_intf), "method": PATCH, "data": payload} + requests.append(ipv6_nd_proxy_req) + + if len(ipv6_nd_proxy_rules) != 0: + nd_proxy_rule_payload = self.build_update_ipv6_nd_proxy_rules(ipv6_nd_proxy_rules) + ipv6_nd_proxy_rules_req = {"path": ipv6_nd_proxy_rules_url.format(intf_name=l3_interface_name, sub_intf_name=sub_intf), "method": PATCH, + "data": nd_proxy_rule_payload} + requests.append(ipv6_nd_proxy_rules_req) + return requests def validate_primary_ips(self, want): @@ -764,6 +999,19 @@ def build_update_ipv6_dad(self, ipv6_dad): payload = {'config': {'ipv6_dad': ipv6_dad}} return payload + def build_update_ipv4_proxy_arp(self, proxy_arp_mode): + ipv4_proxy_payload = {"openconfig-if-ip:mode": proxy_arp_mode} + return ipv4_proxy_payload + + def build_update_ipv6_nd_proxy(self, nd_proxy_mode): + ipv6_proxy_payload = {"openconfig-if-ip:mode": nd_proxy_mode} + return ipv6_proxy_payload + + def build_update_ipv6_nd_proxy_rules(self, nd_proxy_rules): + ipv6_proxy_payload = { + "openconfig-if-ip:nd-proxy-rules": nd_proxy_rules} + return ipv6_proxy_payload + def sort_lists_in_config(self, config): if config: config.sort(key=lambda x: x['name']) diff --git a/plugins/module_utils/network/sonic/facts/l3_interfaces/l3_interfaces.py b/plugins/module_utils/network/sonic/facts/l3_interfaces/l3_interfaces.py index 5ffddfd73..18a17d277 100644 --- a/plugins/module_utils/network/sonic/facts/l3_interfaces/l3_interfaces.py +++ b/plugins/module_utils/network/sonic/facts/l3_interfaces/l3_interfaces.py @@ -94,6 +94,12 @@ def get_l3_interfaces(self): if l3_ipv4: l3_dict['ipv4']['addresses'] = l3_ipv4 + if 'openconfig-if-ip:ipv4' in ip and 'proxy-arp' in ip['openconfig-if-ip:ipv4'] and \ + 'config' in ip['openconfig-if-ip:ipv4']['proxy-arp'] and \ + 'mode' in ip['openconfig-if-ip:ipv4']['proxy-arp']['config']: + l3_dict['ipv4'].setdefault('proxy_arp', {}) + l3_dict['ipv4']['proxy_arp']['mode'] = ip['openconfig-if-ip:ipv4']['proxy-arp']['config']['mode'] + l3_dict['ipv6'] = dict() l3_ipv6 = list() if 'openconfig-if-ip:ipv6' in ip: @@ -115,6 +121,12 @@ def get_l3_interfaces(self): l3_dict['ipv6']['autoconf'] = ip['openconfig-if-ip:ipv6']['config']['ipv6_autoconfig'] if 'config' in ip['openconfig-if-ip:ipv6'] and 'ipv6_dad' in ip['openconfig-if-ip:ipv6']['config']: l3_dict['ipv6']['dad'] = ip['openconfig-if-ip:ipv6']['config']['ipv6_dad'] + if 'nd-proxy' in ip['openconfig-if-ip:ipv6'] and 'config' in ip['openconfig-if-ip:ipv6']['nd-proxy'] and \ + 'mode' in ip['openconfig-if-ip:ipv6']['nd-proxy']['config']: + l3_dict['ipv6'].setdefault('nd_proxy', {}) + l3_dict['ipv6']['nd_proxy']['mode'] = ip['openconfig-if-ip:ipv6']['nd-proxy']['config']['mode'] + if 'nd-proxy-rules' in ip['openconfig-if-ip:ipv6']['nd-proxy']['config']: + l3_dict['ipv6']['nd_proxy']['nd_proxy_rules'] = ip['openconfig-if-ip:ipv6']['nd-proxy']['config']['nd-proxy-rules'] l3_configs.append(l3_dict) return l3_configs diff --git a/plugins/modules/sonic_l3_interfaces.py b/plugins/modules/sonic_l3_interfaces.py index 807dc0121..590cb44e7 100644 --- a/plugins/modules/sonic_l3_interfaces.py +++ b/plugins/modules/sonic_l3_interfaces.py @@ -80,6 +80,20 @@ - List of IPv4 addresses to be set for anycast. type: list elements: str + proxy_arp: + description: + - Configurations parameters for ipv4 proxy ARP + type: dict + suboptions: + mode: + description: + - Modes for proxy_arp + version_added: 3.1.0 + type: str + choices: + - DISABLE + - REMOTE_ONLY + - ALL ipv6: description: - ipv6 configurations to be set for the Layer 3 interface mentioned in name option. @@ -120,6 +134,26 @@ - ENABLE - DISABLE - DISABLE_IPV6_ON_FAILURE + nd_proxy: + description: + - Configurations parameters for ipv6 ND-proxy + type: dict + suboptions: + mode: + description: + - Modes for nd_proxy + version_added: 3.1.0 + type: str + choices: + - DISABLE + - REMOTE_ONLY + - ALL + nd_proxy_rules: + description: + - List of nd_proxy rules can be added. + version_added: 3.1.0 + type: list + elements: str state: description: - The state of the configuration after module completion. @@ -152,6 +186,8 @@ # ipv6 enable # ipv6 address autoconfig # ipv6 nd dad enable +# ip proxy-arp enable remote-only +# ipv6 nd-proxy enable all #! #interface Ethernet24 # mtu 9100 @@ -175,6 +211,8 @@ config: - name: Ethernet20 ipv4: + proxy_arp: + - mode: REMOTE_ONLY addresses: - address: 83.1.1.1/16 - address: 84.1.1.1/16 @@ -206,6 +244,7 @@ # ipv6 enable # ipv6 address autoconfig # ipv6 nd dad enable +# ipv6 nd-proxy enable all #! #interface Ethernet24 # mtu 9100 @@ -240,6 +279,9 @@ # ipv6 enable # ipv6 address autoconfig # ipv6 nd dad enable +# ip proxy-arp enable remote-only +# ipv6 nd-proxy enable all +# ipv6 nd-proxy rule prefix 5001::/24 #! #interface Ethernet24 # mtu 9100 @@ -250,6 +292,9 @@ # ipv6 address 91::1/16 # ipv6 address 92::1/16 # ipv6 address 93::1/16 +# ip proxy-arp enable all +# ipv6 nd-proxy enable remote-only +# ipv6 nd-proxy rule prefix 6001::/24 #! #interface Vlan501 # ip anycast-address 11.12.13.14/12 diff --git a/tests/regression/roles/sonic_l3_interfaces/defaults/main.yml b/tests/regression/roles/sonic_l3_interfaces/defaults/main.yml index e50b3c92f..a114650d0 100644 --- a/tests/regression/roles/sonic_l3_interfaces/defaults/main.yml +++ b/tests/regression/roles/sonic_l3_interfaces/defaults/main.yml @@ -37,6 +37,9 @@ tests: - address: 150::1/32 - address: 160::/64 eui64: True + nd_proxy: + mode: ALL + nd_proxy_rules: [3001::/24, 5001::/24] - name: po 100 ipv4: addresses: @@ -64,6 +67,10 @@ tests: ipv4: addresses: - address: 150.1.1.1/16 + ipv6: + nd_proxy: + mode: REMOTE_ONLY + nd_proxy_rules: [7001::/24] - name: po 100 ipv6: enabled: true @@ -71,6 +78,9 @@ tests: autoconf: True addresses: - address: 180::1/16 + nd_proxy: + mode: ALL + nd_proxy_rules: [8101::/24, 8101::/64] - name: vlan 102 ipv4: anycast_addresses: @@ -91,18 +101,27 @@ tests: ipv4: addresses: - address: 152.1.1.1/16 + proxy_arp: + mode: ALL ipv6: enabled: true addresses: - address: 152::1/16 + nd_proxy: + mode: ALL - name: po 100 ipv4: addresses: - address: 182.1.1.1/16 + proxy_arp: + mode: REMOTE_ONLY ipv6: enabled: true addresses: - address: 182::1/16 + nd_proxy: + mode: REMOTE_ONLY + nd_proxy_rules: [3101::/24, 5101::/24] - name: test_case_04 description: Update interface parameters state: merged @@ -119,6 +138,9 @@ tests: - address: 90::1/16 - address: 100::/64 eui64: True + nd_proxy: + mode: ALL + nd_proxy_rules: [1001::/24, 6001::/24] - name: test_case_05 description: Update interface parameters state: merged @@ -133,6 +155,9 @@ tests: addresses: - address: 90::1/16 - address: 91::1/16 + nd_proxy: + mode: REMOTE_ONLY + nd_proxy_rules: [1101::/24, 6101::/24] - name: test_case_06 description: Update interface parameters state: merged @@ -141,11 +166,16 @@ tests: ipv4: addresses: - address: 83.1.1.1/16 + proxy_arp: + mode: ALL ipv6: enabled: true addresses: - address: 83::1/16 - address: 84::1/16 + nd_proxy: + mode: ALL + nd_proxy_rules: [1301::/24] - name: "{{ interface2 }}" ipv4: addresses: @@ -156,14 +186,18 @@ tests: - address: 91::1/16 - address: 92::1/16 - address: 93::1/16 + nd_proxy: + nd_proxy_rules: [8101::/24] - name: test_case_07 - description: Delete interface addresses + description: Delete interface addresses and disabling the proxy in the interfaces state: deleted input: - name: "{{ interface1 }}" ipv4: addresses: - address: 83.1.1.1/16 + proxy_arp: + mode: ALL - name: "{{ interface2 }}" ipv6: enabled: false @@ -172,16 +206,32 @@ tests: - address: 91::1/16 - address: 100::/64 eui64: True + nd_proxy: + mode: ALL + nd_proxy_rules: + [1101::/24, 6101::/24, 8101::/24, 1001::/24, 6001::/24] - name: Loopback100 ipv4: addresses: - address: 103.1.1.1/32 ipv6: autoconf: True + - name: vlan 100 + ipv4: + proxy_arp: + mode: ALL + ipv6: + nd_proxy: + mode: ALL + nd_proxy_rules: [3001::/24, 5001::/24, 7001::/24] - name: vlan 102 ipv4: anycast_addresses: - 1.1.1.1/16 + - name: po 100 + ipv4: + proxy_arp: + mode: DISABLE - name: test_case_08 description: Delete interface parameters state: deleted @@ -197,10 +247,15 @@ tests: ipv4: addresses: - address: 104.1.1.1/16 + proxy_arp: + mode: ALL ipv6: addresses: - address: 1041::1/16 - address: 1042::1/16 + nd_proxy: + mode: ALL + nd_proxy_rules: [3001::/24, 5001::/24, 7001::/24] - name: Loopback101 ipv4: addresses: @@ -218,6 +273,9 @@ tests: addresses: - address: 3041::1/16 - address: 3042::1/16 + nd_proxy: + mode: REMOTE_ONLY + nd_proxy_rules: [3001::/24, 5001::/24, 7001::/24] - name: test_case_10 description: Update interface parameters state: merged @@ -226,6 +284,8 @@ tests: ipv4: addresses: - address: 105.1.1.1/16 + proxy_arp: + mode: REMOTE_ONLY ipv6: enabled: true dad: ENABLE @@ -234,6 +294,9 @@ tests: - address: 1052::1/16 - address: 1060::/64 eui64: True + nd_proxy: + mode: REMOTE_ONLY + nd_proxy_rules: [3101::/24, 5101::/24, 7101::/24] - name: lo101 ipv4: addresses: @@ -270,6 +333,8 @@ tests: - address: 215.1.1.1/24 - address: 216.1.1.1/24 secondary: true + proxy_arp: + mode: ALL - name: test_case_12 description: Replace interface parameters state: replaced @@ -280,10 +345,15 @@ tests: addresses: - address: 251::1/64 - address: 252::1/64 + nd_proxy: + mode: REMOTE_ONLY + nd_proxy_rules: [3001::/24, 5001::/24, 7001::/24] - name: '{{ interface3 }}' ipv4: addresses: - address: 222.1.1.1/24 + proxy_arp: + mode: REMOTE_ONLY - name: vlan 101 ipv4: anycast_addresses: @@ -296,6 +366,8 @@ tests: ipv4: addresses: - address: 105.2.2.2/16 + proxy_arp: + mode: ALL ipv6: enabled: False autoconf: False @@ -303,6 +375,9 @@ tests: addresses: - address: 1050::/64 eui64: True + nd_proxy: + mode: ALL + nd_proxy_rules: [8101::/24, 9101::/24, 2101::/24] - name: test_case_14 description: Replace interface parameters state: replaced @@ -314,12 +389,17 @@ tests: addresses: - address: 251::1/64 - address: 252::1/64 + nd_proxy: + mode: ALL + nd_proxy_rules: [5101::/24, 6101::/24, 7101::/24] - name: '{{ interface3 }}' ipv4: addresses: - address: 222.1.1.1/24 - address: 223.1.1.1/24 secondary: true + proxy_arp: + mode: ALL - name: test_case_15 description: Override interface parameters state: overridden @@ -332,6 +412,8 @@ tests: - address: 1054::1/64 - address: 1055::1/64 - address: 1056::2/64 + nd_proxy: + mode: REMOTE_ONLY - name: Loopback101 ipv4: addresses: @@ -359,6 +441,8 @@ tests: - address: 1055::1/64 - address: 1056::2/64 - address: 1057::2/64 + nd_proxy: + mode: REMOTE_ONLY - name: Loopback101 ipv4: addresses: @@ -384,6 +468,8 @@ tests: - address: 1056::2/64 - address: 1057::2/64 - address: 1058::2/64 + nd_proxy: + mode: DISABLE - name: Loopback101 ipv4: addresses: diff --git a/tests/unit/modules/network/sonic/fixtures/sonic_l3_interfaces.yaml b/tests/unit/modules/network/sonic/fixtures/sonic_l3_interfaces.yaml index 7528fbfef..dbbc17c7f 100644 --- a/tests/unit/modules/network/sonic/fixtures/sonic_l3_interfaces.yaml +++ b/tests/unit/modules/network/sonic/fixtures/sonic_l3_interfaces.yaml @@ -8,6 +8,8 @@ merged_01: - address: 83.1.1.1/16 - address: 84.1.1.1/16 secondary: True + proxy_arp: + mode: REMOTE_ONLY ipv6: enabled: true autoconf: true @@ -16,12 +18,17 @@ merged_01: - address: 84::/64 eui64: true - address: 83::1/16 + nd_proxy: + mode: ALL + nd_proxy_rules: [3001::/24, 5001::/24] - name: Vlan11 ipv4: addresses: - address: 73.1.1.1/16 - address: 74.1.1.1/16 secondary: True + proxy_arp: + mode: ALL ipv6: enabled: true dad: DISABLE_IPV6_ON_FAILURE @@ -29,6 +36,9 @@ merged_01: - address: 70::/64 eui64: true - address: 73::1/16 + nd_proxy: + mode: REMOTE_ONLY + nd_proxy_rules: [9001::/24, 1001::/24] - name: Vlan12 ipv4: anycast_addresses: @@ -62,6 +72,24 @@ merged_01: ip: 84.1.1.1 prefix-length: 16.0 secondary: True + - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f1/subinterfaces/subinterface=0/openconfig-if-ip:ipv4/proxy-arp/config/mode" + method: "patch" + data: + openconfig-if-ip:mode: REMOTE_ONLY + - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f1/subinterfaces/subinterface=0/openconfig-if-ip:ipv6/addresses" + method: "patch" + data: + openconfig-if-ip:addresses: + address: + - ip: "84::" + openconfig-if-ip:config: + ip: "84::" + prefix-length: 64.0 + openconfig-interfaces-private:eui64: true + - ip: "83::1" + openconfig-if-ip:config: + ip: "83::1" + prefix-length: 16.0 - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f1/subinterfaces/subinterface=0/openconfig-if-ip:ipv6/config" method: "patch" data: @@ -77,20 +105,14 @@ merged_01: data: config: ipv6_dad: ENABLE - - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f1/subinterfaces/subinterface=0/openconfig-if-ip:ipv6/addresses" + - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f1/subinterfaces/subinterface=0/openconfig-if-ip:ipv6/nd-proxy/config/mode" method: "patch" data: - openconfig-if-ip:addresses: - address: - - ip: "84::" - openconfig-if-ip:config: - ip: "84::" - prefix-length: 64.0 - openconfig-interfaces-private:eui64: true - - ip: "83::1" - openconfig-if-ip:config: - ip: "83::1" - prefix-length: 16.0 + openconfig-if-ip:mode: ALL + - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f1/subinterfaces/subinterface=0/openconfig-if-ip:ipv6/nd-proxy/config/nd-proxy-rules" + method: "patch" + data: + openconfig-if-ip:nd-proxy-rules: [3001::/24, 5001::/24] - path: "data/openconfig-interfaces:interfaces/interface=Vlan11/openconfig-vlan:routed-vlan/openconfig-if-ip:ipv4/addresses" method: "patch" data: @@ -110,6 +132,10 @@ merged_01: ip: 74.1.1.1 prefix-length: 16.0 secondary: True + - path: "data/openconfig-interfaces:interfaces/interface=Vlan11/openconfig-vlan:routed-vlan/openconfig-if-ip:ipv4/proxy-arp/config/mode" + method: "patch" + data: + openconfig-if-ip:mode: ALL - path: "data/openconfig-interfaces:interfaces/interface=Vlan11/openconfig-vlan:routed-vlan/openconfig-if-ip:ipv6/addresses" method: "patch" data: @@ -134,6 +160,14 @@ merged_01: data: config: ipv6_dad: DISABLE_IPV6_ON_FAILURE + - path: "data/openconfig-interfaces:interfaces/interface=Vlan11/openconfig-vlan:routed-vlan/openconfig-if-ip:ipv6/nd-proxy/config/mode" + method: "patch" + data: + openconfig-if-ip:mode: REMOTE_ONLY + - path: "data/openconfig-interfaces:interfaces/interface=Vlan11/openconfig-vlan:routed-vlan/openconfig-if-ip:ipv6/nd-proxy/config/nd-proxy-rules" + method: "patch" + data: + openconfig-if-ip:nd-proxy-rules: [9001::/24, 1001::/24] - path: "data/openconfig-interfaces:interfaces/interface=Vlan12/openconfig-vlan:routed-vlan/openconfig-if-ip:ipv4/openconfig-interfaces-ext:sag-ipv4/config/static-anycast-gateway" method: "patch" data: @@ -152,7 +186,7 @@ deleted_01: subinterfaces: subinterface: - index: 0 - config: + config: index: 0 openconfig-if-ip:ipv4: addresses: @@ -161,6 +195,9 @@ deleted_01: ip: 73.1.1.1 prefix-length: 8 secondary: False + proxy-arp: + config: + mode: REMOTE_ONLY openconfig-if-ip:ipv6: addresses: address: @@ -170,6 +207,10 @@ deleted_01: enabled: True ipv6_dad: ENABLE ipv6_autoconfig: True + nd-proxy: + config: + mode: ALL + nd-proxy-rules: [1001::/24, 5001::/24] - name: Vlan99 openconfig-vlan:routed-vlan: openconfig-if-ip:ipv4: @@ -179,6 +220,9 @@ deleted_01: ip: 99.99.99.99 prefix-length: 8 secondary: False + proxy-arp: + config: + mode: ALL - name: Vlan88 openconfig-vlan:routed-vlan: openconfig-if-ip:ipv4: @@ -189,15 +233,27 @@ deleted_01: - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f1/subinterfaces/subinterface=0/openconfig-if-ip:ipv4/addresses" method: "delete" data: + - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f1/subinterfaces/subinterface=0/openconfig-if-ip:ipv4/proxy-arp/config/mode" + method: "delete" + data: - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f1/subinterfaces/subinterface=0/openconfig-if-ip:ipv6/addresses" method: "delete" data: + - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f1/subinterfaces/subinterface=0/openconfig-if-ip:ipv6/nd-proxy/config/mode" + method: "delete" + data: + - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f1/subinterfaces/subinterface=0/openconfig-if-ip:ipv6/nd-proxy/config/nd-proxy-rules" + method: "delete" + data: - path: "data/openconfig-interfaces:interfaces/interface=Vlan88/openconfig-vlan:routed-vlan/openconfig-if-ip:ipv4/openconfig-interfaces-ext:sag-ipv4/config/static-anycast-gateway=11.12.13.14%2f12" method: "delete" data: - path: "data/openconfig-interfaces:interfaces/interface=Vlan99/openconfig-vlan:routed-vlan/openconfig-if-ip:ipv4/addresses" method: "delete" data: + - path: "data/openconfig-interfaces:interfaces/interface=Vlan99/openconfig-vlan:routed-vlan/openconfig-if-ip:ipv4/proxy-arp/config/mode" + method: "delete" + data: deleted_02: module_args: @@ -208,17 +264,24 @@ deleted_02: addresses: - address: 84.1.1.1/8 secondary: True + proxy_arp: + mode: REMOTE_ONLY ipv6: addresses: - address: 84::1/64 - address: 85::/64 eui64: True + nd_proxy: + mode: ALL + nd_proxy_rules: [3001::/24, 5001::/24] - name: Eth1/2 - name: Vlan99 ipv4: addresses: - address: 74.1.1.1/8 secondary: True + proxy_arp: + mode: ALL ipv6: enabled: true autoconf: true @@ -236,7 +299,7 @@ deleted_02: subinterfaces: subinterface: - index: 0 - config: + config: index: 0 openconfig-if-ip:ipv4: addresses: @@ -249,6 +312,9 @@ deleted_02: ip: 84.1.1.1 prefix-length: 8 secondary: True + proxy-arp: + config: + mode: REMOTE_ONLY openconfig-if-ip:ipv6: addresses: address: @@ -262,13 +328,17 @@ deleted_02: ip: "85::" prefix-length: 64 openconfig-interfaces-private:eui64: True + nd-proxy: + config: + mode: ALL + nd-proxy-rules: [3001::/24, 5001::/24] config: enabled: True - name: Eth1/2 subinterfaces: subinterface: - index: 0 - config: + config: index: 0 openconfig-if-ip:ipv4: addresses: @@ -281,6 +351,9 @@ deleted_02: ip: 94.1.1.2 prefix-length: 8 secondary: True + proxy-arp: + config: + mode: ALL openconfig-if-ip:ipv6: addresses: address: @@ -290,6 +363,10 @@ deleted_02: - config: ip: 94::2 prefix-length: 64 + nd-proxy: + config: + mode: REMOTE_ONLY + nd-proxy-rules: [7001::/24, 8001::/24] config: enabled: True ipv6_autoconfig: True @@ -307,6 +384,9 @@ deleted_02: ip: 74.1.1.1 prefix-length: 8 secondary: True + proxy-arp: + config: + mode: ALL openconfig-if-ip:ipv6: addresses: address: @@ -327,15 +407,30 @@ deleted_02: - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f1/subinterfaces/subinterface=0/openconfig-if-ip:ipv4/addresses/address=84.1.1.1/config/secondary" method: "delete" data: + - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f1/subinterfaces/subinterface=0/openconfig-if-ip:ipv4/proxy-arp/config/mode" + method: "delete" + data: - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f1/subinterfaces/subinterface=0/openconfig-if-ip:ipv6/addresses/address=84::1" method: "delete" data: - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f1/subinterfaces/subinterface=0/openconfig-if-ip:ipv6/addresses/address=85::" method: "delete" data: + - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f1/subinterfaces/subinterface=0/openconfig-if-ip:ipv6/nd-proxy/config/mode" + method: "delete" + data: + - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f1/subinterfaces/subinterface=0/openconfig-if-ip:ipv6/nd-proxy/config/nd-proxy-rules=3001%3A%3A%2F24" + method: "delete" + data: + - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f1/subinterfaces/subinterface=0/openconfig-if-ip:ipv6/nd-proxy/config/nd-proxy-rules=5001%3A%3A%2F24" + method: "delete" + data: - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f2/subinterfaces/subinterface=0/openconfig-if-ip:ipv4/addresses" method: "delete" data: + - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f2/subinterfaces/subinterface=0/openconfig-if-ip:ipv4/proxy-arp/config/mode" + method: "delete" + data: - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f2/subinterfaces/subinterface=0/openconfig-if-ip:ipv6/addresses" method: "delete" data: @@ -348,12 +443,24 @@ deleted_02: - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f2/subinterfaces/subinterface=0/openconfig-if-ip:ipv6/config/ipv6_dad" method: "delete" data: + - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f2/subinterfaces/subinterface=0/openconfig-if-ip:ipv6/nd-proxy/config/mode" + method: "delete" + data: + - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f2/subinterfaces/subinterface=0/openconfig-if-ip:ipv6/nd-proxy/config/nd-proxy-rules=7001%3A%3A%2F24" + method: "delete" + data: + - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f2/subinterfaces/subinterface=0/openconfig-if-ip:ipv6/nd-proxy/config/nd-proxy-rules=8001%3A%3A%2F24" + method: "delete" + data: - path: "data/openconfig-interfaces:interfaces/interface=Vlan88/openconfig-vlan:routed-vlan/openconfig-if-ip:ipv4/openconfig-interfaces-ext:sag-ipv4/config/static-anycast-gateway=11.12.13.14%2f12" method: "delete" data: - path: "data/openconfig-interfaces:interfaces/interface=Vlan99/openconfig-vlan:routed-vlan/openconfig-if-ip:ipv4/addresses/address=74.1.1.1/config/secondary" method: "delete" data: + - path: "data/openconfig-interfaces:interfaces/interface=Vlan99/openconfig-vlan:routed-vlan/openconfig-if-ip:ipv4/proxy-arp/config/mode" + method: "delete" + data: - path: "data/openconfig-interfaces:interfaces/interface=Vlan99/openconfig-vlan:routed-vlan/openconfig-if-ip:ipv6/addresses/address=73::1" method: "delete" data: @@ -385,6 +492,8 @@ replaced_01: - address: 31.31.31.1/24 - address: 32.32.32.1/24 secondary: True + proxy_arp: + mode: DISABLE ipv6: addresses: - address: 33::/64 @@ -394,6 +503,8 @@ replaced_01: enabled: true autoconf: true dad: ENABLE + nd_proxy: + mode: DISABLE existing_l3_interfaces_config: - path: "data/openconfig-interfaces:interfaces/interface" response: @@ -413,6 +524,9 @@ replaced_01: ip: 73.1.1.1 prefix-length: 8 secondary: False + proxy-arp: + config: + mode: REMOTE_ONLY openconfig-if-ip:ipv6: addresses: address: @@ -420,6 +534,10 @@ replaced_01: ip: 73::1 prefix-length: 64 enabled: True + nd-proxy: + config: + mode: REMOTE_ONLY + nd-proxy-rules: [7001::/24, 8001::/24] - name: Eth1/2 subinterfaces: subinterface: @@ -437,6 +555,9 @@ replaced_01: ip: 94.1.1.2 prefix-length: 8 secondary: True + proxy-arp: + config: + mode: DISABLE openconfig-if-ip:ipv6: addresses: address: @@ -448,6 +569,10 @@ replaced_01: prefix-length: 64 config: enabled: True + nd-proxy: + config: + mode: ALL + nd-proxy-rules: [2001::/24, 3001::/24] - name: Vlan99 openconfig-vlan:routed-vlan: openconfig-if-ip:ipv4: @@ -461,9 +586,6 @@ replaced_01: - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f1/subinterfaces/subinterface=0/openconfig-if-ip:ipv4/addresses" method: "delete" data: - - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f1/subinterfaces/subinterface=0/openconfig-if-ip:ipv6/addresses" - method: "delete" - data: - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f1/subinterfaces/subinterface=0/openconfig-if-ip:ipv4/addresses" method: "patch" data: @@ -483,6 +605,19 @@ replaced_01: ip: 32.32.32.1 prefix-length: 24.0 secondary: True + - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f1/subinterfaces/subinterface=0/openconfig-if-ip:ipv4/proxy-arp" + method: "delete" + data: + - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f1/subinterfaces/subinterface=0/openconfig-if-ip:ipv4/proxy-arp/config/mode" + method: "delete" + data: + - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f1/subinterfaces/subinterface=0/openconfig-if-ip:ipv4/proxy-arp/config/mode" + method: "patch" + data: + openconfig-if-ip:mode: DISABLE + - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f1/subinterfaces/subinterface=0/openconfig-if-ip:ipv6/addresses" + method: "delete" + data: - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f1/subinterfaces/subinterface=0/openconfig-if-ip:ipv6/addresses" method: "patch" data: @@ -516,6 +651,19 @@ replaced_01: data: config: ipv6_dad: ENABLE + - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f1/subinterfaces/subinterface=0/openconfig-if-ip:ipv6/nd-proxy" + method: "delete" + data: + - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f1/subinterfaces/subinterface=0/openconfig-if-ip:ipv6/nd-proxy/config/mode" + method: "delete" + data: + - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f1/subinterfaces/subinterface=0/openconfig-if-ip:ipv6/nd-proxy/config/mode" + method: "patch" + data: + openconfig-if-ip:mode: DISABLE + - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f1/subinterfaces/subinterface=0/openconfig-if-ip:ipv6/nd-proxy/config/nd-proxy-rules" + method: "delete" + data: - path: "data/openconfig-interfaces:interfaces/interface=Vlan13/openconfig-vlan:routed-vlan/openconfig-if-ip:ipv4/openconfig-interfaces-ext:sag-ipv4/config/static-anycast-gateway" method: "patch" data: @@ -545,6 +693,8 @@ overridden_01: - address: 31.31.31.1/24 - address: 32.32.32.1/24 secondary: True + proxy_arp: + mode: REMOTE_ONLY ipv6: addresses: - address: 33::/64 @@ -553,6 +703,9 @@ overridden_01: - address: 32::1/64 enabled: False autoconf: False + nd_proxy: + mode: REMOTE_ONLY + nd_proxy_rules: [7001::/24, 8001::/24] existing_l3_interfaces_config: - path: "data/openconfig-interfaces:interfaces/interface" response: @@ -572,6 +725,9 @@ overridden_01: ip: 73.1.1.1 prefix-length: 8 secondary: False + proxy-arp: + config: + mode: DISABLE openconfig-if-ip:ipv6: addresses: address: @@ -579,6 +735,11 @@ overridden_01: ip: 73::1 prefix-length: 64 enabled: True + nd-proxy: + config: + mode: ALL + nd-proxy-rules: [2001::/24, 3001::/24] + - name: Eth1/2 subinterfaces: subinterface: @@ -596,6 +757,9 @@ overridden_01: ip: 94.1.1.2 prefix-length: 8 secondary: True + proxy-arp: + config: + mode: REMOTE_ONLY openconfig-if-ip:ipv6: addresses: address: @@ -607,6 +771,10 @@ overridden_01: prefix-length: 64 config: enabled: True + nd-proxy: + config: + mode: REMOTE_ONLY + nd-proxy-rules: [2001::/24, 3001::/24] - name: Vlan99 openconfig-vlan:routed-vlan: openconfig-if-ip:ipv4: @@ -616,25 +784,13 @@ overridden_01: ip: 99.99.99.99 prefix-length: 8 secondary: False + proxy-arp: + config: + mode: ALL expected_config_requests: - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f1/subinterfaces/subinterface=0/openconfig-if-ip:ipv4/addresses" method: "delete" data: - - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f1/subinterfaces/subinterface=0/openconfig-if-ip:ipv6/addresses" - method: "delete" - data: - - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f2/subinterfaces/subinterface=0/openconfig-if-ip:ipv4/addresses" - method: "delete" - data: - - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f2/subinterfaces/subinterface=0/openconfig-if-ip:ipv6/addresses" - method: "delete" - data: - - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f2/subinterfaces/subinterface=0/openconfig-if-ip:ipv6/config/enabled" - method: "delete" - data: - - path: "data/openconfig-interfaces:interfaces/interface=Vlan99/openconfig-vlan:routed-vlan/openconfig-if-ip:ipv4/addresses" - method: "delete" - data: - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f1/subinterfaces/subinterface=0/openconfig-if-ip:ipv4/addresses" method: "patch" data: @@ -654,6 +810,16 @@ overridden_01: ip: 32.32.32.1 prefix-length: 24.0 secondary: True + - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f1/subinterfaces/subinterface=0/openconfig-if-ip:ipv4/proxy-arp/config/mode" + method: "delete" + data: + - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f1/subinterfaces/subinterface=0/openconfig-if-ip:ipv4/proxy-arp/config/mode" + method: "patch" + data: + openconfig-if-ip:mode: REMOTE_ONLY + - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f1/subinterfaces/subinterface=0/openconfig-if-ip:ipv6/addresses" + method: "delete" + data: - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f1/subinterfaces/subinterface=0/openconfig-if-ip:ipv6/addresses" method: "patch" data: @@ -672,6 +838,38 @@ overridden_01: openconfig-if-ip:config: ip: 32::1 prefix-length: 64.0 + - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f1/subinterfaces/subinterface=0/openconfig-if-ip:ipv6/nd-proxy/config/mode" + method: "delete" + data: + - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f1/subinterfaces/subinterface=0/openconfig-if-ip:ipv6/nd-proxy/config/mode" + method: "patch" + data: + openconfig-if-ip:mode: REMOTE_ONLY + - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f1/subinterfaces/subinterface=0/openconfig-if-ip:ipv6/nd-proxy/config/nd-proxy-rules" + method: "delete" + data: + - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f1/subinterfaces/subinterface=0/openconfig-if-ip:ipv6/nd-proxy/config/nd-proxy-rules" + method: "patch" + data: + openconfig-if-ip:nd-proxy-rules: [7001::/24, 8001::/24] + - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f2/subinterfaces/subinterface=0/openconfig-if-ip:ipv4/addresses" + method: "delete" + data: + - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f2/subinterfaces/subinterface=0/openconfig-if-ip:ipv4/proxy-arp/config/mode" + method: "delete" + data: + - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f2/subinterfaces/subinterface=0/openconfig-if-ip:ipv6/addresses" + method: "delete" + data: + - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f2/subinterfaces/subinterface=0/openconfig-if-ip:ipv6/config/enabled" + method: "delete" + data: + - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f2/subinterfaces/subinterface=0/openconfig-if-ip:ipv6/nd-proxy/config/mode" + method: "delete" + data: + - path: "data/openconfig-interfaces:interfaces/interface=Eth1%2f2/subinterfaces/subinterface=0/openconfig-if-ip:ipv6/nd-proxy/config/nd-proxy-rules" + method: "delete" + data: - path: "data/openconfig-interfaces:interfaces/interface=Vlan13/openconfig-vlan:routed-vlan/openconfig-if-ip:ipv4/openconfig-interfaces-ext:sag-ipv4/config/static-anycast-gateway" method: "patch" data: @@ -692,3 +890,9 @@ overridden_01: data: config: ipv6_dad: DISABLE_IPV6_ON_FAILURE + - path: "data/openconfig-interfaces:interfaces/interface=Vlan99/openconfig-vlan:routed-vlan/openconfig-if-ip:ipv4/addresses" + method: "delete" + data: + - path: "data/openconfig-interfaces:interfaces/interface=Vlan99/openconfig-vlan:routed-vlan/openconfig-if-ip:ipv4/proxy-arp/config/mode" + method: "delete" + data: