Updating check_switch_started in p4runtime_switch.py (#85)
The previous implementation had a race conditiona between the socket check and the BMv2 startup. Sometimes, if the check happen just before (or as) BMv2 was trying to bind the port, it would not be able to bind it. This solution uses psutil's equivalent to 'netstat' to determine whether is BMv2 has bound the port yet. Also, some minor README and comment improvements.
This commit is contained in:
parent
b2161b8a27
commit
b41473fcc0
@ -5,7 +5,7 @@
|
|||||||
In this exercise, we will be using P4 Runtime to send flow entries to the
|
In this exercise, we will be using P4 Runtime to send flow entries to the
|
||||||
switch instead of using the switch's CLI. We will be building on the same P4
|
switch instead of using the switch's CLI. We will be building on the same P4
|
||||||
program that you used in the [basic_tunnel](../basic_tunnel) exercise. The
|
program that you used in the [basic_tunnel](../basic_tunnel) exercise. The
|
||||||
P4 program has be renamed to `advanced_tunnel.py` and has been augmented
|
P4 program has been renamed to `advanced_tunnel.py` and has been augmented
|
||||||
with two counters (`ingressTunnelCounter`, `egressTunnelCounter`) and
|
with two counters (`ingressTunnelCounter`, `egressTunnelCounter`) and
|
||||||
two new actions (`myTunnel_ingress`, `myTunnel_egress`).
|
two new actions (`myTunnel_ingress`, `myTunnel_egress`).
|
||||||
|
|
||||||
@ -20,7 +20,7 @@ necessary to tunnel traffic between host 1 and 2.
|
|||||||
## Step 1: Run the (incomplete) starter code
|
## Step 1: Run the (incomplete) starter code
|
||||||
|
|
||||||
The starter code for this assignment is in a file called `mycontroller.py`,
|
The starter code for this assignment is in a file called `mycontroller.py`,
|
||||||
and it will install only some of the rules that you need tunnel traffic between
|
and it will install only some of the rules that you need to tunnel traffic between
|
||||||
two hosts.
|
two hosts.
|
||||||
|
|
||||||
Let's first compile the new P4 program, start the network, use `mycontroller.py`
|
Let's first compile the new P4 program, start the network, use `mycontroller.py`
|
||||||
|
@ -43,13 +43,19 @@ def writeTunnelRules(p4info_helper, ingress_sw, egress_sw, tunnel_id,
|
|||||||
|
|
||||||
# 2) Tunnel Transit Rule
|
# 2) Tunnel Transit Rule
|
||||||
# The rule will need to be added to the myTunnel_exact table and match on
|
# The rule will need to be added to the myTunnel_exact table and match on
|
||||||
# the tunnel ID (hdr.myTunnel.dst_id). For our simple topology, transit
|
# the tunnel ID (hdr.myTunnel.dst_id). Traffic will need to be forwarded
|
||||||
# traffic will need to be forwarded on the using the myTunnel_forward action
|
# using the myTunnel_forward action on the port connected to the next switch.
|
||||||
# on the SWITCH_TO_SWITCH_PORT (port 2).
|
|
||||||
#
|
#
|
||||||
# We will only need on transit rule on the ingress switch because we are
|
# For our simple topology, switch 1 and switch 2 are connected using a
|
||||||
|
# link attached to port 2 on both switches. We have defined a variable at
|
||||||
|
# the top of the file, SWITCH_TO_SWITCH_PORT, that you can use as the output
|
||||||
|
# port for this action.
|
||||||
|
#
|
||||||
|
# We will only need a transit rule on the ingress switch because we are
|
||||||
# using a simple topology. In general, you'll need on transit rule for
|
# using a simple topology. In general, you'll need on transit rule for
|
||||||
# each switch in the path (except the last one).
|
# each switch in the path (except the last switch, which has the egress rule),
|
||||||
|
# and you will need to select the port dynamically for each switch based on
|
||||||
|
# your topology.
|
||||||
|
|
||||||
# TODO build the transit rule
|
# TODO build the transit rule
|
||||||
# TODO install the transit rule on the ingress switch
|
# TODO install the transit rule on the ingress switch
|
||||||
|
@ -48,13 +48,20 @@ def writeTunnelRules(p4info_helper, ingress_sw, egress_sw, tunnel_id,
|
|||||||
|
|
||||||
# 2) Tunnel Transit Rule
|
# 2) Tunnel Transit Rule
|
||||||
# The rule will need to be added to the myTunnel_exact table and match on
|
# The rule will need to be added to the myTunnel_exact table and match on
|
||||||
# the tunnel ID (hdr.myTunnel.dst_id). For our simple topology, transit
|
# the tunnel ID (hdr.myTunnel.dst_id). Traffic will need to be forwarded
|
||||||
# traffic will need to be forwarded on the using the myTunnel_forward action
|
# using the myTunnel_forward action on the port connected to the next switch.
|
||||||
# on the SWITCH_TO_SWITCH_PORT (port 2).
|
|
||||||
#
|
#
|
||||||
# We will only need on transit rule on the ingress switch because we are
|
# For our simple topology, switch 1 and switch 2 are connected using a
|
||||||
|
# link attached to port 2 on both switches. We have defined a variable at
|
||||||
|
# the top of the file, SWITCH_TO_SWITCH_PORT, that you can use as the output
|
||||||
|
# port for this action.
|
||||||
|
#
|
||||||
|
# We will only need a transit rule on the ingress switch because we are
|
||||||
# using a simple topology. In general, you'll need on transit rule for
|
# using a simple topology. In general, you'll need on transit rule for
|
||||||
# each switch in the path (except the last one).
|
# each switch in the path (except the last switch, which has the egress rule),
|
||||||
|
# and you will need to select the port dynamically for each switch based on
|
||||||
|
# your topology.
|
||||||
|
|
||||||
table_entry = p4info_helper.buildTableEntry(
|
table_entry = p4info_helper.buildTableEntry(
|
||||||
table_name="myTunnel_exact",
|
table_name="myTunnel_exact",
|
||||||
match_fields={
|
match_fields={
|
||||||
|
@ -25,6 +25,14 @@ from mininet.log import info, error, debug
|
|||||||
sys.path.append('/home/vagrant/behavioral-model/mininet')
|
sys.path.append('/home/vagrant/behavioral-model/mininet')
|
||||||
from p4_mininet import P4Switch
|
from p4_mininet import P4Switch
|
||||||
|
|
||||||
|
SWITCH_START_TIMEOUT = 10 # seconds
|
||||||
|
|
||||||
|
import psutil
|
||||||
|
def check_listening_on_port(port):
|
||||||
|
for c in psutil.net_connections(kind='inet'):
|
||||||
|
if c.status == 'LISTEN' and c.laddr[1] == port:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
class P4RuntimeSwitch(P4Switch):
|
class P4RuntimeSwitch(P4Switch):
|
||||||
"BMv2 switch with gRPC support"
|
"BMv2 switch with gRPC support"
|
||||||
@ -59,6 +67,10 @@ class P4RuntimeSwitch(P4Switch):
|
|||||||
self.grpc_port = P4RuntimeSwitch.next_grpc_port
|
self.grpc_port = P4RuntimeSwitch.next_grpc_port
|
||||||
P4RuntimeSwitch.next_grpc_port += 1
|
P4RuntimeSwitch.next_grpc_port += 1
|
||||||
|
|
||||||
|
if check_listening_on_port(self.grpc_port):
|
||||||
|
error('%s cannot bind port %d because it is bound by another process\n' % (self.name, self.grpc_port))
|
||||||
|
exit(1)
|
||||||
|
|
||||||
self.verbose = verbose
|
self.verbose = verbose
|
||||||
logfile = "/tmp/p4s.{}.log".format(self.name)
|
logfile = "/tmp/p4s.{}.log".format(self.name)
|
||||||
self.output = open(logfile, 'w')
|
self.output = open(logfile, 'w')
|
||||||
@ -75,17 +87,12 @@ class P4RuntimeSwitch(P4Switch):
|
|||||||
|
|
||||||
|
|
||||||
def check_switch_started(self, pid):
|
def check_switch_started(self, pid):
|
||||||
while True:
|
for _ in range(SWITCH_START_TIMEOUT * 2):
|
||||||
if not os.path.exists(os.path.join("/proc", str(pid))):
|
if not os.path.exists(os.path.join("/proc", str(pid))):
|
||||||
return False
|
return False
|
||||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
if check_listening_on_port(self.grpc_port):
|
||||||
sock.settimeout(0.5)
|
|
||||||
result = sock.connect_ex(("localhost", self.grpc_port))
|
|
||||||
if result == 0:
|
|
||||||
# TODO It seems like sometimes BMv2 can hang if multiple instances start up too quickly;
|
|
||||||
# this sleep might also do nothing...
|
|
||||||
sleep(0.5)
|
|
||||||
return True
|
return True
|
||||||
|
sleep(0.5)
|
||||||
|
|
||||||
def start(self, controllers):
|
def start(self, controllers):
|
||||||
info("Starting P4 switch {}.\n".format(self.name))
|
info("Starting P4 switch {}.\n".format(self.name))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user