]>
Commit | Line | Data |
---|---|---|
99eef98b DF |
1 | /* |
2 | * Copyright (c) 2015 Avaya, Inc. | |
3 | * | |
4 | * Permission to use, copy, modify, and/or distribute this software for any | |
5 | * purpose with or without fee is hereby granted, provided that the above | |
6 | * copyright notice and this permission notice appear in all copies. | |
7 | * | |
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
15 | */ | |
16 | ||
17 | #include <config.h> | |
18 | #undef NDEBUG | |
19 | #include <assert.h> | |
20 | #include <stdio.h> | |
21 | #include <stdlib.h> | |
22 | #include <string.h> | |
23 | #include "ovs-lldp.h" | |
24 | #include "ovstest.h" | |
25 | ||
26 | #define ETH_TYPE_LLDP 0x88cc | |
27 | ||
28 | /* Dummy MAC addresses */ | |
74ff3298 JR |
29 | static const struct eth_addr chassis_mac = { { { 0x5e, 0x10, 0x8e, 0xe7, 0x84, 0xad } } }; |
30 | static const struct eth_addr eth_src = { { { 0x5e, 0x10, 0x8e, 0xe7, 0x84, 0xad } } }; | |
99eef98b DF |
31 | |
32 | /* LLDP multicast address */ | |
74ff3298 | 33 | static const struct eth_addr eth_addr_lldp = { { { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x0e } } }; |
99eef98b DF |
34 | |
35 | /* Count of tests run */ | |
24885e32 | 36 | static int num_tests = 0; |
99eef98b DF |
37 | |
38 | ||
39 | /* | |
40 | * Helper function to validate port info | |
41 | */ | |
42 | static void | |
43 | check_received_port(struct lldpd_port *sport, | |
44 | struct lldpd_port *rport) | |
45 | { | |
46 | assert(rport->p_id_subtype == sport->p_id_subtype); | |
47 | assert(rport->p_id_len == sport->p_id_len); | |
48 | assert(strncmp(rport->p_id, sport->p_id, sport->p_id_len) == 0); | |
49 | assert(strcmp(rport->p_descr, sport->p_descr) == 0); | |
50 | ||
51 | return; | |
52 | } | |
53 | ||
54 | ||
55 | /* | |
56 | * Helper function to validate chassis info | |
57 | */ | |
58 | static void | |
59 | check_received_chassis(struct lldpd_chassis *schassis, | |
60 | struct lldpd_chassis *rchassis) | |
61 | { | |
62 | assert(rchassis->c_id_subtype == schassis->c_id_subtype); | |
63 | assert(rchassis->c_id_len == schassis->c_id_len); | |
1acaf4ac | 64 | assert(memcmp(rchassis->c_id, schassis->c_id, schassis->c_id_len) == 0); |
99eef98b DF |
65 | assert(strcmp(rchassis->c_name, schassis->c_name) == 0); |
66 | assert(strcmp(rchassis->c_descr, schassis->c_descr) == 0); | |
67 | assert(rchassis->c_cap_available == schassis->c_cap_available); | |
68 | assert(rchassis->c_cap_enabled == schassis->c_cap_enabled); | |
69 | ||
70 | return; | |
71 | } | |
72 | ||
73 | ||
74 | /* | |
75 | * Helper function to validate auto-attach info | |
76 | */ | |
77 | static void | |
78 | check_received_aa(struct lldpd_port *sport, | |
79 | struct lldpd_port *rport, | |
80 | struct lldpd_aa_isid_vlan_maps_tlv *smap) | |
81 | { | |
82 | struct lldpd_aa_isid_vlan_maps_tlv *received_map; | |
83 | int i = 0; | |
84 | ||
85 | assert(rport->p_element.type == sport->p_element.type); | |
86 | assert(rport->p_element.mgmt_vlan == sport->p_element.mgmt_vlan); | |
74ff3298 JR |
87 | assert(eth_addr_equals(rport->p_element.system_id.system_mac, |
88 | sport->p_element.system_id.system_mac)); | |
99eef98b DF |
89 | assert(rport->p_element.system_id.conn_type == |
90 | sport->p_element.system_id.conn_type); | |
14691214 DF |
91 | assert(rport->p_element.system_id.rsvd == |
92 | sport->p_element.system_id.rsvd); | |
93 | assert(rport->p_element.system_id.rsvd2[0] == | |
94 | sport->p_element.system_id.rsvd2[0]); | |
95 | assert(rport->p_element.system_id.rsvd2[1] == | |
96 | sport->p_element.system_id.rsvd2[1]); | |
99eef98b DF |
97 | |
98 | /* Should receive 2 mappings */ | |
854560f8 | 99 | assert(!list_is_empty(&rport->p_isid_vlan_maps)); |
99eef98b DF |
100 | |
101 | /* For each received isid/vlan mapping */ | |
854560f8 | 102 | LIST_FOR_EACH (received_map, m_entries, &rport->p_isid_vlan_maps) { |
99eef98b DF |
103 | |
104 | /* Validate against mapping sent */ | |
105 | assert(smap[i].isid_vlan_data.status == | |
106 | received_map->isid_vlan_data.status); | |
107 | assert(smap[i].isid_vlan_data.vlan == | |
108 | received_map->isid_vlan_data.vlan); | |
02c842eb BP |
109 | assert(smap[i].isid_vlan_data.isid == |
110 | received_map->isid_vlan_data.isid); | |
99eef98b DF |
111 | |
112 | /* Next mapping sent */ | |
113 | i++; | |
114 | } | |
115 | assert(i == 2); | |
116 | ||
117 | return; | |
118 | } | |
119 | ||
120 | ||
121 | /* | |
122 | * Validate basic send/receive processing | |
123 | */ | |
124 | static int | |
125 | test_aa_send(void) | |
126 | { | |
127 | struct lldp *lldp; | |
128 | struct lldpd_hardware hardware; | |
129 | struct lldpd_chassis chassis; | |
130 | ||
131 | struct lldpd_chassis *nchassis = NULL; | |
132 | struct lldpd_port *nport = NULL; | |
133 | ||
134 | struct lldpd_hardware *hw = NULL; | |
135 | struct lldpd_chassis *ch = NULL; | |
136 | ||
137 | struct lldpd_aa_isid_vlan_maps_tlv map_init[2]; | |
138 | struct lldpd_aa_isid_vlan_maps_tlv map[2]; | |
139 | ||
140 | uint32_t stub[512 / 4]; | |
22736f59 | 141 | struct dp_packet packet; |
99eef98b DF |
142 | |
143 | int n; | |
144 | ||
145 | /* Prepare data used to construct and validate LLDPPDU */ | |
146 | hardware.h_lport.p_id_subtype = LLDP_PORTID_SUBTYPE_IFNAME; | |
147 | hardware.h_lport.p_id = "FastEthernet 1/5"; | |
148 | hardware.h_lport.p_id_len = strlen(hardware.h_lport.p_id); | |
149 | hardware.h_lport.p_descr = "Fake port description"; | |
150 | hardware.h_lport.p_mfs = 1516; | |
151 | ||
152 | /* Auto attach element discovery info */ | |
14691214 DF |
153 | hardware.h_lport.p_element.type = |
154 | LLDP_TLV_AA_ELEM_TYPE_CLIENT_VIRTUAL_SWITCH; | |
99eef98b | 155 | hardware.h_lport.p_element.mgmt_vlan = 0xCDC; |
37ba4764 | 156 | eth_addr_from_uint64(0x010203040506ULL, |
74ff3298 | 157 | &hardware.h_lport.p_element.system_id.system_mac); |
99eef98b DF |
158 | |
159 | hardware.h_lport.p_element.system_id.conn_type = 0x5; | |
14691214 DF |
160 | hardware.h_lport.p_element.system_id.rsvd = 0x3CC; |
161 | hardware.h_lport.p_element.system_id.rsvd2[0] = 0xB; | |
162 | hardware.h_lport.p_element.system_id.rsvd2[1] = 0xE; | |
99eef98b DF |
163 | |
164 | /* Local chassis info */ | |
165 | chassis.c_id_subtype = LLDP_CHASSISID_SUBTYPE_LLADDR; | |
74ff3298 | 166 | chassis.c_id = CONST_CAST(uint8_t *, chassis_mac.ea); |
09c28fa3 | 167 | chassis.c_id_len = ETH_ADDR_LEN; |
99eef98b DF |
168 | chassis.c_name = "Dummy chassis"; |
169 | chassis.c_descr = "Long dummy chassis description"; | |
170 | chassis.c_cap_available = LLDP_CAP_BRIDGE; | |
171 | chassis.c_cap_enabled = LLDP_CAP_BRIDGE; | |
172 | ||
173 | /* ISID/VLAN mappings */ | |
174 | map_init[0].isid_vlan_data.status = 0xC; | |
175 | map_init[0].isid_vlan_data.vlan = 0x64; | |
02c842eb | 176 | map_init[0].isid_vlan_data.isid = 0x010203; |
99eef98b DF |
177 | |
178 | map_init[1].isid_vlan_data.status = 0xD; | |
179 | map_init[1].isid_vlan_data.vlan = 0xF; | |
02c842eb | 180 | map_init[1].isid_vlan_data.isid = 0x040506; |
99eef98b DF |
181 | |
182 | /* Prepare an empty packet buffer */ | |
22736f59 BP |
183 | dp_packet_use_stub(&packet, stub, sizeof stub); |
184 | dp_packet_clear(&packet); | |
99eef98b DF |
185 | |
186 | /* Create a dummy lldp instance */ | |
187 | lldp = lldp_create_dummy(); | |
188 | if ((lldp == NULL) || | |
189 | (lldp->lldpd == NULL) || | |
2cbb2d90 | 190 | list_is_empty(&lldp->lldpd->g_hardware)) { |
99eef98b DF |
191 | printf("Error: unable to create dummy lldp instance"); |
192 | return 1; | |
193 | } | |
194 | ||
195 | /* Populate instance with local chassis info */ | |
2cbb2d90 | 196 | hw = lldpd_first_hardware(lldp->lldpd); |
99eef98b DF |
197 | ch = hw->h_lport.p_chassis; |
198 | ch->c_id_subtype = chassis.c_id_subtype; | |
199 | ch->c_id = chassis.c_id; | |
200 | ch->c_id_len = chassis.c_id_len; | |
201 | ch->c_name = chassis.c_name; | |
202 | ch->c_descr = chassis.c_descr; | |
203 | ch->c_cap_available = chassis.c_cap_available; | |
204 | ch->c_cap_enabled = chassis.c_cap_enabled; | |
205 | ||
206 | /* Populate instance with local port info */ | |
207 | hw->h_lport.p_id_subtype = hardware.h_lport.p_id_subtype; | |
208 | hw->h_lport.p_id = hardware.h_lport.p_id; | |
209 | hw->h_lport.p_id_len = strlen(hw->h_lport.p_id); | |
210 | hw->h_lport.p_descr = hardware.h_lport.p_descr; | |
211 | hw->h_lport.p_mfs = hardware.h_lport.p_mfs; | |
212 | ||
213 | /* Populate instance with auto attach element discovery info */ | |
214 | ||
215 | hw->h_lport.p_element.type = hardware.h_lport.p_element.type; | |
216 | hw->h_lport.p_element.mgmt_vlan = hardware.h_lport.p_element.mgmt_vlan; | |
74ff3298 JR |
217 | hw->h_lport.p_element.system_id.system_mac = |
218 | hardware.h_lport.p_element.system_id.system_mac; | |
99eef98b DF |
219 | |
220 | hw->h_lport.p_element.system_id.conn_type = | |
221 | hardware.h_lport.p_element.system_id.conn_type; | |
14691214 DF |
222 | hw->h_lport.p_element.system_id.rsvd = |
223 | hardware.h_lport.p_element.system_id.rsvd; | |
224 | hw->h_lport.p_element.system_id.rsvd2[0] = | |
225 | hardware.h_lport.p_element.system_id.rsvd2[0]; | |
226 | hw->h_lport.p_element.system_id.rsvd2[1] = | |
227 | hardware.h_lport.p_element.system_id.rsvd2[1]; | |
99eef98b DF |
228 | |
229 | /* Populate instance with two auto attach isid/vlan mappings */ | |
230 | map[0].isid_vlan_data.status = map_init[0].isid_vlan_data.status; | |
231 | map[0].isid_vlan_data.vlan = map_init[0].isid_vlan_data.vlan; | |
02c842eb | 232 | map[0].isid_vlan_data.isid = map_init[0].isid_vlan_data.isid; |
99eef98b DF |
233 | |
234 | map[1].isid_vlan_data.status = map_init[1].isid_vlan_data.status; | |
235 | map[1].isid_vlan_data.vlan = map_init[1].isid_vlan_data.vlan; | |
02c842eb | 236 | map[1].isid_vlan_data.isid = map_init[1].isid_vlan_data.isid; |
99eef98b | 237 | |
854560f8 BP |
238 | list_init(&hw->h_lport.p_isid_vlan_maps); |
239 | list_push_back(&hw->h_lport.p_isid_vlan_maps, &map[0].m_entries); | |
240 | list_push_back(&hw->h_lport.p_isid_vlan_maps, &map[1].m_entries); | |
99eef98b DF |
241 | |
242 | /* Construct LLDPPDU (including Ethernet header) */ | |
243 | eth_compose(&packet, eth_addr_lldp, eth_src, ETH_TYPE_LLDP, 0); | |
244 | n = lldp_send(lldp->lldpd, hw, &packet); | |
245 | ||
246 | if (n == 0) { | |
247 | printf("Error: unable to build packet\n"); | |
248 | return 1; | |
249 | } | |
250 | ||
251 | /* Decode the constructed LLDPPDU */ | |
09c28fa3 | 252 | assert(lldp_decode(NULL, dp_packet_data(&packet), dp_packet_size(&packet), hw, |
99eef98b DF |
253 | &nchassis, &nport) != -1); |
254 | ||
255 | /* Expecting returned pointers to allocated structures */ | |
256 | if (!nchassis || !nport) { | |
257 | printf("Error: unable to decode packet"); | |
258 | return 1; | |
259 | } | |
260 | ||
261 | /* Verify chassis values */ | |
262 | check_received_chassis(&chassis, nchassis); | |
263 | ||
264 | /* Verify port values */ | |
265 | check_received_port(&hardware.h_lport, nport); | |
266 | ||
267 | /* Verify auto attach values */ | |
268 | check_received_aa(&hardware.h_lport, nport, map_init); | |
269 | ||
270 | return 0; | |
271 | } | |
272 | ||
273 | ||
274 | static void | |
275 | test_aa_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) | |
276 | { | |
277 | int num_errors = 0; | |
278 | ||
279 | /* Make sure we emit valid auto-attach LLDPPDUs */ | |
280 | num_tests++; | |
281 | num_errors += test_aa_send(); | |
282 | ||
283 | /* Add more tests here */ | |
284 | ||
285 | printf("executed %d tests, %d errors\n", num_tests, num_errors); | |
286 | ||
287 | exit(num_errors != 0); | |
288 | } | |
289 | ||
290 | OVSTEST_REGISTER("test-aa", test_aa_main); |