Line data Source code
1 : /*
2 : * vr_vxlan.c -- VXLAN encapsulation handling
3 : *
4 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
5 : * Copyright Contributors to the OpenSDN project
6 : */
7 : #include <vr_os.h>
8 : #include <vr_types.h>
9 : #include <vr_packet.h>
10 : #include "vr_interface.h"
11 : #include "vr_message.h"
12 : #include "vr_sandesh.h"
13 : #include "vr_vxlan.h"
14 : #include "vr_bridge.h"
15 : #include "vr_datapath.h"
16 : #include "vr_offloads_dp.h"
17 :
18 : int
19 1 : vr_vxlan_input(struct vrouter *router, struct vr_packet *pkt,
20 : struct vr_forwarding_md *fmd)
21 : {
22 : struct vr_vxlan *vxlan;
23 : unsigned int vnid, drop_reason;
24 : unsigned int flags;
25 : struct vr_nexthop *nh;
26 : struct vr_forwarding_md c_fmd;
27 : struct vr_ip *ip;
28 :
29 1 : if (!fmd) {
30 0 : vr_init_forwarding_md(&c_fmd);
31 0 : fmd = &c_fmd;
32 : }
33 :
34 1 : ip = (struct vr_ip *)pkt_network_header(pkt);
35 1 : fmd->fmd_outer_src_ip = ip->ip_saddr;
36 :
37 1 : vxlan = (struct vr_vxlan *)pkt_data(pkt);
38 1 : flags = ntohl(vxlan->vxlan_flags);
39 1 : if (!(flags & VR_VXLAN_IBIT)) {
40 0 : drop_reason = VP_DROP_INVALID_VNID;
41 0 : PKT_LOG(drop_reason, pkt, 0, VR_VXLAN_C, __LINE__);
42 0 : goto fail;
43 : }
44 1 : if (!fmd->fmd_fe) {
45 1 : vnid = ntohl(vxlan->vxlan_vnid) >> VR_VXLAN_VNID_SHIFT;
46 1 : if (!pkt_pull(pkt, sizeof(struct vr_vxlan))) {
47 0 : drop_reason = VP_DROP_PULL;
48 0 : PKT_LOG(drop_reason, pkt, 0, VR_VXLAN_C, __LINE__);
49 0 : goto fail;
50 : }
51 :
52 1 : nh = (struct vr_nexthop *)vr_itable_get(router->vr_vxlan_table, vnid);
53 1 : if (!nh) {
54 0 : drop_reason = VP_DROP_INVALID_VNID;
55 0 : PKT_LOG(drop_reason, pkt, 0, VR_VXLAN_C, __LINE__);
56 0 : goto fail;
57 : }
58 : } else {
59 0 : vnid = fmd->fmd_label;
60 0 : nh = pkt->vp_nh;
61 : }
62 :
63 1 : vr_fmd_set_label(fmd, vnid, VR_LABEL_TYPE_VXLAN_ID);
64 :
65 1 : fmd->fmd_vlan = VLAN_ID_INVALID;
66 :
67 1 : if (vr_pkt_type(pkt, 0, fmd) < 0) {
68 0 : drop_reason = VP_DROP_INVALID_PACKET;
69 0 : PKT_LOG(drop_reason, pkt, 0, VR_VXLAN_C, __LINE__);
70 0 : goto fail;
71 : }
72 :
73 1 : if (nh->nh_vrf >= 0) {
74 1 : fmd->fmd_dvrf = nh->nh_vrf;
75 0 : } else if (nh->nh_dev) {
76 0 : fmd->fmd_dvrf = nh->nh_dev->vif_vrf;
77 : } else {
78 0 : fmd->fmd_dvrf = pkt->vp_if->vif_vrf;
79 : }
80 :
81 1 : if (flags & VR_VXLAN_RABIT) {
82 0 : vr_trap(pkt, fmd->fmd_dvrf, AGENT_TRAP_ROUTER_ALERT, NULL);
83 0 : return 0;
84 : }
85 :
86 1 : if (vr_perfr)
87 1 : vr_pkt_set_gro(pkt);
88 :
89 1 : return nh_output(pkt, nh, fmd);
90 :
91 0 : fail:
92 0 : vr_pfree(pkt, drop_reason);
93 0 : return 0;
94 : }
95 :
96 : static void
97 1 : vr_vxlan_make_req(vr_vxlan_req *req, struct vr_nexthop *nh, unsigned int vnid)
98 : {
99 1 : memset(req, 0, sizeof(*req));
100 1 : req->vxlanr_vnid = vnid;
101 1 : if (nh)
102 1 : req->vxlanr_nhid = nh->nh_id;
103 : /* Debug comparison to check if matching entry is programmed on NIC */
104 1 : vr_offload_vxlan_get(req);
105 1 : return;
106 : }
107 :
108 : static int
109 0 : vr_vxlan_trav_cb(unsigned int index, void *data, void *udata)
110 : {
111 0 : struct vr_nexthop *nh = (struct vr_nexthop *)data;
112 0 : struct vr_message_dumper *dumper = (struct vr_message_dumper *)udata;
113 : vr_vxlan_req resp;
114 :
115 0 : vr_vxlan_make_req(&resp, nh, index);
116 0 : return vr_message_dump_object(dumper, VR_VXLAN_OBJECT_ID, &resp);
117 : }
118 :
119 : static int
120 0 : vr_vxlan_dump(vr_vxlan_req *req)
121 : {
122 : int ret;
123 0 : struct vr_message_dumper *dumper = NULL;
124 0 : struct vrouter *router = vrouter_get(req->vxlanr_rid);
125 : unsigned int index;
126 :
127 0 : if (!router && (ret = -ENODEV))
128 0 : goto generate_response;
129 :
130 0 : dumper = vr_message_dump_init(req);
131 0 : if (!dumper && (ret = -ENOMEM))
132 0 : goto generate_response;
133 :
134 0 : index = req->vxlanr_vnid;
135 0 : if (index)
136 0 : index++;
137 :
138 0 : ret = vr_itable_trav(router->vr_vxlan_table, vr_vxlan_trav_cb, index, dumper);
139 :
140 0 : generate_response:
141 0 : vr_message_dump_exit(dumper, ret);
142 0 : return 0;
143 : }
144 :
145 : static int
146 1 : vr_vxlan_get(vr_vxlan_req *req)
147 : {
148 1 : int ret = 0;
149 1 : struct vr_nexthop *nh = NULL;
150 : struct vrouter *router;
151 :
152 1 : router = vrouter_get(req->vxlanr_rid);
153 1 : if (!router) {
154 0 : ret = -ENODEV;
155 : } else {
156 1 : nh = (struct vr_nexthop *)vr_itable_get(router->vr_vxlan_table,
157 1 : req->vxlanr_vnid);
158 1 : if (!nh)
159 0 : ret = -ENOENT;
160 : }
161 :
162 1 : if (!ret)
163 1 : vr_vxlan_make_req(req, nh, req->vxlanr_vnid);
164 : else
165 0 : req = NULL;
166 :
167 1 : vr_message_response(VR_VXLAN_OBJECT_ID, req, ret, false);
168 :
169 1 : return 0;
170 : }
171 :
172 : static int
173 2 : vr_vxlan_del(vr_vxlan_req *req)
174 : {
175 : struct vrouter *router;
176 : struct vr_nexthop *nh;
177 2 : int ret = 0;
178 :
179 2 : router = vrouter_get(req->vxlanr_rid);
180 2 : if (!router) {
181 0 : ret = -EINVAL;
182 0 : goto generate_resp;
183 : }
184 :
185 : /* notify hw offload of change, if enabled */
186 2 : vr_offload_vxlan_del(req->vxlanr_vnid);
187 :
188 2 : nh = vr_itable_del(router->vr_vxlan_table, req->vxlanr_vnid);
189 2 : if (nh)
190 2 : vrouter_put_nexthop(nh);
191 :
192 0 : generate_resp:
193 2 : vr_send_response(ret);
194 2 : return ret;
195 : }
196 :
197 : static int
198 2 : vr_vxlan_add(vr_vxlan_req *req)
199 : {
200 : struct vrouter *router;
201 : struct vr_nexthop *nh, *nh_old;
202 2 : int ret = 0;
203 :
204 2 : router = vrouter_get(req->vxlanr_rid);
205 2 : if (!router) {
206 0 : ret = -EINVAL;
207 0 : goto generate_resp;
208 : }
209 :
210 2 : nh = vrouter_get_nexthop(req->vxlanr_rid, req->vxlanr_nhid);
211 2 : if (!nh) {
212 0 : ret = -EINVAL;
213 0 : goto generate_resp;
214 : }
215 :
216 2 : nh_old = vr_itable_set(router->vr_vxlan_table, req->vxlanr_vnid, nh);
217 :
218 2 : ret = vr_offload_vxlan_add(nh, req->vxlanr_vnid);
219 2 : if (ret) {
220 : /* If offload add fails, restore old nexthop */
221 0 : if (nh_old && nh_old != VR_ITABLE_ERR_PTR)
222 0 : vr_itable_set(router->vr_vxlan_table, req->vxlanr_vnid, nh_old);
223 : else
224 0 : vr_itable_del(router->vr_vxlan_table, req->vxlanr_vnid);
225 0 : vrouter_put_nexthop(nh);
226 0 : goto generate_resp;
227 : }
228 :
229 2 : if (nh_old) {
230 0 : if (nh_old == VR_ITABLE_ERR_PTR) {
231 0 : ret = -EINVAL;
232 : } else {
233 : /* If there is any old nexthop, remove the reference */
234 0 : vrouter_put_nexthop(nh_old);
235 : }
236 : }
237 :
238 2 : generate_resp:
239 2 : vr_send_response(ret);
240 2 : return ret;
241 : }
242 :
243 : void
244 5 : vr_vxlan_req_process(void *s_req)
245 : {
246 5 : vr_vxlan_req *req = (vr_vxlan_req *)s_req;
247 :
248 5 : switch(req->h_op) {
249 2 : case SANDESH_OP_ADD:
250 2 : vr_vxlan_add(req);
251 2 : break;
252 :
253 1 : case SANDESH_OP_GET:
254 1 : vr_vxlan_get(req);
255 1 : break;
256 :
257 0 : case SANDESH_OP_DUMP:
258 0 : vr_vxlan_dump(req);
259 0 : break;
260 :
261 2 : case SANDESH_OP_DEL:
262 2 : vr_vxlan_del(req);
263 2 : break;
264 :
265 0 : default:
266 0 : break;
267 : }
268 :
269 5 : return;
270 : }
271 :
272 : static void
273 0 : vr_vxlan_destroy(unsigned int index, void *arg)
274 : {
275 0 : struct vr_nexthop *nh = (struct vr_nexthop *)arg;
276 :
277 0 : if (nh && nh != VR_ITABLE_ERR_PTR) {
278 0 : vrouter_put_nexthop(nh);
279 : }
280 :
281 0 : return;
282 : }
283 :
284 : void
285 53 : vr_vxlan_exit(struct vrouter *router, bool soft_reset)
286 : {
287 : /* Delete the complete index table, irrespective of soft_reset */
288 53 : vr_itable_delete(router->vr_vxlan_table, vr_vxlan_destroy);
289 53 : router->vr_vxlan_table = NULL;
290 53 : }
291 :
292 : int
293 53 : vr_vxlan_init(struct vrouter *router)
294 : {
295 : /* Create an index table with two strides of 12 bits each */
296 53 : if (!router->vr_vxlan_table) {
297 53 : router->vr_vxlan_table = vr_itable_create(24, 2, 12, 12);
298 53 : if (!router->vr_vxlan_table) {
299 0 : vr_module_error(-ENOMEM, __FUNCTION__, __LINE__, 0);
300 0 : return -ENOMEM;
301 : }
302 : }
303 53 : return 0;
304 : }
|