In other words, if I open a TCP socket the usual way, is there a way in Linux to retrieve packet loss counts for that particular socket from the process that created the socket?
You can use TCP_INFO. This will give you a struct tcp_info that has among other members one called tcpi_lost:
...
164 __u32 tcpi_unacked;
165 __u32 tcpi_sacked;
166 __u32 tcpi_lost;
167 __u32 tcpi_retrans;
168 __u32 tcpi_facke
...
Although that member doesn't have documentation, one can see it relates to "lost packets" because it is set like this
info->tcpi_lost = tp->lost_out
And lost_out does have a comment:
u32 lost_out; /* Lost packets */
Related
I am creating a chat application backend and want to take into consideration the scalability.
I wanted to create a load balancer but not on the L7 layer where HTTP is located, but on the L3 layer where IP network is located to direct connections to the specific servers where I can then make TCP.
Is net.ListenIP the correct function to use to listen to the packets on the IP layer?
Is it the same as the higher Listen("tcp") for example? Is it the right method that I need to implement the load balancer?
Is there a reference to how the packet is structured so I am able get out from it the source and destination IPs to forward them?
If not tell me which function to use to listen on the L3 network layer to balance the loads to other servers.
Personally, I use gopacket in order to capture multiple network layers, and this library is very impressive.
When you're using gopacket, you are able to capture multiple network layers by specifying them, for example Ipv4, TCP, Ethernet...
For more information, see layers packet.
Then, you will be able to analyze your layers by using packet.Data(), which is a set of bytes that make up this entire packet, and then switch on the packet type to perform some actions.
For example, capturing multiple network layers on eth0 :
package main
import (
"fmt"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
"time"
)
//Layers we want to decode
var (
ip4 layers.IPv4
eth layers.Ethernet
tcp layers.TCP
)
func main() {
//Array to store decoded layers
decodedLayers := []gopacket.LayerType{}
//Create parser
parser := gopacket.NewDecodingLayerParser(layers.LayerTypeEthernet, ð, &ip4, &tcp)
//Here we use pcap to capture packet on eth0 interface, we can also use afpacket for example, which is more efficient
handle, err := pcap.OpenLive("eth0", 65536, true, pcap.BlockForever)
if err != nil {
panic("Error opening pcap: " + err.Error())
}
datasource := gopacket.NewPacketSource(handle, layers.LayerTypeEthernet)
//packets will be a channel of packets
packets := datasource.Packets()
for {
select {
case packet := <-packets:
//We are decoding layers, and switching on the layer type
err := parser.DecodeLayers(packet.Data(), &decodedLayers)
for _, typ := range decodedLayers {
switch typ {
case layers.LayerTypeIPv4:
fmt.Printf("Source ip = %s - Destination ip = %s \n", ip4.SrcIP.String(), ip4.DstIP.String())
case layers.LayerTypeTCP:
//Here, we can access tcp packet properties
fmt.Println("Capture tcp traffic")
}
//etc ....
}
if len(decodedLayers) == 0 {
fmt.Println("Packet truncated")
}
//If the DecodeLayers is unable to decode the next layer type
if err != nil {
//fmt.Printf("Layer not found : %s", err)
}
}
}
}
After reading the Docs, yes this function will help you receive IP Packets.
ListenIP acts like ListenPacket for IP networks.
ListenIP is similar to ListenPacket("tcp") but for IP packets.
As for the structure of IP packets, and working with them, the net package doesn't seem to have that.
There's another package gopacket which looks like it will be able to help you read and modify packets from any layer.
In gopacket there is a Packet type, which allows working with the network layer.
Packet.NetworkLayer().LayerContent() and Packet.NetworkLayer().LayerPayload() will each return byte[] which you can interpret by the expected structure of an IP packet.
Note: Now that I've written this whole thing I have to imagine somebody out there has written a nice overlay/wrapper to make this easier. This is just the result of me Googling for 10 minutes. Maybe somebody else will answer with a better tool/method
I started learning on Contiki OS. I am trying to analyze few parameters like energy efficiency, latency, delivery ratio etc with different deployment scenarios. First I should change some parameter like:
Channel check rate to 16/s (I use rpl-sink)
RPL mode of operation to NO_DOWNWARD_ROUTE
Send interval to 5s
UDP application packet size to 100 Bytes
Could you please tell me how to change these parameter in Contiki 2.7?
My answers for reference:
Channel check rate to 16/s (I use rpl-sink)
#undef NETSTACK_RDC_CHANNEL_CHECK_RATE
#define NETSTACK_RDC_CHANNEL_CHECK_RATE 16
RPL mode of operation to NO_DOWNWARD_ROUTE
It's called non-storing mode. To enable it:
#define RPL_CONF_WITH_NON_STORING 1
Send interval to 5s
Depends on the application; there is no standard name for this parameter. If we're talking about ipv6/rpl-collect/, you should #define PERIOD 5 in project-conf.h.
UDP application packet size to 100 Bytes
The payload is constructed in udp-sender.c:
uip_udp_packet_sendto(client_conn, &msg, sizeof(msg),
&server_ipaddr, UIP_HTONS(UDP_SERVER_PORT));
So in order to change the payload size, you need to change the size of the locally-defined anonymous struct variable called msg. You can add some dummy fields to it, for example.
struct {
uint8_t seqno;
uint8_t for_alignment;
struct collect_view_data_msg msg;
char dummy[100 - 2 - sizeof(struct collect_view_data_msg)];
} msg;
I am using a raspberry Pi and arduino CAN schield which is using a MCP2515 and SPI to request a single OBD II PID.
I am able to request and receive a single PID from my OBD emulator (Freematics). I know that is possible to request multiple PIDs (up to 6 PIDs) in a single query.
Whenever I use other kind of messages, I receive only the first request. Can anybody maybe help?
Here is the message for single PID which is working (C++):
msg.id = 0x7DF; //ID_QUERY
msg.header.rtr = 0;
msg.header.length = 0x08;
msg.data[0] = 0x02;
msg.data[1] = 0x01;
msg.data[2] = PID; //Whatever PID I want!
Message for multiple request that is not working:
msg.id = 0x7DF; //ID_QUERY
msg.header.rtr = 0;
msg.header.length = 0x08;
msg.data[0] = 0x07; //! Also it is not working with 0x08
msg.data[1] = 0x01;
msg.data[2] = PID0;
msg.data[3] = PID1;
msg.data[4] = PID2;
msg.data[5] = PID3;
msg.data[6] = PID4;
msg.data[7] = PID5;
Our Freematics OBD II emulator does not support sending multiple responses. One of our test vehicles, a 2010 Toyota corolla does. In our experience it is best to send a test command at startup to see if the device we're communicating with supports multiple responses or not. For our application we send the command 00 twice,
010000
If the response its greater than 25 characters, we know the device supports multiple commands as it responded to both 00 commands. If the response is less than 25 characters, we know the device responded to just the first 00 command and consequently only supports one command at a time. checking how many responses were received could be done multiple ways, but length has worked well for us so far.
Based on your use case, it may be enough to only send single commands. But if you really need the increased speed of multiple commands, add a check at start up to see if the device responds to multiple commands and then construct your messages based on the results. Dont forget to end your messages with the expected number of response lines to further increase speed. See the attached taken from: http://elmelectronics.com/DSheets/ELM327DS.pdf
Sending canbus messages through mcp2515 is a litle bit tricky.
First of all Freematics OBD Emulator support no multiple PID requests. Secondly, the multiple PID request should be sent with ISO 15765 format. when you send a multiple request, he ECU would response only with one "First Frame" message and will wait for the "Flow Control" message from the sender. After receiving the flow control, ECU will continue to sending the responses based on your flow control setting.
For more information about the CAN-Bus messages and how "First Frame" and "Single Frame" works, read the below links:
googleBooks, ISO_15765-2, hackaday (dot) com
I have a dissector that runs above the TCP protocol and has data that flows on more than one TCP packet.
I want to assemble the data before I convert everything, so I understood that I need tcp_dissect_pdus() for it, but I can't find documentation or examples for it.
Can anyone direct me to it or help me understand how I use it?
There is no wslua API for tcp_dissect_pdus. But you can implement it yourself.
If you want to assemble pdu that span two or more packets it's rather simple:
function slicer.dissector(tvb, pinfo, tree)
...
local pdu_length = get_pdu_length(...)
if pdu_length > tvb:len() then
pinfo.desegment_len = pdu_length - tvb:len()
else
do_dissection(tvb, pifo, tree)
end
return
end
If you don't know exact length of the pdu you can do:
pinfo.desegment_len = DESEGMENT_ONE_MORE_SEGMENT
You should read README.developer section 2.7.
I have a UDP server that reflects every ping message it receives (this works well I think). I the client side I would then like to do two things:
make sure that I fired off N (e.g. 10000) messages, and
count the number of correctly received responses.
It seems that either because of the nature of UDP or because of the forkIO thing, my client code below ends prematurely/does not do any counting at all.
Also I am very surprised to see that the function tryOnePing returns 250 times the Int 4. Why could this be?
main = withSocketsDo $ do
s <- socket AF_INET Datagram defaultProtocol
hostAddr <- inet_addr host
thread <- forkIO $ receiveMessages s
-- is there any better way to eg to run that in parallel and make sure
-- that sending/receiving are asynchronous?
-- forM_ [0 .. 10000] $ \i -> do
-- sendTo s "ping" (SockAddrInet port hostAddr)
-- actually this would be preferred since I can discard the Int 4 that
-- it returns but forM or forM_ are out of scope here?
let tryOnePing i = sendTo s "ping" (SockAddrInet port hostAddr)
pings <- mapM tryOnePing [0 .. 1000]
let c = length $ filter (\x -> x==4) pings
-- killThread thread
-- took that out to make sure the function receiveMessages does not
-- end prematurely. still seems that it does
sClose s
print c
-- return()
receiveMessages :: Socket -> IO ()
receiveMessages socket = forever $ do
-- also tried here forM etc. instead of forever but no joy
let recOnePing i = recv socket 1024
msg <- mapM recOnePing [0 .. 1000]
let r = length $ filter (\x -> x=="PING") msg
print r
print "END"
The main problem here is that when your main thread finishes, all other threads gets killed automatically. You have to get the main thread to wait for the receiveMessages thread, or it will in all likelyhood simply finish before any responses have been received. One simple way of doing this is to use an MVar.
An MVar is a synchronized cell that can either be empty or hold exactly one value. The current thread will block if it tries to take from an empty MVar or insert into a full one.
In this case, we don't care about the value itself, so we'll just store a () in it.
We'll start with the MVar empty. Then the main thread will fork off the receiver thread, send all the packets, and try to take the value from the MVar.
import Control.Concurrent.MVar
main = withSocketsDo $ do
-- prepare socket, same as before
done <- newEmptyMVar
-- we need to pass the MVar to the receiver thread so that
-- it can use it to signal us when it's done
forkIO $ receiveMessages sock done
-- send pings, same as before
takeMVar done -- blocks until receiver thread is done
In the receiver thread, we will receive all the messages and then put a () in the MVar to signal that we're done receiving.
receiveMessages socket done = do
-- receive messages, same as before
putMVar done () -- allows the main thread to be unblocked
This solves the main issue, and the program runs fine on my Ubuntu laptop, but there are a couple more things you want to take care of.
sendTo does not guarantee that the whole string will be sent. You'll have to check the return value to see how much was sent, and retry if not all of it was sent. This can happen even for a short message like "ping" if the send buffer is full.
recv requires a connected socket. You'll want to use recvFrom instead. (Although it still works on my PC for some unknown reason).
Printing to standard output is not synchronized, so you might want to alter this so that the MVar will be used to communicate the number of received packets instead of just (). That way, you can do all the output from the main thread. Alternatively, use another MVar as a mutex to control access to standard output.
Finally, I recommend reading the documentation of Network.Socket, Control.Concurrent and Control.Concurrent.MVar carefully. Most of my answer is stitched together from information found there.