Francisco Germano Vogt
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # Lab 5: Introdução a planos de dados programáveis com a linguagem P4 ## Objetivos Este laboratório possui como objetivo geral introduzir o conceito de planos de dados programáveis por meio da linguagem P4 (Programming Protocol-independent Packet Processors - https://p4.org). Os objetivos específicos deste laboratório incluem: • Permitir ao aluno melhorar a sua compreensão do funcionamento de equipamentos de rede, principalmente no que diz respeito ao plano de dado em relação a funções básicas de análise de cabeçalhos (parsing), endereçamento e comutação de pacotes. • Abordar os princípios de projeto de sistema embarcado com foco no plano de dados (datapath) de dispositivos de redes e sua programação através da linguagem P4 versão 16. • Desenvolver atividades práticas com a linguagem P4. O material desta atividade foi adaptado a partir do tutorial P4 disponível no endereço https://github.com/p4lang/tutorials ## Materiais necessários Para realizar esta atividade o aluno necessitará dos seguintes pacotes No Linux, precisamos de: • VirtualBox • Virtual Machine (VM) do P4 No Windows, precisamos de: • VirtualBox • Virtual Machine (VM) do P4 A VM do P4 pode ser baixada no link https://drive.google.com/file/d/1wWi5I-ioEUWQ_HjjcLYLWcFh7vpYYMIp/view?usp=sharing ::: warning Atenção: Os equipamentos devem ter 25GB ou mais livres de espaço em disco para importar a VM. ::: ## Configuração A VM roda o SO Ubuntu 16.04 e dispõe de todas as funcionalidades do Mininet e da linguagem P4 já instaladas. Além disso, a VM possui todos os arquivos e pacotes necessários para utilização nas atividades do laboratório. Dessa forma, o aluno não precisará instalar quaisquer ferramentas para realizar esta atividade. Todas as dicas e configurações mostradas para VirtualBox e acesso SSH podem ser realizadas pelo próprio aluno em um computador pessoal. Primeiro acesso à Máquina Virtual: :::info Para acessar a VM do P4 utilize as seguintes credenciais: Login: p4 Password: p4 ::: ## Contexto ### Arquitetura tradicional de equipamento de rede Analisando uma arquitetura clássica de roteador (veja Fig. 1) nos permite observar que esta se trata de um modelo formado basicamente por dois planos distintos: o software de controle e o hardware dedicado ao processamento de pacotes. O plano de controle é encarregado de implementar protocolos de roteamento e tomar decisões tais como escolha da melhor rota, transferindo essas decisões (ex: tabela de encaminhamento) para o plano de dados através de uma API proprietária. A única interação externa que um roteador pode receber ocorre através de interfaces de configuração, como por exemplo Web, SNMP, CLI. Isto limita o uso do dispositivo às funcionalidades programadas pelo fabricante dos circuitos integrados (ASIC - Application Specific Integrated Circuits) como funções fixas implementadas em hardware por questão de desempenho e custo. Por ser uma implementação em hardware, o usuário do dispositivo não consegue instalar ou alterar as funcionalidades do plano de dados que faz o processamento de pacotes em altas taxas de transmissão. O Plano de dados, majoritariamente proprietário, dedicado e fixo (veja Fig. 2), torna difícil a definição de novas características para o processamento de pacotes, o que prejudica a inovação. Por exemplo, para que se modifique o plano de dados, um novo design de todo o conjunto de hardware deve ser realizado, para que então um novo ASIC seja produzido, distribuído e instalado: um processo de alto custo e longa duração. Daí a necessidade da proposta de um plano de dados flexível, cujo funcionamento possa ser alterado conforme a necessidade, isto é, um plano de dados programável. ![](https://i.imgur.com/wQidoqk.png) ### Plano de dados programável Buscando a flexibilidade para definição de comportamentos específicos no tratamento do encaminhamento de pacotes em redes programáveis (veja Fig. 2), a linguagem P4 abstrai a programação do plano de dados de redes, almejando três objetivos: • Independência do protocolo: O dispositivo deve ser capaz de analisar qualquer tipo de protocolo desde que este seja declarado anteriormente no programa . Como por exemplo, análise de cabeçalho e ações usando o modelo de Match+Action típico do protocol Openflow; • Independência de arquitetura: O programa P4 deve abstrair a camada física, isto é, deve ser o mesmo independente do equipamento alvo (target) no qual está sendo aplicado, mesmo que diferentes tecnologias SW/HW sejam utilizadas. Dessa forma, as peculiaridades de cada equipamento devem ser tratadas pelo próprio compilador; • Reconfiguração em campo: O processamento dos pacotes pode ser alterado uma vez implantado, até mesmo em tempo de execução. ![](https://i.imgur.com/gd4IYXw.png) ![](https://i.imgur.com/ijHE5oN.png) A linguagem P4 se baseia na arquitetura PISA (Protocol-Independent Switch Architecture) caraterizado por hardware baseado em um pipeline que permite (re)configuração usando o modelo de Match+Action (veja Fig. 3). Dessa forma, diferentemente dos ASICs tradicionais com funções fixas, a arquitetura provê grande flexibilidade sem comprometer a performance (chips com capacidade na mesma ordem de Tb/s suportados em ASICs). Na linguagem P4 os principais blocos programáveis são parsers e controls (veja Fig. 4). Parsers são implementados como máquinas de estado com o propósito de extrair campos de cabeçalhos de pacotes de forma definida pelo usuário. Controls são responsáveis pelo processamento principal de pacotes em estruturas match-action. Aqui as regras de tabelas e ações são definidas para manipular cabeçalhos de pacotes e meta-dados (metadata). O programador/usuário é responsável por realizar a codificação de parsers e controls por meio de diferentes tipos de estruturas de dados e expressões providas pela linguagem P4 [(1)](https://opennetworking.org/wp-content/uploads/2020/12/p4-cheat-sheet.pdf). Em contrapartida, as estruturas de definição de arquitetura e bibliotecas externas podem ser definidas pelo fabricante de equipamento onde o programa P4 irá ser executado. Enquanto externs já são estruturas especializadas que definem rotinas como caixas-pretas que o programa P4 pode utilizar em sua execução. ![](https://i.imgur.com/RELHh8k.png) ![](https://i.imgur.com/widt89A.png) A estrutura de um programa escrito na linguagem P4 (veja Fig. 5) possui diferentes elementos, dentre eles: • Headers: representam estruturas de dados que referenciam campos nos cabeçalhos de pacotes • Parser: responsáveis pela análise e extração dos campos de pacotes; • Deparser: responsáveis pela modificação final de cabeçalhos de pacotes; • Ingress: depois de passarem pelo parser pacotes são encaminhados a ingress onde podem ter ações aplicadas sobre eles dependendo de estruturas de tabelas, definindo assim filas e portas de saída para os pacotes; • Egress: antes de deixar o pipeline, pacotes podem ter ações aplicadas sobre eles em egress, com a realização de modificações nos cabeçalhos de pacotes; • Tables: mecanismo que faz o processamento de pacotes por meio de correspondên- cias (key/matches) e suas respectivas ações associadas a serem executadas sobre os pacotes; • Actions: conjunto de primitivas a serem aplicadas (possivelmente por funções customizadas) sobre pacotes; • Control: estabelece o fluxo de processamento de pacotes do programa P4 utilizando os blocos previamente declarados. ![](https://i.imgur.com/RJEKJvO.png) Em um exemplo de programa P4 (veja Fig. 6), temos: (1) a estrutura de controle do switch “V1Switch”2 determinando todos os blocos de control sequencialmente pelos quais os pacotes serão tratados; (2) MyParser realizando o accepts de todos os pacotes recebidos pelo switch; (3) MyIngress realizando a simples alteração de portas de encaminhamento de pacotes (onde pacotes recebidos na porta 1 são encaminhados para porta 2 e vice-versa) (4) e os outros blocos de control não realizando nenhuma operação sobre os pacotes. Note que em cada um dos blocos de controle a função apply() realiza a chamada de ações a serem realizadas em pacotes. :::info Obs.: O termo switch, assim como em Openflow, é usado na comunidade P4 para fazer referência ao equipamento de rede de maneira genérica e não deve ser associado ao termo tradicional de um switch de camada 2 com as funções clássicas de computação e aprendizado de endereços MAC / Ethernet. ::: ![](https://i.imgur.com/AbD8Q4e.png) ## Atividades práticas Nas atividades a seguir iremos trabalhar na análise, no design e na implementação de um programa P4 para o encaminhamento básico de pacotes entre hosts de uma topologia emulada no Mininet (veja Fig. 7). ### Atividade 1: Análise do programa P4 Inicialize a máquina virtual, e ao realizar login na máquina virtual, abra um terminal (ctrl+alt+t), e entre na pasta: ``` $ cd /home/p4/tutorials/exercises/basic ``` Nesta pasta abra o arquivo ``` $ subl basic.p4 ``` :::info Q. 1: Analisando o programa aberto indique (referenciando a linha ou colando parte do código) onde ocorrem as seguintes operações: • Definição dos cabeçalhos Ethernet e IPv4 de pacotes • Parser dos cabeçalhos Ethernet e IPv4 de pacotes • Procura de destino IPv4 na tabela de roteamento • Atualização de endereços MAC fonte e destino • Decremento do campo time-to-live (TTL) do pacote • Definição da porta de saída (egress) do pacote • Cálculo do checksum ::: ![](https://i.imgur.com/BnplnPH.png) ### Atividade 2: Compilação e execução do programa P4 Agora vamos realizar a execução deste programa P4 na topologia Mininet previamente mostrada. Para isto na pasta ``` cd /home/p4/tutorials/exercises/basic ``` execute o comando: ``` make ``` Este comando realiza a compilação do programa basic.p4, e utiliza o código compilado para definir o switch base a ser executado pela plataforma Mininet. Ou seja, os switches mostrados na Fig. 7 serão uma instância deste programa P4. Em seguida o script realiza a configuração das tabelas de encaminhamento de cada um dos switches (s1, s2, s3, s4) utilizando os arquivos “s[1,2,3,4]-runtime.json”. Após a execução do comando “$ make”, no console mostrado da plataforma Mininet execute: ``` mininet> xterm h1 h4 ``` para abrir os consoles externos dos hosts h1 e h4. Na janela do xterm de h4 execute o comando: ``` ./receive.py ``` E na janela do xterm de h1 execute o comando: ``` ./send.py 10.0.4.4 "P4 is cool" ``` Estes programas realizam respectivamente a captura de pacote em h4 e o envio de 1 pacote de h1. :::info Q. 2: Com base no comportamento dos switches, explique: • Por quê os campos Ethernet (src e dst) do pacote enviado em h1 e recebido em h4 são diferentes? • Quais ações foram aplicadas pelos switches sobre o pacote? • A diferença dos valores de TTL do pacote enviado e recebido estão corretos? Por quê? ::: Para realizar o termino da execução da topologia Mininet, execute no console o comando: ``` mininet> exit ``` ### Atividade 3: Programando em P4: Comunicação entre alunos de diferentes planetas Uma das características mais importantes do P4 é permitir definir novos protocolos (ex: definição de cabeçalhos e funcionalidades) ou modificar protocolos existentes. Nesta atividade vamos definir um novo protocolo "planet" que vai ser encapsulado num quadro Ethernet. O arquivo P4 já vai estar disponível e precisaremos apenas adicionar o novo cabeçalho. O nosso novo protocolo "planet" esta definido como Ethernet type 0x66AA. Ele consta de 3 campos: source (Planeta origem), destination (Planeta destino) e seq (RA do aluno). O código do P4 também inclui funções de encaminhamento do pacote usando o valor do RA como entrada instalada pelo plano de controle na tabela do switch (Obs. a linguagem P4 só define as estruturas de dados das tabelas, o seu preenchimento com valores é função do plano de controle!). Para adicionar nosso novo cabeçalho vamos na pasta: ``` cd /home/p4/Class/BB-Gen/ ``` E abrimos o código do P4: ``` vim examples/p4_src/planets.p4 ``` O código tem que se adicionar logo em baixo de: ``` //–––––TODO–––––// ``` O cabeçalho tem que ter o nome planet_t com 3 campos: source (size of 24 bits), destination (size of 24 bits) e seq (size of 32 bits). Obs.: Dentro da pasta examples/p4_src/ tem vários exemplos de códigos P4 - é possível utilizá-los como ajuda para definir o cabeçalho. :::info Q. 3: Desenhe o formato do novo cabeçalho proposto seguindo as práticas usadas em protocolos padronizados pelo IETF (vide como exemplo a figura 9 no final do roteiro). ::: Depois de ter nosso código P4 completo, vamos compilar e gerar os arquivos para sua execução e teste. Na pasta /home/p4/Class/BB-Gen/ executamos o script: ``` ./install.sh <RA> ``` por exemplo: ``` ./install.sh 111111 ``` Esse script vai compilar o P4 (se tiver algum error no código ele vai mostrar), vai gerar os arquivos para visualização do nosso novo protocolo em Wireshark, vai gerar o PCAP com pacotes com nosso novo protocolo e vai prepara os arquivos de teste com Mininet. Se não tiver nenhum erro na execução do comando, vamos para a pasta: ``` cd /home/p4/tutorials/exercises/planet/ ``` E executamos nossa topologia (Fig. 8): ![](https://i.imgur.com/0SXFSVL.png) ``` make ``` para abrir os consoles externos dos hosts h1 e h2: ``` mininet> xterm h1 h2 ``` Nas janelas do xterm de h1 e h2 iniciamos a captura do trafego na interface eth0 executando o seguinte comando em cada um dos hosts: ``` $ wireshark & ``` :::warning Obs.: Se tiver o erro <em>Lua: Error during loading</em>, pode pressionar OK. ::: Na janela do xterm de h1 execute o comando ``` ./send.sh ``` :::info Q. 4: Os pacotes foram recebidos em h2? ::: Agora, na janela do xterm de h2 execute o comando ``` $ ./send.sh ``` :::info Q. 5: Os pacotes foram recebidos em h1? ::: Se olharmos no inicio da execução do Mininet (depois do comando $ make),teremos linhas como as seguintes: ``` planet_fib_match: planet.seq=111111 => fib_hit_nexthop(dmac=08:00:00:00:01:11, port=1) planet_fib_match: planet.seq=222222 => fib_hit_nexthop(dmac=08:00:00:00:02:00, port=2) ``` Elas representam as informações (resultados da lógica do plano de controle) que estão sendo instaladas nas tabelas do switch. :::info Q. 6: Explique qual estado (conteúdo das entradas nas tabelas) as linhas representam. ::: :::warning Obs 1. Pode ser necessário olhar o código P4 modificado para uma melhor compreensão. Obs 2. As interfaces físicas do switch são representadas por portas (port 1, port 2) na figura 8 se mostram quais são as portas da simulação. ::: Nas capturas de Wireshark podemos observar o protocolo que criamos: P4_PLANET Protocol. Olhe o valor do seq dos pacotes enviados em h1 e em h2. :::warning Obs.: O valor mostrado no Wireshark esta em HEX, para saber o valor em decimal pode usar uma ferramenta online como https://www.rapidtables.com/convert/number/hex-to-decimal.html ::: :::info Q. 7: Qual é a relação desse valor com o resultado do comando $ ./send.sh em h1 e em h2?. Q. 8: Envie junto com o relatório as capturas do Wireshark de h1 e h2. Q. 9: Voltando ao contexto inicial da atividade, considerando o tamanho dos campos no cabeçalho, quantos alunos e quantos planetas poderiam ser suportados? Descreva de foram sucinta como poderiam ser usados os campos no cabeçalho para comunicações (envio e recepção de pacotes) entre alunos de diferentes planetas. ::: ### Atividade 4: Calculadora P4 (OPCIONAL) A ideia principal desta atividade é escrever um programa P4 para realizar o cálculo simples de algumas operações matemáticas de acordo com os campos de cabeçalho de pacotes. Para acessar a atividade vamos para a pasta: ``` $ cd /home/p4/ ``` Criamos e acessamos a pasta calc: ``` mkdir calc cd calc ``` Baixamos o repositório: ``` git clone https://github.com/p4lang/tutorials.git `````` Agora copie a pasta "calc"da atividade para dentro do ambiente da VM: ``` cp -r tutorials/exercises/calc/ /home/p4/tutorials/exercises/ ``` Entre na pasta: ``` cd /home/p4/tutorials/exercises/calc ``` Antes, é necessário instalar as dependências necessárias: ``` sudo apt-get update sudo apt-get -y install python3-pip pip3 install scapy ``` E a execução de todo o programa se dá de forma similar a atividade anterior com o comando: ``` make ``` Isto irá compilar o código do programa calc.p4 e instanciar uma topologia mininet com um switch e dois hosts. Para enviar os pedidos de operações matemáticas ao switch no console do mininet digite: ``` mininet> h1 python3 calc.py ``` e em seguida no prompt que abrir, apenas digite os comandos dos pedidos de cálculos para o switch (ex.: 1+1) e tecle enter. Um pacote será criado e enviado ao switch, este realizará o processamento do pacote de acordo com o programa calc.p4 e irá retornar o pacote ao host com o resultado que será mostrado na tela do console no Mininet. O cabeçalho do pacote é criado de acordo com: • P is an ASCII Letter ’P’ (0x50) • 4 is an ASCII Letter ’4’ (0x34) • Version is currently 0.1 (0x01) • Op is an operation to Perform: • ’+’ (0x2b) Result = OperandA + OperandB • ’-’ (0x2d) Result = OperandA - OperandB • ’&’ (0x26) Result = OperandA & OperandB • ’|’ (0x7c) Result = OperandA | OperandB • ’ˆ’(0x5e) Result = OperandA ˆ OperandB ![](https://i.imgur.com/akShA3N.png) O cabeçalho da calculadora (veja Fig. 9) é enviado sobre Ethernet com tipo 0x1234. A tarefa desta atividade é realizar a codificação do arquivo calc.p4. Não há programação no plano de controle a ser feita, a única implementação se dá no arquivo calc.p4. O arquivo calc.p4 realiza o parse do cabeçalho customizado, executa a operação matemática, escreve o resultado no campo result do pacote, e retorna o pacote para o remetente. :::info Q. 11: Quais as modificações realizadas no programa calc.p4 que realizam a programação correta para a execução dos testes de operações matemáticas? Copie o código com as modificações no relatório. :::

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully