OSPF Package
1. 개요
1.1. 주요 기능
다중 장비 및 다중 영역 지원: 하나의 서비스 인스턴스를 통해 여러 장비(
endpoint
)에 OSPF를 설정하고, 각 장비 내에 여러 Area(area
)를 구성할 수 있다.필수 파라미터 입력:
process-id
,area-id
등 OSPF 구성의 핵심 요소를 필수로 입력받아 설정 누락으로 인한 오류를 방지한다.사용자 친화적 인터페이스 선택: 인터페이스를
종류(type)
와이름/번호(name)
로 나누어 입력받아 사용자의 편의성을 높이고 입력 실수를 줄인다.Passive 인터페이스 제어: 각 인터페이스별로 OSPF Hello 패킷을 보내지 않는
passive
모드를 간단한true/false
플래그로 제어할 수 있다.
2. NSO 서비스 패키지 상세 설계
2.1. 서비스 데이터 모델 (ospf.yang)
module ospf { yang-version 1.1; namespace "http://example.com/ospf"; prefix ospf; import ietf-inet-types { prefix inet; } import tailf-ncs { prefix ncs; } description "An OSPF configuration service for Cisco IOS-XR devices."; revision 2025-08-01 { description "Made area-id mandatory and reworked interface input to type + name."; } list ospf-service { key name; uses ncs:service-data; ncs:servicepoint "ospf-servicepoint"; leaf name { type string; } list endpoint { key device; leaf device { type leafref { path "/ncs:devices/ncs:device/ncs:name"; } } leaf process-id { type uint16 { range "1..65535"; } mandatory true; } leaf router-id { type inet:ipv4-address; } list area { key "area-id"; leaf area-id { type uint32; mandatory true; description "The OSPF area ID."; } list interface { key "interface-type interface-name"; description "Interfaces to enable OSPF on for this area."; leaf interface-type { type enumeration { enum "GigabitEthernet"; enum "TenGigE"; enum "HundredGigE"; enum "Loopback"; } mandatory true; description "Type of the interface."; } leaf interface-name { type string; mandatory true; description "Name/number of the interface (e.g., '0/0/0/0' or '0')."; } leaf is-passive { type boolean; mandatory true; description "Set this interface to passive mode."; } } } } } }
2.2. 디바이스 설정 템플릿 (XML Templates)
두 개의 템플릿으로 역할을 분리하여 효율성을 높임
ospf-base-template.xml
: OSPF 프로세스와 라우터 ID 등 장비당 한 번만 설정하면 되는 기본 골격을 생성한다.ospf-area-interface-template.xml
: Area와 그 하위의 인터페이스 설정을 반복적으로 생성한다.
ospf-base-template.xml
<config xmlns="http://tail-f.com/ns/config/1.0" xmlns:cisco-ios-xr="http://tail-f.com/ned/cisco-ios-xr"> <devices xmlns="http://tail-f.com/ns/ncs"> <device> <name>{$device}</name> <config> <router xmlns="http://tail-f.com/ned/cisco-ios-xr"> <ospf> <name>{$process_id}</name> <?if {$router_id}?> <router-id>{$router_id}</router-id> <?end?> </ospf> </router> </config> </device> </devices> </config>
ospf-area-interface-template.xml
<config xmlns="http://tail-f.com/ns/config/1.0"> <devices xmlns="http://tail-f.com/ns/ncs"> <device> <name>{$device}</name> <config> <router xmlns="http://tail-f.com/ned/cisco-ios-xr"> <ospf> <name>{$process_id}</name> <area> <id>{$area_id}</id> <interface> <name>{$interface_name}</name> <?if {$is_passive}?> <passive> <mode>enable</mode> </passive> <?end?> </interface> </area> </ospf> </router> </config> </device> </devices> </config>
2.3. 서비스 로직 (main.py)
# -*- mode: python; python-indent: 4 -*- import ncs from ncs.application import Service, Application class ServiceCallbacks(Service): @Service.create def cb_create(self, tctx, root, service, proplist): self.log.info(f"OSPF Service create called for: {service.name}") template = ncs.template.Template(service) for endpoint in service.endpoint: self.log.info(f"Applying OSPF config for device: {endpoint.device}") base_vars = ncs.template.Variables() base_vars.add('device', endpoint.device) base_vars.add('process_id', endpoint.process_id) if endpoint.router_id: base_vars.add('router_id', endpoint.router_id) else: base_vars.add('router_id', '') template.apply('ospf-base-template', base_vars) for area_item in endpoint.area: for interface_item in area_item.interface: full_interface_name = f"{interface_item.interface_type}{interface_item.interface_name}" self.log.info(f"Configuring interface: {full_interface_name} in area {area_item.area_id}") interface_vars = ncs.template.Variables() interface_vars.add('device', endpoint.device) interface_vars.add('process_id', endpoint.process_id) interface_vars.add('area_id', area_item.area_id) interface_vars.add('interface_name', full_interface_name) if interface_item.is_passive: self.log.info(f"Setting interface {full_interface_name} to passive.") interface_vars.add('is_passive', interface_item.is_passive) else: self.log.info(f"Setting interface {full_interface_name} to active.") interface_vars.add('is_passive', '') template.apply('ospf-area-interface-template', interface_vars) class Ospf(Application): def setup(self): self.log.info('OSPF Application RUNNING') self.register_service('ospf-servicepoint', ServiceCallbacks) def teardown(self): self.log.info('OSPF Application FINISHED')
3. 서비스 사용 방법
3.1. 사용 시나리오
두 대의 라우터 R1
과 R2
에 OSPF Process 100, Area 0를 설정하는 예시입니다. 각 라우터의 Loopback0는 passive, 외부 연결 인터페이스는 active로 설정합니다.
사용시 도움사항
- Tab key
- endpoint 명령어 이후 Tab을 누르면 실제 NSO에 등록되어있는 장치들이 보인다.
root@ncs(config)# ospf-service exam root@ncs(config-ospf-service-exam)# endpoint Possible completions: CE01 CE1 CE02 CE2 PE01 PE02 R1 R2 R3 R4 exam sample7 sample8 sample9 sample10
- area 입력 이후 interface와 GigabitEthernet HundredGigE Loopback TenGigE 자동완성
root@ncs(config-area-10)# interface Possible completions: GigabitEthernet HundredGigE Loopback TenGigE root@ncs(config-area-10)# interface GigabitEthernet 0/0/0/6
- endpoint 명령어 이후 Tab을 누르면 실제 NSO에 등록되어있는 장치들이 보인다.
- router id의 경우 필수 입력 사항이 아니다.
- Tab key
R1
설정 목표Process ID: 100, Router ID: 1.1.1.1
Area 0:
Loopback0
(passive),GigabitEthernet0/0/0/0
(active)
R2
설정 목표Process ID: 100, Router ID: 2.2.2.2
Area 0:
Loopback0
(passive),GigabitEthernet0/0/0/0
(active)
3.2. NSO CLI 생성 명령어
root@ncs(config)# ospf-service MAIN-OSPF-CONFIG root@ncs(config-ospf-service-MAIN-OSPF-CONFIG)# endpoint R Possible completions: R1 R2 R3 R4 ! R1 설정 root@ncs(config-ospf-service-MAIN-OSPF-CONFIG)# endpoint R1 Value for 'process-id' (<unsignedShort, 1 .. 65535>): 100 root@ncs(config-endpoint-R1)# area 0 root@ncs(config-area-0)# interface Loopback 0 Value for 'is-passive' [false,true]: true root@ncs(config-interface-Loopback/0)# exit root@ncs(config-area-0)# interface Possible completions: GigabitEthernet HundredGigE Loopback TenGigE root@ncs(config-area-0)# interface GigabitEthernet 0/0/0/0 Value for 'is-passive' [false,true]: false root@ncs(config-interface-GigabitEthernet/0/0/0/0)# exit root@ncs(config-area-0)# exit root@ncs(config-endpoint-R1)# exit ! R2 설정 root@ncs(config-ospf-service-MAIN-OSPF-CONFIG)# endpoint R2 Value for 'process-id' (<unsignedShort, 1 .. 65535>): 100 root@ncs(config-endpoint-R2)# area Possible completions: <area-id:unsignedInt> range root@ncs(config-endpoint-R2)# router-id 2.2.2.2 root@ncs(config-endpoint-R2)# area 0 root@ncs(config-area-0)# interface Loopback 0 Value for 'is-passive' [false,true]: true root@ncs(config-interface-Loopback/0)# exit root@ncs(config-area-0)# interface GigabitEthernet 0/0/0/0 Value for 'is-passive' [false,true]: false root@ncs(config-interface-GigabitEthernet/0/0/0/0)# commit
3.3. 설정 확인 및 적용
! R1 설정 router ospf 0 area 0 interface Loopback0 passive enable ! interface GigabitEthernet0/0/0/0 ! ! ! ! R2 설정 router ospf 0 router-id 2.2.2.2 area 0 interface Loopback0 passive enable ! interface GigabitEthernet0/0/0/0 ! ! !