From: Mark on
Hi

Trying to understand some application dealing with VLAN and can't figure out
what this piece of code does:

#define MAX_PORTS_IN_UNIT 28
#define MAX_VLAN_ID 4095
#define VLAN_BITMAP_ARRAY_SIZE (MAX_VLAN_ID/32+1)

unsigned long vlan_member_array[VLAN_BITMAP_ARRAY_SIZE];

int sw_is_set_vlan_bit(unsigned long *VlanBitArray, int vlan_id)
{
return (VlanBitArray[(vlan_id - 1) / 32] & (1 << ((vlan_id - 1) % 32)));
}
....
int port;
for (port = 0; port < MAX_PORTS_IN_UNIT; port++) {
....
/* Set PVID for each port */
if (!sw_is_set_vlan_bit(vlan_member_array, pvid)) {
printf("PVID Error!\n");
} else {
.....
}
....
}

Here is a loop running through the ports (let's say 24) and calling
sw_is_set_vlan_bit() for each port:

The code is huge, I hope the snippet I'm providing will suffice. So my
questions are:
1) why to define an array of (MAX_VLAN_ID/32+1) size. What does it indicate?
2) what exactly does the function do?

Thanks!

--
Mark

From: Thomas Maier-Komor on
Mark schrieb:
> Hi
>
> Trying to understand some application dealing with VLAN and can't figure
> out what this piece of code does:
>
> #define MAX_PORTS_IN_UNIT 28
> #define MAX_VLAN_ID 4095
> #define VLAN_BITMAP_ARRAY_SIZE (MAX_VLAN_ID/32+1)
>
> unsigned long vlan_member_array[VLAN_BITMAP_ARRAY_SIZE];
>
> int sw_is_set_vlan_bit(unsigned long *VlanBitArray, int vlan_id)
> {
> return (VlanBitArray[(vlan_id - 1) / 32] & (1 << ((vlan_id - 1) % 32)));
> }
> ...
> int port;
> for (port = 0; port < MAX_PORTS_IN_UNIT; port++) {
> ...
> /* Set PVID for each port */
> if (!sw_is_set_vlan_bit(vlan_member_array, pvid)) {
> printf("PVID Error!\n");
> } else {
> ....
> }
> ...
> }
>
> Here is a loop running through the ports (let's say 24) and calling
> sw_is_set_vlan_bit() for each port:
>
> The code is huge, I hope the snippet I'm providing will suffice. So my
> questions are:
> 1) why to define an array of (MAX_VLAN_ID/32+1) size. What does it
> indicate?
> 2) what exactly does the function do?
>
> Thanks!
>

The function returns 0 if the bit vlan_id in VlanBitArray is not set, if
it is set some value != 0 is returned.

The first portion (i.e. VlanBitArray[(vlan_id - 1) / 32]) selects the
responsible 32bit word in the array, where the relevant bit is located.

The second part (i.e. & (1 << ((vlan_id - 1) % 32))) uses a and mask to
mask out all bits except the relevant one.

The +1 in MAX_VLAN_ID/32+1 is necessary to create a large enough array.
if MAX_VLAN_ID is 16, division by 32 is 0, i.e. the array would be 0
size. Therefore, it is necessary to add one, in case MAX_VLAN_ID is not
a multiple of 32.

HTH,
Thomas
From: Jens Thoms Toerring on
Mark <mark_cruzNOTFORSPAM(a)hotmail.com> wrote:
> Hi

> Trying to understand some application dealing with VLAN and can't figure out
> what this piece of code does:

> #define MAX_PORTS_IN_UNIT 28
> #define MAX_VLAN_ID 4095
> #define VLAN_BITMAP_ARRAY_SIZE (MAX_VLAN_ID/32+1)

> unsigned long vlan_member_array[VLAN_BITMAP_ARRAY_SIZE];

> int sw_is_set_vlan_bit(unsigned long *VlanBitArray, int vlan_id)
> {
> return (VlanBitArray[(vlan_id - 1) / 32] & (1 << ((vlan_id - 1) % 32)));
> }
> ...
> int port;
> for (port = 0; port < MAX_PORTS_IN_UNIT; port++) {
> ...
> /* Set PVID for each port */
> if (!sw_is_set_vlan_bit(vlan_member_array, pvid)) {
> printf("PVID Error!\n");
> } else {
> ....
> }
> ...
> }

> Here is a loop running through the ports (let's say 24) and calling
> sw_is_set_vlan_bit() for each port:

> The code is huge, I hope the snippet I'm providing will suffice. So my
> questions are:
> 1) why to define an array of (MAX_VLAN_ID/32+1) size. What does it indicate?
> 2) what exactly does the function do?

It's not completely clear what all this is meant for, but certain
things look rather obvious to me: the author wanted an array of
bits for each VLAN ID (whatever that is) to be able to store a
single bit of information for each on. Since there are no bit
arrays in C (s)he opted for instead using an array of longs and
using each bit in each long in the array for a different VLAN ID.
So the bit for VLAN ID 1 (the numbering seems to start a 1, not
at 0) would be the least significant bit in 'vlan_member_array[0]',
the one for VLAN ID 2 would be the next higher bit etc. The bit
for VLAN id 33 is then the least significant bit in
'vlan_member_array[1]' etc.

But there seems to be a bug here:

> #define MAX_VLAN_ID 4095
> #define VLAN_BITMAP_ARRAY_SIZE (MAX_VLAN_ID/32+1)
> unsigned long vlan_member_array[VLAN_BITMAP_ARRAY_SIZE];

Instead of as 'MAX_VLAN_ID/32+1' one needs

#define VLAN_BITMAP_ARRAY_SIZE ((MAX_VLAN_ID+1)/32)

to have enough room in the array. And, of course, MAX_VLAN_ID
must be one less than an integer multiple of 32 for this to
work correctly (otherwise you will end up with less array
elements than are required).

There's also an assumption made here that an unsigned long
has (at least) 32 bits. That's correct if meant for "at
least" but may waste space on machines where a long has 8
bytes.

The function

> int sw_is_set_vlan_bit(unsigned long *VlanBitArray, int vlan_id)
> {
> return (VlanBitArray[(vlan_id - 1) / 32] & (1 << ((vlan_id - 1) % 32)));
> }

simple tells if the bit for a certain VLAN ID is set in the
first argument array. The first part

VlanBitArray[(vlan_id - 1) / 32]

gives you the value of the element of the array where the bit
for 'vlan_id' is stored (with the assuption that 'vlan_bit' runs
from 1 to MAX_VLAN_ID+1). For 'vlan_id' from 1 to 32 this gives
the first element of the array, for 'vlan_id' from 33 to 64 its
the second element etc.

The second part

1 << ((vlan_id - 1) % 32)

results in a value with just a single bit set, which one depen-
ding on 'vlan_id'. For 'vlan_id' values of 1, 33, 65 etc. it's
the lowest bit (i.e. a value of 1), for 'vlan_id' values of 2,
34, 66 etc. its the second lowest bit etc. (i.e. a value of 2)
and for 'vlan_id' 32, 64, 96 etc. its the highest bit (i.e. a
value of 2^31). (Nit-pick: I would use '1UL' instead if '1'
for the first '1' in this expression since we want to end up
with an unsigned long value.)

This second value is now used to mask out the correct bit
from the first value using the '&' operator. So the function
returns 0 if the bit for the VLAN ID isn't set and a non-zero
value otherwise.
Regards, Jens
--
\ Jens Thoms Toerring ___ jt(a)toerring.de
\__________________________ http://toerring.de
From: Jens Thoms Toerring on
Jens Thoms Toerring <jt(a)toerring.de> wrote:
> But there seems to be a bug here:

> > #define MAX_VLAN_ID 4095
> > #define VLAN_BITMAP_ARRAY_SIZE (MAX_VLAN_ID/32+1)
> > unsigned long vlan_member_array[VLAN_BITMAP_ARRAY_SIZE];

> Instead of as 'MAX_VLAN_ID/32+1' one needs

> #define VLAN_BITMAP_ARRAY_SIZE ((MAX_VLAN_ID+1)/32)

> to have enough room in the array. And, of course, MAX_VLAN_ID
> must be one less than an integer multiple of 32 for this to
> work correctly (otherwise you will end up with less array
> elements than are required).

Sorry, scratch that. The way it's written is correct (and works
for arbitrary values of MAX_VLAN_ID) and my "replacement" would
get you in trouble! I guess I need more coffee...

Regards, Jens
--
\ Jens Thoms Toerring ___ jt(a)toerring.de
\__________________________ http://toerring.de
From: Rainer Weikusat on
"Mark" <mark_cruzNOTFORSPAM(a)hotmail.com> writes:
> Trying to understand some application dealing with VLAN and can't
> figure out what this piece of code does:
>
> #define MAX_PORTS_IN_UNIT 28
> #define MAX_VLAN_ID 4095
> #define VLAN_BITMAP_ARRAY_SIZE (MAX_VLAN_ID/32+1)
>
> unsigned long vlan_member_array[VLAN_BITMAP_ARRAY_SIZE];
>
> int sw_is_set_vlan_bit(unsigned long *VlanBitArray, int vlan_id)
> {
> return (VlanBitArray[(vlan_id - 1) / 32] & (1 << ((vlan_id - 1) % 32)));
> }

[...]

> 2) what exactly does the function do?

A VLAN ID, as indicated by this function, is a particular encoding of
a two element vector as int. This vector describes a position in a
128x32 space. This 128x32 space is implemented as array of unsigned
long values (y), each supplying (at least) 32 'data bits'
(x). The y-coordinate comes from (0, 127), indicating an index into
the array, and the x-coordindate from (0, 31), selecting the bit whose
value is 2 to the xth power. The VLAN ID is encoded as

((y << 5) | x) + 1

that is, the y-coordinate is shifted five bits to the left, such that
the five lower bits can be used to hold the x-coordinate. There is no
particular reason for the addition[*]. The two expressions
above decode the encoded value, cleverly disgusing the bit shift and
and operations as integer division and integer division remainder,
presumably, because the useles subtraction was deemed to not be
confusing enough. The recovered bit index is used to create an integer
with exactly this bit set and a &-operation is used to test if the
corresponding bit in the space-array is set. The result is non-zero if
it was (and numerically identical to value of the 1 << expression),
otherwise, zero.

[*] It 'encodes' the author lack of understanding of the C
language, where a[n] is defined as *(a + n), ie, the so-called 'array
index' is, in fact, the distance of the addressed field from
the start of the array, at the expense of confusing potential
readers and forcing the computer to do useless work.

This is further emphasized by the fact that the MAX_VLAN_ID
macros is not defined to be the numerically highest VLAN ID
but the largest valid index for addressing elements of the
array and because of this, another correction is necessary
(that's the MAX_VLAN_ID/32 + 1).