@@ -132,23 +132,6 @@ static void efx_tc_free_action_set_list(struct efx_nic *efx,
132132 /* Don't kfree, as acts is embedded inside a struct efx_tc_flow_rule */
133133}
134134
135- static void efx_tc_flow_free (void * ptr , void * arg )
136- {
137- struct efx_tc_flow_rule * rule = ptr ;
138- struct efx_nic * efx = arg ;
139-
140- netif_err (efx , drv , efx -> net_dev ,
141- "tc rule %lx still present at teardown, removing\n" ,
142- rule -> cookie );
143-
144- efx_mae_delete_rule (efx , rule -> fw_id );
145-
146- /* Release entries in subsidiary tables */
147- efx_tc_free_action_set_list (efx , & rule -> acts , true);
148-
149- kfree (rule );
150- }
151-
152135/* Boilerplate for the simple 'copy a field' cases */
153136#define _MAP_KEY_AND_MASK (_name , _type , _tcget , _tcfield , _field ) \
154137if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_##_name)) { \
@@ -219,6 +202,7 @@ static int efx_tc_flower_parse_match(struct efx_nic *efx,
219202 BIT (FLOW_DISSECTOR_KEY_ENC_KEYID ) |
220203 BIT (FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS ) |
221204 BIT (FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS ) |
205+ BIT (FLOW_DISSECTOR_KEY_ENC_IP ) |
222206 BIT (FLOW_DISSECTOR_KEY_ENC_PORTS ) |
223207 BIT (FLOW_DISSECTOR_KEY_ENC_CONTROL ) |
224208 BIT (FLOW_DISSECTOR_KEY_TCP ) |
@@ -363,20 +347,48 @@ static int efx_tc_flower_parse_match(struct efx_nic *efx,
363347 return 0 ;
364348}
365349
350+ static void efx_tc_flower_release_encap_match (struct efx_nic * efx ,
351+ struct efx_tc_encap_match * encap )
352+ {
353+ int rc ;
354+
355+ if (!refcount_dec_and_test (& encap -> ref ))
356+ return ; /* still in use */
357+
358+ if (encap -> type == EFX_TC_EM_DIRECT ) {
359+ rc = efx_mae_unregister_encap_match (efx , encap );
360+ if (rc )
361+ /* Display message but carry on and remove entry from our
362+ * SW tables, because there's not much we can do about it.
363+ */
364+ netif_err (efx , drv , efx -> net_dev ,
365+ "Failed to release encap match %#x, rc %d\n" ,
366+ encap -> fw_id , rc );
367+ }
368+ rhashtable_remove_fast (& efx -> tc -> encap_match_ht , & encap -> linkage ,
369+ efx_tc_encap_match_ht_params );
370+ if (encap -> pseudo )
371+ efx_tc_flower_release_encap_match (efx , encap -> pseudo );
372+ kfree (encap );
373+ }
374+
366375static int efx_tc_flower_record_encap_match (struct efx_nic * efx ,
367376 struct efx_tc_match * match ,
368377 enum efx_encap_type type ,
378+ enum efx_tc_em_pseudo_type em_type ,
379+ u8 child_ip_tos_mask ,
380+ __be16 child_udp_sport_mask ,
369381 struct netlink_ext_ack * extack )
370382{
371- struct efx_tc_encap_match * encap , * old ;
383+ struct efx_tc_encap_match * encap , * old , * pseudo = NULL ;
372384 bool ipv6 = false;
373385 int rc ;
374386
375387 /* We require that the socket-defining fields (IP addrs and UDP dest
376- * port) are present and exact-match. Other fields are currently not
377- * allowed. This meets what OVS will ask for, and means that we don't
378- * need to handle difficult checks for overlapping matches as could
379- * come up if we allowed masks or varying sets of match fields .
388+ * port) are present and exact-match. Other fields may only be used
389+ * if the field-set (and any masks) are the same for all encap
390+ * matches on the same <sip,dip,dport> tuple; this is enforced by
391+ * pseudo encap matches .
380392 */
381393 if (match -> mask .enc_dst_ip | match -> mask .enc_src_ip ) {
382394 if (!IS_ALL_ONES (match -> mask .enc_dst_ip )) {
@@ -414,29 +426,42 @@ static int efx_tc_flower_record_encap_match(struct efx_nic *efx,
414426 NL_SET_ERR_MSG_MOD (extack , "Egress encap match is not exact on dst UDP port" );
415427 return - EOPNOTSUPP ;
416428 }
417- if (match -> mask .enc_sport ) {
418- NL_SET_ERR_MSG_MOD (extack , "Egress encap match on src UDP port not supported" );
419- return - EOPNOTSUPP ;
420- }
421- if (match -> mask .enc_ip_tos ) {
422- NL_SET_ERR_MSG_MOD (extack , "Egress encap match on IP ToS not supported" );
423- return - EOPNOTSUPP ;
429+ if (match -> mask .enc_sport || match -> mask .enc_ip_tos ) {
430+ struct efx_tc_match pmatch = * match ;
431+
432+ if (em_type == EFX_TC_EM_PSEUDO_MASK ) { /* can't happen */
433+ NL_SET_ERR_MSG_MOD (extack , "Bad recursion in egress encap match handler" );
434+ return - EOPNOTSUPP ;
435+ }
436+ pmatch .value .enc_ip_tos = 0 ;
437+ pmatch .mask .enc_ip_tos = 0 ;
438+ pmatch .value .enc_sport = 0 ;
439+ pmatch .mask .enc_sport = 0 ;
440+ rc = efx_tc_flower_record_encap_match (efx , & pmatch , type ,
441+ EFX_TC_EM_PSEUDO_MASK ,
442+ match -> mask .enc_ip_tos ,
443+ match -> mask .enc_sport ,
444+ extack );
445+ if (rc )
446+ return rc ;
447+ pseudo = pmatch .encap ;
424448 }
425449 if (match -> mask .enc_ip_ttl ) {
426450 NL_SET_ERR_MSG_MOD (extack , "Egress encap match on IP TTL not supported" );
427- return - EOPNOTSUPP ;
451+ rc = - EOPNOTSUPP ;
452+ goto fail_pseudo ;
428453 }
429454
430- rc = efx_mae_check_encap_match_caps (efx , ipv6 , extack );
431- if (rc ) {
432- NL_SET_ERR_MSG_FMT_MOD (extack , "MAE hw reports no support for IPv%d encap matches" ,
433- ipv6 ? 6 : 4 );
434- return - EOPNOTSUPP ;
435- }
455+ rc = efx_mae_check_encap_match_caps (efx , ipv6 , match -> mask .enc_ip_tos ,
456+ match -> mask .enc_sport , extack );
457+ if (rc )
458+ goto fail_pseudo ;
436459
437460 encap = kzalloc (sizeof (* encap ), GFP_USER );
438- if (!encap )
439- return - ENOMEM ;
461+ if (!encap ) {
462+ rc = - ENOMEM ;
463+ goto fail_pseudo ;
464+ }
440465 encap -> src_ip = match -> value .enc_src_ip ;
441466 encap -> dst_ip = match -> value .enc_dst_ip ;
442467#ifdef CONFIG_IPV6
@@ -445,12 +470,66 @@ static int efx_tc_flower_record_encap_match(struct efx_nic *efx,
445470#endif
446471 encap -> udp_dport = match -> value .enc_dport ;
447472 encap -> tun_type = type ;
473+ encap -> ip_tos = match -> value .enc_ip_tos ;
474+ encap -> ip_tos_mask = match -> mask .enc_ip_tos ;
475+ encap -> child_ip_tos_mask = child_ip_tos_mask ;
476+ encap -> udp_sport = match -> value .enc_sport ;
477+ encap -> udp_sport_mask = match -> mask .enc_sport ;
478+ encap -> child_udp_sport_mask = child_udp_sport_mask ;
479+ encap -> type = em_type ;
480+ encap -> pseudo = pseudo ;
448481 old = rhashtable_lookup_get_insert_fast (& efx -> tc -> encap_match_ht ,
449482 & encap -> linkage ,
450483 efx_tc_encap_match_ht_params );
451484 if (old ) {
452485 /* don't need our new entry */
453486 kfree (encap );
487+ if (pseudo ) /* don't need our new pseudo either */
488+ efx_tc_flower_release_encap_match (efx , pseudo );
489+ /* check old and new em_types are compatible */
490+ switch (old -> type ) {
491+ case EFX_TC_EM_DIRECT :
492+ /* old EM is in hardware, so mustn't overlap with a
493+ * pseudo, but may be shared with another direct EM
494+ */
495+ if (em_type == EFX_TC_EM_DIRECT )
496+ break ;
497+ NL_SET_ERR_MSG_MOD (extack , "Pseudo encap match conflicts with existing direct entry" );
498+ return - EEXIST ;
499+ case EFX_TC_EM_PSEUDO_MASK :
500+ /* old EM is protecting a ToS- or src port-qualified
501+ * filter, so may only be shared with another pseudo
502+ * for the same ToS and src port masks.
503+ */
504+ if (em_type != EFX_TC_EM_PSEUDO_MASK ) {
505+ NL_SET_ERR_MSG_FMT_MOD (extack ,
506+ "%s encap match conflicts with existing pseudo(MASK) entry" ,
507+ encap -> type ? "Pseudo" : "Direct" );
508+ return - EEXIST ;
509+ }
510+ if (child_ip_tos_mask != old -> child_ip_tos_mask ) {
511+ NL_SET_ERR_MSG_FMT_MOD (extack ,
512+ "Pseudo encap match for TOS mask %#04x conflicts with existing pseudo(MASK) entry for TOS mask %#04x" ,
513+ child_ip_tos_mask ,
514+ old -> child_ip_tos_mask );
515+ return - EEXIST ;
516+ }
517+ if (child_udp_sport_mask != old -> child_udp_sport_mask ) {
518+ NL_SET_ERR_MSG_FMT_MOD (extack ,
519+ "Pseudo encap match for UDP src port mask %#x conflicts with existing pseudo(MASK) entry for mask %#x" ,
520+ child_udp_sport_mask ,
521+ old -> child_udp_sport_mask );
522+ return - EEXIST ;
523+ }
524+ break ;
525+ default : /* Unrecognised pseudo-type. Just say no */
526+ NL_SET_ERR_MSG_FMT_MOD (extack ,
527+ "%s encap match conflicts with existing pseudo(%d) entry" ,
528+ encap -> type ? "Pseudo" : "Direct" ,
529+ old -> type );
530+ return - EEXIST ;
531+ }
532+ /* check old and new tun_types are compatible */
454533 if (old -> tun_type != type ) {
455534 NL_SET_ERR_MSG_FMT_MOD (extack ,
456535 "Egress encap match with conflicting tun_type %u != %u" ,
@@ -462,10 +541,12 @@ static int efx_tc_flower_record_encap_match(struct efx_nic *efx,
462541 /* existing entry found */
463542 encap = old ;
464543 } else {
465- rc = efx_mae_register_encap_match (efx , encap );
466- if (rc ) {
467- NL_SET_ERR_MSG_MOD (extack , "Failed to record egress encap match in HW" );
468- goto fail ;
544+ if (em_type == EFX_TC_EM_DIRECT ) {
545+ rc = efx_mae_register_encap_match (efx , encap );
546+ if (rc ) {
547+ NL_SET_ERR_MSG_MOD (extack , "Failed to record egress encap match in HW" );
548+ goto fail ;
549+ }
469550 }
470551 refcount_set (& encap -> ref , 1 );
471552 }
@@ -475,30 +556,12 @@ static int efx_tc_flower_record_encap_match(struct efx_nic *efx,
475556 rhashtable_remove_fast (& efx -> tc -> encap_match_ht , & encap -> linkage ,
476557 efx_tc_encap_match_ht_params );
477558 kfree (encap );
559+ fail_pseudo :
560+ if (pseudo )
561+ efx_tc_flower_release_encap_match (efx , pseudo );
478562 return rc ;
479563}
480564
481- static void efx_tc_flower_release_encap_match (struct efx_nic * efx ,
482- struct efx_tc_encap_match * encap )
483- {
484- int rc ;
485-
486- if (!refcount_dec_and_test (& encap -> ref ))
487- return ; /* still in use */
488-
489- rc = efx_mae_unregister_encap_match (efx , encap );
490- if (rc )
491- /* Display message but carry on and remove entry from our
492- * SW tables, because there's not much we can do about it.
493- */
494- netif_err (efx , drv , efx -> net_dev ,
495- "Failed to release encap match %#x, rc %d\n" ,
496- encap -> fw_id , rc );
497- rhashtable_remove_fast (& efx -> tc -> encap_match_ht , & encap -> linkage ,
498- efx_tc_encap_match_ht_params );
499- kfree (encap );
500- }
501-
502565static void efx_tc_delete_rule (struct efx_nic * efx , struct efx_tc_flow_rule * rule )
503566{
504567 efx_mae_delete_rule (efx , rule -> fw_id );
@@ -652,6 +715,7 @@ static int efx_tc_flower_replace_foreign(struct efx_nic *efx,
652715 }
653716
654717 rc = efx_tc_flower_record_encap_match (efx , & match , type ,
718+ EFX_TC_EM_DIRECT , 0 , 0 ,
655719 extack );
656720 if (rc )
657721 goto release ;
@@ -1454,6 +1518,21 @@ static void efx_tc_encap_match_free(void *ptr, void *__unused)
14541518 kfree (encap );
14551519}
14561520
1521+ static void efx_tc_flow_free (void * ptr , void * arg )
1522+ {
1523+ struct efx_tc_flow_rule * rule = ptr ;
1524+ struct efx_nic * efx = arg ;
1525+
1526+ netif_err (efx , drv , efx -> net_dev ,
1527+ "tc rule %lx still present at teardown, removing\n" ,
1528+ rule -> cookie );
1529+
1530+ /* Also releases entries in subsidiary tables */
1531+ efx_tc_delete_rule (efx , rule );
1532+
1533+ kfree (rule );
1534+ }
1535+
14571536int efx_init_struct_tc (struct efx_nic * efx )
14581537{
14591538 int rc ;
0 commit comments