diff --git a/Documentation/README.md b/Documentation/README.md index 6a285f32e..7dc9c2954 100644 --- a/Documentation/README.md +++ b/Documentation/README.md @@ -16,6 +16,12 @@ cd Documentation pip install -r requirements.txt ``` +### Edit it + +Documentation is created in the ReSTructured text format. +A nice document listing important commands is the [Restructured Text (reST) and Sphinx CheatSheet](https://thomas-cokelaer.info/tutorials/sphinx/rest_syntax.html). + + ### Build it ``` diff --git a/Documentation/components/index.rst b/Documentation/components/index.rst deleted file mode 100644 index c09fa7fd4..000000000 --- a/Documentation/components/index.rst +++ /dev/null @@ -1,9 +0,0 @@ -Standalone applications based on polycube -========================================= - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - - iptables/pcn-iptables - k8s/pcn-kubernetes diff --git a/Documentation/components/iptables/architecture.rst b/Documentation/components/iptables/architecture.rst deleted file mode 100644 index 465dc03a8..000000000 --- a/Documentation/components/iptables/architecture.rst +++ /dev/null @@ -1,10 +0,0 @@ -pcn-iptables components ------------------------ - -``pcn-iptables`` is composed by three main components: - -1. ``pcn-iptables`` service (``src/services/pcn-iptables``): a Polycube service, a special one since performs some extra work, but basically expose its API and CLI, according to Polycube standard. - -2. ``iptables*`` (``src/components/iptables/iptables``): a modified version of iptables, in charge of validate commands, translate them from iptables to polycube syntax, then forward them to pcn-iptables service instead of push them into the kernel via netfilter. - -3. ``scripts`` (``src/components/iptables/scripts``): this is a folder containing some glue logic and scripts to initialize, cleanup and use ``pcn-iptables``. ``pcn-iptables`` itself is a script that forwards commands to ``iptables*`` (2), then forwards the translated command to ``pcn-iptables`` (1). Scripts are installed under ``/usr/local/bin``. \ No newline at end of file diff --git a/Documentation/components/iptables/pcn-iptables.rst b/Documentation/components/iptables/pcn-iptables.rst index 905a7b5e1..78a623d5e 100644 --- a/Documentation/components/iptables/pcn-iptables.rst +++ b/Documentation/components/iptables/pcn-iptables.rst @@ -61,8 +61,8 @@ Prerequisites pcn-iptables comes as a component of polycube framework. Refer to :doc:`polycube install guide<../../../installation>` for dependencies, kernel requirements and basic checkout and install guide. -Install Steps -^^^^^^^^^^^^^ +Install +^^^^^^^ To compile and install ``pcn-iptables``, you should enable the ``ENABLE_PCN_IPTABLES`` flag in the polycube CMakeFile, which is set to ``OFF`` by default; this allows to compile the customized version of ``iptables`` used to translate commands, and install in the system pcn-iptables-init pcn-iptables and pcn-iptables-clean utils. @@ -160,14 +160,29 @@ Limitations pcn-iptables components ----------------------- +``pcn-iptables`` is composed by three main components: + + 1. ``pcn-iptables`` service (``src/services/pcn-iptables``): a Polycube service, a special one since performs some extra work, but basically expose its API and CLI, according to Polycube standard. + iptables submodule ^^^^^^^^^^^^^^^^^^ A customized fork of iptables is included as submodule under :scm_web:`src/components/iptables/iptables `. -We customized this version of iptables in order not to inject iptables command into netfilter, but convert them, after a validation step, into polycube syntax. +This modified version of iptables is in charge of validate commands, translate them from iptables to polycube syntax, then forward them to pcn-iptables service instead of pushing them into the kernel via netfilter. scripts folder ^^^^^^^^^^^^^^ Scripts are used as a glue logic to make pcn-iptables run. Main purpose is initialize, cleanup and run pcn-iptables, pass pcn-iptables parameters through iptables (in charge of converting them), then pass converted commands to pcn-iptables service. -Scripts are installed under ``/usr/local/bin``. \ No newline at end of file +Scripts are installed under ``/usr/local/bin``. + +pcn-iptables components +----------------------- + +``pcn-iptables`` is composed by three main components: + +1. ``pcn-iptables`` service (``src/services/pcn-iptables``): a Polycube service that is especially tailored to work with the ``pcn-iptables`` executable; as usual, it exposes its API and CLI according to Polycube standard. + +2. ``iptables*`` (``src/components/iptables/iptables``): a modified version of iptables, in charge of validate commands, translate them from iptables to polycube syntax, then forward them to pcn-iptables service instead of push them into the kernel via netfilter. + +3. ``scripts`` (``src/components/iptables/scripts``): this is a folder containing some glue logic and scripts to initialize, cleanup and use ``pcn-iptables``. ``pcn-iptables`` itself is a script that forwards commands to ``iptables*`` (2), then forwards the translated command to ``pcn-iptables`` (1). Scripts are installed under ``/usr/local/bin``. diff --git a/Documentation/components/k8s/developers.rst b/Documentation/components/k8s/developers.rst index 062971554..bec695b6f 100644 --- a/Documentation/components/k8s/developers.rst +++ b/Documentation/components/k8s/developers.rst @@ -1,5 +1,177 @@ -pcn-k8s Developers -================== +Information for developers +========================== + +Controllers +----------- + +Controllers are entities that are in charge of providing you with the resource that you need, as well as watch for events and notify when one has occurred. +In Polycube, five controllers are implemented: + +- ``Kubernetes Network Policies`` +- ``Polycube Network Policies`` +- ``Services`` +- ``Namespaces`` +- ``Pods`` + +Not all of them provide the same functionalities and filtering criteria, but all work based on the same principle. + + +Usage +^^^^^ + +The usage is inspired by Kubernetes' API style. +To use the controllers, you simply need to import the ``pcn_controllers`` package and call the controller you'd like to use. +Take a look at the following examples. + +.. code-block:: go + + package main + import ( + // importing controllers + pcn_controllers "github.com/polycube-network/polycube/src/components/k8s/pcn_k8s/controllers" + ) + + func main() { + // Namespaces + namespaces, err := pcn_controllers.Namespaces().List(...) + + // Pods + unsubscriptor, err := pcn_controllers.Namespaces().Subscribe(...) + + // etc... + } + + +Queries +^^^^^^^ + +All controllers can retrieve resources from the Kubernetes cache, based on some criteria. +To define criteria, you must define the query: the definition is in package ``pcn_types``: + +.. code-block:: go + + // ObjectQuery is a struct that specifies how the object should be found + type ObjectQuery struct { + By string + Name string + Labels map[string]string + } + +Take a look at the following examples: + +.. code-block:: go + + // I want resources that are named "my-service" + serviceQuery := pcn_types.ObjectQuery { + By: "name", + Name: "my-service", + } + + // I want all pods that have labels "app: my-app", and "role: database" + podQuery := pcn_types.ObjectQuery { + By: "labels", + Labels: map[string]string { + "app": "my-app", + "role": "database", + } + +Although you can create these by hand, a convenient function exists to do this and it is specifically made for use with the controllers: + +.. code-block:: go + + import ( + "github.com/polycube-network/polycube/src/components/k8s/utils" + ) + + // ... + + // Build a "by: name" query + serviceQuery := utils.BuildQuery("my-service", nil) + + // Build a "by: labels" query + podQuery := utils.BuildQuery("my-service", map[string]string { + "app": "my-app", + "role": "database", + }) + + // Build a query to get all resources, regardless of name and labels + allResources := utils.BuildQuery("", nil) + +This function returns a **pointer** to the actual query structure because that's what controllers need. When wanting to get all resources, the function returns nil, so you may even just use a nil value without calling the BuildQuery function. + + +List resources +^^^^^^^^^^^^^^ + +To list resources, you need to first create the queries, and then call the **List** function of the controller. +Not all controllers support both name and label criteria: i.e. the Pod Controller only supports labels. + +.. code-block:: go + + // I want all services that apply to pods with labels "app: my-app" and "role: db" + // and are on a namespace called "production" + // So, first create the queries for both the service and namespace. + serviceQuery := utils.BuildQuery(nil, map[string]string { + "app": "my-app", + "role": "db", + }) + + nsQuery := utils.BuildQuery("production", nil) + // Then, get them. Note: there might be more than one service which applies to those pods. + servicesList, err := pcn_controllers.Services().List(serviceQuery, nsQuery) + if err != nil { + return + } + for _, service := range servicesList { + // Do something with this service... + } + +So, usually, the first argument is criteria about the resource, while the second is reserved for criteria about the namespace where you want to find such resources. + +To give additional information: + +- The ``Kubernetes Network Policies`` and ``Polycube Network Policies`` controllers only support querying the policy by name +- The ``Pod`` controller only supports querying by labels +- The ``Pod`` controller also supports a third argument for the node where you want this pod to be located. +- The ``Services`` controller supports both name and labels, but when using labels it searches for them in the **spec.selector** field, not those under its metadata. +- The ``Namespaces`` controller work with namespaces, which cannot belong to other resources and only want one argument. + +Note that, according to the criteria, it may take you a long time to get the results. Whenever possible, or when you expect a query to return lots of resources, adopt an async pattern or use multiple goroutines. + + +Watch for events +^^^^^^^^^^^^^^^^ + +To watch for events, you need to use a controller's ``Subscribe`` function by passing to it the event type you want to monitor, the resource criteria, and the function to be executed when that event is detected. + +.. code-block:: go + + func firstfunc() { + // I want to "myfunc" to be notified whenever a new pod is born. + // Pod controller has the most complex subscribe function, as it also asks you for the phase of the pod. + unsub, err := pcn_controllers.Pods().Subscribe(pcn_types.New, nil, nil, &pcn_types.ObjectQuery{Name: "node-name"}, pcn_types.PodRunning, myfunc) + + // ... + + // I am not interested in that event anymore + unsub() + } + + func myfunc(currentState, previousState *core_v1.Pod) { + // Do something with it... + } + +As the above example shows, the ``Subscribe`` function returns a pointer to a function that you need to call when you're not interested in that event anymore. + +The function to execute must always have two arguments: the current state of the object and its previous state. There are three event types: ``New``, ``Update``, ``Delete``. + +Just some heads up: + +- When monitoring ``New`` events, only the current state of the object is present, the previous is obviously always ``nil``. +- When monitoring ``Delete`` events, the object does not exist anymore, so the current state is always ``nil``. + +All the ``Subscribe`` functions share a similar structure to the ``List`` function in the same controller, to make sure about their usage, check their definitions in the ``pcn_controllers`` package + Creating the Docker Images -------------------------- @@ -12,8 +184,3 @@ Docker 18.06 is needed to build the images, and the daemon has to be started wit export DOCKER_BUILDKIT=1 # flag needed to enable the --mount option docker build --build-arg DEFAULT_MODE=pcn-k8s -t name:tag . docker push name:tag - - -Networking policy controller ----------------------------- -Refer to :doc:`Controller development `. diff --git a/Documentation/components/k8s/index.rst b/Documentation/components/k8s/index.rst new file mode 100644 index 000000000..bd31030f7 --- /dev/null +++ b/Documentation/components/k8s/index.rst @@ -0,0 +1,11 @@ +pcn-k8s: a network provider for kubernetes +========================================== + +.. toctree:: + :maxdepth: 3 + :caption: Contents: + + pcn-kubernetes + kubernetes-network-policies + polycube-network-policies + developers diff --git a/Documentation/components/k8s/pcn-kubernetes.rst b/Documentation/components/k8s/pcn-kubernetes.rst index c675d6c2c..b4247bdbb 100644 --- a/Documentation/components/k8s/pcn-kubernetes.rst +++ b/Documentation/components/k8s/pcn-kubernetes.rst @@ -1,5 +1,6 @@ -pcn-k8s: A pod network provider for kubernetes -============================================== +Introduction +============ + ``pcn-k8s`` leverages some polycube services to provide network support for pods running in Kubernetes. It supports the `cluster Kubernetes networking model `_, ``ClusterIP`` and ``NodePort`` services. @@ -13,10 +14,11 @@ Security policies and ``LoadBalancing`` service mode are not yet supported. .. image:: pcn_k8s_architecture.png + Networking Mode --------------- -The ``pcn-k8s`` solution supports different methods to communicate pods running in different hosts +``pcn-k8s`` supports different methods to communicate pods running in different hosts - **overlay networking**: when nodes are on different subnets and the user does not have direct control over the physical network an overlay networking is used. The default (and only supported yet) technology is ``VxLAN`` - **direct routing**: when nodes are on the same subnet packets can be exchanged between nodes without encapsulating them @@ -24,18 +26,26 @@ The ``pcn-k8s`` solution supports different methods to communicate pods running See `Configuring pcn-k8s`_ to get more info about how to configure the different modes. -Installation: + +Compatibility ------------- + +`pcn-k8s`` is compatible with all versions of Kubernetes equal or greater than 1.9, although we recommend the latest version. + + +Installation +============ You may choose either of the below options. 1. Quick setup with ``vagrant`` (development environment) 2. Using ``kubeadm`` on Bare-Metal or VMs (Single or HA cluster) -1. Quick Setup with ``vagrant`` -------------------------------- + +1. Quick Setup with vagrant +--------------------------- - The fastest mode to test ``pcn-k8s`` including setup. -**Pre-requisite:** +**Prerequisites** Download and set up the following packages. @@ -51,8 +61,8 @@ Download and set up the following packages. Note: This vagrant setup takes care of setting up the kubeadm and joining the nodes along with the ``pcn-k8s`` CNI. -2. Using ``kubeadm`` on Bare-Metal or VMs (Single or HA cluster) ----------------------------------------------------------------- +2. Using kubeadm on Bare-Metal or VMs (Single or HA cluster) +------------------------------------------------------------ The easiest way to get started with ``pcn-k8s`` using ``kubeadm``. @@ -144,8 +154,8 @@ You can see all the nodes in the cluster using the following command: After that, the cluster will be ready to accept requests and deploy pods. -Removing ``pcn-k8s`` -^^^^^^^^^^^^^^^^^^^^ +Removing pcn-k8s +^^^^^^^^^^^^^^^^ In order to remove ``pcn-k8s`` execute on the master node: @@ -154,20 +164,15 @@ In order to remove ``pcn-k8s`` execute on the master node: kubectl delete -f |SCM_RAW_WEB|/src/components/k8s/pcn-k8s.yaml -Testing pcn-k8s ---------------- - -Please refer to :doc:`testing ` to learn how to deploy and test some basic services. - Configuring pcn-k8s -------------------- +=================== ``pcn-k8s`` uses ``etcd`` to save the different configuration parameters. It is exposed at port `30901` of the master node if you used the `standalone_etcd.yaml` template to deploy it. Installing etcdctl -^^^^^^^^^^^^^^^^^^ +------------------ The easiest way to get ``etcdctl`` is to download a `etcd release `_ and take the binary from there. @@ -202,7 +207,7 @@ Note that in order to use that feature `directRouting` must be enabled in both n Running in `aws` -^^^^^^^^^^^^^^^^ +---------------- In order to let ``pcn-k8s`` interact with `aws` an `Identity and Access Management (IAM)` role is needed. @@ -238,11 +243,137 @@ Assign the IAM role (that you've created in above step) to the EC2 instances whi Note: VxLAN exchanges traffic on port `4789/UDP`, be sure that you have configured security rules to allow it. + +Testing your pcn-k8s installation +================================= + +We present here some commands to test that your ``pcn-k8s`` deployment works as expected. + +In order to run these tests, a cluster having at least two schedulable nodes (not tainted) is needed. + +Deploy services and pods to test +-------------------------------- + +.. parsed-literal:: + + kubectl create -f |SCM_RAW_WEB|/src/components/k8s/examples/echoserver_nodeport.yaml + kubectl run curl1 --image=tutum/curl --replicas=5 --command -- sleep 600000 + + +After a short period of time, all pods should be in the `Running` state + +:: + + k8s@k8s-master:~$ kubectl get pods -o wide + NAME READY STATUS RESTARTS AGE IP NODE + curl1-5df485555f-2dpwx 1/1 Running 0 1m 192.168.1.3 k8s-worker2 + curl1-5df485555f-l7ql4 1/1 Running 0 1m 192.168.0.246 k8s-master + curl1-5df485555f-s9wsv 1/1 Running 0 1m 192.168.1.5 k8s-worker2 + curl1-5df485555f-xh4wv 1/1 Running 0 1m 192.168.1.4 k8s-worker2 + curl1-5df485555f-xqmxn 1/1 Running 0 1m 192.168.0.245 k8s-master + myechoserver-86856fd86f-fkzg6 1/1 Running 0 32s 192.168.1.6 k8s-worker2 + + +Tests +----- + +The following section present some test cases to check everything is working as expected. + +Test Node to Pod connectivity +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +:: + + # ping pod in master node + k8s@k8s-master:~$ ping 192.168.0.245 + + k8s@k8s-master:~$ ping 192.168.1.3 + + +Test Pod to Pod connectivity +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +:: + + # select one pod running on master, in this case (192.168.0.245) + k8s@k8s-master:~$ ID=curl1-5df485555f-xqmxn + + # ping pod in master + k8s@k8s-master:~$ kubectl exec $ID ping 192.168.0.246 + + # ping pod in worker + k8s@k8s-master:~$ kubectl exec $ID ping 192.168.1.5 + + +Test Pod to Internet connectivity +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +:: + + # ping to internet + k8s@k8s-master:~$ kubectl exec $ID ping 8.8.8.8 + + +Test ClusterIP service +^^^^^^^^^^^^^^^^^^^^^^ + +The following command will give us the details about the service we created: + +:: + + k8s@k8s-master:~$ kubectl describe service myechoserver + Name: myechoserver + Namespace: default + Labels: app=myechoserver + Annotations: + Selector: app=myechoserver + Type: NodePort + IP: 10.96.23.23 + Port: 8080/TCP + TargetPort: 8080/TCP + NodePort: 31333/TCP + Endpoints: 192.168.1.6:8080 + Session Affinity: None + External Traffic Policy: Cluster + Events: + +:: + + # direct access to the backend + k8s@k8s-master:~$ curl 192.168.1.6:8080 + + # access from node to ClusterIP + curl 10.96.23.23:8080 + + # access from a pod (change ID to both, a pod in the local node and also a pod in a remote node) + kubectl exec $ID curl 10.96.23.23:8080 + + +Test NodePort service +^^^^^^^^^^^^^^^^^^^^^ + +The service is exposed in port `31333`, perform a request to the public IP of the master and the node from a remote host. + +:: + + # request to master + curl 130.192.225.143:31333 + + # request to worker + curl 130.192.225.144:31333 + + +TODO: +- test dns service +- test scale-up scale down + + + + Troubleshooting ---------------- +=============== Recovering from a pcn-k8s failure -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +--------------------------------- ``pcn-k8s`` expects a clean environment to start with and it is likely to fail if this is not verified. In case you hit any problems, please follow the next steps to recover from a failure: @@ -269,10 +400,9 @@ In case you hit any problems, please follow the next steps to recover from a fai kubectl -n kube-system scale --replicas=1 deployment/kube-dns Inspect cube status inside pcn-k8s -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +---------------------------------- ``pcn-k8s`` is deployed as container in each node, sometimes it is helpful to inspect the cube(s) status -within the container for debugging or other purposes. You can login into each node where the pcn-k8s container -is running and get the information via :doc:`polycubectl<../../quickstart#docker>` command locally. +within the container for debugging or other purposes. You can login into each node where the pcn-k8s container is running and get the information via :doc:`polycubectl <../../../polycubectl/polycubectl>` command locally. A more convenient way to do that is using kubectl in k8s master node, first identify the name of pcn-k8s pod running in a particular node you are intereted by executing the following command: @@ -314,16 +444,3 @@ Here is the output for example, k8switch0 c058b8fb-0e57-4ff6-be4d-5f3e99e71690 k8switch TC TRACE false false [7 items] -pcn-k8s networking policy -------------------------- -pcn-k8s CNI implemented both :doc:`standard kubernetes networking policy ` and :doc:`advanced polycube networking policy `. - -Developing ----------- - -Refer to :doc:`Developers ` - -Compatibility -------------- - -Pcn-k8s is compatible with all versions equal or greater than 1.9, although we recommend the latest version of Kubernetes. diff --git a/Documentation/components/k8s/polycube-network-policies.rst b/Documentation/components/k8s/polycube-network-policies.rst index fabb1dc3c..d96f2dea7 100644 --- a/Documentation/components/k8s/polycube-network-policies.rst +++ b/Documentation/components/k8s/polycube-network-policies.rst @@ -1,7 +1,8 @@ Polycube Policies ============================================== -Polycube Policies provide a more flexible, simpler and more advanced approach to filter the traffic that a pod should allow or block. +pcn-k8s CNI implementes both :doc:`standard kubernetes networking policy ` and advanced Polycube networking policies. +The latter provide a more flexible, simpler and more advanced approach to filter the traffic that a pod should allow or block. They include all the features from Kubernetes Network Policies and present some additional features, which are going to be described here. The isolation mode, a core concept in Kubernetes Network Policies, is followed by Polycube Network Policies, as well: pods allow all communication until a policy - either one - is applied to them, and at that moment they will start to allow only what's explicitly specified in the policy. diff --git a/Documentation/components/k8s/polycube_controllers.rst b/Documentation/components/k8s/polycube_controllers.rst deleted file mode 100644 index f24dd594f..000000000 --- a/Documentation/components/k8s/polycube_controllers.rst +++ /dev/null @@ -1,166 +0,0 @@ -Controllers -============================================== - -Controllers are entities that are in charge of providing you with the resource that you need, as well as watch for events and notify when one has occurred. -In Polycube, five controllers are implemented: - -- ``Kubernetes Network Policies`` -- ``Polycube Network Policies`` -- ``Services`` -- ``Namespaces`` -- ``Pods`` - -Not all of them provide the same functionalities and filtering criteria, but all work based on the same principle. - -Usage ------------------- - -The usage is inspired by Kubernetes' API style. -To use the controllers, you simply need to import the ``pcn_controllers`` package and call the controller you'd like to use. -Take a look at the following examples. - -.. code-block:: go - - package main - import ( - // importing controllers - pcn_controllers "github.com/polycube-network/polycube/src/components/k8s/pcn_k8s/controllers" - ) - - func main() { - // Namespaces - namespaces, err := pcn_controllers.Namespaces().List(...) - - // Pods - unsubscriptor, err := pcn_controllers.Namespaces().Subscribe(...) - - // etc... - } - -Queries ------------------- - -All controllers can retrieve resources from the Kubernetes cache, based on some criteria. -To define criteria, you must define the query: the definition is in package ``pcn_types``: - -.. code-block:: go - - // ObjectQuery is a struct that specifies how the object should be found - type ObjectQuery struct { - By string - Name string - Labels map[string]string - } - -Take a look at the following examples: - -.. code-block:: go - - // I want resources that are named "my-service" - serviceQuery := pcn_types.ObjectQuery { - By: "name", - Name: "my-service", - } - - // I want all pods that have labels "app: my-app", and "role: database" - podQuery := pcn_types.ObjectQuery { - By: "labels", - Labels: map[string]string { - "app": "my-app", - "role": "database", - } - -Although you can create these by hand, a convenient function exists to do this and it is specifically made for use with the controllers: - -.. code-block:: go - - import ( - "github.com/polycube-network/polycube/src/components/k8s/utils" - ) - - // ... - - // Build a "by: name" query - serviceQuery := utils.BuildQuery("my-service", nil) - - // Build a "by: labels" query - podQuery := utils.BuildQuery("my-service", map[string]string { - "app": "my-app", - "role": "database", - }) - - // Build a query to get all resources, regardless of name and labels - allResources := utils.BuildQuery("", nil) - -This function returns a **pointer** to the actual query structure because that's what controllers need. When wanting to get all resources, the function returns nil, so you may even just use a nil value without calling the BuildQuery function. - -List resources ------------------- - -To list resources, you need to first create the queries, and then call the **List** function of the controller. -Not all controllers support both name and label criteria: i.e. the Pod Controller only supports labels. - -.. code-block:: go - - // I want all services that apply to pods with labels "app: my-app" and "role: db" - // and are on a namespace called "production" - // So, first create the queries for both the service and namespace. - serviceQuery := utils.BuildQuery(nil, map[string]string { - "app": "my-app", - "role": "db", - }) - - nsQuery := utils.BuildQuery("production", nil) - // Then, get them. Note: there might be more than one service which applies to those pods. - servicesList, err := pcn_controllers.Services().List(serviceQuery, nsQuery) - if err != nil { - return - } - for _, service := range servicesList { - // Do something with this service... - } - -So, usually, the first argument is criteria about the resource, while the second is reserved for criteria about the namespace where you want to find such resources. - -To give additional information: - -- The ``Kubernetes Network Policies`` and ``Polycube Network Policies`` controllers only support querying the policy by name -- The ``Pod`` controller only supports querying by labels -- The ``Pod`` controller also supports a third argument for the node where you want this pod to be located. -- The ``Services`` controller supports both name and labels, but when using labels it searches for them in the **spec.selector** field, not those under its metadata. -- The ``Namespaces`` controller work with namespaces, which cannot belong to other resources and only want one argument. - -Note that, according to the criteria, it may take you a long time to get the results. Whenever possible, or when you expect a query to return lots of resources, adopt an async pattern or use multiple goroutines. - -Watch for events ------------------- - -To watch for events, you need to use a controller's ``Subscribe`` function by passing to it the event type you want to monitor, the resource criteria, and the function to be executed when that event is detected. - -.. code-block:: go - - func firstfunc() { - // I want to "myfunc" to be notified whenever a new pod is born. - // Pod controller has the most complex subscribe function, as it also asks you for the phase of the pod. - unsub, err := pcn_controllers.Pods().Subscribe(pcn_types.New, nil, nil, &pcn_types.ObjectQuery{Name: "node-name"}, pcn_types.PodRunning, myfunc) - - // ... - - // I am not interested in that event anymore - unsub() - } - - func myfunc(currentState, previousState *core_v1.Pod) { - // Do something with it... - } - -As the above example shows, the ``Subscribe`` function returns a pointer to a function that you need to call when you're not interested in that event anymore. - -The function to execute must always have two arguments: the current state of the object and its previous state. There are three event types: ``New``, ``Update``, ``Delete``. - -Just some heads up: - -- When monitoring ``New`` events, only the current state of the object is present, the previous is obviously always ``nil``. -- When monitoring ``Delete`` events, the object does not exist anymore, so the current state is always ``nil``. - -All the ``Subscribe`` functions share a similar structure to the ``List`` function in the same controller, to make sure about their usage, check their definitions in the ``pcn_controllers`` package \ No newline at end of file diff --git a/Documentation/components/k8s/testing.rst b/Documentation/components/k8s/testing.rst deleted file mode 100644 index 5b5a797b6..000000000 --- a/Documentation/components/k8s/testing.rst +++ /dev/null @@ -1,121 +0,0 @@ -Testing pcn-k8s -=============== - -This document contains some commands to test that the deploying is working as expected. - -In order to run these tests, a cluster having at least two schedulable nodes (not tainted) is needed. - -Deploy services and pods to test --------------------------------- - -.. parsed-literal:: - - kubectl create -f |SCM_RAW_WEB|/src/components/k8s/examples/echoserver_nodeport.yaml - kubectl run curl1 --image=tutum/curl --replicas=5 --command -- sleep 600000 - - -After a short period of time, all pods should be in the `Running` state - -:: - - k8s@k8s-master:~$ kubectl get pods -o wide - NAME READY STATUS RESTARTS AGE IP NODE - curl1-5df485555f-2dpwx 1/1 Running 0 1m 192.168.1.3 k8s-worker2 - curl1-5df485555f-l7ql4 1/1 Running 0 1m 192.168.0.246 k8s-master - curl1-5df485555f-s9wsv 1/1 Running 0 1m 192.168.1.5 k8s-worker2 - curl1-5df485555f-xh4wv 1/1 Running 0 1m 192.168.1.4 k8s-worker2 - curl1-5df485555f-xqmxn 1/1 Running 0 1m 192.168.0.245 k8s-master - myechoserver-86856fd86f-fkzg6 1/1 Running 0 32s 192.168.1.6 k8s-worker2 - - -Tests ------ - -The following section present some test cases to check everything is working as expected. - -Test Node to Pod connectivity -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -:: - - # ping pod in master node - k8s@k8s-master:~$ ping 192.168.0.245 - - k8s@k8s-master:~$ ping 192.168.1.3 - - -Test Pod to Pod connectivity -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -:: - - # select one pod running on master, in this case (192.168.0.245) - k8s@k8s-master:~$ ID=curl1-5df485555f-xqmxn - - # ping pod in master - k8s@k8s-master:~$ kubectl exec $ID ping 192.168.0.246 - - # ping pod in worker - k8s@k8s-master:~$ kubectl exec $ID ping 192.168.1.5 - - -Test Pod to Internet connectivity -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -:: - - # ping to internet - k8s@k8s-master:~$ kubectl exec $ID ping 8.8.8.8 - - -Test ClusterIP service -^^^^^^^^^^^^^^^^^^^^^^ - -The following command will give us the details about the service we created: - -:: - - k8s@k8s-master:~$ kubectl describe service myechoserver - Name: myechoserver - Namespace: default - Labels: app=myechoserver - Annotations: - Selector: app=myechoserver - Type: NodePort - IP: 10.96.23.23 - Port: 8080/TCP - TargetPort: 8080/TCP - NodePort: 31333/TCP - Endpoints: 192.168.1.6:8080 - Session Affinity: None - External Traffic Policy: Cluster - Events: - -:: - - # direct access to the backend - k8s@k8s-master:~$ curl 192.168.1.6:8080 - - # access from node to ClusterIP - curl 10.96.23.23:8080 - - # access from a pod (change ID to both, a pod in the local node and also a pod in a remote node) - kubectl exec $ID curl 10.96.23.23:8080 - - -Test NodePort service -^^^^^^^^^^^^^^^^^^^^^ - -The service is exposed in port `31333`, perform a request to the public IP of the master and the node from a remote host. - -:: - - # request to master - curl 130.192.225.143:31333 - - # request to worker - curl 130.192.225.144:31333 - - -TODO: -- test dns service -- test scale-up scale down diff --git a/Documentation/conf.py b/Documentation/conf.py index 800b9a4da..4c46d4bc5 100644 --- a/Documentation/conf.py +++ b/Documentation/conf.py @@ -20,7 +20,7 @@ # -- Project information ----------------------------------------------------- project = u'Polycube' -copyright = u'2018-2019, The Polycube Authors' +copyright = u'2018-2020, The Polycube Authors' author = u'The Polycube Authors' # The short X.Y version diff --git a/Documentation/developers/controlplane.rst b/Documentation/developers/controlplane.rst index 816fe3dcb..2ae95d04f 100644 --- a/Documentation/developers/controlplane.rst +++ b/Documentation/developers/controlplane.rst @@ -11,14 +11,15 @@ The constructor of such classes receives two ``std::vector`` that c The following functions allow to reload, add and delete eBPF programs. -- void reload(const std::string &code, int index, ProgramType type) -- int add_program(const std::string &code, int index, ProgramType type) -- void del_program(int index, ProgramType type) + - void reload(const std::string &code, int index, ProgramType type) + - int add_program(const std::string &code, int index, ProgramType type) + - void del_program(int index, ProgramType type) Where: -- index: position of the program -- type: if the program is on the ``INGRESS`` or ``EGRESS`` chain. + - index: position of the program + - type: if the program is on the ``INGRESS`` or ``EGRESS`` chain. + Adding and removing ports ************************* @@ -33,73 +34,76 @@ The stub generated already include those functions, so in general the developer eBPF maps API ************* -The ``polycube::service::BaseCube`` base class provides the ``get_{raw, array, percpuarray, hash, percpuhash}_table()` methods that allows to get a reference to an eBPF map. +The ``polycube::service::BaseCube`` base class provides the ``get_{raw, array, percpuarray, hash, percpuhash}_table()`` methods that allows to get a reference to an eBPF map. The ``RawTable`` is intended to access the memory of the maps without any formatting, the user should pass pointers to key and/or value buffers. It provides the following API: -- void set(const void *key, const void *value) -- void get(const void *key, void *value) -- void remove(const void*key) + - void set(const void* key, const void* value) + - void get(const void* key, void * value) + - void remove(const void* key) The ``ArrayTable`` and ``PercpuArrayTable`` are intended to handle array like maps, this class is templated on the value type. The ``ArrayTable`` provides the following API: -- void set(const uint32_t &key, const ValueType &value) -- ValueType get(const uint32_t &key)** -- std::vector>> get_all() + - void set(const uint32_t &key, const ValueType &value) + - ValueType get(const uint32_t &key) + - std::vector>> get_all() The the ``PercpuArrayTable`` provides: -- std::vector get(const uint32_t &key) -- std::vector>> get_all() -- void set(const uint32_t &key, const std::vector &value) -- void set(const uint32_t &key, const ValueType &value): Set value in all CPUs. + - std::vector get(const uint32_t &key) + - std::vector>> get_all() + - void set(const uint32_t &key, const std::vector &value) + - void set(const uint32_t &key, const ValueType &value): Set value in all CPUs. The ``HashTable`` and ``PercpuHashTable`` are intended to handle hash like maps, this class is templated on the key and value type. The ``HashTable`` provides the following API: -- ValueType get(const KeyType &key) -- std::vector> get_all() -- void set(const KeyType &key, const ValueType &value) -- void remove(const KeyType &key) -- void remove_all() + - ValueType get(const KeyType &key) + - std::vector> get_all() + - void set(const KeyType &key, const ValueType &value) + - void remove(const KeyType &key) + - void remove_all() The ``PercpuHashTable`` exposes: -- std::vector get(const KeyType &key) -- std::vector>> get_all() -- void set(const KeyType &key, const std::vector &value) -- void set(const KeyType &key, const ValueType &value)**: Set value in all CPUs. -- void remove(const KeyType &key) -- void remove_all() + - std::vector get(const KeyType &key) + - std::vector>> get_all() + - void set(const KeyType &key, const std::vector &value) + - void set(const KeyType &key, const ValueType &value)**: Set value in all CPUs. + - void remove(const KeyType &key) + - void remove_all() In order to have an idea of how to implement this, take at look at the already implemented services, :scm_web:`router ` and :scm_web:`firewall ` are good examples. + Implementing the control path ***************************** Handling PacketIn events ++++++++++++++++++++++++ -If the service is intended to receive data packets in the control path (using an approach that is commonly said _slow path_), you should implement the logic that handles those packets in the `packet_in` function, it receives: -- **port**: a reference to the ingress port of the packet -- **md**: the metadata associated to this packet - - **reason** and **metadata**: values used by the datapath when sending the packet to the control path through the `pcn_pkt_controller` functions. -- **packet**: an array containing the packet's bytes. +If the service is intended to receive data packets in the control path (using an approach that is commonly said *slow path*), you should implement the logic that handles those packets in the `packet_in` function, it receives: + - **port**: a reference to the ingress port of the packet + - **md**: the metadata associated to this packet + - **reason** and **metadata**: values used by the datapath when sending the packet to the control path through the ``pcn_pkt_controller()`` functions. + - **packet**: an array containing the packet's bytes. + Generating PacketOut events +++++++++++++++++++++++++++ -The ``Port`` class contains the ``send_packet_out(EthernetII &packet, bool recirculate = false)`` method that allows to inject packets into the datapath, the recirculate parameter allows to specify if the packet should be sent out of the port (`recirculate = false`) or received through the port (`recirculate = true`). +The ``Port`` class contains the ``send_packet_out(EthernetII &packet, bool recirculate = false)`` method that allows to inject packets into the datapath. +The ``recirculate`` parameter specifies if the packet should be sent out of the port (``recirculate = false``) or received through the port (``recirculate = true``). Only in shadow services the ``Port`` class contains the ``send_packet_ns(EthernetII &packet)`` method that allows to send packets into the service namespace. -A reference to a port can be got using the `get_port` function of the Cube base class. +A reference to a port can be got using the ``get_port()`` function of the Cube base class. Debugging the control plane *************************************** -See how to debug by :ref:`logging in the control plane `. \ No newline at end of file +See how to debug by :ref:`logging in the control plane `. diff --git a/Documentation/developers/datapath.rst b/Documentation/developers/dataplane.rst similarity index 92% rename from Documentation/developers/datapath.rst rename to Documentation/developers/dataplane.rst index b5477b44f..abaf93316 100644 --- a/Documentation/developers/datapath.rst +++ b/Documentation/developers/dataplane.rst @@ -45,19 +45,20 @@ Vlan Support The vlan handling in TC and XDP eBPF programs is a little bit different, so polycube includes a set of helpers to uniform this accross. -- bool pcn_is_vlan_present(struct CTXTYPE *pkt) +- bool pcn_is_vlan_present(struct CTXTYPE* pkt) -- int pcn_get_vlan_id(struct CTXTYPE *pkt, uint16_t *vlan_id, uint16_t *eth_proto); +- int pcn_get_vlan_id(struct CTXTYPE* pkt, uint16_t* vlan_id, uint16_t* eth_proto); -- uint8_t pcn_vlan_pop_tag(struct CTXTYPE *pkt); +- uint8_t pcn_vlan_pop_tag(struct CTXTYPE* pkt); -- uint8_t pcn_vlan_push_tag(struct CTXTYPE *pkt, u16 eth_proto, u32 vlan_id); +- uint8_t pcn_vlan_push_tag(struct CTXTYPE* pkt, u16 eth_proto, u32 vlan_id); Known limitations: ****************** - It is not possible to send a packet through multiple ports, then multicast, broadcast of any similar functionality has to be implemented in the control path. + TODO: ***** @@ -66,4 +67,4 @@ TODO: Debugging the data plane *************************************** -See how to debug by :ref:`logging in the dataplane `. \ No newline at end of file +See how to debug by :ref:`logging in the dataplane `. \ No newline at end of file diff --git a/Documentation/developers/debugging.rst b/Documentation/developers/debugging.rst index 135dc6e8a..1fe46ecb1 100644 --- a/Documentation/developers/debugging.rst +++ b/Documentation/developers/debugging.rst @@ -1,5 +1,6 @@ Debugging Polycube services ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + The main way to debug a service in Polycube is by using debug log messages. Polycube provides the primitives that enables to print messages (from both data and control plane) in the **same** log file, hence facilitating the integrated debugging of both data and control plane components. However, primitives to be used are different in the above two cases and will be presented later in this document. @@ -8,25 +9,37 @@ By default, the log file can be found in ``/var/log/polycube/polycubed.log`` and Configuring logging levels -*************************************** -The Polycube framework defines the above six log levels, listed in increasing order of importance, following the general accepted practice proposed on `StackOverflow `_: - - ``trace``: when the developer would "trace" the code and trying to find one part of a function specifically. - - ``debug``: information that is diagnostically helpful to people more than just developers (IT, sysadmins, etc.). - - ``info`` (*default value*): information that is usually useful to log (service start/stop, configuration assumptions, etc); information that users would like to have available but usually do not care about under normal circumstances. - - ``warning``: anything that can potentially cause application oddities, but that can usually be automatically recovered by the framework, such as switching from a primary to backup server, retrying an operation, missing secondary data, etc. - - ``error``: any error which is fatal to the operation, but not the service or application, such as cannot open a required file, missing data, etc.. These errors should force user (administrator, or direct user) intervention. - - ``critical``: any error that is forcing a shutdown of the service or application to prevent data loss (or further data loss). These errors should be reserved only for the most heinous errors and situations where there is guaranteed to have been data corruption or loss. +************************** + +Polycube defines six log levels, listed below in increasing order of importance, following the general accepted practice proposed on `StackOverflow `_: + + - ``trace``: when the developer would "trace" the code and trying to find one part of a function specifically. + - ``debug``: information that is diagnostically helpful to people more than just developers (IT, sysadmins, etc.). + - ``info`` (*default value*): information that is usually useful to log (service start/stop, configuration assumptions, etc); information that users would like to have available but usually do not care about under normal circumstances. + - ``warning``: anything that can potentially cause application oddities, but that can usually be automatically recovered by the framework, such as switching from a primary to backup server, retrying an operation, missing secondary data, etc. + - ``error``: any error which is fatal to the operation, but not the service or application, such as cannot open a required file, missing data, etc.. These errors should force user (administrator, or direct user) intervention. + - ``critical``: any error that is forcing a shutdown of the service or application to prevent data loss (or further data loss). These errors should be reserved only for the most heinous errors and situations where there is guaranteed to have been data corruption or loss. Each Polycube service has a ``loglevel`` property that enables the printing of log messages filtered by the choosen level. Setting the ``loglevel`` to ``X`` means that all the messages of that loglevel and above will be printed. For instance, if ``loglevel=warning``, all messages marked as ``warning``, ``error`` and ``critical`` are printed. -Setting the ``loglevel`` property of a service is documented in :ref:`polycubectl section `. +Setting the ``loglevel`` property of a service can be achieved by creating the service with the proper property, such as in the following: + +:: + + polycubectl router r0 add loglevel=debug + +This creates a new instance of a router, called ``r0``, with the highest logging level (``debug``) turned on. -**Note 1**: the loglevel of ``polycubectl`` does not affect the outputs produced by the logs of individual services. In other words, ``polycubectl`` loglevel can be set to ``info``, while the loglevel of the ``bridge`` service can be set to ``trace``. +**Note 1** The loglevel of each individual service does not affect the loglevel of the ``polycubectl`` command line. In other words, ``polycubectl`` logging can be set to minimal (i.e., logging level = ``info``), while a given service can have the logging level equal to ``debug``. +More information is available in the :ref:`configuring polycubectl ` section. -**Note 2**: the log file can be easily filtered on either (1) a specific loglevel or (2) a specific service by using the standard Unix ``grep`` tool. +**Note 2** The loglevel of each individual service does not affect the loglevel of the ``polycubed`` system daemon. In other words, ``polycubed`` logging can be set to minimal (i.e., logging level = ``info``), while a given service can have the logging level equal to ``debug``. +More information is available in the :ref:`debugging the polycubed daemon ` section. + +**Note 3**: the log file can be easily filtered on either (1) a specific loglevel or (2) a specific service by using the standard Unix ``grep`` tool. Usage examples: @@ -36,11 +49,15 @@ Setting the ``loglevel`` property of a service is documented in :ref:`polycubect sudo polycubed | grep -E "warning|error|critical" sudo polycubed | grep "bridge" -.. _logging-in-the-data-plane: + + +.. _logging-data-plane: Logging in the data plane -*************************************** -In order to avoid the use of the ``bpf_trace_printk()`` primitive (which is not integrated with control plane logging and should not be used in Polycube), the Polycube framework provides the ``pcn_log()`` primitive. +************************* + +The common eBPF primitive ``bpf_trace_printk()``, which is widely used in other eBPF frameworks, should not be used in Polycube. +Polycube offers a new ``pcn_log()`` primitive, which integrates both data and control plane logging in the same location. Syntax: @@ -48,21 +65,23 @@ Syntax: pcn_log(ctx, level, msg, args...) -- ``ctx``: packet being processed. -- ``level``: type of logging level: ``LOG_TRACE``, ``LOG_DEBUG``, ``LOG_INFO``, ``LOG_WARN``, ``LOG_ERR``, ``LOG_CRITICAL``. -- ``msg``: message to print -- ``args``: arguments of the message + - ``ctx``: packet being processed. + - ``level``: type of logging level: ``LOG_TRACE``, ``LOG_DEBUG``, ``LOG_INFO``, ``LOG_WARN``, ``LOG_ERR``, ``LOG_CRITICAL``. + - ``msg``: message to print + - ``args``: arguments of the message Three special format specifiers are available: -- ``%I``: print an IP address -- ``%M``: print a MAC address -- ``%P``: print a TCP/UDP port + + - ``%I``: print an IP address + - ``%M``: print a MAC address + - ``%P``: print a TCP/UDP port Please note the the custom specifiers expect the data to be in *network byte order* while standard specifiers expects it to be in *host byte order*. Current limitations of ``pcn_log()``: - - Cannot be used inside a macro - - Maximum 4 arguments are allowed + + - Cannot be used inside a macro + - Maximum 4 arguments are allowed Usage example: @@ -72,7 +91,7 @@ Usage example: The ``pcn_pkt_log(ctx, level)`` primitive sends a packet to the control plane where it is printed in a tcpdump-like format. -`ctx` and `level` are the same as in `pcn_log`. +``ctx`` and ``level`` are the same as in ``pcn_log``. This feature is only designed for developers, so final version of services should not include this. Usage example: @@ -81,12 +100,14 @@ Usage example: pcn_pkt_log(ctx, LOG_DEBUG); -.. _logging-in-the-control-plane: + +.. _logging-control-plane: Logging in the control plane -****************************************** +**************************** -In order to avoid the use of custom ``printf()`` or similar primitives, which makes the code difficult to debug, Polycube includes a logging system with a proper class. +Custom ``printf()`` or similar primitives, which make the code difficult to debug, should not be used in the Polycube control plane. +In fact, the ``pcn_log()`` primitive presented below can be used also in the control plane, as Polycube includes a powerful logging system implemented within a dedicated class. Usage example: diff --git a/Documentation/developers/hints.rst b/Documentation/developers/hints.rst index 48cf2a1a4..e91c67494 100644 --- a/Documentation/developers/hints.rst +++ b/Documentation/developers/hints.rst @@ -1,7 +1,6 @@ Some hints for programmers -------------------------- -We apologize for this section being just an unstructured list of suggestions; better documentation will be created soon. Install the provided git-hooks ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -11,14 +10,14 @@ Git hook scripts are useful for identifying simple issues before submission to c To solve these issues and benefit from this feature, we use [pre-commit](https://pre-commit.com/), a framework for managing and maintaining multi-language pre-commit hooks. -The `.pre-commit-config.yaml` configuration file is already available under the root folder of this repo but before you can run hooks, you need to have the pre-commit package manager installed. You can install it using pip: +The ``.pre-commit-config.yaml`` configuration file is already available under the root folder of this repo but before you can run hooks, you need to have the pre-commit package manager installed. You can install it using pip: :: sudo apt-get install python-pip -y pip install pre-commit -After that, run pre-commit install (under the project root folder) to install pre-commit into your git hooks. pre-commit will now run on every commit. +After that, run ``pre-commit install`` (under the project root folder) to install ``pre-commit`` into your git hooks. ``pre-commit`` will now run on every commit. :: @@ -29,8 +28,7 @@ How to write a test The following is a brief guideline about how to write tests for services. Please remember such tests are invoked by a more generic script that tries to execute all tests for all services and provide global results. -1. tests are placed under `pcn-servicename\test` folder (and its first level of subfolders). -E.g. `pcn-bridge\test` and `pcn-bridge\test\vlan` are valid folders. +1. tests are placed under `pcn-servicename\test` folder (and its first level of subfolders). E.g. `pcn-bridge\test` and `pcn-bridge\test\vlan` are valid folders. 2. tests name begins with `test*` @@ -42,14 +40,11 @@ E.g. `pcn-bridge\test` and `pcn-bridge\test\vlan` are valid folders. 6. tests must terminate in a fixed maximum time, no `read` or long `sleep` allowed -7. tests **must** exit with a **clean environment**: all `namespaces`, `links`, `interfaces`, `cubes` created inside the script must be destroyed when script returns. -In order to do that use a `function cleanup` and set `trap cleanup EXIT` to be sure cleanup function gets always executed (also if an error is encountered, and the script fails). +7. tests **must** exit with a **clean environment**: all `namespaces`, `links`, `interfaces`, `cubes` created inside the script must be destroyed when script returns. In order to do that use a `function cleanup` and set ``trap cleanup EXIT`` to be sure cleanup function gets always executed (also if an error is encountered, and the script fails). -8. consider that when `set -e` is enabled in your script, and you want to check if, for instance, a `ping` or `curl` command succeeds, this check is implicitly done by the returning value of the command itself. -So `ping 10.0.0.1 -c 2 -w 4` makes your script succeed if ping works, and make your script fail if it doesn't. +8. consider that when ``set -e`` is enabled in your script, and you want to check if, for instance, a ``ping`` or ``curl`` command succeeds, this check is implicitly done by the returning value of the command itself. Hence, ``ping 10.0.0.1 -c 2 -w 4`` makes your script succeed if ping works, and make your script fail if it does not. -9. if the test `succeded` it returns `0`, otherwise returns `non-zero-value` (this is the standard behavior). -In order to check a single test result, use `echo $?` after script execution to read return value. +9. if the test `succeeded` it returns ``0``, otherwise returns `non-zero-value` (this is the standard behavior). In order to check a single test result, use `echo $?` after script execution to read return value. Please refer to existing examples (E.g. [services/pcn-helloworld/test/test1.sh](services/pcn-helloworld/test/test1.sh)) @@ -69,16 +64,12 @@ Additional hints 1. **Creating multiple data plane programs**. If possible, it would be nice to create a single dataplane program, and enabling/disabling some portions using conditional compilation macros. -2. **Coding Style**: The `scripts/check-style.py` uses `clang-format` to check the code style. -This tool has to be executed from the root folder. -A list of files or folders to check is received as argument; the entire source code is checked when no parameters are passed. -The `--fix` option will automatically fix the code style instead of simply checking +2. **Coding Style**: The ``scripts/check-style.py`` uses ``clang-format`` to check the code style. This tool has to be executed from the root folder. A list of files or folders to check is received as argument; the entire source code is checked when no parameters are passed. The ``--fix`` option will automatically fix the code style instead of simply checking -3. **Trailing white spaces**: Trailing white spaces could generate some git noise. -Any decent text editor has an option to remove them automatically, it is a good idea to enable it. -Please notice that running `clang-format` will remove them automatically. -**NB**: If you are using our `pre-commit git hooks`, you do not need to remove the trailing whitespaces manually, they will be removed automatically at every commit. -If you want to remove them manually you can use execute the following commands in the polycube root folder, please note that this will remove trailing whitespaces of all files. +3. **Trailing white spaces**: Trailing white spaces could generate some git noise. Any decent text editor has an option to remove them automatically, it is a good idea to enable it. Please notice that running ``clang-format`` will remove them automatically. + +**Note**: If you are using our ``pre-commit git hooks``, you do not need to remove the trailing whitespaces manually, they will be removed automatically at every commit. +If you want to remove them manually you can use execute the following commands in the Polycube root folder, please note that this will remove trailing whitespaces of all files. :: @@ -101,6 +92,7 @@ If you want to remove them manually you can use execute the following commands i #usage sudo bpftool + Continuous Integration ^^^^^^^^^^^^^^^^^^^^^^ @@ -131,28 +123,30 @@ Valgrind Valgrind is an open source tool for analyzing memory management and threading bugs. It can easily discover memory leaks, and spot possible segfault errors. -Requirements for polycubed: (1) valgrind 3.15+ (2) disable `setrlimit` in polycubed.cpp +Requirements for polycubed: (1) valgrind 3.15+ (2) disable ``setrlimit`` in ``polycubed.cpp``. -1 Install valgrind 3.15 -*********************** -Valgrind 3.14+ is introducing support for bpf() system call. +1. Install valgrind 3.15 +************************ + +Valgrind 3.14+ supports ``bpf()`` system call. Previous versions won't work. -- Download Valgrind 3.15+ source from here http://www.valgrind.org/downloads/current.html -- Build Valgrind from source http://valgrind.org/docs/manual/dist.install.html +- Download Valgrind 3.15+ source from here: http://www.valgrind.org/downloads/current.html +- Build Valgrind from source: http://valgrind.org/docs/manual/dist.install.html + :: ./configure make sudo make install -2 Disable `setrlimit` -********************* +2. Disable ``setrlimit`` +************************ -Only for debug purposes and in order to be able to run valgrind we have to disable `setrlimit` in polycubed.cpp. +Only for debug purposes and in order to be able to run valgrind we have to disable ``setrlimit`` in ``polycubed.cpp``. -We suggest to comment out following lines in :scm_web:`polycubed.cpp ` +We suggest to comment out following lines in :SCM_WEB:`polycubed.cpp ` :: // Each instance of a service requires a high number of file descriptors diff --git a/Documentation/developers/index.rst b/Documentation/developers/index.rst index 3e229aaab..400a1556e 100644 --- a/Documentation/developers/index.rst +++ b/Documentation/developers/index.rst @@ -8,7 +8,7 @@ This guide represents an initial starting point for developers that want to impl :maxdepth: 2 :caption: Contents: - datapath + dataplane controlplane datamodel codegen @@ -25,7 +25,7 @@ The process to create or update service could be summarized in these steps: 1. :doc:`Write or update a datamodel for the service ` 2. :doc:`Use the datamodel for generating a service stub or updating an existing service stub ` - 3. :doc:`Implement or update the eBPF datapath ` + 3. :doc:`Implement or update the eBPF datapath ` 4. :doc:`Implement or update the control plane ` Please note that steps (1) and (2) are needed only when there is a change to the the YANG data model. diff --git a/Documentation/developers/profiler.rst b/Documentation/developers/profiler.rst index 3bd04e4db..ee03591a6 100644 --- a/Documentation/developers/profiler.rst +++ b/Documentation/developers/profiler.rst @@ -9,10 +9,12 @@ Introduction This framework provides an efficient and simple benchmarking primitive for user programs. Particularly, this can be used to profile the control plane portion of Polycube. Although there are several powerful tools (particularly in Linux) that target benchmarking and profiling, they are often difficult to learn for an occasional user, which may need to perform some simple and fast benchmarking. -A worth-mentioning tool is `perf `_. Perf is a Linux profiling tool with performance counters which helps users to understand at low-level how not only the program, but also the hardware behaves. As the wiki reports, this tool not only is quite complex to learn, but it also produces deep information that users may not use or that they have to aggregate them to achieve a readable result. Moreover, perf refers to different types of event (ex. I/O disk) users may not be interested in. +A worth-mentioning tool is `perf `_. +Perf is a Linux profiling tool with performance counters which helps users to understand at low-level how not only the program, but also the hardware behaves. As the wiki reports, this tool not only is quite complex to learn, but it also produces deep information that users may not use or that they have to aggregate them to achieve a readable result. Moreover, perf refers to different types of event (ex. I/O disk) users may not be interested in. This library provides a simple to use method not only to run a whole program benchmark, but also to measure single code-fragments performance. + How it works ************ @@ -29,10 +31,10 @@ While the usage of a check-point leads to a negligible overhead (\~60 nanosecond Each measure is characterized by: -* filename: the name of the file which contains the check-point; -* line of code: the line of code where the check-point has been inserted; -* name (optional): the name/description of the checkpoint given by the user; -* timestamp: the measure in *nanoseconds* taken. +- filename: the name of the file which contains the check-point; +- line of code: the line of code where the check-point has been inserted; +- name (optional): the name/description of the checkpoint given by the user; +- timestamp: the measure in *nanoseconds* taken. Accordingly, the format used to store check-points is: `,,,`. @@ -60,31 +62,32 @@ In this simple program we want to measure the performance of our function to com .. code-block:: c++ - #define PROFILER - #include - - int main(int argc, char **argv) { - CHECKPOINT("Beginning") //line 7 - computeSquare(1); - CHECKPOINT("After first computation") //line 9 - computeSquare(2); - STOREPOINT("After second computation") //line 11 - return 0; - } + #define PROFILER + #include + + int main(int argc, char **argv) { + CHECKPOINT("Beginning") //line 7 + computeSquare(1); + CHECKPOINT("After first computation") //line 9 + computeSquare(2); + STOREPOINT("After second computation") //line 11 + return 0; + } + +After the execution, we obtain the following ``profile_20190902_181847.log`` file: -After the execution, we obtain the following `profile_20190902_181847.log` file: +.. code-block:: text -.. code-block:: txt + main.cpp,7,Beginning,1567333232104876595 + main.cpp,9,After first computation,1567333232104876666 + main.cpp,11,After second computation,1567333232104876737 - main.cpp,7,Beginning,1567333232104876595 - main.cpp,9,After first computation,1567333232104876666 - main.cpp,11,After second computation,1567333232104876737 +Since the stored timestamps refer to the start of the epoch, to beautify the data and print some statistics we use our script ``profiler_parser.py``: -Since the stored timestamps refer to the start of the epoch, to beautify the data and print some statistics we use our script `profiler_parser.py`: .. code-block:: bash - $ python profiler_parser.py profile_20190902_181847.log + $ python profiler_parser.py profile_20190902_181847.log ======================================================================== ||FROM |TO |TIME(ns) || diff --git a/Documentation/index.rst b/Documentation/index.rst index f685d615c..f47b50c4c 100644 --- a/Documentation/index.rst +++ b/Documentation/index.rst @@ -18,7 +18,8 @@ Welcome to Polycube's documentation! polycubed/polycubed polycubectl/polycubectl security - components/index + components/iptables/pcn-iptables + components/k8s/index services/index tutorials/index developers/index diff --git a/Documentation/polycubectl/polycubectl.rst b/Documentation/polycubectl/polycubectl.rst index 19182f94e..77c11bc03 100644 --- a/Documentation/polycubectl/polycubectl.rst +++ b/Documentation/polycubectl/polycubectl.rst @@ -1,10 +1,13 @@ -.. _polycubectl: - -polycubectl: The Command Line Interface for Polycube +polycubectl: The command-line onterface for Polycube ==================================================== ``polycubectl`` is the Command Line Interface (CLI) for Polycube. +``polycubectl`` is a generic CLI, that enables the user to interact with ``Cubes`` (``bridge``, ``router``, ...) and with some framework primitives to ``connect``, ``show`` and build complex ``topologies``. + +``polycubectl`` does not need to be modified when a new cube is developed ad added to Polycube. Its service-agnostic nature, thanks to the use of YANG data models, enables the CLI to be service-independent. + + Install ------- @@ -14,11 +17,10 @@ Refer to :doc:`quickstart <../quickstart>` or general :doc:`install <../installa How to use ---------- -**NOTE**: ``polycubed`` must be running, in order to use ``polycubectl``. +**NOTE**: ``polycubed`` must be running in order to use ``polycubectl``. You can start the daemon typing ``sudo polycubed`` in another terminal. Refer to :doc:`Quick Start <../quickstart>`. -``polycubectl`` is a generic CLI, that enables the user to interact with ``Cubes`` (``bridge``, ``router``, ...) and with some framework primitives to ``connect``, ``show`` and build complex ``topologies``. :: @@ -51,8 +53,7 @@ Refer to :doc:`Quick Start <../quickstart>`. topology command Show topology of service instances netdevs command Show net devices available -``polycubectl`` is service agnostic, hence the syntax is service dependent. -However we can generalize the syntax as: +The general syntax for ``polycubectl`` is the following: :: @@ -171,11 +172,13 @@ Examples: # hide uuids and mac ports polycubectl router r0 show -hide=ports.uuid,ports.mac + Tutorials ^^^^^^^^^ More complete examples are available in :doc:`tutorials <../tutorials/index>`. + .. _polycubectl-configuration: Configuration diff --git a/Documentation/polycubed/polycubed.rst b/Documentation/polycubed/polycubed.rst index 93c4b4ae7..f28c755be 100644 --- a/Documentation/polycubed/polycubed.rst +++ b/Documentation/polycubed/polycubed.rst @@ -1,14 +1,14 @@ polycubed: the Polycube System Daemon ===================================== -.. The Polycube system daemon (polycubed) is in charge of managing the lifecycle of cubes, such as creating/updating/deleting network services. +The Polycube system daemon (polycubed) is in charge of managing the lifecycle of cubes, such as creating/updating/deleting network services. -.. In addition, it provides a single point of entry (a rest API server) for the configuration of any network function. +In addition, it provides a single point of entry (a rest API server) for the configuration of any network function. -.. The preferred way to interact with polycubed is through `polycubectl <../polycubectl.rst>`_. +The preferred way to interact with polycubed is through :doc:`polycubectl <../polycubectl/polycubectl>`. The Polycube System Daemon ``polycubed`` provides a kernel abstraction layer that is used by the different services. -It exposes a configuration mechanism of the different service instances through a rest API server. Users can interact with it using the :ref:`polycubectl CLI ` +It exposes a configuration mechanism of the different service instances through a rest API server. Users can interact with it using :doc:`polycubectl <../polycubectl/polycubectl>`. It requires root privileges and only an instance can be launched system wide. @@ -106,6 +106,12 @@ There are some limitations: (1) YANG actions, such as "append" for firewall and polycubed --cubes-dump-enable --cubes-dump-clean-init +.. _polycubed-debugging: + +Debugging +^^^^^^^^^ +The debugging of polycubed can be turned on by starting the daemon with the ``--loglevel=debug`` flag. + Rest API ^^^^^^^^ diff --git a/src/services/pcn-firewall/docs/images/fwDatapath.png b/Documentation/services/pcn-firewall/datapath.png similarity index 100% rename from src/services/pcn-firewall/docs/images/fwDatapath.png rename to Documentation/services/pcn-firewall/datapath.png diff --git a/Documentation/services/pcn-firewall/firewall-devel.rst b/Documentation/services/pcn-firewall/firewall-devel.rst deleted file mode 100644 index 89a68a654..000000000 --- a/Documentation/services/pcn-firewall/firewall-devel.rst +++ /dev/null @@ -1,29 +0,0 @@ -Firewall -======== - -Implementation details ----------------------- - -Data plane - fast path -^^^^^^^^^^^^^^^^^^^^^^ - -Currently eBPF does not support maps with ternary values (i.e., ``wildcard maps``), this forced to implement an algorithm that could offer this functionality and support a large number of rules, the **Linear Bit Vector Search**, that is particularly suitable to be implemented in eBPF and modularized using tail calls, but has an O(NRules) complexity. -A first module parses the packet and sends it to the ingress or egress chain. Each chain has a series of eBPF programs that evaluate one single field, compute the bit vector (in linear time) and sends the packet to the next module. The second-to-last module uses the ``De Bruijn sequence`` to perform a first bit set search, and based on the results calls the next module that performs the actual action on the packet. -Each module is injected only if the rule set requires it (for example, if no rule requires matching on IP source, the module in charge of doing it is not injected). -The rule limit and the O(N) complexity is given by the bit vector computation, that requires a linear search of the array, performed using loop unrolling. - -Control Plane -------------- - -Code structure -^^^^^^^^^^^^^^ - -The control plane is in charge of managing each eBPF module. The code has been organized hierarchically to simplify the implementation. The Firewall class acts as a master, it keeps track of all the injected modules. API calls are managed by the ChainRule and Chain classes. Each module is represented in the control plane by a class inheriting from the Program interface, and encapsulates the eBPF module management, offering uniform interfaces to inject or remove the module or interact with its tables. This structure has the advantage of masking a number of MACROS present in the bpf code that are substituted at run-time based on the configuration, for example the number of rules. - -Rules computation -^^^^^^^^^^^^^^^^^ - -The Linear Bit Vector Search requires computing tables of bit vectors, where (in synthesis) each table represent a field, each row represents a value for that field and the matched rules in the form of a bit vector (where the Nth bit is 1 if the rule is matched, 0 if not). -Considering the complexity of the operation, the choice was to compute the tables from zero each time a rule is modified. - - diff --git a/Documentation/services/pcn-firewall/firewall.rst b/Documentation/services/pcn-firewall/firewall.rst index 31b9e0dc5..b2dc5b88b 100644 --- a/Documentation/services/pcn-firewall/firewall.rst +++ b/Documentation/services/pcn-firewall/firewall.rst @@ -3,25 +3,31 @@ Firewall This service implements a transparent firewall. It can be attached to a port or a netdev, and it may drop or forward each packet that matches one of the defined rules, based on the source and destination IPv4 addresses, level 4 protocol and ports, and TCP flags. Policy rules can include one or more of the above fields; if a given field is missing, its content does not influence the matching. -*Non-IP packets are always forwarded, without any check*. + +**Non-IP packets are always forwarded, without any check**. + Features -------- Supported features: -- Matching on following fields: - - ``IPv4 source/destination`` (with prefix match) - - ``L4 protocol`` (TCP/UDP/ICMP) - - ``L4 source/destination port`` - - ``TCP Flags`` - - ``Connection tracking`` status -- Possible actions: - - ``Forward`` packet from the interface from which it was received to the other - - ``Drop`` packet + - Matching on following fields: + + - IPv4 source/destination (with prefix match) + - L4 protocol (TCP/UDP/ICMP) + - L4 source/destination port + - TCP Flags + - Connection tracking status + + - Possible actions: + + - Forward packet from the interface from which it was received to the other + - Drop packet + + - Non-IP packets are always forwarded + - Up to 5k rules for each chain (INGRESS/EGRESS) -- Non-IP packets are always forwarded. -- Up to 5k rules for each chain (INGRESS/EGRESS). How to use ---------- @@ -35,11 +41,13 @@ The service supports independent ingress and egress policy chains, with two diff Rule insertion ^^^^^^^^^^^^^^ -Rule insertion is guaranteed to be ``atomic``: during the computation of the new datapath, the old rule set is used until the new rule set is ready, and only at that moment the new policies will be applied. +Rule insertion is guaranteed to be *atomic*: during the computation of the new datapath, the old rule set is used until the new rule set is ready, and only at that moment the new policies will be applied. Rule insertion is an expensive operation. For this reason, there are two modes that can be used based on the needs: -- ``Interactive mode:`` this is the default mode. It makes the commands to modify policies synchronous, so that they return only when the modification is reflected in the datapath. This is the slowest mode, as it requires to recompute the datapath for each command, but it has the advantage that a command returns only when the operation is completed. -- ``Transaction mode:`` in this mode commands on the policies are chained and asynchronously applied to the datapath altogether when the user asks it. The performance gain is sensible when commands have to be issued together (e.g. a set of rules), as it requires only one interaction with the datapath at the end. To switch in the transaction mode, it is necessary to issue the command ``polycubectl firewall fwname set interactive=false``. In this way, rules can be inserted normally, but to apply them the command ``polycubectl firewall fwname chain INGRESS apply-rules`` has to be issued. Notice: this command is specific for the chain, and updates the specified chain only. + + - ``Interactive mode:`` this is the default mode. It makes the commands to modify policies synchronous, so that they return only when the modification is reflected in the datapath. This is the slowest mode, as it requires to recompute the datapath for each command, but it has the advantage that a command returns only when the operation is completed. + - ``Transaction mode:`` in this mode commands on the policies are chained and asynchronously applied to the datapath altogether when the user asks it. The performance gain is sensible when commands have to be issued together (e.g. a set of rules), as it requires only one interaction with the datapath at the end. To switch in the transaction mode, it is necessary to issue the command ``polycubectl firewall fwname set interactive=false``. In this way, rules can be inserted normally, but to apply them the command ``polycubectl firewall fwname chain INGRESS apply-rules`` has to be issued. Notice: this command is specific for the chain, and updates the specified chain only. + Default action ^^^^^^^^^^^^^^ @@ -55,4 +63,41 @@ The service tracks the number of packets and the total bytes that have matched e Examples -------- -The ``/examples`` folder contains some simple script to show how to configure the service. +The `examples source folder `_ contains some simple scripts to show how to configure the service. + + + +Implementation details +---------------------- + +Data plane - fast path +^^^^^^^^^^^^^^^^^^^^^^ + +Currently eBPF does not support maps with ternary values (i.e., *wildcard maps*), this forced to implement an algorithm that could offer this functionality and support a large number of rules, the **Linear Bit Vector Search**, that is particularly suitable to be implemented in eBPF and modularized using tail calls, but has an O(NRules) complexity. + +A first module parses the packet and sends it to the ingress or egress chain. Each chain has a series of eBPF programs that evaluate one single field, compute the bit vector (in linear time) and sends the packet to the next module. The second-to-last module uses the *De Bruijn sequence* to perform a first bit set search, and based on the results calls the next module that performs the actual action on the packet. + +Each module is injected only if the rule set requires it (for example, if no rule requires matching on IP source, the module in charge of doing it is not injected). +The rule limit and the O(N) complexity is given by the bit vector computation, that requires a linear search of the array, performed using loop unrolling. + +An overview of the algorithm is depicted in the figure below. + +.. image:: datapath.png + :align: center + + +Control Plane +------------- + +Code structure +^^^^^^^^^^^^^^ + +The control plane is in charge of managing each eBPF module. The code has been organized hierarchically to simplify the implementation. The Firewall class acts as a master, it keeps track of all the injected modules. API calls are managed by the ChainRule and Chain classes. Each module is represented in the control plane by a class inheriting from the Program interface, and encapsulates the eBPF module management, offering uniform interfaces to inject or remove the module or interact with its tables. This structure has the advantage of masking a number of MACROS present in the bpf code that are substituted at run-time based on the configuration, for example the number of rules. + +Rules computation +^^^^^^^^^^^^^^^^^ + +The Linear Bit Vector Search requires computing tables of bit vectors, where each table represent a field, each row represents a value for that field and the matched rules in the form of a bit vector (where the Nth bit is 1 if the rule is matched, 0 if not). +Considering the complexity of the operation, the choice was to compute the tables from zero each time a rule is modified. + + diff --git a/src/services/pcn-firewall/docs/datapath.pptx b/Documentation/services/pcn-firewall/images.pptx similarity index 100% rename from src/services/pcn-firewall/docs/datapath.pptx rename to Documentation/services/pcn-firewall/images.pptx diff --git a/src/services/pcn-pbforwarder/docs/flowcharts.pptx b/Documentation/services/pcn-pbforwarder/images.pptx similarity index 100% rename from src/services/pcn-pbforwarder/docs/flowcharts.pptx rename to Documentation/services/pcn-pbforwarder/images.pptx diff --git a/src/services/pcn-pbforwarder/docs/images/insert_rule.png b/Documentation/services/pcn-pbforwarder/insert-rule.png similarity index 100% rename from src/services/pcn-pbforwarder/docs/images/insert_rule.png rename to Documentation/services/pcn-pbforwarder/insert-rule.png diff --git a/Documentation/services/pcn-pbforwarder/pbforwarder-devel.rst b/Documentation/services/pcn-pbforwarder/pbforwarder-devel.rst deleted file mode 100644 index e204adc61..000000000 --- a/Documentation/services/pcn-pbforwarder/pbforwarder-devel.rst +++ /dev/null @@ -1,33 +0,0 @@ -Policy-Based Forwarder -====================== - -Data plane - fast path ----------------------- - -The code of the data path is complicated by the fact that currently eBPF does not support maps with ternary values (i.e., wildcard maps). Therefore the algorithm is forced to implement a linear search, checking if the incoming packet matches the first rule, if not it moves to the second rule, and so on. - -The matching is done by using a flag, associated to each rule, whose bits are ``1`` in correspondence of the fields that are valid in the rule, and ``0`` if the rule does not consider that field and hence the content of the field can be simply ignored. This introduces a limitation in the current number of rules that can be matched, as the eBPF has to unroll a loop in order to check all the rules, hence quickly reaching the maximum number of instructions. - -In order to (partially) overcome the above limitation, the current data plane code depends on two macros: ``LEVEL`` and ``RULES``, both defined by ``generate_code()`` in ``Pbforwarder.cpp``. -Based on the ``LEVEL`` macro, the fast path enables only the portions of the code that are strictly needed for the matching, based on the fields that actually need to be checked. In order words, if the rules refer only to L2 fields, the fast path enables only the portion of code that handles L2 processing, avoiding unnecessary checks on L3 and L4 fields. -In fact, the ``RULES`` macro keeps the actual number of configured rules, hence it represent the number of times the loop is unrolled by the eBPF compiler. - -This flowchart summarizes the fast path algorithm of the service, which is implemented in [src/Pbforwarder_dp.h](./src/Pbforwarder_dp.h). - -TODO: take that image - -![eBPF flowchart](./docs/images/pbforwarder.png) - -This service does not have any noticeable slow path algorithm for the data plane, which is then omitted here. - -Control path ------------- - -When a rule is inserted, the corresponding API method is called in ``DpforwarderApi.cpp``. This prepares a struct and the bitmap based on the input received from the user and passes the control to the set_rule method in ``Dpforwarder.cpp``. -The set_rule method evaluates the level required by the rule and sets the attribute ``match_level``, evaluates if the rule is new and sets the attribute `nr_rules`, then invokes `generate_code()` to prepare the eBPF code and loads it. - -When the number of rules exceeds the capacity of the data plane, the eBPF compiler returns an error and the user is warned that his latest rule cannot be applied. - - -TODO: another image -![Control path flowchart](./docs/images/insert_rule.png) diff --git a/src/services/pcn-pbforwarder/docs/images/pbforwarder.png b/Documentation/services/pcn-pbforwarder/pbforwarder.png similarity index 100% rename from src/services/pcn-pbforwarder/docs/images/pbforwarder.png rename to Documentation/services/pcn-pbforwarder/pbforwarder.png diff --git a/Documentation/services/pcn-pbforwarder/pbforwarder.rst b/Documentation/services/pcn-pbforwarder/pbforwarder.rst index ce363973a..934c425b4 100644 --- a/Documentation/services/pcn-pbforwarder/pbforwarder.rst +++ b/Documentation/services/pcn-pbforwarder/pbforwarder.rst @@ -4,22 +4,25 @@ Policy-Based Forwarder This service drops, forwards, or sends to the slowpath each packet that matches one of the defined rules, based on the source and destination MAC addresses, VLAN ID, IPv4 addresses, level 4 protocol and ports, and on the input port. Policy rules can include one or more of the above fields; if a given field is missing, its content is non-influent for the matching. -Feature list ------------- +Features +-------- Supported features: -- Wildcard matching on the above fields: - - Input port - - MAC source/destination - - VLAN ID - - IPv4 source/destination - - L4 protocol (TCP/UDP) - - L4 source/destination port - -- Possible actions: - - Forward packet on a given output port - - Send packet to slow path - - Drop packet + + - Wildcard matching on the above fields: + + - Input port + - MAC source/destination + - VLAN ID + - IPv4 source/destination + - L4 protocol (TCP/UDP) + - L4 source/destination port + + - Possible actions: + + - Forward packet on a given output port + - Send packet to slow path + - Drop packet Limitations ----------- @@ -33,11 +36,44 @@ Limitations - The code does not recognize the situation in which a complex rule is deleted in such a way that the remaining rules can leverage a more aggressive optimization (e.g, checking only on L2/L3 fields). Hence, in this case the optimization is not applied. -Usage example -------------- +How to use +---------- -TODO: how to expose examples? The [example](./example) show how to use this service to create a multi-hop forwarding service among different namespaces. This could be used to see the basic commands of the ``pcn-pbforwarder`` service. +Implementation details +---------------------- + +Data plane - fast path +^^^^^^^^^^^^^^^^^^^^^^ + +The code of the data path is complicated by the fact that currently eBPF does not support maps with ternary values (i.e., wildcard maps). Therefore the algorithm is forced to implement a linear search, checking if the incoming packet matches the first rule, if not it moves to the second rule, and so on. + +The matching is done by using a flag, associated to each rule, whose bits are ``1`` in correspondence of the fields that are valid in the rule, and ``0`` if the rule does not consider that field and hence the content of the field can be simply ignored. This introduces a limitation in the current number of rules that can be matched, as the eBPF has to unroll a loop in order to check all the rules, hence quickly reaching the maximum number of instructions. + +In order to (partially) overcome the above limitation, the current data plane code depends on two macros: ``LEVEL`` and ``RULES``, both defined by ``generate_code()`` in ``Pbforwarder.cpp``. +Based on the ``LEVEL`` macro, the fast path enables only the portions of the code that are strictly needed for the matching, based on the fields that actually need to be checked. In order words, if the rules refer only to L2 fields, the fast path enables only the portion of code that handles L2 processing, avoiding unnecessary checks on L3 and L4 fields. +In fact, the ``RULES`` macro keeps the actual number of configured rules, hence it represent the number of times the loop is unrolled by the eBPF compiler. + +The flowchart below summarizes the fast path algorithm of the service, which is split in multiple dataplane files (`source folder `_). + +.. image:: pbforwarder.png + :align: center + +This service does not have any noticeable slow path algorithm for the data plane, which is then omitted here. + + +Control path +^^^^^^^^^^^^ + +When a rule is inserted, the corresponding API method is called in ``DpforwarderApi.cpp``. This prepares a struct and the bitmap based on the input received from the user and passes the control to the set_rule method in ``Dpforwarder.cpp``. +The set_rule method evaluates the level required by the rule and sets the attribute ``match_level``, evaluates if the rule is new and sets the attribute `nr_rules`, then invokes `generate_code()` to prepare the eBPF code and loads it. + +When the number of rules exceeds the capacity of the data plane, the eBPF compiler returns an error and the user is warned that his latest rule cannot be applied. + + +.. image:: insert-rule.png + :align: center + diff --git a/Documentation/services/pcn-router/developer.rst b/Documentation/services/pcn-router/developer.rst deleted file mode 100644 index 0dad51a13..000000000 --- a/Documentation/services/pcn-router/developer.rst +++ /dev/null @@ -1,22 +0,0 @@ -Router developer -================ - -**TODO**: this document has to be updated! - -Data plane - fast path ----------------------- - -This flowchart summarizes the fast path algorithm of the router, which is implemented in [src/Router_dp.h](./src/Router_dp.h). - -TODO: should we include this image? - -![eBPF flowchart](./docs/datapath.png) - -Data plane - slow path ----------------------- - -This flowchart summarizes the slow path algorithm of the router, which is implemented in [src/Router.cpp](./src/Router.cpp). - -TODO: what about this? - -![Slowpath flowchart](./docs/slowpath.png) \ No newline at end of file diff --git a/Documentation/services/pcn-router/example1.rst b/Documentation/services/pcn-router/example1.rst deleted file mode 100644 index b4d558986..000000000 --- a/Documentation/services/pcn-router/example1.rst +++ /dev/null @@ -1,3 +0,0 @@ -Example 1 -========= - diff --git a/Documentation/services/pcn-router/router.rst b/Documentation/services/pcn-router/router.rst index 4a621334b..6615de73b 100644 --- a/Documentation/services/pcn-router/router.rst +++ b/Documentation/services/pcn-router/router.rst @@ -25,4 +25,26 @@ This is especially important if your setup is based on a Virtual Machine: virtua Examples ^^^^^^^^ -Please see :doc:`tutorial 2 <../../tutorials/tutorial2/tutorial2>` +Please see :doc:`Tutorial 2 <../../tutorials/tutorial2/tutorial2>`. + + +Implementation details +---------------------- + +Data plane - fast path +^^^^^^^^^^^^^^^^^^^^^^ + +This flowchart summarizes the fast path algorithm of the router, which is implemented in `Router_dp.c `_. + +.. image:: datapath.png + :align: center + + +Data plane - slow path +^^^^^^^^^^^^^^^^^^^^^^ + +This flowchart summarizes the slow path algorithm of the router, which is implemented in the control plane (`source code `_). + +.. image:: slowpath.png + :align: center + diff --git a/src/services/pcn-pbforwarder/docs/datapath.pdf b/src/services/pcn-pbforwarder/docs/datapath.pdf deleted file mode 100644 index 4083775df..000000000 Binary files a/src/services/pcn-pbforwarder/docs/datapath.pdf and /dev/null differ diff --git a/src/services/pcn-pbforwarder/docs/insert_rule.pdf b/src/services/pcn-pbforwarder/docs/insert_rule.pdf deleted file mode 100644 index 4a99fc35a..000000000 Binary files a/src/services/pcn-pbforwarder/docs/insert_rule.pdf and /dev/null differ