Re: Tips for local testing guestfwd

2023-09-06 Thread Felix Wu
Hi,
I noticed why the chardev socket backend disconnects, and I would like to
make this a RFC to see how I should fix it.
Current scenario after boot-up:

   1. tcp_chr_read_poll keeps polling the slirp_socket_can_recv, and
   slirp_socket_can_recv returns 0 since slirp_find_ctl_socket couldn't
   find the guestfwd socket.
   2. The returned 0 in step 1 was assigned to the s->max_size (s is
SocketChardev
   *), and the socket chardev handler won't read since readable size is 0.
   3. When the 1st request is sent, the guestfwd socket is added into the
   slirp's socket list, instead of 0, tcp_chr_read_poll will return the
   result of sopreprbuf > 0.
   4. tcp_chr_read reads the thing.
   5. tcp_chr_read_poll still returns things > 0, which is the output of
   sopreprbuf.
   6. tcp_chr_read reads the thing again, but there's nothing in the
   buffer, so it's unhappy, and closes the connection.
   7. any follow-up requests won't be handled.

These tcp_chr* functions are in fle [1], and slirp_* are in fle [2].

My questions:
1. Since this thing doesn't work on 2nd and later requests, I want to know
how this thing is supposed to work, and to avoid asking people vaguely, I
will provide my though following and please correct me if I am wrong:
a. The state machine in chardev socket should maintain a connected
state (s->state
== TCP_CHARDEV_STATE_CONNECTED), this means no change in [1].
b. slirp_socket_can_recv should return 0 once all data is read instead of
outcome from sopreprbuf. This means I need to remove the socket or change
its state to no file descriptor [3], namely somehow reset it.
c. When a new request comes in, it will need to add the socket back to this
slirp instance's socket list, populate its file descriptor, and establish
the connection.

b and c sounds convoluted so I want to check.

2. What is the outcome of sopreprbuf function [3]?
Since it's returned to the tcp_chr_read_poll function, I thought it's the
readable bytes in the socket, but in my test I noticed following thing:

tcp_chr_read_poll_size : s->max_size: 132480
tcp_chr_read : size: 2076
tcp_chr_read_poll_size : s->max_size: 129600
tcp_chr_read : size: 0

Even there's not remaining things in the buffer (read size 0), it's still
non-zero, and thus the read function keeps reading it until it becomes
unhappy.
Also, 132480-129600 = 2880 vs 2076, the read byte doesn't match.

Either I need to go with the way in question 1, b.c. steps, or I don't need
to delete the socket, but the sopreprbuf wasn't proper to be used there and
I need to correct it.
Also updated https://gitlab.com/qemu-project/qemu/-/issues/1835.

Any feedback will be appreciated, thanks!
Felix

[1].
https://gitlab.com/qemu-project/qemu/-/blob/master/chardev/char-socket.c#L141
[2].
https://gitlab.freedesktop.org/slirp/libslirp/-/blob/master/src/slirp.c#L1582
[3].
https://gitlab.freedesktop.org/slirp/libslirp/-/blob/master/src/socket.h#L221

On Wed, Aug 23, 2023 at 10:27 AM Felix Wu  wrote:

> Update on debugging this thing (already updated
> https://gitlab.com/qemu-project/qemu/-/issues/1835):
> I saw that `tcp_chr_free_connection` was called after the first response
> being successfully sent:
> ```
>
> slirp_guestfwd_write guestfwd_write: size 80tcp_chr_write tcp_chr_write: 
> s->state:2tcp_chr_write tcp_chr_write: len:80qemu_chr_write_parameter len: 80 
> // tracking qemu_chr_writeqemu_chr_write_res len: 80 // same 
> thingtcp_chr_free_connection tcp_chr_free_connection: state: 2, changing it 
> to disconnecttcp_chr_change_state tcp_chr_change_state: state: 2, next state: 
> 0 // state 2==connected, 0==disconnected.
>
> ```
> And after that, the state of `SocketChardev` remained disconnected, and
> when the 2nd request came in, the `tcp_chr_write` dropped it directly.
> Maybe this state machine should be reset after every connection? Not sure.
>
> On Thu, Aug 17, 2023 at 11:58 AM Felix Wu  wrote:
>
>> Hi Samuel,
>>
>> Thanks for the clarification! I missed the email so didn't reply in time,
>> but was able to figure it out.
>>
>> Hi everyone,
>> IPv6 guestfwd works in my local test but it has a weird bug: if you send
>> two requests, the first one gets the correct response, but the second one
>> gets stuck.
>> I am using a simple http server for this test, and just noticed this bug
>> also exists in IPv4 guestfwd. I've documented it in
>> https://gitlab.com/qemu-project/qemu/-/issues/1835.
>>
>> Just want to check if anyone has seen the same issue before.
>>
>> Thanks! Felix
>>
>> On Thu, Jul 20, 2023 at 7:54 AM Samuel Thibault 
>> wrote:
>>
>>> Hello,
>>>
>>> Felix Wu, le mar. 18 juil. 2023 18:12:16 -0700, a ecrit:
>>> > 02 == SYN so it looks good. But both tcpdump and wireshark (looking
>>> into packet
>>> > dump provided by QEMU invocation)
>>>
>>> Which packet dump?
>>>
>>> > I added multiple prints inside slirp and confirmed the ipv6 version of
>>> [1] was
>>> > reached.
>>> > in tcp_output function [2], I got following print:
>>> > qemu-system-aarch64: info: Slirp: 

Re: Tips for local testing guestfwd

2023-08-23 Thread Felix Wu
Update on debugging this thing (already updated
https://gitlab.com/qemu-project/qemu/-/issues/1835):
I saw that `tcp_chr_free_connection` was called after the first response
being successfully sent:
```

slirp_guestfwd_write guestfwd_write: size 80tcp_chr_write
tcp_chr_write: s->state:2tcp_chr_write tcp_chr_write:
len:80qemu_chr_write_parameter len: 80 // tracking
qemu_chr_writeqemu_chr_write_res len: 80 // same
thingtcp_chr_free_connection tcp_chr_free_connection: state: 2,
changing it to disconnecttcp_chr_change_state tcp_chr_change_state:
state: 2, next state: 0 // state 2==connected, 0==disconnected.

```
And after that, the state of `SocketChardev` remained disconnected, and
when the 2nd request came in, the `tcp_chr_write` dropped it directly.
Maybe this state machine should be reset after every connection? Not sure.

On Thu, Aug 17, 2023 at 11:58 AM Felix Wu  wrote:

> Hi Samuel,
>
> Thanks for the clarification! I missed the email so didn't reply in time,
> but was able to figure it out.
>
> Hi everyone,
> IPv6 guestfwd works in my local test but it has a weird bug: if you send
> two requests, the first one gets the correct response, but the second one
> gets stuck.
> I am using a simple http server for this test, and just noticed this bug
> also exists in IPv4 guestfwd. I've documented it in
> https://gitlab.com/qemu-project/qemu/-/issues/1835.
>
> Just want to check if anyone has seen the same issue before.
>
> Thanks! Felix
>
> On Thu, Jul 20, 2023 at 7:54 AM Samuel Thibault 
> wrote:
>
>> Hello,
>>
>> Felix Wu, le mar. 18 juil. 2023 18:12:16 -0700, a ecrit:
>> > 02 == SYN so it looks good. But both tcpdump and wireshark (looking
>> into packet
>> > dump provided by QEMU invocation)
>>
>> Which packet dump?
>>
>> > I added multiple prints inside slirp and confirmed the ipv6 version of
>> [1] was
>> > reached.
>> > in tcp_output function [2], I got following print:
>> > qemu-system-aarch64: info: Slirp: AF_INET6 out dst ip =
>> > fdb5:481:10ce:0:8c41:aaff:fea9:f674, port = 52190
>> > qemu-system-aarch64: info: Slirp: AF_INET6 out src ip = fec0::105, port
>> = 54322
>> > It looks like there should be something being sent back to the guest,
>>
>> That's what it is.
>>
>> > unless my understanding of tcp_output is wrong.
>>
>> It looks so.
>>
>> > To understand the datapath of guestfwd better, I have the following
>> questions:
>> > 1. What's the meaning of tcp_input and tcp_output? My guess is the
>> following
>> > graph, but I would like to confirm.
>>
>> No, tcp_input is for packets that come from the guest, and tcp_output is
>> for packets that are send to the guest. So it's like that:
>>
>> > tcp_inputwrite_cb  host send()
>> > QEMU > slirp ---> QEMU > host
>> > <<- <-
>> >  tcp_output  slirp_socket_recvhost recv()
>>
>> > 2. I don't see port 6655 in the above process. How does slirp know 6655
>> is the
>> > port that needs to be visited on the host side?
>>
>> Slirp itself *doesn't* know that port. The guestfwd piece just calls the
>> SlirpWriteCb when it has data coming from the guest. See the
>> documentation:
>>
>> /* Set up port forwarding between a port in the guest network and a
>>  * callback that will receive the data coming from the port */
>> SLIRP_EXPORT
>> int slirp_add_guestfwd(Slirp *slirp, SlirpWriteCb write_cb, void *opaque,
>>struct in_addr *guest_addr, int guest_port);
>>
>> and
>>
>> /* This is called by the application for a guestfwd, to provide the data
>> to be
>>  * sent on the forwarded port */
>> SLIRP_EXPORT
>> void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr, int
>> guest_port,
>>const uint8_t *buf, int size);
>>
>> Samuel
>>
>


Re: Tips for local testing guestfwd

2023-08-17 Thread Felix Wu
Hi Samuel,

Thanks for the clarification! I missed the email so didn't reply in time,
but was able to figure it out.

Hi everyone,
IPv6 guestfwd works in my local test but it has a weird bug: if you send
two requests, the first one gets the correct response, but the second one
gets stuck.
I am using a simple http server for this test, and just noticed this bug
also exists in IPv4 guestfwd. I've documented it in
https://gitlab.com/qemu-project/qemu/-/issues/1835.

Just want to check if anyone has seen the same issue before.

Thanks! Felix

On Thu, Jul 20, 2023 at 7:54 AM Samuel Thibault 
wrote:

> Hello,
>
> Felix Wu, le mar. 18 juil. 2023 18:12:16 -0700, a ecrit:
> > 02 == SYN so it looks good. But both tcpdump and wireshark (looking into
> packet
> > dump provided by QEMU invocation)
>
> Which packet dump?
>
> > I added multiple prints inside slirp and confirmed the ipv6 version of
> [1] was
> > reached.
> > in tcp_output function [2], I got following print:
> > qemu-system-aarch64: info: Slirp: AF_INET6 out dst ip =
> > fdb5:481:10ce:0:8c41:aaff:fea9:f674, port = 52190
> > qemu-system-aarch64: info: Slirp: AF_INET6 out src ip = fec0::105, port
> = 54322
> > It looks like there should be something being sent back to the guest,
>
> That's what it is.
>
> > unless my understanding of tcp_output is wrong.
>
> It looks so.
>
> > To understand the datapath of guestfwd better, I have the following
> questions:
> > 1. What's the meaning of tcp_input and tcp_output? My guess is the
> following
> > graph, but I would like to confirm.
>
> No, tcp_input is for packets that come from the guest, and tcp_output is
> for packets that are send to the guest. So it's like that:
>
> > tcp_inputwrite_cb  host send()
> > QEMU > slirp ---> QEMU > host
> > <<- <-
> >  tcp_output  slirp_socket_recvhost recv()
>
> > 2. I don't see port 6655 in the above process. How does slirp know 6655
> is the
> > port that needs to be visited on the host side?
>
> Slirp itself *doesn't* know that port. The guestfwd piece just calls the
> SlirpWriteCb when it has data coming from the guest. See the
> documentation:
>
> /* Set up port forwarding between a port in the guest network and a
>  * callback that will receive the data coming from the port */
> SLIRP_EXPORT
> int slirp_add_guestfwd(Slirp *slirp, SlirpWriteCb write_cb, void *opaque,
>struct in_addr *guest_addr, int guest_port);
>
> and
>
> /* This is called by the application for a guestfwd, to provide the data
> to be
>  * sent on the forwarded port */
> SLIRP_EXPORT
> void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr, int
> guest_port,
>const uint8_t *buf, int size);
>
> Samuel
>


Re: Tips for local testing guestfwd

2023-07-20 Thread Samuel Thibault
Hello,

Felix Wu, le mar. 18 juil. 2023 18:12:16 -0700, a ecrit:
> 02 == SYN so it looks good. But both tcpdump and wireshark (looking into 
> packet
> dump provided by QEMU invocation)

Which packet dump?

> I added multiple prints inside slirp and confirmed the ipv6 version of [1] was
> reached.
> in tcp_output function [2], I got following print:
> qemu-system-aarch64: info: Slirp: AF_INET6 out dst ip =
> fdb5:481:10ce:0:8c41:aaff:fea9:f674, port = 52190
> qemu-system-aarch64: info: Slirp: AF_INET6 out src ip = fec0::105, port = 
> 54322
> It looks like there should be something being sent back to the guest,

That's what it is.

> unless my understanding of tcp_output is wrong.

It looks so.

> To understand the datapath of guestfwd better, I have the following questions:
> 1. What's the meaning of tcp_input and tcp_output? My guess is the following
> graph, but I would like to confirm.

No, tcp_input is for packets that come from the guest, and tcp_output is
for packets that are send to the guest. So it's like that:

>         tcp_inputwrite_cb  host send()
> QEMU > slirp ---> QEMU > host
>     <    <- <-
>          tcp_output  slirp_socket_recvhost recv()

> 2. I don't see port 6655 in the above process. How does slirp know 6655 is the
> port that needs to be visited on the host side?

Slirp itself *doesn't* know that port. The guestfwd piece just calls the
SlirpWriteCb when it has data coming from the guest. See the
documentation:

/* Set up port forwarding between a port in the guest network and a
 * callback that will receive the data coming from the port */
SLIRP_EXPORT
int slirp_add_guestfwd(Slirp *slirp, SlirpWriteCb write_cb, void *opaque,
   struct in_addr *guest_addr, int guest_port);

and 

/* This is called by the application for a guestfwd, to provide the data to be
 * sent on the forwarded port */
SLIRP_EXPORT
void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr, int guest_port,
   const uint8_t *buf, int size);

Samuel



Re: Tips for local testing guestfwd

2023-07-18 Thread Felix Wu
Hi all,

I am continuing debugging the ipv6 guestfwd feature, and I would like to
understand the behavior of slirp better.

Progress I've made:
Let QEMU take parameter like following:
guestfwd=tcp:[fec0::105]:54322-tcp:[::1]:6655
For slirp side, I basically searched for the appearance of gfwd_list and
made all code traverse the fwd list compatible with ipv6.
With these change, now I can see the packets coming out of the guest OS to
the assigned guest server port via tcpdump:
```
00:38:18.831831 IP6 fdb5:481:10ce:0:8c41:aaff:fea9:f674.52190 >
fec0::105.54322: tcp 0
0x:  600a 1f94 0028 0640 fdb5 0481 10ce   `(.@
0x0010:  8c41 aaff fea9 f674 fec0     .A.t
0x0020:     0105 cbde d432 df6d 8332  ...2.m.2
0x0030:    a0*02* fd20 535f  0204 05a0  S_..
0x0040:  0402 080a b87b fd3b   0103 0307  .{.;
```
02 == SYN so it looks good. But both tcpdump and wireshark (looking into
packet dump provided by QEMU invocation) didn't see any response and this
packet never reached the host.
I added multiple prints inside slirp and confirmed the ipv6 version of [1]
was reached.
in tcp_output function [2], I got following print:
qemu-system-aarch64: info: Slirp: AF_INET6 out dst ip =
fdb5:481:10ce:0:8c41:aaff:fea9:f674, port = 52190
qemu-system-aarch64: info: Slirp: AF_INET6 out src ip = fec0::105, port =
54322
It looks like there should be something being sent back to the guest,
unless my understanding of tcp_output is wrong.

To understand the datapath of guestfwd better, I have the following
questions:
1. What's the meaning of tcp_input and tcp_output? My guess is the
following graph, but I would like to confirm.
   tcp_input tcp_output
QEMU > slirp --> host
<   <--
 tcp_output   tcp_input

2. I don't see port 6655 in the above process. How does slirp know 6655 is
the port that needs to be visited on the host side?

Thanks in advance, Felix
[1].
https://gitlab.freedesktop.org/slirp/libslirp/-/blob/master/src/tcp_input.c#L630
[2].
https://gitlab.freedesktop.org/slirp/libslirp/-/blob/master/src/tcp_output.c#L477


On Mon, Jun 26, 2023 at 3:08 AM Samuel Thibault 
wrote:

> Hello,
>
> Felix Wu  wrote:
> > 2. I want to understand what ip I should use. Currently I have following
> > formats for the QEMU invocation in ipv6:
> > ```
> > guestfwd=tcp:[::1]:1234-tcp:[my:host:ip:from:ifconfig]:22
> > ```
> > I know the general form is `guestfwd=tcp:server:port-dev`, where
> > server:port is for guest,
>
> Yes, the address to be used within the guest network. So it needs to be
> within the guest network.
>
> > Is the aforementioned invocation correct?
>
> No, because ::1 isn't in the guest network.
>
> > Or in this case [::1] is the local host address and I should put qemu
> > address for it instead?
>
> You can use whatever IP you want, as long as it's in the guest network.
> e.g. [fec0::1234] if you're with the default fec0::/64 network.
>
> > 3. Is there a default ipv6 address for QEMU instance? I think I need it
> in
> > the invocation.
>
> By default it's address 2 within the prefix, i.e. fec0::2 with the
> default fec0::/64 network.
>
> Samuel
>


Re: Tips for local testing guestfwd

2023-06-26 Thread Samuel Thibault
Hello,

Felix Wu  wrote:
> 2. I want to understand what ip I should use. Currently I have following
> formats for the QEMU invocation in ipv6:
> ```
> guestfwd=tcp:[::1]:1234-tcp:[my:host:ip:from:ifconfig]:22
> ```
> I know the general form is `guestfwd=tcp:server:port-dev`, where
> server:port is for guest,

Yes, the address to be used within the guest network. So it needs to be
within the guest network.

> Is the aforementioned invocation correct?

No, because ::1 isn't in the guest network.

> Or in this case [::1] is the local host address and I should put qemu
> address for it instead?

You can use whatever IP you want, as long as it's in the guest network.
e.g. [fec0::1234] if you're with the default fec0::/64 network.

> 3. Is there a default ipv6 address for QEMU instance? I think I need it in
> the invocation.

By default it's address 2 within the prefix, i.e. fec0::2 with the
default fec0::/64 network.

Samuel



Re: Tips for local testing guestfwd

2023-06-26 Thread Lukas Straub
CC'ing SLIRP and net maintainer.

On Sun, 25 Jun 2023 22:58:36 -0700
Felix Wu  wrote:

> Hi all,
> 
> TL,DR: I am working on QEMU ipv6 guestfwd feature and finished coding, and
> would like to learn the best practice to test it.
> Context: in slirp side this task is tracking by [1].
> Currently, I have done following:
> i. made char parse + guestfwd functions happy with ipv6 address.
> ii. enabled debug print and made sure the ip and port are inserted into the
> forward list in libslirp.
> To sufficiently verify it's working, I do have three questions:
> 1. I want to forward a port in the guest (OS in QEMU) to a port 22 on the
> host OS, and ssh from guest back to host,
> does this sound reasonable? If this is not a good idea, what method is
> recommended?
> 2. I want to understand what ip I should use. Currently I have following
> formats for the QEMU invocation in ipv6:
> ```
> guestfwd=tcp:[::1]:1234-tcp:[my:host:ip:from:ifconfig]:22
> ```
> I know the general form is `guestfwd=tcp:server:port-dev`, where
> server:port is for guest, dev is for host.
> Adding [] in my implementation will let QEMU know it's ipv6.
> Is the aforementioned invocation correct? Or in this case [::1] is the
> local host address and I should put qemu address
> for it instead?
> 3. Is there a default ipv6 address for QEMU instance? I think I need it in
> the invocation.
> 
> Thanks in advance! Felix
> 
> [1]. https://gitlab.freedesktop.org/slirp/libslirp/-/issues/67



pgp7peayMUmmF.pgp
Description: OpenPGP digital signature