Commit ec11f992 authored by Jan Moskyto Matejka's avatar Jan Moskyto Matejka
Browse files

MPLS: RTA_ENCAP parsing in netlink interface

parent 45f01fb3
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -194,7 +194,7 @@ net_classify(const net_addr *N)
    return ip6_zero(n->ip6.prefix) ? (IADDR_HOST | SCOPE_UNIVERSE) : ip6_classify(&n->ip6.prefix);

  case NET_MPLS:
    return IADDR_HOST | SCOPE_SITE;
    return IADDR_HOST | SCOPE_UNIVERSE;
  }

  return IADDR_INVALID;
+39 −17
Original line number Diff line number Diff line
@@ -64,10 +64,6 @@
#define RTA_ENCAP  22
#endif

#ifndef AF_MPLS
#define AF_MPLS	 28
#endif

/*
 *	Synchronous Netlink interface
 */
@@ -283,6 +279,10 @@ static struct nl_want_attrs mpnh_attr_want4[BIRD_RTA_MAX] = {
  [RTA_GATEWAY]	  = { 1, 1, sizeof(ip4_addr) },
};

static struct nl_want_attrs encap_mpls_want[BIRD_RTA_MAX] = {
  [RTA_DST]       = { 1, 0, 0 },
};

static struct nl_want_attrs rtm_attr_want4[BIRD_RTA_MAX] = {
  [RTA_DST]	  = { 1, 1, sizeof(ip4_addr) },
  [RTA_OIF]	  = { 1, 1, sizeof(u32) },
@@ -1027,6 +1027,21 @@ mpls_from_ea(struct adata *ad) {
  return s;
}

#define mpls_to_ea(ms, oea) do { \
  ea_list *ea = alloca(sizeof(ea_list) + sizeof(eattr)); \
  ea->next = oea; \
  oea = ea; \
  ea->flags = EALF_SORTED; \
  ea->count = 1; \
  ea->attrs[0].id = EA_GEN_MPLS_STACK; \
  ea->attrs[0].flags = 0; \
  ea->attrs[0].type = EAF_TYPE_INT_SET; \
  ea->attrs[0].u.ptr = alloca(sizeof(struct adata) + sizeof(u32)*ms.len); \
  ea->attrs[0].u.ptr->length = sizeof(u32)*ms.len; \
  for (int j = 0; j < ms.len; j++) \
    ((u32 *)ea->attrs[0].u.ptr->data)[j] = ms.label[j]; \
} while (0)

static int
nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int new)
{
@@ -1235,7 +1250,7 @@ nl_parse_route(struct nlmsghdr *h, int scan)
    SKIP("RTM_DELROUTE in scan\n");

  int c = net_classify(&dst);
  if (i->rtm_family != AF_MPLS && ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK)))
  if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
    SKIP("strange class/scope\n");

  // ignore rtm_scope, it is not a real scope
@@ -1355,19 +1370,26 @@ nl_parse_route(struct nlmsghdr *h, int scan)
  if ((i->rtm_family == AF_MPLS) && a[RTA_NEWDST])
    {
      mpls_stack ms = rta_get_mpls(a[RTA_NEWDST]);
      mpls_to_ea(ms, ra.eattrs);
    }

      ea_list *ea = alloca(sizeof(ea_list) + sizeof(eattr));
      ea->next = ra.eattrs;
      ra.eattrs = ea;
      ea->flags = EALF_SORTED;
      ea->count = 1;
      ea->attrs[0].id = EA_KRT_PREFSRC;
      ea->attrs[0].flags = 0;
      ea->attrs[0].type = EAF_TYPE_INT_SET;
      ea->attrs[0].u.ptr = alloca(sizeof(struct adata) + sizeof(u32)*ms.len);
      ea->attrs[0].u.ptr->length = sizeof(u32)*ms.len;
      for (int j = 0; j < ms.len; j++)
	((u32 *)ea->attrs[0].u.ptr->data)[j] = ms.label[j];
  if (a[RTA_ENCAP] && a[RTA_ENCAP_TYPE])
    {
      switch (*((u16*) RTA_DATA(a[RTA_ENCAP_TYPE])))
	{
	  case LWTUNNEL_ENCAP_MPLS:
	    {
	      struct rtattr *enca[BIRD_RTA_MAX];
	      nl_attr_len = RTA_PAYLOAD(a[RTA_ENCAP]);
	      nl_parse_attrs(RTA_DATA(a[RTA_ENCAP]), encap_mpls_want, enca, sizeof(enca));
	      mpls_stack ms = rta_get_mpls(enca[RTA_DST]);
	      mpls_to_ea(ms, ra.eattrs);
	      break;
	    }
	  default:
	    SKIP("unknown encapsulation method %d\n", *((u16*) RTA_DATA(a[RTA_ENCAP_TYPE])));
	    break;
	}
    }

  if (a[RTA_PREFSRC])