tools: visualize RIB dataset in nfd-status
refs #1749
Change-Id: Ia11b88187635ffa4eda4b829afd6a20120765d58
diff --git a/docs/_static/nfd-status.xsd b/docs/_static/nfd-status.xsd
index 829ba7c..425bbd8 100644
--- a/docs/_static/nfd-status.xsd
+++ b/docs/_static/nfd-status.xsd
@@ -47,8 +47,8 @@
<xs:complexType name="faceFlagsType">
<xs:sequence>
- <xs:element type="xs:string" name="local" maxOccurs="1" minOccurs="0"/>
- <xs:element type="xs:string" name="on-demand" maxOccurs="1" minOccurs="0"/>
+ <xs:element type="xs:string" name="local" minOccurs="0"/>
+ <xs:element type="xs:string" name="on-demand" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
@@ -57,9 +57,9 @@
<xs:element type="xs:nonNegativeInteger" name="faceId"/>
<xs:element type="xs:anyURI" name="remoteUri"/>
<xs:element type="xs:anyURI" name="localUri"/>
- <xs:element type="xs:duration" name="expirationPeriod" maxOccurs="1" minOccurs="0"/>
+ <xs:element type="xs:duration" name="expirationPeriod" minOccurs="0"/>
<xs:element type="nfd:bidirectionalPacketCountersType" name="packetCounters"/>
- <xs:element type="nfd:faceFlagsType" name="flags" maxOccurs="1" minOccurs="0"/>
+ <xs:element type="nfd:faceFlagsType" name="flags" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
@@ -95,6 +95,35 @@
</xs:sequence>
</xs:complexType>
+<xs:complexType name="routeType">
+ <xs:sequence>
+ <xs:element type="xs:nonNegativeInteger" name="faceId"/>
+ <xs:element type="xs:nonNegativeInteger" name="origin"/>
+ <xs:element type="xs:nonNegativeInteger" name="cost"/>
+ <xs:element type="xs:nonNegativeInteger" name="flags"/>
+ <xs:element type="xs:duration" name="expirationPeriod" minOccurs="0"/>
+ </xs:sequence>
+</xs:complexType>
+
+<xs:complexType name="ribEntryType">
+ <xs:sequence>
+ <xs:element type="xs:anyURI" name="prefix"/>
+ <xs:element name="routes">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element type="nfd:routeType" name="route" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+</xs:complexType>
+
+<xs:complexType name="ribType">
+ <xs:sequence>
+ <xs:element type="nfd:ribEntryType" name="ribEntry" maxOccurs="unbounded" minOccurs="0"/>
+ </xs:sequence>
+</xs:complexType>
+
<xs:complexType name="strategyType">
<xs:sequence>
<xs:element type="xs:anyURI" name="name"/>
@@ -122,6 +151,7 @@
<xs:element type="nfd:channelsType" name="channels"/>
<xs:element type="nfd:facesType" name="faces"/>
<xs:element type="nfd:fibType" name="fib"/>
+ <xs:element type="nfd:ribType" name="rib"/>
<xs:element type="nfd:strategyChoicesType" name="strategyChoices"/>
</xs:sequence>
</xs:complexType>
diff --git a/docs/manpages/nfd-status.rst b/docs/manpages/nfd-status.rst
index 5a52ae2..217fca5 100644
--- a/docs/manpages/nfd-status.rst
+++ b/docs/manpages/nfd-status.rst
@@ -31,6 +31,9 @@
``-b``
Retrieve FIB information.
+``-r``
+ Retrieve RIB information.
+
``-s``
Retrieve configured strategy choice for NDN namespaces.
diff --git a/tools/nfd-status-http-server-files/nfd-status.xsl b/tools/nfd-status-http-server-files/nfd-status.xsl
index fb25599..37038c5 100644
--- a/tools/nfd-status-http-server-files/nfd-status.xsl
+++ b/tools/nfd-status-http-server-files/nfd-status.xsl
@@ -176,7 +176,7 @@
<table class="item-list">
<thead>
<tr>
- <th>Prefix</th>
+ <th width="20%">Prefix</th>
<th>NextHops</th>
</tr>
</thead>
@@ -193,9 +193,90 @@
<tr class="{$style}">
<td style="text-align:left;vertical-align:top;padding:0"><xsl:value-of select="nfd:prefix"/></td>
<td>
- <xsl:for-each select="nfd:nextHops/nfd:nextHop">
- faceid=<xsl:value-of select="nfd:faceId"/> (cost=<xsl:value-of select="nfd:cost"/>);
- </xsl:for-each>
+ <table class="item-sublist">
+ <tr>
+ <th>FaceId</th>
+ <xsl:for-each select="nfd:nextHops/nfd:nextHop">
+ <td><xsl:value-of select="nfd:faceId"/></td>
+ </xsl:for-each>
+ </tr>
+ <tr>
+ <th>Cost</th>
+ <xsl:for-each select="nfd:nextHops/nfd:nextHop">
+ <td><xsl:value-of select="nfd:cost"/></td>
+ </xsl:for-each>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </xsl:for-each>
+ </tbody>
+ </table>
+</xsl:template>
+
+<xsl:template match="nfd:rib">
+ <h2>RIB</h2>
+ <table class="item-list">
+ <thead>
+ <tr>
+ <th width="20%">Prefix</th>
+ <th>Routes</th>
+ </tr>
+ </thead>
+ <tbody>
+ <xsl:for-each select="nfd:ribEntry">
+ <xsl:variable name="style">
+ <xsl:choose>
+ <xsl:when test="position() mod 2 = 1">
+ <xsl:text>odd</xsl:text>
+ </xsl:when>
+ <xsl:otherwise>even</xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <tr class="{$style}">
+ <td style="text-align:left;vertical-align:top;padding:0"><xsl:value-of select="nfd:prefix"/></td>
+ <td>
+ <table class="item-sublist">
+ <tr>
+ <th>FaceId</th>
+ <xsl:for-each select="nfd:routes/nfd:route">
+ <td><xsl:value-of select="nfd:faceId"/></td>
+ </xsl:for-each>
+ </tr>
+ <tr>
+ <th>Origin</th>
+ <xsl:for-each select="nfd:routes/nfd:route">
+ <td><xsl:value-of select="nfd:origin"/></td>
+ </xsl:for-each>
+ </tr>
+ <tr>
+ <th>Cost</th>
+ <xsl:for-each select="nfd:routes/nfd:route">
+ <td><xsl:value-of select="nfd:cost"/></td>
+ </xsl:for-each>
+ </tr>
+ <tr>
+ <th>Flags</th>
+ <xsl:for-each select="nfd:routes/nfd:route">
+ <td><xsl:value-of select="nfd:flags"/></td>
+ </xsl:for-each>
+ </tr>
+ <tr>
+ <th>Expires in</th>
+ <xsl:for-each select="nfd:routes/nfd:route">
+ <td>
+ <xsl:choose>
+ <xsl:when test="nfd:expirationPeriod">
+ <xsl:call-template name="formatDuration"><xsl:with-param name="duration" select="nfd:expirationPeriod" /></xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ Never
+ </xsl:otherwise>
+ </xsl:choose>
+ </td>
+ </xsl:for-each>
+ </tr>
+ </table>
</td>
</tr>
</xsl:for-each>
@@ -208,7 +289,7 @@
<table class="item-list">
<thead>
<tr>
- <th>Namespace</th>
+ <th width="20%">Namespace</th>
<th>Strategy Name</th>
</tr>
</thead>
diff --git a/tools/nfd-status-http-server-files/style.css b/tools/nfd-status-http-server-files/style.css
index f2b99d5..176da83 100644
--- a/tools/nfd-status-http-server-files/style.css
+++ b/tools/nfd-status-http-server-files/style.css
@@ -114,6 +114,43 @@
border-top: 1px solid transparent;
}
+.item-sublist
+{
+ border-collapse:collapse;
+ border:1px solid gray;
+
+ padding: 4px;
+ font-family: sans-serif;
+ text-align: center;
+ margin-bottom: 0;
+}
+
+.item-sublist th
+{
+ background-color: transparent;
+ font-weight: bold;
+ padding: 4px;
+ text-align: center;
+
+ border-collapse:collapse;
+ border:1px solid gray;
+}
+
+.item-sublist th.border-left {
+}
+
+.item-sublist td
+{
+ border-collapse:collapse;
+ border:1px solid gray;
+
+ padding: 2px;
+ color: #000;
+ text-align: center;
+ min-width: 20px;
+}
+
+
tr.center td
{
text-align: center;
diff --git a/tools/nfd-status-http-server.py b/tools/nfd-status-http-server.py
index 133cc37..f127d40 100755
--- a/tools/nfd-status-http-server.py
+++ b/tools/nfd-status-http-server.py
@@ -28,7 +28,7 @@
from SimpleHTTPServer import SimpleHTTPRequestHandler
from SocketServer import ThreadingMixIn
import sys
-import commands
+import subprocess
import StringIO
import urlparse
import logging
@@ -73,9 +73,11 @@
This function is to call nfd-status command
to get xml format output
"""
- (res, output) = commands.getstatusoutput('nfd-status -x')
+ sp = subprocess.Popen(['nfd-status', '-x'], stdout=subprocess.PIPE)
+ res = sp.wait()
if res == 0:
# add the xml-stylesheet processing instruction after the 1st '>' symbol
+ output = sp.stdout.read()
newLineIndex = output.index('>') + 1
resultStr = output[:newLineIndex]\
+ "<?xml-stylesheet type=\"text/xsl\" href=\"nfd-status.xsl\"?>"\
diff --git a/tools/nfd-status.cpp b/tools/nfd-status.cpp
index d06e8fb..affd2d8 100644
--- a/tools/nfd-status.cpp
+++ b/tools/nfd-status.cpp
@@ -36,6 +36,7 @@
#include <ndn-cxx/management/nfd-channel-status.hpp>
#include <ndn-cxx/management/nfd-face-status.hpp>
#include <ndn-cxx/management/nfd-fib-entry.hpp>
+#include <ndn-cxx/management/nfd-rib-entry.hpp>
#include <ndn-cxx/management/nfd-strategy-choice.hpp>
#include <boost/algorithm/string/replace.hpp>
@@ -53,6 +54,7 @@
, m_needChannelStatusRetrieval(false)
, m_needFaceStatusRetrieval(false)
, m_needFibEnumerationRetrieval(false)
+ , m_needRibStatusRetrieval(false)
, m_needStrategyChoiceRetrieval(false)
, m_isOutputXml(false)
{
@@ -69,6 +71,7 @@
" [-c] - retrieve channel status information\n"
" [-f] - retrieve face status information\n"
" [-b] - retrieve FIB information\n"
+ " [-r] - retrieve RIB information\n"
" [-s] - retrieve configured strategy choice for NDN namespaces\n"
" [-x] - output NFD status information in XML format\n"
"\n"
@@ -110,6 +113,12 @@
}
void
+ enableRibStatusRetrieval()
+ {
+ m_needRibStatusRetrieval = true;
+ }
+
+ void
enableXmlOutput()
{
m_isOutputXml = true;
@@ -381,13 +390,13 @@
std::cout << "<incomingPackets>";
std::cout << "<nInterests>" << faceStatus.getNInInterests()
<< "</nInterests>";
- std::cout << "<nDatas>" << faceStatus.getNInInterests()
+ std::cout << "<nDatas>" << faceStatus.getNInDatas()
<< "</nDatas>";
std::cout << "</incomingPackets>";
std::cout << "<outgoingPackets>";
std::cout << "<nInterests>" << faceStatus.getNOutInterests()
<< "</nInterests>";
- std::cout << "<nDatas>" << faceStatus.getNOutInterests()
+ std::cout << "<nDatas>" << faceStatus.getNOutDatas()
<< "</nDatas>";
std::cout << "</outgoingPackets>";
std::cout << "</packetCounters>";
@@ -629,6 +638,118 @@
}
void
+ fetchRibStatusInformation()
+ {
+ m_buffer = make_shared<OBufferStream>();
+
+ Interest interest("/localhost/nfd/rib/list");
+ interest.setChildSelector(1);
+ interest.setMustBeFresh(true);
+
+ m_face.expressInterest(interest,
+ bind(&NfdStatus::fetchSegments, this, _2,
+ &NfdStatus::afterFetchedRibStatusInformation),
+ bind(&NfdStatus::onTimeout, this));
+ }
+
+ void
+ afterFetchedRibStatusInformation()
+ {
+ ConstBufferPtr buf = m_buffer->buf();
+ if (m_isOutputXml)
+ {
+ std::cout << "<rib>";
+
+ Block block;
+ size_t offset = 0;
+ while (offset < buf->size())
+ {
+ bool ok = Block::fromBuffer(buf, offset, block);
+ if (!ok)
+ {
+ std::cerr << "ERROR: cannot decode RibEntry TLV";
+ break;
+ }
+ offset += block.size();
+
+ nfd::RibEntry ribEntry(block);
+
+ std::cout << "<ribEntry>";
+ std::string prefix(ribEntry.getName().toUri());
+ escapeSpecialCharacters(&prefix);
+ std::cout << "<prefix>" << prefix << "</prefix>";
+ std::cout << "<routes>";
+ for (std::list<nfd::Route>::const_iterator
+ nextRoute = ribEntry.begin();
+ nextRoute != ribEntry.end();
+ ++nextRoute)
+ {
+ std::cout << "<route>" ;
+ std::cout << "<faceId>" << nextRoute->getFaceId() << "</faceId>";
+ std::cout << "<origin>" << nextRoute->getOrigin() << "</origin>";
+ std::cout << "<cost>" << nextRoute->getCost() << "</cost>";
+ std::cout << "<flags>" << nextRoute->getFlags() << "</flags>";
+ if (!nextRoute->hasInfiniteExpirationPeriod()) {
+ std::cout << "<expirationPeriod>PT"
+ << time::duration_cast<time::seconds>(nextRoute->getExpirationPeriod())
+ .count() << "S"
+ << "</expirationPeriod>";
+ }
+ std::cout << "</route>";
+ }
+ std::cout << "</routes>";
+ std::cout << "</ribEntry>";
+ }
+
+ std::cout << "</rib>";
+ }
+ else
+ {
+ std::cout << "Rib:" << std::endl;
+
+ Block block;
+ size_t offset = 0;
+ while (offset < buf->size())
+ {
+ bool ok = Block::fromBuffer(buf, offset, block);
+ if (!ok)
+ {
+ std::cerr << "ERROR: cannot decode RibEntry TLV" << std::endl;
+ break;
+ }
+
+ offset += block.size();
+
+ nfd::RibEntry ribEntry(block);
+
+ std::cout << " " << ribEntry.getName().toUri() << " route={";
+ for (std::list<nfd::Route>::const_iterator
+ nextRoute = ribEntry.begin();
+ nextRoute != ribEntry.end();
+ ++nextRoute)
+ {
+ if (nextRoute != ribEntry.begin())
+ std::cout << ", ";
+ std::cout << "faceid=" << nextRoute->getFaceId()
+ << " (origin=" << nextRoute->getOrigin()
+ << " cost=" << nextRoute->getCost()
+ << " flags=" << nextRoute->getFlags();
+ if (!nextRoute->hasInfiniteExpirationPeriod()) {
+ std::cout << " expires="
+ << time::duration_cast<time::seconds>(nextRoute->getExpirationPeriod())
+ .count() << "s";
+ }
+ std::cout << ")";
+ }
+ std::cout << "}" << std::endl;
+ }
+ }
+
+ runNextStep();
+ }
+
+
+ void
fetchInformation()
{
if (m_isOutputXml ||
@@ -636,12 +757,14 @@
!m_needChannelStatusRetrieval &&
!m_needFaceStatusRetrieval &&
!m_needFibEnumerationRetrieval &&
+ !m_needRibStatusRetrieval &&
!m_needStrategyChoiceRetrieval))
{
enableVersionRetrieval();
enableChannelStatusRetrieval();
enableFaceStatusRetrieval();
enableFibEnumerationRetrieval();
+ enableRibStatusRetrieval();
enableStrategyChoiceRetrieval();
}
@@ -660,6 +783,9 @@
if (m_needFibEnumerationRetrieval)
m_fetchSteps.push_back(bind(&NfdStatus::fetchFibEnumerationInformation, this));
+ if (m_needRibStatusRetrieval)
+ m_fetchSteps.push_back(bind(&NfdStatus::fetchRibStatusInformation, this));
+
if (m_needStrategyChoiceRetrieval)
m_fetchSteps.push_back(bind(&NfdStatus::fetchStrategyChoiceInformation, this));
@@ -705,6 +831,7 @@
bool m_needChannelStatusRetrieval;
bool m_needFaceStatusRetrieval;
bool m_needFibEnumerationRetrieval;
+ bool m_needRibStatusRetrieval;
bool m_needStrategyChoiceRetrieval;
bool m_isOutputXml;
Face m_face;
@@ -721,7 +848,7 @@
int option;
ndn::NfdStatus nfdStatus(argv[0]);
- while ((option = getopt(argc, argv, "hvcfbsxV")) != -1) {
+ while ((option = getopt(argc, argv, "hvcfbrsxV")) != -1) {
switch (option) {
case 'h':
nfdStatus.usage();
@@ -738,6 +865,9 @@
case 'b':
nfdStatus.enableFibEnumerationRetrieval();
break;
+ case 'r':
+ nfdStatus.enableRibStatusRetrieval();
+ break;
case 's':
nfdStatus.enableStrategyChoiceRetrieval();
break;