First commit

Change-Id: Iab8dca19bca1ef367b1cced4b345554fd32154df
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..4e68904
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+*.iml
+target
+p4c-out
+src/main/resources/p4c-out
\ No newline at end of file
diff --git a/.gitreview b/.gitreview
new file mode 100644
index 0000000..3241765
--- /dev/null
+++ b/.gitreview
@@ -0,0 +1,5 @@
+[gerrit]
+host=gerrit.opencord.org
+port=29418
+project=fabric-tofino.git
+defaultremote=origin
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..261eeb9
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/Makefile b/Makefile
new file mode 100755
index 0000000..da88f63
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,82 @@
+PROFILES ?= all
+ONOS_HOST ?= localhost
+
+mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
+curr_dir := $(patsubst %/,%,$(dir $(mkfile_path)))
+curr_dir_sha := $(shell echo -n "$(curr_dir)" | shasum | cut -c1-7)
+
+mvn_image := maven:3.6.1-jdk-11-slim
+mvn_container := mvn-build-${curr_dir_sha}
+
+onos_url := http://${ONOS_HOST}:8181/onos
+onos_curl := curl --fail -sSL --user onos:rocks --noproxy localhost
+
+pipeconf_app_name := org.opencord.fabric-tofino
+pipeconf_app_version := 2.2.1-SNAPSHOT
+
+tofino_compile := ./src/main/p4/tofino-compile.sh
+
+.PHONY: pipeconf
+
+build: clean $(PROFILES) pipeconf
+
+all: fabric fabric-bng fabric-spgw fabric-int fabric-spgw-int
+
+fabric:
+	@${tofino_compile} fabric ""
+
+fabric-simple:
+	@${tofino_compile} fabric-simple "-DWITH_SIMPLE_NEXT"
+
+fabric-bng:
+	@${tofino_compile} fabric-bng "-DWITH_BNG -DWITH_DOUBLE_VLAN_TERMINATION -DWITHOUT_XCONNECT"
+
+fabric-int:
+	@${tofino_compile} fabric-int "-DWITH_INT_SOURCE -DWITH_INT_TRANSIT"
+
+fabric-spgw:
+	@${tofino_compile} fabric-spgw "-DWITH_SPGW"
+
+fabric-spgw-int:
+	@${tofino_compile} fabric-spgw-int "-DWITH_SPGW -DWITH_INT_SOURCE -DWITH_INT_TRANSIT"
+
+# Reuse the same container to persist mvn repo cache.
+_create_mvn_container:
+	@if ! docker container ls -a --format '{{.Names}}' | grep -q ${mvn_container} ; then \
+		docker create -v ${curr_dir}:/mvn-src -w /mvn-src --name ${mvn_container} ${mvn_image} mvn clean package verify; \
+	fi
+
+_mvn_package:
+	$(info *** Building ONOS app...)
+	@mkdir -p target
+	@docker start -a -i ${mvn_container}
+
+pipeconf: _create_mvn_container _mvn_package
+	$(info *** ONOS pipeconf .oar package created succesfully)
+	@ls -1 ${curr_dir}/target/*.oar
+
+pipeconf-install:
+	$(info *** Installing and activating pipeconf app in ONOS at ${ONOS_HOST}...)
+	${onos_curl} -X POST -HContent-Type:application/octet-stream \
+		'${onos_url}/v1/applications?activate=true' \
+		--data-binary @target/fabric-tofino-${pipeconf_app_version}.oar
+	@echo
+
+pipeconf-uninstall:
+	$(info *** Uninstalling pipeconf app from ONOS (if present) at ${ONOS_HOST}...)
+	-${onos_curl} -X DELETE ${onos_url}/v1/applications/${pipeconf_app_name}
+	@echo
+
+netcfg:
+	$(info *** Pushing tofino-netcfg.json to ONOS at ${ONOS_HOST}...)
+	${onos_curl} -X POST -H 'Content-Type:application/json' \
+		${onos_url}/v1/network/configuration -d@./tofino-netcfg.json
+	@echo
+
+clean:
+	-rm -rf src/main/resources/p4c-out
+
+deep-clean: clean
+	-rm -rf target
+	-rm -rf p4c-out
+	-docker rm ${mvn_container} > /dev/null 2>&1
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..27f2161
--- /dev/null
+++ b/README.md
@@ -0,0 +1,242 @@
+# ONOS Fabric Pipeconf for Tofino
+
+This repository contains instructions and scripts to compile and use
+`fabric.p4` on Intel/Barefoot Tofino-enabled switches.
+
+[fabric.p4][fabric.p4] is a P4 program distributed as part of ONOS,
+designed to work with [Trellis](trellis), a set
+of SDN applications running on top of ONOS to provide the control plane for an
+IP fabric based on MPLS segment-routing.
+
+To use ONOS to control a Tofino-enabled switch, you will need to run the
+[Stratum][stratum] agent on the switch.
+
+## Requirements
+
+* Barefoot SDE >= 8.9 (with the P4_16 compiler for Tofino)
+* ONOS >= 2.2.1
+* Docker (to run the build scripts without worrying about dependencies)
+* cURL (to interact with the ONOS REST APIs)
+
+## Steps to build Tofino-enabled fabric.p4 pipeconfs
+
+ONOS uses "pipeconfs" to deploy and manage a given P4 program on a device.
+Pipeconfs are distrubuted as ONOS applications, hence using the `.oar`
+packaging. The following steps provide instructions on how to generate an oar
+package that includes a compiled version of `fabric.p4` that works on Tofino.
+
+* `src/main/java`: contains Java code that implements the ONOS app responsible
+  of registering the Tofino-enabled pipeconfs in ONOS;
+* `src/main/p4`: contains code to compile fabric.p4 for Tofino.
+
+To learn more about pipeconfs and how ONOS supports P4-programmable devices:
+<https://github.com/opennetworkinglab/ngsdn-tutorial>
+
+### 1 - Obtain fabric.p4 sources from ONOS
+
+`fabric.p4` is distributed as part of ONOS. We recommend using the
+`onos-2.2` branch, which is an LTS branch.
+
+```bash
+git clone -b onos-2.2 https://github.com/opennetworkinglab/onos
+```
+
+Set the `ONOS_ROOT` env variable to the location where ONOS was cloned:
+
+```bash
+export ONOS_ROOT=$PWD/onos
+```
+
+### 2 - Build Tofino-enabled fabric pipeconf
+
+To build `fabric.p4` using the Barefoot compiler and to create the pipeconf
+`.oar` package:
+
+```bash
+cd fabric-tofino # this repo
+make build PROFILES=all
+```
+
+#### Fabric profiles
+
+The above command will build the `fabric.p4` profiles specified in the
+`PROFILES` argument. Possible values are:
+
+| Profile name            | Description                                        |
+| ------------------------|----------------------------------------------------|
+| `fabric`                | Basic profile                                      |
+| `fabric-bng`            | With BNG user plane support                        |
+| `fabric-spgw`           | With SPGW user plane support                       |
+| `fabric-int`            | With INT (spec v0.5) source and transit            |
+| `fabric-spgw-int`       | WITH SPGW and INT support                          |
+
+Check the `Makefile` for other profiles.
+
+To build all profiles: `PROFILES=all`.
+
+To build a subset of the available profiles: `PROFILES="fabric fabric-bng"`
+
+The P4 compiler outputs to include in the `.oar` package (such as `tofino.bin`,
+`context.json`, and `p4info.txt`) will be placed under
+`src/main/resources/p4c-out`.
+
+When done, the pipeconf `.oar` package can be found in
+`target/fabric-tofino-<VERSION>.oar`
+
+#### Using containerized version of the Barefoot SDE / p4c compilers
+
+The previous command expects the `bf-p4c` compiler to be installed locally. As an
+alternative, the build script supports using a Docker-based distribution of the
+Barefoot SDE / p4c compilers. To do so, simply set the `SDE_DOCKER_IMG`
+make argument (or environment variable) to a Docker image that can be downloaded
+via `docker pull`, for example:
+
+```bash
+make build SDE_DOCKER_IMG=my-docker-repo/bf-sde:9.0.0 PROFILES=all
+```
+
+The build script will use `docker run` to invoke the `bf-p4c` command inside the
+given image. For this reason, the script expects a Docker image that has the
+whole Barefoot SDE installed in it or just the p4c package. In both cases, the
+`bf-p4c` executable should be on `PATH`. We do not provide such image, but one
+can be easily generated by executing the SDE install instructions inside a
+Dockerfile.
+
+## Steps to use the Tofino-enabled fabric pipeconf with ONOS
+
+### 1 - Get and run ONOS
+
+The minimum required ONOS version that works with this pipeconf is 2.2.1.
+
+You can either build from sources (using the `onos-2.2` or `master` branch), or
+run one the released versions:
+<https://wiki.onosproject.org/display/ONOS/Downloads>
+
+Pre-built ONOS Docker images are available here:
+<https://hub.docker.com/r/onosproject/onos/tags>
+
+For more information on how to get and run ONOS:
+<https://wiki.onosproject.org/display/ONOS/Guides>
+
+### 2 - Start Stratum on your switch
+
+For instructions on how to install and run Stratum on Tofino-enabled switches:
+<https://github.com/stratum/stratum/tree/master/stratum/hal/bin/barefoot>
+
+### 3 - Install pipeconf app in ONOS
+
+To install the pipeconf app built in the previous step, assuming ONOS is
+running on the local machine:
+
+```bash
+make pipeconf-install ONOS_HOST=localhost
+```
+
+Use the `ONOS_HOST` argument to specify the hostname/IP address of the machine
+where ONOS is running.
+
+This command is a wrapper to a `curl` command that uses the ONOS REST API to
+upload and activate the `.oar` package previously built.
+
+You should see the ONOS log updating with messages notifying the registration of
+new Tofino-specific pipeconfs in the system, depending on the `fabric.p4`
+profiles compiled before and the Barefoot SDE/p4c version used:
+
+```
+New pipeconf registered: org.opencord.fabric.tofino.mavericks_sde_9_0_0 (fingerprint=...)
+New pipeconf registered: org.opencord.fabric.tofino.montara_sde_9_0_0 (fingerprint=...)
+New pipeconf registered: org.opencord.fabric-bng.tofino.mavericks_sde_9_0_0 (fingerprint=...)
+New pipeconf registered: org.opencord.fabric-bng.tofino.montara_sde_9_0_0 (fingerprint=...)
+...
+```
+
+**NOTE: it might take up to one minute for the pipeconfs to be registered.
+This is currently a bug and will be fixed soon.**
+
+To check all pipeconfs registered in the system, use the ONOS CLI:
+
+```
+onos> pipeconfs
+```
+
+### 4 - Connect ONOS to a Stratum switch
+
+Activate the Barefoot drivers in ONOS:
+
+```
+onos> app activate org.onosproject.drivers.barefoot
+```
+
+This command will register a new driver named `stratum-tofino`. As the name
+suggests, this driver allows ONOS to control Tofino-enabled Stratum switches.
+
+For ONOS to be able to discover your switch, you need to push a JSON file,
+usually referred to as the "netcfg" file. We provide an example of such
+`tofino-netcfg.json` file in this repository. Make sure to modify the following
+values:
+
+* `managementAddress` is expected to contain a valid URI with host and port of
+  the Stratum gRPC server running on the switch;
+* The `device_id` URI query parameter is the P4Runtime-internal `device_id`,
+  also known as the Stratum "Node ID". Usually, you can leave this value set to
+  `1`;
+* Use the `pipeconf` field to specify which pipeconf/fabric profile to deploy on
+  the switch.
+
+Push the `tofino-netcfg.json` to ONOS using the command:
+
+```
+make netcfg ONOS_HOST=localhost
+```
+
+Like before, this command is a wrapper to a `curl` command that uses the ONOS
+REST API to push the `tofino-netcfg.json` file.
+
+Check the ONOS log for potential errors.
+
+## Using Trellis with Stratum+Tofino switches
+
+Check the official Trellis documentation here:
+<https://docs.trellisfabric.org>
+
+In the "Device Configuration" section:
+<https://docs.trellisfabric.org/configuration/device-config.html>
+
+make sure to replace the `basic` JSON node for OpenFlow devices with the one
+provided in `tofino-netcfg.json`, for example:
+
+```json
+{
+  "devices" : {
+    "device:leaf-1" : {
+      "segmentrouting" : {
+        "ipv4NodeSid" : 101,
+        "ipv4Loopback" : "192.168.0.201",
+        "ipv6NodeSid" : 111,
+        "ipv6Loopback" : "2000::c0a8:0201",
+        "routerMac" : "00:00:00:00:02:01",
+        "isEdgeRouter" : true,
+        "adjacencySids" : []
+      },
+      "basic": {
+        "managementAddress": "grpc://10.0.0.1:28000?device_id=1",
+        "driver": "stratum-tofino",
+        "pipeconf": "org.opencord.fabric.tofino.montara_sde_9_0_0"
+      }
+    }
+  }
+}
+```
+
+## Support
+
+To report issues when compiling `fabric.p4` for Tofino (i.e., compiler errors),
+please contact Intel/Barefoot support.
+
+To get help with ONOS and the fabric pipeconf, please contact
+<brigade-p4@onosproject.org> (this is a public mailing list, please beware of
+not discussing information under Intel/Barefoot NDA)
+
+[stratum]: https://github.com/stratum/stratum
+[trellis]: https://www.opennetworking.org/trellis
+[fabric.p4]: https://github.com/opennetworkinglab/onos/tree/master/pipelines/fabric/impl/src/main/resources
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..d377ec6
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2019 Open Networking Foundation
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.onosproject</groupId>
+        <artifactId>onos-dependencies</artifactId>
+        <version>2.2.1-b3</version>
+    </parent>
+
+    <groupId>org.opencord</groupId>
+    <artifactId>fabric-tofino</artifactId>
+    <version>2.2.1-SNAPSHOT</version>
+    <packaging>bundle</packaging>
+
+    <description>Pipeconf to use Trellis with Tofino-based targets</description>
+    <url>http://www.opencord.org</url>
+
+    <properties>
+        <onos.app.name>org.opencord.fabric-tofino</onos.app.name>
+        <onos.app.title>Tofino-enabled Fabric Pipeconf</onos.app.title>
+        <onos.app.origin>http://www.opencord.org</onos.app.origin>
+        <onos.app.category>Pipeline</onos.app.category>
+        <onos.app.url>http://www.opencord.org</onos.app.url>
+        <onos.app.readme>
+            Provides pipeconfs based on fabric.p4 to use Trellis with Barefoot
+            Tofino-based switches.
+        </onos.app.readme>
+        <onos.app.requires>
+            org.onosproject.pipelines.fabric
+        </onos.app.requires>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-api</artifactId>
+            <version>${onos.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onlab-osgi</artifactId>
+            <version>${onos.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-pipelines-fabric-api</artifactId>
+            <version>${onos.version}</version>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.onosproject</groupId>
+                <artifactId>onos-maven-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/src/main/java/org/opencord/fabric/tofino/PipeconfLoader.java b/src/main/java/org/opencord/fabric/tofino/PipeconfLoader.java
new file mode 100644
index 0000000..f6b60e9
--- /dev/null
+++ b/src/main/java/org/opencord/fabric/tofino/PipeconfLoader.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.opencord.fabric.tofino;
+
+import org.onosproject.core.CoreService;
+import org.onosproject.net.pi.model.DefaultPiPipeconf;
+import org.onosproject.net.pi.model.PiPipeconf;
+import org.onosproject.net.pi.model.PiPipeconf.ExtensionType;
+import org.onosproject.net.pi.model.PiPipeconfId;
+import org.onosproject.net.pi.service.PiPipeconfService;
+import org.onosproject.pipelines.fabric.FabricPipeconfService;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.wiring.BundleWiring;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferenceCardinality;
+import org.slf4j.Logger;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.net.URL;
+import java.util.Collection;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+import static java.lang.String.format;
+import static org.osgi.framework.wiring.BundleWiring.LISTRESOURCES_RECURSE;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Component responsible of registering Tofino-specific versions
+ * of the fabric pipeconf at app activation.
+ */
+@Component(immediate = true)
+public class PipeconfLoader {
+
+    private static final String APP_NAME = "org.opencord.fabric-tofino";
+
+    private static Logger log = getLogger(PipeconfLoader.class);
+
+    private static final String BASE_PIPECONF_ID = "org.opencord";
+    private static final String P4C_OUT_PATH = "/p4c-out";
+    // p4c-out/<profile>/<platform>
+    private static final String P4C_RES_BASE_PATH = P4C_OUT_PATH + "/%s/%s/%s/";
+    private static final String SEP = File.separator;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY)
+    private PiPipeconfService pipeconfService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY)
+    private FabricPipeconfService fabricPipeconfService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY)
+    private CoreService coreService;
+
+    private Collection<PiPipeconf> pipeconfs;
+
+    private static final String TOFINO = "tofino";
+    private static final String P4INFO_TXT = "p4info.txt";
+    private static final String CPU_PORT_TXT = "cpu_port.txt";
+    private static final String TOFINO_BIN = "pipe/tofino.bin";
+    private static final String TOFINO_CTX_JSON = "pipe/context.json";
+
+
+    @Activate
+    public void activate() {
+        coreService.registerApplication(APP_NAME);
+        // Registers all pipeconf at component activation.
+        pipeconfs = buildAllPipeconfs();
+        pipeconfs.forEach(pipeconfService::register);
+        log.info("Started");
+    }
+
+    @Deactivate
+    public void deactivate() {
+        pipeconfs.stream()
+                .map(PiPipeconf::id)
+                .forEach(pipeconfService::unregister);
+        pipeconfs = null;
+        log.info("Stopped");
+    }
+
+    private Collection<PiPipeconf> buildAllPipeconfs() {
+        return FrameworkUtil
+                .getBundle(this.getClass())
+                .adapt(BundleWiring.class)
+                // List all resource files in /p4c-out
+                .listResources(P4C_OUT_PATH, "*", LISTRESOURCES_RECURSE)
+                .stream()
+                // Filter only directories
+                .filter(name -> name.endsWith(SEP))
+                // Derive profile, target, and platform and build pipeconf.
+                .map(this::buildPipeconfFromPath)
+                .filter(Objects::nonNull)
+                .collect(Collectors.toList());
+    }
+
+    private PiPipeconf buildPipeconfFromPath(String path) {
+        String[] pieces = path.split(SEP);
+        // We expect a path of 4 elements, e.g.
+        // p4c-out/<profile>/<target>/<platform>
+        if (pieces.length != 4) {
+            return null;
+        }
+        String profile = pieces[1];
+        String target = pieces[2];
+        String platform = pieces[3];
+
+        if (TOFINO.equals(target)) {
+            try {
+                return tofinoPipeconf(profile, platform);
+            } catch (FileNotFoundException e) {
+                log.warn("Unable to build pipeconf at {} because file is missing: {}",
+                        path, e.getMessage());
+                return null;
+            }
+        }
+
+        log.warn("Unknown target '{}', skipping pipeconf build at '{}'...",
+                target, path);
+        return null;
+    }
+
+    private PiPipeconf tofinoPipeconf(String profile, String platform)
+            throws FileNotFoundException {
+        final URL tofinoBinUrl = this.getClass().getResource(format(
+                P4C_RES_BASE_PATH + TOFINO_BIN, profile, TOFINO, platform));
+        final URL contextJsonUrl = this.getClass().getResource(format(
+                P4C_RES_BASE_PATH + TOFINO_CTX_JSON, profile, TOFINO, platform));
+        final URL p4InfoUrl = this.getClass().getResource(format(
+                P4C_RES_BASE_PATH + P4INFO_TXT, profile, TOFINO, platform));
+        final URL cpuPortUrl = this.getClass().getResource(format(
+                P4C_RES_BASE_PATH + CPU_PORT_TXT, profile, TOFINO, platform));
+
+        checkFileExists(tofinoBinUrl, TOFINO_BIN);
+        checkFileExists(contextJsonUrl, TOFINO_CTX_JSON);
+        checkFileExists(p4InfoUrl, P4INFO_TXT);
+        checkFileExists(cpuPortUrl, CPU_PORT_TXT);
+
+        final DefaultPiPipeconf.Builder builder = DefaultPiPipeconf.builder()
+                .withId(new PiPipeconfId(format(
+                        "%s.%s.tofino.%s", BASE_PIPECONF_ID, profile, platform)))
+                .addExtension(ExtensionType.TOFINO_BIN, tofinoBinUrl)
+                .addExtension(ExtensionType.TOFINO_CONTEXT_JSON, contextJsonUrl);
+
+        return fabricPipeconfService.buildFabricPipeconf(
+                builder, profile, p4InfoUrl, cpuPortUrl);
+    }
+
+    private void checkFileExists(URL url, String name)
+            throws FileNotFoundException {
+        if (url == null) {
+            throw new FileNotFoundException(name);
+        }
+    }
+}
diff --git a/src/main/java/org/opencord/fabric/tofino/package-info.java b/src/main/java/org/opencord/fabric/tofino/package-info.java
new file mode 100644
index 0000000..2e69823
--- /dev/null
+++ b/src/main/java/org/opencord/fabric/tofino/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Fabric-tofino pipeconf loader app.
+ */
+package org.opencord.fabric.tofino;
\ No newline at end of file
diff --git a/src/main/p4/fabric-tofino.p4 b/src/main/p4/fabric-tofino.p4
new file mode 100755
index 0000000..7b81449
--- /dev/null
+++ b/src/main/p4/fabric-tofino.p4
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _PKT_OUT_HDR_ANNOT @not_extracted_in_egress
+
+#define _BOOL bit<1>
+#define _TRUE 1w1
+#define _FALSE 1w0
+
+#ifdef WITH_INT_TRANSIT
+#define _PRE_INGRESS fabric_metadata.int_meta.ig_tstamp = (bit<32>) standard_metadata.ingress_global_timestamp;
+#define _PRE_EGRESS fabric_metadata.int_meta.eg_tstamp = (bit<32>) standard_metadata.egress_global_timestamp;
+#endif // WITH_INT_TRANSIT
+
+#define _INT_INIT_METADATA \
+    hdr.int_switch_id.switch_id = switch_id;\
+    hdr.int_port_ids.ingress_port_id = (bit<16>) smeta.ingress_port;\
+    hdr.int_port_ids.egress_port_id = (bit<16>) smeta.egress_port;\
+    hdr.int_ingress_tstamp.ingress_tstamp = fmeta.int_meta.ig_tstamp;\
+    hdr.int_egress_tstamp.egress_tstamp = fmeta.int_meta.eg_tstamp;\
+    hdr.int_hop_latency.hop_latency = (bit<32>) smeta.egress_global_timestamp - (bit<32>) smeta.ingress_global_timestamp;\
+    hdr.int_q_occupancy.q_id = 8w0;\
+    hdr.int_q_occupancy.q_occupancy = (bit<24>) smeta.deq_qdepth;\
+    hdr.int_q_congestion.q_id = 8w0;\
+    hdr.int_q_congestion.q_congestion = 24w0;\
+    hdr.int_egress_tx_util.egress_port_tx_util = 32w0;\
+
+#define _INT_METADATA_ACTIONS \
+    action int_set_header_0() { hdr.int_switch_id.setValid(); }\
+    action int_set_header_1() { hdr.int_port_ids.setValid(); }\
+    action int_set_header_2() { hdr.int_hop_latency.setValid(); }\
+    action int_set_header_3() { hdr.int_q_occupancy.setValid(); }\
+    action int_set_header_4() { hdr.int_ingress_tstamp.setValid(); }\
+    action int_set_header_5() { hdr.int_egress_tstamp.setValid(); }\
+    action int_set_header_6() { hdr.int_q_congestion.setValid(); }\
+    action int_set_header_7() { hdr.int_egress_tx_util.setValid(); }\
+
+#define __TABLE_SIZE__
+#define BNG_MAX_SUBSC 1024
+#define BNG_MAX_NET_PER_SUBSC 4
+#define BNG_MAX_SUBSC_NET BNG_MAX_NET_PER_SUBSC * BNG_MAX_SUBSC
+#ifdef WITH_BNG
+    #define PORT_VLAN_TABLE_SIZE BNG_MAX_SUBSC + 2048
+#else
+    #define PORT_VLAN_TABLE_SIZE 2048
+#endif // WITH_BNG
+#define FWD_CLASSIFIER_TABLE_SIZE 128
+#define BRIDGING_TABLE_SIZE 2048
+#define MPLS_TABLE_SIZE 2048
+#ifdef WITH_BNG
+    #define ROUTING_V4_TABLE_SIZE BNG_MAX_SUBSC_NET + 1024
+#else
+    #define ROUTING_V4_TABLE_SIZE 30000
+#endif // WITH_BNG
+#define ACL_TABLE_SIZE 2048
+// Depends on number of unique next_id expected
+#define NEXT_VLAN_TABLE_SIZE 2048
+#define XCONNECT_NEXT_TABLE_SIZE 4096
+#define SIMPLE_NEXT_TABLE_SIZE 2048
+#define HASHED_NEXT_TABLE_SIZE 2048
+// Max size of ECMP groups
+#define HASHED_SELECTOR_MAX_GROUP_SIZE 16
+// Ideally HASHED_NEXT_TABLE_SIZE * HASHED_SELECTOR_MAX_GROUP_SIZE
+#define HASHED_ACT_PROFILE_SIZE 32w32768
+#define MULTICAST_NEXT_TABLE_SIZE 2048
+#define EGRESS_VLAN_TABLE_SIZE 2048
+
+#define _ROUTING_V4_TABLE_ANNOT @alpm(1)
+
+#include "fabric.p4"
diff --git a/src/main/p4/tofino-compile.sh b/src/main/p4/tofino-compile.sh
new file mode 100755
index 0000000..cab4c0c
--- /dev/null
+++ b/src/main/p4/tofino-compile.sh
@@ -0,0 +1,82 @@
+#!/usr/bin/env bash
+# Copyright 2019-present Open Networking Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+MAVERICKS_CPU_PORT=320
+MONTARA_CPU_PORT=192
+
+if [ -z "$ONOS_ROOT" ]; then
+  echo "Error: ONOS_ROOT is not set"
+  exit 1
+fi
+
+P4_SRC_DIR=${ONOS_ROOT}/pipelines/fabric/impl/src/main/resources
+
+if [ ! -d "${P4_SRC_DIR}" ]; then
+  echo "Error: unable to locate fabric P4 sources at ${P4_SRC_DIR}"
+fi
+
+set -e
+
+PROFILE=$1
+OTHER_PP_FLAGS=$2
+
+# PWD is the directory where this script is called from (should be the root of
+# this repo).
+P4C_OUT=${PWD}/p4c-out/${PROFILE}
+
+# DIR is this file directory.
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+
+# Where the compiler output should be placed to be included in the pipeconf.
+DEST_DIR=${DIR}/../resources/p4c-out/${PROFILE}/tofino
+
+# If SDE_DOCKER_IMG env is set, use containerized version of the compiler
+if [ -z "${SDE_DOCKER_IMG}" ]; then
+  P4C_CMD="bf-p4c"
+else
+  P4C_CMD="docker run --rm -v ${P4C_OUT}:${P4C_OUT} -v ${P4_SRC_DIR}:${P4_SRC_DIR} -v ${DIR}:${DIR} -w ${DIR} ${SDE_DOCKER_IMG} bf-p4c"
+fi
+
+SDE_VER=$( ${P4C_CMD} --version | cut -d' ' -f2 )
+
+# shellcheck disable=SC2086
+function do_p4c() {
+  pltf="$1_sde_${SDE_VER//./_}"
+  cpu_port=$2
+  echo "*** Compiling profile '${PROFILE}' for ${pltf} platform..."
+  echo "*** Output in ${P4C_OUT}/${pltf}"
+  pp_flags="-DCPU_PORT=${cpu_port}"
+  mkdir -p ${P4C_OUT}/${pltf}
+  (
+    set -x
+    $P4C_CMD --arch v1model -g \
+      -o ${P4C_OUT}/${pltf} -I ${P4_SRC_DIR} \
+      ${pp_flags} ${OTHER_PP_FLAGS} \
+      --p4runtime-files ${P4C_OUT}/${pltf}/p4info.txt \
+      ${DIR}/fabric-tofino.p4
+  )
+
+  # Copy only the relevant files to the pipeconf resources
+  mkdir -p ${DEST_DIR}/${pltf}/pipe
+  cp ${P4C_OUT}/${pltf}/p4info.txt ${DEST_DIR}/${pltf}
+  cp ${P4C_OUT}/${pltf}/pipe/context.json ${DEST_DIR}/${pltf}/pipe
+  cp ${P4C_OUT}/${pltf}/pipe/tofino.bin ${DEST_DIR}/${pltf}/pipe
+  echo "${cpu_port}" > ${DEST_DIR}/${pltf}/cpu_port.txt
+
+  echo
+}
+
+do_p4c "mavericks" ${MAVERICKS_CPU_PORT}
+do_p4c "montara" ${MONTARA_CPU_PORT}
diff --git a/tofino-netcfg.json b/tofino-netcfg.json
new file mode 100644
index 0000000..b521fdb
--- /dev/null
+++ b/tofino-netcfg.json
@@ -0,0 +1,11 @@
+{
+  "devices": {
+    "device:my-tofino-switch": {
+      "basic": {
+        "managementAddress": "grpc://10.0.0.1:28000?device_id=1",
+        "driver": "stratum-tofino",
+        "pipeconf": "org.opencord.fabric.tofino.montara_sde_9_0_0"
+      }
+    }
+  }
+}
\ No newline at end of file