diff options
| author | vivek <vivek@cumulusnetworks.com> | 2016-04-19 23:08:10 +0000 | 
|---|---|---|
| committer | Donald Sharp <sharpd@cumulusnetworks.com> | 2016-09-23 09:31:02 -0400 | 
| commit | c0f4be83a11c22ff7e9920fc44ebc015d5b1f776 (patch) | |
| tree | d350ca54d663f07ea59610fd0d1c5fd239194c4d /zebra/rt_netlink.c | |
| parent | a22f3f5dadce22784157cdef9b150114b894fd70 (diff) | |
MPLS: Install labeled static routes
This patch installs labeled static routes in the FIB. The routes are installed
using the RTA_ENCAP (and RTA_ENCAP_TYPE) nested attributes.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by:   Donald Sharp <sharpd@cumulusnetworks.com>
Ticket: CM-6040
Reviewed By: CCR-3091
Testing Done: Tested in SE-1, brief manual testing now
Diffstat (limited to 'zebra/rt_netlink.c')
| -rw-r--r-- | zebra/rt_netlink.c | 166 | 
1 files changed, 149 insertions, 17 deletions
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 8d19cbb5dc..3b564f2b15 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -77,12 +77,28 @@ static const struct message nlmsg_str[] = {  #endif  #ifndef RTA_VIA -#define RTA_VIA		16 +#define RTA_VIA		18  #endif  #ifndef RTA_NEWDST  #define RTA_NEWDST	19  #endif + +#ifndef RTA_ENCAP_TYPE +#define RTA_ENCAP_TYPE	21 +#endif + +#ifndef RTA_ENCAP +#define RTA_ENCAP	22 +#endif + +#ifndef LWTUNNEL_ENCAP_MPLS +#define LWTUNNEL_ENCAP_MPLS  1 +#endif + +#ifndef MPLS_IPTUNNEL_DST +#define MPLS_IPTUNNEL_DST  1 +#endif  /* End of temporary definitions */  struct gw_family_t @@ -1720,6 +1736,39 @@ addattr32 (struct nlmsghdr *n, unsigned int maxlen, int type, int data)    return addattr_l(n, maxlen, type, &data, sizeof(u_int32_t));  } +/* Some more utility functions from iproute2 */ +static struct rtattr * +addattr_nest(struct nlmsghdr *n, int maxlen, int type) +{ +  struct rtattr *nest = NLMSG_TAIL(n); + +  addattr_l(n, maxlen, type, NULL, 0); +  return nest; +} + +static int +addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest) +{ +  nest->rta_len = NLMSG_TAIL(n) - nest; +  return n->nlmsg_len; +} + +static struct rtattr * +rta_nest(struct rtattr *rta, int maxlen, int type) +{ +  struct rtattr *nest = RTA_TAIL(rta); + +  rta_addattr_l(rta, maxlen, type, NULL, 0); +  return nest; +} + +static int +rta_nest_end(struct rtattr *rta, struct rtattr *nest) +{ +  nest->rta_len = RTA_TAIL(rta) - nest; +  return rta->rta_len; +} +  static int  netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h,      ns_id_t ns_id) @@ -1865,7 +1914,8 @@ _netlink_route_build_singlepath(          size_t req_size,  	int cmd)  { -  mpls_lse_t out_lse; +  struct nexthop_label *nh_label; +  mpls_lse_t out_lse[MPLS_MAX_LABELS];    char label_buf[100];    if (rtmsg->rtm_family == AF_INET && @@ -1895,16 +1945,55 @@ _netlink_route_build_singlepath(      }    label_buf[0] = '\0'; +  /* outgoing label - either as NEWDST (in the case of LSR) or as ENCAP +   * (in the case of LER) +   */ +  nh_label = nexthop->nh_label;    if (rtmsg->rtm_family == AF_MPLS)      { -      assert (nexthop->nh_label); +      assert (nh_label); +      assert (nh_label->num_labels == 1); +    } -      /* Fill out label, if present. */ -      if (nexthop->nh_label->label[0] != MPLS_IMP_NULL_LABEL) +  if (nh_label && nh_label->num_labels) +    { +      int i, num_labels = 0; +      u_int32_t bos; +      char label_buf1[20]; +  +      for (i = 0; i < nh_label->num_labels; i++)          { -          out_lse = mpls_lse_encode (nexthop->nh_label->label[0], 0, 0, 1); -          addattr_l (nlmsg, req_size, RTA_NEWDST, &out_lse, sizeof(mpls_lse_t)); -          sprintf (label_buf, "label %d", nexthop->nh_label->label[0]); +          if (nh_label->label[i] != MPLS_IMP_NULL_LABEL) +            { +              bos = ((i == (nh_label->num_labels - 1)) ? 1 : 0); +              out_lse[i] = mpls_lse_encode (nh_label->label[i], 0, 0, bos); +              if (!num_labels) +                sprintf (label_buf, "label %d", nh_label->label[i]); +              else +                { +                  sprintf (label_buf1, "/%d", nh_label->label[i]); +                  strcat (label_buf, label_buf1); +                } +              num_labels++; +            } +        } +      if (num_labels) +        { +          if (rtmsg->rtm_family == AF_MPLS) +            addattr_l (nlmsg, req_size, RTA_NEWDST, +                       &out_lse, num_labels * sizeof(mpls_lse_t)); +          else +            { +              struct rtattr *nest; +              u_int16_t encap = LWTUNNEL_ENCAP_MPLS; + +              addattr_l(nlmsg, req_size, RTA_ENCAP_TYPE, +                        &encap, sizeof (u_int16_t)); +              nest = addattr_nest(nlmsg, req_size, RTA_ENCAP); +              addattr_l (nlmsg, req_size, MPLS_IPTUNNEL_DST, +                         &out_lse, num_labels * sizeof(mpls_lse_t)); +              addattr_nest_end(nlmsg, nest); +            }          }      } @@ -2023,7 +2112,8 @@ _netlink_route_build_multipath(          struct rtmsg *rtmsg,          union g_addr **src)  { -  mpls_lse_t out_lse; +  struct nexthop_label *nh_label; +  mpls_lse_t out_lse[MPLS_MAX_LABELS];    char label_buf[100];    rtnh->rtnh_len = sizeof (*rtnh); @@ -2059,18 +2149,60 @@ _netlink_route_build_multipath(      }    label_buf[0] = '\0'; +  /* outgoing label - either as NEWDST (in the case of LSR) or as ENCAP +   * (in the case of LER) +   */ +  nh_label = nexthop->nh_label;    if (rtmsg->rtm_family == AF_MPLS)      { -      assert (nexthop->nh_label); +      assert (nh_label); +      assert (nh_label->num_labels == 1); +    } + +  if (nh_label && nh_label->num_labels) +    { +      int i, num_labels = 0; +      u_int32_t bos; +      char label_buf1[20]; -      /* Fill out label, if present. */ -      if (nexthop->nh_label->label[0] != MPLS_IMP_NULL_LABEL) +      for (i = 0; i < nh_label->num_labels; i++)          { -          out_lse = mpls_lse_encode (nexthop->nh_label->label[0], 0, 0, 1); -          rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_NEWDST, -                         &out_lse, sizeof(mpls_lse_t)); -          rtnh->rtnh_len += RTA_LENGTH (sizeof(mpls_lse_t)); -          sprintf (label_buf, "label %d", nexthop->nh_label->label[0]); +          if (nh_label->label[i] != MPLS_IMP_NULL_LABEL) +            { +              bos = ((i == (nh_label->num_labels - 1)) ? 1 : 0); +              out_lse[i] = mpls_lse_encode (nh_label->label[i], 0, 0, bos); +              if (!num_labels) +                sprintf (label_buf, "label %d", nh_label->label[i]); +              else +                { +                  sprintf (label_buf1, "/%d", nh_label->label[i]); +                  strcat (label_buf, label_buf1); +                } +              num_labels++; +            } +        } +      if (num_labels) +        { +          if (rtmsg->rtm_family == AF_MPLS) +            { +              rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_NEWDST, +                             &out_lse, num_labels * sizeof(mpls_lse_t)); +              rtnh->rtnh_len += RTA_LENGTH (num_labels * sizeof(mpls_lse_t)); +            } +          else +            { +              struct rtattr *nest; +              u_int16_t encap = LWTUNNEL_ENCAP_MPLS; +              int len = rta->rta_len; + +              rta_addattr_l(rta, NL_PKT_BUF_SIZE, RTA_ENCAP_TYPE, +                            &encap, sizeof (u_int16_t)); +              nest = rta_nest(rta, NL_PKT_BUF_SIZE, RTA_ENCAP); +              rta_addattr_l (rta, NL_PKT_BUF_SIZE, MPLS_IPTUNNEL_DST, +                             &out_lse, num_labels * sizeof(mpls_lse_t)); +              rta_nest_end(rta, nest); +              rtnh->rtnh_len += rta->rta_len - len; +            }          }      }  | 
