org.onosproject.drivers.barefoot.TofinoPipelineProgrammable.java Source code

Java tutorial

Introduction

Here is the source code for org.onosproject.drivers.barefoot.TofinoPipelineProgrammable.java

Source

/*
 * Copyright 2017-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.onosproject.drivers.barefoot;

import com.google.common.collect.Lists;
import org.apache.commons.io.IOUtils;
import org.onosproject.drivers.p4runtime.AbstractP4RuntimePipelineProgrammable;
import org.onosproject.net.behaviour.PiPipelineProgrammable;
import org.onosproject.net.pi.model.PiPipeconf;
import org.onosproject.net.pi.model.PiPipeconf.ExtensionType;

import java.io.IOException;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Optional;

import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType.TOFINO_BIN;
import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType.TOFINO_CONTEXT_JSON;

/**
 * Implementation of the PiPipelineProgrammable behaviour for a Tofino-based switch.
 */
public class TofinoPipelineProgrammable extends AbstractP4RuntimePipelineProgrammable
        implements PiPipelineProgrammable {

    @Override
    public Optional<PiPipeconf> getDefaultPipeconf() {
        return Optional.empty();
    }

    @Override
    public ByteBuffer createDeviceDataBuffer(PiPipeconf pipeconf) {

        List<ByteBuffer> buffers = Lists.newLinkedList();
        try {
            buffers.add(nameBuffer(pipeconf));
            buffers.add(extensionBuffer(pipeconf, TOFINO_BIN));
            buffers.add(extensionBuffer(pipeconf, TOFINO_CONTEXT_JSON));
        } catch (ExtensionException e) {
            return null;
        }

        // Concatenate buffers (flip so they can be read).
        int len = buffers.stream().mapToInt(Buffer::limit).sum();
        ByteBuffer deviceData = ByteBuffer.allocate(len);
        buffers.forEach(b -> deviceData.put((ByteBuffer) b.flip()));
        deviceData.flip();

        return deviceData.asReadOnlyBuffer();
    }

    private ByteBuffer nameBuffer(PiPipeconf pipeconf) {
        // Length of the name + name.
        String name = pipeconf.id().toString();
        return ByteBuffer.allocate(Integer.BYTES + name.length()).order(ByteOrder.LITTLE_ENDIAN)
                .putInt(name.length()).put(name.getBytes(StandardCharsets.UTF_8));
    }

    private ByteBuffer extensionBuffer(PiPipeconf pipeconf, ExtensionType extType) {
        if (!pipeconf.extension(extType).isPresent()) {
            log.warn("Missing extension {} in pipeconf {}", extType, pipeconf.id());
            throw new ExtensionException();
        }
        try {
            byte[] bytes = IOUtils.toByteArray(pipeconf.extension(extType).get());
            // Length of the extension + bytes.
            return ByteBuffer.allocate(Integer.BYTES + bytes.length).order(ByteOrder.LITTLE_ENDIAN)
                    .putInt(bytes.length).put(bytes);
        } catch (IOException ex) {
            log.warn("Unable to read extension {} from pipeconf {}: {}", extType, pipeconf.id(), ex.getMessage());
            throw new ExtensionException();
        }
    }

    private static class ExtensionException extends IllegalArgumentException {
    }
}