-
Notifications
You must be signed in to change notification settings - Fork 12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add initial PTF tests for downlink and uplink #5
Conversation
Interestingly, tests failed but the status check is green. I will fix the status reporting. Here's the test error:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Test case LGTM. Comments are more about style.
ptf/tests/spgwu.py
Outdated
UDP_SRC_PORT = None | ||
UDP_DST_PORT = None | ||
PKT_SRC_IP = None | ||
PKT_DST_IP = None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These variables get assigned as part of the test case, so they're not constants (as the case suggests). Let's remove them from here, and simply have (lower_case) variables as part of the test case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
ptf/tests/spgwu.py
Outdated
UDP_SRC_PORT = self.inner_pkt[UDP].sport | ||
UDP_DST_PORT = self.inner_pkt[UDP].dport | ||
PKT_SRC_IP = self.inner_pkt[IP].src | ||
PKT_DST_IP = self.inner_pkt[IP].dst |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's use lower case here, these are not constant values.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
ptf/tests/spgwu.py
Outdated
UDP_SRC_PORT = self.inner_pkt[UDP].sport | ||
UDP_DST_PORT = self.inner_pkt[UDP].dport | ||
PKT_SRC_IP = self.inner_pkt[IP].src | ||
PKT_DST_IP = self.inner_pkt[IP].dst | ||
''' | ||
for teid, src_addr, dst_addr, src_port, dst_port, proto, pdr_id in \ | ||
zip([(src_teid, 0xffffffff),(0xfffff,0)], \ | ||
[(PKT_SRC_IP,IP_MASK), (PKT_DST_IP,IP_MASK)], \ | ||
[(PKT_DST_IP,IP_MASK), (PKT_DST_IP,IP_MASK)], \ | ||
[(UDP_SRC_PORT, UDP_SRC_PORT), (UDP_DST_PORT,UDP_DST_PORT)], \ | ||
[(UDP_DST_PORT, UDP_DST_PORT), (UDP_SRC_PORT, UDP_SRC_PORT)], \ | ||
#range still not sure how to write | ||
[(IP_PROTO_UDP, 0xFF), (IP_PROTO_UDP, 0xFF)], \ | ||
[UL_PDR_ID, DL_PDR_ID]): | ||
self.insert(self.helper.build_table_entry( | ||
table_name="IngressPipeImpl.pdrs", | ||
match_fields={ | ||
# Exact match. | ||
"teid": teid, | ||
"ue_addr": src_addr, | ||
"inet_addr": dst_addr, | ||
"ue_l4_port":src_port, | ||
"inet_l4_port":dst_port, | ||
"ip_proto":proto | ||
}, | ||
action_name="IngressPipeImpl.set_pdr_id", | ||
action_params={"id":pdr_id}, | ||
priority = 1 | ||
)) | ||
''' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we remove this commented block?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed
ptf/tests/spgwu.py
Outdated
#self.testPacket(pkt) | ||
|
||
#pkt[IP].payload[IP] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like these are leftover comments. Let's remove them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed
ptf/tests/spgwu.py
Outdated
"ue_l4_port":(UDP_SRC_PORT, UDP_SRC_PORT), | ||
"inet_l4_port":(UDP_DST_PORT, UDP_DST_PORT), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The same match value is used as mask. I think it should be all ones (16 bits for L4 ports, so 0xFFFF
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ops! my bad, I didn't realize we use range match for ports. I tought it was ternary. Please ignore my comment...
ptf/tests/spgwu.py
Outdated
pkt_route(exp_pkt, next_hop_mac) | ||
pkt_decrement_ttl(exp_pkt) | ||
#exp_pkt = pkt.copy() | ||
print self.port1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This print statement seems useful for debugging, perhaps it can be removed from the commit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed
ptf/tests/spgwu.py
Outdated
SPGW_DIR_UNKNOWN = 0; | ||
SPGW_DIR_UPLINK = 1; | ||
SPGW_DIR_DOWNLINK = 2; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are these used anywhere? I think there are other constants that are not used in the test cases. We should avoid declaring unused stuff which otherwise makes the code hard to read/confusing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not used. removed.
for pkt_type in ["udp"]: | ||
print_inline("%s ... " % pkt_type) | ||
pkt = getattr(testutils, "simple_%s_packet" % pkt_type)() | ||
self.inner_pkt = pkt |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you could avoid using this class-level inner_pkt
variable/attribute, as you are already passing pkt as an argument of self.testPacket()
...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The expected packet is without the gtpu, outer ip and outer udp header. So, storing and using the inner_pkt as expected pkt. We were not able to handle packet access beyond the gtpu in the argument pkt.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. When possible I prefer the functional approach for tests (i.e., everything is a function argument, no class-level variables) to reduce the risk of ending up in spaghetti code as the tests evolve. It looks like you could be passing inner_pkt as an argument of self.testPacket()
and invoke self.pkt_add_gtp()
from within self.testPacket()
after storing an unmmodified version of the packet. Here's a similar test that does pppoe encap for the bng case: https://github.com/opennetworkinglab/tassen/blob/master/ptf/tests/upstream.py#L115
ptf/tests/spgwu.py
Outdated
)) | ||
|
||
# Add entry to pdr_rule_lookup | ||
UDP_SRC_PORT = self.inner_pkt[UDP].sport |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as before, it's not clear to me why you need to define inner_pkt
. Can't you use pkt
from the function arguments?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above.
ptf/tests/spgwu.py
Outdated
|
||
# Expected pkt should have routed MAC addresses and decremented hop | ||
# limit (TTL). | ||
exp_pkt = self.inner_pkt.copy() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, you can use pkt
instead of inner_pkt
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. I left some comments, but we can fix later.
UDP_HDR_SIZE = 8 | ||
GTP_HDR_SIZE = 8 | ||
IP_VERSION_4 = 4 | ||
out_ipv4_src = '192.168.0.202' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks these are constants, so using the upper case is preferred
def read_pkt_count_pre_qos_pdr(self, line_id): | ||
return self.read_pkt_count("IngressPipeImpl.pre_qos_pdr_counter", line_id) | ||
|
||
def read_byte_count_pre_qos_pdr(self, line_id): | ||
return self.read_byte_count("IngressPipeImpl.pre_qos_pdr_counter", line_id) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This helper is meant to be P4 program agnostic. We don't need to fix this now, but in general, methods that are program-specific should go in a separate class, e.g. a client class with multiple implementations for the different targets (one for bmv2, one for tofino, etc.). Then we can think of ways to plug one implementation or the other when running the test cases... it would be good to fix after tonight's meeting.
def read_request(self, req): | ||
entities = [] | ||
grpc_addr = testutils.test_param_get("grpcaddr") | ||
channel = grpc.insecure_channel(grpc_addr) | ||
stub = p4runtime_pb2_grpc.P4RuntimeStub(channel) | ||
try: | ||
for resp in stub.Read(req): | ||
entities.extend(resp.entities) | ||
except grpc.RpcError as e: | ||
if e.code() != grpc.StatusCode.UNKNOWN: | ||
raise e | ||
raise P4RuntimeException(e) | ||
return entities | ||
|
||
def write_request(self, req, store=True): | ||
rep = self._write(req) | ||
if store: | ||
self.reqs.append(req) | ||
return rep | ||
|
||
def get_new_write_request(self): | ||
req = p4runtime_pb2.WriteRequest() | ||
req.device_id = int(testutils.test_param_get("device_id")) | ||
election_id = req.election_id | ||
election_id.high = 0 | ||
election_id.low = self.election_id | ||
return req |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Methods that deal with P4Runtime RPCs should go in base_test.py. As a matter of fact, there's already a grpc channel and a method for write request there. This helper is for constructing P4Runtime messages from a given P4Info (i.e. using table/counter names instead of IDs)
for pkt_type in ["udp"]: | ||
print_inline("%s ... " % pkt_type) | ||
pkt = getattr(testutils, "simple_%s_packet" % pkt_type)() | ||
self.inner_pkt = pkt |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. When possible I prefer the functional approach for tests (i.e., everything is a function argument, no class-level variables) to reduce the risk of ending up in spaghetti code as the tests evolve. It looks like you could be passing inner_pkt as an argument of self.testPacket()
and invoke self.pkt_add_gtp()
from within self.testPacket()
after storing an unmmodified version of the packet. Here's a similar test that does pppoe encap for the bng case: https://github.com/opennetworkinglab/tassen/blob/master/ptf/tests/upstream.py#L115
class GTPU_far_DOWNLINK_Test(P4RuntimeTest): | ||
"""Tests GTPU routing""" | ||
|
||
outer_pkt = None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here, no need to be class-level
"""Tests GTPU routing""" | ||
|
||
inner_pkt = None | ||
ulfseid = 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If ulfseid
is meant to be a constant, then it should go outside of this class and be upper case
"""Tests GTPU routing""" | ||
|
||
outer_pkt = None | ||
dlfseid = 2 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as before, this should go out of this class and be upper case, since it's used as a constant
No description provided.