6. API/CLI tour
In the previous parts we discovered Skydive through its WebUI. In this part we are now going to use the Skydive command line to reproduce what we did previously.
Skydive client, Gremlin requests
In order to have an easy fully functional Skydive multi-node deployment we will use the
Vagrant
environment as previously.
git clone https://github.com/skydive-project/skydive
cd skydive/contrib/vagrant
vagrant up
Following the previous part you should have the following topology in the WebUI.
Now that we have our lab deployed we can connect to the analyzer
node in order to
use the Skydive
binary to request the Skydive API.
vagrant ssh analyzer1
Skydive uses the Gremlin
graph traversal language as its query language.
The following request returns all the eth0
interfaces present in to topology
using the JSON
format.
export SKYDIVE_ANALYZERS=192.168.50.10:8082
skydive client query "G.V().Has('Name', 'eth0')"
We can obtain the full topology in a dot
format with the following request :
skydive client query "G" --format dot
Which gives once rendered the following image:
In order to get the state of the eth0
belonging to specific host, we can use this :
skydive client query "G.V().Has('Name', 'agent1').Out().Has('Name', 'eth0')"
This has to be read as “select the node with the name agent1
then select node
with the name eth0
”
A more exhaustive documentation of the Skydive Gremlin language is available here
Capture request
As seen before it is easy to select interfaces of the topology and starting a traffic capture is as simple as writing a select request.
To start a traffic capture on all the eth0
interface we just have to reuse
our first Gremlin
request like this :
skydive client capture create --gremlin "G.V().Has('Name', 'eth0')"
In order to check that the capture definition matched two interfaces we can just list them.
skydive client capture list
{
"2a1988b1-0d4b-4df5-5b90-9196e6a8d837": {
"UUID": "2a1988b1-0d4b-4df5-5b90-9196e6a8d837",
"GremlinQuery": "G.V().Has('Name', 'eth0')",
"Count": 2,
"ExtraTCPMetric": false,
"SocketInfo": false
}
}
The count field indicates how many traffic capture have been started. Another way to check is to write a request retrieving the interfaces on which the capture have been started.
skydive client query "G.V().Has('Capture.ID', '2a1988b1-0d4b-4df5-5b90-9196e6a8d837').Count()"
2
skydive client query "G.V().Has('Capture.ID', '2a1988b1-0d4b-4df5-5b90-9196e6a8d837').Values('Name')"
[
"eth0",
"eth0"
]
skydive client query "G.V().Has('Capture.ID', '2a1988b1-0d4b-4df5-5b90-9196e6a8d837').Values('Host')"
[
"agent2",
"agent1"
]
Packet injection
We are going to use the command to generate ICMPv4 packets. Packets will be injected from one eth0
towards the other eth0
.
First we need to get the IDs
of the interfaces.
skydive client query "G.V().Has('Name', 'eth0').Values('ID')"
[
"a5f2fd0d-1f30-46a9-75ff-6ba4c82426a1",
"99d511f5-5088-4c0d-67db-e45af33cb87c"
]
Now the packet injection request :
skydive client inject-packet create \
--src "G.V('a5f2fd0d-1f30-46a9-75ff-6ba4c82426a1')" \
--dst "G.V('99d511f5-5088-4c0d-67db-e45af33cb87c')" \
--count 5
And we can finally get the flows. We will get 2 flows as we started two captures so one ECHO/REPLY flow per capture.
skydive client query "G.Flows().Has('Application', 'ICMPv4')"
We can just select a specific field using the Values
Gremlin
step.
skydive client query "G.Flows().Has('Application', 'ICMPv4').Values('Network')"
[
{
"Protocol": "IPV4",
"A": "192.168.121.112",
"B": "192.168.121.217",
"ID": 0
},
{
"Protocol": "IPV4",
"A": "192.168.121.112",
"B": "192.168.121.217",
"ID": 0
}
]
skydive client query "G.Flows().Has('Application', 'ICMPv4').Values('Metric')"
[
{
"ABPackets": 5,
"ABBytes": 210,
"BAPackets": 5,
"BABytes": 210,
"Start": 1520545797027,
"Last": 1520545797027
},
{
"ABPackets": 5,
"ABBytes": 300,
"BAPackets": 5,
"BABytes": 210,
"Start": 1520545796988,
"Last": 1520545796988
}
]
Flows have a unique UUID
per capture but also have a TrackingID
which is the same across multiple captures.
skydive client query "G.Flows().Has('Application', 'ICMPv4').Values('TrackingID')"
[
"b53dafa2e10d19d5c1598e0bc723b7eb5bc3655a",
"b53dafa2e10d19d5c1598e0bc723b7eb5bc3655a"
]
The Gremlin
step Dedup
de-duplicates flow according to the TrackingID
.
skydive client query "G.Flows().Has('Application', 'ICMPv4').Dedup()"
[
{
"UUID": "bad1803ce7caa70e7835356afdccacaa8e89b185",
"LayersPath": "Ethernet/IPv4/ICMPv4",
"Application": "ICMPv4",
"Link": {
"Protocol": "ETHERNET",
"A": "52:54:00:cc:e2:ef",
"B": "52:54:00:43:8c:a3",
"ID": 0
},
"Network": {
"Protocol": "IPV4",
"A": "192.168.121.112",
"B": "192.168.121.217",
"ID": 0
},
"ICMP": {
"Type": "ECHO",
"Code": 0,
"ID": 0
},
"Metric": {
"ABPackets": 5,
"ABBytes": 210,
"BAPackets": 5,
"BABytes": 210,
"Start": 1520545797027,
"Last": 1520545797027
},
"Start": 1520545797027,
"Last": 1520545797027,
"RTT": 208265,
"TrackingID": "b53dafa2e10d19d5c1598e0bc723b7eb5bc3655a",
"L3TrackingID": "52e47eab007caeb74cfba34f713242f939a11ce7",
"ParentUUID": "",
"NodeTID": "50037073-7862-5234-4996-e58cc067c69c",
"BNodeTID": "50037073-7862-5234-4996-e58cc067c69c",
"RawPacketsCaptured": 0
}
]
We can also specify the capture from where we want to get the flow.
skydive client query "G.V('50037073-7862-5234-4996-e58cc067c69c').Flows().Has('Application', 'ICMPv4')"
[
{
"UUID": "bad1803ce7caa70e7835356afdccacaa8e89b185",
"LayersPath": "Ethernet/IPv4/ICMPv4",
"Application": "ICMPv4",
"Link": {
"Protocol": "ETHERNET",
"A": "52:54:00:cc:e2:ef",
"B": "52:54:00:43:8c:a3",
"ID": 0
},
"Network": {
"Protocol": "IPV4",
"A": "192.168.121.112",
"B": "192.168.121.217",
"ID": 0
},
"ICMP": {
"Type": "ECHO",
"Code": 0,
"ID": 0
},
"Metric": {
"ABPackets": 5,
"ABBytes": 210,
"BAPackets": 5,
"BABytes": 210,
"Start": 1520545797027,
"Last": 1520545797027
},
"Start": 1520545797027,
"Last": 1520545797027,
"RTT": 208265,
"TrackingID": "b53dafa2e10d19d5c1598e0bc723b7eb5bc3655a",
"L3TrackingID": "52e47eab007caeb74cfba34f713242f939a11ce7",
"ParentUUID": "",
"NodeTID": "50037073-7862-5234-4996-e58cc067c69c",
"BNodeTID": "50037073-7862-5234-4996-e58cc067c69c",
"RawPacketsCaptured": 0
}
]
If you created a capture with a Name
…
skydive client capture create --name Test123 --gremlin "G.V().Has('Name', 'eth0')"
…you can use it to select the flows.
skydive client query "G.V().Has('Capture.Name', 'Test123').Flows().Has('Application', 'ICMPv4')"
It is also possible to start from a flow to get all the captured interfaces
where ICMPv4
flows have been seen.
skydive client query "G.Flows().Has('Application', 'ICMPv4').CaptureNode().Values('ID')"
[
"a5f2fd0d-1f30-46a9-75ff-6ba4c82426a1",
"99d511f5-5088-4c0d-67db-e45af33cb87c"
]
In order to get only one specific flow we need to use its TrackingID
as this ID is
the same across multiple capture points.
skydive client query "G.Flows().Has('TrackingID', 'b53dafa2e10d19d5c1598e0bc723b7eb5bc3655a').CaptureNode().Values('ID')"
[
"a5f2fd0d-1f30-46a9-75ff-6ba4c82426a1",
"99d511f5-5088-4c0d-67db-e45af33cb87c"
]
This post was just an introduction to the Skydive API and query language. The same language
is leveraged by some other features that Skydive brings, like alerting
. A more complete
documentation is available here