Switched to Chris Wood Build Tools
This commit is contained in:
1 parent
c9fd3edfe6
commit
354f3e0ae8
62 files changed
+10628
-12271
No files matched your search
@@ -0,0 +1,16 @@
|
||||
# icn-flic-manifest
|
||||
FLIC Manifest RFC draft
|
||||
|
||||
# Editing
|
||||
|
||||
Inside each draft, you should use the suffix '-latest' in the draft name, for example:
|
||||
```
|
||||
<rfc category="exp" docName="draft-irtf-icnrg-ccnxmessages-latest" ipr="trust200902">
|
||||
```
|
||||
|
||||
The file `versions` contains the draft version number for each document. After you edit
|
||||
a document, you should be sure to set the correct draft number.
|
||||
|
||||
To build the documents, cd in to the `src/` directory and run make. This will download a subproject
|
||||
to build the system. It will replace the `build/` directory.
|
||||
|
||||
+684
@@ -0,0 +1,684 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
|
||||
<head profile="http://www.w3.org/2006/03/hcard http://dublincore.org/documents/2008/08/04/dc-html/">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />
|
||||
|
||||
<title>Maintaining CCNx or NDN flow balance with highly variable data object sizes </title>
|
||||
|
||||
|
||||
<style type="text/css">/*<![CDATA[*/
|
||||
|
||||
body {
|
||||
font: 16px "Helvetica Neue","Open Sans",Helvetica,Calibri,sans-serif;
|
||||
color: #333;
|
||||
font-size-adjust: 0.5;
|
||||
line-height: 24px;
|
||||
margin: 75px auto;
|
||||
max-width: 624px;
|
||||
padding: 0 5px;
|
||||
}
|
||||
|
||||
.title, .filename, h1, h2, h3, h4, h5 {
|
||||
font: 16px "Roboto Condensed","Helvetica Neue","Open Sans",Helvetica,Calibri,sans-serif;
|
||||
font-size-adjust: 0.5;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
line-height: 100%;
|
||||
margin: 1.2em 0 0.3em;
|
||||
}
|
||||
.title, #rfc\.title h1 { font-size: 32px; }
|
||||
h1, section h1, h2, section h2, section h3, nav h2 { font-size: 20px; }
|
||||
h3, section h4, h4, section h5 { font-size: 16px; }
|
||||
h1 a[href], h2 a[href], h3 a[href], h4 a[href] {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
table {
|
||||
margin-left: 0em;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
th {
|
||||
text-align: left;
|
||||
border-bottom: 2px solid #ddd;
|
||||
}
|
||||
td {
|
||||
border-top: 1px solid #ddd;
|
||||
vertical-align: top;
|
||||
}
|
||||
tr:nth-child(2n+1) > td,
|
||||
tr:nth-child(2n+1) > th {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
td.reference {
|
||||
max-width: 200px;
|
||||
border-top: none;
|
||||
padding-right: 1em;
|
||||
}
|
||||
.right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
|
||||
table.header, table#rfc\.headerblock {
|
||||
width: 100%;
|
||||
}
|
||||
table.header td, table#rfc\.headerblock td {
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
color: black;
|
||||
padding: 0;
|
||||
}
|
||||
.filename {
|
||||
display: block;
|
||||
color: rgb(119, 119, 119);
|
||||
font-size: 20px;
|
||||
font-weight: normal;
|
||||
line-height: 100%;
|
||||
margin: 10px 0 32px;
|
||||
}
|
||||
#rfc\.abstract+p, #rfc\.abstract+p code, #rfc\.abstract+p samp, #rfc\.abstract+p tt {
|
||||
font-size: 20px;
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
samp, tt, code, pre, span.tt {
|
||||
font-size: 13.5px;
|
||||
font-family: Consolas, monospace;
|
||||
font-size-adjust: none;
|
||||
}
|
||||
pre {
|
||||
background-color: #eee;
|
||||
border: 1px solid #ddd;
|
||||
overflow-x: auto;
|
||||
padding: 5px;
|
||||
margin: 5px;
|
||||
}
|
||||
.figure, caption {
|
||||
font-style: italic;
|
||||
margin: 0 1.5em;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
address {
|
||||
margin: 16px 2px;
|
||||
line-height: 20px;
|
||||
}
|
||||
.vcard {
|
||||
font-style: normal;
|
||||
}
|
||||
.vcardline {
|
||||
display: block;
|
||||
}
|
||||
.vcardline .fn, address b {
|
||||
font-weight: normal;
|
||||
}
|
||||
.vcardline .hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
dl {
|
||||
margin-left: 1em;
|
||||
}
|
||||
dl.dl-horizontal: {
|
||||
margin-left: 0;
|
||||
}
|
||||
dl > dt {
|
||||
float: left;
|
||||
margin-right: 1em;
|
||||
}
|
||||
dl.nohang > dt {
|
||||
float: none;
|
||||
}
|
||||
dl > dd {
|
||||
margin-bottom: .5em;
|
||||
}
|
||||
dl.compact > dd {
|
||||
margin-bottom: 0em;
|
||||
}
|
||||
dl > dd > dl {
|
||||
margin-top: 0.5em;
|
||||
margin-bottom: 0em;
|
||||
}
|
||||
ul.empty {
|
||||
list-style-type: none;
|
||||
}
|
||||
ul.empty li {
|
||||
margin-top: .5em;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 0;
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
hr.noprint {
|
||||
display: none;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
a[href] {
|
||||
color: #2a6496;
|
||||
}
|
||||
a[href]:hover {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
p, ol, ul, li {
|
||||
padding: 0;
|
||||
}
|
||||
p {
|
||||
margin: 0.5em 0;
|
||||
}
|
||||
ol, ul {
|
||||
margin: 0.2em 0 0.2em 2em;
|
||||
}
|
||||
li {
|
||||
margin: 0.2em 0;
|
||||
}
|
||||
address {
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
ul.toc ul {
|
||||
margin: 0 0 0 2em;
|
||||
}
|
||||
ul.toc li {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 924px) {
|
||||
body {
|
||||
padding-right: 350px;
|
||||
}
|
||||
body>ul.toc, body>#rfc\.toc {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
right: calc(50vw - 500px);
|
||||
width: 300px;
|
||||
z-index: 1;
|
||||
overflow: auto;
|
||||
overscroll-behavior: contain;
|
||||
}
|
||||
body>#rfc\.toc {
|
||||
top: 55px;
|
||||
}
|
||||
body>ul.toc {
|
||||
top: 100px;
|
||||
}
|
||||
|
||||
ul.toc {
|
||||
margin: 0 0 0 4px;
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
}
|
||||
ul.toc ul {
|
||||
margin-left: 1.2em;
|
||||
}
|
||||
}
|
||||
|
||||
.github-fork-ribbon-wrapper {
|
||||
display: none;
|
||||
}
|
||||
@media screen and (min-width: 800px) {
|
||||
/* "Fork me on GitHub" CSS ribbon based on
|
||||
* https://github.com/simonwhitaker/github-fork-ribbon-css
|
||||
*/
|
||||
.github-fork-ribbon {
|
||||
position: absolute;
|
||||
padding: 2px 0;
|
||||
background-color: #a00;
|
||||
background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15));
|
||||
box-shadow: 0 2px 3px 0 rgba(0, 0, 0, 0.5);
|
||||
font: 700 12px "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
|
||||
pointer-events: auto;
|
||||
|
||||
top: 38px;
|
||||
right: -45px;
|
||||
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.github-fork-ribbon a[href],
|
||||
.github-fork-ribbon a[href]:hover {
|
||||
color: #fff;
|
||||
background-color: transparent;
|
||||
text-decoration: none;
|
||||
text-shadow: 0 -1px rgba(0, 0, 0, 0.5);
|
||||
text-align: center;
|
||||
|
||||
width: 190px;
|
||||
line-height: 18px;
|
||||
|
||||
display: inline-block;
|
||||
padding: 2px 0;
|
||||
|
||||
border: 1.5px dotted #fff;
|
||||
border-color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
.github-fork-ribbon-wrapper {
|
||||
display: block;
|
||||
width: 130px;
|
||||
height: 130px;
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
top: 0; right: 0;
|
||||
z-index: 2;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
@media screen and (min-width: 1000px) {
|
||||
.github-fork-ribbon-wrapper {
|
||||
position: fixed;
|
||||
}
|
||||
/*]]>*/</style>
|
||||
<meta name="viewport" content="initial-scale=1.0">
|
||||
|
||||
|
||||
<link href="#rfc.toc" rel="Contents"/>
|
||||
<link href="#rfc.section.1" rel="Chapter" title="1 Introduction"/>
|
||||
<link href="#rfc.section.2" rel="Chapter" title="2 Requirements Language"/>
|
||||
<link href="#rfc.section.3" rel="Chapter" title="3 Method to enhance congestion control with signaled size information in Interest Messages"/>
|
||||
<link href="#rfc.section.3.1" rel="Chapter" title="3.1 How to predict the size of returning Data messages"/>
|
||||
<link href="#rfc.section.3.2" rel="Chapter" title="3.2 Handling `too big' cases"/>
|
||||
<link href="#rfc.section.3.3" rel="Chapter" title="3.3 Handling `too small' cases"/>
|
||||
<link href="#rfc.section.3.4" rel="Chapter" title="3.4 Interactions with Interest Aggregation"/>
|
||||
<link href="#rfc.section.3.5" rel="Chapter" title="3.5 Operation when some Interests lack the expected data size option and some have it"/>
|
||||
<link href="#rfc.section.4" rel="Chapter" title="4 Dealing with malicious actors"/>
|
||||
<link href="#rfc.section.5" rel="Chapter" title="5 Mapping to CCNx and NDN packet encodings"/>
|
||||
<link href="#rfc.section.5.1" rel="Chapter" title="5.1 Packet encoding for CCNx"/>
|
||||
<link href="#rfc.section.5.2" rel="Chapter" title="5.2 Packet encoding for NDN"/>
|
||||
<link href="#rfc.section.6" rel="Chapter" title="6 IANA Considerations"/>
|
||||
<link href="#rfc.section.7" rel="Chapter" title="7 Security Considerations"/>
|
||||
<link href="#rfc.references" rel="Chapter" title="8 References"/>
|
||||
<link href="#rfc.references.1" rel="Chapter" title="8.1 Normative References"/>
|
||||
<link href="#rfc.references.2" rel="Chapter" title="8.2 Informative References"/>
|
||||
<link href="#rfc.authors" rel="Chapter"/>
|
||||
|
||||
|
||||
<meta name="generator" content="xml2rfc version 2.5.2 - http://tools.ietf.org/tools/xml2rfc" />
|
||||
<link rel="schema.dct" href="http://purl.org/dc/terms/" />
|
||||
|
||||
<meta name="dct.creator" content="D. Oran, " />
|
||||
<meta name="dct.identifier" content="urn:ietf:id:draft-oran-icnrg-flowbalance-02" />
|
||||
<meta name="dct.issued" scheme="ISO8601" content="2019-8" />
|
||||
<meta name="dct.abstract" content="Deeply embedded in some ICN architectures, especially Named Data Networking (NDN) and Content-Centric Networking (CCNx) is the notion of flow balance. This captures the idea that there is a one-to-one correspondence between requests for data, carried in Interest messages, and the responses with the requested data object, carried in Data messages. This has a number of highly beneficial properties for flow and congestion control in networks, as well as some desirable security properties. For example, neither legitimate users nor attackers are able to inject large amounts of un-requested data into the network." />
|
||||
<meta name="description" content="Deeply embedded in some ICN architectures, especially Named Data Networking (NDN) and Content-Centric Networking (CCNx) is the notion of flow balance. This captures the idea that there is a one-to-one correspondence between requests for data, carried in Interest messages, and the responses with the requested data object, carried in Data messages. This has a number of highly beneficial properties for flow and congestion control in networks, as well as some desirable security properties. For example, neither legitimate users nor attackers are able to inject large amounts of un-requested data into the network." />
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<table class="header">
|
||||
<tbody>
|
||||
|
||||
<tr>
|
||||
<td class="left">ICNRG</td>
|
||||
<td class="right">D. Oran</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="left">Internet-Draft</td>
|
||||
<td class="right">Network Systems Research and Design</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="left">Intended status: Experimental</td>
|
||||
<td class="right">August 2019</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="left">Expires: February 2, 2020</td>
|
||||
<td class="right"></td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p class="title">Maintaining CCNx or NDN flow balance with highly variable data object sizes <br />
|
||||
<span class="filename">draft-oran-icnrg-flowbalance-02</span></p>
|
||||
|
||||
<h1 id="rfc.abstract">
|
||||
<a href="#rfc.abstract">Abstract</a>
|
||||
</h1>
|
||||
<p>Deeply embedded in some ICN architectures, especially Named Data Networking (NDN) and Content-Centric Networking (CCNx) is the notion of flow balance. This captures the idea that there is a one-to-one correspondence between requests for data, carried in Interest messages, and the responses with the requested data object, carried in Data messages. This has a number of highly beneficial properties for flow and congestion control in networks, as well as some desirable security properties. For example, neither legitimate users nor attackers are able to inject large amounts of un-requested data into the network.</p>
|
||||
<p>Existing congestion control approaches however cannot deal effectively with a widely varying MTU of ICN data messages, since the protocols allow a dynamic range of 1-64K bytes. Since Interest messages are used to allocate the reverse link bandwidth for returning Data, there is large uncertainty in how to allocate that bandwidth. Unfortunately, current congestion control schemes in CCNx and NDN only count Interest messages and have no idea how much data is involved that could congest the inverse link. This document proposes a method to maintain flow balance by accommodating the wide dynamic range in Data message MTU.</p>
|
||||
<h1 id="rfc.status">
|
||||
<a href="#rfc.status">Status of This Memo</a>
|
||||
</h1>
|
||||
<p>This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.</p>
|
||||
<p>Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at http://datatracker.ietf.org/drafts/current/.</p>
|
||||
<p>Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."</p>
|
||||
<p>This Internet-Draft will expire on February 2, 2020.</p>
|
||||
<h1 id="rfc.copyrightnotice">
|
||||
<a href="#rfc.copyrightnotice">Copyright Notice</a>
|
||||
</h1>
|
||||
<p>Copyright (c) 2019 IETF Trust and the persons identified as the document authors. All rights reserved.</p>
|
||||
<p>This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (http://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Simplified BSD License.</p>
|
||||
|
||||
|
||||
<hr class="noprint" />
|
||||
<h1 class="np" id="rfc.toc"><a href="#rfc.toc">Table of Contents</a></h1>
|
||||
<ul class="toc">
|
||||
|
||||
<li>1. <a href="#rfc.section.1">Introduction</a></li>
|
||||
<li>2. <a href="#rfc.section.2">Requirements Language</a></li>
|
||||
<li>3. <a href="#rfc.section.3">Method to enhance congestion control with signaled size information in Interest Messages</a></li>
|
||||
<ul><li>3.1. <a href="#rfc.section.3.1">How to predict the size of returning Data messages</a></li>
|
||||
<li>3.2. <a href="#rfc.section.3.2">Handling `too big' cases</a></li>
|
||||
<li>3.3. <a href="#rfc.section.3.3">Handling `too small' cases</a></li>
|
||||
<li>3.4. <a href="#rfc.section.3.4">Interactions with Interest Aggregation</a></li>
|
||||
<li>3.5. <a href="#rfc.section.3.5">Operation when some Interests lack the expected data size option and some have it</a></li>
|
||||
</ul><li>4. <a href="#rfc.section.4">Dealing with malicious actors</a></li>
|
||||
<li>5. <a href="#rfc.section.5">Mapping to CCNx and NDN packet encodings</a></li>
|
||||
<ul><li>5.1. <a href="#rfc.section.5.1">Packet encoding for CCNx</a></li>
|
||||
<li>5.2. <a href="#rfc.section.5.2">Packet encoding for NDN</a></li>
|
||||
</ul><li>6. <a href="#rfc.section.6">IANA Considerations</a></li>
|
||||
<li>7. <a href="#rfc.section.7">Security Considerations</a></li>
|
||||
<li>8. <a href="#rfc.references">References</a></li>
|
||||
<ul><li>8.1. <a href="#rfc.references.1">Normative References</a></li>
|
||||
<li>8.2. <a href="#rfc.references.2">Informative References</a></li>
|
||||
</ul><li><a href="#rfc.authors">Author's Address</a></li>
|
||||
|
||||
|
||||
</ul>
|
||||
|
||||
<h1 id="rfc.section.1"><a href="#rfc.section.1">1.</a> <a href="#intro" id="intro">Introduction</a></h1>
|
||||
<p id="rfc.section.1.p.1">Deeply embedded in some ICN architectures, especially Named Data Networking (NDN <a href="#NDN">[NDN]</a>) and Content-Centric Networking (CCNx <a href="#RFC8569">[RFC8569]</a>,<a href="#RFC8609">[RFC8609]</a>) is the notion of <em>flow balance</em>. This captures the idea that there is a one-to-one correspondence between requests for data, carried in Interest messages, and the responses with the requested data object, carried in Data messages. This has a number of highly beneficial properties for flow and congestion control in networks, as well as some desirable security properties. For example, neither legitimate users nor attackers are able to inject large amounts of un-requested data into the network.</p>
|
||||
<p id="rfc.section.1.p.2">This approach leads to a desire to make the size of the objects carried in Data messages small and near constant, because flow balance can then be kept using simple bookkeeping of how many Interest messages are outstanding. While simple, constraining Data messages to be quite small - usually on the order of a link Maximum Transmission Unit (MTU) - has some constraints and deleterious effects, among which are: </p>
|
||||
|
||||
<ul>
|
||||
<li>Such small data objects are inconvenient for many applications; their natural data object sizes can be considerably larger than a link MTU.</li>
|
||||
<li>Applications with truly small data objects (e.g. voice packets in an Internet telephony applications) have no way to communicate that to the network, causing resources to still be allocated for MTU-sized data objects</li>
|
||||
<li>When chunking a larger data object into multiple Data messages, each message has to be individually cryptographically hashed and signed, increasing both computational overhead and overall message header size. The signature can be elided when Manifests are used (by signing the Manifest instead), but the overhead of hashing multiple small messages rather than fewer larger ones remains.</li>
|
||||
</ul>
|
||||
|
||||
<p> </p>
|
||||
<p id="rfc.section.1.p.3">One approach which helps with the last of these is to employ fragmentation for Data messages larger than the Path MTU (PMTU). such messages are carved into smaller pieces for transmission over the link(s). There are three flavors of fragmentation: end-to-end, hop-by-hop with reassembly at every hop, and hop-by-hop with cut-through of individual fragments. A number of ICN protocol architectures incorporate fragmentation and schemes have been proposed for both NDN and CCNx, for example in <a href="#Ghali2013">[Ghali2013]</a>. Fragmentation alone does not ameliorate the flow balance problem however, since from a resource allocation standpoint both memory and link bandwidth must be set aside for maximum-sized data objects to avoid congestion collapse under overload.</p>
|
||||
<p id="rfc.section.1.p.4">The design space considered in this document does not however extend to arbitrarily large objects (e.g. 100's of kilobytes or larger). As the dynamic range of data object sizes gets very large, finding the right tradeoff between handling a large number of small data objects versus a single very large data object when allocating link and buffer resources becomes intractable. Further, the semantics of Interest-Data exchanges means that any error in the exchange results in a re-issue of an Interest for the entire Data object. Very large data objects represent a performance problem because the cost of retransmission when Interests are retransmitted (or re-issued) becomes unsustainably high. Therefore, the method we propose deals with a dynamic range of object sizes from very small (a fraction of a link MTU) to moderately large - about 64 kilobytes or equivalently about 40 Ethernet packets, and assumes an associated fragmentation scheme to handle link MTUs that cannot carry the object in a single link-layer packet.</p>
|
||||
<p id="rfc.section.1.p.5">The approach described in the rest of this document maintains flow balance under the conditions outlined above by allocating resources accurately based on expected data object size, rather than employing simple interest counting.</p>
|
||||
<h1 id="rfc.section.2"><a href="#rfc.section.2">2.</a> Requirements Language</h1>
|
||||
<p id="rfc.section.2.p.1">The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in <a href="#RFC2119">RFC 2119</a> <cite title="NONE">[RFC2119]</cite>.</p>
|
||||
<h1 id="rfc.section.3"><a href="#rfc.section.3">3.</a> <a href="#description" id="description">Method to enhance congestion control with signaled size information in Interest Messages</a></h1>
|
||||
<p id="rfc.section.3.p.1">Before diving into the specifics of the design, it is useful to consider how congestion control works in NDN/CCNx. Unlike the IP protocol family, which relies on end-to-end congestion control (e.g. TCP<a href="#RFC0793">[RFC0793]</a>, DCCP<a href="#RFC4340">[RFC4340]</a>, SCTP<a href="#RFC4960">[RFC4960]</a>, QUIC<a href="#I-D.ietf-quic-transport">[I-D.ietf-quic-transport]</a>), CCNx and NDN employ hop-by-hop congestion control. There is per-Interest/Data state at every hop of the path and therefore for each outstanding Interest, bandwidth for data returning on the inverse path can be allocated. In the current design, this allocation is done using simple Interest counting - by accepting one Interest packet from an downstream node, implicitly this provides a guarantee (either hard or soft) that there is sufficient bandwidth on the inverse direction of the link to send back one Data packet. A number of congestion control schemes have been developed that operate in this fashion, for example <a href="#Wang2013">[Wang2013]</a>,<a href="#Mahdian2016">[Mahdian2016]</a>,<a href="#Song2018">[Song2018]</a>,<a href="#Carofiglio2012">[Carofiglio2012]</a>. Other schemes, like <a href="#Schneider2016">[Schneider2016]</a> neither count nor police interests, but instead monitor queues using AQM (active queue management) to mark returning Data packets that have experienced congestion. It is worth noting that every congestion control algorithm has an explicit fairness goal and associated objective function (usually either <a href="#minmaxfairness">[minmaxfairness]</a> or <a href="#proportionalfairness">[proportionalfairness]</a>). If your fairness is to be based on resource usage, pure interest counting doesn't do the trick, since a consumer asking for large thing can saturate a link and shift loss to consumers asking for small things.</p>
|
||||
<p id="rfc.section.3.p.2">In order to deal with a larger dynamic range of data object size, some means is required to allocate link bandwidth for data messages in bytes with an upper bound larger than a link PMTU and a lower bound lower than a single link MTU. Since resources are allocated for returning Data based on arriving Interests, this information must be available in Interest messages.</p>
|
||||
<p id="rfc.section.3.p.3">Therefore, one key idea is the inclusion of an <em>expected data size</em> TLV in each Interest message. This allows each forwarder on the path taken by the interest to accurately allocate bandwidth on the inverse path for the returning Data message. Also, by including the expected data size, large objects will have a corresponding weight in resource allocation, maintaining link and forwarder buffering fairness. The simpler Interest counting scheme was nominally "fair" on a per-exchange basis within the variations of data that fit in a single PMTU packet because all Interests produced similar amounts of data in return. In the absence of such a field, it is not feasible to allow a large dynamic range in object size. While schemes like <a href="#Schneider2016">[Schneider2016]</a> would not employ the expected data size to allocate reverse link bandwidth, they can still benefit from the information to affect the AQM congestion marking algorithm, preferentially marking data packets that exceed the expected data size.</p>
|
||||
<h1 id="rfc.section.3.1"><a href="#rfc.section.3.1">3.1.</a> <a href="#prediction" id="prediction">How to predict the size of returning Data messages</a></h1>
|
||||
<p id="rfc.section.3.1.p.1">This of course raises the question "How does the requester know how big the corresponding data coming back will be?". For a number of important applications, the size is known a priori due to the characteristics of the application. Here are some examples: </p>
|
||||
|
||||
<ul>
|
||||
<li>For many sensor and other Internet-of-Things applications, the data is instrument readings which have fixed known size.</li>
|
||||
<li>In video streaming, the data is output of a video encoder which produces variable sized frames. This information is typically made available ahead of time to the streaming clients in the form of a Manifest [4], which contains the names of the corresponding segments (or individual frames) of video and audio and their sizes.</li>
|
||||
<li>Internet telephony applications use vocoders that typically employ fixed-size audio frames. Therefore, their size is known either a priori, or via an initialization exchange at the start of an audio session.</li>
|
||||
</ul>
|
||||
|
||||
<p> The more complex cases arise where the data size is not known at the time the Interest must be sent. Much of the nuance of the proposed scheme is in how mismatches between the expected data size and the actual data object returned are handled. The consumer can either under- or over-estimate the data size. In the former case, the under-estimate can lead to congestion and possible loss of data. In the latter case, bandwidth that could have been used by data objects requested by other consumers might be wasted. We first consider "honest" mis-estimates due to imperfect knowledge by the ICN application; later we consider malicious applications that are using the machinery to mount some form of attack. We also consider the effects of Interest aggregation if the aggregated Interests have differing expected data sizes. Also, it should be obvious that if the Data message arrives, the application learns its actual size, which may or may not be useful in adjusting the expected data size estimate for future Interests.</p>
|
||||
<p id="rfc.section.3.1.p.2">In all cases, the expected data size from the Interest can be incorporated in the corresponding Pending Interest Table (PIT) entry of each CCNx/NDN forwarder on the path and hence when a (possibly fragmented) Data object comes back, its total size is known and can be compared to the expected size in the PIT for a mismatch. Aside: In the case of fragmentation, we assume a fragmentation scheme in which the total data size can be known as soon as any one fragment is received (a reasonable assumption for most any well-designed fragmentation method).</p>
|
||||
<h1 id="rfc.section.3.2"><a href="#rfc.section.3.2">3.2.</a> <a href="#toobig" id="toobig">Handling `too big' cases</a></h1>
|
||||
<p id="rfc.section.3.2.p.1">If the returning data is larger than the expected data size, the extra data could result in either unfair bandwidth allocation or possibly data loss under congestion conditions. When this is detected, the forwarder has three choices: </p>
|
||||
|
||||
<ol>
|
||||
<li>It could forward the data anyway, which is safe under non-congestion conditions, but unfair and possibly unstable when the output link is congested</li>
|
||||
<li>It could forward the data when un-congested (e.g. by assessing output queue depth) but drop it when congested</li>
|
||||
<li>It could always drop the data, as a way of "punishing" the requester for the mis-estimate.</li>
|
||||
</ol>
|
||||
|
||||
<p> Either of the latter two strategies is acceptable from a congestion control point of view. However, it is not a good idea to simply drop the Data message with no feedback to the issuer of the Interest because the application has no way to learn the actual data size and retry. Further, recovery would be delayed until the failing Interest timed out. Therefore, an additional element needed in protocol semantics is the incorporation of a "Data too big" error message (via an "interest Return" packet in CCNx).</p>
|
||||
<p id="rfc.section.3.2.p.2">Upon dropping data as above, the CCNx/NDN forwarder converts the normal Data message into an Interest Return message containing the with the T_MTU_TOO_LARGE error code and the actual size of the data object instead of the data object content. It propagates that back toward the client identically to how the original Data message would have been handled. Subsequent nodes upon receiving the T_MTU_TOO_LARGE error treat it as all other Interest Return errors. When the Interest Return eventually arrives back to the issuer of the Interest, the user can, they desire, reissue the Interest with the correct expected data size.</p>
|
||||
<p id="rfc.section.3.2.p.3">One detail to note is that an Interest Return carrying T_MTU_TOO_LARGE must be deterministically smaller than the expected data size in all cases. This is clearly the case for large data objects, but there is a corner case with small data objects. There has to be a minimum expected data size that a client can specify in their Interests, and that minimum cannot be smaller than the size of a T_MTU_TOO_LARGE Interest Return</p>
|
||||
<h1 id="rfc.section.3.3"><a href="#rfc.section.3.3">3.3.</a> <a href="#toosmall" id="toosmall">Handling `too small' cases</a></h1>
|
||||
<p id="rfc.section.3.3.p.1">Next we consider the case where the returning data is smaller than the expected data size. While this case does not result in congestion, it can cause resources to be inefficiently allocated because not all of the set-aside bandwidth for the returning data object gets used. The simplest and most straightforward way to deal with this case is to essentially ignore it. The motivation for not worrying about the smaller data mismatch is that in many situations that employ usage-based resource measurement (and possibly charging), it is trivial to just account for the usage according to the larger expected data size rather than actual returned data size. Properly adjusting congestion control parameters to somehow penalize users for over-estimating their resource usage requires fairly heavyweight machinery, which in most cases is not warranted. If desired, any of the following mechanisms could be considered: </p>
|
||||
|
||||
<ul>
|
||||
<li>Attempt to identify future Interests for the same object or closely related objects and allocate resources based on some retained state about the actual size of prior objects</li>
|
||||
<li>Police consumer behavior and decrease the expected data size in one or more future Interests to compensate</li>
|
||||
<li>For small objects, do more optimistic resource allocation on the links on the presumption that there will be some "slack" due to clients overestimating data object size.</li>
|
||||
</ul>
|
||||
|
||||
<p> One protocol detail of CCNx/NDN that needs to be dealt with is Interest Aggregation. This happens when multiple Interests arrive at a forwarder for the same Named object. These are aggregated such that one of them (i.e.the first to arrive and create PIT state) is forwarded, and the rest are dropped while marking the arrival face so the data can be sent back to the multiple requesting clients. Interest aggregation interacts with expected data size if Interests from different clients contain different values of the expected data size. As above, the simplest solution to this problem is to ignore it, as most error cases are benign. However, there is one problematic error case where one client provides an accurate expected data size, but another who issued the Interest first underestimates, causing both to receive a Data too big error. This introduces a denial of service vulnerability, which we discuss below together with the other malicious actor cases.</p>
|
||||
<h1 id="rfc.section.3.4"><a href="#rfc.section.3.4">3.4.</a> <a href="#aggregation" id="aggregation">Interactions with Interest Aggregation</a></h1>
|
||||
<p id="rfc.section.3.4.p.1">Interest Aggregation, while a powerful feature for maintaining flow balance when multiple consumers send Interests for the same Named object, introduces subtle complications. Whenever a second or subsequent Interest arrives at a forwarder with an active PIT entry it is possible that those Interests carry different parameters, for example hop limit, payload, etc. It is therefore necessary to specify the exact behavior of the forwarder for each of the parameters that might differ. In the case of the expected data size parameter defined here, the value is associated with the ingress face on which the Interest creating the PIT entry arrived, as opposed to being global to the PIT entry as a whole. There are two cases to consider: </p>
|
||||
|
||||
<ol>
|
||||
<li>The arriving interest carries an expected data size smaller than any of the values associated with the PIT entry.</li>
|
||||
<li>The arriving interest carries an expected data size larger than any of the values associated with the PIT entry.</li>
|
||||
</ol>
|
||||
|
||||
<p> </p>
|
||||
<p id="rfc.section.3.4.p.2">For Case (1) the Interest can be safely aggregated since the upstream links will have sufficient bandwidth allocated based on the larger expected data size (assuming the original Interest's expected data size was itself sufficiently large to accommodate the actual size of the returning Data. On the other hand, should the incoming face have bandwidth allocated based on the larger existing Interest's expected data size, or on the smaller value in the arriving interest? Here there are two possible approaches: </p>
|
||||
|
||||
<ol style="list-style-type: lower-alpha">
|
||||
<li>Allocate based on the data size already in the PIT. In this case the consumer sending the earlier Interest can cause over-allocation of link bandwidth for other incoming faces, but there will not be a T_MTU_TOO_LARGE error generated for that Interest</li>
|
||||
<li>Allocate based on the value in the arriving Interest. If the returning Data is in fact larger, generate a T_MTU_TOO_LARGE Interest Return on that ingress face, while successfully returning the Data message on any faces that do not exhibit a too small expected data size</li>
|
||||
</ol>
|
||||
|
||||
<p> It is RECOMMENDED that the second policy be followed. The reasons behind this recommendation are as follows: </p>
|
||||
|
||||
<ol>
|
||||
<li>The link can be congested quite quickly after the queuing decision is made, especially if the data has a long link-occupancy time, so this is a safer alternative.</li>
|
||||
<li>The cost of returning the error is only one link RTT, since the consumer (or downstream forwarder) can immediately re-issue the interest with the correct size and pick up the cached object from the upstream forwarder's Content Store.</li>
|
||||
<li>Being optimistic and returning the data interacts with the behavior of aggregate resource control and resource accounting, which in turn raises the messy issue of whether to "charge" the consumer for the actual bandwidth used or only for the requested bandwidth in the expected data.</li>
|
||||
<li>The rabbit hole goes deeper if you add differential QoS to the equation or consumers "playing games" and intentionally underestimating so their interests get satisfied when links aren't congested. This makes handling malicious actors (<a href="#malicious">Section 4</a>) more difficult.</li>
|
||||
</ol>
|
||||
|
||||
<p> </p>
|
||||
<p id="rfc.section.3.4.p.3">For Case (2) above, the Interest MUST be forwarded rather than aggregated to prevent a consumer from mounting a denial of service attack by sending intentionally too small expected data size (see <a href="#malicious">Section 4</a> for additional detail on this and other attacks). As above for Case (1) it is RECOMMENDED that policy (b) above be followed. </p>
|
||||
<h1 id="rfc.section.3.5"><a href="#rfc.section.3.5">3.5.</a> <a href="#compatibility" id="compatibility">Operation when some Interests lack the expected data size option and some have it</a></h1>
|
||||
<p id="rfc.section.3.5.p.1">Since the expected data size hop-by-hop option forwarders need to be prepared to handle an arbitrary mix of the two forms. There are two general things to address. </p>
|
||||
<p id="rfc.section.3.5.p.2">First, we assume that any forwarder supporting expected data size is running a more sophisticated congestion control algorithm that one employing simple interest counting. The link bandwidth resource allocation is therefore based directly, or indirectly, on the expected Data size in bytes. Therefore, the forwarder has to assign a value to use in the resource allocation for the reverse link. This specification does not mandate any particular approach or a default value to use. However, in the absence on other guidance, it makes sense to do one of two things: </p>
|
||||
|
||||
<ol>
|
||||
<li>Pick a default based on the link MTU of the face on which the Interest arrived and use that for all Interests lacking an expected data size. This is likely to be most compatible with simple interest counting which would rate limit all incoming interests equally</li>
|
||||
<li>Configure some values for given Name prefixes that have known sizes. This may be appropriate for dedicated forwarders supporting single use cases, such as: <ul><li>A forwarder handling IoT sensors sending very small Data packets</li><li>A forwarder handling real-time video with large average Data packets that exceed link MTU and are routinely fragmented</li><li>A forwarder doing voice trunking where the vocoders produce moderate sized packets, still much smaller than the link MTU</li></ul><p> </p></li>
|
||||
</ol>
|
||||
|
||||
<p> </p>
|
||||
<p id="rfc.section.3.5.p.3">The second area to address is what to do if an interest lacking an expected Data size is responded to by a Data message whose size exceeds the default discussed above. It would be inappropriate to issue a T_MTU_TOO_LARGE error, since the consumer is unlikely to understand or deal correctly with that new error case. Instead, it is RECOMMENDED that the forwarder: </p>
|
||||
|
||||
<ul>
|
||||
<li>Ignore the mismatch if the reverse link is not congested and return the requested Data message anyway.</li>
|
||||
<li>If the reverse link is congested, issue an Interest Return with the T_NO_RESOURCES error code</li>
|
||||
</ul>
|
||||
|
||||
<p> This specification does not define or recommend any particular algorithm for assessing the congestion state of the link(s) to carry the Data message downstream to the requesting consumers. It is assumed that a reasonable algorithm is in use, because otherwise even basic Interest counting forms of congestion control would not be effective. </p>
|
||||
<h1 id="rfc.section.4"><a href="#rfc.section.4">4.</a> <a href="#malicious" id="malicious">Dealing with malicious actors</a></h1>
|
||||
<p id="rfc.section.4.p.1">First we note that various known attacks in CCNx or NDN can also be mounted by users employing this method. Attacks that involve interest flooding, cache pollution, cache poisoning, etc. are neither worsened nor ameliorated by the introduction of the congestion control capabilities described here. However, there are two new vulnerabilities that need to be dealt with. These two new vulnerabilities involve intentional mis-estimation of data size.</p>
|
||||
<p id="rfc.section.4.p.2">The first is a consumer who intentionally over-estimates data size with the goal of preventing other users from using the bandwidth. This is at most a minor concern given the above discussion of over-estimation by honest clients. If one of the amelioration techniques above are used, the case of malicious over-estimation is also dealt with adequately.</p>
|
||||
<p id="rfc.section.4.p.3">The second is a user who intentionally under-estimates the data size with the goal having its Interest processed while the other aggregated interests are not processed, thereby causing T_MTU_TOO_LARGE errors and denying service to the other users with overlapping requests. There are a number of possible mitigation techniques for this attack vector, ranging in complexity. We outline two below; there may be others as or more effective with acceptable complexity and overhead: </p>
|
||||
|
||||
<ul>
|
||||
<li>(Simplest) A user sending Interests resulting in a T_MTU_TOO_LARGE error is treated similarly to users mounting interest flooding attacks; the a router aggregating Interests with differing expected data sizes rate limits the face(s) exhibiting these errors, thus decreasing the ability of a user to issue enough mis-estimated Interests to collide and generate Interest aggregation.</li>
|
||||
<li>An ICN forwarder aggregating Interests remembers in the PIT entry not only the expected data size of the Interest it forwarded, but the maximum of the expected data size of the other Interests it aggregated. If a T_MTU_TOO_LARGE error comes back, instead of propagating it, the forwarder MAY treat this as a transient error, drop the Interest Return, and re-forward the Interest using the maximum expected data size in the PIT (assuming it is is bigger). This recovers from the error, but the attacker can still cause an extra round trip to the producer or to an upstream forwarder with a copy of the data in its Content Store.</li>
|
||||
</ul>
|
||||
|
||||
<p> </p>
|
||||
<h1 id="rfc.section.5"><a href="#rfc.section.5">5.</a> <a href="#encoding" id="encoding">Mapping to CCNx and NDN packet encodings</a></h1>
|
||||
<p id="rfc.section.5.p.1">The only actual protocol needed is a TLV in Interest messages that states the size in bytes of the expected Data Message coming back, and in the Interest Return on a "too big" error to carry the actual data size. In the case of CCNx, this covers the encapsulated Data Object, but not the hop-by-hop headers.</p>
|
||||
<h1 id="rfc.section.5.1"><a href="#rfc.section.5.1">5.1.</a> <a href="#CCNx-encoding" id="CCNx-encoding">Packet encoding for CCNx</a></h1>
|
||||
<p id="rfc.section.5.1.p.1">For CCNx<a href="#RFC8569">[RFC8569]</a> there is a new hop-by-hop header TLV, and a new value of the Interest Return "Return Type".</p>
|
||||
<div id="rfc.table.1"/>
|
||||
<div id="DataSize"/>
|
||||
<p>Expected Data Size (for Interest messages), or Actual Data Size (for Interest Return messages) TLV</p>
|
||||
<table cellpadding="3" cellspacing="0" class="tt full center">
|
||||
<caption>Data Size TLV</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="center">Abbrev</th>
|
||||
<th class="center">Name</th>
|
||||
<th class="center">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="center">T_DATASIZE</td>
|
||||
<td class="center">Data Size</td>
|
||||
<td class="center">Expected (<a href="#description">Section 3</a>)or Actual (<a href="#toobig">Section 3.2</a>) Data Size</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h1 id="rfc.section.5.2"><a href="#rfc.section.5.2">5.2.</a> <a href="#NDN-encoding" id="NDN-encoding">Packet encoding for NDN</a></h1>
|
||||
<p id="rfc.section.5.2.p.1">TBD based on <a href="#NDNTLV">[NDNTLV]</a>. Suggestions from the NDN team greatly appreciated.</p>
|
||||
<h1 id="rfc.section.6"><a href="#rfc.section.6">6.</a> <a href="#IANA" id="IANA">IANA Considerations</a></h1>
|
||||
<p id="rfc.section.6.p.1">Please Add the T_TIMETLV TLV to the Hop-by-Hop TLV types registry of RFC8609, with fixed length of 2, and data type numeric</p>
|
||||
<div id="rfc.figure.1"/>
|
||||
<div id="timetlv-encoding"/>
|
||||
<p>Expected/Actual Data Size TLV encoding. The range has an upper bound of 64K bytes, since that is the largest MTU supported by CCNx.</p>
|
||||
<pre>
|
||||
1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+---------------+---------------+---------------+---------------+
|
||||
| T_TIMETLV | 2 |
|
||||
+---------------+---------------+---------------+---------------+
|
||||
| INTERVAL_TIME (see RFC4574) |
|
||||
+---------------+---------------+
|
||||
</pre>
|
||||
<p class="figure">Figure 1: Compresssed Time Values using RFC4574 encoding</p>
|
||||
<h1 id="rfc.section.7"><a href="#rfc.section.7">7.</a> <a href="#Security" id="Security">Security Considerations</a></h1>
|
||||
<p/>
|
||||
<h1 id="rfc.references"><a href="#rfc.references">8.</a> References</h1>
|
||||
<h1 id="rfc.references.1"><a href="#rfc.references.1">8.1.</a> Normative References</h1>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="RFC2119">[RFC2119]</b>
|
||||
</td>
|
||||
<td class="top"><a>Bradner, S.</a>, "<a href="http://tools.ietf.org/html/rfc2119">Key words for use in RFCs to Indicate Requirement Levels</a>", BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="RFC8569">[RFC8569]</b>
|
||||
</td>
|
||||
<td class="top"><a>Mosko, M.</a>, <a>Solis, I.</a> and <a>C. Wood</a>, "<a href="http://tools.ietf.org/html/rfc8569">Content-Centric Networking (CCNx) Semantics</a>", RFC 8569, DOI 10.17487/RFC8569, July 2019.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="RFC8609">[RFC8609]</b>
|
||||
</td>
|
||||
<td class="top"><a>Mosko, M.</a>, <a>Solis, I.</a> and <a>C. Wood</a>, "<a href="http://tools.ietf.org/html/rfc8609">Content-Centric Networking (CCNx) Messages in TLV Format</a>", RFC 8609, DOI 10.17487/RFC8609, July 2019.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h1 id="rfc.references.2"><a href="#rfc.references.2">8.2.</a> Informative References</h1>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="Carofiglio2012">[Carofiglio2012]</b>
|
||||
</td>
|
||||
<td class="top"><a>Carofiglio, G.</a>, <a>Gallo, M.</a> and <a>L. Muscariello</a>, "<a href="http://conferences.sigcomm.org/sigcomm/2012/paper/icn/p37.pdf">Joint hop-by-hop and receiver-driven interest control protocol for content-centric networks, in ICN Workshop at SIGcomm 2012</a>", DOI 10.1145/2377677.2377772, 2102.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="Ghali2013">[Ghali2013]</b>
|
||||
</td>
|
||||
<td class="top"><a>Ghali, C.</a>, <a>Narayanan, A.</a>, <a>Oran, D.</a>, <a>Tsudik, G.</a> and <a>C. Wood</a>, "<a href="http://dx.doi.org/10.1109/NCA.2015.34">Secure Fragmentation for Content-Centric Networks, in IEEE 14th International Symposium on Network Computing and Applications</a>", DOI 10.1109/nca.2015.34, 2015.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="I-D.ietf-quic-transport">[I-D.ietf-quic-transport]</b>
|
||||
</td>
|
||||
<td class="top"><a>Iyengar, J.</a> and <a>M. Thomson</a>, "<a href="http://tools.ietf.org/html/draft-ietf-quic-transport-23">QUIC: A UDP-Based Multiplexed and Secure Transport</a>", Internet-Draft draft-ietf-quic-transport-23, September 2019.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="Mahdian2016">[Mahdian2016]</b>
|
||||
</td>
|
||||
<td class="top"><a>Mahdian, M.</a>, <a>Arianfar, S.</a>, <a>Gibson, J.</a> and <a>D. Oran</a>, "<a href="http://conferences2.sigcomm.org/acm-icn/2016/proceedings/p1-mahdian.pdf">MIRCC: Multipath-aware ICN Rate-based Congestion Control, in Proceedings of the 3rd ACM Conference on Information-Centric Networking</a>", DOI 10.1145/2984356.2984365, 2016.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="minmaxfairness">[minmaxfairness]</b>
|
||||
</td>
|
||||
<td class="top"><a>Wikipedia, </a>, "<a href="https://en.wikipedia.org/wiki/Max-min_fairness">Max-min Fairness</a>", various.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="NDN">[NDN]</b>
|
||||
</td>
|
||||
<td class="top"><a>NDN team, </a>, "<a href="https://named-data.net/project/execsummary/">Named Data Networking</a>", various.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="NDNTLV">[NDNTLV]</b>
|
||||
</td>
|
||||
<td class="top"><a>NDN Project Team, </a>, "<a href="http://named-data.net/doc/ndn-tlv/">NDN Packet Format Specification.</a>", 2016.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="proportionalfairness">[proportionalfairness]</b>
|
||||
</td>
|
||||
<td class="top"><a>Wikipedia, </a>, "<a href="https://en.wikipedia.org/wiki/Proportionally_fair">Proportionally Fair</a>", various.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="RFC0793">[RFC0793]</b>
|
||||
</td>
|
||||
<td class="top"><a>Postel, J.</a>, "<a href="http://tools.ietf.org/html/rfc793">Transmission Control Protocol</a>", STD 7, RFC 793, DOI 10.17487/RFC0793, September 1981.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="RFC4340">[RFC4340]</b>
|
||||
</td>
|
||||
<td class="top"><a>Kohler, E.</a>, <a>Handley, M.</a> and <a>S. Floyd</a>, "<a href="http://tools.ietf.org/html/rfc4340">Datagram Congestion Control Protocol (DCCP)</a>", RFC 4340, DOI 10.17487/RFC4340, March 2006.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="RFC4960">[RFC4960]</b>
|
||||
</td>
|
||||
<td class="top"><a>Stewart, R.</a>, "<a href="http://tools.ietf.org/html/rfc4960">Stream Control Transmission Protocol</a>", RFC 4960, DOI 10.17487/RFC4960, September 2007.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="Schneider2016">[Schneider2016]</b>
|
||||
</td>
|
||||
<td class="top"><a>Schneider, K.</a>, <a>Yi, C.</a>, <a>Zhang, B.</a> and <a>L. Zhang</a>, "<a href="http://conferences2.sigcomm.org/acm-icn/2016/proceedings/p21-schneider.pdf">A Practical Congestion Control Scheme for Named Data Networking, in Proceedings of the 2016 conference on 3rd ACM Conference on Information-Centric Networking - ACM-ICN '16</a>", DOI 10.1145/2984356.2984369, 2016.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="Song2018">[Song2018]</b>
|
||||
</td>
|
||||
<td class="top"><a>Song, J.</a>, <a>Lee, M.</a> and <a>T. Kwon</a>, "<a href="https://conferences.sigcomm.org/acm-icn/2018/proceedings/icn18-final62.pdf">SMIC: Subflow-level Multi-path Interest Control for Information Centric Networking, in 5th ACM Conference on Information-Centric Networking</a>", DOI 10.1145/3267955.3267971, 2018.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="Wang2013">[Wang2013]</b>
|
||||
</td>
|
||||
<td class="top"><a>Wang, Y.</a>, <a>Rozhnova, N.</a>, <a>Narayanan, A.</a>, <a>Oran, D.</a> and <a>I. Rhee</a>, "<a href="http://conferences.sigcomm.org/sigcomm/2013/papers/icn/p55.pdf">An Improved Hop-by-hop Interest Shaper for Congestion Control in Named Data Networking, in ACM SIGCOMM Workshop on Information-Centric Networking</a>", DOI 10.1145/2534169.2491233, 2013.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h1 id="rfc.authors">
|
||||
<a href="#rfc.authors">Author's Address</a>
|
||||
</h1>
|
||||
<div class="avoidbreak">
|
||||
<address class="vcard">
|
||||
<span class="vcardline">
|
||||
<span class="fn">Dave Oran</span>
|
||||
<span class="n hidden">
|
||||
<span class="family-name">D. Oran</span>
|
||||
</span>
|
||||
</span>
|
||||
<span class="org vcardline">Network Systems Research and Design</span>
|
||||
<span class="adr">
|
||||
<span class="vcardline">4 Shady Hill Square</span>
|
||||
|
||||
<span class="vcardline">
|
||||
<span class="locality">Cambridge</span>,
|
||||
<span class="region">MA</span>
|
||||
<span class="code">02138</span>
|
||||
</span>
|
||||
<span class="country-name vcardline">USA</span>
|
||||
</span>
|
||||
<span class="vcardline">EMail: <a href="mailto:daveoran@orandom.net">daveoran@orandom.net</a></span>
|
||||
|
||||
</address>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+840
@@ -0,0 +1,840 @@
|
||||
|
||||
|
||||
|
||||
|
||||
ICNRG D. Oran
|
||||
Internet-Draft Network Systems Research and Design
|
||||
Intended status: Experimental August 2019
|
||||
Expires: February 2, 2020
|
||||
|
||||
|
||||
Maintaining CCNx or NDN flow balance with highly variable data object
|
||||
sizes
|
||||
draft-oran-icnrg-flowbalance-02
|
||||
|
||||
Abstract
|
||||
|
||||
Deeply embedded in some ICN architectures, especially Named Data
|
||||
Networking (NDN) and Content-Centric Networking (CCNx) is the notion
|
||||
of flow balance. This captures the idea that there is a one-to-one
|
||||
correspondence between requests for data, carried in Interest
|
||||
messages, and the responses with the requested data object, carried
|
||||
in Data messages. This has a number of highly beneficial properties
|
||||
for flow and congestion control in networks, as well as some
|
||||
desirable security properties. For example, neither legitimate users
|
||||
nor attackers are able to inject large amounts of un-requested data
|
||||
into the network.
|
||||
|
||||
Existing congestion control approaches however cannot deal
|
||||
effectively with a widely varying MTU of ICN data messages, since the
|
||||
protocols allow a dynamic range of 1-64K bytes. Since Interest
|
||||
messages are used to allocate the reverse link bandwidth for
|
||||
returning Data, there is large uncertainty in how to allocate that
|
||||
bandwidth. Unfortunately, current congestion control schemes in CCNx
|
||||
and NDN only count Interest messages and have no idea how much data
|
||||
is involved that could congest the inverse link. This document
|
||||
proposes a method to maintain flow balance by accommodating the wide
|
||||
dynamic range in Data message MTU.
|
||||
|
||||
Status of This Memo
|
||||
|
||||
This Internet-Draft is submitted in full conformance with the
|
||||
provisions of BCP 78 and BCP 79.
|
||||
|
||||
Internet-Drafts are working documents of the Internet Engineering
|
||||
Task Force (IETF). Note that other groups may also distribute
|
||||
working documents as Internet-Drafts. The list of current Internet-
|
||||
Drafts is at http://datatracker.ietf.org/drafts/current/.
|
||||
|
||||
Internet-Drafts are draft documents valid for a maximum of six months
|
||||
and may be updated, replaced, or obsoleted by other documents at any
|
||||
time. It is inappropriate to use Internet-Drafts as reference
|
||||
material or to cite them other than as "work in progress."
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 2, 2020 [Page 1]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance August 2019
|
||||
|
||||
|
||||
This Internet-Draft will expire on February 2, 2020.
|
||||
|
||||
Copyright Notice
|
||||
|
||||
Copyright (c) 2019 IETF Trust and the persons identified as the
|
||||
document authors. All rights reserved.
|
||||
|
||||
This document is subject to BCP 78 and the IETF Trust's Legal
|
||||
Provisions Relating to IETF Documents
|
||||
(http://trustee.ietf.org/license-info) in effect on the date of
|
||||
publication of this document. Please review these documents
|
||||
carefully, as they describe your rights and restrictions with respect
|
||||
to this document. Code Components extracted from this document must
|
||||
include Simplified BSD License text as described in Section 4.e of
|
||||
the Trust Legal Provisions and are provided without warranty as
|
||||
described in the Simplified BSD License.
|
||||
|
||||
Table of Contents
|
||||
|
||||
1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 2
|
||||
2. Requirements Language . . . . . . . . . . . . . . . . . . . . 4
|
||||
3. Method to enhance congestion control with signaled size
|
||||
information in Interest Messages . . . . . . . . . . . . . . 4
|
||||
3.1. How to predict the size of returning Data messages . . . 5
|
||||
3.2. Handling `too big' cases . . . . . . . . . . . . . . . . 6
|
||||
3.3. Handling `too small' cases . . . . . . . . . . . . . . . 7
|
||||
3.4. Interactions with Interest Aggregation . . . . . . . . . 8
|
||||
3.5. Operation when some Interests lack the expected data size
|
||||
option and some have it . . . . . . . . . . . . . . . . . 10
|
||||
4. Dealing with malicious actors . . . . . . . . . . . . . . . . 11
|
||||
5. Mapping to CCNx and NDN packet encodings . . . . . . . . . . 12
|
||||
5.1. Packet encoding for CCNx . . . . . . . . . . . . . . . . 12
|
||||
5.2. Packet encoding for NDN . . . . . . . . . . . . . . . . . 12
|
||||
6. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 12
|
||||
7. Security Considerations . . . . . . . . . . . . . . . . . . . 13
|
||||
8. References . . . . . . . . . . . . . . . . . . . . . . . . . 13
|
||||
8.1. Normative References . . . . . . . . . . . . . . . . . . 13
|
||||
8.2. Informative References . . . . . . . . . . . . . . . . . 13
|
||||
Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 15
|
||||
|
||||
1. Introduction
|
||||
|
||||
Deeply embedded in some ICN architectures, especially Named Data
|
||||
Networking (NDN [NDN]) and Content-Centric Networking (CCNx
|
||||
[RFC8569],[RFC8609]) is the notion of _flow balance_. This captures
|
||||
the idea that there is a one-to-one correspondence between requests
|
||||
for data, carried in Interest messages, and the responses with the
|
||||
requested data object, carried in Data messages. This has a number
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 2, 2020 [Page 2]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance August 2019
|
||||
|
||||
|
||||
of highly beneficial properties for flow and congestion control in
|
||||
networks, as well as some desirable security properties. For
|
||||
example, neither legitimate users nor attackers are able to inject
|
||||
large amounts of un-requested data into the network.
|
||||
|
||||
This approach leads to a desire to make the size of the objects
|
||||
carried in Data messages small and near constant, because flow
|
||||
balance can then be kept using simple bookkeeping of how many
|
||||
Interest messages are outstanding. While simple, constraining Data
|
||||
messages to be quite small - usually on the order of a link Maximum
|
||||
Transmission Unit (MTU) - has some constraints and deleterious
|
||||
effects, among which are:
|
||||
|
||||
o Such small data objects are inconvenient for many applications;
|
||||
their natural data object sizes can be considerably larger than a
|
||||
link MTU.
|
||||
|
||||
o Applications with truly small data objects (e.g. voice packets in
|
||||
an Internet telephony applications) have no way to communicate
|
||||
that to the network, causing resources to still be allocated for
|
||||
MTU-sized data objects
|
||||
|
||||
o When chunking a larger data object into multiple Data messages,
|
||||
each message has to be individually cryptographically hashed and
|
||||
signed, increasing both computational overhead and overall message
|
||||
header size. The signature can be elided when Manifests are used
|
||||
(by signing the Manifest instead), but the overhead of hashing
|
||||
multiple small messages rather than fewer larger ones remains.
|
||||
|
||||
One approach which helps with the last of these is to employ
|
||||
fragmentation for Data messages larger than the Path MTU (PMTU). such
|
||||
messages are carved into smaller pieces for transmission over the
|
||||
link(s). There are three flavors of fragmentation: end-to-end, hop-
|
||||
by-hop with reassembly at every hop, and hop-by-hop with cut-through
|
||||
of individual fragments. A number of ICN protocol architectures
|
||||
incorporate fragmentation and schemes have been proposed for both NDN
|
||||
and CCNx, for example in [Ghali2013]. Fragmentation alone does not
|
||||
ameliorate the flow balance problem however, since from a resource
|
||||
allocation standpoint both memory and link bandwidth must be set
|
||||
aside for maximum-sized data objects to avoid congestion collapse
|
||||
under overload.
|
||||
|
||||
The design space considered in this document does not however extend
|
||||
to arbitrarily large objects (e.g. 100's of kilobytes or larger). As
|
||||
the dynamic range of data object sizes gets very large, finding the
|
||||
right tradeoff between handling a large number of small data objects
|
||||
versus a single very large data object when allocating link and
|
||||
buffer resources becomes intractable. Further, the semantics of
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 2, 2020 [Page 3]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance August 2019
|
||||
|
||||
|
||||
Interest-Data exchanges means that any error in the exchange results
|
||||
in a re-issue of an Interest for the entire Data object. Very large
|
||||
data objects represent a performance problem because the cost of
|
||||
retransmission when Interests are retransmitted (or re-issued)
|
||||
becomes unsustainably high. Therefore, the method we propose deals
|
||||
with a dynamic range of object sizes from very small (a fraction of a
|
||||
link MTU) to moderately large - about 64 kilobytes or equivalently
|
||||
about 40 Ethernet packets, and assumes an associated fragmentation
|
||||
scheme to handle link MTUs that cannot carry the object in a single
|
||||
link-layer packet.
|
||||
|
||||
The approach described in the rest of this document maintains flow
|
||||
balance under the conditions outlined above by allocating resources
|
||||
accurately based on expected data object size, rather than employing
|
||||
simple interest counting.
|
||||
|
||||
2. Requirements Language
|
||||
|
||||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
|
||||
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
|
||||
document are to be interpreted as described in RFC 2119 [RFC2119].
|
||||
|
||||
3. Method to enhance congestion control with signaled size information
|
||||
in Interest Messages
|
||||
|
||||
Before diving into the specifics of the design, it is useful to
|
||||
consider how congestion control works in NDN/CCNx. Unlike the IP
|
||||
protocol family, which relies on end-to-end congestion control (e.g.
|
||||
TCP[RFC0793], DCCP[RFC4340], SCTP[RFC4960],
|
||||
QUIC[I-D.ietf-quic-transport]), CCNx and NDN employ hop-by-hop
|
||||
congestion control. There is per-Interest/Data state at every hop of
|
||||
the path and therefore for each outstanding Interest, bandwidth for
|
||||
data returning on the inverse path can be allocated. In the current
|
||||
design, this allocation is done using simple Interest counting - by
|
||||
accepting one Interest packet from an downstream node, implicitly
|
||||
this provides a guarantee (either hard or soft) that there is
|
||||
sufficient bandwidth on the inverse direction of the link to send
|
||||
back one Data packet. A number of congestion control schemes have
|
||||
been developed that operate in this fashion, for example
|
||||
[Wang2013],[Mahdian2016],[Song2018],[Carofiglio2012]. Other schemes,
|
||||
like [Schneider2016] neither count nor police interests, but instead
|
||||
monitor queues using AQM (active queue management) to mark returning
|
||||
Data packets that have experienced congestion. It is worth noting
|
||||
that every congestion control algorithm has an explicit fairness goal
|
||||
and associated objective function (usually either [minmaxfairness] or
|
||||
[proportionalfairness]). If your fairness is to be based on resource
|
||||
usage, pure interest counting doesn't do the trick, since a consumer
|
||||
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 2, 2020 [Page 4]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance August 2019
|
||||
|
||||
|
||||
asking for large thing can saturate a link and shift loss to
|
||||
consumers asking for small things.
|
||||
|
||||
In order to deal with a larger dynamic range of data object size,
|
||||
some means is required to allocate link bandwidth for data messages
|
||||
in bytes with an upper bound larger than a link PMTU and a lower
|
||||
bound lower than a single link MTU. Since resources are allocated
|
||||
for returning Data based on arriving Interests, this information must
|
||||
be available in Interest messages.
|
||||
|
||||
Therefore, one key idea is the inclusion of an _expected data size_
|
||||
TLV in each Interest message. This allows each forwarder on the path
|
||||
taken by the interest to accurately allocate bandwidth on the inverse
|
||||
path for the returning Data message. Also, by including the expected
|
||||
data size, large objects will have a corresponding weight in resource
|
||||
allocation, maintaining link and forwarder buffering fairness. The
|
||||
simpler Interest counting scheme was nominally "fair" on a per-
|
||||
exchange basis within the variations of data that fit in a single
|
||||
PMTU packet because all Interests produced similar amounts of data in
|
||||
return. In the absence of such a field, it is not feasible to allow
|
||||
a large dynamic range in object size. While schemes like
|
||||
[Schneider2016] would not employ the expected data size to allocate
|
||||
reverse link bandwidth, they can still benefit from the information
|
||||
to affect the AQM congestion marking algorithm, preferentially
|
||||
marking data packets that exceed the expected data size.
|
||||
|
||||
3.1. How to predict the size of returning Data messages
|
||||
|
||||
This of course raises the question "How does the requester know how
|
||||
big the corresponding data coming back will be?". For a number of
|
||||
important applications, the size is known a priori due to the
|
||||
characteristics of the application. Here are some examples:
|
||||
|
||||
o For many sensor and other Internet-of-Things applications, the
|
||||
data is instrument readings which have fixed known size.
|
||||
|
||||
o In video streaming, the data is output of a video encoder which
|
||||
produces variable sized frames. This information is typically
|
||||
made available ahead of time to the streaming clients in the form
|
||||
of a Manifest [4], which contains the names of the corresponding
|
||||
segments (or individual frames) of video and audio and their
|
||||
sizes.
|
||||
|
||||
o Internet telephony applications use vocoders that typically employ
|
||||
fixed-size audio frames. Therefore, their size is known either a
|
||||
priori, or via an initialization exchange at the start of an audio
|
||||
session.
|
||||
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 2, 2020 [Page 5]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance August 2019
|
||||
|
||||
|
||||
The more complex cases arise where the data size is not known at the
|
||||
time the Interest must be sent. Much of the nuance of the proposed
|
||||
scheme is in how mismatches between the expected data size and the
|
||||
actual data object returned are handled. The consumer can either
|
||||
under- or over-estimate the data size. In the former case, the
|
||||
under-estimate can lead to congestion and possible loss of data. In
|
||||
the latter case, bandwidth that could have been used by data objects
|
||||
requested by other consumers might be wasted. We first consider
|
||||
"honest" mis-estimates due to imperfect knowledge by the ICN
|
||||
application; later we consider malicious applications that are using
|
||||
the machinery to mount some form of attack. We also consider the
|
||||
effects of Interest aggregation if the aggregated Interests have
|
||||
differing expected data sizes. Also, it should be obvious that if
|
||||
the Data message arrives, the application learns its actual size,
|
||||
which may or may not be useful in adjusting the expected data size
|
||||
estimate for future Interests.
|
||||
|
||||
In all cases, the expected data size from the Interest can be
|
||||
incorporated in the corresponding Pending Interest Table (PIT) entry
|
||||
of each CCNx/NDN forwarder on the path and hence when a (possibly
|
||||
fragmented) Data object comes back, its total size is known and can
|
||||
be compared to the expected size in the PIT for a mismatch. Aside:
|
||||
In the case of fragmentation, we assume a fragmentation scheme in
|
||||
which the total data size can be known as soon as any one fragment is
|
||||
received (a reasonable assumption for most any well-designed
|
||||
fragmentation method).
|
||||
|
||||
3.2. Handling `too big' cases
|
||||
|
||||
If the returning data is larger than the expected data size, the
|
||||
extra data could result in either unfair bandwidth allocation or
|
||||
possibly data loss under congestion conditions. When this is
|
||||
detected, the forwarder has three choices:
|
||||
|
||||
1. It could forward the data anyway, which is safe under non-
|
||||
congestion conditions, but unfair and possibly unstable when the
|
||||
output link is congested
|
||||
|
||||
2. It could forward the data when un-congested (e.g. by assessing
|
||||
output queue depth) but drop it when congested
|
||||
|
||||
3. It could always drop the data, as a way of "punishing" the
|
||||
requester for the mis-estimate.
|
||||
|
||||
Either of the latter two strategies is acceptable from a congestion
|
||||
control point of view. However, it is not a good idea to simply drop
|
||||
the Data message with no feedback to the issuer of the Interest
|
||||
because the application has no way to learn the actual data size and
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 2, 2020 [Page 6]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance August 2019
|
||||
|
||||
|
||||
retry. Further, recovery would be delayed until the failing Interest
|
||||
timed out. Therefore, an additional element needed in protocol
|
||||
semantics is the incorporation of a "Data too big" error message (via
|
||||
an "interest Return" packet in CCNx).
|
||||
|
||||
Upon dropping data as above, the CCNx/NDN forwarder converts the
|
||||
normal Data message into an Interest Return message containing the
|
||||
with the T_MTU_TOO_LARGE error code and the actual size of the data
|
||||
object instead of the data object content. It propagates that back
|
||||
toward the client identically to how the original Data message would
|
||||
have been handled. Subsequent nodes upon receiving the
|
||||
T_MTU_TOO_LARGE error treat it as all other Interest Return errors.
|
||||
When the Interest Return eventually arrives back to the issuer of the
|
||||
Interest, the user can, they desire, reissue the Interest with the
|
||||
correct expected data size.
|
||||
|
||||
One detail to note is that an Interest Return carrying
|
||||
T_MTU_TOO_LARGE must be deterministically smaller than the expected
|
||||
data size in all cases. This is clearly the case for large data
|
||||
objects, but there is a corner case with small data objects. There
|
||||
has to be a minimum expected data size that a client can specify in
|
||||
their Interests, and that minimum cannot be smaller than the size of
|
||||
a T_MTU_TOO_LARGE Interest Return
|
||||
|
||||
3.3. Handling `too small' cases
|
||||
|
||||
Next we consider the case where the returning data is smaller than
|
||||
the expected data size. While this case does not result in
|
||||
congestion, it can cause resources to be inefficiently allocated
|
||||
because not all of the set-aside bandwidth for the returning data
|
||||
object gets used. The simplest and most straightforward way to deal
|
||||
with this case is to essentially ignore it. The motivation for not
|
||||
worrying about the smaller data mismatch is that in many situations
|
||||
that employ usage-based resource measurement (and possibly charging),
|
||||
it is trivial to just account for the usage according to the larger
|
||||
expected data size rather than actual returned data size. Properly
|
||||
adjusting congestion control parameters to somehow penalize users for
|
||||
over-estimating their resource usage requires fairly heavyweight
|
||||
machinery, which in most cases is not warranted. If desired, any of
|
||||
the following mechanisms could be considered:
|
||||
|
||||
o Attempt to identify future Interests for the same object or
|
||||
closely related objects and allocate resources based on some
|
||||
retained state about the actual size of prior objects
|
||||
|
||||
o Police consumer behavior and decrease the expected data size in
|
||||
one or more future Interests to compensate
|
||||
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 2, 2020 [Page 7]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance August 2019
|
||||
|
||||
|
||||
o For small objects, do more optimistic resource allocation on the
|
||||
links on the presumption that there will be some "slack" due to
|
||||
clients overestimating data object size.
|
||||
|
||||
One protocol detail of CCNx/NDN that needs to be dealt with is
|
||||
Interest Aggregation. This happens when multiple Interests arrive at
|
||||
a forwarder for the same Named object. These are aggregated such
|
||||
that one of them (i.e.the first to arrive and create PIT state) is
|
||||
forwarded, and the rest are dropped while marking the arrival face so
|
||||
the data can be sent back to the multiple requesting clients.
|
||||
Interest aggregation interacts with expected data size if Interests
|
||||
from different clients contain different values of the expected data
|
||||
size. As above, the simplest solution to this problem is to ignore
|
||||
it, as most error cases are benign. However, there is one
|
||||
problematic error case where one client provides an accurate expected
|
||||
data size, but another who issued the Interest first underestimates,
|
||||
causing both to receive a Data too big error. This introduces a
|
||||
denial of service vulnerability, which we discuss below together with
|
||||
the other malicious actor cases.
|
||||
|
||||
3.4. Interactions with Interest Aggregation
|
||||
|
||||
Interest Aggregation, while a powerful feature for maintaining flow
|
||||
balance when multiple consumers send Interests for the same Named
|
||||
object, introduces subtle complications. Whenever a second or
|
||||
subsequent Interest arrives at a forwarder with an active PIT entry
|
||||
it is possible that those Interests carry different parameters, for
|
||||
example hop limit, payload, etc. It is therefore necessary to
|
||||
specify the exact behavior of the forwarder for each of the
|
||||
parameters that might differ. In the case of the expected data size
|
||||
parameter defined here, the value is associated with the ingress face
|
||||
on which the Interest creating the PIT entry arrived, as opposed to
|
||||
being global to the PIT entry as a whole. There are two cases to
|
||||
consider:
|
||||
|
||||
1. The arriving interest carries an expected data size smaller than
|
||||
any of the values associated with the PIT entry.
|
||||
|
||||
2. The arriving interest carries an expected data size larger than
|
||||
any of the values associated with the PIT entry.
|
||||
|
||||
For Case (1) the Interest can be safely aggregated since the upstream
|
||||
links will have sufficient bandwidth allocated based on the larger
|
||||
expected data size (assuming the original Interest's expected data
|
||||
size was itself sufficiently large to accommodate the actual size of
|
||||
the returning Data. On the other hand, should the incoming face have
|
||||
bandwidth allocated based on the larger existing Interest's expected
|
||||
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 2, 2020 [Page 8]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance August 2019
|
||||
|
||||
|
||||
data size, or on the smaller value in the arriving interest? Here
|
||||
there are two possible approaches:
|
||||
|
||||
a. Allocate based on the data size already in the PIT. In this case
|
||||
the consumer sending the earlier Interest can cause over-
|
||||
allocation of link bandwidth for other incoming faces, but there
|
||||
will not be a T_MTU_TOO_LARGE error generated for that Interest
|
||||
|
||||
b. Allocate based on the value in the arriving Interest. If the
|
||||
returning Data is in fact larger, generate a T_MTU_TOO_LARGE
|
||||
Interest Return on that ingress face, while successfully
|
||||
returning the Data message on any faces that do not exhibit a too
|
||||
small expected data size
|
||||
|
||||
It is RECOMMENDED that the second policy be followed. The reasons
|
||||
behind this recommendation are as follows:
|
||||
|
||||
1. The link can be congested quite quickly after the queuing
|
||||
decision is made, especially if the data has a long link-
|
||||
occupancy time, so this is a safer alternative.
|
||||
|
||||
2. The cost of returning the error is only one link RTT, since the
|
||||
consumer (or downstream forwarder) can immediately re-issue the
|
||||
interest with the correct size and pick up the cached object from
|
||||
the upstream forwarder's Content Store.
|
||||
|
||||
3. Being optimistic and returning the data interacts with the
|
||||
behavior of aggregate resource control and resource accounting,
|
||||
which in turn raises the messy issue of whether to "charge" the
|
||||
consumer for the actual bandwidth used or only for the requested
|
||||
bandwidth in the expected data.
|
||||
|
||||
4. The rabbit hole goes deeper if you add differential QoS to the
|
||||
equation or consumers "playing games" and intentionally
|
||||
underestimating so their interests get satisfied when links
|
||||
aren't congested. This makes handling malicious actors
|
||||
(Section 4) more difficult.
|
||||
|
||||
For Case (2) above, the Interest MUST be forwarded rather than
|
||||
aggregated to prevent a consumer from mounting a denial of service
|
||||
attack by sending intentionally too small expected data size (see
|
||||
Section 4 for additional detail on this and other attacks). As above
|
||||
for Case (1) it is RECOMMENDED that policy (b) above be followed.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 2, 2020 [Page 9]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance August 2019
|
||||
|
||||
|
||||
3.5. Operation when some Interests lack the expected data size option
|
||||
and some have it
|
||||
|
||||
Since the expected data size hop-by-hop option forwarders need to be
|
||||
prepared to handle an arbitrary mix of the two forms. There are two
|
||||
general things to address.
|
||||
|
||||
First, we assume that any forwarder supporting expected data size is
|
||||
running a more sophisticated congestion control algorithm that one
|
||||
employing simple interest counting. The link bandwidth resource
|
||||
allocation is therefore based directly, or indirectly, on the
|
||||
expected Data size in bytes. Therefore, the forwarder has to assign
|
||||
a value to use in the resource allocation for the reverse link. This
|
||||
specification does not mandate any particular approach or a default
|
||||
value to use. However, in the absence on other guidance, it makes
|
||||
sense to do one of two things:
|
||||
|
||||
1. Pick a default based on the link MTU of the face on which the
|
||||
Interest arrived and use that for all Interests lacking an
|
||||
expected data size. This is likely to be most compatible with
|
||||
simple interest counting which would rate limit all incoming
|
||||
interests equally
|
||||
|
||||
2. Configure some values for given Name prefixes that have known
|
||||
sizes. This may be appropriate for dedicated forwarders
|
||||
supporting single use cases, such as:
|
||||
|
||||
* A forwarder handling IoT sensors sending very small Data
|
||||
packets
|
||||
|
||||
* A forwarder handling real-time video with large average Data
|
||||
packets that exceed link MTU and are routinely fragmented
|
||||
|
||||
* A forwarder doing voice trunking where the vocoders produce
|
||||
moderate sized packets, still much smaller than the link MTU
|
||||
|
||||
The second area to address is what to do if an interest lacking an
|
||||
expected Data size is responded to by a Data message whose size
|
||||
exceeds the default discussed above. It would be inappropriate to
|
||||
issue a T_MTU_TOO_LARGE error, since the consumer is unlikely to
|
||||
understand or deal correctly with that new error case. Instead, it
|
||||
is RECOMMENDED that the forwarder:
|
||||
|
||||
o Ignore the mismatch if the reverse link is not congested and
|
||||
return the requested Data message anyway.
|
||||
|
||||
o If the reverse link is congested, issue an Interest Return with
|
||||
the T_NO_RESOURCES error code
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 2, 2020 [Page 10]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance August 2019
|
||||
|
||||
|
||||
This specification does not define or recommend any particular
|
||||
algorithm for assessing the congestion state of the link(s) to carry
|
||||
the Data message downstream to the requesting consumers. It is
|
||||
assumed that a reasonable algorithm is in use, because otherwise even
|
||||
basic Interest counting forms of congestion control would not be
|
||||
effective.
|
||||
|
||||
4. Dealing with malicious actors
|
||||
|
||||
First we note that various known attacks in CCNx or NDN can also be
|
||||
mounted by users employing this method. Attacks that involve
|
||||
interest flooding, cache pollution, cache poisoning, etc. are neither
|
||||
worsened nor ameliorated by the introduction of the congestion
|
||||
control capabilities described here. However, there are two new
|
||||
vulnerabilities that need to be dealt with. These two new
|
||||
vulnerabilities involve intentional mis-estimation of data size.
|
||||
|
||||
The first is a consumer who intentionally over-estimates data size
|
||||
with the goal of preventing other users from using the bandwidth.
|
||||
This is at most a minor concern given the above discussion of over-
|
||||
estimation by honest clients. If one of the amelioration techniques
|
||||
above are used, the case of malicious over-estimation is also dealt
|
||||
with adequately.
|
||||
|
||||
The second is a user who intentionally under-estimates the data size
|
||||
with the goal having its Interest processed while the other
|
||||
aggregated interests are not processed, thereby causing
|
||||
T_MTU_TOO_LARGE errors and denying service to the other users with
|
||||
overlapping requests. There are a number of possible mitigation
|
||||
techniques for this attack vector, ranging in complexity. We outline
|
||||
two below; there may be others as or more effective with acceptable
|
||||
complexity and overhead:
|
||||
|
||||
o (Simplest) A user sending Interests resulting in a T_MTU_TOO_LARGE
|
||||
error is treated similarly to users mounting interest flooding
|
||||
attacks; the a router aggregating Interests with differing
|
||||
expected data sizes rate limits the face(s) exhibiting these
|
||||
errors, thus decreasing the ability of a user to issue enough mis-
|
||||
estimated Interests to collide and generate Interest aggregation.
|
||||
|
||||
o An ICN forwarder aggregating Interests remembers in the PIT entry
|
||||
not only the expected data size of the Interest it forwarded, but
|
||||
the maximum of the expected data size of the other Interests it
|
||||
aggregated. If a T_MTU_TOO_LARGE error comes back, instead of
|
||||
propagating it, the forwarder MAY treat this as a transient error,
|
||||
drop the Interest Return, and re-forward the Interest using the
|
||||
maximum expected data size in the PIT (assuming it is is bigger).
|
||||
This recovers from the error, but the attacker can still cause an
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 2, 2020 [Page 11]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance August 2019
|
||||
|
||||
|
||||
extra round trip to the producer or to an upstream forwarder with
|
||||
a copy of the data in its Content Store.
|
||||
|
||||
5. Mapping to CCNx and NDN packet encodings
|
||||
|
||||
The only actual protocol needed is a TLV in Interest messages that
|
||||
states the size in bytes of the expected Data Message coming back,
|
||||
and in the Interest Return on a "too big" error to carry the actual
|
||||
data size. In the case of CCNx, this covers the encapsulated Data
|
||||
Object, but not the hop-by-hop headers.
|
||||
|
||||
5.1. Packet encoding for CCNx
|
||||
|
||||
For CCNx[RFC8569] there is a new hop-by-hop header TLV, and a new
|
||||
value of the Interest Return "Return Type".
|
||||
|
||||
Expected Data Size (for Interest messages), or Actual Data Size (for
|
||||
Interest Return messages) TLV
|
||||
|
||||
+------------+----------+-------------------------------------------+
|
||||
| Abbrev | Name | Description |
|
||||
+------------+----------+-------------------------------------------+
|
||||
| T_DATASIZE | Data | Expected (Section 3)or Actual (Section |
|
||||
| | Size | 3.2) Data Size |
|
||||
+------------+----------+-------------------------------------------+
|
||||
|
||||
Table 1: Data Size TLV
|
||||
|
||||
5.2. Packet encoding for NDN
|
||||
|
||||
TBD based on [NDNTLV]. Suggestions from the NDN team greatly
|
||||
appreciated.
|
||||
|
||||
6. IANA Considerations
|
||||
|
||||
Please Add the T_TIMETLV TLV to the Hop-by-Hop TLV types registry of
|
||||
RFC8609, with fixed length of 2, and data type numeric
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 2, 2020 [Page 12]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance August 2019
|
||||
|
||||
|
||||
Expected/Actual Data Size TLV encoding. The range has an upper bound
|
||||
of 64K bytes, since that is the largest MTU supported by CCNx.
|
||||
|
||||
1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+---------------+---------------+---------------+---------------+
|
||||
| T_TIMETLV | 2 |
|
||||
+---------------+---------------+---------------+---------------+
|
||||
| INTERVAL_TIME (see RFC4574) |
|
||||
+---------------+---------------+
|
||||
|
||||
Figure 1: Compresssed Time Values using RFC4574 encoding
|
||||
|
||||
7. Security Considerations
|
||||
|
||||
8. References
|
||||
|
||||
8.1. Normative References
|
||||
|
||||
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
|
||||
Requirement Levels", BCP 14, RFC 2119,
|
||||
DOI 10.17487/RFC2119, March 1997, <https://www.rfc-
|
||||
editor.org/info/rfc2119>.
|
||||
|
||||
[RFC8569] Mosko, M., Solis, I., and C. Wood, "Content-Centric
|
||||
Networking (CCNx) Semantics", RFC 8569,
|
||||
DOI 10.17487/RFC8569, July 2019, <https://www.rfc-
|
||||
editor.org/info/rfc8569>.
|
||||
|
||||
[RFC8609] Mosko, M., Solis, I., and C. Wood, "Content-Centric
|
||||
Networking (CCNx) Messages in TLV Format", RFC 8609,
|
||||
DOI 10.17487/RFC8609, July 2019, <https://www.rfc-
|
||||
editor.org/info/rfc8609>.
|
||||
|
||||
8.2. Informative References
|
||||
|
||||
[Carofiglio2012]
|
||||
Carofiglio, G., Gallo, M., and L. Muscariello, "Joint hop-
|
||||
by-hop and receiver-driven interest control protocol for
|
||||
content-centric networks, in ICN Workshop at SIGcomm
|
||||
2012", DOI 10.1145/2377677.2377772, 2102,
|
||||
<http://conferences.sigcomm.org/sigcomm/2012/paper/icn/
|
||||
p37.pdf>.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 2, 2020 [Page 13]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance August 2019
|
||||
|
||||
|
||||
[Ghali2013]
|
||||
Ghali, C., Narayanan, A., Oran, D., Tsudik, G., and C.
|
||||
Wood, "Secure Fragmentation for Content-Centric Networks,
|
||||
in IEEE 14th International Symposium on Network Computing
|
||||
and Applications", DOI 10.1109/nca.2015.34, 2015,
|
||||
<http://dx.doi.org/10.1109/NCA.2015.34>.
|
||||
|
||||
[I-D.ietf-quic-transport]
|
||||
Iyengar, J. and M. Thomson, "QUIC: A UDP-Based Multiplexed
|
||||
and Secure Transport", draft-ietf-quic-transport-23 (work
|
||||
in progress), September 2019.
|
||||
|
||||
[Mahdian2016]
|
||||
Mahdian, M., Arianfar, S., Gibson, J., and D. Oran,
|
||||
"MIRCC: Multipath-aware ICN Rate-based Congestion Control,
|
||||
in Proceedings of the 3rd ACM Conference on Information-
|
||||
Centric Networking", DOI 10.1145/2984356.2984365, 2016,
|
||||
<http://conferences2.sigcomm.org/acm-icn/2016/proceedings/
|
||||
p1-mahdian.pdf>.
|
||||
|
||||
[minmaxfairness]
|
||||
Wikipedia, , "Max-min Fairness", various,
|
||||
<https://en.wikipedia.org/wiki/Max-min_fairness>.
|
||||
|
||||
[NDN] NDN team, , "Named Data Networking", various,
|
||||
<https://named-data.net/project/execsummary/>.
|
||||
|
||||
[NDNTLV] NDN Project Team, , "NDN Packet Format Specification.",
|
||||
2016, <http://named-data.net/doc/ndn-tlv/>.
|
||||
|
||||
[proportionalfairness]
|
||||
Wikipedia, , "Proportionally Fair", various,
|
||||
<https://en.wikipedia.org/wiki/Proportionally_fair>.
|
||||
|
||||
[RFC0793] Postel, J., "Transmission Control Protocol", STD 7,
|
||||
RFC 793, DOI 10.17487/RFC0793, September 1981,
|
||||
<https://www.rfc-editor.org/info/rfc793>.
|
||||
|
||||
[RFC4340] Kohler, E., Handley, M., and S. Floyd, "Datagram
|
||||
Congestion Control Protocol (DCCP)", RFC 4340,
|
||||
DOI 10.17487/RFC4340, March 2006, <https://www.rfc-
|
||||
editor.org/info/rfc4340>.
|
||||
|
||||
[RFC4960] Stewart, R., Ed., "Stream Control Transmission Protocol",
|
||||
RFC 4960, DOI 10.17487/RFC4960, September 2007,
|
||||
<https://www.rfc-editor.org/info/rfc4960>.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 2, 2020 [Page 14]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance August 2019
|
||||
|
||||
|
||||
[Schneider2016]
|
||||
Schneider, K., Yi, C., Zhang, B., and L. Zhang, "A
|
||||
Practical Congestion Control Scheme for Named Data
|
||||
Networking, in Proceedings of the 2016 conference on 3rd
|
||||
ACM Conference on Information-Centric Networking - ACM-ICN
|
||||
'16", DOI 10.1145/2984356.2984369, 2016,
|
||||
<http://conferences2.sigcomm.org/acm-icn/2016/proceedings/
|
||||
p21-schneider.pdf>.
|
||||
|
||||
[Song2018]
|
||||
Song, J., Lee, M., and T. Kwon, "SMIC: Subflow-level
|
||||
Multi-path Interest Control for Information Centric
|
||||
Networking, in 5th ACM Conference on Information-Centric
|
||||
Networking", DOI 10.1145/3267955.3267971, 2018,
|
||||
<https://conferences.sigcomm.org/acm-icn/2018/proceedings/
|
||||
icn18-final62.pdf>.
|
||||
|
||||
[Wang2013]
|
||||
Wang, Y., Rozhnova, N., Narayanan, A., Oran, D., and I.
|
||||
Rhee, "An Improved Hop-by-hop Interest Shaper for
|
||||
Congestion Control in Named Data Networking, in ACM
|
||||
SIGCOMM Workshop on Information-Centric Networking",
|
||||
DOI 10.1145/2534169.2491233, 2013,
|
||||
<http://conferences.sigcomm.org/sigcomm/2013/papers/icn/
|
||||
p55.pdf>.
|
||||
|
||||
Author's Address
|
||||
|
||||
Dave Oran
|
||||
Network Systems Research and Design
|
||||
4 Shady Hill Square
|
||||
Cambridge, MA 02138
|
||||
USA
|
||||
|
||||
Email: daveoran@orandom.net
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 2, 2020 [Page 15]
|
||||
+684
@@ -0,0 +1,684 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
|
||||
<head profile="http://www.w3.org/2006/03/hcard http://dublincore.org/documents/2008/08/04/dc-html/">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />
|
||||
|
||||
<title>Maintaining CCNx or NDN flow balance with highly variable data object sizes </title>
|
||||
|
||||
|
||||
<style type="text/css">/*<![CDATA[*/
|
||||
|
||||
body {
|
||||
font: 16px "Helvetica Neue","Open Sans",Helvetica,Calibri,sans-serif;
|
||||
color: #333;
|
||||
font-size-adjust: 0.5;
|
||||
line-height: 24px;
|
||||
margin: 75px auto;
|
||||
max-width: 624px;
|
||||
padding: 0 5px;
|
||||
}
|
||||
|
||||
.title, .filename, h1, h2, h3, h4, h5 {
|
||||
font: 16px "Roboto Condensed","Helvetica Neue","Open Sans",Helvetica,Calibri,sans-serif;
|
||||
font-size-adjust: 0.5;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
line-height: 100%;
|
||||
margin: 1.2em 0 0.3em;
|
||||
}
|
||||
.title, #rfc\.title h1 { font-size: 32px; }
|
||||
h1, section h1, h2, section h2, section h3, nav h2 { font-size: 20px; }
|
||||
h3, section h4, h4, section h5 { font-size: 16px; }
|
||||
h1 a[href], h2 a[href], h3 a[href], h4 a[href] {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
table {
|
||||
margin-left: 0em;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
th {
|
||||
text-align: left;
|
||||
border-bottom: 2px solid #ddd;
|
||||
}
|
||||
td {
|
||||
border-top: 1px solid #ddd;
|
||||
vertical-align: top;
|
||||
}
|
||||
tr:nth-child(2n+1) > td,
|
||||
tr:nth-child(2n+1) > th {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
td.reference {
|
||||
max-width: 200px;
|
||||
border-top: none;
|
||||
padding-right: 1em;
|
||||
}
|
||||
.right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
|
||||
table.header, table#rfc\.headerblock {
|
||||
width: 100%;
|
||||
}
|
||||
table.header td, table#rfc\.headerblock td {
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
color: black;
|
||||
padding: 0;
|
||||
}
|
||||
.filename {
|
||||
display: block;
|
||||
color: rgb(119, 119, 119);
|
||||
font-size: 20px;
|
||||
font-weight: normal;
|
||||
line-height: 100%;
|
||||
margin: 10px 0 32px;
|
||||
}
|
||||
#rfc\.abstract+p, #rfc\.abstract+p code, #rfc\.abstract+p samp, #rfc\.abstract+p tt {
|
||||
font-size: 20px;
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
samp, tt, code, pre, span.tt {
|
||||
font-size: 13.5px;
|
||||
font-family: Consolas, monospace;
|
||||
font-size-adjust: none;
|
||||
}
|
||||
pre {
|
||||
background-color: #eee;
|
||||
border: 1px solid #ddd;
|
||||
overflow-x: auto;
|
||||
padding: 5px;
|
||||
margin: 5px;
|
||||
}
|
||||
.figure, caption {
|
||||
font-style: italic;
|
||||
margin: 0 1.5em;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
address {
|
||||
margin: 16px 2px;
|
||||
line-height: 20px;
|
||||
}
|
||||
.vcard {
|
||||
font-style: normal;
|
||||
}
|
||||
.vcardline {
|
||||
display: block;
|
||||
}
|
||||
.vcardline .fn, address b {
|
||||
font-weight: normal;
|
||||
}
|
||||
.vcardline .hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
dl {
|
||||
margin-left: 1em;
|
||||
}
|
||||
dl.dl-horizontal: {
|
||||
margin-left: 0;
|
||||
}
|
||||
dl > dt {
|
||||
float: left;
|
||||
margin-right: 1em;
|
||||
}
|
||||
dl.nohang > dt {
|
||||
float: none;
|
||||
}
|
||||
dl > dd {
|
||||
margin-bottom: .5em;
|
||||
}
|
||||
dl.compact > dd {
|
||||
margin-bottom: 0em;
|
||||
}
|
||||
dl > dd > dl {
|
||||
margin-top: 0.5em;
|
||||
margin-bottom: 0em;
|
||||
}
|
||||
ul.empty {
|
||||
list-style-type: none;
|
||||
}
|
||||
ul.empty li {
|
||||
margin-top: .5em;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 0;
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
hr.noprint {
|
||||
display: none;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
a[href] {
|
||||
color: #2a6496;
|
||||
}
|
||||
a[href]:hover {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
p, ol, ul, li {
|
||||
padding: 0;
|
||||
}
|
||||
p {
|
||||
margin: 0.5em 0;
|
||||
}
|
||||
ol, ul {
|
||||
margin: 0.2em 0 0.2em 2em;
|
||||
}
|
||||
li {
|
||||
margin: 0.2em 0;
|
||||
}
|
||||
address {
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
ul.toc ul {
|
||||
margin: 0 0 0 2em;
|
||||
}
|
||||
ul.toc li {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 924px) {
|
||||
body {
|
||||
padding-right: 350px;
|
||||
}
|
||||
body>ul.toc, body>#rfc\.toc {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
right: calc(50vw - 500px);
|
||||
width: 300px;
|
||||
z-index: 1;
|
||||
overflow: auto;
|
||||
overscroll-behavior: contain;
|
||||
}
|
||||
body>#rfc\.toc {
|
||||
top: 55px;
|
||||
}
|
||||
body>ul.toc {
|
||||
top: 100px;
|
||||
}
|
||||
|
||||
ul.toc {
|
||||
margin: 0 0 0 4px;
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
}
|
||||
ul.toc ul {
|
||||
margin-left: 1.2em;
|
||||
}
|
||||
}
|
||||
|
||||
.github-fork-ribbon-wrapper {
|
||||
display: none;
|
||||
}
|
||||
@media screen and (min-width: 800px) {
|
||||
/* "Fork me on GitHub" CSS ribbon based on
|
||||
* https://github.com/simonwhitaker/github-fork-ribbon-css
|
||||
*/
|
||||
.github-fork-ribbon {
|
||||
position: absolute;
|
||||
padding: 2px 0;
|
||||
background-color: #a00;
|
||||
background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15));
|
||||
box-shadow: 0 2px 3px 0 rgba(0, 0, 0, 0.5);
|
||||
font: 700 12px "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
|
||||
pointer-events: auto;
|
||||
|
||||
top: 38px;
|
||||
right: -45px;
|
||||
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.github-fork-ribbon a[href],
|
||||
.github-fork-ribbon a[href]:hover {
|
||||
color: #fff;
|
||||
background-color: transparent;
|
||||
text-decoration: none;
|
||||
text-shadow: 0 -1px rgba(0, 0, 0, 0.5);
|
||||
text-align: center;
|
||||
|
||||
width: 190px;
|
||||
line-height: 18px;
|
||||
|
||||
display: inline-block;
|
||||
padding: 2px 0;
|
||||
|
||||
border: 1.5px dotted #fff;
|
||||
border-color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
.github-fork-ribbon-wrapper {
|
||||
display: block;
|
||||
width: 130px;
|
||||
height: 130px;
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
top: 0; right: 0;
|
||||
z-index: 2;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
@media screen and (min-width: 1000px) {
|
||||
.github-fork-ribbon-wrapper {
|
||||
position: fixed;
|
||||
}
|
||||
/*]]>*/</style>
|
||||
<meta name="viewport" content="initial-scale=1.0">
|
||||
|
||||
|
||||
<link href="#rfc.toc" rel="Contents"/>
|
||||
<link href="#rfc.section.1" rel="Chapter" title="1 Introduction"/>
|
||||
<link href="#rfc.section.2" rel="Chapter" title="2 Requirements Language"/>
|
||||
<link href="#rfc.section.3" rel="Chapter" title="3 Method to enhance congestion control with signaled size information in Interest Messages"/>
|
||||
<link href="#rfc.section.3.1" rel="Chapter" title="3.1 How to predict the size of returning Data messages"/>
|
||||
<link href="#rfc.section.3.2" rel="Chapter" title="3.2 Handling `too big' cases"/>
|
||||
<link href="#rfc.section.3.3" rel="Chapter" title="3.3 Handling `too small' cases"/>
|
||||
<link href="#rfc.section.3.4" rel="Chapter" title="3.4 Interactions with Interest Aggregation"/>
|
||||
<link href="#rfc.section.3.5" rel="Chapter" title="3.5 Operation when some Interests lack the expected data size option and some have it"/>
|
||||
<link href="#rfc.section.4" rel="Chapter" title="4 Dealing with malicious actors"/>
|
||||
<link href="#rfc.section.5" rel="Chapter" title="5 Mapping to CCNx and NDN packet encodings"/>
|
||||
<link href="#rfc.section.5.1" rel="Chapter" title="5.1 Packet encoding for CCNx"/>
|
||||
<link href="#rfc.section.5.2" rel="Chapter" title="5.2 Packet encoding for NDN"/>
|
||||
<link href="#rfc.section.6" rel="Chapter" title="6 IANA Considerations"/>
|
||||
<link href="#rfc.section.7" rel="Chapter" title="7 Security Considerations"/>
|
||||
<link href="#rfc.references" rel="Chapter" title="8 References"/>
|
||||
<link href="#rfc.references.1" rel="Chapter" title="8.1 Normative References"/>
|
||||
<link href="#rfc.references.2" rel="Chapter" title="8.2 Informative References"/>
|
||||
<link href="#rfc.authors" rel="Chapter"/>
|
||||
|
||||
|
||||
<meta name="generator" content="xml2rfc version 2.5.2 - http://tools.ietf.org/tools/xml2rfc" />
|
||||
<link rel="schema.dct" href="http://purl.org/dc/terms/" />
|
||||
|
||||
<meta name="dct.creator" content="D. Oran, " />
|
||||
<meta name="dct.identifier" content="urn:ietf:id:draft-oran-icnrg-flowbalance-latest" />
|
||||
<meta name="dct.issued" scheme="ISO8601" content="2019-8" />
|
||||
<meta name="dct.abstract" content="Deeply embedded in some ICN architectures, especially Named Data Networking (NDN) and Content-Centric Networking (CCNx) is the notion of flow balance. This captures the idea that there is a one-to-one correspondence between requests for data, carried in Interest messages, and the responses with the requested data object, carried in Data messages. This has a number of highly beneficial properties for flow and congestion control in networks, as well as some desirable security properties. For example, neither legitimate users nor attackers are able to inject large amounts of un-requested data into the network." />
|
||||
<meta name="description" content="Deeply embedded in some ICN architectures, especially Named Data Networking (NDN) and Content-Centric Networking (CCNx) is the notion of flow balance. This captures the idea that there is a one-to-one correspondence between requests for data, carried in Interest messages, and the responses with the requested data object, carried in Data messages. This has a number of highly beneficial properties for flow and congestion control in networks, as well as some desirable security properties. For example, neither legitimate users nor attackers are able to inject large amounts of un-requested data into the network." />
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<table class="header">
|
||||
<tbody>
|
||||
|
||||
<tr>
|
||||
<td class="left">ICNRG</td>
|
||||
<td class="right">D. Oran</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="left">Internet-Draft</td>
|
||||
<td class="right">Network Systems Research and Design</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="left">Intended status: Experimental</td>
|
||||
<td class="right">August 2019</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="left">Expires: February 2, 2020</td>
|
||||
<td class="right"></td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p class="title">Maintaining CCNx or NDN flow balance with highly variable data object sizes <br />
|
||||
<span class="filename">draft-oran-icnrg-flowbalance-latest</span></p>
|
||||
|
||||
<h1 id="rfc.abstract">
|
||||
<a href="#rfc.abstract">Abstract</a>
|
||||
</h1>
|
||||
<p>Deeply embedded in some ICN architectures, especially Named Data Networking (NDN) and Content-Centric Networking (CCNx) is the notion of flow balance. This captures the idea that there is a one-to-one correspondence between requests for data, carried in Interest messages, and the responses with the requested data object, carried in Data messages. This has a number of highly beneficial properties for flow and congestion control in networks, as well as some desirable security properties. For example, neither legitimate users nor attackers are able to inject large amounts of un-requested data into the network.</p>
|
||||
<p>Existing congestion control approaches however cannot deal effectively with a widely varying MTU of ICN data messages, since the protocols allow a dynamic range of 1-64K bytes. Since Interest messages are used to allocate the reverse link bandwidth for returning Data, there is large uncertainty in how to allocate that bandwidth. Unfortunately, current congestion control schemes in CCNx and NDN only count Interest messages and have no idea how much data is involved that could congest the inverse link. This document proposes a method to maintain flow balance by accommodating the wide dynamic range in Data message MTU.</p>
|
||||
<h1 id="rfc.status">
|
||||
<a href="#rfc.status">Status of This Memo</a>
|
||||
</h1>
|
||||
<p>This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.</p>
|
||||
<p>Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at http://datatracker.ietf.org/drafts/current/.</p>
|
||||
<p>Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."</p>
|
||||
<p>This Internet-Draft will expire on February 2, 2020.</p>
|
||||
<h1 id="rfc.copyrightnotice">
|
||||
<a href="#rfc.copyrightnotice">Copyright Notice</a>
|
||||
</h1>
|
||||
<p>Copyright (c) 2019 IETF Trust and the persons identified as the document authors. All rights reserved.</p>
|
||||
<p>This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (http://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Simplified BSD License.</p>
|
||||
|
||||
|
||||
<hr class="noprint" />
|
||||
<h1 class="np" id="rfc.toc"><a href="#rfc.toc">Table of Contents</a></h1>
|
||||
<ul class="toc">
|
||||
|
||||
<li>1. <a href="#rfc.section.1">Introduction</a></li>
|
||||
<li>2. <a href="#rfc.section.2">Requirements Language</a></li>
|
||||
<li>3. <a href="#rfc.section.3">Method to enhance congestion control with signaled size information in Interest Messages</a></li>
|
||||
<ul><li>3.1. <a href="#rfc.section.3.1">How to predict the size of returning Data messages</a></li>
|
||||
<li>3.2. <a href="#rfc.section.3.2">Handling `too big' cases</a></li>
|
||||
<li>3.3. <a href="#rfc.section.3.3">Handling `too small' cases</a></li>
|
||||
<li>3.4. <a href="#rfc.section.3.4">Interactions with Interest Aggregation</a></li>
|
||||
<li>3.5. <a href="#rfc.section.3.5">Operation when some Interests lack the expected data size option and some have it</a></li>
|
||||
</ul><li>4. <a href="#rfc.section.4">Dealing with malicious actors</a></li>
|
||||
<li>5. <a href="#rfc.section.5">Mapping to CCNx and NDN packet encodings</a></li>
|
||||
<ul><li>5.1. <a href="#rfc.section.5.1">Packet encoding for CCNx</a></li>
|
||||
<li>5.2. <a href="#rfc.section.5.2">Packet encoding for NDN</a></li>
|
||||
</ul><li>6. <a href="#rfc.section.6">IANA Considerations</a></li>
|
||||
<li>7. <a href="#rfc.section.7">Security Considerations</a></li>
|
||||
<li>8. <a href="#rfc.references">References</a></li>
|
||||
<ul><li>8.1. <a href="#rfc.references.1">Normative References</a></li>
|
||||
<li>8.2. <a href="#rfc.references.2">Informative References</a></li>
|
||||
</ul><li><a href="#rfc.authors">Author's Address</a></li>
|
||||
|
||||
|
||||
</ul>
|
||||
|
||||
<h1 id="rfc.section.1"><a href="#rfc.section.1">1.</a> <a href="#intro" id="intro">Introduction</a></h1>
|
||||
<p id="rfc.section.1.p.1">Deeply embedded in some ICN architectures, especially Named Data Networking (NDN <a href="#NDN">[NDN]</a>) and Content-Centric Networking (CCNx <a href="#RFC8569">[RFC8569]</a>,<a href="#RFC8609">[RFC8609]</a>) is the notion of <em>flow balance</em>. This captures the idea that there is a one-to-one correspondence between requests for data, carried in Interest messages, and the responses with the requested data object, carried in Data messages. This has a number of highly beneficial properties for flow and congestion control in networks, as well as some desirable security properties. For example, neither legitimate users nor attackers are able to inject large amounts of un-requested data into the network.</p>
|
||||
<p id="rfc.section.1.p.2">This approach leads to a desire to make the size of the objects carried in Data messages small and near constant, because flow balance can then be kept using simple bookkeeping of how many Interest messages are outstanding. While simple, constraining Data messages to be quite small - usually on the order of a link Maximum Transmission Unit (MTU) - has some constraints and deleterious effects, among which are: </p>
|
||||
|
||||
<ul>
|
||||
<li>Such small data objects are inconvenient for many applications; their natural data object sizes can be considerably larger than a link MTU.</li>
|
||||
<li>Applications with truly small data objects (e.g. voice packets in an Internet telephony applications) have no way to communicate that to the network, causing resources to still be allocated for MTU-sized data objects</li>
|
||||
<li>When chunking a larger data object into multiple Data messages, each message has to be individually cryptographically hashed and signed, increasing both computational overhead and overall message header size. The signature can be elided when Manifests are used (by signing the Manifest instead), but the overhead of hashing multiple small messages rather than fewer larger ones remains.</li>
|
||||
</ul>
|
||||
|
||||
<p> </p>
|
||||
<p id="rfc.section.1.p.3">One approach which helps with the last of these is to employ fragmentation for Data messages larger than the Path MTU (PMTU). such messages are carved into smaller pieces for transmission over the link(s). There are three flavors of fragmentation: end-to-end, hop-by-hop with reassembly at every hop, and hop-by-hop with cut-through of individual fragments. A number of ICN protocol architectures incorporate fragmentation and schemes have been proposed for both NDN and CCNx, for example in <a href="#Ghali2013">[Ghali2013]</a>. Fragmentation alone does not ameliorate the flow balance problem however, since from a resource allocation standpoint both memory and link bandwidth must be set aside for maximum-sized data objects to avoid congestion collapse under overload.</p>
|
||||
<p id="rfc.section.1.p.4">The design space considered in this document does not however extend to arbitrarily large objects (e.g. 100's of kilobytes or larger). As the dynamic range of data object sizes gets very large, finding the right tradeoff between handling a large number of small data objects versus a single very large data object when allocating link and buffer resources becomes intractable. Further, the semantics of Interest-Data exchanges means that any error in the exchange results in a re-issue of an Interest for the entire Data object. Very large data objects represent a performance problem because the cost of retransmission when Interests are retransmitted (or re-issued) becomes unsustainably high. Therefore, the method we propose deals with a dynamic range of object sizes from very small (a fraction of a link MTU) to moderately large - about 64 kilobytes or equivalently about 40 Ethernet packets, and assumes an associated fragmentation scheme to handle link MTUs that cannot carry the object in a single link-layer packet.</p>
|
||||
<p id="rfc.section.1.p.5">The approach described in the rest of this document maintains flow balance under the conditions outlined above by allocating resources accurately based on expected data object size, rather than employing simple interest counting.</p>
|
||||
<h1 id="rfc.section.2"><a href="#rfc.section.2">2.</a> Requirements Language</h1>
|
||||
<p id="rfc.section.2.p.1">The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in <a href="#RFC2119">RFC 2119</a> <cite title="NONE">[RFC2119]</cite>.</p>
|
||||
<h1 id="rfc.section.3"><a href="#rfc.section.3">3.</a> <a href="#description" id="description">Method to enhance congestion control with signaled size information in Interest Messages</a></h1>
|
||||
<p id="rfc.section.3.p.1">Before diving into the specifics of the design, it is useful to consider how congestion control works in NDN/CCNx. Unlike the IP protocol family, which relies on end-to-end congestion control (e.g. TCP<a href="#RFC0793">[RFC0793]</a>, DCCP<a href="#RFC4340">[RFC4340]</a>, SCTP<a href="#RFC4960">[RFC4960]</a>, QUIC<a href="#I-D.ietf-quic-transport">[I-D.ietf-quic-transport]</a>), CCNx and NDN employ hop-by-hop congestion control. There is per-Interest/Data state at every hop of the path and therefore for each outstanding Interest, bandwidth for data returning on the inverse path can be allocated. In the current design, this allocation is done using simple Interest counting - by accepting one Interest packet from an downstream node, implicitly this provides a guarantee (either hard or soft) that there is sufficient bandwidth on the inverse direction of the link to send back one Data packet. A number of congestion control schemes have been developed that operate in this fashion, for example <a href="#Wang2013">[Wang2013]</a>,<a href="#Mahdian2016">[Mahdian2016]</a>,<a href="#Song2018">[Song2018]</a>,<a href="#Carofiglio2012">[Carofiglio2012]</a>. Other schemes, like <a href="#Schneider2016">[Schneider2016]</a> neither count nor police interests, but instead monitor queues using AQM (active queue management) to mark returning Data packets that have experienced congestion. It is worth noting that every congestion control algorithm has an explicit fairness goal and associated objective function (usually either <a href="#minmaxfairness">[minmaxfairness]</a> or <a href="#proportionalfairness">[proportionalfairness]</a>). If your fairness is to be based on resource usage, pure interest counting doesn't do the trick, since a consumer asking for large thing can saturate a link and shift loss to consumers asking for small things.</p>
|
||||
<p id="rfc.section.3.p.2">In order to deal with a larger dynamic range of data object size, some means is required to allocate link bandwidth for data messages in bytes with an upper bound larger than a link PMTU and a lower bound lower than a single link MTU. Since resources are allocated for returning Data based on arriving Interests, this information must be available in Interest messages.</p>
|
||||
<p id="rfc.section.3.p.3">Therefore, one key idea is the inclusion of an <em>expected data size</em> TLV in each Interest message. This allows each forwarder on the path taken by the interest to accurately allocate bandwidth on the inverse path for the returning Data message. Also, by including the expected data size, large objects will have a corresponding weight in resource allocation, maintaining link and forwarder buffering fairness. The simpler Interest counting scheme was nominally "fair" on a per-exchange basis within the variations of data that fit in a single PMTU packet because all Interests produced similar amounts of data in return. In the absence of such a field, it is not feasible to allow a large dynamic range in object size. While schemes like <a href="#Schneider2016">[Schneider2016]</a> would not employ the expected data size to allocate reverse link bandwidth, they can still benefit from the information to affect the AQM congestion marking algorithm, preferentially marking data packets that exceed the expected data size.</p>
|
||||
<h1 id="rfc.section.3.1"><a href="#rfc.section.3.1">3.1.</a> <a href="#prediction" id="prediction">How to predict the size of returning Data messages</a></h1>
|
||||
<p id="rfc.section.3.1.p.1">This of course raises the question "How does the requester know how big the corresponding data coming back will be?". For a number of important applications, the size is known a priori due to the characteristics of the application. Here are some examples: </p>
|
||||
|
||||
<ul>
|
||||
<li>For many sensor and other Internet-of-Things applications, the data is instrument readings which have fixed known size.</li>
|
||||
<li>In video streaming, the data is output of a video encoder which produces variable sized frames. This information is typically made available ahead of time to the streaming clients in the form of a Manifest [4], which contains the names of the corresponding segments (or individual frames) of video and audio and their sizes.</li>
|
||||
<li>Internet telephony applications use vocoders that typically employ fixed-size audio frames. Therefore, their size is known either a priori, or via an initialization exchange at the start of an audio session.</li>
|
||||
</ul>
|
||||
|
||||
<p> The more complex cases arise where the data size is not known at the time the Interest must be sent. Much of the nuance of the proposed scheme is in how mismatches between the expected data size and the actual data object returned are handled. The consumer can either under- or over-estimate the data size. In the former case, the under-estimate can lead to congestion and possible loss of data. In the latter case, bandwidth that could have been used by data objects requested by other consumers might be wasted. We first consider "honest" mis-estimates due to imperfect knowledge by the ICN application; later we consider malicious applications that are using the machinery to mount some form of attack. We also consider the effects of Interest aggregation if the aggregated Interests have differing expected data sizes. Also, it should be obvious that if the Data message arrives, the application learns its actual size, which may or may not be useful in adjusting the expected data size estimate for future Interests.</p>
|
||||
<p id="rfc.section.3.1.p.2">In all cases, the expected data size from the Interest can be incorporated in the corresponding Pending Interest Table (PIT) entry of each CCNx/NDN forwarder on the path and hence when a (possibly fragmented) Data object comes back, its total size is known and can be compared to the expected size in the PIT for a mismatch. Aside: In the case of fragmentation, we assume a fragmentation scheme in which the total data size can be known as soon as any one fragment is received (a reasonable assumption for most any well-designed fragmentation method).</p>
|
||||
<h1 id="rfc.section.3.2"><a href="#rfc.section.3.2">3.2.</a> <a href="#toobig" id="toobig">Handling `too big' cases</a></h1>
|
||||
<p id="rfc.section.3.2.p.1">If the returning data is larger than the expected data size, the extra data could result in either unfair bandwidth allocation or possibly data loss under congestion conditions. When this is detected, the forwarder has three choices: </p>
|
||||
|
||||
<ol>
|
||||
<li>It could forward the data anyway, which is safe under non-congestion conditions, but unfair and possibly unstable when the output link is congested</li>
|
||||
<li>It could forward the data when un-congested (e.g. by assessing output queue depth) but drop it when congested</li>
|
||||
<li>It could always drop the data, as a way of "punishing" the requester for the mis-estimate.</li>
|
||||
</ol>
|
||||
|
||||
<p> Either of the latter two strategies is acceptable from a congestion control point of view. However, it is not a good idea to simply drop the Data message with no feedback to the issuer of the Interest because the application has no way to learn the actual data size and retry. Further, recovery would be delayed until the failing Interest timed out. Therefore, an additional element needed in protocol semantics is the incorporation of a "Data too big" error message (via an "interest Return" packet in CCNx).</p>
|
||||
<p id="rfc.section.3.2.p.2">Upon dropping data as above, the CCNx/NDN forwarder converts the normal Data message into an Interest Return message containing the with the T_MTU_TOO_LARGE error code and the actual size of the data object instead of the data object content. It propagates that back toward the client identically to how the original Data message would have been handled. Subsequent nodes upon receiving the T_MTU_TOO_LARGE error treat it as all other Interest Return errors. When the Interest Return eventually arrives back to the issuer of the Interest, the user can, they desire, reissue the Interest with the correct expected data size.</p>
|
||||
<p id="rfc.section.3.2.p.3">One detail to note is that an Interest Return carrying T_MTU_TOO_LARGE must be deterministically smaller than the expected data size in all cases. This is clearly the case for large data objects, but there is a corner case with small data objects. There has to be a minimum expected data size that a client can specify in their Interests, and that minimum cannot be smaller than the size of a T_MTU_TOO_LARGE Interest Return</p>
|
||||
<h1 id="rfc.section.3.3"><a href="#rfc.section.3.3">3.3.</a> <a href="#toosmall" id="toosmall">Handling `too small' cases</a></h1>
|
||||
<p id="rfc.section.3.3.p.1">Next we consider the case where the returning data is smaller than the expected data size. While this case does not result in congestion, it can cause resources to be inefficiently allocated because not all of the set-aside bandwidth for the returning data object gets used. The simplest and most straightforward way to deal with this case is to essentially ignore it. The motivation for not worrying about the smaller data mismatch is that in many situations that employ usage-based resource measurement (and possibly charging), it is trivial to just account for the usage according to the larger expected data size rather than actual returned data size. Properly adjusting congestion control parameters to somehow penalize users for over-estimating their resource usage requires fairly heavyweight machinery, which in most cases is not warranted. If desired, any of the following mechanisms could be considered: </p>
|
||||
|
||||
<ul>
|
||||
<li>Attempt to identify future Interests for the same object or closely related objects and allocate resources based on some retained state about the actual size of prior objects</li>
|
||||
<li>Police consumer behavior and decrease the expected data size in one or more future Interests to compensate</li>
|
||||
<li>For small objects, do more optimistic resource allocation on the links on the presumption that there will be some "slack" due to clients overestimating data object size.</li>
|
||||
</ul>
|
||||
|
||||
<p> One protocol detail of CCNx/NDN that needs to be dealt with is Interest Aggregation. This happens when multiple Interests arrive at a forwarder for the same Named object. These are aggregated such that one of them (i.e.the first to arrive and create PIT state) is forwarded, and the rest are dropped while marking the arrival face so the data can be sent back to the multiple requesting clients. Interest aggregation interacts with expected data size if Interests from different clients contain different values of the expected data size. As above, the simplest solution to this problem is to ignore it, as most error cases are benign. However, there is one problematic error case where one client provides an accurate expected data size, but another who issued the Interest first underestimates, causing both to receive a Data too big error. This introduces a denial of service vulnerability, which we discuss below together with the other malicious actor cases.</p>
|
||||
<h1 id="rfc.section.3.4"><a href="#rfc.section.3.4">3.4.</a> <a href="#aggregation" id="aggregation">Interactions with Interest Aggregation</a></h1>
|
||||
<p id="rfc.section.3.4.p.1">Interest Aggregation, while a powerful feature for maintaining flow balance when multiple consumers send Interests for the same Named object, introduces subtle complications. Whenever a second or subsequent Interest arrives at a forwarder with an active PIT entry it is possible that those Interests carry different parameters, for example hop limit, payload, etc. It is therefore necessary to specify the exact behavior of the forwarder for each of the parameters that might differ. In the case of the expected data size parameter defined here, the value is associated with the ingress face on which the Interest creating the PIT entry arrived, as opposed to being global to the PIT entry as a whole. There are two cases to consider: </p>
|
||||
|
||||
<ol>
|
||||
<li>The arriving interest carries an expected data size smaller than any of the values associated with the PIT entry.</li>
|
||||
<li>The arriving interest carries an expected data size larger than any of the values associated with the PIT entry.</li>
|
||||
</ol>
|
||||
|
||||
<p> </p>
|
||||
<p id="rfc.section.3.4.p.2">For Case (1) the Interest can be safely aggregated since the upstream links will have sufficient bandwidth allocated based on the larger expected data size (assuming the original Interest's expected data size was itself sufficiently large to accommodate the actual size of the returning Data. On the other hand, should the incoming face have bandwidth allocated based on the larger existing Interest's expected data size, or on the smaller value in the arriving interest? Here there are two possible approaches: </p>
|
||||
|
||||
<ol style="list-style-type: lower-alpha">
|
||||
<li>Allocate based on the data size already in the PIT. In this case the consumer sending the earlier Interest can cause over-allocation of link bandwidth for other incoming faces, but there will not be a T_MTU_TOO_LARGE error generated for that Interest</li>
|
||||
<li>Allocate based on the value in the arriving Interest. If the returning Data is in fact larger, generate a T_MTU_TOO_LARGE Interest Return on that ingress face, while successfully returning the Data message on any faces that do not exhibit a too small expected data size</li>
|
||||
</ol>
|
||||
|
||||
<p> It is RECOMMENDED that the second policy be followed. The reasons behind this recommendation are as follows: </p>
|
||||
|
||||
<ol>
|
||||
<li>The link can be congested quite quickly after the queuing decision is made, especially if the data has a long link-occupancy time, so this is a safer alternative.</li>
|
||||
<li>The cost of returning the error is only one link RTT, since the consumer (or downstream forwarder) can immediately re-issue the interest with the correct size and pick up the cached object from the upstream forwarder's Content Store.</li>
|
||||
<li>Being optimistic and returning the data interacts with the behavior of aggregate resource control and resource accounting, which in turn raises the messy issue of whether to "charge" the consumer for the actual bandwidth used or only for the requested bandwidth in the expected data.</li>
|
||||
<li>The rabbit hole goes deeper if you add differential QoS to the equation or consumers "playing games" and intentionally underestimating so their interests get satisfied when links aren't congested. This makes handling malicious actors (<a href="#malicious">Section 4</a>) more difficult.</li>
|
||||
</ol>
|
||||
|
||||
<p> </p>
|
||||
<p id="rfc.section.3.4.p.3">For Case (2) above, the Interest MUST be forwarded rather than aggregated to prevent a consumer from mounting a denial of service attack by sending intentionally too small expected data size (see <a href="#malicious">Section 4</a> for additional detail on this and other attacks). As above for Case (1) it is RECOMMENDED that policy (b) above be followed. </p>
|
||||
<h1 id="rfc.section.3.5"><a href="#rfc.section.3.5">3.5.</a> <a href="#compatibility" id="compatibility">Operation when some Interests lack the expected data size option and some have it</a></h1>
|
||||
<p id="rfc.section.3.5.p.1">Since the expected data size hop-by-hop option forwarders need to be prepared to handle an arbitrary mix of the two forms. There are two general things to address. </p>
|
||||
<p id="rfc.section.3.5.p.2">First, we assume that any forwarder supporting expected data size is running a more sophisticated congestion control algorithm that one employing simple interest counting. The link bandwidth resource allocation is therefore based directly, or indirectly, on the expected Data size in bytes. Therefore, the forwarder has to assign a value to use in the resource allocation for the reverse link. This specification does not mandate any particular approach or a default value to use. However, in the absence on other guidance, it makes sense to do one of two things: </p>
|
||||
|
||||
<ol>
|
||||
<li>Pick a default based on the link MTU of the face on which the Interest arrived and use that for all Interests lacking an expected data size. This is likely to be most compatible with simple interest counting which would rate limit all incoming interests equally</li>
|
||||
<li>Configure some values for given Name prefixes that have known sizes. This may be appropriate for dedicated forwarders supporting single use cases, such as: <ul><li>A forwarder handling IoT sensors sending very small Data packets</li><li>A forwarder handling real-time video with large average Data packets that exceed link MTU and are routinely fragmented</li><li>A forwarder doing voice trunking where the vocoders produce moderate sized packets, still much smaller than the link MTU</li></ul><p> </p></li>
|
||||
</ol>
|
||||
|
||||
<p> </p>
|
||||
<p id="rfc.section.3.5.p.3">The second area to address is what to do if an interest lacking an expected Data size is responded to by a Data message whose size exceeds the default discussed above. It would be inappropriate to issue a T_MTU_TOO_LARGE error, since the consumer is unlikely to understand or deal correctly with that new error case. Instead, it is RECOMMENDED that the forwarder: </p>
|
||||
|
||||
<ul>
|
||||
<li>Ignore the mismatch if the reverse link is not congested and return the requested Data message anyway.</li>
|
||||
<li>If the reverse link is congested, issue an Interest Return with the T_NO_RESOURCES error code</li>
|
||||
</ul>
|
||||
|
||||
<p> This specification does not define or recommend any particular algorithm for assessing the congestion state of the link(s) to carry the Data message downstream to the requesting consumers. It is assumed that a reasonable algorithm is in use, because otherwise even basic Interest counting forms of congestion control would not be effective. </p>
|
||||
<h1 id="rfc.section.4"><a href="#rfc.section.4">4.</a> <a href="#malicious" id="malicious">Dealing with malicious actors</a></h1>
|
||||
<p id="rfc.section.4.p.1">First we note that various known attacks in CCNx or NDN can also be mounted by users employing this method. Attacks that involve interest flooding, cache pollution, cache poisoning, etc. are neither worsened nor ameliorated by the introduction of the congestion control capabilities described here. However, there are two new vulnerabilities that need to be dealt with. These two new vulnerabilities involve intentional mis-estimation of data size.</p>
|
||||
<p id="rfc.section.4.p.2">The first is a consumer who intentionally over-estimates data size with the goal of preventing other users from using the bandwidth. This is at most a minor concern given the above discussion of over-estimation by honest clients. If one of the amelioration techniques above are used, the case of malicious over-estimation is also dealt with adequately.</p>
|
||||
<p id="rfc.section.4.p.3">The second is a user who intentionally under-estimates the data size with the goal having its Interest processed while the other aggregated interests are not processed, thereby causing T_MTU_TOO_LARGE errors and denying service to the other users with overlapping requests. There are a number of possible mitigation techniques for this attack vector, ranging in complexity. We outline two below; there may be others as or more effective with acceptable complexity and overhead: </p>
|
||||
|
||||
<ul>
|
||||
<li>(Simplest) A user sending Interests resulting in a T_MTU_TOO_LARGE error is treated similarly to users mounting interest flooding attacks; the a router aggregating Interests with differing expected data sizes rate limits the face(s) exhibiting these errors, thus decreasing the ability of a user to issue enough mis-estimated Interests to collide and generate Interest aggregation.</li>
|
||||
<li>An ICN forwarder aggregating Interests remembers in the PIT entry not only the expected data size of the Interest it forwarded, but the maximum of the expected data size of the other Interests it aggregated. If a T_MTU_TOO_LARGE error comes back, instead of propagating it, the forwarder MAY treat this as a transient error, drop the Interest Return, and re-forward the Interest using the maximum expected data size in the PIT (assuming it is is bigger). This recovers from the error, but the attacker can still cause an extra round trip to the producer or to an upstream forwarder with a copy of the data in its Content Store.</li>
|
||||
</ul>
|
||||
|
||||
<p> </p>
|
||||
<h1 id="rfc.section.5"><a href="#rfc.section.5">5.</a> <a href="#encoding" id="encoding">Mapping to CCNx and NDN packet encodings</a></h1>
|
||||
<p id="rfc.section.5.p.1">The only actual protocol needed is a TLV in Interest messages that states the size in bytes of the expected Data Message coming back, and in the Interest Return on a "too big" error to carry the actual data size. In the case of CCNx, this covers the encapsulated Data Object, but not the hop-by-hop headers.</p>
|
||||
<h1 id="rfc.section.5.1"><a href="#rfc.section.5.1">5.1.</a> <a href="#CCNx-encoding" id="CCNx-encoding">Packet encoding for CCNx</a></h1>
|
||||
<p id="rfc.section.5.1.p.1">For CCNx<a href="#RFC8569">[RFC8569]</a> there is a new hop-by-hop header TLV, and a new value of the Interest Return "Return Type".</p>
|
||||
<div id="rfc.table.1"/>
|
||||
<div id="DataSize"/>
|
||||
<p>Expected Data Size (for Interest messages), or Actual Data Size (for Interest Return messages) TLV</p>
|
||||
<table cellpadding="3" cellspacing="0" class="tt full center">
|
||||
<caption>Data Size TLV</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="center">Abbrev</th>
|
||||
<th class="center">Name</th>
|
||||
<th class="center">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="center">T_DATASIZE</td>
|
||||
<td class="center">Data Size</td>
|
||||
<td class="center">Expected (<a href="#description">Section 3</a>)or Actual (<a href="#toobig">Section 3.2</a>) Data Size</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h1 id="rfc.section.5.2"><a href="#rfc.section.5.2">5.2.</a> <a href="#NDN-encoding" id="NDN-encoding">Packet encoding for NDN</a></h1>
|
||||
<p id="rfc.section.5.2.p.1">TBD based on <a href="#NDNTLV">[NDNTLV]</a>. Suggestions from the NDN team greatly appreciated.</p>
|
||||
<h1 id="rfc.section.6"><a href="#rfc.section.6">6.</a> <a href="#IANA" id="IANA">IANA Considerations</a></h1>
|
||||
<p id="rfc.section.6.p.1">Please Add the T_TIMETLV TLV to the Hop-by-Hop TLV types registry of RFC8609, with fixed length of 2, and data type numeric</p>
|
||||
<div id="rfc.figure.1"/>
|
||||
<div id="timetlv-encoding"/>
|
||||
<p>Expected/Actual Data Size TLV encoding. The range has an upper bound of 64K bytes, since that is the largest MTU supported by CCNx.</p>
|
||||
<pre>
|
||||
1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+---------------+---------------+---------------+---------------+
|
||||
| T_TIMETLV | 2 |
|
||||
+---------------+---------------+---------------+---------------+
|
||||
| INTERVAL_TIME (see RFC4574) |
|
||||
+---------------+---------------+
|
||||
</pre>
|
||||
<p class="figure">Figure 1: Compresssed Time Values using RFC4574 encoding</p>
|
||||
<h1 id="rfc.section.7"><a href="#rfc.section.7">7.</a> <a href="#Security" id="Security">Security Considerations</a></h1>
|
||||
<p/>
|
||||
<h1 id="rfc.references"><a href="#rfc.references">8.</a> References</h1>
|
||||
<h1 id="rfc.references.1"><a href="#rfc.references.1">8.1.</a> Normative References</h1>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="RFC2119">[RFC2119]</b>
|
||||
</td>
|
||||
<td class="top"><a>Bradner, S.</a>, "<a href="http://tools.ietf.org/html/rfc2119">Key words for use in RFCs to Indicate Requirement Levels</a>", BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="RFC8569">[RFC8569]</b>
|
||||
</td>
|
||||
<td class="top"><a>Mosko, M.</a>, <a>Solis, I.</a> and <a>C. Wood</a>, "<a href="http://tools.ietf.org/html/rfc8569">Content-Centric Networking (CCNx) Semantics</a>", RFC 8569, DOI 10.17487/RFC8569, July 2019.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="RFC8609">[RFC8609]</b>
|
||||
</td>
|
||||
<td class="top"><a>Mosko, M.</a>, <a>Solis, I.</a> and <a>C. Wood</a>, "<a href="http://tools.ietf.org/html/rfc8609">Content-Centric Networking (CCNx) Messages in TLV Format</a>", RFC 8609, DOI 10.17487/RFC8609, July 2019.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h1 id="rfc.references.2"><a href="#rfc.references.2">8.2.</a> Informative References</h1>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="Carofiglio2012">[Carofiglio2012]</b>
|
||||
</td>
|
||||
<td class="top"><a>Carofiglio, G.</a>, <a>Gallo, M.</a> and <a>L. Muscariello</a>, "<a href="http://conferences.sigcomm.org/sigcomm/2012/paper/icn/p37.pdf">Joint hop-by-hop and receiver-driven interest control protocol for content-centric networks, in ICN Workshop at SIGcomm 2012</a>", DOI 10.1145/2377677.2377772, 2102.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="Ghali2013">[Ghali2013]</b>
|
||||
</td>
|
||||
<td class="top"><a>Ghali, C.</a>, <a>Narayanan, A.</a>, <a>Oran, D.</a>, <a>Tsudik, G.</a> and <a>C. Wood</a>, "<a href="http://dx.doi.org/10.1109/NCA.2015.34">Secure Fragmentation for Content-Centric Networks, in IEEE 14th International Symposium on Network Computing and Applications</a>", DOI 10.1109/nca.2015.34, 2015.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="I-D.ietf-quic-transport">[I-D.ietf-quic-transport]</b>
|
||||
</td>
|
||||
<td class="top"><a>Iyengar, J.</a> and <a>M. Thomson</a>, "<a href="http://tools.ietf.org/html/draft-ietf-quic-transport-23">QUIC: A UDP-Based Multiplexed and Secure Transport</a>", Internet-Draft draft-ietf-quic-transport-23, September 2019.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="Mahdian2016">[Mahdian2016]</b>
|
||||
</td>
|
||||
<td class="top"><a>Mahdian, M.</a>, <a>Arianfar, S.</a>, <a>Gibson, J.</a> and <a>D. Oran</a>, "<a href="http://conferences2.sigcomm.org/acm-icn/2016/proceedings/p1-mahdian.pdf">MIRCC: Multipath-aware ICN Rate-based Congestion Control, in Proceedings of the 3rd ACM Conference on Information-Centric Networking</a>", DOI 10.1145/2984356.2984365, 2016.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="minmaxfairness">[minmaxfairness]</b>
|
||||
</td>
|
||||
<td class="top"><a>Wikipedia, </a>, "<a href="https://en.wikipedia.org/wiki/Max-min_fairness">Max-min Fairness</a>", various.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="NDN">[NDN]</b>
|
||||
</td>
|
||||
<td class="top"><a>NDN team, </a>, "<a href="https://named-data.net/project/execsummary/">Named Data Networking</a>", various.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="NDNTLV">[NDNTLV]</b>
|
||||
</td>
|
||||
<td class="top"><a>NDN Project Team, </a>, "<a href="http://named-data.net/doc/ndn-tlv/">NDN Packet Format Specification.</a>", 2016.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="proportionalfairness">[proportionalfairness]</b>
|
||||
</td>
|
||||
<td class="top"><a>Wikipedia, </a>, "<a href="https://en.wikipedia.org/wiki/Proportionally_fair">Proportionally Fair</a>", various.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="RFC0793">[RFC0793]</b>
|
||||
</td>
|
||||
<td class="top"><a>Postel, J.</a>, "<a href="http://tools.ietf.org/html/rfc793">Transmission Control Protocol</a>", STD 7, RFC 793, DOI 10.17487/RFC0793, September 1981.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="RFC4340">[RFC4340]</b>
|
||||
</td>
|
||||
<td class="top"><a>Kohler, E.</a>, <a>Handley, M.</a> and <a>S. Floyd</a>, "<a href="http://tools.ietf.org/html/rfc4340">Datagram Congestion Control Protocol (DCCP)</a>", RFC 4340, DOI 10.17487/RFC4340, March 2006.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="RFC4960">[RFC4960]</b>
|
||||
</td>
|
||||
<td class="top"><a>Stewart, R.</a>, "<a href="http://tools.ietf.org/html/rfc4960">Stream Control Transmission Protocol</a>", RFC 4960, DOI 10.17487/RFC4960, September 2007.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="Schneider2016">[Schneider2016]</b>
|
||||
</td>
|
||||
<td class="top"><a>Schneider, K.</a>, <a>Yi, C.</a>, <a>Zhang, B.</a> and <a>L. Zhang</a>, "<a href="http://conferences2.sigcomm.org/acm-icn/2016/proceedings/p21-schneider.pdf">A Practical Congestion Control Scheme for Named Data Networking, in Proceedings of the 2016 conference on 3rd ACM Conference on Information-Centric Networking - ACM-ICN '16</a>", DOI 10.1145/2984356.2984369, 2016.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="Song2018">[Song2018]</b>
|
||||
</td>
|
||||
<td class="top"><a>Song, J.</a>, <a>Lee, M.</a> and <a>T. Kwon</a>, "<a href="https://conferences.sigcomm.org/acm-icn/2018/proceedings/icn18-final62.pdf">SMIC: Subflow-level Multi-path Interest Control for Information Centric Networking, in 5th ACM Conference on Information-Centric Networking</a>", DOI 10.1145/3267955.3267971, 2018.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="Wang2013">[Wang2013]</b>
|
||||
</td>
|
||||
<td class="top"><a>Wang, Y.</a>, <a>Rozhnova, N.</a>, <a>Narayanan, A.</a>, <a>Oran, D.</a> and <a>I. Rhee</a>, "<a href="http://conferences.sigcomm.org/sigcomm/2013/papers/icn/p55.pdf">An Improved Hop-by-hop Interest Shaper for Congestion Control in Named Data Networking, in ACM SIGCOMM Workshop on Information-Centric Networking</a>", DOI 10.1145/2534169.2491233, 2013.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h1 id="rfc.authors">
|
||||
<a href="#rfc.authors">Author's Address</a>
|
||||
</h1>
|
||||
<div class="avoidbreak">
|
||||
<address class="vcard">
|
||||
<span class="vcardline">
|
||||
<span class="fn">Dave Oran</span>
|
||||
<span class="n hidden">
|
||||
<span class="family-name">D. Oran</span>
|
||||
</span>
|
||||
</span>
|
||||
<span class="org vcardline">Network Systems Research and Design</span>
|
||||
<span class="adr">
|
||||
<span class="vcardline">4 Shady Hill Square</span>
|
||||
|
||||
<span class="vcardline">
|
||||
<span class="locality">Cambridge</span>,
|
||||
<span class="region">MA</span>
|
||||
<span class="code">02138</span>
|
||||
</span>
|
||||
<span class="country-name vcardline">USA</span>
|
||||
</span>
|
||||
<span class="vcardline">EMail: <a href="mailto:daveoran@orandom.net">daveoran@orandom.net</a></span>
|
||||
|
||||
</address>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+840
@@ -0,0 +1,840 @@
|
||||
|
||||
|
||||
|
||||
|
||||
ICNRG D. Oran
|
||||
Internet-Draft Network Systems Research and Design
|
||||
Intended status: Experimental August 2019
|
||||
Expires: February 2, 2020
|
||||
|
||||
|
||||
Maintaining CCNx or NDN flow balance with highly variable data object
|
||||
sizes
|
||||
draft-oran-icnrg-flowbalance-latest
|
||||
|
||||
Abstract
|
||||
|
||||
Deeply embedded in some ICN architectures, especially Named Data
|
||||
Networking (NDN) and Content-Centric Networking (CCNx) is the notion
|
||||
of flow balance. This captures the idea that there is a one-to-one
|
||||
correspondence between requests for data, carried in Interest
|
||||
messages, and the responses with the requested data object, carried
|
||||
in Data messages. This has a number of highly beneficial properties
|
||||
for flow and congestion control in networks, as well as some
|
||||
desirable security properties. For example, neither legitimate users
|
||||
nor attackers are able to inject large amounts of un-requested data
|
||||
into the network.
|
||||
|
||||
Existing congestion control approaches however cannot deal
|
||||
effectively with a widely varying MTU of ICN data messages, since the
|
||||
protocols allow a dynamic range of 1-64K bytes. Since Interest
|
||||
messages are used to allocate the reverse link bandwidth for
|
||||
returning Data, there is large uncertainty in how to allocate that
|
||||
bandwidth. Unfortunately, current congestion control schemes in CCNx
|
||||
and NDN only count Interest messages and have no idea how much data
|
||||
is involved that could congest the inverse link. This document
|
||||
proposes a method to maintain flow balance by accommodating the wide
|
||||
dynamic range in Data message MTU.
|
||||
|
||||
Status of This Memo
|
||||
|
||||
This Internet-Draft is submitted in full conformance with the
|
||||
provisions of BCP 78 and BCP 79.
|
||||
|
||||
Internet-Drafts are working documents of the Internet Engineering
|
||||
Task Force (IETF). Note that other groups may also distribute
|
||||
working documents as Internet-Drafts. The list of current Internet-
|
||||
Drafts is at http://datatracker.ietf.org/drafts/current/.
|
||||
|
||||
Internet-Drafts are draft documents valid for a maximum of six months
|
||||
and may be updated, replaced, or obsoleted by other documents at any
|
||||
time. It is inappropriate to use Internet-Drafts as reference
|
||||
material or to cite them other than as "work in progress."
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 2, 2020 [Page 1]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance August 2019
|
||||
|
||||
|
||||
This Internet-Draft will expire on February 2, 2020.
|
||||
|
||||
Copyright Notice
|
||||
|
||||
Copyright (c) 2019 IETF Trust and the persons identified as the
|
||||
document authors. All rights reserved.
|
||||
|
||||
This document is subject to BCP 78 and the IETF Trust's Legal
|
||||
Provisions Relating to IETF Documents
|
||||
(http://trustee.ietf.org/license-info) in effect on the date of
|
||||
publication of this document. Please review these documents
|
||||
carefully, as they describe your rights and restrictions with respect
|
||||
to this document. Code Components extracted from this document must
|
||||
include Simplified BSD License text as described in Section 4.e of
|
||||
the Trust Legal Provisions and are provided without warranty as
|
||||
described in the Simplified BSD License.
|
||||
|
||||
Table of Contents
|
||||
|
||||
1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 2
|
||||
2. Requirements Language . . . . . . . . . . . . . . . . . . . . 4
|
||||
3. Method to enhance congestion control with signaled size
|
||||
information in Interest Messages . . . . . . . . . . . . . . 4
|
||||
3.1. How to predict the size of returning Data messages . . . 5
|
||||
3.2. Handling `too big' cases . . . . . . . . . . . . . . . . 6
|
||||
3.3. Handling `too small' cases . . . . . . . . . . . . . . . 7
|
||||
3.4. Interactions with Interest Aggregation . . . . . . . . . 8
|
||||
3.5. Operation when some Interests lack the expected data size
|
||||
option and some have it . . . . . . . . . . . . . . . . . 10
|
||||
4. Dealing with malicious actors . . . . . . . . . . . . . . . . 11
|
||||
5. Mapping to CCNx and NDN packet encodings . . . . . . . . . . 12
|
||||
5.1. Packet encoding for CCNx . . . . . . . . . . . . . . . . 12
|
||||
5.2. Packet encoding for NDN . . . . . . . . . . . . . . . . . 12
|
||||
6. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 12
|
||||
7. Security Considerations . . . . . . . . . . . . . . . . . . . 13
|
||||
8. References . . . . . . . . . . . . . . . . . . . . . . . . . 13
|
||||
8.1. Normative References . . . . . . . . . . . . . . . . . . 13
|
||||
8.2. Informative References . . . . . . . . . . . . . . . . . 13
|
||||
Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 15
|
||||
|
||||
1. Introduction
|
||||
|
||||
Deeply embedded in some ICN architectures, especially Named Data
|
||||
Networking (NDN [NDN]) and Content-Centric Networking (CCNx
|
||||
[RFC8569],[RFC8609]) is the notion of _flow balance_. This captures
|
||||
the idea that there is a one-to-one correspondence between requests
|
||||
for data, carried in Interest messages, and the responses with the
|
||||
requested data object, carried in Data messages. This has a number
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 2, 2020 [Page 2]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance August 2019
|
||||
|
||||
|
||||
of highly beneficial properties for flow and congestion control in
|
||||
networks, as well as some desirable security properties. For
|
||||
example, neither legitimate users nor attackers are able to inject
|
||||
large amounts of un-requested data into the network.
|
||||
|
||||
This approach leads to a desire to make the size of the objects
|
||||
carried in Data messages small and near constant, because flow
|
||||
balance can then be kept using simple bookkeeping of how many
|
||||
Interest messages are outstanding. While simple, constraining Data
|
||||
messages to be quite small - usually on the order of a link Maximum
|
||||
Transmission Unit (MTU) - has some constraints and deleterious
|
||||
effects, among which are:
|
||||
|
||||
o Such small data objects are inconvenient for many applications;
|
||||
their natural data object sizes can be considerably larger than a
|
||||
link MTU.
|
||||
|
||||
o Applications with truly small data objects (e.g. voice packets in
|
||||
an Internet telephony applications) have no way to communicate
|
||||
that to the network, causing resources to still be allocated for
|
||||
MTU-sized data objects
|
||||
|
||||
o When chunking a larger data object into multiple Data messages,
|
||||
each message has to be individually cryptographically hashed and
|
||||
signed, increasing both computational overhead and overall message
|
||||
header size. The signature can be elided when Manifests are used
|
||||
(by signing the Manifest instead), but the overhead of hashing
|
||||
multiple small messages rather than fewer larger ones remains.
|
||||
|
||||
One approach which helps with the last of these is to employ
|
||||
fragmentation for Data messages larger than the Path MTU (PMTU). such
|
||||
messages are carved into smaller pieces for transmission over the
|
||||
link(s). There are three flavors of fragmentation: end-to-end, hop-
|
||||
by-hop with reassembly at every hop, and hop-by-hop with cut-through
|
||||
of individual fragments. A number of ICN protocol architectures
|
||||
incorporate fragmentation and schemes have been proposed for both NDN
|
||||
and CCNx, for example in [Ghali2013]. Fragmentation alone does not
|
||||
ameliorate the flow balance problem however, since from a resource
|
||||
allocation standpoint both memory and link bandwidth must be set
|
||||
aside for maximum-sized data objects to avoid congestion collapse
|
||||
under overload.
|
||||
|
||||
The design space considered in this document does not however extend
|
||||
to arbitrarily large objects (e.g. 100's of kilobytes or larger). As
|
||||
the dynamic range of data object sizes gets very large, finding the
|
||||
right tradeoff between handling a large number of small data objects
|
||||
versus a single very large data object when allocating link and
|
||||
buffer resources becomes intractable. Further, the semantics of
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 2, 2020 [Page 3]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance August 2019
|
||||
|
||||
|
||||
Interest-Data exchanges means that any error in the exchange results
|
||||
in a re-issue of an Interest for the entire Data object. Very large
|
||||
data objects represent a performance problem because the cost of
|
||||
retransmission when Interests are retransmitted (or re-issued)
|
||||
becomes unsustainably high. Therefore, the method we propose deals
|
||||
with a dynamic range of object sizes from very small (a fraction of a
|
||||
link MTU) to moderately large - about 64 kilobytes or equivalently
|
||||
about 40 Ethernet packets, and assumes an associated fragmentation
|
||||
scheme to handle link MTUs that cannot carry the object in a single
|
||||
link-layer packet.
|
||||
|
||||
The approach described in the rest of this document maintains flow
|
||||
balance under the conditions outlined above by allocating resources
|
||||
accurately based on expected data object size, rather than employing
|
||||
simple interest counting.
|
||||
|
||||
2. Requirements Language
|
||||
|
||||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
|
||||
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
|
||||
document are to be interpreted as described in RFC 2119 [RFC2119].
|
||||
|
||||
3. Method to enhance congestion control with signaled size information
|
||||
in Interest Messages
|
||||
|
||||
Before diving into the specifics of the design, it is useful to
|
||||
consider how congestion control works in NDN/CCNx. Unlike the IP
|
||||
protocol family, which relies on end-to-end congestion control (e.g.
|
||||
TCP[RFC0793], DCCP[RFC4340], SCTP[RFC4960],
|
||||
QUIC[I-D.ietf-quic-transport]), CCNx and NDN employ hop-by-hop
|
||||
congestion control. There is per-Interest/Data state at every hop of
|
||||
the path and therefore for each outstanding Interest, bandwidth for
|
||||
data returning on the inverse path can be allocated. In the current
|
||||
design, this allocation is done using simple Interest counting - by
|
||||
accepting one Interest packet from an downstream node, implicitly
|
||||
this provides a guarantee (either hard or soft) that there is
|
||||
sufficient bandwidth on the inverse direction of the link to send
|
||||
back one Data packet. A number of congestion control schemes have
|
||||
been developed that operate in this fashion, for example
|
||||
[Wang2013],[Mahdian2016],[Song2018],[Carofiglio2012]. Other schemes,
|
||||
like [Schneider2016] neither count nor police interests, but instead
|
||||
monitor queues using AQM (active queue management) to mark returning
|
||||
Data packets that have experienced congestion. It is worth noting
|
||||
that every congestion control algorithm has an explicit fairness goal
|
||||
and associated objective function (usually either [minmaxfairness] or
|
||||
[proportionalfairness]). If your fairness is to be based on resource
|
||||
usage, pure interest counting doesn't do the trick, since a consumer
|
||||
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 2, 2020 [Page 4]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance August 2019
|
||||
|
||||
|
||||
asking for large thing can saturate a link and shift loss to
|
||||
consumers asking for small things.
|
||||
|
||||
In order to deal with a larger dynamic range of data object size,
|
||||
some means is required to allocate link bandwidth for data messages
|
||||
in bytes with an upper bound larger than a link PMTU and a lower
|
||||
bound lower than a single link MTU. Since resources are allocated
|
||||
for returning Data based on arriving Interests, this information must
|
||||
be available in Interest messages.
|
||||
|
||||
Therefore, one key idea is the inclusion of an _expected data size_
|
||||
TLV in each Interest message. This allows each forwarder on the path
|
||||
taken by the interest to accurately allocate bandwidth on the inverse
|
||||
path for the returning Data message. Also, by including the expected
|
||||
data size, large objects will have a corresponding weight in resource
|
||||
allocation, maintaining link and forwarder buffering fairness. The
|
||||
simpler Interest counting scheme was nominally "fair" on a per-
|
||||
exchange basis within the variations of data that fit in a single
|
||||
PMTU packet because all Interests produced similar amounts of data in
|
||||
return. In the absence of such a field, it is not feasible to allow
|
||||
a large dynamic range in object size. While schemes like
|
||||
[Schneider2016] would not employ the expected data size to allocate
|
||||
reverse link bandwidth, they can still benefit from the information
|
||||
to affect the AQM congestion marking algorithm, preferentially
|
||||
marking data packets that exceed the expected data size.
|
||||
|
||||
3.1. How to predict the size of returning Data messages
|
||||
|
||||
This of course raises the question "How does the requester know how
|
||||
big the corresponding data coming back will be?". For a number of
|
||||
important applications, the size is known a priori due to the
|
||||
characteristics of the application. Here are some examples:
|
||||
|
||||
o For many sensor and other Internet-of-Things applications, the
|
||||
data is instrument readings which have fixed known size.
|
||||
|
||||
o In video streaming, the data is output of a video encoder which
|
||||
produces variable sized frames. This information is typically
|
||||
made available ahead of time to the streaming clients in the form
|
||||
of a Manifest [4], which contains the names of the corresponding
|
||||
segments (or individual frames) of video and audio and their
|
||||
sizes.
|
||||
|
||||
o Internet telephony applications use vocoders that typically employ
|
||||
fixed-size audio frames. Therefore, their size is known either a
|
||||
priori, or via an initialization exchange at the start of an audio
|
||||
session.
|
||||
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 2, 2020 [Page 5]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance August 2019
|
||||
|
||||
|
||||
The more complex cases arise where the data size is not known at the
|
||||
time the Interest must be sent. Much of the nuance of the proposed
|
||||
scheme is in how mismatches between the expected data size and the
|
||||
actual data object returned are handled. The consumer can either
|
||||
under- or over-estimate the data size. In the former case, the
|
||||
under-estimate can lead to congestion and possible loss of data. In
|
||||
the latter case, bandwidth that could have been used by data objects
|
||||
requested by other consumers might be wasted. We first consider
|
||||
"honest" mis-estimates due to imperfect knowledge by the ICN
|
||||
application; later we consider malicious applications that are using
|
||||
the machinery to mount some form of attack. We also consider the
|
||||
effects of Interest aggregation if the aggregated Interests have
|
||||
differing expected data sizes. Also, it should be obvious that if
|
||||
the Data message arrives, the application learns its actual size,
|
||||
which may or may not be useful in adjusting the expected data size
|
||||
estimate for future Interests.
|
||||
|
||||
In all cases, the expected data size from the Interest can be
|
||||
incorporated in the corresponding Pending Interest Table (PIT) entry
|
||||
of each CCNx/NDN forwarder on the path and hence when a (possibly
|
||||
fragmented) Data object comes back, its total size is known and can
|
||||
be compared to the expected size in the PIT for a mismatch. Aside:
|
||||
In the case of fragmentation, we assume a fragmentation scheme in
|
||||
which the total data size can be known as soon as any one fragment is
|
||||
received (a reasonable assumption for most any well-designed
|
||||
fragmentation method).
|
||||
|
||||
3.2. Handling `too big' cases
|
||||
|
||||
If the returning data is larger than the expected data size, the
|
||||
extra data could result in either unfair bandwidth allocation or
|
||||
possibly data loss under congestion conditions. When this is
|
||||
detected, the forwarder has three choices:
|
||||
|
||||
1. It could forward the data anyway, which is safe under non-
|
||||
congestion conditions, but unfair and possibly unstable when the
|
||||
output link is congested
|
||||
|
||||
2. It could forward the data when un-congested (e.g. by assessing
|
||||
output queue depth) but drop it when congested
|
||||
|
||||
3. It could always drop the data, as a way of "punishing" the
|
||||
requester for the mis-estimate.
|
||||
|
||||
Either of the latter two strategies is acceptable from a congestion
|
||||
control point of view. However, it is not a good idea to simply drop
|
||||
the Data message with no feedback to the issuer of the Interest
|
||||
because the application has no way to learn the actual data size and
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 2, 2020 [Page 6]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance August 2019
|
||||
|
||||
|
||||
retry. Further, recovery would be delayed until the failing Interest
|
||||
timed out. Therefore, an additional element needed in protocol
|
||||
semantics is the incorporation of a "Data too big" error message (via
|
||||
an "interest Return" packet in CCNx).
|
||||
|
||||
Upon dropping data as above, the CCNx/NDN forwarder converts the
|
||||
normal Data message into an Interest Return message containing the
|
||||
with the T_MTU_TOO_LARGE error code and the actual size of the data
|
||||
object instead of the data object content. It propagates that back
|
||||
toward the client identically to how the original Data message would
|
||||
have been handled. Subsequent nodes upon receiving the
|
||||
T_MTU_TOO_LARGE error treat it as all other Interest Return errors.
|
||||
When the Interest Return eventually arrives back to the issuer of the
|
||||
Interest, the user can, they desire, reissue the Interest with the
|
||||
correct expected data size.
|
||||
|
||||
One detail to note is that an Interest Return carrying
|
||||
T_MTU_TOO_LARGE must be deterministically smaller than the expected
|
||||
data size in all cases. This is clearly the case for large data
|
||||
objects, but there is a corner case with small data objects. There
|
||||
has to be a minimum expected data size that a client can specify in
|
||||
their Interests, and that minimum cannot be smaller than the size of
|
||||
a T_MTU_TOO_LARGE Interest Return
|
||||
|
||||
3.3. Handling `too small' cases
|
||||
|
||||
Next we consider the case where the returning data is smaller than
|
||||
the expected data size. While this case does not result in
|
||||
congestion, it can cause resources to be inefficiently allocated
|
||||
because not all of the set-aside bandwidth for the returning data
|
||||
object gets used. The simplest and most straightforward way to deal
|
||||
with this case is to essentially ignore it. The motivation for not
|
||||
worrying about the smaller data mismatch is that in many situations
|
||||
that employ usage-based resource measurement (and possibly charging),
|
||||
it is trivial to just account for the usage according to the larger
|
||||
expected data size rather than actual returned data size. Properly
|
||||
adjusting congestion control parameters to somehow penalize users for
|
||||
over-estimating their resource usage requires fairly heavyweight
|
||||
machinery, which in most cases is not warranted. If desired, any of
|
||||
the following mechanisms could be considered:
|
||||
|
||||
o Attempt to identify future Interests for the same object or
|
||||
closely related objects and allocate resources based on some
|
||||
retained state about the actual size of prior objects
|
||||
|
||||
o Police consumer behavior and decrease the expected data size in
|
||||
one or more future Interests to compensate
|
||||
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 2, 2020 [Page 7]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance August 2019
|
||||
|
||||
|
||||
o For small objects, do more optimistic resource allocation on the
|
||||
links on the presumption that there will be some "slack" due to
|
||||
clients overestimating data object size.
|
||||
|
||||
One protocol detail of CCNx/NDN that needs to be dealt with is
|
||||
Interest Aggregation. This happens when multiple Interests arrive at
|
||||
a forwarder for the same Named object. These are aggregated such
|
||||
that one of them (i.e.the first to arrive and create PIT state) is
|
||||
forwarded, and the rest are dropped while marking the arrival face so
|
||||
the data can be sent back to the multiple requesting clients.
|
||||
Interest aggregation interacts with expected data size if Interests
|
||||
from different clients contain different values of the expected data
|
||||
size. As above, the simplest solution to this problem is to ignore
|
||||
it, as most error cases are benign. However, there is one
|
||||
problematic error case where one client provides an accurate expected
|
||||
data size, but another who issued the Interest first underestimates,
|
||||
causing both to receive a Data too big error. This introduces a
|
||||
denial of service vulnerability, which we discuss below together with
|
||||
the other malicious actor cases.
|
||||
|
||||
3.4. Interactions with Interest Aggregation
|
||||
|
||||
Interest Aggregation, while a powerful feature for maintaining flow
|
||||
balance when multiple consumers send Interests for the same Named
|
||||
object, introduces subtle complications. Whenever a second or
|
||||
subsequent Interest arrives at a forwarder with an active PIT entry
|
||||
it is possible that those Interests carry different parameters, for
|
||||
example hop limit, payload, etc. It is therefore necessary to
|
||||
specify the exact behavior of the forwarder for each of the
|
||||
parameters that might differ. In the case of the expected data size
|
||||
parameter defined here, the value is associated with the ingress face
|
||||
on which the Interest creating the PIT entry arrived, as opposed to
|
||||
being global to the PIT entry as a whole. There are two cases to
|
||||
consider:
|
||||
|
||||
1. The arriving interest carries an expected data size smaller than
|
||||
any of the values associated with the PIT entry.
|
||||
|
||||
2. The arriving interest carries an expected data size larger than
|
||||
any of the values associated with the PIT entry.
|
||||
|
||||
For Case (1) the Interest can be safely aggregated since the upstream
|
||||
links will have sufficient bandwidth allocated based on the larger
|
||||
expected data size (assuming the original Interest's expected data
|
||||
size was itself sufficiently large to accommodate the actual size of
|
||||
the returning Data. On the other hand, should the incoming face have
|
||||
bandwidth allocated based on the larger existing Interest's expected
|
||||
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 2, 2020 [Page 8]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance August 2019
|
||||
|
||||
|
||||
data size, or on the smaller value in the arriving interest? Here
|
||||
there are two possible approaches:
|
||||
|
||||
a. Allocate based on the data size already in the PIT. In this case
|
||||
the consumer sending the earlier Interest can cause over-
|
||||
allocation of link bandwidth for other incoming faces, but there
|
||||
will not be a T_MTU_TOO_LARGE error generated for that Interest
|
||||
|
||||
b. Allocate based on the value in the arriving Interest. If the
|
||||
returning Data is in fact larger, generate a T_MTU_TOO_LARGE
|
||||
Interest Return on that ingress face, while successfully
|
||||
returning the Data message on any faces that do not exhibit a too
|
||||
small expected data size
|
||||
|
||||
It is RECOMMENDED that the second policy be followed. The reasons
|
||||
behind this recommendation are as follows:
|
||||
|
||||
1. The link can be congested quite quickly after the queuing
|
||||
decision is made, especially if the data has a long link-
|
||||
occupancy time, so this is a safer alternative.
|
||||
|
||||
2. The cost of returning the error is only one link RTT, since the
|
||||
consumer (or downstream forwarder) can immediately re-issue the
|
||||
interest with the correct size and pick up the cached object from
|
||||
the upstream forwarder's Content Store.
|
||||
|
||||
3. Being optimistic and returning the data interacts with the
|
||||
behavior of aggregate resource control and resource accounting,
|
||||
which in turn raises the messy issue of whether to "charge" the
|
||||
consumer for the actual bandwidth used or only for the requested
|
||||
bandwidth in the expected data.
|
||||
|
||||
4. The rabbit hole goes deeper if you add differential QoS to the
|
||||
equation or consumers "playing games" and intentionally
|
||||
underestimating so their interests get satisfied when links
|
||||
aren't congested. This makes handling malicious actors
|
||||
(Section 4) more difficult.
|
||||
|
||||
For Case (2) above, the Interest MUST be forwarded rather than
|
||||
aggregated to prevent a consumer from mounting a denial of service
|
||||
attack by sending intentionally too small expected data size (see
|
||||
Section 4 for additional detail on this and other attacks). As above
|
||||
for Case (1) it is RECOMMENDED that policy (b) above be followed.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 2, 2020 [Page 9]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance August 2019
|
||||
|
||||
|
||||
3.5. Operation when some Interests lack the expected data size option
|
||||
and some have it
|
||||
|
||||
Since the expected data size hop-by-hop option forwarders need to be
|
||||
prepared to handle an arbitrary mix of the two forms. There are two
|
||||
general things to address.
|
||||
|
||||
First, we assume that any forwarder supporting expected data size is
|
||||
running a more sophisticated congestion control algorithm that one
|
||||
employing simple interest counting. The link bandwidth resource
|
||||
allocation is therefore based directly, or indirectly, on the
|
||||
expected Data size in bytes. Therefore, the forwarder has to assign
|
||||
a value to use in the resource allocation for the reverse link. This
|
||||
specification does not mandate any particular approach or a default
|
||||
value to use. However, in the absence on other guidance, it makes
|
||||
sense to do one of two things:
|
||||
|
||||
1. Pick a default based on the link MTU of the face on which the
|
||||
Interest arrived and use that for all Interests lacking an
|
||||
expected data size. This is likely to be most compatible with
|
||||
simple interest counting which would rate limit all incoming
|
||||
interests equally
|
||||
|
||||
2. Configure some values for given Name prefixes that have known
|
||||
sizes. This may be appropriate for dedicated forwarders
|
||||
supporting single use cases, such as:
|
||||
|
||||
* A forwarder handling IoT sensors sending very small Data
|
||||
packets
|
||||
|
||||
* A forwarder handling real-time video with large average Data
|
||||
packets that exceed link MTU and are routinely fragmented
|
||||
|
||||
* A forwarder doing voice trunking where the vocoders produce
|
||||
moderate sized packets, still much smaller than the link MTU
|
||||
|
||||
The second area to address is what to do if an interest lacking an
|
||||
expected Data size is responded to by a Data message whose size
|
||||
exceeds the default discussed above. It would be inappropriate to
|
||||
issue a T_MTU_TOO_LARGE error, since the consumer is unlikely to
|
||||
understand or deal correctly with that new error case. Instead, it
|
||||
is RECOMMENDED that the forwarder:
|
||||
|
||||
o Ignore the mismatch if the reverse link is not congested and
|
||||
return the requested Data message anyway.
|
||||
|
||||
o If the reverse link is congested, issue an Interest Return with
|
||||
the T_NO_RESOURCES error code
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 2, 2020 [Page 10]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance August 2019
|
||||
|
||||
|
||||
This specification does not define or recommend any particular
|
||||
algorithm for assessing the congestion state of the link(s) to carry
|
||||
the Data message downstream to the requesting consumers. It is
|
||||
assumed that a reasonable algorithm is in use, because otherwise even
|
||||
basic Interest counting forms of congestion control would not be
|
||||
effective.
|
||||
|
||||
4. Dealing with malicious actors
|
||||
|
||||
First we note that various known attacks in CCNx or NDN can also be
|
||||
mounted by users employing this method. Attacks that involve
|
||||
interest flooding, cache pollution, cache poisoning, etc. are neither
|
||||
worsened nor ameliorated by the introduction of the congestion
|
||||
control capabilities described here. However, there are two new
|
||||
vulnerabilities that need to be dealt with. These two new
|
||||
vulnerabilities involve intentional mis-estimation of data size.
|
||||
|
||||
The first is a consumer who intentionally over-estimates data size
|
||||
with the goal of preventing other users from using the bandwidth.
|
||||
This is at most a minor concern given the above discussion of over-
|
||||
estimation by honest clients. If one of the amelioration techniques
|
||||
above are used, the case of malicious over-estimation is also dealt
|
||||
with adequately.
|
||||
|
||||
The second is a user who intentionally under-estimates the data size
|
||||
with the goal having its Interest processed while the other
|
||||
aggregated interests are not processed, thereby causing
|
||||
T_MTU_TOO_LARGE errors and denying service to the other users with
|
||||
overlapping requests. There are a number of possible mitigation
|
||||
techniques for this attack vector, ranging in complexity. We outline
|
||||
two below; there may be others as or more effective with acceptable
|
||||
complexity and overhead:
|
||||
|
||||
o (Simplest) A user sending Interests resulting in a T_MTU_TOO_LARGE
|
||||
error is treated similarly to users mounting interest flooding
|
||||
attacks; the a router aggregating Interests with differing
|
||||
expected data sizes rate limits the face(s) exhibiting these
|
||||
errors, thus decreasing the ability of a user to issue enough mis-
|
||||
estimated Interests to collide and generate Interest aggregation.
|
||||
|
||||
o An ICN forwarder aggregating Interests remembers in the PIT entry
|
||||
not only the expected data size of the Interest it forwarded, but
|
||||
the maximum of the expected data size of the other Interests it
|
||||
aggregated. If a T_MTU_TOO_LARGE error comes back, instead of
|
||||
propagating it, the forwarder MAY treat this as a transient error,
|
||||
drop the Interest Return, and re-forward the Interest using the
|
||||
maximum expected data size in the PIT (assuming it is is bigger).
|
||||
This recovers from the error, but the attacker can still cause an
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 2, 2020 [Page 11]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance August 2019
|
||||
|
||||
|
||||
extra round trip to the producer or to an upstream forwarder with
|
||||
a copy of the data in its Content Store.
|
||||
|
||||
5. Mapping to CCNx and NDN packet encodings
|
||||
|
||||
The only actual protocol needed is a TLV in Interest messages that
|
||||
states the size in bytes of the expected Data Message coming back,
|
||||
and in the Interest Return on a "too big" error to carry the actual
|
||||
data size. In the case of CCNx, this covers the encapsulated Data
|
||||
Object, but not the hop-by-hop headers.
|
||||
|
||||
5.1. Packet encoding for CCNx
|
||||
|
||||
For CCNx[RFC8569] there is a new hop-by-hop header TLV, and a new
|
||||
value of the Interest Return "Return Type".
|
||||
|
||||
Expected Data Size (for Interest messages), or Actual Data Size (for
|
||||
Interest Return messages) TLV
|
||||
|
||||
+------------+----------+-------------------------------------------+
|
||||
| Abbrev | Name | Description |
|
||||
+------------+----------+-------------------------------------------+
|
||||
| T_DATASIZE | Data | Expected (Section 3)or Actual (Section |
|
||||
| | Size | 3.2) Data Size |
|
||||
+------------+----------+-------------------------------------------+
|
||||
|
||||
Table 1: Data Size TLV
|
||||
|
||||
5.2. Packet encoding for NDN
|
||||
|
||||
TBD based on [NDNTLV]. Suggestions from the NDN team greatly
|
||||
appreciated.
|
||||
|
||||
6. IANA Considerations
|
||||
|
||||
Please Add the T_TIMETLV TLV to the Hop-by-Hop TLV types registry of
|
||||
RFC8609, with fixed length of 2, and data type numeric
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 2, 2020 [Page 12]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance August 2019
|
||||
|
||||
|
||||
Expected/Actual Data Size TLV encoding. The range has an upper bound
|
||||
of 64K bytes, since that is the largest MTU supported by CCNx.
|
||||
|
||||
1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+---------------+---------------+---------------+---------------+
|
||||
| T_TIMETLV | 2 |
|
||||
+---------------+---------------+---------------+---------------+
|
||||
| INTERVAL_TIME (see RFC4574) |
|
||||
+---------------+---------------+
|
||||
|
||||
Figure 1: Compresssed Time Values using RFC4574 encoding
|
||||
|
||||
7. Security Considerations
|
||||
|
||||
8. References
|
||||
|
||||
8.1. Normative References
|
||||
|
||||
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
|
||||
Requirement Levels", BCP 14, RFC 2119,
|
||||
DOI 10.17487/RFC2119, March 1997, <https://www.rfc-
|
||||
editor.org/info/rfc2119>.
|
||||
|
||||
[RFC8569] Mosko, M., Solis, I., and C. Wood, "Content-Centric
|
||||
Networking (CCNx) Semantics", RFC 8569,
|
||||
DOI 10.17487/RFC8569, July 2019, <https://www.rfc-
|
||||
editor.org/info/rfc8569>.
|
||||
|
||||
[RFC8609] Mosko, M., Solis, I., and C. Wood, "Content-Centric
|
||||
Networking (CCNx) Messages in TLV Format", RFC 8609,
|
||||
DOI 10.17487/RFC8609, July 2019, <https://www.rfc-
|
||||
editor.org/info/rfc8609>.
|
||||
|
||||
8.2. Informative References
|
||||
|
||||
[Carofiglio2012]
|
||||
Carofiglio, G., Gallo, M., and L. Muscariello, "Joint hop-
|
||||
by-hop and receiver-driven interest control protocol for
|
||||
content-centric networks, in ICN Workshop at SIGcomm
|
||||
2012", DOI 10.1145/2377677.2377772, 2102,
|
||||
<http://conferences.sigcomm.org/sigcomm/2012/paper/icn/
|
||||
p37.pdf>.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 2, 2020 [Page 13]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance August 2019
|
||||
|
||||
|
||||
[Ghali2013]
|
||||
Ghali, C., Narayanan, A., Oran, D., Tsudik, G., and C.
|
||||
Wood, "Secure Fragmentation for Content-Centric Networks,
|
||||
in IEEE 14th International Symposium on Network Computing
|
||||
and Applications", DOI 10.1109/nca.2015.34, 2015,
|
||||
<http://dx.doi.org/10.1109/NCA.2015.34>.
|
||||
|
||||
[I-D.ietf-quic-transport]
|
||||
Iyengar, J. and M. Thomson, "QUIC: A UDP-Based Multiplexed
|
||||
and Secure Transport", draft-ietf-quic-transport-23 (work
|
||||
in progress), September 2019.
|
||||
|
||||
[Mahdian2016]
|
||||
Mahdian, M., Arianfar, S., Gibson, J., and D. Oran,
|
||||
"MIRCC: Multipath-aware ICN Rate-based Congestion Control,
|
||||
in Proceedings of the 3rd ACM Conference on Information-
|
||||
Centric Networking", DOI 10.1145/2984356.2984365, 2016,
|
||||
<http://conferences2.sigcomm.org/acm-icn/2016/proceedings/
|
||||
p1-mahdian.pdf>.
|
||||
|
||||
[minmaxfairness]
|
||||
Wikipedia, , "Max-min Fairness", various,
|
||||
<https://en.wikipedia.org/wiki/Max-min_fairness>.
|
||||
|
||||
[NDN] NDN team, , "Named Data Networking", various,
|
||||
<https://named-data.net/project/execsummary/>.
|
||||
|
||||
[NDNTLV] NDN Project Team, , "NDN Packet Format Specification.",
|
||||
2016, <http://named-data.net/doc/ndn-tlv/>.
|
||||
|
||||
[proportionalfairness]
|
||||
Wikipedia, , "Proportionally Fair", various,
|
||||
<https://en.wikipedia.org/wiki/Proportionally_fair>.
|
||||
|
||||
[RFC0793] Postel, J., "Transmission Control Protocol", STD 7,
|
||||
RFC 793, DOI 10.17487/RFC0793, September 1981,
|
||||
<https://www.rfc-editor.org/info/rfc793>.
|
||||
|
||||
[RFC4340] Kohler, E., Handley, M., and S. Floyd, "Datagram
|
||||
Congestion Control Protocol (DCCP)", RFC 4340,
|
||||
DOI 10.17487/RFC4340, March 2006, <https://www.rfc-
|
||||
editor.org/info/rfc4340>.
|
||||
|
||||
[RFC4960] Stewart, R., Ed., "Stream Control Transmission Protocol",
|
||||
RFC 4960, DOI 10.17487/RFC4960, September 2007,
|
||||
<https://www.rfc-editor.org/info/rfc4960>.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 2, 2020 [Page 14]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance August 2019
|
||||
|
||||
|
||||
[Schneider2016]
|
||||
Schneider, K., Yi, C., Zhang, B., and L. Zhang, "A
|
||||
Practical Congestion Control Scheme for Named Data
|
||||
Networking, in Proceedings of the 2016 conference on 3rd
|
||||
ACM Conference on Information-Centric Networking - ACM-ICN
|
||||
'16", DOI 10.1145/2984356.2984369, 2016,
|
||||
<http://conferences2.sigcomm.org/acm-icn/2016/proceedings/
|
||||
p21-schneider.pdf>.
|
||||
|
||||
[Song2018]
|
||||
Song, J., Lee, M., and T. Kwon, "SMIC: Subflow-level
|
||||
Multi-path Interest Control for Information Centric
|
||||
Networking, in 5th ACM Conference on Information-Centric
|
||||
Networking", DOI 10.1145/3267955.3267971, 2018,
|
||||
<https://conferences.sigcomm.org/acm-icn/2018/proceedings/
|
||||
icn18-final62.pdf>.
|
||||
|
||||
[Wang2013]
|
||||
Wang, Y., Rozhnova, N., Narayanan, A., Oran, D., and I.
|
||||
Rhee, "An Improved Hop-by-hop Interest Shaper for
|
||||
Congestion Control in Named Data Networking, in ACM
|
||||
SIGCOMM Workshop on Information-Centric Networking",
|
||||
DOI 10.1145/2534169.2491233, 2013,
|
||||
<http://conferences.sigcomm.org/sigcomm/2013/papers/icn/
|
||||
p55.pdf>.
|
||||
|
||||
Author's Address
|
||||
|
||||
Dave Oran
|
||||
Network Systems Research and Design
|
||||
4 Shady Hill Square
|
||||
Cambridge, MA 02138
|
||||
USA
|
||||
|
||||
Email: daveoran@orandom.net
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 2, 2020 [Page 15]
|
||||
Binary file not shown.
@@ -0,0 +1,784 @@
|
||||
|
||||
|
||||
|
||||
|
||||
ICNRG D. Oran
|
||||
Internet-Draft Network Systems Research and Design
|
||||
Intended status: Experimental July 2019
|
||||
Expires: January 2, 2020
|
||||
|
||||
|
||||
Maintaining CCNx or NDN flow balance with highly variable data object
|
||||
sizes
|
||||
draft-oran-icnrg-flowbalance-00
|
||||
|
||||
Abstract
|
||||
|
||||
Deeply embedded in some ICN architectures, especially Named Data
|
||||
Networking (NDN) and Content-Centric Networking (CCNx) is the notion
|
||||
of flow balance. This captures the idea that there is a one-to-one
|
||||
correspondence between requests for data, carried in Interest
|
||||
messages, and the responses with the requested data object, carried
|
||||
in Data messages. This has a number of highly beneficial properties
|
||||
for flow and congestion control in networks, as well as some
|
||||
desirable security properties. For example, neither legitimate users
|
||||
nor attackers are able to inject large amounts of un-requested data
|
||||
into the network.
|
||||
|
||||
Existing congestion control approaches however cannot deal
|
||||
effectively with a widely varying MTU of ICN data messages, since the
|
||||
protocols allow a dynamic range of 1-64K bytes. Since Interest
|
||||
messages are used to allocate the reverse link bandwidth for
|
||||
returning Data, there is large uncertainty in how to allocate that
|
||||
bandwidth. Unfortunately, current congestion control schemes in CCNx
|
||||
and NDN only count Interest messages and have no idea how much data
|
||||
is involved that could congest the inverse link. This document
|
||||
proposes a method to maintain flow balance by accommodating the wide
|
||||
dynamic range in Data message MTU.
|
||||
|
||||
Status of This Memo
|
||||
|
||||
This Internet-Draft is submitted in full conformance with the
|
||||
provisions of BCP 78 and BCP 79.
|
||||
|
||||
Internet-Drafts are working documents of the Internet Engineering
|
||||
Task Force (IETF). Note that other groups may also distribute
|
||||
working documents as Internet-Drafts. The list of current Internet-
|
||||
Drafts is at http://datatracker.ietf.org/drafts/current/.
|
||||
|
||||
Internet-Drafts are draft documents valid for a maximum of six months
|
||||
and may be updated, replaced, or obsoleted by other documents at any
|
||||
time. It is inappropriate to use Internet-Drafts as reference
|
||||
material or to cite them other than as "work in progress."
|
||||
|
||||
|
||||
|
||||
D. Oran Expires January 2, 2020 [Page 1]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance July 2019
|
||||
|
||||
|
||||
This Internet-Draft will expire on January 2, 2020.
|
||||
|
||||
Copyright Notice
|
||||
|
||||
Copyright (c) 2019 IETF Trust and the persons identified as the
|
||||
document authors. All rights reserved.
|
||||
|
||||
This document is subject to BCP 78 and the IETF Trust's Legal
|
||||
Provisions Relating to IETF Documents
|
||||
(http://trustee.ietf.org/license-info) in effect on the date of
|
||||
publication of this document. Please review these documents
|
||||
carefully, as they describe your rights and restrictions with respect
|
||||
to this document. Code Components extracted from this document must
|
||||
include Simplified BSD License text as described in Section 4.e of
|
||||
the Trust Legal Provisions and are provided without warranty as
|
||||
described in the Simplified BSD License.
|
||||
|
||||
Table of Contents
|
||||
|
||||
1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 2
|
||||
2. Requirements Language . . . . . . . . . . . . . . . . . . . . 4
|
||||
3. Method to enhance congestion control with signaled size
|
||||
information in Interest Messages . . . . . . . . . . . . . . 4
|
||||
3.1. How to predict the size of returning Data messages . . . 5
|
||||
3.2. Handling `too big' cases . . . . . . . . . . . . . . . . 6
|
||||
3.3. Handling `too small' cases . . . . . . . . . . . . . . . 7
|
||||
3.4. Interactions with Interest Aggregation . . . . . . . . . 8
|
||||
3.5. Operation when some Interests lack the expected data size
|
||||
option and some have it . . . . . . . . . . . . . . . . . 9
|
||||
4. Dealing with for malicious actors . . . . . . . . . . . . . . 10
|
||||
5. Mapping to CCNx and NDN packet encodings . . . . . . . . . . 11
|
||||
5.1. Packet encoding for CCNx . . . . . . . . . . . . . . . . 11
|
||||
5.2. Packet encoding for NDN . . . . . . . . . . . . . . . . . 11
|
||||
6. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 11
|
||||
7. Security Considerations . . . . . . . . . . . . . . . . . . . 12
|
||||
8. References . . . . . . . . . . . . . . . . . . . . . . . . . 12
|
||||
8.1. Normative References . . . . . . . . . . . . . . . . . . 12
|
||||
8.2. Informative References . . . . . . . . . . . . . . . . . 13
|
||||
Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 14
|
||||
|
||||
1. Introduction
|
||||
|
||||
Deeply embedded in some ICN architectures, especially Named Data
|
||||
Networking (NDN [NDN]) and Content-Centric Networking (CCNx
|
||||
[RFC8569],[RFC8609]) is the notion of flow balance. This captures
|
||||
the idea that there is a one-to-one correspondence between requests
|
||||
for data, carried in Interest messages, and the responses with the
|
||||
requested data object, carried in Data messages. This has a number
|
||||
|
||||
|
||||
|
||||
D. Oran Expires January 2, 2020 [Page 2]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance July 2019
|
||||
|
||||
|
||||
of highly beneficial properties for flow and congestion control in
|
||||
networks, as well as some desirable security properties. For
|
||||
example, neither legitimate users nor attackers are able to inject
|
||||
large amounts of un-requested data into the network.
|
||||
|
||||
This approach leads to a desire to make the size of the objects
|
||||
carried in Data messages small and near constant, because flow
|
||||
balance can then be kept using simple bookkeeping of how many
|
||||
Interest messages are outstanding. While simple, constraining Data
|
||||
messages to be quite small - usually on the order of a link Maximum
|
||||
Transmission Unit (MTU) - has some constraints and deleterious
|
||||
effects, among which are:
|
||||
|
||||
o Such small data objects are inconvenient for many applications;
|
||||
their natural data object sizes can be considerably larger than a
|
||||
link MTU.
|
||||
|
||||
o Applications with truly small data objects (e.g. voice packets in
|
||||
an Internet telephony applications) have no way to communicate
|
||||
that to the network, causing resources to still be allocated for
|
||||
MTU-sized data objects
|
||||
|
||||
o When chunking a larger data object into multiple Data messages,
|
||||
each message has to be individually cryptographically hashed and
|
||||
signed, increasing both computational overhead and overall message
|
||||
header size. The signature can be elided when Manifests are used
|
||||
(by signing the Manifest instead), but the overhead of hashing
|
||||
multiple small messages rather than fewer larger ones remains.
|
||||
|
||||
One approach which helps with the last of these is to employ
|
||||
fragmentation for Data messages larger than the Path MTU (PMTU). such
|
||||
messages are carved into smaller pieces for transmission over the
|
||||
link(s). There are three flavors of fragmentation: end-to-end, hop-
|
||||
by-hop with reassembly at every hop, and hop-by-hop with cut-through
|
||||
of individual fragments. A number of ICN protocol architectures
|
||||
incorporate fragmentation and schemes have been proposed for both NDN
|
||||
and CCNx, for example in [Ghali2013]. Fragmentation alone does not
|
||||
ameliorate the flow balance problem however, since from a resource
|
||||
allocation standpoint both memory and link bandwidth must be set
|
||||
aside for maximum-sized data objects to avoid congestion collapse
|
||||
under overload.
|
||||
|
||||
The design space considered in this document does not however extend
|
||||
to arbitrarily large objects (e.g. 100's of kilobytes or larger). As
|
||||
the dynamic range of data object sizes gets very large, finding the
|
||||
right tradeoff between handling a large number of small data objects
|
||||
versus a single very large data object when allocating link and
|
||||
buffer resources becomes intractable. Further, the semantics of
|
||||
|
||||
|
||||
|
||||
D. Oran Expires January 2, 2020 [Page 3]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance July 2019
|
||||
|
||||
|
||||
Interest-Data exchanges means that any error in the exchange results
|
||||
in a re-issue of an Interest for the entire Data object. Very large
|
||||
data objects represent a performance problem because the cost of
|
||||
retransmission when Interests are retransmitted (or re-issued)
|
||||
becomes unsustainably high. Therefore, the method we propose deals
|
||||
with a dynamic range of object sizes from very small (a fraction of a
|
||||
link MTU) to moderately large - about 64 kilobytes or equivalently
|
||||
about 40 Ethernet packets, and assumes an associated fragmentation
|
||||
scheme to handle link MTUs that cannot carry the object in a single
|
||||
link-layer packet.
|
||||
|
||||
The approach described in the rest of this document maintains flow
|
||||
balance under the conditions outlined above by allocating resources
|
||||
accurately based on expected data object size, rather than employing
|
||||
simple interest counting.
|
||||
|
||||
2. Requirements Language
|
||||
|
||||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
|
||||
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
|
||||
document are to be interpreted as described in RFC 2119 [RFC2119].
|
||||
|
||||
3. Method to enhance congestion control with signaled size information
|
||||
in Interest Messages
|
||||
|
||||
Before diving into the specifics of the design, it is useful to
|
||||
consider how congestion control works in NDN/CCNx. Unlike the IP
|
||||
protocol family, which relies on end-to-end congestion control (e.g.
|
||||
TCP, DCCP, SCTP, QUIC), CCNx and NDN employ hop-by-hop congestion
|
||||
control. There is per-Interest/Data state at every hop of the path
|
||||
and therefore for each outstanding Interest, bandwidth for data
|
||||
returning on the inverse path can be allocated. In the current
|
||||
design, this allocation is done using simple Interest counting - by
|
||||
accepting one Interest packet from an downstream node, implicitly
|
||||
this provides a guarantee (either hard or soft) that there is
|
||||
sufficient bandwidth on the inverse direction of the link to send
|
||||
back one Data packet. A number of congestion control schemes have
|
||||
been developed that operate in this fashion, for example
|
||||
[Wang2013],[Mahdian2016],[Song2018],[Carofiglio2012].
|
||||
|
||||
In order to deal with a larger dynamic range of data object size,
|
||||
some means is required to allocate link bandwidth for data messages
|
||||
in bytes with an upper bound larger than a link PMTU and a lower
|
||||
bound lower than a single link MTU. Since resources are allocated
|
||||
for returning Data based on arriving Interests, this information must
|
||||
be available in Interest messages.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
D. Oran Expires January 2, 2020 [Page 4]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance July 2019
|
||||
|
||||
|
||||
Therefore, one key idea is the inclusion of an "expected data size"
|
||||
TLV in each Interest message. This allows each forwarder on the path
|
||||
taken by the interest to accurately allocate bandwidth on the inverse
|
||||
path for the returning Data message. Also, by including the expected
|
||||
data size, large objects will have a corresponding weight in resource
|
||||
allocation, maintaining link and forarder buffering fairness. The
|
||||
simpler Interest counting scheme was nominally "fair" on a per-
|
||||
exchange basis within the variations of data that fit in a single
|
||||
PMTU packet because all Interests produced similar amounts of data in
|
||||
return. In the absence of such a field, it is not feasible to allow
|
||||
a large dynamic range in object size.
|
||||
|
||||
3.1. How to predict the size of returning Data messages
|
||||
|
||||
This of course raises the question "How does the requester know how
|
||||
big the corresponding data coming back will be?". For a number of
|
||||
important applications, the size is known a priori due to the
|
||||
characteristics of the application. Here are some examples:
|
||||
|
||||
o For many sensor and other Internet-of-Things applications, the
|
||||
data is instrument readings which have fixed known size.
|
||||
|
||||
o In video streaming, the data is output of a video encoder which
|
||||
produces variable sized frames. This information is typically
|
||||
made available ahead of time to the streaming clients in the form
|
||||
of a Manifest [4], which contains the names of the corresponding
|
||||
segments (or individual frames) of video and audio and their
|
||||
sizes.
|
||||
|
||||
o Internet telephony applications use vocoders that typically employ
|
||||
fixed-size audio frames. Therefore, their size is known either a
|
||||
priori, or via an initialization exchange at the start of an audio
|
||||
session.
|
||||
|
||||
The more complex cases arise where the data size is not known at the
|
||||
time the Interest must be sent. Much of the nunce of the proposed
|
||||
scheme is in how mismatches between the expected data size and the
|
||||
actual data object returned are handled. The consumer can either
|
||||
under- or over-estimate the data size. In the former case, the
|
||||
under-estimate can lead to congestion and possible loss of data. In
|
||||
the latter case, bandwidth that could have been used by data objects
|
||||
requested by other consumers might be wasted. We first consider
|
||||
"honest" mis-estimates due to imperfect knowledge by the ICN
|
||||
application; later we consider malicious applications that are using
|
||||
the machinery to mount some form of attack. We also consider the
|
||||
effects of Interest aggregation if the aggregated Interests have
|
||||
differing expected data sizes. Also, it should be obvious that if
|
||||
the Data message arrives, the application learns its actual size,
|
||||
|
||||
|
||||
|
||||
D. Oran Expires January 2, 2020 [Page 5]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance July 2019
|
||||
|
||||
|
||||
which may or may not be useful in adjusting the expected data size
|
||||
estimate for future Interests.
|
||||
|
||||
In all cases, the expected data size from the Interest can be
|
||||
incorporated in the corresponding Pending Interest Table (PIT) entry
|
||||
of each CCNx/NDN forwarder on the path and hence when a (possibly
|
||||
fragmented) Data object comes back, its total size is known and can
|
||||
be compared to the expected size in the PIT for a mismatch. Aside:
|
||||
In the case of fragmentation, we assume a fragmentation scheme in
|
||||
which the total data size can be known as soon as any one fragment is
|
||||
received (a reasonable assumption for most any well-designed
|
||||
fragmentation method).
|
||||
|
||||
3.2. Handling `too big' cases
|
||||
|
||||
If the returning data is larger than the expected data size, the
|
||||
extra data could result in either unfair bandwidth allocation or
|
||||
possibly data loss under congestion conditions. When this is
|
||||
detected, the forwarder has three choices:
|
||||
|
||||
1. It could forward the data anyway, which is safe under non-
|
||||
congestion conditions, but unfair and possibly unstable when the
|
||||
output link is congested
|
||||
|
||||
2. It could forward the data when un-congested (e.g. by assessing
|
||||
output queue depth) but drop it when congested
|
||||
|
||||
3. It could always drop the data, as a way of "punishing" the
|
||||
requester for the mis-estimate.
|
||||
|
||||
Either of the latter two strategies is acceptable from a congestion
|
||||
control point of view. However, it is not a good idea to simply drop
|
||||
the Data message with no feedback to the issuer of the Interest
|
||||
because the application has no way to learn the actual data size and
|
||||
retry. Further, recovery would be delayed until the failing Interest
|
||||
timed out. Therefore, an additional element needed in protocol
|
||||
semantics is the incorporation of a "Data too big" error message (via
|
||||
an "interest Return" packet in CCNx).
|
||||
|
||||
Upon dropping data as above, the CCNx/NDN forwarder converts the
|
||||
normal Data message into an Interest Return message containing the
|
||||
with the T_MTU_TOO_LARGE error code and the actual size of the data
|
||||
object instead of the data object content. It propagates that back
|
||||
toward the client identically to how the original Data message would
|
||||
have been handled. Subsequent nodes upon receiving the
|
||||
T_MTU_TOO_LARGE error treat it as all other Interest Return errors.
|
||||
When the Interest Return eventually arrives back to the issuer of the
|
||||
|
||||
|
||||
|
||||
|
||||
D. Oran Expires January 2, 2020 [Page 6]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance July 2019
|
||||
|
||||
|
||||
Interest, the user can, they desire, reissue the Interest with the
|
||||
correct expected data size.
|
||||
|
||||
One detail to note is that an Interest Return carrying
|
||||
T_MTU_TOO_LARGE must be deterministically smaller than the expected
|
||||
data size in all cases. This is clearly the case for large data
|
||||
objects, but there is a corner case with small data objects. There
|
||||
has to be a minimum expected data size that a client can specify in
|
||||
their Interests, and that minimum cannot be smaller than the size of
|
||||
a T_MTU_TOO_LARGE Interest Return
|
||||
|
||||
3.3. Handling `too small' cases
|
||||
|
||||
Next we consider the case where the returning data is smaller than
|
||||
the expected data size. While this case does not result in
|
||||
congestion, it can cause resources to be inefficiently allocated
|
||||
because not all of the set-aside bandwidth for the returning data
|
||||
object gets used. The simplest and most straightforward way to deal
|
||||
with this case is to essentially ignore it. The motivation for not
|
||||
worrying about the smaller data mismatch is that in many situations
|
||||
that employ usage-based resource measurement (and possibly charging),
|
||||
it is trivial to just account for the usage according to the larger
|
||||
expected data size rather than actual returned data size. Properly
|
||||
adjusting congestion control parameters to somehow penalize users for
|
||||
over-estimating their resource usage requires fairly heavyweight
|
||||
machinery, which in most cases is not warranted. If desired, any of
|
||||
the following mechanisms could be considered:
|
||||
|
||||
o Attempt to identify future Interests for the same object or
|
||||
closely related objects and allocate resources based on some
|
||||
retained state about the actual size of prior objects
|
||||
|
||||
o Police consumer behavior and decrease the expected data size in
|
||||
one or more future Interests to compensate
|
||||
|
||||
o For small objects, do more optimistic resource allocation on the
|
||||
links on the presumption that there will be some "slack" due to
|
||||
clients overestimating data object size.
|
||||
|
||||
One protocol detail of CCNx/NDN that needs to be dealt with is
|
||||
Interest Aggregation. This happens when multiple Interests arrive at
|
||||
a forwarder for the same Named object. These are aggregated such
|
||||
that one of them (i.e.the first to arrive and create PIT state) is
|
||||
forwarded, and the rest are dropped while marking the arrival face so
|
||||
the data can be sent back to the multiple requesting clients.
|
||||
Interest aggregation interacts with expected data size if Interests
|
||||
from different clients contain different values of the expected data
|
||||
size. As above, the simplest solution to this problem is to ignore
|
||||
|
||||
|
||||
|
||||
D. Oran Expires January 2, 2020 [Page 7]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance July 2019
|
||||
|
||||
|
||||
it, as most error cases are benign. However, there is one
|
||||
problematic error case where one client provides an accurate expected
|
||||
data size, but another who issued the Interest first underestimates,
|
||||
causing both to receive a Data too big error. This introduces a
|
||||
denial of service vulnerability, which we discuss below together with
|
||||
the other malicious actor cases.
|
||||
|
||||
3.4. Interactions with Interest Aggregation
|
||||
|
||||
Interest Aggregation, while a powerful feature for maintaining flow
|
||||
balance when multiple consumers send Interests for the same Named
|
||||
object, introduces subtle complications. Whenever a second or
|
||||
subsequent Interest arrives at a forwarder with an active PIT entry
|
||||
it is possible that those Interests carry different parameters, for
|
||||
example hop limit, payload, etc. It is therefore necessary to
|
||||
specify the exact behavior of the forwarder for each of the
|
||||
parameters that might differ. In the case of the expected data size
|
||||
parameter defined here, the value is associated with the ingress face
|
||||
on which the Interest creating the PIT entry arrived, as opposed to
|
||||
being global to the PIT entry as a whole. There are two cases to
|
||||
consider:
|
||||
|
||||
1. The arriving interest carries an expected data size smaller than
|
||||
any of the values associated with the PIT entry.
|
||||
|
||||
2. The arriving interest carries an expected data size larger than
|
||||
any of the values associated with the PIT entry.
|
||||
|
||||
For Case (1) the Interest can be safely aggregated since the upstream
|
||||
links will have sufficient bandwidth allocated based on the larger
|
||||
expected data size (assuming the original Interest's expected data
|
||||
size was itself sufficiently large to accommodate the actual size of
|
||||
the returning Data. On the other hand, should the incoming face have
|
||||
bandwidth allocated based on the larger existing Interest's expected
|
||||
data size, or on the smaller value in the arriving interest? Here
|
||||
there are two possible approaches:
|
||||
|
||||
a. Allocate based on the data size already in the PIT. In this case
|
||||
the consumer sending the earlier Interest can cause obver-
|
||||
allocation of link bandwidth for other incoming faces, but there
|
||||
will not be a T_MTU_TOO_LARGE error generated for that Interest
|
||||
|
||||
b. Allocate based on the value in the arriving Interest. If the
|
||||
returning Data is in fact larger, generate a T_MTU_TOO_LARGE
|
||||
Interest Return on that ingress face, while successfully
|
||||
returning the Data message on any faces that do not exhibit a too
|
||||
small expected data size
|
||||
|
||||
|
||||
|
||||
|
||||
D. Oran Expires January 2, 2020 [Page 8]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance July 2019
|
||||
|
||||
|
||||
It is RECOMMENDED that the second policy be followed.
|
||||
|
||||
For Case (2) above, the Interest MUST be forwarded rather than
|
||||
aggregated to prevent a consumer from mounting a denial of service
|
||||
attack by sending intentionally too small expected data size (see
|
||||
Section 4 for additional detail on this and other attacks). As above
|
||||
for Case (1) it is RECOMMENDED that policy (b) above be followed.
|
||||
|
||||
3.5. Operation when some Interests lack the expected data size option
|
||||
and some have it
|
||||
|
||||
Since the expected data size hop-by-hop option forwarders need to be
|
||||
prepared to handle an arbitrary mix of the two forms. There are two
|
||||
general things to address.
|
||||
|
||||
First, we assume that any forwarder supporting expected data size is
|
||||
running a more sophisticated congestion control algorithm that one
|
||||
employing simple interest counting. The link bandwidth resource
|
||||
allocation is therefore based directly, or indirectly, on the
|
||||
expected Data size in bytes. Therefore, the forwarder has to assign
|
||||
a value to use in the resource allocation for the reverse link. This
|
||||
specification does not mandate any particular approach or a default
|
||||
value to use. However, in the absence on other guidance, it makes
|
||||
sense to do one of two things:
|
||||
|
||||
1. Pick a default based on the link MTU of the face on which the
|
||||
Interest arrived and use that for all Interests lacking an
|
||||
expected data size. This is likely to be most compatible with
|
||||
simple interest counting which would rate limit all incoming
|
||||
interests equally
|
||||
|
||||
2. Configure some values for given Name prefixes that have known
|
||||
sizes. This may be appropriate for dedicated forwarders
|
||||
supporting single use cases, such as:
|
||||
|
||||
* A forwarder handling IoT sensors sending very small Data
|
||||
packets
|
||||
|
||||
* A forwarder handling real-time video with large average Data
|
||||
packets that exceed link MTU and are routinely fragmented
|
||||
|
||||
* A forwarder doing voice trunking where the vocoders produce
|
||||
moderate sized packets, still much smaller than the link MTU
|
||||
|
||||
The second area to address is what to do if an interest lacking an
|
||||
expected Data size is responded to by a Data message whose size
|
||||
exceeds the default discussed above. It would be inappropriate to
|
||||
issue a T_MTU_TOO_LARGE error, since the consumer is unlikely to
|
||||
|
||||
|
||||
|
||||
D. Oran Expires January 2, 2020 [Page 9]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance July 2019
|
||||
|
||||
|
||||
understand or deal correctly with that new error case. Instead, it
|
||||
is RECOMMENDED that the forwarder:
|
||||
|
||||
o Ignore the mismatch if the reverse link is not congested and
|
||||
return the requested Data message anyway.
|
||||
|
||||
o If the reverse link is congested, issue an Interest Return with
|
||||
the T_NO_RESOURCES error code
|
||||
|
||||
This specification does not define or recommend any particular
|
||||
algorithm for assessing the congestion state of the link(s) to carry
|
||||
the Data message downstream to the requesting consumers. It is
|
||||
assumed that a reasonable algorithm is in sue, because otherwise even
|
||||
basic Interest counting forms of congestion control would not be
|
||||
effective.
|
||||
|
||||
4. Dealing with for malicious actors
|
||||
|
||||
First we note that various known attacks in CCNx or NDN can also be
|
||||
mounted by users employing this method. Attacks that involve
|
||||
interest flooding, cache pollution, cache poisoning, etc. are neither
|
||||
worsened nor ameliorated by the introduction of the congestion
|
||||
control capabilities described here. However, there are two new
|
||||
vulnerabilities that need to be dealt with. These two new
|
||||
vulnerabilities involve intentional mis-estimation of data size.
|
||||
|
||||
The first is a consumer who intentionally over-estimates data size
|
||||
with the goal of preventing other users from using the bandwidth.
|
||||
This is at most a minor concern given the above discussion of over-
|
||||
estimation by honest clients. If one of the amelioration techniques
|
||||
above are used, the case of malicious over-estimation is also dealt
|
||||
with adequately.
|
||||
|
||||
The second is a user who intentionally under-estimates the data size
|
||||
with the goal having its Interest processed while the other
|
||||
aggregated interests are not processed, thereby causing
|
||||
T_MTU_TOO_LARGE errors and denying service to the other users with
|
||||
overlapping requests. There are a number of possible mitigation
|
||||
techniques for this attack vector, ranging in complexity. We outline
|
||||
two below; there may be others as or more effective with acceptable
|
||||
complexity and overhead:
|
||||
|
||||
o (Simplest) A user sending Interests resulting in a T_MTU_TOO_LARGE
|
||||
error is treated similarly to users mounting interest flooding
|
||||
attacks; the a router aggregating Interests with differing
|
||||
expected data sizes rate limits the face(s) exhibiting these
|
||||
errors, thus decreasing the ability of a user to issue enough mis-
|
||||
estimated Interests to collide and generate Interest aggregation.
|
||||
|
||||
|
||||
|
||||
D. Oran Expires January 2, 2020 [Page 10]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance July 2019
|
||||
|
||||
|
||||
o An ICN forwarder aggregating Interests remembers in the PIT entry
|
||||
not only the expected data size of the Interest it forwarded, but
|
||||
the maximum of the expected data size of the other Interests it
|
||||
aggregated. If a T_MTU_TOO_LARGE error comes back, instead of
|
||||
propagating it, the forwarder MAY treat this as a transient error,
|
||||
drop the Interest Return, and re-forward the Interest using the
|
||||
maximum expected data size in the PIT (assuming it is is bigger).
|
||||
This recovers from the error, but the attacker can still cause an
|
||||
extra round trip to the producer or to an upstream forwarder with
|
||||
a copy of the data in its Content Store.
|
||||
|
||||
5. Mapping to CCNx and NDN packet encodings
|
||||
|
||||
The only actual protocol needed is a TLV in Interest messages that
|
||||
states the size in bytes of the expected Data Message coming back,
|
||||
and in the Interest Return on a "too big" error to carry the actual
|
||||
data size. In the case of CCNx, this covers the encapsulated Data
|
||||
Object, but not the hop-by-hop headers.
|
||||
|
||||
5.1. Packet encoding for CCNx
|
||||
|
||||
For CCNx[RFC8569] there is a new hop-by-hop header TLV, and a new
|
||||
value of the Interest Return "Return Type".
|
||||
|
||||
Expected Data Size (for Interest messages), or Actual Data Size (for
|
||||
Interest Return messages) TLV
|
||||
|
||||
+------------+----------+-------------------------------------------+
|
||||
| Abbrev | Name | Description |
|
||||
+------------+----------+-------------------------------------------+
|
||||
| T_DATASIZE | Data | Expected (Section 3)or Actual (Section |
|
||||
| | Size | 3.2) Data Size |
|
||||
+------------+----------+-------------------------------------------+
|
||||
|
||||
Table 1: Data Size TLV
|
||||
|
||||
5.2. Packet encoding for NDN
|
||||
|
||||
TBD based on [NDNTLV]. Suggestions from the NDN team greatly
|
||||
appreciated.
|
||||
|
||||
6. IANA Considerations
|
||||
|
||||
Please Add the T_DATASIZE TLV to the Hop-by-Hop TLV types registry,
|
||||
with fixed length of 2, and data type numeric
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
D. Oran Expires January 2, 2020 [Page 11]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance July 2019
|
||||
|
||||
|
||||
Expected/Actual Data Size TLV encoding. The range has an upper bound
|
||||
of 64K bytes, since that is the largest MTU supported by CCNx.
|
||||
|
||||
1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+---------------+---------------+---------------+---------------+
|
||||
| T_DATASIZE | 2 |
|
||||
+---------------+---------------+---------------+---------------+
|
||||
| Size in bytes (1-65535) |
|
||||
+---------------+---------------+
|
||||
|
||||
Figure 1: Expected/Actual Data Size Encoding
|
||||
|
||||
7. Security Considerations
|
||||
|
||||
Here we recapitulate the vulnerabilities, attack scenarios and
|
||||
mitigations.
|
||||
|
||||
The "too big" error that generates an Interest Return with
|
||||
T_MTU_TOO_LARGE leaks the actual data object size to any consumer who
|
||||
can issue an Interest with an intentionally small expected data size.
|
||||
This does not represent a privacy vulnerability, for two reasons:
|
||||
|
||||
1. The user could learn the actual data size just by looking at the
|
||||
returned Data message using a properly-constructed Interest.
|
||||
|
||||
2. In many cases the actual data sizes are already available as
|
||||
meta-data in the corresponding Manifest pointing to the Data
|
||||
object.
|
||||
|
||||
8. References
|
||||
|
||||
8.1. Normative References
|
||||
|
||||
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
|
||||
Requirement Levels", BCP 14, RFC 2119,
|
||||
DOI 10.17487/RFC2119, March 1997, <https://www.rfc-
|
||||
editor.org/info/rfc2119>.
|
||||
|
||||
[RFC8569] Mosko, M., Solis, I., and C. Wood, "Content-Centric
|
||||
Networking (CCNx) Semantics", RFC 8569,
|
||||
DOI 10.17487/RFC8569, July 2019, <https://www.rfc-
|
||||
editor.org/info/rfc8569>.
|
||||
|
||||
[RFC8609] Mosko, M., Solis, I., and C. Wood, "Content-Centric
|
||||
Networking (CCNx) Messages in TLV Format", RFC 8609,
|
||||
DOI 10.17487/RFC8609, July 2019, <https://www.rfc-
|
||||
editor.org/info/rfc8609>.
|
||||
|
||||
|
||||
|
||||
D. Oran Expires January 2, 2020 [Page 12]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance July 2019
|
||||
|
||||
|
||||
8.2. Informative References
|
||||
|
||||
[Carofiglio2012]
|
||||
Carofiglio, G., Gallo, M., and L. Muscariello, "Joint hop-
|
||||
by-hop and receiver-driven interest control protocol for
|
||||
content-centric networks, in ICN Workshop at SIGcomm
|
||||
2012", DOI 10.1145/2377677.2377772, 2102,
|
||||
<http://conferences.sigcomm.org/sigcomm/2012/paper/icn/
|
||||
p37.pdf>.
|
||||
|
||||
[Ghali2013]
|
||||
Ghali, C., Narayanan, A., Oran, D., Tsudik, G., and C.
|
||||
Wood, "Secure Fragmentation for Content-Centric Networks,
|
||||
in IEEE 14th International Symposium on Network Computing
|
||||
and Applications", DOI 10.1109/nca.2015.34, 2015,
|
||||
<http://dx.doi.org/10.1109/NCA.2015.34>.
|
||||
|
||||
[Mahdian2016]
|
||||
Mahdian, M., Arianfar, S., Gibson, J., and D. Oran,
|
||||
"MIRCC: Multipath-aware ICN Rate-based Congestion Control,
|
||||
in Proceedings of the 3rd ACM Conference on Information-
|
||||
Centric Networking", DOI 10.1145/2984356.2984365, 2016,
|
||||
<http://conferences2.sigcomm.org/acm-icn/2016/proceedings/
|
||||
p1-mahdian.pdf>.
|
||||
|
||||
[NDN] NDN team, , "Named Data Networking", various,
|
||||
<https://named-data.net/project/execsummary/>.
|
||||
|
||||
[NDNTLV] NDN Project Team, , "NDN Packet Format Specification.",
|
||||
2016, <http://named-data.net/doc/ndn-tlv/>.
|
||||
|
||||
[Song2018]
|
||||
Song, J., Lee, M., and T. Kwon, "SMIC: Subflow-level
|
||||
Multi-path Interest Control for Information Centric
|
||||
Networking, in 5th ACM Conference on Information-Centric
|
||||
Networking", DOI 10.1145/3267955.3267971, 2018,
|
||||
<https://conferences.sigcomm.org/acm-icn/2018/proceedings/
|
||||
icn18-final62.pdf>.
|
||||
|
||||
[Wang2013]
|
||||
Wang, Y., Rozhnova, N., Narayanan, A., Oran, D., and I.
|
||||
Rhee, "An Improved Hop-by-hop Interest Shaper for
|
||||
Congestion Control in Named Data Networking, in ACM
|
||||
SIGCOMM Workshop on Information-Centric Networking",
|
||||
DOI 10.1145/2534169.2491233, 2013,
|
||||
<http://conferences.sigcomm.org/sigcomm/2013/papers/icn/
|
||||
p55.pdf>.
|
||||
|
||||
|
||||
|
||||
|
||||
D. Oran Expires January 2, 2020 [Page 13]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance July 2019
|
||||
|
||||
|
||||
Author's Address
|
||||
|
||||
Dave Oran
|
||||
Network Systems Research and Design
|
||||
4 Shady Hill Square
|
||||
Cambridge, MA 02138
|
||||
USA
|
||||
|
||||
Email: daveoran@orandom.net
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
D. Oran Expires January 2, 2020 [Page 14]
|
||||
@@ -0,0 +1,783 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
|
||||
<head profile="http://www.w3.org/2006/03/hcard http://dublincore.org/documents/2008/08/04/dc-html/">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />
|
||||
|
||||
<title>Maintaining CCNx or NDN flow balance with highly variable data object sizes </title>
|
||||
|
||||
<style type="text/css" title="Xml2Rfc (sans serif)">
|
||||
/*<![CDATA[*/
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
/* info code from SantaKlauss at http://www.madaboutstyle.com/tooltip2.html */
|
||||
a.info {
|
||||
/* This is the key. */
|
||||
position: relative;
|
||||
z-index: 24;
|
||||
text-decoration: none;
|
||||
}
|
||||
a.info:hover {
|
||||
z-index: 25;
|
||||
color: #FFF; background-color: #900;
|
||||
}
|
||||
a.info span { display: none; }
|
||||
a.info:hover span.info {
|
||||
/* The span will display just on :hover state. */
|
||||
display: block;
|
||||
position: absolute;
|
||||
font-size: smaller;
|
||||
top: 2em; left: -5em; width: 15em;
|
||||
padding: 2px; border: 1px solid #333;
|
||||
color: #900; background-color: #EEE;
|
||||
text-align: left;
|
||||
}
|
||||
a.smpl {
|
||||
color: black;
|
||||
}
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
a:active {
|
||||
text-decoration: underline;
|
||||
}
|
||||
address {
|
||||
margin-top: 1em;
|
||||
margin-left: 2em;
|
||||
font-style: normal;
|
||||
}
|
||||
body {
|
||||
color: black;
|
||||
font-family: verdana, helvetica, arial, sans-serif;
|
||||
font-size: 10pt;
|
||||
max-width: 55em;
|
||||
|
||||
}
|
||||
cite {
|
||||
font-style: normal;
|
||||
}
|
||||
dd {
|
||||
margin-right: 2em;
|
||||
}
|
||||
dl {
|
||||
margin-left: 2em;
|
||||
}
|
||||
|
||||
ul.empty {
|
||||
list-style-type: none;
|
||||
}
|
||||
ul.empty li {
|
||||
margin-top: .5em;
|
||||
}
|
||||
dl p {
|
||||
margin-left: 0em;
|
||||
}
|
||||
dt {
|
||||
margin-top: .5em;
|
||||
}
|
||||
h1 {
|
||||
font-size: 14pt;
|
||||
line-height: 21pt;
|
||||
page-break-after: avoid;
|
||||
}
|
||||
h1.np {
|
||||
page-break-before: always;
|
||||
}
|
||||
h1 a {
|
||||
color: #333333;
|
||||
}
|
||||
h2 {
|
||||
font-size: 12pt;
|
||||
line-height: 15pt;
|
||||
page-break-after: avoid;
|
||||
}
|
||||
h3, h4, h5, h6 {
|
||||
font-size: 10pt;
|
||||
page-break-after: avoid;
|
||||
}
|
||||
h2 a, h3 a, h4 a, h5 a, h6 a {
|
||||
color: black;
|
||||
}
|
||||
img {
|
||||
margin-left: 3em;
|
||||
}
|
||||
li {
|
||||
margin-left: 2em;
|
||||
margin-right: 2em;
|
||||
}
|
||||
ol {
|
||||
margin-left: 2em;
|
||||
margin-right: 2em;
|
||||
}
|
||||
ol p {
|
||||
margin-left: 0em;
|
||||
}
|
||||
p {
|
||||
margin-left: 2em;
|
||||
margin-right: 2em;
|
||||
}
|
||||
pre {
|
||||
margin-left: 3em;
|
||||
background-color: lightyellow;
|
||||
padding: .25em;
|
||||
}
|
||||
pre.text2 {
|
||||
border-style: dotted;
|
||||
border-width: 1px;
|
||||
background-color: #f0f0f0;
|
||||
width: 69em;
|
||||
}
|
||||
pre.inline {
|
||||
background-color: white;
|
||||
padding: 0em;
|
||||
}
|
||||
pre.text {
|
||||
border-style: dotted;
|
||||
border-width: 1px;
|
||||
background-color: #f8f8f8;
|
||||
width: 69em;
|
||||
}
|
||||
pre.drawing {
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
background-color: #f8f8f8;
|
||||
padding: 2em;
|
||||
}
|
||||
table {
|
||||
margin-left: 2em;
|
||||
}
|
||||
table.tt {
|
||||
vertical-align: top;
|
||||
}
|
||||
table.full {
|
||||
border-style: outset;
|
||||
border-width: 1px;
|
||||
}
|
||||
table.headers {
|
||||
border-style: outset;
|
||||
border-width: 1px;
|
||||
}
|
||||
table.tt td {
|
||||
vertical-align: top;
|
||||
}
|
||||
table.full td {
|
||||
border-style: inset;
|
||||
border-width: 1px;
|
||||
}
|
||||
table.tt th {
|
||||
vertical-align: top;
|
||||
}
|
||||
table.full th {
|
||||
border-style: inset;
|
||||
border-width: 1px;
|
||||
}
|
||||
table.headers th {
|
||||
border-style: none none inset none;
|
||||
border-width: 1px;
|
||||
}
|
||||
table.left {
|
||||
margin-right: auto;
|
||||
}
|
||||
table.right {
|
||||
margin-left: auto;
|
||||
}
|
||||
table.center {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
caption {
|
||||
caption-side: bottom;
|
||||
font-weight: bold;
|
||||
font-size: 9pt;
|
||||
margin-top: .5em;
|
||||
}
|
||||
|
||||
table.header {
|
||||
border-spacing: 1px;
|
||||
width: 95%;
|
||||
font-size: 10pt;
|
||||
color: white;
|
||||
}
|
||||
td.top {
|
||||
vertical-align: top;
|
||||
}
|
||||
td.topnowrap {
|
||||
vertical-align: top;
|
||||
white-space: nowrap;
|
||||
}
|
||||
table.header td {
|
||||
background-color: gray;
|
||||
width: 50%;
|
||||
}
|
||||
table.header a {
|
||||
color: white;
|
||||
}
|
||||
td.reference {
|
||||
vertical-align: top;
|
||||
white-space: nowrap;
|
||||
padding-right: 1em;
|
||||
}
|
||||
thead {
|
||||
display:table-header-group;
|
||||
}
|
||||
ul.toc, ul.toc ul {
|
||||
list-style: none;
|
||||
margin-left: 1.5em;
|
||||
margin-right: 0em;
|
||||
padding-left: 0em;
|
||||
}
|
||||
ul.toc li {
|
||||
line-height: 150%;
|
||||
font-weight: bold;
|
||||
font-size: 10pt;
|
||||
margin-left: 0em;
|
||||
margin-right: 0em;
|
||||
}
|
||||
ul.toc li li {
|
||||
line-height: normal;
|
||||
font-weight: normal;
|
||||
font-size: 9pt;
|
||||
margin-left: 0em;
|
||||
margin-right: 0em;
|
||||
}
|
||||
li.excluded {
|
||||
font-size: 0pt;
|
||||
}
|
||||
ul p {
|
||||
margin-left: 0em;
|
||||
}
|
||||
|
||||
.comment {
|
||||
background-color: yellow;
|
||||
}
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
.error {
|
||||
color: red;
|
||||
font-style: italic;
|
||||
font-weight: bold;
|
||||
}
|
||||
.figure {
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
font-size: 9pt;
|
||||
}
|
||||
.filename {
|
||||
color: #333333;
|
||||
font-weight: bold;
|
||||
font-size: 12pt;
|
||||
line-height: 21pt;
|
||||
text-align: center;
|
||||
}
|
||||
.fn {
|
||||
font-weight: bold;
|
||||
}
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
.left {
|
||||
text-align: left;
|
||||
}
|
||||
.right {
|
||||
text-align: right;
|
||||
}
|
||||
.title {
|
||||
color: #990000;
|
||||
font-size: 18pt;
|
||||
line-height: 18pt;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
margin-top: 36pt;
|
||||
}
|
||||
.vcardline {
|
||||
display: block;
|
||||
}
|
||||
.warning {
|
||||
font-size: 14pt;
|
||||
background-color: yellow;
|
||||
}
|
||||
|
||||
|
||||
@media print {
|
||||
.noprint {
|
||||
display: none;
|
||||
}
|
||||
|
||||
a {
|
||||
color: black;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
table.header {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
td.header {
|
||||
width: 50%;
|
||||
color: black;
|
||||
background-color: white;
|
||||
vertical-align: top;
|
||||
font-size: 12pt;
|
||||
}
|
||||
|
||||
ul.toc a::after {
|
||||
content: leader('.') target-counter(attr(href), page);
|
||||
}
|
||||
|
||||
ul.ind li li a {
|
||||
content: target-counter(attr(href), page);
|
||||
}
|
||||
|
||||
.print2col {
|
||||
column-count: 2;
|
||||
-moz-column-count: 2;
|
||||
column-fill: auto;
|
||||
}
|
||||
}
|
||||
|
||||
@page {
|
||||
@top-left {
|
||||
content: "Internet-Draft";
|
||||
}
|
||||
@top-right {
|
||||
content: "December 2010";
|
||||
}
|
||||
@top-center {
|
||||
content: "Abbreviated Title";
|
||||
}
|
||||
@bottom-left {
|
||||
content: "Doe";
|
||||
}
|
||||
@bottom-center {
|
||||
content: "Expires June 2011";
|
||||
}
|
||||
@bottom-right {
|
||||
content: "[Page " counter(page) "]";
|
||||
}
|
||||
}
|
||||
|
||||
@page:first {
|
||||
@top-left {
|
||||
content: normal;
|
||||
}
|
||||
@top-right {
|
||||
content: normal;
|
||||
}
|
||||
@top-center {
|
||||
content: normal;
|
||||
}
|
||||
}
|
||||
/*]]>*/
|
||||
</style>
|
||||
|
||||
<link href="#rfc.toc" rel="Contents"/>
|
||||
<link href="#rfc.section.1" rel="Chapter" title="1 Introduction"/>
|
||||
<link href="#rfc.section.2" rel="Chapter" title="2 Requirements Language"/>
|
||||
<link href="#rfc.section.3" rel="Chapter" title="3 Method to enhance congestion control with signaled size information in Interest Messages"/>
|
||||
<link href="#rfc.section.3.1" rel="Chapter" title="3.1 How to predict the size of returning Data messages"/>
|
||||
<link href="#rfc.section.3.2" rel="Chapter" title="3.2 Handling `too big' cases"/>
|
||||
<link href="#rfc.section.3.3" rel="Chapter" title="3.3 Handling `too small' cases"/>
|
||||
<link href="#rfc.section.3.4" rel="Chapter" title="3.4 Interactions with Interest Aggregation"/>
|
||||
<link href="#rfc.section.3.5" rel="Chapter" title="3.5 Operation when some Interests lack the expected data size option and some have it"/>
|
||||
<link href="#rfc.section.4" rel="Chapter" title="4 Dealing with malicious actors"/>
|
||||
<link href="#rfc.section.5" rel="Chapter" title="5 Mapping to CCNx and NDN packet encodings"/>
|
||||
<link href="#rfc.section.5.1" rel="Chapter" title="5.1 Packet encoding for CCNx"/>
|
||||
<link href="#rfc.section.5.2" rel="Chapter" title="5.2 Packet encoding for NDN"/>
|
||||
<link href="#rfc.section.6" rel="Chapter" title="6 IANA Considerations"/>
|
||||
<link href="#rfc.section.7" rel="Chapter" title="7 Security Considerations"/>
|
||||
<link href="#rfc.references" rel="Chapter" title="8 References"/>
|
||||
<link href="#rfc.references.1" rel="Chapter" title="8.1 Normative References"/>
|
||||
<link href="#rfc.references.2" rel="Chapter" title="8.2 Informative References"/>
|
||||
<link href="#rfc.authors" rel="Chapter"/>
|
||||
|
||||
|
||||
<meta name="generator" content="xml2rfc version 2.5.2 - http://tools.ietf.org/tools/xml2rfc" />
|
||||
<link rel="schema.dct" href="http://purl.org/dc/terms/" />
|
||||
|
||||
<meta name="dct.creator" content="D. Oran, " />
|
||||
<meta name="dct.identifier" content="urn:ietf:id:draft-oran-icnrg-flowbalance-01" />
|
||||
<meta name="dct.issued" scheme="ISO8601" content="2019-8-10" />
|
||||
<meta name="dct.abstract" content="Deeply embedded in some ICN architectures, especially Named Data Networking (NDN) and Content-Centric Networking (CCNx) is the notion of flow balance. This captures the idea that there is a one-to-one correspondence between requests for data, carried in Interest messages, and the responses with the requested data object, carried in Data messages. This has a number of highly beneficial properties for flow and congestion control in networks, as well as some desirable security properties. For example, neither legitimate users nor attackers are able to inject large amounts of un-requested data into the network." />
|
||||
<meta name="description" content="Deeply embedded in some ICN architectures, especially Named Data Networking (NDN) and Content-Centric Networking (CCNx) is the notion of flow balance. This captures the idea that there is a one-to-one correspondence between requests for data, carried in Interest messages, and the responses with the requested data object, carried in Data messages. This has a number of highly beneficial properties for flow and congestion control in networks, as well as some desirable security properties. For example, neither legitimate users nor attackers are able to inject large amounts of un-requested data into the network." />
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<table class="header">
|
||||
<tbody>
|
||||
|
||||
<tr>
|
||||
<td class="left">ICNRG</td>
|
||||
<td class="right">D. Oran</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="left">Internet-Draft</td>
|
||||
<td class="right">Network Systems Research and Design</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="left">Intended status: Experimental</td>
|
||||
<td class="right">August 10, 2019</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="left">Expires: February 11, 2020</td>
|
||||
<td class="right"></td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p class="title">Maintaining CCNx or NDN flow balance with highly variable data object sizes <br />
|
||||
<span class="filename">draft-oran-icnrg-flowbalance-01</span></p>
|
||||
|
||||
<h1 id="rfc.abstract">
|
||||
<a href="#rfc.abstract">Abstract</a>
|
||||
</h1>
|
||||
<p>Deeply embedded in some ICN architectures, especially Named Data Networking (NDN) and Content-Centric Networking (CCNx) is the notion of flow balance. This captures the idea that there is a one-to-one correspondence between requests for data, carried in Interest messages, and the responses with the requested data object, carried in Data messages. This has a number of highly beneficial properties for flow and congestion control in networks, as well as some desirable security properties. For example, neither legitimate users nor attackers are able to inject large amounts of un-requested data into the network.</p>
|
||||
<p>Existing congestion control approaches however cannot deal effectively with a widely varying MTU of ICN data messages, since the protocols allow a dynamic range of 1-64K bytes. Since Interest messages are used to allocate the reverse link bandwidth for returning Data, there is large uncertainty in how to allocate that bandwidth. Unfortunately, current congestion control schemes in CCNx and NDN only count Interest messages and have no idea how much data is involved that could congest the inverse link. This document proposes a method to maintain flow balance by accommodating the wide dynamic range in Data message MTU.</p>
|
||||
<h1 id="rfc.status">
|
||||
<a href="#rfc.status">Status of This Memo</a>
|
||||
</h1>
|
||||
<p>This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.</p>
|
||||
<p>Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at http://datatracker.ietf.org/drafts/current/.</p>
|
||||
<p>Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."</p>
|
||||
<p>This Internet-Draft will expire on February 11, 2020.</p>
|
||||
<h1 id="rfc.copyrightnotice">
|
||||
<a href="#rfc.copyrightnotice">Copyright Notice</a>
|
||||
</h1>
|
||||
<p>Copyright (c) 2019 IETF Trust and the persons identified as the document authors. All rights reserved.</p>
|
||||
<p>This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (http://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Simplified BSD License.</p>
|
||||
|
||||
|
||||
<hr class="noprint" />
|
||||
<h1 class="np" id="rfc.toc"><a href="#rfc.toc">Table of Contents</a></h1>
|
||||
<ul class="toc">
|
||||
|
||||
<li>1. <a href="#rfc.section.1">Introduction</a></li>
|
||||
<li>2. <a href="#rfc.section.2">Requirements Language</a></li>
|
||||
<li>3. <a href="#rfc.section.3">Method to enhance congestion control with signaled size information in Interest Messages</a></li>
|
||||
<ul><li>3.1. <a href="#rfc.section.3.1">How to predict the size of returning Data messages</a></li>
|
||||
<li>3.2. <a href="#rfc.section.3.2">Handling `too big' cases</a></li>
|
||||
<li>3.3. <a href="#rfc.section.3.3">Handling `too small' cases</a></li>
|
||||
<li>3.4. <a href="#rfc.section.3.4">Interactions with Interest Aggregation</a></li>
|
||||
<li>3.5. <a href="#rfc.section.3.5">Operation when some Interests lack the expected data size option and some have it</a></li>
|
||||
</ul><li>4. <a href="#rfc.section.4">Dealing with malicious actors</a></li>
|
||||
<li>5. <a href="#rfc.section.5">Mapping to CCNx and NDN packet encodings</a></li>
|
||||
<ul><li>5.1. <a href="#rfc.section.5.1">Packet encoding for CCNx</a></li>
|
||||
<li>5.2. <a href="#rfc.section.5.2">Packet encoding for NDN</a></li>
|
||||
</ul><li>6. <a href="#rfc.section.6">IANA Considerations</a></li>
|
||||
<li>7. <a href="#rfc.section.7">Security Considerations</a></li>
|
||||
<li>8. <a href="#rfc.references">References</a></li>
|
||||
<ul><li>8.1. <a href="#rfc.references.1">Normative References</a></li>
|
||||
<li>8.2. <a href="#rfc.references.2">Informative References</a></li>
|
||||
</ul><li><a href="#rfc.authors">Author's Address</a></li>
|
||||
|
||||
|
||||
</ul>
|
||||
|
||||
<h1 id="rfc.section.1"><a href="#rfc.section.1">1.</a> <a href="#intro" id="intro">Introduction</a></h1>
|
||||
<p id="rfc.section.1.p.1">Deeply embedded in some ICN architectures, especially Named Data Networking (NDN <a href="#NDN">[NDN]</a>) and Content-Centric Networking (CCNx <a href="#RFC8569">[RFC8569]</a>,<a href="#RFC8609">[RFC8609]</a>) is the notion of <em>flow balance</em>. This captures the idea that there is a one-to-one correspondence between requests for data, carried in Interest messages, and the responses with the requested data object, carried in Data messages. This has a number of highly beneficial properties for flow and congestion control in networks, as well as some desirable security properties. For example, neither legitimate users nor attackers are able to inject large amounts of un-requested data into the network.</p>
|
||||
<p id="rfc.section.1.p.2">This approach leads to a desire to make the size of the objects carried in Data messages small and near constant, because flow balance can then be kept using simple bookkeeping of how many Interest messages are outstanding. While simple, constraining Data messages to be quite small - usually on the order of a link Maximum Transmission Unit (MTU) - has some constraints and deleterious effects, among which are: </p>
|
||||
|
||||
<ul>
|
||||
<li>Such small data objects are inconvenient for many applications; their natural data object sizes can be considerably larger than a link MTU.</li>
|
||||
<li>Applications with truly small data objects (e.g. voice packets in an Internet telephony applications) have no way to communicate that to the network, causing resources to still be allocated for MTU-sized data objects</li>
|
||||
<li>When chunking a larger data object into multiple Data messages, each message has to be individually cryptographically hashed and signed, increasing both computational overhead and overall message header size. The signature can be elided when Manifests are used (by signing the Manifest instead), but the overhead of hashing multiple small messages rather than fewer larger ones remains.</li>
|
||||
</ul>
|
||||
|
||||
<p> </p>
|
||||
<p id="rfc.section.1.p.3">One approach which helps with the last of these is to employ fragmentation for Data messages larger than the Path MTU (PMTU). such messages are carved into smaller pieces for transmission over the link(s). There are three flavors of fragmentation: end-to-end, hop-by-hop with reassembly at every hop, and hop-by-hop with cut-through of individual fragments. A number of ICN protocol architectures incorporate fragmentation and schemes have been proposed for both NDN and CCNx, for example in <a href="#Ghali2013">[Ghali2013]</a>. Fragmentation alone does not ameliorate the flow balance problem however, since from a resource allocation standpoint both memory and link bandwidth must be set aside for maximum-sized data objects to avoid congestion collapse under overload.</p>
|
||||
<p id="rfc.section.1.p.4">The design space considered in this document does not however extend to arbitrarily large objects (e.g. 100's of kilobytes or larger). As the dynamic range of data object sizes gets very large, finding the right tradeoff between handling a large number of small data objects versus a single very large data object when allocating link and buffer resources becomes intractable. Further, the semantics of Interest-Data exchanges means that any error in the exchange results in a re-issue of an Interest for the entire Data object. Very large data objects represent a performance problem because the cost of retransmission when Interests are retransmitted (or re-issued) becomes unsustainably high. Therefore, the method we propose deals with a dynamic range of object sizes from very small (a fraction of a link MTU) to moderately large - about 64 kilobytes or equivalently about 40 Ethernet packets, and assumes an associated fragmentation scheme to handle link MTUs that cannot carry the object in a single link-layer packet.</p>
|
||||
<p id="rfc.section.1.p.5">The approach described in the rest of this document maintains flow balance under the conditions outlined above by allocating resources accurately based on expected data object size, rather than employing simple interest counting.</p>
|
||||
<h1 id="rfc.section.2"><a href="#rfc.section.2">2.</a> Requirements Language</h1>
|
||||
<p id="rfc.section.2.p.1">The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in <a href="#RFC2119">RFC 2119</a> <cite title="NONE">[RFC2119]</cite>.</p>
|
||||
<h1 id="rfc.section.3"><a href="#rfc.section.3">3.</a> <a href="#description" id="description">Method to enhance congestion control with signaled size information in Interest Messages</a></h1>
|
||||
<p id="rfc.section.3.p.1">Before diving into the specifics of the design, it is useful to consider how congestion control works in NDN/CCNx. Unlike the IP protocol family, which relies on end-to-end congestion control (e.g. TCP<a href="#RFC0793">[RFC0793]</a>, DCCP<a href="#RFC4340">[RFC4340]</a>, SCTP<a href="#RFC4960">[RFC4960]</a>, QUIC<a href="#I-D.ietf-quic-transport">[I-D.ietf-quic-transport]</a>), CCNx and NDN employ hop-by-hop congestion control. There is per-Interest/Data state at every hop of the path and therefore for each outstanding Interest, bandwidth for data returning on the inverse path can be allocated. In the current design, this allocation is done using simple Interest counting - by accepting one Interest packet from an downstream node, implicitly this provides a guarantee (either hard or soft) that there is sufficient bandwidth on the inverse direction of the link to send back one Data packet. A number of congestion control schemes have been developed that operate in this fashion, for example <a href="#Wang2013">[Wang2013]</a>,<a href="#Mahdian2016">[Mahdian2016]</a>,<a href="#Song2018">[Song2018]</a>,<a href="#Carofiglio2012">[Carofiglio2012]</a>. Other schemes, like <a href="#Schneider2016">[Schneider2016]</a> neither count nor police interests, but instead monitor queues using AQM (active queue management) to mark returning Data packets that have experienced congestion. It is worth noting that every congestion control algorithm has an explicit fairness goal and associated objective function (usually either <a href="#minmaxfairness">[minmaxfairness]</a> or <a href="#proportionalfairness">[proportionalfairness]</a>). If your fairness is to be based on resource usage, pure interest counting doesn't do the trick, since a consumer asking for large thing can saturate a link and shift loss to consumers asking for small things.</p>
|
||||
<p id="rfc.section.3.p.2">In order to deal with a larger dynamic range of data object size, some means is required to allocate link bandwidth for data messages in bytes with an upper bound larger than a link PMTU and a lower bound lower than a single link MTU. Since resources are allocated for returning Data based on arriving Interests, this information must be available in Interest messages.</p>
|
||||
<p id="rfc.section.3.p.3">Therefore, one key idea is the inclusion of an <em>expected data size</em> TLV in each Interest message. This allows each forwarder on the path taken by the interest to accurately allocate bandwidth on the inverse path for the returning Data message. Also, by including the expected data size, large objects will have a corresponding weight in resource allocation, maintaining link and forwarder buffering fairness. The simpler Interest counting scheme was nominally "fair" on a per-exchange basis within the variations of data that fit in a single PMTU packet because all Interests produced similar amounts of data in return. In the absence of such a field, it is not feasible to allow a large dynamic range in object size. While schemes like <a href="#Schneider2016">[Schneider2016]</a> would not employ the expected data size to allocate reverse link bandwidth, they can still benefit from the information to affect the AQM congestion marking algorithm, preferentially marking data packets that exceed the expected data size.</p>
|
||||
<h1 id="rfc.section.3.1"><a href="#rfc.section.3.1">3.1.</a> <a href="#prediction" id="prediction">How to predict the size of returning Data messages</a></h1>
|
||||
<p id="rfc.section.3.1.p.1">This of course raises the question "How does the requester know how big the corresponding data coming back will be?". For a number of important applications, the size is known a priori due to the characteristics of the application. Here are some examples: </p>
|
||||
|
||||
<ul>
|
||||
<li>For many sensor and other Internet-of-Things applications, the data is instrument readings which have fixed known size.</li>
|
||||
<li>In video streaming, the data is output of a video encoder which produces variable sized frames. This information is typically made available ahead of time to the streaming clients in the form of a Manifest [4], which contains the names of the corresponding segments (or individual frames) of video and audio and their sizes.</li>
|
||||
<li>Internet telephony applications use vocoders that typically employ fixed-size audio frames. Therefore, their size is known either a priori, or via an initialization exchange at the start of an audio session.</li>
|
||||
</ul>
|
||||
|
||||
<p> The more complex cases arise where the data size is not known at the time the Interest must be sent. Much of the nuance of the proposed scheme is in how mismatches between the expected data size and the actual data object returned are handled. The consumer can either under- or over-estimate the data size. In the former case, the under-estimate can lead to congestion and possible loss of data. In the latter case, bandwidth that could have been used by data objects requested by other consumers might be wasted. We first consider "honest" mis-estimates due to imperfect knowledge by the ICN application; later we consider malicious applications that are using the machinery to mount some form of attack. We also consider the effects of Interest aggregation if the aggregated Interests have differing expected data sizes. Also, it should be obvious that if the Data message arrives, the application learns its actual size, which may or may not be useful in adjusting the expected data size estimate for future Interests.</p>
|
||||
<p id="rfc.section.3.1.p.2">In all cases, the expected data size from the Interest can be incorporated in the corresponding Pending Interest Table (PIT) entry of each CCNx/NDN forwarder on the path and hence when a (possibly fragmented) Data object comes back, its total size is known and can be compared to the expected size in the PIT for a mismatch. Aside: In the case of fragmentation, we assume a fragmentation scheme in which the total data size can be known as soon as any one fragment is received (a reasonable assumption for most any well-designed fragmentation method).</p>
|
||||
<h1 id="rfc.section.3.2"><a href="#rfc.section.3.2">3.2.</a> <a href="#toobig" id="toobig">Handling `too big' cases</a></h1>
|
||||
<p id="rfc.section.3.2.p.1">If the returning data is larger than the expected data size, the extra data could result in either unfair bandwidth allocation or possibly data loss under congestion conditions. When this is detected, the forwarder has three choices: </p>
|
||||
|
||||
<ol>
|
||||
<li>It could forward the data anyway, which is safe under non-congestion conditions, but unfair and possibly unstable when the output link is congested</li>
|
||||
<li>It could forward the data when un-congested (e.g. by assessing output queue depth) but drop it when congested</li>
|
||||
<li>It could always drop the data, as a way of "punishing" the requester for the mis-estimate.</li>
|
||||
</ol>
|
||||
|
||||
<p> Either of the latter two strategies is acceptable from a congestion control point of view. However, it is not a good idea to simply drop the Data message with no feedback to the issuer of the Interest because the application has no way to learn the actual data size and retry. Further, recovery would be delayed until the failing Interest timed out. Therefore, an additional element needed in protocol semantics is the incorporation of a "Data too big" error message (via an "interest Return" packet in CCNx).</p>
|
||||
<p id="rfc.section.3.2.p.2">Upon dropping data as above, the CCNx/NDN forwarder converts the normal Data message into an Interest Return message containing the with the T_MTU_TOO_LARGE error code and the actual size of the data object instead of the data object content. It propagates that back toward the client identically to how the original Data message would have been handled. Subsequent nodes upon receiving the T_MTU_TOO_LARGE error treat it as all other Interest Return errors. When the Interest Return eventually arrives back to the issuer of the Interest, the user can, they desire, reissue the Interest with the correct expected data size.</p>
|
||||
<p id="rfc.section.3.2.p.3">One detail to note is that an Interest Return carrying T_MTU_TOO_LARGE must be deterministically smaller than the expected data size in all cases. This is clearly the case for large data objects, but there is a corner case with small data objects. There has to be a minimum expected data size that a client can specify in their Interests, and that minimum cannot be smaller than the size of a T_MTU_TOO_LARGE Interest Return</p>
|
||||
<h1 id="rfc.section.3.3"><a href="#rfc.section.3.3">3.3.</a> <a href="#toosmall" id="toosmall">Handling `too small' cases</a></h1>
|
||||
<p id="rfc.section.3.3.p.1">Next we consider the case where the returning data is smaller than the expected data size. While this case does not result in congestion, it can cause resources to be inefficiently allocated because not all of the set-aside bandwidth for the returning data object gets used. The simplest and most straightforward way to deal with this case is to essentially ignore it. The motivation for not worrying about the smaller data mismatch is that in many situations that employ usage-based resource measurement (and possibly charging), it is trivial to just account for the usage according to the larger expected data size rather than actual returned data size. Properly adjusting congestion control parameters to somehow penalize users for over-estimating their resource usage requires fairly heavyweight machinery, which in most cases is not warranted. If desired, any of the following mechanisms could be considered: </p>
|
||||
|
||||
<ul>
|
||||
<li>Attempt to identify future Interests for the same object or closely related objects and allocate resources based on some retained state about the actual size of prior objects</li>
|
||||
<li>Police consumer behavior and decrease the expected data size in one or more future Interests to compensate</li>
|
||||
<li>For small objects, do more optimistic resource allocation on the links on the presumption that there will be some "slack" due to clients overestimating data object size.</li>
|
||||
</ul>
|
||||
|
||||
<p> One protocol detail of CCNx/NDN that needs to be dealt with is Interest Aggregation. This happens when multiple Interests arrive at a forwarder for the same Named object. These are aggregated such that one of them (i.e.the first to arrive and create PIT state) is forwarded, and the rest are dropped while marking the arrival face so the data can be sent back to the multiple requesting clients. Interest aggregation interacts with expected data size if Interests from different clients contain different values of the expected data size. As above, the simplest solution to this problem is to ignore it, as most error cases are benign. However, there is one problematic error case where one client provides an accurate expected data size, but another who issued the Interest first underestimates, causing both to receive a Data too big error. This introduces a denial of service vulnerability, which we discuss below together with the other malicious actor cases.</p>
|
||||
<h1 id="rfc.section.3.4"><a href="#rfc.section.3.4">3.4.</a> <a href="#aggregation" id="aggregation">Interactions with Interest Aggregation</a></h1>
|
||||
<p id="rfc.section.3.4.p.1">Interest Aggregation, while a powerful feature for maintaining flow balance when multiple consumers send Interests for the same Named object, introduces subtle complications. Whenever a second or subsequent Interest arrives at a forwarder with an active PIT entry it is possible that those Interests carry different parameters, for example hop limit, payload, etc. It is therefore necessary to specify the exact behavior of the forwarder for each of the parameters that might differ. In the case of the expected data size parameter defined here, the value is associated with the ingress face on which the Interest creating the PIT entry arrived, as opposed to being global to the PIT entry as a whole. There are two cases to consider: </p>
|
||||
|
||||
<ol>
|
||||
<li>The arriving interest carries an expected data size smaller than any of the values associated with the PIT entry.</li>
|
||||
<li>The arriving interest carries an expected data size larger than any of the values associated with the PIT entry.</li>
|
||||
</ol>
|
||||
|
||||
<p> </p>
|
||||
<p id="rfc.section.3.4.p.2">For Case (1) the Interest can be safely aggregated since the upstream links will have sufficient bandwidth allocated based on the larger expected data size (assuming the original Interest's expected data size was itself sufficiently large to accommodate the actual size of the returning Data. On the other hand, should the incoming face have bandwidth allocated based on the larger existing Interest's expected data size, or on the smaller value in the arriving interest? Here there are two possible approaches: </p>
|
||||
|
||||
<ol style="list-style-type: lower-alpha">
|
||||
<li>Allocate based on the data size already in the PIT. In this case the consumer sending the earlier Interest can cause over-allocation of link bandwidth for other incoming faces, but there will not be a T_MTU_TOO_LARGE error generated for that Interest</li>
|
||||
<li>Allocate based on the value in the arriving Interest. If the returning Data is in fact larger, generate a T_MTU_TOO_LARGE Interest Return on that ingress face, while successfully returning the Data message on any faces that do not exhibit a too small expected data size</li>
|
||||
</ol>
|
||||
|
||||
<p> It is RECOMMENDED that the second policy be followed. The reasons behind this recommendation are as follows: </p>
|
||||
|
||||
<ol>
|
||||
<li>The link can be congested quite quickly after the queuing decision is made, especially if the data has a long link-occupancy time, so this is a safer alternative.</li>
|
||||
<li>The cost of returning the error is only one link RTT, since the consumer (or downstream forwarder) can immediately re-issue the interest with the correct size and pick up the cached object from the upstream forwarder's Content Store.</li>
|
||||
<li>Being optimistic and returning the data interacts with the behavior of aggregate resource control and resource accounting, which in turn raises the messy issue of whether to "charge" the consumer for the actual bandwidth used or only for the requested bandwidth in the expected data.</li>
|
||||
<li>The rabbit hole goes deeper if you add differential QoS to the equation or consumers "playing games" and intentionally underestimating so their interests get satisfied when links aren't congested. This makes handling malicious actors (<a href="#malicious">Section 4</a>) more difficult.</li>
|
||||
</ol>
|
||||
|
||||
<p> </p>
|
||||
<p id="rfc.section.3.4.p.3">For Case (2) above, the Interest MUST be forwarded rather than aggregated to prevent a consumer from mounting a denial of service attack by sending intentionally too small expected data size (see <a href="#malicious">Section 4</a> for additional detail on this and other attacks). As above for Case (1) it is RECOMMENDED that policy (b) above be followed. </p>
|
||||
<h1 id="rfc.section.3.5"><a href="#rfc.section.3.5">3.5.</a> <a href="#compatibility" id="compatibility">Operation when some Interests lack the expected data size option and some have it</a></h1>
|
||||
<p id="rfc.section.3.5.p.1">Since the expected data size hop-by-hop option forwarders need to be prepared to handle an arbitrary mix of the two forms. There are two general things to address. </p>
|
||||
<p id="rfc.section.3.5.p.2">First, we assume that any forwarder supporting expected data size is running a more sophisticated congestion control algorithm that one employing simple interest counting. The link bandwidth resource allocation is therefore based directly, or indirectly, on the expected Data size in bytes. Therefore, the forwarder has to assign a value to use in the resource allocation for the reverse link. This specification does not mandate any particular approach or a default value to use. However, in the absence on other guidance, it makes sense to do one of two things: </p>
|
||||
|
||||
<ol>
|
||||
<li>Pick a default based on the link MTU of the face on which the Interest arrived and use that for all Interests lacking an expected data size. This is likely to be most compatible with simple interest counting which would rate limit all incoming interests equally</li>
|
||||
<li>Configure some values for given Name prefixes that have known sizes. This may be appropriate for dedicated forwarders supporting single use cases, such as: <ul><li>A forwarder handling IoT sensors sending very small Data packets</li><li>A forwarder handling real-time video with large average Data packets that exceed link MTU and are routinely fragmented</li><li>A forwarder doing voice trunking where the vocoders produce moderate sized packets, still much smaller than the link MTU</li></ul><p> </p></li>
|
||||
</ol>
|
||||
|
||||
<p> </p>
|
||||
<p id="rfc.section.3.5.p.3">The second area to address is what to do if an interest lacking an expected Data size is responded to by a Data message whose size exceeds the default discussed above. It would be inappropriate to issue a T_MTU_TOO_LARGE error, since the consumer is unlikely to understand or deal correctly with that new error case. Instead, it is RECOMMENDED that the forwarder: </p>
|
||||
|
||||
<ul>
|
||||
<li>Ignore the mismatch if the reverse link is not congested and return the requested Data message anyway.</li>
|
||||
<li>If the reverse link is congested, issue an Interest Return with the T_NO_RESOURCES error code</li>
|
||||
</ul>
|
||||
|
||||
<p> This specification does not define or recommend any particular algorithm for assessing the congestion state of the link(s) to carry the Data message downstream to the requesting consumers. It is assumed that a reasonable algorithm is in use, because otherwise even basic Interest counting forms of congestion control would not be effective. </p>
|
||||
<h1 id="rfc.section.4"><a href="#rfc.section.4">4.</a> <a href="#malicious" id="malicious">Dealing with malicious actors</a></h1>
|
||||
<p id="rfc.section.4.p.1">First we note that various known attacks in CCNx or NDN can also be mounted by users employing this method. Attacks that involve interest flooding, cache pollution, cache poisoning, etc. are neither worsened nor ameliorated by the introduction of the congestion control capabilities described here. However, there are two new vulnerabilities that need to be dealt with. These two new vulnerabilities involve intentional mis-estimation of data size.</p>
|
||||
<p id="rfc.section.4.p.2">The first is a consumer who intentionally over-estimates data size with the goal of preventing other users from using the bandwidth. This is at most a minor concern given the above discussion of over-estimation by honest clients. If one of the amelioration techniques above are used, the case of malicious over-estimation is also dealt with adequately.</p>
|
||||
<p id="rfc.section.4.p.3">The second is a user who intentionally under-estimates the data size with the goal having its Interest processed while the other aggregated interests are not processed, thereby causing T_MTU_TOO_LARGE errors and denying service to the other users with overlapping requests. There are a number of possible mitigation techniques for this attack vector, ranging in complexity. We outline two below; there may be others as or more effective with acceptable complexity and overhead: </p>
|
||||
|
||||
<ul>
|
||||
<li>(Simplest) A user sending Interests resulting in a T_MTU_TOO_LARGE error is treated similarly to users mounting interest flooding attacks; the a router aggregating Interests with differing expected data sizes rate limits the face(s) exhibiting these errors, thus decreasing the ability of a user to issue enough mis-estimated Interests to collide and generate Interest aggregation.</li>
|
||||
<li>An ICN forwarder aggregating Interests remembers in the PIT entry not only the expected data size of the Interest it forwarded, but the maximum of the expected data size of the other Interests it aggregated. If a T_MTU_TOO_LARGE error comes back, instead of propagating it, the forwarder MAY treat this as a transient error, drop the Interest Return, and re-forward the Interest using the maximum expected data size in the PIT (assuming it is is bigger). This recovers from the error, but the attacker can still cause an extra round trip to the producer or to an upstream forwarder with a copy of the data in its Content Store.</li>
|
||||
</ul>
|
||||
|
||||
<p> </p>
|
||||
<h1 id="rfc.section.5"><a href="#rfc.section.5">5.</a> <a href="#encoding" id="encoding">Mapping to CCNx and NDN packet encodings</a></h1>
|
||||
<p id="rfc.section.5.p.1">The only actual protocol needed is a TLV in Interest messages that states the size in bytes of the expected Data Message coming back, and in the Interest Return on a "too big" error to carry the actual data size. In the case of CCNx, this covers the encapsulated Data Object, but not the hop-by-hop headers.</p>
|
||||
<h1 id="rfc.section.5.1"><a href="#rfc.section.5.1">5.1.</a> <a href="#CCNx-encoding" id="CCNx-encoding">Packet encoding for CCNx</a></h1>
|
||||
<p id="rfc.section.5.1.p.1">For CCNx<a href="#RFC8569">[RFC8569]</a> there is a new hop-by-hop header TLV, and a new value of the Interest Return "Return Type".</p>
|
||||
<div id="rfc.table.1"/>
|
||||
<div id="DataSize"/>
|
||||
<p>Expected Data Size (for Interest messages), or Actual Data Size (for Interest Return messages) TLV</p>
|
||||
<table cellpadding="3" cellspacing="0" class="tt full center">
|
||||
<caption>Data Size TLV</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="center">Abbrev</th>
|
||||
<th class="center">Name</th>
|
||||
<th class="center">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="center">T_DATASIZE</td>
|
||||
<td class="center">Data Size</td>
|
||||
<td class="center">Expected (<a href="#description">Section 3</a>)or Actual (<a href="#toobig">Section 3.2</a>) Data Size</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h1 id="rfc.section.5.2"><a href="#rfc.section.5.2">5.2.</a> <a href="#NDN-encoding" id="NDN-encoding">Packet encoding for NDN</a></h1>
|
||||
<p id="rfc.section.5.2.p.1">TBD based on <a href="#NDNTLV">[NDNTLV]</a>. Suggestions from the NDN team greatly appreciated.</p>
|
||||
<h1 id="rfc.section.6"><a href="#rfc.section.6">6.</a> <a href="#IANA" id="IANA">IANA Considerations</a></h1>
|
||||
<p id="rfc.section.6.p.1">Please Add the T_DATASIZE TLV to the Hop-by-Hop TLV types registry, with fixed length of 2, and data type numeric</p>
|
||||
<div id="rfc.figure.1"/>
|
||||
<div id="dsize-encoding"/>
|
||||
<p>Expected/Actual Data Size TLV encoding. The range has an upper bound of 64K bytes, since that is the largest MTU supported by CCNx.</p>
|
||||
<pre>
|
||||
1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+---------------+---------------+---------------+---------------+
|
||||
| T_DATASIZE | 2 |
|
||||
+---------------+---------------+---------------+---------------+
|
||||
| Size in bytes (1-65535) |
|
||||
+---------------+---------------+
|
||||
</pre>
|
||||
<p class="figure">Figure 1: Expected/Actual Data Size Encoding</p>
|
||||
<h1 id="rfc.section.7"><a href="#rfc.section.7">7.</a> <a href="#Security" id="Security">Security Considerations</a></h1>
|
||||
<p id="rfc.section.7.p.1">Here we recapitulate the vulnerabilities, attack scenarios and mitigations.</p>
|
||||
<p id="rfc.section.7.p.2">The "too big" error that generates an Interest Return with T_MTU_TOO_LARGE leaks the actual data object size to any consumer who can issue an Interest with an intentionally small expected data size. This does not represent a privacy vulnerability, for two reasons: </p>
|
||||
|
||||
<ol>
|
||||
<li>The user could learn the actual data size just by looking at the returned Data message using a properly-constructed Interest.</li>
|
||||
<li>In many cases the actual data sizes are already available as meta-data in the corresponding Manifest pointing to the Data object.</li>
|
||||
</ol>
|
||||
|
||||
<p> </p>
|
||||
<h1 id="rfc.references"><a href="#rfc.references">8.</a> References</h1>
|
||||
<h1 id="rfc.references.1"><a href="#rfc.references.1">8.1.</a> Normative References</h1>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="RFC2119">[RFC2119]</b>
|
||||
</td>
|
||||
<td class="top"><a>Bradner, S.</a>, "<a href="http://tools.ietf.org/html/rfc2119">Key words for use in RFCs to Indicate Requirement Levels</a>", BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="RFC8569">[RFC8569]</b>
|
||||
</td>
|
||||
<td class="top"><a>Mosko, M.</a>, <a>Solis, I.</a> and <a>C. Wood</a>, "<a href="http://tools.ietf.org/html/rfc8569">Content-Centric Networking (CCNx) Semantics</a>", RFC 8569, DOI 10.17487/RFC8569, July 2019.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="RFC8609">[RFC8609]</b>
|
||||
</td>
|
||||
<td class="top"><a>Mosko, M.</a>, <a>Solis, I.</a> and <a>C. Wood</a>, "<a href="http://tools.ietf.org/html/rfc8609">Content-Centric Networking (CCNx) Messages in TLV Format</a>", RFC 8609, DOI 10.17487/RFC8609, July 2019.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h1 id="rfc.references.2"><a href="#rfc.references.2">8.2.</a> Informative References</h1>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="Carofiglio2012">[Carofiglio2012]</b>
|
||||
</td>
|
||||
<td class="top"><a>Carofiglio, G.</a>, <a>Gallo, M.</a> and <a>L. Muscariello</a>, "<a href="http://conferences.sigcomm.org/sigcomm/2012/paper/icn/p37.pdf">Joint hop-by-hop and receiver-driven interest control protocol for content-centric networks, in ICN Workshop at SIGcomm 2012</a>", DOI 10.1145/2377677.2377772, 2102.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="Ghali2013">[Ghali2013]</b>
|
||||
</td>
|
||||
<td class="top"><a>Ghali, C.</a>, <a>Narayanan, A.</a>, <a>Oran, D.</a>, <a>Tsudik, G.</a> and <a>C. Wood</a>, "<a href="http://dx.doi.org/10.1109/NCA.2015.34">Secure Fragmentation for Content-Centric Networks, in IEEE 14th International Symposium on Network Computing and Applications</a>", DOI 10.1109/nca.2015.34, 2015.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="I-D.ietf-quic-transport">[I-D.ietf-quic-transport]</b>
|
||||
</td>
|
||||
<td class="top"><a>Iyengar, J.</a> and <a>M. Thomson</a>, "<a href="http://tools.ietf.org/html/draft-ietf-quic-transport-22">QUIC: A UDP-Based Multiplexed and Secure Transport</a>", Internet-Draft draft-ietf-quic-transport-22, July 2019.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="Mahdian2016">[Mahdian2016]</b>
|
||||
</td>
|
||||
<td class="top"><a>Mahdian, M.</a>, <a>Arianfar, S.</a>, <a>Gibson, J.</a> and <a>D. Oran</a>, "<a href="http://conferences2.sigcomm.org/acm-icn/2016/proceedings/p1-mahdian.pdf">MIRCC: Multipath-aware ICN Rate-based Congestion Control, in Proceedings of the 3rd ACM Conference on Information-Centric Networking</a>", DOI 10.1145/2984356.2984365, 2016.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="minmaxfairness">[minmaxfairness]</b>
|
||||
</td>
|
||||
<td class="top"><a>Wikipedia, </a>, "<a href="https://en.wikipedia.org/wiki/Max-min_fairness">Max-min Fairness</a>", various.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="NDN">[NDN]</b>
|
||||
</td>
|
||||
<td class="top"><a>NDN team, </a>, "<a href="https://named-data.net/project/execsummary/">Named Data Networking</a>", various.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="NDNTLV">[NDNTLV]</b>
|
||||
</td>
|
||||
<td class="top"><a>NDN Project Team, </a>, "<a href="http://named-data.net/doc/ndn-tlv/">NDN Packet Format Specification.</a>", 2016.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="proportionalfairness">[proportionalfairness]</b>
|
||||
</td>
|
||||
<td class="top"><a>Wikipedia, </a>, "<a href="https://en.wikipedia.org/wiki/Proportionally_fair">Proportionally Fair</a>", various.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="RFC0793">[RFC0793]</b>
|
||||
</td>
|
||||
<td class="top"><a>Postel, J.</a>, "<a href="http://tools.ietf.org/html/rfc793">Transmission Control Protocol</a>", STD 7, RFC 793, DOI 10.17487/RFC0793, September 1981.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="RFC4340">[RFC4340]</b>
|
||||
</td>
|
||||
<td class="top"><a>Kohler, E.</a>, <a>Handley, M.</a> and <a>S. Floyd</a>, "<a href="http://tools.ietf.org/html/rfc4340">Datagram Congestion Control Protocol (DCCP)</a>", RFC 4340, DOI 10.17487/RFC4340, March 2006.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="RFC4960">[RFC4960]</b>
|
||||
</td>
|
||||
<td class="top"><a>Stewart, R.</a>, "<a href="http://tools.ietf.org/html/rfc4960">Stream Control Transmission Protocol</a>", RFC 4960, DOI 10.17487/RFC4960, September 2007.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="Schneider2016">[Schneider2016]</b>
|
||||
</td>
|
||||
<td class="top"><a>Schneider, K.</a>, <a>Yi, C.</a>, <a>Zhang, B.</a> and <a>L. Zhang</a>, "<a href="http://conferences2.sigcomm.org/acm-icn/2016/proceedings/p21-schneider.pdf">A Practical Congestion Control Scheme for Named Data Networking, in Proceedings of the 2016 conference on 3rd ACM Conference on Information-Centric Networking - ACM-ICN '16</a>", DOI 10.1145/2984356.2984369, 2016.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="Song2018">[Song2018]</b>
|
||||
</td>
|
||||
<td class="top"><a>Song, J.</a>, <a>Lee, M.</a> and <a>T. Kwon</a>, "<a href="https://conferences.sigcomm.org/acm-icn/2018/proceedings/icn18-final62.pdf">SMIC: Subflow-level Multi-path Interest Control for Information Centric Networking, in 5th ACM Conference on Information-Centric Networking</a>", DOI 10.1145/3267955.3267971, 2018.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="reference">
|
||||
<b id="Wang2013">[Wang2013]</b>
|
||||
</td>
|
||||
<td class="top"><a>Wang, Y.</a>, <a>Rozhnova, N.</a>, <a>Narayanan, A.</a>, <a>Oran, D.</a> and <a>I. Rhee</a>, "<a href="http://conferences.sigcomm.org/sigcomm/2013/papers/icn/p55.pdf">An Improved Hop-by-hop Interest Shaper for Congestion Control in Named Data Networking, in ACM SIGCOMM Workshop on Information-Centric Networking</a>", DOI 10.1145/2534169.2491233, 2013.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h1 id="rfc.authors">
|
||||
<a href="#rfc.authors">Author's Address</a>
|
||||
</h1>
|
||||
<div class="avoidbreak">
|
||||
<address class="vcard">
|
||||
<span class="vcardline">
|
||||
<span class="fn">Dave Oran</span>
|
||||
<span class="n hidden">
|
||||
<span class="family-name">D. Oran</span>
|
||||
</span>
|
||||
</span>
|
||||
<span class="org vcardline">Network Systems Research and Design</span>
|
||||
<span class="adr">
|
||||
<span class="vcardline">4 Shady Hill Square</span>
|
||||
|
||||
<span class="vcardline">
|
||||
<span class="locality">Cambridge</span>,
|
||||
<span class="region">MA</span>
|
||||
<span class="code">02138</span>
|
||||
</span>
|
||||
<span class="country-name vcardline">USA</span>
|
||||
</span>
|
||||
<span class="vcardline">EMail: <a href="mailto:daveoran@orandom.net">daveoran@orandom.net</a></span>
|
||||
|
||||
</address>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,840 @@
|
||||
|
||||
|
||||
|
||||
|
||||
ICNRG D. Oran
|
||||
Internet-Draft Network Systems Research and Design
|
||||
Intended status: Experimental August 10, 2019
|
||||
Expires: February 11, 2020
|
||||
|
||||
|
||||
Maintaining CCNx or NDN flow balance with highly variable data object
|
||||
sizes
|
||||
draft-oran-icnrg-flowbalance-01
|
||||
|
||||
Abstract
|
||||
|
||||
Deeply embedded in some ICN architectures, especially Named Data
|
||||
Networking (NDN) and Content-Centric Networking (CCNx) is the notion
|
||||
of flow balance. This captures the idea that there is a one-to-one
|
||||
correspondence between requests for data, carried in Interest
|
||||
messages, and the responses with the requested data object, carried
|
||||
in Data messages. This has a number of highly beneficial properties
|
||||
for flow and congestion control in networks, as well as some
|
||||
desirable security properties. For example, neither legitimate users
|
||||
nor attackers are able to inject large amounts of un-requested data
|
||||
into the network.
|
||||
|
||||
Existing congestion control approaches however cannot deal
|
||||
effectively with a widely varying MTU of ICN data messages, since the
|
||||
protocols allow a dynamic range of 1-64K bytes. Since Interest
|
||||
messages are used to allocate the reverse link bandwidth for
|
||||
returning Data, there is large uncertainty in how to allocate that
|
||||
bandwidth. Unfortunately, current congestion control schemes in CCNx
|
||||
and NDN only count Interest messages and have no idea how much data
|
||||
is involved that could congest the inverse link. This document
|
||||
proposes a method to maintain flow balance by accommodating the wide
|
||||
dynamic range in Data message MTU.
|
||||
|
||||
Status of This Memo
|
||||
|
||||
This Internet-Draft is submitted in full conformance with the
|
||||
provisions of BCP 78 and BCP 79.
|
||||
|
||||
Internet-Drafts are working documents of the Internet Engineering
|
||||
Task Force (IETF). Note that other groups may also distribute
|
||||
working documents as Internet-Drafts. The list of current Internet-
|
||||
Drafts is at http://datatracker.ietf.org/drafts/current/.
|
||||
|
||||
Internet-Drafts are draft documents valid for a maximum of six months
|
||||
and may be updated, replaced, or obsoleted by other documents at any
|
||||
time. It is inappropriate to use Internet-Drafts as reference
|
||||
material or to cite them other than as "work in progress."
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 11, 2020 [Page 1]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance August 2019
|
||||
|
||||
|
||||
This Internet-Draft will expire on February 11, 2020.
|
||||
|
||||
Copyright Notice
|
||||
|
||||
Copyright (c) 2019 IETF Trust and the persons identified as the
|
||||
document authors. All rights reserved.
|
||||
|
||||
This document is subject to BCP 78 and the IETF Trust's Legal
|
||||
Provisions Relating to IETF Documents
|
||||
(http://trustee.ietf.org/license-info) in effect on the date of
|
||||
publication of this document. Please review these documents
|
||||
carefully, as they describe your rights and restrictions with respect
|
||||
to this document. Code Components extracted from this document must
|
||||
include Simplified BSD License text as described in Section 4.e of
|
||||
the Trust Legal Provisions and are provided without warranty as
|
||||
described in the Simplified BSD License.
|
||||
|
||||
Table of Contents
|
||||
|
||||
1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 2
|
||||
2. Requirements Language . . . . . . . . . . . . . . . . . . . . 4
|
||||
3. Method to enhance congestion control with signaled size
|
||||
information in Interest Messages . . . . . . . . . . . . . . 4
|
||||
3.1. How to predict the size of returning Data messages . . . 5
|
||||
3.2. Handling `too big' cases . . . . . . . . . . . . . . . . 6
|
||||
3.3. Handling `too small' cases . . . . . . . . . . . . . . . 7
|
||||
3.4. Interactions with Interest Aggregation . . . . . . . . . 8
|
||||
3.5. Operation when some Interests lack the expected data size
|
||||
option and some have it . . . . . . . . . . . . . . . . . 10
|
||||
4. Dealing with malicious actors . . . . . . . . . . . . . . . . 11
|
||||
5. Mapping to CCNx and NDN packet encodings . . . . . . . . . . 12
|
||||
5.1. Packet encoding for CCNx . . . . . . . . . . . . . . . . 12
|
||||
5.2. Packet encoding for NDN . . . . . . . . . . . . . . . . . 12
|
||||
6. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 12
|
||||
7. Security Considerations . . . . . . . . . . . . . . . . . . . 13
|
||||
8. References . . . . . . . . . . . . . . . . . . . . . . . . . 13
|
||||
8.1. Normative References . . . . . . . . . . . . . . . . . . 13
|
||||
8.2. Informative References . . . . . . . . . . . . . . . . . 14
|
||||
Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 15
|
||||
|
||||
1. Introduction
|
||||
|
||||
Deeply embedded in some ICN architectures, especially Named Data
|
||||
Networking (NDN [NDN]) and Content-Centric Networking (CCNx
|
||||
[RFC8569],[RFC8609]) is the notion of _flow balance_. This captures
|
||||
the idea that there is a one-to-one correspondence between requests
|
||||
for data, carried in Interest messages, and the responses with the
|
||||
requested data object, carried in Data messages. This has a number
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 11, 2020 [Page 2]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance August 2019
|
||||
|
||||
|
||||
of highly beneficial properties for flow and congestion control in
|
||||
networks, as well as some desirable security properties. For
|
||||
example, neither legitimate users nor attackers are able to inject
|
||||
large amounts of un-requested data into the network.
|
||||
|
||||
This approach leads to a desire to make the size of the objects
|
||||
carried in Data messages small and near constant, because flow
|
||||
balance can then be kept using simple bookkeeping of how many
|
||||
Interest messages are outstanding. While simple, constraining Data
|
||||
messages to be quite small - usually on the order of a link Maximum
|
||||
Transmission Unit (MTU) - has some constraints and deleterious
|
||||
effects, among which are:
|
||||
|
||||
o Such small data objects are inconvenient for many applications;
|
||||
their natural data object sizes can be considerably larger than a
|
||||
link MTU.
|
||||
|
||||
o Applications with truly small data objects (e.g. voice packets in
|
||||
an Internet telephony applications) have no way to communicate
|
||||
that to the network, causing resources to still be allocated for
|
||||
MTU-sized data objects
|
||||
|
||||
o When chunking a larger data object into multiple Data messages,
|
||||
each message has to be individually cryptographically hashed and
|
||||
signed, increasing both computational overhead and overall message
|
||||
header size. The signature can be elided when Manifests are used
|
||||
(by signing the Manifest instead), but the overhead of hashing
|
||||
multiple small messages rather than fewer larger ones remains.
|
||||
|
||||
One approach which helps with the last of these is to employ
|
||||
fragmentation for Data messages larger than the Path MTU (PMTU). such
|
||||
messages are carved into smaller pieces for transmission over the
|
||||
link(s). There are three flavors of fragmentation: end-to-end, hop-
|
||||
by-hop with reassembly at every hop, and hop-by-hop with cut-through
|
||||
of individual fragments. A number of ICN protocol architectures
|
||||
incorporate fragmentation and schemes have been proposed for both NDN
|
||||
and CCNx, for example in [Ghali2013]. Fragmentation alone does not
|
||||
ameliorate the flow balance problem however, since from a resource
|
||||
allocation standpoint both memory and link bandwidth must be set
|
||||
aside for maximum-sized data objects to avoid congestion collapse
|
||||
under overload.
|
||||
|
||||
The design space considered in this document does not however extend
|
||||
to arbitrarily large objects (e.g. 100's of kilobytes or larger). As
|
||||
the dynamic range of data object sizes gets very large, finding the
|
||||
right tradeoff between handling a large number of small data objects
|
||||
versus a single very large data object when allocating link and
|
||||
buffer resources becomes intractable. Further, the semantics of
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 11, 2020 [Page 3]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance August 2019
|
||||
|
||||
|
||||
Interest-Data exchanges means that any error in the exchange results
|
||||
in a re-issue of an Interest for the entire Data object. Very large
|
||||
data objects represent a performance problem because the cost of
|
||||
retransmission when Interests are retransmitted (or re-issued)
|
||||
becomes unsustainably high. Therefore, the method we propose deals
|
||||
with a dynamic range of object sizes from very small (a fraction of a
|
||||
link MTU) to moderately large - about 64 kilobytes or equivalently
|
||||
about 40 Ethernet packets, and assumes an associated fragmentation
|
||||
scheme to handle link MTUs that cannot carry the object in a single
|
||||
link-layer packet.
|
||||
|
||||
The approach described in the rest of this document maintains flow
|
||||
balance under the conditions outlined above by allocating resources
|
||||
accurately based on expected data object size, rather than employing
|
||||
simple interest counting.
|
||||
|
||||
2. Requirements Language
|
||||
|
||||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
|
||||
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
|
||||
document are to be interpreted as described in RFC 2119 [RFC2119].
|
||||
|
||||
3. Method to enhance congestion control with signaled size information
|
||||
in Interest Messages
|
||||
|
||||
Before diving into the specifics of the design, it is useful to
|
||||
consider how congestion control works in NDN/CCNx. Unlike the IP
|
||||
protocol family, which relies on end-to-end congestion control (e.g.
|
||||
TCP[RFC0793], DCCP[RFC4340], SCTP[RFC4960],
|
||||
QUIC[I-D.ietf-quic-transport]), CCNx and NDN employ hop-by-hop
|
||||
congestion control. There is per-Interest/Data state at every hop of
|
||||
the path and therefore for each outstanding Interest, bandwidth for
|
||||
data returning on the inverse path can be allocated. In the current
|
||||
design, this allocation is done using simple Interest counting - by
|
||||
accepting one Interest packet from an downstream node, implicitly
|
||||
this provides a guarantee (either hard or soft) that there is
|
||||
sufficient bandwidth on the inverse direction of the link to send
|
||||
back one Data packet. A number of congestion control schemes have
|
||||
been developed that operate in this fashion, for example
|
||||
[Wang2013],[Mahdian2016],[Song2018],[Carofiglio2012]. Other schemes,
|
||||
like [Schneider2016] neither count nor police interests, but instead
|
||||
monitor queues using AQM (active queue management) to mark returning
|
||||
Data packets that have experienced congestion. It is worth noting
|
||||
that every congestion control algorithm has an explicit fairness goal
|
||||
and associated objective function (usually either [minmaxfairness] or
|
||||
[proportionalfairness]). If your fairness is to be based on resource
|
||||
usage, pure interest counting doesn't do the trick, since a consumer
|
||||
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 11, 2020 [Page 4]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance August 2019
|
||||
|
||||
|
||||
asking for large thing can saturate a link and shift loss to
|
||||
consumers asking for small things.
|
||||
|
||||
In order to deal with a larger dynamic range of data object size,
|
||||
some means is required to allocate link bandwidth for data messages
|
||||
in bytes with an upper bound larger than a link PMTU and a lower
|
||||
bound lower than a single link MTU. Since resources are allocated
|
||||
for returning Data based on arriving Interests, this information must
|
||||
be available in Interest messages.
|
||||
|
||||
Therefore, one key idea is the inclusion of an _expected data size_
|
||||
TLV in each Interest message. This allows each forwarder on the path
|
||||
taken by the interest to accurately allocate bandwidth on the inverse
|
||||
path for the returning Data message. Also, by including the expected
|
||||
data size, large objects will have a corresponding weight in resource
|
||||
allocation, maintaining link and forwarder buffering fairness. The
|
||||
simpler Interest counting scheme was nominally "fair" on a per-
|
||||
exchange basis within the variations of data that fit in a single
|
||||
PMTU packet because all Interests produced similar amounts of data in
|
||||
return. In the absence of such a field, it is not feasible to allow
|
||||
a large dynamic range in object size. While schemes like
|
||||
[Schneider2016] would not employ the expected data size to allocate
|
||||
reverse link bandwidth, they can still benefit from the information
|
||||
to affect the AQM congestion marking algorithm, preferentially
|
||||
marking data packets that exceed the expected data size.
|
||||
|
||||
3.1. How to predict the size of returning Data messages
|
||||
|
||||
This of course raises the question "How does the requester know how
|
||||
big the corresponding data coming back will be?". For a number of
|
||||
important applications, the size is known a priori due to the
|
||||
characteristics of the application. Here are some examples:
|
||||
|
||||
o For many sensor and other Internet-of-Things applications, the
|
||||
data is instrument readings which have fixed known size.
|
||||
|
||||
o In video streaming, the data is output of a video encoder which
|
||||
produces variable sized frames. This information is typically
|
||||
made available ahead of time to the streaming clients in the form
|
||||
of a Manifest [4], which contains the names of the corresponding
|
||||
segments (or individual frames) of video and audio and their
|
||||
sizes.
|
||||
|
||||
o Internet telephony applications use vocoders that typically employ
|
||||
fixed-size audio frames. Therefore, their size is known either a
|
||||
priori, or via an initialization exchange at the start of an audio
|
||||
session.
|
||||
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 11, 2020 [Page 5]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance August 2019
|
||||
|
||||
|
||||
The more complex cases arise where the data size is not known at the
|
||||
time the Interest must be sent. Much of the nuance of the proposed
|
||||
scheme is in how mismatches between the expected data size and the
|
||||
actual data object returned are handled. The consumer can either
|
||||
under- or over-estimate the data size. In the former case, the
|
||||
under-estimate can lead to congestion and possible loss of data. In
|
||||
the latter case, bandwidth that could have been used by data objects
|
||||
requested by other consumers might be wasted. We first consider
|
||||
"honest" mis-estimates due to imperfect knowledge by the ICN
|
||||
application; later we consider malicious applications that are using
|
||||
the machinery to mount some form of attack. We also consider the
|
||||
effects of Interest aggregation if the aggregated Interests have
|
||||
differing expected data sizes. Also, it should be obvious that if
|
||||
the Data message arrives, the application learns its actual size,
|
||||
which may or may not be useful in adjusting the expected data size
|
||||
estimate for future Interests.
|
||||
|
||||
In all cases, the expected data size from the Interest can be
|
||||
incorporated in the corresponding Pending Interest Table (PIT) entry
|
||||
of each CCNx/NDN forwarder on the path and hence when a (possibly
|
||||
fragmented) Data object comes back, its total size is known and can
|
||||
be compared to the expected size in the PIT for a mismatch. Aside:
|
||||
In the case of fragmentation, we assume a fragmentation scheme in
|
||||
which the total data size can be known as soon as any one fragment is
|
||||
received (a reasonable assumption for most any well-designed
|
||||
fragmentation method).
|
||||
|
||||
3.2. Handling `too big' cases
|
||||
|
||||
If the returning data is larger than the expected data size, the
|
||||
extra data could result in either unfair bandwidth allocation or
|
||||
possibly data loss under congestion conditions. When this is
|
||||
detected, the forwarder has three choices:
|
||||
|
||||
1. It could forward the data anyway, which is safe under non-
|
||||
congestion conditions, but unfair and possibly unstable when the
|
||||
output link is congested
|
||||
|
||||
2. It could forward the data when un-congested (e.g. by assessing
|
||||
output queue depth) but drop it when congested
|
||||
|
||||
3. It could always drop the data, as a way of "punishing" the
|
||||
requester for the mis-estimate.
|
||||
|
||||
Either of the latter two strategies is acceptable from a congestion
|
||||
control point of view. However, it is not a good idea to simply drop
|
||||
the Data message with no feedback to the issuer of the Interest
|
||||
because the application has no way to learn the actual data size and
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 11, 2020 [Page 6]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance August 2019
|
||||
|
||||
|
||||
retry. Further, recovery would be delayed until the failing Interest
|
||||
timed out. Therefore, an additional element needed in protocol
|
||||
semantics is the incorporation of a "Data too big" error message (via
|
||||
an "interest Return" packet in CCNx).
|
||||
|
||||
Upon dropping data as above, the CCNx/NDN forwarder converts the
|
||||
normal Data message into an Interest Return message containing the
|
||||
with the T_MTU_TOO_LARGE error code and the actual size of the data
|
||||
object instead of the data object content. It propagates that back
|
||||
toward the client identically to how the original Data message would
|
||||
have been handled. Subsequent nodes upon receiving the
|
||||
T_MTU_TOO_LARGE error treat it as all other Interest Return errors.
|
||||
When the Interest Return eventually arrives back to the issuer of the
|
||||
Interest, the user can, they desire, reissue the Interest with the
|
||||
correct expected data size.
|
||||
|
||||
One detail to note is that an Interest Return carrying
|
||||
T_MTU_TOO_LARGE must be deterministically smaller than the expected
|
||||
data size in all cases. This is clearly the case for large data
|
||||
objects, but there is a corner case with small data objects. There
|
||||
has to be a minimum expected data size that a client can specify in
|
||||
their Interests, and that minimum cannot be smaller than the size of
|
||||
a T_MTU_TOO_LARGE Interest Return
|
||||
|
||||
3.3. Handling `too small' cases
|
||||
|
||||
Next we consider the case where the returning data is smaller than
|
||||
the expected data size. While this case does not result in
|
||||
congestion, it can cause resources to be inefficiently allocated
|
||||
because not all of the set-aside bandwidth for the returning data
|
||||
object gets used. The simplest and most straightforward way to deal
|
||||
with this case is to essentially ignore it. The motivation for not
|
||||
worrying about the smaller data mismatch is that in many situations
|
||||
that employ usage-based resource measurement (and possibly charging),
|
||||
it is trivial to just account for the usage according to the larger
|
||||
expected data size rather than actual returned data size. Properly
|
||||
adjusting congestion control parameters to somehow penalize users for
|
||||
over-estimating their resource usage requires fairly heavyweight
|
||||
machinery, which in most cases is not warranted. If desired, any of
|
||||
the following mechanisms could be considered:
|
||||
|
||||
o Attempt to identify future Interests for the same object or
|
||||
closely related objects and allocate resources based on some
|
||||
retained state about the actual size of prior objects
|
||||
|
||||
o Police consumer behavior and decrease the expected data size in
|
||||
one or more future Interests to compensate
|
||||
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 11, 2020 [Page 7]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance August 2019
|
||||
|
||||
|
||||
o For small objects, do more optimistic resource allocation on the
|
||||
links on the presumption that there will be some "slack" due to
|
||||
clients overestimating data object size.
|
||||
|
||||
One protocol detail of CCNx/NDN that needs to be dealt with is
|
||||
Interest Aggregation. This happens when multiple Interests arrive at
|
||||
a forwarder for the same Named object. These are aggregated such
|
||||
that one of them (i.e.the first to arrive and create PIT state) is
|
||||
forwarded, and the rest are dropped while marking the arrival face so
|
||||
the data can be sent back to the multiple requesting clients.
|
||||
Interest aggregation interacts with expected data size if Interests
|
||||
from different clients contain different values of the expected data
|
||||
size. As above, the simplest solution to this problem is to ignore
|
||||
it, as most error cases are benign. However, there is one
|
||||
problematic error case where one client provides an accurate expected
|
||||
data size, but another who issued the Interest first underestimates,
|
||||
causing both to receive a Data too big error. This introduces a
|
||||
denial of service vulnerability, which we discuss below together with
|
||||
the other malicious actor cases.
|
||||
|
||||
3.4. Interactions with Interest Aggregation
|
||||
|
||||
Interest Aggregation, while a powerful feature for maintaining flow
|
||||
balance when multiple consumers send Interests for the same Named
|
||||
object, introduces subtle complications. Whenever a second or
|
||||
subsequent Interest arrives at a forwarder with an active PIT entry
|
||||
it is possible that those Interests carry different parameters, for
|
||||
example hop limit, payload, etc. It is therefore necessary to
|
||||
specify the exact behavior of the forwarder for each of the
|
||||
parameters that might differ. In the case of the expected data size
|
||||
parameter defined here, the value is associated with the ingress face
|
||||
on which the Interest creating the PIT entry arrived, as opposed to
|
||||
being global to the PIT entry as a whole. There are two cases to
|
||||
consider:
|
||||
|
||||
1. The arriving interest carries an expected data size smaller than
|
||||
any of the values associated with the PIT entry.
|
||||
|
||||
2. The arriving interest carries an expected data size larger than
|
||||
any of the values associated with the PIT entry.
|
||||
|
||||
For Case (1) the Interest can be safely aggregated since the upstream
|
||||
links will have sufficient bandwidth allocated based on the larger
|
||||
expected data size (assuming the original Interest's expected data
|
||||
size was itself sufficiently large to accommodate the actual size of
|
||||
the returning Data. On the other hand, should the incoming face have
|
||||
bandwidth allocated based on the larger existing Interest's expected
|
||||
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 11, 2020 [Page 8]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance August 2019
|
||||
|
||||
|
||||
data size, or on the smaller value in the arriving interest? Here
|
||||
there are two possible approaches:
|
||||
|
||||
a. Allocate based on the data size already in the PIT. In this case
|
||||
the consumer sending the earlier Interest can cause over-
|
||||
allocation of link bandwidth for other incoming faces, but there
|
||||
will not be a T_MTU_TOO_LARGE error generated for that Interest
|
||||
|
||||
b. Allocate based on the value in the arriving Interest. If the
|
||||
returning Data is in fact larger, generate a T_MTU_TOO_LARGE
|
||||
Interest Return on that ingress face, while successfully
|
||||
returning the Data message on any faces that do not exhibit a too
|
||||
small expected data size
|
||||
|
||||
It is RECOMMENDED that the second policy be followed. The reasons
|
||||
behind this recommendation are as follows:
|
||||
|
||||
1. The link can be congested quite quickly after the queuing
|
||||
decision is made, especially if the data has a long link-
|
||||
occupancy time, so this is a safer alternative.
|
||||
|
||||
2. The cost of returning the error is only one link RTT, since the
|
||||
consumer (or downstream forwarder) can immediately re-issue the
|
||||
interest with the correct size and pick up the cached object from
|
||||
the upstream forwarder's Content Store.
|
||||
|
||||
3. Being optimistic and returning the data interacts with the
|
||||
behavior of aggregate resource control and resource accounting,
|
||||
which in turn raises the messy issue of whether to "charge" the
|
||||
consumer for the actual bandwidth used or only for the requested
|
||||
bandwidth in the expected data.
|
||||
|
||||
4. The rabbit hole goes deeper if you add differential QoS to the
|
||||
equation or consumers "playing games" and intentionally
|
||||
underestimating so their interests get satisfied when links
|
||||
aren't congested. This makes handling malicious actors
|
||||
(Section 4) more difficult.
|
||||
|
||||
For Case (2) above, the Interest MUST be forwarded rather than
|
||||
aggregated to prevent a consumer from mounting a denial of service
|
||||
attack by sending intentionally too small expected data size (see
|
||||
Section 4 for additional detail on this and other attacks). As above
|
||||
for Case (1) it is RECOMMENDED that policy (b) above be followed.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 11, 2020 [Page 9]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance August 2019
|
||||
|
||||
|
||||
3.5. Operation when some Interests lack the expected data size option
|
||||
and some have it
|
||||
|
||||
Since the expected data size hop-by-hop option forwarders need to be
|
||||
prepared to handle an arbitrary mix of the two forms. There are two
|
||||
general things to address.
|
||||
|
||||
First, we assume that any forwarder supporting expected data size is
|
||||
running a more sophisticated congestion control algorithm that one
|
||||
employing simple interest counting. The link bandwidth resource
|
||||
allocation is therefore based directly, or indirectly, on the
|
||||
expected Data size in bytes. Therefore, the forwarder has to assign
|
||||
a value to use in the resource allocation for the reverse link. This
|
||||
specification does not mandate any particular approach or a default
|
||||
value to use. However, in the absence on other guidance, it makes
|
||||
sense to do one of two things:
|
||||
|
||||
1. Pick a default based on the link MTU of the face on which the
|
||||
Interest arrived and use that for all Interests lacking an
|
||||
expected data size. This is likely to be most compatible with
|
||||
simple interest counting which would rate limit all incoming
|
||||
interests equally
|
||||
|
||||
2. Configure some values for given Name prefixes that have known
|
||||
sizes. This may be appropriate for dedicated forwarders
|
||||
supporting single use cases, such as:
|
||||
|
||||
* A forwarder handling IoT sensors sending very small Data
|
||||
packets
|
||||
|
||||
* A forwarder handling real-time video with large average Data
|
||||
packets that exceed link MTU and are routinely fragmented
|
||||
|
||||
* A forwarder doing voice trunking where the vocoders produce
|
||||
moderate sized packets, still much smaller than the link MTU
|
||||
|
||||
The second area to address is what to do if an interest lacking an
|
||||
expected Data size is responded to by a Data message whose size
|
||||
exceeds the default discussed above. It would be inappropriate to
|
||||
issue a T_MTU_TOO_LARGE error, since the consumer is unlikely to
|
||||
understand or deal correctly with that new error case. Instead, it
|
||||
is RECOMMENDED that the forwarder:
|
||||
|
||||
o Ignore the mismatch if the reverse link is not congested and
|
||||
return the requested Data message anyway.
|
||||
|
||||
o If the reverse link is congested, issue an Interest Return with
|
||||
the T_NO_RESOURCES error code
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 11, 2020 [Page 10]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance August 2019
|
||||
|
||||
|
||||
This specification does not define or recommend any particular
|
||||
algorithm for assessing the congestion state of the link(s) to carry
|
||||
the Data message downstream to the requesting consumers. It is
|
||||
assumed that a reasonable algorithm is in use, because otherwise even
|
||||
basic Interest counting forms of congestion control would not be
|
||||
effective.
|
||||
|
||||
4. Dealing with malicious actors
|
||||
|
||||
First we note that various known attacks in CCNx or NDN can also be
|
||||
mounted by users employing this method. Attacks that involve
|
||||
interest flooding, cache pollution, cache poisoning, etc. are neither
|
||||
worsened nor ameliorated by the introduction of the congestion
|
||||
control capabilities described here. However, there are two new
|
||||
vulnerabilities that need to be dealt with. These two new
|
||||
vulnerabilities involve intentional mis-estimation of data size.
|
||||
|
||||
The first is a consumer who intentionally over-estimates data size
|
||||
with the goal of preventing other users from using the bandwidth.
|
||||
This is at most a minor concern given the above discussion of over-
|
||||
estimation by honest clients. If one of the amelioration techniques
|
||||
above are used, the case of malicious over-estimation is also dealt
|
||||
with adequately.
|
||||
|
||||
The second is a user who intentionally under-estimates the data size
|
||||
with the goal having its Interest processed while the other
|
||||
aggregated interests are not processed, thereby causing
|
||||
T_MTU_TOO_LARGE errors and denying service to the other users with
|
||||
overlapping requests. There are a number of possible mitigation
|
||||
techniques for this attack vector, ranging in complexity. We outline
|
||||
two below; there may be others as or more effective with acceptable
|
||||
complexity and overhead:
|
||||
|
||||
o (Simplest) A user sending Interests resulting in a T_MTU_TOO_LARGE
|
||||
error is treated similarly to users mounting interest flooding
|
||||
attacks; the a router aggregating Interests with differing
|
||||
expected data sizes rate limits the face(s) exhibiting these
|
||||
errors, thus decreasing the ability of a user to issue enough mis-
|
||||
estimated Interests to collide and generate Interest aggregation.
|
||||
|
||||
o An ICN forwarder aggregating Interests remembers in the PIT entry
|
||||
not only the expected data size of the Interest it forwarded, but
|
||||
the maximum of the expected data size of the other Interests it
|
||||
aggregated. If a T_MTU_TOO_LARGE error comes back, instead of
|
||||
propagating it, the forwarder MAY treat this as a transient error,
|
||||
drop the Interest Return, and re-forward the Interest using the
|
||||
maximum expected data size in the PIT (assuming it is is bigger).
|
||||
This recovers from the error, but the attacker can still cause an
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 11, 2020 [Page 11]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance August 2019
|
||||
|
||||
|
||||
extra round trip to the producer or to an upstream forwarder with
|
||||
a copy of the data in its Content Store.
|
||||
|
||||
5. Mapping to CCNx and NDN packet encodings
|
||||
|
||||
The only actual protocol needed is a TLV in Interest messages that
|
||||
states the size in bytes of the expected Data Message coming back,
|
||||
and in the Interest Return on a "too big" error to carry the actual
|
||||
data size. In the case of CCNx, this covers the encapsulated Data
|
||||
Object, but not the hop-by-hop headers.
|
||||
|
||||
5.1. Packet encoding for CCNx
|
||||
|
||||
For CCNx[RFC8569] there is a new hop-by-hop header TLV, and a new
|
||||
value of the Interest Return "Return Type".
|
||||
|
||||
Expected Data Size (for Interest messages), or Actual Data Size (for
|
||||
Interest Return messages) TLV
|
||||
|
||||
+------------+----------+-------------------------------------------+
|
||||
| Abbrev | Name | Description |
|
||||
+------------+----------+-------------------------------------------+
|
||||
| T_DATASIZE | Data | Expected (Section 3)or Actual (Section |
|
||||
| | Size | 3.2) Data Size |
|
||||
+------------+----------+-------------------------------------------+
|
||||
|
||||
Table 1: Data Size TLV
|
||||
|
||||
5.2. Packet encoding for NDN
|
||||
|
||||
TBD based on [NDNTLV]. Suggestions from the NDN team greatly
|
||||
appreciated.
|
||||
|
||||
6. IANA Considerations
|
||||
|
||||
Please Add the T_DATASIZE TLV to the Hop-by-Hop TLV types registry,
|
||||
with fixed length of 2, and data type numeric
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 11, 2020 [Page 12]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance August 2019
|
||||
|
||||
|
||||
Expected/Actual Data Size TLV encoding. The range has an upper bound
|
||||
of 64K bytes, since that is the largest MTU supported by CCNx.
|
||||
|
||||
1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+---------------+---------------+---------------+---------------+
|
||||
| T_DATASIZE | 2 |
|
||||
+---------------+---------------+---------------+---------------+
|
||||
| Size in bytes (1-65535) |
|
||||
+---------------+---------------+
|
||||
|
||||
Figure 1: Expected/Actual Data Size Encoding
|
||||
|
||||
7. Security Considerations
|
||||
|
||||
Here we recapitulate the vulnerabilities, attack scenarios and
|
||||
mitigations.
|
||||
|
||||
The "too big" error that generates an Interest Return with
|
||||
T_MTU_TOO_LARGE leaks the actual data object size to any consumer who
|
||||
can issue an Interest with an intentionally small expected data size.
|
||||
This does not represent a privacy vulnerability, for two reasons:
|
||||
|
||||
1. The user could learn the actual data size just by looking at the
|
||||
returned Data message using a properly-constructed Interest.
|
||||
|
||||
2. In many cases the actual data sizes are already available as
|
||||
meta-data in the corresponding Manifest pointing to the Data
|
||||
object.
|
||||
|
||||
8. References
|
||||
|
||||
8.1. Normative References
|
||||
|
||||
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
|
||||
Requirement Levels", BCP 14, RFC 2119,
|
||||
DOI 10.17487/RFC2119, March 1997, <https://www.rfc-
|
||||
editor.org/info/rfc2119>.
|
||||
|
||||
[RFC8569] Mosko, M., Solis, I., and C. Wood, "Content-Centric
|
||||
Networking (CCNx) Semantics", RFC 8569,
|
||||
DOI 10.17487/RFC8569, July 2019, <https://www.rfc-
|
||||
editor.org/info/rfc8569>.
|
||||
|
||||
[RFC8609] Mosko, M., Solis, I., and C. Wood, "Content-Centric
|
||||
Networking (CCNx) Messages in TLV Format", RFC 8609,
|
||||
DOI 10.17487/RFC8609, July 2019, <https://www.rfc-
|
||||
editor.org/info/rfc8609>.
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 11, 2020 [Page 13]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance August 2019
|
||||
|
||||
|
||||
8.2. Informative References
|
||||
|
||||
[Carofiglio2012]
|
||||
Carofiglio, G., Gallo, M., and L. Muscariello, "Joint hop-
|
||||
by-hop and receiver-driven interest control protocol for
|
||||
content-centric networks, in ICN Workshop at SIGcomm
|
||||
2012", DOI 10.1145/2377677.2377772, 2102,
|
||||
<http://conferences.sigcomm.org/sigcomm/2012/paper/icn/
|
||||
p37.pdf>.
|
||||
|
||||
[Ghali2013]
|
||||
Ghali, C., Narayanan, A., Oran, D., Tsudik, G., and C.
|
||||
Wood, "Secure Fragmentation for Content-Centric Networks,
|
||||
in IEEE 14th International Symposium on Network Computing
|
||||
and Applications", DOI 10.1109/nca.2015.34, 2015,
|
||||
<http://dx.doi.org/10.1109/NCA.2015.34>.
|
||||
|
||||
[I-D.ietf-quic-transport]
|
||||
Iyengar, J. and M. Thomson, "QUIC: A UDP-Based Multiplexed
|
||||
and Secure Transport", draft-ietf-quic-transport-22 (work
|
||||
in progress), July 2019.
|
||||
|
||||
[Mahdian2016]
|
||||
Mahdian, M., Arianfar, S., Gibson, J., and D. Oran,
|
||||
"MIRCC: Multipath-aware ICN Rate-based Congestion Control,
|
||||
in Proceedings of the 3rd ACM Conference on Information-
|
||||
Centric Networking", DOI 10.1145/2984356.2984365, 2016,
|
||||
<http://conferences2.sigcomm.org/acm-icn/2016/proceedings/
|
||||
p1-mahdian.pdf>.
|
||||
|
||||
[minmaxfairness]
|
||||
Wikipedia, , "Max-min Fairness", various,
|
||||
<https://en.wikipedia.org/wiki/Max-min_fairness>.
|
||||
|
||||
[NDN] NDN team, , "Named Data Networking", various,
|
||||
<https://named-data.net/project/execsummary/>.
|
||||
|
||||
[NDNTLV] NDN Project Team, , "NDN Packet Format Specification.",
|
||||
2016, <http://named-data.net/doc/ndn-tlv/>.
|
||||
|
||||
[proportionalfairness]
|
||||
Wikipedia, , "Proportionally Fair", various,
|
||||
<https://en.wikipedia.org/wiki/Proportionally_fair>.
|
||||
|
||||
[RFC0793] Postel, J., "Transmission Control Protocol", STD 7,
|
||||
RFC 793, DOI 10.17487/RFC0793, September 1981,
|
||||
<https://www.rfc-editor.org/info/rfc793>.
|
||||
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 11, 2020 [Page 14]
|
||||
|
||||
Internet-Draft Maintaining Flow Balance August 2019
|
||||
|
||||
|
||||
[RFC4340] Kohler, E., Handley, M., and S. Floyd, "Datagram
|
||||
Congestion Control Protocol (DCCP)", RFC 4340,
|
||||
DOI 10.17487/RFC4340, March 2006, <https://www.rfc-
|
||||
editor.org/info/rfc4340>.
|
||||
|
||||
[RFC4960] Stewart, R., Ed., "Stream Control Transmission Protocol",
|
||||
RFC 4960, DOI 10.17487/RFC4960, September 2007,
|
||||
<https://www.rfc-editor.org/info/rfc4960>.
|
||||
|
||||
[Schneider2016]
|
||||
Schneider, K., Yi, C., Zhang, B., and L. Zhang, "A
|
||||
Practical Congestion Control Scheme for Named Data
|
||||
Networking, in Proceedings of the 2016 conference on 3rd
|
||||
ACM Conference on Information-Centric Networking - ACM-ICN
|
||||
'16", DOI 10.1145/2984356.2984369, 2016,
|
||||
<http://conferences2.sigcomm.org/acm-icn/2016/proceedings/
|
||||
p21-schneider.pdf>.
|
||||
|
||||
[Song2018]
|
||||
Song, J., Lee, M., and T. Kwon, "SMIC: Subflow-level
|
||||
Multi-path Interest Control for Information Centric
|
||||
Networking, in 5th ACM Conference on Information-Centric
|
||||
Networking", DOI 10.1145/3267955.3267971, 2018,
|
||||
<https://conferences.sigcomm.org/acm-icn/2018/proceedings/
|
||||
icn18-final62.pdf>.
|
||||
|
||||
[Wang2013]
|
||||
Wang, Y., Rozhnova, N., Narayanan, A., Oran, D., and I.
|
||||
Rhee, "An Improved Hop-by-hop Interest Shaper for
|
||||
Congestion Control in Named Data Networking, in ACM
|
||||
SIGCOMM Workshop on Information-Centric Networking",
|
||||
DOI 10.1145/2534169.2491233, 2013,
|
||||
<http://conferences.sigcomm.org/sigcomm/2013/papers/icn/
|
||||
p55.pdf>.
|
||||
|
||||
Author's Address
|
||||
|
||||
Dave Oran
|
||||
Network Systems Research and Design
|
||||
4 Shady Hill Square
|
||||
Cambridge, MA 02138
|
||||
USA
|
||||
|
||||
Email: daveoran@orandom.net
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
D. Oran Expires February 11, 2020 [Page 15]
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2017 Christopher Wood
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
File.readlines('versions').each do |line|
|
||||
tagged = line.split(":")
|
||||
basename = tagged[0]
|
||||
oldname = basename + "-latest"
|
||||
newname = basename + "-" + tagged[1].strip!
|
||||
|
||||
`cat docs/build/#{basename}.html | sed -e 's/#{oldname}/#{newname}/' > docs/build/#{newname}.html`
|
||||
`cat docs/build/#{basename}.txt | sed -e 's/#{oldname}/#{newname}/' > docs/build/#{newname}.txt`
|
||||
end
|
||||
-311
@@ -1,311 +0,0 @@
|
||||
<!--
|
||||
revised DTD for the RFC document series, draft of 2000-02-23
|
||||
-->
|
||||
|
||||
|
||||
<!--
|
||||
Typical invocation:
|
||||
<!DOCTYPE rfc PUBLIC "-//IETF//DTD RFC 2629//EN"
|
||||
"http://xml.resource.org/authoring/rfc2629.dtd" [
|
||||
... dtd subset ...
|
||||
]>
|
||||
or
|
||||
<!DOCTYPE rfc SYSTEM "rfc2629.dtd" [
|
||||
... dtd subset ...
|
||||
]>
|
||||
-->
|
||||
|
||||
|
||||
<!--
|
||||
Contents
|
||||
|
||||
Character entities
|
||||
|
||||
DTD data types
|
||||
|
||||
The top-level
|
||||
|
||||
Front matter
|
||||
|
||||
The Body
|
||||
|
||||
Back matter
|
||||
-->
|
||||
|
||||
|
||||
<!--
|
||||
Character entities
|
||||
-->
|
||||
|
||||
|
||||
<!ENTITY % rfc2629-xhtml
|
||||
PUBLIC "-//IETF//ENTITIES XHTML subset for RFC 2629//EN"
|
||||
"rfc2629-xhtml.ent">
|
||||
%rfc2629-xhtml;
|
||||
|
||||
<!ENTITY % rfc2629-other
|
||||
PUBLIC "-//IETF//ENTITIES Other for RFC 2629//EN"
|
||||
"rfc2629-other.ent">
|
||||
%rfc2629-other;
|
||||
|
||||
|
||||
<!--
|
||||
DTD data types:
|
||||
|
||||
entity description
|
||||
====== ===============================================
|
||||
NUMBER [0-9]+
|
||||
NUMBERS a comma-separated list of NUMBER
|
||||
|
||||
DAY the day of the month, e.g., "1"
|
||||
MONTH the month of the year, e.g., "January"
|
||||
YEAR a four-digit year, e.g., "1999"
|
||||
|
||||
URI e.g., "http://invisible.net/"
|
||||
|
||||
ATEXT/CTEXT printable ASCII text (no line-terminators)
|
||||
|
||||
TEXT character data
|
||||
-->
|
||||
|
||||
|
||||
<!ENTITY % NUMBER "CDATA">
|
||||
<!ENTITY % NUMBERS "CDATA">
|
||||
|
||||
<!ENTITY % DAY "CDATA">
|
||||
<!ENTITY % MONTH "CDATA">
|
||||
<!ENTITY % YEAR "CDATA">
|
||||
|
||||
<!ENTITY % URI "CDATA">
|
||||
|
||||
<!ENTITY % ATEXT "CDATA">
|
||||
<!ENTITY % CTEXT "#PCDATA">
|
||||
|
||||
<!ENTITY % TEXT "#PCDATA">
|
||||
|
||||
<!ENTITY rfc.number "XXXX">
|
||||
|
||||
|
||||
<!--
|
||||
The top-level
|
||||
-->
|
||||
|
||||
|
||||
<!--
|
||||
attributes for the "rfc" element are supplied by the RFC
|
||||
editor. when preparing drafts, authors should leave them blank.
|
||||
|
||||
the "seriesNo" attribute is used if the category is, e.g., BCP.
|
||||
-->
|
||||
<!ELEMENT rfc (front,middle,back?)>
|
||||
<!ATTLIST rfc
|
||||
number %NUMBER; #IMPLIED
|
||||
obsoletes %NUMBERS; ""
|
||||
updates %NUMBERS; ""
|
||||
category (std|bcp|info|exp|historic)
|
||||
#IMPLIED
|
||||
seriesNo %NUMBER; #IMPLIED
|
||||
ipr (full2026|noDerivativeWorks2026|none
|
||||
|full3667|noModification3667|noDerivatives3667
|
||||
|full3978|noModification3978|noDerivatives3978
|
||||
|trust200811|noModificationTrust200811|noDerivativesTrust200811
|
||||
|trust200902|noModificationTrust200902|noDerivativesTrust200902
|
||||
|pre5378Trust200902)
|
||||
#IMPLIED
|
||||
iprExtract IDREF #IMPLIED
|
||||
submissionType
|
||||
(IETF|independent) "IETF"
|
||||
docName %ATEXT; #IMPLIED
|
||||
xml:lang %ATEXT; "en">
|
||||
|
||||
|
||||
<!--
|
||||
Front matter
|
||||
-->
|
||||
|
||||
|
||||
<!ELEMENT front (title,author+,date,area*,workgroup*,keyword*,
|
||||
abstract?,note*)>
|
||||
|
||||
<!-- the "abbrev" attribute is used for headers, etc. -->
|
||||
<!ELEMENT title (%CTEXT;)>
|
||||
<!ATTLIST title
|
||||
abbrev %ATEXT; #IMPLIED>
|
||||
|
||||
<!ELEMENT author (organization,address?)>
|
||||
<!ATTLIST author
|
||||
initials %ATEXT; #IMPLIED
|
||||
surname %ATEXT; #IMPLIED
|
||||
fullname %ATEXT; #IMPLIED
|
||||
role (editor) #IMPLIED>
|
||||
|
||||
<!ELEMENT organization
|
||||
(%CTEXT;)>
|
||||
<!ATTLIST organization
|
||||
abbrev %ATEXT; #IMPLIED>
|
||||
|
||||
<!ELEMENT address (postal?,phone?,facsimile?,email?,uri?)>
|
||||
|
||||
<!-- this content model should be more strict:
|
||||
at most one of each the city, region, code, and country
|
||||
elements may be present -->
|
||||
<!ELEMENT postal (street+,(city|region|code|country)*)>
|
||||
<!ELEMENT street (%CTEXT;)>
|
||||
<!ELEMENT city (%CTEXT;)>
|
||||
<!ELEMENT region (%CTEXT;)>
|
||||
<!ELEMENT code (%CTEXT;)>
|
||||
<!ELEMENT country (%CTEXT;)>
|
||||
<!ELEMENT phone (%CTEXT;)>
|
||||
<!ELEMENT facsimile (%CTEXT;)>
|
||||
<!ELEMENT email (%CTEXT;)>
|
||||
<!ELEMENT uri (%CTEXT;)>
|
||||
|
||||
<!ELEMENT date EMPTY>
|
||||
<!ATTLIST date
|
||||
day %DAY; #IMPLIED
|
||||
month %MONTH; #IMPLIED
|
||||
year %YEAR; #IMPLIED>
|
||||
|
||||
<!-- meta-data... -->
|
||||
<!ELEMENT area (%CTEXT;)>
|
||||
<!ELEMENT workgroup (%CTEXT;)>
|
||||
<!ELEMENT keyword (%CTEXT;)>
|
||||
|
||||
<!ELEMENT abstract (t)+>
|
||||
<!ELEMENT note (t)+>
|
||||
<!ATTLIST note
|
||||
title %ATEXT; #REQUIRED>
|
||||
|
||||
|
||||
<!--
|
||||
The body
|
||||
-->
|
||||
|
||||
|
||||
<!ELEMENT middle (section+)>
|
||||
|
||||
<!ELEMENT section ((t|figure|texttable|iref)*,section*)>
|
||||
<!ATTLIST section
|
||||
anchor ID #IMPLIED
|
||||
title %ATEXT; #REQUIRED
|
||||
toc (include|exclude|default)
|
||||
"default">
|
||||
|
||||
<!-- use of <appendix/> is deprecated...
|
||||
<!ELEMENT appendix ((t|figure|texttable|iref)*,appendix*)>
|
||||
<!ATTLIST appendix
|
||||
anchor ID #IMPLIED
|
||||
title %ATEXT; #REQUIRED
|
||||
toc (include|exclude|default)
|
||||
"default">
|
||||
-->
|
||||
|
||||
<!-- use of <figure/> is deprecated... -->
|
||||
<!ELEMENT t (%TEXT;|list|figure|xref|eref|iref|cref|spanx|vspace)*>
|
||||
<!ATTLIST t
|
||||
anchor ID #IMPLIED
|
||||
hangText %ATEXT; #IMPLIED>
|
||||
|
||||
<!-- the value of the style attribute is inherited from the closest
|
||||
parent -->
|
||||
<!ELEMENT list (t+)>
|
||||
<!ATTLIST list
|
||||
style %ATEXT; #IMPLIED
|
||||
hangIndent %NUMBER; #IMPLIED
|
||||
counter %ATEXT; #IMPLIED>
|
||||
|
||||
<!ELEMENT xref (%CTEXT;)>
|
||||
<!ATTLIST xref
|
||||
target IDREF #REQUIRED
|
||||
pageno (true|false) "false"
|
||||
format (counter|title|none|default)
|
||||
"default">
|
||||
|
||||
<!ELEMENT eref (%CTEXT;)>
|
||||
<!ATTLIST eref
|
||||
target %URI; #REQUIRED>
|
||||
|
||||
<!ELEMENT iref EMPTY>
|
||||
<!ATTLIST iref
|
||||
item %ATEXT; #REQUIRED
|
||||
subitem %ATEXT; ""
|
||||
primary (true|false) "false">
|
||||
|
||||
<!ELEMENT cref (%CTEXT;)>
|
||||
<!ATTLIST cref
|
||||
anchor ID #IMPLIED
|
||||
source %ATEXT; #IMPLIED>
|
||||
|
||||
<!ELEMENT spanx (%CTEXT;)>
|
||||
<!ATTLIST spanx
|
||||
xml:space (default|preserve) "preserve"
|
||||
style %ATEXT; "emph">
|
||||
|
||||
<!ELEMENT vspace EMPTY>
|
||||
<!ATTLIST vspace
|
||||
blankLines %NUMBER; "0">
|
||||
|
||||
<!ELEMENT figure (iref*,preamble?,artwork,postamble?)>
|
||||
<!ATTLIST figure
|
||||
anchor ID #IMPLIED
|
||||
title %ATEXT; ""
|
||||
suppress-title (true|false) "false"
|
||||
src %URI; #IMPLIED
|
||||
align (left|center|right) "left"
|
||||
alt %ATEXT; ""
|
||||
width %ATEXT; ""
|
||||
height %ATEXT; "">
|
||||
|
||||
<!ELEMENT preamble (%TEXT;|xref|eref|iref|cref|spanx)*>
|
||||
<!ELEMENT artwork (%TEXT;)*>
|
||||
<!ATTLIST artwork
|
||||
xml:space (default|preserve) "preserve"
|
||||
name %ATEXT; ""
|
||||
type %ATEXT; ""
|
||||
src %URI; #IMPLIED
|
||||
align (left|center|right) "left"
|
||||
alt %ATEXT; ""
|
||||
width %ATEXT; ""
|
||||
height %ATEXT; "">
|
||||
|
||||
<!ELEMENT postamble (%TEXT;|xref|eref|iref|cref|spanx)*>
|
||||
|
||||
<!ELEMENT texttable (preamble?,ttcol+,c*,postamble?)>
|
||||
<!ATTLIST texttable
|
||||
anchor ID #IMPLIED
|
||||
title %ATEXT; ""
|
||||
suppress-title (true|false) "false"
|
||||
align (left|center|right) "center"
|
||||
style (all|none|headers|full) "full">
|
||||
<!ELEMENT ttcol (%CTEXT;)>
|
||||
<!ATTLIST ttcol
|
||||
width %ATEXT; #IMPLIED
|
||||
align (left|center|right) "left">
|
||||
<!ELEMENT c (%TEXT;|xref|eref|iref|cref|spanx)*>
|
||||
|
||||
|
||||
<!--
|
||||
Back matter
|
||||
-->
|
||||
|
||||
|
||||
<!-- sections, if present, are appendices -->
|
||||
<!ELEMENT back (references*,section*)>
|
||||
|
||||
<!ELEMENT references (reference+)>
|
||||
<!ATTLIST references
|
||||
title %ATEXT; "References">
|
||||
<!ELEMENT reference (front,seriesInfo*,format*,annotation*)>
|
||||
<!ATTLIST reference
|
||||
anchor ID #IMPLIED
|
||||
target %URI; #IMPLIED>
|
||||
<!ELEMENT seriesInfo EMPTY>
|
||||
<!ATTLIST seriesInfo
|
||||
name %ATEXT; #REQUIRED
|
||||
value %ATEXT; #REQUIRED>
|
||||
<!ELEMENT format EMPTY>
|
||||
<!ATTLIST format
|
||||
target %URI; #IMPLIED
|
||||
type %ATEXT; #REQUIRED
|
||||
octets %NUMBER; #IMPLIED>
|
||||
<!ELEMENT annotation (%TEXT;|xref|eref|iref|cref|spanx)*>
|
||||
-11960
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,2 @@
|
||||
TARGETS_DRAFTS := draft-oran-icnrg-flowbalance
|
||||
TARGETS_TAGS :=
|
||||
@@ -0,0 +1,36 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2017 Christopher Wood
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
include lib/main.mk
|
||||
|
||||
lib/main.mk:
|
||||
ifneq (,$(shell git submodule status lib 2>/dev/null))
|
||||
git submodule sync
|
||||
git submodule update --init
|
||||
else
|
||||
git clone --depth 10 -b master https://github.com/martinthomson/i-d-template.git lib
|
||||
endif
|
||||
|
||||
up: lib/main.mk
|
||||
rm -rf ../docs/build/*
|
||||
mv *.html ../docs/build
|
||||
mv *.txt ../docs/build
|
||||
@@ -0,0 +1,548 @@
|
||||
#! /usr/bin/python
|
||||
# coding=utf-8
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
#
|
||||
# Transform a unified diff from stdin to a colored
|
||||
# side-by-side HTML page on stdout.
|
||||
#
|
||||
# Authors: Olivier Matz <zer0@droids-corp.org>
|
||||
# Alan De Smet <adesmet@cs.wisc.edu>
|
||||
# Sergey Satskiy <sergey.satskiy@gmail.com>
|
||||
# scito <info at scito.ch>
|
||||
#
|
||||
# Inspired by diff2html.rb from Dave Burt <dave (at) burt.id.au>
|
||||
# (mainly for html theme)
|
||||
#
|
||||
# TODO:
|
||||
# - The sane function currently mashes non-ASCII characters to "."
|
||||
# Instead be clever and convert to something like "xF0"
|
||||
# (the hex value), and mark with a <span>. Even more clever:
|
||||
# Detect if the character is "printable" for whatever definition,
|
||||
# and display those directly.
|
||||
|
||||
import sys, re, htmlentitydefs, getopt, StringIO, codecs, datetime
|
||||
try:
|
||||
from simplediff import diff, string_diff
|
||||
except ImportError:
|
||||
sys.stderr.write("info: simplediff module not found, only linediff is available\n")
|
||||
sys.stderr.write("info: it can be downloaded at https://github.com/paulgb/simplediff\n")
|
||||
|
||||
# minimum line size, we add a zero-sized breakable space every
|
||||
# LINESIZE characters
|
||||
linesize = 20
|
||||
tabsize = 8
|
||||
show_CR = False
|
||||
encoding = "utf-8"
|
||||
lang = "en"
|
||||
algorithm = 0
|
||||
|
||||
desc = "File comparison"
|
||||
dtnow = datetime.datetime.now()
|
||||
modified_date = "%s+01:00"%dtnow.isoformat()
|
||||
|
||||
html_hdr = """<!DOCTYPE html>
|
||||
<html lang="{5}" dir="ltr"
|
||||
xmlns:dc="http://purl.org/dc/terms/">
|
||||
<head>
|
||||
<meta charset="{1}" />
|
||||
<meta name="generator" content="diff2html.py (http://git.droids-corp.org/gitweb/?p=diff2html)" />
|
||||
<!--meta name="author" content="Fill in" /-->
|
||||
<title>HTML Diff{0}</title>
|
||||
<link rel="shortcut icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAACVBMVEXAAAAAgAD///+K/HwIAAAAJUlEQVQI12NYBQQM2IgGBQ4mCIEQW7oyK4phampkGIQAc1G1AQCRxCNbyW92oQAAAABJRU5ErkJggg==" type="image/png" />
|
||||
<meta property="dc:language" content="{5}" />
|
||||
<!--meta property="dc:date" content="{3}" /-->
|
||||
<meta property="dc:modified" content="{4}" />
|
||||
<meta name="description" content="{2}" />
|
||||
<meta property="dc:abstract" content="{2}" />
|
||||
<style>
|
||||
table {{ border:0px; border-collapse:collapse; width: 100%; font-size:0.75em; font-family: Lucida Console, monospace }}
|
||||
td.line {{ color:#8080a0 }}
|
||||
th {{ background: black; color: white }}
|
||||
tr.diffunmodified td {{ background: #D0D0E0 }}
|
||||
tr.diffhunk td {{ background: #A0A0A0 }}
|
||||
tr.diffadded td {{ background: #CCFFCC }}
|
||||
tr.diffdeleted td {{ background: #FFCCCC }}
|
||||
tr.diffchanged td {{ background: #FFFFA0 }}
|
||||
span.diffchanged2 {{ background: #E0C880 }}
|
||||
span.diffponct {{ color: #B08080 }}
|
||||
tr.diffmisc td {{}}
|
||||
tr.diffseparator td {{}}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
"""
|
||||
|
||||
html_footer = """
|
||||
<footer>
|
||||
<p>Modified at {1}. HTML formatting created by <a href="http://git.droids-corp.org/gitweb/?p=diff2html;a=summary">diff2html</a>. </p>
|
||||
</footer>
|
||||
</body></html>
|
||||
"""
|
||||
|
||||
table_hdr = """
|
||||
<table class="diff">
|
||||
"""
|
||||
|
||||
table_footer = """
|
||||
</table>
|
||||
"""
|
||||
|
||||
DIFFON = "\x01"
|
||||
DIFFOFF = "\x02"
|
||||
|
||||
buf = []
|
||||
add_cpt, del_cpt = 0, 0
|
||||
line1, line2 = 0, 0
|
||||
hunk_off1, hunk_size1, hunk_off2, hunk_size2 = 0, 0, 0, 0
|
||||
|
||||
|
||||
# Characters we're willing to word wrap on
|
||||
WORDBREAK = " \t;.,/):-"
|
||||
|
||||
def sane(x):
|
||||
r = ""
|
||||
for i in x:
|
||||
j = ord(i)
|
||||
if i not in ['\t', '\n'] and (j < 32):
|
||||
r = r + "."
|
||||
else:
|
||||
r = r + i
|
||||
return r
|
||||
|
||||
def linediff(s, t):
|
||||
'''
|
||||
Original line diff algorithm of diff2html. It's character based.
|
||||
'''
|
||||
if len(s):
|
||||
s = unicode(reduce(lambda x, y:x+y, [ sane(c) for c in s ]))
|
||||
if len(t):
|
||||
t = unicode(reduce(lambda x, y:x+y, [ sane(c) for c in t ]))
|
||||
|
||||
m, n = len(s), len(t)
|
||||
d = [[(0, 0) for i in range(n+1)] for i in range(m+1)]
|
||||
|
||||
|
||||
d[0][0] = (0, (0, 0))
|
||||
for i in range(m+1)[1:]:
|
||||
d[i][0] = (i,(i-1, 0))
|
||||
for j in range(n+1)[1:]:
|
||||
d[0][j] = (j,(0, j-1))
|
||||
|
||||
for i in range(m+1)[1:]:
|
||||
for j in range(n+1)[1:]:
|
||||
if s[i-1] == t[j-1]:
|
||||
cost = 0
|
||||
else:
|
||||
cost = 1
|
||||
d[i][j] = min((d[i-1][j][0] + 1, (i-1, j)),
|
||||
(d[i][j-1][0] + 1, (i, j-1)),
|
||||
(d[i-1][j-1][0] + cost, (i-1, j-1)))
|
||||
|
||||
l = []
|
||||
coord = (m, n)
|
||||
while coord != (0, 0):
|
||||
l.insert(0, coord)
|
||||
x, y = coord
|
||||
coord = d[x][y][1]
|
||||
|
||||
l1 = []
|
||||
l2 = []
|
||||
|
||||
for coord in l:
|
||||
cx, cy = coord
|
||||
child_val = d[cx][cy][0]
|
||||
|
||||
father_coord = d[cx][cy][1]
|
||||
fx, fy = father_coord
|
||||
father_val = d[fx][fy][0]
|
||||
|
||||
diff = (cx-fx, cy-fy)
|
||||
|
||||
if diff == (0, 1):
|
||||
l1.append("")
|
||||
l2.append(DIFFON + t[fy] + DIFFOFF)
|
||||
elif diff == (1, 0):
|
||||
l1.append(DIFFON + s[fx] + DIFFOFF)
|
||||
l2.append("")
|
||||
elif child_val-father_val == 1:
|
||||
l1.append(DIFFON + s[fx] + DIFFOFF)
|
||||
l2.append(DIFFON + t[fy] + DIFFOFF)
|
||||
else:
|
||||
l1.append(s[fx])
|
||||
l2.append(t[fy])
|
||||
|
||||
r1, r2 = (reduce(lambda x, y:x+y, l1), reduce(lambda x, y:x+y, l2))
|
||||
return r1, r2
|
||||
|
||||
|
||||
def diff_changed(old, new):
|
||||
'''
|
||||
Returns the differences basend on characters between two strings
|
||||
wrapped with DIFFON and DIFFOFF using `diff`.
|
||||
'''
|
||||
con = {'=': (lambda x: x),
|
||||
'+': (lambda x: DIFFON + x + DIFFOFF),
|
||||
'-': (lambda x: '')}
|
||||
return "".join([(con[a])("".join(b)) for a, b in diff(old, new)])
|
||||
|
||||
|
||||
def diff_changed_ts(old, new):
|
||||
'''
|
||||
Returns a tuple for a two sided comparison based on characters, see `diff_changed`.
|
||||
'''
|
||||
return (diff_changed(new, old), diff_changed(old, new))
|
||||
|
||||
|
||||
def word_diff(old, new):
|
||||
'''
|
||||
Returns the difference between the old and new strings based on words. Punctuation is not part of the word.
|
||||
|
||||
Params:
|
||||
old the old string
|
||||
new the new string
|
||||
|
||||
Returns:
|
||||
the output of `diff` on the two strings after splitting them
|
||||
on whitespace (a list of change instructions; see the docstring
|
||||
of `diff`)
|
||||
'''
|
||||
separator_pattern = '(\W+)';
|
||||
return diff(re.split(separator_pattern, old, flags=re.UNICODE), re.split(separator_pattern, new, flags=re.UNICODE))
|
||||
|
||||
|
||||
def diff_changed_words(old, new):
|
||||
'''
|
||||
Returns the difference between two strings based on words (see `word_diff`)
|
||||
wrapped with DIFFON and DIFFOFF.
|
||||
|
||||
Returns:
|
||||
the output of the diff expressed delimited with DIFFON and DIFFOFF.
|
||||
'''
|
||||
con = {'=': (lambda x: x),
|
||||
'+': (lambda x: DIFFON + x + DIFFOFF),
|
||||
'-': (lambda x: '')}
|
||||
return "".join([(con[a])("".join(b)) for a, b in word_diff(old, new)])
|
||||
|
||||
|
||||
def diff_changed_words_ts(old, new):
|
||||
'''
|
||||
Returns a tuple for a two sided comparison based on words, see `diff_changed_words`.
|
||||
'''
|
||||
return (diff_changed_words(new, old), diff_changed_words(old, new))
|
||||
|
||||
|
||||
def convert(s, linesize=0, ponct=0):
|
||||
i = 0
|
||||
t = u""
|
||||
for c in s:
|
||||
# used by diffs
|
||||
if c == DIFFON:
|
||||
t += u'<span class="diffchanged2">'
|
||||
elif c == DIFFOFF:
|
||||
t += u"</span>"
|
||||
|
||||
# special html chars
|
||||
elif htmlentitydefs.codepoint2name.has_key(ord(c)):
|
||||
t += u"&%s;" % (htmlentitydefs.codepoint2name[ord(c)])
|
||||
i += 1
|
||||
|
||||
# special highlighted chars
|
||||
elif c == "\t" and ponct == 1:
|
||||
n = tabsize-(i%tabsize)
|
||||
if n == 0:
|
||||
n = tabsize
|
||||
t += (u'<span class="diffponct">»</span>'+' '*(n-1))
|
||||
elif c == " " and ponct == 1:
|
||||
t += u'<span class="diffponct">·</span>'
|
||||
elif c == "\n" and ponct == 1:
|
||||
if show_CR:
|
||||
t += u'<span class="diffponct">\</span>'
|
||||
else:
|
||||
t += c
|
||||
i += 1
|
||||
|
||||
if linesize and (WORDBREAK.count(c) == 1):
|
||||
t += u'​'
|
||||
i = 0
|
||||
if linesize and i > linesize:
|
||||
i = 0
|
||||
t += u"​"
|
||||
|
||||
return t
|
||||
|
||||
|
||||
def add_comment(s, output_file):
|
||||
output_file.write(('<tr class="diffmisc"><td colspan="4">%s</td></tr>\n'%convert(s)).encode(encoding))
|
||||
|
||||
|
||||
def add_filename(f1, f2, output_file):
|
||||
output_file.write(("<tr><th colspan='2'>%s</th>"%convert(f1, linesize=linesize)).encode(encoding))
|
||||
output_file.write(("<th colspan='2'>%s</th></tr>\n"%convert(f2, linesize=linesize)).encode(encoding))
|
||||
|
||||
|
||||
def add_hunk(output_file, show_hunk_infos):
|
||||
if show_hunk_infos:
|
||||
output_file.write('<tr class="diffhunk"><td colspan="2">Offset %d, %d lines modified</td>'%(hunk_off1, hunk_size1))
|
||||
output_file.write('<td colspan="2">Offset %d, %d lines modified</td></tr>\n'%(hunk_off2, hunk_size2))
|
||||
else:
|
||||
# ⋮ - vertical ellipsis
|
||||
output_file.write('<tr class="diffhunk"><td colspan="2">⋮</td><td colspan="2">⋮</td></tr>')
|
||||
|
||||
|
||||
def add_line(s1, s2, output_file):
|
||||
global line1
|
||||
global line2
|
||||
|
||||
orig1 = s1
|
||||
orig2 = s2
|
||||
|
||||
if s1 == None and s2 == None:
|
||||
type_name = "unmodified"
|
||||
elif s1 == None or s1 == "":
|
||||
type_name = "added"
|
||||
elif s2 == None or s1 == "":
|
||||
type_name = "deleted"
|
||||
elif s1 == s2:
|
||||
type_name = "unmodified"
|
||||
else:
|
||||
type_name = "changed"
|
||||
if algorithm == 1:
|
||||
s1, s2 = diff_changed_words_ts(orig1, orig2)
|
||||
elif algorithm == 2:
|
||||
s1, s2 = diff_changed_ts(orig1, orig2)
|
||||
else: # default
|
||||
s1, s2 = linediff(orig1, orig2)
|
||||
|
||||
output_file.write(('<tr class="diff%s">' % type_name).encode(encoding))
|
||||
if s1 != None and s1 != "":
|
||||
output_file.write(('<td class="diffline">%d </td>' % line1).encode(encoding))
|
||||
output_file.write('<td class="diffpresent">'.encode(encoding))
|
||||
output_file.write(convert(s1, linesize=linesize, ponct=1).encode(encoding))
|
||||
output_file.write('</td>')
|
||||
else:
|
||||
s1 = ""
|
||||
output_file.write('<td colspan="2"> </td>')
|
||||
|
||||
if s2 != None and s2 != "":
|
||||
output_file.write(('<td class="diffline">%d </td>'%line2).encode(encoding))
|
||||
output_file.write('<td class="diffpresent">')
|
||||
output_file.write(convert(s2, linesize=linesize, ponct=1).encode(encoding))
|
||||
output_file.write('</td>')
|
||||
else:
|
||||
s2 = ""
|
||||
output_file.write('<td colspan="2"></td>')
|
||||
|
||||
output_file.write('</tr>\n')
|
||||
|
||||
if s1 != "":
|
||||
line1 += 1
|
||||
if s2 != "":
|
||||
line2 += 1
|
||||
|
||||
|
||||
def empty_buffer(output_file):
|
||||
global buf
|
||||
global add_cpt
|
||||
global del_cpt
|
||||
|
||||
if del_cpt == 0 or add_cpt == 0:
|
||||
for l in buf:
|
||||
add_line(l[0], l[1], output_file)
|
||||
|
||||
elif del_cpt != 0 and add_cpt != 0:
|
||||
l0, l1 = [], []
|
||||
for l in buf:
|
||||
if l[0] != None:
|
||||
l0.append(l[0])
|
||||
if l[1] != None:
|
||||
l1.append(l[1])
|
||||
max_len = (len(l0) > len(l1)) and len(l0) or len(l1)
|
||||
for i in range(max_len):
|
||||
s0, s1 = "", ""
|
||||
if i < len(l0):
|
||||
s0 = l0[i]
|
||||
if i < len(l1):
|
||||
s1 = l1[i]
|
||||
add_line(s0, s1, output_file)
|
||||
|
||||
add_cpt, del_cpt = 0, 0
|
||||
buf = []
|
||||
|
||||
|
||||
def parse_input(input_file, output_file, input_file_name, output_file_name,
|
||||
exclude_headers, show_hunk_infos):
|
||||
global add_cpt, del_cpt
|
||||
global line1, line2
|
||||
global hunk_off1, hunk_size1, hunk_off2, hunk_size2
|
||||
|
||||
if not exclude_headers:
|
||||
title_suffix = ' ' + input_file_name
|
||||
output_file.write(html_hdr.format(title_suffix, encoding, desc, "", modified_date, lang).encode(encoding))
|
||||
output_file.write(table_hdr.encode(encoding))
|
||||
|
||||
while True:
|
||||
l = input_file.readline()
|
||||
if l == "":
|
||||
break
|
||||
|
||||
m = re.match('^--- ([^\s]*)', l)
|
||||
if m:
|
||||
empty_buffer(output_file)
|
||||
file1 = m.groups()[0]
|
||||
while True:
|
||||
l = input_file.readline()
|
||||
m = re.match('^\+\+\+ ([^\s]*)', l)
|
||||
if m:
|
||||
file2 = m.groups()[0]
|
||||
break
|
||||
add_filename(file1, file2, output_file)
|
||||
hunk_off1, hunk_size1, hunk_off2, hunk_size2 = 0, 0, 0, 0
|
||||
continue
|
||||
|
||||
m = re.match("@@ -(\d+),?(\d*) \+(\d+),?(\d*)", l)
|
||||
if m:
|
||||
empty_buffer(output_file)
|
||||
hunk_data = map(lambda x:x=="" and 1 or int(x), m.groups())
|
||||
hunk_off1, hunk_size1, hunk_off2, hunk_size2 = hunk_data
|
||||
line1, line2 = hunk_off1, hunk_off2
|
||||
add_hunk(output_file, show_hunk_infos)
|
||||
continue
|
||||
|
||||
if hunk_size1 == 0 and hunk_size2 == 0:
|
||||
empty_buffer(output_file)
|
||||
add_comment(l, output_file)
|
||||
continue
|
||||
|
||||
if re.match("^\+", l):
|
||||
add_cpt += 1
|
||||
hunk_size2 -= 1
|
||||
buf.append((None, l[1:]))
|
||||
continue
|
||||
|
||||
if re.match("^\-", l):
|
||||
del_cpt += 1
|
||||
hunk_size1 -= 1
|
||||
buf.append((l[1:], None))
|
||||
continue
|
||||
|
||||
if re.match("^\ ", l) and hunk_size1 and hunk_size2:
|
||||
empty_buffer(output_file)
|
||||
hunk_size1 -= 1
|
||||
hunk_size2 -= 1
|
||||
buf.append((l[1:], l[1:]))
|
||||
continue
|
||||
|
||||
empty_buffer(output_file)
|
||||
add_comment(l, output_file)
|
||||
|
||||
empty_buffer(output_file)
|
||||
output_file.write(table_footer.encode(encoding))
|
||||
if not exclude_headers:
|
||||
output_file.write(html_footer.format("", dtnow.strftime("%d.%m.%Y")).encode(encoding))
|
||||
|
||||
|
||||
def usage():
|
||||
print '''
|
||||
diff2html.py [-e encoding] [-i file] [-o file] [-x]
|
||||
diff2html.py -h
|
||||
|
||||
Transform a unified diff from stdin to a colored side-by-side HTML
|
||||
page on stdout.
|
||||
stdout may not work with UTF-8, instead use -o option.
|
||||
|
||||
-i file set input file, else use stdin
|
||||
-e encoding set file encoding (default utf-8)
|
||||
-o file set output file, else use stdout
|
||||
-x exclude html header and footer
|
||||
-t tabsize set tab size (default 8)
|
||||
-l linesize set maximum line size is there is no word break (default 20)
|
||||
-r show \\r characters
|
||||
-k show hunk infos
|
||||
-a algo line diff algorithm (0: linediff characters, 1: word, 2: simplediff characters) (default 0)
|
||||
-h show help and exit
|
||||
'''
|
||||
|
||||
def main():
|
||||
global linesize, tabsize
|
||||
global show_CR
|
||||
global encoding
|
||||
global algorithm
|
||||
|
||||
input_file_name = ''
|
||||
output_file_name = ''
|
||||
|
||||
exclude_headers = False
|
||||
show_hunk_infos = False
|
||||
|
||||
try:
|
||||
opts, args = getopt.getopt(sys.argv[1:], "he:i:o:xt:l:rka:",
|
||||
["help", "encoding=", "input=", "output=",
|
||||
"exclude-html-headers", "tabsize=",
|
||||
"linesize=", "show-cr", "show-hunk-infos", "algorithm="])
|
||||
except getopt.GetoptError, err:
|
||||
print unicode(err) # will print something like "option -a not recognized"
|
||||
usage()
|
||||
sys.exit(2)
|
||||
verbose = False
|
||||
for o, a in opts:
|
||||
if o in ("-h", "--help"):
|
||||
usage()
|
||||
sys.exit()
|
||||
elif o in ("-e", "--encoding"):
|
||||
encoding = a
|
||||
elif o in ("-i", "--input"):
|
||||
input_file = codecs.open(a, "r", encoding)
|
||||
input_file_name = a
|
||||
elif o in ("-o", "--output"):
|
||||
output_file = codecs.open(a, "w")
|
||||
output_file_name = a
|
||||
elif o in ("-x", "--exclude-html-headers"):
|
||||
exclude_headers = True
|
||||
elif o in ("-t", "--tabsize"):
|
||||
tabsize = int(a)
|
||||
elif o in ("-l", "--linesize"):
|
||||
linesize = int(a)
|
||||
elif o in ("-r", "--show-cr"):
|
||||
show_CR = True
|
||||
elif o in ("-k", "--show-hunk-infos"):
|
||||
show_hunk_infos = True
|
||||
elif o in ("-a", "--algorithm"):
|
||||
algorithm = int(a)
|
||||
else:
|
||||
assert False, "unhandled option"
|
||||
|
||||
# Use stdin if not input file is set
|
||||
if not ('input_file' in locals()):
|
||||
input_file = codecs.getreader(encoding)(sys.stdin)
|
||||
|
||||
# Use stdout if not output file is set
|
||||
if not ('output_file' in locals()):
|
||||
output_file = codecs.getwriter(encoding)(sys.stdout)
|
||||
|
||||
parse_input(input_file, output_file, input_file_name, output_file_name,
|
||||
exclude_headers, show_hunk_infos)
|
||||
|
||||
def parse_from_memory(txt, exclude_headers, show_hunk_infos):
|
||||
" Parses diff from memory and returns a string with html "
|
||||
input_stream = StringIO.StringIO(txt)
|
||||
output_stream = StringIO.StringIO()
|
||||
parse_input(input_stream, output_stream, '', '', exclude_headers, show_hunk_infos)
|
||||
return output_stream.getvalue()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,487 @@
|
||||
<?xml version="1.0" encoding="US-ASCII"?>
|
||||
<!-- This template is for creating an Internet Draft using xml2rfc,
|
||||
which is available here: http://xml.resource.org. -->
|
||||
<!DOCTYPE rfc SYSTEM "rfc2629.dtd" [
|
||||
<!-- One method to get references from the online citation libraries.
|
||||
There has to be one entity for each item to be referenced.
|
||||
An alternate method (rfc include) is described in the references. -->
|
||||
|
||||
<!ENTITY RFC0793 SYSTEM "http://xml.resource.org/public/rfc/bibxml/reference.RFC.0793.xml">
|
||||
<!ENTITY RFC2119 SYSTEM "http://xml.resource.org/public/rfc/bibxml/reference.RFC.2119.xml">
|
||||
<!ENTITY RFC2474 SYSTEM "http://xml.resource.org/public/rfc/bibxml/reference.RFC.2474.xml">
|
||||
<!ENTITY RFC2629 SYSTEM "http://xml.resource.org/public/rfc/bibxml/reference.RFC.2629.xml">
|
||||
<!ENTITY RFC2998 SYSTEM "http://xml.resource.org/public/rfc/bibxml/reference.RFC.2998.xml">
|
||||
<!ENTITY RFC3552 SYSTEM "http://xml.resource.org/public/rfc/bibxml/reference.RFC.3552.xml">
|
||||
<!ENTITY RFC4340 SYSTEM "http://xml.resource.org/public/rfc/bibxml/reference.RFC.4340.xml">
|
||||
<!ENTITY RFC4960 SYSTEM "http://xml.resource.org/public/rfc/bibxml/reference.RFC.4960.xml">
|
||||
<!ENTITY RFC8569 SYSTEM "http://xml.resource.org/public/rfc/bibxml/reference.RFC.8569.xml">
|
||||
<!ENTITY RFC8609 SYSTEM "http://xml.resource.org/public/rfc/bibxml/reference.RFC.8609.xml">
|
||||
<!ENTITY I-D.moiseenko-icnrg-flowclass SYSTEM "http://xml.resource.org/public/rfc/bibxml3/reference.I-D.moiseenko-icnrg-flowclass.xml">
|
||||
<!ENTITY I-D.ietf-quic-transport SYSTEM "http://xml.resource.org/public/rfc/bibxml3/reference.I-D.ietf-quic-transport.xml">
|
||||
]>
|
||||
<?xml-stylesheet type='text/xsl' href='rfc2629.xslt' ?>
|
||||
<!-- used by XSLT processors -->
|
||||
<!-- For a complete list and description of processing instructions (PIs),
|
||||
please see http://xml.resource.org/authoring/README.html. -->
|
||||
<!-- Below are generally applicable Processing Instructions (PIs) that most I-Ds might want to use.
|
||||
(Here they are set differently than their defaults in xml2rfc v1.32) -->
|
||||
<?rfc strict="yes" ?>
|
||||
<!-- give errors regarding ID-nits and DTD validation -->
|
||||
<!-- control the table of contents (ToC) -->
|
||||
<?rfc toc="yes"?>
|
||||
<!-- generate a ToC -->
|
||||
<?rfc tocdepth="4"?>
|
||||
<!-- the number of levels of subsections in ToC. default: 3 -->
|
||||
<!-- control references -->
|
||||
<?rfc symrefs="yes"?>
|
||||
<!-- use symbolic references tags, i.e, [RFC2119] instead of [1] -->
|
||||
<?rfc sortrefs="yes" ?>
|
||||
<!-- sort the reference entries alphabetically -->
|
||||
<!-- control vertical white space
|
||||
(using these PIs as follows is recommended by the RFC Editor) -->
|
||||
<?rfc compact="yes" ?>
|
||||
<!-- do not start each main section on a new page -->
|
||||
<?rfc subcompact="no" ?>
|
||||
<!-- keep one blank line between list items -->
|
||||
<!-- end of list of popular I-D processing instructions -->
|
||||
|
||||
<rfc category="exp" docName="draft-oran-icnrg-flowbalance-latest" ipr="trust200902">
|
||||
<!-- category values: std, bcp, info, exp, and historic
|
||||
ipr values: full3667, noModification3667, noDerivatives3667
|
||||
you can add the attributes updates="NNNN" and obsoletes="NNNN"
|
||||
they will automatically be output with "(if approved)" -->
|
||||
|
||||
<!-- ***** FRONT MATTER ***** -->
|
||||
<front>
|
||||
<!-- The abbreviated title is used in the page header - it is only necessary if the
|
||||
full title is longer than 39 characters -->
|
||||
<title abbrev="Maintaining Flow Balance">
|
||||
Maintaining CCNx or NDN flow balance with highly variable data object sizes
|
||||
</title>
|
||||
|
||||
<!-- add 'role="editor"' below for the editors if appropriate -->
|
||||
|
||||
<!-- Another author who claims to be an editor -->
|
||||
<author fullname="Dave Oran" surname="D. Oran">
|
||||
<organization>Network Systems Research and Design</organization>
|
||||
<address>
|
||||
<postal>
|
||||
<street>4 Shady Hill Square</street>
|
||||
<!-- Reorder these if your country does things differently -->
|
||||
<city>Cambridge</city>
|
||||
<region>MA</region>
|
||||
<code>02138</code>
|
||||
<country>USA</country>
|
||||
</postal>
|
||||
<phone></phone>
|
||||
<email>daveoran@orandom.net</email>
|
||||
<!-- uri and facsimile elements may also be added -->
|
||||
</address>
|
||||
</author>
|
||||
|
||||
<date month="August" year="2019" />
|
||||
|
||||
<!-- If the month and year are both specified and are the current ones, xml2rfc will fill
|
||||
in the current day for you. If only the current year is specified, xml2rfc will fill
|
||||
in the current day and month for you. If the year is not the current one, it is
|
||||
necessary to specify at least a month (xml2rfc assumes day="1" if not specified for the
|
||||
purpose of calculating the expiry date). With drafts it is normally sufficient to
|
||||
specify just the year. -->
|
||||
|
||||
<!-- Meta-data Declarations -->
|
||||
|
||||
<area>IRTF</area>
|
||||
<workgroup>ICNRG</workgroup>
|
||||
|
||||
<!-- WG name at the upperleft corner of the doc,
|
||||
IETF is fine for individual submissions.
|
||||
If this element is not present, the default is "Network Working Group",
|
||||
which is used by the RFC Editor as a nod to the history of the IETF. -->
|
||||
|
||||
<keyword>template</keyword>
|
||||
|
||||
<!-- Keywords will be incorporated into HTML output
|
||||
files in a meta tag but they have no effect on text or nroff
|
||||
output. If you submit your draft to the RFC Editor, the
|
||||
keywords will be used for the search engine. -->
|
||||
|
||||
<abstract>
|
||||
<t>Deeply embedded in some ICN architectures, especially Named Data Networking (NDN) and Content-Centric Networking (CCNx) is the notion of flow balance. This captures the idea that there is a one-to-one correspondence between requests for data, carried in Interest messages, and the responses with the requested data object, carried in Data messages. This has a number of highly beneficial properties for flow and congestion control in networks, as well as some desirable security properties. For example, neither legitimate users nor attackers are able to inject large amounts of un-requested data into the network.</t>
|
||||
<t>Existing congestion control approaches however cannot deal effectively with a widely varying MTU of ICN data messages, since the protocols allow a dynamic range of 1-64K bytes. Since Interest messages are used to allocate the reverse link bandwidth for returning Data, there is large uncertainty in how to allocate that bandwidth. Unfortunately, current congestion control schemes in CCNx and NDN only count Interest messages and have no idea how much data is involved that could congest the inverse link. This document proposes a method to maintain flow balance by accommodating the wide dynamic range in Data message MTU.</t>
|
||||
<!--This document is a product of the IRTF Information-Centric Networking Research Group (ICNRG). -->
|
||||
</abstract>
|
||||
</front>
|
||||
|
||||
<middle>
|
||||
<section anchor="intro" title="Introduction">
|
||||
<t>Deeply embedded in some ICN architectures, especially Named Data Networking (NDN <xref target="NDN"/>) and Content-Centric Networking (CCNx <xref target="RFC8569"/>,<xref target="RFC8609"/>) is the notion of <spanx>flow balance</spanx>. This captures the idea that there is a one-to-one correspondence between requests for data, carried in Interest messages, and the responses with the requested data object, carried in Data messages. This has a number of highly beneficial properties for flow and congestion control in networks, as well as some desirable security properties. For example, neither legitimate users nor attackers are able to inject large amounts of un-requested data into the network.</t>
|
||||
|
||||
<t>This approach leads to a desire to make the size of the objects carried in Data messages small and near constant, because flow balance can then be kept using simple bookkeeping of how many Interest messages are outstanding. While simple, constraining Data messages to be quite small - usually on the order of a link Maximum Transmission Unit (MTU) - has some constraints and deleterious effects, among which are:
|
||||
<list style="symbols">
|
||||
<t>Such small data objects are inconvenient for many applications; their natural data object sizes can be considerably larger than a link MTU.</t>
|
||||
<t>Applications with truly small data objects (e.g. voice packets in an Internet telephony applications) have no way to communicate that to the network, causing resources to still be allocated for MTU-sized data objects</t>
|
||||
<t>When chunking a larger data object into multiple Data messages, each message has to be individually cryptographically hashed and signed, increasing both computational overhead and overall message header size. The signature can be elided when Manifests are used (by signing the Manifest instead), but the overhead of hashing multiple small messages rather than fewer larger ones remains.</t>
|
||||
</list>
|
||||
</t>
|
||||
|
||||
<t>One approach which helps with the last of these is to employ fragmentation for Data messages larger than the Path MTU (PMTU). such messages are carved into smaller pieces for transmission over the link(s). There are three flavors of fragmentation: end-to-end, hop-by-hop with reassembly at every hop, and hop-by-hop with cut-through of individual fragments. A number of ICN protocol architectures incorporate fragmentation and schemes have been proposed for both NDN and CCNx, for example in <xref target="Ghali2013"/>. Fragmentation alone does not ameliorate the flow balance problem however, since from a resource allocation standpoint both memory and link bandwidth must be set aside for maximum-sized data objects to avoid congestion collapse under overload.</t>
|
||||
|
||||
<t>The design space considered in this document does not however extend to arbitrarily large objects (e.g. 100's of kilobytes or larger). As the dynamic range of data object sizes gets very large, finding the right tradeoff between handling a large number of small data objects versus a single very large data object when allocating link and buffer resources becomes intractable. Further, the semantics of Interest-Data exchanges means that any error in the exchange results in a re-issue of an Interest for the entire Data object. Very large data objects represent a performance problem because the cost of retransmission when Interests are retransmitted (or re-issued) becomes unsustainably high. Therefore, the method we propose deals with a dynamic range of object sizes from very small (a fraction of a link MTU) to moderately large - about 64 kilobytes or equivalently about 40 Ethernet packets, and assumes an associated fragmentation scheme to handle link MTUs that cannot carry the object in a single link-layer packet.</t>
|
||||
|
||||
<t>The approach described in the rest of this document maintains flow balance under the conditions outlined above by allocating resources accurately based on expected data object size, rather than employing simple interest counting.</t>
|
||||
</section>
|
||||
|
||||
<section title="Requirements Language">
|
||||
<t>The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
|
||||
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
|
||||
document are to be interpreted as described in <xref
|
||||
target="RFC2119">RFC 2119</xref>.</t>
|
||||
</section>
|
||||
|
||||
<section anchor="description" title="Method to enhance congestion control with signaled size information in Interest Messages">
|
||||
|
||||
<t>Before diving into the specifics of the design, it is useful to consider how congestion control works in NDN/CCNx. Unlike the IP protocol family, which relies on end-to-end congestion control (e.g. TCP<xref target="RFC0793"/>, DCCP<xref target="RFC4340"/>, SCTP<xref target="RFC4960"/>, QUIC<xref target="I-D.ietf-quic-transport"/>), CCNx and NDN employ hop-by-hop congestion control. There is per-Interest/Data state at every hop of the path and therefore for each outstanding Interest, bandwidth for data returning on the inverse path can be allocated. In the current design, this allocation is done using simple Interest counting - by accepting one Interest packet from an downstream node, implicitly this provides a guarantee (either hard or soft) that there is sufficient bandwidth on the inverse direction of the link to send back one Data packet. A number of congestion control schemes have been developed that operate in this fashion, for example <xref target="Wang2013"/>,<xref target="Mahdian2016"/>,<xref target="Song2018"/>,<xref target="Carofiglio2012"/>. Other schemes, like <xref target="Schneider2016"/> neither count nor police interests, but instead monitor queues using AQM (active queue management) to mark returning Data packets that have experienced congestion. It is worth noting that every congestion control algorithm has an explicit fairness goal and associated objective function (usually either <xref target="minmaxfairness"/> or <xref target="proportionalfairness"/>). If your fairness is to be based on resource usage, pure interest counting doesn't do the trick, since a consumer asking for large thing can saturate a link and shift loss to consumers asking for small things.</t>
|
||||
|
||||
<t>In order to deal with a larger dynamic range of data object size, some means is required to allocate link bandwidth for data messages in bytes with an upper bound larger than a link PMTU and a lower bound lower than a single link MTU. Since resources are allocated for returning Data based on arriving Interests, this information must be available in Interest messages.</t>
|
||||
|
||||
<t>Therefore, one key idea is the inclusion of an <spanx>expected data size</spanx> TLV in each Interest message. This allows each forwarder on the path taken by the interest to accurately allocate bandwidth on the inverse path for the returning Data message. Also, by including the expected data size, large objects will have a corresponding weight in resource allocation, maintaining link and forwarder buffering fairness. The simpler Interest counting scheme was nominally "fair" on a per-exchange basis within the variations of data that fit in a single PMTU packet because all Interests produced similar amounts of data in return. In the absence of such a field, it is not feasible to allow a large dynamic range in object size. While schemes like <xref target="Schneider2016"/> would not employ the expected data size to allocate reverse link bandwidth, they can still benefit from the information to affect the AQM congestion marking algorithm, preferentially marking data packets that exceed the expected data size.</t>
|
||||
|
||||
|
||||
<section anchor="prediction" title="How to predict the size of returning Data messages">
|
||||
|
||||
<t>This of course raises the question "How does the requester know how big the corresponding data coming back will be?". For a number of important applications, the size is known a priori due to the characteristics of the application. Here are some examples:
|
||||
|
||||
<list style="symbols">
|
||||
<t>For many sensor and other Internet-of-Things applications, the data is instrument readings which have fixed known size.</t>
|
||||
<t>In video streaming, the data is output of a video encoder which produces variable sized frames. This information is typically made available ahead of time to the streaming clients in the form of a Manifest [4], which contains the names of the corresponding segments (or individual frames) of video and audio and their sizes.</t>
|
||||
<t>Internet telephony applications use vocoders that typically employ fixed-size audio frames. Therefore, their size is known either a priori, or via an initialization exchange at the start of an audio session.</t>
|
||||
</list>
|
||||
|
||||
The more complex cases arise where the data size is not known at the time the Interest must be sent. Much of the nuance of the proposed scheme is in how mismatches between the expected data size and the actual data object returned are handled. The consumer can either under- or over-estimate the data size. In the former case, the under-estimate can lead to congestion and possible loss of data. In the latter case, bandwidth that could have been used by data objects requested by other consumers might be wasted. We first consider "honest" mis-estimates due to imperfect knowledge by the ICN application; later we consider malicious applications that are using the machinery to mount some form of attack. We also consider the effects of Interest aggregation if the aggregated Interests have differing expected data sizes. Also, it should be obvious that if the Data message arrives, the application learns its actual size, which may or may not be useful in adjusting the expected data size estimate for future Interests.</t>
|
||||
|
||||
<t>In all cases, the expected data size from the Interest can be incorporated in the corresponding Pending Interest Table (PIT) entry of each CCNx/NDN forwarder on the path and hence when a (possibly fragmented) Data object comes back, its total size is known and can be compared to the expected size in the PIT for a mismatch. Aside: In the case of fragmentation, we assume a fragmentation scheme in which the total data size can be known as soon as any one fragment is received (a reasonable assumption for most any well-designed fragmentation method).</t>
|
||||
|
||||
</section>
|
||||
|
||||
<section anchor="toobig" title="Handling `too big' cases">
|
||||
<t>If the returning data is larger than the expected data size, the extra data could result in either unfair bandwidth allocation or possibly data loss under congestion conditions. When this is detected, the forwarder has three choices:
|
||||
|
||||
<list style="numbers">
|
||||
<t>It could forward the data anyway, which is safe under non-congestion conditions, but unfair and possibly unstable when the output link is congested</t>
|
||||
<t>It could forward the data when un-congested (e.g. by assessing output queue depth) but drop it when congested</t>
|
||||
<t>It could always drop the data, as a way of "punishing" the requester for the mis-estimate.</t>
|
||||
</list>
|
||||
Either of the latter two strategies is acceptable from a congestion control point of view. However, it is not a good idea to simply drop the Data message with no feedback to the issuer of the Interest because the application has no way to learn the actual data size and retry. Further, recovery would be delayed until the failing Interest timed out. Therefore, an additional element needed in protocol semantics is the incorporation of a "Data too big" error message (via an "interest Return" packet in CCNx).</t>
|
||||
|
||||
<t>Upon dropping data as above, the CCNx/NDN forwarder converts the normal Data message into an Interest Return message containing the with the T_MTU_TOO_LARGE error code and the actual size of the data object instead of the data object content. It propagates that back toward the client identically to how the original Data message would have been handled. Subsequent nodes upon receiving the T_MTU_TOO_LARGE error treat it as all other Interest Return errors. When the Interest Return eventually arrives back to the issuer of the Interest, the user can, they desire, reissue the Interest with the correct expected data size.</t>
|
||||
|
||||
<t>One detail to note is that an Interest Return carrying T_MTU_TOO_LARGE must be deterministically smaller than the expected data size in all cases. This is clearly the case for large data objects, but there is a corner case with small data objects. There has to be a minimum expected data size that a client can specify in their Interests, and that minimum cannot be smaller than the size of a T_MTU_TOO_LARGE Interest Return</t>
|
||||
</section>
|
||||
|
||||
<section anchor="toosmall" title="Handling `too small' cases">
|
||||
<t>Next we consider the case where the returning data is smaller than the expected data size. While this case does not result in congestion, it can cause resources to be inefficiently allocated because not all of the set-aside bandwidth for the returning data object gets used. The simplest and most straightforward way to deal with this case is to essentially ignore it. The motivation for not worrying about the smaller data mismatch is that in many situations that employ usage-based resource measurement (and possibly charging), it is trivial to just account for the usage according to the larger expected data size rather than actual returned data size. Properly adjusting congestion control parameters to somehow penalize users for over-estimating their resource usage requires fairly heavyweight machinery, which in most cases is not warranted. If desired, any of the following mechanisms could be considered:
|
||||
<list style="symbols">
|
||||
<t>Attempt to identify future Interests for the same object or closely related objects and allocate resources based on some retained state about the actual size of prior objects</t>
|
||||
<t>Police consumer behavior and decrease the expected data size in one or more future Interests to compensate</t>
|
||||
<t>For small objects, do more optimistic resource allocation on the links on the presumption that there will be some "slack" due to clients overestimating data object size.</t>
|
||||
</list>
|
||||
|
||||
One protocol detail of CCNx/NDN that needs to be dealt with is Interest Aggregation. This happens when multiple Interests arrive at a forwarder for the same Named object. These are aggregated such that one of them (i.e.the first to arrive and create PIT state) is forwarded, and the rest are dropped while marking the arrival face so the data can be sent back to the multiple requesting clients. Interest aggregation interacts with expected data size if Interests from different clients contain different values of the expected data size. As above, the simplest solution to this problem is to ignore it, as most error cases are benign. However, there is one problematic error case where one client provides an accurate expected data size, but another who issued the Interest first underestimates, causing both to receive a Data too big error. This introduces a denial of service vulnerability, which we discuss below together with the other malicious actor cases.</t>
|
||||
</section>
|
||||
|
||||
<section anchor="aggregation" title="Interactions with Interest Aggregation">
|
||||
<t>Interest Aggregation, while a powerful feature for maintaining flow balance when multiple consumers send Interests for the same Named object, introduces subtle complications. Whenever a second or subsequent Interest arrives at a forwarder with an active PIT entry it is possible that those Interests carry different parameters, for example hop limit, payload, etc. It is therefore necessary to specify the exact behavior of the forwarder for each of the parameters that might differ. In the case of the expected data size parameter defined here, the value is associated with the ingress face on which the Interest creating the PIT entry arrived, as opposed to being global to the PIT entry as a whole. There are two cases to consider:
|
||||
<list style="numbers">
|
||||
<t>The arriving interest carries an expected data size smaller than any of the values associated with the PIT entry.</t>
|
||||
<t>The arriving interest carries an expected data size larger than any of the values associated with the PIT entry.</t>
|
||||
</list>
|
||||
</t>
|
||||
|
||||
<t>For Case (1) the Interest can be safely aggregated since the upstream links will have sufficient bandwidth allocated based on the larger expected data size (assuming the original Interest's expected data size was itself sufficiently large to accommodate the actual size of the returning Data. On the other hand, should the incoming face have bandwidth allocated based on the larger existing Interest's expected data size, or on the smaller value in the arriving interest? Here there are two possible approaches:
|
||||
|
||||
<list style="letters">
|
||||
<t>Allocate based on the data size already in the PIT. In this case the consumer sending the earlier Interest can cause over-allocation of link bandwidth for other incoming faces, but there will not be a T_MTU_TOO_LARGE error generated for that Interest</t>
|
||||
<t>Allocate based on the value in the arriving Interest. If the returning Data is in fact larger, generate a T_MTU_TOO_LARGE Interest Return on that ingress face, while successfully returning the Data message on any faces that do not exhibit a too small expected data size</t>
|
||||
</list>
|
||||
|
||||
It is RECOMMENDED that the second policy be followed. The reasons behind this recommendation are as follows:
|
||||
<list style="numbers">
|
||||
<t>The link can be congested quite quickly after the queuing decision is made, especially if the data has a long link-occupancy time, so this is a safer alternative.</t>
|
||||
<t>The cost of returning the error is only one link RTT, since the consumer (or downstream forwarder) can immediately re-issue the interest with the correct size and pick up the cached object from the upstream forwarder's Content Store.</t>
|
||||
<t>Being optimistic and returning the data interacts with the behavior of aggregate resource control and resource accounting, which in turn raises the messy issue of whether to "charge" the consumer for the actual bandwidth used or only for the requested bandwidth in the expected data.</t>
|
||||
<t>The rabbit hole goes deeper if you add differential QoS to the equation or consumers "playing games" and intentionally underestimating so their interests get satisfied when links aren't congested. This makes handling malicious actors (<xref target="malicious"/>) more difficult.</t>
|
||||
</list>
|
||||
</t>
|
||||
|
||||
<t>For Case (2) above, the Interest MUST be forwarded rather than aggregated to prevent a consumer from mounting a denial of service attack by sending intentionally too small expected data size (see <xref target="malicious"/> for additional detail on this and other attacks). As above for Case (1) it is RECOMMENDED that policy (b) above be followed.
|
||||
</t>
|
||||
|
||||
</section>
|
||||
|
||||
<section anchor="compatibility" title="Operation when some Interests lack the expected data size option and some have it">
|
||||
<t>Since the expected data size hop-by-hop option forwarders need to be prepared to handle an arbitrary mix of the two forms. There are two general things to address. </t>
|
||||
|
||||
<t>First, we assume that any forwarder supporting expected data size is running a more sophisticated congestion control algorithm that one employing simple interest counting. The link bandwidth resource allocation is therefore based directly, or indirectly, on the expected Data size in bytes. Therefore, the forwarder has to assign a value to use in the resource allocation for the reverse link. This specification does not mandate any particular approach or a default value to use. However, in the absence on other guidance, it makes sense to do one of two things:
|
||||
<list style="numbers">
|
||||
<t>Pick a default based on the link MTU of the face on which the Interest arrived and use that for all Interests lacking an expected data size. This is likely to be most compatible with simple interest counting which would rate limit all incoming interests equally</t>
|
||||
<t>Configure some values for given Name prefixes that have known sizes. This may be appropriate for dedicated forwarders supporting single use cases, such as:
|
||||
<list style="symbols">
|
||||
<t>A forwarder handling IoT sensors sending very small Data packets</t>
|
||||
<t>A forwarder handling real-time video with large average Data packets that exceed link MTU and are routinely fragmented</t>
|
||||
<t>A forwarder doing voice trunking where the vocoders produce moderate sized packets, still much smaller than the link MTU</t>
|
||||
</list>
|
||||
</t>
|
||||
</list>
|
||||
</t>
|
||||
|
||||
<t>The second area to address is what to do if an interest lacking an expected Data size is responded to by a Data message whose size exceeds the default discussed above. It would be inappropriate to issue a T_MTU_TOO_LARGE error, since the consumer is unlikely to understand or deal correctly with that new error case. Instead, it is RECOMMENDED that the forwarder:
|
||||
<list style="symbols">
|
||||
<t>Ignore the mismatch if the reverse link is not congested and return the requested Data message anyway.</t>
|
||||
<t>If the reverse link is congested, issue an Interest Return with the T_NO_RESOURCES error code</t>
|
||||
</list>
|
||||
This specification does not define or recommend any particular algorithm for assessing the congestion state of the link(s) to carry the Data message downstream to the requesting consumers. It is assumed that a reasonable algorithm is in use, because otherwise even basic Interest counting forms of congestion control would not be effective.
|
||||
</t>
|
||||
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section anchor="malicious" title="Dealing with malicious actors">
|
||||
<t>First we note that various known attacks in CCNx or NDN can also be mounted by users employing this method. Attacks that involve interest flooding, cache pollution, cache poisoning, etc. are neither worsened nor ameliorated by the introduction of the congestion control capabilities described here. However, there are two new vulnerabilities that need to be dealt with. These two new vulnerabilities involve intentional mis-estimation of data size.</t>
|
||||
|
||||
<t>The first is a consumer who intentionally over-estimates data size with the goal of preventing other users from using the bandwidth. This is at most a minor concern given the above discussion of over-estimation by honest clients. If one of the amelioration techniques above are used, the case of malicious over-estimation is also dealt with adequately.</t>
|
||||
|
||||
<t>The second is a user who intentionally under-estimates the data size with the goal having its Interest processed while the other aggregated interests are not processed, thereby causing T_MTU_TOO_LARGE errors and denying service to the other users with overlapping requests. There are a number of possible mitigation techniques for this attack vector, ranging in complexity. We outline two below; there may be others as or more effective with acceptable complexity and overhead:
|
||||
|
||||
<list style="symbols">
|
||||
<t>(Simplest) A user sending Interests resulting in a T_MTU_TOO_LARGE error is treated similarly to users mounting interest flooding attacks; the a router aggregating Interests with differing expected data sizes rate limits the face(s) exhibiting these errors, thus decreasing the ability of a user to issue enough mis-estimated Interests to collide and generate Interest aggregation.</t>
|
||||
|
||||
<t>An ICN forwarder aggregating Interests remembers in the PIT entry not only the expected data size of the Interest it forwarded, but the maximum of the expected data size of the other Interests it aggregated. If a T_MTU_TOO_LARGE error comes back, instead of propagating it, the forwarder MAY treat this as a transient error, drop the Interest Return, and re-forward the Interest using the maximum expected data size in the PIT (assuming it is is bigger). This recovers from the error, but the attacker can still cause an extra round trip to the producer or to an upstream forwarder with a copy of the data in its Content Store.</t>
|
||||
</list>
|
||||
</t>
|
||||
</section>
|
||||
|
||||
<section anchor="encoding" title="Mapping to CCNx and NDN packet encodings">
|
||||
<t>The only actual protocol needed is a TLV in Interest messages that states the size in bytes of the expected Data Message coming back, and in the Interest Return on a "too big" error to carry the actual data size. In the case of CCNx, this covers the encapsulated Data Object, but not the hop-by-hop headers.</t>
|
||||
|
||||
<section anchor="CCNx-encoding" title="Packet encoding for CCNx">
|
||||
<t>For CCNx<xref target="RFC8569"/> there is a new hop-by-hop header TLV, and a new value of the Interest Return "Return Type".</t>
|
||||
<texttable anchor="DataSize" title="Data Size TLV">
|
||||
<preamble>Expected Data Size (for Interest messages), or Actual Data Size (for Interest Return messages) TLV</preamble>
|
||||
<ttcol align="center">Abbrev</ttcol>
|
||||
<ttcol align="center">Name</ttcol>
|
||||
<ttcol align="center">Description</ttcol>
|
||||
<c>T_DATASIZE</c>
|
||||
<c>Data Size</c>
|
||||
<c>Expected (<xref target="description"/>)or Actual (<xref target="toobig"/>) Data Size</c>
|
||||
</texttable>
|
||||
|
||||
<!-- <texttable anchor="toobigerror" title="TOOBIG Interest Return error code">
|
||||
<preamble>Too Big Return type for Interest Return Message</preamble>
|
||||
<ttcol align="center">Return Type</ttcol>
|
||||
<ttcol align="center">Name</ttcol>
|
||||
<c>T_RETURN_TOOBIG</c>
|
||||
<c>Data is bigger than expected data size in Interest Message</c>
|
||||
</texttable>
|
||||
-->
|
||||
|
||||
</section>
|
||||
|
||||
<section anchor="NDN-encoding" title="Packet encoding for NDN">
|
||||
<t>TBD based on <xref target="NDNTLV"/>. Suggestions from the NDN team greatly appreciated.</t>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<!-- This PI places the pagebreak correctly (before the section title) in the text output. -->
|
||||
<!--<?rfc needLines="8" ?>-->
|
||||
<!-- Possibly a 'Contributors' section ... -->
|
||||
|
||||
<section anchor="IANA" title="IANA Considerations">
|
||||
<t>Please Add the T_TIMETLV TLV to the Hop-by-Hop TLV types registry of RFC8609, with fixed length of 2, and data type numeric</t>
|
||||
<figure anchor="timetlv-encoding" title="Compresssed Time Values using RFC4574 encoding">
|
||||
<preamble>Expected/Actual Data Size TLV encoding. The range has an upper bound of 64K bytes, since that is the largest MTU supported by CCNx.</preamble>
|
||||
<artwork align="left"><![CDATA[
|
||||
1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+---------------+---------------+---------------+---------------+
|
||||
| T_TIMETLV | 2 |
|
||||
+---------------+---------------+---------------+---------------+
|
||||
| INTERVAL_TIME (see RFC4574) |
|
||||
+---------------+---------------+
|
||||
]]></artwork>
|
||||
</figure>
|
||||
|
||||
<!-- <t>Please add the T_RETURN_TOOBIG error to the Interest Return types registry</t>
|
||||
<texttable title="CCNx Interest Return Type for Too Big Errors">
|
||||
<ttcol align="center">Type</ttcol>
|
||||
<ttcol align="center">Name</ttcol>
|
||||
<ttcol align="center">Reference</ttcol>
|
||||
|
||||
<c>TBA</c>
|
||||
<c>T_RETURN_TOO_BIG</c>
|
||||
<c><xref target="toobigerror">Too Big Error Code</xref></c>
|
||||
</texttable>
|
||||
-->
|
||||
</section>
|
||||
|
||||
<section anchor="Security" title="Security Considerations">
|
||||
<t>
|
||||
</t>
|
||||
</section>
|
||||
|
||||
</middle>
|
||||
|
||||
<!-- *****BACK MATTER ***** -->
|
||||
|
||||
<back>
|
||||
<!-- References split into informative and normative -->
|
||||
|
||||
<!-- There are 2 ways to insert reference entries from the citation libraries:
|
||||
1. define an ENTITY at the top, and use "ampersand character"RFC2629; here (as shown)
|
||||
2. simply use a PI "less than character"?rfc include="reference.RFC.2119.xml"?> here
|
||||
(for I-Ds: include="reference.I-D.narten-iana-considerations-rfc2434bis.xml")
|
||||
|
||||
Both are cited textually in the same manner: by using xref elements.
|
||||
If you use the PI option, xml2rfc will, by default, try to find included files in the same
|
||||
directory as the including file. You can also define the XML_LIBRARY environment variable
|
||||
with a value containing a set of directories to search. These can be either in the local
|
||||
filing system or remote ones accessed by http (http://domain/dir/... ).-->
|
||||
|
||||
<references title="Normative References">
|
||||
<!--?rfc include="http://xml.resource.org/public/rfc/bibxml/reference.RFC.2119.xml"?-->
|
||||
&RFC2119;
|
||||
&RFC8569;
|
||||
&RFC8609;
|
||||
</references>
|
||||
|
||||
<references title="Informative References">
|
||||
&RFC0793;
|
||||
<!-- &RFC2474; -->
|
||||
<!-- &RFC2998; -->
|
||||
&RFC4340;
|
||||
&RFC4960;
|
||||
&I-D.ietf-quic-transport;
|
||||
|
||||
<reference anchor="Ghali2013" target="http://dx.doi.org/10.1109/NCA.2015.34">
|
||||
<front>
|
||||
<title>Secure Fragmentation for Content-Centric Networks, in IEEE 14th International Symposium on Network Computing and Applications</title>
|
||||
<author surname="Ghali" initials="C."/>
|
||||
<author surname="Narayanan" initials="A."/>
|
||||
<author surname="Oran" initials="D."/>
|
||||
<author surname="Tsudik" initials="G."/>
|
||||
<author surname="Wood" initials="C."/>
|
||||
<date year="2015"/>
|
||||
</front>
|
||||
<seriesInfo name="DOI" value="10.1109/nca.2015.34"/>
|
||||
</reference>
|
||||
|
||||
<reference anchor="Mahdian2016" target="http://conferences2.sigcomm.org/acm-icn/2016/proceedings/p1-mahdian.pdf">
|
||||
<front>
|
||||
<title>MIRCC: Multipath-aware ICN Rate-based Congestion Control, in Proceedings of the 3rd ACM Conference on Information-Centric Networking</title>
|
||||
<author surname="Mahdian" initials="M."/>
|
||||
<author surname="Arianfar" initials="S."/>
|
||||
<author surname="Gibson" initials="J."/>
|
||||
<author surname="Oran" initials="D."/>
|
||||
<date year="2016"/>
|
||||
</front>
|
||||
<seriesInfo name="DOI" value="10.1145/2984356.2984365"/>
|
||||
</reference>
|
||||
|
||||
<reference anchor="Carofiglio2012" target="http://conferences.sigcomm.org/sigcomm/2012/paper/icn/p37.pdf">
|
||||
<front>
|
||||
<title>Joint hop-by-hop and receiver-driven interest control protocol for content-centric networks, in ICN Workshop at SIGcomm 2012</title>
|
||||
<author surname="Carofiglio" initials="G."/>
|
||||
<author surname="Gallo" initials="M."/>
|
||||
<author surname="Muscariello" initials="L."/>
|
||||
<date year="2102"/>
|
||||
</front>
|
||||
<seriesInfo name="DOI" value="10.1145/2377677.2377772"/>
|
||||
</reference>
|
||||
|
||||
<reference anchor="Wang2013" target="http://conferences.sigcomm.org/sigcomm/2013/papers/icn/p55.pdf">
|
||||
<front>
|
||||
<title>
|
||||
An Improved Hop-by-hop Interest Shaper for Congestion Control in Named Data Networking, in ACM SIGCOMM Workshop on Information-Centric Networking
|
||||
</title>
|
||||
<author surname="Wang" initials="Y."></author>
|
||||
<author surname="Rozhnova" initials="N."></author>
|
||||
<author surname="Narayanan" initials="A."></author>
|
||||
<author surname="Oran" initials="D."></author>
|
||||
<author surname="Rhee" initials="I."></author>
|
||||
<date year="2013"></date>
|
||||
</front>
|
||||
<seriesInfo name="DOI" value="10.1145/2534169.2491233"/>
|
||||
</reference>
|
||||
|
||||
<reference anchor="Song2018" target="https://conferences.sigcomm.org/acm-icn/2018/proceedings/icn18-final62.pdf">
|
||||
<front>
|
||||
<title>SMIC: Subflow-level Multi-path Interest Control for Information Centric Networking, in 5th ACM Conference on Information-Centric Networking</title>
|
||||
<author surname="Song" initials="J."/>
|
||||
<author surname="Lee" initials="M."/>
|
||||
<author surname="Kwon" initials="T."/>
|
||||
<date year="2018"/>
|
||||
</front>
|
||||
<seriesInfo name="DOI" value="10.1145/3267955.3267971"/>
|
||||
</reference>
|
||||
|
||||
<reference anchor="Schneider2016" target="http://conferences2.sigcomm.org/acm-icn/2016/proceedings/p21-schneider.pdf">
|
||||
<front>
|
||||
<title>A Practical Congestion Control Scheme for Named Data Networking, in Proceedings of the 2016 conference on 3rd ACM Conference on Information-Centric Networking - ACM-ICN '16</title>
|
||||
<author surname="Schneider" initials="K."/>
|
||||
<author surname="Yi" initials="C."/>
|
||||
<author surname="Zhang" initials="B."/>
|
||||
<author surname="Zhang" initials="L."/>
|
||||
<date year="2016"/>
|
||||
</front>
|
||||
<seriesInfo name="DOI" value="10.1145/2984356.2984369"/>
|
||||
</reference>
|
||||
|
||||
|
||||
<!-- <reference anchor="Pursuit" target="https://www.fp7-pursuit.eu">
|
||||
<front>
|
||||
<title>The Pursuit Project</title>
|
||||
<author surname="FP7"/>
|
||||
<date year="2015"/>
|
||||
</front>
|
||||
</reference>
|
||||
-->
|
||||
|
||||
<reference anchor="NDN" target="https://named-data.net/project/execsummary/">
|
||||
<front>
|
||||
<title>Named Data Networking</title>
|
||||
<author surname="NDN team"/>
|
||||
<date year="various"/>
|
||||
</front>
|
||||
</reference>
|
||||
|
||||
<reference anchor="NDNTLV" target="http://named-data.net/doc/ndn-tlv/">
|
||||
<front>
|
||||
<title>NDN Packet Format Specification.</title>
|
||||
<author surname="NDN Project Team"/>
|
||||
<date year="2016" />
|
||||
</front>
|
||||
</reference>
|
||||
|
||||
<reference anchor="minmaxfairness" target="https://en.wikipedia.org/wiki/Max-min_fairness">
|
||||
<front>
|
||||
<title>Max-min Fairness</title>
|
||||
<author surname="Wikipedia"/>
|
||||
<date year="various"/>
|
||||
</front>
|
||||
</reference>
|
||||
|
||||
<reference anchor="proportionalfairness" target="https://en.wikipedia.org/wiki/Proportionally_fair">
|
||||
<front>
|
||||
<title>Proportionally Fair</title>
|
||||
<author surname="Wikipedia"/>
|
||||
<date year="various"/>
|
||||
</front>
|
||||
</reference>
|
||||
|
||||
</references>
|
||||
|
||||
<!-- Change Log
|
||||
v00 2019-07-13 DRO Initial version
|
||||
v01 2019-08-10 DRO Respond to comments by Naveen Nathan and Klaus Schneider
|
||||
-->
|
||||
</back>
|
||||
</rfc>
|
||||
@@ -0,0 +1 @@
|
||||
This project is in the public domain; your contributions need to be too.
|
||||
@@ -0,0 +1 @@
|
||||
This project is in the public domain.
|
||||
@@ -0,0 +1,22 @@
|
||||
# Internet Draft Template Repository
|
||||
|
||||
The contents of this repository can be used to get started with a new internet
|
||||
draft.
|
||||
|
||||
This tool provides many
|
||||
[features](https://github.com/martinthomson/i-d-template/blob/master/doc/FEATURES.md).
|
||||
|
||||
# Getting Started
|
||||
|
||||
You need a [GitHub account](https://github.com/join).
|
||||
|
||||
Make sure you have the [necessary software
|
||||
installed](https://github.com/martinthomson/i-d-template/blob/master/doc/SETUP.md).
|
||||
|
||||
[Setup your
|
||||
repository](https://github.com/martinthomson/i-d-template/blob/master/doc/REPO.md).
|
||||
|
||||
Work.
|
||||
|
||||
[Submit the final
|
||||
product](https://github.com/martinthomson/i-d-template/blob/master/doc/SUBMITTING.md).
|
||||
@@ -0,0 +1,3 @@
|
||||
\~~</body>~ { i\
|
||||
<div class="github-fork-ribbon-wrapper"><div class="github-fork-ribbon"><a href="https://github.com/{SLUG}">Fork me on GitHub</a></div></div>
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/<style[^>]*>/,/<\/style>/{
|
||||
/<style[^>]*>/{
|
||||
h
|
||||
s/<style[^>]*>.*//
|
||||
p
|
||||
i\
|
||||
<style type="text/css">/*<![CDATA[*/
|
||||
# Unfortunately, r appends after the current line. If the end of the style
|
||||
# pattern is on this line, then this will mean that the end of the line
|
||||
# will appear before the style. That's terrible. See below.
|
||||
r lib/style.css
|
||||
a\
|
||||
/*]]>*/</style>
|
||||
a\
|
||||
<meta name="viewport" content="initial-scale=1.0">
|
||||
g
|
||||
}
|
||||
# Save the last line for later.
|
||||
/<\/style>/h
|
||||
d
|
||||
}
|
||||
# This recovers a saved line and prints it.
|
||||
x
|
||||
/<\/style>/{
|
||||
s/.*<\/style>//
|
||||
p
|
||||
}
|
||||
x
|
||||
@@ -0,0 +1,125 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Usage: $0 [dir] [gh-user] [gh-repo] > index.html
|
||||
|
||||
hash realpath 2>/dev/null || function realpath() { cd "$1"; pwd -P; }
|
||||
|
||||
master=${GITHUB_MASTER:-master}
|
||||
root=$(realpath "${1:-.}")
|
||||
branch="${2:-$master}"
|
||||
user="${3:-<user>}"
|
||||
repo="${4:-<repo>}"
|
||||
|
||||
gh="https://github.com/${user}/${repo}"
|
||||
|
||||
indent=''
|
||||
function p() {
|
||||
echo -n "$indent";echo "$@"
|
||||
}
|
||||
function pi() {
|
||||
p "$@"
|
||||
indent="$indent "
|
||||
}
|
||||
function po() {
|
||||
indent="${indent# }"
|
||||
p "$@"
|
||||
}
|
||||
|
||||
p '<!DOCTYPE html>'
|
||||
pi '<html>'
|
||||
pi '<head>'
|
||||
p '<title>'"$user/$repo $branch"' preview</title>'
|
||||
p '<meta name="viewport" content="initial-scale=1.0">'
|
||||
pi '<style type="text/css">/*<![CDATA[*/'
|
||||
p 'body { font-family: "Helvetica Neue","Open Sans",Helvetica,Calibri,sans-serif; }'
|
||||
p 'h1, h2, td { font-family: "Helvetica Neue","Roboto Condensed","Open Sans",Helvetica,Calibri,sans-serif; }'
|
||||
p 'h1 { font-size: 20px; } h2 { font-size: 16px; }'
|
||||
p 'table { margin: 5px 10px; border-collapse: collapse; }'
|
||||
p 'th, td { font-weight: normal; text-align: left; padding: 2px 5px; }'
|
||||
p 'a:link { color: #000; } a:visited { color: #00a; }'
|
||||
po '/*]]>*/</style>'
|
||||
po '</head>'
|
||||
pi '<body>'
|
||||
|
||||
function rfcdiff() {
|
||||
echo "https://tools.ietf.org/rfcdiff?url1=${1}&url2=${2}"
|
||||
}
|
||||
|
||||
function reldot() {
|
||||
[ "$1" = "$root" ] && echo '.' || echo "${1/$root\//}"
|
||||
}
|
||||
|
||||
function githubio() {
|
||||
d="${1%/}/"
|
||||
echo "https://${user}.github.io/${repo}/${d#master/}${2}.txt"
|
||||
}
|
||||
|
||||
function list_dir() {
|
||||
pi '<table id="branch-'"$2"'">'
|
||||
for file in "$1"/*.txt; do
|
||||
dir=$(dirname "$file")
|
||||
file=$(basename "$file" .txt)
|
||||
|
||||
pi '<tr>'
|
||||
p '<th>'"${file}"'</th>'
|
||||
p '<td><a href="'"$(reldot "$dir")/${file}"'.html"'
|
||||
p ' class="html '"$file"'">html</a></td>'
|
||||
p '<td><a href="'"$(reldot "$dir")/${file}"'.txt"'
|
||||
p ' class="txt '"$file"'">plain text</a></td>'
|
||||
this_githubio=$(githubio "$branch${dir#$root}" "$file")
|
||||
if [ "$2" != "$master" ]; then
|
||||
diff=$(rfcdiff $(githubio "$master/" "$file") "$this_githubio")
|
||||
p '<td><a href='"$diff"'>diff with '"$master"'</a></td>'
|
||||
fi
|
||||
diff=$(rfcdiff "https://tools.ietf.org/id/${file}.txt" "$this_githubio")
|
||||
p '<td><a href="'"$diff"'" class="diff '"$file"'">'
|
||||
p ' diff with last submission</a></td>'
|
||||
po '</tr>'
|
||||
done
|
||||
po '</table>'
|
||||
}
|
||||
|
||||
branchlink="$gh"
|
||||
[ "$branch" = "$master" ] || branchlink="${branchlink}/tree/${branch}"
|
||||
p "<h1>Editor's drafts for ${branch} branch of <a href=\"${branchlink}\">${user}/${repo}</a></h1>"
|
||||
p "<p>View <a href=\"issues.html\">saved issues</a>,"
|
||||
p " or the latest GitHub <a href=\"${gh}/issues\">issues</a>"
|
||||
p " and <a href=\"${gh}/pulls\">pull requests</a>.</p>"
|
||||
|
||||
list_dir "${root}" $branch
|
||||
|
||||
for dir in $(find "${root}" -mindepth 1 -type d \( -name '.*' -prune -o -print \)); do
|
||||
dirbranch="${dir#$root/}"
|
||||
p '<h2>Preview for branch <a href="'"$dirbranch"'">'"$dirbranch"'</a></h2>'
|
||||
list_dir "$dir" "$dirbranch"
|
||||
done
|
||||
|
||||
pi '<script>'
|
||||
cat <<EOJS
|
||||
// @licstart
|
||||
// Any copyright is dedicated to the Public Domain.
|
||||
// http://creativecommons.org/publicdomain/zero/1.0/
|
||||
// @licend
|
||||
window.onload = function() {
|
||||
var referrer_branch = 'master';
|
||||
// e.g., "https://github.com/user/repo/tree/master"
|
||||
var chunks = document.referrer.split("/");
|
||||
if (chunks[2] === 'github.com' && chunks[5] === 'tree') {
|
||||
referrer_branch = chunks[6];
|
||||
}
|
||||
let branch = document.querySelector('#branch-' + referrer_branch);
|
||||
let h = document.location.hash.substring(1);
|
||||
if (h === 'show') {
|
||||
document.location.hash = '#' + branch.id;
|
||||
} else if (branch && h.startsWith('go')) {
|
||||
let e = branch.querySelector(h.substring(2));
|
||||
if (e && e.href) {
|
||||
document.location = e.href;
|
||||
}
|
||||
}
|
||||
};
|
||||
EOJS
|
||||
po '</script>'
|
||||
|
||||
po '</body>'
|
||||
po '</html>'
|
||||
@@ -0,0 +1,96 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build extra targets for make. This includes targets that are a little tricky
|
||||
# to build. This includes all versions of the draft other than the latest: all
|
||||
# tagged versions and the next version for submission. As a result, it also
|
||||
# includes diffs.
|
||||
|
||||
# Usage: $0 <tagfile> <outputfile> [drafts ...]
|
||||
|
||||
drafts=("$@")
|
||||
candidates=$((${#drafts[@]} * 5))
|
||||
|
||||
next() {
|
||||
printf "${1%-*}-%2.2d" $((1${1##*-} - 99))
|
||||
}
|
||||
|
||||
print_sed() {
|
||||
noop_cmd="$1"
|
||||
sed_cmd="$2"
|
||||
shift 2
|
||||
if [ $# -gt 0 ]; then
|
||||
printf "$sed_cmd"
|
||||
else
|
||||
printf "$noop_cmd"
|
||||
fi
|
||||
for s in "$@"; do
|
||||
printf " -e '$s'"
|
||||
done
|
||||
}
|
||||
|
||||
# This builds a make target for a specific tag.
|
||||
build_target() {
|
||||
tag="$1"
|
||||
target_name="$2"
|
||||
source_file=
|
||||
subst=()
|
||||
for file in $(git ls-tree --name-only "$tag" | grep '^draft-'); do
|
||||
if [ "${file%.*}" = "${target_name%-*}" ]; then
|
||||
source_file="$file"
|
||||
file_tag="$target_name"
|
||||
else
|
||||
# This is the last tag for the identified file at the tag we're
|
||||
# interested in.
|
||||
prev_file_tag=$(git describe --candidates="$candidates" --tags \
|
||||
--match "${file%.*}-*" --abbrev=0 "$tag" 2>/dev/null)
|
||||
|
||||
# No previous: -00, building for HEAD: next, otherwise use tag.
|
||||
if [ -z "$prev_file_tag" ]; then
|
||||
file_tag="${file%.*}-00"
|
||||
elif [ "$tag" = HEAD ]; then
|
||||
file_tag=$(next "$prev_file_tag")
|
||||
else
|
||||
file_tag="$prev_file_tag"
|
||||
fi
|
||||
fi
|
||||
subst+=("s/${file%.*}-latest/${file_tag}/g")
|
||||
done
|
||||
|
||||
if [ -z "$source_file" ]; then
|
||||
echo "warning: No file found at revision $tag for $target_name" 1>&2
|
||||
return
|
||||
fi
|
||||
|
||||
target="${target_name}.${source_file##*.}"
|
||||
if [ "$tag" == HEAD ]; then
|
||||
printf "${target}: ${source_file}\n"
|
||||
printf "\t"
|
||||
print_sed cat sed "${subst[@]}"
|
||||
printf " \$< >\$@\n"
|
||||
else
|
||||
printf ".INTERMEDIATE: ${target}\n"
|
||||
printf "${target}:\n"
|
||||
printf "\tgit show \"$tag:$source_file\""
|
||||
print_sed '' ' | sed' "${subst[@]}"
|
||||
printf " >\$@\n"
|
||||
fi
|
||||
}
|
||||
|
||||
for draft in "${drafts[@]%.*}"; do
|
||||
tags=($(git tag --list "${draft}-[0-9][0-9]"))
|
||||
for i in "${tags[@]}"; do
|
||||
build_target "$i" "$i"
|
||||
done
|
||||
|
||||
if [ "${#tags[@]}" -gt 0 ]; then
|
||||
next_draft=$(next "${tags[$((${#tags[@]}-1))]}")
|
||||
else
|
||||
next_draft="${draft}-00"
|
||||
fi
|
||||
build_target HEAD "$next_draft"
|
||||
|
||||
if [ "${#tags[@]}" -gt 0 ]; then
|
||||
# Write out a diff target
|
||||
printf "diff-${draft}.html: ${tags[$((${#tags[@]}-1))]}.txt ${next_draft}.txt\n"
|
||||
printf "\t-\$(rfcdiff) --html --stdout \$^ > \$@\n"
|
||||
fi
|
||||
done
|
||||
@@ -0,0 +1,27 @@
|
||||
machine:
|
||||
environment:
|
||||
GOPATH: "${HOME}/${CIRCLE_PROJECT_REPONAME}/.go_workspace"
|
||||
mmark_src: github.com/miekg/mmark/mmark
|
||||
mmark: ./mmark
|
||||
PATH: ${PATH}:~/bats/bin
|
||||
KRAMDOWN_REFCACHEDIR: "${HOME}/${CIRCLE_PROJECT_REPONAME}/.refcache"
|
||||
python:
|
||||
version: 3.5.2
|
||||
|
||||
checkout:
|
||||
post:
|
||||
|
||||
dependencies:
|
||||
pre:
|
||||
- pip install xml2rfc behave
|
||||
- gem install --no-doc kramdown-rfc2629
|
||||
- go get "$mmark_src" && go build "$mmark_src"
|
||||
cache_directories:
|
||||
- "/opt/circleci/.rvm/gems"
|
||||
|
||||
test:
|
||||
override:
|
||||
- behave --junit --junit-directory $CIRCLE_TEST_REPORTS/cucumber/:
|
||||
parallel: true
|
||||
files:
|
||||
- tests/*.feature
|
||||
@@ -0,0 +1,46 @@
|
||||
# The following tools are used by this file.
|
||||
# All are assumed to be on the path, but you can override these
|
||||
# in the environment, or command line.
|
||||
|
||||
# Mandatory:
|
||||
# https://pypi.python.org/pypi/xml2rfc
|
||||
xml2rfc ?= xml2rfc -q
|
||||
|
||||
# If you are using markdown files use either kramdown-rfc2629 or mmark
|
||||
# https://github.com/cabo/kramdown-rfc2629
|
||||
kramdown-rfc2629 ?= kramdown-rfc2629
|
||||
|
||||
# mmark (https://github.com/miekg/mmark)
|
||||
mmark ?= mmark
|
||||
|
||||
# If you are using outline files:
|
||||
# https://github.com/Juniper/libslax/tree/master/doc/oxtradoc
|
||||
oxtradoc ?= oxtradoc.in
|
||||
|
||||
# When using rfc2629.xslt extensions:
|
||||
# https://greenbytes.de/tech/webdav/rfc2629xslt.html
|
||||
xsltproc ?= xsltproc
|
||||
|
||||
# For sanity checkout your draft:
|
||||
# https://tools.ietf.org/tools/idnits/
|
||||
idnits ?= idnits
|
||||
|
||||
# For diff:
|
||||
# https://tools.ietf.org/tools/rfcdiff/
|
||||
rfcdiff ?= rfcdiff
|
||||
|
||||
# For generating PDF:
|
||||
# https://www.gnu.org/software/enscript/
|
||||
enscript ?= enscript
|
||||
# http://www.ghostscript.com/
|
||||
ps2pdf ?= ps2pdf
|
||||
|
||||
# Where to get references
|
||||
XML_RESOURCE_ORG_PREFIX ?= https://xml2rfc.tools.ietf.org/public/rfc
|
||||
|
||||
# This is for people running macs
|
||||
SHELL := bash
|
||||
|
||||
# For uploading draft "releases" to the datatracker.
|
||||
curl ?= curl -sS
|
||||
DATATRACKER_UPLOAD_URL ?= https://datatracker.ietf.org/api/submit
|
||||
@@ -0,0 +1,77 @@
|
||||
# Adopting a Draft
|
||||
|
||||
When a working group adopts an individual draft that was created with this
|
||||
template, the obvious ways of migrating a repository to a different organization
|
||||
are often not great.
|
||||
|
||||
Firstly, **do not create a fork**. There are better options.
|
||||
|
||||
|
||||
## Best Option - Transfer the Repository
|
||||
|
||||
A transfer means that all the pull requests, issues and any CI configuration are moved
|
||||
in addition to the code (the drafts).
|
||||
|
||||
To do this, make the owner of the repository part of the working group organization.
|
||||
You need to give them the ability to create repositories in order for this to be
|
||||
allowed.
|
||||
|
||||
The owner of the repository can go to the settings tab for the repository and transfer.
|
||||
This can be found at the very bottom of the page, in the "Danger Zone".
|
||||
|
||||
See the [GitHub instructions for transferring repositories](https://help.github.com/articles/about-repository-transfers/).
|
||||
|
||||
|
||||
## Alternative - Copy History
|
||||
|
||||
In case you can't transfer, you can copy the history of the old repository into
|
||||
a new repository. For this, you don't need any special roles, just the ability
|
||||
to push to the new repository. This won't copy or move issues or pull requests.
|
||||
|
||||
Make a new repository. Make sure that it is empty when you make it (don't
|
||||
create a README when GitHub asks). Then make a new repository locally:
|
||||
|
||||
```sh
|
||||
$ git init new-repo
|
||||
$ cd new-repo
|
||||
$ git remote add origin https://github.com/new-owner/new-repo
|
||||
```
|
||||
|
||||
Then pull the contents of the old repo in:
|
||||
|
||||
```sh
|
||||
$ git pull https://github.com/old-owner/old-repo master
|
||||
$ git push
|
||||
```
|
||||
|
||||
You then need to setup the `gh-pages` and `gh-issues`
|
||||
branches:
|
||||
|
||||
```sh
|
||||
$ make
|
||||
$ make -f lib/setup.mk setup-ghpages setup-ghissues
|
||||
```
|
||||
|
||||
|
||||
## Cleanup
|
||||
|
||||
After transfering or copying you might want to rebuild the README:
|
||||
|
||||
```sh
|
||||
$ make -f lib/setup.mk README.md
|
||||
$ git commit -m "Update README" README.md
|
||||
```
|
||||
|
||||
If you have made changes to the README, you can just update the intro text and
|
||||
the links.
|
||||
|
||||
Any copies of the repository should have any clone that references the old
|
||||
location updated. The old location will continue to work, but it's good pratice
|
||||
to change:
|
||||
|
||||
```sh
|
||||
$ git remote set-url origin https://github.com/new/repo
|
||||
```
|
||||
|
||||
You should also update any CI configuration and links to your repo from other
|
||||
places.
|
||||
@@ -0,0 +1,79 @@
|
||||
# What This Project Can Do
|
||||
|
||||
```sh
|
||||
$ make
|
||||
```
|
||||
|
||||
Turn internet-draft source into text and HTML. This supports XML files using
|
||||
[xml2rfc](https://xml2rfc.tools.ietf.org/), markdown files using either
|
||||
[kramdown-rfc2629](https://github.com/cabo/kramdown-rfc2629) or
|
||||
[mmark](https://github.com/miekg/mmark)
|
||||
|
||||
```sh
|
||||
$ make diff
|
||||
```
|
||||
|
||||
Show changes since your last draft submission using
|
||||
[rfcdiff](https://tools.ietf.org/tools/rfcdiff/).
|
||||
|
||||
```sh
|
||||
$ make gh-pages
|
||||
```
|
||||
|
||||
Update the `gh-pages` branch with the latest edits. [GitHub
|
||||
pages](https://pages.github.com/) make your changes available on the web.
|
||||
|
||||
This builds a HTML index that links to HTML and text copies of all drafts on all
|
||||
branches, plus links for showing changes with the most recent draft submission.
|
||||
Files for old branches are retained for one month after the branch is deleted,
|
||||
then cleaned up the next time this process runs.
|
||||
|
||||
```sh
|
||||
$ git tag -a draft-ietf-unicorn-protocol-02
|
||||
$ make upload
|
||||
```
|
||||
|
||||
Upload tagged changes to the IETF datatracker using the
|
||||
[API](https://datatracker.ietf.org/api/submit).
|
||||
|
||||
```sh
|
||||
$ make lint
|
||||
$ make fix-lint
|
||||
```
|
||||
|
||||
Check for common formatting errors like trailing whitespace and automatically
|
||||
fix them.
|
||||
|
||||
The lint check and a check that drafts build correctly is installed as a git
|
||||
hook so that it runs before each commit.
|
||||
|
||||
```sh
|
||||
$ make idnits
|
||||
```
|
||||
|
||||
Check for nits using the [idnits](https://tools.ietf.org/tools/idnits/) tool.
|
||||
|
||||
```sh
|
||||
$ make issues
|
||||
```
|
||||
|
||||
Download a copy of GitHub issues and pull requests.
|
||||
|
||||
|
||||
## Setup a Repository
|
||||
|
||||
When you [setup a repository](REPO.md), this tool installs a stub `Makefile`.
|
||||
It also creates the following files from a template: `.gitignore`,
|
||||
`CONTRIBUTING.md`, `LICENSE.md`, `.travis.yml`, and `.circleci/config.yml`.
|
||||
|
||||
|
||||
## With Continuous Integration Services
|
||||
|
||||
Using [circleci](http://circleci.com/) or [travis](https://travis-ci.org/)
|
||||
[configured](REPO.md#automatic-update-for-editors-copy) you can:
|
||||
|
||||
* Check that commits and pull requests for errors.
|
||||
* Automatically maintain your `gh-pages` branch.
|
||||
* Automatically save a copy of GitHub issues and pull requests to the repository
|
||||
for offline access. This includes a simple HTML viewer.
|
||||
* Automatically submit tagged versions of drafts to the IETF datatracker.
|
||||
@@ -0,0 +1,163 @@
|
||||
# Working Group Setup
|
||||
|
||||
Make a [new organization](https://github.com/organizations/new) for your working
|
||||
group. This guide will use the name `unicorn-wg` for your working group.
|
||||
|
||||
There is a [more detailed
|
||||
guide](https://github.com/martinthomson/i-d-template/blob/master/doc/WG-SETUP.md)
|
||||
for working groups.
|
||||
|
||||
# New Draft Setup
|
||||
|
||||
If you are more familiar with git and GitHub, try the [fast setup](#fast-setup).
|
||||
|
||||
[Make a new repository](https://github.com/new). This guide will use the
|
||||
name `unicorn-protocol` in examples.
|
||||
|
||||
When prompted, select the option to initialize the repository with a README.
|
||||
|
||||
Clone that repository:
|
||||
```sh
|
||||
$ git clone https://github.com/unicorn-wg/unicorn-protocol.git
|
||||
$ cd unicorn-protocol
|
||||
```
|
||||
|
||||
Choose whether you want to use markdown, outline, or xml as your input format.
|
||||
If you already have a draft, then that decision is already made for you.
|
||||
|
||||
Make a draft file in the root of the repo. The name of the file is important; make
|
||||
it match the name of your draft. Don't include a version number in the name. Our
|
||||
example would be `draft-ietf-unicorn-protocol.md` in markdown.
|
||||
|
||||
You can copy of one of the examples files
|
||||
([markdown](https://github.com/martinthomson/i-d-template/blob/master/doc/example.md) or
|
||||
[XML](https://github.com/martinthomson/i-d-template/blob/master/doc/example.xml))
|
||||
if you are starting from scratch.
|
||||
|
||||
Edit the draft so that it has both a title and the correct name. These tools
|
||||
uses the `-latest` suffix in place of the usual number ('-00', or '-08'). The
|
||||
number is generated automatically when you use `make submit`.
|
||||
|
||||
In XML, you should have at least:
|
||||
```xml
|
||||
<rfc docName="draft-ietf-unicorn-protocol-latest">
|
||||
<front>
|
||||
<title>The Unicorn Protocol</title>
|
||||
```
|
||||
|
||||
Markdown is similar:
|
||||
```yaml
|
||||
docname: draft-ietf-unicorn-protocol-latest
|
||||
title: The Unicorn Protocol
|
||||
```
|
||||
|
||||
Add, commit and push your changes:
|
||||
```sh
|
||||
$ git add draft-ietf-unicorn-protocol.md
|
||||
$ git commit draft-ietf-unicorn-protocol.md
|
||||
$ git push
|
||||
```
|
||||
|
||||
Clone a copy of this repository into place:
|
||||
|
||||
```sh
|
||||
$ git clone https://github.com/martinthomson/i-d-template lib
|
||||
```
|
||||
|
||||
*Option:* If you prefer a stable version of this code, you can use `git submodule`
|
||||
instead.
|
||||
|
||||
Run the setup command:
|
||||
|
||||
```sh
|
||||
$ make -f lib/setup.mk
|
||||
```
|
||||
|
||||
*Option:* If you prefer to use [Julian Reschke's
|
||||
XSLT](https://github.com/reschke/xml2rfc) for generating HTML, add
|
||||
`USE_XSLT=true` to the setup command line.
|
||||
|
||||
The setup removes adds some files, updates `README.md` with the details of
|
||||
your draft, sets up a `gh-pages` branch for your editor's copy. This pushes
|
||||
the `gh-pages` branch to `origin`. If you don't want that, run `make -f
|
||||
lib/setup.mk setup-master` instead.
|
||||
|
||||
Finally, push:
|
||||
|
||||
```sh
|
||||
$ git push
|
||||
```
|
||||
|
||||
|
||||
# Fast Setup
|
||||
|
||||
For the brave, or those who are more familiar with git. This is the process I
|
||||
follow. Make a new repository on GitHub, but don't initialize it with a
|
||||
README. Then:
|
||||
|
||||
```sh
|
||||
$ git init unicorn-protocol
|
||||
$ cd unicorn-protocol
|
||||
$ git remote add origin https://github.com/unicorn-wg/unicorn-protocol
|
||||
# Copy a template in place, change the filename and title.
|
||||
$ git commit -m "Initial version blah blah blah" draft-*.{md,xml}
|
||||
$ git push -u origin master
|
||||
$ git clone https://github.com/martinthomson/i-d-template lib
|
||||
$ make -f lib/setup.mk
|
||||
$ git push
|
||||
```
|
||||
|
||||
|
||||
# Updating The Editor's Copy
|
||||
|
||||
Github will serve any HTML you check in on the `gh-pages` branch. This can be
|
||||
useful for ensuring that the latest version of your draft is available in a
|
||||
usable form.
|
||||
|
||||
You can maintain `gh-pages` manually by running the following command
|
||||
occasionally.
|
||||
|
||||
```sh
|
||||
$ make ghpages
|
||||
```
|
||||
|
||||
When you do that, you will need to push the `gh-pages` branch yourself.
|
||||
|
||||
Or, you can setup an automatic commit hook using Circle or Travis CI, as described
|
||||
in the next section.
|
||||
|
||||
|
||||
# Automatic Update for Editor's Copy
|
||||
|
||||
Manual maintenance of `gh-pages` means that it will always be out of date. You can
|
||||
use an integrated continuous integration system to maintain a copy.
|
||||
|
||||
This requires that you sign in with [Circle](https://circleci.com/) or
|
||||
[Travis](https://travis-ci.org/).
|
||||
|
||||
First [enable builds for the new repository](https://circleci.com/add-projects)
|
||||
(or on [Travis](https://travis-ci.org/profile), though Travis might need to be
|
||||
refreshed before you can see your repository).
|
||||
|
||||
Then, you need to get yourself a [new GitHub application
|
||||
token](https://github.com/settings/tokens/new). The application token only
|
||||
needs the `public_repo` privilege. This will let it push updates to your
|
||||
`gh-pages` branch.
|
||||
|
||||
You can add environment variables using the Travis or Circle interface. Make
|
||||
a variable with the name `GH_TOKEN` and the value of your newly-created
|
||||
application token. On Travis, make sure to leave the value of "Display value in
|
||||
build log" disabled, or you will be making your token public.
|
||||
|
||||
**WARNING**: You might want to use a dummy account for application tokens to
|
||||
minimize the consequences of accidental leaks of your key.
|
||||
|
||||
Once you enable pushes, be very careful merging pull requests that alter
|
||||
`circle.yml`, `.travis.yml`, or `Makefile`. Those files can cause the value of
|
||||
the token to be published for all to see. You don't want that to happen. Even
|
||||
though tokens can be revoked easily, discovering a leak might take some time.
|
||||
Only pushes to the main repository will be able to see the token, so don't worry
|
||||
about pull requests.
|
||||
|
||||
Circle (or Travis) will now also check pull requests for errors, letting you
|
||||
know if things didn't work out so that you don't merge anything suspect.
|
||||
@@ -0,0 +1,104 @@
|
||||
# Installation and Setup
|
||||
|
||||
At a minimum, you need `make` and `xml2rfc`.
|
||||
|
||||
|
||||
## make
|
||||
|
||||
Mac users might need to install [Homebrew](https://brew.sh) to get a version of
|
||||
[`make`](https://www.gnu.org/software/make/) that works properly (the version
|
||||
shipped in XCode is subtly broken).
|
||||
|
||||
```sh
|
||||
brew install --with-default-names make
|
||||
```
|
||||
|
||||
Windows users will need to use [Cygwin](http://cygwin.org/) or [the Windows
|
||||
Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/install-win10)
|
||||
to get `make`.
|
||||
|
||||
|
||||
## xml2rfc
|
||||
|
||||
All systems require [xml2rfc](http://xml2rfc.tools.ietf.org/). This
|
||||
requires [Python](https://www.python.org/). The easiest way to get
|
||||
`xml2rfc` is with [pip](https://pip.pypa.io/en/stable/installing/), which
|
||||
is either installed with python, or part of the `python-pip` package
|
||||
on most distributions.
|
||||
|
||||
On Cygwin, you'll need to install `pip` directly:
|
||||
|
||||
```sh
|
||||
$ curl https://bootstrap.pypa.io/get-pip.py | python
|
||||
```
|
||||
|
||||
Once pip is installed, you can install xml2rfc.
|
||||
|
||||
Using a `virtualenv`:
|
||||
|
||||
```sh
|
||||
$ virtualenv --no-site-packages venv
|
||||
# remember also to activate the virtualenv before any 'make' run
|
||||
$ source venv/bin/activate
|
||||
$ pip install xml2rfc
|
||||
```
|
||||
|
||||
To your local user account:
|
||||
|
||||
```sh
|
||||
$ pip install --user xml2rfc
|
||||
```
|
||||
|
||||
Or globally (not advisable):
|
||||
|
||||
```sh
|
||||
$ sudo pip install xml2rfc
|
||||
```
|
||||
|
||||
xml2rfc might need development versions of [libxml2](http://xmlsoft.org/) and
|
||||
[libxslt1](http://xmlsoft.org/XSLT). These packages are named `libxml2-dev` and
|
||||
`libxslt1-dev` (Debian, Ubuntu); `libxml2-devel` and `libxslt1-devel` (RedHat,
|
||||
Fedora); or `libxml2-devel` and `libxslt-devel` (Cygwin).
|
||||
|
||||
|
||||
## Markdown
|
||||
|
||||
If you use markdown, you will also need to install `kramdown-rfc2629` or `mmark`.
|
||||
|
||||
The template stuff tries to work out which of these you are working with based
|
||||
on the first line of the file:
|
||||
|
||||
* `kramdown-rfc2629` files must start with '---'
|
||||
|
||||
* `mmark` files must start with '%%%'
|
||||
|
||||
## kramdown-rfc2629
|
||||
|
||||
[`kramdown-rfc2629`](https://github.com/cabo/kramdown-rfc2629) requires
|
||||
[Ruby](https://www.ruby-lang.org/) and can be installed using the Ruby package
|
||||
manager, `gem`:
|
||||
|
||||
```sh
|
||||
$ gem install kramdown-rfc2629
|
||||
```
|
||||
|
||||
|
||||
## mmark
|
||||
|
||||
[`mmark`](https://github.com/miekg/mmark) requires [go](https://golang.org/), and that comes with its
|
||||
own complications.
|
||||
|
||||
```sh
|
||||
cd ~/bin
|
||||
go get github.com/miekg/mmark/mmark
|
||||
go build github.com/miekg/mmark/mmark
|
||||
```
|
||||
|
||||
You might want to set aside a directory for your go code other than the default,
|
||||
and find a directory that is on the path where you can install `mmark`. For
|
||||
these, I set `GOPATH=~/gocode`.
|
||||
|
||||
|
||||
## Other tools
|
||||
|
||||
Some other helpful tools are listed in `config.mk`.
|
||||
@@ -0,0 +1,106 @@
|
||||
# Submitting Drafts
|
||||
|
||||
Occasionally, you will want to submit versions of your draft to the official
|
||||
IETF repository. The automated process is recommended.
|
||||
|
||||
|
||||
## Automated Process
|
||||
|
||||
If you have enabled continuous integration, the CI system can automatically
|
||||
upload a draft to the datatracker. All you have to do is tag the repository,
|
||||
push the tag, and await an email with further instructions.
|
||||
|
||||
```sh
|
||||
$ git tag -a draft-ietf-unicorn-protocol-03
|
||||
$ git push origin <branchname>
|
||||
$ git push origin draft-ietf-unicorn-protocol-03
|
||||
```
|
||||
|
||||
This tag has to include the full name of the draft without any file extension.
|
||||
That name has to include a revision number. The tag also has to match the name
|
||||
of the source file. For the above example, the source for the draft needs to
|
||||
be either `draft-ietf-unicorn-protocol.md` or
|
||||
`draft-ietf-unicorn-protocol.xml`.
|
||||
|
||||
For this feature to work you also need to use an annotated tag (that's the `-a`
|
||||
option above). Annotated tags require a comment (use `-m` to set this on the
|
||||
command line). An annotated tag associates your email address with the
|
||||
submission. Lightweight tags don't have an email address and will be ignored
|
||||
by the CI build.
|
||||
|
||||
**Important**: Push the commit that you intend to tag before you push the tag
|
||||
to check that the draft can be built correctly. Pushing the tag won't also
|
||||
push the commit it references and so the build will not run. Circle (and maybe
|
||||
Travis) will then refuse to build that tag ever again.
|
||||
|
||||
**Note**: The email address you use for making this submission needs to match a
|
||||
valid datatracker account email address ([create one
|
||||
here](https://datatracker.ietf.org/accounts/create/)). The email address must
|
||||
also match one of the author addresses (this condition [might be
|
||||
temporary](https://trac.tools.ietf.org/tools/ietfdb/ticket/2390)). The email
|
||||
address that git uses can be found by calling `git config --get user.email`, if
|
||||
you aren't certain.
|
||||
|
||||
**Note**: Existing users will need to update their configuration to take
|
||||
advantage of this feature. For Circle CI users, adding
|
||||
[.circleci/config.yml](https://github.com/martinthomson/i-d-template/blob/master/template/.circleci/config.yml)
|
||||
to your repository and removing any existing `circle.yml` file is recommended.
|
||||
[Travis
|
||||
support](https://github.com/martinthomson/i-d-template/blob/master/template/.travis.yml)
|
||||
is less well-tested (and slower). Updating the
|
||||
[Makefile](https://github.com/martinthomson/i-d-template/blob/master/template/Makefile)
|
||||
provides a small additional speed improvement.
|
||||
|
||||
**Bug**: Circle CI has a [bug](https://support.circleci.com/hc/en-us/articles/115013854347-Jobs-builds-not-triggered-when-pushing-tag)
|
||||
that prevents `git push --tags` from triggering builds if you have multiple drafts.
|
||||
Tag every draft, then push each tag individually. (Tagging all drafts first means
|
||||
that cross references will work.)
|
||||
|
||||
Once the CI system has built the draft, it will upload it automatically and you
|
||||
will receive an email asking you to confirm submission. You don't need to have
|
||||
a GitHub account token configured for this feature to be enabled.
|
||||
|
||||
|
||||
## Semi-automated Process
|
||||
|
||||
Rather than rely on the CI system, the `make upload` command can be used to
|
||||
upload a tagged draft to the datatracker.
|
||||
|
||||
```sh
|
||||
$ git tag -a draft-ietf-unicorn-protocol-03
|
||||
$ git push origin draft-ietf-unicorn-protocol-03
|
||||
$ make upload
|
||||
```
|
||||
|
||||
This uses the same process as the CI system. Note that if you have multiple
|
||||
tags pointing to the current HEAD, this will attempt to upload all of those
|
||||
drafts.
|
||||
|
||||
|
||||
## Manual Process
|
||||
|
||||
Make a submission version of your draft. The makefile uses git tags to work out
|
||||
what version to create. It looks for the last version number you have tagged
|
||||
the draft with and calculates the next version. When there are no tags, it
|
||||
generates a `-00` version.
|
||||
|
||||
```sh
|
||||
$ make submit
|
||||
```
|
||||
|
||||
If you already have a tag in place or want to build a specific tag, you can
|
||||
identify the specific XML file directly.
|
||||
|
||||
```sh
|
||||
$ make draft-ietf-unicorn-protocol-03.xml
|
||||
```
|
||||
|
||||
[Submit the .xml file](https://datatracker.ietf.org/submit/).
|
||||
|
||||
Then you can tag your repository and upload the tags. The tag you should
|
||||
use is the full draft name including a revision number.
|
||||
|
||||
```sh
|
||||
$ git tag -a draft-ietf-unicorn-protocol-03
|
||||
$ git push origin draft-ietf-unicorn-protocol-03
|
||||
```
|
||||
@@ -0,0 +1,63 @@
|
||||
## When Creating Pull Requests on Another Repository
|
||||
|
||||
Make the `origin` remote point to two different places. Pull from the "main"
|
||||
repository, and push to your own fork. Like this:
|
||||
|
||||
```sh
|
||||
$ git clone https://github.com/tlswg/tls13-spec tls13
|
||||
$ cd tls13
|
||||
$ git remote set-url --push origin https://github.com/martinthomson/tls13-spec
|
||||
$ git remote -v
|
||||
origin https://github.com/tlswg/tls13-spec (fetch)
|
||||
origin https://github.com/martinthomson/tls13-spec (push)
|
||||
```
|
||||
|
||||
Now when you pull, you will pull from the "main" repository, but pushes go to
|
||||
your private branch.
|
||||
|
||||
If you work on multiple machines and use push and pull to synchronize, you can
|
||||
setup another remote for your fork, or just pull or fetch directly by
|
||||
specifying the full remote name:
|
||||
|
||||
```sh
|
||||
$ git pull https://github.com/martinthomson/tls13-spec master
|
||||
$ git fetch https://github.com/martinthomson/tls13-spec
|
||||
```
|
||||
|
||||
|
||||
## Cleaning Old Branches
|
||||
|
||||
If you work on many pull requests over time, you will create many branches.
|
||||
Even if you delete the branch on GitHub, your local repository can have lots
|
||||
of dead branches. The following creates a command, `git trim` that prunes
|
||||
branches that have been merged.
|
||||
|
||||
```sh
|
||||
$ git config --global alias.trim '!f() { git branch --merged @ | sed -e '"'"'/^\*/d;s/^ //;/^\('"'"'$(git config --get trim.savebranch | sed -e '"'"'s/[, ]/\\|/g'"'"')'"'"'\)$/d'"'"' | xargs -r git branch -d; }; f'
|
||||
$ git config --global trim.savebranch master,gh-pages,gh-issues
|
||||
```
|
||||
|
||||
The `trim.savebranch` config item includes the names of branches that you
|
||||
want to keep always.
|
||||
|
||||
|
||||
## No Unnecessary Merges on Pull
|
||||
|
||||
When you pull, git can decide to merge for you if your branch has diverged.
|
||||
This can be annoying to recover from. Setting the following configuration
|
||||
ensures that you don't create merge commits when you pull:
|
||||
|
||||
```sh
|
||||
$ git config --global pull.ff only
|
||||
```
|
||||
|
||||
Now when you pull, your local changes will be rebased onto remote changes.
|
||||
|
||||
|
||||
## When Using kramdown-rfc2629
|
||||
|
||||
Set `KRAMDOWN_REFCACHEDIR` in your environment to `~/.cache/xml2rfc`. If you
|
||||
have multiple repositories, this means that you only have a single global
|
||||
cache. You will download the references for RFC 2119 far less often. Also,
|
||||
this is where `xml2rfc` caches references, so both tools will prime the cache
|
||||
for the other.
|
||||
@@ -0,0 +1,57 @@
|
||||
# Setting up Github for an IETF WG
|
||||
|
||||
* The unit of Github is a repository.
|
||||
* Repositories are owned by individuals or organizations
|
||||
* The mapping to IETF concepts is:
|
||||
* repository <-> draft(s)
|
||||
* organization <-> WG
|
||||
* There an [IETF organization](https://github.com/ietf), but it's just a shell that maintains pointers to WGs
|
||||
|
||||
The starting point for setting up a WG / I-D is here:
|
||||
https://github.com/martinthomson/i-d-template
|
||||
|
||||
# Prerequisites
|
||||
|
||||
* A web browser
|
||||
* A Github account
|
||||
* A git client. Command-line is best, and we'll assume that below. You can probably accomplish the same thing with a GUI git client, but it will be much harder. You can get a client at <http://git-scm.com/downloads>
|
||||
* Tools to "compile" your draft, for which there are instructions here: <https://github.com/martinthomson/i-d-template/blob/master/doc/SETUP.md>
|
||||
|
||||
# Setting up an organization
|
||||
|
||||
As that document linked above says, the first thing to do is to click the link and set up a new organization. You will need to choose an organization name and provide a "billing" email (even though you'll use the free version). The normal pattern for organization names is $WGNAME-wg, e.g., "rtcweb-wg". For the billing email, it's simplest just to put in the email that goes with your Github account.
|
||||
|
||||
Then you'll be prompted to invite other people to the organization. You should add your co-chair, and maybe the responsible AD. We'll talk about authors further down, when we talk about repositories. Click "Finish", and your organization will be created.
|
||||
|
||||
Once your organization has been created, you can access it under the "Organizations" section of your Github home page, or at <https://github.com/$ORGNAME>, for example <https://github.com/rtcweb-wg>.
|
||||
|
||||
|
||||
# Setting up a repository for a document
|
||||
|
||||
If you go to your organization's page (i.e., the WG's page), then there's a big green button in the middle that says "New Repository". Click it!
|
||||
|
||||
The repository name should be the draft name, without the "draft-ietf-wg" part; that's redundant with the rest of the URL. So for example, if you were creating draft-ietf-unicorn-tears, the repository name would simply be "tears". You can leave the "Description" field blank or fill in a brief description; it's just Github eye candy. Choose "Public" for the visibility level (transparency!). Finally, make sure that the "Initialize this repository with a README" check box is checked (this will simplify things down the road).
|
||||
|
||||
Click "Create Repository", and now you have a repo!
|
||||
|
||||
|
||||
# Allowing people to contribute to a document
|
||||
|
||||
In order to keep things orderly, only certain people can commit to a document's repository (or "push" in the git lingo). The owners of the organization have push privileges by default (that's the chairs and AD you added earlier). You will need to set the permissions to allow the document author to push to the repository.
|
||||
|
||||
This is done by adding authors to a "team" that can push to this repository. Back on your organization page, find the tab that says "Teams". Hit the "New Team" button. Choose a name, such as "$REPOSITORY_NAME editors" (this name is not publicly visible to anyone but you). Select "Write Access" so that editors can push. Then, find the search box that says "Add a person" (top right) and add the Github user ids of the editors of the draft. This will send the authors an invitation that they will need to accept.
|
||||
|
||||
Protip: If you have regular contributors to the working group, it might pay to create another group with "Read Access" for those contributors. This allows you to assign tasks to those people in the Github UI, and makes other user-related functions more accessible.
|
||||
|
||||
|
||||
# Initializing the repository with a document
|
||||
|
||||
Since we're talking about a WG document here, we'll assume you've already got an XML or Markdown file that represents the draft. We will set up the repo to contain that document, along with some tooling that makes it easy to "compile" the document into RFC format.
|
||||
|
||||
WARNING: THIS IS THE PART THAT REQUIRES A COMMAND LINE.
|
||||
|
||||
Full instructions for initializing the repository are [here](https://github.com/martinthomson/i-d-template/blob/master/REPO.md).
|
||||
|
||||
In essence, what you're doing is copying over the tooling from a template repository, and then creating the Internet-Draft either from your existing source file, or from a template. Both XML and Markdown are supported as the draft source. (There is also experimental support for the [outline2xml](https://github.com/martinthomson/i-d-template/pull/2) format, which has been used for netconf drafts.)
|
||||
|
||||
Once you've got your draft populated, just use "make" to create HTML- and TXT-formatted versions Internet-Draft.
|
||||
@@ -0,0 +1,64 @@
|
||||
---
|
||||
title: TODO - Your title
|
||||
abbrev: TODO - Abbreviation
|
||||
docname: draft-todo-your-name-here
|
||||
category: info
|
||||
|
||||
ipr: trust200902
|
||||
area: General
|
||||
workgroup: TODO Working Group
|
||||
keyword: Internet-Draft
|
||||
|
||||
stand_alone: yes
|
||||
pi: [toc, sortrefs, symrefs]
|
||||
|
||||
author:
|
||||
-
|
||||
ins: "H. Tschofenig"
|
||||
name: "Hannes Tschofenig"
|
||||
organization: "Arm Limited"
|
||||
email: hannes.tschofenig@arm.com
|
||||
|
||||
normative:
|
||||
RFC2119:
|
||||
|
||||
informative:
|
||||
|
||||
|
||||
|
||||
--- abstract
|
||||
|
||||
TODO Abstract
|
||||
|
||||
--- middle
|
||||
|
||||
# Introduction
|
||||
|
||||
TODO Introduction
|
||||
|
||||
|
||||
# Conventions and Definitions
|
||||
|
||||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD",
|
||||
"SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this
|
||||
document are to be interpreted as described in BCP 14 {{RFC2119}} {{!RFC8174}}
|
||||
when, and only when, they appear in all capitals, as shown here.
|
||||
|
||||
|
||||
# Security Considerations
|
||||
|
||||
TODO Security
|
||||
|
||||
|
||||
# IANA Considerations
|
||||
|
||||
This document has no IANA actions.
|
||||
|
||||
|
||||
|
||||
--- back
|
||||
|
||||
# Acknowledgments
|
||||
{:numbered="false"}
|
||||
|
||||
TODO acknowledge.
|
||||
@@ -0,0 +1,637 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE rfc SYSTEM "rfc2629.dtd" [
|
||||
<!-- A set of on-line citation libraries are maintained on the xml2rfc web site.
|
||||
The next line defines an entity named RFC2629, which contains the necessary XML
|
||||
for the reference element, and is used much later in the file. This XML contains an
|
||||
anchor (also RFC2629) which can be used to cross-reference this item in the text.
|
||||
You can also use local file names instead of a URI. The environment variable
|
||||
XML_LIBRARY provides a search path of directories to look at to locate a
|
||||
relative path name for the file. There has to be one entity for each item to be
|
||||
referenced. -->
|
||||
<!ENTITY RFC2234 SYSTEM "http://xml.resource.org/public/rfc/bibxml/reference.RFC.2234.xml">
|
||||
<!ENTITY RFC2629 SYSTEM "http://xml.resource.org/public/rfc/bibxml/reference.RFC.2629.xml">
|
||||
<!ENTITY RFC4234 SYSTEM "http://xml.resource.org/public/rfc/bibxml/reference.RFC.4234.xml">
|
||||
<!-- There is also a library of current Internet Draft citations. It isn't a good idea to
|
||||
actually use one for the template because it might have disappeared when you come to test
|
||||
this template. This is the form of the entity definition
|
||||
<!ENTITY I-D.mrose-writing-rfcs SYSTEM
|
||||
"http://xml.resource.org/public/rfc/bibxml3/reference.I-D.mrose-writing-rfcs.xml">
|
||||
corresponding to a draft filename draft-mrose-writing-rfcs-nn.txt. The citation will be
|
||||
to the most recent draft in the sequence, and is updated roughly hourly on the web site.
|
||||
For working group drafts, the same principle applies: file name starts draft-ietf-wgname-..
|
||||
and entity file is reference.I-D.ietf-wgname-... The corresponding entity name is
|
||||
I-D.ietf-wgname-... (I-D.mrose-writing-rfcs for the other example). Of course this doesn't
|
||||
change when the draft version changes.
|
||||
-->
|
||||
<!-- Fudge for XMLmind which doesn't have this built in -->
|
||||
<!ENTITY nbsp " ">
|
||||
]>
|
||||
|
||||
<!-- Extra statement used by XSLT processors to control the output style. -->
|
||||
<?xml-stylesheet type='text/xsl' href='rfc2629.xslt' ?>
|
||||
|
||||
|
||||
<!-- Processing Instructions can be placed here but if you are editing
|
||||
with XMLmind (and maybe other XML editors) they are better placed
|
||||
after the rfc element start tag as shown below. -->
|
||||
|
||||
<!-- Information about the document.
|
||||
category values: std, bcp, info, exp, and historic
|
||||
For Internet-Drafts, specify attribute "ipr".
|
||||
(ipr values are: full3667, noModification3667, noDerivatives3667),
|
||||
Also for Internet-Drafts, can specify values for
|
||||
attributes "docName" and, if relevant, "iprExtract". Note
|
||||
that the value for iprExtract is the anchor attribute
|
||||
value of a section (such as a MIB specification) that can be
|
||||
extracted for separate publication, and is only
|
||||
useful whenhe value of "ipr" is not "full3667". -->
|
||||
<!-- TODO: verify which attributes are specified only
|
||||
by the RFC editor. It appears that attributes
|
||||
"number", "obsoletes", "updates", and "seriesNo"
|
||||
are specified by the RFC editor (and not by
|
||||
the document author). -->
|
||||
<rfc
|
||||
category="info"
|
||||
ipr="noModification3978"
|
||||
iprExtract="codeExample"
|
||||
docName="draft-ietf-edu-xml2rfc-full-template-latest" >
|
||||
<!-- Processing Instructions- PIs (for a complete list and description,
|
||||
see file http://xml.resource.org/authoring/README.html and below... -->
|
||||
|
||||
<!-- Some of the more generally applicable PIs that most I-Ds might want to use -->
|
||||
|
||||
<!-- Try to enforce the ID-nits conventions and DTD validity -->
|
||||
<?rfc strict="yes" ?>
|
||||
|
||||
<!-- Items used when reviewing the document -->
|
||||
<?rfc comments="no" ?> <!-- Controls display of <cref> elements -->
|
||||
<?rfc inline="no" ?> <!-- When no, put comments at end in comments section,
|
||||
otherwise, put inline -->
|
||||
<?rfc editing="no" ?> <!-- When yes, insert editing marks: editing marks consist of a
|
||||
string such as <29> printed in the blank line at the
|
||||
beginning of each paragraph of text. -->
|
||||
|
||||
<!-- Create Table of Contents (ToC) and set some options for it.
|
||||
Note the ToC may be omitted for very short documents,but idnits insists on a ToC
|
||||
if the document has more than 15 pages. -->
|
||||
<?rfc toc="yes"?>
|
||||
<?rfc tocompact="yes"?> <!-- If "yes" eliminates blank lines before main section entries. -->
|
||||
<?rfc tocdepth="3"?> <!-- Sets the number of levels of sections/subsections... in ToC -->
|
||||
|
||||
<!-- Choose the options for the references.
|
||||
Some like symbolic tags in the references (and citations) and others prefer
|
||||
numbers. The RFC Editor always uses symbolic tags.
|
||||
The tags used are the anchor attributes of the references. -->
|
||||
<?rfc symrefs="no"?>
|
||||
<?rfc sortrefs="yes" ?> <!-- If "yes", causes the references to be sorted in order of tags.
|
||||
This doesn't have any effect unless symrefs is "yes" also. -->
|
||||
|
||||
<!-- These two save paper: Just setting compact to "yes" makes savings by not starting each
|
||||
main section on a new page but does not omit the blank lines between list items.
|
||||
If subcompact is also "yes" the blank lines between list items are also omitted. -->
|
||||
<?rfc compact="yes" ?>
|
||||
<?rfc subcompact="no" ?>
|
||||
<!-- end of list of popular I-D processing instructions -->
|
||||
|
||||
<!-- ***** FRONT MATTER ***** -->
|
||||
<front>
|
||||
<!-- The abbreviated title is used in the page header - it is only necessary if the
|
||||
full title is longer than 42 characters -->
|
||||
<title abbrev="Abbreviated-Title">Full Title</title>
|
||||
|
||||
<!-- add 'role="editor"' below for the editors if appropriate -->
|
||||
<author
|
||||
fullname="Pekka Savola"
|
||||
initials="P."
|
||||
surname="Savola">
|
||||
|
||||
<!-- abbrev not needed but can be used for the header
|
||||
if the full organization name is too long -->
|
||||
<organization abbrev="Abbreviated OrgName">Full Organization name</organization>
|
||||
<address>
|
||||
<postal>
|
||||
<!-- I've omitted my street address here -->
|
||||
<street/>
|
||||
<city>Espoo</city>
|
||||
<!--
|
||||
The IETF seems to meet once a year in Minneapolis,
|
||||
so that's practically my US address. If so, I would
|
||||
add the following elements:
|
||||
<region>MN</region>
|
||||
<code>55403</code>
|
||||
However, if I lived in France, the <code> comes before the city. xml2rfc
|
||||
preserves the order of <city>, <region>, <code> and <country> elements in
|
||||
output so that they can reflect any possible the national scheme
|
||||
-->
|
||||
<!-- The country element is supposed to contain an ISO3166 two letter country
|
||||
code. -->
|
||||
<country>FI</country>
|
||||
</postal>
|
||||
<email>psavola@funet.fi</email>
|
||||
<!--
|
||||
If I had a phone, fax machine, and a URI, I could add the following:
|
||||
<phone>+1-408-555-1234</phone>
|
||||
<facsimile>+1-555-911-9111</facsimile>
|
||||
<uri>http://www.example.com/</uri>
|
||||
-->
|
||||
</address>
|
||||
</author>
|
||||
|
||||
<!-- Another author who claims to be an editor -->
|
||||
<author fullname="Elwyn Davies"
|
||||
initials="E.B."
|
||||
surname="Davies"
|
||||
role="editor">
|
||||
<organization>Folly Consulting</organization>
|
||||
|
||||
<address>
|
||||
<postal>
|
||||
<street></street>
|
||||
|
||||
<city>Soham</city>
|
||||
|
||||
<region></region>
|
||||
|
||||
<code></code>
|
||||
|
||||
<country>UK</country>
|
||||
</postal>
|
||||
|
||||
<phone>+44 7889 488 335</phone>
|
||||
|
||||
<facsimile></facsimile>
|
||||
|
||||
<email>elwynd@dial.pipex.com</email>
|
||||
|
||||
<uri></uri>
|
||||
</address>
|
||||
</author>
|
||||
|
||||
<date year="2006" month="March"/> <!-- month="March" is no longer necessary
|
||||
note also, day="30" is optional -->
|
||||
<!-- WARNING: If the month and year are the current ones, xml2rfc will fill in the day for
|
||||
you. If only the year is specified, xml2rfc will fill in the current day and month
|
||||
irrespective of the day. This silliness should be fixed in v1.31. -->
|
||||
|
||||
<!-- Meta-data Declarations -->
|
||||
|
||||
<!-- Notice the use of & as an escape for & which would otherwise
|
||||
start an entity declaration, whereas we want a literal &. -->
|
||||
<area>Operations & Management</area>
|
||||
|
||||
<!-- WG name at the upperleft corner of the doc,
|
||||
IETF fine for individual submissions. You can also
|
||||
omit this element in which case in defaults to "Network Working Group" -
|
||||
a hangover from the ancient history of the IETF! -->
|
||||
<workgroup>Internet Engineering Task Force</workgroup>
|
||||
|
||||
<!-- The DTD allows multiple area and workgroup elements but only the first one has any
|
||||
effect on output. -->
|
||||
<!-- You can add <keyword/> elements here. They will be incorporated into HTML output
|
||||
files in a meta tag but they have no effect on text or nroff output. -->
|
||||
|
||||
|
||||
<abstract>
|
||||
<t>This is an abstract abstract. I-Ds and RFCs MUST have an abstract.
|
||||
Remember, don't add references here. So we would just say the 'language' used to write
|
||||
this document is defined in RFC 2629.</t>
|
||||
</abstract>
|
||||
|
||||
<note title="Foreword">
|
||||
<t>This "forward" section is an unnumbered section that is not included
|
||||
in the table of contents. It is primarily used for the IESG to
|
||||
make comments about the document. It can also be used for comments about the status
|
||||
of the document and sometimes is used for the RFC2119 requirements language statement.
|
||||
</t>
|
||||
<t>In this example, it is used as a handy place to specify URLs to
|
||||
documents and tools to author RFC-style documents using XML.</t>
|
||||
<t>RFC2629 is the original published document on authoring RFC-style
|
||||
documents in XML
|
||||
(<eref target="http://xml.resource.org/public/rfc/html/rfc2629.html"/>).
|
||||
It is being updated (and called RFC2629(bis) and is
|
||||
<eref target="http://xml.resource.org/authoring/draft-mrose-writing-rfcs.html"/>.
|
||||
The tool to convert XML documents to RFC-style text (and HTML) files
|
||||
is described in document <eref target="http://xml.resource.org/authoring/README.html"/>.
|
||||
</t>
|
||||
<t>Please also remember to check out
|
||||
<eref target="http://www.ietf.org/ID-Checklist.html"/> for issues to note when writing
|
||||
drafts and the automated tools documented at
|
||||
<eref target="http://tools.ietf.org/tools/"/>.</t>
|
||||
<t>Remember, you don't need to have any other tools than a 'notepad'
|
||||
or your favorite editor to write xml2rfc drafts. You can use the web
|
||||
interface at <eref target="http://xml.resource.org"/> for processing. The benefit of
|
||||
using XML editors is mostly catching those missing tags which the processor will
|
||||
warn you about, but you don't need to worry about the editors when getting
|
||||
started.</t>
|
||||
<t>This template is not meant to be a conclusive list of everything,
|
||||
but summarize the often-needed basic features to get one started.</t>
|
||||
</note>
|
||||
|
||||
|
||||
<note title="Requirements Language">
|
||||
<t>The key words "MUST", "MUST NOT",
|
||||
"REQUIRED", "SHALL", "SHALL NOT",
|
||||
"SHOULD", "SHOULD NOT", "RECOMMENDED",
|
||||
"MAY", and "OPTIONAL" in this document are to be
|
||||
interpreted as described in <xref target="RFC2119">RFC 2119</xref>.
|
||||
</t>
|
||||
</note>
|
||||
|
||||
</front>
|
||||
|
||||
<middle>
|
||||
<section title="Introduction">
|
||||
<t>Now you can have a bit lengthier text here.</t>
|
||||
<t>The definition of the XML Data Type Description used to 'describe' an RFC or Internet
|
||||
Draft can be found in a document which we can refer to as
|
||||
<xref target="RFC2629">RFC 2629</xref>.</t>
|
||||
<t>Let's refer to a couple more documents, just for practice:
|
||||
<xref target="DOMINATION"/> and
|
||||
<xref target="RFC2661">L2TP</xref>. For text generation, these look equivalent,
|
||||
but the latter looks a bit neater in the HTML representation.</t>
|
||||
<t>You might also add a note about the usage of RFC2119 keywords here..</t>
|
||||
<t>You can cross-reference the sections of the document in a stable manner either by
|
||||
<xref target="sect2">section number</xref> - the usual way - or by section title
|
||||
("<xref target="sect2" format="title"/>"): if the organization of the
|
||||
document changes the reference will still be to the correct section. However
|
||||
"sect2" is not a very good 'anchor' name because there is no guarantee that
|
||||
this section will remain as Section 2 for ever. It is best to use some sort of mnemonic
|
||||
for the contents of the section, which also makes it easier to remember the anchor when
|
||||
creating a cross-reference many pages later. A final note about anchors: anchors are
|
||||
XML 'tokens' and must therefore consist only of letters, numbers, underscores, hyphens
|
||||
and periods, starting with either a letter or underscore. Anchors with spaces or other
|
||||
punctuation characters are not allowed.
|
||||
</t>
|
||||
</section>
|
||||
|
||||
<section anchor="sect2" title="An Example Section">
|
||||
<t>Technical documents often use lists. There are multiple list styles:
|
||||
'empty', 'symbols', 'letters', 'numbers', 'hanging', 'format', etc.</t>
|
||||
<t>
|
||||
A more complicated list structure can be found in <xref target="more_lists"/>.
|
||||
<list style="symbols">
|
||||
<t>First bullet</t>
|
||||
<t>Second bullet</t>
|
||||
</list>
|
||||
You can write text here as well - the difference, as compared with putting it in the next
|
||||
<t> element, is that there will not be a blank line between the last list item
|
||||
and this text if the processing instructions compact and subcompact are both set to
|
||||
"yes". Otherwise list items and the text before and after will be separated by blank
|
||||
lines.
|
||||
</t>
|
||||
<t>One can draw fancy diagrams as well; remember to ensure that they
|
||||
don't exceed 69 chars/line until v1.31 comes along. v1.31 should give you the ability
|
||||
to start figures at the left margin getting figures up to 72 characters wide.</t>
|
||||
<t>Setting the alignment for the whole figure to "center" instead of the default "left"
|
||||
causes all the components to be centred unless it is overridden just for the "artwork",
|
||||
as it is here.</t>
|
||||
<figure anchor="xml_happy" align="center">
|
||||
<preamble>Figures can have some text before the artwork should it be needed. Note
|
||||
that figures should NOT be inside <t> elements. Originally they were allowed
|
||||
to be but you will now get a warning that this is deprecated, and the figure should
|
||||
be a 'child' of the section element.</preamble>
|
||||
<artwork align="left">
|
||||
<![CDATA[
|
||||
+-----------------------+
|
||||
| Use XML, be Happy :-) |
|
||||
|_______________________|
|
||||
|
||||
]]>
|
||||
</artwork>
|
||||
<postamble>Figures can also have text after the artwork and before the caption (if
|
||||
any). This figure has an anchor. This means that the figure will get a caption...
|
||||
</postamble>
|
||||
</figure>
|
||||
<t>Note that including a CDATA means you don't need to escape most special characters
|
||||
you might otherwise have to. Figures may also have a title attribute but it won't be
|
||||
displayed unless there is also an anchor, and it will be somewhat disconcerting for
|
||||
readers if some figures have numbers and others don't..</t>
|
||||
|
||||
<section title="A Subsection">
|
||||
<t>There can be a lot of subsections (and sub-subsections). By default 3 levels of
|
||||
nesting show in table of contents but that can be adjusted with the
|
||||
value of the "tocdepth" processing instruction.</t>
|
||||
</section>
|
||||
|
||||
<section title="Tables">
|
||||
<t>Another item that you might need is a table. The XML for tables is very similar
|
||||
to that for figures:
|
||||
</t>
|
||||
<texttable anchor='table_example' title="A Very Simple Table">
|
||||
<preamble>Tables use ttcol to define column headers and widths.
|
||||
Every cell then has a "c" element for its content.</preamble>
|
||||
<ttcol align='center'>ttcol #1</ttcol>
|
||||
<ttcol align='center'>ttcol #2</ttcol>
|
||||
<c>c #1</c>
|
||||
<c>c #2</c>
|
||||
<c>c #3</c>
|
||||
<c>c #4</c>
|
||||
<c>c #5</c>
|
||||
<c>c #6</c>
|
||||
<postamble>which is a very simple example.</postamble>
|
||||
</texttable>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section anchor="more_lists" title="More About Lists">
|
||||
<t>One useful style of lists uses 'hanging labels' where the list item is indented by
|
||||
the amount of the hangIndent with the hanging label displayed to the left of the first
|
||||
line of the item. This example shows how <vspace> can be used to deal with the
|
||||
odd label longer than the indent you really want to use (This is only really relevant
|
||||
to text mode output because the labels are always on separate lines in HTML output):
|
||||
<list hangIndent="8" style="hanging">
|
||||
<t hangText="short">With a label shorter than the hangIndent there
|
||||
is white space after the label and before the item text starts
|
||||
although it starts on the same line - clearly separating the label
|
||||
from the column of items.</t>
|
||||
<t hangText="fantastically long label">With a label longer than the hangIndent
|
||||
the label runs on into the text item and the separation is lost.</t>
|
||||
<t hangText="vspace_trick"><vspace blankLines="0" />Inserting a
|
||||
<vspace /> at the start of the item forces the new item to
|
||||
start on a new line emphasizing the separation again.</t>
|
||||
</list>
|
||||
</t>
|
||||
<!-- It would be nice to see the next piece (12 lines) all on one page. -->
|
||||
<?rfc needLines="12" ?>
|
||||
<t>List items in xml2rfc are made up of one <t> element. In some cases it would be
|
||||
nice to have more than one paragraph in a list item. This can be achieved with
|
||||
<vspace> also:
|
||||
<list style="letters">
|
||||
<t>First, a short item that needs only one paragraph.</t>
|
||||
<t>Second, a longer list item. We have more to say, and we want a separate
|
||||
paragraph.<vspace blankLines="1"/>
|
||||
And here we can have it, and go on to our heart's content.</t>
|
||||
</list>
|
||||
</t>
|
||||
<t> If you just want an indented paragraph (say for a quotation) use the "empty" style:
|
||||
<list style="empty" hangIndent="10">
|
||||
<t>The quick, brown fox jumped over the lazy dog and lived to fool many another
|
||||
hunter in the great wood in the west.</t>
|
||||
</list>
|
||||
</t>
|
||||
<section title="Numbering Lists Across Lists and Sections">
|
||||
<t>Sometimes it is useful to be able to number items continuously although they are
|
||||
in separate <list> elements, maybe in separate sections. This can be achieved
|
||||
using the "format" style and a "counter" variable.
|
||||
</t>
|
||||
<t>First list with (say) requirements items:
|
||||
<list style="format R%d" counter="reqs" hangIndent="4">
|
||||
<t>Requirement #1</t>
|
||||
<t>Requirement #2</t>
|
||||
<t>Requirement #3</t>
|
||||
</list>
|
||||
It is wise to specify the indent explicitly so that all the items line up nicely.
|
||||
Otherwise the indent in each list is determined by the maximum length of the labels
|
||||
in that list, even if later lists have longer labels.</t>
|
||||
<t>A little later there is a second list with requirements items:
|
||||
<list style="format R%d" counter="reqs" hangIndent="4">
|
||||
<t>Requirement #4</t>
|
||||
<t>Requirement #5</t>
|
||||
<t>Requirement #6</t>
|
||||
</list>
|
||||
before this section finishes.</t>
|
||||
</section>
|
||||
<section title="Where the List Numbering Continues">
|
||||
<t>But in the next section the list of requirements continues:</t>
|
||||
<t>Third list with requirements items:
|
||||
<list style="format R%d" counter="reqs" hangIndent="4">
|
||||
<t>Requirement #7</t>
|
||||
<t>Requirement #8</t>
|
||||
<t>Requirement #9</t>
|
||||
<t>Requirement #10</t>
|
||||
</list>
|
||||
And finally that is all about the requirements.</t>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section title="Using Typed Artwork">
|
||||
<t>The <spanx style='verb'>artwork</spanx> element from RFC 2629 supports an
|
||||
optional <spanx style='verb'>type</spanx> attribute. While most possible values are
|
||||
just ignored, including the special case where the attribute is unspecified or just
|
||||
empty, some values are recognized. In particular,
|
||||
<spanx style='verb'>type='abnf'</spanx> can be used if the
|
||||
<spanx style='verb'>artwork</spanx> contains an Augmented Backus-Naur Form (ABNF)
|
||||
syntax specification <xref target='RFC4234' />. As a special extension in its
|
||||
<spanx style='emph'>behavior</spanx>, <spanx style='strong'>xml2rfc</spanx> will
|
||||
attempt to validate the syntax and colorize the HTML output of ABNF, since it is so
|
||||
widely used in RFCs. It does this colorizing by relying on the full parsing it does
|
||||
right before, not on a quick and partial (e.g., line-by-line) pattern-based hack.
|
||||
ABNF is the only artwork type to benefit from this kind of internal support at this
|
||||
time. If the <spanx style='verb'>strict</spanx> rfc-PI directive is activated,
|
||||
invalid ABNF content will cause <spanx style='strong'>xml2rfc</spanx> to abort with an
|
||||
error message. Omitting the <spanx style='verb'>type</spanx> attribute altogether
|
||||
is the obvious way to avoid having this validation and colorizing performed.</t>
|
||||
|
||||
<figure align='left'>
|
||||
<preamble>For example (to be viewed in HTML):</preamble>
|
||||
<artwork align='center' type='abnf'><![CDATA[
|
||||
char-val = DQUOTE *(%x20-21 / %x23-7E) DQUOTE
|
||||
; quoted string of SP and VCHAR
|
||||
without DQUOTE
|
||||
|
||||
num-val = "%" (bin-val / dec-val / hex-val)
|
||||
|
||||
bin-val = "b" 1*BIT
|
||||
[ 1*("." 1*BIT) / ("-" 1*BIT) ]
|
||||
; series of concatenated bit values
|
||||
; or single ONEOF range
|
||||
|
||||
dec-val = "d" 1*DIGIT
|
||||
[ 1*("." 1*DIGIT) / ("-" 1*DIGIT) ]
|
||||
|
||||
hex-val = "x" 1*HEXDIG
|
||||
[ 1*("." 1*HEXDIG) / ("-" 1*HEXDIG) ]
|
||||
|
||||
prose-val = "<" *(%x20-3D / %x3F-7E) ">"
|
||||
; bracketed string of SP and VCHAR
|
||||
without angles
|
||||
; prose description, to be used as
|
||||
last resort
|
||||
]]>
|
||||
</artwork>
|
||||
<postamble>This is from the original RFC on ABNF <xref target='RFC2234' />,
|
||||
with its minor mistakes in manually folded comment lines purposely left intact,
|
||||
for illustration. Since the result is still valid ABNF (but incorrect with respect
|
||||
to what was intended), this showcases how colorizing might give a human author
|
||||
(or editor or reader) a better chance to spot the three mistakes (and correct them,
|
||||
e.g., with extra semicolons, as has been done in a more recent
|
||||
version <xref target='RFC4234' /> of the ABNF specification). Note that it is
|
||||
the white space characters at the beginning of the subsequent lines (including the
|
||||
commented ones) that conspire to extend the reach of those rules across several
|
||||
lines.</postamble>
|
||||
</figure>
|
||||
</section>
|
||||
|
||||
<section title="Decrypting XML2RFC Parsing errors">
|
||||
<t>The most common form of xml2rfc parsing errors are those where a
|
||||
closing tag has been expected to be present before a new kind of tag is
|
||||
specified. In the example below, Introduction section's last paragraph was
|
||||
missing the closing t-element. The rest of the error messages can be rather
|
||||
easily understood as well by reading it carefully and examining the context.
|
||||
The reason is typically a missing tag somewhere.</t>
|
||||
<figure>
|
||||
<artwork>
|
||||
<![CDATA[
|
||||
======8<=========
|
||||
end tag "section" does not match open element "t" around line 65
|
||||
|
||||
Context:
|
||||
<rfc ipr="full3667" category="info"
|
||||
docName="draft-ietf-template-edu-full-00.txt"
|
||||
updates="1,2"
|
||||
obsoletes="3">
|
||||
<middle>
|
||||
<section title="Introduction">
|
||||
<t>
|
||||
=======8<========
|
||||
]]>
|
||||
</artwork>
|
||||
</figure>
|
||||
</section>
|
||||
<section title="Example of code or MIB module to be extracted"
|
||||
anchor="codeExample">
|
||||
<figure>
|
||||
<artwork>
|
||||
<![CDATA[
|
||||
/**** an example C program */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
void
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
|
||||
printf("program arguments are:\n");
|
||||
for (i = 0; i < argc; i++) {
|
||||
printf("%d: \"%s\"\n", i, argv[i]);
|
||||
}
|
||||
|
||||
exit(0);
|
||||
} /* main */
|
||||
|
||||
/* end of file */
|
||||
]]>
|
||||
</artwork>
|
||||
</figure>
|
||||
</section>
|
||||
<section anchor="Acknowledgements" title="Acknowledgements">
|
||||
<t>Remember, it's important to acknowledge people who have
|
||||
contributed to the work.</t>
|
||||
<t>This template was extended from an initial version written by Pekka Savola and
|
||||
contributed by him to the xml2rfc project.</t>
|
||||
</section>
|
||||
|
||||
<!-- Possibly a 'Contributors' section ... -->
|
||||
|
||||
<section anchor="IANA" title="IANA Considerations">
|
||||
<t>This memo includes no request to IANA.</t>
|
||||
<t>(It's good - indeed pretty much mandatory now - to have an explicit note because
|
||||
otherwise IANA wastes cycles trying to figure out if something is needed..)</t>
|
||||
</section>
|
||||
|
||||
<section anchor="Security" title="Security Considerations">
|
||||
<t>Remember to consider security from the start.. and all drafts are required to have
|
||||
a security considerations section before they will pass the IESG.
|
||||
</t>
|
||||
</section>
|
||||
</middle>
|
||||
|
||||
<!-- *****BACK MATTER ***** -->
|
||||
<back>
|
||||
<!-- References split to informative and normative -->
|
||||
<references title="Normative References">
|
||||
<reference anchor="RFC2661">
|
||||
<!-- the following is the minimum to make xml2rfc happy -->
|
||||
<front>
|
||||
<title>RFC2661</title>
|
||||
<author initials="authInitials" surname="authSurName">
|
||||
<organization/>
|
||||
</author>
|
||||
<date year="year" />
|
||||
</front>
|
||||
</reference>
|
||||
|
||||
<!-- A *really* full, totally OTT reference - Note, the "target" attribute of the
|
||||
"reference": if you want a URI printed in the reference, this is where it goes. -->
|
||||
<reference anchor='RFC2119'
|
||||
target='http://xml.resource.org/public/rfc/html/rfc2119.html'>
|
||||
<front>
|
||||
<title abbrev='RFC Key Words'>Key words for use in RFCs to Indicate Requirement
|
||||
Levels</title>
|
||||
<author initials='S.' surname='Bradner' fullname='Scott Bradner'>
|
||||
<organization>Harvard University</organization>
|
||||
<address>
|
||||
<postal>
|
||||
<street>1350 Mass. Ave.</street>
|
||||
<street>Cambridge</street>
|
||||
<street>MA 02138</street>
|
||||
</postal>
|
||||
<phone>- +1 617 495 3864</phone>
|
||||
<email>sob@harvard.edu</email>
|
||||
</address>
|
||||
</author>
|
||||
<date year='1997' month='March' />
|
||||
<area>General</area>
|
||||
<keyword>keyword</keyword>
|
||||
<abstract>
|
||||
<t>In many standards track documents several words are used to signify
|
||||
the requirements in the specification. These words are often
|
||||
capitalized. This document defines these words as they should be
|
||||
interpreted in IETF documents. Authors who follow these guidelines
|
||||
should incorporate this phrase near the beginning of their document:
|
||||
|
||||
<list>
|
||||
<t>
|
||||
The key words "MUST", "MUST NOT",
|
||||
"REQUIRED", "SHALL", "SHALL NOT",
|
||||
"SHOULD", "SHOULD NOT", "RECOMMENDED",
|
||||
"MAY", and "OPTIONAL" in this document are to be
|
||||
interpreted as described in RFC 2119.</t>
|
||||
</list>
|
||||
</t>
|
||||
<t>
|
||||
Note that the force of these words is modified by the requirement level of
|
||||
the document in which they are used.</t>
|
||||
</abstract>
|
||||
</front>
|
||||
|
||||
<seriesInfo name='BCP' value='14' />
|
||||
<seriesInfo name='RFC' value='2119' />
|
||||
<format type='TXT' octets='4723' target='ftp://ftp.isi.edu/in-notes/rfc2119.txt' />
|
||||
<format type='HTML' octets='14486'
|
||||
target='http://xml.resource.org/public/rfc/html/rfc2119.html' />
|
||||
<format type='XML' octets='5661'
|
||||
target='http://xml.resource.org/public/rfc/xml/rfc2119.xml' />
|
||||
</reference>
|
||||
|
||||
<!-- Right back at the beginning we defined an entity which (we asserted) would contain
|
||||
XML needed for a reference... this is where we use it. -->
|
||||
&RFC2629;
|
||||
</references>
|
||||
|
||||
<references title="Informative References">
|
||||
<!-- A reference written by by an organization not a persoN. -->
|
||||
<reference
|
||||
anchor="DOMINATION" >
|
||||
<front>
|
||||
<title>Ultimate Plan for Taking Over the World</title>
|
||||
<author>
|
||||
<organization>Mad Dominators, Inc.</organization>
|
||||
</author>
|
||||
<date year="1984" />
|
||||
</front>
|
||||
</reference>
|
||||
&RFC4234;
|
||||
&RFC2234;
|
||||
</references>
|
||||
|
||||
<section anchor="app-additional" title="Additional stuff">
|
||||
<t>You can add appendices just as regular sections, the only
|
||||
difference is that they go within the "back" element, and not
|
||||
within the "middle" element. And they follow the "reference"
|
||||
elements.</t>
|
||||
</section>
|
||||
</back>
|
||||
|
||||
</rfc>
|
||||
@@ -0,0 +1,50 @@
|
||||
FROM ubuntu:18.04
|
||||
LABEL maintainer="Martin Thomson <martin.thomson@gmail.com>"
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
ca-certificates coreutils curl git make ssh libxml2-utils xsltproc \
|
||||
python3-minimal python3-lxml python3-pip python3-setuptools python3-wheel \
|
||||
mmark ruby \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& apt-get autoremove -y && apt-get clean -y
|
||||
|
||||
ENV USER idci
|
||||
ENV LOGNAME $USER
|
||||
ENV HOSTNAME $USER
|
||||
ENV HOME /home/$USER
|
||||
ENV SHELL /bin/bash
|
||||
|
||||
RUN useradd -d "$HOME" -s "$SHELL" -m "$USER"
|
||||
WORKDIR $HOME
|
||||
USER $USER
|
||||
|
||||
ENV BINDIR $HOME/bin
|
||||
RUN mkdir -p $BINDIR
|
||||
ENV PATH $BINDIR:/usr/local/bin:/usr/bin:/bin
|
||||
|
||||
RUN set -e; tool_install() { \
|
||||
tool="$1";version="$2";sha="$3"; tmp=$(mktemp -t "${tool}XXXXX.tgz"); \
|
||||
curl -sSLf "https://tools.ietf.org/tools/${tool}/${tool}-${version}".tgz -o "$tmp"; \
|
||||
[ $(sha256sum -b "$tmp" | cut -d ' ' -f 1 -) = "$sha" ]; \
|
||||
target="${BINDIR:-~/.local/bin}/${tool}"; \
|
||||
tar xzfO "$tmp" "${tool}-${version}/${tool}" >"$target"; rm -f "$tmp"; \
|
||||
chmod 755 "$target"; }; \
|
||||
tool_install idnits 2.16.0 \
|
||||
5d9f49e528879e46aff03dcaf3e0ef438ab49d5e834543a741df57fcaeca1ddb && \
|
||||
tool_install rfcdiff 1.47 \
|
||||
75a9e83869885836c024a94f35128eaf292c6b9de3fd9d3361fbc62d46ec9f16
|
||||
|
||||
RUN pip3 install --user --compile xml2rfc && \
|
||||
ln -s $HOME/.local/bin/xml2rfc $BINDIR
|
||||
RUN gem install --no-doc --user-install --bindir $BINDIR \
|
||||
certified kramdown-rfc2629 && \
|
||||
certified-update
|
||||
|
||||
ENV KRAMDOWN_REFCACHEDIR=$HOME/.cache/xml2rfc
|
||||
RUN mkdir -p $KRAMDOWN_REFCACHEDIR
|
||||
|
||||
RUN GIT_REFERENCE=$HOME/git-reference; \
|
||||
git init $GIT_REFERENCE; \
|
||||
git -C $GIT_REFERENCE remote add i-d-template https://github.com/martinthomson/i-d-template; \
|
||||
git -C $GIT_REFERENCE remote add rfc2629xslt https://github.com/reschke/xml2rfc; \
|
||||
git -C $GIT_REFERENCE fetch --all
|
||||
@@ -0,0 +1,124 @@
|
||||
## Update the gh-pages branch with useful files
|
||||
|
||||
ifeq (true,$(TRAVIS))
|
||||
# Travis is a nightmare. It doesn't actually include the branch name in the
|
||||
# repo at all. Also, it doesn't consistently set the current branch name.
|
||||
ifneq (,$(TRAVIS_PULL_REQUEST_BRANCH))
|
||||
SOURCE_BRANCH := $(TRAVIS_PULL_REQUEST_BRANCH)
|
||||
else
|
||||
SOURCE_BRANCH := $(TRAVIS_BRANCH)
|
||||
endif
|
||||
else
|
||||
SOURCE_BRANCH := $(shell git rev-parse --abbrev-ref HEAD)
|
||||
ifeq (HEAD,$(SOURCE_BRANCH))
|
||||
SOURCE_BRANCH := $(shell git rev-parse --short HEAD)
|
||||
endif
|
||||
endif
|
||||
|
||||
# Default to pushing if a key or token is available.
|
||||
ifneq (,$(GH_TOKEN)$(CI_HAS_WRITE_KEY))
|
||||
PUSH_GHPAGES ?= true
|
||||
endif
|
||||
PUSH_GHPAGES ?= false
|
||||
|
||||
index.html: $(drafts_html) $(drafts_txt)
|
||||
ifeq (1,$(words $(drafts)))
|
||||
cp $< $@
|
||||
else
|
||||
@echo '<!DOCTYPE html>' >$@
|
||||
@echo '<html>' >>$@
|
||||
@echo '<head><title>$(GITHUB_REPO) drafts</title></head>' >>$@
|
||||
@echo '<body><ul>' >>$@
|
||||
@for draft in $(drafts); do \
|
||||
echo '<li><a href="'"$${draft}"'.html">'"$${draft}"'</a> (<a href="'"$${draft}"'.txt">txt</a>)</li>' >>$@; \
|
||||
done
|
||||
@echo '</ul></body>' >>$@
|
||||
@echo '</html>' >>$@
|
||||
endif
|
||||
|
||||
.IGNORE: fetch-ghpages
|
||||
.PHONY: fetch-ghpages
|
||||
fetch-ghpages:
|
||||
git fetch -q origin gh-pages:gh-pages
|
||||
|
||||
GHPAGES_ROOT := /tmp/ghpages$(shell echo $$$$)
|
||||
ghpages: $(GHPAGES_ROOT)
|
||||
$(GHPAGES_ROOT): fetch-ghpages
|
||||
@git show-ref refs/heads/gh-pages >/dev/null 2>&1 || \
|
||||
(git show-ref refs/remotes/origin/gh-pages >/dev/null 2>&1 && \
|
||||
git branch -t gh-pages origin/gh-pages) || \
|
||||
! echo 'Error: No gh-pages branch, run `make -f $(LIBDIR)/setup.mk setup-ghpages` to initialize it.'
|
||||
git clone -q -b gh-pages . $@
|
||||
|
||||
GHPAGES_TARGET := $(GHPAGES_ROOT)$(filter-out /master,/$(SOURCE_BRANCH))
|
||||
ifneq ($(GHPAGES_TARGET),$(GHPAGES_ROOT))
|
||||
$(GHPAGES_TARGET): $(GHPAGES_ROOT)
|
||||
mkdir -p $@
|
||||
endif
|
||||
|
||||
GHPAGES_PUBLISHED := $(drafts_html) $(drafts_txt) $(GHPAGES_EXTRA)
|
||||
GHPAGES_INSTALLED := $(addprefix $(GHPAGES_TARGET)/,$(GHPAGES_PUBLISHED))
|
||||
$(GHPAGES_INSTALLED): $(GHPAGES_PUBLISHED) $(GHPAGES_TARGET)
|
||||
cp -f $(notdir $@) $@
|
||||
|
||||
GHPAGES_ALL := $(GHPAGES_INSTALLED) $(GHPAGES_TARGET)/index.html
|
||||
$(GHPAGES_TARGET)/index.html: $(GHPAGES_INSTALLED)
|
||||
$(LIBDIR)/build-index.sh "$(dir $@)" "$(SOURCE_BRANCH)" "$(GITHUB_USER)" "$(GITHUB_REPO)" >$@
|
||||
|
||||
ifneq ($(GHPAGES_TARGET),$(GHPAGES_ROOT))
|
||||
GHPAGES_ALL += $(GHPAGES_ROOT)/index.html
|
||||
$(GHPAGES_ROOT)/index.html: $(GHPAGES_INSTALLED)
|
||||
$(LIBDIR)/build-index.sh "$(dir $@)" master "$(GITHUB_USER)" "$(GITHUB_REPO)" >$@
|
||||
endif
|
||||
|
||||
.PHONY: cleanup-ghpages
|
||||
cleanup-ghpages: $(GHPAGES_ROOT)
|
||||
-@for remote in `git remote`; do \
|
||||
git remote prune $$remote; \
|
||||
done;
|
||||
|
||||
# Clean up obsolete directories (2592000 = 30 days)
|
||||
@CUTOFF=$$(($$(date '+%s')-2592000)); \
|
||||
MAYBE_OBSOLETE=`comm -13 <(git branch -a | sed -e 's,.*[ /],,' | sort | uniq) <(ls $(GHPAGES_ROOT) | sed -e 's,.*/,,')`; \
|
||||
for item in $$MAYBE_OBSOLETE; do \
|
||||
if [ -d "$(GHPAGES_ROOT)/$$item" ] && \
|
||||
[ `git -C $(GHPAGES_ROOT) log -n 1 --format=%ct -- $$item` -lt $$CUTOFF ]; then \
|
||||
echo "Remove obsolete '$$item'"; \
|
||||
git -C $(GHPAGES_ROOT) rm -rfq -- $$item; \
|
||||
fi \
|
||||
done
|
||||
|
||||
# Clean up contents of target directory
|
||||
@if [ -d $(GHPAGES_TARGET) ]; then \
|
||||
echo git -C $(GHPAGES_ROOT) rm -fq --ignore-unmatch -- $(GHPAGES_TARGET)/draft-*.html $(GHPAGES_TARGET)/draft-*.txt $(addprefix $(GHPAGES_TARGET)/,$(GHPAGES_EXTRA)); \
|
||||
git -C $(GHPAGES_ROOT) rm -fq --ignore-unmatch -- $(GHPAGES_TARGET)/draft-*.html $(GHPAGES_TARGET)/draft-*.txt $(addprefix $(GHPAGES_TARGET)/,$(GHPAGES_EXTRA)); \
|
||||
fi
|
||||
|
||||
|
||||
.PHONY: ghpages gh-pages
|
||||
gh-pages: ghpages
|
||||
ghpages: cleanup-ghpages $(GHPAGES_ALL)
|
||||
git -C $(GHPAGES_ROOT) add -f $(GHPAGES_ALL)
|
||||
if test `git -C $(GHPAGES_ROOT) status --porcelain | grep '^[A-Z]' | wc -l` -gt 0; then \
|
||||
git -C $(GHPAGES_ROOT) $(CI_AUTHOR) commit -m "Script updating gh-pages from $(shell git rev-parse --short HEAD). [ci skip]"; fi
|
||||
ifeq (true,$(PUSH_GHPAGES))
|
||||
ifneq (,$(if $(CI_HAS_WRITE_KEY),1,$(if $(GH_TOKEN),,1)))
|
||||
git -C $(GHPAGES_ROOT) push https://github.com/$(GITHUB_REPO_FULL) gh-pages
|
||||
else
|
||||
@echo git -C $(GHPAGES_ROOT) push -q https://github.com/$(GITHUB_REPO_FULL) gh-pages
|
||||
@git -C $(GHPAGES_ROOT) push -q https://$(GH_TOKEN)@github.com/$(GITHUB_REPO_FULL) gh-pages >/dev/null 2>&1
|
||||
endif
|
||||
else
|
||||
git -C $(GHPAGES_ROOT) push origin gh-pages
|
||||
endif # PUSH_GHPAGES
|
||||
-rm -rf $(GHPAGES_ROOT)
|
||||
|
||||
## Save published documents to the CI_ARTIFACTS directory
|
||||
ifneq (,$(CI_ARTIFACTS))
|
||||
$(CI_ARTIFACTS):
|
||||
mkdir -p $@
|
||||
|
||||
.PHONY: artifacts
|
||||
artifacts: $(GHPAGES_PUBLISHED) $(CI_ARTIFACTS)
|
||||
cp -f $(filter-out $(CI_ARTIFACTS),$^) $(CI_ARTIFACTS)
|
||||
endif
|
||||
@@ -0,0 +1,79 @@
|
||||
## Identify drafts, types and versions
|
||||
|
||||
drafts := $(sort $(basename $(wildcard $(foreach pattern,? *-[-a-z]? *-?[a-z] *[a-z0-9]??,$(foreach ext,xml org md,draft-$(pattern).$(ext))))))
|
||||
|
||||
ifeq (0,$(words $(drafts)))
|
||||
drafts := $(sort $(basename $(wildcard rfc[0-9]*.xml)))
|
||||
endif
|
||||
|
||||
ifeq (0,$(words $(drafts)))
|
||||
$(warning No file named draft-*.md or draft-*.xml or draft-*.org)
|
||||
$(error Create a draft file before running make)
|
||||
endif
|
||||
|
||||
draft_types := $(foreach draft,$(drafts),\
|
||||
$(suffix $(firstword $(wildcard $(draft).md $(draft).org $(draft).xml))))
|
||||
drafts_source := $(join $(drafts),$(draft_types))
|
||||
|
||||
drafts_tags := $(shell git tag --sort=refname 2>/dev/null | grep '^draft-')
|
||||
f_prev_tag = $(lastword $(subst -, ,$(lastword $(filter $(draft)-%,$(drafts_tags)))))
|
||||
f_next_tag = $(if $(f_prev_tag),$(shell printf "%.2d" $$(( 1$(f_prev_tag) - 99)) ),00)
|
||||
drafts_next := $(foreach draft,$(drafts),$(draft)-$(f_next_tag))
|
||||
drafts_prev := $(foreach draft,$(drafts),$(draft)-$(f_prev_tag))
|
||||
drafts_with_prev := $(foreach draft,$(drafts),$(if $(f_prev_tag),$(draft)))
|
||||
|
||||
drafts_txt := $(addsuffix .txt,$(drafts))
|
||||
drafts_html := $(addsuffix .html,$(drafts))
|
||||
drafts_xml := $(addsuffix .xml,$(drafts))
|
||||
drafts_next_txt := $(addsuffix .txt,$(drafts_next))
|
||||
drafts_next_xml := $(addsuffix .xml,$(drafts_next))
|
||||
drafts_prev_txt := $(addsuffix .txt,$(drafts_prev))
|
||||
|
||||
last_modified = $$(stat $$([ $$(uname -s) = Darwin ] && echo -f '%m' || echo -c '%Y') $(1))
|
||||
last_commit = $$(git rev-list -n 1 --timestamp $(1) -- $(2) | sed -e 's/ .*//')
|
||||
|
||||
# CI config
|
||||
CI ?= false
|
||||
CI_USER ?= $(word 1,$(subst /, ,$(TRAVIS_REPO_SLUG)))$(CIRCLE_PROJECT_USERNAME)
|
||||
CI_REPO ?= $(word 2,$(subst /, ,$(TRAVIS_REPO_SLUG)))$(CIRCLE_PROJECT_REPONAME)
|
||||
ifneq (,$(CI_USER))
|
||||
ifneq (,$(CI_REPO))
|
||||
CI_REPO_FULL = $(CI_USER)/$(CI_REPO)
|
||||
endif
|
||||
endif
|
||||
ifdef CI_PULL_REQUESTS
|
||||
CI_IS_PR = true
|
||||
else
|
||||
# Circle makes this easy
|
||||
ifdef TRAVIS_PULL_REQUEST
|
||||
ifeq (false,$(TRAVIS_PULL_REQUEST))
|
||||
# If $TRAVIS_PULL_REQUEST is the word 'false', it's a branch build.
|
||||
CI_IS_PR = false
|
||||
else
|
||||
CI_IS_PR = true
|
||||
endif
|
||||
else
|
||||
CI_IS_PR = false
|
||||
endif
|
||||
endif
|
||||
CI_ARTIFACTS := $(CIRCLE_ARTIFACTS)
|
||||
|
||||
ifeq (,$(shell git config --global --get user.name))
|
||||
CI_AUTHOR = -c user.name="ID Bot"
|
||||
endif
|
||||
ifeq (,$(shell git config --global --get user.email))
|
||||
CI_AUTHOR += -c user.email="idbot@example.com"
|
||||
endif
|
||||
|
||||
# Github guesses
|
||||
GIT_REMOTE ?= origin
|
||||
ifeq (,$(CI_REPO_FULL))
|
||||
GITHUB_REPO_FULL := $(shell git ls-remote --get-url $(GIT_REMOTE) 2>/dev/null |\
|
||||
sed -e 's/^.*github\.com.//;s/\.git$$//')
|
||||
GITHUB_USER := $(word 1,$(subst /, ,$(GITHUB_REPO_FULL)))
|
||||
GITHUB_REPO := $(word 2,$(subst /, ,$(GITHUB_REPO_FULL)))
|
||||
else
|
||||
GITHUB_REPO_FULL := $(CI_REPO_FULL)
|
||||
GITHUB_USER := $(CI_USER)
|
||||
GITHUB_REPO := $(CI_REPO)
|
||||
endif
|
||||
@@ -0,0 +1,78 @@
|
||||
GH_ISSUES := gh-pages
|
||||
.PHONY: fetch-ghissues
|
||||
fetch-ghissues:
|
||||
-git fetch -q origin $(GH_ISSUES):$(GH_ISSUES)
|
||||
|
||||
ifneq (,$(GH_TOKEN))
|
||||
GITHUB_OAUTH := -H "Authorization: token $(GH_TOKEN)"
|
||||
endif
|
||||
|
||||
ifneq (true,$(PUSH_GHPAGES))
|
||||
DISABLE_ISSUE_FETCH ?= true
|
||||
endif
|
||||
|
||||
## Store a copy of any github issues
|
||||
.PHONY: issues
|
||||
issues: issues.json pulls.json
|
||||
issues.json pulls.json: fetch-ghissues $(drafts_source)
|
||||
@if [ -f $@ ] && [ "$(call last_modified,$@)" -gt "$(call last_commit,$(GH_ISSUES),$@)" ] 2>/dev/null; then \
|
||||
echo 'Skipping update of $@ (it is newer than the one on the branch)'; exit; \
|
||||
fi; \
|
||||
skip=$(DISABLE_ISSUE_FETCH); \
|
||||
if [ $(CI) = true -a "$$skip" != true -a \
|
||||
$$(($$(date '+%s')-28800)) -lt "$$(git log -n 1 --pretty=format:%ct $(GH_ISSUES) -- $@)" ] 2>/dev/null; then \
|
||||
skip=true; echo 'Skipping update of $@ (most recent update was in the last 8 hours)'; \
|
||||
fi; \
|
||||
if [ "$$skip" = true ]; then \
|
||||
git show $(GH_ISSUES):$@ > $@; exit; \
|
||||
fi; \
|
||||
echo '[' > $@; \
|
||||
url=https://api.github.com/repos/$(GITHUB_REPO_FULL)/$(basename $(notdir $@))?state=all; \
|
||||
tmp=$$(mktemp /tmp/$(basename $(notdir $@)).XXXXXX); trap 'rm -f $$tmp' EXIT; \
|
||||
while [ -n "$$url" ]; do \
|
||||
echo "Fetching $(basename $(notdir $@)) from $$url"; \
|
||||
$(curl) $(GITHUB_OAUTH) $$url -D $$tmp | sed -e '1s/^ *\[//;$$s/\] *$$//' >> $@; \
|
||||
if ! head -1 $$tmp | grep -q ' 200 OK'; then \
|
||||
echo "Error loading $$url:"; cat $$tmp; exit 1; \
|
||||
fi; \
|
||||
url=$$(sed -e 's/^Link:.*<\([^>]*\)>;[^,]*rel="next".*/\1/;t;d' $$tmp); \
|
||||
[ -n "$$url" ] && echo , >> $@; \
|
||||
done; \
|
||||
echo ']' >> $@
|
||||
|
||||
GHISSUES_ROOT := /tmp/ghissues$(shell echo $$$$)
|
||||
$(GHISSUES_ROOT): fetch-ghissues
|
||||
@git show-ref refs/heads/$(GH_ISSUES) >/dev/null 2>&1 || \
|
||||
(git show-ref refs/remotes/origin/$(GH_ISSUES) >/dev/null 2>&1 && \
|
||||
git branch -t $(GH_ISSUES) origin/$(GH_ISSUES)) || \
|
||||
! echo 'Error: No $(GH_ISSUES) branch, run `make -f $(LIBDIR)/setup.mk setup-ghpages` to initialize it.'
|
||||
git clone -q -b $(GH_ISSUES) . $@
|
||||
|
||||
$(GHISSUES_ROOT)/%.json: %.json $(GHISSUES_ROOT)
|
||||
cp -f $< $@
|
||||
|
||||
## Commit and push the changes to $(GH_ISSUES)
|
||||
.PHONY: ghissues gh-issues
|
||||
gh-issues: ghissues
|
||||
ghissues: $(GHISSUES_ROOT)/issues.json $(GHISSUES_ROOT)/pulls.json
|
||||
cp -f $(LIBDIR)/template/issues.html $(LIBDIR)/template/issues.js $(GHISSUES_ROOT)
|
||||
git -C $(GHISSUES_ROOT) add -f issues.json pulls.json issues.html issues.js
|
||||
if test `git -C $(GHISSUES_ROOT) status --porcelain issues.json pulls.json issues.js issues.html | wc -l` -gt 0; then \
|
||||
git -C $(GHISSUES_ROOT) $(CI_AUTHOR) commit -m "Script updating issues at $(shell date -u +%FT%TZ). [ci skip]"; fi
|
||||
ifeq (true,$(PUSH_GHPAGES))
|
||||
ifneq (,$(if $(CI_HAS_WRITE_KEY),1,$(if $(GH_TOKEN),,1)))
|
||||
git -C $(GHISSUES_ROOT) push https://github.com/$(GITHUB_REPO_FULL) $(GH_ISSUES)
|
||||
else
|
||||
@echo git -C $(GHISSUES_ROOT) push -q https://github.com/$(GITHUB_REPO_FULL) $(GH_ISSUES)
|
||||
@git -C $(GHISSUES_ROOT) push -q https://$(GH_TOKEN)@github.com/$(GITHUB_REPO_FULL) $(GH_ISSUES) >/dev/null 2>&1
|
||||
endif
|
||||
else
|
||||
git -C $(GHISSUES_ROOT) push origin $(GH_ISSUES)
|
||||
endif # PUSH_GHPAGES
|
||||
-rm -rf $(GHISSUES_ROOT)
|
||||
|
||||
## Save issues.json to the CI_ARTIFACTS directory
|
||||
ifneq (,$(CI_ARTIFACTS))
|
||||
.PHONY: artifacts
|
||||
artifacts: issues.json pulls.json
|
||||
endif
|
||||
+188
@@ -0,0 +1,188 @@
|
||||
.PHONY: latest
|
||||
latest:: txt html
|
||||
|
||||
.DELETE_ON_ERROR:
|
||||
|
||||
LIBDIR ?= lib
|
||||
include $(LIBDIR)/config.mk
|
||||
include $(LIBDIR)/id.mk
|
||||
include $(LIBDIR)/ghpages.mk
|
||||
include $(LIBDIR)/issues.mk
|
||||
include $(LIBDIR)/upload.mk
|
||||
include $(LIBDIR)/update.mk
|
||||
|
||||
## Basic Targets
|
||||
.PHONY: txt html pdf
|
||||
txt:: $(drafts_txt)
|
||||
html:: $(drafts_html)
|
||||
pdf:: $(addsuffix .pdf,$(drafts))
|
||||
|
||||
## Basic Recipes
|
||||
.INTERMEDIATE: $(filter-out $(join $(drafts),$(draft_types)),$(addsuffix .xml,$(drafts)))
|
||||
|
||||
NOT_CURRENT = $(filter-out $(basename $<),$(drafts))
|
||||
ifneq (,$(MD_PREPROCESSOR))
|
||||
MD_PREPROCESSOR := | $(MD_PREPROCESSOR)
|
||||
endif
|
||||
ifneq (1,$(words $(drafts)))
|
||||
REMOVE_LATEST = | sed -e '$(join $(addprefix s/,$(addsuffix -latest/,$(NOT_CURRENT))), \
|
||||
$(addsuffix /g;,$(NOT_CURRENT)))'
|
||||
else
|
||||
REMOVE_LATEST =
|
||||
endif
|
||||
export XML_RESOURCE_ORG_PREFIX
|
||||
|
||||
%.xml: %.md
|
||||
@h=$$(head -1 $< | cut -c 1-4 -); set -o pipefail; \
|
||||
if [ "$${h:0:1}" = $$'\ufeff' ]; then echo 'warning: BOM in $<' 1>&2; h="$${h:1:3}"; \
|
||||
else h="$${h:0:3}"; fi; \
|
||||
if [ "$$h" = '---' ]; then \
|
||||
echo '$(subst ','"'"',cat $< $(MD_PREPROCESSOR) $(REMOVE_LATEST) | $(kramdown-rfc2629) > $@)'; \
|
||||
cat $< $(MD_PREPROCESSOR) $(REMOVE_LATEST) | $(kramdown-rfc2629) > $@; \
|
||||
elif [ "$$h" = '%%%' ]; then \
|
||||
echo '$(subst ','"'"',cat $< $(MD_PREPROCESSOR) $(REMOVE_LATEST) | $(mmark) -xml2 -page > $@)'; \
|
||||
cat $< $(MD_PREPROCESSOR) $(REMOVE_LATEST) | $(mmark) -xml2 -page > $@; \
|
||||
else \
|
||||
! echo "Unable to detect '%%%' or '---' in markdown file" 1>&2; \
|
||||
fi
|
||||
|
||||
ifdef REFCACHEDIR
|
||||
%.xml: .refcache
|
||||
.refcache: $(REFCACHEDIR)
|
||||
ln -s $< $@
|
||||
endif
|
||||
|
||||
%.xml: %.org
|
||||
$(oxtradoc) -m outline-to-xml -n "$@" $< > $@
|
||||
|
||||
XSLTDIR ?= $(LIBDIR)/rfc2629xslt
|
||||
ifeq (true,$(USE_XSLT))
|
||||
$(LIBDIR)/rfc2629.xslt: $(XSLTDIR)/rfc2629.xslt
|
||||
$(xsltproc) $(XSLTDIR)/to-1.0-xslt.xslt $< > $@
|
||||
|
||||
$(LIBDIR)/clean-for-DTD.xslt: $(LIBDIR)/rfc2629xslt/clean-for-DTD.xslt
|
||||
$(xsltproc) $(XSLTDIR)/to-1.0-xslt.xslt $< > $@
|
||||
|
||||
$(XSLTDIR)/clean-for-DTD.xslt $(XSLTDIR)/rfc2629.xslt: $(XSLTDIR)
|
||||
$(XSLTDIR):
|
||||
git clone --depth 10 $(CLONE_ARGS) -b master https://github.com/reschke/xml2rfc $@
|
||||
|
||||
%.cleanxml: %.xml $(LIBDIR)/clean-for-DTD.xslt $(LIBDIR)/rfc2629.xslt
|
||||
$(xsltproc) --novalid $(LIBDIR)/clean-for-DTD.xslt $< > $@
|
||||
|
||||
%.htmltmp: %.xml $(LIBDIR)/rfc2629.xslt
|
||||
$(xsltproc) --novalid $(LIBDIR)/rfc2629.xslt $< > $@
|
||||
|
||||
%.txt: %.cleanxml
|
||||
$(xml2rfc) $< -o $@ --text
|
||||
else
|
||||
%.htmltmp: %.xml
|
||||
$(xml2rfc) $< -o $@ --html
|
||||
|
||||
%.txt: %.xml
|
||||
$(xml2rfc) $< -o $@ --text
|
||||
endif
|
||||
|
||||
%.html: %.htmltmp $(LIBDIR)/addstyle.sed $(LIBDIR)/style.css
|
||||
# Note that the extra `echo` here is to work around a limitation in addstyle.sed
|
||||
ifneq (,$(if $(ENABLE_RIBBON),$(CI_REPO_FULL),))
|
||||
(cat $<;echo) | sed -f $(LIBDIR)/addstyle.sed -f $(LIBDIR)/addribbon.sed | \
|
||||
sed -e 's~{SLUG}~$(CI_REPO_FULL)~' > $@
|
||||
else
|
||||
(cat $<;echo) | sed -f $(LIBDIR)/addstyle.sed > $@
|
||||
endif
|
||||
|
||||
%.pdf: %.txt
|
||||
$(enscript) --margins 76::76: -B -q -p - $< | $(ps2pdf) - $@
|
||||
|
||||
## Build copies of drafts for submission
|
||||
.PHONY: submit
|
||||
submit:: $(drafts_next_txt) $(drafts_next_xml)
|
||||
|
||||
targets_file := .targets.mk
|
||||
targets_drafts := TARGETS_DRAFTS := $(drafts)
|
||||
targets_tags := TARGETS_TAGS := $(drafts_tags)
|
||||
|
||||
ifeq (,$(DISABLE_TARGETS_UPDATE))
|
||||
# Note that $(shell ) folds multiple lines into one, which is OK here.
|
||||
ifneq ($(targets_drafts) $(targets_tags),$(shell head -2 $(targets_file) 2>/dev/null))
|
||||
$(warning Forcing rebuild of $(targets_file))
|
||||
# Force an update of .targets.mk by setting a double-colon rule with no
|
||||
# prerequisites if the set of drafts or tags it contains is out of date.
|
||||
.PHONY: $(targets_file)
|
||||
endif
|
||||
endif # DISABLE_TARGETS_UPDATE
|
||||
|
||||
.SILENT: $(targets_file)
|
||||
$(targets_file): $(LIBDIR)/build-targets.sh
|
||||
echo "$(targets_drafts)" >$@
|
||||
echo "$(targets_tags)" >>$@
|
||||
$< $(drafts) >>$@
|
||||
include $(targets_file)
|
||||
|
||||
## Check for validity
|
||||
.PHONY: check idnits
|
||||
check:: idnits
|
||||
idnits:: $(drafts_next_txt)
|
||||
echo $^ | xargs -n 1 sh -c '$(idnits) $$0'
|
||||
|
||||
## Build diffs between the current draft versions and the most recent version
|
||||
draft_diffs := $(addprefix diff-,$(addsuffix .html,$(drafts_with_prev)))
|
||||
.PHONY: diff
|
||||
diff: $(draft_diffs)
|
||||
|
||||
## Generate a test report
|
||||
ifneq (,$(CIRCLE_TEST_REPORTS))
|
||||
TEST_REPORT := $(CIRCLE_TEST_REPORTS)/report/drafts.xml
|
||||
else
|
||||
TEST_REPORT := report.xml
|
||||
endif
|
||||
all_outputs := $(drafts_html) $(drafts_txt)
|
||||
.PHONY: report
|
||||
report: $(TEST_REPORT)
|
||||
$(TEST_REPORT):
|
||||
@echo build_report $^
|
||||
@mkdir -p $(dir $@)
|
||||
@echo '<?xml version="1.0" encoding="UTF-8"?>' >$@
|
||||
@passed=();failed=();for i in $(all_outputs); do \
|
||||
if [ -f "$$i" ]; then passed+=("$$i"); else failed+=("$$i"); fi; \
|
||||
done; echo '<testsuite' >>$@; \
|
||||
echo ' tests="'"$$(($${#passed[@]} + $${#failed[@]}))"'"' >>$@; \
|
||||
echo ' failures="'"$${#failed[@]}"'">' >>$@; \
|
||||
for i in "$${passed[@]}"; do \
|
||||
echo ' <testcase name="'"$$i"'" classname="build.'"$${i%.*}"'"/>' >>$@; \
|
||||
done; \
|
||||
for i in "$${failed[@]}"; do \
|
||||
echo ' <testcase name="'"$$i"'" classname="build.'"$${i%.*}"'">' >>$@; \
|
||||
echo ' <failure message="Error building file"/>' >>$@; \
|
||||
echo ' </testcase>' >>$@; \
|
||||
done; \
|
||||
echo '</testsuite>' >>$@
|
||||
|
||||
.PHONY: lint
|
||||
lint::
|
||||
@err=0; for f in $(join $(drafts),$(draft_types)); do \
|
||||
if [ ! -z "$$(tail -c 1 "$$f")" ]; then \
|
||||
echo "$$f has no newline on the last line"; err=1; \
|
||||
fi; \
|
||||
if grep -n $$' \r*$$' "$$f"; then \
|
||||
echo "$$f contains trailing whitespace"; err=1; \
|
||||
fi; \
|
||||
done; [ "$$err" -eq 0 ] || ! echo "Run 'make fix-lint' to automatically fix some errors" 1>&2
|
||||
|
||||
.PHONY: fix-lint
|
||||
fix-lint::
|
||||
for f in $(join $(drafts),$(draft_types)); do \
|
||||
[ -z "$$(tail -c 1 "$$f")" ] || echo >>"$$f"; \
|
||||
done
|
||||
sed -i~ -e 's/ *$$//' $(join $(drafts),$(draft_types))
|
||||
|
||||
## Cleanup
|
||||
COMMA := ,
|
||||
.PHONY: clean
|
||||
clean::
|
||||
-rm -f .tags $(targets_file) issues.json \
|
||||
$(addsuffix .{txt$(COMMA)html$(COMMA)pdf},$(drafts)) index.html \
|
||||
$(addsuffix -[0-9][0-9].{xml$(COMMA)md$(COMMA)org$(COMMA)txt$(COMMA)html$(COMMA)pdf},$(drafts)) \
|
||||
$(filter-out $(join $(drafts),$(draft_types)),$(addsuffix .xml,$(drafts))) \
|
||||
$(uploads) $(draft_diffs)
|
||||
@@ -0,0 +1,32 @@
|
||||
#!/bin/bash
|
||||
|
||||
exec 1>&2
|
||||
|
||||
BRANCH=$(git symbolic-ref --short HEAD 2>/dev/null)
|
||||
if [ "$BRANCH" = "gh-pages" -o "$BRANCH" = "gh-issues" -o -e .git/MERGE_HEAD ]; then
|
||||
exit
|
||||
fi
|
||||
|
||||
hash gmake 2> /dev/null && MAKE=gmake || MAKE=make
|
||||
|
||||
function abort() {
|
||||
echo "Commit refused: documents don't build successfully."
|
||||
echo "To commit anyway, run \"git commit --no-verify\""
|
||||
exit 1
|
||||
}
|
||||
trap abort ERR
|
||||
|
||||
files=($(git status --porcelain draft-* | sed '/^[MARCU]/{s/.*draft-/draft-/;p;};d' | sort))
|
||||
txtfiles=()
|
||||
tmpfiles=()
|
||||
trap 'rm -f "${tmpfiles[@]}" "${txtfiles[@]}"' EXIT
|
||||
for f in "${files[@]}"; do
|
||||
tmp="${f%.*}"-tmp$$."${f##*.}"
|
||||
tmpfiles+=("$tmp")
|
||||
txtfiles+=("${tmp%.*}.txt")
|
||||
# This makes a copy of the staged file.
|
||||
(git show :"$f" 2>/dev/null || cat "$f") > "$tmp"
|
||||
done
|
||||
[ "${#files[@]}" -eq 0 ] && exit 0
|
||||
|
||||
"$MAKE" txt lint "drafts=${tmpfiles[*]%.*}" DISABLE_TARGETS_UPDATE=true
|
||||
@@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
|
||||
err=0
|
||||
tags=0
|
||||
while read local_ref local_sha remote_ref remote_sha; do
|
||||
if [[ "${local_ref#refs/tags/draft-}" != "${local_ref}" ]]; then
|
||||
if [[ -z "$(git for-each-ref --format '%(taggeremail)' "${local_ref}")" ]]; then
|
||||
echo "pre-push: tag ${local_ref#refs/tags/} is not an annotated tag" 1>&2
|
||||
err=1
|
||||
fi
|
||||
tags=$((tags+1))
|
||||
fi
|
||||
done
|
||||
if [[ $tags -gt 1 ]]; then
|
||||
echo "pre-push: more than one tag pushed, which circle doesn't currently handle" 1>&2
|
||||
err=2
|
||||
fi
|
||||
[[ $err -eq 0 ]] || echo "pre-push: use git push --no-verify to override this check" 1>&2
|
||||
exit $err
|
||||
@@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
branch="$1"
|
||||
shift
|
||||
|
||||
if git show-ref -s "$branch" >/dev/null 2>&1; then
|
||||
echo "The $branch branch already exists, skipping setup."
|
||||
exit
|
||||
fi
|
||||
|
||||
tmp=$(mktemp -d /tmp/init-branch-"$branch"-XXXXX)
|
||||
function cleanup() {
|
||||
rm -rf "$tmp"
|
||||
}
|
||||
trap cleanup ERR EXIT
|
||||
|
||||
echo "Initializing $branch branch"
|
||||
git clone -n . "$tmp"
|
||||
git -C "$tmp" checkout -q --orphan "$branch"
|
||||
git -C "$tmp" rm -rfq .
|
||||
|
||||
echo Creating .gitignore and initial files
|
||||
echo lib > "$tmp"/.gitignore
|
||||
echo venv >> "$tmp"/.gitignore
|
||||
echo .refcache >> "$tmp"/.gitignore
|
||||
for f in "$@"; do
|
||||
touch "$tmp"/"$f"
|
||||
done
|
||||
|
||||
echo Commit and push to origin/"$branch"
|
||||
user=()
|
||||
git config --global --get user.name >/dev/null || user+=(-c user.name='ID Bot')
|
||||
git config --global --get user.email >/dev/null || user+=(-c user.email='idbot@example.com')
|
||||
|
||||
git -C "$tmp" add .gitignore "$@"
|
||||
git -C "$tmp" "${user[@]}" commit -m "Automatic setup of $branch."
|
||||
git -C "$tmp" push origin "$branch"
|
||||
git push --set-upstream origin "$branch"
|
||||
@@ -0,0 +1,91 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Usage: $0 <user> <repo> [draftxml ...]
|
||||
|
||||
user="$1"
|
||||
repo="$2"
|
||||
shift 2
|
||||
|
||||
githubio="https://${user}.github.io/${repo}/#go"
|
||||
|
||||
function fixup_other_md() {
|
||||
markdown=(LICENSE.md CONTRIBUTING.md)
|
||||
s='s~{WG_NAME}~'"$1"'~g'
|
||||
s="$s"';s~{GITHUB_USER}~'"$user"'~g'
|
||||
s="$s"';s~{GITHUB_REPO}~'"$repo"'~g'
|
||||
sed -i~ -e "$s" "${markdown[@]}"
|
||||
for i in "${markdown[@]}"; do
|
||||
rm -f "$i"~
|
||||
done
|
||||
}
|
||||
|
||||
function get_title() {
|
||||
if hash xmllint >/dev/null 2>&1; then
|
||||
title=($(xmllint --xpath '/rfc/front/title/text()' "$1"))
|
||||
else
|
||||
# sed kludge if xmllint isn't available
|
||||
title=($(sed -e '/<title[^>]*>/,/<\/title>/{s/.*<title[^>]*>//;/<\/title>/{s/<\/title>.*//;H;x;q;};H;};d' "$1"))
|
||||
fi
|
||||
# haxx: rely on bash parameter normalization to remove redundant whitespace
|
||||
echo "${title[*]}"
|
||||
}
|
||||
|
||||
first=true
|
||||
for d in "$@"; do
|
||||
fullname="${d%.xml}"
|
||||
author=$(echo "${fullname}" | cut -f 2 -d - -)
|
||||
wg=$(echo "${fullname}" | cut -f 3 -d - -)
|
||||
wgupper=$(echo "${wg}" | tr 'a-z' 'A-Z')
|
||||
title=$(get_title "$d")
|
||||
|
||||
if "$first"; then
|
||||
fixup_other_md "$wg"
|
||||
|
||||
if [ "$author" = "ietf" ]; then
|
||||
status="Working Group"
|
||||
status_full="IETF [${wgupper} Working Group](https://datatracker.ietf.org/wg/${wg}/documents/) Internet-Draft"
|
||||
else
|
||||
status="Individual"
|
||||
status_full="individual Internet-Draft"
|
||||
fi
|
||||
if [ $# -gt 1 ]; then
|
||||
echo "# ${wgupper} Drafts"
|
||||
status_full="${status_full}s"
|
||||
else
|
||||
echo "# $title"
|
||||
status_full="the ${status_full}, \"${title}\""
|
||||
fi
|
||||
echo
|
||||
echo "This is the working area for ${status_full}."
|
||||
first=false
|
||||
fi
|
||||
|
||||
if [ $# -gt 1 ]; then
|
||||
echo
|
||||
echo "## $title"
|
||||
fi
|
||||
echo
|
||||
echo "* [Editor's Copy](${githubio}.${fullname}.html)"
|
||||
echo "* [${status} Draft](https://tools.ietf.org/html/${fullname})"
|
||||
echo "* [Compare Editor's Copy to ${status} Draft](${githubio}.${fullname}.diff)"
|
||||
done
|
||||
|
||||
cat <<EOF
|
||||
|
||||
## Building the Draft
|
||||
|
||||
Formatted text and HTML versions of the draft can be built using \`make\`.
|
||||
|
||||
\`\`\`sh
|
||||
$ make
|
||||
\`\`\`
|
||||
|
||||
This requires that you have the necessary software installed. See
|
||||
[the instructions](https://github.com/martinthomson/i-d-template/blob/master/doc/SETUP.md).
|
||||
|
||||
|
||||
## Contributing
|
||||
|
||||
See the
|
||||
[guidelines for contributions](https://github.com/${user}/${repo}/blob/master/CONTRIBUTING.md).
|
||||
EOF
|
||||
@@ -0,0 +1,88 @@
|
||||
.PHONY: setup
|
||||
setup: setup-master setup-ghpages setup-precommit
|
||||
|
||||
LIBDIR ?= lib
|
||||
include $(LIBDIR)/main.mk
|
||||
|
||||
# Check that everything is ready
|
||||
ifeq (,$(wildcard .git))
|
||||
$(error Please make sure that this is a git repository by running "git init")
|
||||
endif
|
||||
GIT_ORIG := $(shell git branch 2>/dev/null | grep '*' | cut -c 3-)
|
||||
ifneq (1,$(words $(GIT_ORIG)))
|
||||
$(error If you are just starting out, please commit something before starting)
|
||||
endif
|
||||
ifneq (master,$(GIT_ORIG))
|
||||
$(warning Using a branch called 'master' is recommended)
|
||||
endif
|
||||
|
||||
LATEST_WARNING := $(strip $(foreach draft,$(join $(drafts),$(draft_types)),\
|
||||
$(shell grep -q $(basename $(draft))-latest $(draft) || \
|
||||
echo $(draft) should include a name of $(basename $(draft))-latest. )))
|
||||
ifneq (,$(LATEST_WARNING))
|
||||
$(warning Check names: $(LATEST_WARNING))
|
||||
endif
|
||||
ifneq (,$(strip $(shell git status -s --porcelain 2>/dev/null | egrep -v '^.. (.targets.mk|$(LIBDIR)/?|$(LIBDIR)/.template-files.mk)$$')))
|
||||
$(error You have uncommitted changes or untracked files, please commit them before running setup)
|
||||
endif
|
||||
ifneq ($(GIT_REMOTE),$(shell git remote 2>/dev/null | grep '^$(GIT_REMOTE)$$'))
|
||||
$(error Please configure a remote called '$(GIT_REMOTE)' before running setup)
|
||||
endif
|
||||
ifeq (,$(shell git show-ref $(GIT_REMOTE)/$(GIT_ORIG)))
|
||||
$(error Please push the '$(GIT_ORIG)' branch to '$(GIT_REMOTE)', e.g., "git push $(GIT_REMOTE) $(GIT_ORIG)")
|
||||
endif
|
||||
|
||||
TEMPLATE_FILES := \
|
||||
Makefile .gitignore \
|
||||
CONTRIBUTING.md LICENSE.md \
|
||||
.travis.yml .circleci/config.yml
|
||||
|
||||
TEMPLATE_FILE_MK := $(LIBDIR)/.template-files.mk
|
||||
include $(TEMPLATE_FILE_MK)
|
||||
$(TEMPLATE_FILE_MK): $(LIBDIR)/setup.mk
|
||||
@echo '# Automatically generated setup rules' >$@
|
||||
@$(foreach f,$(TEMPLATE_FILES),\
|
||||
echo $(f): $(LIBDIR)/template/$(f) >>$@;\
|
||||
echo ' mkdir -p $$(dir $$@)' >>$@;\
|
||||
echo ' -cp $$< $$@' >>$@;)
|
||||
|
||||
.PHONY: setup-files
|
||||
setup-files: $(TEMPLATE_FILES) README.md
|
||||
git add $(join $(drafts),$(draft_types))
|
||||
git add $^
|
||||
|
||||
ifeq (true,$(USE_XSLT))
|
||||
setup-master: setup-makefile
|
||||
.PHONY: setup-makefile
|
||||
setup-makefile: Makefile
|
||||
sed -i~ -e '1{h;s/^.*$$/USE_XSLT := true/;p;x;}' $<
|
||||
@-rm -f $<~
|
||||
git add $<
|
||||
endif # USE_XSLT
|
||||
|
||||
.PHONY: setup-gitignore
|
||||
setup-gitignore: .gitignore $(LIBDIR)/template/.gitignore
|
||||
tmp=`mktemp`; cat $^ | sort -u >$$tmp && mv -f $$tmp $<
|
||||
ifndef SUBMODULE
|
||||
echo $(LIBDIR) >>$<
|
||||
endif
|
||||
$(foreach x,$(filter-out .xml,$(join $(drafts),$(draft_types))),\
|
||||
echo $(basename $(x)).xml >>$<;)
|
||||
git add $<
|
||||
|
||||
README.md: $(LIBDIR)/setup-readme.sh $(drafts_xml) $(filter %.md, $(TEMPLATE_FILES))
|
||||
$(LIBDIR)/setup-readme.sh $(GITHUB_USER) $(GITHUB_REPO) $(filter %.xml,$^) >$@
|
||||
git add $@ $(filter %.md, $(TEMPLATE_FILES))
|
||||
|
||||
.PHONY: setup-master
|
||||
setup-master: setup-files README.md setup-gitignore
|
||||
git $(CI_AUTHOR) commit -m "Setup repository for $(firstword $(drafts)) using https://github.com/martinthomson/i-d-template"
|
||||
|
||||
.PHONY: setup-precommit
|
||||
setup-precommit: .git/hooks/pre-commit
|
||||
.git/hooks/pre-commit:
|
||||
-ln -s ../../lib/pre-commit.sh $@
|
||||
|
||||
.PHONY: setup-ghpages
|
||||
setup-ghpages:
|
||||
$(LIBDIR)/setup-branch.sh gh-pages index.html issues.json pulls.json
|
||||
@@ -0,0 +1,268 @@
|
||||
|
||||
body {
|
||||
font: 16px "Helvetica Neue","Open Sans",Helvetica,Calibri,sans-serif;
|
||||
color: #333;
|
||||
font-size-adjust: 0.5;
|
||||
line-height: 24px;
|
||||
margin: 75px auto;
|
||||
max-width: 624px;
|
||||
padding: 0 5px;
|
||||
}
|
||||
|
||||
.title, .filename, h1, h2, h3, h4, h5 {
|
||||
font: 16px "Roboto Condensed","Helvetica Neue","Open Sans",Helvetica,Calibri,sans-serif;
|
||||
font-size-adjust: 0.5;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
line-height: 100%;
|
||||
margin: 1.2em 0 0.3em;
|
||||
}
|
||||
.title, #rfc\.title h1 { font-size: 32px; }
|
||||
h1, section h1, h2, section h2, section h3, nav h2 { font-size: 20px; }
|
||||
h3, section h4, h4, section h5 { font-size: 16px; }
|
||||
h1 a[href], h2 a[href], h3 a[href], h4 a[href] {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
table {
|
||||
margin-left: 0em;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
th {
|
||||
text-align: left;
|
||||
border-bottom: 2px solid #ddd;
|
||||
}
|
||||
td {
|
||||
border-top: 1px solid #ddd;
|
||||
vertical-align: top;
|
||||
}
|
||||
tr:nth-child(2n+1) > td,
|
||||
tr:nth-child(2n+1) > th {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
td.reference {
|
||||
max-width: 200px;
|
||||
border-top: none;
|
||||
padding-right: 1em;
|
||||
}
|
||||
.right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
|
||||
table.header, table#rfc\.headerblock {
|
||||
width: 100%;
|
||||
}
|
||||
table.header td, table#rfc\.headerblock td {
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
color: black;
|
||||
padding: 0;
|
||||
}
|
||||
.filename {
|
||||
display: block;
|
||||
color: rgb(119, 119, 119);
|
||||
font-size: 20px;
|
||||
font-weight: normal;
|
||||
line-height: 100%;
|
||||
margin: 10px 0 32px;
|
||||
}
|
||||
#rfc\.abstract+p, #rfc\.abstract+p code, #rfc\.abstract+p samp, #rfc\.abstract+p tt {
|
||||
font-size: 20px;
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
samp, tt, code, pre, span.tt {
|
||||
font-size: 13.5px;
|
||||
font-family: Consolas, monospace;
|
||||
font-size-adjust: none;
|
||||
}
|
||||
pre {
|
||||
background-color: #eee;
|
||||
border: 1px solid #ddd;
|
||||
overflow-x: auto;
|
||||
padding: 5px;
|
||||
margin: 5px;
|
||||
}
|
||||
.figure, caption {
|
||||
font-style: italic;
|
||||
margin: 0 1.5em;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
address {
|
||||
margin: 16px 2px;
|
||||
line-height: 20px;
|
||||
}
|
||||
.vcard {
|
||||
font-style: normal;
|
||||
}
|
||||
.vcardline {
|
||||
display: block;
|
||||
}
|
||||
.vcardline .fn, address b {
|
||||
font-weight: normal;
|
||||
}
|
||||
.vcardline .hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
dl {
|
||||
margin-left: 1em;
|
||||
}
|
||||
dl.dl-horizontal: {
|
||||
margin-left: 0;
|
||||
}
|
||||
dl > dt {
|
||||
float: left;
|
||||
margin-right: 1em;
|
||||
}
|
||||
dl.nohang > dt {
|
||||
float: none;
|
||||
}
|
||||
dl > dd {
|
||||
margin-bottom: .5em;
|
||||
}
|
||||
dl.compact > dd {
|
||||
margin-bottom: 0em;
|
||||
}
|
||||
dl > dd > dl {
|
||||
margin-top: 0.5em;
|
||||
margin-bottom: 0em;
|
||||
}
|
||||
ul.empty {
|
||||
list-style-type: none;
|
||||
}
|
||||
ul.empty li {
|
||||
margin-top: .5em;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 0;
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
hr.noprint {
|
||||
display: none;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
a[href] {
|
||||
color: #2a6496;
|
||||
}
|
||||
a[href]:hover {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
p, ol, ul, li {
|
||||
padding: 0;
|
||||
}
|
||||
p {
|
||||
margin: 0.5em 0;
|
||||
}
|
||||
ol, ul {
|
||||
margin: 0.2em 0 0.2em 2em;
|
||||
}
|
||||
li {
|
||||
margin: 0.2em 0;
|
||||
}
|
||||
address {
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
ul.toc ul {
|
||||
margin: 0 0 0 2em;
|
||||
}
|
||||
ul.toc li {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 924px) {
|
||||
body {
|
||||
padding-right: 350px;
|
||||
}
|
||||
body>ul.toc, body>#rfc\.toc {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
right: calc(50vw - 500px);
|
||||
width: 300px;
|
||||
z-index: 1;
|
||||
overflow: auto;
|
||||
overscroll-behavior: contain;
|
||||
}
|
||||
body>#rfc\.toc {
|
||||
top: 55px;
|
||||
}
|
||||
body>ul.toc {
|
||||
top: 100px;
|
||||
}
|
||||
|
||||
ul.toc {
|
||||
margin: 0 0 0 4px;
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
}
|
||||
ul.toc ul {
|
||||
margin-left: 1.2em;
|
||||
}
|
||||
}
|
||||
|
||||
.github-fork-ribbon-wrapper {
|
||||
display: none;
|
||||
}
|
||||
@media screen and (min-width: 800px) {
|
||||
/* "Fork me on GitHub" CSS ribbon based on
|
||||
* https://github.com/simonwhitaker/github-fork-ribbon-css
|
||||
*/
|
||||
.github-fork-ribbon {
|
||||
position: absolute;
|
||||
padding: 2px 0;
|
||||
background-color: #a00;
|
||||
background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15));
|
||||
box-shadow: 0 2px 3px 0 rgba(0, 0, 0, 0.5);
|
||||
font: 700 12px "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
|
||||
pointer-events: auto;
|
||||
|
||||
top: 38px;
|
||||
right: -45px;
|
||||
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.github-fork-ribbon a[href],
|
||||
.github-fork-ribbon a[href]:hover {
|
||||
color: #fff;
|
||||
background-color: transparent;
|
||||
text-decoration: none;
|
||||
text-shadow: 0 -1px rgba(0, 0, 0, 0.5);
|
||||
text-align: center;
|
||||
|
||||
width: 190px;
|
||||
line-height: 18px;
|
||||
|
||||
display: inline-block;
|
||||
padding: 2px 0;
|
||||
|
||||
border: 1.5px dotted #fff;
|
||||
border-color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
.github-fork-ribbon-wrapper {
|
||||
display: block;
|
||||
width: 130px;
|
||||
height: 130px;
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
top: 0; right: 0;
|
||||
z-index: 2;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
@media screen and (min-width: 1000px) {
|
||||
.github-fork-ribbon-wrapper {
|
||||
position: fixed;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
# Contributing
|
||||
|
||||
This repository relates to activities in the Internet Engineering Task Force
|
||||
([IETF](https://www.ietf.org/)). All material in this repository is considered
|
||||
Contributions to the IETF Standards Process, as defined in the intellectual
|
||||
property policies of IETF currently designated as
|
||||
[BCP 78](https://www.rfc-editor.org/info/bcp78),
|
||||
[BCP 79](https://www.rfc-editor.org/info/bcp79) and the
|
||||
[IETF Trust Legal Provisions (TLP) Relating to IETF Documents](http://trustee.ietf.org/trust-legal-provisions.html).
|
||||
|
||||
Any edit, commit, pull request, issue, comment or other change made to this
|
||||
repository constitutes Contributions to the IETF Standards Process
|
||||
(https://www.ietf.org/).
|
||||
|
||||
You agree to comply with all applicable IETF policies and procedures, including,
|
||||
BCP 78, 79, the TLP, and the TLP rules regarding code components (e.g. being
|
||||
subject to a Simplified BSD License) in Contributions.
|
||||
|
||||
|
||||
## Other Resources
|
||||
|
||||
Discussion of this work occurs on the
|
||||
[{WG_NAME} working group mailing list](https://mailarchive.ietf.org/arch/browse/{WG_NAME}/)
|
||||
([subscribe](https://www.ietf.org/mailman/listinfo/{WG_NAME})). In addition to
|
||||
contributions in GitHub, you are encouraged to participate in discussions there.
|
||||
|
||||
**Note**: Some working groups adopt a policy whereby substantive discussion of
|
||||
technical issues needs to occur on the mailing list.
|
||||
|
||||
You might also like to familiarize yourself with other
|
||||
[working group documents](https://datatracker.ietf.org/wg/{WG_NAME}/documents/).
|
||||
@@ -0,0 +1,4 @@
|
||||
# License
|
||||
|
||||
See the
|
||||
[guidelines for contributions](https://github.com/{GITHUB_USER}/{GITHUB_REPO}/blob/master/CONTRIBUTING.md).
|
||||
@@ -0,0 +1,11 @@
|
||||
LIBDIR := lib
|
||||
include $(LIBDIR)/main.mk
|
||||
|
||||
$(LIBDIR)/main.mk:
|
||||
ifneq (,$(shell grep "path *= *$(LIBDIR)" .gitmodules 2>/dev/null))
|
||||
git submodule sync
|
||||
git submodule update $(CLONE_ARGS) --init
|
||||
else
|
||||
git clone -q --depth 10 $(CLONE_ARGS) \
|
||||
-b master https://github.com/martinthomson/i-d-template $(LIBDIR)
|
||||
endif
|
||||
@@ -0,0 +1,62 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Issue Viewer</title>
|
||||
<script src="issues.js"></script>
|
||||
<style>
|
||||
body { font-family: sans-serif; font-size: 15px; }
|
||||
table { border: 1px solid #ddd; border-collapse: collapse; }
|
||||
td, th { border: 1px solid #eee; padding: 5px 1px; text-align: left; vertical-align: top; }
|
||||
td .extra { display: none; max-width: 600px; overflow: auto; margin-top: 5px; }
|
||||
td.id { text-align: right; }
|
||||
td.active .extra { display: block; }
|
||||
td.label span { display: inline-block; margin: 0 2px; padding: 1px 3px; font-size: 12px;
|
||||
overflow: hidden; text-overflow: ellipsis; max-width: 64px; white-space: nowrap; }
|
||||
td.user a { display: inline-block; text-decoration: none; vertical-align: middle; margin: 2px;
|
||||
font-weight: bold; font-size: 12px; color: black; }
|
||||
td.user a:hover { text-decoration: underline; }
|
||||
td.user a.short { overflow:hidden; max-width: 32px; }
|
||||
td.label span, td.user img { border-radius: 2px; vertical-align: middle; }
|
||||
.hidden { display: none; }
|
||||
.warning { font-weight: bold; padding 2px 10px; }
|
||||
code { background-color: #eee; white-space: nowrap; }
|
||||
#cmd { width: 600px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<label for="cmd">Filter:</label>
|
||||
<input id="cmd" name="cmd" type="search" autofocus
|
||||
placeholder="type '/help' to show filter syntax">
|
||||
<span id="status"><span id="count"></span> records</span>
|
||||
</div>
|
||||
<div id="help">
|
||||
<p>This page shows GitHub issues in a simple form.</p>
|
||||
<p>The filter box above accepts a set of filters, each separated by
|
||||
space.</p>
|
||||
<ul id="functions">
|
||||
</ul>
|
||||
<p>You can also type <tt>/local</tt> to reload the file, or <tt>/remote
|
||||
<user> <repo></tt> to load a new set of issues from GitHub
|
||||
(only works online). You can <tt>/sort</tt> on <tt>id</tt>
|
||||
or <tt>recent</tt>.</p>
|
||||
</div>
|
||||
<div id="display">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Title</th>
|
||||
<th>State</th>
|
||||
<th>User</th>
|
||||
<th>Assignee</th>
|
||||
<th>Labels</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="tbody">
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,605 @@
|
||||
function setStatus(msg) {
|
||||
let status = document.getElementById('status');
|
||||
status.innerText = msg;
|
||||
}
|
||||
|
||||
var sortKey = 'id';
|
||||
function sort(k) {
|
||||
k = k || sortKey;
|
||||
if (k === 'id') {
|
||||
issues.sort((x, y) => x.number - y.number);
|
||||
setStatus('sorted by ID');
|
||||
} else if (k === 'recent') {
|
||||
issues.sort((x, y) => Date.parse(y.updated_at) - Date.parse(x.updated_at));
|
||||
setStatus('sorted by last modified');
|
||||
} else {
|
||||
setStatus('no idea how to sort like that');
|
||||
return;
|
||||
}
|
||||
sortKey = k;
|
||||
}
|
||||
|
||||
function getNext(response) {
|
||||
const link = response.headers.get('link');
|
||||
if (!link) {
|
||||
return;
|
||||
}
|
||||
|
||||
const m = link.match(/^<([^>]*)>\s*;[^,]*rel="?next"?/);
|
||||
if (!m) {
|
||||
return;
|
||||
}
|
||||
return m[1];
|
||||
}
|
||||
|
||||
function buildUrl(wg, repo, type) {
|
||||
if (wg && repo) {
|
||||
console.log(`loading remote ${type} for ${wg}/${repo}`);
|
||||
return `https://api.github.com/repos/${wg}/${repo}/${type}?state=all`;
|
||||
}
|
||||
return `${type}.json`;
|
||||
}
|
||||
|
||||
async function getAll(url) {
|
||||
let records = [];
|
||||
do {
|
||||
const response = await fetch(url);
|
||||
if (Math.floor(response.status / 100) !== 2) {
|
||||
throw new Error(`Error loading <${url}>: ${response.status}`);
|
||||
}
|
||||
records = records.concat(await response.json());
|
||||
url = getNext(response);
|
||||
} while (url);
|
||||
return records;
|
||||
}
|
||||
|
||||
var issues;
|
||||
|
||||
async function get(wg, repo) {
|
||||
issues = null;
|
||||
var pulls = null;
|
||||
[issues, pulls] = await Promise.all(
|
||||
['issues', 'pulls'].map(type => getAll(buildUrl(wg, repo, type))));
|
||||
issues.forEach(issue => {
|
||||
if (issue.pull_request) {
|
||||
let pull = pulls.find(x => x.url == issue.pull_request.url);
|
||||
if (pull) {
|
||||
issue.pull_request = pull;
|
||||
}
|
||||
}
|
||||
});
|
||||
sort();
|
||||
let m = issues[0].html_url.match(/^https:\/\/github\.com\/([^\/]+)\/([^\/]+)\//);
|
||||
if (m) {
|
||||
document.title = m[1] + '/' + m[2] + ' Issues';
|
||||
}
|
||||
console.log('loaded all issues');
|
||||
console.log('Raw data for issues can be found in:');
|
||||
console.log(' window.issues = all issues');
|
||||
console.log(' window.subset = just the subset of issues that are shown');
|
||||
console.log('format(subset[, formatter]) to dump the current subset to the console');
|
||||
}
|
||||
|
||||
var issueFilters = {
|
||||
assigned: {
|
||||
args: [],
|
||||
h: 'has an assignee',
|
||||
f: issue => issue.assignees.length > 0,
|
||||
},
|
||||
|
||||
assigned_to: {
|
||||
args: ['string'],
|
||||
h: 'assigned to a specific user',
|
||||
f: login => issue => issue.assignees.some(assignee => assignee.login === login),
|
||||
},
|
||||
|
||||
created_by: {
|
||||
args: ['string'],
|
||||
h: 'created by a specific user',
|
||||
f: login => issue => issue.user.login === login,
|
||||
},
|
||||
|
||||
closed: {
|
||||
args: [],
|
||||
h: 'is closed',
|
||||
f: issue => issue.closed_at,
|
||||
},
|
||||
|
||||
open: {
|
||||
args: [],
|
||||
h: 'is open',
|
||||
f: issue => !issue.closed_at,
|
||||
},
|
||||
|
||||
merged: {
|
||||
args: [],
|
||||
h: 'a merged pull request',
|
||||
f: issue => issue.pull_request && issue.pull_request.merged_at,
|
||||
},
|
||||
|
||||
discarded: {
|
||||
args: [],
|
||||
h: 'a discarded pull request',
|
||||
f: issue => issue.pull_request && !issue.pull_request.merged_at && issue.closed_at
|
||||
},
|
||||
|
||||
n: {
|
||||
args: ['integer'],
|
||||
h: 'issue by number',
|
||||
f: i => issue => issue.number === i,
|
||||
},
|
||||
|
||||
label: {
|
||||
args: ['string'],
|
||||
h: 'has a specific label',
|
||||
f: name => issue => issue.labels.some(label => label.name === name),
|
||||
},
|
||||
|
||||
labelled: {
|
||||
args: [],
|
||||
h: 'has any label',
|
||||
f: issue => issue.labels.length > 0,
|
||||
},
|
||||
|
||||
title: {
|
||||
args: ['string'],
|
||||
h: 'search title with a regular expression',
|
||||
f: function(re) {
|
||||
re = new RegExp(re);
|
||||
return issue => issue.title.match(re);
|
||||
}
|
||||
},
|
||||
|
||||
body: {
|
||||
args: ['string'],
|
||||
h: 'search body with a regular expression',
|
||||
f: function(re) {
|
||||
re = new RegExp(re);
|
||||
return issue => issue.body.match(re);
|
||||
}
|
||||
},
|
||||
|
||||
text: {
|
||||
args: ['string'],
|
||||
h: 'search title and body with a regular expression',
|
||||
f: function(re) {
|
||||
re = new RegExp(re);
|
||||
return issue => issue.title.match(re) || issue.body.match(re);
|
||||
}
|
||||
},
|
||||
|
||||
pr: {
|
||||
args: [],
|
||||
h: 'is a pull request',
|
||||
f: issue => issue.pull_request,
|
||||
},
|
||||
|
||||
issue: {
|
||||
args: [],
|
||||
h: 'is a plain issue, i.e., not(pr)',
|
||||
f: function(issue) {
|
||||
return !issue.pull_request;
|
||||
}
|
||||
},
|
||||
|
||||
or: {
|
||||
args: ['filter', '...filter'],
|
||||
h: 'union',
|
||||
f: (...filters) => x => filters.some(filter => filter(x)),
|
||||
},
|
||||
|
||||
and: {
|
||||
args: ['filter', '...filter'],
|
||||
h: 'intersection',
|
||||
f: (...filters) => x => filters.every(filter => filter(x)),
|
||||
},
|
||||
|
||||
|
||||
xor: {
|
||||
args: ['filter', '...filter'],
|
||||
h: 'for the insane',
|
||||
f: (...filters) =>
|
||||
x => filters.slice(1).reduce((a, filter) => a ^ filter(x), filters[0](x)),
|
||||
},
|
||||
|
||||
not: {
|
||||
args: ['filter'],
|
||||
h: 'exclusion',
|
||||
f: a => issue => !a(issue),
|
||||
},
|
||||
|
||||
closed_since: {
|
||||
args: ['date'],
|
||||
h: 'issues closed since the date and time',
|
||||
f: since => issue => Date.parse(issue.closed_at) >= since,
|
||||
},
|
||||
|
||||
updated_since: {
|
||||
args: ['date'],
|
||||
h: 'issues updated since the date and time',
|
||||
f: since => issue => Date.parse(issue.updated_at) >= since,
|
||||
}
|
||||
};
|
||||
|
||||
class Parser {
|
||||
constructor(s) {
|
||||
this.str = s;
|
||||
this.skipws();
|
||||
}
|
||||
|
||||
skipws() {
|
||||
this.str = this.str.trimLeft();
|
||||
}
|
||||
|
||||
jump(idx) {
|
||||
this.str = this.str.slice(idx);
|
||||
this.skipws();
|
||||
}
|
||||
|
||||
get next() {
|
||||
return this.str.charAt(0);
|
||||
}
|
||||
|
||||
parseName() {
|
||||
let m = this.str.match(/^[a-zA-Z](?:[a-zA-Z0-9_-]*[a-zA-Z0-9])?/);
|
||||
if (!m) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.jump(m[0].length);
|
||||
return m[0];
|
||||
}
|
||||
|
||||
parseSeparator(separator) {
|
||||
if (this.next !== separator) {
|
||||
throw new Error(`Expecting separator ${separator}`);
|
||||
}
|
||||
this.jump(1);
|
||||
}
|
||||
|
||||
parseString() {
|
||||
let end = -1;
|
||||
for (let i = 0; i < this.str.length; ++i) {
|
||||
let v = this.str.charAt(i);
|
||||
if (v === ')' || v === ',') {
|
||||
end = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (end < 0) {
|
||||
throw new Error(`Unterminated string`);
|
||||
}
|
||||
let s = this.str.slice(0, end).trim();
|
||||
this.jump(end);
|
||||
return s;
|
||||
}
|
||||
|
||||
parseDate() {
|
||||
let str = this.parseString();
|
||||
let time = Date.parse(str);
|
||||
if (isNaN(time)) {
|
||||
throw new Error(`not a valid date: ${str}`);
|
||||
}
|
||||
return time;
|
||||
}
|
||||
|
||||
parseNumber() {
|
||||
let m = this.str.match(/^\d+/);
|
||||
if (!m) {
|
||||
return;
|
||||
}
|
||||
this.jump(m[0].length);
|
||||
return parseInt(m[0], 10);
|
||||
}
|
||||
|
||||
parseFilter() {
|
||||
let name = this.parseName();
|
||||
if (!name) {
|
||||
let n = this.parseNumber();
|
||||
if (!isNaN(n)) {
|
||||
return issueFilters.n.f.call(null, n);
|
||||
}
|
||||
return;
|
||||
}
|
||||
let f = issueFilters[name];
|
||||
if (!f) {
|
||||
throw new Error(`Unknown filter: ${name}`);
|
||||
}
|
||||
if (f.args.length === 0) {
|
||||
return f.f;
|
||||
}
|
||||
let args = [];
|
||||
for (let i = 0; i < f.args.length; ++i) {
|
||||
let arg = f.args[i];
|
||||
let ellipsis = arg.slice(0, 3) === '...';
|
||||
if (ellipsis) {
|
||||
arg = arg.slice(3);
|
||||
}
|
||||
|
||||
this.parseSeparator((i === 0) ? '(' : ',');
|
||||
if (arg === 'string') {
|
||||
args.push(this.parseString());
|
||||
} else if (arg === 'date') {
|
||||
args.push(this.parseDate());
|
||||
} else if (arg === 'integer') {
|
||||
args.push(this.parseNumber());
|
||||
} else if (arg === 'filter') {
|
||||
args.push(this.parseFilter());
|
||||
} else {
|
||||
throw new Error(`Error in filter ${name} definition`);
|
||||
}
|
||||
if (ellipsis && this.next === ',') {
|
||||
--i;
|
||||
}
|
||||
}
|
||||
this.parseSeparator(')');
|
||||
return f.f.apply(null, args);
|
||||
}
|
||||
}
|
||||
|
||||
var subset = [];
|
||||
function filterIssues(str) {
|
||||
subset = issues;
|
||||
let parser = new Parser(str);
|
||||
let f = parser.parseFilter();
|
||||
while (f) {
|
||||
subset = subset.filter(f);
|
||||
f = parser.parseFilter();
|
||||
}
|
||||
}
|
||||
|
||||
var formatter = {
|
||||
brief: x => `* ${x.title} (#${x.number})`,
|
||||
md: x => `* [#${x.number}](${x.html_url}): ${x.title}`,
|
||||
};
|
||||
|
||||
function format(set, f) {
|
||||
return (set || subset).map(f || formatter.brief).join('\n');
|
||||
}
|
||||
|
||||
var debounces = {};
|
||||
var debounceSlowdown = 100;
|
||||
function measureSlowdown() {
|
||||
let start = Date.now();
|
||||
window.setTimeout(_ => {
|
||||
let diff = Date.now() - start;
|
||||
if (diff > debounceSlowdown) {
|
||||
console.log(`slowed to ${diff} ms`);
|
||||
debounceSlowdown = Math.min(1000, diff + debounceSlowdown / 2);
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
function debounce(f) {
|
||||
let r = now => {
|
||||
measureSlowdown();
|
||||
f(now);
|
||||
};
|
||||
return e => {
|
||||
if (debounces[f.name]) {
|
||||
window.clearTimeout(debounces[f.name]);
|
||||
delete debounces[f.name];
|
||||
}
|
||||
if (e.key === "Enter") {
|
||||
r(true);
|
||||
} else {
|
||||
debounces[f.name] = window.setTimeout(_ => {
|
||||
delete debounces[f.name];
|
||||
r(false)
|
||||
}, 10 + debounceSlowdown);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function makeRow(issue) {
|
||||
function cellID() {
|
||||
let td = document.createElement('td');
|
||||
td.className = 'id';
|
||||
let a = document.createElement('a');
|
||||
a.href = issue.html_url;
|
||||
a.innerText = issue.number;
|
||||
td.appendChild(a);
|
||||
return td;
|
||||
}
|
||||
|
||||
function cellTitle() {
|
||||
let td = document.createElement('td');
|
||||
let div = document.createElement('div');
|
||||
div.innerText = issue.title;
|
||||
div.onclick = e => e.target.parentNode.classList.toggle('active');
|
||||
div.style.cursor = 'pointer';
|
||||
td.appendChild(div);
|
||||
div = document.createElement('div');
|
||||
div.innerText = issue.body;
|
||||
div.className = 'extra';
|
||||
td.appendChild(div);
|
||||
return td;
|
||||
}
|
||||
|
||||
function addUser(td, user, short) {
|
||||
let image = document.createElement('img');
|
||||
image.src = user.avatar_url + '&s=32';
|
||||
image.width = 16;
|
||||
image.height = 16;
|
||||
td.appendChild(image);
|
||||
let a = document.createElement('a');
|
||||
a.href = user.html_url;
|
||||
a.innerText = user.login;
|
||||
if (short) {
|
||||
a.classList.add('short');
|
||||
}
|
||||
td.appendChild(a);
|
||||
}
|
||||
|
||||
function cellUser() {
|
||||
let td = document.createElement('td');
|
||||
td.className = 'user';
|
||||
addUser(td, issue.user);
|
||||
return td;
|
||||
}
|
||||
|
||||
function cellAssignees() {
|
||||
let td = document.createElement('td');
|
||||
td.className = 'user';
|
||||
if (issue.assignees) {
|
||||
issue.assignees.forEach(user => addUser(td, user, issue.assignees.length > 1));
|
||||
}
|
||||
return td;
|
||||
}
|
||||
|
||||
function cellState() {
|
||||
let td = document.createElement('td');
|
||||
if (issue.pull_request) {
|
||||
if (issue.pull_request.merged_at) {
|
||||
td.innerText = 'merged';
|
||||
} else if (issue.pull_request.closed_at) {
|
||||
td.innerText = 'discarded';
|
||||
} else {
|
||||
td.innerText = 'pr';
|
||||
}
|
||||
} else {
|
||||
td.innerText = issue.state;
|
||||
}
|
||||
return td;
|
||||
}
|
||||
|
||||
function cellLabels() {
|
||||
let td = document.createElement('td');
|
||||
td.className = 'label';
|
||||
issue.labels.forEach(label => {
|
||||
let sp = document.createElement('span');
|
||||
sp.style.backgroundColor = '#' + label.color;
|
||||
sp.innerText = label.name;
|
||||
td.appendChild(sp);
|
||||
});
|
||||
return td;
|
||||
}
|
||||
|
||||
let tr = document.createElement('tr');
|
||||
tr.appendChild(cellID());
|
||||
tr.appendChild(cellTitle());
|
||||
tr.appendChild(cellState());
|
||||
tr.appendChild(cellUser());
|
||||
tr.appendChild(cellAssignees());
|
||||
tr.appendChild(cellLabels());
|
||||
return tr;
|
||||
}
|
||||
|
||||
function show(issues) {
|
||||
if (!issues) {
|
||||
return;
|
||||
}
|
||||
|
||||
let tbody = document.getElementById('tbody');
|
||||
tbody.innerHTML = '';
|
||||
issues.forEach(issue => {
|
||||
tbody.appendChild(makeRow(issue));
|
||||
});
|
||||
}
|
||||
|
||||
var currentFilter = '';
|
||||
function filter(str, now) {
|
||||
try {
|
||||
filterIssues(str);
|
||||
setStatus(`${issues.length} records selected`);
|
||||
if (now) {
|
||||
window.location.hash = str;
|
||||
currentFilter = str;
|
||||
}
|
||||
} catch (e) {
|
||||
if (now) { // Only show errors when someone hits enter.
|
||||
setStatus(`Error: ${e.message}`);
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function slashCmd(cmd) {
|
||||
if (cmd[0] === 'help') {
|
||||
setStatus('help shown');
|
||||
document.getElementById('help').classList.remove('hidden');
|
||||
} else if (cmd[0] === 'local') {
|
||||
setStatus('retrieving local JSON files');
|
||||
get().then(redraw);
|
||||
} else if (cmd[0] === 'remote') {
|
||||
if (cmd.length < 3) {
|
||||
setStatus('need to specify github repo');
|
||||
} else {
|
||||
get(cmd[1], cmd[2]).then(redraw)
|
||||
.then(
|
||||
_ => status.innerText = `successfully loaded ${cmd[1]}/${cmd[2]} from GitHub`,
|
||||
e => status.innerText = `Error: ${e.message}`);
|
||||
setStatus(`fetching from GitHub for ${cmd[1]}/${cmd[2]}`);
|
||||
}
|
||||
} else if (cmd[0] === 'sort') {
|
||||
sort(cmd[1]);
|
||||
show(subset);
|
||||
} else {
|
||||
setStatus('unknown command: /' + cmd.join(' '));
|
||||
}
|
||||
}
|
||||
|
||||
function redraw(now) {
|
||||
let cmd = document.getElementById('cmd');
|
||||
if (cmd.value.charAt(0) == '/') {
|
||||
if (now) {
|
||||
slashCmd(cmd.value.slice(1).split(' ').map(x => x.trim()));
|
||||
cmd.value = currentFilter;
|
||||
document.getElementById('display').classList.add('hidden');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!issues) {
|
||||
if (now) {
|
||||
showStatus('Still loading...');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
document.getElementById('help').classList.add('hidden');
|
||||
document.getElementById('display').classList.remove('hidden');
|
||||
filter(cmd.value, now);
|
||||
show(subset);
|
||||
}
|
||||
|
||||
function generateHelp() {
|
||||
let functionhelp = document.getElementById('functions');
|
||||
Object.keys(issueFilters).forEach(k => {
|
||||
let li = document.createElement('li');
|
||||
let arglist = '';
|
||||
if (issueFilters[k].args.length > 0) {
|
||||
arglist = '(' + issueFilters[k].args.map(x => '<' + x + '>').join(', ') + ')';
|
||||
}
|
||||
let help = '';
|
||||
if (issueFilters[k].h) {
|
||||
help = ' - ' + issueFilters[k].h;
|
||||
}
|
||||
li.innerText = `${k}${arglist}${help}`;
|
||||
functionhelp.appendChild(li);
|
||||
});
|
||||
}
|
||||
|
||||
function addFileHelp() {
|
||||
setStatus('error loading file');
|
||||
if (window.location.protocol !== 'file:') {
|
||||
return;
|
||||
}
|
||||
let h = document.getElementById('help');
|
||||
let p = document.createElement('p');
|
||||
p.className = 'warning';
|
||||
p.innerHTML = 'Important: Browsers display files inconsistently.' +
|
||||
' You can work around this by running an HTTP server,' +
|
||||
' such as <code>python -m SimpleHTTPServer</code>,' +
|
||||
' then view this file using that server.';
|
||||
h.insertBefore(p, h.firstChild);
|
||||
}
|
||||
|
||||
window.onload = () => {
|
||||
let cmd = document.getElementById('cmd');
|
||||
cmd.onkeypress = debounce(redraw);
|
||||
if (window.location.hash) {
|
||||
cmd.value = decodeURIComponent(window.location.hash.substring(1));
|
||||
}
|
||||
generateHelp();
|
||||
get().then(redraw).catch(addFileHelp);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
Feature: Building drafts
|
||||
|
||||
Scenario: Single Kramdown draft can build
|
||||
Given a configured git repo with a Kramdown draft
|
||||
when make is run
|
||||
then it succeeds
|
||||
and generates documents
|
||||
|
||||
Scenario: Multiple Kramdown drafts can build
|
||||
Given a configured git repo with multiple Kramdown drafts
|
||||
when make is run
|
||||
then it succeeds
|
||||
and generates documents
|
||||
|
||||
Scenario: Incorrect Kramdown draft fails
|
||||
Given a configured git repo with a Kramdown draft
|
||||
when the draft is broken
|
||||
and make is run
|
||||
then it fails
|
||||
|
||||
Scenario: Submodule for lib
|
||||
Given a configured git repo with a Kramdown draft
|
||||
when lib is added as a submodule
|
||||
and make is run
|
||||
then it succeeds
|
||||
and generates documents
|
||||
|
||||
Scenario: Submodule removed
|
||||
Given a configured git repo with a Kramdown draft
|
||||
when the lib dir is removed
|
||||
and lib is added as a submodule
|
||||
and the lib dir is removed
|
||||
and make is run
|
||||
then it succeeds
|
||||
and generates documents
|
||||
|
||||
# Scenario: Mmark draft can build
|
||||
# Given a configured git repo with an Mmark draft
|
||||
# when we run make
|
||||
# then make succeeds and generates documents
|
||||
#
|
||||
# Scenario: Incorrect Mmark draft fails
|
||||
# Given a configured git repo with a Mmark draft
|
||||
# when we break the draft and run make
|
||||
# then make fails
|
||||
@@ -0,0 +1,9 @@
|
||||
from behave import *
|
||||
from shutil import rmtree
|
||||
|
||||
|
||||
def after_scenario(context, scenario):
|
||||
if 'working_dir' in context:
|
||||
rmtree(context.working_dir)
|
||||
if 'origin_dir' in context:
|
||||
rmtree(context.origin_dir)
|
||||
@@ -0,0 +1,26 @@
|
||||
Feature: git integration
|
||||
|
||||
Scenario: make ghpages
|
||||
Given a configured git repo with a Kramdown draft
|
||||
when make "ghpages" is run with "PUSH_GHPAGES=false"
|
||||
then it succeeds
|
||||
and a branch is created called "gh-pages" containing "index.html"
|
||||
and documents are added to gh-pages
|
||||
|
||||
Scenario: make ghissues
|
||||
Given a configured git repo with a Kramdown draft
|
||||
when make "ghissues" is run with "DISABLE_ISSUE_FETCH=true"
|
||||
then it succeeds
|
||||
and a branch is created called "gh-pages" containing "issues.json"
|
||||
|
||||
Scenario: git pre-commit hook blocks broken drafts
|
||||
Given a configured git repo with a Kramdown draft
|
||||
when the draft is broken
|
||||
and git commit is run
|
||||
then it fails
|
||||
|
||||
Scenario: git pre-commit hook does not block other drafts
|
||||
Given a configured git repo with multiple Kramdown drafts
|
||||
when the draft is broken
|
||||
and a non-broken draft is committed
|
||||
then it succeeds
|
||||
@@ -0,0 +1,71 @@
|
||||
Feature: Initial setup
|
||||
|
||||
Scenario: Run setup script on correctly-set-up directory
|
||||
Given a git repo with a single Kramdown draft
|
||||
when the setup script is run
|
||||
then it succeeds
|
||||
and a file is created called "Makefile"
|
||||
and a file is created called "README.md"
|
||||
and a file is created called "CONTRIBUTING.md"
|
||||
and a file is created called "LICENSE.md"
|
||||
and a file is created called ".gitignore"
|
||||
and a file is created called ".travis.yml"
|
||||
and a file is created called ".circleci/config.yml"
|
||||
and a branch is created called "gh-pages" containing "index.html"
|
||||
and a branch is created called "gh-pages" containing "issues.json"
|
||||
and gitignore lists xml files
|
||||
and a precommit hook is installed
|
||||
|
||||
Scenario: Run setup script with XSLT on correctly-set-up directory
|
||||
Given a git repo with a single Kramdown draft
|
||||
when the setup script is run with "USE_XSLT=true"
|
||||
then it succeeds
|
||||
and a file is created called "Makefile" which contains "USE_XSLT := true"
|
||||
and a file is created called "README.md"
|
||||
and a file is created called "CONTRIBUTING.md"
|
||||
and a file is created called "LICENSE.md"
|
||||
and a file is created called ".gitignore"
|
||||
and a file is created called ".travis.yml"
|
||||
and a file is created called ".circleci/config.yml"
|
||||
and a branch is created called "gh-pages" containing "index.html"
|
||||
and a branch is created called "gh-pages" containing "issues.json"
|
||||
and gitignore lists xml files
|
||||
and a precommit hook is installed
|
||||
|
||||
Scenario: Run setup script on directory with no draft
|
||||
Given an empty git repo
|
||||
and lib is cloned in
|
||||
when the setup script is run
|
||||
then it fails
|
||||
and generates a message "Create a draft file"
|
||||
|
||||
Scenario: Run setup script on directory with multiple drafts
|
||||
Given a git repo with multiple Kramdown drafts
|
||||
when the setup script is run
|
||||
then it succeeds
|
||||
and gitignore lists xml files
|
||||
|
||||
Scenario: Run setup script on directory with no origin remote
|
||||
Given a git repo with no origin
|
||||
and lib is cloned in
|
||||
and a Kramdown draft is created
|
||||
when the setup script is run
|
||||
then it fails
|
||||
and generates a message "remote"
|
||||
|
||||
Scenario: Run setup script on directory without pushing to master
|
||||
Given a git repo with no origin
|
||||
and an empty origin remote is added
|
||||
and lib is cloned in
|
||||
and a Kramdown draft is created
|
||||
when the setup script is run
|
||||
then it fails
|
||||
and generates a message "push"
|
||||
|
||||
Scenario: Retain .gitignore when running setup
|
||||
Given a git repo with a single Kramdown draft
|
||||
and a .gitignore with the line "IGNORE-ME"
|
||||
when the setup script is run
|
||||
then it succeeds
|
||||
and gitignore lists "IGNORE-ME"
|
||||
and gitignore lists xml files
|
||||
@@ -0,0 +1,101 @@
|
||||
from __future__ import print_function
|
||||
from behave import *
|
||||
from subprocess import call
|
||||
from contextlib import contextmanager
|
||||
from tempfile import TemporaryFile
|
||||
from glob import glob
|
||||
import os
|
||||
import sys
|
||||
import fileinput
|
||||
|
||||
git_commit = ["git", "-c", "user.name=Behave Tests", "-c",
|
||||
"user.email=behave@example.com", "commit"]
|
||||
|
||||
|
||||
@contextmanager
|
||||
def cd(newdir):
|
||||
prevdir = os.getcwd()
|
||||
os.chdir(os.path.expanduser(newdir))
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
os.chdir(prevdir)
|
||||
|
||||
|
||||
def run_with_capture(context, command):
|
||||
with cd(context.working_dir), \
|
||||
TemporaryFile(mode='w+') as outFile, \
|
||||
TemporaryFile(mode='w+') as errFile:
|
||||
context.result = call(command,
|
||||
stdout=outFile, stderr=errFile)
|
||||
outFile.seek(0)
|
||||
context.out = outFile.read()
|
||||
errFile.seek(0)
|
||||
context.error = errFile.read()
|
||||
print(context.out)
|
||||
print(context.error, file=sys.stderr)
|
||||
|
||||
|
||||
@when(u'the setup script is run')
|
||||
def step_impl(context):
|
||||
run_with_capture(context, ["make", "-f", "lib/setup.mk"])
|
||||
|
||||
|
||||
@when(u'the setup script is run with "{option}"')
|
||||
def step_impl(context, option):
|
||||
run_with_capture(context, ["make", "-f", "lib/setup.mk", option])
|
||||
|
||||
|
||||
@when(u'make is run')
|
||||
def step_impl(context):
|
||||
run_with_capture(context, ["make"])
|
||||
|
||||
|
||||
@when(u'make "{target}" is run')
|
||||
def step_impl(context, target):
|
||||
run_with_capture(context, ["make", target])
|
||||
|
||||
|
||||
@when(u'make "{target}" is run with "{option}"')
|
||||
def step_impl(context, target, option):
|
||||
run_with_capture(context, ["make", target, option])
|
||||
|
||||
|
||||
@when(u'the draft is broken')
|
||||
def step_impl(context):
|
||||
with cd(context.working_dir):
|
||||
break_this = glob("draft-*.md")[0]
|
||||
run_with_capture(context, [
|
||||
"sed", "-i", "-e", "s/{{RFC2119}}/{{broken-reference}}/", break_this])
|
||||
context.broken_file = break_this
|
||||
|
||||
|
||||
@when(u'the lib dir is removed')
|
||||
def step_impl(context):
|
||||
run_with_capture(context, ["rm", "-rf", "lib"])
|
||||
|
||||
|
||||
@when(u'lib is added as a submodule')
|
||||
def step_impl(context):
|
||||
run_with_capture(context, ["git", "submodule",
|
||||
"add", "-f", os.getcwd(), "lib"])
|
||||
|
||||
|
||||
@when(u'git commit is run')
|
||||
def step_impl(context):
|
||||
with cd(context.working_dir):
|
||||
run_with_capture(context, git_commit +
|
||||
["-am", "Committing broken draft"])
|
||||
|
||||
|
||||
@when(u'a non-broken draft is committed')
|
||||
def step_impl(context):
|
||||
with cd(context.working_dir):
|
||||
drafts = glob("draft-*.md")
|
||||
drafts.remove(context.broken_file)
|
||||
commit_this_file = drafts[0]
|
||||
with open(commit_this_file, "a") as update:
|
||||
update.write("# One more appendix\n\nCan you see me?\n")
|
||||
call(["git", "add", commit_this_file])
|
||||
run_with_capture(context, git_commit +
|
||||
["-m", "Only the non-broken file"])
|
||||
@@ -0,0 +1,125 @@
|
||||
from behave import *
|
||||
from glob import glob
|
||||
from subprocess import call
|
||||
from tempfile import mkdtemp, NamedTemporaryFile
|
||||
from contextlib import contextmanager
|
||||
import os
|
||||
import random
|
||||
import string
|
||||
|
||||
|
||||
@contextmanager
|
||||
def cd(newdir):
|
||||
prevdir = os.getcwd()
|
||||
os.chdir(os.path.expanduser(newdir))
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
os.chdir(prevdir)
|
||||
|
||||
|
||||
@given(u'an empty git repo')
|
||||
def step_impl(context):
|
||||
context.test_dir = os.getcwd()
|
||||
context.working_dir = mkdtemp()
|
||||
context.origin_dir = mkdtemp()
|
||||
with cd(context.origin_dir):
|
||||
call(["git", "init"])
|
||||
# Need to checkout another branch so that pushes to master work.
|
||||
call(["git", "checkout", "-b", "testing"])
|
||||
|
||||
with cd(context.working_dir):
|
||||
call(["git", "clone", context.origin_dir, "."])
|
||||
call(["git", "config", "user.name", "Behave Tests"])
|
||||
call(["git", "config", "user.email", "behave@example.com"])
|
||||
|
||||
|
||||
@given(u'a git repo with no origin')
|
||||
def step_impl(context):
|
||||
context.test_dir = os.getcwd()
|
||||
context.working_dir = mkdtemp()
|
||||
with cd(context.working_dir):
|
||||
call(["git", "init"])
|
||||
call(["git", "config", "user.name", "Behave Tests"])
|
||||
call(["git", "config", "user.email", "behave@example.com"])
|
||||
|
||||
|
||||
@given(u'lib is cloned in')
|
||||
def step_impl(context):
|
||||
with cd(context.working_dir):
|
||||
call(["ln", "-s", context.test_dir, "lib"])
|
||||
|
||||
|
||||
@given(u'the repo is tagged')
|
||||
def step_impl(context):
|
||||
with cd(context.working_dir):
|
||||
md_files = glob("draft-*.md")
|
||||
for md in md_files:
|
||||
tag = md.replace(".md", "-00")
|
||||
call(["git", "tag", "-am", "testing", tag])
|
||||
|
||||
|
||||
@given(u'an empty origin remote is added')
|
||||
def step_impl(context):
|
||||
with cd(context.working_dir):
|
||||
call(["git", "remote", "add", "origin", mkdtemp()])
|
||||
|
||||
|
||||
@given(u'a Kramdown draft is created')
|
||||
def step_impl(context):
|
||||
with cd(context.working_dir):
|
||||
random_string = ''.join(random.SystemRandom().choice(
|
||||
string.ascii_lowercase) for n in range(8))
|
||||
draft_name = "draft-behave-" + random_string
|
||||
file_name = draft_name + ".md"
|
||||
with open(file_name, "wb") as newFile:
|
||||
call(["sed", "-e", "s/draft-hartke-xmpp-stupid/{}/".format(draft_name),
|
||||
"lib/doc/example.md"], stdout=newFile)
|
||||
call(["git", "add", file_name])
|
||||
call(["git", "commit", "-am", "Initial commit of {}".format(draft_name)])
|
||||
|
||||
|
||||
@given(u'a .gitignore with the line "{ignore}"')
|
||||
def step_impl(context, ignore):
|
||||
with cd(context.working_dir):
|
||||
with open(".gitignore", "w") as gi:
|
||||
gi.write("{}\n".format(ignore))
|
||||
call(["git", "add", ".gitignore"])
|
||||
call(["git", "commit", "-am", "Create .gitignore with '{}'".format(ignore)])
|
||||
|
||||
|
||||
@given(u'pushed to origin/master')
|
||||
def step_impl(context):
|
||||
with cd(context.working_dir):
|
||||
call(["git", "push", "origin", "master"])
|
||||
|
||||
|
||||
@given(u'a git repo with a single Kramdown draft')
|
||||
def step_impl(context):
|
||||
context.execute_steps(u'''
|
||||
Given an empty git repo
|
||||
and lib is cloned in
|
||||
and a Kramdown draft is created
|
||||
and pushed to origin/master''')
|
||||
|
||||
|
||||
@given(u'a git repo with multiple Kramdown drafts')
|
||||
def step_impl(context):
|
||||
context.execute_steps(u'''
|
||||
Given a git repo with a single Kramdown draft
|
||||
and a Kramdown draft is created
|
||||
and pushed to origin/master''')
|
||||
|
||||
|
||||
@given(u'a configured git repo with a Kramdown draft')
|
||||
def step_impl(context):
|
||||
context.execute_steps(u'Given a git repo with a single Kramdown draft')
|
||||
with cd(context.working_dir):
|
||||
context.result = call(["make", "-f", "lib/setup.mk"])
|
||||
|
||||
|
||||
@given(u'a configured git repo with multiple Kramdown drafts')
|
||||
def step_impl(context):
|
||||
context.execute_steps(u'Given a git repo with multiple Kramdown drafts')
|
||||
with cd(context.working_dir):
|
||||
context.result = call(["make", "-f", "lib/setup.mk"])
|
||||
@@ -0,0 +1,111 @@
|
||||
from behave import *
|
||||
from contextlib import contextmanager
|
||||
from subprocess import check_output, check_call
|
||||
import os
|
||||
from glob import glob
|
||||
|
||||
|
||||
@contextmanager
|
||||
def cd(newdir):
|
||||
prevdir = os.getcwd()
|
||||
os.chdir(os.path.expanduser(newdir))
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
os.chdir(prevdir)
|
||||
|
||||
|
||||
@then(u'it succeeds')
|
||||
def step_impl(context):
|
||||
assert context.result == 0
|
||||
|
||||
|
||||
@then(u'it fails')
|
||||
def step_impl(context):
|
||||
assert context.result != 0
|
||||
|
||||
|
||||
@then(u'generates a message "{text}"')
|
||||
def step_impl(context, text):
|
||||
assert context.error.find(text) != -1
|
||||
|
||||
|
||||
@then(u'gitignore lists xml files')
|
||||
def step_impl(context):
|
||||
with cd(context.working_dir):
|
||||
md_files = glob("draft-*.md")
|
||||
for md in md_files:
|
||||
context.execute_steps(
|
||||
u'then gitignore lists "{}"'.format(md.replace(".md", ".xml")))
|
||||
|
||||
|
||||
@then(u'gitignore lists "{ignore}"')
|
||||
def step_impl(context, ignore):
|
||||
with cd(context.working_dir):
|
||||
c = check_output(["grep", "-c", ignore, ".gitignore"]).decode("utf-8")
|
||||
assert int(c) == 1
|
||||
|
||||
|
||||
@then(u'generates documents')
|
||||
def step_impl(context):
|
||||
with cd(context.working_dir):
|
||||
md_files = glob("draft-*.md")
|
||||
for md in md_files:
|
||||
txt_file = md.replace(".md", ".txt")
|
||||
html_file = md.replace(".md", ".html")
|
||||
assert os.path.isfile(txt_file)
|
||||
assert os.path.isfile(html_file)
|
||||
|
||||
|
||||
@then(u'generates upload files')
|
||||
def step_impl(context):
|
||||
with cd(context.working_dir):
|
||||
for md in glob("draft-*.md"):
|
||||
if not "-00.md" in md:
|
||||
upload_file = "." + md.replace(".md", "-00.upload")
|
||||
assert os.path.isfile(upload_file)
|
||||
|
||||
|
||||
@then(u'documents are added to gh-pages')
|
||||
def step_impl(context):
|
||||
with cd(context.working_dir):
|
||||
md_files = glob("draft-*.md")
|
||||
ghpages_files = check_output(
|
||||
["git", "ls-tree", "gh-pages", "--name-only", "-r"]) \
|
||||
.decode("utf-8")
|
||||
for md in md_files:
|
||||
txt_file = md.replace(".md", ".txt")
|
||||
html_file = md.replace(".md", ".html")
|
||||
assert txt_file in ghpages_files
|
||||
assert html_file in ghpages_files
|
||||
|
||||
|
||||
@then(u'a file is created called "{filename}" which contains "{text}"')
|
||||
def step_impl(context, filename, text):
|
||||
context.execute_steps(
|
||||
u'then a branch is created called "master" containing "%s"' % filename)
|
||||
with cd(context.working_dir):
|
||||
content = check_output(
|
||||
["git", "show", "master:%s" % filename]).decode("utf-8")
|
||||
assert text in content
|
||||
|
||||
|
||||
@then(u'a file is created called "{filename}"')
|
||||
def step_impl(context, filename):
|
||||
context.execute_steps(
|
||||
u'then a branch is created called "master" containing "%s"' % filename)
|
||||
|
||||
|
||||
@then(u'a branch is created called "{branch}" containing "{filename}"')
|
||||
def step_impl(context, branch, filename):
|
||||
with cd(context.working_dir):
|
||||
files = check_output(
|
||||
["git", "ls-tree", branch, "--name-only", "-r"]) \
|
||||
.decode("utf-8")
|
||||
assert filename in files
|
||||
|
||||
|
||||
@then(u'a precommit hook is installed')
|
||||
def step_impl(context):
|
||||
with cd(context.working_dir):
|
||||
assert len(glob('.git/hooks/pre-commit')) == 1
|
||||
@@ -0,0 +1,22 @@
|
||||
Feature: Uploading drafts
|
||||
|
||||
Scenario: Simple draft upload works
|
||||
Given a configured git repo with a Kramdown draft
|
||||
and the repo is tagged
|
||||
when make "upload" is run with "curl=f() { echo "curl $$@" > $@; echo "HTTP/1.1 200 OK" >> $@; };f"
|
||||
then it succeeds
|
||||
and generates upload files
|
||||
|
||||
Scenario: Multiple draft upload works
|
||||
Given a configured git repo with multiple Kramdown drafts
|
||||
and the repo is tagged
|
||||
when make "upload" is run with "curl=f() { echo "curl $$@" > $@; echo "HTTP/1.1 200 OK" >> $@; };f"
|
||||
then it succeeds
|
||||
and generates upload files
|
||||
|
||||
Scenario: Failing to upload shows error message
|
||||
Given a configured git repo with a Kramdown draft
|
||||
and the repo is tagged
|
||||
when make "upload" is run with "curl=f() { echo "curl $$@" > $@; echo "HTTP/1.1 400 Bad Request" >> $@; };f"
|
||||
then it fails
|
||||
and generates a message "400 Bad Request"
|
||||
@@ -0,0 +1,43 @@
|
||||
ifneq (true,$(CI))
|
||||
ifndef SUBMODULE
|
||||
UPDATE_COMMAND = echo Updating template && git -C $(LIBDIR) pull && \
|
||||
([ ! -d $(XSLTDIR) ] || git -C $(XSLTDIR) pull)
|
||||
FETCH_HEAD = $(wildcard $(LIBDIR)/.git/FETCH_HEAD)
|
||||
else
|
||||
UPDATE_COMMAND = echo Your template is old, please run `make update`
|
||||
FETCH_HEAD = $(wildcard .git/modules/$(LIBDIR)/FETCH_HEAD)
|
||||
endif
|
||||
|
||||
NOW = $$(date '+%s')
|
||||
ifeq (,$(FETCH_HEAD))
|
||||
UPDATE_NEEDED = false
|
||||
else
|
||||
UPDATE_INTERVAL = 1209600 # 2 weeks
|
||||
UPDATE_NEEDED = $(shell [ $$(($(NOW) - $(call last_modified,$(FETCH_HEAD)))) -gt $(UPDATE_INTERVAL) ] && echo true)
|
||||
endif
|
||||
|
||||
ifeq (true, $(UPDATE_NEEDED))
|
||||
latest submit:: auto_update
|
||||
endif
|
||||
|
||||
.PHONY: auto_update
|
||||
.SILENT: auto_update
|
||||
.IGNORE: auto_update
|
||||
auto_update:
|
||||
$(UPDATE_COMMAND)
|
||||
|
||||
.PHONY: update
|
||||
update: auto_update
|
||||
@[ ! -r circle.yml ] || \
|
||||
echo circle.yml has been replaced by .circleci/config.yml. Please update from $(LIBDIR)/template.
|
||||
@for i in Makefile .travis.yml .circleci/config.yml; do \
|
||||
[ -z "$(comm -13 $$i $(LIBDIR)/template/$$i)" ] || \
|
||||
echo $$i is out of date, check against $(LIBDIR)/template/$$i for changes.; \
|
||||
done
|
||||
@dotgit=$$(git rev-parse --git-dir); \
|
||||
[ -L "$$dotgit"/hooks/pre-commit ] || \
|
||||
ln -s ../../$(LIBDIR)/pre-commit.sh "$$dotgit"/hooks/pre-commit; \
|
||||
[ -L "$$dotgit"/hooks/pre-push ] || \
|
||||
ln -s ../../$(LIBDIR)/pre-push.sh "$$dotgit"/hooks/pre-push
|
||||
|
||||
endif # CI
|
||||
@@ -0,0 +1,28 @@
|
||||
# This only works for tags that are created with `git tag -a`. Using an
|
||||
# annotated tag associates an email address, which this uses in the upload.
|
||||
ifneq (,$(CIRCLE_TAG)$(TRAVIS_TAG))
|
||||
draft_releases := $(CIRCLE_TAG)$(TRAVIS_TAG)
|
||||
else
|
||||
draft_releases := $(shell git tag --list --points-at HEAD --format '%(tag),%(taggeremail)' | grep '^draft-.*,<.*>$$' | cut -f 1 -d , -)
|
||||
endif
|
||||
|
||||
ifneq ($(foreach tag,$(draft_releases),$(shell git tag --list --format='%(tag)' $(tag))),$(draft_releases))
|
||||
$(warning Attempting upload for a lightweight tag: $(draft_releases))
|
||||
$(error Only annotated tags \(created with `git tag -a`\) are supported)
|
||||
endif
|
||||
|
||||
uploads := $(addprefix .,$(addsuffix .upload,$(draft_releases)))
|
||||
|
||||
ifneq (,$(TRAVIS))
|
||||
# Ensure that we build the XML files needed for upload during the main build.
|
||||
latest:: $(addsuffix .xml,$(draft_releases))
|
||||
endif
|
||||
|
||||
.PHONY: upload
|
||||
upload: $(uploads)
|
||||
|
||||
.%.upload: %.xml
|
||||
$(curl) -D $@ -F "user=$(shell git tag --list --format '%(taggeremail)' $(basename $<) | \
|
||||
sed -e 's/^<//;s/>$$//')" -F "xml=@$<" \
|
||||
"$(DATATRACKER_UPLOAD_URL)" && echo && \
|
||||
(grep -q ' 200 OK' $@ >/dev/null 2>&1 || ! cat $@ 1>&2)
|
||||
Reference in new issue
Block a user