@@ -45,10 +45,14 @@ type endpoint struct {
4545 // its end of the communication pipe.
4646 closed func (* tcpip.Error )
4747
48- vv * buffer.VectorisedView
49- iovecs []syscall.Iovec
50- views []buffer.View
51- attached bool
48+ vv * buffer.VectorisedView
49+ iovecs []syscall.Iovec
50+ views []buffer.View
51+ dispatcher stack.NetworkDispatcher
52+
53+ // egressLocal indicates whether packets destined to itself should be
54+ // forwarded to the FD endpoint (true) or be sent back to netstack (false).
55+ egressLocal bool
5256}
5357
5458// Options specify the details about the fd-based endpoint to be created.
@@ -59,6 +63,7 @@ type Options struct {
5963 ChecksumOffload bool
6064 ClosedFunc func (* tcpip.Error )
6165 Address tcpip.LinkAddress
66+ EgressLocal bool
6267}
6368
6469// New creates a new fd-based endpoint.
@@ -80,14 +85,15 @@ func New(opts *Options) tcpip.LinkEndpointID {
8085 }
8186
8287 e := & endpoint {
83- fd : opts .FD ,
84- mtu : opts .MTU ,
85- caps : caps ,
86- closed : opts .ClosedFunc ,
87- addr : opts .Address ,
88- hdrSize : hdrSize ,
89- views : make ([]buffer.View , len (BufConfig )),
90- iovecs : make ([]syscall.Iovec , len (BufConfig )),
88+ fd : opts .FD ,
89+ mtu : opts .MTU ,
90+ caps : caps ,
91+ closed : opts .ClosedFunc ,
92+ addr : opts .Address ,
93+ hdrSize : hdrSize ,
94+ views : make ([]buffer.View , len (BufConfig )),
95+ iovecs : make ([]syscall.Iovec , len (BufConfig )),
96+ egressLocal : opts .EgressLocal ,
9197 }
9298 vv := buffer .NewVectorisedView (0 , e .views )
9399 e .vv = & vv
@@ -97,13 +103,13 @@ func New(opts *Options) tcpip.LinkEndpointID {
97103// Attach launches the goroutine that reads packets from the file descriptor and
98104// dispatches them via the provided dispatcher.
99105func (e * endpoint ) Attach (dispatcher stack.NetworkDispatcher ) {
100- e .attached = true
101- go e .dispatchLoop (dispatcher ) // S/R-FIXME
106+ e .dispatcher = dispatcher
107+ go e .dispatchLoop () // S/R-FIXME
102108}
103109
104110// IsAttached implements stack.LinkEndpoint.IsAttached.
105111func (e * endpoint ) IsAttached () bool {
106- return e .attached
112+ return e .dispatcher != nil
107113}
108114
109115// MTU implements stack.LinkEndpoint.MTU. It returns the value initialized
@@ -130,6 +136,12 @@ func (e *endpoint) LinkAddress() tcpip.LinkAddress {
130136// WritePacket writes outbound packets to the file descriptor. If it is not
131137// currently writable, the packet is dropped.
132138func (e * endpoint ) WritePacket (r * stack.Route , hdr * buffer.Prependable , payload buffer.View , protocol tcpip.NetworkProtocolNumber ) * tcpip.Error {
139+ if ! e .egressLocal && r .LocalAddress != "" && r .LocalAddress == r .RemoteAddress {
140+ hdrView := hdr .View ()
141+ vv := buffer .NewVectorisedView (len (hdrView )+ len (payload ), []buffer.View {hdrView , payload })
142+ e .dispatcher .DeliverNetworkPacket (e , r .RemoteLinkAddress , protocol , & vv )
143+ return nil
144+ }
133145 if e .hdrSize > 0 {
134146 // Add ethernet header if needed.
135147 eth := header .Ethernet (hdr .Prepend (header .EthernetMinimumSize ))
@@ -142,7 +154,6 @@ func (e *endpoint) WritePacket(r *stack.Route, hdr *buffer.Prependable, payload
142154
143155 if len (payload ) == 0 {
144156 return rawfile .NonBlockingWrite (e .fd , hdr .UsedBytes ())
145-
146157 }
147158
148159 return rawfile .NonBlockingWrite2 (e .fd , hdr .UsedBytes (), payload )
@@ -175,7 +186,7 @@ func (e *endpoint) allocateViews(bufConfig []int) {
175186}
176187
177188// dispatch reads one packet from the file descriptor and dispatches it.
178- func (e * endpoint ) dispatch (d stack. NetworkDispatcher , largeV buffer.View ) (bool , * tcpip.Error ) {
189+ func (e * endpoint ) dispatch (largeV buffer.View ) (bool , * tcpip.Error ) {
179190 e .allocateViews (BufConfig )
180191
181192 n , err := rawfile .BlockingReadv (e .fd , e .iovecs )
@@ -211,7 +222,7 @@ func (e *endpoint) dispatch(d stack.NetworkDispatcher, largeV buffer.View) (bool
211222 e .vv .SetSize (n )
212223 e .vv .TrimFront (e .hdrSize )
213224
214- d .DeliverNetworkPacket (e , addr , p , e .vv )
225+ e . dispatcher .DeliverNetworkPacket (e , addr , p , e .vv )
215226
216227 // Prepare e.views for another packet: release used views.
217228 for i := 0 ; i < used ; i ++ {
@@ -223,10 +234,10 @@ func (e *endpoint) dispatch(d stack.NetworkDispatcher, largeV buffer.View) (bool
223234
224235// dispatchLoop reads packets from the file descriptor in a loop and dispatches
225236// them to the network stack.
226- func (e * endpoint ) dispatchLoop (d stack. NetworkDispatcher ) * tcpip.Error {
237+ func (e * endpoint ) dispatchLoop () * tcpip.Error {
227238 v := buffer .NewView (header .MaxIPPacketSize )
228239 for {
229- cont , err := e .dispatch (d , v )
240+ cont , err := e .dispatch (v )
230241 if err != nil || ! cont {
231242 if e .closed != nil {
232243 e .closed (err )
0 commit comments