Prev: Restricting symbols from getting exported to global symb table
Next: waitpid == -1 and errno == ECHILD
From: Mark on 27 Nov 2009 01:48 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 27 Nov 2009 03:44 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 27 Nov 2009 04:09 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 27 Nov 2009 04:15 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 27 Nov 2009 07:52 "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).
|
Next
|
Last
Pages: 1 2 3 Prev: Restricting symbols from getting exported to global symb table Next: waitpid == -1 and errno == ECHILD |