Skip to content
LinkState
Go back

Translating Between OpenConfig and Native Namespaces

Design Memo: Correlating OpenConfig Paths with Native Vendor Namespaces

Author: Sophia Lin – Cloud & Automation Architect


Introduction

OpenConfig provides vendor‑neutral YANG models for configuration, telemetry, and operational state. Network operating systems (NOS) expose native YANG hierarchies rooted in vendor‑specific namespaces (e.g., Cisco IOS‑XR, Juniper Junos, Nokia SR OS, Arista EOS).

Operators building model‑driven, multi‑vendor automation stacks must correlate OpenConfig paths with native namespaces while preserving:

  1. Identity – the same logical object (interface, VLAN, BGP peer) is recognizable in both views.
  2. Provenance – changes made via OpenConfig can be traced back to the originating request for audit and rollback.
  3. Operator Trust – visibility into the mapping process ensures confidence that automation behaves as expected.

A robust correlation mechanism is therefore essential for scalable, vendor‑agnostic network automation.


Design Considerations

Identity Preservation

Provenance Maintenance

Operator Trust Establishment

Scalability and Performance Implications


Data Modeling

OpenConfig YANG Modeling

OpenConfig modules are written in YANG 1.1. Key patterns:

module openconfig-interfaces {
  namespace "http://openconfig.net/yang/interfaces";
  prefix oc-if;

  list interface {
    key "name";
    leaf name { type string; }
    leaf description { type string; }
    // …
  }
}

Native Vendor Namespace YANG Modeling

Vendor modules follow the same syntax but often diverge in naming and structure:

module Cisco-IOS-XR-ifmgr-cfg {
  namespace "http://cisco.com/ns/yang/Cisco-IOS-XR-ifmgr-cfg";
  prefix ifmgr;

  list interface {
    key "interface-name";
    leaf interface-name { type string; }
    leaf description { type string; }
    // …
  }
}

Mapping OpenConfig Paths to Native Vendor Namespaces

A mapping must resolve:

  1. Path Translation – Convert an OpenConfig XPath (e.g., /interfaces/interface[name='Gig0/0/0/1']/description) to the native equivalent (/ifmgr:interface/interface-name='Gig0/0/0/1'/description).
  2. Leaf‑Level Semantics – Handle differences in data types, units, or enumerations (e.g., OpenConfig oc-if:admin-status uses UP/DOWN; native may use a Boolean enabled/disabled).
  3. Conditional Augmentations – Apply vendor‑specific augments only when the device advertises support (via YANG‑library or CAPABILITIES exchange).

Mappings can be expressed as declarative translation rules (JSON/YAML) consumed at runtime by a correlation engine.


Implementation Approaches

Using Translation Tables

A translation table maps each OpenConfig path pattern to a native path pattern, optionally with leaf‑level transformation functions.

FieldDescription
oc_path_patternOpenConfig XPath with placeholders (e.g., /interfaces/interface[$name]/description)
native_path_patternNative XPath with same placeholders (e.g., /ifmgr:interface[$interface-name]/description)
key_mapMapping of placeholder names to native leaf names (name → interface-name)
value_transformOptional function (e.g., enum_to_bool)
conditionVendor/OS version predicate (e.g., vendor == 'cisco' && version >= '6.5')

Lookup Algorithm – For a given OpenConfig path, iterate over table entries, evaluate pattern match (using a path‑matching library or custom regex), extract placeholders, apply key_map to build the native path, then apply value_transform to leaf values.

Pros – Simple, auditable, low runtime overhead after load.
Cons – Requires manual authoring per vendor/OS version; limited handling of structural divergences (e.g., OpenConfig aggregate vs. native bundle).

Leveraging Intermediate Data Models

Introduce an intermediate canonical model that is a superset of OpenConfig and vendor models. The correlation engine performs two transformations:

  1. OpenConfig → Intermediate (lossless, well‑defined mapping).
  2. Intermediate → Native (vendor‑specific, possibly lossy if the native model lacks certain features).

The intermediate model can be a YANG module that imports OpenConfig and adds vendor‑specific augmentations as optional nodes.

Advantages – Decouples OpenConfig changes from native updates; adding a new vendor only requires defining the intermediate‑to‑native map.
Drawbacks – Increases modeling complexity; the intermediate model may become bloated; runtime must maintain two transformation sets.

Implementing Custom Mapping Logic

When simple path substitution is insufficient (e.g., OpenConfig models a LAG as a list under /interfaces/interface while the native model uses a separate /lag container), embed procedural code in the correlation engine.

class PathMapper:
    def map_oc_to_native(self, oc_path: str, oc_value: Any) -> Tuple[str, Any]:
        ...
    def map_native_to_oc(self, native_path: str, native_value: Any) -> Tuple[str, Any]:
        ...

Implementation – Each vendor supplies a plugin implementing the above methods using libraries such as pyangbind (Python) or yangtools (Java). Plugins can perform:

Pros – Full flexibility to handle any divergence.
Cons – Higher development effort, harder to audit, potential for bugs that erode trust.


Troubleshooting Correlation Issues

Identifying Correlation Errors

SymptomLikely Cause
gNMI Set succeeds but telemetry shows unchanged native stateMapping produced a no‑op native path (incorrect placeholder resolution).
gNMI Get returns data that does not match OpenConfig viewReverse mapping missing or incorrect leaf transformation.
Frequent invalid‑argument errors from deviceValue type/unit mismatch (e.g., sending Mbps as raw integer vs. kbps).
Correlation table lookup latency spikesTable size exceeded memory, causing disk switchover or O(N) scan.

Detection – Enable structured logging at INFO level for each mapping operation, capturing:

Correlate these logs with telemetry streams (gNMI Subscribe or periodic poll) to detect drift.

Debugging Techniques

  1. Replay Mapping in Isolation – Feed the suspect OpenConfig path into a unit‑test harness that invokes the mapper and prints the intermediate native path.
  2. YANG Validation – Use pyang or yanglint to validate the generated native path against the vendor YANG module; catches structural errors early.
  3. Device‑Side Debug – Enable verbose NETCONF/gNMI server logs on the device (if available) to see the exact XPath it received.
  4. Diff‑Based Validation – Periodically compute the diff between the OpenConfig‑derived intended state (via mapper) and the actual native state (via gNMI Get); any non‑zero diff flags a correlation problem.
  5. Feature Flags – Toggle between translation‑table mode and custom‑mapper mode at runtime to isolate whether the issue lies in static rules or procedural code.

Common Pitfalls and Solutions

PitfallDescriptionMitigation
Placeholder CollisionTwo different OpenConfig leafs map to the same native placeholder, causing overwrites.Enforce unique placeholder names per mapping entry; validate at load time.
Implicit DefaultsNative model applies a default value when a leaf is omitted; OpenConfig expects explicit setting.Always include leafs with explicit values in mapper output, even if the value equals the default.
Version DriftA mapping written for OS version X fails on version Y due to YANG module changes.Tag each mapping entry with a version range; load dynamically based on device‑reported YANG‑library.
Lossy AugmentsOpenConfig augment adds a leaf not present in native model; dropping it silently leads to configuration drift.Treat missing native leaf as a hard error; either reject the operation or raise an alert for manual review.
Caching StalenessCached mapping becomes outdated after a vendor YANG upgrade.Bind cache TTL to the device’s YANG‑library version; invalidate on version change.

Code Example

Using Python and pyangbind for OpenConfig‑Native Correlation

Assumptions

# mapper.py
import json
import re
from pathlib import Path
from typing import Any, Tuple, Dict

class PathMapper:
    def __init__(self, table_path: Path):
        self.table = json.loads(table_path.read_text())
        # Pre‑compile regex patterns for speed
        for entry in self.table:
            entry["oc_regex"] = self._path_to_regex(entry["oc_path_pattern"])
            entry["native_regex"] = self._path_to_regex(entry["native_path_pattern"])

    @staticmethod
    def _path_to_regex(pattern: str) -> str:
        """
        Convert /interfaces/interface[$name]/description
        -> ^/interfaces/interface/(?P<name>[^/]+)/description$
        """
        return re.sub(
            r'\[\$([A-Za-z0-9_]+)\]',
            r'(?P<\1>[^/]+)',
            f'^{pattern}$'
        )

    def map_oc_to_native(self, oc_path: str, oc_value: Any) -> Tuple[str, Any]:
        for entry in self.table:
            match = re.match(entry["oc_regex"], oc_path)
            if not match:
                continue
            # Extract placeholders
            placeholders = match.groupdict()
            # Apply key map to get native leaf names
            native_path = entry["native_path_pattern"]
            for ph, val in placeholders.items():
                native_leaf = entry["key_map"].get(ph, ph)
                native_path = native_path.replace(f'[{ph}]', val)
            # Apply value transformation if any
            if entry.get("value_transform"):
                oc_value = entry["value_transform"](oc_value)
            return native_path, oc_value
        raise ValueError(f"No mapping found for OpenConfig path: {oc_path}")

    # Reverse mapping omitted for brevity

Usage

if __name__ == "__main__":
    mapper = PathMapper(Path("translation_table.json"))
    native_path, value = mapper.map_oc_to_native(
        "/interfaces/interface[name='Gig0/0/0/1']/description",
        "Uplink to core"
    )
    print(f"Native path: {native_path}, value: {value}")

End of memo.


Share this post on:

Previous Post
Map RTBH containment failures before they become route leaks
Next Post
Migrating from kube dns to CoreDNS without brownouts