Diff for /embedaddon/quagga/zebra/rt_netlink.c between versions 1.1.1.3 and 1.1.1.4

version 1.1.1.3, 2013/07/21 23:54:41 version 1.1.1.4, 2016/11/02 10:09:10
Line 20 Line 20
  */   */
   
 #include <zebra.h>  #include <zebra.h>
   #include <net/if_arp.h>
   
 /* Hack for GNU libc version 2. */  /* Hack for GNU libc version 2. */
 #ifndef MSG_TRUNC  #ifndef MSG_TRUNC
Line 36 Line 37
 #include "rib.h"  #include "rib.h"
 #include "thread.h"  #include "thread.h"
 #include "privs.h"  #include "privs.h"
   #include "vrf.h"
   
 #include "zebra/zserv.h"  #include "zebra/zserv.h"
 #include "zebra/rt.h"  #include "zebra/rt.h"
Line 45 Line 47
   
 #include "rt_netlink.h"  #include "rt_netlink.h"
   
 /* Socket interface to kernel */  
 struct nlsock  
 {  
   int sock;  
   int seq;  
   struct sockaddr_nl snl;  
   const char *name;  
 } netlink      = { -1, 0, {0}, "netlink-listen"},     /* kernel messages */  
   netlink_cmd  = { -1, 0, {0}, "netlink-cmd"};        /* command channel */  
   
 static const struct message nlmsg_str[] = {  static const struct message nlmsg_str[] = {
   {RTM_NEWROUTE, "RTM_NEWROUTE"},    {RTM_NEWROUTE, "RTM_NEWROUTE"},
   {RTM_DELROUTE, "RTM_DELROUTE"},    {RTM_DELROUTE, "RTM_DELROUTE"},
Line 77  extern u_int32_t nl_rcvbufsize; Line 69  extern u_int32_t nl_rcvbufsize;
 /* Note: on netlink systems, there should be a 1-to-1 mapping between interface  /* Note: on netlink systems, there should be a 1-to-1 mapping between interface
    names and ifindex values. */     names and ifindex values. */
 static void  static void
set_ifindex(struct interface *ifp, unsigned int ifi_index)set_ifindex(struct interface *ifp, ifindex_t ifi_index)
 {  {
   struct interface *oifp;    struct interface *oifp;
   
Line 101  set_ifindex(struct interface *ifp, unsigned int ifi_in Line 93  set_ifindex(struct interface *ifp, unsigned int ifi_in
   ifp->ifindex = ifi_index;    ifp->ifindex = ifi_index;
 }  }
   
   #ifndef SO_RCVBUFFORCE
   #define SO_RCVBUFFORCE  (33)
   #endif
   
 static int  static int
 netlink_recvbuf (struct nlsock *nl, uint32_t newsize)  netlink_recvbuf (struct nlsock *nl, uint32_t newsize)
 {  {
Line 117  netlink_recvbuf (struct nlsock *nl, uint32_t newsize) Line 113  netlink_recvbuf (struct nlsock *nl, uint32_t newsize)
       return -1;        return -1;
     }      }
   
  ret = setsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &nl_rcvbufsize,  /* Try force option (linux >= 2.6.14) and fall back to normal set */
   if ( zserv_privs.change (ZPRIVS_RAISE) )
     zlog_err ("routing_socket: Can't raise privileges");
   ret = setsockopt(nl->sock, SOL_SOCKET, SO_RCVBUFFORCE, &nl_rcvbufsize,
                    sizeof(nl_rcvbufsize));                     sizeof(nl_rcvbufsize));
     if ( zserv_privs.change (ZPRIVS_LOWER) )
       zlog_err ("routing_socket: Can't lower privileges");
   if (ret < 0)    if (ret < 0)
        ret = setsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &nl_rcvbufsize,
                         sizeof(nl_rcvbufsize));
     if (ret < 0)
     {      {
       zlog (NULL, LOG_ERR, "Can't set %s receive buffer size: %s", nl->name,        zlog (NULL, LOG_ERR, "Can't set %s receive buffer size: %s", nl->name,
             safe_strerror (errno));              safe_strerror (errno));
Line 142  netlink_recvbuf (struct nlsock *nl, uint32_t newsize) Line 146  netlink_recvbuf (struct nlsock *nl, uint32_t newsize)
   
 /* Make socket for Linux netlink interface. */  /* Make socket for Linux netlink interface. */
 static int  static int
netlink_socket (struct nlsock *nl, unsigned long groups)netlink_socket (struct nlsock *nl, unsigned long groups, vrf_id_t vrf_id)
 {  {
   int ret;    int ret;
   struct sockaddr_nl snl;    struct sockaddr_nl snl;
Line 150  netlink_socket (struct nlsock *nl, unsigned long group Line 154  netlink_socket (struct nlsock *nl, unsigned long group
   int namelen;    int namelen;
   int save_errno;    int save_errno;
   
  sock = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);  if (zserv_privs.change (ZPRIVS_RAISE))
     {
       zlog (NULL, LOG_ERR, "Can't raise privileges");
       return -1;
     }
 
   sock = vrf_socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE, vrf_id);
   if (sock < 0)    if (sock < 0)
     {      {
       zlog (NULL, LOG_ERR, "Can't open %s socket: %s", nl->name,        zlog (NULL, LOG_ERR, "Can't open %s socket: %s", nl->name,
Line 163  netlink_socket (struct nlsock *nl, unsigned long group Line 173  netlink_socket (struct nlsock *nl, unsigned long group
   snl.nl_groups = groups;    snl.nl_groups = groups;
   
   /* Bind the socket to the netlink structure for anything. */    /* Bind the socket to the netlink structure for anything. */
   if (zserv_privs.change (ZPRIVS_RAISE))  
     {  
       zlog (NULL, LOG_ERR, "Can't raise privileges");  
       return -1;  
     }  
   
   ret = bind (sock, (struct sockaddr *) &snl, sizeof snl);    ret = bind (sock, (struct sockaddr *) &snl, sizeof snl);
   save_errno = errno;    save_errno = errno;
   if (zserv_privs.change (ZPRIVS_LOWER))    if (zserv_privs.change (ZPRIVS_LOWER))
Line 260  netlink_request (int family, int type, struct nlsock * Line 264  netlink_request (int family, int type, struct nlsock *
 /* Receive message from netlink interface and pass those information  /* Receive message from netlink interface and pass those information
    to the given function. */     to the given function. */
 static int  static int
netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *),netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *,
                    struct nlsock *nl)                                   vrf_id_t),
                     struct nlsock *nl, struct zebra_vrf *zvrf)
 {  {
   int status;    int status;
   int ret = 0;    int ret = 0;
Line 270  netlink_parse_info (int (*filter) (struct sockaddr_nl  Line 275  netlink_parse_info (int (*filter) (struct sockaddr_nl 
   while (1)    while (1)
     {      {
       char buf[NL_PKT_BUF_SIZE];        char buf[NL_PKT_BUF_SIZE];
      struct iovec iov = { buf, sizeof buf };      struct iovec iov = {
         .iov_base = buf,
         .iov_len = sizeof buf
       };
       struct sockaddr_nl snl;        struct sockaddr_nl snl;
      struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };      struct msghdr msg = {
         .msg_name = (void *) &snl,
         .msg_namelen = sizeof snl,
         .msg_iov = &iov,
         .msg_iovlen = 1
       };
       struct nlmsghdr *h;        struct nlmsghdr *h;
   
       status = recvmsg (nl->sock, &msg, 0);        status = recvmsg (nl->sock, &msg, 0);
Line 342  netlink_parse_info (int (*filter) (struct sockaddr_nl  Line 355  netlink_parse_info (int (*filter) (struct sockaddr_nl 
                 }                  }
   
               /* Deal with errors that occur because of races in link handling */                /* Deal with errors that occur because of races in link handling */
              if (nl == &netlink_cmd              if (nl == &zvrf->netlink_cmd
                   && ((msg_type == RTM_DELROUTE &&                    && ((msg_type == RTM_DELROUTE &&
                        (-errnum == ENODEV || -errnum == ESRCH))                         (-errnum == ENODEV || -errnum == ESRCH))
                       || (msg_type == RTM_NEWROUTE && -errnum == EEXIST)))                        || (msg_type == RTM_NEWROUTE && -errnum == EEXIST)))
Line 369  netlink_parse_info (int (*filter) (struct sockaddr_nl  Line 382  netlink_parse_info (int (*filter) (struct sockaddr_nl 
                        lookup (nlmsg_str, h->nlmsg_type), h->nlmsg_type,                         lookup (nlmsg_str, h->nlmsg_type), h->nlmsg_type,
                        h->nlmsg_seq, h->nlmsg_pid);                         h->nlmsg_seq, h->nlmsg_pid);
   
          /* skip unsolicited messages originating from command socket */          /* skip unsolicited messages originating from command socket
          if (nl != &netlink_cmd && h->nlmsg_pid == netlink_cmd.snl.nl_pid)           * linux sets the originators port-id for {NEW|DEL}ADDR messages,
            * so this has to be checked here. */
           if (nl != &zvrf->netlink_cmd
               && h->nlmsg_pid == zvrf->netlink_cmd.snl.nl_pid
               && (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR))
             {              {
               if (IS_ZEBRA_DEBUG_KERNEL)                if (IS_ZEBRA_DEBUG_KERNEL)
                 zlog_debug ("netlink_parse_info: %s packet comes from %s",                  zlog_debug ("netlink_parse_info: %s packet comes from %s",
                            netlink_cmd.name, nl->name);                            zvrf->netlink_cmd.name, nl->name);
               continue;                continue;
             }              }
   
          error = (*filter) (&snl, h);          error = (*filter) (&snl, h, zvrf->vrf_id);
           if (error < 0)            if (error < 0)
             {              {
               zlog (NULL, LOG_ERR, "%s filter function error", nl->name);                zlog (NULL, LOG_ERR, "%s filter function error", nl->name);
Line 446  netlink_interface_update_hw_addr (struct rtattr **tb,  Line 463  netlink_interface_update_hw_addr (struct rtattr **tb, 
     }      }
 }  }
   
   static enum zebra_link_type
   netlink_to_zebra_link_type (unsigned int hwt)
   {
     switch (hwt)
     {
       case ARPHRD_ETHER: return ZEBRA_LLT_ETHER;
       case ARPHRD_EETHER: return ZEBRA_LLT_EETHER;
       case ARPHRD_AX25: return ZEBRA_LLT_AX25;
       case ARPHRD_PRONET: return ZEBRA_LLT_PRONET;
       case ARPHRD_IEEE802: return ZEBRA_LLT_IEEE802;
       case ARPHRD_ARCNET: return ZEBRA_LLT_ARCNET;
       case ARPHRD_APPLETLK: return ZEBRA_LLT_APPLETLK;
       case ARPHRD_DLCI: return ZEBRA_LLT_DLCI;
       case ARPHRD_ATM: return ZEBRA_LLT_ATM;
       case ARPHRD_METRICOM: return ZEBRA_LLT_METRICOM;
       case ARPHRD_IEEE1394: return ZEBRA_LLT_IEEE1394;
       case ARPHRD_EUI64: return ZEBRA_LLT_EUI64;
       case ARPHRD_INFINIBAND: return ZEBRA_LLT_INFINIBAND;
       case ARPHRD_SLIP: return ZEBRA_LLT_SLIP;
       case ARPHRD_CSLIP: return ZEBRA_LLT_CSLIP;
       case ARPHRD_SLIP6: return ZEBRA_LLT_SLIP6;
       case ARPHRD_CSLIP6: return ZEBRA_LLT_CSLIP6;
       case ARPHRD_RSRVD: return ZEBRA_LLT_RSRVD;
       case ARPHRD_ADAPT: return ZEBRA_LLT_ADAPT;
       case ARPHRD_ROSE: return ZEBRA_LLT_ROSE;
       case ARPHRD_X25: return ZEBRA_LLT_X25;
       case ARPHRD_PPP: return ZEBRA_LLT_PPP;
       case ARPHRD_CISCO: return ZEBRA_LLT_CHDLC;
       case ARPHRD_LAPB: return ZEBRA_LLT_LAPB;
       case ARPHRD_RAWHDLC: return ZEBRA_LLT_RAWHDLC;
       case ARPHRD_TUNNEL: return ZEBRA_LLT_IPIP;
       case ARPHRD_TUNNEL6: return ZEBRA_LLT_IPIP6;
       case ARPHRD_FRAD: return ZEBRA_LLT_FRAD;
       case ARPHRD_SKIP: return ZEBRA_LLT_SKIP;
       case ARPHRD_LOOPBACK: return ZEBRA_LLT_LOOPBACK;
       case ARPHRD_LOCALTLK: return ZEBRA_LLT_LOCALTLK;
       case ARPHRD_FDDI: return ZEBRA_LLT_FDDI;
       case ARPHRD_SIT: return ZEBRA_LLT_SIT;
       case ARPHRD_IPDDP: return ZEBRA_LLT_IPDDP;
       case ARPHRD_IPGRE: return ZEBRA_LLT_IPGRE;
       case ARPHRD_PIMREG: return ZEBRA_LLT_PIMREG;
       case ARPHRD_HIPPI: return ZEBRA_LLT_HIPPI;
       case ARPHRD_ECONET: return ZEBRA_LLT_ECONET;
       case ARPHRD_IRDA: return ZEBRA_LLT_IRDA;
       case ARPHRD_FCPP: return ZEBRA_LLT_FCPP;
       case ARPHRD_FCAL: return ZEBRA_LLT_FCAL;
       case ARPHRD_FCPL: return ZEBRA_LLT_FCPL;
       case ARPHRD_FCFABRIC: return ZEBRA_LLT_FCFABRIC;
       case ARPHRD_IEEE802_TR: return ZEBRA_LLT_IEEE802_TR;
       case ARPHRD_IEEE80211: return ZEBRA_LLT_IEEE80211;
       case ARPHRD_IEEE802154: return ZEBRA_LLT_IEEE802154;
   #ifdef ARPHRD_IP6GRE
       case ARPHRD_IP6GRE: return ZEBRA_LLT_IP6GRE;
   #endif
   #ifdef ARPHRD_IEEE802154_PHY
       case ARPHRD_IEEE802154_PHY: return ZEBRA_LLT_IEEE802154_PHY;
   #endif
   
       default: return ZEBRA_LLT_UNKNOWN;
     }
   }
   
 /* Called from interface_lookup_netlink().  This function is only used  /* Called from interface_lookup_netlink().  This function is only used
    during bootstrap. */     during bootstrap. */
 static int  static int
netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h)netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h,
     vrf_id_t vrf_id)
 {  {
   int len;    int len;
   struct ifinfomsg *ifi;    struct ifinfomsg *ifi;
Line 485  netlink_interface (struct sockaddr_nl *snl, struct nlm Line 565  netlink_interface (struct sockaddr_nl *snl, struct nlm
   name = (char *) RTA_DATA (tb[IFLA_IFNAME]);    name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
   
   /* Add interface. */    /* Add interface. */
  ifp = if_get_by_name (name);  ifp = if_get_by_name_vrf (name, vrf_id);
   set_ifindex(ifp, ifi->ifi_index);    set_ifindex(ifp, ifi->ifi_index);
   ifp->flags = ifi->ifi_flags & 0x0000fffff;    ifp->flags = ifi->ifi_flags & 0x0000fffff;
   ifp->mtu6 = ifp->mtu = *(uint32_t *) RTA_DATA (tb[IFLA_MTU]);    ifp->mtu6 = ifp->mtu = *(uint32_t *) RTA_DATA (tb[IFLA_MTU]);
  ifp->metric = 1;  ifp->metric = 0;
   
   /* Hardware type and address. */    /* Hardware type and address. */
  ifp->hw_type = ifi->ifi_type;  ifp->ll_type = netlink_to_zebra_link_type (ifi->ifi_type);
   netlink_interface_update_hw_addr (tb, ifp);    netlink_interface_update_hw_addr (tb, ifp);
   
   if_add_update (ifp);    if_add_update (ifp);
Line 502  netlink_interface (struct sockaddr_nl *snl, struct nlm Line 582  netlink_interface (struct sockaddr_nl *snl, struct nlm
   
 /* Lookup interface IPv4/IPv6 address. */  /* Lookup interface IPv4/IPv6 address. */
 static int  static int
netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h)netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h,
     vrf_id_t vrf_id)
 {  {
   int len;    int len;
   struct ifaddrmsg *ifa;    struct ifaddrmsg *ifa;
Line 532  netlink_interface_addr (struct sockaddr_nl *snl, struc Line 613  netlink_interface_addr (struct sockaddr_nl *snl, struc
   memset (tb, 0, sizeof tb);    memset (tb, 0, sizeof tb);
   netlink_parse_rtattr (tb, IFA_MAX, IFA_RTA (ifa), len);    netlink_parse_rtattr (tb, IFA_MAX, IFA_RTA (ifa), len);
   
  ifp = if_lookup_by_index (ifa->ifa_index);  ifp = if_lookup_by_index_vrf (ifa->ifa_index, vrf_id);
   if (ifp == NULL)    if (ifp == NULL)
     {      {
      zlog_err ("netlink_interface_addr can't find interface by index %d",      zlog_err ("netlink_interface_addr can't find interface by index %d vrf %u",
                ifa->ifa_index);                ifa->ifa_index, vrf_id);
       return -1;        return -1;
     }      }
   
   if (IS_ZEBRA_DEBUG_KERNEL)    /* remove this line to see initial ifcfg */    if (IS_ZEBRA_DEBUG_KERNEL)    /* remove this line to see initial ifcfg */
     {      {
       char buf[BUFSIZ];        char buf[BUFSIZ];
      zlog_debug ("netlink_interface_addr %s %s:",      zlog_debug ("netlink_interface_addr %s %s vrf %u:",
                 lookup (nlmsg_str, h->nlmsg_type), ifp->name);                 lookup (nlmsg_str, h->nlmsg_type), ifp->name, vrf_id);
       if (tb[IFA_LOCAL])        if (tb[IFA_LOCAL])
         zlog_debug ("  IFA_LOCAL     %s/%d",          zlog_debug ("  IFA_LOCAL     %s/%d",
                     inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_LOCAL]),                      inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_LOCAL]),
Line 637  netlink_interface_addr (struct sockaddr_nl *snl, struc Line 718  netlink_interface_addr (struct sockaddr_nl *snl, struc
   
 /* Looking up routing table by netlink interface. */  /* Looking up routing table by netlink interface. */
 static int  static int
netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h,
     vrf_id_t vrf_id)
 {  {
   int len;    int len;
   struct rtmsg *rtm;    struct rtmsg *rtm;
Line 648  netlink_routing_table (struct sockaddr_nl *snl, struct Line 730  netlink_routing_table (struct sockaddr_nl *snl, struct
   
   int index;    int index;
   int table;    int table;
  int metric;  u_int32_t mtu = 0;
   
   void *dest;    void *dest;
   void *gate;    void *gate;
Line 689  netlink_routing_table (struct sockaddr_nl *snl, struct Line 771  netlink_routing_table (struct sockaddr_nl *snl, struct
     flags |= ZEBRA_FLAG_SELFROUTE;      flags |= ZEBRA_FLAG_SELFROUTE;
   
   index = 0;    index = 0;
   metric = 0;  
   dest = NULL;    dest = NULL;
   gate = NULL;    gate = NULL;
   src = NULL;    src = NULL;
Line 708  netlink_routing_table (struct sockaddr_nl *snl, struct Line 789  netlink_routing_table (struct sockaddr_nl *snl, struct
   if (tb[RTA_GATEWAY])    if (tb[RTA_GATEWAY])
     gate = RTA_DATA (tb[RTA_GATEWAY]);      gate = RTA_DATA (tb[RTA_GATEWAY]);
   
  if (tb[RTA_PRIORITY])  if (tb[RTA_METRICS])
    metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);    {
       struct rtattr *mxrta[RTAX_MAX+1];
   
         memset (mxrta, 0, sizeof mxrta);
         netlink_parse_rtattr (mxrta, RTAX_MAX, RTA_DATA(tb[RTA_METRICS]),
                               RTA_PAYLOAD(tb[RTA_METRICS]));
   
         if (mxrta[RTAX_MTU])
           mtu = *(u_int32_t *) RTA_DATA(mxrta[RTAX_MTU]);
       }
   
   if (rtm->rtm_family == AF_INET)    if (rtm->rtm_family == AF_INET)
     {      {
       struct prefix_ipv4 p;        struct prefix_ipv4 p;
Line 720  netlink_routing_table (struct sockaddr_nl *snl, struct Line 810  netlink_routing_table (struct sockaddr_nl *snl, struct
   
       if (!tb[RTA_MULTIPATH])        if (!tb[RTA_MULTIPATH])
           rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index,            rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index,
                        table, metric, 0, SAFI_UNICAST);                        vrf_id, table, 0, mtu, 0, SAFI_UNICAST);
       else        else
         {          {
           /* This is a multipath route */            /* This is a multipath route */
Line 735  netlink_routing_table (struct sockaddr_nl *snl, struct Line 825  netlink_routing_table (struct sockaddr_nl *snl, struct
           rib->type = ZEBRA_ROUTE_KERNEL;            rib->type = ZEBRA_ROUTE_KERNEL;
           rib->distance = 0;            rib->distance = 0;
           rib->flags = flags;            rib->flags = flags;
          rib->metric = metric;          rib->metric = 0;
           rib->mtu = mtu;
           rib->vrf_id = vrf_id;
           rib->table = table;            rib->table = table;
           rib->nexthop_num = 0;            rib->nexthop_num = 0;
           rib->uptime = time (NULL);            rib->uptime = time (NULL);
Line 745  netlink_routing_table (struct sockaddr_nl *snl, struct Line 837  netlink_routing_table (struct sockaddr_nl *snl, struct
               if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len)                if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len)
                 break;                  break;
   
               rib->nexthop_num++;  
               index = rtnh->rtnh_ifindex;                index = rtnh->rtnh_ifindex;
               gate = 0;                gate = 0;
               if (rtnh->rtnh_len > sizeof (*rtnh))                if (rtnh->rtnh_len > sizeof (*rtnh))
Line 785  netlink_routing_table (struct sockaddr_nl *snl, struct Line 876  netlink_routing_table (struct sockaddr_nl *snl, struct
       memcpy (&p.prefix, dest, 16);        memcpy (&p.prefix, dest, 16);
       p.prefixlen = rtm->rtm_dst_len;        p.prefixlen = rtm->rtm_dst_len;
   
      rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table,      rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, vrf_id,
                    metric, 0, SAFI_UNICAST);                    table, 0, mtu, 0, SAFI_UNICAST);
     }      }
 #endif /* HAVE_IPV6 */  #endif /* HAVE_IPV6 */
   
Line 810  static const struct message rtproto_str[] = { Line 901  static const struct message rtproto_str[] = {
   
 /* Routing information change from the kernel. */  /* Routing information change from the kernel. */
 static int  static int
netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
     vrf_id_t vrf_id)
 {  {
   int len;    int len;
   struct rtmsg *rtm;    struct rtmsg *rtm;
Line 820  netlink_route_change (struct sockaddr_nl *snl, struct  Line 912  netlink_route_change (struct sockaddr_nl *snl, struct 
   
   int index;    int index;
   int table;    int table;
  int metric;  u_int32_t mtu = 0;
   
   void *dest;    void *dest;
   void *gate;    void *gate;
Line 831  netlink_route_change (struct sockaddr_nl *snl, struct  Line 923  netlink_route_change (struct sockaddr_nl *snl, struct 
   if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE))    if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE))
     {      {
       /* If this is not route add/delete message print warning. */        /* If this is not route add/delete message print warning. */
      zlog_warn ("Kernel message: %d\n", h->nlmsg_type);      zlog_warn ("Kernel message: %d vrf %u\n", h->nlmsg_type, vrf_id);
       return 0;        return 0;
     }      }
   
   /* Connected route. */    /* Connected route. */
   if (IS_ZEBRA_DEBUG_KERNEL)    if (IS_ZEBRA_DEBUG_KERNEL)
    zlog_debug ("%s %s %s proto %s",    zlog_debug ("%s %s %s proto %s vrf %u",
                h->nlmsg_type ==                 h->nlmsg_type ==
                RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",                 RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
                rtm->rtm_family == AF_INET ? "ipv4" : "ipv6",                 rtm->rtm_family == AF_INET ? "ipv4" : "ipv6",
                rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast",                 rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast",
               lookup (rtproto_str, rtm->rtm_protocol));               lookup (rtproto_str, rtm->rtm_protocol),
                vrf_id);
   
   if (rtm->rtm_type != RTN_UNICAST)    if (rtm->rtm_type != RTN_UNICAST)
     {      {
Line 874  netlink_route_change (struct sockaddr_nl *snl, struct  Line 967  netlink_route_change (struct sockaddr_nl *snl, struct 
   
   if (rtm->rtm_src_len != 0)    if (rtm->rtm_src_len != 0)
     {      {
      zlog_warn ("netlink_route_change(): no src len");      zlog_warn ("netlink_route_change(): no src len, vrf %u", vrf_id);
       return 0;        return 0;
     }      }
   
   index = 0;    index = 0;
   metric = 0;  
   dest = NULL;    dest = NULL;
   gate = NULL;    gate = NULL;
   src = NULL;    src = NULL;
Line 898  netlink_route_change (struct sockaddr_nl *snl, struct  Line 990  netlink_route_change (struct sockaddr_nl *snl, struct 
   if (tb[RTA_PREFSRC])    if (tb[RTA_PREFSRC])
     src = RTA_DATA (tb[RTA_PREFSRC]);      src = RTA_DATA (tb[RTA_PREFSRC]);
   
  if (h->nlmsg_type == RTM_NEWROUTE && tb[RTA_PRIORITY])  if (h->nlmsg_type == RTM_NEWROUTE)
    metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);    {
       if (tb[RTA_METRICS])
         {
           struct rtattr *mxrta[RTAX_MAX+1];
   
             memset (mxrta, 0, sizeof mxrta);
             netlink_parse_rtattr (mxrta, RTAX_MAX, RTA_DATA(tb[RTA_METRICS]),
                                   RTA_PAYLOAD(tb[RTA_METRICS]));
   
             if (mxrta[RTAX_MTU])
               mtu = *(u_int32_t *) RTA_DATA(mxrta[RTAX_MTU]);
           }
       }
   
   if (rtm->rtm_family == AF_INET)    if (rtm->rtm_family == AF_INET)
     {      {
       struct prefix_ipv4 p;        struct prefix_ipv4 p;
Line 910  netlink_route_change (struct sockaddr_nl *snl, struct  Line 1014  netlink_route_change (struct sockaddr_nl *snl, struct 
   
       if (IS_ZEBRA_DEBUG_KERNEL)        if (IS_ZEBRA_DEBUG_KERNEL)
         {          {
          if (h->nlmsg_type == RTM_NEWROUTE)          char buf[PREFIX_STRLEN];
            zlog_debug ("RTM_NEWROUTE %s/%d",          zlog_debug ("%s %s vrf %u",
                       inet_ntoa (p.prefix), p.prefixlen);                      h->nlmsg_type == RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
          else                      prefix2str (&p, buf, sizeof(buf)), vrf_id);
            zlog_debug ("RTM_DELROUTE %s/%d", 
                       inet_ntoa (p.prefix), p.prefixlen); 
         }          }
   
       if (h->nlmsg_type == RTM_NEWROUTE)        if (h->nlmsg_type == RTM_NEWROUTE)
         {          {
           if (!tb[RTA_MULTIPATH])            if (!tb[RTA_MULTIPATH])
            rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table,            rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, vrf_id,
                          metric, 0, SAFI_UNICAST);                          table, 0, mtu, 0, SAFI_UNICAST);
           else            else
             {              {
               /* This is a multipath route */                /* This is a multipath route */
Line 937  netlink_route_change (struct sockaddr_nl *snl, struct  Line 1039  netlink_route_change (struct sockaddr_nl *snl, struct 
               rib->type = ZEBRA_ROUTE_KERNEL;                rib->type = ZEBRA_ROUTE_KERNEL;
               rib->distance = 0;                rib->distance = 0;
               rib->flags = 0;                rib->flags = 0;
              rib->metric = metric;              rib->metric = 0;
               rib->mtu = mtu;
               rib->vrf_id = vrf_id;
               rib->table = table;                rib->table = table;
               rib->nexthop_num = 0;                rib->nexthop_num = 0;
               rib->uptime = time (NULL);                rib->uptime = time (NULL);
Line 947  netlink_route_change (struct sockaddr_nl *snl, struct  Line 1051  netlink_route_change (struct sockaddr_nl *snl, struct 
                   if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len)                    if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len)
                     break;                      break;
   
                   rib->nexthop_num++;  
                   index = rtnh->rtnh_ifindex;                    index = rtnh->rtnh_ifindex;
                   gate = 0;                    gate = 0;
                   if (rtnh->rtnh_len > sizeof (*rtnh))                    if (rtnh->rtnh_len > sizeof (*rtnh))
Line 980  netlink_route_change (struct sockaddr_nl *snl, struct  Line 1083  netlink_route_change (struct sockaddr_nl *snl, struct 
             }              }
         }          }
       else        else
        rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, SAFI_UNICAST);        rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, vrf_id,
                          SAFI_UNICAST);
     }      }
   
 #ifdef HAVE_IPV6  #ifdef HAVE_IPV6
   if (rtm->rtm_family == AF_INET6)    if (rtm->rtm_family == AF_INET6)
     {      {
       struct prefix_ipv6 p;        struct prefix_ipv6 p;
       char buf[BUFSIZ];  
   
       p.family = AF_INET6;        p.family = AF_INET6;
       memcpy (&p.prefix, dest, 16);        memcpy (&p.prefix, dest, 16);
Line 995  netlink_route_change (struct sockaddr_nl *snl, struct  Line 1098  netlink_route_change (struct sockaddr_nl *snl, struct 
   
       if (IS_ZEBRA_DEBUG_KERNEL)        if (IS_ZEBRA_DEBUG_KERNEL)
         {          {
          if (h->nlmsg_type == RTM_NEWROUTE)          char buf[PREFIX_STRLEN];
            zlog_debug ("RTM_NEWROUTE %s/%d",          zlog_debug ("%s %s vrf %u",
                       inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),                      h->nlmsg_type == RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
                       p.prefixlen);                      prefix2str (&p, buf, sizeof(buf)), vrf_id);
          else 
            zlog_debug ("RTM_DELROUTE %s/%d", 
                       inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ), 
                       p.prefixlen); 
         }          }
   
       if (h->nlmsg_type == RTM_NEWROUTE)        if (h->nlmsg_type == RTM_NEWROUTE)
        rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, metric, 0, SAFI_UNICAST);        rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, vrf_id, table,
                       0, mtu, 0, SAFI_UNICAST);
       else        else
        rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, SAFI_UNICAST);        rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, vrf_id,
                          SAFI_UNICAST);
     }      }
 #endif /* HAVE_IPV6 */  #endif /* HAVE_IPV6 */
   
Line 1016  netlink_route_change (struct sockaddr_nl *snl, struct  Line 1117  netlink_route_change (struct sockaddr_nl *snl, struct 
 }  }
   
 static int  static int
netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
     vrf_id_t vrf_id)
 {  {
   int len;    int len;
   struct ifinfomsg *ifi;    struct ifinfomsg *ifi;
Line 1029  netlink_link_change (struct sockaddr_nl *snl, struct n Line 1131  netlink_link_change (struct sockaddr_nl *snl, struct n
   if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK))    if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK))
     {      {
       /* If this is not link add/delete message so print warning. */        /* If this is not link add/delete message so print warning. */
      zlog_warn ("netlink_link_change: wrong kernel message %d\n",      zlog_warn ("netlink_link_change: wrong kernel message %d vrf %u\n",
                 h->nlmsg_type);                 h->nlmsg_type, vrf_id);
       return 0;        return 0;
     }      }
   
Line 1047  netlink_link_change (struct sockaddr_nl *snl, struct n Line 1149  netlink_link_change (struct sockaddr_nl *snl, struct n
   if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))    if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
     {      {
       if (IS_ZEBRA_DEBUG_KERNEL)        if (IS_ZEBRA_DEBUG_KERNEL)
        zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);        zlog_debug ("%s: ignoring IFLA_WIRELESS message, vrf %u", __func__,
                     vrf_id);
       return 0;        return 0;
     }      }
 #endif /* IFLA_WIRELESS */  #endif /* IFLA_WIRELESS */
Line 1059  netlink_link_change (struct sockaddr_nl *snl, struct n Line 1162  netlink_link_change (struct sockaddr_nl *snl, struct n
   /* Add interface. */    /* Add interface. */
   if (h->nlmsg_type == RTM_NEWLINK)    if (h->nlmsg_type == RTM_NEWLINK)
     {      {
      ifp = if_lookup_by_name (name);      ifp = if_lookup_by_name_vrf (name, vrf_id);
   
       if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))        if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
         {          {
           if (ifp == NULL)            if (ifp == NULL)
            ifp = if_get_by_name (name);            ifp = if_get_by_name_vrf (name, vrf_id);
   
           set_ifindex(ifp, ifi->ifi_index);            set_ifindex(ifp, ifi->ifi_index);
           ifp->flags = ifi->ifi_flags & 0x0000fffff;            ifp->flags = ifi->ifi_flags & 0x0000fffff;
           ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);            ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
          ifp->metric = 1;          ifp->metric = 0;
   
           netlink_interface_update_hw_addr (tb, ifp);            netlink_interface_update_hw_addr (tb, ifp);
   
Line 1081  netlink_link_change (struct sockaddr_nl *snl, struct n Line 1184  netlink_link_change (struct sockaddr_nl *snl, struct n
           /* Interface status change. */            /* Interface status change. */
           set_ifindex(ifp, ifi->ifi_index);            set_ifindex(ifp, ifi->ifi_index);
           ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);            ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
          ifp->metric = 1;          ifp->metric = 0;
   
           netlink_interface_update_hw_addr (tb, ifp);            netlink_interface_update_hw_addr (tb, ifp);
   
Line 1105  netlink_link_change (struct sockaddr_nl *snl, struct n Line 1208  netlink_link_change (struct sockaddr_nl *snl, struct n
   else    else
     {      {
       /* RTM_DELLINK. */        /* RTM_DELLINK. */
      ifp = if_lookup_by_name (name);      ifp = if_lookup_by_name_vrf (name, vrf_id);
   
       if (ifp == NULL)        if (ifp == NULL)
         {          {
          zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find",          zlog_warn ("interface %s vrf %u is deleted but can't find",
                name);                     name, vrf_id);
           return 0;            return 0;
         }          }
   
Line 1121  netlink_link_change (struct sockaddr_nl *snl, struct n Line 1224  netlink_link_change (struct sockaddr_nl *snl, struct n
 }  }
   
 static int  static int
netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h)netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h,
     vrf_id_t vrf_id)
 {  {
   /* JF: Ignore messages that aren't from the kernel */    /* JF: Ignore messages that aren't from the kernel */
   if ( snl->nl_pid != 0 )    if ( snl->nl_pid != 0 )
Line 1133  netlink_information_fetch (struct sockaddr_nl *snl, st Line 1237  netlink_information_fetch (struct sockaddr_nl *snl, st
   switch (h->nlmsg_type)    switch (h->nlmsg_type)
     {      {
     case RTM_NEWROUTE:      case RTM_NEWROUTE:
      return netlink_route_change (snl, h);      return netlink_route_change (snl, h, vrf_id);
       break;        break;
     case RTM_DELROUTE:      case RTM_DELROUTE:
      return netlink_route_change (snl, h);      return netlink_route_change (snl, h, vrf_id);
       break;        break;
     case RTM_NEWLINK:      case RTM_NEWLINK:
      return netlink_link_change (snl, h);      return netlink_link_change (snl, h, vrf_id);
       break;        break;
     case RTM_DELLINK:      case RTM_DELLINK:
      return netlink_link_change (snl, h);      return netlink_link_change (snl, h, vrf_id);
       break;        break;
     case RTM_NEWADDR:      case RTM_NEWADDR:
      return netlink_interface_addr (snl, h);      return netlink_interface_addr (snl, h, vrf_id);
       break;        break;
     case RTM_DELADDR:      case RTM_DELADDR:
      return netlink_interface_addr (snl, h);      return netlink_interface_addr (snl, h, vrf_id);
       break;        break;
     default:      default:
      zlog_warn ("Unknown netlink nlmsg_type %d\n", h->nlmsg_type);      zlog_warn ("Unknown netlink nlmsg_type %d vrf %u\n", h->nlmsg_type,
                  vrf_id);
       break;        break;
     }      }
   return 0;    return 0;
Line 1159  netlink_information_fetch (struct sockaddr_nl *snl, st Line 1264  netlink_information_fetch (struct sockaddr_nl *snl, st
   
 /* Interface lookup by netlink socket. */  /* Interface lookup by netlink socket. */
 int  int
interface_lookup_netlink (void)interface_lookup_netlink (struct zebra_vrf *zvrf)
 {  {
   int ret;    int ret;
   
   /* Get interface information. */    /* Get interface information. */
  ret = netlink_request (AF_PACKET, RTM_GETLINK, &netlink_cmd);  ret = netlink_request (AF_PACKET, RTM_GETLINK, &zvrf->netlink_cmd);
   if (ret < 0)    if (ret < 0)
     return ret;      return ret;
  ret = netlink_parse_info (netlink_interface, &netlink_cmd);  ret = netlink_parse_info (netlink_interface, &zvrf->netlink_cmd, zvrf);
   if (ret < 0)    if (ret < 0)
     return ret;      return ret;
   
   /* Get IPv4 address of the interfaces. */    /* Get IPv4 address of the interfaces. */
  ret = netlink_request (AF_INET, RTM_GETADDR, &netlink_cmd);  ret = netlink_request (AF_INET, RTM_GETADDR, &zvrf->netlink_cmd);
   if (ret < 0)    if (ret < 0)
     return ret;      return ret;
  ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);  ret = netlink_parse_info (netlink_interface_addr, &zvrf->netlink_cmd, zvrf);
   if (ret < 0)    if (ret < 0)
     return ret;      return ret;
   
 #ifdef HAVE_IPV6  #ifdef HAVE_IPV6
   /* Get IPv6 address of the interfaces. */    /* Get IPv6 address of the interfaces. */
  ret = netlink_request (AF_INET6, RTM_GETADDR, &netlink_cmd);  ret = netlink_request (AF_INET6, RTM_GETADDR, &zvrf->netlink_cmd);
   if (ret < 0)    if (ret < 0)
     return ret;      return ret;
  ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);  ret = netlink_parse_info (netlink_interface_addr, &zvrf->netlink_cmd, zvrf);
   if (ret < 0)    if (ret < 0)
     return ret;      return ret;
 #endif /* HAVE_IPV6 */  #endif /* HAVE_IPV6 */
Line 1195  interface_lookup_netlink (void) Line 1300  interface_lookup_netlink (void)
 /* Routing table read function using netlink interface.  Only called  /* Routing table read function using netlink interface.  Only called
    bootstrap time. */     bootstrap time. */
 int  int
netlink_route_read (void)netlink_route_read (struct zebra_vrf *zvrf)
 {  {
   int ret;    int ret;
   
   /* Get IPv4 routing table. */    /* Get IPv4 routing table. */
  ret = netlink_request (AF_INET, RTM_GETROUTE, &netlink_cmd);  ret = netlink_request (AF_INET, RTM_GETROUTE, &zvrf->netlink_cmd);
   if (ret < 0)    if (ret < 0)
     return ret;      return ret;
  ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);  ret = netlink_parse_info (netlink_routing_table, &zvrf->netlink_cmd, zvrf);
   if (ret < 0)    if (ret < 0)
     return ret;      return ret;
   
 #ifdef HAVE_IPV6  #ifdef HAVE_IPV6
   /* Get IPv6 routing table. */    /* Get IPv6 routing table. */
  ret = netlink_request (AF_INET6, RTM_GETROUTE, &netlink_cmd);  ret = netlink_request (AF_INET6, RTM_GETROUTE, &zvrf->netlink_cmd);
   if (ret < 0)    if (ret < 0)
     return ret;      return ret;
  ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);  ret = netlink_parse_info (netlink_routing_table, &zvrf->netlink_cmd, zvrf);
   if (ret < 0)    if (ret < 0)
     return ret;      return ret;
 #endif /* HAVE_IPV6 */  #endif /* HAVE_IPV6 */
Line 1223  netlink_route_read (void) Line 1328  netlink_route_read (void)
 /* Utility function  comes from iproute2.   /* Utility function  comes from iproute2. 
    Authors:     Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */     Authors:     Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
 int  int
addattr_l (struct nlmsghdr *n, int maxlen, int type, void *data, int alen)addattr_l (struct nlmsghdr *n, size_t maxlen, int type, void *data, int alen)
 {  {
  int len;  size_t len;
   struct rtattr *rta;    struct rtattr *rta;
   
   len = RTA_LENGTH (alen);    len = RTA_LENGTH (alen);
Line 1265  rta_addattr_l (struct rtattr *rta, int maxlen, int typ Line 1370  rta_addattr_l (struct rtattr *rta, int maxlen, int typ
 /* Utility function comes from iproute2.   /* Utility function comes from iproute2. 
    Authors:     Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */     Authors:     Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
 int  int
addattr32 (struct nlmsghdr *n, int maxlen, int type, int data)addattr32 (struct nlmsghdr *n, size_t maxlen, int type, int data)
 {  {
  int len;  size_t len;
   struct rtattr *rta;    struct rtattr *rta;
   
   len = RTA_LENGTH (4);    len = RTA_LENGTH (4);
Line 1285  addattr32 (struct nlmsghdr *n, int maxlen, int type, i Line 1390  addattr32 (struct nlmsghdr *n, int maxlen, int type, i
 }  }
   
 static int  static int
netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h)netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h,
     vrf_id_t vrf_id)
 {  {
  zlog_warn ("netlink_talk: ignoring message type 0x%04x", h->nlmsg_type);  zlog_warn ("netlink_talk: ignoring message type 0x%04x vrf %u", h->nlmsg_type,
              vrf_id);
   return 0;    return 0;
 }  }
   
 /* sendmsg() to netlink socket then recvmsg(). */  /* sendmsg() to netlink socket then recvmsg(). */
 static int  static int
netlink_talk (struct nlmsghdr *n, struct nlsock *nl)netlink_talk (struct nlmsghdr *n, struct nlsock *nl, struct zebra_vrf *zvrf)
 {  {
   int status;    int status;
   struct sockaddr_nl snl;    struct sockaddr_nl snl;
  struct iovec iov = { (void *) n, n->nlmsg_len };  struct iovec iov = {
  struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };    .iov_base = (void *) n,
     .iov_len = n->nlmsg_len
   };
   struct msghdr msg = {
     .msg_name = (void *) &snl,
     .msg_namelen = sizeof snl,
     .msg_iov = &iov,
     .msg_iovlen = 1,
   };
   int save_errno;    int save_errno;
   
   memset (&snl, 0, sizeof snl);    memset (&snl, 0, sizeof snl);
Line 1334  netlink_talk (struct nlmsghdr *n, struct nlsock *nl) Line 1449  netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
    * Get reply from netlink socket.      * Get reply from netlink socket. 
    * The reply should either be an acknowlegement or an error.     * The reply should either be an acknowlegement or an error.
    */     */
  return netlink_parse_info (netlink_talk_filter, nl);  return netlink_parse_info (netlink_talk_filter, nl, zvrf);
 }  }
   
/* Routing table change via netlink interface. *//* This function takes a nexthop as argument and adds
static int * the appropriate netlink attributes to an existing
netlink_route (int cmd, int family, void *dest, int length, void *gate, * netlink message.
               int index, int zebra_flags, int table) *
  * @param routedesc: Human readable description of route type
  *                   (direct/recursive, single-/multipath)
  * @param bytelen: Length of addresses in bytes.
  * @param nexthop: Nexthop information
  * @param nlmsg: nlmsghdr structure to fill in.
  * @param req_size: The size allocated for the message.
  */
 static void
 _netlink_route_build_singlepath(
         const char *routedesc,
         int bytelen,
         struct nexthop *nexthop,
         struct nlmsghdr *nlmsg,
         struct rtmsg *rtmsg,
         size_t req_size)
 {  {
  int ret;  if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ONLINK))
  int bytelen;    rtmsg->rtm_flags |= RTNH_F_ONLINK;
  struct sockaddr_nl snl;  if (nexthop->type == NEXTHOP_TYPE_IPV4
  int discard;      || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
     {
       addattr_l (nlmsg, req_size, RTA_GATEWAY,
                  &nexthop->gate.ipv4, bytelen);
       if (nexthop->src.ipv4.s_addr)
         addattr_l (nlmsg, req_size, RTA_PREFSRC,
                    &nexthop->src.ipv4, bytelen);
   
  struct      if (IS_ZEBRA_DEBUG_KERNEL)
  {        zlog_debug("netlink_route_multipath() (%s): "
    struct nlmsghdr n;                   "nexthop via %s if %u",
    struct rtmsg r;                   routedesc,
    char buf[NL_PKT_BUF_SIZE];                   inet_ntoa (nexthop->gate.ipv4),
  } req;                   nexthop->ifindex);
     }
 #ifdef HAVE_IPV6
   if (nexthop->type == NEXTHOP_TYPE_IPV6
       || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
       || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
     {
       addattr_l (nlmsg, req_size, RTA_GATEWAY,
                  &nexthop->gate.ipv6, bytelen);
   
  memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE);      if (IS_ZEBRA_DEBUG_KERNEL)
         zlog_debug("netlink_route_multipath() (%s): "
                    "nexthop via %s if %u",
                    routedesc,
                    inet6_ntoa (nexthop->gate.ipv6),
                    nexthop->ifindex);
     }
 #endif /* HAVE_IPV6 */
   if (nexthop->type == NEXTHOP_TYPE_IFINDEX
       || nexthop->type == NEXTHOP_TYPE_IFNAME
       || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
     {
       addattr32 (nlmsg, req_size, RTA_OIF, nexthop->ifindex);
   
  bytelen = (family == AF_INET ? 4 : 16);      if (nexthop->src.ipv4.s_addr)
         addattr_l (nlmsg, req_size, RTA_PREFSRC,
                    &nexthop->src.ipv4, bytelen);
   
  req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));      if (IS_ZEBRA_DEBUG_KERNEL)
  req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;        zlog_debug("netlink_route_multipath() (%s): "
  req.n.nlmsg_type = cmd;                   "nexthop via if %u", routedesc, nexthop->ifindex);
  req.r.rtm_family = family;    }
  req.r.rtm_table = table; 
  req.r.rtm_dst_len = length; 
  req.r.rtm_protocol = RTPROT_ZEBRA; 
  req.r.rtm_scope = RT_SCOPE_UNIVERSE; 
   
  if ((zebra_flags & ZEBRA_FLAG_BLACKHOLE)  if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
      || (zebra_flags & ZEBRA_FLAG_REJECT))      || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
    discard = 1; 
  else 
    discard = 0; 
 
  if (cmd == RTM_NEWROUTE) 
     {      {
      if (discard)      addattr32 (nlmsg, req_size, RTA_OIF, nexthop->ifindex);
        {
          if (zebra_flags & ZEBRA_FLAG_BLACKHOLE)      if (IS_ZEBRA_DEBUG_KERNEL)
            req.r.rtm_type = RTN_BLACKHOLE;        zlog_debug("netlink_route_multipath() (%s): "
          else if (zebra_flags & ZEBRA_FLAG_REJECT)                   "nexthop via if %u", routedesc, nexthop->ifindex);
            req.r.rtm_type = RTN_UNREACHABLE; 
          else 
            assert (RTN_BLACKHOLE != RTN_UNREACHABLE);  /* false */ 
        } 
      else 
        req.r.rtm_type = RTN_UNICAST; 
     }      }
   }
   
  if (dest)/* This function takes a nexthop as argument and
    addattr_l (&req.n, sizeof req, RTA_DST, dest, bytelen); * appends to the given rtattr/rtnexthop pair the
  * representation of the nexthop. If the nexthop
  * defines a preferred source, the src parameter
  * will be modified to point to that src, otherwise
  * it will be kept unmodified.
  *
  * @param routedesc: Human readable description of route type
  *                   (direct/recursive, single-/multipath)
  * @param bytelen: Length of addresses in bytes.
  * @param nexthop: Nexthop information
  * @param rta: rtnetlink attribute structure
  * @param rtnh: pointer to an rtnetlink nexthop structure
  * @param src: pointer pointing to a location where
  *             the prefsrc should be stored.
  */
 static void
 _netlink_route_build_multipath(
         const char *routedesc,
         int bytelen,
         struct nexthop *nexthop,
         struct rtattr *rta,
         struct rtnexthop *rtnh,
         union g_addr **src
         )
 {
   rtnh->rtnh_len = sizeof (*rtnh);
   rtnh->rtnh_flags = 0;
   rtnh->rtnh_hops = 0;
   rta->rta_len += rtnh->rtnh_len;
   
  if (!discard)  if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ONLINK))
     rtnh->rtnh_flags |= RTNH_F_ONLINK;
 
   if (nexthop->type == NEXTHOP_TYPE_IPV4
       || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
     {      {
      if (gate)      rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY,
        addattr_l (&req.n, sizeof req, RTA_GATEWAY, gate, bytelen);                     &nexthop->gate.ipv4, bytelen);
      if (index > 0)      rtnh->rtnh_len += sizeof (struct rtattr) + bytelen;
        addattr32 (&req.n, sizeof req, RTA_OIF, index);
       if (nexthop->src.ipv4.s_addr)
         *src = &nexthop->src;
 
       if (IS_ZEBRA_DEBUG_KERNEL)
         zlog_debug("netlink_route_multipath() (%s): "
                    "nexthop via %s if %u",
                    routedesc,
                    inet_ntoa (nexthop->gate.ipv4),
                    nexthop->ifindex);
     }      }
   #ifdef HAVE_IPV6
     if (nexthop->type == NEXTHOP_TYPE_IPV6
         || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
         || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
       {
         rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY,
                        &nexthop->gate.ipv6, bytelen);
         rtnh->rtnh_len += sizeof (struct rtattr) + bytelen;
   
  /* Destination netlink address. */      if (IS_ZEBRA_DEBUG_KERNEL)
  memset (&snl, 0, sizeof snl);        zlog_debug("netlink_route_multipath() (%s): "
  snl.nl_family = AF_NETLINK;                   "nexthop via %s if %u",
                    routedesc,
                    inet6_ntoa (nexthop->gate.ipv6),
                    nexthop->ifindex);
     }
 #endif /* HAVE_IPV6 */
   /* ifindex */
   if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
       || nexthop->type == NEXTHOP_TYPE_IFINDEX
       || nexthop->type == NEXTHOP_TYPE_IFNAME)
     {
       rtnh->rtnh_ifindex = nexthop->ifindex;
       if (nexthop->src.ipv4.s_addr)
         *src = &nexthop->src;
       if (IS_ZEBRA_DEBUG_KERNEL)
         zlog_debug("netlink_route_multipath() (%s): "
                    "nexthop via if %u", routedesc, nexthop->ifindex);
     }
   else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
       || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
     {
       rtnh->rtnh_ifindex = nexthop->ifindex;
   
  /* Talk to netlink socket. */      if (IS_ZEBRA_DEBUG_KERNEL)
  ret = netlink_talk (&req.n, &netlink_cmd);        zlog_debug("netlink_route_multipath() (%s): "
  if (ret < 0)                   "nexthop via if %u", routedesc, nexthop->ifindex);
    return -1;    }
   else
     {
       rtnh->rtnh_ifindex = 0;
     }
 }
   
  return 0;/* Log debug information for netlink_route_multipath
  * if debug logging is enabled.
  *
  * @param cmd: Netlink command which is to be processed
  * @param p: Prefix for which the change is due
  * @param nexthop: Nexthop which is currently processed
  * @param routedesc: Semantic annotation for nexthop
  *                     (recursive, multipath, etc.)
  * @param family: Address family which the change concerns
  */
 static void
 _netlink_route_debug(
         int cmd,
         struct prefix *p,
         struct nexthop *nexthop,
         const char *routedesc,
         int family,
         struct zebra_vrf *zvrf)
 {
   if (IS_ZEBRA_DEBUG_KERNEL)
     {
       char buf[PREFIX_STRLEN];
       zlog_debug ("netlink_route_multipath() (%s): %s %s vrf %u type %s",
          routedesc,
          lookup (nlmsg_str, cmd),
          prefix2str (p, buf, sizeof(buf)),
          zvrf->vrf_id,
          nexthop_type_to_str (nexthop->type));
     }
 }  }
   
 /* Routing table change via netlink interface. */  /* Routing table change via netlink interface. */
 static int  static int
netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib)
                         int family) 
 {  {
   int bytelen;    int bytelen;
   struct sockaddr_nl snl;    struct sockaddr_nl snl;
  struct nexthop *nexthop = NULL;  struct nexthop *nexthop = NULL, *tnexthop;
  int nexthop_num = 0;  int recursing;
   int nexthop_num;
   int discard;    int discard;
     int family = PREFIX_FAMILY(p);
     const char *routedesc;
   
   struct    struct
   {    {
Line 1429  netlink_route_multipath (int cmd, struct prefix *p, st Line 1678  netlink_route_multipath (int cmd, struct prefix *p, st
     char buf[NL_PKT_BUF_SIZE];      char buf[NL_PKT_BUF_SIZE];
   } req;    } req;
   
     struct zebra_vrf *zvrf = vrf_info_lookup (rib->vrf_id);
   
   memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE);    memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE);
   
   bytelen = (family == AF_INET ? 4 : 16);    bytelen = (family == AF_INET ? 4 : 16);
   
   req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));    req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
  req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;  req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REPLACE | NLM_F_REQUEST;
   req.n.nlmsg_type = cmd;    req.n.nlmsg_type = cmd;
   req.r.rtm_family = family;    req.r.rtm_family = family;
   req.r.rtm_table = rib->table;    req.r.rtm_table = rib->table;
   req.r.rtm_dst_len = p->prefixlen;    req.r.rtm_dst_len = p->prefixlen;
   req.r.rtm_protocol = RTPROT_ZEBRA;    req.r.rtm_protocol = RTPROT_ZEBRA;
  req.r.rtm_scope = RT_SCOPE_UNIVERSE;  req.r.rtm_scope = RT_SCOPE_LINK;
   
   if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))    if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))
     discard = 1;      discard = 1;
Line 1465  netlink_route_multipath (int cmd, struct prefix *p, st Line 1716  netlink_route_multipath (int cmd, struct prefix *p, st
   addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);    addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);
   
   /* Metric. */    /* Metric. */
  addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric);  addattr32 (&req.n, sizeof req, RTA_PRIORITY, NL_DEFAULT_ROUTE_METRIC);
   
     if (rib->mtu || rib->nexthop_mtu)
       {
         char buf[NL_PKT_BUF_SIZE];
         struct rtattr *rta = (void *) buf;
         u_int32_t mtu = rib->mtu;
         if (!mtu || (rib->nexthop_mtu && rib->nexthop_mtu < mtu))
           mtu = rib->nexthop_mtu;
         rta->rta_type = RTA_METRICS;
         rta->rta_len = RTA_LENGTH(0);
         rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTAX_MTU, &mtu, sizeof mtu);
         addattr_l (&req.n, NL_PKT_BUF_SIZE, RTA_METRICS, RTA_DATA (rta),
                    RTA_PAYLOAD (rta));
       }
   
   if (discard)    if (discard)
     {      {
       if (cmd == RTM_NEWROUTE)        if (cmd == RTM_NEWROUTE)
        for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)        for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
          SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);          {
             /* We shouldn't encounter recursive nexthops on discard routes,
              * but it is probably better to handle that case correctly anyway.
              */
             if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
               continue;
             SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
           }
       goto skip;        goto skip;
     }      }
   
  /* Multipath case. */  /* Count overall nexthops so we can decide whether to use singlepath
  if (rib->nexthop_active_num == 1 || MULTIPATH_NUM == 1)   * or multipath case. */
   nexthop_num = 0;
   for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
     {      {
      for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)      if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
         continue;
       if (cmd == RTM_NEWROUTE && !CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
         continue;
       if (cmd == RTM_DELROUTE && !CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
         continue;
 
       if (nexthop->type != NEXTHOP_TYPE_IFINDEX &&
           nexthop->type != NEXTHOP_TYPE_IFNAME)
         req.r.rtm_scope = RT_SCOPE_UNIVERSE;
 
       nexthop_num++;
     }
 
   /* Singlepath case. */
   if (nexthop_num == 1 || MULTIPATH_NUM == 1)
     {
       nexthop_num = 0;
       for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
         {          {
             if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
               continue;
   
           if ((cmd == RTM_NEWROUTE            if ((cmd == RTM_NEWROUTE
                && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))                 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
               || (cmd == RTM_DELROUTE                || (cmd == RTM_DELROUTE
                   && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))                    && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
             {              {
                 routedesc = recursing ? "recursive, 1 hop" : "single hop";
   
              if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))              _netlink_route_debug(cmd, p, nexthop, routedesc, family, zvrf);
                {              _netlink_route_build_singlepath(routedesc, bytelen,
                  if (IS_ZEBRA_DEBUG_KERNEL)                                              nexthop, &req.n, &req.r,
                    {                                              sizeof req);
                      zlog_debug 
                        ("netlink_route_multipath() (recursive, 1 hop): " 
                         "%s %s/%d, type %s", lookup (nlmsg_str, cmd), 
#ifdef HAVE_IPV6 
                         (family == AF_INET) ? inet_ntoa (p->u.prefix4) : 
                         inet6_ntoa (p->u.prefix6), 
#else 
                         inet_ntoa (p->u.prefix4), 
#endif /* HAVE_IPV6 */ 
                          
                         p->prefixlen, nexthop_type_to_str (nexthop->rtype)); 
                    } 
   
                   if (nexthop->rtype == NEXTHOP_TYPE_IPV4  
                       || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)  
                     {  
                       addattr_l (&req.n, sizeof req, RTA_GATEWAY,  
                                  &nexthop->rgate.ipv4, bytelen);  
                       if (nexthop->src.ipv4.s_addr)  
                           addattr_l(&req.n, sizeof req, RTA_PREFSRC,  
                                      &nexthop->src.ipv4, bytelen);  
                       if (IS_ZEBRA_DEBUG_KERNEL)  
                         zlog_debug("netlink_route_multipath() (recursive, "  
                                    "1 hop): nexthop via %s if %u",  
                                    inet_ntoa (nexthop->rgate.ipv4),  
                                    nexthop->rifindex);  
                     }  
 #ifdef HAVE_IPV6  
                   if (nexthop->rtype == NEXTHOP_TYPE_IPV6  
                       || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX  
                       || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)  
                     {  
                       addattr_l (&req.n, sizeof req, RTA_GATEWAY,  
                                  &nexthop->rgate.ipv6, bytelen);  
   
                       if (IS_ZEBRA_DEBUG_KERNEL)  
                         zlog_debug("netlink_route_multipath() (recursive, "  
                                    "1 hop): nexthop via %s if %u",  
                                    inet6_ntoa (nexthop->rgate.ipv6),  
                                    nexthop->rifindex);  
                     }  
 #endif /* HAVE_IPV6 */  
                   if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX  
                       || nexthop->rtype == NEXTHOP_TYPE_IFNAME  
                       || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX  
                       || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX  
                       || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)  
                     {  
                       addattr32 (&req.n, sizeof req, RTA_OIF,  
                                  nexthop->rifindex);  
                       if ((nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX  
                            || nexthop->rtype == NEXTHOP_TYPE_IFINDEX)  
                           && nexthop->src.ipv4.s_addr)  
                         addattr_l (&req.n, sizeof req, RTA_PREFSRC,  
                                  &nexthop->src.ipv4, bytelen);  
   
                       if (IS_ZEBRA_DEBUG_KERNEL)  
                         zlog_debug("netlink_route_multipath() (recursive, "  
                                    "1 hop): nexthop via if %u",  
                                    nexthop->rifindex);  
                     }  
                 }  
               else  
                 {  
                   if (IS_ZEBRA_DEBUG_KERNEL)  
                     {  
                       zlog_debug  
                         ("netlink_route_multipath() (single hop): "  
                          "%s %s/%d, type %s", lookup (nlmsg_str, cmd),  
 #ifdef HAVE_IPV6  
                          (family == AF_INET) ? inet_ntoa (p->u.prefix4) :  
                          inet6_ntoa (p->u.prefix6),  
 #else  
                          inet_ntoa (p->u.prefix4),  
 #endif /* HAVE_IPV6 */  
                          p->prefixlen, nexthop_type_to_str (nexthop->type));  
                     }  
   
                   if (nexthop->type == NEXTHOP_TYPE_IPV4  
                       || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)  
                     {  
                       addattr_l (&req.n, sizeof req, RTA_GATEWAY,  
                                  &nexthop->gate.ipv4, bytelen);  
                       if (nexthop->src.ipv4.s_addr)  
                         addattr_l (&req.n, sizeof req, RTA_PREFSRC,  
                                  &nexthop->src.ipv4, bytelen);  
   
                       if (IS_ZEBRA_DEBUG_KERNEL)  
                         zlog_debug("netlink_route_multipath() (single hop): "  
                                    "nexthop via %s if %u",  
                                    inet_ntoa (nexthop->gate.ipv4),  
                                    nexthop->ifindex);  
                     }  
 #ifdef HAVE_IPV6  
                   if (nexthop->type == NEXTHOP_TYPE_IPV6  
                       || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME  
                       || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)  
                     {  
                       addattr_l (&req.n, sizeof req, RTA_GATEWAY,  
                                  &nexthop->gate.ipv6, bytelen);  
   
                       if (IS_ZEBRA_DEBUG_KERNEL)  
                         zlog_debug("netlink_route_multipath() (single hop): "  
                                    "nexthop via %s if %u",  
                                    inet6_ntoa (nexthop->gate.ipv6),  
                                    nexthop->ifindex);  
                     }  
 #endif /* HAVE_IPV6 */  
                   if (nexthop->type == NEXTHOP_TYPE_IFINDEX  
                       || nexthop->type == NEXTHOP_TYPE_IFNAME  
                       || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)  
                     {  
                       addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);  
   
                       if (nexthop->src.ipv4.s_addr)  
                         addattr_l (&req.n, sizeof req, RTA_PREFSRC,  
                                  &nexthop->src.ipv4, bytelen);  
   
                       if (IS_ZEBRA_DEBUG_KERNEL)  
                         zlog_debug("netlink_route_multipath() (single hop): "  
                                    "nexthop via if %u", nexthop->ifindex);  
                     }  
                   else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX  
                       || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)  
                     {  
                       addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);  
   
                       if (IS_ZEBRA_DEBUG_KERNEL)  
                         zlog_debug("netlink_route_multipath() (single hop): "  
                                    "nexthop via if %u", nexthop->ifindex);  
                     }  
                 }  
   
               if (cmd == RTM_NEWROUTE)                if (cmd == RTM_NEWROUTE)
                 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);                  SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
   
Line 1644  netlink_route_multipath (int cmd, struct prefix *p, st Line 1807  netlink_route_multipath (int cmd, struct prefix *p, st
       rtnh = RTA_DATA (rta);        rtnh = RTA_DATA (rta);
   
       nexthop_num = 0;        nexthop_num = 0;
      for (nexthop = rib->nexthop;      for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
           nexthop && (MULTIPATH_NUM == 0 || nexthop_num < MULTIPATH_NUM); 
           nexthop = nexthop->next) 
         {          {
             if (nexthop_num >= MULTIPATH_NUM)
               break;
   
             if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
               continue;
   
           if ((cmd == RTM_NEWROUTE            if ((cmd == RTM_NEWROUTE
                && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))                 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
               || (cmd == RTM_DELROUTE                || (cmd == RTM_DELROUTE
                   && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))                    && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
             {              {
                 routedesc = recursing ? "recursive, multihop" : "multihop";
               nexthop_num++;                nexthop_num++;
   
              rtnh->rtnh_len = sizeof (*rtnh);              _netlink_route_debug(cmd, p, nexthop,
              rtnh->rtnh_flags = 0;                                   routedesc, family, zvrf);
              rtnh->rtnh_hops = 0;              _netlink_route_build_multipath(routedesc, bytelen,
              rta->rta_len += rtnh->rtnh_len;                                             nexthop, rta, rtnh, &src);
 
              if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) 
                { 
                  if (IS_ZEBRA_DEBUG_KERNEL) 
                    { 
                      zlog_debug ("netlink_route_multipath() " 
                         "(recursive, multihop): %s %s/%d type %s", 
                         lookup (nlmsg_str, cmd), 
#ifdef HAVE_IPV6 
                         (family == AF_INET) ? inet_ntoa (p->u.prefix4) : 
                         inet6_ntoa (p->u.prefix6), 
#else 
                         inet_ntoa (p->u.prefix4), 
#endif /* HAVE_IPV6 */ 
                         p->prefixlen, nexthop_type_to_str (nexthop->rtype)); 
                    } 
                  if (nexthop->rtype == NEXTHOP_TYPE_IPV4 
                      || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX) 
                    { 
                      rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY, 
                                     &nexthop->rgate.ipv4, bytelen); 
                      rtnh->rtnh_len += sizeof (struct rtattr) + 4; 
 
                      if (nexthop->src.ipv4.s_addr) 
                        src = &nexthop->src; 
 
                      if (IS_ZEBRA_DEBUG_KERNEL) 
                        zlog_debug("netlink_route_multipath() (recursive, " 
                                   "multihop): nexthop via %s if %u", 
                                   inet_ntoa (nexthop->rgate.ipv4), 
                                   nexthop->rifindex); 
                    } 
#ifdef HAVE_IPV6 
                  if (nexthop->rtype == NEXTHOP_TYPE_IPV6 
                      || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME 
                      || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX) 
                    { 
                      rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY, 
                                     &nexthop->rgate.ipv6, bytelen); 
 
                      if (IS_ZEBRA_DEBUG_KERNEL) 
                        zlog_debug("netlink_route_multipath() (recursive, " 
                                   "multihop): nexthop via %s if %u", 
                                   inet6_ntoa (nexthop->rgate.ipv6), 
                                   nexthop->rifindex); 
                    } 
#endif /* HAVE_IPV6 */ 
                  /* ifindex */ 
                  if (nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX 
                      || nexthop->rtype == NEXTHOP_TYPE_IFINDEX 
                      || nexthop->rtype == NEXTHOP_TYPE_IFNAME) 
                    { 
                      rtnh->rtnh_ifindex = nexthop->rifindex; 
                      if (nexthop->src.ipv4.s_addr) 
                        src = &nexthop->src; 
 
                      if (IS_ZEBRA_DEBUG_KERNEL) 
                        zlog_debug("netlink_route_multipath() (recursive, " 
                                   "multihop): nexthop via if %u", 
                                   nexthop->rifindex); 
                    } 
                  else if (nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX 
                      || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME) 
                    { 
                      rtnh->rtnh_ifindex = nexthop->rifindex; 
 
                      if (IS_ZEBRA_DEBUG_KERNEL) 
                        zlog_debug("netlink_route_multipath() (recursive, " 
                                   "multihop): nexthop via if %u", 
                                   nexthop->rifindex); 
                    } 
                  else 
                    { 
                      rtnh->rtnh_ifindex = 0; 
                    } 
                } 
              else 
                { 
                  if (IS_ZEBRA_DEBUG_KERNEL) 
                    { 
                      zlog_debug ("netlink_route_multipath() (multihop): " 
                         "%s %s/%d, type %s", lookup (nlmsg_str, cmd), 
#ifdef HAVE_IPV6 
                         (family == AF_INET) ? inet_ntoa (p->u.prefix4) : 
                         inet6_ntoa (p->u.prefix6), 
#else 
                         inet_ntoa (p->u.prefix4), 
#endif /* HAVE_IPV6 */ 
                         p->prefixlen, nexthop_type_to_str (nexthop->type)); 
                    } 
                  if (nexthop->type == NEXTHOP_TYPE_IPV4 
                      || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) 
                    { 
                      rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY, 
                                     &nexthop->gate.ipv4, bytelen); 
                      rtnh->rtnh_len += sizeof (struct rtattr) + 4; 
 
                      if (nexthop->src.ipv4.s_addr) 
                        src = &nexthop->src; 
 
                      if (IS_ZEBRA_DEBUG_KERNEL) 
                        zlog_debug("netlink_route_multipath() (multihop): " 
                                   "nexthop via %s if %u", 
                                   inet_ntoa (nexthop->gate.ipv4), 
                                   nexthop->ifindex); 
                    } 
#ifdef HAVE_IPV6 
                  if (nexthop->type == NEXTHOP_TYPE_IPV6 
                      || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME 
                      || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) 
                    {  
                      rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY, 
                                     &nexthop->gate.ipv6, bytelen); 
 
                      if (IS_ZEBRA_DEBUG_KERNEL) 
                        zlog_debug("netlink_route_multipath() (multihop): " 
                                   "nexthop via %s if %u", 
                                   inet6_ntoa (nexthop->gate.ipv6), 
                                   nexthop->ifindex); 
                    } 
#endif /* HAVE_IPV6 */ 
                  /* ifindex */ 
                  if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX 
                      || nexthop->type == NEXTHOP_TYPE_IFINDEX 
                      || nexthop->type == NEXTHOP_TYPE_IFNAME) 
                    { 
                      rtnh->rtnh_ifindex = nexthop->ifindex; 
                      if (nexthop->src.ipv4.s_addr) 
                        src = &nexthop->src; 
                      if (IS_ZEBRA_DEBUG_KERNEL) 
                        zlog_debug("netlink_route_multipath() (multihop): " 
                                   "nexthop via if %u", nexthop->ifindex); 
                    } 
                  else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME 
                      || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) 
                    { 
                      rtnh->rtnh_ifindex = nexthop->ifindex; 
 
                      if (IS_ZEBRA_DEBUG_KERNEL) 
                        zlog_debug("netlink_route_multipath() (multihop): " 
                                   "nexthop via if %u", nexthop->ifindex); 
                    } 
                  else 
                    { 
                      rtnh->rtnh_ifindex = 0; 
                    } 
                } 
               rtnh = RTNH_NEXT (rtnh);                rtnh = RTNH_NEXT (rtnh);
   
               if (cmd == RTM_NEWROUTE)                if (cmd == RTM_NEWROUTE)
Line 1835  skip: Line 1856  skip:
   snl.nl_family = AF_NETLINK;    snl.nl_family = AF_NETLINK;
   
   /* Talk to netlink socket. */    /* Talk to netlink socket. */
  return netlink_talk (&req.n, &netlink_cmd);  return netlink_talk (&req.n, &zvrf->netlink_cmd, zvrf);
 }  }
   
 int  int
kernel_add_ipv4 (struct prefix *p, struct rib *rib)kernel_route_rib (struct prefix *p, struct rib *old, struct rib *new)
 {  {
  return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET);  if (!old && new)
}    return netlink_route_multipath (RTM_NEWROUTE, p, new);
   if (old && !new)
     return netlink_route_multipath (RTM_DELROUTE, p, old);
   
int   /* Replace, can be done atomically if metric does not change;
kernel_delete_ipv4 (struct prefix *p, struct rib *rib)    * netlink uses [prefix, tos, priority] to identify prefix.
{    * Now metric is not sent to kernel, so we can just do atomic replace. */
  return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET);  return netlink_route_multipath (RTM_NEWROUTE, p, new);
 }  }
   
 #ifdef HAVE_IPV6  
 int  
 kernel_add_ipv6 (struct prefix *p, struct rib *rib)  
 {  
   return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6);  
 }  
   
 int  
 kernel_delete_ipv6 (struct prefix *p, struct rib *rib)  
 {  
   return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6);  
 }  
   
 /* Delete IPv6 route from the kernel. */  
 int  
 kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,  
                         unsigned int index, int flags, int table)  
 {  
   return netlink_route (RTM_DELROUTE, AF_INET6, &dest->prefix,  
                         dest->prefixlen, gate, index, flags, table);  
 }  
 #endif /* HAVE_IPV6 */  
   
 /* Interface address modification. */  /* Interface address modification. */
 static int  static int
 netlink_address (int cmd, int family, struct interface *ifp,  netlink_address (int cmd, int family, struct interface *ifp,
Line 1888  netlink_address (int cmd, int family, struct interface Line 1888  netlink_address (int cmd, int family, struct interface
     char buf[NL_PKT_BUF_SIZE];      char buf[NL_PKT_BUF_SIZE];
   } req;    } req;
   
     struct zebra_vrf *zvrf = vrf_info_lookup (ifp->vrf_id);
   
   p = ifc->address;    p = ifc->address;
   memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE);    memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE);
   
Line 1920  netlink_address (int cmd, int family, struct interface Line 1922  netlink_address (int cmd, int family, struct interface
     addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label,      addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label,
                strlen (ifc->label) + 1);                 strlen (ifc->label) + 1);
   
  return netlink_talk (&req.n, &netlink_cmd);  return netlink_talk (&req.n, &zvrf->netlink_cmd, zvrf);
 }  }
   
 int  int
Line 1942  extern struct thread_master *master; Line 1944  extern struct thread_master *master;
 static int  static int
 kernel_read (struct thread *thread)  kernel_read (struct thread *thread)
 {  {
  netlink_parse_info (netlink_information_fetch, &netlink);  struct zebra_vrf *zvrf = (struct zebra_vrf *)THREAD_ARG (thread);
  thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);  netlink_parse_info (netlink_information_fetch, &zvrf->netlink, zvrf);
   zvrf->t_netlink = thread_add_read (zebrad.master, kernel_read, zvrf,
                                      zvrf->netlink.sock);
   
   return 0;    return 0;
 }  }
Line 1982  static void netlink_install_filter (int sock, __u32 pi Line 1986  static void netlink_install_filter (int sock, __u32 pi
 /* Exported interface function.  This function simply calls  /* Exported interface function.  This function simply calls
    netlink_socket (). */     netlink_socket (). */
 void  void
kernel_init (void)kernel_init (struct zebra_vrf *zvrf)
 {  {
   unsigned long groups;    unsigned long groups;
   
Line 1990  kernel_init (void) Line 1994  kernel_init (void)
 #ifdef HAVE_IPV6  #ifdef HAVE_IPV6
   groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR;    groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR;
 #endif /* HAVE_IPV6 */  #endif /* HAVE_IPV6 */
  netlink_socket (&netlink, groups);  netlink_socket (&zvrf->netlink, groups, zvrf->vrf_id);
  netlink_socket (&netlink_cmd, 0);  netlink_socket (&zvrf->netlink_cmd, 0, zvrf->vrf_id);
   
   /* Register kernel socket. */    /* Register kernel socket. */
  if (netlink.sock > 0)  if (zvrf->netlink.sock > 0)
     {      {
       /* Only want non-blocking on the netlink event socket */        /* Only want non-blocking on the netlink event socket */
      if (fcntl (netlink.sock, F_SETFL, O_NONBLOCK) < 0)      if (fcntl (zvrf->netlink.sock, F_SETFL, O_NONBLOCK) < 0)
        zlog (NULL, LOG_ERR, "Can't set %s socket flags: %s", netlink.name,        zlog_err ("Can't set %s socket flags: %s", zvrf->netlink.name,
                safe_strerror (errno));                  safe_strerror (errno));
   
       /* Set receive buffer size if it's set from command line */        /* Set receive buffer size if it's set from command line */
       if (nl_rcvbufsize)        if (nl_rcvbufsize)
        netlink_recvbuf (&netlink, nl_rcvbufsize);        netlink_recvbuf (&zvrf->netlink, nl_rcvbufsize);
   
      netlink_install_filter (netlink.sock, netlink_cmd.snl.nl_pid);      netlink_install_filter (zvrf->netlink.sock, zvrf->netlink_cmd.snl.nl_pid);
      thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);      zvrf->t_netlink = thread_add_read (zebrad.master, kernel_read, zvrf,
                                          zvrf->netlink.sock);
     }
 }
 
 void
 kernel_terminate (struct zebra_vrf *zvrf)
 {
   THREAD_READ_OFF (zvrf->t_netlink);
 
   if (zvrf->netlink.sock >= 0)
     {
       close (zvrf->netlink.sock);
       zvrf->netlink.sock = -1;
     }
 
   if (zvrf->netlink_cmd.sock >= 0)
     {
       close (zvrf->netlink_cmd.sock);
       zvrf->netlink_cmd.sock = -1;
     }      }
 }  }
   

Removed from v.1.1.1.3  
changed lines
  Added in v.1.1.1.4


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>