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 ! ! !