]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge branch 'master' into working/master/bgp-vpn-vrf-leaking
authorpaulzlabn <paulz@labn.net>
Wed, 14 Mar 2018 20:31:58 +0000 (13:31 -0700)
committerGitHub <noreply@github.com>
Wed, 14 Mar 2018 20:31:58 +0000 (13:31 -0700)
12 files changed:
1  2 
bgpd/bgp_debug.c
bgpd/bgp_debug.h
bgpd/bgp_route.c
bgpd/bgp_routemap.c
bgpd/bgpd.c
bgpd/bgpd.h
lib/log.c
lib/zclient.c
vtysh/vtysh.c
zebra/redistribute.c
zebra/zebra_rib.c
zebra/zserv.c

Simple merge
Simple merge
Simple merge
Simple merge
diff --cc bgpd/bgpd.c
Simple merge
diff --cc bgpd/bgpd.h
index 41ae8e916fde195b9f7e8f2fb970d6f53bb2c818,9e1d279091e86fe8429fe6f66e0d8b7240eaf157..664f8c9da4a82c812ee7eb52429956274c666cb7
@@@ -317,8 -311,14 +317,15 @@@ struct bgp 
        /* BGP Per AF flags */
        u_int16_t af_flags[AFI_MAX][SAFI_MAX];
  #define BGP_CONFIG_DAMPENING              (1 << 0)
 +#define BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT  (1 << 1)
  
+ /* l2vpn evpn flags - 1 << 0 is used for DAMPENNG */
+ #define BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST      (1 << 1)
+ #define BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST      (1 << 2)
+ #define BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV4    (1 << 3)
+ #define BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV6    (1 << 4)
        /* Route table for next-hop lookup cache. */
        struct bgp_table *nexthop_cache_table[AFI_MAX];
  
diff --cc lib/log.c
Simple merge
diff --cc lib/zclient.c
Simple merge
diff --cc vtysh/vtysh.c
Simple merge
index 36168a5f2a2ebdcdca1ee5cdab9feff8d8e80445,5a239306fbfae0fbd2ec6e19e04d111fe8d8a026..3a66aea45f897ef6d9f7d1b61987d0c50c129669
@@@ -251,16 -249,10 +250,16 @@@ void zebra_redistribute_add(ZAPI_HANDLE
        int type = 0;
        u_short instance;
  
-       STREAM_GETC(client->ibuf, afi);
-       STREAM_GETC(client->ibuf, type);
-       STREAM_GETW(client->ibuf, instance);
+       STREAM_GETC(msg, afi);
+       STREAM_GETC(msg, type);
+       STREAM_GETW(msg, instance);
  
 +      if (IS_ZEBRA_DEBUG_EVENT)
 +              zlog_debug(
 +                      "%s: client proto %s afi=%d, wants %s, vrf %d, instance=%d",
 +                      __func__, zebra_route_string(client->proto), afi,
 +                      zebra_route_string(type), zvrf_id(zvrf), instance);
 +
        if (afi == 0 || afi > AFI_MAX) {
                zlog_warn("%s: Specified afi %d does not exist",
                          __PRETTY_FUNCTION__, afi);
Simple merge
diff --cc zebra/zserv.c
index 54e688ebcd174285c13e54ed75ad538c292b16c0,0def903803126b516c9b50ae609960c2f7d50cda..2f2c09112f571b5a0bdb840125deab8b0c86cf3f
@@@ -660,492 -592,510 +592,547 @@@ int zsend_redistribute_route(int cmd, s
        SET_FLAG(api.message, ZAPI_MESSAGE_MTU);
        api.mtu = re->mtu;
  
+       struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ);
        /* Encode route and send. */
-       if (zapi_route_encode(cmd, client->obuf, &api) < 0)
+       if (zapi_route_encode(cmd, s, &api) < 0)
                return -1;
 -      return zebra_server_send_message(client, s);
 +
 +      if (IS_ZEBRA_DEBUG_SEND) {
 +              char buf_prefix[PREFIX_STRLEN];
 +              prefix2str(&api.prefix, buf_prefix, sizeof(buf_prefix));
 +
 +              zlog_debug("%s: %s to client %s: type %s, vrf_id %d, p %s",
 +                         __func__, zserv_command_string(cmd),
 +                         zebra_route_string(client->proto),
 +                         zebra_route_string(api.type), api.vrf_id,
 +                         buf_prefix);
 +      }
 +      return zebra_server_send_message(client);
 +}
 +
 +static int zsend_write_nexthop(struct stream *s, struct nexthop *nexthop)
 +{
 +      stream_putc(s, nexthop->type);
 +      switch (nexthop->type) {
 +      case NEXTHOP_TYPE_IPV4:
 +      case NEXTHOP_TYPE_IPV4_IFINDEX:
 +              stream_put_in_addr(s, &nexthop->gate.ipv4);
 +              stream_putl(s, nexthop->ifindex);
 +              break;
 +      case NEXTHOP_TYPE_IPV6:
 +              stream_put(s, &nexthop->gate.ipv6, 16);
 +              break;
 +      case NEXTHOP_TYPE_IPV6_IFINDEX:
 +              stream_put(s, &nexthop->gate.ipv6, 16);
 +              stream_putl(s, nexthop->ifindex);
 +              break;
 +      case NEXTHOP_TYPE_IFINDEX:
 +              stream_putl(s, nexthop->ifindex);
 +              break;
 +      default:
 +              /* do nothing */
 +              break;
 +      }
 +      return 1;
  }
  
- /* Nexthop register */
- static int zserv_rnh_register(struct zserv *client, u_short length,
-                             rnh_type_t type, struct zebra_vrf *zvrf)
+ /*
+  * Modified version of zsend_ipv4_nexthop_lookup(): Query unicast rib if
+  * nexthop is not found on mrib. Returns both route metric and protocol
+  * distance.
+  */
+ static int zsend_ipv4_nexthop_lookup_mrib(struct zserv *client,
+                                         struct in_addr addr,
+                                         struct route_entry *re,
+                                         struct zebra_vrf *zvrf)
  {
-       struct rnh *rnh;
        struct stream *s;
-       struct prefix p;
-       u_short l = 0;
-       u_char flags = 0;
-       if (IS_ZEBRA_DEBUG_NHT)
-               zlog_debug(
-                       "rnh_register msg from client %s: length=%d, type=%s\n",
-                       zebra_route_string(client->proto), length,
-                       (type == RNH_NEXTHOP_TYPE) ? "nexthop" : "route");
+       unsigned long nump;
+       u_char num;
+       struct nexthop *nexthop;
  
-       s = client->ibuf;
+       /* Get output stream. */
+       s = stream_new(ZEBRA_MAX_PACKET_SIZ);
+       stream_reset(s);
  
-       client->nh_reg_time = monotime(NULL);
+       /* Fill in result. */
+       zclient_create_header(s, ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB, zvrf_id(zvrf));
+       stream_put_in_addr(s, &addr);
  
-       while (l < length) {
-               STREAM_GETC(s, flags);
-               STREAM_GETW(s, p.family);
-               STREAM_GETC(s, p.prefixlen);
-               l += 4;
-               if (p.family == AF_INET) {
-                       if (p.prefixlen > IPV4_MAX_BITLEN) {
-                               zlog_warn(
-                                       "%s: Specified prefix length %d is too large for a v4 address",
-                                       __PRETTY_FUNCTION__, p.prefixlen);
-                               return -1;
-                       }
-                       STREAM_GET(&p.u.prefix4.s_addr, s, IPV4_MAX_BYTELEN);
-                       l += IPV4_MAX_BYTELEN;
-               } else if (p.family == AF_INET6) {
-                       if (p.prefixlen > IPV6_MAX_BITLEN) {
-                               zlog_warn(
-                                       "%s: Specified prefix length %d is to large for a v6 address",
-                                       __PRETTY_FUNCTION__, p.prefixlen);
-                               return -1;
-                       }
-                       STREAM_GET(&p.u.prefix6, s, IPV6_MAX_BYTELEN);
-                       l += IPV6_MAX_BYTELEN;
-               } else {
-                       zlog_err(
-                               "rnh_register: Received unknown family type %d\n",
-                               p.family);
-                       return -1;
-               }
-               rnh = zebra_add_rnh(&p, zvrf_id(zvrf), type);
-               if (type == RNH_NEXTHOP_TYPE) {
-                       if (flags
-                           && !CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED))
-                               SET_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED);
-                       else if (!flags
-                                && CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED))
-                               UNSET_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED);
-               } else if (type == RNH_IMPORT_CHECK_TYPE) {
-                       if (flags
-                           && !CHECK_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH))
-                               SET_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH);
-                       else if (!flags && CHECK_FLAG(rnh->flags,
-                                                     ZEBRA_NHT_EXACT_MATCH))
-                               UNSET_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH);
-               }
+       if (re) {
+               stream_putc(s, re->distance);
+               stream_putl(s, re->metric);
+               num = 0;
+               nump = stream_get_endp(
+                       s);     /* remember position for nexthop_num */
+               stream_putc(s, 0); /* reserve room for nexthop_num */
+               /* Only non-recursive routes are elegible to resolve the nexthop
+                * we
+                * are looking up. Therefore, we will just iterate over the top
+                * chain of nexthops. */
+               for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next)
+                       if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+                               num += zserv_encode_nexthop(s, nexthop);
  
-               zebra_add_rnh_client(rnh, client, type, zvrf_id(zvrf));
-               /* Anything not AF_INET/INET6 has been filtered out above */
-               zebra_evaluate_rnh(zvrf_id(zvrf), p.family, 1, type, &p);
+               stream_putc_at(s, nump, num); /* store nexthop_num */
+       } else {
+               stream_putc(s, 0); /* distance */
+               stream_putl(s, 0); /* metric */
+               stream_putc(s, 0); /* nexthop_num */
        }
  
- stream_failure:
-       return 0;
+       stream_putw_at(s, 0, stream_get_endp(s));
+       return zebra_server_send_message(client, s);
  }
  
- /* Nexthop register */
- static int zserv_rnh_unregister(struct zserv *client, u_short length,
-                               rnh_type_t type, struct zebra_vrf *zvrf)
+ int zsend_route_notify_owner(struct route_entry *re, struct prefix *p,
+                            enum zapi_route_notify_owner note)
  {
-       struct rnh *rnh;
+       struct zserv *client;
        struct stream *s;
-       struct prefix p;
-       u_short l = 0;
+       uint8_t blen;
  
-       if (IS_ZEBRA_DEBUG_NHT)
-               zlog_debug("rnh_unregister msg from client %s: length=%d\n",
-                          zebra_route_string(client->proto), length);
+       client = zebra_find_client(re->type, re->instance);
+       if (!client || !client->notify_owner) {
+               if (IS_ZEBRA_DEBUG_PACKET) {
+                       char buff[PREFIX_STRLEN];
  
-       s = client->ibuf;
+                       zlog_debug(
+                               "Not Notifying Owner: %u about prefix %s(%u) %d",
+                               re->type, prefix2str(p, buff, sizeof(buff)),
+                               re->table, note);
+               }
+               return 0;
+       }
  
-       while (l < length) {
-               uint8_t flags;
+       if (IS_ZEBRA_DEBUG_PACKET) {
+               char buff[PREFIX_STRLEN];
  
-               STREAM_GETC(s, flags);
-               if (flags != 0)
-                       goto stream_failure;
+               zlog_debug("Notifying Owner: %u about prefix %s(%u) %d",
+                          re->type, prefix2str(p, buff, sizeof(buff)),
+                          re->table, note);
+       }
  
-               STREAM_GETW(s, p.family);
-               STREAM_GETC(s, p.prefixlen);
-               l += 4;
-               if (p.family == AF_INET) {
-                       if (p.prefixlen > IPV4_MAX_BITLEN) {
-                               zlog_warn(
-                                       "%s: Specified prefix length %d is to large for a v4 address",
-                                       __PRETTY_FUNCTION__, p.prefixlen);
-                               return -1;
-                       }
-                       STREAM_GET(&p.u.prefix4.s_addr, s, IPV4_MAX_BYTELEN);
-                       l += IPV4_MAX_BYTELEN;
-               } else if (p.family == AF_INET6) {
-                       if (p.prefixlen > IPV6_MAX_BITLEN) {
-                               zlog_warn(
-                                       "%s: Specified prefix length %d is to large for a v6 address",
-                                       __PRETTY_FUNCTION__, p.prefixlen);
-                               return -1;
-                       }
-                       STREAM_GET(&p.u.prefix6, s, IPV6_MAX_BYTELEN);
-                       l += IPV6_MAX_BYTELEN;
-               } else {
-                       zlog_err(
-                               "rnh_register: Received unknown family type %d\n",
-                               p.family);
-                       return -1;
-               }
-               rnh = zebra_lookup_rnh(&p, zvrf_id(zvrf), type);
-               if (rnh) {
-                       client->nh_dereg_time = monotime(NULL);
-                       zebra_remove_rnh_client(rnh, client, type);
-               }
-       }
- stream_failure:
-       return 0;
- }
+       s = stream_new(ZEBRA_MAX_PACKET_SIZ);
+       stream_reset(s);
  
- #define ZEBRA_MIN_FEC_LENGTH 5
+       zclient_create_header(s, ZEBRA_ROUTE_NOTIFY_OWNER, re->vrf_id);
  
- /* FEC register */
- static int zserv_fec_register(struct zserv *client, u_short length)
- {
-       struct stream *s;
-       struct zebra_vrf *zvrf;
-       u_short l = 0;
-       struct prefix p;
-       u_int16_t flags;
-       u_int32_t label_index = MPLS_INVALID_LABEL_INDEX;
+       stream_put(s, &note, sizeof(note));
  
-       s = client->ibuf;
-       zvrf = vrf_info_lookup(VRF_DEFAULT);
-       if (!zvrf)
-               return 0; // unexpected
+       stream_putc(s, p->family);
  
-       /*
-        * The minimum amount of data that can be sent for one fec
-        * registration
-        */
-       if (length < ZEBRA_MIN_FEC_LENGTH) {
-               zlog_err(
-                       "fec_register: Received a fec register of length %d, it is of insufficient size to properly decode",
-                       length);
-               return -1;
-       }
+       blen = prefix_blen(p);
+       stream_putc(s, p->prefixlen);
+       stream_put(s, &p->u.prefix, blen);
  
-       while (l < length) {
-               STREAM_GETW(s, flags);
-               memset(&p, 0, sizeof(p));
-               STREAM_GETW(s, p.family);
-               if (p.family != AF_INET && p.family != AF_INET6) {
-                       zlog_err(
-                               "fec_register: Received unknown family type %d\n",
-                               p.family);
-                       return -1;
-               }
-               STREAM_GETC(s, p.prefixlen);
-               if ((p.family == AF_INET && p.prefixlen > IPV4_MAX_BITLEN)
-                   || (p.family == AF_INET6
-                       && p.prefixlen > IPV6_MAX_BITLEN)) {
-                       zlog_warn(
-                               "%s: Specified prefix length: %d is to long for %d",
-                               __PRETTY_FUNCTION__, p.prefixlen, p.family);
-                       return -1;
-               }
-               l += 5;
-               STREAM_GET(&p.u.prefix, s, PSIZE(p.prefixlen));
-               l += PSIZE(p.prefixlen);
-               if (flags & ZEBRA_FEC_REGISTER_LABEL_INDEX) {
-                       STREAM_GETL(s, label_index);
-                       l += 4;
-               } else
-                       label_index = MPLS_INVALID_LABEL_INDEX;
-               zebra_mpls_fec_register(zvrf, &p, label_index, client);
-       }
+       stream_putl(s, re->table);
  
- stream_failure:
-       return 0;
+       stream_putw_at(s, 0, stream_get_endp(s));
+       return zebra_server_send_message(client, s);
  }
  
- /* FEC unregister */
static int zserv_fec_unregister(struct zserv *client, u_short length)
+ void zsend_rule_notify_owner(struct zebra_pbr_rule *rule,
                           enum zapi_rule_notify_owner note)
  {
+       struct listnode *node;
+       struct zserv *client;
        struct stream *s;
-       struct zebra_vrf *zvrf;
-       u_short l = 0;
-       struct prefix p;
-       uint16_t flags;
  
-       s = client->ibuf;
-       zvrf = vrf_info_lookup(VRF_DEFAULT);
-       if (!zvrf)
-               return 0; // unexpected
+       if (IS_ZEBRA_DEBUG_PACKET) {
+               zlog_debug("%s: Notifying %u", __PRETTY_FUNCTION__,
+                          rule->unique);
+       }
  
-       /*
-        * The minimum amount of data that can be sent for one
-        * fec unregistration
-        */
-       if (length < ZEBRA_MIN_FEC_LENGTH) {
-               zlog_err(
-                       "fec_unregister: Received a fec unregister of length %d, it is of insufficient size to properly decode",
-                       length);
-               return -1;
+       for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) {
+               if (rule->sock == client->sock)
+                       break;
        }
  
-       while (l < length) {
-               STREAM_GETW(s, flags);
-               if (flags != 0)
-                       goto stream_failure;
+       if (!client)
+               return;
  
-               memset(&p, 0, sizeof(p));
-               STREAM_GETW(s, p.family);
-               if (p.family != AF_INET && p.family != AF_INET6) {
-                       zlog_err(
-                               "fec_unregister: Received unknown family type %d\n",
-                               p.family);
-                       return -1;
-               }
-               STREAM_GETC(s, p.prefixlen);
-               if ((p.family == AF_INET && p.prefixlen > IPV4_MAX_BITLEN)
-                   || (p.family == AF_INET6
-                       && p.prefixlen > IPV6_MAX_BITLEN)) {
-                       zlog_warn(
-                               "%s: Received prefix length %d which is greater than %d can support",
-                               __PRETTY_FUNCTION__, p.prefixlen, p.family);
-                       return -1;
-               }
-               l += 5;
-               STREAM_GET(&p.u.prefix, s, PSIZE(p.prefixlen));
-               l += PSIZE(p.prefixlen);
-               zebra_mpls_fec_unregister(zvrf, &p, client);
-       }
+       s = stream_new(ZEBRA_MAX_PACKET_SIZ);
+       stream_reset(s);
  
- stream_failure:
-       return 0;
+       zclient_create_header(s, ZEBRA_RULE_NOTIFY_OWNER, VRF_DEFAULT);
+       stream_put(s, &note, sizeof(note));
+       stream_putl(s, rule->seq);
+       stream_putl(s, rule->priority);
+       stream_putl(s, rule->unique);
+       if (rule->ifp)
+               stream_putl(s, rule->ifp->ifindex);
+       else
+               stream_putl(s, 0);
+       stream_putw_at(s, 0, stream_get_endp(s));
+       zebra_server_send_message(client, s);
  }
  
- /*
-   Modified version of zsend_ipv4_nexthop_lookup():
-   Query unicast rib if nexthop is not found on mrib.
-   Returns both route metric and protocol distance.
- */
- static int zsend_ipv4_nexthop_lookup_mrib(struct zserv *client,
-                                         struct in_addr addr,
-                                         struct route_entry *re,
-                                         struct zebra_vrf *zvrf)
+ /* Router-id is updated. Send ZEBRA_ROUTER_ID_ADD to client. */
+ int zsend_router_id_update(struct zserv *client, struct prefix *p,
+                          vrf_id_t vrf_id)
  {
-       struct stream *s;
-       unsigned long nump;
-       u_char num;
-       struct nexthop *nexthop;
+       int blen;
  
-       /* Get output stream. */
-       s = client->obuf;
-       stream_reset(s);
+       /* Check this client need interface information. */
+       if (!vrf_bitmap_check(client->ridinfo, vrf_id))
+               return 0;
  
-       /* Fill in result. */
-       zclient_create_header(s, ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB, zvrf_id(zvrf));
-       stream_put_in_addr(s, &addr);
+       struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ);
  
-       if (re) {
-               stream_putc(s, re->distance);
-               stream_putl(s, re->metric);
-               num = 0;
-               nump = stream_get_endp(
-                       s);     /* remember position for nexthop_num */
-               stream_putc(s, 0); /* reserve room for nexthop_num */
-               /* Only non-recursive routes are elegible to resolve the nexthop
-                * we
-                * are looking up. Therefore, we will just iterate over the top
-                * chain of nexthops. */
-               for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next)
-                       if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
-                               num += zsend_write_nexthop(s, nexthop);
+       /* Message type. */
+       zclient_create_header(s, ZEBRA_ROUTER_ID_UPDATE, vrf_id);
  
-               stream_putc_at(s, nump, num); /* store nexthop_num */
-       } else {
-               stream_putc(s, 0); /* distance */
-               stream_putl(s, 0); /* metric */
-               stream_putc(s, 0); /* nexthop_num */
-       }
+       /* Prefix information. */
+       stream_putc(s, p->family);
+       blen = prefix_blen(p);
+       stream_put(s, &p->u.prefix, blen);
+       stream_putc(s, p->prefixlen);
  
+       /* Write packet size. */
        stream_putw_at(s, 0, stream_get_endp(s));
  
-       return zebra_server_send_message(client);
+       return zebra_server_send_message(client, s);
  }
  
- int zsend_route_notify_owner(struct route_entry *re, struct prefix *p,
-                            enum zapi_route_notify_owner note)
+ /*
+  * Function used by Zebra to send a PW status update to LDP daemon
+  */
+ int zsend_pw_update(struct zserv *client, struct zebra_pw *pw)
  {
-       struct zserv *client;
-       struct stream *s;
-       uint8_t blen;
+       struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ);
  
-       client = zebra_find_client(re->type, re->instance);
-       if (!client || !client->notify_owner) {
-               if (IS_ZEBRA_DEBUG_PACKET) {
-                       char buff[PREFIX_STRLEN];
+       zclient_create_header(s, ZEBRA_PW_STATUS_UPDATE, pw->vrf_id);
+       stream_write(s, pw->ifname, IF_NAMESIZE);
+       stream_putl(s, pw->ifindex);
+       stream_putl(s, pw->status);
  
-                       zlog_debug(
-                               "Not Notifying Owner: %u about prefix %s(%u) %d",
-                               re->type, prefix2str(p, buff, sizeof(buff)),
-                               re->table, note);
-               }
-               return 0;
-       }
+       /* Put length at the first point of the stream. */
+       stream_putw_at(s, 0, stream_get_endp(s));
  
-       if (IS_ZEBRA_DEBUG_PACKET) {
-               char buff[PREFIX_STRLEN];
+       return zebra_server_send_message(client, s);
+ }
  
-               zlog_debug("Notifying Owner: %u about prefix %s(%u) %d",
-                          re->type, prefix2str(p, buff, sizeof(buff)),
-                          re->table, note);
-       }
+ /* Send response to a get label chunk request to client */
+ static int zsend_assign_label_chunk_response(struct zserv *client,
+                                            vrf_id_t vrf_id,
+                                            struct label_manager_chunk *lmc)
+ {
+       int ret;
+       struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ);
  
-       s = client->obuf;
-       stream_reset(s);
+       zclient_create_header(s, ZEBRA_GET_LABEL_CHUNK, vrf_id);
  
-       zclient_create_header(s, ZEBRA_ROUTE_NOTIFY_OWNER, re->vrf_id);
+       if (lmc) {
+               /* keep */
+               stream_putc(s, lmc->keep);
+               /* start and end labels */
+               stream_putl(s, lmc->start);
+               stream_putl(s, lmc->end);
+       }
  
-       stream_put(s, &note, sizeof(note));
+       /* Write packet size. */
+       stream_putw_at(s, 0, stream_get_endp(s));
  
-       stream_putc(s, p->family);
+       ret = writen(client->sock, s->data, stream_get_endp(s));
+       stream_free(s);
+       return ret;
+ }
  
-       blen = prefix_blen(p);
-       stream_putc(s, p->prefixlen);
-       stream_put(s, &p->u.prefix, blen);
+ /* Send response to a label manager connect request to client */
+ static int zsend_label_manager_connect_response(struct zserv *client,
+                                               vrf_id_t vrf_id, u_short result)
+ {
+       int ret;
+       struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ);
  
-       stream_putl(s, re->table);
+       zclient_create_header(s, ZEBRA_LABEL_MANAGER_CONNECT, vrf_id);
  
+       /* result */
+       stream_putc(s, result);
+       /* Write packet size. */
        stream_putw_at(s, 0, stream_get_endp(s));
  
-       return zebra_server_send_message(client);
+       ret = writen(client->sock, s->data, stream_get_endp(s));
+       stream_free(s);
+       return ret;
  }
  
- void zsend_rule_notify_owner(struct zebra_pbr_rule *rule,
-                            enum zapi_rule_notify_owner note)
+ /* Inbound message handling ------------------------------------------------ */
+ int cmd2type[] = {
+       [ZEBRA_NEXTHOP_REGISTER] = RNH_NEXTHOP_TYPE,
+       [ZEBRA_NEXTHOP_UNREGISTER] = RNH_NEXTHOP_TYPE,
+       [ZEBRA_IMPORT_ROUTE_REGISTER] = RNH_IMPORT_CHECK_TYPE,
+       [ZEBRA_IMPORT_ROUTE_UNREGISTER] = RNH_IMPORT_CHECK_TYPE,
+ };
+ /* Nexthop register */
+ static void zread_rnh_register(ZAPI_HANDLER_ARGS)
  {
-       struct listnode *node;
-       struct zserv *client;
+       struct rnh *rnh;
        struct stream *s;
+       struct prefix p;
+       u_short l = 0;
+       u_char flags = 0;
+       uint16_t type = cmd2type[hdr->command];
  
-       if (IS_ZEBRA_DEBUG_PACKET) {
-               zlog_debug("%s: Notifying %u",
-                          __PRETTY_FUNCTION__, rule->unique);
-       }
+       if (IS_ZEBRA_DEBUG_NHT)
+               zlog_debug(
+                       "rnh_register msg from client %s: hdr->length=%d, type=%s\n",
+                       zebra_route_string(client->proto), hdr->length,
+                       (type == RNH_NEXTHOP_TYPE) ? "nexthop" : "route");
  
-       for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) {
-               if (rule->sock == client->sock)
-                       break;
+       s = msg;
+       client->nh_reg_time = monotime(NULL);
+       while (l < hdr->length) {
+               STREAM_GETC(s, flags);
+               STREAM_GETW(s, p.family);
+               STREAM_GETC(s, p.prefixlen);
+               l += 4;
+               if (p.family == AF_INET) {
+                       if (p.prefixlen > IPV4_MAX_BITLEN) {
+                               zlog_warn(
+                                       "%s: Specified prefix hdr->length %d is too large for a v4 address",
+                                       __PRETTY_FUNCTION__, p.prefixlen);
+                               return;
+                       }
+                       STREAM_GET(&p.u.prefix4.s_addr, s, IPV4_MAX_BYTELEN);
+                       l += IPV4_MAX_BYTELEN;
+               } else if (p.family == AF_INET6) {
+                       if (p.prefixlen > IPV6_MAX_BITLEN) {
+                               zlog_warn(
+                                       "%s: Specified prefix hdr->length %d is to large for a v6 address",
+                                       __PRETTY_FUNCTION__, p.prefixlen);
+                               return;
+                       }
+                       STREAM_GET(&p.u.prefix6, s, IPV6_MAX_BYTELEN);
+                       l += IPV6_MAX_BYTELEN;
+               } else {
+                       zlog_err(
+                               "rnh_register: Received unknown family type %d\n",
+                               p.family);
+                       return;
+               }
+               rnh = zebra_add_rnh(&p, zvrf_id(zvrf), type);
+               if (type == RNH_NEXTHOP_TYPE) {
+                       if (flags
+                           && !CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED))
+                               SET_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED);
+                       else if (!flags
+                                && CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED))
+                               UNSET_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED);
+               } else if (type == RNH_IMPORT_CHECK_TYPE) {
+                       if (flags
+                           && !CHECK_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH))
+                               SET_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH);
+                       else if (!flags
+                                && CHECK_FLAG(rnh->flags,
+                                              ZEBRA_NHT_EXACT_MATCH))
+                               UNSET_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH);
+               }
+               zebra_add_rnh_client(rnh, client, type, zvrf_id(zvrf));
+               /* Anything not AF_INET/INET6 has been filtered out above */
+               zebra_evaluate_rnh(zvrf_id(zvrf), p.family, 1, type, &p);
        }
  
-       if (!client)
-               return;
+ stream_failure:
+       return;
+ }
  
-       s = client->obuf;
-       stream_reset(s);
+ /* Nexthop register */
+ static void zread_rnh_unregister(ZAPI_HANDLER_ARGS)
+ {
+       struct rnh *rnh;
+       struct stream *s;
+       struct prefix p;
+       u_short l = 0;
+       uint16_t type = cmd2type[hdr->command];
  
-       zclient_create_header(s, ZEBRA_RULE_NOTIFY_OWNER, VRF_DEFAULT);
-       stream_put(s, &note, sizeof(note));
-       stream_putl(s, rule->seq);
-       stream_putl(s, rule->priority);
-       stream_putl(s, rule->unique);
-       if (rule->ifp)
-               stream_putl(s, rule->ifp->ifindex);
-       else
-               stream_putl(s, 0);
+       if (IS_ZEBRA_DEBUG_NHT)
+               zlog_debug(
+                       "rnh_unregister msg from client %s: hdr->length=%d\n",
+                       zebra_route_string(client->proto), hdr->length);
  
-       stream_putw_at(s, 0, stream_get_endp(s));
+       s = msg;
+       while (l < hdr->length) {
+               uint8_t flags;
+               STREAM_GETC(s, flags);
+               if (flags != 0)
+                       goto stream_failure;
  
-       zebra_server_send_message(client);
+               STREAM_GETW(s, p.family);
+               STREAM_GETC(s, p.prefixlen);
+               l += 4;
+               if (p.family == AF_INET) {
+                       if (p.prefixlen > IPV4_MAX_BITLEN) {
+                               zlog_warn(
+                                       "%s: Specified prefix hdr->length %d is to large for a v4 address",
+                                       __PRETTY_FUNCTION__, p.prefixlen);
+                               return;
+                       }
+                       STREAM_GET(&p.u.prefix4.s_addr, s, IPV4_MAX_BYTELEN);
+                       l += IPV4_MAX_BYTELEN;
+               } else if (p.family == AF_INET6) {
+                       if (p.prefixlen > IPV6_MAX_BITLEN) {
+                               zlog_warn(
+                                       "%s: Specified prefix hdr->length %d is to large for a v6 address",
+                                       __PRETTY_FUNCTION__, p.prefixlen);
+                               return;
+                       }
+                       STREAM_GET(&p.u.prefix6, s, IPV6_MAX_BYTELEN);
+                       l += IPV6_MAX_BYTELEN;
+               } else {
+                       zlog_err(
+                               "rnh_register: Received unknown family type %d\n",
+                               p.family);
+                       return;
+               }
+               rnh = zebra_lookup_rnh(&p, zvrf_id(zvrf), type);
+               if (rnh) {
+                       client->nh_dereg_time = monotime(NULL);
+                       zebra_remove_rnh_client(rnh, client, type);
+               }
+       }
+ stream_failure:
+       return;
  }
  
- /* Router-id is updated. Send ZEBRA_ROUTER_ID_ADD to client. */
- int zsend_router_id_update(struct zserv *client, struct prefix *p,
-                          vrf_id_t vrf_id)
+ #define ZEBRA_MIN_FEC_LENGTH 5
+ /* FEC register */
+ static void zread_fec_register(ZAPI_HANDLER_ARGS)
  {
        struct stream *s;
-       int blen;
-       /* Check this client need interface information. */
-       if (!vrf_bitmap_check(client->ridinfo, vrf_id))
-               return 0;
-       s = client->obuf;
-       stream_reset(s);
+       u_short l = 0;
+       struct prefix p;
+       uint16_t flags;
+       uint32_t label_index = MPLS_INVALID_LABEL_INDEX;
  
-       /* Message type. */
-       zclient_create_header(s, ZEBRA_ROUTER_ID_UPDATE, vrf_id);
+       s = msg;
+       zvrf = vrf_info_lookup(VRF_DEFAULT);
+       if (!zvrf)
+               return; // unexpected
  
-       /* Prefix information. */
-       stream_putc(s, p->family);
-       blen = prefix_blen(p);
-       stream_put(s, &p->u.prefix, blen);
-       stream_putc(s, p->prefixlen);
+       /*
+        * The minimum amount of data that can be sent for one fec
+        * registration
+        */
+       if (hdr->length < ZEBRA_MIN_FEC_LENGTH) {
+               zlog_err(
+                       "fec_register: Received a fec register of hdr->length %d, it is of insufficient size to properly decode",
+                       hdr->length);
+               return;
+       }
  
-       /* Write packet size. */
-       stream_putw_at(s, 0, stream_get_endp(s));
+       while (l < hdr->length) {
+               STREAM_GETW(s, flags);
+               memset(&p, 0, sizeof(p));
+               STREAM_GETW(s, p.family);
+               if (p.family != AF_INET && p.family != AF_INET6) {
+                       zlog_err(
+                               "fec_register: Received unknown family type %d\n",
+                               p.family);
+                       return;
+               }
+               STREAM_GETC(s, p.prefixlen);
+               if ((p.family == AF_INET && p.prefixlen > IPV4_MAX_BITLEN)
+                   || (p.family == AF_INET6
+                       && p.prefixlen > IPV6_MAX_BITLEN)) {
+                       zlog_warn(
+                               "%s: Specified prefix hdr->length: %d is to long for %d",
+                               __PRETTY_FUNCTION__, p.prefixlen, p.family);
+                       return;
+               }
+               l += 5;
+               STREAM_GET(&p.u.prefix, s, PSIZE(p.prefixlen));
+               l += PSIZE(p.prefixlen);
+               if (flags & ZEBRA_FEC_REGISTER_LABEL_INDEX) {
+                       STREAM_GETL(s, label_index);
+                       l += 4;
+               } else
+                       label_index = MPLS_INVALID_LABEL_INDEX;
+               zebra_mpls_fec_register(zvrf, &p, label_index, client);
+       }
  
-       return zebra_server_send_message(client);
+ stream_failure:
+       return;
  }
  
- /*
-  * Function used by Zebra to send a PW status update to LDP daemon
-  */
- int zsend_pw_update(struct zserv *client, struct zebra_pw *pw)
+ /* FEC unregister */
+ static void zread_fec_unregister(ZAPI_HANDLER_ARGS)
  {
        struct stream *s;
+       u_short l = 0;
+       struct prefix p;
+       uint16_t flags;
  
-       s = client->obuf;
-       stream_reset(s);
+       s = msg;
+       zvrf = vrf_info_lookup(VRF_DEFAULT);
+       if (!zvrf)
+               return; // unexpected
  
-       zclient_create_header(s, ZEBRA_PW_STATUS_UPDATE, pw->vrf_id);
-       stream_write(s, pw->ifname, IF_NAMESIZE);
-       stream_putl(s, pw->ifindex);
-       stream_putl(s, pw->status);
+       /*
+        * The minimum amount of data that can be sent for one
+        * fec unregistration
+        */
+       if (hdr->length < ZEBRA_MIN_FEC_LENGTH) {
+               zlog_err(
+                       "fec_unregister: Received a fec unregister of hdr->length %d, it is of insufficient size to properly decode",
+                       hdr->length);
+               return;
+       }
  
-       /* Put length at the first point of the stream. */
-       stream_putw_at(s, 0, stream_get_endp(s));
+       while (l < hdr->length) {
+               STREAM_GETW(s, flags);
+               if (flags != 0)
+                       goto stream_failure;
  
-       return zebra_server_send_message(client);
+               memset(&p, 0, sizeof(p));
+               STREAM_GETW(s, p.family);
+               if (p.family != AF_INET && p.family != AF_INET6) {
+                       zlog_err(
+                               "fec_unregister: Received unknown family type %d\n",
+                               p.family);
+                       return;
+               }
+               STREAM_GETC(s, p.prefixlen);
+               if ((p.family == AF_INET && p.prefixlen > IPV4_MAX_BITLEN)
+                   || (p.family == AF_INET6
+                       && p.prefixlen > IPV6_MAX_BITLEN)) {
+                       zlog_warn(
+                               "%s: Received prefix hdr->length %d which is greater than %d can support",
+                               __PRETTY_FUNCTION__, p.prefixlen, p.family);
+                       return;
+               }
+               l += 5;
+               STREAM_GET(&p.u.prefix, s, PSIZE(p.prefixlen));
+               l += PSIZE(p.prefixlen);
+               zebra_mpls_fec_unregister(zvrf, &p, client);
+       }
+ stream_failure:
+       return;
  }
  
- /* Register zebra server interface information.  Send current all
-    interface and address information. */
- static int zread_interface_add(struct zserv *client, u_short length,
-                              struct zebra_vrf *zvrf)
+ /*
+  * Register zebra server interface information.
+  * Send current all interface and address information.
+  */
+ static void zread_interface_add(ZAPI_HANDLER_ARGS)
  {
        struct vrf *vrf;
        struct interface *ifp;
@@@ -1201,21 -1144,11 +1181,21 @@@ static void zread_route_add(ZAPI_HANDLE
        struct nexthop *nexthop = NULL;
        int i, ret;
        vrf_id_t vrf_id = 0;
+       struct ipaddr vtep_ip;
  
-       s = client->ibuf;
-       if (zapi_route_decode(s, &api) < 0)
-               return -1;
+       s = msg;
+       zapi_route_decode(s, &api);
  
 +      if (IS_ZEBRA_DEBUG_RECV) {
 +              char buf_prefix[PREFIX_STRLEN];
 +              prefix2str(&api.prefix, buf_prefix, sizeof(buf_prefix));
 +              zlog_debug("%s: p=%s, ZAPI_MESSAGE_LABEL: %sset, flags=0x%x",
 +                         __func__, buf_prefix,
 +                         (CHECK_FLAG(api.message, ZAPI_MESSAGE_LABEL) ? ""
 +                                                                      : "un"),
 +                         api.flags);
 +      }
 +
        /* Allocate new route. */
        vrf_id = zvrf_id(zvrf);
        re = XCALLOC(MTYPE_RE, sizeof(struct route_entry));