1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2023 Marvell.
3 */
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8
9 #include <cmdline_parse.h>
10 #include <cmdline_parse_num.h>
11 #include <cmdline_parse_string.h>
12 #include <cmdline_socket.h>
13 #include <rte_node_ip4_api.h>
14
15 #include "module_api.h"
16 #include "route_priv.h"
17
18 static const char
19 cmd_ipv4_lookup_help[] = "ipv4_lookup route add ipv4 <ip> netmask <mask> via <ip>";
20
21 struct ip4_route route4 = TAILQ_HEAD_INITIALIZER(route4);
22
23 void
route_ip4_list_clean(void)24 route_ip4_list_clean(void)
25 {
26 struct route_ipv4_config *route;
27
28 while (!TAILQ_EMPTY(&route4)) {
29 route = TAILQ_FIRST(&route4);
30 TAILQ_REMOVE(&route4, route, next);
31 }
32 }
33
34 static struct route_ipv4_config *
find_route4_entry(struct route_ipv4_config * route)35 find_route4_entry(struct route_ipv4_config *route)
36 {
37 struct route_ipv4_config *ipv4route;
38
39 TAILQ_FOREACH(ipv4route, &route4, next) {
40 if (!memcmp(ipv4route, route, sizeof(*route)))
41 return ipv4route;
42 }
43 return NULL;
44
45 }
46
47 static uint8_t
convert_netmask_to_depth(uint32_t netmask)48 convert_netmask_to_depth(uint32_t netmask)
49 {
50 uint8_t zerobits = 0;
51
52 while ((netmask & 0x1) == 0) {
53 netmask = netmask >> 1;
54 zerobits++;
55 }
56
57 return (32 - zerobits);
58 }
59
60 static int
route4_rewirte_table_update(struct route_ipv4_config * ipv4route)61 route4_rewirte_table_update(struct route_ipv4_config *ipv4route)
62 {
63 uint8_t depth;
64 int portid;
65
66 portid = ethdev_portid_by_ip4(ipv4route->via, ipv4route->netmask);
67 if (portid < 0) {
68 printf("Invalid portid found to install the route\n");
69 return portid;
70 }
71
72 depth = convert_netmask_to_depth(ipv4route->netmask);
73
74 return rte_node_ip4_route_add(ipv4route->ip, depth, portid,
75 RTE_NODE_IP4_LOOKUP_NEXT_REWRITE);
76 }
77
78 static int
route_ip4_add(struct route_ipv4_config * route)79 route_ip4_add(struct route_ipv4_config *route)
80 {
81 struct route_ipv4_config *ipv4route;
82 int rc = -EINVAL;
83
84 ipv4route = find_route4_entry(route);
85
86 if (!ipv4route) {
87 ipv4route = malloc(sizeof(struct route_ipv4_config));
88 if (!ipv4route)
89 return -ENOMEM;
90 } else {
91 return 0;
92 }
93
94 ipv4route->ip = route->ip;
95 ipv4route->netmask = route->netmask;
96 ipv4route->via = route->via;
97 ipv4route->is_used = true;
98
99 if (!graph_status_get())
100 goto exit;
101
102 rc = route4_rewirte_table_update(ipv4route);
103 if (rc)
104 goto free;
105
106 exit:
107 TAILQ_INSERT_TAIL(&route4, ipv4route, next);
108 return 0;
109 free:
110 free(ipv4route);
111 return rc;
112 }
113
114 int
route_ip4_add_to_lookup(void)115 route_ip4_add_to_lookup(void)
116 {
117 struct route_ipv4_config *route = NULL;
118 int rc = -EINVAL;
119
120 TAILQ_FOREACH(route, &route4, next) {
121 rc = route4_rewirte_table_update(route);
122 if (rc < 0)
123 return rc;
124 }
125
126 return 0;
127 }
128
129 void
cmd_help_ipv4_lookup_parsed(__rte_unused void * parsed_result,__rte_unused struct cmdline * cl,__rte_unused void * data)130 cmd_help_ipv4_lookup_parsed(__rte_unused void *parsed_result, __rte_unused struct cmdline *cl,
131 __rte_unused void *data)
132 {
133 size_t len;
134
135 len = strlen(conn->msg_out);
136 conn->msg_out += len;
137 snprintf(conn->msg_out, conn->msg_out_len_max, "\n%s\n%s\n",
138 "--------------------------- ipv4_lookup command help ---------------------------",
139 cmd_ipv4_lookup_help);
140
141 len = strlen(conn->msg_out);
142 conn->msg_out_len_max -= len;
143 }
144
145 void
cmd_ipv4_lookup_route_add_ipv4_parsed(void * parsed_result,__rte_unused struct cmdline * cl,void * data __rte_unused)146 cmd_ipv4_lookup_route_add_ipv4_parsed(void *parsed_result, __rte_unused struct cmdline *cl,
147 void *data __rte_unused)
148 {
149 struct cmd_ipv4_lookup_route_add_ipv4_result *res = parsed_result;
150 struct route_ipv4_config config;
151 int rc = -EINVAL;
152
153 config.ip = rte_be_to_cpu_32(res->ip.addr.ipv4.s_addr);
154 config.netmask = rte_be_to_cpu_32(res->mask.addr.ipv4.s_addr);
155 config.via = rte_be_to_cpu_32(res->via_ip.addr.ipv4.s_addr);
156
157 rc = route_ip4_add(&config);
158 if (rc < 0)
159 printf(MSG_CMD_FAIL, res->ipv4_lookup);
160 }
161