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