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