]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge pull request #2309 from opensourcerouting/master-mpls_te_print_detail-fix
authorOlivier Dugeon <olivier.dugeon@orange.com>
Fri, 1 Jun 2018 14:32:15 +0000 (16:32 +0200)
committerGitHub <noreply@github.com>
Fri, 1 Jun 2018 14:32:15 +0000 (16:32 +0200)
isisd: fix mpls_te_print_detail to not read out-of-bounds

35 files changed:
bgpd/bgp_attr.c
bgpd/bgp_debug.c
bgpd/bgp_ecommunity.c
bgpd/bgp_flowspec.h
bgpd/bgp_flowspec_vty.c
bgpd/bgp_pbr.c
bgpd/bgp_pbr.h
bgpd/bgp_rd.c
bgpd/bgp_route.c
bgpd/bgp_route.h
bgpd/bgp_zebra.c
bgpd/bgp_zebra.h
bgpd/bgpd.c
bgpd/bgpd.h
doc/user/sharp.rst
isisd/isis_tlvs.c
lib/memory.c
lib/pbr.h
lib/zclient.h
ospf6d/ospf6_abr.c
ospf6d/ospf6_abr.h
ospf6d/ospf6_asbr.c
pbrd/pbr_zebra.c
pimd/pim_msdp.c
redhat/daemons
redhat/frr.spec.in
tests/.gitignore
zebra/debug.c
zebra/debug.h
zebra/rule_netlink.c
zebra/zapi_msg.c
zebra/zebra_ns.c
zebra/zebra_pbr.c
zebra/zebra_pbr.h
zebra/zebra_vty.c

index 276a7054e37ae4007de403875b4f9ca32d191bad..e714e17bde3e3ea269e6de3b8c5147617e4d1882 100644 (file)
@@ -2276,7 +2276,8 @@ static int bgp_attr_check(struct peer *peer, struct attr *attr)
           are present, it should.  Check for any other attribute being present
           instead.
         */
-       if (attr->flag == ATTR_FLAG_BIT(BGP_ATTR_MP_UNREACH_NLRI))
+       if ((!CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI)) &&
+            CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MP_UNREACH_NLRI))))
                return BGP_ATTR_PARSE_PROCEED;
 
        if (!CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_ORIGIN)))
index 3e3fbcbfe8088e47e1d566c2efbde2838587f6df..a4ded57c25630d2008103bbcbb5a3e5a2bd62e43 100644 (file)
@@ -1661,11 +1661,23 @@ DEFUN (no_debug_bgp_vpn,
 /* debug bgp pbr */
 DEFUN (debug_bgp_pbr,
        debug_bgp_pbr_cmd,
-       "debug bgp pbr",
+       "debug bgp pbr [error]",
        DEBUG_STR
        BGP_STR
-       "BGP policy based routing\n")
+       "BGP policy based routing\n"
+       "BGP PBR error\n")
 {
+       int idx = 3;
+
+       if (argv_find(argv, argc, "error", &idx)) {
+               if (vty->node == CONFIG_NODE)
+                       DEBUG_ON(pbr, PBR_ERROR);
+               else {
+                       TERM_DEBUG_ON(pbr, PBR_ERROR);
+                       vty_out(vty, "BGP policy based routing error is on\n");
+               }
+               return CMD_SUCCESS;
+       }
        if (vty->node == CONFIG_NODE)
                DEBUG_ON(pbr, PBR);
        else {
@@ -1677,12 +1689,24 @@ DEFUN (debug_bgp_pbr,
 
 DEFUN (no_debug_bgp_pbr,
        no_debug_bgp_pbr_cmd,
-       "no debug bgp pbr",
+       "no debug bgp pbr [error]",
        NO_STR
        DEBUG_STR
        BGP_STR
-       "BGP policy based routing\n")
+       "BGP policy based routing\n"
+       "BGP PBR Error\n")
 {
+       int idx = 3;
+
+       if (argv_find(argv, argc, "error", &idx)) {
+               if (vty->node == CONFIG_NODE)
+                       DEBUG_OFF(pbr, PBR_ERROR);
+               else {
+                       TERM_DEBUG_OFF(pbr, PBR_ERROR);
+                       vty_out(vty, "BGP policy based routing error is off\n");
+               }
+               return CMD_SUCCESS;
+       }
        if (vty->node == CONFIG_NODE)
                DEBUG_OFF(pbr, PBR);
        else {
@@ -1769,6 +1793,7 @@ DEFUN (no_debug_bgp,
        TERM_DEBUG_OFF(flowspec, FLOWSPEC);
        TERM_DEBUG_OFF(labelpool, LABELPOOL);
        TERM_DEBUG_OFF(pbr, PBR);
+       TERM_DEBUG_OFF(pbr, PBR_ERROR);
        vty_out(vty, "All possible debugging has been turned off\n");
 
        return CMD_SUCCESS;
@@ -1846,6 +1871,8 @@ DEFUN_NOSH (show_debugging_bgp,
 
        if (BGP_DEBUG(pbr, PBR))
                vty_out(vty, "  BGP policy based routing debugging is on\n");
+       if (BGP_DEBUG(pbr, PBR_ERROR))
+               vty_out(vty, "  BGP policy based routing error debugging is on\n");
 
        vty_out(vty, "\n");
        return CMD_SUCCESS;
@@ -1906,6 +1933,8 @@ int bgp_debug_count(void)
 
        if (BGP_DEBUG(pbr, PBR))
                ret++;
+       if (BGP_DEBUG(pbr, PBR_ERROR))
+               ret++;
 
        return ret;
 }
@@ -2012,6 +2041,10 @@ static int bgp_config_write_debug(struct vty *vty)
                vty_out(vty, "debug bgp pbr\n");
                write++;
        }
+       if (CONF_BGP_DEBUG(pbr, PBR_ERROR)) {
+               vty_out(vty, "debug bgp pbr error\n");
+               write++;
+       }
        return write;
 }
 
index 99fe80f055497d5ebe0fec3050404a5f3340b210..20f5e15d6943243bede138153551d16d53f8f262 100644 (file)
@@ -642,9 +642,9 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
 {
        int i;
        uint8_t *pnt;
-       int type = 0;
-       int sub_type = 0;
-#define ECOMMUNITY_STR_DEFAULT_LEN  27
+       uint8_t type = 0;
+       uint8_t sub_type = 0;
+#define ECOMMUNITY_STR_DEFAULT_LEN  64
        int str_size;
        int str_pnt;
        char *str_buf;
@@ -750,10 +750,25 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
                                        "FS:redirect IP 0x%x", *(pnt+5));
                        } else
                                unk_ecom = 1;
-               } else if (type == ECOMMUNITY_ENCODE_TRANS_EXP) {
+               } else if (type == ECOMMUNITY_ENCODE_TRANS_EXP ||
+                          type == ECOMMUNITY_EXTENDED_COMMUNITY_PART_2 ||
+                          type == ECOMMUNITY_EXTENDED_COMMUNITY_PART_3) {
                        sub_type = *pnt++;
+                       if (sub_type == ECOMMUNITY_REDIRECT_VRF) {
+                               char buf[16];
 
-                       if (sub_type == ECOMMUNITY_TRAFFIC_ACTION) {
+                               memset(buf, 0, sizeof(buf));
+                               ecommunity_rt_soo_str(buf, (uint8_t *)pnt,
+                                                     type &
+                                                     ~ECOMMUNITY_ENCODE_TRANS_EXP,
+                                                     ECOMMUNITY_ROUTE_TARGET,
+                                                     ECOMMUNITY_FORMAT_DISPLAY);
+                               len = snprintf(str_buf + str_pnt,
+                                              str_size - len,
+                                              "FS:redirect VRF %s", buf);
+                       } else if (type != ECOMMUNITY_ENCODE_TRANS_EXP)
+                               unk_ecom = 1;
+                       else if (sub_type == ECOMMUNITY_TRAFFIC_ACTION) {
                                char action[64];
                                char *ptr = action;
 
@@ -782,30 +797,20 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
                                len = sprintf(
                                        str_buf + str_pnt,
                                        "FS:rate %f", data.rate_float);
-                       } else if (sub_type == ECOMMUNITY_REDIRECT_VRF) {
-                               char buf[16];
-
-                               memset(buf, 0, sizeof(buf));
-                               ecommunity_rt_soo_str(buf, (uint8_t *)pnt,
-                                               type &
-                                               ~ECOMMUNITY_ENCODE_TRANS_EXP,
-                                               ECOMMUNITY_ROUTE_TARGET,
-                                               ECOMMUNITY_FORMAT_DISPLAY);
-                               len = snprintf(
-                                       str_buf + str_pnt,
-                                       str_size - len,
-                                       "FS:redirect VRF %s", buf);
                        } else if (sub_type == ECOMMUNITY_TRAFFIC_MARKING) {
                                len = sprintf(
                                        str_buf + str_pnt,
                                        "FS:marking %u", *(pnt+5));
                        } else
                                unk_ecom = 1;
-               } else
+               } else {
+                       sub_type = *pnt++;
                        unk_ecom = 1;
+               }
 
                if (unk_ecom)
-                       len = sprintf(str_buf + str_pnt, "?");
+                       len = sprintf(str_buf + str_pnt, "UNK:%d, %d",
+                                     type, sub_type);
 
                str_pnt += len;
                first = 0;
index 392b32153036dd82f412ddb85e508900375a3dcb..5dd2c3931ac7a78c1150aded46b125d375c3fd86 100644 (file)
@@ -47,4 +47,7 @@ extern void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len,
 extern void route_vty_out_flowspec(struct vty *vty, struct prefix *p,
                                   struct bgp_info *binfo,
                                   int display, json_object *json_paths);
+extern int bgp_fs_config_write_pbr(struct vty *vty, struct bgp *bgp,
+                                  afi_t afi, safi_t safi);
+
 #endif /* _FRR_BGP_FLOWSPEC_H */
index 7bf11f12aa1747919f9bbee5bd0a2f91bd0946d8..b21e5ae0dcc4b2284c510c91dee3af34868d0d1c 100644 (file)
@@ -30,6 +30,7 @@
 #include "bgpd/bgp_flowspec_util.h"
 #include "bgpd/bgp_flowspec_private.h"
 #include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_pbr.h"
 
 /* Local Structures and variables declarations
  * This code block hosts the struct declared that host the flowspec rules
@@ -318,16 +319,32 @@ void route_vty_out_flowspec(struct vty *vty, struct prefix *p,
                XFREE(MTYPE_ECOMMUNITY_STR, s);
        }
        peer_uptime(binfo->uptime, timebuf, BGP_UPTIME_LEN, 0, NULL);
-       if (display == NLRI_STRING_FORMAT_LARGE)
-               vty_out(vty, "\tup for %8s\n", timebuf);
-       else if (json_paths) {
+       if (display == NLRI_STRING_FORMAT_LARGE) {
+               vty_out(vty, "\treceived for %8s\n", timebuf);
+       else if (json_paths) {
                json_time_path = json_object_new_object();
                json_object_string_add(json_time_path,
                                       "time", timebuf);
                if (display == NLRI_STRING_FORMAT_JSON)
                        json_object_array_add(json_paths, json_time_path);
        }
+       if (display == NLRI_STRING_FORMAT_LARGE) {
+               struct bgp_info_extra *extra = bgp_info_extra_get(binfo);
 
+               if (extra->bgp_fs_pbr) {
+                       struct bgp_pbr_match_entry *bpme;
+                       struct bgp_pbr_match *bpm;
+
+                       bpme = (struct bgp_pbr_match_entry *)extra->bgp_fs_pbr;
+                       bpm = bpme->backpointer;
+                       vty_out(vty, "\tinstalled in PBR");
+                       if (bpm)
+                               vty_out(vty, " (%s)\n", bpm->ipset_name);
+                       else
+                               vty_out(vty, "\n");
+               } else
+                       vty_out(vty, "\tnot installed in PBR\n");
+       }
 }
 
 int bgp_show_table_flowspec(struct vty *vty, struct bgp *bgp, afi_t afi,
@@ -408,10 +425,113 @@ DEFUN (no_debug_bgp_flowspec,
        return CMD_SUCCESS;
 }
 
+int bgp_fs_config_write_pbr(struct vty *vty, struct bgp *bgp,
+                           afi_t afi, safi_t safi)
+{
+       struct bgp_pbr_interface *pbr_if;
+       bool declare_node = false;
+       struct bgp_pbr_config *bgp_pbr_cfg = bgp->bgp_pbr_cfg;
+       struct bgp_pbr_interface_head *head;
+       bool bgp_pbr_interface_any;
+
+       if (!bgp_pbr_cfg || safi != SAFI_FLOWSPEC || afi != AFI_IP)
+               return 0;
+       head = &(bgp_pbr_cfg->ifaces_by_name_ipv4);
+       bgp_pbr_interface_any = bgp_pbr_cfg->pbr_interface_any_ipv4;
+       if (!RB_EMPTY(bgp_pbr_interface_head, head) ||
+            !bgp_pbr_interface_any)
+               declare_node = true;
+       RB_FOREACH (pbr_if, bgp_pbr_interface_head, head) {
+               vty_out(vty, "  local-install %s\n", pbr_if->name);
+       }
+       if (!bgp_pbr_interface_any)
+               vty_out(vty, "  no local-install any\n");
+       return declare_node ? 1 : 0;
+}
+
+static int bgp_fs_local_install_interface(struct bgp *bgp,
+                                         const char *no, const char *ifname)
+{
+       struct bgp_pbr_interface *pbr_if;
+       struct bgp_pbr_config *bgp_pbr_cfg = bgp->bgp_pbr_cfg;
+       struct bgp_pbr_interface_head *head;
+       bool *bgp_pbr_interface_any;
+
+       if (!bgp_pbr_cfg)
+               return CMD_SUCCESS;
+       head = &(bgp_pbr_cfg->ifaces_by_name_ipv4);
+       bgp_pbr_interface_any = &(bgp_pbr_cfg->pbr_interface_any_ipv4);
+       if (no) {
+               if (!ifname) {
+                       if (*bgp_pbr_interface_any) {
+                               *bgp_pbr_interface_any = false;
+                               /* remove all other interface list */
+                               bgp_pbr_reset(bgp, AFI_IP);
+                       }
+                       return CMD_SUCCESS;
+               }
+               pbr_if = bgp_pbr_interface_lookup(ifname, head);
+               if (!pbr_if)
+                       return CMD_SUCCESS;
+               RB_REMOVE(bgp_pbr_interface_head, head, pbr_if);
+               return CMD_SUCCESS;
+       }
+       if (ifname) {
+               pbr_if = bgp_pbr_interface_lookup(ifname, head);
+               if (pbr_if)
+                       return CMD_SUCCESS;
+               pbr_if = XCALLOC(MTYPE_TMP,
+                                sizeof(struct bgp_pbr_interface));
+               strlcpy(pbr_if->name, ifname, INTERFACE_NAMSIZ);
+               RB_INSERT(bgp_pbr_interface_head, head, pbr_if);
+               *bgp_pbr_interface_any = false;
+       } else {
+               /* set to default */
+               if (!*bgp_pbr_interface_any) {
+                       /* remove all other interface list
+                        */
+                       bgp_pbr_reset(bgp, AFI_IP);
+                       *bgp_pbr_interface_any = true;
+               }
+       }
+       return CMD_SUCCESS;
+}
+
+DEFUN (bgp_fs_local_install_ifname,
+       bgp_fs_local_install_ifname_cmd,
+       "[no] local-install INTERFACE",
+       NO_STR
+       "Apply local policy routing\n"
+       "Interface name\n")
+{
+       struct bgp *bgp = VTY_GET_CONTEXT(bgp);
+       int idx = 0;
+       const char *no = strmatch(argv[0]->text, (char *)"no") ? "no" : NULL;
+       char *ifname = argv_find(argv, argc, "INTERFACE", &idx) ?
+               argv[idx]->arg : NULL;
+
+       return bgp_fs_local_install_interface(bgp, no, ifname);
+}
+
+DEFUN (bgp_fs_local_install_any,
+       bgp_fs_local_install_any_cmd,
+       "[no] local-install any",
+       NO_STR
+       "Apply local policy routing\n"
+       "Any Interface\n")
+{
+       struct bgp *bgp = VTY_GET_CONTEXT(bgp);
+       const char *no = strmatch(argv[0]->text, (char *)"no") ? "no" : NULL;
+
+       return bgp_fs_local_install_interface(bgp, no, NULL);
+}
+
 void bgp_flowspec_vty_init(void)
 {
        install_element(ENABLE_NODE, &debug_bgp_flowspec_cmd);
        install_element(CONFIG_NODE, &debug_bgp_flowspec_cmd);
        install_element(ENABLE_NODE, &no_debug_bgp_flowspec_cmd);
        install_element(CONFIG_NODE, &no_debug_bgp_flowspec_cmd);
+       install_element(BGP_FLOWSPECV4_NODE, &bgp_fs_local_install_any_cmd);
+       install_element(BGP_FLOWSPECV4_NODE, &bgp_fs_local_install_ifname_cmd);
 }
index 04d6314fd7282681e88a1443b8b1e77b83b92d37..5e36f9175048eb6d1a332ea8370ad0fd77576c65 100644 (file)
 DEFINE_MTYPE_STATIC(BGPD, PBR_MATCH_ENTRY, "PBR match entry")
 DEFINE_MTYPE_STATIC(BGPD, PBR_MATCH, "PBR match")
 DEFINE_MTYPE_STATIC(BGPD, PBR_ACTION, "PBR action")
+DEFINE_MTYPE_STATIC(BGPD, PBR, "BGP PBR Context")
+
+RB_GENERATE(bgp_pbr_interface_head, bgp_pbr_interface,
+           id_entry, bgp_pbr_interface_compare);
+struct bgp_pbr_interface_head ifaces_by_name_ipv4 =
+       RB_INITIALIZER(&ifaces_by_name_ipv4);
 
 static int bgp_pbr_match_counter_unique;
 static int bgp_pbr_match_entry_counter_unique;
@@ -169,7 +175,60 @@ static int sprintf_bgp_pbr_match_val(char *str, struct bgp_pbr_match_val *mval,
                _cnt++; \
        } while (0)
 
-/* return 1 if OK, 0 if validation should stop) */
+struct bgp_pbr_range_port {
+       uint16_t min_port;
+       uint16_t max_port;
+};
+
+/* return true if extraction ok
+ */
+static bool bgp_pbr_extract(struct bgp_pbr_match_val list[],
+                           int num,
+                           struct bgp_pbr_range_port *range)
+{
+       int i = 0;
+       bool exact_match = false;
+
+       if (range)
+               memset(range, 0, sizeof(struct bgp_pbr_range_port));
+
+       if (num > 2)
+               return false;
+       for (i = 0; i < num; i++) {
+               if (i != 0 && (list[i].compare_operator ==
+                              OPERATOR_COMPARE_EQUAL_TO))
+                       return false;
+               if (i == 0 && (list[i].compare_operator ==
+                              OPERATOR_COMPARE_EQUAL_TO)) {
+                       if (range)
+                               range->min_port = list[i].value;
+                       exact_match = true;
+               }
+               if (exact_match == true && i > 0)
+                       return false;
+               if (list[i].compare_operator ==
+                   (OPERATOR_COMPARE_GREATER_THAN +
+                    OPERATOR_COMPARE_EQUAL_TO)) {
+                       if (range)
+                               range->min_port = list[i].value;
+               } else if (list[i].compare_operator ==
+                          (OPERATOR_COMPARE_LESS_THAN +
+                           OPERATOR_COMPARE_EQUAL_TO)) {
+                       if (range)
+                               range->max_port = list[i].value;
+               } else if (list[i].compare_operator ==
+                          OPERATOR_COMPARE_LESS_THAN) {
+                       if (range)
+                               range->max_port = list[i].value - 1;
+               } else if (list[i].compare_operator ==
+                          OPERATOR_COMPARE_GREATER_THAN) {
+                       if (range)
+                               range->min_port = list[i].value + 1;
+               }
+       }
+       return true;
+}
+
 static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main *api)
 {
        /* because bgp pbr entry may contain unsupported
@@ -179,18 +238,62 @@ static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main *api)
         * - combination src/dst => redirect nexthop [ + rate]
         * - combination src/dst => redirect VRF [ + rate]
         * - combination src/dst => drop
+        * - combination srcport + @IP
         */
-       if (api->match_src_port_num || api->match_dst_port_num
-           || api->match_port_num || api->match_protocol_num
-           || api->match_icmp_type_num || api->match_icmp_type_num
-           || api->match_packet_length_num || api->match_dscp_num
-           || api->match_tcpflags_num) {
+       if (api->match_icmp_type_num || api->match_packet_length_num
+           || api->match_dscp_num || api->match_tcpflags_num) {
                if (BGP_DEBUG(pbr, PBR)) {
                        bgp_pbr_print_policy_route(api);
                        zlog_debug("BGP: some SET actions not supported by Zebra. ignoring.");
+                       zlog_debug("BGP: case icmp or length or dscp or tcp flags");
                }
                return 0;
        }
+
+       if (api->match_protocol_num > 1) {
+               if (BGP_DEBUG(pbr, PBR))
+                       zlog_debug("BGP: match protocol operations:"
+                                "multiple protocols ( %d). ignoring.",
+                                api->match_protocol_num);
+               return 0;
+       }
+       if (api->match_protocol_num == 1 &&
+           api->protocol[0].value != PROTOCOL_UDP &&
+           api->protocol[0].value != PROTOCOL_TCP) {
+               if (BGP_DEBUG(pbr, PBR))
+                       zlog_debug("BGP: match protocol operations:"
+                                  "protocol (%d) not supported. ignoring",
+                                  api->match_protocol_num);
+               return 0;
+       }
+       if (!bgp_pbr_extract(api->src_port, api->match_src_port_num, NULL)) {
+               if (BGP_DEBUG(pbr, PBR))
+                       zlog_debug("BGP: match src port operations:"
+                                  "too complex. ignoring.");
+               return 0;
+       }
+       if (!bgp_pbr_extract(api->dst_port, api->match_dst_port_num, NULL)) {
+               if (BGP_DEBUG(pbr, PBR))
+                       zlog_debug("BGP: match dst port operations:"
+                                  "too complex. ignoring.");
+               return 0;
+       }
+       if (!bgp_pbr_extract(api->port, api->match_port_num, NULL)) {
+               if (BGP_DEBUG(pbr, PBR))
+                       zlog_debug("BGP: match port operations:"
+                                "too complex. ignoring.");
+               return 0;
+       }
+       /* no combinations with both src_port and dst_port
+        * or port with src_port and dst_port
+        */
+       if (api->match_src_port_num + api->match_dst_port_num +
+           api->match_port_num > 3) {
+               if (BGP_DEBUG(pbr, PBR))
+                       zlog_debug("BGP: match multiple port operations:"
+                                " too complex. ignoring.");
+               return 0;
+       }
        if (!(api->match_bitmask & PREFIX_SRC_PRESENT) &&
            !(api->match_bitmask & PREFIX_DST_PRESENT)) {
                if (BGP_DEBUG(pbr, PBR)) {
@@ -228,15 +331,15 @@ static int bgp_pbr_build_and_validate_entry(struct prefix *p,
                ecom = info->attr->ecommunity;
                for (i = 0; i < ecom->size; i++) {
                        ecom_eval = (struct ecommunity_val *)
-                               ecom->val + (i * ECOMMUNITY_SIZE);
-
+                               (ecom->val + (i * ECOMMUNITY_SIZE));
+                       action_count++;
                        if (action_count > ACTIONS_MAX_NUM) {
                                if (BGP_DEBUG(pbr, PBR_ERROR))
                                        zlog_err("%s: flowspec actions exceeds limit (max %u)",
                                                 __func__, action_count);
                                break;
                        }
-                       api_action = &api->actions[action_count];
+                       api_action = &api->actions[action_count - 1];
 
                        if ((ecom_eval->val[1] ==
                             (char)ECOMMUNITY_REDIRECT_VRF) &&
@@ -376,6 +479,7 @@ static void bgp_pbr_action_free(void *arg)
                                                   AFI_IP,
                                                   bpa->table_id,
                                                   false);
+                       bpa->installed = false;
                }
        }
        XFREE(MTYPE_PBR_ACTION, bpa);
@@ -447,6 +551,11 @@ uint32_t bgp_pbr_match_entry_hash_key(void *arg)
        pbme = (struct bgp_pbr_match_entry *)arg;
        key = prefix_hash_key(&pbme->src);
        key = jhash_1word(prefix_hash_key(&pbme->dst), key);
+       key = jhash(&pbme->dst_port_min, 2, key);
+       key = jhash(&pbme->src_port_min, 2, key);
+       key = jhash(&pbme->dst_port_max, 2, key);
+       key = jhash(&pbme->src_port_max, 2, key);
+       key = jhash(&pbme->proto, 1, key);
 
        return key;
 }
@@ -474,6 +583,21 @@ int bgp_pbr_match_entry_hash_equal(const void *arg1, const void *arg2)
        if (!prefix_same(&r1->dst, &r2->dst))
                return 0;
 
+       if (r1->src_port_min != r2->src_port_min)
+               return 0;
+
+       if (r1->dst_port_min != r2->dst_port_min)
+               return 0;
+
+       if (r1->src_port_max != r2->src_port_max)
+               return 0;
+
+       if (r1->dst_port_max != r2->dst_port_max)
+               return 0;
+
+       if (r1->proto != r2->proto)
+               return 0;
+
        return 1;
 }
 
@@ -497,10 +621,8 @@ int bgp_pbr_action_hash_equal(const void *arg1, const void *arg2)
 
        /* unique value is self calculated
         * table and fwmark is self calculated
+        * rate is ignored
         */
-       if (r1->rate != r2->rate)
-               return 0;
-
        if (r1->vrf_id != r2->vrf_id)
                return 0;
 
@@ -587,6 +709,11 @@ void bgp_pbr_cleanup(struct bgp *bgp)
                hash_free(bgp->pbr_action_hash);
                bgp->pbr_action_hash = NULL;
        }
+       if (bgp->bgp_pbr_cfg == NULL)
+               return;
+       bgp_pbr_reset(bgp, AFI_IP);
+       XFREE(MTYPE_PBR, bgp->bgp_pbr_cfg);
+       bgp->bgp_pbr_cfg = NULL;
 }
 
 void bgp_pbr_init(struct bgp *bgp)
@@ -599,6 +726,9 @@ void bgp_pbr_init(struct bgp *bgp)
                hash_create_size(8, bgp_pbr_action_hash_key,
                                 bgp_pbr_action_hash_equal,
                                 "Match Hash Entry");
+
+       bgp->bgp_pbr_cfg = XCALLOC(MTYPE_PBR, sizeof(struct bgp_pbr_config));
+       bgp->bgp_pbr_cfg->pbr_interface_any_ipv4 = true;
 }
 
 void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main *api)
@@ -749,6 +879,16 @@ static void bgp_pbr_flush_entry(struct bgp *bgp, struct bgp_pbr_action *bpa,
                bgp_send_pbr_ipset_entry_match(bpme, false);
                bpme->installed = false;
                bpme->backpointer = NULL;
+               if (bpme->bgp_info) {
+                       struct bgp_info *bgp_info;
+                       struct bgp_info_extra *extra;
+
+                       /* unlink bgp_info to bpme */
+                       bgp_info = (struct bgp_info *)bpme->bgp_info;
+                       extra = bgp_info_extra_get(bgp_info);
+                       extra->bgp_fs_pbr = NULL;
+                       bpme->bgp_info = NULL;
+               }
        }
        hash_release(bpm->entry_hash, bpme);
        if (hashcount(bpm->entry_hash) == 0) {
@@ -777,6 +917,7 @@ static void bgp_pbr_flush_entry(struct bgp *bgp, struct bgp_pbr_action *bpa,
                                                   AFI_IP,
                                                   bpa->table_id,
                                                   false);
+                       bpa->installed = false;
                }
        }
 }
@@ -813,10 +954,13 @@ static int bgp_pbr_get_remaining_entry(struct hash_backet *backet, void *arg)
 }
 
 static void bgp_pbr_policyroute_remove_from_zebra(struct bgp *bgp,
-                                                 struct bgp_info *binfo,
-                                                 vrf_id_t vrf_id,
-                                                 struct prefix *src,
-                                                 struct prefix *dst)
+                                         struct bgp_info *binfo,
+                                         vrf_id_t vrf_id,
+                                         struct prefix *src,
+                                         struct prefix *dst,
+                                         uint8_t protocol,
+                                         struct bgp_pbr_range_port *src_port,
+                                         struct bgp_pbr_range_port *dst_port)
 {
        struct bgp_pbr_match temp;
        struct bgp_pbr_match_entry temp2;
@@ -840,11 +984,35 @@ static void bgp_pbr_policyroute_remove_from_zebra(struct bgp *bgp,
                prefix_copy(&temp2.dst, dst);
        } else
                temp2.dst.family = AF_INET;
-
-       if (src == NULL || dst == NULL)
-               temp.type = IPSET_NET;
-       else
-               temp.type = IPSET_NET_NET;
+       if (src_port) {
+               temp.flags |= MATCH_PORT_SRC_SET;
+               temp2.src_port_min = src_port->min_port;
+               if (src_port->max_port) {
+                       temp.flags |= MATCH_PORT_SRC_RANGE_SET;
+                       temp2.src_port_max = src_port->max_port;
+               }
+       }
+       if (dst_port) {
+               temp.flags |= MATCH_PORT_DST_SET;
+               temp2.dst_port_min = dst_port->min_port;
+               if (dst_port->max_port) {
+                       temp.flags |= MATCH_PORT_DST_RANGE_SET;
+                       temp2.dst_port_max = dst_port->max_port;
+               }
+       }
+       temp2.proto = protocol;
+
+       if (src == NULL || dst == NULL) {
+               if (temp.flags & (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET))
+                       temp.type = IPSET_NET_PORT;
+               else
+                       temp.type = IPSET_NET;
+       } else {
+               if (temp.flags & (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET))
+                       temp.type = IPSET_NET_PORT_NET;
+               else
+                       temp.type = IPSET_NET_NET;
+       }
        if (vrf_id == VRF_UNKNOWN) /* XXX case BGP destroy */
                temp.vrf_id = 0;
        else
@@ -870,12 +1038,15 @@ static void bgp_pbr_policyroute_remove_from_zebra(struct bgp *bgp,
 }
 
 static void bgp_pbr_policyroute_add_to_zebra(struct bgp *bgp,
-                                            struct bgp_info *binfo,
-                                            vrf_id_t vrf_id,
-                                            struct prefix *src,
-                                            struct prefix *dst,
-                                            struct nexthop *nh,
-                                            float *rate)
+                                    struct bgp_info *binfo,
+                                    vrf_id_t vrf_id,
+                                    struct prefix *src,
+                                    struct prefix *dst,
+                                    struct nexthop *nh,
+                                    float *rate,
+                                    uint8_t protocol,
+                                    struct bgp_pbr_range_port *src_port,
+                                    struct bgp_pbr_range_port *dst_port)
 {
        struct bgp_pbr_match temp;
        struct bgp_pbr_match_entry temp2;
@@ -913,15 +1084,33 @@ static void bgp_pbr_policyroute_add_to_zebra(struct bgp *bgp,
 
        /* then look for bpm */
        memset(&temp, 0, sizeof(temp));
-       if (src == NULL || dst == NULL)
-               temp.type = IPSET_NET;
-       else
-               temp.type = IPSET_NET_NET;
+       if (src == NULL || dst == NULL) {
+               if ((src_port && src_port->min_port) ||
+                   (dst_port && dst_port->min_port))
+                       temp.type = IPSET_NET_PORT;
+               else
+                       temp.type = IPSET_NET;
+       } else {
+               if ((src_port && src_port->min_port) ||
+                   (dst_port && dst_port->min_port))
+                       temp.type = IPSET_NET_PORT_NET;
+               else
+                       temp.type = IPSET_NET_NET;
+       }
        temp.vrf_id = vrf_id;
        if (src)
                temp.flags |= MATCH_IP_SRC_SET;
        if (dst)
                temp.flags |= MATCH_IP_DST_SET;
+
+       if (src_port && src_port->min_port)
+               temp.flags |= MATCH_PORT_SRC_SET;
+       if (dst_port && dst_port->min_port)
+               temp.flags |= MATCH_PORT_DST_SET;
+       if (src_port && src_port->max_port)
+               temp.flags |= MATCH_PORT_SRC_RANGE_SET;
+       if (dst_port && dst_port->max_port)
+               temp.flags |= MATCH_PORT_DST_RANGE_SET;
        temp.action = bpa;
        bpm = hash_get(bgp->pbr_match_hash, &temp,
                       bgp_pbr_match_alloc_intern);
@@ -953,15 +1142,22 @@ static void bgp_pbr_policyroute_add_to_zebra(struct bgp *bgp,
                prefix_copy(&temp2.dst, dst);
        else
                temp2.dst.family = AF_INET;
+       temp2.src_port_min = src_port ? src_port->min_port : 0;
+       temp2.dst_port_min = dst_port ? dst_port->min_port : 0;
+       temp2.src_port_max = src_port ? src_port->max_port : 0;
+       temp2.dst_port_max = dst_port ? dst_port->max_port : 0;
+       temp2.proto = protocol;
        if (bpm)
                bpme = hash_get(bpm->entry_hash, &temp2,
-                       bgp_pbr_match_entry_alloc_intern);
+                               bgp_pbr_match_entry_alloc_intern);
        if (bpme && bpme->unique == 0) {
                bpme->unique = ++bgp_pbr_match_entry_counter_unique;
                /* 0 value is forbidden */
                bpme->backpointer = bpm;
                bpme->installed = false;
                bpme->install_in_progress = false;
+               /* link bgp info to bpme */
+               bpme->bgp_info = (void *)binfo;
        }
 
        /* BGP FS: append entry to zebra
@@ -1021,17 +1217,44 @@ static void bgp_pbr_handle_entry(struct bgp *bgp,
        int continue_loop = 1;
        float rate = 0;
        struct prefix *src = NULL, *dst = NULL;
+       uint8_t proto = 0;
+       struct bgp_pbr_range_port *srcp = NULL, *dstp = NULL;
+       struct bgp_pbr_range_port range;
 
+       memset(&nh, 0, sizeof(struct nexthop));
        if (api->match_bitmask & PREFIX_SRC_PRESENT)
                src = &api->src_prefix;
        if (api->match_bitmask & PREFIX_DST_PRESENT)
                dst = &api->dst_prefix;
        memset(&nh, 0, sizeof(struct nexthop));
        nh.vrf_id = VRF_UNKNOWN;
-
+       if (api->match_protocol_num)
+               proto = (uint8_t)api->protocol[0].value;
+       /* if match_port is selected, then either src or dst port will be parsed
+        * but not both at the same time
+        */
+       if (api->match_port_num >= 1) {
+               bgp_pbr_extract(api->port,
+                               api->match_port_num,
+                               &range);
+               srcp = dstp = &range;
+       } else if (api->match_src_port_num >= 1) {
+               bgp_pbr_extract(api->src_port,
+                               api->match_src_port_num,
+                               &range);
+               srcp = &range;
+               dstp = NULL;
+       } else if (api->match_dst_port_num >= 1) {
+               bgp_pbr_extract(api->dst_port,
+                               api->match_dst_port_num,
+                               &range);
+               dstp = &range;
+               srcp = NULL;
+       }
        if (!add)
                return bgp_pbr_policyroute_remove_from_zebra(bgp, binfo,
-                                            api->vrf_id, src, dst);
+                                            api->vrf_id, src, dst,
+                                            proto, srcp, dstp);
        /* no action for add = true */
        for (i = 0; i < api->action_num; i++) {
                switch (api->actions[i].action) {
@@ -1042,7 +1265,8 @@ static void bgp_pbr_handle_entry(struct bgp *bgp,
                                nh.type = NEXTHOP_TYPE_BLACKHOLE;
                                bgp_pbr_policyroute_add_to_zebra(bgp, binfo,
                                                    api->vrf_id, src, dst,
-                                                   &nh, &rate);
+                                                   &nh, &rate, proto,
+                                                   srcp, dstp);
                        } else {
                                /* update rate. can be reentrant */
                                rate = api->actions[i].u.r.rate;
@@ -1085,7 +1309,8 @@ static void bgp_pbr_handle_entry(struct bgp *bgp,
                        bgp_pbr_policyroute_add_to_zebra(bgp, binfo,
                                                            api->vrf_id,
                                                            src, dst,
-                                                           &nh, &rate);
+                                                           &nh, &rate, proto,
+                                                           srcp, dstp);
                        /* XXX combination with REDIRECT_VRF
                         * + REDIRECT_NH_IP not done
                         */
@@ -1097,7 +1322,8 @@ static void bgp_pbr_handle_entry(struct bgp *bgp,
                        bgp_pbr_policyroute_add_to_zebra(bgp, binfo,
                                                         api->vrf_id,
                                                         src, dst,
-                                                        &nh, &rate);
+                                                        &nh, &rate, proto,
+                                                        srcp, dstp);
                        continue_loop = 0;
                        break;
                case ACTION_MARKING:
@@ -1120,6 +1346,7 @@ void bgp_pbr_update_entry(struct bgp *bgp, struct prefix *p,
                         bool nlri_update)
 {
        struct bgp_pbr_entry_main api;
+       struct bgp_info_extra *extra = bgp_info_extra_get(info);
 
        if (afi == AFI_IP6)
                return; /* IPv6 not supported */
@@ -1130,11 +1357,61 @@ void bgp_pbr_update_entry(struct bgp *bgp, struct prefix *p,
        api.vrf_id = bgp->vrf_id;
        api.afi = afi;
 
-       if (bgp_pbr_build_and_validate_entry(p, info, &api) < 0) {
+       if (!bgp_zebra_tm_chunk_obtained()) {
                if (BGP_DEBUG(pbr, PBR_ERROR))
-                       zlog_err("%s: cancel updating entry in bgp pbr",
+                       zlog_err("%s: table chunk not obtained yet",
                                 __func__);
                return;
        }
+       /* already installed */
+       if (nlri_update && extra->bgp_fs_pbr) {
+               if (BGP_DEBUG(pbr, PBR_ERROR))
+                       zlog_err("%s: entry %p already installed in bgp pbr",
+                                __func__, info);
+               return;
+       }
+
+       if (bgp_pbr_build_and_validate_entry(p, info, &api) < 0) {
+               if (BGP_DEBUG(pbr, PBR_ERROR))
+                       zlog_err("%s: cancel updating entry %p in bgp pbr",
+                                __func__, info);
+               return;
+       }
        bgp_pbr_handle_entry(bgp, info, &api, nlri_update);
 }
+
+int bgp_pbr_interface_compare(const struct bgp_pbr_interface *a,
+                         const struct bgp_pbr_interface *b)
+{
+       return strcmp(a->name, b->name);
+}
+
+struct bgp_pbr_interface *bgp_pbr_interface_lookup(const char *name,
+                                          struct bgp_pbr_interface_head *head)
+{
+       struct bgp_pbr_interface pbr_if;
+
+       strlcpy(pbr_if.name, name, sizeof(pbr_if.name));
+       return (RB_FIND(bgp_pbr_interface_head,
+                       head, &pbr_if));
+}
+
+/* this function resets to the default policy routing
+ * go back to default status
+ */
+void bgp_pbr_reset(struct bgp *bgp, afi_t afi)
+{
+       struct bgp_pbr_config *bgp_pbr_cfg = bgp->bgp_pbr_cfg;
+       struct bgp_pbr_interface_head *head;
+       struct bgp_pbr_interface *pbr_if;
+
+       if (!bgp_pbr_cfg || afi != AFI_IP)
+               return;
+       head = &(bgp_pbr_cfg->ifaces_by_name_ipv4);
+
+       while (!RB_EMPTY(bgp_pbr_interface_head, head)) {
+               pbr_if = RB_ROOT(bgp_pbr_interface_head, head);
+               RB_REMOVE(bgp_pbr_interface_head, head, pbr_if);
+               XFREE(MTYPE_TMP, pbr_if);
+       }
+}
index 5129ada37b57d8a6b4ae4dfa3b55146efb6e355a..20edaf30b8a567fa5bf70a6f73e73375ef6cb276 100644 (file)
@@ -123,6 +123,8 @@ struct bgp_pbr_entry_main {
        struct prefix src_prefix;
        struct prefix dst_prefix;
 
+#define PROTOCOL_UDP 17
+#define PROTOCOL_TCP 6
        struct bgp_pbr_match_val protocol[BGP_PBR_MATCH_VAL_MAX];
        struct bgp_pbr_match_val src_port[BGP_PBR_MATCH_VAL_MAX];
        struct bgp_pbr_match_val dst_port[BGP_PBR_MATCH_VAL_MAX];
@@ -148,6 +150,25 @@ struct bgp_pbr_entry_main {
        vrf_id_t vrf_id;
 };
 
+struct bgp_pbr_interface {
+       RB_ENTRY(bgp_pbr_interface) id_entry;
+       char name[INTERFACE_NAMSIZ];
+};
+
+RB_HEAD(bgp_pbr_interface_head, bgp_pbr_interface);
+RB_PROTOTYPE(bgp_pbr_interface_head, bgp_pbr_interface, id_entry,
+            bgp_pbr_interface_compare);
+
+extern int bgp_pbr_interface_compare(const struct bgp_pbr_interface *a,
+                                    const struct bgp_pbr_interface *b);
+
+struct bgp_pbr_config {
+       struct bgp_pbr_interface_head ifaces_by_name_ipv4;
+       bool pbr_interface_any_ipv4;
+};
+
+extern struct bgp_pbr_config *bgp_pbr_cfg;
+
 struct bgp_pbr_match {
        char ipset_name[ZEBRA_IPSET_NAME_SIZE];
 
@@ -157,6 +178,10 @@ struct bgp_pbr_match {
 
 #define MATCH_IP_SRC_SET               (1 << 0)
 #define MATCH_IP_DST_SET               (1 << 1)
+#define MATCH_PORT_SRC_SET             (1 << 2)
+#define MATCH_PORT_DST_SET             (1 << 3)
+#define MATCH_PORT_SRC_RANGE_SET       (1 << 4)
+#define MATCH_PORT_DST_RANGE_SET       (1 << 5)
        uint32_t flags;
 
        vrf_id_t vrf_id;
@@ -189,6 +214,14 @@ struct bgp_pbr_match_entry {
        struct prefix src;
        struct prefix dst;
 
+       uint16_t src_port_min;
+       uint16_t src_port_max;
+       uint16_t dst_port_min;
+       uint16_t dst_port_max;
+       uint8_t proto;
+
+       void *bgp_info;
+
        bool installed;
        bool install_in_progress;
 };
@@ -253,4 +286,10 @@ extern void bgp_pbr_update_entry(struct bgp *bgp, struct prefix *p,
                                afi_t afi, safi_t safi,
                                bool nlri_update);
 
+/* bgp pbr utilities */
+extern struct bgp_pbr_interface *pbr_interface_lookup(const char *name);
+extern void bgp_pbr_reset(struct bgp *bgp, afi_t afi);
+extern struct bgp_pbr_interface *bgp_pbr_interface_lookup(const char *name,
+                                  struct bgp_pbr_interface_head *head);
+
 #endif /* __BGP_PBR_H__ */
index 3f7ea160452dc731d1b46e70324983755f28a221..356a949d691c0a79b3e08907536e1072cef917d3 100644 (file)
@@ -210,5 +210,5 @@ void form_auto_rd(struct in_addr router_id,
        prd->family = AF_UNSPEC;
        prd->prefixlen = 64;
        sprintf(buf, "%s:%hu", inet_ntoa(router_id), rd_id);
-       str2prefix_rd(buf, prd);
+       (void)str2prefix_rd(buf, prd);
 }
index 132fa5fc9d391e36ab53883987aa199eefe59e6e..390bdaeca3027d56c9689bcd5fa1c76bdc7c350d 100644 (file)
@@ -2551,7 +2551,9 @@ static int bgp_maximum_prefix_restart_timer(struct thread *thread)
                        "%s Maximum-prefix restart timer expired, restore peering",
                        peer->host);
 
-       peer_clear(peer, NULL);
+       if ((peer_clear(peer, NULL) < 0) && bgp_debug_neighbor_events(peer))
+               zlog_debug("%s: %s peer_clear failed",
+                          __PRETTY_FUNCTION__, peer->host);
 
        return 0;
 }
index 288b66fb85fa336aadfe6c3798dfef7eaaf1be1c..72923901b837cca1a3ea4f73a9d6b6871c0f9625 100644 (file)
@@ -146,6 +146,8 @@ struct bgp_info_extra {
         * Set nexthop_orig.family to 0 if not valid.
         */
        struct prefix nexthop_orig;
+       /* presence of FS pbr entry */
+       void *bgp_fs_pbr;
 };
 
 struct bgp_info {
index 390eb44eb8086423a8fa608aefc4e3f278a5330f..1cd51cb6f4aa96f793ed14cb07986767ce34ef13 100644 (file)
@@ -1001,6 +1001,7 @@ static bool bgp_tm_status_connected;
 static bool bgp_tm_chunk_obtained;
 #define BGP_FLOWSPEC_TABLE_CHUNK 100000
 static uint32_t bgp_tm_min, bgp_tm_max, bgp_tm_chunk_size;
+struct bgp *bgp_tm_bgp;
 
 static int bgp_zebra_tm_connect(struct thread *t)
 {
@@ -1024,8 +1025,11 @@ static int bgp_zebra_tm_connect(struct thread *t)
                if (!bgp_tm_chunk_obtained) {
                        if (bgp_zebra_get_table_range(bgp_tm_chunk_size,
                                                      &bgp_tm_min,
-                                                     &bgp_tm_max) >= 0)
+                                                     &bgp_tm_max) >= 0) {
                                bgp_tm_chunk_obtained = true;
+                               /* parse non installed entries */
+                               bgp_zebra_announce_table(bgp_tm_bgp, AFI_IP, SAFI_FLOWSPEC);
+                       }
                }
        }
        thread_add_timer(bm->master, bgp_zebra_tm_connect, zclient, delay,
@@ -1033,6 +1037,11 @@ static int bgp_zebra_tm_connect(struct thread *t)
        return 0;
 }
 
+bool bgp_zebra_tm_chunk_obtained(void)
+{
+       return bgp_tm_chunk_obtained;
+}
+
 uint32_t bgp_zebra_tm_get_id(void)
 {
        static int table_id;
@@ -1042,7 +1051,7 @@ uint32_t bgp_zebra_tm_get_id(void)
        return bgp_tm_min++;
 }
 
-void bgp_zebra_init_tm_connect(void)
+void bgp_zebra_init_tm_connect(struct bgp *bgp)
 {
        int delay = 1;
 
@@ -1054,6 +1063,7 @@ void bgp_zebra_init_tm_connect(void)
        bgp_tm_chunk_obtained = false;
        bgp_tm_min = bgp_tm_max = 0;
        bgp_tm_chunk_size = BGP_FLOWSPEC_TABLE_CHUNK;
+       bgp_tm_bgp = bgp;
        thread_add_timer(bm->master, bgp_zebra_tm_connect, zclient, delay,
                         &bgp_tm_thread_connect);
 }
@@ -1225,13 +1235,6 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
 
        tag = info->attr->tag;
 
-       /*
-        * When we create an aggregate route we must also install a
-        * Null0 route in the RIB
-        */
-       if (info->sub_type == BGP_ROUTE_AGGREGATE)
-               zapi_route_set_blackhole(&api, BLACKHOLE_NULL);
-
        /* If the route's source is EVPN, flag as such. */
        is_evpn = is_route_parent_evpn(info);
        if (is_evpn)
@@ -1313,7 +1316,7 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
                                        &mpinfo_cp->attr->nexthop,
                                        mpinfo_cp->attr, is_evpn, api_nh);
                } else {
-                       ifindex_t ifindex;
+                       ifindex_t ifindex = IFINDEX_INTERNAL;
                        struct in6_addr *nexthop;
 
                        if (bgp->table_map[afi][safi].name) {
@@ -1371,7 +1374,14 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
        if (has_valid_label && !(CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)))
                SET_FLAG(api.message, ZAPI_MESSAGE_LABEL);
 
-       if (info->sub_type != BGP_ROUTE_AGGREGATE)
+       /*
+        * When we create an aggregate route we must also
+        * install a Null0 route in the RIB, so overwrite
+        * what was written into api with a blackhole route
+        */
+       if (info->sub_type == BGP_ROUTE_AGGREGATE)
+               zapi_route_set_blackhole(&api, BLACKHOLE_NULL);
+       else
                api.nexthop_num = valid_nh_count;
 
        SET_FLAG(api.message, ZAPI_MESSAGE_METRIC);
@@ -1962,6 +1972,7 @@ static int rule_notify_owner(int command, struct zclient *zclient,
                        zlog_debug("%s: Received RULE_INSTALLED",
                                   __PRETTY_FUNCTION__);
                break;
+       case ZAPI_RULE_FAIL_REMOVE:
        case ZAPI_RULE_REMOVED:
                if (BGP_DEBUG(zebra, ZEBRA))
                        zlog_debug("%s: Received RULE REMOVED",
@@ -1987,8 +1998,8 @@ static int ipset_notify_owner(int command, struct zclient *zclient,
        bgp_pbim = bgp_pbr_match_ipset_lookup(vrf_id, unique);
        if (!bgp_pbim) {
                if (BGP_DEBUG(zebra, ZEBRA))
-                       zlog_debug("%s: Fail to look BGP match (%u)",
-                                  __PRETTY_FUNCTION__, unique);
+                       zlog_debug("%s: Fail to look BGP match ( %u %u)",
+                                  __PRETTY_FUNCTION__, note, unique);
                return 0;
        }
 
@@ -2007,6 +2018,7 @@ static int ipset_notify_owner(int command, struct zclient *zclient,
                        zlog_debug("%s: Received IPSET_INSTALLED",
                                   __PRETTY_FUNCTION__);
                break;
+       case ZAPI_IPSET_FAIL_REMOVE:
        case ZAPI_IPSET_REMOVED:
                if (BGP_DEBUG(zebra, ZEBRA))
                        zlog_debug("%s: Received IPSET REMOVED",
@@ -2036,8 +2048,8 @@ static int ipset_entry_notify_owner(int command, struct zclient *zclient,
                                                     unique);
        if (!bgp_pbime) {
                if (BGP_DEBUG(zebra, ZEBRA))
-                       zlog_debug("%s: Fail to look BGP match entry (%u)",
-                                  __PRETTY_FUNCTION__, unique);
+                       zlog_debug("%s: Fail to look BGP match entry (%u %u)",
+                                  __PRETTY_FUNCTION__, note, unique);
                return 0;
        }
 
@@ -2050,12 +2062,22 @@ static int ipset_entry_notify_owner(int command, struct zclient *zclient,
                bgp_pbime->install_in_progress = false;
                break;
        case ZAPI_IPSET_ENTRY_INSTALLED:
-               bgp_pbime->installed = true;
-               bgp_pbime->install_in_progress = false;
-               if (BGP_DEBUG(zebra, ZEBRA))
-                       zlog_debug("%s: Received IPSET_ENTRY_INSTALLED",
-                                  __PRETTY_FUNCTION__);
+               {
+                       struct bgp_info *bgp_info;
+                       struct bgp_info_extra *extra;
+
+                       bgp_pbime->installed = true;
+                       bgp_pbime->install_in_progress = false;
+                       if (BGP_DEBUG(zebra, ZEBRA))
+                               zlog_debug("%s: Received IPSET_ENTRY_INSTALLED",
+                                          __PRETTY_FUNCTION__);
+                       /* link bgp_info to bpme */
+                       bgp_info = (struct bgp_info *)bgp_pbime->bgp_info;
+                       extra = bgp_info_extra_get(bgp_info);
+                       extra->bgp_fs_pbr = (void *)bgp_pbime;
+               }
                break;
+       case ZAPI_IPSET_ENTRY_FAIL_REMOVE:
        case ZAPI_IPSET_ENTRY_REMOVED:
                if (BGP_DEBUG(zebra, ZEBRA))
                        zlog_debug("%s: Received IPSET_ENTRY_REMOVED",
@@ -2080,8 +2102,8 @@ static int iptable_notify_owner(int command, struct zclient *zclient,
        bgpm = bgp_pbr_match_iptable_lookup(vrf_id, unique);
        if (!bgpm) {
                if (BGP_DEBUG(zebra, ZEBRA))
-                       zlog_debug("%s: Fail to look BGP iptable (%u)",
-                                  __PRETTY_FUNCTION__, unique);
+                       zlog_debug("%s: Fail to look BGP iptable (%u %u)",
+                                  __PRETTY_FUNCTION__, note, unique);
                return 0;
        }
        switch (note) {
@@ -2100,6 +2122,7 @@ static int iptable_notify_owner(int command, struct zclient *zclient,
                                   __PRETTY_FUNCTION__);
                bgpm->action->refcnt++;
                break;
+       case ZAPI_IPTABLE_FAIL_REMOVE:
        case ZAPI_IPTABLE_REMOVED:
                if (BGP_DEBUG(zebra, ZEBRA))
                        zlog_debug("%s: Received IPTABLE REMOVED",
@@ -2167,6 +2190,12 @@ static void bgp_encode_pbr_ipset_entry_match(struct stream *s,
        stream_putc(s, pbime->dst.family);
        stream_putc(s, pbime->dst.prefixlen);
        stream_put(s, &pbime->dst.u.prefix, prefix_blen(&pbime->dst));
+
+       stream_putw(s, pbime->src_port_min);
+       stream_putw(s, pbime->src_port_max);
+       stream_putw(s, pbime->dst_port_min);
+       stream_putw(s, pbime->dst_port_max);
+       stream_putc(s, pbime->proto);
 }
 
 static void bgp_encode_pbr_iptable_match(struct stream *s,
@@ -2490,8 +2519,10 @@ void bgp_send_pbr_rule_action(struct bgp_pbr_action *pbra, bool install)
 
        if (pbra->install_in_progress)
                return;
-       zlog_debug("%s: table %d fwmark %d %d", __PRETTY_FUNCTION__,
-                  pbra->table_id, pbra->fwmark, install);
+       if (BGP_DEBUG(zebra, ZEBRA))
+               zlog_debug("%s: table %d fwmark %d %d",
+                          __PRETTY_FUNCTION__,
+                          pbra->table_id, pbra->fwmark, install);
        s = zclient->obuf;
        stream_reset(s);
 
@@ -2513,8 +2544,10 @@ void bgp_send_pbr_ipset_match(struct bgp_pbr_match *pbrim, bool install)
 
        if (pbrim->install_in_progress)
                return;
-       zlog_debug("%s: name %s type %d %d", __PRETTY_FUNCTION__,
-                  pbrim->ipset_name, pbrim->type, install);
+       if (BGP_DEBUG(zebra, ZEBRA))
+               zlog_debug("%s: name %s type %d %d",
+                          __PRETTY_FUNCTION__,
+                          pbrim->ipset_name, pbrim->type, install);
        s = zclient->obuf;
        stream_reset(s);
 
@@ -2539,9 +2572,10 @@ void bgp_send_pbr_ipset_entry_match(struct bgp_pbr_match_entry *pbrime,
 
        if (pbrime->install_in_progress)
                return;
-       zlog_debug("%s: name %s %d %d", __PRETTY_FUNCTION__,
-                  pbrime->backpointer->ipset_name,
-                  pbrime->unique, install);
+       if (BGP_DEBUG(zebra, ZEBRA))
+               zlog_debug("%s: name %s %d %d", __PRETTY_FUNCTION__,
+                          pbrime->backpointer->ipset_name,
+                          pbrime->unique, install);
        s = zclient->obuf;
        stream_reset(s);
 
@@ -2559,16 +2593,56 @@ void bgp_send_pbr_ipset_entry_match(struct bgp_pbr_match_entry *pbrime,
                pbrime->install_in_progress = true;
 }
 
+static void bgp_encode_pbr_interface_list(struct bgp *bgp, struct stream *s)
+{
+       struct bgp_pbr_config *bgp_pbr_cfg = bgp->bgp_pbr_cfg;
+       struct bgp_pbr_interface_head *head;
+       struct bgp_pbr_interface *pbr_if;
+       struct interface *ifp;
+
+       if (!bgp_pbr_cfg)
+               return;
+       head = &(bgp_pbr_cfg->ifaces_by_name_ipv4);
+
+       RB_FOREACH (pbr_if, bgp_pbr_interface_head, head) {
+               ifp = if_lookup_by_name(pbr_if->name, bgp->vrf_id);
+               if (ifp)
+                       stream_putl(s, ifp->ifindex);
+       }
+}
+
+static int bgp_pbr_get_ifnumber(struct bgp *bgp)
+{
+       struct bgp_pbr_config *bgp_pbr_cfg = bgp->bgp_pbr_cfg;
+       struct bgp_pbr_interface_head *head;
+       struct bgp_pbr_interface *pbr_if;
+       int cnt = 0;
+
+       if (!bgp_pbr_cfg)
+               return 0;
+       head = &(bgp_pbr_cfg->ifaces_by_name_ipv4);
+
+       RB_FOREACH (pbr_if, bgp_pbr_interface_head, head) {
+               if (if_lookup_by_name(pbr_if->name, bgp->vrf_id))
+                       cnt++;
+       }
+       return cnt;
+}
+
 void bgp_send_pbr_iptable(struct bgp_pbr_action *pba,
                          struct bgp_pbr_match *pbm,
                          bool install)
 {
        struct stream *s;
+       int ret = 0;
+       int nb_interface;
 
        if (pbm->install_iptable_in_progress)
                return;
-       zlog_debug("%s: name %s type %d mark %d %d", __PRETTY_FUNCTION__,
-                  pbm->ipset_name, pbm->type, pba->fwmark, install);
+       if (BGP_DEBUG(zebra, ZEBRA))
+               zlog_debug("%s: name %s type %d mark %d %d",
+                          __PRETTY_FUNCTION__, pbm->ipset_name,
+                          pbm->type, pba->fwmark, install);
        s = zclient->obuf;
        stream_reset(s);
 
@@ -2578,11 +2652,17 @@ void bgp_send_pbr_iptable(struct bgp_pbr_action *pba,
                              VRF_DEFAULT);
 
        bgp_encode_pbr_iptable_match(s, pba, pbm);
-
+       nb_interface = bgp_pbr_get_ifnumber(pba->bgp);
+       stream_putl(s, nb_interface);
+       if (nb_interface)
+               bgp_encode_pbr_interface_list(pba->bgp, s);
        stream_putw_at(s, 0, stream_get_endp(s));
-       if (!zclient_send_message(zclient) && install) {
-               pbm->install_iptable_in_progress = true;
-               pba->refcnt++;
+       ret = zclient_send_message(zclient);
+       if (install) {
+               if (ret)
+                       pba->refcnt++;
+               else
+                       pbm->install_iptable_in_progress = true;
        }
 }
 
@@ -2626,7 +2706,8 @@ void bgp_zebra_announce_default(struct bgp *bgp, struct nexthop *nh,
 
                inet_ntop(AF_INET, &(nh->gate.ipv4), buff, INET_ADDRSTRLEN);
                if (BGP_DEBUG(zebra, ZEBRA))
-                       zlog_info("BGP: sending default route to %s table %d (redirect IP)",
+                       zlog_info("BGP: %s default route to %s table %d (redirect IP)",
+                                 announce ? "adding" : "withdrawing",
                                  buff, table_id);
                zclient_route_send(announce ? ZEBRA_ROUTE_ADD
                                   : ZEBRA_ROUTE_DELETE,
@@ -2648,7 +2729,8 @@ void bgp_zebra_announce_default(struct bgp *bgp, struct nexthop *nh,
                api_nh->type = NEXTHOP_TYPE_IFINDEX;
                api_nh->ifindex = ifp->ifindex;
                if (BGP_DEBUG(zebra, ZEBRA))
-                       zlog_info("BGP: sending default route to %s table %d (redirect VRF)",
+                       zlog_info("BGP: %s default route to %s table %d (redirect VRF)",
+                                 announce ? "adding" : "withdrawing",
                                  vrf->name, table_id);
                zclient_route_send(announce ? ZEBRA_ROUTE_ADD
                                   : ZEBRA_ROUTE_DELETE,
index 7ac40fecff6c431bca9be10b48383690f2889a43..e3c88b9db664712e4eab521a4faef8da42214cef 100644 (file)
@@ -24,8 +24,9 @@
 #include "vxlan.h"
 
 extern void bgp_zebra_init(struct thread_master *master);
-extern void bgp_zebra_init_tm_connect(void);
+extern void bgp_zebra_init_tm_connect(struct bgp *bgp);
 extern uint32_t bgp_zebra_tm_get_id(void);
+extern bool bgp_zebra_tm_chunk_obtained(void);
 extern void bgp_zebra_destroy(void);
 extern int bgp_zebra_get_table_range(uint32_t chunk_size,
                                     uint32_t *start, uint32_t *end);
index 71707b6afa8ebae15eddf9651686d73451e496d5..69297cd3e4598be05227a72a9ca553db418a7dd0 100644 (file)
@@ -1988,7 +1988,7 @@ int peer_activate(struct peer *peer, afi_t afi, safi_t safi)
 
        if (safi == SAFI_FLOWSPEC) {
                /* connect to table manager */
-               bgp_zebra_init_tm_connect();
+               bgp_zebra_init_tm_connect(bgp);
        }
        return ret;
 }
@@ -7266,6 +7266,9 @@ static void bgp_config_write_family(struct vty *vty, struct bgp *bgp, afi_t afi,
        if (safi == SAFI_EVPN)
                bgp_config_write_evpn_info(vty, bgp, afi, safi);
 
+       if (safi == SAFI_FLOWSPEC)
+               bgp_fs_config_write_pbr(vty, bgp, afi, safi);
+
        if (safi == SAFI_UNICAST) {
                bgp_vpn_policy_config_write_afi(vty, bgp, afi);
                if (CHECK_FLAG(bgp->af_flags[afi][safi],
index 340851e8d90ce1c3544ed556ecd23860eb47d9df..f663df162f7b37667c63f5f84dbfce6212b19d2b 100644 (file)
@@ -47,6 +47,7 @@
 
 struct update_subgroup;
 struct bpacket;
+struct bgp_pbr_config;
 
 /*
  * Allow the neighbor XXXX remote-as to take internal or external
@@ -531,6 +532,8 @@ struct bgp {
 
        struct vpn_policy vpn_policy[AFI_MAX];
 
+       struct bgp_pbr_config *bgp_pbr_cfg;
+
        QOBJ_FIELDS
 };
 DECLARE_QOBJ_TYPE(bgp)
index 090628044c228d7562712af8d5bda686bab6d0e9..e27da63b536f951221e0ff7dd777c2b550140efe 100644 (file)
@@ -1,13 +1,13 @@
 .. _sharp:
 
-***
+*****
 SHARP
-***
+*****
+
+:abbr:`SHARP (Super Happy Advanced Routing Process)` is a daemon that provides
+miscellaneous functionality used for testing FRR and creating proof-of-concept
+labs.
 
-:abbr:`SHARP` Super Happy Advanced Routing Process.  This daemon is useful
-for the testing of FRR itself as well as useful for creation of Proof of
-Concept labs.
-      
 .. _starting-sharp:
 
 Starting SHARP
@@ -26,42 +26,39 @@ documented elsewhere.
 
 .. _using-sharp:
 
-USING SHARP
+Using SHARP
 ===========
 
-All sharp commands are under the enable node and proceeded by the
-:abbr:`sharp` keyword.  There are currently no permenent sharp
-commands for configuration.
-
-..index:: sharp install
-..clicmd:: sharp install routes A.B.C.D nexthop E.F.G.H (1-1000000)
-
-Install up to a million /32 routes starting at A.B.C.D with specified nexthop
-E.F.G.H.  The nexthop is a NEXTHOP_TYPE_IPV4 and must be reachable to be
-installed into the kernel.  The routes are installed into zebra as
-ZEBRA_ROUTE_SHARP and can be used as part of a normal route redistribution.
-Route installation time is noted in the debug log and upon zebra successful
-installation into the kernel and sharp receiving the notification of all
-route installs the success will be noted in the debug log as well.
+All sharp commands are under the enable node and preceeded by the ``sharp``
+keyword. At present, no sharp commands will be preserved in the config.
 
-..index:: sharp remove
-..clicmd:: sharp remove routes A.B.C.D (1-1000000)
+.. index:: sharp install
+.. clicmd:: sharp install routes A.B.C.D nexthop E.F.G.H (1-1000000)
 
-Remove up 1000000 million /32 routes starting at A.B.C.D.  The routes are
-removed from zebra.  Route deletion start is noted in the debug log
-and when all routes have been successfully deleted the debug log will
-be updated with this information as well.
+   Install up to 1,000,000 (one million) /32 routes starting at ``A.B.C.D``
+   with specified nexthop ``E.F.G.H``. The nexthop is a ``NEXTHOP_TYPE_IPV4``
+   and must be reachable to be installed into the kernel. The routes are
+   installed into zebra as ``ZEBRA_ROUTE_SHARP`` and can be used as part of a
+   normal route redistribution. Route installation time is noted in the debug
+   log. When zebra successfully installs a route into the kernel and SHARP
+   receives success notifications for all routes this is logged as well.
 
-..index:: sharp label
-..clicmd:: sharp label <ipv4|ipv6> vrf NAME label (0-1000000)
+.. index:: sharp remove
+.. clicmd:: sharp remove routes A.B.C.D (1-1000000)
 
-Install a label into the kernel that causes the specified vrf NAME table to be
-used for pop and forward operations when the specified label is seen.
+   Remove up to 1,000,000 (one million) /32 routes starting at ``A.B.C.D``. The
+   routes are removed from zebra. Route deletion start is noted in the debug
+   log and when all routes have been successfully deleted the debug log will be
+   updated with this information as well.
 
-..index:: sharp watch
-..clicmd: sharp watch nexthop <A.B.C.D|X:X::X:X>
+.. index:: sharp label
+.. clicmd:: sharp label <ipv4|ipv6> vrf NAME label (0-1000000)
 
-Instruct zebra to monitor and notify sharp when the specified nexthop is
-changed.  The notification from zebra is written into the debug log.
+   Install a label into the kernel that causes the specified vrf NAME table to
+   be used for pop and forward operations when the specified label is seen.
 
+.. index:: sharp watch
+.. clicmd:: sharp watch nexthop <A.B.C.D|X:X::X:X>
 
+   Instruct zebra to monitor and notify sharp when the specified nexthop is
+   changed. The notification from zebra is written into the debug log.
index d51eb3e5195f320a7c7eeb63aa1905bb9feadba1..9b2aa7470b6f6cd418f4f357acf70efac19b2456 100644 (file)
@@ -2132,7 +2132,7 @@ struct isis_tlvs *isis_copy_tlvs(struct isis_tlvs *tlvs)
        copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO,
                   &tlvs->mt_router_info, &rv->mt_router_info);
 
-       tlvs->mt_router_info_empty = rv->mt_router_info_empty;
+       rv->mt_router_info_empty = tlvs->mt_router_info_empty;
 
        copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_REACH,
                   &tlvs->oldstyle_reach, &rv->oldstyle_reach);
index be8b100ba7a989b779bd7fc4fd41ff42da2c1b1d..318c381bf567fda324a9afe5cfca628673c74414 100644 (file)
@@ -52,7 +52,10 @@ static inline void mt_count_free(struct memtype *mt)
 static inline void *mt_checkalloc(struct memtype *mt, void *ptr, size_t size)
 {
        if (__builtin_expect(ptr == NULL, 0)) {
-               memory_oom(size, mt->name);
+               if (size) {
+                       /* malloc(0) is allowed to return NULL */
+                       memory_oom(size, mt->name);
+               }
                return NULL;
        }
        mt_count_alloc(mt, size);
index b49cb562a1b520daff9f01b3a06fe55622e207b0..401cfb08133dcfa2c9be994b5533fd7580f940dc 100644 (file)
--- a/lib/pbr.h
+++ b/lib/pbr.h
 struct pbr_filter {
        uint32_t filter_bm; /* not encoded by zapi
                             */
-#define PBR_FILTER_SRC_IP     (1 << 0)
-#define PBR_FILTER_DST_IP     (1 << 1)
-#define PBR_FILTER_SRC_PORT   (1 << 2)
-#define PBR_FILTER_DST_PORT   (1 << 3)
-#define PBR_FILTER_FWMARK     (1 << 4)
+#define PBR_FILTER_SRC_IP              (1 << 0)
+#define PBR_FILTER_DST_IP              (1 << 1)
+#define PBR_FILTER_SRC_PORT            (1 << 2)
+#define PBR_FILTER_DST_PORT            (1 << 3)
+#define PBR_FILTER_FWMARK              (1 << 4)
+#define PBR_FILTER_PROTO               (1 << 5)
+#define PBR_FILTER_SRC_PORT_RANGE      (1 << 6)
+#define PBR_FILTER_DST_PORT_RANGE      (1 << 7)
 
        /* Source and Destination IP address with masks. */
        struct prefix src_ip;
index c5eaf9c0fde99ac7bcd87b692e0e92c0008a811b..2ec03acc448aab27624284d08dd78f476cef91e2 100644 (file)
@@ -408,6 +408,7 @@ enum zapi_rule_notify_owner {
        ZAPI_RULE_FAIL_INSTALL,
        ZAPI_RULE_INSTALLED,
        ZAPI_RULE_REMOVED,
+       ZAPI_RULE_FAIL_REMOVE,
 };
 
 enum ipset_type {
@@ -421,18 +422,21 @@ enum zapi_ipset_notify_owner {
        ZAPI_IPSET_FAIL_INSTALL,
        ZAPI_IPSET_INSTALLED,
        ZAPI_IPSET_REMOVED,
+       ZAPI_IPSET_FAIL_REMOVE,
 };
 
 enum zapi_ipset_entry_notify_owner {
        ZAPI_IPSET_ENTRY_FAIL_INSTALL,
        ZAPI_IPSET_ENTRY_INSTALLED,
        ZAPI_IPSET_ENTRY_REMOVED,
+       ZAPI_IPSET_ENTRY_FAIL_REMOVE,
 };
 
 enum zapi_iptable_notify_owner {
        ZAPI_IPTABLE_FAIL_INSTALL,
        ZAPI_IPTABLE_INSTALLED,
        ZAPI_IPTABLE_REMOVED,
+       ZAPI_IPTABLE_FAIL_REMOVE,
 };
 
 /* Zebra MAC types */
index bc1ce621ae60f29f6ff1925e36f78eba809cc809..b3aa3b21d2b5221e1d3eb76cf9395cd6764b1a23 100644 (file)
@@ -216,11 +216,31 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route,
                summary_table = area->summary_router;
        } else {
                if (IS_OSPF6_DEBUG_ABR
-                   || IS_OSPF6_DEBUG_ORIGINATE(INTER_PREFIX)) {
+                   || IS_OSPF6_DEBUG_ORIGINATE(INTER_PREFIX))
                        is_debug++;
+
+               if (route->type == OSPF6_DEST_TYPE_NETWORK &&
+                   route->path.origin.type ==
+                   htons(OSPF6_LSTYPE_INTER_PREFIX)) {
+                       if (!CHECK_FLAG(route->flag, OSPF6_ROUTE_BEST)) {
+                               if (is_debug) {
+                                       inet_ntop(AF_INET,
+                                                 &(ADV_ROUTER_IN_PREFIX(
+                                                       &route->prefix)), buf,
+                                                 sizeof(buf));
+                                       zlog_debug(
+                                               "%s: route %s with cost %u is not best, ignore."
+                                               , __PRETTY_FUNCTION__, buf,
+                                               route->path.cost);
+                               }
+                               return 0;
+                       }
+               }
+
+               if (is_debug) {
                        prefix2str(&route->prefix, buf, sizeof(buf));
-                       zlog_debug("Originating summary in area %s for %s",
-                                  area->name, buf);
+                       zlog_debug("Originating summary in area %s for %s cost %u",
+                                  area->name, buf, route->path.cost);
                }
                summary_table = area->summary_prefix;
        }
@@ -679,6 +699,136 @@ void ospf6_abr_defaults_to_stub(struct ospf6 *o)
        ospf6_route_delete(def);
 }
 
+void ospf6_abr_old_path_update(struct ospf6_route *old_route,
+                              struct ospf6_route *route,
+                              struct ospf6_route_table *table)
+{
+       struct ospf6_path *o_path = NULL;
+       struct listnode *anode, *anext;
+       struct listnode *nnode, *rnode, *rnext;
+       struct ospf6_nexthop *nh, *rnh;
+
+       for (ALL_LIST_ELEMENTS(old_route->paths, anode, anext, o_path)) {
+               if (o_path->area_id != route->path.area_id ||
+                   (memcmp(&(o_path)->origin, &(route)->path.origin,
+                           sizeof(struct ospf6_ls_origin)) != 0))
+                       continue;
+
+               if ((o_path->cost == route->path.cost) &&
+                   (o_path->u.cost_e2 == route->path.u.cost_e2))
+                       continue;
+
+               for (ALL_LIST_ELEMENTS_RO(o_path->nh_list, nnode, nh)) {
+                       for (ALL_LIST_ELEMENTS(old_route->nh_list, rnode,
+                                              rnext, rnh)) {
+                               if (!ospf6_nexthop_is_same(rnh, nh))
+                                       continue;
+                               listnode_delete(old_route->nh_list, rnh);
+                               ospf6_nexthop_delete(rnh);
+                       }
+
+               }
+
+               listnode_delete(old_route->paths, o_path);
+               ospf6_path_free(o_path);
+
+               for (ALL_LIST_ELEMENTS(old_route->paths, anode,
+                                      anext, o_path)) {
+                       ospf6_merge_nexthops(old_route->nh_list,
+                                            o_path->nh_list);
+               }
+
+               if (IS_OSPF6_DEBUG_ABR || IS_OSPF6_DEBUG_EXAMIN(INTER_PREFIX))
+                       zlog_debug("%s: paths %u nh %u", __PRETTY_FUNCTION__,
+                                  old_route->paths ?
+                                  listcount(old_route->paths) : 0,
+                                  old_route->nh_list ?
+                                  listcount(old_route->nh_list) : 0);
+
+               if (table->hook_add)
+                       (*table->hook_add)(old_route);
+
+               if (old_route->path.origin.id == route->path.origin.id &&
+                   old_route->path.origin.adv_router ==
+                   route->path.origin.adv_router) {
+                       struct ospf6_path *h_path;
+
+                       h_path = (struct ospf6_path *)
+                       listgetdata(listhead(old_route->paths));
+                       old_route->path.origin.type = h_path->origin.type;
+                       old_route->path.origin.id = h_path->origin.id;
+                       old_route->path.origin.adv_router =
+                               h_path->origin.adv_router;
+               }
+       }
+}
+
+void ospf6_abr_old_route_remove(struct ospf6_lsa *lsa,
+                               struct ospf6_route *old,
+                               struct ospf6_route_table *table)
+{
+       if (listcount(old->paths) > 1) {
+               struct listnode *anode, *anext, *nnode, *rnode, *rnext;
+               struct ospf6_path *o_path;
+               struct ospf6_nexthop *nh, *rnh;
+               bool nh_updated = false;
+               char buf[PREFIX2STR_BUFFER];
+
+               for (ALL_LIST_ELEMENTS(old->paths, anode, anext, o_path)) {
+                       if (o_path->origin.adv_router != lsa->header->adv_router
+                           && o_path->origin.id != lsa->header->id)
+                               continue;
+                       for (ALL_LIST_ELEMENTS_RO(o_path->nh_list, nnode, nh)) {
+                               for (ALL_LIST_ELEMENTS(old->nh_list,
+                                                       rnode, rnext, rnh)) {
+                                       if (!ospf6_nexthop_is_same(rnh, nh))
+                                               continue;
+                                       listnode_delete(old->nh_list, rnh);
+                                       ospf6_nexthop_delete(rnh);
+                               }
+                       }
+                       listnode_delete(old->paths, o_path);
+                       ospf6_path_free(o_path);
+                       nh_updated = true;
+               }
+
+               if (nh_updated) {
+                       if (listcount(old->paths)) {
+                               if (IS_OSPF6_DEBUG_ABR ||
+                                   IS_OSPF6_DEBUG_EXAMIN(INTER_PREFIX)) {
+                                       prefix2str(&old->prefix, buf,
+                                                  sizeof(buf));
+                                       zlog_debug("%s: old %s updated nh %u",
+                                                  __PRETTY_FUNCTION__, buf,
+                                                  old->nh_list ?
+                                                  listcount(old->nh_list) : 0);
+                               }
+
+                               if (table->hook_add)
+                                       (*table->hook_add)(old);
+
+                               if ((old->path.origin.id == lsa->header->id) &&
+                                   (old->path.origin.adv_router
+                                                == lsa->header->adv_router)) {
+                                       struct ospf6_path *h_path;
+
+                                       h_path = (struct ospf6_path *)
+                                               listgetdata(
+                                                       listhead(old->paths));
+                                       old->path.origin.type =
+                                               h_path->origin.type;
+                                       old->path.origin.id = h_path->origin.id;
+                                       old->path.origin.adv_router =
+                                               h_path->origin.adv_router;
+                               }
+                       } else
+                               ospf6_route_remove(old, table);
+               }
+       } else
+               ospf6_route_remove(old, table);
+
+}
+
 /* RFC 2328 16.2. Calculating the inter-area routes */
 void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
 {
@@ -696,6 +846,9 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
        struct ospf6_inter_prefix_lsa *prefix_lsa = NULL;
        struct ospf6_inter_router_lsa *router_lsa = NULL;
        bool old_entry_updated = false;
+       struct ospf6_path *path, *o_path, *ecmp_path;
+       struct listnode *anode;
+       char adv_router[16];
 
        memset(&prefix, 0, sizeof(prefix));
 
@@ -751,10 +904,39 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
        while (route && ospf6_route_is_prefix(&prefix, route)) {
                if (route->path.area_id == oa->area_id
                    && route->path.origin.type == lsa->header->type
-                   && route->path.origin.id == lsa->header->id
-                   && route->path.origin.adv_router == lsa->header->adv_router
-                   && !CHECK_FLAG(route->flag, OSPF6_ROUTE_WAS_REMOVED))
-                       old = route;
+                   && !CHECK_FLAG(route->flag, OSPF6_ROUTE_WAS_REMOVED)) {
+                       /* LSA adv. router could be part of route's
+                        * paths list. Find the existing path and set
+                        * old as the route.
+                        */
+                       if (listcount(route->paths) > 1) {
+                               struct listnode *anode;
+                               struct ospf6_path *o_path;
+
+                               for (ALL_LIST_ELEMENTS_RO(route->paths, anode,
+                                                         o_path)) {
+                                       inet_ntop(AF_INET,
+                                                 &o_path->origin.adv_router,
+                                                 adv_router,
+                                                 sizeof(adv_router));
+                                       if (o_path->origin.id == lsa->header->id
+                                           && o_path->origin.adv_router ==
+                                           lsa->header->adv_router) {
+                                               old = route;
+
+                                               if (is_debug)
+                                                       zlog_debug("%s: old entry found in paths, adv_router %s",
+                                                       __PRETTY_FUNCTION__,
+                                                       adv_router);
+
+                                               break;
+                                       }
+                               }
+                       } else if (route->path.origin.id == lsa->header->id &&
+                                  route->path.origin.adv_router ==
+                                  lsa->header->adv_router)
+                               old = route;
+               }
                route = ospf6_route_next(route);
        }
        if (route)
@@ -765,7 +947,7 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
                if (is_debug)
                        zlog_debug("cost is LS_INFINITY, ignore");
                if (old)
-                       ospf6_route_remove(old, table);
+                       ospf6_abr_old_route_remove(lsa, old, table);
                return;
        }
        if (OSPF6_LSA_IS_MAXAGE(lsa)) {
@@ -773,14 +955,15 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
                        zlog_debug("%s: LSA %s is MaxAge, ignore",
                                   __PRETTY_FUNCTION__, lsa->name);
                if (old)
-                       ospf6_route_remove(old, table);
+                       ospf6_abr_old_route_remove(lsa, old, table);
                return;
        }
 
        /* (2) if the LSA is self-originated, ignore */
        if (lsa->header->adv_router == oa->ospf6->router_id) {
                if (is_debug)
-                       zlog_debug("LSA is self-originated, ignore");
+                       zlog_debug("LSA %s is self-originated, ignore",
+                                  lsa->name);
                if (old)
                        ospf6_route_remove(old, table);
                return;
@@ -888,7 +1071,7 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
        }
 
        /* Check input prefix-list */
-       if (PREFIX_LIST_IN(oa))
+       if (PREFIX_LIST_IN(oa)) {
                if (prefix_list_apply(PREFIX_LIST_IN(oa), &prefix)
                    != PREFIX_PERMIT) {
                        if (is_debug)
@@ -897,14 +1080,12 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
                                ospf6_route_remove(old, table);
                        return;
                }
+       }
 
        /* (5),(6): the path preference is handled by the sorting
           in the routing table. Always install the path by substituting
           old route (if any). */
-       if (old)
-               route = ospf6_route_copy(old);
-       else
-               route = ospf6_route_create();
+       route = ospf6_route_create();
 
        route->type = type;
        route->prefix = prefix;
@@ -920,11 +1101,8 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
        route->path.type = OSPF6_PATH_TYPE_INTER;
        route->path.cost = abr_entry->path.cost + cost;
 
-       /* Inter abr_entry is same as brouter.
-        * Avoid duplicate nexthops to brouter and its
-        * learnt route. i.e. use merge nexthops.
-        */
-       ospf6_route_merge_nexthops(route, abr_entry);
+       /* copy brouter rechable nexthops into the route. */
+       ospf6_route_copy_nexthops(route, abr_entry);
 
        /* (7) If the routes are identical, copy the next hops over to existing
           route. ospf6's route table implementation will otherwise string both
@@ -948,20 +1126,69 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
                                           old_route->path.cost,
                                           route->path.cost);
                        }
+
+                       /* Check new route's adv. router is same in one of
+                        * the paths with differed cost, if so remove the
+                        * old path as later new route will be added.
+                        */
+                       if (listcount(old_route->paths) > 1)
+                               ospf6_abr_old_path_update(old_route, route,
+                                                         table);
                        continue;
                }
 
+               ospf6_route_merge_nexthops(old_route, route);
                old_entry_updated = true;
-               ospf6_route_merge_nexthops(old, route);
+
+               for (ALL_LIST_ELEMENTS_RO(old_route->paths, anode,
+                                                 o_path)) {
+                       if (o_path->area_id == route->path.area_id &&
+                           (memcmp(&(o_path)->origin, &(route)->path.origin,
+                                   sizeof(struct ospf6_ls_origin)) == 0))
+                               break;
+               }
+
+               /* New adv. router for a existing path add to paths list */
+               if (o_path == NULL) {
+                       ecmp_path = ospf6_path_dup(&route->path);
+
+                       /* Add a nh_list to new ecmp path */
+                       ospf6_copy_nexthops(ecmp_path->nh_list, route->nh_list);
+
+                       /* Add the new path to route's path list */
+                       listnode_add_sort(old_route->paths, ecmp_path);
+
+                       if (is_debug) {
+                               prefix2str(&route->prefix, buf, sizeof(buf));
+                               inet_ntop(AF_INET,
+                                         &ecmp_path->origin.adv_router,
+                                         adv_router, sizeof(adv_router));
+                               zlog_debug("%s: route %s cost %u another path %s added with nh %u, effective paths %u nh %u",
+                                               __PRETTY_FUNCTION__, buf,
+                                               old_route->path.cost,
+                                               adv_router,
+                                               listcount(ecmp_path->nh_list),
+                                               old_route->paths ?
+                                               listcount(old_route->paths) : 0,
+                                               listcount(old_route->nh_list));
+                       }
+               } else {
+                       /* adv. router exists in the list, update the nhs */
+                       list_delete_all_node(o_path->nh_list);
+                       ospf6_copy_nexthops(o_path->nh_list, route->nh_list);
+               }
+
                if (is_debug)
-                       zlog_debug("%s: Update route: %s old cost %u new cost %u nh %u",
-                                  __PRETTY_FUNCTION__,
-                                  buf, old->path.cost, route->path.cost,
+                       zlog_debug("%s: Update route: %s %p old cost %u new cost %u nh %u",
+                                  __PRETTY_FUNCTION__, buf, (void *)old_route,
+                                  old_route->path.cost, route->path.cost,
                                   listcount(route->nh_list));
 
-               /* Update RIB/FIB */
+               /* For Inter-Prefix route: Update RIB/FIB,
+                * For Inter-Router trigger summary update
+                */
                if (table->hook_add)
-                       (*table->hook_add)(old);
+                       (*table->hook_add)(old_route);
 
                /* Delete new route */
                ospf6_route_delete(route);
@@ -969,10 +1196,18 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
        }
 
        if (old_entry_updated == false) {
-               if (is_debug)
-                       zlog_debug("%s: Install route: %s cost %u nh %u",
+               if (is_debug) {
+                       inet_ntop(AF_INET, &route->path.origin.adv_router,
+                                 adv_router, sizeof(adv_router));
+                       zlog_debug("%s: Install route: %s cost %u nh %u adv_router %s ",
                                   __PRETTY_FUNCTION__, buf, route->path.cost,
-                                  listcount(route->nh_list));
+                                  listcount(route->nh_list), adv_router);
+               }
+
+               path = ospf6_path_dup(&route->path);
+               ospf6_copy_nexthops(path->nh_list, abr_entry->nh_list);
+               listnode_add_sort(route->paths, path);
+
                /* ospf6_ia_add_nw_route (table, &prefix, route); */
                ospf6_route_add(route, table);
        }
index abc383463fd8eea88185643ff68573661acd5d3a..e40d155037f3ac2cac37a26fde505d134f8ad374 100644 (file)
@@ -76,7 +76,12 @@ extern void ospf6_abr_prefix_resummarize(struct ospf6 *ospf6);
 extern int config_write_ospf6_debug_abr(struct vty *vty);
 extern void install_element_ospf6_debug_abr(void);
 extern int ospf6_abr_config_write(struct vty *vty);
-
+extern void ospf6_abr_old_route_remove(struct ospf6_lsa *lsa,
+                                      struct ospf6_route *old,
+                                      struct ospf6_route_table *table);
+extern void ospf6_abr_old_path_update(struct ospf6_route *old_route,
+                                     struct ospf6_route *route,
+                                     struct ospf6_route_table *table);
 extern void ospf6_abr_init(void);
 
 #endif /*OSPF6_ABR_H*/
index 8bd0683f14da5add8fc8f16d2fced19b21085877..7f575ee50638b8e5da6c56add7fa7f4cc802a34c 100644 (file)
@@ -303,7 +303,6 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
                                        old_route->path.origin.adv_router =
                                                h_path->origin.adv_router;
                                }
-                               break;
                        } else {
                                if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
                                        prefix2str(&old_route->prefix, buf,
@@ -316,7 +315,6 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
                                }
                                ospf6_route_remove(old_route,
                                                   ospf6->route_table);
-                               break;
                        }
                }
                if (route_updated)
index cdacfad4b4db1a96339bda5d183e384dd99de4a8..8d336c9d0d95b3b98984e93caaf62a910cc56027 100644 (file)
@@ -222,6 +222,7 @@ static int rule_notify_owner(int command, struct zclient *zclient,
                DEBUGD(&pbr_dbg_zebra, "%s: Recived RULE_INSTALLED",
                       __PRETTY_FUNCTION__);
                break;
+       case ZAPI_RULE_FAIL_REMOVE:
        case ZAPI_RULE_REMOVED:
                pbrms->installed &= ~installed;
                DEBUGD(&pbr_dbg_zebra, "%s: Received RULE REMOVED",
index 7afc37a28e74a763592edd97e1060d83b6b9da59..e798d70a51122c9fb5f954349fe6359302c4461f 100644 (file)
@@ -254,11 +254,6 @@ static struct pim_msdp_sa *pim_msdp_sa_new(struct pim_instance *pim,
 
        /* insert into misc tables for easy access */
        sa = hash_get(pim->msdp.sa_hash, sa, hash_alloc_intern);
-       if (!sa) {
-               zlog_err("%s: PIM hash get failure", __PRETTY_FUNCTION__);
-               pim_msdp_sa_free(sa);
-               return NULL;
-       }
        listnode_add_sort(pim->msdp.sa_list, sa);
 
        if (PIM_DEBUG_MSDP_EVENTS) {
index 1dd7c95d23b1dc825b4a6ba939b29438a9f4de4e..b674d738b8f24864faaca361872fee9a80837146 100644 (file)
@@ -34,7 +34,7 @@
 # When using "vtysh" such a config file is also needed. It should be owned by
 # group "frrvty" and set to ug=rw,o= though. Check /etc/pam.d/frr, too.
 #
-watchfrr_enable=no
+watchfrr_enable=yes
 watchfrr_options=("-b_" "-r/usr/lib/frr/frr_restart_%s" "-s/usr/lib/frr/frr_start_%s" "-k/usr/lib/frr/frr_stop_%s")
 #
 zebra=no
index b3e7e31aaa6d7489ce71f31009a072be3ea3a576..c6cc10542bde005112d126bb96db62f35631fe03 100644 (file)
@@ -448,6 +448,12 @@ done
 #  Config files won't get replaced by default, so we do this ugly hack to fix it
 %__sed -i 's|/etc/init.d/|%{_sbindir}/|g' %{_sysconfdir}/daemons 2> /dev/null || true
 
+# With systemd, watchfrr is mandatory. Fix config to make sure it's enabled if
+# we install or upgrade to a frr built with systemd
+%if "%{initsystem}" == "systemd"
+    %__sed -i 's|watchfrr_enable=no|watchfrr_enable=yes|g' %{_sysconfdir}/daemons 2> /dev/null || true
+%endif
+
 /sbin/install-info %{_infodir}/frr.info.gz %{_infodir}/dir
 
 # Create dummy files if they don't exist so basic functions can be used.
index 1708a4b7b064e9ce7c3bfb1db2a76faf2355bbf1..1ff038573f5dbfaa477a65dd9ff19d3f0a666ad4 100644 (file)
@@ -19,6 +19,7 @@ TAGS
 .arch-inventory
 .arch-ids
 __pycache__
+.pytest_cache
 /bgpd/test_aspath
 /bgpd/test_capability
 /bgpd/test_ecommunity
index 14b36cb5fb384a2012a74ce0d0b4f7c48a7156c5..85be620bff0992c38bccbdd918b283fc8ce19485 100644 (file)
@@ -34,6 +34,8 @@ unsigned long zebra_debug_mpls;
 unsigned long zebra_debug_vxlan;
 unsigned long zebra_debug_pw;
 
+DEFINE_HOOK(zebra_debug_show_debugging, (struct vty *vty), (vty));
+
 DEFUN_NOSH (show_debugging_zebra,
            show_debugging_zebra_cmd,
            "show debugging [zebra]",
@@ -88,6 +90,7 @@ DEFUN_NOSH (show_debugging_zebra,
        if (IS_ZEBRA_DEBUG_PW)
                vty_out(vty, "  Zebra pseudowire debugging is on\n");
 
+       hook_call(zebra_debug_show_debugging, vty);
        return CMD_SUCCESS;
 }
 
index 987f9d012543e4b1a7daaad31384cac9cc19b137..1c08459e268151815cc5e055fd5eac390363ff8a 100644 (file)
@@ -82,4 +82,6 @@ extern unsigned long zebra_debug_pw;
 
 extern void zebra_debug_init(void);
 
+DECLARE_HOOK(zebra_debug_show_debugging, (struct vty *vty), (vty));
+
 #endif /* _ZEBRA_DEBUG_H */
index 5f7354585598a27ac1fae862dabb8c06ac2ca151..f0ed8f2f5d2a57d0e15af1c4ba61aa858c5da54d 100644 (file)
@@ -98,6 +98,12 @@ static int netlink_rule_update(int cmd, struct zebra_pbr_rule *rule)
                          &rule->rule.filter.dst_ip.u.prefix, bytelen);
        }
 
+       /* fwmark, if specified */
+       if (IS_RULE_FILTERING_ON_FWMARK(rule)) {
+               addattr32(&req.n, sizeof(req), FRA_FWMARK,
+                         rule->rule.filter.fwmark);
+       }
+
        /* Route table to use to forward, if filter criteria matches. */
        if (rule->rule.action.table < 256)
                req.frh.table = rule->rule.action.table;
index 9a18cc22f0c5500c090b7ef1c2cb56515129a187..943329b1962bc0d3b6121d07f36394e94dff0ffd 100644 (file)
@@ -2847,6 +2847,7 @@ static inline void zread_ipset(ZAPI_HANDLER_ARGS)
                memset(&zpi, 0, sizeof(zpi));
 
                zpi.sock = client->sock;
+               zpi.vrf_id = zvrf->vrf->vrf_id;
                STREAM_GETL(s, zpi.unique);
                STREAM_GETL(s, zpi.type);
                STREAM_GET(&zpi.ipset_name, s, ZEBRA_IPSET_NAME_SIZE);
@@ -2885,11 +2886,26 @@ static inline void zread_ipset_entry(ZAPI_HANDLER_ARGS)
                STREAM_GETC(s, zpi.dst.prefixlen);
                STREAM_GET(&zpi.dst.u.prefix, s, prefix_blen(&zpi.dst));
 
+               STREAM_GETW(s, zpi.src_port_min);
+               STREAM_GETW(s, zpi.src_port_max);
+               STREAM_GETW(s, zpi.dst_port_min);
+               STREAM_GETW(s, zpi.dst_port_max);
+               STREAM_GETC(s, zpi.proto);
                if (!is_default_prefix(&zpi.src))
                        zpi.filter_bm |= PBR_FILTER_SRC_IP;
 
                if (!is_default_prefix(&zpi.dst))
                        zpi.filter_bm |= PBR_FILTER_DST_IP;
+               if (zpi.dst_port_min != 0)
+                       zpi.filter_bm |= PBR_FILTER_DST_PORT;
+               if (zpi.src_port_min != 0)
+                       zpi.filter_bm |= PBR_FILTER_SRC_PORT;
+               if (zpi.dst_port_max != 0)
+                       zpi.filter_bm |= PBR_FILTER_DST_PORT_RANGE;
+               if (zpi.src_port_max != 0)
+                       zpi.filter_bm |= PBR_FILTER_SRC_PORT_RANGE;
+               if (zpi.proto != 0)
+                       zpi.filter_bm |= PBR_FILTER_PROTO;
 
                /* calculate backpointer */
                zpi.backpointer = zebra_pbr_lookup_ipset_pername(
@@ -2913,13 +2929,17 @@ static inline void zread_iptable(ZAPI_HANDLER_ARGS)
 
        memset(&zpi, 0, sizeof(zpi));
 
+       zpi.interface_name_list = list_new();
        zpi.sock = client->sock;
+       zpi.vrf_id = zvrf->vrf->vrf_id;
        STREAM_GETL(s, zpi.unique);
        STREAM_GETL(s, zpi.type);
        STREAM_GETL(s, zpi.filter_bm);
        STREAM_GETL(s, zpi.action);
        STREAM_GETL(s, zpi.fwmark);
        STREAM_GET(&zpi.ipset_name, s, ZEBRA_IPSET_NAME_SIZE);
+       STREAM_GETL(s, zpi.nb_interface);
+       zebra_pbr_iptable_update_interfacelist(s, &zpi);
 
        if (hdr->command == ZEBRA_IPTABLE_ADD)
                zebra_pbr_add_iptable(zvrf->zns, &zpi);
index 5c62e366a63293ab96c961c6d3f01f79ebbb4993..4526a14870f00ed457ccc6d0ef45f29c31de6695 100644 (file)
@@ -262,10 +262,10 @@ int zebra_ns_disable(ns_id_t ns_id, void **info)
 
        hash_clean(zns->rules_hash, zebra_pbr_rules_free);
        hash_free(zns->rules_hash);
-       hash_clean(zns->ipset_hash, zebra_pbr_ipset_free);
-       hash_free(zns->ipset_hash);
        hash_clean(zns->ipset_entry_hash,
                   zebra_pbr_ipset_entry_free),
+       hash_clean(zns->ipset_hash, zebra_pbr_ipset_free);
+       hash_free(zns->ipset_hash);
        hash_free(zns->ipset_entry_hash);
        hash_clean(zns->iptable_hash,
                   zebra_pbr_iptable_free);
index 54a9cdbc5b8fb3b19bb3fefda34b73a3369023f5..6a42aaecb464db307dc2bc65e31b374a5f56965d 100644 (file)
 
 #include <jhash.h>
 #include <hash.h>
+#include <memory.h>
+#include <hook.h>
 
 #include "zebra/zebra_pbr.h"
 #include "zebra/rt.h"
 #include "zebra/zapi_msg.h"
+#include "zebra/zebra_memory.h"
 
 /* definitions */
+DEFINE_MTYPE_STATIC(ZEBRA, PBR_IPTABLE_IFNAME, "PBR interface list")
+
+/* definitions */
+static const struct message ipset_type_msg[] = {
+       {IPSET_NET_PORT_NET, "net,port,net"},
+       {IPSET_NET_PORT, "net,port"},
+       {IPSET_NET_NET, "net,net"},
+       {IPSET_NET, "net"},
+       {0}
+};
 
 /* static function declarations */
+DEFINE_HOOK(zebra_pbr_ipset_entry_wrap_script_get_stat, (struct zebra_ns *zns,
+                                   struct zebra_pbr_ipset_entry *ipset,
+                                   uint64_t *pkts, uint64_t *bytes),
+                                    (zns, ipset, pkts, bytes))
+
+DEFINE_HOOK(zebra_pbr_iptable_wrap_script_get_stat, (struct zebra_ns *zns,
+                                   struct zebra_pbr_iptable *iptable,
+                                   uint64_t *pkts, uint64_t *bytes),
+                                    (zns, iptable, pkts, bytes))
+
+DEFINE_HOOK(zebra_pbr_iptable_wrap_script_update, (struct zebra_ns *zns,
+                                            int cmd,
+                                            struct zebra_pbr_iptable *iptable),
+                                           (zns, cmd, iptable));
+
+DEFINE_HOOK(zebra_pbr_ipset_entry_wrap_script_update, (struct zebra_ns *zns,
+                                 int cmd,
+                                 struct zebra_pbr_ipset_entry *ipset),
+                                 (zns, cmd, ipset));
+
+DEFINE_HOOK(zebra_pbr_ipset_wrap_script_update, (struct zebra_ns *zns,
+                                 int cmd,
+                                 struct zebra_pbr_ipset *ipset),
+                                 (zns, cmd, ipset));
 
 /* Private functions */
 
@@ -145,9 +182,15 @@ static struct zebra_pbr_rule *pbr_rule_lookup_unique(struct zebra_ns *zns,
 void zebra_pbr_ipset_free(void *arg)
 {
        struct zebra_pbr_ipset *ipset;
+       struct zebra_ns *zns;
 
        ipset = (struct zebra_pbr_ipset *)arg;
-
+       if (vrf_is_backend_netns())
+               zns = zebra_ns_lookup(ipset->vrf_id);
+       else
+               zns = zebra_ns_lookup(NS_DEFAULT);
+       hook_call(zebra_pbr_ipset_wrap_script_update,
+                 zns, 0, ipset);
        XFREE(MTYPE_TMP, ipset);
 }
 
@@ -179,8 +222,17 @@ int zebra_pbr_ipset_hash_equal(const void *arg1, const void *arg2)
 void zebra_pbr_ipset_entry_free(void *arg)
 {
        struct zebra_pbr_ipset_entry *ipset;
+       struct zebra_ns *zns;
 
        ipset = (struct zebra_pbr_ipset_entry *)arg;
+       if (ipset->backpointer && vrf_is_backend_netns()) {
+               struct zebra_pbr_ipset *ips = ipset->backpointer;
+
+               zns = zebra_ns_lookup((ns_id_t)ips->vrf_id);
+       } else
+               zns = zebra_ns_lookup(NS_DEFAULT);
+       hook_call(zebra_pbr_ipset_entry_wrap_script_update,
+                 zns, 0, ipset);
 
        XFREE(MTYPE_TMP, ipset);
 }
@@ -194,6 +246,11 @@ uint32_t zebra_pbr_ipset_entry_hash_key(void *arg)
        key = prefix_hash_key(&ipset->src);
        key = jhash_1word(ipset->unique, key);
        key = jhash_1word(prefix_hash_key(&ipset->dst), key);
+       key = jhash(&ipset->dst_port_min, 2, key);
+       key = jhash(&ipset->dst_port_max, 2, key);
+       key = jhash(&ipset->src_port_min, 2, key);
+       key = jhash(&ipset->src_port_max, 2, key);
+       key = jhash(&ipset->proto, 1, key);
 
        return key;
 }
@@ -214,15 +271,44 @@ int zebra_pbr_ipset_entry_hash_equal(const void *arg1, const void *arg2)
        if (!prefix_same(&r1->dst, &r2->dst))
                return 0;
 
+       if (r1->src_port_min != r2->src_port_min)
+               return 0;
+
+       if (r1->src_port_max != r2->src_port_max)
+               return 0;
+
+       if (r1->dst_port_min != r2->dst_port_min)
+               return 0;
+
+       if (r1->dst_port_max != r2->dst_port_max)
+               return 0;
+
+       if (r1->proto != r2->proto)
+               return 0;
        return 1;
 }
 
 void zebra_pbr_iptable_free(void *arg)
 {
        struct zebra_pbr_iptable *iptable;
+       struct listnode *node, *nnode;
+       char *name;
+       struct zebra_ns *zns;
 
        iptable = (struct zebra_pbr_iptable *)arg;
-
+       if (vrf_is_backend_netns())
+               zns = zebra_ns_lookup((ns_id_t)iptable->vrf_id);
+       else
+               zns =  zebra_ns_lookup(NS_DEFAULT);
+       hook_call(zebra_pbr_iptable_wrap_script_update,
+                 zns, 0, iptable);
+
+       for (ALL_LIST_ELEMENTS(iptable->interface_name_list,
+                                       node, nnode, name)) {
+               XFREE(MTYPE_PBR_IPTABLE_IFNAME, name);
+               list_delete_node(iptable->interface_name_list,
+                                node);
+       }
        XFREE(MTYPE_TMP, iptable);
 }
 
@@ -283,7 +369,6 @@ void zebra_pbr_add_rule(struct zebra_ns *zns, struct zebra_pbr_rule *rule)
 
        (void)hash_get(zns->rules_hash, rule, pbr_rule_alloc_intern);
        kernel_add_pbr_rule(rule);
-
        /*
         * Rule Replace semantics, if we have an old, install the
         * new rule, look above, and then delete the old
@@ -320,6 +405,45 @@ static void zebra_pbr_cleanup_rules(struct hash_backet *b, void *data)
        }
 }
 
+static void zebra_pbr_cleanup_ipset(struct hash_backet *b, void *data)
+{
+       struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
+       struct zebra_pbr_ipset *ipset = b->data;
+       int *sock = data;
+
+       if (ipset->sock == *sock) {
+               hook_call(zebra_pbr_ipset_wrap_script_update,
+                         zns, 0, ipset);
+               hash_release(zns->ipset_hash, ipset);
+       }
+}
+
+static void zebra_pbr_cleanup_ipset_entry(struct hash_backet *b, void *data)
+{
+       struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
+       struct zebra_pbr_ipset_entry *ipset = b->data;
+       int *sock = data;
+
+       if (ipset->sock == *sock) {
+               hook_call(zebra_pbr_ipset_entry_wrap_script_update,
+                         zns, 0, ipset);
+               hash_release(zns->ipset_entry_hash, ipset);
+       }
+}
+
+static void zebra_pbr_cleanup_iptable(struct hash_backet *b, void *data)
+{
+       struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
+       struct zebra_pbr_iptable *iptable = b->data;
+       int *sock = data;
+
+       if (iptable->sock == *sock) {
+               hook_call(zebra_pbr_iptable_wrap_script_update,
+                         zns, 0, iptable);
+               hash_release(zns->iptable_hash, iptable);
+       }
+}
+
 static int zebra_pbr_client_close_cleanup(struct zserv *client)
 {
        int sock = client->sock;
@@ -328,6 +452,12 @@ static int zebra_pbr_client_close_cleanup(struct zserv *client)
        if (!sock)
                return 0;
        hash_iterate(zns->rules_hash, zebra_pbr_cleanup_rules, &sock);
+       hash_iterate(zns->iptable_hash,
+                    zebra_pbr_cleanup_iptable, &sock);
+       hash_iterate(zns->ipset_entry_hash,
+                    zebra_pbr_cleanup_ipset_entry, &sock);
+       hash_iterate(zns->ipset_hash,
+                    zebra_pbr_cleanup_ipset, &sock);
        return 1;
 }
 
@@ -353,10 +483,14 @@ static void *pbr_ipset_alloc_intern(void *arg)
 void zebra_pbr_create_ipset(struct zebra_ns *zns,
                            struct zebra_pbr_ipset *ipset)
 {
+       int ret;
+
        (void)hash_get(zns->ipset_hash, ipset, pbr_ipset_alloc_intern);
-       /* TODO:
-        * - Netlink call
-        */
+       ret = hook_call(zebra_pbr_ipset_wrap_script_update,
+                 zns, 1, ipset);
+       kernel_pbr_ipset_add_del_status(ipset,
+                                       ret ? SOUTHBOUND_INSTALL_SUCCESS
+                                       : SOUTHBOUND_INSTALL_FAILURE);
 }
 
 void zebra_pbr_destroy_ipset(struct zebra_ns *zns,
@@ -365,13 +499,12 @@ void zebra_pbr_destroy_ipset(struct zebra_ns *zns,
        struct zebra_pbr_ipset *lookup;
 
        lookup = hash_lookup(zns->ipset_hash, ipset);
-       /* TODO:
-        * - Netlink destroy from kernel
-        * - ?? destroy ipset entries before
-        */
-       if (lookup)
+       hook_call(zebra_pbr_ipset_wrap_script_update,
+                 zns, 0, ipset);
+       if (lookup) {
+               hash_release(zns->ipset_hash, lookup);
                XFREE(MTYPE_TMP, lookup);
-       else
+       else
                zlog_warn("%s: IPSet Entry being deleted we know nothing about",
                          __PRETTY_FUNCTION__);
 }
@@ -381,6 +514,12 @@ struct pbr_ipset_name_lookup {
        char ipset_name[ZEBRA_IPSET_NAME_SIZE];
 };
 
+static const char *zebra_pbr_ipset_type2str(uint32_t type)
+{
+       return lookup_msg(ipset_type_msg, type,
+                         "Unrecognized IPset Type");
+}
+
 static int zebra_pbr_ipset_pername_walkcb(struct hash_backet *backet, void *arg)
 {
        struct pbr_ipset_name_lookup *pinl =
@@ -427,12 +566,15 @@ static void *pbr_ipset_entry_alloc_intern(void *arg)
 void zebra_pbr_add_ipset_entry(struct zebra_ns *zns,
                               struct zebra_pbr_ipset_entry *ipset)
 {
+       int ret;
+
        (void)hash_get(zns->ipset_entry_hash, ipset,
                       pbr_ipset_entry_alloc_intern);
-       /* TODO:
-        * - attach to ipset list
-        * - Netlink add to kernel
-        */
+       ret = hook_call(zebra_pbr_ipset_entry_wrap_script_update,
+                 zns, 1, ipset);
+       kernel_pbr_ipset_entry_add_del_status(ipset,
+                                       ret ? SOUTHBOUND_INSTALL_SUCCESS
+                                       : SOUTHBOUND_INSTALL_FAILURE);
 }
 
 void zebra_pbr_del_ipset_entry(struct zebra_ns *zns,
@@ -441,14 +583,12 @@ void zebra_pbr_del_ipset_entry(struct zebra_ns *zns,
        struct zebra_pbr_ipset_entry *lookup;
 
        lookup = hash_lookup(zns->ipset_entry_hash, ipset);
-       /* TODO:
-        * - Netlink destroy
-        * - detach from ipset list
-        * - ?? if no more entres, delete ipset
-        */
-       if (lookup)
+       hook_call(zebra_pbr_ipset_entry_wrap_script_update,
+                 zns, 0, ipset);
+       if (lookup) {
+               hash_release(zns->ipset_entry_hash, lookup);
                XFREE(MTYPE_TMP, lookup);
-       else
+       else
                zlog_warn("%s: IPSet being deleted we know nothing about",
                          __PRETTY_FUNCTION__);
 }
@@ -470,24 +610,36 @@ static void *pbr_iptable_alloc_intern(void *arg)
 void zebra_pbr_add_iptable(struct zebra_ns *zns,
                           struct zebra_pbr_iptable *iptable)
 {
+       int ret;
+
        (void)hash_get(zns->iptable_hash, iptable,
                       pbr_iptable_alloc_intern);
-       /* TODO call netlink layer */
+       ret = hook_call(zebra_pbr_iptable_wrap_script_update, zns, 1, iptable);
+       kernel_pbr_iptable_add_del_status(iptable,
+                                         ret ? SOUTHBOUND_INSTALL_SUCCESS
+                                         : SOUTHBOUND_INSTALL_FAILURE);
 }
 
 void zebra_pbr_del_iptable(struct zebra_ns *zns,
                           struct zebra_pbr_iptable *iptable)
 {
-       struct zebra_pbr_ipset_entry *lookup;
+       struct zebra_pbr_iptable *lookup;
 
        lookup = hash_lookup(zns->iptable_hash, iptable);
-       /* TODO:
-        * - call netlink layer
-        * - detach from iptable list
-        */
-       if (lookup)
+       hook_call(zebra_pbr_iptable_wrap_script_update, zns, 0, iptable);
+       if (lookup) {
+               struct listnode *node, *nnode;
+               char *name;
+
+               hash_release(zns->iptable_hash, lookup);
+               for (ALL_LIST_ELEMENTS(iptable->interface_name_list,
+                                      node, nnode, name)) {
+                       XFREE(MTYPE_PBR_IPTABLE_IFNAME, name);
+                       list_delete_node(iptable->interface_name_list,
+                                        node);
+               }
                XFREE(MTYPE_TMP, lookup);
-       else
+       else
                zlog_warn("%s: IPTable being deleted we know nothing about",
                          __PRETTY_FUNCTION__);
 }
@@ -509,7 +661,7 @@ void kernel_pbr_rule_add_del_status(struct zebra_pbr_rule *rule,
                zsend_rule_notify_owner(rule, ZAPI_RULE_REMOVED);
                break;
        case SOUTHBOUND_DELETE_FAILURE:
-               zsend_rule_notify_owner(rule, ZAPI_RULE_REMOVED);
+               zsend_rule_notify_owner(rule, ZAPI_RULE_FAIL_REMOVE);
                break;
        }
 }
@@ -528,8 +680,10 @@ void kernel_pbr_ipset_add_del_status(struct zebra_pbr_ipset *ipset,
                zsend_ipset_notify_owner(ipset, ZAPI_IPSET_FAIL_INSTALL);
                break;
        case SOUTHBOUND_DELETE_SUCCESS:
+               zsend_ipset_notify_owner(ipset, ZAPI_IPSET_REMOVED);
+               break;
        case SOUTHBOUND_DELETE_FAILURE:
-               /* TODO : handling of delete event */
+               zsend_ipset_notify_owner(ipset, ZAPI_IPSET_FAIL_REMOVE);
                break;
        }
 }
@@ -551,8 +705,12 @@ void kernel_pbr_ipset_entry_add_del_status(
                                               ZAPI_IPSET_ENTRY_FAIL_INSTALL);
                break;
        case SOUTHBOUND_DELETE_SUCCESS:
+               zsend_ipset_entry_notify_owner(ipset,
+                                              ZAPI_IPSET_ENTRY_REMOVED);
+               break;
        case SOUTHBOUND_DELETE_FAILURE:
-               /* TODO : handling of delete event */
+               zsend_ipset_entry_notify_owner(ipset,
+                                              ZAPI_IPSET_ENTRY_FAIL_REMOVE);
                break;
        }
 }
@@ -571,8 +729,12 @@ void kernel_pbr_iptable_add_del_status(struct zebra_pbr_iptable *iptable,
                zsend_iptable_notify_owner(iptable, ZAPI_IPTABLE_FAIL_INSTALL);
                break;
        case SOUTHBOUND_DELETE_SUCCESS:
+               zsend_iptable_notify_owner(iptable,
+                                          ZAPI_IPTABLE_REMOVED);
+               break;
        case SOUTHBOUND_DELETE_FAILURE:
-               /* TODO : handling of delete event */
+               zsend_iptable_notify_owner(iptable,
+                                          ZAPI_IPTABLE_FAIL_REMOVE);
                break;
        }
 }
@@ -584,3 +746,256 @@ int kernel_pbr_rule_del(struct zebra_pbr_rule *rule)
 {
        return 0;
 }
+
+struct zebra_pbr_ipset_entry_unique_display {
+       struct zebra_pbr_ipset *zpi;
+       struct vty *vty;
+       struct zebra_ns *zns;
+};
+
+struct zebra_pbr_env_display {
+       struct zebra_ns *zns;
+       struct vty *vty;
+};
+
+static const char *zebra_pbr_prefix2str(union prefixconstptr pu,
+                                       char *str, int size)
+{
+       const struct prefix *p = pu.p;
+       char buf[PREFIX2STR_BUFFER];
+
+       if (p->family == AF_INET && p->prefixlen == IPV4_MAX_PREFIXLEN) {
+               snprintf(str, size, "%s", inet_ntop(p->family, &p->u.prefix,
+                                                   buf, PREFIX2STR_BUFFER));
+               return str;
+       }
+       return prefix2str(pu, str, size);
+}
+
+static void zebra_pbr_display_port(struct vty *vty, uint32_t filter_bm,
+                           uint16_t port_min, uint16_t port_max,
+                           uint8_t proto)
+{
+       if (!(filter_bm & PBR_FILTER_PROTO)) {
+               if (port_max)
+                       vty_out(vty, ":udp/tcp:%d-%d",
+                               port_min, port_max);
+               else
+                       vty_out(vty, ":udp/tcp:%d",
+                               port_min);
+       } else {
+               if (port_max)
+                       vty_out(vty, ":proto %d:%d-%d",
+                               proto, port_min, port_max);
+               else
+                       vty_out(vty, ":proto %d:%d",
+                               proto, port_min);
+       }
+}
+
+static int zebra_pbr_show_ipset_entry_walkcb(struct hash_backet *backet,
+                                            void *arg)
+{
+       struct zebra_pbr_ipset_entry_unique_display *unique =
+               (struct zebra_pbr_ipset_entry_unique_display *)arg;
+       struct zebra_pbr_ipset *zpi = unique->zpi;
+       struct vty *vty = unique->vty;
+       struct zebra_pbr_ipset_entry *zpie =
+               (struct zebra_pbr_ipset_entry *)backet->data;
+       uint64_t pkts = 0, bytes = 0;
+       struct zebra_ns *zns = unique->zns;
+       int ret = 0;
+
+       if (zpie->backpointer != zpi)
+               return HASHWALK_CONTINUE;
+
+       if ((zpi->type == IPSET_NET_NET) ||
+           (zpi->type == IPSET_NET_PORT_NET)) {
+               char buf[PREFIX_STRLEN];
+
+               zebra_pbr_prefix2str(&(zpie->src), buf, sizeof(buf));
+               vty_out(vty, "\tfrom %s", buf);
+               if (zpie->filter_bm & PBR_FILTER_SRC_PORT)
+                       zebra_pbr_display_port(vty, zpie->filter_bm,
+                                              zpie->src_port_min,
+                                              zpie->src_port_max,
+                                              zpie->proto);
+               vty_out(vty, " to ");
+               zebra_pbr_prefix2str(&(zpie->dst), buf, sizeof(buf));
+               vty_out(vty, "%s", buf);
+               if (zpie->filter_bm & PBR_FILTER_DST_PORT)
+                       zebra_pbr_display_port(vty, zpie->filter_bm,
+                                              zpie->dst_port_min,
+                                              zpie->dst_port_max,
+                                              zpie->proto);
+       } else if ((zpi->type == IPSET_NET) ||
+                  (zpi->type == IPSET_NET_PORT)) {
+               char buf[PREFIX_STRLEN];
+
+               if (zpie->filter_bm & PBR_FILTER_SRC_IP) {
+                       zebra_pbr_prefix2str(&(zpie->src), buf, sizeof(buf));
+                       vty_out(vty, "\tfrom %s", buf);
+               }
+               if (zpie->filter_bm & PBR_FILTER_SRC_PORT)
+                       zebra_pbr_display_port(vty, zpie->filter_bm,
+                                              zpie->src_port_min,
+                                              zpie->src_port_max,
+                                              zpie->proto);
+               if (zpie->filter_bm & PBR_FILTER_DST_IP) {
+                       zebra_pbr_prefix2str(&(zpie->dst), buf, sizeof(buf));
+                       vty_out(vty, "\tto %s", buf);
+               }
+               if (zpie->filter_bm & PBR_FILTER_DST_PORT)
+                       zebra_pbr_display_port(vty, zpie->filter_bm,
+                                              zpie->dst_port_min,
+                                              zpie->dst_port_max,
+                                              zpie->proto);
+       }
+       vty_out(vty, " (%u)\n", zpie->unique);
+
+       ret = hook_call(zebra_pbr_ipset_entry_wrap_script_get_stat,
+                       zns, zpie, &pkts, &bytes);
+       if (ret && pkts > 0)
+               vty_out(vty, "\t pkts %" PRIu64 ", bytes %" PRIu64"\n",
+                       pkts, bytes);
+       return HASHWALK_CONTINUE;
+}
+
+static int zebra_pbr_show_ipset_walkcb(struct hash_backet *backet, void *arg)
+{
+       struct zebra_pbr_env_display *uniqueipset =
+               (struct zebra_pbr_env_display *)arg;
+       struct zebra_pbr_ipset *zpi = (struct zebra_pbr_ipset *)backet->data;
+       struct zebra_pbr_ipset_entry_unique_display unique;
+       struct vty *vty = uniqueipset->vty;
+       struct zebra_ns *zns = uniqueipset->zns;
+
+       vty_out(vty, "IPset %s type %s\n", zpi->ipset_name,
+               zebra_pbr_ipset_type2str(zpi->type));
+       unique.vty = vty;
+       unique.zpi = zpi;
+       unique.zns = zns;
+       hash_walk(zns->ipset_entry_hash, zebra_pbr_show_ipset_entry_walkcb,
+                 &unique);
+       vty_out(vty, "\n");
+       return HASHWALK_CONTINUE;
+}
+
+/*
+ */
+void zebra_pbr_show_ipset_list(struct vty *vty, char *ipsetname)
+{
+       struct zebra_pbr_ipset *zpi;
+       struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
+       struct zebra_pbr_ipset_entry_unique_display unique;
+       struct zebra_pbr_env_display uniqueipset;
+
+       if (ipsetname) {
+               zpi = zebra_pbr_lookup_ipset_pername(zns, ipsetname);
+               if (!zpi) {
+                       vty_out(vty, "No IPset %s found\n", ipsetname);
+                       return;
+               }
+               vty_out(vty, "IPset %s type %s\n", ipsetname,
+                       zebra_pbr_ipset_type2str(zpi->type));
+
+               unique.vty = vty;
+               unique.zpi = zpi;
+               unique.zns = zns;
+               hash_walk(zns->ipset_entry_hash,
+                         zebra_pbr_show_ipset_entry_walkcb,
+                         &unique);
+               return;
+       }
+       uniqueipset.zns = zns;
+       uniqueipset.vty = vty;
+       hash_walk(zns->ipset_hash, zebra_pbr_show_ipset_walkcb,
+                 &uniqueipset);
+}
+
+struct pbr_rule_fwmark_lookup {
+       struct zebra_pbr_rule *ptr;
+       uint32_t fwmark;
+};
+
+static int zebra_pbr_rule_lookup_fwmark_walkcb(struct hash_backet *backet,
+                                              void *arg)
+{
+       struct pbr_rule_fwmark_lookup *iprule =
+               (struct pbr_rule_fwmark_lookup *)arg;
+       struct zebra_pbr_rule *zpr = (struct zebra_pbr_rule *)backet->data;
+
+       if (iprule->fwmark == zpr->rule.filter.fwmark) {
+               iprule->ptr = zpr;
+               return HASHWALK_ABORT;
+       }
+       return HASHWALK_CONTINUE;
+}
+
+static int zebra_pbr_show_iptable_walkcb(struct hash_backet *backet, void *arg)
+{
+       struct zebra_pbr_iptable *iptable =
+               (struct zebra_pbr_iptable *)backet->data;
+       struct zebra_pbr_env_display *env = (struct zebra_pbr_env_display *)arg;
+       struct vty *vty = env->vty;
+       struct zebra_ns *zns = env->zns;
+       int ret;
+       uint64_t pkts = 0, bytes = 0;
+
+       vty_out(vty, "IPtable %s action %s (%u)\n", iptable->ipset_name,
+               iptable->action == ZEBRA_IPTABLES_DROP ? "drop" : "redirect",
+               iptable->unique);
+
+       ret = hook_call(zebra_pbr_iptable_wrap_script_get_stat,
+                       zns, iptable, &pkts, &bytes);
+       if (ret && pkts > 0)
+               vty_out(vty, "\t pkts %" PRIu64 ", bytes %" PRIu64"\n",
+                       pkts, bytes);
+       if (iptable->action != ZEBRA_IPTABLES_DROP) {
+               struct pbr_rule_fwmark_lookup prfl;
+
+               prfl.fwmark = iptable->fwmark;
+               prfl.ptr = NULL;
+               hash_walk(zns->rules_hash,
+                         &zebra_pbr_rule_lookup_fwmark_walkcb, &prfl);
+               if (prfl.ptr) {
+                       struct zebra_pbr_rule *zpr = prfl.ptr;
+
+                       vty_out(vty, "\t table %u, fwmark %u\n",
+                               zpr->rule.action.table,
+                               prfl.fwmark);
+               }
+       }
+       return HASHWALK_CONTINUE;
+}
+
+void zebra_pbr_show_iptable(struct vty *vty)
+{
+       struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
+       struct zebra_pbr_env_display env;
+
+       env.vty = vty;
+       env.zns = zns;
+
+       hash_walk(zns->iptable_hash, zebra_pbr_show_iptable_walkcb,
+                 &env);
+}
+
+void zebra_pbr_iptable_update_interfacelist(struct stream *s,
+                                           struct zebra_pbr_iptable *zpi)
+{
+       uint32_t i = 0, index;
+       struct interface *ifp;
+       char *name;
+
+       for (i = 0; i < zpi->nb_interface; i++) {
+               STREAM_GETL(s, index);
+               ifp = if_lookup_by_index(index, zpi->vrf_id);
+               if (!ifp)
+                       continue;
+               name = XSTRDUP(MTYPE_PBR_IPTABLE_IFNAME, ifp->name);
+               listnode_add(zpi->interface_name_list, name);
+       }
+stream_failure:
+       return;
+}
index 6b5cd1e8d12ec82d3f5c3d280fb85224dfb8b628..31fc553581f8911f2f804bf8a72feb3d0c68fb5f 100644 (file)
@@ -48,6 +48,8 @@ struct zebra_pbr_rule {
        (r->rule.filter.filter_bm & PBR_FILTER_SRC_PORT)
 #define IS_RULE_FILTERING_ON_DST_PORT(r) \
        (r->rule.filter.filter_bm & PBR_FILTER_DST_PORT)
+#define IS_RULE_FILTERING_ON_FWMARK(r) \
+       (r->rule.filter.filter_bm & PBR_FILTER_FWMARK)
 
 /*
  * An IPSet Entry Filter
@@ -61,6 +63,8 @@ struct zebra_pbr_ipset {
         */
        int sock;
 
+       vrf_id_t vrf_id;
+
        uint32_t unique;
 
        /* type is encoded as uint32_t
@@ -87,6 +91,13 @@ struct zebra_pbr_ipset_entry {
        struct prefix src;
        struct prefix dst;
 
+       uint16_t src_port_min;
+       uint16_t src_port_max;
+       uint16_t dst_port_min;
+       uint16_t dst_port_max;
+
+       uint8_t proto;
+
        uint32_t filter_bm;
 
        struct zebra_pbr_ipset *backpointer;
@@ -104,6 +115,8 @@ struct zebra_pbr_iptable {
         */
        int sock;
 
+       vrf_id_t vrf_id;
+
        uint32_t unique;
 
        /* include ipset type
@@ -118,6 +131,10 @@ struct zebra_pbr_iptable {
 
        uint32_t action;
 
+       uint32_t nb_interface;
+
+       struct list *interface_name_list;
+
        char ipset_name[ZEBRA_IPSET_NAME_SIZE];
 };
 
@@ -204,4 +221,31 @@ extern uint32_t zebra_pbr_iptable_hash_key(void *arg);
 extern int zebra_pbr_iptable_hash_equal(const void *arg1, const void *arg2);
 
 extern void zebra_pbr_init(void);
+extern void zebra_pbr_show_ipset_list(struct vty *vty, char *ipsetname);
+extern void zebra_pbr_show_iptable(struct vty *vty);
+extern void zebra_pbr_iptable_update_interfacelist(struct stream *s,
+                                  struct zebra_pbr_iptable *zpi);
+
+DECLARE_HOOK(zebra_pbr_ipset_entry_wrap_script_get_stat, (struct zebra_ns *zns,
+                                   struct zebra_pbr_ipset_entry *ipset,
+                                   uint64_t *pkts, uint64_t *bytes),
+                                    (zns, ipset, pkts, bytes))
+DECLARE_HOOK(zebra_pbr_iptable_wrap_script_get_stat, (struct zebra_ns *zns,
+                                   struct zebra_pbr_iptable *iptable,
+                                   uint64_t *pkts, uint64_t *bytes),
+                                    (zns, iptable, pkts, bytes))
+DECLARE_HOOK(zebra_pbr_iptable_wrap_script_update, (struct zebra_ns *zns,
+                                            int cmd,
+                                            struct zebra_pbr_iptable *iptable),
+                                            (zns, cmd, iptable));
+
+DECLARE_HOOK(zebra_pbr_ipset_entry_wrap_script_update, (struct zebra_ns *zns,
+                                 int cmd,
+                                 struct zebra_pbr_ipset_entry *ipset),
+                                    (zns, cmd, ipset));
+DECLARE_HOOK(zebra_pbr_ipset_wrap_script_update, (struct zebra_ns *zns,
+                                 int cmd,
+                                 struct zebra_pbr_ipset *ipset),
+                                    (zns, cmd, ipset));
+
 #endif /* _ZEBRA_PBR_H */
index e6f80f92a7ddb08a9f17958ccb4b19e6b9029fef..a094ca585e8d07dc3e6f326b967216f0ce76750b 100644 (file)
@@ -51,6 +51,7 @@
 #include "zebra/router-id.h"
 #include "zebra/ipforward.h"
 #include "zebra/zebra_vxlan_private.h"
+#include "zebra/zebra_pbr.h"
 
 extern int allow_delete;
 
@@ -3260,6 +3261,37 @@ DEFUN (show_evpn_neigh_vni_vtep,
        return CMD_SUCCESS;
 }
 
+/* policy routing contexts */
+DEFUN (show_pbr_ipset,
+       show_pbr_ipset_cmd,
+       "show pbr ipset [WORD]",
+       SHOW_STR
+       "Policy-Based Routing\n"
+       "IPset Context information\n"
+       "IPset Name information\n")
+{
+       int idx = 0;
+       int found = 0;
+       found = argv_find(argv, argc, "WORD", &idx);
+       if (!found)
+               zebra_pbr_show_ipset_list(vty, NULL);
+       else
+               zebra_pbr_show_ipset_list(vty, argv[idx]->arg);
+       return CMD_SUCCESS;
+}
+
+/* policy routing contexts */
+DEFUN (show_pbr_iptable,
+       show_pbr_iptable_cmd,
+       "show pbr iptable",
+       SHOW_STR
+       "Policy-Based Routing\n"
+       "IPtable Context information\n")
+{
+       zebra_pbr_show_iptable(vty);
+       return CMD_SUCCESS;
+}
+
 /* Static ip route configuration write function. */
 static int zebra_ip_config(struct vty *vty)
 {
@@ -3762,6 +3794,9 @@ void zebra_vty_init(void)
        install_element(VIEW_NODE, &show_evpn_neigh_vni_neigh_cmd);
        install_element(VIEW_NODE, &show_evpn_neigh_vni_vtep_cmd);
 
+       install_element(VIEW_NODE, &show_pbr_ipset_cmd);
+       install_element(VIEW_NODE, &show_pbr_iptable_cmd);
+
        install_element(CONFIG_NODE, &default_vrf_vni_mapping_cmd);
        install_element(CONFIG_NODE, &no_default_vrf_vni_mapping_cmd);
        install_element(VRF_NODE, &vrf_vni_mapping_cmd);