Loading src/device/service/drivers/ietf_l3vpn/IetfL3VpnDriver.py +1 −0 Original line number Diff line number Diff line Loading @@ -191,6 +191,7 @@ class IetfL3VpnDriver(_Driver): if len(resources) == 0: return results with self.__lock: if 'ipowdm' in str(resources): LOGGER.info('Processing IPoWDM resources: {:s}'.format(str(resources))) for resource in resources: if 'ipowdm' in str(resource): try: Loading src/device/service/drivers/ietf_l3vpn/templates/l3vpn.json 0 → 100644 +149 −0 Original line number Diff line number Diff line { "ietf-l3vpn-svc:l3vpn-svc": { "vpn-services": { "vpn-service": [ { "vpn-id": "r2r-l3vpn_v2" } ] }, "sites": { "site": [ { "site-id": "site_R1", "management": { "type": "ietf-l3vpn-svc:provider-managed" }, "locations": { "location": [ { "location-id": "R1" } ] }, "devices": { "device": [ { "device-id": "r1", "location": "R1" } ] }, "site-network-accesses": { "site-network-access": [ { "site-network-access-id": "Ethernet10", "site-network-access-type": "ietf-l3vpn-svc:multipoint", "device-reference": "r1", "vpn-attachment": { "vpn-id": "r2r-l3vpn_v2", "site-role": "ietf-l3vpn-svc:spoke-role" }, "ip-connection": { "ipv4": { "address-allocation-type": "ietf-l3vpn-svc:static-address", "addresses": { "provider-address": "10.0.12.5", "customer-address": "10.0.12.6", "prefix-length": 30 } } }, "service": { "svc-mtu": 1500, "svc-input-bandwidth": 1000000000, "svc-output-bandwidth": 1000000000, "qos": { "qos-profile": { "classes": { "class": [ { "class-id": "qos-realtime", "direction": "ietf-l3vpn-svc:both", "latency": { "latency-boundary": 10 }, "bandwidth": { "guaranteed-bw-percent": 100 } } ] } } } } } ] } }, { "site-id": "site_R2", "management": { "type": "ietf-l3vpn-svc:provider-managed" }, "locations": { "location": [ { "location-id": "R2" } ] }, "devices": { "device": [ { "device-id": "r2", "location": "R2" } ] }, "site-network-accesses": { "site-network-access": [ { "site-network-access-id": "Ethernet10", "site-network-access-type": "ietf-l3vpn-svc:multipoint", "device-reference": "r2", "vpn-attachment": { "vpn-id": "r2r-l3vpn_v2", "site-role": "ietf-l3vpn-svc:hub-role" }, "ip-connection": { "ipv4": { "address-allocation-type": "ietf-l3vpn-svc:static-address", "addresses": { "provider-address": "10.0.12.6", "customer-address": "10.0.12.5", "prefix-length": 30 } } }, "service": { "svc-mtu": 1500, "svc-input-bandwidth": 1000000000, "svc-output-bandwidth": 1000000000, "qos": { "qos-profile": { "classes": { "class": [ { "class-id": "qos-realtime", "direction": "ietf-l3vpn-svc:both", "latency": { "latency-boundary": 10 }, "bandwidth": { "guaranteed-bw-percent": 100 } } ] } } } } } ] } } ] } } } No newline at end of file src/device/service/drivers/ietf_l3vpn/templates/tools.py +85 −245 Original line number Diff line number Diff line Loading @@ -27,213 +27,24 @@ HEADERS = { executor = ThreadPoolExecutor() site_template = { "site-id": "", "devices": { "device": [ { "device-id": "", "location": "" } ] }, "site-network-accesses": { "site-network-access": [ { "site-network-access-id": "", "device-reference": "", "ip-connection": { "ipv4": { "address-allocation-type": "ietf-l3vpn-svc:static-address", "addresses": { "provider-address": "", "customer-address": "", "prefix-length": "" } } }, "vpn-attachment": { "vpn-id": "vpn-p2mp" }, "site-network-access-type": "ietf-l3vpn-svc:multipoint" } ] } } def generate_l3vpn_template_pair( vpn_id, svc_mtu=1500, svc_input_bandwidth=1000000000, svc_output_bandwidth=1000000000, latency_boundary=10, guaranteed_bw_percent=100): template_path = os.path.join(os.path.dirname(__file__), "l3vpn.json") with open(template_path, "r") as f: template = json.load(f) def generate_l3vpn_template_pair(src, dst, vpn_id): template['ietf-l3vpn-svc:l3vpn-svc']['vpn-services']['vpn-service'][0]['vpn-id'] = vpn_id return { "ietf-l3vpn-svc:l3vpn-svc": { "vpn-services": { "vpn-service": [{"vpn-id": vpn_id}] }, "sites": { "site": [ { "site-id": src["uuid"], "management": {"type": "ietf-l3vpn-svc:provider-managed"}, "locations": {"location": [{"location-id": f"location-{src['uuid']}"}]}, "devices": {"device": [{ "device-id": "10.0.30.1", "location": f"location-{src['uuid']}" }]}, "routing-protocols": {"routing-protocol": [{ "type": "ietf-l3vpn-svc:static", "static": { "cascaded-lan-prefixes": { "ipv4-lan-prefixes": [ { "lan": "128.32.10.1/24", "lan-tag": f"vlan{src['vlan_id']}", "next-hop": "10.0.30.10" } ] } } }]}, "site-network-accesses": { "site-network-access": [{ "site-network-access-id": f"{src['vlan_id']}", "site-network-access-type": "ietf-l3vpn-svc:multipoint", "device-reference": "10.0.30.1", "vpn-attachment": { "vpn-id": vpn_id, "site-role": "ietf-l3vpn-svc:spoke-role" }, "ip-connection": { "ipv4": { "address-allocation-type": "ietf-l3vpn-svc:static-address", "addresses": { "provider-address": "10.0.30.254", "customer-address": "10.0.30.10", "prefix-length": 24 } } }, "routing-protocols": {"routing-protocol": [{ "type": "ietf-l3vpn-svc:static", "static": { "cascaded-lan-prefixes": { "ipv4-lan-prefixes": [ { "lan": "172.1.101.1/24", "lan-tag": "vlan100", "next-hop": "10.0.30.254" } ] } } }]}, "service": { "svc-mtu": 1500, "svc-input-bandwidth": 1000000000, "svc-output-bandwidth": 1000000000, "qos": { "qos-profile": { "classes": { "class": [ { "class-id": "qos-realtime", "direction": "ietf-l3vpn-svc:both", "latency": { "latency-boundary": 10 }, "bandwidth": { "guaranteed-bw-percent": 100 } } ] } } } } }] } }, { "site-id": dst["uuid"], "management": {"type": "ietf-l3vpn-svc:provider-managed"}, "locations": {"location": [{"location-id": f"location-{dst['uuid']}"}]}, "devices": {"device": [{ "device-id": "10.0.20.1", "location": f"location-{dst['uuid']}" }]}, "routing-protocols": {"routing-protocol": [{ "type": "ietf-l3vpn-svc:static", "static": { "cascaded-lan-prefixes": { "ipv4-lan-prefixes": [ { "lan": "172.1.101.1/24", "lan-tag": "vlan200", "next-hop": "172.10.33.2" } ] } } }]}, "site-network-accesses": { "site-network-access": [{ "site-network-access-id": f"{dst['vlan_id']}", "site-network-access-type": "ietf-l3vpn-svc:multipoint", "device-reference": "10.0.20.1", "vpn-attachment": { "vpn-id": vpn_id, "site-role": "ietf-l3vpn-svc:hub-role" }, "ip-connection": { "ipv4": { "address-allocation-type": "ietf-l3vpn-svc:static-address", "addresses": { "provider-address": "172.10.33.254", "customer-address": "172.10.33.2", "prefix-length": 24 } } }, "routing-protocols": {"routing-protocol": [{ "type": "ietf-l3vpn-svc:static", "static": { "cascaded-lan-prefixes": { "ipv4-lan-prefixes": [ { "lan": "128.32.10.1/24", "lan-tag": "vlan200", "next-hop": "172.10.33.254" } ] } } }]}, "service": { "svc-mtu": 1500, "svc-input-bandwidth": 1000000000, "svc-output-bandwidth": 1000000000, "qos": { "qos-profile": { "classes": { "class": [ { "class-id": "qos-realtime", "direction": "ietf-l3vpn-svc:both", "latency": { "latency-boundary": 10 }, "bandwidth": { "guaranteed-bw-percent": 100 } } ] } } } } }] } } ] } } } for site in template['ietf-l3vpn-svc:l3vpn-svc']['sites']['site']: for access in site['site-network-accesses']['site-network-access']: access['vpn-attachment']['vpn-id'] = vpn_id access['service']['svc-mtu'] = svc_mtu access['service']['svc-input-bandwidth'] = svc_input_bandwidth access['service']['svc-output-bandwidth'] = svc_output_bandwidth for qos_class in access['service']['qos']['qos-profile']['classes']['class']: qos_class['latency']['latency-boundary'] = latency_boundary qos_class['bandwidth']['guaranteed-bw-percent'] = guaranteed_bw_percent return template def create_request(resource_value): """ Create and send HTTP request based on a JSON template and provided resource value. Loading @@ -256,14 +67,28 @@ def create_request(resource_value): LOGGER.info("Creating request for resource_value: %s", resource_value) node_src = resource_value[1]['rule_set']['src'][0] try: val = resource_value[1] if isinstance(val, str): val = json.loads(val) except Exception as e: LOGGER.error(f"Error parsing resource_value[1] JSON: {e}") return None try: node_src = val['rule_set']['src'][0] src = [{ 'uuid': node_src["uuid"], 'ip_address': node_src["ip_address"], 'ip_mask': node_src["ip_mask"], 'vlan_id': node_src["vlan_id"] }] dst_list = resource_value[1]['rule_set']['dst'] except Exception as e: LOGGER.info(f"Error parsing src: {e}") try: dst_list = val['rule_set']['dst'] dsts = [] for node in dst_list: dsts.append({ Loading @@ -272,39 +97,54 @@ def create_request(resource_value): 'ip_mask': node["ip_mask"], 'vlan_id': node["vlan_id"] }) except Exception as e: LOGGER.info(f"Error parsing dst: {e}") sites_input = src + dsts dests_uuids = [dst['uuid'] for dst in dsts] src_uuid = src[0]['uuid'] vpn_id = src_uuid + "-" + "-".join(dests_uuids) LOGGER.info(f"VPN ID: {vpn_id}") components = resource_value[1]['rule_set']['transceiver']['components'] try: components = val['rule_set']['transceiver']['components'] for i, device in enumerate(components): name = sites_input[i]['uuid'] LOGGER.info(f"NODE TO CONFIGURE: \n{name}: {json.dumps(device, indent=2)}") # try: # response = patch_optical_channel_frequency(device, name) # LOGGER.debug(f"RESPONSE :\n {response}") # except Exception as e: # LOGGER.error(f"Error configuring node: {e}") # return except Exception as e: LOGGER.error(f"Error parsing components: {e}") return if name == "T2.1":device["frequency"]= 195000000 if name == "T1.1":device["frequency"]= 195006250 if name == "T1.2":device["frequency"]= 195018750 if name == "T1.3":device["frequency"]= 195031250 LOGGER.debug(f"NODE TO CONFIGURE: \n{name}: {json.dumps(device, indent=2)}") response = patch_optical_channel_frequency(device, name) LOGGER.debug(f"RESPONSE :\n {response}") templates = [] for dst in dsts: LOGGER.info(f"dst: {dst}") vpn = "L3VPN_"+src[0]['uuid']+"_"+dst['uuid'] templates.append(generate_l3vpn_template_pair(src[0], dst,vpn)) LOGGER.info(f"VPN ID: {vpn}") templates.append(generate_l3vpn_template_pair(vpn_id=vpn_id, svc_mtu="1500", svc_input_bandwidth=1000000000, svc_output_bandwidth=1000000000, latency_boundary=10, guaranteed_bw_percent=100)) LOGGER.info(f"Generated L3VPN P2MP service JSONs:\n{json.dumps(templates, indent=2)}") url = "http://192.168.202.254:80/restconf/data/ietf-l3vpn-svc:l3vpn-svc/vpn-services" headers = { 'accept': 'application/json', 'Content-Type': 'application/json' } for template in templates: LOGGER.info("Generated L3VPN P2MP service JSON:\n%s", json.dumps(template, indent=2)) # url = "http://192.168.202.254:80/restconf/data/ietf-l3vpn-svc:l3vpn-svc/vpn-services" # headers = { # 'accept': 'application/json', # 'Content-Type': 'application/json' # } response = requests.post(url = url, headers= headers, json=template) LOGGER.debug(response) # for template in templates: # LOGGER.info("Generated L3VPN P2MP service JSON:\n%s", json.dumps(template, indent=2)) # response = requests.post(url = url, headers= headers, json=template) # LOGGER.debug(response) return None def patch_optical_channel_frequency(data, DEVICE_ID): encoded_path = f"http://192.168.202.254:80/restconf/data/device={DEVICE_ID}/openconfig-platform:components/component=channel-1/optical-channel/config" Loading src/nbi/service/app.py +1 −1 Original line number Diff line number Diff line Loading @@ -103,6 +103,7 @@ register_ietf_network (nbi_app) register_ietf_nss (nbi_app) register_ietf_sap_topology(nbi_app) register_optical_slice (nbi_app) register_ipowdm (nbi_app) register_osm_api (nbi_app) register_qkd_app (nbi_app) register_restconf_root (nbi_app) Loading @@ -110,7 +111,6 @@ register_telemetry_subscription(nbi_app) register_tfs_api (nbi_app) #register_topology_updates(nbi_app) # does not work; check if eventlet-grpc side effects register_vntm_recommend (nbi_app) register_ipowdm (nbi_app) register_media_channel (nbi_app) register_well_known (nbi_app) LOGGER.info('All connectors registered') Loading src/nbi/service/ipowdm/Resources.py +25 −6 Original line number Diff line number Diff line Loading @@ -36,14 +36,33 @@ class IPoWDMService(Resource): request_data = request.get_json() LOGGER.info("IPoWDM request data: %s", json.dumps(request_data, indent=2)) if 'src' not in request_data or 'dst' not in request_data: return {'status': 'error', 'message': 'Missing required fields: src and dst'}, 400 # Support nested/wrapped payload structure if isinstance(request_data, dict) and 'services' in request_data: services = request_data['services'] if isinstance(services, list) and len(services) > 0: first_item = services[0] if isinstance(first_item, list) and len(first_item) > 0: first_item = first_item[0] if isinstance(first_item, dict): request_data = first_item if isinstance(request_data, dict) and 'rule_set' in request_data: rule_set = request_data['rule_set'] src_endpoints = rule_set.get('src', []) dst_endpoints = rule_set.get('dst', []) bandwidth = rule_set.get('bw', 100) device_id = rule_set.get('uuid', 'TFS-PACKET') if 'endpoint_id' in request_data: device_id = request_data['endpoint_id'].get('device_id', {}).get('device_uuid', {}).get('uuid') or device_id else: src_endpoints = request_data.get('src', []) dst_endpoints = request_data.get('dst', []) bandwidth = request_data.get('bw', 100) device_id = request_data.get('device_id', 'TFS-PACKET') if not src_endpoints or not dst_endpoints: return {'status': 'error', 'message': 'Missing required fields: src and dst'}, 400 LOGGER.info(f"Service UUID: {serviceId}") LOGGER.info(f"Bandwidth: {bandwidth}") LOGGER.info(f"Source endpoints: {len(src_endpoints)}") Loading Loading
src/device/service/drivers/ietf_l3vpn/IetfL3VpnDriver.py +1 −0 Original line number Diff line number Diff line Loading @@ -191,6 +191,7 @@ class IetfL3VpnDriver(_Driver): if len(resources) == 0: return results with self.__lock: if 'ipowdm' in str(resources): LOGGER.info('Processing IPoWDM resources: {:s}'.format(str(resources))) for resource in resources: if 'ipowdm' in str(resource): try: Loading
src/device/service/drivers/ietf_l3vpn/templates/l3vpn.json 0 → 100644 +149 −0 Original line number Diff line number Diff line { "ietf-l3vpn-svc:l3vpn-svc": { "vpn-services": { "vpn-service": [ { "vpn-id": "r2r-l3vpn_v2" } ] }, "sites": { "site": [ { "site-id": "site_R1", "management": { "type": "ietf-l3vpn-svc:provider-managed" }, "locations": { "location": [ { "location-id": "R1" } ] }, "devices": { "device": [ { "device-id": "r1", "location": "R1" } ] }, "site-network-accesses": { "site-network-access": [ { "site-network-access-id": "Ethernet10", "site-network-access-type": "ietf-l3vpn-svc:multipoint", "device-reference": "r1", "vpn-attachment": { "vpn-id": "r2r-l3vpn_v2", "site-role": "ietf-l3vpn-svc:spoke-role" }, "ip-connection": { "ipv4": { "address-allocation-type": "ietf-l3vpn-svc:static-address", "addresses": { "provider-address": "10.0.12.5", "customer-address": "10.0.12.6", "prefix-length": 30 } } }, "service": { "svc-mtu": 1500, "svc-input-bandwidth": 1000000000, "svc-output-bandwidth": 1000000000, "qos": { "qos-profile": { "classes": { "class": [ { "class-id": "qos-realtime", "direction": "ietf-l3vpn-svc:both", "latency": { "latency-boundary": 10 }, "bandwidth": { "guaranteed-bw-percent": 100 } } ] } } } } } ] } }, { "site-id": "site_R2", "management": { "type": "ietf-l3vpn-svc:provider-managed" }, "locations": { "location": [ { "location-id": "R2" } ] }, "devices": { "device": [ { "device-id": "r2", "location": "R2" } ] }, "site-network-accesses": { "site-network-access": [ { "site-network-access-id": "Ethernet10", "site-network-access-type": "ietf-l3vpn-svc:multipoint", "device-reference": "r2", "vpn-attachment": { "vpn-id": "r2r-l3vpn_v2", "site-role": "ietf-l3vpn-svc:hub-role" }, "ip-connection": { "ipv4": { "address-allocation-type": "ietf-l3vpn-svc:static-address", "addresses": { "provider-address": "10.0.12.6", "customer-address": "10.0.12.5", "prefix-length": 30 } } }, "service": { "svc-mtu": 1500, "svc-input-bandwidth": 1000000000, "svc-output-bandwidth": 1000000000, "qos": { "qos-profile": { "classes": { "class": [ { "class-id": "qos-realtime", "direction": "ietf-l3vpn-svc:both", "latency": { "latency-boundary": 10 }, "bandwidth": { "guaranteed-bw-percent": 100 } } ] } } } } } ] } } ] } } } No newline at end of file
src/device/service/drivers/ietf_l3vpn/templates/tools.py +85 −245 Original line number Diff line number Diff line Loading @@ -27,213 +27,24 @@ HEADERS = { executor = ThreadPoolExecutor() site_template = { "site-id": "", "devices": { "device": [ { "device-id": "", "location": "" } ] }, "site-network-accesses": { "site-network-access": [ { "site-network-access-id": "", "device-reference": "", "ip-connection": { "ipv4": { "address-allocation-type": "ietf-l3vpn-svc:static-address", "addresses": { "provider-address": "", "customer-address": "", "prefix-length": "" } } }, "vpn-attachment": { "vpn-id": "vpn-p2mp" }, "site-network-access-type": "ietf-l3vpn-svc:multipoint" } ] } } def generate_l3vpn_template_pair( vpn_id, svc_mtu=1500, svc_input_bandwidth=1000000000, svc_output_bandwidth=1000000000, latency_boundary=10, guaranteed_bw_percent=100): template_path = os.path.join(os.path.dirname(__file__), "l3vpn.json") with open(template_path, "r") as f: template = json.load(f) def generate_l3vpn_template_pair(src, dst, vpn_id): template['ietf-l3vpn-svc:l3vpn-svc']['vpn-services']['vpn-service'][0]['vpn-id'] = vpn_id return { "ietf-l3vpn-svc:l3vpn-svc": { "vpn-services": { "vpn-service": [{"vpn-id": vpn_id}] }, "sites": { "site": [ { "site-id": src["uuid"], "management": {"type": "ietf-l3vpn-svc:provider-managed"}, "locations": {"location": [{"location-id": f"location-{src['uuid']}"}]}, "devices": {"device": [{ "device-id": "10.0.30.1", "location": f"location-{src['uuid']}" }]}, "routing-protocols": {"routing-protocol": [{ "type": "ietf-l3vpn-svc:static", "static": { "cascaded-lan-prefixes": { "ipv4-lan-prefixes": [ { "lan": "128.32.10.1/24", "lan-tag": f"vlan{src['vlan_id']}", "next-hop": "10.0.30.10" } ] } } }]}, "site-network-accesses": { "site-network-access": [{ "site-network-access-id": f"{src['vlan_id']}", "site-network-access-type": "ietf-l3vpn-svc:multipoint", "device-reference": "10.0.30.1", "vpn-attachment": { "vpn-id": vpn_id, "site-role": "ietf-l3vpn-svc:spoke-role" }, "ip-connection": { "ipv4": { "address-allocation-type": "ietf-l3vpn-svc:static-address", "addresses": { "provider-address": "10.0.30.254", "customer-address": "10.0.30.10", "prefix-length": 24 } } }, "routing-protocols": {"routing-protocol": [{ "type": "ietf-l3vpn-svc:static", "static": { "cascaded-lan-prefixes": { "ipv4-lan-prefixes": [ { "lan": "172.1.101.1/24", "lan-tag": "vlan100", "next-hop": "10.0.30.254" } ] } } }]}, "service": { "svc-mtu": 1500, "svc-input-bandwidth": 1000000000, "svc-output-bandwidth": 1000000000, "qos": { "qos-profile": { "classes": { "class": [ { "class-id": "qos-realtime", "direction": "ietf-l3vpn-svc:both", "latency": { "latency-boundary": 10 }, "bandwidth": { "guaranteed-bw-percent": 100 } } ] } } } } }] } }, { "site-id": dst["uuid"], "management": {"type": "ietf-l3vpn-svc:provider-managed"}, "locations": {"location": [{"location-id": f"location-{dst['uuid']}"}]}, "devices": {"device": [{ "device-id": "10.0.20.1", "location": f"location-{dst['uuid']}" }]}, "routing-protocols": {"routing-protocol": [{ "type": "ietf-l3vpn-svc:static", "static": { "cascaded-lan-prefixes": { "ipv4-lan-prefixes": [ { "lan": "172.1.101.1/24", "lan-tag": "vlan200", "next-hop": "172.10.33.2" } ] } } }]}, "site-network-accesses": { "site-network-access": [{ "site-network-access-id": f"{dst['vlan_id']}", "site-network-access-type": "ietf-l3vpn-svc:multipoint", "device-reference": "10.0.20.1", "vpn-attachment": { "vpn-id": vpn_id, "site-role": "ietf-l3vpn-svc:hub-role" }, "ip-connection": { "ipv4": { "address-allocation-type": "ietf-l3vpn-svc:static-address", "addresses": { "provider-address": "172.10.33.254", "customer-address": "172.10.33.2", "prefix-length": 24 } } }, "routing-protocols": {"routing-protocol": [{ "type": "ietf-l3vpn-svc:static", "static": { "cascaded-lan-prefixes": { "ipv4-lan-prefixes": [ { "lan": "128.32.10.1/24", "lan-tag": "vlan200", "next-hop": "172.10.33.254" } ] } } }]}, "service": { "svc-mtu": 1500, "svc-input-bandwidth": 1000000000, "svc-output-bandwidth": 1000000000, "qos": { "qos-profile": { "classes": { "class": [ { "class-id": "qos-realtime", "direction": "ietf-l3vpn-svc:both", "latency": { "latency-boundary": 10 }, "bandwidth": { "guaranteed-bw-percent": 100 } } ] } } } } }] } } ] } } } for site in template['ietf-l3vpn-svc:l3vpn-svc']['sites']['site']: for access in site['site-network-accesses']['site-network-access']: access['vpn-attachment']['vpn-id'] = vpn_id access['service']['svc-mtu'] = svc_mtu access['service']['svc-input-bandwidth'] = svc_input_bandwidth access['service']['svc-output-bandwidth'] = svc_output_bandwidth for qos_class in access['service']['qos']['qos-profile']['classes']['class']: qos_class['latency']['latency-boundary'] = latency_boundary qos_class['bandwidth']['guaranteed-bw-percent'] = guaranteed_bw_percent return template def create_request(resource_value): """ Create and send HTTP request based on a JSON template and provided resource value. Loading @@ -256,14 +67,28 @@ def create_request(resource_value): LOGGER.info("Creating request for resource_value: %s", resource_value) node_src = resource_value[1]['rule_set']['src'][0] try: val = resource_value[1] if isinstance(val, str): val = json.loads(val) except Exception as e: LOGGER.error(f"Error parsing resource_value[1] JSON: {e}") return None try: node_src = val['rule_set']['src'][0] src = [{ 'uuid': node_src["uuid"], 'ip_address': node_src["ip_address"], 'ip_mask': node_src["ip_mask"], 'vlan_id': node_src["vlan_id"] }] dst_list = resource_value[1]['rule_set']['dst'] except Exception as e: LOGGER.info(f"Error parsing src: {e}") try: dst_list = val['rule_set']['dst'] dsts = [] for node in dst_list: dsts.append({ Loading @@ -272,39 +97,54 @@ def create_request(resource_value): 'ip_mask': node["ip_mask"], 'vlan_id': node["vlan_id"] }) except Exception as e: LOGGER.info(f"Error parsing dst: {e}") sites_input = src + dsts dests_uuids = [dst['uuid'] for dst in dsts] src_uuid = src[0]['uuid'] vpn_id = src_uuid + "-" + "-".join(dests_uuids) LOGGER.info(f"VPN ID: {vpn_id}") components = resource_value[1]['rule_set']['transceiver']['components'] try: components = val['rule_set']['transceiver']['components'] for i, device in enumerate(components): name = sites_input[i]['uuid'] LOGGER.info(f"NODE TO CONFIGURE: \n{name}: {json.dumps(device, indent=2)}") # try: # response = patch_optical_channel_frequency(device, name) # LOGGER.debug(f"RESPONSE :\n {response}") # except Exception as e: # LOGGER.error(f"Error configuring node: {e}") # return except Exception as e: LOGGER.error(f"Error parsing components: {e}") return if name == "T2.1":device["frequency"]= 195000000 if name == "T1.1":device["frequency"]= 195006250 if name == "T1.2":device["frequency"]= 195018750 if name == "T1.3":device["frequency"]= 195031250 LOGGER.debug(f"NODE TO CONFIGURE: \n{name}: {json.dumps(device, indent=2)}") response = patch_optical_channel_frequency(device, name) LOGGER.debug(f"RESPONSE :\n {response}") templates = [] for dst in dsts: LOGGER.info(f"dst: {dst}") vpn = "L3VPN_"+src[0]['uuid']+"_"+dst['uuid'] templates.append(generate_l3vpn_template_pair(src[0], dst,vpn)) LOGGER.info(f"VPN ID: {vpn}") templates.append(generate_l3vpn_template_pair(vpn_id=vpn_id, svc_mtu="1500", svc_input_bandwidth=1000000000, svc_output_bandwidth=1000000000, latency_boundary=10, guaranteed_bw_percent=100)) LOGGER.info(f"Generated L3VPN P2MP service JSONs:\n{json.dumps(templates, indent=2)}") url = "http://192.168.202.254:80/restconf/data/ietf-l3vpn-svc:l3vpn-svc/vpn-services" headers = { 'accept': 'application/json', 'Content-Type': 'application/json' } for template in templates: LOGGER.info("Generated L3VPN P2MP service JSON:\n%s", json.dumps(template, indent=2)) # url = "http://192.168.202.254:80/restconf/data/ietf-l3vpn-svc:l3vpn-svc/vpn-services" # headers = { # 'accept': 'application/json', # 'Content-Type': 'application/json' # } response = requests.post(url = url, headers= headers, json=template) LOGGER.debug(response) # for template in templates: # LOGGER.info("Generated L3VPN P2MP service JSON:\n%s", json.dumps(template, indent=2)) # response = requests.post(url = url, headers= headers, json=template) # LOGGER.debug(response) return None def patch_optical_channel_frequency(data, DEVICE_ID): encoded_path = f"http://192.168.202.254:80/restconf/data/device={DEVICE_ID}/openconfig-platform:components/component=channel-1/optical-channel/config" Loading
src/nbi/service/app.py +1 −1 Original line number Diff line number Diff line Loading @@ -103,6 +103,7 @@ register_ietf_network (nbi_app) register_ietf_nss (nbi_app) register_ietf_sap_topology(nbi_app) register_optical_slice (nbi_app) register_ipowdm (nbi_app) register_osm_api (nbi_app) register_qkd_app (nbi_app) register_restconf_root (nbi_app) Loading @@ -110,7 +111,6 @@ register_telemetry_subscription(nbi_app) register_tfs_api (nbi_app) #register_topology_updates(nbi_app) # does not work; check if eventlet-grpc side effects register_vntm_recommend (nbi_app) register_ipowdm (nbi_app) register_media_channel (nbi_app) register_well_known (nbi_app) LOGGER.info('All connectors registered') Loading
src/nbi/service/ipowdm/Resources.py +25 −6 Original line number Diff line number Diff line Loading @@ -36,14 +36,33 @@ class IPoWDMService(Resource): request_data = request.get_json() LOGGER.info("IPoWDM request data: %s", json.dumps(request_data, indent=2)) if 'src' not in request_data or 'dst' not in request_data: return {'status': 'error', 'message': 'Missing required fields: src and dst'}, 400 # Support nested/wrapped payload structure if isinstance(request_data, dict) and 'services' in request_data: services = request_data['services'] if isinstance(services, list) and len(services) > 0: first_item = services[0] if isinstance(first_item, list) and len(first_item) > 0: first_item = first_item[0] if isinstance(first_item, dict): request_data = first_item if isinstance(request_data, dict) and 'rule_set' in request_data: rule_set = request_data['rule_set'] src_endpoints = rule_set.get('src', []) dst_endpoints = rule_set.get('dst', []) bandwidth = rule_set.get('bw', 100) device_id = rule_set.get('uuid', 'TFS-PACKET') if 'endpoint_id' in request_data: device_id = request_data['endpoint_id'].get('device_id', {}).get('device_uuid', {}).get('uuid') or device_id else: src_endpoints = request_data.get('src', []) dst_endpoints = request_data.get('dst', []) bandwidth = request_data.get('bw', 100) device_id = request_data.get('device_id', 'TFS-PACKET') if not src_endpoints or not dst_endpoints: return {'status': 'error', 'message': 'Missing required fields: src and dst'}, 400 LOGGER.info(f"Service UUID: {serviceId}") LOGGER.info(f"Bandwidth: {bandwidth}") LOGGER.info(f"Source endpoints: {len(src_endpoints)}") Loading