Line data Source code
1 : /*
2 : * vr_dpdk_flow_mem.c -- memory allocation for flow table
3 : *
4 : * Copyright(c) 2014, Juniper Networks Inc.,
5 : * Copyright Contributors to the OpenSDN project
6 : * All rights reserved
7 : */
8 :
9 : #include <stdint.h>
10 : #include <sys/types.h>
11 : #include <sys/mman.h>
12 : #include <sys/stat.h>
13 : #include <fcntl.h>
14 : #include <unistd.h>
15 :
16 : #include "vr_dpdk.h"
17 : #include "vr_btable.h"
18 : #include "vr_mem.h"
19 : #include "nl_util.h"
20 :
21 : #include <rte_errno.h>
22 :
23 : #define MAX_LINE_SIZE 256
24 : #define HPI_MAX 16
25 : #define MOUNT_TABLE "/proc/mounts"
26 :
27 : struct vr_hugepage_info {
28 : char *mnt;
29 : size_t page_size;
30 : size_t size;
31 : uint32_t num_pages;
32 : } vr_hugepage_md[HPI_MAX];
33 :
34 : extern void *vr_flow_table, *vr_oflow_table;
35 : extern void *vr_bridge_table, *vr_obridge_table;
36 : extern unsigned char *vr_flow_path, *vr_bridge_table_path;
37 : char flow_mem_file[VR_UNIX_PATH_MAX];
38 : char bridge_mem_file[VR_UNIX_PATH_MAX];
39 :
40 : static int
41 0 : vr_hugepage_info_init(void)
42 : {
43 0 : unsigned int i = 0, multiple = 1;
44 : char *str, *token;
45 :
46 : char *dev, *mnt, *fs, *options, *size;
47 : char *size_attr, *sys_hp_file;
48 0 : FILE *fp = NULL, *sys_fp = NULL;
49 : struct vr_hugepage_info *hp;
50 :
51 : char line[MAX_LINE_SIZE];
52 : char nr_pages[MAX_LINE_SIZE];
53 :
54 :
55 0 : fp = fopen(MOUNT_TABLE, "r");
56 0 : if (!fp)
57 0 : return -errno;
58 :
59 0 : while (fgets(line, MAX_LINE_SIZE, fp)) {
60 0 : if (i >= HPI_MAX)
61 0 : break;
62 :
63 0 : if ((str = strstr(line, "hugetlbfs"))) {
64 0 : hp = &vr_hugepage_md[i++];
65 0 : dev = strtok(line, " ");
66 0 : mnt = strtok(NULL, " ");
67 0 : fs = strtok(NULL, " ");
68 0 : options = strtok(NULL, " ");
69 :
70 : RTE_SET_USED(fs);
71 : RTE_SET_USED(dev);
72 : RTE_SET_USED(token);
73 :
74 0 : hp->mnt = malloc(strlen(mnt) + 1);
75 0 : memcpy(hp->mnt, mnt, strlen(mnt) + 1);
76 :
77 0 : if (strstr(options, "pagesize=1G") || strstr(options, "pagesize=1024M")) {
78 0 : hp->page_size = (1024 * 1024 * 1024);
79 0 : sys_hp_file =
80 : "/sys/kernel/mm/hugepages/hugepages-1048576kB/nr_hugepages";
81 : } else {
82 0 : hp->page_size = (2 * 1024 * 1024);
83 0 : sys_hp_file =
84 : "/sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages";
85 : }
86 :
87 0 : size = strstr(options, "size=");
88 0 : if (size && (size != options) && (*(size - 1) != ','))
89 0 : size = strstr(size + 1, "size=");
90 :
91 0 : if (size && ((size == options) || (*(size - 1) == ','))) {
92 0 : size += strlen("size=");
93 0 : size = strtok(size, ",");
94 0 : size_attr = size + strlen(size) - 1;
95 0 : switch (*size_attr) {
96 0 : case 'k':
97 : case 'K':
98 0 : multiple = 1024;
99 0 : *size_attr = '\0';
100 0 : break;
101 :
102 0 : case 'M':
103 : case 'm':
104 0 : multiple = 1024 * 1024;
105 0 : *size_attr = '\0';
106 0 : break;
107 :
108 0 : case 'G':
109 : case 'g':
110 0 : multiple = 1024 * 1024 * 1024;
111 0 : *size_attr = '\0';
112 0 : break;
113 : }
114 :
115 0 : hp->size = strtoul(size, NULL, 0) * multiple;
116 0 : hp->num_pages = hp->size / hp->page_size;
117 : } else {
118 0 : sys_fp = fopen(sys_hp_file, "r");
119 0 : if (!sys_fp)
120 0 : goto exit_func;
121 :
122 0 : str = fgets(nr_pages, MAX_LINE_SIZE, sys_fp);
123 0 : if (str == NULL)
124 0 : goto exit_func;
125 0 : hp->num_pages = strtoul(nr_pages, NULL, 0);
126 0 : hp->size = hp->num_pages * hp->page_size;
127 : }
128 :
129 : }
130 : }
131 :
132 0 : exit_func:
133 0 : if (fp)
134 0 : fclose(fp);
135 :
136 0 : if (sys_fp)
137 0 : fclose(sys_fp);
138 :
139 0 : return 0;
140 : }
141 :
142 :
143 : int
144 106 : vr_dpdk_table_mem_init(unsigned int table, unsigned int entries,
145 : unsigned long size, unsigned int oentries, unsigned long osize)
146 : {
147 : int ret, i, fd;
148 :
149 : void **table_p;
150 : char *shm_file;
151 106 : char *file_name, *touse_file_name = NULL;
152 : char *shmem_name, *hp_file_name;
153 : unsigned char **path;
154 :
155 : struct stat f_stat;
156 : struct vr_hugepage_info *hpi;
157 :
158 106 : if (!oentries) {
159 106 : oentries = (entries / 5 + 1023) & ~1023;
160 106 : osize = (size / entries) * oentries;
161 : }
162 :
163 106 : size += osize;
164 :
165 106 : switch (table) {
166 53 : case VR_MEM_FLOW_TABLE_OBJECT:
167 53 : shmem_name = "flow.shmem";
168 53 : hp_file_name = "flow";
169 53 : table_p = &vr_dpdk.flow_table;
170 53 : path = &vr_flow_path;
171 53 : vr_oflow_entries = oentries;
172 53 : shm_file = flow_mem_file;
173 53 : break;
174 :
175 53 : case VR_MEM_BRIDGE_TABLE_OBJECT:
176 53 : shmem_name = "bridge.shmem";
177 53 : hp_file_name = "bridge";
178 53 : table_p = &vr_dpdk.bridge_table;
179 53 : path = &vr_bridge_table_path;
180 53 : vr_bridge_oentries = oentries;
181 53 : shm_file = bridge_mem_file;
182 53 : break;
183 :
184 0 : default:
185 0 : return -EINVAL;
186 : }
187 :
188 106 : if (no_huge_set) {
189 : /* Create a shared memory under the socket directory. */
190 106 : ret = snprintf(shm_file, VR_UNIX_PATH_MAX, "%s/%s",
191 : vr_socket_dir, shmem_name);
192 106 : if (ret >= VR_UNIX_PATH_MAX) {
193 0 : RTE_LOG(ERR, VROUTER, "Error creating shared memory file\n");
194 0 : return -ENOMEM;
195 : }
196 106 : touse_file_name = shm_file;
197 : } else {
198 0 : ret = vr_hugepage_info_init();
199 0 : if (ret < 0) {
200 0 : RTE_LOG(ERR, VROUTER, "Error initializing hugepage info: %s (%d)\n",
201 : rte_strerror(-ret), -ret);
202 0 : return ret;
203 : }
204 :
205 0 : for (i = 0; i < HPI_MAX; i++) {
206 0 : hpi = &vr_hugepage_md[i];
207 0 : if (!hpi->mnt)
208 0 : continue;
209 0 : file_name = malloc(strlen(hpi->mnt) + strlen(hp_file_name) + 2);
210 0 : sprintf(file_name, "%s/%s", hpi->mnt, hp_file_name);
211 0 : if (stat(file_name, &f_stat) == -1) {
212 0 : if (!touse_file_name) {
213 0 : if (hpi->size >= size) {
214 0 : touse_file_name = file_name;
215 : } else {
216 0 : free(file_name);
217 : }
218 : }
219 : } else {
220 0 : free(touse_file_name);
221 0 : touse_file_name = file_name;
222 0 : break;
223 : }
224 : }
225 : }
226 :
227 106 : if (touse_file_name) {
228 106 : fd = open(touse_file_name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
229 106 : if (fd == -1) {
230 0 : RTE_LOG(ERR, VROUTER, "Error opening file \"%s\": %s (%d)\n",
231 : touse_file_name, rte_strerror(errno), errno);
232 0 : return -errno;
233 : }
234 :
235 106 : if (no_huge_set) {
236 106 : ret = ftruncate(fd, size);
237 106 : if (ret == -1) {
238 0 : RTE_LOG(ERR, VROUTER, "Error truncating file %s: %s (%d)\n",
239 : touse_file_name, rte_strerror(errno), errno);
240 0 : return -errno;
241 : }
242 : }
243 :
244 106 : *table_p = mmap(NULL, size, PROT_READ | PROT_WRITE,
245 : MAP_SHARED, fd, 0);
246 : /* the file descriptor is no longer needed */
247 106 : close(fd);
248 106 : if (*table_p == MAP_FAILED) {
249 0 : RTE_LOG(ERR, VROUTER, "Error mmapping file %s: %s (%d)\n",
250 : touse_file_name, rte_strerror(errno), errno);
251 0 : return -errno;
252 : }
253 106 : memset(*table_p, 0, size);
254 106 : *path = (unsigned char *)touse_file_name;
255 : }
256 :
257 106 : return 0;
258 : }
259 :
260 : int
261 53 : vr_dpdk_bridge_init(void)
262 : {
263 53 : if (!vr_dpdk.bridge_table)
264 0 : return -1;
265 :
266 53 : vr_bridge_table = vr_dpdk.bridge_table;
267 53 : vr_obridge_table = vr_dpdk.bridge_table + VR_BRIDGE_TABLE_SIZE;
268 :
269 53 : return 0;
270 : }
271 :
272 : int
273 53 : vr_dpdk_flow_init(void)
274 : {
275 53 : if (!vr_dpdk.flow_table)
276 0 : return -1;
277 :
278 53 : vr_flow_table = vr_dpdk.flow_table;
279 53 : vr_oflow_table = vr_dpdk.flow_table + VR_FLOW_TABLE_SIZE;
280 :
281 53 : if (!vr_flow_table)
282 0 : return -1;
283 :
284 53 : vr_flow_hold_limit = VR_DPDK_MAX_FLOW_TABLE_HOLD_COUNT;
285 53 : RTE_LOG(INFO, VROUTER, "Max HOLD flow entries set to %u\n",
286 : vr_flow_hold_limit);
287 :
288 53 : return 0;
289 : }
|