Compare versions of Cisco IOS software

This JavaScript library can compare the train, throttle, and rebuild numbers of Cisco IOS and IOS XE versions to determine if one version is newer than another.

If an IOS XE version number starting with '3' is given it will convert that to the underlying IOS version before doing the comparison. (e.g. it knows that 3.3.3SE equals 15.1(2)SE3)

It does not compare feature sets (e.g. IP Base vs IP Services).

Get the code

JavaScript library to compare Cisco IOS or IOS XE version strings

Example

Enter two Cisco IOS versions to compare them:


e.g. 15.2(1)SY5b

e.g. 15.2(1)SY4

More examples

Additional examples

The code

/**
Licensed under the terms in this file: http://www.dougandadrienne.info/dougs-network-software/versionCompareForCiscoIos/versionCompareForCiscoIos.js
*/        

/**
According to this link there is a train, a throttle, and a rebuild.
https://www.cisco.com/c/en/us/support/docs/ios-nx-os-software/ios-software-release-1513t/200095-Understanding-Cisco-IOS-Naming-Conventio.html
These are the constants for the array containing all the parts.
@constant
*/
var ML = 0,
    TRAIN = 1,
    THROTTLE = 2,
    REBUILD = 3,
    TRAIN_PART1 = 0,
    TRAIN_PART2 = 1;
/**
IOS XE versions map to these IOS versions according to this table:
https://www.cisco.com/c/en/us/td/docs/routers/asr1000/release/notes/asr1k_rn_rel_notes/asr1k_rn_intro.html
@constant
@default
*/
var xeMapping = [
    '3.1.:15.0(1)',
    '3.2.:15.1(1)',
    '3.3.:15.1(2)',
    '3.4.:15.1(3)',
    '3.5.:15.2(1)',
    '3.6.:15.2(2)',
    '3.7.:15.2(4)',
    '3.8.:15.3(1)',
    '3.9.:15.3(2)',
    '3.10.:15.3(3)',
    '3.11.:15.4(1)',
    '3.12.:15.4(2)',
    '3.13.:15.4(3)',
    '3.14.:15.5(1)',
    '3.15.:15.5(2)',
    '3.16.:15.5(3)',
    '3.17.:15.6(1)'
];

/**
 * @param {string} v any IOS or IOS XE version string e.g. 15.0(1)M3d or 3.3.3SE
 * @returns {string} the original IOS version, or the IOS equivalent of the IOS XE version 
 *                   e.g. 15.0(1)M3d or 15.1(2)3SE  (don't worry that the SE is in the wrong spot.  It comes out in the wash in extractParts().)
 */
function iosVersionFromIosXeVersion(v) {
    var i, j;
    if (v.charAt(0) === '3') {
        for (i = 0; i < xeMapping.length; i++) {
            j = xeMapping[i].split(':');
            v = v.replace(j[0], j[1]);
        }
    }
    return v;
}

/**
 * @param {string} v an IOS version string e.g 15.0(1)M3d
 * @returns {Array} [ maint level (T or S or feature set), train, throttle, rebuild ]:
 */
function extractParts(v) {
    var ml = '',
        rest = '',
        i, num;
    // pull out the maint level/feature set, which is all caps
    for (i = 0; i < v.length; i++) {
        if (v.charCodeAt(i) > 64 && v.charCodeAt(i) < 91) {
            ml += v.charAt(i);
        } else {
            rest += v.charAt(i);
        }
    }
    // convert parens to dots and split into the parts
    // before: 15.0(1)3 after: 15.0.1.3
    rest = rest.replace(')', '.');
    rest = rest.replace('(', '.');
    var parts = rest.split('.');

    if (parts.length === 3) {
        // IOS 16 has fewer components in the version number, so let's fake the throttle digit to '0'
        parts[REBUILD] = parts[THROTTLE];
        parts[THROTTLE] = '0';
    } else if (parts[REBUILD] === '') {
        // some versions are missing a rebuild number, but it's technically rebuild zero.
        // e.g. 15.0(1) = 15.0(1)0, which can be rebuilt into 15.0(1)0a
        parts[REBUILD] = '0';
    }

    // some longer-lived trottles can get into double digits
    num = parseInt(parts[THROTTLE], 10);
    if (num < 10) {
        parts[THROTTLE] = '0' + parts[THROTTLE];
    }

    // some longer-lived rebuilds can get into double digits
    num = parseInt(parts[REBUILD], 10);
    if (num < 10) {
        parts[REBUILD] = '0' + parts[REBUILD];
    }

    // [ maint level (T or S or feature set), train, throttle, rebuild ]:
    return [ml, parts[TRAIN_PART1] + '.' + parts[TRAIN_PART2], parts[THROTTLE], parts[REBUILD]];
}

/**
 * @param {Array} v1 an array containing the parts of an IOS version
 * @param {Array} v2 an array containing the parts of an IOS version
 * @returns {number|null} null if they can't be compared (different maint level, train or throttle),
 *    0 if equal
 *    1 if v1's rebuild is greater than v2's rebuild
 *    -1 if v1's rebuild is less than v2's rebuild
 */
function compareIosParts(v1, v2) {
    if (v1.length !== v2.length) {
        // can't compare
        return null;
    }
    if (v1[ML] !== v2[ML]) {
        // can't compare different maint levels
        return null;
    }
    if (v1[TRAIN] !== v2[TRAIN]) {
        // can't compare different trains
        return null;
    }
    if (v1[THROTTLE] !== v2[THROTTLE]) {
        // can't compare throttle levels
        return null;
    }
    if (v1[REBUILD] < v2[REBUILD]) {
        return -1;
    } else if (v1[REBUILD] > v2[REBUILD]) {
        return 1;
    } else {
        return 0;
    }
}


/**
 * @export
 * @param {string} v1 an IOS/IOS XE version string
 * @param {string} v2 an IOS/IOS XE version string
 * @returns {number|null} null if they can't be compared (different maint level, train or throttle),
 *    0 if equal
 *    1 if v1's rebuild is greater than v2's rebuild
 *    -1 if v1's rebuild is less than v2's rebuild
 */
function compareIos(v1, v2) {
    return compareIosParts(extractParts(iosVersionFromIosXeVersion(v1)), extractParts(iosVersionFromIosXeVersion(v2)));
}