back to topotato report
topotato coverage report
Current view: top level - bgpd - bgp_pbr.c (source / functions) Hit Total Coverage
Test: test_bgp_minimum_holdtime.py::TestBGPMinimumHoldtime Lines: 43 1615 2.7 %
Date: 2023-02-24 18:37:25 Functions: 15 70 21.4 %

          Line data    Source code
       1             : /*
       2             :  * BGP pbr
       3             :  * Copyright (C) 6WIND
       4             :  *
       5             :  * FRR is free software; you can redistribute it and/or modify it
       6             :  * under the terms of the GNU General Public License as published by the
       7             :  * Free Software Foundation; either version 2, or (at your option) any
       8             :  * later version.
       9             :  *
      10             :  * FRR is distributed in the hope that it will be useful, but
      11             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      12             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13             :  * General Public License for more details.
      14             :  *
      15             :  * You should have received a copy of the GNU General Public License along
      16             :  * with this program; see the file COPYING; if not, write to the Free Software
      17             :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      18             :  */
      19             : 
      20             : #include "zebra.h"
      21             : #include "prefix.h"
      22             : #include "zclient.h"
      23             : #include "jhash.h"
      24             : #include "pbr.h"
      25             : 
      26             : #include "lib/printfrr.h"
      27             : 
      28             : #include "bgpd/bgpd.h"
      29             : #include "bgpd/bgp_pbr.h"
      30             : #include "bgpd/bgp_debug.h"
      31             : #include "bgpd/bgp_flowspec_util.h"
      32             : #include "bgpd/bgp_ecommunity.h"
      33             : #include "bgpd/bgp_route.h"
      34             : #include "bgpd/bgp_attr.h"
      35             : #include "bgpd/bgp_zebra.h"
      36             : #include "bgpd/bgp_mplsvpn.h"
      37             : #include "bgpd/bgp_flowspec_private.h"
      38             : #include "bgpd/bgp_errors.h"
      39             : 
      40           6 : DEFINE_MTYPE_STATIC(BGPD, PBR_MATCH_ENTRY, "PBR match entry");
      41           6 : DEFINE_MTYPE_STATIC(BGPD, PBR_MATCH, "PBR match");
      42           6 : DEFINE_MTYPE_STATIC(BGPD, PBR_ACTION, "PBR action");
      43           6 : DEFINE_MTYPE_STATIC(BGPD, PBR_RULE, "PBR rule");
      44           6 : DEFINE_MTYPE_STATIC(BGPD, PBR, "BGP PBR Context");
      45           6 : DEFINE_MTYPE_STATIC(BGPD, PBR_VALMASK, "BGP PBR Val Mask Value");
      46             : 
      47             : /* chain strings too long to fit in one line */
      48             : #define FSPEC_ACTION_EXCEED_LIMIT "flowspec actions exceeds limit"
      49             : #define IPV6_FRAGMENT_INVALID "fragment not valid for IPv6 for this implementation"
      50             : 
      51           0 : RB_GENERATE(bgp_pbr_interface_head, bgp_pbr_interface,
      52             :             id_entry, bgp_pbr_interface_compare);
      53             : struct bgp_pbr_interface_head ifaces_by_name_ipv4 =
      54             :         RB_INITIALIZER(&ifaces_by_name_ipv4);
      55             : 
      56             : static int bgp_pbr_match_counter_unique;
      57             : static int bgp_pbr_match_entry_counter_unique;
      58             : static int bgp_pbr_action_counter_unique;
      59             : static int bgp_pbr_match_iptable_counter_unique;
      60             : 
      61             : struct bgp_pbr_match_iptable_unique {
      62             :         uint32_t unique;
      63             :         struct bgp_pbr_match *bpm_found;
      64             : };
      65             : 
      66             : struct bgp_pbr_match_entry_unique {
      67             :         uint32_t unique;
      68             :         struct bgp_pbr_match_entry *bpme_found;
      69             : };
      70             : 
      71             : struct bgp_pbr_action_unique {
      72             :         uint32_t unique;
      73             :         struct bgp_pbr_action *bpa_found;
      74             : };
      75             : 
      76             : struct bgp_pbr_rule_unique {
      77             :         uint32_t unique;
      78             :         struct bgp_pbr_rule *bpr_found;
      79             : };
      80             : 
      81           0 : static int bgp_pbr_rule_walkcb(struct hash_bucket *bucket, void *arg)
      82             : {
      83           0 :         struct bgp_pbr_rule *bpr = (struct bgp_pbr_rule *)bucket->data;
      84           0 :         struct bgp_pbr_rule_unique *bpru = (struct bgp_pbr_rule_unique *)
      85             :                 arg;
      86           0 :         uint32_t unique = bpru->unique;
      87             : 
      88           0 :         if (bpr->unique == unique) {
      89           0 :                 bpru->bpr_found = bpr;
      90           0 :                 return HASHWALK_ABORT;
      91             :         }
      92             :         return HASHWALK_CONTINUE;
      93             : }
      94             : 
      95           0 : static int bgp_pbr_action_walkcb(struct hash_bucket *bucket, void *arg)
      96             : {
      97           0 :         struct bgp_pbr_action *bpa = (struct bgp_pbr_action *)bucket->data;
      98           0 :         struct bgp_pbr_action_unique *bpau = (struct bgp_pbr_action_unique *)
      99             :                 arg;
     100           0 :         uint32_t unique = bpau->unique;
     101             : 
     102           0 :         if (bpa->unique == unique) {
     103           0 :                 bpau->bpa_found = bpa;
     104           0 :                 return HASHWALK_ABORT;
     105             :         }
     106             :         return HASHWALK_CONTINUE;
     107             : }
     108             : 
     109           0 : static int bgp_pbr_match_entry_walkcb(struct hash_bucket *bucket, void *arg)
     110             : {
     111           0 :         struct bgp_pbr_match_entry *bpme =
     112             :                 (struct bgp_pbr_match_entry *)bucket->data;
     113           0 :         struct bgp_pbr_match_entry_unique *bpmeu =
     114             :                 (struct bgp_pbr_match_entry_unique *)arg;
     115           0 :         uint32_t unique = bpmeu->unique;
     116             : 
     117           0 :         if (bpme->unique == unique) {
     118           0 :                 bpmeu->bpme_found = bpme;
     119           0 :                 return HASHWALK_ABORT;
     120             :         }
     121             :         return HASHWALK_CONTINUE;
     122             : }
     123             : 
     124             : struct bgp_pbr_match_ipsetname {
     125             :         char *ipsetname;
     126             :         struct bgp_pbr_match *bpm_found;
     127             : };
     128             : 
     129           0 : static int bgp_pbr_match_pername_walkcb(struct hash_bucket *bucket, void *arg)
     130             : {
     131           0 :         struct bgp_pbr_match *bpm = (struct bgp_pbr_match *)bucket->data;
     132           0 :         struct bgp_pbr_match_ipsetname *bpmi =
     133             :                 (struct bgp_pbr_match_ipsetname *)arg;
     134           0 :         char *ipset_name = bpmi->ipsetname;
     135             : 
     136           0 :         if (!strncmp(ipset_name, bpm->ipset_name,
     137             :                      ZEBRA_IPSET_NAME_SIZE)) {
     138           0 :                 bpmi->bpm_found = bpm;
     139           0 :                 return HASHWALK_ABORT;
     140             :         }
     141             :         return HASHWALK_CONTINUE;
     142             : }
     143             : 
     144           0 : static int bgp_pbr_match_iptable_walkcb(struct hash_bucket *bucket, void *arg)
     145             : {
     146           0 :         struct bgp_pbr_match *bpm = (struct bgp_pbr_match *)bucket->data;
     147           0 :         struct bgp_pbr_match_iptable_unique *bpmiu =
     148             :                 (struct bgp_pbr_match_iptable_unique *)arg;
     149           0 :         uint32_t unique = bpmiu->unique;
     150             : 
     151           0 :         if (bpm->unique2 == unique) {
     152           0 :                 bpmiu->bpm_found = bpm;
     153           0 :                 return HASHWALK_ABORT;
     154             :         }
     155             :         return HASHWALK_CONTINUE;
     156             : }
     157             : 
     158             : struct bgp_pbr_match_unique {
     159             :         uint32_t unique;
     160             :         struct bgp_pbr_match *bpm_found;
     161             : };
     162             : 
     163           0 : static int bgp_pbr_match_walkcb(struct hash_bucket *bucket, void *arg)
     164             : {
     165           0 :         struct bgp_pbr_match *bpm = (struct bgp_pbr_match *)bucket->data;
     166           0 :         struct bgp_pbr_match_unique *bpmu = (struct bgp_pbr_match_unique *)
     167             :                 arg;
     168           0 :         uint32_t unique = bpmu->unique;
     169             : 
     170           0 :         if (bpm->unique == unique) {
     171           0 :                 bpmu->bpm_found = bpm;
     172           0 :                 return HASHWALK_ABORT;
     173             :         }
     174             :         return HASHWALK_CONTINUE;
     175             : }
     176             : 
     177           0 : static int snprintf_bgp_pbr_match_val(char *str, int len,
     178             :                                       struct bgp_pbr_match_val *mval,
     179             :                                       const char *prepend)
     180             : {
     181           0 :         char *ptr = str;
     182           0 :         int delta;
     183             : 
     184           0 :         if (prepend) {
     185           0 :                 delta = snprintf(ptr, len, "%s", prepend);
     186           0 :                 ptr += delta;
     187           0 :                 len -= delta;
     188             :         } else {
     189           0 :                 if (mval->unary_operator & OPERATOR_UNARY_OR) {
     190           0 :                         delta = snprintf(ptr, len, ", or ");
     191           0 :                         ptr += delta;
     192           0 :                         len -= delta;
     193             :                 }
     194           0 :                 if (mval->unary_operator & OPERATOR_UNARY_AND) {
     195           0 :                         delta = snprintf(ptr, len, ", and ");
     196           0 :                         ptr += delta;
     197           0 :                         len -= delta;
     198             :                 }
     199             :         }
     200           0 :         if (mval->compare_operator & OPERATOR_COMPARE_LESS_THAN) {
     201           0 :                 delta = snprintf(ptr, len, "<");
     202           0 :                 ptr += delta;
     203           0 :                 len -= delta;
     204             :         }
     205           0 :         if (mval->compare_operator & OPERATOR_COMPARE_GREATER_THAN) {
     206           0 :                 delta = snprintf(ptr, len, ">");
     207           0 :                 ptr += delta;
     208           0 :                 len -= delta;
     209             :         }
     210           0 :         if (mval->compare_operator & OPERATOR_COMPARE_EQUAL_TO) {
     211           0 :                 delta = snprintf(ptr, len, "=");
     212           0 :                 ptr += delta;
     213           0 :                 len -= delta;
     214             :         }
     215           0 :         if (mval->compare_operator & OPERATOR_COMPARE_EXACT_MATCH) {
     216           0 :                 delta = snprintf(ptr, len, "match");
     217           0 :                 ptr += delta;
     218           0 :                 len -= delta;
     219             :         }
     220           0 :         ptr += snprintf(ptr, len, " %u", mval->value);
     221           0 :         return (int)(ptr - str);
     222             : }
     223             : 
     224             : #define INCREMENT_DISPLAY(_ptr, _cnt, _len) do {        \
     225             :                 int sn_delta;                           \
     226             :                                                         \
     227             :                 if (_cnt) {                             \
     228             :                         sn_delta = snprintf((_ptr), (_len), "; ");\
     229             :                         (_len) -= sn_delta;             \
     230             :                         (_ptr) += sn_delta;             \
     231             :                 }                               \
     232             :                 (_cnt)++;       \
     233             :         } while (0)
     234             : 
     235             : /* this structure can be used for port range,
     236             :  * but also for other values range like packet length range
     237             :  */
     238             : struct bgp_pbr_range_port {
     239             :         uint16_t min_port;
     240             :         uint16_t max_port;
     241             : };
     242             : 
     243             : /* this structure can be used to filter with a mask
     244             :  * for instance it supports not instructions like for
     245             :  * tcpflags
     246             :  */
     247             : struct bgp_pbr_val_mask {
     248             :         uint16_t val;
     249             :         uint16_t mask;
     250             : };
     251             : 
     252             : /* this structure is used to pass instructs
     253             :  * so that BGP can create pbr instructions to ZEBRA
     254             :  */
     255             : struct bgp_pbr_filter {
     256             :         uint8_t type;
     257             :         vrf_id_t vrf_id;
     258             :         uint8_t family;
     259             :         struct prefix *src;
     260             :         struct prefix *dst;
     261             :         uint8_t bitmask_iprule;
     262             :         uint8_t protocol;
     263             :         struct bgp_pbr_range_port *pkt_len;
     264             :         struct bgp_pbr_range_port *src_port;
     265             :         struct bgp_pbr_range_port *dst_port;
     266             :         struct bgp_pbr_val_mask *tcp_flags;
     267             :         struct bgp_pbr_val_mask *dscp;
     268             :         struct bgp_pbr_val_mask *flow_label;
     269             :         struct bgp_pbr_val_mask *pkt_len_val;
     270             :         struct bgp_pbr_val_mask *fragment;
     271             : };
     272             : 
     273             : /* this structure is used to contain OR instructions
     274             :  * so that BGP can create multiple pbr instructions
     275             :  * to ZEBRA
     276             :  */
     277             : struct bgp_pbr_or_filter {
     278             :         struct list *tcpflags;
     279             :         struct list *dscp;
     280             :         struct list *flowlabel;
     281             :         struct list *pkt_len;
     282             :         struct list *fragment;
     283             :         struct list *icmp_type;
     284             :         struct list *icmp_code;
     285             : };
     286             : 
     287             : static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp,
     288             :                                                   struct bgp_path_info *path,
     289             :                                                   struct bgp_pbr_filter *bpf,
     290             :                                                   struct nexthop *nh,
     291             :                                                   float *rate);
     292             : 
     293             : static void bgp_pbr_dump_entry(struct bgp_pbr_filter *bpf, bool add);
     294             : 
     295           0 : static bool bgp_pbr_extract_enumerate_unary_opposite(
     296             :                                  uint8_t unary_operator,
     297             :                                  struct bgp_pbr_val_mask *and_valmask,
     298             :                                  struct list *or_valmask, uint32_t value,
     299             :                                  uint8_t type_entry)
     300             : {
     301           0 :         if (unary_operator == OPERATOR_UNARY_AND && and_valmask) {
     302           0 :                 if (type_entry == FLOWSPEC_TCP_FLAGS) {
     303           0 :                         and_valmask->mask |=
     304           0 :                                 TCP_HEADER_ALL_FLAGS &
     305             :                                 ~(value);
     306           0 :                 } else if (type_entry == FLOWSPEC_DSCP ||
     307           0 :                            type_entry == FLOWSPEC_FLOW_LABEL ||
     308           0 :                            type_entry == FLOWSPEC_PKT_LEN ||
     309           0 :                            type_entry == FLOWSPEC_FRAGMENT) {
     310           0 :                         and_valmask->val = value;
     311           0 :                         and_valmask->mask = 1; /* inverse */
     312             :                 }
     313           0 :         } else if (unary_operator == OPERATOR_UNARY_OR && or_valmask) {
     314           0 :                 and_valmask = XCALLOC(MTYPE_PBR_VALMASK,
     315             :                                       sizeof(struct bgp_pbr_val_mask));
     316           0 :                 if (type_entry == FLOWSPEC_TCP_FLAGS) {
     317           0 :                         and_valmask->val = TCP_HEADER_ALL_FLAGS;
     318           0 :                         and_valmask->mask |=
     319           0 :                                 TCP_HEADER_ALL_FLAGS &
     320             :                                 ~(value);
     321           0 :                 } else if (type_entry == FLOWSPEC_DSCP ||
     322           0 :                            type_entry == FLOWSPEC_FLOW_LABEL ||
     323           0 :                            type_entry == FLOWSPEC_FRAGMENT ||
     324           0 :                            type_entry == FLOWSPEC_PKT_LEN) {
     325           0 :                         and_valmask->val = value;
     326           0 :                         and_valmask->mask = 1; /* inverse */
     327             :                 }
     328           0 :                 listnode_add(or_valmask, and_valmask);
     329           0 :         } else if (type_entry == FLOWSPEC_ICMP_CODE ||
     330             :                    type_entry == FLOWSPEC_ICMP_TYPE)
     331             :                 return false;
     332             :         return true;
     333             : }
     334             : 
     335             : /* TCP : FIN and SYN -> val = ALL; mask = 3
     336             :  * TCP : not (FIN and SYN) -> val = ALL; mask = ALL & ~(FIN|RST)
     337             :  * other variables type: dscp, pkt len, fragment, flow label
     338             :  * - value is copied in bgp_pbr_val_mask->val value
     339             :  * - if negate form is identifierd, bgp_pbr_val_mask->mask set to 1
     340             :  */
     341           0 : static bool bgp_pbr_extract_enumerate_unary(struct bgp_pbr_match_val list[],
     342             :                                             int num, uint8_t unary_operator,
     343             :                                             void *valmask, uint8_t type_entry)
     344             : {
     345           0 :         int i = 0;
     346           0 :         struct bgp_pbr_val_mask *and_valmask = NULL;
     347           0 :         struct list *or_valmask = NULL;
     348           0 :         bool ret;
     349             : 
     350           0 :         if (valmask) {
     351           0 :                 if (unary_operator == OPERATOR_UNARY_AND) {
     352           0 :                         and_valmask = (struct bgp_pbr_val_mask *)valmask;
     353           0 :                         memset(and_valmask, 0, sizeof(struct bgp_pbr_val_mask));
     354           0 :                 } else if (unary_operator == OPERATOR_UNARY_OR) {
     355           0 :                         or_valmask = (struct list *)valmask;
     356             :                 }
     357             :         }
     358           0 :         for (i = 0; i < num; i++) {
     359           0 :                 if (i != 0 && list[i].unary_operator !=
     360             :                     unary_operator)
     361             :                         return false;
     362           0 :                 if (!(list[i].compare_operator &
     363             :                     OPERATOR_COMPARE_EQUAL_TO) &&
     364             :                     !(list[i].compare_operator &
     365             :                       OPERATOR_COMPARE_EXACT_MATCH)) {
     366           0 :                         if ((list[i].compare_operator &
     367             :                              OPERATOR_COMPARE_LESS_THAN) &&
     368             :                             (list[i].compare_operator &
     369             :                              OPERATOR_COMPARE_GREATER_THAN)) {
     370           0 :                                 ret = bgp_pbr_extract_enumerate_unary_opposite(
     371             :                                                  unary_operator, and_valmask,
     372           0 :                                                  or_valmask, list[i].value,
     373             :                                                  type_entry);
     374           0 :                                 if (!ret)
     375             :                                         return ret;
     376           0 :                                 continue;
     377             :                         }
     378             :                         return false;
     379             :                 }
     380           0 :                 if (unary_operator == OPERATOR_UNARY_AND && and_valmask) {
     381           0 :                         if (type_entry == FLOWSPEC_TCP_FLAGS)
     382           0 :                                 and_valmask->mask |=
     383           0 :                                         TCP_HEADER_ALL_FLAGS & list[i].value;
     384           0 :                 } else if (unary_operator == OPERATOR_UNARY_OR && or_valmask) {
     385           0 :                         and_valmask = XCALLOC(MTYPE_PBR_VALMASK,
     386             :                                               sizeof(struct bgp_pbr_val_mask));
     387           0 :                         if (type_entry == FLOWSPEC_TCP_FLAGS) {
     388           0 :                                 and_valmask->val = TCP_HEADER_ALL_FLAGS;
     389           0 :                                 and_valmask->mask |=
     390           0 :                                         TCP_HEADER_ALL_FLAGS & list[i].value;
     391           0 :                         } else if (type_entry == FLOWSPEC_DSCP ||
     392           0 :                                    type_entry == FLOWSPEC_FLOW_LABEL ||
     393           0 :                                    type_entry == FLOWSPEC_ICMP_TYPE ||
     394             :                                    type_entry == FLOWSPEC_ICMP_CODE ||
     395           0 :                                    type_entry == FLOWSPEC_FRAGMENT ||
     396           0 :                                    type_entry == FLOWSPEC_PKT_LEN)
     397           0 :                                 and_valmask->val = list[i].value;
     398           0 :                         listnode_add(or_valmask, and_valmask);
     399             :                 }
     400             :         }
     401           0 :         if (unary_operator == OPERATOR_UNARY_AND && and_valmask
     402           0 :             && type_entry == FLOWSPEC_TCP_FLAGS)
     403           0 :                 and_valmask->val = TCP_HEADER_ALL_FLAGS;
     404             :         return true;
     405             : }
     406             : 
     407             : /* if unary operator can either be UNARY_OR/AND/OR-AND.
     408             :  * in the latter case, combinationf of both is not handled
     409             :  */
     410           0 : static bool bgp_pbr_extract_enumerate(struct bgp_pbr_match_val list[],
     411             :                                       int num, uint8_t unary_operator,
     412             :                                       void *valmask, uint8_t type_entry)
     413             : {
     414           0 :         bool ret;
     415           0 :         uint8_t unary_operator_val;
     416           0 :         bool double_check = false;
     417             : 
     418           0 :         if ((unary_operator & OPERATOR_UNARY_OR) &&
     419             :             (unary_operator & OPERATOR_UNARY_AND)) {
     420             :                 unary_operator_val = OPERATOR_UNARY_AND;
     421             :                 double_check = true;
     422             :         } else
     423           0 :                 unary_operator_val = unary_operator;
     424           0 :         ret = bgp_pbr_extract_enumerate_unary(list, num, unary_operator_val,
     425             :                                               valmask, type_entry);
     426           0 :         if (!ret && double_check)
     427           0 :                 ret = bgp_pbr_extract_enumerate_unary(list, num,
     428             :                                                       OPERATOR_UNARY_OR,
     429             :                                                       valmask,
     430             :                                                       type_entry);
     431           0 :         return ret;
     432             : }
     433             : 
     434             : /* returns the unary operator that is in the list
     435             :  * return 0 if both operators are used
     436             :  */
     437           0 : static uint8_t bgp_pbr_match_val_get_operator(struct bgp_pbr_match_val list[],
     438             :                                               int num)
     439             : 
     440             : {
     441           0 :         int i;
     442           0 :         uint8_t unary_operator = OPERATOR_UNARY_AND;
     443             : 
     444           0 :         for (i = 0; i < num; i++) {
     445           0 :                 if (i == 0)
     446           0 :                         continue;
     447           0 :                 if (list[i].unary_operator & OPERATOR_UNARY_OR)
     448           0 :                         unary_operator = OPERATOR_UNARY_OR;
     449           0 :                 if ((list[i].unary_operator & OPERATOR_UNARY_AND
     450           0 :                      && unary_operator == OPERATOR_UNARY_OR) ||
     451             :                     (list[i].unary_operator & OPERATOR_UNARY_OR
     452           0 :                      && unary_operator == OPERATOR_UNARY_AND))
     453             :                         return 0;
     454             :         }
     455             :         return unary_operator;
     456             : }
     457             : 
     458             : 
     459             : /* return true if extraction ok
     460             :  */
     461           0 : static bool bgp_pbr_extract(struct bgp_pbr_match_val list[],
     462             :                             int num,
     463             :                             struct bgp_pbr_range_port *range)
     464             : {
     465           0 :         int i = 0;
     466           0 :         bool exact_match = false;
     467             : 
     468           0 :         if (range)
     469           0 :                 memset(range, 0, sizeof(struct bgp_pbr_range_port));
     470             : 
     471           0 :         if (num > 2)
     472             :                 return false;
     473           0 :         for (i = 0; i < num; i++) {
     474           0 :                 if (i != 0 && (list[i].compare_operator ==
     475             :                                OPERATOR_COMPARE_EQUAL_TO))
     476             :                         return false;
     477           0 :                 if (i == 0 && (list[i].compare_operator ==
     478             :                                OPERATOR_COMPARE_EQUAL_TO)) {
     479           0 :                         if (range)
     480           0 :                                 range->min_port = list[i].value;
     481             :                         exact_match = true;
     482             :                 }
     483           0 :                 if (exact_match && i > 0)
     484             :                         return false;
     485           0 :                 if (list[i].compare_operator ==
     486             :                     (OPERATOR_COMPARE_GREATER_THAN +
     487             :                      OPERATOR_COMPARE_EQUAL_TO)) {
     488           0 :                         if (range)
     489           0 :                                 range->min_port = list[i].value;
     490           0 :                 } else if (list[i].compare_operator ==
     491             :                            (OPERATOR_COMPARE_LESS_THAN +
     492             :                             OPERATOR_COMPARE_EQUAL_TO)) {
     493           0 :                         if (range)
     494           0 :                                 range->max_port = list[i].value;
     495           0 :                 } else if (list[i].compare_operator ==
     496             :                            OPERATOR_COMPARE_LESS_THAN) {
     497           0 :                         if (range)
     498           0 :                                 range->max_port = list[i].value - 1;
     499           0 :                 } else if (list[i].compare_operator ==
     500             :                            OPERATOR_COMPARE_GREATER_THAN) {
     501           0 :                         if (range)
     502           0 :                                 range->min_port = list[i].value + 1;
     503             :                 }
     504             :         }
     505             :         return true;
     506             : }
     507             : 
     508           0 : static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main *api)
     509             : {
     510           0 :         bool enumerate_icmp = false;
     511             : 
     512           0 :         if (api->type ==  BGP_PBR_UNDEFINED) {
     513           0 :                 if (BGP_DEBUG(pbr, PBR))
     514           0 :                         zlog_debug("BGP: pbr entry undefined. cancel.");
     515           0 :                 return 0;
     516             :         }
     517             :         /* because bgp pbr entry may contain unsupported
     518             :          * combinations, a message will be displayed here if
     519             :          * not supported.
     520             :          * for now, only match/set supported is
     521             :          * - combination src/dst => redirect nexthop [ + rate]
     522             :          * - combination src/dst => redirect VRF [ + rate]
     523             :          * - combination src/dst => drop
     524             :          * - combination srcport + @IP
     525             :          */
     526           0 :         if (api->match_protocol_num > 1) {
     527           0 :                 if (BGP_DEBUG(pbr, PBR))
     528           0 :                         zlog_debug("BGP: match protocol operations:multiple protocols ( %d). ignoring.",
     529             :                                  api->match_protocol_num);
     530           0 :                 return 0;
     531             :         }
     532           0 :         if (api->src_prefix_offset > 0 ||
     533             :             api->dst_prefix_offset > 0) {
     534           0 :                 if (BGP_DEBUG(pbr, PBR))
     535           0 :                         zlog_debug("BGP: match prefix offset:"
     536             :                                    "implementation does not support it.");
     537           0 :                 return 0;
     538             :         }
     539           0 :         if (api->match_protocol_num == 1 &&
     540           0 :             api->protocol[0].value != PROTOCOL_UDP &&
     541             :             api->protocol[0].value != PROTOCOL_ICMP &&
     542             :             api->protocol[0].value != PROTOCOL_ICMPV6 &&
     543             :             api->protocol[0].value != PROTOCOL_TCP) {
     544           0 :                 if (BGP_DEBUG(pbr, PBR))
     545           0 :                         zlog_debug("BGP: match protocol operations:protocol (%d) not supported. ignoring",
     546             :                                    api->match_protocol_num);
     547           0 :                 return 0;
     548             :         }
     549           0 :         if (!bgp_pbr_extract(api->src_port, api->match_src_port_num, NULL)) {
     550           0 :                 if (BGP_DEBUG(pbr, PBR))
     551           0 :                         zlog_debug("BGP: match src port operations:too complex. ignoring.");
     552           0 :                 return 0;
     553             :         }
     554           0 :         if (!bgp_pbr_extract(api->dst_port, api->match_dst_port_num, NULL)) {
     555           0 :                 if (BGP_DEBUG(pbr, PBR))
     556           0 :                         zlog_debug("BGP: match dst port operations:too complex. ignoring.");
     557           0 :                 return 0;
     558             :         }
     559           0 :         if (!bgp_pbr_extract_enumerate(api->tcpflags,
     560           0 :                                        api->match_tcpflags_num,
     561             :                                        OPERATOR_UNARY_AND |
     562             :                                        OPERATOR_UNARY_OR, NULL,
     563             :                                        FLOWSPEC_TCP_FLAGS)) {
     564           0 :                 if (BGP_DEBUG(pbr, PBR))
     565           0 :                         zlog_debug("BGP: match tcp flags:too complex. ignoring.");
     566           0 :                 return 0;
     567             :         }
     568           0 :         if (!bgp_pbr_extract(api->icmp_type, api->match_icmp_type_num, NULL)) {
     569           0 :                 if (!bgp_pbr_extract_enumerate(api->icmp_type,
     570             :                                                api->match_icmp_type_num,
     571             :                                                OPERATOR_UNARY_OR, NULL,
     572             :                                                FLOWSPEC_ICMP_TYPE)) {
     573           0 :                         if (BGP_DEBUG(pbr, PBR))
     574           0 :                                 zlog_debug("BGP: match icmp type operations:too complex. ignoring.");
     575           0 :                         return 0;
     576             :                 }
     577             :                 enumerate_icmp = true;
     578             :         }
     579           0 :         if (!bgp_pbr_extract(api->icmp_code, api->match_icmp_code_num, NULL)) {
     580           0 :                 if (!bgp_pbr_extract_enumerate(api->icmp_code,
     581             :                                                api->match_icmp_code_num,
     582             :                                                OPERATOR_UNARY_OR, NULL,
     583             :                                                FLOWSPEC_ICMP_CODE)) {
     584           0 :                         if (BGP_DEBUG(pbr, PBR))
     585           0 :                                 zlog_debug("BGP: match icmp code operations:too complex. ignoring.");
     586           0 :                         return 0;
     587           0 :                 } else if (api->match_icmp_type_num > 1 &&
     588             :                            !enumerate_icmp) {
     589           0 :                         if (BGP_DEBUG(pbr, PBR))
     590           0 :                                 zlog_debug("BGP: match icmp code is enumerate, and icmp type is not. too complex. ignoring.");
     591           0 :                         return 0;
     592             :                 }
     593             :         }
     594           0 :         if (!bgp_pbr_extract(api->port, api->match_port_num, NULL)) {
     595           0 :                 if (BGP_DEBUG(pbr, PBR))
     596           0 :                         zlog_debug("BGP: match port operations:too complex. ignoring.");
     597           0 :                 return 0;
     598             :         }
     599           0 :         if (api->match_packet_length_num) {
     600           0 :                 bool ret;
     601             : 
     602           0 :                 ret = bgp_pbr_extract(api->packet_length,
     603             :                                       api->match_packet_length_num, NULL);
     604           0 :                 if (!ret)
     605           0 :                         ret = bgp_pbr_extract_enumerate(api->packet_length,
     606             :                                                 api->match_packet_length_num,
     607             :                                                 OPERATOR_UNARY_OR
     608             :                                                 | OPERATOR_UNARY_AND,
     609             :                                                 NULL, FLOWSPEC_PKT_LEN);
     610           0 :                 if (!ret) {
     611           0 :                         if (BGP_DEBUG(pbr, PBR))
     612           0 :                                 zlog_debug("BGP: match packet length operations:too complex. ignoring.");
     613           0 :                         return 0;
     614             :                 }
     615             :         }
     616           0 :         if (api->match_dscp_num) {
     617           0 :                 if (!bgp_pbr_extract_enumerate(api->dscp, api->match_dscp_num,
     618             :                                 OPERATOR_UNARY_OR | OPERATOR_UNARY_AND,
     619             :                                                NULL, FLOWSPEC_DSCP)) {
     620           0 :                         if (BGP_DEBUG(pbr, PBR))
     621           0 :                                 zlog_debug("BGP: match DSCP operations:too complex. ignoring.");
     622           0 :                         return 0;
     623             :                 }
     624             :         }
     625           0 :         if (api->match_flowlabel_num) {
     626           0 :                 if (api->afi == AFI_IP) {
     627           0 :                         if (BGP_DEBUG(pbr, PBR))
     628           0 :                                 zlog_debug("BGP: match Flow Label operations:"
     629             :                                            "Not for IPv4.");
     630           0 :                         return 0;
     631             :                 }
     632           0 :                 if (!bgp_pbr_extract_enumerate(api->flow_label,
     633             :                                                api->match_flowlabel_num,
     634             :                                 OPERATOR_UNARY_OR | OPERATOR_UNARY_AND,
     635             :                                                NULL, FLOWSPEC_FLOW_LABEL)) {
     636           0 :                         if (BGP_DEBUG(pbr, PBR))
     637           0 :                                 zlog_debug("BGP: match FlowLabel operations:"
     638             :                                            "too complex. ignoring.");
     639           0 :                         return 0;
     640             :                 }
     641           0 :                 if (BGP_DEBUG(pbr, PBR))
     642           0 :                         zlog_debug("BGP: match FlowLabel operations "
     643             :                                    "not supported. ignoring.");
     644           0 :                 return 0;
     645             :         }
     646           0 :         if (api->match_fragment_num) {
     647           0 :                 char fail_str[64];
     648           0 :                 bool success;
     649             : 
     650           0 :                 success = bgp_pbr_extract_enumerate(api->fragment,
     651             :                                                     api->match_fragment_num,
     652             :                                                     OPERATOR_UNARY_OR
     653             :                                                     | OPERATOR_UNARY_AND,
     654             :                                                     NULL, FLOWSPEC_FRAGMENT);
     655           0 :                 if (success) {
     656             :                         int i;
     657             : 
     658           0 :                         for (i = 0; i < api->match_fragment_num; i++) {
     659           0 :                                 if (api->fragment[i].value != 1 &&
     660           0 :                                     api->fragment[i].value != 2 &&
     661           0 :                                     api->fragment[i].value != 4 &&
     662             :                                     api->fragment[i].value != 8) {
     663           0 :                                         success = false;
     664           0 :                                         snprintf(
     665             :                                                 fail_str, sizeof(fail_str),
     666             :                                                 "Value not valid (%d) for this implementation",
     667             :                                                 api->fragment[i].value);
     668             :                                 }
     669           0 :                                 if (api->afi == AFI_IP6 &&
     670           0 :                                     api->fragment[i].value == 1) {
     671           0 :                                         success = false;
     672           0 :                                         snprintf(fail_str, sizeof(fail_str),
     673             :                                                  "IPv6 dont fragment match invalid (%d)",
     674             :                                                  api->fragment[i].value);
     675             :                                 }
     676             :                         }
     677           0 :                         if (api->afi == AFI_IP6) {
     678           0 :                                 success = false;
     679           0 :                                 snprintf(fail_str, sizeof(fail_str),
     680             :                                          "%s", IPV6_FRAGMENT_INVALID);
     681             :                         }
     682             :                 } else
     683           0 :                         snprintf(fail_str, sizeof(fail_str),
     684             :                                  "too complex. ignoring");
     685           0 :                 if (!success) {
     686           0 :                         if (BGP_DEBUG(pbr, PBR))
     687           0 :                                 zlog_debug("BGP: match fragment operation (%d) %s",
     688             :                                            api->match_fragment_num,
     689             :                                            fail_str);
     690           0 :                         return 0;
     691             :                 }
     692             :         }
     693             : 
     694             :         /* no combinations with both src_port and dst_port
     695             :          * or port with src_port and dst_port
     696             :          */
     697           0 :         if (api->match_src_port_num + api->match_dst_port_num +
     698           0 :             api->match_port_num > 3) {
     699           0 :                 if (BGP_DEBUG(pbr, PBR))
     700           0 :                         zlog_debug("BGP: match multiple port operations: too complex. ignoring.");
     701           0 :                 return 0;
     702             :         }
     703           0 :         if ((api->match_src_port_num || api->match_dst_port_num
     704           0 :              || api->match_port_num) && (api->match_icmp_type_num
     705           0 :                                          || api->match_icmp_code_num)) {
     706           0 :                 if (BGP_DEBUG(pbr, PBR))
     707           0 :                         zlog_debug("BGP: match multiple port/imcp operations: too complex. ignoring.");
     708           0 :                 return 0;
     709             :         }
     710             :         /* iprule only supports redirect IP */
     711           0 :         if (api->type == BGP_PBR_IPRULE) {
     712             :                 int i;
     713             : 
     714           0 :                 for (i = 0; i < api->action_num; i++) {
     715           0 :                         if (api->actions[i].action == ACTION_TRAFFICRATE &&
     716           0 :                             api->actions[i].u.r.rate == 0) {
     717           0 :                                 if (BGP_DEBUG(pbr, PBR)) {
     718           0 :                                         bgp_pbr_print_policy_route(api);
     719           0 :                                         zlog_debug("BGP: iprule match actions drop not supported");
     720             :                                 }
     721           0 :                                 return 0;
     722             :                         }
     723           0 :                         if (api->actions[i].action == ACTION_MARKING) {
     724           0 :                                 if (BGP_DEBUG(pbr, PBR)) {
     725           0 :                                         bgp_pbr_print_policy_route(api);
     726           0 :                                         zlog_warn("PBR: iprule set DSCP/Flow Label %u not supported",
     727             :                                                 api->actions[i].u.marking_dscp);
     728             :                                 }
     729             :                         }
     730           0 :                         if (api->actions[i].action == ACTION_REDIRECT) {
     731           0 :                                 if (BGP_DEBUG(pbr, PBR)) {
     732           0 :                                         bgp_pbr_print_policy_route(api);
     733           0 :                                         zlog_warn("PBR: iprule redirect VRF %u not supported",
     734             :                                                 api->actions[i].u.redirect_vrf);
     735             :                                 }
     736             :                         }
     737             :                 }
     738             : 
     739           0 :         } else if (!(api->match_bitmask & PREFIX_SRC_PRESENT) &&
     740             :                    !(api->match_bitmask & PREFIX_DST_PRESENT)) {
     741           0 :                 if (BGP_DEBUG(pbr, PBR)) {
     742           0 :                         bgp_pbr_print_policy_route(api);
     743           0 :                         zlog_debug("BGP: match actions without src or dst address can not operate. ignoring.");
     744             :                 }
     745           0 :                 return 0;
     746             :         }
     747             :         return 1;
     748             : }
     749             : 
     750             : /* return -1 if build or validation failed */
     751             : 
     752           0 : int bgp_pbr_build_and_validate_entry(const struct prefix *p,
     753             :                                      struct bgp_path_info *path,
     754             :                                      struct bgp_pbr_entry_main *api)
     755             : {
     756           0 :         int ret;
     757           0 :         uint32_t i, action_count = 0;
     758           0 :         struct ecommunity *ecom;
     759           0 :         struct ecommunity_val *ecom_eval;
     760           0 :         struct bgp_pbr_entry_action *api_action;
     761           0 :         struct prefix *src = NULL, *dst = NULL;
     762           0 :         int valid_prefix = 0;
     763           0 :         struct bgp_pbr_entry_action *api_action_redirect_ip = NULL;
     764           0 :         bool discard_action_found = false;
     765           0 :         afi_t afi = family2afi(p->u.prefix_flowspec.family);
     766             : 
     767             :         /* extract match from flowspec entries */
     768           0 :         ret = bgp_flowspec_match_rules_fill((uint8_t *)p->u.prefix_flowspec.ptr,
     769           0 :                                             p->u.prefix_flowspec.prefixlen, api, afi);
     770           0 :         if (ret < 0)
     771             :                 return -1;
     772             :         /* extract actiosn from flowspec ecom list */
     773           0 :         if (path && bgp_attr_get_ecommunity(path->attr)) {
     774             :                 ecom = bgp_attr_get_ecommunity(path->attr);
     775           0 :                 for (i = 0; i < ecom->size; i++) {
     776           0 :                         ecom_eval = (struct ecommunity_val *)
     777           0 :                                 (ecom->val + (i * ECOMMUNITY_SIZE));
     778           0 :                         action_count++;
     779           0 :                         if (action_count > ACTIONS_MAX_NUM) {
     780           0 :                                 if (BGP_DEBUG(pbr, PBR_ERROR))
     781           0 :                                         flog_err(
     782             :                                                 EC_BGP_FLOWSPEC_PACKET,
     783             :                                                 "%s: %s (max %u)",
     784             :                                                 __func__,
     785             :                                                 FSPEC_ACTION_EXCEED_LIMIT,
     786             :                                                 action_count);
     787             :                                 break;
     788             :                         }
     789           0 :                         api_action = &api->actions[action_count - 1];
     790             : 
     791           0 :                         if ((ecom_eval->val[1] ==
     792           0 :                              (char)ECOMMUNITY_REDIRECT_VRF) &&
     793           0 :                             (ecom_eval->val[0] ==
     794           0 :                              (char)ECOMMUNITY_ENCODE_TRANS_EXP ||
     795             :                              ecom_eval->val[0] ==
     796           0 :                              (char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_2 ||
     797             :                              ecom_eval->val[0] ==
     798           0 :                              (char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_3)) {
     799           0 :                                 struct ecommunity *eckey = ecommunity_new();
     800           0 :                                 struct ecommunity_val ecom_copy;
     801             : 
     802           0 :                                 memcpy(&ecom_copy, ecom_eval,
     803             :                                        sizeof(struct ecommunity_val));
     804           0 :                                 ecom_copy.val[0] &=
     805             :                                         ~ECOMMUNITY_ENCODE_TRANS_EXP;
     806           0 :                                 ecom_copy.val[1] = ECOMMUNITY_ROUTE_TARGET;
     807           0 :                                 ecommunity_add_val(eckey, &ecom_copy,
     808             :                                                    false, false);
     809             : 
     810           0 :                                 api_action->action = ACTION_REDIRECT;
     811           0 :                                 api_action->u.redirect_vrf =
     812           0 :                                         get_first_vrf_for_redirect_with_rt(
     813             :                                                                 eckey);
     814           0 :                                 ecommunity_free(&eckey);
     815           0 :                         } else if ((ecom_eval->val[0] ==
     816           0 :                                     (char)ECOMMUNITY_ENCODE_REDIRECT_IP_NH) &&
     817             :                                    (ecom_eval->val[1] ==
     818             :                                     (char)ECOMMUNITY_REDIRECT_IP_NH)) {
     819             :                                 /* in case the 2 ecom present,
     820             :                                  * do not overwrite
     821             :                                  * draft-ietf-idr-flowspec-redirect
     822             :                                  */
     823           0 :                                 if (api_action_redirect_ip &&
     824           0 :                                     p->u.prefix_flowspec.family == AF_INET) {
     825           0 :                                         if (api_action_redirect_ip->u
     826           0 :                                             .zr.redirect_ip_v4.s_addr
     827             :                                             != INADDR_ANY)
     828           0 :                                                 continue;
     829           0 :                                         if (path->attr->nexthop.s_addr
     830             :                                             == INADDR_ANY)
     831           0 :                                                 continue;
     832           0 :                                         api_action_redirect_ip->u.zr
     833           0 :                                                 .redirect_ip_v4.s_addr =
     834             :                                                 path->attr->nexthop.s_addr;
     835           0 :                                         api_action_redirect_ip->u.zr.duplicate
     836           0 :                                                 = ecom_eval->val[7];
     837           0 :                                         continue;
     838           0 :                                 } else if (api_action_redirect_ip &&
     839             :                                     p->u.prefix_flowspec.family == AF_INET6) {
     840           0 :                                         if (memcmp(&api_action_redirect_ip->u
     841             :                                                    .zr.redirect_ip_v6,
     842             :                                                    &in6addr_any,
     843             :                                                    sizeof(struct in6_addr)))
     844           0 :                                                 continue;
     845           0 :                                         if (path->attr->mp_nexthop_len == 0 ||
     846             :                                             path->attr->mp_nexthop_len ==
     847           0 :                                             BGP_ATTR_NHLEN_IPV4 ||
     848             :                                             path->attr->mp_nexthop_len ==
     849             :                                             BGP_ATTR_NHLEN_VPNV4)
     850           0 :                                                 continue;
     851           0 :                                         memcpy(&api_action_redirect_ip->u
     852             :                                                .zr.redirect_ip_v6,
     853             :                                                &path->attr->mp_nexthop_global,
     854             :                                                sizeof(struct in6_addr));
     855           0 :                                         api_action_redirect_ip->u.zr.duplicate
     856           0 :                                                 = ecom_eval->val[7];
     857           0 :                                         continue;
     858           0 :                                 } else if (p->u.prefix_flowspec.family ==
     859             :                                            AF_INET) {
     860           0 :                                         api_action->action = ACTION_REDIRECT_IP;
     861           0 :                                         api_action->u.zr.redirect_ip_v4.s_addr =
     862           0 :                                                 path->attr->nexthop.s_addr;
     863           0 :                                         api_action->u.zr.duplicate =
     864           0 :                                                 ecom_eval->val[7];
     865           0 :                                         api_action_redirect_ip = api_action;
     866           0 :                                 } else if (p->u.prefix_flowspec.family ==
     867             :                                            AF_INET6) {
     868           0 :                                         api_action->action = ACTION_REDIRECT_IP;
     869           0 :                                         memcpy(&api_action->u
     870             :                                                .zr.redirect_ip_v6,
     871           0 :                                                &path->attr->mp_nexthop_global,
     872             :                                                sizeof(struct in6_addr));
     873           0 :                                         api_action->u.zr.duplicate
     874           0 :                                                 = ecom_eval->val[7];
     875           0 :                                         api_action_redirect_ip = api_action;
     876             :                                 }
     877           0 :                         } else if ((ecom_eval->val[0] ==
     878           0 :                                     (char)ECOMMUNITY_ENCODE_IP) &&
     879             :                                    (ecom_eval->val[1] ==
     880             :                                     (char)ECOMMUNITY_FLOWSPEC_REDIRECT_IPV4)) {
     881             :                                 /* in case the 2 ecom present,
     882             :                                  * overwrite simpson draft
     883             :                                  * update redirect ip fields
     884             :                                  */
     885           0 :                                 if (api_action_redirect_ip) {
     886           0 :                                         memcpy(&(api_action_redirect_ip->u
     887             :                                                  .zr.redirect_ip_v4.s_addr),
     888             :                                                (ecom_eval->val+2), 4);
     889           0 :                                         api_action_redirect_ip->u
     890           0 :                                                 .zr.duplicate =
     891           0 :                                                 ecom_eval->val[7];
     892           0 :                                         continue;
     893             :                                 } else {
     894           0 :                                         api_action->action = ACTION_REDIRECT_IP;
     895           0 :                                         memcpy(&(api_action->u
     896             :                                                  .zr.redirect_ip_v4.s_addr),
     897             :                                                (ecom_eval->val+2), 4);
     898           0 :                                         api_action->u.zr.duplicate =
     899           0 :                                                 ecom_eval->val[7];
     900           0 :                                         api_action_redirect_ip = api_action;
     901             :                                 }
     902             :                         } else {
     903           0 :                                 if (ecom_eval->val[0] !=
     904             :                                     (char)ECOMMUNITY_ENCODE_TRANS_EXP)
     905           0 :                                         continue;
     906           0 :                                 ret = ecommunity_fill_pbr_action(ecom_eval,
     907             :                                                                  api_action,
     908             :                                                                  afi);
     909           0 :                                 if (ret != 0)
     910           0 :                                         continue;
     911           0 :                                 if ((api_action->action == ACTION_TRAFFICRATE)
     912           0 :                                     && api->actions[i].u.r.rate == 0)
     913           0 :                                         discard_action_found = true;
     914             :                         }
     915           0 :                         api->action_num++;
     916             :                 }
     917             :         }
     918           0 :         if (path && path->attr && bgp_attr_get_ipv6_ecommunity(path->attr)) {
     919             :                 struct ecommunity_val_ipv6 *ipv6_ecom_eval;
     920             : 
     921             :                 ecom = bgp_attr_get_ipv6_ecommunity(path->attr);
     922           0 :                 for (i = 0; i < ecom->size; i++) {
     923           0 :                         ipv6_ecom_eval = (struct ecommunity_val_ipv6 *)
     924           0 :                                 (ecom->val + (i * ecom->unit_size));
     925           0 :                         action_count++;
     926           0 :                         if (action_count > ACTIONS_MAX_NUM) {
     927           0 :                                 if (BGP_DEBUG(pbr, PBR_ERROR))
     928           0 :                                         flog_err(
     929             :                                                 EC_BGP_FLOWSPEC_PACKET,
     930             :                                                 "%s: flowspec actions exceeds limit (max %u)",
     931             :                                                 __func__, action_count);
     932             :                                 break;
     933             :                         }
     934           0 :                         api_action = &api->actions[action_count - 1];
     935           0 :                         if ((ipv6_ecom_eval->val[1] ==
     936           0 :                              (char)ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6) &&
     937           0 :                             (ipv6_ecom_eval->val[0] ==
     938             :                              (char)ECOMMUNITY_ENCODE_TRANS_EXP)) {
     939           0 :                                 struct ecommunity *eckey = ecommunity_new();
     940           0 :                                 struct ecommunity_val_ipv6 ecom_copy;
     941             : 
     942           0 :                                 eckey->unit_size = IPV6_ECOMMUNITY_SIZE;
     943           0 :                                 memcpy(&ecom_copy, ipv6_ecom_eval,
     944             :                                        sizeof(struct ecommunity_val_ipv6));
     945           0 :                                 ecom_copy.val[1] = ECOMMUNITY_ROUTE_TARGET;
     946           0 :                                 ecommunity_add_val_ipv6(eckey, &ecom_copy,
     947             :                                                         false, false);
     948           0 :                                 api_action->action = ACTION_REDIRECT;
     949           0 :                                 api_action->u.redirect_vrf =
     950           0 :                                         get_first_vrf_for_redirect_with_rt(
     951             :                                                                 eckey);
     952           0 :                                 ecommunity_free(&eckey);
     953           0 :                                 api->action_num++;
     954             :                         }
     955             :                 }
     956             :         }
     957             :         /* if ECOMMUNITY_TRAFFIC_RATE = 0 as action
     958             :          * then reduce the API action list to that action
     959             :          */
     960           0 :         if (api->action_num > 1 && discard_action_found) {
     961           0 :                 api->action_num = 1;
     962           0 :                 memset(&api->actions[0], 0,
     963             :                        sizeof(struct bgp_pbr_entry_action));
     964           0 :                 api->actions[0].action = ACTION_TRAFFICRATE;
     965             :         }
     966             : 
     967             :         /* validate if incoming matc/action is compatible
     968             :          * with our policy routing engine
     969             :          */
     970           0 :         if (!bgp_pbr_validate_policy_route(api))
     971             :                 return -1;
     972             : 
     973             :         /* check inconsistency in the match rule */
     974           0 :         if (api->match_bitmask & PREFIX_SRC_PRESENT) {
     975           0 :                 src = &api->src_prefix;
     976           0 :                 afi = family2afi(src->family);
     977           0 :                 valid_prefix = 1;
     978             :         }
     979           0 :         if (api->match_bitmask & PREFIX_DST_PRESENT) {
     980           0 :                 dst = &api->dst_prefix;
     981           0 :                 if (valid_prefix && afi != family2afi(dst->family)) {
     982           0 :                         if (BGP_DEBUG(pbr, PBR)) {
     983           0 :                                 bgp_pbr_print_policy_route(api);
     984           0 :                                 zlog_debug("%s: inconsistency: no match for afi src and dst (%u/%u)",
     985             :                                      __func__, afi, family2afi(dst->family));
     986             :                         }
     987           0 :                         return -1;
     988             :                 }
     989             :         }
     990             :         return 0;
     991             : }
     992             : 
     993           0 : static void bgp_pbr_match_entry_free(void *arg)
     994             : {
     995           0 :         struct bgp_pbr_match_entry *bpme;
     996             : 
     997           0 :         bpme = (struct bgp_pbr_match_entry *)arg;
     998             : 
     999           0 :         if (bpme->installed) {
    1000           0 :                 bgp_send_pbr_ipset_entry_match(bpme, false);
    1001           0 :                 bpme->installed = false;
    1002           0 :                 bpme->backpointer = NULL;
    1003             :         }
    1004           0 :         XFREE(MTYPE_PBR_MATCH_ENTRY, bpme);
    1005           0 : }
    1006             : 
    1007           0 : static void bgp_pbr_match_free(void *arg)
    1008             : {
    1009           0 :         struct bgp_pbr_match *bpm;
    1010             : 
    1011           0 :         bpm = (struct bgp_pbr_match *)arg;
    1012             : 
    1013           0 :         hash_clean(bpm->entry_hash, bgp_pbr_match_entry_free);
    1014             : 
    1015           0 :         if (hashcount(bpm->entry_hash) == 0) {
    1016             :                 /* delete iptable entry first */
    1017             :                 /* then delete ipset match */
    1018           0 :                 if (bpm->installed) {
    1019           0 :                         if (bpm->installed_in_iptable) {
    1020           0 :                                 bgp_send_pbr_iptable(bpm->action,
    1021             :                                                      bpm, false);
    1022           0 :                                 bpm->installed_in_iptable = false;
    1023           0 :                                 bpm->action->refcnt--;
    1024             :                         }
    1025           0 :                         bgp_send_pbr_ipset_match(bpm, false);
    1026           0 :                         bpm->installed = false;
    1027           0 :                         bpm->action = NULL;
    1028             :                 }
    1029             :         }
    1030           0 :         hash_free(bpm->entry_hash);
    1031             : 
    1032           0 :         XFREE(MTYPE_PBR_MATCH, bpm);
    1033           0 : }
    1034             : 
    1035           0 : static void *bgp_pbr_match_alloc_intern(void *arg)
    1036             : {
    1037           0 :         struct bgp_pbr_match *bpm, *new;
    1038             : 
    1039           0 :         bpm = (struct bgp_pbr_match *)arg;
    1040             : 
    1041           0 :         new = XCALLOC(MTYPE_PBR_MATCH, sizeof(*new));
    1042           0 :         memcpy(new, bpm, sizeof(*bpm));
    1043             : 
    1044           0 :         return new;
    1045             : }
    1046             : 
    1047           0 : static void bgp_pbr_rule_free(void *arg)
    1048             : {
    1049           0 :         struct bgp_pbr_rule *bpr;
    1050             : 
    1051           0 :         bpr = (struct bgp_pbr_rule *)arg;
    1052             : 
    1053             :         /* delete iprule */
    1054           0 :         if (bpr->installed) {
    1055           0 :                 bgp_send_pbr_rule_action(bpr->action, bpr, false);
    1056           0 :                 bpr->installed = false;
    1057           0 :                 bpr->action->refcnt--;
    1058           0 :                 bpr->action = NULL;
    1059             :         }
    1060           0 :         XFREE(MTYPE_PBR_RULE, bpr);
    1061           0 : }
    1062             : 
    1063           0 : static void *bgp_pbr_rule_alloc_intern(void *arg)
    1064             : {
    1065           0 :         struct bgp_pbr_rule *bpr, *new;
    1066             : 
    1067           0 :         bpr = (struct bgp_pbr_rule *)arg;
    1068             : 
    1069           0 :         new = XCALLOC(MTYPE_PBR_RULE, sizeof(*new));
    1070           0 :         memcpy(new, bpr, sizeof(*bpr));
    1071             : 
    1072           0 :         return new;
    1073             : }
    1074             : 
    1075           0 : static void bgp_pbr_bpa_remove(struct bgp_pbr_action *bpa)
    1076             : {
    1077           0 :         if ((bpa->refcnt == 0) && bpa->installed && bpa->table_id != 0) {
    1078           0 :                 bgp_send_pbr_rule_action(bpa, NULL, false);
    1079           0 :                 bgp_zebra_announce_default(bpa->bgp, &bpa->nh, bpa->afi,
    1080             :                                            bpa->table_id, false);
    1081           0 :                 bpa->installed = false;
    1082             :         }
    1083           0 : }
    1084             : 
    1085           0 : static void bgp_pbr_bpa_add(struct bgp_pbr_action *bpa)
    1086             : {
    1087           0 :         if (!bpa->installed && !bpa->install_in_progress) {
    1088           0 :                 bgp_send_pbr_rule_action(bpa, NULL, true);
    1089           0 :                 bgp_zebra_announce_default(bpa->bgp, &bpa->nh, bpa->afi,
    1090             :                                            bpa->table_id, true);
    1091             :         }
    1092           0 : }
    1093             : 
    1094           0 : static void bgp_pbr_action_free(void *arg)
    1095             : {
    1096           0 :         struct bgp_pbr_action *bpa = arg;
    1097             : 
    1098           0 :         bgp_pbr_bpa_remove(bpa);
    1099             : 
    1100           0 :         XFREE(MTYPE_PBR_ACTION, bpa);
    1101           0 : }
    1102             : 
    1103           0 : static void *bgp_pbr_action_alloc_intern(void *arg)
    1104             : {
    1105           0 :         struct bgp_pbr_action *bpa, *new;
    1106             : 
    1107           0 :         bpa = (struct bgp_pbr_action *)arg;
    1108             : 
    1109           0 :         new = XCALLOC(MTYPE_PBR_ACTION, sizeof(*new));
    1110             : 
    1111           0 :         memcpy(new, bpa, sizeof(*bpa));
    1112             : 
    1113           0 :         return new;
    1114             : }
    1115             : 
    1116           0 : static void *bgp_pbr_match_entry_alloc_intern(void *arg)
    1117             : {
    1118           0 :         struct bgp_pbr_match_entry *bpme, *new;
    1119             : 
    1120           0 :         bpme = (struct bgp_pbr_match_entry *)arg;
    1121             : 
    1122           0 :         new = XCALLOC(MTYPE_PBR_MATCH_ENTRY, sizeof(*new));
    1123             : 
    1124           0 :         memcpy(new, bpme, sizeof(*bpme));
    1125             : 
    1126           0 :         return new;
    1127             : }
    1128             : 
    1129           0 : uint32_t bgp_pbr_match_hash_key(const void *arg)
    1130             : {
    1131           0 :         const struct bgp_pbr_match *pbm = arg;
    1132           0 :         uint32_t key;
    1133             : 
    1134           0 :         key = jhash_1word(pbm->vrf_id, 0x4312abde);
    1135           0 :         key = jhash_1word(pbm->flags, key);
    1136           0 :         key = jhash_1word(pbm->family, key);
    1137           0 :         key = jhash(&pbm->pkt_len_min, 2, key);
    1138           0 :         key = jhash(&pbm->pkt_len_max, 2, key);
    1139           0 :         key = jhash(&pbm->tcp_flags, 2, key);
    1140           0 :         key = jhash(&pbm->tcp_mask_flags, 2, key);
    1141           0 :         key = jhash(&pbm->dscp_value, 1, key);
    1142           0 :         key = jhash(&pbm->flow_label, 2, key);
    1143           0 :         key = jhash(&pbm->fragment, 1, key);
    1144           0 :         key = jhash(&pbm->protocol, 1, key);
    1145           0 :         return jhash_1word(pbm->type, key);
    1146             : }
    1147             : 
    1148           0 : bool bgp_pbr_match_hash_equal(const void *arg1, const void *arg2)
    1149             : {
    1150           0 :         const struct bgp_pbr_match *r1, *r2;
    1151             : 
    1152           0 :         r1 = (const struct bgp_pbr_match *)arg1;
    1153           0 :         r2 = (const struct bgp_pbr_match *)arg2;
    1154             : 
    1155           0 :         if (r1->vrf_id != r2->vrf_id)
    1156             :                 return false;
    1157             : 
    1158           0 :         if (r1->family != r2->family)
    1159             :                 return false;
    1160             : 
    1161           0 :         if (r1->type != r2->type)
    1162             :                 return false;
    1163             : 
    1164           0 :         if (r1->flags != r2->flags)
    1165             :                 return false;
    1166             : 
    1167           0 :         if (r1->action != r2->action)
    1168             :                 return false;
    1169             : 
    1170           0 :         if (r1->pkt_len_min != r2->pkt_len_min)
    1171             :                 return false;
    1172             : 
    1173           0 :         if (r1->pkt_len_max != r2->pkt_len_max)
    1174             :                 return false;
    1175             : 
    1176           0 :         if (r1->tcp_flags != r2->tcp_flags)
    1177             :                 return false;
    1178             : 
    1179           0 :         if (r1->tcp_mask_flags != r2->tcp_mask_flags)
    1180             :                 return false;
    1181             : 
    1182           0 :         if (r1->dscp_value != r2->dscp_value)
    1183             :                 return false;
    1184             : 
    1185           0 :         if (r1->flow_label != r2->flow_label)
    1186             :                 return false;
    1187             : 
    1188           0 :         if (r1->fragment != r2->fragment)
    1189             :                 return false;
    1190             : 
    1191           0 :         if (r1->protocol != r2->protocol)
    1192           0 :                 return false;
    1193             :         return true;
    1194             : }
    1195             : 
    1196           0 : uint32_t bgp_pbr_rule_hash_key(const void *arg)
    1197             : {
    1198           0 :         const struct bgp_pbr_rule *pbr = arg;
    1199           0 :         uint32_t key;
    1200             : 
    1201           0 :         key = prefix_hash_key(&pbr->src);
    1202           0 :         key = jhash_1word(pbr->vrf_id, key);
    1203           0 :         key = jhash_1word(pbr->flags, key);
    1204           0 :         return jhash_1word(prefix_hash_key(&pbr->dst), key);
    1205             : }
    1206             : 
    1207           0 : bool bgp_pbr_rule_hash_equal(const void *arg1, const void *arg2)
    1208             : {
    1209           0 :         const struct bgp_pbr_rule *r1, *r2;
    1210             : 
    1211           0 :         r1 = (const struct bgp_pbr_rule *)arg1;
    1212           0 :         r2 = (const struct bgp_pbr_rule *)arg2;
    1213             : 
    1214           0 :         if (r1->vrf_id != r2->vrf_id)
    1215             :                 return false;
    1216             : 
    1217           0 :         if (r1->flags != r2->flags)
    1218             :                 return false;
    1219             : 
    1220           0 :         if (r1->action != r2->action)
    1221             :                 return false;
    1222             : 
    1223           0 :         if ((r1->flags & MATCH_IP_SRC_SET) &&
    1224           0 :             !prefix_same(&r1->src, &r2->src))
    1225             :                 return false;
    1226             : 
    1227           0 :         if ((r1->flags & MATCH_IP_DST_SET) &&
    1228           0 :             !prefix_same(&r1->dst, &r2->dst))
    1229             :                 return false;
    1230             : 
    1231             :         return true;
    1232             : }
    1233             : 
    1234           0 : uint32_t bgp_pbr_match_entry_hash_key(const void *arg)
    1235             : {
    1236           0 :         const struct bgp_pbr_match_entry *pbme;
    1237           0 :         uint32_t key;
    1238             : 
    1239           0 :         pbme = arg;
    1240           0 :         key = prefix_hash_key(&pbme->src);
    1241           0 :         key = jhash_1word(prefix_hash_key(&pbme->dst), key);
    1242           0 :         key = jhash(&pbme->dst_port_min, 2, key);
    1243           0 :         key = jhash(&pbme->src_port_min, 2, key);
    1244           0 :         key = jhash(&pbme->dst_port_max, 2, key);
    1245           0 :         key = jhash(&pbme->src_port_max, 2, key);
    1246           0 :         key = jhash(&pbme->proto, 1, key);
    1247             : 
    1248           0 :         return key;
    1249             : }
    1250             : 
    1251           0 : bool bgp_pbr_match_entry_hash_equal(const void *arg1, const void *arg2)
    1252             : {
    1253           0 :         const struct bgp_pbr_match_entry *r1, *r2;
    1254             : 
    1255           0 :         r1 = (const struct bgp_pbr_match_entry *)arg1;
    1256           0 :         r2 = (const struct bgp_pbr_match_entry *)arg2;
    1257             : 
    1258             :         /*
    1259             :          * on updates, comparing backpointer is not necessary
    1260             :          * unique value is self calculated
    1261             :          * rate is ignored for now
    1262             :          */
    1263             : 
    1264           0 :         if (!prefix_same(&r1->src, &r2->src))
    1265             :                 return false;
    1266             : 
    1267           0 :         if (!prefix_same(&r1->dst, &r2->dst))
    1268             :                 return false;
    1269             : 
    1270           0 :         if (r1->src_port_min != r2->src_port_min)
    1271             :                 return false;
    1272             : 
    1273           0 :         if (r1->dst_port_min != r2->dst_port_min)
    1274             :                 return false;
    1275             : 
    1276           0 :         if (r1->src_port_max != r2->src_port_max)
    1277             :                 return false;
    1278             : 
    1279           0 :         if (r1->dst_port_max != r2->dst_port_max)
    1280             :                 return false;
    1281             : 
    1282           0 :         if (r1->proto != r2->proto)
    1283             :                 return false;
    1284             : 
    1285             :         return true;
    1286             : }
    1287             : 
    1288           0 : uint32_t bgp_pbr_action_hash_key(const void *arg)
    1289             : {
    1290           0 :         const struct bgp_pbr_action *pbra;
    1291           0 :         uint32_t key;
    1292             : 
    1293           0 :         pbra = arg;
    1294           0 :         key = jhash_1word(pbra->table_id, 0x4312abde);
    1295           0 :         key = jhash_1word(pbra->fwmark, key);
    1296           0 :         key = jhash_1word(pbra->afi, key);
    1297           0 :         return key;
    1298             : }
    1299             : 
    1300           0 : bool bgp_pbr_action_hash_equal(const void *arg1, const void *arg2)
    1301             : {
    1302           0 :         const struct bgp_pbr_action *r1, *r2;
    1303             : 
    1304           0 :         r1 = (const struct bgp_pbr_action *)arg1;
    1305           0 :         r2 = (const struct bgp_pbr_action *)arg2;
    1306             : 
    1307             :         /* unique value is self calculated
    1308             :          * table and fwmark is self calculated
    1309             :          * rate is ignored
    1310             :          */
    1311           0 :         if (r1->vrf_id != r2->vrf_id)
    1312             :                 return false;
    1313             : 
    1314           0 :         if (r1->afi != r2->afi)
    1315             :                 return false;
    1316             : 
    1317           0 :         return nexthop_same(&r1->nh, &r2->nh);
    1318             : }
    1319             : 
    1320           0 : struct bgp_pbr_rule *bgp_pbr_rule_lookup(vrf_id_t vrf_id,
    1321             :                                          uint32_t unique)
    1322             : {
    1323           0 :         struct bgp *bgp = bgp_lookup_by_vrf_id(vrf_id);
    1324           0 :         struct bgp_pbr_rule_unique bpru;
    1325             : 
    1326           0 :         if (!bgp || unique == 0)
    1327             :                 return NULL;
    1328           0 :         bpru.unique = unique;
    1329           0 :         bpru.bpr_found = NULL;
    1330           0 :         hash_walk(bgp->pbr_rule_hash, bgp_pbr_rule_walkcb, &bpru);
    1331           0 :         return bpru.bpr_found;
    1332             : }
    1333             : 
    1334           0 : struct bgp_pbr_action *bgp_pbr_action_rule_lookup(vrf_id_t vrf_id,
    1335             :                                                   uint32_t unique)
    1336             : {
    1337           0 :         struct bgp *bgp = bgp_lookup_by_vrf_id(vrf_id);
    1338           0 :         struct bgp_pbr_action_unique bpau;
    1339             : 
    1340           0 :         if (!bgp || unique == 0)
    1341             :                 return NULL;
    1342           0 :         bpau.unique = unique;
    1343           0 :         bpau.bpa_found = NULL;
    1344           0 :         hash_walk(bgp->pbr_action_hash, bgp_pbr_action_walkcb, &bpau);
    1345           0 :         return bpau.bpa_found;
    1346             : }
    1347             : 
    1348           0 : struct bgp_pbr_match *bgp_pbr_match_ipset_lookup(vrf_id_t vrf_id,
    1349             :                                                  uint32_t unique)
    1350             : {
    1351           0 :         struct bgp *bgp = bgp_lookup_by_vrf_id(vrf_id);
    1352           0 :         struct bgp_pbr_match_unique bpmu;
    1353             : 
    1354           0 :         if (!bgp || unique == 0)
    1355             :                 return NULL;
    1356           0 :         bpmu.unique = unique;
    1357           0 :         bpmu.bpm_found = NULL;
    1358           0 :         hash_walk(bgp->pbr_match_hash, bgp_pbr_match_walkcb, &bpmu);
    1359           0 :         return bpmu.bpm_found;
    1360             : }
    1361             : 
    1362           0 : struct bgp_pbr_match_entry *bgp_pbr_match_ipset_entry_lookup(vrf_id_t vrf_id,
    1363             :                                                        char *ipset_name,
    1364             :                                                        uint32_t unique)
    1365             : {
    1366           0 :         struct bgp *bgp = bgp_lookup_by_vrf_id(vrf_id);
    1367           0 :         struct bgp_pbr_match_entry_unique bpmeu;
    1368           0 :         struct bgp_pbr_match_ipsetname bpmi;
    1369             : 
    1370           0 :         if (!bgp || unique == 0)
    1371             :                 return NULL;
    1372           0 :         bpmi.ipsetname = XCALLOC(MTYPE_TMP, ZEBRA_IPSET_NAME_SIZE);
    1373           0 :         snprintf(bpmi.ipsetname, ZEBRA_IPSET_NAME_SIZE, "%s", ipset_name);
    1374           0 :         bpmi.bpm_found = NULL;
    1375           0 :         hash_walk(bgp->pbr_match_hash, bgp_pbr_match_pername_walkcb, &bpmi);
    1376           0 :         XFREE(MTYPE_TMP, bpmi.ipsetname);
    1377           0 :         if (!bpmi.bpm_found)
    1378             :                 return NULL;
    1379           0 :         bpmeu.bpme_found = NULL;
    1380           0 :         bpmeu.unique = unique;
    1381           0 :         hash_walk(bpmi.bpm_found->entry_hash,
    1382             :                   bgp_pbr_match_entry_walkcb, &bpmeu);
    1383           0 :         return bpmeu.bpme_found;
    1384             : }
    1385             : 
    1386           0 : struct bgp_pbr_match *bgp_pbr_match_iptable_lookup(vrf_id_t vrf_id,
    1387             :                                                    uint32_t unique)
    1388             : {
    1389           0 :         struct bgp *bgp = bgp_lookup_by_vrf_id(vrf_id);
    1390           0 :         struct bgp_pbr_match_iptable_unique bpmiu;
    1391             : 
    1392           0 :         if (!bgp || unique == 0)
    1393             :                 return NULL;
    1394           0 :         bpmiu.unique = unique;
    1395           0 :         bpmiu.bpm_found = NULL;
    1396           0 :         hash_walk(bgp->pbr_match_hash, bgp_pbr_match_iptable_walkcb, &bpmiu);
    1397           0 :         return bpmiu.bpm_found;
    1398             : }
    1399             : 
    1400           2 : void bgp_pbr_cleanup(struct bgp *bgp)
    1401             : {
    1402           2 :         if (bgp->pbr_match_hash) {
    1403           2 :                 hash_clean(bgp->pbr_match_hash, bgp_pbr_match_free);
    1404           2 :                 hash_free(bgp->pbr_match_hash);
    1405           2 :                 bgp->pbr_match_hash = NULL;
    1406             :         }
    1407           2 :         if (bgp->pbr_rule_hash) {
    1408           2 :                 hash_clean(bgp->pbr_rule_hash, bgp_pbr_rule_free);
    1409           2 :                 hash_free(bgp->pbr_rule_hash);
    1410           2 :                 bgp->pbr_rule_hash = NULL;
    1411             :         }
    1412           2 :         if (bgp->pbr_action_hash) {
    1413           2 :                 hash_clean(bgp->pbr_action_hash, bgp_pbr_action_free);
    1414           2 :                 hash_free(bgp->pbr_action_hash);
    1415           2 :                 bgp->pbr_action_hash = NULL;
    1416             :         }
    1417           2 :         if (bgp->bgp_pbr_cfg == NULL)
    1418             :                 return;
    1419           2 :         bgp_pbr_reset(bgp, AFI_IP);
    1420           2 :         bgp_pbr_reset(bgp, AFI_IP6);
    1421           2 :         XFREE(MTYPE_PBR, bgp->bgp_pbr_cfg);
    1422             : }
    1423             : 
    1424           2 : void bgp_pbr_init(struct bgp *bgp)
    1425             : {
    1426           4 :         bgp->pbr_match_hash =
    1427           2 :                 hash_create_size(8, bgp_pbr_match_hash_key,
    1428             :                                  bgp_pbr_match_hash_equal,
    1429             :                                  "Match Hash");
    1430           4 :         bgp->pbr_action_hash =
    1431           2 :                 hash_create_size(8, bgp_pbr_action_hash_key,
    1432             :                                  bgp_pbr_action_hash_equal,
    1433             :                                  "Match Hash Entry");
    1434             : 
    1435           4 :         bgp->pbr_rule_hash =
    1436           2 :                 hash_create_size(8, bgp_pbr_rule_hash_key,
    1437             :                                  bgp_pbr_rule_hash_equal,
    1438             :                                  "Match Rule");
    1439             : 
    1440           2 :         bgp->bgp_pbr_cfg = XCALLOC(MTYPE_PBR, sizeof(struct bgp_pbr_config));
    1441           2 :         bgp->bgp_pbr_cfg->pbr_interface_any_ipv4 = true;
    1442           2 : }
    1443             : 
    1444           0 : void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main *api)
    1445             : {
    1446           0 :         int i = 0;
    1447           0 :         char return_string[512];
    1448           0 :         char *ptr = return_string;
    1449           0 :         int nb_items = 0;
    1450           0 :         int delta, len = sizeof(return_string);
    1451             : 
    1452           0 :         delta = snprintf(ptr, sizeof(return_string),  "MATCH : ");
    1453           0 :         len -= delta;
    1454           0 :         ptr += delta;
    1455           0 :         if (api->match_bitmask & PREFIX_SRC_PRESENT) {
    1456           0 :                 struct prefix *p = &(api->src_prefix);
    1457             : 
    1458           0 :                 if (api->src_prefix_offset)
    1459           0 :                         delta = snprintfrr(ptr, len, "@src %pFX/off%u", p,
    1460             :                                            api->src_prefix_offset);
    1461             :                 else
    1462           0 :                         delta = snprintfrr(ptr, len, "@src %pFX", p);
    1463           0 :                 len -= delta;
    1464           0 :                 ptr += delta;
    1465           0 :                 INCREMENT_DISPLAY(ptr, nb_items, len);
    1466             :         }
    1467           0 :         if (api->match_bitmask & PREFIX_DST_PRESENT) {
    1468           0 :                 struct prefix *p = &(api->dst_prefix);
    1469             : 
    1470           0 :                 INCREMENT_DISPLAY(ptr, nb_items, len);
    1471           0 :                 if (api->dst_prefix_offset)
    1472           0 :                         delta = snprintfrr(ptr, len, "@dst %pFX/off%u", p,
    1473             :                                            api->dst_prefix_offset);
    1474             :                 else
    1475           0 :                         delta = snprintfrr(ptr, len, "@dst %pFX", p);
    1476           0 :                 len -= delta;
    1477           0 :                 ptr += delta;
    1478             :         }
    1479             : 
    1480           0 :         if (api->match_protocol_num)
    1481           0 :                 INCREMENT_DISPLAY(ptr, nb_items, len);
    1482           0 :         for (i = 0; i < api->match_protocol_num; i++) {
    1483           0 :                 delta = snprintf_bgp_pbr_match_val(ptr, len, &api->protocol[i],
    1484             :                                                    i > 0 ? NULL : "@proto ");
    1485           0 :                 len -= delta;
    1486           0 :                 ptr += delta;
    1487             :         }
    1488             : 
    1489           0 :         if (api->match_src_port_num)
    1490           0 :                 INCREMENT_DISPLAY(ptr, nb_items, len);
    1491           0 :         for (i = 0; i < api->match_src_port_num; i++) {
    1492           0 :                 delta = snprintf_bgp_pbr_match_val(ptr, len, &api->src_port[i],
    1493             :                                                    i > 0 ? NULL : "@srcport ");
    1494           0 :                 len -= delta;
    1495           0 :                 ptr += delta;
    1496             :         }
    1497             : 
    1498           0 :         if (api->match_dst_port_num)
    1499           0 :                 INCREMENT_DISPLAY(ptr, nb_items, len);
    1500           0 :         for (i = 0; i < api->match_dst_port_num; i++) {
    1501           0 :                 delta = snprintf_bgp_pbr_match_val(ptr, len, &api->dst_port[i],
    1502             :                                                    i > 0 ? NULL : "@dstport ");
    1503           0 :                 len -= delta;
    1504           0 :                 ptr += delta;
    1505             :         }
    1506             : 
    1507           0 :         if (api->match_port_num)
    1508           0 :                 INCREMENT_DISPLAY(ptr, nb_items, len);
    1509           0 :         for (i = 0; i < api->match_port_num; i++) {
    1510           0 :                 delta = snprintf_bgp_pbr_match_val(ptr, len, &api->port[i],
    1511             :                                                    i > 0 ? NULL : "@port ");
    1512           0 :                 len -= delta;
    1513           0 :                 ptr += delta;
    1514             :         }
    1515             : 
    1516           0 :         if (api->match_icmp_type_num)
    1517           0 :                 INCREMENT_DISPLAY(ptr, nb_items, len);
    1518           0 :         for (i = 0; i < api->match_icmp_type_num; i++) {
    1519           0 :                 delta = snprintf_bgp_pbr_match_val(ptr, len, &api->icmp_type[i],
    1520             :                                                    i > 0 ? NULL : "@icmptype ");
    1521           0 :                 len -= delta;
    1522           0 :                 ptr += delta;
    1523             :         }
    1524             : 
    1525           0 :         if (api->match_icmp_code_num)
    1526           0 :                 INCREMENT_DISPLAY(ptr, nb_items, len);
    1527           0 :         for (i = 0; i < api->match_icmp_code_num; i++) {
    1528           0 :                 delta = snprintf_bgp_pbr_match_val(ptr, len, &api->icmp_code[i],
    1529             :                                                    i > 0 ? NULL : "@icmpcode ");
    1530           0 :                 len -= delta;
    1531           0 :                 ptr += delta;
    1532             :         }
    1533             : 
    1534           0 :         if (api->match_packet_length_num)
    1535           0 :                 INCREMENT_DISPLAY(ptr, nb_items, len);
    1536           0 :         for (i = 0; i < api->match_packet_length_num; i++) {
    1537           0 :                 delta = snprintf_bgp_pbr_match_val(ptr, len,
    1538             :                                                    &api->packet_length[i],
    1539             :                                                    i > 0 ? NULL : "@plen ");
    1540           0 :                 len -= delta;
    1541           0 :                 ptr += delta;
    1542             :         }
    1543             : 
    1544           0 :         if (api->match_dscp_num)
    1545           0 :                 INCREMENT_DISPLAY(ptr, nb_items, len);
    1546           0 :         for (i = 0; i < api->match_dscp_num; i++) {
    1547           0 :                 delta = snprintf_bgp_pbr_match_val(ptr, len, &api->dscp[i],
    1548             :                                                    i > 0 ? NULL : "@dscp ");
    1549           0 :                 len -= delta;
    1550           0 :                 ptr += delta;
    1551             :         }
    1552             : 
    1553           0 :         if (api->match_flowlabel_num)
    1554           0 :                 INCREMENT_DISPLAY(ptr, nb_items, len);
    1555           0 :         for (i = 0; i < api->match_flowlabel_num; i++) {
    1556           0 :                 delta = snprintf_bgp_pbr_match_val(ptr, len,
    1557             :                                                   &api->flow_label[i],
    1558             :                                                   i > 0 ? NULL : "@flowlabel ");
    1559           0 :                 len -= delta;
    1560           0 :                 ptr += delta;
    1561             :         }
    1562             : 
    1563           0 :         if (api->match_tcpflags_num)
    1564           0 :                 INCREMENT_DISPLAY(ptr, nb_items, len);
    1565           0 :         for (i = 0; i < api->match_tcpflags_num; i++) {
    1566           0 :                 delta = snprintf_bgp_pbr_match_val(ptr, len, &api->tcpflags[i],
    1567             :                                                    i > 0 ? NULL : "@tcpflags ");
    1568           0 :                 len -= delta;
    1569           0 :                 ptr += delta;
    1570             :         }
    1571             : 
    1572           0 :         if (api->match_fragment_num)
    1573           0 :                 INCREMENT_DISPLAY(ptr, nb_items, len);
    1574           0 :         for (i = 0; i < api->match_fragment_num; i++) {
    1575           0 :                 delta = snprintf_bgp_pbr_match_val(ptr, len, &api->fragment[i],
    1576             :                                                    i > 0 ? NULL : "@fragment ");
    1577           0 :                 len -= delta;
    1578           0 :                 ptr += delta;
    1579             :         }
    1580             : 
    1581           0 :         len = sizeof(return_string);
    1582           0 :         if (!nb_items) {
    1583             :                 ptr = return_string;
    1584             :         } else {
    1585           0 :                 len -= (ptr - return_string);
    1586           0 :                 delta = snprintf(ptr, len, "; ");
    1587           0 :                 len -= delta;
    1588           0 :                 ptr += delta;
    1589             :         }
    1590           0 :         if (api->action_num) {
    1591           0 :                 delta = snprintf(ptr, len, "SET : ");
    1592           0 :                 len -= delta;
    1593           0 :                 ptr += delta;
    1594             :         }
    1595             :         nb_items = 0;
    1596           0 :         for (i = 0; i < api->action_num; i++) {
    1597           0 :                 switch (api->actions[i].action) {
    1598           0 :                 case ACTION_TRAFFICRATE:
    1599           0 :                         INCREMENT_DISPLAY(ptr, nb_items, len);
    1600           0 :                         delta = snprintf(ptr, len, "@set rate %f",
    1601           0 :                                         api->actions[i].u.r.rate);
    1602           0 :                         len -= delta;
    1603           0 :                         ptr += delta;
    1604           0 :                         break;
    1605           0 :                 case ACTION_TRAFFIC_ACTION:
    1606           0 :                         INCREMENT_DISPLAY(ptr, nb_items, len);
    1607           0 :                         delta = snprintf(ptr, len, "@action ");
    1608           0 :                         len -= delta;
    1609           0 :                         ptr += delta;
    1610           0 :                         if (api->actions[i].u.za.filter
    1611             :                             & TRAFFIC_ACTION_TERMINATE) {
    1612           0 :                                 delta = snprintf(ptr, len,
    1613             :                                                  " terminate (apply filter(s))");
    1614           0 :                                 len -= delta;
    1615           0 :                                 ptr += delta;
    1616             :                         }
    1617           0 :                         if (api->actions[i].u.za.filter
    1618             :                             & TRAFFIC_ACTION_DISTRIBUTE) {
    1619           0 :                                 delta = snprintf(ptr, len, " distribute");
    1620           0 :                                 len -= delta;
    1621           0 :                                 ptr += delta;
    1622             :                         }
    1623           0 :                         if (api->actions[i].u.za.filter
    1624             :                             & TRAFFIC_ACTION_SAMPLE) {
    1625           0 :                                 delta = snprintf(ptr, len, " sample");
    1626           0 :                                 len -= delta;
    1627           0 :                                 ptr += delta;
    1628             :                         }
    1629             :                         break;
    1630           0 :                 case ACTION_REDIRECT_IP: {
    1631           0 :                         char local_buff[INET6_ADDRSTRLEN];
    1632           0 :                         void *ptr_ip;
    1633             : 
    1634           0 :                         INCREMENT_DISPLAY(ptr, nb_items, len);
    1635           0 :                         if (api->afi == AF_INET)
    1636           0 :                                 ptr_ip = &api->actions[i].u.zr.redirect_ip_v4;
    1637             :                         else
    1638           0 :                                 ptr_ip = &api->actions[i].u.zr.redirect_ip_v6;
    1639           0 :                         if (inet_ntop(afi2family(api->afi), ptr_ip, local_buff,
    1640             :                                       sizeof(local_buff)) != NULL) {
    1641           0 :                                 delta = snprintf(ptr, len,
    1642             :                                           "@redirect ip nh %s", local_buff);
    1643           0 :                                 len -= delta;
    1644           0 :                                 ptr += delta;
    1645             :                         }
    1646           0 :                         break;
    1647             :                 }
    1648           0 :                 case ACTION_REDIRECT: {
    1649           0 :                         struct vrf *vrf;
    1650             : 
    1651           0 :                         vrf = vrf_lookup_by_id(api->actions[i].u.redirect_vrf);
    1652           0 :                         INCREMENT_DISPLAY(ptr, nb_items, len);
    1653           0 :                         delta = snprintf(ptr, len, "@redirect vrf %s(%u)",
    1654             :                                          VRF_LOGNAME(vrf),
    1655             :                                          api->actions[i].u.redirect_vrf);
    1656           0 :                         len -= delta;
    1657           0 :                         ptr += delta;
    1658           0 :                         break;
    1659             :                 }
    1660           0 :                 case ACTION_MARKING:
    1661           0 :                         INCREMENT_DISPLAY(ptr, nb_items, len);
    1662           0 :                         delta = snprintf(ptr, len, "@set dscp/flowlabel %u",
    1663           0 :                                          api->actions[i].u.marking_dscp);
    1664           0 :                         len -= delta;
    1665           0 :                         ptr += delta;
    1666           0 :                         break;
    1667             :                 default:
    1668             :                         break;
    1669             :                 }
    1670             :         }
    1671           0 :         zlog_info("%s", return_string);
    1672           0 : }
    1673             : 
    1674           0 : static void bgp_pbr_flush_iprule(struct bgp *bgp, struct bgp_pbr_action *bpa,
    1675             :                                   struct bgp_pbr_rule *bpr)
    1676             : {
    1677             :         /* if bpr is null, do nothing
    1678             :          */
    1679           0 :         if (bpr == NULL)
    1680             :                 return;
    1681           0 :         if (bpr->installed) {
    1682           0 :                 bgp_send_pbr_rule_action(bpa, bpr, false);
    1683           0 :                 bpr->installed = false;
    1684           0 :                 bpr->action->refcnt--;
    1685           0 :                 bpr->action = NULL;
    1686           0 :                 if (bpr->path) {
    1687           0 :                         struct bgp_path_info *path;
    1688           0 :                         struct bgp_path_info_extra *extra;
    1689             : 
    1690             :                         /* unlink path to bpme */
    1691           0 :                         path = (struct bgp_path_info *)bpr->path;
    1692           0 :                         extra = bgp_path_info_extra_get(path);
    1693           0 :                         if (extra->bgp_fs_iprule)
    1694           0 :                                 listnode_delete(extra->bgp_fs_iprule, bpr);
    1695           0 :                         bpr->path = NULL;
    1696             :                 }
    1697             :         }
    1698           0 :         hash_release(bgp->pbr_rule_hash, bpr);
    1699           0 :         bgp_pbr_bpa_remove(bpa);
    1700             : }
    1701             : 
    1702           0 : static void bgp_pbr_flush_entry(struct bgp *bgp, struct bgp_pbr_action *bpa,
    1703             :                                 struct bgp_pbr_match *bpm,
    1704             :                                 struct bgp_pbr_match_entry *bpme)
    1705             : {
    1706             :         /* if bpme is null, bpm is also null
    1707             :          */
    1708           0 :         if (bpme == NULL)
    1709             :                 return;
    1710             :         /* ipset del entry */
    1711           0 :         if (bpme->installed) {
    1712           0 :                 bgp_send_pbr_ipset_entry_match(bpme, false);
    1713           0 :                 bpme->installed = false;
    1714           0 :                 bpme->backpointer = NULL;
    1715           0 :                 if (bpme->path) {
    1716           0 :                         struct bgp_path_info *path;
    1717           0 :                         struct bgp_path_info_extra *extra;
    1718             : 
    1719             :                         /* unlink path to bpme */
    1720           0 :                         path = (struct bgp_path_info *)bpme->path;
    1721           0 :                         extra = bgp_path_info_extra_get(path);
    1722           0 :                         if (extra->bgp_fs_pbr)
    1723           0 :                                 listnode_delete(extra->bgp_fs_pbr, bpme);
    1724           0 :                         bpme->path = NULL;
    1725             :                 }
    1726             :         }
    1727           0 :         hash_release(bpm->entry_hash, bpme);
    1728           0 :         if (hashcount(bpm->entry_hash) == 0) {
    1729             :                 /* delete iptable entry first */
    1730             :                 /* then delete ipset match */
    1731           0 :                 if (bpm->installed) {
    1732           0 :                         if (bpm->installed_in_iptable) {
    1733           0 :                                 bgp_send_pbr_iptable(bpm->action,
    1734             :                                                      bpm, false);
    1735           0 :                                 bpm->installed_in_iptable = false;
    1736           0 :                                 bpm->action->refcnt--;
    1737             :                         }
    1738           0 :                         bgp_send_pbr_ipset_match(bpm, false);
    1739           0 :                         bpm->installed = false;
    1740           0 :                         bpm->action = NULL;
    1741             :                 }
    1742           0 :                 hash_release(bgp->pbr_match_hash, bpm);
    1743             :                 /* XXX release pbr_match_action if not used
    1744             :                  * note that drop does not need to call send_pbr_action
    1745             :                  */
    1746             :         }
    1747           0 :         bgp_pbr_bpa_remove(bpa);
    1748             : }
    1749             : 
    1750             : struct bgp_pbr_match_entry_remain {
    1751             :         struct bgp_pbr_match_entry *bpme_to_match;
    1752             :         struct bgp_pbr_match_entry *bpme_found;
    1753             : };
    1754             : 
    1755             : struct bgp_pbr_rule_remain {
    1756             :         struct bgp_pbr_rule *bpr_to_match;
    1757             :         struct bgp_pbr_rule *bpr_found;
    1758             : };
    1759             : 
    1760           0 : static int bgp_pbr_get_same_rule(struct hash_bucket *bucket, void *arg)
    1761             : {
    1762           0 :         struct bgp_pbr_rule *r1 = (struct bgp_pbr_rule *)bucket->data;
    1763           0 :         struct bgp_pbr_rule_remain *ctxt =
    1764             :                 (struct bgp_pbr_rule_remain *)arg;
    1765           0 :         struct bgp_pbr_rule *r2;
    1766             : 
    1767           0 :         r2 = ctxt->bpr_to_match;
    1768             : 
    1769           0 :         if (r1->vrf_id != r2->vrf_id)
    1770             :                 return HASHWALK_CONTINUE;
    1771             : 
    1772           0 :         if (r1->flags != r2->flags)
    1773             :                 return HASHWALK_CONTINUE;
    1774             : 
    1775           0 :         if ((r1->flags & MATCH_IP_SRC_SET) &&
    1776           0 :             !prefix_same(&r1->src, &r2->src))
    1777             :                 return HASHWALK_CONTINUE;
    1778             : 
    1779           0 :         if ((r1->flags & MATCH_IP_DST_SET) &&
    1780           0 :             !prefix_same(&r1->dst, &r2->dst))
    1781             :                 return HASHWALK_CONTINUE;
    1782             : 
    1783             :         /* this function is used for two cases:
    1784             :          * - remove an entry upon withdraw request
    1785             :          * (case r2->action is null)
    1786             :          * - replace an old iprule with different action
    1787             :          * (case r2->action is != null)
    1788             :          * the old one is removed after the new one
    1789             :          * this is to avoid disruption in traffic
    1790             :          */
    1791           0 :         if (r2->action == NULL ||
    1792           0 :             r1->action != r2->action) {
    1793           0 :                 ctxt->bpr_found = r1;
    1794           0 :                 return HASHWALK_ABORT;
    1795             :         }
    1796             :         return HASHWALK_CONTINUE;
    1797             : }
    1798             : 
    1799           0 : static int bgp_pbr_get_remaining_entry(struct hash_bucket *bucket, void *arg)
    1800             : {
    1801           0 :         struct bgp_pbr_match *bpm = (struct bgp_pbr_match *)bucket->data;
    1802           0 :         struct bgp_pbr_match_entry_remain *bpmer =
    1803             :                 (struct bgp_pbr_match_entry_remain *)arg;
    1804           0 :         struct bgp_pbr_match *bpm_temp;
    1805           0 :         struct bgp_pbr_match_entry *bpme = bpmer->bpme_to_match;
    1806             : 
    1807           0 :         if (!bpme->backpointer ||
    1808           0 :             bpm == bpme->backpointer ||
    1809           0 :             bpme->backpointer->action == bpm->action)
    1810             :                 return HASHWALK_CONTINUE;
    1811             :         /* ensure bpm other characteristics are equal */
    1812           0 :         bpm_temp = bpme->backpointer;
    1813           0 :         if (bpm_temp->vrf_id != bpm->vrf_id ||
    1814           0 :             bpm_temp->type != bpm->type ||
    1815           0 :             bpm_temp->flags != bpm->flags ||
    1816           0 :             bpm_temp->tcp_flags != bpm->tcp_flags ||
    1817           0 :             bpm_temp->tcp_mask_flags != bpm->tcp_mask_flags ||
    1818           0 :             bpm_temp->pkt_len_min != bpm->pkt_len_min ||
    1819             :             bpm_temp->pkt_len_max != bpm->pkt_len_max ||
    1820           0 :             bpm_temp->dscp_value != bpm->dscp_value ||
    1821           0 :             bpm_temp->flow_label != bpm->flow_label ||
    1822           0 :             bpm_temp->family != bpm->family ||
    1823           0 :             bpm_temp->fragment != bpm->fragment)
    1824             :                 return HASHWALK_CONTINUE;
    1825             : 
    1826             :         /* look for remaining bpme */
    1827           0 :         bpmer->bpme_found = hash_lookup(bpm->entry_hash, bpme);
    1828           0 :         if (!bpmer->bpme_found)
    1829             :                 return HASHWALK_CONTINUE;
    1830             :         return HASHWALK_ABORT;
    1831             : }
    1832             : 
    1833           0 : static void bgp_pbr_policyroute_remove_from_zebra_unit(
    1834             :         struct bgp *bgp, struct bgp_path_info *path, struct bgp_pbr_filter *bpf)
    1835             : {
    1836           0 :         struct bgp_pbr_match temp;
    1837           0 :         struct bgp_pbr_match_entry temp2;
    1838           0 :         struct bgp_pbr_rule pbr_rule;
    1839           0 :         struct bgp_pbr_rule *bpr;
    1840           0 :         struct bgp_pbr_match *bpm;
    1841           0 :         struct bgp_pbr_match_entry *bpme;
    1842           0 :         struct bgp_pbr_match_entry_remain bpmer;
    1843           0 :         struct bgp_pbr_range_port *src_port;
    1844           0 :         struct bgp_pbr_range_port *dst_port;
    1845           0 :         struct bgp_pbr_range_port *pkt_len;
    1846           0 :         struct bgp_pbr_rule_remain bprr;
    1847             : 
    1848           0 :         if (!bpf)
    1849           0 :                 return;
    1850           0 :         src_port = bpf->src_port;
    1851           0 :         dst_port = bpf->dst_port;
    1852           0 :         pkt_len = bpf->pkt_len;
    1853             : 
    1854           0 :         if (BGP_DEBUG(zebra, ZEBRA))
    1855           0 :                 bgp_pbr_dump_entry(bpf, false);
    1856             : 
    1857             :         /* as we don't know information from EC
    1858             :          * look for bpm that have the bpm
    1859             :          * with vrf_id characteristics
    1860             :          */
    1861           0 :         memset(&temp2, 0, sizeof(temp2));
    1862           0 :         memset(&temp, 0, sizeof(temp));
    1863             : 
    1864           0 :         if (bpf->type == BGP_PBR_IPRULE) {
    1865           0 :                 memset(&pbr_rule, 0, sizeof(pbr_rule));
    1866           0 :                 pbr_rule.vrf_id = bpf->vrf_id;
    1867           0 :                 if (bpf->src) {
    1868           0 :                         prefix_copy(&pbr_rule.src, bpf->src);
    1869           0 :                         pbr_rule.flags |= MATCH_IP_SRC_SET;
    1870             :                 }
    1871           0 :                 if (bpf->dst) {
    1872           0 :                         prefix_copy(&pbr_rule.dst, bpf->dst);
    1873           0 :                         pbr_rule.flags |= MATCH_IP_DST_SET;
    1874             :                 }
    1875           0 :                 bpr = &pbr_rule;
    1876             :                 /* A previous entry may already exist
    1877             :                  * flush previous entry if necessary
    1878             :                  */
    1879           0 :                 bprr.bpr_to_match = bpr;
    1880           0 :                 bprr.bpr_found = NULL;
    1881           0 :                 hash_walk(bgp->pbr_rule_hash, bgp_pbr_get_same_rule, &bprr);
    1882           0 :                 if (bprr.bpr_found) {
    1883           0 :                         static struct bgp_pbr_rule *local_bpr;
    1884           0 :                         static struct bgp_pbr_action *local_bpa;
    1885             : 
    1886           0 :                         local_bpr = bprr.bpr_found;
    1887           0 :                         local_bpa = local_bpr->action;
    1888           0 :                         bgp_pbr_flush_iprule(bgp, local_bpa,
    1889             :                                              local_bpr);
    1890             :                 }
    1891           0 :                 return;
    1892             :         }
    1893             : 
    1894           0 :         temp.family = bpf->family;
    1895           0 :         if (bpf->src) {
    1896           0 :                 temp.flags |= MATCH_IP_SRC_SET;
    1897           0 :                 prefix_copy(&temp2.src, bpf->src);
    1898             :         } else
    1899           0 :                 temp2.src.family = bpf->family;
    1900           0 :         if (bpf->dst) {
    1901           0 :                 temp.flags |= MATCH_IP_DST_SET;
    1902           0 :                 prefix_copy(&temp2.dst, bpf->dst);
    1903             :         } else
    1904           0 :                 temp2.dst.family = bpf->family;
    1905           0 :         if (src_port && (src_port->min_port || bpf->protocol == IPPROTO_ICMP)) {
    1906           0 :                 if (bpf->protocol == IPPROTO_ICMP)
    1907           0 :                         temp.flags |= MATCH_ICMP_SET;
    1908           0 :                 temp.flags |= MATCH_PORT_SRC_SET;
    1909           0 :                 temp2.src_port_min = src_port->min_port;
    1910           0 :                 if (src_port->max_port) {
    1911           0 :                         temp.flags |= MATCH_PORT_SRC_RANGE_SET;
    1912           0 :                         temp2.src_port_max = src_port->max_port;
    1913             :                 }
    1914             :         }
    1915           0 :         if (dst_port && (dst_port->min_port || bpf->protocol == IPPROTO_ICMP)) {
    1916           0 :                 if (bpf->protocol == IPPROTO_ICMP)
    1917           0 :                         temp.flags |= MATCH_ICMP_SET;
    1918           0 :                 temp.flags |= MATCH_PORT_DST_SET;
    1919           0 :                 temp2.dst_port_min = dst_port->min_port;
    1920           0 :                 if (dst_port->max_port) {
    1921           0 :                         temp.flags |= MATCH_PORT_DST_RANGE_SET;
    1922           0 :                         temp2.dst_port_max = dst_port->max_port;
    1923             :                 }
    1924             :         }
    1925           0 :         temp2.proto = bpf->protocol;
    1926             : 
    1927           0 :         if (pkt_len) {
    1928           0 :                 temp.pkt_len_min = pkt_len->min_port;
    1929           0 :                 if (pkt_len->max_port)
    1930           0 :                         temp.pkt_len_max = pkt_len->max_port;
    1931           0 :         } else if (bpf->pkt_len_val) {
    1932           0 :                 if (bpf->pkt_len_val->mask)
    1933           0 :                         temp.flags |= MATCH_PKT_LEN_INVERSE_SET;
    1934           0 :                 temp.pkt_len_min = bpf->pkt_len_val->val;
    1935             :         }
    1936           0 :         if (bpf->tcp_flags) {
    1937           0 :                 temp.tcp_flags = bpf->tcp_flags->val;
    1938           0 :                 temp.tcp_mask_flags = bpf->tcp_flags->mask;
    1939             :         }
    1940           0 :         if (bpf->dscp) {
    1941           0 :                 if (bpf->dscp->mask)
    1942           0 :                         temp.flags |= MATCH_DSCP_INVERSE_SET;
    1943             :                 else
    1944           0 :                         temp.flags |= MATCH_DSCP_SET;
    1945           0 :                 temp.dscp_value = bpf->dscp->val;
    1946             :         }
    1947           0 :         if (bpf->flow_label) {
    1948           0 :                 if (bpf->flow_label->mask)
    1949           0 :                         temp.flags |= MATCH_FLOW_LABEL_INVERSE_SET;
    1950             :                 else
    1951           0 :                         temp.flags |= MATCH_FLOW_LABEL_SET;
    1952           0 :                 temp.flow_label = bpf->flow_label->val;
    1953             :         }
    1954             : 
    1955           0 :         if (bpf->fragment) {
    1956           0 :                 if (bpf->fragment->mask)
    1957           0 :                         temp.flags |= MATCH_FRAGMENT_INVERSE_SET;
    1958           0 :                 temp.fragment = bpf->fragment->val;
    1959             :         }
    1960             : 
    1961           0 :         if (bpf->src == NULL || bpf->dst == NULL) {
    1962           0 :                 if (temp.flags & (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET))
    1963           0 :                         temp.type = IPSET_NET_PORT;
    1964             :                 else
    1965           0 :                         temp.type = IPSET_NET;
    1966             :         } else {
    1967           0 :                 if (temp.flags & (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET))
    1968           0 :                         temp.type = IPSET_NET_PORT_NET;
    1969             :                 else
    1970           0 :                         temp.type = IPSET_NET_NET;
    1971             :         }
    1972           0 :         if (bpf->vrf_id == VRF_UNKNOWN) /* XXX case BGP destroy */
    1973           0 :                 temp.vrf_id = VRF_DEFAULT;
    1974             :         else
    1975           0 :                 temp.vrf_id = bpf->vrf_id;
    1976           0 :         bpme = &temp2;
    1977           0 :         bpm = &temp;
    1978           0 :         bpme->backpointer = bpm;
    1979             :         /* right now, a previous entry may already exist
    1980             :          * flush previous entry if necessary
    1981             :          */
    1982           0 :         bpmer.bpme_to_match = bpme;
    1983           0 :         bpmer.bpme_found = NULL;
    1984           0 :         hash_walk(bgp->pbr_match_hash, bgp_pbr_get_remaining_entry, &bpmer);
    1985           0 :         if (bpmer.bpme_found) {
    1986           0 :                 static struct bgp_pbr_match *local_bpm;
    1987           0 :                 static struct bgp_pbr_action *local_bpa;
    1988             : 
    1989           0 :                 local_bpm = bpmer.bpme_found->backpointer;
    1990           0 :                 local_bpa = local_bpm->action;
    1991           0 :                 bgp_pbr_flush_entry(bgp, local_bpa,
    1992             :                                     local_bpm, bpmer.bpme_found);
    1993             :         }
    1994             : }
    1995             : 
    1996           0 : static uint8_t bgp_pbr_next_type_entry(uint8_t type_entry)
    1997             : {
    1998           0 :         if (type_entry == FLOWSPEC_TCP_FLAGS)
    1999             :                 return FLOWSPEC_DSCP;
    2000             :         if (type_entry == FLOWSPEC_DSCP)
    2001             :                 return FLOWSPEC_FLOW_LABEL;
    2002             :         if (type_entry == FLOWSPEC_FLOW_LABEL)
    2003             :                 return FLOWSPEC_PKT_LEN;
    2004             :         if (type_entry == FLOWSPEC_PKT_LEN)
    2005             :                 return FLOWSPEC_FRAGMENT;
    2006             :         if (type_entry == FLOWSPEC_FRAGMENT)
    2007             :                 return FLOWSPEC_ICMP_TYPE;
    2008             :         return 0;
    2009             : }
    2010             : 
    2011           0 : static void bgp_pbr_icmp_action(struct bgp *bgp, struct bgp_path_info *path,
    2012             :                                 struct bgp_pbr_filter *bpf,
    2013             :                                 struct bgp_pbr_or_filter *bpof, bool add,
    2014             :                                 struct nexthop *nh, float *rate)
    2015             : {
    2016           0 :         struct bgp_pbr_range_port srcp, dstp;
    2017           0 :         struct bgp_pbr_val_mask *icmp_type, *icmp_code;
    2018           0 :         struct listnode *tnode, *cnode;
    2019             : 
    2020           0 :         if (!bpf)
    2021           0 :                 return;
    2022           0 :         if (bpf->protocol != IPPROTO_ICMP)
    2023             :                 return;
    2024             : 
    2025           0 :         memset(&srcp, 0, sizeof(srcp));
    2026           0 :         memset(&dstp, 0, sizeof(dstp));
    2027           0 :         bpf->src_port = &srcp;
    2028           0 :         bpf->dst_port = &dstp;
    2029             :         /* parse icmp type and lookup appropriate icmp code
    2030             :          * if no icmp code found, create as many entryes as
    2031             :          * there are listed icmp codes for that icmp type
    2032             :          */
    2033           0 :         if (!bpof->icmp_type) {
    2034           0 :                 srcp.min_port = 0;
    2035           0 :                 srcp.max_port = 255;
    2036           0 :                 for (ALL_LIST_ELEMENTS_RO(bpof->icmp_code, cnode, icmp_code)) {
    2037           0 :                         dstp.min_port = icmp_code->val;
    2038           0 :                         if (add)
    2039           0 :                                 bgp_pbr_policyroute_add_to_zebra_unit(
    2040             :                                         bgp, path, bpf, nh, rate);
    2041             :                         else
    2042           0 :                                 bgp_pbr_policyroute_remove_from_zebra_unit(
    2043             :                                         bgp, path, bpf);
    2044             :                 }
    2045             :                 return;
    2046             :         }
    2047           0 :         for (ALL_LIST_ELEMENTS_RO(bpof->icmp_type, tnode, icmp_type)) {
    2048           0 :                 srcp.min_port = icmp_type->val;
    2049           0 :                 srcp.max_port = 0;
    2050           0 :                 dstp.max_port = 0;
    2051             :                 /* only icmp type. create an entry only with icmp type */
    2052           0 :                 if (!bpof->icmp_code) {
    2053             :                         /* icmp type is not one of the above
    2054             :                          * forge an entry only based on the icmp type
    2055             :                          */
    2056           0 :                         dstp.min_port = 0;
    2057           0 :                         dstp.max_port = 255;
    2058           0 :                         if (add)
    2059           0 :                                 bgp_pbr_policyroute_add_to_zebra_unit(
    2060             :                                         bgp, path, bpf, nh, rate);
    2061             :                         else
    2062           0 :                                 bgp_pbr_policyroute_remove_from_zebra_unit(
    2063             :                                         bgp, path, bpf);
    2064           0 :                         continue;
    2065             :                 }
    2066           0 :                 for (ALL_LIST_ELEMENTS_RO(bpof->icmp_code, cnode, icmp_code)) {
    2067           0 :                         dstp.min_port = icmp_code->val;
    2068           0 :                         if (add)
    2069           0 :                                 bgp_pbr_policyroute_add_to_zebra_unit(
    2070             :                                         bgp, path, bpf, nh, rate);
    2071             :                         else
    2072           0 :                                 bgp_pbr_policyroute_remove_from_zebra_unit(
    2073             :                                         bgp, path, bpf);
    2074             :                 }
    2075             :         }
    2076             : 
    2077           0 :         bpf->src_port = NULL;
    2078           0 :         bpf->dst_port = NULL;
    2079             : }
    2080             : 
    2081           0 : static void bgp_pbr_policyroute_remove_from_zebra_recursive(
    2082             :         struct bgp *bgp, struct bgp_path_info *path, struct bgp_pbr_filter *bpf,
    2083             :         struct bgp_pbr_or_filter *bpof, uint8_t type_entry)
    2084             : {
    2085           0 :         struct listnode *node, *nnode;
    2086           0 :         struct bgp_pbr_val_mask *valmask;
    2087           0 :         uint8_t next_type_entry;
    2088           0 :         struct list *orig_list;
    2089           0 :         struct bgp_pbr_val_mask **target_val;
    2090             : 
    2091           0 :         if (type_entry == 0) {
    2092           0 :                 bgp_pbr_policyroute_remove_from_zebra_unit(bgp, path, bpf);
    2093           0 :                 return;
    2094             :         }
    2095           0 :         next_type_entry = bgp_pbr_next_type_entry(type_entry);
    2096           0 :         if (type_entry == FLOWSPEC_TCP_FLAGS && bpof->tcpflags) {
    2097           0 :                 orig_list = bpof->tcpflags;
    2098           0 :                 target_val = &bpf->tcp_flags;
    2099           0 :         } else if (type_entry == FLOWSPEC_DSCP && bpof->dscp) {
    2100           0 :                 orig_list = bpof->dscp;
    2101           0 :                 target_val = &bpf->dscp;
    2102           0 :         } else if (type_entry == FLOWSPEC_FLOW_LABEL && bpof->flowlabel) {
    2103           0 :                 orig_list = bpof->flowlabel;
    2104           0 :                 target_val = &bpf->flow_label;
    2105           0 :         } else if (type_entry == FLOWSPEC_PKT_LEN && bpof->pkt_len) {
    2106           0 :                 orig_list = bpof->pkt_len;
    2107           0 :                 target_val = &bpf->pkt_len_val;
    2108           0 :         } else if (type_entry == FLOWSPEC_FRAGMENT && bpof->fragment) {
    2109           0 :                 orig_list = bpof->fragment;
    2110           0 :                 target_val = &bpf->fragment;
    2111           0 :         } else if (type_entry == FLOWSPEC_ICMP_TYPE &&
    2112           0 :                    (bpof->icmp_type || bpof->icmp_code)) {
    2113             :                 /* enumerate list for icmp - must be last one  */
    2114           0 :                 bgp_pbr_icmp_action(bgp, path, bpf, bpof, false, NULL, NULL);
    2115           0 :                 return;
    2116             :         } else {
    2117           0 :                 bgp_pbr_policyroute_remove_from_zebra_recursive(
    2118             :                         bgp, path, bpf, bpof, next_type_entry);
    2119           0 :                 return;
    2120             :         }
    2121           0 :         for (ALL_LIST_ELEMENTS(orig_list, node, nnode, valmask)) {
    2122           0 :                 *target_val = valmask;
    2123           0 :                 bgp_pbr_policyroute_remove_from_zebra_recursive(
    2124             :                         bgp, path, bpf, bpof, next_type_entry);
    2125             :         }
    2126             : }
    2127             : 
    2128           0 : static void bgp_pbr_policyroute_remove_from_zebra(
    2129             :         struct bgp *bgp, struct bgp_path_info *path, struct bgp_pbr_filter *bpf,
    2130             :         struct bgp_pbr_or_filter *bpof)
    2131             : {
    2132           0 :         if (!bpof) {
    2133           0 :                 bgp_pbr_policyroute_remove_from_zebra_unit(bgp, path, bpf);
    2134           0 :                 return;
    2135             :         }
    2136           0 :         if (bpof->tcpflags)
    2137           0 :                 bgp_pbr_policyroute_remove_from_zebra_recursive(
    2138             :                         bgp, path, bpf, bpof, FLOWSPEC_TCP_FLAGS);
    2139           0 :         else if (bpof->dscp)
    2140           0 :                 bgp_pbr_policyroute_remove_from_zebra_recursive(
    2141             :                         bgp, path, bpf, bpof, FLOWSPEC_DSCP);
    2142           0 :         else if (bpof->flowlabel)
    2143           0 :                 bgp_pbr_policyroute_remove_from_zebra_recursive(
    2144             :                         bgp, path, bpf, bpof, FLOWSPEC_FLOW_LABEL);
    2145           0 :         else if (bpof->pkt_len)
    2146           0 :                 bgp_pbr_policyroute_remove_from_zebra_recursive(
    2147             :                         bgp, path, bpf, bpof, FLOWSPEC_PKT_LEN);
    2148           0 :         else if (bpof->fragment)
    2149           0 :                 bgp_pbr_policyroute_remove_from_zebra_recursive(
    2150             :                         bgp, path, bpf, bpof, FLOWSPEC_FRAGMENT);
    2151           0 :         else if (bpof->icmp_type || bpof->icmp_code)
    2152           0 :                 bgp_pbr_policyroute_remove_from_zebra_recursive(
    2153             :                         bgp, path, bpf, bpof, FLOWSPEC_ICMP_TYPE);
    2154             :         else
    2155           0 :                 bgp_pbr_policyroute_remove_from_zebra_unit(bgp, path, bpf);
    2156             :         /* flush bpof */
    2157           0 :         if (bpof->tcpflags)
    2158           0 :                 list_delete_all_node(bpof->tcpflags);
    2159           0 :         if (bpof->dscp)
    2160           0 :                 list_delete_all_node(bpof->dscp);
    2161           0 :         if (bpof->flowlabel)
    2162           0 :                 list_delete_all_node(bpof->flowlabel);
    2163           0 :         if (bpof->pkt_len)
    2164           0 :                 list_delete_all_node(bpof->pkt_len);
    2165           0 :         if (bpof->fragment)
    2166           0 :                 list_delete_all_node(bpof->fragment);
    2167             : }
    2168             : 
    2169           0 : static void bgp_pbr_dump_entry(struct bgp_pbr_filter *bpf, bool add)
    2170             : {
    2171           0 :         struct bgp_pbr_range_port *src_port;
    2172           0 :         struct bgp_pbr_range_port *dst_port;
    2173           0 :         struct bgp_pbr_range_port *pkt_len;
    2174           0 :         char bufsrc[64], bufdst[64];
    2175           0 :         char buffer[64];
    2176           0 :         int remaining_len = 0;
    2177           0 :         char protocol_str[16];
    2178             : 
    2179           0 :         if (!bpf)
    2180           0 :                 return;
    2181           0 :         src_port = bpf->src_port;
    2182           0 :         dst_port = bpf->dst_port;
    2183           0 :         pkt_len = bpf->pkt_len;
    2184             : 
    2185           0 :         protocol_str[0] = '\0';
    2186           0 :         if (bpf->tcp_flags && bpf->tcp_flags->mask)
    2187           0 :                 bpf->protocol = IPPROTO_TCP;
    2188           0 :         if (bpf->protocol)
    2189           0 :                 snprintf(protocol_str, sizeof(protocol_str),
    2190             :                          "proto %d", bpf->protocol);
    2191           0 :         buffer[0] = '\0';
    2192           0 :         if (bpf->protocol == IPPROTO_ICMP && src_port && dst_port)
    2193           0 :                 remaining_len += snprintf(buffer, sizeof(buffer),
    2194             :                                           "type %d, code %d",
    2195           0 :                                           src_port->min_port,
    2196           0 :                                           dst_port->min_port);
    2197           0 :         else if (bpf->protocol == IPPROTO_UDP ||
    2198             :                  bpf->protocol == IPPROTO_TCP) {
    2199             : 
    2200           0 :                 if (src_port && src_port->min_port)
    2201           0 :                         remaining_len += snprintf(buffer,
    2202             :                                                   sizeof(buffer),
    2203             :                                                   "from [%u:%u]",
    2204             :                                                   src_port->min_port,
    2205           0 :                                                   src_port->max_port ?
    2206             :                                                   src_port->max_port :
    2207             :                                                   src_port->min_port);
    2208           0 :                 if (dst_port && dst_port->min_port)
    2209           0 :                         remaining_len += snprintf(buffer +
    2210             :                                                   remaining_len,
    2211             :                                                   sizeof(buffer)
    2212             :                                                   - remaining_len,
    2213             :                                                   "to [%u:%u]",
    2214             :                                                   dst_port->min_port,
    2215           0 :                                                   dst_port->max_port ?
    2216             :                                                   dst_port->max_port :
    2217             :                                                   dst_port->min_port);
    2218             :         }
    2219           0 :         if (pkt_len && (pkt_len->min_port || pkt_len->max_port)) {
    2220           0 :                 remaining_len += snprintf(buffer + remaining_len,
    2221             :                                           sizeof(buffer)
    2222             :                                           - remaining_len,
    2223             :                                           " len [%u:%u]",
    2224             :                                           pkt_len->min_port,
    2225           0 :                                           pkt_len->max_port ?
    2226             :                                           pkt_len->max_port :
    2227           0 :                                           pkt_len->min_port);
    2228           0 :         } else if (bpf->pkt_len_val) {
    2229           0 :                 remaining_len += snprintf(buffer + remaining_len,
    2230             :                                           sizeof(buffer)
    2231             :                                           - remaining_len,
    2232             :                                           " %s len %u",
    2233           0 :                                           bpf->pkt_len_val->mask
    2234             :                                           ? "!" : "",
    2235           0 :                                           bpf->pkt_len_val->val);
    2236             :         }
    2237           0 :         if (bpf->tcp_flags) {
    2238           0 :                 remaining_len += snprintf(buffer + remaining_len,
    2239             :                                           sizeof(buffer)
    2240             :                                           - remaining_len,
    2241             :                                           "tcpflags %x/%x",
    2242           0 :                                           bpf->tcp_flags->val,
    2243           0 :                                           bpf->tcp_flags->mask);
    2244             :         }
    2245           0 :         if (bpf->dscp) {
    2246           0 :                 snprintf(buffer + remaining_len,
    2247             :                          sizeof(buffer)
    2248             :                          - remaining_len,
    2249             :                          "%s dscp %d",
    2250           0 :                          bpf->dscp->mask
    2251             :                          ? "!" : "",
    2252           0 :                          bpf->dscp->val);
    2253             :         }
    2254           0 :         if (bpf->flow_label) {
    2255           0 :                 snprintf(buffer + remaining_len,
    2256             :                          sizeof(buffer)
    2257             :                          - remaining_len,
    2258             :                          "%s flow_label %d",
    2259           0 :                          bpf->flow_label->mask
    2260             :                          ? "!" : "",
    2261           0 :                          bpf->flow_label->val);
    2262             :         }
    2263           0 :         zlog_debug("BGP: %s FS PBR from %s to %s, %s %s",
    2264             :                   add ? "adding" : "removing",
    2265             :                   bpf->src == NULL ? "<all>" :
    2266             :                   prefix2str(bpf->src, bufsrc, sizeof(bufsrc)),
    2267             :                   bpf->dst == NULL ? "<all>" :
    2268             :                   prefix2str(bpf->dst, bufdst, sizeof(bufdst)),
    2269             :                   protocol_str, buffer);
    2270             : 
    2271             : }
    2272             : 
    2273           0 : static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp,
    2274             :                                                   struct bgp_path_info *path,
    2275             :                                                   struct bgp_pbr_filter *bpf,
    2276             :                                                   struct nexthop *nh,
    2277             :                                                   float *rate)
    2278             : {
    2279           0 :         struct bgp_pbr_match temp;
    2280           0 :         struct bgp_pbr_match_entry temp2;
    2281           0 :         struct bgp_pbr_match *bpm;
    2282           0 :         struct bgp_pbr_match_entry *bpme = NULL;
    2283           0 :         struct bgp_pbr_action temp3;
    2284           0 :         struct bgp_pbr_action *bpa = NULL;
    2285           0 :         struct bgp_pbr_match_entry_remain bpmer;
    2286           0 :         struct bgp_pbr_rule_remain bprr;
    2287           0 :         struct bgp_pbr_range_port *src_port;
    2288           0 :         struct bgp_pbr_range_port *dst_port;
    2289           0 :         struct bgp_pbr_range_port *pkt_len;
    2290           0 :         struct bgp_pbr_rule pbr_rule;
    2291           0 :         struct bgp_pbr_rule *bpr;
    2292           0 :         bool bpr_found = false;
    2293           0 :         bool bpme_found = false;
    2294           0 :         struct vrf *vrf = NULL;
    2295             : 
    2296           0 :         if (!bpf)
    2297           0 :                 return;
    2298           0 :         src_port = bpf->src_port;
    2299           0 :         dst_port = bpf->dst_port;
    2300           0 :         pkt_len = bpf->pkt_len;
    2301             : 
    2302           0 :         if (BGP_DEBUG(zebra, ZEBRA))
    2303           0 :                 bgp_pbr_dump_entry(bpf, true);
    2304             : 
    2305             :         /* look for bpa first */
    2306           0 :         memset(&temp3, 0, sizeof(temp3));
    2307           0 :         if (rate)
    2308           0 :                 temp3.rate = *rate;
    2309           0 :         if (nh)
    2310           0 :                 memcpy(&temp3.nh, nh, sizeof(struct nexthop));
    2311           0 :         temp3.vrf_id = bpf->vrf_id;
    2312           0 :         temp3.afi = family2afi(bpf->family);
    2313           0 :         bpa = hash_get(bgp->pbr_action_hash, &temp3,
    2314             :                        bgp_pbr_action_alloc_intern);
    2315             : 
    2316           0 :         if (nh)
    2317           0 :                 vrf = vrf_lookup_by_id(nh->vrf_id);
    2318           0 :         if (bpa->fwmark == 0) {
    2319             :                 /* drop is handled by iptable */
    2320           0 :                 if (nh && nh->type == NEXTHOP_TYPE_BLACKHOLE) {
    2321           0 :                         bpa->table_id = 0;
    2322           0 :                         bpa->installed = true;
    2323             :                 } else {
    2324           0 :                         bpa->fwmark = bgp_zebra_tm_get_id();
    2325             :                         /* if action is redirect-vrf, then
    2326             :                          * use directly table_id of vrf
    2327             :                          */
    2328           0 :                         if (nh && vrf && !vrf_is_backend_netns()
    2329           0 :                             && bpf->vrf_id != vrf->vrf_id)
    2330           0 :                                 bpa->table_id = vrf->data.l.table_id;
    2331             :                         else
    2332           0 :                                 bpa->table_id = bpa->fwmark;
    2333           0 :                         bpa->installed = false;
    2334             :                 }
    2335           0 :                 bpa->bgp = bgp;
    2336           0 :                 bpa->unique = ++bgp_pbr_action_counter_unique;
    2337             :                 /* 0 value is forbidden */
    2338           0 :                 bpa->install_in_progress = false;
    2339             :         }
    2340           0 :         if (bpf->type == BGP_PBR_IPRULE) {
    2341           0 :                 memset(&pbr_rule, 0, sizeof(pbr_rule));
    2342           0 :                 pbr_rule.vrf_id = bpf->vrf_id;
    2343           0 :                 pbr_rule.priority = 20;
    2344           0 :                 if (bpf->src) {
    2345           0 :                         pbr_rule.flags |= MATCH_IP_SRC_SET;
    2346           0 :                         prefix_copy(&pbr_rule.src, bpf->src);
    2347             :                 }
    2348           0 :                 if (bpf->dst) {
    2349           0 :                         pbr_rule.flags |= MATCH_IP_DST_SET;
    2350           0 :                         prefix_copy(&pbr_rule.dst, bpf->dst);
    2351             :                 }
    2352           0 :                 pbr_rule.action = bpa;
    2353           0 :                 bpr = hash_get(bgp->pbr_rule_hash, &pbr_rule,
    2354             :                                bgp_pbr_rule_alloc_intern);
    2355           0 :                 if (bpr->unique == 0) {
    2356           0 :                         bpr->unique = ++bgp_pbr_action_counter_unique;
    2357           0 :                         bpr->installed = false;
    2358           0 :                         bpr->install_in_progress = false;
    2359             :                         /* link bgp info to bpr */
    2360           0 :                         bpr->path = (void *)path;
    2361             :                 } else
    2362             :                         bpr_found = true;
    2363             :                 /* already installed */
    2364           0 :                 if (bpr_found) {
    2365           0 :                         struct bgp_path_info_extra *extra =
    2366           0 :                                 bgp_path_info_extra_get(path);
    2367             : 
    2368           0 :                         if (extra &&
    2369           0 :                             listnode_lookup_nocheck(extra->bgp_fs_iprule,
    2370             :                                                     bpr)) {
    2371           0 :                                 if (BGP_DEBUG(pbr, PBR_ERROR))
    2372           0 :                                         zlog_err("%s: entry %p/%p already installed in bgp pbr iprule",
    2373             :                                                  __func__, path, bpr);
    2374           0 :                                 return;
    2375             :                         }
    2376             :                 }
    2377             : 
    2378           0 :                 bgp_pbr_bpa_add(bpa);
    2379             : 
    2380             :                 /* ip rule add */
    2381           0 :                 if (!bpr->installed)
    2382           0 :                         bgp_send_pbr_rule_action(bpa, bpr, true);
    2383             : 
    2384             :                 /* A previous entry may already exist
    2385             :                  * flush previous entry if necessary
    2386             :                  */
    2387           0 :                 bprr.bpr_to_match = bpr;
    2388           0 :                 bprr.bpr_found = NULL;
    2389           0 :                 hash_walk(bgp->pbr_rule_hash, bgp_pbr_get_same_rule, &bprr);
    2390           0 :                 if (bprr.bpr_found) {
    2391           0 :                         static struct bgp_pbr_rule *local_bpr;
    2392           0 :                         static struct bgp_pbr_action *local_bpa;
    2393             : 
    2394           0 :                         local_bpr = bprr.bpr_found;
    2395           0 :                         local_bpa = local_bpr->action;
    2396           0 :                         bgp_pbr_flush_iprule(bgp, local_bpa,
    2397             :                                              local_bpr);
    2398             :                 }
    2399           0 :                 return;
    2400             :         }
    2401             :         /* then look for bpm */
    2402           0 :         memset(&temp, 0, sizeof(temp));
    2403           0 :         temp.vrf_id = bpf->vrf_id;
    2404           0 :         temp.family = bpf->family;
    2405           0 :         if (bpf->src)
    2406           0 :                 temp.flags |= MATCH_IP_SRC_SET;
    2407           0 :         if (bpf->dst)
    2408           0 :                 temp.flags |= MATCH_IP_DST_SET;
    2409             : 
    2410           0 :         if (src_port && (src_port->min_port || bpf->protocol == IPPROTO_ICMP)) {
    2411           0 :                 if (bpf->protocol == IPPROTO_ICMP)
    2412           0 :                         temp.flags |= MATCH_ICMP_SET;
    2413           0 :                 temp.flags |= MATCH_PORT_SRC_SET;
    2414             :         }
    2415           0 :         if (dst_port && (dst_port->min_port || bpf->protocol == IPPROTO_ICMP)) {
    2416           0 :                 if (bpf->protocol == IPPROTO_ICMP)
    2417           0 :                         temp.flags |= MATCH_ICMP_SET;
    2418           0 :                 temp.flags |= MATCH_PORT_DST_SET;
    2419             :         }
    2420           0 :         if (src_port && src_port->max_port)
    2421           0 :                 temp.flags |= MATCH_PORT_SRC_RANGE_SET;
    2422           0 :         if (dst_port && dst_port->max_port)
    2423           0 :                 temp.flags |= MATCH_PORT_DST_RANGE_SET;
    2424             : 
    2425           0 :         if (bpf->src == NULL || bpf->dst == NULL) {
    2426           0 :                 if (temp.flags & (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET))
    2427           0 :                         temp.type = IPSET_NET_PORT;
    2428             :                 else
    2429           0 :                         temp.type = IPSET_NET;
    2430             :         } else {
    2431           0 :                 if (temp.flags & (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET))
    2432           0 :                         temp.type = IPSET_NET_PORT_NET;
    2433             :                 else
    2434           0 :                         temp.type = IPSET_NET_NET;
    2435             :         }
    2436           0 :         if (pkt_len) {
    2437           0 :                 temp.pkt_len_min = pkt_len->min_port;
    2438           0 :                 if (pkt_len->max_port)
    2439           0 :                         temp.pkt_len_max = pkt_len->max_port;
    2440           0 :         } else if (bpf->pkt_len_val) {
    2441           0 :                 if (bpf->pkt_len_val->mask)
    2442           0 :                         temp.flags |= MATCH_PKT_LEN_INVERSE_SET;
    2443           0 :                 temp.pkt_len_min = bpf->pkt_len_val->val;
    2444             :         }
    2445           0 :         if (bpf->tcp_flags) {
    2446           0 :                 temp.tcp_flags = bpf->tcp_flags->val;
    2447           0 :                 temp.tcp_mask_flags = bpf->tcp_flags->mask;
    2448             :         }
    2449           0 :         if (bpf->dscp) {
    2450           0 :                 if (bpf->dscp->mask)
    2451           0 :                         temp.flags |= MATCH_DSCP_INVERSE_SET;
    2452             :                 else
    2453           0 :                         temp.flags |= MATCH_DSCP_SET;
    2454           0 :                 temp.dscp_value = bpf->dscp->val;
    2455             :         }
    2456           0 :         if (bpf->flow_label) {
    2457           0 :                 if (bpf->flow_label->mask)
    2458           0 :                         temp.flags |= MATCH_FLOW_LABEL_INVERSE_SET;
    2459             :                 else
    2460           0 :                         temp.flags |= MATCH_FLOW_LABEL_SET;
    2461           0 :                 temp.flow_label = bpf->flow_label->val;
    2462             :         }
    2463           0 :         if (bpf->fragment) {
    2464           0 :                 if (bpf->fragment->mask)
    2465           0 :                         temp.flags |= MATCH_FRAGMENT_INVERSE_SET;
    2466           0 :                 temp.fragment = bpf->fragment->val;
    2467             :         }
    2468           0 :         if (bpf->protocol) {
    2469           0 :                 temp.protocol = bpf->protocol;
    2470           0 :                 temp.flags |= MATCH_PROTOCOL_SET;
    2471             :         }
    2472           0 :         temp.action = bpa;
    2473           0 :         bpm = hash_get(bgp->pbr_match_hash, &temp,
    2474             :                        bgp_pbr_match_alloc_intern);
    2475             : 
    2476             :         /* new, then self allocate ipset_name and unique */
    2477           0 :         if (bpm->unique == 0) {
    2478           0 :                 bpm->unique = ++bgp_pbr_match_counter_unique;
    2479             :                 /* 0 value is forbidden */
    2480           0 :                 snprintf(bpm->ipset_name, sizeof(bpm->ipset_name),
    2481             :                          "match%p", bpm);
    2482           0 :                 bpm->entry_hash = hash_create_size(8,
    2483             :                                    bgp_pbr_match_entry_hash_key,
    2484             :                                    bgp_pbr_match_entry_hash_equal,
    2485             :                                    "Match Entry Hash");
    2486           0 :                 bpm->installed = false;
    2487             : 
    2488             :                 /* unique2 should be updated too */
    2489           0 :                 bpm->unique2 = ++bgp_pbr_match_iptable_counter_unique;
    2490           0 :                 bpm->installed_in_iptable = false;
    2491           0 :                 bpm->install_in_progress = false;
    2492           0 :                 bpm->install_iptable_in_progress = false;
    2493             :         }
    2494             : 
    2495           0 :         memset(&temp2, 0, sizeof(temp2));
    2496           0 :         if (bpf->src)
    2497           0 :                 prefix_copy(&temp2.src, bpf->src);
    2498             :         else
    2499           0 :                 temp2.src.family = bpf->family;
    2500           0 :         if (bpf->dst)
    2501           0 :                 prefix_copy(&temp2.dst, bpf->dst);
    2502             :         else
    2503           0 :                 temp2.dst.family = bpf->family;
    2504           0 :         temp2.src_port_min = src_port ? src_port->min_port : 0;
    2505           0 :         temp2.dst_port_min = dst_port ? dst_port->min_port : 0;
    2506           0 :         temp2.src_port_max = src_port ? src_port->max_port : 0;
    2507           0 :         temp2.dst_port_max = dst_port ? dst_port->max_port : 0;
    2508           0 :         temp2.proto = bpf->protocol;
    2509           0 :         bpme = hash_get(bpm->entry_hash, &temp2,
    2510             :                         bgp_pbr_match_entry_alloc_intern);
    2511           0 :         if (bpme->unique == 0) {
    2512           0 :                 bpme->unique = ++bgp_pbr_match_entry_counter_unique;
    2513             :                 /* 0 value is forbidden */
    2514           0 :                 bpme->backpointer = bpm;
    2515           0 :                 bpme->installed = false;
    2516           0 :                 bpme->install_in_progress = false;
    2517             :                 /* link bgp info to bpme */
    2518           0 :                 bpme->path = (void *)path;
    2519             :         } else
    2520             :                 bpme_found = true;
    2521             : 
    2522             :         /* already installed */
    2523           0 :         if (bpme_found) {
    2524           0 :                 struct bgp_path_info_extra *extra =
    2525           0 :                         bgp_path_info_extra_get(path);
    2526             : 
    2527           0 :                 if (extra &&
    2528           0 :                     listnode_lookup_nocheck(extra->bgp_fs_pbr, bpme)) {
    2529           0 :                         if (BGP_DEBUG(pbr, PBR_ERROR))
    2530           0 :                                 zlog_err(
    2531             :                                         "%s: entry %p/%p already installed in bgp pbr",
    2532             :                                         __func__, path, bpme);
    2533           0 :                         return;
    2534             :                 }
    2535             :         }
    2536             :         /* BGP FS: append entry to zebra
    2537             :          * - policies are not routing entries and as such
    2538             :          * route replace semantics don't necessarily follow
    2539             :          * through to policy entries
    2540             :          * - because of that, not all policing information will be stored
    2541             :          * into zebra. and non selected policies will be suppressed from zebra
    2542             :          * - as consequence, in order to bring consistency
    2543             :          * a policy will be added, then ifan ecmp policy exists,
    2544             :          * it will be suppressed subsequently
    2545             :          */
    2546             :         /* ip rule add */
    2547           0 :         bgp_pbr_bpa_add(bpa);
    2548             : 
    2549             :         /* ipset create */
    2550           0 :         if (!bpm->installed)
    2551           0 :                 bgp_send_pbr_ipset_match(bpm, true);
    2552             :         /* ipset add */
    2553           0 :         if (!bpme->installed)
    2554           0 :                 bgp_send_pbr_ipset_entry_match(bpme, true);
    2555             : 
    2556             :         /* iptables */
    2557           0 :         if (!bpm->installed_in_iptable)
    2558           0 :                 bgp_send_pbr_iptable(bpa, bpm, true);
    2559             : 
    2560             :         /* A previous entry may already exist
    2561             :          * flush previous entry if necessary
    2562             :          */
    2563           0 :         bpmer.bpme_to_match = bpme;
    2564           0 :         bpmer.bpme_found = NULL;
    2565           0 :         hash_walk(bgp->pbr_match_hash, bgp_pbr_get_remaining_entry, &bpmer);
    2566           0 :         if (bpmer.bpme_found) {
    2567           0 :                 static struct bgp_pbr_match *local_bpm;
    2568           0 :                 static struct bgp_pbr_action *local_bpa;
    2569             : 
    2570           0 :                 local_bpm = bpmer.bpme_found->backpointer;
    2571           0 :                 local_bpa = local_bpm->action;
    2572           0 :                 bgp_pbr_flush_entry(bgp, local_bpa,
    2573             :                                     local_bpm, bpmer.bpme_found);
    2574             :         }
    2575             : 
    2576             : 
    2577             : }
    2578             : 
    2579           0 : static void bgp_pbr_policyroute_add_to_zebra_recursive(
    2580             :         struct bgp *bgp, struct bgp_path_info *path, struct bgp_pbr_filter *bpf,
    2581             :         struct bgp_pbr_or_filter *bpof, struct nexthop *nh, float *rate,
    2582             :         uint8_t type_entry)
    2583             : {
    2584           0 :         struct listnode *node, *nnode;
    2585           0 :         struct bgp_pbr_val_mask *valmask;
    2586           0 :         uint8_t next_type_entry;
    2587           0 :         struct list *orig_list;
    2588           0 :         struct bgp_pbr_val_mask **target_val;
    2589             : 
    2590           0 :         if (type_entry == 0) {
    2591           0 :                 bgp_pbr_policyroute_add_to_zebra_unit(bgp, path, bpf, nh, rate);
    2592           0 :                 return;
    2593             :         }
    2594           0 :         next_type_entry = bgp_pbr_next_type_entry(type_entry);
    2595           0 :         if (type_entry == FLOWSPEC_TCP_FLAGS && bpof->tcpflags) {
    2596           0 :                 orig_list = bpof->tcpflags;
    2597           0 :                 target_val = &bpf->tcp_flags;
    2598           0 :         } else if (type_entry == FLOWSPEC_DSCP && bpof->dscp) {
    2599           0 :                 orig_list = bpof->dscp;
    2600           0 :                 target_val = &bpf->dscp;
    2601           0 :         } else if (type_entry == FLOWSPEC_PKT_LEN && bpof->pkt_len) {
    2602           0 :                 orig_list = bpof->pkt_len;
    2603           0 :                 target_val = &bpf->pkt_len_val;
    2604           0 :         } else if (type_entry == FLOWSPEC_FRAGMENT && bpof->fragment) {
    2605           0 :                 orig_list = bpof->fragment;
    2606           0 :                 target_val = &bpf->fragment;
    2607           0 :         } else if (type_entry == FLOWSPEC_ICMP_TYPE &&
    2608           0 :                    (bpof->icmp_type || bpof->icmp_code)) {
    2609             :                 /* enumerate list for icmp - must be last one  */
    2610           0 :                 bgp_pbr_icmp_action(bgp, path, bpf, bpof, true, nh, rate);
    2611           0 :                 return;
    2612             :         } else {
    2613           0 :                 bgp_pbr_policyroute_add_to_zebra_recursive(
    2614             :                         bgp, path, bpf, bpof, nh, rate, next_type_entry);
    2615           0 :                 return;
    2616             :         }
    2617           0 :         for (ALL_LIST_ELEMENTS(orig_list, node, nnode, valmask)) {
    2618           0 :                 *target_val = valmask;
    2619           0 :                 bgp_pbr_policyroute_add_to_zebra_recursive(
    2620             :                         bgp, path, bpf, bpof, nh, rate, next_type_entry);
    2621             :         }
    2622             : }
    2623             : 
    2624           0 : static void bgp_pbr_policyroute_add_to_zebra(struct bgp *bgp,
    2625             :                                              struct bgp_path_info *path,
    2626             :                                              struct bgp_pbr_filter *bpf,
    2627             :                                              struct bgp_pbr_or_filter *bpof,
    2628             :                                              struct nexthop *nh, float *rate)
    2629             : {
    2630           0 :         if (!bpof) {
    2631           0 :                 bgp_pbr_policyroute_add_to_zebra_unit(bgp, path, bpf, nh, rate);
    2632           0 :                 return;
    2633             :         }
    2634           0 :         if (bpof->tcpflags)
    2635           0 :                 bgp_pbr_policyroute_add_to_zebra_recursive(
    2636             :                         bgp, path, bpf, bpof, nh, rate, FLOWSPEC_TCP_FLAGS);
    2637           0 :         else if (bpof->dscp)
    2638           0 :                 bgp_pbr_policyroute_add_to_zebra_recursive(
    2639             :                         bgp, path, bpf, bpof, nh, rate, FLOWSPEC_DSCP);
    2640           0 :         else if (bpof->pkt_len)
    2641           0 :                 bgp_pbr_policyroute_add_to_zebra_recursive(
    2642             :                         bgp, path, bpf, bpof, nh, rate, FLOWSPEC_PKT_LEN);
    2643           0 :         else if (bpof->fragment)
    2644           0 :                 bgp_pbr_policyroute_add_to_zebra_recursive(
    2645             :                         bgp, path, bpf, bpof, nh, rate, FLOWSPEC_FRAGMENT);
    2646           0 :         else if (bpof->icmp_type || bpof->icmp_code)
    2647           0 :                 bgp_pbr_policyroute_add_to_zebra_recursive(
    2648             :                         bgp, path, bpf, bpof, nh, rate, FLOWSPEC_ICMP_TYPE);
    2649             :         else
    2650           0 :                 bgp_pbr_policyroute_add_to_zebra_unit(bgp, path, bpf, nh, rate);
    2651             :         /* flush bpof */
    2652           0 :         if (bpof->tcpflags)
    2653           0 :                 list_delete_all_node(bpof->tcpflags);
    2654           0 :         if (bpof->dscp)
    2655           0 :                 list_delete_all_node(bpof->dscp);
    2656           0 :         if (bpof->pkt_len)
    2657           0 :                 list_delete_all_node(bpof->pkt_len);
    2658           0 :         if (bpof->fragment)
    2659           0 :                 list_delete_all_node(bpof->fragment);
    2660           0 :         if (bpof->icmp_type)
    2661           0 :                 list_delete_all_node(bpof->icmp_type);
    2662           0 :         if (bpof->icmp_code)
    2663           0 :                 list_delete_all_node(bpof->icmp_code);
    2664             : }
    2665             : 
    2666           0 : static void bgp_pbr_handle_entry(struct bgp *bgp, struct bgp_path_info *path,
    2667             :                                  struct bgp_pbr_entry_main *api, bool add)
    2668             : {
    2669           0 :         struct nexthop nh;
    2670           0 :         int i = 0;
    2671           0 :         int continue_loop = 1;
    2672           0 :         float rate = 0;
    2673           0 :         struct prefix *src = NULL, *dst = NULL;
    2674           0 :         uint8_t proto = 0;
    2675           0 :         struct bgp_pbr_range_port *srcp = NULL, *dstp = NULL;
    2676           0 :         struct bgp_pbr_range_port range, range_icmp_code;
    2677           0 :         struct bgp_pbr_range_port pkt_len;
    2678           0 :         struct bgp_pbr_filter bpf;
    2679           0 :         uint8_t kind_enum;
    2680           0 :         struct bgp_pbr_or_filter bpof;
    2681           0 :         struct bgp_pbr_val_mask bpvm;
    2682             : 
    2683           0 :         memset(&range, 0, sizeof(range));
    2684           0 :         memset(&nh, 0, sizeof(nh));
    2685           0 :         memset(&bpf, 0, sizeof(bpf));
    2686           0 :         memset(&bpof, 0, sizeof(bpof));
    2687           0 :         if (api->match_bitmask & PREFIX_SRC_PRESENT ||
    2688           0 :             (api->type == BGP_PBR_IPRULE &&
    2689           0 :              api->match_bitmask_iprule & PREFIX_SRC_PRESENT))
    2690           0 :                 src = &api->src_prefix;
    2691           0 :         if (api->match_bitmask & PREFIX_DST_PRESENT ||
    2692           0 :             (api->type == BGP_PBR_IPRULE &&
    2693           0 :              api->match_bitmask_iprule & PREFIX_DST_PRESENT))
    2694           0 :                 dst = &api->dst_prefix;
    2695           0 :         if (api->type == BGP_PBR_IPRULE)
    2696           0 :                 bpf.type = api->type;
    2697           0 :         memset(&nh, 0, sizeof(nh));
    2698           0 :         nh.vrf_id = VRF_UNKNOWN;
    2699           0 :         if (api->match_protocol_num) {
    2700           0 :                 proto = (uint8_t)api->protocol[0].value;
    2701           0 :                 if (api->afi == AF_INET6 && proto == IPPROTO_ICMPV6)
    2702           0 :                         proto = IPPROTO_ICMP;
    2703             :         }
    2704             :         /* if match_port is selected, then either src or dst port will be parsed
    2705             :          * but not both at the same time
    2706             :          */
    2707           0 :         if (api->match_port_num >= 1) {
    2708           0 :                 bgp_pbr_extract(api->port,
    2709             :                                 api->match_port_num,
    2710             :                                 &range);
    2711           0 :                 srcp = dstp = &range;
    2712           0 :         } else if (api->match_src_port_num >= 1) {
    2713           0 :                 bgp_pbr_extract(api->src_port,
    2714             :                                 api->match_src_port_num,
    2715             :                                 &range);
    2716           0 :                 srcp = &range;
    2717           0 :                 dstp = NULL;
    2718           0 :         } else if (api->match_dst_port_num >= 1) {
    2719           0 :                 bgp_pbr_extract(api->dst_port,
    2720             :                                 api->match_dst_port_num,
    2721             :                                 &range);
    2722           0 :                 dstp = &range;
    2723           0 :                 srcp = NULL;
    2724             :         }
    2725           0 :         if (api->match_icmp_type_num >= 1) {
    2726           0 :                 proto = IPPROTO_ICMP;
    2727           0 :                 if (bgp_pbr_extract(api->icmp_type,
    2728             :                                     api->match_icmp_type_num,
    2729             :                                     &range))
    2730             :                         srcp = &range;
    2731             :                 else {
    2732           0 :                         bpof.icmp_type = list_new();
    2733           0 :                         bgp_pbr_extract_enumerate(api->icmp_type,
    2734           0 :                                                   api->match_icmp_type_num,
    2735             :                                                   OPERATOR_UNARY_OR,
    2736             :                                                   bpof.icmp_type,
    2737             :                                                   FLOWSPEC_ICMP_TYPE);
    2738             :                 }
    2739             :         }
    2740           0 :         if (api->match_icmp_code_num >= 1) {
    2741           0 :                 proto = IPPROTO_ICMP;
    2742           0 :                 if (bgp_pbr_extract(api->icmp_code,
    2743             :                                     api->match_icmp_code_num,
    2744             :                                     &range_icmp_code))
    2745             :                         dstp = &range_icmp_code;
    2746             :                 else {
    2747           0 :                         bpof.icmp_code = list_new();
    2748           0 :                         bgp_pbr_extract_enumerate(api->icmp_code,
    2749           0 :                                                   api->match_icmp_code_num,
    2750             :                                                   OPERATOR_UNARY_OR,
    2751             :                                                   bpof.icmp_code,
    2752             :                                                   FLOWSPEC_ICMP_CODE);
    2753             :                 }
    2754             :         }
    2755             : 
    2756           0 :         if (api->match_tcpflags_num) {
    2757           0 :                 kind_enum = bgp_pbr_match_val_get_operator(api->tcpflags,
    2758             :                                                    api->match_tcpflags_num);
    2759           0 :                 if (kind_enum == OPERATOR_UNARY_AND) {
    2760           0 :                         bpf.tcp_flags = &bpvm;
    2761           0 :                         bgp_pbr_extract_enumerate(api->tcpflags,
    2762             :                                                   api->match_tcpflags_num,
    2763             :                                                   OPERATOR_UNARY_AND,
    2764             :                                                   bpf.tcp_flags,
    2765             :                                                   FLOWSPEC_TCP_FLAGS);
    2766           0 :                 } else if (kind_enum == OPERATOR_UNARY_OR) {
    2767           0 :                         bpof.tcpflags = list_new();
    2768           0 :                         bgp_pbr_extract_enumerate(api->tcpflags,
    2769           0 :                                                   api->match_tcpflags_num,
    2770             :                                                   OPERATOR_UNARY_OR,
    2771             :                                                   bpof.tcpflags,
    2772             :                                                   FLOWSPEC_TCP_FLAGS);
    2773             :                 }
    2774             :         }
    2775           0 :         if (api->match_packet_length_num) {
    2776           0 :                 bool ret;
    2777             : 
    2778           0 :                 ret = bgp_pbr_extract(api->packet_length,
    2779             :                                       api->match_packet_length_num,
    2780             :                                       &pkt_len);
    2781           0 :                 if (ret)
    2782           0 :                         bpf.pkt_len = &pkt_len;
    2783             :                 else {
    2784           0 :                         bpof.pkt_len = list_new();
    2785           0 :                         bgp_pbr_extract_enumerate(api->packet_length,
    2786           0 :                                                   api->match_packet_length_num,
    2787             :                                                   OPERATOR_UNARY_OR,
    2788             :                                                   bpof.pkt_len,
    2789             :                                                   FLOWSPEC_PKT_LEN);
    2790             :                 }
    2791             :         }
    2792           0 :         if (api->match_dscp_num >= 1) {
    2793           0 :                 bpof.dscp = list_new();
    2794           0 :                 bgp_pbr_extract_enumerate(api->dscp, api->match_dscp_num,
    2795             :                                           OPERATOR_UNARY_OR,
    2796             :                                           bpof.dscp, FLOWSPEC_DSCP);
    2797             :         }
    2798           0 :         if (api->match_fragment_num) {
    2799           0 :                 bpof.fragment = list_new();
    2800           0 :                 bgp_pbr_extract_enumerate(api->fragment,
    2801           0 :                                           api->match_fragment_num,
    2802             :                                           OPERATOR_UNARY_OR,
    2803             :                                           bpof.fragment,
    2804             :                                           FLOWSPEC_FRAGMENT);
    2805             :         }
    2806           0 :         bpf.vrf_id = api->vrf_id;
    2807           0 :         bpf.src = src;
    2808           0 :         bpf.dst = dst;
    2809           0 :         bpf.protocol = proto;
    2810           0 :         bpf.src_port = srcp;
    2811           0 :         bpf.dst_port = dstp;
    2812           0 :         bpf.family = afi2family(api->afi);
    2813           0 :         if (!add) {
    2814           0 :                 bgp_pbr_policyroute_remove_from_zebra(bgp, path, &bpf, &bpof);
    2815           0 :                 return;
    2816             :         }
    2817             :         /* no action for add = true */
    2818           0 :         for (i = 0; i < api->action_num; i++) {
    2819           0 :                 switch (api->actions[i].action) {
    2820           0 :                 case ACTION_TRAFFICRATE:
    2821             :                         /* drop packet */
    2822           0 :                         if (api->actions[i].u.r.rate == 0) {
    2823           0 :                                 nh.vrf_id = api->vrf_id;
    2824           0 :                                 nh.type = NEXTHOP_TYPE_BLACKHOLE;
    2825           0 :                                 bgp_pbr_policyroute_add_to_zebra(
    2826             :                                         bgp, path, &bpf, &bpof, &nh, &rate);
    2827             :                         } else {
    2828             :                                 /* update rate. can be reentrant */
    2829           0 :                                 rate = api->actions[i].u.r.rate;
    2830           0 :                                 if (BGP_DEBUG(pbr, PBR)) {
    2831           0 :                                         bgp_pbr_print_policy_route(api);
    2832           0 :                                         zlog_warn("PBR: ignoring Set action rate %f",
    2833             :                                                   api->actions[i].u.r.rate);
    2834             :                                 }
    2835             :                         }
    2836             :                         break;
    2837           0 :                 case ACTION_TRAFFIC_ACTION:
    2838           0 :                         if (api->actions[i].u.za.filter
    2839             :                             & TRAFFIC_ACTION_SAMPLE) {
    2840           0 :                                 if (BGP_DEBUG(pbr, PBR)) {
    2841           0 :                                         bgp_pbr_print_policy_route(api);
    2842           0 :                                         zlog_warn("PBR: Sample action Ignored");
    2843             :                                 }
    2844             :                         }
    2845             :                         /* terminate action: run other filters
    2846             :                          */
    2847             :                         break;
    2848           0 :                 case ACTION_REDIRECT_IP:
    2849           0 :                         nh.vrf_id = api->vrf_id;
    2850           0 :                         if (api->afi == AFI_IP) {
    2851           0 :                                 nh.type = NEXTHOP_TYPE_IPV4;
    2852           0 :                                 nh.gate.ipv4.s_addr =
    2853             :                                         api->actions[i].u.zr.
    2854           0 :                                         redirect_ip_v4.s_addr;
    2855             :                         } else {
    2856           0 :                                 nh.type = NEXTHOP_TYPE_IPV6;
    2857           0 :                                 memcpy(&nh.gate.ipv6,
    2858           0 :                                        &api->actions[i].u.zr.redirect_ip_v6,
    2859             :                                        sizeof(struct in6_addr));
    2860             :                         }
    2861           0 :                         bgp_pbr_policyroute_add_to_zebra(bgp, path, &bpf, &bpof,
    2862             :                                                          &nh, &rate);
    2863             :                         /* XXX combination with REDIRECT_VRF
    2864             :                          * + REDIRECT_NH_IP not done
    2865             :                          */
    2866           0 :                         continue_loop = 0;
    2867           0 :                         break;
    2868           0 :                 case ACTION_REDIRECT:
    2869           0 :                         if (api->afi == AFI_IP)
    2870           0 :                                 nh.type = NEXTHOP_TYPE_IPV4;
    2871             :                         else
    2872           0 :                                 nh.type = NEXTHOP_TYPE_IPV6;
    2873           0 :                         nh.vrf_id = api->actions[i].u.redirect_vrf;
    2874           0 :                         bgp_pbr_policyroute_add_to_zebra(bgp, path, &bpf, &bpof,
    2875             :                                                          &nh, &rate);
    2876           0 :                         continue_loop = 0;
    2877           0 :                         break;
    2878           0 :                 case ACTION_MARKING:
    2879           0 :                         if (BGP_DEBUG(pbr, PBR)) {
    2880           0 :                                 bgp_pbr_print_policy_route(api);
    2881           0 :                                 zlog_warn("PBR: Set DSCP/FlowLabel %u Ignored",
    2882             :                                           api->actions[i].u.marking_dscp);
    2883             :                         }
    2884             :                         break;
    2885             :                 default:
    2886             :                         break;
    2887             :                 }
    2888           0 :                 if (continue_loop == 0)
    2889             :                         break;
    2890             :         }
    2891             : }
    2892             : 
    2893           0 : void bgp_pbr_update_entry(struct bgp *bgp, const struct prefix *p,
    2894             :                           struct bgp_path_info *info, afi_t afi, safi_t safi,
    2895             :                           bool nlri_update)
    2896             : {
    2897           0 :         struct bgp_pbr_entry_main api;
    2898             : 
    2899           0 :         if (safi != SAFI_FLOWSPEC)
    2900           0 :                 return; /* not supported */
    2901             :         /* Make Zebra API structure. */
    2902           0 :         memset(&api, 0, sizeof(api));
    2903           0 :         api.vrf_id = bgp->vrf_id;
    2904           0 :         api.afi = afi;
    2905             : 
    2906           0 :         if (!bgp_zebra_tm_chunk_obtained()) {
    2907           0 :                 if (BGP_DEBUG(pbr, PBR_ERROR))
    2908           0 :                         flog_err(EC_BGP_TABLE_CHUNK,
    2909             :                                  "%s: table chunk not obtained yet", __func__);
    2910           0 :                 return;
    2911             :         }
    2912             : 
    2913           0 :         if (bgp_pbr_build_and_validate_entry(p, info, &api) < 0) {
    2914           0 :                 if (BGP_DEBUG(pbr, PBR_ERROR))
    2915           0 :                         flog_err(EC_BGP_FLOWSPEC_INSTALLATION,
    2916             :                                  "%s: cancel updating entry %p in bgp pbr",
    2917             :                                  __func__, info);
    2918           0 :                 return;
    2919             :         }
    2920           0 :         bgp_pbr_handle_entry(bgp, info, &api, nlri_update);
    2921             : }
    2922             : 
    2923           0 : int bgp_pbr_interface_compare(const struct bgp_pbr_interface *a,
    2924             :                           const struct bgp_pbr_interface *b)
    2925             : {
    2926           0 :         return strcmp(a->name, b->name);
    2927             : }
    2928             : 
    2929           0 : struct bgp_pbr_interface *bgp_pbr_interface_lookup(const char *name,
    2930             :                                            struct bgp_pbr_interface_head *head)
    2931             : {
    2932           0 :         struct bgp_pbr_interface pbr_if;
    2933             : 
    2934           0 :         strlcpy(pbr_if.name, name, sizeof(pbr_if.name));
    2935           0 :         return (RB_FIND(bgp_pbr_interface_head,
    2936             :                         head, &pbr_if));
    2937             : }
    2938             : 
    2939             : /* this function resets to the default policy routing
    2940             :  * go back to default status
    2941             :  */
    2942           4 : void bgp_pbr_reset(struct bgp *bgp, afi_t afi)
    2943             : {
    2944           4 :         struct bgp_pbr_config *bgp_pbr_cfg = bgp->bgp_pbr_cfg;
    2945           4 :         struct bgp_pbr_interface_head *head;
    2946           4 :         struct bgp_pbr_interface *pbr_if;
    2947             : 
    2948           4 :         if (!bgp_pbr_cfg)
    2949             :                 return;
    2950           4 :         if (afi == AFI_IP)
    2951           2 :                 head = &(bgp_pbr_cfg->ifaces_by_name_ipv4);
    2952             :         else
    2953           2 :                 head = &(bgp_pbr_cfg->ifaces_by_name_ipv6);
    2954           4 :         while (!RB_EMPTY(bgp_pbr_interface_head, head)) {
    2955           0 :                 pbr_if = RB_ROOT(bgp_pbr_interface_head, head);
    2956           0 :                 RB_REMOVE(bgp_pbr_interface_head, head, pbr_if);
    2957           4 :                 XFREE(MTYPE_TMP, pbr_if);
    2958             :         }
    2959             : }

Generated by: LCOV version v1.16-topotato