def test_abf6(self): """ IPv6 ACL Based Forwarding """ # # Simple test for matching IPv6 packets # # # Rule 1 # rule_1 = AclRule(is_permit=1, proto=17, ports=1234, src_prefix=IPv6Network("2001::2/128"), dst_prefix=IPv6Network("2001::1/128")) acl_1 = VppAcl(self, rules=[rule_1]) acl_1.add_vpp_config() # # ABF policy for ACL 1 - path via interface 1 # abf_1 = VppAbfPolicy(self, 10, acl_1, [VppRoutePath("3001::1", 0xffffffff)]) abf_1.add_vpp_config() attach_1 = VppAbfAttach(self, 10, self.pg0.sw_if_index, 45, is_ipv6=True) attach_1.add_vpp_config() # # a packet matching the rule # p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IPv6(src="2001::2", dst="2001::1") / UDP(sport=1234, dport=1234) / Raw(b'\xa5' * 100)) # # packets are dropped because there is no route to the policy's # next hop # self.send_and_assert_no_replies(self.pg1, p * NUM_PKTS, "no route") # # add a route resolving the next-hop # route = VppIpRoute(self, "3001::1", 32, [VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index)]) route.add_vpp_config() # # now expect packets forwarded. # self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg1)
def create_acls_for_a_stream(self, stream_dict, test_l2_action, is_reflect): r = stream_dict['rules'] r_permit = stream_dict['permit_rules'] r_permit_reflect = stream_dict['permit_and_reflect_rules'] r_action = r_permit_reflect if is_reflect else r action_acl = VppAcl(self, rules=r_action, tag="act. acl") action_acl.add_vpp_config() permit_acl = VppAcl(self, rules=r_permit, tag="perm. acl") permit_acl.add_vpp_config() return {'L2': action_acl if test_l2_action else permit_acl, 'L3': permit_acl if test_l2_action else action_acl, 'permit': permit_acl, 'action': action_acl}
def create_acls_for_a_stream(self, stream_dict, test_l2_action, is_reflect): r = stream_dict["rules"] r_permit = stream_dict["permit_rules"] r_permit_reflect = stream_dict["permit_and_reflect_rules"] r_action = r_permit_reflect if is_reflect else r action_acl = VppAcl(self, rules=r_action, tag="act. acl") action_acl.add_vpp_config() permit_acl = VppAcl(self, rules=r_permit, tag="perm. acl") permit_acl.add_vpp_config() return { "L2": action_acl if test_l2_action else permit_acl, "L3": permit_acl if test_l2_action else action_acl, "permit": permit_acl, "action": action_acl, }
def apply_acls(self, reflect_side, acl_side): pkts = [] pkts.append(self.pkt(0)) pkts.append(self.pkt(1)) pkt = pkts[reflect_side] r = [] r.append(pkt.to_acl_rule(2, wildcard_sport=True)) r.append(self.wildcard_rule(0)) reflect_acl = VppAcl(self.testcase, r) reflect_acl.add_vpp_config() r = [] r.append(self.wildcard_rule(0)) deny_acl = VppAcl(self.testcase, r) deny_acl.add_vpp_config() if reflect_side == acl_side: acl_if0 = VppAclInterface( self.testcase, self.ifs[acl_side].sw_if_index, [reflect_acl, deny_acl], n_input=1, ) acl_if1 = VppAclInterface(self.testcase, self.ifs[1 - acl_side].sw_if_index, [], n_input=0) acl_if0.add_vpp_config() acl_if1.add_vpp_config() else: acl_if0 = VppAclInterface( self.testcase, self.ifs[acl_side].sw_if_index, [deny_acl, reflect_acl], n_input=1, ) acl_if1 = VppAclInterface(self.testcase, self.ifs[1 - acl_side].sw_if_index, [], n_input=0) acl_if0.add_vpp_config() acl_if1.add_vpp_config()
def test_abf4(self): """ IPv4 ACL Based Forwarding """ # # We are not testing the various matching capabilities # of ACLs, that's done elsewhere. Here ware are testing # the application of ACLs to a forwarding path to achieve # ABF # So we construct just a few ACLs to ensure the ABF policies # are correctly constructed and used. And a few path types # to test the API path decoding. # # # Rule 1 # rule_1 = AclRule(is_permit=1, proto=17, ports=1234, src_prefix=IPv4Network("1.1.1.1/32"), dst_prefix=IPv4Network("1.1.1.2/32")) acl_1 = VppAcl(self, rules=[rule_1]) acl_1.add_vpp_config() # # ABF policy for ACL 1 - path via interface 1 # abf_1 = VppAbfPolicy(self, 10, acl_1, [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)]) abf_1.add_vpp_config() # # Attach the policy to input interface Pg0 # attach_1 = VppAbfAttach(self, 10, self.pg0.sw_if_index, 50) attach_1.add_vpp_config() # # fire in packet matching the ACL src,dst. If it's forwarded # then the ABF was successful, since default routing will drop it # p_1 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src="1.1.1.1", dst="1.1.1.2") / UDP(sport=1234, dport=1234) / Raw(b'\xa5' * 100)) self.send_and_expect(self.pg0, p_1*NUM_PKTS, self.pg1) # # Attach a 'better' priority policy to the same interface # abf_2 = VppAbfPolicy(self, 11, acl_1, [VppRoutePath(self.pg2.remote_ip4, self.pg2.sw_if_index)]) abf_2.add_vpp_config() attach_2 = VppAbfAttach(self, 11, self.pg0.sw_if_index, 40) attach_2.add_vpp_config() self.send_and_expect(self.pg0, p_1*NUM_PKTS, self.pg2) # # Attach a policy with priority in the middle # abf_3 = VppAbfPolicy(self, 12, acl_1, [VppRoutePath(self.pg3.remote_ip4, self.pg3.sw_if_index)]) abf_3.add_vpp_config() attach_3 = VppAbfAttach(self, 12, self.pg0.sw_if_index, 45) attach_3.add_vpp_config() self.send_and_expect(self.pg0, p_1*NUM_PKTS, self.pg2) # # remove the best priority # attach_2.remove_vpp_config() self.send_and_expect(self.pg0, p_1*NUM_PKTS, self.pg3) # # Attach one of the same policies to Pg1 # attach_4 = VppAbfAttach(self, 12, self.pg1.sw_if_index, 45) attach_4.add_vpp_config() p_2 = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / IP(src="1.1.1.1", dst="1.1.1.2") / UDP(sport=1234, dport=1234) / Raw(b'\xa5' * 100)) self.send_and_expect(self.pg1, p_2 * NUM_PKTS, self.pg3) # # detach the policy from PG1, now expect traffic to be dropped # attach_4.remove_vpp_config() self.send_and_assert_no_replies(self.pg1, p_2 * NUM_PKTS, "Detached") # # Swap to route via a next-hop in the non-default table # table_20 = VppIpTable(self, 20) table_20.add_vpp_config() self.pg4.set_table_ip4(table_20.table_id) self.pg4.admin_up() self.pg4.config_ip4() self.pg4.resolve_arp() abf_13 = VppAbfPolicy(self, 13, acl_1, [VppRoutePath(self.pg4.remote_ip4, 0xffffffff, nh_table_id=table_20.table_id)]) abf_13.add_vpp_config() attach_5 = VppAbfAttach(self, 13, self.pg0.sw_if_index, 30) attach_5.add_vpp_config() self.send_and_expect(self.pg0, p_1*NUM_PKTS, self.pg4) self.pg4.unconfig_ip4() self.pg4.set_table_ip4(0)
def test_pipe(self): """Pipes""" pipes = [VppPipe(self), VppPipe(self, 10)] for p in pipes: p.add_vpp_config() p.admin_up() # # L2 cross-connect pipe0 east with pg0 and west with pg1 # self.vapi.sw_interface_set_l2_xconnect(self.pg0.sw_if_index, pipes[0].east, enable=1) self.vapi.sw_interface_set_l2_xconnect(pipes[0].east, self.pg0.sw_if_index, enable=1) self.vapi.sw_interface_set_l2_xconnect(self.pg1.sw_if_index, pipes[0].west, enable=1) self.vapi.sw_interface_set_l2_xconnect(pipes[0].west, self.pg1.sw_if_index, enable=1) # test bi-directional L2 flow pg0<->pg1 p = (Ether(src=self.pg0.remote_mac, dst=self.pg1.remote_mac) / IP(src="1.1.1.1", dst="1.1.1.2") / UDP(sport=1234, dport=1234) / Raw(b"\xa5" * 100)) self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg1) self.send_and_expect(self.pg1, p * NUM_PKTS, self.pg0) # # Attach ACL to ensure features are run on the pipe # rule_1 = AclRule( is_permit=0, proto=17, src_prefix=IPv4Network("1.1.1.1/32"), dst_prefix=IPv4Network("1.1.1.2/32"), ports=1234, ) acl = VppAcl(self, rules=[rule_1]) acl.add_vpp_config() # Apply the ACL on the pipe on output acl_if_e = VppAclInterface(self, sw_if_index=pipes[0].east, n_input=0, acls=[acl]) acl_if_e.add_vpp_config() self.send_and_assert_no_replies(self.pg0, p * NUM_PKTS) self.send_and_expect(self.pg1, p * NUM_PKTS, self.pg0) # remove from output and apply on input acl_if_e.remove_vpp_config() acl_if_w = VppAclInterface(self, sw_if_index=pipes[0].west, n_input=1, acls=[acl]) acl_if_w.add_vpp_config() self.send_and_assert_no_replies(self.pg0, p * NUM_PKTS) self.send_and_expect(self.pg1, p * NUM_PKTS, self.pg0) acl_if_w.remove_vpp_config() self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg1) self.send_and_expect(self.pg1, p * NUM_PKTS, self.pg0) # # L3 routes in two separate tables so a pipe can be used to L3 # x-connect # tables = [] tables.append(VppIpTable(self, 1)) tables.append(VppIpTable(self, 2)) for t in tables: t.add_vpp_config() self.pg2.set_table_ip4(1) self.pg2.config_ip4() self.pg2.resolve_arp() self.pg3.set_table_ip4(2) self.pg3.config_ip4() self.pg3.resolve_arp() routes = [] routes.append( VppIpRoute( self, "1.1.1.1", 32, [VppRoutePath(self.pg3.remote_ip4, self.pg3.sw_if_index)], table_id=2, )) routes.append( VppIpRoute( self, "1.1.1.1", 32, [VppRoutePath("0.0.0.0", pipes[1].east)], table_id=1, )) routes.append( VppIpRoute( self, "1.1.1.2", 32, [VppRoutePath("0.0.0.0", pipes[1].west)], table_id=2, )) routes.append( VppIpRoute( self, "1.1.1.2", 32, [VppRoutePath(self.pg2.remote_ip4, self.pg2.sw_if_index)], table_id=1, )) for r in routes: r.add_vpp_config() p_east = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) / IP(src="1.1.1.2", dst="1.1.1.1") / UDP(sport=1234, dport=1234) / Raw(b"\xa5" * 100)) # bind the pipe ends to the correct tables self.vapi.sw_interface_set_table(pipes[1].west, 0, 2) self.vapi.sw_interface_set_table(pipes[1].east, 0, 1) # IP is not enabled on the pipes at this point self.send_and_assert_no_replies(self.pg2, p_east * NUM_PKTS) # IP enable the Pipes by making them unnumbered pipes[1].set_unnumbered(self.pg2.sw_if_index, True) pipes[1].set_unnumbered(self.pg3.sw_if_index, False) self.send_and_expect(self.pg2, p_east * NUM_PKTS, self.pg3) # and the return path p_west = (Ether(src=self.pg3.remote_mac, dst=self.pg3.local_mac) / IP(src="1.1.1.1", dst="1.1.1.2") / UDP(sport=1234, dport=1234) / Raw(b"\xa5" * 100)) self.send_and_expect(self.pg3, p_west * NUM_PKTS, self.pg2) # # Use ACLs to test features run on the Pipes # acl_if_e1 = VppAclInterface(self, sw_if_index=pipes[1].east, n_input=0, acls=[acl]) acl_if_e1.add_vpp_config() self.send_and_assert_no_replies(self.pg2, p_east * NUM_PKTS) self.send_and_expect(self.pg3, p_west * NUM_PKTS, self.pg2) # remove from output and apply on input acl_if_e1.remove_vpp_config() acl_if_w1 = VppAclInterface(self, sw_if_index=pipes[1].west, n_input=1, acls=[acl]) acl_if_w1.add_vpp_config() self.send_and_assert_no_replies(self.pg2, p_east * NUM_PKTS) self.send_and_expect(self.pg3, p_west * NUM_PKTS, self.pg2) acl_if_w1.remove_vpp_config() self.send_and_expect(self.pg2, p_east * NUM_PKTS, self.pg3) self.send_and_expect(self.pg3, p_west * NUM_PKTS, self.pg2) # cleanup (so the tables delete) self.pg2.unconfig_ip4() self.pg2.set_table_ip4(0) self.pg3.unconfig_ip4() self.pg3.set_table_ip4(0) self.vapi.sw_interface_set_table(pipes[1].west, 0, 0) self.vapi.sw_interface_set_table(pipes[1].east, 0, 0)
def test_dvr(self): """ Distributed Virtual Router """ # # A packet destined to an IP address that is L2 bridged via # a non-tag interface # ip_non_tag_bridged = "10.10.10.10" ip_tag_bridged = "10.10.10.11" any_src_addr = "1.1.1.1" pkt_no_tag = ( Ether(src=self.pg0.remote_mac, dst=self.loop0.local_mac) / IP(src=any_src_addr, dst=ip_non_tag_bridged) / UDP(sport=1234, dport=1234) / Raw(b'\xa5' * 100)) pkt_tag = (Ether(src=self.pg0.remote_mac, dst=self.loop0.local_mac) / IP(src=any_src_addr, dst=ip_tag_bridged) / UDP(sport=1234, dport=1234) / Raw(b'\xa5' * 100)) # # Two sub-interfaces so we can test VLAN tag push/pop # sub_if_on_pg2 = VppDot1QSubint(self, self.pg2, 92) sub_if_on_pg3 = VppDot1QSubint(self, self.pg3, 93) sub_if_on_pg2.admin_up() sub_if_on_pg3.admin_up() # # Put all the interfaces into a new bridge domain # self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=self.pg0.sw_if_index, bd_id=1) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=self.pg1.sw_if_index, bd_id=1) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=sub_if_on_pg2.sw_if_index, bd_id=1) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=sub_if_on_pg3.sw_if_index, bd_id=1) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=self.loop0.sw_if_index, bd_id=1, port_type=L2_PORT_TYPE.BVI) self.vapi.l2_interface_vlan_tag_rewrite( sw_if_index=sub_if_on_pg2.sw_if_index, vtr_op=L2_VTR_OP.L2_POP_1, push_dot1q=92) self.vapi.l2_interface_vlan_tag_rewrite( sw_if_index=sub_if_on_pg3.sw_if_index, vtr_op=L2_VTR_OP.L2_POP_1, push_dot1q=93) # # Add routes to bridge the traffic via a tagged an nontagged interface # route_no_tag = VppIpRoute(self, ip_non_tag_bridged, 32, [ VppRoutePath("0.0.0.0", self.pg1.sw_if_index, type=FibPathType.FIB_PATH_TYPE_DVR) ]) route_no_tag.add_vpp_config() # # Inject the packet that arrives and leaves on a non-tagged interface # Since it's 'bridged' expect that the MAC headed is unchanged. # rx = self.send_and_expect(self.pg0, pkt_no_tag * NUM_PKTS, self.pg1) self.assert_same_mac_addr(pkt_no_tag, rx) self.assert_has_no_tag(rx) # # Add routes to bridge the traffic via a tagged interface # route_with_tag = VppIpRoute(self, ip_tag_bridged, 32, [ VppRoutePath("0.0.0.0", sub_if_on_pg3.sw_if_index, type=FibPathType.FIB_PATH_TYPE_DVR) ]) route_with_tag.add_vpp_config() # # Inject the packet that arrives non-tag and leaves on a tagged # interface # rx = self.send_and_expect(self.pg0, pkt_tag * NUM_PKTS, self.pg3) self.assert_same_mac_addr(pkt_tag, rx) self.assert_has_vlan_tag(93, rx) # # Tag to tag # pkt_tag_to_tag = ( Ether(src=self.pg2.remote_mac, dst=self.loop0.local_mac) / Dot1Q(vlan=92) / IP(src=any_src_addr, dst=ip_tag_bridged) / UDP(sport=1234, dport=1234) / Raw(b'\xa5' * 100)) rx = self.send_and_expect(self.pg2, pkt_tag_to_tag * NUM_PKTS, self.pg3) self.assert_same_mac_addr(pkt_tag_to_tag, rx) self.assert_has_vlan_tag(93, rx) # # Tag to non-Tag # pkt_tag_to_non_tag = ( Ether(src=self.pg2.remote_mac, dst=self.loop0.local_mac) / Dot1Q(vlan=92) / IP(src=any_src_addr, dst=ip_non_tag_bridged) / UDP(sport=1234, dport=1234) / Raw(b'\xa5' * 100)) rx = self.send_and_expect(self.pg2, pkt_tag_to_non_tag * NUM_PKTS, self.pg1) self.assert_same_mac_addr(pkt_tag_to_tag, rx) self.assert_has_no_tag(rx) # # Add an output L3 ACL that will block the traffic # rule_1 = AclRule(is_permit=0, proto=17, ports=1234, src_prefix=IPv4Network((any_src_addr, 32)), dst_prefix=IPv4Network((ip_non_tag_bridged, 32))) acl = VppAcl(self, rules=[rule_1]) acl.add_vpp_config() # # Apply the ACL on the output interface # acl_if1 = VppAclInterface(self, sw_if_index=self.pg1.sw_if_index, n_input=0, acls=[acl]) acl_if1.add_vpp_config() # # Send packet's that should match the ACL and be dropped # rx = self.send_and_assert_no_replies(self.pg2, pkt_tag_to_non_tag * NUM_PKTS) # # cleanup # acl_if1.remove_vpp_config() acl.remove_vpp_config() self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=self.pg0.sw_if_index, bd_id=1, enable=0) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=self.pg1.sw_if_index, bd_id=1, enable=0) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=sub_if_on_pg2.sw_if_index, bd_id=1, enable=0) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=sub_if_on_pg3.sw_if_index, bd_id=1, enable=0) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=self.loop0.sw_if_index, bd_id=1, port_type=L2_PORT_TYPE.BVI, enable=0) # # Do a FIB dump to make sure the paths are correctly reported as DVR # routes = self.vapi.ip_route_dump(0) for r in routes: if (ip_tag_bridged == str(r.route.prefix.network_address)): self.assertEqual(r.route.paths[0].sw_if_index, sub_if_on_pg3.sw_if_index) self.assertEqual(r.route.paths[0].type, FibPathType.FIB_PATH_TYPE_DVR) if (ip_non_tag_bridged == str(r.route.prefix.network_address)): self.assertEqual(r.route.paths[0].sw_if_index, self.pg1.sw_if_index) self.assertEqual(r.route.paths[0].type, FibPathType.FIB_PATH_TYPE_DVR) # # the explicit route delete is require so it happens before # the sbu-interface delete. subinterface delete is required # because that object type does not use the object registry # route_no_tag.remove_vpp_config() route_with_tag.remove_vpp_config() sub_if_on_pg3.remove_vpp_config() sub_if_on_pg2.remove_vpp_config()
def applied_acl_shuffle(self, acl_if): saved_n_input = acl_if.n_input # TOTO: maybe copy each one?? saved_acls = acl_if.acls # now create a list of all the rules in all ACLs all_rules = [] for old_acl in saved_acls: for rule in old_acl.rules: all_rules.append(rule) # Add a few ACLs made from shuffled rules shuffle(all_rules) acl1 = VppAcl(self, rules=all_rules[::2], tag="shuffle 1. acl") acl1.add_vpp_config() shuffle(all_rules) acl2 = VppAcl(self, rules=all_rules[::3], tag="shuffle 2. acl") acl2.add_vpp_config() shuffle(all_rules) acl3 = VppAcl(self, rules=all_rules[::2], tag="shuffle 3. acl") acl3.add_vpp_config() # apply the shuffle ACLs in front input_acls = [acl1, acl2] output_acls = [acl1, acl2] # add the currently applied ACLs n_input = acl_if.n_input input_acls.extend(saved_acls[:n_input]) output_acls.extend(saved_acls[n_input:]) # and the trailing shuffle ACL(s) input_acls.extend([acl3]) output_acls.extend([acl3]) # set the interface ACL list to the result acl_if.n_input = len(input_acls) acl_if.acls = input_acls + output_acls acl_if.add_vpp_config() # change the ACLs a few times for i in range(1, 10): shuffle(all_rules) acl1.modify_vpp_config(all_rules[::1 + (i % 2)]) shuffle(all_rules) acl2.modify_vpp_config(all_rules[::1 + (i % 3)]) shuffle(all_rules) acl3.modify_vpp_config(all_rules[::1 + (i % 5)]) # restore to how it was before and clean up acl_if.n_input = saved_n_input acl_if.acls = saved_acls acl_if.add_vpp_config() acl1.remove_vpp_config() acl2.remove_vpp_config() acl3.remove_vpp_config()
def run_traffic( self, mac_type, ip_type, traffic, is_ip6, packets, do_not_expected_capture=False, tags=None, apply_rules=True, isMACIP=True, permit_tags=PERMIT_TAGS, try_replace=False, ): self.reset_packet_infos() if tags is None: tx_if = self.pg0 if traffic == self.BRIDGED else self.pg3 rx_if = self.pg3 if traffic == self.BRIDGED else self.pg0 src_if = self.pg3 dst_if = self.loop0 else: if tags == self.DOT1Q: if traffic == self.BRIDGED: tx_if = self.subifs[0] rx_if = self.pg0 src_if = self.subifs[0] dst_if = self.loop0 else: tx_if = self.subifs[2] rx_if = self.pg0 src_if = self.subifs[2] dst_if = self.loop0 elif tags == self.DOT1AD: if traffic == self.BRIDGED: tx_if = self.subifs[1] rx_if = self.pg0 src_if = self.subifs[1] dst_if = self.loop0 else: tx_if = self.subifs[3] rx_if = self.pg0 src_if = self.subifs[3] dst_if = self.loop0 else: return test_dict = self.create_stream( mac_type, ip_type, packets, src_if, dst_if, traffic, is_ip6, tags=permit_tags, ) if apply_rules: if isMACIP: self.acl = VppMacipAcl(self, rules=test_dict["macip_rules"]) else: self.acl = VppAcl(self, rules=test_dict["acl_rules"]) self.acl.add_vpp_config() if isMACIP: self.acl_if = VppMacipAclInterface( self, sw_if_index=tx_if.sw_if_index, acls=[self.acl] ) self.acl_if.add_vpp_config() dump = self.acl_if.dump() self.assertTrue(dump) self.assertEqual(dump[0].acls[0], self.acl.acl_index) else: self.acl_if = VppAclInterface( self, sw_if_index=tx_if.sw_if_index, n_input=1, acls=[self.acl] ) self.acl_if.add_vpp_config() else: if hasattr(self, "acl_if"): self.acl_if.remove_vpp_config() if try_replace and hasattr(self, "acl"): if isMACIP: self.acl.modify_vpp_config(test_dict["macip_rules"]) else: self.acl.modify_vpp_config(test_dict["acl_rules"]) if not isinstance(src_if, VppSubInterface): tx_if.add_stream(test_dict["stream"]) else: tx_if.parent.add_stream(test_dict["stream"]) self.pg_enable_capture(self.pg_interfaces) self.pg_start() if do_not_expected_capture: rx_if.get_capture(0) else: if ( traffic == self.BRIDGED and mac_type == self.WILD_MAC and ip_type == self.WILD_IP ): capture = rx_if.get_capture(packets) else: capture = rx_if.get_capture( self.get_packet_count_for_if_idx(dst_if.sw_if_index) ) self.verify_capture(test_dict["stream"], capture, is_ip6) if not isMACIP: if hasattr(self, "acl_if"): self.acl_if.remove_vpp_config() if hasattr(self, "acl"): self.acl.remove_vpp_config()
class MethodHolder(VppTestCase): DEBUG = False BRIDGED = True ROUTED = False IS_IP4 = False IS_IP6 = True DOT1AD = "dot1ad" DOT1Q = "dot1q" PERMIT_TAGS = True DENY_TAGS = False # rule types DENY = 0 PERMIT = 1 # ACL types EXACT_IP = 1 SUBNET_IP = 2 WILD_IP = 3 EXACT_MAC = 1 WILD_MAC = 2 OUI_MAC = 3 ACLS = [] @classmethod def setUpClass(cls): """ Perform standard class setup (defined by class method setUpClass in class VppTestCase) before running the test case, set test case related variables and configure VPP. """ super(MethodHolder, cls).setUpClass() cls.pg_if_packet_sizes = [64, 512, 1518, 9018] # packet sizes cls.bd_id = 111 cls.remote_hosts_count = 200 try: # create 4 pg interfaces, 1 loopback interface cls.create_pg_interfaces(range(4)) cls.create_loopback_interfaces(1) # create 2 subinterfaces cls.subifs = [ VppDot1QSubint(cls, cls.pg1, 10), VppDot1ADSubint(cls, cls.pg2, 20, 300, 400), VppDot1QSubint(cls, cls.pg3, 30), VppDot1ADSubint(cls, cls.pg3, 40, 600, 700), ] cls.subifs[0].set_vtr(L2_VTR_OP.L2_POP_1, inner=10, push1q=1) cls.subifs[1].set_vtr(L2_VTR_OP.L2_POP_2, outer=300, inner=400, push1q=1) cls.subifs[2].set_vtr(L2_VTR_OP.L2_POP_1, inner=30, push1q=1) cls.subifs[3].set_vtr(L2_VTR_OP.L2_POP_2, outer=600, inner=700, push1q=1) cls.interfaces = list(cls.pg_interfaces) cls.interfaces.extend(cls.lo_interfaces) cls.interfaces.extend(cls.subifs) for i in cls.interfaces: i.admin_up() # Create BD with MAC learning enabled and put interfaces to this BD cls.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=cls.loop0.sw_if_index, bd_id=cls.bd_id, port_type=L2_PORT_TYPE.BVI, ) cls.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=cls.pg0.sw_if_index, bd_id=cls.bd_id ) cls.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=cls.pg1.sw_if_index, bd_id=cls.bd_id ) cls.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=cls.subifs[0].sw_if_index, bd_id=cls.bd_id ) cls.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=cls.subifs[1].sw_if_index, bd_id=cls.bd_id ) # Configure IPv4/6 addresses on loop interface and routed interface cls.loop0.config_ip4() cls.loop0.config_ip6() cls.pg2.config_ip4() cls.pg2.config_ip6() cls.pg3.config_ip4() cls.pg3.config_ip6() # Configure MAC address binding to IPv4 neighbors on loop0 cls.loop0.generate_remote_hosts(cls.remote_hosts_count) # Modify host mac addresses to have different OUI parts for i in range(2, cls.remote_hosts_count + 2): mac = cls.loop0.remote_hosts[i - 2]._mac.split(":") mac[2] = format(int(mac[2], 16) + i, "02x") cls.loop0.remote_hosts[i - 2]._mac = ":".join(mac) cls.loop0.configure_ipv4_neighbors() cls.loop0.configure_ipv6_neighbors() # configure MAC address on pg3 cls.pg3.resolve_arp() cls.pg3.resolve_ndp() # configure MAC address on subifs for i in cls.subifs: i.config_ip4() i.resolve_arp() i.config_ip6() # configure MAC address on pg2 cls.pg2.resolve_arp() cls.pg2.resolve_ndp() # Loopback BVI interface has remote hosts # one half of hosts are behind pg0 second behind pg1,pg2,pg3 subifs cls.pg0.remote_hosts = cls.loop0.remote_hosts[:100] cls.subifs[0].remote_hosts = cls.loop0.remote_hosts[100:125] cls.subifs[1].remote_hosts = cls.loop0.remote_hosts[125:150] cls.subifs[2].remote_hosts = cls.loop0.remote_hosts[150:175] cls.subifs[3].remote_hosts = cls.loop0.remote_hosts[175:] except Exception: super(MethodHolder, cls).tearDownClass() raise @classmethod def tearDownClass(cls): super(MethodHolder, cls).tearDownClass() def setUp(self): super(MethodHolder, self).setUp() self.reset_packet_infos() def show_commands_at_teardown(self): self.logger.info(self.vapi.ppcli("show interface address")) self.logger.info(self.vapi.ppcli("show hardware")) self.logger.info(self.vapi.ppcli("sh acl-plugin macip acl")) self.logger.info(self.vapi.ppcli("sh acl-plugin macip interface")) self.logger.info(self.vapi.ppcli("sh classify tables verbose")) self.logger.info(self.vapi.ppcli("sh acl-plugin acl")) self.logger.info(self.vapi.ppcli("sh acl-plugin interface")) self.logger.info(self.vapi.ppcli("sh acl-plugin tables")) # print(self.vapi.ppcli("show interface address")) # print(self.vapi.ppcli("show hardware")) # print(self.vapi.ppcli("sh acl-plugin macip interface")) # print(self.vapi.ppcli("sh acl-plugin macip acl")) def macip_acl_dump_debug(self): acls = self.vapi.macip_acl_dump() if self.DEBUG: for acl in acls: # print("ACL #"+str(acl.acl_index)) for r in acl.r: rule = "ACTION" if r.is_permit == 1: rule = "PERMIT" elif r.is_permit == 0: rule = "DENY " """ print(" IP6" if r.is_ipv6 else " IP4", rule, binascii.hexlify(r.src_mac), binascii.hexlify(r.src_mac_mask), unpack('<16B', r.src_ip_addr), r.src_ip_prefix_len) """ return acls def create_rules( self, mac_type=EXACT_MAC, ip_type=EXACT_IP, acl_count=1, rules_count=None ): acls = [] if rules_count is None: rules_count = [1] src_mac = int("220000dead00", 16) for acl in range(2, (acl_count + 1) * 2): rules = [] host = random.choice(self.loop0.remote_hosts) is_ip6 = acl % 2 ip4 = host.ip4.split(".") ip6 = list(unpack("<16B", inet_pton(AF_INET6, host.ip6))) if ip_type == self.EXACT_IP: prefix_len4 = 32 prefix_len6 = 128 elif ip_type == self.WILD_IP: ip4 = [0, 0, 0, 0] ip6 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] prefix_len4 = 0 prefix_len6 = 0 rules_count[int((acl / 2) - 1)] = 1 else: prefix_len4 = 24 prefix_len6 = 64 if mac_type == self.EXACT_MAC: mask = "ff:ff:ff:ff:ff:ff" elif mac_type == self.WILD_MAC: mask = "00:00:00:00:00:00" elif mac_type == self.OUI_MAC: mask = "ff:ff:ff:00:00:00" else: mask = "ff:ff:ff:ff:ff:00" ip = ip6 if is_ip6 else ip4 ip_len = prefix_len6 if is_ip6 else prefix_len4 for i in range(0, (rules_count[int((acl / 2) - 1)])): src_mac += 16777217 if mac_type == self.WILD_MAC: mac = "00:00:00:00:00:00" elif mac_type == self.OUI_MAC: mac = ( ":".join(re.findall("..", "{:02x}".format(src_mac))[:3]) + ":00:00:00" ) else: mac = ":".join(re.findall("..", "{:02x}".format(src_mac))) if ip_type == self.EXACT_IP: ip4[3] = random.randint(100, 200) ip6[15] = random.randint(100, 200) elif ip_type == self.SUBNET_IP: ip4[2] = random.randint(100, 200) ip4[3] = 0 ip6[7] = random.randint(100, 200) ip6[15] = 0 ip_pack = b"" for j in range(0, len(ip)): ip_pack += pack("<B", int(ip[j])) rule = MacipRule( is_permit=self.PERMIT, src_prefix=ip_network((ip_pack, ip_len)), src_mac=MACAddress(mac).packed, src_mac_mask=MACAddress(mask).packed, ) rules.append(rule) if ip_type == self.WILD_IP: break acls.append(rules) src_mac += 1099511627776 return acls def apply_macip_rules(self, acls): macip_acls = [] for acl in acls: macip_acl = VppMacipAcl(self, rules=acl) macip_acl.add_vpp_config() macip_acls.append(macip_acl) return macip_acls def verify_macip_acls(self, acl_count, rules_count, expected_count=2): reply = self.macip_acl_dump_debug() for acl in range(2, (acl_count + 1) * 2): self.assertEqual(reply[acl - 2].count, rules_count[acl // 2 - 1]) self.vapi.macip_acl_interface_get() self.vapi.macip_acl_interface_add_del(sw_if_index=0, acl_index=0) self.vapi.macip_acl_interface_add_del(sw_if_index=1, acl_index=1) reply = self.vapi.macip_acl_interface_get() self.assertEqual(reply.count, expected_count) def create_stream( self, mac_type, ip_type, packet_count, src_if, dst_if, traffic, is_ip6, tags=PERMIT_TAGS, ): # exact MAC and exact IP # exact MAC and subnet of IPs # exact MAC and wildcard IP # wildcard MAC and exact IP # wildcard MAC and subnet of IPs # wildcard MAC and wildcard IP # OUI restricted MAC and exact IP # OUI restricted MAC and subnet of IPs # OUI restricted MAC and wildcard IP packets = [] macip_rules = [] acl_rules = [] ip_permit = "" mac_permit = "" dst_mac = "" mac_rule = "00:00:00:00:00:00" mac_mask = "00:00:00:00:00:00" for p in range(0, packet_count): remote_dst_index = p % len(dst_if.remote_hosts) remote_dst_host = dst_if.remote_hosts[remote_dst_index] dst_port = 1234 + p src_port = 4321 + p is_permit = self.PERMIT if p % 3 == 0 else self.DENY denyMAC = True if not is_permit and p % 3 == 1 else False denyIP = True if not is_permit and p % 3 == 2 else False if not is_permit and ip_type == self.WILD_IP: denyMAC = True if not is_permit and mac_type == self.WILD_MAC: denyIP = True if traffic == self.BRIDGED: if is_permit: src_mac = remote_dst_host._mac dst_mac = "de:ad:00:00:00:00" src_ip4 = remote_dst_host.ip4 dst_ip4 = src_if.remote_ip4 src_ip6 = remote_dst_host.ip6 dst_ip6 = src_if.remote_ip6 ip_permit = src_ip6 if is_ip6 else src_ip4 mac_permit = src_mac if denyMAC: mac = src_mac.split(":") mac[0] = format(int(mac[0], 16) + 1, "02x") src_mac = ":".join(mac) if is_ip6: src_ip6 = ip_permit else: src_ip4 = ip_permit if denyIP: if ip_type != self.WILD_IP: src_mac = mac_permit src_ip4 = remote_dst_host.ip4 dst_ip4 = src_if.remote_ip4 src_ip6 = remote_dst_host.ip6 dst_ip6 = src_if.remote_ip6 else: if is_permit: src_mac = remote_dst_host._mac dst_mac = src_if.local_mac src_ip4 = src_if.remote_ip4 dst_ip4 = remote_dst_host.ip4 src_ip6 = src_if.remote_ip6 dst_ip6 = remote_dst_host.ip6 ip_permit = src_ip6 if is_ip6 else src_ip4 mac_permit = src_mac if denyMAC: mac = src_mac.split(":") mac[0] = format(int(mac[0], 16) + 1, "02x") src_mac = ":".join(mac) if is_ip6: src_ip6 = ip_permit else: src_ip4 = ip_permit if denyIP: src_mac = remote_dst_host._mac if ip_type != self.WILD_IP: src_mac = mac_permit src_ip4 = remote_dst_host.ip4 dst_ip4 = src_if.remote_ip4 src_ip6 = remote_dst_host.ip6 dst_ip6 = src_if.remote_ip6 if is_permit: info = self.create_packet_info(src_if, dst_if) payload = self.info_to_payload(info) else: payload = "to be blocked" if mac_type == self.WILD_MAC: mac = src_mac.split(":") for i in range(1, 5): mac[i] = format(random.randint(0, 255), "02x") src_mac = ":".join(mac) # create packet packet = Ether(src=src_mac, dst=dst_mac) ip_rule = src_ip6 if is_ip6 else src_ip4 if is_ip6: if ip_type != self.EXACT_IP: sub_ip = list(unpack("<16B", inet_pton(AF_INET6, ip_rule))) if ip_type == self.WILD_IP: sub_ip[0] = random.randint(240, 254) sub_ip[1] = random.randint(230, 239) sub_ip[14] = random.randint(100, 199) sub_ip[15] = random.randint(200, 255) elif ip_type == self.SUBNET_IP: if denyIP: sub_ip[2] = int(sub_ip[2]) + 1 sub_ip[14] = random.randint(100, 199) sub_ip[15] = random.randint(200, 255) packed_src_ip6 = b"".join([scapy.compat.chb(x) for x in sub_ip]) src_ip6 = inet_ntop(AF_INET6, packed_src_ip6) packet /= IPv6(src=src_ip6, dst=dst_ip6) else: if ip_type != self.EXACT_IP: sub_ip = ip_rule.split(".") if ip_type == self.WILD_IP: sub_ip[0] = random.randint(1, 49) sub_ip[1] = random.randint(50, 99) sub_ip[2] = random.randint(100, 199) sub_ip[3] = random.randint(200, 255) elif ip_type == self.SUBNET_IP: if denyIP: sub_ip[1] = int(sub_ip[1]) + 1 sub_ip[2] = random.randint(100, 199) sub_ip[3] = random.randint(200, 255) src_ip4 = ".".join(["{!s}".format(x) for x in sub_ip]) packet /= IP(src=src_ip4, dst=dst_ip4, frag=0, flags=0) packet /= UDP(sport=src_port, dport=dst_port) / Raw(payload) packet[Raw].load += b" mac:%s" % src_mac.encode("utf-8") size = self.pg_if_packet_sizes[p % len(self.pg_if_packet_sizes)] if isinstance(src_if, VppSubInterface): size = size + 4 if isinstance(src_if, VppDot1QSubint): if src_if is self.subifs[0]: if tags == self.PERMIT_TAGS: packet = src_if.add_dot1q_layer(packet, 10) else: packet = src_if.add_dot1q_layer(packet, 11) else: if tags == self.PERMIT_TAGS: packet = src_if.add_dot1q_layer(packet, 30) else: packet = src_if.add_dot1q_layer(packet, 33) elif isinstance(src_if, VppDot1ADSubint): if src_if is self.subifs[1]: if tags == self.PERMIT_TAGS: packet = src_if.add_dot1ad_layer(packet, 300, 400) else: packet = src_if.add_dot1ad_layer(packet, 333, 444) else: if tags == self.PERMIT_TAGS: packet = src_if.add_dot1ad_layer(packet, 600, 700) else: packet = src_if.add_dot1ad_layer(packet, 666, 777) self.extend_packet(packet, size) packets.append(packet) # create suitable MACIP rule if mac_type == self.EXACT_MAC: mac_rule = src_mac mac_mask = "ff:ff:ff:ff:ff:ff" elif mac_type == self.WILD_MAC: mac_rule = "00:00:00:00:00:00" mac_mask = "00:00:00:00:00:00" elif mac_type == self.OUI_MAC: mac = src_mac.split(":") mac[3] = mac[4] = mac[5] = "00" mac_rule = ":".join(mac) mac_mask = "ff:ff:ff:00:00:00" if is_ip6: if ip_type == self.WILD_IP: ip = "0::0" else: ip = src_ip6 if ip_type == self.SUBNET_IP: sub_ip = list(unpack("<16B", inet_pton(AF_INET6, ip))) for i in range(8, 16): sub_ip[i] = 0 packed_ip = b"".join([scapy.compat.chb(x) for x in sub_ip]) ip = inet_ntop(AF_INET6, packed_ip) else: if ip_type == self.WILD_IP: ip = "0.0.0.0" else: ip = src_ip4 if ip_type == self.SUBNET_IP: sub_ip = ip.split(".") sub_ip[2] = sub_ip[3] = "0" ip = ".".join(sub_ip) prefix_len = 128 if is_ip6 else 32 if ip_type == self.WILD_IP: prefix_len = 0 elif ip_type == self.SUBNET_IP: prefix_len = 64 if is_ip6 else 16 ip_rule = inet_pton(AF_INET6 if is_ip6 else AF_INET, ip) # create suitable ACL rule if is_permit: rule_l4_sport = packet[UDP].sport rule_l4_dport = packet[UDP].dport rule_family = AF_INET6 if packet.haslayer(IPv6) else AF_INET rule_prefix_len = 128 if packet.haslayer(IPv6) else 32 rule_l3_layer = IPv6 if packet.haslayer(IPv6) else IP if packet.haslayer(IPv6): rule_l4_proto = packet[UDP].overload_fields[IPv6]["nh"] else: rule_l4_proto = packet[IP].proto src_network = ip_network((packet[rule_l3_layer].src, rule_prefix_len)) dst_network = ip_network((packet[rule_l3_layer].dst, rule_prefix_len)) acl_rule = AclRule( is_permit=is_permit, proto=rule_l4_proto, src_prefix=src_network, dst_prefix=dst_network, sport_from=rule_l4_sport, sport_to=rule_l4_sport, dport_from=rule_l4_dport, dport_to=rule_l4_dport, ) acl_rules.append(acl_rule) if mac_type == self.WILD_MAC and ip_type == self.WILD_IP and p > 0: continue if is_permit: macip_rule = MacipRule( is_permit=is_permit, src_prefix=ip_network((ip_rule, prefix_len)), src_mac=MACAddress(mac_rule).packed, src_mac_mask=MACAddress(mac_mask).packed, ) macip_rules.append(macip_rule) # deny all other packets if not (mac_type == self.WILD_MAC and ip_type == self.WILD_IP): network = IPv6Network((0, 0)) if is_ip6 else IPv4Network((0, 0)) macip_rule = MacipRule( is_permit=0, src_prefix=network, src_mac=MACAddress("00:00:00:00:00:00").packed, src_mac_mask=MACAddress("00:00:00:00:00:00").packed, ) macip_rules.append(macip_rule) network = IPv6Network((0, 0)) if is_ip6 else IPv4Network((0, 0)) acl_rule = AclRule( is_permit=0, src_prefix=network, dst_prefix=network, sport_from=0, sport_to=0, dport_from=0, dport_to=0, ) acl_rules.append(acl_rule) return {"stream": packets, "macip_rules": macip_rules, "acl_rules": acl_rules} def verify_capture(self, stream, capture, is_ip6): """ :param stream: :param capture: :param is_ip6: :return: """ # p_l3 = IPv6 if is_ip6 else IP # if self.DEBUG: # for p in stream: # print(p[Ether].src, p[Ether].dst, p[p_l3].src, p[p_l3].dst) # # acls = self.macip_acl_dump_debug() # TODO : verify # for acl in acls: # for r in acl.r: # print(binascii.hexlify(r.src_mac), \ # binascii.hexlify(r.src_mac_mask),\ # unpack('<16B', r.src_ip_addr), \ # r.src_ip_prefix_len) # # for p in capture: # print(p[Ether].src, p[Ether].dst, p[p_l3].src, p[p_l3].dst # data = p[Raw].load.split(':',1)[1]) # print(p[p_l3].src, data) def run_traffic( self, mac_type, ip_type, traffic, is_ip6, packets, do_not_expected_capture=False, tags=None, apply_rules=True, isMACIP=True, permit_tags=PERMIT_TAGS, try_replace=False, ): self.reset_packet_infos() if tags is None: tx_if = self.pg0 if traffic == self.BRIDGED else self.pg3 rx_if = self.pg3 if traffic == self.BRIDGED else self.pg0 src_if = self.pg3 dst_if = self.loop0 else: if tags == self.DOT1Q: if traffic == self.BRIDGED: tx_if = self.subifs[0] rx_if = self.pg0 src_if = self.subifs[0] dst_if = self.loop0 else: tx_if = self.subifs[2] rx_if = self.pg0 src_if = self.subifs[2] dst_if = self.loop0 elif tags == self.DOT1AD: if traffic == self.BRIDGED: tx_if = self.subifs[1] rx_if = self.pg0 src_if = self.subifs[1] dst_if = self.loop0 else: tx_if = self.subifs[3] rx_if = self.pg0 src_if = self.subifs[3] dst_if = self.loop0 else: return test_dict = self.create_stream( mac_type, ip_type, packets, src_if, dst_if, traffic, is_ip6, tags=permit_tags, ) if apply_rules: if isMACIP: self.acl = VppMacipAcl(self, rules=test_dict["macip_rules"]) else: self.acl = VppAcl(self, rules=test_dict["acl_rules"]) self.acl.add_vpp_config() if isMACIP: self.acl_if = VppMacipAclInterface( self, sw_if_index=tx_if.sw_if_index, acls=[self.acl] ) self.acl_if.add_vpp_config() dump = self.acl_if.dump() self.assertTrue(dump) self.assertEqual(dump[0].acls[0], self.acl.acl_index) else: self.acl_if = VppAclInterface( self, sw_if_index=tx_if.sw_if_index, n_input=1, acls=[self.acl] ) self.acl_if.add_vpp_config() else: if hasattr(self, "acl_if"): self.acl_if.remove_vpp_config() if try_replace and hasattr(self, "acl"): if isMACIP: self.acl.modify_vpp_config(test_dict["macip_rules"]) else: self.acl.modify_vpp_config(test_dict["acl_rules"]) if not isinstance(src_if, VppSubInterface): tx_if.add_stream(test_dict["stream"]) else: tx_if.parent.add_stream(test_dict["stream"]) self.pg_enable_capture(self.pg_interfaces) self.pg_start() if do_not_expected_capture: rx_if.get_capture(0) else: if ( traffic == self.BRIDGED and mac_type == self.WILD_MAC and ip_type == self.WILD_IP ): capture = rx_if.get_capture(packets) else: capture = rx_if.get_capture( self.get_packet_count_for_if_idx(dst_if.sw_if_index) ) self.verify_capture(test_dict["stream"], capture, is_ip6) if not isMACIP: if hasattr(self, "acl_if"): self.acl_if.remove_vpp_config() if hasattr(self, "acl"): self.acl.remove_vpp_config() def run_test_acls( self, mac_type, ip_type, acl_count, rules_count, traffic=None, ip=None ): self.apply_macip_rules( self.create_rules(mac_type, ip_type, acl_count, rules_count) ) self.verify_macip_acls(acl_count, rules_count) if traffic is not None: self.run_traffic(self.EXACT_MAC, self.EXACT_IP, traffic, ip, 9)