1 /*
2  * Copyright (c) 2010 Lawrence Livermore National Lab.  All rights reserved.
3  *
4  * This software is available to you under a choice of one of two
5  * licenses.  You may choose to be licensed under the terms of the GNU
6  * General Public License (GPL) Version 2, available from the file
7  * COPYING in the main directory of this source tree, or the
8  * OpenIB.org BSD license below:
9  *
10  *     Redistribution and use in source and binary forms, with or
11  *     without modification, are permitted provided that the following
12  *     conditions are met:
13  *
14  *      - Redistributions of source code must retain the above
15  *        copyright notice, this list of conditions and the following
16  *        disclaimer.
17  *
18  *      - Redistributions in binary form must reproduce the above
19  *        copyright notice, this list of conditions and the following
20  *        disclaimer in the documentation and/or other materials
21  *        provided with the distribution.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30  * SOFTWARE.
31  *
32  */
33 
34 #if HAVE_CONFIG_H
35 #  include <config.h>
36 #endif				/* HAVE_CONFIG_H */
37 
38 #define _GNU_SOURCE
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <getopt.h>
43 #include <inttypes.h>
44 
45 #include <infiniband/mad.h>
46 #include <infiniband/ibnetdisc.h>
47 
48 #include "ibdiag_common.h"
49 
50 uint64_t switchguid_before = 0;
51 uint64_t switchguid_after = 0;
52 int switchguid_flag = 0;
53 
54 uint64_t caguid_before = 0;
55 uint64_t caguid_after = 0;
56 int caguid_flag = 0;
57 
58 uint64_t sysimgguid_before = 0;
59 uint64_t sysimgguid_after = 0;
60 int sysimgguid_flag = 0;
61 
62 uint64_t portguid_nodeguid = 0;
63 uint64_t portguid_before = 0;
64 uint64_t portguid_after = 0;
65 int portguid_flag = 0;
66 
67 struct guids {
68 	uint64_t searchguid;
69 	int searchguid_found;
70 	uint64_t before;
71 	uint64_t after;
72 	int found;
73 };
74 
75 static int parse_beforeafter(char *arg, uint64_t *before, uint64_t *after)
76 {
77 	char *ptr;
78 	char *before_str;
79 	char *after_str;
80 
81 	ptr = strchr(optarg, ':');
82 	if (!ptr || !(*(ptr + 1))) {
83 		fprintf(stderr, "invalid input '%s'\n", arg);
84 		return -1;
85 	}
86 	(*ptr) = '\0';
87 	before_str = arg;
88 	after_str = ptr + 1;
89 
90 	(*before) = strtoull(before_str, 0, 0);
91 	(*after) = strtoull(after_str, 0, 0);
92 	return 0;
93 }
94 
95 static int parse_guidbeforeafter(char *arg,
96 				 uint64_t *guid,
97 				 uint64_t *before,
98 				 uint64_t *after)
99 {
100 	char *ptr1;
101 	char *ptr2;
102 	char *guid_str;
103 	char *before_str;
104 	char *after_str;
105 
106 	ptr1 = strchr(optarg, ':');
107 	if (!ptr1 || !(*(ptr1 + 1))) {
108 		fprintf(stderr, "invalid input '%s'\n", arg);
109 		return -1;
110 	}
111 	guid_str = arg;
112 	before_str = ptr1 + 1;
113 
114 	ptr2 = strchr(before_str, ':');
115 	if (!ptr2 || !(*(ptr2 + 1))) {
116 		fprintf(stderr, "invalid input '%s'\n", arg);
117 		return -1;
118 	}
119 	(*ptr1) = '\0';
120 	(*ptr2) = '\0';
121 	after_str = ptr2 + 1;
122 
123 	(*guid) = strtoull(guid_str, 0, 0);
124 	(*before) = strtoull(before_str, 0, 0);
125 	(*after) = strtoull(after_str, 0, 0);
126 	return 0;
127 }
128 
129 static int process_opt(void *context, int ch, char *optarg)
130 {
131 	switch (ch) {
132 	case 1:
133 		if (parse_beforeafter(optarg,
134 				      &switchguid_before,
135 				      &switchguid_after) < 0)
136 			return -1;
137 		switchguid_flag++;
138 		break;
139 	case 2:
140 		if (parse_beforeafter(optarg,
141 				      &caguid_before,
142 				      &caguid_after) < 0)
143 			return -1;
144 		caguid_flag++;
145 		break;
146 	case 3:
147 		if (parse_beforeafter(optarg,
148 				      &sysimgguid_before,
149 				      &sysimgguid_after) < 0)
150 			return -1;
151 		sysimgguid_flag++;
152 		break;
153 	case 4:
154 		if (parse_guidbeforeafter(optarg,
155 					  &portguid_nodeguid,
156 					  &portguid_before,
157 					  &portguid_after) < 0)
158 			return -1;
159 		portguid_flag++;
160 		break;
161 	default:
162 		return -1;
163 	}
164 
165 	return 0;
166 }
167 
168 static void update_switchportguids(ibnd_node_t *node)
169 {
170 	ibnd_port_t *port;
171 	int p;
172 
173 	for (p = 0; p <= node->numports; p++) {
174 		port = node->ports[p];
175 		if (port)
176 			port->guid = node->guid;
177 	}
178 }
179 
180 static void replace_node_guid(ibnd_node_t *node, void *user_data)
181 {
182 	struct guids *guids;
183 
184 	guids = (struct guids *)user_data;
185 
186 	if (node->guid == guids->before) {
187 
188 		node->guid = guids->after;
189 
190 		/* port guids are identical to switch guids on
191 		 * switches, so update port guids too
192 		 */
193 		if (node->type == IB_NODE_SWITCH)
194 			update_switchportguids(node);
195 
196 		guids->found++;
197 	}
198 }
199 
200 static void replace_sysimgguid(ibnd_node_t *node, void *user_data)
201 {
202 	struct guids *guids;
203 	uint64_t sysimgguid;
204 
205 	guids = (struct guids *)user_data;
206 
207 	sysimgguid = mad_get_field64(node->info, 0, IB_NODE_SYSTEM_GUID_F);
208 	if (sysimgguid == guids->before) {
209 		mad_set_field64(node->info, 0, IB_NODE_SYSTEM_GUID_F,
210 				guids->after);
211 		guids->found++;
212 	}
213 }
214 
215 static void replace_portguid(ibnd_node_t *node, void *user_data)
216 {
217 	struct guids *guids;
218 
219 	guids = (struct guids *)user_data;
220 
221 	if (node->guid != guids->searchguid)
222 		return;
223 
224 	guids->searchguid_found++;
225 
226 	if (node->type == IB_NODE_SWITCH) {
227 		/* port guids are identical to switch guids on
228 		 * switches, so update switch guid too
229 		 */
230 		if (node->guid == guids->before) {
231 			node->guid = guids->after;
232 			update_switchportguids(node);
233 			guids->found++;
234 		}
235 	}
236 	else {
237 		ibnd_port_t *port;
238 		int p;
239 
240 		for (p = 1; p <= node->numports; p++) {
241 			port = node->ports[p];
242 			if (port
243 			    && port->guid == guids->before) {
244 				port->guid = guids->after;
245 				guids->found++;
246 				break;
247 			}
248 		}
249 	}
250 }
251 
252 int main(int argc, char **argv)
253 {
254 	ibnd_fabric_t *fabric = NULL;
255 	char *orig_cache_file = NULL;
256 	char *new_cache_file = NULL;
257 	struct guids guids;
258 
259 	const struct ibdiag_opt opts[] = {
260 		{"switchguid", 1, 1, "BEFOREGUID:AFTERGUID",
261 		 "Specify before and after switchguid to edit"},
262 		{"caguid", 2, 1, "BEFOREGUID:AFTERGUID",
263 		 "Specify before and after caguid to edit"},
264 		{"sysimgguid", 3, 1, "BEFOREGUID:AFTERGUID",
265 		 "Specify before and after sysimgguid to edit"},
266 		{"portguid", 4, 1, "NODEGUID:BEFOREGUID:AFTERGUID",
267 		 "Specify before and after port guid to edit"},
268 		{0}
269 	};
270 	char *usage_args = "<orig.cache> <new.cache>";
271 
272 	ibdiag_process_opts(argc, argv, NULL, "CDdeGKLPstvy",
273 			    opts, process_opt, usage_args,
274 			    NULL);
275 
276 	argc -= optind;
277 	argv += optind;
278 
279 	orig_cache_file = argv[0];
280 	new_cache_file = argv[1];
281 
282 	if (!orig_cache_file)
283 		IBEXIT("original cache file not specified");
284 
285 	if (!new_cache_file)
286 		IBEXIT("new cache file not specified");
287 
288 	if ((fabric = ibnd_load_fabric(orig_cache_file, 0)) == NULL)
289 		IBEXIT("loading original cached fabric failed");
290 
291 	if (switchguid_flag) {
292 		guids.before = switchguid_before;
293 		guids.after = switchguid_after;
294 		guids.found = 0;
295 		ibnd_iter_nodes_type(fabric,
296 				     replace_node_guid,
297 				     IB_NODE_SWITCH,
298 				     &guids);
299 
300 		if (!guids.found)
301 			IBEXIT("switchguid = %" PRIx64 " not found",
302 				switchguid_before);
303 	}
304 
305 	if (caguid_flag) {
306 		guids.before = caguid_before;
307 		guids.after = caguid_after;
308 		guids.found = 0;
309 		ibnd_iter_nodes_type(fabric,
310 				     replace_node_guid,
311 				     IB_NODE_CA,
312 				     &guids);
313 
314 		if (!guids.found)
315 			IBEXIT("caguid = %" PRIx64 " not found",
316 				caguid_before);
317 	}
318 
319 	if (sysimgguid_flag) {
320 		guids.before = sysimgguid_before;
321 		guids.after = sysimgguid_after;
322 		guids.found = 0;
323 		ibnd_iter_nodes(fabric,
324 				replace_sysimgguid,
325 				&guids);
326 
327 		if (!guids.found)
328 			IBEXIT("sysimgguid = %" PRIx64 " not found",
329 				sysimgguid_before);
330 	}
331 
332 	if (portguid_flag) {
333 		guids.searchguid = portguid_nodeguid;
334 		guids.searchguid_found = 0;
335 		guids.before = portguid_before;
336 		guids.after = portguid_after;
337 		guids.found = 0;
338 		ibnd_iter_nodes(fabric,
339 				replace_portguid,
340 				&guids);
341 
342 		if (!guids.searchguid_found)
343 			IBEXIT("nodeguid = %" PRIx64 " not found",
344 				portguid_nodeguid);
345 
346 		if (!guids.found)
347 			IBEXIT("portguid = %" PRIx64 " not found",
348 				portguid_before);
349 	}
350 
351 	if (ibnd_cache_fabric(fabric, new_cache_file, 0) < 0)
352 		IBEXIT("caching new cache data failed");
353 
354 	ibnd_destroy_fabric(fabric);
355 	exit(0);
356 }
357