Improve interface ordering #5

Closed
opened 2025-12-29 15:28:22 +01:00 by adam · 7 comments
Owner

Originally created by @jeremystretch on GitHub (May 23, 2016).

We need to come up with a better way of sorting arbitrary interface IDs. The current approach works well for simple cases (e.g. formats Gi0/1 and xe-0/0/1) but falls apart when faced with more exotic IDs, such as Junos' channelized interfaces (e.g. xe-0/0/33:[0-3]).

Originally created by @jeremystretch on GitHub (May 23, 2016). We need to come up with a better way of sorting arbitrary interface IDs. The current approach works well for simple cases (e.g. formats Gi0/1 and xe-0/0/1) but falls apart when faced with more exotic IDs, such as Junos' channelized interfaces (e.g. xe-0/0/33:[0-3]).
adam closed this issue 2025-12-29 15:28:22 +01:00
Author
Owner

@topside844 commented on GitHub (Jun 28, 2016):

The current sort seems to be a simple alphanumeric sort which will not do a proper numeric sort within the numeric part of the interface name. For example, 'Eth1/11' gets listed before 'Eth1/2'. In the past, I've used the python module "natsort" to achieve great results when sorting interface lists like this.

Example:

list = set(['Eth1/1','Eth1/11', 'Eth1/2', 'Eth1/12', 'Eth1/101', 'xe-0/0/33:0', 'xe-0/0/13:2', 'xe-0/0/13:1', 'xe-0/0/13:11', 'xe-0/0/2:1', 'xe-0/0/2:0'])
print '\n'.join(natsort.natsorted(list))

Eth1/1
Eth1/2
Eth1/11
Eth1/12
Eth1/101
xe-0/0/2:0
xe-0/0/2:1
xe-0/0/13:1
xe-0/0/13:2
xe-0/0/13:11
xe-0/0/33:0

@topside844 commented on GitHub (Jun 28, 2016): The current sort seems to be a simple alphanumeric sort which will not do a proper numeric sort within the numeric part of the interface name. For example, 'Eth1/11' gets listed before 'Eth1/2'. In the past, I've used the python module "natsort" to achieve great results when sorting interface lists like this. Example: ``` list = set(['Eth1/1','Eth1/11', 'Eth1/2', 'Eth1/12', 'Eth1/101', 'xe-0/0/33:0', 'xe-0/0/13:2', 'xe-0/0/13:1', 'xe-0/0/13:11', 'xe-0/0/2:1', 'xe-0/0/2:0']) print '\n'.join(natsort.natsorted(list)) ``` > Eth1/1 > Eth1/2 > Eth1/11 > Eth1/12 > Eth1/101 > xe-0/0/2:0 > xe-0/0/2:1 > xe-0/0/13:1 > xe-0/0/13:2 > xe-0/0/13:11 > xe-0/0/33:0
Author
Owner

@topside844 commented on GitHub (Jun 28, 2016):

Also, if you're doing this on the browser side via JS, then you can overload sort using the popular naturalCompare() function

function naturalCompare(a, b) {
    var ax = [], bx = [];

    a.replace(/(\d+)|(\D+)/g, function(_, $1, $2) { ax.push([$1 || Infinity, $2 || ""]) });
    b.replace(/(\d+)|(\D+)/g, function(_, $1, $2) { bx.push([$1 || Infinity, $2 || ""]) });

    while(ax.length && bx.length) {
        var an = ax.shift();
        var bn = bx.shift();
        var nn = (an[0] - bn[0]) || an[1].localeCompare(bn[1]);
        if(nn) return nn;
    }

    return ax.length - bx.length;
}

test = ["Eth1/1","Eth1/11","Eth1/2","Eth1/12","Eth1/101","xe-0/0/33:0","xe-0/0/13:2","xe-0/0/13:1","xe-0/0/13:11","xe-0/0/2:1","xe-0/0/2:0"];
test.sort(naturalCompare);
document.write("<pre>" + JSON.stringify(test,0,3));

[
"Eth1/1",
"Eth1/2",
"Eth1/11",
"Eth1/12",
"Eth1/101",
"xe-0/0/2:0",
"xe-0/0/2:1",
"xe-0/0/13:1",
"xe-0/0/13:2",
"xe-0/0/13:11",
"xe-0/0/33:0"
]

@topside844 commented on GitHub (Jun 28, 2016): Also, if you're doing this on the browser side via JS, then you can overload sort using the popular naturalCompare() function ``` function naturalCompare(a, b) { var ax = [], bx = []; a.replace(/(\d+)|(\D+)/g, function(_, $1, $2) { ax.push([$1 || Infinity, $2 || ""]) }); b.replace(/(\d+)|(\D+)/g, function(_, $1, $2) { bx.push([$1 || Infinity, $2 || ""]) }); while(ax.length && bx.length) { var an = ax.shift(); var bn = bx.shift(); var nn = (an[0] - bn[0]) || an[1].localeCompare(bn[1]); if(nn) return nn; } return ax.length - bx.length; } test = ["Eth1/1","Eth1/11","Eth1/2","Eth1/12","Eth1/101","xe-0/0/33:0","xe-0/0/13:2","xe-0/0/13:1","xe-0/0/13:11","xe-0/0/2:1","xe-0/0/2:0"]; test.sort(naturalCompare); document.write("<pre>" + JSON.stringify(test,0,3)); ``` > [ > "Eth1/1", > "Eth1/2", > "Eth1/11", > "Eth1/12", > "Eth1/101", > "xe-0/0/2:0", > "xe-0/0/2:1", > "xe-0/0/13:1", > "xe-0/0/13:2", > "xe-0/0/13:11", > "xe-0/0/33:0" > ]
Author
Owner

@jeremystretch commented on GitHub (Jun 28, 2016):

This code is responsible for the ordering of interfaces:

return super(InterfaceManager, self).get_queryset().extra(select={
    '_id1': "CAST(SUBSTRING(dcim_interface.name FROM '([0-9]+)\/([0-9]+)\/([0-9]+)$') AS integer)",
    '_id2': "CAST(SUBSTRING(dcim_interface.name FROM '([0-9]+)\/([0-9]+)$') AS integer)",
    '_id3': "CAST(SUBSTRING(dcim_interface.name FROM '([0-9]+)$') AS integer)",
}).order_by('device', '_id1', '_id2', '_id3')

This casts each numerical ID in an interface such as xe-1/2/3 as a separate integer. That's why, for example, ge-0/0/2 is listed before ge-0/0/10. The problem of course is that this approach is extremely rigid, and doesn't work at all outside the x/y/z numbering system.

@jeremystretch commented on GitHub (Jun 28, 2016): This code is responsible for the ordering of interfaces: ``` return super(InterfaceManager, self).get_queryset().extra(select={ '_id1': "CAST(SUBSTRING(dcim_interface.name FROM '([0-9]+)\/([0-9]+)\/([0-9]+)$') AS integer)", '_id2': "CAST(SUBSTRING(dcim_interface.name FROM '([0-9]+)\/([0-9]+)$') AS integer)", '_id3': "CAST(SUBSTRING(dcim_interface.name FROM '([0-9]+)$') AS integer)", }).order_by('device', '_id1', '_id2', '_id3') ``` This casts each numerical ID in an interface such as xe-1/2/3 as a separate integer. That's why, for example, ge-0/0/2 is listed before ge-0/0/10. The problem of course is that this approach is extremely rigid, and doesn't work at all outside the x/y/z numbering system.
Author
Owner

@topside844 commented on GitHub (Jun 28, 2016):

Apparently I was looking at the interface list within the 'device-type' view, which does appear to be a pure alphanumeric sort. I didn't notice the interface list is 'correct' when viewing an individual device directly.

Looks like the ordering just needs to be applied to the device-type view as well.

@topside844 commented on GitHub (Jun 28, 2016): Apparently I was looking at the interface list within the 'device-type' view, which does appear to be a pure alphanumeric sort. I didn't notice the interface list is 'correct' when viewing an individual device directly. Looks like the ordering just needs to be applied to the device-type view as well.
Author
Owner

@jeremystretch commented on GitHub (Jun 29, 2016):

Good point. We can apply the current scheme there for now. I'd still like to figure something out for a more robust long-term solution.

@jeremystretch commented on GitHub (Jun 29, 2016): Good point. We can apply the current scheme there for now. I'd still like to figure something out for a more robust long-term solution.
Author
Owner

@jeremystretch commented on GitHub (Jun 29, 2016):

Alright, in b02c54c I added a fourth ID field for ordering and abstracted the ordering logic so that it could be applied to both Interfaces and InterfaceTemplates. Curious to see how it works for people.

@jeremystretch commented on GitHub (Jun 29, 2016): Alright, in b02c54c I added a fourth ID field for ordering and abstracted the ordering logic so that it could be applied to both Interfaces and InterfaceTemplates. Curious to see how it works for people.
Author
Owner

@jeremystretch commented on GitHub (Jun 29, 2016):

Going to marked this as resolved, but people are welcome to open a new issue if they encounter any further ordering problems (please be sure to provide a specific example when doing so).

@jeremystretch commented on GitHub (Jun 29, 2016): Going to marked this as resolved, but people are welcome to open a new issue if they encounter any further ordering problems (please be sure to provide a specific example when doing so).
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/netbox#5