Skip to content
Snippets Groups Projects
Commit 49a7e404 authored by Lluis Gifre Renom's avatar Lluis Gifre Renom
Browse files

Merge branch 'netx22-p4' into 'develop'

NetworkX 22 P4 workshop

See merge request !7
parents 85e0820d 86cfe709
No related branches found
No related tags found
2 merge requests!54Release 2.0.0,!7NetworkX 22 P4 workshop
Showing
with 1799 additions and 0 deletions
# Network X 22 Demo - P4 driver, Basic connectivity functionality
This functional test shows the P4 driver with a basic connectivity test between 2 hosts connected to a single P4 switch, using the TeraFlow Cloud-native SDN Controller.
## Functional test folder
This functional test can be found in folder `src/tests/netx22-p4/`.
## P4 source and Mininet topology
This test is designed to operate with a mininet deployment that contains 2 hosts and a BMv2 switch, such a topology can be found in the 'src/tests/netx22-p4/mininet' folder.
Additionally the P4 source code, along with its compiled artifacts are present in the 'src/tests/netx22-p4/mininet' folder.
## Deployment and Dependencies
To run this functional test, it is assumed you have deployed a MicroK8s-based Kubernetes environment and a TeraFlowSDN
controller instance as described in the [Tutorial: Deployment Guide](./1-0-deployment.md), and you configured the Python
environment as described in
[Tutorial: Run Experiments Guide > 2.1. Configure Python Environment](./2-1-python-environment.md).
Remember to source the scenario settings appropriately, e.g., `cd ~/tfs-ctrl && source my_deploy.sh` in each terminal
you open.
Additionally mininet should be installed, we suggest using the mininet packaged in the [Next-Gen SDN Tutorial][https://github.com/opennetworkinglab/ngsdn-tutorial], as it provides an easy way to deploy mininet dockerized and comes with the BMv2Stratum software switch.
## Test Execution
### Mininet
To execute this functional test, first make sure that mininet is running the correct topology.
If you have used the Next-Gen SDN Tutorial for it, you may add the topology provided in the mininet folder of the ngsdn tutorial and add the following make rule to its Makefile
```
start-simple: NGSDN_TOPO_PY := topo-simple.py
start-simple: _start
```
After that run
```
make start-simple
make mn-cli
```
You will be prompted with the mininet cli. Run the following and let it run until the end of the experiment
```
client ping server
```
### Teraflow
In another terminal cd to the teraflow directory and run the following
```
src/tests/netx22-p4/setup.sh
```
This will copy the p4 artifacts to the device pod.
Then you can bootstrap the device to the Teraflow Controller
```
src/tests/netx22-p4/run_test_01_bootstrap.sh
```
Install the required rules to the p4 switch
```
src/tests/netx22-p4/run_test_02_create_service.sh
```
You should now check the mininet terminal. The two hosts should be pinging each other as intended.
You can remove the rules from the p4 switch
```
src/tests/netx22-p4/run_test_03_delete_service.sh
```
The two hosts on the mininet terminal, should stop pinging.
And remove the device from the Teraflow Controller
```
src/tests/netx22-p4/run_test_04_cleanup.sh
```
# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/)
#
# 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.
# Set the URL of your local Docker registry where the images will be uploaded to.
export TFS_REGISTRY_IMAGE="http://localhost:32000/tfs/"
# Set the list of components, separated by spaces, you want to build images for, and deploy.
export TFS_COMPONENTS="context device automation service compute monitoring webui"
# Set the tag you want to use for your images.
export TFS_IMAGE_TAG="dev"
# Set the name of the Kubernetes namespace to deploy to.
export TFS_K8S_NAMESPACE="tfs"
# Set additional manifest files to be applied after the deployment
export TFS_EXTRA_MANIFESTS="manifests/nginx_ingress_http.yaml"
# Set the neew Grafana admin password
export TFS_GRAFANA_PASSWORD="admin123+"
#!/usr/bin/python
# 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.
import argparse
from mininet.cli import CLI
from mininet.log import setLogLevel
from mininet.net import Mininet
from mininet.node import Host
from mininet.topo import Topo
from stratum import StratumBmv2Switch
CPU_PORT = 255
class IPv4Host(Host):
"""Host that can be configured with an IPv4 gateway (default route).
"""
def config(self, mac=None, ip=None, defaultRoute=None, lo='up', gw=None,
**_params):
super(IPv4Host, self).config(mac, ip, defaultRoute, lo, **_params)
self.cmd('arp -s 192.168.1.1 11:22:33:44:55:77')
self.cmd('ip -4 addr flush dev %s' % self.defaultIntf())
self.cmd('ip -6 addr flush dev %s' % self.defaultIntf())
self.cmd('ip -4 link set up %s' % self.defaultIntf())
self.cmd('ip -4 addr add %s dev %s' % (ip, self.defaultIntf()))
if gw:
self.cmd('ip -4 route add default via %s' % gw)
# Disable offload
for attr in ["rx", "tx", "sg"]:
cmd = "/sbin/ethtool --offload %s %s off" % (
self.defaultIntf(), attr)
self.cmd(cmd)
def updateIP():
return ip.split('/')[0]
self.defaultIntf().updateIP = updateIP
class TutorialTopo(Topo):
"""Basic Server-Client topology with IPv4 hosts"""
def __init__(self, *args, **kwargs):
Topo.__init__(self, *args, **kwargs)
# Spines
# gRPC port 50001
switch1 = self.addSwitch('switch1', cls=StratumBmv2Switch, cpuport=CPU_PORT)
# IPv4 hosts attached to switch 1
client = self.addHost('client', cls=IPv4Host, mac="aa:bb:cc:dd:ee:11",
ip='10.0.0.1/24', gw='10.0.0.100')
server = self.addHost('server', cls=IPv4Host, mac="aa:bb:cc:dd:ee:22",
ip='10.0.0.2/24', gw='10.0.0.100')
self.addLink(client, switch1) # port 1
self.addLink(server, switch1) # port 2
def main():
net = Mininet(topo=TutorialTopo(), controller=None)
net.start()
client = net.hosts[0]
server = net.hosts[1]
client.setARP('10.0.0.2', 'aa:bb:cc:dd:ee:22')
server.setARP('10.0.0.1', 'aa:bb:cc:dd:ee:11')
CLI(net)
net.stop()
print '#' * 80
print 'ATTENTION: Mininet was stopped! Perhaps accidentally?'
print 'No worries, it will restart automatically in a few seconds...'
print 'To access again the Mininet CLI, use `make mn-cli`'
print 'To detach from the CLI (without stopping), press Ctrl-D'
print 'To permanently quit Mininet, use `make stop`'
print '#' * 80
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description='Mininet topology script for 2x2 fabric with stratum_bmv2 and IPv4 hosts')
args = parser.parse_args()
setLogLevel('info')
main()
{
"header_types" : [
{
"name" : "scalars_0",
"id" : 0,
"fields" : [
["tmp", 1, false],
["local_metadata_t.is_multicast", 1, false],
["_padding_0", 6, false]
]
},
{
"name" : "standard_metadata",
"id" : 1,
"fields" : [
["ingress_port", 9, false],
["egress_spec", 9, false],
["egress_port", 9, false],
["clone_spec", 32, false],
["instance_type", 32, false],
["drop", 1, false],
["recirculate_port", 16, false],
["packet_length", 32, false],
["enq_timestamp", 32, false],
["enq_qdepth", 19, false],
["deq_timedelta", 32, false],
["deq_qdepth", 19, false],
["ingress_global_timestamp", 48, false],
["egress_global_timestamp", 48, false],
["lf_field_list", 32, false],
["mcast_grp", 16, false],
["resubmit_flag", 32, false],
["egress_rid", 16, false],
["recirculate_flag", 32, false],
["checksum_error", 1, false],
["parser_error", 32, false],
["priority", 3, false],
["_padding", 2, false]
]
},
{
"name" : "ethernet_t",
"id" : 2,
"fields" : [
["dst_addr", 48, false],
["src_addr", 48, false],
["ether_type", 16, false]
]
}
],
"headers" : [
{
"name" : "scalars",
"id" : 0,
"header_type" : "scalars_0",
"metadata" : true,
"pi_omit" : true
},
{
"name" : "standard_metadata",
"id" : 1,
"header_type" : "standard_metadata",
"metadata" : true,
"pi_omit" : true
},
{
"name" : "ethernet",
"id" : 2,
"header_type" : "ethernet_t",
"metadata" : false,
"pi_omit" : true
}
],
"header_stacks" : [],
"header_union_types" : [],
"header_unions" : [],
"header_union_stacks" : [],
"field_lists" : [],
"errors" : [
["NoError", 1],
["PacketTooShort", 2],
["NoMatch", 3],
["StackOutOfBounds", 4],
["HeaderTooShort", 5],
["ParserTimeout", 6],
["ParserInvalidArgument", 7]
],
"enums" : [],
"parsers" : [
{
"name" : "parser",
"id" : 0,
"init_state" : "start",
"parse_states" : [
{
"name" : "start",
"id" : 0,
"parser_ops" : [
{
"parameters" : [
{
"type" : "regular",
"value" : "ethernet"
}
],
"op" : "extract"
}
],
"transitions" : [
{
"value" : "default",
"mask" : null,
"next_state" : null
}
],
"transition_key" : []
}
]
}
],
"parse_vsets" : [],
"deparsers" : [
{
"name" : "deparser",
"id" : 0,
"source_info" : {
"filename" : "p4src/main.p4",
"line" : 148,
"column" : 8,
"source_fragment" : "DeparserImpl"
},
"order" : ["ethernet"]
}
],
"meter_arrays" : [],
"counter_arrays" : [],
"register_arrays" : [],
"calculations" : [],
"learn_lists" : [],
"actions" : [
{
"name" : "IngressPipeImpl.drop",
"id" : 0,
"runtime_data" : [],
"primitives" : [
{
"op" : "mark_to_drop",
"parameters" : [
{
"type" : "header",
"value" : "standard_metadata"
}
],
"source_info" : {
"filename" : "p4src/main.p4",
"line" : 77,
"column" : 8,
"source_fragment" : "mark_to_drop(standard_metadata)"
}
}
]
},
{
"name" : "IngressPipeImpl.drop",
"id" : 1,
"runtime_data" : [],
"primitives" : [
{
"op" : "mark_to_drop",
"parameters" : [
{
"type" : "header",
"value" : "standard_metadata"
}
],
"source_info" : {
"filename" : "p4src/main.p4",
"line" : 77,
"column" : 8,
"source_fragment" : "mark_to_drop(standard_metadata)"
}
}
]
},
{
"name" : "IngressPipeImpl.set_egress_port",
"id" : 2,
"runtime_data" : [
{
"name" : "port_num",
"bitwidth" : 9
}
],
"primitives" : [
{
"op" : "assign",
"parameters" : [
{
"type" : "field",
"value" : ["standard_metadata", "egress_spec"]
},
{
"type" : "runtime_data",
"value" : 0
}
],
"source_info" : {
"filename" : "p4src/main.p4",
"line" : 81,
"column" : 8,
"source_fragment" : "standard_metadata.egress_spec = port_num"
}
}
]
},
{
"name" : "IngressPipeImpl.set_egress_port",
"id" : 3,
"runtime_data" : [
{
"name" : "port_num",
"bitwidth" : 9
}
],
"primitives" : [
{
"op" : "assign",
"parameters" : [
{
"type" : "field",
"value" : ["standard_metadata", "egress_spec"]
},
{
"type" : "runtime_data",
"value" : 0
}
],
"source_info" : {
"filename" : "p4src/main.p4",
"line" : 81,
"column" : 8,
"source_fragment" : "standard_metadata.egress_spec = port_num"
}
}
]
},
{
"name" : "IngressPipeImpl.set_multicast_group",
"id" : 4,
"runtime_data" : [
{
"name" : "gid",
"bitwidth" : 16
}
],
"primitives" : [
{
"op" : "assign",
"parameters" : [
{
"type" : "field",
"value" : ["standard_metadata", "mcast_grp"]
},
{
"type" : "runtime_data",
"value" : 0
}
],
"source_info" : {
"filename" : "p4src/main.p4",
"line" : 89,
"column" : 8,
"source_fragment" : "standard_metadata.mcast_grp = gid"
}
},
{
"op" : "assign",
"parameters" : [
{
"type" : "field",
"value" : ["scalars", "local_metadata_t.is_multicast"]
},
{
"type" : "expression",
"value" : {
"type" : "expression",
"value" : {
"op" : "b2d",
"left" : null,
"right" : {
"type" : "bool",
"value" : true
}
}
}
}
],
"source_info" : {
"filename" : "p4src/main.p4",
"line" : 90,
"column" : 8,
"source_fragment" : "local_metadata.is_multicast = true"
}
}
]
},
{
"name" : "IngressPipeImpl.set_multicast_group",
"id" : 5,
"runtime_data" : [
{
"name" : "gid",
"bitwidth" : 16
}
],
"primitives" : [
{
"op" : "assign",
"parameters" : [
{
"type" : "field",
"value" : ["standard_metadata", "mcast_grp"]
},
{
"type" : "runtime_data",
"value" : 0
}
],
"source_info" : {
"filename" : "p4src/main.p4",
"line" : 89,
"column" : 8,
"source_fragment" : "standard_metadata.mcast_grp = gid"
}
},
{
"op" : "assign",
"parameters" : [
{
"type" : "field",
"value" : ["scalars", "local_metadata_t.is_multicast"]
},
{
"type" : "expression",
"value" : {
"type" : "expression",
"value" : {
"op" : "b2d",
"left" : null,
"right" : {
"type" : "bool",
"value" : true
}
}
}
}
],
"source_info" : {
"filename" : "p4src/main.p4",
"line" : 90,
"column" : 8,
"source_fragment" : "local_metadata.is_multicast = true"
}
}
]
},
{
"name" : "act",
"id" : 6,
"runtime_data" : [],
"primitives" : [
{
"op" : "assign",
"parameters" : [
{
"type" : "field",
"value" : ["scalars", "tmp"]
},
{
"type" : "expression",
"value" : {
"type" : "expression",
"value" : {
"op" : "b2d",
"left" : null,
"right" : {
"type" : "bool",
"value" : true
}
}
}
}
]
}
]
},
{
"name" : "act_0",
"id" : 7,
"runtime_data" : [],
"primitives" : [
{
"op" : "assign",
"parameters" : [
{
"type" : "field",
"value" : ["scalars", "tmp"]
},
{
"type" : "expression",
"value" : {
"type" : "expression",
"value" : {
"op" : "b2d",
"left" : null,
"right" : {
"type" : "bool",
"value" : false
}
}
}
}
]
}
]
}
],
"pipelines" : [
{
"name" : "ingress",
"id" : 0,
"source_info" : {
"filename" : "p4src/main.p4",
"line" : 71,
"column" : 8,
"source_fragment" : "IngressPipeImpl"
},
"init_table" : "IngressPipeImpl.l2_exact_table",
"tables" : [
{
"name" : "IngressPipeImpl.l2_exact_table",
"id" : 0,
"source_info" : {
"filename" : "p4src/main.p4",
"line" : 95,
"column" : 10,
"source_fragment" : "l2_exact_table"
},
"key" : [
{
"match_type" : "exact",
"name" : "hdr.ethernet.dst_addr",
"target" : ["ethernet", "dst_addr"],
"mask" : null
}
],
"match_type" : "exact",
"type" : "simple",
"max_size" : 1024,
"with_counters" : false,
"support_timeout" : false,
"direct_meters" : null,
"action_ids" : [2, 4, 0],
"actions" : ["IngressPipeImpl.set_egress_port", "IngressPipeImpl.set_multicast_group", "IngressPipeImpl.drop"],
"base_default_next" : null,
"next_tables" : {
"__HIT__" : "tbl_act",
"__MISS__" : "tbl_act_0"
},
"default_entry" : {
"action_id" : 0,
"action_const" : true,
"action_data" : [],
"action_entry_const" : true
}
},
{
"name" : "tbl_act",
"id" : 1,
"key" : [],
"match_type" : "exact",
"type" : "simple",
"max_size" : 1024,
"with_counters" : false,
"support_timeout" : false,
"direct_meters" : null,
"action_ids" : [6],
"actions" : ["act"],
"base_default_next" : "node_5",
"next_tables" : {
"act" : "node_5"
},
"default_entry" : {
"action_id" : 6,
"action_const" : true,
"action_data" : [],
"action_entry_const" : true
}
},
{
"name" : "tbl_act_0",
"id" : 2,
"key" : [],
"match_type" : "exact",
"type" : "simple",
"max_size" : 1024,
"with_counters" : false,
"support_timeout" : false,
"direct_meters" : null,
"action_ids" : [7],
"actions" : ["act_0"],
"base_default_next" : "node_5",
"next_tables" : {
"act_0" : "node_5"
},
"default_entry" : {
"action_id" : 7,
"action_const" : true,
"action_data" : [],
"action_entry_const" : true
}
},
{
"name" : "IngressPipeImpl.l2_ternary_table",
"id" : 3,
"source_info" : {
"filename" : "p4src/main.p4",
"line" : 109,
"column" : 10,
"source_fragment" : "l2_ternary_table"
},
"key" : [
{
"match_type" : "ternary",
"name" : "hdr.ethernet.dst_addr",
"target" : ["ethernet", "dst_addr"],
"mask" : null
}
],
"match_type" : "ternary",
"type" : "simple",
"max_size" : 1024,
"with_counters" : false,
"support_timeout" : false,
"direct_meters" : null,
"action_ids" : [3, 5, 1],
"actions" : ["IngressPipeImpl.set_egress_port", "IngressPipeImpl.set_multicast_group", "IngressPipeImpl.drop"],
"base_default_next" : null,
"next_tables" : {
"IngressPipeImpl.set_egress_port" : null,
"IngressPipeImpl.set_multicast_group" : null,
"IngressPipeImpl.drop" : null
},
"default_entry" : {
"action_id" : 1,
"action_const" : true,
"action_data" : [],
"action_entry_const" : true
}
}
],
"action_profiles" : [],
"conditionals" : [
{
"name" : "node_5",
"id" : 0,
"source_info" : {
"filename" : "p4src/main.p4",
"line" : 122,
"column" : 12,
"source_fragment" : "!l2_exact_table.apply().hit"
},
"expression" : {
"type" : "expression",
"value" : {
"op" : "not",
"left" : null,
"right" : {
"type" : "expression",
"value" : {
"op" : "d2b",
"left" : null,
"right" : {
"type" : "field",
"value" : ["scalars", "tmp"]
}
}
}
}
},
"false_next" : null,
"true_next" : "IngressPipeImpl.l2_ternary_table"
}
]
},
{
"name" : "egress",
"id" : 1,
"source_info" : {
"filename" : "p4src/main.p4",
"line" : 134,
"column" : 8,
"source_fragment" : "EgressPipeImpl"
},
"init_table" : null,
"tables" : [],
"action_profiles" : [],
"conditionals" : []
}
],
"checksums" : [],
"force_arith" : [],
"extern_instances" : [],
"field_aliases" : [
[
"queueing_metadata.enq_timestamp",
["standard_metadata", "enq_timestamp"]
],
[
"queueing_metadata.enq_qdepth",
["standard_metadata", "enq_qdepth"]
],
[
"queueing_metadata.deq_timedelta",
["standard_metadata", "deq_timedelta"]
],
[
"queueing_metadata.deq_qdepth",
["standard_metadata", "deq_qdepth"]
],
[
"intrinsic_metadata.ingress_global_timestamp",
["standard_metadata", "ingress_global_timestamp"]
],
[
"intrinsic_metadata.egress_global_timestamp",
["standard_metadata", "egress_global_timestamp"]
],
[
"intrinsic_metadata.lf_field_list",
["standard_metadata", "lf_field_list"]
],
[
"intrinsic_metadata.mcast_grp",
["standard_metadata", "mcast_grp"]
],
[
"intrinsic_metadata.resubmit_flag",
["standard_metadata", "resubmit_flag"]
],
[
"intrinsic_metadata.egress_rid",
["standard_metadata", "egress_rid"]
],
[
"intrinsic_metadata.recirculate_flag",
["standard_metadata", "recirculate_flag"]
],
[
"intrinsic_metadata.priority",
["standard_metadata", "priority"]
]
],
"program" : "p4src/main.p4",
"__meta__" : {
"version" : [2, 18],
"compiler" : "https://github.com/p4lang/p4c"
}
}
\ No newline at end of file
/*
* 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.
*/
#include <core.p4>
#include <v1model.p4>
typedef bit<9> port_num_t;
typedef bit<48> mac_addr_t;
typedef bit<16> mcast_group_id_t;
//------------------------------------------------------------------------------
// HEADER DEFINITIONS
//------------------------------------------------------------------------------
header ethernet_t {
mac_addr_t dst_addr;
mac_addr_t src_addr;
bit<16> ether_type;
}
struct parsed_headers_t {
ethernet_t ethernet;
}
struct local_metadata_t {
bool is_multicast;
}
//------------------------------------------------------------------------------
// INGRESS PIPELINE
//------------------------------------------------------------------------------
parser ParserImpl (packet_in packet,
out parsed_headers_t hdr,
inout local_metadata_t local_metadata,
inout standard_metadata_t standard_metadata)
{
state start {
transition parse_ethernet;
}
state parse_ethernet {
packet.extract(hdr.ethernet);
transition accept;
}
}
control VerifyChecksumImpl(inout parsed_headers_t hdr,
inout local_metadata_t meta)
{
apply { /* EMPTY */ }
}
control IngressPipeImpl (inout parsed_headers_t hdr,
inout local_metadata_t local_metadata,
inout standard_metadata_t standard_metadata) {
// Drop action shared by many tables.
action drop() {
mark_to_drop(standard_metadata);
}
action set_egress_port(port_num_t port_num) {
standard_metadata.egress_spec = port_num;
}
action set_multicast_group(mcast_group_id_t gid) {
// gid will be used by the Packet Replication Engine (PRE) in the
// Traffic Manager--located right after the ingress pipeline, to
// replicate a packet to multiple egress ports, specified by the control
// plane by means of P4Runtime MulticastGroupEntry messages.
standard_metadata.mcast_grp = gid;
local_metadata.is_multicast = true;
}
// --- l2_exact_table ------------------
table l2_exact_table {
key = {
hdr.ethernet.dst_addr: exact;
}
actions = {
set_egress_port;
set_multicast_group;
@defaultonly drop;
}
const default_action = drop;
}
// --- l2_ternary_table ------------------
table l2_ternary_table {
key = {
hdr.ethernet.dst_addr: ternary;
}
actions = {
set_egress_port;
set_multicast_group;
@defaultonly drop;
}
const default_action = drop;
}
apply {
if (!l2_exact_table.apply().hit) {
// ...if an entry is NOT found, apply the ternary one in case
// this is a multicast/broadcast NDP NS packet.
l2_ternary_table.apply();
}
}
}
//------------------------------------------------------------------------------
// EGRESS PIPELINE
//------------------------------------------------------------------------------
control EgressPipeImpl (inout parsed_headers_t hdr,
inout local_metadata_t local_metadata,
inout standard_metadata_t standard_metadata) {
apply { /* EMPTY */ }
}
control ComputeChecksumImpl(inout parsed_headers_t hdr,
inout local_metadata_t local_metadata)
{
apply { /* EMPTY */ }
}
control DeparserImpl(packet_out packet, in parsed_headers_t hdr) {
apply {
packet.emit(hdr.ethernet);
}
}
V1Switch(
ParserImpl(),
VerifyChecksumImpl(),
IngressPipeImpl(),
EgressPipeImpl(),
ComputeChecksumImpl(),
DeparserImpl()
) main;
pkg_info {
arch: "v1model"
}
tables {
preamble {
id: 33605373
name: "IngressPipeImpl.l2_exact_table"
alias: "l2_exact_table"
}
match_fields {
id: 1
name: "hdr.ethernet.dst_addr"
bitwidth: 48
match_type: EXACT
}
action_refs {
id: 16812802
}
action_refs {
id: 16841371
}
action_refs {
id: 16796182
annotations: "@defaultonly"
scope: DEFAULT_ONLY
}
const_default_action_id: 16796182
size: 1024
}
tables {
preamble {
id: 33573501
name: "IngressPipeImpl.l2_ternary_table"
alias: "l2_ternary_table"
}
match_fields {
id: 1
name: "hdr.ethernet.dst_addr"
bitwidth: 48
match_type: TERNARY
}
action_refs {
id: 16812802
}
action_refs {
id: 16841371
}
action_refs {
id: 16796182
annotations: "@defaultonly"
scope: DEFAULT_ONLY
}
const_default_action_id: 16796182
size: 1024
}
actions {
preamble {
id: 16796182
name: "IngressPipeImpl.drop"
alias: "drop"
}
}
actions {
preamble {
id: 16812802
name: "IngressPipeImpl.set_egress_port"
alias: "set_egress_port"
}
params {
id: 1
name: "port_num"
bitwidth: 9
}
}
actions {
preamble {
id: 16841371
name: "IngressPipeImpl.set_multicast_group"
alias: "set_multicast_group"
}
params {
id: 1
name: "gid"
bitwidth: 16
}
}
type_info {
}
#!/bin/bash
# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/)
#
# 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.
# make sure to source the following scripts:
# - my_deploy.sh
# - tfs_runtime_env_vars.sh
source tfs_runtime_env_vars.sh
python -m pytest --verbose src/tests/netx22-p4/tests/test_functional_bootstrap.py
#!/bin/bash
# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/)
#
# 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.
source tfs_runtime_env_vars.sh
python -m pytest --verbose src/tests/netx22-p4/tests/test_functional_create_service.py
#!/bin/bash
# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/)
#
# 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.
source tfs_runtime_env_vars.sh
python -m pytest --verbose src/tests/netx22-p4/tests/test_functional_delete_service.py
#!/bin/bash
# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/)
#
# 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.
source tfs_runtime_env_vars.sh
python -m pytest --verbose src/tests/netx22-p4/tests/test_functional_cleanup.py
#! /bin/bash
export POD_NAME=$(kubectl get pods -n=tfs | grep device | awk '{print $1}')
kubectl exec ${POD_NAME} -n=tfs -- mkdir /root/p4
kubectl cp src/tests/netx22-p4/p4/p4info.txt tfs/${POD_NAME}:/root/p4
kubectl cp src/tests/netx22-p4/p4/bmv2.json tfs/${POD_NAME}:/root/p4
# Add here your files containing confidential testbed details such as IP addresses, ports, usernames, passwords, etc.
Credentials.py
# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/)
#
# 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.
import copy, json, sys
from .Objects import CONTEXTS, DEVICES, LINKS, TOPOLOGIES
def main():
with open('tests/ofc22/descriptors_emulated.json', 'w', encoding='UTF-8') as f:
devices = []
for device,connect_rules in DEVICES:
device = copy.deepcopy(device)
device['device_config']['config_rules'].extend(connect_rules)
devices.append(device)
f.write(json.dumps({
'contexts': CONTEXTS,
'topologies': TOPOLOGIES,
'devices': devices,
'links': LINKS
}))
return 0
if __name__ == '__main__':
sys.exit(main())
# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/)
#
# 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.
import json, logging, sys
from common.Settings import get_setting
from context.client.ContextClient import ContextClient
from common.proto.context_pb2 import Context, Device, Link, Topology
from device.client.DeviceClient import DeviceClient
LOGGER = logging.getLogger(__name__)
LOGGER.setLevel(logging.DEBUG)
def main():
context_client = ContextClient(
get_setting('CONTEXTSERVICE_SERVICE_HOST'), get_setting('CONTEXTSERVICE_SERVICE_PORT_GRPC'))
device_client = DeviceClient(
get_setting('DEVICESERVICE_SERVICE_HOST'), get_setting('DEVICESERVICE_SERVICE_PORT_GRPC'))
with open('tests/ofc22/descriptors.json', 'r', encoding='UTF-8') as f:
descriptors = json.loads(f.read())
for context in descriptors['contexts' ]: context_client.SetContext (Context (**context ))
for topology in descriptors['topologies']: context_client.SetTopology(Topology(**topology))
for device in descriptors['devices' ]: device_client .AddDevice (Device (**device ))
for link in descriptors['links' ]: context_client.SetLink (Link (**link ))
return 0
if __name__ == '__main__':
sys.exit(main())
# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/)
# 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.
import os
from typing import Dict, List, Tuple
from common.Constants import DEFAULT_CONTEXT_UUID, DEFAULT_TOPOLOGY_UUID
from common.tools.object_factory.Context import json_context, json_context_id
from common.tools.object_factory.Device import (
json_device_connect_rules, json_device_emulated_connect_rules, json_device_emulated_packet_router_disabled,
json_device_connect_rules, json_device_id, json_device_p4_disabled,
json_device_emulated_tapi_disabled, json_device_id, json_device_packetrouter_disabled, json_device_tapi_disabled)
from common.tools.object_factory.ConfigRule import (
json_config_rule_set, json_config_rule_delete)
from common.tools.object_factory.EndPoint import json_endpoint, json_endpoint_id
from common.tools.object_factory.Link import json_link, json_link_id
from common.tools.object_factory.Topology import json_topology, json_topology_id
from common.proto.kpi_sample_types_pb2 import KpiSampleType
# ----- Context --------------------------------------------------------------------------------------------------------
CONTEXT_ID = json_context_id(DEFAULT_CONTEXT_UUID)
CONTEXT = json_context(DEFAULT_CONTEXT_UUID)
# ----- Topology -------------------------------------------------------------------------------------------------------
TOPOLOGY_ID = json_topology_id(DEFAULT_TOPOLOGY_UUID, context_id=CONTEXT_ID)
TOPOLOGY = json_topology(DEFAULT_TOPOLOGY_UUID, context_id=CONTEXT_ID)
# ----- Monitoring Samples ---------------------------------------------------------------------------------------------
PACKET_PORT_SAMPLE_TYPES = [
KpiSampleType.KPISAMPLETYPE_PACKETS_TRANSMITTED,
KpiSampleType.KPISAMPLETYPE_PACKETS_RECEIVED,
KpiSampleType.KPISAMPLETYPE_BYTES_TRANSMITTED,
KpiSampleType.KPISAMPLETYPE_BYTES_RECEIVED,
]
# ----- Devices --------------------------------------------------------------------------------------------------------
CUR_PATH = os.path.dirname(os.path.abspath(__file__))
DEVICE_SW1_UUID = 'SW1'
DEVICE_SW1_TIMEOUT = 60
DEVICE_SW1_ID = json_device_id(DEVICE_SW1_UUID)
DEVICE_SW1 = json_device_p4_disabled(DEVICE_SW1_UUID)
DEVICE_SW1_DPID = 1
DEVICE_SW1_NAME = DEVICE_SW1_UUID
DEVICE_SW1_IP_ADDR = '10.0.2.10'
DEVICE_SW1_PORT = '50001'
DEVICE_SW1_VENDOR = 'Open Networking Foundation'
DEVICE_SW1_HW_VER = 'BMv2 simple_switch'
DEVICE_SW1_SW_VER = 'Stratum'
DEVICE_SW1_BIN_PATH = '/root/p4/bmv2.json'
DEVICE_SW1_INFO_PATH = '/root/p4/p4info.txt'
DEVICE_SW1_CONNECT_RULES = json_device_connect_rules(
DEVICE_SW1_IP_ADDR,
DEVICE_SW1_PORT,
{
'id': DEVICE_SW1_DPID,
'name': DEVICE_SW1_NAME,
'vendor': DEVICE_SW1_VENDOR,
'hw_ver': DEVICE_SW1_HW_VER,
'sw_ver': DEVICE_SW1_SW_VER,
'timeout': DEVICE_SW1_TIMEOUT,
'p4bin': DEVICE_SW1_BIN_PATH,
'p4info': DEVICE_SW1_INFO_PATH
}
)
################################## TABLE ENTRIES ##################################
DEVICE_SW1_CONFIG_TABLE_ENTRIES = [
json_config_rule_set(
'table',
{
'table-name': 'IngressPipeImpl.l2_exact_table',
'match-fields': [
{
'match-field': 'hdr.ethernet.dst_addr',
'match-value': 'aa:bb:cc:dd:ee:11'
}
],
'action-name': 'IngressPipeImpl.set_egress_port',
'action-params': [
{
'action-param': 'port_num',
'action-value': '1'
}
]
}
),
json_config_rule_set(
'table',
{
'table-name': 'IngressPipeImpl.l2_exact_table',
'match-fields': [
{
'match-field': 'hdr.ethernet.dst_addr',
'match-value': 'aa:bb:cc:dd:ee:22'
}
],
'action-name': 'IngressPipeImpl.set_egress_port',
'action-params': [
{
'action-param': 'port_num',
'action-value': '2'
}
]
}
)
]
"""
DEVICE_SW1_CONFIG_TABLE_ENTRIES = [
json_config_rule_set(
'table',
{
'table-name': 'IngressPipeImpl.l2_ternary_table',
'match-fields': [
{
'match-field': 'hdr.ethernet.dst_addr',
'match-value': 'aa:bb:cc:dd:ee:11 &&& ff:ff:ff:ff:ff:ff'
}
],
'action-name': 'IngressPipeImpl.set_egress_port',
'action-params': [
{
'action-param': 'port_num',
'action-value': '1'
}
],
'priority': 1
}
),
json_config_rule_set(
'table',
{
'table-name': 'IngressPipeImpl.l2_ternary_table',
'match-fields': [
{
'match-field': 'hdr.ethernet.dst_addr',
'match-value': 'aa:bb:cc:dd:ee:22 &&& ff:ff:ff:ff:ff:ff'
}
],
'action-name': 'IngressPipeImpl.set_egress_port',
'action-params': [
{
'action-param': 'port_num',
'action-value': '2'
}
],
'priority': 1
}
),
]
"""
################################## TABLE DECONF ##################################
DEVICE_SW1_DECONF_TABLE_ENTRIES = [
json_config_rule_delete(
'table',
{
'table-name': 'IngressPipeImpl.l2_exact_table',
'match-fields': [
{
'match-field': 'hdr.ethernet.dst_addr',
'match-value': 'aa:bb:cc:dd:ee:11'
}
],
'action-name': 'IngressPipeImpl.set_egress_port',
'action-params': [
{
'action-param': 'port_num',
'action-value': '1'
}
]
}
),
json_config_rule_delete(
'table',
{
'table-name': 'IngressPipeImpl.l2_exact_table',
'match-fields': [
{
'match-field': 'hdr.ethernet.dst_addr',
'match-value': 'aa:bb:cc:dd:ee:22'
}
],
'action-name': 'IngressPipeImpl.set_egress_port',
'action-params': [
{
'action-param': 'port_num',
'action-value': '2'
}
]
}
)
]
"""
DEVICE_SW1_DECONF_TABLE_ENTRIES = [
json_config_rule_delete(
'table',
{
'table-name': 'IngressPipeImpl.l2_ternary_table',
'match-fields': [
{
'match-field': 'hdr.ethernet.dst_addr',
'match-value': 'aa:bb:cc:dd:ee:11 &&& ff:ff:ff:ff:ff:ff'
}
],
'action-name': 'IngressPipeImpl.set_egress_port',
'action-params': [
{
'action-param': 'port_num',
'action-value': '1'
}
],
'priority': 1
}
),
json_config_rule_delete(
'table',
{
'table-name': 'IngressPipeImpl.l2_ternary_table',
'match-fields': [
{
'match-field': 'hdr.ethernet.dst_addr',
'match-value': 'aa:bb:cc:dd:ee:22 &&& ff:ff:ff:ff:ff:ff'
}
],
'action-name': 'IngressPipeImpl.set_egress_port',
'action-params': [
{
'action-param': 'port_num',
'action-value': '2'
}
],
'priority': 1
}
),
]
"""
# ----- Links ----------------------------------------------------------------------------------------------------------
# ----- WIM Service Settings -------------------------------------------------------------------------------------------
# ----- Object Collections ---------------------------------------------------------------------------------------------
CONTEXTS = [CONTEXT]
TOPOLOGIES = [TOPOLOGY]
DEVICES = [
(DEVICE_SW1, DEVICE_SW1_CONNECT_RULES, DEVICE_SW1_CONFIG_TABLE_ENTRIES, DEVICE_SW1_DECONF_TABLE_ENTRIES),
]
LINKS = []
# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/)
#
# 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.
# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/)
#
# 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.
import copy, logging, pytest
from common.Settings import get_setting
from common.tests.EventTools import EVENT_CREATE, EVENT_UPDATE, check_events
from common.tools.object_factory.Context import json_context_id
from common.tools.object_factory.Device import json_device_id
from common.tools.object_factory.Link import json_link_id
from common.tools.object_factory.Topology import json_topology_id
from context.client.ContextClient import ContextClient
from context.client.EventsCollector import EventsCollector
from common.proto.context_pb2 import ConfigActionEnum, Context, ContextId, Device, Empty, Link, Topology, DeviceOperationalStatusEnum
from device.client.DeviceClient import DeviceClient
from .Objects import CONTEXT_ID, CONTEXTS, DEVICES, LINKS, TOPOLOGIES
LOGGER = logging.getLogger(__name__)
LOGGER.setLevel(logging.DEBUG)
@pytest.fixture(scope='session')
def context_client():
_client = ContextClient(get_setting('CONTEXTSERVICE_SERVICE_HOST'), get_setting('CONTEXTSERVICE_SERVICE_PORT_GRPC'))
yield _client
_client.close()
@pytest.fixture(scope='session')
def device_client():
_client = DeviceClient(get_setting('DEVICESERVICE_SERVICE_HOST'), get_setting('DEVICESERVICE_SERVICE_PORT_GRPC'))
yield _client
_client.close()
def test_prepare_scenario(context_client : ContextClient): # pylint: disable=redefined-outer-name
# ----- Create Contexts and Topologies -----------------------------------------------------------------------------
for context in CONTEXTS:
context_uuid = context['context_id']['context_uuid']['uuid']
LOGGER.info('Adding Context {:s}'.format(context_uuid))
response = context_client.SetContext(Context(**context))
assert response.context_uuid.uuid == context_uuid
for topology in TOPOLOGIES:
context_uuid = topology['topology_id']['context_id']['context_uuid']['uuid']
topology_uuid = topology['topology_id']['topology_uuid']['uuid']
LOGGER.info('Adding Topology {:s}/{:s}'.format(context_uuid, topology_uuid))
response = context_client.SetTopology(Topology(**topology))
assert response.context_id.context_uuid.uuid == context_uuid
assert response.topology_uuid.uuid == topology_uuid
context_id = json_context_id(context_uuid)
def test_scenario_ready(context_client : ContextClient): # pylint: disable=redefined-outer-name
# ----- List entities - Ensure scenario is ready -------------------------------------------------------------------
response = context_client.ListContexts(Empty())
assert len(response.contexts) == len(CONTEXTS)
response = context_client.ListTopologies(ContextId(**CONTEXT_ID))
assert len(response.topologies) == len(TOPOLOGIES)
response = context_client.ListDevices(Empty())
assert len(response.devices) == 0
def test_devices_bootstraping(
context_client : ContextClient, device_client : DeviceClient): # pylint: disable=redefined-outer-name
# ----- Create Devices ---------------------------------------------------------------
for device, connect_rules, config_rules, _ in DEVICES:
device_uuid = device['device_id']['device_uuid']['uuid']
LOGGER.info('Adding Device {:s}'.format(device_uuid))
device_p4_with_connect_rules = copy.deepcopy(device)
device_p4_with_connect_rules['device_config']['config_rules'].extend(connect_rules)
response = device_client.AddDevice(Device(**device_p4_with_connect_rules))
assert response.device_uuid.uuid == device_uuid
def test_devices_bootstrapped(context_client : ContextClient): # pylint: disable=redefined-outer-name
# ----- List entities - Ensure bevices are created -----------------------------------------------------------------
response = context_client.ListContexts(Empty())
assert len(response.contexts) == len(CONTEXTS)
response = context_client.ListTopologies(ContextId(**CONTEXT_ID))
assert len(response.topologies) == len(TOPOLOGIES)
response = context_client.ListDevices(Empty())
assert len(response.devices) == len(DEVICES)
# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/)
#
# 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.
import copy, logging, pytest
from common.Settings import get_setting
from common.tests.EventTools import EVENT_REMOVE, check_events
from common.tools.object_factory.Context import json_context_id
from common.tools.object_factory.Device import json_device_id
from common.tools.object_factory.Link import json_link_id
from common.tools.object_factory.Topology import json_topology_id
from context.client.ContextClient import ContextClient
from context.client.EventsCollector import EventsCollector
from common.proto.context_pb2 import ConfigActionEnum, ContextId, Device, DeviceId, Empty, LinkId, TopologyId, DeviceOperationalStatusEnum
from device.client.DeviceClient import DeviceClient
from .Objects import CONTEXT_ID, CONTEXTS, DEVICES, LINKS, TOPOLOGIES
LOGGER = logging.getLogger(__name__)
LOGGER.setLevel(logging.DEBUG)
@pytest.fixture(scope='session')
def context_client():
_client = ContextClient(get_setting('CONTEXTSERVICE_SERVICE_HOST'), get_setting('CONTEXTSERVICE_SERVICE_PORT_GRPC'))
yield _client
_client.close()
@pytest.fixture(scope='session')
def device_client():
_client = DeviceClient(get_setting('DEVICESERVICE_SERVICE_HOST'), get_setting('DEVICESERVICE_SERVICE_PORT_GRPC'))
yield _client
_client.close()
def test_scenario_cleanup(
context_client : ContextClient, device_client : DeviceClient): # pylint: disable=redefined-outer-name
# ----- Delete Devices and Validate Collected Events ---------------------------------------------------------------
for device, _, _, deconf_rules in DEVICES:
device_id = device['device_id']
device_uuid = device_id['device_uuid']['uuid']
LOGGER.info('Deleting Device {:s}'.format(device_uuid))
device_client.DeleteDevice(DeviceId(**device_id))
#expected_events.append(('DeviceEvent', EVENT_REMOVE, json_device_id(device_uuid)))
response = context_client.ListDevices(Empty())
assert len(response.devices) == 0
# ----- Delete Topologies and Validate Collected Events ------------------------------------------------------------
for topology in TOPOLOGIES:
topology_id = topology['topology_id']
context_uuid = topology_id['context_id']['context_uuid']['uuid']
topology_uuid = topology_id['topology_uuid']['uuid']
LOGGER.info('Deleting Topology {:s}/{:s}'.format(context_uuid, topology_uuid))
context_client.RemoveTopology(TopologyId(**topology_id))
context_id = json_context_id(context_uuid)
#expected_events.append(('TopologyEvent', EVENT_REMOVE, json_topology_id(topology_uuid, context_id=context_id)))
# ----- Delete Contexts and Validate Collected Events --------------------------------------------------------------
for context in CONTEXTS:
context_id = context['context_id']
context_uuid = context_id['context_uuid']['uuid']
LOGGER.info('Deleting Context {:s}'.format(context_uuid))
context_client.RemoveContext(ContextId(**context_id))
#expected_events.append(('ContextEvent', EVENT_REMOVE, json_context_id(context_uuid)))
# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/)
#
# 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.
import copy, logging, pytest
from common.Settings import get_setting
from common.tests.EventTools import EVENT_CREATE, EVENT_UPDATE, check_events
from common.tools.object_factory.Context import json_context_id
from common.tools.object_factory.Device import json_device_id
from common.tools.object_factory.Link import json_link_id
from common.tools.object_factory.Topology import json_topology_id
from context.client.ContextClient import ContextClient
from context.client.EventsCollector import EventsCollector
from common.proto.context_pb2 import Context, ContextId, Device, Empty, Link, Topology
from device.client.DeviceClient import DeviceClient
from .Objects import CONTEXT_ID, CONTEXTS, DEVICES, LINKS, TOPOLOGIES
from common.proto.context_pb2 import ConfigActionEnum, Device, DeviceId,\
DeviceOperationalStatusEnum
LOGGER = logging.getLogger(__name__)
LOGGER.setLevel(logging.DEBUG)
@pytest.fixture(scope='session')
def context_client():
_client = ContextClient(get_setting('CONTEXTSERVICE_SERVICE_HOST'), get_setting('CONTEXTSERVICE_SERVICE_PORT_GRPC'))
yield _client
_client.close()
@pytest.fixture(scope='session')
def device_client():
_client = DeviceClient(get_setting('DEVICESERVICE_SERVICE_HOST'), get_setting('DEVICESERVICE_SERVICE_PORT_GRPC'))
yield _client
_client.close()
def test_rules_entry(
context_client : ContextClient, device_client : DeviceClient): # pylint: disable=redefined-outer-name
# ----- Create Devices ---------------------------------------------------------------
for device, connect_rules, config_rules, _ in DEVICES:
# Enable device
device_p4_with_operational_status = copy.deepcopy(device)
device_p4_with_operational_status['device_operational_status'] = \
DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED
device_client.ConfigureDevice(Device(**device_p4_with_operational_status))
device_data = context_client.GetDevice(DeviceId(**json_device_id('SW1')))
# Insert table entries
device_p4_with_config_rules = copy.deepcopy(device)
device_p4_with_config_rules['device_config']['config_rules'].extend(config_rules)
device_client.ConfigureDevice(Device(**device_p4_with_config_rules))
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment