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
This commit is contained in:
vivek 2016-04-19 23:08:10 +00:00 committed by Donald Sharp
parent a22f3f5dad
commit c0f4be83a1
5 changed files with 235 additions and 40 deletions

View File

@ -129,6 +129,9 @@ copy_nexthops (struct nexthop **tnh, struct nexthop *nh)
nexthop->ifindex = nh->ifindex;
memcpy(&(nexthop->gate), &(nh->gate), sizeof(union g_addr));
memcpy(&(nexthop->src), &(nh->src), sizeof(union g_addr));
if (nh->nh_label)
nexthop_add_labels (nexthop, nh->nh_label->num_labels,
&nh->nh_label->label[0]);
nexthop_add(tnh, nexthop);
if (CHECK_FLAG(nh1->flags, NEXTHOP_FLAG_RECURSIVE))

View File

@ -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);
}
/* 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);
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;
}
}
}

View File

@ -204,6 +204,9 @@ rib_copy_nexthops (struct rib *rib, struct nexthop *nh)
nexthop->ifindex = nh->ifindex;
memcpy(&(nexthop->gate), &(nh->gate), sizeof(union g_addr));
memcpy(&(nexthop->src), &(nh->src), sizeof(union g_addr));
if (nh->nh_label)
nexthop_add_labels (nexthop, nh->nh_label->num_labels,
&nh->nh_label->label[0]);
rib_nexthop_add(rib, nexthop);
if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE))
copy_nexthops(&nexthop->resolved, nh->resolved);

View File

@ -42,6 +42,7 @@ static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_ro
struct route_node *rn;
struct route_table *table;
struct prefix nh_p;
struct nexthop *nexthop = NULL;
/* Lookup table. */
table = zebra_vrf_table (afi, safi, si->vrf_id);
@ -71,29 +72,34 @@ static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_ro
switch (si->type)
{
case STATIC_IPV4_GATEWAY:
rib_nexthop_ipv4_add (rib, &si->addr.ipv4, NULL);
nexthop = rib_nexthop_ipv4_add (rib, &si->addr.ipv4, NULL);
nh_p.family = AF_INET;
nh_p.prefixlen = IPV4_MAX_BITLEN;
nh_p.u.prefix4 = si->addr.ipv4;
zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn);
break;
case STATIC_IFINDEX:
rib_nexthop_ifindex_add (rib, si->ifindex);
nexthop = rib_nexthop_ifindex_add (rib, si->ifindex);
break;
case STATIC_IPV4_BLACKHOLE:
rib_nexthop_blackhole_add (rib);
nexthop = rib_nexthop_blackhole_add (rib);
break;
case STATIC_IPV6_GATEWAY:
rib_nexthop_ipv6_add (rib, &si->addr.ipv6);
nexthop = rib_nexthop_ipv6_add (rib, &si->addr.ipv6);
nh_p.family = AF_INET6;
nh_p.prefixlen = IPV6_MAX_BITLEN;
nh_p.u.prefix6 = si->addr.ipv6;
zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn);
break;
case STATIC_IPV6_GATEWAY_IFINDEX:
rib_nexthop_ipv6_ifindex_add (rib, &si->addr.ipv6, si->ifindex);
nexthop = rib_nexthop_ipv6_ifindex_add (rib, &si->addr.ipv6,
si->ifindex);
break;
}
/* Update label(s), if present. */
if (si->snh_label.num_labels)
nexthop_add_labels (nexthop, si->snh_label.num_labels,
&si->snh_label.label[0]);
if (IS_ZEBRA_DEBUG_RIB)
{
@ -130,29 +136,34 @@ static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_ro
switch (si->type)
{
case STATIC_IPV4_GATEWAY:
rib_nexthop_ipv4_add (rib, &si->addr.ipv4, NULL);
nexthop = rib_nexthop_ipv4_add (rib, &si->addr.ipv4, NULL);
nh_p.family = AF_INET;
nh_p.prefixlen = IPV4_MAX_BITLEN;
nh_p.u.prefix4 = si->addr.ipv4;
zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn);
break;
case STATIC_IFINDEX:
rib_nexthop_ifindex_add (rib, si->ifindex);
nexthop = rib_nexthop_ifindex_add (rib, si->ifindex);
break;
case STATIC_IPV4_BLACKHOLE:
rib_nexthop_blackhole_add (rib);
nexthop = rib_nexthop_blackhole_add (rib);
break;
case STATIC_IPV6_GATEWAY:
rib_nexthop_ipv6_add (rib, &si->addr.ipv6);
nexthop = rib_nexthop_ipv6_add (rib, &si->addr.ipv6);
nh_p.family = AF_INET6;
nh_p.prefixlen = IPV6_MAX_BITLEN;
nh_p.u.prefix6 = si->addr.ipv6;
zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn);
break;
case STATIC_IPV6_GATEWAY_IFINDEX:
rib_nexthop_ipv6_ifindex_add (rib, &si->addr.ipv6, si->ifindex);
nexthop = rib_nexthop_ipv6_ifindex_add (rib, &si->addr.ipv6,
si->ifindex);
break;
}
/* Update label(s), if present. */
if (si->snh_label.num_labels)
nexthop_add_labels (nexthop, si->snh_label.num_labels,
&si->snh_label.label[0]);
/* Save the flags of this static routes (reject, blackhole) */
rib->flags = si->flags;
@ -181,30 +192,59 @@ static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_ro
}
}
static int
static_nexthop_label_same (struct nexthop *nexthop,
struct static_nh_label *snh_label)
{
int i;
if ((snh_label->num_labels == 0 && nexthop->nh_label) ||
(snh_label->num_labels != 0 && !nexthop->nh_label))
return 0;
if (snh_label->num_labels != 0)
if (snh_label->num_labels != nexthop->nh_label->num_labels)
return 0;
for (i = 0; i < snh_label->num_labels; i++)
if (snh_label->label[i] != nexthop->nh_label->label[i])
return 0;
return 1;
}
static int
static_nexthop_same (struct nexthop *nexthop, struct static_route *si)
{
if (nexthop->type == NEXTHOP_TYPE_IPV4
&& si->type == STATIC_IPV4_GATEWAY
&& IPV4_ADDR_SAME (&nexthop->gate.ipv4, &si->addr.ipv4))
return 1;
if (nexthop->type == NEXTHOP_TYPE_IFINDEX
&& si->type == STATIC_IFINDEX
&& nexthop->ifindex == si->ifindex)
return 1;
int gw_match = 0;
if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE
&& si->type == STATIC_IPV4_BLACKHOLE)
return 1;
if (nexthop->type == NEXTHOP_TYPE_IPV6
if (nexthop->type == NEXTHOP_TYPE_IPV4
&& si->type == STATIC_IPV4_GATEWAY
&& IPV4_ADDR_SAME (&nexthop->gate.ipv4, &si->addr.ipv4))
gw_match = 1;
else if (nexthop->type == NEXTHOP_TYPE_IFINDEX
&& si->type == STATIC_IFINDEX
&& nexthop->ifindex == si->ifindex)
gw_match = 1;
else if (nexthop->type == NEXTHOP_TYPE_IPV6
&& si->type == STATIC_IPV6_GATEWAY
&& IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->addr.ipv6))
return 1;
if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
gw_match = 1;
else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
&& si->type == STATIC_IPV6_GATEWAY_IFINDEX
&& IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->addr.ipv6)
&& nexthop->ifindex == si->ifindex)
return 1;
return 0;
gw_match = 1;
if (!gw_match)
return 0;
/* Check match on label(s), if any */
return static_nexthop_label_same (nexthop, &si->snh_label);
}
/* Uninstall static route from RIB. */

View File

@ -2318,6 +2318,15 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, int mcast)
default:
break;
}
/* Label information */
if (nexthop->nh_label && nexthop->nh_label->num_labels)
{
vty_out (vty, " label %s",
mpls_label2str (nexthop->nh_label->num_labels,
nexthop->nh_label->label, buf, BUFSIZ));
}
vty_out (vty, "%s", VTY_NEWLINE);
}
vty_out (vty, "%s", VTY_NEWLINE);
@ -2558,6 +2567,14 @@ vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib,
break;
}
/* Label information */
if (nexthop->nh_label && nexthop->nh_label->num_labels)
{
vty_out (vty, " label %s",
mpls_label2str (nexthop->nh_label->num_labels,
nexthop->nh_label->label, buf, BUFSIZ));
}
if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE))
vty_out (vty, ", bh");
if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_REJECT))