wiki.slank.dev Logo
latest

netlink book

  • Structure Types and Enums Cheatsheet
  • Netlink Configuration Examples
    • base code
    • get genl family id
    • sr tunsrc show
    • ip route add encap seg6
    • ip route add encap seg6local End
    • ip route add encap seg6local End.X
    • ip route add encap seg6local End.T
    • ip route add encap seg6local End.DX4
    • ip {-6|-4} route {add|del} via NH
    • ip link
    • ip nexthop
  • Netlink Helper inline functions
  • Hexdump util c-func
  • FRR/ZEBRA Internals
  • FRR/BGPd Internals
  • Netlink Book :: はじめに
  • Netlink Book :: Netlinkとはなにか

system software

  • Linux
  • KVM
  • QEMU
  • BPF (eBPF / bpftools / BCC)
  • DPDK
  • OpenStack
  • Vagrant
  • ipftrace

misc

  • Prometheus
  • Consul
  • Ansible
  • jq
  • etcd
  • python
  • Xmonadの環境構築
  • sshでの作業
  • 実機での作業
  • トラブルシューティング
  • MBP用の設定
  • VPP
  • Tshark / tshark
  • Trex: Software Traffic Generator by cisco
  • Docker
  • LXD/LXC
  • Kubernetes
  • Arch Linux インストールバトル 2015/09/08
  • Linuxカーネル構築の伝統的方法
  • performance tools
  • TestPMD
  • ISC-DHCP server
  • Open vSwitch
  • OVS-dpdk
  • Pktgen-DPDK
  • Spirent
  • OpenVPN
  • すべてのパケットをキャプチャする
  • GoBGP
  • nginx / NGINX
  • gRPC c++ usage
  • Sphinx ドキュメント
  • CPUクロック速度の設定
  • Graphviz
  • Systemtap導入方法
  • valgring つかってみた
  • Wordpressの環境構築
  • WordPressのバックアップの手順
  • WordPressのコンテンツ復元の手順
  • DC作業KIT
  • life-tips

Linux Distribution

  • Debian Package

NOS / Network OS

  • VyOS Setup
  • Cisco 1812J
  • JUNOS
  • Cisco IOS / IOS-XR / IOS-XE
  • Cumulus Linux
  • FRR / Quagga

Sehll

  • Zshチートシート
  • Bash Cheatsheet

Unix tools

  • Mutt
  • OpenSSL
  • Gnuplot
  • Xclip
  • Travis-CI使い方
  • SSH Cheatsheet
  • GCCチートシート
  • GDB
  • Git Command チートシート
  • GNU Global Cheatsheet
  • Make チートシート
  • objdumpチートシート
  • Options
  • Xコマンドチートシート
  • Tmux
  • Vim
  • Regex Cheatsheet
  • cpupower 使い方
  • 研究室サーバ SSH ユーザ追加手順
  • Asmメモ
  • Mount Command Cheatsheet
  • RCS (Revision Control System)
  • Docker Command

Markup Language

  • Markdown 記法チートシート
  • ReST形式チートシート
  • Pandoc
  • Doxygen 使い方
  • TeX環境構築

Programming Language

  • matplotlib
  • Go lang
  • Coq
wiki.slank.dev
  • Docs »
  • Netlink Configuration Examples
  • Edit on GitHub

Netlink Configuration Examples¶

base code¶

rtnl

#include "hexdump.h"
#include "netlink.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netinet/in.h>

void main() {
  int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
  if (fd < 0)
    exit(1);

  ...(snip)...

  close(fd);
}

genl

#include "hexdump.h"
#include "netlink.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netinet/in.h>

void main() {
  int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
  if (fd < 0)
    exit(1);

  ...(snip)...

  close(fd);
}

get genl family id¶

static int get_family(int fd, const char *family_name)
{
  GENL_REQUEST(req, 1024, GENL_ID_CTRL, 0,
      2, CTRL_CMD_GETFAMILY, NLM_F_REQUEST);
  addattrstrz(&req.n, 1024, CTRL_ATTR_FAMILY_NAME, family_name);

  char buf[10000];
  struct nlmsghdr *answer = (struct nlmsghdr*)buf;
  if (nl_talk(fd, &req.n, answer, sizeof(buf)) < 0)
    exit(1);

  int genl_family = -1;
  memcpy(&req, answer, sizeof(req));
  int len = req.n.nlmsg_len;
  if (NLMSG_OK(&req.n, len) ) {
    struct rtattr *rta[CTRL_ATTR_MAX + 1] = {};
    int l = req.n.nlmsg_len - NLMSG_LENGTH(sizeof(struct genlmsghdr));
    parse_rtattr(rta, CTRL_ATTR_MAX, (struct rtattr*)req.buf, l);

    if(rta[CTRL_ATTR_FAMILY_ID]) {
      uint16_t id = rta_getattr_u16(rta[CTRL_ATTR_FAMILY_ID]);
      genl_family = id;
    }
  }
        return genl_family;
}

void main() {
  int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
  int genl_family = get_family(fd, "SEG6");
  printf("family_id: %d\n", genl_family);
  close(fd);
}

sr tunsrc show¶

static void show_sr_tunsrc(int fd, int genl_family)
{
  GENL_REQUEST(req, 1024, genl_family, 0,
      SEG6_GENL_VERSION, SEG6_CMD_GET_TUNSRC, NLM_F_REQUEST);

  char buf[10000];
  struct nlmsghdr *answer = (struct nlmsghdr*)buf;
  if (nl_talk(fd, &req.n, answer, sizeof(buf)) < 0)
    exit(1);

  memcpy(&req, answer, sizeof(req));
  int len = req.n.nlmsg_len;
  if (NLMSG_OK(&req.n, len) ) {
    struct rtattr *rta[CTRL_ATTR_MAX + 1] = {};
    int l = req.n.nlmsg_len - NLMSG_LENGTH(sizeof(struct genlmsghdr));
    parse_rtattr(rta, CTRL_ATTR_MAX, (struct rtattr*)req.buf, l);

    if(rta[SEG6_ATTR_DST]) {
      const struct in6_addr *dst = RTA_DATA(rta[SEG6_ATTR_DST]);
      char str[128];
      inet_ntop(AF_INET6, dst, str, sizeof(str));
      printf("SRC: %s\n", str);
    }
  }
}

void main() {
  int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
  int genl_family = get_family(fd, "SEG6");
  show_sr_tunsrc(fd, genl_family);
  close(fd);
}

## sr tunsrc set

static void set_sr_tunsrc(int fd, int genl_family, struct in6_addr *src)
{
  GENL_REQUEST(req, 1024, genl_family, 0, SEG6_GENL_VERSION, SEG6_CMD_SET_TUNSRC, NLM_F_REQUEST);
  addattr_l(&req.n, sizeof(req), SEG6_ATTR_DST, src, sizeof(struct in6_addr));
  if (nl_talk(fd, &req.n, NULL, 0) < 0)
    exit(1);
}

void main() {
  int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
  int genl_family = get_family(fd, "SEG6");
  inet_pton(AF_INET6, "dd::", &src);
  set_sr_tunsrc(fd, genl_family, &src);
  close(fd);
}

ip route add encap seg6¶

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <linux/seg6_iptunnel.h>
#include <linux/lwtunnel.h>
static void srh_dump(FILE* fp, struct ipv6_sr_hdr *srh)
{
  fprintf(fp, "SRH\n");
  fprintf(fp, "+ nexthdr      : 0x%02x(%u)\n", srh->nexthdr      , srh->nexthdr      );
  fprintf(fp, "+ hdrlen       : 0x%02x(%u)\n", srh->hdrlen       , srh->hdrlen       );
  fprintf(fp, "+ type         : 0x%02x(%u)\n", srh->type         , srh->type         );
  fprintf(fp, "+ segments_left: 0x%02x(%u)\n", srh->segments_left, srh->segments_left);
  fprintf(fp, "+ first_segment: 0x%02x(%u)\n", srh->first_segment, srh->first_segment);
  fprintf(fp, "+ flags        : 0x%02x(%u)\n", srh->flags        , srh->flags        );
  fprintf(fp, "+ tag          : 0x%04x(%u)\n", srh->tag          , srh->tag          );
  fprintf(fp, "+ segments: [");
  const size_t n_loop = srh->segments_left + 1;
  for (size_t i=0; i<n_loop; i++) {
    char strbuf[100];
    inet_ntop(AF_INET6,
        (const void*)&srh->segments[i],
        strbuf, sizeof(strbuf));
    printf("%s%s", strbuf, i+1<n_loop?",":"]\n");
  }
}
static struct ipv6_sr_hdr *parse_srh(bool encap,
    size_t num_segs, struct in6_addr *segs)
{
  const size_t srhlen = 8 + sizeof(struct in6_addr)*(encap ? num_segs+1 : num_segs);

  struct ipv6_sr_hdr *srh = malloc(srhlen);
  memset(srh, 0, srhlen);
  srh->hdrlen = (srhlen >> 3) - 1;
  srh->type = 4;
  srh->segments_left = encap ? num_segs : num_segs - 1;
  srh->first_segment = encap ? num_segs : num_segs - 1;

  size_t srh_idx = encap ? 1 : 0;
  for (ssize_t i=num_segs-1; i>=0; i--)
    memcpy(&srh->segments[srh_idx + i], &segs[num_segs - 1 - i], sizeof(struct in6_addr));
  return srh;
}

static void add_seg6_route(int fd,
    struct in_addr *pref, size_t plen,
    int mode, size_t num_segs, struct in6_addr *segs,
    uint32_t oif_idx)
{
  struct {
    struct nlmsghdr  n;
    struct rtmsg r;
    char buf[4096];
  } req = {
    .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)),
    .n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK,
    .n.nlmsg_type = RTM_NEWROUTE,
    .r.rtm_family = AF_INET,
    .r.rtm_dst_len = plen,
    .r.rtm_src_len = 0,
    .r.rtm_tos = 0,
    .r.rtm_table = RT_TABLE_MAIN,
    .r.rtm_protocol = 0x03,
    .r.rtm_scope = 0xfd,
    .r.rtm_type = RTN_UNICAST,
    .r.rtm_flags = 0,
  };

  /* set RTA_DST */
  addattr_l(&req.n, sizeof(req), RTA_DST, pref, sizeof(struct in_addr));
  req.r.rtm_dst_len = plen;

  /* set RTA_OIF */
  addattr32(&req.n, sizeof(req), RTA_OIF, oif_idx);

  /* set RTA_ENCAP */
  char buf[1024];
  struct rtattr *rta = (void *)buf;
  rta->rta_type = RTA_ENCAP;
  rta->rta_len = RTA_LENGTH(0);
  struct rtattr *nest = rta_nest(rta, sizeof(buf), RTA_ENCAP);
  struct ipv6_sr_hdr *srh = parse_srh(false, num_segs, segs);
  size_t srhlen = (srh->hdrlen + 1) << 3;
  struct seg6_iptunnel_encap *tuninfo = malloc(sizeof(*tuninfo) + srhlen);
  memset(tuninfo, 0, sizeof(*tuninfo) + srhlen);
  memcpy(tuninfo->srh, srh, srhlen);
  tuninfo->mode = SEG6_IPTUN_MODE_ENCAP;
  rta_addattr_l(rta, sizeof(buf), SEG6_IPTUNNEL_SRH,
      tuninfo, sizeof(*tuninfo) + srhlen);
  rta_nest_end(rta, nest);
  addraw_l(&req.n, 1024 , RTA_DATA(rta), RTA_PAYLOAD(rta));

  /* set RTA_ENCAP_TYPE */
  addattr16(&req.n, sizeof(req), RTA_ENCAP_TYPE, LWTUNNEL_ENCAP_SEG6);

  if (nl_talk(fd, &req.n, NULL, 0) < 0)
    exit(1);
}
/* 1.1.1.1  encap seg6 mode encap segs 2 [ 1:: 2:: ] dev dum0 scope link */
monitoring group(RTMGRP) is 0xffffffff ...
RTM_NEWROUTE f=0x0600 s=1571141704 p=0000028760 :: fmly=2 dl=32 sl=0 tos=0 tab=254 pro=3 scope=253 type=1 f=0x0
  0x000f RTA_TABLE        :: 254
  0x0001 RTA_DST          :: 1.1.1.1
  0x0004 RTA_OIF          :: 42
  0x0016 RTA_ENCAP        :: nested-data
    0x0001 SEG6_IPTUNNEL_SRH    :: mode=1 (SEG6_IPTUN_MODE_ENCAP) nh=0 hl=4 t=4 sl=1 [2::,1::]
  0x0015 RTA_ENCAP_TYPE   :: 5 (LWTUNNEL_ENCAP_SEG6)

sudo ./ip/ip route add 1.1.1.2 encap seg6 mode encap segs 1::,2:: dev dum0
0000:    68 00 00 00 18 00 05 06  56 c6 a5 5d 00 00 00 00   h.......  V..]....
0010:    02 20 00 00 fe 03 fd 01  00 00 00 00 08 00 01 00   . ......  ........
0020:    01 01 01 02 34 00 16 80  30 00 01 00 01 00 00 00   ....4...  0.......
0030:    00 04 04 01 01 00 00 00  00 02 00 00 00 00 00 00   ........  ........
0040:    00 00 00 00 00 00 00 00  00 01 00 00 00 00 00 00   ........  ........
0050:    00 00 00 00 00 00 00 00  06 00 15 00 05 00 00 00   ........  ........
0060:    08 00 04 00 2a 00 00 00                           ....*...

sudo ./build/a.out
0000:    68 00 00 00 18 00 05 06  00 00 00 00 00 00 00 00   h.......  ........
0010:    02 20 00 00 fe 00 ff 01  00 00 00 00 08 00 01 00   . ......  ........
0020:    01 01 01 02 08 00 04 00  2a 00 00 00 34 00 16 80   ........  *...4...
0030:    30 00 01 00 01 00 00 00  00 04 04 01 01 00 00 00   0.......  ........
0040:    00 01 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ........  ........
0050:    00 02 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ........  ........
0060:    06 00 15 00 05 00 00 00                           ........

ip route add encap seg6local End¶

static void add_seg6local_end_route(int fd,
    struct in6_addr *pref, size_t plen,
    uint32_t oif_idx)
{
  struct {
    struct nlmsghdr  n;
    struct rtmsg r;
    char buf[4096];
  } req = {
    .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)),
    .n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK,
    .n.nlmsg_type = RTM_NEWROUTE,
    .r.rtm_family = AF_INET6,
    .r.rtm_dst_len = plen,
    .r.rtm_src_len = 0,
    .r.rtm_tos = 0,
    .r.rtm_table = RT_TABLE_MAIN,
    .r.rtm_protocol = 0x03,
    .r.rtm_scope = 0xfd,
    .r.rtm_type = RTN_UNICAST,
    .r.rtm_flags = 0,
  };

  /* set RTA_DST */
  addattr_l(&req.n, sizeof(req), RTA_DST, pref, sizeof(struct in6_addr));
  req.r.rtm_dst_len = plen;

  /* set RTA_OIF */
  addattr32(&req.n, sizeof(req), RTA_OIF, oif_idx);

  /* set RTA_ENCAP */
  char buf[1024];
  struct rtattr *rta = (void *)buf;
  rta->rta_type = RTA_ENCAP;
  rta->rta_len = RTA_LENGTH(0);
  struct rtattr *nest = rta_nest(rta, sizeof(buf), RTA_ENCAP);
  rta_addattr32(rta, sizeof(buf), SEG6_LOCAL_ACTION, SEG6_LOCAL_ACTION_END);
  rta_nest_end(rta, nest);
  addraw_l(&req.n, 1024 , RTA_DATA(rta), RTA_PAYLOAD(rta));

  /* set RTA_ENCAP_TYPE */
  addattr16(&req.n, sizeof(req), RTA_ENCAP_TYPE, LWTUNNEL_ENCAP_SEG6_LOCAL);

  hexdump(stdout, &req.n, req.n.nlmsg_len);
  if (nl_talk(fd, &req.n, NULL, 0) < 0)
    exit(1);
}
sudo nlsniff -g all
monitoring group(RTMGRP) is 0xffffffff ...
RTM_NEWROUTE f=0x0600 s=1571166864 p=0000006645 :: fmly=10 dl=128 sl=0 tos=0 tab=254 pro=3 scope=0 type=1 f=0x0
  0x000f RTA_TABLE        :: 254
  0x0001 RTA_DST          :: 1::
  0x0006 RTA_PRIORITY     :: 1024
  0x0004 RTA_OIF          :: 42
  0x0016 RTA_ENCAP        :: nested-data
    0x0001 SEG6_LOCAL_ACTION    :: 1 (SEG6_LOCAL_ACTION_END)
  0x0015 RTA_ENCAP_TYPE   :: 7 (LWTUNNEL_ENCAP_SEG6_LOCAL)
  0x000c RTA_CACHEINFO    :: unknown-fmt(rta_len=36,data=01000000...)
  0x0014 RTA_PREF         :: 0

sudo ./ip/ip route add 1:: encap seg6local action End dev dum0
0000:    4c 00 00 00 18 00 05 06  90 1a a6 5d 00 00 00 00   L.......  ...]....
0010:    0a 80 00 00 fe 03 00 01  00 00 00 00 14 00 01 00   ........  ........
0020:    00 01 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ........  ........
0030:    0c 00 16 80 08 00 01 00  01 00 00 00 06 00 15 00   ........  ........
0040:    07 00 00 00 08 00 04 00  2a 00 00 00               ........  *...

sudo ./build/a.out
0000:    4c 00 00 00 18 00 05 06  00 00 00 00 00 00 00 00   L.......  ........
0010:    0a 80 00 00 fe 03 fd 01  00 00 00 00 14 00 01 00   ........  ........
0020:    00 f1 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ........  ........
0030:    08 00 04 00 2a 00 00 00  0c 00 16 80 08 00 01 00   ....*...  ........
0040:    01 00 00 00 06 00 15 00  07 00 00 00               ........  ....

ip route add encap seg6local End.X¶

static void add_seg6local_end_x_route(int fd,
    struct in6_addr *pref, size_t plen,
    struct in6_addr *nh6,
    uint32_t oif_idx)
{
  struct {
    struct nlmsghdr  n;
    struct rtmsg r;
    char buf[4096];
  } req = {
    .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)),
    .n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK,
    .n.nlmsg_type = RTM_NEWROUTE,
    .r.rtm_family = AF_INET6,
    .r.rtm_dst_len = plen,
    .r.rtm_src_len = 0,
    .r.rtm_tos = 0,
    .r.rtm_table = RT_TABLE_MAIN,
    .r.rtm_protocol = 0x03,
    .r.rtm_scope = 0xfd,
    .r.rtm_type = RTN_UNICAST,
    .r.rtm_flags = 0,
  };

  /* set RTA_DST */
  addattr_l(&req.n, sizeof(req), RTA_DST, pref, sizeof(struct in6_addr));
  req.r.rtm_dst_len = plen;

  /* set RTA_OIF */
  addattr32(&req.n, sizeof(req), RTA_OIF, oif_idx);

  /* set RTA_ENCAP */
  char buf[1024];
  struct rtattr *rta = (void *)buf;
  rta->rta_type = RTA_ENCAP;
  rta->rta_len = RTA_LENGTH(0);
  struct rtattr *nest = rta_nest(rta, sizeof(buf), RTA_ENCAP);
  rta_addattr32(rta, sizeof(buf), SEG6_LOCAL_ACTION, SEG6_LOCAL_ACTION_END_X);
  rta_addattr_l(rta, sizeof(buf), SEG6_LOCAL_NH6, nh6, sizeof(struct in6_addr));
  rta_nest_end(rta, nest);
  addraw_l(&req.n, 1024 , RTA_DATA(rta), RTA_PAYLOAD(rta));

  /* set RTA_ENCAP_TYPE */
  addattr16(&req.n, sizeof(req), RTA_ENCAP_TYPE, LWTUNNEL_ENCAP_SEG6_LOCAL);

  hexdump(stdout, &req.n, req.n.nlmsg_len);
  if (nl_talk(fd, &req.n, NULL, 0) < 0)
    exit(1);
}
sudo nlsniff -g all
monitoring group(RTMGRP) is 0xffffffff ...
RTM_NEWROUTE f=0x0600 s=1571167833 p=0000021250 :: fmly=10 dl=128 sl=0 tos=0 tab=254 pro=3 scope=0 type=1 f=0x0
  0x000f RTA_TABLE        :: 254
  0x0001 RTA_DST          :: f1::
  0x0006 RTA_PRIORITY     :: 1024
  0x0004 RTA_OIF          :: 42
  0x0016 RTA_ENCAP        :: nested-data
    0x0001 SEG6_LOCAL_ACTION    :: 2 (SEG6_LOCAL_ACTION_END_X)
    0x0005 SEG6_LOCAL_NH6       :: 2001::2
  0x0015 RTA_ENCAP_TYPE   :: 7 (LWTUNNEL_ENCAP_SEG6_LOCAL)
  0x000c RTA_CACHEINFO    :: unknown-fmt(rta_len=36,data=01000000...)
  0x0014 RTA_PREF         :: 0

sudo ./ip/ip route add f1:: encap seg6local action End.X nh6 2001::2 dev dum0
0000:    60 00 00 00 18 00 05 06  59 1e a6 5d 00 00 00 00   `.......  Y..]....
0010:    0a 80 00 00 fe 03 00 01  00 00 00 00 14 00 01 00   ........  ........
0020:    00 f1 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ........  ........
0030:    20 00 16 80 08 00 01 00  02 00 00 00 14 00 05 00    .......  ........
0040:    20 01 00 00 00 00 00 00  00 00 00 00 00 00 00 02    .......  ........
0050:    06 00 15 00 07 00 00 00  08 00 04 00 2a 00 00 00   ........  ....*...

sudo ./build/a.out
0000:    60 00 00 00 18 00 05 06  00 00 00 00 00 00 00 00   `.......  ........
0010:    0a 80 00 00 fe 03 fd 01  00 00 00 00 14 00 01 00   ........  ........
0020:    00 f1 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ........  ........
0030:    08 00 04 00 2a 00 00 00  20 00 16 80 08 00 01 00   ....*...   .......
0040:    02 00 00 00 14 00 05 00  20 01 00 00 00 00 00 00   ........   .......
0050:    00 00 00 00 00 00 00 02  06 00 15 00 07 00 00 00   ........  ........

ip route add encap seg6local End.T¶

static void add_seg6local_end_t_route(int fd,
    struct in6_addr *pref, size_t plen,
                uint32_t table_id,
    uint32_t oif_idx)
{
  struct {
    struct nlmsghdr  n;
    struct rtmsg r;
    char buf[4096];
  } req = {
    .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)),
    .n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK,
    .n.nlmsg_type = RTM_NEWROUTE,
    .r.rtm_family = AF_INET6,
    .r.rtm_dst_len = plen,
    .r.rtm_src_len = 0,
    .r.rtm_tos = 0,
    .r.rtm_table = RT_TABLE_MAIN,
    .r.rtm_protocol = 0x03,
    .r.rtm_scope = 0xfd,
    .r.rtm_type = RTN_UNICAST,
    .r.rtm_flags = 0,
  };

  /* set RTA_DST */
  addattr_l(&req.n, sizeof(req), RTA_DST, pref, sizeof(struct in6_addr));
  req.r.rtm_dst_len = plen;

  /* set RTA_OIF */
  addattr32(&req.n, sizeof(req), RTA_OIF, oif_idx);

  /* set RTA_ENCAP */
  char buf[1024];
  struct rtattr *rta = (void *)buf;
  rta->rta_type = RTA_ENCAP;
  rta->rta_len = RTA_LENGTH(0);
  struct rtattr *nest = rta_nest(rta, sizeof(buf), RTA_ENCAP);
        rta_addattr32(rta, sizeof(buf), SEG6_LOCAL_ACTION, SEG6_LOCAL_ACTION_END_T);
        rta_addattr32(rta, sizeof(buf), SEG6_LOCAL_TABLE, table_id);
  rta_nest_end(rta, nest);
  addraw_l(&req.n, 1024 , RTA_DATA(rta), RTA_PAYLOAD(rta));

  /* set RTA_ENCAP_TYPE */
  addattr16(&req.n, sizeof(req), RTA_ENCAP_TYPE, LWTUNNEL_ENCAP_SEG6_LOCAL);

  hexdump(stdout, &req.n, req.n.nlmsg_len);
  if (nl_talk(fd, &req.n, NULL, 0) < 0)
    exit(1);
}
sudo nlsniff -g all
monitoring group(RTMGRP) is 0xffffffff ...
RTM_NEWROUTE f=0x0600 s=1571168033 p=0000005254 :: fmly=10 dl=128 sl=0 tos=0 tab=254 pro=3 scope=0 type=1 f=0x0
  0x000f RTA_TABLE        :: 254
  0x0001 RTA_DST          :: f2::
  0x0006 RTA_PRIORITY     :: 1024
  0x0004 RTA_OIF          :: 42
  0x0016 RTA_ENCAP        :: nested-data
    0x0001 SEG6_LOCAL_ACTION    :: 3 (SEG6_LOCAL_ACTION_END_T)
    0x0003 SEG6_LOCAL_TABLE     :: 10
  0x0015 RTA_ENCAP_TYPE   :: 7 (LWTUNNEL_ENCAP_SEG6_LOCAL)
  0x000c RTA_CACHEINFO    :: unknown-fmt(rta_len=36,data=01000000...)
  0x0014 RTA_PREF         :: 0

sudo ./ip/ip route add f2:: encap seg6local action End.T table 10 dev dum0
0000:    54 00 00 00 18 00 05 06  21 1f a6 5d 00 00 00 00   T.......  !..]....
0010:    0a 80 00 00 fe 03 00 01  00 00 00 00 14 00 01 00   ........  ........
0020:    00 f2 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ........  ........
0030:    14 00 16 80 08 00 01 00  03 00 00 00 08 00 03 00   ........  ........
0040:    0a 00 00 00 06 00 15 00  07 00 00 00 08 00 04 00   ........  ........
0050:    2a 00 00 00                                       *...

sudo ./build/a.out
0000:    54 00 00 00 18 00 05 06  00 00 00 00 00 00 00 00   T.......  ........
0010:    0a 80 00 00 fe 03 fd 01  00 00 00 00 14 00 01 00   ........  ........
0020:    00 f1 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ........  ........
0030:    08 00 04 00 2a 00 00 00  14 00 16 80 08 00 01 00   ....*...  ........
0040:    03 00 00 00 08 00 03 00  0a 00 00 00 06 00 15 00   ........  ........
0050:    07 00 00 00                                       ....

ip route add encap seg6local End.DX4¶

static void add_seg6local_end_dx4_route(int fd,
    struct in6_addr *pref, size_t plen,
                struct in_addr *nh4,
    uint32_t oif_idx)
{
  struct {
    struct nlmsghdr  n;
    struct rtmsg r;
    char buf[4096];
  } req = {
    .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)),
    .n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK,
    .n.nlmsg_type = RTM_NEWROUTE,
    .r.rtm_family = AF_INET6,
    .r.rtm_dst_len = plen,
    .r.rtm_src_len = 0,
    .r.rtm_tos = 0,
    .r.rtm_table = RT_TABLE_MAIN,
    .r.rtm_protocol = 0x03,
    .r.rtm_scope = 0xfd,
    .r.rtm_type = RTN_UNICAST,
    .r.rtm_flags = 0,
  };

  /* set RTA_DST */
  addattr_l(&req.n, sizeof(req), RTA_DST, pref, sizeof(struct in6_addr));
  req.r.rtm_dst_len = plen;

  /* set RTA_OIF */
  addattr32(&req.n, sizeof(req), RTA_OIF, oif_idx);

  /* set RTA_ENCAP */
  char buf[1024];
  struct rtattr *rta = (void *)buf;
  rta->rta_type = RTA_ENCAP;
  rta->rta_len = RTA_LENGTH(0);
  struct rtattr *nest = rta_nest(rta, sizeof(buf), RTA_ENCAP);
        rta_addattr32(rta, sizeof(buf), SEG6_LOCAL_ACTION, SEG6_LOCAL_ACTION_END_DX4);
        rta_addattr_l(rta, sizeof(buf), SEG6_LOCAL_NH4, nh4, sizeof(struct in_addr));
  rta_nest_end(rta, nest);
  addraw_l(&req.n, 1024 , RTA_DATA(rta), RTA_PAYLOAD(rta));

  /* set RTA_ENCAP_TYPE */
  addattr16(&req.n, sizeof(req), RTA_ENCAP_TYPE, LWTUNNEL_ENCAP_SEG6_LOCAL);

  hexdump(stdout, &req.n, req.n.nlmsg_len);
  if (nl_talk(fd, &req.n, NULL, 0) < 0)
    exit(1);
}
RTM_NEWROUTE f=0x0600 s=1571168127 p=0000012831 :: fmly=10 dl=128 sl=0 tos=0 tab=254 pro=3 scope=0 type=1 f=0x0
  0x000f RTA_TABLE        :: 254
  0x0001 RTA_DST          :: f2::
  0x0006 RTA_PRIORITY     :: 1024
  0x0004 RTA_OIF          :: 42
  0x0016 RTA_ENCAP        :: nested-data
    0x0001 SEG6_LOCAL_ACTION    :: 6 (SEG6_LOCAL_ACTION_END_DX4)
    0x0004 SEG6_LOCAL_NH4       :: 10.0.0.2
  0x0015 RTA_ENCAP_TYPE   :: 7 (LWTUNNEL_ENCAP_SEG6_LOCAL)
  0x000c RTA_CACHEINFO    :: unknown-fmt(rta_len=36,data=01000000...)
  0x0014 RTA_PREF         :: 0

sudo ./ip/ip route add f2:: encap seg6local action End.DX4 nh4 10.0.0.2 dev dum0
0000:    54 00 00 00 18 00 05 06  7f 1f a6 5d 00 00 00 00   T.......  ...]....
0010:    0a 80 00 00 fe 03 00 01  00 00 00 00 14 00 01 00   ........  ........
0020:    00 f2 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ........  ........
0030:    14 00 16 80 08 00 01 00  06 00 00 00 08 00 04 00   ........  ........
0040:    0a 00 00 02 06 00 15 00  07 00 00 00 08 00 04 00   ........  ........
0050:    2a 00 00 00                                       *...

sudo ./build/a.out
0000:    54 00 00 00 18 00 05 06  00 00 00 00 00 00 00 00   T.......  ........
0010:    0a 80 00 00 fe 03 fd 01  00 00 00 00 14 00 01 00   ........  ........
0020:    00 f1 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ........  ........
0030:    08 00 04 00 2a 00 00 00  14 00 16 80 08 00 01 00   ....*...  ........
0040:    06 00 00 00 08 00 04 00  0a 00 00 02 06 00 15 00   ........  ........
0050:    07 00 00 00                                       ....

ip {-6|-4} route {add|del} via NH¶

#include "hexdump.h"
#include "netlink.h"
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>

static void adddel_in6_route(int fd,
    struct in6_addr *pref, uint32_t plen,
                struct in6_addr *nh6, bool install)
{
  struct {
    struct nlmsghdr  n;
    struct rtmsg r;
    char buf[4096];
  } req = {
    .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)),
    .n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK,
    .n.nlmsg_type = install ? RTM_NEWROUTE : RTM_DELROUTE,
    .r.rtm_family = AF_INET6,
    .r.rtm_dst_len = plen,
    .r.rtm_src_len = 0,
    .r.rtm_tos = 0,
    .r.rtm_table = RT_TABLE_MAIN,
    .r.rtm_protocol = 0x03,
    .r.rtm_scope = 0xfd,
    .r.rtm_type = RTN_UNICAST,
    .r.rtm_flags = 0,
  };

  /* set RTA_DST */
  addattr_l(&req.n, sizeof(req), RTA_DST, pref, sizeof(struct in6_addr));
  req.r.rtm_dst_len = plen;

  /* set RTA_GATEWAY */
  addattr_l(&req.n, sizeof(req), RTA_GATEWAY, nh6, sizeof(struct in6_addr));

  /* talk with netlink-bus */
  hexdump(stdout, &req.n, req.n.nlmsg_len);
  if (nl_talk(fd, &req.n, NULL, 0) < 0)
    exit(1);
}

void main() {
  int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
  if (fd < 0)
    exit(1);

  struct in6_addr pref, nh6;
  uint32_t plen = 128;
  uint32_t num_segs = 3;
  inet_pton(AF_INET6, "20::", &pref);
  inet_pton(AF_INET6, "2001::2", &nh6);

  adddel_in6_route(fd, &pref, plen, &nh6, true);
  close(fd);
}

ip link¶

ip nexthop¶

#include "netlink.h"
#include "hexdump.h"
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <linux/nexthop.h>
#include <linux/lwtunnel.h>
#include <linux/seg6.h>
#include <linux/seg6_local.h>
#include <linux/seg6_iptunnel.h>

static void adddel_nexthop(int fd,
    uint32_t oif_idx, uint32_t nh_id,
    bool install)
{
  struct {
    struct nlmsghdr  n;
    struct nhmsg nh;
    char buf[4096];
  } req = {
    .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg)),
    .n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK,
    .n.nlmsg_type = install ? RTM_NEWNEXTHOP : RTM_DELNEXTHOP,
    .nh.nh_family = AF_INET6,
    .nh.nh_scope = 0x00,
    .nh.nh_protocol = 0x03,
    .nh.resvd = 0x00,
    .nh.nh_flags = 0,
  };

  addattr32(&req.n, sizeof(req), NHA_OIF, oif_idx);
  addattr32(&req.n, sizeof(req), NHA_ID, nh_id);
  addattr16(&req.n, sizeof(req), NHA_ENCAP_TYPE, LWTUNNEL_ENCAP_SEG6_LOCAL);

  char buf[1024];
  struct rtattr *rta = (void *)buf;
  rta->rta_type = NHA_ENCAP;
  rta->rta_len = RTA_LENGTH(0);
  struct rtattr *nest = rta_nest(rta, sizeof(buf), NHA_ENCAP);
  rta_addattr32(rta, sizeof(buf), SEG6_LOCAL_ACTION, SEG6_LOCAL_ACTION_END);
  rta_nest_end(rta, nest);
  addraw_l(&req.n, 1024 , RTA_DATA(rta), RTA_PAYLOAD(rta));

  int ret = nl_talk(fd, &req.n, NULL, 0):
  if (ret < 0)
    exit(1);
}

void main() {
  int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
  if (fd < 0)
    exit(1);

  uint32_t oif_idx = 4;
  uint32_t nh_id = 22;
  adddel_nexthop(fd, oif_idx, nh_id, true);
  close(fd);
}
Next Previous

© Copyright 2019, slankdev Revision a388a159.

Built with Sphinx using a theme provided by Read the Docs.