]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Nest: Multicast net parsing and MIF managing
authorOndrej Zajicek (work) <santiago@crfreenet.org>
Thu, 22 Feb 2018 15:51:43 +0000 (16:51 +0100)
committerOndrej Zajicek (work) <santiago@crfreenet.org>
Thu, 22 Feb 2018 15:51:43 +0000 (16:51 +0100)
conf/confbase.Y
lib/birdlib.h
lib/net.c
lib/net.h
nest/iface.c
nest/iface.h
nest/route.h
nest/rt-show.c

index 7e0537c5b8398131c05193979315ae20ae8c7967..7cc74cf39cc9da14e2b04e331ff9701f6a4e8476 100644 (file)
@@ -83,7 +83,7 @@ CF_DECLS
 %type <time> expr_us time
 %type <a> ipa
 %type <net> net_ip4_ net_ip6_ net_ip6 net_ip_ net_ip net_or_ipa
-%type <net_ptr> net_ net_any net_vpn4_ net_vpn6_ net_vpn_ net_roa4_ net_roa6_ net_roa_ net_mpls_
+%type <net_ptr> net_ net_any net_vpn4_ net_vpn6_ net_vpn_ net_roa4_ net_roa6_ net_roa_ net_mreq4_ net_mreq6_ net_mreq_ net_mgrp4_ net_mgrp6_ net_mgrp_ net_mpls_
 %type <mls> label_stack_start label_stack
 
 %type <t> text opttext
@@ -234,6 +234,30 @@ net_roa6_: net_ip6_ MAX NUM AS NUM
     cf_error("Invalid max prefix length %u", $3);
 };
 
+net_mreq4_: MREQ4 '(' '*' ',' IP4 ')'
+{
+  $$ = cfg_alloc(sizeof(net_addr_mreq4));
+  net_fill_mreq4($$, $5, 0); // XXXX
+}
+
+net_mreq6_: MREQ6 '(' '*' ',' IP6 ')'
+{
+  $$ = cfg_alloc(sizeof(net_addr_mreq6));
+  net_fill_mreq6($$, $5, 0); // XXXX
+}
+
+net_mgrp4_: MGRP4 '(' '*' ',' IP4 ')'
+{
+  $$ = cfg_alloc(sizeof(net_addr_mgrp4));
+  net_fill_mgrp4($$, $5);
+}
+
+net_mgrp6_: MGRP6 '(' '*' ',' IP6 ')'
+{
+  $$ = cfg_alloc(sizeof(net_addr_mgrp6));
+  net_fill_mgrp6($$, $5);
+}
+
 net_mpls_: MPLS NUM
 {
   $$ = cfg_alloc(sizeof(net_addr_roa6));
@@ -243,12 +267,16 @@ net_mpls_: MPLS NUM
 net_ip_: net_ip4_ | net_ip6_ ;
 net_vpn_: net_vpn4_ | net_vpn6_ ;
 net_roa_: net_roa4_ | net_roa6_ ;
+net_mreq_: net_mreq4_ | net_mreq6_ ;
+net_mgrp_: net_mgrp4_ | net_mgrp6_ ;
 
 net_:
    net_ip_ { $$ = cfg_alloc($1.length); net_copy($$, &($1)); }
  | net_vpn_
  | net_roa_
  | net_flow_
+ | net_mreq_
+ | net_mgrp_
  | net_mpls_
  ;
 
index 428b3209ff8c542ad4c8a1d39de79cfd00c3d776..601cae58b719be63a910e9f46e4169ca85f82a56 100644 (file)
@@ -40,6 +40,9 @@ struct align_probe { char x; long int y; };
 #define CALL(fn, args...) ({ if (fn) fn(args); })
 #define ADVANCE(w, r, l) ({ r -= l; w += l; })
 
+#define WALK_ARRAY(v,l,n) \
+  for (typeof(*(v)) *_n = (v), n; _n < ((v) + (l)) && (n = *_n, 1); _n++)
+
 static inline int uint_cmp(uint i1, uint i2)
 { return (int)(i1 > i2) - (int)(i1 < i2); }
 
index 01af3a4d1694157a446bd53910e91348995d3899..24619fca72432fdd1ac695f5b745e6e6a1bc31ef 100644 (file)
--- a/lib/net.c
+++ b/lib/net.c
@@ -64,8 +64,8 @@ const u16 net_max_text_length[] = {
   [NET_FLOW6]  = 0,    /* "flow6 { ... }" */
   [NET_MREQ4]  = 15,   /* "255.255.255.255" */
   [NET_MREQ6]  = 39,   /* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" */
-  [NET_MGRP4]  = 15,   /* "255.255.255.255" */
-  [NET_MGRP6]  = 39,   /* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" */
+  [NET_MGRP4]  = 20,   /* "(*, 255.255.255.255)" */
+  [NET_MGRP6]  = 44,   /* "(*, ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff)" */
   [NET_MPLS]   = 7,    /* "1048575" */
 };
 
@@ -123,9 +123,9 @@ net_format(const net_addr *N, char *buf, int buflen)
   case NET_MREQ6:
     return bsnprintf(buf, buflen, "%I6", n->mreq6.grp);
   case NET_MGRP4:
-    return bsnprintf(buf, buflen, "%I4", n->mgrp4.grp);
+    return bsnprintf(buf, buflen, "(*, %I4)", n->mgrp4.grp);
   case NET_MGRP6:
-    return bsnprintf(buf, buflen, "%I6", n->mgrp6.grp);
+    return bsnprintf(buf, buflen, "(*, %I6)", n->mgrp6.grp);
   case NET_MPLS:
     return bsnprintf(buf, buflen, "%u", n->mpls.label);
   }
index de25ad6d29d3cc7845038ef4078b85d62eefc128..39f0f905d87d58b88a6c2bed5e54ab9a47696143 100644 (file)
--- a/lib/net.h
+++ b/lib/net.h
 #define NB_MREQ                (NB_MREQ4 | NB_MREQ6)
 #define NB_MGRP                (NB_MGRP4 | NB_MGRP6)
 
+/* FIXME: Better validation of (NET, RTD) combinations */
 #define NB_HOST                (NB_IP | NB_VPN | NB_ROA)
-#define NB_DEST                (NB_IP | NB_VPN | NB_MPLS)
+// #define NB_DEST     (NB_IP | NB_VPN | NB_MPLS)
+#define NB_DEST                (NB_IP | NB_VPN | NB_MGRP | NB_MPLS)
 #define NB_ANY         0xffffffff
 
+#define MIFS_MAX       32
+
 
 typedef struct net_addr {
   u8 type;
index 54c16c583d3ef8fbc284b4bad2ee916801d1f6ba..b165e6e74902dadddb40556cb2893e2e7d72e487 100644 (file)
 static pool *if_pool;
 
 list iface_list;
+struct mif_group *global_mif_group;
 
 static void if_recalc_preferred(struct iface *i);
+static struct mif_group *mif_get_group(void);
 
 /**
  * ifa_dump - dump interface address
@@ -714,6 +716,61 @@ if_init(void)
   if_pool = rp_new(&root_pool, "Interfaces");
   init_list(&iface_list);
   neigh_init(if_pool);
+  global_mif_group = mif_get_group();
+}
+
+/*
+ *     Multicast Ifaces
+ */
+
+static struct mif_group *
+mif_get_group(void)
+{
+  struct mif_group *grp = mb_allocz(if_pool, sizeof(struct mif_group));
+  init_list(&grp->sockets);
+
+  return grp;
+}
+
+static inline int u32_cto(uint x) { return ffs(~x) - 1; }
+
+struct mif *
+mif_get(struct mif_group *grp, struct iface *iface)
+{
+  WALK_ARRAY(grp->mifs, MIFS_MAX, mif)
+    if (mif && (mif->iface == iface))
+      return mif->uc++, mif;
+
+  int i = u32_cto(grp->indexes);
+  if (i < 0)
+    return NULL;
+
+  struct mif *mif = mb_allocz(if_pool, sizeof(struct mif));
+  mif->iface = iface;
+  mif->index = i;
+  mif->uc = 1;
+  init_list(&mif->sockets);
+
+  grp->mifs[mif->index] = mif;
+  MIFS_SET(mif, grp->indexes);
+
+  return mif;
+}
+
+void
+mif_free(struct mif_group *grp, struct mif *mif)
+{
+  if (--mif->uc)
+    return;
+
+  node *n;
+  WALK_LIST_FIRST(n, mif->sockets)
+    rem_node(n);
+
+  grp->mifs[mif->index] = NULL;
+  MIFS_CLR(mif, grp->indexes);
+
+  mb_free(mif);
 }
 
 /*
index ab3f8f351646dd88010e6cee84672c76bd7e54a7..dc44dfadbc1debebb18cdf45834c6f7a48a704aa 100644 (file)
@@ -13,6 +13,7 @@
 #include "lib/ip.h"
 
 extern list iface_list;
+extern struct mif_group *global_mif_group;
 
 struct proto;
 struct pool;
@@ -44,6 +45,20 @@ struct iface {
   list neighbors;                      /* All neighbors on this interface */
 };
 
+struct mif {
+  struct iface *iface;
+  uint index;                          /* MIF (VIF) index for multicast routes */
+  uint uc;                             /* Use count */
+  list sockets;                                /* Listening per-iface IGMP sockets */
+};
+
+struct mif_group {
+  uint indexes;
+  uint uc;                             /* Use count, not implemented */
+  list sockets;                                /* Listening global IGMP sockets */
+  struct mif *mifs[MIFS_MAX];
+};
+
 #define IF_UP 1                                /* Currently just IF_ADMIN_UP */
 #define IF_MULTIACCESS 2
 #define IF_BROADCAST 4
@@ -115,6 +130,13 @@ struct iface *if_find_by_name(char *);
 struct iface *if_get_by_name(char *);
 void if_recalc_all_preferred_addresses(void);
 
+struct mif *mif_get(struct mif_group *grp, struct iface *iface);
+void mif_free(struct mif_group *grp, struct mif *mif);
+
+#define MIFS_SET(mif,m)                ((m) |= (1 << (mif)->index))
+#define MIFS_CLR(mif,m)                ((m) &= ~(1 << (mif)->index))
+#define MIFS_ISSET(mif,m)      ((m) & (1 << (mif)->index))
+
 
 /* The Neighbor Cache */
 
index d47645f8ee1be45aa85dc9cb12363979b07687b6..b2ae4686d72afe36b4db9433b12051b5a80ba718 100644 (file)
@@ -152,6 +152,7 @@ typedef struct rtable {
   int pipe_busy;                       /* Pipe loop detection */
   int use_count;                       /* Number of protocols using this table */
   struct hostcache *hostcache;
+  // struct mif_group *mif_group;
   struct rtable_config *config;                /* Configuration of this table */
   struct config *deleted;              /* Table doesn't exist in current configuration,
                                         * delete as soon as use_count becomes 0 and remove
@@ -249,9 +250,6 @@ typedef struct rte {
       u8 best;                         /* Best route in network, propagated to core */
       u32 metric;                      /* Kernel metric */
     } krt;
-    struct {
-      u32 iifs, oifs;                  /* Bitmaps for iifs and oifs. Use RTE_MGRP_* macros to manipulate. */
-    } mkrt;
   } u;
 } rte;
 
@@ -637,6 +635,19 @@ rta_set_recursive_next_hop(rtable *dep, rta *a, rtable *tab, ip_addr gw, ip_addr
   rta_apply_hostentry(a, rt_get_hostentry(tab, gw, ll, dep), mls);
 }
 
+/* For RTD_MULTICAST, we encode iifs and oifs to nh.gw */
+static inline u32 rta_iifs(rta *a)
+{ return _I0(a->nh.gw); }
+
+static inline void rta_set_iifs(rta *a, u32 val)
+{ _I0(a->nh.gw) = val; }
+
+static inline u32 rta_oifs(rta *a)
+{ return _I1(a->nh.gw); }
+
+static inline void rta_set_oifs(rta *a, u32 val)
+{ _I1(a->nh.gw) = val; }
+
 /*
  * rta_set_recursive_next_hop() acquires hostentry from hostcache and fills
  * rta->hostentry field.  New hostentry has zero use count. Cached rta locks its
index 41a141a2602d6f8cf7d985041f5cebe9a551c6ce..b8366881b91d3a12fb710ede9dcf6814ccd35a29 100644 (file)
@@ -28,6 +28,30 @@ rt_show_table(struct cli *c, struct rt_show_data *d)
   d->last_table = d->tab;
 }
 
+static void
+rt_show_mifs(char *key, struct mif_group *grp, u32 mifs)
+{
+  uint blen = 512;
+  char *buf = alloca(blen + 8);
+  char *pos = buf;
+  pos[0] = 0;
+
+  WALK_ARRAY(grp->mifs, MIFS_MAX, mif)
+    if (mif && MIFS_ISSET(mif, mifs))
+    {
+      int i = bsnprintf(pos, blen, " %s", mif->iface->name);
+      if (i < 0)
+      {
+       bsprintf(pos, " ...");
+       break;
+      }
+
+      ADVANCE(pos, blen, i);
+    }
+
+  cli_msg(-1007, "%s%s", key, buf);
+}
+
 static void
 rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tmpa)
 {
@@ -92,6 +116,12 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tm
                   nh->iface->name, mpls,  onlink, weight);
     }
 
+  if (a->dest == RTD_MULTICAST)
+    {
+      rt_show_mifs("\tfrom", global_mif_group, rta_iifs(a));
+      rt_show_mifs("\tto", global_mif_group, rta_oifs(a));
+    }
+
   if (d->verbose)
     rta_show(c, a, tmpa);
 }