Prepare for DPDK 19.08 support
[samplevnf.git] / VNFs / DPPD-PROX / genl4_stream_udp.c
1 /*
2 // Copyright (c) 2010-2017 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16
17 #include "genl4_stream_udp.h"
18 #include "mbuf_utils.h"
19
20 int stream_udp_is_ended(struct stream_ctx *ctx)
21 {
22         return ctx->cur_action == ctx->stream_cfg->n_actions;
23 }
24
25 static void update_token_times(struct stream_ctx *ctx)
26 {
27         uint64_t now = rte_rdtsc();
28
29         token_time_update(&ctx->token_time_other, now);
30         token_time_update(&ctx->token_time, now);
31 }
32
33 int stream_udp_proc(struct stream_ctx *ctx, struct rte_mbuf *mbuf, struct l4_meta *l4_meta, uint64_t *next_tsc)
34 {
35         update_token_times(ctx);
36
37         if (l4_meta) {
38                 enum l4gen_peer peer = ctx->stream_cfg->actions[ctx->cur_action].peer;
39                 plogx_dbg("Consuming UDP data\n");
40                 /* data should come from the other side */
41                 if (peer == ctx->peer) {
42                         plogx_err("Wrong peer\n");
43                         return -1;
44                 }
45                 /* Fixed length data expected */
46                 if (ctx->stream_cfg->actions[ctx->cur_action].len != l4_meta->len) {
47                         plogx_dbg("unexpected UDP len (expected = %u, got = %u, action = %u)\n",
48                                   ctx->stream_cfg->actions[ctx->cur_action].len,
49                                   l4_meta->len,
50                                   ctx->cur_action);
51
52                         return -1;
53                 }
54                 /* With specific payload */
55                 if (memcmp(ctx->stream_cfg->data[peer].content + ctx->stream_cfg->actions[ctx->cur_action].beg, l4_meta->payload, l4_meta->len) != 0) {
56                         plogx_dbg("Bad payload at action_id %d, with peer = %d and pos = %d and len=%d\n", ctx->cur_action, peer, ctx->cur_pos[peer], l4_meta->len);
57                         return -1;
58                 }
59                 ctx->cur_pos[peer] += l4_meta->len;
60                 ctx->cur_action++;
61
62                 if (stream_udp_is_ended(ctx))
63                         return -1;
64
65                 token_time_take(&ctx->token_time_other, mbuf_wire_size(mbuf));
66                 /* Time before next packet is expected to
67                    arrive. Note, addition amount of time is accounted
68                    for due to rate limiting. */
69                 uint64_t wait = token_time_tsc_until_full(&ctx->token_time_other);
70                 *next_tsc = wait + ctx->stream_cfg->tsc_timeout;
71         }
72
73         if (ctx->stream_cfg->actions[ctx->cur_action].peer != ctx->peer) {
74                 const char *other_peer_str = ctx->peer != PEER_SERVER? "server" : "client";
75
76                 plogx_dbg("Expecting more UDP data from %s, will expire = %s\n", other_peer_str, l4_meta == NULL? "yes" : "no");
77                 if (!l4_meta) {
78                         ctx->flags |= STREAM_CTX_F_EXPIRED;
79                 }
80                 return -1;
81         }
82
83         uint64_t wait_tsc = token_time_tsc_until_full(&ctx->token_time);
84
85         if (wait_tsc != 0) {
86                 plogx_dbg("Wait = %"PRIu64"\n", wait_tsc);
87                 *next_tsc = wait_tsc;
88                 return -1;
89         }
90
91         const struct stream_cfg *stream_cfg = ctx->stream_cfg;
92
93         uint8_t *pkt = rte_pktmbuf_mtod(mbuf, uint8_t *);
94         const struct peer_action *act = &stream_cfg->actions[ctx->cur_action];
95
96         uint16_t pkt_len = stream_cfg->data[act->peer].hdr_len + sizeof(prox_rte_udp_hdr) + act->len;
97
98         rte_pktmbuf_pkt_len(mbuf) = pkt_len;
99         rte_pktmbuf_data_len(mbuf) = pkt_len;
100         plogx_dbg("Creating UDP data (peer = %s, payload len = %u)\n", act->peer == PEER_CLIENT? "client" : "server", act->len);
101         /* Construct the packet. The template is used up to L4 header,
102            a gap of sizeof(l4_hdr) is skipped, followed by the payload. */
103         rte_memcpy(pkt, stream_cfg->data[act->peer].hdr, stream_cfg->data[act->peer].hdr_len);
104         rte_memcpy(pkt + stream_cfg->data[act->peer].hdr_len + sizeof(prox_rte_udp_hdr), stream_cfg->data[act->peer].content + act->beg, act->len);
105
106         prox_rte_ipv4_hdr *l3_hdr = (prox_rte_ipv4_hdr*)&pkt[stream_cfg->data[act->peer].hdr_len - sizeof(prox_rte_ipv4_hdr)];
107         prox_rte_udp_hdr *l4_hdr = (prox_rte_udp_hdr*)&pkt[stream_cfg->data[act->peer].hdr_len];
108
109         l3_hdr->src_addr = ctx->tuple->dst_addr;
110         l3_hdr->dst_addr = ctx->tuple->src_addr;
111         l3_hdr->next_proto_id = IPPROTO_UDP;
112         l4_hdr->src_port = ctx->tuple->dst_port;
113         l4_hdr->dst_port = ctx->tuple->src_port;
114         l4_hdr->dgram_len = rte_bswap16(sizeof(prox_rte_udp_hdr) + act->len);
115         /* TODO: UDP checksum calculation */
116         l3_hdr->total_length = rte_bswap16(sizeof(prox_rte_ipv4_hdr) + sizeof(prox_rte_udp_hdr) + act->len);
117         ctx->cur_pos[ctx->peer] += act->len;
118         ctx->cur_action++;
119
120         /* When the stream has ended, there is no need to schedule
121            another timeout (which will be unscheduled at the end of
122            the stream). */
123         if (stream_udp_is_ended(ctx))
124                 return 0;
125
126         token_time_take(&ctx->token_time, mbuf_wire_size(mbuf));
127
128         /* Send next packet as soon as possible */
129         if (ctx->stream_cfg->actions[ctx->cur_action].peer == ctx->peer) {
130                 *next_tsc = token_time_tsc_until_full(&ctx->token_time);
131         }
132         else {
133                 uint64_t wait = token_time_tsc_until_full(&ctx->token_time_other);
134                 *next_tsc = wait + ctx->stream_cfg->tsc_timeout;
135         }
136
137         return 0;
138 }
139
140 uint16_t stream_udp_reply_len(struct stream_ctx *ctx)
141 {
142         if (stream_udp_is_ended(ctx))
143                 return 0;
144         else if (ctx->stream_cfg->actions[ctx->cur_action].peer == ctx->peer)
145                 return 0;
146         else
147                 return ctx->stream_cfg->data[ctx->stream_cfg->actions[ctx->cur_action].peer].hdr_len + sizeof(prox_rte_udp_hdr) +
148                         ctx->stream_cfg->actions[ctx->cur_action].len;
149 }
150
151 void stream_udp_calc_len(struct stream_cfg *cfg, uint32_t *n_pkts, uint32_t *n_bytes)
152 {
153         const uint32_t client_hdr_len = cfg->data[PEER_CLIENT].hdr_len;
154         const uint32_t server_hdr_len = cfg->data[PEER_SERVER].hdr_len;
155
156         *n_pkts = 0;
157         *n_bytes = 0;
158
159         for (uint32_t i = 0; i < cfg->n_actions; ++i) {
160                 const uint32_t send_hdr_len = cfg->actions[i].peer == PEER_CLIENT? client_hdr_len : server_hdr_len;
161                 uint32_t len = send_hdr_len + sizeof(prox_rte_udp_hdr) + cfg->actions[i].len;
162                 *n_bytes += (len < 60? 60 : len) + 24;
163                 (*n_pkts)++;
164         }
165 }