]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge pull request #4145 from pguibert6WIND/bfd_converge_up
authorRuss White <russ@riw.us>
Thu, 25 Apr 2019 22:44:50 +0000 (18:44 -0400)
committerGitHub <noreply@github.com>
Thu, 25 Apr 2019 22:44:50 +0000 (18:44 -0400)
BFD speed convergence up

113 files changed:
Makefile.am
bfdd/bfd.h
bgpd/bgp_evpn.c
bgpd/bgp_evpn.h
bgpd/bgp_evpn_private.h
bgpd/bgp_evpn_vty.c
bgpd/bgp_filter.c
bgpd/bgp_filter.h
bgpd/bgp_flowspec.c
bgpd/bgp_label.c
bgpd/bgp_main.c
bgpd/bgp_mplsvpn.c
bgpd/bgp_packet.c
bgpd/bgp_route.c
bgpd/bgp_route.h
bgpd/bgp_vty.c
bgpd/bgp_zebra.c
doc/developer/ospf-api.rst
doc/manpages/ospfd.rst
doc/user/ospfd.rst
doc/user/overview.rst
doc/user/pim.rst
isisd/isis_cli.c
isisd/isis_misc.c
isisd/isis_northbound.c
lib/if.c
lib/if.h
lib/if_rmap.c
lib/libfrr.c
lib/linklist.c
lib/linklist.h
lib/log.c
lib/log.h
lib/log_int.h
lib/nexthop.h
lib/nexthop_group.c
lib/nexthop_group.h
lib/northbound.c
lib/northbound.h
lib/northbound_sysrepo.c
lib/prefix.c
lib/prefix.h
lib/privs.c
lib/privs.h
lib/vxlan.h
lib/yang.c
lib/yang.h
lib/zclient.c
lib/zclient.h
pimd/pim_cmd.c
pimd/pim_cmd.h
pimd/pim_iface.c
pimd/pim_iface.h
pimd/pim_instance.c
pimd/pim_instance.h
pimd/pim_memory.c
pimd/pim_memory.h
pimd/pim_mroute.c
pimd/pim_oil.c
pimd/pim_oil.h
pimd/pim_register.c
pimd/pim_register.h
pimd/pim_rpf.c
pimd/pim_str.c
pimd/pim_str.h
pimd/pim_upstream.c
pimd/pim_upstream.h
pimd/pim_vty.c
pimd/pim_vxlan.c [new file with mode: 0644]
pimd/pim_vxlan.h [new file with mode: 0644]
pimd/pim_vxlan_instance.h [new file with mode: 0644]
pimd/pim_zebra.c
pimd/pimd.h
pimd/subdir.am
ports/Makefile [deleted file]
ports/README [deleted file]
ports/files/md5 [deleted file]
ports/pkg/COMMENT [deleted file]
ports/pkg/DESCR [deleted file]
ports/pkg/PLIST [deleted file]
ripd/rip_northbound.c
ripd/rip_offset.c
ripd/ripd.c
ripd/ripd.h
ripngd/ripng_northbound.c
ripngd/ripng_offset.c
ripngd/ripngd.c
ripngd/ripngd.h
tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/adjacencies.py
tests/topotests/bgp_maximum_prefix_invalid_update/__init__.py [new file with mode: 0644]
tests/topotests/bgp_maximum_prefix_invalid_update/r1/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_maximum_prefix_invalid_update/r1/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_maximum_prefix_invalid_update/r2/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_maximum_prefix_invalid_update/r2/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_maximum_prefix_invalid_update/test_bgp_maximum_prefix_invalid_update.py [new file with mode: 0644]
zebra/if_netlink.c
zebra/interface.c
zebra/ioctl.c
zebra/ioctl.h
zebra/ioctl_solaris.c
zebra/rt.h
zebra/zebra_dplane.c
zebra/zebra_dplane.h
zebra/zebra_l2.c
zebra/zebra_l2.h
zebra/zebra_rib.c
zebra/zebra_rnh.c
zebra/zebra_vrf.h
zebra/zebra_vxlan.c
zebra/zebra_vxlan.h
zebra/zebra_vxlan_private.h
zebra/zserv.c
zebra/zserv.h

index 2618029a4bfdc6d674785ea24cfd2d92bc03fffc..9c6c8663ee535fa82090b56c8517acb8e0fdcc4e 100644 (file)
@@ -207,7 +207,6 @@ EXTRA_DIST += \
        ospfd/Makefile \
        pbrd/Makefile \
        pimd/Makefile \
-       ports/Makefile \
        qpb/Makefile \
        ripd/Makefile \
        ripngd/Makefile \
index a69ff9a1a7b9a33b7756d6ef6305a125904220d2..28832e4c4831ba6798c43f7c5a561ab9538fa62b 100644 (file)
@@ -308,8 +308,8 @@ TAILQ_HEAD(obslist, bfd_session_observer);
 #define BFD_PKT_INFO_VAL 1
 #define BFD_IPV6_PKT_INFO_VAL 1
 #define BFD_IPV6_ONLY_VAL 1
-#define BFD_SRCPORTINIT 49142
-#define BFD_SRCPORTMAX 65536
+#define BFD_SRCPORTINIT 49152
+#define BFD_SRCPORTMAX 65535
 #define BFD_DEFDESTPORT 3784
 #define BFD_DEF_ECHO_PORT 3785
 #define BFD_DEF_MHOP_DEST_PORT 4784
index 732cc6d2bb4c044c1d1ee8c4e789b1145bd3e231..52aa923959a91cc9870799f2dfec29694b773d4c 100644 (file)
@@ -609,7 +609,8 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn,
  * Add (update) or delete remote VTEP from zebra.
  */
 static int bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn,
-                                     struct prefix_evpn *p, int add)
+                               struct prefix_evpn *p,
+                               int flood_control, int add)
 {
        struct stream *s;
 
@@ -641,6 +642,7 @@ static int bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn,
                        add ? "ADD" : "DEL", vpn->vni);
                return -1;
        }
+       stream_putl(s, flood_control);
 
        stream_putw_at(s, 0, stream_get_endp(s));
 
@@ -889,6 +891,7 @@ static int evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn,
 {
        int ret;
        uint8_t flags;
+       int flood_control;
 
        if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
                flags = 0;
@@ -903,7 +906,20 @@ static int evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn,
                        bgp, vpn, p, pi->attr->nexthop, 1, flags,
                        mac_mobility_seqnum(pi->attr));
        } else {
-               ret = bgp_zebra_send_remote_vtep(bgp, vpn, p, 1);
+               switch (pi->attr->pmsi_tnl_type) {
+               case PMSI_TNLTYPE_INGR_REPL:
+                       flood_control = VXLAN_FLOOD_HEAD_END_REPL;
+                       break;
+
+               case PMSI_TNLTYPE_PIM_SM:
+                       flood_control = VXLAN_FLOOD_PIM_SM;
+                       break;
+
+               default:
+                       flood_control = VXLAN_FLOOD_DISABLED;
+                       break;
+               }
+               ret = bgp_zebra_send_remote_vtep(bgp, vpn, p, flood_control, 1);
        }
 
        return ret;
@@ -920,7 +936,8 @@ static int evpn_zebra_uninstall(struct bgp *bgp, struct bgpevpn *vpn,
                ret = bgp_zebra_send_remote_macip(bgp, vpn, p, remote_vtep_ip,
                                                  0, 0, 0);
        else
-               ret = bgp_zebra_send_remote_vtep(bgp, vpn, p, 0);
+               ret = bgp_zebra_send_remote_vtep(bgp, vpn, p,
+                                       VXLAN_FLOOD_DISABLED, 0);
 
        return ret;
 }
@@ -2220,6 +2237,24 @@ static int delete_all_vni_routes(struct bgp *bgp, struct bgpevpn *vpn)
        return 0;
 }
 
+/* BUM traffic flood mode per-l2-vni */
+static int bgp_evpn_vni_flood_mode_get(struct bgp *bgp,
+                                       struct bgpevpn *vpn)
+{
+       /* if flooding has been globally disabled per-vni mode is
+        * not relevant
+        */
+       if (bgp->vxlan_flood_ctrl == VXLAN_FLOOD_DISABLED)
+               return VXLAN_FLOOD_DISABLED;
+
+       /* if mcast group ip has been specified we use a PIM-SM MDT */
+       if (vpn->mcast_grp.s_addr != INADDR_ANY)
+               return VXLAN_FLOOD_PIM_SM;
+
+       /* default is ingress replication */
+       return VXLAN_FLOOD_HEAD_END_REPL;
+}
+
 /*
  * Update (and advertise) local routes for a VNI. Invoked upon the VNI
  * export RT getting modified or change to tunnel IP. Note that these
@@ -2236,7 +2271,8 @@ static int update_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn)
         *
         * RT-3 only if doing head-end replication
         */
-       if (bgp->vxlan_flood_ctrl == VXLAN_FLOOD_HEAD_END_REPL) {
+       if (bgp_evpn_vni_flood_mode_get(bgp, vpn)
+                               == VXLAN_FLOOD_HEAD_END_REPL) {
                build_evpn_type3_prefix(&p, vpn->originator_ip);
                ret = update_evpn_route(bgp, vpn, &p, 0, 0);
                if (ret)
@@ -2296,6 +2332,26 @@ static int delete_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn)
        return delete_all_vni_routes(bgp, vpn);
 }
 
+/*
+ * There is a flood mcast IP address change. Update the mcast-grp and
+ * remove the type-3 route if any. A new type-3 route will be generated
+ * post tunnel_ip update if the new flood mode is head-end-replication.
+ */
+static int bgp_evpn_mcast_grp_change(struct bgp *bgp, struct bgpevpn *vpn,
+               struct in_addr mcast_grp)
+{
+       struct prefix_evpn p;
+
+       vpn->mcast_grp = mcast_grp;
+
+       if (is_vni_live(vpn)) {
+               build_evpn_type3_prefix(&p, vpn->originator_ip);
+               delete_evpn_route(bgp, vpn, &p);
+       }
+
+       return 0;
+}
+
 /*
  * There is a tunnel endpoint IP address change for this VNI, delete
  * prior type-3 route (if needed) and update.
@@ -3538,7 +3594,8 @@ static int update_advertise_vni_routes(struct bgp *bgp, struct bgpevpn *vpn)
         *
         * RT-3 only if doing head-end replication
         */
-       if (bgp->vxlan_flood_ctrl == VXLAN_FLOOD_HEAD_END_REPL) {
+       if (bgp_evpn_vni_flood_mode_get(bgp, vpn)
+                               == VXLAN_FLOOD_HEAD_END_REPL) {
                build_evpn_type3_prefix(&p, vpn->originator_ip);
                rn = bgp_node_lookup(vpn->route_table, (struct prefix *)&p);
                if (!rn) /* unexpected */
@@ -3684,7 +3741,9 @@ static void create_advertise_type3(struct hash_bucket *bucket, void *data)
        struct bgp *bgp = data;
        struct prefix_evpn p;
 
-       if (!vpn || !is_vni_live(vpn))
+       if (!vpn || !is_vni_live(vpn) ||
+               bgp_evpn_vni_flood_mode_get(bgp, vpn)
+                                       != VXLAN_FLOOD_HEAD_END_REPL)
                return;
 
        build_evpn_type3_prefix(&p, vpn->originator_ip);
@@ -3858,12 +3917,12 @@ static int process_type3_route(struct peer *peer, afi_t afi, safi_t safi,
         */
        if (attr &&
            (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL))) {
-               if (attr->pmsi_tnl_type != PMSI_TNLTYPE_INGR_REPL) {
-                       flog_warn(
-                               EC_BGP_EVPN_PMSI_PRESENT,
-                               "%u:%s - Rx EVPN Type-3 NLRI with unsupported PTA %d",
-                               peer->bgp->vrf_id, peer->host,
-                               attr->pmsi_tnl_type);
+               if (attr->pmsi_tnl_type != PMSI_TNLTYPE_INGR_REPL &&
+                       attr->pmsi_tnl_type != PMSI_TNLTYPE_PIM_SM) {
+                       flog_warn(EC_BGP_EVPN_PMSI_PRESENT,
+                                 "%u:%s - Rx EVPN Type-3 NLRI with unsupported PTA %d",
+                                 peer->bgp->vrf_id, peer->host,
+                                 attr->pmsi_tnl_type);
                }
        }
 
@@ -4862,7 +4921,7 @@ int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr,
                if (addpath_encoded) {
                        /* When packet overflow occurs return immediately. */
                        if (pnt + BGP_ADDPATH_ID_LEN > lim)
-                               return -1;
+                               return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW;
 
                        addpath_id = ntohl(*((uint32_t *)pnt));
                        pnt += BGP_ADDPATH_ID_LEN;
@@ -4870,14 +4929,14 @@ int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr,
 
                /* All EVPN NLRI types start with type and length. */
                if (pnt + 2 > lim)
-                       return -1;
+                       return BGP_NLRI_PARSE_ERROR_EVPN_MISSING_TYPE;
 
                rtype = *pnt++;
                psize = *pnt++;
 
                /* When packet overflow occur return immediately. */
                if (pnt + psize > lim)
-                       return -1;
+                       return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW;
 
                switch (rtype) {
                case BGP_EVPN_MAC_IP_ROUTE:
@@ -4888,7 +4947,7 @@ int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr,
                                        EC_BGP_EVPN_FAIL,
                                        "%u:%s - Error in processing EVPN type-2 NLRI size %d",
                                        peer->bgp->vrf_id, peer->host, psize);
-                               return -1;
+                               return BGP_NLRI_PARSE_ERROR_EVPN_TYPE2_SIZE;
                        }
                        break;
 
@@ -4900,7 +4959,7 @@ int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr,
                                        EC_BGP_PKT_PROCESS,
                                        "%u:%s - Error in processing EVPN type-3 NLRI size %d",
                                        peer->bgp->vrf_id, peer->host, psize);
-                               return -1;
+                               return BGP_NLRI_PARSE_ERROR_EVPN_TYPE3_SIZE;
                        }
                        break;
 
@@ -4912,7 +4971,7 @@ int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr,
                                        EC_BGP_PKT_PROCESS,
                                        "%u:%s - Error in processing EVPN type-4 NLRI size %d",
                                        peer->bgp->vrf_id, peer->host, psize);
-                               return -1;
+                               return BGP_NLRI_PARSE_ERROR_EVPN_TYPE4_SIZE;
                        }
                        break;
 
@@ -4924,7 +4983,7 @@ int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr,
                                        EC_BGP_PKT_PROCESS,
                                        "%u:%s - Error in processing EVPN type-5 NLRI size %d",
                                        peer->bgp->vrf_id, peer->host, psize);
-                               return -1;
+                               return BGP_NLRI_PARSE_ERROR_EVPN_TYPE5_SIZE;
                        }
                        break;
 
@@ -4935,9 +4994,9 @@ int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr,
 
        /* Packet length consistency check. */
        if (pnt != lim)
-               return -1;
+               return BGP_NLRI_PARSE_ERROR_PACKET_LENGTH;
 
-       return 0;
+       return BGP_NLRI_PARSE_OK;
 }
 
 /*
@@ -5138,8 +5197,9 @@ struct bgpevpn *bgp_evpn_lookup_vni(struct bgp *bgp, vni_t vni)
  * Create a new vpn - invoked upon configuration or zebra notification.
  */
 struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni,
-                            struct in_addr originator_ip,
-                            vrf_id_t tenant_vrf_id)
+               struct in_addr originator_ip,
+               vrf_id_t tenant_vrf_id,
+               struct in_addr mcast_grp)
 {
        struct bgpevpn *vpn;
 
@@ -5152,6 +5212,7 @@ struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni,
        vpn->vni = vni;
        vpn->originator_ip = originator_ip;
        vpn->tenant_vrf_id = tenant_vrf_id;
+       vpn->mcast_grp = mcast_grp;
 
        /* Initialize route-target import and export lists */
        vpn->import_rtl = list_new();
@@ -5650,7 +5711,10 @@ int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni)
  * about are for the local-tunnel-ip and the (tenant) VRF.
  */
 int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
-                          struct in_addr originator_ip, vrf_id_t tenant_vrf_id)
+                          struct in_addr originator_ip,
+                          vrf_id_t tenant_vrf_id,
+                          struct in_addr mcast_grp)
+
 {
        struct bgpevpn *vpn;
        struct prefix_evpn p;
@@ -5661,11 +5725,14 @@ int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
 
                if (is_vni_live(vpn)
                    && IPV4_ADDR_SAME(&vpn->originator_ip, &originator_ip)
+                   && IPV4_ADDR_SAME(&vpn->mcast_grp, &mcast_grp)
                    && vpn->tenant_vrf_id == tenant_vrf_id)
                        /* Probably some other param has changed that we don't
                         * care about. */
                        return 0;
 
+               bgp_evpn_mcast_grp_change(bgp, vpn, mcast_grp);
+
                /* Update tenant_vrf_id if it has changed. */
                if (vpn->tenant_vrf_id != tenant_vrf_id) {
                        bgpevpn_unlink_from_l3vni(vpn);
@@ -5688,7 +5755,8 @@ int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
 
        /* Create or update as appropriate. */
        if (!vpn) {
-               vpn = bgp_evpn_new(bgp, vni, originator_ip, tenant_vrf_id);
+               vpn = bgp_evpn_new(bgp, vni, originator_ip, tenant_vrf_id,
+                               mcast_grp);
                if (!vpn) {
                        flog_err(
                                EC_BGP_VNI,
@@ -5716,7 +5784,8 @@ int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
         *
         * RT-3 only if doing head-end replication
         */
-       if (bgp->vxlan_flood_ctrl == VXLAN_FLOOD_HEAD_END_REPL) {
+       if (bgp_evpn_vni_flood_mode_get(bgp, vpn)
+                       == VXLAN_FLOOD_HEAD_END_REPL) {
                build_evpn_type3_prefix(&p, vpn->originator_ip);
                if (update_evpn_route(bgp, vpn, &p, 0, 0)) {
                        flog_err(EC_BGP_EVPN_ROUTE_CREATE,
index f5802fa894002162a8d6efde0c21fe6d6bb6ca52..4ad8e95bee05e402218c730f618b337aee86ef00 100644 (file)
@@ -180,7 +180,8 @@ extern int bgp_evpn_local_l3vni_del(vni_t vni, vrf_id_t vrf_id);
 extern int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni);
 extern int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
                                  struct in_addr originator_ip,
-                                 vrf_id_t tenant_vrf_id);
+                                 vrf_id_t tenant_vrf_id,
+                                 struct in_addr mcast_grp);
 extern int bgp_evpn_local_es_add(struct bgp *bgp, esi_t *esi,
                                 struct ipaddr *originator_ip);
 extern int bgp_evpn_local_es_del(struct bgp *bgp, esi_t *esi,
index 785139865e40f0813310a37028c9278aa99f46d9..a5a091242f1636ca61b95d1ca4be5b1ccc68ac1a 100644 (file)
@@ -87,6 +87,9 @@ struct bgpevpn {
        /* Route type 3 field */
        struct in_addr originator_ip;
 
+       /* PIM-SM MDT group for BUM flooding */
+       struct in_addr mcast_grp;
+
        /* Import and Export RTs. */
        struct list *import_rtl;
        struct list *export_rtl;
@@ -237,6 +240,7 @@ static inline void bgpevpn_unlink_from_l3vni(struct bgpevpn *vpn)
        listnode_delete(vpn->bgp_vrf->l2vnis, vpn);
 
        /* remove the backpointer to the vrf instance */
+       bgp_unlock(vpn->bgp_vrf);
        vpn->bgp_vrf = NULL;
 }
 
@@ -253,7 +257,7 @@ static inline void bgpevpn_link_to_l3vni(struct bgpevpn *vpn)
                return;
 
        /* associate the vpn to the bgp_vrf instance */
-       vpn->bgp_vrf = bgp_vrf;
+       vpn->bgp_vrf = bgp_lock(bgp_vrf);
        listnode_add_sort(bgp_vrf->l2vnis, vpn);
 
        /* check if we are advertising two labels for this vpn */
@@ -525,8 +529,9 @@ extern void bgp_evpn_derive_auto_rd(struct bgp *bgp, struct bgpevpn *vpn);
 extern void bgp_evpn_derive_auto_rd_for_vrf(struct bgp *bgp);
 extern struct bgpevpn *bgp_evpn_lookup_vni(struct bgp *bgp, vni_t vni);
 extern struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni,
-                                   struct in_addr originator_ip,
-                                   vrf_id_t tenant_vrf_id);
+               struct in_addr originator_ip,
+               vrf_id_t tenant_vrf_id,
+               struct in_addr mcast_grp);
 extern void bgp_evpn_free(struct bgp *bgp, struct bgpevpn *vpn);
 extern struct evpnes *bgp_evpn_lookup_es(struct bgp *bgp, esi_t *esi);
 extern struct evpnes *bgp_evpn_es_new(struct bgp *bgp, esi_t *esi,
index 5a5d1e0cd4174e950db2002521a2aa5b193776a4..4dccc89f52357473cc147b556ed9a7164f57f95d 100644 (file)
@@ -473,6 +473,8 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
                        prefix_rd2str(&vpn->prd, buf1, sizeof(buf1)));
                json_object_string_add(json, "originatorIp",
                                       inet_ntoa(vpn->originator_ip));
+               json_object_string_add(json, "mcastGroup",
+                               inet_ntoa(vpn->mcast_grp));
                json_object_string_add(json, "advertiseGatewayMacip",
                                       vpn->advertise_gw_macip ? "Yes" : "No");
        } else {
@@ -488,6 +490,8 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
                        prefix_rd2str(&vpn->prd, buf1, sizeof(buf1)));
                vty_out(vty, "  Originator IP: %s\n",
                        inet_ntoa(vpn->originator_ip));
+               vty_out(vty, "  Mcast group: %s\n",
+                               inet_ntoa(vpn->mcast_grp));
                vty_out(vty, "  Advertise-gw-macip : %s\n",
                        vpn->advertise_gw_macip ? "Yes" : "No");
                vty_out(vty, "  Advertise-svi-macip : %s\n",
@@ -1897,6 +1901,7 @@ static void evpn_unconfigure_rd(struct bgp *bgp, struct bgpevpn *vpn)
 static struct bgpevpn *evpn_create_update_vni(struct bgp *bgp, vni_t vni)
 {
        struct bgpevpn *vpn;
+       struct in_addr mcast_grp = {INADDR_ANY};
 
        if (!bgp->vnihash)
                return NULL;
@@ -1915,7 +1920,7 @@ static struct bgpevpn *evpn_create_update_vni(struct bgp *bgp, vni_t vni)
                /* tenant vrf will be updated when we get local_vni_add from
                 * zebra
                 */
-               vpn = bgp_evpn_new(bgp, vni, bgp->router_id, 0);
+               vpn = bgp_evpn_new(bgp, vni, bgp->router_id, 0, mcast_grp);
                if (!vpn) {
                        flog_err(
                                EC_BGP_VNI,
@@ -2396,13 +2401,13 @@ static void evpn_show_route_rd(struct vty *vty, struct bgp *bgp,
  * If 'type' is non-zero, only routes matching that type are shown.
  */
 static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type,
-                                json_object *json)
+                                json_object *json, int detail)
 {
        struct bgp_node *rd_rn;
        struct bgp_table *table;
        struct bgp_node *rn;
        struct bgp_path_info *pi;
-       int header = 1;
+       int header = detail ? 0 : 1;
        int rd_header;
        afi_t afi;
        safi_t safi;
@@ -2482,6 +2487,13 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type,
                                                    rn->p.prefixlen);
                        }
 
+                       /* Prefix and num paths displayed once per prefix. */
+                       if (detail)
+                               route_vty_out_detail_header(
+                                       vty, bgp, rn,
+                                       (struct prefix_rd *)&rd_rn->p,
+                                       AFI_L2VPN, SAFI_EVPN, json_prefix);
+
                        /* For EVPN, the prefix is displayed for each path (to
                         * fit in
                         * with code that already exists).
@@ -2495,8 +2507,13 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type,
                                if (json)
                                        json_path = json_object_new_array();
 
-                               route_vty_out(vty, &rn->p, pi, 0, SAFI_EVPN,
-                                             json_path);
+                               if (detail) {
+                                       route_vty_out_detail(
+                                               vty, bgp, &rn->p, pi, AFI_L2VPN,
+                                               SAFI_EVPN, json_path);
+                               } else
+                                       route_vty_out(vty, &rn->p, pi, 0,
+                                                     SAFI_EVPN, json_path);
 
                                if (json)
                                        json_object_array_add(json_paths,
@@ -3633,12 +3650,13 @@ DEFUN(show_bgp_l2vpn_evpn_summary,
  */
 DEFUN(show_bgp_l2vpn_evpn_route,
       show_bgp_l2vpn_evpn_route_cmd,
-      "show bgp l2vpn evpn route [type <macip|multicast|es|prefix>] [json]",
+      "show bgp l2vpn evpn route [detail] [type <macip|multicast|es|prefix>] [json]",
       SHOW_STR
       BGP_STR
       L2VPN_HELP_STR
       EVPN_HELP_STR
       "EVPN route information\n"
+      "Display Detailed Information\n"
       "Specify Route type\n"
       "MAC-IP (Type-2) route\n"
       "Multicast (Type-3) route\n"
@@ -3648,6 +3666,7 @@ DEFUN(show_bgp_l2vpn_evpn_route,
 {
        struct bgp *bgp;
        int type_idx = 0;
+       int detail = 0;
        int type = 0;
        bool uj = false;
        json_object *json = NULL;
@@ -3676,7 +3695,10 @@ DEFUN(show_bgp_l2vpn_evpn_route,
                        return CMD_WARNING;
        }
 
-       evpn_show_all_routes(vty, bgp, type, json);
+       if (argv_find(argv, argc, "detail", &detail))
+               detail = 1;
+
+       evpn_show_all_routes(vty, bgp, type, json, detail);
 
        if (uj) {
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
@@ -4298,9 +4320,10 @@ ALIAS_HIDDEN(show_bgp_l2vpn_evpn_summary, show_bgp_evpn_summary_cmd,
             "Summary of BGP neighbor status\n" JSON_STR)
 
 ALIAS_HIDDEN(show_bgp_l2vpn_evpn_route, show_bgp_evpn_route_cmd,
-            "show bgp evpn route [type <macip|multicast>]",
+            "show bgp evpn route [detail] [type <macip|multicast>]",
             SHOW_STR BGP_STR EVPN_HELP_STR
             "EVPN route information\n"
+            "Display Detailed Information\n"
             "Specify Route type\n"
             "MAC-IP (Type-2) route\n"
             "Multicast (Type-3) route\n")
index 80cfb97436e2402176802de305790739d633bd7b..d4f608d40feb49c0ca4a8eeb51ee7315d3dc272e 100644 (file)
@@ -389,9 +389,9 @@ static int as_list_dup_check(struct as_list *aslist, struct as_filter *new)
        return 0;
 }
 
-static int config_bgp_aspath_validate(const char *regstr)
+int config_bgp_aspath_validate(const char *regstr)
 {
-       char valid_chars[] = "1234567890_^|[,{}() ]$*+.?-";
+       char valid_chars[] = "1234567890_^|[,{}() ]$*+.?-\\";
 
        if (strspn(regstr, valid_chars) == strlen(regstr))
                return 1;
@@ -407,7 +407,7 @@ DEFUN(as_path, bgp_as_path_cmd,
       "Regular expression access list name\n"
       "Specify packets to reject\n"
       "Specify packets to forward\n"
-      "A regular-expression (1234567890_(^|[,{}() ]|$)) to match the BGP AS paths\n")
+      "A regular-expression (1234567890_^|[,{}() ]$*+.?-\\) to match the BGP AS paths\n")
 {
        int idx = 0;
        enum as_filter_type type;
@@ -475,7 +475,7 @@ ALIAS(as_path, ip_as_path_cmd,
       "Regular expression access list name\n"
       "Specify packets to reject\n"
       "Specify packets to forward\n"
-      "A regular-expression (1234567890_(^|[,{}() ]|$)) to match the BGP AS paths\n")
+      "A regular-expression (1234567890_^|[,{}() ]$*+.?-\\) to match the BGP AS paths\n")
 
 DEFUN(no_as_path, no_bgp_as_path_cmd,
       "no bgp as-path access-list WORD <deny|permit> LINE...",
@@ -486,7 +486,7 @@ DEFUN(no_as_path, no_bgp_as_path_cmd,
       "Regular expression access list name\n"
       "Specify packets to reject\n"
       "Specify packets to forward\n"
-      "A regular-expression (1234567890_(^|[,{}() ]|$)) to match the BGP AS paths\n")
+      "A regular-expression (1234567890_^|[,{}() ]$*+.?-\\) to match the BGP AS paths\n")
 {
        int idx = 0;
        enum as_filter_type type;
@@ -563,7 +563,7 @@ ALIAS(no_as_path, no_ip_as_path_cmd,
       "Regular expression access list name\n"
       "Specify packets to reject\n"
       "Specify packets to forward\n"
-      "A regular-expression (1234567890_(^|[,{}() ]|$)) to match the BGP AS paths\n")
+      "A regular-expression (1234567890_^|[,{}() ]$*+.?-\\) to match the BGP AS paths\n")
 
 DEFUN (no_as_path_all,
        no_bgp_as_path_all_cmd,
index e54372f8e064e90d38129c723fe397a7f9481106..3c49e357ffddf297479d47e009fb69dec162a15b 100644 (file)
@@ -31,5 +31,6 @@ extern enum as_filter_type as_list_apply(struct as_list *, void *);
 extern struct as_list *as_list_lookup(const char *);
 extern void as_list_add_hook(void (*func)(char *));
 extern void as_list_delete_hook(void (*func)(const char *));
+extern int config_bgp_aspath_validate(const char *regstr);
 
 #endif /* _QUAGGA_BGP_FILTER_H */
index ab8bfcb770c708268db3dcb21a91e1dbd85a433f..9554638735f163f68ec77a537806259d400c517a 100644 (file)
@@ -105,14 +105,14 @@ int bgp_nlri_parse_flowspec(struct peer *peer, struct attr *attr,
 
        if (afi == AFI_IP6) {
                flog_err(EC_LIB_DEVELOPMENT, "BGP flowspec IPv6 not supported");
-               return -1;
+               return BGP_NLRI_PARSE_ERROR_FLOWSPEC_IPV6_NOT_SUPPORTED;
        }
 
        if (packet->length >= FLOWSPEC_NLRI_SIZELIMIT) {
                flog_err(EC_BGP_FLOWSPEC_PACKET,
                         "BGP flowspec nlri length maximum reached (%u)",
                         packet->length);
-               return -1;
+               return BGP_NLRI_PARSE_ERROR_FLOWSPEC_NLRI_SIZELIMIT;
        }
 
        for (; pnt < lim; pnt += psize) {
@@ -121,7 +121,7 @@ int bgp_nlri_parse_flowspec(struct peer *peer, struct attr *attr,
 
                /* All FlowSpec NLRI begin with length. */
                if (pnt + 1 > lim)
-                       return -1;
+                       return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW;
 
                psize = *pnt++;
 
@@ -131,13 +131,13 @@ int bgp_nlri_parse_flowspec(struct peer *peer, struct attr *attr,
                                EC_BGP_FLOWSPEC_PACKET,
                                "Flowspec NLRI length inconsistent ( size %u seen)",
                                psize);
-                       return -1;
+                       return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW;
                }
                if (bgp_fs_nlri_validate(pnt, psize) < 0) {
                        flog_err(
                                EC_BGP_FLOWSPEC_PACKET,
                                "Bad flowspec format or NLRI options not supported");
-                       return -1;
+                       return BGP_NLRI_PARSE_ERROR_FLOWSPEC_BAD_FORMAT;
                }
                p.family = AF_FLOWSPEC;
                p.prefixlen = 0;
@@ -192,8 +192,8 @@ int bgp_nlri_parse_flowspec(struct peer *peer, struct attr *attr,
                        flog_err(EC_BGP_FLOWSPEC_INSTALLATION,
                                 "Flowspec NLRI failed to be %s.",
                                 attr ? "added" : "withdrawn");
-                       return -1;
+                       return BGP_NLRI_PARSE_ERROR;
                }
        }
-       return 0;
+       return BGP_NLRI_PARSE_OK;
 }
index a219c407dabd861f71b68aae00dc0cab95bce357..95116508427776323934dbc191d9f97de548bf2b 100644 (file)
@@ -355,7 +355,7 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr,
 
                        /* When packet overflow occurs return immediately. */
                        if (pnt + BGP_ADDPATH_ID_LEN > lim)
-                               return -1;
+                               return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW;
 
                        addpath_id = ntohl(*((uint32_t *)pnt));
                        pnt += BGP_ADDPATH_ID_LEN;
@@ -372,7 +372,7 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr,
                                EC_BGP_UPDATE_RCV,
                                "%s [Error] Update packet error / L-U (prefix length %d exceeds packet size %u)",
                                peer->host, prefixlen, (uint)(lim - pnt));
-                       return -1;
+                       return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW;
                }
 
                /* Fill in the labels */
@@ -387,12 +387,12 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr,
                                 peer->host, prefixlen);
                        bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
                                        BGP_NOTIFY_UPDATE_INVAL_NETWORK);
-                       return -1;
+                       return BGP_NLRI_PARSE_ERROR_LABEL_LENGTH;
                }
 
                if ((afi == AFI_IP && p.prefixlen > 32)
                    || (afi == AFI_IP6 && p.prefixlen > 128))
-                       return -1;
+                       return BGP_NLRI_PARSE_ERROR_PREFIX_LENGTH;
 
                /* Fetch prefix from NLRI packet */
                memcpy(&p.u.prefix, pnt + llen, psize - llen);
@@ -463,8 +463,8 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr,
                        EC_BGP_UPDATE_RCV,
                        "%s [Error] Update packet error / L-U (%zu data remaining after parsing)",
                        peer->host, lim - pnt);
-               return -1;
+               return BGP_NLRI_PARSE_ERROR_PACKET_LENGTH;
        }
 
-       return 0;
+       return BGP_NLRI_PARSE_OK;
 }
index e42bc441154b935dd426b5e507c6e8c52995ce43..adba73e404659198a29c224bef0f0bffb7738589 100644 (file)
@@ -78,6 +78,7 @@ static const struct option longopts[] = {
        {"skip_runas", no_argument, NULL, 'S'},
        {"ecmp", required_argument, NULL, 'e'},
        {"int_num", required_argument, NULL, 'I'},
+       {"no_zebra", no_argument, NULL, 'Z'},
        {0}};
 
 /* signal definitions */
@@ -387,7 +388,7 @@ int main(int argc, char **argv)
 
        frr_preinit(&bgpd_di, argc, argv);
        frr_opt_add(
-               "p:l:Sne:I:" DEPRECATED_OPTIONS, longopts,
+               "p:l:SnZe:I:" DEPRECATED_OPTIONS, longopts,
                "  -p, --bgp_port     Set BGP listen port number (0 means do not listen).\n"
                "  -l, --listenon     Listen on specified address (implies -n)\n"
                "  -n, --no_kernel    Do not install route to kernel.\n"
index 4c4659ad543959f989200bedb8c757b68c99d140..d7cb84c32358d204edd93a1d62a11f9f6fee62bf 100644 (file)
@@ -140,7 +140,7 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,
 
                        /* When packet overflow occurs return immediately. */
                        if (pnt + BGP_ADDPATH_ID_LEN > lim)
-                               return -1;
+                               return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW;
 
                        addpath_id = ntohl(*((uint32_t *)pnt));
                        pnt += BGP_ADDPATH_ID_LEN;
@@ -156,7 +156,7 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,
                                EC_BGP_UPDATE_RCV,
                                "%s [Error] Update packet error / VPN (prefix length %d less than VPN min length)",
                                peer->host, prefixlen);
-                       return -1;
+                       return BGP_NLRI_PARSE_ERROR_PREFIX_LENGTH;
                }
 
                /* sanity check against packet data */
@@ -165,7 +165,7 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,
                                EC_BGP_UPDATE_RCV,
                                "%s [Error] Update packet error / VPN (prefix length %d exceeds packet size %u)",
                                peer->host, prefixlen, (uint)(lim - pnt));
-                       return -1;
+                       return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW;
                }
 
                /* sanity check against storage for the IP address portion */
@@ -176,7 +176,7 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,
                                peer->host,
                                prefixlen - VPN_PREFIXLEN_MIN_BYTES * 8,
                                sizeof(p.u));
-                       return -1;
+                       return BGP_NLRI_PARSE_ERROR_PACKET_LENGTH;
                }
 
                /* Sanity check against max bitlen of the address family */
@@ -187,7 +187,7 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,
                                peer->host,
                                prefixlen - VPN_PREFIXLEN_MIN_BYTES * 8,
                                p.family, prefix_blen(&p));
-                       return -1;
+                       return BGP_NLRI_PARSE_ERROR_PACKET_LENGTH;
                }
 
                /* Copy label to prefix. */
@@ -245,7 +245,7 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,
                        EC_BGP_UPDATE_RCV,
                        "%s [Error] Update packet error / VPN (%zu data remaining after parsing)",
                        peer->host, lim - pnt);
-               return -1;
+               return BGP_NLRI_PARSE_ERROR_PACKET_LENGTH;
        }
 
        return 0;
index 7b76d7e83e881d1a7fd098bb9e23448cfb3179eb..130e06a6cf1ba887531db13fee05b445dc501391 100644 (file)
@@ -308,7 +308,7 @@ int bgp_nlri_parse(struct peer *peer, struct attr *attr,
        case SAFI_FLOWSPEC:
                return bgp_nlri_parse_flowspec(peer, attr, packet, mp_withdraw);
        }
-       return -1;
+       return BGP_NLRI_PARSE_ERROR;
 }
 
 /*
@@ -1568,10 +1568,11 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size)
                        nlri_ret = bgp_nlri_parse(peer, &attr, &nlris[i], 1);
                        break;
                default:
-                       nlri_ret = -1;
+                       nlri_ret = BGP_NLRI_PARSE_ERROR;
                }
 
-               if (nlri_ret < 0) {
+               if (nlri_ret < BGP_NLRI_PARSE_OK
+                   && nlri_ret != BGP_NLRI_PARSE_ERROR_PREFIX_OVERFLOW) {
                        flog_err(EC_BGP_UPDATE_RCV,
                                 "%s [Error] Error parsing NLRI", peer->host);
                        if (peer->status == Established)
index 7036ededac405dae3f24c2e38920bb6dd76e2edb..063cc24dc1bd69918e6397b14c9ba8d97a4161c7 100644 (file)
@@ -4218,6 +4218,13 @@ static void bgp_cleanup_table(struct bgp *bgp, struct bgp_table *table,
        for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn))
                for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = next) {
                        next = pi->next;
+
+                       /* Unimport EVPN routes from VRFs */
+                       if (safi == SAFI_EVPN)
+                               bgp_evpn_unimport_route(bgp, AFI_L2VPN,
+                                                       SAFI_EVPN,
+                                                       &rn->p, pi);
+
                        if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)
                            && pi->type == ZEBRA_ROUTE_BGP
                            && (pi->sub_type == BGP_ROUTE_NORMAL
@@ -4333,7 +4340,7 @@ int bgp_nlri_parse_ip(struct peer *peer, struct attr *attr,
 
                        /* When packet overflow occurs return immediately. */
                        if (pnt + BGP_ADDPATH_ID_LEN > lim)
-                               return -1;
+                               return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW;
 
                        addpath_id = ntohl(*((uint32_t *)pnt));
                        pnt += BGP_ADDPATH_ID_LEN;
@@ -4351,7 +4358,7 @@ int bgp_nlri_parse_ip(struct peer *peer, struct attr *attr,
                                EC_BGP_UPDATE_RCV,
                                "%s [Error] Update packet error (wrong prefix length %d for afi %u)",
                                peer->host, p.prefixlen, packet->afi);
-                       return -1;
+                       return BGP_NLRI_PARSE_ERROR_PREFIX_LENGTH;
                }
 
                /* Packet size overflow check. */
@@ -4363,7 +4370,7 @@ int bgp_nlri_parse_ip(struct peer *peer, struct attr *attr,
                                EC_BGP_UPDATE_RCV,
                                "%s [Error] Update packet error (prefix length %d overflows packet)",
                                peer->host, p.prefixlen);
-                       return -1;
+                       return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW;
                }
 
                /* Defensive coding, double-check the psize fits in a struct
@@ -4373,7 +4380,7 @@ int bgp_nlri_parse_ip(struct peer *peer, struct attr *attr,
                                EC_BGP_UPDATE_RCV,
                                "%s [Error] Update packet error (prefix length %d too large for prefix storage %zu)",
                                peer->host, p.prefixlen, sizeof(p.u));
-                       return -1;
+                       return BGP_NLRI_PARSE_ERROR_PACKET_LENGTH;
                }
 
                /* Fetch prefix from NLRI packet. */
@@ -4438,10 +4445,14 @@ int bgp_nlri_parse_ip(struct peer *peer, struct attr *attr,
                                           BGP_ROUTE_NORMAL, NULL, NULL, 0,
                                           NULL);
 
-               /* Address family configuration mismatch or maximum-prefix count
-                  overflow. */
+               /* Do not send BGP notification twice when maximum-prefix count
+                * overflow. */
+               if (CHECK_FLAG(peer->sflags, PEER_STATUS_PREFIX_OVERFLOW))
+                       return BGP_NLRI_PARSE_ERROR_PREFIX_OVERFLOW;
+
+               /* Address family configuration mismatch. */
                if (ret < 0)
-                       return -1;
+                       return BGP_NLRI_PARSE_ERROR_ADDRESS_FAMILY;
        }
 
        /* Packet length consistency check. */
@@ -4450,10 +4461,10 @@ int bgp_nlri_parse_ip(struct peer *peer, struct attr *attr,
                        EC_BGP_UPDATE_RCV,
                        "%s [Error] Update packet error (prefix length mismatch with total length)",
                        peer->host);
-               return -1;
+               return BGP_NLRI_PARSE_ERROR_PACKET_LENGTH;
        }
 
-       return 0;
+       return BGP_NLRI_PARSE_OK;
 }
 
 static struct bgp_static *bgp_static_new(void)
@@ -9927,7 +9938,7 @@ DEFUN (show_ip_bgp_regexp,
        BGP_AFI_HELP_STR
        BGP_SAFI_WITH_LABEL_HELP_STR
        "Display routes matching the AS path regular expression\n"
-       "A regular-expression to match the BGP AS paths\n")
+       "A regular-expression (1234567890_^|[,{}() ]$*+.?-\\) to match the BGP AS paths\n")
 {
        afi_t afi = AFI_IP6;
        safi_t safi = SAFI_UNICAST;
@@ -9985,6 +9996,12 @@ static int bgp_show_regexp(struct vty *vty, struct bgp *bgp, const char *regstr,
        regex_t *regex;
        int rc;
 
+       if (!config_bgp_aspath_validate(regstr)) {
+               vty_out(vty, "Invalid character in as-path access-list %s\n",
+                       regstr);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
        regex = bgp_regcomp(regstr);
        if (!regex) {
                vty_out(vty, "Can't compile regexp %s\n", regstr);
index a559a6b58cb4390acd6045f7d5c0adf8de509190..7bbc14b46f2b11444d2a7ce32600ea02f24f40d9 100644 (file)
@@ -73,6 +73,24 @@ enum bgp_show_adj_route_type {
  */
 #define BGP_MAX_LABELS 2
 
+/* Error codes for handling NLRI */
+#define BGP_NLRI_PARSE_OK 0
+#define BGP_NLRI_PARSE_ERROR_PREFIX_OVERFLOW -1
+#define BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW -2
+#define BGP_NLRI_PARSE_ERROR_PREFIX_LENGTH -3
+#define BGP_NLRI_PARSE_ERROR_PACKET_LENGTH -4
+#define BGP_NLRI_PARSE_ERROR_LABEL_LENGTH -5
+#define BGP_NLRI_PARSE_ERROR_EVPN_MISSING_TYPE -6
+#define BGP_NLRI_PARSE_ERROR_EVPN_TYPE2_SIZE -7
+#define BGP_NLRI_PARSE_ERROR_EVPN_TYPE3_SIZE -8
+#define BGP_NLRI_PARSE_ERROR_EVPN_TYPE4_SIZE -9
+#define BGP_NLRI_PARSE_ERROR_EVPN_TYPE5_SIZE -10
+#define BGP_NLRI_PARSE_ERROR_FLOWSPEC_IPV6_NOT_SUPPORTED -11
+#define BGP_NLRI_PARSE_ERROR_FLOWSPEC_NLRI_SIZELIMIT -12
+#define BGP_NLRI_PARSE_ERROR_FLOWSPEC_BAD_FORMAT -13
+#define BGP_NLRI_PARSE_ERROR_ADDRESS_FAMILY -14
+#define BGP_NLRI_PARSE_ERROR -32
+
 /* Ancillary information to struct bgp_path_info,
  * used for uncommonly used data (aggregation, MPLS, etc.)
  * and lazily allocated to save memory.
index 9004926dee5edb5dcf9cdd821365b9999cd16fd5..01144f5c78ae94346297540e51ed5a1972b89a87 100644 (file)
@@ -3943,6 +3943,13 @@ ALIAS_HIDDEN(neighbor_nexthop_self_force,
             "Disable the next hop calculation for this neighbor\n"
             "Set the next hop to self for reflected routes\n")
 
+ALIAS_HIDDEN(neighbor_nexthop_self_force,
+            neighbor_nexthop_self_all_hidden_cmd,
+            "neighbor <A.B.C.D|X:X::X:X|WORD> next-hop-self all",
+            NEIGHBOR_STR NEIGHBOR_ADDR_STR2
+            "Disable the next hop calculation for this neighbor\n"
+            "Set the next hop to self for reflected routes\n")
+
 DEFUN (no_neighbor_nexthop_self,
        no_neighbor_nexthop_self_cmd,
        "no neighbor <A.B.C.D|X:X::X:X|WORD> next-hop-self",
@@ -3984,6 +3991,13 @@ ALIAS_HIDDEN(no_neighbor_nexthop_self_force,
             "Disable the next hop calculation for this neighbor\n"
             "Set the next hop to self for reflected routes\n")
 
+ALIAS_HIDDEN(no_neighbor_nexthop_self_force,
+            no_neighbor_nexthop_self_all_hidden_cmd,
+            "no neighbor <A.B.C.D|X:X::X:X|WORD> next-hop-self all",
+            NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
+            "Disable the next hop calculation for this neighbor\n"
+            "Set the next hop to self for reflected routes\n")
+
 /* neighbor as-override */
 DEFUN (neighbor_as_override,
        neighbor_as_override_cmd,
@@ -13234,6 +13248,8 @@ void bgp_vty_init(void)
        /* "neighbor next-hop-self force" commands. */
        install_element(BGP_NODE, &neighbor_nexthop_self_force_hidden_cmd);
        install_element(BGP_NODE, &no_neighbor_nexthop_self_force_hidden_cmd);
+       install_element(BGP_NODE, &neighbor_nexthop_self_all_hidden_cmd);
+       install_element(BGP_NODE, &no_neighbor_nexthop_self_all_hidden_cmd);
        install_element(BGP_IPV4_NODE, &neighbor_nexthop_self_force_cmd);
        install_element(BGP_IPV4_NODE, &no_neighbor_nexthop_self_force_cmd);
        install_element(BGP_IPV4M_NODE, &neighbor_nexthop_self_force_cmd);
index 55ecc5f16ced7588268e613ded1410ceb2b0eb5b..e42d6ee260358528b52e35efaacc0a602e865a6e 100644 (file)
@@ -2553,12 +2553,14 @@ static int bgp_zebra_process_local_vni(int command, struct zclient *zclient,
        struct bgp *bgp;
        struct in_addr vtep_ip = {INADDR_ANY};
        vrf_id_t tenant_vrf_id = VRF_DEFAULT;
+       struct in_addr mcast_grp = {INADDR_ANY};
 
        s = zclient->ibuf;
        vni = stream_getl(s);
        if (command == ZEBRA_VNI_ADD) {
                vtep_ip.s_addr = stream_get_ipv4(s);
                stream_get(&tenant_vrf_id, s, sizeof(vrf_id_t));
+               mcast_grp.s_addr = stream_get_ipv4(s);
        }
 
        bgp = bgp_lookup_by_vrf_id(vrf_id);
@@ -2574,7 +2576,7 @@ static int bgp_zebra_process_local_vni(int command, struct zclient *zclient,
        if (command == ZEBRA_VNI_ADD)
                return bgp_evpn_local_vni_add(
                        bgp, vni, vtep_ip.s_addr ? vtep_ip : bgp->router_id,
-                       tenant_vrf_id);
+                       tenant_vrf_id, mcast_grp);
        else
                return bgp_evpn_local_vni_del(bgp, vni);
 }
index f4f38a63e904fcbd50d9119e2f46d495e7ef1120..41c31b29c3dd80d7ef967cdedd91d7ac6d6563c0 100644 (file)
@@ -4,76 +4,76 @@ OSPF API Documentation
 Disclaimer
 ----------
 
-The OSPF daemon contains an API for application access to the LSA
-database. This API was created by Ralph Keller, originally as patch for
-Zebra. Unfortunately, the page containing documentation of the API is no
-longer online. This page is an attempt to recreate documentation for the
-API (with lots of help of the WayBackMachine)
+The OSPF daemon contains an API for application access to the LSA database.
+This API and documentation was created by Ralph Keller, originally as patch for
+Zebra. Unfortunately, the page containing documentation for the API is no
+longer online. This page is an attempt to recreate documentation for the API
+(with lots of help from the WayBackMachine).
+
+Ralph has kindly licensed this documentation under GPLv2+. Please preserve the
+acknowledgements at the bottom of this document.
 
 Introduction
 ------------
 
-This page describes an API that allows external applications to access
-the link-state database (LSDB) of the OSPF daemon. The implementation is
-based on the OSPF code from FRRouting (forked from Quagga and formerly
-Zebra) routing protocol suite and is subject to the GNU General Public
-License. The OSPF API provides you with the following functionality:
-
--  Retrieval of the full or partial link-state database of the OSPF
-   daemon. This allows applications to obtain an exact copy of the LSDB
-   including router LSAs, network LSAs and so on. Whenever a new LSA
-   arrives at the OSPF daemon, the API module immediately informs the
-   application by sending a message. This way, the application is always
-   synchronized with the LSDB of the OSPF daemon.
--  Origination of own opaque LSAs (of type 9, 10, or 11) which are then
-   distributed transparently to other routers within the flooding scope
-   and received by other applications through the OSPF API.
-
-Opaque LSAs, which are described in RFC 2370 , allow you to distribute
-application-specific information within a network using the OSPF
-protocol. The information contained in opaque LSAs is transparent for
-the routing process but it can be processed by other modules such as
-traffic engineering (e.g., MPLS-TE).
+This page describes an API that allows external applications to access the
+link-state database (LSDB) of the OSPF daemon. The implementation is based on
+the OSPF code from FRRouting (forked from Quagga and formerly Zebra) routing
+protocol suite and is subject to the GNU General Public License. The OSPF API
+provides you with the following functionality:
+
+- Retrieval of the full or partial link-state database of the OSPF daemon.
+  This allows applications to obtain an exact copy of the LSDB including router
+  LSAs, network LSAs and so on. Whenever a new LSA arrives at the OSPF daemon,
+  the API module immediately informs the application by sending a message. This
+  way, the application is always synchronized with the LSDB of the OSPF daemon.
+- Origination of own opaque LSAs (of type 9, 10, or 11) which are then
+  distributed transparently to other routers within the flooding scope and
+  received by other applications through the OSPF API.
+
+Opaque LSAs, which are described in :rfc:`2370`, allow you to distribute
+application-specific information within a network using the OSPF protocol. The
+information contained in opaque LSAs is transparent for the routing process but
+it can be processed by other modules such as traffic engineering (e.g.,
+MPLS-TE).
 
 Architecture
 ------------
 
-The following picture depicts the architecture of the Quagga/Zebra
-protocol suite. The OSPF daemon is extended with opaque LSA capabilities
-and an API for external applications. The OSPF core module executes the
-OSPF protocol by discovering neighbors and exchanging neighbor state.
-The opaque module, implemented by Masahiko Endo, provides functions to
-exchange opaque LSAs between routers. Opaque LSAs can be generated by
-several modules such as the MPLS-TE module or the API server module.
-These modules then invoke the opaque module to flood their data to
-neighbors within the flooding scope.
-
-The client, which is an application potentially running on a different
-node than the OSPF daemon, links against the OSPF API client library.
-This client library establishes a socket connection with the API server
-module of the OSPF daemon and uses this connection to retrieve LSAs and
-originate opaque LSAs.
+The following picture depicts the architecture of the Quagga/Zebra protocol
+suite. The OSPF daemon is extended with opaque LSA capabilities and an API for
+external applications. The OSPF core module executes the OSPF protocol by
+discovering neighbors and exchanging neighbor state.  The opaque module,
+implemented by Masahiko Endo, provides functions to exchange opaque LSAs
+between routers. Opaque LSAs can be generated by several modules such as the
+MPLS-TE module or the API server module.  These modules then invoke the opaque
+module to flood their data to neighbors within the flooding scope.
+
+The client, which is an application potentially running on a different node
+than the OSPF daemon, links against the OSPF API client library.  This client
+library establishes a socket connection with the API server module of the OSPF
+daemon and uses this connection to retrieve LSAs and originate opaque LSAs.
 
 .. figure:: ../figures/ospf_api_architecture.png
    :alt: image
 
    image
 
-The OSPF API server module works like any other internal opaque module
-(such as the MPLS-TE module), but listens to connections from external
-applications that want to communicate with the OSPF daemon. The API
-server module can handle multiple clients concurrently.
+The OSPF API server module works like any other internal opaque module (such as
+the MPLS-TE module), but listens to connections from external applications that
+want to communicate with the OSPF daemon. The API server module can handle
+multiple clients concurrently.
 
-One of the main objectives of the implementation is to make as little
-changes to the existing Zebra code as possible.
+One of the main objectives of the implementation is to make as little changes
+to the existing Zebra code as possible.
 
 Installation & Configuration
 ----------------------------
 
-Download FRRouting and unpack
+Download FRRouting and unpack it.
 
-Configure your frr version (note that --enable-opaque-lsa also enables
-the ospfapi server and ospfclient).
+Configure and build FRR (note that ``--enable-opaque-lsa`` also enables the
+ospfapi server and ospfclient).
 
 ::
 
@@ -83,8 +83,8 @@ the ospfapi server and ospfclient).
 This should also compile the client library and sample application in
 ospfclient.
 
-Make sure that you have enabled opaque LSAs in your configuration. Add
-the ospf opaque-lsa statement to your ospfd.conf:
+Make sure that you have enabled opaque LSAs in your configuration. Add the
+``ospf opaque-lsa`` statement to your :file:`ospfd.conf`:
 
 ::
 
@@ -108,171 +108,165 @@ Usage
 -----
 
 In the following we describe how you can use the sample application to
-originate opaque LSAs. The sample application first registers with the
-OSPF daemon the opaque type it wants to inject and then waits until the
-OSPF daemon is ready to accept opaque LSAs of that type. Then the client
-application originates an opaque LSA, waits 10 seconds and then updates
-the opaque LSA with new opaque data. After another 20 seconds, the
-client application deletes the opaque LSA from the LSDB. If the clients
-terminates unexpectedly, the OSPF API module will remove all the opaque
-LSAs that the application registered. Since the opaque LSAs are flooded
-to other routers, we will see the opaque LSAs in all routers according
-to the flooding scope of the opaque LSA.
+originate opaque LSAs. The sample application first registers with the OSPF
+daemon the opaque type it wants to inject and then waits until the OSPF daemon
+is ready to accept opaque LSAs of that type. Then the client application
+originates an opaque LSA, waits 10 seconds and then updates the opaque LSA with
+new opaque data. After another 20 seconds, the client application deletes the
+opaque LSA from the LSDB. If the clients terminates unexpectedly, the OSPF API
+module will remove all the opaque LSAs that the application registered. Since
+the opaque LSAs are flooded to other routers, we will see the opaque LSAs in
+all routers according to the flooding scope of the opaque LSA.
 
 We have a very simple demo setup, just two routers connected with an ATM
-point-to-point link. Start the modified OSPF daemons on two adjacent
-routers. First run on msr2:
+point-to-point link. Start the modified OSPF daemons on two adjacent routers.
+First run on msr2:
 
-::
+.. code-block:: console
 
-        > msr2:/home/keller/ospfapi/zebra/ospfd# ./ospfd -f /usr/local/etc/ospfd.conf
+   # ./ospfd --apiserver -f /usr/local/etc/ospfd.conf
 
 And on the neighboring router msr3:
 
-::
+.. code-block:: console
 
-        > msr3:/home/keller/ospfapi/zebra/ospfd# ./ospfd -f /usr/local/etc/ospfd.conf
+   # ./ospfd --apiserver -f /usr/local/etc/ospfd.conf
 
 Now the two routers form adjacency and start exchanging their databases.
 Looking at the OSPF daemon of msr2 (or msr3), you see this:
 
-::
+.. code-block:: console
 
-        ospfd> show ip ospf database
+   ospfd> show ip ospf database
 
-               OSPF Router with ID (10.0.0.1)
+          OSPF Router with ID (10.0.0.1)
 
-                        Router Link States (Area 0.0.0.1)
+                   Router Link States (Area 0.0.0.1)
 
-        Link ID         ADV Router      Age  Seq#       CkSum  Link count
-        10.0.0.1        10.0.0.1          55 0x80000003 0xc62f 2
-        10.0.0.2        10.0.0.2          55 0x80000003 0xe3e4 3
+   Link ID         ADV Router      Age  Seq#       CkSum  Link count
+   10.0.0.1        10.0.0.1          55 0x80000003 0xc62f 2
+   10.0.0.2        10.0.0.2          55 0x80000003 0xe3e4 3
 
-                        Net Link States (Area 0.0.0.1)
+                   Net Link States (Area 0.0.0.1)
 
-        Link ID         ADV Router      Age  Seq#       CkSum
-        10.0.0.2        10.0.0.2          60 0x80000001 0x5fcb
+   Link ID         ADV Router      Age  Seq#       CkSum
+   10.0.0.2        10.0.0.2          60 0x80000001 0x5fcb
 
 Now we start the sample main application that originates an opaque LSA.
 
-::
+.. code-block:: console
 
-        > cd ospfapi/apiclient
-        > ./main msr2 10 250 20 0.0.0.0 0.0.0.1
+   # cd ospfapi/apiclient
+   # ./main msr2 10 250 20 0.0.0.0 0.0.0.1
 
-This originates an opaque LSA of type 10 (area local), with opaque type
-250 (experimental), opaque id of 20 (chosen arbitrarily), interface
-address 0.0.0.0 (which is used only for opaque LSAs type 9), and area
-0.0.0.1
+This originates an opaque LSA of type 10 (area local), with opaque type 250
+(experimental), opaque id of 20 (chosen arbitrarily), interface address 0.0.0.0
+(which is used only for opaque LSAs type 9), and area 0.0.0.1
 
 Again looking at the OSPF database you see:
 
-::
+.. code-block:: console
 
-        ospfd> show ip ospf database
+   ospfd> show ip ospf database
 
-               OSPF Router with ID (10.0.0.1)
+          OSPF Router with ID (10.0.0.1)
 
-                        Router Link States (Area 0.0.0.1)
+                   Router Link States (Area 0.0.0.1)
 
-        Link ID         ADV Router      Age  Seq#       CkSum  Link count
-        10.0.0.1        10.0.0.1         437 0x80000003 0xc62f 2
-        10.0.0.2        10.0.0.2         437 0x80000003 0xe3e4 3
+   Link ID         ADV Router      Age  Seq#       CkSum  Link count
+   10.0.0.1        10.0.0.1         437 0x80000003 0xc62f 2
+   10.0.0.2        10.0.0.2         437 0x80000003 0xe3e4 3
 
-                        Net Link States (Area 0.0.0.1)
+                   Net Link States (Area 0.0.0.1)
 
-        Link ID         ADV Router      Age  Seq#       CkSum
-        10.0.0.2        10.0.0.2         442 0x80000001 0x5fcb
+   Link ID         ADV Router      Age  Seq#       CkSum
+   10.0.0.2        10.0.0.2         442 0x80000001 0x5fcb
 
-                        Area-Local Opaque-LSA (Area 0.0.0.1)
+                   Area-Local Opaque-LSA (Area 0.0.0.1)
 
-        Opaque-Type/Id  ADV Router      Age  Seq#       CkSum
-        250.0.0.20      10.0.0.1           0 0x80000001 0x58a6  <=== opaque LSA
+   Opaque-Type/Id  ADV Router      Age  Seq#       CkSum
+   250.0.0.20      10.0.0.1           0 0x80000001 0x58a6  <=== opaque LSA
 
 You can take a closer look at this opaque LSA:
 
-::
+.. code-block:: console
 
-           ospfd> show ip ospf database opaque-area
+   ospfd> show ip ospf database opaque-area
 
-           OSPF Router with ID (10.0.0.1)
+          OSPF Router with ID (10.0.0.1)
 
 
-           Area-Local Opaque-LSA (Area 0.0.0.1)
+                   Area-Local Opaque-LSA (Area 0.0.0.1)
 
-           LS age: 4
-           Options: 66
-           LS Type: Area-Local Opaque-LSA
-           Link State ID: 250.0.0.20 (Area-Local Opaque-Type/ID)
-           Advertising Router: 10.0.0.1
-           LS Seq Number: 80000001
-           Checksum: 0x58a6
-           Length: 24
-           Opaque-Type 250 (Private/Experimental)
-           Opaque-ID 0x14
-           Opaque-Info: 4 octets of data
-           Added using OSPF API: 4 octets of opaque data
-           Opaque data: 1 0 0 0 <==== counter is 1
+   LS age: 4
+   Options: 66
+   LS Type: Area-Local Opaque-LSA
+   Link State ID: 250.0.0.20 (Area-Local Opaque-Type/ID)
+   Advertising Router: 10.0.0.1
+   LS Seq Number: 80000001
+   Checksum: 0x58a6
+   Length: 24
+   Opaque-Type 250 (Private/Experimental)
+   Opaque-ID 0x14
+   Opaque-Info: 4 octets of data
+   Added using OSPF API: 4 octets of opaque data
+   Opaque data: 1 0 0 0 <==== counter is 1
 
-Note that the main application updates the opaque LSA after 10 seconds,
-then it looks as follows:
+Note that the main application updates the opaque LSA after 10 seconds, then it
+looks as follows:
 
-::
+.. code-block:: console
 
-        ospfd> show ip ospf database opaque-area
+   ospfd> show ip ospf database opaque-area
 
-               OSPF Router with ID (10.0.0.1)
+          OSPF Router with ID (10.0.0.1)
 
 
-                        Area-Local Opaque-LSA (Area 0.0.0.1)
+                   Area-Local Opaque-LSA (Area 0.0.0.1)
 
-          LS age: 1
-          Options: 66
-          LS Type: Area-Local Opaque-LSA
-          Link State ID: 250.0.0.20 (Area-Local Opaque-Type/ID)
-          Advertising Router: 10.0.0.1
-          LS Seq Number: 80000002
-          Checksum: 0x59a3
-          Length: 24
-          Opaque-Type 250 (Private/Experimental)
-          Opaque-ID   0x14
-          Opaque-Info: 4 octets of data
-          Added using OSPF API: 4 octets of opaque data
-          Opaque data: 2 0 0 0  <==== counter is now 2
+   LS age: 1
+   Options: 66
+   LS Type: Area-Local Opaque-LSA
+   Link State ID: 250.0.0.20 (Area-Local Opaque-Type/ID)
+   Advertising Router: 10.0.0.1
+   LS Seq Number: 80000002
+   Checksum: 0x59a3
+   Length: 24
+   Opaque-Type 250 (Private/Experimental)
+   Opaque-ID   0x14
+   Opaque-Info: 4 octets of data
+   Added using OSPF API: 4 octets of opaque data
+   Opaque data: 2 0 0 0  <==== counter is now 2
 
-Note that the payload of the opaque LSA has changed as you can see
-above.
+Note that the payload of the opaque LSA has changed as you can see above.
 
-Then, again after another 20 seconds, the opaque LSA is flushed from the
-LSDB.
+Then, again after another 20 seconds, the opaque LSA is flushed from the LSDB.
 
 Important note:
 ^^^^^^^^^^^^^^^
 
 In order to originate an opaque LSA, there must be at least one active
-opaque-capable neighbor. Thus, you cannot originate opaque LSAs of no
-neighbors are present. If you try to originate even so no neighbor is
-ready, you will receive a not ready error message. The reason for this
-restriction is that it might be possible that some routers have an
-identical opaque LSA from a previous origination in their LSDB that
-unfortunately could not be flushed due to a crash, and now if the router
-comes up again and starts originating a new opaque LSA, the new opaque
-LSA is considered older since it has a lower sequence number and is
-ignored by other routers (that consider the stalled opaque LSA as more
-recent). However, if the originating router first synchronizes the
-database before originating opaque LSAs, it will detect the older opaque
-LSA and can flush it first.
+opaque-capable neighbor. Thus, you cannot originate opaque LSAs if no neighbors
+are present. If you try to originate when no neighbors are ready, you will
+receive a not ready error message. The reason for this restriction is that it
+might be possible that some routers have an identical opaque LSA from a
+previous origination in their LSDB that unfortunately could not be flushed due
+to a crash, and now if the router comes up again and starts originating a new
+opaque LSA, the new opaque LSA is considered older since it has a lower
+sequence number and is ignored by other routers (that consider the stalled
+opaque LSA as more recent). However, if the originating router first
+synchronizes the database before originating opaque LSAs, it will detect the
+older opaque LSA and can flush it first.
 
 Protocol and Message Formats
 ----------------------------
 
-If you are developing your own client application and you don't want to
-make use of the client library (due to the GNU license restriction or
-whatever reason), you can implement your own client-side message
-handling. The OSPF API uses two connections between the client and the
-OSPF API server: One connection is used for a synchronous request /reply
-protocol and another connection is used for asynchronous notifications
-(e.g., LSA update, neighbor status change).
+If you are developing your own client application and you don't want to make
+use of the client library (due to the GNU license restriction or whatever
+reason), you can implement your own client-side message handling. The OSPF API
+uses two connections between the client and the OSPF API server: One connection
+is used for a synchronous request /reply protocol and another connection is
+used for asynchronous notifications (e.g., LSA update, neighbor status change).
 
 Each message begins with the following header:
 
@@ -326,8 +320,8 @@ The synchronous requests and replies have the following message formats:
 
    image
 
-The origin field allows to select according to the following types of
-origins:
+The origin field allows origin-based filtering using the following origin
+types:
 
 +-------------------------+---------+
 | Origin                  | Value   |
@@ -339,7 +333,7 @@ origins:
 | ANY\_ORIGIN             | 2       |
 +-------------------------+---------+
 
-The reply message has on of the following error codes:
+The reply message has one of the following error codes:
 
 +--------------------------+---------+
 | Error code               | Value   |
@@ -372,16 +366,18 @@ The asynchronous notifications have the following message formats:
 
    image
 
+
+.. Do not delete these acknowledgements!
+
 Original Acknowledgments from Ralph Keller
 ------------------------------------------
 
-I would like to thank Masahiko Endo, the author of the opaque LSA
-extension module, for his great support. His wonderful ASCII graphs
-explaining the internal workings of this code, and his invaluable input
-proved to be crucial in designing a useful API for accessing the link
-state database of the OSPF daemon. Once, he even decided to take the
-plane from Tokyo to Zurich so that we could actually meet and have
-face-to-face discussions, which was a lot of fun. Clearly, without
-Masahiko no API would ever be completed. I also would like to thank
-Daniel Bauer who wrote an opaque LSA implementation too and was willing
+I would like to thank Masahiko Endo, the author of the opaque LSA extension
+module, for his great support. His wonderful ASCII graphs explaining the
+internal workings of this code, and his invaluable input proved to be crucial
+in designing a useful API for accessing the link state database of the OSPF
+daemon. Once, he even decided to take the plane from Tokyo to Zurich so that we
+could actually meet and have face-to-face discussions, which was a lot of fun.
+Clearly, without Masahiko no API would ever be completed. I also would like to
+thank Daniel Bauer who wrote an opaque LSA implementation too and was willing
 to test the OSPF API code in one of his projects.
index 6e4d093f69aa51e8a741b7311ade6ce111e8dd93..951a0229aa194a836e2f74439f50cceacba11b37 100644 (file)
@@ -22,6 +22,10 @@ OPTIONS available for the |DAEMON| command:
 
 .. include:: common-options.rst
 
+.. option:: -a, --apiserver
+
+   Enable the OSPF API server.
+
 FILES
 =====
 
index ad0a8639a34a5ff09dc9bb72171aea936731a7b7..83e14d474f0a6ff76b0a764430bfbb3dc646e553 100644 (file)
@@ -26,7 +26,7 @@ Configuring OSPF
 
 .. option:: -a, --apiserver
 
-   Enable the OSPF API server
+   Enable the OSPF API server. This is required to use ``ospfclient``.
 
 *ospfd* must acquire interface information from *zebra* in order to function.
 Therefore *zebra* must be running before invoking *ospfd*. Also, if *zebra* is
index 6aa946229729cb34f601b5b1c509756d1ce98c2c..7f8ea392dc6512b84883ff6b6f8b05314ff2bee0 100644 (file)
@@ -228,6 +228,8 @@ features with system dependencies are included here.
 +-----------------------------------+----------------+--------------+------------+------------+------------+
 |    ASM (Any Source)               | :mark:`Y`      | :mark:`N`    | :mark:`N`  | :mark:`N`  | :mark:`N`  |
 +-----------------------------------+----------------+--------------+------------+------------+------------+
+|    EVPN BUM Forwarding            | :mark:`≥5.0`   | :mark:`N`    | :mark:`N`  | :mark:`N`  | :mark:`N`  |
++-----------------------------------+----------------+--------------+------------+------------+------------+
 
 The indicators have the following semantics:
 
index f4611c520b16c0e33404647713687df1d2091215..5148d3baff18a9dad2e78bea440234afeb58b0b0 100644 (file)
@@ -8,7 +8,8 @@ PIM -- Protocol Independent Multicast
 
 *pimd* supports pim-sm as well as igmp v2 and v3. pim is
 vrf aware and can work within the context of vrf's in order to
-do S,G mrouting.
+do S,G mrouting.  Additionally PIM can be used in the EVPN underlay
+network for optimizing forwarding of overlay BUM traffic.
 
 .. _starting-and-stopping-pimd:
 
@@ -292,10 +293,14 @@ cause great confusion.
 
    Display various information about the interfaces used in this pim instance.
 
-.. index:: show ip mroute
-.. clicmd:: show ip mroute
+.. index:: show ip mroute [vrf NAME] [A.B.C.D [A.B.C.D]] [fill] [json]
+.. clicmd:: show ip mroute [vrf NAME] [A.B.C.D [A.B.C.D]] [fill] [json]
 
-   Display information about installed into the kernel S,G mroutes.
+   Display information about installed into the kernel S,G mroutes.  If
+   one address is specified we assume it is the Group we are interested
+   in displaying data on.  If the second address is specified then it is
+   Source Group.  The keyword `fill` says to fill in all assumed data
+   for test/data gathering purposes.
 
 .. index:: show ip mroute count
 .. clicmd:: show ip mroute count
@@ -333,10 +338,12 @@ cause great confusion.
 
    Display information about interfaces PIM is using.
 
-.. index:: show ip pim join
+.. index:: show ip pim [vrf NAME] join [A.B.C.D [A.B.C.D]] [json]
 .. clicmd:: show ip pim join
 
-   Display information about PIM joins received.
+   Display information about PIM joins received.  If one address is specified
+   then we assume it is the Group we are interested in displaying data on.
+   If the second address is specified then it is Source Group.
 
 .. index:: show ip pim local-membership
 .. clicmd:: show ip pim local-membership
@@ -383,10 +390,11 @@ cause great confusion.
    Display information about known S,G's and incoming interface as well as the
    OIL and how they were chosen.
 
-.. index:: show ip pim upstream
+.. index:: show ip pim [vrf NAME] upstream [A.B.C.D [A.B.C.D]] [json]
 .. clicmd:: show ip pim upstream
 
-   Display upstream information about a S,G mroute.
+   Display upstream information about a S,G mroute.  Allow the user to
+   specify sub Source and Groups that we are only interested in.
 
 .. index:: show ip pim upstream-join-desired
 .. clicmd:: show ip pim upstream-join-desired
@@ -495,3 +503,28 @@ Clear commands reset various variables.
 .. clicmd:: clear ip pim oil
 
    Rescan PIM OIL (output interface list).
+
+PIM EVPN configuration
+======================
+To use PIM in the underlay for overlay BUM forwarding associate a multicast
+group with the L2 VNI. The actual configuration is based on your distribution.
+Here is an ifupdown2 example::
+
+   auto vx-10100
+   iface vx-10100
+       vxlan-id 10100
+       bridge-access 100
+       vxlan-local-tunnelip 27.0.0.11
+       vxlan-mcastgrp 239.1.1.100
+
+.. note::
+
+   PIM will see the ``vxlan-mcastgrp`` configuration and auto configure state
+   to properly forward BUM traffic.
+
+PIM also needs to be configured in the underlay to allow the BUM MDT to be
+setup. This is existing PIM configuration:
+
+- Enable pim on the underlay L3 interface via the "ip pim" command.
+- Configure RPs for the BUM multicast group range.
+- Ensure the PIM is enabled on the lo of the VTEPs and the RP.
index 52f68eff5ab693928b554b1459590efbac7d4920..5f7be160341a1f720744d7dddd516bd91e675124 100644 (file)
@@ -136,8 +136,6 @@ DEFPY(ip_router_isis, ip_router_isis_cmd, "ip router isis WORD$tag",
        const char *circ_type;
        struct isis_area *area;
        struct interface *ifp;
-       const struct lyd_node *dnode =
-               yang_dnode_get(running_config->dnode, VTY_CURR_XPATH);
 
        /* area will be created if it is not present. make sure the yang model
         * is synced with FRR and call the appropriate NB cb.
@@ -190,7 +188,7 @@ DEFPY(ip_router_isis, ip_router_isis_cmd, "ip router isis WORD$tag",
        }
 
        /* check if the interface is a loopback and if so set it as passive */
-       ifp = yang_dnode_get_entry(dnode, false);
+       ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
        if (ifp && if_is_loopback(ifp))
                nb_cli_enqueue_change(vty, "./frr-isisd:isis/passive",
                                      NB_OP_MODIFY, "true");
@@ -208,8 +206,6 @@ DEFPY(ip6_router_isis, ip6_router_isis_cmd, "ipv6 router isis WORD$tag",
        const char *circ_type;
        struct isis_area *area;
        struct interface *ifp;
-       const struct lyd_node *dnode =
-               yang_dnode_get(running_config->dnode, VTY_CURR_XPATH);
 
        /* area will be created if it is not present. make sure the yang model
         * is synced with FRR and call the appropriate NB cb.
@@ -262,7 +258,7 @@ DEFPY(ip6_router_isis, ip6_router_isis_cmd, "ipv6 router isis WORD$tag",
        }
 
        /* check if the interface is a loopback and if so set it as passive */
-       ifp = yang_dnode_get_entry(dnode, false);
+       ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
        if (ifp && if_is_loopback(ifp))
                nb_cli_enqueue_change(vty, "./frr-isisd:isis/passive",
                                      NB_OP_MODIFY, "true");
@@ -373,9 +369,9 @@ DEFPY(no_is_type, no_is_type_cmd,
       "Act as an area router only\n")
 {
        const char *value = NULL;
-       const struct lyd_node *dnode =
-               yang_dnode_get(running_config->dnode, VTY_CURR_XPATH);
-       struct isis_area *area = yang_dnode_get_entry(dnode, false);
+       struct isis_area *area;
+
+       area = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
 
        /*
         * Put the is-type back to defaults:
@@ -1761,7 +1757,6 @@ DEFPY(no_isis_circuit_type, no_isis_circuit_type_cmd,
       "Level-1-2 adjacencies are formed\n"
       "Level-2 only adjacencies are formed\n")
 {
-       const struct lyd_node *dnode;
        struct interface *ifp;
        struct isis_circuit *circuit;
        int is_type;
@@ -1772,8 +1767,7 @@ DEFPY(no_isis_circuit_type, no_isis_circuit_type_cmd,
         * and the is-type of the area if there is one. So we need to do this
         * here.
         */
-       dnode = yang_dnode_get(running_config->dnode, VTY_CURR_XPATH);
-       ifp = yang_dnode_get_entry(dnode, false);
+       ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
        if (!ifp)
                goto def_val;
 
index c24917454a8556bb7897cf87fbf15b9ebc2f4039..2ce68262ebd7e3822bc7df45cf66641d8df4cff2 100644 (file)
@@ -28,7 +28,6 @@
 #include "hash.h"
 #include "if.h"
 #include "command.h"
-#include "log_int.h"
 
 #include "isisd/dict.h"
 #include "isisd/isis_constants.h"
index 8b26a7397549ff1fea88ff6e9983c532a33cd3ce..95595e37b9d904183ebb5d3a8467f912861e9274 100644 (file)
@@ -67,7 +67,7 @@ static int isis_instance_create(enum nb_event event,
 
        area = isis_area_create(area_tag);
        /* save area in dnode to avoid looking it up all the time */
-       yang_dnode_set_entry(dnode, area);
+       nb_running_set_entry(dnode, area);
 
        return NB_OK;
 }
@@ -75,13 +75,13 @@ static int isis_instance_create(enum nb_event event,
 static int isis_instance_destroy(enum nb_event event,
                                const struct lyd_node *dnode)
 {
-       const char *area_tag;
+       struct isis_area *area;
 
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       area_tag = yang_dnode_get_string(dnode, "./area-tag");
-       isis_area_destroy(area_tag);
+       area = nb_running_unset_entry(dnode);
+       isis_area_destroy(area->area_tag);
 
        return NB_OK;
 }
@@ -99,7 +99,7 @@ static int isis_instance_is_type_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       area = yang_dnode_get_entry(dnode, true);
+       area = nb_running_get_entry(dnode, NULL, true);
        type = yang_dnode_get_enum(dnode, NULL);
        isis_area_is_type_set(area, type);
 
@@ -150,7 +150,7 @@ static int isis_instance_area_address_create(enum nb_event event,
                XFREE(MTYPE_ISIS_AREA_ADDR, resource->ptr);
                break;
        case NB_EV_APPLY:
-               area = yang_dnode_get_entry(dnode, true);
+               area = nb_running_get_entry(dnode, NULL, true);
                addrr = resource->ptr;
 
                if (isis->sysid_set == 0) {
@@ -208,7 +208,7 @@ static int isis_instance_area_address_destroy(enum nb_event event,
        net_title = yang_dnode_get_string(dnode, NULL);
        addr.addr_len = dotformat2buff(buff, net_title);
        memcpy(addr.area_addr, buff, (int)addr.addr_len);
-       area = yang_dnode_get_entry(dnode, true);
+       area = nb_running_get_entry(dnode, NULL, true);
        for (ALL_LIST_ELEMENTS_RO(area->area_addrs, node, addrp)) {
                if ((addrp->addr_len + ISIS_SYS_ID_LEN + 1) == addr.addr_len
                    && !memcmp(addrp->area_addr, addr.area_addr, addr.addr_len))
@@ -244,7 +244,7 @@ static int isis_instance_dynamic_hostname_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       area = yang_dnode_get_entry(dnode, true);
+       area = nb_running_get_entry(dnode, NULL, true);
        isis_area_dynhostname_set(area, yang_dnode_get_bool(dnode, NULL));
 
        return NB_OK;
@@ -263,7 +263,7 @@ static int isis_instance_attached_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       area = yang_dnode_get_entry(dnode, true);
+       area = nb_running_get_entry(dnode, NULL, true);
        attached = yang_dnode_get_bool(dnode, NULL);
        isis_area_attached_bit_set(area, attached);
 
@@ -283,7 +283,7 @@ static int isis_instance_overload_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       area = yang_dnode_get_entry(dnode, true);
+       area = nb_running_get_entry(dnode, NULL, true);
        overload = yang_dnode_get_bool(dnode, NULL);
        isis_area_overload_bit_set(area, overload);
 
@@ -304,7 +304,7 @@ static int isis_instance_metric_style_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       area = yang_dnode_get_entry(dnode, true);
+       area = nb_running_get_entry(dnode, NULL, true);
        old_metric = (metric_style == ISIS_WIDE_METRIC) ? false : true;
        new_metric = (metric_style == ISIS_NARROW_METRIC) ? false : true;
        isis_area_metricstyle_set(area, old_metric, new_metric);
@@ -324,7 +324,7 @@ static int isis_instance_purge_originator_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       area = yang_dnode_get_entry(dnode, true);
+       area = nb_running_get_entry(dnode, NULL, true);
        area->purge_originator = yang_dnode_get_bool(dnode, NULL);
 
        return NB_OK;
@@ -344,7 +344,7 @@ static int isis_instance_lsp_mtu_modify(enum nb_event event,
 
        switch (event) {
        case NB_EV_VALIDATE:
-               area = yang_dnode_get_entry(dnode, false);
+               area = nb_running_get_entry(dnode, NULL, false);
                if (!area)
                        break;
                for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
@@ -365,7 +365,7 @@ static int isis_instance_lsp_mtu_modify(enum nb_event event,
        case NB_EV_ABORT:
                break;
        case NB_EV_APPLY:
-               area = yang_dnode_get_entry(dnode, true);
+               area = nb_running_get_entry(dnode, NULL, true);
                isis_area_lsp_mtu_set(area, lsp_mtu);
                break;
        }
@@ -388,7 +388,7 @@ isis_instance_lsp_refresh_interval_level_1_modify(enum nb_event event,
                return NB_OK;
 
        refr_int = yang_dnode_get_uint16(dnode, NULL);
-       area = yang_dnode_get_entry(dnode, true);
+       area = nb_running_get_entry(dnode, NULL, true);
        isis_area_lsp_refresh_set(area, IS_LEVEL_1, refr_int);
 
        return NB_OK;
@@ -409,7 +409,7 @@ isis_instance_lsp_refresh_interval_level_2_modify(enum nb_event event,
                return NB_OK;
 
        refr_int = yang_dnode_get_uint16(dnode, NULL);
-       area = yang_dnode_get_entry(dnode, true);
+       area = nb_running_get_entry(dnode, NULL, true);
        isis_area_lsp_refresh_set(area, IS_LEVEL_2, refr_int);
 
        return NB_OK;
@@ -430,7 +430,7 @@ isis_instance_lsp_maximum_lifetime_level_1_modify(enum nb_event event,
                return NB_OK;
 
        max_lt = yang_dnode_get_uint16(dnode, NULL);
-       area = yang_dnode_get_entry(dnode, true);
+       area = nb_running_get_entry(dnode, NULL, true);
        isis_area_max_lsp_lifetime_set(area, IS_LEVEL_1, max_lt);
 
        return NB_OK;
@@ -451,7 +451,7 @@ isis_instance_lsp_maximum_lifetime_level_2_modify(enum nb_event event,
                return NB_OK;
 
        max_lt = yang_dnode_get_uint16(dnode, NULL);
-       area = yang_dnode_get_entry(dnode, true);
+       area = nb_running_get_entry(dnode, NULL, true);
        isis_area_max_lsp_lifetime_set(area, IS_LEVEL_2, max_lt);
 
        return NB_OK;
@@ -471,7 +471,7 @@ static int isis_instance_lsp_generation_interval_level_1_modify(
                return NB_OK;
 
        gen_int = yang_dnode_get_uint16(dnode, NULL);
-       area = yang_dnode_get_entry(dnode, true);
+       area = nb_running_get_entry(dnode, NULL, true);
        area->lsp_gen_interval[0] = gen_int;
 
        return NB_OK;
@@ -491,7 +491,7 @@ static int isis_instance_lsp_generation_interval_level_2_modify(
                return NB_OK;
 
        gen_int = yang_dnode_get_uint16(dnode, NULL);
-       area = yang_dnode_get_entry(dnode, true);
+       area = nb_running_get_entry(dnode, NULL, true);
        area->lsp_gen_interval[1] = gen_int;
 
        return NB_OK;
@@ -507,7 +507,7 @@ static void ietf_backoff_delay_apply_finish(const struct lyd_node *dnode)
        long long_delay = yang_dnode_get_uint16(dnode, "./long-delay");
        long holddown = yang_dnode_get_uint16(dnode, "./hold-down");
        long timetolearn = yang_dnode_get_uint16(dnode, "./time-to-learn");
-       struct isis_area *area = yang_dnode_get_entry(dnode, true);
+       struct isis_area *area = nb_running_get_entry(dnode, NULL, true);
        size_t bufsiz = strlen(area->area_tag) + sizeof("IS-IS  Lx");
        char *buf = XCALLOC(MTYPE_TMP, bufsiz);
 
@@ -544,7 +544,7 @@ isis_instance_spf_ietf_backoff_delay_destroy(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       area = yang_dnode_get_entry(dnode, true);
+       area = nb_running_get_entry(dnode, NULL, true);
        spf_backoff_free(area->spf_delay_ietf[0]);
        spf_backoff_free(area->spf_delay_ietf[1]);
        area->spf_delay_ietf[0] = NULL;
@@ -621,7 +621,7 @@ isis_instance_spf_minimum_interval_level_1_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       area = yang_dnode_get_entry(dnode, true);
+       area = nb_running_get_entry(dnode, NULL, true);
        area->min_spf_interval[0] = yang_dnode_get_uint16(dnode, NULL);
 
        return NB_OK;
@@ -640,7 +640,7 @@ isis_instance_spf_minimum_interval_level_2_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       area = yang_dnode_get_entry(dnode, true);
+       area = nb_running_get_entry(dnode, NULL, true);
        area->min_spf_interval[1] = yang_dnode_get_uint16(dnode, NULL);
 
        return NB_OK;
@@ -652,7 +652,7 @@ isis_instance_spf_minimum_interval_level_2_modify(enum nb_event event,
 static void area_password_apply_finish(const struct lyd_node *dnode)
 {
        const char *password = yang_dnode_get_string(dnode, "./password");
-       struct isis_area *area = yang_dnode_get_entry(dnode, true);
+       struct isis_area *area = nb_running_get_entry(dnode, NULL, true);
        int pass_type = yang_dnode_get_enum(dnode, "./password-type");
        uint8_t snp_auth = yang_dnode_get_enum(dnode, "./authenticate-snp");
 
@@ -684,7 +684,7 @@ static int isis_instance_area_password_destroy(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       area = yang_dnode_get_entry(dnode, true);
+       area = nb_running_get_entry(dnode, NULL, true);
        isis_area_passwd_unset(area, IS_LEVEL_1);
 
        return NB_OK;
@@ -731,7 +731,7 @@ static int isis_instance_area_password_authenticate_snp_modify(
 static void domain_password_apply_finish(const struct lyd_node *dnode)
 {
        const char *password = yang_dnode_get_string(dnode, "./password");
-       struct isis_area *area = yang_dnode_get_entry(dnode, true);
+       struct isis_area *area = nb_running_get_entry(dnode, NULL, true);
        int pass_type = yang_dnode_get_enum(dnode, "./password-type");
        uint8_t snp_auth = yang_dnode_get_enum(dnode, "./authenticate-snp");
 
@@ -763,7 +763,7 @@ static int isis_instance_domain_password_destroy(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       area = yang_dnode_get_entry(dnode, true);
+       area = nb_running_get_entry(dnode, NULL, true);
        isis_area_passwd_unset(area, IS_LEVEL_2);
 
        return NB_OK;
@@ -813,7 +813,7 @@ static void default_info_origin_apply_finish(const struct lyd_node *dnode,
        int originate_type = DEFAULT_ORIGINATE;
        unsigned long metric = 0;
        const char *routemap = NULL;
-       struct isis_area *area = yang_dnode_get_entry(dnode, true);
+       struct isis_area *area = nb_running_get_entry(dnode, NULL, true);
        int level = yang_dnode_get_enum(dnode, "./level");
 
        if (yang_dnode_get_bool(dnode, "./always")) {
@@ -860,7 +860,7 @@ static int isis_instance_default_information_originate_ipv4_destroy(
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       area = yang_dnode_get_entry(dnode, true);
+       area = nb_running_get_entry(dnode, NULL, true);
        level = yang_dnode_get_enum(dnode, "./level");
        isis_redist_unset(area, level, AF_INET, DEFAULT_ROUTE);
 
@@ -927,7 +927,7 @@ static int isis_instance_default_information_originate_ipv6_destroy(
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       area = yang_dnode_get_entry(dnode, true);
+       area = nb_running_get_entry(dnode, NULL, true);
        level = yang_dnode_get_enum(dnode, "./level");
        isis_redist_unset(area, level, AF_INET6, DEFAULT_ROUTE);
 
@@ -987,7 +987,7 @@ static void redistribute_apply_finish(const struct lyd_node *dnode, int family)
 
        type = yang_dnode_get_enum(dnode, "./protocol");
        level = yang_dnode_get_enum(dnode, "./level");
-       area = yang_dnode_get_entry(dnode, true);
+       area = nb_running_get_entry(dnode, NULL, true);
 
        if (yang_dnode_exists(dnode, "./metric"))
                metric = yang_dnode_get_uint32(dnode, "./metric");
@@ -1024,7 +1024,7 @@ static int isis_instance_redistribute_ipv4_destroy(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       area = yang_dnode_get_entry(dnode, true);
+       area = nb_running_get_entry(dnode, NULL, true);
        level = yang_dnode_get_enum(dnode, "./level");
        type = yang_dnode_get_enum(dnode, "./protocol");
        isis_redist_unset(area, level, AF_INET, type);
@@ -1084,7 +1084,7 @@ static int isis_instance_redistribute_ipv6_destroy(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       area = yang_dnode_get_entry(dnode, true);
+       area = nb_running_get_entry(dnode, NULL, true);
        level = yang_dnode_get_enum(dnode, "./level");
        type = yang_dnode_get_enum(dnode, "./protocol");
        isis_redist_unset(area, level, AF_INET6, type);
@@ -1147,7 +1147,7 @@ static int isis_multi_topology_common(enum nb_event event,
        case NB_EV_ABORT:
                break;
        case NB_EV_APPLY:
-               area = yang_dnode_get_entry(dnode, true);
+               area = nb_running_get_entry(dnode, NULL, true);
                setting = area_get_mt_setting(area, mtid);
                setting->enabled = create;
                lsp_regenerate_schedule(area, IS_LEVEL_1 | IS_LEVEL_2, 0);
@@ -1169,7 +1169,7 @@ static int isis_multi_topology_overload_common(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       area = yang_dnode_get_entry(dnode, true);
+       area = nb_running_get_entry(dnode, NULL, true);
        setting = area_get_mt_setting(area, mtid);
        setting->overload = yang_dnode_get_bool(dnode, NULL);
        if (setting->enabled)
@@ -1358,7 +1358,7 @@ isis_instance_log_adjacency_changes_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       area = yang_dnode_get_entry(dnode, true);
+       area = nb_running_get_entry(dnode, NULL, true);
        area->log_adj_changes = log ? 1 : 0;
 
        return NB_OK;
@@ -1517,10 +1517,10 @@ static int lib_interface_isis_create(enum nb_event event,
                abort();
        }
 
-       ifp = yang_dnode_get_entry(dnode, true);
+       ifp = nb_running_get_entry(dnode, NULL, true);
        circuit = isis_circuit_create(area, ifp);
        assert(circuit->state == C_STATE_CONF || circuit->state == C_STATE_UP);
-       yang_dnode_set_entry(dnode, circuit);
+       nb_running_set_entry(dnode, circuit);
 
        return NB_OK;
 }
@@ -1533,7 +1533,7 @@ static int lib_interface_isis_destroy(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       circuit = yang_dnode_get_entry(dnode, true);
+       circuit = nb_running_unset_entry(dnode);
        if (!circuit)
                return NB_ERR_INCONSISTENCY;
        /* delete circuit through csm changes */
@@ -1629,7 +1629,7 @@ static int lib_interface_isis_circuit_type_modify(enum nb_event event,
        case NB_EV_ABORT:
                break;
        case NB_EV_APPLY:
-               circuit = yang_dnode_get_entry(dnode, true);
+               circuit = nb_running_get_entry(dnode, NULL, true);
                isis_circuit_is_type_set(circuit, circ_type);
                break;
        }
@@ -1650,7 +1650,7 @@ static int lib_interface_isis_ipv4_routing_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       circuit = yang_dnode_get_entry(dnode, true);
+       circuit = nb_running_get_entry(dnode, NULL, true);
        ipv4 = yang_dnode_get_bool(dnode, NULL);
        ipv6 = yang_dnode_get_bool(dnode, "../ipv6-routing");
        isis_circuit_af_set(circuit, ipv4, ipv6);
@@ -1671,7 +1671,7 @@ static int lib_interface_isis_ipv6_routing_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       circuit = yang_dnode_get_entry(dnode, true);
+       circuit = nb_running_get_entry(dnode, NULL, true);
        ipv4 = yang_dnode_exists(dnode, "../ipv4-routing");
        ipv6 = yang_dnode_get_bool(dnode, NULL);
        isis_circuit_af_set(circuit, ipv4, ipv6);
@@ -1692,7 +1692,7 @@ lib_interface_isis_csnp_interval_level_1_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       circuit = yang_dnode_get_entry(dnode, true);
+       circuit = nb_running_get_entry(dnode, NULL, true);
        circuit->csnp_interval[0] = yang_dnode_get_uint16(dnode, NULL);
 
        return NB_OK;
@@ -1711,7 +1711,7 @@ lib_interface_isis_csnp_interval_level_2_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       circuit = yang_dnode_get_entry(dnode, true);
+       circuit = nb_running_get_entry(dnode, NULL, true);
        circuit->csnp_interval[1] = yang_dnode_get_uint16(dnode, NULL);
 
        return NB_OK;
@@ -1730,7 +1730,7 @@ lib_interface_isis_psnp_interval_level_1_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       circuit = yang_dnode_get_entry(dnode, true);
+       circuit = nb_running_get_entry(dnode, NULL, true);
        circuit->psnp_interval[0] = yang_dnode_get_uint16(dnode, NULL);
 
        return NB_OK;
@@ -1749,7 +1749,7 @@ lib_interface_isis_psnp_interval_level_2_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       circuit = yang_dnode_get_entry(dnode, true);
+       circuit = nb_running_get_entry(dnode, NULL, true);
        circuit->psnp_interval[1] = yang_dnode_get_uint16(dnode, NULL);
 
        return NB_OK;
@@ -1767,7 +1767,7 @@ static int lib_interface_isis_hello_padding_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       circuit = yang_dnode_get_entry(dnode, true);
+       circuit = nb_running_get_entry(dnode, NULL, true);
        circuit->pad_hellos = yang_dnode_get_bool(dnode, NULL);
 
        return NB_OK;
@@ -1787,7 +1787,7 @@ lib_interface_isis_hello_interval_level_1_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       circuit = yang_dnode_get_entry(dnode, true);
+       circuit = nb_running_get_entry(dnode, NULL, true);
        interval = yang_dnode_get_uint32(dnode, NULL);
        circuit->hello_interval[0] = interval;
 
@@ -1808,7 +1808,7 @@ lib_interface_isis_hello_interval_level_2_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       circuit = yang_dnode_get_entry(dnode, true);
+       circuit = nb_running_get_entry(dnode, NULL, true);
        interval = yang_dnode_get_uint32(dnode, NULL);
        circuit->hello_interval[1] = interval;
 
@@ -1829,7 +1829,7 @@ lib_interface_isis_hello_multiplier_level_1_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       circuit = yang_dnode_get_entry(dnode, true);
+       circuit = nb_running_get_entry(dnode, NULL, true);
        multi = yang_dnode_get_uint16(dnode, NULL);
        circuit->hello_multiplier[0] = multi;
 
@@ -1850,7 +1850,7 @@ lib_interface_isis_hello_multiplier_level_2_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       circuit = yang_dnode_get_entry(dnode, true);
+       circuit = nb_running_get_entry(dnode, NULL, true);
        multi = yang_dnode_get_uint16(dnode, NULL);
        circuit->hello_multiplier[1] = multi;
 
@@ -1871,7 +1871,7 @@ lib_interface_isis_metric_level_1_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       circuit = yang_dnode_get_entry(dnode, true);
+       circuit = nb_running_get_entry(dnode, NULL, true);
        met = yang_dnode_get_uint32(dnode, NULL);
        isis_circuit_metric_set(circuit, IS_LEVEL_1, met);
 
@@ -1892,7 +1892,7 @@ lib_interface_isis_metric_level_2_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       circuit = yang_dnode_get_entry(dnode, true);
+       circuit = nb_running_get_entry(dnode, NULL, true);
        met = yang_dnode_get_uint32(dnode, NULL);
        isis_circuit_metric_set(circuit, IS_LEVEL_2, met);
 
@@ -1912,7 +1912,7 @@ lib_interface_isis_priority_level_1_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       circuit = yang_dnode_get_entry(dnode, true);
+       circuit = nb_running_get_entry(dnode, NULL, true);
        circuit->priority[0] = yang_dnode_get_uint8(dnode, NULL);
 
        return NB_OK;
@@ -1931,7 +1931,7 @@ lib_interface_isis_priority_level_2_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       circuit = yang_dnode_get_entry(dnode, true);
+       circuit = nb_running_get_entry(dnode, NULL, true);
        circuit->priority[1] = yang_dnode_get_uint8(dnode, NULL);
 
        return NB_OK;
@@ -1949,7 +1949,7 @@ static int lib_interface_isis_network_type_modify(enum nb_event event,
 
        switch (event) {
        case NB_EV_VALIDATE:
-               circuit = yang_dnode_get_entry(dnode, false);
+               circuit = nb_running_get_entry(dnode, NULL, false);
                if (!circuit)
                        break;
                if (circuit->circ_type == CIRCUIT_T_LOOPBACK) {
@@ -1971,7 +1971,7 @@ static int lib_interface_isis_network_type_modify(enum nb_event event,
        case NB_EV_ABORT:
                break;
        case NB_EV_APPLY:
-               circuit = yang_dnode_get_entry(dnode, true);
+               circuit = nb_running_get_entry(dnode, NULL, true);
                isis_circuit_circ_type_set(circuit, net_type);
                break;
        }
@@ -1993,7 +1993,7 @@ static int lib_interface_isis_passive_modify(enum nb_event event,
 
        /* validation only applies if we are setting passive to false */
        if (!passive && event == NB_EV_VALIDATE) {
-               circuit = yang_dnode_get_entry(dnode, false);
+               circuit = nb_running_get_entry(dnode, NULL, false);
                if (!circuit)
                        return NB_OK;
                ifp = circuit->interface;
@@ -2009,7 +2009,7 @@ static int lib_interface_isis_passive_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       circuit = yang_dnode_get_entry(dnode, true);
+       circuit = nb_running_get_entry(dnode, NULL, true);
        if (circuit->state != C_STATE_UP) {
                circuit->is_passive = passive;
        } else {
@@ -2040,7 +2040,7 @@ static int lib_interface_isis_password_destroy(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       circuit = yang_dnode_get_entry(dnode, true);
+       circuit = nb_running_get_entry(dnode, NULL, true);
        isis_circuit_passwd_unset(circuit);
 
        return NB_OK;
@@ -2061,7 +2061,7 @@ lib_interface_isis_password_password_modify(enum nb_event event,
                return NB_OK;
 
        password = yang_dnode_get_string(dnode, NULL);
-       circuit = yang_dnode_get_entry(dnode, true);
+       circuit = nb_running_get_entry(dnode, NULL, true);
 
        isis_circuit_passwd_set(circuit, circuit->passwd.type, password);
 
@@ -2083,7 +2083,7 @@ lib_interface_isis_password_password_type_modify(enum nb_event event,
                return NB_OK;
 
        pass_type = yang_dnode_get_enum(dnode, NULL);
-       circuit = yang_dnode_get_entry(dnode, true);
+       circuit = nb_running_get_entry(dnode, NULL, true);
        circuit->passwd.type = pass_type;
 
        return NB_OK;
@@ -2102,7 +2102,7 @@ static int lib_interface_isis_disable_three_way_handshake_modify(
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       circuit = yang_dnode_get_entry(dnode, true);
+       circuit = nb_running_get_entry(dnode, NULL, true);
        circuit->disable_threeway_adj = yang_dnode_get_bool(dnode, NULL);
 
        return NB_OK;
@@ -2120,7 +2120,7 @@ static int lib_interface_isis_multi_topology_common(
 
        switch (event) {
        case NB_EV_VALIDATE:
-               circuit = yang_dnode_get_entry(dnode, false);
+               circuit = nb_running_get_entry(dnode, NULL, false);
                if (circuit && circuit->area && circuit->area->oldmetric) {
                        flog_warn(
                                EC_LIB_NB_CB_CONFIG_VALIDATE,
@@ -2132,7 +2132,7 @@ static int lib_interface_isis_multi_topology_common(
        case NB_EV_ABORT:
                break;
        case NB_EV_APPLY:
-               circuit = yang_dnode_get_entry(dnode, true);
+               circuit = nb_running_get_entry(dnode, NULL, true);
                value = yang_dnode_get_bool(dnode, NULL);
                isis_circuit_mt_enabled_set(circuit, mtid, value);
                break;
index a31b44c7d575f2f987ba41a8c1372b1c3f043b4e..86b850c059f785ab1926d957ab09c29156a7c34a 100644 (file)
--- a/lib/if.c
+++ b/lib/if.c
@@ -436,13 +436,13 @@ void if_set_index(struct interface *ifp, ifindex_t ifindex)
 }
 
 /* Does interface up ? */
-int if_is_up(struct interface *ifp)
+int if_is_up(const struct interface *ifp)
 {
        return ifp->flags & IFF_UP;
 }
 
 /* Is interface running? */
-int if_is_running(struct interface *ifp)
+int if_is_running(const struct interface *ifp)
 {
        return ifp->flags & IFF_RUNNING;
 }
@@ -450,7 +450,7 @@ int if_is_running(struct interface *ifp)
 /* Is the interface operative, eg. either UP & RUNNING
    or UP & !ZEBRA_INTERFACE_LINK_DETECTION and
    if ptm checking is enabled, then ptm check has passed */
-int if_is_operative(struct interface *ifp)
+int if_is_operative(const struct interface *ifp)
 {
        return ((ifp->flags & IFF_UP)
                && (((ifp->flags & IFF_RUNNING)
@@ -461,7 +461,7 @@ int if_is_operative(struct interface *ifp)
 
 /* Is the interface operative, eg. either UP & RUNNING
    or UP & !ZEBRA_INTERFACE_LINK_DETECTION, without PTM check */
-int if_is_no_ptm_operative(struct interface *ifp)
+int if_is_no_ptm_operative(const struct interface *ifp)
 {
        return ((ifp->flags & IFF_UP)
                && ((ifp->flags & IFF_RUNNING)
@@ -470,7 +470,7 @@ int if_is_no_ptm_operative(struct interface *ifp)
 }
 
 /* Is this loopback interface ? */
-int if_is_loopback(struct interface *ifp)
+int if_is_loopback(const struct interface *ifp)
 {
        /* XXX: Do this better, eg what if IFF_WHATEVER means X on platform M
         * but Y on platform N?
@@ -479,12 +479,12 @@ int if_is_loopback(struct interface *ifp)
 }
 
 /* Check interface is VRF */
-int if_is_vrf(struct interface *ifp)
+int if_is_vrf(const struct interface *ifp)
 {
        return CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK);
 }
 
-bool if_is_loopback_or_vrf(struct interface *ifp)
+bool if_is_loopback_or_vrf(const struct interface *ifp)
 {
        if (if_is_loopback(ifp) || if_is_vrf(ifp))
                return true;
@@ -493,19 +493,19 @@ bool if_is_loopback_or_vrf(struct interface *ifp)
 }
 
 /* Does this interface support broadcast ? */
-int if_is_broadcast(struct interface *ifp)
+int if_is_broadcast(const struct interface *ifp)
 {
        return ifp->flags & IFF_BROADCAST;
 }
 
 /* Does this interface support broadcast ? */
-int if_is_pointopoint(struct interface *ifp)
+int if_is_pointopoint(const struct interface *ifp)
 {
        return ifp->flags & IFF_POINTOPOINT;
 }
 
 /* Does this interface support multicast ? */
-int if_is_multicast(struct interface *ifp)
+int if_is_multicast(const struct interface *ifp)
 {
        return ifp->flags & IFF_MULTICAST;
 }
@@ -1303,7 +1303,7 @@ static int lib_interface_create(enum nb_event event,
 #else
                ifp = if_get_by_name(ifname, vrf->vrf_id);
 #endif /* SUNOS_5 */
-               yang_dnode_set_entry(dnode, ifp);
+               nb_running_set_entry(dnode, ifp);
                break;
        }
 
@@ -1315,10 +1315,10 @@ static int lib_interface_destroy(enum nb_event event,
 {
        struct interface *ifp;
 
-       ifp = yang_dnode_get_entry(dnode, true);
 
        switch (event) {
        case NB_EV_VALIDATE:
+               ifp = nb_running_get_entry(dnode, NULL, true);
                if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) {
                        zlog_warn("%s: only inactive interfaces can be deleted",
                                  __func__);
@@ -1329,6 +1329,7 @@ static int lib_interface_destroy(enum nb_event event,
        case NB_EV_ABORT:
                break;
        case NB_EV_APPLY:
+               ifp = nb_running_unset_entry(dnode);
                if_delete(ifp);
                break;
        }
@@ -1349,7 +1350,7 @@ static int lib_interface_description_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ifp = yang_dnode_get_entry(dnode, true);
+       ifp = nb_running_get_entry(dnode, NULL, true);
        XFREE(MTYPE_TMP, ifp->desc);
        description = yang_dnode_get_string(dnode, NULL);
        ifp->desc = XSTRDUP(MTYPE_TMP, description);
@@ -1365,7 +1366,7 @@ static int lib_interface_description_destroy(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ifp = yang_dnode_get_entry(dnode, true);
+       ifp = nb_running_get_entry(dnode, NULL, true);
        XFREE(MTYPE_TMP, ifp->desc);
 
        return NB_OK;
index 6689769beb8872c6b0be22bfa3759f83c6fea755..d26d4dd68b1de79378009d46120b594b0eb1f763 100644 (file)
--- a/lib/if.h
+++ b/lib/if.h
@@ -499,16 +499,16 @@ extern void if_delete_retain(struct interface *);
    deletes it from the interface list and frees the structure. */
 extern void if_delete(struct interface *);
 
-extern int if_is_up(struct interface *);
-extern int if_is_running(struct interface *);
-extern int if_is_operative(struct interface *);
-extern int if_is_no_ptm_operative(struct interface *);
-extern int if_is_loopback(struct interface *);
-extern int if_is_vrf(struct interface *ifp);
-extern bool if_is_loopback_or_vrf(struct interface *ifp);
-extern int if_is_broadcast(struct interface *);
-extern int if_is_pointopoint(struct interface *);
-extern int if_is_multicast(struct interface *);
+extern int if_is_up(const struct interface *ifp);
+extern int if_is_running(const struct interface *ifp);
+extern int if_is_operative(const struct interface *ifp);
+extern int if_is_no_ptm_operative(const struct interface *ifp);
+extern int if_is_loopback(const struct interface *ifp);
+extern int if_is_vrf(const struct interface *ifp);
+extern bool if_is_loopback_or_vrf(const struct interface *ifp);
+extern int if_is_broadcast(const struct interface *ifp);
+extern int if_is_pointopoint(const struct interface *ifp);
+extern int if_is_multicast(const struct interface *ifp);
 struct vrf;
 extern void if_terminate(struct vrf *vrf);
 extern void if_dump_all(void);
index d8236b6b255e3829c446dea3ad6d27b9da18111d..b0802da96147950c5848ed87d552b1d0e6d4e719 100644 (file)
@@ -291,6 +291,7 @@ int config_write_if_rmap(struct vty *vty,
 
 void if_rmap_ctx_delete(struct if_rmap_ctx *ctx)
 {
+       listnode_delete(if_rmap_ctx_list, ctx);
        hash_clean(ctx->ifrmaphash, (void (*)(void *))if_rmap_free);
        if (ctx->name)
                XFREE(MTYPE_IF_RMAP_CTX_NAME, ctx);
index 1afe30d618486594fe454f1d8816bdb3e7ca2a0f..0d4c8d6c0f1b4200895491cc3ef28c7fb5aa2847 100644 (file)
@@ -38,6 +38,7 @@
 #include "lib_errors.h"
 #include "db.h"
 #include "northbound_cli.h"
+#include "northbound_db.h"
 
 DEFINE_HOOK(frr_late_init, (struct thread_master * tm), (tm))
 DEFINE_KOOH(frr_early_fini, (), ())
@@ -654,6 +655,10 @@ struct thread_master *frr_init(void)
 
        yang_init();
        nb_init(master, di->yang_modules, di->n_yang_modules);
+       if (nb_db_init() != NB_OK)
+               flog_warn(EC_LIB_NB_DATABASE,
+                         "%s: failed to initialize northbound database",
+                         __func__);
 
        return master;
 }
index f0d0c292450c5dadf8d2586c0d42613a7d854546..40c4b271698ce48d125f8e14abfeee20ebd8519c 100644 (file)
@@ -50,7 +50,7 @@ static void listnode_free(struct listnode *node)
        XFREE(MTYPE_LINK_NODE, node);
 }
 
-void listnode_add(struct list *list, void *val)
+struct listnode *listnode_add(struct list *list, void *val)
 {
        struct listnode *node;
 
@@ -68,6 +68,8 @@ void listnode_add(struct list *list, void *val)
        list->tail = node;
 
        list->count++;
+
+       return node;
 }
 
 void listnode_add_head(struct list *list, void *val)
@@ -326,7 +328,7 @@ void list_sort(struct list *list, int (*cmp)(const void **, const void **))
        XFREE(MTYPE_TMP, items);
 }
 
-void listnode_add_force(struct list **list, void *val)
+struct listnode *listnode_add_force(struct list **list, void *val)
 {
        if (*list == NULL)
                *list = list_new();
index e75d86343100567b93d045a7d62956fed55ee16e..c30d8d314a3bb785d016bb1d3e529ca2f77aac68 100644 (file)
@@ -84,7 +84,7 @@ extern struct list *list_new(void);
  * data
  *    element to add
  */
-extern void listnode_add(struct list *list, void *data);
+extern struct listnode *listnode_add(struct list *list, void *data);
 
 /*
  * Add a new element to the beginning of a list.
@@ -343,7 +343,13 @@ extern void list_add_list(struct list *list, struct list *add);
 
 extern struct listnode *listnode_lookup_nocheck(struct list *list, void *data);
 
-extern void listnode_add_force(struct list **list, void *val);
+/*
+ * Add a node to *list, if non-NULL. Otherwise, allocate a new list, mail
+ * it back in *list, and add a new node.
+ *
+ * Return: the new node.
+ */
+extern struct listnode *listnode_add_force(struct list **list, void *val);
 
 #ifdef __cplusplus
 }
index 8724e0db9349b64618b58568869ce1519a961a7d..e64c00186be21204ab9137b0034bbeb9dd2b54cd 100644 (file)
--- a/lib/log.c
+++ b/lib/log.c
@@ -1068,6 +1068,8 @@ static const struct zebra_desc_table command_types[] = {
        DESC_ENTRY(ZEBRA_IPTABLE_DELETE),
        DESC_ENTRY(ZEBRA_IPTABLE_NOTIFY_OWNER),
        DESC_ENTRY(ZEBRA_VXLAN_FLOOD_CONTROL),
+       DESC_ENTRY(ZEBRA_VXLAN_SG_ADD),
+       DESC_ENTRY(ZEBRA_VXLAN_SG_DEL),
 };
 #undef DESC_ENTRY
 
index 189857a90746360bf588b96d940bb294ffde874e..9368bf9e829937fda784740a036e86450325d4b8 100644 (file)
--- a/lib/log.h
+++ b/lib/log.h
@@ -94,6 +94,7 @@ extern void zlog_warn(const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
 extern void zlog_info(const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
 extern void zlog_notice(const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
 extern void zlog_debug(const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
+extern void zlog(int priority, const char *format, ...) PRINTF_ATTRIBUTE(2, 3);
 
 /* For logs which have error codes associated with them */
 #define flog_err(ferr_id, format, ...)                                        \
@@ -102,7 +103,8 @@ extern void zlog_debug(const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
        flog_err(ferr_id, format, ##__VA_ARGS__)
 #define flog_warn(ferr_id, format, ...)                                        \
        zlog_warn("[EC %" PRIu32 "] " format, ferr_id, ##__VA_ARGS__)
-
+#define flog(priority, ferr_id, format, ...)                                   \
+       zlog(priority, "[EC %" PRIu32 "] " format, ferr_id, ##__VA_ARGS__)
 
 extern void zlog_thread_info(int log_level);
 
index 58ae031e1b77e1fd90a07866a088f3d35ce51c13..287e626eab3651f4e4c5a2313bd22e4c032c9c35 100644 (file)
@@ -51,7 +51,6 @@ extern const char *zlog_priority[];
 
 /* Generic function for zlog. */
 extern void vzlog(int priority, const char *format, va_list args);
-extern void zlog(int priority, const char *format, ...) PRINTF_ATTRIBUTE(2, 3);
 
 #ifdef __cplusplus
 }
index 24b0953191efb74071c4a8e91f6f81ed87be8bfe..663acaeb69513eb5e64ff5c3c87e817e815ae115 100644 (file)
@@ -81,8 +81,8 @@ struct nexthop {
 #define NEXTHOP_FLAG_RECURSIVE  (1 << 2) /* Recursive nexthop. */
 #define NEXTHOP_FLAG_ONLINK     (1 << 3) /* Nexthop should be installed onlink. */
 #define NEXTHOP_FLAG_MATCHED    (1 << 4) /* Already matched vs a nexthop */
-#define NEXTHOP_FLAG_FILTERED   (1 << 5) /* rmap filtered, used by static only */
-#define NEXTHOP_FLAG_DUPLICATE  (1 << 6) /* nexthop duplicates another active one */
+#define NEXTHOP_FLAG_DUPLICATE  (1 << 5) /* nexthop duplicates another active one */
+#define NEXTHOP_FLAG_RNH_FILTERED  (1 << 6) /* rmap filtered, used by rnh */
 #define NEXTHOP_IS_ACTIVE(flags)                                               \
        (CHECK_FLAG(flags, NEXTHOP_FLAG_ACTIVE)                                \
         && !CHECK_FLAG(flags, NEXTHOP_FLAG_DUPLICATE))
index fa89b7708c632d9d66b78bedbec495a27f920bce..ed22f64494b40a4e158072b7418a1a6e2362d3b6 100644 (file)
@@ -59,6 +59,30 @@ nexthop_group_cmd_compare(const struct nexthop_group_cmd *nhgc1,
        return strcmp(nhgc1->name, nhgc2->name);
 }
 
+uint8_t nexthop_group_nexthop_num(const struct nexthop_group *nhg)
+{
+       struct nexthop *nhop;
+       uint8_t num = 0;
+
+       for (ALL_NEXTHOPS_PTR(nhg, nhop))
+               num++;
+
+       return num;
+}
+
+uint8_t nexthop_group_active_nexthop_num(const struct nexthop_group *nhg)
+{
+       struct nexthop *nhop;
+       uint8_t num = 0;
+
+       for (ALL_NEXTHOPS_PTR(nhg, nhop)) {
+               if (CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_ACTIVE))
+                       num++;
+       }
+
+       return num;
+}
+
 struct nexthop *nexthop_exists(struct nexthop_group *nhg, struct nexthop *nh)
 {
        struct nexthop *nexthop;
index f68033c20c90d3092cff63f31f88517fa98143ce..5adf2db937b530eec43153006bc669d06c652bcc 100644 (file)
@@ -117,6 +117,11 @@ extern struct nexthop_group_cmd *nhgc_find(const char *name);
 
 extern void nexthop_group_write_nexthop(struct vty *vty, struct nexthop *nh);
 
+/* Return the number of nexthops in this nhg */
+extern uint8_t nexthop_group_nexthop_num(const struct nexthop_group *nhg);
+extern uint8_t
+nexthop_group_active_nexthop_num(const struct nexthop_group *nhg);
+
 #ifdef __cplusplus
 }
 #endif
index 9deb9c6cceb28a9dc908f56f6bdec85b6c0d3d4b..5e031ac2cea8ba4fdc9cbcb88f3ea0fbf5ef1572 100644 (file)
@@ -22,6 +22,7 @@
 #include "libfrr.h"
 #include "log.h"
 #include "lib_errors.h"
+#include "hash.h"
 #include "command.h"
 #include "debug.h"
 #include "db.h"
 
 DEFINE_MTYPE_STATIC(LIB, NB_NODE, "Northbound Node")
 DEFINE_MTYPE_STATIC(LIB, NB_CONFIG, "Northbound Configuration")
+DEFINE_MTYPE_STATIC(LIB, NB_CONFIG_ENTRY, "Northbound Configuration Entry")
 
 /* Running configuration - shouldn't be modified directly. */
 struct nb_config *running_config;
 
+/* Hash table of user pointers associated with configuration entries. */
+static struct hash *running_config_entries;
+
 /*
  * Global lock used to prevent multiple configuration transactions from
  * happening concurrently.
@@ -454,13 +459,6 @@ int nb_candidate_edit(struct nb_config *candidate,
        struct lyd_node *dnode;
        char xpath_edit[XPATH_MAXLEN];
 
-       if (!nb_operation_is_valid(operation, nb_node->snode)) {
-               flog_warn(EC_LIB_NB_CANDIDATE_EDIT_ERROR,
-                         "%s: %s operation not valid for %s", __func__,
-                         nb_operation_name(operation), xpath);
-               return NB_ERR;
-       }
-
        /* Use special notation for leaf-lists (RFC 6020, section 9.13.5). */
        if (nb_node->snode->nodetype == LYS_LEAFLIST)
                snprintf(xpath_edit, sizeof(xpath_edit), "%s[.='%s']", xpath,
@@ -534,38 +532,6 @@ int nb_candidate_update(struct nb_config *candidate)
        return NB_OK;
 }
 
-/*
- * The northbound configuration callbacks use the 'priv' pointer present in the
- * libyang lyd_node structure to store pointers to FRR internal variables
- * associated to YANG lists and presence containers. Before commiting a
- * candidate configuration, we must restore the 'priv' pointers stored in the
- * running configuration since they might be lost while editing the candidate.
- */
-static void nb_candidate_restore_priv_pointers(struct nb_config *candidate)
-{
-       struct lyd_node *root, *next, *dnode_iter;
-
-       LY_TREE_FOR (running_config->dnode, root) {
-               LY_TREE_DFS_BEGIN (root, next, dnode_iter) {
-                       struct lyd_node *dnode_candidate;
-                       char xpath[XPATH_MAXLEN];
-
-                       if (!dnode_iter->priv)
-                               goto next;
-
-                       yang_dnode_get_path(dnode_iter, xpath, sizeof(xpath));
-                       dnode_candidate =
-                               yang_dnode_get(candidate->dnode, xpath);
-                       if (dnode_candidate)
-                               yang_dnode_set_entry(dnode_candidate,
-                                                    dnode_iter->priv);
-
-               next:
-                       LY_TREE_DFS_END(root, next, dnode_iter);
-               }
-       }
-}
-
 /*
  * Perform YANG syntactic and semantic validation.
  *
@@ -588,7 +554,6 @@ static int nb_candidate_validate_changes(struct nb_config *candidate,
 {
        struct nb_config_cb *cb;
 
-       nb_candidate_restore_priv_pointers(candidate);
        RB_FOREACH (cb, nb_config_cbs, changes) {
                struct nb_config_change *change = (struct nb_config_change *)cb;
                int ret;
@@ -753,40 +718,44 @@ static int nb_callback_configuration(const enum nb_event event,
                ret = (*nb_node->cbs.move)(event, dnode);
                break;
        default:
-               break;
+               flog_err(EC_LIB_DEVELOPMENT,
+                        "%s: unknown operation (%u) [xpath %s]", __func__,
+                        operation, xpath);
+               exit(1);
        }
 
        if (ret != NB_OK) {
-               enum lib_log_refs ref = 0;
+               int priority;
+               enum lib_log_refs ref;
 
                switch (event) {
                case NB_EV_VALIDATE:
+                       priority = LOG_WARNING;
                        ref = EC_LIB_NB_CB_CONFIG_VALIDATE;
                        break;
                case NB_EV_PREPARE:
+                       priority = LOG_WARNING;
                        ref = EC_LIB_NB_CB_CONFIG_PREPARE;
                        break;
                case NB_EV_ABORT:
+                       priority = LOG_WARNING;
                        ref = EC_LIB_NB_CB_CONFIG_ABORT;
                        break;
                case NB_EV_APPLY:
+                       priority = LOG_ERR;
                        ref = EC_LIB_NB_CB_CONFIG_APPLY;
                        break;
+               default:
+                       flog_err(EC_LIB_DEVELOPMENT,
+                                "%s: unknown event (%u) [xpath %s]",
+                                __func__, event, xpath);
+                       exit(1);
                }
-               if (event == NB_EV_VALIDATE || event == NB_EV_PREPARE)
-                       flog_warn(
-                               ref,
-                               "%s: error processing configuration change: error [%s] event [%s] operation [%s] xpath [%s]",
-                               __func__, nb_err_name(ret),
-                               nb_event_name(event),
-                               nb_operation_name(operation), xpath);
-               else
-                       flog_err(
-                               ref,
-                               "%s: error processing configuration change: error [%s] event [%s] operation [%s] xpath [%s]",
-                               __func__, nb_err_name(ret),
-                               nb_event_name(event),
-                               nb_operation_name(operation), xpath);
+
+               flog(priority, ref,
+                    "%s: error processing configuration change: error [%s] event [%s] operation [%s] xpath [%s]",
+                    __func__, nb_err_name(ret), nb_event_name(event),
+                    nb_operation_name(operation), xpath);
        }
 
        return ret;
@@ -1548,6 +1517,116 @@ int nb_notification_send(const char *xpath, struct list *arguments)
        return ret;
 }
 
+/* Running configuration user pointers management. */
+struct nb_config_entry {
+       char xpath[XPATH_MAXLEN];
+       void *entry;
+};
+
+static bool running_config_entry_cmp(const void *value1, const void *value2)
+{
+       const struct nb_config_entry *c1 = value1;
+       const struct nb_config_entry *c2 = value2;
+
+       return strmatch(c1->xpath, c2->xpath);
+}
+
+static unsigned int running_config_entry_key_make(void *value)
+{
+       return string_hash_make(value);
+}
+
+static void *running_config_entry_alloc(void *p)
+{
+       struct nb_config_entry *new, *key = p;
+
+       new = XCALLOC(MTYPE_NB_CONFIG_ENTRY, sizeof(*new));
+       strlcpy(new->xpath, key->xpath, sizeof(new->xpath));
+
+       return new;
+}
+
+static void running_config_entry_free(void *arg)
+{
+       XFREE(MTYPE_NB_CONFIG_ENTRY, arg);
+}
+
+void nb_running_set_entry(const struct lyd_node *dnode, void *entry)
+{
+       struct nb_config_entry *config, s;
+
+       yang_dnode_get_path(dnode, s.xpath, sizeof(s.xpath));
+       config = hash_get(running_config_entries, &s,
+                         running_config_entry_alloc);
+       config->entry = entry;
+}
+
+static void *nb_running_unset_entry_helper(const struct lyd_node *dnode)
+{
+       struct nb_config_entry *config, s;
+       struct lyd_node *child;
+       void *entry = NULL;
+
+       yang_dnode_get_path(dnode, s.xpath, sizeof(s.xpath));
+       config = hash_release(running_config_entries, &s);
+       if (config) {
+               entry = config->entry;
+               running_config_entry_free(config);
+       }
+
+       /* Unset user pointers from the child nodes. */
+       if (CHECK_FLAG(dnode->schema->nodetype, LYS_LIST | LYS_CONTAINER)) {
+               LY_TREE_FOR (dnode->child, child) {
+                       (void)nb_running_unset_entry_helper(child);
+               }
+       }
+
+       return entry;
+}
+
+void *nb_running_unset_entry(const struct lyd_node *dnode)
+{
+       void *entry;
+
+       entry = nb_running_unset_entry_helper(dnode);
+       assert(entry);
+
+       return entry;
+}
+
+void *nb_running_get_entry(const struct lyd_node *dnode, const char *xpath,
+                          bool abort_if_not_found)
+{
+       const struct lyd_node *orig_dnode = dnode;
+       char xpath_buf[XPATH_MAXLEN];
+
+       assert(dnode || xpath);
+
+       if (!dnode)
+               dnode = yang_dnode_get(running_config->dnode, xpath);
+
+       while (dnode) {
+               struct nb_config_entry *config, s;
+
+               yang_dnode_get_path(dnode, s.xpath, sizeof(s.xpath));
+               config = hash_lookup(running_config_entries, &s);
+               if (config)
+                       return config->entry;
+
+               dnode = dnode->parent;
+       }
+
+       if (!abort_if_not_found)
+               return NULL;
+
+       yang_dnode_get_path(orig_dnode, xpath_buf, sizeof(xpath_buf));
+       flog_err(EC_LIB_YANG_DNODE_NOT_FOUND,
+                "%s: failed to find entry [xpath %s]", __func__, xpath_buf);
+       zlog_backtrace(LOG_ERR);
+       abort();
+}
+
+/* Logging functions. */
 const char *nb_event_name(enum nb_event event)
 {
        switch (event) {
@@ -1677,14 +1756,11 @@ void nb_init(struct thread_master *tm,
                exit(1);
        }
 
-       /* Initialize the northbound database (used for the rollback log). */
-       if (nb_db_init() != NB_OK)
-               flog_warn(EC_LIB_NB_DATABASE,
-                         "%s: failed to initialize northbound database",
-                         __func__);
-
        /* Create an empty running configuration. */
        running_config = nb_config_new(NULL);
+       running_config_entries = hash_create(running_config_entry_key_make,
+                                            running_config_entry_cmp,
+                                            "Running Configuration Entries");
 
        /* Initialize the northbound CLI. */
        nb_cli_init(tm);
@@ -1699,5 +1775,7 @@ void nb_terminate(void)
        nb_nodes_delete();
 
        /* Delete the running configuration. */
+       hash_clean(running_config_entries, running_config_entry_free);
+       hash_free(running_config_entries);
        nb_config_free(running_config);
 }
index bfa28b3f65505071686977ffcd3958f85096f8cf..14f27c1d41034b07ce1989014f5ad1d85d4248a9 100644 (file)
@@ -807,6 +807,75 @@ extern bool nb_operation_is_valid(enum nb_operation operation,
  */
 extern int nb_notification_send(const char *xpath, struct list *arguments);
 
+/*
+ * Associate a user pointer to a configuration node.
+ *
+ * This should be called by northbound 'create' callbacks in the NB_EV_APPLY
+ * phase only.
+ *
+ * dnode
+ *    libyang data node - only its XPath is used.
+ *
+ * entry
+ *    Arbitrary user-specified pointer.
+ */
+extern void nb_running_set_entry(const struct lyd_node *dnode, void *entry);
+
+/*
+ * Unset the user pointer associated to a configuration node.
+ *
+ * This should be called by northbound 'destroy' callbacks in the NB_EV_APPLY
+ * phase only.
+ *
+ * dnode
+ *    libyang data node - only its XPath is used.
+ *
+ * Returns:
+ *    The user pointer that was unset.
+ */
+extern void *nb_running_unset_entry(const struct lyd_node *dnode);
+
+/*
+ * Find the user pointer (if any) associated to a configuration node.
+ *
+ * The XPath associated to the configuration node can be provided directly or
+ * indirectly through a libyang data node.
+ *
+ * If an user point is not found, this function follows the parent nodes in the
+ * running configuration until an user pointer is found or until the root node
+ * is reached.
+ *
+ * dnode
+ *    libyang data node - only its XPath is used (can be NULL if 'xpath' is
+ *    provided).
+ *
+ * xpath
+ *    XPath of the configuration node (can be NULL if 'dnode' is provided).
+ *
+ * abort_if_not_found
+ *    When set to true, abort the program if no user pointer is found.
+ *
+ *    As a rule of thumb, this parameter should be set to true in the following
+ *    scenarios:
+ *    - Calling this function from any northbound configuration callback during
+ *      the NB_EV_APPLY phase.
+ *    - Calling this function from a 'delete' northbound configuration callback
+ *      during any phase.
+ *
+ *    In both the above cases, the given configuration node should contain an
+ *    user pointer except when there's a bug in the code, in which case it's
+ *    better to abort the program right away and eliminate the need for
+ *    unnecessary NULL checks.
+ *
+ *    In all other cases, this parameter should be set to false and the caller
+ *    should check if the function returned NULL or not.
+ *
+ * Returns:
+ *    User pointer if found, NULL otherwise.
+ */
+extern void *nb_running_get_entry(const struct lyd_node *dnode, const char *xpath,
+                                 bool abort_if_not_found);
+
 /*
  * Return a human-readable string representing a northbound event.
  *
index 4359c39cafce83cc1f76b09fa8e42d14cbb18970..33b6c247825e86f3622d7f983892de53d6fc0f9a 100644 (file)
@@ -374,7 +374,7 @@ static int frr_sr_state_data_iter_cb(const struct lys_node *snode,
 /* Callback for state retrieval. */
 static int frr_sr_state_cb(const char *xpath, sr_val_t **values,
                           size_t *values_cnt, uint64_t request_id,
-                          void *private_ctx)
+                          const char *original_xpath, void *private_ctx)
 {
        struct list *elements;
        struct yang_data *data;
index 52bb266f115bcbdd016ac45bdc8398a8d317146d..6b91969218fdb0c704e179dfc0a880342b2c69e5 100644 (file)
@@ -1359,6 +1359,35 @@ const char *prefix2str(union prefixconstptr pu, char *str, int size)
        return str;
 }
 
+void prefix_mcast_inet4_dump(const char *onfail, struct in_addr addr,
+               char *buf, int buf_size)
+{
+       int save_errno = errno;
+
+       if (addr.s_addr == INADDR_ANY)
+               strcpy(buf, "*");
+       else {
+               if (!inet_ntop(AF_INET, &addr, buf, buf_size)) {
+                       if (onfail)
+                               snprintf(buf, buf_size, "%s", onfail);
+               }
+       }
+
+       errno = save_errno;
+}
+
+const char *prefix_sg2str(const struct prefix_sg *sg, char *sg_str)
+{
+       char src_str[INET_ADDRSTRLEN];
+       char grp_str[INET_ADDRSTRLEN];
+
+       prefix_mcast_inet4_dump("<src?>", sg->src, src_str, sizeof(src_str));
+       prefix_mcast_inet4_dump("<grp?>", sg->grp, grp_str, sizeof(grp_str));
+       snprintf(sg_str, PREFIX_SG_STR_LEN, "(%s,%s)", src_str, grp_str);
+
+       return sg_str;
+}
+
 struct prefix *prefix_new(void)
 {
        struct prefix *p;
index a1c2086b8db4e6727a6f6d1401ec1d2b4d5c0e28..d3c387e102945e9df619485f6e0db9749e0d250a 100644 (file)
@@ -321,6 +321,15 @@ union prefixconstptr {
 /* Maximum string length of the result of prefix2str */
 #define PREFIX_STRLEN 80
 
+/*
+ * Longest possible length of a (S,G) string is 36 bytes
+ * 123.123.123.123 = 15 * 2
+ * (,) = 3
+ * NULL Character at end = 1
+ * (123.123.123.123,123.123.123.123)
+ */
+#define PREFIX_SG_STR_LEN 34
+
 /* Max bit/byte length of IPv4 address. */
 #define IPV4_MAX_BYTELEN    4
 #define IPV4_MAX_BITLEN    32
@@ -394,6 +403,9 @@ extern int str2prefix(const char *, struct prefix *);
 
 #define PREFIX2STR_BUFFER  PREFIX_STRLEN
 
+extern void prefix_mcast_inet4_dump(const char *onfail, struct in_addr addr,
+                               char *buf, int buf_size);
+extern const char *prefix_sg2str(const struct prefix_sg *sg, char *str);
 extern const char *prefix2str(union prefixconstptr, char *, int);
 extern int prefix_match(const struct prefix *, const struct prefix *);
 extern int prefix_match_network_statement(const struct prefix *,
index 59f24afe4a5aecc4a84f47b18a778401ed8d4dd1..a19707b1c928c1c7866ee5d5a3c08775cad52f57 100644 (file)
 #include "privs.h"
 #include "memory.h"
 #include "lib_errors.h"
+#include "lib/queue.h"
 
+DEFINE_MTYPE_STATIC(LIB, PRIVS, "Privilege information")
+
+/*
+ * Different capabilities/privileges apis have different characteristics: some
+ * are process-wide, and some are per-thread.
+ */
 #ifdef HAVE_CAPABILITIES
+#ifdef HAVE_LCAPS
+static const bool privs_per_process;  /* = false */
+#elif defined(HAVE_SOLARIS_CAPABILITIES)
+static const bool privs_per_process = true;
+#endif
+#else
+static const bool privs_per_process = true;
+#endif /* HAVE_CAPABILITIES */
 
-DEFINE_MTYPE_STATIC(LIB, PRIVS, "Privilege information")
+#ifdef HAVE_CAPABILITIES
 
 /* sort out some generic internal types for:
  *
@@ -698,25 +713,66 @@ static int getgrouplist(const char *user, gid_t group, gid_t *groups,
 }
 #endif /* HAVE_GETGROUPLIST */
 
+/*
+ * Helper function that locates a refcounting object to use: a process-wide
+ * object or a per-pthread object.
+ */
+static struct zebra_privs_refs_t *get_privs_refs(struct zebra_privs_t *privs)
+{
+       struct zebra_privs_refs_t *temp, *refs = NULL;
+       pthread_t tid;
+
+       if (privs_per_process)
+               refs = &(privs->process_refs);
+       else {
+               /* Locate - or create - the object for the current pthread. */
+               tid = pthread_self();
+
+               STAILQ_FOREACH(temp, &(privs->thread_refs), entry) {
+                       if (pthread_equal(temp->tid, tid)) {
+                               refs = temp;
+                               break;
+                       }
+               }
+
+               /* Need to create a new refcounting object. */
+               if (refs == NULL) {
+                       refs = XCALLOC(MTYPE_PRIVS,
+                                      sizeof(struct zebra_privs_refs_t));
+                       refs->tid = tid;
+                       STAILQ_INSERT_TAIL(&(privs->thread_refs), refs, entry);
+               }
+       }
+
+       return refs;
+}
+
 struct zebra_privs_t *_zprivs_raise(struct zebra_privs_t *privs,
                                    const char *funcname)
 {
        int save_errno = errno;
+       struct zebra_privs_refs_t *refs;
 
        if (!privs)
                return NULL;
 
-       /* If we're already elevated, just return */
+       /*
+        * Serialize 'raise' operations; particularly important for
+        * OSes where privs are process-wide.
+        */
        pthread_mutex_lock(&(privs->mutex));
        {
-               if (++(privs->refcount) == 1) {
+               /* Locate ref-counting object to use */
+               refs = get_privs_refs(privs);
+
+               if (++(refs->refcount) == 1) {
                        errno = 0;
                        if (privs->change(ZPRIVS_RAISE)) {
                                zlog_err("%s: Failed to raise privileges (%s)",
                                         funcname, safe_strerror(errno));
                        }
                        errno = save_errno;
-                       privs->raised_in_funcname = funcname;
+                       refs->raised_in_funcname = funcname;
                }
        }
        pthread_mutex_unlock(&(privs->mutex));
@@ -727,22 +783,27 @@ struct zebra_privs_t *_zprivs_raise(struct zebra_privs_t *privs,
 void _zprivs_lower(struct zebra_privs_t **privs)
 {
        int save_errno = errno;
+       struct zebra_privs_refs_t *refs;
 
        if (!*privs)
                return;
 
-       /* Don't lower privs if there's another caller */
+       /* Serialize 'lower privs' operation - particularly important
+        * when OS privs are process-wide.
+        */
        pthread_mutex_lock(&(*privs)->mutex);
        {
-               if (--((*privs)->refcount) == 0) {
+               refs = get_privs_refs(*privs);
+
+               if (--(refs->refcount) == 0) {
                        errno = 0;
                        if ((*privs)->change(ZPRIVS_LOWER)) {
                                zlog_err("%s: Failed to lower privileges (%s)",
-                                        (*privs)->raised_in_funcname,
+                                        refs->raised_in_funcname,
                                         safe_strerror(errno));
                        }
                        errno = save_errno;
-                       (*privs)->raised_in_funcname = NULL;
+                       refs->raised_in_funcname = NULL;
                }
        }
        pthread_mutex_unlock(&(*privs)->mutex);
@@ -761,7 +822,9 @@ void zprivs_preinit(struct zebra_privs_t *zprivs)
        }
 
        pthread_mutex_init(&(zprivs->mutex), NULL);
-       zprivs->refcount = 0;
+       zprivs->process_refs.refcount = 0;
+       zprivs->process_refs.raised_in_funcname = NULL;
+       STAILQ_INIT(&zprivs->thread_refs);
 
        if (zprivs->vty_group) {
                /* in a "NULL" setup, this is allowed to fail too, but still
@@ -919,6 +982,8 @@ void zprivs_init(struct zebra_privs_t *zprivs)
 
 void zprivs_terminate(struct zebra_privs_t *zprivs)
 {
+       struct zebra_privs_refs_t *refs;
+
        if (!zprivs) {
                fprintf(stderr, "%s: no privs struct given, terminating",
                        __func__);
@@ -941,6 +1006,11 @@ void zprivs_terminate(struct zebra_privs_t *zprivs)
        }
 #endif /* HAVE_LCAPS */
 
+       while ((refs = STAILQ_FIRST(&(zprivs->thread_refs))) != NULL) {
+               STAILQ_REMOVE_HEAD(&(zprivs->thread_refs), entry);
+               XFREE(MTYPE_PRIVS, refs);
+       }
+
        zprivs->change = zprivs_change_null;
        zprivs->current_state = zprivs_state_null;
        zprivs_null_state = ZPRIVS_LOWERED;
index 01ddba46223e207a7eecca88a867dddce71e96af..2b0b44b3f2f7ca485a3a7e52303592fdc67fac2a 100644 (file)
@@ -24,6 +24,7 @@
 #define _ZEBRA_PRIVS_H
 
 #include <pthread.h>
+#include "lib/queue.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -56,6 +57,13 @@ typedef enum {
        ZPRIVS_LOWER,
 } zebra_privs_ops_t;
 
+struct zebra_privs_refs_t {
+       STAILQ_ENTRY(zebra_privs_refs_t) entry;
+       pthread_t tid;
+       uint32_t refcount;
+       const char *raised_in_funcname;
+};
+
 struct zebra_privs_t {
        zebra_capabilities_t *caps_p; /* caps required for operation */
        zebra_capabilities_t *caps_i; /* caps to allow inheritance of */
@@ -63,11 +71,15 @@ struct zebra_privs_t {
        int cap_num_i;
 
        /* Mutex and counter used to avoid race conditions in multi-threaded
-        * processes. The privs elevation is process-wide, so we need to
-        * avoid changing the privilege status across threads.
+        * processes. If privs status is process-wide, we need to
+        * control changes to the privilege status among threads.
+        * If privs changes are per-thread, we need to be able to
+        * manage that too.
         */
        pthread_mutex_t mutex;
-       uint32_t refcount;
+       struct zebra_privs_refs_t process_refs;
+
+       STAILQ_HEAD(thread_refs_q, zebra_privs_refs_t) thread_refs;
 
        const char *user; /* user and group to run as */
        const char *group;
@@ -76,7 +88,6 @@ struct zebra_privs_t {
        int (*change)(zebra_privs_ops_t); /* change privileges, 0 on success */
        zebra_privs_current_t (*current_state)(
                void); /* current privilege state */
-       const char *raised_in_funcname;
 };
 
 struct zprivs_ids_t {
index 2a8077f8cf3297984d9d3a650d56edf44cbf9db5..69d3939596bb5ac05720844a8d806b5dc6c6bd6d 100644 (file)
@@ -38,6 +38,7 @@ typedef uint32_t vni_t;
 enum vxlan_flood_control {
        VXLAN_FLOOD_HEAD_END_REPL = 0,
        VXLAN_FLOOD_DISABLED,
+       VXLAN_FLOOD_PIM_SM,
 };
 
 #ifdef __cplusplus
index 7982d14fdddb9c56ada01af1ae0842d6e289b85f..2a2c155deede2928e979ad95a5d43d1c2c832ee2 100644 (file)
@@ -20,7 +20,6 @@
 #include <zebra.h>
 
 #include "log.h"
-#include "log_int.h"
 #include "lib_errors.h"
 #include "yang.h"
 #include "yang_translator.h"
@@ -513,42 +512,6 @@ void yang_dnode_change_leaf(struct lyd_node *dnode, const char *value)
        lyd_change_leaf((struct lyd_node_leaf_list *)dnode, value);
 }
 
-void yang_dnode_set_entry(const struct lyd_node *dnode, void *entry)
-{
-       assert(CHECK_FLAG(dnode->schema->nodetype, LYS_LIST | LYS_CONTAINER));
-       lyd_set_private(dnode, entry);
-}
-
-void *yang_dnode_get_entry(const struct lyd_node *dnode,
-                          bool abort_if_not_found)
-{
-       const struct lyd_node *orig_dnode = dnode;
-       char xpath[XPATH_MAXLEN];
-
-       while (dnode) {
-               switch (dnode->schema->nodetype) {
-               case LYS_CONTAINER:
-               case LYS_LIST:
-                       if (dnode->priv)
-                               return dnode->priv;
-                       break;
-               default:
-                       break;
-               }
-
-               dnode = dnode->parent;
-       }
-
-       if (!abort_if_not_found)
-               return NULL;
-
-       yang_dnode_get_path(orig_dnode, xpath, sizeof(xpath));
-       flog_err(EC_LIB_YANG_DNODE_NOT_FOUND,
-                "%s: failed to find entry [xpath %s]", __func__, xpath);
-       zlog_backtrace(LOG_ERR);
-       abort();
-}
-
 struct lyd_node *yang_dnode_new(struct ly_ctx *ly_ctx, bool config_only)
 {
        struct lyd_node *dnode;
@@ -629,12 +592,6 @@ struct yang_data *yang_data_list_find(const struct list *list,
        return NULL;
 }
 
-static void *ly_dup_cb(const void *priv)
-{
-       /* Make a shallow copy of the priv pointer. */
-       return (void *)priv;
-}
-
 /* Make libyang log its errors using FRR logging infrastructure. */
 static void ly_log_cb(LY_LOG_LEVEL level, const char *msg, const char *path)
 {
@@ -724,7 +681,6 @@ CPP_NOTICE("lib/yang: deprecated libyang <0.16.74 extension loading in use!")
                flog_err(EC_LIB_LIBYANG, "%s: ly_ctx_new() failed", __func__);
                exit(1);
        }
-       ly_ctx_set_priv_dup_clb(ly_native_ctx, ly_dup_cb);
 
 #ifndef LIBYANG_EXT_BUILTIN
        /* Detect if the required libyang plugin(s) were loaded successfully. */
index 15f0ec7ae6af0854809adf7de806880f46a6d495..6f8c84ab64276050933cbff90639e1b3bc98ea06 100644 (file)
@@ -402,51 +402,6 @@ extern bool yang_dnode_is_default_recursive(const struct lyd_node *dnode);
  */
 extern void yang_dnode_change_leaf(struct lyd_node *dnode, const char *value);
 
-/*
- * Set the libyang private pointer to a user pointer. Can only be used on YANG
- * lists and containers.
- *
- * dnode
- *    libyang data node to operate on.
- *
- * entry
- *    Arbitrary user-specified pointer.
- */
-extern void yang_dnode_set_entry(const struct lyd_node *dnode, void *entry);
-
-/*
- * Find the user pointer associated to the given libyang data node.
- *
- * The data node is traversed by following the parent pointers until an user
- * pointer is found or until the root node is reached.
- *
- * dnode
- *    libyang data node to operate on.
- *
- * abort_if_not_found
- *    When set to true, abort the program if no user pointer is found.
- *
- *    As a rule of thumb, this parameter should be set to true in the following
- *    scenarios:
- *    - Calling this function from any northbound configuration callback during
- *      the NB_EV_APPLY phase.
- *    - Calling this function from a 'delete' northbound configuration callback
- *      during any phase.
- *
- *    In both the above cases, the libyang data node should contain an user
- *    pointer except when there's a bug in the code, in which case it's better
- *    to abort the program right away and eliminate the need for unnecessary
- *    NULL checks.
- *
- *    In all other cases, this parameter should be set to false and the caller
- *    should check if the function returned NULL or not.
- *
- * Returns:
- *    User pointer if found, NULL otherwise.
- */
-extern void *yang_dnode_get_entry(const struct lyd_node *dnode,
-                                 bool abort_if_not_found);
-
 /*
  * Create a new libyang data node.
  *
index e5cab9e0f2f9d732af1ba76520d2d0760e26b731..4901c92743567dd60dcfa6e18280202202f90d29 100644 (file)
@@ -2701,6 +2701,17 @@ static int zclient_read(struct thread *thread)
                        (*zclient->iptable_notify_owner)(command,
                                                 zclient, length,
                                                 vrf_id);
+               break;
+       case ZEBRA_VXLAN_SG_ADD:
+               if (zclient->vxlan_sg_add)
+                       (*zclient->vxlan_sg_add)(command, zclient, length,
+                                                   vrf_id);
+               break;
+       case ZEBRA_VXLAN_SG_DEL:
+               if (zclient->vxlan_sg_del)
+                       (*zclient->vxlan_sg_del)(command, zclient, length,
+                                                   vrf_id);
+               break;
        default:
                break;
        }
index 3a054e5e7213e8f6a5eff878e9dcdc34321f1d14..0926281f2eb0d770338537a2245494ac20862581 100644 (file)
@@ -164,6 +164,8 @@ typedef enum {
        ZEBRA_IPTABLE_DELETE,
        ZEBRA_IPTABLE_NOTIFY_OWNER,
        ZEBRA_VXLAN_FLOOD_CONTROL,
+       ZEBRA_VXLAN_SG_ADD,
+       ZEBRA_VXLAN_SG_DEL,
 } zebra_message_types_t;
 
 struct redist_proto {
@@ -275,6 +277,10 @@ struct zclient {
                                    struct zclient *zclient,
                                    uint16_t length,
                                    vrf_id_t vrf_id);
+       int (*vxlan_sg_add)(int command, struct zclient *client,
+                       uint16_t length, vrf_id_t vrf_id);
+       int (*vxlan_sg_del)(int command, struct zclient *client,
+                       uint16_t length, vrf_id_t vrf_id_t);
 };
 
 /* Zebra API message flag. */
index 2d5acb87a91b5fc9814659a7f2406812431c2b70..77ea314d54d5bf154cf30699681fefb8ed3ae84f 100644 (file)
@@ -60,6 +60,7 @@
 #include "pim_ssm.h"
 #include "pim_nht.h"
 #include "pim_bfd.h"
+#include "pim_vxlan.h"
 #include "bfd.h"
 
 #ifndef VTYSH_EXTRACT_PL
@@ -1696,7 +1697,8 @@ static void pim_show_join_helper(struct vty *vty, struct pim_interface *pim_ifp,
        }
 }
 
-static void pim_show_join(struct pim_instance *pim, struct vty *vty, bool uj)
+static void pim_show_join(struct pim_instance *pim, struct vty *vty,
+                         struct prefix_sg *sg, bool uj)
 {
        struct pim_interface *pim_ifp;
        struct pim_ifchannel *ch;
@@ -1718,6 +1720,12 @@ static void pim_show_join(struct pim_instance *pim, struct vty *vty, bool uj)
                        continue;
 
                RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
+                       if (sg->grp.s_addr != 0
+                           && sg->grp.s_addr != ch->sg.grp.s_addr)
+                               continue;
+                       if (sg->src.s_addr != 0
+                           && sg->src.s_addr != ch->sg.src.s_addr)
+                       continue;
                        pim_show_join_helper(vty, pim_ifp, ch, json, now, uj);
                } /* scan interface channels */
        }
@@ -1956,7 +1964,7 @@ static void pim_show_state(struct pim_instance *pim, struct vty *vty,
                json = json_object_new_object();
        } else {
                vty_out(vty,
-                       "Codes: J -> Pim Join, I -> IGMP Report, S -> Source, * -> Inherited from (*,G)");
+                       "Codes: J -> Pim Join, I -> IGMP Report, S -> Source, * -> Inherited from (*,G), V -> VxLAN");
                vty_out(vty,
                        "\nInstalled Source           Group            IIF               OIL\n");
        }
@@ -2085,7 +2093,7 @@ static void pim_show_state(struct pim_instance *pim, struct vty *vty,
                        } else {
                                if (first_oif) {
                                        first_oif = 0;
-                                       vty_out(vty, "%s(%c%c%c%c)", out_ifname,
+                                       vty_out(vty, "%s(%c%c%c%c%c)", out_ifname,
                                                (c_oil->oif_flags[oif_vif_index]
                                                 & PIM_OIF_FLAG_PROTO_IGMP)
                                                        ? 'I'
@@ -2094,6 +2102,10 @@ static void pim_show_state(struct pim_instance *pim, struct vty *vty,
                                                 & PIM_OIF_FLAG_PROTO_PIM)
                                                        ? 'J'
                                                        : ' ',
+                                               (c_oil->oif_flags[oif_vif_index]
+                                                & PIM_OIF_FLAG_PROTO_VXLAN)
+                                                       ? 'V'
+                                                       : ' ',
                                                (c_oil->oif_flags[oif_vif_index]
                                                 & PIM_OIF_FLAG_PROTO_SOURCE)
                                                        ? 'S'
@@ -2103,7 +2115,7 @@ static void pim_show_state(struct pim_instance *pim, struct vty *vty,
                                                        ? '*'
                                                        : ' ');
                                } else
-                                       vty_out(vty, ", %s(%c%c%c%c)",
+                                       vty_out(vty, ", %s(%c%c%c%c%c)",
                                                out_ifname,
                                                (c_oil->oif_flags[oif_vif_index]
                                                 & PIM_OIF_FLAG_PROTO_IGMP)
@@ -2113,6 +2125,10 @@ static void pim_show_state(struct pim_instance *pim, struct vty *vty,
                                                 & PIM_OIF_FLAG_PROTO_PIM)
                                                        ? 'J'
                                                        : ' ',
+                                               (c_oil->oif_flags[oif_vif_index]
+                                                & PIM_OIF_FLAG_PROTO_VXLAN)
+                                                       ? 'V'
+                                                       : ' ',
                                                (c_oil->oif_flags[oif_vif_index]
                                                 & PIM_OIF_FLAG_PROTO_SOURCE)
                                                        ? 'S'
@@ -2335,7 +2351,7 @@ static const char *pim_reg_state2brief_str(enum pim_reg_state reg_state,
 }
 
 static void pim_show_upstream(struct pim_instance *pim, struct vty *vty,
-                             bool uj)
+                             struct prefix_sg *sg, bool uj)
 {
        struct listnode *upnode;
        struct pim_upstream *up;
@@ -2362,6 +2378,11 @@ static void pim_show_upstream(struct pim_instance *pim, struct vty *vty,
                char msdp_reg_timer[10];
                char state_str[PIM_REG_STATE_STR_LEN];
 
+               if (sg->grp.s_addr != 0 && sg->grp.s_addr != up->sg.grp.s_addr)
+                       continue;
+               if (sg->src.s_addr != 0 && sg->src.s_addr != up->sg.src.s_addr)
+                       continue;
+
                pim_inet4_dump("<src?>", up->sg.src, src_str, sizeof(src_str));
                pim_inet4_dump("<grp?>", up->sg.grp, grp_str, sizeof(grp_str));
                pim_time_uptime(uptime, sizeof(uptime),
@@ -3777,24 +3798,45 @@ DEFUN (show_ip_pim_interface_vrf_all,
        return CMD_SUCCESS;
 }
 
-DEFUN (show_ip_pim_join,
+DEFPY (show_ip_pim_join,
        show_ip_pim_join_cmd,
-       "show ip pim [vrf NAME] join [json]",
+       "show ip pim [vrf NAME] join [A.B.C.D$s_or_g [A.B.C.D$g]] [json$json]",
        SHOW_STR
        IP_STR
        PIM_STR
        VRF_CMD_HELP_STR
        "PIM interface join information\n"
+       "The Source or Group\n"
+       "The Group\n"
        JSON_STR)
 {
-       int idx = 2;
-       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
-       bool uj = use_json(argc, argv);
+       struct prefix_sg sg = {0};
+       struct vrf *v;
+       bool uj = !!json;
+       struct pim_instance *pim;
 
-       if (!vrf)
+       v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
+
+       if (!v) {
+               vty_out(vty, "%% Vrf specified: %s does not exist\n", vrf);
+               return CMD_WARNING;
+       }
+       pim = pim_get_pim_instance(v->vrf_id);
+
+       if (!pim) {
+               vty_out(vty, "%% Unable to find pim instance\n");
                return CMD_WARNING;
+       }
 
-       pim_show_join(vrf->info, vty, uj);
+       if (s_or_g.s_addr != 0) {
+               if (g.s_addr != 0) {
+                       sg.src = s_or_g;
+                       sg.grp = g;
+               } else
+                       sg.grp = s_or_g;
+       }
+
+       pim_show_join(pim, vty, &sg, uj);
 
        return CMD_SUCCESS;
 }
@@ -3809,6 +3851,7 @@ DEFUN (show_ip_pim_join_vrf_all,
        "PIM interface join information\n"
        JSON_STR)
 {
+       struct prefix_sg sg = {0};
        bool uj = use_json(argc, argv);
        struct vrf *vrf;
        bool first = true;
@@ -3823,7 +3866,7 @@ DEFUN (show_ip_pim_join_vrf_all,
                        first = false;
                } else
                        vty_out(vty, "VRF: %s\n", vrf->name);
-               pim_show_join(vrf->info, vty, uj);
+               pim_show_join(vrf->info, vty, &sg, uj);
        }
        if (uj)
                vty_out(vty, "}\n");
@@ -4022,24 +4065,44 @@ DEFUN (show_ip_pim_state_vrf_all,
        return CMD_SUCCESS;
 }
 
-DEFUN (show_ip_pim_upstream,
+DEFPY (show_ip_pim_upstream,
        show_ip_pim_upstream_cmd,
-       "show ip pim [vrf NAME] upstream [json]",
+       "show ip pim [vrf NAME] upstream [A.B.C.D$s_or_g [A.B.C.D$g]] [json$json]",
        SHOW_STR
        IP_STR
        PIM_STR
        VRF_CMD_HELP_STR
        "PIM upstream information\n"
+       "The Source or Group\n"
+       "The Group\n"
        JSON_STR)
 {
-       int idx = 2;
-       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
-       bool uj = use_json(argc, argv);
+       struct prefix_sg sg = {0};
+       struct vrf *v;
+       bool uj = !!json;
+       struct pim_instance *pim;
 
-       if (!vrf)
+       v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
+
+       if (!v) {
+               vty_out(vty, "%% Vrf specified: %s does not exist\n", vrf);
                return CMD_WARNING;
+       }
+       pim = pim_get_pim_instance(v->vrf_id);
 
-       pim_show_upstream(vrf->info, vty, uj);
+       if (!pim) {
+               vty_out(vty, "%% Unable to find pim instance\n");
+               return CMD_WARNING;
+       }
+
+       if (s_or_g.s_addr != 0) {
+               if (g.s_addr != 0) {
+                       sg.src = s_or_g;
+                       sg.grp = g;
+               } else
+                       sg.grp = s_or_g;
+       }
+       pim_show_upstream(pim, vty, &sg, uj);
 
        return CMD_SUCCESS;
 }
@@ -4054,6 +4117,7 @@ DEFUN (show_ip_pim_upstream_vrf_all,
        "PIM upstream information\n"
        JSON_STR)
 {
+       struct prefix_sg sg = {0};
        bool uj = use_json(argc, argv);
        struct vrf *vrf;
        bool first = true;
@@ -4068,7 +4132,7 @@ DEFUN (show_ip_pim_upstream_vrf_all,
                        first = false;
                } else
                        vty_out(vty, "VRF: %s\n", vrf->name);
-               pim_show_upstream(vrf->info, vty, uj);
+               pim_show_upstream(vrf->info, vty, &sg, uj);
        }
 
        return CMD_SUCCESS;
@@ -4493,8 +4557,8 @@ DEFUN (show_ip_multicast_vrf_all,
        return CMD_SUCCESS;
 }
 
-static void show_mroute(struct pim_instance *pim, struct vty *vty, bool fill,
-                       bool uj)
+static void show_mroute(struct pim_instance *pim, struct vty *vty,
+                       struct prefix_sg *sg, bool fill, bool uj)
 {
        struct listnode *node;
        struct channel_oil *c_oil;
@@ -4531,6 +4595,13 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty, bool fill,
                if (!c_oil->installed && !uj)
                        continue;
 
+               if (sg->grp.s_addr != 0 &&
+                   sg->grp.s_addr != c_oil->oil.mfcc_mcastgrp.s_addr)
+                       continue;
+               if (sg->src.s_addr != 0 &&
+                   sg->src.s_addr != c_oil->oil.mfcc_origin.s_addr)
+                       continue;
+
                pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, grp_str,
                               sizeof(grp_str));
                pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, src_str,
@@ -4616,6 +4687,11 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty, bool fill,
                                        json_object_boolean_true_add(
                                                json_ifp_out, "protocolIgmp");
 
+                               if (c_oil->oif_flags[oif_vif_index]
+                                   & PIM_OIF_FLAG_PROTO_VXLAN)
+                                       json_object_boolean_true_add(
+                                               json_ifp_out, "protocolVxlan");
+
                                if (c_oil->oif_flags[oif_vif_index]
                                    & PIM_OIF_FLAG_PROTO_SOURCE)
                                        json_object_boolean_true_add(
@@ -4658,6 +4734,11 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty, bool fill,
                                        strcpy(proto, "IGMP");
                                }
 
+                               if (c_oil->oif_flags[oif_vif_index]
+                                   & PIM_OIF_FLAG_PROTO_VXLAN) {
+                                       strcpy(proto, "VxLAN");
+                               }
+
                                if (c_oil->oif_flags[oif_vif_index]
                                    & PIM_OIF_FLAG_PROTO_SOURCE) {
                                        strcpy(proto, "SRC");
@@ -4818,28 +4899,43 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty, bool fill,
        }
 }
 
-DEFUN (show_ip_mroute,
+DEFPY (show_ip_mroute,
        show_ip_mroute_cmd,
-       "show ip mroute [vrf NAME] [fill] [json]",
+       "show ip mroute [vrf NAME] [A.B.C.D$s_or_g [A.B.C.D$g]] [fill$fill] [json$json]",
        SHOW_STR
        IP_STR
        MROUTE_STR
        VRF_CMD_HELP_STR
+       "The Source or Group\n"
+       "The Group\n"
        "Fill in Assumed data\n"
        JSON_STR)
 {
-       bool uj = use_json(argc, argv);
-       bool fill = false;
-       int idx = 2;
-       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+       struct prefix_sg sg = {0};
+       struct pim_instance *pim;
+       struct vrf *v;
 
-       if (!vrf)
+       v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
+
+       if (!v) {
+               vty_out(vty, "%% Vrf specified: %s does not exist\n", vrf);
                return CMD_WARNING;
+       }
+       pim = pim_get_pim_instance(v->vrf_id);
 
-       if (argv_find(argv, argc, "fill", &idx))
-               fill = true;
+       if (!pim) {
+               vty_out(vty, "%% Unable to find pim instance\n");
+               return CMD_WARNING;
+       }
 
-       show_mroute(vrf->info, vty, fill, uj);
+       if (s_or_g.s_addr != 0) {
+               if (g.s_addr != 0) {
+                       sg.src = s_or_g;
+                       sg.grp = g;
+               } else
+                       sg.grp = s_or_g;
+       }
+       show_mroute(pim, vty, &sg, !!fill, !!json);
        return CMD_SUCCESS;
 }
 
@@ -4853,6 +4949,7 @@ DEFUN (show_ip_mroute_vrf_all,
        "Fill in Assumed data\n"
        JSON_STR)
 {
+       struct prefix_sg sg = {0};
        bool uj = use_json(argc, argv);
        int idx = 4;
        struct vrf *vrf;
@@ -4872,7 +4969,7 @@ DEFUN (show_ip_mroute_vrf_all,
                        first = false;
                } else
                        vty_out(vty, "VRF: %s\n", vrf->name);
-               show_mroute(vrf->info, vty, fill, uj);
+               show_mroute(vrf->info, vty, &sg, fill, uj);
        }
        if (uj)
                vty_out(vty, "}\n");
@@ -5770,7 +5867,8 @@ static int pim_cmd_igmp_start(struct vty *vty, struct interface *ifp)
        pim_ifp = ifp->info;
 
        if (!pim_ifp) {
-               pim_ifp = pim_if_new(ifp, true, false, false);
+               pim_ifp = pim_if_new(ifp, true, false, false,
+                       false /*vxlan_term*/);
                if (!pim_ifp) {
                        vty_out(vty, "Could not enable IGMP on interface %s\n",
                                ifp->name);
@@ -6381,7 +6479,8 @@ static int pim_cmd_interface_add(struct interface *ifp)
        struct pim_interface *pim_ifp = ifp->info;
 
        if (!pim_ifp) {
-               pim_ifp = pim_if_new(ifp, false, true, false);
+               pim_ifp = pim_if_new(ifp, false, true, false,
+                       false /*vxlan_term*/);
                if (!pim_ifp) {
                        return 0;
                }
@@ -7380,6 +7479,29 @@ DEFUN (no_debug_pim_zebra,
        return CMD_SUCCESS;
 }
 
+DEFUN (debug_pim_vxlan,
+       debug_pim_vxlan_cmd,
+       "debug pim vxlan",
+       DEBUG_STR
+       DEBUG_PIM_STR
+       DEBUG_PIM_VXLAN_STR)
+{
+       PIM_DO_DEBUG_VXLAN;
+       return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_pim_vxlan,
+       no_debug_pim_vxlan_cmd,
+       "no debug pim vxlan",
+       NO_STR
+       DEBUG_STR
+       DEBUG_PIM_STR
+       DEBUG_PIM_VXLAN_STR)
+{
+       PIM_DONT_DEBUG_VXLAN;
+       return CMD_SUCCESS;
+}
+
 DEFUN (debug_msdp,
        debug_msdp_cmd,
        "debug msdp",
@@ -8681,6 +8803,369 @@ DEFUN (show_ip_msdp_sa_sg_vrf_all,
        return CMD_SUCCESS;
 }
 
+struct pim_sg_cache_walk_data {
+       struct vty *vty;
+       json_object *json;
+       json_object *json_group;
+       struct in_addr addr;
+       bool addr_match;
+};
+
+static void pim_show_vxlan_sg_entry(struct pim_vxlan_sg *vxlan_sg,
+                        struct pim_sg_cache_walk_data *cwd)
+{
+       struct vty *vty = cwd->vty;
+       json_object *json = cwd->json;
+       char src_str[INET_ADDRSTRLEN];
+       char grp_str[INET_ADDRSTRLEN];
+       json_object *json_row;
+       bool installed = (vxlan_sg->up)?TRUE:FALSE;
+       const char *iif_name = vxlan_sg->iif?vxlan_sg->iif->name:"-";
+       const char *oif_name;
+
+       if (pim_vxlan_is_orig_mroute(vxlan_sg))
+               oif_name = vxlan_sg->orig_oif?vxlan_sg->orig_oif->name:"";
+       else
+               oif_name = vxlan_sg->term_oif?vxlan_sg->term_oif->name:"";
+
+       if (cwd->addr_match && (vxlan_sg->sg.src.s_addr != cwd->addr.s_addr) &&
+                       (vxlan_sg->sg.grp.s_addr != cwd->addr.s_addr)) {
+               return;
+       }
+       pim_inet4_dump("<src?>", vxlan_sg->sg.src, src_str, sizeof(src_str));
+       pim_inet4_dump("<grp?>", vxlan_sg->sg.grp, grp_str, sizeof(grp_str));
+       if (json) {
+               json_object_object_get_ex(json, grp_str, &cwd->json_group);
+
+               if (!cwd->json_group) {
+                       cwd->json_group = json_object_new_object();
+                       json_object_object_add(json, grp_str,
+                                       cwd->json_group);
+               }
+
+               json_row = json_object_new_object();
+               json_object_string_add(json_row, "source", src_str);
+               json_object_string_add(json_row, "group", grp_str);
+               json_object_string_add(json_row, "input", iif_name);
+               json_object_string_add(json_row, "output", oif_name);
+               if (installed)
+                       json_object_boolean_true_add(json_row, "installed");
+               else
+                       json_object_boolean_false_add(json_row, "installed");
+               json_object_object_add(cwd->json_group, src_str, json_row);
+       } else {
+               vty_out(vty, "%-15s %-15s %-15s %-15s %-5s\n",
+                               src_str, grp_str, iif_name, oif_name,
+                               installed?"I":"");
+       }
+}
+
+static void pim_show_vxlan_sg_hash_entry(struct hash_backet *backet, void *arg)
+{
+       pim_show_vxlan_sg_entry((struct pim_vxlan_sg *)backet->data,
+                (struct pim_sg_cache_walk_data *)arg);
+}
+
+static void pim_show_vxlan_sg(struct pim_instance *pim,
+               struct vty *vty, bool uj)
+{
+       json_object *json = NULL;
+       struct pim_sg_cache_walk_data cwd;
+
+       if (uj) {
+               json = json_object_new_object();
+       } else {
+               vty_out(vty, "Codes: I -> installed\n");
+               vty_out(vty,
+                       "Source          Group           Input           Output          Flags\n");
+       }
+
+       memset(&cwd, 0, sizeof(cwd));
+       cwd.vty = vty;
+       cwd.json = json;
+       hash_iterate(pim->vxlan.sg_hash, pim_show_vxlan_sg_hash_entry, &cwd);
+
+       if (uj) {
+               vty_out(vty, "%s\n", json_object_to_json_string_ext(
+                                       json, JSON_C_TO_STRING_PRETTY));
+               json_object_free(json);
+       }
+}
+
+static void pim_show_vxlan_sg_match_addr(struct pim_instance *pim,
+               struct vty *vty, char *addr_str, bool uj)
+{
+       json_object *json = NULL;
+       struct pim_sg_cache_walk_data cwd;
+       int result = 0;
+
+       memset(&cwd, 0, sizeof(cwd));
+       result = inet_pton(AF_INET, addr_str, &cwd.addr);
+       if (result <= 0) {
+               vty_out(vty, "Bad address %s: errno=%d: %s\n", addr_str,
+                               errno, safe_strerror(errno));
+               return;
+       }
+
+       if (uj) {
+               json = json_object_new_object();
+       } else {
+               vty_out(vty, "Codes: I -> installed\n");
+               vty_out(vty,
+                       "Source          Group           Input           Output          Flags\n");
+       }
+
+       cwd.vty = vty;
+       cwd.json = json;
+       cwd.addr_match = TRUE;
+       hash_iterate(pim->vxlan.sg_hash, pim_show_vxlan_sg_hash_entry, &cwd);
+
+       if (uj) {
+               vty_out(vty, "%s\n", json_object_to_json_string_ext(
+                                       json, JSON_C_TO_STRING_PRETTY));
+               json_object_free(json);
+       }
+}
+
+static void pim_show_vxlan_sg_one(struct pim_instance *pim,
+               struct vty *vty, char *src_str, char *grp_str, bool uj)
+{
+       json_object *json = NULL;
+       struct prefix_sg sg;
+       int result = 0;
+       struct pim_vxlan_sg *vxlan_sg;
+       const char *iif_name;
+       bool installed;
+       const char *oif_name;
+
+       result = inet_pton(AF_INET, src_str, &sg.src);
+       if (result <= 0) {
+               vty_out(vty, "Bad src address %s: errno=%d: %s\n", src_str,
+                               errno, safe_strerror(errno));
+               return;
+       }
+       result = inet_pton(AF_INET, grp_str, &sg.grp);
+       if (result <= 0) {
+               vty_out(vty, "Bad grp address %s: errno=%d: %s\n", grp_str,
+                               errno, safe_strerror(errno));
+               return;
+       }
+
+       sg.family = AF_INET;
+       sg.prefixlen = IPV4_MAX_BITLEN;
+       if (uj)
+               json = json_object_new_object();
+
+       vxlan_sg = pim_vxlan_sg_find(pim, &sg);
+       if (vxlan_sg) {
+               installed = (vxlan_sg->up)?TRUE:FALSE;
+               iif_name = vxlan_sg->iif?vxlan_sg->iif->name:"-";
+
+               if (pim_vxlan_is_orig_mroute(vxlan_sg))
+                       oif_name =
+                               vxlan_sg->orig_oif?vxlan_sg->orig_oif->name:"";
+               else
+                       oif_name =
+                               vxlan_sg->term_oif?vxlan_sg->term_oif->name:"";
+
+               if (uj) {
+                       json_object_string_add(json, "source", src_str);
+                       json_object_string_add(json, "group", grp_str);
+                       json_object_string_add(json, "input", iif_name);
+                       json_object_string_add(json, "output", oif_name);
+                       if (installed)
+                               json_object_boolean_true_add(json, "installed");
+                       else
+                               json_object_boolean_false_add(json,
+                                       "installed");
+               } else {
+                       vty_out(vty, "SG : %s\n", vxlan_sg->sg_str);
+                       vty_out(vty, "  Input     : %s\n", iif_name);
+                       vty_out(vty, "  Output    : %s\n", oif_name);
+                       vty_out(vty, "  installed : %s\n",
+                               installed?"yes":"no");
+               }
+       }
+
+       if (uj) {
+               vty_out(vty, "%s\n", json_object_to_json_string_ext(
+                                       json, JSON_C_TO_STRING_PRETTY));
+               json_object_free(json);
+       }
+}
+
+DEFUN (show_ip_pim_vxlan_sg,
+       show_ip_pim_vxlan_sg_cmd,
+       "show ip pim [vrf NAME] vxlan-groups [A.B.C.D [A.B.C.D]] [json]",
+       SHOW_STR
+       IP_STR
+       PIM_STR
+       VRF_CMD_HELP_STR
+       "VxLAN BUM groups\n"
+       "source or group ip\n"
+       "group ip\n"
+       JSON_STR)
+{
+       bool uj = use_json(argc, argv);
+       struct vrf *vrf;
+       int idx = 2;
+
+       vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+       if (!vrf)
+               return CMD_WARNING;
+
+       char *src_ip = argv_find(argv, argc, "A.B.C.D", &idx) ?
+               argv[idx++]->arg:NULL;
+       char *grp_ip = idx < argc && argv_find(argv, argc, "A.B.C.D", &idx) ?
+               argv[idx]->arg:NULL;
+
+       if (src_ip && grp_ip)
+               pim_show_vxlan_sg_one(vrf->info, vty, src_ip, grp_ip, uj);
+       else if (src_ip)
+               pim_show_vxlan_sg_match_addr(vrf->info, vty, src_ip, uj);
+       else
+               pim_show_vxlan_sg(vrf->info, vty, uj);
+
+       return CMD_SUCCESS;
+}
+
+static void pim_show_vxlan_sg_work(struct pim_instance *pim,
+               struct vty *vty, bool uj)
+{
+       json_object *json = NULL;
+       struct pim_sg_cache_walk_data cwd;
+       struct listnode *node;
+       struct pim_vxlan_sg *vxlan_sg;
+
+       if (uj) {
+               json = json_object_new_object();
+       } else {
+               vty_out(vty, "Codes: I -> installed\n");
+               vty_out(vty,
+                       "Source          Group           Input           Flags\n");
+       }
+
+       memset(&cwd, 0, sizeof(cwd));
+       cwd.vty = vty;
+       cwd.json = json;
+       for (ALL_LIST_ELEMENTS_RO(pim_vxlan_p->work_list, node, vxlan_sg))
+               pim_show_vxlan_sg_entry(vxlan_sg, &cwd);
+
+       if (uj) {
+               vty_out(vty, "%s\n", json_object_to_json_string_ext(
+                                       json, JSON_C_TO_STRING_PRETTY));
+               json_object_free(json);
+       }
+}
+
+DEFUN_HIDDEN (show_ip_pim_vxlan_sg_work,
+              show_ip_pim_vxlan_sg_work_cmd,
+              "show ip pim [vrf NAME] vxlan-work [json]",
+              SHOW_STR
+              IP_STR
+              PIM_STR
+              VRF_CMD_HELP_STR
+              "VxLAN work list\n"
+              JSON_STR)
+{
+       bool uj = use_json(argc, argv);
+       struct vrf *vrf;
+       int idx = 2;
+
+       vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+       if (!vrf)
+               return CMD_WARNING;
+
+       pim_show_vxlan_sg_work(vrf->info, vty, uj);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN_HIDDEN (no_ip_pim_mlag,
+       no_ip_pim_mlag_cmd,
+       "no ip pim mlag",
+       NO_STR
+       IP_STR
+       PIM_STR
+       "MLAG\n")
+{
+       struct in_addr addr;
+
+       addr.s_addr = 0;
+       pim_vxlan_mlag_update(TRUE /*mlag_enable*/,
+               FALSE /*peer_state*/, PIM_VXLAN_MLAG_ROLE_SECONDARY,
+               NULL/*peerlink*/, &addr);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN_HIDDEN (ip_pim_mlag,
+       ip_pim_mlag_cmd,
+       "ip pim mlag INTERFACE role [primary|secondary] state [up|down] addr A.B.C.D",
+       IP_STR
+       PIM_STR
+       "MLAG\n"
+       "peerlink sub interface\n"
+       "MLAG role\n"
+       "MLAG role primary\n"
+       "MLAG role secondary\n"
+       "peer session state\n"
+       "peer session state up\n"
+       "peer session state down\n"
+       "configure PIP\n"
+       "unique ip address\n")
+{
+       struct interface *ifp;
+       const char *peerlink;
+       uint32_t role;
+       int idx;
+       bool peer_state;
+       int result;
+       struct in_addr reg_addr;
+
+       idx = 3;
+       peerlink = argv[idx]->arg;
+       ifp = if_lookup_by_name(peerlink, VRF_DEFAULT);
+       if (!ifp) {
+               vty_out(vty, "No such interface name %s\n", peerlink);
+               return CMD_WARNING;
+       }
+
+       idx += 2;
+       if (!strcmp(argv[idx]->arg, "primary")) {
+               role = PIM_VXLAN_MLAG_ROLE_PRIMARY;
+       } else if (!strcmp(argv[idx]->arg, "secondary")) {
+               role = PIM_VXLAN_MLAG_ROLE_SECONDARY;
+       } else {
+               vty_out(vty, "unknown MLAG role %s\n", argv[idx]->arg);
+               return CMD_WARNING;
+       }
+
+       idx += 2;
+       if (!strcmp(argv[idx]->arg, "up")) {
+               peer_state = TRUE;
+       } else if (strcmp(argv[idx]->arg, "down")) {
+               peer_state = FALSE;
+       } else {
+               vty_out(vty, "unknown MLAG state %s\n", argv[idx]->arg);
+               return CMD_WARNING;
+       }
+
+       idx += 2;
+       result = inet_pton(AF_INET, argv[idx]->arg, &reg_addr);
+       if (result <= 0) {
+               vty_out(vty, "%% Bad reg address %s: errno=%d: %s\n",
+                       argv[idx]->arg,
+                       errno, safe_strerror(errno));
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+       pim_vxlan_mlag_update(TRUE, peer_state, role, ifp, &reg_addr);
+
+       return CMD_SUCCESS;
+}
+
 void pim_cmd_init(void)
 {
        install_node(&interface_node,
@@ -8754,6 +9239,8 @@ void pim_cmd_init(void)
        install_element(VRF_NODE, &ip_pim_ecmp_rebalance_cmd);
        install_element(CONFIG_NODE, &no_ip_pim_ecmp_rebalance_cmd);
        install_element(VRF_NODE, &no_ip_pim_ecmp_rebalance_cmd);
+       install_element(CONFIG_NODE, &ip_pim_mlag_cmd);
+       install_element(CONFIG_NODE, &no_ip_pim_mlag_cmd);
 
        install_element(INTERFACE_NODE, &interface_ip_igmp_cmd);
        install_element(INTERFACE_NODE, &interface_no_ip_igmp_cmd);
@@ -8880,6 +9367,8 @@ void pim_cmd_init(void)
        install_element(ENABLE_NODE, &no_debug_ssmpingd_cmd);
        install_element(ENABLE_NODE, &debug_pim_zebra_cmd);
        install_element(ENABLE_NODE, &no_debug_pim_zebra_cmd);
+       install_element(ENABLE_NODE, &debug_pim_vxlan_cmd);
+       install_element(ENABLE_NODE, &no_debug_pim_vxlan_cmd);
        install_element(ENABLE_NODE, &debug_msdp_cmd);
        install_element(ENABLE_NODE, &no_debug_msdp_cmd);
        install_element(ENABLE_NODE, &debug_msdp_events_cmd);
@@ -8921,6 +9410,8 @@ void pim_cmd_init(void)
        install_element(CONFIG_NODE, &no_debug_ssmpingd_cmd);
        install_element(CONFIG_NODE, &debug_pim_zebra_cmd);
        install_element(CONFIG_NODE, &no_debug_pim_zebra_cmd);
+       install_element(CONFIG_NODE, &debug_pim_vxlan_cmd);
+       install_element(CONFIG_NODE, &no_debug_pim_vxlan_cmd);
        install_element(CONFIG_NODE, &debug_msdp_cmd);
        install_element(CONFIG_NODE, &no_debug_msdp_cmd);
        install_element(CONFIG_NODE, &debug_msdp_events_cmd);
@@ -8948,6 +9439,8 @@ void pim_cmd_init(void)
        install_element(VIEW_NODE, &show_ip_msdp_mesh_group_vrf_all_cmd);
        install_element(VIEW_NODE, &show_ip_pim_ssm_range_cmd);
        install_element(VIEW_NODE, &show_ip_pim_group_type_cmd);
+       install_element(VIEW_NODE, &show_ip_pim_vxlan_sg_cmd);
+       install_element(VIEW_NODE, &show_ip_pim_vxlan_sg_work_cmd);
        install_element(INTERFACE_NODE, &interface_pim_use_source_cmd);
        install_element(INTERFACE_NODE, &interface_no_pim_use_source_cmd);
        /* Install BFD command */
index b58da30bdd64847fb9d873d783d34c8e5db86da0..67d6e43c34a5a959958464034409f334b69388f6 100644 (file)
@@ -52,6 +52,7 @@
 #define DEBUG_PIM_PACKETDUMP_RECV_STR               "Dump received packets\n"
 #define DEBUG_PIM_TRACE_STR                         "PIM internal daemon activity\n"
 #define DEBUG_PIM_ZEBRA_STR                         "ZEBRA protocol activity\n"
+#define DEBUG_PIM_VXLAN_STR                         "PIM VxLAN events\n"
 #define DEBUG_SSMPINGD_STR                          "ssmpingd activity\n"
 #define CLEAR_IP_IGMP_STR                           "IGMP clear commands\n"
 #define CLEAR_IP_PIM_STR                            "PIM clear commands\n"
index 92d21cf42960621673f537eea61d6be37f884e5e..0fb7f176ce8e843989b56ee21f5ba0d469060bf5 100644 (file)
@@ -47,6 +47,7 @@
 #include "pim_nht.h"
 #include "pim_jp_agg.h"
 #include "pim_igmp_join.h"
+#include "pim_vxlan.h"
 
 static void pim_if_igmp_join_del_all(struct interface *ifp);
 static int igmp_join_sock(const char *ifname, ifindex_t ifindex,
@@ -109,7 +110,7 @@ static int pim_sec_addr_comp(const void *p1, const void *p2)
 }
 
 struct pim_interface *pim_if_new(struct interface *ifp, bool igmp, bool pim,
-                                bool ispimreg)
+                                bool ispimreg, bool is_vxlan_term)
 {
        struct pim_interface *pim_ifp;
 
@@ -178,7 +179,7 @@ struct pim_interface *pim_if_new(struct interface *ifp, bool igmp, bool pim,
 
        pim_sock_reset(ifp);
 
-       pim_if_add_vif(ifp, ispimreg);
+       pim_if_add_vif(ifp, ispimreg, is_vxlan_term);
 
        return pim_ifp;
 }
@@ -628,7 +629,7 @@ void pim_if_addr_add(struct connected *ifc)
          address assigned, then try to create a vif_index.
        */
        if (pim_ifp->mroute_vif_index < 0) {
-               pim_if_add_vif(ifp, false);
+               pim_if_add_vif(ifp, false, false /*vxlan_term*/);
        }
        pim_ifchannel_scan_forward_start(ifp);
 }
@@ -761,7 +762,7 @@ void pim_if_addr_add_all(struct interface *ifp)
         * address assigned, then try to create a vif_index.
         */
        if (pim_ifp->mroute_vif_index < 0) {
-               pim_if_add_vif(ifp, false);
+               pim_if_add_vif(ifp, false, false /*vxlan_term*/);
        }
        pim_ifchannel_scan_forward_start(ifp);
 
@@ -926,7 +927,7 @@ static int pim_iface_next_vif_index(struct interface *ifp)
 
   see also pim_if_find_vifindex_by_ifindex()
  */
-int pim_if_add_vif(struct interface *ifp, bool ispimreg)
+int pim_if_add_vif(struct interface *ifp, bool ispimreg, bool is_vxlan_term)
 {
        struct pim_interface *pim_ifp = ifp->info;
        struct in_addr ifaddr;
@@ -948,7 +949,7 @@ int pim_if_add_vif(struct interface *ifp, bool ispimreg)
        }
 
        ifaddr = pim_ifp->primary_address;
-       if (!ispimreg && PIM_INADDR_IS_ANY(ifaddr)) {
+       if (!ispimreg && !is_vxlan_term && PIM_INADDR_IS_ANY(ifaddr)) {
                zlog_warn(
                        "%s: could not get address for interface %s ifindex=%d",
                        __PRETTY_FUNCTION__, ifp->name, ifp->ifindex);
@@ -977,6 +978,10 @@ int pim_if_add_vif(struct interface *ifp, bool ispimreg)
        }
 
        pim_ifp->pim->iface_vif_index[pim_ifp->mroute_vif_index] = 1;
+
+       /* if the device qualifies as pim_vxlan iif/oif update vxlan entries */
+       pim_vxlan_add_vif(ifp);
+
        return 0;
 }
 
@@ -991,6 +996,9 @@ int pim_if_del_vif(struct interface *ifp)
                return -1;
        }
 
+       /* if the device was a pim_vxlan iif/oif update vxlan mroute entries */
+       pim_vxlan_del_vif(ifp);
+
        pim_mroute_del_vif(ifp);
 
        /*
@@ -1469,7 +1477,8 @@ void pim_if_create_pimreg(struct pim_instance *pim)
                pim->regiface = if_create(pimreg_name, pim->vrf_id);
                pim->regiface->ifindex = PIM_OIF_PIM_REGISTER_VIF;
 
-               pim_if_new(pim->regiface, false, false, true);
+               pim_if_new(pim->regiface, false, false, true,
+                       false /*vxlan_term*/);
        }
 }
 
index 5066998cb53bcb75a157ffda9f3e0cd6dcf45adf..fe96c077582cfd10b59d394aaef02b3c78ca40da 100644 (file)
@@ -158,7 +158,7 @@ void pim_if_init(struct pim_instance *pim);
 void pim_if_terminate(struct pim_instance *pim);
 
 struct pim_interface *pim_if_new(struct interface *ifp, bool igmp, bool pim,
-                                bool ispimreg);
+                                bool ispimreg, bool is_vxlan_term);
 void pim_if_delete(struct interface *ifp);
 void pim_if_addr_add(struct connected *ifc);
 void pim_if_addr_del(struct connected *ifc, int force_prim_as_any);
@@ -167,7 +167,7 @@ void pim_if_addr_del_all(struct interface *ifp);
 void pim_if_addr_del_all_igmp(struct interface *ifp);
 void pim_if_addr_del_all_pim(struct interface *ifp);
 
-int pim_if_add_vif(struct interface *ifp, bool ispimreg);
+int pim_if_add_vif(struct interface *ifp, bool ispimreg, bool is_vxlan_term);
 int pim_if_del_vif(struct interface *ifp);
 void pim_if_add_vif_all(struct pim_instance *pim);
 void pim_if_del_vif_all(struct pim_instance *pim);
index 092a2d76fa08c76821bebcaaba7686ff2511d02f..a2bf3d27839b64969df4d0cdc3cb8f6c44529213 100644 (file)
@@ -36,6 +36,8 @@
 
 static void pim_instance_terminate(struct pim_instance *pim)
 {
+       pim_vxlan_exit(pim);
+
        if (pim->ssm_info) {
                pim_ssm_terminate(pim->ssm_info);
                pim->ssm_info = NULL;
@@ -86,6 +88,7 @@ static struct pim_instance *pim_instance_init(struct vrf *vrf)
        pim->spt.plist = NULL;
 
        pim_msdp_init(pim, router->master);
+       pim_vxlan_init(pim);
 
        snprintf(hash_name, 64, "PIM %s RPF Hash", vrf->name);
        pim->rpf_hash = hash_create_size(256, pim_rpf_hash_key, pim_rpf_equal,
index e651356bfed4796651d955295abc4fa955feb13d..1740bcc7900d2ced781b72f8edd518f00f0f7186 100644 (file)
@@ -26,6 +26,7 @@
 #include "pim_str.h"
 #include "pim_msdp.h"
 #include "pim_assert.h"
+#include "pim_vxlan_instance.h"
 
 #if defined(HAVE_LINUX_MROUTE_H)
 #include <linux/mroute.h>
@@ -110,6 +111,7 @@ struct pim_instance {
        struct hash *channel_oil_hash;
 
        struct pim_msdp msdp;
+       struct pim_vxlan_instance vxlan;
 
        struct list *ssmpingd_list;
        struct in_addr ssmpingd_group_addr;
index dff16c41658511d0598c54e8d61a29c354db2f4f..2bbab67e458a730a85484161b3b842e1577aa431 100644 (file)
@@ -52,3 +52,4 @@ DEFINE_MTYPE(PIMD, PIM_PIM_INSTANCE, "PIM global state")
 DEFINE_MTYPE(PIMD, PIM_NEXTHOP_CACHE, "PIM nexthop cache state")
 DEFINE_MTYPE(PIMD, PIM_SSM_INFO, "PIM SSM configuration")
 DEFINE_MTYPE(PIMD, PIM_SPT_PLIST_NAME, "PIM SPT Prefix List Name")
+DEFINE_MTYPE(PIMD, PIM_VXLAN_SG, "PIM VxLAN mroute cache")
index 01189aca7681674e753c42afb4df11bd45f16d0f..e5ca57a15dc22eb0cbc192578b3e79dc2ea48854 100644 (file)
@@ -51,5 +51,6 @@ DECLARE_MTYPE(PIM_PIM_INSTANCE)
 DECLARE_MTYPE(PIM_NEXTHOP_CACHE)
 DECLARE_MTYPE(PIM_SSM_INFO)
 DECLARE_MTYPE(PIM_SPT_PLIST_NAME);
+DECLARE_MTYPE(PIM_VXLAN_SG)
 
 #endif /* _QUAGGA_PIM_MEMORY_H */
index a2d50aba5159c5b8f5d7b3360ee2122914836303..866a19fc9831defe3fed610912782df567ef403e 100644 (file)
@@ -42,6 +42,7 @@
 #include "pim_zlookup.h"
 #include "pim_ssm.h"
 #include "pim_sock.h"
+#include "pim_vxlan.h"
 
 static void mroute_read_on(struct pim_instance *pim);
 
@@ -896,6 +897,12 @@ int pim_mroute_add(struct channel_oil *c_oil, const char *name)
        int err;
        int orig = 0;
        int orig_iif_vif = 0;
+       struct pim_interface *pim_reg_ifp;
+       int orig_pimreg_ttl;
+       bool pimreg_ttl_reset = false;
+       struct pim_interface *vxlan_ifp;
+       int orig_term_ttl;
+       bool orig_term_ttl_reset = false;
 
        pim->mroute_add_last = pim_time_monotonic_sec();
        ++pim->mroute_add_events;
@@ -921,6 +928,37 @@ int pim_mroute_add(struct channel_oil *c_oil, const char *name)
                c_oil->oil.mfcc_ttls[c_oil->oil.mfcc_parent] = 1;
        }
 
+       if (c_oil->up) {
+               /* suppress pimreg in the OIL if the mroute is not supposed to
+                * trigger register encapsulated data
+                */
+               if (PIM_UPSTREAM_FLAG_TEST_NO_PIMREG_DATA(c_oil->up->flags)) {
+                       pim_reg_ifp = pim->regiface->info;
+                       orig_pimreg_ttl =
+                               c_oil->oil.mfcc_ttls[pim_reg_ifp->mroute_vif_index];
+                       c_oil->oil.mfcc_ttls[pim_reg_ifp->mroute_vif_index] = 0;
+                       /* remember to flip it back after MFC programming */
+                       pimreg_ttl_reset = true;
+               }
+
+               vxlan_ifp = pim_vxlan_get_term_ifp(pim);
+               /* 1. vxlan termination device must never be added to the
+                * origination mroute (and that can actually happen because
+                * of XG inheritance from the termination mroute) otherwise
+                * traffic will end up looping.
+                * 2. vxlan termination device should be removed from the non-DF
+                * to prevent duplicates to the overlay rxer
+                */
+               if (vxlan_ifp &&
+                       (PIM_UPSTREAM_FLAG_TEST_SRC_VXLAN_ORIG(c_oil->up->flags) ||
+                        PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(c_oil->up->flags))) {
+                       orig_term_ttl_reset = true;
+                       orig_term_ttl =
+                               c_oil->oil.mfcc_ttls[vxlan_ifp->mroute_vif_index];
+                       c_oil->oil.mfcc_ttls[vxlan_ifp->mroute_vif_index] = 0;
+               }
+       }
+
        /*
         * If we have an unresolved cache entry for the S,G
         * it is owned by the pimreg for the incoming IIF
@@ -947,6 +985,14 @@ int pim_mroute_add(struct channel_oil *c_oil, const char *name)
        if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY)
                c_oil->oil.mfcc_ttls[c_oil->oil.mfcc_parent] = orig;
 
+       if (pimreg_ttl_reset)
+               c_oil->oil.mfcc_ttls[pim_reg_ifp->mroute_vif_index] =
+                       orig_pimreg_ttl;
+
+       if (orig_term_ttl_reset)
+               c_oil->oil.mfcc_ttls[vxlan_ifp->mroute_vif_index] =
+                       orig_term_ttl;
+
        if (err) {
                zlog_warn(
                        "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_MFC): errno=%d: %s",
index 55d26113f7c51981729486117c00599589a6fb3d..5945bc55fd9299577ef155fb863a248e92e1ed1d 100644 (file)
@@ -320,6 +320,7 @@ int pim_channel_add_oif(struct channel_oil *channel_oil, struct interface *oif,
 {
        struct pim_interface *pim_ifp;
        int old_ttl;
+       bool allow_iif_in_oil = false;
 
        /*
         * If we've gotten here we've gone bad, but let's
@@ -344,7 +345,14 @@ int pim_channel_add_oif(struct channel_oil *channel_oil, struct interface *oif,
          by both source and receiver attached to the same interface. See
          TODO T22.
        */
-       if (pim_ifp->mroute_vif_index == channel_oil->oil.mfcc_parent) {
+       if (channel_oil->up &&
+                       PIM_UPSTREAM_FLAG_TEST_ALLOW_IIF_IN_OIL(
+                               channel_oil->up->flags)) {
+               allow_iif_in_oil = true;
+       }
+
+       if (!allow_iif_in_oil &&
+               pim_ifp->mroute_vif_index == channel_oil->oil.mfcc_parent) {
                channel_oil->oil_inherited_rescan = 1;
                if (PIM_DEBUG_MROUTE) {
                        char group_str[INET_ADDRSTRLEN];
index 8b95324142c23f4f5c2261228fb14b7d9a9e37cd..c5106d01cbe067b71485bee16050b6e8651417f7 100644 (file)
 #define PIM_OIF_FLAG_PROTO_PIM    (1 << 1)
 #define PIM_OIF_FLAG_PROTO_SOURCE (1 << 2)
 #define PIM_OIF_FLAG_PROTO_STAR   (1 << 3)
-#define PIM_OIF_FLAG_PROTO_ANY                                                 \
-       (PIM_OIF_FLAG_PROTO_IGMP | PIM_OIF_FLAG_PROTO_PIM                      \
-        | PIM_OIF_FLAG_PROTO_SOURCE | PIM_OIF_FLAG_PROTO_STAR)
+#define PIM_OIF_FLAG_PROTO_VXLAN  (1 << 4)
+#define PIM_OIF_FLAG_PROTO_ANY                                 \
+       (PIM_OIF_FLAG_PROTO_IGMP | PIM_OIF_FLAG_PROTO_PIM      \
+        | PIM_OIF_FLAG_PROTO_SOURCE | PIM_OIF_FLAG_PROTO_STAR \
+        | PIM_OIF_FLAG_PROTO_VXLAN)
 
 /*
  * We need a pimreg vif id from the kernel.
index 386ed1d4240775ffeab660e64fbd86d208734ef1..431236eebe720f2f2717bf0802caedebb313cc2c 100644 (file)
@@ -43,6 +43,7 @@
 #include "pim_join.h"
 #include "pim_util.h"
 #include "pim_ssm.h"
+#include "pim_vxlan.h"
 
 struct thread *send_test_packet_timer = NULL;
 
@@ -60,6 +61,7 @@ void pim_register_join(struct pim_upstream *up)
        pim_channel_add_oif(up->channel_oil, pim->regiface,
                            PIM_OIF_FLAG_PROTO_PIM);
        up->reg_state = PIM_REG_JOIN;
+       pim_vxlan_update_sg_reg_state(pim, up, TRUE /*reg_join*/);
 }
 
 void pim_register_stop_send(struct interface *ifp, struct prefix_sg *sg,
@@ -145,6 +147,8 @@ int pim_register_stop_recv(struct interface *ifp, uint8_t *buf, int buf_size)
                pim_channel_del_oif(upstream->channel_oil, pim->regiface,
                                    PIM_OIF_FLAG_PROTO_PIM);
                pim_upstream_start_register_stop_timer(upstream, 0);
+               pim_vxlan_update_sg_reg_state(pim, upstream,
+                       FALSE /*reg_join*/);
                break;
        case PIM_REG_JOIN_PENDING:
                upstream->reg_state = PIM_REG_PRUNE;
@@ -219,6 +223,54 @@ void pim_register_send(const uint8_t *buf, int buf_size, struct in_addr src,
        }
 }
 
+void pim_null_register_send(struct pim_upstream *up)
+{
+       struct ip ip_hdr;
+       struct pim_interface *pim_ifp;
+       struct pim_rpf *rpg;
+       struct in_addr src;
+
+       pim_ifp = up->rpf.source_nexthop.interface->info;
+       if (!pim_ifp) {
+               if (PIM_DEBUG_TRACE)
+                       zlog_debug(
+                               "%s: Cannot send null-register for %s no valid iif",
+                               __PRETTY_FUNCTION__, up->sg_str);
+               return;
+       }
+
+       rpg = RP(pim_ifp->pim, up->sg.grp);
+       if (!rpg) {
+               if (PIM_DEBUG_TRACE)
+                       zlog_debug(
+                               "%s: Cannot send null-register for %s no RPF to the RP",
+                               __PRETTY_FUNCTION__, up->sg_str);
+               return;
+       }
+
+       memset(&ip_hdr, 0, sizeof(struct ip));
+       ip_hdr.ip_p = PIM_IP_PROTO_PIM;
+       ip_hdr.ip_hl = 5;
+       ip_hdr.ip_v = 4;
+       ip_hdr.ip_src = up->sg.src;
+       ip_hdr.ip_dst = up->sg.grp;
+       ip_hdr.ip_len = htons(20);
+
+       /* checksum is broken */
+       src = pim_ifp->primary_address;
+       if (PIM_UPSTREAM_FLAG_TEST_SRC_VXLAN_ORIG(up->flags)) {
+               if (!pim_vxlan_get_register_src(pim_ifp->pim, up, &src)) {
+                       if (PIM_DEBUG_TRACE)
+                               zlog_debug(
+                                       "%s: Cannot send null-register for %s vxlan-aa PIP unavailable",
+                                       __PRETTY_FUNCTION__, up->sg_str);
+                       return;
+               }
+       }
+       pim_register_send((uint8_t *)&ip_hdr, sizeof(struct ip),
+                       src, rpg, 1, up);
+}
+
 /*
  * 4.4.2 Receiving Register Messages at the RP
  *
index 906d093bb76ba575562750403c205f616d4e50f4..c5a28fee41b4c78dfebfa7396918169d2c74bb1c 100644 (file)
@@ -42,5 +42,6 @@ void pim_register_send(const uint8_t *buf, int buf_size, struct in_addr src,
 void pim_register_stop_send(struct interface *ifp, struct prefix_sg *sg,
                            struct in_addr src, struct in_addr originator);
 void pim_register_join(struct pim_upstream *up);
+void pim_null_register_send(struct pim_upstream *up);
 
 #endif
index 8cc8b7481cbb0a1ab34a7ff2b553c483524b7786..afe3886aa5b98e32f7d2bdb41352f89eeadf20cc 100644 (file)
@@ -204,6 +204,9 @@ enum pim_rpf_result pim_rpf_update(struct pim_instance *pim,
        struct prefix src, grp;
        bool neigh_needed = true;
 
+       if (PIM_UPSTREAM_FLAG_TEST_STATIC_IIF(up->flags))
+               return PIM_RPF_OK;
+
        if (up->upstream_addr.s_addr == INADDR_ANY) {
                zlog_debug("%s: RP is not configured yet for %s",
                        __PRETTY_FUNCTION__, up->sg_str);
index fa1a6e624c5a8af1b0cc530d2e6694f6a450b33b..f6acd087394a3012ee91299530d89425cb9040a9 100644 (file)
@@ -42,47 +42,12 @@ void pim_addr_dump(const char *onfail, struct prefix *p, char *buf,
        errno = save_errno;
 }
 
-void pim_inet4_dump(const char *onfail, struct in_addr addr, char *buf,
-                   int buf_size)
-{
-       int save_errno = errno;
-
-       if (addr.s_addr == INADDR_ANY)
-               strcpy(buf, "*");
-       else {
-               if (!inet_ntop(AF_INET, &addr, buf, buf_size)) {
-                       zlog_warn(
-                               "pim_inet4_dump: inet_ntop(AF_INET,buf_size=%d): errno=%d: %s",
-                               buf_size, errno, safe_strerror(errno));
-                       if (onfail)
-                               snprintf(buf, buf_size, "%s", onfail);
-               }
-       }
-
-       errno = save_errno;
-}
-
 char *pim_str_sg_dump(const struct prefix_sg *sg)
 {
-       char src_str[INET_ADDRSTRLEN];
-       char grp_str[INET_ADDRSTRLEN];
        static char sg_str[PIM_SG_LEN];
 
-       pim_inet4_dump("<src?>", sg->src, src_str, sizeof(src_str));
-       pim_inet4_dump("<grp?>", sg->grp, grp_str, sizeof(grp_str));
-       snprintf(sg_str, PIM_SG_LEN, "(%s,%s)", src_str, grp_str);
+       pim_str_sg_set(sg, sg_str);
 
        return sg_str;
 }
 
-char *pim_str_sg_set(const struct prefix_sg *sg, char *sg_str)
-{
-       char src_str[INET_ADDRSTRLEN];
-       char grp_str[INET_ADDRSTRLEN];
-
-       pim_inet4_dump("<src?>", sg->src, src_str, sizeof(src_str));
-       pim_inet4_dump("<grp?>", sg->grp, grp_str, sizeof(grp_str));
-       snprintf(sg_str, PIM_SG_LEN, "(%s,%s)", src_str, grp_str);
-
-       return sg_str;
-}
index 12a33a810f66244ba02e5b8b1fea41c06d8ecc07..94ba32415400f4e68a748e226faa7f2aecf0d3eb 100644 (file)
  * NULL Character at end = 1
  * (123.123.123.123,123,123,123,123)
  */
-#define PIM_SG_LEN 36
+#define PIM_SG_LEN PREFIX_SG_STR_LEN
+#define pim_inet4_dump prefix_mcast_inet4_dump
+#define pim_str_sg_set prefix_sg2str
 
 void pim_addr_dump(const char *onfail, struct prefix *p, char *buf,
                   int buf_size);
 void pim_inet4_dump(const char *onfail, struct in_addr addr, char *buf,
                    int buf_size);
 char *pim_str_sg_dump(const struct prefix_sg *sg);
-char *pim_str_sg_set(const struct prefix_sg *sg, char *sg_str);
 
 #endif
index 04137b0b78cd311c704f0176aef55c9cbfafb03b..b708e86a2050891625ab06f6a1c44e4beed6d5a7 100644 (file)
@@ -51,6 +51,7 @@
 #include "pim_jp_agg.h"
 #include "pim_nht.h"
 #include "pim_ssm.h"
+#include "pim_vxlan.h"
 
 static void join_timer_stop(struct pim_upstream *up);
 static void
@@ -483,6 +484,13 @@ static int pim_upstream_could_register(struct pim_upstream *up)
 {
        struct pim_interface *pim_ifp = NULL;
 
+       /* FORCE_PIMREG is a generic flag to let an app like VxLAN-AA register
+        * a source on an upstream entry even if the source is not directly
+        * connected on the IIF.
+        */
+       if (PIM_UPSTREAM_FLAG_TEST_FORCE_PIMREG(up->flags))
+               return 1;
+
        if (up->rpf.source_nexthop.interface)
                pim_ifp = up->rpf.source_nexthop.interface->info;
        else {
@@ -576,9 +584,10 @@ void pim_upstream_switch(struct pim_instance *pim, struct pim_upstream *up,
        pim_upstream_update_assert_tracking_desired(up);
 
        if (new_state == PIM_UPSTREAM_JOINED) {
+               pim_upstream_inherited_olist_decide(pim, up);
                if (old_state != PIM_UPSTREAM_JOINED) {
                        int old_fhr = PIM_UPSTREAM_FLAG_TEST_FHR(up->flags);
-                       forward_on(up);
+
                        pim_msdp_up_join_state_changed(pim, up);
                        if (pim_upstream_could_register(up)) {
                                PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
@@ -593,8 +602,6 @@ void pim_upstream_switch(struct pim_instance *pim, struct pim_upstream *up,
                                pim_upstream_send_join(up);
                                join_timer_start(up);
                        }
-               } else {
-                       forward_on(up);
                }
        } else {
 
@@ -647,6 +654,23 @@ int pim_upstream_compare(void *arg1, void *arg2)
        return 0;
 }
 
+void pim_upstream_fill_static_iif(struct pim_upstream *up,
+                               struct interface *incoming)
+{
+       up->rpf.source_nexthop.interface = incoming;
+
+       /* reset other parameters to matched a connected incoming interface */
+       up->rpf.source_nexthop.mrib_nexthop_addr.family = AF_INET;
+       up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr =
+               PIM_NET_INADDR_ANY;
+       up->rpf.source_nexthop.mrib_metric_preference =
+               ZEBRA_CONNECT_DISTANCE_DEFAULT;
+       up->rpf.source_nexthop.mrib_route_metric = 0;
+       up->rpf.rpf_addr.family = AF_INET;
+       up->rpf.rpf_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY;
+
+}
+
 static struct pim_upstream *pim_upstream_new(struct pim_instance *pim,
                                             struct prefix_sg *sg,
                                             struct interface *incoming,
@@ -712,13 +736,19 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim,
        if (up->sg.src.s_addr != INADDR_ANY)
                wheel_add_item(pim->upstream_sg_wheel, up);
 
-       if (up->upstream_addr.s_addr == INADDR_ANY)
+       if (PIM_UPSTREAM_FLAG_TEST_STATIC_IIF(up->flags)) {
+               pim_upstream_fill_static_iif(up, incoming);
+               pim_ifp = up->rpf.source_nexthop.interface->info;
+               assert(pim_ifp);
+               up->channel_oil = pim_channel_oil_add(pim,
+                               &up->sg, pim_ifp->mroute_vif_index);
+       } else if (up->upstream_addr.s_addr == INADDR_ANY) {
                /* Create a dummmy channel oil with incoming ineterface MAXVIFS,
                 * since RP is not configured
                 */
                up->channel_oil = pim_channel_oil_add(pim, &up->sg, MAXVIFS);
 
-       else {
+       else {
                rpf_result = pim_rpf_update(pim, up, NULL, 1);
                if (rpf_result == PIM_RPF_FAILURE) {
                        if (PIM_DEBUG_TRACE)
@@ -1117,14 +1147,21 @@ static void pim_upstream_fhr_kat_start(struct pim_upstream *up)
  * KAT expiry indicates that flow is inactive. If the flow was created or
  * maintained by activity now is the time to deref it.
  */
-static int pim_upstream_keep_alive_timer(struct thread *t)
+struct pim_upstream *pim_upstream_keep_alive_timer_proc(
+               struct pim_upstream *up)
 {
-       struct pim_upstream *up;
        struct pim_instance *pim;
 
-       up = THREAD_ARG(t);
        pim = up->channel_oil->pim;
 
+       if (PIM_UPSTREAM_FLAG_TEST_DISABLE_KAT_EXPIRY(up->flags)) {
+               /* if the router is a PIM vxlan encapsulator we prevent expiry
+                * of KAT as the mroute is pre-setup without any traffic
+                */
+               pim_upstream_keep_alive_timer_start(up, pim->keep_alive_time);
+               return up;
+       }
+
        if (I_am_RP(pim, up->sg.grp)) {
                pim_br_clear_pmbr(&up->sg);
                /*
@@ -1144,12 +1181,12 @@ static int pim_upstream_keep_alive_timer(struct thread *t)
                                "kat expired on %s[%s]; remove stream reference",
                                up->sg_str, pim->vrf->name);
                PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up->flags);
-               pim_upstream_del(pim, up, __PRETTY_FUNCTION__);
+               up = pim_upstream_del(pim, up, __PRETTY_FUNCTION__);
        } else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags)) {
                struct pim_upstream *parent = up->parent;
 
                PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(up->flags);
-               pim_upstream_del(pim, up, __PRETTY_FUNCTION__);
+               up = pim_upstream_del(pim, up, __PRETTY_FUNCTION__);
 
                if (parent) {
                        pim_jp_agg_single_upstream_send(&parent->rpf, parent,
@@ -1157,6 +1194,15 @@ static int pim_upstream_keep_alive_timer(struct thread *t)
                }
        }
 
+       return up;
+}
+static int pim_upstream_keep_alive_timer(struct thread *t)
+{
+       struct pim_upstream *up;
+
+       up = THREAD_ARG(t);
+
+       pim_upstream_keep_alive_timer_proc(up);
        return 0;
 }
 
@@ -1371,8 +1417,6 @@ static int pim_upstream_register_stop_timer(struct thread *t)
        struct pim_interface *pim_ifp;
        struct pim_instance *pim;
        struct pim_upstream *up;
-       struct pim_rpf *rpg;
-       struct ip ip_hdr;
        up = THREAD_ARG(t);
        pim = up->channel_oil->pim;
 
@@ -1388,6 +1432,7 @@ static int pim_upstream_register_stop_timer(struct thread *t)
                up->reg_state = PIM_REG_JOIN;
                pim_channel_add_oif(up->channel_oil, pim->regiface,
                                    PIM_OIF_FLAG_PROTO_PIM);
+               pim_vxlan_update_sg_reg_state(pim, up, TRUE /*reg_join*/);
                break;
        case PIM_REG_JOIN:
                break;
@@ -1420,24 +1465,7 @@ static int pim_upstream_register_stop_timer(struct thread *t)
                                        __PRETTY_FUNCTION__);
                        return 0;
                }
-               rpg = RP(pim_ifp->pim, up->sg.grp);
-               if (!rpg) {
-                       if (PIM_DEBUG_TRACE)
-                               zlog_debug(
-                                       "%s: Cannot send register for %s no RPF to the RP",
-                                       __PRETTY_FUNCTION__, up->sg_str);
-                       return 0;
-               }
-               memset(&ip_hdr, 0, sizeof(struct ip));
-               ip_hdr.ip_p = PIM_IP_PROTO_PIM;
-               ip_hdr.ip_hl = 5;
-               ip_hdr.ip_v = 4;
-               ip_hdr.ip_src = up->sg.src;
-               ip_hdr.ip_dst = up->sg.grp;
-               ip_hdr.ip_len = htons(20);
-               // checksum is broken
-               pim_register_send((uint8_t *)&ip_hdr, sizeof(struct ip),
-                                 pim_ifp->primary_address, rpg, 1, up);
+               pim_null_register_send(up);
                break;
        default:
                break;
index 70e70140d19b0c2838c7af9465b275efafee1784..13a3dcdf8ca7472c0b26fcc5b742df64ea0e2d06 100644 (file)
 #define PIM_UPSTREAM_FLAG_MASK_SRC_MSDP                (1 << 6)
 #define PIM_UPSTREAM_FLAG_MASK_SEND_SG_RPT_PRUNE       (1 << 7)
 #define PIM_UPSTREAM_FLAG_MASK_SRC_LHR                 (1 << 8)
+/* In the case of pim vxlan we prime the pump by registering the
+ * vxlan source and keeping the SPT (FHR-RP) alive by sending periodic
+ * NULL registers. So we need to prevent KAT expiry because of the
+ * lack of BUM traffic.
+ */
+#define PIM_UPSTREAM_FLAG_MASK_DISABLE_KAT_EXPIRY      (1 << 9)
+/* for pim vxlan we need to pin the IIF to lo or MLAG-ISL on the
+ * originating VTEP. This flag allows that by setting IIF to the
+ * value specified and preventing next-hop-tracking on the entry
+ */
+#define PIM_UPSTREAM_FLAG_MASK_STATIC_IIF              (1 << 10)
+#define PIM_UPSTREAM_FLAG_MASK_ALLOW_IIF_IN_OIL        (1 << 11)
+/* Disable pimreg encasulation for a flow */
+#define PIM_UPSTREAM_FLAG_MASK_NO_PIMREG_DATA          (1 << 12)
+/* For some MDTs we need to register the router as a source even
+ * if the not DR or directly connected on the IIF. This is typically
+ * needed on a VxLAN-AA (MLAG) setup.
+ */
+#define PIM_UPSTREAM_FLAG_MASK_FORCE_PIMREG            (1 << 13)
+/* VxLAN origination mroute - SG was registered by EVPN where S is the
+ * local VTEP IP and G is the BUM multicast group address
+ */
+#define PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_ORIG          (1 << 14)
+/* VxLAN termination mroute - *G entry where G is the BUM multicast group
+ * address
+ */
+#define PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_TERM          (1 << 15)
+/* MLAG mroute - synced to the MLAG peer and subject to DF (designated
+ * forwarder) election
+ */
+#define PIM_UPSTREAM_FLAG_MASK_MLAG_VXLAN              (1 << 16)
+/* MLAG mroute that lost the DF election with peer and is installed in
+ * a dormant state i.e. MLAG OIFs are removed from the MFC.
+ * In most cases the OIL is empty (but not not always) simply
+ * blackholing the traffic pulled down to the LHR.
+ */
+#define PIM_UPSTREAM_FLAG_MASK_MLAG_NON_DF             (1 << 17)
 #define PIM_UPSTREAM_FLAG_ALL 0xFFFFFFFF
 
 #define PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED)
 #define PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_SRC_MSDP)
 #define PIM_UPSTREAM_FLAG_TEST_SEND_SG_RPT_PRUNE(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_SEND_SG_RPT_PRUNE)
 #define PIM_UPSTREAM_FLAG_TEST_SRC_LHR(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_SRC_LHR)
+#define PIM_UPSTREAM_FLAG_TEST_DISABLE_KAT_EXPIRY(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_DISABLE_KAT_EXPIRY)
+#define PIM_UPSTREAM_FLAG_TEST_STATIC_IIF(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_STATIC_IIF)
+#define PIM_UPSTREAM_FLAG_TEST_ALLOW_IIF_IN_OIL(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_ALLOW_IIF_IN_OIL)
+#define PIM_UPSTREAM_FLAG_TEST_NO_PIMREG_DATA(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_NO_PIMREG_DATA)
+#define PIM_UPSTREAM_FLAG_TEST_FORCE_PIMREG(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_FORCE_PIMREG)
+#define PIM_UPSTREAM_FLAG_TEST_SRC_VXLAN_ORIG(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_ORIG)
+#define PIM_UPSTREAM_FLAG_TEST_SRC_VXLAN_TERM(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_TERM)
+#define PIM_UPSTREAM_FLAG_TEST_SRC_VXLAN(flags) ((flags) & (PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_ORIG | PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_TERM))
+#define PIM_UPSTREAM_FLAG_TEST_MLAG_VXLAN(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_MLAG_VXLAN)
+#define PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_MLAG_NON_DF)
 
 #define PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED)
 #define PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED)
 #define PIM_UPSTREAM_FLAG_SET_SRC_MSDP(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SRC_MSDP)
 #define PIM_UPSTREAM_FLAG_SET_SEND_SG_RPT_PRUNE(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SEND_SG_RPT_PRUNE)
 #define PIM_UPSTREAM_FLAG_SET_SRC_LHR(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SRC_LHR)
+#define PIM_UPSTREAM_FLAG_SET_DISABLE_KAT_EXPIRY(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_DISABLE_KAT_EXPIRY)
+#define PIM_UPSTREAM_FLAG_SET_STATIC_IIF(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_STATIC_IIF)
+#define PIM_UPSTREAM_FLAG_SET_ALLOW_IIF_IN_OIL(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_ALLOW_IIF_IN_OIL)
+#define PIM_UPSTREAM_FLAG_SET_NO_PIMREG_DATA(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_NO_PIMREG_DATA)
+#define PIM_UPSTREAM_FLAG_SET_FORCE_PIMREG(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_FORCE_PIMREG)
+#define PIM_UPSTREAM_FLAG_SET_SRC_VXLAN_ORIG(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_ORIG)
+#define PIM_UPSTREAM_FLAG_SET_SRC_VXLAN_TERM(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_TERM)
+#define PIM_UPSTREAM_FLAG_SET_MLAG_VXLAN(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_MLAG_VXLAN)
+#define PIM_UPSTREAM_FLAG_SET_MLAG_NON_DF(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_MLAG_NON_DF)
 
 #define PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED)
 #define PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED)
 #define PIM_UPSTREAM_FLAG_UNSET_SRC_MSDP(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_MSDP)
 #define PIM_UPSTREAM_FLAG_UNSET_SEND_SG_RPT_PRUNE(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SEND_SG_RPT_PRUNE)
 #define PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_LHR)
+#define PIM_UPSTREAM_FLAG_UNSET_DISABLE_KAT_EXPIRY(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_DISABLE_KAT_EXPIRY)
+#define PIM_UPSTREAM_FLAG_UNSET_STATIC_IIF(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_STATIC_IIF)
+#define PIM_UPSTREAM_FLAG_UNSET_ALLOW_IIF_IN_OIL(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_ALLOW_IIF_IN_OIL)
+#define PIM_UPSTREAM_FLAG_UNSET_NO_PIMREG_DATA(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_NO_PIMREG_DATA)
+#define PIM_UPSTREAM_FLAG_UNSET_FORCE_PIMREG(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_FORCE_PIMREG)
+#define PIM_UPSTREAM_FLAG_UNSET_SRC_VXLAN_ORIG(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_ORIG)
+#define PIM_UPSTREAM_FLAG_UNSET_SRC_VXLAN_TERM(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_TERM)
+#define PIM_UPSTREAM_FLAG_UNSET_MLAG_VXLAN(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_MLAG_VXLAN)
+#define PIM_UPSTREAM_FLAG_UNSET_MLAG_NON_DF(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_MLAG_NON_DF)
 
 enum pim_upstream_state {
        PIM_UPSTREAM_NOTJOINED,
@@ -245,4 +310,8 @@ void pim_upstream_spt_prefix_list_update(struct pim_instance *pim,
 
 unsigned int pim_upstream_hash_key(void *arg);
 bool pim_upstream_equal(const void *arg1, const void *arg2);
+struct pim_upstream *pim_upstream_keep_alive_timer_proc(
+               struct pim_upstream *up);
+void pim_upstream_fill_static_iif(struct pim_upstream *up,
+                               struct interface *incoming);
 #endif /* PIM_UPSTREAM_H */
index 649578874842e9855b61906a35b36b38326167d3..2654ebc588b6b93a1397a7e4755bc8a6cb2ce42d 100644 (file)
@@ -39,6 +39,7 @@
 #include "pim_msdp.h"
 #include "pim_ssm.h"
 #include "pim_bfd.h"
+#include "pim_vxlan.h"
 
 int pim_debug_config_write(struct vty *vty)
 {
@@ -119,6 +120,11 @@ int pim_debug_config_write(struct vty *vty)
                ++writes;
        }
 
+       if (PIM_DEBUG_VXLAN) {
+               vty_out(vty, "debug pim vxlan\n");
+               ++writes;
+       }
+
        if (PIM_DEBUG_SSMPINGD) {
                vty_out(vty, "debug ssmpingd\n");
                ++writes;
@@ -234,6 +240,8 @@ int pim_global_config_write_worker(struct pim_instance *pim, struct vty *vty)
                }
        }
 
+       pim_vxlan_config_write(vty, spaces, &writes);
+
        return writes;
 }
 
diff --git a/pimd/pim_vxlan.c b/pimd/pim_vxlan.c
new file mode 100644 (file)
index 0000000..af76c6d
--- /dev/null
@@ -0,0 +1,1025 @@
+/* PIM support for VxLAN BUM flooding
+ *
+ * Copyright (C) 2019 Cumulus Networks, Inc.
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <zebra.h>
+
+#include <hash.h>
+#include <jhash.h>
+#include <log.h>
+#include <prefix.h>
+#include <vrf.h>
+
+#include "pimd.h"
+#include "pim_iface.h"
+#include "pim_memory.h"
+#include "pim_oil.h"
+#include "pim_register.h"
+#include "pim_str.h"
+#include "pim_upstream.h"
+#include "pim_ifchannel.h"
+#include "pim_nht.h"
+#include "pim_zebra.h"
+#include "pim_vxlan.h"
+
+/* pim-vxlan global info */
+struct pim_vxlan vxlan_info, *pim_vxlan_p = &vxlan_info;
+
+static void pim_vxlan_work_timer_setup(bool start);
+static void pim_vxlan_set_peerlink_rif(struct pim_instance *pim,
+                       struct interface *ifp);
+
+/*************************** vxlan work list **********************************
+ * A work list is maintained for staggered generation of pim null register
+ * messages for vxlan SG entries that are in a reg_join state.
+ *
+ * A max of 500 NULL registers are generated at one shot. If paused reg
+ * generation continues on the next second and so on till all register
+ * messages have been sent out. And the process is restarted every 60s.
+ *
+ * purpose of this null register generation is to setup the SPT and maintain
+ * independent of the presence of overlay BUM traffic.
+ ****************************************************************************/
+static void pim_vxlan_do_reg_work(void)
+{
+       struct listnode *listnode;
+       int work_cnt = 0;
+       struct pim_vxlan_sg *vxlan_sg;
+       static int sec_count;
+
+       ++sec_count;
+
+       if (sec_count > PIM_VXLAN_NULL_REG_INTERVAL) {
+               sec_count = 0;
+               listnode = vxlan_info.next_work ?
+                                       vxlan_info.next_work :
+                                       vxlan_info.work_list->head;
+               if (PIM_DEBUG_VXLAN && listnode)
+                       zlog_debug("vxlan SG work %s",
+                               vxlan_info.next_work ? "continues" : "starts");
+       } else {
+               listnode = vxlan_info.next_work;
+       }
+
+       for (; listnode; listnode = listnode->next) {
+               vxlan_sg = (struct pim_vxlan_sg *)listnode->data;
+               if (vxlan_sg->up && (vxlan_sg->up->reg_state == PIM_REG_JOIN)) {
+                       if (PIM_DEBUG_VXLAN)
+                               zlog_debug("vxlan SG %s periodic NULL register",
+                                               vxlan_sg->sg_str);
+                       pim_null_register_send(vxlan_sg->up);
+                       ++work_cnt;
+               }
+
+               if (work_cnt > vxlan_info.max_work_cnt) {
+                       vxlan_info.next_work = listnode->next;
+                       if (PIM_DEBUG_VXLAN)
+                               zlog_debug("vxlan SG %d work items proc and pause",
+                                       work_cnt);
+                       return;
+               }
+       }
+
+       if (work_cnt) {
+               if (PIM_DEBUG_VXLAN)
+                       zlog_debug("vxlan SG %d work items proc", work_cnt);
+       }
+       vxlan_info.next_work = NULL;
+}
+
+/* Staggered work related info is initialized when the first work comes
+ * along
+ */
+static void pim_vxlan_init_work(void)
+{
+       if (vxlan_info.flags & PIM_VXLANF_WORK_INITED)
+               return;
+
+       vxlan_info.max_work_cnt = PIM_VXLAN_WORK_MAX;
+       vxlan_info.flags |= PIM_VXLANF_WORK_INITED;
+       vxlan_info.work_list = list_new();
+       pim_vxlan_work_timer_setup(TRUE /* start */);
+}
+
+static void pim_vxlan_add_work(struct pim_vxlan_sg *vxlan_sg)
+{
+       if (vxlan_sg->flags & PIM_VXLAN_SGF_DEL_IN_PROG) {
+               if (PIM_DEBUG_VXLAN)
+                       zlog_debug("vxlan SG %s skip work list; del-in-prog",
+                                       vxlan_sg->sg_str);
+               return;
+       }
+
+       pim_vxlan_init_work();
+
+       /* already a part of the work list */
+       if (vxlan_sg->work_node)
+               return;
+
+       if (PIM_DEBUG_VXLAN)
+               zlog_debug("vxlan SG %s work list add",
+                               vxlan_sg->sg_str);
+       vxlan_sg->work_node = listnode_add(vxlan_info.work_list, vxlan_sg);
+       /* XXX: adjust max_work_cnt if needed */
+}
+
+static void pim_vxlan_del_work(struct pim_vxlan_sg *vxlan_sg)
+{
+       if (!vxlan_sg->work_node)
+               return;
+
+       if (PIM_DEBUG_VXLAN)
+               zlog_debug("vxlan SG %s work list del",
+                               vxlan_sg->sg_str);
+
+       if (vxlan_sg->work_node == vxlan_info.next_work)
+               vxlan_info.next_work = vxlan_sg->work_node->next;
+
+       list_delete_node(vxlan_info.work_list, vxlan_sg->work_node);
+       vxlan_sg->work_node = NULL;
+}
+
+void pim_vxlan_update_sg_reg_state(struct pim_instance *pim,
+               struct pim_upstream *up, bool reg_join)
+{
+       struct pim_vxlan_sg *vxlan_sg;
+
+       vxlan_sg = pim_vxlan_sg_find(pim, &up->sg);
+       if (!vxlan_sg)
+               return;
+
+       /* add the vxlan sg entry to a work list for periodic reg joins.
+        * the entry will stay in the list as long as the register state is
+        * PIM_REG_JOIN
+        */
+       if (reg_join)
+               pim_vxlan_add_work(vxlan_sg);
+       else
+               pim_vxlan_del_work(vxlan_sg);
+}
+
+static int pim_vxlan_work_timer_cb(struct thread *t)
+{
+       pim_vxlan_do_reg_work();
+       pim_vxlan_work_timer_setup(true /* start */);
+       return 0;
+}
+
+/* global 1second timer used for periodic processing */
+static void pim_vxlan_work_timer_setup(bool start)
+{
+       THREAD_OFF(vxlan_info.work_timer);
+       if (start)
+               thread_add_timer(router->master, pim_vxlan_work_timer_cb, NULL,
+                       PIM_VXLAN_WORK_TIME, &vxlan_info.work_timer);
+}
+
+/**************************** vxlan origination mroutes ***********************
+ * For every (local-vtep-ip, bum-mcast-grp) registered by evpn an origination
+ * mroute is setup by pimd. The purpose of this mroute is to forward vxlan
+ * encapsulated BUM (broadcast, unknown-unicast and unknown-multicast packets
+ * over the underlay.)
+ *
+ * Sample mroute (single VTEP):
+ * (27.0.0.7, 239.1.1.100)     Iif: lo      Oifs: uplink-1
+ *
+ * Sample mroute (anycast VTEP):
+ * (36.0.0.9, 239.1.1.100)          Iif: peerlink-3.4094\
+ *                                       Oifs: peerlink-3.4094 uplink-1
+ ***************************************************************************/
+static void pim_vxlan_orig_mr_up_del(struct pim_vxlan_sg *vxlan_sg)
+{
+       struct pim_upstream *up = vxlan_sg->up;
+
+       if (!up)
+               return;
+
+       if (PIM_DEBUG_VXLAN)
+               zlog_debug("vxlan SG %s orig mroute-up del",
+                       vxlan_sg->sg_str);
+
+       vxlan_sg->up = NULL;
+       if (up->flags & PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_ORIG) {
+               /* clear out all the vxlan properties */
+               up->flags &= ~(PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_ORIG |
+                       PIM_UPSTREAM_FLAG_MASK_STATIC_IIF |
+                       PIM_UPSTREAM_FLAG_MASK_DISABLE_KAT_EXPIRY |
+                       PIM_UPSTREAM_FLAG_MASK_FORCE_PIMREG |
+                       PIM_UPSTREAM_FLAG_MASK_NO_PIMREG_DATA |
+                       PIM_UPSTREAM_FLAG_MASK_ALLOW_IIF_IN_OIL);
+
+               /* We bring things to a grinding halt by force expirying
+                * the kat. Doing this will also remove the reference we
+                * created as a "vxlan" source and delete the upstream entry
+                * if there are no other references.
+                */
+               if (PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) {
+                       THREAD_OFF(up->t_ka_timer);
+                       up = pim_upstream_keep_alive_timer_proc(up);
+               } else {
+                       /* this is really unexpected as we force vxlan
+                        * origination mroutes active sources but just in
+                        * case
+                        */
+                       up = pim_upstream_del(vxlan_sg->pim, up,
+                               __PRETTY_FUNCTION__);
+               }
+               /* if there are other references register the source
+                * for nht
+                */
+               if (up)
+                       pim_rpf_update(vxlan_sg->pim, up, NULL, 1 /* is_new */);
+       }
+}
+
+static void pim_vxlan_orig_mr_up_iif_update(struct pim_vxlan_sg *vxlan_sg)
+{
+       int vif_index;
+
+       /* update MFC with the new IIF */
+       pim_upstream_fill_static_iif(vxlan_sg->up, vxlan_sg->iif);
+       vif_index = pim_if_find_vifindex_by_ifindex(vxlan_sg->pim,
+                       vxlan_sg->iif->ifindex);
+       if (vif_index > 0)
+               pim_scan_individual_oil(vxlan_sg->up->channel_oil,
+                               vif_index);
+
+       if (PIM_DEBUG_VXLAN)
+               zlog_debug("vxlan SG %s orig mroute-up updated with iif %s vifi %d",
+                       vxlan_sg->sg_str,
+                       vxlan_sg->iif?vxlan_sg->iif->name:"-", vif_index);
+
+}
+
+/* For every VxLAN BUM multicast group we setup a SG-up that has the following
+ * "forced properties" -
+ * 1. Directly connected on a DR interface i.e. we must act as an FHR
+ * 2. We prime the pump i.e. no multicast data is needed to register this
+ *    source with the FHR. To do that we send periodic null registers if
+ *    the SG entry is in a register-join state. We also prevent expiry of
+ *    KAT.
+ * 3. As this SG is setup without data there is no need to register encapsulate
+ *    data traffic. This encapsulation is explicitly skipped for the following
+ *    reasons -
+ *    a) Many levels of encapsulation are needed creating MTU disc challenges.
+ *       Overlay BUM is encapsulated in a vxlan/UDP/IP header and then
+ *       encapsulated again in a pim-register header.
+ *    b) On a vxlan-aa setup both switches rx a copy of each BUM packet. if
+ *       they both reg encapsulated traffic the RP will accept the duplicates
+ *       as there are no RPF checks for this encapsulated data.
+ *    a), b) can be workarounded if needed, but there is really no need because
+ *    of (2) i.e. the pump is primed without data.
+ */
+static void pim_vxlan_orig_mr_up_add(struct pim_vxlan_sg *vxlan_sg)
+{
+       struct pim_upstream *up;
+       int flags = 0;
+       struct prefix nht_p;
+
+       if (vxlan_sg->up) {
+               /* nothing to do */
+               return;
+       }
+
+       if (PIM_DEBUG_VXLAN)
+               zlog_debug("vxlan SG %s orig mroute-up add with iif %s",
+                       vxlan_sg->sg_str,
+                       vxlan_sg->iif?vxlan_sg->iif->name:"-");
+
+       PIM_UPSTREAM_FLAG_SET_SRC_VXLAN_ORIG(flags);
+       /* pin the IIF to lo or peerlink-subinterface and disable NHT */
+       PIM_UPSTREAM_FLAG_SET_STATIC_IIF(flags);
+       /* Fake traffic by setting SRC_STREAM and starting KAT */
+       /* We intentionally skip updating ref count for SRC_STREAM/FHR.
+        * Setting SRC_VXLAN should have already created a reference
+        * preventing the entry from being deleted
+        */
+       PIM_UPSTREAM_FLAG_SET_FHR(flags);
+       PIM_UPSTREAM_FLAG_SET_SRC_STREAM(flags);
+       /* Force pimreg even if non-DR. This is needed on a MLAG setup for
+        * VxLAN AA
+        */
+       PIM_UPSTREAM_FLAG_SET_FORCE_PIMREG(flags);
+       /* prevent KAT expiry. we want the MDT setup even if there is no BUM
+        * traffic
+        */
+       PIM_UPSTREAM_FLAG_SET_DISABLE_KAT_EXPIRY(flags);
+       /* SPT for vxlan BUM groups is primed and maintained via NULL
+        * registers so there is no need to reg-encapsulate
+        * vxlan-encapsulated overlay data traffic
+        */
+       PIM_UPSTREAM_FLAG_SET_NO_PIMREG_DATA(flags);
+       /* On a MLAG setup we force a copy to the MLAG peer while also
+        * accepting traffic from the peer. To do this we set peerlink-rif as
+        * the IIF and also add it to the OIL
+        */
+       PIM_UPSTREAM_FLAG_SET_ALLOW_IIF_IN_OIL(flags);
+
+       /* XXX: todo: defer pim_upstream add if pim is not enabled on the iif */
+       up = pim_upstream_find(vxlan_sg->pim, &vxlan_sg->sg);
+       if (up) {
+               /* if the iif is set to something other than the vxlan_sg->iif
+                * we must dereg the old nexthop and force to new "static"
+                * iif
+                */
+               if (!PIM_UPSTREAM_FLAG_TEST_STATIC_IIF(up->flags)) {
+                       nht_p.family = AF_INET;
+                       nht_p.prefixlen = IPV4_MAX_BITLEN;
+                       nht_p.u.prefix4 = up->upstream_addr;
+                       pim_delete_tracked_nexthop(vxlan_sg->pim,
+                               &nht_p, up, NULL);
+               }
+               pim_upstream_ref(up, flags, __PRETTY_FUNCTION__);
+               vxlan_sg->up = up;
+               pim_vxlan_orig_mr_up_iif_update(vxlan_sg);
+       } else {
+               up = pim_upstream_add(vxlan_sg->pim, &vxlan_sg->sg,
+                               vxlan_sg->iif, flags,
+                               __PRETTY_FUNCTION__, NULL);
+               vxlan_sg->up = up;
+       }
+
+       if (!up) {
+               if (PIM_DEBUG_VXLAN)
+                       zlog_debug("vxlan SG %s orig mroute-up add failed",
+                                       vxlan_sg->sg_str);
+               return;
+       }
+
+       pim_upstream_keep_alive_timer_start(up, vxlan_sg->pim->keep_alive_time);
+
+       /* register the source with the RP */
+       if (up->reg_state == PIM_REG_NOINFO) {
+               pim_register_join(up);
+               pim_null_register_send(up);
+       }
+
+       /* update the inherited OIL */
+       pim_upstream_inherited_olist(vxlan_sg->pim, up);
+}
+
+static void pim_vxlan_orig_mr_oif_add(struct pim_vxlan_sg *vxlan_sg)
+{
+       if (!vxlan_sg->up || !vxlan_sg->orig_oif)
+               return;
+
+       if (PIM_DEBUG_VXLAN)
+               zlog_debug("vxlan SG %s oif %s add",
+                       vxlan_sg->sg_str, vxlan_sg->orig_oif->name);
+
+       vxlan_sg->flags |= PIM_VXLAN_SGF_OIF_INSTALLED;
+       pim_channel_add_oif(vxlan_sg->up->channel_oil,
+               vxlan_sg->orig_oif, PIM_OIF_FLAG_PROTO_VXLAN);
+}
+
+static void pim_vxlan_orig_mr_oif_del(struct pim_vxlan_sg *vxlan_sg)
+{
+       struct interface *orig_oif;
+
+       orig_oif = vxlan_sg->orig_oif;
+       vxlan_sg->orig_oif = NULL;
+
+       if (!(vxlan_sg->flags & PIM_VXLAN_SGF_OIF_INSTALLED))
+               return;
+
+       if (PIM_DEBUG_VXLAN)
+               zlog_debug("vxlan SG %s oif %s del",
+                       vxlan_sg->sg_str, orig_oif->name);
+
+       vxlan_sg->flags &= ~PIM_VXLAN_SGF_OIF_INSTALLED;
+       pim_channel_del_oif(vxlan_sg->up->channel_oil,
+               orig_oif, PIM_OIF_FLAG_PROTO_VXLAN);
+}
+
+static inline struct interface *pim_vxlan_orig_mr_oif_get(
+               struct pim_instance *pim)
+{
+       return (vxlan_mlag.flags & PIM_VXLAN_MLAGF_ENABLED) ?
+               pim->vxlan.peerlink_rif : NULL;
+}
+
+/* Single VTEPs: IIF for the vxlan-origination-mroutes is lo or vrf-dev (if
+ * the mroute is in a non-default vrf).
+ * Anycast VTEPs: IIF is the MLAG ISL/peerlink.
+ */
+static inline struct interface *pim_vxlan_orig_mr_iif_get(
+               struct pim_instance *pim)
+{
+       return ((vxlan_mlag.flags & PIM_VXLAN_MLAGF_ENABLED) &&
+                       pim->vxlan.peerlink_rif) ?
+               pim->vxlan.peerlink_rif : pim->vxlan.default_iif;
+}
+
+static bool pim_vxlan_orig_mr_add_is_ok(struct pim_vxlan_sg *vxlan_sg)
+{
+       struct pim_interface *pim_ifp;
+
+       vxlan_sg->iif = pim_vxlan_orig_mr_iif_get(vxlan_sg->pim);
+       if (!vxlan_sg->iif)
+               return false;
+
+       pim_ifp = (struct pim_interface *)vxlan_sg->iif->info;
+       if (!pim_ifp || (pim_ifp->mroute_vif_index < 0))
+               return false;
+
+       return true;
+}
+
+static void pim_vxlan_orig_mr_install(struct pim_vxlan_sg *vxlan_sg)
+{
+       pim_vxlan_orig_mr_up_add(vxlan_sg);
+
+       vxlan_sg->orig_oif = pim_vxlan_orig_mr_oif_get(vxlan_sg->pim);
+       pim_vxlan_orig_mr_oif_add(vxlan_sg);
+}
+
+static void pim_vxlan_orig_mr_add(struct pim_vxlan_sg *vxlan_sg)
+{
+       if (!pim_vxlan_orig_mr_add_is_ok(vxlan_sg))
+               return;
+
+       if (PIM_DEBUG_VXLAN)
+               zlog_debug("vxlan SG %s orig-mr add", vxlan_sg->sg_str);
+
+       pim_vxlan_orig_mr_install(vxlan_sg);
+}
+
+static void pim_vxlan_orig_mr_del(struct pim_vxlan_sg *vxlan_sg)
+{
+       if (PIM_DEBUG_VXLAN)
+               zlog_debug("vxlan SG %s orig-mr del", vxlan_sg->sg_str);
+
+       pim_vxlan_orig_mr_oif_del(vxlan_sg);
+       pim_vxlan_orig_mr_up_del(vxlan_sg);
+}
+
+static void pim_vxlan_orig_mr_iif_update(struct hash_backet *backet, void *arg)
+{
+       struct interface *ifp = (struct interface *)arg;
+       struct pim_vxlan_sg *vxlan_sg = (struct pim_vxlan_sg *)backet->data;
+       struct interface *old_iif = vxlan_sg->iif;
+
+       if (!pim_vxlan_is_orig_mroute(vxlan_sg))
+               return;
+
+       if (PIM_DEBUG_VXLAN)
+               zlog_debug("vxlan SG %s iif changed from %s to %s",
+                               vxlan_sg->sg_str,
+                               old_iif ? old_iif->name : "-",
+                               ifp ? ifp->name : "-");
+
+       if (pim_vxlan_orig_mr_add_is_ok(vxlan_sg)) {
+               if (vxlan_sg->up) {
+                       /* upstream exists but iif changed */
+                       pim_vxlan_orig_mr_up_iif_update(vxlan_sg);
+               } else {
+                       /* install mroute */
+                       pim_vxlan_orig_mr_install(vxlan_sg);
+               }
+       } else {
+               pim_vxlan_orig_mr_del(vxlan_sg);
+       }
+}
+
+/**************************** vxlan termination mroutes ***********************
+ * For every bum-mcast-grp registered by evpn a *G termination
+ * mroute is setup by pimd. The purpose of this mroute is to pull down vxlan
+ * packets with the bum-mcast-grp dip from the underlay and terminate the
+ * tunnel. This is done by including the vxlan termination device (ipmr-lo) in
+ * its OIL. The vxlan de-capsulated packets are subject to subsequent overlay
+ * bridging.
+ *
+ * Sample mroute:
+ * (0.0.0.0, 239.1.1.100)     Iif: uplink-1      Oifs: ipmr-lo, uplink-1
+ *****************************************************************************/
+struct pim_interface *pim_vxlan_get_term_ifp(struct pim_instance *pim)
+{
+       return pim->vxlan.term_if ?
+               (struct pim_interface *)pim->vxlan.term_if->info : NULL;
+}
+
+static void pim_vxlan_term_mr_oif_add(struct pim_vxlan_sg *vxlan_sg)
+{
+       if (vxlan_sg->flags & PIM_VXLAN_SGF_OIF_INSTALLED)
+               return;
+
+       if (PIM_DEBUG_VXLAN)
+               zlog_debug("vxlan SG %s term-oif %s add",
+                       vxlan_sg->sg_str, vxlan_sg->term_oif->name);
+
+       if (pim_ifchannel_local_membership_add(vxlan_sg->term_oif,
+                               &vxlan_sg->sg)) {
+               vxlan_sg->flags |= PIM_VXLAN_SGF_OIF_INSTALLED;
+       } else {
+               zlog_warn("vxlan SG %s term-oif %s add failed",
+                       vxlan_sg->sg_str, vxlan_sg->term_oif->name);
+       }
+}
+
+static void pim_vxlan_term_mr_oif_del(struct pim_vxlan_sg *vxlan_sg)
+{
+       if (!(vxlan_sg->flags & PIM_VXLAN_SGF_OIF_INSTALLED))
+               return;
+
+       if (PIM_DEBUG_VXLAN)
+               zlog_debug("vxlan SG %s oif %s del",
+                       vxlan_sg->sg_str, vxlan_sg->term_oif->name);
+
+       vxlan_sg->flags &= ~PIM_VXLAN_SGF_OIF_INSTALLED;
+       pim_ifchannel_local_membership_del(vxlan_sg->term_oif, &vxlan_sg->sg);
+}
+
+static void pim_vxlan_term_mr_up_add(struct pim_vxlan_sg *vxlan_sg)
+{
+       struct pim_upstream *up;
+       int flags = 0;
+
+       if (vxlan_sg->up) {
+               /* nothing to do */
+               return;
+       }
+
+       if (PIM_DEBUG_VXLAN)
+               zlog_debug("vxlan SG %s term mroute-up add",
+                       vxlan_sg->sg_str);
+
+       PIM_UPSTREAM_FLAG_SET_SRC_VXLAN_TERM(flags);
+       /* enable MLAG designated-forwarder election on termination mroutes */
+       PIM_UPSTREAM_FLAG_SET_MLAG_VXLAN(flags);
+
+       up = pim_upstream_add(vxlan_sg->pim, &vxlan_sg->sg,
+                       NULL /* iif */, flags,
+                       __PRETTY_FUNCTION__, NULL);
+       vxlan_sg->up = up;
+
+       if (!up) {
+               zlog_warn("vxlan SG %s term mroute-up add failed",
+                       vxlan_sg->sg_str);
+       }
+}
+
+static void pim_vxlan_term_mr_up_del(struct pim_vxlan_sg *vxlan_sg)
+{
+       struct pim_upstream *up = vxlan_sg->up;
+
+       if (!up)
+               return;
+
+       if (PIM_DEBUG_VXLAN)
+               zlog_debug("vxlan SG %s term mroute-up del",
+                       vxlan_sg->sg_str);
+       vxlan_sg->up = NULL;
+       if (up->flags & PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_TERM) {
+               /* clear out all the vxlan related flags */
+               up->flags &= ~(PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_TERM |
+                       PIM_UPSTREAM_FLAG_MASK_MLAG_VXLAN);
+
+               pim_upstream_del(vxlan_sg->pim, up,
+                               __PRETTY_FUNCTION__);
+       }
+}
+
+static void pim_vxlan_term_mr_add(struct pim_vxlan_sg *vxlan_sg)
+{
+       if (PIM_DEBUG_VXLAN)
+               zlog_debug("vxlan SG %s term mroute add", vxlan_sg->sg_str);
+
+       vxlan_sg->term_oif = vxlan_sg->pim->vxlan.term_if;
+       if (!vxlan_sg->term_oif)
+               /* defer termination mroute till we have a termination device */
+               return;
+
+       pim_vxlan_term_mr_up_add(vxlan_sg);
+       /* set up local membership for the term-oif */
+       pim_vxlan_term_mr_oif_add(vxlan_sg);
+}
+
+static void pim_vxlan_term_mr_del(struct pim_vxlan_sg *vxlan_sg)
+{
+       if (PIM_DEBUG_VXLAN)
+               zlog_debug("vxlan SG %s term mroute del", vxlan_sg->sg_str);
+
+       /* remove local membership associated with the term oif */
+       pim_vxlan_term_mr_oif_del(vxlan_sg);
+       /* remove references to the upstream entry */
+       pim_vxlan_term_mr_up_del(vxlan_sg);
+}
+
+/************************** vxlan SG cache management ************************/
+static unsigned int pim_vxlan_sg_hash_key_make(void *p)
+{
+       struct pim_vxlan_sg *vxlan_sg = p;
+
+       return (jhash_2words(vxlan_sg->sg.src.s_addr,
+                               vxlan_sg->sg.grp.s_addr, 0));
+}
+
+static bool pim_vxlan_sg_hash_eq(const void *p1, const void *p2)
+{
+       const struct pim_vxlan_sg *sg1 = p1;
+       const struct pim_vxlan_sg *sg2 = p2;
+
+       return ((sg1->sg.src.s_addr == sg2->sg.src.s_addr)
+                       && (sg1->sg.grp.s_addr == sg2->sg.grp.s_addr));
+}
+
+static struct pim_vxlan_sg *pim_vxlan_sg_new(struct pim_instance *pim,
+               struct prefix_sg *sg)
+{
+       struct pim_vxlan_sg *vxlan_sg;
+
+       vxlan_sg = XCALLOC(MTYPE_PIM_VXLAN_SG, sizeof(*vxlan_sg));
+
+       vxlan_sg->pim = pim;
+       vxlan_sg->sg = *sg;
+       pim_str_sg_set(sg, vxlan_sg->sg_str);
+
+       if (PIM_DEBUG_VXLAN)
+               zlog_debug("vxlan SG %s alloc", vxlan_sg->sg_str);
+
+       vxlan_sg = hash_get(pim->vxlan.sg_hash, vxlan_sg, hash_alloc_intern);
+
+       return vxlan_sg;
+}
+
+struct pim_vxlan_sg *pim_vxlan_sg_find(struct pim_instance *pim,
+               struct prefix_sg *sg)
+{
+       struct pim_vxlan_sg lookup;
+
+       lookup.sg = *sg;
+       return hash_lookup(pim->vxlan.sg_hash, &lookup);
+}
+
+struct pim_vxlan_sg *pim_vxlan_sg_add(struct pim_instance *pim,
+               struct prefix_sg *sg)
+{
+       struct pim_vxlan_sg *vxlan_sg;
+
+       vxlan_sg = pim_vxlan_sg_find(pim, sg);
+       if (vxlan_sg)
+               return vxlan_sg;
+
+       vxlan_sg = pim_vxlan_sg_new(pim, sg);
+
+       if (pim_vxlan_is_orig_mroute(vxlan_sg))
+               pim_vxlan_orig_mr_add(vxlan_sg);
+       else
+               pim_vxlan_term_mr_add(vxlan_sg);
+
+       return vxlan_sg;
+}
+
+void pim_vxlan_sg_del(struct pim_instance *pim, struct prefix_sg *sg)
+{
+       struct pim_vxlan_sg *vxlan_sg;
+
+       vxlan_sg = pim_vxlan_sg_find(pim, sg);
+       if (!vxlan_sg)
+               return;
+
+       vxlan_sg->flags |= PIM_VXLAN_SGF_DEL_IN_PROG;
+
+       pim_vxlan_del_work(vxlan_sg);
+
+       if (pim_vxlan_is_orig_mroute(vxlan_sg))
+               pim_vxlan_orig_mr_del(vxlan_sg);
+       else
+               pim_vxlan_term_mr_del(vxlan_sg);
+
+       hash_release(vxlan_sg->pim->vxlan.sg_hash, vxlan_sg);
+
+       if (PIM_DEBUG_VXLAN)
+               zlog_debug("vxlan SG %s free", vxlan_sg->sg_str);
+
+       XFREE(MTYPE_PIM_VXLAN_SG, vxlan_sg);
+}
+
+/******************************* MLAG handling *******************************/
+/* The peerlink sub-interface is added as an OIF to the origination-mroute.
+ * This is done to send a copy of the multicast-vxlan encapsulated traffic
+ * to the MLAG peer which may mroute it over the underlay if there are any
+ * interested receivers.
+ */
+static void pim_vxlan_sg_peerlink_update(struct hash_backet *backet, void *arg)
+{
+       struct interface *new_oif = (struct interface *)arg;
+       struct pim_vxlan_sg *vxlan_sg = (struct pim_vxlan_sg *)backet->data;
+
+       if (!pim_vxlan_is_orig_mroute(vxlan_sg))
+               return;
+
+       if (vxlan_sg->orig_oif == new_oif)
+               return;
+
+       pim_vxlan_orig_mr_oif_del(vxlan_sg);
+
+       vxlan_sg->orig_oif = new_oif;
+       pim_vxlan_orig_mr_oif_add(vxlan_sg);
+}
+
+/* In the case of anycast VTEPs the VTEP-PIP must be used as the
+ * register source.
+ */
+bool pim_vxlan_get_register_src(struct pim_instance *pim,
+               struct pim_upstream *up, struct in_addr *src_p)
+{
+       if (!(vxlan_mlag.flags & PIM_VXLAN_MLAGF_ENABLED))
+               return true;
+
+       /* if address is not available suppress the pim-register */
+       if (vxlan_mlag.reg_addr.s_addr == INADDR_ANY)
+               return false;
+
+       *src_p = vxlan_mlag.reg_addr;
+       return true;
+}
+
+void pim_vxlan_mlag_update(bool enable, bool peer_state, uint32_t role,
+                               struct interface *peerlink_rif,
+                               struct in_addr *reg_addr)
+{
+       struct pim_instance *pim;
+       struct interface *old_oif;
+       struct interface *new_oif;
+       char addr_buf[INET_ADDRSTRLEN];
+       struct pim_interface *pim_ifp = NULL;
+
+       if (PIM_DEBUG_VXLAN) {
+               inet_ntop(AF_INET, reg_addr,
+                               addr_buf, INET_ADDRSTRLEN);
+               zlog_debug("vxlan MLAG update %s state %s role %d rif %s addr %s",
+                               enable ? "enable" : "disable",
+                               peer_state ? "up" : "down",
+                               role,
+                               peerlink_rif ? peerlink_rif->name : "-",
+                               addr_buf);
+       }
+
+       /* XXX: for now vxlan termination is only possible in the default VRF
+        * when that changes this will need to change to iterate all VRFs
+        */
+       pim = pim_get_pim_instance(VRF_DEFAULT);
+
+       old_oif = pim_vxlan_orig_mr_oif_get(pim);
+
+       if (enable)
+               vxlan_mlag.flags |= PIM_VXLAN_MLAGF_ENABLED;
+       else
+               vxlan_mlag.flags &= ~PIM_VXLAN_MLAGF_ENABLED;
+
+       if (vxlan_mlag.peerlink_rif != peerlink_rif)
+               vxlan_mlag.peerlink_rif = peerlink_rif;
+
+       vxlan_mlag.reg_addr = *reg_addr;
+       vxlan_mlag.peer_state = peer_state;
+       vxlan_mlag.role = role;
+
+       /* process changes */
+       if (vxlan_mlag.peerlink_rif)
+               pim_ifp = (struct pim_interface *)vxlan_mlag.peerlink_rif->info;
+       if ((vxlan_mlag.flags & PIM_VXLAN_MLAGF_ENABLED) &&
+                       pim_ifp && (pim_ifp->mroute_vif_index > 0))
+               pim_vxlan_set_peerlink_rif(pim, peerlink_rif);
+       else
+               pim_vxlan_set_peerlink_rif(pim, NULL);
+
+       new_oif = pim_vxlan_orig_mr_oif_get(pim);
+       if (old_oif != new_oif)
+               hash_iterate(pim->vxlan.sg_hash, pim_vxlan_sg_peerlink_update,
+                       new_oif);
+}
+
+/****************************** misc callbacks *******************************/
+void pim_vxlan_config_write(struct vty *vty, char *spaces, int *writes)
+{
+       char addr_buf[INET_ADDRSTRLEN];
+
+       if ((vxlan_mlag.flags & PIM_VXLAN_MLAGF_ENABLED) &&
+                       vxlan_mlag.peerlink_rif) {
+
+               inet_ntop(AF_INET, &vxlan_mlag.reg_addr,
+                               addr_buf, sizeof(addr_buf));
+               vty_out(vty,
+                       "%sip pim mlag %s role %s state %s addr %s\n",
+                       spaces,
+                       vxlan_mlag.peerlink_rif->name,
+                       (vxlan_mlag.role == PIM_VXLAN_MLAG_ROLE_PRIMARY) ?
+                               "primary":"secondary",
+                       vxlan_mlag.peer_state ? "up" : "down",
+                       addr_buf);
+               *writes += 1;
+       }
+}
+
+static void pim_vxlan_set_default_iif(struct pim_instance *pim,
+                               struct interface *ifp)
+{
+       struct interface *old_iif;
+
+       if (pim->vxlan.default_iif == ifp)
+               return;
+
+       old_iif = pim->vxlan.default_iif;
+       if (PIM_DEBUG_VXLAN)
+               zlog_debug("%s: vxlan default iif changed from %s to %s",
+                       __PRETTY_FUNCTION__,
+                       old_iif ? old_iif->name : "-",
+                       ifp ? ifp->name : "-");
+
+       old_iif = pim_vxlan_orig_mr_iif_get(pim);
+       pim->vxlan.default_iif = ifp;
+       ifp = pim_vxlan_orig_mr_iif_get(pim);
+       if (old_iif == ifp)
+               return;
+
+       if (PIM_DEBUG_VXLAN)
+               zlog_debug("%s: vxlan orig iif changed from %s to %s",
+                       __PRETTY_FUNCTION__, old_iif ? old_iif->name : "-",
+                       ifp ? ifp->name : "-");
+
+       /* add/del upstream entries for the existing vxlan SG when the
+        * interface becomes available
+        */
+       if (pim->vxlan.sg_hash)
+               hash_iterate(pim->vxlan.sg_hash,
+                               pim_vxlan_orig_mr_iif_update, ifp);
+}
+
+static void pim_vxlan_set_peerlink_rif(struct pim_instance *pim,
+                       struct interface *ifp)
+{
+       struct interface *old_iif;
+
+       if (pim->vxlan.peerlink_rif == ifp)
+               return;
+
+       old_iif = pim->vxlan.peerlink_rif;
+       if (PIM_DEBUG_VXLAN)
+               zlog_debug("%s: vxlan peerlink_rif changed from %s to %s",
+                       __PRETTY_FUNCTION__, old_iif ? old_iif->name : "-",
+                       ifp ? ifp->name : "-");
+
+       old_iif = pim_vxlan_orig_mr_iif_get(pim);
+       pim->vxlan.peerlink_rif = ifp;
+       ifp = pim_vxlan_orig_mr_iif_get(pim);
+       if (old_iif == ifp)
+               return;
+
+       if (PIM_DEBUG_VXLAN)
+               zlog_debug("%s: vxlan orig iif changed from %s to %s",
+                       __PRETTY_FUNCTION__, old_iif ? old_iif->name : "-",
+                       ifp ? ifp->name : "-");
+
+       /* add/del upstream entries for the existing vxlan SG when the
+        * interface becomes available
+        */
+       if (pim->vxlan.sg_hash)
+               hash_iterate(pim->vxlan.sg_hash,
+                               pim_vxlan_orig_mr_iif_update, ifp);
+}
+
+void pim_vxlan_add_vif(struct interface *ifp)
+{
+       struct pim_interface *pim_ifp = ifp->info;
+       struct pim_instance *pim = pim_ifp->pim;
+
+       if (pim->vrf_id != VRF_DEFAULT)
+               return;
+
+       if (if_is_loopback_or_vrf(ifp))
+               pim_vxlan_set_default_iif(pim, ifp);
+
+       if (vxlan_mlag.flags & PIM_VXLAN_MLAGF_ENABLED &&
+                       (ifp == vxlan_mlag.peerlink_rif))
+               pim_vxlan_set_peerlink_rif(pim, ifp);
+}
+
+void pim_vxlan_del_vif(struct interface *ifp)
+{
+       struct pim_interface *pim_ifp = ifp->info;
+       struct pim_instance *pim = pim_ifp->pim;
+
+       if (pim->vrf_id != VRF_DEFAULT)
+               return;
+
+       if (pim->vxlan.default_iif == ifp)
+               pim_vxlan_set_default_iif(pim, NULL);
+
+       if (pim->vxlan.peerlink_rif == ifp)
+               pim_vxlan_set_peerlink_rif(pim, NULL);
+}
+
+static void pim_vxlan_term_mr_oif_update(struct hash_backet *backet, void *arg)
+{
+       struct interface *ifp = (struct interface *)arg;
+       struct pim_vxlan_sg *vxlan_sg = (struct pim_vxlan_sg *)backet->data;
+
+       if (pim_vxlan_is_orig_mroute(vxlan_sg))
+               return;
+
+       if (vxlan_sg->term_oif == ifp)
+               return;
+
+       if (PIM_DEBUG_VXLAN)
+               zlog_debug("vxlan SG %s term oif changed from %s to %s",
+                       vxlan_sg->sg_str,
+                       vxlan_sg->term_oif ? vxlan_sg->term_oif->name : "-",
+                       ifp ? ifp->name : "-");
+
+       pim_vxlan_term_mr_del(vxlan_sg);
+       vxlan_sg->term_oif = ifp;
+       pim_vxlan_term_mr_add(vxlan_sg);
+}
+
+void pim_vxlan_add_term_dev(struct pim_instance *pim,
+               struct interface *ifp)
+{
+       struct pim_interface *pim_ifp;
+
+       if (pim->vxlan.term_if == ifp)
+               return;
+
+       if (PIM_DEBUG_VXLAN)
+               zlog_debug("vxlan term oif changed from %s to %s",
+                       pim->vxlan.term_if ? pim->vxlan.term_if->name : "-",
+                       ifp->name);
+
+       /* enable pim on the term ifp */
+       pim_ifp = (struct pim_interface *)ifp->info;
+       if (pim_ifp) {
+               PIM_IF_DO_PIM(pim_ifp->options);
+       } else {
+               pim_ifp = pim_if_new(ifp, false /*igmp*/, true /*pim*/,
+                               false /*pimreg*/, true /*vxlan_term*/);
+               /* ensure that pimreg existss before using the newly created
+                * vxlan termination device
+                */
+               pim_if_create_pimreg(pim);
+       }
+
+       pim->vxlan.term_if = ifp;
+
+       if (pim->vxlan.sg_hash)
+               hash_iterate(pim_ifp->pim->vxlan.sg_hash,
+                               pim_vxlan_term_mr_oif_update, ifp);
+}
+
+void pim_vxlan_del_term_dev(struct pim_instance *pim)
+{
+       struct interface *ifp = pim->vxlan.term_if;
+       struct pim_interface *pim_ifp;
+
+       if (PIM_DEBUG_VXLAN)
+               zlog_debug("vxlan term oif changed from %s to -", ifp->name);
+
+       pim->vxlan.term_if = NULL;
+
+       if (pim->vxlan.sg_hash)
+               hash_iterate(pim->vxlan.sg_hash,
+                               pim_vxlan_term_mr_oif_update, NULL);
+
+       pim_ifp = (struct pim_interface *)ifp->info;
+       if (pim_ifp) {
+               PIM_IF_DONT_PIM(pim_ifp->options);
+               if (!PIM_IF_TEST_IGMP(pim_ifp->options))
+                       pim_if_delete(ifp);
+       }
+
+}
+
+void pim_vxlan_init(struct pim_instance *pim)
+{
+       char hash_name[64];
+
+       snprintf(hash_name, sizeof(hash_name),
+               "PIM %s vxlan SG hash", pim->vrf->name);
+       pim->vxlan.sg_hash = hash_create(pim_vxlan_sg_hash_key_make,
+                       pim_vxlan_sg_hash_eq, hash_name);
+}
+
+void pim_vxlan_exit(struct pim_instance *pim)
+{
+       if (pim->vxlan.sg_hash) {
+               hash_clean(pim->vxlan.sg_hash, NULL);
+               hash_free(pim->vxlan.sg_hash);
+               pim->vxlan.sg_hash = NULL;
+       }
+}
diff --git a/pimd/pim_vxlan.h b/pimd/pim_vxlan.h
new file mode 100644 (file)
index 0000000..f0a66e6
--- /dev/null
@@ -0,0 +1,139 @@
+/* PIM support for VxLAN BUM flooding
+ *
+ * Copyright (C) 2019 Cumulus Networks, Inc.
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef PIM_VXLAN_H
+#define PIM_VXLAN_H
+
+/* global timer used for miscellaneous staggered processing */
+#define PIM_VXLAN_WORK_TIME 1
+/* number of SG entries processed at one shot */
+#define PIM_VXLAN_WORK_MAX 500
+/* frequency of periodic NULL registers */
+#define PIM_VXLAN_NULL_REG_INTERVAL 60 /* seconds */
+
+#define vxlan_mlag (vxlan_info.mlag)
+
+enum pim_vxlan_sg_flags {
+       PIM_VXLAN_SGF_NONE = 0,
+       PIM_VXLAN_SGF_DEL_IN_PROG = (1 << 0),
+       PIM_VXLAN_SGF_OIF_INSTALLED = (1 << 1)
+};
+
+struct pim_vxlan_sg {
+       struct pim_instance *pim;
+
+       /* key */
+       struct prefix_sg sg;
+       char sg_str[PIM_SG_LEN];
+
+       enum pim_vxlan_sg_flags flags;
+       struct pim_upstream *up;
+       struct listnode *work_node; /* to pim_vxlan.work_list */
+
+       /* termination info (only applicable to termination XG mroutes)
+        * term_if - termination device ipmr-lo is added to the OIL
+        * as local/IGMP membership to allow termination of vxlan traffic
+        */
+       struct interface *term_oif;
+
+       /* origination info
+        * iif - lo/vrf or peerlink (on MLAG setups)
+        * peerlink_oif - added to the OIL to send encapsulated BUM traffic to
+        * the MLAG peer switch
+        */
+       struct interface *iif;
+       /* on a MLAG setup the peerlink is added as a static OIF */
+       struct interface *orig_oif;
+};
+
+enum pim_vxlan_mlag_flags {
+       PIM_VXLAN_MLAGF_NONE = 0,
+       PIM_VXLAN_MLAGF_ENABLED = (1 << 0)
+};
+
+enum pim_vxlan_mlag_role {
+       PIM_VXLAN_MLAG_ROLE_SECONDARY = 0,
+       PIM_VXLAN_MLAG_ROLE_PRIMARY
+};
+
+struct pim_vxlan_mlag {
+       enum pim_vxlan_mlag_flags flags;
+       enum pim_vxlan_mlag_role role;
+       bool peer_state;
+       /* routed interface setup on top of MLAG peerlink */
+       struct interface *peerlink_rif;
+       struct in_addr reg_addr;
+};
+
+enum pim_vxlan_flags {
+       PIM_VXLANF_NONE = 0,
+       PIM_VXLANF_WORK_INITED = (1 << 0)
+};
+
+struct pim_vxlan {
+       enum pim_vxlan_flags flags;
+
+       struct thread *work_timer;
+       struct list *work_list;
+       struct listnode *next_work;
+       int max_work_cnt;
+
+       struct pim_vxlan_mlag mlag;
+};
+
+/* zebra adds-
+ * 1. one (S, G) entry where S=local-VTEP-IP and G==BUM-mcast-grp for
+ * each BUM MDT. This is the origination entry.
+ * 2. and one (*, G) entry each MDT. This is the termination place holder.
+ *
+ * Note: This doesn't mean that only (*, G) mroutes are used for tunnel
+ * termination. (S, G) mroutes with ipmr-lo in the OIL can also be
+ * used for tunnel termiation if SPT switchover happens; however such
+ * SG entries are created by traffic and will NOT be a part of the vxlan SG
+ * database.
+ */
+static inline bool pim_vxlan_is_orig_mroute(struct pim_vxlan_sg *vxlan_sg)
+{
+       return (vxlan_sg->sg.src.s_addr != 0);
+}
+
+extern struct pim_vxlan *pim_vxlan_p;
+extern struct pim_vxlan_sg *pim_vxlan_sg_find(struct pim_instance *pim,
+                                           struct prefix_sg *sg);
+extern struct pim_vxlan_sg *pim_vxlan_sg_add(struct pim_instance *pim,
+                                          struct prefix_sg *sg);
+extern void pim_vxlan_sg_del(struct pim_instance *pim, struct prefix_sg *sg);
+extern void pim_vxlan_update_sg_reg_state(struct pim_instance *pim,
+               struct pim_upstream *up, bool reg_join);
+extern struct pim_interface *pim_vxlan_get_term_ifp(struct pim_instance *pim);
+extern void pim_vxlan_add_vif(struct interface *ifp);
+extern void pim_vxlan_del_vif(struct interface *ifp);
+extern void pim_vxlan_add_term_dev(struct pim_instance *pim,
+               struct interface *ifp);
+extern void pim_vxlan_del_term_dev(struct pim_instance *pim);
+extern bool pim_vxlan_get_register_src(struct pim_instance *pim,
+               struct pim_upstream *up, struct in_addr *src_p);
+extern void pim_vxlan_mlag_update(bool enable, bool peer_state, uint32_t role,
+                               struct interface *peerlink_rif,
+                               struct in_addr *reg_addr);
+extern void pim_vxlan_config_write(struct vty *vty, char *spaces, int *writes);
+
+#endif /* PIM_VXLAN_H */
diff --git a/pimd/pim_vxlan_instance.h b/pimd/pim_vxlan_instance.h
new file mode 100644 (file)
index 0000000..3f99483
--- /dev/null
@@ -0,0 +1,45 @@
+/* PIM support for VxLAN BUM flooding
+ *
+ * Copyright (C) 2019 Cumulus Networks, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ */
+
+#ifndef PIM_VXLAN_INSTANCE_H
+#define PIM_VXLAN_INSTANCE_H
+
+/* pim termination device is expected to include the substring ipmr-lo */
+#define PIM_VXLAN_TERM_DEV_NAME "ipmr-lo"
+
+struct pim_vxlan_instance {
+       struct hash *sg_hash;
+
+       /* this is lo for default instance and vrf-dev for non-default
+        * instances
+        */
+       struct interface *default_iif;
+
+       /* In a MLAG/VxLAN-AA setup the peerlink sub-interface (ISL-rif) is
+        * used as the IIF in
+        */
+       struct interface *peerlink_rif;
+
+       /* device used by the dataplane to terminate multicast encapsulated
+        * vxlan traffic
+        */
+       struct interface *term_if;
+};
+
+extern void pim_vxlan_init(struct pim_instance *pim);
+extern void pim_vxlan_exit(struct pim_instance *pim);
+
+#endif /* PIM_VXLAN_INSTANCE_H */
index b20f31082d955ce9bb74b0c6c8cd1a399bb58336..aeaea7d69f08ea9eb8e1770bc394250f13de93a3 100644 (file)
@@ -45,6 +45,7 @@
 #include "pim_jp_agg.h"
 #include "pim_nht.h"
 #include "pim_ssm.h"
+#include "pim_vxlan.h"
 
 #undef PIM_DEBUG_IFADDR_DUMP
 #define PIM_DEBUG_IFADDR_DUMP
@@ -110,13 +111,18 @@ static int pim_zebra_if_add(int command, struct zclient *zclient,
                struct pim_interface *pim_ifp;
 
                if (!ifp->info) {
-                       pim_ifp = pim_if_new(ifp, false, false, false);
+                       pim_ifp = pim_if_new(ifp, false, false, false,
+                                       false /*vxlan_term*/);
                        ifp->info = pim_ifp;
                }
 
                pim_sock_add(ifp);
        }
 
+       if (!strncmp(ifp->name, PIM_VXLAN_TERM_DEV_NAME,
+                               sizeof(PIM_VXLAN_TERM_DEV_NAME)))
+               pim_vxlan_add_term_dev(pim, ifp);
+
        return 0;
 }
 
@@ -124,6 +130,7 @@ static int pim_zebra_if_del(int command, struct zclient *zclient,
                            zebra_size_t length, vrf_id_t vrf_id)
 {
        struct interface *ifp;
+       struct pim_instance *pim;
 
        /*
          zebra api adds/dels interfaces using the same call
@@ -152,6 +159,10 @@ static int pim_zebra_if_del(int command, struct zclient *zclient,
 
        if_set_index(ifp, IFINDEX_INTERNAL);
 
+       pim = pim_get_pim_instance(vrf_id);
+       if (pim && pim->vxlan.term_if == ifp)
+               pim_vxlan_del_term_dev(pim);
+
        return 0;
 }
 
@@ -543,6 +554,41 @@ void pim_zebra_upstream_rpf_changed(struct pim_instance *pim,
        pim_upstream_update_join_desired(pim, up);
 }
 
+static int pim_zebra_vxlan_sg_proc(int command, struct zclient *zclient,
+               zebra_size_t length, vrf_id_t vrf_id)
+{
+       struct stream *s;
+       struct pim_instance *pim;
+       struct prefix_sg sg;
+
+       pim = pim_get_pim_instance(vrf_id);
+       if (!pim)
+               return 0;
+
+       s = zclient->ibuf;
+
+       sg.family = AF_INET;
+       sg.prefixlen = stream_getl(s);
+       stream_get(&sg.src.s_addr, s, sg.prefixlen);
+       stream_get(&sg.grp.s_addr, s, sg.prefixlen);
+
+       if (PIM_DEBUG_ZEBRA) {
+               char sg_str[PIM_SG_LEN];
+
+               pim_str_sg_set(&sg, sg_str);
+               zlog_debug("%u:recv SG %s %s", vrf_id,
+                       (command == ZEBRA_VXLAN_SG_ADD)?"add":"del",
+                       sg_str);
+       }
+
+       if (command == ZEBRA_VXLAN_SG_ADD)
+               pim_vxlan_sg_add(pim, &sg);
+       else
+               pim_vxlan_sg_del(pim, &sg);
+
+       return 0;
+}
+
 void pim_scan_individual_oil(struct channel_oil *c_oil, int in_vif_index)
 {
        struct in_addr vif_source;
@@ -769,6 +815,8 @@ void pim_zebra_init(void)
        zclient->interface_address_delete = pim_zebra_if_address_del;
        zclient->interface_vrf_update = pim_zebra_interface_vrf_update;
        zclient->nexthop_update = pim_parse_nexthop_update;
+       zclient->vxlan_sg_add = pim_zebra_vxlan_sg_proc;
+       zclient->vxlan_sg_del = pim_zebra_vxlan_sg_proc;
 
        zclient_init(zclient, ZEBRA_ROUTE_PIM, 0, &pimd_privs);
        if (PIM_DEBUG_PIM_TRACE) {
index 50c19658dab044f4cc528d369bb8f87c0209d49e..2f2a870371397bb084b0733e23b64ddbed9c32d5 100644 (file)
 #define PIM_MASK_PIM_NHT_DETAIL      (1 << 23)
 #define PIM_MASK_PIM_NHT_RP          (1 << 24)
 #define PIM_MASK_MTRACE              (1 << 25)
+#define PIM_MASK_VXLAN               (1 << 26)
 /* Remember 32 bits!!! */
 
 /* PIM error codes */
@@ -180,6 +181,7 @@ extern uint8_t qpim_ecmp_rebalance_enable;
 #define PIM_DEBUG_PIM_NHT_DETAIL (router->debugs & PIM_MASK_PIM_NHT_DETAIL)
 #define PIM_DEBUG_PIM_NHT_RP (router->debugs & PIM_MASK_PIM_NHT_RP)
 #define PIM_DEBUG_MTRACE (router->debugs & PIM_MASK_MTRACE)
+#define PIM_DEBUG_VXLAN (router->debugs & PIM_MASK_VXLAN)
 
 #define PIM_DEBUG_EVENTS                                                       \
        (router->debugs                                                        \
@@ -220,6 +222,7 @@ extern uint8_t qpim_ecmp_rebalance_enable;
 #define PIM_DO_DEBUG_PIM_NHT (router->debugs |= PIM_MASK_PIM_NHT)
 #define PIM_DO_DEBUG_PIM_NHT_RP (router->debugs |= PIM_MASK_PIM_NHT_RP)
 #define PIM_DO_DEBUG_MTRACE (router->debugs |= PIM_MASK_MTRACE)
+#define PIM_DO_DEBUG_VXLAN (router->debugs |= PIM_MASK_VXLAN)
 
 #define PIM_DONT_DEBUG_PIM_EVENTS (router->debugs &= ~PIM_MASK_PIM_EVENTS)
 #define PIM_DONT_DEBUG_PIM_PACKETS (router->debugs &= ~PIM_MASK_PIM_PACKETS)
@@ -249,6 +252,7 @@ extern uint8_t qpim_ecmp_rebalance_enable;
 #define PIM_DONT_DEBUG_PIM_NHT (router->debugs &= ~PIM_MASK_PIM_NHT)
 #define PIM_DONT_DEBUG_PIM_NHT_RP (router->debugs &= ~PIM_MASK_PIM_NHT_RP)
 #define PIM_DONT_DEBUG_MTRACE (router->debugs &= ~PIM_MASK_MTRACE)
+#define PIM_DONT_DEBUG_VXLAN (router->debugs &= ~PIM_MASK_VXLAN)
 
 void pim_router_init(void);
 void pim_router_terminate(void);
index 7d8df7d1053b3c84e5d48804e354648e9fc5524f..7f4810722b858267f139c8dc5b2f0a5ae5305aa9 100644 (file)
@@ -60,6 +60,7 @@ pimd_libpim_a_SOURCES = \
        pimd/pim_vty.c \
        pimd/pim_zebra.c \
        pimd/pim_zlookup.c \
+       pimd/pim_vxlan.c \
        pimd/pimd.c \
        # end
 
@@ -110,6 +111,8 @@ noinst_HEADERS += \
        pimd/pim_vty.h \
        pimd/pim_zebra.h \
        pimd/pim_zlookup.h \
+       pimd/pim_vxlan.h \
+       pimd/pim_vxlan_instance.h \
        pimd/pimd.h \
        pimd/mtracebis_netlink.h \
        pimd/mtracebis_routeget.h \
diff --git a/ports/Makefile b/ports/Makefile
deleted file mode 100644 (file)
index 86f77bd..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-# New ports collection makefile for:   zebra
-# Version required:    2.1.5
-# Date created:                28 Feb 1998
-# Whom:                        seirios@matrix.iri.co.jp
-#
-
-#DISTNAME=     zebra-980224
-DISTNAME=      zebra-current
-PKGNAME=       zebra
-CATEGORIES=    net
-MASTER_SITES=  ftp://ftp.zebra.org/pub/zebra/
-
-MAINTAINER=    seirios@matrix.iri.co.jp
-
-WRKSRC=                ${WRKDIR}/zebra-current
-
-#### Under constructing, We cannot support md5
-NO_CHECKSUM=   yes
-
-do-build:
-       @(cd ${WRKSRC}; sh ./configure; make)
-
-post-install:
-       @if [ ! -f ${PREFIX}/etc/rc.d/zebra.sh ]; then \
-               echo "Installing ${PREFIX}/etc/rc.d/zebra.sh startup file."; \
-               echo "#!/bin/sh" > ${PREFIX}/etc/rc.d/zebra.sh; \
-               echo "# zebra" >> ${PREFIX}/etc/rc.d/zebra.sh; \
-               echo "if [ -x /usr/local/sbin/zebra -a ! -f /var/run/zebra.pid -a -f /usr/local/etc/zebra.conf ]; then" >> ${PREFIX}/etc/rc.d/zebra.sh; \
-               echo "  /usr/local/sbin/zebra -d -f /usr/local/etc/zebra.conf" >> ${PREFIX}/etc/rc.d/zebra.sh; \
-               echo "  echo -n ' zebra'" >> ${PREFIX}/etc/rc.d/zebra.sh; \
-               echo "fi" >> ${PREFIX}/etc/rc.d/zebra.sh; \
-               echo "# bgpd" >> ${PREFIX}/etc/rc.d/zebra.sh; \
-               echo "if [ -x /usr/local/sbin/bgpd -a ! -f /var/run/bgpd.pid -a -f /usr/local/etc/bgpd.conf ]; then" >> ${PREFIX}/etc/rc.d/zebra.sh; \
-               echo "  /usr/local/sbin/bgpd -d -f /usr/local/etc/bgpd.conf" >> ${PREFIX}/etc/rc.d/zebra.sh; \
-               echo "  echo -n ' bgpd'" >> ${PREFIX}/etc/rc.d/zebra.sh; \
-               echo "fi" >> ${PREFIX}/etc/rc.d/zebra.sh; \
-               echo "# ripd" >> ${PREFIX}/etc/rc.d/zebra.sh; \
-               echo "if [ -x /usr/local/sbin/ripd -a ! -f /var/run/ripd.pid -a -f /usr/local/etc/ripd.conf ]; then" >> ${PREFIX}/etc/rc.d/zebra.sh; \
-               echo "  /usr/local/sbin/ripd -d -f /usr/local/etc/ripd.conf" >> ${PREFIX}/etc/rc.d/zebra.sh; \
-               echo "  echo -n ' ripd'" >> ${PREFIX}/etc/rc.d/zebra.sh; \
-               echo "fi" >> ${PREFIX}/etc/rc.d/zebra.sh; \
-               echo "# ripngd" >> ${PREFIX}/etc/rc.d/zebra.sh; \
-               echo "if [ -x /usr/local/sbin/ripngd -a ! -f /var/run/ripd.pid -a -f /usr/local/etc/ripd.conf ]; then" >> ${PREFIX}/etc/rc.d/zebra.sh; \
-               echo "  /usr/local/sbin/ripngd -d -f /usr/local/etc/ripd.conf" >> ${PREFIX}/etc/rc.d/zebra.sh; \
-               echo "  echo -n ' ripngd'" >> ${PREFIX}/etc/rc.d/zebra.sh; \
-               echo "fi" >> ${PREFIX}/etc/rc.d/zebra.sh; \
-               chmod 751 ${PREFIX}/etc/rc.d/zebra.sh; \
-       fi
-       @echo "If you will access zebra,bgpd,ripd,ripngd with telnet,";
-       @echo "then you add some line (written under this line) to /etc/services";
-       @echo " zebrasrv      2600/tcp            # zebra service";
-       @echo " zebra         2601/tcp            # zebra vty";
-       @echo " ripd          2602/tcp            # RIPd vty";
-       @echo " ripngd        2603/tcp            # RIPngd vty";
-       @echo " ospfd         2604/tcp            # OSPFd vty";
-       @echo " bgpd          2605/tcp            # BGPd vty";
-       @echo " pimd          2611/tcp            # PIMd vty";
-
-.include <bsd.port.mk>
diff --git a/ports/README b/ports/README
deleted file mode 100644 (file)
index a650eaa..0000000
+++ /dev/null
@@ -1 +0,0 @@
-This directory contain files for making FreeBSD package.
diff --git a/ports/files/md5 b/ports/files/md5
deleted file mode 100644 (file)
index 520c348..0000000
+++ /dev/null
@@ -1 +0,0 @@
-MD5 (zebra-980224.tar.gz) = c6887645741200c43341156c168c7034
diff --git a/ports/pkg/COMMENT b/ports/pkg/COMMENT
deleted file mode 100644 (file)
index 53c55e3..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Zebra Routing protocol daemon
diff --git a/ports/pkg/DESCR b/ports/pkg/DESCR
deleted file mode 100644 (file)
index aeb1950..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-=============
-WHAT IS ZEBRA
-=============
-  Zebra is a free software that manages TCP/IP based routing protocol.
-  It takes multi-server and multi-thread approach to resolve the current
-complexity of the Internet.
-
-  Currently zebra is still under development, so If you want to use zebra,
-I strongly recommend you to get the latest version of zebra.
-  Zebra snapshot is released on every monday.
-
-===================
-SUPPORTED Protocols
-===================
-  Zebra supports both IPv4 and IPv6 :-)
-  For supporting IPv4 Routing protocols is here
-       RIP (both version1 and version2)
-               RIPv2 supports both Multicast and Broadcast
-       BGP (only support BGP4)
-
-  For supporting IPv6 Routing protocols is here
-       RIPng
-       BGP4+
-
-===================
-Supported plat-home
-===================
-  Now zebra is testing on 
-  o FreeBSD 2.2.8
-      -- without IPv6 ;-)
-      -- with KAME
-      -- with INRIA IPv6 protocol stack.
-
-  o GNU/Linux 2.2.2
-  o GNU/Linux 2.0.36
-
-===========
-ZEBRA Ports
-===========
-  Each daemon has each own terminal interface.  Also zebra has communication
-port which provides several services to other daemons.  Below is zebra ports
-list.
-
-zebrasrv      2600/tcp           # zebra service
-zebra        2601/tcp            # zebra vty
-ripd         2602/tcp            # RIPd vty
-ripngd       2603/tcp            # RIPngd vty
-ospfd        2604/tcp            # OSPFd vty
-bgpd         2605/tcp            # BGPd vty
-pimd         2611/tcp            # PIMd vty
-
-I recommend you to add upper list to /etc/services.
-
-====================
-For More Information
-====================
-  Web page is located at:
-       http://www.zebra.org/
-
-  Alpha version source file can be found at:
-       ftp://ftp.zebra.org/pub/zebra/
-
-  Mailing List is here
-       zebra@zebra.org
-       zebra-jp@zebra.org
-
-    If you want to join zebra mailing list, mail to 
-       majordomo@zebra.org
-    and you write
-       subscribe zebra
-         -- if you want to talk with English
-       subscribe zebra-jp
-         -- if you want to talk with Japanese
-    on Mail BODY (Not Subject).
-
-Enjoy.
diff --git a/ports/pkg/PLIST b/ports/pkg/PLIST
deleted file mode 100644 (file)
index ccc69eb..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-sbin/zebra
-sbin/bgpd
-sbin/ripd
-etc/bgpd.conf.sample
-etc/ripd.conf.sample
-etc/zebra.conf.sample
-etc/rc.d/zebra.sh
-info/zebra.info
index c1ff678f25ad53778e4f85a069ff9119f31270ba..d4fde5519bfcd2112a932c5f8b1d38608a3fade0 100644 (file)
@@ -79,7 +79,7 @@ static int ripd_instance_create(enum nb_event event,
                        socket = -1;
 
                rip = rip_create(vrf_name, vrf, socket);
-               yang_dnode_set_entry(dnode, rip);
+               nb_running_set_entry(dnode, rip);
                break;
        }
 
@@ -94,7 +94,7 @@ static int ripd_instance_destroy(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       rip = yang_dnode_get_entry(dnode, true);
+       rip = nb_running_unset_entry(dnode);
        rip_clean(rip);
 
        return NB_OK;
@@ -144,7 +144,7 @@ static int ripd_instance_allow_ecmp_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       rip = yang_dnode_get_entry(dnode, true);
+       rip = nb_running_get_entry(dnode, NULL, true);
        rip->ecmp = yang_dnode_get_bool(dnode, NULL);
        if (!rip->ecmp)
                rip_ecmp_disable(rip);
@@ -167,7 +167,7 @@ ripd_instance_default_information_originate_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       rip = yang_dnode_get_entry(dnode, true);
+       rip = nb_running_get_entry(dnode, NULL, true);
        default_information = yang_dnode_get_bool(dnode, NULL);
 
        memset(&p, 0, sizeof(struct prefix_ipv4));
@@ -199,7 +199,7 @@ static int ripd_instance_default_metric_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       rip = yang_dnode_get_entry(dnode, true);
+       rip = nb_running_get_entry(dnode, NULL, true);
        rip->default_metric = yang_dnode_get_uint8(dnode, NULL);
        /* rip_update_default_metric (); */
 
@@ -218,7 +218,7 @@ static int ripd_instance_distance_default_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       rip = yang_dnode_get_entry(dnode, true);
+       rip = nb_running_get_entry(dnode, NULL, true);
        rip->distance = yang_dnode_get_uint8(dnode, NULL);
 
        return NB_OK;
@@ -242,10 +242,10 @@ static int ripd_instance_distance_source_create(enum nb_event event,
        apply_mask_ipv4(&prefix);
 
        /* Get RIP distance node. */
-       rip = yang_dnode_get_entry(dnode, true);
+       rip = nb_running_get_entry(dnode, NULL, true);
        rn = route_node_get(rip->distance_table, (struct prefix *)&prefix);
        rn->info = rip_distance_new();
-       yang_dnode_set_entry(dnode, rn);
+       nb_running_set_entry(dnode, rn);
 
        return NB_OK;
 }
@@ -259,7 +259,7 @@ static int ripd_instance_distance_source_destroy(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       rn = yang_dnode_get_entry(dnode, true);
+       rn = nb_running_unset_entry(dnode);
        rdistance = rn->info;
        rip_distance_free(rdistance);
        rn->info = NULL;
@@ -284,7 +284,7 @@ ripd_instance_distance_source_distance_modify(enum nb_event event,
                return NB_OK;
 
        /* Set distance value. */
-       rn = yang_dnode_get_entry(dnode, true);
+       rn = nb_running_get_entry(dnode, NULL, true);
        distance = yang_dnode_get_uint8(dnode, NULL);
        rdistance = rn->info;
        rdistance->distance = distance;
@@ -310,7 +310,7 @@ ripd_instance_distance_source_access_list_modify(enum nb_event event,
        acl_name = yang_dnode_get_string(dnode, NULL);
 
        /* Set access-list */
-       rn = yang_dnode_get_entry(dnode, true);
+       rn = nb_running_get_entry(dnode, NULL, true);
        rdistance = rn->info;
        if (rdistance->access_list)
                free(rdistance->access_list);
@@ -330,7 +330,7 @@ ripd_instance_distance_source_access_list_destroy(enum nb_event event,
                return NB_OK;
 
        /* Reset access-list configuration. */
-       rn = yang_dnode_get_entry(dnode, true);
+       rn = nb_running_get_entry(dnode, NULL, true);
        rdistance = rn->info;
        free(rdistance->access_list);
        rdistance->access_list = NULL;
@@ -351,7 +351,7 @@ static int ripd_instance_explicit_neighbor_create(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       rip = yang_dnode_get_entry(dnode, true);
+       rip = nb_running_get_entry(dnode, NULL, true);
        p.family = AF_INET;
        p.prefixlen = IPV4_MAX_BITLEN;
        yang_dnode_get_ipv4(&p.prefix, dnode, NULL);
@@ -368,7 +368,7 @@ static int ripd_instance_explicit_neighbor_destroy(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       rip = yang_dnode_get_entry(dnode, true);
+       rip = nb_running_get_entry(dnode, NULL, true);
        p.family = AF_INET;
        p.prefixlen = IPV4_MAX_BITLEN;
        yang_dnode_get_ipv4(&p.prefix, dnode, NULL);
@@ -389,7 +389,7 @@ static int ripd_instance_network_create(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       rip = yang_dnode_get_entry(dnode, true);
+       rip = nb_running_get_entry(dnode, NULL, true);
        yang_dnode_get_ipv4p(&p, dnode, NULL);
        apply_mask_ipv4((struct prefix_ipv4 *)&p);
 
@@ -405,7 +405,7 @@ static int ripd_instance_network_destroy(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       rip = yang_dnode_get_entry(dnode, true);
+       rip = nb_running_get_entry(dnode, NULL, true);
        yang_dnode_get_ipv4p(&p, dnode, NULL);
        apply_mask_ipv4((struct prefix_ipv4 *)&p);
 
@@ -425,7 +425,7 @@ static int ripd_instance_interface_create(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       rip = yang_dnode_get_entry(dnode, true);
+       rip = nb_running_get_entry(dnode, NULL, true);
        ifname = yang_dnode_get_string(dnode, NULL);
 
        return rip_enable_if_add(rip, ifname);
@@ -440,7 +440,7 @@ static int ripd_instance_interface_destroy(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       rip = yang_dnode_get_entry(dnode, true);
+       rip = nb_running_get_entry(dnode, NULL, true);
        ifname = yang_dnode_get_string(dnode, NULL);
 
        return rip_enable_if_delete(rip, ifname);
@@ -460,11 +460,11 @@ static int ripd_instance_offset_list_create(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       rip = yang_dnode_get_entry(dnode, true);
+       rip = nb_running_get_entry(dnode, NULL, true);
        ifname = yang_dnode_get_string(dnode, "./interface");
 
        offset = rip_offset_list_new(rip, ifname);
-       yang_dnode_set_entry(dnode, offset);
+       nb_running_set_entry(dnode, offset);
 
        return NB_OK;
 }
@@ -480,7 +480,7 @@ static int ripd_instance_offset_list_destroy(enum nb_event event,
 
        direct = yang_dnode_get_enum(dnode, "./direction");
 
-       offset = yang_dnode_get_entry(dnode, true);
+       offset = nb_running_unset_entry(dnode);
        if (offset->direct[direct].alist_name) {
                free(offset->direct[direct].alist_name);
                offset->direct[direct].alist_name = NULL;
@@ -510,7 +510,7 @@ ripd_instance_offset_list_access_list_modify(enum nb_event event,
        direct = yang_dnode_get_enum(dnode, "../direction");
        alist_name = yang_dnode_get_string(dnode, NULL);
 
-       offset = yang_dnode_get_entry(dnode, true);
+       offset = nb_running_get_entry(dnode, NULL, true);
        if (offset->direct[direct].alist_name)
                free(offset->direct[direct].alist_name);
        offset->direct[direct].alist_name = strdup(alist_name);
@@ -535,7 +535,7 @@ static int ripd_instance_offset_list_metric_modify(enum nb_event event,
        direct = yang_dnode_get_enum(dnode, "../direction");
        metric = yang_dnode_get_uint8(dnode, NULL);
 
-       offset = yang_dnode_get_entry(dnode, true);
+       offset = nb_running_get_entry(dnode, NULL, true);
        offset->direct[direct].metric = metric;
 
        return NB_OK;
@@ -553,7 +553,7 @@ static int ripd_instance_passive_default_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       rip = yang_dnode_get_entry(dnode, true);
+       rip = nb_running_get_entry(dnode, NULL, true);
        rip->passive_default = yang_dnode_get_bool(dnode, NULL);
        rip_passive_nondefault_clean(rip);
 
@@ -573,7 +573,7 @@ static int ripd_instance_passive_interface_create(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       rip = yang_dnode_get_entry(dnode, true);
+       rip = nb_running_get_entry(dnode, NULL, true);
        ifname = yang_dnode_get_string(dnode, NULL);
 
        return rip_passive_nondefault_set(rip, ifname);
@@ -588,7 +588,7 @@ static int ripd_instance_passive_interface_destroy(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       rip = yang_dnode_get_entry(dnode, true);
+       rip = nb_running_get_entry(dnode, NULL, true);
        ifname = yang_dnode_get_string(dnode, NULL);
 
        return rip_passive_nondefault_unset(rip, ifname);
@@ -608,7 +608,7 @@ ripd_instance_non_passive_interface_create(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       rip = yang_dnode_get_entry(dnode, true);
+       rip = nb_running_get_entry(dnode, NULL, true);
        ifname = yang_dnode_get_string(dnode, NULL);
 
        return rip_passive_nondefault_unset(rip, ifname);
@@ -624,7 +624,7 @@ ripd_instance_non_passive_interface_destroy(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       rip = yang_dnode_get_entry(dnode, true);
+       rip = nb_running_get_entry(dnode, NULL, true);
        ifname = yang_dnode_get_string(dnode, NULL);
 
        return rip_passive_nondefault_set(rip, ifname);
@@ -643,7 +643,7 @@ static int ripd_instance_redistribute_create(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       rip = yang_dnode_get_entry(dnode, true);
+       rip = nb_running_get_entry(dnode, NULL, true);
        type = yang_dnode_get_enum(dnode, "./protocol");
 
        rip->redist[type].enabled = true;
@@ -660,7 +660,7 @@ static int ripd_instance_redistribute_destroy(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       rip = yang_dnode_get_entry(dnode, true);
+       rip = nb_running_get_entry(dnode, NULL, true);
        type = yang_dnode_get_enum(dnode, "./protocol");
 
        rip->redist[type].enabled = false;
@@ -684,7 +684,7 @@ ripd_instance_redistribute_apply_finish(const struct lyd_node *dnode)
        struct rip *rip;
        int type;
 
-       rip = yang_dnode_get_entry(dnode, true);
+       rip = nb_running_get_entry(dnode, NULL, true);
        type = yang_dnode_get_enum(dnode, "./protocol");
 
        if (rip->enabled)
@@ -706,7 +706,7 @@ ripd_instance_redistribute_route_map_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       rip = yang_dnode_get_entry(dnode, true);
+       rip = nb_running_get_entry(dnode, NULL, true);
        type = yang_dnode_get_enum(dnode, "../protocol");
        rmap_name = yang_dnode_get_string(dnode, NULL);
 
@@ -728,7 +728,7 @@ ripd_instance_redistribute_route_map_destroy(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       rip = yang_dnode_get_entry(dnode, true);
+       rip = nb_running_get_entry(dnode, NULL, true);
        type = yang_dnode_get_enum(dnode, "../protocol");
 
        free(rip->redist[type].route_map.name);
@@ -753,7 +753,7 @@ ripd_instance_redistribute_metric_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       rip = yang_dnode_get_entry(dnode, true);
+       rip = nb_running_get_entry(dnode, NULL, true);
        type = yang_dnode_get_enum(dnode, "../protocol");
        metric = yang_dnode_get_uint8(dnode, NULL);
 
@@ -773,7 +773,7 @@ ripd_instance_redistribute_metric_destroy(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       rip = yang_dnode_get_entry(dnode, true);
+       rip = nb_running_get_entry(dnode, NULL, true);
        type = yang_dnode_get_enum(dnode, "../protocol");
 
        rip->redist[type].metric_config = false;
@@ -796,7 +796,7 @@ static int ripd_instance_static_route_create(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       rip = yang_dnode_get_entry(dnode, true);
+       rip = nb_running_get_entry(dnode, NULL, true);
        yang_dnode_get_ipv4p(&p, dnode, NULL);
        apply_mask_ipv4(&p);
 
@@ -817,7 +817,7 @@ static int ripd_instance_static_route_destroy(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       rip = yang_dnode_get_entry(dnode, true);
+       rip = nb_running_get_entry(dnode, NULL, true);
        yang_dnode_get_ipv4p(&p, dnode, NULL);
        apply_mask_ipv4(&p);
 
@@ -833,7 +833,7 @@ static void ripd_instance_timers_apply_finish(const struct lyd_node *dnode)
 {
        struct rip *rip;
 
-       rip = yang_dnode_get_entry(dnode, true);
+       rip = nb_running_get_entry(dnode, NULL, true);
 
        /* Reset update timer thread. */
        rip_event(rip, RIP_UPDATE_EVENT, 0);
@@ -852,7 +852,7 @@ ripd_instance_timers_flush_interval_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       rip = yang_dnode_get_entry(dnode, true);
+       rip = nb_running_get_entry(dnode, NULL, true);
        rip->garbage_time = yang_dnode_get_uint32(dnode, NULL);
 
        return NB_OK;
@@ -871,7 +871,7 @@ ripd_instance_timers_holddown_interval_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       rip = yang_dnode_get_entry(dnode, true);
+       rip = nb_running_get_entry(dnode, NULL, true);
        rip->timeout_time = yang_dnode_get_uint32(dnode, NULL);
 
        return NB_OK;
@@ -890,7 +890,7 @@ ripd_instance_timers_update_interval_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       rip = yang_dnode_get_entry(dnode, true);
+       rip = nb_running_get_entry(dnode, NULL, true);
        rip->update_time = yang_dnode_get_uint32(dnode, NULL);
 
        return NB_OK;
@@ -908,7 +908,7 @@ static int ripd_instance_version_receive_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       rip = yang_dnode_get_entry(dnode, true);
+       rip = nb_running_get_entry(dnode, NULL, true);
        rip->version_recv = yang_dnode_get_enum(dnode, NULL);
 
        return NB_OK;
@@ -926,7 +926,7 @@ static int ripd_instance_version_send_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       rip = yang_dnode_get_entry(dnode, true);
+       rip = nb_running_get_entry(dnode, NULL, true);
        rip->version_send = yang_dnode_get_enum(dnode, NULL);
 
        return NB_OK;
@@ -945,7 +945,7 @@ static int lib_interface_rip_split_horizon_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ifp = yang_dnode_get_entry(dnode, true);
+       ifp = nb_running_get_entry(dnode, NULL, true);
        ri = ifp->info;
        ri->split_horizon = yang_dnode_get_enum(dnode, NULL);
 
@@ -965,7 +965,7 @@ static int lib_interface_rip_v2_broadcast_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ifp = yang_dnode_get_entry(dnode, true);
+       ifp = nb_running_get_entry(dnode, NULL, true);
        ri = ifp->info;
        ri->v2_broadcast = yang_dnode_get_bool(dnode, NULL);
 
@@ -986,7 +986,7 @@ lib_interface_rip_version_receive_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ifp = yang_dnode_get_entry(dnode, true);
+       ifp = nb_running_get_entry(dnode, NULL, true);
        ri = ifp->info;
        ri->ri_receive = yang_dnode_get_enum(dnode, NULL);
 
@@ -1006,7 +1006,7 @@ static int lib_interface_rip_version_send_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ifp = yang_dnode_get_entry(dnode, true);
+       ifp = nb_running_get_entry(dnode, NULL, true);
        ri = ifp->info;
        ri->ri_send = yang_dnode_get_enum(dnode, NULL);
 
@@ -1026,7 +1026,7 @@ static int lib_interface_rip_authentication_scheme_mode_modify(
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ifp = yang_dnode_get_entry(dnode, true);
+       ifp = nb_running_get_entry(dnode, NULL, true);
        ri = ifp->info;
        ri->auth_type = yang_dnode_get_enum(dnode, NULL);
 
@@ -1047,7 +1047,7 @@ static int lib_interface_rip_authentication_scheme_md5_auth_length_modify(
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ifp = yang_dnode_get_entry(dnode, true);
+       ifp = nb_running_get_entry(dnode, NULL, true);
        ri = ifp->info;
        ri->md5_auth_len = yang_dnode_get_enum(dnode, NULL);
 
@@ -1063,7 +1063,7 @@ static int lib_interface_rip_authentication_scheme_md5_auth_length_destroy(
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ifp = yang_dnode_get_entry(dnode, true);
+       ifp = nb_running_get_entry(dnode, NULL, true);
        ri = ifp->info;
        ri->md5_auth_len = yang_get_default_enum(
                "%s/authentication-scheme/md5-auth-length", RIP_IFACE);
@@ -1085,7 +1085,7 @@ lib_interface_rip_authentication_password_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ifp = yang_dnode_get_entry(dnode, true);
+       ifp = nb_running_get_entry(dnode, NULL, true);
        ri = ifp->info;
        XFREE(MTYPE_RIP_INTERFACE_STRING, ri->auth_str);
        ri->auth_str = XSTRDUP(MTYPE_RIP_INTERFACE_STRING,
@@ -1104,7 +1104,7 @@ lib_interface_rip_authentication_password_destroy(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ifp = yang_dnode_get_entry(dnode, true);
+       ifp = nb_running_get_entry(dnode, NULL, true);
        ri = ifp->info;
        XFREE(MTYPE_RIP_INTERFACE_STRING, ri->auth_str);
 
@@ -1125,7 +1125,7 @@ lib_interface_rip_authentication_key_chain_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ifp = yang_dnode_get_entry(dnode, true);
+       ifp = nb_running_get_entry(dnode, NULL, true);
        ri = ifp->info;
        XFREE(MTYPE_RIP_INTERFACE_STRING, ri->key_chain);
        ri->key_chain = XSTRDUP(MTYPE_RIP_INTERFACE_STRING,
@@ -1144,7 +1144,7 @@ lib_interface_rip_authentication_key_chain_destroy(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ifp = yang_dnode_get_entry(dnode, true);
+       ifp = nb_running_get_entry(dnode, NULL, true);
        ri = ifp->info;
        XFREE(MTYPE_RIP_INTERFACE_STRING, ri->key_chain);
 
index b3f84fe50f6a702b1ae8b54415e795c5ff9d0f16..8307a95d27b3b11a792297d8b82105b3e8247bf6 100644 (file)
@@ -50,6 +50,11 @@ struct rip_offset_list *rip_offset_list_new(struct rip *rip, const char *ifname)
 void offset_list_del(struct rip_offset_list *offset)
 {
        listnode_delete(offset->rip->offset_list_master, offset);
+       offset_list_free(offset);
+}
+
+void offset_list_free(struct rip_offset_list *offset)
+{
        if (OFFSET_LIST_IN_NAME(offset))
                free(OFFSET_LIST_IN_NAME(offset));
        if (OFFSET_LIST_OUT_NAME(offset))
index 201de9a46e0b3f46942e999f230f6ff06442c63a..3a1ffd17a6f47561d7b54a1e40f4c71e77509602 100644 (file)
@@ -2712,7 +2712,7 @@ struct rip *rip_create(const char *vrf_name, struct vrf *vrf, int socket)
        rip->passive_nondefault = vector_init(1);
        rip->offset_list_master = list_new();
        rip->offset_list_master->cmp = (int (*)(void *, void *))offset_list_cmp;
-       rip->offset_list_master->del = (void (*)(void *))offset_list_del;
+       rip->offset_list_master->del = (void (*)(void *))offset_list_free;
 
        /* Distribute list install. */
        rip->distribute_ctx = distribute_list_ctx_create(vrf);
index 7b196a16be40e13a489b05918965b6e6efd35634..44f5932fb69a2c99e0bfa27a506cac86b9ce978c 100644 (file)
@@ -507,6 +507,7 @@ extern struct rip_info *rip_ecmp_delete(struct rip *rip,
 extern struct rip_offset_list *rip_offset_list_new(struct rip *rip,
                                                   const char *ifname);
 extern void offset_list_del(struct rip_offset_list *offset);
+extern void offset_list_free(struct rip_offset_list *offset);
 extern struct rip_offset_list *rip_offset_list_lookup(struct rip *rip,
                                                      const char *ifname);
 extern int rip_offset_list_apply_in(struct prefix_ipv4 *, struct interface *,
index c483ad65f8405285900d3398a8935fb6f4588112..f8ac4a5cd5c1bb9a1d9bd17613b6848c7570dbc8 100644 (file)
@@ -81,7 +81,7 @@ static int ripngd_instance_create(enum nb_event event,
                        socket = -1;
 
                ripng = ripng_create(vrf_name, vrf, socket);
-               yang_dnode_set_entry(dnode, ripng);
+               nb_running_set_entry(dnode, ripng);
                break;
        }
 
@@ -96,7 +96,7 @@ static int ripngd_instance_destroy(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ripng = yang_dnode_get_entry(dnode, true);
+       ripng = nb_running_unset_entry(dnode);
        ripng_clean(ripng);
 
        return NB_OK;
@@ -147,7 +147,7 @@ static int ripngd_instance_allow_ecmp_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ripng = yang_dnode_get_entry(dnode, true);
+       ripng = nb_running_get_entry(dnode, NULL, true);
        ripng->ecmp = yang_dnode_get_bool(dnode, NULL);
        if (!ripng->ecmp)
                ripng_ecmp_disable(ripng);
@@ -169,7 +169,7 @@ static int ripngd_instance_default_information_originate_modify(
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ripng = yang_dnode_get_entry(dnode, true);
+       ripng = nb_running_get_entry(dnode, NULL, true);
        default_information = yang_dnode_get_bool(dnode, NULL);
 
        str2prefix_ipv6("::/0", &p);
@@ -196,7 +196,7 @@ static int ripngd_instance_default_metric_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ripng = yang_dnode_get_entry(dnode, true);
+       ripng = nb_running_get_entry(dnode, NULL, true);
        ripng->default_metric = yang_dnode_get_uint8(dnode, NULL);
 
        return NB_OK;
@@ -215,7 +215,7 @@ static int ripngd_instance_network_create(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ripng = yang_dnode_get_entry(dnode, true);
+       ripng = nb_running_get_entry(dnode, NULL, true);
        yang_dnode_get_ipv6p(&p, dnode, NULL);
        apply_mask_ipv6((struct prefix_ipv6 *)&p);
 
@@ -231,7 +231,7 @@ static int ripngd_instance_network_destroy(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ripng = yang_dnode_get_entry(dnode, true);
+       ripng = nb_running_get_entry(dnode, NULL, true);
        yang_dnode_get_ipv6p(&p, dnode, NULL);
        apply_mask_ipv6((struct prefix_ipv6 *)&p);
 
@@ -251,7 +251,7 @@ static int ripngd_instance_interface_create(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ripng = yang_dnode_get_entry(dnode, true);
+       ripng = nb_running_get_entry(dnode, NULL, true);
        ifname = yang_dnode_get_string(dnode, NULL);
 
        return ripng_enable_if_add(ripng, ifname);
@@ -266,7 +266,7 @@ static int ripngd_instance_interface_destroy(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ripng = yang_dnode_get_entry(dnode, true);
+       ripng = nb_running_get_entry(dnode, NULL, true);
        ifname = yang_dnode_get_string(dnode, NULL);
 
        return ripng_enable_if_delete(ripng, ifname);
@@ -286,11 +286,11 @@ static int ripngd_instance_offset_list_create(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ripng = yang_dnode_get_entry(dnode, true);
+       ripng = nb_running_get_entry(dnode, NULL, true);
        ifname = yang_dnode_get_string(dnode, "./interface");
 
        offset = ripng_offset_list_new(ripng, ifname);
-       yang_dnode_set_entry(dnode, offset);
+       nb_running_set_entry(dnode, offset);
 
        return NB_OK;
 }
@@ -306,7 +306,7 @@ static int ripngd_instance_offset_list_destroy(enum nb_event event,
 
        direct = yang_dnode_get_enum(dnode, "./direction");
 
-       offset = yang_dnode_get_entry(dnode, true);
+       offset = nb_running_unset_entry(dnode);
        if (offset->direct[direct].alist_name) {
                free(offset->direct[direct].alist_name);
                offset->direct[direct].alist_name = NULL;
@@ -336,7 +336,7 @@ ripngd_instance_offset_list_access_list_modify(enum nb_event event,
        direct = yang_dnode_get_enum(dnode, "../direction");
        alist_name = yang_dnode_get_string(dnode, NULL);
 
-       offset = yang_dnode_get_entry(dnode, true);
+       offset = nb_running_get_entry(dnode, NULL, true);
        if (offset->direct[direct].alist_name)
                free(offset->direct[direct].alist_name);
        offset->direct[direct].alist_name = strdup(alist_name);
@@ -362,7 +362,7 @@ ripngd_instance_offset_list_metric_modify(enum nb_event event,
        direct = yang_dnode_get_enum(dnode, "../direction");
        metric = yang_dnode_get_uint8(dnode, NULL);
 
-       offset = yang_dnode_get_entry(dnode, true);
+       offset = nb_running_get_entry(dnode, NULL, true);
        offset->direct[direct].metric = metric;
 
        return NB_OK;
@@ -382,7 +382,7 @@ ripngd_instance_passive_interface_create(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ripng = yang_dnode_get_entry(dnode, true);
+       ripng = nb_running_get_entry(dnode, NULL, true);
        ifname = yang_dnode_get_string(dnode, NULL);
 
        return ripng_passive_interface_set(ripng, ifname);
@@ -398,7 +398,7 @@ ripngd_instance_passive_interface_destroy(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ripng = yang_dnode_get_entry(dnode, true);
+       ripng = nb_running_get_entry(dnode, NULL, true);
        ifname = yang_dnode_get_string(dnode, NULL);
 
        return ripng_passive_interface_unset(ripng, ifname);
@@ -417,7 +417,7 @@ static int ripngd_instance_redistribute_create(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ripng = yang_dnode_get_entry(dnode, true);
+       ripng = nb_running_get_entry(dnode, NULL, true);
        type = yang_dnode_get_enum(dnode, "./protocol");
 
        ripng->redist[type].enabled = true;
@@ -434,7 +434,7 @@ static int ripngd_instance_redistribute_destroy(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ripng = yang_dnode_get_entry(dnode, true);
+       ripng = nb_running_get_entry(dnode, NULL, true);
        type = yang_dnode_get_enum(dnode, "./protocol");
 
        ripng->redist[type].enabled = false;
@@ -458,7 +458,7 @@ ripngd_instance_redistribute_apply_finish(const struct lyd_node *dnode)
        struct ripng *ripng;
        int type;
 
-       ripng = yang_dnode_get_entry(dnode, true);
+       ripng = nb_running_get_entry(dnode, NULL, true);
        type = yang_dnode_get_enum(dnode, "./protocol");
 
        if (ripng->enabled)
@@ -480,7 +480,7 @@ ripngd_instance_redistribute_route_map_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ripng = yang_dnode_get_entry(dnode, true);
+       ripng = nb_running_get_entry(dnode, NULL, true);
        type = yang_dnode_get_enum(dnode, "../protocol");
        rmap_name = yang_dnode_get_string(dnode, NULL);
 
@@ -502,7 +502,7 @@ ripngd_instance_redistribute_route_map_destroy(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ripng = yang_dnode_get_entry(dnode, true);
+       ripng = nb_running_get_entry(dnode, NULL, true);
        type = yang_dnode_get_enum(dnode, "../protocol");
 
        free(ripng->redist[type].route_map.name);
@@ -527,7 +527,7 @@ ripngd_instance_redistribute_metric_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ripng = yang_dnode_get_entry(dnode, true);
+       ripng = nb_running_get_entry(dnode, NULL, true);
        type = yang_dnode_get_enum(dnode, "../protocol");
        metric = yang_dnode_get_uint8(dnode, NULL);
 
@@ -547,7 +547,7 @@ ripngd_instance_redistribute_metric_destroy(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ripng = yang_dnode_get_entry(dnode, true);
+       ripng = nb_running_get_entry(dnode, NULL, true);
        type = yang_dnode_get_enum(dnode, "../protocol");
 
        ripng->redist[type].metric_config = false;
@@ -569,7 +569,7 @@ static int ripngd_instance_static_route_create(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ripng = yang_dnode_get_entry(dnode, true);
+       ripng = nb_running_get_entry(dnode, NULL, true);
        yang_dnode_get_ipv6p(&p, dnode, NULL);
        apply_mask_ipv6(&p);
 
@@ -588,7 +588,7 @@ static int ripngd_instance_static_route_destroy(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ripng = yang_dnode_get_entry(dnode, true);
+       ripng = nb_running_get_entry(dnode, NULL, true);
        yang_dnode_get_ipv6p(&p, dnode, NULL);
        apply_mask_ipv6(&p);
 
@@ -612,7 +612,7 @@ ripngd_instance_aggregate_address_create(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ripng = yang_dnode_get_entry(dnode, true);
+       ripng = nb_running_get_entry(dnode, NULL, true);
        yang_dnode_get_ipv6p(&p, dnode, NULL);
        apply_mask_ipv6(&p);
 
@@ -631,7 +631,7 @@ ripngd_instance_aggregate_address_destroy(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ripng = yang_dnode_get_entry(dnode, true);
+       ripng = nb_running_get_entry(dnode, NULL, true);
        yang_dnode_get_ipv6p(&p, dnode, NULL);
        apply_mask_ipv6(&p);
 
@@ -647,7 +647,7 @@ static void ripngd_instance_timers_apply_finish(const struct lyd_node *dnode)
 {
        struct ripng *ripng;
 
-       ripng = yang_dnode_get_entry(dnode, true);
+       ripng = nb_running_get_entry(dnode, NULL, true);
 
        /* Reset update timer thread. */
        ripng_event(ripng, RIPNG_UPDATE_EVENT, 0);
@@ -666,7 +666,7 @@ ripngd_instance_timers_flush_interval_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ripng = yang_dnode_get_entry(dnode, true);
+       ripng = nb_running_get_entry(dnode, NULL, true);
        ripng->garbage_time = yang_dnode_get_uint16(dnode, NULL);
 
        return NB_OK;
@@ -685,7 +685,7 @@ ripngd_instance_timers_holddown_interval_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ripng = yang_dnode_get_entry(dnode, true);
+       ripng = nb_running_get_entry(dnode, NULL, true);
        ripng->timeout_time = yang_dnode_get_uint16(dnode, NULL);
 
        return NB_OK;
@@ -704,7 +704,7 @@ ripngd_instance_timers_update_interval_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ripng = yang_dnode_get_entry(dnode, true);
+       ripng = nb_running_get_entry(dnode, NULL, true);
        ripng->update_time = yang_dnode_get_uint16(dnode, NULL);
 
        return NB_OK;
@@ -999,7 +999,7 @@ lib_interface_ripng_split_horizon_modify(enum nb_event event,
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ifp = yang_dnode_get_entry(dnode, true);
+       ifp = nb_running_get_entry(dnode, NULL, true);
        ri = ifp->info;
        ri->split_horizon = yang_dnode_get_enum(dnode, NULL);
 
index 41ba2360ba07d5b4510328dc23fc33efacc661d5..fe95ccfc2bdf18907fbf91fd6d2c10a58dbf20cc 100644 (file)
@@ -56,6 +56,11 @@ struct ripng_offset_list *ripng_offset_list_new(struct ripng *ripng,
 void ripng_offset_list_del(struct ripng_offset_list *offset)
 {
        listnode_delete(offset->ripng->offset_list_master, offset);
+       ripng_offset_list_free(offset);
+}
+
+void ripng_offset_list_free(struct ripng_offset_list *offset)
+{
        if (OFFSET_LIST_IN_NAME(offset))
                free(OFFSET_LIST_IN_NAME(offset));
        if (OFFSET_LIST_OUT_NAME(offset))
index b36cee2c5d5a1f156b3c0654e72d577362e0d48f..411689a7a720eeb761419d2483b55a6011d03ed7 100644 (file)
@@ -1889,7 +1889,7 @@ struct ripng *ripng_create(const char *vrf_name, struct vrf *vrf, int socket)
        ripng->offset_list_master->cmp =
                (int (*)(void *, void *))offset_list_cmp;
        ripng->offset_list_master->del =
-               (void (*)(void *))ripng_offset_list_del;
+               (void (*)(void *))ripng_offset_list_free;
        ripng->distribute_ctx = distribute_list_ctx_create(vrf);
        distribute_list_add_hook(ripng->distribute_ctx,
                                 ripng_distribute_update);
index dcc61ae58a0e6249b2d98011179a962d6961c262..dc425b6958c60228c6c0bdc331a1bdc7380300cc 100644 (file)
@@ -421,6 +421,7 @@ extern void ripng_peer_list_del(void *arg);
 extern struct ripng_offset_list *ripng_offset_list_new(struct ripng *ripng,
                                                       const char *ifname);
 extern void ripng_offset_list_del(struct ripng_offset_list *offset);
+extern void ripng_offset_list_free(struct ripng_offset_list *offset);
 extern struct ripng_offset_list *ripng_offset_list_lookup(struct ripng *ripng,
                                                          const char *ifname);
 extern int ripng_offset_list_apply_in(struct ripng *ripng,
index 28ecfeec5ac37030c34ee2769994f3d884e818fe..5674120b9c750c7213e8fd4348d7d626d2a7f7a1 100644 (file)
@@ -1,7 +1,7 @@
 from lutil import luCommand
 luCommand('ce1','vtysh -c "show bgp summary"',' 00:0','wait','Adjacencies up',180)
-luCommand('ce2','vtysh -c "show bgp summary"',' 00:0','wait','Adjacencies up')
-luCommand('ce3','vtysh -c "show bgp summary"',' 00:0','wait','Adjacencies up')
+luCommand('ce2','vtysh -c "show bgp summary"',' 00:0','wait','Adjacencies up',180)
+luCommand('ce3','vtysh -c "show bgp summary"',' 00:0','wait','Adjacencies up',180)
 luCommand('ce4','vtysh -c "show bgp vrf all summary"',' 00:0','wait','Adjacencies up',180)
 luCommand('r1','ping 2.2.2.2 -c 1',' 0. packet loss','wait','PE->P2 (loopback) ping',60)
 luCommand('r3','ping 2.2.2.2 -c 1',' 0. packet loss','wait','PE->P2 (loopback) ping',60)
diff --git a/tests/topotests/bgp_maximum_prefix_invalid_update/__init__.py b/tests/topotests/bgp_maximum_prefix_invalid_update/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/topotests/bgp_maximum_prefix_invalid_update/r1/bgpd.conf b/tests/topotests/bgp_maximum_prefix_invalid_update/r1/bgpd.conf
new file mode 100644 (file)
index 0000000..235b42b
--- /dev/null
@@ -0,0 +1,4 @@
+router bgp 65000
+  neighbor 192.168.255.2 remote-as 65001
+  address-family ipv4 unicast
+    redistribute connected
diff --git a/tests/topotests/bgp_maximum_prefix_invalid_update/r1/zebra.conf b/tests/topotests/bgp_maximum_prefix_invalid_update/r1/zebra.conf
new file mode 100644 (file)
index 0000000..0a283c0
--- /dev/null
@@ -0,0 +1,9 @@
+!
+interface lo
+ ip address 172.16.255.254/32
+!
+interface r1-eth0
+ ip address 192.168.255.1/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_maximum_prefix_invalid_update/r2/bgpd.conf b/tests/topotests/bgp_maximum_prefix_invalid_update/r2/bgpd.conf
new file mode 100644 (file)
index 0000000..e016284
--- /dev/null
@@ -0,0 +1,4 @@
+router bgp 65001
+  neighbor 192.168.255.1 remote-as 65000
+  address-family ipv4
+    neighbor 192.168.255.1 maximum-prefix 1
diff --git a/tests/topotests/bgp_maximum_prefix_invalid_update/r2/zebra.conf b/tests/topotests/bgp_maximum_prefix_invalid_update/r2/zebra.conf
new file mode 100644 (file)
index 0000000..606c17b
--- /dev/null
@@ -0,0 +1,6 @@
+!
+interface r2-eth0
+ ip address 192.168.255.2/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_maximum_prefix_invalid_update/test_bgp_maximum_prefix_invalid_update.py b/tests/topotests/bgp_maximum_prefix_invalid_update/test_bgp_maximum_prefix_invalid_update.py
new file mode 100644 (file)
index 0000000..69b8c7c
--- /dev/null
@@ -0,0 +1,113 @@
+#!/usr/bin/env python
+
+#
+# bgp_local_as_private_remove.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2019 by
+# Network Device Education Foundation, Inc. ("NetDEF")
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+bgp_maximum_prefix_invalid_update.py:
+Test if unnecesarry UPDATE message like below:
+
+[Error] Error parsing NLRI
+%NOTIFICATION: sent to neighbor X.X.X.X 3/10 (UPDATE Message Error/Invalid Network Field) 0 bytes
+
+is not sent if maximum-prefix count is overflow.
+"""
+
+import os
+import sys
+import json
+import time
+import pytest
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, '../'))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+from mininet.topo import Topo
+
+class TemplateTopo(Topo):
+    def build(self, *_args, **_opts):
+        tgen = get_topogen(self)
+
+        for routern in range(1, 3):
+            tgen.add_router('r{}'.format(routern))
+
+        switch = tgen.add_switch('s1')
+        switch.add_link(tgen.gears['r1'])
+        switch.add_link(tgen.gears['r2'])
+
+def setup_module(mod):
+    tgen = Topogen(TemplateTopo, mod.__name__)
+    tgen.start_topology()
+
+    router_list = tgen.routers()
+
+    for i, (rname, router) in enumerate(router_list.iteritems(), 1):
+        router.load_config(
+            TopoRouter.RD_ZEBRA,
+            os.path.join(CWD, '{}/zebra.conf'.format(rname))
+        )
+        router.load_config(
+            TopoRouter.RD_BGP,
+            os.path.join(CWD, '{}/bgpd.conf'.format(rname))
+        )
+
+    tgen.start_router()
+
+def teardown_module(mod):
+    tgen = get_topogen()
+    tgen.stop_topology()
+
+def test_bgp_maximum_prefix_invalid():
+    tgen = get_topogen()
+
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    def _bgp_converge(router):
+        while True:
+            output = json.loads(tgen.gears[router].vtysh_cmd("show ip bgp neighbor 192.168.255.1 json"))
+            if output['192.168.255.1']['connectionsEstablished'] > 3:
+                return True
+            time.sleep(1)
+
+    def _bgp_parsing_nlri(router):
+        cmd_max_exceeded = 'grep "%MAXPFXEXCEED: No. of IPv4 Unicast prefix received" bgpd.log'
+        cmdt_error_parsing_nlri = 'grep "Error parsing NLRI" bgpd.log'
+        output_max_exceeded = tgen.gears[router].run(cmd_max_exceeded)
+        output_error_parsing_nlri = tgen.gears[router].run(cmdt_error_parsing_nlri)
+
+        if len(output_max_exceeded) > 0:
+            if len(output_error_parsing_nlri) > 0:
+                return False
+        return True
+
+
+    if _bgp_converge('r2'):
+        assert _bgp_parsing_nlri('r2') == True
+
+if __name__ == '__main__':
+    args = ["-s"] + sys.argv[1:]
+    sys.exit(pytest.main(args))
index b2f470bc8d9ba59565f45f0d97aeceb8f250a955..ba518ea576fe0a8b0f7e9c54829cd68ea9e210f1 100644 (file)
@@ -481,6 +481,11 @@ static int netlink_extract_vxlan_info(struct rtattr *link_data,
                vxl_info->vtep_ip = vtep_ip_in_msg;
        }
 
+       if (attr[IFLA_VXLAN_GROUP]) {
+               vxl_info->mcast_grp =
+                       *(struct in_addr *)RTA_DATA(attr[IFLA_VXLAN_GROUP]);
+       }
+
        return 0;
 }
 
@@ -834,11 +839,12 @@ int kernel_interface_set_master(struct interface *master,
 }
 
 /* Interface address modification. */
-static int netlink_address(int cmd, int family, struct interface *ifp,
-                          struct connected *ifc)
+static int netlink_address_ctx(const struct zebra_dplane_ctx *ctx)
 {
        int bytelen;
-       struct prefix *p;
+       const struct prefix *p;
+       int cmd;
+       const char *label;
 
        struct {
                struct nlmsghdr n;
@@ -846,72 +852,59 @@ static int netlink_address(int cmd, int family, struct interface *ifp,
                char buf[NL_PKT_BUF_SIZE];
        } req;
 
-       struct zebra_ns *zns;
-
-       if (vrf_is_backend_netns())
-               zns = zebra_ns_lookup((ns_id_t)ifp->vrf_id);
-       else
-               zns = zebra_ns_lookup(NS_DEFAULT);
-       p = ifc->address;
-       memset(&req, 0, sizeof req - NL_PKT_BUF_SIZE);
+       p = dplane_ctx_get_intf_addr(ctx);
+       memset(&req, 0, sizeof(req) - NL_PKT_BUF_SIZE);
 
-       bytelen = (family == AF_INET ? 4 : 16);
+       bytelen = (p->family == AF_INET ? 4 : 16);
 
        req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
        req.n.nlmsg_flags = NLM_F_REQUEST;
-       req.n.nlmsg_type = cmd;
-       req.n.nlmsg_pid = zns->netlink_cmd.snl.nl_pid;
 
-       req.ifa.ifa_family = family;
+       if (dplane_ctx_get_op(ctx) == DPLANE_OP_ADDR_INSTALL)
+               cmd = RTM_NEWADDR;
+       else
+               cmd = RTM_DELADDR;
+
+       req.n.nlmsg_type = cmd;
+       req.ifa.ifa_family = p->family;
 
-       req.ifa.ifa_index = ifp->ifindex;
+       req.ifa.ifa_index = dplane_ctx_get_ifindex(ctx);
 
-       addattr_l(&req.n, sizeof req, IFA_LOCAL, &p->u.prefix, bytelen);
+       addattr_l(&req.n, sizeof(req), IFA_LOCAL, &p->u.prefix, bytelen);
 
-       if (family == AF_INET) {
-               if (CONNECTED_PEER(ifc)) {
-                       p = ifc->destination;
-                       addattr_l(&req.n, sizeof req, IFA_ADDRESS, &p->u.prefix,
-                                 bytelen);
-               } else if (cmd == RTM_NEWADDR && ifc->destination) {
-                       p = ifc->destination;
-                       addattr_l(&req.n, sizeof req, IFA_BROADCAST,
+       if (p->family == AF_INET) {
+               if (dplane_ctx_intf_is_connected(ctx)) {
+                       p = dplane_ctx_get_intf_dest(ctx);
+                       addattr_l(&req.n, sizeof(req), IFA_ADDRESS,
+                                 &p->u.prefix, bytelen);
+               } else if (cmd == RTM_NEWADDR &&
+                          dplane_ctx_intf_has_dest(ctx)) {
+                       p = dplane_ctx_get_intf_dest(ctx);
+                       addattr_l(&req.n, sizeof(req), IFA_BROADCAST,
                                  &p->u.prefix, bytelen);
                }
        }
 
-       /* p is now either ifc->address or ifc->destination */
+       /* p is now either address or destination/bcast addr */
        req.ifa.ifa_prefixlen = p->prefixlen;
 
-       if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY))
+       if (dplane_ctx_intf_is_secondary(ctx))
                SET_FLAG(req.ifa.ifa_flags, IFA_F_SECONDARY);
 
-       if (ifc->label)
-               addattr_l(&req.n, sizeof req, IFA_LABEL, ifc->label,
-                         strlen(ifc->label) + 1);
-
-       return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns,
-                           0);
-}
-
-int kernel_address_add_ipv4(struct interface *ifp, struct connected *ifc)
-{
-       return netlink_address(RTM_NEWADDR, AF_INET, ifp, ifc);
-}
-
-int kernel_address_delete_ipv4(struct interface *ifp, struct connected *ifc)
-{
-       return netlink_address(RTM_DELADDR, AF_INET, ifp, ifc);
-}
+       if (dplane_ctx_intf_has_label(ctx)) {
+               label = dplane_ctx_get_intf_label(ctx);
+               addattr_l(&req.n, sizeof(req), IFA_LABEL, label,
+                         strlen(label) + 1);
+       }
 
-int kernel_address_add_ipv6(struct interface *ifp, struct connected *ifc)
-{
-       return netlink_address(RTM_NEWADDR, AF_INET6, ifp, ifc);
+       return netlink_talk_info(netlink_talk_filter, &req.n,
+                                dplane_ctx_get_ns(ctx), 0);
 }
 
-int kernel_address_delete_ipv6(struct interface *ifp, struct connected *ifc)
+enum zebra_dplane_result kernel_address_update_ctx(struct zebra_dplane_ctx *ctx)
 {
-       return netlink_address(RTM_DELADDR, AF_INET6, ifp, ifc);
+       return (netlink_address_ctx(ctx) == 0 ?
+               ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE);
 }
 
 int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup)
index 229f9c1da425be21a0d30b8a63b96fdeef73e234..10f1f9210052b1dc24613d69e84b95160294cbd3 100644 (file)
@@ -441,7 +441,7 @@ static void if_addr_wakeup(struct interface *ifp)
        struct listnode *node, *nnode;
        struct connected *ifc;
        struct prefix *p;
-       int ret;
+       enum zebra_dplane_result dplane_res;
 
        for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, ifc)) {
                p = ifc->address;
@@ -479,12 +479,13 @@ static void if_addr_wakeup(struct interface *ifp)
                                        if_refresh(ifp);
                                }
 
-                               ret = if_set_prefix(ifp, ifc);
-                               if (ret < 0) {
+                               dplane_res = dplane_intf_addr_set(ifp, ifc);
+                               if (dplane_res ==
+                                   ZEBRA_DPLANE_REQUEST_FAILURE) {
                                        flog_err_sys(
                                                EC_ZEBRA_IFACE_ADDR_ADD_FAILED,
                                                "Can't set interface's address: %s",
-                                               safe_strerror(errno));
+                                               dplane_res2str(dplane_res));
                                        continue;
                                }
 
@@ -502,12 +503,14 @@ static void if_addr_wakeup(struct interface *ifp)
                                        if_refresh(ifp);
                                }
 
-                               ret = if_prefix_add_ipv6(ifp, ifc);
-                               if (ret < 0) {
+
+                               dplane_res = dplane_intf_addr_set(ifp, ifc);
+                               if (dplane_res ==
+                                   ZEBRA_DPLANE_REQUEST_FAILURE) {
                                        flog_err_sys(
                                                EC_ZEBRA_IFACE_ADDR_ADD_FAILED,
                                                "Can't set interface's address: %s",
-                                               safe_strerror(errno));
+                                               dplane_res2str(dplane_res));
                                        continue;
                                }
 
@@ -1369,8 +1372,11 @@ static void if_dump_vty(struct vty *vty, struct interface *ifp)
                        vty_out(vty, " VTEP IP: %s",
                                inet_ntoa(vxlan_info->vtep_ip));
                if (vxlan_info->access_vlan)
-                       vty_out(vty, " Access VLAN Id %u",
+                       vty_out(vty, " Access VLAN Id %u\n",
                                vxlan_info->access_vlan);
+               if (vxlan_info->mcast_grp.s_addr != INADDR_ANY)
+                       vty_out(vty, "  Mcast Group %s",
+                                       inet_ntoa(vxlan_info->mcast_grp));
                vty_out(vty, "\n");
        }
 
@@ -2626,6 +2632,7 @@ static int ip_address_install(struct vty *vty, struct interface *ifp,
        struct connected *ifc;
        struct prefix_ipv4 *p;
        int ret;
+       enum zebra_dplane_result dplane_res;
 
        if_data = ifp->info;
 
@@ -2699,10 +2706,10 @@ static int ip_address_install(struct vty *vty, struct interface *ifp,
                        if_refresh(ifp);
                }
 
-               ret = if_set_prefix(ifp, ifc);
-               if (ret < 0) {
+               dplane_res = dplane_intf_addr_set(ifp, ifc);
+               if (dplane_res == ZEBRA_DPLANE_REQUEST_FAILURE) {
                        vty_out(vty, "%% Can't set interface IP address: %s.\n",
-                               safe_strerror(errno));
+                               dplane_res2str(dplane_res));
                        return CMD_WARNING_CONFIG_FAILED;
                }
 
@@ -2723,6 +2730,7 @@ static int ip_address_uninstall(struct vty *vty, struct interface *ifp,
        struct prefix_ipv4 lp, pp;
        struct connected *ifc;
        int ret;
+       enum zebra_dplane_result dplane_res;
 
        /* Convert to prefix structure. */
        ret = str2prefix_ipv4(addr_str, &lp);
@@ -2767,10 +2775,10 @@ static int ip_address_uninstall(struct vty *vty, struct interface *ifp,
        }
 
        /* This is real route. */
-       ret = if_unset_prefix(ifp, ifc);
-       if (ret < 0) {
+       dplane_res = dplane_intf_addr_unset(ifp, ifc);
+       if (dplane_res == ZEBRA_DPLANE_REQUEST_FAILURE) {
                vty_out(vty, "%% Can't unset interface IP address: %s.\n",
-                       safe_strerror(errno));
+                       dplane_res2str(dplane_res));
                return CMD_WARNING_CONFIG_FAILED;
        }
        UNSET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED);
@@ -2877,6 +2885,7 @@ static int ipv6_address_install(struct vty *vty, struct interface *ifp,
        struct connected *ifc;
        struct prefix_ipv6 *p;
        int ret;
+       enum zebra_dplane_result dplane_res;
 
        if_data = ifp->info;
 
@@ -2923,11 +2932,10 @@ static int ipv6_address_install(struct vty *vty, struct interface *ifp,
                        if_refresh(ifp);
                }
 
-               ret = if_prefix_add_ipv6(ifp, ifc);
-
-               if (ret < 0) {
+               dplane_res = dplane_intf_addr_set(ifp, ifc);
+               if (dplane_res == ZEBRA_DPLANE_REQUEST_FAILURE) {
                        vty_out(vty, "%% Can't set interface IP address: %s.\n",
-                               safe_strerror(errno));
+                               dplane_res2str(dplane_res));
                        return CMD_WARNING_CONFIG_FAILED;
                }
 
@@ -2961,6 +2969,7 @@ static int ipv6_address_uninstall(struct vty *vty, struct interface *ifp,
        struct prefix_ipv6 cp;
        struct connected *ifc;
        int ret;
+       enum zebra_dplane_result dplane_res;
 
        /* Convert to prefix structure. */
        ret = str2prefix_ipv6(addr_str, &cp);
@@ -2991,10 +3000,10 @@ static int ipv6_address_uninstall(struct vty *vty, struct interface *ifp,
        }
 
        /* This is real route. */
-       ret = if_prefix_delete_ipv6(ifp, ifc);
-       if (ret < 0) {
+       dplane_res = dplane_intf_addr_unset(ifp, ifc);
+       if (dplane_res == ZEBRA_DPLANE_REQUEST_FAILURE) {
                vty_out(vty, "%% Can't unset interface IP address: %s.\n",
-                       safe_strerror(errno));
+                       dplane_res2str(dplane_res));
                return CMD_WARNING_CONFIG_FAILED;
        }
 
index 9499c731ef4cccfca5c823cbb8c2e9c16eb1758e..322527015bd5b440503fe0d68f69da2b69bfde89 100644 (file)
@@ -34,6 +34,7 @@
 #include "zebra/rt.h"
 #include "zebra/interface.h"
 #include "zebra/zebra_errors.h"
+#include "zebra/debug.h"
 
 #ifndef SUNOS_5
 
@@ -180,40 +181,72 @@ void if_get_mtu(struct interface *ifp)
 #endif
 }
 
-#ifdef HAVE_NETLINK
-/* Interface address setting via netlink interface. */
-int if_set_prefix(struct interface *ifp, struct connected *ifc)
-{
-       return kernel_address_add_ipv4(ifp, ifc);
-}
+/*
+ * Handler for interface address programming via the zebra dplane,
+ * for non-netlink platforms. This handler dispatches to per-platform
+ * helpers, based on the operation requested.
+ */
+#ifndef HAVE_NETLINK
 
-/* Interface address is removed using netlink interface. */
-int if_unset_prefix(struct interface *ifp, struct connected *ifc)
+/* Prototypes: these are placed in this block so that they're only seen
+ * on non-netlink platforms.
+ */
+static int if_set_prefix_ctx(const struct zebra_dplane_ctx *ctx);
+static int if_unset_prefix_ctx(const struct zebra_dplane_ctx *ctx);
+static int if_set_prefix6_ctx(const struct zebra_dplane_ctx *ctx);
+static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx *ctx);
+
+enum zebra_dplane_result kernel_address_update_ctx(
+       struct zebra_dplane_ctx *ctx)
 {
-       return kernel_address_delete_ipv4(ifp, ifc);
+       int ret = -1;
+       const struct prefix *p;
+
+       p = dplane_ctx_get_intf_addr(ctx);
+
+       if (dplane_ctx_get_op(ctx) == DPLANE_OP_ADDR_INSTALL) {
+               if (p->family == AF_INET)
+                       ret = if_set_prefix_ctx(ctx);
+               else
+                       ret = if_set_prefix6_ctx(ctx);
+       } else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ADDR_UNINSTALL) {
+               if (p->family == AF_INET)
+                       ret = if_unset_prefix_ctx(ctx);
+               else
+                       ret = if_unset_prefix6_ctx(ctx);
+       } else {
+               if (IS_ZEBRA_DEBUG_DPLANE)
+                       zlog_debug("Invalid op in interface-addr install");
+       }
+
+       return (ret == 0 ?
+               ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE);
 }
+
+#endif /* !HAVE_NETLINK */
+
+#ifdef HAVE_NETLINK
+
+/* TODO -- remove; no use of these apis with netlink any longer */
+
 #else /* ! HAVE_NETLINK */
 #ifdef HAVE_STRUCT_IFALIASREQ
-/* Set up interface's IP address, netmask (and broadcas? ).  *BSD may
-   has ifaliasreq structure.  */
-int if_set_prefix(struct interface *ifp, struct connected *ifc)
+
+/*
+ * Helper for interface-addr install, non-netlink
+ */
+static int if_set_prefix_ctx(const struct zebra_dplane_ctx *ctx)
 {
        int ret;
        struct ifaliasreq addreq;
        struct sockaddr_in addr, mask, peer;
        struct prefix_ipv4 *p;
 
-       /* don't configure PtP addresses on broadcast ifs or reverse */
-       if (!(ifp->flags & IFF_POINTOPOINT) != !CONNECTED_PEER(ifc)) {
-               errno = EINVAL;
-               return -1;
-       }
+       p = (struct prefix_ipv4 *)dplane_ctx_get_intf_addr(ctx);
 
-       p = (struct prefix_ipv4 *)ifc->address;
-       rib_lookup_and_pushup(p, ifp->vrf_id);
-
-       memset(&addreq, 0, sizeof addreq);
-       strlcpy(addreq.ifra_name, ifp->name, sizeof(addreq.ifra_name));
+       memset(&addreq, 0, sizeof(addreq));
+       strncpy((char *)&addreq.ifra_name, dplane_ctx_get_ifname(ctx),
+               sizeof(addreq.ifra_name));
 
        memset(&addr, 0, sizeof(struct sockaddr_in));
        addr.sin_addr = p->prefix;
@@ -223,8 +256,8 @@ int if_set_prefix(struct interface *ifp, struct connected *ifc)
 #endif
        memcpy(&addreq.ifra_addr, &addr, sizeof(struct sockaddr_in));
 
-       if (CONNECTED_PEER(ifc)) {
-               p = (struct prefix_ipv4 *)ifc->destination;
+       if (dplane_ctx_intf_is_connected(ctx)) {
+               p = (struct prefix_ipv4 *)dplane_ctx_get_intf_dest(ctx);
                memset(&mask, 0, sizeof(struct sockaddr_in));
                peer.sin_addr = p->prefix;
                peer.sin_family = p->family;
@@ -247,27 +280,24 @@ int if_set_prefix(struct interface *ifp, struct connected *ifc)
        if (ret < 0)
                return ret;
        return 0;
+
 }
 
-/* Set up interface's IP address, netmask (and broadcas? ).  *BSD may
-   has ifaliasreq structure.  */
-int if_unset_prefix(struct interface *ifp, struct connected *ifc)
+/*
+ * Helper for interface-addr un-install, non-netlink
+ */
+static int if_unset_prefix_ctx(const struct zebra_dplane_ctx *ctx)
 {
        int ret;
        struct ifaliasreq addreq;
        struct sockaddr_in addr, mask, peer;
        struct prefix_ipv4 *p;
 
-       /* this would probably wreak havoc */
-       if (!(ifp->flags & IFF_POINTOPOINT) != !CONNECTED_PEER(ifc)) {
-               errno = EINVAL;
-               return -1;
-       }
+       p = (struct prefix_ipv4 *)dplane_ctx_get_intf_addr(ctx);
 
-       p = (struct prefix_ipv4 *)ifc->address;
-
-       memset(&addreq, 0, sizeof addreq);
-       strlcpy(addreq.ifra_name, ifp->name, sizeof(addreq.ifra_name));
+       memset(&addreq, 0, sizeof(addreq));
+       strncpy((char *)&addreq.ifra_name, dplane_ctx_get_ifname(ctx),
+               sizeof(addreq.ifra_name));
 
        memset(&addr, 0, sizeof(struct sockaddr_in));
        addr.sin_addr = p->prefix;
@@ -277,8 +307,8 @@ int if_unset_prefix(struct interface *ifp, struct connected *ifc)
 #endif
        memcpy(&addreq.ifra_addr, &addr, sizeof(struct sockaddr_in));
 
-       if (CONNECTED_PEER(ifc)) {
-               p = (struct prefix_ipv4 *)ifc->destination;
+       if (dplane_ctx_intf_is_connected(ctx)) {
+               p = (struct prefix_ipv4 *)dplane_ctx_get_intf_dest(ctx);
                memset(&mask, 0, sizeof(struct sockaddr_in));
                peer.sin_addr = p->prefix;
                peer.sin_family = p->family;
@@ -305,7 +335,7 @@ int if_unset_prefix(struct interface *ifp, struct connected *ifc)
 #else
 /* Set up interface's address, netmask (and broadcas? ).  Linux or
    Solaris uses ifname:number semantics to set IP address aliases. */
-int if_set_prefix(struct interface *ifp, struct connected *ifc)
+int if_set_prefix_ctx(const struct zebra_dplane_ctx *ctx)
 {
        int ret;
        struct ifreq ifreq;
@@ -315,11 +345,12 @@ int if_set_prefix(struct interface *ifp, struct connected *ifc)
        struct prefix_ipv4 ifaddr;
        struct prefix_ipv4 *p;
 
-       p = (struct prefix_ipv4 *)ifc->address;
+       p = (struct prefix_ipv4 *)dplane_ctx_get_intf_addr(ctx);
 
        ifaddr = *p;
 
-       ifreq_set_name(&ifreq, ifp);
+       strlcpy(ifreq.ifr_name, dplane_ctx_get_ifname(ctx),
+               sizeof(ifreq.ifr_name));
 
        addr.sin_addr = p->prefix;
        addr.sin_family = p->family;
@@ -331,7 +362,7 @@ int if_set_prefix(struct interface *ifp, struct connected *ifc)
        /* We need mask for make broadcast addr. */
        masklen2ip(p->prefixlen, &mask.sin_addr);
 
-       if (if_is_broadcast(ifp)) {
+       if (dplane_ctx_intf_is_broadcast(ctx)) {
                apply_mask_ipv4(&ifaddr);
                addr.sin_addr = ifaddr.prefix;
 
@@ -350,7 +381,7 @@ int if_set_prefix(struct interface *ifp, struct connected *ifc)
 #ifdef SUNOS_5
        memcpy(&mask, &ifreq.ifr_addr, sizeof(mask));
 #else
-       memcpy(&ifreq.ifr_netmask, &mask, sizeof(struct sockaddr_in));
+       memcpy(&ifreq.ifr_addr, &mask, sizeof(struct sockaddr_in));
 #endif /* SUNOS5 */
        ret = if_ioctl(SIOCSIFNETMASK, (caddr_t)&ifreq);
        if (ret < 0)
@@ -361,16 +392,17 @@ int if_set_prefix(struct interface *ifp, struct connected *ifc)
 
 /* Set up interface's address, netmask (and broadcas? ).  Linux or
    Solaris uses ifname:number semantics to set IP address aliases. */
-int if_unset_prefix(struct interface *ifp, struct connected *ifc)
+int if_unset_prefix_ctx(const struct zebra_dplane_ctx *ctx)
 {
        int ret;
        struct ifreq ifreq;
        struct sockaddr_in addr;
        struct prefix_ipv4 *p;
 
-       p = (struct prefix_ipv4 *)ifc->address;
+       p = (struct prefix_ipv4 *)dplane_ctx_get_intf_addr(ctx);
 
-       ifreq_set_name(&ifreq, ifp);
+       strlcpy(ifreq.ifr_name, dplane_ctx_get_ifname(ctx),
+               sizeof(ifreq.ifr_name));
 
        memset(&addr, 0, sizeof(struct sockaddr_in));
        addr.sin_family = p->family;
@@ -475,35 +507,17 @@ int if_unset_flags(struct interface *ifp, uint64_t flags)
        return 0;
 }
 
-#ifdef LINUX_IPV6
-#ifndef _LINUX_IN6_H
-/* linux/include/net/ipv6.h */
-struct in6_ifreq {
-       struct in6_addr ifr6_addr;
-       uint32_t ifr6_prefixlen;
-       int ifr6_ifindex;
-};
-#endif /* _LINUX_IN6_H */
-/* Interface's address add/delete functions. */
-int if_prefix_add_ipv6(struct interface *ifp, struct connected *ifc)
-{
-#ifdef HAVE_NETLINK
-       return kernel_address_add_ipv6(ifp, ifc);
-#endif /* HAVE_NETLINK */
-}
+#ifndef LINUX_IPV6 /* Netlink has its own code */
 
-int if_prefix_delete_ipv6(struct interface *ifp, struct connected *ifc)
-{
-#ifdef HAVE_NETLINK
-       return kernel_address_delete_ipv6(ifp, ifc);
-#endif /* HAVE_NETLINK */
-}
-#else /* LINUX_IPV6 */
 #ifdef HAVE_STRUCT_IN6_ALIASREQ
 #ifndef ND6_INFINITE_LIFETIME
 #define ND6_INFINITE_LIFETIME 0xffffffffL
 #endif /* ND6_INFINITE_LIFETIME */
-int if_prefix_add_ipv6(struct interface *ifp, struct connected *ifc)
+
+/*
+ * Helper for interface-addr install, non-netlink
+ */
+static int if_set_prefix6_ctx(const struct zebra_dplane_ctx *ctx)
 {
        int ret;
        struct in6_aliasreq addreq;
@@ -511,10 +525,11 @@ int if_prefix_add_ipv6(struct interface *ifp, struct connected *ifc)
        struct sockaddr_in6 mask;
        struct prefix_ipv6 *p;
 
-       p = (struct prefix_ipv6 *)ifc->address;
+       p = (struct prefix_ipv6 *)dplane_ctx_get_intf_addr(ctx);
 
-       memset(&addreq, 0, sizeof addreq);
-       strlcpy(addreq.ifra_name, ifp->name, sizeof(addreq.ifra_name));
+       memset(&addreq, 0, sizeof(addreq));
+       strlcpy((char *)&addreq.ifra_name,
+               dplane_ctx_get_ifname(ctx), sizeof(addreq.ifra_name));
 
        memset(&addr, 0, sizeof(struct sockaddr_in6));
        addr.sin6_addr = p->prefix;
@@ -546,7 +561,10 @@ int if_prefix_add_ipv6(struct interface *ifp, struct connected *ifc)
        return 0;
 }
 
-int if_prefix_delete_ipv6(struct interface *ifp, struct connected *ifc)
+/*
+ * Helper for interface-addr un-install, non-netlink
+ */
+static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx *ctx)
 {
        int ret;
        struct in6_aliasreq addreq;
@@ -554,10 +572,11 @@ int if_prefix_delete_ipv6(struct interface *ifp, struct connected *ifc)
        struct sockaddr_in6 mask;
        struct prefix_ipv6 *p;
 
-       p = (struct prefix_ipv6 *)ifc->address;
+       p = (struct prefix_ipv6 *)dplane_ctx_get_intf_addr(ctx);
 
-       memset(&addreq, 0, sizeof addreq);
-       strlcpy(addreq.ifra_name, ifp->name, sizeof(addreq.ifra_name));
+       memset(&addreq, 0, sizeof(addreq));
+       strlcpy((char *)&addreq.ifra_name,
+               dplane_ctx_get_ifname(ctx), sizeof(addreq.ifra_name));
 
        memset(&addr, 0, sizeof(struct sockaddr_in6));
        addr.sin6_addr = p->prefix;
@@ -586,12 +605,15 @@ int if_prefix_delete_ipv6(struct interface *ifp, struct connected *ifc)
        return 0;
 }
 #else
-int if_prefix_add_ipv6(struct interface *ifp, struct connected *ifc)
+/* The old, pre-dataplane code here just returned, so we're retaining that
+ * choice.
+ */
+static int if_set_prefix6_ctx(const struct zebra_dplane_ctx *ctx)
 {
        return 0;
 }
 
-int if_prefix_delete_ipv6(struct interface *ifp, struct connected *ifc)
+static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx *ctx)
 {
        return 0;
 }
index 67ffd45a0818adec7e5dceaa9916e2b92bc55c70..03f3911d526eb61510309b85fc9249f49866cc62 100644 (file)
@@ -35,15 +35,9 @@ extern int if_set_flags(struct interface *, uint64_t);
 extern int if_unset_flags(struct interface *, uint64_t);
 extern void if_get_flags(struct interface *);
 
-extern int if_set_prefix(struct interface *, struct connected *);
-extern int if_unset_prefix(struct interface *, struct connected *);
-
 extern void if_get_metric(struct interface *);
 extern void if_get_mtu(struct interface *);
 
-extern int if_prefix_add_ipv6(struct interface *, struct connected *);
-extern int if_prefix_delete_ipv6(struct interface *, struct connected *);
-
 #ifdef SOLARIS_IPV6
 extern int if_ioctl_ipv6(unsigned long, caddr_t);
 extern struct connected *if_lookup_linklocal(struct interface *);
index c523ee983d32f3e8bb5fe025beb8d748a9bf2181..ccfa7a4a4c38f3111b9eb5f6fbf27aa0e1170986 100644 (file)
 #include "zebra/interface.h"
 #include "zebra/ioctl_solaris.h"
 #include "zebra/zebra_errors.h"
+#include "zebra/debug.h"
 
 extern struct zebra_privs_t zserv_privs;
 
+/* Prototypes */
+static int if_set_prefix_ctx(const struct zebra_dplane_ctx *ctx);
+static int if_unset_prefix_ctx(const struct zebra_dplane_ctx *ctx);
+static int if_set_prefix6_ctx(const struct zebra_dplane_ctx *ctx);
+static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx *ctx);
+
 /* clear and set interface name string */
 void lifreq_set_name(struct lifreq *lifreq, const char *ifname)
 {
@@ -183,23 +190,52 @@ void if_get_mtu(struct interface *ifp)
                zebra_interface_up_update(ifp);
 }
 
+/*
+ *
+ */
+enum zebra_dplane_result kernel_address_update_ctx(
+       struct zebra_dplane_ctx *ctx)
+{
+       int ret = -1;
+       const struct prefix *p;
+
+       p = dplane_ctx_get_intf_addr(ctx);
+
+       if (dplane_ctx_get_op(ctx) == DPLANE_OP_ADDR_INSTALL) {
+               if (p->family == AF_INET)
+                       ret = if_set_prefix_ctx(ctx);
+               else
+                       ret = if_set_prefix6_ctx(ctx);
+       } else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ADDR_UNINSTALL) {
+               if (p->family == AF_INET)
+                       ret = if_unset_prefix_ctx(ctx);
+               else
+                       ret = if_unset_prefix6_ctx(ctx);
+       } else {
+               if (IS_ZEBRA_DEBUG_DPLANE)
+                       zlog_debug("Invalid op in interface-addr install");
+       }
+
+       return (ret == 0 ?
+               ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE);
+}
+
 /* Set up interface's address, netmask (and broadcast? ).
    Solaris uses ifname:number semantics to set IP address aliases. */
-int if_set_prefix(struct interface *ifp, struct connected *ifc)
+static int if_set_prefix_ctx(const struct zebra_dplane_ctx *ctx)
 {
        int ret;
        struct ifreq ifreq;
-       struct sockaddr_in addr;
-       struct sockaddr_in broad;
-       struct sockaddr_in mask;
+       struct sockaddr_in addr, broad, mask;
        struct prefix_ipv4 ifaddr;
        struct prefix_ipv4 *p;
 
-       p = (struct prefix_ipv4 *)ifc->address;
+       p = (struct prefix_ipv4 *)dplane_ctx_get_intf_addr(ctx);
 
        ifaddr = *p;
 
-       strlcpy(ifreq.ifr_name, ifp->name, sizeof(ifreq.ifr_name));
+       strlcpy(ifreq.ifr_name, dplane_ctx_get_ifname(ctx),
+               sizeof(ifreq.ifr_name));
 
        addr.sin_addr = p->prefix;
        addr.sin_family = p->family;
@@ -213,7 +249,7 @@ int if_set_prefix(struct interface *ifp, struct connected *ifc)
        /* We need mask for make broadcast addr. */
        masklen2ip(p->prefixlen, &mask.sin_addr);
 
-       if (if_is_broadcast(ifp)) {
+       if (dplane_ctx_intf_is_broadcast(ctx)) {
                apply_mask_ipv4(&ifaddr);
                addr.sin_addr = ifaddr.prefix;
 
@@ -241,16 +277,17 @@ int if_set_prefix(struct interface *ifp, struct connected *ifc)
 
 /* Set up interface's address, netmask (and broadcast).
    Solaris uses ifname:number semantics to set IP address aliases. */
-int if_unset_prefix(struct interface *ifp, struct connected *ifc)
+static int if_unset_prefix_ctx(const struct zebra_dplane_ctx *ctx)
 {
        int ret;
        struct ifreq ifreq;
        struct sockaddr_in addr;
        struct prefix_ipv4 *p;
 
-       p = (struct prefix_ipv4 *)ifc->address;
+       p = (struct prefix_ipv4 *)dplane_ctx_get_intf_addr(ctx);
 
-       strlcpy(ifreq.ifr_name, ifp->name, sizeof(ifreq.ifr_name));
+       strncpy(ifreq.ifr_name, dplane_ctx_get_ifname(ctx),
+               sizeof(ifreq.ifr_name));
 
        memset(&addr, 0, sizeof(struct sockaddr_in));
        addr.sin_family = p->family;
@@ -377,24 +414,26 @@ int if_unset_flags(struct interface *ifp, uint64_t flags)
 }
 
 /* Interface's address add/delete functions. */
-int if_prefix_add_ipv6(struct interface *ifp, struct connected *ifc)
+static int if_set_prefix6_ctx(const struct zebra_dplane_ctx *ctx)
 {
        char addrbuf[PREFIX_STRLEN];
 
+       prefix2str(dplane_ctx_get_intf_addr(ctx), addrbuf, sizeof(addrbuf));
+
        flog_warn(EC_LIB_DEVELOPMENT, "Can't set %s on interface %s",
-                 prefix2str(ifc->address, addrbuf, sizeof(addrbuf)),
-                 ifp->name);
+                 addrbuf, dplane_ctx_get_ifname(ctx));
 
        return 0;
 }
 
-int if_prefix_delete_ipv6(struct interface *ifp, struct connected *ifc)
+static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx *ctx)
 {
        char addrbuf[PREFIX_STRLEN];
 
+       prefix2str(dplane_ctx_get_intf_addr(ctx), addrbuf, sizeof(addrbuf));
+
        flog_warn(EC_LIB_DEVELOPMENT, "Can't delete %s on interface %s",
-                 prefix2str(ifc->address, addrbuf, sizeof(addrbuf)),
-                 ifp->name);
+                 addrbuf, dplane_ctx_get_ifname(ctx));
 
        return 0;
 }
index 2c77af2aad9f12a9962956f83ad4bf13f4ff1309..08b51fcc0bcf4ba5fdf11df10bd030049c3b2637 100644 (file)
@@ -50,10 +50,9 @@ extern enum zebra_dplane_result kernel_lsp_update(
 
 enum zebra_dplane_result kernel_pw_update(struct zebra_dplane_ctx *ctx);
 
-extern int kernel_address_add_ipv4(struct interface *, struct connected *);
-extern int kernel_address_delete_ipv4(struct interface *, struct connected *);
-extern int kernel_address_add_ipv6(struct interface *, struct connected *);
-extern int kernel_address_delete_ipv6(struct interface *, struct connected *);
+enum zebra_dplane_result kernel_address_update_ctx(
+       struct zebra_dplane_ctx *ctx);
+
 extern int kernel_neigh_update(int cmd, int ifindex, uint32_t addr, char *lla,
                               int llalen, ns_id_t ns_id);
 extern int kernel_interface_set_master(struct interface *master,
index af54c3b5c7bd31bc8dfc738bce5f9c39759e15b2..d1b28227c37d7f78cd14e123691a18bd03b16030 100644 (file)
@@ -121,6 +121,33 @@ struct dplane_pw_info {
        union pw_protocol_fields fields;
 };
 
+/*
+ * Interface/prefix info for the dataplane
+ */
+struct dplane_intf_info {
+
+       char ifname[INTERFACE_NAMSIZ];
+       ifindex_t ifindex;
+
+       uint32_t metric;
+       uint32_t flags;
+
+#define DPLANE_INTF_CONNECTED   (1 << 0) /* Connected peer, p2p */
+#define DPLANE_INTF_SECONDARY   (1 << 1)
+#define DPLANE_INTF_BROADCAST   (1 << 2)
+#define DPLANE_INTF_HAS_DEST    (1 << 3)
+#define DPLANE_INTF_HAS_LABEL   (1 << 4)
+
+       /* Interface address/prefix */
+       struct prefix prefix;
+
+       /* Dest address, for p2p, or broadcast prefix */
+       struct prefix dest_prefix;
+
+       char *label;
+       char label_buf[32];
+};
+
 /*
  * The context block used to exchange info about route updates across
  * the boundary between the zebra main context (and pthread) and the
@@ -152,11 +179,12 @@ struct zebra_dplane_ctx {
        vrf_id_t zd_vrf_id;
        uint32_t zd_table_id;
 
-       /* Support info for either route or LSP update */
+       /* Support info for different kinds of updates */
        union {
                struct dplane_route_info rinfo;
                zebra_lsp_t lsp;
                struct dplane_pw_info pw;
+               struct dplane_intf_info intf;
        } u;
 
        /* Namespace info, used especially for netlink kernel communication */
@@ -266,6 +294,9 @@ static struct zebra_dplane_globals {
        _Atomic uint32_t dg_pws_in;
        _Atomic uint32_t dg_pw_errors;
 
+       _Atomic uint32_t dg_intf_addrs_in;
+       _Atomic uint32_t dg_intf_addr_errors;
+
        _Atomic uint32_t dg_update_yields;
 
        /* Dataplane pthread */
@@ -303,6 +334,9 @@ static enum zebra_dplane_result lsp_update_internal(zebra_lsp_t *lsp,
                                                    enum dplane_op_e op);
 static enum zebra_dplane_result pw_update_internal(struct zebra_pw *pw,
                                                   enum dplane_op_e op);
+static enum zebra_dplane_result intf_addr_update_internal(
+       const struct interface *ifp, const struct connected *ifc,
+       enum dplane_op_e op);
 
 /*
  * Public APIs
@@ -409,6 +443,16 @@ static void dplane_ctx_free(struct zebra_dplane_ctx **pctx)
                }
                break;
 
+       case DPLANE_OP_ADDR_INSTALL:
+       case DPLANE_OP_ADDR_UNINSTALL:
+               /* Maybe free label string, if allocated */
+               if ((*pctx)->u.intf.label != NULL &&
+                   (*pctx)->u.intf.label != (*pctx)->u.intf.label_buf) {
+                       free((*pctx)->u.intf.label);
+                       (*pctx)->u.intf.label = NULL;
+               }
+               break;
+
        case DPLANE_OP_NONE:
                break;
        }
@@ -549,6 +593,14 @@ const char *dplane_op2str(enum dplane_op_e op)
        case DPLANE_OP_SYS_ROUTE_DELETE:
                ret = "SYS_ROUTE_DEL";
                break;
+
+       case DPLANE_OP_ADDR_INSTALL:
+               ret = "ADDR_INSTALL";
+               break;
+       case DPLANE_OP_ADDR_UNINSTALL:
+               ret = "ADDR_UNINSTALL";
+               break;
+
        }
 
        return ret;
@@ -868,6 +920,90 @@ dplane_ctx_get_pw_nhg(const struct zebra_dplane_ctx *ctx)
        return &(ctx->u.pw.nhg);
 }
 
+/* Accessors for interface information */
+const char *dplane_ctx_get_ifname(const struct zebra_dplane_ctx *ctx)
+{
+       DPLANE_CTX_VALID(ctx);
+
+       return ctx->u.intf.ifname;
+}
+
+ifindex_t dplane_ctx_get_ifindex(const struct zebra_dplane_ctx *ctx)
+{
+       DPLANE_CTX_VALID(ctx);
+
+       return ctx->u.intf.ifindex;
+}
+
+uint32_t dplane_ctx_get_intf_metric(const struct zebra_dplane_ctx *ctx)
+{
+       DPLANE_CTX_VALID(ctx);
+
+       return ctx->u.intf.metric;
+}
+
+/* Is interface addr p2p? */
+bool dplane_ctx_intf_is_connected(const struct zebra_dplane_ctx *ctx)
+{
+       DPLANE_CTX_VALID(ctx);
+
+       return (ctx->u.intf.flags & DPLANE_INTF_CONNECTED);
+}
+
+bool dplane_ctx_intf_is_secondary(const struct zebra_dplane_ctx *ctx)
+{
+       DPLANE_CTX_VALID(ctx);
+
+       return (ctx->u.intf.flags & DPLANE_INTF_SECONDARY);
+}
+
+bool dplane_ctx_intf_is_broadcast(const struct zebra_dplane_ctx *ctx)
+{
+       DPLANE_CTX_VALID(ctx);
+
+       return (ctx->u.intf.flags & DPLANE_INTF_BROADCAST);
+}
+
+const struct prefix *dplane_ctx_get_intf_addr(
+       const struct zebra_dplane_ctx *ctx)
+{
+       DPLANE_CTX_VALID(ctx);
+
+       return &(ctx->u.intf.prefix);
+}
+
+bool dplane_ctx_intf_has_dest(const struct zebra_dplane_ctx *ctx)
+{
+       DPLANE_CTX_VALID(ctx);
+
+       return (ctx->u.intf.flags & DPLANE_INTF_HAS_DEST);
+}
+
+const struct prefix *dplane_ctx_get_intf_dest(
+       const struct zebra_dplane_ctx *ctx)
+{
+       DPLANE_CTX_VALID(ctx);
+
+       if (ctx->u.intf.flags & DPLANE_INTF_HAS_DEST)
+               return &(ctx->u.intf.dest_prefix);
+       else
+               return NULL;
+}
+
+bool dplane_ctx_intf_has_label(const struct zebra_dplane_ctx *ctx)
+{
+       DPLANE_CTX_VALID(ctx);
+
+       return (ctx->u.intf.flags & DPLANE_INTF_HAS_LABEL);
+}
+
+const char *dplane_ctx_get_intf_label(const struct zebra_dplane_ctx *ctx)
+{
+       DPLANE_CTX_VALID(ctx);
+
+       return ctx->u.intf.label;
+}
+
 /*
  * End of dplane context accessors
  */
@@ -1493,6 +1629,140 @@ done:
        return result;
 }
 
+/*
+ * Enqueue interface address add for the dataplane.
+ */
+enum zebra_dplane_result dplane_intf_addr_set(const struct interface *ifp,
+                                             const struct connected *ifc)
+{
+#if !defined(HAVE_NETLINK) && defined(HAVE_STRUCT_IFALIASREQ)
+       /* Extra checks for this OS path. */
+
+       /* Don't configure PtP addresses on broadcast ifs or reverse */
+       if (!(ifp->flags & IFF_POINTOPOINT) != !CONNECTED_PEER(ifc)) {
+               if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_DPLANE)
+                       zlog_debug("Failed to set intf addr: mismatch p2p and connected");
+
+               return ZEBRA_DPLANE_REQUEST_FAILURE;
+       }
+
+       /* Ensure that no existing installed v4 route conflicts with
+        * the new interface prefix. This check must be done in the
+        * zebra pthread context, and any route delete (if needed)
+        * is enqueued before the interface address programming attempt.
+        */
+       if (ifc->address->family == AF_INET) {
+               struct prefix_ipv4 *p;
+
+               p = (struct prefix_ipv4 *)ifc->address;
+               rib_lookup_and_pushup(p, ifp->vrf_id);
+       }
+#endif
+
+       return intf_addr_update_internal(ifp, ifc, DPLANE_OP_ADDR_INSTALL);
+}
+
+/*
+ * Enqueue interface address remove/uninstall for the dataplane.
+ */
+enum zebra_dplane_result dplane_intf_addr_unset(const struct interface *ifp,
+                                               const struct connected *ifc)
+{
+       return intf_addr_update_internal(ifp, ifc, DPLANE_OP_ADDR_UNINSTALL);
+}
+
+static enum zebra_dplane_result intf_addr_update_internal(
+       const struct interface *ifp, const struct connected *ifc,
+       enum dplane_op_e op)
+{
+       enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
+       int ret = EINVAL;
+       struct zebra_dplane_ctx *ctx = NULL;
+       struct zebra_ns *zns;
+
+       if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
+               char addr_str[PREFIX_STRLEN];
+
+               prefix2str(ifc->address, addr_str, sizeof(addr_str));
+
+               zlog_debug("init intf ctx %s: idx %d, addr %u:%s",
+                          dplane_op2str(op), ifp->ifindex, ifp->vrf_id,
+                          addr_str);
+       }
+
+       ctx = dplane_ctx_alloc();
+       if (ctx == NULL) {
+               ret = ENOMEM;
+               goto done;
+       }
+
+       ctx->zd_op = op;
+       ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
+       ctx->zd_vrf_id = ifp->vrf_id;
+
+       zns = zebra_ns_lookup(ifp->vrf_id);
+       dplane_ctx_ns_init(ctx, zns, false);
+
+       /* Init the interface-addr-specific area */
+       memset(&ctx->u.intf, 0, sizeof(ctx->u.intf));
+
+       strncpy(ctx->u.intf.ifname, ifp->name, sizeof(ctx->u.intf.ifname));
+       ctx->u.intf.ifindex = ifp->ifindex;
+       ctx->u.intf.prefix = *(ifc->address);
+
+       if (if_is_broadcast(ifp))
+               ctx->u.intf.flags |= DPLANE_INTF_BROADCAST;
+
+       if (CONNECTED_PEER(ifc)) {
+               ctx->u.intf.dest_prefix = *(ifc->destination);
+               ctx->u.intf.flags |=
+                       (DPLANE_INTF_CONNECTED | DPLANE_INTF_HAS_DEST);
+       } else if (ifc->destination) {
+               ctx->u.intf.dest_prefix = *(ifc->destination);
+               ctx->u.intf.flags |= DPLANE_INTF_HAS_DEST;
+       }
+
+       if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY))
+               ctx->u.intf.flags |= DPLANE_INTF_SECONDARY;
+
+       if (ifc->label) {
+               size_t len;
+
+               ctx->u.intf.flags |= DPLANE_INTF_HAS_LABEL;
+
+               /* Use embedded buffer if it's adequate; else allocate. */
+               len = strlen(ifc->label);
+
+               if (len < sizeof(ctx->u.intf.label_buf)) {
+                       strncpy(ctx->u.intf.label_buf, ifc->label,
+                               sizeof(ctx->u.intf.label_buf));
+                       ctx->u.intf.label = ctx->u.intf.label_buf;
+               } else {
+                       ctx->u.intf.label = strdup(ifc->label);
+               }
+       }
+
+       ret = dplane_route_enqueue(ctx);
+
+done:
+
+       /* Increment counter */
+       atomic_fetch_add_explicit(&zdplane_info.dg_intf_addrs_in, 1,
+                                 memory_order_relaxed);
+
+       if (ret == AOK)
+               result = ZEBRA_DPLANE_REQUEST_QUEUED;
+       else {
+               /* Error counter */
+               atomic_fetch_add_explicit(&zdplane_info.dg_intf_addr_errors,
+                                         1, memory_order_relaxed);
+               if (ctx)
+                       dplane_ctx_free(&ctx);
+       }
+
+       return result;
+}
+
 /*
  * Handler for 'show dplane'
  */
@@ -1876,6 +2146,35 @@ kernel_dplane_route_update(struct zebra_dplane_ctx *ctx)
        return res;
 }
 
+/*
+ * Handler for kernel-facing interface address updates
+ */
+static enum zebra_dplane_result
+kernel_dplane_address_update(struct zebra_dplane_ctx *ctx)
+{
+       enum zebra_dplane_result res;
+
+
+       if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
+               char dest_str[PREFIX_STRLEN];
+
+               prefix2str(dplane_ctx_get_intf_addr(ctx), dest_str,
+                          sizeof(dest_str));
+
+               zlog_debug("Dplane intf %s, idx %u, addr %s",
+                          dplane_op2str(dplane_ctx_get_op(ctx)),
+                          dplane_ctx_get_ifindex(ctx), dest_str);
+       }
+
+       res = kernel_address_update_ctx(ctx);
+
+       if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
+               atomic_fetch_add_explicit(&zdplane_info.dg_intf_addr_errors,
+                                         1, memory_order_relaxed);
+
+       return res;
+}
+
 /*
  * Kernel provider callback
  */
@@ -1925,6 +2224,11 @@ static int kernel_dplane_process_func(struct zebra_dplane_provider *prov)
                        res = kernel_dplane_pw_update(ctx);
                        break;
 
+               case DPLANE_OP_ADDR_INSTALL:
+               case DPLANE_OP_ADDR_UNINSTALL:
+                       res = kernel_dplane_address_update(ctx);
+                       break;
+
                /* Ignore system 'notifications' - the kernel already knows */
                case DPLANE_OP_SYS_ROUTE_ADD:
                case DPLANE_OP_SYS_ROUTE_DELETE:
index 4e089bc66b7d04bdd9e39645310d1c734ac25994..d45628fdd04c9be3dac3ce5053da5e07188dc4fc 100644 (file)
@@ -118,6 +118,10 @@ enum dplane_op_e {
        /* System route notification */
        DPLANE_OP_SYS_ROUTE_ADD,
        DPLANE_OP_SYS_ROUTE_DELETE,
+
+       /* Interface address update */
+       DPLANE_OP_ADDR_INSTALL,
+       DPLANE_OP_ADDR_UNINSTALL,
 };
 
 /* Enable system route notifications */
@@ -234,6 +238,22 @@ const union pw_protocol_fields *dplane_ctx_get_pw_proto(
 const struct nexthop_group *dplane_ctx_get_pw_nhg(
        const struct zebra_dplane_ctx *ctx);
 
+/* Accessors for interface information */
+const char *dplane_ctx_get_ifname(const struct zebra_dplane_ctx *ctx);
+ifindex_t dplane_ctx_get_ifindex(const struct zebra_dplane_ctx *ctx);
+uint32_t dplane_ctx_get_intf_metric(const struct zebra_dplane_ctx *ctx);
+/* Is interface addr p2p? */
+bool dplane_ctx_intf_is_connected(const struct zebra_dplane_ctx *ctx);
+bool dplane_ctx_intf_is_secondary(const struct zebra_dplane_ctx *ctx);
+bool dplane_ctx_intf_is_broadcast(const struct zebra_dplane_ctx *ctx);
+const struct prefix *dplane_ctx_get_intf_addr(
+       const struct zebra_dplane_ctx *ctx);
+bool dplane_ctx_intf_has_dest(const struct zebra_dplane_ctx *ctx);
+const struct prefix *dplane_ctx_get_intf_dest(
+       const struct zebra_dplane_ctx *ctx);
+bool dplane_ctx_intf_has_label(const struct zebra_dplane_ctx *ctx);
+const char *dplane_ctx_get_intf_label(const struct zebra_dplane_ctx *ctx);
+
 /* Namespace info - esp. for netlink communication */
 const struct zebra_dplane_info *dplane_ctx_get_ns(
        const struct zebra_dplane_ctx *ctx);
@@ -275,6 +295,15 @@ enum zebra_dplane_result dplane_lsp_delete(zebra_lsp_t *lsp);
 enum zebra_dplane_result dplane_pw_install(struct zebra_pw *pw);
 enum zebra_dplane_result dplane_pw_uninstall(struct zebra_pw *pw);
 
+/*
+ * Enqueue interface address changes for the dataplane.
+ */
+enum zebra_dplane_result dplane_intf_addr_set(const struct interface *ifp,
+                                             const struct connected *ifc);
+enum zebra_dplane_result dplane_intf_addr_unset(const struct interface *ifp,
+                                               const struct connected *ifc);
+
+
 /* Retrieve the limit on the number of pending, unprocessed updates. */
 uint32_t dplane_get_in_queue_limit(void);
 
index f4b2fe4794da14d73d453b445d86820d2cde6c3c..ca37dd748edc502028340bf85b775b9bb3f1f6eb 100644 (file)
@@ -172,6 +172,7 @@ void zebra_l2_vxlanif_add_update(struct interface *ifp,
 {
        struct zebra_if *zif;
        struct in_addr old_vtep_ip;
+       uint16_t chgflags = 0;
 
        zif = ifp->info;
        assert(zif);
@@ -183,11 +184,20 @@ void zebra_l2_vxlanif_add_update(struct interface *ifp,
        }
 
        old_vtep_ip = zif->l2info.vxl.vtep_ip;
-       if (IPV4_ADDR_SAME(&old_vtep_ip, &vxlan_info->vtep_ip))
-               return;
 
-       zif->l2info.vxl.vtep_ip = vxlan_info->vtep_ip;
-       zebra_vxlan_if_update(ifp, ZEBRA_VXLIF_LOCAL_IP_CHANGE);
+       if (!IPV4_ADDR_SAME(&old_vtep_ip, &vxlan_info->vtep_ip)) {
+               chgflags |= ZEBRA_VXLIF_LOCAL_IP_CHANGE;
+               zif->l2info.vxl.vtep_ip = vxlan_info->vtep_ip;
+       }
+
+       if (!IPV4_ADDR_SAME(&zif->l2info.vxl.mcast_grp,
+                               &vxlan_info->mcast_grp)) {
+               chgflags |= ZEBRA_VXLIF_MCAST_GRP_CHANGE;
+               zif->l2info.vxl.mcast_grp = vxlan_info->mcast_grp;
+       }
+
+       if (chgflags)
+               zebra_vxlan_if_update(ifp, chgflags);
 }
 
 /*
index 2e3e5b4a855b82a9903052b5760e5f14b3e268b9..33aa2e374644c1ca11482b4959f5914192539b68 100644 (file)
@@ -54,6 +54,7 @@ struct zebra_l2info_vxlan {
        vni_t vni;              /* VNI */
        struct in_addr vtep_ip; /* Local tunnel IP */
        vlanid_t access_vlan;   /* Access VLAN - for VLAN-aware bridge. */
+       struct in_addr mcast_grp;
 };
 
 struct zebra_l2info_bondslave {
index e47499b0656deae821692861baa5f0b954f647fb..0e1df1cc35016ef1c9f1597cdafbd6a1ec13aa6c 100644 (file)
@@ -24,7 +24,6 @@
 #include "if.h"
 #include "linklist.h"
 #include "log.h"
-#include "log_int.h"
 #include "memory.h"
 #include "mpls.h"
 #include "nexthop.h"
@@ -403,10 +402,13 @@ static void nexthop_set_resolved(afi_t afi, const struct nexthop *newhop,
        nexthop_add(&nexthop->resolved, resolved_hop);
 }
 
-/* If force flag is not set, do not modify falgs at all for uninstall
-   the route from FIB. */
+/*
+ * Given a nexthop we need to properly recursively resolve
+ * the route.  As such, do a table lookup to find and match
+ * if at all possible.  Set the nexthop->ifindex as appropriate
+ */
 static int nexthop_active(afi_t afi, struct route_entry *re,
-                         struct nexthop *nexthop, bool set,
+                         struct nexthop *nexthop,
                          struct route_node *top)
 {
        struct prefix p;
@@ -422,12 +424,10 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
            || nexthop->type == NEXTHOP_TYPE_IPV6)
                nexthop->ifindex = 0;
 
-       if (set) {
-               UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
-               nexthops_free(nexthop->resolved);
-               nexthop->resolved = NULL;
-               re->nexthop_mtu = 0;
-       }
+       UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
+       nexthops_free(nexthop->resolved);
+       nexthop->resolved = NULL;
+       re->nexthop_mtu = 0;
 
        /*
         * If the kernel has sent us a route, then
@@ -437,16 +437,6 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
            re->type == ZEBRA_ROUTE_SYSTEM)
                return 1;
 
-       /* Skip nexthops that have been filtered out due to route-map */
-       /* The nexthops are specific to this route and so the same */
-       /* nexthop for a different route may not have this flag set */
-       if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FILTERED)) {
-               if (IS_ZEBRA_DEBUG_RIB_DETAILED)
-                       zlog_debug("\t%s: Nexthop Filtered",
-                                  __PRETTY_FUNCTION__);
-               return 0;
-       }
-
        /*
         * Check to see if we should trust the passed in information
         * for UNNUMBERED interfaces as that we won't find the GW
@@ -581,17 +571,14 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
                                               NEXTHOP_FLAG_RECURSIVE))
                                        continue;
 
-                               if (set) {
-                                       SET_FLAG(nexthop->flags,
-                                                NEXTHOP_FLAG_RECURSIVE);
-                                       SET_FLAG(re->status,
-                                                ROUTE_ENTRY_NEXTHOPS_CHANGED);
-                                       nexthop_set_resolved(afi, newhop,
-                                                            nexthop);
-                               }
+                               SET_FLAG(nexthop->flags,
+                                        NEXTHOP_FLAG_RECURSIVE);
+                               SET_FLAG(re->status,
+                                        ROUTE_ENTRY_NEXTHOPS_CHANGED);
+                               nexthop_set_resolved(afi, newhop, nexthop);
                                resolved = 1;
                        }
-                       if (resolved && set)
+                       if (resolved)
                                re->nexthop_mtu = match->mtu;
                        if (!resolved && IS_ZEBRA_DEBUG_RIB_DETAILED)
                                zlog_debug("\t%s: Recursion failed to find",
@@ -607,15 +594,12 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
                                               NEXTHOP_FLAG_RECURSIVE))
                                        continue;
 
-                               if (set) {
-                                       SET_FLAG(nexthop->flags,
-                                                NEXTHOP_FLAG_RECURSIVE);
-                                       nexthop_set_resolved(afi, newhop,
-                                                            nexthop);
-                               }
+                               SET_FLAG(nexthop->flags,
+                                        NEXTHOP_FLAG_RECURSIVE);
+                               nexthop_set_resolved(afi, newhop, nexthop);
                                resolved = 1;
                        }
-                       if (resolved && set)
+                       if (resolved)
                                re->nexthop_mtu = match->mtu;
 
                        if (!resolved && IS_ZEBRA_DEBUG_RIB_DETAILED)
@@ -819,17 +803,15 @@ struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p, vrf_id_t vrf_id)
 
 /* This function verifies reachability of one given nexthop, which can be
  * numbered or unnumbered, IPv4 or IPv6. The result is unconditionally stored
- * in nexthop->flags field. If the 4th parameter, 'set', is non-zero,
- * nexthop->ifindex will be updated appropriately as well.
- * An existing route map can turn (otherwise active) nexthop into inactive, but
- * not vice versa.
+ * in nexthop->flags field. The nexthop->ifindex will be updated
+ * appropriately as well.  An existing route map can turn
+ * (otherwise active) nexthop into inactive, but not vice versa.
  *
  * The return value is the final value of 'ACTIVE' flag.
  */
-
 static unsigned nexthop_active_check(struct route_node *rn,
                                     struct route_entry *re,
-                                    struct nexthop *nexthop, bool set)
+                                    struct nexthop *nexthop)
 {
        struct interface *ifp;
        route_map_result_t ret = RMAP_MATCH;
@@ -857,14 +839,14 @@ static unsigned nexthop_active_check(struct route_node *rn,
        case NEXTHOP_TYPE_IPV4:
        case NEXTHOP_TYPE_IPV4_IFINDEX:
                family = AFI_IP;
-               if (nexthop_active(AFI_IP, re, nexthop, set, rn))
+               if (nexthop_active(AFI_IP, re, nexthop, rn))
                        SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
                else
                        UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
                break;
        case NEXTHOP_TYPE_IPV6:
                family = AFI_IP6;
-               if (nexthop_active(AFI_IP6, re, nexthop, set, rn))
+               if (nexthop_active(AFI_IP6, re, nexthop, rn))
                        SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
                else
                        UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
@@ -881,7 +863,7 @@ static unsigned nexthop_active_check(struct route_node *rn,
                        else
                                UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
                } else {
-                       if (nexthop_active(AFI_IP6, re, nexthop, set, rn))
+                       if (nexthop_active(AFI_IP6, re, nexthop, rn))
                                SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
                        else
                                UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
@@ -946,25 +928,21 @@ static unsigned nexthop_active_check(struct route_node *rn,
        return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
 }
 
-/* Iterate over all nexthops of the given RIB entry and refresh their
+/*
+ * Iterate over all nexthops of the given RIB entry and refresh their
  * ACTIVE flag. re->nexthop_active_num is updated accordingly. If any
  * nexthop is found to toggle the ACTIVE flag, the whole re structure
- * is flagged with ROUTE_ENTRY_CHANGED. The 4th 'set' argument is
- * transparently passed to nexthop_active_check().
+ * is flagged with ROUTE_ENTRY_CHANGED.
  *
  * Return value is the new number of active nexthops.
  */
-
-static int nexthop_active_update(struct route_node *rn, struct route_entry *re,
-                                bool set)
+static int nexthop_active_update(struct route_node *rn, struct route_entry *re)
 {
        struct nexthop *nexthop;
        union g_addr prev_src;
-       unsigned int prev_active, new_active, old_num_nh;
+       unsigned int prev_active, new_active;
        ifindex_t prev_index;
 
-       old_num_nh = re->nexthop_active_num;
-
        re->nexthop_active_num = 0;
        UNSET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
 
@@ -980,7 +958,7 @@ static int nexthop_active_update(struct route_node *rn, struct route_entry *re,
                 * a multipath perpsective should not be a data plane
                 * decision point.
                 */
-               new_active = nexthop_active_check(rn, re, nexthop, set);
+               new_active = nexthop_active_check(rn, re, nexthop);
                if (new_active && re->nexthop_active_num >= multipath_num) {
                        UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
                        new_active = 0;
@@ -996,19 +974,13 @@ static int nexthop_active_update(struct route_node *rn, struct route_entry *re,
                    || ((nexthop->type >= NEXTHOP_TYPE_IPV6
                         && nexthop->type < NEXTHOP_TYPE_BLACKHOLE)
                        && !(IPV6_ADDR_SAME(&prev_src.ipv6,
-                                           &nexthop->rmap_src.ipv6)))) {
+                                           &nexthop->rmap_src.ipv6)))
+                   || CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED)) {
                        SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
                        SET_FLAG(re->status, ROUTE_ENTRY_NEXTHOPS_CHANGED);
                }
        }
 
-       if (old_num_nh != re->nexthop_active_num)
-               SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
-
-       if (CHECK_FLAG(re->status, ROUTE_ENTRY_CHANGED)) {
-               SET_FLAG(re->status, ROUTE_ENTRY_NEXTHOPS_CHANGED);
-       }
-
        return re->nexthop_active_num;
 }
 
@@ -1354,7 +1326,7 @@ static void rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn,
 
        /* Update real nexthop. This may actually determine if nexthop is active
         * or not. */
-       if (!nexthop_active_update(rn, new, true)) {
+       if (!nexthop_group_active_nexthop_num(&new->ng)) {
                UNSET_FLAG(new->status, ROUTE_ENTRY_CHANGED);
                return;
        }
@@ -1401,8 +1373,7 @@ static void rib_process_del_fib(struct zebra_vrf *zvrf, struct route_node *rn,
         * down, causing the kernel to delete routes without sending DELROUTE
         * notifications
         */
-       if (!nexthop_active_update(rn, old, true) &&
-           (RIB_KERNEL_ROUTE(old)))
+       if (RIB_KERNEL_ROUTE(old))
                SET_FLAG(old->status, ROUTE_ENTRY_REMOVED);
        else
                UNSET_FLAG(old->status, ROUTE_ENTRY_CHANGED);
@@ -1424,7 +1395,7 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf,
 
                /* Update the nexthop; we could determine here that nexthop is
                 * inactive. */
-               if (nexthop_active_update(rn, new, true))
+               if (nexthop_group_active_nexthop_num(&new->ng))
                        nh_active = 1;
 
                /* If nexthop is active, install the selected route, if
@@ -1509,11 +1480,8 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf,
        }
 
        /* Update prior route. */
-       if (new != old) {
-               /* Set real nexthop. */
-               nexthop_active_update(rn, old, true);
+       if (new != old)
                UNSET_FLAG(old->status, ROUTE_ENTRY_CHANGED);
-       }
 
        /* Clear changed flag. */
        UNSET_FLAG(new->status, ROUTE_ENTRY_CHANGED);
@@ -1643,38 +1611,30 @@ static void rib_process(struct route_node *rn)
 
                /* Skip unreachable nexthop. */
                /* This first call to nexthop_active_update is merely to
-                * determine if
-                * there's any change to nexthops associated with this RIB
-                * entry. Now,
-                * rib_process() can be invoked due to an external event such as
-                * link
-                * down or due to next-hop-tracking evaluation. In the latter
-                * case,
+                * determine if there's any change to nexthops associated
+                * with this RIB entry. Now, rib_process() can be invoked due
+                * to an external event such as link down or due to
+                * next-hop-tracking evaluation. In the latter case,
                 * a decision has already been made that the NHs have changed.
-                * So, no
-                * need to invoke a potentially expensive call again. Further,
-                * since
-                * the change might be in a recursive NH which is not caught in
-                * the nexthop_active_update() code. Thus, we might miss changes
-                * to
-                * recursive NHs.
+                * So, no need to invoke a potentially expensive call again.
+                * Further, since the change might be in a recursive NH which
+                * is not caught in the nexthop_active_update() code. Thus, we
+                * might miss changes to recursive NHs.
                 */
-               if (!CHECK_FLAG(re->status, ROUTE_ENTRY_CHANGED)
-                   && !nexthop_active_update(rn, re, false)) {
+               if (CHECK_FLAG(re->status, ROUTE_ENTRY_CHANGED)
+                   && !nexthop_active_update(rn, re)) {
                        if (re->type == ZEBRA_ROUTE_TABLE) {
                                /* XXX: HERE BE DRAGONS!!!!!
                                 * In all honesty, I have not yet figured out
-                                * what this part
-                                * does or why the ROUTE_ENTRY_CHANGED test
-                                * above is correct
+                                * what this part does or why the
+                                * ROUTE_ENTRY_CHANGED test above is correct
                                 * or why we need to delete a route here, and
-                                * also not whether
-                                * this concerns both selected and fib route, or
-                                * only selected
-                                * or only fib */
-                               /* This entry was denied by the 'ip protocol
-                                * table' route-map, we
-                                * need to delete it */
+                                * also not whether this concerns both selected
+                                * and fib route, or only selected
+                                * or only fib
+                                *
+                                * This entry was denied by the 'ip protocol
+                                * table' route-map, we need to delete it */
                                if (re != old_selected) {
                                        if (IS_ZEBRA_DEBUG_RIB)
                                                zlog_debug(
@@ -1751,10 +1711,8 @@ static void rib_process(struct route_node *rn)
        /* Update SELECTED entry */
        if (old_selected != new_selected || selected_changed) {
 
-               if (new_selected && new_selected != new_fib) {
-                       nexthop_active_update(rn, new_selected, true);
+               if (new_selected && new_selected != new_fib)
                        UNSET_FLAG(new_selected->status, ROUTE_ENTRY_CHANGED);
-               }
 
                if (new_selected)
                        SET_FLAG(new_selected->flags, ZEBRA_FLAG_SELECTED);
@@ -2613,8 +2571,8 @@ void _route_entry_dump(const char *func, union prefixconstptr pp,
                                  INET6_ADDRSTRLEN);
                        break;
                }
-               zlog_debug("%s: %s %s[%u] vrf %s(%u) with flags %s%s%s", func,
-                          (nexthop->rparent ? "  NH" : "NH"), straddr,
+               zlog_debug("%s: %s %s[%u] vrf %s(%u) with flags %s%s%s%s%s%s",
+                          func, (nexthop->rparent ? "  NH" : "NH"), straddr,
                           nexthop->ifindex, vrf ? vrf->name : "Unknown",
                           nexthop->vrf_id,
                           (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)
@@ -2624,7 +2582,16 @@ void _route_entry_dump(const char *func, union prefixconstptr pp,
                                    ? "FIB "
                                    : ""),
                           (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)
-                                   ? "RECURSIVE"
+                                   ? "RECURSIVE "
+                                   : ""),
+                          (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)
+                                   ? "ONLINK "
+                                   : ""),
+                          (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_MATCHED)
+                                   ? "MATCHED "
+                                   : ""),
+                          (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE)
+                                   ? "DUPLICATE "
                                    : ""));
        }
        zlog_debug("%s: dump complete", func);
@@ -2814,6 +2781,8 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
                if (IS_ZEBRA_DEBUG_RIB_DETAILED)
                        route_entry_dump(p, src_p, re);
        }
+
+       SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
        rib_addnode(rn, re, 1);
        ret = 1;
 
index 040043146a1fb2b153a8312f725469eb5e4c6db0..220a8006d011c8cd08d1c5dafbe778a4e9adf37b 100644 (file)
@@ -377,6 +377,20 @@ void zebra_deregister_rnh_pseudowire(vrf_id_t vrf_id, struct zebra_pw *pw)
        zebra_delete_rnh(rnh, RNH_NEXTHOP_TYPE);
 }
 
+/* Clear the NEXTHOP_FLAG_RNH_FILTERED flags on all nexthops
+ */
+static void zebra_rnh_clear_nexthop_rnh_filters(struct route_entry *re)
+{
+       struct nexthop *nexthop;
+
+       if (re) {
+               for (nexthop = re->ng.nexthop; nexthop;
+                    nexthop = nexthop->next) {
+                       UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_RNH_FILTERED);
+               }
+       }
+}
+
 /* Apply the NHT route-map for a client to the route (and nexthops)
  * resolving a NH.
  */
@@ -393,11 +407,11 @@ static int zebra_rnh_apply_nht_rmap(afi_t afi, struct zebra_vrf *zvrf,
                     nexthop = nexthop->next) {
                        ret = zebra_nht_route_map_check(
                                afi, proto, &prn->p, zvrf, re, nexthop);
-                       if (ret != RMAP_DENYMATCH) {
-                               SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+                       if (ret != RMAP_DENYMATCH)
                                at_least_one++; /* at least one valid NH */
-                       } else {
-                               UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+                       else {
+                               SET_FLAG(nexthop->flags,
+                                               NEXTHOP_FLAG_RNH_FILTERED);
                        }
                }
        }
@@ -546,6 +560,7 @@ static void zebra_rnh_notify_protocol_clients(struct zebra_vrf *zvrf, afi_t afi,
                         * this
                         * nexthop to see if it is filtered or not.
                         */
+                       zebra_rnh_clear_nexthop_rnh_filters(re);
                        num_resolving_nh = zebra_rnh_apply_nht_rmap(
                                afi, zvrf, prn, re, client->proto);
                        if (num_resolving_nh)
@@ -572,6 +587,9 @@ static void zebra_rnh_notify_protocol_clients(struct zebra_vrf *zvrf, afi_t afi,
 
                send_client(rnh, client, RNH_NEXTHOP_TYPE, zvrf->vrf->vrf_id);
        }
+
+       if (re)
+               zebra_rnh_clear_nexthop_rnh_filters(re);
 }
 
 static void zebra_rnh_process_pbr_tables(afi_t afi, struct route_node *nrn,
@@ -631,7 +649,10 @@ static bool rnh_nexthop_valid(const struct route_entry *re,
                              const struct nexthop *nh)
 {
        return (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)
-               && CHECK_FLAG(nh->flags, NEXTHOP_FLAG_ACTIVE));
+               && CHECK_FLAG(nh->flags, NEXTHOP_FLAG_ACTIVE)
+               && !CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE)
+               && !CHECK_FLAG(nh->flags, NEXTHOP_FLAG_DUPLICATE)
+               && !CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RNH_FILTERED));
 }
 
 /*
index 7113c160ac2c4b9a020cd6b9cce4d2af662756cb..c7a64d300a8e3492e84429feb0ed54e8cd089248 100644 (file)
@@ -130,6 +130,9 @@ struct zebra_vrf {
        /* l3-vni info */
        vni_t l3vni;
 
+       /* pim mroutes installed for vxlan flooding */
+       struct hash *vxlan_sg_table;
+
        bool dup_addr_detect;
 
        int dad_time;
index 3a8426e77257ac922d14610cb3d97e3ab5e8c0fd..4f6e4e85974de0e84df7a74abbf5afe1b61e9ee7 100644 (file)
@@ -58,8 +58,19 @@ DEFINE_MTYPE_STATIC(ZEBRA, ZL3VNI, "L3 VNI hash");
 DEFINE_MTYPE_STATIC(ZEBRA, ZVNI_VTEP, "VNI remote VTEP");
 DEFINE_MTYPE_STATIC(ZEBRA, MAC, "VNI MAC");
 DEFINE_MTYPE_STATIC(ZEBRA, NEIGH, "VNI Neighbor");
+DEFINE_MTYPE_STATIC(ZEBRA, ZVXLAN_SG, "zebra VxLAN multicast group");
 
 /* definitions */
+/* PMSI strings. */
+#define VXLAN_FLOOD_STR_NO_INFO "-"
+#define VXLAN_FLOOD_STR_DEFAULT VXLAN_FLOOD_STR_NO_INFO
+static const struct message zvtep_flood_str[] = {
+       {VXLAN_FLOOD_DISABLED, VXLAN_FLOOD_STR_NO_INFO},
+       {VXLAN_FLOOD_PIM_SM, "PIM-SM"},
+       {VXLAN_FLOOD_HEAD_END_REPL, "HER"},
+       {0}
+};
+
 
 /* static function declarations */
 static int ip_prefix_send_to_client(vrf_id_t vrf_id, struct prefix *p,
@@ -167,10 +178,11 @@ static int zvni_send_del_to_client(vni_t vni);
 static void zvni_build_hash_table(void);
 static int zvni_vtep_match(struct in_addr *vtep_ip, zebra_vtep_t *zvtep);
 static zebra_vtep_t *zvni_vtep_find(zebra_vni_t *zvni, struct in_addr *vtep_ip);
-static zebra_vtep_t *zvni_vtep_add(zebra_vni_t *zvni, struct in_addr *vtep_ip);
+static zebra_vtep_t *zvni_vtep_add(zebra_vni_t *zvni, struct in_addr *vtep_ip,
+               int flood_control);
 static int zvni_vtep_del(zebra_vni_t *zvni, zebra_vtep_t *zvtep);
 static int zvni_vtep_del_all(zebra_vni_t *zvni, int uninstall);
-static int zvni_vtep_install(zebra_vni_t *zvni, struct in_addr *vtep_ip);
+static int zvni_vtep_install(zebra_vni_t *zvni, zebra_vtep_t *zvtep);
 static int zvni_vtep_uninstall(zebra_vni_t *zvni, struct in_addr *vtep_ip);
 static int zvni_del_macip_for_intf(struct interface *ifp, zebra_vni_t *zvni);
 static int zvni_add_macip_for_intf(struct interface *ifp, zebra_vni_t *zvni);
@@ -201,6 +213,17 @@ static void zebra_vxlan_dup_addr_detect_for_mac(struct zebra_vrf *zvrf,
                                                bool do_dad,
                                                bool *is_dup_detect,
                                                bool is_local);
+static unsigned int zebra_vxlan_sg_hash_key_make(void *p);
+static bool zebra_vxlan_sg_hash_eq(const void *p1, const void *p2);
+static void zebra_vxlan_sg_do_deref(struct zebra_vrf *zvrf,
+               struct in_addr sip, struct in_addr mcast_grp);
+static zebra_vxlan_sg_t *zebra_vxlan_sg_do_ref(struct zebra_vrf *vrf,
+                               struct in_addr sip, struct in_addr mcast_grp);
+static void zebra_vxlan_sg_deref(struct in_addr local_vtep_ip,
+                               struct in_addr mcast_grp);
+static void zebra_vxlan_sg_ref(struct in_addr local_vtep_ip,
+                               struct in_addr mcast_grp);
+static void zebra_vxlan_sg_cleanup(struct hash_backet *backet, void *arg);
 
 /* Private functions */
 static int host_rb_entry_compare(const struct host_rb_entry *hle1,
@@ -1858,12 +1881,16 @@ static void zvni_print(zebra_vni_t *zvni, void **ctxt)
                vty_out(vty, " VxLAN ifIndex: %u\n", zvni->vxlan_if->ifindex);
                vty_out(vty, " Local VTEP IP: %s\n",
                        inet_ntoa(zvni->local_vtep_ip));
+               vty_out(vty, " Mcast group: %s\n",
+                               inet_ntoa(zvni->mcast_grp));
        } else {
                json_object_string_add(json, "vxlanInterface",
                                       zvni->vxlan_if->name);
                json_object_int_add(json, "ifindex", zvni->vxlan_if->ifindex);
                json_object_string_add(json, "vtepIp",
                                       inet_ntoa(zvni->local_vtep_ip));
+               json_object_string_add(json, "mcastGroup",
+                               inet_ntoa(zvni->mcast_grp));
                json_object_string_add(json, "advertiseGatewayMacip",
                                       zvni->advertise_gw_macip ? "Yes" : "No");
                json_object_int_add(json, "numMacs", num_macs);
@@ -1878,14 +1905,19 @@ static void zvni_print(zebra_vni_t *zvni, void **ctxt)
                else
                        json_vtep_list = json_object_new_array();
                for (zvtep = zvni->vteps; zvtep; zvtep = zvtep->next) {
-                       if (json == NULL)
-                               vty_out(vty, "  %s\n",
-                                       inet_ntoa(zvtep->vtep_ip));
-                       else {
+                       const char *flood_str = lookup_msg(zvtep_flood_str,
+                                       zvtep->flood_control,
+                                       VXLAN_FLOOD_STR_DEFAULT);
+
+                       if (json == NULL) {
+                               vty_out(vty, "  %s flood: %s\n",
+                                               inet_ntoa(zvtep->vtep_ip),
+                                               flood_str);
+                       } else {
                                json_ip_str = json_object_new_string(
-                                       inet_ntoa(zvtep->vtep_ip));
+                                               inet_ntoa(zvtep->vtep_ip));
                                json_object_array_add(json_vtep_list,
-                                                     json_ip_str);
+                                               json_ip_str);
                        }
                }
                if (json)
@@ -3882,6 +3914,9 @@ static int zvni_del(zebra_vni_t *zvni)
 
        zvni->vxlan_if = NULL;
 
+       /* Remove references to the BUM mcast grp */
+       zebra_vxlan_sg_deref(zvni->local_vtep_ip, zvni->mcast_grp);
+
        /* Free the neighbor hash table. */
        hash_free(zvni->neigh_table);
        zvni->neigh_table = NULL;
@@ -3916,6 +3951,7 @@ static int zvni_send_add_to_client(zebra_vni_t *zvni)
        stream_putl(s, zvni->vni);
        stream_put_in_addr(s, &zvni->local_vtep_ip);
        stream_put(s, &zvni->vrf_id, sizeof(vrf_id_t)); /* tenant vrf */
+       stream_put_in_addr(s, &zvni->mcast_grp);
 
        /* Write packet size. */
        stream_putw_at(s, 0, stream_get_endp(s));
@@ -4038,7 +4074,15 @@ static void zvni_build_hash_table(void)
                                return;
                        }
 
-                       zvni->local_vtep_ip = vxl->vtep_ip;
+                       if (zvni->local_vtep_ip.s_addr != vxl->vtep_ip.s_addr ||
+                               zvni->mcast_grp.s_addr != vxl->mcast_grp.s_addr) {
+                               zebra_vxlan_sg_deref(zvni->local_vtep_ip,
+                                       zvni->mcast_grp);
+                               zebra_vxlan_sg_ref(vxl->vtep_ip,
+                                       vxl->mcast_grp);
+                               zvni->local_vtep_ip = vxl->vtep_ip;
+                               zvni->mcast_grp = vxl->mcast_grp;
+                       }
                        zvni->vxlan_if = ifp;
                        vlan_if = zvni_map_to_svi(vxl->access_vlan,
                                                  zif->brslave_info.br_if);
@@ -4086,13 +4130,16 @@ static zebra_vtep_t *zvni_vtep_find(zebra_vni_t *zvni, struct in_addr *vtep_ip)
 /*
  * Add remote VTEP to VNI hash table.
  */
-static zebra_vtep_t *zvni_vtep_add(zebra_vni_t *zvni, struct in_addr *vtep_ip)
+static zebra_vtep_t *zvni_vtep_add(zebra_vni_t *zvni, struct in_addr *vtep_ip,
+               int flood_control)
+
 {
        zebra_vtep_t *zvtep;
 
        zvtep = XCALLOC(MTYPE_ZVNI_VTEP, sizeof(zebra_vtep_t));
 
        zvtep->vtep_ip = *vtep_ip;
+       zvtep->flood_control = flood_control;
 
        if (zvni->vteps)
                zvni->vteps->prev = zvtep;
@@ -4142,12 +4189,15 @@ static int zvni_vtep_del_all(zebra_vni_t *zvni, int uninstall)
 }
 
 /*
- * Install remote VTEP into the kernel.
+ * Install remote VTEP into the kernel if the remote VTEP has asked
+ * for head-end-replication.
  */
-static int zvni_vtep_install(zebra_vni_t *zvni, struct in_addr *vtep_ip)
+static int zvni_vtep_install(zebra_vni_t *zvni, zebra_vtep_t *zvtep)
 {
-       if (is_vxlan_flooding_head_end())
-               return kernel_add_vtep(zvni->vni, zvni->vxlan_if, vtep_ip);
+       if (is_vxlan_flooding_head_end() &&
+                       (zvtep->flood_control == VXLAN_FLOOD_HEAD_END_REPL))
+               return kernel_add_vtep(zvni->vni, zvni->vxlan_if,
+                               &zvtep->vtep_ip);
        return 0;
 }
 
@@ -4181,7 +4231,7 @@ static void zvni_handle_flooding_remote_vteps(struct hash_bucket *bucket,
 
        for (zvtep = zvni->vteps; zvtep; zvtep = zvtep->next) {
                if (is_vxlan_flooding_head_end())
-                       zvni_vtep_install(zvni, &zvtep->vtep_ip);
+                       zvni_vtep_install(zvni, zvtep);
                else
                        zvni_vtep_uninstall(zvni, &zvtep->vtep_ip);
        }
@@ -5159,7 +5209,8 @@ static void process_remote_macip_add(vni_t vni,
         */
        zvtep = zvni_vtep_find(zvni, &vtep_ip);
        if (!zvtep) {
-               if (zvni_vtep_add(zvni, &vtep_ip) == NULL) {
+               zvtep = zvni_vtep_add(zvni, &vtep_ip, VXLAN_FLOOD_DISABLED);
+               if (!zvtep) {
                        flog_err(
                                EC_ZEBRA_VTEP_ADD_FAILED,
                                "Failed to add remote VTEP, VNI %u zvni %p upon remote MACIP ADD",
@@ -5167,7 +5218,7 @@ static void process_remote_macip_add(vni_t vni,
                        return;
                }
 
-               zvni_vtep_install(zvni, &vtep_ip);
+               zvni_vtep_install(zvni, zvtep);
        }
 
        sticky = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
@@ -7874,6 +7925,8 @@ void zebra_vxlan_remote_vtep_add(ZAPI_HANDLER_ARGS)
        zebra_vni_t *zvni;
        struct interface *ifp;
        struct zebra_if *zif;
+       int flood_control;
+       zebra_vtep_t *zvtep;
 
        if (!is_evpn_enabled()) {
                zlog_debug(
@@ -7895,12 +7948,13 @@ void zebra_vxlan_remote_vtep_add(ZAPI_HANDLER_ARGS)
                STREAM_GETL(s, vni);
                l += 4;
                STREAM_GET(&vtep_ip.s_addr, s, IPV4_MAX_BYTELEN);
+               STREAM_GETL(s, flood_control);
                l += IPV4_MAX_BYTELEN;
 
                if (IS_ZEBRA_DEBUG_VXLAN)
-                       zlog_debug("Recv VTEP_ADD %s VNI %u from %s",
-                                  inet_ntoa(vtep_ip), vni,
-                                  zebra_route_string(client->proto));
+                       zlog_debug("Recv VTEP_ADD %s VNI %u flood %d from %s",
+                                       inet_ntoa(vtep_ip), vni, flood_control,
+                                       zebra_route_string(client->proto));
 
                /* Locate VNI hash entry - expected to exist. */
                zvni = zvni_lookup(vni);
@@ -7927,19 +7981,31 @@ void zebra_vxlan_remote_vtep_add(ZAPI_HANDLER_ARGS)
                if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
                        continue;
 
-               /* If the remote VTEP already exists,
-                  there's nothing more to do. */
-               if (zvni_vtep_find(zvni, &vtep_ip))
-                       continue;
-
-               if (zvni_vtep_add(zvni, &vtep_ip) == NULL) {
-                       flog_err(EC_ZEBRA_VTEP_ADD_FAILED,
-                                "Failed to add remote VTEP, VNI %u zvni %p",
-                                vni, zvni);
-                       continue;
+               zvtep = zvni_vtep_find(zvni, &vtep_ip);
+               if (zvtep) {
+                       /* If the remote VTEP already exists check if
+                        * the flood mode has changed
+                        */
+                       if (zvtep->flood_control != flood_control) {
+                               if (zvtep->flood_control
+                                               == VXLAN_FLOOD_DISABLED)
+                                       /* old mode was head-end-replication but
+                                        * is no longer; get rid of the HER fdb
+                                        * entry installed before
+                                        */
+                                       zvni_vtep_uninstall(zvni, &vtep_ip);
+                               zvtep->flood_control = flood_control;
+                               zvni_vtep_install(zvni, zvtep);
+                       }
+               } else {
+                       zvtep = zvni_vtep_add(zvni, &vtep_ip, flood_control);
+                       if (zvtep)
+                               zvni_vtep_install(zvni, zvtep);
+                       else
+                               flog_err(EC_ZEBRA_VTEP_ADD_FAILED,
+                                       "Failed to add remote VTEP, VNI %u zvni %p",
+                                       vni, zvni);
                }
-
-               zvni_vtep_install(zvni, &vtep_ip);
        }
 
 stream_failure:
@@ -8476,7 +8542,14 @@ int zebra_vxlan_if_update(struct interface *ifp, uint16_t chgflags)
                        zvni_mac_del_all(zvni, 0, 1, DEL_LOCAL_MAC);
                }
 
-               zvni->local_vtep_ip = vxl->vtep_ip;
+               if (zvni->local_vtep_ip.s_addr != vxl->vtep_ip.s_addr ||
+                       zvni->mcast_grp.s_addr != vxl->mcast_grp.s_addr) {
+                       zebra_vxlan_sg_deref(zvni->local_vtep_ip,
+                               zvni->mcast_grp);
+                       zebra_vxlan_sg_ref(vxl->vtep_ip, vxl->mcast_grp);
+                       zvni->local_vtep_ip = vxl->vtep_ip;
+                       zvni->mcast_grp = vxl->mcast_grp;
+               }
                zvni->vxlan_if = ifp;
 
                /* Take further actions needed.
@@ -8488,7 +8561,9 @@ int zebra_vxlan_if_update(struct interface *ifp, uint16_t chgflags)
 
                /* Inform BGP, if there is a change of interest. */
                if (chgflags
-                   & (ZEBRA_VXLIF_MASTER_CHANGE | ZEBRA_VXLIF_LOCAL_IP_CHANGE))
+                       & (ZEBRA_VXLIF_MASTER_CHANGE |
+                          ZEBRA_VXLIF_LOCAL_IP_CHANGE |
+                          ZEBRA_VXLIF_MCAST_GRP_CHANGE))
                        zvni_send_add_to_client(zvni);
 
                /* If there is a valid new master or a VLAN mapping change,
@@ -8578,7 +8653,14 @@ int zebra_vxlan_if_add(struct interface *ifp)
                        }
                }
 
-               zvni->local_vtep_ip = vxl->vtep_ip;
+               if (zvni->local_vtep_ip.s_addr != vxl->vtep_ip.s_addr ||
+                       zvni->mcast_grp.s_addr != vxl->mcast_grp.s_addr) {
+                       zebra_vxlan_sg_deref(zvni->local_vtep_ip,
+                               zvni->mcast_grp);
+                       zebra_vxlan_sg_ref(vxl->vtep_ip, vxl->mcast_grp);
+                       zvni->local_vtep_ip = vxl->vtep_ip;
+                       zvni->mcast_grp = vxl->mcast_grp;
+               }
                zvni->vxlan_if = ifp;
                vlan_if = zvni_map_to_svi(vxl->access_vlan,
                                          zif->brslave_info.br_if);
@@ -8589,15 +8671,24 @@ int zebra_vxlan_if_add(struct interface *ifp)
                                listnode_add_sort(zl3vni->l2vnis, zvni);
                }
 
-               if (IS_ZEBRA_DEBUG_VXLAN)
+               if (IS_ZEBRA_DEBUG_VXLAN) {
+                       char addr_buf1[INET_ADDRSTRLEN];
+                       char addr_buf2[INET_ADDRSTRLEN];
+
+                       inet_ntop(AF_INET, &vxl->vtep_ip,
+                                       addr_buf1, INET_ADDRSTRLEN);
+                       inet_ntop(AF_INET, &vxl->mcast_grp,
+                                       addr_buf2, INET_ADDRSTRLEN);
+
                        zlog_debug(
-                               "Add L2-VNI %u VRF %s intf %s(%u) VLAN %u local IP %s master %u",
+                               "Add L2-VNI %u VRF %s intf %s(%u) VLAN %u local IP %s mcast_grp %s master %u",
                                vni,
                                vlan_if ? vrf_id_to_name(vlan_if->vrf_id)
                                        : VRF_DEFAULT_NAME,
                                ifp->name, ifp->ifindex, vxl->access_vlan,
-                               inet_ntoa(vxl->vtep_ip),
+                               addr_buf1, addr_buf2,
                                zif->brslave_info.bridge_ifindex);
+               }
 
                /* If down or not mapped to a bridge, we're done. */
                if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
@@ -8688,6 +8779,13 @@ int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, vni_t vni,
                        return -1;
                }
 
+               if (zvrf->l3vni != vni) {
+                       snprintf(err, err_str_sz,
+                                       "VNI %d doesn't exist in VRF: %s",
+                                       vni, zvrf->vrf->name);
+                       return -1;
+               }
+
                if (filter && !CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY)) {
                        snprintf(err, ERR_STR_SZ,
                                 "prefix-routes-only is not set for the vni");
@@ -9144,6 +9242,8 @@ void zebra_vxlan_init_tables(struct zebra_vrf *zvrf)
                return;
        zvrf->vni_table = hash_create(vni_hash_keymake, vni_hash_cmp,
                                      "Zebra VRF VNI Table");
+       zvrf->vxlan_sg_table = hash_create(zebra_vxlan_sg_hash_key_make,
+                       zebra_vxlan_sg_hash_eq, "Zebra VxLAN SG Table");
 }
 
 /* Cleanup VNI info, but don't free the table. */
@@ -9152,6 +9252,7 @@ void zebra_vxlan_cleanup_tables(struct zebra_vrf *zvrf)
        if (!zvrf)
                return;
        hash_iterate(zvrf->vni_table, zvni_cleanup_all, zvrf);
+       hash_iterate(zvrf->vxlan_sg_table, zebra_vxlan_sg_cleanup, NULL);
 }
 
 /* Close all VNI handling */
@@ -9311,3 +9412,221 @@ static int zebra_vxlan_dad_mac_auto_recovery_exp(struct thread *t)
 
        return 0;
 }
+
+/************************** vxlan SG cache management ************************/
+/* Inform PIM about the mcast group */
+static int zebra_vxlan_sg_send(struct prefix_sg *sg,
+                       char *sg_str, uint16_t cmd)
+{
+       struct zserv *client = NULL;
+       struct stream *s = NULL;
+
+       client = zserv_find_client(ZEBRA_ROUTE_PIM, 0);
+       if (!client)
+               return 0;
+
+       s = stream_new(ZEBRA_MAX_PACKET_SIZ);
+
+       zclient_create_header(s, cmd, VRF_DEFAULT);
+       stream_putl(s, IPV4_MAX_BYTELEN);
+       stream_put(s, &sg->src.s_addr, IPV4_MAX_BYTELEN);
+       stream_put(s, &sg->grp.s_addr, IPV4_MAX_BYTELEN);
+
+       /* Write packet size. */
+       stream_putw_at(s, 0, stream_get_endp(s));
+
+       if (IS_ZEBRA_DEBUG_VXLAN)
+               zlog_debug(
+                       "Send %s %s to %s",
+                       (cmd == ZEBRA_VXLAN_SG_ADD) ? "add" : "del", sg_str,
+                       zebra_route_string(client->proto));
+
+       if (cmd == ZEBRA_VXLAN_SG_ADD)
+               client->vxlan_sg_add_cnt++;
+       else
+               client->vxlan_sg_del_cnt++;
+
+       return zserv_send_message(client, s);
+}
+
+static unsigned int zebra_vxlan_sg_hash_key_make(void *p)
+{
+       zebra_vxlan_sg_t *vxlan_sg = p;
+
+       return (jhash_2words(vxlan_sg->sg.src.s_addr,
+                               vxlan_sg->sg.grp.s_addr, 0));
+}
+
+static bool zebra_vxlan_sg_hash_eq(const void *p1, const void *p2)
+{
+       const zebra_vxlan_sg_t *sg1 = p1;
+       const zebra_vxlan_sg_t *sg2 = p2;
+
+       return ((sg1->sg.src.s_addr == sg2->sg.src.s_addr)
+               && (sg1->sg.grp.s_addr == sg2->sg.grp.s_addr));
+}
+
+static zebra_vxlan_sg_t *zebra_vxlan_sg_new(struct zebra_vrf *zvrf,
+               struct prefix_sg *sg)
+{
+       zebra_vxlan_sg_t *vxlan_sg;
+
+       vxlan_sg = XCALLOC(MTYPE_ZVXLAN_SG, sizeof(*vxlan_sg));
+
+       vxlan_sg->zvrf = zvrf;
+       vxlan_sg->sg = *sg;
+       prefix_sg2str(sg, vxlan_sg->sg_str);
+
+       vxlan_sg = hash_get(zvrf->vxlan_sg_table, vxlan_sg, hash_alloc_intern);
+
+       if (IS_ZEBRA_DEBUG_VXLAN)
+               zlog_debug("vxlan SG %s created", vxlan_sg->sg_str);
+
+       return vxlan_sg;
+}
+
+static zebra_vxlan_sg_t *zebra_vxlan_sg_find(struct zebra_vrf *zvrf,
+                                           struct prefix_sg *sg)
+{
+       zebra_vxlan_sg_t lookup;
+
+       lookup.sg = *sg;
+       return hash_lookup(zvrf->vxlan_sg_table, &lookup);
+}
+
+static zebra_vxlan_sg_t *zebra_vxlan_sg_add(struct zebra_vrf *zvrf,
+                                          struct prefix_sg *sg)
+{
+       zebra_vxlan_sg_t *vxlan_sg;
+       zebra_vxlan_sg_t *parent = NULL;
+       struct in_addr sip;
+
+       vxlan_sg = zebra_vxlan_sg_find(zvrf, sg);
+       if (vxlan_sg)
+               return vxlan_sg;
+
+       /* create a *G entry for every BUM group implicitly -
+        * 1. The SG entry is used by pimd to setup the vxlan-origination-mroute
+        * 2. the XG entry is used by pimd to setup the
+        * vxlan-termination-mroute
+        */
+       if (sg->src.s_addr) {
+               memset(&sip, 0, sizeof(sip));
+               parent = zebra_vxlan_sg_do_ref(zvrf, sip, sg->grp);
+               if (!parent)
+                       return NULL;
+       }
+
+       vxlan_sg = zebra_vxlan_sg_new(zvrf, sg);
+       if (!vxlan_sg) {
+               if (parent)
+                       zebra_vxlan_sg_do_deref(zvrf, sip, sg->grp);
+               return vxlan_sg;
+       }
+
+       zebra_vxlan_sg_send(sg, vxlan_sg->sg_str, ZEBRA_VXLAN_SG_ADD);
+
+       return vxlan_sg;
+}
+
+static void zebra_vxlan_sg_del(zebra_vxlan_sg_t *vxlan_sg)
+{
+       struct in_addr sip;
+       struct zebra_vrf *zvrf;
+
+       zvrf = vrf_info_lookup(VRF_DEFAULT);
+       if (!zvrf)
+               return;
+
+       /* On SG entry deletion remove the reference to its parent XG
+        * entry
+        */
+       if (vxlan_sg->sg.src.s_addr) {
+               memset(&sip, 0, sizeof(sip));
+               zebra_vxlan_sg_do_deref(zvrf, sip, vxlan_sg->sg.grp);
+       }
+
+       zebra_vxlan_sg_send(&vxlan_sg->sg, vxlan_sg->sg_str,
+               ZEBRA_VXLAN_SG_DEL);
+
+       hash_release(vxlan_sg->zvrf->vxlan_sg_table, vxlan_sg);
+
+       if (IS_ZEBRA_DEBUG_VXLAN)
+               zlog_debug("VXLAN SG %s deleted", vxlan_sg->sg_str);
+
+       XFREE(MTYPE_ZVXLAN_SG, vxlan_sg);
+}
+
+static void zebra_vxlan_sg_do_deref(struct zebra_vrf *zvrf,
+               struct in_addr sip, struct in_addr mcast_grp)
+{
+       zebra_vxlan_sg_t *vxlan_sg;
+       struct prefix_sg sg;
+
+       sg.family = AF_INET;
+       sg.prefixlen = IPV4_MAX_BYTELEN;
+       sg.src = sip;
+       sg.grp = mcast_grp;
+       vxlan_sg = zebra_vxlan_sg_find(zvrf, &sg);
+       if (!vxlan_sg)
+               return;
+
+       if (vxlan_sg->ref_cnt)
+               --vxlan_sg->ref_cnt;
+
+       if (!vxlan_sg->ref_cnt)
+               zebra_vxlan_sg_del(vxlan_sg);
+}
+
+static zebra_vxlan_sg_t *zebra_vxlan_sg_do_ref(struct zebra_vrf *zvrf,
+                               struct in_addr sip, struct in_addr mcast_grp)
+{
+       zebra_vxlan_sg_t *vxlan_sg;
+       struct prefix_sg sg;
+
+       sg.family = AF_INET;
+       sg.prefixlen = IPV4_MAX_BYTELEN;
+       sg.src = sip;
+       sg.grp = mcast_grp;
+       vxlan_sg = zebra_vxlan_sg_add(zvrf, &sg);
+       if (vxlan_sg)
+               ++vxlan_sg->ref_cnt;
+
+       return vxlan_sg;
+}
+
+static void zebra_vxlan_sg_deref(struct in_addr local_vtep_ip,
+               struct in_addr mcast_grp)
+{
+       struct zebra_vrf *zvrf;
+
+       if (!local_vtep_ip.s_addr || !mcast_grp.s_addr)
+               return;
+
+       zvrf = vrf_info_lookup(VRF_DEFAULT);
+       if (!zvrf)
+               return;
+
+       zebra_vxlan_sg_do_deref(zvrf, local_vtep_ip, mcast_grp);
+}
+
+static void zebra_vxlan_sg_ref(struct in_addr local_vtep_ip,
+                               struct in_addr mcast_grp)
+{
+       struct zebra_vrf *zvrf;
+
+       if (!local_vtep_ip.s_addr || !mcast_grp.s_addr)
+               return;
+
+       zvrf = vrf_info_lookup(VRF_DEFAULT);
+       if (!zvrf)
+               return;
+       zebra_vxlan_sg_do_ref(zvrf, local_vtep_ip, mcast_grp);
+}
+
+static void zebra_vxlan_sg_cleanup(struct hash_backet *backet, void *arg)
+{
+       zebra_vxlan_sg_t *vxlan_sg = (zebra_vxlan_sg_t *)backet->data;
+
+       zebra_vxlan_sg_del(vxlan_sg);
+}
index 2ff92970d777a825b36148ea058b7340a938fcf8..f752bdd690d27995d23f375e787899a357180596 100644 (file)
@@ -60,9 +60,11 @@ is_vxlan_flooding_head_end(void)
 }
 
 /* VxLAN interface change flags of interest. */
-#define ZEBRA_VXLIF_LOCAL_IP_CHANGE     0x1
-#define ZEBRA_VXLIF_MASTER_CHANGE       0x2
-#define ZEBRA_VXLIF_VLAN_CHANGE         0x4
+#define ZEBRA_VXLIF_LOCAL_IP_CHANGE     (1 << 0)
+#define ZEBRA_VXLIF_MASTER_CHANGE       (1 << 1)
+#define ZEBRA_VXLIF_VLAN_CHANGE         (1 << 2)
+#define ZEBRA_VXLIF_MCAST_GRP_CHANGE    (1 << 3)
+
 
 #define VNI_STR_LEN 32
 
index 5081c08d1931a484a661743c462450202b77b394..9f945442bba46ae206e05c63b192cb682335ceea 100644 (file)
@@ -52,6 +52,10 @@ struct zebra_vtep_t_ {
        /* Remote IP. */
        /* NOTE: Can only be IPv4 right now. */
        struct in_addr vtep_ip;
+       /* Flood mode (one of enum vxlan_flood_control) based on the PMSI
+        * tunnel type advertised by the remote VTEP
+        */
+       int flood_control;
 
        /* Links. */
        struct zebra_vtep_t_ *next;
@@ -87,6 +91,9 @@ struct zebra_vni_t_ {
        /* Local IP */
        struct in_addr local_vtep_ip;
 
+       /* PIM-SM MDT group for BUM flooding */
+       struct in_addr mcast_grp;
+
        /* tenant VRF, if any */
        vrf_id_t vrf_id;
 
@@ -427,4 +434,26 @@ struct nh_walk_ctx {
 }
 #endif
 
+/*
+ * Multicast hash table.
+ *
+ * This table contains -
+ * 1. The (S, G) entries used for encapsulating and forwarding BUM traffic.
+ *    S is the local VTEP-IP and G is a BUM mcast group address.
+ * 2. The (X, G) entries used for terminating a BUM flow.
+ * Multiple L2-VNIs can share the same MDT hence the need to maintain
+ * an aggregated table that pimd can consume without much
+ * re-interpretation.
+ */
+typedef struct zebra_vxlan_sg_ {
+       struct zebra_vrf *zvrf;
+
+       struct prefix_sg sg;
+       char sg_str[PREFIX_SG_STR_LEN];
+
+       /* For SG - num of L2 VNIs using this entry for sending BUM traffic */
+       /* For XG - num of SG using this as parent */
+       uint32_t ref_cnt;
+} zebra_vxlan_sg_t;
+
 #endif /* _ZEBRA_VXLAN_PRIVATE_H */
index 80fdbefcd5837c9ba40c900383717c0bc6ed67ae..df5f236c04f0d617687695058846951277bd6371 100644 (file)
@@ -970,6 +970,8 @@ static void zebra_show_client_detail(struct vty *vty, struct zserv *client)
                client->v4_nh_watch_add_cnt, 0, client->v4_nh_watch_rem_cnt);
        vty_out(vty, "NHT v6      %-12d%-12d%-12d\n",
                client->v6_nh_watch_add_cnt, 0, client->v6_nh_watch_rem_cnt);
+       vty_out(vty, "VxLAN SG    %-12d%-12d%-12d\n", client->vxlan_sg_add_cnt,
+               0, client->vxlan_sg_del_cnt);
        vty_out(vty, "Interface Up Notifications: %d\n", client->ifup_cnt);
        vty_out(vty, "Interface Down Notifications: %d\n", client->ifdown_cnt);
        vty_out(vty, "VNI add notifications: %d\n", client->vniadd_cnt);
index 86863d961c2bf961f87dd727f172b65027a6ce9c..90fd195712be79217cc84a98db35b5137d0c3bae 100644 (file)
@@ -141,6 +141,8 @@ struct zserv {
        uint32_t v4_nh_watch_rem_cnt;
        uint32_t v6_nh_watch_add_cnt;
        uint32_t v6_nh_watch_rem_cnt;
+       uint32_t vxlan_sg_add_cnt;
+       uint32_t vxlan_sg_del_cnt;
 
        time_t nh_reg_time;
        time_t nh_dereg_time;