Starting -03 version

- bumped version to -03
- deleted old build environment
- address comments fro Ken Calvert
This commit is contained in:
David Oran committed 2020-02-10 11:39:37 -05:00
1 parent e2ef838ff7
commit 2683ac12a0
55 files changed
+1619 -8186

No files matched your search

-684
View File
@@ -1,684 +0,0 @@
<!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
View File
@@ -1,840 +0,0 @@
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
View File
@@ -1,684 +0,0 @@
<!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
View File
@@ -1,840 +0,0 @@
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]
+2 -2
View File
@@ -1052,7 +1052,7 @@ table {
</tr></thead>
<tfoot><tr>
<td class="left">Oran</td>
<td class="center">Expires 6 August 2020</td>
<td class="center">Expires 12 August 2020</td>
<td class="right">[Page]</td>
</tr></tfoot>
</table>
@@ -1070,7 +1070,7 @@ table {
<dt class="label-intended-status">Intended Status:</dt>
<dd class="intended-status">Experimental</dd>
<dt class="label-expires">Expires:</dt>
<dd class="expires"><time datetime="2020-08-06">6 August 2020</time></dd>
<dd class="expires"><time datetime="2020-08-12">12 August 2020</time></dd>
<dt class="label-authors">Author:</dt>
<dd class="authors">
<div class="author">
File diff suppressed because it is too large. Load diff
@@ -27,7 +27,7 @@
<?rfc subcompact="no" ?>
<!-- keep one blank line between list items -->
<!-- end of list of popular I-D processing instructions -->
<rfc xmlns:xi="http://www.w3.org/2001/XInclude" category="exp" docName="draft-oran-icnrg-flowbalance-latest" ipr="trust200902" obsoletes="" updates="" submissionType="IRTF" xml:lang="en" tocInclude="true" tocDepth="4" symRefs="true" sortRefs="true" version="3">
<rfc xmlns:xi="http://www.w3.org/2001/XInclude" category="exp" docName="draft-oran-icnrg-flowbalance-03" ipr="trust200902" obsoletes="" updates="" submissionType="IRTF" xml:lang="en" tocInclude="true" tocDepth="4" symRefs="true" sortRefs="true" version="3">
<!-- xml2rfc v2v3 conversion 2.39.0 -->
<!-- category values: std, bcp, info, exp, and historic
ipr values: full3667, noModification3667, noDerivatives3667
@@ -41,7 +41,7 @@
<title abbrev="Maintaining Flow Balance">
Maintaining CCNx or NDN flow balance with highly variable data object sizes
</title>
<seriesInfo name="Internet-Draft" value="draft-oran-icnrg-flowbalance-latest"/>
<seriesInfo name="Internet-Draft" value="draft-oran-icnrg-flowbalance-03"/>
<!-- add 'role="editor"' below for the editors if appropriate -->
<!-- Another author who claims to be an editor -->
@@ -113,11 +113,11 @@
<section anchor="description" numbered="true" toc="default">
<name>Method to enhance congestion control with signaled size information in Interest Messages</name>
<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" format="default"/>, DCCP<xref target="RFC4340" format="default"/>, SCTP<xref target="RFC4960" format="default"/>, QUIC<xref target="I-D.ietf-quic-transport" format="default"/>), 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" format="default"/>,<xref target="Mahdian2016" format="default"/>,<xref target="Song2018" format="default"/>,<xref target="Carofiglio2012" format="default"/>. Other schemes, like <xref target="Schneider2016" format="default"/> 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" format="default"/> or <xref target="proportionalfairness" format="default"/>). 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>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" format="default"/>, DCCP<xref target="RFC4340" format="default"/>, SCTP<xref target="RFC4960" format="default"/>, QUIC<xref target="I-D.ietf-quic-transport" format="default"/>), 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 queueing and subsequently forwarding one Interest message 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 message. A number of congestion control schemes have been developed that operate in this fashion, for example <xref target="Wang2013" format="default"/>,<xref target="Mahdian2016" format="default"/>,<xref target="Song2018" format="default"/>,<xref target="Carofiglio2012" format="default"/>. Other schemes, like <xref target="Schneider2016" format="default"/> 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" format="default"/> or <xref target="proportionalfairness" format="default"/>). 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>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 Path MTU 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 <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 <xref target="Schneider2016" format="default"/> 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>
<t>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 more 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" format="default"/> 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" numbered="true" toc="default">
<name>How to predict the size of returning Data messages</name>
@@ -130,7 +130,7 @@
<t>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>
<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, such as that in <xref target='Ghali2013'/>).</t>
</section>
<section anchor="toobig" numbered="true" toc="default">
@@ -145,7 +145,7 @@
<t>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>Upon dropping data as above, the CCNx/NDN forwarder converts the normal Data message into an Interest Return message containing the with the existing 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 MAY 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>
@@ -158,12 +158,13 @@
<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>
<t>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" numbered="true" toc="default">
<name>Interactions with Interest Aggregation</name>
<t>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>
<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:</t>
<ol spacing="normal" type="1">
@@ -171,7 +172,7 @@
<li>The arriving interest carries an expected data size larger than any of the values associated with the PIT entry.</li>
</ol>
<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:</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:</t>
<ol spacing="normal" type="a">
<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>
@@ -189,9 +190,11 @@
<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" format="default"/> 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" numbered="true" toc="default">
<name>Operation when some Interests lack the expected data size option and some have it</name>
<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>Since the expected data size is an optional hop-by-hop packet field, forwarders need to be prepared to handle an arbitrary mix of packets containing or lacking this option. 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:</t>
@@ -221,7 +224,7 @@
<name>Dealing with malicious actors</name>
<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 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 additional concern given the discussion of how to handle over-estimation by honest clients in <xref target='toobig'/>. If one of the amelioration techniques described there is 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:</t>
@@ -265,7 +268,7 @@
</section>
</section>
!-- This PI places the pagebreak correctly (before the section title) in the text output. -->
<!-- This PI places the pagebreak correctly (before the section title) in the text output. -->
<!--<?rfc needLines="8" ?>-->
<!-- Possibly a 'Contributors' section ... -->
@@ -304,6 +307,12 @@
<t>
</t>
</section>
<section anchor="Ackknowledgements" numbered='true' toc='default'>
<name>Acknowledgements</name>
<t>Klaus Schneider and Ken Calvert have contributed a number of useful comments which have substantially improved the document.</t>
</section>
</middle>
<back>
@@ -458,6 +467,7 @@
v00 2019-07-13 DRO Initial version
v01 2019-08-10 DRO Respond to comments by Naveen Nathan and Klaus Schneider
v02 2020-02-04 DRO Convert to xml2rfc v3 and minor text adjustments
v03 2020- DRO Changes based on comments by Ken Calvert
-->
</back>
</rfc>
-2
View File
@@ -1,2 +0,0 @@
TARGETS_DRAFTS := draft-oran-icnrg-flowbalance draft-oran-icnrg-flowbalance-v2
TARGETS_TAGS :=
-36
View File
@@ -1,36 +0,0 @@
# 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
-548
View File
@@ -1,548 +0,0 @@
#! /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">&raquo;</span>'+'&nbsp;'*(n-1))
elif c == " " and ponct == 1:
t += u'<span class="diffponct">&middot;</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'&#8203;'
i = 0
if linesize and i > linesize:
i = 0
t += u"&#8203;"
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:
# &#8942; - vertical ellipsis
output_file.write('<tr class="diffhunk"><td colspan="2">&#8942;</td><td colspan="2">&#8942;</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()
-487
View File
@@ -1,487 +0,0 @@
<?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>
-1
View File
@@ -1 +0,0 @@
This project is in the public domain; your contributions need to be too.
-1
View File
@@ -1 +0,0 @@
This project is in the public domain.
-22
View File
@@ -1,22 +0,0 @@
# 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).
-3
View File
@@ -1,3 +0,0 @@
\~~</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>
}
-28
View File
@@ -1,28 +0,0 @@
/<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
-125
View File
@@ -1,125 +0,0 @@
#!/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}&amp;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>'
-96
View File
@@ -1,96 +0,0 @@
#!/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
-27
View File
@@ -1,27 +0,0 @@
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
-46
View File
@@ -1,46 +0,0 @@
# 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
-77
View File
@@ -1,77 +0,0 @@
# 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.
-79
View File
@@ -1,79 +0,0 @@
# 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.
-163
View File
@@ -1,163 +0,0 @@
# 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.
-104
View File
@@ -1,104 +0,0 @@
# 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`.
-106
View File
@@ -1,106 +0,0 @@
# 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
```
-63
View File
@@ -1,63 +0,0 @@
## 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.
-57
View File
@@ -1,57 +0,0 @@
# 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.
-64
View File
@@ -1,64 +0,0 @@
---
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.
-637
View File
@@ -1,637 +0,0 @@
<?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
&lt;!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 "&#160;">
]>
<!-- 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 &amp; as an escape for & which would otherwise
start an entity declaration, whereas we want a literal &. -->
<area>Operations &amp; 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 &quot;MUST&quot;, &quot;MUST NOT&quot;,
&quot;REQUIRED&quot;, &quot;SHALL&quot;, &quot;SHALL NOT&quot;,
&quot;SHOULD&quot;, &quot;SHOULD NOT&quot;, &quot;RECOMMENDED&quot;,
&quot;MAY&quot;, and &quot;OPTIONAL&quot; 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
(&quot;<xref target="sect2" format="title"/>&quot;): if the organization of the
document changes the reference will still be to the correct section. However
&quot;sect2&quot; 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
&lt;t&gt; 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 &lt;t&gt; 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 &quot;c&quot; 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 &lt;vspace&gt; 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
&lt;vspace /&gt; 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 &lt;t&gt; element. In some cases it would be
nice to have more than one paragraph in a list item. This can be achieved with
&lt;vspace&gt; 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 &lt;list&gt; 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&nbsp;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&nbsp;<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&nbsp;<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&nbsp;<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 &quot;MUST&quot;, &quot;MUST NOT&quot;,
&quot;REQUIRED&quot;, &quot;SHALL&quot;, &quot;SHALL NOT&quot;,
&quot;SHOULD&quot;, &quot;SHOULD NOT&quot;, &quot;RECOMMENDED&quot;,
&quot;MAY&quot;, and &quot;OPTIONAL&quot; 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>
-50
View File
@@ -1,50 +0,0 @@
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
-124
View File
@@ -1,124 +0,0 @@
## 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
-79
View File
@@ -1,79 +0,0 @@
## 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
-78
View File
@@ -1,78 +0,0 @@
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
View File
@@ -1,188 +0,0 @@
.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)
-32
View File
@@ -1,32 +0,0 @@
#!/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
-19
View File
@@ -1,19 +0,0 @@
#!/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
-40
View File
@@ -1,40 +0,0 @@
#!/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"
-91
View File
@@ -1,91 +0,0 @@
#!/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
-88
View File
@@ -1,88 +0,0 @@
.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
-268
View File
@@ -1,268 +0,0 @@
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;
}
-31
View File
@@ -1,31 +0,0 @@
# 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/).
-4
View File
@@ -1,4 +0,0 @@
# License
See the
[guidelines for contributions](https://github.com/{GITHUB_USER}/{GITHUB_REPO}/blob/master/CONTRIBUTING.md).
-11
View File
@@ -1,11 +0,0 @@
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
-62
View File
@@ -1,62 +0,0 @@
<!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
&lt;user&gt; &lt;repo&gt;</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>
-605
View File
@@ -1,605 +0,0 @@
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);
}
-45
View File
@@ -1,45 +0,0 @@
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
-9
View File
@@ -1,9 +0,0 @@
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)
-26
View File
@@ -1,26 +0,0 @@
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
-71
View File
@@ -1,71 +0,0 @@
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
-101
View File
@@ -1,101 +0,0 @@
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"])
-125
View File
@@ -1,125 +0,0 @@
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"])
-111
View File
@@ -1,111 +0,0 @@
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
-22
View File
@@ -1,22 +0,0 @@
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"
-43
View File
@@ -1,43 +0,0 @@
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
-28
View File
@@ -1,28 +0,0 @@
# 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)