]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge pull request #2475 from LabNConsulting/working/master/no_vrf_socket_4l3mdev
authorRuss White <russ@riw.us>
Mon, 2 Jul 2018 03:06:22 +0000 (23:06 -0400)
committerGitHub <noreply@github.com>
Mon, 2 Jul 2018 03:06:22 +0000 (23:06 -0400)
Don't open per vrf sockets when net.ipv4.tcp|udp_l3mdev_accept != 0

155 files changed:
babeld/babel_interface.c
babeld/message.c
babeld/neighbour.c
babeld/util.c
bgpd/bgp_aspath.c
bgpd/bgp_attr.c
bgpd/bgp_btoa.c
bgpd/bgp_clist.c
bgpd/bgp_evpn.c
bgpd/bgp_evpn_vty.c
bgpd/bgp_flowspec.c
bgpd/bgp_flowspec_util.c
bgpd/bgp_flowspec_util.h
bgpd/bgp_flowspec_vty.c
bgpd/bgp_fsm.c
bgpd/bgp_io.c
bgpd/bgp_mpath.c
bgpd/bgp_mplsvpn.c
bgpd/bgp_nexthop.c
bgpd/bgp_open.c
bgpd/bgp_packet.c
bgpd/bgp_pbr.c
bgpd/bgp_pbr.h
bgpd/bgp_rd.c
bgpd/bgp_route.c
bgpd/bgp_routemap.c
bgpd/bgp_rpki.c
bgpd/bgp_snmp.c
bgpd/bgp_updgrp.c
bgpd/bgp_updgrp_packet.c
bgpd/bgp_vpn.c
bgpd/bgp_vty.c
bgpd/bgp_zebra.c
bgpd/bgpd.c
bgpd/bgpd.h
bgpd/rfapi/bgp_rfapi_cfg.c
bgpd/rfapi/rfapi.c
bgpd/rfapi/rfapi_vty.c
doc/developer/workflow.rst
doc/user/basic.rst
doc/user/pbr.rst
doc/user/pim.rst
eigrpd/eigrp_fsm.c
eigrpd/eigrp_interface.c
eigrpd/eigrp_network.c
eigrpd/eigrp_packet.c
eigrpd/eigrp_snmp.c
eigrpd/eigrp_topology.c
eigrpd/eigrp_update.c
include/linux/netlink.h [new file with mode: 0644]
include/subdir.am
isisd/isis_adjacency.c
isisd/isis_circuit.c
isisd/isis_lsp.c
isisd/isis_pfpacket.c
isisd/isis_spf.c
isisd/isis_te.c
isisd/isisd.c
ldpd/ldp_debug.c
ldpd/ldp_vty_conf.c
ldpd/ldpd.c
ldpd/packet.c
lib/clippy.c
lib/command.c
lib/command.h
lib/command_match.c
lib/csv.c
lib/frr_pthread.c
lib/frr_zmq.c
lib/frrstr.c
lib/frrstr.h
lib/hash.c
lib/imsg.c
lib/libfrr.c
lib/libfrr.h
lib/linklist.c
lib/linklist.h
lib/pbr.h
lib/plist.c
lib/prefix.c
lib/prefix.h
lib/privs.c
lib/ptm_lib.c
lib/routemap.c
lib/routemap.h
lib/sbuf.c
lib/sigevent.c
lib/sockopt.c
lib/sockunion.c
lib/stream.c
lib/stream.h
lib/subdir.am
lib/thread.c
lib/vty.c
lib/vty.h
lib/zebra.h
nhrpd/resolver.c
nhrpd/vici.c
ospf6d/ospf6_abr.c
ospf6d/ospf6_asbr.c
ospf6d/ospf6_flood.c
ospf6d/ospf6_intra.c
ospf6d/ospf6_proto.c
ospf6d/ospf6_proto.h
ospf6d/ospf6_spf.c
ospfd/ospf_api.c
ospfd/ospf_apiserver.c
ospfd/ospf_ase.c
ospfd/ospf_dump.c
ospfd/ospf_interface.c
ospfd/ospf_packet.c
ospfd/ospf_ri.c
ospfd/ospf_route.c
ospfd/ospf_routemap.c
ospfd/ospf_snmp.c
ospfd/ospf_te.c
ospfd/ospf_vty.c
ospfd/ospf_zebra.c
ospfd/ospfd.c
pbrd/pbr_nht.c
pbrd/pbr_nht.h
pbrd/pbr_vty.c
pimd/mtracebis.c
pimd/pim_cmd.c
pimd/pim_igmp_mtrace.c
pimd/pim_oil.c
pimd/pim_pim.c
pimd/pim_routemap.c
pimd/pim_zebra.c
redhat/frr.spec.in
ripd/ripd.c
sharpd/sharp_main.c
tests/Makefile.am
tests/bgpd/test_peer_attr.c
tests/bgpd/test_peer_attr.py
tests/lib/test_checksum.c
tests/lib/test_graph.c
tests/lib/test_srcdest_table.c
tests/lib/test_timer_performance.c
tools/start-stop-daemon.c
vtysh/vtysh.c
zebra/if_netlink.c
zebra/interface.c
zebra/kernel_netlink.c
zebra/rt_netlink.c
zebra/rule_netlink.c
zebra/zapi_msg.c
zebra/zebra_netns_id.c
zebra/zebra_netns_notify.c
zebra/zebra_pbr.c
zebra/zebra_pbr.h
zebra/zebra_rib.c
zebra/zebra_routemap.c
zebra/zebra_vty.c
zebra/zserv.c

index d4958ddf249e35c15d56c7f108510c127492d5a8..453fd8e04e62732c59a085e81717c8d283e75121 100644 (file)
@@ -1001,7 +1001,7 @@ show_babel_routes_sub(struct babel_route *route, struct vty *vty,
                 break;
             if(k > 0)
                 channels[j++] = ',';
-            snprintf(channels + j, 100 - j, "%d", route->channels[k]);
+            snprintf(channels + j, 100 - j, "%u", route->channels[k]);
             j = strlen(channels);
         }
         snprintf(channels + j, 100 - j, ")");
index 1ff4867908cf19a134f291564d9fc112c3b3633e..95b4e87cc7e64b487a00aca8c5a3f96a754ade99 100644 (file)
@@ -662,7 +662,7 @@ static int
 check_bucket(struct interface *ifp)
 {
     babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
-    if(babel_ifp->bucket <= 0) {
+    if(babel_ifp->bucket == 0) {
         int seconds = babel_now.tv_sec - babel_ifp->bucket_time;
         if(seconds > 0) {
             babel_ifp->bucket = MIN(BUCKET_TOKENS_MAX,
index 48a32c4a9c39c658d86ee6564958475685ed20cf..3db121fd263ea9114cb84ffcdef7fe3b602790f5 100644 (file)
@@ -120,7 +120,7 @@ update_neighbour(struct neighbour *neigh, int hello, int hello_interval)
     int rc = 0;
 
     if(hello < 0) {
-        if(neigh->hello_interval <= 0)
+        if(neigh->hello_interval == 0)
             return rc;
         missed_hellos =
             ((int)timeval_minus_msec(&babel_now, &neigh->hello_time) -
index 7dff11d124bddce3b20226eab3a6b4ecb4d94604..4a3ecace0ccad0748ac8dca4463b93fa273586fc 100644 (file)
@@ -303,7 +303,7 @@ format_thousands(unsigned int value)
     static char buf[4][15];
     static int i = 0;
     i = (i + 1) % 4;
-    snprintf(buf[i], 15, "%d.%.3d", value / 1000, value % 1000);
+    snprintf(buf[i], 15, "%u.%.3u", value / 1000, value % 1000);
     return buf[i];
 }
 
index e02617691fa783a402fca224740a6ec51100e5c5..05e67baa8a83140277a6274568e1e755034eae4c 100644 (file)
@@ -1632,7 +1632,7 @@ struct aspath *aspath_reconcile_as4(struct aspath *aspath,
        struct aspath *newpath = NULL, *mergedpath;
        int hops, cpasns = 0;
 
-       if (!aspath)
+       if (!aspath || !as4path)
                return NULL;
 
        seg = aspath->segments;
index 2c52b57b36f8e7c370e57cc5336d0c42087e4389..6596e7cfa2643d1e4b650ecdeb4d5705d3762230 100644 (file)
@@ -1513,6 +1513,9 @@ bgp_attr_munge_as4_attrs(struct peer *const peer, struct attr *const attr,
        if (!ignore_as4_path
            && (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))) {
                newpath = aspath_reconcile_as4(attr->aspath, as4_path);
+               if (!newpath)
+                       return BGP_ATTR_PARSE_ERROR;
+
                aspath_unintern(&attr->aspath);
                attr->aspath = aspath_intern(newpath);
        }
index bf2607f2e7df26580ce0b316ed9e40f659dacf76..cc37e352ef9a96e536194fc224fbbefbacbb7dcd 100644 (file)
@@ -122,7 +122,7 @@ static int attr_parse(struct stream *s, uint16_t len)
 int main(int argc, char **argv)
 {
        int ret;
-       FILE *fp;
+       int fd;
        struct stream *s;
        time_t now;
        int type;
@@ -143,8 +143,8 @@ int main(int argc, char **argv)
                fprintf(stderr, "Usage: %s FILENAME\n", argv[0]);
                exit(1);
        }
-       fp = fopen(argv[1], "r");
-       if (!fp) {
+       fd = open(argv[1], O_RDONLY);
+       if (fd < 0) {
                fprintf(stdout,
                        "%% Can't open configuration file %s due to '%s'.\n",
                        argv[1], safe_strerror(errno));
@@ -154,13 +154,14 @@ int main(int argc, char **argv)
        while (1) {
                stream_reset(s);
 
-               ret = fread(s->data, 12, 1, fp);
-               if (!ret || feof(fp)) {
-                       printf("END OF FILE\n");
-                       break;
-               }
-               if (ferror(fp)) {
-                       printf("ERROR OF FREAD\n");
+               ret = stream_read(s, fd, 12);
+               if (ret != 12) {
+                       if (!ret)
+                               printf("END OF FILE\n");
+                       else if (ret < 0)
+                               printf("ERROR OF READ\n");
+                       else
+                               printf("UNDERFLOW\n");
                        break;
                }
 
@@ -217,13 +218,14 @@ int main(int argc, char **argv)
 
                printf("len: %zd\n", len);
 
-               fread(s->data + 12, len, 1, fp);
-               if (feof(fp)) {
-                       printf("ENDOF FILE 2\n");
-                       break;
-               }
-               if (ferror(fp)) {
-                       printf("ERROR OF FREAD 2\n");
+               ret = stream_read(s, fd, len);
+               if (ret != (int)len) {
+                       if (!ret)
+                               printf("END OF FILE 2\n");
+                       else if (ret < 0)
+                               printf("ERROR OF READ 2\n");
+                       else
+                               printf("UNDERFLOW 2\n");
                        break;
                }
 
@@ -284,6 +286,6 @@ int main(int argc, char **argv)
                        printf("\n");
                }
        }
-       fclose(fp);
+       close(fd);
        return 0;
 }
index 7cf14775496cdb2bb6e8f0cc9eb04f2c5bb20b31..0ffbe174ed9d609579c4201684cc55cf53ada050 100644 (file)
@@ -1054,6 +1054,9 @@ int extcommunity_list_set(struct community_list_handler *ch, const char *name,
        struct ecommunity *ecom = NULL;
        regex_t *regex = NULL;
 
+       if (str == NULL)
+               return COMMUNITY_LIST_ERR_MALFORMED_VAL;
+
        entry = NULL;
 
        /* Get community list. */
@@ -1089,7 +1092,7 @@ int extcommunity_list_set(struct community_list_handler *ch, const char *name,
        entry = community_entry_new();
        entry->direct = direct;
        entry->style = style;
-       entry->any = (str ? 0 : 1);
+       entry->any = 0;
        if (ecom)
                entry->config = ecommunity_ecom2str(
                        ecom, ECOMMUNITY_FORMAT_COMMUNITY_LIST, 0);
index 0557bbcce9a59efd3e55a2ad9037f4b1426e49b5..959418658c9587ae8be1afcb8bcbd0ac9a1992ef 100644 (file)
@@ -4242,8 +4242,9 @@ void bgp_evpn_unconfigure_import_rt_for_vrf(struct bgp *bgp_vrf,
        if (node_to_del)
                list_delete_node(bgp_vrf->vrf_import_rtl, node_to_del);
 
+       assert(bgp_vrf->vrf_import_rtl);
        /* fallback to auto import rt, if this was the last RT */
-       if (list_isempty(bgp_vrf->vrf_import_rtl)) {
+       if (bgp_vrf->vrf_import_rtl && list_isempty(bgp_vrf->vrf_import_rtl)) {
                UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_RT_CFGD);
                evpn_auto_rt_import_add_for_vrf(bgp_vrf);
        }
index 8556a325bb1bd953e81cf79273c34dec66a7814c..5a4ebc9b173529f48279ae1a68b986b653841828 100644 (file)
@@ -52,7 +52,6 @@ struct vni_walk_ctx {
        json_object *json;
 };
 
-#if defined(HAVE_CUMULUS)
 static void display_vrf_import_rt(struct vty *vty, struct vrf_irt_node *irt,
                                  json_object *json)
 {
@@ -245,7 +244,7 @@ static void display_import_rt(struct vty *vty, struct irt_node *irt,
        for (ALL_LIST_ELEMENTS(irt->vnis, node, nnode, tmp_vpn)) {
                if (json)
                        json_object_array_add(
-                               json_vnis, json_object_new_int64(tmp_vpn->vni));
+                               json_vnis, json_object_new_int(tmp_vpn->vni));
                else
                        vty_out(vty, "  %u\n", tmp_vpn->vni);
        }
@@ -980,7 +979,6 @@ static void show_vni_entry(struct hash_backet *backet, void *args[])
                vty_out(vty, "\n");
        }
 }
-#endif /* HAVE_CUMULUS */
 
 static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd,
                                 enum bgp_show_type type, void *output_arg,
@@ -1636,8 +1634,6 @@ DEFUN(no_evpnrt5_network,
                argv[idx_gwip]->arg, argv[idx_ethtag]->arg);
 }
 
-#if defined(HAVE_CUMULUS)
-
 static void evpn_import_rt_delete_auto(struct bgp *bgp, struct bgpevpn *vpn)
 {
        evpn_rt_delete_auto(bgp, vpn->vni, vpn->import_rtl);
@@ -1721,6 +1717,7 @@ static void evpn_unconfigure_import_rt(struct bgp *bgp, struct bgpevpn *vpn,
                        list_delete_node(vpn->import_rtl, node_to_del);
        }
 
+       assert(vpn->import_rtl);
        /* Reset to auto RT - this also rebuilds the RT to VNI mapping */
        if (list_isempty(vpn->import_rtl)) {
                UNSET_FLAG(vpn->flags, VNI_FLAG_IMPRT_CFGD);
@@ -1788,6 +1785,7 @@ static void evpn_unconfigure_export_rt(struct bgp *bgp, struct bgpevpn *vpn,
                        list_delete_node(vpn->export_rtl, node_to_del);
        }
 
+       assert(vpn->export_rtl);
        if (list_isempty(vpn->export_rtl)) {
                UNSET_FLAG(vpn->flags, VNI_FLAG_EXPRT_CFGD);
                bgp_evpn_derive_auto_rt_export(bgp, vpn);
@@ -1829,6 +1827,7 @@ static void evpn_unconfigure_vrf_rd(struct bgp *bgp_vrf)
 
        /* fall back to default RD */
        bgp_evpn_derive_auto_rd_for_vrf(bgp_vrf);
+       UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_RD_CFGD);
 
        /* We have a new RD for VRF.
         * Advertise all type-5 routes again with the new RD
@@ -2751,7 +2750,6 @@ static void evpn_unset_advertise_autort_rfc8365(struct bgp *bgp)
        bgp->advertise_autort_rfc8365 = 0;
        bgp_evpn_handle_autort_change(bgp);
 }
-#endif /* HAVE_CUMULUS */
 
 static void write_vni_config(struct vty *vty, struct bgpevpn *vpn)
 {
@@ -2798,7 +2796,6 @@ static void write_vni_config(struct vty *vty, struct bgpevpn *vpn)
        }
 }
 
-#if defined(HAVE_CUMULUS)
 DEFUN (bgp_evpn_advertise_default_gw_vni,
        bgp_evpn_advertise_default_gw_vni_cmd,
        "advertise-default-gw",
@@ -3261,10 +3258,11 @@ DEFUN(show_bgp_l2vpn_evpn_es,
 {
        int idx = 0;
        uint8_t uj = 0;
-       esi_t esi = {0};
+       esi_t esi;
        json_object *json = NULL;
        struct bgp *bgp = NULL;
 
+       memset(&esi, 0, sizeof(esi));
        uj = use_json(argc, argv);
 
        bgp = bgp_get_default();
@@ -3546,10 +3544,11 @@ DEFUN(show_bgp_l2vpn_evpn_route_esi,
       JSON_STR)
 {
        int uj = 0;
-       esi_t esi = {0};
+       esi_t esi;
        struct bgp *bgp = NULL;
        json_object *json = NULL;
 
+       memset(&esi, 0, sizeof(esi));
        bgp = bgp_get_default();
        if (!bgp)
                return CMD_WARNING;
@@ -3903,7 +3902,6 @@ DEFUN(show_bgp_l2vpn_evpn_import_rt,
        return CMD_SUCCESS;
 }
 
-#if defined(HAVE_CUMULUS)
 DEFUN(test_adv_evpn_type4_route,
       test_adv_evpn_type4_route_cmd,
       "advertise es ESI",
@@ -4063,7 +4061,6 @@ ALIAS_HIDDEN(show_bgp_l2vpn_evpn_route_vni_all, show_bgp_evpn_route_vni_all_cmd,
 ALIAS_HIDDEN(show_bgp_l2vpn_evpn_import_rt, show_bgp_evpn_import_rt_cmd,
             "show bgp evpn import-rt",
             SHOW_STR BGP_STR EVPN_HELP_STR "Show import route target\n")
-#endif
 
 DEFUN_NOSH (bgp_evpn_vni,
             bgp_evpn_vni_cmd,
@@ -4840,7 +4837,6 @@ DEFUN (no_bgp_evpn_vni_rt_without_val,
                evpn_unconfigure_export_rt(bgp, vpn, NULL);
        return CMD_SUCCESS;
 }
-#endif
 
 static int vni_cmp(const void **a, const void **b)
 {
@@ -4960,7 +4956,6 @@ void bgp_ethernetvpn_init(void)
        install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_all_overlay_cmd);
        install_element(BGP_EVPN_NODE, &no_evpnrt5_network_cmd);
        install_element(BGP_EVPN_NODE, &evpnrt5_network_cmd);
-#if defined(HAVE_CUMULUS)
        install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_all_vni_cmd);
        install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_all_vni_cmd);
        install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_autort_rfc8365_cmd);
@@ -5026,5 +5021,4 @@ void bgp_ethernetvpn_init(void)
        install_element(BGP_EVPN_VNI_NODE, &bgp_evpn_advertise_vni_subnet_cmd);
        install_element(BGP_EVPN_VNI_NODE,
                        &no_bgp_evpn_advertise_vni_subnet_cmd);
-#endif
 }
index 884c5aa51a182aab9ae5360a027b7bb4b810ba63..9b998d4497f9031c81362ff3acdb98ffab103bf6 100644 (file)
@@ -59,7 +59,8 @@ static int bgp_fs_nlri_validate(uint8_t *nlri_content, uint32_t len)
                                                   len - offset, NULL, &error);
                        break;
                case FLOWSPEC_TCP_FLAGS:
-                       ret = bgp_flowspec_tcpflags_decode(
+               case FLOWSPEC_FRAGMENT:
+                       ret = bgp_flowspec_bitmask_decode(
                                                   BGP_FLOWSPEC_VALIDATE_ONLY,
                                                   nlri_content + offset,
                                                   len - offset, NULL, &error);
@@ -71,12 +72,6 @@ static int bgp_fs_nlri_validate(uint8_t *nlri_content, uint32_t len)
                                                nlri_content + offset,
                                                len - offset, NULL, &error);
                        break;
-               case FLOWSPEC_FRAGMENT:
-                       ret = bgp_flowspec_fragment_type_decode(
-                                               BGP_FLOWSPEC_VALIDATE_ONLY,
-                                               nlri_content + offset,
-                                               len - offset, NULL, &error);
-                       break;
                default:
                        error = -1;
                        break;
index 956cf28c211dfc2df74f0a0bada96ccaac4acad3..1b874276613c2a32150578c30a3a173761e2cbff 100644 (file)
@@ -124,8 +124,9 @@ static bool bgp_flowspec_contains_prefix(struct prefix *pfs,
                                                     len - offset,
                                                     NULL, &error);
                        break;
+               case FLOWSPEC_FRAGMENT:
                case FLOWSPEC_TCP_FLAGS:
-                       ret = bgp_flowspec_tcpflags_decode(
+                       ret = bgp_flowspec_bitmask_decode(
                                                BGP_FLOWSPEC_VALIDATE_ONLY,
                                                nlri_content+offset,
                                                len - offset,
@@ -139,13 +140,6 @@ static bool bgp_flowspec_contains_prefix(struct prefix *pfs,
                                                len - offset, NULL,
                                                &error);
                        break;
-               case FLOWSPEC_FRAGMENT:
-                       ret = bgp_flowspec_fragment_type_decode(
-                                               BGP_FLOWSPEC_VALIDATE_ONLY,
-                                               nlri_content + offset,
-                                               len - offset, NULL,
-                                               &error);
-                       break;
                default:
                        error = -1;
                        break;
@@ -312,14 +306,14 @@ int bgp_flowspec_op_decode(enum bgp_flowspec_util_nlri_t type,
 
 
 /*
- * handle the flowspec tcpflags field
+ * handle the flowspec tcpflags or fragment field
  * return number of bytes analysed
  * if there is an error, the passed error param is used to give error:
  * -1 if decoding error,
  * if result is a string, its assumed length
  *  is BGP_FLOWSPEC_STRING_DISPLAY_MAX
  */
-int bgp_flowspec_tcpflags_decode(enum bgp_flowspec_util_nlri_t type,
+int bgp_flowspec_bitmask_decode(enum bgp_flowspec_util_nlri_t type,
                                 uint8_t *nlri_ptr,
                                 uint32_t max_len,
                                 void *result, int *error)
@@ -348,32 +342,33 @@ int bgp_flowspec_tcpflags_decode(enum bgp_flowspec_util_nlri_t type,
                case BGP_FLOWSPEC_RETURN_STRING:
                        if (op[1] == 1 && loop != 0) {
                                len_written = snprintf(ptr, len_string,
-                                                      ", and ");
+                                                      ",&");
                                len_string -= len_written;
                                ptr += len_written;
                        } else if (op[1] == 0 && loop != 0) {
                                len_written = snprintf(ptr, len_string,
-                                                     ", or ");
+                                                     ",|");
                                len_string -= len_written;
                                ptr += len_written;
                        }
-                       len_written = snprintf(ptr, len_string,
-                                              "tcp flags is ");
-                       len_string -= len_written;
-                       ptr += len_written;
-                       if (op[6] == 1) {
-                               ptr += snprintf(ptr, len_string,
-                                              "not ");
+                       if (op[7] == 1) {
+                               len_written = snprintf(ptr, len_string,
+                                              "= ");
+                               len_string -= len_written;
+                               ptr += len_written;
+                       } else {
+                               len_written = snprintf(ptr, len_string,
+                                                      "∋ ");
                                len_string -= len_written;
                                ptr += len_written;
                        }
-                       if (op[7] == 1) {
-                               ptr += snprintf(ptr, len_string,
-                                              "exactly match ");
+                       if (op[6] == 1) {
+                               len_written = snprintf(ptr, len_string,
+                                              "! ");
                                len_string -= len_written;
                                ptr += len_written;
                        }
-                       ptr += snprintf(ptr, len_string,
+                       len_written = snprintf(ptr, len_string,
                                       "%d", value);
                        len_string -= len_written;
                        ptr += len_written;
@@ -419,92 +414,6 @@ int bgp_flowspec_tcpflags_decode(enum bgp_flowspec_util_nlri_t type,
        return offset;
 }
 
-/*
- * handle the flowspec fragment type field
- * return error (returned values are invalid) or number of bytes analysed
- * -1 if error in decoding
- * >= 0 : number of bytes analysed (ok).
- */
-int bgp_flowspec_fragment_type_decode(enum bgp_flowspec_util_nlri_t type,
-                                     uint8_t *nlri_ptr,
-                                     uint32_t max_len,
-                                     void *result, int *error)
-{
-       int op[8];
-       int len, value, value_size, loop = 0;
-       char *ptr = (char *)result; /* for return_string */
-       struct bgp_pbr_fragment_val *mval =
-               (struct bgp_pbr_fragment_val *)result;
-       uint32_t offset = 0;
-       int len_string = BGP_FLOWSPEC_STRING_DISPLAY_MAX;
-       int len_written;
-
-       *error = 0;
-       do {
-               hex2bin(&nlri_ptr[offset], op);
-               offset++;
-               len = 2 * op[2] + op[3];
-               value_size = 1 << len;
-               value = hexstr2num(&nlri_ptr[offset], value_size);
-               if (value != 1 && value != 2 && value != 4 && value != 8)
-                       *error = -1;
-               offset += value_size;
-               /* TODO : as per RFC5574 : first Fragment bits are Reserved
-                * does that mean that it is not possible
-                * to handle multiple occurences ?
-                * as of today, we only grab the first TCP fragment
-                */
-               if (loop) {
-                       *error = -2;
-                       loop++;
-                       continue;
-               }
-               switch (type) {
-               case BGP_FLOWSPEC_RETURN_STRING:
-                       switch (value) {
-                       case 1:
-                               len_written = snprintf(ptr, len_string,
-                                                      "dont-fragment");
-                               len_string -= len_written;
-                               ptr += len_written;
-                               break;
-                       case 2:
-                               len_written = snprintf(ptr, len_string,
-                                                     "is-fragment");
-                               len_string -= len_written;
-                               ptr += len_written;
-                               break;
-                       case 4:
-                               len_written = snprintf(ptr, len_string,
-                                                      "first-fragment");
-                               len_string -= len_written;
-                               ptr += len_written;
-                               break;
-                       case 8:
-                               len_written = snprintf(ptr, len_string,
-                                                      "last-fragment");
-                               len_string -= len_written;
-                               ptr += len_written;
-                               break;
-                       default:
-                               {}
-                       }
-                       break;
-               case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE:
-                       mval->bitmask = (uint8_t)value;
-                       break;
-               case BGP_FLOWSPEC_VALIDATE_ONLY:
-               default:
-                       /* no action */
-                       break;
-               }
-               loop++;
-       } while (op[0] == 0 && offset < max_len - 1);
-       if (offset > max_len)
-               *error = -1;
-       return offset;
-}
-
 int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
                                  struct bgp_pbr_entry_main *bpem)
 {
@@ -623,7 +532,7 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
                                                        &error);
                        break;
                case FLOWSPEC_TCP_FLAGS:
-                       ret = bgp_flowspec_tcpflags_decode(
+                       ret = bgp_flowspec_bitmask_decode(
                                        BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE,
                                        nlri_content + offset,
                                        len - offset,
@@ -637,7 +546,7 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
                        offset += ret;
                        break;
                case FLOWSPEC_FRAGMENT:
-                       ret = bgp_flowspec_fragment_type_decode(
+                       ret = bgp_flowspec_bitmask_decode(
                                        BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE,
                                        nlri_content + offset,
                                        len - offset, &bpem->fragment,
@@ -646,7 +555,7 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
                                zlog_err("%s: flowspec_fragment_type_decode error %d",
                                         __func__, error);
                        else
-                               bpem->match_bitmask |= FRAGMENT_PRESENT;
+                               bpem->match_fragment_num = error;
                        offset += ret;
                        break;
                default:
index e4454ab4dba3fe87876ab40def2a74a8cf1abb98..2d16e57a36fdc9de6dd09fc2e5cb98797488687b 100644 (file)
@@ -41,15 +41,11 @@ extern int bgp_flowspec_ip_address(enum bgp_flowspec_util_nlri_t type,
                                   uint32_t max_len,
                                   void *result, int *error);
 
-extern int bgp_flowspec_tcpflags_decode(enum bgp_flowspec_util_nlri_t type,
+extern int bgp_flowspec_bitmask_decode(enum bgp_flowspec_util_nlri_t type,
                                        uint8_t *nlri_ptr,
                                        uint32_t max_len,
                                        void *result, int *error);
 
-extern int bgp_flowspec_fragment_type_decode(enum bgp_flowspec_util_nlri_t type,
-                                            uint8_t *nlri_ptr,
-                                            uint32_t max_len,
-                                            void *result, int *error);
 struct bgp_pbr_entry_main;
 extern int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
                                         struct bgp_pbr_entry_main *bpem);
index b21e5ae0dcc4b2284c510c91dee3af34868d0d1c..90acd8fcb16f48beb0f07ac2436dae0eacd5c4d2 100644 (file)
@@ -62,7 +62,7 @@ static const struct message bgp_flowspec_display_min[] = {
        {FLOWSPEC_SRC_PORT, "srcp"},
        {FLOWSPEC_ICMP_TYPE, "type"},
        {FLOWSPEC_ICMP_CODE, "code"},
-       {FLOWSPEC_TCP_FLAGS, "flags"},
+       {FLOWSPEC_TCP_FLAGS, "tcp"},
        {FLOWSPEC_PKT_LEN, "pktlen"},
        {FLOWSPEC_DSCP, "dscp"},
        {FLOWSPEC_FRAGMENT, "pktfrag"},
@@ -173,7 +173,7 @@ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len,
                        ptr += len_written;
                        break;
                case FLOWSPEC_TCP_FLAGS:
-                       ret = bgp_flowspec_tcpflags_decode(
+                       ret = bgp_flowspec_bitmask_decode(
                                              type_util,
                                              nlri_content+offset,
                                              len - offset,
@@ -221,11 +221,11 @@ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len,
                        ptr += len_written;
                        break;
                case FLOWSPEC_FRAGMENT:
-                       ret = bgp_flowspec_fragment_type_decode(
-                                               type_util,
-                                               nlri_content + offset,
-                                               len - offset, local_string,
-                                               &error);
+                       ret = bgp_flowspec_bitmask_decode(
+                                             type_util,
+                                             nlri_content+offset,
+                                             len - offset,
+                                             local_string, &error);
                        if (ret <= 0)
                                break;
                        if (json_path) {
index 3f5ff12cbc0306c19f86d983f8cda55d55401a24..2fd63531db757d42f7c76906583e251e78758f0d 100644 (file)
@@ -194,7 +194,6 @@ static struct peer *peer_xfer_conn(struct peer *from_peer)
        peer->as = from_peer->as;
        peer->v_holdtime = from_peer->v_holdtime;
        peer->v_keepalive = from_peer->v_keepalive;
-       peer->routeadv = from_peer->routeadv;
        peer->v_routeadv = from_peer->v_routeadv;
        peer->v_gr_restart = from_peer->v_gr_restart;
        peer->cap = from_peer->cap;
@@ -1144,7 +1143,7 @@ int bgp_stop(struct peer *peer)
        }
 
        /* Reset keepalive and holdtime */
-       if (PEER_OR_GROUP_TIMER_SET(peer)) {
+       if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER)) {
                peer->v_keepalive = peer->keepalive;
                peer->v_holdtime = peer->holdtime;
        } else {
index 69c92e829c59ce6174a792ee08df89470cd6e6b6..c8d5b1daa121a3ed51817f242e0dc53fde9fc21e 100644 (file)
@@ -174,7 +174,6 @@ static int bgp_process_reads(struct thread *thread)
        bool more = true;               // whether we got more data
        bool fatal = false;             // whether fatal error occurred
        bool added_pkt = false;         // whether we pushed onto ->ibuf
-       bool header_valid = true;       // whether header is valid
        /* clang-format on */
 
        peer = THREAD_ARG(thread);
@@ -214,10 +213,8 @@ static int bgp_process_reads(struct thread *thread)
                if (ringbuf_remain(ibw) < BGP_HEADER_SIZE)
                        break;
 
-               /* validate header */
-               header_valid = validate_header(peer);
-
-               if (!header_valid) {
+               /* check that header is valid */
+               if (!validate_header(peer)) {
                        fatal = true;
                        break;
                }
index 915387ca2defc86c42030743f8686fcb9c847fd7..333d09806e29af2c56a8a0f128d4d016ed3357af 100644 (file)
@@ -471,7 +471,7 @@ void bgp_info_mpath_update(struct bgp_node *rn, struct bgp_info *new_best,
                zlog_debug(
                        "%s: starting mpath update, newbest %s num candidates %d old-mpath-count %d",
                        pfx_buf, new_best ? new_best->peer->host : "NONE",
-                       listcount(mp_list), old_mpath_count);
+                       mp_list ? listcount(mp_list) : 0, old_mpath_count);
 
        /*
         * We perform an ordered walk through both lists in parallel.
index eef711aa59bf907b1be46e9345a9b250756753ec..3a854be534bf39ff17534db70e3213d91be5ae44 100644 (file)
@@ -466,6 +466,7 @@ leak_update(
 {
        struct prefix *p = &bn->p;
        struct bgp_info *bi;
+       struct bgp_info *bi_ultimate;
        struct bgp_info *new;
        char buf_prefix[PREFIX_STRLEN];
 
@@ -476,6 +477,26 @@ leak_update(
                        source_bi->type, source_bi->sub_type);
        }
 
+       /*
+        * Routes that are redistributed into BGP from zebra do not get
+        * nexthop tracking. However, if those routes are subsequently
+        * imported to other RIBs within BGP, the leaked routes do not
+        * carry the original BGP_ROUTE_REDISTRIBUTE sub_type. Therefore,
+        * in order to determine if the route we are currently leaking
+        * should have nexthop tracking, we must find the ultimate
+        * parent so we can check its sub_type.
+        *
+        * As of now, source_bi may at most be a second-generation route
+        * (only one hop back to ultimate parent for vrf-vpn-vrf scheme).
+        * Using a loop here supports more complex intra-bgp import-export
+        * schemes that could be implemented in the future.
+        * 
+        */
+       for (bi_ultimate = source_bi;
+               bi_ultimate->extra && bi_ultimate->extra->parent;
+               bi_ultimate = bi_ultimate->extra->parent)
+                       ;
+
        /*
         * match parent
         */
@@ -528,7 +549,7 @@ leak_update(
                        bgp_nexthop = bi->extra->bgp_orig;
 
                /* No nexthop tracking for redistributed routes */
-               if (source_bi->sub_type == BGP_ROUTE_REDISTRIBUTE)
+               if (bi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE)
                        nh_valid = 1;
                else
                        /*
@@ -591,7 +612,7 @@ leak_update(
         * their originating protocols will do the tracking and
         * withdraw those routes if the nexthops become unreachable
         */
-       if (source_bi->sub_type == BGP_ROUTE_REDISTRIBUTE)
+       if (bi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE)
                nh_valid = 1;
        else
                /*
@@ -1335,6 +1356,9 @@ void vpn_leak_to_vrf_update_all(struct bgp *bgp_vrf, /* to */
        struct bgp_node *prn;
        safi_t safi = SAFI_MPLS_VPN;
 
+       if (!bgp_vpn)
+               return;
+
        /*
         * Walk vpn table
         */
index fd8d894878a55aa277a2cfbf177bcba85efbd2a9..32011d210ba29f02e3806e7ec9ddd3c5e3da7f9a 100644 (file)
@@ -438,7 +438,7 @@ int bgp_subgrp_multiaccess_check_v4(struct in_addr nexthop,
        struct bgp_node *rn1, *rn2;
        struct peer_af *paf;
        struct prefix p, np;
-       struct bgp *bgp = NULL;
+       struct bgp *bgp;
 
        np.family = AF_INET;
        np.prefixlen = IPV4_MAX_BITLEN;
@@ -447,7 +447,7 @@ int bgp_subgrp_multiaccess_check_v4(struct in_addr nexthop,
        p.family = AF_INET;
        p.prefixlen = IPV4_MAX_BITLEN;
 
-       rn1 = rn2 = NULL;
+       rn2 = NULL;
 
        bgp = SUBGRP_INST(subgrp);
        rn1 = bgp_node_match(bgp->connected_table[AFI_IP], &np);
index aa98f8a55726423371b215cc2f7f34339537549f..da90bbd67dad6591b5747da3c1696948dee160ab 100644 (file)
@@ -80,8 +80,9 @@ void bgp_capability_vty_out(struct vty *vty, struct peer *peer,
                        afi_t afi;
                        safi_t safi;
 
-                       bgp_map_afi_safi_iana2int(ntohs(mpc.afi), mpc.safi,
-                                                 &afi, &safi);
+                       (void)bgp_map_afi_safi_iana2int(ntohs(mpc.afi),
+                                                       mpc.safi, &afi, &safi);
+
                        if (use_json) {
                                switch (afi) {
                                case AFI_IP:
index 9ea2f22cec15c9ea0285abc54b7e79f218576963..446dc5ac1254dece034006922c2d0afac5e6d719 100644 (file)
@@ -503,7 +503,7 @@ void bgp_open_send(struct peer *peer)
        uint16_t send_holdtime;
        as_t local_as;
 
-       if (PEER_OR_GROUP_TIMER_SET(peer))
+       if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER))
                send_holdtime = peer->holdtime;
        else
                send_holdtime = peer->bgp->default_holdtime;
@@ -1237,7 +1237,7 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size)
           implementation MAY adjust the rate at which it sends KEEPALIVE
           messages as a function of the Hold Time interval. */
 
-       if (PEER_OR_GROUP_TIMER_SET(peer))
+       if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER))
                send_holdtime = peer->holdtime;
        else
                send_holdtime = peer->bgp->default_holdtime;
@@ -1247,7 +1247,7 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size)
        else
                peer->v_holdtime = send_holdtime;
 
-       if ((PEER_OR_GROUP_TIMER_SET(peer))
+       if ((CHECK_FLAG(peer->flags, PEER_FLAG_TIMER))
            && (peer->keepalive < peer->v_holdtime / 3))
                peer->v_keepalive = peer->keepalive;
        else
index 5e36f9175048eb6d1a332ea8370ad0fd77576c65..45ec21631c0f2fcb6113ed1f273b52b4d4b614ef 100644 (file)
@@ -21,6 +21,7 @@
 #include "prefix.h"
 #include "zclient.h"
 #include "jhash.h"
+#include "pbr.h"
 
 #include "bgpd/bgpd.h"
 #include "bgpd/bgp_pbr.h"
 #include "bgpd/bgp_attr.h"
 #include "bgpd/bgp_zebra.h"
 #include "bgpd/bgp_mplsvpn.h"
+#include "bgpd/bgp_flowspec_private.h"
 
 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")
+DEFINE_MTYPE_STATIC(BGPD, PBR_VALMASK, "BGP PBR Val Mask Value")
 
 RB_GENERATE(bgp_pbr_interface_head, bgp_pbr_interface,
            id_entry, bgp_pbr_interface_compare);
@@ -175,11 +178,220 @@ static int sprintf_bgp_pbr_match_val(char *str, struct bgp_pbr_match_val *mval,
                _cnt++; \
        } while (0)
 
+/* this structure can be used for port range,
+ * but also for other values range like packet length range
+ */
 struct bgp_pbr_range_port {
        uint16_t min_port;
        uint16_t max_port;
 };
 
+/* this structure can be used to filter with a mask
+ * for instance it supports not instructions like for
+ * tcpflags
+ */
+struct bgp_pbr_val_mask {
+       uint16_t val;
+       uint16_t mask;
+};
+
+/* this structure is used to pass instructs
+ * so that BGP can create pbr instructions to ZEBRA
+ */
+struct bgp_pbr_filter {
+       vrf_id_t vrf_id;
+       struct prefix *src;
+       struct prefix *dst;
+       uint8_t protocol;
+       struct bgp_pbr_range_port *pkt_len;
+       struct bgp_pbr_range_port *src_port;
+       struct bgp_pbr_range_port *dst_port;
+       struct bgp_pbr_val_mask *tcp_flags;
+       struct bgp_pbr_val_mask *dscp;
+       struct bgp_pbr_val_mask *pkt_len_val;
+       struct bgp_pbr_val_mask *fragment;
+};
+
+/* this structure is used to contain OR instructions
+ * so that BGP can create multiple pbr instructions
+ * to ZEBRA
+ */
+struct bgp_pbr_or_filter {
+       struct list *tcpflags;
+       struct list *dscp;
+       struct list *pkt_len;
+       struct list *fragment;
+       struct list *icmp_type;
+       struct list *icmp_code;
+};
+
+static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp,
+                                                 struct bgp_info *binfo,
+                                                 struct bgp_pbr_filter *bpf,
+                                                 struct nexthop *nh,
+                                                 float *rate);
+
+static bool bgp_pbr_extract_enumerate_unary_opposite(
+                                uint8_t unary_operator,
+                                struct bgp_pbr_val_mask *and_valmask,
+                                struct list *or_valmask, uint32_t value,
+                                uint8_t type_entry)
+{
+       if (unary_operator == OPERATOR_UNARY_AND && and_valmask) {
+               if (type_entry == FLOWSPEC_TCP_FLAGS) {
+                       and_valmask->mask |=
+                               TCP_HEADER_ALL_FLAGS &
+                               ~(value);
+               } else if (type_entry == FLOWSPEC_DSCP ||
+                          type_entry == FLOWSPEC_PKT_LEN ||
+                          type_entry == FLOWSPEC_FRAGMENT) {
+                       and_valmask->val = value;
+                       and_valmask->mask = 1; /* inverse */
+               }
+       } else if (unary_operator == OPERATOR_UNARY_OR && or_valmask) {
+               and_valmask = XCALLOC(MTYPE_PBR_VALMASK,
+                                     sizeof(struct bgp_pbr_val_mask));
+               if (type_entry == FLOWSPEC_TCP_FLAGS) {
+                       and_valmask->val = TCP_HEADER_ALL_FLAGS;
+                       and_valmask->mask |=
+                               TCP_HEADER_ALL_FLAGS &
+                               ~(value);
+               } else if (type_entry == FLOWSPEC_DSCP ||
+                          type_entry == FLOWSPEC_FRAGMENT ||
+                          type_entry == FLOWSPEC_PKT_LEN) {
+                       and_valmask->val = value;
+                       and_valmask->mask = 1; /* inverse */
+               }
+               listnode_add(or_valmask, and_valmask);
+       } else if (type_entry == FLOWSPEC_ICMP_CODE ||
+                  type_entry == FLOWSPEC_ICMP_TYPE)
+               return false;
+       return true;
+}
+
+/* TCP : FIN and SYN -> val = ALL; mask = 3
+ * TCP : not (FIN and SYN) -> val = ALL; mask = ALL & ~(FIN|RST)
+ * other variables type: dscp, pkt len, fragment
+ * - value is copied in bgp_pbr_val_mask->val value
+ * - if negate form is identifierd, bgp_pbr_val_mask->mask set to 1
+ */
+static bool bgp_pbr_extract_enumerate_unary(struct bgp_pbr_match_val list[],
+                                           int num, uint8_t unary_operator,
+                                           void *valmask, uint8_t type_entry)
+{
+       int i = 0;
+       struct bgp_pbr_val_mask *and_valmask = NULL;
+       struct list *or_valmask = NULL;
+       bool ret;
+
+       if (valmask) {
+               if (unary_operator == OPERATOR_UNARY_AND) {
+                       and_valmask = (struct bgp_pbr_val_mask *)valmask;
+                       memset(and_valmask, 0, sizeof(struct bgp_pbr_val_mask));
+               } else if (unary_operator == OPERATOR_UNARY_OR) {
+                       or_valmask = (struct list *)valmask;
+               }
+       }
+       for (i = 0; i < num; i++) {
+               if (i != 0 && list[i].unary_operator !=
+                   unary_operator)
+                       return false;
+               if (!(list[i].compare_operator &
+                   OPERATOR_COMPARE_EQUAL_TO) &&
+                   !(list[i].compare_operator &
+                     OPERATOR_COMPARE_EXACT_MATCH)) {
+                       if ((list[i].compare_operator &
+                            OPERATOR_COMPARE_LESS_THAN) &&
+                           (list[i].compare_operator &
+                            OPERATOR_COMPARE_GREATER_THAN)) {
+                               ret = bgp_pbr_extract_enumerate_unary_opposite(
+                                                unary_operator, and_valmask,
+                                                or_valmask, list[i].value,
+                                                type_entry);
+                               if (ret == false)
+                                       return ret;
+                               continue;
+                       }
+                       return false;
+               }
+               if (unary_operator == OPERATOR_UNARY_AND && and_valmask) {
+                       if (type_entry == FLOWSPEC_TCP_FLAGS)
+                               and_valmask->mask |=
+                                       TCP_HEADER_ALL_FLAGS & list[i].value;
+               } else if (unary_operator == OPERATOR_UNARY_OR && or_valmask) {
+                       and_valmask = XCALLOC(MTYPE_PBR_VALMASK,
+                                             sizeof(struct bgp_pbr_val_mask));
+                       if (type_entry == FLOWSPEC_TCP_FLAGS) {
+                               and_valmask->val = TCP_HEADER_ALL_FLAGS;
+                               and_valmask->mask |=
+                                       TCP_HEADER_ALL_FLAGS & list[i].value;
+                       } else if (type_entry == FLOWSPEC_DSCP ||
+                                  type_entry == FLOWSPEC_ICMP_TYPE ||
+                                  type_entry == FLOWSPEC_ICMP_CODE ||
+                                  type_entry == FLOWSPEC_FRAGMENT ||
+                                  type_entry == FLOWSPEC_PKT_LEN)
+                               and_valmask->val = list[i].value;
+                       listnode_add(or_valmask, and_valmask);
+               }
+       }
+       if (unary_operator == OPERATOR_UNARY_AND && and_valmask
+           && type_entry == FLOWSPEC_TCP_FLAGS)
+               and_valmask->val = TCP_HEADER_ALL_FLAGS;
+       return true;
+}
+
+/* if unary operator can either be UNARY_OR/AND/OR-AND.
+ * in the latter case, combinationf of both is not handled
+ */
+static bool bgp_pbr_extract_enumerate(struct bgp_pbr_match_val list[],
+                                     int num, uint8_t unary_operator,
+                                     void *valmask, uint8_t type_entry)
+{
+       bool ret;
+       uint8_t unary_operator_val = unary_operator;
+       bool double_check = false;
+
+       if ((unary_operator & OPERATOR_UNARY_OR) &&
+           (unary_operator & OPERATOR_UNARY_AND)) {
+               unary_operator_val = OPERATOR_UNARY_AND;
+               double_check = true;
+       } else
+               unary_operator_val = unary_operator;
+       ret = bgp_pbr_extract_enumerate_unary(list, num, unary_operator_val,
+                                             valmask, type_entry);
+       if (!ret && double_check)
+               ret = bgp_pbr_extract_enumerate_unary(list, num,
+                                                     OPERATOR_UNARY_OR,
+                                                     valmask,
+                                                     type_entry);
+       return ret;
+}
+
+/* returns the unary operator that is in the list
+ * return 0 if both operators are used
+ */
+static uint8_t bgp_pbr_match_val_get_operator(struct bgp_pbr_match_val list[],
+                                             int num)
+
+{
+       int i;
+       uint8_t unary_operator = OPERATOR_UNARY_AND;
+
+       for (i = 0; i < num; i++) {
+               if (i == 0)
+                       continue;
+               if (list[i].unary_operator & OPERATOR_UNARY_OR)
+                       unary_operator = OPERATOR_UNARY_OR;
+               if ((list[i].unary_operator & OPERATOR_UNARY_AND
+                    && unary_operator == OPERATOR_UNARY_OR) ||
+                   (list[i].unary_operator & OPERATOR_UNARY_OR
+                    && unary_operator == OPERATOR_UNARY_AND))
+                       return 0;
+       }
+       return unary_operator;
+}
+
+
 /* return true if extraction ok
  */
 static bool bgp_pbr_extract(struct bgp_pbr_match_val list[],
@@ -231,6 +443,8 @@ static bool bgp_pbr_extract(struct bgp_pbr_match_val list[],
 
 static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main *api)
 {
+       bool enumerate_icmp = false;
+
        /* because bgp pbr entry may contain unsupported
         * combinations, a message will be displayed here if
         * not supported.
@@ -240,16 +454,6 @@ static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main *api)
         * - combination src/dst => drop
         * - combination srcport + @IP
         */
-       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:"
@@ -259,6 +463,7 @@ static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main *api)
        }
        if (api->match_protocol_num == 1 &&
            api->protocol[0].value != PROTOCOL_UDP &&
+           api->protocol[0].value != PROTOCOL_ICMP &&
            api->protocol[0].value != PROTOCOL_TCP) {
                if (BGP_DEBUG(pbr, PBR))
                        zlog_debug("BGP: match protocol operations:"
@@ -278,12 +483,114 @@ static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main *api)
                                   "too complex. ignoring.");
                return 0;
        }
+       if (!bgp_pbr_extract_enumerate(api->tcpflags,
+                                      api->match_tcpflags_num,
+                                      OPERATOR_UNARY_AND |
+                                      OPERATOR_UNARY_OR, NULL,
+                                      FLOWSPEC_TCP_FLAGS)) {
+               if (BGP_DEBUG(pbr, PBR))
+                       zlog_debug("BGP: match tcp flags:"
+                                  "too complex. ignoring.");
+               return 0;
+       }
+       if (!bgp_pbr_extract(api->icmp_type, api->match_icmp_type_num, NULL)) {
+               if (!bgp_pbr_extract_enumerate(api->icmp_type,
+                                              api->match_icmp_type_num,
+                                              OPERATOR_UNARY_OR, NULL,
+                                              FLOWSPEC_ICMP_TYPE)) {
+                       if (BGP_DEBUG(pbr, PBR))
+                               zlog_debug("BGP: match icmp type operations:"
+                                          "too complex. ignoring.");
+                       return 0;
+               }
+               enumerate_icmp = true;
+       }
+       if (!bgp_pbr_extract(api->icmp_code, api->match_icmp_code_num, NULL)) {
+               if (!bgp_pbr_extract_enumerate(api->icmp_code,
+                                              api->match_icmp_code_num,
+                                              OPERATOR_UNARY_OR, NULL,
+                                              FLOWSPEC_ICMP_CODE)) {
+                       if (BGP_DEBUG(pbr, PBR))
+                               zlog_debug("BGP: match icmp code operations:"
+                                          "too complex. ignoring.");
+                       return 0;
+               } else if (api->match_icmp_type_num > 1 &&
+                          enumerate_icmp == false) {
+                       if (BGP_DEBUG(pbr, PBR))
+                               zlog_debug("BGP: match icmp code is enumerate"
+                                          ", and icmp type is not."
+                                          " 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;
        }
+       if (api->match_packet_length_num) {
+               bool ret;
+
+               ret = bgp_pbr_extract(api->packet_length,
+                                     api->match_packet_length_num, NULL);
+               if (!ret)
+                       ret = bgp_pbr_extract_enumerate(api->packet_length,
+                                               api->match_packet_length_num,
+                                               OPERATOR_UNARY_OR
+                                               | OPERATOR_UNARY_AND,
+                                               NULL, FLOWSPEC_PKT_LEN);
+               if (!ret) {
+                       if (BGP_DEBUG(pbr, PBR))
+                               zlog_debug("BGP: match packet length operations:"
+                                  "too complex. ignoring.");
+                       return 0;
+               }
+       }
+       if (api->match_dscp_num) {
+               if (!bgp_pbr_extract_enumerate(api->dscp, api->match_dscp_num,
+                               OPERATOR_UNARY_OR | OPERATOR_UNARY_AND,
+                                              NULL, FLOWSPEC_DSCP)) {
+                       if (BGP_DEBUG(pbr, PBR))
+                               zlog_debug("BGP: match DSCP operations:"
+                                          "too complex. ignoring.");
+                       return 0;
+               }
+       }
+       if (api->match_fragment_num) {
+               char fail_str[64];
+               bool success;
+
+               success = bgp_pbr_extract_enumerate(api->fragment,
+                                                   api->match_fragment_num,
+                                                   OPERATOR_UNARY_OR
+                                                   | OPERATOR_UNARY_AND,
+                                                   NULL, FLOWSPEC_FRAGMENT);
+               if (success) {
+                       int i;
+
+                       for (i = 0; i < api->match_fragment_num; i++) {
+                               if (api->fragment[i].value != 1 &&
+                                   api->fragment[i].value != 2 &&
+                                   api->fragment[i].value != 4 &&
+                                   api->fragment[i].value != 8) {
+                                       success = false;
+                                       sprintf(fail_str,
+                                               "Value not valid (%d) for this implementation",
+                                               api->fragment[i].value);
+                               }
+                       }
+               } else
+                       sprintf(fail_str, "too complex. ignoring");
+               if (!success) {
+                       if (BGP_DEBUG(pbr, PBR))
+                               zlog_debug("BGP: match fragment operation (%d) %s",
+                                          api->match_fragment_num,
+                                          fail_str);
+                       return 0;
+               }
+       }
+
        /* no combinations with both src_port and dst_port
         * or port with src_port and dst_port
         */
@@ -294,6 +601,14 @@ static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main *api)
                                 " too complex. ignoring.");
                return 0;
        }
+       if ((api->match_src_port_num || api->match_dst_port_num
+            || api->match_port_num) && (api->match_icmp_type_num
+                                        || api->match_icmp_code_num)) {
+               if (BGP_DEBUG(pbr, PBR))
+                       zlog_debug("BGP: match multiple port/imcp operations:"
+                                " too complex. ignoring.");
+               return 0;
+       }
        if (!(api->match_bitmask & PREFIX_SRC_PRESENT) &&
            !(api->match_bitmask & PREFIX_DST_PRESENT)) {
                if (BGP_DEBUG(pbr, PBR)) {
@@ -518,6 +833,12 @@ uint32_t bgp_pbr_match_hash_key(void *arg)
 
        key = jhash_1word(pbm->vrf_id, 0x4312abde);
        key = jhash_1word(pbm->flags, key);
+       key = jhash_1word(pbm->pkt_len_min, key);
+       key = jhash_1word(pbm->pkt_len_max, key);
+       key = jhash_1word(pbm->tcp_flags, key);
+       key = jhash_1word(pbm->tcp_mask_flags, key);
+       key = jhash_1word(pbm->dscp_value, key);
+       key = jhash_1word(pbm->fragment, key);
        return jhash_1word(pbm->type, key);
 }
 
@@ -540,6 +861,23 @@ int bgp_pbr_match_hash_equal(const void *arg1, const void *arg2)
        if (r1->action != r2->action)
                return 0;
 
+       if (r1->pkt_len_min != r2->pkt_len_min)
+               return 0;
+
+       if (r1->pkt_len_max != r2->pkt_len_max)
+               return 0;
+
+       if (r1->tcp_flags != r2->tcp_flags)
+               return 0;
+
+       if (r1->tcp_mask_flags != r2->tcp_mask_flags)
+               return 0;
+
+       if (r1->dscp_value != r2->dscp_value)
+               return 0;
+
+       if (r1->fragment != r2->fragment)
+               return 0;
        return 1;
 }
 
@@ -807,10 +1145,11 @@ void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main *api)
                ptr += sprintf_bgp_pbr_match_val(ptr, &api->tcpflags[i],
                                         i > 0 ? NULL : "@tcpflags ");
 
-       if (api->match_bitmask & FRAGMENT_PRESENT) {
+       if (api->match_fragment_num)
                INCREMENT_DISPLAY(ptr, nb_items);
-               ptr += sprintf(ptr, "@fragment %u", api->fragment.bitmask);
-       }
+       for (i = 0; i < api->match_fragment_num; i++)
+               ptr += sprintf_bgp_pbr_match_val(ptr, &api->fragment[i],
+                                        i > 0 ? NULL : "@fragment ");
        if (!nb_items)
                ptr = return_string;
        else
@@ -953,20 +1292,24 @@ static int bgp_pbr_get_remaining_entry(struct hash_backet *backet, void *arg)
        return HASHWALK_ABORT;
 }
 
-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,
-                                         uint8_t protocol,
-                                         struct bgp_pbr_range_port *src_port,
-                                         struct bgp_pbr_range_port *dst_port)
+static void bgp_pbr_policyroute_remove_from_zebra_unit(struct bgp *bgp,
+                               struct bgp_info *binfo,
+                               struct bgp_pbr_filter *bpf)
 {
        struct bgp_pbr_match temp;
        struct bgp_pbr_match_entry temp2;
        struct bgp_pbr_match *bpm;
        struct bgp_pbr_match_entry *bpme;
        struct bgp_pbr_match_entry_remain bpmer;
+       struct bgp_pbr_range_port *src_port;
+       struct bgp_pbr_range_port *dst_port;
+       struct bgp_pbr_range_port *pkt_len;
+
+       if (!bpf)
+               return;
+       src_port = bpf->src_port;
+       dst_port = bpf->dst_port;
+       pkt_len = bpf->pkt_len;
 
        /* as we don't know information from EC
         * look for bpm that have the bpm
@@ -974,17 +1317,19 @@ static void bgp_pbr_policyroute_remove_from_zebra(struct bgp *bgp,
         */
        memset(&temp2, 0, sizeof(temp2));
        memset(&temp, 0, sizeof(temp));
-       if (src) {
+       if (bpf->src) {
                temp.flags |= MATCH_IP_SRC_SET;
-               prefix_copy(&temp2.src, src);
+               prefix_copy(&temp2.src, bpf->src);
        } else
                temp2.src.family = AF_INET;
-       if (dst) {
+       if (bpf->dst) {
                temp.flags |= MATCH_IP_DST_SET;
-               prefix_copy(&temp2.dst, dst);
+               prefix_copy(&temp2.dst, bpf->dst);
        } else
                temp2.dst.family = AF_INET;
-       if (src_port) {
+       if (src_port && (src_port->min_port || bpf->protocol == IPPROTO_ICMP)) {
+               if (bpf->protocol == IPPROTO_ICMP)
+                       temp.flags |= MATCH_ICMP_SET;
                temp.flags |= MATCH_PORT_SRC_SET;
                temp2.src_port_min = src_port->min_port;
                if (src_port->max_port) {
@@ -992,7 +1337,9 @@ static void bgp_pbr_policyroute_remove_from_zebra(struct bgp *bgp,
                        temp2.src_port_max = src_port->max_port;
                }
        }
-       if (dst_port) {
+       if (dst_port && (dst_port->min_port || bpf->protocol == IPPROTO_ICMP)) {
+               if (bpf->protocol == IPPROTO_ICMP)
+                       temp.flags |= MATCH_ICMP_SET;
                temp.flags |= MATCH_PORT_DST_SET;
                temp2.dst_port_min = dst_port->min_port;
                if (dst_port->max_port) {
@@ -1000,9 +1347,35 @@ static void bgp_pbr_policyroute_remove_from_zebra(struct bgp *bgp,
                        temp2.dst_port_max = dst_port->max_port;
                }
        }
-       temp2.proto = protocol;
+       temp2.proto = bpf->protocol;
+
+       if (pkt_len) {
+               temp.pkt_len_min = pkt_len->min_port;
+               if (pkt_len->max_port)
+                       temp.pkt_len_max = pkt_len->max_port;
+       } else if (bpf->pkt_len_val) {
+               if (bpf->pkt_len_val->mask)
+                       temp.flags |= MATCH_PKT_LEN_INVERSE_SET;
+               temp.pkt_len_min = bpf->pkt_len_val->val;
+       }
+       if (bpf->tcp_flags) {
+               temp.tcp_flags = bpf->tcp_flags->val;
+               temp.tcp_mask_flags = bpf->tcp_flags->mask;
+       }
+       if (bpf->dscp) {
+               if (bpf->dscp->mask)
+                       temp.flags |= MATCH_DSCP_INVERSE_SET;
+               else
+                       temp.flags |= MATCH_DSCP_SET;
+               temp.dscp_value = bpf->dscp->val;
+       }
+       if (bpf->fragment) {
+               if (bpf->fragment->mask)
+                       temp.flags |= MATCH_FRAGMENT_INVERSE_SET;
+               temp.fragment = bpf->fragment->val;
+       }
 
-       if (src == NULL || dst == NULL) {
+       if (bpf->src == NULL || bpf->dst == NULL) {
                if (temp.flags & (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET))
                        temp.type = IPSET_NET_PORT;
                else
@@ -1013,10 +1386,10 @@ static void bgp_pbr_policyroute_remove_from_zebra(struct bgp *bgp,
                else
                        temp.type = IPSET_NET_NET;
        }
-       if (vrf_id == VRF_UNKNOWN) /* XXX case BGP destroy */
+       if (bpf->vrf_id == VRF_UNKNOWN) /* XXX case BGP destroy */
                temp.vrf_id = 0;
        else
-               temp.vrf_id = vrf_id;
+               temp.vrf_id = bpf->vrf_id;
        bpme = &temp2;
        bpm = &temp;
        bpme->backpointer = bpm;
@@ -1037,16 +1410,182 @@ static void bgp_pbr_policyroute_remove_from_zebra(struct bgp *bgp,
        }
 }
 
-static void bgp_pbr_policyroute_add_to_zebra(struct bgp *bgp,
+static uint8_t bgp_pbr_next_type_entry(uint8_t type_entry)
+{
+       if (type_entry == FLOWSPEC_TCP_FLAGS)
+               return FLOWSPEC_DSCP;
+       if (type_entry == FLOWSPEC_DSCP)
+               return FLOWSPEC_PKT_LEN;
+       if (type_entry == FLOWSPEC_PKT_LEN)
+               return FLOWSPEC_FRAGMENT;
+       if (type_entry == FLOWSPEC_FRAGMENT)
+               return FLOWSPEC_ICMP_TYPE;
+       return 0;
+}
+
+static void  bgp_pbr_icmp_action(struct bgp *bgp,
+                                struct bgp_info *binfo,
+                                struct bgp_pbr_filter *bpf,
+                                struct bgp_pbr_or_filter *bpof,
+                                bool add,
+                                struct nexthop *nh,
+                                float *rate)
+{
+       struct bgp_pbr_range_port srcp, dstp;
+       struct bgp_pbr_val_mask *icmp_type, *icmp_code;
+       struct listnode *tnode, *cnode;
+
+       if (!bpf)
+               return;
+       if (bpf->protocol != IPPROTO_ICMP)
+               return;
+       bpf->src_port = &srcp;
+       bpf->dst_port = &dstp;
+       /* parse icmp type and lookup appropriate icmp code
+        * if no icmp code found, create as many entryes as
+        * there are listed icmp codes for that icmp type
+        */
+       if (!bpof->icmp_type) {
+               srcp.min_port = 0;
+               srcp.max_port = 255;
+               for (ALL_LIST_ELEMENTS_RO(bpof->icmp_code, cnode, icmp_code)) {
+                       dstp.min_port = icmp_code->val;
+                       if (add)
+                               bgp_pbr_policyroute_add_to_zebra_unit(bgp, binfo,
+                                                       bpf, nh, rate);
+                       else
+                               bgp_pbr_policyroute_remove_from_zebra_unit(
+                                                       bgp, binfo, bpf);
+               }
+               return;
+       }
+       for (ALL_LIST_ELEMENTS_RO(bpof->icmp_type, tnode, icmp_type)) {
+               srcp.min_port = icmp_type->val;
+               srcp.max_port = 0;
+               dstp.max_port = 0;
+               /* only icmp type. create an entry only with icmp type */
+               if (!bpof->icmp_code) {
+                       /* icmp type is not one of the above
+                        * forge an entry only based on the icmp type
+                        */
+                       dstp.min_port = 0;
+                       dstp.max_port = 255;
+                       if (add)
+                               bgp_pbr_policyroute_add_to_zebra_unit(
+                                                       bgp, binfo,
+                                                       bpf, nh, rate);
+                       else
+                               bgp_pbr_policyroute_remove_from_zebra_unit(bgp,
+                                                             binfo, bpf);
+                       continue;
+               }
+               for (ALL_LIST_ELEMENTS_RO(bpof->icmp_code, cnode, icmp_code)) {
+                       dstp.min_port = icmp_code->val;
+                       if (add)
+                               bgp_pbr_policyroute_add_to_zebra_unit(
+                                                       bgp, binfo,
+                                                       bpf, nh, rate);
+                       else
+                               bgp_pbr_policyroute_remove_from_zebra_unit(
+                                                          bgp, binfo, bpf);
+               }
+       }
+}
+
+static void bgp_pbr_policyroute_remove_from_zebra_recursive(struct bgp *bgp,
+                       struct bgp_info *binfo,
+                       struct bgp_pbr_filter *bpf,
+                       struct bgp_pbr_or_filter *bpof,
+                       uint8_t type_entry)
+{
+       struct listnode *node, *nnode;
+       struct bgp_pbr_val_mask *valmask;
+       uint8_t next_type_entry;
+       struct list *orig_list;
+       struct bgp_pbr_val_mask **target_val;
+
+       if (type_entry == 0)
+               return bgp_pbr_policyroute_remove_from_zebra_unit(bgp,
+                                                       binfo, bpf);
+       next_type_entry = bgp_pbr_next_type_entry(type_entry);
+       if (type_entry == FLOWSPEC_TCP_FLAGS && bpof->tcpflags) {
+               orig_list = bpof->tcpflags;
+               target_val = &bpf->tcp_flags;
+       } else if (type_entry == FLOWSPEC_DSCP && bpof->dscp) {
+               orig_list = bpof->dscp;
+               target_val = &bpf->dscp;
+       } else if (type_entry == FLOWSPEC_PKT_LEN && bpof->pkt_len) {
+               orig_list = bpof->pkt_len;
+               target_val = &bpf->pkt_len_val;
+       } else if (type_entry == FLOWSPEC_FRAGMENT && bpof->fragment) {
+               orig_list = bpof->fragment;
+               target_val = &bpf->fragment;
+       } else if (type_entry == FLOWSPEC_ICMP_TYPE &&
+                  (bpof->icmp_type || bpof->icmp_code)) {
+               /* enumerate list for icmp - must be last one  */
+               bgp_pbr_icmp_action(bgp, binfo, bpf, bpof, false, NULL, NULL);
+               return;
+       } else {
+               return bgp_pbr_policyroute_remove_from_zebra_recursive(bgp,
+                                                       binfo,
+                                                       bpf, bpof,
+                                                       next_type_entry);
+       }
+       for (ALL_LIST_ELEMENTS(orig_list, node, nnode, valmask)) {
+               *target_val = valmask;
+               bgp_pbr_policyroute_remove_from_zebra_recursive(bgp, binfo,
+                                                       bpf, bpof,
+                                                       next_type_entry);
+       }
+}
+
+static void bgp_pbr_policyroute_remove_from_zebra(struct bgp *bgp,
+                               struct bgp_info *binfo,
+                               struct bgp_pbr_filter *bpf,
+                               struct bgp_pbr_or_filter *bpof)
+{
+       if (!bpof)
+               return bgp_pbr_policyroute_remove_from_zebra_unit(bgp,
+                                                                 binfo,
+                                                                 bpf);
+       if (bpof->tcpflags)
+               bgp_pbr_policyroute_remove_from_zebra_recursive(bgp, binfo,
+                                                       bpf, bpof,
+                                                       FLOWSPEC_TCP_FLAGS);
+       else if (bpof->dscp)
+               bgp_pbr_policyroute_remove_from_zebra_recursive(bgp, binfo,
+                                                       bpf, bpof,
+                                                       FLOWSPEC_DSCP);
+       else if (bpof->pkt_len)
+               bgp_pbr_policyroute_remove_from_zebra_recursive(bgp, binfo,
+                                                       bpf, bpof,
+                                                       FLOWSPEC_PKT_LEN);
+       else if (bpof->fragment)
+               bgp_pbr_policyroute_remove_from_zebra_recursive(bgp, binfo,
+                                                       bpf, bpof,
+                                                       FLOWSPEC_FRAGMENT);
+       else if (bpof->icmp_type || bpof->icmp_code)
+               bgp_pbr_policyroute_remove_from_zebra_recursive(bgp, binfo,
+                                                       bpf, bpof,
+                                                       FLOWSPEC_ICMP_TYPE);
+       else
+               bgp_pbr_policyroute_remove_from_zebra_unit(bgp, binfo, bpf);
+       /* flush bpof */
+       if (bpof->tcpflags)
+               list_delete_all_node(bpof->tcpflags);
+       if (bpof->dscp)
+               list_delete_all_node(bpof->dscp);
+       if (bpof->pkt_len)
+               list_delete_all_node(bpof->pkt_len);
+       if (bpof->fragment)
+               list_delete_all_node(bpof->fragment);
+}
+
+static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp,
                                     struct bgp_info *binfo,
-                                    vrf_id_t vrf_id,
-                                    struct prefix *src,
-                                    struct prefix *dst,
+                                    struct bgp_pbr_filter *bpf,
                                     struct nexthop *nh,
-                                    float *rate,
-                                    uint8_t protocol,
-                                    struct bgp_pbr_range_port *src_port,
-                                    struct bgp_pbr_range_port *dst_port)
+                                    float *rate)
 {
        struct bgp_pbr_match temp;
        struct bgp_pbr_match_entry temp2;
@@ -1055,14 +1594,104 @@ static void bgp_pbr_policyroute_add_to_zebra(struct bgp *bgp,
        struct bgp_pbr_action temp3;
        struct bgp_pbr_action *bpa = NULL;
        struct bgp_pbr_match_entry_remain bpmer;
+       struct bgp_pbr_range_port *src_port;
+       struct bgp_pbr_range_port *dst_port;
+       struct bgp_pbr_range_port *pkt_len;
 
+       if (!bpf)
+               return;
+       src_port = bpf->src_port;
+       dst_port = bpf->dst_port;
+       pkt_len = bpf->pkt_len;
+
+       if (BGP_DEBUG(zebra, ZEBRA)) {
+               char bufsrc[64], bufdst[64];
+               char buffer[64];
+               int remaining_len = 0;
+               char protocol_str[16];
+
+               protocol_str[0] = '\0';
+               if (bpf->tcp_flags && bpf->tcp_flags->mask)
+                       bpf->protocol = IPPROTO_TCP;
+               if (bpf->protocol)
+                       snprintf(protocol_str, sizeof(protocol_str),
+                                "proto %d", bpf->protocol);
+               buffer[0] = '\0';
+               if (bpf->protocol == IPPROTO_ICMP && src_port && dst_port)
+                       remaining_len += snprintf(buffer, sizeof(buffer),
+                                                 "type %d, code %d",
+                                src_port->min_port, dst_port->min_port);
+               else if (bpf->protocol == IPPROTO_UDP ||
+                        bpf->protocol == IPPROTO_TCP) {
+
+                       if (src_port && src_port->min_port)
+                               remaining_len += snprintf(buffer,
+                                                         sizeof(buffer),
+                                                         "from [%u:%u]",
+                                                         src_port->min_port,
+                                                         src_port->max_port ?
+                                                         src_port->max_port :
+                                                         src_port->min_port);
+                       if (dst_port && dst_port->min_port)
+                               remaining_len += snprintf(buffer +
+                                                         remaining_len,
+                                                         sizeof(buffer)
+                                                         - remaining_len,
+                                                         "to [%u:%u]",
+                                                         dst_port->min_port,
+                                                         dst_port->max_port ?
+                                                         dst_port->max_port :
+                                                         dst_port->min_port);
+               }
+               if (pkt_len && (pkt_len->min_port || pkt_len->max_port)) {
+                       remaining_len += snprintf(buffer + remaining_len,
+                                                 sizeof(buffer)
+                                                 - remaining_len,
+                                                 " len [%u:%u]",
+                                                 pkt_len->min_port,
+                                                 pkt_len->max_port ?
+                                                 pkt_len->max_port :
+                                                 pkt_len->min_port);
+               } else if (bpf->pkt_len_val) {
+                       remaining_len += snprintf(buffer + remaining_len,
+                                                 sizeof(buffer)
+                                                 - remaining_len,
+                                                 " %s len %u",
+                                                 bpf->pkt_len_val->mask
+                                                 ? "!" : "",
+                                                 bpf->pkt_len_val->val);
+               }
+               if (bpf->tcp_flags) {
+                       remaining_len += snprintf(buffer + remaining_len,
+                                                 sizeof(buffer)
+                                                 - remaining_len,
+                                                 "tcpflags %x/%x",
+                                                 bpf->tcp_flags->val,
+                                                 bpf->tcp_flags->mask);
+               }
+               if (bpf->dscp) {
+                       snprintf(buffer + remaining_len,
+                                sizeof(buffer)
+                                - remaining_len,
+                                "%s dscp %d",
+                                bpf->dscp->mask
+                                ? "!" : "",
+                                bpf->dscp->val);
+               }
+               zlog_info("BGP: adding FS PBR from %s to %s, %s %s",
+                         bpf->src == NULL ? "<all>" :
+                         prefix2str(bpf->src, bufsrc, sizeof(bufsrc)),
+                         bpf->dst == NULL ? "<all>" :
+                         prefix2str(bpf->dst, bufdst, sizeof(bufdst)),
+                         protocol_str, buffer);
+       }
        /* look for bpa first */
        memset(&temp3, 0, sizeof(temp3));
        if (rate)
                temp3.rate = *rate;
        if (nh)
                memcpy(&temp3.nh, nh, sizeof(struct nexthop));
-       temp3.vrf_id = vrf_id;
+       temp3.vrf_id = bpf->vrf_id;
        bpa = hash_get(bgp->pbr_action_hash, &temp3,
                       bgp_pbr_action_alloc_intern);
 
@@ -1084,33 +1713,63 @@ 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) {
-               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.vrf_id = bpf->vrf_id;
+       if (bpf->src)
                temp.flags |= MATCH_IP_SRC_SET;
-       if (dst)
+       if (bpf->dst)
                temp.flags |= MATCH_IP_DST_SET;
 
-       if (src_port && src_port->min_port)
+       if (src_port && (src_port->min_port || bpf->protocol == IPPROTO_ICMP)) {
+               if (bpf->protocol == IPPROTO_ICMP)
+                       temp.flags |= MATCH_ICMP_SET;
                temp.flags |= MATCH_PORT_SRC_SET;
-       if (dst_port && dst_port->min_port)
+       }
+       if (dst_port && (dst_port->min_port || bpf->protocol == IPPROTO_ICMP)) {
+               if (bpf->protocol == IPPROTO_ICMP)
+                       temp.flags |= MATCH_ICMP_SET;
                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;
+
+       if (bpf->src == NULL || bpf->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 (pkt_len) {
+               temp.pkt_len_min = pkt_len->min_port;
+               if (pkt_len->max_port)
+                       temp.pkt_len_max = pkt_len->max_port;
+       } else if (bpf->pkt_len_val) {
+               if (bpf->pkt_len_val->mask)
+                       temp.flags |= MATCH_PKT_LEN_INVERSE_SET;
+               temp.pkt_len_min = bpf->pkt_len_val->val;
+       }
+       if (bpf->tcp_flags) {
+               temp.tcp_flags = bpf->tcp_flags->val;
+               temp.tcp_mask_flags = bpf->tcp_flags->mask;
+       }
+       if (bpf->dscp) {
+               if (bpf->dscp->mask)
+                       temp.flags |= MATCH_DSCP_INVERSE_SET;
+               else
+                       temp.flags |= MATCH_DSCP_SET;
+               temp.dscp_value = bpf->dscp->val;
+       }
+       if (bpf->fragment) {
+               if (bpf->fragment->mask)
+                       temp.flags |= MATCH_FRAGMENT_INVERSE_SET;
+               temp.fragment = bpf->fragment->val;
+       }
        temp.action = bpa;
        bpm = hash_get(bgp->pbr_match_hash, &temp,
                       bgp_pbr_match_alloc_intern);
@@ -1134,19 +1793,19 @@ static void bgp_pbr_policyroute_add_to_zebra(struct bgp *bgp,
        }
 
        memset(&temp2, 0, sizeof(temp2));
-       if (src)
-               prefix_copy(&temp2.src, src);
+       if (bpf->src)
+               prefix_copy(&temp2.src, bpf->src);
        else
                temp2.src.family = AF_INET;
-       if (dst)
-               prefix_copy(&temp2.dst, dst);
+       if (bpf->dst)
+               prefix_copy(&temp2.dst, bpf->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;
+       temp2.proto = bpf->protocol;
        if (bpm)
                bpme = hash_get(bpm->entry_hash, &temp2,
                                bgp_pbr_match_entry_alloc_intern);
@@ -1171,7 +1830,7 @@ static void bgp_pbr_policyroute_add_to_zebra(struct bgp *bgp,
         * it will be suppressed subsequently
         */
        /* ip rule add */
-       if (!bpa->installed) {
+       if (!bpa->installed && !bpa->install_in_progress) {
                bgp_send_pbr_rule_action(bpa, true);
                bgp_zebra_announce_default(bgp, nh,
                                           AFI_IP, bpa->table_id, true);
@@ -1207,6 +1866,107 @@ static void bgp_pbr_policyroute_add_to_zebra(struct bgp *bgp,
 
 }
 
+static void bgp_pbr_policyroute_add_to_zebra_recursive(struct bgp *bgp,
+                       struct bgp_info *binfo,
+                       struct bgp_pbr_filter *bpf,
+                       struct bgp_pbr_or_filter *bpof,
+                       struct nexthop *nh,
+                       float *rate,
+                       uint8_t type_entry)
+{
+       struct listnode *node, *nnode;
+       struct bgp_pbr_val_mask *valmask;
+       uint8_t next_type_entry;
+       struct list *orig_list;
+       struct bgp_pbr_val_mask **target_val;
+
+       if (type_entry == 0)
+               return bgp_pbr_policyroute_add_to_zebra_unit(bgp, binfo, bpf,
+                                                            nh, rate);
+       next_type_entry = bgp_pbr_next_type_entry(type_entry);
+       if (type_entry == FLOWSPEC_TCP_FLAGS && bpof->tcpflags) {
+               orig_list = bpof->tcpflags;
+               target_val = &bpf->tcp_flags;
+       } else if (type_entry == FLOWSPEC_DSCP && bpof->dscp) {
+               orig_list = bpof->dscp;
+               target_val = &bpf->dscp;
+       } else if (type_entry == FLOWSPEC_PKT_LEN && bpof->pkt_len) {
+               orig_list = bpof->pkt_len;
+               target_val = &bpf->pkt_len_val;
+       } else if (type_entry == FLOWSPEC_FRAGMENT && bpof->fragment) {
+               orig_list = bpof->fragment;
+               target_val = &bpf->fragment;
+       } else if (type_entry == FLOWSPEC_ICMP_TYPE &&
+                  (bpof->icmp_type || bpof->icmp_code)) {
+               /* enumerate list for icmp - must be last one  */
+               bgp_pbr_icmp_action(bgp, binfo, bpf, bpof, true, nh, rate);
+               return;
+       } else {
+               return bgp_pbr_policyroute_add_to_zebra_recursive(bgp, binfo,
+                                               bpf, bpof, nh, rate,
+                                               next_type_entry);
+       }
+       for (ALL_LIST_ELEMENTS(orig_list, node, nnode, valmask)) {
+               *target_val = valmask;
+               bgp_pbr_policyroute_add_to_zebra_recursive(bgp, binfo,
+                                                       bpf, bpof,
+                                                       nh, rate,
+                                                       next_type_entry);
+       }
+}
+
+static void bgp_pbr_policyroute_add_to_zebra(struct bgp *bgp,
+                                    struct bgp_info *binfo,
+                                    struct bgp_pbr_filter *bpf,
+                                    struct bgp_pbr_or_filter *bpof,
+                                    struct nexthop *nh,
+                                    float *rate)
+{
+       if (!bpof)
+               return bgp_pbr_policyroute_add_to_zebra_unit(bgp, binfo,
+                                                            bpf, nh, rate);
+       if (bpof->tcpflags)
+               bgp_pbr_policyroute_add_to_zebra_recursive(bgp, binfo,
+                                                          bpf, bpof,
+                                                          nh, rate,
+                                                          FLOWSPEC_TCP_FLAGS);
+       else if (bpof->dscp)
+               bgp_pbr_policyroute_add_to_zebra_recursive(bgp, binfo,
+                                                          bpf, bpof,
+                                                          nh, rate,
+                                                          FLOWSPEC_DSCP);
+       else if (bpof->pkt_len)
+               bgp_pbr_policyroute_add_to_zebra_recursive(bgp, binfo,
+                                                          bpf, bpof,
+                                                          nh, rate,
+                                                          FLOWSPEC_PKT_LEN);
+       else if (bpof->fragment)
+               bgp_pbr_policyroute_add_to_zebra_recursive(bgp, binfo,
+                                                          bpf, bpof,
+                                                          nh, rate,
+                                                          FLOWSPEC_FRAGMENT);
+       else if (bpof->icmp_type || bpof->icmp_code)
+               bgp_pbr_policyroute_add_to_zebra_recursive(bgp, binfo,
+                                                  bpf, bpof, nh, rate,
+                                                  FLOWSPEC_ICMP_TYPE);
+       else
+               bgp_pbr_policyroute_add_to_zebra_unit(bgp, binfo, bpf,
+                                                     nh, rate);
+       /* flush bpof */
+       if (bpof->tcpflags)
+               list_delete_all_node(bpof->tcpflags);
+       if (bpof->dscp)
+               list_delete_all_node(bpof->dscp);
+       if (bpof->pkt_len)
+               list_delete_all_node(bpof->pkt_len);
+       if (bpof->fragment)
+               list_delete_all_node(bpof->fragment);
+       if (bpof->icmp_type)
+               list_delete_all_node(bpof->icmp_type);
+       if (bpof->icmp_code)
+               list_delete_all_node(bpof->icmp_code);
+}
+
 static void bgp_pbr_handle_entry(struct bgp *bgp,
                                struct bgp_info *binfo,
                                struct bgp_pbr_entry_main *api,
@@ -1219,9 +1979,16 @@ static void bgp_pbr_handle_entry(struct bgp *bgp,
        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;
+       struct bgp_pbr_range_port range, range_icmp_code;
+       struct bgp_pbr_range_port pkt_len;
+       struct bgp_pbr_filter bpf;
+       uint8_t kind_enum;
+       struct bgp_pbr_or_filter bpof;
+       struct bgp_pbr_val_mask bpvm;
 
        memset(&nh, 0, sizeof(struct nexthop));
+       memset(&bpf, 0, sizeof(struct bgp_pbr_filter));
+       memset(&bpof, 0, sizeof(struct bgp_pbr_or_filter));
        if (api->match_bitmask & PREFIX_SRC_PRESENT)
                src = &api->src_prefix;
        if (api->match_bitmask & PREFIX_DST_PRESENT)
@@ -1251,10 +2018,97 @@ static void bgp_pbr_handle_entry(struct bgp *bgp,
                dstp = &range;
                srcp = NULL;
        }
+       if (api->match_icmp_type_num >= 1) {
+               proto = IPPROTO_ICMP;
+               if (bgp_pbr_extract(api->icmp_type,
+                                   api->match_icmp_type_num,
+                                   &range))
+                       srcp = &range;
+               else {
+                       bpof.icmp_type = list_new();
+                       bgp_pbr_extract_enumerate(api->icmp_type,
+                                                 api->match_icmp_type_num,
+                                                 OPERATOR_UNARY_OR,
+                                                 bpof.icmp_type,
+                                                 FLOWSPEC_ICMP_TYPE);
+               }
+       }
+       if (api->match_icmp_code_num >= 1) {
+               proto = IPPROTO_ICMP;
+               if (bgp_pbr_extract(api->icmp_code,
+                                   api->match_icmp_code_num,
+                                   &range_icmp_code))
+                       dstp = &range_icmp_code;
+               else {
+                       bpof.icmp_code = list_new();
+                       bgp_pbr_extract_enumerate(api->icmp_code,
+                                                 api->match_icmp_code_num,
+                                                 OPERATOR_UNARY_OR,
+                                                 bpof.icmp_code,
+                                                 FLOWSPEC_ICMP_CODE);
+               }
+       }
+
+       if (api->match_tcpflags_num) {
+               kind_enum = bgp_pbr_match_val_get_operator(api->tcpflags,
+                                                  api->match_tcpflags_num);
+               if (kind_enum == OPERATOR_UNARY_AND) {
+                       bpf.tcp_flags = &bpvm;
+                       bgp_pbr_extract_enumerate(api->tcpflags,
+                                                 api->match_tcpflags_num,
+                                                 OPERATOR_UNARY_AND,
+                                                 bpf.tcp_flags,
+                                                 FLOWSPEC_TCP_FLAGS);
+               } else if (kind_enum == OPERATOR_UNARY_OR) {
+                       bpof.tcpflags = list_new();
+                       bgp_pbr_extract_enumerate(api->tcpflags,
+                                                 api->match_tcpflags_num,
+                                                 OPERATOR_UNARY_OR,
+                                                 bpof.tcpflags,
+                                                 FLOWSPEC_TCP_FLAGS);
+               }
+       }
+       if (api->match_packet_length_num) {
+               bool ret;
+
+               ret = bgp_pbr_extract(api->packet_length,
+                                     api->match_packet_length_num,
+                                     &pkt_len);
+               if (ret)
+                       bpf.pkt_len = &pkt_len;
+               else {
+                       bpof.pkt_len = list_new();
+                       bgp_pbr_extract_enumerate(api->packet_length,
+                                                 api->match_packet_length_num,
+                                                 OPERATOR_UNARY_OR,
+                                                 bpof.pkt_len,
+                                                 FLOWSPEC_PKT_LEN);
+               }
+       }
+       if (api->match_dscp_num >= 1) {
+               bpof.dscp = list_new();
+               bgp_pbr_extract_enumerate(api->dscp, api->match_dscp_num,
+                                         OPERATOR_UNARY_OR,
+                                         bpof.dscp, FLOWSPEC_DSCP);
+       }
+       if (api->match_fragment_num) {
+               bpof.fragment = list_new();
+               bgp_pbr_extract_enumerate(api->fragment,
+                                         api->match_fragment_num,
+                                         OPERATOR_UNARY_OR,
+                                         bpof.fragment,
+                                         FLOWSPEC_FRAGMENT);
+       }
+       bpf.vrf_id = api->vrf_id;
+       bpf.src = src;
+       bpf.dst = dst;
+       bpf.protocol = proto;
+       bpf.src_port = srcp;
+       bpf.dst_port = dstp;
        if (!add)
-               return bgp_pbr_policyroute_remove_from_zebra(bgp, binfo,
-                                            api->vrf_id, src, dst,
-                                            proto, srcp, dstp);
+               return bgp_pbr_policyroute_remove_from_zebra(bgp,
+                                                            binfo,
+                                                            &bpf, &bpof);
        /* no action for add = true */
        for (i = 0; i < api->action_num; i++) {
                switch (api->actions[i].action) {
@@ -1264,9 +2118,8 @@ static void bgp_pbr_handle_entry(struct bgp *bgp,
                                nh.vrf_id = api->vrf_id;
                                nh.type = NEXTHOP_TYPE_BLACKHOLE;
                                bgp_pbr_policyroute_add_to_zebra(bgp, binfo,
-                                                   api->vrf_id, src, dst,
-                                                   &nh, &rate, proto,
-                                                   srcp, dstp);
+                                                                &bpf, &bpof,
+                                                                &nh, &rate);
                        } else {
                                /* update rate. can be reentrant */
                                rate = api->actions[i].u.r.rate;
@@ -1307,10 +2160,8 @@ static void bgp_pbr_handle_entry(struct bgp *bgp,
                                api->actions[i].u.zr.redirect_ip_v4.s_addr;
                        nh.vrf_id = api->vrf_id;
                        bgp_pbr_policyroute_add_to_zebra(bgp, binfo,
-                                                           api->vrf_id,
-                                                           src, dst,
-                                                           &nh, &rate, proto,
-                                                           srcp, dstp);
+                                                        &bpf, &bpof,
+                                                        &nh, &rate);
                        /* XXX combination with REDIRECT_VRF
                         * + REDIRECT_NH_IP not done
                         */
@@ -1320,10 +2171,8 @@ static void bgp_pbr_handle_entry(struct bgp *bgp,
                        nh.vrf_id = api->actions[i].u.redirect_vrf;
                        nh.type = NEXTHOP_TYPE_IPV4;
                        bgp_pbr_policyroute_add_to_zebra(bgp, binfo,
-                                                        api->vrf_id,
-                                                        src, dst,
-                                                        &nh, &rate, proto,
-                                                        srcp, dstp);
+                                                        &bpf, &bpof,
+                                                        &nh, &rate);
                        continue_loop = 0;
                        break;
                case ACTION_MARKING:
index 20edaf30b8a567fa5bf70a6f73e73375ef6cb276..307a34e34f4c02749f49604601b0cc90b9151532 100644 (file)
@@ -107,7 +107,6 @@ struct bgp_pbr_entry_main {
 
 #define PREFIX_SRC_PRESENT (1 << 0)
 #define PREFIX_DST_PRESENT (1 << 1)
-#define FRAGMENT_PRESENT   (1 << 2)
        uint8_t match_bitmask;
 
        uint8_t match_src_port_num;
@@ -119,12 +118,14 @@ struct bgp_pbr_entry_main {
        uint8_t match_packet_length_num;
        uint8_t match_dscp_num;
        uint8_t match_tcpflags_num;
+       uint8_t match_fragment_num;
 
        struct prefix src_prefix;
        struct prefix dst_prefix;
 
 #define PROTOCOL_UDP 17
 #define PROTOCOL_TCP 6
+#define PROTOCOL_ICMP 1
        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];
@@ -133,8 +134,9 @@ struct bgp_pbr_entry_main {
        struct bgp_pbr_match_val icmp_code[BGP_PBR_MATCH_VAL_MAX];
        struct bgp_pbr_match_val packet_length[BGP_PBR_MATCH_VAL_MAX];
        struct bgp_pbr_match_val dscp[BGP_PBR_MATCH_VAL_MAX];
+
        struct bgp_pbr_match_val tcpflags[BGP_PBR_MATCH_VAL_MAX];
-       struct bgp_pbr_fragment_val fragment;
+       struct bgp_pbr_match_val fragment[BGP_PBR_MATCH_VAL_MAX];
 
        uint16_t action_num;
        struct bgp_pbr_entry_action actions[ACTIONS_MAX_NUM];
@@ -176,14 +178,15 @@ struct bgp_pbr_match {
         */
        uint32_t type;
 
-#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;
 
+       uint16_t pkt_len_min;
+       uint16_t pkt_len_max;
+       uint16_t tcp_flags;
+       uint16_t tcp_mask_flags;
+       uint8_t dscp_value;
+       uint8_t fragment;
+
        vrf_id_t vrf_id;
 
        /* unique identifier for ipset create transaction
index 356a949d691c0a79b3e08907536e1072cef917d3..77f5aade5f0cad0f300c07549df2a478ff10e435 100644 (file)
@@ -27,6 +27,7 @@
 #include "memory.h"
 #include "stream.h"
 #include "filter.h"
+#include "frrstr.h"
 
 #include "bgpd/bgpd.h"
 #include "bgpd/bgp_rd.h"
index 0a15eb504080a5d38c16640de428b1edad6a56e1..7057b62f2b00a47271b8eaa19d28602ae7599392 100644 (file)
@@ -1185,12 +1185,8 @@ static int bgp_input_modifier(struct peer *peer, struct prefix *p,
 
                peer->rmap_type = 0;
 
-               if (ret == RMAP_DENYMATCH) {
-                       /* Free newly generated AS path and community by
-                        * route-map. */
-                       bgp_attr_flush(attr);
+               if (ret == RMAP_DENYMATCH)
                        return RMAP_DENY;
-               }
        }
        return RMAP_PERMIT;
 }
@@ -1322,6 +1318,8 @@ void bgp_attr_add_gshut_community(struct attr *attr)
        old = attr->community;
        gshut = community_str2com("graceful-shutdown");
 
+       assert(gshut);
+
        if (old) {
                merge = community_merge(community_dup(old), gshut);
 
@@ -6284,7 +6282,6 @@ static void route_vty_out_route(struct prefix *p, struct vty *vty,
                prefix2str(p, buf, PREFIX_STRLEN);
                len = vty_out(vty, "%s", buf);
        } else if (p->family == AF_EVPN) {
-#if defined(HAVE_CUMULUS)
                if (!json)
                        len = vty_out(
                                vty, "%s",
@@ -6292,10 +6289,6 @@ static void route_vty_out_route(struct prefix *p, struct vty *vty,
                                                   BUFSIZ));
                else
                        bgp_evpn_route2json((struct prefix_evpn *)p, json);
-#else
-               prefix2str(p, buf, PREFIX_STRLEN);
-               len = vty_out(vty, "%s", buf);
-#endif
        } else if (p->family == AF_FLOWSPEC) {
                route_vty_out_flowspec(vty, p, NULL,
                               json ?
@@ -6568,14 +6561,8 @@ void route_vty_out(struct vty *vty, struct prefix *p, struct bgp_info *binfo,
                } else {
                        char buf[BUFSIZ];
 
-                       if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_EVPN))
-                               snprintf(buf, sizeof(buf), "%s%s",
-                                       inet_ntoa(attr->mp_nexthop_global_in),
-                                       vrf_id_str);
-                       else
-                               snprintf(buf, sizeof(buf), "%s%s",
-                                       inet_ntoa(attr->nexthop),
-                                       vrf_id_str);
+                       snprintf(buf, sizeof(buf), "%s%s",
+                               inet_ntoa(attr->nexthop), vrf_id_str);
                        vty_out(vty, "%-16s", buf);
                }
        }
@@ -7309,9 +7296,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p,
 {
        char buf[INET6_ADDRSTRLEN];
        char buf1[BUFSIZ];
-#if defined(HAVE_CUMULUS)
        char buf2[EVPN_ROUTE_STRLEN];
-#endif
        struct attr *attr;
        int sockunion_vty_out(struct vty *, union sockunion *);
        time_t tbuf;
@@ -7344,7 +7329,6 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p,
                json_nexthop_global = json_object_new_object();
        }
 
-#if defined(HAVE_CUMULUS)
        if (!json_paths && safi == SAFI_EVPN) {
                char tag_buf[30];
 
@@ -7374,7 +7358,6 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p,
                        }
                }
        }
-#endif
 
        attr = binfo->attr;
 
@@ -8027,14 +8010,9 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p,
                if (binfo->extra && binfo->extra->damp_info)
                        bgp_damp_info_vty(vty, binfo, json_path);
 
-/* Remote Label */
-#if defined(HAVE_CUMULUS)
+               /* Remote Label */
                if (binfo->extra && bgp_is_valid_label(&binfo->extra->label[0])
-                   && safi != SAFI_EVPN)
-#else
-               if (binfo->extra && bgp_is_valid_label(&binfo->extra->label[0]))
-#endif
-               {
+                   && safi != SAFI_EVPN) {
                        mpls_label_t label =
                                label_pton(&binfo->extra->label[0]);
                        if (json_paths)
@@ -8605,9 +8583,7 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
        struct listnode *node, *nnode;
        char buf1[RD_ADDRSTRLEN];
        char buf2[INET6_ADDRSTRLEN];
-#if defined(HAVE_CUMULUS)
        char buf3[EVPN_ROUTE_STRLEN];
-#endif
        char prefix_str[BUFSIZ];
        int count = 0;
        int best = 0;
@@ -8634,7 +8610,6 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
                        json, "prefix",
                        prefix2str(p, prefix_str, sizeof(prefix_str)));
        } else {
-#if defined(HAVE_CUMULUS)
                if (safi == SAFI_EVPN)
                        vty_out(vty, "BGP routing table entry for %s%s%s\n",
                                prd ? prefix_rd2str(prd, buf1, sizeof(buf1))
@@ -8652,29 +8627,10 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
                                inet_ntop(p->family, &p->u.prefix, buf2,
                                          INET6_ADDRSTRLEN),
                                p->prefixlen);
-#else
-               if (p->family == AF_ETHERNET)
-                       prefix2str(p, buf2, INET6_ADDRSTRLEN);
-               else
-                       inet_ntop(p->family, &p->u.prefix, buf2,
-                                 INET6_ADDRSTRLEN);
-               vty_out(vty, "BGP routing table entry for %s%s%s/%d\n",
-                       ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP
-                         || safi == SAFI_EVPN)
-                                ? prefix_rd2str(prd, buf1, sizeof(buf1))
-                                : ""),
-                       ((safi == SAFI_MPLS_VPN) || (safi == SAFI_EVPN)) ? ":"
-                                                                        : "",
-                       buf2, p->prefixlen);
-#endif
 
                if (has_valid_label)
                        vty_out(vty, "Local label: %d\n", label);
-#if defined(HAVE_CUMULUS)
                if (bgp_labeled_safi(safi) && safi != SAFI_EVPN)
-#else
-               if (bgp_labeled_safi(safi))
-#endif
                        vty_out(vty, "not allocated\n");
        }
 
index cbacd6b4f28cac71fde3c9c6266fcd0a305381a0..f7c79f873df0b84d35cf7d4e3f2180b84981798c 100644 (file)
@@ -37,6 +37,7 @@
 #include "sockunion.h"
 #include "hash.h"
 #include "queue.h"
+#include "frrstr.h"
 
 #include "bgpd/bgpd.h"
 #include "bgpd/bgp_table.h"
@@ -3112,7 +3113,7 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name,
        }
 }
 
-static int bgp_route_map_process_update_cb(char *rmap_name)
+static void bgp_route_map_process_update_cb(char *rmap_name)
 {
        struct listnode *node, *nnode;
        struct bgp *bgp;
@@ -3127,8 +3128,6 @@ static int bgp_route_map_process_update_cb(char *rmap_name)
        }
 
        vpn_policy_routemap_event(rmap_name);
-
-       return 0;
 }
 
 int bgp_route_map_update_timer(struct thread *thread)
@@ -3172,7 +3171,7 @@ static void bgp_route_map_mark_update(const char *rmap_name)
 
 static void bgp_route_map_add(const char *rmap_name)
 {
-       if (route_map_mark_updated(rmap_name, 0) == 0)
+       if (route_map_mark_updated(rmap_name) == 0)
                bgp_route_map_mark_update(rmap_name);
 
        route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED);
@@ -3180,7 +3179,7 @@ static void bgp_route_map_add(const char *rmap_name)
 
 static void bgp_route_map_delete(const char *rmap_name)
 {
-       if (route_map_mark_updated(rmap_name, 1) == 0)
+       if (route_map_mark_updated(rmap_name) == 0)
                bgp_route_map_mark_update(rmap_name);
 
        route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_DELETED);
@@ -3188,7 +3187,7 @@ static void bgp_route_map_delete(const char *rmap_name)
 
 static void bgp_route_map_event(route_map_event_t event, const char *rmap_name)
 {
-       if (route_map_mark_updated(rmap_name, 0) == 0)
+       if (route_map_mark_updated(rmap_name) == 0)
                bgp_route_map_mark_update(rmap_name);
 
        route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED);
index a23d5d03c4a06599ea1ed08da7b70c2306340e9a..82e857dbf4e426560fd6cde0919fd619e7e47efe 100644 (file)
@@ -158,6 +158,30 @@ static void free_wrapper(void *ptr)
        XFREE(MTYPE_BGP_RPKI_CACHE, ptr);
 }
 
+static void init_tr_socket(struct cache *cache)
+{
+       if (cache->type == TCP)
+               tr_tcp_init(cache->tr_config.tcp_config,
+                           cache->tr_socket);
+#if defined(FOUND_SSH)
+       else
+               tr_ssh_init(cache->tr_config.ssh_config,
+                           cache->tr_socket);
+#endif
+}
+
+static void free_tr_socket(struct cache *cache)
+{
+       if (cache->type == TCP)
+               tr_tcp_init(cache->tr_config.tcp_config,
+                           cache->tr_socket);
+#if defined(FOUND_SSH)
+       else
+               tr_ssh_init(cache->tr_config.ssh_config,
+                           cache->tr_socket);
+#endif
+}
+
 static int rpki_validate_prefix(struct peer *peer, struct attr *attr,
                                struct prefix *prefix);
 
@@ -253,14 +277,7 @@ static struct rtr_mgr_group *get_groups(void)
                rtr_mgr_groups[i].sockets_len = 1;
                rtr_mgr_groups[i].preference = cache->preference;
 
-               if (cache->type == TCP)
-                       tr_tcp_init(cache->tr_config.tcp_config,
-                                   cache->tr_socket);
-#if defined(FOUND_SSH)
-               else
-                       tr_ssh_init(cache->tr_config.ssh_config,
-                                   cache->tr_socket);
-#endif
+               init_tr_socket(cache);
 
                i++;
        }
@@ -384,7 +401,7 @@ static int reset(bool force)
 
 static struct rtr_mgr_group *get_connected_group(void)
 {
-       if (list_isempty(cache_list))
+       if (!cache_list || list_isempty(cache_list))
                return NULL;
 
        return rtr_mgr_get_first_group(rtr_config);
@@ -517,9 +534,13 @@ static int add_cache(struct cache *cache)
 
        listnode_add(cache_list, cache);
 
-       if (rtr_is_running
-           && rtr_mgr_add_group(rtr_config, &group) != RTR_SUCCESS) {
-               return ERROR;
+       if (rtr_is_running) {
+               init_tr_socket(cache);
+
+               if (rtr_mgr_add_group(rtr_config, &group) != RTR_SUCCESS) {
+                       free_tr_socket(cache);
+                       return ERROR;
+               }
        }
 
        return SUCCESS;
index 241b23a62db758d0320aa046ed9ca2c5e537faed..0700e0ac242e63003431c82ee1d934ba1e611aee 100644 (file)
@@ -487,17 +487,17 @@ static int write_bgpPeerTable(int action, uint8_t *var_val,
                        return SNMP_ERR_NOSUCHNAME;
                break;
        case BGPPEERCONNECTRETRYINTERVAL:
-               SET_FLAG(peer->config, PEER_CONFIG_CONNECT);
+               peer_flag_set(peer, PEER_FLAG_TIMER_CONNECT);
                peer->connect = intval;
                peer->v_connect = intval;
                break;
        case BGPPEERHOLDTIMECONFIGURED:
-               SET_FLAG(peer->config, PEER_CONFIG_TIMER);
+               peer_flag_set(peer, PEER_FLAG_TIMER);
                peer->holdtime = intval;
                peer->v_holdtime = intval;
                break;
        case BGPPEERKEEPALIVECONFIGURED:
-               SET_FLAG(peer->config, PEER_CONFIG_TIMER);
+               peer_flag_set(peer, PEER_FLAG_TIMER);
                peer->keepalive = intval;
                peer->v_keepalive = intval;
                break;
@@ -617,14 +617,14 @@ static uint8_t *bgpPeerTable(struct variable *v, oid name[], size_t *length,
                break;
        case BGPPEERHOLDTIMECONFIGURED:
                *write_method = write_bgpPeerTable;
-               if (PEER_OR_GROUP_TIMER_SET(peer))
+               if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER))
                        return SNMP_INTEGER(peer->holdtime);
                else
                        return SNMP_INTEGER(peer->v_holdtime);
                break;
        case BGPPEERKEEPALIVECONFIGURED:
                *write_method = write_bgpPeerTable;
-               if (PEER_OR_GROUP_TIMER_SET(peer))
+               if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER))
                        return SNMP_INTEGER(peer->keepalive);
                else
                        return SNMP_INTEGER(peer->v_keepalive);
index c607c4577d34dbb8cf7de6cbe3e046e48b8c4604..6a65f982e0d071f1095c10a2f2d837023453364c 100644 (file)
@@ -905,7 +905,7 @@ static void update_subgroup_add_peer(struct update_subgroup *subgrp,
 static void update_subgroup_remove_peer_internal(struct update_subgroup *subgrp,
                                                 struct peer_af *paf)
 {
-       assert(subgrp && paf);
+       assert(subgrp && paf && subgrp->update_group);
 
        if (bgp_debug_peer_updout_enabled(paf->peer->host)) {
                UPDGRP_PEER_DBG_DIS(subgrp->update_group);
index cabd5b5cbd795027ae9a4797a2b2e17abce90d4f..34ddbfcd14171db41b90934ff5acf73dddee0aa8 100644 (file)
@@ -397,7 +397,7 @@ struct stream *bpacket_reformat_for_peer(struct bpacket *pkt,
        vec = &pkt->arr.entries[BGP_ATTR_VEC_NH];
        if (CHECK_FLAG(vec->flags, BPKT_ATTRVEC_FLAGS_UPDATED)) {
                uint8_t nhlen;
-               afi_t nhafi = AFI_MAX; /* NH AFI is based on nhlen! */
+               afi_t nhafi;
                int route_map_sets_nh;
                nhlen = stream_getc_from(s, vec->offset);
                if (peer_cap_enhe(peer, paf->afi, paf->safi))
index 80bd2cd7990b7bb967d9f1b6f53e7f089b2c8e95..a771eedf0f74019bc78790bbf23b9821782609ba 100644 (file)
@@ -125,7 +125,7 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer,
 
                                        if (rd_header) {
                                                uint16_t type;
-                                               struct rd_as rd_as;
+                                               struct rd_as rd_as = {0};
                                                struct rd_ip rd_ip = {0};
 #if ENABLE_BGP_VNC
                                                struct rd_vnc_eth rd_vnc_eth = {
@@ -223,23 +223,27 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer,
                                                }
                                                rd_header = 0;
                                        }
-                                       route_vty_out_tmp(vty, &rm->p, attr,
-                                                         SAFI_MPLS_VPN,
-                                                         use_json, json_array);
+                                       if (use_json) {
+                                               char buf_a[BUFSIZ];
+                                               char buf_b[BUFSIZ];
+
+                                               sprintf(buf_a, "%s/%d",
+                                                       inet_ntop(rm->p.family,
+                                                                 rm->p.u.val,
+                                                                 buf_b,
+                                                                 BUFSIZ),
+                                                       rm->p.prefixlen);
+                                               json_object_object_add(
+                                                       json_routes, buf_a,
+                                                       json_array);
+                                       } else {
+                                               route_vty_out_tmp(
+                                                       vty, &rm->p, attr,
+                                                       SAFI_MPLS_VPN, use_json,
+                                                       json_array);
+                                       }
                                }
                        }
-                       if (use_json) {
-                               struct prefix *p;
-                               char buf_a[BUFSIZ];
-                               char buf_b[BUFSIZ];
-                               p = &rm->p;
-                               sprintf(buf_a, "%s/%d",
-                                       inet_ntop(p->family, &p->u.prefix,
-                                                 buf_b, BUFSIZ),
-                                       p->prefixlen);
-                               json_object_object_add(json_routes, buf_a,
-                                                      json_array);
-                       }
                }
        }
        if (use_json) {
index c1851a3e026ffe134dbb1f6fedd496177254ca78..86f3f97c4934f7eb04197e50eea2c9d6baa2c5a8 100644 (file)
@@ -34,6 +34,7 @@
 #include "hash.h"
 #include "queue.h"
 #include "filter.h"
+#include "frrstr.h"
 
 #include "bgpd/bgpd.h"
 #include "bgpd/bgp_advertise.h"
@@ -2008,27 +2009,19 @@ DEFUN (no_bgp_fast_external_failover,
 CPP_NOTICE("bgpd: remove deprecated '[no] bgp enforce-first-as' commands")
 #endif
 
-DEFUN_DEPRECATED (bgp_enforce_first_as,
-       bgp_enforce_first_as_cmd,
-       "bgp enforce-first-as",
-       BGP_STR
-       "Enforce the first AS for EBGP routes\n")
+DEFUN_HIDDEN (bgp_enforce_first_as,
+             bgp_enforce_first_as_cmd,
+             "[no] bgp enforce-first-as",
+             NO_STR
+             BGP_STR
+             "Enforce the first AS for EBGP routes\n")
 {
        VTY_DECLVAR_CONTEXT(bgp, bgp);
-       bgp_flag_set(bgp, BGP_FLAG_ENFORCE_FIRST_AS);
-
-       return CMD_SUCCESS;
-}
 
-DEFUN_DEPRECATED (no_bgp_enforce_first_as,
-       no_bgp_enforce_first_as_cmd,
-       "no bgp enforce-first-as",
-       NO_STR
-       BGP_STR
-       "Enforce the first AS for EBGP routes\n")
-{
-       VTY_DECLVAR_CONTEXT(bgp, bgp);
-       bgp_flag_unset(bgp, BGP_FLAG_ENFORCE_FIRST_AS);
+       if (strmatch(argv[0]->text, "no"))
+               bgp_flag_unset(bgp, BGP_FLAG_ENFORCE_FIRST_AS);
+       else
+               bgp_flag_set(bgp, BGP_FLAG_ENFORCE_FIRST_AS);
 
        return CMD_SUCCESS;
 }
@@ -2832,7 +2825,7 @@ static int peer_conf_interface_get(struct vty *vty, const char *conf_if,
                }
 
                if (v6only)
-                       SET_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY);
+                       peer_flag_set(peer, PEER_FLAG_IFPEER_V6ONLY);
 
                /* Request zebra to initiate IPv6 RAs on this interface. We do
                 * this
@@ -2849,9 +2842,9 @@ static int peer_conf_interface_get(struct vty *vty, const char *conf_if,
        if ((v6only && !CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY))
            || (!v6only && CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY))) {
                if (v6only)
-                       SET_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY);
+                       peer_flag_set(peer, PEER_FLAG_IFPEER_V6ONLY);
                else
-                       UNSET_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY);
+                       peer_flag_unset(peer, PEER_FLAG_IFPEER_V6ONLY);
 
                /* v6only flag changed. Reset bgp seesion */
                if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
@@ -2862,8 +2855,11 @@ static int peer_conf_interface_get(struct vty *vty, const char *conf_if,
                        bgp_session_reset(peer);
        }
 
-       if (!CHECK_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE))
-               peer_flag_set(peer, PEER_FLAG_CAPABILITY_ENHE);
+       if (!CHECK_FLAG(peer->flags_invert, PEER_FLAG_CAPABILITY_ENHE)) {
+               SET_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE);
+               SET_FLAG(peer->flags_invert, PEER_FLAG_CAPABILITY_ENHE);
+               UNSET_FLAG(peer->flags_override, PEER_FLAG_CAPABILITY_ENHE);
+       }
 
        if (peer_group_name) {
                group = peer_group_lookup(bgp, peer_group_name);
@@ -4652,12 +4648,11 @@ DEFUN (neighbor_description,
 
 DEFUN (no_neighbor_description,
        no_neighbor_description_cmd,
-       "no neighbor <A.B.C.D|X:X::X:X|WORD> description [LINE]",
+       "no neighbor <A.B.C.D|X:X::X:X|WORD> description",
        NO_STR
        NEIGHBOR_STR
        NEIGHBOR_ADDR_STR2
-       "Neighbor specific description\n"
-       "Up to 80 characters describing this neighbor\n")
+       "Neighbor specific description\n")
 {
        int idx_peer = 2;
        struct peer *peer;
@@ -4671,6 +4666,11 @@ DEFUN (no_neighbor_description,
        return CMD_SUCCESS;
 }
 
+ALIAS(no_neighbor_description, no_neighbor_description_comment_cmd,
+      "no neighbor <A.B.C.D|X:X::X:X|WORD> description LINE...",
+      NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
+      "Neighbor specific description\n"
+      "Up to 80 characters describing this neighbor\n")
 
 /* Neighbor update-source. */
 static int peer_update_source_vty(struct vty *vty, const char *peer_str,
@@ -4678,6 +4678,7 @@ static int peer_update_source_vty(struct vty *vty, const char *peer_str,
 {
        struct peer *peer;
        struct prefix p;
+       union sockunion su;
 
        peer = peer_and_group_lookup_vty(vty, peer_str);
        if (!peer)
@@ -4687,10 +4688,7 @@ static int peer_update_source_vty(struct vty *vty, const char *peer_str,
                return CMD_WARNING;
 
        if (source_str) {
-               union sockunion su;
-               int ret = str2sockunion(source_str, &su);
-
-               if (ret == 0)
+               if (str2sockunion(source_str, &su) == 0)
                        peer_update_source_addr_set(peer, &su);
                else {
                        if (str2prefix(source_str, &p)) {
@@ -4980,26 +4978,28 @@ DEFUN (no_neighbor_override_capability,
 
 DEFUN (neighbor_strict_capability,
        neighbor_strict_capability_cmd,
-       "neighbor <A.B.C.D|X:X::X:X> strict-capability-match",
+       "neighbor <A.B.C.D|X:X::X:X|WORD> strict-capability-match",
        NEIGHBOR_STR
-       NEIGHBOR_ADDR_STR
+       NEIGHBOR_ADDR_STR2
        "Strict capability negotiation match\n")
 {
-       int idx_ip = 1;
-       return peer_flag_set_vty(vty, argv[idx_ip]->arg,
+       int idx_peer = 1;
+
+       return peer_flag_set_vty(vty, argv[idx_peer]->arg,
                                 PEER_FLAG_STRICT_CAP_MATCH);
 }
 
 DEFUN (no_neighbor_strict_capability,
        no_neighbor_strict_capability_cmd,
-       "no neighbor <A.B.C.D|X:X::X:X> strict-capability-match",
+       "no neighbor <A.B.C.D|X:X::X:X|WORD> strict-capability-match",
        NO_STR
        NEIGHBOR_STR
-       NEIGHBOR_ADDR_STR
+       NEIGHBOR_ADDR_STR2
        "Strict capability negotiation match\n")
 {
-       int idx_ip = 2;
-       return peer_flag_unset_vty(vty, argv[idx_ip]->arg,
+       int idx_peer = 2;
+
+       return peer_flag_unset_vty(vty, argv[idx_peer]->arg,
                                   PEER_FLAG_STRICT_CAP_MATCH);
 }
 
@@ -6737,6 +6737,11 @@ DEFPY (bgp_imexport_vrf,
        safi_t safi;
        afi_t afi;
 
+       if (import_name == NULL) {
+               vty_out(vty, "%% Missing import name\n");
+               return CMD_WARNING;
+       }
+
        if (argv_find(argv, argc, "no", &idx))
                remove = true;
 
@@ -7067,7 +7072,7 @@ static int bgp_clear_prefix(struct vty *vty, const char *view_name,
                                    != NULL) {
                                        if (rm->p.prefixlen
                                            == match.prefixlen) {
-                                               SET_FLAG(rn->flags,
+                                               SET_FLAG(rm->flags,
                                                         BGP_NODE_USER_CLEAR);
                                                bgp_process(bgp, rm, afi, safi);
                                        }
@@ -7930,6 +7935,11 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
                        if (CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN))
                                json_object_string_add(json_peer, "state",
                                                       "Idle (Admin)");
+                       else if (peer->afc_recv[afi][safi])
+                               json_object_string_add(
+                                       json_peer, "state",
+                                       lookup_msg(bgp_status_msg, peer->status,
+                                                  NULL));
                        else if (CHECK_FLAG(peer->sflags,
                                            PEER_STATUS_PREFIX_OVERFLOW))
                                json_object_string_add(json_peer, "state",
@@ -9186,8 +9196,7 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, uint8_t use_json,
                json_object_int_add(json_neigh,
                                    "bgpTimerKeepAliveIntervalMsecs",
                                    p->v_keepalive * 1000);
-
-               if (PEER_OR_GROUP_TIMER_SET(p)) {
+               if (CHECK_FLAG(p->flags, PEER_FLAG_TIMER)) {
                        json_object_int_add(json_neigh,
                                            "bgpTimerConfiguredHoldTimeMsecs",
                                            p->holdtime * 1000);
@@ -9251,7 +9260,7 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, uint8_t use_json,
                vty_out(vty,
                        "  Hold time is %d, keepalive interval is %d seconds\n",
                        p->v_holdtime, p->v_keepalive);
-               if (PEER_OR_GROUP_TIMER_SET(p)) {
+               if (CHECK_FLAG(p->flags, PEER_FLAG_TIMER)) {
                        vty_out(vty, "  Configured hold time is %d",
                                p->holdtime);
                        vty_out(vty, ", keepalive interval is %d seconds\n",
@@ -11402,7 +11411,6 @@ DEFUN (show_ip_bgp_peer_groups,
        "Peer group name\n")
 {
        char *vrf, *pg;
-       vrf = pg = NULL;
        int idx = 0;
 
        vrf = argv_find(argv, argc, "VIEWVRFNAME", &idx) ? argv[idx]->arg
@@ -12433,7 +12441,6 @@ void bgp_vty_init(void)
 
        /* "bgp enforce-first-as" commands */
        install_element(BGP_NODE, &bgp_enforce_first_as_cmd);
-       install_element(BGP_NODE, &no_bgp_enforce_first_as_cmd);
 
        /* "bgp bestpath compare-routerid" commands */
        install_element(BGP_NODE, &bgp_bestpath_compare_router_id_cmd);
@@ -13026,6 +13033,7 @@ void bgp_vty_init(void)
        /* "neighbor description" commands. */
        install_element(BGP_NODE, &neighbor_description_cmd);
        install_element(BGP_NODE, &no_neighbor_description_cmd);
+       install_element(BGP_NODE, &no_neighbor_description_comment_cmd);
 
        /* "neighbor update-source" commands. "*/
        install_element(BGP_NODE, &neighbor_update_source_cmd);
index 2d808a6ffb2548e90be34b97b85e85242a34b60d..df3f9ddd6fd51c2b207b2b177ea79e01a9406406 100644 (file)
@@ -2219,6 +2219,12 @@ static void bgp_encode_pbr_iptable_match(struct stream *s,
        stream_putl(s, bpa->fwmark);
        stream_put(s, pbm->ipset_name,
                   ZEBRA_IPSET_NAME_SIZE);
+       stream_putw(s, pbm->pkt_len_min);
+       stream_putw(s, pbm->pkt_len_max);
+       stream_putw(s, pbm->tcp_flags);
+       stream_putw(s, pbm->tcp_mask_flags);
+       stream_putc(s, pbm->dscp_value);
+       stream_putc(s, pbm->fragment);
 }
 
 /* BGP has established connection with Zebra. */
index 5bae542f892bbdddcade9e553e78b3e23c2f92e7..283949ab2a709bf60a3ad5449db3e82e17f73d2c 100644 (file)
@@ -783,6 +783,30 @@ static int peer_hash_same(const void *p1, const void *p2)
                           == CHECK_FLAG(peer2->flags, PEER_FLAG_CONFIG_NODE));
 }
 
+void peer_flag_inherit(struct peer *peer, uint32_t flag)
+{
+       bool group_val;
+
+       /* Skip if peer is not a peer-group member. */
+       if (!peer_group_active(peer))
+               return;
+
+       /* Unset override flag to signal inheritance from peer-group. */
+       UNSET_FLAG(peer->flags_override, flag);
+
+       /*
+        * Inherit flag state from peer-group. If the flag of the peer-group is
+        * not being inverted, the peer must inherit the inverse of the current
+        * peer-group flag state.
+        */
+       group_val = CHECK_FLAG(peer->group->conf->flags, flag);
+       if (!CHECK_FLAG(peer->group->conf->flags_invert, flag)
+           && CHECK_FLAG(peer->flags_invert, flag))
+               COND_FLAG(peer->flags, flag, !group_val);
+       else
+               COND_FLAG(peer->flags, flag, group_val);
+}
+
 int peer_af_flag_check(struct peer *peer, afi_t afi, safi_t safi, uint32_t flag)
 {
        return CHECK_FLAG(peer->af_flags[afi][safi], flag);
@@ -791,6 +815,8 @@ int peer_af_flag_check(struct peer *peer, afi_t afi, safi_t safi, uint32_t flag)
 void peer_af_flag_inherit(struct peer *peer, afi_t afi, safi_t safi,
                          uint32_t flag)
 {
+       bool group_val;
+
        /* Skip if peer is not a peer-group member. */
        if (!peer_group_active(peer))
                return;
@@ -798,11 +824,29 @@ void peer_af_flag_inherit(struct peer *peer, afi_t afi, safi_t safi,
        /* Unset override flag to signal inheritance from peer-group. */
        UNSET_FLAG(peer->af_flags_override[afi][safi], flag);
 
-       /* Inherit flag state from peer-group. */
-       if (CHECK_FLAG(peer->group->conf->af_flags[afi][safi], flag))
-               SET_FLAG(peer->af_flags[afi][safi], flag);
+       /*
+        * Inherit flag state from peer-group. If the flag of the peer-group is
+        * not being inverted, the peer must inherit the inverse of the current
+        * peer-group flag state.
+        */
+       group_val = CHECK_FLAG(peer->group->conf->af_flags[afi][safi], flag);
+       if (!CHECK_FLAG(peer->group->conf->af_flags_invert[afi][safi], flag)
+           && CHECK_FLAG(peer->af_flags_invert[afi][safi], flag))
+               COND_FLAG(peer->af_flags[afi][safi], flag, !group_val);
        else
-               UNSET_FLAG(peer->af_flags[afi][safi], flag);
+               COND_FLAG(peer->af_flags[afi][safi], flag, group_val);
+}
+
+static bool peergroup_flag_check(struct peer *peer, uint32_t flag)
+{
+       if (!peer_group_active(peer)) {
+               if (CHECK_FLAG(peer->flags_invert, flag))
+                       return !CHECK_FLAG(peer->flags, flag);
+               else
+                       return !!CHECK_FLAG(peer->flags, flag);
+       }
+
+       return !!CHECK_FLAG(peer->flags_override, flag);
 }
 
 static bool peergroup_af_flag_check(struct peer *peer, afi_t afi, safi_t safi,
@@ -949,7 +993,6 @@ static void peer_global_config_reset(struct peer *peer)
        peer->flags = 0;
        SET_FLAG(peer->flags, saved_flags);
 
-       peer->config = 0;
        peer->holdtime = 0;
        peer->keepalive = 0;
        peer->connect = 0;
@@ -989,6 +1032,8 @@ static inline bgp_peer_sort_t peer_calc_sort(struct peer *peer)
 
                else {
                        struct peer *peer1;
+
+                       assert(peer->group);
                        peer1 = listnode_head(peer->group->peer);
 
                        if (peer1)
@@ -1265,7 +1310,6 @@ void peer_xfer_config(struct peer *peer_dst, struct peer *peer_src)
        /* peer flags apply */
        peer_dst->flags = peer_src->flags;
        peer_dst->cap = peer_src->cap;
-       peer_dst->config = peer_src->config;
 
        peer_dst->local_as = peer_src->local_as;
        peer_dst->port = peer_src->port;
@@ -1289,8 +1333,6 @@ void peer_xfer_config(struct peer *peer_dst, struct peer *peer_src)
        FOREACH_AFI_SAFI (afi, safi) {
                peer_dst->afc[afi][safi] = peer_src->afc[afi][safi];
                peer_dst->af_flags[afi][safi] = peer_src->af_flags[afi][safi];
-               peer_dst->af_flags_invert[afi][safi] =
-                       peer_src->af_flags_invert[afi][safi];
                peer_dst->allowas_in[afi][safi] =
                        peer_src->allowas_in[afi][safi];
                peer_dst->weight[afi][safi] = peer_src->weight[afi][safi];
@@ -1454,10 +1496,12 @@ void bgp_peer_conf_if_to_su_update(struct peer *peer)
         * needed.
         */
        if (peer_addr_updated) {
-               if (peer->password && prev_family == AF_UNSPEC)
+               if (CHECK_FLAG(peer->flags, PEER_FLAG_PASSWORD)
+                   && prev_family == AF_UNSPEC)
                        bgp_md5_set(peer);
        } else {
-               if (peer->password && prev_family != AF_UNSPEC)
+               if (CHECK_FLAG(peer->flags, PEER_FLAG_PASSWORD)
+                   && prev_family != AF_UNSPEC)
                        bgp_md5_unset(peer);
                peer->su.sa.sa_family = AF_UNSPEC;
                memset(&peer->su.sin6.sin6_addr, 0, sizeof(struct in6_addr));
@@ -1534,10 +1578,9 @@ struct peer *peer_create(union sockunion *su, const char *conf_if,
        peer->local_id = bgp->router_id;
        peer->v_holdtime = bgp->default_holdtime;
        peer->v_keepalive = bgp->default_keepalive;
-       if (peer_sort(peer) == BGP_PEER_IBGP)
-               peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV;
-       else
-               peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
+       peer->v_routeadv = (peer_sort(peer) == BGP_PEER_IBGP)
+                                  ? BGP_DEFAULT_IBGP_ROUTEADV
+                                  : BGP_DEFAULT_EBGP_ROUTEADV;
 
        peer = peer_lock(peer); /* bgp peer list reference */
        peer->group = group;
@@ -1613,7 +1656,6 @@ int bgp_afi_safi_peer_exists(struct bgp *bgp, afi_t afi, safi_t safi)
 void peer_as_change(struct peer *peer, as_t as, int as_specified)
 {
        bgp_peer_sort_t type;
-       struct peer *conf;
 
        /* Stop peer. */
        if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
@@ -1636,22 +1678,12 @@ void peer_as_change(struct peer *peer, as_t as, int as_specified)
                peer->local_as = peer->bgp->as;
 
        /* Advertisement-interval reset */
-       conf = NULL;
-       if (peer->group)
-               conf = peer->group->conf;
-
-       if (conf && CHECK_FLAG(conf->config, PEER_CONFIG_ROUTEADV)) {
-               peer->v_routeadv = conf->routeadv;
-       }
-       /* Only go back to the default advertisement-interval if the user had
-        * not
-        * already configured it */
-       else if (!CHECK_FLAG(peer->config, PEER_CONFIG_ROUTEADV)) {
-               if (peer_sort(peer) == BGP_PEER_IBGP)
-                       peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV;
-               else
-                       peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
+       if (!CHECK_FLAG(peer->flags, PEER_FLAG_ROUTEADV)) {
+               peer->v_routeadv = (peer_sort(peer) == BGP_PEER_IBGP)
+                                          ? BGP_DEFAULT_IBGP_ROUTEADV
+                                          : BGP_DEFAULT_EBGP_ROUTEADV;
        }
+
        /* TTL reset */
        if (peer_sort(peer) == BGP_PEER_IBGP)
                peer->ttl = MAXTTL;
@@ -1691,8 +1723,9 @@ void peer_as_change(struct peer *peer, as_t as, int as_specified)
        /* local-as reset */
        if (peer_sort(peer) != BGP_PEER_EBGP) {
                peer->change_local_as = 0;
-               UNSET_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
-               UNSET_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
+               peer_flag_unset(peer, PEER_FLAG_LOCAL_AS);
+               peer_flag_unset(peer, PEER_FLAG_LOCAL_AS_NO_PREPEND);
+               peer_flag_unset(peer, PEER_FLAG_LOCAL_AS_REPLACE_AS);
        }
 }
 
@@ -1776,141 +1809,119 @@ static void peer_group2peer_config_copy_af(struct peer_group *group,
 {
        int in = FILTER_IN;
        int out = FILTER_OUT;
+       uint32_t flags_tmp;
+       uint32_t pflags_ovrd;
+       uint8_t *pfilter_ovrd;
        struct peer *conf;
-       struct bgp_filter *pfilter;
-       struct bgp_filter *gfilter;
 
        conf = group->conf;
-       pfilter = &peer->filter[afi][safi];
-       gfilter = &conf->filter[afi][safi];
+       pflags_ovrd = peer->af_flags_override[afi][safi];
+       pfilter_ovrd = &peer->filter_override[afi][safi][in];
 
        /* peer af_flags apply */
-       peer->af_flags[afi][safi] = conf->af_flags[afi][safi];
-       peer->af_flags_invert[afi][safi] = conf->af_flags_invert[afi][safi];
+       flags_tmp = conf->af_flags[afi][safi] & ~pflags_ovrd;
+       flags_tmp ^= conf->af_flags_invert[afi][safi]
+                    ^ peer->af_flags_invert[afi][safi];
+       flags_tmp &= ~pflags_ovrd;
+
+       UNSET_FLAG(peer->af_flags[afi][safi], ~pflags_ovrd);
+       SET_FLAG(peer->af_flags[afi][safi], flags_tmp);
+       SET_FLAG(peer->af_flags_invert[afi][safi],
+                conf->af_flags_invert[afi][safi]);
 
        /* maximum-prefix */
-       peer->pmax[afi][safi] = conf->pmax[afi][safi];
-       peer->pmax_threshold[afi][safi] = conf->pmax_threshold[afi][safi];
-       peer->pmax_restart[afi][safi] = conf->pmax_restart[afi][safi];
+       if (!CHECK_FLAG(pflags_ovrd, PEER_FLAG_MAX_PREFIX)) {
+               PEER_ATTR_INHERIT(peer, group, pmax[afi][safi]);
+               PEER_ATTR_INHERIT(peer, group, pmax_threshold[afi][safi]);
+               PEER_ATTR_INHERIT(peer, group, pmax_restart[afi][safi]);
+       }
 
        /* allowas-in */
-       peer->allowas_in[afi][safi] = conf->allowas_in[afi][safi];
+       if (!CHECK_FLAG(pflags_ovrd, PEER_FLAG_ALLOWAS_IN))
+               PEER_ATTR_INHERIT(peer, group, allowas_in[afi][safi]);
 
        /* weight */
-       peer->weight[afi][safi] = conf->weight[afi][safi];
+       if (!CHECK_FLAG(pflags_ovrd, PEER_FLAG_WEIGHT))
+               PEER_ATTR_INHERIT(peer, group, weight[afi][safi]);
 
        /* default-originate route-map */
-       if (conf->default_rmap[afi][safi].name) {
-               if (peer->default_rmap[afi][safi].name)
-                       XFREE(MTYPE_BGP_FILTER_NAME,
-                             peer->default_rmap[afi][safi].name);
-               peer->default_rmap[afi][safi].name =
-                       XSTRDUP(MTYPE_BGP_FILTER_NAME,
-                               conf->default_rmap[afi][safi].name);
-               peer->default_rmap[afi][safi].map =
-                       conf->default_rmap[afi][safi].map;
+       if (!CHECK_FLAG(pflags_ovrd, PEER_FLAG_DEFAULT_ORIGINATE)) {
+               PEER_STR_ATTR_INHERIT(peer, group, default_rmap[afi][safi].name,
+                                     MTYPE_ROUTE_MAP_NAME);
+               PEER_ATTR_INHERIT(peer, group, default_rmap[afi][safi].map);
        }
 
        /* inbound filter apply */
-       if (gfilter->dlist[in].name && !pfilter->dlist[in].name) {
-               if (pfilter->dlist[in].name)
-                       XFREE(MTYPE_BGP_FILTER_NAME, pfilter->dlist[in].name);
-               pfilter->dlist[in].name =
-                       XSTRDUP(MTYPE_BGP_FILTER_NAME, gfilter->dlist[in].name);
-               pfilter->dlist[in].alist = gfilter->dlist[in].alist;
+       if (!CHECK_FLAG(pfilter_ovrd[in], PEER_FT_DISTRIBUTE_LIST)) {
+               PEER_STR_ATTR_INHERIT(peer, group,
+                                     filter[afi][safi].dlist[in].name,
+                                     MTYPE_BGP_FILTER_NAME);
+               PEER_ATTR_INHERIT(peer, group,
+                                 filter[afi][safi].dlist[in].alist);
        }
 
-       if (gfilter->plist[in].name && !pfilter->plist[in].name) {
-               if (pfilter->plist[in].name)
-                       XFREE(MTYPE_BGP_FILTER_NAME, pfilter->plist[in].name);
-               pfilter->plist[in].name =
-                       XSTRDUP(MTYPE_BGP_FILTER_NAME, gfilter->plist[in].name);
-               pfilter->plist[in].plist = gfilter->plist[in].plist;
+       if (!CHECK_FLAG(pfilter_ovrd[in], PEER_FT_PREFIX_LIST)) {
+               PEER_STR_ATTR_INHERIT(peer, group,
+                                     filter[afi][safi].plist[in].name,
+                                     MTYPE_BGP_FILTER_NAME);
+               PEER_ATTR_INHERIT(peer, group,
+                                 filter[afi][safi].plist[in].plist);
        }
 
-       if (gfilter->aslist[in].name && !pfilter->aslist[in].name) {
-               if (pfilter->aslist[in].name)
-                       XFREE(MTYPE_BGP_FILTER_NAME, pfilter->aslist[in].name);
-               pfilter->aslist[in].name = XSTRDUP(MTYPE_BGP_FILTER_NAME,
-                                                  gfilter->aslist[in].name);
-               pfilter->aslist[in].aslist = gfilter->aslist[in].aslist;
+       if (!CHECK_FLAG(pfilter_ovrd[in], PEER_FT_FILTER_LIST)) {
+               PEER_STR_ATTR_INHERIT(peer, group,
+                                     filter[afi][safi].aslist[in].name,
+                                     MTYPE_BGP_FILTER_NAME);
+               PEER_ATTR_INHERIT(peer, group,
+                                 filter[afi][safi].aslist[in].aslist);
        }
 
-       if (gfilter->map[RMAP_IN].name && !pfilter->map[RMAP_IN].name) {
-               if (pfilter->map[RMAP_IN].name)
-                       XFREE(MTYPE_BGP_FILTER_NAME,
-                             pfilter->map[RMAP_IN].name);
-               pfilter->map[RMAP_IN].name = XSTRDUP(
-                       MTYPE_BGP_FILTER_NAME, gfilter->map[RMAP_IN].name);
-               pfilter->map[RMAP_IN].map = gfilter->map[RMAP_IN].map;
+       if (!CHECK_FLAG(pfilter_ovrd[RMAP_IN], PEER_FT_ROUTE_MAP)) {
+               PEER_STR_ATTR_INHERIT(peer, group,
+                                     filter[afi][safi].map[in].name,
+                                     MTYPE_BGP_FILTER_NAME);
+               PEER_ATTR_INHERIT(peer, group,
+                                 filter[afi][safi].map[RMAP_IN].map);
        }
 
        /* outbound filter apply */
-       if (gfilter->dlist[out].name) {
-               if (pfilter->dlist[out].name)
-                       XFREE(MTYPE_BGP_FILTER_NAME, pfilter->dlist[out].name);
-               pfilter->dlist[out].name = XSTRDUP(MTYPE_BGP_FILTER_NAME,
-                                                  gfilter->dlist[out].name);
-               pfilter->dlist[out].alist = gfilter->dlist[out].alist;
-       } else {
-               if (pfilter->dlist[out].name)
-                       XFREE(MTYPE_BGP_FILTER_NAME, pfilter->dlist[out].name);
-               pfilter->dlist[out].name = NULL;
-               pfilter->dlist[out].alist = NULL;
-       }
-
-       if (gfilter->plist[out].name) {
-               if (pfilter->plist[out].name)
-                       XFREE(MTYPE_BGP_FILTER_NAME, pfilter->plist[out].name);
-               pfilter->plist[out].name = XSTRDUP(MTYPE_BGP_FILTER_NAME,
-                                                  gfilter->plist[out].name);
-               pfilter->plist[out].plist = gfilter->plist[out].plist;
-       } else {
-               if (pfilter->plist[out].name)
-                       XFREE(MTYPE_BGP_FILTER_NAME, pfilter->plist[out].name);
-               pfilter->plist[out].name = NULL;
-               pfilter->plist[out].plist = NULL;
-       }
-
-       if (gfilter->aslist[out].name) {
-               if (pfilter->aslist[out].name)
-                       XFREE(MTYPE_BGP_FILTER_NAME, pfilter->aslist[out].name);
-               pfilter->aslist[out].name = XSTRDUP(MTYPE_BGP_FILTER_NAME,
-                                                   gfilter->aslist[out].name);
-               pfilter->aslist[out].aslist = gfilter->aslist[out].aslist;
-       } else {
-               if (pfilter->aslist[out].name)
-                       XFREE(MTYPE_BGP_FILTER_NAME, pfilter->aslist[out].name);
-               pfilter->aslist[out].name = NULL;
-               pfilter->aslist[out].aslist = NULL;
+       if (!CHECK_FLAG(pfilter_ovrd[out], PEER_FT_DISTRIBUTE_LIST)) {
+               PEER_STR_ATTR_INHERIT(peer, group,
+                                     filter[afi][safi].dlist[out].name,
+                                     MTYPE_BGP_FILTER_NAME);
+               PEER_ATTR_INHERIT(peer, group,
+                                 filter[afi][safi].dlist[out].alist);
        }
 
-       if (gfilter->map[RMAP_OUT].name) {
-               if (pfilter->map[RMAP_OUT].name)
-                       XFREE(MTYPE_BGP_FILTER_NAME,
-                             pfilter->map[RMAP_OUT].name);
-               pfilter->map[RMAP_OUT].name = XSTRDUP(
-                       MTYPE_BGP_FILTER_NAME, gfilter->map[RMAP_OUT].name);
-               pfilter->map[RMAP_OUT].map = gfilter->map[RMAP_OUT].map;
-       } else {
-               if (pfilter->map[RMAP_OUT].name)
-                       XFREE(MTYPE_BGP_FILTER_NAME,
-                             pfilter->map[RMAP_OUT].name);
-               pfilter->map[RMAP_OUT].name = NULL;
-               pfilter->map[RMAP_OUT].map = NULL;
+       if (!CHECK_FLAG(pfilter_ovrd[out], PEER_FT_PREFIX_LIST)) {
+               PEER_STR_ATTR_INHERIT(peer, group,
+                                     filter[afi][safi].plist[out].name,
+                                     MTYPE_BGP_FILTER_NAME);
+               PEER_ATTR_INHERIT(peer, group,
+                                 filter[afi][safi].plist[out].plist);
        }
 
-       if (gfilter->usmap.name) {
-               if (pfilter->usmap.name)
-                       XFREE(MTYPE_BGP_FILTER_NAME, pfilter->usmap.name);
-               pfilter->usmap.name =
-                       XSTRDUP(MTYPE_BGP_FILTER_NAME, gfilter->usmap.name);
-               pfilter->usmap.map = gfilter->usmap.map;
-       } else {
-               if (pfilter->usmap.name)
-                       XFREE(MTYPE_BGP_FILTER_NAME, pfilter->usmap.name);
-               pfilter->usmap.name = NULL;
-               pfilter->usmap.map = NULL;
+       if (!CHECK_FLAG(pfilter_ovrd[out], PEER_FT_FILTER_LIST)) {
+               PEER_STR_ATTR_INHERIT(peer, group,
+                                     filter[afi][safi].aslist[out].name,
+                                     MTYPE_BGP_FILTER_NAME);
+               PEER_ATTR_INHERIT(peer, group,
+                                 filter[afi][safi].aslist[out].aslist);
+       }
+
+       if (!CHECK_FLAG(pfilter_ovrd[RMAP_OUT], PEER_FT_ROUTE_MAP)) {
+               PEER_STR_ATTR_INHERIT(peer, group,
+                                     filter[afi][safi].map[RMAP_OUT].name,
+                                     MTYPE_BGP_FILTER_NAME);
+               PEER_ATTR_INHERIT(peer, group,
+                                 filter[afi][safi].map[RMAP_OUT].map);
+       }
+
+       /* nondirectional filter apply */
+       if (!CHECK_FLAG(pfilter_ovrd[0], PEER_FT_UNSUPPRESS_MAP)) {
+               PEER_STR_ATTR_INHERIT(peer, group, filter[afi][safi].usmap.name,
+                                     MTYPE_BGP_FILTER_NAME);
+               PEER_ATTR_INHERIT(peer, group, filter[afi][safi].usmap.map);
        }
 }
 
@@ -2232,9 +2243,8 @@ int peer_delete(struct peer *peer)
                bgp_unlink_nexthop_by_peer(peer);
 
        /* Password configuration */
-       if (peer->password) {
+       if (CHECK_FLAG(peer->flags, PEER_FLAG_PASSWORD)) {
                XFREE(MTYPE_PEER_PASSWORD, peer->password);
-               peer->password = NULL;
 
                if (!accept_peer && !BGP_PEER_SU_UNSPEC(peer)
                    && !CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
@@ -2407,12 +2417,6 @@ struct peer_group *peer_group_get(struct bgp *bgp, const char *name)
        group->conf->ttl = 1;
        group->conf->gtsm_hops = 0;
        group->conf->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
-       UNSET_FLAG(group->conf->config, PEER_CONFIG_TIMER);
-       UNSET_FLAG(group->conf->config, PEER_GROUP_CONFIG_TIMER);
-       UNSET_FLAG(group->conf->config, PEER_CONFIG_CONNECT);
-       group->conf->keepalive = 0;
-       group->conf->holdtime = 0;
-       group->conf->connect = 0;
        SET_FLAG(group->conf->sflags, PEER_STATUS_GROUP);
        listnode_add_sort(bgp->group, group);
 
@@ -2422,8 +2426,8 @@ struct peer_group *peer_group_get(struct bgp *bgp, const char *name)
 static void peer_group2peer_config_copy(struct peer_group *group,
                                        struct peer *peer)
 {
+       uint32_t flags_tmp;
        struct peer *conf;
-       int saved_flags = 0;
 
        conf = group->conf;
 
@@ -2431,8 +2435,8 @@ static void peer_group2peer_config_copy(struct peer_group *group,
        if (conf->as)
                peer->as = conf->as;
 
-       /* remote-as */
-       if (conf->change_local_as)
+       /* local-as */
+       if (!CHECK_FLAG(peer->flags_override, PEER_FLAG_LOCAL_AS))
                peer->change_local_as = conf->change_local_as;
 
        /* TTL */
@@ -2441,57 +2445,58 @@ static void peer_group2peer_config_copy(struct peer_group *group,
        /* GTSM hops */
        peer->gtsm_hops = conf->gtsm_hops;
 
-       /* These are per-peer specific flags and so we must preserve them */
-       saved_flags |= CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY);
-       saved_flags |= CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN);
-       peer->flags = conf->flags;
-       SET_FLAG(peer->flags, saved_flags);
+       /* peer flags apply */
+       flags_tmp = conf->flags & ~peer->flags_override;
+       flags_tmp ^= conf->flags_invert ^ peer->flags_invert;
+       flags_tmp &= ~peer->flags_override;
 
-       /* peer config apply */
-       peer->config = conf->config;
+       UNSET_FLAG(peer->flags, ~peer->flags_override);
+       SET_FLAG(peer->flags, flags_tmp);
+       SET_FLAG(peer->flags_invert, conf->flags_invert);
 
        /* peer timers apply */
-       peer->holdtime = conf->holdtime;
-       peer->keepalive = conf->keepalive;
-       peer->connect = conf->connect;
-       if (CHECK_FLAG(conf->config, PEER_CONFIG_CONNECT))
-               peer->v_connect = conf->connect;
-       else
-               peer->v_connect = BGP_DEFAULT_CONNECT_RETRY;
+       if (!CHECK_FLAG(peer->flags_override, PEER_FLAG_TIMER)) {
+               PEER_ATTR_INHERIT(peer, group, holdtime);
+               PEER_ATTR_INHERIT(peer, group, keepalive);
+       }
 
-       /* advertisement-interval reset */
-       if (CHECK_FLAG(conf->config, PEER_CONFIG_ROUTEADV))
-               peer->v_routeadv = conf->routeadv;
-       else if (peer_sort(peer) == BGP_PEER_IBGP)
-               peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV;
-       else
-               peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
+       if (!CHECK_FLAG(peer->flags_override, PEER_FLAG_TIMER_CONNECT)) {
+               PEER_ATTR_INHERIT(peer, group, connect);
+               if (CHECK_FLAG(conf->flags, PEER_FLAG_TIMER_CONNECT))
+                       peer->v_connect = conf->connect;
+               else
+                       peer->v_connect = BGP_DEFAULT_CONNECT_RETRY;
+       }
+
+       /* advertisement-interval apply */
+       if (!CHECK_FLAG(peer->flags_override, PEER_FLAG_ROUTEADV)) {
+               PEER_ATTR_INHERIT(peer, group, routeadv);
+               if (CHECK_FLAG(conf->flags, PEER_FLAG_ROUTEADV))
+                       peer->v_routeadv = conf->routeadv;
+               else
+                       peer->v_routeadv = (peer_sort(peer) == BGP_PEER_IBGP)
+                                                  ? BGP_DEFAULT_IBGP_ROUTEADV
+                                                  : BGP_DEFAULT_EBGP_ROUTEADV;
+       }
 
        /* password apply */
-       if (conf->password && !peer->password)
-               peer->password = XSTRDUP(MTYPE_PEER_PASSWORD, conf->password);
+       if (!CHECK_FLAG(peer->flags_override, PEER_FLAG_PASSWORD))
+               PEER_STR_ATTR_INHERIT(peer, group, password,
+                                     MTYPE_PEER_PASSWORD);
 
        if (!BGP_PEER_SU_UNSPEC(peer))
                bgp_md5_set(peer);
 
        /* update-source apply */
-       if (conf->update_source) {
-               if (peer->update_source)
-                       sockunion_free(peer->update_source);
-               if (peer->update_if) {
+       if (!CHECK_FLAG(peer->flags_override, PEER_FLAG_UPDATE_SOURCE)) {
+               if (conf->update_source) {
                        XFREE(MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
-                       peer->update_if = NULL;
-               }
-               peer->update_source = sockunion_dup(conf->update_source);
-       } else if (conf->update_if) {
-               if (peer->update_if)
-                       XFREE(MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
-               if (peer->update_source) {
+                       PEER_SU_ATTR_INHERIT(peer, group, update_source);
+               } else if (conf->update_if) {
                        sockunion_free(peer->update_source);
-                       peer->update_source = NULL;
+                       PEER_STR_ATTR_INHERIT(peer, group, update_if,
+                                             MTYPE_PEER_UPDATE_SOURCE);
                }
-               peer->update_if =
-                       XSTRDUP(MTYPE_PEER_UPDATE_SOURCE, conf->update_if);
        }
 
        bgp_bfd_peer_group2peer_copy(conf, peer);
@@ -2673,7 +2678,6 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer,
        int first_member = 0;
        afi_t afi;
        safi_t safi;
-       int cap_enhe_preset = 0;
 
        /* Lookup the peer.  */
        if (!peer)
@@ -2713,19 +2717,8 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer,
                                first_member = 1;
                }
 
-               if (CHECK_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE))
-                       cap_enhe_preset = 1;
-
                peer_group2peer_config_copy(group, peer);
 
-               /*
-                * Capability extended-nexthop is enabled for an interface
-                * neighbor by
-                * default. So, fix that up here.
-                */
-               if (peer->conf_if && cap_enhe_preset)
-                       peer_flag_set(peer, PEER_FLAG_CAPABILITY_ENHE);
-
                FOREACH_AFI_SAFI (afi, safi) {
                        if (group->conf->afc[afi][safi]) {
                                peer->afc[afi][safi] = 1;
@@ -2742,9 +2735,8 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer,
                if (peer->group) {
                        assert(group && peer->group == group);
                } else {
-                       struct listnode *pn;
-                       pn = listnode_lookup(bgp->peer, peer);
-                       list_delete_node(bgp->peer, pn);
+                       listnode_delete(bgp->peer, peer);
+
                        peer->group = group;
                        listnode_add_sort(bgp->peer, peer);
 
@@ -2754,14 +2746,13 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer,
 
                if (first_member) {
                        /* Advertisement-interval reset */
-                       if (!CHECK_FLAG(group->conf->config,
-                                       PEER_CONFIG_ROUTEADV)) {
-                               if (peer_sort(group->conf) == BGP_PEER_IBGP)
-                                       group->conf->v_routeadv =
-                                               BGP_DEFAULT_IBGP_ROUTEADV;
-                               else
-                                       group->conf->v_routeadv =
-                                               BGP_DEFAULT_EBGP_ROUTEADV;
+                       if (!CHECK_FLAG(group->conf->flags,
+                                       PEER_FLAG_ROUTEADV)) {
+                               group->conf->v_routeadv =
+                                       (peer_sort(group->conf)
+                                        == BGP_PEER_IBGP)
+                                               ? BGP_DEFAULT_IBGP_ROUTEADV
+                                               : BGP_DEFAULT_EBGP_ROUTEADV;
                        }
 
                        /* ebgp-multihop reset */
@@ -2771,10 +2762,12 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer,
                        /* local-as reset */
                        if (peer_sort(group->conf) != BGP_PEER_EBGP) {
                                group->conf->change_local_as = 0;
-                               UNSET_FLAG(peer->flags,
-                                          PEER_FLAG_LOCAL_AS_NO_PREPEND);
-                               UNSET_FLAG(peer->flags,
-                                          PEER_FLAG_LOCAL_AS_REPLACE_AS);
+                               peer_flag_unset(group->conf,
+                                               PEER_FLAG_LOCAL_AS);
+                               peer_flag_unset(group->conf,
+                                               PEER_FLAG_LOCAL_AS_NO_PREPEND);
+                               peer_flag_unset(group->conf,
+                                               PEER_FLAG_LOCAL_AS_REPLACE_AS);
                        }
                }
 
@@ -3845,6 +3838,14 @@ static const struct peer_flag_action peer_flag_action_list[] = {
        {PEER_FLAG_DISABLE_CONNECTED_CHECK, 0, peer_change_reset},
        {PEER_FLAG_CAPABILITY_ENHE, 0, peer_change_reset},
        {PEER_FLAG_ENFORCE_FIRST_AS, 0, peer_change_reset_in},
+       {PEER_FLAG_ROUTEADV, 0, peer_change_none},
+       {PEER_FLAG_TIMER, 0, peer_change_none},
+       {PEER_FLAG_TIMER_CONNECT, 0, peer_change_none},
+       {PEER_FLAG_PASSWORD, 0, peer_change_none},
+       {PEER_FLAG_LOCAL_AS, 0, peer_change_none},
+       {PEER_FLAG_LOCAL_AS_NO_PREPEND, 0, peer_change_none},
+       {PEER_FLAG_LOCAL_AS_REPLACE_AS, 0, peer_change_none},
+       {PEER_FLAG_UPDATE_SOURCE, 0, peer_change_none},
        {0, 0, 0}};
 
 static const struct peer_flag_action peer_af_flag_action_list[] = {
@@ -3993,72 +3994,87 @@ static int peer_flag_modify(struct peer *peer, uint32_t flag, int set)
 {
        int found;
        int size;
-       struct peer_group *group;
-       struct peer *tmp_peer;
+       bool invert, member_invert;
+       struct peer *member;
        struct listnode *node, *nnode;
        struct peer_flag_action action;
 
        memset(&action, 0, sizeof(struct peer_flag_action));
        size = sizeof peer_flag_action_list / sizeof(struct peer_flag_action);
 
+       invert = CHECK_FLAG(peer->flags_invert, flag);
        found = peer_flag_action_set(peer_flag_action_list, size, &action,
                                     flag);
 
-       /* No flag action is found.  */
+       /* Abort if no flag action exists. */
        if (!found)
                return BGP_ERR_INVALID_FLAG;
 
-       /* When unset the peer-group member's flag we have to check
-          peer-group configuration.  */
-       if (!set && peer_group_active(peer))
-               if (CHECK_FLAG(peer->group->conf->flags, flag)) {
-                       if (flag == PEER_FLAG_SHUTDOWN)
-                               return BGP_ERR_PEER_GROUP_SHUTDOWN;
-               }
-
-       /* Flag conflict check.  */
+       /* Check for flag conflict: STRICT_CAP_MATCH && OVERRIDE_CAPABILITY */
        if (set && CHECK_FLAG(peer->flags | flag, PEER_FLAG_STRICT_CAP_MATCH)
            && CHECK_FLAG(peer->flags | flag, PEER_FLAG_OVERRIDE_CAPABILITY))
                return BGP_ERR_PEER_FLAG_CONFLICT;
 
+       /* Handle flag updates where desired state matches current state. */
        if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
-               if (set && CHECK_FLAG(peer->flags, flag) == flag)
+               if (set && CHECK_FLAG(peer->flags, flag)) {
+                       COND_FLAG(peer->flags_override, flag, !invert);
                        return 0;
-               if (!set && !CHECK_FLAG(peer->flags, flag))
+               }
+
+               if (!set && !CHECK_FLAG(peer->flags, flag)) {
+                       COND_FLAG(peer->flags_override, flag, invert);
                        return 0;
+               }
        }
 
-       if (set)
-               SET_FLAG(peer->flags, flag);
+       /* Inherit from peer-group or set/unset flags accordingly. */
+       if (peer_group_active(peer) && set == invert)
+               peer_flag_inherit(peer, flag);
        else
-               UNSET_FLAG(peer->flags, flag);
+               COND_FLAG(peer->flags, flag, set);
 
+       /* Check if handling a regular peer. */
        if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+               /* Update flag override state accordingly. */
+               COND_FLAG(peer->flags_override, flag, set != invert);
+
+               /* Execute flag action on peer. */
                if (action.type == peer_change_reset)
                        peer_flag_modify_action(peer, flag);
 
+               /* Skip peer-group mechanics for regular peers. */
                return 0;
        }
 
-       /* peer-group member updates. */
-       group = peer->group;
+       /*
+        * Update peer-group members, unless they are explicitely overriding
+        * peer-group configuration.
+        */
+       for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+               /* Skip peers with overridden configuration. */
+               if (CHECK_FLAG(member->flags_override, flag))
+                       continue;
 
-       for (ALL_LIST_ELEMENTS(group->peer, node, nnode, tmp_peer)) {
+               /* Check if only member without group is inverted. */
+               member_invert =
+                       CHECK_FLAG(member->flags_invert, flag) && !invert;
 
-               if (set && CHECK_FLAG(tmp_peer->flags, flag) == flag)
+               /* Skip peers with equivalent configuration. */
+               if (set != member_invert && CHECK_FLAG(member->flags, flag))
                        continue;
 
-               if (!set && !CHECK_FLAG(tmp_peer->flags, flag))
+               if (set == member_invert && !CHECK_FLAG(member->flags, flag))
                        continue;
 
-               if (set)
-                       SET_FLAG(tmp_peer->flags, flag);
-               else
-                       UNSET_FLAG(tmp_peer->flags, flag);
+               /* Update flag on peer-group member. */
+               COND_FLAG(member->flags, flag, set != member_invert);
 
+               /* Execute flag action on peer-group member. */
                if (action.type == peer_change_reset)
-                       peer_flag_modify_action(tmp_peer, flag);
+                       peer_flag_modify_action(member, flag);
        }
+
        return 0;
 }
 
@@ -4078,12 +4094,11 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi,
        int found;
        int size;
        int addpath_tx_used;
-       bool invert;
+       bool invert, member_invert;
+       struct bgp *bgp;
+       struct peer *member;
        struct listnode *node, *nnode;
-       struct peer_group *group;
        struct peer_flag_action action;
-       struct peer *tmp_peer;
-       struct bgp *bgp;
 
        memset(&action, 0, sizeof(struct peer_flag_action));
        size = sizeof peer_af_flag_action_list
@@ -4093,7 +4108,7 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi,
        found = peer_flag_action_set(peer_af_flag_action_list, size, &action,
                                     flag);
 
-       /* No flag action is found.  */
+       /* Abort if flag action exists. */
        if (!found)
                return BGP_ERR_INVALID_FLAG;
 
@@ -4111,25 +4126,17 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi,
        if (flag & PEER_FLAG_AS_OVERRIDE && peer_sort(peer) == BGP_PEER_IBGP)
                return BGP_ERR_AS_OVERRIDE;
 
-       /* When current flag configuration is same as requested one.  */
+       /* Handle flag updates where desired state matches current state. */
        if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
                if (set && CHECK_FLAG(peer->af_flags[afi][safi], flag)) {
-                       if (invert)
-                               UNSET_FLAG(peer->af_flags_override[afi][safi],
-                                          flag);
-                       else
-                               SET_FLAG(peer->af_flags_override[afi][safi],
-                                        flag);
+                       COND_FLAG(peer->af_flags_override[afi][safi], flag,
+                                 !invert);
                        return 0;
                }
 
                if (!set && !CHECK_FLAG(peer->af_flags[afi][safi], flag)) {
-                       if (invert)
-                               SET_FLAG(peer->af_flags_override[afi][safi],
-                                        flag);
-                       else
-                               UNSET_FLAG(peer->af_flags_override[afi][safi],
-                                          flag);
+                       COND_FLAG(peer->af_flags_override[afi][safi], flag,
+                                 invert);
                        return 0;
                }
        }
@@ -4163,22 +4170,11 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi,
                }
        }
 
-       /* Set/unset flag or inherit from peer-group if appropriate. */
-       if (invert) {
-               if (!set)
-                       UNSET_FLAG(peer->af_flags[afi][safi], flag);
-               else if (peer_group_active(peer))
-                       peer_af_flag_inherit(peer, afi, safi, flag);
-               else
-                       SET_FLAG(peer->af_flags[afi][safi], flag);
-       } else {
-               if (set)
-                       SET_FLAG(peer->af_flags[afi][safi], flag);
-               else if (peer_group_active(peer))
-                       peer_af_flag_inherit(peer, afi, safi, flag);
-               else
-                       UNSET_FLAG(peer->af_flags[afi][safi], flag);
-       }
+       /* Inherit from peer-group or set/unset flags accordingly. */
+       if (peer_group_active(peer) && set == invert)
+               peer_af_flag_inherit(peer, afi, safi, flag);
+       else
+               COND_FLAG(peer->af_flags[afi][safi], flag, set);
 
        /* Execute action when peer is established.  */
        if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)
@@ -4199,57 +4195,67 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi,
                }
        }
 
-       /* Peer group member updates.  */
-       if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
-               group = peer->group;
-               for (ALL_LIST_ELEMENTS(group->peer, node, nnode, tmp_peer)) {
-                       if (CHECK_FLAG(tmp_peer->af_flags_override[afi][safi],
+       /* Check if handling a regular peer. */
+       if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+               COND_FLAG(peer->af_flags_override[afi][safi], flag,
+                         set != invert);
+       } else {
+               /*
+                * Update peer-group members, unless they are explicitely
+                * overriding peer-group configuration.
+                */
+               for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode,
+                                      member)) {
+                       /* Skip peers with overridden configuration. */
+                       if (CHECK_FLAG(member->af_flags_override[afi][safi],
                                       flag))
                                continue;
 
-                       if (set
-                           && CHECK_FLAG(tmp_peer->af_flags[afi][safi], flag))
+                       /* Check if only member without group is inverted. */
+                       member_invert =
+                               CHECK_FLAG(member->af_flags_invert[afi][safi],
+                                          flag)
+                               && !invert;
+
+                       /* Skip peers with equivalent configuration. */
+                       if (set != member_invert
+                           && CHECK_FLAG(member->af_flags[afi][safi], flag))
                                continue;
 
-                       if (!set
-                           && !CHECK_FLAG(tmp_peer->af_flags[afi][safi], flag))
+                       if (set == member_invert
+                           && !CHECK_FLAG(member->af_flags[afi][safi], flag))
                                continue;
 
-                       if (set)
-                               SET_FLAG(tmp_peer->af_flags[afi][safi], flag);
-                       else
-                               UNSET_FLAG(tmp_peer->af_flags[afi][safi], flag);
+                       /* Update flag on peer-group member. */
+                       COND_FLAG(member->af_flags[afi][safi], flag,
+                                 set != member_invert);
 
-                       if (tmp_peer->status == Established) {
+                       /* Execute flag action on peer-group member. */
+                       if (member->status == Established) {
                                if (!set && flag == PEER_FLAG_SOFT_RECONFIG)
-                                       bgp_clear_adj_in(tmp_peer, afi, safi);
+                                       bgp_clear_adj_in(member, afi, safi);
                                else {
                                        if (flag == PEER_FLAG_REFLECTOR_CLIENT)
-                                               tmp_peer->last_reset =
+                                               member->last_reset =
                                                        PEER_DOWN_RR_CLIENT_CHANGE;
                                        else if (flag
                                                 == PEER_FLAG_RSERVER_CLIENT)
-                                               tmp_peer->last_reset =
+                                               member->last_reset =
                                                        PEER_DOWN_RS_CLIENT_CHANGE;
                                        else if (flag
                                                 == PEER_FLAG_ORF_PREFIX_SM)
-                                               tmp_peer->last_reset =
+                                               member->last_reset =
                                                        PEER_DOWN_CAPABILITY_CHANGE;
                                        else if (flag
                                                 == PEER_FLAG_ORF_PREFIX_RM)
-                                               tmp_peer->last_reset =
+                                               member->last_reset =
                                                        PEER_DOWN_CAPABILITY_CHANGE;
 
-                                       peer_change_action(tmp_peer, afi, safi,
+                                       peer_change_action(member, afi, safi,
                                                           action.type);
                                }
                        }
                }
-       } else {
-               if (set != invert)
-                       SET_FLAG(peer->af_flags_override[afi][safi], flag);
-               else
-                       UNSET_FLAG(peer->af_flags_override[afi][safi], flag);
        }
 
        /* Track if addpath TX is in use */
@@ -4276,11 +4282,11 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi,
                        }
                } else {
                        for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode,
-                                              tmp_peer)) {
-                               if (CHECK_FLAG(tmp_peer->af_flags[afi][safi],
+                                              member)) {
+                               if (CHECK_FLAG(member->af_flags[afi][safi],
                                               PEER_FLAG_ADDPATH_TX_ALL_PATHS)
                                    || CHECK_FLAG(
-                                              tmp_peer->af_flags[afi][safi],
+                                              member->af_flags[afi][safi],
                                               PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS)) {
                                        addpath_tx_used = 1;
                                        break;
@@ -4446,183 +4452,195 @@ int peer_description_unset(struct peer *peer)
 /* Neighbor update-source. */
 int peer_update_source_if_set(struct peer *peer, const char *ifname)
 {
-       struct peer_group *group;
+       struct peer *member;
        struct listnode *node, *nnode;
 
+       /* Set flag and configuration on peer. */
+       peer_flag_set(peer, PEER_FLAG_UPDATE_SOURCE);
        if (peer->update_if) {
-               if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)
-                   && strcmp(peer->update_if, ifname) == 0)
+               if (strcmp(peer->update_if, ifname) == 0)
                        return 0;
-
                XFREE(MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
-               peer->update_if = NULL;
-       }
-
-       if (peer->update_source) {
-               sockunion_free(peer->update_source);
-               peer->update_source = NULL;
        }
-
        peer->update_if = XSTRDUP(MTYPE_PEER_UPDATE_SOURCE, ifname);
+       sockunion_free(peer->update_source);
+       peer->update_source = NULL;
 
+       /* Check if handling a regular peer. */
        if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+               /* Send notification or reset peer depending on state. */
                if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
                        peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE;
                        bgp_notify_send(peer, BGP_NOTIFY_CEASE,
                                        BGP_NOTIFY_CEASE_CONFIG_CHANGE);
                } else
                        bgp_session_reset(peer);
+
+               /* Skip peer-group mechanics for regular peers. */
                return 0;
        }
 
-       /* peer-group member updates. */
-       group = peer->group;
-       for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
-               if (peer->update_if) {
-                       if (strcmp(peer->update_if, ifname) == 0)
-                               continue;
-
-                       XFREE(MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
-                       peer->update_if = NULL;
-               }
+       /*
+        * Set flag and configuration on all peer-group members, unless they are
+        * explicitely overriding peer-group configuration.
+        */
+       for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+               /* Skip peers with overridden configuration. */
+               if (CHECK_FLAG(member->flags_override, PEER_FLAG_UPDATE_SOURCE))
+                       continue;
 
-               if (peer->update_source) {
-                       sockunion_free(peer->update_source);
-                       peer->update_source = NULL;
+               /* Skip peers with the same configuration. */
+               if (member->update_if) {
+                       if (strcmp(member->update_if, ifname) == 0)
+                               continue;
+                       XFREE(MTYPE_PEER_UPDATE_SOURCE, member->update_if);
                }
 
-               peer->update_if = XSTRDUP(MTYPE_PEER_UPDATE_SOURCE, ifname);
-
-               if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
-                       peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE;
-                       bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+               /* Set flag and configuration on peer-group member. */
+               SET_FLAG(member->flags, PEER_FLAG_UPDATE_SOURCE);
+               member->update_if = XSTRDUP(MTYPE_PEER_UPDATE_SOURCE, ifname);
+               sockunion_free(member->update_source);
+               member->update_source = NULL;
+
+               /* Send notification or reset peer depending on state. */
+               if (BGP_IS_VALID_STATE_FOR_NOTIF(member->status)) {
+                       member->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE;
+                       bgp_notify_send(member, BGP_NOTIFY_CEASE,
                                        BGP_NOTIFY_CEASE_CONFIG_CHANGE);
                } else
-                       bgp_session_reset(peer);
+                       bgp_session_reset(member);
        }
+
        return 0;
 }
 
 int peer_update_source_addr_set(struct peer *peer, const union sockunion *su)
 {
-       struct peer_group *group;
+       struct peer *member;
        struct listnode *node, *nnode;
 
+       /* Set flag and configuration on peer. */
+       peer_flag_set(peer, PEER_FLAG_UPDATE_SOURCE);
        if (peer->update_source) {
-               if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)
-                   && sockunion_cmp(peer->update_source, su) == 0)
+               if (sockunion_cmp(peer->update_source, su) == 0)
                        return 0;
                sockunion_free(peer->update_source);
-               peer->update_source = NULL;
-       }
-
-       if (peer->update_if) {
-               XFREE(MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
-               peer->update_if = NULL;
        }
-
        peer->update_source = sockunion_dup(su);
+       XFREE(MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
 
+       /* Check if handling a regular peer. */
        if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+               /* Send notification or reset peer depending on state. */
                if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
                        peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE;
                        bgp_notify_send(peer, BGP_NOTIFY_CEASE,
                                        BGP_NOTIFY_CEASE_CONFIG_CHANGE);
                } else
                        bgp_session_reset(peer);
+
+               /* Skip peer-group mechanics for regular peers. */
                return 0;
        }
 
-       /* peer-group member updates. */
-       group = peer->group;
-       for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
-               if (peer->update_source) {
-                       if (sockunion_cmp(peer->update_source, su) == 0)
-                               continue;
-                       sockunion_free(peer->update_source);
-                       peer->update_source = NULL;
-               }
+       /*
+        * Set flag and configuration on all peer-group members, unless they are
+        * explicitely overriding peer-group configuration.
+        */
+       for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+               /* Skip peers with overridden configuration. */
+               if (CHECK_FLAG(member->flags_override, PEER_FLAG_UPDATE_SOURCE))
+                       continue;
 
-               if (peer->update_if) {
-                       XFREE(MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
-                       peer->update_if = NULL;
+               /* Skip peers with the same configuration. */
+               if (member->update_source) {
+                       if (sockunion_cmp(member->update_source, su) == 0)
+                               continue;
+                       sockunion_free(member->update_source);
                }
 
-               peer->update_source = sockunion_dup(su);
-
-               if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
-                       peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE;
-                       bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+               /* Set flag and configuration on peer-group member. */
+               SET_FLAG(member->flags, PEER_FLAG_UPDATE_SOURCE);
+               member->update_source = sockunion_dup(su);
+               XFREE(MTYPE_PEER_UPDATE_SOURCE, member->update_if);
+
+               /* Send notification or reset peer depending on state. */
+               if (BGP_IS_VALID_STATE_FOR_NOTIF(member->status)) {
+                       member->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE;
+                       bgp_notify_send(member, BGP_NOTIFY_CEASE,
                                        BGP_NOTIFY_CEASE_CONFIG_CHANGE);
                } else
-                       bgp_session_reset(peer);
+                       bgp_session_reset(member);
        }
+
        return 0;
 }
 
 int peer_update_source_unset(struct peer *peer)
 {
-       union sockunion *su;
-       struct peer_group *group;
+       struct peer *member;
        struct listnode *node, *nnode;
 
-       if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP) && !peer->update_source
-           && !peer->update_if)
+       if (!CHECK_FLAG(peer->flags, PEER_FLAG_UPDATE_SOURCE))
                return 0;
 
-       if (peer->update_source) {
+       /* Inherit configuration from peer-group if peer is member. */
+       if (peer_group_active(peer)) {
+               peer_flag_inherit(peer, PEER_FLAG_UPDATE_SOURCE);
+               PEER_SU_ATTR_INHERIT(peer, peer->group, update_source);
+               PEER_STR_ATTR_INHERIT(peer, peer->group, update_if,
+                                     MTYPE_PEER_UPDATE_SOURCE);
+       } else {
+               /* Otherwise remove flag and configuration from peer. */
+               peer_flag_unset(peer, PEER_FLAG_UPDATE_SOURCE);
                sockunion_free(peer->update_source);
                peer->update_source = NULL;
-       }
-       if (peer->update_if) {
                XFREE(MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
-               peer->update_if = NULL;
-       }
-
-       if (peer_group_active(peer)) {
-               group = peer->group;
-
-               if (group->conf->update_source) {
-                       su = sockunion_dup(group->conf->update_source);
-                       peer->update_source = su;
-               } else if (group->conf->update_if)
-                       peer->update_if = XSTRDUP(MTYPE_PEER_UPDATE_SOURCE,
-                                                 group->conf->update_if);
        }
 
+       /* Check if handling a regular peer. */
        if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+               /* Send notification or reset peer depending on state. */
                if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
                        peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE;
                        bgp_notify_send(peer, BGP_NOTIFY_CEASE,
                                        BGP_NOTIFY_CEASE_CONFIG_CHANGE);
                } else
                        bgp_session_reset(peer);
+
+               /* Skip peer-group mechanics for regular peers. */
                return 0;
        }
 
-       /* peer-group member updates. */
-       group = peer->group;
-       for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
-               if (!peer->update_source && !peer->update_if)
+       /*
+        * Set flag and configuration on all peer-group members, unless they are
+        * explicitely overriding peer-group configuration.
+        */
+       for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+               /* Skip peers with overridden configuration. */
+               if (CHECK_FLAG(member->flags_override, PEER_FLAG_UPDATE_SOURCE))
                        continue;
 
-               if (peer->update_source) {
-                       sockunion_free(peer->update_source);
-                       peer->update_source = NULL;
-               }
-
-               if (peer->update_if) {
-                       XFREE(MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
-                       peer->update_if = NULL;
-               }
+               /* Skip peers with the same configuration. */
+               if (!CHECK_FLAG(member->flags, PEER_FLAG_UPDATE_SOURCE)
+                   && !member->update_source && !member->update_if)
+                       continue;
 
-               if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
-                       peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE;
-                       bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+               /* Remove flag and configuration on peer-group member. */
+               UNSET_FLAG(member->flags, PEER_FLAG_UPDATE_SOURCE);
+               sockunion_free(member->update_source);
+               member->update_source = NULL;
+               XFREE(MTYPE_PEER_UPDATE_SOURCE, member->update_if);
+
+               /* Send notification or reset peer depending on state. */
+               if (BGP_IS_VALID_STATE_FOR_NOTIF(member->status)) {
+                       member->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE;
+                       bgp_notify_send(member, BGP_NOTIFY_CEASE,
                                        BGP_NOTIFY_CEASE_CONFIG_CHANGE);
                } else
-                       bgp_session_reset(peer);
+                       bgp_session_reset(member);
        }
+
        return 0;
 }
 
@@ -4714,9 +4732,11 @@ int peer_default_originate_unset(struct peer *peer, afi_t afi, safi_t safi)
        if (peer_group_active(peer)) {
                peer_af_flag_inherit(peer, afi, safi,
                                     PEER_FLAG_DEFAULT_ORIGINATE);
-               PEER_STR_ATTR_INHERIT(MTYPE_ROUTE_MAP_NAME, peer,
-                                     default_rmap[afi][safi].name);
-               PEER_ATTR_INHERIT(peer, default_rmap[afi][safi].map);
+               PEER_STR_ATTR_INHERIT(peer, peer->group,
+                                     default_rmap[afi][safi].name,
+                                     MTYPE_ROUTE_MAP_NAME);
+               PEER_ATTR_INHERIT(peer, peer->group,
+                                 default_rmap[afi][safi].map);
        } else {
                /* Otherwise remove flag and configuration from peer. */
                peer_af_flag_unset(peer, afi, safi,
@@ -4858,7 +4878,7 @@ int peer_weight_unset(struct peer *peer, afi_t afi, safi_t safi)
        /* Inherit configuration from peer-group if peer is member. */
        if (peer_group_active(peer)) {
                peer_af_flag_inherit(peer, afi, safi, PEER_FLAG_WEIGHT);
-               PEER_ATTR_INHERIT(peer, weight[afi][safi]);
+               PEER_ATTR_INHERIT(peer, peer->group, weight[afi][safi]);
 
                peer_on_policy_change(peer, afi, safi, 0);
                return 0;
@@ -4898,44 +4918,40 @@ int peer_weight_unset(struct peer *peer, afi_t afi, safi_t safi)
 
 int peer_timers_set(struct peer *peer, uint32_t keepalive, uint32_t holdtime)
 {
-       struct peer_group *group;
+       struct peer *member;
        struct listnode *node, *nnode;
 
-       /* keepalive value check.  */
        if (keepalive > 65535)
                return BGP_ERR_INVALID_VALUE;
 
-       /* Holdtime value check.  */
        if (holdtime > 65535)
                return BGP_ERR_INVALID_VALUE;
 
-       /* Holdtime value must be either 0 or greater than 3.  */
        if (holdtime < 3 && holdtime != 0)
                return BGP_ERR_INVALID_VALUE;
 
-       /* Set value to the configuration. */
+       /* Set flag and configuration on peer. */
+       peer_flag_set(peer, PEER_FLAG_TIMER);
        peer->holdtime = holdtime;
        peer->keepalive = (keepalive < holdtime / 3 ? keepalive : holdtime / 3);
 
-       /* First work on real peers with timers */
-       if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
-               SET_FLAG(peer->config, PEER_CONFIG_TIMER);
-               UNSET_FLAG(peer->config, PEER_GROUP_CONFIG_TIMER);
-       } else {
-               /* Now work on the peer-group timers */
-               SET_FLAG(peer->config, PEER_GROUP_CONFIG_TIMER);
+       /* Skip peer-group mechanics for regular peers. */
+       if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+               return 0;
 
-               /* peer-group member updates. */
-               group = peer->group;
-               for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
-                       /* Skip peers that have their own timers */
-                       if (CHECK_FLAG(peer->config, PEER_CONFIG_TIMER))
-                               continue;
+       /*
+        * Set flag and configuration on all peer-group members, unless they are
+        * explicitely overriding peer-group configuration.
+        */
+       for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+               /* Skip peers with overridden configuration. */
+               if (CHECK_FLAG(member->flags_override, PEER_FLAG_TIMER))
+                       continue;
 
-                       SET_FLAG(peer->config, PEER_GROUP_CONFIG_TIMER);
-                       peer->holdtime = group->conf->holdtime;
-                       peer->keepalive = group->conf->keepalive;
-               }
+               /* Set flag and configuration on peer-group member. */
+               SET_FLAG(member->flags, PEER_FLAG_TIMER);
+               PEER_ATTR_INHERIT(peer, peer->group, holdtime);
+               PEER_ATTR_INHERIT(peer, peer->group, keepalive);
        }
 
        return 0;
@@ -4943,35 +4959,38 @@ int peer_timers_set(struct peer *peer, uint32_t keepalive, uint32_t holdtime)
 
 int peer_timers_unset(struct peer *peer)
 {
-       struct peer_group *group;
+       struct peer *member;
        struct listnode *node, *nnode;
 
-       /* First work on real peers vs the peer-group */
-       if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
-               UNSET_FLAG(peer->config, PEER_CONFIG_TIMER);
-               peer->keepalive = 0;
-               peer->holdtime = 0;
-
-               if (peer->group && peer->group->conf->holdtime) {
-                       SET_FLAG(peer->config, PEER_GROUP_CONFIG_TIMER);
-                       peer->keepalive = peer->group->conf->keepalive;
-                       peer->holdtime = peer->group->conf->holdtime;
-               }
+       /* Inherit configuration from peer-group if peer is member. */
+       if (peer_group_active(peer)) {
+               peer_flag_inherit(peer, PEER_FLAG_TIMER);
+               PEER_ATTR_INHERIT(peer, peer->group, holdtime);
+               PEER_ATTR_INHERIT(peer, peer->group, keepalive);
        } else {
-               /* peer-group member updates. */
-               group = peer->group;
-               for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
-                       if (!CHECK_FLAG(peer->config, PEER_CONFIG_TIMER)) {
-                               UNSET_FLAG(peer->config,
-                                          PEER_GROUP_CONFIG_TIMER);
-                               peer->holdtime = 0;
-                               peer->keepalive = 0;
-                       }
-               }
+               /* Otherwise remove flag and configuration from peer. */
+               peer_flag_unset(peer, PEER_FLAG_TIMER);
+               peer->holdtime = 0;
+               peer->keepalive = 0;
+       }
+
+       /* Skip peer-group mechanics for regular peers. */
+       if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+               return 0;
+
+       /*
+        * Remove flag and configuration from all peer-group members, unless
+        * they are explicitely overriding peer-group configuration.
+        */
+       for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+               /* Skip peers with overridden configuration. */
+               if (CHECK_FLAG(member->flags_override, PEER_FLAG_TIMER))
+                       continue;
 
-               UNSET_FLAG(group->conf->config, PEER_GROUP_CONFIG_TIMER);
-               group->conf->holdtime = 0;
-               group->conf->keepalive = 0;
+               /* Remove flag and configuration on peer-group member. */
+               UNSET_FLAG(member->flags, PEER_FLAG_TIMER);
+               member->holdtime = 0;
+               member->keepalive = 0;
        }
 
        return 0;
@@ -4979,85 +4998,124 @@ int peer_timers_unset(struct peer *peer)
 
 int peer_timers_connect_set(struct peer *peer, uint32_t connect)
 {
-       struct peer_group *group;
+       struct peer *member;
        struct listnode *node, *nnode;
 
        if (connect > 65535)
                return BGP_ERR_INVALID_VALUE;
 
-       /* Set value to the configuration. */
-       SET_FLAG(peer->config, PEER_CONFIG_CONNECT);
+       /* Set flag and configuration on peer. */
+       peer_flag_set(peer, PEER_FLAG_TIMER_CONNECT);
        peer->connect = connect;
-
-       /* Set value to timer setting. */
        peer->v_connect = connect;
 
+       /* Skip peer-group mechanics for regular peers. */
        if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
                return 0;
 
-       /* peer-group member updates. */
-       group = peer->group;
-       for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
-               SET_FLAG(peer->config, PEER_CONFIG_CONNECT);
-               peer->connect = connect;
-               peer->v_connect = connect;
+       /*
+        * Set flag and configuration on all peer-group members, unless they are
+        * explicitely overriding peer-group configuration.
+        */
+       for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+               /* Skip peers with overridden configuration. */
+               if (CHECK_FLAG(member->flags_override, PEER_FLAG_TIMER_CONNECT))
+                       continue;
+
+               /* Set flag and configuration on peer-group member. */
+               SET_FLAG(member->flags, PEER_FLAG_TIMER_CONNECT);
+               member->connect = connect;
+               member->v_connect = connect;
        }
+
        return 0;
 }
 
 int peer_timers_connect_unset(struct peer *peer)
 {
-       struct peer_group *group;
+       struct peer *member;
        struct listnode *node, *nnode;
 
-       /* Clear configuration. */
-       UNSET_FLAG(peer->config, PEER_CONFIG_CONNECT);
-       peer->connect = 0;
+       /* Inherit configuration from peer-group if peer is member. */
+       if (peer_group_active(peer)) {
+               peer_flag_inherit(peer, PEER_FLAG_TIMER_CONNECT);
+               PEER_ATTR_INHERIT(peer, peer->group, connect);
+       } else {
+               /* Otherwise remove flag and configuration from peer. */
+               peer_flag_unset(peer, PEER_FLAG_TIMER_CONNECT);
+               peer->connect = 0;
+       }
 
-       /* Set timer setting to default value. */
-       peer->v_connect = BGP_DEFAULT_CONNECT_RETRY;
+       /* Set timer with fallback to default value. */
+       if (peer->connect)
+               peer->v_connect = peer->connect;
+       else
+               peer->v_connect = BGP_DEFAULT_CONNECT_RETRY;
 
+       /* Skip peer-group mechanics for regular peers. */
        if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
                return 0;
 
-       /* peer-group member updates. */
-       group = peer->group;
-       for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
-               UNSET_FLAG(peer->config, PEER_CONFIG_CONNECT);
-               peer->connect = 0;
-               peer->v_connect = BGP_DEFAULT_CONNECT_RETRY;
+       /*
+        * Remove flag and configuration from all peer-group members, unless
+        * they are explicitely overriding peer-group configuration.
+        */
+       for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+               /* Skip peers with overridden configuration. */
+               if (CHECK_FLAG(member->flags_override, PEER_FLAG_TIMER_CONNECT))
+                       continue;
+
+               /* Remove flag and configuration on peer-group member. */
+               UNSET_FLAG(member->flags, PEER_FLAG_TIMER_CONNECT);
+               member->connect = 0;
+               member->v_connect = BGP_DEFAULT_CONNECT_RETRY;
        }
+
        return 0;
 }
 
 int peer_advertise_interval_set(struct peer *peer, uint32_t routeadv)
 {
-       struct peer_group *group;
+       struct peer *member;
        struct listnode *node, *nnode;
 
        if (routeadv > 600)
                return BGP_ERR_INVALID_VALUE;
 
-       SET_FLAG(peer->config, PEER_CONFIG_ROUTEADV);
+       /* Set flag and configuration on peer. */
+       peer_flag_set(peer, PEER_FLAG_ROUTEADV);
        peer->routeadv = routeadv;
        peer->v_routeadv = routeadv;
 
+       /* Check if handling a regular peer. */
        if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+               /* Update peer route announcements. */
                update_group_adjust_peer_afs(peer);
                if (peer->status == Established)
                        bgp_announce_route_all(peer);
+
+               /* Skip peer-group mechanics for regular peers. */
                return 0;
        }
 
-       /* peer-group member updates. */
-       group = peer->group;
-       for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
-               SET_FLAG(peer->config, PEER_CONFIG_ROUTEADV);
-               peer->routeadv = routeadv;
-               peer->v_routeadv = routeadv;
-               update_group_adjust_peer_afs(peer);
-               if (peer->status == Established)
-                       bgp_announce_route_all(peer);
+       /*
+        * Set flag and configuration on all peer-group members, unless they are
+        * explicitely overriding peer-group configuration.
+        */
+       for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+               /* Skip peers with overridden configuration. */
+               if (CHECK_FLAG(member->flags_override, PEER_FLAG_ROUTEADV))
+                       continue;
+
+               /* Set flag and configuration on peer-group member. */
+               SET_FLAG(member->flags, PEER_FLAG_ROUTEADV);
+               member->routeadv = routeadv;
+               member->v_routeadv = routeadv;
+
+               /* Update peer route announcements. */
+               update_group_adjust_peer_afs(member);
+               if (member->status == Established)
+                       bgp_announce_route_all(member);
        }
 
        return 0;
@@ -5065,38 +5123,58 @@ int peer_advertise_interval_set(struct peer *peer, uint32_t routeadv)
 
 int peer_advertise_interval_unset(struct peer *peer)
 {
-       struct peer_group *group;
+       struct peer *member;
        struct listnode *node, *nnode;
 
-       UNSET_FLAG(peer->config, PEER_CONFIG_ROUTEADV);
-       peer->routeadv = 0;
+       /* Inherit configuration from peer-group if peer is member. */
+       if (peer_group_active(peer)) {
+               peer_flag_inherit(peer, PEER_FLAG_ROUTEADV);
+               PEER_ATTR_INHERIT(peer, peer->group, routeadv);
+       } else {
+               /* Otherwise remove flag and configuration from peer. */
+               peer_flag_unset(peer, PEER_FLAG_ROUTEADV);
+               peer->routeadv = 0;
+       }
 
-       if (peer->sort == BGP_PEER_IBGP)
-               peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV;
+       /* Set timer with fallback to default value. */
+       if (peer->routeadv)
+               peer->v_routeadv = peer->routeadv;
        else
-               peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
+               peer->v_routeadv = (peer->sort == BGP_PEER_IBGP)
+                                          ? BGP_DEFAULT_IBGP_ROUTEADV
+                                          : BGP_DEFAULT_EBGP_ROUTEADV;
 
+       /* Check if handling a regular peer. */
        if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+               /* Update peer route announcements. */
                update_group_adjust_peer_afs(peer);
                if (peer->status == Established)
                        bgp_announce_route_all(peer);
+
+               /* Skip peer-group mechanics for regular peers. */
                return 0;
        }
 
-       /* peer-group member updates. */
-       group = peer->group;
-       for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
-               UNSET_FLAG(peer->config, PEER_CONFIG_ROUTEADV);
-               peer->routeadv = 0;
+       /*
+        * Remove flag and configuration from all peer-group members, unless
+        * they are explicitely overriding peer-group configuration.
+        */
+       for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+               /* Skip peers with overridden configuration. */
+               if (CHECK_FLAG(member->flags_override, PEER_FLAG_ROUTEADV))
+                       continue;
 
-               if (peer->sort == BGP_PEER_IBGP)
-                       peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV;
-               else
-                       peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
+               /* Remove flag and configuration on peer-group member. */
+               UNSET_FLAG(member->flags, PEER_FLAG_ROUTEADV);
+               member->routeadv = 0;
+               member->v_routeadv = (member->sort == BGP_PEER_IBGP)
+                                            ? BGP_DEFAULT_IBGP_ROUTEADV
+                                            : BGP_DEFAULT_EBGP_ROUTEADV;
 
-               update_group_adjust_peer_afs(peer);
-               if (peer->status == Established)
-                       bgp_announce_route_all(peer);
+               /* Update peer route announcements. */
+               update_group_adjust_peer_afs(member);
+               if (member->status == Established)
+                       bgp_announce_route_all(member);
        }
 
        return 0;
@@ -5204,7 +5282,7 @@ int peer_allowas_in_unset(struct peer *peer, afi_t afi, safi_t safi)
                peer_af_flag_inherit(peer, afi, safi, PEER_FLAG_ALLOWAS_IN);
                peer_af_flag_inherit(peer, afi, safi,
                                     PEER_FLAG_ALLOWAS_IN_ORIGIN);
-               PEER_ATTR_INHERIT(peer, allowas_in[afi][safi]);
+               PEER_ATTR_INHERIT(peer, peer->group, allowas_in[afi][safi]);
                peer_on_policy_change(peer, afi, safi, 0);
 
                return 0;
@@ -5249,8 +5327,9 @@ int peer_allowas_in_unset(struct peer *peer, afi_t afi, safi_t safi)
 int peer_local_as_set(struct peer *peer, as_t as, int no_prepend,
                      int replace_as)
 {
+       bool old_no_prepend, old_replace_as;
        struct bgp *bgp = peer->bgp;
-       struct peer_group *group;
+       struct peer *member;
        struct listnode *node, *nnode;
 
        if (peer_sort(peer) != BGP_PEER_EBGP
@@ -5263,57 +5342,71 @@ int peer_local_as_set(struct peer *peer, as_t as, int no_prepend,
        if (peer->as == as)
                return BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS_REMOTE_AS;
 
-       if (peer->change_local_as == as
-           && ((CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND)
-                && no_prepend)
-               || (!CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND)
-                   && !no_prepend))
-           && ((CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS)
-                && replace_as)
-               || (!CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS)
-                   && !replace_as)))
-               return 0;
+       /* Save previous flag states. */
+       old_no_prepend =
+               !!CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
+       old_replace_as =
+               !!CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
 
-       peer->change_local_as = as;
-       if (no_prepend)
-               SET_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
-       else
-               UNSET_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
+       /* Set flag and configuration on peer. */
+       peer_flag_set(peer, PEER_FLAG_LOCAL_AS);
+       peer_flag_modify(peer, PEER_FLAG_LOCAL_AS_NO_PREPEND, no_prepend);
+       peer_flag_modify(peer, PEER_FLAG_LOCAL_AS_REPLACE_AS, replace_as);
 
-       if (replace_as)
-               SET_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
-       else
-               UNSET_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
+       if (peer->change_local_as == as && old_no_prepend == no_prepend
+           && old_replace_as == replace_as)
+               return 0;
+       peer->change_local_as = as;
 
+       /* Check if handling a regular peer. */
        if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+               /* Send notification or reset peer depending on state. */
                if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
                        peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE;
                        bgp_notify_send(peer, BGP_NOTIFY_CEASE,
                                        BGP_NOTIFY_CEASE_CONFIG_CHANGE);
                } else
                        bgp_session_reset(peer);
+
+               /* Skip peer-group mechanics for regular peers. */
                return 0;
        }
 
-       group = peer->group;
-       for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
-               peer->change_local_as = as;
-               if (no_prepend)
-                       SET_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
-               else
-                       UNSET_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
+       /*
+        * Set flag and configuration on all peer-group members, unless they are
+        * explicitely overriding peer-group configuration.
+        */
+       for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+               /* Skip peers with overridden configuration. */
+               if (CHECK_FLAG(member->flags_override, PEER_FLAG_LOCAL_AS))
+                       continue;
 
-               if (replace_as)
-                       SET_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
-               else
-                       UNSET_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
+               /* Skip peers with the same configuration. */
+               old_no_prepend = CHECK_FLAG(member->flags,
+                                           PEER_FLAG_LOCAL_AS_NO_PREPEND);
+               old_replace_as = CHECK_FLAG(member->flags,
+                                           PEER_FLAG_LOCAL_AS_REPLACE_AS);
+               if (member->change_local_as == as
+                   && CHECK_FLAG(member->flags, PEER_FLAG_LOCAL_AS)
+                   && old_no_prepend == no_prepend
+                   && old_replace_as == replace_as)
+                       continue;
 
-               if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
-                       peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE;
-                       bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+               /* Set flag and configuration on peer-group member. */
+               SET_FLAG(member->flags, PEER_FLAG_LOCAL_AS);
+               COND_FLAG(member->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND,
+                         no_prepend);
+               COND_FLAG(member->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS,
+                         replace_as);
+               member->change_local_as = as;
+
+               /* Send notification or stop peer depending on state. */
+               if (BGP_IS_VALID_STATE_FOR_NOTIF(member->status)) {
+                       member->last_reset = PEER_DOWN_LOCAL_AS_CHANGE;
+                       bgp_notify_send(member, BGP_NOTIFY_CEASE,
                                        BGP_NOTIFY_CEASE_CONFIG_CHANGE);
                } else
-                       BGP_EVENT_ADD(peer, BGP_Stop);
+                       BGP_EVENT_ADD(member, BGP_Stop);
        }
 
        return 0;
@@ -5321,17 +5414,29 @@ int peer_local_as_set(struct peer *peer, as_t as, int no_prepend,
 
 int peer_local_as_unset(struct peer *peer)
 {
-       struct peer_group *group;
+       struct peer *member;
        struct listnode *node, *nnode;
 
-       if (!peer->change_local_as)
+       if (!CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS))
                return 0;
 
-       peer->change_local_as = 0;
-       UNSET_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
-       UNSET_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
+       /* Inherit configuration from peer-group if peer is member. */
+       if (peer_group_active(peer)) {
+               peer_flag_inherit(peer, PEER_FLAG_LOCAL_AS);
+               peer_flag_inherit(peer, PEER_FLAG_LOCAL_AS_NO_PREPEND);
+               peer_flag_inherit(peer, PEER_FLAG_LOCAL_AS_REPLACE_AS);
+               PEER_ATTR_INHERIT(peer, peer->group, change_local_as);
+       } else {
+               /* Otherwise remove flag and configuration from peer. */
+               peer_flag_unset(peer, PEER_FLAG_LOCAL_AS);
+               peer_flag_unset(peer, PEER_FLAG_LOCAL_AS_NO_PREPEND);
+               peer_flag_unset(peer, PEER_FLAG_LOCAL_AS_REPLACE_AS);
+               peer->change_local_as = 0;
+       }
 
+       /* Check if handling a regular peer. */
        if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+               /* Send notification or stop peer depending on state. */
                if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
                        peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE;
                        bgp_notify_send(peer, BGP_NOTIFY_CEASE,
@@ -5339,77 +5444,103 @@ int peer_local_as_unset(struct peer *peer)
                } else
                        BGP_EVENT_ADD(peer, BGP_Stop);
 
+               /* Skip peer-group mechanics for regular peers. */
                return 0;
        }
 
-       group = peer->group;
-       for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
-               peer->change_local_as = 0;
-               UNSET_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
-               UNSET_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
+       /*
+        * Remove flag and configuration from all peer-group members, unless
+        * they are explicitely overriding peer-group configuration.
+        */
+       for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+               /* Skip peers with overridden configuration. */
+               if (CHECK_FLAG(member->flags_override, PEER_FLAG_LOCAL_AS))
+                       continue;
 
-               if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
-                       peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE;
-                       bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+               /* Remove flag and configuration on peer-group member. */
+               UNSET_FLAG(member->flags, PEER_FLAG_LOCAL_AS);
+               UNSET_FLAG(member->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
+               UNSET_FLAG(member->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
+               member->change_local_as = 0;
+
+               /* Send notification or stop peer depending on state. */
+               if (BGP_IS_VALID_STATE_FOR_NOTIF(member->status)) {
+                       member->last_reset = PEER_DOWN_LOCAL_AS_CHANGE;
+                       bgp_notify_send(member, BGP_NOTIFY_CEASE,
                                        BGP_NOTIFY_CEASE_CONFIG_CHANGE);
                } else
-                       bgp_session_reset(peer);
+                       bgp_session_reset(member);
        }
+
        return 0;
 }
 
 /* Set password for authenticating with the peer. */
 int peer_password_set(struct peer *peer, const char *password)
 {
-       struct listnode *nn, *nnode;
+       struct peer *member;
+       struct listnode *node, *nnode;
        int len = password ? strlen(password) : 0;
        int ret = BGP_SUCCESS;
 
        if ((len < PEER_PASSWORD_MINLEN) || (len > PEER_PASSWORD_MAXLEN))
                return BGP_ERR_INVALID_VALUE;
 
-       if (peer->password && strcmp(peer->password, password) == 0
-           && !CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+       /* Set flag and configuration on peer. */
+       peer_flag_set(peer, PEER_FLAG_PASSWORD);
+       if (peer->password && strcmp(peer->password, password) == 0)
                return 0;
-
-       if (peer->password)
-               XFREE(MTYPE_PEER_PASSWORD, peer->password);
-
+       XFREE(MTYPE_PEER_PASSWORD, peer->password);
        peer->password = XSTRDUP(MTYPE_PEER_PASSWORD, password);
 
+       /* Check if handling a regular peer. */
        if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+               /* Send notification or reset peer depending on state. */
                if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
                        bgp_notify_send(peer, BGP_NOTIFY_CEASE,
                                        BGP_NOTIFY_CEASE_CONFIG_CHANGE);
                else
                        bgp_session_reset(peer);
 
+               /*
+                * Attempt to install password on socket and skip peer-group
+                * mechanics.
+                */
                if (BGP_PEER_SU_UNSPEC(peer))
                        return BGP_SUCCESS;
-
                return (bgp_md5_set(peer) >= 0) ? BGP_SUCCESS
                                                : BGP_ERR_TCPSIG_FAILED;
        }
 
-       for (ALL_LIST_ELEMENTS(peer->group->peer, nn, nnode, peer)) {
-               if (peer->password && strcmp(peer->password, password) == 0)
+       /*
+        * Set flag and configuration on all peer-group members, unless they are
+        * explicitely overriding peer-group configuration.
+        */
+       for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+               /* Skip peers with overridden configuration. */
+               if (CHECK_FLAG(member->flags_override, PEER_FLAG_PASSWORD))
                        continue;
 
-               if (peer->password)
-                       XFREE(MTYPE_PEER_PASSWORD, peer->password);
-
-               peer->password = XSTRDUP(MTYPE_PEER_PASSWORD, password);
+               /* Skip peers with the same password. */
+               if (member->password && strcmp(member->password, password) == 0)
+                       continue;
 
-               if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
-                       bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+               /* Set flag and configuration on peer-group member. */
+               SET_FLAG(member->flags, PEER_FLAG_PASSWORD);
+               if (member->password)
+                       XFREE(MTYPE_PEER_PASSWORD, member->password);
+               member->password = XSTRDUP(MTYPE_PEER_PASSWORD, password);
+
+               /* Send notification or reset peer depending on state. */
+               if (BGP_IS_VALID_STATE_FOR_NOTIF(member->status))
+                       bgp_notify_send(member, BGP_NOTIFY_CEASE,
                                        BGP_NOTIFY_CEASE_CONFIG_CHANGE);
                else
-                       bgp_session_reset(peer);
+                       bgp_session_reset(member);
 
-               if (!BGP_PEER_SU_UNSPEC(peer)) {
-                       if (bgp_md5_set(peer) < 0)
-                               ret = BGP_ERR_TCPSIG_FAILED;
-               }
+               /* Attempt to install password on socket. */
+               if (!BGP_PEER_SU_UNSPEC(member) && bgp_md5_set(member) < 0)
+                       ret = BGP_ERR_TCPSIG_FAILED;
        }
 
        return ret;
@@ -5417,47 +5548,63 @@ int peer_password_set(struct peer *peer, const char *password)
 
 int peer_password_unset(struct peer *peer)
 {
-       struct listnode *nn, *nnode;
+       struct peer *member;
+       struct listnode *node, *nnode;
 
-       if (!peer->password && !CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+       if (!CHECK_FLAG(peer->flags, PEER_FLAG_PASSWORD))
                return 0;
 
+       /* Inherit configuration from peer-group if peer is member. */
+       if (peer_group_active(peer)) {
+               peer_flag_inherit(peer, PEER_FLAG_PASSWORD);
+               PEER_STR_ATTR_INHERIT(peer, peer->group, password,
+                                     MTYPE_PEER_PASSWORD);
+       } else {
+               /* Otherwise remove flag and configuration from peer. */
+               peer_flag_unset(peer, PEER_FLAG_PASSWORD);
+               XFREE(MTYPE_PEER_PASSWORD, peer->password);
+       }
+
+       /* Check if handling a regular peer. */
        if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+               /* Send notification or reset peer depending on state. */
                if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
                        bgp_notify_send(peer, BGP_NOTIFY_CEASE,
                                        BGP_NOTIFY_CEASE_CONFIG_CHANGE);
                else
                        bgp_session_reset(peer);
 
-               if (peer->password)
-                       XFREE(MTYPE_PEER_PASSWORD, peer->password);
-
-               peer->password = NULL;
-
+               /* Attempt to uninstall password on socket. */
                if (!BGP_PEER_SU_UNSPEC(peer))
                        bgp_md5_unset(peer);
 
+               /* Skip peer-group mechanics for regular peers. */
                return 0;
        }
 
-       XFREE(MTYPE_PEER_PASSWORD, peer->password);
-       peer->password = NULL;
-
-       for (ALL_LIST_ELEMENTS(peer->group->peer, nn, nnode, peer)) {
-               if (!peer->password)
+       /*
+        * Remove flag and configuration from all peer-group members, unless
+        * they are explicitely overriding peer-group configuration.
+        */
+       for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+               /* Skip peers with overridden configuration. */
+               if (CHECK_FLAG(member->flags_override, PEER_FLAG_PASSWORD))
                        continue;
 
-               if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
-                       bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+               /* Remove flag and configuration on peer-group member. */
+               UNSET_FLAG(member->flags, PEER_FLAG_PASSWORD);
+               XFREE(MTYPE_PEER_PASSWORD, member->password);
+
+               /* Send notification or reset peer depending on state. */
+               if (BGP_IS_VALID_STATE_FOR_NOTIF(member->status))
+                       bgp_notify_send(member, BGP_NOTIFY_CEASE,
                                        BGP_NOTIFY_CEASE_CONFIG_CHANGE);
                else
-                       bgp_session_reset(peer);
-
-               XFREE(MTYPE_PEER_PASSWORD, peer->password);
-               peer->password = NULL;
+                       bgp_session_reset(member);
 
-               if (!BGP_PEER_SU_UNSPEC(peer))
-                       bgp_md5_unset(peer);
+               /* Attempt to uninstall password on socket. */
+               if (!BGP_PEER_SU_UNSPEC(member))
+                       bgp_md5_unset(member);
        }
 
        return 0;
@@ -5538,9 +5685,11 @@ int peer_distribute_unset(struct peer *peer, afi_t afi, safi_t safi, int direct)
 
        /* Inherit configuration from peer-group if peer is member. */
        if (peer_group_active(peer)) {
-               PEER_STR_ATTR_INHERIT(MTYPE_BGP_FILTER_NAME, peer,
-                                     filter[afi][safi].dlist[direct].name);
-               PEER_ATTR_INHERIT(peer, filter[afi][safi].dlist[direct].alist);
+               PEER_STR_ATTR_INHERIT(peer, peer->group,
+                                     filter[afi][safi].dlist[direct].name,
+                                     MTYPE_BGP_FILTER_NAME);
+               PEER_ATTR_INHERIT(peer, peer->group,
+                                 filter[afi][safi].dlist[direct].alist);
        } else {
                /* Otherwise remove configuration from peer. */
                filter = &peer->filter[afi][safi];
@@ -5721,9 +5870,11 @@ int peer_prefix_list_unset(struct peer *peer, afi_t afi, safi_t safi,
 
        /* Inherit configuration from peer-group if peer is member. */
        if (peer_group_active(peer)) {
-               PEER_STR_ATTR_INHERIT(MTYPE_BGP_FILTER_NAME, peer,
-                                     filter[afi][safi].plist[direct].name);
-               PEER_ATTR_INHERIT(peer, filter[afi][safi].plist[direct].plist);
+               PEER_STR_ATTR_INHERIT(peer, peer->group,
+                                     filter[afi][safi].plist[direct].name,
+                                     MTYPE_BGP_FILTER_NAME);
+               PEER_ATTR_INHERIT(peer, peer->group,
+                                 filter[afi][safi].plist[direct].plist);
        } else {
                /* Otherwise remove configuration from peer. */
                filter = &peer->filter[afi][safi];
@@ -5902,9 +6053,10 @@ int peer_aslist_unset(struct peer *peer, afi_t afi, safi_t safi, int direct)
 
        /* Inherit configuration from peer-group if peer is member. */
        if (peer_group_active(peer)) {
-               PEER_STR_ATTR_INHERIT(MTYPE_BGP_FILTER_NAME, peer,
-                                     filter[afi][safi].aslist[direct].name);
-               PEER_ATTR_INHERIT(peer,
+               PEER_STR_ATTR_INHERIT(peer, peer->group,
+                                     filter[afi][safi].aslist[direct].name,
+                                     MTYPE_BGP_FILTER_NAME);
+               PEER_ATTR_INHERIT(peer, peer->group,
                                  filter[afi][safi].aslist[direct].aslist);
        } else {
                /* Otherwise remove configuration from peer. */
@@ -6087,9 +6239,11 @@ int peer_route_map_unset(struct peer *peer, afi_t afi, safi_t safi, int direct)
 
        /* Inherit configuration from peer-group if peer is member. */
        if (peer_group_active(peer)) {
-               PEER_STR_ATTR_INHERIT(MTYPE_BGP_FILTER_NAME, peer,
-                                     filter[afi][safi].map[direct].name);
-               PEER_ATTR_INHERIT(peer, filter[afi][safi].map[direct].map);
+               PEER_STR_ATTR_INHERIT(peer, peer->group,
+                                     filter[afi][safi].map[direct].name,
+                                     MTYPE_BGP_FILTER_NAME);
+               PEER_ATTR_INHERIT(peer, peer->group,
+                                 filter[afi][safi].map[direct].map);
        } else {
                /* Otherwise remove configuration from peer. */
                filter = &peer->filter[afi][safi];
@@ -6196,9 +6350,11 @@ int peer_unsuppress_map_unset(struct peer *peer, afi_t afi, safi_t safi)
 
        /* Inherit configuration from peer-group if peer is member. */
        if (peer_group_active(peer)) {
-               PEER_STR_ATTR_INHERIT(MTYPE_BGP_FILTER_NAME, peer,
-                                     filter[afi][safi].usmap.name);
-               PEER_ATTR_INHERIT(peer, filter[afi][safi].usmap.map);
+               PEER_STR_ATTR_INHERIT(peer, peer->group,
+                                     filter[afi][safi].usmap.name,
+                                     MTYPE_BGP_FILTER_NAME);
+               PEER_ATTR_INHERIT(peer, peer->group,
+                                 filter[afi][safi].usmap.map);
        } else {
                /* Otherwise remove configuration from peer. */
                filter = &peer->filter[afi][safi];
@@ -6309,9 +6465,9 @@ int peer_maximum_prefix_unset(struct peer *peer, afi_t afi, safi_t safi)
                peer_af_flag_inherit(peer, afi, safi, PEER_FLAG_MAX_PREFIX);
                peer_af_flag_inherit(peer, afi, safi,
                                     PEER_FLAG_MAX_PREFIX_WARNING);
-               PEER_ATTR_INHERIT(peer, pmax[afi][safi]);
-               PEER_ATTR_INHERIT(peer, pmax_threshold[afi][safi]);
-               PEER_ATTR_INHERIT(peer, pmax_restart[afi][safi]);
+               PEER_ATTR_INHERIT(peer, peer->group, pmax[afi][safi]);
+               PEER_ATTR_INHERIT(peer, peer->group, pmax_threshold[afi][safi]);
+               PEER_ATTR_INHERIT(peer, peer->group, pmax_restart[afi][safi]);
 
                return 0;
        }
@@ -6859,26 +7015,14 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
        }
 
        /* local-as */
-       if (peer->change_local_as) {
-               if (!peer_group_active(peer)
-                   || peer->change_local_as != g_peer->change_local_as
-                   || (CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND)
-                       != CHECK_FLAG(g_peer->flags,
-                                     PEER_FLAG_LOCAL_AS_NO_PREPEND))
-                   || (CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS)
-                       != CHECK_FLAG(g_peer->flags,
-                                     PEER_FLAG_LOCAL_AS_REPLACE_AS))) {
-                       vty_out(vty, " neighbor %s local-as %u%s%s\n", addr,
-                               peer->change_local_as,
-                               CHECK_FLAG(peer->flags,
-                                          PEER_FLAG_LOCAL_AS_NO_PREPEND)
-                                       ? " no-prepend"
-                                       : "",
-                               CHECK_FLAG(peer->flags,
-                                          PEER_FLAG_LOCAL_AS_REPLACE_AS)
-                                       ? " replace-as"
-                                       : "");
-               }
+       if (peergroup_flag_check(peer, PEER_FLAG_LOCAL_AS)) {
+               vty_out(vty, " neighbor %s local-as %u", addr,
+                       peer->change_local_as);
+               if (peergroup_flag_check(peer, PEER_FLAG_LOCAL_AS_NO_PREPEND))
+                       vty_out(vty, " no-prepend");
+               if (peergroup_flag_check(peer, PEER_FLAG_LOCAL_AS_REPLACE_AS))
+                       vty_out(vty, " replace-as");
+               vty_out(vty, "\n");
        }
 
        /* description */
@@ -6887,17 +7031,12 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
        }
 
        /* shutdown */
-       if (CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN)) {
-               if (!peer_group_active(peer)
-                   || !CHECK_FLAG(g_peer->flags, PEER_FLAG_SHUTDOWN)
-                   || peer->tx_shutdown_message) {
-                       if (peer->tx_shutdown_message)
-                               vty_out(vty,
-                                       " neighbor %s shutdown message %s\n",
-                                       addr, peer->tx_shutdown_message);
-                       else
-                               vty_out(vty, " neighbor %s shutdown\n", addr);
-               }
+       if (peergroup_flag_check(peer, PEER_FLAG_SHUTDOWN)) {
+               if (peer->tx_shutdown_message)
+                       vty_out(vty, " neighbor %s shutdown message %s\n", addr,
+                               peer->tx_shutdown_message);
+               else
+                       vty_out(vty, " neighbor %s shutdown\n", addr);
        }
 
        /* bfd */
@@ -6908,13 +7047,9 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
        }
 
        /* password */
-       if (peer->password) {
-               if (!peer_group_active(peer) || !g_peer->password
-                   || strcmp(peer->password, g_peer->password) != 0) {
-                       vty_out(vty, " neighbor %s password %s\n", addr,
-                               peer->password);
-               }
-       }
+       if (peergroup_flag_check(peer, PEER_FLAG_PASSWORD))
+               vty_out(vty, " neighbor %s password %s\n", addr,
+                       peer->password);
 
        /* neighbor solo */
        if (CHECK_FLAG(peer->flags, PEER_FLAG_LONESOUL)) {
@@ -6934,12 +7069,8 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
        }
 
        /* passive */
-       if (CHECK_FLAG(peer->flags, PEER_FLAG_PASSIVE)) {
-               if (!peer_group_active(peer)
-                   || !CHECK_FLAG(g_peer->flags, PEER_FLAG_PASSIVE)) {
-                       vty_out(vty, " neighbor %s passive\n", addr);
-               }
-       }
+       if (peergroup_flag_check(peer, PEER_FLAG_PASSIVE))
+               vty_out(vty, " neighbor %s passive\n", addr);
 
        /* ebgp-multihop */
        if (peer->sort != BGP_PEER_IBGP && peer->ttl != 1
@@ -6960,129 +7091,66 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
        }
 
        /* disable-connected-check */
-       if (CHECK_FLAG(peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) {
-               if (!peer_group_active(peer)
-                   || !CHECK_FLAG(g_peer->flags,
-                                  PEER_FLAG_DISABLE_CONNECTED_CHECK)) {
-                       vty_out(vty, " neighbor %s disable-connected-check\n",
-                               addr);
-               }
-       }
+       if (peergroup_flag_check(peer, PEER_FLAG_DISABLE_CONNECTED_CHECK))
+               vty_out(vty, " neighbor %s disable-connected-check\n", addr);
 
        /* enforce-first-as */
-       if (CHECK_FLAG(peer->flags, PEER_FLAG_ENFORCE_FIRST_AS)) {
-               if (!peer_group_active(peer)
-                   || !CHECK_FLAG(g_peer->flags, PEER_FLAG_ENFORCE_FIRST_AS)) {
-                       vty_out(vty, " neighbor %s enforce-first-as\n", addr);
-               }
-       }
+       if (peergroup_flag_check(peer, PEER_FLAG_ENFORCE_FIRST_AS))
+               vty_out(vty, " neighbor %s enforce-first-as\n", addr);
 
        /* update-source */
-       if (peer->update_if) {
-               if (!peer_group_active(peer) || !g_peer->update_if
-                   || strcmp(g_peer->update_if, peer->update_if) != 0) {
-                       vty_out(vty, " neighbor %s update-source %s\n", addr,
-                               peer->update_if);
-               }
-       }
-       if (peer->update_source) {
-               if (!peer_group_active(peer) || !g_peer->update_source
-                   || sockunion_cmp(g_peer->update_source, peer->update_source)
-                              != 0) {
+       if (peergroup_flag_check(peer, PEER_FLAG_UPDATE_SOURCE)) {
+               if (peer->update_source)
                        vty_out(vty, " neighbor %s update-source %s\n", addr,
                                sockunion2str(peer->update_source, buf,
                                              SU_ADDRSTRLEN));
-               }
+               else if (peer->update_if)
+                       vty_out(vty, " neighbor %s update-source %s\n", addr,
+                               peer->update_if);
        }
 
        /* advertisement-interval */
-       if (CHECK_FLAG(peer->config, PEER_CONFIG_ROUTEADV)
-           && ((!peer_group_active(peer)
-                && peer->v_routeadv != BGP_DEFAULT_EBGP_ROUTEADV)
-               || (peer_group_active(peer)
-                   && peer->v_routeadv != g_peer->v_routeadv))) {
+       if (peergroup_flag_check(peer, PEER_FLAG_ROUTEADV))
                vty_out(vty, " neighbor %s advertisement-interval %u\n", addr,
-                       peer->v_routeadv);
-       }
+                       peer->routeadv);
 
        /* timers */
-       if ((PEER_OR_GROUP_TIMER_SET(peer))
-           && ((!peer_group_active(peer)
-                && (peer->keepalive != BGP_DEFAULT_KEEPALIVE
-                    || peer->holdtime != BGP_DEFAULT_HOLDTIME))
-               || (peer_group_active(peer)
-                   && (peer->keepalive != g_peer->keepalive
-                       || peer->holdtime != g_peer->holdtime)))) {
+       if (peergroup_flag_check(peer, PEER_FLAG_TIMER))
                vty_out(vty, " neighbor %s timers %u %u\n", addr,
                        peer->keepalive, peer->holdtime);
-       }
-
-       if (CHECK_FLAG(peer->config, PEER_CONFIG_CONNECT)
-           && ((!peer_group_active(peer)
-                && peer->connect != BGP_DEFAULT_CONNECT_RETRY)
-               || (peer_group_active(peer)
-                   && peer->connect != g_peer->connect)))
 
-       {
+       /* timers connect */
+       if (peergroup_flag_check(peer, PEER_FLAG_TIMER_CONNECT))
                vty_out(vty, " neighbor %s timers connect %u\n", addr,
                        peer->connect);
-       }
 
        /* capability dynamic */
-       if (CHECK_FLAG(peer->flags, PEER_FLAG_DYNAMIC_CAPABILITY)) {
-               if (!peer_group_active(peer)
-                   || !CHECK_FLAG(g_peer->flags,
-                                  PEER_FLAG_DYNAMIC_CAPABILITY)) {
-                       vty_out(vty, " neighbor %s capability dynamic\n", addr);
-               }
-       }
+       if (peergroup_flag_check(peer, PEER_FLAG_DYNAMIC_CAPABILITY))
+               vty_out(vty, " neighbor %s capability dynamic\n", addr);
 
        /* capability extended-nexthop */
-       if (peer->ifp && !CHECK_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE)) {
-               if (!peer_group_active(peer)
-                   || !CHECK_FLAG(g_peer->flags, PEER_FLAG_CAPABILITY_ENHE)) {
+       if (peergroup_flag_check(peer, PEER_FLAG_CAPABILITY_ENHE)) {
+               if (CHECK_FLAG(peer->flags_invert, PEER_FLAG_CAPABILITY_ENHE))
                        vty_out(vty,
                                " no neighbor %s capability extended-nexthop\n",
                                addr);
-               }
-       }
-
-       if (!peer->ifp && CHECK_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE)) {
-               if (!peer_group_active(peer)
-                   || !CHECK_FLAG(g_peer->flags, PEER_FLAG_CAPABILITY_ENHE)) {
+               else
                        vty_out(vty,
                                " neighbor %s capability extended-nexthop\n",
                                addr);
-               }
        }
 
        /* dont-capability-negotiation */
-       if (CHECK_FLAG(peer->flags, PEER_FLAG_DONT_CAPABILITY)) {
-               if (!peer_group_active(peer)
-                   || !CHECK_FLAG(g_peer->flags, PEER_FLAG_DONT_CAPABILITY)) {
-                       vty_out(vty, " neighbor %s dont-capability-negotiate\n",
-                               addr);
-               }
-       }
+       if (peergroup_flag_check(peer, PEER_FLAG_DONT_CAPABILITY))
+               vty_out(vty, " neighbor %s dont-capability-negotiate\n", addr);
 
        /* override-capability */
-       if (CHECK_FLAG(peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) {
-               if (!peer_group_active(peer)
-                   || !CHECK_FLAG(g_peer->flags,
-                                  PEER_FLAG_OVERRIDE_CAPABILITY)) {
-                       vty_out(vty, " neighbor %s override-capability\n",
-                               addr);
-               }
-       }
+       if (peergroup_flag_check(peer, PEER_FLAG_OVERRIDE_CAPABILITY))
+               vty_out(vty, " neighbor %s override-capability\n", addr);
 
        /* strict-capability-match */
-       if (CHECK_FLAG(peer->flags, PEER_FLAG_STRICT_CAP_MATCH)) {
-               if (!peer_group_active(peer)
-                   || !CHECK_FLAG(g_peer->flags, PEER_FLAG_STRICT_CAP_MATCH)) {
-                       vty_out(vty, " neighbor %s strict-capability-match\n",
-                               addr);
-               }
-       }
+       if (peergroup_flag_check(peer, PEER_FLAG_STRICT_CAP_MATCH))
+               vty_out(vty, " neighbor %s strict-capability-match\n", addr);
 }
 
 /* BGP peer configuration display function. */
index 33d65bcb0f8d5b3d36ed7b8d686a67f2c085cdde..1fbc0a0db9fe0e8c04ad5b5dac5e0a09c7decc3f 100644 (file)
@@ -822,6 +822,61 @@ struct peer {
 #define PEER_CAP_ENHE_AF_NEGO               (1 << 14) /* Extended nexthop afi/safi negotiated */
 
        /* Global configuration flags. */
+       /*
+        * Parallel array to flags that indicates whether each flag originates
+        * from a peer-group or if it is config that is specific to this
+        * individual peer. If a flag is set independent of the peer-group, the
+        * same bit should be set here. If this peer is a peer-group, this
+        * memory region should be all zeros.
+        *
+        * The assumption is that the default state for all flags is unset,
+        * so if a flag is unset, the corresponding override flag is unset too.
+        * However if a flag is set, the corresponding override flag is set.
+        */
+       uint32_t flags_override;
+       /*
+        * Parallel array to flags that indicates whether the default behavior
+        * of *flags_override* should be inverted. If a flag is unset and the
+        * corresponding invert flag is set, the corresponding override flag
+        * would be set. However if a flag is set and the corresponding invert
+        * flag is unset, the corresponding override flag would be unset.
+        *
+        * This can be used for attributes like *send-community*, which are
+        * implicitely enabled and have to be disabled explicitely, compared to
+        * 'normal' attributes like *next-hop-self* which are implicitely set.
+        *
+        * All operations dealing with flags should apply the following boolean
+        * logic to keep the internal flag system in a sane state:
+        *
+        * value=0 invert=0     Inherit flag if member, otherwise unset flag
+        * value=0 invert=1     Unset flag unconditionally
+        * value=1 invert=0     Set flag unconditionally
+        * value=1 invert=1     Inherit flag if member, otherwise set flag
+        *
+        * Contrary to the implementation of *flags_override*, the flag
+        * inversion state can be set either on the peer OR the peer *and* the
+        * peer-group. This was done on purpose, as the inversion state of a
+        * flag can be determined on either the peer or the peer-group.
+        *
+        * Example: Enabling the cisco configuration mode inverts all flags
+        * related to *send-community* unconditionally for both peer-groups and
+        * peers.
+        *
+        * This behavior is different for interface peers though, which enable
+        * the *extended-nexthop* flag by default, which regular peers do not.
+        * As the peer-group can contain both regular and interface peers, the
+        * flag inversion state must be set on the peer only.
+        *
+        * When a peer inherits the configuration from a peer-group and the
+        * inversion state of the flag differs between peer and peer-group, the
+        * newly set value must equal to the inverted state of the peer-group.
+        */
+       uint32_t flags_invert;
+       /*
+        * Effective array for storing the peer/peer-group flags. In case of a
+        * peer-group, the peer-specific overrides (see flags_override and
+        * flags_invert) must be respected.
+        */
        uint32_t flags;
 #define PEER_FLAG_PASSIVE                   (1 << 0) /* passive mode */
 #define PEER_FLAG_SHUTDOWN                  (1 << 1) /* shutdown */
@@ -840,6 +895,12 @@ struct peer {
 #define PEER_FLAG_IFPEER_V6ONLY             (1 << 14) /* if-based peer is v6 only */
 #define PEER_FLAG_IS_RFAPI_HD               (1 << 15) /* attached to rfapi HD */
 #define PEER_FLAG_ENFORCE_FIRST_AS          (1 << 16) /* enforce-first-as */
+#define PEER_FLAG_ROUTEADV                  (1 << 17) /* route advertise */
+#define PEER_FLAG_TIMER                     (1 << 18) /* keepalive & holdtime */
+#define PEER_FLAG_TIMER_CONNECT             (1 << 19) /* connect timer */
+#define PEER_FLAG_PASSWORD                  (1 << 20) /* password */
+#define PEER_FLAG_LOCAL_AS                  (1 << 21) /* local-as */
+#define PEER_FLAG_UPDATE_SOURCE             (1 << 22) /* update-source */
 
        /* outgoing message sent in CEASE_ADMIN_SHUTDOWN notify */
        char *tx_shutdown_message;
@@ -849,37 +910,13 @@ struct peer {
 
        /* Peer Per AF flags */
        /*
-        * Parallel array to af_flags that indicates whether each flag
-        * originates from a peer-group or if it is config that is specific to
-        * this individual peer. If a flag is set independent of the
-        * peer-group the same bit should be set here. If this peer is a
-        * peer-group, this memory region should be all zeros. The assumption
-        * is that the default state for all flags is unset.
-        *
-        * Notes:
-        * - if a flag for an individual peer is unset, the corresponding
-        *   override flag is unset and the peer is considered to be back in
-        *   sync with the peer-group.
-        * - This does *not* contain the flag values, rather it contains
-        *   whether the flag at the same position in af_flags is
-        *   *peer-specific*.
+        * Please consult the comments for *flags_override*, *flags_invert* and
+        * *flags* to understand what these three arrays do. The address-family
+        * specific attributes are being treated the exact same way as global
+        * peer attributes.
         */
        uint32_t af_flags_override[AFI_MAX][SAFI_MAX];
-       /*
-        * Parallel array to af_flags that indicates whether each flag should
-        * be treated as regular (defaults to 0) or inverted (defaults to 1).
-        * If a flag is set to 1 by default, the same bit should be set here.
-        *
-        * Notes:
-        * - This does *not* contain the flag values, rather it contains
-        *   whether the flag at the same position in af_flags is *regular* or
-        *   *inverted*.
-        */
        uint32_t af_flags_invert[AFI_MAX][SAFI_MAX];
-       /*
-        * Effective flags, computed by applying peer-group flags and then
-        * overriding with individual flags
-        */
        uint32_t af_flags[AFI_MAX][SAFI_MAX];
 #define PEER_FLAG_SEND_COMMUNITY            (1 << 0) /* send-community */
 #define PEER_FLAG_SEND_EXT_COMMUNITY        (1 << 1) /* send-community ext. */
@@ -937,17 +974,7 @@ struct peer {
 #define PEER_STATUS_EOR_SEND          (1 << 4) /* end-of-rib send to peer */
 #define PEER_STATUS_EOR_RECEIVED      (1 << 5) /* end-of-rib received from peer */
 
-       /* Default attribute value for the peer. */
-       uint32_t config;
-#define PEER_CONFIG_TIMER             (1 << 0) /* keepalive & holdtime */
-#define PEER_CONFIG_CONNECT           (1 << 1) /* connect */
-#define PEER_CONFIG_ROUTEADV          (1 << 2) /* route advertise */
-#define PEER_GROUP_CONFIG_TIMER       (1 << 3) /* timers from peer-group */
-
-#define PEER_OR_GROUP_TIMER_SET(peer)                                          \
-       (CHECK_FLAG(peer->config, PEER_CONFIG_TIMER)                           \
-        || CHECK_FLAG(peer->config, PEER_GROUP_CONFIG_TIMER))
-
+       /* Configured timer values. */
        _Atomic uint32_t holdtime;
        _Atomic uint32_t keepalive;
        _Atomic uint32_t connect;
@@ -1153,13 +1180,23 @@ struct peer {
 DECLARE_QOBJ_TYPE(peer)
 
 /* Inherit peer attribute from peer-group. */
-#define PEER_ATTR_INHERIT(peer, attr) ((peer)->attr = (peer)->group->conf->attr)
-#define PEER_STR_ATTR_INHERIT(mt, peer, attr)                                  \
+#define PEER_ATTR_INHERIT(peer, group, attr)                                   \
+       ((peer)->attr = (group)->conf->attr)
+#define PEER_STR_ATTR_INHERIT(peer, group, attr, mt)                           \
        do {                                                                   \
                if ((peer)->attr)                                              \
                        XFREE(mt, (peer)->attr);                               \
-               if ((peer)->group->conf->attr)                                 \
-                       (peer)->attr = XSTRDUP(mt, (peer)->group->conf->attr); \
+               if ((group)->conf->attr)                                       \
+                       (peer)->attr = XSTRDUP(mt, (group)->conf->attr);       \
+               else                                                           \
+                       (peer)->attr = NULL;                                   \
+       } while (0)
+#define PEER_SU_ATTR_INHERIT(peer, group, attr)                                \
+       do {                                                                   \
+               if ((peer)->attr)                                              \
+                       sockunion_free((peer)->attr);                          \
+               if ((group)->conf->attr)                                       \
+                       (peer)->attr = sockunion_dup((group)->conf->attr);     \
                else                                                           \
                        (peer)->attr = NULL;                                   \
        } while (0)
@@ -1557,6 +1594,7 @@ extern int peer_group_unbind(struct bgp *, struct peer *, struct peer_group *);
 
 extern int peer_flag_set(struct peer *, uint32_t);
 extern int peer_flag_unset(struct peer *, uint32_t);
+extern void peer_flag_inherit(struct peer *peer, uint32_t flag);
 
 extern int peer_af_flag_set(struct peer *, afi_t, safi_t, uint32_t);
 extern int peer_af_flag_unset(struct peer *, afi_t, safi_t, uint32_t);
index 2f93328887efcf874b19fa67571c3e7d9ec62acc..8553846c9025137bbf0b5a0db3f14b6cf60f522c 100644 (file)
@@ -662,7 +662,8 @@ static int rfapi_str2route_type(const char *l3str, const char *pstr, afi_t *afi,
                        vnc_import_bgp_exterior_redist_enable((bgp), (afi));   \
                        break;                                                 \
                default:                                                       \
-                       vnc_redistribute_set((bgp), (afi), (type));            \
+                       if ((type) < ZEBRA_ROUTE_MAX)                          \
+                               vnc_redistribute_set((bgp), (afi), (type));    \
                        break;                                                 \
                }                                                              \
        } while (0)
@@ -677,7 +678,8 @@ static int rfapi_str2route_type(const char *l3str, const char *pstr, afi_t *afi,
                        vnc_import_bgp_exterior_redist_disable((bgp), (afi));  \
                        break;                                                 \
                default:                                                       \
-                       vnc_redistribute_unset((bgp), (afi), (type));          \
+                       if ((type) < ZEBRA_ROUTE_MAX)                          \
+                               vnc_redistribute_unset((bgp), (afi), (type));  \
                        break;                                                 \
                }                                                              \
        } while (0)
@@ -1424,7 +1426,8 @@ DEFUN (vnc_export_nvegroup,
        if (rfg_new == NULL) {
                rfg_new = bgp_rfapi_cfg_match_byname(bgp, argv[5]->arg,
                                                     RFAPI_GROUP_CFG_VRF);
-               vnc_add_vrf_opener(bgp, rfg_new);
+               if (rfg_new)
+                       vnc_add_vrf_opener(bgp, rfg_new);
        }
 
        if (rfg_new == NULL) {
@@ -4516,7 +4519,7 @@ void bgp_rfapi_show_summary(struct bgp *bgp, struct vty *vty)
        if (VNC_EXPORT_ZEBRA_GRP_ENABLED(hc)) {
                redist++;
                vty_out(vty, "%sToZebra Groups={", (redist == 1 ? "" : " "));
-               if (hc->rfg_export_direct_bgp_l) {
+               if (hc->rfg_export_zebra_l) {
                        int cnt = 0;
                        struct listnode *node, *nnode;
                        struct rfapi_rfg_name *rfgn;
index 8d782864c8c5c3958bf17f4611803f7f35cc0620..177244d2778bb882b6bd84f1592c2484795fb724 100644 (file)
@@ -3368,13 +3368,7 @@ DEFUN (debug_rfapi_query_vn_un_l2o,
 {
        struct rfapi_ip_addr vn;
        struct rfapi_ip_addr un;
-       struct rfapi_ip_addr target;
-       rfapi_handle handle;
        int rc;
-       struct rfapi_next_hop_entry *pNextHopEntry;
-       struct rfapi_l2address_option l2o_buf;
-       struct bgp_tea_options hopt;
-       uint8_t valbuf[14];
 
        /*
         * Get VN addr
@@ -3389,69 +3383,8 @@ DEFUN (debug_rfapi_query_vn_un_l2o,
        if ((rc = rfapiCliGetRfapiIpAddr(vty, argv[6]->arg, &un)))
                return rc;
 
-
-#if 0 /* there is no IP target arg here ?????? */
-  /*
-   * Get target addr
-   */
-  if ((rc = rfapiCliGetRfapiIpAddr (vty, argv[2], &target)))
-    return rc;
-#else
        vty_out(vty, "%% This command is broken.\n");
        return CMD_WARNING_CONFIG_FAILED;
-#endif
-
-       if (rfapi_find_handle_vty(vty, &vn, &un, &handle)) {
-               vty_out(vty, "can't locate handle matching vn=%s, un=%s\n",
-                       argv[4]->arg, argv[6]->arg);
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-
-       /*
-        * Set up L2 parameters
-        */
-       memset(&l2o_buf, 0, sizeof(l2o_buf));
-       if (rfapiStr2EthAddr(argv[10]->arg, &l2o_buf.macaddr)) {
-               vty_out(vty, "Bad mac address \"%s\"\n", argv[10]->arg);
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-
-       l2o_buf.logical_net_id = strtoul(argv[8]->arg, NULL, 10);
-
-       /* construct option chain */
-
-       memset(valbuf, 0, sizeof(valbuf));
-       memcpy(valbuf, &l2o_buf.macaddr.octet, ETH_ALEN);
-       valbuf[11] = (l2o_buf.logical_net_id >> 16) & 0xff;
-       valbuf[12] = (l2o_buf.logical_net_id >> 8) & 0xff;
-       valbuf[13] = l2o_buf.logical_net_id & 0xff;
-
-       memset(&hopt, 0, sizeof(hopt));
-       hopt.options_count = 1;
-       hopt.options_length = sizeof(valbuf); /* is this right? */
-       hopt.type = RFAPI_VN_OPTION_TYPE_L2ADDR;
-       hopt.length = sizeof(valbuf);
-       hopt.value = valbuf;
-
-
-       /*
-        * options parameter not used? Set to NULL for now
-        */
-       rc = rfapi_query(handle, &target, &l2o_buf, &pNextHopEntry);
-
-       if (rc) {
-               vty_out(vty, "rfapi_query failed with rc=%d (%s)\n", rc,
-                       strerror(rc));
-       } else {
-               /*
-                * print nexthop list
-                */
-               /* TBD enhance to print L2 information */
-               test_nexthops_callback(/*&target, */ pNextHopEntry,
-                                      vty); /* frees nh list! */
-       }
-
-       return CMD_SUCCESS;
 }
 
 
index ccaa472092d37e3c3b1873b13ef34c712c15016d..cd12edbccb1f9c47c30aadccd64f2684c9e93d27 100644 (file)
@@ -388,15 +388,11 @@ int rfapiStream2Vty(void *stream,                    /* input */
                return 1;
        }
 
-       if (stream) {
-               *vty = stream; /* VTYNL requires vty to be legit */
-               *fp = (int (*)(void *, const char *, ...))vty_out;
-               *outstream = stream;
-               *vty_newline = str_vty_newline(*vty);
-               return 1;
-       }
-
-       return 0;
+       *vty = stream; /* VTYNL requires vty to be legit */
+       *fp = (int (*)(void *, const char *, ...))vty_out;
+       *outstream = stream;
+       *vty_newline = str_vty_newline(*vty);
+       return 1;
 }
 
 /* called from bgpd/bgp_vty.c'route_vty_out() */
@@ -1733,7 +1729,8 @@ void rfapiPrintMatchingDescriptors(struct vty *vty, struct prefix *vn_prefix,
 int rfapiCliGetPrefixAddr(struct vty *vty, const char *str, struct prefix *p)
 {
        if (!str2prefix(str, p)) {
-               vty_out(vty, "Malformed address \"%s\"%s", str, HVTYNL);
+               vty_out(vty, "Malformed address \"%s\"%s", str ? str : "null",
+                       HVTYNL);
                return CMD_WARNING;
        }
        switch (p->family) {
@@ -3020,9 +3017,9 @@ static int rfapiDeleteLocalPrefixesByRFD(struct rfapi_local_reg_delete_arg *cda,
                 * match un, vn addresses of NVEs
                 */
                if (pUn && (rfapi_ip_addr_cmp(pUn, &rfd->un_addr)))
-                       continue;
+                       break;
                if (pVn && (rfapi_ip_addr_cmp(pVn, &rfd->vn_addr)))
-                       continue;
+                       break;
 
 #if DEBUG_L2_EXTRA
                vnc_zlog_debug_verbose("%s: un, vn match", __func__);
index 6e3fb42fb9d59d3456448404c2cbf9cdabc50b3c..b29769da4947592de6355697719b502d69989020 100644 (file)
@@ -4,6 +4,8 @@
 Process & Workflow
 *******************
 
+.. highlight:: none
+
 FRR is a large project developed by many different groups. This section
 documents standards for code style & quality, commit messages, pull requests
 and best practices that all contributors are asked to follow.
@@ -35,43 +37,66 @@ community. Italicized lists are private.
 +----------------------------------+--------------------------------+
 
 The Development list is used to discuss and document general issues related to
-project development and governance. The public Slack instance,
-frrouting.slack.com, and weekly technical meetings provide a higher bandwidth
-channel for discussions.  The results of such discussions must be reflected in
-updates, as appropriate, to code (i.e., merges), `Github issues`_, and for
-governance or process changes, updates to the Development list and either this
-file or information posted at https://frrouting.org/.
+project development and governance. The public
+`Slack instance <https://frrouting.slack.com>`_ and weekly technical meetings
+provide a higher bandwidth channel for discussions.  The results of such
+discussions must be reflected in updates, as appropriate, to code (i.e.,
+merges), `GitHub issues`_, and for governance or process changes, updates to
+the Development list and either this file or information posted at
+https://frrouting.org/.
+
+Development & Release Cycle
+===========================
+
+Development
+-----------
+
+.. figure:: ../figures/git_branches.png
+   :align: center
+   :scale: 55%
+   :alt: Merging Git branches into a central trunk
+
+   Rough outline of FRR development workflow
+
+The master Git for FRR resides on `GitHub`_.
+
+There is one main branch for development, ``master``. For each major release
+(2.0, 3.0 etc) a new release branch is created based on the master. Significant
+bugfixes should be backported to upcoming and existing release branches no more
+than 1 year old. As a general rule new features are not backported to release
+branches.
 
-Release Process & Schedule
-==========================
+Subsequent point releases based on a major branch are handled with git tags.
 
-FRR employs a <MAJOR>.<MINOR>.<BUGFIX> versioning scheme.
+Releases
+--------
+FRR employs a ``<MAJOR>.<MINOR>.<BUGFIX>`` versioning scheme.
 
-MAJOR
+``MAJOR``
    Significant new features or multiple minor features. The addition of a new
    routing protocol or daemon would fall under this class.
 
-MINOR
+``MINOR``
    Small features, e.g. options for automatic BGP shutdown.
 
-BUGFIX
+``BUGFIX``
    Fixes for actual bugs and/or security issues.
 
 We will pull a new development branch for the next release every 4 months.  The
-current schedule is Feb/June/October 1. The decision for a MAJOR/MINOR release
-is made at the time of branch pull based on what has been received the previous
-4 months. The branch name will be dev/MAJOR.MINOR. At this point in time the
-master branch, :file:`configure.ac`, documentation and packaging systems will
-be updated to reflect the next possible release name to allow for easy
-distinguishing. Additionally the new dev branch will have these files updated
-too.
-
-After one month the development branch will be renamed to stable/MAJOR.MINOR.
-This process is not held up unless a crash or security issue has been found and
-needs to be addressed. Issues being fixed will not cause a delay.
+current schedule is Feb/June/October 1. The decision for a ``MAJOR/MINOR``
+release is made at the time of branch pull based on what has been received the
+previous 4 months. The branch name will be ``dev/MAJOR.MINOR``. At this point
+in time the master branch and this new branch, :file:`configure.ac`,
+documentation and packaging systems will be updated to reflect the next
+possible release name to allow for easy distinguishing.
+
+After one month the development branch will be renamed to
+``stable/MAJOR.MINOR``.  This process is not held up unless a crash or security
+issue has been found and needs to be addressed. Issues being fixed will not
+cause a delay.
 
 Bugfix releases are made as needed at 1 month intervals until the next
-MAJOR.MINOR relese branch is pulled. Depending on the severity of the bugs,
+``MAJOR.MINOR`` relese branch is pulled. Depending on the severity of the bugs,
 bugfix releases may occur sooner.
 
 Bugfixes are applied to the two most recent releases. Security fixes are
@@ -79,8 +104,7 @@ backported to all releases less than or equal to one year old. Security fixes
 may also be backported to older releases depending on severity.
 
 Changelog
-=========
-
+---------
 The changelog will be the base for the release notes. A changelog entry for
 your changes is usually not required and will be added based on your commit
 messages by the maintainers. However, you are free to include an update to the
@@ -92,149 +116,133 @@ Submitting Patches and Enhancements
 FRR accepts patches from two sources:
 
 - Email (git format-patch)
-- Github pull request
+- GitHub pull request
 
-Contributors are highly encouraged to use Github's fork-and-pr workflow. It is
-easier for us to review it, test it, try it and discuss it on Github than it is
-via email, thus your patch will get more attention more quickly on Github.
+Contributors are highly encouraged to use GitHub's fork-and-PR workflow. It is
+easier for us to review it, test it, try it and discuss it on GitHub than it is
+via email, thus your patch will get more attention more quickly on GitHub.
 
 The base branch for new contributions and non-critical bug fixes should be
 ``master``. Please ensure your pull request is based on this branch when you
 submit it.
 
-Pre-submission Checklist
-------------------------
-
--  Format code (see `Code Formatting <#code-formatting>`__)
--  Verify and acknowledge license (see `License for
-   contributions <#license-for-contributions>`__)
--  Ensure you have properly signed off (see `Signing
-   Off <#signing-off>`__)
--  Test building with various configurations:
-
-   -  ``buildtest.sh``
-
--  Verify building source distribution:
-
-   -  ``make dist`` (and try rebuilding from the resulting tar file)
-
--  Run unit tests:
+GitHub Pull Requests
+--------------------
 
-   -  ``make test``
+The preferred method of submitting changes is a GitHub pull request.  Code
+submitted by pull request will be automatically tested by one or more CI
+systems. Once the automated tests succeed, other developers will review your
+code for quality and correctness. After any concerns are resolved, your code
+will be merged into the branch it was submitted against.
 
--  Document Regression Runs and plans for continued maintenance of the
-   feature
+Patch Submission via Mailing List
+---------------------------------
 
-License for contributions
--------------------------
+As an alternative submission method, a patch can be mailed to the
+development mailing list. Patches received on the mailing list will be
+picked up by Patchwork and tested against the latest development branch.
 
-FRR is under a “GPLv2 or later” license. Any code submitted must
-be released under the same license (preferred) or any license which
-allows redistribution under this GPLv2 license (eg MIT License).
+The recommended way to send the patch (or series of NN patches) to the
+list is by using ``git send-email`` as follows (assuming they are the N
+most recent commit(s) in your git history)::
 
-Signing Off
------------
+    git send-email -NN --annotate --to=dev@lists.frrouting.org
 
-Code submitted to FRR must be signed off. We have the same
-requirements for using the signed-off-by process as the Linux kernel. In
-short, you must include a signed-off-by tag in every patch.
+If your commits do not already contain a ``Signed-off-by`` line, then
+use the following command to add it (after making sure you agree to the
+Developer Certificate of Origin as outlined above)::
 
-``Signed-off-by:`` this is a developer's certification that he or she
-has the right to submit the patch for inclusion into the project. It is
-an agreement to the Developer's Certificate of Origin (below). Code
-without a proper signoff can not and will not be merged.
+    git send-email -NN --annotate --signoff --to=dev@lists.frrouting.org
 
-If you are unfamiliar with this process, you should read the `official
-policy at
-kernel.org <https://www.kernel.org/doc/html/latest/process/submitting-patches.html>`__
-and you might find this article about `participating in the Linux
-community on the Linux Foundation
-website <http://www.linuxfoundation.org/content/how-participate-linux-community-0>`__
-to be a helpful resource.
+Submitting multi-commit patches as a GitHub pull request is **strongly
+encouraged** and increases the probability of your patch getting reviewed and
+merged in a timely manner.
 
-In short, when you sign off on a commit, you assert your agreement to
-all of the following:
+.. _license-for-contributions:
 
-::
+License for Contributions
+-------------------------
+FRR is under a “GPLv2 or later” license. Any code submitted must be released
+under the same license (preferred) or any license which allows redistribution
+under this GPLv2 license (eg MIT License).
 
-    Developer's Certificate of Origin 1.1
+Pre-submission Checklist
+------------------------
+-  Format code (see `Code Formatting <#code-formatting>`__)
+-  Verify and acknowledge license (see :ref:`license-for-contributions`)
+-  Ensure you have properly signed off (see :ref:`signing-off`)
+-  Test building with various configurations:
 
-    By making a contribution to this project, I certify that:
+   -  ``buildtest.sh``
 
-    (a) The contribution was created in whole or in part by me and I
-        have the right to submit it under the open source license
-        indicated in the file; or
+-  Verify building source distribution:
 
-    (b) The contribution is based upon previous work that, to the best
-        of my knowledge, is covered under an appropriate open source
-        license and I have the right under that license to submit that
-        work with modifications, whether created in whole or in part by
-        me, under the same open source license (unless I am permitted to
-        submit under a different license), as indicated in the file; or
+   -  ``make dist`` (and try rebuilding from the resulting tar file)
 
-    (c) The contribution was provided directly to me by some other
-        person who certified (a), (b) or (c) and I have not modified it.
+-  Run unit tests:
 
-    (d) I understand and agree that this project and the contribution
-        are public and that a record of the contribution (including all
-        personal information I submit with it, including my sign-off) is
-        maintained indefinitely and may be redistributed consistent with
-        this project or the open source license(s) involved.
+   -  ``make test``
 
-What do I submit my changes against?
-------------------------------------
+- In the case of a major new feature or other significant change, document
+  plans for continued maintenance of the feature
 
-We've documented where we would like to have the different fixes applied
-at
-https://github.com/FRRouting/frr/wiki/Where-Do-I-create-a-Pull-Request-against%3F
-If you are unsure where your submission goes, look at that document or
-ask a project maintainer.
+.. _signing-off:
 
-Github pull requests
---------------------
+Signing Off
+-----------
+Code submitted to FRR must be signed off. We have the same requirements for
+using the signed-off-by process as the Linux kernel. In short, you must include
+a ``Signed-off-by`` tag in every patch.
 
-The preferred method of submitting changes is a Github pull request.
-Code submitted by pull request will be automatically tested by one or
-more CI systems. Once the automated tests succeed, other developers will
-review your code for quality and correctness. After any concerns are
-resolved, your code will be merged into the branch it was submitted
-against.
+``Signed-off-by`` is a developer's certification that they have the right to
+submit the patch for inclusion into the project. It is an agreement to the
+:ref:`Developer's Certificate of Origin <developers-certificate-of-origin>`.
+Code without a proper ``Signed-off-by`` line cannot and will not be merged.
 
-Patch submission via mailing list
----------------------------------
+If you are unfamiliar with this process, you should read the
+`official policy at kernel.org <https://www.kernel.org/doc/html/latest/process/submitting-patches.html>`_.
+You might also find
+`this article <http://www.linuxfoundation.org/content/how-participate-linux-community-0>`_
+about participating in the Linux community on the Linux Foundation website to
+be a helpful resource.
 
-As an alternative submission method, a patch can be mailed to the
-development mailing list. Patches received on the mailing list will be
-picked up by Patchwork and tested against the latest development branch.
+.. _developers-certificate-of-origin:
 
-The recommended way to send the patch (or series of NN patches) to the
-list is by using ``git send-email`` as follows (assuming they are the N
-most recent commit(s) in your git history:
+In short, when you sign off on a commit, you assert your agreement to all of
+the following::
 
-::
+   Developer's Certificate of Origin 1.1
 
-    git send-email -NN --annotate --to=dev@lists.frrouting.org
+   By making a contribution to this project, I certify that:
 
-If your commits do not already contain a ``Signed-off-by`` line, then
-use the following command to add it (after making sure you agree to the
-Developer Certificate of Origin as outlined above):
+   (a) The contribution was created in whole or in part by me and I
+       have the right to submit it under the open source license
+       indicated in the file; or
 
-::
+   (b) The contribution is based upon previous work that, to the best
+       of my knowledge, is covered under an appropriate open source
+       license and I have the right under that license to submit that
+       work with modifications, whether created in whole or in part by
+       me, under the same open source license (unless I am permitted to
+       submit under a different license), as indicated in the file; or
 
-    git send-email -NN --annotate --signoff --to=dev@lists.frrouting.org
+   (c) The contribution was provided directly to me by some other
+       person who certified (a), (b) or (c) and I have not modified it.
 
-Submitting multi-commit patches as a Github pull request is **strongly
-encouraged** and increases the probability of your patch getting
-reviewed and merged in a timely manner.
+   (d) I understand and agree that this project and the contribution
+       are public and that a record of the contribution (including all
+       personal information I submit with it, including my sign-off) is
+       maintained indefinitely and may be redistributed consistent with
+       this project or the open source license(s) involved.
 
-After submitting your changes
+After Submitting Your Changes
 -----------------------------
 
--  Watch for Continuous Integration (CI) Test results
+-  Watch for Continuous Integration (CI) test results
 
    -  You should automatically receive an email with the test results
       within less than 2 hrs of the submission. If you don’t get the
-      email, then check status on the Github pull request.
+      email, then check status on the GitHub pull request.
    -  Please notify the development mailing list if you think something
       doesn't work.
 
@@ -273,22 +281,6 @@ After submitting your changes
    community members.
 -  Your submission is done once it is merged to the master branch.
 
-Git Structure
-=============
-
-.. figure:: ../figures/git_branches.png
-   :align: center
-   :scale: 55%
-   :alt: Merging Git branches into a central trunk
-
-   Rough outline of FRR development workflow
-
-The master Git for FRR resides on `GitHub`_.
-
-There is one main branch for development, ``master``. For each major release
-(2.0, 3.0 etc) a new release branch is created based on the master. Subsequent
-point releases based on a major branch are marked by tagging.
-
 Programming Languages, Tools and Libraries
 ==========================================
 
@@ -308,7 +300,6 @@ Documentation should be written in reStructuredText. Sphinx extensions may be
 utilized but pure ReST is preferred where possible. See
 :ref:`documentation`.
 
-
 Coding Practices & Style
 ========================
 
@@ -316,30 +307,33 @@ Commit messages
 ---------------
 
 Commit messages should be formatted in the same way as Linux kernel
-commit messages. The format is roughly
-
-::
+commit messages. The format is roughly::
 
     dir: short summary
 
     extended summary
 
-``dir`` should be the top level source directory under which the change
-was made. For example, a change in bgpd/rfapi would be formatted as:::
+``dir`` should be the top level source directory under which the change was
+made. For example, a change in :file:`bgpd/rfapi` would be formatted as::
 
    bgpd: short summary
 
-The first line should be no longer than 50 characters. Subsequent lines
-should be wrapped to 72 characters.
+   ...
+
+The first line should be no longer than 50 characters. Subsequent lines should
+be wrapped to 72 characters.
 
-Source file header
+You must also sign off on your commit.
+
+.. seealso:: :ref:`signing-off`
+
+Source File Header
 ------------------
 
-New files need to have a Copyright header (see `License for
-contributions <#license-for-contributions>`__ above) added to the file.
-Preferred form of the header is as follows:
+New files must have a copyright header (see :ref:`license-for-contributions`
+above) added to the file. The header should be:
 
-::
+.. code-block:: c
 
     /*
      * Title/Function of file
@@ -362,25 +356,34 @@ Preferred form of the header is as follows:
 
     #include <zebra.h>
 
-Adding copyright claims to existing files
+Please copy-paste this header verbatim. In particular:
+
+- Do not replace "This program" with "FRR"
+- Do not change the address of the FSF
+
+Adding Copyright Claims to Existing Files
 -----------------------------------------
 
-When adding copyright claims for modifications to an existing file,
-please preface the claim with "Portions: " on a line before it and
-indent the "Copyright ..." string. If such a case already exists, add
-your indented claim immediately after. E.g.:
+When adding copyright claims for modifications to an existing file, please
+add a ``Portions:`` section as shown below. If this section already exists, add
+your new claim at the end of the list.
 
-::
+.. code-block:: c
 
-    Portions:
-      Copyright (C) 2010 Entity A ....
-      Copyright (C) 2016 Your name [optional brief change description]
+    /*
+     * Title/Function of file
+     * Copyright (C) YEAR  Author’s Name
+     * Portions:
+     *     Copyright (C) 2010 Entity A ....
+     *     Copyright (C) 2016 Your name [optional brief change description]
+     * ...
+     */
 
 Code Formatting
 ---------------
 
-FRR uses Linux kernel style except where noted below. Code which does
-not comply with these style guidelines will not be accepted.
+FRR uses Linux kernel style except where noted below. Code which does not
+comply with these style guidelines will not be accepted.
 
 The project provides multiple tools to allow you to correctly style your code
 as painlessly as possible, primarily built around ``clang-format``.
@@ -451,11 +454,9 @@ checkpatch.sh
    submission is highly recommended. The CI system runs this script as well and
    will comment on the PR with the results if style errors are found.
 
-   It is run like this:
-
-   ::
+   It is run like this::
 
-      checkpatch.sh <patch> <tree>
+      ./checkpatch.sh <patch> <tree>
 
    Reports are generated on ``stderr`` and the exit code indicates whether
    issues were found (2, 1) or not (0).
@@ -635,20 +636,19 @@ is preferred to
     frobnicate ();
     #endif /* SOME_SYMBOL */
 
-Note that the former approach requires ensuring that ``SOME_SYMBOL``
-will be defined (watch your ``AC_DEFINE``\ s).
+Note that the former approach requires ensuring that ``SOME_SYMBOL`` will be
+defined (watch your ``AC_DEFINE``\ s).
 
 Debug-guards in code
 --------------------
 
-Debugging statements are an important methodology to allow developers to
-fix issues found in the code after it has been released. The caveat here
-is that the developer must remember that people will be using the code
-at scale and in ways that can be unexpected for the original
-implementor. As such debugs **MUST** be guarded in such a way that they
-can be turned off. FRR has the ability to turn on/off debugs from the
-CLI and it is expected that the developer will use this convention to
-allow control of their debugs.
+Debugging statements are an important methodology to allow developers to fix
+issues found in the code after it has been released. The caveat here is that
+the developer must remember that people will be using the code at scale and in
+ways that can be unexpected for the original implementor. As such debugs
+**MUST** be guarded in such a way that they can be turned off. FRR has the
+ability to turn on/off debugs from the CLI and it is expected that the
+developer will use this convention to allow control of their debugs.
 
 Static Analysis and Sanitizers
 ------------------------------
@@ -704,53 +704,50 @@ members with Coverity access of newly introduced defects.
 CLI changes
 -----------
 
-CLI's are a complicated ugly beast. Additions or changes to the CLI
-should use a DEFUN to encapsulate one setting as much as is possible.
-Additionally as new DEFUN's are added to the system, documentation
-should be provided for the new commands.
+CLI's are a complicated ugly beast. Additions or changes to the CLI should use
+a DEFUN to encapsulate one setting as much as is possible.  Additionally as new
+DEFUN's are added to the system, documentation should be provided for the new
+commands.
 
 Backwards Compatibility
 -----------------------
 
-As a general principle, changes to CLI and code in the lib/ directory
-should be made in a backwards compatible fashion. This means that
-changes that are purely stylistic in nature should be avoided, e.g.,
-renaming an existing macro or library function name without any
-functional change. When adding new parameters to common functions, it is
-also good to consider if this too should be done in a backward
-compatible fashion, e.g., by preserving the old form in addition to
+As a general principle, changes to CLI and code in the lib/ directory should be
+made in a backwards compatible fashion. This means that changes that are purely
+stylistic in nature should be avoided, e.g., renaming an existing macro or
+library function name without any functional change. When adding new parameters
+to common functions, it is also good to consider if this too should be done in
+a backward compatible fashion, e.g., by preserving the old form in addition to
 adding the new form.
 
-This is not to say that minor or even major functional changes to CLI
-and common code should be avoided, but rather that the benefit gained
-from a change should be weighed against the added cost/complexity to
-existing code. Also, that when making such changes, it is good to
-preserve compatibility when possible to do so without introducing
-maintenance overhead/cost. It is also important to keep in mind,
-existing code includes code that may reside in private repositories (and
-is yet to be submitted) or code that has yet to be migrated from Quagga
-to FRR.
-
-That said, compatibility measures can (and should) be removed when
-either:
-
--  they become a significant burden, e.g. when data structures change
-   and the compatibility measure would need a complex adaptation layer
-   or becomes flat-out impossible
--  some measure of time (dependent on the specific case) has passed, so
-   that the compatibility grace period is considered expired.
-
-In all cases, compatibility pieces should be marked with
-compiler/preprocessor annotations to print warnings at compile time,
-pointing to the appropriate update path. A ``-Werror`` build should fail
-if compatibility bits are used. To avoid compilation issues in released
-code, such compiler/preprocessor annotations must be ignored
-non-development branches. For example:
-
-    #if defined(VERSION_TYPE_DEV) && CONFDATE > 20180403
-    CPP_NOTICE("Use of <XYZ> is deprecated, please use <ABC>")
-    #endif
+This is not to say that minor or even major functional changes to CLI and
+common code should be avoided, but rather that the benefit gained from a change
+should be weighed against the added cost/complexity to existing code. Also,
+that when making such changes, it is good to preserve compatibility when
+possible to do so without introducing maintenance overhead/cost. It is also
+important to keep in mind, existing code includes code that may reside in
+private repositories (and is yet to be submitted) or code that has yet to be
+migrated from Quagga to FRR.
 
+That said, compatibility measures can (and should) be removed when either:
+
+-  they become a significant burden, e.g. when data structures change and the
+   compatibility measure would need a complex adaptation layer or becomes
+   flat-out impossible
+-  some measure of time (dependent on the specific case) has passed, so that
+   the compatibility grace period is considered expired.
+
+In all cases, compatibility pieces should be marked with compiler/preprocessor
+annotations to print warnings at compile time, pointing to the appropriate
+update path. A ``-Werror`` build should fail if compatibility bits are used. To
+avoid compilation issues in released code, such compiler/preprocessor
+annotations must be ignored non-development branches. For example:
+
+.. code-block:: c
+
+   #if defined(VERSION_TYPE_DEV) && CONFDATE > 20180403
+   CPP_NOTICE("Use of <XYZ> is deprecated, please use <ABC>")
+   #endif
 
 Preferably, the shell script :file:`tools/fixup-deprecated.py` will be
 updated along with making non-backwards compatible code changes, or an
@@ -762,8 +759,8 @@ changes, just internal code, macros and libraries.
 Miscellaneous
 -------------
 
-When in doubt, follow the guidelines in the Linux kernel style guide, or
-ask on the development mailing list / public Slack instance.
+When in doubt, follow the guidelines in the Linux kernel style guide, or ask on
+the development mailing list / public Slack instance.
 
 
 .. _documentation:
@@ -859,14 +856,19 @@ Some specific guidelines that contributors should follow are:
      /*
       * Determines whether or not a string is cool.
       *
-      * @param text - the string to check for coolness
-      * @param is_clccfc - whether capslock is cruise control for cool
-      * @return 7 if the text is cool, 0 otherwise
+      * text
+      *    the string to check for coolness
+      *
+      * is_clccfc
+      *    whether capslock is cruise control for cool
+      *
+      * Returns:
+      *    7 if the text is cool, 0 otherwise
       */
      int check_coolness(const char *text, bool is_clccfc);
 
-  The Javadoc-style annotations are not required, but you should still strive
-  to make it equally clear what parameters and return values are used for.
+  Function comments should make it clear what parameters and return values are
+  used for.
 
 - Static functions should have descriptive comments in the same form as above
   if what they do is not immediately obvious. Use good engineering judgement
index a75017c4429ec3ef582ec39eee483d6b58cf513d..cb46080055bde7fc1d69621f320a7f0d4a3388b8 100644 (file)
@@ -405,6 +405,18 @@ These options apply to all |PACKAGE_NAME| daemons.
 
    Print program version.
 
+.. option:: --log <stdout|syslog|file:/path/to/log/file>
+
+   When initializing the daemon, setup the log to go to either stdout,
+   syslog or to a file.  These values will be displayed as part of
+   a show run.  Additionally they can be overridden at runtime if
+   desired via the normal log commands.
+
+.. option:: --log-level <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>
+
+   When initializing the daemon, allow the specification of a default
+   log level at startup from one of the specified levels.
+
 .. _loadable-module-support:
 
 Loadable Module Support
index aa48a3cd4f72ff5621e799a5c2f0e078bf1fc4ef..638767c55777b4a54ee7497c1a24b6875650ec82 100644 (file)
@@ -33,7 +33,6 @@ Nexthop Groups
 Nexthop groups are a way to encapsulate ECMP information together.  It's a
 listing of ECMP nexthops used to forward packets for when a pbr-map is matched.
 
-.. index:: nexthop-group
 .. clicmd:: nexthop-group NAME
 
    Create a nexthop-group with an associated NAME.  This will put you into a
@@ -46,24 +45,38 @@ listing of ECMP nexthops used to forward packets for when a pbr-map is matched.
    are used to are allowed here.  The syntax was intentionally kept the same as
    creating nexthops as you would for static routes.
 
+.. clicmd:: [no] pbr table range (10000-4294966272) (10000-4294966272)
+
+   Set or unset the range used to assign numeric table ID's to new
+   nexthop-group tables. Existing tables will not be modified to fit in this
+   range, so it is recommended to configure this before adding nexthop groups.
+
+   .. seealso:: :ref:`pbr-details`
+
+Showing Nexthop Group Information
+---------------------------------
+
+.. clicmd:: show pbr nexthop-groups [NAME]
+
+   Display information on a PBR nexthop-group. If ``NAME`` is omitted, all
+   nexthop groups are shown.
+
 .. _pbr-maps:
 
 PBR Maps
 ========
 
-PBR maps are a way to group policies that we would like to apply
-to individual interfaces.  These policies when applied are matched
-against incoming packets.  If matched the nexthop-group or nexthop
-is used to forward the packets to the end destination
+PBR maps are a way to group policies that we would like to apply to individual
+interfaces. These policies when applied are matched against incoming packets.
+If matched the nexthop-group or nexthop is used to forward the packets to the
+end destination.
 
-.. index:: pbr-map
 .. clicmd:: pbr-map NAME seq (1-700)
 
    Create a pbr-map with NAME and sequence number specified.  This command puts
    you into a new submode for pbr-map specification.  To exit this mode type
    exit or end as per normal conventions for leaving a sub-mode.
 
-.. index:: match
 .. clicmd:: match src-ip PREFIX
 
    When a incoming packet matches the source prefix specified, take the packet
index 04bda5f236c14fcb9352ed336c4d714d6a2ebc36..feb77db1e154615802f19cbd70bd6a2e4c4b69ea 100644 (file)
@@ -189,8 +189,8 @@ is in a vrf, enter the interface command with the vrf keyword at the end.
    Tell pim to receive IGMP reports and Query on this interface. The default
    version is v3. This command is useful on the LHR.
 
-.. index:: ip igmp join
-.. clicmd:: ip igmp join
+.. index:: ip igmp join A.B.C.D A.B.C.D
+.. clicmd:: ip igmp join A.B.C.D A.B.C.D
 
    Join multicast source-group on an interface.
 
@@ -404,10 +404,10 @@ cause great confusion.
 
    Display the multicast RIB created in zebra.
 
-.. index:: mtrace
-.. clicmd:: mtrace
+.. index:: mtrace A.B.C.D [A.B.C.D]
+.. clicmd:: mtrace A.B.C.D [A.B.C.D]
 
-   Display multicast traceroute towards source.
+   Display multicast traceroute towards source, optionally for particular group.
 
 PIM Debug Commands
 ==================
index 4107d440901c01e2690808d8efe1215b4ab6590e..eeefc519688ccce2c37f7298254b46bfa46b91be 100644 (file)
@@ -486,6 +486,7 @@ int eigrp_fsm_event_q_fcn(struct eigrp_fsm_action_message *msg)
 
 int eigrp_fsm_event_keep_state(struct eigrp_fsm_action_message *msg)
 {
+       struct eigrp *eigrp;
        struct eigrp_prefix_entry *prefix = msg->prefix;
        struct eigrp_nexthop_entry *ne = listnode_head(prefix->entries);
 
@@ -498,9 +499,10 @@ int eigrp_fsm_event_keep_state(struct eigrp_fsm_action_message *msg)
                        if (msg->packet_type == EIGRP_OPC_QUERY)
                                eigrp_send_reply(msg->adv_router, prefix);
                        prefix->req_action |= EIGRP_FSM_NEED_UPDATE;
-                       listnode_add(
-                               (eigrp_lookup())->topology_changes_internalIPV4,
-                               prefix);
+                       eigrp = eigrp_lookup();
+                       assert(eigrp);
+                       listnode_add(eigrp->topology_changes_internalIPV4,
+                                    prefix);
                }
                eigrp_topology_update_node_flags(prefix);
                eigrp_update_routing_table(prefix);
index cd459fdc42940fbb8fa580972971b5a91c96eaa2..cd62811fdfdadf34da3698590019f8974155b998 100644 (file)
@@ -336,6 +336,9 @@ void eigrp_if_free(struct eigrp_interface *ei, int source)
        struct eigrp_prefix_entry *pe;
        struct eigrp *eigrp = eigrp_lookup();
 
+       if (!eigrp)
+               return;
+
        if (source == INTERFACE_DOWN_BY_VTY) {
                THREAD_OFF(ei->t_hello);
                eigrp_hello_send(ei, EIGRP_HELLO_GRACEFUL_SHUTDOWN, NULL);
index 2578fecb35ccad6f07beaec573c42f760001706d..629beddec39a305c0a4a7ad659c7215fa9a978fd 100644 (file)
@@ -55,7 +55,10 @@ static void eigrp_network_run_interface(struct eigrp *, struct prefix *,
 int eigrp_sock_init(void)
 {
        int eigrp_sock;
-       int ret, hincl = 1;
+       int ret;
+#ifdef IP_HDRINCL
+       int hincl = 1;
+#endif
 
        if (eigrpd_privs.change(ZPRIVS_RAISE))
                zlog_err("eigrp_sock_init: could not raise privs, %s",
index 59864532cf9fde511ae9786a93547276ad6243df..fab21e52019b6d9cda10e61dd1236849ff691b92 100644 (file)
@@ -944,8 +944,6 @@ void eigrp_packet_free(struct eigrp_packet *ep)
        THREAD_OFF(ep->t_retrans_timer);
 
        XFREE(MTYPE_EIGRP_PACKET, ep);
-
-       ep = NULL;
 }
 
 /* EIGRP Header verification. */
index 7dd95b7bc6c860177b8d3dc0209fca72be2efa9e..21c92386aeb42fd767e52bbbcb5f18a960456cb0 100644 (file)
@@ -514,7 +514,6 @@ eigrp_snmp_nbr_lookup_next(struct in_addr *nbr_addr, unsigned int *ifindex,
        struct listnode *node, *nnode, *node2, *nnode2;
        struct eigrp_interface *ei;
        struct eigrp_neighbor *nbr;
-       struct route_node *rn;
        struct eigrp_neighbor *min = NULL;
        struct eigrp *eigrp;
 
@@ -573,7 +572,7 @@ static struct eigrp_neighbor *eigrpNbrLookup(struct variable *v, oid *name,
                first = 0;
                len = *length - v->namelen;
 
-               if (len <= 0)
+               if (len == 0)
                        first = 1;
 
                if (len > IN_ADDR_SIZE)
@@ -918,8 +917,6 @@ static uint8_t *eigrpTopologyEntry(struct variable *v, oid *name,
                                   WriteMethod **write_method)
 {
        struct eigrp *eigrp;
-       struct eigrp_interface *ei;
-       struct listnode *node, *nnode;
 
        eigrp = eigrp_lookup();
 
@@ -1067,7 +1064,6 @@ static uint8_t *eigrpPeerEntry(struct variable *v, oid *name, size_t *length,
 {
        struct eigrp *eigrp;
        struct eigrp_interface *ei;
-       struct listnode *node, *nnode;
        struct eigrp_neighbor *nbr;
        struct in_addr nbr_addr;
        unsigned int ifindex;
@@ -1199,11 +1195,9 @@ static uint8_t *eigrpInterfaceEntry(struct variable *v, oid *name,
                                    WriteMethod **write_method)
 {
        struct eigrp *eigrp;
-       struct eigrp_interface *ei;
        struct listnode *node, *nnode;
        struct keychain *keychain;
        struct list *keylist;
-       int counter;
 
        eigrp = eigrp_lookup();
 
index becb29a95faafb530994c6303284b98eeeaf1daf..8ca0e282a8cdfb09814505934e8cd94e46fb3877 100644 (file)
@@ -182,6 +182,9 @@ void eigrp_prefix_entry_delete(struct route_table *table,
        struct eigrp *eigrp = eigrp_lookup();
        struct route_node *rn;
 
+       if (!eigrp)
+               return;
+
        rn = route_node_lookup(table, pe->destination);
        if (!rn)
                return;
@@ -426,6 +429,9 @@ void eigrp_topology_update_all_node_flags(struct eigrp *eigrp)
        struct eigrp_prefix_entry *pe;
        struct route_node *rn;
 
+       if (!eigrp)
+               return;
+
        for (rn = route_top(eigrp->topology_table); rn; rn = route_next(rn)) {
                pe = rn->info;
 
@@ -442,6 +448,8 @@ void eigrp_topology_update_node_flags(struct eigrp_prefix_entry *dest)
        struct eigrp_nexthop_entry *entry;
        struct eigrp *eigrp = eigrp_lookup();
 
+       assert(eigrp);
+
        for (ALL_LIST_ELEMENTS_RO(dest->entries, node, entry)) {
                if (entry->reported_distance < dest->fdistance) {
                        // is feasible successor, can be successor
@@ -471,11 +479,15 @@ void eigrp_topology_update_node_flags(struct eigrp_prefix_entry *dest)
 void eigrp_update_routing_table(struct eigrp_prefix_entry *prefix)
 {
        struct eigrp *eigrp = eigrp_lookup();
-       struct list *successors =
-               eigrp_topology_get_successor_max(prefix, eigrp->max_paths);
+       struct list *successors;
        struct listnode *node;
        struct eigrp_nexthop_entry *entry;
 
+       if (!eigrp)
+               return;
+
+       successors = eigrp_topology_get_successor_max(prefix, eigrp->max_paths);
+
        if (successors) {
                eigrp_zebra_route_add(prefix->destination, successors);
                for (ALL_LIST_ELEMENTS_RO(successors, node, entry))
index a3080136b5bf815fd56596915cfd0ea33ddffed3..e0142f6b326363f0f1d0f6a42f2d4e9932238233 100644 (file)
@@ -757,7 +757,6 @@ static void eigrp_update_send_GR_part(struct eigrp_neighbor *nbr)
        prefixes = nbr->nbr_gr_prefixes_send;
 
        send_prefixes = 0;
-       length = EIGRP_HEADER_LEN;
 
        /* if there already were last packet chunk, we won't continue */
        if (nbr->nbr_gr_packet_type == EIGRP_PACKET_PART_LAST)
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
new file mode 100644 (file)
index 0000000..0b2c29b
--- /dev/null
@@ -0,0 +1,247 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef __LINUX_NETLINK_H
+#define __LINUX_NETLINK_H
+
+#include <linux/kernel.h>
+#include <linux/socket.h> /* for __kernel_sa_family_t */
+#include <linux/types.h>
+
+#define NETLINK_ROUTE          0       /* Routing/device hook                          */
+#define NETLINK_UNUSED         1       /* Unused number                                */
+#define NETLINK_USERSOCK       2       /* Reserved for user mode socket protocols      */
+#define NETLINK_FIREWALL       3       /* Unused number, formerly ip_queue             */
+#define NETLINK_SOCK_DIAG      4       /* socket monitoring                            */
+#define NETLINK_NFLOG          5       /* netfilter/iptables ULOG */
+#define NETLINK_XFRM           6       /* ipsec */
+#define NETLINK_SELINUX                7       /* SELinux event notifications */
+#define NETLINK_ISCSI          8       /* Open-iSCSI */
+#define NETLINK_AUDIT          9       /* auditing */
+#define NETLINK_FIB_LOOKUP     10      
+#define NETLINK_CONNECTOR      11
+#define NETLINK_NETFILTER      12      /* netfilter subsystem */
+#define NETLINK_IP6_FW         13
+#define NETLINK_DNRTMSG                14      /* DECnet routing messages */
+#define NETLINK_KOBJECT_UEVENT 15      /* Kernel messages to userspace */
+#define NETLINK_GENERIC                16
+/* leave room for NETLINK_DM (DM Events) */
+#define NETLINK_SCSITRANSPORT  18      /* SCSI Transports */
+#define NETLINK_ECRYPTFS       19
+#define NETLINK_RDMA           20
+#define NETLINK_CRYPTO         21      /* Crypto layer */
+#define NETLINK_SMC            22      /* SMC monitoring */
+
+#define NETLINK_INET_DIAG      NETLINK_SOCK_DIAG
+
+#define MAX_LINKS 32           
+
+struct sockaddr_nl {
+       __kernel_sa_family_t    nl_family;      /* AF_NETLINK   */
+       unsigned short  nl_pad;         /* zero         */
+       __u32           nl_pid;         /* port ID      */
+               __u32           nl_groups;      /* multicast groups mask */
+};
+
+struct nlmsghdr {
+       __u32           nlmsg_len;      /* Length of message including header */
+       __u16           nlmsg_type;     /* Message content */
+       __u16           nlmsg_flags;    /* Additional flags */
+       __u32           nlmsg_seq;      /* Sequence number */
+       __u32           nlmsg_pid;      /* Sending process port ID */
+};
+
+/* Flags values */
+
+#define NLM_F_REQUEST          0x01    /* It is request message.       */
+#define NLM_F_MULTI            0x02    /* Multipart message, terminated by NLMSG_DONE */
+#define NLM_F_ACK              0x04    /* Reply with ack, with zero or error code */
+#define NLM_F_ECHO             0x08    /* Echo this request            */
+#define NLM_F_DUMP_INTR                0x10    /* Dump was inconsistent due to sequence change */
+#define NLM_F_DUMP_FILTERED    0x20    /* Dump was filtered as requested */
+
+/* Modifiers to GET request */
+#define NLM_F_ROOT     0x100   /* specify tree root    */
+#define NLM_F_MATCH    0x200   /* return all matching  */
+#define NLM_F_ATOMIC   0x400   /* atomic GET           */
+#define NLM_F_DUMP     (NLM_F_ROOT|NLM_F_MATCH)
+
+/* Modifiers to NEW request */
+#define NLM_F_REPLACE  0x100   /* Override existing            */
+#define NLM_F_EXCL     0x200   /* Do not touch, if it exists   */
+#define NLM_F_CREATE   0x400   /* Create, if it does not exist */
+#define NLM_F_APPEND   0x800   /* Add to end of list           */
+
+/* Modifiers to DELETE request */
+#define NLM_F_NONREC   0x100   /* Do not delete recursively    */
+
+/* Flags for ACK message */
+#define NLM_F_CAPPED   0x100   /* request was capped */
+#define NLM_F_ACK_TLVS 0x200   /* extended ACK TVLs were included */
+
+/*
+   4.4BSD ADD          NLM_F_CREATE|NLM_F_EXCL
+   4.4BSD CHANGE       NLM_F_REPLACE
+
+   True CHANGE         NLM_F_CREATE|NLM_F_REPLACE
+   Append              NLM_F_CREATE
+   Check               NLM_F_EXCL
+ */
+
+#define NLMSG_ALIGNTO  4U
+#define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) )
+#define NLMSG_HDRLEN    ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
+#define NLMSG_LENGTH(len) ((len) + NLMSG_HDRLEN)
+#define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len))
+#define NLMSG_DATA(nlh)  ((void*)(((char*)nlh) + NLMSG_LENGTH(0)))
+#define NLMSG_NEXT(nlh,len)     ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
+                                 (struct nlmsghdr*)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)))
+#define NLMSG_OK(nlh,len) ((len) >= (int)sizeof(struct nlmsghdr) && \
+                          (nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \
+                          (nlh)->nlmsg_len <= (len))
+#define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len)))
+
+#define NLMSG_NOOP             0x1     /* Nothing.             */
+#define NLMSG_ERROR            0x2     /* Error                */
+#define NLMSG_DONE             0x3     /* End of a dump        */
+#define NLMSG_OVERRUN          0x4     /* Data lost            */
+
+#define NLMSG_MIN_TYPE         0x10    /* < 0x10: reserved control messages */
+
+struct nlmsgerr {
+       int             error;
+       struct nlmsghdr msg;
+       /*
+        * followed by the message contents unless NETLINK_CAP_ACK was set
+        * or the ACK indicates success (error == 0)
+        * message length is aligned with NLMSG_ALIGN()
+        */
+       /*
+        * followed by TLVs defined in enum nlmsgerr_attrs
+        * if NETLINK_EXT_ACK was set
+        */
+};
+
+/**
+ * enum nlmsgerr_attrs - nlmsgerr attributes
+ * @NLMSGERR_ATTR_UNUSED: unused
+ * @NLMSGERR_ATTR_MSG: error message string (string)
+ * @NLMSGERR_ATTR_OFFS: offset of the invalid attribute in the original
+ *      message, counting from the beginning of the header (u32)
+ * @NLMSGERR_ATTR_COOKIE: arbitrary subsystem specific cookie to
+ *     be used - in the success case - to identify a created
+ *     object or operation or similar (binary)
+ * @__NLMSGERR_ATTR_MAX: number of attributes
+ * @NLMSGERR_ATTR_MAX: highest attribute number
+ */
+enum nlmsgerr_attrs {
+       NLMSGERR_ATTR_UNUSED,
+       NLMSGERR_ATTR_MSG,
+       NLMSGERR_ATTR_OFFS,
+       NLMSGERR_ATTR_COOKIE,
+
+       __NLMSGERR_ATTR_MAX,
+       NLMSGERR_ATTR_MAX = __NLMSGERR_ATTR_MAX - 1
+};
+
+#define NETLINK_ADD_MEMBERSHIP         1
+#define NETLINK_DROP_MEMBERSHIP                2
+#define NETLINK_PKTINFO                        3
+#define NETLINK_BROADCAST_ERROR                4
+#define NETLINK_NO_ENOBUFS             5
+#define NETLINK_RX_RING                        6
+#define NETLINK_TX_RING                        7
+#define NETLINK_LISTEN_ALL_NSID                8
+#define NETLINK_LIST_MEMBERSHIPS       9
+#define NETLINK_CAP_ACK                        10
+#define NETLINK_EXT_ACK                        11
+
+struct nl_pktinfo {
+       __u32   group;
+};
+
+struct nl_mmap_req {
+       unsigned int    nm_block_size;
+       unsigned int    nm_block_nr;
+       unsigned int    nm_frame_size;
+       unsigned int    nm_frame_nr;
+};
+
+struct nl_mmap_hdr {
+       unsigned int    nm_status;
+       unsigned int    nm_len;
+       __u32           nm_group;
+       /* credentials */
+       __u32           nm_pid;
+       __u32           nm_uid;
+       __u32           nm_gid;
+};
+
+enum nl_mmap_status {
+       NL_MMAP_STATUS_UNUSED,
+       NL_MMAP_STATUS_RESERVED,
+       NL_MMAP_STATUS_VALID,
+       NL_MMAP_STATUS_COPY,
+       NL_MMAP_STATUS_SKIP,
+};
+
+#define NL_MMAP_MSG_ALIGNMENT          NLMSG_ALIGNTO
+#define NL_MMAP_MSG_ALIGN(sz)          __ALIGN_KERNEL(sz, NL_MMAP_MSG_ALIGNMENT)
+#define NL_MMAP_HDRLEN                 NL_MMAP_MSG_ALIGN(sizeof(struct nl_mmap_hdr))
+
+#define NET_MAJOR 36           /* Major 36 is reserved for networking                                          */
+
+enum {
+       NETLINK_UNCONNECTED = 0,
+       NETLINK_CONNECTED,
+};
+
+/*
+ *  <------- NLA_HDRLEN ------> <-- NLA_ALIGN(payload)-->
+ * +---------------------+- - -+- - - - - - - - - -+- - -+
+ * |        Header       | Pad |     Payload       | Pad |
+ * |   (struct nlattr)   | ing |                   | ing |
+ * +---------------------+- - -+- - - - - - - - - -+- - -+
+ *  <-------------- nlattr->nla_len -------------->
+ */
+
+struct nlattr {
+       __u16           nla_len;
+       __u16           nla_type;
+};
+
+/*
+ * nla_type (16 bits)
+ * +---+---+-------------------------------+
+ * | N | O | Attribute Type                |
+ * +---+---+-------------------------------+
+ * N := Carries nested attributes
+ * O := Payload stored in network byte order
+ *
+ * Note: The N and O flag are mutually exclusive.
+ */
+#define NLA_F_NESTED           (1 << 15)
+#define NLA_F_NET_BYTEORDER    (1 << 14)
+#define NLA_TYPE_MASK          ~(NLA_F_NESTED | NLA_F_NET_BYTEORDER)
+
+#define NLA_ALIGNTO            4
+#define NLA_ALIGN(len)         (((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1))
+#define NLA_HDRLEN             ((int) NLA_ALIGN(sizeof(struct nlattr)))
+
+/* Generic 32 bitflags attribute content sent to the kernel.
+ *
+ * The value is a bitmap that defines the values being set
+ * The selector is a bitmask that defines which value is legit
+ *
+ * Examples:
+ *  value = 0x0, and selector = 0x1
+ *  implies we are selecting bit 1 and we want to set its value to 0.
+ *
+ *  value = 0x2, and selector = 0x2
+ *  implies we are selecting bit 2 and we want to set its value to 1.
+ *
+ */
+struct nla_bitfield32 {
+       __u32 value;
+       __u32 selector;
+};
+
+#endif /* __LINUX_NETLINK_H */
index db5ed06c61e85880c8a6010c6513aeb5e326cc94..731785d4b4dd61ffdfe802197d8abf8601e5f69e 100644 (file)
@@ -4,6 +4,7 @@ noinst_HEADERS += \
        include/linux/lwtunnel.h \
        include/linux/mpls_iptunnel.h \
        include/linux/neighbour.h \
+       include/linux/netlink.h \
        include/linux/rtnetlink.h \
        include/linux/socket.h \
        include/linux/net_namespace.h \
index 81495d0a797e86c4fba6afe08456f86b02dc67eb..4b3d78421e8cf3a451b6c22feef551d3bd274376 100644 (file)
@@ -288,7 +288,6 @@ void isis_adj_state_change(struct isis_adjacency *adj,
                if (del)
                        isis_delete_adj(adj);
 
-               adj = NULL;
        } else if (circuit->circ_type == CIRCUIT_T_P2P) {
                del = false;
                for (level = IS_LEVEL_1; level <= IS_LEVEL_2; level++) {
@@ -326,8 +325,6 @@ void isis_adj_state_change(struct isis_adjacency *adj,
 
                if (del)
                        isis_delete_adj(adj);
-
-               adj = NULL;
        }
 
        return;
index 6f4d72cb1fe067ce84bc0fa323bd1c9f56948fb7..f8df33d3ee99df7f2afa07d7f21cd7380cc8021c 100644 (file)
@@ -357,14 +357,14 @@ void isis_circuit_del_addr(struct isis_circuit *circuit,
                        for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_link, node,
                                                  ip6)) {
                                prefix2str((struct prefix *)ip6, (char *)buf,
-                                          BUFSIZ);
+                                          sizeof(buf));
                                zlog_warn("  %s", buf);
                        }
                        zlog_warn(" -----");
                        for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, node,
                                                  ip6)) {
                                prefix2str((struct prefix *)ip6, (char *)buf,
-                                          BUFSIZ);
+                                          sizeof(buf));
                                zlog_warn("  %s", buf);
                        }
                        zlog_warn("End of addresses");
index 95fa38223e41c7f56665bfcc269292b59208ea87..c8ef829064b54bfa268ee21a284f49a8fec8f5c2 100644 (file)
@@ -55,9 +55,6 @@
 #include "isisd/isis_mt.h"
 #include "isisd/isis_tlvs.h"
 
-/* staticly assigned vars for printing purposes */
-char lsp_bits_string[200]; /* FIXME: enough ? */
-
 static int lsp_l1_refresh(struct thread *thread);
 static int lsp_l2_refresh(struct thread *thread);
 static int lsp_l1_refresh_pseudo(struct thread *thread);
@@ -608,13 +605,16 @@ static void lspid_print(uint8_t *lsp_id, uint8_t *trg, char dynhost, char frag)
 }
 
 /* Convert the lsp attribute bits to attribute string */
-static const char *lsp_bits2string(uint8_t lsp_bits)
+static const char *lsp_bits2string(uint8_t lsp_bits, char *buf, size_t buf_size)
 {
-       char *pos = lsp_bits_string;
+       char *pos = buf;
 
        if (!lsp_bits)
                return " none";
 
+       if (buf_size < 2 * 3)
+               return " error";
+
        /* we only focus on the default metric */
        pos += sprintf(pos, "%d/",
                       ISIS_MASK_LSP_ATT_DEFAULT_BIT(lsp_bits) ? 1 : 0);
@@ -622,11 +622,9 @@ static const char *lsp_bits2string(uint8_t lsp_bits)
        pos += sprintf(pos, "%d/",
                       ISIS_MASK_LSP_PARTITION_BIT(lsp_bits) ? 1 : 0);
 
-       pos += sprintf(pos, "%d", ISIS_MASK_LSP_OL_BIT(lsp_bits) ? 1 : 0);
-
-       *(pos) = '\0';
+       sprintf(pos, "%d", ISIS_MASK_LSP_OL_BIT(lsp_bits) ? 1 : 0);
 
-       return lsp_bits_string;
+       return buf;
 }
 
 /* this function prints the lsp on show isis database */
@@ -634,6 +632,7 @@ void lsp_print(struct isis_lsp *lsp, struct vty *vty, char dynhost)
 {
        uint8_t LSPid[255];
        char age_out[8];
+       char b[200];
 
        lspid_print(lsp->hdr.lsp_id, LSPid, dynhost, 1);
        vty_out(vty, "%-21s%c  ", LSPid, lsp->own_lsp ? '*' : ' ');
@@ -646,7 +645,7 @@ void lsp_print(struct isis_lsp *lsp, struct vty *vty, char dynhost)
                vty_out(vty, "%7s   ", age_out);
        } else
                vty_out(vty, " %5" PRIu16 "    ", lsp->hdr.rem_lifetime);
-       vty_out(vty, "%s\n", lsp_bits2string(lsp->hdr.lsp_bits));
+       vty_out(vty, "%s\n", lsp_bits2string(lsp->hdr.lsp_bits, b, sizeof(b)));
 }
 
 void lsp_print_detail(struct isis_lsp *lsp, struct vty *vty, char dynhost)
@@ -1053,6 +1052,7 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
                                        uint8_t subtlv_len;
 
                                        if (IS_MPLS_TE(isisMplsTE)
+                                           && circuit->interface != NULL
                                            && HAS_LINK_PARAMS(
                                                       circuit->interface))
                                                /* Update Local and Remote IP
index 6e56870ebd8c432b1236f86f85bd222445a70e01..fd82b85f51e71e0d844b6d794029870a37b7a10e 100644 (file)
@@ -309,9 +309,9 @@ int isis_recv_pdu_p2p(struct isis_circuit *circuit, uint8_t *ssnpa)
        addr_len = sizeof(s_addr);
 
        /* we can read directly to the stream */
-       stream_recvfrom(circuit->rcv_stream, circuit->fd,
-                       circuit->interface->mtu, 0, (struct sockaddr *)&s_addr,
-                       (socklen_t *)&addr_len);
+       (void)stream_recvfrom(
+               circuit->rcv_stream, circuit->fd, circuit->interface->mtu, 0,
+               (struct sockaddr *)&s_addr, (socklen_t *)&addr_len);
 
        if (s_addr.sll_pkttype == PACKET_OUTGOING) {
                /*  Read the packet into discard buff */
index a55a0e1902168b6b934acb6e58f20f6d53be01a8..556f2890cfbc22caee61a27ed0783f72bb3e799c 100644 (file)
@@ -77,14 +77,13 @@ enum vertextype {
 /*
  * Triple <N, d(N), {Adj(N)}>
  */
+union isis_N {
+       uint8_t id[ISIS_SYS_ID_LEN + 1];
+       struct prefix prefix;
+};
 struct isis_vertex {
        enum vertextype type;
-
-       union {
-               uint8_t id[ISIS_SYS_ID_LEN + 1];
-               struct prefix prefix;
-       } N;
-
+       union isis_N N;
        uint32_t d_N;     /* d(N) Distance from this IS      */
        uint16_t depth; /* The depth in the imaginary tree */
        struct list *Adj_N;    /* {Adj(N)} next hop or neighbor list */
@@ -407,28 +406,28 @@ static const char *vid2string(struct isis_vertex *vertex, char *buff, int size)
        return "UNKNOWN";
 }
 
-static void isis_vertex_id_init(struct isis_vertex *vertex, void *id,
+static void isis_vertex_id_init(struct isis_vertex *vertex, union isis_N *n,
                                enum vertextype vtype)
 {
        vertex->type = vtype;
 
        if (VTYPE_IS(vtype) || VTYPE_ES(vtype)) {
-               memcpy(vertex->N.id, (uint8_t *)id, ISIS_SYS_ID_LEN + 1);
+               memcpy(vertex->N.id, n->id, ISIS_SYS_ID_LEN + 1);
        } else if (VTYPE_IP(vtype)) {
-               memcpy(&vertex->N.prefix, (struct prefix *)id,
-                      sizeof(struct prefix));
+               memcpy(&vertex->N.prefix, &n->prefix, sizeof(struct prefix));
        } else {
                zlog_err("WTF!");
        }
 }
 
-static struct isis_vertex *isis_vertex_new(void *id, enum vertextype vtype)
+static struct isis_vertex *isis_vertex_new(union isis_N *n,
+                                          enum vertextype vtype)
 {
        struct isis_vertex *vertex;
 
        vertex = XCALLOC(MTYPE_ISIS_VERTEX, sizeof(struct isis_vertex));
 
-       isis_vertex_id_init(vertex, id, vtype);
+       isis_vertex_id_init(vertex, n, vtype);
 
        vertex->Adj_N = list_new();
        vertex->parents = list_new();
@@ -598,17 +597,17 @@ static struct isis_vertex *isis_spf_add_root(struct isis_spftree *spftree,
 #ifdef EXTREME_DEBUG
        char buff[PREFIX2STR_BUFFER];
 #endif /* EXTREME_DEBUG */
-       uint8_t id[ISIS_SYS_ID_LEN + 1];
+       union isis_N n;
 
-       memcpy(id, sysid, ISIS_SYS_ID_LEN);
-       LSP_PSEUDO_ID(id) = 0;
+       memcpy(n.id, sysid, ISIS_SYS_ID_LEN);
+       LSP_PSEUDO_ID(n.id) = 0;
 
        lsp = isis_root_system_lsp(spftree->area, spftree->level, sysid);
        if (lsp == NULL)
                zlog_warn("ISIS-Spf: could not find own l%d LSP!",
                          spftree->level);
 
-       vertex = isis_vertex_new(id,
+       vertex = isis_vertex_new(&n,
                                 spftree->area->oldmetric
                                         ? VTYPE_NONPSEUDO_IS
                                         : VTYPE_NONPSEUDO_TE_IS);
@@ -625,11 +624,12 @@ static struct isis_vertex *isis_spf_add_root(struct isis_spftree *spftree,
 }
 
 static struct isis_vertex *isis_find_vertex(struct isis_vertex_queue *queue,
-                                           void *id, enum vertextype vtype)
+                                           union isis_N *n,
+                                           enum vertextype vtype)
 {
        struct isis_vertex querier;
 
-       isis_vertex_id_init(&querier, id, vtype);
+       isis_vertex_id_init(&querier, n, vtype);
        return hash_lookup(queue->hash, &querier);
 }
 
@@ -1212,7 +1212,7 @@ static void add_to_paths(struct isis_spftree *spftree,
 {
        char buff[PREFIX2STR_BUFFER];
 
-       if (isis_find_vertex(&spftree->paths, vertex->N.id, vertex->type))
+       if (isis_find_vertex(&spftree->paths, &vertex->N, vertex->type))
                return;
        isis_vertex_queue_append(&spftree->paths, vertex);
 
@@ -1473,8 +1473,9 @@ static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue,
                vty_out(vty, "%-20s %-12s %-6u ",
                        vid2string(vertex, buff, sizeof(buff)),
                        vtype2string(vertex->type), vertex->d_N);
-               for (unsigned int i = 0; i < MAX(listcount(vertex->Adj_N),
-                                                listcount(vertex->parents));
+               for (unsigned int i = 0;
+                    i < MAX(vertex->Adj_N ? listcount(vertex->Adj_N) : 0,
+                            vertex->parents ? listcount(vertex->parents) : 0);
                     i++) {
                        if (anode) {
                                adj = listgetdata(anode);
index 6834f52a82a63c2bbab54ac4b332a753e6451c8c..8e53df3b61fe5dfb8c46e172772f9110a45c3af7 100644 (file)
@@ -884,7 +884,7 @@ static uint8_t print_subtlv_use_bw(struct sbuf *buf, int indent,
 static uint8_t print_unknown_tlv(struct sbuf *buf, int indent,
                                 struct subtlv_header *tlvh)
 {
-       int i, rtn = 1;
+       int i, rtn;
        uint8_t *v = (uint8_t *)tlvh;
 
        if (tlvh->length != 0) {
index 6f04d72082bc589c3a2afe7bd0eaf4c0735d016e..cecaa0693dba709ee8212a699230edc0ffdbbf1c 100644 (file)
@@ -1373,7 +1373,7 @@ static int show_isis_database(struct vty *vty, const char *argv, int ui_level)
        struct isis_area *area;
        struct isis_lsp *lsp;
        struct isis_dynhn *dynhn;
-       const char *pos = argv;
+       const char *pos;
        uint8_t lspid[ISIS_SYS_ID_LEN + 2];
        char sysid[255];
        uint8_t number[3];
index 39e20ef7c84d467d2b2081af8823653be3a0df29..ec70ef510adecd14d82c2cc76ed3f3f462aefe1e 100644 (file)
@@ -41,6 +41,9 @@ int
 ldp_vty_debug(struct vty *vty, const char *negate, const char *type_str,
     const char *dir_str, const char *all)
 {
+       if (type_str == NULL)
+               return (CMD_WARNING_CONFIG_FAILED);
+
        if (strcmp(type_str, "discovery") == 0) {
                if (dir_str == NULL)
                        return (CMD_WARNING_CONFIG_FAILED);
index 382b00688440d854285b66b10e0bd75479f5b87a..4ef57f574a75c21b90f09202653a543041926703 100644 (file)
@@ -89,6 +89,9 @@ struct cmd_node ldp_pseudowire_node =
 int
 ldp_get_address(const char *str, int *af, union ldpd_addr *addr)
 {
+       if (!str || !af || !addr)
+               return (-1);
+
        memset(addr, 0, sizeof(*addr));
 
        if (inet_pton(AF_INET, str, &addr->v4) == 1) {
@@ -428,6 +431,9 @@ ldp_vty_address_family(struct vty *vty, const char *negate, const char *af_str)
        struct ldpd_af_conf     *af_conf;
        int                      af;
 
+       if (af_str == NULL)
+               return (CMD_WARNING_CONFIG_FAILED);
+
        if (strcmp(af_str, "ipv4") == 0) {
                af = AF_INET;
                af_conf = &vty_conf->ipv4;
@@ -709,6 +715,11 @@ ldp_vty_interface(struct vty *vty, const char *negate, const char *ifname)
        struct iface            *iface;
        struct iface_af         *ia;
 
+       if (ifname == NULL) {
+               vty_out (vty, "%% Missing IF name\n");
+               return (CMD_WARNING_CONFIG_FAILED);
+       }
+
        af = ldp_vty_get_af(vty);
        iface = if_lookup_name(vty_conf, ifname);
 
@@ -776,8 +787,9 @@ ldp_vty_trans_addr(struct vty *vty, const char *negate, const char *addr_str)
        if (negate)
                memset(&af_conf->trans_addr, 0, sizeof(af_conf->trans_addr));
        else {
-               if (inet_pton(af, addr_str, &af_conf->trans_addr) != 1 ||
-                   bad_addr(af, &af_conf->trans_addr)) {
+               if (addr_str == NULL
+                   || inet_pton(af, addr_str, &af_conf->trans_addr) != 1
+                   || bad_addr(af, &af_conf->trans_addr)) {
                        vty_out (vty, "%% Malformed address\n");
                        return (CMD_SUCCESS);
                }
@@ -797,7 +809,7 @@ ldp_vty_neighbor_targeted(struct vty *vty, const char *negate, const char *addr_
 
        af = ldp_vty_get_af(vty);
 
-       if (inet_pton(af, addr_str, &addr) != 1 ||
+       if (addr_str == NULL || inet_pton(af, addr_str, &addr) != 1 ||
            bad_addr(af, &addr)) {
                vty_out (vty, "%% Malformed address\n");
                return (CMD_WARNING_CONFIG_FAILED);
@@ -1018,6 +1030,11 @@ ldp_vty_neighbor_password(struct vty *vty, const char *negate, struct in_addr ls
        size_t                   password_len;
        struct nbr_params       *nbrp;
 
+       if (password_str == NULL) {
+               vty_out (vty, "%% Missing password\n");
+               return (CMD_WARNING_CONFIG_FAILED);
+       }
+
        if (bad_addr_v4(lsr_id)) {
                vty_out (vty, "%% Malformed address\n");
                return (CMD_WARNING_CONFIG_FAILED);
@@ -1113,6 +1130,11 @@ ldp_vty_l2vpn(struct vty *vty, const char *negate, const char *name_str)
        struct l2vpn_if         *lif;
        struct l2vpn_pw         *pw;
 
+       if (name_str == NULL) {
+               vty_out (vty, "%% Missing name\n");
+               return (CMD_WARNING_CONFIG_FAILED);
+       }
+
        l2vpn = l2vpn_find(vty_conf, name_str);
 
        if (negate) {
@@ -1158,8 +1180,13 @@ ldp_vty_l2vpn_bridge(struct vty *vty, const char *negate, const char *ifname)
 
        if (negate)
                memset(l2vpn->br_ifname, 0, sizeof(l2vpn->br_ifname));
-       else
+       else {
+               if (ifname == NULL) {
+                       vty_out (vty, "%% Missing IF name\n");
+                       return (CMD_WARNING_CONFIG_FAILED);
+               }
                strlcpy(l2vpn->br_ifname, ifname, sizeof(l2vpn->br_ifname));
+       }
 
        ldp_config_apply(vty, vty_conf);
 
@@ -1187,6 +1214,11 @@ ldp_vty_l2vpn_pwtype(struct vty *vty, const char *negate, const char *type_str)
        VTY_DECLVAR_CONTEXT(l2vpn, l2vpn);
        int                      pw_type;
 
+       if (type_str == NULL) {
+               vty_out (vty, "%% Missing type\n");
+               return (CMD_WARNING_CONFIG_FAILED);
+       }
+
        if (strcmp(type_str, "ethernet") == 0)
                pw_type = PW_TYPE_ETHERNET;
        else
@@ -1208,6 +1240,11 @@ ldp_vty_l2vpn_interface(struct vty *vty, const char *negate, const char *ifname)
        VTY_DECLVAR_CONTEXT(l2vpn, l2vpn);
        struct l2vpn_if         *lif;
 
+       if (ifname == NULL) {
+               vty_out (vty, "%% Missing IF name\n");
+               return (CMD_WARNING_CONFIG_FAILED);
+       }
+
        lif = l2vpn_if_find(l2vpn, ifname);
 
        if (negate) {
@@ -1246,6 +1283,11 @@ ldp_vty_l2vpn_pseudowire(struct vty *vty, const char *negate, const char *ifname
        VTY_DECLVAR_CONTEXT(l2vpn, l2vpn);
        struct l2vpn_pw         *pw;
 
+       if (ifname == NULL) {
+               vty_out (vty, "%% Missing IF name\n");
+               return (CMD_WARNING_CONFIG_FAILED);
+       }
+
        pw = l2vpn_pw_find(l2vpn, ifname);
 
        if (negate) {
@@ -1294,6 +1336,10 @@ ldp_vty_l2vpn_pw_cword(struct vty *vty, const char *negate, const char *preferen
        if (negate)
                pw->flags |= F_PW_CWORD_CONF;
        else {
+               if (!preference_str) {
+                       vty_out (vty, "%% Missing preference\n");
+                       return (CMD_WARNING_CONFIG_FAILED);
+               }
                if (preference_str[0] == 'e')
                        pw->flags &= ~F_PW_CWORD_CONF;
                else
index 255febeb60344b676093a3eb6ad561e665940456..b51ff82cea5a9b035fa182dddcc4b64009d44ad0 100644 (file)
@@ -187,6 +187,22 @@ FRR_DAEMON_INFO(ldpd, LDP,
        .privs = &ldpd_privs,
 )
 
+static int ldp_config_fork_apply(struct thread *t)
+{
+       /*
+        * So the frr_config_fork() function schedules
+        * the read of the vty config( if there is a
+        * non-integrated config ) to be after the
+        * end of startup and we are starting the
+        * main process loop.  We need to schedule
+        * the application of this if necessary
+        * after the read in of the config.
+        */
+       ldp_config_apply(NULL, vty_conf);
+
+       return 0;
+}
+
 int
 main(int argc, char *argv[])
 {
@@ -195,6 +211,7 @@ main(int argc, char *argv[])
        int                      pipe_parent2ldpe[2], pipe_parent2ldpe_sync[2];
        int                      pipe_parent2lde[2], pipe_parent2lde_sync[2];
        char                    *ctl_sock_name;
+       struct thread           *thread = NULL;
 
        ldpd_process = PROC_MAIN;
        log_procname = log_procnames[ldpd_process];
@@ -331,7 +348,7 @@ main(int argc, char *argv[])
        frr_config_fork();
 
        /* apply configuration */
-       ldp_config_apply(NULL, vty_conf);
+       thread_add_event(master, ldp_config_fork_apply, NULL, 0, &thread);
 
        /* setup pipes to children */
        if ((iev_ldpe = calloc(1, sizeof(struct imsgev))) == NULL ||
@@ -406,16 +423,32 @@ ldpd_shutdown(void)
        free(vty_conf);
 
        log_debug("waiting for children to terminate");
-       do {
+
+       while (true) {
+               /* Wait for child process. */
                pid = wait(&status);
                if (pid == -1) {
-                       if (errno != EINTR && errno != ECHILD)
-                               fatal("wait");
-               } else if (WIFSIGNALED(status))
+                       /* We got interrupted, try again. */
+                       if (errno == EINTR)
+                               continue;
+                       /* No more processes were found. */
+                       if (errno != ECHILD)
+                               break;
+
+                       /* Unhandled errno condition. */
+                       fatal("wait");
+                       /* UNREACHABLE */
+               }
+
+               /* We found something, lets announce it. */
+               if (WIFSIGNALED(status))
                        log_warnx("%s terminated; signal %d",
-                           (pid == lde_pid) ? "label decision engine" :
-                           "ldp engine", WTERMSIG(status));
-       } while (pid != -1 || (pid == -1 && errno == EINTR));
+                                 (pid == lde_pid ? "label decision engine"
+                                                 : "ldp engine"),
+                                 WTERMSIG(status));
+
+               /* Repeat until there are no more child processes. */
+       }
 
        free(iev_ldpe);
        free(iev_lde);
index 4a4b258b91b1c416399838d9c6bcf7732c1cb683..b0f9c5eb14f8abadd7dcbf8129f6647610ff061d 100644 (file)
@@ -144,7 +144,7 @@ disc_recv_packet(struct thread *thread)
 
        /* reschedule read */
        *threadp = NULL;
-       thread_add_read(master, disc_recv_packet, threadp, fd, &*threadp);
+       thread_add_read(master, disc_recv_packet, threadp, fd, threadp);
 
        /* setup buffer */
        memset(&m, 0, sizeof(m));
index bcec6c2ccab3113a76183729b2047e642445686e..44dcc02eb8645b765a5ee04ccd5a363b8aa45bd7 100644 (file)
 #define pychar wchar_t
 static wchar_t *wconv(const char *s)
 {
-       size_t outlen = mbstowcs(NULL, s, 0);
+       size_t outlen = s ? mbstowcs(NULL, s, 0) : 0;
        wchar_t *out = malloc((outlen + 1) * sizeof(wchar_t));
-       mbstowcs(out, s, outlen + 1);
+
+       if (outlen > 0)
+               mbstowcs(out, s, outlen);
        out[outlen] = 0;
        return out;
 }
index a8e61c6bb4f1a8784ea2a441be104b1760c6deb9..0bf856f2484b4ac07d74466629e11f6f92982723 100644 (file)
@@ -261,8 +261,11 @@ void print_version(const char *progname)
 
 char *argv_concat(struct cmd_token **argv, int argc, int shift)
 {
-       int cnt = argc - shift;
-       const char *argstr[cnt];
+       int cnt = MAX(argc - shift, 0);
+       const char *argstr[cnt + 1];
+
+       if (!cnt)
+               return NULL;
 
        for (int i = 0; i < cnt; i++)
                argstr[i] = argv[i + shift]->arg;
@@ -515,13 +518,6 @@ static int config_write_host(struct vty *vty)
                                        host.enable);
                }
 
-               if (zlog_default->default_lvl != LOG_DEBUG) {
-                       vty_out(vty,
-                               "! N.B. The 'log trap' command is deprecated.\n");
-                       vty_out(vty, "log trap %s\n",
-                               zlog_priority[zlog_default->default_lvl]);
-               }
-
                if (host.logfile
                    && (zlog_default->maxlvl[ZLOG_DEST_FILE]
                        != ZLOG_DISABLED)) {
@@ -2429,7 +2425,8 @@ static int set_log_file(struct vty *vty, const char *fname, int loglevel)
                XFREE(MTYPE_TMP, p);
 
        if (!ret) {
-               vty_out(vty, "can't open logfile %s\n", fname);
+               if (vty)
+                       vty_out(vty, "can't open logfile %s\n", fname);
                return CMD_WARNING_CONFIG_FAILED;
        }
 
@@ -2445,6 +2442,39 @@ static int set_log_file(struct vty *vty, const char *fname, int loglevel)
        return CMD_SUCCESS;
 }
 
+void command_setup_early_logging(const char *dest, const char *level)
+{
+       char *token;
+
+       if (level) {
+               int nlevel = level_match(level);
+
+               if (nlevel != ZLOG_DISABLED)
+                       zlog_default->default_lvl = nlevel;
+       }
+
+       if (!dest)
+               return;
+
+       if (strcmp(dest, "stdout") == 0) {
+               zlog_set_level(ZLOG_DEST_STDOUT, zlog_default->default_lvl);
+               return;
+       }
+
+       if (strcmp(dest, "syslog") == 0) {
+               zlog_set_level(ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
+               return;
+       }
+
+       token = strstr(dest, ":");
+       if (token == NULL)
+               return;
+
+       token++;
+
+       set_log_file(NULL, token, zlog_default->default_lvl);
+}
+
 DEFUN (config_log_file,
        config_log_file_cmd,
        "log file FILENAME [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
@@ -2552,36 +2582,6 @@ DEFUN (no_config_log_facility,
        return CMD_SUCCESS;
 }
 
-DEFUN_DEPRECATED(
-       config_log_trap, config_log_trap_cmd,
-       "log trap <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>",
-       "Logging control\n"
-       "(Deprecated) Set logging level and default for all destinations\n" LOG_LEVEL_DESC)
-{
-       int new_level;
-       int i;
-
-       if ((new_level = level_match(argv[2]->arg)) == ZLOG_DISABLED)
-               return CMD_ERR_NO_MATCH;
-
-       zlog_default->default_lvl = new_level;
-       for (i = 0; i < ZLOG_NUM_DESTS; i++)
-               if (zlog_default->maxlvl[i] != ZLOG_DISABLED)
-                       zlog_default->maxlvl[i] = new_level;
-       return CMD_SUCCESS;
-}
-
-DEFUN_DEPRECATED(
-       no_config_log_trap, no_config_log_trap_cmd,
-       "no log trap [emergencies|alerts|critical|errors|warnings|notifications|informational|debugging]",
-       NO_STR
-       "Logging control\n"
-       "Permit all logging information\n" LOG_LEVEL_DESC)
-{
-       zlog_default->default_lvl = LOG_DEBUG;
-       return CMD_SUCCESS;
-}
-
 DEFUN (config_log_record_priority,
        config_log_record_priority_cmd,
        "log record-priority",
@@ -2871,8 +2871,6 @@ void cmd_init(int terminal)
                install_element(CONFIG_NODE, &no_config_log_syslog_cmd);
                install_element(CONFIG_NODE, &config_log_facility_cmd);
                install_element(CONFIG_NODE, &no_config_log_facility_cmd);
-               install_element(CONFIG_NODE, &config_log_trap_cmd);
-               install_element(CONFIG_NODE, &no_config_log_trap_cmd);
                install_element(CONFIG_NODE, &config_log_record_priority_cmd);
                install_element(CONFIG_NODE,
                                &no_config_log_record_priority_cmd);
index 9bf482f41b6054c902adce326dd8839140a374fe..2d333b098a0c39d8f74edb7a221f3a6c3f4adae6 100644 (file)
@@ -240,9 +240,6 @@ struct cmd_node {
 #define DEFUN_HIDDEN(funcname, cmdname, cmdstr, helpstr)                       \
        DEFUN_ATTR(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN)
 
-#define DEFUN_DEPRECATED(funcname, cmdname, cmdstr, helpstr)                   \
-       DEFUN_ATTR(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_DEPRECATED)
-
 /* DEFUN_NOSH for commands that vtysh should ignore */
 #define DEFUN_NOSH(funcname, cmdname, cmdstr, helpstr)                         \
        DEFUN(funcname, cmdname, cmdstr, helpstr)
@@ -479,4 +476,5 @@ extern void
 cmd_variable_handler_register(const struct cmd_variable_handler *cvh);
 extern char *cmd_variable_comp2str(vector comps, unsigned short cols);
 
+extern void command_setup_early_logging(const char *dest, const char *level);
 #endif /* _ZEBRA_COMMAND_H */
index 99ec03e0c2486d3e4a3f9c1aa03b6a35f7bcbd06..c165305d78315a7c9e4f440f574e825af7a0ad1d 100644 (file)
@@ -608,11 +608,14 @@ static struct cmd_token *disambiguate_tokens(struct cmd_token *first,
 static struct list *disambiguate(struct list *first, struct list *second,
                                 vector vline, unsigned int n)
 {
+       assert(first != NULL);
+       assert(second != NULL);
        // doesn't make sense for these to be inequal length
        assert(first->count == second->count);
        assert(first->count == vector_active(vline) - n + 1);
 
-       struct listnode *fnode = listhead(first), *snode = listhead(second);
+       struct listnode *fnode = listhead_unchecked(first),
+                       *snode = listhead_unchecked(second);
        struct cmd_token *ftok = listgetdata(fnode), *stok = listgetdata(snode),
                         *best = NULL;
 
index e6a5eae2e2bba4306026e6de5c9f33643cb57943..ce84783aa6f7570da98027cabbc489a8cf1cd4b6 100644 (file)
--- a/lib/csv.c
+++ b/lib/csv.c
@@ -663,8 +663,8 @@ int main()
 
        log_verbose("Mem: %d\n", get_memory_usage(getpid()));
        csv_init(&csv, buf, 256);
-       sprintf(hdr1, "%4u", 0);
-       sprintf(hdr2, "%4u", 1);
+       sprintf(hdr1, "%4d", 0);
+       sprintf(hdr2, "%4d", 1);
        log_verbose("(%zu/%zu/%d/%d)\n", strlen(hdr1), strlen(hdr2), atoi(hdr1),
                    atoi(hdr2));
        rec = csv_encode(&csv, 2, hdr1, hdr2);
@@ -676,8 +676,8 @@ int main()
        }
        csv_encode(&csv, 2, "pdfadfadfadsadsaddfdfdsfdsd", "35444554545454545");
        log_verbose("%s\n", buf);
-       sprintf(hdr1, "%4u", csv.csv_len);
-       sprintf(hdr2, "%4u", 1);
+       sprintf(hdr1, "%4d", csv.csv_len);
+       sprintf(hdr2, "%4d", 1);
        log_verbose("(%zu/%zu/%d/%d)\n", strlen(hdr1), strlen(hdr2), atoi(hdr1),
                    atoi(hdr2));
        rec = csv_encode_record(&csv, rec, 2, hdr1, hdr2);
index 36a89168c28fc9ec8bba552dce8e2bdb96b3f0d5..00681b9db86167b85d17cd843f75c03812a48fbc 100644 (file)
@@ -269,7 +269,6 @@ static int fpt_halt(struct frr_pthread *fpt, void **res)
 {
        thread_add_event(fpt->master, &fpt_finish, fpt, 0, NULL);
        pthread_join(fpt->thread, res);
-       fpt = NULL;
 
        return 0;
 }
index 8f190a3a09c713c42ea5bbd135520962d3962b40..3153e697faaa03f4ca29af82baf6726211ae75ae 100644 (file)
@@ -174,9 +174,10 @@ int funcname_frrzmq_thread_add_read(struct thread_master *master,
                cb = *cbp;
        else {
                cb = XCALLOC(MTYPE_ZEROMQ_CB, sizeof(struct frrzmq_cb));
-               cb->write.cancelled = 1;
                if (!cb)
                        return -1;
+
+               cb->write.cancelled = 1;
                *cbp = cb;
        }
 
@@ -282,9 +283,10 @@ int funcname_frrzmq_thread_add_write(struct thread_master *master,
                cb = *cbp;
        else {
                cb = XCALLOC(MTYPE_ZEROMQ_CB, sizeof(struct frrzmq_cb));
-               cb->read.cancelled = 1;
                if (!cb)
                        return -1;
+
+               cb->read.cancelled = 1;
                *cbp = cb;
        }
 
index d003590ba6d2b0937bf000bf53da618059d43226..715e67b868c24bbe9adeb945f6aec9986850d3bb 100644 (file)
@@ -78,6 +78,9 @@ char *frrstr_join(const char **parts, int argc, const char *join)
        size_t len = 0;
        size_t joinlen = join ? strlen(join) : 0;
 
+       if (!argc)
+               return NULL;
+
        for (i = 0; i < argc; i++)
                len += strlen(parts[i]);
        len += argc * joinlen + 1;
@@ -158,3 +161,11 @@ bool begins_with(const char *str, const char *prefix)
 
        return strncmp(str, prefix, lenprefix) == 0;
 }
+
+int all_digit(const char *str)
+{
+       for (; *str != '\0'; str++)
+               if (!isdigit((int)*str))
+                       return 0;
+       return 1;
+}
index 24547711221618a7c981ab9876ba99a3540183ee..891a3f337ca98da88542c7392dfd2218dc3d0fab 100644 (file)
@@ -97,4 +97,15 @@ void frrstr_strvec_free(vector v);
  */
 bool begins_with(const char *str, const char *prefix);
 
+/*
+ * Check the string only contains digit characters.
+ *
+ * str
+ *    string to check for digits
+ *
+ * Returns:
+ *    1 str only contains digit characters, 0 otherwise
+ */
+int all_digit(const char *str);
+
 #endif /* _FRRSTR_H_ */
index ee5401b2367a4816111439863c3b67f1d8df51d7..37f6cdcc8f86a4c3d65e405131942fa2d1fe1367 100644 (file)
@@ -241,15 +241,21 @@ void hash_iterate(struct hash *hash, void (*func)(struct hash_backet *, void *),
        unsigned int i;
        struct hash_backet *hb;
        struct hash_backet *hbnext;
+       uint32_t count = 0;
 
-       for (i = 0; i < hash->size; i++)
+       for (i = 0; i < hash->size; i++) {
                for (hb = hash->index[i]; hb; hb = hbnext) {
                        /* get pointer to next hash backet here, in case (*func)
                         * decides to delete hb by calling hash_release
                         */
                        hbnext = hb->next;
                        (*func)(hb, arg);
+                       count++;
+
                }
+               if (count == hash->count)
+                       return;
+       }
 }
 
 void hash_walk(struct hash *hash, int (*func)(struct hash_backet *, void *),
@@ -259,6 +265,7 @@ void hash_walk(struct hash *hash, int (*func)(struct hash_backet *, void *),
        struct hash_backet *hb;
        struct hash_backet *hbnext;
        int ret = HASHWALK_CONTINUE;
+       uint32_t count = 0;
 
        for (i = 0; i < hash->size; i++) {
                for (hb = hash->index[i]; hb; hb = hbnext) {
@@ -269,7 +276,10 @@ void hash_walk(struct hash *hash, int (*func)(struct hash_backet *, void *),
                        ret = (*func)(hb, arg);
                        if (ret == HASHWALK_ABORT)
                                return;
+                       count++;
                }
+               if (count == hash->count)
+                       return;
        }
 }
 
index 6419f805abb57c6ed2f568d4ccf05e1dfe29cff1..54241407205d203f0ae3964e784afbf27bc03e7d 100644 (file)
@@ -77,7 +77,7 @@ ssize_t imsg_read(struct imsgbuf *ibuf)
                char buf[CMSG_SPACE(sizeof(int) * 1)];
        } cmsgbuf;
        struct iovec iov;
-       ssize_t n = -1;
+       ssize_t n;
        int fd;
        struct imsg_fd *ifd;
 
@@ -110,7 +110,8 @@ again:
                return (-1);
        }
 
-       if ((n = recvmsg(ibuf->fd, &msg, 0)) == -1) {
+       n = recvmsg(ibuf->fd, &msg, 0);
+       if (n == -1) {
                if (errno == EINTR)
                        goto again;
                goto fail;
index 88203fbeb6bb57e424d5a1a2a5bfbd7db0d78fd2..9ea5e985cd424ab631362335ef33cdb7da5715c6 100644 (file)
@@ -78,6 +78,8 @@ static void opt_extend(const struct optspec *os)
 
 #define OPTION_VTYSOCK   1000
 #define OPTION_MODULEDIR 1002
+#define OPTION_LOG       1003
+#define OPTION_LOGLEVEL  1004
 
 static const struct option lo_always[] = {
        {"help", no_argument, NULL, 'h'},
@@ -86,6 +88,8 @@ static const struct option lo_always[] = {
        {"module", no_argument, NULL, 'M'},
        {"vty_socket", required_argument, NULL, OPTION_VTYSOCK},
        {"moduledir", required_argument, NULL, OPTION_MODULEDIR},
+       {"log", required_argument, NULL, OPTION_LOG},
+       {"log-level", required_argument, NULL, OPTION_LOGLEVEL},
        {NULL}};
 static const struct optspec os_always = {
        "hvdM:",
@@ -94,7 +98,9 @@ static const struct optspec os_always = {
        "  -d, --daemon       Runs in daemon mode\n"
        "  -M, --module       Load specified module\n"
        "      --vty_socket   Override vty socket path\n"
-       "      --moduledir    Override modules directory\n",
+       "      --moduledir    Override modules directory\n"
+       "      --log          Set Logging to stdout, syslog, or file:<name>\n"
+       "      --log-level    Set Logging Level to use, debug, info, warn, etc\n",
        lo_always};
 
 
@@ -444,6 +450,12 @@ static int frr_opt(int opt)
                        return 1;
                di->privs->group = optarg;
                break;
+       case OPTION_LOG:
+               di->early_logging = optarg;
+               break;
+       case OPTION_LOGLEVEL:
+               di->early_loglevel = optarg;
+               break;
        default:
                return 1;
        }
@@ -543,9 +555,8 @@ struct thread_master *frr_init(void)
 
        openzlog(di->progname, di->logname, di->instance,
                 LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON);
-#if defined(HAVE_CUMULUS)
-       zlog_set_level(ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
-#endif
+
+       command_setup_early_logging(di->early_logging, di->early_loglevel);
 
        if (!frr_zclient_addr(&zclient_addr, &zclient_addr_len,
                              frr_zclientpath)) {
@@ -721,15 +732,37 @@ static void frr_daemonize(void)
        frr_daemon_wait(fds[0]);
 }
 
+/*
+ * Why is this a thread?
+ *
+ * The read in of config for integrated config happens *after*
+ * thread execution starts( because it is passed in via a vtysh -b -n )
+ * While if you are not using integrated config we want the ability
+ * to read the config in after thread execution starts, so that
+ * we can match this behavior.
+ */
+static int frr_config_read_in(struct thread *t)
+{
+       if (!vty_read_config(di->config_file, config_default) &&
+           di->backup_config_file) {
+               zlog_info("Attempting to read backup config file: %s specified",
+                         di->backup_config_file);
+               vty_read_config(di->backup_config_file, config_default);
+       }
+       return 0;
+}
+
 void frr_config_fork(void)
 {
        hook_call(frr_late_init, master);
 
-       vty_read_config(di->config_file, config_default);
-
        /* Don't start execution if we are in dry-run mode */
-       if (di->dryrun)
+       if (di->dryrun) {
+               frr_config_read_in(NULL);
                exit(0);
+       }
+
+       thread_add_event(master, frr_config_read_in, NULL, 0, &di->read_in);
 
        if (di->daemon_mode || di->terminal)
                frr_daemonize();
@@ -813,7 +846,9 @@ static int frr_daemon_ctl(struct thread *t)
        switch (buf[0]) {
        case 'S': /* SIGTSTP */
                vty_stdio_suspend();
-               send(daemon_ctl_sock, "s", 1, 0);
+               if (send(daemon_ctl_sock, "s", 1, 0) < 0)
+                       zlog_err("%s send(\"s\") error (SIGTSTP propagation)",
+                                (di && di->name ? di->name : ""));
                break;
        case 'R': /* SIGTCNT [implicit] */
                vty_stdio_resume();
index 7ffa780bfb9a75d8d6316a0b73d564d9399650d4..d2552799069ce9233d048c7f2a46f8383e9d3f64 100644 (file)
@@ -50,11 +50,16 @@ struct frr_daemon_info {
        bool dryrun;
        bool daemon_mode;
        bool terminal;
+
+       struct thread *read_in;
        const char *config_file;
+       const char *backup_config_file;
        const char *pid_file;
        const char *vty_path;
        const char *module_path;
        const char *pathspace;
+       const char *early_logging;
+       const char *early_loglevel;
 
        const char *proghelp;
        void (*printhelp)(FILE *target);
index 2cfa3e748208158968754fa14ca314593b97d867..86649dd4952ec12dbdfec6c5272df9f8ce06ea8a 100644 (file)
@@ -186,26 +186,10 @@ void listnode_move_to_tail(struct list *l, struct listnode *n)
 
 void listnode_delete(struct list *list, void *val)
 {
-       struct listnode *node;
+       struct listnode *node = listnode_lookup(list, val);
 
-       assert(list);
-       for (node = list->head; node; node = node->next) {
-               if (node->data == val) {
-                       if (node->prev)
-                               node->prev->next = node->next;
-                       else
-                               list->head = node->next;
-
-                       if (node->next)
-                               node->next->prev = node->prev;
-                       else
-                               list->tail = node->prev;
-
-                       list->count--;
-                       listnode_free(node);
-                       return;
-               }
-       }
+       if (node)
+               list_delete_node(list, node);
 }
 
 void *listnode_head(struct list *list)
index 39e70293d24bafd974afaf87f5221bef01c3861a..1e2631ea46157157d05f406adb052cbcb9524637 100644 (file)
@@ -52,7 +52,9 @@ struct list {
 };
 
 #define listnextnode(X) ((X) ? ((X)->next) : NULL)
+#define listnextnode_unchecked(X) ((X)->next)
 #define listhead(X) ((X) ? ((X)->head) : NULL)
+#define listhead_unchecked(X) ((X)->head)
 #define listtail(X) ((X) ? ((X)->tail) : NULL)
 #define listcount(X) ((X)->count)
 #define list_isempty(X) ((X)->head == NULL && (X)->tail == NULL)
index 401cfb08133dcfa2c9be994b5533fd7580f940dc..90997348cf3ab3bdf129abe9541fc6cb27a2882c 100644 (file)
--- a/lib/pbr.h
+++ b/lib/pbr.h
 #ifndef _PBR_H
 #define _PBR_H
 
+#include <zebra.h>
+#include "stream.h"
+#include "prefix.h"
+
+#define PBR_STR "Policy Based Routing\n"
+
 /*
  * A PBR filter
  *
@@ -83,6 +89,35 @@ struct pbr_rule {
        uint32_t ifindex;
 };
 
+/* TCP flags value shared
+ * those are values of byte 13 of TCP header
+ * as mentioned in rfc793
+ */
+#define TCP_HEADER_FIN (0x01)
+#define TCP_HEADER_SYN (0x02)
+#define TCP_HEADER_RST (0x04)
+#define TCP_HEADER_PSH (0x08)
+#define TCP_HEADER_ACK (0x10)
+#define TCP_HEADER_URG (0x20)
+#define TCP_HEADER_ALL_FLAGS (TCP_HEADER_FIN | TCP_HEADER_SYN \
+                             | TCP_HEADER_RST | TCP_HEADER_PSH \
+                             | TCP_HEADER_ACK | TCP_HEADER_URG)
+
+/* Pbr IPTable defines
+ * those are common flags shared between BGP and Zebra
+ */
+#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)
+#define MATCH_DSCP_SET                 (1 << 6)
+#define MATCH_DSCP_INVERSE_SET         (1 << 7)
+#define MATCH_PKT_LEN_INVERSE_SET      (1 << 8)
+#define MATCH_FRAGMENT_INVERSE_SET     (1 << 9)
+#define MATCH_ICMP_SET                 (1 << 10)
+
 extern int zapi_pbr_rule_encode(uint8_t cmd, struct stream *s,
                                struct pbr_rule *zrule);
 
index 5ed1589f456630b3b325a007fab9097a9a0f0556..056b737f540ce8895dc037082362652a81d4a8df 100644 (file)
@@ -850,6 +850,11 @@ static int vty_prefix_list_install(struct vty *vty, afi_t afi, const char *name,
        int lenum = 0;
        int genum = 0;
 
+       if (name == NULL || prefix == NULL || typestr == NULL) {
+               vty_out(vty, "%% Missing prefix or type\n");
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
        /* Sequential number. */
        if (seq)
                seqnum = (int64_t)atol(seq);
index ed0774e77495b03415aef24c2f5d524d3e0fe1dd..751f20cb83ebfa89e9da2d13d8f2d73ebf98bb84 100644 (file)
@@ -1197,6 +1197,9 @@ int str2prefix(const char *str, struct prefix *p)
 {
        int ret;
 
+       if (!str || !p)
+               return 0;
+
        /* First we try to convert string to struct prefix_ipv4. */
        ret = str2prefix_ipv4(str, (struct prefix_ipv4 *)p);
        if (ret)
@@ -1370,17 +1373,6 @@ void prefix_free(struct prefix *p)
        XFREE(MTYPE_PREFIX, p);
 }
 
-/* Utility function.  Check the string only contains digit
- * character.
- * FIXME str.[c|h] would be better place for this function. */
-int all_digit(const char *str)
-{
-       for (; *str != '\0'; str++)
-               if (!isdigit((int)*str))
-                       return 0;
-       return 1;
-}
-
 /* Utility function to convert ipv4 prefixes to Classful prefixes */
 void apply_classful_mask_ipv4(struct prefix_ipv4 *p)
 {
index f5dbb22f79282c51d00ee42f80e7a1eba5d3696b..4247569137dd4a4b5a3e3e917e9e6c0190d670ad 100644 (file)
@@ -458,7 +458,6 @@ static inline int ipv6_martian(struct in6_addr *addr)
        return 0;
 }
 
-extern int all_digit(const char *);
 extern int macstr2prefix_evpn(const char *str, struct prefix_evpn *p);
 
 /* NOTE: This routine expects the address argument in network byte order. */
index cfe7d6d6f81bdf802191e2559f1438ab7c985e98..7c99742d3407bf3454b30ac2c50436b226a8d79f 100644 (file)
@@ -824,6 +824,19 @@ void zprivs_init(struct zebra_privs_t *zprivs)
 
 #ifdef HAVE_CAPABILITIES
        zprivs_caps_init(zprivs);
+
+       /*
+        * If we have initialized the system with no requested
+        * capabilities, change will not have been set
+        * to anything by zprivs_caps_init, As such
+        * we should make sure that when we attempt
+        * to raize privileges that we actually have
+        * a do nothing function to call instead of a
+        * crash :).
+        */
+       if (!zprivs->change)
+               zprivs->change = zprivs_change_null;
+
 #else  /* !HAVE_CAPABILITIES */
        /* we dont have caps. we'll need to maintain rid and saved uid
         * and change euid back to saved uid (who we presume has all neccessary
index fea5a8cc4015ba6ac858dc1f8a91891b67bcd5e4..69fd61e2a06998ea914551f4b02b3aeb71e43c24 100644 (file)
@@ -60,10 +60,10 @@ static csv_record_t *_ptm_lib_encode_header(csv_t *csv, csv_record_t *rec,
        char client_buf[32];
        csv_record_t *rec1;
 
-       sprintf(msglen_buf, "%4u", msglen);
-       sprintf(vers_buf, "%4u", version);
-       sprintf(type_buf, "%4u", type);
-       sprintf(cmdid_buf, "%4u", cmd_id);
+       sprintf(msglen_buf, "%4d", msglen);
+       sprintf(vers_buf, "%4d", version);
+       sprintf(type_buf, "%4d", type);
+       sprintf(cmdid_buf, "%4d", cmd_id);
        snprintf(client_buf, 17, "%16.16s", client_name);
        if (rec) {
                rec1 = csv_encode_record(csv, rec, 5, msglen_buf, vers_buf,
index 892b19dac50134d28d7e3230126e52d345e63fb1..056c7934540d744d50e17fbada8c88338780f56c 100644 (file)
@@ -751,7 +751,7 @@ struct route_map *route_map_lookup_by_name(const char *name)
        return map;
 }
 
-int route_map_mark_updated(const char *name, int del_later)
+int route_map_mark_updated(const char *name)
 {
        struct route_map *map;
        int ret = -1;
@@ -781,7 +781,7 @@ int route_map_mark_updated(const char *name, int del_later)
        return (ret);
 }
 
-int route_map_clear_updated(struct route_map *map)
+static int route_map_clear_updated(struct route_map *map)
 {
        int ret = -1;
 
@@ -807,7 +807,7 @@ static struct route_map *route_map_get(const char *name)
        return map;
 }
 
-void route_map_walk_update_list(int (*route_map_update_fn)(char *name))
+void route_map_walk_update_list(void (*route_map_update_fn)(char *name))
 {
        struct route_map *node;
        struct route_map *nnode = NULL;
index 990c7fa72f43d28f50e7c7a8969432425141b047..0aeba7e1f66d4e5627c9b1bb2641f0e289af002e 100644 (file)
@@ -215,9 +215,8 @@ extern route_map_result_t route_map_apply(struct route_map *map,
 extern void route_map_add_hook(void (*func)(const char *));
 extern void route_map_delete_hook(void (*func)(const char *));
 extern void route_map_event_hook(void (*func)(route_map_event_t, const char *));
-extern int route_map_mark_updated(const char *name, int deleted);
-extern int route_map_clear_updated(struct route_map *rmap);
-extern void route_map_walk_update_list(int (*update_fn)(char *name));
+extern int route_map_mark_updated(const char *name);
+extern void route_map_walk_update_list(void (*update_fn)(char *name));
 extern void route_map_upd8_dependency(route_map_event_t type, const char *arg,
                                      const char *rmap_name);
 extern void route_map_notify_dependencies(const char *affected_name,
index 37c1e5283deac6ed38a7114ca94cbfa5e7cf3a7a..03a2be3e09fa39dc0ea6ac9405b679a64f422afc 100644 (file)
@@ -63,13 +63,12 @@ void sbuf_push(struct sbuf *buf, int indent, const char *format, ...)
        int written;
 
        if (!buf->fixed) {
-               char dummy;
                int written1, written2;
                size_t new_size;
 
-               written1 = snprintf(&dummy, 0, "%*s", indent, "");
+               written1 = indent;
                va_start(args, format);
-               written2 = vsnprintf(&dummy, 0, format, args);
+               written2 = vsnprintf(NULL, 0, format, args);
                va_end(args);
 
                new_size = buf->size;
index d299760fabe0ffafffb8e801d11d5b78975c8683..59eaa8037075a754073cd40433c26fa3e9830fc6 100644 (file)
@@ -119,8 +119,6 @@ int quagga_sigevent_process(void)
 int quagga_signal_timer(struct thread *t)
 {
        struct quagga_sigevent_master_t *sigm;
-       struct quagga_signal_t *sig;
-       int i;
 
        sigm = THREAD_ARG(t);
        sigm->t = NULL;
index 1d8d9990df5d812cd4a2014ac33991ae84280350..815be86c2e152eec3f943f4d87007ca25363e8a2 100644 (file)
@@ -457,8 +457,7 @@ int setsockopt_ifindex(int af, int sock, ifindex_t val)
  */
 static ifindex_t getsockopt_ipv4_ifindex(struct msghdr *msgh)
 {
-       /* XXX: initialize to zero?  (Always overwritten, so just cosmetic.) */
-       ifindex_t ifindex = -1;
+       ifindex_t ifindex;
 
 #if defined(IP_PKTINFO)
        /* Linux pktinfo based ifindex retrieval */
@@ -466,7 +465,11 @@ static ifindex_t getsockopt_ipv4_ifindex(struct msghdr *msgh)
 
        pktinfo = (struct in_pktinfo *)getsockopt_cmsg_data(msgh, IPPROTO_IP,
                                                            IP_PKTINFO);
-       /* XXX Can pktinfo be NULL?  Clean up post 0.98. */
+
+       /* getsockopt_ifindex() will forward this, being 0 "not found" */
+       if (pktinfo == NULL)
+               return 0;
+
        ifindex = pktinfo->ipi_ifindex;
 
 #elif defined(IP_RECVIF)
index 28a7f647cba7faf80c1fef56da5b8f42a8c3045c..44378b536303060f9aaf3999ddac6994c76e694b 100644 (file)
@@ -46,6 +46,9 @@ int str2sockunion(const char *str, union sockunion *su)
 {
        int ret;
 
+       if (str == NULL)
+               return -1;
+
        memset(su, 0, sizeof(union sockunion));
 
        ret = inet_pton(AF_INET, str, &su->sin.sin_addr);
index aba4c20166175e27049d126def18c4315e95e25e..a172eedc995256ee378e77fa23849259dbf4a53d 100644 (file)
@@ -1109,6 +1109,10 @@ struct stream_fifo *stream_fifo_new(void)
 /* Add new stream to fifo. */
 void stream_fifo_push(struct stream_fifo *fifo, struct stream *s)
 {
+#if defined DEV_BUILD
+       size_t max, curmax;
+#endif
+
        if (fifo->tail)
                fifo->tail->next = s;
        else
@@ -1116,8 +1120,15 @@ void stream_fifo_push(struct stream_fifo *fifo, struct stream *s)
 
        fifo->tail = s;
        fifo->tail->next = NULL;
-
+#if !defined DEV_BUILD
        atomic_fetch_add_explicit(&fifo->count, 1, memory_order_release);
+#else
+       max = atomic_fetch_add_explicit(&fifo->count, 1, memory_order_release);
+       curmax = atomic_load_explicit(&fifo->max_count, memory_order_relaxed);
+       if (max > curmax)
+               atomic_store_explicit(&fifo->max_count, max,
+                                     memory_order_relaxed);
+#endif
 }
 
 void stream_fifo_push_safe(struct stream_fifo *fifo, struct stream *s)
index e5d325e43ed4940dd65f421d6152e60d892a9d81..11af85c663d086438a270f4879742f2c547eaef3 100644 (file)
@@ -115,6 +115,9 @@ struct stream_fifo {
 
        /* number of streams in this fifo */
        _Atomic size_t count;
+#if defined DEV_BUILD
+       _Atomic size_t max_count;
+#endif
 
        struct stream *head;
        struct stream *tail;
index 9472fabe1d1573614899575458fef892c28559fb..9eaae59df8cbbdf6169f05e4ffb88d0e86675db7 100644 (file)
@@ -236,7 +236,7 @@ lib_grammar_sandbox_LDADD = \
        lib/libfrr.la
 
 lib_clippy_CPPFLAGS = $(AM_CPPFLAGS) -D_GNU_SOURCE -DBUILDING_CLIPPY @SAN_CLIPPY_FLAGS@
-lib_clippy_CFLAGS = $(PYTHON_CFLAGS) $(AM_CFLAGS) @SAN_CLIPPY_FLAGS@
+lib_clippy_CFLAGS = $(PYTHON_CFLAGS) @SAN_CLIPPY_FLAGS@
 lib_clippy_LDADD = $(PYTHON_LIBS)
 lib_clippy_SOURCES = \
        lib/clippy.c \
index 18e1c922804cf43faad3302a2860582835ab79e2..1c5e8387729774dc9bf355b47055c6a736e97383 100644 (file)
@@ -296,6 +296,47 @@ DEFUN (show_thread_cpu,
        return CMD_SUCCESS;
 }
 
+static void show_thread_poll_helper(struct vty *vty, struct thread_master *m)
+{
+       const char *name = m->name ? m->name : "main";
+       char underline[strlen(name) + 1];
+       uint32_t i;
+
+       memset(underline, '-', sizeof(underline));
+       underline[sizeof(underline) - 1] = '\0';
+
+       vty_out(vty, "\nShowing poll FD's for %s\n", name);
+       vty_out(vty, "----------------------%s\n", underline);
+       vty_out(vty, "Count: %u\n", (uint32_t)m->handler.pfdcount);
+       for (i = 0; i < m->handler.pfdcount; i++)
+               vty_out(vty, "\t%6d fd:%6d events:%2d revents:%2d\n", i,
+                       m->handler.pfds[i].fd,
+                       m->handler.pfds[i].events,
+                       m->handler.pfds[i].revents);
+}
+
+DEFUN (show_thread_poll,
+       show_thread_poll_cmd,
+       "show thread poll",
+       SHOW_STR
+       "Thread information\n"
+       "Show poll FD's and information\n")
+{
+       struct listnode *node;
+       struct thread_master *m;
+
+       pthread_mutex_lock(&masters_mtx);
+       {
+               for (ALL_LIST_ELEMENTS_RO(masters, node, m)) {
+                       show_thread_poll_helper(vty, m);
+               }
+       }
+       pthread_mutex_unlock(&masters_mtx);
+
+       return CMD_SUCCESS;
+}
+
+
 DEFUN (clear_thread_cpu,
        clear_thread_cpu_cmd,
        "clear thread cpu [FILTER]",
@@ -325,6 +366,7 @@ DEFUN (clear_thread_cpu,
 void thread_cmd_init(void)
 {
        install_element(VIEW_NODE, &show_thread_cpu_cmd);
+       install_element(VIEW_NODE, &show_thread_poll_cmd);
        install_element(ENABLE_NODE, &clear_thread_cpu_cmd);
 }
 /* CLI end ------------------------------------------------------------------ */
index 280b2ace51a64bd64c5df459b5291854bc2ab554..e9d1f2e323747eaf7879af78fb34b1e22513352e 100644 (file)
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -2462,12 +2462,13 @@ static FILE *vty_use_backup_config(const char *fullpath)
 }
 
 /* Read up configuration file from file_name. */
-void vty_read_config(const char *config_file, char *config_default_dir)
+bool vty_read_config(const char *config_file, char *config_default_dir)
 {
        char cwd[MAXPATHLEN];
        FILE *confp = NULL;
        const char *fullpath;
        char *tmp = NULL;
+       bool read_success = false;
 
        /* If -f flag specified. */
        if (config_file != NULL) {
@@ -2525,8 +2526,10 @@ void vty_read_config(const char *config_file, char *config_default_dir)
 
                if (strstr(config_default_dir, "vtysh") == NULL) {
                        ret = stat(integrate_default, &conf_stat);
-                       if (ret >= 0)
+                       if (ret >= 0) {
+                               read_success = true;
                                goto tmp_free_and_out;
+                       }
                }
 #endif /* VTYSH */
                confp = fopen(config_default_dir, "r");
@@ -2550,6 +2553,7 @@ void vty_read_config(const char *config_file, char *config_default_dir)
        }
 
        vty_read_file(confp);
+       read_success = true;
 
        fclose(confp);
 
@@ -2558,6 +2562,8 @@ void vty_read_config(const char *config_file, char *config_default_dir)
 tmp_free_and_out:
        if (tmp)
                XFREE(MTYPE_TMP, tmp);
+
+       return read_success;
 }
 
 /* Small utility function which output log to the VTY. */
index d14ddf5908d69dbe4a7825ba061dd764288bff79..b55abf22043f4956617b05ce4aab9084e3807b47 100644 (file)
--- a/lib/vty.h
+++ b/lib/vty.h
@@ -242,7 +242,7 @@ extern void vty_frame(struct vty *, const char *, ...) PRINTF_ATTRIBUTE(2, 3);
 extern void vty_endframe(struct vty *, const char *);
 bool vty_set_include(struct vty *vty, const char *regexp);
 
-extern void vty_read_config(const char *, char *);
+extern bool vty_read_config(const char *, char *);
 extern void vty_time_print(struct vty *, int);
 extern void vty_serv_sock(const char *, unsigned short, const char *);
 extern void vty_close(struct vty *);
index 255e247221d84954a700ca25d11c40b85884cd46..98428eaab237685d5e6872e801705ef9123a308b 100644 (file)
@@ -486,6 +486,7 @@ typedef enum {
 #define SET_FLAG(V,F)        (V) |= (F)
 #define UNSET_FLAG(V,F)      (V) &= ~(F)
 #define RESET_FLAG(V)        (V) = 0
+#define COND_FLAG(V, F, C)   ((C) ? (SET_FLAG(V, F)) : (UNSET_FLAG(V, F)))
 
 /* Atomic flag manipulation macros. */
 #define CHECK_FLAG_ATOMIC(PV, F)                                               \
index 6349224adcb241448ed38f5e427c7e94921e6242..415e7523de047b67ddf3c65d94f9a6e5f3512b26 100644 (file)
@@ -164,7 +164,7 @@ static void ares_address_cb(void *arg, int status, int timeouts,
                return;
        }
 
-       for (i = 0; he->h_addr_list[i] != NULL && i < ZEBRA_NUM_OF(addr); i++) {
+       for (i = 0; i < ZEBRA_NUM_OF(addr) && he->h_addr_list[i] != NULL; i++) {
                memset(&addr[i], 0, sizeof(addr[i]));
                addr[i].sa.sa_family = he->h_addrtype;
                switch (he->h_addrtype) {
index e6111f9d7120e618f6a0c3471e8694bb2c482374..3bb0d8308ecbb94c1574eadbf57e7ca486985883 100644 (file)
@@ -287,6 +287,7 @@ static void vici_recv_sa(struct vici_conn *vici, struct zbuf *msg, int event)
        char buf[32];
        struct handle_sa_ctx ctx = {
                .event = event,
+               .msgctx.nsections = 0
        };
 
        vici_parse_message(vici, msg, parse_sa_message, &ctx.msgctx);
index b3aa3b21d2b5221e1d3eb76cf9395cd6764b1a23..7bccc78e00882fe4f93daea760c176f2e4eaeaa6 100644 (file)
@@ -161,9 +161,10 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route,
            && route->type != OSPF6_DEST_TYPE_RANGE
            && ((route->type != OSPF6_DEST_TYPE_ROUTER)
                || !CHECK_FLAG(route->path.router_bits, OSPF6_ROUTER_BIT_E))) {
-               if (is_debug)
-                       zlog_debug(
-                               "Route type is none of network, range nor ASBR, ignore");
+#if 0
+               zlog_debug(
+                       "Route type is none of network, range nor ASBR, ignore");
+#endif
                return 0;
        }
 
@@ -177,16 +178,17 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route,
 
        /* do not generate if the path's area is the same as target area */
        if (route->path.area_id == area->area_id) {
-               if (is_debug)
-                       zlog_debug("The route is in the area itself, ignore");
+#if 0
+               zlog_debug("The route is in the area itself, ignore");
+#endif
                return 0;
        }
 
        /* do not generate if the nexthops belongs to the target area */
        if (ospf6_abr_nexthops_belong_to_area(route, area)) {
-               if (is_debug)
-                       zlog_debug(
-                               "The route's nexthop is in the same area, ignore");
+#if 0
+               zlog_debug("The route's nexthop is in the same area, ignore");
+#endif
                return 0;
        }
 
@@ -641,6 +643,11 @@ void ospf6_abr_originate_summary(struct ospf6_route *route)
 
        if (route->type == OSPF6_DEST_TYPE_NETWORK) {
                oa = ospf6_area_lookup(route->path.area_id, ospf6);
+               if (!oa) {
+                       zlog_err("OSPFv6 area lookup failed");
+                       return;
+               }
+
                range = ospf6_route_lookup_bestmatch(&route->prefix,
                                                     oa->range_table);
                if (range) {
@@ -864,7 +871,8 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
                                lsa->header);
                prefix.family = AF_INET6;
                prefix.prefixlen = prefix_lsa->prefix.prefix_length;
-               ospf6_prefix_in6_addr(&prefix.u.prefix6, &prefix_lsa->prefix);
+               ospf6_prefix_in6_addr(&prefix.u.prefix6, prefix_lsa,
+                                     &prefix_lsa->prefix);
                if (is_debug)
                        prefix2str(&prefix, buf, sizeof(buf));
                table = oa->ospf6->route_table;
@@ -1284,7 +1292,7 @@ static char *ospf6_inter_area_prefix_lsa_get_prefix_str(struct ospf6_lsa *lsa,
                        (struct ospf6_inter_prefix_lsa *)OSPF6_LSA_HEADER_END(
                                lsa->header);
 
-               ospf6_prefix_in6_addr(&in6, &prefix_lsa->prefix);
+               ospf6_prefix_in6_addr(&in6, prefix_lsa, &prefix_lsa->prefix);
                if (buf) {
                        inet_ntop(AF_INET6, &in6, buf, buflen);
                        sprintf(&buf[strlen(buf)], "/%d",
index 7f575ee50638b8e5da6c56add7fa7f4cc802a34c..a7233965077b03b703500a94bd13ac59cc89b0e5 100644 (file)
@@ -497,7 +497,8 @@ void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa)
        route->type = OSPF6_DEST_TYPE_NETWORK;
        route->prefix.family = AF_INET6;
        route->prefix.prefixlen = external->prefix.prefix_length;
-       ospf6_prefix_in6_addr(&route->prefix.u.prefix6, &external->prefix);
+       ospf6_prefix_in6_addr(&route->prefix.u.prefix6, external,
+                             &external->prefix);
 
        route->path.area_id = asbr_entry->path.area_id;
        route->path.origin.type = lsa->header->type;
@@ -576,7 +577,7 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa,
        route_to_del->type = OSPF6_DEST_TYPE_NETWORK;
        route_to_del->prefix.family = AF_INET6;
        route_to_del->prefix.prefixlen = external->prefix.prefix_length;
-       ospf6_prefix_in6_addr(&route_to_del->prefix.u.prefix6,
+       ospf6_prefix_in6_addr(&route_to_del->prefix.u.prefix6, external,
                              &external->prefix);
 
        route_to_del->path.origin.type = lsa->header->type;
@@ -603,7 +604,7 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa,
        memset(&prefix, 0, sizeof(struct prefix));
        prefix.family = AF_INET6;
        prefix.prefixlen = external->prefix.prefix_length;
-       ospf6_prefix_in6_addr(&prefix.u.prefix6, &external->prefix);
+       ospf6_prefix_in6_addr(&prefix.u.prefix6, external, &external->prefix);
 
        route = ospf6_route_lookup(&prefix, ospf6->route_table);
        if (route == NULL) {
@@ -1705,7 +1706,8 @@ static char *ospf6_as_external_lsa_get_prefix_str(struct ospf6_lsa *lsa,
                        lsa->header);
 
                if (pos == 0) {
-                       ospf6_prefix_in6_addr(&in6, &external->prefix);
+                       ospf6_prefix_in6_addr(&in6, external,
+                                             &external->prefix);
                        prefix_length = external->prefix.prefix_length;
                } else {
                        in6 = *((struct in6_addr
index 2059d8486829c099daf136c1b853df2d8e418fc0..ae26668c8ae8c199230459dd29818fcb20234726 100644 (file)
@@ -347,6 +347,7 @@ void ospf6_flood_interface(struct ospf6_neighbor *from, struct ospf6_lsa *lsa,
                                                        "Received is newer, remove requesting");
                                        if (req == on->last_ls_req) {
                                                ospf6_lsa_unlock(req);
+                                               req = NULL;
                                                on->last_ls_req = NULL;
                                        }
                                        if (req)
index d99541ebaddfa8c28ae9a1423546b551921d3430..0ce08a61e259b67e9fdde0fddfc6ea5dc6481299 100644 (file)
@@ -1323,6 +1323,8 @@ static void ospf6_intra_prefix_update_route_origin(struct ospf6_route *oa_route)
        g_route = ospf6_route_lookup(&oa_route->prefix,
                                     ospf6->route_table);
 
+       assert(g_route);
+
        for (ospf6_route_lock(g_route); g_route &&
             ospf6_route_is_prefix(&oa_route->prefix, g_route);
             g_route = nroute) {
@@ -1698,7 +1700,8 @@ void ospf6_intra_prefix_lsa_add(struct ospf6_lsa *lsa)
                memset(&route->prefix, 0, sizeof(struct prefix));
                route->prefix.family = AF_INET6;
                route->prefix.prefixlen = op->prefix_length;
-               ospf6_prefix_in6_addr(&route->prefix.u.prefix6, op);
+               ospf6_prefix_in6_addr(&route->prefix.u.prefix6,
+                                     intra_prefix_lsa, op);
 
                route->type = OSPF6_DEST_TYPE_NETWORK;
                route->path.origin.type = lsa->header->type;
@@ -1880,7 +1883,7 @@ void ospf6_intra_prefix_lsa_remove(struct ospf6_lsa *lsa)
                memset(&prefix, 0, sizeof(struct prefix));
                prefix.family = AF_INET6;
                prefix.prefixlen = op->prefix_length;
-               ospf6_prefix_in6_addr(&prefix.u.prefix6, op);
+               ospf6_prefix_in6_addr(&prefix.u.prefix6, intra_prefix_lsa, op);
 
                route = ospf6_route_lookup(&prefix, oa->route_table);
                if (route == NULL)
index 4b56a64b7f66803e9e788c3808316ccad5f356a2..864974c9a4c3d952723a1a9a6dede2e786c685ab 100644 (file)
 
 #include "ospf6_proto.h"
 
+void ospf6_prefix_in6_addr(struct in6_addr *in6, const void *prefix_buf,
+                          const struct ospf6_prefix *p)
+{
+       ptrdiff_t in6_off = (caddr_t)p->addr - (caddr_t)prefix_buf;
+
+       memset(in6, 0, sizeof(struct in6_addr));
+       memcpy(in6, (uint8_t *)prefix_buf + in6_off,
+              OSPF6_PREFIX_SPACE(p->prefix_length));
+}
+
 void ospf6_prefix_apply_mask(struct ospf6_prefix *op)
 {
        uint8_t *pnt, mask;
index ca2804c47624d52eeb7b0aa46ed1bc241f58fcb5..c9e7b549db8b4443cb99f86fb33c87b41ff11f44 100644 (file)
@@ -84,13 +84,8 @@ struct ospf6_prefix {
 #define OSPF6_PREFIX_NEXT(x)                                                   \
        ((struct ospf6_prefix *)((caddr_t)(x) + OSPF6_PREFIX_SIZE(x)))
 
-#define ospf6_prefix_in6_addr(in6, op)                                         \
-       do {                                                                   \
-               memset(in6, 0, sizeof(struct in6_addr));                       \
-               memcpy(in6, (caddr_t)(op) + sizeof(struct ospf6_prefix),       \
-                      OSPF6_PREFIX_SPACE((op)->prefix_length));               \
-       } while (0)
-
+extern void ospf6_prefix_in6_addr(struct in6_addr *in6, const void *prefix_buf,
+                                 const struct ospf6_prefix *p);
 extern void ospf6_prefix_apply_mask(struct ospf6_prefix *op);
 extern void ospf6_prefix_options_printbuf(uint8_t prefix_options, char *buf,
                                          int size);
index 28c3459825e0a5ce756d2af40c8ba4808a0742d2..5b6691e6bf1b4039f9724a2130d019d18a59cd68 100644 (file)
@@ -677,6 +677,10 @@ void ospf6_spf_schedule(struct ospf6 *ospf6, unsigned int reason)
 {
        unsigned long delay, elapsed, ht;
 
+       /* OSPF instance does not exist. */
+       if (ospf6 == NULL)
+               return;
+
        ospf6_set_spf_reason(ospf6, reason);
 
        if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF(TIME)) {
@@ -686,10 +690,6 @@ void ospf6_spf_schedule(struct ospf6 *ospf6, unsigned int reason)
                           rbuf);
        }
 
-       /* OSPF instance does not exist. */
-       if (ospf6 == NULL)
-               return;
-
        /* SPF calculation timer is already scheduled. */
        if (ospf6->t_spf_calc) {
                if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF(TIME))
index 8369dde82215ad67cbe64511a14f7cda623554c3..b1175a2f68cc3f7e080fff2048a7a3945b439c49 100644 (file)
@@ -510,17 +510,18 @@ struct msg *new_msg_originate_request(uint32_t seqnum, struct in_addr ifaddr,
        struct msg_originate_request *omsg;
        unsigned int omsglen;
        char buf[OSPF_API_MAX_MSG_SIZE];
+       size_t off_data = offsetof(struct msg_originate_request, data);
+       size_t data_maxs = sizeof(buf) - off_data;
+       struct lsa_header *omsg_data = (struct lsa_header *)&buf[off_data];
 
        omsg = (struct msg_originate_request *)buf;
        omsg->ifaddr = ifaddr;
        omsg->area_id = area_id;
 
        omsglen = ntohs(data->length);
-       if (omsglen
-           > sizeof(buf) - offsetof(struct msg_originate_request, data))
-               omsglen = sizeof(buf)
-                         - offsetof(struct msg_originate_request, data);
-       memcpy(&omsg->data, data, omsglen);
+       if (omsglen > data_maxs)
+               omsglen = data_maxs;
+       memcpy(omsg_data, data, omsglen);
        omsglen += sizeof(struct msg_originate_request)
                   - sizeof(struct lsa_header);
 
@@ -630,6 +631,9 @@ struct msg *new_msg_lsa_change_notify(uint8_t msgtype, uint32_t seqnum,
        uint8_t buf[OSPF_API_MAX_MSG_SIZE];
        struct msg_lsa_change_notify *nmsg;
        unsigned int len;
+       size_t off_data = offsetof(struct msg_lsa_change_notify, data);
+       size_t data_maxs = sizeof(buf) - off_data;
+       struct lsa_header *nmsg_data = (struct lsa_header *)&buf[off_data];
 
        assert(data);
 
@@ -640,10 +644,9 @@ struct msg *new_msg_lsa_change_notify(uint8_t msgtype, uint32_t seqnum,
        memset(&nmsg->pad, 0, sizeof(nmsg->pad));
 
        len = ntohs(data->length);
-       if (len > sizeof(buf) - offsetof(struct msg_lsa_change_notify, data))
-               len = sizeof(buf)
-                     - offsetof(struct msg_lsa_change_notify, data);
-       memcpy(&nmsg->data, data, len);
+       if (len > data_maxs)
+               len = data_maxs;
+       memcpy(nmsg_data, data, len);
        len += sizeof(struct msg_lsa_change_notify) - sizeof(struct lsa_header);
 
        return msg_new(msgtype, nmsg, seqnum, len);
index 37735e36119e3129cb091bc5d2d3f06b8312bb80..8f8900e147fee286bc442f9d970055d35674655a 100644 (file)
@@ -1741,6 +1741,8 @@ struct ospf_lsa *ospf_apiserver_lsa_refresher(struct ospf_lsa *lsa)
        struct ospf_lsa *new = NULL;
        struct ospf *ospf;
 
+       assert(lsa);
+
        ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
        assert(ospf);
 
@@ -1751,6 +1753,7 @@ struct ospf_lsa *ospf_apiserver_lsa_refresher(struct ospf_lsa *lsa)
                        dump_lsa_key(lsa));
                lsa->data->ls_age =
                        htons(OSPF_LSA_MAXAGE); /* Flush it anyway. */
+               goto out;
        }
 
        if (IS_LSA_MAXAGE(lsa)) {
index d42562486299fa4f336f28848bb48ba8e6eb43c0..c799a4b30f9840e4bbb65f6a4934075af9ce6ada 100644 (file)
@@ -582,7 +582,7 @@ static int ospf_ase_route_match_same(struct route_table *rt,
 
        /* Check each path. */
        for (n1 = listhead(or->paths), n2 = listhead(newor->paths); n1 && n2;
-            n1 = listnextnode(n1), n2 = listnextnode(n2)) {
+            n1 = listnextnode_unchecked(n1), n2 = listnextnode_unchecked(n2)) {
                op = listgetdata(n1);
                newop = listgetdata(n2);
 
index 08bedadf41bba43493c81947bb95890fc4f5e12a..d8742943c0043022494ac545da87104a1926715b 100644 (file)
@@ -146,8 +146,6 @@ void ospf_nbr_state_message(struct ospf_neighbor *nbr, char *buf, size_t size)
        else
                state = ISM_DROther;
 
-       memset(buf, 0, size);
-
        snprintf(buf, size, "%s/%s",
                 lookup_msg(ospf_nsm_state_msg, nbr->state, NULL),
                 lookup_msg(ospf_ism_state_msg, state, NULL));
@@ -201,17 +199,17 @@ const char *ospf_timeval_dump(struct timeval *t, char *buf, size_t size)
        }
 
        if (w > 99)
-               snprintf(buf, size, "%ldw%1ldd", w, d);
+               snprintf(buf, size, "%luw%1lud", w, d);
        else if (w)
-               snprintf(buf, size, "%ldw%1ldd%02ldh", w, d, h);
+               snprintf(buf, size, "%luw%1lud%02luh", w, d, h);
        else if (d)
-               snprintf(buf, size, "%1ldd%02ldh%02ldm", d, h, m);
+               snprintf(buf, size, "%1lud%02luh%02lum", d, h, m);
        else if (h)
-               snprintf(buf, size, "%ldh%02ldm%02lds", h, m, (long)t->tv_sec);
+               snprintf(buf, size, "%luh%02lum%02lds", h, m, (long)t->tv_sec);
        else if (m)
-               snprintf(buf, size, "%ldm%02lds", m, (long)t->tv_sec);
+               snprintf(buf, size, "%lum%02lds", m, (long)t->tv_sec);
        else if (ms)
-               snprintf(buf, size, "%ld.%03lds", (long)t->tv_sec, ms);
+               snprintf(buf, size, "%ld.%03lus", (long)t->tv_sec, ms);
        else
                snprintf(buf, size, "%ld usecs", (long)t->tv_usec);
 
@@ -254,8 +252,6 @@ static void ospf_packet_hello_dump(struct stream *s, uint16_t length)
 
 static char *ospf_dd_flags_dump(uint8_t flags, char *buf, size_t size)
 {
-       memset(buf, 0, size);
-
        snprintf(buf, size, "%s|%s|%s", (flags & OSPF_DD_FLAG_I) ? "I" : "-",
                 (flags & OSPF_DD_FLAG_M) ? "M" : "-",
                 (flags & OSPF_DD_FLAG_MS) ? "MS" : "-");
@@ -265,8 +261,6 @@ static char *ospf_dd_flags_dump(uint8_t flags, char *buf, size_t size)
 
 static char *ospf_router_lsa_flags_dump(uint8_t flags, char *buf, size_t size)
 {
-       memset(buf, 0, size);
-
        snprintf(buf, size, "%s|%s|%s",
                 (flags & ROUTER_LSA_VIRTUAL) ? "V" : "-",
                 (flags & ROUTER_LSA_EXTERNAL) ? "E" : "-",
@@ -1689,7 +1683,7 @@ static int config_write_debug(struct vty *vty)
                return CMD_SUCCESS;
 
        if (ospf->instance)
-               sprintf(str, " %d", ospf->instance);
+               sprintf(str, " %u", ospf->instance);
 
        /* debug ospf ism (status|events|timers). */
        if (IS_CONF_DEBUG_OSPF(ism, ISM) == OSPF_DEBUG_ISM)
index ea31d8c2ca2bbb8f50d6801d0a8750489a9b6c1b..23353b3c309f089a3e124ac5ff2ab2fb90bf364d 100644 (file)
@@ -857,7 +857,7 @@ struct ospf_interface *ospf_vl_new(struct ospf *ospf,
                        "ospf_vl_new(): creating pseudo zebra interface vrf id %u",
                        ospf->vrf_id);
 
-       snprintf(ifname, sizeof(ifname), "VLINK%d", vlink_count);
+       snprintf(ifname, sizeof(ifname), "VLINK%u", vlink_count);
        vi = if_create(ifname, ospf->vrf_id);
        /*
         * if_create sets ZEBRA_INTERFACE_LINKDETECTION
index 1f67c0d5ade8d114197e023ff83d43175f2ea5cf..486ef3335d473077284252b3a3ef75666723a5a7 100644 (file)
@@ -144,8 +144,6 @@ void ospf_packet_free(struct ospf_packet *op)
                stream_free(op->s);
 
        XFREE(MTYPE_OSPF_PACKET, op);
-
-       op = NULL;
 }
 
 struct ospf_fifo *ospf_fifo_new()
index 786b1990290cfef084e43112091a3dd07af81f0b..93267156f2f9381b53d4c823d9ed73ff9598ca95 100644 (file)
@@ -516,12 +516,13 @@ static void unset_sr_node_msd(void)
        TLV_LEN(OspfRI.sr_info.msd) = htons(0);
 }
 
-static void unset_param(struct tlv_header *tlv)
+static void unset_param(void *tlv_buffer)
 {
+       struct tlv_header *tlv = (struct tlv_header *)tlv_buffer;
 
        tlv->type = 0;
        /* Fill the Value to 0 */
-       memset(TLV_DATA(tlv), 0, TLV_BODY_SIZE(tlv));
+       memset(TLV_DATA(tlv_buffer), 0, TLV_BODY_SIZE(tlv));
        tlv->length = 0;
 
        return;
@@ -1571,7 +1572,7 @@ DEFUN (no_pce_address,
        "PCE address in IPv4 address format\n")
 {
 
-       unset_param(&OspfRI.pce_info.pce_address.header);
+       unset_param(&OspfRI.pce_info.pce_address);
 
        /* Refresh RI LSA if already engaged */
        if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED))
@@ -1621,7 +1622,7 @@ DEFUN (no_pce_path_scope,
        "32-bit Hexadecimal value\n")
 {
 
-       unset_param(&OspfRI.pce_info.pce_address.header);
+       unset_param(&OspfRI.pce_info.pce_address);
 
        /* Refresh RI LSA if already engaged */
        if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED))
@@ -1810,7 +1811,7 @@ DEFUN (no_pce_cap_flag,
        "Disable PCE capabilities\n")
 {
 
-       unset_param(&OspfRI.pce_info.pce_cap_flag.header);
+       unset_param(&OspfRI.pce_info.pce_cap_flag);
 
        /* Refresh RI LSA if already engaged */
        if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED))
index b964bbab74092763cab8639056c71eb04459f775..b36f2f4652069ee0f95d2775af6980a96856f5ea 100644 (file)
@@ -170,8 +170,8 @@ int ospf_route_match_same(struct route_table *rt, struct prefix_ipv4 *prefix,
                        /* Check each path. */
                        for (n1 = listhead(or->paths),
                            n2 = listhead(newor->paths);
-                            n1 && n2;
-                            n1 = listnextnode(n1), n2 = listnextnode(n2)) {
+                            n1 && n2; n1 = listnextnode_unchecked(n1),
+                           n2 = listnextnode_unchecked(n2)) {
                                op = listgetdata(n1);
                                newop = listgetdata(n2);
 
index ca711aa42f1b8c39e5bc2ec8228a425526a53919..f3271acfa2ae1d76eb91b091e7f2eb44f5815d29 100644 (file)
@@ -32,6 +32,7 @@
 #include "log.h"
 #include "plist.h"
 #include "vrf.h"
+#include "frrstr.h"
 
 #include "ospfd/ospfd.h"
 #include "ospfd/ospf_asbr.h"
index 6825be83ac89b007078e9ee369690c771f2d34ec..c90db031dcf2f2137687d2cf81da53bc8e122980 100644 (file)
@@ -1626,7 +1626,7 @@ static struct ospf_interface *ospfIfLookup(struct variable *v, oid *name,
                len = *length - v->namelen;
                if (len >= IN_ADDR_SIZE)
                        len = IN_ADDR_SIZE;
-               if (len <= 0)
+               if (len == 0)
                        ifaddr_next = 1;
 
                oid2in_addr(name + v->namelen, len, ifaddr);
@@ -1990,7 +1990,7 @@ ospfVirtIfLookup(struct variable *v, oid *name, size_t *length,
                first = 0;
 
                len = *length - v->namelen;
-               if (len <= 0)
+               if (len == 0)
                        first = 1;
                if (len > IN_ADDR_SIZE)
                        len = IN_ADDR_SIZE;
@@ -2176,7 +2176,7 @@ static struct ospf_neighbor *ospfNbrLookup(struct variable *v, oid *name,
                first = 0;
                len = *length - v->namelen;
 
-               if (len <= 0)
+               if (len == 0)
                        first = 1;
 
                if (len > IN_ADDR_SIZE)
index 2b1b328617e31e1c1ef034095b0da3eb5e68eae6..86125d0c769fcb11ea3e55da2295ddbc59999fc8 100644 (file)
@@ -2051,12 +2051,11 @@ static uint16_t ospf_mpls_te_show_link_subtlv(struct vty *vty,
                                              struct tlv_header *tlvh0,
                                              uint16_t subtotal, uint16_t total)
 {
-       struct tlv_header *tlvh, *next;
+       struct tlv_header *tlvh;
        uint16_t sum = subtotal;
 
        for (tlvh = tlvh0; sum < total;
-            tlvh = (next ? next : TLV_HDR_NEXT(tlvh))) {
-               next = NULL;
+            tlvh = TLV_HDR_NEXT(tlvh)) {
                switch (ntohs(tlvh->type)) {
                case TE_LINK_SUBTLV_LINK_TYPE:
                        sum += show_vty_link_subtlv_link_type(vty, tlvh);
index 31cffea7f2350be03bd6233a409073da3d3bb380..ddf9133ed96ff30ae1dc3c50e6af8990904a18e3 100644 (file)
@@ -2412,8 +2412,8 @@ DEFUN (ospf_neighbor_poll_interval,
        int idx_poll = 3;
        int idx_pri = 5;
        struct in_addr nbr_addr;
-       unsigned int priority = OSPF_NEIGHBOR_PRIORITY_DEFAULT;
-       unsigned int interval = OSPF_POLL_INTERVAL_DEFAULT;
+       unsigned int priority;
+       unsigned int interval;
 
        if (!inet_aton(argv[idx_ipv4]->arg, &nbr_addr)) {
                vty_out(vty, "Please specify Neighbor ID by A.B.C.D\n");
@@ -2422,8 +2422,8 @@ DEFUN (ospf_neighbor_poll_interval,
 
        interval = strtoul(argv[idx_poll]->arg, NULL, 10);
 
-       if (argc > 4)
-               priority = strtoul(argv[idx_pri]->arg, NULL, 10);
+       priority = argc > 4 ? strtoul(argv[idx_pri]->arg, NULL, 10)
+                           : OSPF_NEIGHBOR_PRIORITY_DEFAULT;
 
        ospf_nbr_nbma_set(ospf, nbr_addr);
        ospf_nbr_nbma_poll_interval_set(ospf, nbr_addr, interval);
@@ -8166,6 +8166,11 @@ DEFUN (ospf_redistribute_instance_source,
 
        source = proto_redistnum(AFI_IP, argv[idx_ospf_table]->text);
 
+       if (source < 0) {
+               vty_out(vty, "Unknown instance redistribution\n");
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
        instance = strtoul(argv[idx_number]->arg, NULL, 10);
 
        if ((source == ZEBRA_ROUTE_OSPF) && !ospf->instance) {
index 141ece9c7a74b228c6f075dff134d233d8943742..0a7776cced054c5dac2eb563530f0e3c80c46b7f 100644 (file)
@@ -670,6 +670,16 @@ int ospf_redistribute_set(struct ospf *ospf, int type, unsigned short instance,
        struct ospf_redist *red;
 
        red = ospf_redist_lookup(ospf, type, instance);
+
+       if (red == NULL) {
+               zlog_err(
+                        "Redistribute[%s][%d]: Lookup failed  Type[%d] , Metric[%d]",
+                        ospf_redist_string(type), instance,
+                        metric_type(ospf, type, instance),
+                        metric_value(ospf, type, instance));
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
        if (ospf_is_type_redistributed(ospf, type, instance)) {
                if (mtype != red->dmetric.type) {
                        red->dmetric.type = mtype;
index 4cf38439c658e6efdefdc2de52cdd74d26574db2..f315421843ee1e9df1fd9e0e4c9042de1eaf21b7 100644 (file)
@@ -243,13 +243,14 @@ static struct ospf *ospf_new(unsigned short instance, const char *name)
                        zlog_debug(
                                "%s: Create new ospf instance with vrf_name %s vrf_id %u",
                                __PRETTY_FUNCTION__, name, new->vrf_id);
-               if (vrf)
-                       ospf_vrf_link(new, vrf);
        } else {
                new->vrf_id = VRF_DEFAULT;
                vrf = vrf_lookup_by_id(VRF_DEFAULT);
-               ospf_vrf_link(new, vrf);
        }
+
+       if (vrf)
+               ospf_vrf_link(new, vrf);
+
        ospf_zebra_vrf_register(new);
 
        new->abr_type = OSPF_ABR_DEFAULT;
index a4a9233f72a138a94267e42edc4225adee79bf03..a8cefce84f1db0ed0ee37e5f8074d4e17aa62faf 100644 (file)
@@ -192,7 +192,7 @@ static void *pbr_nhgc_alloc(void *p)
        new = XCALLOC(MTYPE_PBR_NHG, sizeof(*new));
 
        strcpy(new->name, pnhgc->name);
-       new->table_id = pbr_nht_get_next_tableid();
+       new->table_id = pbr_nht_get_next_tableid(false);
 
        DEBUGD(&pbr_dbg_nht, "%s: NHT: %s assigned Table ID: %u",
               __PRETTY_FUNCTION__, new->name, new->table_id);
@@ -218,6 +218,9 @@ void pbr_nhgroup_add_cb(const char *name)
 
        pnhgc = pbr_nht_add_group(name);
 
+       if (!pnhgc)
+               return;
+
        DEBUGD(&pbr_dbg_nht, "%s: Added nexthop-group %s", __PRETTY_FUNCTION__,
               name);
 
@@ -234,6 +237,13 @@ void pbr_nhgroup_add_nexthop_cb(const struct nexthop_group_cmd *nhgc,
        struct pbr_nexthop_cache pnhc_find = {};
        struct pbr_nexthop_cache *pnhc;
 
+       if (!pbr_nht_get_next_tableid(true)) {
+               zlog_warn(
+                       "%s: Exhausted all table identifiers; cannot create nexthop-group cache for nexthop-group '%s'",
+                       __PRETTY_FUNCTION__, nhgc->name);
+               return;
+       }
+
        /* find pnhgc by name */
        strlcpy(pnhgc_find.name, nhgc->name, sizeof(pnhgc_find.name));
        pnhgc = hash_get(pbr_nhg_hash, &pnhgc_find, pbr_nhgc_alloc);
@@ -268,7 +278,7 @@ void pbr_nhgroup_del_nexthop_cb(const struct nexthop_group_cmd *nhgc,
 
        /* find pnhgc by name */
        strlcpy(pnhgc_find.name, nhgc->name, sizeof(pnhgc_find.name));
-       pnhgc = hash_get(pbr_nhg_hash, &pnhgc_find, pbr_nhgc_alloc);
+       pnhgc = hash_lookup(pbr_nhg_hash, &pnhgc_find);
 
        /* delete pnhc from pnhgc->nhh */
        pnhc_find.nexthop = (struct nexthop *)nhop;
@@ -487,6 +497,14 @@ void pbr_nht_add_individual_nexthop(struct pbr_map_sequence *pbrms)
        memset(&find, 0, sizeof(find));
        pbr_nht_nexthop_make_name(pbrms->parent->name, PBR_NHC_NAMELEN,
                                  pbrms->seqno, find.name);
+
+       if (!pbr_nht_get_next_tableid(true)) {
+               zlog_warn(
+                       "%s: Exhausted all table identifiers; cannot create nexthop-group cache for nexthop-group '%s'",
+                       __PRETTY_FUNCTION__, find.name);
+               return;
+       }
+
        if (!pbrms->internal_nhg_name)
                pbrms->internal_nhg_name = XSTRDUP(MTYPE_TMP, find.name);
 
@@ -547,11 +565,18 @@ struct pbr_nexthop_group_cache *pbr_nht_add_group(const char *name)
        struct pbr_nexthop_group_cache *pnhgc;
        struct pbr_nexthop_group_cache lookup;
 
+       if (!pbr_nht_get_next_tableid(true)) {
+               zlog_warn(
+                       "%s: Exhausted all table identifiers; cannot create nexthop-group cache for nexthop-group '%s'",
+                       __PRETTY_FUNCTION__, name);
+               return NULL;
+       }
+
        nhgc = nhgc_find(name);
 
        if (!nhgc) {
-               zlog_warn("%s: Could not find group %s to add",
-                         __PRETTY_FUNCTION__, name);
+               DEBUGD(&pbr_dbg_nht, "%s: Could not find nhgc with name: %s\n",
+                      __PRETTY_FUNCTION__, name);
                return NULL;
        }
 
@@ -709,8 +734,7 @@ static int pbr_nhg_hash_equal(const void *arg1, const void *arg2)
        return !strcmp(nhgc1->name, nhgc2->name);
 }
 
-
-uint32_t pbr_nht_get_next_tableid(void)
+uint32_t pbr_nht_get_next_tableid(bool peek)
 {
        uint32_t i;
        bool found = false;
@@ -723,7 +747,7 @@ uint32_t pbr_nht_get_next_tableid(void)
        }
 
        if (found) {
-               nhg_tableid[i] = true;
+               nhg_tableid[i] = !peek;
                return i;
        } else
                return 0;
index e6fdbfd04cb838ffb9a0e541c6294550115194c1..d37803fbe32e52fffeb5c0b605715064413254b4 100644 (file)
@@ -56,9 +56,13 @@ extern void pbr_nht_write_table_range(struct vty *vty);
 extern void pbr_nht_set_tableid_range(uint32_t low, uint32_t high);
 
 /*
- * Get the next tableid to use for installation
+ * Get the next tableid to use for installation.
+ *
+ * peek
+ *    If set to true, retrieves the next ID without marking it used. The next
+ *    call will return the same ID.
  */
-extern uint32_t pbr_nht_get_next_tableid(void);
+extern uint32_t pbr_nht_get_next_tableid(bool peek);
 /*
  * Get the next rule number to use for installation
  */
index 7e0e8d632ba2bc2b447f94df8796252f02514e08..44e14c5477dff78061faed8f16f4abdecbb7c6f3 100644 (file)
@@ -26,8 +26,8 @@
 #include "nexthop.h"
 #include "nexthop_group.h"
 #include "log.h"
-#include "json.h"
 #include "debug.h"
+#include "pbr.h"
 
 #include "pbrd/pbr_nht.h"
 #include "pbrd/pbr_map.h"
@@ -85,6 +85,34 @@ DEFUN_NOSH(no_pbr_map, no_pbr_map_cmd, "no pbr-map WORD [seq (1-700)]",
        return CMD_SUCCESS;
 }
 
+DEFPY(pbr_set_table_range,
+      pbr_set_table_range_cmd,
+      "[no] pbr table range (10000-4294966272)$lb (10000-4294966272)$ub",
+      NO_STR
+      PBR_STR
+      "Set table ID range\n"
+      "Set table ID range\n"
+      "Lower bound for table ID range\n"
+      "Upper bound for table ID range\n")
+{
+       /* upper bound is 2^32 - 2^10 */
+       int ret = CMD_WARNING;
+       const int minrange = 1000;
+
+       /* validate given bounds */
+       if (lb > ub)
+               vty_out(vty, "%% Lower bound must be less than upper bound\n");
+       else if (ub - lb < minrange)
+               vty_out(vty, "%% Range breadth must be at least %d\n", minrange);
+       else {
+               ret = CMD_SUCCESS;
+               pbr_nht_set_tableid_range((uint32_t) lb, (uint32_t) ub);
+       }
+
+       return ret;
+}
+
+
 DEFPY(pbr_map_match_src, pbr_map_match_src_cmd,
        "[no] match src-ip <A.B.C.D/M|X:X::X:X/M>$prefix",
        NO_STR
@@ -355,10 +383,9 @@ DEFPY (pbr_policy,
 
 DEFPY (show_pbr,
        show_pbr_cmd,
-       "show pbr [json$json]",
+       "show pbr",
        SHOW_STR
-       "Policy Based Routing\n"
-       JSON_STR)
+       PBR_STR)
 {
        pbr_nht_write_table_range(vty);
        pbr_nht_write_rule_range(vty);
@@ -368,13 +395,12 @@ DEFPY (show_pbr,
 
 DEFPY (show_pbr_map,
        show_pbr_map_cmd,
-       "show pbr map [NAME$name] [detail$detail] [json$json]",
+       "show pbr map [NAME$name] [detail$detail]",
        SHOW_STR
-       "Policy Based Routing\n"
+       PBR_STR
        "PBR Map\n"
        "PBR Map Name\n"
-       "Detailed information\n"
-       JSON_STR)
+       "Detailed information\n")
 {
        struct pbr_map_sequence *pbrms;
        struct pbr_map *pbrm;
@@ -439,7 +465,7 @@ DEFPY(show_pbr_nexthop_group,
       show_pbr_nexthop_group_cmd,
       "show pbr nexthop-groups [WORD$word]",
       SHOW_STR
-      "Policy Based Routing\n"
+      PBR_STR
       "Nexthop Groups\n"
       "Optional Name of the nexthop group\n")
 {
@@ -450,12 +476,11 @@ DEFPY(show_pbr_nexthop_group,
 
 DEFPY (show_pbr_interface,
        show_pbr_interface_cmd,
-       "show pbr interface [NAME$name] [json$json]",
+       "show pbr interface [NAME$name]",
        SHOW_STR
-       "Policy Based Routing\n"
+       PBR_STR
        "PBR Interface\n"
-       "PBR Interface Name\n"
-       JSON_STR)
+       "PBR Interface Name\n")
 {
        struct interface *ifp;
        struct vrf *vrf;
@@ -489,7 +514,6 @@ DEFPY (show_pbr_interface,
 }
 
 /* PBR debugging CLI ------------------------------------------------------- */
-/* clang-format off */
 
 static struct cmd_node debug_node = {DEBUG_NODE, "", 1};
 
@@ -498,7 +522,7 @@ DEFPY(debug_pbr,
       "[no] debug pbr [{map$map|zebra$zebra|nht$nht|events$events}]",
       NO_STR
       DEBUG_STR
-      "Policy Based Routing\n"
+      PBR_STR
       "Policy maps\n"
       "PBRD <-> Zebra communications\n"
       "Nexthop tracking\n"
@@ -527,7 +551,7 @@ DEFUN_NOSH(show_debugging_pbr,
           "show debugging [pbr]",
           SHOW_STR
           DEBUG_STR
-          "Policy Based Routing\n")
+          PBR_STR)
 {
        vty_out(vty, "PBR debugging status:\n");
 
@@ -536,7 +560,6 @@ DEFUN_NOSH(show_debugging_pbr,
        return CMD_SUCCESS;
 }
 
-/* clang-format on */
 /* ------------------------------------------------------------------------- */
 
 
@@ -634,6 +657,7 @@ void pbr_vty_init(void)
 
        install_element(CONFIG_NODE, &pbr_map_cmd);
        install_element(CONFIG_NODE, &no_pbr_map_cmd);
+       install_element(CONFIG_NODE, &pbr_set_table_range_cmd);
        install_element(INTERFACE_NODE, &pbr_policy_cmd);
        install_element(PBRMAP_NODE, &pbr_map_match_src_cmd);
        install_element(PBRMAP_NODE, &pbr_map_match_dst_cmd);
index a073fa70beeead052838a736e6b6a79c5809dd66..c0d95aeed9e3799542ee7097f3d982b899a8e98e 100644 (file)
@@ -266,6 +266,8 @@ static int recv_response(int fd, int *hops, struct igmp_mtrace *mtracer)
        int mtrace_len;
        int responses;
        unsigned short sum;
+       size_t mtrace_off;
+       size_t ip_len;
 
        recvd = recvfrom(fd, mtrace_buf, IP_AND_MTRACE_BUF_LEN, 0, NULL, 0);
 
@@ -292,13 +294,20 @@ static int recv_response(int fd, int *hops, struct igmp_mtrace *mtracer)
        if (sum != in_cksum(ip, ip->ip_hl * 4))
                return -1;
 
-       mtrace = (struct igmp_mtrace *)(mtrace_buf + (4 * ip->ip_hl));
-
-       mtrace_len = ntohs(ip->ip_len) - ip->ip_hl * 4;
+       /* Header overflow check */
+       mtrace_off = 4 * ip->ip_hl;
+       if (mtrace_off > MTRACE_BUF_LEN)
+               return -1;
 
-       if (mtrace_len < (int)MTRACE_HDR_SIZE)
+       /* Underflow/overflow check */
+       ip_len = ntohs(ip->ip_len);
+       if (ip_len < mtrace_off || ip_len < MTRACE_HDR_SIZE
+           || ip_len > MTRACE_BUF_LEN)
                return -1;
 
+       mtrace_len = ip_len - mtrace_off;
+       mtrace = (struct igmp_mtrace *)(mtrace_buf + mtrace_off);
+
        sum = mtrace->checksum;
        mtrace->checksum = 0;
        if (sum != in_cksum(mtrace, mtrace_len)) {
@@ -332,7 +341,7 @@ static int wait_for_response(int fd, int *hops, struct igmp_mtrace *mtrace,
 {
        fd_set readfds;
        struct timeval timeout;
-       int ret = -1;
+       int ret;
        long msec, rmsec, tmsec;
 
        FD_ZERO(&readfds);
index 55222ecddbd81ab973ca2702eefdc6a77fbc570e..123c47568cb0a5b6ec61b4c6cb7a05a877901f37 100644 (file)
@@ -4504,8 +4504,8 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty, bool fill,
        json_object *json_source = NULL;
        json_object *json_oil = NULL;
        json_object *json_ifp_out = NULL;
-       int found_oif = 0;
-       int first = 1;
+       int found_oif;
+       int first;
        char grp_str[INET_ADDRSTRLEN];
        char src_str[INET_ADDRSTRLEN];
        char in_ifname[INTERFACE_NAMSIZ + 1];
index 673e2ca5b8f2e66566128a7ce92da6ec89440646..95d0278a34317a789275e5357ee9dab41b33e310 100644 (file)
@@ -817,7 +817,7 @@ int igmp_mtrace_recv_qry_req(struct igmp_sock *igmp, struct ip *ip_hdr,
                 * Previous-hop router not known,
                 * packet is sent to an appropriate multicast address
                 */
-               inet_aton(MCAST_ALL_ROUTERS, &nh_addr);
+               (void)inet_aton(MCAST_ALL_ROUTERS, &nh_addr);
        }
 
        /* 6.2.2 8. If this router is the Rendez-vous Point */
index fd3c04e8ca3d6043bde503d3b92076be26ebbfb5..d49484f869f91fdb8c325e9017d431a9a0ea32e4 100644 (file)
@@ -40,7 +40,6 @@ char *pim_channel_oil_dump(struct channel_oil *c_oil, char *buf, size_t size)
        struct prefix_sg sg;
        int i;
 
-       memset(buf, 0, size);
        sg.src = c_oil->oil.mfcc_origin;
        sg.grp = c_oil->oil.mfcc_mcastgrp;
        sprintf(buf, "%s IIF: %d, OIFS: ", pim_str_sg_dump(&sg),
index de09b070f467a3f2d4cf45fc3e9b8270dd9ead46..f506875282d3cb65f9d797b06e3f55b2f00bb474 100644 (file)
@@ -521,7 +521,7 @@ int pim_msg_send(int fd, struct in_addr src, struct in_addr dst,
        socklen_t tolen;
        unsigned char buffer[10000];
        unsigned char *msg_start;
-       uint8_t ttl = MAXTTL;
+       uint8_t ttl;
        struct pim_msg_header *header;
        struct ip *ip;
 
index 6d06229b98810dc8c3809b9ae5b6894ba23f2084..b41124376f9f2546e31f61aec6f05b671ebfeba0 100644 (file)
 
 #include "pimd.h"
 
-
-static void pim_route_map_mark_update(const char *rmap_name)
-{
-       // placeholder
-       return;
-}
-
 static void pim_route_map_add(const char *rmap_name)
 {
-       if (route_map_mark_updated(rmap_name, 0) == 0)
-               pim_route_map_mark_update(rmap_name);
-
        route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED);
 }
 
 static void pim_route_map_delete(const char *rmap_name)
 {
-       if (route_map_mark_updated(rmap_name, 1) == 0)
-               pim_route_map_mark_update(rmap_name);
-
        route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_DELETED);
 }
 
 static void pim_route_map_event(route_map_event_t event, const char *rmap_name)
 {
-       if (route_map_mark_updated(rmap_name, 0) == 0)
-               pim_route_map_mark_update(rmap_name);
-
        route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED);
 }
 
index ae7f61c8eb1c2d9787ffa539946e3a47d2224b0a..cb384bfe1da8d2dd021f2c18a44c91df73d3d459 100644 (file)
@@ -737,8 +737,6 @@ static void pim_zebra_connected(struct zclient *zclient)
 
 void pim_zebra_init(void)
 {
-       int i;
-
        /* Socket for receiving updates from Zebra daemon */
        zclient = zclient_new_notify(master, &zclient_options_default);
 
@@ -754,31 +752,7 @@ void pim_zebra_init(void)
 
        zclient_init(zclient, ZEBRA_ROUTE_PIM, 0, &pimd_privs);
        if (PIM_DEBUG_PIM_TRACE) {
-               zlog_info("zclient_init cleared redistribution request");
-       }
-
-       /* Request all redistribution */
-       for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
-               if (i == zclient->redist_default)
-                       continue;
-               vrf_bitmap_set(zclient->redist[AFI_IP][i], pimg->vrf_id);
-               ;
-               if (PIM_DEBUG_PIM_TRACE) {
-                       zlog_debug("%s: requesting redistribution for %s (%i)",
-                                  __PRETTY_FUNCTION__, zebra_route_string(i),
-                                  i);
-               }
-       }
-
-       /* Request default information */
-       zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_ADD, zclient,
-                                    pimg->vrf_id);
-
-       if (PIM_DEBUG_PIM_TRACE) {
-               zlog_info("%s: requesting default information redistribution",
-                         __PRETTY_FUNCTION__);
-
-               zlog_notice("%s: zclient update socket initialized",
+               zlog_notice("%s: zclient socket initialized",
                            __PRETTY_FUNCTION__);
        }
 
index c6cc10542bde005112d126bb96db62f35631fe03..064b78b260ea900f85da86bf2c7a7ce6517b9ec5 100644 (file)
 
 #### Check for systemd or init.d (upstart)
 # Check for init.d (upstart) as used in CentOS 6 or systemd (ie CentOS 7)
-%if 0%{?fedora} >= 15 || 0%{?rhel} >= 7 || 0%{?suse_version} >= 1210
+%if 0%{?fedora} || 0%{?rhel} >= 7 || 0%{?suse_version} >= 1210
     %global initsystem systemd
 %else
-%if (0%{?fedora} && 0%{?fedora} < 15) || (0%{?rhel} && 0%{?rhel} < 7)
+%if 0%{?rhel} && 0%{?rhel} < 7
     %global initsystem upstart
 %else
     %{expand: %%global initsystem %(if [[ `/sbin/init --version 2> /dev/null` =~ upstart ]]; then echo upstart; elif [[ `readlink -f /sbin/init` = /usr/lib/systemd/systemd ]]; then echo systemd; elif [[ `systemctl` =~ -\.mount ]]; then echo systemd; fi)}
 %endif
 %endif
-#
-# If init system is systemd, then always disable watchfrr
-#
+
+# If init system is systemd, then always enable watchfrr
 %if "%{initsystem}" == "systemd"
-    # Note: For systems with systemd, watchfrr will NOT be built. Systemd
-    # takes over the role of restarting crashed processes. Value will
-    # be overwritten with 0 below for systemd independent on the setting here
     %global with_watchfrr 1
 %endif
 
-#### Check for RedHat 6.x or CentOS 6.x - they are too old to support PIM. 
+#### Check for RedHat 6.x or CentOS 6.x - they are too old to support PIM.
 ####   Always disable it on these old systems unconditionally
 #
 # if CentOS / RedHat and version < 7, then disable PIMd (too old, won't work)
 %define     daemon_list zebra ripd ospfd bgpd isisd ripngd ospf6d pbrd
 
 %if %{with_ldpd}
-%define     daemon_ldpd ldpd
+%define daemon_ldpd ldpd
 %else
-%define     daemon_ldpd ""
+%define daemon_ldpd ""
 %endif
 
 %if %{with_pimd}
-%define     daemon_pimd pimd
+%define daemon_pimd pimd
 %else
-%define     daemon_pimd ""
+%define daemon_pimd ""
 %endif
 
 %if %{with_pbrd}
-%define     daemon_pbrd pbrd
+%define daemon_pbrd pbrd
 %else
-%define     daemon_pbrd ""
+%define daemon_pbrd ""
 %endif
 
 %if %{with_nhrpd}
-%define         daemon_nhrpd   nhrpd
+%define daemon_nhrpd nhrpd
 %else
-%define                daemon_nhrpd    ""
+%define daemon_nhrpd ""
 %endif
 
 %if %{with_eigrpd}
-%define         daemon_eigrpd  eigrpd
+%define daemon_eigrpd eigrpd
 %else
-%define                daemon_eigrpd   ""
+%define daemon_eigrpd ""
 %endif
 
 %if %{with_babeld}
-%define         daemon_babeld  babeld
+%define daemon_babeld babeld
 %else
-%define                daemon_babeld   ""
+%define daemon_babeld ""
 %endif
 
 %if %{with_watchfrr}
-%define     daemon_watchfrr watchfrr
+%define daemon_watchfrr watchfrr
 %else
-%define     daemon_watchfrr ""
+%define daemon_watchfrr ""
 %endif
 
-%define     all_daemons %{daemon_list} %{daemon_ldpd} %{daemon_pimd} %{daemon_nhrpd} %{daemon_eigrpd} %{daemon_babeld} %{daemon_watchfrr} %{daemon_pbrd}
+%define all_daemons %{daemon_list} %{daemon_ldpd} %{daemon_pimd} %{daemon_nhrpd} %{daemon_eigrpd} %{daemon_babeld} %{daemon_watchfrr} %{daemon_pbrd}
 
 # allow build dir to be kept
 %{!?keep_build:         %global  keep_build         0 }
@@ -145,13 +141,12 @@ Version:        %{rpmversion}
 Release:        @CONFDATE@%{release_rev}%{?dist}
 License:        GPLv2+
 Group:          System Environment/Daemons
-Source0:        http://www.frrouting.org/releases/frr/%{name}-%{frrversion}.tar.gz
-URL:            http://www.frrouting.org
-Requires(pre):  /sbin/install-info
-Requires(preun): /sbin/install-info
-Requires(post): /sbin/install-info
+Source0:        https://github.com/FRRouting/frr/archive/%{name}-%{frrversion}.tar.gz
+URL:            https://www.frrouting.org
+Requires(preun): info
+Requires(post): info
 BuildRequires:  gcc patch libcap-devel
-BuildRequires:  readline readline-devel ncurses ncurses-devel
+BuildRequires:  readline-devel ncurses-devel
 BuildRequires:  json-c-devel bison >= 2.7 flex make
 BuildRequires:  c-ares-devel texinfo
 %if 0%{?rhel} && 0%{?rhel} < 7
@@ -160,14 +155,12 @@ BuildRequires:  python27-devel python27-sphinx
 %else
 BuildRequires:  python-devel >= 2.7 python-sphinx
 %endif
-Requires:       ncurses json-c initscripts
+Requires:       json-c initscripts
 %if %{with_pam}
 BuildRequires:  pam-devel
-Requires:       pam
 %endif
 %if %{with_rpki}
 BuildRequires:  librtr-devel >= 0.5
-Requires:       librtr >= 0.5
 %endif
 %if "%{initsystem}" == "systemd"
 BuildRequires:      systemd systemd-devel
@@ -175,6 +168,8 @@ Requires(post):     systemd
 Requires(preun):    systemd
 Requires(postun):   systemd
 %else
+Requires(post):     chkconfig
+Requires(preun):    chkconfig
 # Initscripts > 5.60 is required for IPv6 support
 Requires(pre):      initscripts >= 5.60
 %endif
@@ -203,7 +198,7 @@ Contributed/3rd party tools which may be of use with frr.
 %package pythontools
 Summary: python tools for frr
 BuildRequires: python
-Requires: python python-ipaddr
+Requires: python-ipaddr
 Group: System Environment/Daemons
 
 %description pythontools
@@ -254,14 +249,14 @@ developing OSPF-API and frr applications.
     --disable-ospfclient\
 %endif
 %if %{with_ospfapi}
-    --enable-ospfapi=yes \
+    --enable-ospfapi \
 %else
-    --enable-ospfapi=no \
+    --disable-ospfapi \
 %endif
 %if %{with_rtadv}
-    --enable-rtadv=yes \
+    --enable-rtadv \
 %else
-    --enable-rtadv=no \
+    --disable-rtadv \
 %endif
 %if %{with_ldpd}
     --enable-ldpd \
@@ -279,19 +274,19 @@ developing OSPF-API and frr applications.
     --disable-pbrd \
 %endif
 %if %{with_nhrpd}
-       --enable-nhrpd \
+    --enable-nhrpd \
 %else
-       --disable-nhrpd \
+    --disable-nhrpd \
 %endif
 %if %{with_eigrpd}
-       --enable-eigrpd \
+    --enable-eigrpd \
 %else
-       --disable-eigrpd \
+    --disable-eigrpd \
 %endif
 %if %{with_babeld}
-       --enable-babeld \
+    --enable-babeld \
 %else
-       --disable-babeld \
+    --disable-babeld \
 %endif
 %if %{with_pam}
     --with-libpam \
@@ -318,14 +313,14 @@ developing OSPF-API and frr applications.
 %else
     --disable-bgp-vnc \
 %endif
-    --enable-isisd=yes \
+    --enable-isisd \
 %if "%{initsystem}" == "systemd"
-    --enable-systemd=yes \
+    --enable-systemd \
 %endif
 %if %{with_rpki}
     --enable-rpki \
 %endif
-    --enable-poll=yes
+    --enable-poll
 
 make %{?_smp_mflags} MAKEINFO="makeinfo --no-split" SPHINXBUILD=%{sphinx}
 
@@ -399,7 +394,7 @@ fi
 
 zebra_spec_add_service ()
 {
-    # Add port /etc/services entry if it isn't already there 
+    # Add port /etc/services entry if it isn't already there
     if [ -f /etc/services ] && \
         ! %__sed -e 's/#.*$//' /etc/services | %__grep -wq $1 ; then
         echo "$1        $2          # $3"  >> /etc/services
@@ -543,7 +538,7 @@ rm -rf %{buildroot}
 %doc ChangeLog NEWS README
 %if 0%{?frr_user:1}
 %dir %attr(751,%frr_user,%frr_user) %{_sysconfdir}
-%dir %attr(750,%frr_user,%frr_user) /var/log/frr 
+%dir %attr(750,%frr_user,%frr_user) /var/log/frr
 %dir %attr(751,%frr_user,%frr_user) /var/run/frr
 %else
 %dir %attr(750,root,root) %{_sysconfdir}
@@ -600,14 +595,13 @@ rm -rf %{buildroot}
 %config(noreplace) /etc/frr/[!v]*.conf*
 %config(noreplace) %attr(750,%frr_user,%frr_user) /etc/frr/daemons
 %if "%{initsystem}" == "systemd"
-    %attr(644,root,root) %{_unitdir}/frr.service
-    %{_sbindir}/frr
+    %{_unitdir}/frr.service
 %else
     /etc/rc.d/init.d/frr
-    %{_sbindir}/frr
 %endif
+%{_sbindir}/frr
 %config(noreplace) /etc/pam.d/frr
-%config(noreplace) %attr(640,root,root) /etc/logrotate.d/*
+%config(noreplace) /etc/logrotate.d/frr
 %{_sbindir}/frr-reload
 
 %files contrib
@@ -661,13 +655,13 @@ rm -rf %{buildroot}
 - new subpackage frr-pythontools with python 2.7 restart script
 - remove PIMd from CentOS/RedHat 6 RPM packages (won't work - too old)
 - converted to single frr init script (not per daemon) based on debian init script
-- created systemd service file for systemd based systems (which uses init script) 
+- created systemd service file for systemd based systems (which uses init script)
 - Various other RPM package fixes for FRR 2.0
 
 * Fri Jan  6 2017 Martin Winter <mwinter@opensourcerouting.org>
 - Renamed to frr for FRRouting fork of Quagga
 
-* Thu Feb 11 2016 Paul Jakma <paul@jakma.org> 
+* Thu Feb 11 2016 Paul Jakma <paul@jakma.org>
 - remove with_ipv6 conditionals, always build v6
 - Fix UTF-8 char in spec changelog
 - remove quagga.pam.stack, long deprecated.
@@ -678,7 +672,7 @@ rm -rf %{buildroot}
 - Remove support for old fedora 4/5
 - Fix for package nameing
 - Fix Weekdays of previous changelogs (bogus dates)
-- Add conditional logic to only build tex footnotes with supported texi2html 
+- Add conditional logic to only build tex footnotes with supported texi2html
 - Added pimd to files section and fix double listing of /var/lib*/quagga
 - Numerous fixes to unify upstart/systemd startup into same spec file
 - Only allow use of watchfrr for non-systemd systems. no need with systemd
@@ -771,7 +765,7 @@ rm -rf %{buildroot}
 - walk up tree - 17218
 - ospfd NSSA fixes - 16681
 - ospfd nsm fixes - 16824
-- ospfd OLSA fixes and new feature - 16823 
+- ospfd OLSA fixes and new feature - 16823
 - KAME and ifindex fixes - 16525
 - spec file changes to allow redhat files to be in tree
 
@@ -829,7 +823,7 @@ rm -rf %{buildroot}
 * Tue Feb  6 2001 Tim Powers <timp@redhat.com>
 - built for Powertools
 
-* Sun Feb  4 2001 Pekka Savola <pekkas@netcore.fi> 
+* Sun Feb  4 2001 Pekka Savola <pekkas@netcore.fi>
 - Hacked up from PLD Linux 0.90-1, Mandrake 0.90-1mdk and one from zebra.org.
 - Update to 0.91a
 - Very heavy modifications to init.d/*, .spec, pam, i18n, logrotate, etc.
index 92c27106d583be85b09f9ba645e354e5b9408026..90dc7808ebb802be538ff46dcada1e10a4185cec 100644 (file)
@@ -799,11 +799,11 @@ static int rip_auth_simple_password(struct rte *rte, struct sockaddr_in *from,
                                    struct interface *ifp)
 {
        struct rip_interface *ri;
-       char *auth_str = (char *)&rte->prefix;
+       char *auth_str = (char *)rte + offsetof(struct rte, prefix);
        int i;
 
        /* reject passwords with zeros in the middle of the string */
-       for (i = strlen(auth_str); i < 16; i++) {
+       for (i = strnlen(auth_str, 16); i < 16; i++) {
                if (auth_str[i] != '\0')
                        return 0;
        }
index a478b416bf7f687700db89c2493ec7f2b3cb6fef..22a19da0b3257114b300c4c5d70e904f2b5eb260 100644 (file)
@@ -51,7 +51,6 @@ uint32_t installed_routes = 0;
 uint32_t removed_routes = 0;
 
 zebra_capabilities_t _caps_p[] = {
-       ZCAP_NET_RAW, ZCAP_BIND, ZCAP_NET_ADMIN,
 };
 
 struct zebra_privs_t sharp_privs = {
index aefe0d06ac556e09059e38a582fe5c4403638bca..32d2db768a0fa8e19aa6a8e3d3a3b5918e345672 100644 (file)
@@ -3,7 +3,7 @@ include ../common.am
 PYTHON ?= python
 
 AUTOMAKE_OPTIONS = subdir-objects
-AM_CPPFLAGS = \
+AM_CPPFLAGS += \
        -I.. \
        -I$(top_srcdir) \
        -I$(top_srcdir)/lib \
@@ -102,8 +102,6 @@ lib/cli/test_commands_defun.c: ../vtysh/vtysh_cmd.c
 
 isisd/test_fuzz_isis_tlv_tests.h: $(top_srcdir)/tests/isisd/test_fuzz_isis_tlv_tests.h.gz
        gzip -d < $(top_srcdir)/tests/isisd/test_fuzz_isis_tlv_tests.h.gz > "$@"
-isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.$(OBJEXT): \
-       isisd/test_fuzz_isis_tlv_tests.h
 
 noinst_HEADERS = \
        ./helpers/c/prng.h \
@@ -146,6 +144,9 @@ bgpd_test_ecommunity_SOURCES = bgpd/test_ecommunity.c
 bgpd_test_mp_attr_SOURCES = bgpd/test_mp_attr.c
 bgpd_test_mpath_SOURCES = bgpd/test_mpath.c
 isisd_test_fuzz_isis_tlv_SOURCES = isisd/test_fuzz_isis_tlv.c
+nodist_isisd_test_fuzz_isis_tlv_SOURCES = isisd/test_fuzz_isis_tlv_tests.h
+BUILT_SOURCES=isisd/test_fuzz_isis_tlv_tests.h
+CLEANFILES=isisd/test_fuzz_isis_tlv_tests.h
 isisd_test_fuzz_isis_tlv_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_builddir)/tests/isisd
 isisd_test_isis_vertex_queue_SOURCES = isisd/test_isis_vertex_queue.c
 
index 67a6db849f8ad4c9828db6bb2af517fcaf626dcc..16bd5d96dab51e53d8cdbaffb12c6467d431cf3b 100644 (file)
 #include "bgpd/rfapi/rfapi_backend.h"
 #endif
 
+#define OUT_SYMBOL_INFO "\u25ba"
+#define OUT_SYMBOL_OK "\u2714"
+#define OUT_SYMBOL_NOK "\u2716"
+
+#define TEST_ASSERT(T, C)                                                      \
+       do {                                                                   \
+               if ((T)->state != TEST_SUCCESS || (C))                         \
+                       break;                                                 \
+               (T)->state = TEST_ASSERT_ERROR;                                \
+               (T)->error = str_printf("assertion failed: %s (%s:%d)", (#C),  \
+                                       __FILE__, __LINE__);                   \
+       } while (0)
+
+#define TEST_ASSERT_EQ(T, A, B)                                                \
+       do {                                                                   \
+               if ((T)->state != TEST_SUCCESS || ((A) == (B)))                \
+                       break;                                                 \
+               (T)->state = TEST_ASSERT_ERROR;                                \
+               (T)->error = str_printf(                                       \
+                       "assertion failed: %s[%d] == [%d]%s (%s:%d)", (#A),    \
+                       (A), (B), (#B), __FILE__, __LINE__);                   \
+       } while (0)
+
+#define TEST_HANDLER_MAX 5
+#define TEST_HANDLER(name) _test_handler_##name
+#define TEST_HANDLER_DECL(name)                                                \
+       static void _test_handler_##name(                                      \
+               struct test *test, struct test_peer_attr *pa,                  \
+               struct peer *peer, struct peer *group, bool peer_set,          \
+               bool group_set)
+
+#define TEST_ATTR_HANDLER_DECL(name, attr, pval, gval)                         \
+       TEST_HANDLER_DECL(name)                                                \
+       {                                                                      \
+               if (peer_set)                                                  \
+                       TEST_ASSERT_EQ(test, peer->attr, (pval));              \
+               else if (peer_group_active(peer) && group_set)                 \
+                       TEST_ASSERT_EQ(test, peer->attr, (gval));              \
+               if (group_set)                                                 \
+                       TEST_ASSERT_EQ(test, group->attr, (gval));             \
+       }                                                                      \
+       TEST_HANDLER_DECL(name)
+
+#define TEST_STR_ATTR_HANDLER_DECL(name, attr, pval, gval)                     \
+       TEST_HANDLER_DECL(name)                                                \
+       {                                                                      \
+               if (peer_set) {                                                \
+                       TEST_ASSERT(test, peer->attr != NULL);                 \
+                       TEST_ASSERT(test, !strcmp(peer->attr, (pval)));        \
+               } else if (peer_group_active(peer) && group_set) {             \
+                       TEST_ASSERT(test, peer->attr != NULL);                 \
+                       TEST_ASSERT(test, !strcmp(peer->attr, (gval)));        \
+               }                                                              \
+               if (group_set) {                                               \
+                       TEST_ASSERT(test, group->attr != NULL);                \
+                       TEST_ASSERT(test, !strcmp(group->attr, (gval)));       \
+               }                                                              \
+       }                                                                      \
+       TEST_HANDLER_DECL(name)
+
+#define TEST_SU_ATTR_HANDLER_DECL(name, attr, pval, gval)                      \
+       TEST_HANDLER_DECL(name)                                                \
+       {                                                                      \
+               union sockunion su;                                            \
+               if (peer_set) {                                                \
+                       str2sockunion(pval, &su);                              \
+                       TEST_ASSERT(test, !sockunion_cmp(peer->attr, &su));    \
+               } else if (peer_group_active(peer) && group_set) {             \
+                       str2sockunion(gval, &su);                              \
+                       TEST_ASSERT(test, !sockunion_cmp(group->attr, &su));   \
+               }                                                              \
+               if (group_set) {                                               \
+                       str2sockunion(gval, &su);                              \
+                       TEST_ASSERT(test, !sockunion_cmp(group->attr, &su));   \
+               }                                                              \
+       }                                                                      \
+       TEST_HANDLER_DECL(name)
+
 /* Required variables to link in libbgp */
 struct zebra_privs_t bgpd_privs = {0};
 struct thread_master *master;
 
 enum test_state {
        TEST_SUCCESS,
+       TEST_SKIPPING,
        TEST_COMMAND_ERROR,
        TEST_CONFIG_ERROR,
        TEST_ASSERT_ERROR,
+       TEST_CUSTOM_ERROR,
        TEST_INTERNAL_ERROR,
 };
 
+enum test_peer_attr_type {
+       PEER_AT_AF_FLAG = 0,
+       PEER_AT_AF_FILTER = 1,
+       PEER_AT_AF_CUSTOM = 2,
+       PEER_AT_GLOBAL_FLAG = 3,
+       PEER_AT_GLOBAL_CUSTOM = 4
+};
+
 struct test {
        enum test_state state;
        char *desc;
@@ -56,12 +144,18 @@ struct test {
        struct bgp *bgp;
        struct peer *peer;
        struct peer_group *group;
+
+       struct {
+               bool use_ibgp;
+               bool use_iface_peer;
+       } o;
 };
 
 struct test_config {
        int local_asn;
        int peer_asn;
        const char *peer_address;
+       const char *peer_interface;
        const char *peer_group;
 };
 
@@ -75,9 +169,7 @@ struct test_peer_attr {
        const char *peer_cmd;
        const char *group_cmd;
 
-       enum { PEER_AT_AF_FLAG = 0,
-              PEER_AT_AF_FILTER = 1,
-              PEER_AT_GLOBAL_FLAG = 2 } type;
+       enum test_peer_attr_type type;
        union {
                uint32_t flag;
                struct {
@@ -86,33 +178,29 @@ struct test_peer_attr {
                } filter;
        } u;
        struct {
-               bool invert;
+               bool invert_peer;
+               bool invert_group;
                bool use_ibgp;
+               bool use_iface_peer;
+               bool skip_xfer_cases;
        } o;
 
        afi_t afi;
        safi_t safi;
        struct test_peer_family families[AFI_MAX * SAFI_MAX];
-};
-
-#define OUT_SYMBOL_INFO "\u25ba"
-#define OUT_SYMBOL_OK "\u2714"
-#define OUT_SYMBOL_NOK "\u2716"
 
-#define TEST_ASSERT_EQ(T, A, B)                                                \
-       do {                                                                   \
-               if ((T)->state != TEST_SUCCESS || ((A) == (B)))                \
-                       break;                                                 \
-               (T)->state = TEST_ASSERT_ERROR;                                \
-               (T)->error = str_printf(                                       \
-                       "assertion failed: %s[%d] == [%d]%s (%s:%d)", (#A),    \
-                       (A), (B), (#B), __FILE__, __LINE__);                   \
-       } while (0)
+       void (*handlers[TEST_HANDLER_MAX])(struct test *test,
+                                          struct test_peer_attr *pa,
+                                          struct peer *peer,
+                                          struct peer *group, bool peer_set,
+                                          bool group_set);
+};
 
 static struct test_config cfg = {
        .local_asn = 100,
        .peer_asn = 200,
        .peer_address = "1.1.1.1",
+       .peer_interface = "IP-TEST",
        .peer_group = "PG-TEST",
 };
 
@@ -123,8 +211,208 @@ static struct test_peer_family test_default_families[] = {
        {.afi = AFI_IP6, .safi = SAFI_MULTICAST},
 };
 
+static char *str_vprintf(const char *fmt, va_list ap)
+{
+       int ret;
+       int buf_size = 0;
+       char *buf = NULL;
+       va_list apc;
+
+       while (1) {
+               va_copy(apc, ap);
+               ret = vsnprintf(buf, buf_size, fmt, apc);
+               va_end(apc);
+
+               if (ret >= 0 && ret < buf_size)
+                       break;
+
+               if (ret >= 0)
+                       buf_size = ret + 1;
+               else
+                       buf_size *= 2;
+
+               buf = XREALLOC(MTYPE_TMP, buf, buf_size);
+       }
+
+       return buf;
+}
+
+static char *str_printf(const char *fmt, ...)
+{
+       char *buf;
+       va_list ap;
+
+       va_start(ap, fmt);
+       buf = str_vprintf(fmt, ap);
+       va_end(ap);
+
+       return buf;
+}
+
+TEST_ATTR_HANDLER_DECL(advertisement_interval, v_routeadv, 10, 20);
+TEST_STR_ATTR_HANDLER_DECL(password, password, "FRR-Peer", "FRR-Group");
+TEST_ATTR_HANDLER_DECL(local_as, change_local_as, 1, 2);
+TEST_ATTR_HANDLER_DECL(timers_1, keepalive, 10, 20);
+TEST_ATTR_HANDLER_DECL(timers_2, holdtime, 30, 60);
+TEST_SU_ATTR_HANDLER_DECL(update_source_su, update_source, "255.255.255.1",
+                         "255.255.255.2");
+TEST_STR_ATTR_HANDLER_DECL(update_source_if, update_if, "IF-PEER", "IF-GROUP");
+
+TEST_ATTR_HANDLER_DECL(allowas_in, allowas_in[pa->afi][pa->safi], 1, 2);
+TEST_STR_ATTR_HANDLER_DECL(default_originate_route_map,
+                          default_rmap[pa->afi][pa->safi].name, "RM-PEER",
+                          "RM-GROUP");
+TEST_STR_ATTR_HANDLER_DECL(
+       distribute_list,
+       filter[pa->afi][pa->safi].dlist[pa->u.filter.direct].name, "DL-PEER",
+       "DL-GROUP");
+TEST_STR_ATTR_HANDLER_DECL(
+       filter_list, filter[pa->afi][pa->safi].aslist[pa->u.filter.direct].name,
+       "FL-PEER", "FL-GROUP");
+TEST_ATTR_HANDLER_DECL(maximum_prefix, pmax[pa->afi][pa->safi], 10, 20);
+TEST_ATTR_HANDLER_DECL(maximum_prefix_threshold,
+                      pmax_threshold[pa->afi][pa->safi], 1, 2);
+TEST_ATTR_HANDLER_DECL(maximum_prefix_restart, pmax_restart[pa->afi][pa->safi],
+                      100, 200);
+TEST_STR_ATTR_HANDLER_DECL(
+       prefix_list, filter[pa->afi][pa->safi].plist[pa->u.filter.direct].name,
+       "PL-PEER", "PL-GROUP");
+TEST_STR_ATTR_HANDLER_DECL(
+       route_map, filter[pa->afi][pa->safi].map[pa->u.filter.direct].name,
+       "RM-PEER", "RM-GROUP");
+TEST_STR_ATTR_HANDLER_DECL(unsuppress_map, filter[pa->afi][pa->safi].usmap.name,
+                          "UM-PEER", "UM-GROUP");
+TEST_ATTR_HANDLER_DECL(weight, weight[pa->afi][pa->safi], 100, 200);
+
 /* clang-format off */
 static struct test_peer_attr test_peer_attrs[] = {
+       /* Peer Attributes */
+       {
+               .cmd = "advertisement-interval",
+               .peer_cmd = "advertisement-interval 10",
+               .group_cmd = "advertisement-interval 20",
+               .u.flag = PEER_FLAG_ROUTEADV,
+               .type = PEER_AT_GLOBAL_FLAG,
+               .handlers[0] = TEST_HANDLER(advertisement_interval),
+       },
+       {
+               .cmd = "capability dynamic",
+               .u.flag = PEER_FLAG_DYNAMIC_CAPABILITY,
+               .type = PEER_AT_GLOBAL_FLAG,
+       },
+       {
+               .cmd = "capability extended-nexthop",
+               .u.flag = PEER_FLAG_CAPABILITY_ENHE,
+               .type = PEER_AT_GLOBAL_FLAG,
+       },
+       {
+               .cmd = "capability extended-nexthop",
+               .u.flag = PEER_FLAG_CAPABILITY_ENHE,
+               .type = PEER_AT_GLOBAL_FLAG,
+               .o.invert_peer = true,
+               .o.use_iface_peer = true,
+       },
+       {
+               .cmd = "description",
+               .peer_cmd = "description FRR Peer",
+               .group_cmd = "description FRR Group",
+               .type = PEER_AT_GLOBAL_CUSTOM,
+       },
+       {
+               .cmd = "disable-connected-check",
+               .u.flag = PEER_FLAG_DISABLE_CONNECTED_CHECK,
+               .type = PEER_AT_GLOBAL_FLAG,
+       },
+       {
+               .cmd = "dont-capability-negotiate",
+               .u.flag = PEER_FLAG_DONT_CAPABILITY,
+               .type = PEER_AT_GLOBAL_FLAG,
+       },
+       {
+               .cmd = "enforce-first-as",
+               .u.flag = PEER_FLAG_ENFORCE_FIRST_AS,
+               .type = PEER_AT_GLOBAL_FLAG,
+       },
+       {
+               .cmd = "local-as",
+               .peer_cmd = "local-as 1",
+               .group_cmd = "local-as 2",
+               .u.flag = PEER_FLAG_LOCAL_AS,
+               .type = PEER_AT_GLOBAL_FLAG,
+               .handlers[0] = TEST_HANDLER(local_as),
+       },
+       {
+               .cmd = "local-as 1 no-prepend",
+               .u.flag = PEER_FLAG_LOCAL_AS | PEER_FLAG_LOCAL_AS_NO_PREPEND,
+               .type = PEER_AT_GLOBAL_FLAG,
+       },
+       {
+               .cmd = "local-as 1 no-prepend replace-as",
+               .u.flag = PEER_FLAG_LOCAL_AS | PEER_FLAG_LOCAL_AS_REPLACE_AS,
+               .type = PEER_AT_GLOBAL_FLAG,
+       },
+       {
+               .cmd = "override-capability",
+               .u.flag = PEER_FLAG_OVERRIDE_CAPABILITY,
+               .type = PEER_AT_GLOBAL_FLAG,
+       },
+       {
+               .cmd = "passive",
+               .u.flag = PEER_FLAG_PASSIVE,
+               .type = PEER_AT_GLOBAL_FLAG,
+       },
+       {
+               .cmd = "password",
+               .peer_cmd = "password FRR-Peer",
+               .group_cmd = "password FRR-Group",
+               .u.flag = PEER_FLAG_PASSWORD,
+               .type = PEER_AT_GLOBAL_FLAG,
+               .handlers[0] = TEST_HANDLER(password),
+       },
+       {
+               .cmd = "shutdown",
+               .u.flag = PEER_FLAG_SHUTDOWN,
+               .type = PEER_AT_GLOBAL_FLAG,
+       },
+       {
+               .cmd = "strict-capability-match",
+               .u.flag = PEER_FLAG_STRICT_CAP_MATCH,
+               .type = PEER_AT_GLOBAL_FLAG,
+       },
+       {
+               .cmd = "timers",
+               .peer_cmd = "timers 10 30",
+               .group_cmd = "timers 20 60",
+               .u.flag = PEER_FLAG_TIMER,
+               .type = PEER_AT_GLOBAL_FLAG,
+               .handlers[0] = TEST_HANDLER(timers_1),
+               .handlers[1] = TEST_HANDLER(timers_2),
+       },
+       {
+               .cmd = "timers connect",
+               .peer_cmd = "timers connect 10",
+               .group_cmd = "timers connect 20",
+               .u.flag = PEER_FLAG_TIMER_CONNECT,
+               .type = PEER_AT_GLOBAL_FLAG,
+       },
+       {
+               .cmd = "update-source",
+               .peer_cmd = "update-source 255.255.255.1",
+               .group_cmd = "update-source 255.255.255.2",
+               .u.flag = PEER_FLAG_UPDATE_SOURCE,
+               .type = PEER_AT_GLOBAL_FLAG,
+               .handlers[0] = TEST_HANDLER(update_source_su),
+       },
+       {
+               .cmd = "update-source",
+               .peer_cmd = "update-source IF-PEER",
+               .group_cmd = "update-source IF-GROUP",
+               .u.flag = PEER_FLAG_UPDATE_SOURCE,
+               .type = PEER_AT_GLOBAL_FLAG,
+               .handlers[0] = TEST_HANDLER(update_source_if),
+       },
+
+       /* Address Family Attributes */
        {
                .cmd = "addpath-tx-all-paths",
                .u.flag = PEER_FLAG_ADDPATH_TX_ALL_PATHS,
@@ -138,6 +426,7 @@ static struct test_peer_attr test_peer_attrs[] = {
                .peer_cmd = "allowas-in 1",
                .group_cmd = "allowas-in 2",
                .u.flag = PEER_FLAG_ALLOWAS_IN,
+               .handlers[0] = TEST_HANDLER(allowas_in),
        },
        {
                .cmd = "allowas-in origin",
@@ -196,6 +485,25 @@ static struct test_peer_attr test_peer_attrs[] = {
                .peer_cmd = "default-originate route-map RM-PEER",
                .group_cmd = "default-originate route-map RM-GROUP",
                .u.flag = PEER_FLAG_DEFAULT_ORIGINATE,
+               .handlers[0] = TEST_HANDLER(default_originate_route_map),
+       },
+       {
+               .cmd = "distribute-list",
+               .peer_cmd = "distribute-list DL-PEER in",
+               .group_cmd = "distribute-list DL-GROUP in",
+               .type = PEER_AT_AF_FILTER,
+               .u.filter.flag = PEER_FT_DISTRIBUTE_LIST,
+               .u.filter.direct = FILTER_IN,
+               .handlers[0] = TEST_HANDLER(distribute_list),
+       },
+       {
+               .cmd = "distribute-list",
+               .peer_cmd = "distribute-list DL-PEER out",
+               .group_cmd = "distribute-list DL-GROUP out",
+               .type = PEER_AT_AF_FILTER,
+               .u.filter.flag = PEER_FT_DISTRIBUTE_LIST,
+               .u.filter.direct = FILTER_OUT,
+               .handlers[0] = TEST_HANDLER(distribute_list),
        },
        {
                .cmd = "filter-list",
@@ -204,6 +512,7 @@ static struct test_peer_attr test_peer_attrs[] = {
                .type = PEER_AT_AF_FILTER,
                .u.filter.flag = PEER_FT_FILTER_LIST,
                .u.filter.direct = FILTER_IN,
+               .handlers[0] = TEST_HANDLER(filter_list),
        },
        {
                .cmd = "filter-list",
@@ -212,36 +521,46 @@ static struct test_peer_attr test_peer_attrs[] = {
                .type = PEER_AT_AF_FILTER,
                .u.filter.flag = PEER_FT_FILTER_LIST,
                .u.filter.direct = FILTER_OUT,
+               .handlers[0] = TEST_HANDLER(filter_list),
        },
        {
                .cmd = "maximum-prefix",
                .peer_cmd = "maximum-prefix 10",
                .group_cmd = "maximum-prefix 20",
                .u.flag = PEER_FLAG_MAX_PREFIX,
+               .handlers[0] = TEST_HANDLER(maximum_prefix),
        },
        {
                .cmd = "maximum-prefix",
                .peer_cmd = "maximum-prefix 10 restart 100",
                .group_cmd = "maximum-prefix 20 restart 200",
                .u.flag = PEER_FLAG_MAX_PREFIX,
+               .handlers[0] = TEST_HANDLER(maximum_prefix),
+               .handlers[1] = TEST_HANDLER(maximum_prefix_restart),
        },
        {
                .cmd = "maximum-prefix",
                .peer_cmd = "maximum-prefix 10 1 restart 100",
                .group_cmd = "maximum-prefix 20 2 restart 200",
                .u.flag = PEER_FLAG_MAX_PREFIX,
+               .handlers[0] = TEST_HANDLER(maximum_prefix),
+               .handlers[1] = TEST_HANDLER(maximum_prefix_threshold),
+               .handlers[2] = TEST_HANDLER(maximum_prefix_restart),
        },
        {
                .cmd = "maximum-prefix",
                .peer_cmd = "maximum-prefix 10 warning-only",
                .group_cmd = "maximum-prefix 20 warning-only",
                .u.flag = PEER_FLAG_MAX_PREFIX | PEER_FLAG_MAX_PREFIX_WARNING,
+               .handlers[0] = TEST_HANDLER(maximum_prefix),
        },
        {
                .cmd = "maximum-prefix",
                .peer_cmd = "maximum-prefix 10 1 warning-only",
                .group_cmd = "maximum-prefix 20 2 warning-only",
                .u.flag = PEER_FLAG_MAX_PREFIX | PEER_FLAG_MAX_PREFIX_WARNING,
+               .handlers[0] = TEST_HANDLER(maximum_prefix),
+               .handlers[1] = TEST_HANDLER(maximum_prefix_threshold),
        },
        {
                .cmd = "next-hop-self",
@@ -258,6 +577,7 @@ static struct test_peer_attr test_peer_attrs[] = {
                .type = PEER_AT_AF_FILTER,
                .u.filter.flag = PEER_FT_PREFIX_LIST,
                .u.filter.direct = FILTER_IN,
+               .handlers[0] = TEST_HANDLER(prefix_list),
        },
        {
                .cmd = "prefix-list",
@@ -266,6 +586,7 @@ static struct test_peer_attr test_peer_attrs[] = {
                .type = PEER_AT_AF_FILTER,
                .u.filter.flag = PEER_FT_PREFIX_LIST,
                .u.filter.direct = FILTER_OUT,
+               .handlers[0] = TEST_HANDLER(prefix_list),
        },
        {
                .cmd = "remove-private-AS",
@@ -292,6 +613,7 @@ static struct test_peer_attr test_peer_attrs[] = {
                .type = PEER_AT_AF_FILTER,
                .u.filter.flag = PEER_FT_ROUTE_MAP,
                .u.filter.direct = FILTER_IN,
+               .handlers[0] = TEST_HANDLER(route_map),
        },
        {
                .cmd = "route-map",
@@ -300,11 +622,13 @@ static struct test_peer_attr test_peer_attrs[] = {
                .type = PEER_AT_AF_FILTER,
                .u.filter.flag = PEER_FT_ROUTE_MAP,
                .u.filter.direct = FILTER_OUT,
+               .handlers[0] = TEST_HANDLER(route_map),
        },
        {
                .cmd = "route-reflector-client",
                .u.flag = PEER_FLAG_REFLECTOR_CLIENT,
                .o.use_ibgp = true,
+               .o.skip_xfer_cases = true,
        },
        {
                .cmd = "route-server-client",
@@ -313,17 +637,20 @@ static struct test_peer_attr test_peer_attrs[] = {
        {
                .cmd = "send-community",
                .u.flag = PEER_FLAG_SEND_COMMUNITY,
-               .o.invert = true,
+               .o.invert_peer = true,
+               .o.invert_group = true,
        },
        {
                .cmd = "send-community extended",
                .u.flag = PEER_FLAG_SEND_EXT_COMMUNITY,
-               .o.invert = true,
+               .o.invert_peer = true,
+               .o.invert_group = true,
        },
        {
                .cmd = "send-community large",
                .u.flag = PEER_FLAG_SEND_LARGE_COMMUNITY,
-               .o.invert = true,
+               .o.invert_peer = true,
+               .o.invert_group = true,
        },
        {
                .cmd = "soft-reconfiguration inbound",
@@ -336,55 +663,19 @@ static struct test_peer_attr test_peer_attrs[] = {
                .type = PEER_AT_AF_FILTER,
                .u.filter.flag = PEER_FT_UNSUPPRESS_MAP,
                .u.filter.direct = 0,
+               .handlers[0] = TEST_HANDLER(unsuppress_map),
        },
        {
                .cmd = "weight",
                .peer_cmd = "weight 100",
                .group_cmd = "weight 200",
                .u.flag = PEER_FLAG_WEIGHT,
+               .handlers[0] = TEST_HANDLER(weight),
        },
        {NULL}
 };
 /* clang-format on */
 
-static char *str_vprintf(const char *fmt, va_list ap)
-{
-       int ret;
-       int buf_size = 0;
-       char *buf = NULL;
-       va_list apc;
-
-       while (1) {
-               va_copy(apc, ap);
-               ret = vsnprintf(buf, buf_size, fmt, apc);
-               va_end(apc);
-
-               if (ret >= 0 && ret < buf_size)
-                       break;
-
-               if (ret >= 0)
-                       buf_size = ret + 1;
-               else
-                       buf_size *= 2;
-
-               buf = XREALLOC(MTYPE_TMP, buf, buf_size);
-       }
-
-       return buf;
-}
-
-static char *str_printf(const char *fmt, ...)
-{
-       char *buf;
-       va_list ap;
-
-       va_start(ap, fmt);
-       buf = str_vprintf(fmt, ap);
-       va_end(ap);
-
-       return buf;
-}
-
 static const char *str_from_afi(afi_t afi)
 {
        switch (afi) {
@@ -409,6 +700,42 @@ static const char *str_from_safi(safi_t safi)
        }
 }
 
+static const char *str_from_attr_type(enum test_peer_attr_type at)
+{
+       switch (at) {
+       case PEER_AT_GLOBAL_FLAG:
+               return "peer-flag";
+       case PEER_AT_AF_FLAG:
+               return "af-flag";
+       case PEER_AT_AF_FILTER:
+               return "af-filter";
+       case PEER_AT_GLOBAL_CUSTOM:
+       case PEER_AT_AF_CUSTOM:
+               return "custom";
+       default:
+               return NULL;
+       }
+}
+
+static bool is_attr_type_global(enum test_peer_attr_type at)
+{
+       return at == PEER_AT_GLOBAL_FLAG || at == PEER_AT_GLOBAL_CUSTOM;
+}
+
+static void test_log(struct test *test, const char *fmt, ...)
+{
+       va_list ap;
+
+       /* Skip logging if test instance has previously failed. */
+       if (test->state != TEST_SUCCESS)
+               return;
+
+       /* Store formatted log message. */
+       va_start(ap, fmt);
+       listnode_add(test->log, str_vprintf(fmt, ap));
+       va_end(ap);
+}
+
 static void test_execute(struct test *test, const char *fmt, ...)
 {
        int ret;
@@ -520,19 +847,17 @@ static void test_config_absent(struct test *test, const char *fmt, ...)
        va_end(ap);
 }
 
-static struct test *test_new(const char *desc, bool use_ibgp)
+static void test_initialize(struct test *test)
 {
-       struct test *test;
        union sockunion su;
 
-       test = XCALLOC(MTYPE_TMP, sizeof(struct test));
-       test->state = TEST_SUCCESS;
-       test->desc = XSTRDUP(MTYPE_TMP, desc);
-       test->log = list_new();
+       /* Skip execution if test instance has previously failed. */
+       if (test->state != TEST_SUCCESS)
+               return;
 
-       test->vty = vty_new();
-       test->vty->type = VTY_TERM;
-       test->vty->node = CONFIG_NODE;
+       /* Log message about (re)-initialization */
+       test_log(test, "prepare: %sinitialize bgp test environment",
+                test->bgp ? "re-" : "");
 
        /* Attempt gracefully to purge previous BGP configuration. */
        test_execute(test, "no router bgp");
@@ -542,10 +867,18 @@ static struct test *test_new(const char *desc, bool use_ibgp)
        test_execute(test, "router bgp %d", cfg.local_asn);
        test_execute(test, "no bgp default ipv4-unicast");
        test_execute(test, "neighbor %s peer-group", cfg.peer_group);
-       test_execute(test, "neighbor %s remote-as %d", cfg.peer_address,
-                    use_ibgp ? cfg.local_asn : cfg.peer_asn);
+       if (test->o.use_iface_peer) {
+               test_execute(test, "neighbor %s interface", cfg.peer_interface);
+               test_execute(test, "neighbor %s remote-as %d",
+                            cfg.peer_interface,
+                            test->o.use_ibgp ? cfg.local_asn : cfg.peer_asn);
+       } else {
+               test_execute(test, "neighbor %s remote-as %d", cfg.peer_address,
+                            test->o.use_ibgp ? cfg.local_asn : cfg.peer_asn);
+       }
+
        if (test->state != TEST_SUCCESS)
-               return test;
+               return;
 
        /* Fetch default BGP instance. */
        test->bgp = bgp_get_default();
@@ -553,18 +886,23 @@ static struct test *test_new(const char *desc, bool use_ibgp)
                test->state = TEST_INTERNAL_ERROR;
                test->error =
                        str_printf("could not retrieve default bgp instance");
-               return test;
+               return;
        }
 
        /* Fetch peer instance. */
-       str2sockunion(cfg.peer_address, &su);
-       test->peer = peer_lookup(test->bgp, &su);
+       if (test->o.use_iface_peer) {
+               test->peer =
+                       peer_lookup_by_conf_if(test->bgp, cfg.peer_interface);
+       } else {
+               str2sockunion(cfg.peer_address, &su);
+               test->peer = peer_lookup(test->bgp, &su);
+       }
        if (!test->peer) {
                test->state = TEST_INTERNAL_ERROR;
                test->error = str_printf(
                        "could not retrieve instance of bgp peer [%s]",
                        cfg.peer_address);
-               return test;
+               return;
        }
 
        /* Fetch peer-group instance. */
@@ -574,25 +912,30 @@ static struct test *test_new(const char *desc, bool use_ibgp)
                test->error = str_printf(
                        "could not retrieve instance of bgp peer-group [%s]",
                        cfg.peer_group);
-               return test;
+               return;
        }
+}
 
-       return test;
-};
-
-static void test_log(struct test *test, const char *fmt, ...)
+static struct test *test_new(const char *desc, bool use_ibgp,
+                            bool use_iface_peer)
 {
-       va_list ap;
+       struct test *test;
 
-       /* Skip logging if test instance has previously failed. */
-       if (test->state != TEST_SUCCESS)
-               return;
+       test = XCALLOC(MTYPE_TMP, sizeof(struct test));
+       test->state = TEST_SUCCESS;
+       test->desc = XSTRDUP(MTYPE_TMP, desc);
+       test->log = list_new();
+       test->o.use_ibgp = use_ibgp;
+       test->o.use_iface_peer = use_iface_peer;
 
-       /* Store formatted log message. */
-       va_start(ap, fmt);
-       listnode_add(test->log, str_vprintf(fmt, ap));
-       va_end(ap);
-}
+       test->vty = vty_new();
+       test->vty->type = VTY_TERM;
+       test->vty->node = CONFIG_NODE;
+
+       test_initialize(test);
+
+       return test;
+};
 
 static void test_finish(struct test *test)
 {
@@ -631,23 +974,37 @@ static void test_finish(struct test *test)
        XFREE(MTYPE_TMP, test);
 }
 
-static void test_af_flags(struct test *test, struct peer *peer,
-                         struct test_peer_attr *attr, bool exp_val,
-                         bool exp_ovrd)
+static void test_peer_flags(struct test *test, struct test_peer_attr *pa,
+                           struct peer *peer, bool exp_val, bool exp_ovrd)
 {
        bool exp_inv, cur_val, cur_ovrd, cur_inv;
 
-       /* Flip expected values for inverted flags. */
-       exp_inv = attr->o.invert;
+       /* Skip execution if test instance has previously failed. */
+       if (test->state != TEST_SUCCESS)
+               return;
+
+       /* Detect if flag is meant to be inverted. */
+       if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+               exp_inv = pa->o.invert_group;
+       else
+               exp_inv = pa->o.invert_peer;
+
+       /* Flip expected value if flag is inverted. */
        exp_val ^= exp_inv;
 
        /* Fetch current state of value, override and invert flags. */
-       cur_val = !!CHECK_FLAG(peer->af_flags[attr->afi][attr->safi],
-                              attr->u.flag);
-       cur_ovrd = !!CHECK_FLAG(peer->af_flags_override[attr->afi][attr->safi],
-                               attr->u.flag);
-       cur_inv = !!CHECK_FLAG(peer->af_flags_invert[attr->afi][attr->safi],
-                              attr->u.flag);
+       if (pa->type == PEER_AT_GLOBAL_FLAG) {
+               cur_val = !!CHECK_FLAG(peer->flags, pa->u.flag);
+               cur_ovrd = !!CHECK_FLAG(peer->flags_override, pa->u.flag);
+               cur_inv = !!CHECK_FLAG(peer->flags_invert, pa->u.flag);
+       } else /* if (pa->type == PEER_AT_AF_FLAG) */ {
+               cur_val = !!CHECK_FLAG(peer->af_flags[pa->afi][pa->safi],
+                                      pa->u.flag);
+               cur_ovrd = !!CHECK_FLAG(
+                       peer->af_flags_override[pa->afi][pa->safi], pa->u.flag);
+               cur_inv = !!CHECK_FLAG(peer->af_flags_invert[pa->afi][pa->safi],
+                                      pa->u.flag);
+       }
 
        /* Assert expected flag states. */
        TEST_ASSERT_EQ(test, cur_val, exp_val);
@@ -655,42 +1012,44 @@ static void test_af_flags(struct test *test, struct peer *peer,
        TEST_ASSERT_EQ(test, cur_inv, exp_inv);
 }
 
-static void test_af_filter(struct test *test, struct peer *peer,
-                          struct test_peer_attr *attr, bool exp_state,
-                          bool exp_ovrd)
+static void test_af_filter(struct test *test, struct test_peer_attr *pa,
+                          struct peer *peer, bool exp_state, bool exp_ovrd)
 {
        bool cur_ovrd;
        struct bgp_filter *filter;
 
+       /* Skip execution if test instance has previously failed. */
+       if (test->state != TEST_SUCCESS)
+               return;
+
        /* Fetch and assert current state of override flag. */
-       cur_ovrd = !!CHECK_FLAG(peer->filter_override[attr->afi][attr->safi]
-                                                    [attr->u.filter.direct],
-                               attr->u.filter.flag);
+       cur_ovrd = !!CHECK_FLAG(
+               peer->filter_override[pa->afi][pa->safi][pa->u.filter.direct],
+               pa->u.filter.flag);
 
        TEST_ASSERT_EQ(test, cur_ovrd, exp_ovrd);
 
        /* Assert that map/list matches expected state (set/unset). */
-       filter = &peer->filter[attr->afi][attr->safi];
+       filter = &peer->filter[pa->afi][pa->safi];
 
-       switch (attr->u.filter.flag) {
+       switch (pa->u.filter.flag) {
        case PEER_FT_DISTRIBUTE_LIST:
                TEST_ASSERT_EQ(test,
-                              !!(filter->dlist[attr->u.filter.direct].name),
+                              !!(filter->dlist[pa->u.filter.direct].name),
                               exp_state);
                break;
        case PEER_FT_FILTER_LIST:
                TEST_ASSERT_EQ(test,
-                              !!(filter->aslist[attr->u.filter.direct].name),
+                              !!(filter->aslist[pa->u.filter.direct].name),
                               exp_state);
                break;
        case PEER_FT_PREFIX_LIST:
                TEST_ASSERT_EQ(test,
-                              !!(filter->plist[attr->u.filter.direct].name),
+                              !!(filter->plist[pa->u.filter.direct].name),
                               exp_state);
                break;
        case PEER_FT_ROUTE_MAP:
-               TEST_ASSERT_EQ(test,
-                              !!(filter->map[attr->u.filter.direct].name),
+               TEST_ASSERT_EQ(test, !!(filter->map[pa->u.filter.direct].name),
                               exp_state);
                break;
        case PEER_FT_UNSUPPRESS_MAP:
@@ -699,173 +1058,322 @@ static void test_af_filter(struct test *test, struct peer *peer,
        }
 }
 
+static void test_custom(struct test *test, struct test_peer_attr *pa,
+                       struct peer *peer, struct peer *group, bool peer_set,
+                       bool group_set)
+{
+       int i;
+       char *handler_error;
+
+       for (i = 0; i < TEST_HANDLER_MAX; i++) {
+               /* Skip execution if test instance has previously failed. */
+               if (test->state != TEST_SUCCESS)
+                       return;
+
+               /* Skip further execution if handler is undefined. */
+               if (!pa->handlers[i])
+                       return;
+
+               /* Execute custom handler. */
+               pa->handlers[i](test, pa, peer, group, peer_set, group_set);
+               if (test->state != TEST_SUCCESS) {
+                       test->state = TEST_CUSTOM_ERROR;
+                       handler_error = test->error;
+                       test->error = str_printf("custom handler failed: %s",
+                                                handler_error);
+                       XFREE(MTYPE_TMP, handler_error);
+               }
+       }
+}
+
+
+static void test_process(struct test *test, struct test_peer_attr *pa,
+                        struct peer *peer, struct peer *group, bool peer_set,
+                        bool group_set)
+{
+       switch (pa->type) {
+       case PEER_AT_GLOBAL_FLAG:
+       case PEER_AT_AF_FLAG:
+               test_peer_flags(
+                       test, pa, peer,
+                       peer_set || (peer_group_active(peer) && group_set),
+                       peer_set);
+               test_peer_flags(test, pa, group, group_set, false);
+               break;
+
+       case PEER_AT_AF_FILTER:
+               test_af_filter(
+                       test, pa, peer,
+                       peer_set || (peer_group_active(peer) && group_set),
+                       peer_set);
+               test_af_filter(test, pa, group, group_set, false);
+               break;
+
+       case PEER_AT_GLOBAL_CUSTOM:
+       case PEER_AT_AF_CUSTOM:
+               /*
+                * Do nothing here - a custom handler can be executed, but this
+                * is not required. This will allow defining peer attributes
+                * which shall not be checked for flag/filter/other internal
+                * states.
+                */
+               break;
+
+       default:
+               test->state = TEST_INTERNAL_ERROR;
+               test->error =
+                       str_printf("invalid attribute type: %d", pa->type);
+               break;
+       }
+
+       /* Attempt to call a custom handler if set for further processing. */
+       test_custom(test, pa, peer, group, peer_set, group_set);
+}
+
 static void test_peer_attr(struct test *test, struct test_peer_attr *pa)
 {
        int tc = 1;
        const char *type;
-       const char *ec = pa->o.invert ? "no " : "";
-       const char *dc = pa->o.invert ? "" : "no ";
+       const char *ecp = pa->o.invert_peer ? "no " : "";
+       const char *dcp = pa->o.invert_peer ? "" : "no ";
+       const char *ecg = pa->o.invert_group ? "no " : "";
+       const char *dcg = pa->o.invert_group ? "" : "no ";
        const char *peer_cmd = pa->peer_cmd ?: pa->cmd;
        const char *group_cmd = pa->group_cmd ?: pa->cmd;
        struct peer *p = test->peer;
        struct peer_group *g = test->group;
 
-       if (pa->type == PEER_AT_AF_FLAG)
-               type = "af-flag";
-       else /* if (pa->type == PEER_AT_AF_FILTER) */
-               type = "af-filter";
+       /* Determine type and if test is address-family relevant */
+       type = str_from_attr_type(pa->type);
+       if (!type) {
+               test->state = TEST_INTERNAL_ERROR;
+               test->error =
+                       str_printf("invalid attribute type: %d", pa->type);
+               return;
+       }
 
-       /* Test Case: Switch active address-family. */
-       if (pa->type == PEER_AT_AF_FLAG || pa->type == PEER_AT_AF_FILTER) {
+       /*
+        * =====================================================================
+        * Test Case Suite 1: Config persistence after adding peer to group
+        *
+        * Example: If a peer attribute has value [1] and a group attribute has
+        * value [2], the peer attribute value should be persisted when the peer
+        * gets added to the peer-group.
+        *
+        * This test suite is meant to test the group2peer functions which can
+        * be found inside bgpd/bgpd.c, which are related to initial peer-group
+        * inheritance.
+        * =====================================================================
+        */
+
+       /* Test Preparation: Switch and activate address-family. */
+       if (!is_attr_type_global(pa->type)) {
                test_log(test, "prepare: switch address-family to [%s]",
                         afi_safi_print(pa->afi, pa->safi));
                test_execute(test, "address-family %s %s",
                             str_from_afi(pa->afi), str_from_safi(pa->safi));
+               test_execute(test, "neighbor %s activate", g->name);
+               test_execute(test, "neighbor %s activate", p->host);
        }
 
+       /* Skip peer-group to peer transfer test cases if requested. */
+       if (pa->o.skip_xfer_cases && test->state == TEST_SUCCESS)
+               test->state = TEST_SKIPPING;
+
        /* Test Case: Set flag on BGP peer. */
        test_log(test, "case %02d: set %s [%s] on [%s]", tc++, type, peer_cmd,
                 p->host);
-       test_execute(test, "%sneighbor %s %s", ec, p->host, peer_cmd);
-       test_config_present(test, "%sneighbor %s %s", ec, p->host, peer_cmd);
+       test_execute(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
+       test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
        test_config_absent(test, "neighbor %s %s", g->name, pa->cmd);
-       if (pa->type == PEER_AT_AF_FLAG) {
-               test_af_flags(test, p, pa, true, true);
-               test_af_flags(test, g->conf, pa, false, false);
-       } else if (pa->type == PEER_AT_AF_FILTER) {
-               test_af_filter(test, p, pa, true, true);
-               test_af_filter(test, g->conf, pa, false, false);
-       }
+       test_process(test, pa, p, g->conf, true, false);
+
+       /* Test Case: Set flag on BGP peer-group. */
+       test_log(test, "case %02d: set %s [%s] on [%s]", tc++, type, group_cmd,
+                g->name);
+       test_execute(test, "%sneighbor %s %s", ecg, g->name, group_cmd);
+       test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
+       test_config_present(test, "%sneighbor %s %s", ecg, g->name, group_cmd);
+       test_process(test, pa, p, g->conf, true, true);
 
        /* Test Case: Add BGP peer to peer-group. */
        test_log(test, "case %02d: add peer [%s] to group [%s]", tc++, p->host,
                 g->name);
        test_execute(test, "neighbor %s peer-group %s", p->host, g->name);
-       test_config_present(test, "neighbor %s peer-group %s", p->host,
-                           g->name);
-       test_config_present(test, "%sneighbor %s %s", ec, p->host, peer_cmd);
+       test_config_present(test, "neighbor %s %speer-group %s", p->host,
+                           p->conf_if ? "interface " : "", g->name);
+       test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
+       test_config_present(test, "%sneighbor %s %s", ecg, g->name, group_cmd);
+       test_process(test, pa, p, g->conf, true, true);
+
+       /* Test Case: Unset flag on BGP peer-group. */
+       test_log(test, "case %02d: unset %s [%s] on [%s]", tc++, type,
+                group_cmd, g->name);
+       test_execute(test, "%sneighbor %s %s", dcg, g->name, group_cmd);
+       test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
        test_config_absent(test, "neighbor %s %s", g->name, pa->cmd);
-       if (pa->type == PEER_AT_AF_FLAG) {
-               test_af_flags(test, p, pa, true, true);
-               test_af_flags(test, g->conf, pa, false, false);
-       } else if (pa->type == PEER_AT_AF_FILTER) {
-               test_af_filter(test, p, pa, true, true);
-               test_af_filter(test, g->conf, pa, false, false);
+       test_process(test, pa, p, g->conf, true, false);
+
+       /*
+        * =====================================================================
+        * Test Case Suite 2: Config inheritance after adding peer to group
+        *
+        * Example: If a peer attribute has not been set and a group attribute
+        * has a value of [2], the group attribute should be inherited to the
+        * peer without flagging the newly set value as overridden.
+        *
+        * This test suite is meant to test the group2peer functions which can
+        * be found inside bgpd/bgpd.c, which are related to initial peer-group
+        * inheritance.
+        * =====================================================================
+        */
+
+       /* Test Preparation: Re-initialize test environment. */
+       test_initialize(test);
+       p = test->peer;
+       g = test->group;
+
+       /* Test Preparation: Switch and activate address-family. */
+       if (!is_attr_type_global(pa->type)) {
+               test_log(test, "prepare: switch address-family to [%s]",
+                        afi_safi_print(pa->afi, pa->safi));
+               test_execute(test, "address-family %s %s",
+                            str_from_afi(pa->afi), str_from_safi(pa->safi));
+               test_execute(test, "neighbor %s activate", g->name);
+               test_execute(test, "neighbor %s activate", p->host);
+       }
+
+       /* Test Case: Set flag on BGP peer-group. */
+       test_log(test, "case %02d: set %s [%s] on [%s]", tc++, type, group_cmd,
+                g->name);
+       test_execute(test, "%sneighbor %s %s", ecg, g->name, group_cmd);
+       test_config_absent(test, "neighbor %s %s", p->host, pa->cmd);
+       test_config_present(test, "%sneighbor %s %s", ecg, g->name, group_cmd);
+       test_process(test, pa, p, g->conf, false, true);
+
+       /* Test Case: Add BGP peer to peer-group. */
+       test_log(test, "case %02d: add peer [%s] to group [%s]", tc++, p->host,
+                g->name);
+       test_execute(test, "neighbor %s peer-group %s", p->host, g->name);
+       test_config_present(test, "neighbor %s %speer-group %s", p->host,
+                           p->conf_if ? "interface " : "", g->name);
+       test_config_absent(test, "neighbor %s %s", p->host, pa->cmd);
+       test_config_present(test, "%sneighbor %s %s", ecg, g->name, group_cmd);
+       test_process(test, pa, p, g->conf, false, true);
+
+       /* Stop skipping test cases if previously enabled. */
+       if (pa->o.skip_xfer_cases && test->state == TEST_SKIPPING)
+               test->state = TEST_SUCCESS;
+
+       /*
+        * =====================================================================
+        * Test Case Suite 3: Miscellaneous flag checks
+        *
+        * This test suite does not focus on initial peer-group inheritance and
+        * instead executes various different commands to set/unset attributes
+        * on both peer- and group-level. These checks should always be executed
+        * and must pass.
+        * =====================================================================
+        */
+
+       /* Test Preparation: Re-initialize test environment. */
+       test_initialize(test);
+       p = test->peer;
+       g = test->group;
+
+       /* Test Preparation: Switch and activate address-family. */
+       if (!is_attr_type_global(pa->type)) {
+               test_log(test, "prepare: switch address-family to [%s]",
+                        afi_safi_print(pa->afi, pa->safi));
+               test_execute(test, "address-family %s %s",
+                            str_from_afi(pa->afi), str_from_safi(pa->safi));
+               test_execute(test, "neighbor %s activate", g->name);
+               test_execute(test, "neighbor %s activate", p->host);
        }
 
+       /* Test Case: Set flag on BGP peer. */
+       test_log(test, "case %02d: set %s [%s] on [%s]", tc++, type, peer_cmd,
+                p->host);
+       test_execute(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
+       test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
+       test_config_absent(test, "neighbor %s %s", g->name, pa->cmd);
+       test_process(test, pa, p, g->conf, true, false);
+
+       /* Test Case: Add BGP peer to peer-group. */
+       test_log(test, "case %02d: add peer [%s] to group [%s]", tc++, p->host,
+                g->name);
+       test_execute(test, "neighbor %s peer-group %s", p->host, g->name);
+       test_config_present(test, "neighbor %s %speer-group %s", p->host,
+                           p->conf_if ? "interface " : "", g->name);
+       test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
+       test_config_absent(test, "neighbor %s %s", g->name, pa->cmd);
+       test_process(test, pa, p, g->conf, true, false);
+
        /* Test Case: Re-add BGP peer to peer-group. */
        test_log(test, "case %02d: re-add peer [%s] to group [%s]", tc++,
                 p->host, g->name);
        test_execute(test, "neighbor %s peer-group %s", p->host, g->name);
-       test_config_present(test, "neighbor %s peer-group %s", p->host,
-                           g->name);
-       test_config_present(test, "%sneighbor %s %s", ec, p->host, peer_cmd);
+       test_config_present(test, "neighbor %s %speer-group %s", p->host,
+                           p->conf_if ? "interface " : "", g->name);
+       test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
        test_config_absent(test, "neighbor %s %s", g->name, pa->cmd);
-       if (pa->type == PEER_AT_AF_FLAG) {
-               test_af_flags(test, p, pa, true, true);
-               test_af_flags(test, g->conf, pa, false, false);
-       } else if (pa->type == PEER_AT_AF_FILTER) {
-               test_af_filter(test, p, pa, true, true);
-               test_af_filter(test, g->conf, pa, false, false);
-       }
+       test_process(test, pa, p, g->conf, true, false);
 
        /* Test Case: Set flag on BGP peer-group. */
        test_log(test, "case %02d: set %s [%s] on [%s]", tc++, type, group_cmd,
                 g->name);
-       test_execute(test, "%sneighbor %s %s", ec, g->name, group_cmd);
-       test_config_present(test, "%sneighbor %s %s", ec, p->host, peer_cmd);
-       test_config_present(test, "%sneighbor %s %s", ec, g->name, group_cmd);
-       if (pa->type == PEER_AT_AF_FLAG) {
-               test_af_flags(test, p, pa, true, true);
-               test_af_flags(test, g->conf, pa, true, false);
-       } else if (pa->type == PEER_AT_AF_FILTER) {
-               test_af_filter(test, p, pa, true, true);
-               test_af_filter(test, g->conf, pa, true, false);
-       }
+       test_execute(test, "%sneighbor %s %s", ecg, g->name, group_cmd);
+       test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
+       test_config_present(test, "%sneighbor %s %s", ecg, g->name, group_cmd);
+       test_process(test, pa, p, g->conf, true, true);
 
        /* Test Case: Unset flag on BGP peer-group. */
        test_log(test, "case %02d: unset %s [%s] on [%s]", tc++, type,
                 group_cmd, g->name);
-       test_execute(test, "%sneighbor %s %s", dc, g->name, group_cmd);
-       test_config_present(test, "%sneighbor %s %s", ec, p->host, peer_cmd);
+       test_execute(test, "%sneighbor %s %s", dcg, g->name, group_cmd);
+       test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
        test_config_absent(test, "neighbor %s %s", g->name, pa->cmd);
-       if (pa->type == PEER_AT_AF_FLAG) {
-               test_af_flags(test, p, pa, true, true);
-               test_af_flags(test, g->conf, pa, false, false);
-       } else if (pa->type == PEER_AT_AF_FILTER) {
-               test_af_filter(test, p, pa, true, true);
-               test_af_filter(test, g->conf, pa, false, false);
-       }
+       test_process(test, pa, p, g->conf, true, false);
 
        /* Test Case: Set flag on BGP peer-group. */
        test_log(test, "case %02d: set %s [%s] on [%s]", tc++, type, group_cmd,
                 g->name);
-       test_execute(test, "%sneighbor %s %s", ec, g->name, group_cmd);
-       test_config_present(test, "%sneighbor %s %s", ec, p->host, peer_cmd);
-       test_config_present(test, "%sneighbor %s %s", ec, g->name, group_cmd);
-       if (pa->type == PEER_AT_AF_FLAG) {
-               test_af_flags(test, p, pa, true, true);
-               test_af_flags(test, g->conf, pa, true, false);
-       } else if (pa->type == PEER_AT_AF_FILTER) {
-               test_af_filter(test, p, pa, true, true);
-               test_af_filter(test, g->conf, pa, true, false);
-       }
+       test_execute(test, "%sneighbor %s %s", ecg, g->name, group_cmd);
+       test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
+       test_config_present(test, "%sneighbor %s %s", ecg, g->name, group_cmd);
+       test_process(test, pa, p, g->conf, true, true);
 
        /* Test Case: Re-set flag on BGP peer. */
        test_log(test, "case %02d: re-set %s [%s] on [%s]", tc++, type,
                 peer_cmd, p->host);
-       test_execute(test, "%sneighbor %s %s", ec, p->host, peer_cmd);
-       test_config_present(test, "%sneighbor %s %s", ec, p->host, peer_cmd);
-       test_config_present(test, "%sneighbor %s %s", ec, g->name, group_cmd);
-       if (pa->type == PEER_AT_AF_FLAG) {
-               test_af_flags(test, p, pa, true, true);
-               test_af_flags(test, g->conf, pa, true, false);
-       } else if (pa->type == PEER_AT_AF_FILTER) {
-               test_af_filter(test, p, pa, true, true);
-               test_af_filter(test, g->conf, pa, true, false);
-       }
+       test_execute(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
+       test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
+       test_config_present(test, "%sneighbor %s %s", ecg, g->name, group_cmd);
+       test_process(test, pa, p, g->conf, true, true);
 
        /* Test Case: Unset flag on BGP peer. */
        test_log(test, "case %02d: unset %s [%s] on [%s]", tc++, type, peer_cmd,
                 p->host);
-       test_execute(test, "%sneighbor %s %s", dc, p->host, peer_cmd);
+       test_execute(test, "%sneighbor %s %s", dcp, p->host, peer_cmd);
        test_config_absent(test, "neighbor %s %s", p->host, pa->cmd);
-       test_config_present(test, "%sneighbor %s %s", ec, g->name, group_cmd);
-       if (pa->type == PEER_AT_AF_FLAG) {
-               test_af_flags(test, p, pa, true, false);
-               test_af_flags(test, g->conf, pa, true, false);
-       } else if (pa->type == PEER_AT_AF_FILTER) {
-               test_af_filter(test, p, pa, true, false);
-               test_af_filter(test, g->conf, pa, true, false);
-       }
+       test_config_present(test, "%sneighbor %s %s", ecg, g->name, group_cmd);
+       test_process(test, pa, p, g->conf, false, true);
 
        /* Test Case: Unset flag on BGP peer-group. */
        test_log(test, "case %02d: unset %s [%s] on [%s]", tc++, type,
                 group_cmd, g->name);
-       test_execute(test, "%sneighbor %s %s", dc, g->name, group_cmd);
+       test_execute(test, "%sneighbor %s %s", dcg, g->name, group_cmd);
        test_config_absent(test, "neighbor %s %s", p->host, pa->cmd);
        test_config_absent(test, "neighbor %s %s", g->name, pa->cmd);
-       if (pa->type == PEER_AT_AF_FLAG) {
-               test_af_flags(test, p, pa, false, false);
-               test_af_flags(test, g->conf, pa, false, false);
-       } else if (pa->type == PEER_AT_AF_FILTER) {
-               test_af_filter(test, p, pa, false, false);
-               test_af_filter(test, g->conf, pa, false, false);
-       }
+       test_process(test, pa, p, g->conf, false, false);
 
        /* Test Case: Set flag on BGP peer. */
        test_log(test, "case %02d: set %s [%s] on [%s]", tc++, type, peer_cmd,
                 p->host);
-       test_execute(test, "%sneighbor %s %s", ec, p->host, peer_cmd);
-       test_config_present(test, "%sneighbor %s %s", ec, p->host, peer_cmd);
+       test_execute(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
+       test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
        test_config_absent(test, "neighbor %s %s", g->name, pa->cmd);
-       if (pa->type == PEER_AT_AF_FLAG) {
-               test_af_flags(test, p, pa, true, true);
-               test_af_flags(test, g->conf, pa, false, false);
-       } else if (pa->type == PEER_AT_AF_FILTER) {
-               test_af_filter(test, p, pa, true, true);
-               test_af_filter(test, g->conf, pa, false, false);
-       }
+       test_process(test, pa, p, g->conf, true, false);
 }
 
 static void bgp_startup(void)
@@ -941,7 +1449,7 @@ int main(void)
                pa = &test_peer_attrs[i++];
 
                /* Just copy the peer attribute structure for global flags. */
-               if (pa->type == PEER_AT_GLOBAL_FLAG) {
+               if (is_attr_type_global(pa->type)) {
                        pac = XMALLOC(MTYPE_TMP, sizeof(struct test_peer_attr));
                        memcpy(pac, pa, sizeof(struct test_peer_attr));
                        listnode_add(pa_list, pac);
@@ -980,7 +1488,7 @@ int main(void)
                        desc = str_printf("peer\\%s", pa->cmd);
 
                /* Initialize new test instance. */
-               test = test_new(desc, pa->o.use_ibgp);
+               test = test_new(desc, pa->o.use_ibgp, pa->o.use_iface_peer);
                XFREE(MTYPE_TMP, desc);
 
                /* Execute tests and finish test instance. */
index d93dfc0050b1669782589e662e9e0bbde1d4d779..7a4dd2b04a2e242cd46dd338467508a12f9addc6 100644 (file)
@@ -6,6 +6,26 @@ class TestFlag(frrtest.TestMultiOut):
 # List of tests can be generated by executing:
 # $> ./test_peer_attr 2>&1 | sed -n 's/\\/\\\\/g; s/\S\+ \[test\] \(.\+\)/TestFlag.okfail(\x27\1\x27)/pg'
 #
+TestFlag.okfail('peer\\advertisement-interval')
+TestFlag.okfail('peer\\capability dynamic')
+TestFlag.okfail('peer\\capability extended-nexthop')
+TestFlag.okfail('peer\\capability extended-nexthop')
+TestFlag.okfail('peer\\description')
+TestFlag.okfail('peer\\disable-connected-check')
+TestFlag.okfail('peer\\dont-capability-negotiate')
+TestFlag.okfail('peer\\enforce-first-as')
+TestFlag.okfail('peer\\local-as')
+TestFlag.okfail('peer\\local-as 1 no-prepend')
+TestFlag.okfail('peer\\local-as 1 no-prepend replace-as')
+TestFlag.okfail('peer\\override-capability')
+TestFlag.okfail('peer\\passive')
+TestFlag.okfail('peer\\password')
+TestFlag.okfail('peer\\shutdown')
+TestFlag.okfail('peer\\strict-capability-match')
+TestFlag.okfail('peer\\timers')
+TestFlag.okfail('peer\\timers connect')
+TestFlag.okfail('peer\\update-source')
+TestFlag.okfail('peer\\update-source')
 TestFlag.okfail('peer\\ipv4-unicast\\addpath-tx-all-paths')
 TestFlag.okfail('peer\\ipv4-multicast\\addpath-tx-all-paths')
 TestFlag.okfail('peer\\ipv6-unicast\\addpath-tx-all-paths')
@@ -70,6 +90,14 @@ TestFlag.okfail('peer\\ipv4-unicast\\default-originate route-map')
 TestFlag.okfail('peer\\ipv4-multicast\\default-originate route-map')
 TestFlag.okfail('peer\\ipv6-unicast\\default-originate route-map')
 TestFlag.okfail('peer\\ipv6-multicast\\default-originate route-map')
+TestFlag.okfail('peer\\ipv4-unicast\\distribute-list')
+TestFlag.okfail('peer\\ipv4-multicast\\distribute-list')
+TestFlag.okfail('peer\\ipv6-unicast\\distribute-list')
+TestFlag.okfail('peer\\ipv6-multicast\\distribute-list')
+TestFlag.okfail('peer\\ipv4-unicast\\distribute-list')
+TestFlag.okfail('peer\\ipv4-multicast\\distribute-list')
+TestFlag.okfail('peer\\ipv6-unicast\\distribute-list')
+TestFlag.okfail('peer\\ipv6-multicast\\distribute-list')
 TestFlag.okfail('peer\\ipv4-unicast\\filter-list')
 TestFlag.okfail('peer\\ipv4-multicast\\filter-list')
 TestFlag.okfail('peer\\ipv6-unicast\\filter-list')
index 3972f76763e3bbc4c21722763e0f94ec4df1484c..13d35b0e995862f9bc453cd7c01c9db7c8ab3817 100644 (file)
@@ -506,7 +506,7 @@ int main(int argc, char **argv)
                        printf("verify: lib failed\n");
 
                if (ospfd != lib) {
-                       printf("Mismatch in values at size %u\n"
+                       printf("Mismatch in values at size %d\n"
                               "ospfd: 0x%04x\tc0: %d\tc1: %d\tx: %d\ty: %d\n"
                               "isisd: 0x%04x\tc0: %d\tc1: %d\tx: %d\ty: %d\n"
                               "lib: 0x%04x\n",
index f21f8b793c731012385ea8620dd537ea30acd169..2801c48bc53bacb7d38f48e33712763dc2bc37aa 100644 (file)
@@ -46,7 +46,7 @@ int main(int argc, char **argv)
 
        /* create vertices */
        for (unsigned int i = 0; i < NUMNODES; i++) {
-               snprintf(names[i], sizeof(names[i]), "%d", i);
+               snprintf(names[i], sizeof(names[i]), "%u", i);
                gn[i] = graph_new_node(g, names[i], NULL);
        }
 
index 408f4e058199f3f95a7656d936a2ef42df213b06..04e85435d157b11a0dabf45c423e8d391cbd203e 100644 (file)
@@ -104,9 +104,7 @@ static unsigned int log_key(void *data)
 
 static int log_cmp(const void *a, const void *b)
 {
-       if (a == NULL && b != NULL)
-               return 0;
-       if (b == NULL && a != NULL)
+       if (a == NULL || b == NULL)
                return 0;
 
        return !memcmp(a, b, 2 * sizeof(struct prefix));
index f9a244e2595f942ca808a1eec12cc303f5d61db9..d5f4badc85b5cdeff32971f96695e6e3a3733e10 100644 (file)
@@ -92,9 +92,9 @@ int main(int argc, char **argv)
        t_remove = 1000 * (tv_stop.tv_sec - tv_lap.tv_sec);
        t_remove += (tv_stop.tv_usec - tv_lap.tv_usec) / 1000;
 
-       printf("Scheduling %d random timers took %ld.%03ld seconds.\n",
+       printf("Scheduling %d random timers took %lu.%03lu seconds.\n",
               SCHEDULE_TIMERS, t_schedule / 1000, t_schedule % 1000);
-       printf("Removing %d random timers took %ld.%03ld seconds.\n",
+       printf("Removing %d random timers took %lu.%03lu seconds.\n",
               REMOVE_TIMERS, t_remove / 1000, t_remove % 1000);
        fflush(stdout);
 
index 8c3fe0c3c5743ce963e930deda0bd75bea2c8cc1..de58e0a20e2b75756bc168828a9563872ad033da 100644 (file)
@@ -1024,8 +1024,10 @@ int main(int argc, char **argv)
                        close(i);
                /* change tty */
                fd = open("/dev/tty", O_RDWR);
-               ioctl(fd, TIOCNOTTY, 0);
-               close(fd);
+               if (fd >= 0) {
+                       ioctl(fd, TIOCNOTTY, 0);
+                       close(fd);
+               }
                chdir("/");
                umask(022);    /* set a default for dumb programs */
                setpgid(0, 0); /* set the process group */
index c6e060500b83a4e4b72da761ae4999e2bfad557e..b56eaa899f5fb7a2b55e13ff236fa34bc667f792 100644 (file)
@@ -816,7 +816,7 @@ int vtysh_mark_file(const char *filename)
                        vty_out(vty, "%s", vty->buf);
                        break;
                case CMD_SUCCESS_DAEMON: {
-                       int cmd_stat = CMD_SUCCESS;
+                       int cmd_stat;
 
                        vty_out(vty, "%s", vty->buf);
                        cmd_stat = vtysh_client_execute(&vtysh_client[0],
@@ -2136,6 +2136,28 @@ DEFUNSH(VTYSH_INTERFACE, vtysh_quit_interface, vtysh_quit_interface_cmd, "quit",
        return vtysh_exit_interface(self, vty, argc, argv);
 }
 
+DEFUN (vtysh_show_poll,
+       vtysh_show_poll_cmd,
+       "show thread poll",
+       SHOW_STR
+       "Thread information\n"
+       "Thread Poll Information\n")
+{
+       unsigned int i;
+       int ret = CMD_SUCCESS;
+       char line[100];
+
+       snprintf(line, sizeof(line), "do show thread poll\n");
+       for (i = 0; i < array_size(vtysh_client); i++)
+               if (vtysh_client[i].fd >= 0) {
+                       vty_out(vty, "Thread statistics for %s:\n",
+                               vtysh_client[i].name);
+                       ret = vtysh_client_execute(&vtysh_client[i], line);
+                       vty_out(vty, "\n");
+               }
+       return ret;
+}
+
 DEFUN (vtysh_show_thread,
        vtysh_show_thread_cmd,
        "show thread cpu [FILTER]",
@@ -2393,10 +2415,11 @@ DEFUNSH(VTYSH_ALL, vtysh_log_syslog, vtysh_log_syslog_cmd,
 }
 
 DEFUNSH(VTYSH_ALL, no_vtysh_log_syslog, no_vtysh_log_syslog_cmd,
-       "no log syslog [LEVEL]", NO_STR
+       "no log syslog [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
+       NO_STR
        "Logging control\n"
        "Cancel logging to syslog\n"
-       "Logging level\n")
+       LOG_LEVEL_DESC)
 {
        return CMD_SUCCESS;
 }
@@ -2418,24 +2441,6 @@ DEFUNSH(VTYSH_ALL, no_vtysh_log_facility, no_vtysh_log_facility_cmd,
        return CMD_SUCCESS;
 }
 
-DEFUNSH_DEPRECATED(
-       VTYSH_ALL, vtysh_log_trap, vtysh_log_trap_cmd,
-       "log trap <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>",
-       "Logging control\n"
-       "(Deprecated) Set logging level and default for all destinations\n" LOG_LEVEL_DESC)
-{
-       return CMD_SUCCESS;
-}
-
-DEFUNSH_DEPRECATED(VTYSH_ALL, no_vtysh_log_trap, no_vtysh_log_trap_cmd,
-                  "no log trap [LEVEL]", NO_STR
-                  "Logging control\n"
-                  "Permit all logging information\n"
-                  "Logging level\n")
-{
-       return CMD_SUCCESS;
-}
-
 DEFUNSH(VTYSH_ALL, vtysh_log_record_priority, vtysh_log_record_priority_cmd,
        "log record-priority",
        "Logging control\n"
@@ -2612,8 +2617,13 @@ static void backup_config_file(const char *fbackup)
        strcat(integrate_sav, CONF_BACKUP_EXT);
 
        /* Move current configuration file to backup config file. */
-       unlink(integrate_sav);
-       rename(fbackup, integrate_sav);
+       if (unlink(integrate_sav) != 0) {
+               vty_out(vty, "Warning: %s unlink failed\n", integrate_sav);
+       }
+       if (rename(fbackup, integrate_sav) != 0) {
+               vty_out(vty, "Error renaming %s to %s\n", fbackup,
+                       integrate_sav);
+       }
        free(integrate_sav);
 }
 
@@ -2623,8 +2633,12 @@ int vtysh_write_config_integrated(void)
        char line[] = "do write terminal\n";
        FILE *fp;
        int fd;
+#ifdef FRR_USER
        struct passwd *pwentry;
+#endif
+#ifdef FRR_GROUP
        struct group *grentry;
+#endif
        uid_t uid = -1;
        gid_t gid = -1;
        struct stat st;
@@ -3343,9 +3357,12 @@ static void vtysh_autocomplete(vector comps, struct cmd_token *token)
        snprintf(accmd, sizeof(accmd), "autocomplete %d %s %s", token->type,
                 token->text, token->varname ? token->varname : "-");
 
+       vty->of_saved = vty->of;
+       vty->of = NULL;
        for (i = 0; i < array_size(vtysh_client); i++)
                vtysh_client_run_all(&vtysh_client[i], accmd, 1, vtysh_ac_line,
                                     comps);
+       vty->of = vty->of_saved;
 }
 
 static const struct cmd_variable_handler vtysh_var_handler[] = {
@@ -3720,6 +3737,7 @@ void vtysh_init_vty(void)
        install_element(VIEW_NODE, &vtysh_show_work_queues_cmd);
        install_element(VIEW_NODE, &vtysh_show_work_queues_daemon_cmd);
        install_element(VIEW_NODE, &vtysh_show_thread_cmd);
+       install_element(VIEW_NODE, &vtysh_show_poll_cmd);
 
        /* Logging */
        install_element(VIEW_NODE, &vtysh_show_logging_cmd);
@@ -3733,8 +3751,6 @@ void vtysh_init_vty(void)
        install_element(CONFIG_NODE, &no_vtysh_log_monitor_cmd);
        install_element(CONFIG_NODE, &vtysh_log_syslog_cmd);
        install_element(CONFIG_NODE, &no_vtysh_log_syslog_cmd);
-       install_element(CONFIG_NODE, &vtysh_log_trap_cmd);
-       install_element(CONFIG_NODE, &no_vtysh_log_trap_cmd);
        install_element(CONFIG_NODE, &vtysh_log_facility_cmd);
        install_element(CONFIG_NODE, &no_vtysh_log_facility_cmd);
        install_element(CONFIG_NODE, &vtysh_log_record_priority_cmd);
index e6d324ab6a64d0697e44943f31c7bdd55e620bcb..5c84219418422842abf7cad504a8da98aa8408dd 100644 (file)
@@ -586,8 +586,13 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup)
                return 0;
 
        len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifinfomsg));
-       if (len < 0)
+       if (len < 0) {
+               zlog_err("%s: Message received from netlink is of a broken size: %d %zu",
+                        __PRETTY_FUNCTION__,
+                        h->nlmsg_len,
+                        (size_t)NLMSG_LENGTH(sizeof(struct ifinfomsg)));
                return -1;
+       }
 
        /* We are interested in some AF_BRIDGE notifications. */
        if (ifi->ifi_family == AF_BRIDGE)
@@ -893,8 +898,13 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup)
                return 0;
 
        len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifaddrmsg));
-       if (len < 0)
+       if (len < 0) {
+               zlog_err("%s: Message received from netlink is of a broken size: %d %zu",
+                        __PRETTY_FUNCTION__,
+                        h->nlmsg_len,
+                        (size_t)NLMSG_LENGTH(sizeof(struct ifaddrmsg)));
                return -1;
+       }
 
        memset(tb, 0, sizeof tb);
        netlink_parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), len);
@@ -1105,8 +1115,12 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
        }
 
        len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifinfomsg));
-       if (len < 0)
+       if (len < 0) {
+               zlog_err("%s: Message received from netlink is of a broken size %d %zu",
+                        __PRETTY_FUNCTION__, h->nlmsg_len,
+                        (size_t)NLMSG_LENGTH(sizeof(struct ifinfomsg)));
                return -1;
+       }
 
        /* We are interested in some AF_BRIDGE notifications. */
        if (ifi->ifi_family == AF_BRIDGE)
index 7de18d683c1b2d4574f045bb989ec15094fb1a4f..6125ff9a16b37b769c6a7a3ba44127c530c65ff8 100644 (file)
@@ -934,6 +934,12 @@ void if_up(struct interface *ifp)
        /* Install connected routes to the kernel. */
        if_install_connected(ifp);
 
+       /* Install any static routes using this vrf interface */
+       if (IS_ZEBRA_IF_VRF(ifp)) {
+               static_fixup_vrf_ids(zvrf);
+               static_config_install_delayed_routes(zvrf);
+       }
+
        if (IS_ZEBRA_DEBUG_RIB_DETAILED)
                zlog_debug("%u: IF %s up, scheduling RIB processing",
                           ifp->vrf_id, ifp->name);
index 0e79b8253319d8da60830ceed8daf580ad371462..d9c663184531acb27f873f4ac1664bed917ceb93 100644 (file)
@@ -498,6 +498,75 @@ const char *nl_rttype_to_str(uint8_t rttype)
        return lookup_msg(rttype_str, rttype, "");
 }
 
+#define NL_OK(nla, len)                                                        \
+       ((len) >= (int)sizeof(struct nlattr)                                   \
+        && (nla)->nla_len >= sizeof(struct nlattr)                            \
+        && (nla)->nla_len <= (len))
+#define NL_NEXT(nla, attrlen)                                                  \
+       ((attrlen) -= RTA_ALIGN((nla)->nla_len),                               \
+        (struct nlattr *)(((char *)(nla)) + RTA_ALIGN((nla)->nla_len)))
+#define NL_RTA(r)                                                              \
+       ((struct nlattr *)(((char *)(r))                                       \
+                          + NLMSG_ALIGN(sizeof(struct nlmsgerr))))
+
+static void netlink_parse_nlattr(struct nlattr **tb, int max,
+                                struct nlattr *nla, int len)
+{
+       while (NL_OK(nla, len)) {
+               if (nla->nla_type <= max)
+                       tb[nla->nla_type] = nla;
+               nla = NL_NEXT(nla, len);
+       }
+}
+
+static void netlink_parse_extended_ack(struct nlmsghdr *h)
+{
+       struct nlattr *tb[NLMSGERR_ATTR_MAX + 1];
+       const struct nlmsgerr *err =
+               (const struct nlmsgerr *)((uint8_t *)h
+                                         + NLMSG_ALIGN(
+                                                   sizeof(struct nlmsghdr)));
+       const struct nlmsghdr *err_nlh = NULL;
+       uint32_t hlen = sizeof(*err);
+       const char *msg = NULL;
+       uint32_t off = 0;
+
+       if (!(h->nlmsg_flags & NLM_F_CAPPED))
+               hlen += h->nlmsg_len - NLMSG_ALIGN(sizeof(struct nlmsghdr));
+
+       memset(tb, 0, sizeof(tb));
+       netlink_parse_nlattr(tb, NLMSGERR_ATTR_MAX, NL_RTA(h), hlen);
+
+       if (tb[NLMSGERR_ATTR_MSG])
+               msg = (const char *)RTA_DATA(tb[NLMSGERR_ATTR_MSG]);
+
+       if (tb[NLMSGERR_ATTR_OFFS]) {
+               off = *(uint32_t *)RTA_DATA(tb[NLMSGERR_ATTR_OFFS]);
+
+               if (off > h->nlmsg_len) {
+                       zlog_err("Invalid offset for NLMSGERR_ATTR_OFFS\n");
+               } else if (!(h->nlmsg_flags & NLM_F_CAPPED)) {
+                       /*
+                        * Header of failed message
+                        * we are not doing anything currently with it
+                        * but noticing it for later.
+                        */
+                       err_nlh = &err->msg;
+                       zlog_warn("%s: Received %d extended Ack",
+                                 __PRETTY_FUNCTION__, err_nlh->nlmsg_type);
+               }
+       }
+
+       if (msg && *msg != '\0') {
+               bool is_err = !!err->error;
+
+               if (is_err)
+                       zlog_err("Extended Error: %s", msg);
+               else
+                       zlog_warn("Extended Warning: %s", msg);
+       }
+}
+
 /*
  * netlink_parse_info
  *
@@ -582,6 +651,23 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int),
                                int errnum = err->error;
                                int msg_type = err->msg.nlmsg_type;
 
+                               if (h->nlmsg_len
+                                   < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
+                                       zlog_err("%s error: message truncated",
+                                                nl->name);
+                                       return -1;
+                               }
+
+                               /*
+                                * Parse the extended information before
+                                * we actually handle it.
+                                * At this point in time we do not
+                                * do anything other than report the
+                                * issue.
+                                */
+                               if (h->nlmsg_flags & NLM_F_ACK_TLVS)
+                                       netlink_parse_extended_ack(h);
+
                                /* If the error field is zero, then this is an
                                 * ACK */
                                if (err->error == 0) {
@@ -603,13 +689,6 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int),
                                        continue;
                                }
 
-                               if (h->nlmsg_len
-                                   < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
-                                       zlog_err("%s error: message truncated",
-                                                nl->name);
-                                       return -1;
-                               }
-
                                /* Deal with errors that occur because of races
                                 * in link handling */
                                if (nl == &zns->netlink_cmd
@@ -692,6 +771,7 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int),
                        error = (*filter)(h, zns->ns_id, startup);
                        if (error < 0) {
                                zlog_err("%s filter function error", nl->name);
+                               zlog_backtrace(LOG_ERR);
                                ret = error;
                        }
                }
@@ -836,6 +916,9 @@ int netlink_request(struct nlsock *nl, struct nlmsghdr *n)
 void kernel_init(struct zebra_ns *zns)
 {
        unsigned long groups;
+#if defined SOL_NETLINK
+       int one, ret;
+#endif
 
        /*
         * Initialize netlink sockets
@@ -866,6 +949,25 @@ void kernel_init(struct zebra_ns *zns)
        zns->netlink_cmd.sock = -1;
        netlink_socket(&zns->netlink_cmd, 0, zns->ns_id);
 
+       /*
+        * SOL_NETLINK is not available on all platforms yet
+        * apparently.  It's in bits/socket.h which I am not
+        * sure that we want to pull into our build system.
+        */
+#if defined SOL_NETLINK
+       /*
+        * Let's tell the kernel that we want to receive extended
+        * ACKS over our command socket
+        */
+       one = 1;
+       ret = setsockopt(zns->netlink_cmd.sock, SOL_NETLINK, NETLINK_EXT_ACK,
+                        &one, sizeof(one));
+
+       if (ret < 0)
+               zlog_notice("Registration for extended ACK failed : %d %s",
+                           errno, safe_strerror(errno));
+#endif
+
        /* Register kernel socket. */
        if (zns->netlink.sock > 0) {
                /* Only want non-blocking on the netlink event socket */
@@ -880,6 +982,7 @@ void kernel_init(struct zebra_ns *zns)
                netlink_install_filter(zns->netlink.sock,
                                       zns->netlink_cmd.snl.nl_pid);
                zns->t_netlink = NULL;
+
                thread_add_read(zebrad.master, kernel_read, zns,
                                zns->netlink.sock, &zns->t_netlink);
        }
index a5f288f54117f155eb1d8b652c0f9dd27e4d4528..90334915491e1c9f69c51314602c78fbf4386b3d 100644 (file)
@@ -295,8 +295,12 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
        }
 
        len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg));
-       if (len < 0)
+       if (len < 0) {
+               zlog_err("%s: Message received from netlink is of a broken size %d %zu",
+                        __PRETTY_FUNCTION__, h->nlmsg_len,
+                        (size_t)NLMSG_LENGTH(sizeof(struct rtmsg)));
                return -1;
+       }
 
        memset(tb, 0, sizeof tb);
        netlink_parse_rtattr(tb, RTA_MAX, RTM_RTA(rtm), len);
@@ -747,8 +751,13 @@ int netlink_route_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
                return 0;
 
        len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg));
-       if (len < 0)
+       if (len < 0) {
+               zlog_err("%s: Message received from netlink is of a broken size: %d %zu",
+                        __PRETTY_FUNCTION__,
+                        h->nlmsg_len,
+                        (size_t)NLMSG_LENGTH(sizeof(struct rtmsg)));
                return -1;
+       }
 
        if (rtm->rtm_type == RTN_MULTICAST)
                netlink_route_change_read_multicast(h, ns_id, startup);
@@ -2356,8 +2365,12 @@ int netlink_neigh_change(struct nlmsghdr *h, ns_id_t ns_id)
 
        /* Length validity. */
        len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct ndmsg));
-       if (len < 0)
+       if (len < 0) {
+               zlog_err("%s: Message received from netlink is of a broken size %d %zu",
+                        __PRETTY_FUNCTION__, h->nlmsg_len,
+                        (size_t)NLMSG_LENGTH(sizeof(struct ndmsg)));
                return -1;
+       }
 
        /* Is this a notification for the MAC FDB or IP neighbor table? */
        ndm = NLMSG_DATA(h);
index bcffdf47221e9980a4eb7d18f076322112db7d0e..c7a8517e17c73c0ea496db700a5df9db85d24960 100644 (file)
@@ -196,8 +196,12 @@ int netlink_rule_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
                return 0;
 
        len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct fib_rule_hdr));
-       if (len < 0)
+       if (len < 0) {
+               zlog_err("%s: Message received from netlink is of a broken size: %d %zu",
+                        __PRETTY_FUNCTION__, h->nlmsg_len,
+                        (size_t)NLMSG_LENGTH(sizeof(struct fib_rule_hdr)));
                return -1;
+       }
 
        frh = NLMSG_DATA(h);
        if (frh->family != AF_INET && frh->family != AF_INET6)
index 853a83373dbdfdeeeb887977e999caacaa0eb755..6e0d86d668eeb5d251df638bd9f6fb17383841f8 100644 (file)
@@ -521,6 +521,7 @@ int zsend_redistribute_route(int cmd, struct zserv *client, struct prefix *p,
        struct zapi_nexthop *api_nh;
        struct nexthop *nexthop;
        int count = 0;
+       afi_t afi;
 
        memset(&api, 0, sizeof(api));
        api.vrf_id = re->vrf_id;
@@ -528,6 +529,24 @@ int zsend_redistribute_route(int cmd, struct zserv *client, struct prefix *p,
        api.instance = re->instance;
        api.flags = re->flags;
 
+       afi = family2afi(p->family);
+       switch (afi) {
+       case AFI_IP:
+               if (cmd == ZEBRA_REDISTRIBUTE_ROUTE_ADD)
+                       client->redist_v4_add_cnt++;
+               else
+                       client->redist_v4_del_cnt++;
+               break;
+       case AFI_IP6:
+               if (cmd == ZEBRA_REDISTRIBUTE_ROUTE_ADD)
+                       client->redist_v6_add_cnt++;
+               else
+                       client->redist_v6_del_cnt++;
+               break;
+       default:
+               break;
+       }
+
        /* Prefix. */
        api.prefix = *p;
        if (src_p) {
@@ -2896,9 +2915,9 @@ static inline void zread_ipset_entry(ZAPI_HANDLER_ARGS)
 
                if (!is_default_prefix(&zpi.dst))
                        zpi.filter_bm |= PBR_FILTER_DST_IP;
-               if (zpi.dst_port_min != 0)
+               if (zpi.dst_port_min != 0 || zpi.proto == IPPROTO_ICMP)
                        zpi.filter_bm |= PBR_FILTER_DST_PORT;
-               if (zpi.src_port_min != 0)
+               if (zpi.src_port_min != 0 || zpi.proto == IPPROTO_ICMP)
                        zpi.filter_bm |= PBR_FILTER_SRC_PORT;
                if (zpi.dst_port_max != 0)
                        zpi.filter_bm |= PBR_FILTER_DST_PORT_RANGE;
@@ -2938,6 +2957,12 @@ static inline void zread_iptable(ZAPI_HANDLER_ARGS)
        STREAM_GETL(s, zpi.action);
        STREAM_GETL(s, zpi.fwmark);
        STREAM_GET(&zpi.ipset_name, s, ZEBRA_IPSET_NAME_SIZE);
+       STREAM_GETW(s, zpi.pkt_len_min);
+       STREAM_GETW(s, zpi.pkt_len_max);
+       STREAM_GETW(s, zpi.tcp_flags);
+       STREAM_GETW(s, zpi.tcp_mask_flags);
+       STREAM_GETC(s, zpi.dscp_value);
+       STREAM_GETC(s, zpi.fragment);
        STREAM_GETL(s, zpi.nb_interface);
        zebra_pbr_iptable_update_interfacelist(s, &zpi);
 
index 317b02f601139d4182f85c8a2c01c8cc2038f9ba..96e6df34da9c1514e3669716b44abc76927a3bad 100644 (file)
@@ -307,7 +307,7 @@ ns_id_t zebra_ns_id_get(const char *netnspath)
                        nlh = (struct nlmsghdr *)((char *)nlh
                                                  + NETLINK_ALIGN(
                                                            nlh->nlmsg_len));
-               } while (len != 0 && return_nsid != NS_UNKNOWN && ret == 0);
+               } while (len != 0 && ret == 0);
        }
 
        close(fd);
index 30f850597c65c0b848ceddb96115bf4a4a37a71a..d0ea661403d0bdc0ffecce3289ec8a4d3ac540ae 100644 (file)
@@ -212,6 +212,18 @@ static int zebra_ns_notify_read(struct thread *t)
                        continue;
                if (event->mask & IN_DELETE)
                        return zebra_ns_delete(event->name);
+
+               if (offsetof(struct inotify_event, name) + event->len
+                   >= sizeof(buf)) {
+                       zlog_err("NS notify read: buffer underflow");
+                       break;
+               }
+
+               if (strnlen(event->name, event->len) == event->len) {
+                       zlog_err("NS notify error: bad event name");
+                       break;
+               }
+
                netnspath = ns_netns_pathname(NULL, event->name);
                if (!netnspath)
                        continue;
index d511c8c6ec1479e4eb9d2262dad25b8107944afc..74ef25b031fb750c8dff6edeeab2b988d077fb48 100644 (file)
@@ -44,6 +44,63 @@ static const struct message ipset_type_msg[] = {
        {0}
 };
 
+const struct message icmp_typecode_str[] = {
+       { 0 << 8, "echo-reply"},
+       { 0 << 8, "pong"},
+       { 3 << 8, "network-unreachable"},
+       { (3 << 8) + 1, "host-unreachable"},
+       { (3 << 8) + 2, "protocol-unreachable"},
+       { (3 << 8) + 3, "port-unreachable"},
+       { (3 << 8) + 4, "fragmentation-needed"},
+       { (3 << 8) + 5, "source-route-failed"},
+       { (3 << 8) + 6, "network-unknown"},
+       { (3 << 8) + 7, "host-unknown"},
+       { (3 << 8) + 9, "network-prohibited"},
+       { (3 << 8) + 10, "host-prohibited"},
+       { (3 << 8) + 11, "TOS-network-unreachable"},
+       { (3 << 8) + 12, "TOS-host-unreachable"},
+       { (3 << 8) + 13, "communication-prohibited"},
+       { (3 << 8) + 14, "host-precedence-violation"},
+       { (3 << 8) + 15, "precedence-cutoff"},
+       { 4 << 8, "source-quench"},
+       { 5 << 8, "network-redirect"},
+       { (5 << 8) +  1, "host-redirect"},
+       { (5 << 8) +  2, "TOS-network-redirect"},
+       { (5 << 8) +  3, "TOS-host-redirect"},
+       { 8 << 8, "echo-request"},
+       { 8 << 8, "ping"},
+       { 9 << 8, "router-advertisement"},
+       { 10 << 8, "router-solicitation"},
+       { 11 << 8, "ttl-zero-during-transit"},
+       { (11 << 8) + 1, "ttl-zero-during-reassembly"},
+       { 12 << 8, "ip-header-bad"},
+       { (12 << 8) + 1, "required-option-missing"},
+       { 13 << 8, "timestamp-request"},
+       { 14 << 8, "timestamp-reply"},
+       { 17 << 8, "address-mask-request"},
+       { 18 << 8, "address-mask-reply"},
+       {0}
+};
+
+/* definitions */
+static const struct message tcp_value_str[] = {
+       {TCP_HEADER_FIN, "FIN"},
+       {TCP_HEADER_SYN, "SYN"},
+       {TCP_HEADER_RST, "RST"},
+       {TCP_HEADER_PSH, "PSH"},
+       {TCP_HEADER_ACK, "ACK"},
+       {TCP_HEADER_URG, "URG"},
+       {0}
+};
+
+static const struct message fragment_value_str[] = {
+       {1, "dont-fragment"},
+       {2, "is-fragment"},
+       {4, "first-fragment"},
+       {8, "last-fragment"},
+       {0}
+};
+
 /* static function declarations */
 DEFINE_HOOK(zebra_pbr_ipset_entry_wrap_script_get_stat, (struct zebra_ns *zns,
                                    struct zebra_pbr_ipset_entry *ipset,
@@ -322,6 +379,12 @@ uint32_t zebra_pbr_iptable_hash_key(void *arg)
        key = jhash2(pnt, ZEBRA_IPSET_NAME_HASH_SIZE,
                     0x63ab42de);
        key = jhash_1word(iptable->fwmark, key);
+       key = jhash_1word(iptable->pkt_len_min, key);
+       key = jhash_1word(iptable->pkt_len_max, key);
+       key = jhash_1word(iptable->tcp_flags, key);
+       key = jhash_1word(iptable->tcp_mask_flags, key);
+       key = jhash_1word(iptable->dscp_value, key);
+       key = jhash_1word(iptable->fragment, key);
        return jhash_3words(iptable->filter_bm, iptable->type,
                            iptable->unique, key);
 }
@@ -346,6 +409,18 @@ int zebra_pbr_iptable_hash_equal(const void *arg1, const void *arg2)
        if (strncmp(r1->ipset_name, r2->ipset_name,
                    ZEBRA_IPSET_NAME_SIZE))
                return 0;
+       if (r1->pkt_len_min != r2->pkt_len_min)
+               return 0;
+       if (r1->pkt_len_max != r2->pkt_len_max)
+               return 0;
+       if (r1->tcp_flags != r2->tcp_flags)
+               return 0;
+       if (r1->tcp_mask_flags != r2->tcp_mask_flags)
+               return 0;
+       if (r1->dscp_value != r2->dscp_value)
+               return 0;
+       if (r1->fragment != r2->fragment)
+               return 0;
        return 1;
 }
 
@@ -515,7 +590,7 @@ struct pbr_ipset_name_lookup {
        char ipset_name[ZEBRA_IPSET_NAME_SIZE];
 };
 
-static const char *zebra_pbr_ipset_type2str(uint32_t type)
+const char *zebra_pbr_ipset_type2str(uint32_t type)
 {
        return lookup_msg(ipset_type_msg, type,
                          "Unrecognized IPset Type");
@@ -773,6 +848,30 @@ static const char *zebra_pbr_prefix2str(union prefixconstptr pu,
        return prefix2str(pu, str, size);
 }
 
+static void zebra_pbr_display_icmp(struct vty *vty,
+                                  struct zebra_pbr_ipset_entry *zpie)
+{
+       char decoded_str[20];
+       uint16_t port;
+
+       /* range icmp type */
+       if (zpie->src_port_max || zpie->dst_port_max) {
+               vty_out(vty, ":icmp:[type <%d:%d>;code <%d:%d>",
+                       zpie->src_port_min, zpie->src_port_max,
+                       zpie->dst_port_min, zpie->dst_port_max);
+       } else {
+               port = ((zpie->src_port_min << 8) & 0xff00) +
+                       (zpie->dst_port_min & 0xff);
+               memset(decoded_str, 0, sizeof(decoded_str));
+               sprintf(decoded_str, "%d/%d",
+                       zpie->src_port_min,
+                       zpie->dst_port_min);
+               vty_out(vty, ":icmp:%s",
+                       lookup_msg(icmp_typecode_str,
+                                  port, decoded_str));
+       }
+}
+
 static void zebra_pbr_display_port(struct vty *vty, uint32_t filter_bm,
                            uint16_t port_min, uint16_t port_max,
                            uint8_t proto)
@@ -816,7 +915,8 @@ static int zebra_pbr_show_ipset_entry_walkcb(struct hash_backet *backet,
 
                zebra_pbr_prefix2str(&(zpie->src), buf, sizeof(buf));
                vty_out(vty, "\tfrom %s", buf);
-               if (zpie->filter_bm & PBR_FILTER_SRC_PORT)
+               if (zpie->filter_bm & PBR_FILTER_SRC_PORT &&
+                   zpie->proto != IPPROTO_ICMP)
                        zebra_pbr_display_port(vty, zpie->filter_bm,
                                               zpie->src_port_min,
                                               zpie->src_port_max,
@@ -824,11 +924,14 @@ static int zebra_pbr_show_ipset_entry_walkcb(struct hash_backet *backet,
                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)
+               if (zpie->filter_bm & PBR_FILTER_DST_PORT &&
+                   zpie->proto != IPPROTO_ICMP)
                        zebra_pbr_display_port(vty, zpie->filter_bm,
                                               zpie->dst_port_min,
                                               zpie->dst_port_max,
                                               zpie->proto);
+               if (zpie->proto == IPPROTO_ICMP)
+                       zebra_pbr_display_icmp(vty, zpie);
        } else if ((zpi->type == IPSET_NET) ||
                   (zpi->type == IPSET_NET_PORT)) {
                char buf[PREFIX_STRLEN];
@@ -837,7 +940,8 @@ static int zebra_pbr_show_ipset_entry_walkcb(struct hash_backet *backet,
                        zebra_pbr_prefix2str(&(zpie->src), buf, sizeof(buf));
                        vty_out(vty, "\tfrom %s", buf);
                }
-               if (zpie->filter_bm & PBR_FILTER_SRC_PORT)
+               if (zpie->filter_bm & PBR_FILTER_SRC_PORT &&
+                   zpie->proto != IPPROTO_ICMP)
                        zebra_pbr_display_port(vty, zpie->filter_bm,
                                               zpie->src_port_min,
                                               zpie->src_port_max,
@@ -846,11 +950,14 @@ static int zebra_pbr_show_ipset_entry_walkcb(struct hash_backet *backet,
                        zebra_pbr_prefix2str(&(zpie->dst), buf, sizeof(buf));
                        vty_out(vty, "\tto %s", buf);
                }
-               if (zpie->filter_bm & PBR_FILTER_DST_PORT)
+               if (zpie->filter_bm & PBR_FILTER_DST_PORT &&
+                   zpie->proto != IPPROTO_ICMP)
                        zebra_pbr_display_port(vty, zpie->filter_bm,
                                               zpie->dst_port_min,
                                               zpie->dst_port_max,
                                               zpie->proto);
+               if (zpie->proto == IPPROTO_ICMP)
+                       zebra_pbr_display_icmp(vty, zpie);
        }
        vty_out(vty, " (%u)\n", zpie->unique);
 
@@ -882,6 +989,26 @@ static int zebra_pbr_show_ipset_walkcb(struct hash_backet *backet, void *arg)
        return HASHWALK_CONTINUE;
 }
 
+size_t zebra_pbr_tcpflags_snprintf(char *buffer, size_t len,
+                                  uint16_t tcp_val)
+{
+       size_t len_written = 0;
+       static struct message nt = {0};
+       const struct message *pnt;
+       int incr = 0;
+
+       for (pnt = tcp_value_str;
+            memcmp(pnt, &nt, sizeof(struct message)); pnt++)
+               if (pnt->key & tcp_val) {
+                       len_written += snprintf(buffer + len_written,
+                                               len - len_written,
+                                               "%s%s", incr ?
+                                               ",":"", pnt->str);
+                       incr++;
+               }
+       return len_written;
+}
+
 /*
  */
 void zebra_pbr_show_ipset_list(struct vty *vty, char *ipsetname)
@@ -946,7 +1073,42 @@ static int zebra_pbr_show_iptable_walkcb(struct hash_backet *backet, void *arg)
        vty_out(vty, "IPtable %s action %s (%u)\n", iptable->ipset_name,
                iptable->action == ZEBRA_IPTABLES_DROP ? "drop" : "redirect",
                iptable->unique);
-
+       if (iptable->pkt_len_min || iptable->pkt_len_max) {
+               if (!iptable->pkt_len_max)
+                       vty_out(vty, "\t pkt len %u\n",
+                               iptable->pkt_len_min);
+               else
+                       vty_out(vty, "\t pkt len [%u;%u]\n",
+                               iptable->pkt_len_min,
+                               iptable->pkt_len_max);
+       }
+       if (iptable->tcp_flags || iptable->tcp_mask_flags) {
+               char tcp_flag_str[64];
+               char tcp_flag_mask_str[64];
+
+               zebra_pbr_tcpflags_snprintf(tcp_flag_str,
+                                           sizeof(tcp_flag_str),
+                                           iptable->tcp_flags);
+               zebra_pbr_tcpflags_snprintf(tcp_flag_mask_str,
+                                           sizeof(tcp_flag_mask_str),
+                                           iptable->tcp_mask_flags);
+               vty_out(vty, "\t tcpflags [%s/%s]\n",
+                       tcp_flag_str, tcp_flag_mask_str);
+       }
+       if (iptable->filter_bm & (MATCH_DSCP_SET | MATCH_DSCP_INVERSE_SET)) {
+               vty_out(vty, "\t dscp %s %d\n",
+                       iptable->filter_bm & MATCH_DSCP_INVERSE_SET ?
+                       "not" : "", iptable->dscp_value);
+       }
+       if (iptable->fragment) {
+               char val_str[10];
+
+               sprintf(val_str, "%d", iptable->fragment);
+               vty_out(vty, "\t fragment%s %s\n",
+                       iptable->filter_bm & MATCH_FRAGMENT_INVERSE_SET ?
+                       " not" : "", lookup_msg(fragment_value_str,
+                                              iptable->fragment, val_str));
+       }
        ret = hook_call(zebra_pbr_iptable_wrap_script_get_stat,
                        zns, iptable, &pkts, &bytes);
        if (ret && pkts > 0)
index 6cbafd6daaed1dd771c41395d6e8fb40344c3e69..fd83502ae180e1f8982228b7a50c79474a7660ba 100644 (file)
@@ -91,8 +91,10 @@ struct zebra_pbr_ipset_entry {
        struct prefix src;
        struct prefix dst;
 
+       /* udp/tcp src port or icmp type */
        uint16_t src_port_min;
        uint16_t src_port_max;
+       /* udp/tcp dst port or icmp code */
        uint16_t dst_port_min;
        uint16_t dst_port_max;
 
@@ -131,6 +133,13 @@ struct zebra_pbr_iptable {
 
        uint32_t action;
 
+       uint16_t pkt_len_min;
+       uint16_t pkt_len_max;
+       uint16_t tcp_flags;
+       uint16_t tcp_mask_flags;
+       uint8_t dscp_value;
+       uint8_t fragment;
+
        uint32_t nb_interface;
 
        struct list *interface_name_list;
@@ -138,6 +147,10 @@ struct zebra_pbr_iptable {
        char ipset_name[ZEBRA_IPSET_NAME_SIZE];
 };
 
+extern const struct message icmp_typecode_str[];
+
+const char *zebra_pbr_ipset_type2str(uint32_t type);
+
 void zebra_pbr_add_rule(struct zebra_ns *zns, struct zebra_pbr_rule *rule);
 void zebra_pbr_del_rule(struct zebra_ns *zns, struct zebra_pbr_rule *rule);
 void zebra_pbr_create_ipset(struct zebra_ns *zns,
@@ -225,6 +238,8 @@ 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);
+size_t zebra_pbr_tcpflags_snprintf(char *buffer, size_t len,
+                                  uint16_t tcp_val);
 
 DECLARE_HOOK(zebra_pbr_ipset_entry_wrap_script_get_stat, (struct zebra_ns *zns,
                                    struct zebra_pbr_ipset_entry *ipset,
index 879e7e831769b877523da38a3563a9b816eaed08..8935956b2572f94a3e4d02a01ea9e63c4cd8a1c2 100644 (file)
@@ -1428,18 +1428,14 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf,
                                if (new != old)
                                        zlog_debug(
                                                "%u:%s: Deleting route rn %p, re %p (type %d) "
-                                               "old %p (type %d) - %s",
+                                               "old %p (type %d) - nexthop inactive",
                                                zvrf_id(zvrf), buf, rn, new,
-                                               new->type, old, old->type,
-                                               nh_active ? "install failed"
-                                                         : "nexthop inactive");
+                                               new->type, old, old->type);
                                else
                                        zlog_debug(
-                                               "%u:%s: Deleting route rn %p, re %p (type %d) - %s",
+                                               "%u:%s: Deleting route rn %p, re %p (type %d) - nexthop inactive",
                                                zvrf_id(zvrf), buf, rn, new,
-                                               new->type,
-                                               nh_active ? "install failed"
-                                                         : "nexthop inactive");
+                                               new->type);
                        }
 
                        /* If labeled-unicast route, uninstall transit LSP. */
@@ -2542,12 +2538,10 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
                                                rn, vrf_id,
                                                "via %s ifindex %d type %d "
                                                "doesn't exist in rib",
-                                               inet_ntop(
-                                                       family2afi(afi),
-                                                       &nh->gate, buf2,
-                                                       INET_ADDRSTRLEN), /* FIXME
-                                                                            */
-                                               nh->ifindex, type);
+                                               inet_ntop(afi2family(afi),
+                                                         &nh->gate, buf2,
+                                                         sizeof(buf2)),
+                                                         nh->ifindex, type);
                                else
                                        rnode_debug(
                                                rn, vrf_id,
index 10ba88880a8935363f93d59715a9aecc6181371e..ce51f54a65b7d7d68d13abe3857e2aff9b163486 100644 (file)
@@ -31,6 +31,7 @@
 #include "plist.h"
 #include "nexthop.h"
 #include "vrf.h"
+#include "frrstr.h"
 
 #include "zebra/zserv.h"
 #include "zebra/redistribute.h"
@@ -1282,6 +1283,13 @@ static struct route_map_rule_cmd route_set_src_cmd = {
        "src", route_set_src, route_set_src_compile, route_set_src_free,
 };
 
+static void zebra_route_map_process_update_cb(char *rmap_name)
+{
+       if (IS_ZEBRA_DEBUG_EVENT)
+               zlog_debug("Event handler for route-map: %s",
+                          rmap_name);
+}
+
 static int zebra_route_map_update_timer(struct thread *thread)
 {
        zebra_t_rmap_update = NULL;
@@ -1294,6 +1302,13 @@ static int zebra_route_map_update_timer(struct thread *thread)
                        "%u: Routemap update-timer fired, scheduling RIB processing",
                        VRF_DEFAULT);
 
+       route_map_walk_update_list(zebra_route_map_process_update_cb);
+
+       /*
+        * This code needs to be updated to be:
+        * 1) VRF Aware <sigh>
+        * 2) Route-map aware
+        */
        zebra_import_table_rm_update();
        rib_update(VRF_DEFAULT, RIB_UPDATE_RMAP_CHANGE);
        zebra_evaluate_rnh(0, AF_INET, 1, RNH_NEXTHOP_TYPE, NULL);
@@ -1433,20 +1448,26 @@ static void zebra_route_map_mark_update(const char *rmap_name)
 
 static void zebra_route_map_add(const char *rmap_name)
 {
-       zebra_route_map_mark_update(rmap_name);
+       if (route_map_mark_updated(rmap_name) == 0)
+               zebra_route_map_mark_update(rmap_name);
+
        route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED);
 }
 
 static void zebra_route_map_delete(const char *rmap_name)
 {
-       zebra_route_map_mark_update(rmap_name);
+       if (route_map_mark_updated(rmap_name) == 0)
+               zebra_route_map_mark_update(rmap_name);
+
        route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_DELETED);
 }
 
 static void zebra_route_map_event(route_map_event_t event,
                                  const char *rmap_name)
 {
-       zebra_route_map_mark_update(rmap_name);
+       if (route_map_mark_updated(rmap_name) == 0)
+               zebra_route_map_mark_update(rmap_name);
+
        route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED);
 }
 
index 9ce8c74220042cb35164079d032c7a50dd8d3945..55c4f6e916b1106a6cfe10969e9bc56d748590fc 100644 (file)
@@ -2898,7 +2898,7 @@ DEFUN (show_vrf,
        return CMD_SUCCESS;
 }
 
-DEFUN (default_vrf_vni_mapping,
+DEFUN_HIDDEN (default_vrf_vni_mapping,
        default_vrf_vni_mapping_cmd,
        "vni " CMD_VNI_RANGE "[prefix-routes-only]",
        "VNI corresponding to the DEFAULT VRF\n"
@@ -2928,7 +2928,7 @@ DEFUN (default_vrf_vni_mapping,
        return CMD_SUCCESS;
 }
 
-DEFUN (no_default_vrf_vni_mapping,
+DEFUN_HIDDEN (no_default_vrf_vni_mapping,
        no_default_vrf_vni_mapping_cmd,
        "no vni " CMD_VNI_RANGE,
        NO_STR
index 14e0db40bfb50c62d864f14a30716af10b375e7d..b297f75ed943b4b5c2433650345d56fbf390bab6 100644 (file)
@@ -198,7 +198,7 @@ static int zserv_write(struct thread *thread)
 {
        struct zserv *client = THREAD_ARG(thread);
        struct stream *msg;
-       uint32_t wcmd;
+       uint32_t wcmd = 0;
        struct stream_fifo *cache;
 
        /* If we have any data pending, try to flush it first */
@@ -939,6 +939,11 @@ static void zebra_show_client_detail(struct vty *vty, struct zserv *client)
        vty_out(vty, "MAC-IP add notifications: %d\n", client->macipadd_cnt);
        vty_out(vty, "MAC-IP delete notifications: %d\n", client->macipdel_cnt);
 
+#if defined DEV_BUILD
+       vty_out(vty, "Input Fifo: %zu:%zu Output Fifo: %zu:%zu\n",
+               client->ibuf_fifo->count, client->ibuf_fifo->max_count,
+               client->obuf_fifo->count, client->obuf_fifo->max_count);
+#endif
        vty_out(vty, "\n");
        return;
 }