Reputation: 6358
I have to convert 2 DWORDs, IP address and a network mask to CDIR format... So I have 2 DWORDs corresponding 1.1.1.1 and 255.255.255.255 and I want to come up with string 1.1.1.1/32
Any thoughts on this?
Thanks
Upvotes: 3
Views: 13972
Reputation: 11
This isn't completely portable, but is likely the fastest way of doing this if your program is running on a chip that supports the Intel instruction set. (And a similar approach may work for other architectures). The Intel chips have an instruction called POPCNT
, which returns the number of bits in a variable that are set to 1
. Most compilers should provide an intrinsic to access this. For example, the Microsoft compilers give you __popcnt
and GCC gives you __builtin_popcount
. (With various flavors for different argument sizes).
Assuming a well-formed mask (as do all of the other solutions offered here), you can get the CIDR bit count with a single machine instruction.
inline uint32_t getBitCountFromIPv4Mask(uint32_t mask) {
return __builtin_popcount(mask); // presumes a well-formed mask.
}
You can do this with IPv6 masks as well. There's a 64-bit version of POPCNT
, but since in6_addr
won't give out address fragments in 64 bit chunks, it's probably best to not use it here.
uint32_t getBitCountFromIPv6Mask(const in6_addr &mask) {
uint32_t bitCount = 0;
for (uint32_t ii = 0; ii < 4; ii++) {
bitCount += __builtin_popcount(mask.s6_addr32[ii]);
}
return bitCount;
}
Upvotes: 1
Reputation: 433
Simplest approach:
static unsigned short toCidr(char* ipAddress)
{
unsigned short netmask_cidr;
int ipbytes[4];
netmask_cidr=0;
sscanf(ipAddress, "%d.%d.%d.%d", &ipbytes[0], &ipbytes[1], &ipbytes[2], &ipbytes[3]);
for (int i=0; i<4; i++)
{
switch(ipbytes[i])
{
case 0x80:
netmask_cidr+=1;
break;
case 0xC0:
netmask_cidr+=2;
break;
case 0xE0:
netmask_cidr+=3;
break;
case 0xF0:
netmask_cidr+=4;
break;
case 0xF8:
netmask_cidr+=5;
break;
case 0xFC:
netmask_cidr+=6;
break;
case 0xFE:
netmask_cidr+=7;
break;
case 0xFF:
netmask_cidr+=8;
break;
default:
return netmask_cidr;
break;
}
}
return netmask_cidr;
}
Upvotes: 7
Reputation: 20370
Not efficient if you have a large amount of these to do, as it goes through the bits one at a time. But very straightforward way to count each bit in the netmask:
int cidr = 0;
while ( netmask )
{
cidr += ( netmask & 0x01 );
netmask >>= 1;
}
Then combine the IP address with this CIDR value.
Upvotes: 3
Reputation: 7507
Since there are a small and fixed number of valid netmasks (32, to be exact), the fastest way is probably to just build a map of masks to prefix length once at init time, and the conversion is just a lookup in the map.
Upvotes: 4
Reputation: 272687
The prefix-length is equal to the number of (leading) ones in the binary representation of the subnet mask. So you just need to count the number of (leading) ones.
Upvotes: 3