Neo4j中的网络路由

人们使用Neo4j来管理企业架构。如果你还没有看到该演讲由托马斯·劳伦斯来自Amadeus的,那么你应该为自己观看。但是低层网络呢?我们可以使用Neo4j来建模物理网络中的路由吗?当然我们可以,今天我会告诉你如何。Neo4j中的网络路由

我们将保持简单,只需要路由器,交换机,接口和服务器。路由器之间将具有“ROUTE_TO”关系。该关系将路由表包含为String Array。例如:[“10.175.112.0/20”,“10.175.108.0/22”,“10.175.112.0/20”,“10.182.14.64 / 26”...]。路由器与Interfaces之间也有“TRANSLATES_TO”关系(例如VLAN)具有ip和mac地址属性。接口与具有mac和port属性的交换机之间将具有“CONNECTS_TO”关系。最后,交换机还将具有与具有mac和port属性的服务器的“CONNECTS_TO”关系。服务器,如路由器,将具有IP地址属性。也许这张图片将有助于理解这一点:

Neo4j中的网络路由

在本练习中,让我们从一个ip为“10.175.64.2”的路由器开始,看看如何通过ip为“10.175.122.10”来访问服务器。这是我们网络的一部分图片:

Neo4j中的网络路由

我们将创建一个存储过程,通过查找我们的路由器和服务器开始。然后,我们将使用Traversal API创建TraversalDescription,它将深度探索图形,使用NetworkExpander扩展,我们将在下面讨论,并评估它遍历的路径,直到找到服务器节点。假设我们找到一些路径,我们将返回它们作为结果:

    @Procedure(名称 =  “com.maxdemarzi.router” ,模式 =  模式。READ)
    @Description(“CALL com.maxdemarzi.router(from,to) - 遍历路径”)
    public  Stream < PathResult >  router(@Name(“from”)String  from,@ Name(“to”)String  to){
        节点 路由器 =  db。findNode(标签。路由器,“ip”,来自);
        节点 服务器 =  db。findNode(标签。服务器,“ip”,to);
        if(router  !=  null  &&  server  !=  null){
            TraversalDescription  td  =  db。遍历描述()
                    。depthFirst()
                    。expand(新的 NetworkExpander(to))
                    。评估(评估者。endNodeIs(评估。INCLUDE_AND_PRUNE,
                            评价。EXCLUDE_AND_CONTINUE,server));
 
            返回 td。遍历(路由器)。iterator()。stream()。map(PathResult :: new);
        }
        返回 流。of(new  PathResult(null));
    }

棘手的部分是NetworkExpander,所以我们来看看吧。它的构造函数要求我们传入我们想要访问的IP地址,并将它们保存为String和IPAddress。

公共 类 NetworkExpander  实现 PathExpander < 字符串> {
    private  String  ip ;
    私有 IPAddress  ipAddress ;
 
    public  NetworkExpander(String  ip){
        这个。ip  =  ip ;
        这个。ipAddress  =  new  IPAddressString(ip)。getAddress();
    }

在我们的扩展器中,我们将首先通过查看ROUTES_TO关系来尝试第3层路由,并查看String Array routes属性中的任何条目是否包含我们要查找的IP地址,并选择具有较长前缀的IP地址。例如,如果我们遇到3个ROUTES_TO关系,每个关系都有一个路由表条目:

192.168。32.0 / 26  ROUTES_TO  10.1。1.1
192.168。32.0 / 24  ROUTES_TO  10.1。1.2
192.168。32.0 / 19  ROUTES_TO  10.1。1.3

......我们希望得到“192.168.32.1”,我们将所有3个关系添加到我们的无序路由中,但是在订购时,我们首先尝试将关系转到“10.1.1.1”,因为包含“192.168.32.1”在192.168.32.0/26网络(192.168.32.0到192.168.32.63)内,并且具有更长的前缀(26)。

如果我们想要“192.168.32.100”,我们将跳过第一个关系“192.168.32.0/26”,因为x.100不包括在0-63的范围内。其他两个关系是有效的,因为“192.168.32.0/24”包括192.168.32.0到192.168.32.255而“192.168.32.0/19”包括192.168.32.1到192.168.63.254,但我们先尝试“10.1.1.2”因为它有更长的前缀(24)。我来告诉你代码:

    @覆盖
    public  Iterable < Relationship >  expand(Path  path,BranchState  branchState){
        节点 last  =  路径。endNode();
 
        ArrayList < Relationship >  relationships  =  new  ArrayList <>();
        ArrayList < Pair < Integer,Relationship >>  unorderedRoutes  =  new  ArrayList <>();
 
        //第3层最长前缀匹配
        为(关系 routes_to:最后。getRelationships(关系类型。ROUTES_TO,方向。OUTGOING)){
            String [] routes  =(String [])routes_to。getProperty(“routes”,new  String [] {});
            for(String  route:routes){
                IPAddressString  addrString  =  new  IPAddressString(route);
                如果(addrString。的getAddress()。包含(ip地址)){
                    无序路线。添加(对。的(addrString。getNetworkPrefixLength(),routes_to));
                }
            }
        }
        无序路线。排序(比较。comparingInt(p  - >  -  p。第一()));
        无序路线。的forEach(p  - >  关系。添加(p。等()));

现在你可能会问自己,“IPAddressString和IPAddress来自哪里?” 它们来自Sean C. Foley的IPAddress库。如果您想自己动手,这个*帖子可能是一个很好的起点。

一旦我们希望到达应该引导我们到服务器的路由器,我们就转到第2层。在这里,我们遍历TRANSLATES_TO关系,导致我们的IP地址,转换为mac地址,并继续我们的遍历。我们遵循具有相同mac地址的CONNECTS_TO关系,直到我们到达目的地。再一次,这是代码:

        //如果没有第3层下一跳,请转到第2层
        如果(关系。的isEmpty()){
            //第2层
            为(关系 translates_to:最后。getRelationships(关系类型。TRANSLATES_TO,方向。OUTGOING)){
                String  ip  =(String)translates_to。getProperty(“ip”);
                如果(IP。等于(此。IP)){
                    关系。add(translates_to);
                }
            }
            String  mac  =  “” ;
            关系 lastRel  =  路径。lastRelationship();
            if(lastRel  !=  null){
                mac  =(String)lastRel。getProperty(“mac”,“”);
            }
 
            为(关系 connects_to:最后。getRelationships(关系类型。CONNECTS_TO,方向。OUTGOING)){
                串 mac_too  =(字符串)connects_to。getProperty(“mac”,“”);
                如果(MAC。等于(mac_too)){
                    关系。add(connects_to);
                }
            }
        }
        回归 关系 ;

项目存储库中的README文件包含用于构建小型网络的密码脚本。在我们构建网络之后,我们可以尝试我们的存储过程,例如:

CALL  com 。maxdemarzi 。router ('10 .175.64.2' , '10 .175.122.10' )

......这将是我们的结果。

Neo4j中的网络路由

如果您看到的关系多于此,请确保转到Neo4j浏览器“设置”(单击侧面板上的齿轮),完全向下滚动,取消选中“连接结果节点”,然后重新运行存储过程。

Neo4j中的网络路由

与往常一样,代码在GitHub上,所以请随意尝试。此模型中的路由表是一个简单的字符串列表,但在更真实的场景中,每个条目可能是路由器之间的关系,优先级,权重和其他元属性会影响路由顺序,但是概念是一样的。