1041379a6SGreg Tucker /**********************************************************************
2041379a6SGreg Tucker Copyright(c) 2011-2018 Intel Corporation All rights reserved.
3041379a6SGreg Tucker
4041379a6SGreg Tucker Redistribution and use in source and binary forms, with or without
5041379a6SGreg Tucker modification, are permitted provided that the following conditions
6041379a6SGreg Tucker are met:
7041379a6SGreg Tucker * Redistributions of source code must retain the above copyright
8041379a6SGreg Tucker notice, this list of conditions and the following disclaimer.
9041379a6SGreg Tucker * Redistributions in binary form must reproduce the above copyright
10041379a6SGreg Tucker notice, this list of conditions and the following disclaimer in
11041379a6SGreg Tucker the documentation and/or other materials provided with the
12041379a6SGreg Tucker distribution.
13041379a6SGreg Tucker * Neither the name of Intel Corporation nor the names of its
14041379a6SGreg Tucker contributors may be used to endorse or promote products derived
15041379a6SGreg Tucker from this software without specific prior written permission.
16041379a6SGreg Tucker
17041379a6SGreg Tucker THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18041379a6SGreg Tucker "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19041379a6SGreg Tucker LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20041379a6SGreg Tucker A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21041379a6SGreg Tucker OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22041379a6SGreg Tucker SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23041379a6SGreg Tucker LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24041379a6SGreg Tucker DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25041379a6SGreg Tucker THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26041379a6SGreg Tucker (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27041379a6SGreg Tucker OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28041379a6SGreg Tucker **********************************************************************/
29041379a6SGreg Tucker
30041379a6SGreg Tucker #include <stdio.h>
31041379a6SGreg Tucker #include <stdlib.h>
32041379a6SGreg Tucker #include <string.h>
33041379a6SGreg Tucker #include <getopt.h>
34041379a6SGreg Tucker #include "erasure_code.h" // use <isa-l.h> instead when linking against installed
35041379a6SGreg Tucker
36041379a6SGreg Tucker #define MMAX 255
37041379a6SGreg Tucker #define KMAX 255
38041379a6SGreg Tucker
39041379a6SGreg Tucker typedef unsigned char u8;
40041379a6SGreg Tucker
41*9d99f821SMarcel Cornu int
usage(void)42*9d99f821SMarcel Cornu usage(void)
43041379a6SGreg Tucker {
44041379a6SGreg Tucker fprintf(stderr,
45041379a6SGreg Tucker "Usage: ec_simple_example [options]\n"
46041379a6SGreg Tucker " -h Help\n"
47041379a6SGreg Tucker " -k <val> Number of source fragments\n"
48041379a6SGreg Tucker " -p <val> Number of parity fragments\n"
49041379a6SGreg Tucker " -l <val> Length of fragments\n"
50041379a6SGreg Tucker " -e <val> Simulate erasure on frag index val. Zero based. Can be repeated.\n"
51041379a6SGreg Tucker " -r <seed> Pick random (k, p) with seed\n");
52041379a6SGreg Tucker exit(0);
53041379a6SGreg Tucker }
54041379a6SGreg Tucker
55*9d99f821SMarcel Cornu static int
56*9d99f821SMarcel Cornu gf_gen_decode_matrix_simple(u8 *encode_matrix, u8 *decode_matrix, u8 *invert_matrix,
57*9d99f821SMarcel Cornu u8 *temp_matrix, u8 *decode_index, u8 *frag_err_list, int nerrs, int k,
58*9d99f821SMarcel Cornu int m);
59041379a6SGreg Tucker
60*9d99f821SMarcel Cornu int
main(int argc,char * argv[])61*9d99f821SMarcel Cornu main(int argc, char *argv[])
62041379a6SGreg Tucker {
63041379a6SGreg Tucker int i, j, m, c, e, ret;
64041379a6SGreg Tucker int k = 10, p = 4, len = 8 * 1024; // Default params
65041379a6SGreg Tucker int nerrs = 0;
66041379a6SGreg Tucker
67041379a6SGreg Tucker // Fragment buffer pointers
68041379a6SGreg Tucker u8 *frag_ptrs[MMAX];
69041379a6SGreg Tucker u8 *recover_srcs[KMAX];
70041379a6SGreg Tucker u8 *recover_outp[KMAX];
71041379a6SGreg Tucker u8 frag_err_list[MMAX];
72041379a6SGreg Tucker
73041379a6SGreg Tucker // Coefficient matrices
74041379a6SGreg Tucker u8 *encode_matrix, *decode_matrix;
75041379a6SGreg Tucker u8 *invert_matrix, *temp_matrix;
76041379a6SGreg Tucker u8 *g_tbls;
77041379a6SGreg Tucker u8 decode_index[MMAX];
78041379a6SGreg Tucker
79041379a6SGreg Tucker if (argc == 1)
80041379a6SGreg Tucker for (i = 0; i < p; i++)
81041379a6SGreg Tucker frag_err_list[nerrs++] = rand() % (k + p);
82041379a6SGreg Tucker
83041379a6SGreg Tucker while ((c = getopt(argc, argv, "k:p:l:e:r:h")) != -1) {
84041379a6SGreg Tucker switch (c) {
85041379a6SGreg Tucker case 'k':
86041379a6SGreg Tucker k = atoi(optarg);
87041379a6SGreg Tucker break;
88041379a6SGreg Tucker case 'p':
89041379a6SGreg Tucker p = atoi(optarg);
90041379a6SGreg Tucker break;
91041379a6SGreg Tucker case 'l':
92041379a6SGreg Tucker len = atoi(optarg);
93041379a6SGreg Tucker if (len < 0)
94041379a6SGreg Tucker usage();
95041379a6SGreg Tucker break;
96041379a6SGreg Tucker case 'e':
97041379a6SGreg Tucker e = atoi(optarg);
98041379a6SGreg Tucker frag_err_list[nerrs++] = e;
99041379a6SGreg Tucker break;
100041379a6SGreg Tucker case 'r':
101041379a6SGreg Tucker srand(atoi(optarg));
1029edac479SGreg Tucker k = (rand() % (MMAX - 1)) + 1; // Pick k {1 to MMAX - 1}
1039edac479SGreg Tucker p = (rand() % (MMAX - k)) + 1; // Pick p {1 to MMAX - k}
1049edac479SGreg Tucker
105041379a6SGreg Tucker for (i = 0; i < k + p && nerrs < p; i++)
106041379a6SGreg Tucker if (rand() & 1)
107041379a6SGreg Tucker frag_err_list[nerrs++] = i;
108041379a6SGreg Tucker break;
109041379a6SGreg Tucker case 'h':
110041379a6SGreg Tucker default:
111041379a6SGreg Tucker usage();
112041379a6SGreg Tucker break;
113041379a6SGreg Tucker }
114041379a6SGreg Tucker }
115041379a6SGreg Tucker m = k + p;
116041379a6SGreg Tucker
117041379a6SGreg Tucker // Check for valid parameters
1184c4185baSGreg Tucker if (m > MMAX || k > KMAX || m < 0 || p < 1 || k < 1) {
119*9d99f821SMarcel Cornu printf(" Input test parameter error m=%d, k=%d, p=%d, erasures=%d\n", m, k, p,
120*9d99f821SMarcel Cornu nerrs);
121041379a6SGreg Tucker usage();
122041379a6SGreg Tucker }
123041379a6SGreg Tucker if (nerrs > p) {
124*9d99f821SMarcel Cornu printf(" Number of erasures chosen exceeds power of code erasures=%d p=%d\n", nerrs,
125*9d99f821SMarcel Cornu p);
126041379a6SGreg Tucker usage();
127041379a6SGreg Tucker }
128041379a6SGreg Tucker for (i = 0; i < nerrs; i++) {
129041379a6SGreg Tucker if (frag_err_list[i] >= m) {
130041379a6SGreg Tucker printf(" fragment %d not in range\n", frag_err_list[i]);
131041379a6SGreg Tucker usage();
132041379a6SGreg Tucker }
133041379a6SGreg Tucker }
134041379a6SGreg Tucker
135041379a6SGreg Tucker printf("ec_simple_example:\n");
136041379a6SGreg Tucker
137041379a6SGreg Tucker // Allocate coding matrices
138041379a6SGreg Tucker encode_matrix = malloc(m * k);
139041379a6SGreg Tucker decode_matrix = malloc(m * k);
140041379a6SGreg Tucker invert_matrix = malloc(m * k);
141041379a6SGreg Tucker temp_matrix = malloc(m * k);
142041379a6SGreg Tucker g_tbls = malloc(k * p * 32);
143041379a6SGreg Tucker
144*9d99f821SMarcel Cornu if (encode_matrix == NULL || decode_matrix == NULL || invert_matrix == NULL ||
145*9d99f821SMarcel Cornu temp_matrix == NULL || g_tbls == NULL) {
146041379a6SGreg Tucker printf("Test failure! Error with malloc\n");
147041379a6SGreg Tucker return -1;
148041379a6SGreg Tucker }
149041379a6SGreg Tucker // Allocate the src & parity buffers
150041379a6SGreg Tucker for (i = 0; i < m; i++) {
151041379a6SGreg Tucker if (NULL == (frag_ptrs[i] = malloc(len))) {
152041379a6SGreg Tucker printf("alloc error: Fail\n");
153041379a6SGreg Tucker return -1;
154041379a6SGreg Tucker }
155041379a6SGreg Tucker }
156041379a6SGreg Tucker
157041379a6SGreg Tucker // Allocate buffers for recovered data
158041379a6SGreg Tucker for (i = 0; i < p; i++) {
159041379a6SGreg Tucker if (NULL == (recover_outp[i] = malloc(len))) {
160041379a6SGreg Tucker printf("alloc error: Fail\n");
161041379a6SGreg Tucker return -1;
162041379a6SGreg Tucker }
163041379a6SGreg Tucker }
164041379a6SGreg Tucker
165041379a6SGreg Tucker // Fill sources with random data
166041379a6SGreg Tucker for (i = 0; i < k; i++)
167041379a6SGreg Tucker for (j = 0; j < len; j++)
168041379a6SGreg Tucker frag_ptrs[i][j] = rand();
169041379a6SGreg Tucker
170041379a6SGreg Tucker printf(" encode (m,k,p)=(%d,%d,%d) len=%d\n", m, k, p, len);
171041379a6SGreg Tucker
172041379a6SGreg Tucker // Pick an encode matrix. A Cauchy matrix is a good choice as even
173041379a6SGreg Tucker // large k are always invertable keeping the recovery rule simple.
174041379a6SGreg Tucker gf_gen_cauchy1_matrix(encode_matrix, m, k);
175041379a6SGreg Tucker
176041379a6SGreg Tucker // Initialize g_tbls from encode matrix
177041379a6SGreg Tucker ec_init_tables(k, p, &encode_matrix[k * k], g_tbls);
178041379a6SGreg Tucker
179041379a6SGreg Tucker // Generate EC parity blocks from sources
180041379a6SGreg Tucker ec_encode_data(len, k, p, g_tbls, frag_ptrs, &frag_ptrs[k]);
181041379a6SGreg Tucker
182041379a6SGreg Tucker if (nerrs <= 0)
183041379a6SGreg Tucker return 0;
184041379a6SGreg Tucker
185041379a6SGreg Tucker printf(" recover %d fragments\n", nerrs);
186041379a6SGreg Tucker
187041379a6SGreg Tucker // Find a decode matrix to regenerate all erasures from remaining frags
188*9d99f821SMarcel Cornu ret = gf_gen_decode_matrix_simple(encode_matrix, decode_matrix, invert_matrix, temp_matrix,
189*9d99f821SMarcel Cornu decode_index, frag_err_list, nerrs, k, m);
190041379a6SGreg Tucker if (ret != 0) {
191041379a6SGreg Tucker printf("Fail on generate decode matrix\n");
192041379a6SGreg Tucker return -1;
193041379a6SGreg Tucker }
194041379a6SGreg Tucker // Pack recovery array pointers as list of valid fragments
195041379a6SGreg Tucker for (i = 0; i < k; i++)
196041379a6SGreg Tucker recover_srcs[i] = frag_ptrs[decode_index[i]];
197041379a6SGreg Tucker
198041379a6SGreg Tucker // Recover data
199041379a6SGreg Tucker ec_init_tables(k, nerrs, decode_matrix, g_tbls);
200041379a6SGreg Tucker ec_encode_data(len, k, nerrs, g_tbls, recover_srcs, recover_outp);
201041379a6SGreg Tucker
202041379a6SGreg Tucker // Check that recovered buffers are the same as original
203041379a6SGreg Tucker printf(" check recovery of block {");
204041379a6SGreg Tucker for (i = 0; i < nerrs; i++) {
205041379a6SGreg Tucker printf(" %d", frag_err_list[i]);
206041379a6SGreg Tucker if (memcmp(recover_outp[i], frag_ptrs[frag_err_list[i]], len)) {
207041379a6SGreg Tucker printf(" Fail erasure recovery %d, frag %d\n", i, frag_err_list[i]);
208041379a6SGreg Tucker return -1;
209041379a6SGreg Tucker }
210041379a6SGreg Tucker }
211041379a6SGreg Tucker
212041379a6SGreg Tucker printf(" } done all: Pass\n");
213041379a6SGreg Tucker return 0;
214041379a6SGreg Tucker }
215041379a6SGreg Tucker
216041379a6SGreg Tucker /*
217041379a6SGreg Tucker * Generate decode matrix from encode matrix and erasure list
218041379a6SGreg Tucker *
219041379a6SGreg Tucker */
220041379a6SGreg Tucker
221*9d99f821SMarcel Cornu static int
gf_gen_decode_matrix_simple(u8 * encode_matrix,u8 * decode_matrix,u8 * invert_matrix,u8 * temp_matrix,u8 * decode_index,u8 * frag_err_list,int nerrs,int k,int m)222*9d99f821SMarcel Cornu gf_gen_decode_matrix_simple(u8 *encode_matrix, u8 *decode_matrix, u8 *invert_matrix,
223*9d99f821SMarcel Cornu u8 *temp_matrix, u8 *decode_index, u8 *frag_err_list, int nerrs, int k,
224041379a6SGreg Tucker int m)
225041379a6SGreg Tucker {
226041379a6SGreg Tucker int i, j, p, r;
227041379a6SGreg Tucker int nsrcerrs = 0;
228041379a6SGreg Tucker u8 s, *b = temp_matrix;
229041379a6SGreg Tucker u8 frag_in_err[MMAX];
230041379a6SGreg Tucker
231041379a6SGreg Tucker memset(frag_in_err, 0, sizeof(frag_in_err));
232041379a6SGreg Tucker
233041379a6SGreg Tucker // Order the fragments in erasure for easier sorting
234041379a6SGreg Tucker for (i = 0; i < nerrs; i++) {
235041379a6SGreg Tucker if (frag_err_list[i] < k)
236041379a6SGreg Tucker nsrcerrs++;
237041379a6SGreg Tucker frag_in_err[frag_err_list[i]] = 1;
238041379a6SGreg Tucker }
239041379a6SGreg Tucker
240041379a6SGreg Tucker // Construct b (matrix that encoded remaining frags) by removing erased rows
241041379a6SGreg Tucker for (i = 0, r = 0; i < k; i++, r++) {
242041379a6SGreg Tucker while (frag_in_err[r])
243041379a6SGreg Tucker r++;
244041379a6SGreg Tucker for (j = 0; j < k; j++)
245041379a6SGreg Tucker b[k * i + j] = encode_matrix[k * r + j];
246041379a6SGreg Tucker decode_index[i] = r;
247041379a6SGreg Tucker }
248041379a6SGreg Tucker
249041379a6SGreg Tucker // Invert matrix to get recovery matrix
250041379a6SGreg Tucker if (gf_invert_matrix(b, invert_matrix, k) < 0)
251041379a6SGreg Tucker return -1;
252041379a6SGreg Tucker
253041379a6SGreg Tucker // Get decode matrix with only wanted recovery rows
2549edac479SGreg Tucker for (i = 0; i < nerrs; i++) {
2559edac479SGreg Tucker if (frag_err_list[i] < k) // A src err
2569edac479SGreg Tucker for (j = 0; j < k; j++)
257*9d99f821SMarcel Cornu decode_matrix[k * i + j] = invert_matrix[k * frag_err_list[i] + j];
258041379a6SGreg Tucker }
259041379a6SGreg Tucker
260041379a6SGreg Tucker // For non-src (parity) erasures need to multiply encode matrix * invert
2619edac479SGreg Tucker for (p = 0; p < nerrs; p++) {
2629edac479SGreg Tucker if (frag_err_list[p] >= k) { // A parity err
263041379a6SGreg Tucker for (i = 0; i < k; i++) {
264041379a6SGreg Tucker s = 0;
265041379a6SGreg Tucker for (j = 0; j < k; j++)
266041379a6SGreg Tucker s ^= gf_mul(invert_matrix[j * k + i],
267041379a6SGreg Tucker encode_matrix[k * frag_err_list[p] + j]);
268041379a6SGreg Tucker decode_matrix[k * p + i] = s;
269041379a6SGreg Tucker }
270041379a6SGreg Tucker }
2719edac479SGreg Tucker }
272041379a6SGreg Tucker return 0;
273041379a6SGreg Tucker }
274