diff options
-rw-r--r-- | src/vnet/classify/classify.api | 5 | ||||
-rw-r--r-- | src/vnet/classify/vnet_classify.c | 10 | ||||
-rw-r--r-- | src/vnet/classify/vnet_classify.h | 1 | ||||
-rw-r--r-- | src/vnet/ip/ip_input_acl.c | 2 | ||||
-rw-r--r-- | src/vnet/srv6/sr_steering.md | 24 | ||||
-rw-r--r-- | test/test_srv6.py | 145 | ||||
-rw-r--r-- | test/vpp_papi_provider.py | 10 |
7 files changed, 196 insertions, 1 deletions
diff --git a/src/vnet/classify/classify.api b/src/vnet/classify/classify.api index de9de773858..9d666ee35a5 100644 --- a/src/vnet/classify/classify.api +++ b/src/vnet/classify/classify.api @@ -90,8 +90,13 @@ define classify_add_del_table_reply 2: Classified IP packets will be looked up from the specified ipv6 fib table (configured by metadata as VRF id). Only valid for L3 input ACL node + 3: Classified packet will be steered to source routig policy + of given index (in metadata). + This is only valid for IPv6 packets redirected to a source + routing node. @param metadata - valid only if action != 0 VRF id if action is 1 or 2. + sr policy index if action is 3. @param match[] - for add, match value for session, required */ autoreply define classify_add_del_session diff --git a/src/vnet/classify/vnet_classify.c b/src/vnet/classify/vnet_classify.c index f2fe23b3231..d634550bafd 100644 --- a/src/vnet/classify/vnet_classify.c +++ b/src/vnet/classify/vnet_classify.c @@ -373,6 +373,8 @@ vnet_classify_entry_claim_resource (vnet_classify_entry_t *e) case CLASSIFY_ACTION_SET_IP6_FIB_INDEX: fib_table_lock (e->metadata, FIB_PROTOCOL_IP6, FIB_SOURCE_CLASSIFY); break; + case CLASSIFY_ACTION_SET_SR_POLICY_INDEX: + break; } } @@ -387,6 +389,8 @@ vnet_classify_entry_release_resource (vnet_classify_entry_t *e) case CLASSIFY_ACTION_SET_IP6_FIB_INDEX: fib_table_unlock (e->metadata, FIB_PROTOCOL_IP6, FIB_SOURCE_CLASSIFY); break; + case CLASSIFY_ACTION_SET_SR_POLICY_INDEX: + break; } } @@ -2104,6 +2108,8 @@ int vnet_classify_add_del_session (vnet_classify_main_t * cm, e->metadata = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, metadata, FIB_SOURCE_CLASSIFY); + else if (e->action == CLASSIFY_ACTION_SET_SR_POLICY_INDEX) + e->metadata = metadata; else e->metadata = 0; @@ -2172,6 +2178,8 @@ classify_session_command_fn (vlib_main_t * vm, action = 1; else if (unformat (input, "action set-ip6-fib-id %d", &metadata)) action = 2; + else if (unformat (input, "action set-sr-policy-index %d", &metadata)) + action = 3; else { /* Try registered opaque-index unformat fns */ @@ -2217,7 +2225,7 @@ VLIB_CLI_COMMAND (classify_session_command, static) = { "classify session [hit-next|l2-hit-next|" "acl-hit-next <next_index>|policer-hit-next <policer_name>]" "\n table-index <nn> match [hex] [l2] [l3 ip4] [opaque-index <index>]" - "\n [action set-ip4-fib-id <n>] [action set-ip6-fib-id <n>] [del]", + "\n [action set-ip4-fib-id|set-ip6-fib-id|set-sr-policy-index <n>] [del]", .function = classify_session_command_fn, }; diff --git a/src/vnet/classify/vnet_classify.h b/src/vnet/classify/vnet_classify.h index 1eb5b14d024..c4a5a61364c 100644 --- a/src/vnet/classify/vnet_classify.h +++ b/src/vnet/classify/vnet_classify.h @@ -66,6 +66,7 @@ typedef enum vnet_classify_action_t_ { CLASSIFY_ACTION_SET_IP4_FIB_INDEX = 1, CLASSIFY_ACTION_SET_IP6_FIB_INDEX = 2, + CLASSIFY_ACTION_SET_SR_POLICY_INDEX = 3, } __attribute__ ((packed)) vnet_classify_action_t; struct _vnet_classify_main; diff --git a/src/vnet/ip/ip_input_acl.c b/src/vnet/ip/ip_input_acl.c index b0b52ab11c3..1dd5317ee24 100644 --- a/src/vnet/ip/ip_input_acl.c +++ b/src/vnet/ip/ip_input_acl.c @@ -288,6 +288,8 @@ ip_inacl_inline (vlib_main_t * vm, if (e0->action == CLASSIFY_ACTION_SET_IP4_FIB_INDEX || e0->action == CLASSIFY_ACTION_SET_IP6_FIB_INDEX) vnet_buffer (b0)->sw_if_index[VLIB_TX] = e0->metadata; + else if (e0->action == CLASSIFY_ACTION_SET_SR_POLICY_INDEX) + vnet_buffer (b0)->ip.adj_index[VLIB_TX] = e0->metadata; } else { diff --git a/src/vnet/srv6/sr_steering.md b/src/vnet/srv6/sr_steering.md index cf446f8171e..7e91892e0bc 100644 --- a/src/vnet/srv6/sr_steering.md +++ b/src/vnet/srv6/sr_steering.md @@ -1,5 +1,7 @@ # Steering packets into a SR Policy {#srv6_steering_doc} +## steer packets uging the sr steering policy + To steer packets in Transit into an SR policy (T.Insert, T.Encaps and T.Encaps.L2 behaviors), the user needs to create an 'sr steering policy'. sr steer l3 2001::/64 via sr policy index 1 @@ -9,3 +11,25 @@ To steer packets in Transit into an SR policy (T.Insert, T.Encaps and T.Encaps.L sr steer l2 TenGE0/1/0 via sr policy bsid cafe::1 Disclaimer: The T.Encaps.L2 will steer L2 frames into an SR Policy. Notice that creating an SR steering policy for L2 frames will actually automatically *put the interface into promiscous mode*. + +## steer packets using the classifier + +Another way to steer packet is to use the classifier. + +First the user need to manually add the source routing node to the list of the +ip6-inacl next nodes. +Using the python api this can be donne with: + + # jsonfiles = get list of json api files + vpp = VPP(jsonfiles) + vpp.add_node_next(node_name='ip6-inacl', next_name='sr-pl-rewrite-insert') + +Below is a classifier mask filtering all the packets from the interface +TenGigabitEthernet5/0/0 on ip version and moving all ipv6 packets to the +sr-pl-rewrite-insert node (dropping the others) and applying the source routing +index 2. +In essence, this means "apply this sr policy to all the packets from this interface) + + vpp# classify table miss-next 0 current-data-flag 1 mask hex f000000000000000 skip 0 + vpp# classify session acl-hit-next 1 table-index 0 match hex 6000000000000000 action set-sr-policy-index 2 + vpp# set interface input acl intfc TenGigabitEthernet5/0/0 ip6-table 0 diff --git a/test/test_srv6.py b/test/test_srv6.py index a31b30eb619..4a2ef016039 100644 --- a/test/test_srv6.py +++ b/test/test_srv6.py @@ -1,6 +1,7 @@ #!/usr/bin/env python import unittest +import binascii from socket import AF_INET6 from framework import VppTestCase, VppTestRunner @@ -1165,6 +1166,150 @@ class TestSRv6(VppTestCase): # cleanup interfaces self.teardown_interfaces() + def test_SRv6_T_Insert_Classifier(self): + """ Test SRv6 Transit.Insert behavior (IPv6 only). + steer packets using the classifier + """ + # send traffic to one destination interface + # source and destination are IPv6 only + self.setup_interfaces(ipv6=[False, False, False, True, True]) + + # configure FIB entries + route = VppIpRoute(self, "a4::", 64, + [VppRoutePath(self.pg4.remote_ip6, + self.pg4.sw_if_index, + proto=DpoProto.DPO_PROTO_IP6)], + is_ip6=1) + route.add_vpp_config() + + # configure encaps IPv6 source address + # needs to be done before SR Policy config + # TODO: API? + self.vapi.cli("set sr encaps source addr a3::") + + bsid = 'a3::9999:1' + # configure SRv6 Policy + # Note: segment list order: first -> last + sr_policy = VppSRv6Policy( + self, bsid=bsid, + is_encap=0, + sr_type=SRv6PolicyType.SR_POLICY_TYPE_DEFAULT, + weight=1, fib_table=0, + segments=['a4::', 'a5::', 'a6::c7'], + source='a3::') + sr_policy.add_vpp_config() + self.sr_policy = sr_policy + + # log the sr policies + self.logger.info(self.vapi.cli("show sr policies")) + + # add classify table + # mask on dst ip address prefix a7::/8 + mask = '{:0<16}'.format('ff') + r = self.vapi.classify_add_del_table( + 1, + binascii.unhexlify(mask), + match_n_vectors=(len(mask) - 1) // 32 + 1, + current_data_flag=1, + skip_n_vectors=2) # data offset + self.assertIsNotNone(r, msg='No response msg for add_del_table') + table_index = r.new_table_index + + # add the source routign node as a ip6 inacl netxt node + r = self.vapi.add_node_next('ip6-inacl', + 'sr-pl-rewrite-insert') + inacl_next_node_index = r.node_index + + match = '{:0<16}'.format('a7') + r = self.vapi.classify_add_del_session( + 1, + table_index, + binascii.unhexlify(match), + hit_next_index=inacl_next_node_index, + action=3, + metadata=0) # sr policy index + self.assertIsNotNone(r, msg='No response msg for add_del_session') + + # log the classify table used in the steering policy + self.logger.info(self.vapi.cli("show classify table")) + + r = self.vapi.input_acl_set_interface( + is_add=1, + sw_if_index=self.pg3.sw_if_index, + ip6_table_index=table_index) + self.assertIsNotNone(r, + msg='No response msg for input_acl_set_interface') + + # log the ip6 inacl + self.logger.info(self.vapi.cli("show inacl type ip6")) + + # create packets + count = len(self.pg_packet_sizes) + dst_inner = 'a7::1234' + pkts = [] + + # create IPv6 packets without SRH + packet_header = self.create_packet_header_IPv6(dst_inner) + # create traffic stream pg3->pg4 + pkts.extend(self.create_stream(self.pg3, self.pg4, packet_header, + self.pg_packet_sizes, count)) + + # create IPv6 packets with SRH + # packets with segments-left 1, active segment a7:: + packet_header = self.create_packet_header_IPv6_SRH( + sidlist=['a8::', 'a7::', 'a6::'], + segleft=1) + # create traffic stream pg3->pg4 + pkts.extend(self.create_stream(self.pg3, self.pg4, packet_header, + self.pg_packet_sizes, count)) + + # send packets and verify received packets + self.send_and_verify_pkts(self.pg3, pkts, self.pg4, + self.compare_rx_tx_packet_T_Insert) + + # remove the interface l2 input feature + r = self.vapi.input_acl_set_interface( + is_add=0, + sw_if_index=self.pg3.sw_if_index, + ip6_table_index=table_index) + self.assertIsNotNone(r, + msg='No response msg for input_acl_set_interface') + + # log the ip6 inacl after cleaning + self.logger.info(self.vapi.cli("show inacl type ip6")) + + # log the localsid counters + self.logger.info(self.vapi.cli("show sr localsid")) + + # remove classifier SR steering + # classifier_steering.remove_vpp_config() + self.logger.info(self.vapi.cli("show sr steering policies")) + + # remove SR Policies + self.sr_policy.remove_vpp_config() + self.logger.info(self.vapi.cli("show sr policies")) + + # remove classify session and table + r = self.vapi.classify_add_del_session( + 0, + table_index, + binascii.unhexlify(match)) + self.assertIsNotNone(r, msg='No response msg for add_del_session') + + r = self.vapi.classify_add_del_table( + 0, + binascii.unhexlify(mask), + table_index=table_index) + self.assertIsNotNone(r, msg='No response msg for add_del_table') + + self.logger.info(self.vapi.cli("show classify table")) + + # remove FIB entries + # done by tearDown + + # cleanup interfaces + self.teardown_interfaces() + def compare_rx_tx_packet_T_Encaps(self, tx_pkt, rx_pkt): """ Compare input and output packet after passing T.Encaps diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py index 893ef0d89b9..66126c599ae 100644 --- a/test/vpp_papi_provider.py +++ b/test/vpp_papi_provider.py @@ -2753,3 +2753,13 @@ class VppPapiProvider(object): return self.api( self.papi.bier_disp_entry_dump, {'bde_tbl_id': bdti}) + + def add_node_next(self, node_name, next_name): + """ Set the next node for a given node request + + :param node_name: + :param next_name: + """ + return self.api(self.papi.add_node_next, + {'node_name': node_name, + 'next_name': next_name}) |