1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2022 Intel Corporation 3 */ 4 5 #include <stdio.h> 6 #include <stdint.h> 7 #include <errno.h> 8 #include <sys/socket.h> 9 10 #include "l3fwd.h" 11 #include "l3fwd_route.h" 12 13 static struct em_rule *em_route_base_v4; 14 static struct em_rule *em_route_base_v6; 15 16 enum { 17 CB_FLD_DST_ADDR, 18 CB_FLD_SRC_ADDR, 19 CB_FLD_DST_PORT, 20 CB_FLD_SRC_PORT, 21 CB_FLD_PROTO, 22 CB_FLD_IF_OUT, 23 CB_FLD_MAX 24 }; 25 26 static int 27 em_parse_v6_net(const char *in, uint8_t *v) 28 { 29 int32_t rc; 30 31 /* get address. */ 32 rc = inet_pton(AF_INET6, in, v); 33 if (rc != 1) 34 return -EINVAL; 35 36 return 0; 37 } 38 39 static int 40 em_parse_v6_rule(char *str, struct em_rule *v) 41 { 42 int i, rc; 43 char *s, *sp, *in[CB_FLD_MAX]; 44 static const char *dlm = " \t\n"; 45 int dim = CB_FLD_MAX; 46 s = str; 47 48 for (i = 0; i != dim; i++, s = NULL) { 49 in[i] = strtok_r(s, dlm, &sp); 50 if (in[i] == NULL) 51 return -EINVAL; 52 } 53 54 rc = em_parse_v6_net(in[CB_FLD_DST_ADDR], v->v6_key.ip_dst); 55 if (rc != 0) 56 return rc; 57 rc = em_parse_v6_net(in[CB_FLD_SRC_ADDR], v->v6_key.ip_src); 58 if (rc != 0) 59 return rc; 60 61 /* source port. */ 62 GET_CB_FIELD(in[CB_FLD_SRC_PORT], v->v6_key.port_src, 0, UINT16_MAX, 0); 63 /* destination port. */ 64 GET_CB_FIELD(in[CB_FLD_DST_PORT], v->v6_key.port_dst, 0, UINT16_MAX, 0); 65 /* protocol. */ 66 GET_CB_FIELD(in[CB_FLD_PROTO], v->v6_key.proto, 0, UINT8_MAX, 0); 67 /* out interface. */ 68 GET_CB_FIELD(in[CB_FLD_IF_OUT], v->if_out, 0, UINT8_MAX, 0); 69 70 return 0; 71 } 72 73 static int 74 em_parse_v4_rule(char *str, struct em_rule *v) 75 { 76 int i, rc; 77 char *s, *sp, *in[CB_FLD_MAX]; 78 static const char *dlm = " \t\n"; 79 int dim = CB_FLD_MAX; 80 s = str; 81 82 for (i = 0; i != dim; i++, s = NULL) { 83 in[i] = strtok_r(s, dlm, &sp); 84 if (in[i] == NULL) 85 return -EINVAL; 86 } 87 88 rc = inet_pton(AF_INET, in[CB_FLD_DST_ADDR], &(v->v4_key.ip_dst)); 89 v->v4_key.ip_dst = ntohl(v->v4_key.ip_dst); 90 if (rc != 1) 91 return rc; 92 93 rc = inet_pton(AF_INET, in[CB_FLD_SRC_ADDR], &(v->v4_key.ip_src)); 94 v->v4_key.ip_src = ntohl(v->v4_key.ip_src); 95 if (rc != 1) 96 return rc; 97 98 /* source port. */ 99 GET_CB_FIELD(in[CB_FLD_SRC_PORT], v->v4_key.port_src, 0, UINT16_MAX, 0); 100 /* destination port. */ 101 GET_CB_FIELD(in[CB_FLD_DST_PORT], v->v4_key.port_dst, 0, UINT16_MAX, 0); 102 /* protocol. */ 103 GET_CB_FIELD(in[CB_FLD_PROTO], v->v4_key.proto, 0, UINT8_MAX, 0); 104 /* out interface. */ 105 GET_CB_FIELD(in[CB_FLD_IF_OUT], v->if_out, 0, UINT8_MAX, 0); 106 107 return 0; 108 } 109 110 static int 111 em_add_rules(const char *rule_path, 112 struct em_rule **proute_base, 113 int (*parser)(char *, struct em_rule *)) 114 { 115 struct em_rule *route_rules; 116 struct em_rule *next; 117 unsigned int route_num = 0; 118 unsigned int route_cnt = 0; 119 char buff[LINE_MAX]; 120 FILE *fh; 121 unsigned int i = 0, rule_size = sizeof(*next); 122 int val; 123 124 *proute_base = NULL; 125 fh = fopen(rule_path, "rb"); 126 if (fh == NULL) 127 return -EINVAL; 128 129 while ((fgets(buff, LINE_MAX, fh) != NULL)) { 130 if (buff[0] == ROUTE_LEAD_CHAR) 131 route_num++; 132 } 133 134 if (route_num == 0) { 135 fclose(fh); 136 return -EINVAL; 137 } 138 139 val = fseek(fh, 0, SEEK_SET); 140 if (val < 0) { 141 fclose(fh); 142 return -EINVAL; 143 } 144 145 route_rules = calloc(route_num, rule_size); 146 147 if (route_rules == NULL) { 148 fclose(fh); 149 return -EINVAL; 150 } 151 152 i = 0; 153 while (fgets(buff, LINE_MAX, fh) != NULL) { 154 i++; 155 if (is_bypass_line(buff)) 156 continue; 157 158 char s = buff[0]; 159 160 /* Route entry */ 161 if (s == ROUTE_LEAD_CHAR) 162 next = &route_rules[route_cnt]; 163 164 /* Illegal line */ 165 else { 166 RTE_LOG(ERR, L3FWD, 167 "%s Line %u: should start with leading " 168 "char %c\n", 169 rule_path, i, ROUTE_LEAD_CHAR); 170 fclose(fh); 171 free(route_rules); 172 return -EINVAL; 173 } 174 175 if (parser(buff + 1, next) != 0) { 176 RTE_LOG(ERR, L3FWD, 177 "%s Line %u: parse rules error\n", 178 rule_path, i); 179 fclose(fh); 180 free(route_rules); 181 return -EINVAL; 182 } 183 184 route_cnt++; 185 } 186 187 fclose(fh); 188 189 *proute_base = route_rules; 190 191 return route_cnt; 192 } 193 194 static int 195 em_add_default_v4_rules(void) 196 { 197 /* populate the LPM IPv4 table */ 198 unsigned int i, rule_size = sizeof(*em_route_base_v4); 199 route_num_v4 = RTE_DIM(ipv4_l3fwd_em_route_array); 200 201 em_route_base_v4 = calloc(route_num_v4, rule_size); 202 203 for (i = 0; i < (unsigned int)route_num_v4; i++) { 204 em_route_base_v4[i].v4_key.ip_dst = ipv4_l3fwd_em_route_array[i].key.ip_dst; 205 em_route_base_v4[i].v4_key.ip_src = ipv4_l3fwd_em_route_array[i].key.ip_src; 206 em_route_base_v4[i].v4_key.port_dst = ipv4_l3fwd_em_route_array[i].key.port_dst; 207 em_route_base_v4[i].v4_key.port_src = ipv4_l3fwd_em_route_array[i].key.port_src; 208 em_route_base_v4[i].v4_key.proto = ipv4_l3fwd_em_route_array[i].key.proto; 209 em_route_base_v4[i].if_out = ipv4_l3fwd_em_route_array[i].if_out; 210 } 211 return 0; 212 } 213 214 static int 215 em_add_default_v6_rules(void) 216 { 217 /* populate the LPM IPv6 table */ 218 unsigned int i, rule_size = sizeof(*em_route_base_v6); 219 route_num_v6 = RTE_DIM(ipv6_l3fwd_em_route_array); 220 221 em_route_base_v6 = calloc(route_num_v6, rule_size); 222 223 for (i = 0; i < (unsigned int)route_num_v6; i++) { 224 memcpy(em_route_base_v6[i].v6_key.ip_dst, ipv6_l3fwd_em_route_array[i].key.ip_dst, 225 sizeof(em_route_base_v6[i].v6_key.ip_dst)); 226 memcpy(em_route_base_v6[i].v6_key.ip_src, ipv6_l3fwd_em_route_array[i].key.ip_src, 227 sizeof(em_route_base_v6[i].v6_key.ip_src)); 228 em_route_base_v6[i].v6_key.port_dst = ipv6_l3fwd_em_route_array[i].key.port_dst; 229 em_route_base_v6[i].v6_key.port_src = ipv6_l3fwd_em_route_array[i].key.port_src; 230 em_route_base_v6[i].v6_key.proto = ipv6_l3fwd_em_route_array[i].key.proto; 231 em_route_base_v6[i].if_out = ipv6_l3fwd_em_route_array[i].if_out; 232 } 233 return 0; 234 } 235 236 void 237 em_free_routes(void) 238 { 239 free(em_route_base_v4); 240 free(em_route_base_v6); 241 em_route_base_v4 = NULL; 242 em_route_base_v6 = NULL; 243 route_num_v4 = 0; 244 route_num_v6 = 0; 245 } 246 247 /* Load rules from the input file */ 248 void 249 read_config_files_em(void) 250 { 251 /* ipv4 check */ 252 if (parm_config.rule_ipv4_name != NULL && 253 parm_config.rule_ipv6_name != NULL) { 254 /* ipv4 check */ 255 route_num_v4 = em_add_rules(parm_config.rule_ipv4_name, 256 &em_route_base_v4, &em_parse_v4_rule); 257 if (route_num_v4 < 0) { 258 em_free_routes(); 259 rte_exit(EXIT_FAILURE, "Failed to add EM IPv4 rules\n"); 260 } 261 262 /* ipv6 check */ 263 route_num_v6 = em_add_rules(parm_config.rule_ipv6_name, 264 &em_route_base_v6, &em_parse_v6_rule); 265 if (route_num_v6 < 0) { 266 em_free_routes(); 267 rte_exit(EXIT_FAILURE, "Failed to add EM IPv6 rules\n"); 268 } 269 } else { 270 RTE_LOG(INFO, L3FWD, "Missing 1 or more rule files, using default instead\n"); 271 if (em_add_default_v4_rules() < 0) { 272 em_free_routes(); 273 rte_exit(EXIT_FAILURE, "Failed to add default IPv4 rules\n"); 274 } 275 if (em_add_default_v6_rules() < 0) { 276 em_free_routes(); 277 rte_exit(EXIT_FAILURE, "Failed to add default IPv6 rules\n"); 278 } 279 } 280 } 281