1 /*- 2 * BSD LICENSE 3 * 4 * Copyright(c) 2016 Intel Corporation. All rights reserved. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 /* 35 * Routing Table (RT) 36 */ 37 #include <sys/types.h> 38 #include <rte_lpm.h> 39 #include <rte_lpm6.h> 40 #include <rte_errno.h> 41 #include <rte_ip.h> 42 43 #include "ipsec.h" 44 #include "parser.h" 45 46 #define RT_IPV4_MAX_RULES 1024 47 #define RT_IPV6_MAX_RULES 1024 48 49 struct ip4_route { 50 uint32_t ip; 51 uint8_t depth; 52 uint8_t if_out; 53 }; 54 55 struct ip6_route { 56 uint8_t ip[16]; 57 uint8_t depth; 58 uint8_t if_out; 59 }; 60 61 struct ip4_route rt_ip4[RT_IPV4_MAX_RULES]; 62 uint32_t nb_rt_ip4; 63 64 struct ip6_route rt_ip6[RT_IPV4_MAX_RULES]; 65 uint32_t nb_rt_ip6; 66 67 void 68 parse_rt_tokens(char **tokens, uint32_t n_tokens, 69 struct parse_status *status) 70 { 71 uint32_t ti; 72 uint32_t *n_rts = NULL; 73 struct ip4_route *route_ipv4 = NULL; 74 struct ip6_route *route_ipv6 = NULL; 75 76 if (strcmp(tokens[0], "ipv4") == 0) { 77 n_rts = &nb_rt_ip4; 78 route_ipv4 = &rt_ip4[*n_rts]; 79 80 APP_CHECK(*n_rts <= RT_IPV4_MAX_RULES - 1, status, 81 "too many rt rules, abort insertion\n"); 82 if (status->status < 0) 83 return; 84 85 } else if (strcmp(tokens[0], "ipv6") == 0) { 86 n_rts = &nb_rt_ip6; 87 route_ipv6 = &rt_ip6[*n_rts]; 88 89 APP_CHECK(*n_rts <= RT_IPV6_MAX_RULES - 1, status, 90 "too many rt rules, abort insertion\n"); 91 if (status->status < 0) 92 return; 93 } else { 94 APP_CHECK(0, status, "unrecognized input \"%s\"", 95 tokens[0]); 96 return; 97 } 98 99 for (ti = 1; ti < n_tokens; ti++) { 100 if (strcmp(tokens[ti], "dst") == 0) { 101 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 102 if (status->status < 0) 103 return; 104 105 if (route_ipv4 != NULL) { 106 struct in_addr ip; 107 uint32_t depth = 0; 108 109 APP_CHECK(parse_ipv4_addr(tokens[ti], 110 &ip, &depth) == 0, status, 111 "unrecognized input \"%s\", " 112 "expect valid ipv4 addr", 113 tokens[ti]); 114 if (status->status < 0) 115 return; 116 route_ipv4->ip = rte_bswap32( 117 (uint32_t)ip.s_addr); 118 route_ipv4->depth = (uint8_t)depth; 119 } else { 120 struct in6_addr ip; 121 uint32_t depth; 122 123 APP_CHECK(parse_ipv6_addr(tokens[ti], 124 &ip, &depth) == 0, status, 125 "unrecognized input \"%s\", " 126 "expect valid ipv6 address", 127 tokens[ti]); 128 if (status->status < 0) 129 return; 130 memcpy(route_ipv6->ip, ip.s6_addr, 16); 131 route_ipv6->depth = (uint8_t)depth; 132 } 133 } 134 135 if (strcmp(tokens[ti], "port") == 0) { 136 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 137 if (status->status < 0) 138 return; 139 APP_CHECK_TOKEN_IS_NUM(tokens, ti, status); 140 if (status->status < 0) 141 return; 142 if (route_ipv4 != NULL) 143 route_ipv4->if_out = atoi(tokens[ti]); 144 else 145 route_ipv6->if_out = atoi(tokens[ti]); 146 } 147 } 148 149 *n_rts = *n_rts + 1; 150 } 151 152 void 153 rt_init(struct socket_ctx *ctx, int32_t socket_id) 154 { 155 char name[PATH_MAX]; 156 uint32_t i; 157 int32_t ret; 158 struct rte_lpm *lpm; 159 struct rte_lpm6 *lpm6; 160 char a, b, c, d; 161 struct rte_lpm_config conf = { 0 }; 162 struct rte_lpm6_config conf6 = { 0 }; 163 164 if (ctx == NULL) 165 rte_exit(EXIT_FAILURE, "NULL context.\n"); 166 167 if (ctx->rt_ip4 != NULL) 168 rte_exit(EXIT_FAILURE, "IPv4 Routing Table for socket %u " 169 "already initialized\n", socket_id); 170 171 if (ctx->rt_ip6 != NULL) 172 rte_exit(EXIT_FAILURE, "IPv6 Routing Table for socket %u " 173 "already initialized\n", socket_id); 174 175 if (nb_rt_ip4 == 0 && nb_rt_ip6 == 0) 176 RTE_LOG(WARNING, IPSEC, "No Routing rule specified\n"); 177 178 printf("Creating IPv4 Routing Table (RT) context with %u max routes\n", 179 RT_IPV4_MAX_RULES); 180 181 /* create the LPM table */ 182 snprintf(name, sizeof(name), "%s_%u", "rt_ip4", socket_id); 183 conf.max_rules = RT_IPV4_MAX_RULES; 184 conf.number_tbl8s = RTE_LPM_TBL8_NUM_ENTRIES; 185 lpm = rte_lpm_create(name, socket_id, &conf); 186 if (lpm == NULL) 187 rte_exit(EXIT_FAILURE, "Unable to create %s LPM table " 188 "on socket %d\n", name, socket_id); 189 190 /* populate the LPM table */ 191 for (i = 0; i < nb_rt_ip4; i++) { 192 ret = rte_lpm_add(lpm, rt_ip4[i].ip, rt_ip4[i].depth, 193 rt_ip4[i].if_out); 194 if (ret < 0) 195 rte_exit(EXIT_FAILURE, "Fail to add entry num %u to %s " 196 "LPM table on socket %d\n", i, name, socket_id); 197 198 uint32_t_to_char(rt_ip4[i].ip, &a, &b, &c, &d); 199 printf("LPM: Adding route %hhu.%hhu.%hhu.%hhu/%hhu (%hhu)\n", 200 a, b, c, d, rt_ip4[i].depth, 201 rt_ip4[i].if_out); 202 } 203 204 snprintf(name, sizeof(name), "%s_%u", "rt_ip6", socket_id); 205 conf6.max_rules = RT_IPV6_MAX_RULES; 206 conf6.number_tbl8s = RTE_LPM_TBL8_NUM_ENTRIES; 207 lpm6 = rte_lpm6_create(name, socket_id, &conf6); 208 if (lpm6 == NULL) 209 rte_exit(EXIT_FAILURE, "Unable to create %s LPM table " 210 "on socket %d\n", name, socket_id); 211 212 /* populate the LPM table */ 213 for (i = 0; i < nb_rt_ip6; i++) { 214 ret = rte_lpm6_add(lpm6, rt_ip6[i].ip, rt_ip6[i].depth, 215 rt_ip6[i].if_out); 216 if (ret < 0) 217 rte_exit(EXIT_FAILURE, "Fail to add entry num %u to %s " 218 "LPM table on socket %d\n", i, name, socket_id); 219 220 printf("LPM6: Adding route " 221 " %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx/%hhx (%hhx)\n", 222 (uint16_t)((rt_ip6[i].ip[0] << 8) | rt_ip6[i].ip[1]), 223 (uint16_t)((rt_ip6[i].ip[2] << 8) | rt_ip6[i].ip[3]), 224 (uint16_t)((rt_ip6[i].ip[4] << 8) | rt_ip6[i].ip[5]), 225 (uint16_t)((rt_ip6[i].ip[6] << 8) | rt_ip6[i].ip[7]), 226 (uint16_t)((rt_ip6[i].ip[8] << 8) | rt_ip6[i].ip[9]), 227 (uint16_t)((rt_ip6[i].ip[10] << 8) | rt_ip6[i].ip[11]), 228 (uint16_t)((rt_ip6[i].ip[12] << 8) | rt_ip6[i].ip[13]), 229 (uint16_t)((rt_ip6[i].ip[14] << 8) | rt_ip6[i].ip[15]), 230 rt_ip6[i].depth, rt_ip6[i].if_out); 231 } 232 233 ctx->rt_ip4 = (struct rt_ctx *)lpm; 234 ctx->rt_ip6 = (struct rt_ctx *)lpm6; 235 } 236