Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

xds: Delete check for router filter being last in config selector #6259

Closed
easwars opened this issue May 5, 2023 · 17 comments
Closed

xds: Delete check for router filter being last in config selector #6259

easwars opened this issue May 5, 2023 · 17 comments
Assignees
Labels

Comments

@easwars
Copy link
Contributor

easwars commented May 5, 2023

gRFC A39 talks about gRPC's support for xDS HTTP filters. This gRFC was amended as part of PR 250. While we ended up implementing most of the changes mentioned in the amendment, we failed to implement the config time validation check to ensure that an LDS resource contains the router filter as the last filter.

HTTP filters received as part of an LDS resource are processed in this function:

func processHTTPFilters(filters []*v3httppb.HttpFilter, server bool) ([]HTTPFilter, error) {

While we do validate that the filter chain is not empty and that the last filter in the chain is a terminal filter, we are not currently validating that the last filter is in-fact the router filter.

The router filter package does provide a utility function to check if a filter is the router filter:

func IsRouterFilter(b httpfilter.Filter) bool {

We can use that function here to ensure that the router filter is present in the list and that it is the last filter in the list.

@easwars
Copy link
Contributor Author

easwars commented May 5, 2023

@Aditya-Sood

@Aditya-Sood
Copy link
Contributor

thanks @easwars, I'll get started on this

@Aditya-Sood
Copy link
Contributor

hi @easwars
so I understand that we can additionally check for the terminal filter to also be a router filter as follows:

        if !ret[i].Filter.IsTerminal() {
                return nil, fmt.Errorf("http filter %q is not a terminal filter", ret[len(ret)-1].Name)
        }
+       if !router.IsRouterFilter(ret[len(ret)-1].Filter) {
+               return nil, fmt.Errorf("http filter %q is not a router filter", ret[len(ret)-1].Name)
+       }

however I'm still trying to figure out how to write the testcase for it

the IsRouterFilter() just checks whether the filter value passed can be asserted as a router.builder type (which in turn is an empty struct being used as a method receiver)

I found this testcase corresponding to the not a terminal filter test, trying to understand how to modify it for 'not a router filter` test

would you happen to have any pointers for me on how to do this?

@easwars
Copy link
Contributor Author

easwars commented May 8, 2023

If you scroll all the way to the bottom of unmarshal_lds_test.go, you will find a bunch of custom filter implementations used by the test such as clientOnlyHTTPFilter, serverOnlyHTTPFilter, errHTTPFilter etc. I would suggest adding another custom filter implementation here and call it something like terminalHTTPFilter. The implementation would be very similar to the type httpFilter (in the sense that it would embed both httpfilter.ClientInterceptorBuilder and httpfilter.ServerInterceptorBuilder), but the IsTerminal() method would return true.

And you would have to add a test case for both the client (TestUnmarshalListener_ClientSide) and server (TestUnmarshalListener_ServerSide) side to ensure that on both sides, if the terminal filter is not a router filter, we return the appropriate error.

Hope this helps.

@Aditya-Sood
Copy link
Contributor

Aditya-Sood commented May 9, 2023

Thank you, this is really helpful
One quick query - do we need to create a terminalNonRouterHTTPFilter as well? (To cover the test case of a terminal filter failing the router.IsRouterFilter() method)

@easwars
Copy link
Contributor Author

easwars commented May 9, 2023

Thank you, this is really helpful One quick query - do we need to create a terminalNonRouterHTTPFilter as well? (To cover the test case of a terminal filter failing the router.IsRouterFilter() method)

I thought that was the only test case to add. What other cases were you planning to add?

@easwars
Copy link
Contributor Author

easwars commented May 9, 2023

Is there an issue with checking that the last filter is in fact the router filter and not just any terminal filter?

@easwars
Copy link
Contributor Author

easwars commented May 9, 2023

Currently the config selector is checking if the last filter is the router filter, which doesn't seem like the correct place to have that check. If we at all should have that check, it should be in the xds client.

@zasweq
Copy link
Contributor

zasweq commented May 9, 2023

I don't see an issue with an explicit check for the router filter. However, if what I mentioned earlier was correct (router is only terminal filter), router filter -> terminal filter, so the check does technically encapsulate "in face the router filter" and not "any terminal filter"

@Aditya-Sood
Copy link
Contributor

hi @easwars
So initially I figured that there is a need for an additional terminalHTTPFilter because all the other filter types in the file (httpFilter, errHTTPFilter, serverOnlyHTTPFilter, clientOnlyHTTPFilter) were defined to return false for IsTerminal(); and so our new type would be the one to return true for it

However I was going through the actual tests which use those existing types and found that the filter chains in those tests in fact add a routerFilter explicitly as the last filter in the filter chain. Examples are as follows:

  1. httpFilter - https://github.com/grpc/grpc-go/blob/master/xds/internal/xdsclient/xdsresource/unmarshal_lds_test.go#L359
  2. errHTTPFilter - Surprisingly not used anywhere in the codebase except in the init() of unmarshal_lds_test.go - might have to create tests for it?
  3. clientOnlyHTTPFilter - https://github.com/grpc/grpc-go/blob/master/xds/internal/xdsclient/xdsresource/unmarshal_lds_test.go#L470
  4. serverOnlyHTTPFilter - https://github.com/grpc/grpc-go/blob/master/xds/internal/xdsclient/xdsresource/filter_chain_test.go#L1059

Now these Router type filters (i.e. router.builder type filters) already return true for IsTerminal() - link to router.builder type definition

Hence I think we could modify processHTTPFilters() to replace the IsTerminal() check with IsRouterFilter() check, because:
a. Router filters are Terminal filters by default (as they return true for IsTerminal() by definition)
b. All legal filter chains seem to use a Router filter as the last in the chain (based on my above observation of the existing test cases)

Then we just need to create one new NonRouterFilter HTTP filter type and test only for that

@easwars
Copy link
Contributor Author

easwars commented May 12, 2023

@Aditya-Sood : Sounds good.

@Aditya-Sood
Copy link
Contributor

Raised #6281 for the Router filter check

Also regarding the errHTTPFilter:

errHTTPFilter - Surprisingly not used anywhere in the codebase except in the init() of unmarshal_lds_test.go - might have to create tests for it?

Shall I create test cases for this as well in a separate PR?

@zasweq zasweq changed the title xds: ensure router filter is the last filter in the chain xds: Delete check for router filter being last in config selector May 31, 2023
@zasweq
Copy link
Contributor

zasweq commented May 31, 2023

As per discussion on #6281 and #6248, the xDS Client handling of this is correct and what the gRPC team designed. However, we have a trailing check in config selector that needs to be deleted from the deleted part in the gRFC. It is a currently a no-op, since emissions from the client will have router filter as last filter in chain, but it still is a cleanup that can be done.

@zasweq zasweq added Type: Internal Cleanup Refactors, etc and removed Type: Bug labels May 31, 2023
@Aditya-Sood
Copy link
Contributor

@zasweq could you confirm if this is the cleanup you are referring to be done as part of this PR?
#6248 (comment)

@zasweq zasweq added the P2 label Jun 6, 2023
@Aditya-Sood
Copy link
Contributor

hi @zasweq @easwars
I believe #6248 also fixes this issue, based on these changes?
forgot to mention this ticket in that PR

@zasweq
Copy link
Contributor

zasweq commented Aug 11, 2023

Yeah, that is :). Closing this issue.

@easwars easwars closed this as completed Aug 14, 2023
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Feb 11, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants