Hello @SteffenLindner,
I have seen those tutorials before but I as far as I can tell they help u push your compiled P4 program, insert/delete entries to/from the tables in a simple_switch_grpc, but they dont help you parse packet_in messages. I have tested that part and it is working fine(pushing entries to tables/.json files), however, what I am trying to do is to parse the packet_in messages sent by the P4runtime(simple_switch_grpc), for instance, I have a P4 program that is sending packet_in messages to the grpc client(controller) every time a packet does not match with an entry in one of its tables. My P4 program is offloading all those packets to the CPU port 510 and in turn the P4runtime is sending those packets for the controller, however, I need to parse those packets/messages sent by the P4runtime on the controller side, and here is when I am having problems, because I am not sure how to do it(BTW, sniffing on the controller side I can see that the P4runtime is sending those packet_in messages to the controller and I am receiving them in the controller host, but I dont know how to parse them).
This is my code on the controller side, basically pushes the compiled P4 program to the simple_switch_grpc and then tries to listen for packet_in messages to parse them:
import sys
import grpc
import struct
from p4.v1 import p4runtime_pb2_grpc, p4runtime_pb2
import p4runtime_sh.shell as sh
import signal
class PacketInOutTest:
CPU_PORT = 510
def __init__(self, grpc_addr, p4info_file, bmv2_json_file):
class PacketInOutTest:
CPU_PORT = 510
def __init__(self, grpc_addr, p4info_file, bmv2_json_file):
# Setup with p4runtime_sh
self.sh = sh.setup(
device_id=0,
grpc_addr=grpc_addr,
election_id=(1, 0), # Election ID is required for P4Runtime to grant control
config=sh.FwdPipeConfig(p4info_file, bmv2_json_file)
)
# Now, establish a gRPC channel for packet-in handling with keepalive parameters
self.channel = grpc.insecure_channel(grpc_addr, options=[
('grpc.keepalive_time_ms', 30000),
('grpc.keepalive_timeout_ms', 10000),
('grpc.keepalive_permit_without_calls', True),
('grpc.http2.max_pings_without_data', 0),
('grpc.http2.min_time_between_pings_ms', 10000),
])
self.stub = p4runtime_pb2_grpc.P4RuntimeStub(self.channel)
def on_connectivity_change(self, state):
print(f"Channel state changed: {state}")
def listen_for_packet_in(self):
print("Listening for packet-in messages...")
self.channel.subscribe(self.on_connectivity_change, try_to_connect=True)
def request_iterator():
yield p4runtime_pb2.StreamMessageRequest()
stream = self.stub.StreamChannel(request_iterator())
try:
for response in stream:
if response.WhichOneof('update') == 'packet':
print(f"Packet-in received with payload: {packet.payload.hex()}")
return True # Packet-in message received
except grpc.RpcError as e:
print(f"RPC error occurred: {e.code()} - {e.details()}")
return False # No Packet-in message received or an error occurred
def tearDown(self):
print("Shutting down gracefully...")
sh.teardown()
self.channel.close()
def signal_handler(sig, frame):
print('Interrupt received, shutting down...')
global test
test.tearDown()
sys.exit(0)
if __name__ == '__main__':
signal.signal(signal.SIGINT, signal_handler)
test = PacketInOutTest(grpc_addr='192.168.30.149:9559', p4info_file='packetinout.p4info.txt',
bmv2_json_file='packetinout.json')
test.listen_for_packet_in()
And this is my basic P4 program that is sending all the packets to the controller(CPU port 510):
#include <core.p4>
#include <v1model.p4>
#define CPU_PORT 510
struct headers_t {
}
struct metadata_t {
}
parser parserImpl(packet_in packet,
out headers_t hdr,
inout metadata_t meta,
inout standard_metadata_t stdmeta)
{
state start {
transition accept;
}
}
control ingressImpl(inout headers_t hdr,
inout metadata_t meta,
inout standard_metadata_t stdmeta)
{
apply {
// Send all traffic to CPU port
stdmeta.egress_spec = CPU_PORT;
}
}
control egressImpl(inout headers_t hdr,
inout metadata_t meta,
inout standard_metadata_t stdmeta)
{
apply {
// No processing required on egress
}
}
control deparserImpl(packet_out packet,
in headers_t hdr)
{
apply {
}
}
control verifyChecksum(inout headers_t hdr, inout metadata_t meta) {
apply {
// Checksum verification not needed for this example
}
}
control computeChecksum(inout headers_t hdr, inout metadata_t meta) {
apply {
// Checksum computation not needed for this example
}
}
V1Switch(
parserImpl(),
verifyChecksum(),
ingressImpl(),
egressImpl(),
computeChecksum(),
deparserImpl()
) main;
By parsing the packet_in messages sent by the P4runtime I would process/analyze those packets and take actions accordinly. Id appreacite any help to accomplish my goal.
Note that when I run the python code(controller), these are the outputs, the GOAWAY messages pop out after much later than when I received the packet_in messages sent by the P4runtime, so, thats not originating the error.
root@absuarez-virtual-machine:/home/absuarez/ss_grpc_client/lab3# python3 packetinout5.py
Listening for packet-in messages...
Channel state changed: ChannelConnectivity.IDLE
Channel state changed: ChannelConnectivity.READY
E0310 04:57:59.153710151 3991 chttp2_transport.cc:1216] ipv4:192.168.30.149:9559: Received a GOAWAY with error code ENHANCE_YOUR_CALM and debug data equal to "too_many_pings". Current keepalive time (before throttling): 30000ms
Channel state changed: ChannelConnectivity.IDLE