summaryrefslogtreecommitdiff
path: root/service/src/vdev.c
blob: 4591556506e0e33abaae3051a1a9428f23beba0f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
/*
 * \brief 虚拟设备管理器
 *
 * 虚拟设备,用于驱动与应用进行数据通信。驱动程序将从物理设备
 * 收取的报文,经过交换逻辑送入虚拟设备中,从而分发到各应用进行处理。
 *
 * \author Lu Qiuwen<[email protected]>
 * \date 2017-02-17
 *
 */

#include <MESA_prof_load.h>
#include <arpa/inet.h>
#include <assert.h>
#include <common.h>
#include <mr_rte_msg.h>
#include <rte_malloc.h>
#include <rte_pdump.h>
#include <rte_string_fns.h>
#include <sc_app.h>
#include <sc_common.h>
#include <sc_pdump.h>
#include <sc_vdev.h>
#include <sys/queue.h>
#include <vnode.h>

#ifndef VDEV_DEFAULT_SZ_BUFFER
#define VDEV_DEFAULT_SZ_BUFFER 32
#endif

#ifndef VDEV_DEFAULT_SZ_TUNNEL
#define VDEV_DEFAULT_SZ_TUNNEL 512
#endif

/* =========================================================================================== */

int vdev_iterate(struct vdev_main * v_main, struct vdev ** vdev_result, unsigned int * next)
{
    if (*next >= v_main->vdev_max_idx)
        return -ENOENT;
    else
        *vdev_result = &v_main->_vdev_array[(*next)++]->vdev;
    return 0;
}

struct vdev * vdev_lookup(struct vdev_main * v_main, const char * symbol)
{
    struct vdev * vdev = NULL;
    unsigned int next = 0;
    while (vdev_iterate(v_main, &vdev, &next) >= 0)
    {
        if (strncmp(vdev->symbol, symbol, sizeof(vdev->symbol)) != 0)
            continue;
        return vdev;
    }

    return NULL;
}

/* Datapath Functions */
int vdev_dispatch(struct vdev * vdev, queue_id_t qid, struct rte_mbuf * pkts[], unsigned int nr_pkts, int flags)
{
    struct _vdev * _vdev = container_of(vdev, struct _vdev, vdev);
    mr_pdump_tx(vdev->port_id, qid, pkts, nr_pkts);
    return vdev_data_dispatch(_vdev, qid, pkts, nr_pkts, flags);
}

int vdev_collect(struct vdev * vdev, queue_id_t qid, struct rte_mbuf * pkts[], unsigned int nr_pkts, int flags)
{
    struct _vdev * _vdev = container_of(vdev, struct _vdev, vdev);
    unsigned int rx_nr_mbufs = vdev_data_collect(_vdev, qid, pkts, nr_pkts, flags);
    mr_pdump_rx(vdev->port_id, qid, pkts, rx_nr_mbufs);
    return (int)rx_nr_mbufs;
}

int vdev_rt_pkts_retrieve(struct vdev * vdev, queue_id_t qid, struct rte_mbuf * pkts[], unsigned int nr_pkts)
{
    struct _vdev * _vdev = container_of(vdev, struct _vdev, vdev);
    return vdev_data_rt_pkts_retrieve(_vdev, qid, pkts, nr_pkts);
}

int vdev_idle_poll(struct vdev * vdev, queue_id_t qid)
{
    struct _vdev * _vdev = container_of(vdev, struct _vdev, vdev);
    return vdev_data_idle_poll(_vdev, qid);
}

int vdev_stats_get(struct vdev * vdev, struct vdev_stat_info * stat_info)
{
    struct _vdev * _vdev = container_of(vdev, struct _vdev, vdev);
    return vdev_data_stats_get(_vdev, stat_info);
}

void vdev_stats_last_save(struct vdev * vdev, struct vdev_stat_info * stat_info_last)
{
    struct _vdev * _vdev = container_of(vdev, struct _vdev, vdev);
    _vdev->stat_info_last = *stat_info_last;
}

void vdev_stats_last_get(struct vdev * vdev, struct vdev_stat_info * stat_info_last)
{
    struct _vdev * _vdev = container_of(vdev, struct _vdev, vdev);
    *stat_info_last = _vdev->stat_info_last;
}

static int vdev_instance_create_handler(const struct rte_mp_msg * msg, const void * peer)
{
    assert(msg->len_param == sizeof(struct ctrl_msg_vdev_open_request));
    struct ctrl_msg_vdev_open_request * msg_req = (struct ctrl_msg_vdev_open_request *)msg->param;

    /* prepare the response message */
    struct rte_mp_msg msg_rep = {};
    snprintf(msg_rep.name, sizeof(msg_rep.name), "%s", msg->name);
    msg_rep.len_param = sizeof(struct ctrl_msg_vdev_open_response);
    struct ctrl_msg_vdev_open_response * vdev_open_rep = (struct ctrl_msg_vdev_open_response *)msg_rep.param;

    /* app object and other handlers */
    struct app * app_object = app_lookup_by_symbol(sc_main_get(), (const char *)msg_req->appsym);
    assert(app_object != NULL);

    struct vdev_main * vdev_main = sc_main_get()->vdev_main;
    assert(vdev_main != NULL);

    struct vdev * vdev = vdev_lookup(vdev_main, (char *)msg_req->devsym);
    if (vdev == NULL)
    {
        MR_WARNING("invalid vdi request: from %s, device %s is not existed", app_object->symbol,
                   (char *)msg_req->devsym);

        vdev_open_rep->errcode = ENODEV;
        goto out;
    }

    /* Verify the vdev usage status */
    if (vdev->in_use == VDEV_IN_USE)
    {
        MR_WARNING("invalid vdi request: from %s, device %s is already in use", app_object->symbol,
                   (char *)msg_req->devsym);

        vdev_open_rep->errcode = EBUSY;
        goto out;
    }

    struct _vdev * _vdev = container_of(vdev, struct _vdev, vdev);
    struct vdev_instance * vdi =
        vdev_data_instance_create(_vdev, app_object->symbol, msg_req->nr_rxstream, msg_req->nr_txstream);

    if (vdi == NULL)
    {
        MR_ERROR("Create vdev instance %s for app %s failed. ", (char *)msg_req->devsym, app_object->symbol);
        vdev_open_rep->errcode = ENOMEM;
        goto out;
    }

    /* get the notify structure, and transfer the eventfd used in app */
    struct vnode_cons_notify * notify_ctx = vnode_mirror_notify_ctx_cons(vdi->vnode_rx_cons);
    msg_rep.num_fds = msg_req->nr_rxstream;
    for (unsigned int i = 0; i < msg_req->nr_rxstream; i++)
    {
        msg_rep.fds[i] = notify_ctx[i].cons_notify_eventfd;
    }

    /* VDI申请成功 */
    vdev_open_rep->ptr_vdi = (uint64_t)vdi;
    vdev_open_rep->nr_rxstream = msg_req->nr_rxstream;
    vdev_open_rep->nr_txstream = msg_req->nr_txstream;
    snprintf((char *)vdev_open_rep->devsym, sizeof(vdev_open_rep->devsym) - 1, "%s", vdev->symbol);

    if (vdev->link_status == LINK_DOWN)
    {
        vdev->link_status = LINK_UP;
        MR_INFO("shmdev %s link status is up. ", vdev->symbol);
    }

    /* Mark the vdev as in use */
    vdev->in_use = VDEV_IN_USE;

    struct vdev_main_pme * vdev_main_pme = (struct vdev_main_pme *)app_object->pme_vdev_main;
    TAILQ_INSERT_TAIL(&vdev_main_pme->vdi_list, vdi, next);

out:
    rte_mp_reply(&msg_rep, peer);
    return 0;
}

static void shmdev_event_handler_app_register(struct app_main * app_main, struct app * app, void * arg)
{
    app->pme_vdev_main = ZMALLOC(sizeof(struct vdev_main_pme));
    MR_VERIFY_MALLOC(app->pme_vdev_main);

    struct vdev_main_pme * vdev_main_pme = (struct vdev_main_pme *)app->pme_vdev_main;
    TAILQ_INIT(&vdev_main_pme->vdi_list);
}

static void shmdev_event_handler_app_unregister(struct app_main * app_main, struct app * app, void * arg)
{
    struct vdev_instance * vdi;
    struct vdev_main_pme * vdev_main_pme = (struct vdev_main_pme *)app->pme_vdev_main;

    if (vdev_main_pme == NULL)
        return;

    while (!TAILQ_EMPTY(&vdev_main_pme->vdi_list))
    {
        vdi = TAILQ_FIRST(&vdev_main_pme->vdi_list);
        TAILQ_REMOVE(&vdev_main_pme->vdi_list, vdi, next);

        if (vdi->vdev->link_status == LINK_UP)
        {
            vdi->vdev->link_status = LINK_DOWN;
            MR_INFO("shmdev %s link status is down. ", vdi->vdev->symbol);
        }

        /* Mark the vdev as not in use */
        vdi->vdev->in_use = VDEV_NOT_IN_USE;
        vdev_data_instance_destory(vdi);
    }

    FREE(vdev_main_pme);
}

int vdev_main_init(struct sc_main * sc)
{
    sc->vdev_main = ZMALLOC(sizeof(struct vdev_main));
    MR_VERIFY_MALLOC(sc->vdev_main);

    rte_mp_action_register("vdev_instance_request", vdev_instance_create_handler);

    /* 注册应用注册、反注册处理函数,主要用于释放资源 */
    app_event_handler_register(sc->app_main, APP_EV_TYPE_REGISTER, shmdev_event_handler_app_register, sc->vdev_main);
    app_event_handler_register(sc->app_main, APP_EV_TYPE_UNREGISTER, shmdev_event_handler_app_unregister,
                               sc->vdev_main);

    return RT_SUCCESS;
}

int vdev_dump(struct sc_main * sc)
{
    MR_INFO("\n");

    for (int i = 0; i < sc->vdev_main->vdev_max_idx; i++)
    {
        struct _vdev * _vdev_iter = sc->vdev_main->_vdev_array[i];
        char str_vdev_info[2048];

        int len = snprintf(str_vdev_info, sizeof(str_vdev_info),
                           "virtual device, name=%s, rx_thread_count=%d, tx_thread_count=%d, rx_ring_size=%d, "
                           "tx_ring_size=%d, max_inflight=%d",
                           _vdev_iter->vdev.symbol, _vdev_iter->nr_rxstream, _vdev_iter->nr_txstream,
                           _vdev_iter->sz_rx_tunnel, _vdev_iter->sz_tx_tunnel, _vdev_iter->sz_max_inflight);

        /* IP地址没有配置,忽略IP类信息的输出 */
        if (_vdev_iter->vdev.in_addr.s_addr != 0)
        {
            snprintf(str_vdev_info + len, sizeof(str_vdev_info) - len, ", ip_addr=%s, subnet_mask=%s, gateway=%s",
                     inet_ntoa(_vdev_iter->vdev.in_addr), inet_ntoa(_vdev_iter->vdev.in_addr),
                     inet_ntoa(_vdev_iter->vdev.in_gateway));
        }

        MR_INFO("%s", str_vdev_info);
    }

    return 0;
}