Skip to content

Commit dd7f7fd

Browse files
committed
ndni: LpHeader_Parse accepts segmented mbuf
1 parent 803d88c commit dd7f7fd

File tree

13 files changed

+214
-39
lines changed

13 files changed

+214
-39
lines changed

csrc/dpdk/mbuf.h

+27
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,33 @@ Mbuf_ChainVector(struct rte_mbuf* vec[], uint16_t count) {
113113
return head;
114114
}
115115

116+
/**
117+
* @brief Free a sequence of segments.
118+
* @param begin pointer to first segment pointer.
119+
* @param end exclusive last segment, will not be freed.
120+
* @param pktLen pointer to packet length, will be decremented.
121+
* @return number of freed segments.
122+
* @post @c *begin is freed, but @c end is not freed.
123+
* @post *begin == end
124+
* @code
125+
* // free second through last segments of an mbuf
126+
* pkt->nb_segs -= Mbuf_FreeSegs(&pkt->next, NULL, &pkt->pkt_len);
127+
* @endcode
128+
*/
129+
__attribute__((nonnull(1, 3))) static inline uint16_t
130+
Mbuf_FreeSegs(struct rte_mbuf** begin, struct rte_mbuf* end, uint32_t* pktLen) {
131+
uint16_t count = 0;
132+
for (struct rte_mbuf* seg = *begin; seg != end;) {
133+
struct rte_mbuf* next = seg->next;
134+
++count;
135+
*pktLen -= seg->data_len;
136+
rte_pktmbuf_free_seg(seg);
137+
seg = next;
138+
}
139+
*begin = end;
140+
return count;
141+
}
142+
116143
/**
117144
* @brief Enqueue a burst of packets to a ring buffer.
118145
* @param autoFree if true, rejected packets are freed.

csrc/iface/face-rx.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ FaceRx_Input(Face* face, int rxThread, struct rte_mbuf* pkt) {
1111
rxt->nFrames[0] += pkt->pkt_len; // nOctets counter
1212

1313
Packet* npkt = Packet_FromMbuf(pkt);
14-
if (unlikely(!rte_pktmbuf_is_contiguous(pkt) || !Packet_Parse(npkt, face->impl->rxParseFor))) {
14+
if (unlikely(!Packet_Parse(npkt, face->impl->rxParseFor))) {
1515
++rxt->nDecodeErr;
1616
N_LOGD("l2-decode-error face=%" PRI_FaceID " thread=%d", face->id, rxThread);
1717
rte_pktmbuf_free(pkt);

csrc/iface/reassembler.c

+4-1
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,13 @@ Reassembler_Reassemble_(Reassembler* reass, LpL2* pm, hash_sig_t hash) {
9191
Packet*
9292
Reassembler_Accept(Reassembler* reass, Packet* fragment) {
9393
struct rte_mbuf* pkt = Packet_ToMbuf(fragment);
94+
if (unlikely(!rte_pktmbuf_is_contiguous(pkt))) {
95+
goto DROP_PKT;
96+
}
9497
LpL2* l2 = &Packet_GetLpHdr(fragment)->l2;
9598
NDNDPDK_ASSERT(l2->fragCount > 1 && // single fragment packets should bypass reassembler
9699
l2->fragCount <= LpMaxFragments && RTE_MBUF_DIRECT(pkt) &&
97-
rte_pktmbuf_is_contiguous(pkt) && rte_mbuf_refcnt_read(pkt) == 1);
100+
rte_mbuf_refcnt_read(pkt) == 1);
98101

99102
hash_sig_t hash = rte_hash_hash(reass->table, &l2->seqNumBase);
100103
LpL2* pm = NULL;

csrc/iface/reassembler.h

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ Reassembler_Close(Reassembler* reass);
3636
/**
3737
* @brief Accept an incoming fragment.
3838
* @param fragment an NDNLPv2 fragment. It must have type PktFragment and FragCount greater than 1.
39+
* Non-contiguous packet is unsupported and will be rejected.
3940
* @return a reassembled network layer packet, unparsed.
4041
* @retval NULL no network layer packet is ready.
4142
*/

csrc/ndni/lp.c

+29-13
Original file line numberDiff line numberDiff line change
@@ -46,32 +46,40 @@ LpHeader_ParseNack(LpHeader* lph, TlvDecoder* d) {
4646

4747
bool
4848
LpHeader_Parse(LpHeader* lph, struct rte_mbuf* pkt) {
49-
NDNDPDK_ASSERT(RTE_MBUF_DIRECT(pkt) && rte_pktmbuf_is_contiguous(pkt) &&
50-
rte_mbuf_refcnt_read(pkt) == 1);
49+
NDNDPDK_ASSERT(RTE_MBUF_DIRECT(pkt) && rte_mbuf_refcnt_read(pkt) == 1);
5150
*lph = (const LpHeader){0};
5251
lph->l2.fragCount = 1;
52+
uint64_t seqNum = 0;
5353

5454
TlvDecoder d = TlvDecoder_Init(pkt);
5555
uint32_t length0, type0 = TlvDecoder_ReadTL(&d, &length0);
56-
pkt->pkt_len = pkt->data_len = d.offset + length0; // strip Ethernet trailer, if any
57-
d.length = length0;
5856
switch (type0) {
5957
case TtInterest:
60-
case TtData:
61-
return true;
58+
case TtData: {
59+
uint32_t trailerL = d.length - length0;
60+
if (likely(trailerL == 0)) {
61+
// no Ethernet trailer, no truncation needed
62+
return true;
63+
}
64+
d = TlvDecoder_Init(pkt);
65+
d.length -= trailerL;
66+
goto ACCEPT;
67+
}
6268
case TtLpPacket:
69+
d.length = length0;
6370
break;
6471
default:
6572
return false;
6673
}
6774

68-
uint64_t seqNum = 0;
6975
TlvDecoder_EachTL (&d, type, length) {
7076
switch (type) {
7177
case TtLpPayload: {
72-
pkt->data_off += d.offset;
73-
pkt->pkt_len = pkt->data_len = length;
74-
goto FOUND_PAYLOAD;
78+
if (unlikely(length == 0)) {
79+
return false;
80+
}
81+
d.length = length;
82+
goto ACCEPT;
7583
}
7684
case TtLpSeqNum: {
7785
if (unlikely(length != 8 || !TlvDecoder_ReadNniTo(&d, length, &seqNum))) {
@@ -121,10 +129,18 @@ LpHeader_Parse(LpHeader* lph, struct rte_mbuf* pkt) {
121129
}
122130
}
123131

124-
pkt->pkt_len = pkt->data_len = 0; // no payload
125-
FOUND_PAYLOAD:;
132+
// no payload i.e. IDLE packet, no feature depends on it
133+
return false;
134+
135+
ACCEPT:;
126136
lph->l2.seqNumBase = seqNum - lph->l2.fragIndex;
127-
return lph->l2.fragIndex < lph->l2.fragCount;
137+
if (unlikely(lph->l2.fragIndex >= lph->l2.fragCount)) {
138+
return false;
139+
}
140+
141+
// truncate pkt to d.length that covers fragment
142+
TlvDecoder_Truncate(&d);
143+
return true;
128144
}
129145

130146
void

csrc/ndni/lp.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ typedef struct LpHeader {
6767

6868
/**
6969
* @brief Parse NDNLPv2 header and strip from mbuf.
70-
* @param pkt a uniquely owned, unsegmented, direct mbuf.
70+
* @param pkt a uniquely owned, possibly segmented, direct mbuf.
7171
* @return whether success.
7272
* @post @p pkt contains only (fragment of) network layer packet.
7373
*

csrc/ndni/packet.c

+1-7
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ const char* PktType_Strings_[] = {
1010
bool
1111
Packet_Parse(Packet* npkt, ParseFor parseFor) {
1212
struct rte_mbuf* pkt = Packet_ToMbuf(npkt);
13-
NDNDPDK_ASSERT(RTE_MBUF_DIRECT(pkt) && rte_pktmbuf_is_contiguous(pkt) &&
14-
rte_mbuf_refcnt_read(pkt) == 1);
13+
NDNDPDK_ASSERT(RTE_MBUF_DIRECT(pkt) && rte_mbuf_refcnt_read(pkt) == 1);
1514
pkt->packet_type = 0;
1615
PacketPriv* priv = Packet_GetPriv_(npkt);
1716
NDNDPDK_ASSERT(pkt->priv_size >= sizeof(*priv));
@@ -22,11 +21,6 @@ Packet_Parse(Packet* npkt, ParseFor parseFor) {
2221
return false;
2322
}
2423

25-
if (unlikely(pkt->pkt_len == 0)) {
26-
// there isn't any feature that depends on IDLE packets yet
27-
return false;
28-
}
29-
3024
if (lph->l2.fragCount > 1) {
3125
Packet_SetType(npkt, PktFragment);
3226
return true;

csrc/ndni/packet.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ Packet_GetNackHdr(Packet* npkt) {
122122

123123
/**
124124
* @brief Parse layer 2 and layer 3 in mbuf.
125-
* @param npkt a uniquely owned, unsegmented, direct mbuf.
125+
* @param npkt a uniquely owned, possibly segmented, direct mbuf.
126126
* @param parseFor see @c PInterest_Parse and @c PData_Parse .
127127
* @return whether success.
128128
* @post If the packet is fragmented, Packet_GetType(npkt) returns @c PktFragment .

csrc/ndni/tlv-decoder.c

+54-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,57 @@
11
#include "tlv-decoder.h"
22

3+
void
4+
TlvDecoder_Truncate(TlvDecoder* d) {
5+
uint32_t length = d->length;
6+
NDNDPDK_ASSERT(length > 0);
7+
8+
if (unlikely(d->m != d->p)) { // d->m is not the first segment
9+
// move 1 octet from d->m to d->p so that the first segment is non-empty
10+
NDNDPDK_ASSERT(d->p->data_len >= 1);
11+
d->p->pkt_len -= (d->p->data_len - 1);
12+
d->p->data_len = 1;
13+
d->p->data_off = RTE_PKTMBUF_HEADROOM;
14+
TlvDecoder_Copy(d, rte_pktmbuf_mtod(d->p, uint8_t*), 1);
15+
rte_mbuf_sanity_check(d->p, true);
16+
17+
if (unlikely(d->length == 0)) { // 1-octet packet, already in d->p
18+
d->p->nb_segs -= Mbuf_FreeSegs(&d->p->next, NULL, &d->p->pkt_len);
19+
goto FINISH;
20+
}
21+
22+
// delete segments after d->p and before d->m
23+
d->p->nb_segs -= Mbuf_FreeSegs(&d->p->next, d->m, &d->p->pkt_len);
24+
rte_mbuf_sanity_check(d->p, true);
25+
}
26+
27+
// delete d->m[:d->offset] range
28+
d->p->pkt_len -= d->offset;
29+
d->m->data_len -= d->offset;
30+
d->m->data_off += d->offset;
31+
d->offset = 0;
32+
rte_mbuf_sanity_check(d->p, true);
33+
34+
// skip over to end of fragment
35+
struct rte_mbuf* last = d->m;
36+
TlvDecoder_Skip_(d, d->length, &last);
37+
if (d->offset == 0) { // d->m does not contain useful octets
38+
// delete d->m and segments after d->m
39+
d->p->nb_segs -= Mbuf_FreeSegs(&last->next, NULL, &d->p->pkt_len);
40+
} else { // d->m contains useful octets
41+
// delete d->m[d->offset:] range
42+
d->p->pkt_len -= (d->m->data_len - d->offset);
43+
d->m->data_len = d->offset;
44+
45+
// delete segments after d->m
46+
d->p->nb_segs -= Mbuf_FreeSegs(&d->m->next, NULL, &d->p->pkt_len);
47+
}
48+
49+
FINISH:;
50+
rte_mbuf_sanity_check(d->p, true);
51+
NDNDPDK_ASSERT(d->p->pkt_len == length);
52+
POISON(d);
53+
}
54+
355
void
456
TlvDecoder_Copy_(TlvDecoder* d, uint8_t* output, uint16_t count) {
557
for (uint16_t remain = count; remain > 0;) {
@@ -122,13 +174,8 @@ TlvDecoder_Fragment(TlvDecoder* d, uint32_t count, struct rte_mbuf* frames[], ui
122174

123175
__attribute__((nonnull)) static void
124176
Linearize_Delete_(TlvDecoder* d, struct rte_mbuf* c) {
125-
for (struct rte_mbuf* seg = c->next; seg != d->m;) {
126-
struct rte_mbuf* next = seg->next;
127-
rte_pktmbuf_free_seg(seg);
128-
--d->p->nb_segs;
129-
seg = next;
130-
}
131-
c->next = d->m;
177+
uint32_t unusedPktLen = UINT32_MAX;
178+
d->p->nb_segs -= Mbuf_FreeSegs(&c->next, d->m, &unusedPktLen);
132179
if (likely(d->m != NULL)) {
133180
d->m->data_len -= d->offset;
134181
d->m->data_off += d->offset;

csrc/ndni/tlv-decoder.h

+31-5
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,11 @@ TlvDecoder_Init(struct rte_mbuf* p) {
2929
};
3030
}
3131

32-
/**
33-
* @brief Skip @p count octets.
34-
* @pre Decoder has no less than @p count remaining octets.
35-
*/
3632
__attribute__((nonnull)) static inline void
37-
TlvDecoder_Skip(TlvDecoder* d, uint32_t count) {
33+
TlvDecoder_Skip_(TlvDecoder* d, uint32_t count, struct rte_mbuf** last) {
3834
NDNDPDK_ASSERT(count <= d->length);
3935
for (uint32_t remain = count; remain > 0;) {
36+
*last = d->m;
4037
uint32_t here = d->m->data_len - d->offset;
4138
if (likely(remain < here)) {
4239
d->offset += remain;
@@ -49,6 +46,26 @@ TlvDecoder_Skip(TlvDecoder* d, uint32_t count) {
4946
d->length -= count;
5047
}
5148

49+
/**
50+
* @brief Skip @p count octets.
51+
* @pre Decoder has no less than @p count remaining octets.
52+
*/
53+
__attribute__((nonnull)) static inline void
54+
TlvDecoder_Skip(TlvDecoder* d, uint32_t count) {
55+
struct rte_mbuf* unusedLast = NULL;
56+
TlvDecoder_Skip_(d, count, &unusedLast);
57+
}
58+
59+
/**
60+
* @brief Truncate mbuf to the remaining bytes.
61+
* @param d decoder.
62+
* It shall have a uniquely owned, possibly segmented, direct mbuf.
63+
* Its remaining length shall be non-zero.
64+
* @post @p d cannot be further used.
65+
*/
66+
void
67+
TlvDecoder_Truncate(TlvDecoder* d);
68+
5269
__attribute__((nonnull)) void
5370
TlvDecoder_Copy_(TlvDecoder* d, uint8_t* output, uint16_t count);
5471

@@ -63,6 +80,15 @@ TlvDecoder_Copy(TlvDecoder* d, uint8_t* output, uint16_t count) {
6380
if (unlikely(count == 0)) {
6481
return;
6582
}
83+
84+
uint16_t here = d->m->data_len - d->offset;
85+
if (likely(count < here)) {
86+
rte_memcpy(output, rte_pktmbuf_mtod_offset(d->m, const uint8_t*, d->offset), count);
87+
d->offset += count;
88+
d->length -= count;
89+
return;
90+
}
91+
6692
TlvDecoder_Copy_(d, output, count);
6793
}
6894

ndni/README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,9 @@ To receive and parse a packet, calling code should:
7373
### Interest Decoding Details
7474

7575
`PInterest_Parse` function decodes an Interest.
76-
If the Interest carries a *forwarding hint*, up to `PInterestMaxFwHints` delegations are recognized, and any remaining delegations are ignored.
76+
If the Interest carries a *forwarding hint*, up to `PInterestMaxFwHints` names are recognized, and any remaining names are ignored.
7777
The decoder only determines the length of each name, but does not parse at component level.
78-
`PInterest_SelectFwHint` function activates a forwarding hint, parses the delegation into components on demand; only one delegation name can be active at any time.
78+
`PInterest_SelectFwHint` function activates a forwarding hint, parses the name into components on demand; only one name can be active at any time.
7979

8080
Although the packet format specifies Nonce as optional, it is required when an Interest is transmitted over network links.
8181
Thus, `PInterest_Parse` requires Nonce to be present.

0 commit comments

Comments
 (0)