-
Notifications
You must be signed in to change notification settings - Fork 794
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
Added vlan tag to the bridge cni plugin. #231
Added vlan tag to the bridge cni plugin. #231
Conversation
Neat. Linux bridges never cease to surprise me :-). Some minor requests:
And some larger questions:
|
d1d2fca
to
9ff5e57
Compare
Done
Done
I can't see a use-case like that, The tag will not work if the vlanFiltering is not configured.
I think we can always enable the vlanFiltering. untag traffic will work unrelated if the feature is enable or not. |
So, we talked about this at the CNI maintainers meeting, and this came up: If a container is started in a vlan, how does it get connectivity? Presumably there's no equivalent vlan-100 "uplink" interface on the "host" side of the bridge (i.e. "br0.100"). What are you envisioning? Do you have a separate step that creates the "br0.100" interface? Or do you expect non-default vlans to be private / isolated? It's generally expected, but by no means required, that a CNI plugin results in a container being "online." Of course, these are loose definitions, but they are helpful to guide decisions. Should this plugin also create the "br0.100" interface if configured with a vlan? |
@squeed forgive me, I don't know much about setting of VLAN directly on a bridge, but my understanding was this: If I connect two containers on the same host to bridge+vlan, they would be able to reach each other. If I create a bridges on two nodes and connect them via a trunk interface. Then containers connected to this bridge+vlan can reach each other node-to-node. Is that right or is more needed? |
If properly set, the bridge has one trunk uplink (e.g. eth0) and multiple ports, one per Pod. Traffic arriving to eth0 tagged with vlanX is repeated (under usual bridge rules) to all ports belonging to this vlan, but with the tag stripped. The reverse happen to egress traffic. So if I get what you're asking, the bridge port itself plays the role of br0.100 vlan device. They tag egress and strip ingress in the same way. (/me slightly rephrasing @phoracek) |
I don't know how it usually works on github, but @SchSeba maybe you can start you commit message by explaining what bridge vlan filtering is (include https://developers.redhat.com/blog/2017/09/14/vlan-filter-support-on-bridge/ ) and why it is useful here. |
db0fcec
to
f81be1f
Compare
The code to allow the vlan to be tagged on the bridge interface. there is not need to create a br0.100 interface. if n.Vlan != 0 {
err = netlink.BridgeVlanAdd(br, uint16(n.Vlan), false, true, true, false)
if err != nil {
return nil, nil, fmt.Errorf("failed to setup vlan tag on the bridge interface %q: %v", br.Name, err)
}
} |
@squeed there is any update on this PR? |
Then I still don't understand it. Are you manually trunking in another physical interface? If I want to send a packet from the host to a container on vlan 100, how do I do it? |
Hi @squeed Thanks for the comment. So if the want so send a packet you need to allow the vlan on the bridge interface and configure ip address in the same subnet on that interface. |
Maybe a little diagram would help explain what we'd like to achieve. The suggested change is aimed to allow multiple Pods, each one connected to a possibly-different vlan, share access to NIC that is connected to a trunk port of an external switch. If the node needs access to a vlan, it can connect to it just like any other namespace. @squeed am I addressing your question?
|
plugins/main/bridge/bridge.go
Outdated
if err != nil { | ||
return nil, nil, fmt.Errorf("failed to create bridge %q: %v", n.BrName, err) | ||
} | ||
|
||
if n.Vlan != 0 { | ||
err = netlink.BridgeVlanAdd(br, uint16(n.Vlan), false, true, true, false) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see this vlan filter entry being removed on DEL
. Are there any downsides to leaving it in place on the bridge even after all veths tagged with the vid have been removed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I don't remove it from the bridge I can't find any good reason to remove it just link we are not removing the bridge if there is no veths connected to it.
plugins/main/bridge/bridge_test.go
Outdated
@@ -171,6 +180,7 @@ var counter uint | |||
// arguments for a test case. | |||
func (tc testCase) createCmdArgs(targetNS ns.NetNS, dataDir string) *skel.CmdArgs { | |||
conf := tc.netConfJSON(dataDir) | |||
fmt.Println(conf) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
did you intend to leave this in the testCase
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope my bad sorry
f81be1f
to
a1438fc
Compare
Hi @squeed there is something that prevent this PR from be merged? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mostly /lgtm
Just a couple README nits.
plugins/main/bridge/README.md
Outdated
@@ -52,3 +52,8 @@ If the bridge is missing, the plugin will create one on first use and, if gatewa | |||
* `hairpinMode` (boolean, optional): set hairpin mode for interfaces on the bridge. Defaults to false. | |||
* `ipam` (dictionary, required): IPAM configuration to be used for this network. For L2-only network, create empty dictionary. | |||
* `promiscMode` (boolean, optional): set promiscuous mode on the bridge. Defaults to false. | |||
* `vlan` (int, optional): assign VLAN tag. Defaults to none. | |||
|
|||
*Note:* The VLAN parameter config the VLAN tag on the host end of the veth and also enable the vlan_filtering feature on the bridge interface. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"config" -> "configures"
"enable" -> "enables"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done Thanks!
plugins/main/bridge/README.md
Outdated
|
||
*Note:* The VLAN parameter config the VLAN tag on the host end of the veth and also enable the vlan_filtering feature on the bridge interface. | ||
|
||
*Note:* To configure up link for L2 network you need to allow the vlan on the up link interface by using the follow command ``` bridge vlan add vid VLAN_ID dev DEV``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"up link" -> "uplink"
"follow" -> "following"
And I assume DEV here is like eth0 or whatever the hosts physical NIC would usually be?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And I assume DEV here is like eth0 or whatever the hosts physical NIC would usually be?
Correct. A better text would be
To configure up link for L2 network you need to allow the vlan on the up link interface DEV
by using the follow command
or maybe use the blog example of bridge vlan add dev bond0 vid 2 master
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
This isn't quite clear enough to me... what would be required on the host side to send a packet to a container on a given VLAN? Would you need to create another veth and attach it to the bridge using the same VLAN ID as the container? |
you don't need to create any additional interface, the bridge interface will get the vlan ID. |
a1438fc
to
a9ab503
Compare
I tested this with two configurations, same bridge: {
"cniVersion": "0.3.1",
"name": "mybridge",
"type": "bridge",
"ipMasq": true,
"ipam": {
"type": "host-local",
"subnet": "10.42.0.0/24"
},
"isDefaultGateway": true,
"hairpinMode": true
} and {
"cniVersion": "0.3.1",
"name": "myvlanbridge",
"type": "bridge",
"ipMasq": true,
"ipam": {
"type": "host-local",
"subnet": "10.52.0.0/24"
},
"isDefaultGateway": true,
"hairpinMode": true,
"vlan": 99
} and got the following error: $ sudo CNI_PATH=./bin ../cni/bin/cnitool add myvlanbridge /var/run/netns/vlan100
failed to set bridge addr: "cni0" already has an IP address different from 10.52.0.1/24 |
Just to follow up on my previous comment: I would expect setting the If I understand your use-case correctly, you only really care about layer2 connectivity, so that's not an issue. However, I would really like the plugins to continue to meet user expectations, and it's not at all clear to me as an end-user why adding vlan tag would require me to drop layer3. So I'd like you to come up with a way for containers to have both a vlan tag and layer3 connectivity. If this means you have to create |
22df5b9
to
0502f71
Compare
Hi @SchSeba, |
Hi @squeed thanks for the comment just to be sure you want me to remove the cni0.99 interface from the result.interfaces list? |
@squeed ping? |
@SchSeba not quite; leave the cni0.99 interface in the Interfaces array. But when there is an L3 address for cni0 or cni0.99 we don't need to include that in the IPs array because the existing bridge plugin does not include the cni0 address there either. So I think what you have now is what Casey is asking for. |
Thanks for the comment @dcbw so I think this PR is ready to get merge :) |
@SchSeba Casey is on PTO today but will do a final check on Monday. |
Hi @rosenhouse maybe you can help me get this PR merge? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code looks OK; if Casey is ok with it I am too.
Code LGTM. Can you squash in to two commits (vendor and code), and I'll merge? |
19363f7
to
67c1036
Compare
67c1036
to
58a7125
Compare
Hi @squeed please take a look on my last commit I was requested to add some lines to the test to fix them after the rebase. |
Hi @squeed any update? |
@SchSeba Gotcha. looks good from my side. Squash this and I'll merge it :-) |
With the VLAN filter, the Linux bridge acts more like a real switch, Allow to tag and untag vlan id's on every interface connected to the bridge. This PR also creates a veth interface for the bridge vlan interface on L3 configuration. Related to https://developers.redhat.com/blog/2017/09/14/vlan-filter-support-on-bridge/ post. Note: This feature was introduced in Linux kernel 3.8 and was added to RHEL in version 7.0.
58a7125
to
b69a2dd
Compare
@squeed done and also the tests looks good :) |
vlanFiltering := false | ||
if n.Vlan != 0 { | ||
vlanFiltering = true | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what if vlan filtering is enabled in the begining (for those with Vlan IDs), and a new vlan, without vlan ID, is to be created. Wouldn't the new vlan disable vlan filtering?
I know this sounds like an obvious question, but... ...How does this work? I've tried creating a bridge interface but can't get pod-to-host networking working over VLANs. |
I believe you must first connect the host to a bridge port with the relevant Vlan ID enabled. You should be able to do so by running this CNI in the host networking namespace and set an IP address on the free veth. |
Ok - so my setup: Host:
Other hosts:
Via multus:
When I attach this to a POD (incidentally a KubeVirt instance), the address comes up and I see the device show up on a bridge vlan command on the physical host... But can't ping a 10.8.0.5 address which is on the same VLAN, on a physical host (not the host this Pod is running on). Yet... with the real bond0.101 device I can ping 10.8.0.5. What am I missing? I was hoping there would be some sort of example to make this work considering this merge request enables a VLAN tag on a bridge plugin but i'm just coming up agonisingly short. |
Kudos for using KubeVirt ;-) You're most welcome to share your use case on kubevirt-dev Can you ping between two pods on the same node over their If my guess is off, you'd need a bit of |
I'm betting this is where i'm falling down here. So there's more that needs to be done in order to make this work? Lol! So - dummies guide - If we just use the physical bond, bond0 (which carries all VLANS):
This creates a veth with VLAN 101, bond0 bridge carries 101... And br1 gets created that links to bond0 if it's created. Is that correct? |
Can someone provide an example of how is this suppose to work? We can use docker ipvlan and get vlan tagged traffic. When using this plugin we can't ping/reach anything using vlans. |
Allow the user to assign VLAN tag.
Updated netlink library to introduce the VlanFiltering variable into the bridge struct