blob: f6b60e9cbfbdfaf021676e345d3d9fd6b39a5786 [file] [log] [blame]
Carmelo Cascone97efefb2019-12-05 16:40:45 -08001/*
2 * Copyright 2019-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.opencord.fabric.tofino;
18
19import org.onosproject.core.CoreService;
20import org.onosproject.net.pi.model.DefaultPiPipeconf;
21import org.onosproject.net.pi.model.PiPipeconf;
22import org.onosproject.net.pi.model.PiPipeconf.ExtensionType;
23import org.onosproject.net.pi.model.PiPipeconfId;
24import org.onosproject.net.pi.service.PiPipeconfService;
25import org.onosproject.pipelines.fabric.FabricPipeconfService;
26import org.osgi.framework.FrameworkUtil;
27import org.osgi.framework.wiring.BundleWiring;
28import org.osgi.service.component.annotations.Activate;
29import org.osgi.service.component.annotations.Component;
30import org.osgi.service.component.annotations.Deactivate;
31import org.osgi.service.component.annotations.Reference;
32import org.osgi.service.component.annotations.ReferenceCardinality;
33import org.slf4j.Logger;
34
35import java.io.File;
36import java.io.FileNotFoundException;
37import java.net.URL;
38import java.util.Collection;
39import java.util.Objects;
40import java.util.stream.Collectors;
41
42import static java.lang.String.format;
43import static org.osgi.framework.wiring.BundleWiring.LISTRESOURCES_RECURSE;
44import static org.slf4j.LoggerFactory.getLogger;
45
46/**
47 * Component responsible of registering Tofino-specific versions
48 * of the fabric pipeconf at app activation.
49 */
50@Component(immediate = true)
51public class PipeconfLoader {
52
53 private static final String APP_NAME = "org.opencord.fabric-tofino";
54
55 private static Logger log = getLogger(PipeconfLoader.class);
56
57 private static final String BASE_PIPECONF_ID = "org.opencord";
58 private static final String P4C_OUT_PATH = "/p4c-out";
59 // p4c-out/<profile>/<platform>
60 private static final String P4C_RES_BASE_PATH = P4C_OUT_PATH + "/%s/%s/%s/";
61 private static final String SEP = File.separator;
62
63 @Reference(cardinality = ReferenceCardinality.MANDATORY)
64 private PiPipeconfService pipeconfService;
65
66 @Reference(cardinality = ReferenceCardinality.MANDATORY)
67 private FabricPipeconfService fabricPipeconfService;
68
69 @Reference(cardinality = ReferenceCardinality.MANDATORY)
70 private CoreService coreService;
71
72 private Collection<PiPipeconf> pipeconfs;
73
74 private static final String TOFINO = "tofino";
75 private static final String P4INFO_TXT = "p4info.txt";
76 private static final String CPU_PORT_TXT = "cpu_port.txt";
77 private static final String TOFINO_BIN = "pipe/tofino.bin";
78 private static final String TOFINO_CTX_JSON = "pipe/context.json";
79
80
81 @Activate
82 public void activate() {
83 coreService.registerApplication(APP_NAME);
84 // Registers all pipeconf at component activation.
85 pipeconfs = buildAllPipeconfs();
86 pipeconfs.forEach(pipeconfService::register);
87 log.info("Started");
88 }
89
90 @Deactivate
91 public void deactivate() {
92 pipeconfs.stream()
93 .map(PiPipeconf::id)
94 .forEach(pipeconfService::unregister);
95 pipeconfs = null;
96 log.info("Stopped");
97 }
98
99 private Collection<PiPipeconf> buildAllPipeconfs() {
100 return FrameworkUtil
101 .getBundle(this.getClass())
102 .adapt(BundleWiring.class)
103 // List all resource files in /p4c-out
104 .listResources(P4C_OUT_PATH, "*", LISTRESOURCES_RECURSE)
105 .stream()
106 // Filter only directories
107 .filter(name -> name.endsWith(SEP))
108 // Derive profile, target, and platform and build pipeconf.
109 .map(this::buildPipeconfFromPath)
110 .filter(Objects::nonNull)
111 .collect(Collectors.toList());
112 }
113
114 private PiPipeconf buildPipeconfFromPath(String path) {
115 String[] pieces = path.split(SEP);
116 // We expect a path of 4 elements, e.g.
117 // p4c-out/<profile>/<target>/<platform>
118 if (pieces.length != 4) {
119 return null;
120 }
121 String profile = pieces[1];
122 String target = pieces[2];
123 String platform = pieces[3];
124
125 if (TOFINO.equals(target)) {
126 try {
127 return tofinoPipeconf(profile, platform);
128 } catch (FileNotFoundException e) {
129 log.warn("Unable to build pipeconf at {} because file is missing: {}",
130 path, e.getMessage());
131 return null;
132 }
133 }
134
135 log.warn("Unknown target '{}', skipping pipeconf build at '{}'...",
136 target, path);
137 return null;
138 }
139
140 private PiPipeconf tofinoPipeconf(String profile, String platform)
141 throws FileNotFoundException {
142 final URL tofinoBinUrl = this.getClass().getResource(format(
143 P4C_RES_BASE_PATH + TOFINO_BIN, profile, TOFINO, platform));
144 final URL contextJsonUrl = this.getClass().getResource(format(
145 P4C_RES_BASE_PATH + TOFINO_CTX_JSON, profile, TOFINO, platform));
146 final URL p4InfoUrl = this.getClass().getResource(format(
147 P4C_RES_BASE_PATH + P4INFO_TXT, profile, TOFINO, platform));
148 final URL cpuPortUrl = this.getClass().getResource(format(
149 P4C_RES_BASE_PATH + CPU_PORT_TXT, profile, TOFINO, platform));
150
151 checkFileExists(tofinoBinUrl, TOFINO_BIN);
152 checkFileExists(contextJsonUrl, TOFINO_CTX_JSON);
153 checkFileExists(p4InfoUrl, P4INFO_TXT);
154 checkFileExists(cpuPortUrl, CPU_PORT_TXT);
155
156 final DefaultPiPipeconf.Builder builder = DefaultPiPipeconf.builder()
157 .withId(new PiPipeconfId(format(
158 "%s.%s.tofino.%s", BASE_PIPECONF_ID, profile, platform)))
159 .addExtension(ExtensionType.TOFINO_BIN, tofinoBinUrl)
160 .addExtension(ExtensionType.TOFINO_CONTEXT_JSON, contextJsonUrl);
161
162 return fabricPipeconfService.buildFabricPipeconf(
163 builder, profile, p4InfoUrl, cpuPortUrl);
164 }
165
166 private void checkFileExists(URL url, String name)
167 throws FileNotFoundException {
168 if (url == null) {
169 throw new FileNotFoundException(name);
170 }
171 }
172}