Search code examples
network-programmingpowerbiipdaxcidr

PowerBI/DAX calculated column to compute network CIDR from a specifc machine/network ip and mask


I have only the "basic" PBI installed on my company server, so I need to find a solution with DAX or PowerQuery. No Python, No R ... :/

I have two tables with Networks ip and mask, and another one with Machines ip and mask.

I would like to set a relation between the two tables.

My idea is to compute a new column in each table. It will be the network ip and mask in CIDR notation, which I will use as a common key to set up the relation:

Machines --N:1--> Networks

Networks Table
==
netip,        netmask          -> netcidr *
10.10.1.32,   255.255.255.224  -> 10.10.1.32/27


Machines Table
==
machineip,    netmask          -> netcidr *
10.10.1.35,   255.255.255.224  -> 10.10.1.32/27
10.10.1.38,   255.255.255.224  -> 10.10.1.32/27
  • I need to compute the netcidr columns in both case.

I have done it with Python function, but I need to convert this in DAX or PowerQuery or SQL:

def network2(ipmask):
    ip, cidr = ipmask.split('/')
    print(">", ip, cidr)
    a, b, c, d = ip.split('.')
    ipn = (((int(a)*256+int(b))*256)+int(c))*256+int(d)

    cidr = int(cidr)
    mask = (0xffffffff >> (32 - cidr)) << (32 - cidr)
    net = ipn & mask

    print (ipn, cidr, mask, net )
    
    a = net%(256**4)//(256**3)
    b = net%(256**3)//(256**2)
    c = net%(256**2)//(256**1)
    d = net%(256**1)//(256**0)
    
    #net IP decimal
    print(">>>old  - ip: ", ipmask)
    print(">>>nets - ip: ", a, b, c, d, "/", cidr)


    #ip, cidr, mask
    # for i in ip.split('.')

network2('10.10.1.32/27') #mask 255.255.255.224
network2('10.10.1.38/27')


>>>old  - ip:  10.10.1.32/27
>>>nets - ip:  10 10 1 32 / 27
>>>old  - ip:  10.10.1.38/27
>>>nets - ip:  10 10 1 32 / 27

It works in Python and now I try to do it in DAX:

cidr_net = 
// ...
VAR mask = data[mask_lan]
VAR dot1 = FIND(".", mask, 1, 0)
VAR p1   = VALUE(IF(dot1>0, (MID(mask, 1, dot1-1)), "0"))
VAR dot2 = FIND(".", mask, dot1+1, 0)
VAR p2   = VALUE(IF(dot2>0, MID(mask, dot1+1, dot2-1-dot1), "0"))
VAR dot3 = FIND(".", mask, dot2+1, 0)
VAR p3   = VALUE(IF(dot3>0, MID(mask, dot2+1, dot3-1-dot2), "0"))
VAR p4   = VALUE(IF(dot3>0, MID(mask, dot3+1, len(mask)-dot3), "0"))

VAR ip    = data[ip_lan]
VAR d1    = FIND(".", ip, 1, 0)
VAR ip1   = VALUE(IF(d1>0, (MID(ip, 1, d1-1)), "0"))
VAR d2    = FIND(".", ip, d1+1, 0)
VAR ip2   = VALUE(IF(d2>0, MID(ip, d1+1, d2-1-d1), "0"))
VAR d3    = FIND(".", ip, d2+1, 0)
VAR ip3   = VALUE(IF(d3>0, MID(ip, d2+1, d3-1-d2), "0"))
VAR ip4   = VALUE(IF(d3>0, MID(ip, d3+1, len(ip)-d3), "0"))

VAR n1    = p1 && ip1
VAR n2    = p2 && ip2
VAR n3    = p3 && ip3
VAR n4    = p4 && ip4


VAR cidr = FORMAT( 32-log( 4294967296-((((p1*256+p2)*256)+p3)*256+p4), 2), "##")
RETURN CONCATENATE(CONCATENATE(CONCATENATE(CONCATENATE(CONCATENATE(CONCATENATE(CONCATENATE(CONCATENATE(n1, "."), n2), "."), n3), "."), n4), "/"), cidr)

But it does not work:

1/ I cannot find bitwise operators in DAX ... so "VAR n1 = p1 && ip1" does not work as a bitwise and. Is it possible to do the bitwise and another way ?

2/ Is there another way to do this more easily in DAX ?

3/ Otherwise maybee with PowerQuery ?


Solution

  • A DAX solution can be implemented, even if it would be better to move this computation to SQL or Power Query

    I think I fixed the final steps of your code

    [cidr_net] =
            // il faut un biwise and de l ip et du mask pour trouver le cidre du reseau ...
            VAR mask = "255.255.255.224"
            VAR dot1 =
                FIND ( ".", mask, 1, 0 )
            VAR p1 =
                VALUE ( IF ( dot1 > 0, ( MID ( mask, 1, dot1 - 1 ) ), "0" ) )
            VAR dot2 =
                FIND ( ".", mask, dot1 + 1, 0 )
            VAR p2 =
                VALUE ( IF ( dot2 > 0, MID ( mask, dot1 + 1, dot2 - 1 - dot1 ), "0" ) )
            VAR dot3 =
                FIND ( ".", mask, dot2 + 1, 0 )
            VAR p3 =
                VALUE ( IF ( dot3 > 0, MID ( mask, dot2 + 1, dot3 - 1 - dot2 ), "0" ) )
            VAR p4 =
                VALUE ( IF ( dot3 > 0, MID ( mask, dot3 + 1, LEN ( mask ) - dot3 ), "0" ) )
            VAR ip = "10.10.1.38"
            VAR d1 =
                FIND ( ".", ip, 1, 0 )
            VAR ip1 =
                VALUE ( IF ( d1 > 0, ( MID ( ip, 1, d1 - 1 ) ), "0" ) )
            VAR d2 =
                FIND ( ".", ip, d1 + 1, 0 )
            VAR ip2 =
                VALUE ( IF ( d2 > 0, MID ( ip, d1 + 1, d2 - 1 - d1 ), "0" ) )
            VAR d3 =
                FIND ( ".", ip, d2 + 1, 0 )
            VAR ip3 =
                VALUE ( IF ( d3 > 0, MID ( ip, d2 + 1, d3 - 1 - d2 ), "0" ) )
            VAR ip4 =
                VALUE ( IF ( d3 > 0, MID ( ip, d3 + 1, LEN ( ip ) - d3 ), "0" ) )
            VAR ipAddress = ( ( ip1 * 256 + ip2 ) * 256 + ip3 ) * 256 + ip4
            VAR ipMask = ( ( p1 * 256 + p2 ) * 256 + p3 ) * 256 + p4
            VAR unmask = 2 ^ 32 - ipMask
            VAR ipNet =
                INT ( ipAddress / unmask ) * unmask
            VAR in1 =
                INT ( ipNet / 2 ^ 24 )
            VAR in2 =
                INT ( MOD ( ipNet, 2 ^ 24 ) / 2 ^ 16 )
            VAR in3 =
                INT ( MOD ( ipNet, 2 ^ 16 ) / 2 ^ 8 )
            VAR in4 =
                MOD ( ipNet, 2 ^ 8 )
            VAR Result =
                in1 & "." & in2 & "." & in3 & "." & in4 & "/"
                    & 32 - LOG ( unmask, 2 )
            RETURN
                Result
    

    this is a link to a working version of this code on DAX.do