0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

IOS XE の「一度消さないと変更できない設定」を Atomic Config Replace で一発適用する

0
Posted at

IOS XE の「一度消さないと変更できない設定」を Atomic Config Replace で一発適用する

IOS XE の設定変更では、単純に差分のコンフィグを流し込むだけでは変更できない設定があります。

たとえば、既存の設定を一度削除してから入れ直さないと反映できないものです。

  • policy-map type inspect の途中に class type inspect を追加したい
  • ip slaicmp-echosource-interface を変更したい

こうした設定は、従来の CLI ベースの投入だと手順が複数段階になりがちです。

今回は Atomic Config Replace (ACR) を活用して、IOS XE の部分的な設定差分を安全に適用するサンプルを紹介します。

困っていたこと

たとえば、次のような policy-map があるとします。

policy-map type inspect PM_ZBF_SELF_TO_INTERNET
 class type inspect CM_ZBF_COMMON_ICMP_ERROR
  pass
 class type inspect CM_ZBF_COMMON_DMVPN
  pass
 class type inspect CM_ZBF_SELF_TO_INTERNET_DHCP
  pass
 class type inspect CM_ZBF_COMMON_ALL_L4
  inspect
 class class-default
  drop

既存の class type inspect の間に別の class-map を追加したい場合、設定の並び順や親子関係の都合で、単純な追加コマンドだけでは期待どおりにならないことがあります。

また、今回扱う ip sla でも同じような問題があります。

変更前の設定は次のとおりです。

ip sla 1
 icmp-echo 8.8.8.8 source-interface TenGigabitEthernet0/0/8.2068
ip sla schedule 1 life forever start-time now
ip sla 2
 icmp-echo 8.8.4.4 source-interface TenGigabitEthernet0/0/8.2068
ip sla schedule 2 life forever start-time now

この source-interfaceLoopback1 に変更したい場合、従来は次のような手順が必要でした。

  1. ip sla schedule を無効化する
  2. ip sla の設定を書き換える
  3. ip sla schedule を再度有効化する

つまり、最終的にほしい設定は小さな差分なのに、実際の投入手順は状態依存のオペレーションになります。

Atomic Config Replace でやりたいこと

今回やりたいことは、次の candidate config を IOS XE に渡して、対象範囲だけを置き換えることです。

ip sla 1
 icmp-echo 8.8.8.8 source-interface Loopback1
ip sla schedule 1 life forever start-time now
ip sla 2
 icmp-echo 8.8.4.4 source-interface Loopback1
ip sla schedule 2 life forever start-time now

下記は私お手製のツールで、現在の running config と candidate config を並べて確認し、Selective replace として差分を作成しています。

Screenshot 2026-05-26 at 22.30.20.png

差分としては、以下のように source-interfaceTenGigabitEthernet0/0/8.2068 から Loopback1 に変わります。

 ip sla 1
- icmp-echo 8.8.8.8 source-interface TenGigabitEthernet0/0/8.2068
+ icmp-echo 8.8.8.8 source-interface Loopback1
 ip sla schedule 1 life forever start-time now

 ip sla 2
- icmp-echo 8.8.4.4 source-interface TenGigabitEthernet0/0/8.2068
+ icmp-echo 8.8.4.4 source-interface Loopback1
 ip sla schedule 2 life forever start-time now

適用結果は次のようになりました。

cr1: selective-replace / success / 2047 ms
Configuration applied successfully

変更後の確認

変更後の running config では、ip sla 1ip sla 2 の source interface が Loopback1 になっています。

cr1#show run | section ip sla
track 1 ip sla 1 state
track 2 ip sla 2 state
ip sla 1
 icmp-echo 8.8.8.8 source-interface Loopback1
ip sla schedule 1 life forever start-time now
ip sla 2
 icmp-echo 8.8.4.4 source-interface Loopback1
ip sla schedule 2 life forever start-time now
ip sla 100
 http raw http://ipoe-static.ocn.ad.jp
  http-raw-request
   GET /nic/update?hostname=<redacted> HTTP/1.1\r\nHost: ipoe-static.ocn.ad.jp\r\nAuthorization: Basic <redacted>\r\nConnection: close\r\n\r\n
   exit
  frequency 3600
ip sla schedule 100 life forever start-time now

show ip sla summary でも、ip sla 1ip sla 2 が active で、Return Code が OK になっています。

cr1#show ip sla summary
IPSLAs Latest Operation Summary
Codes: * active, ^ inactive, ~ pending
All Stats are in milliseconds. Stats with u are in microseconds

ID           Type        Destination       Stats       Return      Last
                                                       Code        Run
-----------------------------------------------------------------------
*1           icmp-echo   8.8.8.8           RTT=4       OK          27 seconds ago
*2           icmp-echo   8.8.4.4           RTT=4       OK          27 seconds ago
*100         http        2001:380:0:D::108 RTT=142     OK          58 minutes ago

さらに show ip sla configuration 1 でも、対象アドレスと source interface が 8.8.8.8/Loopback1 になっていることを確認できます。

cr1#show ip sla configuration 1
IP SLAs Infrastructure Engine-III
Entry number: 1
Owner:
Tag:
Operation timeout (milliseconds): 5000
Type of operation to perform: icmp-echo
Target address/Source interface: 8.8.8.8/Loopback1
Type Of Service parameter: 0x0
Request size (ARR data portion): 28
Data pattern: 0xABCDABCD
Verify data: No
Vrf Name:
Do not fragment: No
Schedule:
   Operation frequency (seconds): 60
   Next Scheduled Start Time: Start Time already passed
   Group Scheduled : FALSE
   Randomly Scheduled : FALSE
   Life (seconds): Forever
   Entry Ageout (seconds): never
   Recurring (Starting Everyday): FALSE
   Status of entry (SNMP RowStatus): Active
Threshold (milliseconds): 5000

selective replace の最小サンプル

今回作ったツールでは、内部的には IOS XE の Cisco-IOS-XE-cli-rpc を NETCONF 経由で呼び出しています。

実際の run のコードは公開しない予定なので、ここでは selective replace の要点だけに絞ったサンプルを載せます。

必要な Python ライブラリは ncclient です。

pip install ncclient

candidate config を config-ios-cli-trans RPC の <clis> に入れ、<operation>selective-replace を指定します。

from html import escape

from ncclient import manager
from ncclient.xml_ import to_ele


HOST = "192.0.2.10"
USERNAME = "admin"
PASSWORD = "password"


def config_replace_rpc(config: str, operation: str = "selective-replace"):
    return to_ele(
        '<config-ios-cli-trans xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-cli-rpc">'
        f"<clis>{escape(config, quote=False)}</clis>"
        f"<operation>{operation}</operation>"
        "</config-ios-cli-trans>"
    )


candidate_config = """\
ip sla 1
 icmp-echo 8.8.8.8 source-interface Loopback1
ip sla schedule 1 life forever start-time now
ip sla 2
 icmp-echo 8.8.4.4 source-interface Loopback1
ip sla schedule 2 life forever start-time now
"""


with manager.connect(
    host=HOST,
    port=830,
    username=USERNAME,
    password=PASSWORD,
    hostkey_verify=False,
    allow_agent=False,
    look_for_keys=False,
    device_params={"name": "iosxe"},
) as session:
    reply = session.dispatch(config_replace_rpc(candidate_config))
    print(reply.xml)

ポイントは、candidate config に configure terminalend を含めないことです。

この RPC に渡すのは、IOS XE に投入したい CLI 形式の設定本文だけです。
これも重要なポイントで、NetconfでXMLで渡すことができれば問題はないのですが、現実問題自分が必要とするCLI設定をXMLへの変換を即時におこなうことは難しいのかと思います。
Cisco-IOS-XE-cli-rpcであればCLIで渡すことができるわけです。

現在設定を CLI 形式で取得する

差分確認用には、同じ Cisco-IOS-XE-cli-rpcget-modelled-config-clis を使って running config を CLI 形式で取得できます。

from ncclient import manager
from ncclient.xml_ import to_ele


def get_modelled_config_rpc():
    return to_ele(
        '<get-modelled-config-clis xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-cli-rpc"/>'
    )


with manager.connect(
    host=HOST,
    port=830,
    username=USERNAME,
    password=PASSWORD,
    hostkey_verify=False,
    allow_agent=False,
    look_for_keys=False,
    device_params={"name": "iosxe"},
) as session:
    reply = session.dispatch(get_modelled_config_rpc())
    print(reply.xml)

取得した XML から text を取り出して、candidate config と比較すれば、適用前に差分を確認できます。

selective replace 用の diff

selective replace の場合、candidate config に書いたトップレベルの設定だけを running config から抜き出して比較すると、差分が読みやすくなります。

たとえば candidate config が ip sla 1ip sla 2 だけなら、running config 側も ip sla 1ip sla 2 の section だけに絞ります。

import difflib


def top_level_config_keys(config: str) -> list[str]:
    keys = []
    for line in config.splitlines():
        if not line or line[0].isspace() or line.strip() == "!":
            continue
        keys.append(line.strip())
    return keys


def config_sections(config: str) -> dict[str, list[str]]:
    sections = {}
    current_key = ""
    current_lines = []

    for line in config.splitlines():
        if line.strip() == "!":
            if current_key:
                current_lines.append(line)
            continue

        if line and not line[0].isspace():
            if current_key:
                sections[current_key] = current_lines
            current_key = line.strip()
            current_lines = [line]
            continue

        if current_key:
            current_lines.append(line)

    if current_key:
        sections[current_key] = current_lines

    return sections


def selective_current_config(current: str, candidate: str) -> str:
    sections = config_sections(current)
    lines = []

    for key in top_level_config_keys(candidate):
        if key in sections:
            if lines:
                lines.append("!")
            lines.extend(sections[key])

    return "\n".join(lines)


def build_diff(current: str, candidate: str) -> str:
    current_scope = selective_current_config(current, candidate)
    return "\n".join(
        difflib.unified_diff(
            current_scope.splitlines(),
            candidate.splitlines(),
            fromfile="running:selective-replace",
            tofile="candidate:selective-replace",
            lineterm="",
        )
    )

この処理は実際の replace そのものには必須ではありません。

ただ、operator が見る diff としては、全 running config と candidate config を比較するよりもかなり読みやすくなります。

作ったツールの流れ

今回のツールでは、ざっくり次の流れで selective replace を実行しています。

  1. NetBox から対象デバイスを取得する
  2. NetBox の tag や管理情報をもとに、対象機器と投入対象の config を選ぶ
  3. IOS XE から current config を取得する
  4. candidate config を入力する
  5. current config と candidate config の差分を作る
  6. 差分を確認して APPLY と入力した場合だけ適用する
  7. ACR による selective replace を実行する
  8. 実行結果と所要時間を画面に表示する

画面では以下の操作を用意しています。

  • Fetch current: 対象機器の現在設定を取得する
  • Diff candidate: current config と candidate config の差分を表示する
  • Atomic replace: 確認文字列が一致した場合だけ ACR を実行する

これにより、手作業では複数ステップになる設定変更を、candidate config として宣言的に扱えるようになります。

便利だった点

一番大きいメリットは、設定変更を「手順」ではなく「最終的にこうなってほしい状態」として扱えることです。

ip sla のように、いったん schedule を外してから設定を書き換え、最後に schedule を戻す必要がある設定でも、operator は candidate config だけを見ればよくなります。

また、適用前に current config と candidate config の diff を確認できるため、変更対象が想定どおりかどうかを人間が確認しやすくなります。

注意点

今回使った RPC では、画面にも表示しているとおり、一部の機能はサポート対象外です。

Wireless, app-hosting, telemetry features are not supported through this RPC.

そのため、すべての IOS XE 設定をこの方式で扱えるわけではありません。

また、ACR は強力な仕組みなので、適用前の diff 確認、対象範囲の限定、実行ログの保存は必須だと思います。

まとめ

Atomic Config Replace を使うと、IOS XE の「一度消してからでないと変更しづらい設定」を、candidate config ベースで扱えます。

今回の ip sla の例では、source-interface の変更に伴う複数ステップの作業を、selective replace として一度に適用できました。

この手の自動化ではインベントリをどのように管理維持するのかが一つチャレンジだと考えます。
Catalyst Center, Meraki のようなメーカーNMSをつかうのも一つの選択肢です。オープンなツールであるNetBox と組み合わせて対象デバイスや tag を管理し、current config の取得、diff 生成、確認後の apply までをツール化すると、運用作業としてかなり扱いやすくなるのかなと思います。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?