OSPF Package

1. 개요

1.1. 주요 기능

  • 다중 장비 및 다중 영역 지원: 하나의 서비스 인스턴스를 통해 여러 장비(endpoint)에 OSPF를 설정하고, 각 장비 내에 여러 Area(area)를 구성할 수 있다.

  • 필수 파라미터 입력: process-idarea-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. 사용 시나리오

두 대의 라우터 R1R2에 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 
    • router id의 경우 필수 입력 사항이 아니다.
  • 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
  !
 !        
!