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

[libnetwork] Default Profile for a new IPPool generates ipset with no members. Ingress packet to a workload always matches no profile and gets dropped by iptables. #190

Open
Syraxius opened this issue Jan 3, 2019 · 3 comments

Comments

@Syraxius
Copy link

Syraxius commented Jan 3, 2019

Expected Behavior

The default profile generated should allow all egress traffic, and allow ingress traffic from the same network as specified in the documentation page here.

Current Behavior

All egress traffic are permitted, but no ingress traffic is permitted other than from the node itself to its own workload. This is caused by an empty ipset which is supposed to match the IPPool's subnet.

In summary:

  • Working: Workload to external
  • Working: Workload to node
  • Not Working: Workload to workload (dropped at node iptables)
  • Not Working: External to workload (dropped at node iptables)

Possible Solution

The issue I was having was fixed when changing the Profile from:

source:
      selector: has(calico-pool-0)

To:

source: {}

(The name of my IPPool resource and Profile are both calico-pool-0)

Of course, the above will now allow everything which is not in the spirit of the default profile.

I will find time soon to determine from code the actual reason why has(calico-pool-0) causes an empty ipset.

Steps to Reproduce (for bugs)

  1. Create a new IPPool with this configuration:
apiVersion: projectcalico.org/v3
kind: IPPool
metadata:
  name: calico-pool-0
spec:
  cidr: 192.168.101.0/24
  blockSize: 26
  ipipMode: CrossSubnet
  natOutgoing: true
  disabled: false
  1. Add a new network in Docker:
docker network create --driver calico --ipam-driver calico-ipam --subnet=192.168.101.0/24 calico-pool-1
  1. Create two workloads on different hosts:
# Host 1
docker run --net=calico-pool-0 --name w1 -dit busybox sh
# Host 2
docker run --net=calico-pool-0 --name w2 -dit busybox sh
  1. Try to ping w2 from w1. Doesn't work. Details are as follows...

Here is the tcpdump (from tcpdump -enni any icmp):

15:13:05.704290  In 08:00:27:cb:0e:5c ethertype IPv4 (0x0800), length 100: 192.168.101.1 > 192.168.101.193: ICMP echo request, id 3072, seq 12, length 64
15:13:06.704784  In 08:00:27:cb:0e:5c ethertype IPv4 (0x0800), length 100: 192.168.101.1 > 192.168.101.193: ICMP echo request, id 3072, seq 13, length 64
15:13:07.705399  In 08:00:27:cb:0e:5c ethertype IPv4 (0x0800), length 100: 192.168.101.1 > 192.168.101.193: ICMP echo request, id 3072, seq 14, length 64
15:13:08.705967  In 08:00:27:cb:0e:5c ethertype IPv4 (0x0800), length 100: 192.168.101.1 > 192.168.101.193: ICMP echo request, id 3072, seq 15, length 64
15:13:09.706307  In 08:00:27:cb:0e:5c ethertype IPv4 (0x0800), length 100: 192.168.101.1 > 192.168.101.193: ICMP echo request, id 3072, seq 16, length 64
15:13:10.706950  In 08:00:27:cb:0e:5c ethertype IPv4 (0x0800), length 100: 192.168.101.1 > 192.168.101.193: ICMP echo request, id 3072, seq 17, length 64

It seems it's getting dropped by iptables because it's not getting marked in cali-pro-calico-pool-0 chain:

Chain cali-pro-calico-pool-0 (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 MARK       all  --  any    any     anywhere             anywhere             /* cali:faAFuoL5iNMQqlTy */ MARK or 0x10000
    0     0 RETURN     all  --  any    any     anywhere             anywhere             /* cali:mwhwnGS9ylSlHDLE */ mark match 0x10000/0x10000

Chain cali-tw-calif42bbb120f0 (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 ACCEPT     all  --  any    any     anywhere             anywhere             /* cali:2e1wtQwhc6xY4lxs */ ctstate RELATED,ESTABLISHED
    0     0 DROP       all  --  any    any     anywhere             anywhere             /* cali:-TWo_rIkIp3cS0fT */ ctstate INVALID
   76  6384 MARK       all  --  any    any     anywhere             anywhere             /* cali:yJvGboVd7BQ96sDz */ MARK and 0xfffeffff
   76  6384 cali-pri-calico-pool-0  all  --  any    any     anywhere             anywhere             /* cali:hLdAvuX7r-VmswBt */
    0     0 RETURN     all  --  any    any     anywhere             anywhere             /* cali:E4J1GHCRA1rLqJte */ /* Return if profile accepted */ mark match 0x10000/0x10000
   76  6384 DROP       all  --  any    any     anywhere             anywhere             /* cali:Xl8oR2dSw6Awy0oF */ /* Drop if no profiles matched */

From iptables-save -c we can see that the ipset (cali40s:Gcr-rptUOZhd-mtexAmjwZt) is used to match the packets to be marked:

[0:0] -A cali-pri-calico-pool-0 -m comment --comment "cali:asFUIp0qsmlr9w1E" -m set --match-set cali40s:Gcr-rptUOZhd-mtexAmjwZt src -j MARK --set-xmark 0x10000/0x10000
[0:0] -A cali-pri-calico-pool-0 -m comment --comment "cali:8gezXKKJqj4pVICf" -m mark --mark 0x10000/0x10000 -j RETURN

And it seems like the ipset cali40s:Gcr-rptUOZhd-mtexAmjwZt is empty:

Name: cali40s:Gcr-rptUOZhd-mtexAmjwZt
Type: hash:net
Revision: 6
Header: family inet hashsize 1024 maxelem 1048576
Size in memory: 384
References: 1
Members:

I've tried enabling --use-docker-networking-container-labels but it still does not work.

Context

Trying to run Calico 3.4 with plain Docker. I've compiled libnetwork-plugin and added it to the calico/node image.

Your Environment

  • Felix version (if using Felix binary directly calico-felix --version):flag: v3.4.0 (from calico-node -v)
  • And/Or, calico/node container version (if running Felix in a container): release-v3.4
  • Which orchestrator are you using (e.g. Kubernetes, OpenStack, Docker, Mesos): Docker
  • Orchestrator version (if used): N/A
  • Etcd version (if using etcd datastore driver): 3.3.8
  • Operating System and version: Ubuntu 16.04 amd64
  • Link to your project (optional): N/A
@Syraxius Syraxius changed the title Default Profile for a new IPPool has no members. Ingress packet to a workload always matches no profile and gets dropped by iptables. Default Profile for a new IPPool generates ipset with no members. Ingress packet to a workload always matches no profile and gets dropped by iptables. Jan 3, 2019
@caseydavenport
Copy link
Member

source:
      selector: has(calico-pool-0)

I don't think this sort of thing works out of the box - rule selectors match workload endpoints, not IP pools. So, unless your workload endpoints or NetworkSets are labeled with that particular label then that rule won't select anything.

You can check what labels are applied to your workload endpoints with calicoctl get workloadendpoints -o wide --all-namespaces

@Syraxius
Copy link
Author

Syraxius commented Jan 14, 2019

Thanks for your prompt reply @caseydavenport !

Actually what I meant was... The selector configuration was automatically generated (I didn't create it) when the docker network and test containers were created, and it seems to lead to iptables rules / ipsets which drop all traffic (iptables uses an ipset which is empty).

When I run the calicoctl get workloadendpoints -o yml --all-namespaces command, the calico-pool-0 label is not applied to the workload. My workloads only have the following labels:

projectcalico.org/namespace: libnetwork
projectcalico.org/orchestrator: libnetwork

It seems the default selector expects the name of the network (calico-pool-0) to be attached as a label to containers created in that network. However, the label is missing which leads to all traffic being dropped.

Thanks again!

@caseydavenport
Copy link
Member

@Syraxius Ah, right I see what you mean.

docker network create --driver calico --ipam-driver calico-ipam --subnet=192.168.101.0/24 calico-pool-1

I noticed in your example command uses calico-pool-1 - I suspect this isn't relevant, but thought I'd call it out anyway in case it was more than just a typo.

This seems to be the only code which is setting labels currently: https://github.com/projectcalico/libnetwork-plugin/blob/master/driver/network_driver.go#L648-L667

From a quick read, I don't see it setting the network name as a label, which I would assume is the root cause here.

As you pointed out, the profile expects a networkName label, and that aligns with the code here: https://github.com/projectcalico/libnetwork-plugin/blob/master/driver/network_driver.go#L361

A simple fix, I think, would be to add the label at this point: https://github.com/projectcalico/libnetwork-plugin/blob/master/driver/network_driver.go#L300

@caseydavenport caseydavenport changed the title Default Profile for a new IPPool generates ipset with no members. Ingress packet to a workload always matches no profile and gets dropped by iptables. [libnetwork] Default Profile for a new IPPool generates ipset with no members. Ingress packet to a workload always matches no profile and gets dropped by iptables. Apr 5, 2019
@rafaelvanoni rafaelvanoni self-assigned this Sep 23, 2019
@caseydavenport caseydavenport transferred this issue from projectcalico/felix Nov 8, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants