Skip to content

add channel filter extension point#219

Open
kralicky wants to merge 10 commits intomainfrom
kralicky/channel-filters
Open

add channel filter extension point#219
kralicky wants to merge 10 commits intomainfrom
kralicky/channel-filters

Conversation

@kralicky
Copy link
Copy Markdown
Collaborator

This adds a new channel filter extension type which can be used in a similar manner as generic proxy stream filters, but scoped to individual ssh channels instead of the entire connection. Channel filters implement a method onMessageForward which is called before a channel is about to forward a message to the peer. Channel filters are also able to query a channel's internal id, type, and stats, and are able to interrupt channels using the same preempt mechanism used for graceful shutdown.

@kralicky kralicky requested a review from kenjenkins April 21, 2026 23:58
@coveralls
Copy link
Copy Markdown

coveralls commented Apr 22, 2026

Coverage Report for CI Build 24791090420

Warning

No base build found for commit aa54b84 on kralicky/refactor-channel-open.
Coverage changes can't be calculated without a base build.
If a base build is processing, this comment will update automatically when it completes.

Coverage: 100.0%

Details

  • Patch coverage: 105 of 105 lines across 11 files are fully covered (100%).

Uncovered Changes

No uncovered changes found.

Coverage Regressions

Requires a base build to compare against. How to fix this →


Coverage Stats

Coverage Status
Relevant Lines: 7623
Covered Lines: 7623
Line Coverage: 100.0%
Coverage Strength: 20388.0 hits per line

💛 - Coveralls


ConnectionServiceOptions connection_service_options = 8;

repeated string enabled_channel_filters = 9;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the intended relationship between enabled_channel_filters here and the UpstreamTarget channel_filters below?

I'm not sure I understand why this field takes just the filter name while that one takes a full TypedExtensionConfig.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be fixed, I hadn't actually wired up the channel_filters configuration yet and realized I was missing some config setup code here. enabled_channel_filters controls which channel filter factory instances are created for new ssh connections. These can have their own typed config, which controls the factory itself. Then, the extension configs in channel_filters are checked against the list of enabled filters and validated, and when a channel is created a read filter or write filter is created from each configured factory. The channel filters themselves have a separate config type.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the naming is confusing me: if both of these end in channel_filters I would expect them to take the same kind of config.

Would it make sense to rename this one to channel_filter_factories? (or enabled_channel_filter_factories, if you want to keep the enabled bit)

Comment on lines +37 to +38
struct unused_in_this_test {};
ChannelFilterManager(unused_in_this_test) {}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is a special test-only constructor? Is there some way we could keep this out of the production code?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes this is for tests which cannot obtain a ServerFactoryContext. I don't think there is a way to #ifdef this out for tests only.

Comment on lines +14 to +15
virtual ChannelFilterPtr createReadFilter(ChannelFilterCallbacks& channel_callbacks) PURE;
virtual ChannelFilterPtr createWriteFilter(ChannelFilterCallbacks& channel_callbacks) PURE;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand how the distinction between "read filter" and "write filter" relates to the ChannelFilter type, as I see only the one onMessageForward() method there. Can you help me understand the intended design?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Read filters are passed downstream->upstream forwarded messages, and Write filters are passed upstream->downstream forwarded messages. I could rename these createDownstreamFilter and createUpstreamFilter but I don't know if that would be more or less confusing.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add some comments here to help explain the terminology?

I'm still not sure I understand:

  • Does this mean that each configured filter is effectively inserted twice, once on the downstream → upstream direction and once on the upstream → downstream direction?
  • Do we anticipate that individual filters would need to distinguish between messages forwarded in one direction vs. the other?
  • Do we anticipate wanting the ability to insert a filter only in one direction or the other?

@kralicky kralicky force-pushed the kralicky/channel-filters branch 4 times, most recently from 9c8be7c to 0000ff4 Compare April 22, 2026 21:57
@kralicky kralicky changed the base branch from kralicky/refactor-channel-open to main April 22, 2026 21:57
private:
Envoy::Server::Configuration::ServerFactoryContext* context_{};
std::unordered_map<std::string, ChannelFilterFactoryPtr> factories_;
std::unordered_map<std::string, ProtobufTypes::MessagePtr> filter_configs_;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you help me understand the lifecycle of ChannelFilterManager? The mutable state here makes me nervous.

It looks like there is one ChannelFilterManager per SshCodecFactory — does that mean the manager is shared across multiple ssh connections?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this file deletion intended?

@kralicky kralicky force-pushed the kralicky/channel-filters branch from 3570f81 to 4057d7f Compare April 28, 2026 18:35
@kralicky kralicky force-pushed the kralicky/channel-filters branch from 4057d7f to ebc948f Compare April 29, 2026 17:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants