def test_table_direct_with_group_id(self): te = sh.TableEntry("ExactOne") te.match["header_test.field32"] = "10.0.0.0" with self.assertRaisesRegex(UserError, "does not support groups"): te.group_id = 1 with self.assertRaisesRegex(UserError, "does not support groups"): te = sh.TableEntry("ExactOne")(group_id=1)
def test_table_indirect_with_direct_action(self): te = sh.TableEntry("IndirectWS") te.match["header_test.field32"] = "10.0.0.0" with self.assertRaisesRegex(UserError, "does not support direct actions"): te.action = sh.Action("actionA") with self.assertRaisesRegex(UserError, "does not support direct actions"): te = sh.TableEntry("IndirectWS")(action="actionA")
def stopShell(): shell_lock.acquire() try: te = sh.TableEntry('control_out_port.ipv4_check_checksum')( action='DoMirror') sh.TableEntry('control_out_port.ipv4_check_checksum').read( lambda t: t.delete()) sh.teardown() print("disconnected") finally: shell_lock.release()
def test_direct_meter_entry_invalid(self): ce = sh.DirectMeterEntry("ExactOne_meter") with self.assertRaisesRegex(UserError, "table_entry must be an instance of TableEntry"): ce.table_entry = 0xbad with self.assertRaisesRegex(UserError, "This DirectMeterEntry is for table"): ce.table_entry = sh.TableEntry("TernaryOne") with self.assertRaisesRegex(UserError, "Direct meters are not index-based"): ce.index = 1 te = sh.TableEntry("LpmOne")(action="actionA") with self.assertRaisesRegex(UserError, "Table has no direct meter"): te.meter_config.cir = 100
def test_direct_counter_entry_2(self): te = sh.TableEntry("ExactOne")(action="actionA") te.match["header_test.field32"] = "10.0.0.0" te.action["param"] = "aa:bb:cc:dd:ee:ff" te.counter_data.packet_count = 100 expected_entry = """ table_id: 33582705 match { field_id: 1 exact { value: "\\x0a\\x00\\x00\\x00" } } action { action { action_id: 16783703 params { param_id: 1 value: "\\xaa\\xbb\\xcc\\xdd\\xee\\xff" } } } counter_data { packet_count: 100 } """ expected_req = self.make_write_request(p4runtime_pb2.Update.INSERT, P4RuntimeEntity.table_entry, expected_entry) te.insert() self.servicer.Write.assert_called_once_with(ProtoCmp(expected_req), ANY) self.simple_read_check(expected_req.updates[0].entity, te, P4RuntimeEntity.table_entry)
def test_table_entry_lpm(self, input_, value, length): te = sh.TableEntry("LpmOne")(action="actionA") te.match["header_test.field32"] = input_ te.action["param"] = "aa:bb:cc:dd:ee:ff" te.insert() # Cannot use format here because it would require escaping all braces, # which would make wiriting tests much more annoying expected_entry = """ table_id: 33567650 match { field_id: 1 lpm { value: "%s" prefix_len: %s } } action { action { action_id: 16783703 params { param_id: 1 value: "\\xaa\\xbb\\xcc\\xdd\\xee\\xff" } } } """ % (value, length) expected_req = self.make_write_request(p4runtime_pb2.Update.INSERT, P4RuntimeEntity.table_entry, expected_entry) self.servicer.Write.assert_called_once_with(ProtoCmp(expected_req), ANY)
def test_table_entry_range(self): te = sh.TableEntry("RangeOne")(action="actionA") te.match["header_test.field32"] = "0..1024" te.action["param"] = "aa:bb:cc:dd:ee:ff" te.insert() expected_entry = """ table_id: 33603558 match { field_id: 1 range { low: "\\x00" high: "\\x04\\x00" } } action { action { action_id: 16783703 params { param_id: 1 value: "\\xaa\\xbb\\xcc\\xdd\\xee\\xff" } } } """ expected_req = self.make_write_request(p4runtime_pb2.Update.INSERT, P4RuntimeEntity.table_entry, expected_entry) self.servicer.Write.assert_called_once_with(ProtoCmp(expected_req), ANY)
def test_direct_counter_entry_invalid(self): ce = sh.DirectCounterEntry("ExactOne_counter") with self.assertRaisesRegex(UserError, "table_entry must be an instance of TableEntry"): ce.table_entry = 0xbad with self.assertRaisesRegex(UserError, "This DirectCounterEntry is for table"): ce.table_entry = sh.TableEntry("TernaryOne") with self.assertRaisesRegex(UserError, "Direct counters are not index-based"): ce.index = 1 te = sh.TableEntry("LpmOne")(action="actionA") with self.assertRaisesRegex(UserError, "Table has no direct counter"): te.counter_data.packet_count = 100 te = sh.TableEntry("ExactOne")(action="actionA") with self.assertRaisesRegex(UserError, "Counter 'ExactOne_counter' is of type 'PACKETS"): te.counter_data.byte_count = 100
def test_table_entry_optional(self): te = sh.TableEntry("OptionalOne")(action="actionA") te.match["header_test.field32"] = "0x123456" te.action["param"] = "aa:bb:cc:dd:ee:ff" te.insert() expected_entry = """ table_id: 33611248 match { field_id: 1 optional { value: "\\x12\\x34\\x56" } } action { action { action_id: 16783703 params { param_id: 1 value: "\\xaa\\xbb\\xcc\\xdd\\xee\\xff" } } } """ expected_req = self.make_write_request(p4runtime_pb2.Update.INSERT, P4RuntimeEntity.table_entry, expected_entry) self.servicer.Write.assert_called_once_with(ProtoCmp(expected_req), ANY)
def test_string_match_ekey(self): te = sh.TableEntry("StringMatchKeyTable")(action="actionA") te.match["f13"] = "16" te.action["param"] = "aa:bb:cc:dd:ee:ff" te.insert() expected_entry = """ table_id: 33554507 match { field_id: 1 exact { value: "16" } } action { action { action_id: 16783703 params { param_id: 1 value: "\\xaa\\xbb\\xcc\\xdd\\xee\\xff" } } } """ expected_req = self.make_write_request(p4runtime_pb2.Update.INSERT, P4RuntimeEntity.table_entry, expected_entry) self.servicer.Write.assert_called_once_with(ProtoCmp(expected_req), ANY)
def test_table_entry_ternary(self, input_, value, mask): te = sh.TableEntry("TernaryOne")(action="actionA") te.match["header_test.field32"] = input_ te.action["param"] = "aa:bb:cc:dd:ee:ff" te.insert() expected_entry = """ table_id: 33584148 match { field_id: 1 ternary { value: "%s" mask: "%s" } } action { action { action_id: 16783703 params { param_id: 1 value: "\\xaa\\xbb\\xcc\\xdd\\xee\\xff" } } } """ % (value, mask) expected_req = self.make_write_request(p4runtime_pb2.Update.INSERT, P4RuntimeEntity.table_entry, expected_entry) self.servicer.Write.assert_called_once_with(ProtoCmp(expected_req), ANY)
def test_table_indirect_oneshot(self): te = sh.TableEntry("IndirectWS") te.match["header_test.field32"] = "10.0.0.0" a1 = sh.Action("actionA") a1["param"] = "aa:bb:cc:dd:ee:ff" a2 = sh.Action("actionB") a2["param"] = "10" te.oneshot.add(a1).add(a2, weight=2) expected_entry = """ table_id: 33586946 match { field_id: 1 exact { value: "\\x0a\\x00\\x00\\x00" } } action { action_profile_action_set { action_profile_actions { action { action_id: 16783703 params { param_id: 1 value: "\\xaa\\xbb\\xcc\\xdd\\xee\\xff" } } weight: 1 watch: 0 } action_profile_actions { action { action_id: 16809468 params { param_id: 1 value: "\\x0a" } } weight: 2 watch: 0 } } } """ te.insert() expected_req = self.make_write_request(p4runtime_pb2.Update.INSERT, P4RuntimeEntity.table_entry, expected_entry) self.servicer.Write.assert_called_once_with(ProtoCmp(expected_req), ANY) self.simple_read_check(expected_req.updates[0].entity, te, P4RuntimeEntity.table_entry)
def analyzeCongestion(): congestion_lock.acquire() if still_congested[0][0]: print("Congestion found on port", still_congested[0][1]) print("Setting up P4Runtime entry to match on port") shell_lock.acquire() try: te = sh.TableEntry('control_out_port.ipv4_check_checksum')( action='DoMirror') te.match['standard_metadata.egress_port'] = hex( still_congested[0][1]) te.match['headers.ip.ipv4.hdr_checksum'] = '0x7f00&&&0x7f00' te.action['analyzer_port'] = '0x04' te.priority = 1 te.insert() finally: shell_lock.release() else: print("No Congestion found") congestion_lock.release()
def test_table_metadata(self): te = sh.TableEntry("ExactOne")(action="actionA") te.metadata = b"abcdef\x00\xff" te.insert() expected_entry = """ table_id: 33582705 action { action { action_id: 16783703 } } metadata: "abcdef\\x00\\xff" """ expected_req = self.make_write_request(p4runtime_pb2.Update.INSERT, P4RuntimeEntity.table_entry, expected_entry) self.servicer.Write.assert_called_once_with(ProtoCmp(expected_req), ANY)
def test_table_idle_timeout(self): te = sh.TableEntry("ExactOne")(action="actionA") te.idle_timeout_ns = 100 te.insert() expected_entry = """ table_id: 33582705 action { action { action_id: 16783703 } } idle_timeout_ns: 100 """ expected_req = self.make_write_request(p4runtime_pb2.Update.INSERT, P4RuntimeEntity.table_entry, expected_entry) self.servicer.Write.assert_called_once_with(ProtoCmp(expected_req), ANY)
def test_table_entry_lpm_dont_care(self): te = sh.TableEntry("LpmOne") with self.assertRaisesRegex(UserError, "LPM don't care match"): te.match["header_test.field32"] = "10.0.0.0/0"
import p4runtime_sh.shell as sh # you can omit the config argument if the switch is already configured with the # correct P4 dataplane. sh.setup(device_id=1, grpc_addr='172.17.0.2:50001', election_id=(1, 0), config=sh.FwdPipeConfig('/tmp/cfg/mri.p4.p4info.txt', '/tmp/cfg/mri.json')) # see p4runtime_sh/test.py for more examples te = sh.TableEntry("MyEgress.swtrace")(action="MyEgress.add_swtrace") te.action["swid"] = ("1") te.insert() te = sh.TableEntry("MyIngress.ipv4_lpm")(action="MyIngress.ipv4_forward") te.match["hdr.ipv4.dstAddr"] = ("10.0.0.1") te.action["dstAddr"] = ("9a:96:b1:20:bf:84") te.action["port"] = ("1") te.insert() te = sh.TableEntry("MyIngress.ipv4_lpm")(action="MyIngress.ipv4_forward") te.match["hdr.ipv4.dstAddr"] = ("10.0.0.2") te.action["dstAddr"] = ("de:cb:66:ce:75:8e") te.action["port"] = ("2") te.insert() # ... sh.teardown()
def test_table_indirect(self): member = sh.ActionProfileMember("ActProfWS")(member_id=1, action="actionA") member.action["param"] = "aa:bb:cc:dd:ee:ff" group = sh.ActionProfileGroup("ActProfWS")(group_id=1) group.add(member.member_id) expected_member = """ action_profile_id: 285237193 member_id: 1 action { action_id: 16783703 params { param_id: 1 value: "\\xaa\\xbb\\xcc\\xdd\\xee\\xff" } } """ expected_group = """ action_profile_id: 285237193 group_id: 1 members { member_id: 1 weight: 1 } """ expected_entry_1 = """ table_id: 33586946 match { field_id: 1 exact { value: "\\x0a\\x00\\x00\\x00" } } action { action_profile_member_id: 1 } """ expected_entry_2 = """ table_id: 33586946 match { field_id: 1 exact { value: "\\x0a\\x00\\x00\\x00" } } action { action_profile_group_id: 1 } """ expected_req = self.make_write_request( p4runtime_pb2.Update.INSERT, P4RuntimeEntity.action_profile_member, expected_member) member.insert() self.servicer.Write.assert_called_with(ProtoCmp(expected_req), ANY) expected_req = self.make_write_request( p4runtime_pb2.Update.INSERT, P4RuntimeEntity.action_profile_group, expected_group) group.insert() self.servicer.Write.assert_called_with(ProtoCmp(expected_req), ANY) te = sh.TableEntry("IndirectWS") te.match["header_test.field32"] = "10.0.0.0" te.member_id = member.member_id te.insert() expected_req = self.make_write_request(p4runtime_pb2.Update.INSERT, P4RuntimeEntity.table_entry, expected_entry_1) self.servicer.Write.assert_called_with(ProtoCmp(expected_req), ANY) te.group_id = group.group_id te.modify() expected_req = self.make_write_request(p4runtime_pb2.Update.MODIFY, P4RuntimeEntity.table_entry, expected_entry_2) self.servicer.Write.assert_called_with(ProtoCmp(expected_req), ANY)
type=int, required=False, default=0, help='The device ID (default 0)') parser.add_argument('-n', '--table-name', help='The table name to clean', type=str, required=True) return parser.parse_args() if __name__ == '__main__': """ Clears all entries from a P4 table """ args = get_args() logging.basicConfig(stream=sys.stdout, level=logging.DEBUG) logger.info('Connecting to switch at [%s]', args.grpc_addr) sh.setup(device_id=args.dev_id, grpc_addr=args.grpc_addr) logger.info('Retrieving table entry - [%s]', args.table_name) table_entry = sh.TableEntry(args.table_name) logger.info('Table entry to clear - [%s]', table_entry) table_entry.read(lambda te: logger.info('Deleting - [%s]', te)) table_entry.read(lambda te: te.delete()) logger.info('Table [%s] cleared', args.table_name) sh.teardown()
def test_table_entry_range_invalid(self): te = sh.TableEntry("RangeOne") with self.assertRaisesRegex(UserError, "Invalid range match"): te.match["header_test.field32"] = "77..22"
def test_table_entry_range_dont_care(self): te = sh.TableEntry("RangeOne") with self.assertRaisesRegex(UserError, "range don't care match"): te.match["header_test.field32"] = "0..255.255.255.255"
def get_te(): te = sh.TableEntry("ExactOne")(action="actionA") te.match["header_test.field32"] = "0x0" te.action["param"] = "00:00:11:00:22:33" return te
def test_table_entry_ternary_dont_care(self): te = sh.TableEntry("TernaryOne") with self.assertRaisesRegex(UserError, "ternary don't care match"): te.match["header_test.field32"] = "10.0.0.0&&&0.0.0.0"
] entries = filtering_entries + \ spgw_entries + \ forwarding_entries + \ acl_entries + \ next_entries + \ [] print("deleting entries from any previous run") tables = sh.P4Objects(context.P4Type.table) count = 0 for table in tables: for te in sh.TableEntry(table.name).read(): count += 1 te.delete() print("Deleted %d entries" % count) print("installing entries") for i, entry in enumerate(entries): print("installing %d" % i) try: te = sh.TableEntry(entry["table"])(action=entry["action"]) for key, val in entry["keys"].items(): te.match[key] = val for arg,val in entry["args"].items(): te.action[arg] = val priority = entry.get("priority", None) if priority != None: te.priority = priority te.insert()
# ======================================# ''' This is the P4Runtime shell-related setup. We are using p4runtime-shell open-souce code from the git found at https://github.com/p4lang/p4runtime-shell and installed on the lab's Collector. the setup & teardown should only be done once! ''' if not connection_set[0]: shell_lock.acquire() try: sh.setup(device_id=0, grpc_addr='132.68.36.62:50051', election_id=(0, 1), config=sh.FwdPipeConfig('/tmp/OurMirror.p4info', '/tmp/OurMirror.bin')) te = sh.TableEntry('control_out_port.ipv4_check_checksum')( action='DoMirror') connection_set[0] = True print("connection acomplished") finally: shell_lock.release() # ======================================# def clear(): # for windows if name == 'nt': _ = system('cls') # for mac and linux(here, os.name is 'posix') else: