diff --git a/src/device/service/drivers/openconfig/templates/VPN/Network_instance_multivendor.py b/src/device/service/drivers/openconfig/templates/VPN/Network_instance_multivendor.py
index 761312c475973e9ef3034258dd8f5885b8e91bca..e2a17e8989869927c49528d44d94893461549ef8 100644
--- a/src/device/service/drivers/openconfig/templates/VPN/Network_instance_multivendor.py
+++ b/src/device/service/drivers/openconfig/templates/VPN/Network_instance_multivendor.py
@@ -68,12 +68,14 @@ def create_NI(parameters,vendor,DEL):
with tag('router-id'):text(parameters['router_id'])
if vendor is None or vendor == 'ADVA':
with tag('type', 'xmlns:oc-ni-types="http://openconfig.net/yang/network-instance-types"'):text('oc-ni-types:',parameters['type'])
+ with tag('enable'):text('true')
+ with tag('enabled-address-families', 'xmlns:oc-types="http://openconfig.net/yang/openconfig-types"'):text('oc-types:IPV4')
with tag('route-distinguisher'):text(parameters['route_distinguisher'])
- if vendor is None or vendor == 'ADVA':
- with tag('encapsulation'):
- with tag('config'):
- with tag('encapsulation-type', 'xmlns:oc-ni-types="http://openconfig.net/yang/network-instance-types"') :text('oc-ni-types:MPLS')
- with tag('label-allocation-mode','xmlns:oc-ni-types="http://openconfig.net/yang/network-instance-types"'):text('oc-ni-types:INSTANCE_LABEL')
+ #if vendor is None or vendor == 'ADVA':
+ # with tag('encapsulation'):
+ # with tag('config'):
+ # with tag('encapsulation-type', 'xmlns:oc-ni-types="http://openconfig.net/yang/network-instance-types"') :text('oc-ni-types:MPLS')
+ # with tag('label-allocation-mode','xmlns:oc-ni-types="http://openconfig.net/yang/network-instance-types"'):text('oc-ni-types:INSTANCE_LABEL')
result = indent(
doc.getvalue(),
@@ -148,7 +150,9 @@ def add_protocol_NI(parameters,vendor, DEL):
with tag('afi-safis'):
with tag('afi-safi', 'xmlns:oc-bgp-types="http://openconfig.net/yang/bgp-types"'):
with tag('afi-safi-name'): text('oc-bgp-types:IPV4_UNICAST')
- with tag('enabled'): text('true')
+ with tag('config'):
+ with tag('afi-safi-name'): text('oc-bgp-types:IPV4_UNICAST')
+ with tag('enabled'): text('true')
with tag('config'):
with tag('neighbor-address'): text(neighbor['ip_address'])
with tag('enabled'): text('true')
@@ -291,15 +295,23 @@ def associate_virtual_circuit(parameters):
def associate_RP_to_NI(parameters):
doc, tag, text = Doc().tagtext()
with tag('network-instances',xmlns="http://openconfig.net/yang/network-instance"):
- with tag('network-instance'):
- with tag('name'):text(parameters['name'])
- with tag('inter-instance-policies'):
- with tag('apply-policy'):
- with tag('config'):
- if'import_policy' in parameters :
- with tag('import-policy'):text(parameters['import_policy'])
- elif 'export_policy' in parameters:
- with tag('export-policy'):text(parameters['export_policy'])
+ with tag('network-instance'):
+ with tag('name'): text(parameters['name'])
+ with tag('inter-instance-policies'):
+ if 'import_policy' in parameters or 'export_policy' in parameters:
+ with tag('apply-policy'):
+ with tag('config'):
+ if 'import_policy' in parameters:
+ with tag('import-policy'): text(parameters['import_policy'])
+ if 'export_policy' in parameters:
+ with tag('export-policy'): text(parameters['export_policy'])
+ if 'import_route_target' in parameters or 'export_route_target' in parameters:
+ with tag('import-export-policy'):
+ with tag('config'):
+ if 'import_route_target' in parameters:
+ with tag('import-route-target'): text(parameters['import_route_target'])
+ if 'export_route_target' in parameters:
+ with tag('export-route-target'): text(parameters['export_route_target'])
result = indent(
doc.getvalue(),
indentation = ' '*2,
@@ -338,12 +350,12 @@ def create_table_conns(parameters,DEL):
with tag('name'):text(parameters['name'])
if DEL == True:
with tag('table-connections'):
- with tag('table-connection','xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" nc:operation="delete"'):
- with tag('src-protocol','xmlns:oc-pol-types="http://openconfig.net/yang/policy-types"'): text('oc-pol-types:',parameters['src_protocol'])
- with tag('dst-protocol','xmlns:oc-pol-types="http://openconfig.net/yang/policy-types"'): text('oc-pol-types:',parameters['dst_protocol'])
+ with tag('table-connection', 'xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" nc:operation="delete"'):
+ with tag('src-protocol', 'xmlns:oc-pol-types="http://openconfig.net/yang/policy-types"'): text('oc-pol-types:',parameters['src_protocol'])
+ with tag('dst-protocol', 'xmlns:oc-pol-types="http://openconfig.net/yang/policy-types"'): text('oc-pol-types:',parameters['dst_protocol'])
with tag('address-family', 'xmlns:oc-types="http://openconfig.net/yang/openconfig-types"'):text('oc-types:',parameters['address_family'])
else:
- with tag('table-connections'):
+ with tag('table-connections', 'xmlns:oc-types="http://openconfig.net/yang/openconfig-types"'):
with tag('table-connection'):
with tag('src-protocol','xmlns:oc-pol-types="http://openconfig.net/yang/policy-types"'): text('oc-pol-types:',parameters['src_protocol'])
with tag('dst-protocol','xmlns:oc-pol-types="http://openconfig.net/yang/policy-types"'): text('oc-pol-types:',parameters['dst_protocol'])
diff --git a/src/device/service/drivers/openconfig/templates/interface/edit_config.xml b/src/device/service/drivers/openconfig/templates/interface/edit_config.xml
index 220f062b5da09d26ff6ec271491d6d40cfd46669..372c5bc0ef53a268cbc8bcfd26dfceb03db64ab0 100644
--- a/src/device/service/drivers/openconfig/templates/interface/edit_config.xml
+++ b/src/device/service/drivers/openconfig/templates/interface/edit_config.xml
@@ -6,8 +6,16 @@
{{name}}
ianaift:{{type}}
- {{mtu}}
+ {% if mtu is defined %}{{mtu}}{% endif %}
- {% endif %}
+ {% if auto_negotiate is defined or port_speed is defined %}
+
+
+ {% if auto_negotiate is defined %}{{auto_negotiate}}{% endif %}
+ {% if port_speed is defined %}{{port_speed}}{% endif %}
+
+
+ {% endif %}
+ {% endif %}
diff --git a/src/device/service/drivers/openconfig/templates/interface/subinterface/edit_config.xml b/src/device/service/drivers/openconfig/templates/interface/subinterface/edit_config.xml
index 2d8d3ee07b3a8df20a4b51be755e18b7aec982de..5d485eb07bc6967158b56d3da431237348da2f8f 100644
--- a/src/device/service/drivers/openconfig/templates/interface/subinterface/edit_config.xml
+++ b/src/device/service/drivers/openconfig/templates/interface/subinterface/edit_config.xml
@@ -5,9 +5,17 @@
{{name}}
ianaift:{{type}}
- {% if mtu is defined %}{{mtu}}{% endif%}
+ {% if mtu is defined %}{{mtu}}{% endif %}
true
+ {% if auto_negotiate is defined or port_speed is defined %}
+
+
+ {% if auto_negotiate is defined %}{{auto_negotiate}}{% endif %}
+ {% if port_speed is defined %}{{port_speed}}{% endif %}
+
+
+ {% endif %}
{{index}}
@@ -18,21 +26,32 @@
true
{% endif%}
- {% if vlan_id is defined %}
+ {% if vlan_id is defined or vlan_ids is defined %}
+ {% if vlan_id is defined %}
{{vlan_id}}
+ {% endif %}
+ {% if vlan_ids is defined %}
+
+
+ {% for vlan_id in vlan_ids %}
+ {{vlan_id}}
+ {% endfor %}
+
+
+ {% endif %}
{% endif %}
{% if address_ip is defined %}
- {% if mtu is defined %}{{mtu}}{% endif%}
+ {% if mtu is defined %}{{mtu}}{% endif %}
diff --git a/src/device/service/drivers/openconfig/templates/network_instance/edit_config.xml b/src/device/service/drivers/openconfig/templates/network_instance/edit_config.xml
index 6b6b733dab12a107bf0420907da9c9683173faeb..8f8ab3a5c6ab4e7421b72204d33c0a81de2ebdfe 100644
--- a/src/device/service/drivers/openconfig/templates/network_instance/edit_config.xml
+++ b/src/device/service/drivers/openconfig/templates/network_instance/edit_config.xml
@@ -8,6 +8,7 @@
{% if description is defined %}{{description}}{% endif %}
true
{% if type=='L3VRF' %}
+ oc-types:IPV4
{% if router_id is defined %}{{router_id}}{% endif %}
{{route_distinguisher}}
{% endif %}
diff --git a/src/device/service/drivers/openconfig/templates/network_instance/inter_instance_policies/edit_config.xml b/src/device/service/drivers/openconfig/templates/network_instance/inter_instance_policies/edit_config.xml
index b7c87c7ab13317b5bb2a15c43d241673196bf6d2..fdf6bc4c1aeafea83c80502664e9694f05bef164 100644
--- a/src/device/service/drivers/openconfig/templates/network_instance/inter_instance_policies/edit_config.xml
+++ b/src/device/service/drivers/openconfig/templates/network_instance/inter_instance_policies/edit_config.xml
@@ -3,12 +3,22 @@
{{name}}
+ {% if import_policy is defined or export_policy is defined %}
{% if import_policy is defined %}{{import_policy}}{% endif%}
{% if export_policy is defined %}{{export_policy}}{% endif%}
+ {% endif%}
+ {% if import_route_target is defined or export_route_target is defined %}
+
+
+ {% if import_route_target is defined %}{{import_route_target}}{% endif%}
+ {% if export_route_target is defined %}{{export_route_target}}{% endif%}
+
+
+ {% endif%}
diff --git a/src/device/service/drivers/openconfig/templates/network_instance/interface/edit_config.xml b/src/device/service/drivers/openconfig/templates/network_instance/interface/edit_config.xml
index e926796d039d54e30f6ba13eb5eb66bcec079c08..ab1c183bb9d68c4054df319ccdb4fadbe03911d3 100644
--- a/src/device/service/drivers/openconfig/templates/network_instance/interface/edit_config.xml
+++ b/src/device/service/drivers/openconfig/templates/network_instance/interface/edit_config.xml
@@ -1,10 +1,12 @@
{{name}}
+ {% if False %}
{{name}}
oc-ni-types:{{type}}
+ {% endif %}
{{id}}
diff --git a/src/device/service/drivers/openconfig/templates/network_instance/table_connections/edit_config.xml b/src/device/service/drivers/openconfig/templates/network_instance/table_connections/edit_config.xml
index 35c535c6bd3f78e30fc2177ecc722b1115f54fc5..bd1dac1b326c9d14645d059bafefd73319497593 100644
--- a/src/device/service/drivers/openconfig/templates/network_instance/table_connections/edit_config.xml
+++ b/src/device/service/drivers/openconfig/templates/network_instance/table_connections/edit_config.xml
@@ -11,9 +11,7 @@
oc-pol-types:{{src_protocol}}
oc-pol-types:{{dst_protocol}}
oc-types:{{address_family}}
- {% if False %}
- {{as}}
- {% endif %}
+ {{as}}
{% if default_import_policy is defined %}{{default_import_policy}}{% endif %}
{% endif %}
diff --git a/src/device/tests/gnmi_openconfig/test_unitary_gnmi_oc_arista_l2vpn.py b/src/device/tests/gnmi_openconfig/test_unitary_gnmi_oc_arista_l2vpn.py
index 2374cbad8bf37f1faef9b9648d49c851e17658af..7449377c69d020a0d5404406bc4ee009bf7c7caf 100644
--- a/src/device/tests/gnmi_openconfig/test_unitary_gnmi_oc_arista_l2vpn.py
+++ b/src/device/tests/gnmi_openconfig/test_unitary_gnmi_oc_arista_l2vpn.py
@@ -144,21 +144,21 @@ def test_configure(drivers : Dict[str, OpenConfigDriver]):
#LOGGER.info('results_getconfig = {:s}'.format(str(results_getconfig)))
csgw1_resources_to_set = [
- network_instance('ecoc24', 'L3VRF', '192.168.150.1', '65001:1'),
- network_instance_add_protocol_direct('ecoc24', 'L3VRF'),
- network_instance_add_protocol_static('ecoc24', 'L3VRF'),
- network_instance_add_protocol_bgp('ecoc24', 'L3VRF', '192.168.150.1', '65001', neighbors=[
+ network_instance('ofc25', 'L3VRF', '192.168.150.1', '65001:1'),
+ network_instance_add_protocol_direct('ofc25', 'L3VRF'),
+ network_instance_add_protocol_static('ofc25', 'L3VRF'),
+ network_instance_add_protocol_bgp('ofc25', 'L3VRF', '192.168.150.1', '65001', neighbors=[
('192.168.150.2', '65001')
]),
- network_instance_add_table_connection('ecoc24', 'DIRECTLY_CONNECTED', 'BGP', 'IPV4', 'ACCEPT_ROUTE', bgp_as='65001'),
- network_instance_add_table_connection('ecoc24', 'STATIC', 'BGP', 'IPV4', 'ACCEPT_ROUTE', bgp_as='65001'),
+ network_instance_add_table_connection('ofc25', 'DIRECTLY_CONNECTED', 'BGP', 'IPV4', 'ACCEPT_ROUTE', bgp_as='65001'),
+ network_instance_add_table_connection('ofc25', 'STATIC', 'BGP', 'IPV4', 'ACCEPT_ROUTE', bgp_as='65001'),
interface('ce1', 0, if_type='ethernetCsmacd', mtu=1500),
- network_instance_interface('ecoc24', 'L3VRF', 'ce1', 0),
+ network_instance_interface('ofc25', 'L3VRF', 'ce1', 0),
interface('ce1', 0, if_type='ethernetCsmacd', mtu=1500, ipv4_address_prefix=('192.168.10.1', 24), enabled=True),
interface('xe5', 0, if_type='ethernetCsmacd', mtu=1500),
- network_instance_interface('ecoc24', 'L3VRF', 'xe5', 0),
+ network_instance_interface('ofc25', 'L3VRF', 'xe5', 0),
interface('xe5', 0, if_type='ethernetCsmacd', mtu=1500, ipv4_address_prefix=('192.168.150.1', 24), enabled=True),
]
LOGGER.info('CSGW1 resources_to_set = {:s}'.format(str(csgw1_resources_to_set)))
@@ -166,21 +166,21 @@ def test_configure(drivers : Dict[str, OpenConfigDriver]):
LOGGER.info('CSGW1 results_setconfig = {:s}'.format(str(results_setconfig)))
csgw2_resources_to_set = [
- network_instance('ecoc24', 'L3VRF', '192.168.150.2', '65001:1'),
- network_instance_add_protocol_direct('ecoc24', 'L3VRF'),
- network_instance_add_protocol_static('ecoc24', 'L3VRF'),
- network_instance_add_protocol_bgp('ecoc24', 'L3VRF', '192.168.150.2', '65001', neighbors=[
+ network_instance('ofc25', 'L3VRF', '192.168.150.2', '65001:1'),
+ network_instance_add_protocol_direct('ofc25', 'L3VRF'),
+ network_instance_add_protocol_static('ofc25', 'L3VRF'),
+ network_instance_add_protocol_bgp('ofc25', 'L3VRF', '192.168.150.2', '65001', neighbors=[
('192.168.150.1', '65001')
]),
- network_instance_add_table_connection('ecoc24', 'DIRECTLY_CONNECTED', 'BGP', 'IPV4', 'ACCEPT_ROUTE', bgp_as='65001'),
- network_instance_add_table_connection('ecoc24', 'STATIC', 'BGP', 'IPV4', 'ACCEPT_ROUTE', bgp_as='65001'),
+ network_instance_add_table_connection('ofc25', 'DIRECTLY_CONNECTED', 'BGP', 'IPV4', 'ACCEPT_ROUTE', bgp_as='65001'),
+ network_instance_add_table_connection('ofc25', 'STATIC', 'BGP', 'IPV4', 'ACCEPT_ROUTE', bgp_as='65001'),
interface('ce1', 0, if_type='ethernetCsmacd', mtu=1500),
- network_instance_interface('ecoc24', 'L3VRF', 'ce1', 0),
+ network_instance_interface('ofc25', 'L3VRF', 'ce1', 0),
interface('ce1', 0, if_type='ethernetCsmacd', mtu=1500, ipv4_address_prefix=('192.168.20.1', 24), enabled=True),
interface('xe5', 0, if_type='ethernetCsmacd', mtu=1500),
- network_instance_interface('ecoc24', 'L3VRF', 'xe5', 0),
+ network_instance_interface('ofc25', 'L3VRF', 'xe5', 0),
interface('xe5', 0, if_type='ethernetCsmacd', mtu=1500, ipv4_address_prefix=('192.168.150.2', 24), enabled=True),
]
LOGGER.info('CSGW2 resources_to_set = {:s}'.format(str(csgw2_resources_to_set)))
@@ -188,22 +188,22 @@ def test_configure(drivers : Dict[str, OpenConfigDriver]):
LOGGER.info('CSGW2 results_setconfig = {:s}'.format(str(results_setconfig)))
csgw1_resources_to_delete = [
- network_instance_interface('ecoc24', 'L3VRF', 'ce1', 0),
- network_instance_interface('ecoc24', 'L3VRF', 'xe5', 0),
+ network_instance_interface('ofc25', 'L3VRF', 'ce1', 0),
+ network_instance_interface('ofc25', 'L3VRF', 'xe5', 0),
#interface('ce1', 0),
#interface('xe5', 0),
- network_instance('ecoc24', 'L3VRF'),
+ network_instance('ofc25', 'L3VRF'),
]
LOGGER.info('CSGW1 resources_to_delete = {:s}'.format(str(csgw1_resources_to_delete)))
results_deleteconfig = drivers['CSGW1'].DeleteConfig(csgw1_resources_to_delete)
LOGGER.info('CSGW1 results_deleteconfig = {:s}'.format(str(results_deleteconfig)))
csgw2_resources_to_delete = [
- network_instance_interface('ecoc24', 'L3VRF', 'ce1', 0),
- network_instance_interface('ecoc24', 'L3VRF', 'xe5', 0),
+ network_instance_interface('ofc25', 'L3VRF', 'ce1', 0),
+ network_instance_interface('ofc25', 'L3VRF', 'xe5', 0),
#interface('ce1', 0),
#interface('xe5', 0),
- network_instance('ecoc24', 'L3VRF'),
+ network_instance('ofc25', 'L3VRF'),
]
LOGGER.info('CSGW2 resources_to_delete = {:s}'.format(str(csgw2_resources_to_delete)))
results_deleteconfig = drivers['CSGW2'].DeleteConfig(csgw2_resources_to_delete)
diff --git a/src/device/tests/test_unitary_openconfig_ocnos.py b/src/device/tests/test_unitary_openconfig_ocnos.py
index fa034ff3a65dca4b8ccf59bd9f5202e91d7ce6a1..594d20d54f6837691ef47fed776467dab39c9e77 100644
--- a/src/device/tests/test_unitary_openconfig_ocnos.py
+++ b/src/device/tests/test_unitary_openconfig_ocnos.py
@@ -144,21 +144,21 @@ def test_configure(drivers : Dict[str, OpenConfigDriver]):
#LOGGER.info('results_getconfig = {:s}'.format(str(results_getconfig)))
csgw1_resources_to_set = [
- network_instance('ecoc24', 'L3VRF', '192.168.150.1', '65001:1'),
- network_instance_add_protocol_direct('ecoc24', 'L3VRF'),
- network_instance_add_protocol_static('ecoc24', 'L3VRF'),
- network_instance_add_protocol_bgp('ecoc24', 'L3VRF', '192.168.150.1', '65001', neighbors=[
+ network_instance('ofc25', 'L3VRF', '192.168.150.1', '65001:1'),
+ network_instance_add_protocol_direct('ofc25', 'L3VRF'),
+ network_instance_add_protocol_static('ofc25', 'L3VRF'),
+ network_instance_add_protocol_bgp('ofc25', 'L3VRF', '192.168.150.1', '65001', neighbors=[
('192.168.150.2', '65001')
]),
- network_instance_add_table_connection('ecoc24', 'DIRECTLY_CONNECTED', 'BGP', 'IPV4', 'ACCEPT_ROUTE', bgp_as='65001'),
- network_instance_add_table_connection('ecoc24', 'STATIC', 'BGP', 'IPV4', 'ACCEPT_ROUTE', bgp_as='65001'),
+ network_instance_add_table_connection('ofc25', 'DIRECTLY_CONNECTED', 'BGP', 'IPV4', 'ACCEPT_ROUTE', bgp_as='65001'),
+ network_instance_add_table_connection('ofc25', 'STATIC', 'BGP', 'IPV4', 'ACCEPT_ROUTE', bgp_as='65001'),
interface('ce1', 0, if_type='ethernetCsmacd', mtu=1500),
- network_instance_interface('ecoc24', 'L3VRF', 'ce1', 0),
+ network_instance_interface('ofc25', 'L3VRF', 'ce1', 0),
interface('ce1', 0, if_type='ethernetCsmacd', mtu=1500, ipv4_address_prefix=('192.168.10.1', 24), enabled=True),
interface('xe5', 0, if_type='ethernetCsmacd', mtu=1500),
- network_instance_interface('ecoc24', 'L3VRF', 'xe5', 0),
+ network_instance_interface('ofc25', 'L3VRF', 'xe5', 0),
interface('xe5', 0, if_type='ethernetCsmacd', mtu=1500, ipv4_address_prefix=('192.168.150.1', 24), enabled=True),
]
LOGGER.info('CSGW1 resources_to_set = {:s}'.format(str(csgw1_resources_to_set)))
@@ -166,21 +166,21 @@ def test_configure(drivers : Dict[str, OpenConfigDriver]):
LOGGER.info('CSGW1 results_setconfig = {:s}'.format(str(results_setconfig)))
csgw2_resources_to_set = [
- network_instance('ecoc24', 'L3VRF', '192.168.150.2', '65001:1'),
- network_instance_add_protocol_direct('ecoc24', 'L3VRF'),
- network_instance_add_protocol_static('ecoc24', 'L3VRF'),
- network_instance_add_protocol_bgp('ecoc24', 'L3VRF', '192.168.150.2', '65001', neighbors=[
+ network_instance('ofc25', 'L3VRF', '192.168.150.2', '65001:1'),
+ network_instance_add_protocol_direct('ofc25', 'L3VRF'),
+ network_instance_add_protocol_static('ofc25', 'L3VRF'),
+ network_instance_add_protocol_bgp('ofc25', 'L3VRF', '192.168.150.2', '65001', neighbors=[
('192.168.150.1', '65001')
]),
- network_instance_add_table_connection('ecoc24', 'DIRECTLY_CONNECTED', 'BGP', 'IPV4', 'ACCEPT_ROUTE', bgp_as='65001'),
- network_instance_add_table_connection('ecoc24', 'STATIC', 'BGP', 'IPV4', 'ACCEPT_ROUTE', bgp_as='65001'),
+ network_instance_add_table_connection('ofc25', 'DIRECTLY_CONNECTED', 'BGP', 'IPV4', 'ACCEPT_ROUTE', bgp_as='65001'),
+ network_instance_add_table_connection('ofc25', 'STATIC', 'BGP', 'IPV4', 'ACCEPT_ROUTE', bgp_as='65001'),
interface('ce1', 0, if_type='ethernetCsmacd', mtu=1500),
- network_instance_interface('ecoc24', 'L3VRF', 'ce1', 0),
+ network_instance_interface('ofc25', 'L3VRF', 'ce1', 0),
interface('ce1', 0, if_type='ethernetCsmacd', mtu=1500, ipv4_address_prefix=('192.168.20.1', 24), enabled=True),
interface('xe5', 0, if_type='ethernetCsmacd', mtu=1500),
- network_instance_interface('ecoc24', 'L3VRF', 'xe5', 0),
+ network_instance_interface('ofc25', 'L3VRF', 'xe5', 0),
interface('xe5', 0, if_type='ethernetCsmacd', mtu=1500, ipv4_address_prefix=('192.168.150.2', 24), enabled=True),
]
LOGGER.info('CSGW2 resources_to_set = {:s}'.format(str(csgw2_resources_to_set)))
@@ -188,22 +188,22 @@ def test_configure(drivers : Dict[str, OpenConfigDriver]):
LOGGER.info('CSGW2 results_setconfig = {:s}'.format(str(results_setconfig)))
csgw1_resources_to_delete = [
- network_instance_interface('ecoc24', 'L3VRF', 'ce1', 0),
- network_instance_interface('ecoc24', 'L3VRF', 'xe5', 0),
+ network_instance_interface('ofc25', 'L3VRF', 'ce1', 0),
+ network_instance_interface('ofc25', 'L3VRF', 'xe5', 0),
#interface('ce1', 0),
#interface('xe5', 0),
- network_instance('ecoc24', 'L3VRF'),
+ network_instance('ofc25', 'L3VRF'),
]
LOGGER.info('CSGW1 resources_to_delete = {:s}'.format(str(csgw1_resources_to_delete)))
results_deleteconfig = drivers['CSGW1'].DeleteConfig(csgw1_resources_to_delete)
LOGGER.info('CSGW1 results_deleteconfig = {:s}'.format(str(results_deleteconfig)))
csgw2_resources_to_delete = [
- network_instance_interface('ecoc24', 'L3VRF', 'ce1', 0),
- network_instance_interface('ecoc24', 'L3VRF', 'xe5', 0),
+ network_instance_interface('ofc25', 'L3VRF', 'ce1', 0),
+ network_instance_interface('ofc25', 'L3VRF', 'xe5', 0),
#interface('ce1', 0),
#interface('xe5', 0),
- network_instance('ecoc24', 'L3VRF'),
+ network_instance('ofc25', 'L3VRF'),
]
LOGGER.info('CSGW2 resources_to_delete = {:s}'.format(str(csgw2_resources_to_delete)))
results_deleteconfig = drivers['CSGW2'].DeleteConfig(csgw2_resources_to_delete)
diff --git a/test_csgw/Config.py b/test_csgw/Config.py
new file mode 100644
index 0000000000000000000000000000000000000000..cf9b7699995e7f83b30feaa1fe280c22e83fec74
--- /dev/null
+++ b/test_csgw/Config.py
@@ -0,0 +1,99 @@
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+from .DataStructures import Bgp, Cidr, Ethernet, Interface, NetworkInstance, NetworkInstances, Router, SubInterface
+
+NETWORK_INSTANCES = NetworkInstances()
+
+NETWORK_INSTANCES.instances['vlink-1'] = NetworkInstance(
+ name = 'vlink-1',
+ bgp = Bgp(bgp_as=65000, bgp_number=1, rt_import_number=1, rt_export_number=1),
+ routers = {
+ 'IP1': Router(
+ routing_if = Interface(
+ name='xe1', ethernet=Ethernet(auto_negotiate=True, port_speed='SPEED_UNKNOWN'),
+ index=0, cidr=Cidr(address='1.1.1.1', prefix=30), mtu=1500
+ ),
+ client_if = Interface(
+ name='ce1', ethernet=Ethernet(auto_negotiate=False, port_speed='SPEED_UNKNOWN'),
+ index=101, cidr=Cidr(address='192.168.101.1', prefix=24), mtu=1500, vlan_ids=[101]
+ ),
+ ),
+ 'IP2': Router(
+ routing_if = Interface(
+ name='xe1', ethernet=Ethernet(auto_negotiate=True, port_speed='SPEED_UNKNOWN'),
+ index=0, cidr=Cidr(address='1.1.1.2', prefix=30), mtu=1500
+ ),
+ client_if = Interface(
+ name='ce1', ethernet=Ethernet(auto_negotiate=False, port_speed='SPEED_UNKNOWN'),
+ index=201, cidr=Cidr(address='192.168.201.1', prefix=24), mtu=1500, vlan_ids=[201]
+ ),
+ ),
+ }
+)
+
+NETWORK_INSTANCES.instances['vlink-2'] = NetworkInstance(
+ name = 'vlink-2',
+ bgp = Bgp(bgp_as=65000, bgp_number=2, rt_import_number=2, rt_export_number=2),
+ routers = {
+ 'IP1': Router(
+ routing_if = Interface(
+ name='xe2', ethernet=Ethernet(auto_negotiate=True, port_speed='SPEED_UNKNOWN'),
+ index=0, cidr=Cidr(address='1.1.2.1', prefix=30), mtu=1500
+ ),
+ client_if = Interface(
+ name='ce1', ethernet=Ethernet(auto_negotiate=False, port_speed='SPEED_UNKNOWN'),
+ index=102, cidr=Cidr(address='192.168.102.1', prefix=24), mtu=1500, vlan_ids=[102]
+ ),
+ ),
+ 'IP2': Router(
+ routing_if = Interface(
+ name='xe2', ethernet=Ethernet(auto_negotiate=True, port_speed='SPEED_UNKNOWN'),
+ index=0, cidr=Cidr(address='1.1.2.2', prefix=30), mtu=1500
+ ),
+ client_if = Interface(
+ name='ce1', ethernet=Ethernet(auto_negotiate=False, port_speed='SPEED_UNKNOWN'),
+ index=202, cidr=Cidr(address='192.168.202.1', prefix=24), mtu=1500, vlan_ids=[202]
+ ),
+ ),
+ }
+)
+
+NETWORK_INSTANCES.instances['vlink-3'] = NetworkInstance(
+ name = 'vlink-3',
+ bgp = Bgp(bgp_as=65000, bgp_number=3, rt_import_number=3, rt_export_number=3),
+ routers = {
+ 'IP1': Router(
+ routing_if = Interface(
+ name='xe3', ethernet=Ethernet(auto_negotiate=True, port_speed='SPEED_UNKNOWN'),
+ index=0, cidr=Cidr(address='1.1.3.1', prefix=30), mtu=1500
+ ),
+ client_if = Interface(
+ name='ce1', ethernet=Ethernet(auto_negotiate=False, port_speed='SPEED_UNKNOWN'),
+ index=103, cidr=Cidr(address='192.168.103.1', prefix=24), mtu=1500, vlan_ids=[103]
+ ),
+ ),
+ 'IP2': Router(
+ routing_if = Interface(
+ name='xe3', index=0, ethernet=Ethernet(auto_negotiate=True, port_speed='SPEED_UNKNOWN'),
+ index=0, cidr=Cidr(address='1.1.3.2', prefix=30), mtu=1500
+ ),
+ client_if = Interface(
+ name='ce1', ethernet=Ethernet(auto_negotiate=False, port_speed='SPEED_UNKNOWN'),
+ index=203, cidr=Cidr(address='192.168.203.1', prefix=24), mtu=1500, vlan_ids=[203]
+ ),
+ ),
+ }
+)
diff --git a/test_csgw/DataStructures.py b/test_csgw/DataStructures.py
new file mode 100644
index 0000000000000000000000000000000000000000..51a03ac517f56fe9d078c640940732c1d67af2f2
--- /dev/null
+++ b/test_csgw/DataStructures.py
@@ -0,0 +1,90 @@
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+from collections import defaultdict
+from dataclasses import dataclass, field
+from typing import Dict, List, Tuple
+
+@dataclass
+class Bgp:
+ bgp_as : int = field(default=0)
+ bgp_number : int = field(default=0)
+ rt_import_number : int = field(default=0)
+ rt_export_number : int = field(default=0)
+
+ def get_route_distinguisher(self) -> str:
+ return '{:d}:{:d}'.format(self.bgp_as, self.bgp_number)
+
+ def get_route_target_import(self) -> str:
+ return '{:d}:{:d}'.format(self.bgp_as, self.rt_import_number)
+
+ def get_route_target_export(self) -> str:
+ return '{:d}:{:d}'.format(self.bgp_as, self.rt_export_number)
+
+@dataclass
+class Ethernet:
+ auto_negotiate : bool = field(default=False)
+ port_speed : str = field(default='SPEED_UNKNOWN')
+
+@dataclass
+class Cidr:
+ address : str = field(default='0.0.0.0')
+ prefix : int = field(default=0)
+
+ def as_tuple(self) -> Tuple[str, int]:
+ return (self.address, self.prefix)
+
+@dataclass
+class Interface:
+ name : str = field(default='')
+ index : int = field(default=0)
+ ethernet : Ethernet = field(default_factory=Ethernet)
+ mtu : int = field(default=1500)
+ cidr : Cidr = field(default_factory=Cidr)
+ vlan_ids : List[int] = field(default_factory=list)
+
+@dataclass
+class Router:
+ routing_if : Interface = field(default_factory=Interface)
+ client_if : Interface = field(default_factory=Interface)
+
+@dataclass
+class NetworkInstance:
+ name : str
+ bgp : Bgp = field(default_factory=Bgp)
+ routers : Dict[str, Router] = field(default_factory=lambda: defaultdict(Router))
+
+ def get_router(self, name : str) -> Router:
+ if name not in self.routers:
+ MSG = 'Router({:s}) not found'
+ raise Exception(MSG.format(name))
+ return self.routers[name]
+
+ def get_neighbors_of(self, name : str) -> List[Router]:
+ return [
+ router
+ for router_name, router in self.routers.items()
+ if router_name != name
+ ]
+
+@dataclass
+class NetworkInstances:
+ instances : Dict[str, NetworkInstance] = field(default_factory=lambda: defaultdict(NetworkInstance))
+
+ def get(self, name : str) -> NetworkInstance:
+ if name not in self.instances:
+ MSG = 'NetworkInstance({:s}) not found'
+ raise Exception(MSG.format(name))
+ return self.instances[name]
diff --git a/test_csgw/DoConfiguration.py b/test_csgw/DoConfiguration.py
new file mode 100644
index 0000000000000000000000000000000000000000..a6b77ddaa1a6009b6c935f25a56549968ae5f427
--- /dev/null
+++ b/test_csgw/DoConfiguration.py
@@ -0,0 +1,68 @@
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+import json, os
+from typing import Dict, List
+from common.proto.context_pb2 import ConfigRule
+from common.tools.context_queries.Device import get_device
+from context.client.ContextClient import ContextClient
+from device.client.DeviceClient import DeviceClient
+
+os.environ['DEVICE_EMULATED_ONLY'] = 'YES'
+
+# pylint: disable=wrong-import-position
+from device.service.drivers.openconfig.OpenConfigDriver import OpenConfigDriver
+
+
+DEVICE_DRIVER_PARAMETERS = {
+ 'IP1': {'address': '10.1.1.86', 'port': 830, 'settings': {
+ 'username': 'ocnos', 'password': 'ocnos', 'vendor': None, 'force_running': False,
+ 'hostkey_verify': False, 'look_for_keys': False, 'allow_agent': False,
+ 'commit_per_rule': True, 'device_params': {'name': 'default'}, 'manager_params': {'timeout' : 120},
+ 'message_renderer': 'jinja'
+ }},
+ 'IP2': {'address': '10.1.1.87', 'port': 830, 'settings': {
+ 'username': 'ocnos', 'password': 'ocnos', 'vendor': None, 'force_running': False,
+ 'hostkey_verify': False, 'look_for_keys': False, 'allow_agent': False,
+ 'commit_per_rule': True, 'device_params': {'name': 'default'}, 'manager_params': {'timeout' : 120},
+ 'message_renderer': 'jinja'
+ }},
+}
+
+def configure_device_direct(
+ device_name : str, config_rules : List[ConfigRule], is_delete : bool = False
+) -> None:
+ resources = [
+ (config_rule.custom.resource_key, config_rule.custom.resource_value)
+ for config_rule in config_rules
+ ]
+
+ driver_params = DEVICE_DRIVER_PARAMETERS[device_name]
+ driver = OpenConfigDriver(driver_params['address'], driver_params['port'], **(driver_params['settings']))
+ driver.Connect()
+ method = driver.DeleteConfig if is_delete else driver.SetConfig
+ method(resources)
+ driver.Disconnect()
+
+def configure_device_normal(device_uuid : str, config_rules : List[Dict]) -> None:
+ context_client = ContextClient()
+ device_client = DeviceClient()
+
+ device = get_device(
+ context_client, device_uuid, rw_copy=True, include_endpoints=False,
+ include_config_rules=False, include_components=False
+ )
+ device.device_config.config_rules.extend(config_rules)
+ device_client.ConfigureDevice(device)
diff --git a/test_csgw/RuleComposer.py b/test_csgw/RuleComposer.py
new file mode 100644
index 0000000000000000000000000000000000000000..d9773235f7ea5ff563691a2bb3c35e138ec47838
--- /dev/null
+++ b/test_csgw/RuleComposer.py
@@ -0,0 +1,202 @@
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+import hashlib, json
+from typing import Dict, List, Optional
+from common.proto.context_pb2 import ConfigRule
+from common.tools.object_factory.ConfigRule import json_config_rule_set, json_config_rule_delete
+from .DataStructures import NetworkInstance
+
+
+def compose_config_rule(resource_key, resource_value, delete) -> Dict:
+ json_config_rule = json_config_rule_delete if delete else json_config_rule_set
+ return ConfigRule(**json_config_rule(resource_key, resource_value))
+
+def network_instance(ni_name, ni_type, ni_router_id=None, ni_route_distinguisher=None, delete=False) -> Dict:
+ path = '/network_instance[{:s}]'.format(ni_name)
+ data = {'name': ni_name, 'type': ni_type}
+ if ni_router_id is not None: data['router_id'] = ni_router_id
+ if ni_route_distinguisher is not None: data['route_distinguisher'] = ni_route_distinguisher
+ return compose_config_rule(path, data, delete)
+
+def network_instance_add_protocol_bgp(ni_name, ni_type, ni_router_id, ni_bgp_as, neighbors=[], delete=False)-> Dict:
+ path = '/network_instance[{:s}]/protocols[BGP]'.format(ni_name)
+ data = {
+ 'name': ni_name, 'type': ni_type, 'router_id': ni_router_id, 'identifier': 'BGP',
+ 'protocol_name': ni_bgp_as, 'as': ni_bgp_as
+ }
+ if len(neighbors) > 0:
+ data['neighbors'] = [
+ {'ip_address': neighbor_ip_address, 'remote_as': neighbor_remote_as}
+ for neighbor_ip_address, neighbor_remote_as in neighbors
+ ]
+ return compose_config_rule(path, data, delete)
+
+def network_instance_add_inter_instance_policy(
+ ni_name : str,
+ import_policy : Optional[str] = None, export_policy : Optional[str] = None,
+ import_route_target : Optional[str] = None, export_route_target : Optional[str] = None,
+ delete=False
+)-> Dict:
+ data = dict()
+ if import_policy is not None: data['import_policy' ] = import_policy
+ if export_policy is not None: data['export_policy' ] = export_policy
+ if import_route_target is not None: data['import_route_target'] = import_route_target
+ if export_route_target is not None: data['export_route_target'] = export_route_target
+ str_policy_data = json.dumps(data, sort_keys=True)
+ full_policy_hash = hashlib.sha256(str_policy_data.encode()).digest()
+ policy_hash = full_policy_hash[:8].hex()
+ path = '/network_instance[{:s}]/inter_instance_policies[{:s}]'.format(ni_name, policy_hash)
+ data['name'] = ni_name
+ return compose_config_rule(path, data, delete)
+
+def network_instance_add_protocol_direct(ni_name, ni_type, delete=False) -> Dict:
+ path = '/network_instance[{:s}]/protocols[DIRECTLY_CONNECTED]'.format(ni_name)
+ data = {
+ 'name': ni_name, 'type': ni_type, 'identifier': 'DIRECTLY_CONNECTED',
+ 'protocol_name': 'DIRECTLY_CONNECTED'
+ }
+ return compose_config_rule(path, data, delete)
+
+def network_instance_add_protocol_static(ni_name, ni_type, delete=False) -> Dict:
+ path = '/network_instance[{:s}]/protocols[STATIC]'.format(ni_name)
+ data = {
+ 'name': ni_name, 'type': ni_type, 'identifier': 'STATIC',
+ 'protocol_name': 'STATIC'
+ }
+ return compose_config_rule(path, data, delete)
+
+def network_instance_add_table_connection(
+ ni_name, src_protocol, dst_protocol, address_family, default_import_policy, bgp_as=None, delete=False
+) -> Dict:
+ path = '/network_instance[{:s}]/table_connections[{:s}][{:s}][{:s}]'.format(
+ ni_name, src_protocol, dst_protocol, address_family
+ )
+ data = {
+ 'name': ni_name, 'src_protocol': src_protocol, 'dst_protocol': dst_protocol,
+ 'address_family': address_family, 'default_import_policy': default_import_policy,
+ }
+ if bgp_as is not None: data['as'] = bgp_as
+ return compose_config_rule(path, data, delete)
+
+def interface(
+ name, index, description=None, if_type=None, vlan_id=None, vlan_ids=None, mtu=None, ipv4_address_prefix=None,
+ enabled=None, delete=False
+) -> Dict:
+ path = '/interface[{:s}]/subinterface[{:d}]'.format(name, index)
+ data = {'name': name, 'index': index}
+ if description is not None: data['description'] = description
+ if if_type is not None: data['type' ] = if_type
+ if mtu is not None: data['mtu' ] = mtu
+ if enabled is not None: data['enabled' ] = enabled
+
+ if vlan_id is not None: data['vlan_id'] = vlan_id
+
+ if vlan_ids is not None and len(vlan_ids) > 0:
+ data['vlan_ids'] = vlan_ids
+
+ if ipv4_address_prefix is not None:
+ ipv4_address, ipv4_prefix = ipv4_address_prefix
+ data['address_ip' ] = ipv4_address
+ data['address_prefix'] = ipv4_prefix
+ return compose_config_rule(path, data, delete)
+
+def network_instance_interface(ni_name, ni_type, if_name, if_index, delete=False) -> Dict:
+ path = '/network_instance[{:s}]/interface[{:s}.{:d}]'.format(ni_name, if_name, if_index)
+ data = {'name': ni_name, 'type': ni_type, 'id': if_name, 'interface': if_name, 'subinterface': if_index}
+ return compose_config_rule(path, data, delete)
+
+
+def compose_configure_rules(ni_data : NetworkInstance, router_name : str) -> List[Dict]:
+ ni_bgp = ni_data.bgp
+ ni_router = ni_data.get_router(router_name)
+ ni_neighbors = ni_data.get_neighbors_of(router_name)
+
+ return [
+ # Create network instance with BGP-support
+ network_instance(
+ ni_data.name, 'L3VRF', ni_router.router_id, ni_bgp.get_route_distinguisher()
+ ),
+
+ # Configure routing protocols
+ network_instance_add_protocol_direct(ni_data.name, 'L3VRF'),
+ network_instance_add_protocol_static(ni_data.name, 'L3VRF'),
+ network_instance_add_protocol_bgp(
+ ni_data.name, 'L3VRF', ni_router.router_id, ni_bgp.bgp_as, neighbors=[
+ (neighbor.routing_if.cidr.address, ni_bgp.bgp_as) for neighbor in ni_neighbors
+ ]),
+
+ network_instance_add_inter_instance_policy(
+ ni_data.name,
+ import_route_target=ni_data.bgp.get_route_target_import(),
+ export_route_target=ni_data.bgp.get_route_target_export(),
+ ),
+
+ # Configure routing protocol table exchanges
+ network_instance_add_table_connection(
+ ni_data.name, 'DIRECTLY_CONNECTED', 'BGP', 'IPV4', 'ACCEPT_ROUTE', bgp_as=ni_bgp.bgp_as
+ ),
+ network_instance_add_table_connection(
+ ni_data.name, 'STATIC', 'BGP', 'IPV4', 'ACCEPT_ROUTE', bgp_as=ni_bgp.bgp_as
+ ),
+
+ # Configure routing interface
+ interface(
+ ni_router.routing_if.name, ni_router.routing_if.index, if_type='ethernetCsmacd',
+ mtu=ni_router.routing_if.mtu, vlan_ids=ni_router.routing_if.vlan_ids
+ ),
+ network_instance_interface(
+ ni_data.name, 'L3VRF', ni_router.routing_if.name, ni_router.routing_if.index
+ ),
+ interface(
+ ni_router.routing_if.name, ni_router.routing_if.index, if_type='ethernetCsmacd',
+ mtu=ni_router.routing_if.mtu, vlan_ids=ni_router.routing_if.vlan_ids,
+ ipv4_address_prefix=ni_router.routing_if.cidr.as_tuple(), enabled=True
+ ),
+
+ # Configure client interface
+ interface(
+ ni_router.client_if.name, ni_router.client_if.index, if_type='ethernetCsmacd',
+ mtu=ni_router.client_if.mtu, vlan_ids=ni_router.client_if.vlan_ids
+ ),
+ network_instance_interface(
+ ni_data.name, 'L3VRF', ni_router.client_if.name, ni_router.client_if.index
+ ),
+ interface(
+ ni_router.client_if.name, ni_router.client_if.index, if_type='ethernetCsmacd',
+ mtu=ni_router.client_if.mtu, vlan_ids=ni_router.client_if.vlan_ids,
+ ipv4_address_prefix=ni_router.client_if.cidr.as_tuple(), enabled=True
+ ),
+ ]
+
+def compose_deconfigure_rules(ni_data : NetworkInstance, router_name : str) -> List[Dict]:
+ ni_router = ni_data.get_router(router_name)
+
+ return [
+ # Deconfigure client interface
+ network_instance_interface(
+ ni_data.name, 'L3VRF', ni_router.client_if.name, ni_router.client_if.index, delete=True
+ ),
+ interface(ni_router.client_if.name, ni_router.client_if.index, delete=True),
+
+ # Deconfigure routing interface
+ network_instance_interface(
+ ni_data.name, 'L3VRF', ni_router.routing_if.name, ni_router.routing_if.index, delete=True
+ ),
+ interface(ni_router.routing_if.name, ni_router.routing_if.index, delete=True),
+
+ # Remove network instance
+ network_instance(ni_data.name, 'L3VRF', delete=True),
+ ]
diff --git a/test_csgw/__init__.py b/test_csgw/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..023830645e0fcb60e3f8583674a954810af222f2
--- /dev/null
+++ b/test_csgw/__init__.py
@@ -0,0 +1,13 @@
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
diff --git a/test_csgw/__main__.py b/test_csgw/__main__.py
new file mode 100644
index 0000000000000000000000000000000000000000..ff03280fb6bf6cc54543bac5c2bc4a6ba3b46a34
--- /dev/null
+++ b/test_csgw/__main__.py
@@ -0,0 +1,51 @@
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import logging
+from .Config import NETWORK_INSTANCES
+from .DoConfiguration import configure_device_direct
+from .RuleComposer import compose_configure_rules, compose_deconfigure_rules
+
+logging.basicConfig(level=logging.DEBUG)
+#logging.getLogger('ncclient.operations.rpc').setLevel(logging.INFO)
+#logging.getLogger('ncclient.transport.parser').setLevel(logging.INFO)
+LOGGER = logging.getLogger(__name__)
+
+def configure(router_a : str, router_b : str, ni_name : str) -> None:
+ ni_data = NETWORK_INSTANCES.get(ni_name)
+
+ config_rules_a = compose_configure_rules(ni_data, router_a)
+ config_rules_b = compose_configure_rules(ni_data, router_b)
+
+ configure_device_direct(router_a, config_rules_a, is_delete=False)
+ configure_device_direct(router_b, config_rules_b, is_delete=False)
+
+def deconfigure(router_a : str, router_b : str, ni_name : str) -> None:
+ ni_data = NETWORK_INSTANCES.get(ni_name)
+
+ config_rules_a = compose_deconfigure_rules(ni_data, router_a)
+ config_rules_b = compose_deconfigure_rules(ni_data, router_b)
+
+ configure_device_direct(router_a, config_rules_a, is_delete=True)
+ configure_device_direct(router_b, config_rules_b, is_delete=True)
+
+
+if __name__ == '__main__':
+ configure('IP1', 'IP2', 'vlink-1')
+ #configure('IP1', 'IP2', 'vlink-2')
+ #configure('IP1', 'IP2', 'vlink-3')
+
+ #deconfigure('IP1', 'IP2', 'vlink-1')
+ #deconfigure('IP1', 'IP2', 'vlink-2')
+ #deconfigure('IP1', 'IP2', 'vlink-3')
diff --git a/test_csgw/config/csgws-works.conf b/test_csgw/config/csgws-works.conf
new file mode 100644
index 0000000000000000000000000000000000000000..2d1b728e3c8fb9fbe1d629e684685e63e78d0765
--- /dev/null
+++ b/test_csgw/config/csgws-works.conf
@@ -0,0 +1,69 @@
+# Ref: https://docs.ipinfusion.com/service-provider-6.5/index.html#page/OcNOS_SP/BGP-Config/BGP_Configuration.html
+# Ref: https://docs.ipinfusion.com/service-provider-6.5/index.html#page/OcNOS_SP/VRF-Lite-Config/BGP_configuration.html
+# Ref: https://docs.ipinfusion.com/service-provider-6.5/index.html#page/OcNOS_SP/L3-Subif-Config/subinterface_config.html
+
+# CSGW1
+ip vrf vlink1
+ rd 65000:1
+ route-target import 65000:1
+ route-target export 65000:1
+ exit
+
+interface ce1
+ ip address 192.168.10.1/24
+
+interface ce1.101
+ encapsulation dot1q 101
+ ip vrf forwarding vlink1
+ ip address 192.168.101.1/24
+
+interface xe1
+ transceiver 10gbase-sr
+ speed auto
+ ip vrf forwarding vlink1
+ ip address 2.2.2.1/24
+ exit
+
+router bgp 65000
+ address-family ipv4 vrf vlink1
+ redistribute connected
+ redistribute static
+ neighbor 2.2.2.2 remote-as 65000
+ neighbor 2.2.2.2 activate
+ exit
+ exit
+
+commit
+
+# CSGW2
+ip vrf vlink1
+ rd 65000:1
+ route-target import 65000:1
+ route-target export 65000:1
+ exit
+
+interface ce1
+ ip address 192.168.20.1/24
+
+interface ce1.201
+ encapsulation dot1q 201
+ ip vrf forwarding vlink1
+ ip address 192.168.201.1/24
+
+interface xe1
+ transceiver 10gbase-sr
+ speed auto
+ ip vrf forwarding vlink1
+ ip address 2.2.2.2/24
+ exit
+
+router bgp 65000
+ address-family ipv4 vrf vlink1
+ redistribute connected
+ redistribute static
+ neighbor 2.2.2.1 remote-as 65000
+ neighbor 2.2.2.1 activate
+ exit
+ exit
+
+commit
diff --git a/test_csgw/csgw-configs/manual-config-bgp-custom-vrf-csgw1.conf b/test_csgw/csgw-configs/manual-config-bgp-custom-vrf-csgw1.conf
new file mode 100644
index 0000000000000000000000000000000000000000..d0335a1e340a7d12205ce362a730e7d83e933c04
--- /dev/null
+++ b/test_csgw/csgw-configs/manual-config-bgp-custom-vrf-csgw1.conf
@@ -0,0 +1,20 @@
+ip vrf ecoc24
+ rd 65001:1
+ route-target both 65001:1
+
+interface ce1
+ ip vrf forwarding ecoc24
+ ip address 192.168.10.1/24
+ mtu 1500
+
+interface xe5
+ ip vrf forwarding ecoc24
+ ip address 192.168.150.1/24
+ mtu 1500
+
+router bgp 65001
+ address-family ipv4 vrf ecoc24
+ network 192.168.10.0/24
+ neighbor 192.168.150.2 remote-as 65001
+ neighbor 192.168.150.2 activate
+ exit-address-family
diff --git a/test_csgw/csgw-configs/manual-config-bgp-custom-vrf-csgw2.conf b/test_csgw/csgw-configs/manual-config-bgp-custom-vrf-csgw2.conf
new file mode 100644
index 0000000000000000000000000000000000000000..e8abac09d42698fcb58c922a7e22442502c98b3e
--- /dev/null
+++ b/test_csgw/csgw-configs/manual-config-bgp-custom-vrf-csgw2.conf
@@ -0,0 +1,20 @@
+ip vrf ecoc24
+ rd 65001:1
+ route-target both 65001:1
+
+interface ce1
+ ip vrf forwarding ecoc24
+ ip address 192.168.20.1/24
+ mtu 1500
+
+interface xe5
+ ip vrf forwarding ecoc24
+ ip address 192.168.150.2/24
+ mtu 1500
+
+router bgp 65001
+ address-family ipv4 vrf ecoc24
+ network 192.168.20.0/24
+ neighbor 192.168.150.1 remote-as 65001
+ neighbor 192.168.150.1 activate
+ exit-address-family
diff --git a/test_csgw/csgw-configs/manual-config-bgp-custom-vrf-ecmp-csgw1.conf b/test_csgw/csgw-configs/manual-config-bgp-custom-vrf-ecmp-csgw1.conf
new file mode 100644
index 0000000000000000000000000000000000000000..c062a8dfe5ff3f4077e5494cb41a5050e40e4861
--- /dev/null
+++ b/test_csgw/csgw-configs/manual-config-bgp-custom-vrf-ecmp-csgw1.conf
@@ -0,0 +1,28 @@
+ip vrf ecoc24
+ rd 65001:1
+
+interface ce1
+ ip vrf forwarding ecoc24
+ ip address 192.168.10.1/24
+ mtu 1500
+
+interface xe4
+ ip vrf forwarding ecoc24
+ ip address 192.168.150.1/24
+ mtu 1500
+
+interface xe5
+ ip vrf forwarding ecoc24
+ ip address 192.168.151.1/24
+ mtu 1500
+
+router bgp 65001
+ bgp router-id 10.1.1.86
+ address-family ipv4 vrf ecoc24
+ max-paths ibgp 2
+ network 192.168.10.0/24
+ neighbor 192.168.150.2 remote-as 65001
+ neighbor 192.168.150.2 activate
+ neighbor 192.168.151.2 remote-as 65001
+ neighbor 192.168.151.2 activate
+ exit-address-family
diff --git a/test_csgw/csgw-configs/manual-config-bgp-custom-vrf-ecmp-csgw2.conf b/test_csgw/csgw-configs/manual-config-bgp-custom-vrf-ecmp-csgw2.conf
new file mode 100644
index 0000000000000000000000000000000000000000..05ff62175e30a8242d394306bbcebf545c61edaa
--- /dev/null
+++ b/test_csgw/csgw-configs/manual-config-bgp-custom-vrf-ecmp-csgw2.conf
@@ -0,0 +1,28 @@
+ip vrf ecoc24
+ rd 65001:1
+
+interface ce1
+ ip vrf forwarding ecoc24
+ ip address 192.168.20.1/24
+ mtu 1500
+
+interface xe4
+ ip vrf forwarding ecoc24
+ ip address 192.168.150.2/24
+ mtu 1500
+
+interface xe5
+ ip vrf forwarding ecoc24
+ ip address 192.168.151.2/24
+ mtu 1500
+
+router bgp 65001
+ bgp router-id 10.1.1.87
+ address-family ipv4 vrf ecoc24
+ max-paths ibgp 2
+ network 192.168.20.0/24
+ neighbor 192.168.150.1 remote-as 65001
+ neighbor 192.168.150.1 activate
+ neighbor 192.168.151.1 remote-as 65001
+ neighbor 192.168.151.1 activate
+ exit-address-family
diff --git a/test_csgw/csgw-configs/manual-config-bgp-default-vrf-csgw1.conf b/test_csgw/csgw-configs/manual-config-bgp-default-vrf-csgw1.conf
new file mode 100644
index 0000000000000000000000000000000000000000..596e3e51a02fbc27cd213d6e43a1f3f4fb10b2dc
--- /dev/null
+++ b/test_csgw/csgw-configs/manual-config-bgp-default-vrf-csgw1.conf
@@ -0,0 +1,15 @@
+interface ce1
+ ip address 192.168.10.1/24
+ mtu 1500
+
+interface xe5
+ ip address 192.168.150.1/24
+ mtu 1500
+
+router bgp 65001
+ bgp router-id 192.168.150.1
+ neighbor 192.168.150.2 remote-as 65001
+ address-family ipv4 unicast
+ network 192.168.10.0/24
+ neighbor 192.168.150.2 activate
+ exit-address-family
diff --git a/test_csgw/csgw-configs/manual-config-bgp-default-vrf-csgw2.conf b/test_csgw/csgw-configs/manual-config-bgp-default-vrf-csgw2.conf
new file mode 100644
index 0000000000000000000000000000000000000000..341cfeebc08861953c4b6a9f48f79e33384b1c4e
--- /dev/null
+++ b/test_csgw/csgw-configs/manual-config-bgp-default-vrf-csgw2.conf
@@ -0,0 +1,15 @@
+interface ce1
+ ip address 192.168.20.1/24
+ mtu 1500
+
+interface xe5
+ ip address 192.168.150.2/24
+ mtu 1500
+
+router bgp 65000
+ bgp router-id 192.168.150.2
+ neighbor 192.168.150.1 remote-as 65000
+ address-family ipv4 unicast
+ network 192.168.20.0/24
+ neighbor 192.168.150.1 activate
+ exit-address-family
diff --git a/test_csgw/csgw-configs/manual-config-static-routing-csgw1.conf b/test_csgw/csgw-configs/manual-config-static-routing-csgw1.conf
new file mode 100644
index 0000000000000000000000000000000000000000..6e5f98f0f7398dca154f5b3e772287e2df61aba4
--- /dev/null
+++ b/test_csgw/csgw-configs/manual-config-static-routing-csgw1.conf
@@ -0,0 +1,9 @@
+interface ce1
+ ip address 192.168.10.1/24
+ mtu 1500
+
+interface xe5
+ ip address 192.168.150.1/24
+ mtu 1500
+
+ip route 192.168.20.0/24 192.168.150.2
diff --git a/test_csgw/csgw-configs/manual-config-static-routing-csgw2.conf b/test_csgw/csgw-configs/manual-config-static-routing-csgw2.conf
new file mode 100644
index 0000000000000000000000000000000000000000..a32394cb496a3b69fc9e587ed94a5329d4ca0771
--- /dev/null
+++ b/test_csgw/csgw-configs/manual-config-static-routing-csgw2.conf
@@ -0,0 +1,9 @@
+interface ce1
+ ip address 192.168.20.1/24
+ mtu 1500
+
+interface xe5
+ ip address 192.168.150.2/24
+ mtu 1500
+
+ip route 192.168.10.0/24 192.168.150.1
diff --git a/test_csgw/csgw-configs/tfs-configured-bgp-csgw1.cfg b/test_csgw/csgw-configs/tfs-configured-bgp-csgw1.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..7efd17cb050309f1dfe45ef3600af742f98c64ad
--- /dev/null
+++ b/test_csgw/csgw-configs/tfs-configured-bgp-csgw1.cfg
@@ -0,0 +1,29 @@
+ip vrf ecoc24
+ router-id 192.168.150.1
+ rd 65001:1
+
+mpls label mode all-afs vrf ecoc24 per-vrf
+
+interface ce1
+ ip vrf forwarding ecoc24
+ ip address 192.168.10.1/24
+ mtu 1500
+
+interface lo.ecoc24
+ ip vrf forwarding ecoc24
+ ip address 127.0.0.1/8
+ ipv6 address ::1/128
+
+interface xe5
+ ip vrf forwarding ecoc24
+ ip address 192.168.150.1/24
+ mtu 1500
+
+router bgp 65001
+ bgp router-id 192.168.150.1
+ address-family ipv4 vrf ecoc24
+ redistribute connected
+ redistribute static
+ neighbor 192.168.150.2 remote-as 65001
+ neighbor 192.168.150.2 activate
+ exit-address-family
diff --git a/test_csgw/csgw-configs/tfs-configured-bgp-csgw2.cfg b/test_csgw/csgw-configs/tfs-configured-bgp-csgw2.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..2aaeb1427eec908a83e611bf1eadcdfba6c5275d
--- /dev/null
+++ b/test_csgw/csgw-configs/tfs-configured-bgp-csgw2.cfg
@@ -0,0 +1,29 @@
+ip vrf ecoc24
+ router-id 192.168.150.2
+ rd 65001:1
+
+mpls label mode all-afs vrf ecoc24 per-vrf
+
+interface ce1
+ ip vrf forwarding ecoc24
+ ip address 192.168.20.1/24
+ mtu 1500
+
+interface lo.ecoc24
+ ip vrf forwarding ecoc24
+ ip address 127.0.0.1/8
+ ipv6 address ::1/128
+
+interface xe5
+ ip vrf forwarding ecoc24
+ ip address 192.168.150.2/24
+ mtu 1500
+
+router bgp 65001
+ bgp router-id 192.168.150.2
+ address-family ipv4 vrf ecoc24
+ redistribute connected
+ redistribute static
+ neighbor 192.168.150.1 remote-as 65001
+ neighbor 192.168.150.1 activate
+ exit-address-family
diff --git a/test_csgw/csgw-configs/tfs-ip-topology.json b/test_csgw/csgw-configs/tfs-ip-topology.json
new file mode 100644
index 0000000000000000000000000000000000000000..e9d89eaa5b5267b4b04041a6ef62aedbad697663
--- /dev/null
+++ b/test_csgw/csgw-configs/tfs-ip-topology.json
@@ -0,0 +1,34 @@
+{
+ "contexts": [
+ {"context_id": {"context_uuid": {"uuid": "admin"}}}
+ ],
+ "topologies": [
+ {"topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}
+ ],
+ "devices": [
+ {
+ "device_id": {"device_uuid": {"uuid": "CSGW1"}}, "device_type": "packet-router", "device_drivers": ["DEVICEDRIVER_OPENCONFIG"],
+ "device_config": {"config_rules": [
+ {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "10.1.1.86"}},
+ {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "830"}},
+ {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": {
+ "username": "ocnos", "password": "ocnos", "force_running": false, "hostkey_verify": false,
+ "look_for_keys": false, "allow_agent": false, "commit_per_rule": true,
+ "device_params": {"name": "default"}, "manager_params": {"timeout" : 120}
+ }}}
+ ]}
+ },
+ {
+ "device_id": {"device_uuid": {"uuid": "CSGW2"}}, "device_type": "packet-router", "device_drivers": ["DEVICEDRIVER_OPENCONFIG"],
+ "device_config": {"config_rules": [
+ {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "10.1.1.87"}},
+ {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "830"}},
+ {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": {
+ "username": "ocnos", "password": "ocnos", "force_running": false, "hostkey_verify": false,
+ "look_for_keys": false, "allow_agent": false, "commit_per_rule": true,
+ "device_params": {"name": "default"}, "manager_params": {"timeout" : 120}
+ }}}
+ ]}
+ }
+ ]
+}
diff --git a/test_csgw/get_config/get_config.py b/test_csgw/get_config/get_config.py
new file mode 100644
index 0000000000000000000000000000000000000000..ed26938d5b32d690f176863163b32327f61df264
--- /dev/null
+++ b/test_csgw/get_config/get_config.py
@@ -0,0 +1,40 @@
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from typing import Optional
+from ncclient.manager import Manager, connect_ssh
+
+def _filter(str_filter : Optional[str] = None) -> str:
+ return "{:s}".format(str_filter or '')
+
+#str_filter_components = _filter('')
+
+def get_config(host : str, out_file : str, str_filter : Optional[str] = None) -> None:
+ manager : Manager = connect_ssh(
+ host=host, port=830, username='ocnos', password='ocnos',
+ device_params={'name': 'huaweiyang'}, manager_params={'timeout': 120},
+ key_filename=None, hostkey_verify=False, allow_agent=False,
+ look_for_keys=False
+ )
+ data = manager.get_config('running', filter=str_filter, with_defaults=None).data_xml
+ with open(out_file, 'w', encoding='utf-8') as f:
+ f.write(data)
+ manager.close_session()
+
+def main() -> None:
+ get_config('10.1.1.86', 'csgw1_all.xml', str_filter=None)
+ get_config('10.1.1.87', 'csgw2_all.xml', str_filter=None)
+
+if __name__ == '__main__':
+ main()
diff --git a/test_csgw/run.sh b/test_csgw/run.sh
new file mode 100644
index 0000000000000000000000000000000000000000..8cc73b78b9fb8a99309b1c9823256d205404cda8
--- /dev/null
+++ b/test_csgw/run.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+PYTHONPATH=./src
+python -m test_csgw